mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eed09600f7 | ||
|
|
8d6634ff7e | ||
|
|
6c9ed3ca53 | ||
|
|
ede1befffa | ||
|
|
2cd4852321 | ||
|
|
1eb719f2d9 | ||
|
|
bf633082ac | ||
|
|
075a152779 | ||
|
|
c079a13b24 | ||
|
|
113c9d5a02 | ||
|
|
05fa677382 | ||
|
|
ab3c070e1c | ||
|
|
2e6a01b931 | ||
|
|
9fa66bf237 | ||
|
|
98c382e7af | ||
|
|
94c7a3862a | ||
|
|
6869b64b31 | ||
|
|
8faf6f7b72 | ||
|
|
99ddb2f12a | ||
|
|
ca9212c3ca | ||
|
|
c9183f3851 | ||
|
|
0912a7f473 | ||
|
|
38421657b3 | ||
|
|
64cfe1d389 | ||
|
|
69b0b58d46 | ||
|
|
0d442058e5 | ||
|
|
1ef31461bc | ||
|
|
0b09df97ac | ||
|
|
0263e39584 | ||
|
|
d8424726bb | ||
|
|
080cb2dd4b | ||
|
|
786caaecb2 | ||
|
|
eb92b5f1b3 | ||
|
|
c5ba6016aa | ||
|
|
73a845a327 | ||
|
|
6eec552ea4 | ||
|
|
cb62203cf3 | ||
|
|
4fcb64fe90 | ||
|
|
8966f47c7a | ||
|
|
e251375c0c | ||
|
|
672e1ec8c6 | ||
|
|
f8713ede2d | ||
|
|
0b5f854bf0 | ||
|
|
3770020b74 | ||
|
|
9f9a1638f7 | ||
|
|
fb07a937e7 | ||
|
|
025cd283c4 | ||
|
|
b39426dbf7 | ||
|
|
5157bd0960 | ||
|
|
2aaedef4af | ||
|
|
a0b037d288 | ||
|
|
011bdc22b2 | ||
|
|
b437d56736 | ||
|
|
6205e69ab2 | ||
|
|
038f8823f1 | ||
|
|
03dd8367bf | ||
|
|
b597da34da | ||
|
|
bf387f9544 | ||
|
|
365b5e8f8a | ||
|
|
47651766fb | ||
|
|
043ea54a2a | ||
|
|
55c8c82c4b | ||
|
|
557d1f4c49 | ||
|
|
2539a473fe | ||
|
|
6bd35a4c18 | ||
|
|
fb8f0ed4d6 | ||
|
|
3ffdf5459a | ||
|
|
02098b1903 | ||
|
|
c189553c8b | ||
|
|
d970705596 | ||
|
|
5c9ab40601 | ||
|
|
451d077170 | ||
|
|
30d1573346 | ||
|
|
0adef2db5b | ||
|
|
8c1866a4af | ||
|
|
2a7a594b49 | ||
|
|
78ea04556f | ||
|
|
7fe2944477 | ||
|
|
93131417e6 | ||
|
|
6ef5eb0665 | ||
|
|
24103ff5df | ||
|
|
2118de37c3 | ||
|
|
0804ce71d5 | ||
|
|
2ffb558e30 | ||
|
|
05062be889 | ||
|
|
ba6c01e602 | ||
|
|
dfc0f00478 | ||
|
|
ecb2b0e53d | ||
|
|
ed74cd82f5 | ||
|
|
d2be594262 | ||
|
|
1e632d3215 | ||
|
|
5642dfcf38 | ||
|
|
4dff36ffde | ||
|
|
771ce9059c | ||
|
|
e490b30c38 | ||
|
|
f935ef832b | ||
|
|
79cdb77e5d | ||
|
|
ff0c2d3f91 | ||
|
|
6f9901b65c | ||
|
|
bce3a85702 | ||
|
|
f741349d51 | ||
|
|
25863b59a6 | ||
|
|
72c861bb83 | ||
|
|
586574e176 | ||
|
|
0f15954727 | ||
|
|
167338f216 | ||
|
|
d82f6b7607 | ||
|
|
614b219a27 | ||
|
|
35cf8687df | ||
|
|
d883b0f0f9 | ||
|
|
0b942aaaba | ||
|
|
364235e7ae | ||
|
|
ba1f2ced8e | ||
|
|
c4c34a8f4d | ||
|
|
a866f4e174 | ||
|
|
c5916814cd | ||
|
|
349717ac0e | ||
|
|
5d27766424 | ||
|
|
97668ba6c9 | ||
|
|
98fb44f836 | ||
|
|
2260c8ddc0 | ||
|
|
edffc46b98 | ||
|
|
7bd8cc3c0c | ||
|
|
828f6cd7fe | ||
|
|
f9873eb87a | ||
|
|
358e4ffbf5 | ||
|
|
9aad922983 | ||
|
|
d9ab7af8b4 | ||
|
|
05b2a04267 | ||
|
|
4408083b4d | ||
|
|
4f01f101fc | ||
|
|
d9f9911d9b | ||
|
|
93b4562515 | ||
|
|
0bb67e06c1 | ||
|
|
518b3aa726 | ||
|
|
07f3554db3 | ||
|
|
acab70ee7c | ||
|
|
c388bc2dd3 | ||
|
|
8072b0a7d4 | ||
|
|
3f4be595a6 | ||
|
|
5d11901af8 | ||
|
|
43953782f9 | ||
|
|
12e133a5e9 | ||
|
|
e92d4451ef | ||
|
|
fadb60d776 | ||
|
|
0521d78982 | ||
|
|
3602d54a5b | ||
|
|
8428f362c1 | ||
|
|
fafc9c6a20 | ||
|
|
66e088d843 | ||
|
|
4a760ad324 | ||
|
|
c92d7c3bc8 | ||
|
|
ee91109d9f | ||
|
|
30fe257691 | ||
|
|
ab6f145e3e | ||
|
|
83dc425e25 | ||
|
|
001cd78b45 | ||
|
|
3d3359910f | ||
|
|
ee8111e424 | ||
|
|
1861b1137b | ||
|
|
ccf43fe3e3 | ||
|
|
8b491d75b5 | ||
|
|
d70c18d692 |
No files matched your search
@@ -4,36 +4,42 @@
|
|||||||
PROG= mongoose
|
PROG= mongoose
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@echo "make (linux|bsd|solaris|mac|windows|mingw)"
|
@echo "make (linux|bsd|solaris|mac|windows|mingw|cygwin)"
|
||||||
|
|
||||||
# Possible COPT values: (in brackets are rough numbers for 'gcc -O2' on i386)
|
# Possible COPT values: (in brackets are rough numbers for 'gcc -O2' on i386)
|
||||||
# -DHAVE_MD5 - use system md5 library (-2kb)
|
# -DHAVE_MD5 - use system md5 library (-2kb)
|
||||||
# -DNDEBUG - strip off all debug code (-5kb)
|
# -DNDEBUG - strip off all debug code (-5kb)
|
||||||
# -DDEBUG - build debug version (very noisy) (+7kb)
|
# -DDEBUG - build debug version (very noisy) (+7kb)
|
||||||
# -DNO_CGI - disable CGI support (-5kb)
|
# -DNO_CGI - disable CGI support (-5kb)
|
||||||
# -DNO_SSL - disable SSL functionality (-2kb)
|
# -DNO_SSL - disable SSL functionality (-2kb)
|
||||||
# -DCONFIG_FILE=\"file\" - use `file' as the default config file
|
# -DNO_SSL_DL - link against system libssl library (-1kb)
|
||||||
# -DHAVE_STRTOUI64 - use system strtoui64() function for strtoull()
|
# -DCONFIG_FILE=\"file\" - use `file' as the default config file
|
||||||
# -DSSL_LIB=\"libssl.so.<version>\" - use system versioned SSL shared object
|
# -DSSL_LIB=\"libssl.so.<version>\" - use system versioned SSL shared object
|
||||||
# -DCRYPTO_LIB=\"libcrypto.so.<version>\" - use system versioned CRYPTO so
|
# -DCRYPTO_LIB=\"libcrypto.so.<version>\" - use system versioned CRYPTO so
|
||||||
|
# -DUSE_LUA - embed Lua in Mongoose (+100kb)
|
||||||
|
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
### UNIX build: linux, bsd, mac, rtems
|
### UNIX build: linux, bsd, mac, rtems
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
CFLAGS = -W -Wall -std=c99 -pedantic -O2 $(COPT)
|
# To build with Lua, download and unzip Lua 5.2.1 source code into the
|
||||||
MAC_SHARED = -flat_namespace -bundle -undefined suppress
|
# mongoose directory, and then add $(LUA_FLAGS) to CFLAGS below
|
||||||
LINFLAGS = -ldl -pthread $(CFLAGS)
|
LUA = lua-5.2.1/src
|
||||||
LIB = _$(PROG).so
|
LUA_FLAGS = -DUSE_LUA -I$(LUA) -L$(LUA) -llua -lm
|
||||||
#CC = g++
|
|
||||||
|
GCC_WARNS = -W -Wall -pedantic
|
||||||
|
CFLAGS = -std=c99 -O2 $(GCC_WARNS) $(COPT)
|
||||||
|
MAC_SHARED = -flat_namespace -bundle -undefined suppress
|
||||||
|
LINFLAGS = -ldl -pthread $(CFLAGS)
|
||||||
|
LIB = lib$(PROG).so$(MONGOOSE_LIB_SUFFIX)
|
||||||
|
|
||||||
# Make sure that the compiler flags come last in the compilation string.
|
# Make sure that the compiler flags come last in the compilation string.
|
||||||
# If not so, this can break some on some Linux distros which use
|
# If not so, this can break some on some Linux distros which use
|
||||||
# "-Wl,--as-needed" turned on by default in cc command.
|
# "-Wl,--as-needed" turned on by default in cc command.
|
||||||
# Also, this is turned in many other distros in static linkage builds.
|
# Also, this is turned in many other distros in static linkage builds.
|
||||||
linux:
|
linux:
|
||||||
$(CC) mongoose.c -shared -fPIC -fpic -o $(LIB) $(LINFLAGS)
|
$(CC) mongoose.c -shared -fPIC -fpic -o $(LIB) -Wl,-soname,$(LIB) $(LINFLAGS)
|
||||||
$(CC) mongoose.c main.c -o $(PROG) $(LINFLAGS)
|
$(CC) mongoose.c main.c -o $(PROG) $(LINFLAGS)
|
||||||
|
|
||||||
bsd:
|
bsd:
|
||||||
@@ -45,9 +51,9 @@ mac:
|
|||||||
$(CC) mongoose.c main.c -pthread -o $(PROG) $(CFLAGS)
|
$(CC) mongoose.c main.c -pthread -o $(PROG) $(CFLAGS)
|
||||||
|
|
||||||
solaris:
|
solaris:
|
||||||
gcc mongoose.c -pthread -lnsl \
|
$(CC) mongoose.c -pthread -lnsl \
|
||||||
-lsocket -fpic -fPIC -shared -o $(LIB) $(CFLAGS)
|
-lsocket -fpic -fPIC -shared -o $(LIB) $(CFLAGS)
|
||||||
gcc mongoose.c main.c -pthread -lnsl -lsocket -o $(PROG) $(CFLAGS)
|
$(CC) mongoose.c main.c -pthread -lnsl -lsocket -o $(PROG) $(CFLAGS)
|
||||||
|
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
@@ -55,74 +61,86 @@ solaris:
|
|||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
# Using Visual Studio 6.0. To build Mongoose:
|
# Using Visual Studio 6.0. To build Mongoose:
|
||||||
# o Set VC variable below to where VS 6.0 is installed on your system
|
# o Set MSVC variable below to where VS 6.0 is installed on your system
|
||||||
# o Run "PATH_TO_VC6\bin\nmake windows"
|
# o Run "PATH_TO_VC6\bin\nmake windows"
|
||||||
|
|
||||||
VC= z:
|
MSVC = e:/vc6
|
||||||
CYA= y:
|
CYA = e:/cyassl-2.0.0rc2
|
||||||
#DBG= /Zi /DDEBUG /Od
|
#DBG = /Zi /DDEBUG /Od
|
||||||
DBG= /DNDEBUG /O1
|
DBG = /DNDEBUG /O1
|
||||||
CL= cl /MD /TC /nologo $(DBG) /Gz /W3 /DNO_SSL_DL
|
CL = $(MSVC)/bin/cl /MD /TC /nologo $(DBG) /Gz /W3 /DNO_SSL_DL \
|
||||||
GUILIB= user32.lib shell32.lib
|
/I$(MSVC)/include /DUSE_LUA /I$(LUA)
|
||||||
LINK= /link /incremental:no /libpath:$(VC)\lib /subsystem:windows \
|
GUILIB= user32.lib shell32.lib
|
||||||
ws2_32.lib advapi32.lib cyassl.lib
|
LINK = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \
|
||||||
CYAFL = /c /I $(CYA)/include -I $(CYA)/include/openssl \
|
/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
|
/I $(CYA)/ctaocrypt/include /D _LIB /D OPENSSL_EXTRA
|
||||||
|
|
||||||
CYASRC= \
|
LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \
|
||||||
$(CYA)/src/cyassl_int.c \
|
$(LUA)/ldebug.c $(LUA)/ldo.c $(LUA)/ldump.c \
|
||||||
$(CYA)/src/cyassl_io.c \
|
$(LUA)/lfunc.c $(LUA)/lgc.c $(LUA)/llex.c \
|
||||||
$(CYA)/src/keys.c \
|
$(LUA)/lmem.c $(LUA)/lobject.c $(LUA)/lopcodes.c \
|
||||||
$(CYA)/src/tls.c \
|
$(LUA)/lparser.c $(LUA)/lstate.c $(LUA)/lstring.c \
|
||||||
$(CYA)/src/ssl.c \
|
$(LUA)/ltable.c $(LUA)/ltm.c $(LUA)/lundump.c \
|
||||||
$(CYA)/ctaocrypt/src/aes.c \
|
$(LUA)/lvm.c $(LUA)/lzio.c $(LUA)/lauxlib.c \
|
||||||
$(CYA)/ctaocrypt/src/arc4.c \
|
$(LUA)/lbaselib.c $(LUA)/lbitlib.c $(LUA)/lcorolib.c \
|
||||||
$(CYA)/ctaocrypt/src/asn.c \
|
$(LUA)/ldblib.c $(LUA)/liolib.c $(LUA)/lmathlib.c \
|
||||||
$(CYA)/ctaocrypt/src/coding.c \
|
$(LUA)/loslib.c $(LUA)/lstrlib.c $(LUA)/ltablib.c \
|
||||||
$(CYA)/ctaocrypt/src/ctc_asm.c \
|
$(LUA)/loadlib.c $(LUA)/linit.c
|
||||||
$(CYA)/ctaocrypt/src/ctc_misc.c \
|
LUA_OBJECTS = $(LUA_SOURCES:%.c=%.o)
|
||||||
$(CYA)/ctaocrypt/src/cyassl_memory.c \
|
|
||||||
$(CYA)/ctaocrypt/src/des3.c \
|
|
||||||
$(CYA)/ctaocrypt/src/dh.c \
|
|
||||||
$(CYA)/ctaocrypt/src/dsa.c \
|
|
||||||
$(CYA)/ctaocrypt/src/ecc.c \
|
|
||||||
$(CYA)/ctaocrypt/src/hc128.c \
|
|
||||||
$(CYA)/ctaocrypt/src/hmac.c \
|
|
||||||
$(CYA)/ctaocrypt/src/integer.c \
|
|
||||||
$(CYA)/ctaocrypt/src/md4.c \
|
|
||||||
$(CYA)/ctaocrypt/src/md5.c \
|
|
||||||
$(CYA)/ctaocrypt/src/pwdbased.c \
|
|
||||||
$(CYA)/ctaocrypt/src/rabbit.c \
|
|
||||||
$(CYA)/ctaocrypt/src/random.c \
|
|
||||||
$(CYA)/ctaocrypt/src/ripemd.c \
|
|
||||||
$(CYA)/ctaocrypt/src/rsa.c \
|
|
||||||
$(CYA)/ctaocrypt/src/sha.c \
|
|
||||||
$(CYA)/ctaocrypt/src/sha256.c \
|
|
||||||
$(CYA)/ctaocrypt/src/sha512.c \
|
|
||||||
$(CYA)/ctaocrypt/src/tfm.c
|
|
||||||
|
|
||||||
cyassl:
|
CYA_SOURCES = $(CYA)/src/cyassl_int.c $(CYA)/src/cyassl_io.c \
|
||||||
$(CL) $(CYASRC) $(CYAFL) $(DEF)
|
$(CYA)/src/keys.c $(CYA)/src/tls.c $(CYA)/src/ssl.c \
|
||||||
lib *.obj /out:cyassl.lib
|
$(CYA)/ctaocrypt/src/aes.c $(CYA)/ctaocrypt/src/arc4.c \
|
||||||
|
$(CYA)/ctaocrypt/src/asn.c $(CYA)/ctaocrypt/src/coding.c \
|
||||||
|
$(CYA)/ctaocrypt/src/ctc_asm.c $(CYA)/ctaocrypt/src/ctc_misc.c \
|
||||||
|
$(CYA)/ctaocrypt/src/cyassl_memory.c $(CYA)/ctaocrypt/src/des3.c \
|
||||||
|
$(CYA)/ctaocrypt/src/dh.c $(CYA)/ctaocrypt/src/dsa.c \
|
||||||
|
$(CYA)/ctaocrypt/src/ecc.c $(CYA)/ctaocrypt/src/hc128.c \
|
||||||
|
$(CYA)/ctaocrypt/src/hmac.c $(CYA)/ctaocrypt/src/integer.c \
|
||||||
|
$(CYA)/ctaocrypt/src/md4.c $(CYA)/ctaocrypt/src/md5.c \
|
||||||
|
$(CYA)/ctaocrypt/src/pwdbased.c $(CYA)/ctaocrypt/src/rabbit.c \
|
||||||
|
$(CYA)/ctaocrypt/src/random.c $(CYA)/ctaocrypt/src/ripemd.c \
|
||||||
|
$(CYA)/ctaocrypt/src/rsa.c $(CYA)/ctaocrypt/src/sha.c \
|
||||||
|
$(CYA)/ctaocrypt/src/sha256.c $(CYA)/ctaocrypt/src/sha512.c \
|
||||||
|
$(CYA)/ctaocrypt/src/tfm.c
|
||||||
|
|
||||||
windows:
|
cyassl.lib:
|
||||||
rc win32\res.rc
|
$(CL) /Fo$(CYA)/ $(CYA_SOURCES) $(CYAFL) $(DEF)
|
||||||
$(CL) main.c mongoose.c /GA $(LINK) win32\res.res \
|
$(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 lua.lib
|
||||||
|
$(MSVC)/bin/rc win32\res.rc
|
||||||
|
$(CL) /I win32 main.c mongoose.c /GA $(LINK) win32\res.res \
|
||||||
$(GUILIB) /out:$(PROG).exe
|
$(GUILIB) /out:$(PROG).exe
|
||||||
$(CL) mongoose.c /GD $(LINK) /DLL /DEF:win32\dll.def /out:_$(PROG).dll
|
$(CL) mongoose.c /GD $(LINK) /DLL /DEF:win32\dll.def /out:$(PROG).dll
|
||||||
|
|
||||||
# Build for Windows under MinGW
|
# Build for Windows under MinGW
|
||||||
#MINGWDBG= -DDEBUG -O0
|
#MINGWDBG= -DDEBUG -O0 -ggdb
|
||||||
MINGWDBG= -DNDEBUG -Os
|
MINGWDBG= -DNDEBUG -Os
|
||||||
#MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT
|
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
|
||||||
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,windows $(MINGWDBG)
|
#MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,windows $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
|
||||||
mingw:
|
mingw:
|
||||||
windres win32\res.rc win32\res.o
|
windres win32\res.rc win32\res.o
|
||||||
gcc $(MINGWOPT) mongoose.c -lws2_32 \
|
$(CC) $(MINGWOPT) mongoose.c -lws2_32 \
|
||||||
-shared -Wl,--out-implib=$(PROG).lib -o _$(PROG).dll
|
-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
|
||||||
gcc $(MINGWOPT) mongoose.c main.c win32\res.o -lws2_32 -ladvapi32 \
|
$(CC) $(MINGWOPT) -Iwin32 mongoose.c main.c win32\res.o -lws2_32 -ladvapi32 \
|
||||||
-o $(PROG).exe
|
-o $(PROG).exe
|
||||||
|
|
||||||
|
# Build for Windows under Cygwin
|
||||||
|
#CYGWINDBG= -DDEBUG -O0 -ggdb
|
||||||
|
CYGWINDBG= -DNDEBUG -Os
|
||||||
|
CYGWINOPT= -W -Wall -mthreads -Wl,--subsystem,console $(CYGWINDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
|
||||||
|
cygwin:
|
||||||
|
windres ./win32/res.rc ./win32/res.o
|
||||||
|
$(CC) $(CYGWINOPT) mongoose.c -lws2_32 \
|
||||||
|
-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
|
||||||
|
$(CC) $(CYGWINOPT) -Iwin32 mongoose.c main.c ./win32/res.o -lws2_32 \
|
||||||
|
-ladvapi32 -o $(PROG).exe
|
||||||
|
|
||||||
##########################################################################
|
##########################################################################
|
||||||
### Manuals, cleanup, test, release
|
### Manuals, cleanup, test, release
|
||||||
@@ -135,12 +153,11 @@ man:
|
|||||||
# "TEST=unit make test" - perform unit test only
|
# "TEST=unit make test" - perform unit test only
|
||||||
# "TEST=embedded" - test embedded API by building and testing test/embed.c
|
# "TEST=embedded" - test embedded API by building and testing test/embed.c
|
||||||
# "TEST=basic_tests" - perform basic tests only (no CGI, SSI..)
|
# "TEST=basic_tests" - perform basic tests only (no CGI, SSI..)
|
||||||
test: do_test
|
tests:
|
||||||
do_test:
|
|
||||||
perl test/test.pl $(TEST)
|
perl test/test.pl $(TEST)
|
||||||
|
|
||||||
release: clean
|
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
|
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:
|
clean:
|
||||||
rm -rf *.o *.core $(PROG) *.obj *.so $(PROG).txt *.dSYM *.tgz
|
rm -rf *.o *.core $(PROG) *.obj *.so $(PROG).txt *.dSYM *.tgz $(PROG).exe *.dll *.lib win32/res.o
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
Mongoose is easy to use web server. It also can be used as embedded web server library to provide web interface to applications.
|
||||||
|
|
||||||
|
Mongoose executable does not depend on any external library or configuration. If it is copied to any directory and launched from there, it starts to serve that directory on port 8080 (so to access files, go to http://localhost:8080). If some additional config is required - for example, different listening port or IP-based access control, that can be done via command line flags or configuration file, which should be created in the same directory where mongoose itself lives. This makes Mongoose perfect for all sorts of demos, quick tests, file sharing, and Web programming.
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Crossplatform - works on Windows, MacOS and most flavors of UNIX
|
||||||
|
- CGI, SSL, SSI, Digest (MD5) authorization, Websocket, WEbDAV support
|
||||||
|
- Lua server pages (like PHP, but using Lua as a language instead of PHP)
|
||||||
|
- Resumed download, URL rewrite, IP-based ACL, Windows service
|
||||||
|
- Excluding files from serving by URI pattern (file blacklist)
|
||||||
|
- Download speed limit based on client subnet or URI pattern
|
||||||
|
- Small footprint: executable size is 50 kB on Linux 2.6 i386 system
|
||||||
|
- 130 kilobytes Windows executable with all of the above compiled in, and no dependencies
|
||||||
|
- Embeddable with simple and clean API ([mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h)). The source is in single [mongoose.c](https://github.com/valenok/mongoose/blob/master/mongoose.c) file to make things easy.
|
||||||
|
- Embedding examples: [hello.c](https://github.com/valenok/mongoose/blob/master/examples/hello.c), [post.c](https://github.com/valenok/mongoose/blob/master/examples/post.c), [upload.c](https://github.com/valenok/mongoose/blob/master/examples/upload.c), [websocket.c](https://github.com/valenok/mongoose/blob/master/examples/websocket.c)
|
||||||
|
- Super-liberal MIT license, great for commercial users!
|
||||||
|
|
||||||
|
|
||||||
|
Mailing list
|
||||||
|
------------
|
||||||
|
|
||||||
|
You can read it online, subscribe to, or send a message at [mongoose-users](http://groups.google.com/group/mongoose-users).
|
||||||
|
|
||||||
|
|
||||||
|
Keep Sergey happy
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
I have a [books wishlist](http://amzn.com/w/1OC2ZCPTQYIEP?sort=priority) on Amazon. If you feel brave, you can buy me a book!
|
||||||
|
Many thanks to all who already did so: T.Barmann, D.Hughes, J.C.Sloan and 4 others. Appreciated, guys, you keep my brains going!
|
||||||
@@ -11,24 +11,24 @@ import sys
|
|||||||
def EventHandler(event, conn):
|
def EventHandler(event, conn):
|
||||||
info = conn.info
|
info = conn.info
|
||||||
if event == mongoose.HTTP_ERROR:
|
if event == mongoose.HTTP_ERROR:
|
||||||
conn.printf('%s', 'HTTP/1.0 200 OK\r\n')
|
conn.write('HTTP/1.0 200 OK\r\n')
|
||||||
conn.printf('%s', 'Content-Type: text/plain\r\n\r\n')
|
conn.write('Content-Type: text/plain\r\n\r\n')
|
||||||
conn.printf('HTTP error: %d\n', info.status_code)
|
|
||||||
return True
|
return True
|
||||||
elif event == mongoose.NEW_REQUEST and info.uri == '/show':
|
elif event == mongoose.NEW_REQUEST and info.uri == '/show':
|
||||||
conn.printf('%s', 'HTTP/1.0 200 OK\r\n')
|
conn.write('HTTP/1.0 200 OK\r\n')
|
||||||
conn.printf('%s', 'Content-Type: text/plain\r\n\r\n')
|
conn.write('Content-Type: text/plain\r\n\r\n')
|
||||||
conn.printf('%s %s\n', info.request_method, info.uri)
|
conn.write('[%s] [%s] [%s]\n' % (info.request_method, info.uri,
|
||||||
|
info.query_string))
|
||||||
if info.request_method == 'POST':
|
if info.request_method == 'POST':
|
||||||
content_len = conn.get_header('Content-Length')
|
content_len = conn.get_header('Content-Length')
|
||||||
post_data = conn.read(int(content_len))
|
post_data = conn.read(int(content_len))
|
||||||
my_var = conn.get_var(post_data, 'my_var')
|
my_var = conn.get_var(post_data, 'my_var')
|
||||||
else:
|
else:
|
||||||
my_var = conn.get_var(info.query_string, 'my_var')
|
my_var = conn.get_var(info.query_string, 'my_var')
|
||||||
conn.printf('my_var: %s\n', my_var or '<not set>')
|
conn.write('my_var: %s\n' % (my_var or '<not set>'))
|
||||||
conn.printf('HEADERS: \n')
|
conn.write('HEADERS: \n')
|
||||||
for header in info.http_headers[:info.num_headers]:
|
for header in info.http_headers[:info.num_headers]:
|
||||||
conn.printf(' %s: %s\n', header.name, header.value)
|
conn.write(' %s: %s\n' % (header.name, header.value))
|
||||||
return True
|
return True
|
||||||
elif event == mongoose.NEW_REQUEST and info.uri == '/form':
|
elif event == mongoose.NEW_REQUEST and info.uri == '/form':
|
||||||
conn.write('HTTP/1.0 200 OK\r\n'
|
conn.write('HTTP/1.0 200 OK\r\n'
|
||||||
|
|||||||
@@ -40,10 +40,17 @@ import ctypes
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
NEW_REQUEST = 0
|
NEW_REQUEST = 0
|
||||||
HTTP_ERROR = 1
|
REQUEST_COMPLETE = 1
|
||||||
EVENT_LOG = 2
|
HTTP_ERROR = 2
|
||||||
INIT_SSL = 3
|
EVENT_LOG = 3
|
||||||
|
INIT_SSL = 4
|
||||||
|
WEBSOCKET_CONNECT = 5
|
||||||
|
WEBSOCKET_READY = 6
|
||||||
|
WEBSOCKET_MESSAGE = 7
|
||||||
|
WEBSOCKET_CLOSE = 8
|
||||||
|
OPEN_FILE = 9
|
||||||
|
INIT_LUA = 10
|
||||||
|
|
||||||
|
|
||||||
class mg_header(ctypes.Structure):
|
class mg_header(ctypes.Structure):
|
||||||
@@ -57,19 +64,18 @@ class mg_header(ctypes.Structure):
|
|||||||
class mg_request_info(ctypes.Structure):
|
class mg_request_info(ctypes.Structure):
|
||||||
"""A wrapper for struct mg_request_info."""
|
"""A wrapper for struct mg_request_info."""
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
('user_data', ctypes.c_char_p),
|
|
||||||
('request_method', ctypes.c_char_p),
|
('request_method', ctypes.c_char_p),
|
||||||
('uri', ctypes.c_char_p),
|
('uri', ctypes.c_char_p),
|
||||||
('http_version', ctypes.c_char_p),
|
('http_version', ctypes.c_char_p),
|
||||||
('query_string', ctypes.c_char_p),
|
('query_string', ctypes.c_char_p),
|
||||||
('remote_user', ctypes.c_char_p),
|
('remote_user', ctypes.c_char_p),
|
||||||
('log_message', ctypes.c_char_p),
|
|
||||||
('remote_ip', ctypes.c_long),
|
('remote_ip', ctypes.c_long),
|
||||||
('remote_port', ctypes.c_int),
|
('remote_port', ctypes.c_int),
|
||||||
('status_code', ctypes.c_int),
|
|
||||||
('is_ssl', ctypes.c_int),
|
('is_ssl', ctypes.c_int),
|
||||||
('num_headers', ctypes.c_int),
|
('num_headers', ctypes.c_int),
|
||||||
('http_headers', mg_header * 64),
|
('http_headers', mg_header * 64),
|
||||||
|
('user_data', ctypes.c_void_p),
|
||||||
|
('ev_data', ctypes.c_void_p),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -117,9 +123,9 @@ class Mongoose(object):
|
|||||||
|
|
||||||
def __init__(self, callback, **kwargs):
|
def __init__(self, callback, **kwargs):
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
self.dll = ctypes.WinDLL('_mongoose.dll')
|
self.dll = ctypes.WinDLL('mongoose.dll')
|
||||||
else:
|
else:
|
||||||
self.dll = ctypes.CDLL('_mongoose.so')
|
self.dll = ctypes.CDLL('libmongoose.so')
|
||||||
|
|
||||||
self.dll.mg_start.restype = ctypes.c_void_p
|
self.dll.mg_start.restype = ctypes.c_void_p
|
||||||
self.dll.mg_modify_passwords_file.restype = ctypes.c_int
|
self.dll.mg_modify_passwords_file.restype = ctypes.c_int
|
||||||
|
|||||||
@@ -4,4 +4,25 @@ all:
|
|||||||
OS=`uname`; \
|
OS=`uname`; \
|
||||||
test "$$OS" = Linux && LIBS="-ldl" ; \
|
test "$$OS" = Linux && LIBS="-ldl" ; \
|
||||||
$(CC) $(CFLAGS) hello.c ../mongoose.c $$LIBS $(ADD) -o hello;
|
$(CC) $(CFLAGS) hello.c ../mongoose.c $$LIBS $(ADD) -o hello;
|
||||||
|
$(CC) $(CFLAGS) upload.c ../mongoose.c $$LIBS $(ADD) -o upload;
|
||||||
|
$(CC) $(CFLAGS) post.c ../mongoose.c $$LIBS $(ADD) -o post;
|
||||||
|
$(CC) $(CFLAGS) -DUSE_WEBSOCKET websocket.c ../mongoose.c $$LIBS $(ADD) -o websocket;
|
||||||
$(CC) $(CFLAGS) chat.c ../mongoose.c $$LIBS $(ADD) -o chat
|
$(CC) $(CFLAGS) chat.c ../mongoose.c $$LIBS $(ADD) -o chat
|
||||||
|
|
||||||
|
|
||||||
|
MSVC = e:/vc6
|
||||||
|
CL = $(MSVC)/bin/cl
|
||||||
|
CLFLAGS = /MD /TC /nologo $(DBG) /W3 /DNO_SSL \
|
||||||
|
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf \
|
||||||
|
/link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
|
||||||
|
|
||||||
|
windows:
|
||||||
|
$(CL) upload.c ../mongoose.c $(CLFLAGS)
|
||||||
|
$(CL) hello.c ../mongoose.c $(CLFLAGS)
|
||||||
|
$(CL) upload.c ../mongoose.c $(CLFLAGS)
|
||||||
|
$(CL) post.c ../mongoose.c $(CLFLAGS)
|
||||||
|
$(CL) post.c ../mongoose.c $(CLFLAGS)
|
||||||
|
$(CL) /DUSE_WEBSOCKET websocket.c ../mongoose.c $(CLFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf hello hello.exe upload upload.exe post post.exe websocket websocket.exe chat chat.exe *.dSYM *.obj
|
||||||
+8
-3
@@ -122,7 +122,7 @@ static int handle_jsonp(struct mg_connection *conn,
|
|||||||
if (cb[0] != '\0') {
|
if (cb[0] != '\0') {
|
||||||
mg_printf(conn, "%s(", cb);
|
mg_printf(conn, "%s(", cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb[0] == '\0' ? 0 : 1;
|
return cb[0] == '\0' ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,6 +346,9 @@ static void *event_handler(enum mg_event event,
|
|||||||
// try to serve the request.
|
// try to serve the request.
|
||||||
processed = NULL;
|
processed = NULL;
|
||||||
}
|
}
|
||||||
|
} else if (event == MG_EVENT_LOG) {
|
||||||
|
printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
|
||||||
|
processed = NULL;
|
||||||
} else {
|
} else {
|
||||||
processed = NULL;
|
processed = NULL;
|
||||||
}
|
}
|
||||||
@@ -369,8 +372,10 @@ int main(void) {
|
|||||||
srand((unsigned) time(0));
|
srand((unsigned) time(0));
|
||||||
|
|
||||||
// Setup and start Mongoose
|
// Setup and start Mongoose
|
||||||
ctx = mg_start(&event_handler, NULL, options);
|
if ((ctx = mg_start(&event_handler, NULL, options)) == NULL) {
|
||||||
assert(ctx != NULL);
|
printf("%s\n", "Cannot start chat server, fatal exit");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Wait until enter is pressed, then exit
|
// Wait until enter is pressed, then exit
|
||||||
printf("Chat server started on ports %s, press enter to quit.\n",
|
printf("Chat server started on ports %s, press enter to quit.\n",
|
||||||
|
|||||||
+11
-4
@@ -16,6 +16,11 @@ chat.normalizeText = function(text) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
chat.refresh = function(data) {
|
chat.refresh = function(data) {
|
||||||
|
|
||||||
|
if (data === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$.each(data, function(index, entry) {
|
$.each(data, function(index, entry) {
|
||||||
var row = $('<div>').addClass('message-row').appendTo('#mml');
|
var row = $('<div>').addClass('message-row').appendTo('#mml');
|
||||||
var timestamp = (new Date(entry.timestamp * 1000)).toLocaleTimeString();
|
var timestamp = (new Date(entry.timestamp * 1000)).toLocaleTimeString();
|
||||||
@@ -42,7 +47,7 @@ chat.refresh = function(data) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
chat.getMessages = function() {
|
chat.getMessages = function(enter_loop) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
dataType: 'jsonp',
|
dataType: 'jsonp',
|
||||||
url: chat.backendUrl + '/ajax/get_messages',
|
url: chat.backendUrl + '/ajax/get_messages',
|
||||||
@@ -51,7 +56,9 @@ chat.getMessages = function() {
|
|||||||
error: function() {
|
error: function() {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
window.setTimeout(chat.getMessages, chat.getMessagesIntervalMs);
|
if (enter_loop) {
|
||||||
|
window.setTimeout('chat.getMessages(true)', chat.getMessagesIntervalMs);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
chat.handleMenuItemClick = function(ev) {
|
chat.handleMenuItemClick = function(ev) {
|
||||||
@@ -81,7 +88,7 @@ chat.handleMessageInput = function(ev) {
|
|||||||
success: function(ev) {
|
success: function(ev) {
|
||||||
input.value = '';
|
input.value = '';
|
||||||
input.disabled = false;
|
input.disabled = false;
|
||||||
chat.getMessages();
|
chat.getMessages(false);
|
||||||
},
|
},
|
||||||
error: function(ev) {
|
error: function(ev) {
|
||||||
chat.showError('Error sending message');
|
chat.showError('Error sending message');
|
||||||
@@ -93,7 +100,7 @@ chat.handleMessageInput = function(ev) {
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('.menu-item').click(chat.handleMenuItemClick);
|
$('.menu-item').click(chat.handleMenuItemClick);
|
||||||
$('.message-input').keypress(chat.handleMessageInput);
|
$('.message-input').keypress(chat.handleMessageInput);
|
||||||
chat.getMessages();
|
chat.getMessages(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// vim:ts=2:sw=2:et
|
// vim:ts=2:sw=2:et
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static const char *html_form =
|
||||||
|
"<html><body>POST example."
|
||||||
|
"<form method=\"POST\" action=\"/handle_post_request\">"
|
||||||
|
"Input 1: <input type=\"text\" name=\"input_1\" /> <br/>"
|
||||||
|
"Input 2: <input type=\"text\" name=\"input_2\" /> <br/>"
|
||||||
|
"<input type=\"submit\" />"
|
||||||
|
"</form></body></html>";
|
||||||
|
|
||||||
|
static void *callback(enum mg_event event,
|
||||||
|
struct mg_connection *conn) {
|
||||||
|
const struct mg_request_info *ri = mg_get_request_info(conn);
|
||||||
|
|
||||||
|
if (event == MG_NEW_REQUEST) {
|
||||||
|
if (!strcmp(ri->uri, "/handle_post_request")) {
|
||||||
|
// User has submitted a form, show submitted data and a variable value
|
||||||
|
char post_data[1024],
|
||||||
|
input1[sizeof(post_data)], input2[sizeof(post_data)];
|
||||||
|
int post_data_len;
|
||||||
|
|
||||||
|
// Read POST data
|
||||||
|
post_data_len = mg_read(conn, post_data, sizeof(post_data));
|
||||||
|
|
||||||
|
// Parse form data. input1 and input2 are guaranteed to be NUL-terminated
|
||||||
|
mg_get_var(post_data, post_data_len, "input_1", input1, sizeof(input1));
|
||||||
|
mg_get_var(post_data, post_data_len, "input_2", input2, sizeof(input2));
|
||||||
|
|
||||||
|
mg_printf(conn, "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Type: text/plain\r\n\r\n"
|
||||||
|
"Submitted data: [%.*s]\n"
|
||||||
|
"Submitted data length: %d bytes\n"
|
||||||
|
"input_1: [%s]\n"
|
||||||
|
"input_2: [%s]\n",
|
||||||
|
post_data_len, post_data, post_data_len, input1, input2);
|
||||||
|
} else {
|
||||||
|
// Show HTML form.
|
||||||
|
mg_printf(conn, "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Content-Type: text/html\r\n\r\n%s",
|
||||||
|
(int) strlen(html_form), html_form);
|
||||||
|
}
|
||||||
|
// Mark as processed
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_context *ctx;
|
||||||
|
const char *options[] = {"listening_ports", "8080", NULL};
|
||||||
|
|
||||||
|
ctx = mg_start(&callback, NULL, options);
|
||||||
|
getchar(); // Wait until user hits "enter"
|
||||||
|
mg_stop(ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) 2004-2012 Sergey Lyubka
|
||||||
|
// This file is a part of mongoose project, http://github.com/valenok/mongoose
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define strtoll strtol
|
||||||
|
typedef __int64 int64_t;
|
||||||
|
#else
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif // !_WIN32
|
||||||
|
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static void *callback(enum mg_event event, struct mg_connection *conn) {
|
||||||
|
if (event == MG_NEW_REQUEST) {
|
||||||
|
if (!strcmp(mg_get_request_info(conn)->uri, "/handle_post_request")) {
|
||||||
|
mg_printf(conn, "%s", "HTTP/1.0 200 OK\r\n\r\n");
|
||||||
|
mg_upload(conn, "/tmp");
|
||||||
|
} else {
|
||||||
|
// Show HTML form. Make sure it has enctype="multipart/form-data" attr.
|
||||||
|
static const char *html_form =
|
||||||
|
"<html><body>Upload example."
|
||||||
|
"<form method=\"POST\" action=\"/handle_post_request\" "
|
||||||
|
" enctype=\"multipart/form-data\">"
|
||||||
|
"<input type=\"file\" name=\"file\" /> <br/>"
|
||||||
|
"<input type=\"submit\" value=\"Upload\" />"
|
||||||
|
"</form></body></html>";
|
||||||
|
|
||||||
|
mg_printf(conn, "HTTP/1.0 200 OK\r\n"
|
||||||
|
"Content-Length: %d\r\n"
|
||||||
|
"Content-Type: text/html\r\n\r\n%s",
|
||||||
|
(int) strlen(html_form), html_form);
|
||||||
|
}
|
||||||
|
// Mark as processed
|
||||||
|
return "";
|
||||||
|
} else if (event == MG_UPLOAD) {
|
||||||
|
mg_printf(conn, "Saved [%s]", mg_get_request_info(conn)->ev_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_context *ctx;
|
||||||
|
const char *options[] = {"listening_ports", "8080", NULL};
|
||||||
|
|
||||||
|
ctx = mg_start(&callback, NULL, options);
|
||||||
|
getchar(); // Wait until user hits "enter"
|
||||||
|
pause();
|
||||||
|
mg_stop(ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) 2004-2012 Sergey Lyubka
|
||||||
|
// This file is a part of mongoose project, http://github.com/valenok/mongoose
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "mongoose.h"
|
||||||
|
|
||||||
|
static void *callback(enum mg_event event, struct mg_connection *conn) {
|
||||||
|
if (event == MG_WEBSOCKET_READY) {
|
||||||
|
unsigned char buf[40];
|
||||||
|
buf[0] = 0x81;
|
||||||
|
buf[1] = snprintf((char *) buf + 2, sizeof(buf) - 2, "%s", "server ready");
|
||||||
|
mg_write(conn, buf, 2 + buf[1]);
|
||||||
|
return ""; // MG_WEBSOCKET_READY return value is ignored
|
||||||
|
} else if (event == MG_WEBSOCKET_MESSAGE) {
|
||||||
|
unsigned char buf[200], reply[200];
|
||||||
|
int n, i, mask_len, xor, msg_len, len;
|
||||||
|
|
||||||
|
// Read message from the client.
|
||||||
|
// Accept only small (<126 bytes) messages.
|
||||||
|
len = 0;
|
||||||
|
msg_len = mask_len = 0;
|
||||||
|
for (;;) {
|
||||||
|
if ((n = mg_read(conn, buf + len, sizeof(buf) - len)) <= 0) {
|
||||||
|
return ""; // Read error, close websocket
|
||||||
|
}
|
||||||
|
len += n;
|
||||||
|
if (len >= 2) {
|
||||||
|
msg_len = buf[1] & 127;
|
||||||
|
mask_len = (buf[1] & 128) ? 4 : 0;
|
||||||
|
if (msg_len > 125) {
|
||||||
|
return ""; // Message is too long, close websocket
|
||||||
|
}
|
||||||
|
// If we've buffered the whole message, exit the loop
|
||||||
|
if (len >= 2 + mask_len + msg_len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare frame
|
||||||
|
reply[0] = 0x81; // text, FIN set
|
||||||
|
reply[1] = msg_len;
|
||||||
|
|
||||||
|
// Copy message from request to reply, applying the mask if required.
|
||||||
|
for (i = 0; i < msg_len; i++) {
|
||||||
|
xor = mask_len == 0 ? 0 : buf[2 + (i % 4)];
|
||||||
|
reply[i + 2] = buf[i + 2 + mask_len] ^ xor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Echo the message back to the client
|
||||||
|
mg_write(conn, reply, 2 + msg_len);
|
||||||
|
|
||||||
|
// Return non-NULL means stoping websocket conversation.
|
||||||
|
// Close the conversation if client has sent us "exit" string.
|
||||||
|
return memcmp(reply + 2, "exit", 4) == 0 ? "" : NULL;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
struct mg_context *ctx;
|
||||||
|
const char *options[] = {
|
||||||
|
"listening_ports", "8080",
|
||||||
|
"document_root", "websocket_html_root",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx = mg_start(&callback, NULL, options);
|
||||||
|
getchar(); // Wait until user hits "enter"
|
||||||
|
mg_stop(ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>WebSocket Test</title>
|
||||||
|
<script language="javascript" type="text/javascript">
|
||||||
|
|
||||||
|
var writeToScreen = function(message) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
div.innerHTML = message;
|
||||||
|
document.getElementById('output').appendChild(div);
|
||||||
|
};
|
||||||
|
window.onload = function() {
|
||||||
|
var url = 'ws://' + window.location.host + '/foo';
|
||||||
|
websocket = new WebSocket(url);
|
||||||
|
websocket.onopen = function(ev) {
|
||||||
|
writeToScreen('CONNECTED');
|
||||||
|
var message = 'Не всё подчиняется разуму. Но всё подчиняется упорству. ';
|
||||||
|
writeToScreen('SENT: ' + message);
|
||||||
|
websocket.send(message);
|
||||||
|
};
|
||||||
|
websocket.onclose = function(ev) {
|
||||||
|
writeToScreen('DISCONNECTED');
|
||||||
|
};
|
||||||
|
websocket.onmessage = function(ev) {
|
||||||
|
writeToScreen('<span style="color: blue;">RESPONSE: ' + ev.data +
|
||||||
|
' </span>');
|
||||||
|
websocket.send('exit');
|
||||||
|
};
|
||||||
|
websocket.onerror = function(ev) {
|
||||||
|
writeToScreen('<span style="color: red; ">ERROR: </span> ' + ev.data);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style> div {font: small Verdana; } </style>
|
||||||
|
<h2>Mongoose WebSocket Test</h2>
|
||||||
|
|
||||||
|
<div style="width: 400px; color: #aaa; padding: 1em; ">
|
||||||
|
This page code creates websocket to the URI "/foo",
|
||||||
|
sends a message to it, waits for the reply, then sends an "exit" message.
|
||||||
|
Server must echo all messages back, and terminate the conversation after
|
||||||
|
receiving the "exit" message.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="output"></div>
|
||||||
|
</html>
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
|
||||||
@@ -191,7 +192,8 @@ static void process_command_line_arguments(char *argv[], char **options) {
|
|||||||
line_no++;
|
line_no++;
|
||||||
|
|
||||||
// Ignore empty lines and comments
|
// Ignore empty lines and comments
|
||||||
if (line[0] == '#' || line[0] == '\n')
|
for (i = 0; isspace(* (unsigned char *) &line[i]); ) i++;
|
||||||
|
if (line[i] == '#' || line[i] == '\0')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
|
if (sscanf(line, "%s %[^\r\n#]", opt, val) != 2) {
|
||||||
@@ -203,7 +205,7 @@ static void process_command_line_arguments(char *argv[], char **options) {
|
|||||||
(void) fclose(fp);
|
(void) fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now handle command line flags. They override config file settings.
|
// Handle command line flags. They override config file and default settings.
|
||||||
for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
|
for (i = cmd_line_opts_start; argv[i] != NULL; i += 2) {
|
||||||
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
||||||
show_usage_and_exit();
|
show_usage_and_exit();
|
||||||
@@ -219,9 +221,11 @@ static void init_server_name(void) {
|
|||||||
|
|
||||||
static void *mongoose_callback(enum mg_event ev, struct mg_connection *conn) {
|
static void *mongoose_callback(enum mg_event ev, struct mg_connection *conn) {
|
||||||
if (ev == MG_EVENT_LOG) {
|
if (ev == MG_EVENT_LOG) {
|
||||||
printf("%s\n", mg_get_request_info(conn)->log_message);
|
printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returning NULL marks request as not handled, signalling mongoose to
|
||||||
|
// proceed with handling it.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,6 +487,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
|
|||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the WM_QUIT value.
|
||||||
return msg.wParam;
|
return msg.wParam;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
+13
-3
@@ -1,7 +1,7 @@
|
|||||||
.\" Process this file with
|
.\" Process this file with
|
||||||
.\" groff -man -Tascii mongoose.1
|
.\" groff -man -Tascii mongoose.1
|
||||||
.\" $Id: mongoose.1,v 1.12 2008/11/29 15:32:42 drozd Exp $
|
.\" $Id: mongoose.1,v 1.12 2008/11/29 15:32:42 drozd Exp $
|
||||||
.Dd Aug 31, 2010
|
.Dd Sep 23, 2012
|
||||||
.Dt mongoose 1
|
.Dt mongoose 1
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm mongoose
|
.Nm mongoose
|
||||||
@@ -82,8 +82,6 @@ Use
|
|||||||
as a CGI interpreter for all CGI scripts regardless script extension.
|
as a CGI interpreter for all CGI scripts regardless script extension.
|
||||||
Mongoose decides which interpreter to use by looking at
|
Mongoose decides which interpreter to use by looking at
|
||||||
the first line of a CGI script. Default: "".
|
the first line of a CGI script. Default: "".
|
||||||
.It Fl M Ar max_request_size
|
|
||||||
Maximum HTTP request size in bytes. Default: "16384"
|
|
||||||
.It Fl P Ar protect_uri
|
.It Fl P Ar protect_uri
|
||||||
Comma separated list of URI=PATH pairs, specifying that given URIs
|
Comma separated list of URI=PATH pairs, specifying that given URIs
|
||||||
must be protected with respected password files. Default: ""
|
must be protected with respected password files. Default: ""
|
||||||
@@ -93,6 +91,18 @@ Authorization realm. Default: "mydomain.com"
|
|||||||
All files that fully match ssi_pattern are treated as SSI.
|
All files that fully match ssi_pattern are treated as SSI.
|
||||||
Unknown SSI directives are silently ignored. Currently, two SSI directives
|
Unknown SSI directives are silently ignored. Currently, two SSI directives
|
||||||
are supported, "include" and "exec". Default: "**.shtml$|**.shtm$"
|
are supported, "include" and "exec". Default: "**.shtml$|**.shtm$"
|
||||||
|
.It Fl T Ar throttle
|
||||||
|
Limit download speed for clients.
|
||||||
|
.Ar throttle
|
||||||
|
is a comma-separated list of key=value pairs, where
|
||||||
|
key could be a '*' character (limit for all connections), a subnet in form
|
||||||
|
x.x.x.x/mask (limit for a given subnet, for example 10.0.0.0/8), or an
|
||||||
|
URI prefix pattern (limit for the set of URIs, for example /foo/**). The value
|
||||||
|
is a floating-point number of bytes per second, optionally followed by a
|
||||||
|
`k' or `m' character, meaning kilobytes and megabytes respectively. A limit
|
||||||
|
of 0 means unlimited rate. The last matching rule wins. For example,
|
||||||
|
"*=1k,10.0.0.0/8" means limit everybody to 1 kilobyte per second, but give
|
||||||
|
people from 10/8 subnet unlimited speed. Default: ""
|
||||||
.It Fl a Ar access_log_file
|
.It Fl a Ar access_log_file
|
||||||
Access log file. Default: "", no logging is done.
|
Access log file. Default: "", no logging is done.
|
||||||
.It Fl d Ar enable_directory_listing
|
.It Fl d Ar enable_directory_listing
|
||||||
|
|||||||
+1422
-645
File diff suppressed because it is too large.
Load diff
+146
-48
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2004-2011 Sergey Lyubka
|
// Copyright (c) 2004-2012 Sergey Lyubka
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -34,34 +34,107 @@ struct mg_connection; // Handle for the individual connection
|
|||||||
|
|
||||||
// This structure contains information about the HTTP request.
|
// This structure contains information about the HTTP request.
|
||||||
struct mg_request_info {
|
struct mg_request_info {
|
||||||
void *user_data; // User-defined pointer passed to mg_start()
|
const char *request_method; // "GET", "POST", etc
|
||||||
char *request_method; // "GET", "POST", etc
|
const char *uri; // URL-decoded URI
|
||||||
char *uri; // URL-decoded URI
|
const char *http_version; // E.g. "1.0", "1.1"
|
||||||
char *http_version; // E.g. "1.0", "1.1"
|
const char *query_string; // URL part after '?', not including '?', or NULL
|
||||||
char *query_string; // URL part after '?' (not including '?') or NULL
|
const char *remote_user; // Authenticated user, or NULL if no auth used
|
||||||
char *remote_user; // Authenticated user, or NULL if no auth used
|
long remote_ip; // Client's IP address
|
||||||
char *log_message; // Mongoose error log message, MG_EVENT_LOG only
|
int remote_port; // Client's port
|
||||||
long remote_ip; // Client's IP address
|
int is_ssl; // 1 if SSL-ed, 0 if not
|
||||||
int remote_port; // Client's port
|
int num_headers; // Number of headers
|
||||||
int status_code; // HTTP reply status code, e.g. 200
|
|
||||||
int is_ssl; // 1 if SSL-ed, 0 if not
|
|
||||||
int num_headers; // Number of headers
|
|
||||||
struct mg_header {
|
struct mg_header {
|
||||||
char *name; // HTTP header name
|
const char *name; // HTTP header name
|
||||||
char *value; // HTTP header value
|
const char *value; // HTTP header value
|
||||||
} http_headers[64]; // Maximum 64 headers
|
} http_headers[64]; // Maximum 64 headers
|
||||||
|
void *user_data; // User data pointer passed to the mg_start()
|
||||||
|
void *ev_data; // Event-specific data pointer
|
||||||
};
|
};
|
||||||
|
|
||||||
// Various events on which user-defined function is called by Mongoose.
|
|
||||||
|
// Various events on which user-defined callback function is called by Mongoose.
|
||||||
enum mg_event {
|
enum mg_event {
|
||||||
MG_NEW_REQUEST, // New HTTP request has arrived from the client
|
// New HTTP request has arrived from the client.
|
||||||
MG_HTTP_ERROR, // HTTP error must be returned to the client
|
// If callback returns non-NULL, Mongoose stops handling current request.
|
||||||
MG_EVENT_LOG, // Mongoose logs an event, request_info.log_message
|
// ev_data contains NULL.
|
||||||
MG_INIT_SSL, // Mongoose initializes SSL. Instead of mg_connection *,
|
MG_NEW_REQUEST,
|
||||||
// SSL context is passed to the callback function.
|
|
||||||
MG_REQUEST_COMPLETE // Mongoose has finished handling the request
|
// Mongoose has finished handling the request.
|
||||||
|
// Callback return value is ignored.
|
||||||
|
// ev_data contains NULL.
|
||||||
|
MG_REQUEST_COMPLETE,
|
||||||
|
|
||||||
|
// HTTP error must be returned to the client.
|
||||||
|
// If callback returns non-NULL, Mongoose stops handling error.
|
||||||
|
// ev_data contains HTTP error code:
|
||||||
|
// int http_reply_status_code = (long) request_info->ev_data;
|
||||||
|
MG_HTTP_ERROR,
|
||||||
|
|
||||||
|
// Mongoose logs a message.
|
||||||
|
// If callback returns non-NULL, Mongoose stops handling that event.
|
||||||
|
// ev_data contains a message to be logged:
|
||||||
|
// const char *log_message = request_info->ev_data;
|
||||||
|
MG_EVENT_LOG,
|
||||||
|
|
||||||
|
// SSL initialization, sent before certificate setup.
|
||||||
|
// If callback returns non-NULL, Mongoose does not set up certificates.
|
||||||
|
// ev_data contains server's OpenSSL context:
|
||||||
|
// SSL_CTX *ssl_context = request_info->ev_data;
|
||||||
|
MG_INIT_SSL,
|
||||||
|
|
||||||
|
// Sent on HTTP connect, before websocket handshake.
|
||||||
|
// If user callback returns NULL, then mongoose proceeds
|
||||||
|
// with handshake, otherwise it closes the connection.
|
||||||
|
// ev_data contains NULL.
|
||||||
|
MG_WEBSOCKET_CONNECT,
|
||||||
|
|
||||||
|
// Handshake has been successfully completed.
|
||||||
|
// Callback's return value is ignored.
|
||||||
|
// ev_data contains NULL.
|
||||||
|
MG_WEBSOCKET_READY,
|
||||||
|
|
||||||
|
// Incoming message from the client, data could be read with mg_read().
|
||||||
|
// If user callback returns non-NULL, mongoose closes the websocket.
|
||||||
|
// ev_data contains NULL.
|
||||||
|
MG_WEBSOCKET_MESSAGE,
|
||||||
|
|
||||||
|
// Client has closed the connection.
|
||||||
|
// Callback's return value is ignored.
|
||||||
|
// ev_data contains NULL.
|
||||||
|
MG_WEBSOCKET_CLOSE,
|
||||||
|
|
||||||
|
// Mongoose tries to open file.
|
||||||
|
// If callback returns non-NULL, Mongoose will not try to open it, but
|
||||||
|
// will use the returned value as a pointer to the file data. This allows
|
||||||
|
// for example to serve files from memory.
|
||||||
|
// ev_data contains file path, including document root path.
|
||||||
|
// Upon return, ev_data should return file size, which should be a long int.
|
||||||
|
//
|
||||||
|
// const char *file_name = request_info->ev_data;
|
||||||
|
// if (strcmp(file_name, "foo.txt") == 0) {
|
||||||
|
// request_info->ev_data = (void *) (long) 4;
|
||||||
|
// return "data";
|
||||||
|
// }
|
||||||
|
// return NULL;
|
||||||
|
//
|
||||||
|
// Note that this even is sent multiple times during one request. Each
|
||||||
|
// time mongoose tries to open or stat the file, this event is sent, e.g.
|
||||||
|
// for opening .htpasswd file, stat-ting requested file, opening requested
|
||||||
|
// file, etc.
|
||||||
|
MG_OPEN_FILE,
|
||||||
|
|
||||||
|
// Mongoose initializes Lua server page. Sent only if Lua support is enabled.
|
||||||
|
// Callback's return value is ignored.
|
||||||
|
// ev_data contains lua_State pointer.
|
||||||
|
MG_INIT_LUA,
|
||||||
|
|
||||||
|
// Mongoose has uploaded file to a temporary directory.
|
||||||
|
// Callback's return value is ignored.
|
||||||
|
// ev_data contains NUL-terminated file name.
|
||||||
|
MG_UPLOAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Prototype for the user-defined function. Mongoose calls this function
|
// Prototype for the user-defined function. Mongoose calls this function
|
||||||
// on every MG_* event.
|
// on every MG_* event.
|
||||||
//
|
//
|
||||||
@@ -77,8 +150,7 @@ enum mg_event {
|
|||||||
// If handler returns NULL, that means that handler has not processed
|
// If handler returns NULL, that means that handler has not processed
|
||||||
// the request. Handler must not send any data to the client in this case.
|
// the request. Handler must not send any data to the client in this case.
|
||||||
// Mongoose proceeds with request handling as if nothing happened.
|
// Mongoose proceeds with request handling as if nothing happened.
|
||||||
typedef void * (*mg_callback_t)(enum mg_event event,
|
typedef void *(*mg_callback_t)(enum mg_event event, struct mg_connection *conn);
|
||||||
struct mg_connection *conn);
|
|
||||||
|
|
||||||
|
|
||||||
// Start web server.
|
// Start web server.
|
||||||
@@ -151,26 +223,44 @@ int mg_modify_passwords_file(const char *passwords_file_name,
|
|||||||
const char *password);
|
const char *password);
|
||||||
|
|
||||||
|
|
||||||
// Return mg_request_info structure associated with the request.
|
// Return information associated with the request.
|
||||||
// Always succeeds.
|
struct mg_request_info *mg_get_request_info(struct mg_connection *);
|
||||||
const struct mg_request_info *mg_get_request_info(struct mg_connection *);
|
|
||||||
|
|
||||||
|
|
||||||
// Send data to the client.
|
// Send data to the client.
|
||||||
|
// Return:
|
||||||
|
// 0 when the connection has been closed
|
||||||
|
// -1 on error
|
||||||
|
// number of bytes written on success
|
||||||
int mg_write(struct mg_connection *, const void *buf, size_t len);
|
int mg_write(struct mg_connection *, const void *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
// Send data to the browser using printf() semantics.
|
// Send data to the browser using printf() semantics.
|
||||||
//
|
//
|
||||||
// Works exactly like mg_write(), but allows to do message formatting.
|
// Works exactly like mg_write(), but allows to do message formatting.
|
||||||
// Note that mg_printf() uses internal buffer of size IO_BUF_SIZE
|
// Below are the macros for enabling compiler-specific checks for
|
||||||
// (8 Kb by default) as temporary message storage for formatting. Do not
|
// printf-like arguments.
|
||||||
// print data that is bigger than that, otherwise it will be truncated.
|
|
||||||
int mg_printf(struct mg_connection *, const char *fmt, ...)
|
#undef PRINTF_FORMAT_STRING
|
||||||
#ifdef __GNUC__
|
#if _MSC_VER >= 1400
|
||||||
__attribute__((format(printf, 2, 3)))
|
#include <sal.h>
|
||||||
|
#if _MSC_VER > 1400
|
||||||
|
#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
|
||||||
|
#else
|
||||||
|
#define PRINTF_FORMAT_STRING(s) __format_string s
|
||||||
#endif
|
#endif
|
||||||
;
|
#else
|
||||||
|
#define PRINTF_FORMAT_STRING(s) s
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
|
||||||
|
#else
|
||||||
|
#define PRINTF_ARGS(x, y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int mg_printf(struct mg_connection *,
|
||||||
|
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
|
||||||
|
|
||||||
|
|
||||||
// Send contents of the entire file together with HTTP headers.
|
// Send contents of the entire file together with HTTP headers.
|
||||||
@@ -196,17 +286,19 @@ const char *mg_get_header(const struct mg_connection *, const char *name);
|
|||||||
// or request_info.query_string.
|
// or request_info.query_string.
|
||||||
// data_len: length of the encoded data.
|
// data_len: length of the encoded data.
|
||||||
// var_name: variable name to decode from the buffer
|
// var_name: variable name to decode from the buffer
|
||||||
// buf: destination buffer for the decoded variable
|
// dst: destination buffer for the decoded variable
|
||||||
// buf_len: length of the destination buffer
|
// dst_len: length of the destination buffer
|
||||||
//
|
//
|
||||||
// Return:
|
// Return:
|
||||||
// On success, length of the decoded variable.
|
// On success, length of the decoded variable.
|
||||||
// On error, -1 (variable not found, or destination buffer is too small).
|
// On error:
|
||||||
|
// -1 (variable not found).
|
||||||
|
// -2 (destination buffer is NULL, zero length or too small to hold the decoded variable).
|
||||||
//
|
//
|
||||||
// Destination buffer is guaranteed to be '\0' - terminated. In case of
|
// Destination buffer is guaranteed to be '\0' - terminated if it is not
|
||||||
// failure, dst[0] == '\0'.
|
// NULL or zero length.
|
||||||
int mg_get_var(const char *data, size_t data_len,
|
int mg_get_var(const char *data, size_t data_len,
|
||||||
const char *var_name, char *buf, size_t buf_len);
|
const char *var_name, char *dst, size_t dst_len);
|
||||||
|
|
||||||
// Fetch value of certain cookie variable into the destination buffer.
|
// Fetch value of certain cookie variable into the destination buffer.
|
||||||
//
|
//
|
||||||
@@ -216,9 +308,9 @@ int mg_get_var(const char *data, size_t data_len,
|
|||||||
//
|
//
|
||||||
// Return:
|
// Return:
|
||||||
// On success, value length.
|
// On success, value length.
|
||||||
// On error, 0 (either "Cookie:" header is not present at all, or the
|
// On error:
|
||||||
// requested parameter is not found, or destination buffer is too small
|
// -1 (either "Cookie:" header is not present at all or the requested parameter is not found).
|
||||||
// to hold the value).
|
// -2 (destination buffer is NULL, zero length or too small to hold the value).
|
||||||
int mg_get_cookie(const struct mg_connection *,
|
int mg_get_cookie(const struct mg_connection *,
|
||||||
const char *cookie_name, char *buf, size_t buf_len);
|
const char *cookie_name, char *buf, size_t buf_len);
|
||||||
|
|
||||||
@@ -243,12 +335,18 @@ void mg_close_connection(struct mg_connection *conn);
|
|||||||
// Return:
|
// Return:
|
||||||
// On error, NULL
|
// On error, NULL
|
||||||
// On success, opened file stream to the downloaded contents. The stream
|
// On success, opened file stream to the downloaded contents. The stream
|
||||||
// is positioned to the end of the file. It is a user responsibility
|
// is positioned to the end of the file. It is the user's responsibility
|
||||||
// to fclose() opened file stream.
|
// to fclose() the opened file stream.
|
||||||
FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
|
FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
|
||||||
char *buf, size_t buf_len, struct mg_request_info *request_info);
|
char *buf, size_t buf_len, struct mg_request_info *request_info);
|
||||||
|
|
||||||
|
|
||||||
|
// File upload functionality. Each uploaded file gets saved into a temporary
|
||||||
|
// file and MG_UPLOAD event is sent.
|
||||||
|
// Return number of uploaded files.
|
||||||
|
int mg_upload(struct mg_connection *conn, const char *destination_dir);
|
||||||
|
|
||||||
|
|
||||||
// Convenience function -- create detached thread.
|
// Convenience function -- create detached thread.
|
||||||
// Return: 0 on success, non-0 on error.
|
// Return: 0 on success, non-0 on error.
|
||||||
typedef void * (*mg_thread_func_t)(void *);
|
typedef void * (*mg_thread_func_t)(void *);
|
||||||
@@ -266,11 +364,11 @@ const char *mg_version(void);
|
|||||||
|
|
||||||
// MD5 hash given strings.
|
// MD5 hash given strings.
|
||||||
// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
|
// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
|
||||||
// asciiz strings. When function returns, buf will contain human-readable
|
// ASCIIz strings. When function returns, buf will contain human-readable
|
||||||
// MD5 hash. Example:
|
// MD5 hash. Example:
|
||||||
// char buf[33];
|
// char buf[33];
|
||||||
// mg_md5(buf, "aa", "bb", NULL);
|
// mg_md5(buf, "aa", "bb", NULL);
|
||||||
void mg_md5(char *buf, ...);
|
void mg_md5(char buf[33], ...);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
blah
|
|
||||||
+3
-2
@@ -119,9 +119,10 @@ static void test_get_request_info(struct mg_connection *conn,
|
|||||||
|
|
||||||
static void test_error(struct mg_connection *conn,
|
static void test_error(struct mg_connection *conn,
|
||||||
const struct mg_request_info *ri) {
|
const struct mg_request_info *ri) {
|
||||||
|
int status = (int) ri->ev_data;
|
||||||
mg_printf(conn, "HTTP/1.1 %d XX\r\n"
|
mg_printf(conn, "HTTP/1.1 %d XX\r\n"
|
||||||
"Conntection: close\r\n\r\n", ri->status_code);
|
"Conntection: close\r\n\r\n", status);
|
||||||
mg_printf(conn, "Error: [%d]", ri->status_code);
|
mg_printf(conn, "Error: [%d]", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_post(struct mg_connection *conn,
|
static void test_post(struct mg_connection *conn,
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<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>
|
||||||
+3
-2
@@ -180,6 +180,9 @@ my $cmd = "$exe ".
|
|||||||
$cmd .= ' -cgi_interpreter perl' if on_windows();
|
$cmd .= ' -cgi_interpreter perl' if on_windows();
|
||||||
spawn($cmd);
|
spawn($cmd);
|
||||||
|
|
||||||
|
o("GET /hello.txt HTTP/1.1\nConnection: close\nRange: bytes=3-50\r\n\r\n",
|
||||||
|
'Content-Length: 15\s', 'Range past the file end');
|
||||||
|
|
||||||
o("GET /hello.txt HTTP/1.1\n\n GET /hello.txt HTTP/1.0\n\n",
|
o("GET /hello.txt HTTP/1.1\n\n GET /hello.txt HTTP/1.0\n\n",
|
||||||
'HTTP/1.1 200.+keep-alive.+HTTP/1.1 200.+close',
|
'HTTP/1.1 200.+keep-alive.+HTTP/1.1 200.+close',
|
||||||
'Request pipelining', 2);
|
'Request pipelining', 2);
|
||||||
@@ -215,8 +218,6 @@ $num_requests++;
|
|||||||
write_file("$root/a+.txt", '');
|
write_file("$root/a+.txt", '');
|
||||||
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI');
|
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI');
|
||||||
|
|
||||||
o("GET /%5c/a.txt HTTP/1.0\n\n", 'blah', 'GET dir backslash');
|
|
||||||
|
|
||||||
# Test HTTP version parsing
|
# Test HTTP version parsing
|
||||||
o("GET / HTTPX/1.0\r\n\r\n", '400 Bad Request', 'Bad HTTP Version', 0);
|
o("GET / HTTPX/1.0\r\n\r\n", '400 Bad Request', 'Bad HTTP Version', 0);
|
||||||
o("GET / HTTP/x.1\r\n\r\n", '505 HTTP', 'Bad HTTP maj Version');
|
o("GET / HTTP/x.1\r\n\r\n", '505 HTTP', 'Bad HTTP maj Version');
|
||||||
|
|||||||
+215
-21
@@ -1,3 +1,4 @@
|
|||||||
|
#define USE_WEBSOCKET
|
||||||
#include "mongoose.c"
|
#include "mongoose.c"
|
||||||
|
|
||||||
#define FATAL(str, line) do { \
|
#define FATAL(str, line) do { \
|
||||||
@@ -6,6 +7,8 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
|
#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
|
||||||
|
|
||||||
|
#define UNUSED_PORT "33796"
|
||||||
|
|
||||||
static void test_parse_http_request() {
|
static void test_parse_http_request() {
|
||||||
struct mg_request_info ri;
|
struct mg_request_info ri;
|
||||||
char req1[] = "GET / HTTP/1.1\r\n\r\n";
|
char req1[] = "GET / HTTP/1.1\r\n\r\n";
|
||||||
@@ -30,7 +33,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].name, "baz\r\n\r") == 0);
|
||||||
ASSERT(strcmp(ri.http_headers[2].value, "") == 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) {
|
static void test_should_keep_alive(void) {
|
||||||
@@ -64,10 +67,10 @@ static void test_should_keep_alive(void) {
|
|||||||
parse_http_request(req4, sizeof(req4), &conn.request_info);
|
parse_http_request(req4, sizeof(req4), &conn.request_info);
|
||||||
ASSERT(should_keep_alive(&conn) == 1);
|
ASSERT(should_keep_alive(&conn) == 1);
|
||||||
|
|
||||||
conn.request_info.status_code = 401;
|
conn.status_code = 401;
|
||||||
ASSERT(should_keep_alive(&conn) == 0);
|
ASSERT(should_keep_alive(&conn) == 0);
|
||||||
|
|
||||||
conn.request_info.status_code = 200;
|
conn.status_code = 200;
|
||||||
conn.must_close = 1;
|
conn.must_close = 1;
|
||||||
ASSERT(should_keep_alive(&conn) == 0);
|
ASSERT(should_keep_alive(&conn) == 0);
|
||||||
}
|
}
|
||||||
@@ -111,69 +114,75 @@ static void test_remove_double_dots() {
|
|||||||
{"/...///", "/./"},
|
{"/...///", "/./"},
|
||||||
{"/a...///", "/a.../"},
|
{"/a...///", "/a.../"},
|
||||||
{"/.x", "/.x"},
|
{"/.x", "/.x"},
|
||||||
#if defined(_WIN32)
|
|
||||||
{"/\\", "/"},
|
{"/\\", "/"},
|
||||||
#else
|
|
||||||
{"/\\", "/\\"},
|
|
||||||
#endif
|
|
||||||
{"/a\\", "/a\\"},
|
{"/a\\", "/a\\"},
|
||||||
|
{"/a\\\\...", "/a\\."},
|
||||||
};
|
};
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data); i++) {
|
for (i = 0; i < ARRAY_SIZE(data); i++) {
|
||||||
//printf("[%s] -> [%s]\n", data[i].before, data[i].after);
|
printf("[%s] -> [%s]\n", data[i].before, data[i].after);
|
||||||
remove_double_dots_and_double_slashes(data[i].before);
|
remove_double_dots_and_double_slashes(data[i].before);
|
||||||
ASSERT(strcmp(data[i].before, data[i].after) == 0);
|
ASSERT(strcmp(data[i].before, data[i].after) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *fetch_data = "hello world!\n";
|
static const char *fetch_data = "hello world!\n";
|
||||||
static void *event_handler(enum mg_event event,
|
static const char *inmemory_file_data = "hi there";
|
||||||
struct mg_connection *conn) {
|
static void *event_handler(enum mg_event event, struct mg_connection *conn) {
|
||||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||||
|
|
||||||
if (event == MG_NEW_REQUEST && !strcmp(request_info->uri, "/data")) {
|
if (event == MG_NEW_REQUEST && !strcmp(request_info->uri, "/data")) {
|
||||||
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
|
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
"Content-Type: text/plain\r\n\r\n"
|
"Content-Type: text/plain\r\n\r\n"
|
||||||
"%s", (int) strlen(fetch_data), fetch_data);
|
"%s", (int) strlen(fetch_data), fetch_data);
|
||||||
return "";
|
return "";
|
||||||
|
} else if (event == MG_OPEN_FILE) {
|
||||||
|
const char *path = request_info->ev_data;
|
||||||
|
printf("%s: [%s]\n", __func__, path);
|
||||||
|
if (strcmp(path, "./blah") == 0) {
|
||||||
|
mg_get_request_info(conn)->ev_data =
|
||||||
|
(void *) (int) strlen(inmemory_file_data);
|
||||||
|
return (void *) inmemory_file_data;
|
||||||
|
}
|
||||||
} else if (event == MG_EVENT_LOG) {
|
} else if (event == MG_EVENT_LOG) {
|
||||||
printf("%s\n", request_info->log_message);
|
printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mg_fetch(void) {
|
static void test_mg_fetch(void) {
|
||||||
static const char *options[] = {
|
static const char *options[] = {
|
||||||
"document_root", ".",
|
"document_root", ".",
|
||||||
"listening_ports", "33796",
|
"listening_ports", UNUSED_PORT,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
char buf[2000], buf2[2000];
|
char buf[2000], buf2[2000];
|
||||||
int length;
|
int n, length;
|
||||||
struct mg_context *ctx;
|
struct mg_context *ctx;
|
||||||
struct mg_request_info ri;
|
struct mg_request_info ri;
|
||||||
const char *tmp_file = "temporary_file_name_for_unit_test.txt";
|
const char *tmp_file = "temporary_file_name_for_unit_test.txt";
|
||||||
struct mgstat st;
|
struct file file;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
ASSERT((ctx = mg_start(event_handler, NULL, options)) != NULL);
|
ASSERT((ctx = mg_start(event_handler, NULL, options)) != NULL);
|
||||||
|
|
||||||
// Failed fetch, pass invalid URL
|
// Failed fetch, pass invalid URL
|
||||||
ASSERT(mg_fetch(ctx, "localhost", tmp_file, buf, sizeof(buf), &ri) == NULL);
|
ASSERT(mg_fetch(ctx, "localhost", tmp_file, buf, sizeof(buf), &ri) == NULL);
|
||||||
ASSERT(mg_fetch(ctx, "localhost:33796", tmp_file,
|
ASSERT(mg_fetch(ctx, "localhost:" UNUSED_PORT, tmp_file,
|
||||||
buf, sizeof(buf), &ri) == NULL);
|
buf, sizeof(buf), &ri) == NULL);
|
||||||
ASSERT(mg_fetch(ctx, "http://$$$.$$$", tmp_file,
|
ASSERT(mg_fetch(ctx, "http://$$$.$$$", tmp_file,
|
||||||
buf, sizeof(buf), &ri) == NULL);
|
buf, sizeof(buf), &ri) == NULL);
|
||||||
|
|
||||||
// Failed fetch, pass invalid file name
|
// Failed fetch, pass invalid file name
|
||||||
ASSERT(mg_fetch(ctx, "http://localhost:33796/data",
|
ASSERT(mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/data",
|
||||||
"/this/file/must/not/exist/ever",
|
"/this/file/must/not/exist/ever",
|
||||||
buf, sizeof(buf), &ri) == NULL);
|
buf, sizeof(buf), &ri) == NULL);
|
||||||
|
|
||||||
// Successful fetch
|
// Successful fetch
|
||||||
ASSERT((fp = mg_fetch(ctx, "http://localhost:33796/data",
|
ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/data",
|
||||||
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||||
ASSERT(ri.num_headers == 2);
|
ASSERT(ri.num_headers == 2);
|
||||||
ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
|
ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
|
||||||
@@ -186,21 +195,206 @@ static void test_mg_fetch(void) {
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
// Fetch big file, mongoose.c
|
// Fetch big file, mongoose.c
|
||||||
ASSERT((fp = mg_fetch(ctx, "http://localhost:33796/mongoose.c",
|
ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/mongoose.c",
|
||||||
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||||
ASSERT(mg_stat("mongoose.c", &st) == 0);
|
ASSERT(mg_stat(fc(ctx), "mongoose.c", &file));
|
||||||
ASSERT(st.size == ftell(fp));
|
ASSERT(file.size == ftell(fp));
|
||||||
ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
|
ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
|
||||||
|
|
||||||
|
// Fetch nonexistent file, /blah
|
||||||
|
ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/boo",
|
||||||
|
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||||
|
ASSERT(!mg_strcasecmp(ri.uri, "404"));
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
// Fetch existing inmemory file
|
||||||
|
ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/blah",
|
||||||
|
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||||
|
ASSERT(!mg_strcasecmp(ri.uri, "200"));
|
||||||
|
n = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2);
|
||||||
|
n = fread(buf2, 1, n, fp);
|
||||||
|
printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2);
|
||||||
|
ASSERT((size_t) ftell(fp) == (size_t) strlen(inmemory_file_data));
|
||||||
|
ASSERT(!memcmp(inmemory_file_data, buf2, ftell(fp)));
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
remove(tmp_file);
|
remove(tmp_file);
|
||||||
mg_stop(ctx);
|
mg_stop(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_base64_encode(void) {
|
||||||
|
const char *in[] = {"a", "ab", "abc", "abcd", NULL};
|
||||||
|
const char *out[] = {"YQ==", "YWI=", "YWJj", "YWJjZA=="};
|
||||||
|
char buf[100];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; in[i] != NULL; i++) {
|
||||||
|
base64_encode((unsigned char *) in[i], strlen(in[i]), buf);
|
||||||
|
printf("[%s] [%s]\n", out[i], buf);
|
||||||
|
ASSERT(!strcmp(buf, out[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_mg_get_var(void) {
|
||||||
|
static const char *post[] = {
|
||||||
|
"a=1&&b=2&d&=&c=3%20&e=",
|
||||||
|
"q=&st=2012%2F11%2F13+17%3A05&et=&team_id=",
|
||||||
|
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(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) == -2);
|
||||||
|
|
||||||
|
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);
|
||||||
|
ASSERT(mg_get_var(post[1], strlen(post[1]), "st", buf, 16) == -2);
|
||||||
|
ASSERT(mg_get_var(post[1], strlen(post[1]), "st", buf, 17) == 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_set_throttle(void) {
|
||||||
|
ASSERT(set_throttle(NULL, 0x0a000001, "/") == 0);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=20", 0x0a000001, "/") == 20);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=0.5k", 0x0a000001, "/") == 512);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=17m", 0x0a000001, "/") == 1048576 * 17);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=1x", 0x0a000001, "/") == 0);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=5,0.0.0.0/0=10", 0x0a000001, "/") == 10);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=5,/foo/**=7", 0x0a000001, "/index") == 5);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=5,/foo/**=7", 0x0a000001, "/foo/x") == 7);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=5,/foo/**=7", 0x0b000001, "/foxo/x") == 0);
|
||||||
|
ASSERT(set_throttle("10.0.0.0/8=5,*=1", 0x0b000001, "/foxo/x") == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_next_option(void) {
|
||||||
|
const char *p, *list = "x/8,/y**=1;2k,z";
|
||||||
|
struct vec a, b;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ASSERT(next_option(NULL, &a, &b) == NULL);
|
||||||
|
for (i = 0, p = list; (p = next_option(p, &a, &b)) != NULL; i++) {
|
||||||
|
ASSERT(i != 0 || (a.ptr == list && a.len == 3 && b.len == 0));
|
||||||
|
ASSERT(i != 1 || (a.ptr == list + 4 && a.len == 4 && b.ptr == list + 9 &&
|
||||||
|
b.len == 4));
|
||||||
|
|
||||||
|
ASSERT(i != 2 || (a.ptr == list + 14 && a.len == 1 && b.len == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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\nhello 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
|
||||||
|
|
||||||
|
static void *user_data_tester(enum mg_event event, struct mg_connection *conn) {
|
||||||
|
struct mg_request_info *ri = mg_get_request_info(conn);
|
||||||
|
ASSERT(ri->user_data == (void *) 123);
|
||||||
|
ASSERT(event == MG_NEW_REQUEST);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_user_data(void) {
|
||||||
|
static const char *options[] = {"listening_ports", UNUSED_PORT, NULL};
|
||||||
|
struct mg_context *ctx;
|
||||||
|
|
||||||
|
ASSERT((ctx = mg_start(user_data_tester, (void *) 123, options)) != NULL);
|
||||||
|
ASSERT(ctx->user_data == (void *) 123);
|
||||||
|
call_user(fc(ctx), MG_NEW_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_mg_stat(void) {
|
||||||
|
static struct mg_context ctx;
|
||||||
|
struct file file;
|
||||||
|
memset(&file, 'A', sizeof(file));
|
||||||
|
ASSERT(!mg_stat(fc(&ctx), " does not exist ", &file));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_skip_quoted(void) {
|
||||||
|
char x[] = "a=1, b=2 c='hi \' there'", *s = x, *p;
|
||||||
|
|
||||||
|
p = skip_quoted(&s, ", ", ", ", 0);
|
||||||
|
ASSERT(p != NULL && !strcmp(p, "a=1"));
|
||||||
|
|
||||||
|
p = skip_quoted(&s, ", ", ", ", 0);
|
||||||
|
ASSERT(p != NULL && !strcmp(p, "b=2"));
|
||||||
|
|
||||||
|
// TODO(lsm): fix this
|
||||||
|
#if 0
|
||||||
|
p = skip_quoted(&s, "'", ", ", '\\');
|
||||||
|
p = skip_quoted(&s, "'", ", ", '\\');
|
||||||
|
printf("[%s]\n", p);
|
||||||
|
ASSERT(p != NULL && !strcmp(p, "hi ' there"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
test_base64_encode();
|
||||||
test_match_prefix();
|
test_match_prefix();
|
||||||
test_remove_double_dots();
|
test_remove_double_dots();
|
||||||
test_should_keep_alive();
|
test_should_keep_alive();
|
||||||
test_parse_http_request();
|
test_parse_http_request();
|
||||||
test_mg_fetch();
|
test_mg_fetch();
|
||||||
|
test_mg_get_var();
|
||||||
|
test_set_throttle();
|
||||||
|
test_next_option();
|
||||||
|
test_user_data();
|
||||||
|
test_mg_stat();
|
||||||
|
#ifdef USE_LUA
|
||||||
|
test_lua();
|
||||||
|
#endif
|
||||||
|
test_skip_quoted();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<html>
|
||||||
|
<form method="post">
|
||||||
|
<input name="x" type="text" />
|
||||||
|
<input type="submit" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<? echo $_POST["x"]; ?>
|
||||||
|
|
||||||
|
</html>
|
||||||
Reference in new issue
Block a user