mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-28 23:49:44 +08:00
LSP functionality
This commit is contained in:
parent
407877a4d5
commit
18b1e95350
@ -1,7 +1,11 @@
|
||||
HTTP/1.0 200 OK
|
||||
Content-Type: text/html
|
||||
|
||||
<html><body>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<p>This is an example Lua server page served by
|
||||
@ -22,6 +26,7 @@ all requests done previously.</p>
|
||||
-- db:trace(function(data, sql) mg.write('Executing: ', sql: '\n') end, nil)
|
||||
|
||||
-- Create a table if it is not created already
|
||||
db:exec('PRAGMA encoding="UTF-8"; ')
|
||||
db:exec([[
|
||||
CREATE TABLE IF NOT EXISTS requests (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@ -54,4 +59,9 @@ all requests done previously.</p>
|
||||
-- Close database
|
||||
db:close()
|
||||
?>
|
||||
</pre></body></html>
|
||||
</pre>
|
||||
|
||||
This is an example on how to include files a-la SSI:
|
||||
<pre><? mg.write(io.open('dll.def'):read('*all')) ?></pre>
|
||||
|
||||
</body></html>
|
||||
|
@ -1,74 +1,59 @@
|
||||
# Mongoose Lua Server Pages
|
||||
|
||||
Pre-built Windows and Mac mongoose binaries have built-in Lua Server Pages
|
||||
support. That means it is possible to write PHP-like scripts with mongoose,
|
||||
Pre-built Windows and Mac mongoose binaries support Lua Server Pages
|
||||
functionality.
|
||||
That means it is possible to write PHP-like scripts with mongoose
|
||||
using Lua programming language instead of PHP. Lua is known
|
||||
for it's speed and small size. Mongoose uses Lua version 5.2.1, the
|
||||
documentation for it can be found at
|
||||
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
|
||||
|
||||
To create a Lua Page, make sure a file has `.lp` extension. For example,
|
||||
let's say it is going to be `my_page.lp`. The contents of the file, just like
|
||||
with PHP, is HTML with embedded Lua code. Lua code must be enclosed in
|
||||
`<? ?>` blocks, and can appear anywhere on the page. For example, to
|
||||
print current weekday name, one can write:
|
||||
To create a Lua Page, make a file that is called `<something>.lp`. For example,
|
||||
let's say it is going to be `my_page.lp`. It is important to have a file
|
||||
name that ends up with `.lp`, cause this is the way mongoose recognises
|
||||
Lua Page file. The contents of the file, just like
|
||||
with PHP, is HTML with embedded Lua code. Lua code must be enclosed within
|
||||
`<? ?>` blocks, and can appear anywhere on the page.
|
||||
|
||||
<p>
|
||||
<span>Today is:</span>
|
||||
<? mg.write(os.date("%A")) ?>
|
||||
</p>
|
||||
Mongoose does not send HTTP headers for Lua pages. Therefore,
|
||||
every Lua Page must begin with HTTP status line and headers, like this:
|
||||
|
||||
<? mg.write('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
|
||||
<html><body>
|
||||
<span>Today is:</span> <? mg.write(os.date("%A")) ?>
|
||||
</body></html>
|
||||
|
||||
Note that this example uses function `mg.write()`, which prints data to the
|
||||
web page. Using function `mg.write()` is the way to generate web content from
|
||||
inside Lua code. In addition to `mg.write()`, all standard library functions
|
||||
are accessible from the Lua code (please check reference manual for details),
|
||||
and also information about the request is available in `mg.request_info` object,
|
||||
like request method, all headers, etcetera. Please refer to
|
||||
are accessible from the Lua code (please check reference manual for details).
|
||||
Information about the request is available in `mg.request_info` object.
|
||||
I contains request method, all headers, etcetera. Please refer to
|
||||
`struct mg_request_info` definition in
|
||||
[mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h)
|
||||
to see what kind of information is present in `mg.request_info` object. Also,
|
||||
to see what is available in `mg.request_info`. Also,
|
||||
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp) and
|
||||
[prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp)
|
||||
contains some example code that uses `request_info` and other functions(form submitting for example).
|
||||
contain some example code that uses `request_info` and other functions,
|
||||
like form submission.
|
||||
|
||||
Mongoose exports the following to the Lua server page:
|
||||
|
||||
mg.read() -- reads a chunk from POST data, returns it as a string
|
||||
mg.write(str) -- writes string to the client
|
||||
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
|
||||
sqlite3 -- Sqlite3 interface
|
||||
|
||||
-- Connect to the remote TCP server. This function is an implementation
|
||||
-- of simple socket interface. It returns a socket object with three
|
||||
-- methods: send, recv, close, which are synchronous (blocking).
|
||||
-- connect() throws an exception on connection error.
|
||||
connect(host, port, use_ssl)
|
||||
slite3 functions are documented at [lua.sqlite.org](http://lua.sqlite.org/),
|
||||
and usage example is at
|
||||
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp).
|
||||
|
||||
-- Example of using connect() interface:
|
||||
local host = 'code.google.com' -- IP address or domain name
|
||||
local ok, sock = pcall(connect, host, 80, 1)
|
||||
if ok then
|
||||
sock:send('GET /p/mongoose/ HTTP/1.0\r\n' ..
|
||||
'Host: ' .. host .. '\r\n\r\n')
|
||||
local reply = sock:recv()
|
||||
sock:close()
|
||||
-- reply now contains the web page https://code.google.com/p/mongoose
|
||||
end
|
||||
Using Lua scripting it is easy to emulate SSI functionality. For example,
|
||||
to include the content of another file, one can write:
|
||||
|
||||
<? mg.write(io.open('MY_FILE.TXT'):read('*all')) ?>
|
||||
|
||||
**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') ?>
|
||||
<html><body>
|
||||
... the rest of the web page ...
|
||||
|
||||
To serve Lua Page, mongoose creates Lua context. That context is used for
|
||||
To serve a 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
|
||||
share the same context. If one block defines a variable, for example, that
|
||||
variable is visible in the block that follows.
|
||||
|
||||
|
||||
|
71
mongoose.c
71
mongoose.c
@ -156,7 +156,7 @@ struct ll { struct ll *prev, *next; };
|
||||
#define MAX_REQUEST_SIZE 16384
|
||||
#define IOBUF_SIZE 8192
|
||||
#define MAX_PATH_SIZE 8192
|
||||
#define LUA_SCRIPT_PATTERN "**.mg.lua$"
|
||||
#define LUA_SCRIPT_PATTERN "**.lp$"
|
||||
#define CGI_ENVIRONMENT_SIZE 4096
|
||||
#define MAX_CGI_ENVIR_VARS 64
|
||||
#define ENV_EXPORT_TO_CGI "MONGOOSE_CGI"
|
||||
@ -2802,6 +2802,23 @@ int mg_parse_header(const char *str, const char *var_name, char *buf,
|
||||
#ifdef USE_LUA
|
||||
#include "lua_5.2.1.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 reg_string(struct lua_State *L, const char *name, const char *val) {
|
||||
lua_pushstring(L, name);
|
||||
lua_pushstring(L, val);
|
||||
@ -3003,22 +3020,50 @@ static int lua_error_handler(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_lua_request(struct connection *conn, const char *path) {
|
||||
lua_State *L;
|
||||
static void lsp(struct connection *conn, const char *p, int len, lua_State *L) {
|
||||
int i, j, pos = 0;
|
||||
|
||||
if (path != NULL && (L = luaL_newstate()) != NULL) {
|
||||
for (i = 0; i < len; i++) {
|
||||
if (p[i] == '<' && p[i + 1] == '?') {
|
||||
for (j = i + 1; j < len ; j++) {
|
||||
if (p[j] == '?' && p[j + 1] == '>') {
|
||||
mg_write(&conn->mg_conn, p + pos, i - pos);
|
||||
if (luaL_loadbuffer(L, p + (i + 2), j - (i + 2), "") == LUA_OK) {
|
||||
lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||
}
|
||||
pos = j + 2;
|
||||
i = pos - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i > pos) mg_write(&conn->mg_conn, p + pos, i - pos);
|
||||
}
|
||||
|
||||
static void handle_lsp_request(struct connection *conn, const char *path,
|
||||
file_stat_t *st) {
|
||||
void *p = NULL;
|
||||
lua_State *L = NULL;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if ((fp = fopen(path, "r")) == NULL ||
|
||||
(p = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE,
|
||||
fileno(fp), 0)) == MAP_FAILED ||
|
||||
(L = luaL_newstate()) == NULL) {
|
||||
send_http_error(conn, 500);
|
||||
} else {
|
||||
// We're not sending HTTP headers here, Lua page must do it.
|
||||
prepare_lua_environment(&conn->mg_conn, L);
|
||||
lua_pushcclosure(L, &lua_error_handler, 0);
|
||||
|
||||
lua_pushglobaltable(L);
|
||||
|
||||
if (luaL_loadfile(L, path) != 0) {
|
||||
lua_error_handler(L);
|
||||
}
|
||||
lua_pcall(L, 0, 0, -2);
|
||||
lua_close(L);
|
||||
lsp(conn, p, st->st_size, L);
|
||||
close_local_endpoint(conn);
|
||||
}
|
||||
close_local_endpoint(conn);
|
||||
|
||||
if (L != NULL) lua_close(L);
|
||||
if (p != NULL) munmap(p, st->st_size);
|
||||
if (fp != NULL) fclose(fp);
|
||||
}
|
||||
#endif // USE_LUA
|
||||
|
||||
@ -3090,7 +3135,7 @@ static void open_local_endpoint(struct connection *conn) {
|
||||
}
|
||||
} else if (match_prefix(lua_pat, sizeof(lua_pat) - 1, path) > 0) {
|
||||
#ifdef USE_LUA
|
||||
handle_lua_request(conn, path);
|
||||
handle_lsp_request(conn, path, &st);
|
||||
#else
|
||||
send_http_error(conn, 501);
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user