Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
mongoose
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
esp
mongoose
Commits
8c1866a4
Commit
8c1866a4
authored
Sep 26, 2012
by
Sergey Lyubka
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Lua server pages support
parent
78ea0455
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
279 additions
and
14 deletions
+279
-14
Makefile
Makefile
+27
-8
mongoose.c
mongoose.c
+156
-1
page.lsp
test/page.lsp
+40
-0
unit_test.c
test/unit_test.c
+56
-5
No files found.
Makefile
View file @
8c1866a4
...
...
@@ -22,8 +22,11 @@ all:
### UNIX build: linux, bsd, mac, rtems
##########################################################################
# Add $(LUA_FLAGS) to CFLAGS below if you want to build with Lua
LUA
=
lua-5.2.1/src
LUA_FLAGS
=
-DUSE_LUA
-I
$(LUA)
-L
$(LUA)
-llua
-lm
GCC_WARNS
=
-W
-Wall
-pedantic
# -Wno-missing-field-initializers -Wno-unused-parameter -Wno-format-zero-length -Wno-missing-braces
CFLAGS
=
-std
=
c99
-O2
$(GCC_WARNS)
$(COPT)
MAC_SHARED
=
-flat_namespace
-bundle
-undefined
suppress
LINFLAGS
=
-ldl
-pthread
$(CFLAGS)
...
...
@@ -64,14 +67,26 @@ CYA = e:/cyassl-2.0.0rc2
#DBG = /Zi /DDEBUG /Od
DBG
=
/DNDEBUG /O1
CL
=
$(MSVC)
/bin/cl /MD /TC /nologo
$(DBG)
/Gz /W3 /DNO_SSL_DL
\
/I
$(MSVC)
/include
/I
$(MSVC)
/include
/DUSE_LUA /I
$(LUA)
GUILIB
=
user32.lib shell32.lib
LINK
=
/link /incremental:no /libpath:
$(MSVC)
/lib /machine:IX86
\
/subsystem:windows ws2_32.lib advapi32.lib cyassl.lib
/subsystem:windows ws2_32.lib advapi32.lib cyassl.lib
lua.lib
CYAFL
=
/c /I
$(CYA)
/include
-I
$(CYA)
/include/openssl /I
$(MSVC)
/INCLUDE
\
/I
$(CYA)
/ctaocrypt/include /D _LIB /D OPENSSL_EXTRA
CYASRC
=
\
LUA_SOURCES
=
$(LUA)
/lapi.c
$(LUA)
/lcode.c
$(LUA)
/lctype.c
\
$(LUA)
/ldebug.c
$(LUA)
/ldo.c
$(LUA)
/ldump.c
\
$(LUA)
/lfunc.c
$(LUA)
/lgc.c
$(LUA)
/llex.c
\
$(LUA)
/lmem.c
$(LUA)
/lobject.c
$(LUA)
/lopcodes.c
\
$(LUA)
/lparser.c
$(LUA)
/lstate.c
$(LUA)
/lstring.c
\
$(LUA)
/ltable.c
$(LUA)
/ltm.c
$(LUA)
/lundump.c
\
$(LUA)
/lvm.c
$(LUA)
/lzio.c
$(LUA)
/lauxlib.c
\
$(LUA)
/lbaselib.c
$(LUA)
/lbitlib.c
$(LUA)
/lcorolib.c
\
$(LUA)
/ldblib.c
$(LUA)
/liolib.c
$(LUA)
/lmathlib.c
\
$(LUA)
/loslib.c
$(LUA)
/lstrlib.c
$(LUA)
/ltablib.c
\
$(LUA)
/loadlib.c
$(LUA)
/linit.c
CYA_SOURCES
=
\
$(CYA)
/src/cyassl_int.c
\
$(CYA)
/src/cyassl_io.c
\
$(CYA)
/src/keys.c
\
...
...
@@ -104,10 +119,14 @@ CYASRC= \
$(CYA)
/ctaocrypt/src/tfm.c
cyassl.lib
:
$(CL)
$(CYASRC)
$(CYAFL)
$(DEF)
$(MSVC)
/bin/lib
*
.obj /out:
$@
$(CL)
/Fo
$(CYA)
/
$(CYA_SOURCES)
$(CYAFL)
$(DEF)
$(MSVC)
/bin/lib
$(CYA)
/
*
.obj /out:
$@
lua.lib
:
$(CL)
/c /Fo
$(LUA)
/
$(LUA_SOURCES)
$(MSVC)
/bin/lib
$
(
LUA_SOURCES:%.c
=
%.obj
)
/out:
$@
windows
:
cyassl.lib
windows
:
cyassl.lib
lua.lib
$(MSVC)
/bin/rc win32
\r
es.rc
$(CL)
/I win32 main.c mongoose.c /GA
$(LINK)
win32
\r
es.res
\
$(GUILIB)
/out:
$(PROG)
.exe
...
...
@@ -144,4 +163,4 @@ release: clean
F
=
mongoose-
`
perl
-lne
'/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1'
mongoose.c
`
.tgz
;
cd
..
&&
tar
-czf
x mongoose/
{
LICENSE,Makefile,bindings,examples,test,win32,mongoose.c,mongoose.h,mongoose.1,main.c
}
&&
mv
x mongoose/
$$
F
clean
:
rm
-rf
*
.o
*
.core
$(PROG)
*
.obj
*
.so
$(PROG)
.txt
*
.dSYM
*
.tgz
$(PROG)
.exe
*
.dll
*
.lib
rm
-rf
*
.o
*
.core
$(PROG)
*
.obj
*
.so
$(PROG)
.txt
*
.dSYM
*
.tgz
$(PROG)
.exe
*
.dll
*
.lib
\ No newline at end of file
mongoose.c
View file @
8c1866a4
...
...
@@ -218,6 +218,11 @@ typedef int SOCKET;
#include "mongoose.h"
#ifdef USE_LUA
#include <lua.h>
#include <lauxlib.h>
#endif
#define MONGOOSE_VERSION "3.4"
#define PASSWORDS_FILE_NAME ".htpasswd"
#define CGI_ENVIRONMENT_SIZE 4096
...
...
@@ -1530,7 +1535,7 @@ int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
conn
->
last_throttle_bytes
+=
total
;
while
(
total
<
(
int64_t
)
len
&&
conn
->
ctx
->
stop_flag
==
0
)
{
allowed
=
conn
->
throttle
>
(
int64_t
)
len
-
total
?
len
-
total
:
conn
->
throttle
;
(
int64_t
)
len
-
total
:
conn
->
throttle
;
if
((
n
=
push
(
NULL
,
conn
->
client
.
sock
,
conn
->
ssl
,
(
const
char
*
)
buf
,
(
int64_t
)
allowed
))
!=
allowed
)
{
break
;
...
...
@@ -3835,6 +3840,152 @@ static uint32_t get_remote_ip(const struct mg_connection *conn) {
return
ntohl
(
*
(
uint32_t
*
)
&
conn
->
client
.
rsa
.
sin
.
sin_addr
);
}
#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
(
fh
);
CloseHandle
(
mh
);
return
p
;
}
#define munmap(x, y) UnmapViewOfFile(x)
#define MAP_FAILED NULL
#define PROT_READ 0
#else
#include <sys/mman.h>
#endif
static
void
lsp
(
struct
mg_connection
*
conn
,
const
char
*
p
,
int64_t
len
,
lua_State
*
L
)
{
int
i
,
j
,
pos
=
0
;
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
,
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
,
p
+
pos
,
i
-
pos
);
}
}
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
));
lua_settop
(
L
,
0
);
lua_pushlstring
(
L
,
buf
,
len
);
return
1
;
}
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
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
);
// 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"
);
// 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"
);
}
static
void
handle_lsp_request
(
struct
mg_connection
*
conn
,
const
char
*
path
,
const
struct
mgstat
*
st
)
{
void
*
p
=
NULL
;
FILE
*
fp
=
NULL
;
lua_State
*
L
=
NULL
;
if
((
fp
=
fopen
(
path
,
"r"
))
==
NULL
)
{
send_http_error
(
conn
,
404
,
"Not Found"
,
"%s"
,
"File not found"
);
}
else
if
((
p
=
mmap
(
NULL
,
st
->
size
,
PROT_READ
,
0
,
fileno
(
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\n
Connection: close
\r\n\r\n
"
);
prepare_lua_environment
(
conn
,
L
);
lsp
(
conn
,
p
,
st
->
size
,
L
);
}
if
(
L
)
lua_close
(
L
);
if
(
p
)
munmap
(
p
,
st
->
size
);
if
(
fp
)
fclose
(
fp
);
}
#endif // USE_LUA
// This is the heart of the Mongoose's logic.
// This function is called when the request is read, parsed and validated,
// and Mongoose must decide what action to take: serve a file, or
...
...
@@ -3897,6 +4048,10 @@ static void handle_request(struct mg_connection *conn) {
send_http_error
(
conn
,
403
,
"Directory Listing Denied"
,
"Directory listing denied"
);
}
#ifdef USE_LUA
}
else
if
(
match_prefix
(
"**.lsp$"
,
7
,
path
)
>
0
)
{
handle_lsp_request
(
conn
,
path
,
&
st
);
#endif
#if !defined(NO_CGI)
}
else
if
(
match_prefix
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
],
strlen
(
conn
->
ctx
->
config
[
CGI_EXTENSIONS
]),
...
...
test/page.lsp
0 → 100644
View file @
8c1866a4
<html>
<p>
Prime numbers from 0 to 100, calculated by Lua:
</p>
<?
function is_prime(n)
if n <= 0 then return false end
if n <= 2 then return true end
if (n % 2 == 0) then return false end
for i = 3, n / 2, 2 do
if (n % i == 0) then return false end
end
return true
end
for i = 1, 100 do
if is_prime(i) then print('<span>' .. i .. '</span> ') end
end
?>
<p>
Reading POST data from Lua (click submit):
</p>
<form
method=
"POST"
><input
type=
"text"
name=
"t1"
/><input
type=
"submit"
></form>
<pre>
POST data: [
<? post_data = read() print(post_data) ?>
]
request method: [
<? print(request_info.request_method) ?>
]
IP/port: [
<? print(request_info.remote_ip, ':', request_info.remote_port) ?>
]
URI: [
<? print(request_info.uri) ?>
]
HTTP version [
<? print(request_info.http_version) ?>
]
HEADERS:
<?
for name, value in pairs(request_info.http_headers) do
print(name, ':', value, '\n')
end
?>
</pre>
</html>
test/unit_test.c
View file @
8c1866a4
...
...
@@ -31,7 +31,7 @@ static void test_parse_http_request() {
ASSERT
(
strcmp
(
ri
.
http_headers
[
2
].
name
,
"baz
\r\n\r
"
)
==
0
);
ASSERT
(
strcmp
(
ri
.
http_headers
[
2
].
value
,
""
)
==
0
);
// TODO(lsm): add more tests.
// TODO(lsm): add more tests.
}
static
void
test_should_keep_alive
(
void
)
{
...
...
@@ -210,18 +210,18 @@ static void test_base64_encode(void) {
static
void
test_mg_get_var
(
void
)
{
static
const
char
*
post
[]
=
{
"a=1&&b=2&d&=&c=3%20&e="
,
NULL
};
char
buf
[
20
];
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"a"
,
buf
,
sizeof
(
buf
))
==
1
);
ASSERT
(
buf
[
0
]
==
'1'
&&
buf
[
1
]
==
'\0'
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"b"
,
buf
,
sizeof
(
buf
))
==
1
);
ASSERT
(
buf
[
0
]
==
'2'
&&
buf
[
1
]
==
'\0'
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"c"
,
buf
,
sizeof
(
buf
))
==
2
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"c"
,
buf
,
sizeof
(
buf
))
==
2
);
ASSERT
(
buf
[
0
]
==
'3'
&&
buf
[
1
]
==
' '
&&
buf
[
2
]
==
'\0'
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"e"
,
buf
,
sizeof
(
buf
))
==
0
);
ASSERT
(
buf
[
0
]
==
'\0'
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"d"
,
buf
,
sizeof
(
buf
))
==
-
1
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"c"
,
buf
,
2
)
==
-
1
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"d"
,
buf
,
sizeof
(
buf
))
==
-
1
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"c"
,
buf
,
2
)
==
-
1
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"x"
,
NULL
,
10
)
==
-
2
);
ASSERT
(
mg_get_var
(
post
[
0
],
strlen
(
post
[
0
]),
"x"
,
buf
,
0
)
==
-
2
);
...
...
@@ -255,6 +255,54 @@ static void test_next_option(void) {
}
}
#ifdef USE_LUA
static
void
check_lua_expr
(
lua_State
*
L
,
const
char
*
expr
,
const
char
*
value
)
{
const
char
*
v
,
*
var_name
=
"myVar"
;
char
buf
[
100
];
snprintf
(
buf
,
sizeof
(
buf
),
"%s = %s"
,
var_name
,
expr
);
luaL_dostring
(
L
,
buf
);
lua_getglobal
(
L
,
var_name
);
v
=
lua_tostring
(
L
,
-
1
);
printf
(
"%s: %s: [%s] [%s]
\n
"
,
__func__
,
expr
,
v
==
NULL
?
"null"
:
v
,
value
);
ASSERT
((
value
==
NULL
&&
v
==
NULL
)
||
(
value
!=
NULL
&&
v
!=
NULL
&&
!
strcmp
(
value
,
v
)));
}
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\n
hello world!"
;
const
char
*
page
=
"<? print('hi') ?>"
;
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_request
(
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
,
"request_info.request_method"
,
"POST"
);
check_lua_expr
(
L
,
"request_info.uri"
,
"/foo/bar"
);
check_lua_expr
(
L
,
"request_info.num_headers"
,
"2"
);
check_lua_expr
(
L
,
"request_info.remote_ip"
,
"0"
);
check_lua_expr
(
L
,
"request_info.http_headers['Content-Length']"
,
"12"
);
check_lua_expr
(
L
,
"request_info.http_headers['Connection']"
,
"close"
);
luaL_dostring
(
L
,
"post = read()"
);
check_lua_expr
(
L
,
"# post"
,
"12"
);
check_lua_expr
(
L
,
"post"
,
"hello world!"
);
lua_close
(
L
);
}
#endif
int
main
(
void
)
{
test_base64_encode
();
test_match_prefix
();
...
...
@@ -265,5 +313,8 @@ int main(void) {
test_mg_get_var
();
test_set_throttle
();
test_next_option
();
#ifdef USE_LUA
test_lua
();
#endif
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment