mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-19 16:13:07 +08:00
Moved mod_lua.c to src/lua.c
This commit is contained in:
parent
d3577b7877
commit
70154f6c23
@ -21,13 +21,13 @@
|
||||
|
||||
PROG = mongoose
|
||||
EXE_SUFFIX =
|
||||
CFLAGS = -std=c99 -O2 -W -Wall -pedantic -pthread -pipe -I.. $(CFLAGS_EXTRA)
|
||||
CFLAGS = -std=c99 -O2 -W -Wall -pedantic -pthread -pipe -I. -I.. $(CFLAGS_EXTRA)
|
||||
VERSION = $(shell perl -lne \
|
||||
'print $$1 if /define\s+MONGOOSE_VERSION\s+"(\S+)"/' ../mongoose.c)
|
||||
|
||||
# The order in which files are listed is important
|
||||
SOURCES = src/internal.h src/string.c src/parse_date.c src/options.c \
|
||||
src/crypto.c src/auth.c src/mongoose.c
|
||||
src/crypto.c src/auth.c src/mongoose.c src/lua.c
|
||||
|
||||
TINY_SOURCES = ../mongoose.c main.c
|
||||
LUA_SOURCES = $(TINY_SOURCES) sqlite3.c lsqlite3.c lua_5.2.1.c
|
||||
@ -60,7 +60,7 @@ endif
|
||||
all:
|
||||
@echo "make (unix|windows|macos)"
|
||||
|
||||
../mongoose.c: mod_lua.c ../mongoose.h Makefile $(SOURCES)
|
||||
../mongoose.c: ../mongoose.h Makefile $(SOURCES)
|
||||
cat $(SOURCES) | sed '/#include "internal.h"/d' > $@
|
||||
|
||||
unix_unit_test: $(LUA_SOURCES) Makefile ../test/unit_test.c
|
||||
|
@ -460,3 +460,9 @@ struct de {
|
||||
|
||||
static FILE *mg_fopen(const char *path, const char *mode);
|
||||
static int mg_stat(const char *path, struct file *filep);
|
||||
|
||||
#ifdef USE_LUA
|
||||
#include "lua_5.2.1.h"
|
||||
static int handle_lsp_request(struct mg_connection *, const char *,
|
||||
struct file *, struct lua_State *);
|
||||
#endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "lua_5.2.1.h"
|
||||
#include "internal.h"
|
||||
|
||||
#ifdef USE_LUA
|
||||
#ifdef _WIN32
|
||||
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
|
||||
int offset) {
|
||||
@ -20,7 +21,6 @@ static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
|
||||
static const char *LUASOCKET = "luasocket";
|
||||
|
||||
// Forward declarations
|
||||
static void handle_request(struct mg_connection *);
|
||||
static int handle_lsp_request(struct mg_connection *, const char *,
|
||||
struct file *, struct lua_State *);
|
||||
|
||||
@ -387,3 +387,4 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path,
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif // USE_LUA
|
@ -2842,10 +2842,6 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) {
|
||||
return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
|
||||
}
|
||||
|
||||
#ifdef USE_LUA
|
||||
#include "build/mod_lua.c"
|
||||
#endif // USE_LUA
|
||||
|
||||
FILE *mg_upload(struct mg_connection *conn, const char *destination_dir,
|
||||
char *path, int path_len) {
|
||||
const char *content_type_header, *boundary_start;
|
||||
|
399
mongoose.c
399
mongoose.c
@ -461,6 +461,12 @@ struct de {
|
||||
static FILE *mg_fopen(const char *path, const char *mode);
|
||||
static int mg_stat(const char *path, struct file *filep);
|
||||
|
||||
#ifdef USE_LUA
|
||||
#include "lua_5.2.1.h"
|
||||
static int handle_lsp_request(struct mg_connection *, const char *,
|
||||
struct file *, struct lua_State *);
|
||||
#endif
|
||||
|
||||
static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
|
||||
for (; *src != '\0' && n > 1; n--) {
|
||||
*dst++ = *src++;
|
||||
@ -4147,10 +4153,6 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) {
|
||||
return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
|
||||
}
|
||||
|
||||
#ifdef USE_LUA
|
||||
#include "build/mod_lua.c"
|
||||
#endif // USE_LUA
|
||||
|
||||
FILE *mg_upload(struct mg_connection *conn, const char *destination_dir,
|
||||
char *path, int path_len) {
|
||||
const char *content_type_header, *boundary_start;
|
||||
@ -5390,3 +5392,392 @@ struct mg_context *mg_start(const char **options,
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
#ifdef USE_LUA
|
||||
#ifdef _WIN32
|
||||
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
|
||||
int offset) {
|
||||
HANDLE fh = (HANDLE) _get_osfhandle(fd);
|
||||
HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
|
||||
void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
|
||||
CloseHandle(mh);
|
||||
return p;
|
||||
}
|
||||
#define munmap(x, y) UnmapViewOfFile(x)
|
||||
#define MAP_FAILED NULL
|
||||
#define MAP_PRIVATE 0
|
||||
#define PROT_READ 0
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
static const char *LUASOCKET = "luasocket";
|
||||
|
||||
// Forward declarations
|
||||
static int handle_lsp_request(struct mg_connection *, const char *,
|
||||
struct file *, struct lua_State *);
|
||||
|
||||
static void reg_string(struct lua_State *L, const char *name, const char *val) {
|
||||
lua_pushstring(L, name);
|
||||
lua_pushstring(L, val);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
static void reg_int(struct lua_State *L, const char *name, int val) {
|
||||
lua_pushstring(L, name);
|
||||
lua_pushinteger(L, val);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
static void reg_function(struct lua_State *L, const char *name,
|
||||
lua_CFunction func, struct mg_connection *conn) {
|
||||
lua_pushstring(L, name);
|
||||
lua_pushlightuserdata(L, conn);
|
||||
lua_pushcclosure(L, func, 1);
|
||||
lua_rawset(L, -3);
|
||||
}
|
||||
|
||||
static int lsp_sock_close(lua_State *L) {
|
||||
if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
|
||||
lua_getfield(L, -1, "sock");
|
||||
closesocket((SOCKET) lua_tonumber(L, -1));
|
||||
} else {
|
||||
return luaL_error(L, "invalid :close() call");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lsp_sock_recv(lua_State *L) {
|
||||
char buf[2000];
|
||||
int n;
|
||||
|
||||
if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
|
||||
lua_getfield(L, -1, "sock");
|
||||
n = recv((SOCKET) lua_tonumber(L, -1), buf, sizeof(buf), 0);
|
||||
if (n <= 0) {
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
lua_pushlstring(L, buf, n);
|
||||
}
|
||||
} else {
|
||||
return luaL_error(L, "invalid :close() call");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lsp_sock_send(lua_State *L) {
|
||||
const char *buf;
|
||||
size_t len, sent = 0;
|
||||
int n, sock;
|
||||
|
||||
if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) {
|
||||
buf = lua_tolstring(L, -1, &len);
|
||||
lua_getfield(L, -2, "sock");
|
||||
sock = (int) lua_tonumber(L, -1);
|
||||
while (sent < len) {
|
||||
if ((n = send(sock, buf + sent, len - sent, 0)) <= 0) {
|
||||
break;
|
||||
}
|
||||
sent += n;
|
||||
}
|
||||
lua_pushnumber(L, n);
|
||||
} else {
|
||||
return luaL_error(L, "invalid :close() call");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct luaL_Reg luasocket_methods[] = {
|
||||
{"close", lsp_sock_close},
|
||||
{"send", lsp_sock_send},
|
||||
{"recv", lsp_sock_recv},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int lsp_connect(lua_State *L) {
|
||||
char ebuf[100];
|
||||
SOCKET sock;
|
||||
|
||||
if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
|
||||
sock = conn2(lua_tostring(L, -3), (int) lua_tonumber(L, -2),
|
||||
(int) lua_tonumber(L, -1), ebuf, sizeof(ebuf));
|
||||
if (sock == INVALID_SOCKET) {
|
||||
return luaL_error(L, ebuf);
|
||||
} else {
|
||||
lua_newtable(L);
|
||||
reg_int(L, "sock", sock);
|
||||
reg_string(L, "host", lua_tostring(L, -4));
|
||||
luaL_getmetatable(L, LUASOCKET);
|
||||
lua_setmetatable(L, -2);
|
||||
}
|
||||
} else {
|
||||
return luaL_error(L, "connect(host,port,is_ssl): invalid parameter given.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lsp_error(lua_State *L) {
|
||||
lua_getglobal(L, "mg");
|
||||
lua_getfield(L, -1, "onerror");
|
||||
lua_pushvalue(L, -3);
|
||||
lua_pcall(L, 1, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Silently stop processing chunks.
|
||||
static void lsp_abort(lua_State *L) {
|
||||
int top = lua_gettop(L);
|
||||
lua_getglobal(L, "mg");
|
||||
lua_pushnil(L);
|
||||
lua_setfield(L, -2, "onerror");
|
||||
lua_settop(L, top);
|
||||
lua_pushstring(L, "aborting");
|
||||
lua_error(L);
|
||||
}
|
||||
|
||||
static int lsp(struct mg_connection *conn, const char *path,
|
||||
const char *p, int64_t len, lua_State *L) {
|
||||
int i, j, pos = 0, lines = 1, lualines = 0;
|
||||
char chunkname[MG_BUF_LEN];
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (p[i] == '\n') lines++;
|
||||
if (p[i] == '<' && p[i + 1] == '?') {
|
||||
for (j = i + 1; j < len ; j++) {
|
||||
if (p[j] == '\n') lualines++;
|
||||
if (p[j] == '?' && p[j + 1] == '>') {
|
||||
mg_write(conn, p + pos, i - pos);
|
||||
|
||||
snprintf(chunkname, sizeof(chunkname), "@%s+%i", path, lines);
|
||||
lua_pushlightuserdata(L, conn);
|
||||
lua_pushcclosure(L, lsp_error, 1);
|
||||
if (luaL_loadbuffer(L, p + (i + 2), j - (i + 2), chunkname)) {
|
||||
// Syntax error or OOM. Error message is pushed on stack.
|
||||
lua_pcall(L, 1, 0, 0);
|
||||
} else {
|
||||
// Success loading chunk. Call it.
|
||||
lua_pcall(L, 0, 0, 1);
|
||||
}
|
||||
|
||||
pos = j + 2;
|
||||
i = pos - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lualines > 0) {
|
||||
lines += lualines;
|
||||
lualines = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i > pos) {
|
||||
mg_write(conn, p + pos, i - pos);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lsp_write(lua_State *L) {
|
||||
int i, num_args;
|
||||
const char *str;
|
||||
size_t size;
|
||||
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
||||
|
||||
num_args = lua_gettop(L);
|
||||
for (i = 1; i <= num_args; i++) {
|
||||
if (lua_isstring(L, i)) {
|
||||
str = lua_tolstring(L, i, &size);
|
||||
mg_write(conn, str, size);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lsp_read(lua_State *L) {
|
||||
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
||||
char buf[1024];
|
||||
int len = mg_read(conn, buf, sizeof(buf));
|
||||
|
||||
if (len <= 0) return 0;
|
||||
lua_pushlstring(L, buf, len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// mg.include: Include another .lp file
|
||||
static int lsp_include(lua_State *L) {
|
||||
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
||||
struct file file = STRUCT_FILE_INITIALIZER;
|
||||
if (handle_lsp_request(conn, lua_tostring(L, -1), &file, L)) {
|
||||
// handle_lsp_request returned an error code, meaning an error occured in
|
||||
// the included page and mg.onerror returned non-zero. Stop processing.
|
||||
lsp_abort(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// mg.cry: Log an error. Default value for mg.onerror.
|
||||
static int lsp_cry(lua_State *L){
|
||||
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
||||
cry(conn, "%s", lua_tostring(L, -1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// mg.redirect: Redirect the request (internally).
|
||||
static int lsp_redirect(lua_State *L) {
|
||||
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
|
||||
conn->request_info.uri = lua_tostring(L, -1);
|
||||
handle_request(conn);
|
||||
lsp_abort(L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prepare_lua_environment(struct mg_connection *conn, lua_State *L) {
|
||||
const struct mg_request_info *ri = &conn->request_info;
|
||||
extern void luaL_openlibs(lua_State *);
|
||||
int i;
|
||||
|
||||
luaL_openlibs(L);
|
||||
#ifdef USE_LUA_SQLITE3
|
||||
{ extern int luaopen_lsqlite3(lua_State *); luaopen_lsqlite3(L); }
|
||||
#endif
|
||||
|
||||
luaL_newmetatable(L, LUASOCKET);
|
||||
lua_pushliteral(L, "__index");
|
||||
luaL_newlib(L, luasocket_methods);
|
||||
lua_rawset(L, -3);
|
||||
lua_pop(L, 1);
|
||||
lua_register(L, "connect", lsp_connect);
|
||||
|
||||
if (conn == NULL) return;
|
||||
|
||||
// Register mg module
|
||||
lua_newtable(L);
|
||||
|
||||
reg_function(L, "read", lsp_read, conn);
|
||||
reg_function(L, "write", lsp_write, conn);
|
||||
reg_function(L, "cry", lsp_cry, conn);
|
||||
reg_function(L, "include", lsp_include, conn);
|
||||
reg_function(L, "redirect", lsp_redirect, conn);
|
||||
reg_string(L, "version", MONGOOSE_VERSION);
|
||||
|
||||
// Export request_info
|
||||
lua_pushstring(L, "request_info");
|
||||
lua_newtable(L);
|
||||
reg_string(L, "request_method", ri->request_method);
|
||||
reg_string(L, "uri", ri->uri);
|
||||
reg_string(L, "http_version", ri->http_version);
|
||||
reg_string(L, "query_string", ri->query_string);
|
||||
reg_int(L, "remote_ip", ri->remote_ip);
|
||||
reg_int(L, "remote_port", ri->remote_port);
|
||||
reg_int(L, "num_headers", ri->num_headers);
|
||||
lua_pushstring(L, "http_headers");
|
||||
lua_newtable(L);
|
||||
for (i = 0; i < ri->num_headers; i++) {
|
||||
reg_string(L, ri->http_headers[i].name, ri->http_headers[i].value);
|
||||
}
|
||||
lua_rawset(L, -3);
|
||||
lua_rawset(L, -3);
|
||||
|
||||
lua_setglobal(L, "mg");
|
||||
|
||||
// Register default mg.onerror function
|
||||
luaL_dostring(L, "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
|
||||
"debug.traceback(e, 1)) end");
|
||||
}
|
||||
|
||||
static int lua_error_handler(lua_State *L) {
|
||||
const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
|
||||
|
||||
lua_getglobal(L, "mg");
|
||||
if (!lua_isnil(L, -1)) {
|
||||
lua_getfield(L, -1, "write"); // call mg.write()
|
||||
lua_pushstring(L, error_msg);
|
||||
lua_pushliteral(L, "\n");
|
||||
lua_call(L, 2, 0);
|
||||
luaL_dostring(L, "mg.write(debug.traceback(), '\\n')");
|
||||
} else {
|
||||
printf("Lua error: [%s]\n", error_msg);
|
||||
luaL_dostring(L, "print(debug.traceback(), '\\n')");
|
||||
}
|
||||
// TODO(lsm): leave the stack balanced
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
|
||||
const char *fmt, ...) {
|
||||
char buf[MG_BUF_LEN];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (L == NULL) {
|
||||
send_http_error(conn, 500, http_500_error, "%s", buf);
|
||||
} else {
|
||||
lua_pushstring(L, buf);
|
||||
lua_error(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;
|
||||
}
|
||||
#endif // USE_LUA
|
||||
|
@ -222,7 +222,7 @@ static int event_handler(struct mg_event *event) {
|
||||
|
||||
if (!strcmp(ri->uri, "/upload")) {
|
||||
test_upload(event->conn, "lua_5.2.1.h", "./f1.txt");
|
||||
test_upload(event->conn, "mod_lua.c", "./f2.txt");
|
||||
test_upload(event->conn, "lsqlite3.c", "./f2.txt");
|
||||
ASSERT(mg_upload(event->conn, ".", NULL, 0) == NULL);
|
||||
|
||||
mg_printf(event->conn, "HTTP/1.0 200 OK\r\n"
|
||||
@ -330,7 +330,7 @@ static void test_mg_upload(void) {
|
||||
|
||||
// Upload two files
|
||||
ASSERT((file_data = read_file("lua_5.2.1.h", &file_len)) != NULL);
|
||||
ASSERT((file2_data = read_file("mod_lua.c", &file2_len)) != NULL);
|
||||
ASSERT((file2_data = read_file("lsqlite3.c", &file2_len)) != NULL);
|
||||
post_data = NULL;
|
||||
post_data_len = alloc_printf(&post_data, 0,
|
||||
// First file
|
||||
|
Loading…
Reference in New Issue
Block a user