Commit 2e232b33 authored by Sergey Lyubka's avatar Sergey Lyubka

Lua functionality change: print renamed to mg.write, read renamed to mg.read....

Lua functionality change: print renamed to mg.write, read renamed to mg.read. Expanded user manual, fixed example pages.
parent d72645bf
...@@ -302,35 +302,40 @@ print current weekday name, one can write: ...@@ -302,35 +302,40 @@ print current weekday name, one can write:
<p> <p>
<span>Today is:</span> <span>Today is:</span>
<? print(os.date("%A")) ?> <? mg.write(os.date("%A")) ?>
</p> </p>
Note that this example uses function `print()`, which prints data to the Note that this example uses function `mg.write()`, which prints data to the
web page. Using function `print()` is the way to generate web content from web page. Using function `mg.write()` is the way to generate web content from
inside Lua code. In addition to `print()`, all standard library functions inside Lua code. In addition to `mg.write()`, all standard library functions
are accessible from the Lua code (please check reference manual for details), are accessible from the Lua code (please check reference manual for details),
and also information about the request is available in `request_info` object, and also information about the request is available in `mg.request_info` object,
like request method, all headers, etcetera. Please refer to like request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in `struct mg_request_info` definition in
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h) [mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h)
to see what kind of information is present in `request_info` object. Also, to see what kind of information is present in `mg.request_info` object. Also,
[page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp) and [page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp) and
[prime_numbers.lp](https://github.com/valenok/mongoose/blob/master/examples/lua/prime_numbers.lp) [prime_numbers.lp](https://github.com/valenok/mongoose/blob/master/examples/lua/prime_numbers.lp)
contains some example code that uses `request_info` and other functions(form submitting for example). contains some example code that uses `request_info` and other functions(form submitting for example).
Mongoose exports the following to the Lua server page:
One substantial difference of mongoose's Lua Pages and PHP is that Mongoose mg.read() -- reads a chunk from POST data, returns it as a string
expects Lua page to output HTTP headers. Therefore, **at the very beginning of mg.write(str) -- writes string to the client
every Lua Page must be a Lua block that outputs HTTP headers**, like this: mg.include(path) -- sources another Lua file
mg.redirect(uri) -- internal redirect to a given URI
mg.onerror(msg) -- error handler, can be overridden
mg.version -- a string that holds Mongoose version
mg.request_info -- a table with request information
**IMPORTANT: Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP reply line and headers**, like this:
<? print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?> <? print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
<html><body> <html><body>
... the rest of the web page ... ... the rest of the web page ...
It is easy to do things like redirects, for example:
<? print('HTTP/1.0 302 Found\r\nLocation: http://google.com\r\n\r\n') ?>
To serve Lua Page, mongoose creates Lua context. That context is used for To serve Lua Page, mongoose creates Lua context. That context is used for
all Lua blocks within the page. That means, all Lua blocks on the same page all Lua blocks within the page. That means, all Lua blocks on the same page
share the same context. If one block defines a variable, for example, that share the same context. If one block defines a variable, for example, that
......
<? HTTP/1.0 200 OK
-- Lua server pages have full control over the output, including HTTP Content-Type: text/html
-- headers they send to the client. Send HTTP headers:
print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n')
?>
<html> <html>
<p>Prime numbers from 0 to 100, calculated by Lua:</p> <p>Prime numbers from 0 to 100, calculated by Lua:</p>
...@@ -18,7 +15,7 @@ ...@@ -18,7 +15,7 @@
end end
for i = 1, 100 do for i = 1, 100 do
if is_prime(i) then print('<span>' .. i .. '</span>&nbsp;') end if is_prime(i) then mg.write('<span>' .. i .. '</span>&nbsp;') end
end end
?> ?>
...@@ -27,15 +24,16 @@ ...@@ -27,15 +24,16 @@
<form method="POST" ><input type="text" name="t1"/><input type="submit"></form> <form method="POST" ><input type="text" name="t1"/><input type="submit"></form>
<pre> <pre>
POST data: [<? print(read())?>] POST data: [<? mg.write(mg.read())?>]
request method: [<? print(request_info.request_method) ?>] request method: [<? mg.write(mg.request_info.request_method) ?>]
IP/port: [<? print(request_info.remote_ip, ':', request_info.remote_port) ?>] IP/port: [<? mg.write(mg.request_info.remote_ip, ':',
URI: [<? print(request_info.uri) ?>] mg.request_info.remote_port) ?>]
HTTP version [<? print(request_info.http_version) ?>] URI: [<? mg.write(mg.request_info.uri) ?>]
HTTP version [<? mg.write(mg.request_info.http_version) ?>]
HEADERS: HEADERS:
<? <?
for name, value in pairs(request_info.http_headers) do for name, value in pairs(mg.request_info.http_headers) do
print(name, ':', value, '\n') mg.write(name, ':', value, '\n')
end end
?> ?>
</pre> </pre>
......
#include <lua.h>
#include <lauxlib.h>
#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 void handle_request(struct mg_connection *);
static int handle_lsp_request(struct mg_connection *, const char *,
struct file *, struct lua_State *);
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) 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 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 void prepare_lua_environment(struct mg_connection *conn, lua_State *L) {
const struct mg_request_info *ri = mg_get_request_info(conn);
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
// 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 void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
const char *fmt, ...) {
char buf[MG_BUF_LEN];
va_list ap;
int len;
va_start(ap, fmt);
len = 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;
int error = 1;
// We need both mg_stat to get file size, and mg_fopen to get fd
if (!mg_stat(conn, path, filep) || !mg_fopen(conn, path, "r", filep)) {
lsp_send_err(conn, ls, "File [%s] not found", path);
} else if (filep->membuf == NULL &&
(p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
fileno(filep->fp), 0)) == MAP_FAILED) {
lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
fileno(filep->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);
if (conn->ctx->callbacks.init_lua != NULL) {
conn->ctx->callbacks.init_lua(conn, L);
}
}
error = lsp(conn, path, filep->membuf == NULL ? p : filep->membuf,
filep->size, L);
}
if (L != NULL && ls == NULL) lua_close(L);
if (p != NULL) munmap(p, filep->size);
mg_fclose(filep);
return error;
}
...@@ -248,11 +248,6 @@ typedef int SOCKET; ...@@ -248,11 +248,6 @@ typedef int SOCKET;
#include "mongoose.h" #include "mongoose.h"
#ifdef USE_LUA
#include <lua.h>
#include <lauxlib.h>
#endif
#define MONGOOSE_VERSION "3.8" #define MONGOOSE_VERSION "3.8"
#define PASSWORDS_FILE_NAME ".htpasswd" #define PASSWORDS_FILE_NAME ".htpasswd"
#define CGI_ENVIRONMENT_SIZE 4096 #define CGI_ENVIRONMENT_SIZE 4096
...@@ -3983,290 +3978,7 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) { ...@@ -3983,290 +3978,7 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) {
} }
#ifdef USE_LUA #ifdef USE_LUA
#include "mod_lua.c"
#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 void handle_request(struct mg_connection *);
static int handle_lsp_request(struct mg_connection *, const char *,
struct file *, struct lua_State *);
static int lsp_mg_error(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
int top = lua_gettop(L);
if (top < 1) lua_pushstring(L, "unknown error");
// Get mg.onerror.
lua_getglobal(L, "mg");
lua_getfield(L, -1, "onerror");
// If mg.onerror is nil, silently stop processing chunks.
if (lua_isnil(L, -1)) {
lua_pushinteger(L, 1);
return 1;
}
// Call mg.onerror.
lua_pushvalue(L, top);
lua_remove(L, top);
if (lua_pcall(L, 1, 1, 0)) {
// If mg.onerror fails, cry the error message and stop processing chunks.
cry(conn, "mg.onerror failed: %s", lua_tostring(L, -1));
lua_pushinteger(L, 1);
return 1;
}
// Return the return value from mg.onerror. Non-0 = stop processing chunks.
return 1;
}
// 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, result, 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);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, lsp_mg_error, 1);
snprintf (chunkname, sizeof(chunkname), "@%s+%i", path, lines);
if (luaL_loadbuffer(L, p + (i + 2), j - (i + 2), chunkname)) {
lua_pcall(L, 1, 1, 0);
result = lua_tointeger(L, -1);
if (result) return result;
} else {
lua_pcall(L, 0, 0, 1);
result = lua_tointeger(L, -1);
if (result) return result;
}
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_mg_print(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_mg_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) return 0;
lua_pushlstring(L, buf, len);
return 1;
}
// mg.include: Include another .lp file
static int lsp_mod_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_mod_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_mod_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 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 void prepare_lua_environment(struct mg_connection *conn, lua_State *L) {
const struct mg_request_info *ri = mg_get_request_info(conn);
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
// Register "print" function which calls mg_write()
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, lsp_mg_print, 1);
lua_setglobal(L, "print");
// Register mg_read()
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, lsp_mg_read, 1);
lua_setglobal(L, "read");
// Register mg module
lua_newtable(L);
reg_function(L, "cry", lsp_mod_cry, conn);
reg_function(L, "include", lsp_mod_include, conn);
reg_function(L, "onerror", lsp_mod_cry, conn);
reg_function(L, "redirect", lsp_mod_redirect, conn);
reg_string(L, "version", MONGOOSE_VERSION);
lua_setglobal(L, "mg");
// Export 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_setglobal(L, "request_info");
}
// Throw a lua error. Called from handle_lsp_request via mg.include
static void send_lua_error(struct lua_State *L,
PRINTF_FORMAT_STRING(const char *fmt), ...)
PRINTF_ARGS(2, 3);
static void send_lua_error(struct lua_State *L, const char *fmt, ...) {
char buf[MG_BUF_LEN];
va_list ap;
int len = 0;
va_start(ap, fmt);
len += vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
va_end(ap);
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;
int error = 1;
if (!mg_stat(conn, path, filep) || !mg_fopen(conn, path, "r", filep)) {
if (ls == NULL) {
send_http_error(conn, 404, "Not Found", "%s", "File not found");
} else {
send_lua_error(ls, "File not found: %s", path);
}
} else if (filep->membuf == NULL &&
(p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
fileno(filep->fp), 0)) == MAP_FAILED) {
if (ls == NULL) {
send_http_error(conn, 500, http_500_error, "mmap(%s, %zu, %d): %s", path,
(size_t) filep->size, fileno(filep->fp), strerror(errno));
} else {
send_lua_error(ls, "mmap(%s, %zu, %d): %s", path,
(size_t) filep->size, fileno(filep->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);
if (conn->ctx->callbacks.init_lua != NULL) {
conn->ctx->callbacks.init_lua(conn, L);
}
}
error = lsp(conn, path, filep->membuf == NULL ? p : filep->membuf,
filep->size, L);
}
if (L && ls == NULL) lua_close(L);
if (p) munmap(p, filep->size);
mg_fclose(filep);
return error;
}
#endif // USE_LUA #endif // USE_LUA
int mg_upload(struct mg_connection *conn, const char *destination_dir) { int mg_upload(struct mg_connection *conn, const char *destination_dir) {
......
<? HTTP/1.0 200 OK
-- Lua server pages have full control over the output, including HTTP Content-Type: text/html
-- headers they send to the client. Send HTTP headers:
print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') <html><body>
?><html><body>
<p>This is an example Lua server page served by <p>This is an example Lua server page served by
<a href="http://code.google.com/p/mongoose">Mongoose web server</a>. <a href="http://code.google.com/p/mongoose">Mongoose web server</a>.
Mongoose has Lua, Sqlite, and other functionality built in the binary. Mongoose has Lua, Sqlite, and other functionality built in the binary.
This example page stores the request in the Sqlite database, and shows This example page stores the request in the Sqlite database, and shows
all requests done previously.</p> all requests done previously.</p>
<p> Today is <? print(os.date("%A")) ?> <p> Today is <? mg.write(os.date("%A")) ?>
<pre> <pre>
<? <?
-- for k,v in pairs(_G) do mg.write(k, '\n') end
-- Open database -- Open database
local db = sqlite3.open('requests.db') local db = sqlite3.open('requests.db')
-- Setup a trace callback, to show SQL statements we'll be executing. -- Setup a trace callback, to show SQL statements we'll be executing.
-- db:trace(function(data, sql) print('Executing: ' .. sql .. '\n') end, nil) -- db:trace(function(data, sql) mg.write('Executing: ', sql: '\n') end, nil)
-- Create a table if it is not created already -- Create a table if it is not created already
db:exec([[ db:exec([[
...@@ -27,24 +28,26 @@ all requests done previously.</p> ...@@ -27,24 +28,26 @@ all requests done previously.</p>
timestamp NOT NULL, timestamp NOT NULL,
method NOT NULL, method NOT NULL,
uri NOT NULL, uri NOT NULL,
user_agent addr
); );
]]) ]])
-- Add entry about this request -- Add entry about this request
local stmt = db:prepare( local stmt = db:prepare(
'INSERT INTO requests VALUES(NULL, datetime("now"), ?, ?, ?);'); 'INSERT INTO requests VALUES(NULL, datetime("now"), ?, ?, ?);');
stmt:bind_values(request_info.request_method, request_info.uri, stmt:bind_values(mg.request_info.request_method,
request_info.http_headers['User-Agent']) mg.request_info.uri,
mg.request_info.remote_port)
stmt:step() stmt:step()
stmt:finalize() stmt:finalize()
-- Show all previous records -- Show all previous records
print('Previous requests:\n') mg.write('Previous requests:\n')
stmt = db:prepare('SELECT * FROM requests ORDER BY id DESC;') stmt = db:prepare('SELECT * FROM requests ORDER BY id DESC;')
while stmt:step() == sqlite3.ROW do while stmt:step() == sqlite3.ROW do
local v = stmt:get_values() local v = stmt:get_values()
print(v[1] .. ' ' .. v[2] .. ' ' .. v[3] .. ' ' mg.write(v[1] .. ' ' .. v[2] .. ' ' .. v[3] .. ' '
.. v[4] .. ' ' .. v[5] .. '\n') .. v[4] .. ' ' .. v[5] .. '\n')
end end
......
...@@ -467,13 +467,13 @@ static void test_lua(void) { ...@@ -467,13 +467,13 @@ static void test_lua(void) {
ASSERT(lua_gettop(L) == 0); ASSERT(lua_gettop(L) == 0);
check_lua_expr(L, "'hi'", "hi"); check_lua_expr(L, "'hi'", "hi");
check_lua_expr(L, "request_info.request_method", "POST"); check_lua_expr(L, "mg.request_info.request_method", "POST");
check_lua_expr(L, "request_info.uri", "/foo/bar"); check_lua_expr(L, "mg.request_info.uri", "/foo/bar");
check_lua_expr(L, "request_info.num_headers", "2"); check_lua_expr(L, "mg.request_info.num_headers", "2");
check_lua_expr(L, "request_info.remote_ip", "0"); check_lua_expr(L, "mg.request_info.remote_ip", "0");
check_lua_expr(L, "request_info.http_headers['Content-Length']", "12"); check_lua_expr(L, "mg.request_info.http_headers['Content-Length']", "12");
check_lua_expr(L, "request_info.http_headers['Connection']", "close"); check_lua_expr(L, "mg.request_info.http_headers['Connection']", "close");
(void) luaL_dostring(L, "post = read()"); (void) luaL_dostring(L, "post = mg.read()");
check_lua_expr(L, "# post", "12"); check_lua_expr(L, "# post", "12");
check_lua_expr(L, "post", "hello world!"); check_lua_expr(L, "post", "hello world!");
lua_close(L); lua_close(L);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment