mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
@@ -7,14 +7,14 @@ all:
|
||||
@echo "make (linux|bsd|solaris|mac|windows|mingw)"
|
||||
|
||||
# Possible COPT values: (in brackets are rough numbers for 'gcc -O2' on i386)
|
||||
# -DHAVE_MD5 - use system md5 library (-2kb)
|
||||
# -DNDEBUG - strip off all debug code (-5kb)
|
||||
# -DDEBUG - build debug version (very noisy) (+7kb)
|
||||
# -DNO_CGI - disable CGI support (-5kb)
|
||||
# -DNO_SSL - disable SSL functionality (-2kb)
|
||||
# -DCONFIG_FILE=\"file\" - use `file' as the default config file
|
||||
# -DHAVE_STRTOUI64 - use system strtoui64() function for strtoull()
|
||||
# -DSSL_LIB=\"libssl.so.<version>\" - use system versioned SSL shared object
|
||||
# -DHAVE_MD5 - use system md5 library (-2kb)
|
||||
# -DNDEBUG - strip off all debug code (-5kb)
|
||||
# -DDEBUG - build debug version (very noisy) (+7kb)
|
||||
# -DNO_CGI - disable CGI support (-5kb)
|
||||
# -DNO_SSL - disable SSL functionality (-2kb)
|
||||
# -DCONFIG_FILE=\"file\" - use `file' as the default config file
|
||||
# -DHAVE_STRTOUI64 - use system strtoui64() function for strtoull()
|
||||
# -DSSL_LIB=\"libssl.so.<version>\" - use system versioned SSL shared object
|
||||
# -DCRYPTO_LIB=\"libcrypto.so.<version>\" - use system versioned CRYPTO so
|
||||
|
||||
|
||||
@@ -22,18 +22,19 @@ all:
|
||||
### UNIX build: linux, bsd, mac, rtems
|
||||
##########################################################################
|
||||
|
||||
CFLAGS = -W -Wall -std=c99 -pedantic -O2 $(COPT)
|
||||
MAC_SHARED = -flat_namespace -bundle -undefined suppress
|
||||
LINFLAGS = -ldl -pthread $(CFLAGS)
|
||||
LIB = _$(PROG).so
|
||||
#CC = g++
|
||||
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)
|
||||
LIB = lib$(PROG).so$(MONGOOSE_LIB_SUFFIX)
|
||||
|
||||
# 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
|
||||
# "-Wl,--as-needed" turned on by default in cc command.
|
||||
# Also, this is turned in many other distros in static linkage builds.
|
||||
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)
|
||||
|
||||
bsd:
|
||||
@@ -45,9 +46,9 @@ mac:
|
||||
$(CC) mongoose.c main.c -pthread -o $(PROG) $(CFLAGS)
|
||||
|
||||
solaris:
|
||||
gcc mongoose.c -pthread -lnsl \
|
||||
$(CC) mongoose.c -pthread -lnsl \
|
||||
-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,18 +56,19 @@ solaris:
|
||||
##########################################################################
|
||||
|
||||
# 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"
|
||||
|
||||
VC= z:
|
||||
CYA= y:
|
||||
#DBG= /Zi /DDEBUG /Od
|
||||
DBG= /DNDEBUG /O1
|
||||
CL= cl /MD /TC /nologo $(DBG) /Gz /W3 /DNO_SSL_DL
|
||||
GUILIB= user32.lib shell32.lib
|
||||
LINK= /link /incremental:no /libpath:$(VC)\lib /subsystem:windows \
|
||||
ws2_32.lib advapi32.lib cyassl.lib
|
||||
CYAFL = /c /I $(CYA)/include -I $(CYA)/include/openssl \
|
||||
MSVC = e:/vc6
|
||||
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
|
||||
GUILIB= user32.lib shell32.lib
|
||||
LINK = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \
|
||||
/subsystem:windows ws2_32.lib advapi32.lib cyassl.lib
|
||||
CYAFL = /c /I $(CYA)/include -I $(CYA)/include/openssl /I$(MSVC)/INCLUDE \
|
||||
/I $(CYA)/ctaocrypt/include /D _LIB /D OPENSSL_EXTRA
|
||||
|
||||
CYASRC= \
|
||||
@@ -101,26 +103,26 @@ CYASRC= \
|
||||
$(CYA)/ctaocrypt/src/sha512.c \
|
||||
$(CYA)/ctaocrypt/src/tfm.c
|
||||
|
||||
cyassl:
|
||||
cyassl.lib:
|
||||
$(CL) $(CYASRC) $(CYAFL) $(DEF)
|
||||
lib *.obj /out:cyassl.lib
|
||||
$(MSVC)/bin/lib *.obj /out:$@
|
||||
|
||||
windows:
|
||||
rc win32\res.rc
|
||||
$(CL) main.c mongoose.c /GA $(LINK) win32\res.res \
|
||||
windows: cyassl.lib
|
||||
$(MSVC)/bin/rc win32\res.rc
|
||||
$(CL) /I win32 main.c mongoose.c /GA $(LINK) win32\res.res \
|
||||
$(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
|
||||
#MINGWDBG= -DDEBUG -O0
|
||||
#MINGWDBG= -DDEBUG -O0 -ggdb
|
||||
MINGWDBG= -DNDEBUG -Os
|
||||
#MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT
|
||||
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,windows $(MINGWDBG)
|
||||
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
|
||||
#MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,windows $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
|
||||
mingw:
|
||||
windres win32\res.rc win32\res.o
|
||||
gcc $(MINGWOPT) mongoose.c -lws2_32 \
|
||||
-shared -Wl,--out-implib=$(PROG).lib -o _$(PROG).dll
|
||||
gcc $(MINGWOPT) mongoose.c main.c win32\res.o -lws2_32 -ladvapi32 \
|
||||
$(CC) $(MINGWOPT) mongoose.c -lws2_32 \
|
||||
-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
|
||||
$(CC) $(MINGWOPT) -Iwin32 mongoose.c main.c win32\res.o -lws2_32 -ladvapi32 \
|
||||
-o $(PROG).exe
|
||||
|
||||
|
||||
@@ -135,12 +137,11 @@ man:
|
||||
# "TEST=unit make test" - perform unit test only
|
||||
# "TEST=embedded" - test embedded API by building and testing test/embed.c
|
||||
# "TEST=basic_tests" - perform basic tests only (no CGI, SSI..)
|
||||
test: do_test
|
||||
do_test:
|
||||
tests:
|
||||
perl test/test.pl $(TEST)
|
||||
|
||||
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
|
||||
rm -rf *.o *.core $(PROG) *.obj *.so $(PROG).txt *.dSYM *.tgz $(PROG).exe *.dll *.lib
|
||||
@@ -0,0 +1,31 @@
|
||||
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, then a mongoose.conf file with respective options can be created in the same directory where executable 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
|
||||
- Resumed download, URL rewrite support
|
||||
- IP-based ACL, Windows service, GET, POST, HEAD, PUT, DELETE methods
|
||||
- Small footprint: executable size is 40 kB on Linux 2.6 i386 system
|
||||
- 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)
|
||||
- Python and C# bindings
|
||||
|
||||
|
||||
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!
|
||||
@@ -13,7 +13,7 @@ def EventHandler(event, conn):
|
||||
if event == mongoose.HTTP_ERROR:
|
||||
conn.printf('%s', 'HTTP/1.0 200 OK\r\n')
|
||||
conn.printf('%s', 'Content-Type: text/plain\r\n\r\n')
|
||||
conn.printf('HTTP error: %d\n', info.status_code)
|
||||
conn.printf('HTTP error: %d\n', conn.reply_status_code)
|
||||
return True
|
||||
elif event == mongoose.NEW_REQUEST and info.uri == '/show':
|
||||
conn.printf('%s', 'HTTP/1.0 200 OK\r\n')
|
||||
|
||||
@@ -40,10 +40,15 @@ import ctypes
|
||||
import os
|
||||
|
||||
|
||||
NEW_REQUEST = 0
|
||||
HTTP_ERROR = 1
|
||||
EVENT_LOG = 2
|
||||
INIT_SSL = 3
|
||||
NEW_REQUEST = 0
|
||||
REQUEST_COMPLETE = 1
|
||||
HTTP_ERROR = 2
|
||||
EVENT_LOG = 3
|
||||
INIT_SSL = 4
|
||||
WEBSOCKET_CONNECT = 5
|
||||
WEBSOCKET_READY = 6
|
||||
WEBSOCKET_MESSAGE = 7
|
||||
WEBSOCKET_CLOSE = 8
|
||||
|
||||
|
||||
class mg_header(ctypes.Structure):
|
||||
@@ -57,16 +62,13 @@ class mg_header(ctypes.Structure):
|
||||
class mg_request_info(ctypes.Structure):
|
||||
"""A wrapper for struct mg_request_info."""
|
||||
_fields_ = [
|
||||
('user_data', ctypes.c_char_p),
|
||||
('request_method', ctypes.c_char_p),
|
||||
('uri', ctypes.c_char_p),
|
||||
('http_version', ctypes.c_char_p),
|
||||
('query_string', ctypes.c_char_p),
|
||||
('remote_user', ctypes.c_char_p),
|
||||
('log_message', ctypes.c_char_p),
|
||||
('remote_ip', ctypes.c_long),
|
||||
('remote_port', ctypes.c_int),
|
||||
('status_code', ctypes.c_int),
|
||||
('is_ssl', ctypes.c_int),
|
||||
('num_headers', ctypes.c_int),
|
||||
('http_headers', mg_header * 64),
|
||||
@@ -84,6 +86,10 @@ class Connection(object):
|
||||
self.m = mongoose
|
||||
self.conn = ctypes.c_void_p(connection)
|
||||
self.info = self.m.dll.mg_get_request_info(self.conn).contents
|
||||
self.user_data = self.m.dll.mg_get_user_data(self.conn)
|
||||
self.log_message = self.m.dll.mg_get_log_message(self.conn)
|
||||
self.reply_status_code = self.m.dll.mg_get_reply_status_code(self.conn)
|
||||
self.ssl_context = self.m.dll.mg_get_ssl_context(self.conn)
|
||||
|
||||
def get_header(self, name):
|
||||
val = self.m.dll.mg_get_header(self.conn, name)
|
||||
@@ -117,9 +123,9 @@ class Mongoose(object):
|
||||
|
||||
def __init__(self, callback, **kwargs):
|
||||
if os.name == 'nt':
|
||||
self.dll = ctypes.WinDLL('_mongoose.dll')
|
||||
self.dll = ctypes.WinDLL('mongoose.dll')
|
||||
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_modify_passwords_file.restype = ctypes.c_int
|
||||
@@ -131,6 +137,10 @@ class Mongoose(object):
|
||||
self.dll.mg_get_cookie.restype = ctypes.c_int
|
||||
self.dll.mg_get_option.restype = ctypes.c_char_p
|
||||
self.dll.mg_get_request_info.restype = ctypes.POINTER(mg_request_info)
|
||||
self.dll.mg_get_user_data.restype = ctypes.c_void_p
|
||||
self.dll.mg_get_reply_status_code.restype = ctypes.c_int
|
||||
self.dll.mg_get_log_message.restype = ctypes.c_char_p
|
||||
self.dll.mg_get_ssl_context.restype = ctypes.c_void_p
|
||||
|
||||
if callback:
|
||||
# Create a closure that will be called by the shared library.
|
||||
|
||||
@@ -4,4 +4,7 @@ all:
|
||||
OS=`uname`; \
|
||||
test "$$OS" = Linux && LIBS="-ldl" ; \
|
||||
$(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
|
||||
+5
-3
@@ -122,7 +122,7 @@ static int handle_jsonp(struct mg_connection *conn,
|
||||
if (cb[0] != '\0') {
|
||||
mg_printf(conn, "%s(", cb);
|
||||
}
|
||||
|
||||
|
||||
return cb[0] == '\0' ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -369,8 +369,10 @@ int main(void) {
|
||||
srand((unsigned) time(0));
|
||||
|
||||
// Setup and start Mongoose
|
||||
ctx = mg_start(&event_handler, NULL, options);
|
||||
assert(ctx != NULL);
|
||||
if ((ctx = mg_start(&event_handler, NULL, options)) == NULL) {
|
||||
printf("%s\n", "Cannot start chat server, fatal exit");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Wait until enter is pressed, then exit
|
||||
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) {
|
||||
|
||||
if (data === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.each(data, function(index, entry) {
|
||||
var row = $('<div>').addClass('message-row').appendTo('#mml');
|
||||
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({
|
||||
dataType: 'jsonp',
|
||||
url: chat.backendUrl + '/ajax/get_messages',
|
||||
@@ -51,7 +56,9 @@ chat.getMessages = function() {
|
||||
error: function() {
|
||||
},
|
||||
});
|
||||
window.setTimeout(chat.getMessages, chat.getMessagesIntervalMs);
|
||||
if (enter_loop) {
|
||||
window.setTimeout('chat.getMessages(true)', chat.getMessagesIntervalMs);
|
||||
}
|
||||
};
|
||||
|
||||
chat.handleMenuItemClick = function(ev) {
|
||||
@@ -81,7 +88,7 @@ chat.handleMessageInput = function(ev) {
|
||||
success: function(ev) {
|
||||
input.value = '';
|
||||
input.disabled = false;
|
||||
chat.getMessages();
|
||||
chat.getMessages(false);
|
||||
},
|
||||
error: function(ev) {
|
||||
chat.showError('Error sending message');
|
||||
@@ -93,7 +100,7 @@ chat.handleMessageInput = function(ev) {
|
||||
$(document).ready(function() {
|
||||
$('.menu-item').click(chat.handleMenuItemClick);
|
||||
$('.message-input').keypress(chat.handleMessageInput);
|
||||
chat.getMessages();
|
||||
chat.getMessages(true);
|
||||
});
|
||||
|
||||
// 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,130 @@
|
||||
// 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>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include "mongoose.h"
|
||||
|
||||
// Make sure that form has enctype="multipart/form-data" attribute
|
||||
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>";
|
||||
|
||||
static const char *HTTP_500 = "HTTP/1.0 500 Server Error\r\n\r\n";
|
||||
|
||||
static void handle_file_upload(struct mg_connection *conn) {
|
||||
const char *cl_header;
|
||||
char post_data[16 * 1024], path[999], file_name[1024], mime_type[100],
|
||||
buf[BUFSIZ], *eop, *s, *p;
|
||||
FILE *fp;
|
||||
long long int cl, written;
|
||||
int fd, n, post_data_len;
|
||||
|
||||
// Figure out total content length. Return if it is not present or invalid.
|
||||
cl_header = mg_get_header(conn, "Content-Length");
|
||||
if (cl_header == NULL || (cl = strtoll(cl_header, NULL, 10)) <= 0) {
|
||||
mg_printf(conn, "%s%s", HTTP_500, "Invalid Conent-Length");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the initial chunk into memory. This should be multipart POST data.
|
||||
// Parse headers, where we should find file name and content-type.
|
||||
post_data_len = mg_read(conn, post_data, sizeof(post_data));
|
||||
file_name[0] = mime_type[0] = '\0';
|
||||
for (s = p = post_data; p < &post_data[post_data_len]; p++) {
|
||||
if (p[0] == '\r' && p[1] == '\n') {
|
||||
if (s == p) {
|
||||
p += 2;
|
||||
break; // End of headers
|
||||
}
|
||||
p[0] = p[1] = '\0';
|
||||
sscanf(s, "Content-Type: %99s", mime_type);
|
||||
// TODO(lsm): don't expect filename to be the 3rd field,
|
||||
// parse the header properly instead.
|
||||
sscanf(s, "Content-Disposition: %*s %*s filename=\"%1023[^\"]",
|
||||
file_name);
|
||||
s = p + 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Finished parsing headers. Now "p" points to the first byte of data.
|
||||
// Calculate file size
|
||||
cl -= p - post_data; // Subtract headers size
|
||||
cl -= strlen(post_data); // Subtract the boundary marker at the end
|
||||
cl -= 6; // Subtract "\r\n" before and after boundary
|
||||
|
||||
// Construct destination file name. Write to /tmp, do not allow
|
||||
// paths that contain slashes.
|
||||
if ((s = strrchr(file_name, '/')) == NULL) {
|
||||
s = file_name;
|
||||
}
|
||||
snprintf(path, sizeof(path), "/tmp/%s", s);
|
||||
|
||||
if (file_name[0] == '\0') {
|
||||
mg_printf(conn, "%s%s", HTTP_500, "Can't get file name");
|
||||
} else if (cl <= 0) {
|
||||
mg_printf(conn, "%s%s", HTTP_500, "Empty file");
|
||||
} else if ((fd = open(path, O_CREAT | O_TRUNC |
|
||||
O_WRONLY | O_EXLOCK | O_CLOEXEC)) < 0) {
|
||||
// We're opening the file with exclusive lock held. This guarantee us that
|
||||
// there is no other thread can save into the same file simultaneously.
|
||||
mg_printf(conn, "%s%s", HTTP_500, "Cannot open file");
|
||||
} else if ((fp = fdopen(fd, "w")) == NULL) {
|
||||
mg_printf(conn, "%s%s", HTTP_500, "Cannot reopen file stream");
|
||||
close(fd);
|
||||
} else {
|
||||
// Success. Write data into the file.
|
||||
eop = post_data + post_data_len;
|
||||
n = p + cl > eop ? (int) (eop - p) : (int) cl;
|
||||
(void) fwrite(p, 1, n, fp);
|
||||
written = n;
|
||||
while (written < cl &&
|
||||
(n = mg_read(conn, buf, cl - written > (long long) sizeof(buf) ?
|
||||
sizeof(buf) : cl - written)) > 0) {
|
||||
(void) fwrite(buf, 1, n, fp);
|
||||
written += n;
|
||||
}
|
||||
(void) fclose(fp);
|
||||
mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n"
|
||||
"Saved to [%s], written %llu bytes", path, cl);
|
||||
}
|
||||
}
|
||||
|
||||
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")) {
|
||||
handle_file_upload(conn);
|
||||
} 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,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 <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
@@ -191,7 +192,8 @@ static void process_command_line_arguments(char *argv[], char **options) {
|
||||
line_no++;
|
||||
|
||||
// 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (argv[i][0] != '-' || argv[i + 1] == NULL) {
|
||||
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) {
|
||||
if (ev == MG_EVENT_LOG) {
|
||||
printf("%s\n", mg_get_request_info(conn)->log_message);
|
||||
printf("%s\n", mg_get_log_message(conn));
|
||||
}
|
||||
|
||||
// Returning NULL marks request as not handled, signalling mongoose to
|
||||
// proceed with handling it.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -483,6 +487,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdline, int show) {
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
// Return the WM_QUIT value.
|
||||
return msg.wParam;
|
||||
}
|
||||
#else
|
||||
|
||||
+13
-3
@@ -1,7 +1,7 @@
|
||||
.\" Process this file with
|
||||
.\" groff -man -Tascii mongoose.1
|
||||
.\" $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
|
||||
.Sh NAME
|
||||
.Nm mongoose
|
||||
@@ -82,8 +82,6 @@ Use
|
||||
as a CGI interpreter for all CGI scripts regardless script extension.
|
||||
Mongoose decides which interpreter to use by looking at
|
||||
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
|
||||
Comma separated list of URI=PATH pairs, specifying that given URIs
|
||||
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.
|
||||
Unknown SSI directives are silently ignored. Currently, two SSI directives
|
||||
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
|
||||
Access log file. Default: "", no logging is done.
|
||||
.It Fl d Ar enable_directory_listing
|
||||
|
||||
+754
-344
File diff suppressed because it is too large.
Load diff
+58
-30
@@ -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
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -34,16 +34,13 @@ struct mg_connection; // Handle for the individual connection
|
||||
|
||||
// This structure contains information about the HTTP request.
|
||||
struct mg_request_info {
|
||||
void *user_data; // User-defined pointer passed to mg_start()
|
||||
char *request_method; // "GET", "POST", etc
|
||||
char *uri; // URL-decoded URI
|
||||
char *http_version; // E.g. "1.0", "1.1"
|
||||
char *query_string; // URL part after '?' (not including '?') or NULL
|
||||
char *remote_user; // Authenticated user, or NULL if no auth used
|
||||
char *log_message; // Mongoose error log message, MG_EVENT_LOG only
|
||||
long remote_ip; // Client's IP address
|
||||
int remote_port; // Client's port
|
||||
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 {
|
||||
@@ -52,16 +49,23 @@ struct mg_request_info {
|
||||
} http_headers[64]; // Maximum 64 headers
|
||||
};
|
||||
|
||||
|
||||
// Various events on which user-defined function is called by Mongoose.
|
||||
enum mg_event {
|
||||
MG_NEW_REQUEST, // New HTTP request has arrived from the client
|
||||
MG_HTTP_ERROR, // HTTP error must be returned to the client
|
||||
MG_EVENT_LOG, // Mongoose logs an event, request_info.log_message
|
||||
MG_INIT_SSL, // Mongoose initializes SSL. Instead of mg_connection *,
|
||||
// SSL context is passed to the callback function.
|
||||
MG_REQUEST_COMPLETE // Mongoose has finished handling the request
|
||||
MG_NEW_REQUEST, // New HTTP request has arrived from the client
|
||||
MG_REQUEST_COMPLETE, // Mongoose has finished handling the request
|
||||
MG_HTTP_ERROR, // HTTP error must be returned to the client
|
||||
MG_EVENT_LOG, // Mongoose logs an event, request_info.log_message
|
||||
MG_INIT_SSL, // SSL initialization, sent before certificate setup
|
||||
MG_WEBSOCKET_CONNECT, // Sent on HTTP connect, before websocket handshake.
|
||||
// If user callback returns NULL, then mongoose proceeds
|
||||
// with handshake, otherwise it closes the connection.
|
||||
MG_WEBSOCKET_READY, // Handshake has been successfully completed.
|
||||
MG_WEBSOCKET_MESSAGE, // Incoming message from the client
|
||||
MG_WEBSOCKET_CLOSE, // Client has closed the connection
|
||||
};
|
||||
|
||||
|
||||
// Prototype for the user-defined function. Mongoose calls this function
|
||||
// on every MG_* event.
|
||||
//
|
||||
@@ -77,8 +81,7 @@ enum mg_event {
|
||||
// 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.
|
||||
// Mongoose proceeds with request handling as if nothing happened.
|
||||
typedef void * (*mg_callback_t)(enum mg_event event,
|
||||
struct mg_connection *conn);
|
||||
typedef void *(*mg_callback_t)(enum mg_event event, struct mg_connection *conn);
|
||||
|
||||
|
||||
// Start web server.
|
||||
@@ -151,26 +154,49 @@ int mg_modify_passwords_file(const char *passwords_file_name,
|
||||
const char *password);
|
||||
|
||||
|
||||
// Return mg_request_info structure associated with the request.
|
||||
// Always succeeds.
|
||||
const struct mg_request_info *mg_get_request_info(struct mg_connection *);
|
||||
// Return information associated with the request.
|
||||
// These functions always succeed.
|
||||
const struct mg_request_info *mg_get_request_info(const struct mg_connection *);
|
||||
void *mg_get_user_data(struct mg_connection *);
|
||||
const char *mg_get_log_message(const struct mg_connection *);
|
||||
int mg_get_reply_status_code(const struct mg_connection *);
|
||||
void *mg_get_ssl_context(const struct mg_connection *);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// Send data to the browser using printf() semantics.
|
||||
//
|
||||
// Works exactly like mg_write(), but allows to do message formatting.
|
||||
// Note that mg_printf() uses internal buffer of size IO_BUF_SIZE
|
||||
// (8 Kb by default) as temporary message storage for formatting. Do not
|
||||
// print data that is bigger than that, otherwise it will be truncated.
|
||||
int mg_printf(struct mg_connection *, const char *fmt, ...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
// Below are the macros for enabling compiler-specific checks for
|
||||
// printf-like arguments.
|
||||
|
||||
#undef PRINTF_FORMAT_STRING
|
||||
#if _MSC_VER >= 1400
|
||||
#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
|
||||
;
|
||||
#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.
|
||||
@@ -201,10 +227,12 @@ const char *mg_get_header(const struct mg_connection *, const char *name);
|
||||
//
|
||||
// Return:
|
||||
// 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, or destination buffer is too small).
|
||||
// -2 (destination buffer is NULL or zero length).
|
||||
//
|
||||
// Destination buffer is guaranteed to be '\0' - terminated. In case of
|
||||
// failure, dst[0] == '\0'.
|
||||
// Destination buffer is guaranteed to be '\0' - terminated if it is not
|
||||
// NULL or zero length. In case of failure, dst[0] == '\0'.
|
||||
int mg_get_var(const char *data, size_t data_len,
|
||||
const char *var_name, char *buf, size_t buf_len);
|
||||
|
||||
@@ -216,7 +244,7 @@ int mg_get_var(const char *data, size_t data_len,
|
||||
//
|
||||
// Return:
|
||||
// On success, value length.
|
||||
// On error, 0 (either "Cookie:" header is not present at all, or the
|
||||
// On error, -1 (either "Cookie:" header is not present at all, or the
|
||||
// requested parameter is not found, or destination buffer is too small
|
||||
// to hold the value).
|
||||
int mg_get_cookie(const struct mg_connection *,
|
||||
@@ -243,8 +271,8 @@ void mg_close_connection(struct mg_connection *conn);
|
||||
// Return:
|
||||
// On error, NULL
|
||||
// On success, opened file stream to the downloaded contents. The stream
|
||||
// is positioned to the end of the file. It is a user responsibility
|
||||
// to fclose() opened file stream.
|
||||
// is positioned to the end of the file. It is the user's responsibility
|
||||
// to fclose() the opened file stream.
|
||||
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);
|
||||
|
||||
@@ -266,11 +294,11 @@ const char *mg_version(void);
|
||||
|
||||
// MD5 hash given strings.
|
||||
// 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:
|
||||
// char buf[33];
|
||||
// mg_md5(buf, "aa", "bb", NULL);
|
||||
void mg_md5(char *buf, ...);
|
||||
void mg_md5(char buf[33], ...);
|
||||
|
||||
|
||||
#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,
|
||||
const struct mg_request_info *ri) {
|
||||
(void) ri;
|
||||
mg_printf(conn, "HTTP/1.1 %d XX\r\n"
|
||||
"Conntection: close\r\n\r\n", ri->status_code);
|
||||
mg_printf(conn, "Error: [%d]", ri->status_code);
|
||||
"Conntection: close\r\n\r\n", mg_get_reply_status_code(conn));
|
||||
mg_printf(conn, "Error: [%d]", mg_get_reply_status_code(conn));
|
||||
}
|
||||
|
||||
static void test_post(struct mg_connection *conn,
|
||||
|
||||
@@ -215,8 +215,6 @@ $num_requests++;
|
||||
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 /%5c/a.txt HTTP/1.0\n\n", 'blah', 'GET dir backslash');
|
||||
|
||||
# Test HTTP version parsing
|
||||
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');
|
||||
|
||||
+71
-8
@@ -1,3 +1,4 @@
|
||||
#define USE_WEBSOCKET
|
||||
#include "mongoose.c"
|
||||
|
||||
#define FATAL(str, line) do { \
|
||||
@@ -64,10 +65,10 @@ static void test_should_keep_alive(void) {
|
||||
parse_http_request(req4, sizeof(req4), &conn.request_info);
|
||||
ASSERT(should_keep_alive(&conn) == 1);
|
||||
|
||||
conn.request_info.status_code = 401;
|
||||
conn.status_code = 401;
|
||||
ASSERT(should_keep_alive(&conn) == 0);
|
||||
|
||||
conn.request_info.status_code = 200;
|
||||
conn.status_code = 200;
|
||||
conn.must_close = 1;
|
||||
ASSERT(should_keep_alive(&conn) == 0);
|
||||
}
|
||||
@@ -111,17 +112,14 @@ static void test_remove_double_dots() {
|
||||
{"/...///", "/./"},
|
||||
{"/a...///", "/a.../"},
|
||||
{"/.x", "/.x"},
|
||||
#if defined(_WIN32)
|
||||
{"/\\", "/"},
|
||||
#else
|
||||
{"/\\", "/\\"},
|
||||
#endif
|
||||
{"/a\\", "/a\\"},
|
||||
{"/a\\\\...", "/a\\."},
|
||||
};
|
||||
size_t 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);
|
||||
ASSERT(strcmp(data[i].before, data[i].after) == 0);
|
||||
}
|
||||
@@ -138,7 +136,7 @@ static void *event_handler(enum mg_event event,
|
||||
"%s", (int) strlen(fetch_data), fetch_data);
|
||||
return "";
|
||||
} else if (event == MG_EVENT_LOG) {
|
||||
printf("%s\n", request_info->log_message);
|
||||
printf("%s\n", mg_get_log_message(conn));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -196,11 +194,76 @@ static void test_mg_fetch(void) {
|
||||
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=", 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) == -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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_base64_encode();
|
||||
test_match_prefix();
|
||||
test_remove_double_dots();
|
||||
test_should_keep_alive();
|
||||
test_parse_http_request();
|
||||
test_mg_fetch();
|
||||
test_mg_get_var();
|
||||
test_set_throttle();
|
||||
test_next_option();
|
||||
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