static void test_lua(void) { static struct mg_connection conn; static struct mg_context ctx; char http_request[] = "POST /foo/bar HTTP/1.1\r\n" "Content-Length: 12\r\n" "Connection: close\r\n\r\nhello world!"; lua_State *L = luaL_newstate(); conn.ctx = &ctx; conn.buf = http_request; conn.buf_size = conn.data_len = strlen(http_request); conn.request_len = parse_http_message(conn.buf, conn.data_len, &conn.request_info); conn.content_len = conn.data_len - conn.request_len; prepare_lua_environment(&conn, L); ASSERT(lua_gettop(L) == 0); check_lua_expr(L, "'hi'", "hi"); check_lua_expr(L, "mg.request_info.request_method", "POST"); check_lua_expr(L, "mg.request_info.uri", "/foo/bar"); check_lua_expr(L, "mg.request_info.num_headers", "2"); check_lua_expr(L, "mg.request_info.remote_ip", "0"); check_lua_expr(L, "mg.request_info.http_headers['Content-Length']", "12"); check_lua_expr(L, "mg.request_info.http_headers['Connection']", "close"); (void) luaL_dostring(L, "post = mg.read()"); check_lua_expr(L, "# post", "12"); check_lua_expr(L, "post", "hello world!"); lua_close(L); }
void mg_exec_lua_script(struct mg_connection *conn, const char *path, const void **exports) { int i; lua_State *L; if (path != NULL && (L = luaL_newstate()) != NULL) { prepare_lua_environment(conn, L); lua_pushcclosure(L, &lua_error_handler, 0); lua_pushglobaltable(L); if (exports != NULL) { for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) { lua_pushstring(L, exports[i]); lua_pushcclosure(L, (lua_CFunction) exports[i + 1], 0); lua_rawset(L, -3); } } if (luaL_loadfile(L, path) != 0) { lua_error_handler(L); } lua_pcall(L, 0, 0, -2); lua_close(L); } }
static int handle_lsp_request(struct mg_connection *conn, const char *path, struct file *filep, struct lua_State *ls) { void *p = NULL; lua_State *L = NULL; FILE *fp = NULL; int error = 1; // We need both mg_stat to get file size, and mg_fopen to get fd if (!mg_stat(path, filep) || (fp = mg_fopen(path, "r")) == NULL) { lsp_send_err(conn, ls, "File [%s] not found", path); } else if ((p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE, fileno(fp), 0)) == MAP_FAILED) { lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size, fileno(fp), strerror(errno)); } else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) { send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed"); } else { // We're not sending HTTP headers here, Lua page must do it. if (ls == NULL) { prepare_lua_environment(conn, L); } error = lsp(conn, path, p, filep->size, L); } if (L != NULL && ls == NULL) lua_close(L); if (p != NULL) munmap(p, filep->size); fclose(fp); return error; }
REPLACE_STATIC void handle_lsp_request(struct mg_connection *conn, const char *path, struct file *filep) { void *p = NULL; lua_State *L = NULL; if (!mg_fopen(conn, path, "r", filep)) { send_http_error(conn, 404, "Not Found", "%s", "File not found"); } else if (filep->membuf == NULL && (p = mmap(NULL, filep->size, PROT_READ, MAP_PRIVATE, fileno(filep->fp), 0)) == MAP_FAILED) { send_http_error(conn, 500, http_500_error, "%s", "x"); } else if ((L = luaL_newstate()) == NULL) { send_http_error(conn, 500, http_500_error, "%s", "y"); } else { mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\nConnection: close\r\n\r\n"); prepare_lua_environment(conn, L); conn->request_info.ev_data = L; call_user(conn, MG_INIT_LUA); lsp(conn, filep->membuf == NULL ? p : filep->membuf, filep->size, L); } if (L) lua_close(L); if (p) munmap(p, filep->size); mg_fclose(filep); }
// This function will be called by mongoose on every new request. int web_engine::begin_request_handler(struct mg_connection *conn) { astring file_path(mg_get_option(m_server, "document_root"), PATH_SEPARATOR, conn->uri); if (filename_endswith(file_path.c_str(), ".lp")) { FILE *fp = NULL; if ((fp = fopen(file_path.c_str(), "rb")) != NULL) { fseek (fp, 0, SEEK_END); size_t size = ftell(fp); fseek (fp, 0, SEEK_SET); char *data = (char*)mg_mmap(fp,size); lua_State *L = luaL_newstate(); prepare_lua_environment(conn, L); lsp(conn, data, (int) size, L); if (L != NULL) lua_close(L); mg_munmap(data,size); fclose(fp); return MG_TRUE; } else { return MG_FALSE; } } else if (!strncmp(conn->uri, "/json/",6)) { if (!strcmp(conn->uri, "/json/game")) { return json_game_handler(conn); } if (!strcmp(conn->uri, "/json/slider")) { return json_slider_handler(conn); } } else if (!strncmp(conn->uri, "/keypost",8)) { // Is there any sane way to determine the length of the buffer before getting it? // A request for a way was previously filed with the mongoose devs, // but it looks like it was never implemented. // For now, we'll allow a paste buffer of 32k. // To-do: Send an error if the paste is too big? char cmd_val[32768]; int pastelength = mg_get_var(conn, "val", cmd_val, sizeof(cmd_val)); if (pastelength > 0) { machine().ioport().natkeyboard().post_utf8(cmd_val); } // Send HTTP reply to the client mg_printf(conn, "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Content-Length: 2\r\n" // Always set Content-Length "\r\n" "OK"); // Returning non-zero tells mongoose that our function has replied to // the client, and mongoose should not send client any more data. return MG_TRUE; } else if (!strncmp(conn->uri, "/keyupload",8)) { char *upload_data; int data_length, ofs = 0; char var_name[100], file_name[255]; while ((ofs = mg_parse_multipart(conn->content + ofs, conn->content_len - ofs, var_name, sizeof(var_name), file_name, sizeof(file_name), (const char **)&upload_data, &data_length)) > 0) { mg_printf_data(conn, "File: %s, size: %d bytes", file_name, data_length); } // That upload_data contains more than we need. It also has the headers. // We'll need to strip it down to just what we want. if ((&data_length > 0) && (sizeof(file_name) > 0)) { // MSVC doesn't yet support variable-length arrays, so chop the string the old-fashioned way upload_data[data_length] = '\0'; // Now paste the stripped down paste_data.. machine().ioport().natkeyboard().post_utf8(upload_data); } return MG_TRUE; } else if (!strncmp(conn->uri, "/cmd",4)) { char cmd_name[64]; mg_get_var(conn, "name", cmd_name, sizeof(cmd_name)); if(!strcmp(cmd_name,"softreset")) { m_machine->schedule_soft_reset(); } else if(!strcmp(cmd_name,"hardreset")) { m_machine->schedule_hard_reset(); } else if(!strcmp(cmd_name,"exit")) { m_machine->schedule_exit(); } else if(!strcmp(cmd_name,"togglepause")) { if (m_machine->paused()) m_machine->resume(); else m_machine->pause(); } else if(!strcmp(cmd_name,"savestate")) { char cmd_val[64]; mg_get_var(conn, "val", cmd_val, sizeof(cmd_val)); char *filename = websanitize_statefilename(cmd_val); m_machine->schedule_save(filename); } else if(!strcmp(cmd_name,"loadstate")) { char cmd_val[64]; mg_get_var(conn, "val", cmd_val, sizeof(cmd_val)); char *filename = cmd_val; m_machine->schedule_load(filename); } else if(!strcmp(cmd_name,"loadauto")) { // This is here to just load the autosave and only the autosave. m_machine->schedule_load("auto"); } // Send HTTP reply to the client mg_printf(conn, "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Content-Length: 2\r\n" // Always set Content-Length "\r\n" "OK"); // Returning non-zero tells mongoose that our function has replied to // the client, and mongoose should not send client any more data. return MG_TRUE; } else if (!strncmp(conn->uri, "/slider",7)) { char cmd_id[64]; char cmd_val[64]; mg_get_var(conn, "id", cmd_id, sizeof(cmd_id)); mg_get_var(conn, "val", cmd_val, sizeof(cmd_val)); int cnt = 0; int id = atoi(cmd_id); const slider_state *curslider; for (curslider = machine().ui().get_slider_list(); curslider != NULL; curslider = curslider->next) { if (cnt==id) (*curslider->update)(machine(), curslider->arg, NULL, atoi(cmd_val)); cnt++; } for (curslider = (slider_state*)machine().osd().get_slider_list(); curslider != NULL; curslider = curslider->next) { if (cnt==id) (*curslider->update)(machine(), curslider->arg, NULL, atoi(cmd_val)); cnt++; } // Send HTTP reply to the client mg_printf(conn, "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Content-Length: 2\r\n" // Always set Content-Length "\r\n" "OK"); // Returning non-zero tells mongoose that our function has replied to // the client, and mongoose should not send client any more data. return MG_TRUE; } else if (!strncmp(conn->uri, "/screenshot.png",15)) { screen_device_iterator iter(m_machine->root_device()); screen_device *screen = iter.first(); if (screen == NULL) { return 0; } astring fname("screenshot.png"); emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); file_error filerr = file.open(fname.c_str()); if (filerr != FILERR_NONE) { return 0; } m_machine->video().save_snapshot(screen, file); astring fullpath(file.fullpath()); file.close(); mg_send_header(conn, "Cache-Control", "no-cache, no-store, must-revalidate"); mg_send_header(conn, "Pragma", "no-cache"); mg_send_header(conn, "Expires", "0"); mg_send_file(conn, fullpath.c_str(), NULL); return MG_MORE; // It is important to return MG_MORE after mg_send_file! } return 0; }