Compare commits

..
287 Commits
Author SHA1 Message Date
Sergey Lyubka 22f8cb14d5 Updated downloads link 2013-09-07 20:20:11 +01:00
Sergey Lyubka e28b3ca91d Not ignoring SIGCHLD, cause it renders system() unusable on QNX 2013-09-07 19:50:54 +01:00
Sergey Lyubka 73d2b395d1 Moved SIGCHLD handler out of mongoose.c. Embedded user must set SIGCHLD handler if CGI is used. 2013-09-07 19:41:40 +01:00
Sergey Lyubka e556a487e0 Fix for the SCRIPT_NAME in the presence of PATH_INFO, https://code.google.com/p/mongoose/issues/detail?id=403 2013-09-07 18:49:24 +01:00
Sergey Lyubka 5728fa1cea Added windows_tiny target. Adding only mongoose.[ch] files to the source tarball. 2013-09-07 18:47:38 +01:00
Sergey Lyubka b461edabd9 Squashed warnings 2013-09-07 18:46:50 +01:00
Sergey Lyubka c9e666babc Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-09-07 07:07:28 +01:00
Sergey Lyubka 18e64397fc Fixed tests 2013-09-07 07:07:18 +01:00
Sergey Lyubka 3c8418d324 Removed -I$(LUA) from LUA_FLAGS 2013-09-07 07:07:07 +01:00
Sergey Lyubka 784a1580ce Merge pull request #232 from ellusak/master
use chunked encoding for directory listing
2013-09-05 11:18:07 -07:00
Sergey Lyubka 6a0ac69761 version 3.9 -> 4.0 2013-09-05 12:35:44 +01:00
ellusak 7c06279a8c use chunked encoding for directory listing 2013-09-05 17:14:34 +08:00
Sergey Lyubka aec6f85f55 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-09-02 11:15:57 +01:00
Sergey Lyubka 52e3be5c58 Refactored f[un]lockfile for Windows using LockFileEx/UnlockFileEx 2013-09-02 11:15:48 +01:00
Sergey Lyubka 01a664ad06 Merge pull request #231 from tehnick/fix-compilation-warning
Fixed compilation warning
2013-08-31 03:08:06 -07:00
Boris Pek 94933047a7 Fixed compilation warning 2013-08-30 21:32:58 +03:00
Sergey Lyubka cd6005c86f Calling thread_stop() before free-ing conn 2013-08-28 09:54:00 +01:00
Sergey Lyubka 6d14ed3a18 thread_setup -> thread_start 2013-08-28 09:53:10 +01:00
Sergey Lyubka 0fb5db59d3 Putting CFLAGS at the end of the compilation flags for Linux 2013-08-27 00:02:40 +01:00
Sergey Lyubka 20b274bb2b Using amalgamated lua 2013-08-27 00:01:53 +01:00
Sergey Lyubka 00b289a0f4 Added thread_start() and thread_stop() 2013-08-26 12:22:38 +01:00
Sergey Lyubka 9818f9849b Added downloads section 2013-08-20 16:26:33 +01:00
Sergey Lyubka df1c23222e Corrected google group email address. Reworded paragraph about SLRE. 2013-08-20 07:54:28 +01:00
Sergey Lyubka f18ac3e094 Fixed test invokation 2013-08-19 19:10:41 +01:00
Sergey Lyubka d8596fae27 Fixed unit test 2013-08-19 19:10:17 +01:00
Sergey Lyubka 85209ac4fa Reverted contributions by jmucchiello 2013-08-19 11:54:47 +01:00
Sergey Lyubka a58e82b301 Added note about GNU make 2013-08-19 11:39:59 +01:00
Sergey Lyubka 35f485558b Amalgamated Lua 2013-08-19 07:56:13 +01:00
Sergey Lyubka 93365fcbd2 audio/ogg -> application/ogg 2013-08-19 06:46:13 +01:00
Sergey Lyubka e40a44ba70 Moved mod_lua to build/ 2013-08-18 23:04:36 +01:00
Sergey Lyubka 1eed770238 Moved Makefile and main.c to build/ 2013-08-18 23:02:43 +01:00
Sergey Lyubka 511ef4137f Better SSI mime type handling 2013-08-18 13:27:54 +01:00
Sergey Lyubka 479164129b Styling, lines > 80 chars 2013-08-18 13:16:53 +01:00
Sergey Lyubka 08746115e2 Sending EXTRA_HTTP_HEADERS in handle_file_request() 2013-08-18 13:03:39 +01:00
Sergey Lyubka 587aad75c1 License change 2013-08-16 11:28:50 +01:00
Sergey Lyubka 218428662e License change 2013-08-16 11:18:16 +01:00
Sergey Lyubka 04fc209644 removing dmg dir on clean 2013-08-16 11:18:04 +01:00
Sergey Lyubka 53bedd1eb5 made separate targets for each example 2013-08-16 11:17:15 +01:00
Sergey Lyubka a0b43ae8e0 Merge pull request #218 from MikieMorales/patch-3
Changing Embedding example to C file.
2013-08-14 09:50:07 -07:00
Miguel Morales 866a7e2823 Changing Embedding example to C file. 2013-08-14 12:38:32 -04:00
Sergey Lyubka 2055d41a9f Corrected misplaced brackets in parse_http_message() 2013-08-14 10:55:36 +01:00
Sergey Lyubka 1ef29c1b3b Using #define MGSQLEN for the socket queue length 2013-08-14 08:23:30 +01:00
Sergey Lyubka e95dbb90a7 Sending content-length from put_file() 2013-08-14 08:15:42 +01:00
Sergey Lyubka cf18c932a4 Refactored parse_http_message() 2013-08-14 07:41:47 +01:00
Sergey Lyubka a730afc44d Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-08-14 07:09:28 +01:00
Sergey Lyubka 94296c9697 Corrected check for websocket connection close 2013-08-14 07:09:22 +01:00
Sergey Lyubka 667707df50 Merge pull request #214 from DanielOaks/server_software
Added SERVER_SOFTWARE CGI variable
2013-08-13 04:28:26 -07:00
Daniel Oaks 90b6fab3bb Added SERVER_SOFTWARE CGI variable 2013-08-13 21:21:05 +10:00
Sergey Lyubka e47dbcbdc5 Merge pull request #213 from MikieMorales/patch-1
Update UserManual.md
2013-08-12 08:59:39 -07:00
MikieMorales 2a15f8d567 Update UserManual.md
SheBang wikipedia link is broken due to the end parenthesis. I tried escaping it with backslash and it seems to be working now.
2013-08-12 11:23:11 -04:00
Sergey Lyubka b5d397c74f Merge pull request #212 from pas2k/master
Consume \n in mg_fgets when reading from membuf
2013-08-12 04:16:19 -07:00
Pavel Khlebovich 3d6b373c8f (mg_fgets) Accept lines at the end not terminated by \n
(mg_fgets) Don't consume more than size bytes when line cannot fit into buffer.
2013-08-12 14:27:20 +04:00
Sergey Lyubka ed236dddeb changed signature for mg_exec_lua_script(). fixed lua_error_handler() 2013-08-12 09:53:42 +01:00
Sergey Lyubka 596fb1e88a Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-08-12 09:52:22 +01:00
Sergey Lyubka ca0cd5040d Updated sqlite 2013-08-12 09:52:10 +01:00
Pavel Khlebovich 5b84acbc14 Consume \n in mg_fgets when reading from membuf. 2013-08-12 00:47:12 +04:00
Sergey Lyubka c12838e2c3 Merge pull request #211 from nigels-com/msc_ver
gcc complains about _MSC_VER being an undefined macro.
2013-08-08 22:50:19 -07:00
Nigel Stewart fa3e6ce271 gcc complains about _MSC_VER being an undefined macro. 2013-08-08 22:08:00 -05:00
Sergey Lyubka 743f48b8e0 Added mg_exec_lua_script, mg_prepare_lua_environment -> prepare_lua_environment 2013-08-08 13:11:05 +01:00
Sergey Lyubka 421c16b2bb Added -DLUA_USE_DLOPEN, and added mongoose.o: mod_lua.c 2013-08-08 12:15:40 +01:00
Sergey Lyubka 3054a7f09e Make sure child closes all pipe fds when executing CGI 2013-08-03 07:18:25 +01:00
Sergey Lyubka 2de96bd54e Workaround for non-compliant vsnprintf() 2013-08-02 11:00:21 +01:00
Sergey Lyubka f815c315e7 Added git analytics link 2013-08-01 14:20:35 +01:00
Sergey Lyubka e59ee00154 Added request_timeout_ms 2013-07-30 15:21:34 +01:00
Sergey Lyubka b07745ab50 Added Lua dll example 2013-07-30 14:49:52 +01:00
Sergey Lyubka 2468a8fb38 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-07-30 11:19:42 +01:00
Sergey Lyubka ed38a4102e showing error string as well as numeric error on bind failure 2013-07-30 11:19:33 +01:00
Sergey Lyubka b1c66f6544 Merge pull request #207 from bick4ord/master
Add casts to fix strict compiler errors [-fpermissive]
2013-07-29 13:20:43 -07:00
bick 8f79a0564f Add casts to fix strict compiler errors [-fpermissive]
When using g++ and enforcing strict compiler errors, this commit fixes the following:

mongoose.c: In function ‘char* mg_fgets(char*, size_t, file*, char**)’:
mongoose.c:2405:60: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]

mongoose.c: In function ‘int set_ports_option(mg_context*)’:
mongoose.c:4586:64: error: invalid conversion from ‘void*’ to ‘socket*’ [-fpermissive]

mongoose.c: In function ‘void* worker_thread(void*)’:
mongoose.c:5104:28: error: invalid conversion from ‘void*’ to ‘mg_context*’ [-fpermissive]

mongoose.c: In function ‘void* master_thread(void*)’:
mongoose.c:5220:28: error: invalid conversion from ‘void*’ to ‘mg_context*’ [-fpermissive]
mongoose.c:5235:58: error: invalid conversion from ‘void*’ to ‘pollfd*’ [-fpermissive]
2013-07-29 11:46:24 -07:00
Sergey Lyubka 2e93cde929 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-07-28 12:15:30 +01:00
Sergey Lyubka e53d05637a Binding to IPv6 addresses 2013-07-28 12:15:16 +01:00
Sergey Lyubka 9d75d35365 v. x.x -> v.x.x 2013-07-28 08:20:21 +01:00
Sergey Lyubka 2ea8d85cff Merge pull request #206 from bick4ord/master
adding include of openssl/err.h to fix errors when NO_SSL_DL is defined:
2013-07-26 22:48:49 -07:00
bick ea81a22529 adding include of openssl/err.h to fix errors when NO_SSL_DL is defined:
mongoose.c:4680:23: error: ‘ERR_get_error’ was not declared in this scope
mongoose.c:4681:52: error: ‘ERR_error_string’ was not declared in this scope
2013-07-26 14:12:33 -07:00
Sergey Lyubka 526f3aa31c Added check for document_root != NULL in convert_uri_to_file_name(). Added #define rmdir _rmdir for win32 2013-07-25 07:22:02 +01:00
Sergey Lyubka 62d66201c9 make match_prefix() case-insensitive 2013-07-25 07:07:25 +01:00
Sergey Lyubka f32e14478f Merge pull request #203 from JoseGoncalves/fixes
Fix uninitialized argument in getsockname().
2013-07-24 04:58:27 -07:00
José Miguel Gonçalves ca019799b9 Fix uninitialized argument in getsockname(). 2013-07-24 12:24:13 +01:00
Sergey Lyubka c6fb9ac3d0 Fixed indenting in is_put_or_delete_request() 2013-07-23 08:24:52 +01:00
Sergey Lyubka c80a88a407 Added test for uploading 2 files 2013-07-23 08:17:00 +01:00
Sergey Lyubka f2e19ca3ff Fixed indenting 2013-07-23 08:16:38 +01:00
Sergey Lyubka 16c463d2e9 Added compile-time option to set stack size 2013-07-22 10:10:19 +01:00
Sergey Lyubka 6a99518048 updated readme 2013-07-22 09:54:02 +01:00
Sergey Lyubka 3b242ec68b Added Android makefile 2013-07-22 09:45:23 +01:00
Sergey Lyubka 7409166409 Updated readme 2013-07-22 09:30:01 +01:00
Sergey Lyubka ca66b84f7d Updated readme 2013-07-22 09:27:47 +01:00
Sergey Lyubka dc1c732f11 Updated readme 2013-07-22 09:24:17 +01:00
Sergey Lyubka 61148f1323 Using absolute paths for all file/directory options 2013-07-22 08:23:15 +01:00
Sergey Lyubka 136e3e353d updated readme 2013-07-21 10:09:47 +01:00
Sergey Lyubka c70b80e4e1 marketing for LSP added 2013-07-20 15:30:00 +01:00
Sergey Lyubka cba4c9d85d removed travis icon 2013-07-20 15:26:05 +01:00
Sergey Lyubka 3e588065dc removed 2013-07-20 15:25:39 +01:00
Sergey Lyubka 35cb27dbe6 Always use absolute path for document_root. If relative path is used, it is relative to mongoose.exe directory. See https://github.com/valenok/mongoose/issues/181 2013-07-20 14:11:05 +01:00
Sergey Lyubka d6b9f76e9c Added COPT to CFLAGS 2013-07-20 14:08:06 +01:00
Sergey Lyubka a9d51c0e87 squashed warning 2013-07-20 11:33:34 +01:00
Sergey Lyubka 4b163232e3 fixed docstring for mg_get_valid_option_names 2013-07-20 07:12:49 +01:00
Sergey Lyubka e003236a03 Made SSI #include file= relative to the current doc, as per spec 2013-07-19 07:57:47 +01:00
Sergey Lyubka de7745370c Merge pull request #200 from ejohnstown/master
Allow no SSL_CERTIFICATE when using init_ssl callback.
2013-07-18 23:35:16 -07:00
Sergey Lyubka 21786eec8e Changed int -> SOCKET where appropriate, per Ben Currie 2013-07-18 18:17:48 +01:00
Sergey Lyubka 036b213b2b Added connection-specific conn_data pointer to struct mg_request_info 2013-07-18 17:31:16 +01:00
John Safranek 61f5f0b725 Allow no SSL_CERTIFICATE when using init_ssl callback. 2013-07-17 16:37:28 -07:00
Sergey Lyubka d864d72470 On windows, enclosing path to CGI script in quotes to allow paths with spaces 2013-07-17 08:24:52 +01:00
Sergey Lyubka 7ca5962d2d in pull_all() and read_request(), respect ctx->stop_flag() 2013-07-16 17:17:36 +01:00
Sergey Lyubka 8ce1562f0d Using SetHandleInformation() to make socket handles on Windows non-inheritable 2013-07-16 15:52:40 +01:00
Sergey Lyubka 49d9016275 For lua, let mg.read() read only if the data is there. 2013-07-16 13:56:00 +01:00
Sergey Lyubka cdc7380d00 3.8 -> 3.9 2013-07-16 08:13:00 +01:00
Sergey Lyubka e645b33b6c using mg.read() only for POST requests 2013-07-16 07:53:08 +01:00
Sergey Lyubka 30f71a8bc4 Added description for the connect() socket interface 2013-07-16 07:24:39 +01:00
Sergey Lyubka faa030385c Removing extra SSL_shutdown() call. 2013-07-15 18:20:16 +01:00
Sergey Lyubka feb3b5db96 Using $(FLAGS) for cocoa target 2013-07-15 10:52:27 +01:00
Sergey Lyubka 508b67d6f5 Removed /Gd from windows compilation flags, cause that breaks sqlite3 + fts (qsort callback is __cdecl, not __stdcall) 2013-07-15 10:41:47 +01:00
Sergey Lyubka 133aec777d Added enable_keep_alive description 2013-07-15 10:32:52 +01:00
Sergey Lyubka 389ed4e099 Enabling FTS in sqlite 2013-07-15 10:28:52 +01:00
Sergey Lyubka bc40aa5442 fixed strtoll() for win32: using _atoi64 2013-07-14 12:49:24 +01:00
Sergey Lyubka 5fb9aca2e1 Added -mmacosx-version-min for macos build 2013-07-12 12:39:19 +01:00
Sergey Lyubka c68df310b8 Added mg_websocket_write(), per morgan3d pull request 2013-07-12 12:25:25 +01:00
Sergey Lyubka 70ce6c5ad3 Added comments to read_websocket(), per morgan3d pull request 2013-07-12 11:55:52 +01:00
Sergey Lyubka 460738f11b Corrected link to Android NDK 2013-07-11 14:41:04 +01:00
Sergey Lyubka a09ec8988e Added lua.lib target 2013-07-11 14:24:24 +01:00
Sergey Lyubka c46aa050ae MAX_OPTIONS 40 -> 100 2013-07-11 11:37:39 +01:00
Sergey Lyubka 348db16245 NOT redirecting stderr to stdout for UNIX CGI, to avoid output being littered with error messages. 2013-07-11 08:44:51 +01:00
Sergey Lyubka c0ca6a53be put_delete_auth_file is the correct option name 2013-07-10 19:08:21 +01:00
Sergey Lyubka e58d622d5f Added note about /Gz for OpenSSL & Windows 2013-07-10 07:57:20 +01:00
Sergey Lyubka bcb294620f increased buffer for the ip address string from 20 to 50, to allow ipv6 addresses 2013-07-10 07:48:06 +01:00
Sergey Lyubka 15937a9c5c readme updated 2013-07-10 07:37:56 +01:00
Sergey Lyubka fa160cb9a3 Merge pull request #191 from kblinova/master
Detect Window's style slashes in mg_upload file names
2013-07-01 00:47:21 -07:00
Sergey Lyubka 137d6484e2 Removed bogus comment 2013-07-01 08:46:20 +01:00
Sergey Lyubka e7c34c26cb mg_read() with no Content-Length would read until socket is closed 2013-07-01 08:45:07 +01:00
Katerina Blinova dfb7d928c2 Review revision for windows path separator detection in mg_upload 2013-06-28 11:05:33 -07:00
Katerina Blinova 4bb9faaf50 Detect Window's style slashes in mg_upload file names 2013-06-27 11:46:52 -07:00
Sergey Lyubka a856971b6d Update README.md 2013-06-27 13:07:34 +01:00
Sergey Lyubka 4a88ad5ca9 Merge pull request #184 from unrzn0/master
MKCOL and DELETE
2013-06-11 15:30:39 -07:00
Stefan Doehla 17ecb0a459 MKCOL and recursive DELETE 2013-06-12 00:04:07 +02:00
Sergey Lyubka afd39abc6f Update README.md 2013-06-06 05:28:46 +02:00
Sergey Lyubka 4babcff8de Update UserManual.md 2013-06-03 08:18:41 +02:00
Sergey Lyubka 17d48b1d04 Update README.md 2013-06-01 12:23:16 +02:00
Sergey Lyubka 6ab20ed9a3 Update README.md 2013-06-01 12:21:02 +02:00
Sergey Lyubka a0e5494569 Merge pull request #177 from arvidn/master
support serving pre-gzipped files
2013-05-30 10:14:45 -07:00
Sergey Lyubka f62c733990 Merge pull request #176 from codyhanson/portRangeFix
Added bounds checking for listening_ports.
2013-05-30 10:05:21 -07:00
arvidn d283e3167f support serving pre-gzipped files transparently provided the user agent accepts gzip content-encoding. The feature breaks if the user agent makes a range request within a gzipped file, and returns 501 in this case 2013-05-30 09:59:11 -07:00
Cody Hanson 94050d44e4 Added bounds checking for listening_ports.
Needs to be a valid TCP port number, and not less than 1 or greater than 65535
2013-05-30 10:54:59 -06:00
Sergey Lyubka dee97cbf22 Update README.md 2013-05-30 18:24:41 +02:00
Sergey Lyubka be01471968 Update README.md 2013-05-29 13:40:57 +02:00
Sergey Lyubka a74c44c463 Update README.md 2013-05-29 13:37:31 +02:00
Sergey Lyubka 81e53d8375 Update README.md 2013-05-26 19:12:12 +02:00
Sergey Lyubka ca626abcac Update README.md 2013-05-23 18:50:49 +02:00
Sergey Lyubka b5e7730ac7 Update README.md 2013-05-22 23:56:07 +02:00
Sergey Lyubka 33b920ed2c Exported mg_url_encode() 2013-05-19 08:00:42 +01:00
Sergey Lyubka b5b234fab2 Improved docstring for mg_read() 2013-05-19 08:00:12 +01:00
Sergey Lyubka af89d2446b Squashed warnings on win32 in Lua code 2013-05-19 07:46:15 +01:00
Sergey Lyubka 791ad49651 Merge pull request #172 from jwang11/master
Securely close SSL connection by standard SSL_shutdown
2013-05-18 23:43:51 -07:00
jwang 063b26fece Securely close SSL conection
For SSL in close_connection, current implementation use close_socket_gracefully to close socket firstly, then SSL_free. In my
testing, this approach may cause some pending write data missing. I'd suggest use standard SSL_shutdown in SSL conection. It
need call twice according to openSSL manual - one call sends the close_notify alert and one call receives the response from
the peer
2013-05-19 10:40:10 +08:00
Sergey Lyubka add079a949 Added socket functions to lua environment 2013-05-19 01:25:54 +01:00
Sergey Lyubka 6e59ad8a0d Fix for prepare_lua_environment 2013-05-19 01:25:10 +01:00
Sergey Lyubka f4862b646d defined ALL_WINOBJS and using it for windows build 2013-05-18 15:21:52 +01:00
Sergey Lyubka 91fa767efb Fix doc string for websocket_data() 2013-05-18 15:21:20 +01:00
Sergey Lyubka 5e78711467 Fixed masking in websocket code 2013-05-18 10:29:03 +01:00
Sergey Lyubka b4a622cfd6 merge 2013-05-17 11:00:36 +01:00
Sergey Lyubka 8c118bf4cc Exported mg_prepare_lua_environment() 2013-05-17 10:52:40 +01:00
Sergey Lyubka 728ebdaafa Merge pull request #170 from oerik/movadd
Added .mov (quicktime) to builtin_mimes_types
2013-05-16 05:39:10 -07:00
Erik Oomen 3a186976d7 Added .mov (quicktime) to builtin_mimes_types 2013-05-16 14:33:58 +02:00
Sergey Lyubka 2e232b3304 Lua functionality change: print renamed to mg.write, read renamed to mg.read. Expanded user manual, fixed example pages. 2013-05-15 17:42:34 +01:00
Sergey Lyubka d72645bf91 Using local var in open_auth_file 2013-05-15 09:43:38 +01:00
Sergey Lyubka 7d5bcec92d Better cleanup in close_connection() 2013-05-15 08:28:56 +01:00
Sergey Lyubka 215ea28db0 Added lua to the repo 2013-05-14 13:41:44 +01:00
Sergey Lyubka 9b76d60b38 Merge pull request #131 from abadc0de/lua_read_fixup
lsp_mg_read: remove dead code, return nil on empty read
2013-05-13 10:15:34 -07:00
Sergey Lyubka 63ccf8199f Style changes in poll() 2013-05-13 18:07:38 +01:00
Sergey Lyubka 6bc6022aa9 Merge pull request #164 from fredfung/master
Fix parameter 1 for select in poll()
2013-05-13 10:05:26 -07:00
ff.feng b68db66e97 Fix parameter 1 for select in poll() 2013-05-13 23:57:26 +08:00
Sergey Lyubka 94e1c5a41b Added sanity checking in send_file_data() 2013-05-12 23:17:44 +01:00
Sergey Lyubka ab16220861 Not leaking socket in set ports option 2013-05-10 15:40:19 +01:00
Sergey Lyubka c0eb3e56b4 Not using realloc2 in set_ports_option 2013-05-10 15:21:55 +01:00
Sergey Lyubka 5591aa5a0d Added .ttf mime type, https://github.com/valenok/mongoose/issues/129 2013-05-10 14:45:12 +01:00
Sergey Lyubka 6f946f5eea websocket code fix, https://github.com/valenok/mongoose/pull/146 2013-05-10 13:41:48 +01:00
Sergey Lyubka 39cd5b8323 Signature for mg_get_cookie changed 2013-05-10 13:14:04 +01:00
Sergey Lyubka ca96db714a Updated readme 2013-05-10 12:30:30 +01:00
Sergey Lyubka a7f97bf2f2 Fixed leaks, per afs-bb https://github.com/valenok/mongoose/pull/161 2013-05-10 12:22:04 +01:00
Sergey Lyubka e579355b01 url_decode -> mg_url_decode 2013-05-08 11:40:13 +01:00
Sergey Lyubka cfbaf7f1ae Expose mg_url_decode to the API 2013-05-08 11:36:38 +01:00
Sergey Lyubka ce26234ace Merge pull request #159 from aerotech/master
_CRT_SECURE_NO_WARNINGS should not generate a warning if already defined
2013-05-07 03:29:03 -07:00
Pavel c28dc45d4c removing warning about _CRT_SECURE_NO_WARNINGS if it is already defined
modified:   mongoose.c
2013-05-06 09:02:30 -04:00
Sergey Lyubka 98b6c5e16a Merge pull request #157 from Thileepan/master
Environment variable required for PHP cgi
2013-05-06 01:50:26 -07:00
Thileepan 1d9d1111e1 Environmental variables required for PHP cgi.
In few windows machines, the environment variables "ProgramFiles" is required to successfully execute PHP code especially socket functions.
2013-05-06 13:05:37 +05:30
Sergey Lyubka 2a0b55b30b mg_upload: trigger callback when file is already closed 2013-04-26 21:32:22 +01:00
Sergey Lyubka 1e3b167208 updated readme 2013-04-25 16:34:36 +01:00
Sergey Lyubka f7821b757c Updated README 2013-04-19 16:28:39 -07:00
Sergey Lyubka c352486abb Squashed warning in push() 2013-04-11 12:51:07 -07:00
Sergey Lyubka 4120b9bcc0 mg_get_cookie() signature change 2013-04-11 12:49:41 -07:00
Sergey Lyubka f7725f2eeb updated readme 2013-04-02 09:17:36 -07:00
Sergey Lyubka be06c3620c Updated readme 2013-03-28 18:46:15 -07:00
Sergey Lyubka 272644e39f mg_md5 returns char *, not void 2013-03-27 01:31:12 -07:00
Sergey Lyubka 55ef3afea4 Updated README 2013-03-24 09:06:52 -07:00
Sergey Lyubka 9e07c742ff Merge pull request #132 from hendrikp/master
Fixed crash and description for digest authentication
2013-03-19 10:54:05 -07:00
Hendrik Polczynski cd2e50c2c4 Update UserManual.md
fixed/extended global_auth_file description.
2013-03-19 17:52:17 +01:00
Hendrik Polczynski fdef2b8643 Update mongoose.c
when having connections with and without auth would cause double free and then crash
2013-03-19 17:42:21 +01:00
abadc0de ce55924a02 lsp_mg_read: remove dead code, return nil on empty read 2013-03-17 23:33:02 -04:00
Sergey Lyubka fbca54bcaf Updated readme 2013-03-17 07:53:03 -07:00
Sergey Lyubka 41c25d60d6 Updated README 2013-03-13 05:07:20 -07:00
Sergey Lyubka a9b5bb351f Added travis config 2013-03-11 07:25:11 -07:00
Sergey Lyubka 51ed3efcd1 Style fixes 2013-03-09 13:16:41 +00:00
Sergey Lyubka 67cffc8db5 Documented struct mg_callbacks 2013-03-09 13:12:03 +00:00
Sergey Lyubka 72abaa043b Documented struct mg_callbacks 2013-03-09 13:01:02 +00:00
Sergey Lyubka b3a511f9c5 Broken down cocoa target 2013-03-08 16:13:29 +00:00
Sergey Lyubka 8d1f6377c4 Changed websocket_data() handler API. Buffering and passing whole websocket message. 2013-03-08 16:03:23 +00:00
Sergey Lyubka 22dddc2eeb Merge pull request #124 from abadc0de/lua_err
Lua page error handling cleanup
2013-03-08 03:15:04 -08:00
Sergey Lyubka daab527743 Merge pull request #125 from bakwc/warnings
A little bit more warnings suppresed
2013-03-08 02:52:14 -08:00
Filipp Kovalev dd49c0791f A little bit more warnings suppresed 2013-03-08 14:41:17 +04:00
Sergey Lyubka 4b539d4b95 Suppressed some mingw warnings 2013-03-08 07:18:39 +00:00
Sergey Lyubka 5eabfe5da2 Using pijyoi's patch for connection close. 2013-03-08 07:08:09 +00:00
Sergey Lyubka 36b7c8d60d Forcing connection close when client disconnects. 2013-03-08 07:03:23 +00:00
abadc0de aa37b728ad Merge commit '10234' into lua_err 2013-03-07 03:02:15 -05:00
Sergey Lyubka 62085e5215 updated user manual 2013-03-06 13:37:01 +00:00
Sergey Lyubka d036f8a3f0 Merge pull request #118 from theaccordance/master
Added additional artwork files for Retina Display Support
2013-03-05 11:03:18 -08:00
Sergey Lyubka fb5e2b8c2f Setting off IPV6_V6ONLY for USE_IPV6 case 2013-03-05 18:55:33 +00:00
Sergey Lyubka 4505b00733 Removed support for option names 2013-03-05 18:26:10 +00:00
Sergey Lyubka c485b8264e Updated readme 2013-03-05 08:44:25 +00:00
Joseph Mainwaring 8edd710c00 Added additonal icon files to support Retina displays 2013-03-03 20:32:08 -06:00
Sergey Lyubka 3984e9f5cc Grammar in user manual 2013-03-02 10:34:28 +00:00
Sergey Lyubka d4fa794c83 Added mongoose internals section 2013-03-02 10:30:47 +00:00
Sergey Lyubka 3892e0199e Passing user_data to init_ssl() 2013-02-28 09:12:52 +00:00
Sergey Lyubka 67f5de624e updated readme 2013-02-28 08:09:39 +00:00
abadc0de 10234b07c4 Remove dead code 2013-02-27 16:33:05 -05:00
abadc0de 36a83e1452 Merge https://github.com/valenok/mongoose 2013-02-27 15:32:43 -05:00
abadc0de 34df4ec1fd Fix mg.onerror returns non-zero to stop processing 2013-02-27 15:29:18 -05:00
Sergey Lyubka 69cb94f3fb Removed header printing from page.lp 2013-02-27 18:06:35 +00:00
Sergey Lyubka 7204d71136 Merge pull request #102 from abadc0de/master
Better error handling and an include function for lua pages
2013-02-27 03:27:28 -08:00
Sergey Lyubka 283f590349 Merge pull request #106 from BusyJay/feature-2
Fix bugs about range request and explorer crashes
2013-02-27 03:21:33 -08:00
Sergey Lyubka 27735f293b Updated dates 2013-02-27 11:17:33 +00:00
Sergey Lyubka a560334fbb Merge pull request #111 from dpsk/lua_docs
Lua docs
2013-02-27 03:10:14 -08:00
Mikhail Nikalyukin cd1707034c update README.md 2013-02-27 13:04:08 +02:00
Mikhail Nikalyukin 5ce1fc3c2a add lua page example with the form submitting 2013-02-27 13:02:39 +02:00
Sergey Lyubka c78fe425a0 Updated Lua section in user manual 2013-02-27 10:49:31 +00:00
Sergey Lyubka a58bb71c19 Added Lua section to the user manual 2013-02-27 10:44:59 +00:00
Sergey Lyubka fc9a9593d2 Added sqlite to linux_lua target 2013-02-27 10:44:42 +00:00
Sergey Lyubka eb1fdf56e6 Updated readme 2013-02-26 11:47:46 +01:00
abadc0de ab960df8a9 Lua call stack cleanup 2013-02-25 20:48:36 -05:00
abadc0de 08048bd5bb Merge https://github.com/valenok/mongoose 2013-02-25 16:23:50 -05:00
abadc0de 800517ac16 Added support for lua error handling and includes
- Added mg.onerror, mg.include, mg.redirect
- mg.onerror, if overridden, lets the user trap syntax errors and
  other loadbuffer errors, and dump stack traces and debug info
  for uncaught runtime errors.
- Log unexpected errors from mg.onerror handlers
- Provide mg.cry so custom handlers can reproduce default behavior
- Call mg.onerror handler before unwinding stack
- If mg.onerror returns non-0, stop loading chunks
- Included pages stop parent page processing if mg.onerror returns non-zero
- Included pages don't sent HTTP errors, they throw lua errors
2013-02-25 16:19:38 -05:00
Jay 690eff4fa2 Fix bugs about range request and explorer crashes
1. fix a bug that when header contains "Range: 100-", the range request
support will fail
2. (windows) fix a bug that when explorer.exe crashes due to some
reason, the tray icon will disappear.
2013-02-25 22:17:46 +08:00
Sergey Lyubka e47b5b775a Squashed warning 2013-02-24 20:34:32 +00:00
Sergey Lyubka c15e2af897 Merge pull request #104 from pijyoi/warning-fix
minor fixes to reduce warnings in mingw
2013-02-24 12:28:23 -08:00
KIU Shueng Chuan d8536b011c portable socket type should be SOCKET 2013-02-24 23:41:32 +08:00
KIU Shueng Chuan a2239c2b4b squash mingw variable set but not used warning 2013-02-24 23:29:05 +08:00
KIU Shueng Chuan d3c02331d4 squash mingw printf format warning 2013-02-24 23:22:34 +08:00
Sergey Lyubka d707841166 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-02-24 07:58:21 +00:00
Sergey Lyubka affd82a885 updated readme 2013-02-24 07:56:41 +00:00
Sergey Lyubka 8322c82790 Merge pull request #103 from pijyoi/mingw-fix
avoid defining macros already present on mingw32
2013-02-23 00:52:08 -08:00
KIU Shueng Chuan 08708435a7 avoid defining macros already present on mingw32 2013-02-23 10:37:45 +08:00
Sergey Lyubka 1c6036c3ac Updated readme 2013-02-22 08:08:47 +00:00
Sergey Lyubka 6c3cb6f3eb Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-02-22 04:34:21 +00:00
Sergey Lyubka a123874ac5 Updated readme 2013-02-21 22:58:51 +00:00
Sergey Lyubka 7931929a42 Fix compile of mg_strcasestr() under windows 2013-02-18 10:49:03 +00:00
Sergey Lyubka cc4a4fb2ab Added http_error() to struct mg_callbacks 2013-02-16 15:26:11 +00:00
Sergey Lyubka 3d211d89c5 win32 mmap() must not close file handle, issue 99 2013-02-16 14:37:58 +00:00
Sergey Lyubka fbf1ccee45 Fix out-of-bounds acces in url_decode() 2013-02-16 14:31:37 +00:00
Sergey Lyubka 0bd43bcae3 Using mg_strcasestr() instead of strstr() 2013-02-16 14:17:38 +00:00
Sergey Lyubka b809665cad Squashed warning 2013-02-16 12:54:16 +00:00
Sergey Lyubka 463b49f1bd Fixed poll() issue with QNX 2013-02-16 12:54:02 +00:00
Sergey Lyubka a881aad5c6 Updated readme 2013-02-16 11:48:34 +00:00
Sergey Lyubka aae0995cd2 Updated README 2013-02-12 21:24:08 +00:00
Sergey Lyubka 26b3f227d9 Merge branch 'master' of ssh://github.com/valenok/mongoose 2013-02-12 21:04:42 +00:00
Sergey Lyubka 665770d602 cleaning up more files on make clean 2013-02-12 21:04:23 +00:00
Sergey Lyubka fcafaa73d6 Style fixes in the comments 2013-02-12 21:03:54 +00:00
Sergey Lyubka 079b9ec2c1 Added linux_lua target 2013-02-12 12:33:44 +00:00
Sergey Lyubka 7bd9a85897 Merge pull request #92 from jmucchiello/send_http_error
Send http error
2013-02-10 13:51:34 -08:00
Joe Mucchiello 2efc5d9fce http_error callback
Allow user to display status code errors
2013-02-10 15:58:06 -05:00
Joe Mucchiello 1cb094e059 Revert "Add http_error callback"
This reverts commit 27fe9c8f01.
2013-02-10 15:50:20 -05:00
Joe Mucchiello 27fe9c8f01 Add http_error callback
Allows user code to display its own error status responses or just log
the errors. Is called even in cases where begin_request is not called.
2013-02-10 15:02:37 -05:00
jmucchiello 9178fbd153 Merge pull request #1 from valenok/master
update
2013-02-10 11:51:24 -08:00
Sergey Lyubka b2b43ab0cd updated user manual 2013-02-10 16:27:19 +00:00
Sergey Lyubka 1415d187eb Added comments about auth checks done before begin_request() 2013-02-10 15:32:08 +00:00
Sergey Lyubka a65078b858 Calling begin_request() after auth checks. 2013-02-10 15:25:11 +00:00
Sergey Lyubka 7107afae5c updated readme 2013-02-10 15:00:34 +00:00
Sergey Lyubka f6a807c5a4 updated readme 2013-02-10 08:17:59 +00:00
Sergey Lyubka 47b11dd19e Updated README 2013-02-08 10:50:45 +00:00
Sergey Lyubka 61cdc93405 Updated README 2013-02-08 10:49:29 +00:00
Sergey Lyubka 7a52bd643c Updated manual 2013-02-08 10:45:40 +00:00
Sergey Lyubka 63e8052e4b Added index.lp to the index_files 2013-02-08 10:26:25 +00:00
Sergey Lyubka 782d0cda46 Updated user manual 2013-02-08 10:10:02 +00:00
Sergey Lyubka 72803eb7f8 num_threads 20 -> 50 2013-02-08 10:09:53 +00:00
Sergey Lyubka c7fd221ab7 Updated README 2013-02-08 09:17:59 +00:00
Sergey Lyubka 492185e35f Updated README 2013-02-08 09:17:21 +00:00
Sergey Lyubka 845d7b08e1 Fixed assert for keepalive code path 2013-02-08 08:21:52 +00:00
Sergey Lyubka 49bac31d2d Updated README 2013-02-08 08:21:05 +00:00
Sergey Lyubka 9baf2d4ba4 Using keep alive in unit test 2013-02-08 08:19:01 +00:00
Sergey Lyubka 1becd26a8f Updated readme 2013-02-07 20:58:37 +00:00
Sergey Lyubka ffa983552f 3.7 -> 3.8 2013-02-06 09:40:26 +00:00
33 changed files with 25816 additions and 2223 deletions

No files matched your search

+13 -16
View File
@@ -1,19 +1,16 @@
Copyright (c) 2004-2010 Sergey Lyubka Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013 Cesanta Software Limited
All rights reserved
Permission is hereby granted, free of charge, to any person obtaining a copy This code is dual-licensed: you can redistribute it and/or modify
of this software and associated documentation files (the "Software"), to deal it under the terms of the GNU General Public License version 2 as
in the Software without restriction, including without limitation the rights published by the Free Software Foundation. For the terms of this
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell license, see <http://www.gnu.org/licenses/>.
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in You are free to use this code under the terms of the GNU General
all copies or substantial portions of the Software. Public License, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR Alternatively, you can license this code under a commercial
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, license, as set out in <http://cesanta.com/products.html>.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+33 -43
View File
@@ -1,67 +1,57 @@
Project Mission # Project Mission
---------------
Project mission is to provide simple, functional, embeddable web server to Project mission is to provide easy to use, powerful, embeddable web server.
make it easy for application and device developers to implement web interface
for their application and devices, and to offer a simple web development
environment.
Overview # Downloads
--------
To accomplish it's mission, Mongoose keeps balance on functionality and Sources, binaries and bundles are available for download at
[mongoose downloads](http://cesanta.com/downloads.html).
# Overview
Mongoose keeps the balance between functionality and
simplicity by carefully selected list of features: simplicity by carefully selected list of features:
- Liberal, commercial-friendly
[MIT license](http://en.wikipedia.org/wiki/MIT_License)
- Works on Windows, Mac, UNIX, iPhone, Android, and many other platforms - Works on Windows, Mac, UNIX, iPhone, Android, and many other platforms
- Scripting and database support (Lua Server Pages + Sqlite, see
[page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp) ),
which provides ready to go, powerful web development platform in
one single-click executable with **no dependencies**: forget LAMP!
- Support for CGI, SSL, SSI, Digest (MD5) authorization, Websocket, WEbDAV - Support for CGI, SSL, SSI, Digest (MD5) authorization, Websocket, WEbDAV
- Lua server pages (PHP-like functionality using Lua), see - Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service
[page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp)
- 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 - 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 and no dependencies
- Simple and clean embedding API, - Simple and clean embedding API,
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h). [mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h).
The source is in single The source is in single
[mongoose.c](https://github.com/valenok/mongoose/blob/master/mongoose.c) file [mongoose.c](https://github.com/valenok/mongoose/blob/master/mongoose.c) file
to make things easy to make things easy. Embedding examples:
- Embedding examples:
[hello.c](https://github.com/valenok/mongoose/blob/master/examples/hello.c), [hello.c](https://github.com/valenok/mongoose/blob/master/examples/hello.c),
[post.c](https://github.com/valenok/mongoose/blob/master/examples/post.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), [upload.c](https://github.com/valenok/mongoose/blob/master/examples/upload.c),
[websocket.c](https://github.com/valenok/mongoose/blob/master/examples/websocket.c) [websocket.c](https://github.com/valenok/mongoose/blob/master/examples/websocket.c)
- HTTP client functionality for embedded usage, capable of - HTTP client capable of sending arbitrary HTTP/HTTPS requests
sending arbitrary HTTP/HTTPS requests - [User Manual](https://github.com/valenok/mongoose/blob/master/UserManual.md)
- Extensive documentation in form of
[User Manual](https://github.com/valenok/mongoose/blob/master/UserManual.md) Note that Windows and MacOS binaries have following 3rd party software
compiled in:
<a href="http://wolfssl.com">WolfSSL lightweight SSL library</a>,
<a href="http://sqlite.org">SQLite embedded database</a>,
<a href="http://lua.org">Lua embedded scripting engine</a>.
Questions can be asked at Questions can be asked at
[mongoose-users@google.com](http://groups.google.com/group/mongoose-users) [mongoose-users@googlegroups.com](http://groups.google.com/group/mongoose-users)
mailing list. mailing list.
[![&nbsp;](https://cruel-carlota.pagodabox.com/2a613890c1f4b60e5919a9c1dd3caca2 "githalytics.com")](http://githalytics.com/valenok/mongoose)
Keep Sergey happy
-----------------
I am Sergey Lyubka, a software engineer from Galway, Ireland. I started
working on Mongoose in 2004, and since then continuously improving it,
investing thousands of hours of work. My other project I'm contributing to the
community for free is
[Super Light Regular Expression library](http://code.google.com/p/slre).
If you feel grateful for the stuff I've done, you can buy me a book from my # License
[Amazon wishlist](http://amzn.com/w/1OC2ZCPTQYIEP?sort=priority). Many thanks
to all who already did so: T.Barmann, D.Hughes, J.C.Sloan, R.Romeo,
L.E.Spencer, S.Kotay, B.Fjukstad and 6 others.
Appreciated guys, you keep my brains going!
Cash is also appreciated indeed. Press Mongoose is dual-licensed. It is available under the terms of
[<img src="http://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif">](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DGZ2FMP95TAL6) [GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) license
button to donate. Donation progress: 4/1000 &euro; license for free, or under the terms of standard commercial license provided
(thanks to O.M.Vilhunen, C.Radik) by [Cesanta Software](http://cesanta.com).
![Progress](http://chart.googleapis.com/chart?chxr=0,0,1000&chxt=x&chbh=30,0,0&chs=300x35&cht=bhs&chco=90c0f0&chd=s:B) [Super Light Regular Expression library](https://github.com/cesanta/slre) is
another project by Cesanta Software, developed with the same philosophy
of functionality and simplicity.
+462 -130
View File
@@ -1,14 +1,15 @@
# Overview
**NOTE: THIS MANUAL IS WORK IN PROGRESS**
## Overview
Mongoose is small and easy to use web server. It is self-contained, and does Mongoose is small and easy to use web server. It is self-contained, and does
not require any external software to run. not require any external software to run.
On Windows, mongoose iconifies itself to the system tray icon when started. On Windows, mongoose iconifies itself to the system tray icon when started.
Right-click on the icon pops up a menu, where it is possible to stop Right-click on the icon pops up a menu, where it is possible to stop
mongoose, or configure it, or install it as Windows service. mongoose, or configure it, or install it as Windows service. The easiest way
to share a folder on Windows is to copy `mongoose.exe` to a folder,
double-click the exe, and launch a browser at
[http://localhost:8080](http://localhost:8080). Note that 'localhost' should
be changed to a machine's name if a folder is accessed from other computer.
On UNIX and Mac, mongoose is a command line utility. Running `mongoose` in On UNIX and Mac, mongoose is a command line utility. Running `mongoose` in
terminal, optionally followed by configuration parameters terminal, optionally followed by configuration parameters
@@ -21,12 +22,13 @@ When started, mongoose first searches for the configuration file.
If configuration file is specified explicitly in the command line, i.e. If configuration file is specified explicitly in the command line, i.e.
`mongoose path_to_config_file`, then specified configuration file is used. `mongoose path_to_config_file`, then specified configuration file is used.
Otherwise, mongoose would search for file `mongoose.conf` in the same directory Otherwise, mongoose would search for file `mongoose.conf` in the same directory
where binary is located, and use it. where binary is located, and use it. Configuration file can be absent.
Configuration file is a sequence of lines, each line containing Configuration file is a sequence of lines, each line containing
command line argument name and it's value. Empty lines, and lines beginning command line argument name and it's value. Empty lines, and lines beginning
with `#`, are ignored. Here is the example of `mongoose.conf` file: with `#`, are ignored. Here is the example of `mongoose.conf` file:
# mongoose.conf file
document_root c:\www document_root c:\www
listening_ports 8080,8043s listening_ports 8080,8043s
ssl_certificate c:\mongoose\ssl_cert.pem ssl_certificate c:\mongoose\ssl_cert.pem
@@ -38,164 +40,409 @@ For example, if `mongoose.conf` has line
`document_root /var/www`, and mongoose has been started as `document_root /var/www`, and mongoose has been started as
`mongoose -document_root /etc`, then `/etc` directory will be served as `mongoose -document_root /etc`, then `/etc` directory will be served as
document root, because command line options take priority over document root, because command line options take priority over
configuration file. configuration file. Configuration options section below provide a good
overview of Mongoose features.
Note that configuration options on the command line must start with `-`,
but their names are the same as in the config file. All option names are
listed in the next section. Thus, the following two setups are equivalent:
# Using command line arguments
$ mongoose -listening_ports 1234 -document_root /var/www
# Using config file
$ cat mongoose.conf
listening_ports 1234
document_root /var/www
$ mongoose
Mongoose can also be used to modify `.htpasswd` passwords file: Mongoose can also be used to modify `.htpasswd` passwords file:
mongoose -A <htpasswd_file> <realm> <user> <passwd> mongoose -A <htpasswd_file> <realm> <user> <passwd>
## Usage Examples Unlike other web servers, mongoose does not require CGI scripts be located in
a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
recognized by the file name pattern. Mongoose uses shell-like glob
patterns. Pattern match starts at the beginning of the string, so essentially
patterns are prefix patterns. Syntax is as follows:
- How to share a Windows folder: copy mongoose executable to a folder and ** Matches everything
double-click the executable. The folder should be accessible via * Matches everything but slash character, '/'
[http://localhost:8080](http://localhost:8080) in any browser. ? Matches any character
$ Matches the end of the string
| Matches if pattern on the left side or the right side matches.
- How to start mongoose at UNIX startup time in daemon mode, serving All other characters in the pattern match themselves. Examples:
directory `/var/www`: put this line in the system startup script:
`/path/to/mongoose -listening_ports 80 -document_root /var/www &`
- How to serve user home directories using URL rewrite: **.cgi$ Any string that ends with .cgi
`mongoose -url_rewrite_patterns /~joe/=/home/joe/,/~bill=/home/bill/` /foo Any string that begins with /foo
**a$|**b$ Any string that ends with a or b
## Configuration Options # Configuration Options
```
-C cgi_pattern
All files that fully match cgi_pattern are treated as CGI.
Default pattern allows CGI files be anywhere. To restrict CGIs to
certain directory, use e.g. "-C /cgi-bin/**.cgi". Default:
"**.cgi$|**.pl$|**.php$"
-E cgi_environment Below is a list of configuration options Mongoose understands. Every option
Extra environment variables to be passed to the CGI script in is followed by it's default value. If default value is not present, then
addition to standard ones. The list must be comma-separated list it is empty.
of X=Y pairs, like this: "VARIABLE1=VALUE1,VARIABLE2=VALUE2".
Default: ""
-G put_delete_passwords_file ### cgi_pattern `**.cgi$|**.pl$|**.php$`
PUT and DELETE passwords file. This must be specified if PUT or All files that match `cgi_pattern` are treated as CGI files. Default pattern
DELETE methods are used. Default: "" allows CGI files be anywhere. To restrict CGIs to a certain directory,
use `/path/to/cgi-bin/**.cgi` as pattern. Note that full file path is
matched against the pattern, not the URI.
-I cgi_interpreter ### cgi_environment
Use cgi_interpreter as a CGI interpreter for all CGI scripts Extra environment variables to be passed to the CGI script in
regardless script extension. Mongoose decides which interpreter addition to standard ones. The list must be comma-separated list
to use by looking at the first line of a CGI script. Default: of name=value pairs, like this: `VARIABLE1=VALUE1,VARIABLE2=VALUE2`.
"".
-P protect_uri ### put\_delete\_auth\_file
Comma separated list of URI=PATH pairs, specifying that given Passwords file for PUT and DELETE requests. Without it, PUT and DELETE requests
URIs must be protected with respected password files. Default: "" will fail.
-R authentication_domain ### cgi_interpreter
Authorization realm. Default: "mydomain.com" Path to an executable to use as CGI interpreter for __all__ CGI scripts
regardless script extension. If this option is not set (which is a default),
Mongoose looks at first line of a CGI script,
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\)), for an interpreter.
-S ssi_pattern For example, if both PHP and perl CGIs are used, then
All files that fully match ssi_pattern are treated as SSI. `#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
Unknown SSI directives are silently ignored. Currently, two SSI respective CGI scripts. Note that paths should be either full file paths,
directives are supported, "include" and "exec". Default: or file paths relative to the current working directory of mongoose server.
"**.shtml$|**.shtm$" If mongoose is started by mouse double-click on Windows, current working
directory is a directory where mongoose executable is located.
-T throttle If all CGIs use the same interpreter, for example they are all PHP, then
Limit download speed for clients. throttle is a comma-separated `cgi_interpreter` can be set to the path to `php-cgi.exe` executable and
list of key=value pairs, where key could be a '*' character shebang line in the CGI scripts can be omitted.
(limit for all connections), a subnet in form x.x.x.x/mask (limit Note that PHP scripts must use `php-cgi.exe` executable, not `php.exe`.
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: ""
-a access_log_file ### protect_uri
Access log file. Default: "", no logging is done. Comma separated list of URI=PATH pairs, specifying that given
URIs must be protected with respected password files. Paths must be full
file paths.
-d enable_directory_listing ### authentication_domain `mydomain.com`
Enable/disable directory listing. Default: "yes" Authorization realm used in `.htpasswd` authorization.
-e error_log_file ### ssi_pattern `**.shtml$|**.shtm$`
Error log file. Default: "", no errors are logged. All files that match `ssi_pattern` are treated as SSI.
-g global_passwords_file Server Side Includes (SSI) is a simple interpreted server-side scripting
Location of a global passwords file. If set, per-directory language which is most commonly used to include the contents of a file into
.htpasswd files are ignored, and all requests must be authorised a web page. It can be useful when it is desirable to include a common piece
against that file. Default: "" of code throughout a website, for example, headers and footers.
-i index_files In order for a webpage to recognize an SSI-enabled HTML file, the filename
Comma-separated list of files to be treated as directory index should end with a special extension, by default the extension should be
files. Default: "index.html,index.htm,index.cgi" either `.shtml` or `.shtm`.
-l access_control_list Unknown SSI directives are silently ignored by mongoose. Currently, two SSI
Specify access control list (ACL). ACL is a comma separated list directives are supported, `<!--#include ...>` and
of IP subnets, each subnet is prepended by '-' or '+' sign. Plus `<!--#exec "command">`. Note that `<!--#include ...>` directive supports
means allow, minus means deny. If subnet mask is omitted, like three path specifications:
"-1.2.3.4", then it means single IP address. Mask may vary from 0
to 32 inclusive. On each request, full list is traversed, and
last match wins. Default setting is to allow all. For example, to
allow only 192.168/16 subnet to connect, run "mongoose
-0.0.0.0/0,+192.168/16". Default: ""
-m extra_mime_types <!--#include virtual="path"> Path is relative to web server root
Extra mime types to recognize, in form "extension1=type1,exten- <!--#include abspath="path"> Path is absolute or relative to
sion2=type2,...". Extension must include dot. Example: "mongoose web server working dir
-m .cpp=plain/text,.java=plain/text". Default: "" <!--#include file="path">, Path is relative to current document
<!--#include "path">
-p listening_ports The `include` directive may be used to include the contents of a file or the
Comma-separated list of ports to listen on. If the port is SSL, a result of running a CGI script. The `exec` directive is used to execute a
letter 's' must be appeneded, for example, "-p 80,443s" will open command on a server, and show command's output. Example:
port 80 and port 443, and connections on port 443 will be SSL-ed.
It is possible to specify an IP address to bind to. In this case,
an IP address and a colon must be prepended to the port number.
For example, to bind to a loopback interface on port 80 and to
all interfaces on HTTPS port 443, use "mongoose -p
127.0.0.1:80,443s". Default: "8080"
-r document_root <!--#exec "ls -l" -->
Location of the WWW root directory. Default: "."
-s ssl_certificate For more information on Server Side Includes, take a look at the Wikipedia:
Location of SSL certificate file. Default: "" [Server Side Includes](http://en.wikipedia.org/wiki/Server_Side_Includes)
-t num_threads ### throttle
Number of worker threads to start. Default: "10" Limit download speed for clients. `throttle` is a comma-separated
list of key=value pairs, where key could be:
-u run_as_user * limit speed for all connections
Switch to given user's credentials after startup. Default: "" x.x.x.x/mask limit speed for specified subnet
uri_prefix_pattern limit speed for given URIs
-w url_rewrite_patterns The value is a floating-point number of bytes per second, optionally
Comma-separated list of URL rewrites in the form of "pattern=sub- followed by a `k` or `m` character, meaning kilobytes and
stitution,..." If the "pattern" matches some prefix of the megabytes respectively. A limit of 0 means unlimited rate. The
requested URL, then matched prefix gets substituted with "substi- last matching rule wins. Examples:
tution". For example, "-w /con-
fig=/etc,**.doc|**.rtf=/path/to/cgi-bin/handle_doc.cgi" will
serve all URLs that start with "/config" from the "/etc" direc-
tory, and call handle_doc.cgi script for .doc and .rtf file
requests. If some pattern matches, no further matching/substitu-
tion is performed (first matching pattern wins). Use full paths
in substitutions. Default: ""
-x hide_files_patterns *=1k,10.0.0.0/8=0 limit all accesses to 1 kilobyte per second,
A prefix pattern for the files to hide. Files that match the pat- but give connections from 10.0.0.0/8 subnet
tern will not show up in directory listing and return 404 Not unlimited speed
Found if requested. Default: ""
``` /downloads/=5k limit accesses to all URIs in `/downloads/` to
5 kilobytes per secods. All other accesses are unlimited
## Common Problems ### access\_log\_file
--------------- Path to a file for access logs. Either full path, or relative to current
working directory. If absent (default), then accesses are not logged.
### error\_log\_file
Path to a file for error logs. Either full path, or relative to current
working directory. If absent (default), then errors are not logged.
### enable\_directory\_listing `yes`
Enable directory listing, either `yes` or `no`.
### enable\_keep\_alive `no`
Enable connection keep alive, either `yes` or `no`.
Experimental feature. Allows clients to reuse TCP connection for
subsequent HTTP requests, which improves performance.
For this to work when using request handlers it's important to add the correct
Content-Length HTTP header for each request. If this is forgotten the client
will time out.
### global\_auth\_file
Path to a global passwords file, either full path or relative to the current
working directory. If set, per-directory `.htpasswd` files are ignored,
and all requests are authorised against that file.
The file has to include the realm set through `authentication_domain` and the password in digest format:
user:realm:digest
test:test.com:ce0220efc2dd2fad6185e1f1af5a4327
(e.g. use [this generator](http://www.askapache.com/online-tools/htpasswd-generator))
### index_files `index.html,index.htm,index.cgi,index.shtml,index.php`
Comma-separated list of files to be treated as directory index
files.
### access\_control\_list
An Access Control List (ACL) allows restrictions to be put on the list of IP
addresses which have access to the web server. In the case of the Mongoose
web server, the ACL is a comma separated list of IP subnets, where each
subnet is prepended by either a `-` or a `+` sign. A plus sign means allow,
where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
this means to deny only that single IP address.
Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
all accesses. On each request the full list is traversed, and
the last match wins. Examples:
-0.0.0.0/0,+192.168/16 deny all acccesses, only allow 192.168/16 subnet
To learn more about subnet masks, see the
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
### extra\_mime\_types
Extra mime types to recognize, in form `extension1=type1,exten-
sion2=type2,...`. Extension must include dot. Example:
`.cpp=plain/text,.java=plain/text`
### listening_ports `8080`
Comma-separated list of ports to listen on. If the port is SSL, a
letter `s` must be appeneded, for example, `80,443s` will open
port 80 and port 443, and connections on port 443 will be SSL-ed.
For non-SSL ports, it is allowed to append letter `r`, meaning 'redirect'.
Redirect ports will redirect all their traffic to the first configured
SSL port. For example, if `listening_ports` is `80r,443s`, then all
HTTP traffic coming at port 80 will be redirected to HTTPS port 443.
It is possible to specify an IP address to bind to. In this case,
an IP address and a colon must be prepended to the port number.
For example, to bind to a loopback interface on port 80 and to
all interfaces on HTTPS port 443, use `127.0.0.1:80,443s`.
### document_root `.`
A directory to serve. By default, currect directory is served. Current
directory is commonly referenced as dot (`.`).
### ssl_certificate
Path to SSL certificate file. This option is only required when at least one
of the `listening_ports` is SSL. The file must be in PEM format,
and it must have both private key and certificate, see for example
[ssl_cert.pem](https://github.com/valenok/mongoose/blob/master/build/ssl_cert.pem)
### num_threads `50`
Number of worker threads. Mongoose handles each incoming connection in a
separate thread. Therefore, the value of this option is effectively a number
of concurrent HTTP connections Mongoose can handle.
### run\_as\_user
Switch to given user credentials after startup. Usually, this option is
required when mongoose needs to bind on privileged port on UNIX. To do
that, mongoose needs to be started as root. But running as root is a bad idea,
therefore this option can be used to drop privileges. Example:
mongoose -listening_ports 80 -run_as_user nobody
### request\_timeout\_ms `30000`
Timeout for network read and network write operations, in milliseconds.
If client intends to keep long-running connection, either increase this value
or use keep-alive messages.
### url\_rewrite\_patterns
Comma-separated list of URL rewrites in the form of
`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
it constructs the file name to show by combining `document_root` and the URI.
However, if the rewrite option is used and `uri_pattern` matches the
requested URI, then `document_root` is ignored. Insted,
`file_or_directory_path` is used, which should be a full path name or
a path relative to the web server's current working directory. Note that
`uri_pattern`, as all mongoose patterns, is a prefix pattern.
This makes it possible to serve many directories outside from `document_root`,
redirect all requests to scripts, and do other tricky things. For example,
to redirect all accesses to `.doc` files to a special script, do:
mongoose -url_rewrite_patterns **.doc$=/path/to/cgi-bin/handle_doc.cgi
Or, to imitate user home directories support, do:
mongoose -url_rewrite_patterns /~joe/=/home/joe/,/~bill=/home/bill/
### hide\_files\_patterns
A pattern for the files to hide. Files that match the pattern will not
show up in directory listing and return `404 Not Found` if requested. Pattern
must be for a file name only, not including directory name. Example:
mongoose -hide_files_patterns secret.txt|even_more_secret.txt
# Lua Server Pages
Pre-built Windows and Mac mongoose binaries have built-in Lua Server Pages
support. That means it is possible to write PHP-like scripts with mongoose,
using Lua programming language instead of PHP. Lua is known
for it's speed and small size. Mongoose uses Lua version 5.2.1, the
documentation for it can be found at
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
To create a Lua Page, make sure a file has `.lp` extension. For example,
let's say it is going to be `my_page.lp`. The contents of the file, just like
with PHP, is HTML with embedded Lua code. Lua code must be enclosed in
`<? ?>` blocks, and can appear anywhere on the page. For example, to
print current weekday name, one can write:
<p>
<span>Today is:</span>
<? mg.write(os.date("%A")) ?>
</p>
Note that this example uses function `mg.write()`, which prints data to the
web page. Using function `mg.write()` is the way to generate web content from
inside Lua code. In addition to `mg.write()`, all standard library functions
are accessible from the Lua code (please check reference manual for details),
and also information about the request is available in `mg.request_info` object,
like request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h)
to see what kind of information is present in `mg.request_info` object. Also,
[page.lp](https://github.com/valenok/mongoose/blob/master/test/page.lp) and
[prime_numbers.lp](https://github.com/valenok/mongoose/blob/master/examples/lua/prime_numbers.lp)
contains some example code that uses `request_info` and other functions(form submitting for example).
Mongoose exports the following to the Lua server page:
mg.read() -- reads a chunk from POST data, returns it as a string
mg.write(str) -- writes string to the client
mg.include(path) -- sources another Lua file
mg.redirect(uri) -- internal redirect to a given URI
mg.onerror(msg) -- error handler, can be overridden
mg.version -- a string that holds Mongoose version
mg.request_info -- a table with request information
-- Connect to the remote TCP server. This function is an implementation
-- of simple socket interface. It returns a socket object with three
-- methods: send, recv, close, which are synchronous (blocking).
-- connect() throws an exception on connection error.
connect(host, port, use_ssl)
-- Example of using connect() interface:
local host = 'code.google.com' -- IP address or domain name
local ok, sock = pcall(connect, host, 80, 1)
if ok then
sock:send('GET /p/mongoose/ HTTP/1.0\r\n' ..
'Host: ' .. host .. '\r\n\r\n')
local reply = sock:recv()
sock:close()
-- reply now contains the web page https://code.google.com/p/mongoose
end
**IMPORTANT: Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP reply line and headers**, like this:
<? print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
<html><body>
... the rest of the web page ...
To serve Lua Page, mongoose creates Lua context. That context is used for
all Lua blocks within the page. That means, all Lua blocks on the same page
share the same context. If one block defines a variable, for example, that
variable is visible in the block that follows.
# Common Problems
- PHP doesn't work - getting empty page, or 'File not found' error. The - PHP doesn't work - getting empty page, or 'File not found' error. The
reason for that is wrong paths to the interpreter. Remember that with PHP, reason for that is wrong paths to the interpreter. Remember that with PHP,
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
full path to the PHP interpreter, e.g. full path to the PHP interpreter, e.g.:
`mongoose -cgi_interpreter /full/path/to/php-cgi` `mongoose -cgi_interpreter /full/path/to/php-cgi`
## Embedding - Mongoose fails to start. If Mongoose exits immediately when run, this
Embedding Mongoose is easy. Somewhere in the application code, `mg_start()` usually indicates a syntax error in the configuration file
function must be called. That starts the web server in a separate thread. (named `mongoose.conf` by default) or the command-line arguments.
When it is not needed anymore, `mg_stop()` must be called. Application code Syntax checking is omitted from Mongoose to keep its size low. However,
can pass configuration options to `mg_start()`, and also specify callback the Manual should be of help. Note: the syntax changes from time to time,
functions that Mongoose should call at certain events. so updating the config file might be necessary after executable update.
[hello.c](http://a.c) provides a minimalistic example.
- Embedding with OpenSSL on Windows might fail because of calling convention.
To force Mongoose to use `__stdcall` convention, add `/Gz` compilation
flag in Visual Studio compiler.
# Embedding
Embedding Mongoose is easy. Copy
[mongoose.c](https://github.com/valenok/mongoose/blob/master/mongoose.c) and
[mongoose.h](https://github.com/valenok/mongoose/blob/master/mongoose.h)
to your application's source tree and include them in the build. For
example, your application's code lives in C file `my_app.c`, then on UNIX
this command embeds Mongoose:
$ ls
my_app.c mongoose.c mongoose.h
$ gcc my_app.c mongoose.c -o my_app -ldl -pthread
Somewhere in the application code, call `mg_start()` to start the server.
Pass configuration options and event handlers to `mg_start()`.
Mongoose then calls handlers when certain events happen.
For example, when new request arrives, Mongoose calls `begin_request`
handler function to let user handle the request. In the handler, user code
can get all information about the request -- parsed headers, etcetera.
Mongoose API is logically divided in three categories: server setup/shutdown
functions, functions to be used by user-written event handlers, and
convenience utility functions.
### Starting and stopping embedded web server
To start the embedded web server, call `mg_start()`. To stop it, call
`mg_stop()`.
// This structure needs to be passed to mg_start(), to let mongoose know
// which callbacks to invoke. For detailed description, see
// https://github.com/valenok/mongoose/blob/master/UserManual.md
struct mg_callbacks {
int (*begin_request)(struct mg_connection *);
void (*end_request)(const struct mg_connection *, int reply_status_code);
int (*log_message)(const struct mg_connection *, const char *message);
int (*init_ssl)(void *ssl_context);
int (*websocket_connect)(const struct mg_connection *);
void (*websocket_ready)(struct mg_connection *);
int (*websocket_data)(struct mg_connection *);
const char * (*open_file)(const struct mg_connection *,
const char *path, size_t *data_len);
void (*init_lua)(struct mg_connection *, void *lua_context);
void (*upload)(struct mg_connection *, const char *file_name);
int (*http_error)(struct mg_connection *, int status);
};
[hello.c](https://github.com/valenok/mongoose/blob/master/examples/hello.c)
provides a minimalistic example.
Common pattern is to implement `begin_request` callback, and serve static files Common pattern is to implement `begin_request` callback, and serve static files
from memory, and/or construct dynamic replies on the fly. Here is from memory, and/or construct dynamic replies on the fly. Here is
@@ -204,8 +451,93 @@ that shows how to easily any data can be embedded
directly into the executable. If such data needs to be encrypted, then directly into the executable. If such data needs to be encrypted, then
encrypted database or encryption dongles would be a better choice. encrypted database or encryption dongles would be a better choice.
# Build on Android
## Other Resources This is a small guide to help you run mongoose on Android. Currently it is
tested on the HTC Wildfire. If you have managed to run it on other devices
as well, please comment or drop an email in the mailing list.
Note : You dont need root access to run mongoose on Android.
- Download the source from the Downloads page.
- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html)
- Run `/path-to-ndk/ndk-build -C /path-to-mongoose/build`
That should generate mongoose/lib/armeabi/mongoose
- Using the adb tool (you need to have Android SDK installed for that),
push the generated mongoose binary to `/data/local` folder on device.
- From adb shell, navigate to `/data/local` and execute `./mongoose`.
- To test if the server is running fine, visit your web-browser and
navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
![screenshot](https://a248.e.akamai.net/camo.github.com/b88428bf009a2b6141000937ab684e04cc8586af/687474703a2f2f692e696d6775722e636f6d2f62676f6b702e706e67)
Notes:
- `jni` stands for Java Native Interface. Read up on Android NDK if you want
to know how to interact with the native C functions of mongoose in Android
Java applications.
- TODO: A Java application that interacts with the native binary or a
shared library.
# Mongoose internals
Mongoose is multithreaded web server. `mg_start()` function allocates
web server context (`struct mg_context`), which holds all information
about web server instance:
- configuration options. Note that mongoose makes internal copies of
passed options.
- SSL context, if any
- user-defined callbacks
- opened listening sockets
- a queue for accepted sockets
- mutexes and condition variables for inter-thread synchronization
When `mg_start()` returns, all initialization is quaranteed to be complete
(e.g. listening ports are opened, SSL is initialized, etc). `mg_start()` starts
two threads: a master thread, that accepts new connections, and several
worker threads, that process accepted connections. The number of worker threads
is configurable via `num_threads` configuration option. That number puts a
limit on number of simultaneous requests that can be handled by mongoose.
When master thread accepts new connection, a new accepted socket (described by
`struct socket`) it placed into the accepted sockets queue,
which has size of 20 (see [code](https://github.com/valenok/mongoose/blob/3892e0199e6ca9613b160535d9d107ede09daa43/mongoose.c#L486)). Any idle worker thread
can grab accepted sockets from that queue. If all worker threads are busy,
master thread can accept and queue up to 20 more TCP connections,
filling up the queue.
In the attempt to queue next accepted connection, master thread blocks
until there is space in a queue. When master thread is blocked on a
full queue, TCP layer in OS can also queue incoming connection.
The number is limited by the `listen()` call parameter on listening socket,
which is `SOMAXCONN` in case of Mongoose, and depends on a platform.
Worker threads are running in an infinite loop, which in simplified form
looks something like this:
static void *worker_thread() {
while (consume_socket()) {
process_new_connection();
}
}
Function `consume_socket()` gets new accepted socket from the mongoose socket
queue, atomically removing it from the queue. If the queue is empty,
`consume_socket()` blocks and waits until new sockets are placed in a queue
by the master thread. `process_new_connection()` actually processes the
connection, i.e. reads the request, parses it, and performs appropriate action
depending on a parsed request.
Master thread uses `poll()` and `accept()` to accept new connections on
listening sockets. `poll()` is used to avoid `FD_SETSIZE` limitation of
`select()`. Since there are only a few listening sockets, there is no reason
to use hi-performance alternatives like `epoll()` or `kqueue()`. Worker
threads use blocking IO on accepted sockets for reading and writing data.
All accepted sockets have `SO_RCVTIMEO` and `SO_SNDTIMEO` socket options set
(controlled by `request_timeout_ms` mongoose option, 30 seconds default) which
specify read/write timeout on client connection.
# Other Resources
- Presentation made by Arnout Vandecappelle at FOSDEM 2011 on 2011-02-06 - Presentation made by Arnout Vandecappelle at FOSDEM 2011 on 2011-02-06
in Brussels, Belgium, called in Brussels, Belgium, called
"Creating secure web based user interfaces for Embedded Devices" "Creating secure web based user interfaces for Embedded Devices"
+110 -53
View File
@@ -1,6 +1,9 @@
# This Makefile is part of Mongoose web server project, # This Makefile is part of Mongoose web server project,
# https://github.com/valenok/mongoose # https://github.com/valenok/mongoose
# #
# This Makefile is GNU make compatible. You can get GNU Make from
# http://gnuwin32.sourceforge.net/packages/make.htm
#
# Example custom build: # Example custom build:
# COPT="-g -O0 -DNO_SSL_DL -DUSE_LUA -llua -lcrypto -lssl" make linux # COPT="-g -O0 -DNO_SSL_DL -DUSE_LUA -llua -lcrypto -lssl" make linux
# #
@@ -17,11 +20,12 @@
# -DUSE_LUA - embed Lua in Mongoose (+100kb) # -DUSE_LUA - embed Lua in Mongoose (+100kb)
PROG = mongoose PROG = mongoose
CFLAGS = -std=c99 -O2 -W -Wall -pedantic -pthread $(COPT) CFLAGS = -std=c99 -O2 -W -Wall -pedantic -pthread -pipe -I.. $(COPT)
# To build with Lua, download and unzip Lua 5.2.1 source code into the # To build with Lua, download and unzip Lua 5.2.1 source code into the
# mongoose directory, and then add $(LUA_SOURCES) to CFLAGS # mongoose directory, and then add $(LUA_SOURCES) to CFLAGS
LUA = lua-5.2.1/src LUA = ../lua-5.2.1/src
LUA_FLAGS = -DLUA_COMPAT_ALL
LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \ LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \
$(LUA)/ldebug.c $(LUA)/ldo.c $(LUA)/ldump.c \ $(LUA)/ldebug.c $(LUA)/ldo.c $(LUA)/ldump.c \
$(LUA)/lfunc.c $(LUA)/lgc.c $(LUA)/llex.c \ $(LUA)/lfunc.c $(LUA)/lgc.c $(LUA)/llex.c \
@@ -33,21 +37,32 @@ LUA_SOURCES = $(LUA)/lapi.c $(LUA)/lcode.c $(LUA)/lctype.c \
$(LUA)/ldblib.c $(LUA)/liolib.c $(LUA)/lmathlib.c \ $(LUA)/ldblib.c $(LUA)/liolib.c $(LUA)/lmathlib.c \
$(LUA)/loslib.c $(LUA)/lstrlib.c $(LUA)/ltablib.c \ $(LUA)/loslib.c $(LUA)/lstrlib.c $(LUA)/ltablib.c \
$(LUA)/loadlib.c $(LUA)/linit.c $(LUA)/loadlib.c $(LUA)/linit.c
LUA_OBJECTS = $(LUA_SOURCES:%.c=%.o) LUA_HEADERS = $(LUA)/llimits.h $(LUA)/lobject.h $(LUA)/lapi.h $(LUA)/lzio.h \
$(LUA)/ldo.h $(LUA)/ltm.h $(LUA)/lstate.h $(LUA)/lgc.h \
$(LUA)/lvm.h $(LUA)/ltable.h $(LUA)/lstring.h $(LUA)/lfunc.h \
$(LUA)/lundump.h $(LUA)/ldebug.h $(LUA)/lopcodes.h $(LUA)/llex.h \
$(LUA)/lparser.h $(LUA)/lcode.h $(LUA)/lmem.h $(LUA)/lctype.h
LUA_WINOBJS = $(LUA_SOURCES:%.c=%.obj)
# Using Visual Studio 6.0. To build Mongoose: ifneq ($(OS), Windows_NT)
# Set MSVC variable below to where VS 6.0 is installed on your system LUA_FLAGS += -DLUA_USE_DLOPEN
# Run "PATH_TO_VC6\bin\nmake windows" endif
MSVC = ../vc6
#DBG = /Zi /Od lua_5.2.1.c: lua_5.2.1.h
DBG = /DNDEBUG /O1 (echo '#define LUA_CORE' ; \
CL = $(MSVC)/bin/cl /MD /TC /nologo $(DBG) /Gz /W3 \ echo '#define LUA_LIB' ; \
/I$(MSVC)/include /I$(LUA) /I. /I$(YASSL) /I$(YASSL)/cyassl /GA echo '#define lobject_c' ; \
MSLIB = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \ echo '#define lua_c' ; \
user32.lib shell32.lib comdlg32.lib ws2_32.lib advapi32.lib echo '#define ltable_c' ; \
echo '#include "lua_5.2.1.h"' ; \
cat $(LUA_HEADERS) $(LUA_SOURCES) | sed '/^#include "/d') > $@
lua_5.2.1.h:
cat $(LUA)/luaconf.h $(LUA)/lua.h $(LUA)/lauxlib.h $(LUA)/lualib.h | \
sed '/^#include "/d' > $@
# Stock windows binary builds with Lua and YASSL library. # Stock windows binary builds with Lua and YASSL library.
YASSL = ../cyassl-2.4.6 YASSL = ../../cyassl-2.4.6
YASSL_FLAGS = -I $(YASSL) -I $(YASSL)/cyassl \ YASSL_FLAGS = -I $(YASSL) -I $(YASSL)/cyassl \
-D _LIB -D OPENSSL_EXTRA -D HAVE_ERRNO_H \ -D _LIB -D OPENSSL_EXTRA -D HAVE_ERRNO_H \
-D HAVE_GETHOSTBYNAME -D HAVE_INET_NTOA -D HAVE_LIMITS_H \ -D HAVE_GETHOSTBYNAME -D HAVE_INET_NTOA -D HAVE_LIMITS_H \
@@ -71,67 +86,108 @@ YASSL_SOURCES = \
$(YASSL)/ctaocrypt/src/ecc.c $(YASSL)/src/ocsp.c $(YASSL)/src/crl.c \ $(YASSL)/ctaocrypt/src/ecc.c $(YASSL)/src/ocsp.c $(YASSL)/src/crl.c \
$(YASSL)/ctaocrypt/src/hc128.c $(YASSL)/ctaocrypt/src/memory.c $(YASSL)/ctaocrypt/src/hc128.c $(YASSL)/ctaocrypt/src/memory.c
ALL_SOURCES = ../mongoose.c main.c sqlite3.c lsqlite3.c lua_5.2.1.c \
$(YASSL_SOURCES)
ALL_OBJECTS = $(ALL_SOURCES:%.c=%.o)
ALL_WINOBJS = $(ALL_SOURCES:%.c=%.obj)
SQLITE_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS
MONGOOSE_FLAGS = -DNO_SSL_DL -DUSE_LUA -DUSE_LUA_SQLITE3 -I.. $(COPT)
FLAGS = $(MONGOOSE_FLAGS) $(SQLITE_FLAGS) $(YASSL_FLAGS) $(LUA_FLAGS)
# Using Visual Studio 6.0. To build Mongoose:
# Set MSVC variable below to where VS 6.0 is installed on your system
# Run "PATH_TO_VC6\bin\nmake windows"
MSVC = ../../vc6
#DBG = /Zi /Od
DBG = /DNDEBUG /O1
CL = $(MSVC)/bin/cl /MD /TC /nologo $(DBG) /W3 /GA /I$(MSVC)/include
LINK_FLAGS = /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \
user32.lib shell32.lib comdlg32.lib ws2_32.lib advapi32.lib
LINK = $(MSVC)/bin/link $(LINK_FLAGS)
all: all:
@echo "make (linux|bsd|solaris|mac|windows|mingw|cygwin)" @echo "make (linux|bsd|solaris|mac|windows|mingw|cygwin)"
%.obj: %.c
$(CL) /c $(FLAGS) /Fo$@ $<
%.o: %.c
$(CC) -o $@ $< -c $(FLAGS) $(CFLAGS)
# Lua library for Windows
lua.lib: $(LUA_WINOBJS)
$(MSVC)/bin/lib /out:$@ $(LUA_WINOBJS)
# To build with lua, make sure you have Lua unpacked into lua-5.2.1 directory
linux_lua: $(ALL_OBJECTS)
$(CC) $(ALL_OBJECTS) -o $(PROG) -ldl
mongoose.o: mod_lua.c
# 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 main.c -o $(PROG) -ldl $(CFLAGS) $(CC) ../mongoose.c main.c -o $(PROG) -ldl $(CFLAGS)
mac: bsd mac: bsd
bsd: bsd:
$(CC) mongoose.c main.c -o $(PROG) $(CFLAGS) $(CC) ../mongoose.c main.c -o $(PROG) $(CFLAGS)
bsd_yassl: bsd_lua: $(ALL_OBJECTS)
$(CC) mongoose.c main.c build/lsqlite3.c build/sqlite3.c -o $(PROG) \ $(CC) $(ALL_OBJECTS) -o $@
$(CFLAGS) -I$(LUA) -Ibuild \
$(YASSL_SOURCES) $(YASSL_FLAGS) -DNO_SSL_DL \
$(LUA_SOURCES) -DUSE_LUA -DUSE_LUA_SQLITE3 -DLUA_COMPAT_ALL
solaris: solaris:
$(CC) mongoose.c main.c -lnsl -lsocket -o $(PROG) $(CFLAGS) $(CC) ../mongoose.c main.c -lnsl -lsocket -o $(PROG) $(CFLAGS)
lib$(PROG).a: $(ALL_OBJECTS)
ar cr $@ $(ALL_OBJECTS)
$(PROG).lib: $(ALL_WINOBJS)
$(MSVC)/bin/lib /out:$@ $(ALL_WINOBJS)
# For codesign to work in non-interactive mode, unlock login keychain: # For codesign to work in non-interactive mode, unlock login keychain:
# security unlock ~/Library/Keychains/login.keychain # security unlock ~/Library/Keychains/login.keychain
# See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html # See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html
cocoa: Mongoose: ../mongoose.c main.c
$(CC) mongoose.c main.c build/lsqlite3.c build/sqlite3.c \ $(CC) $(ALL_SOURCES) \
-DUSE_COCOA $(CFLAGS) -I$(LUA) -Ibuild \ -DUSE_COCOA $(CFLAGS) $(FLAGS) -mmacosx-version-min=10.4 \
$(YASSL_SOURCES) $(YASSL_FLAGS) -DNO_SSL_DL \
$(LUA_SOURCES) -DUSE_LUA -DUSE_LUA_SQLITE3 -DLUA_COMPAT_ALL \
-framework Cocoa -ObjC -arch i386 -arch x86_64 -o Mongoose -framework Cocoa -ObjC -arch i386 -arch x86_64 -o Mongoose
V=`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`; DIR=dmg/Mongoose.app && rm -rf $$DIR && mkdir -p $$DIR/Contents/{MacOS,Resources} && install -m 644 build/mongoose_*.png $$DIR/Contents/Resources/ && install -m 644 build/Info.plist $$DIR/Contents/ && install -m 755 Mongoose $$DIR/Contents/MacOS/ && ln -fs /Applications dmg/ ; hdiutil create Mongoose_$$V.dmg -volname "Mongoose $$V" -srcfolder dmg -ov #; rm -rf dmg
u: cocoa: Mongoose
$(CC) test/unit_test.c -o unit_test -I. -I$(LUA) $(LUA_SOURCES) \ V=`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' ../mongoose.c`; DIR=dmg/Mongoose.app && rm -rf $$DIR && mkdir -p $$DIR/Contents/{MacOS,Resources} && install -m 644 mongoose_*.png $$DIR/Contents/Resources/ && install -m 644 Info.plist $$DIR/Contents/ && install -m 755 Mongoose $$DIR/Contents/MacOS/ && ln -fs /Applications dmg/ ; hdiutil create Mongoose_$$V.dmg -volname "Mongoose $$V" -srcfolder dmg -ov #; rm -rf dmg
$(CFLAGS) -g -O0
un:
$(CC) ../test/unit_test.c -o unit_test lua_5.2.1.c $(CFLAGS) -g -O0
./unit_test ./unit_test
w: wi:
$(CL) test/unit_test.c $(LUA_SOURCES) \ $(CL) test/unit_test.c $(LUA_SOURCES) $(LUA_FLAGS) \
$(YASSL_SOURCES) $(YASSL_FLAGS) /DNO_SSL_DL \ $(YASSL_SOURCES) $(YASSL_FLAGS) /I. /DNO_SSL_DL \
$(MSLIB) /out:unit_test.exe /link /libpath:$(MSVC)/lib advapi32.lib /out:unit_test.exe
./unit_test.exe ./unit_test.exe
windows: windows: $(ALL_WINOBJS)
$(MSVC)/bin/rc build\res.rc $(MSVC)/bin/rc res.rc
$(CL) main.c mongoose.c build/lsqlite3.c build/sqlite3.c \ $(LINK) /nologo $(ALL_WINOBJS) res.res /out:$(PROG).exe
$(YASSL_SOURCES) $(YASSL_FLAGS) /DNO_SSL_DL \
$(LUA_SOURCES) /DUSE_LUA /DUSE_LUA_SQLITE3 /DLUA_COMPAT_ALL \ windows_tiny: $(ALL_SOURCES)
$(MSLIB) build\res.res /out:$(PROG).exe /subsystem:windows $(MSVC)/bin/rc res.rc
$(CL) /nologo ../mongoose.c main.c /I.. \
/link $(LINK_FLAGS) res.res /out:$(PROG)-tiny.exe
# Build for Windows under MinGW # Build for Windows under MinGW
#MINGWDBG= -DDEBUG -O0 -ggdb #MINGWDBG= -DDEBUG -O0 -ggdb
MINGWDBG= -DNDEBUG -Os MINGWDBG= -DNDEBUG -Os
MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT) MINGWOPT= -W -Wall -mthreads -Wl,--subsystem,console $(MINGWDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
mingw: mingw:
windres build\res.rc build\res.o windres res.rc res.o
$(CC) $(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
$(CC) $(MINGWOPT) mongoose.c main.c build\res.o \ $(CC) $(MINGWOPT) ../mongoose.c main.c res.o \
-lws2_32 -ladvapi32 -lcomdlg32 -o $(PROG).exe -lws2_32 -ladvapi32 -lcomdlg32 -o $(PROG).exe
# Build for Windows under Cygwin # Build for Windows under Cygwin
@@ -139,23 +195,24 @@ mingw:
CYGWINDBG= -DNDEBUG -Os CYGWINDBG= -DNDEBUG -Os
CYGWINOPT= -W -Wall -mthreads -Wl,--subsystem,console $(CYGWINDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT) CYGWINOPT= -W -Wall -mthreads -Wl,--subsystem,console $(CYGWINDBG) -DHAVE_STDINT $(GCC_WARNINGS) $(COPT)
cygwin: cygwin:
windres ./build/res.rc ./build/res.o windres res.rc res.o
$(CC) $(CYGWINOPT) mongoose.c -lws2_32 \ $(CC) $(CYGWINOPT) ../mongoose.c -lws2_32 \
-shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll -shared -Wl,--out-implib=$(PROG).lib -o $(PROG).dll
$(CC) $(CYGWINOPT) -Ibuild mongoose.c main.c ./build/res.o \ $(CC) $(CYGWINOPT) -I.. ../mongoose.c main.c res.o \
-lws2_32 -ladvapi32 -o $(PROG).exe -lws2_32 -ladvapi32 -o $(PROG).exe
tests: tests:
perl test/test.pl $(TEST) perl ../test/test.pl $(TEST)
tarball: clean tarball: clean
F=mongoose-`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`.tgz ; cd .. && tar -czf x mongoose/{LICENSE,Makefile,examples,test,build,*.[ch],*.md} && 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,*.[ch]} && mv x mongoose/build/$$F
release: tarball cocoa release: tarball cocoa
wine make windows wine make windows windows_tiny
V=`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' mongoose.c`; upx mongoose.exe; cp mongoose.exe mongoose-$$V.exe; cp mongoose.exe mongoose_php_bundle/; zip -r mongoose_php_bundle_$$V.zip mongoose_php_bundle/ V=`perl -lne '/define\s+MONGOOSE_VERSION\s+"(\S+)"/ and print $$1' ../mongoose.c`; upx mongoose.exe; upx mongoose-tiny.exe ; cp mongoose.exe mongoose-$$V.exe; cp mongoose-tiny.exe mongoose-tiny-$$V.exe; cp mongoose.exe mongoose_php_bundle/; zip -r mongoose-php-$$V.zip mongoose_php_bundle/
clean: clean:
cd examples && $(MAKE) clean cd ../examples && $(MAKE) 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 build/res.o build/res.RES *.dSYM $(PROG).exe *.dll *.lib res.o res.RES *.dSYM *.zip *.pdb \
*.exe *dmg* $(ALL_OBJECTS) $(ALL_WINOBJS)
+6
View File
@@ -0,0 +1,6 @@
LOCAL_PATH := $(call my-dir)/../..
include $(CLEAR_VARS)
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(COPT)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := main.c mongoose.c
include $(BUILD_EXECUTABLE)
+1 -3
View File
@@ -31,9 +31,7 @@
#include <assert.h> #include <assert.h>
#define LUA_LIB #define LUA_LIB
#include "lua.h" #include "lua_5.2.1.h"
#include "lauxlib.h"
#include "sqlite3.h" #include "sqlite3.h"
/* compile time features */ /* compile time features */
+17698
View File
File diff suppressed because it is too large. Load diff
+1247
View File
File diff suppressed because it is too large. Load diff
+142 -58
View File
@@ -41,21 +41,30 @@
#include <windows.h> #include <windows.h>
#include <winsvc.h> #include <winsvc.h>
#include <shlobj.h> #include <shlobj.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH #define PATH_MAX MAX_PATH
#endif
#ifndef S_ISDIR
#define S_ISDIR(x) ((x) & _S_IFDIR) #define S_ISDIR(x) ((x) & _S_IFDIR)
#endif
#define DIRSEP '\\' #define DIRSEP '\\'
#define snprintf _snprintf #define snprintf _snprintf
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#define sleep(x) Sleep((x) * 1000) #define sleep(x) Sleep((x) * 1000)
#define WINCDECL __cdecl #define WINCDECL __cdecl
#define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size))
#else #else
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#define DIRSEP '/' #define DIRSEP '/'
#define WINCDECL #define WINCDECL
#define abs_path(rel, abs, abs_size) realpath((rel), (abs))
#endif // _WIN32 #endif // _WIN32
#define MAX_OPTIONS 40 #define MAX_OPTIONS 100
#define MAX_CONF_FILE_LINE_SIZE (8 * 1024) #define MAX_CONF_FILE_LINE_SIZE (8 * 1024)
static int exit_flag; static int exit_flag;
@@ -68,7 +77,15 @@ static struct mg_context *ctx; // Set by start_mongoose()
#endif /* !CONFIG_FILE */ #endif /* !CONFIG_FILE */
static void WINCDECL signal_handler(int sig_num) { static void WINCDECL signal_handler(int sig_num) {
exit_flag = sig_num; #if !defined(_WIN32)
// Do not do the trick with ignoring SIGCHLD, cause not all OSes (e.g. QNX)
// reap zombies if SIGCHLD is ignored. On QNX, for example, waitpid()
// fails if SIGCHLD is ignored, making system() non-functional.
if (sig_num == SIGCHLD) {
do {} while (waitpid(-1, &sig_num, WNOHANG) > 0);
} else
#endif
{ exit_flag = sig_num; }
} }
static void die(const char *fmt, ...) { static void die(const char *fmt, ...) {
@@ -92,18 +109,18 @@ static void show_usage_and_exit(void) {
const char **names; const char **names;
int i; int i;
fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built %s\n", fprintf(stderr, "Mongoose version %s (c) Sergey Lyubka, built on %s\n",
mg_version(), __DATE__); mg_version(), __DATE__);
fprintf(stderr, "Usage:\n"); fprintf(stderr, "Usage:\n");
fprintf(stderr, " mongoose -A <htpasswd_file> <realm> <user> <passwd>\n"); fprintf(stderr, " mongoose -A <htpasswd_file> <realm> <user> <passwd>\n");
fprintf(stderr, " mongoose <config_file>\n"); fprintf(stderr, " mongoose [config_file]\n");
fprintf(stderr, " mongoose [-option value ...]\n"); fprintf(stderr, " mongoose [-option value ...]\n");
fprintf(stderr, "\nOPTIONS:\n"); fprintf(stderr, "\nOPTIONS:\n");
names = mg_get_valid_option_names(); names = mg_get_valid_option_names();
for (i = 0; names[i] != NULL; i += 3) { for (i = 0; names[i] != NULL; i += 2) {
fprintf(stderr, " -%s %s (default: \"%s\")\n", fprintf(stderr, " -%s %s\n",
names[i], names[i + 1], names[i + 2] == NULL ? "" : names[i + 2]); names[i], names[i + 1] == NULL ? "<empty>" : names[i + 1]);
} }
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -146,32 +163,15 @@ static void create_config_file(const char *path) {
} else if ((fp = fopen(path, "a+")) != NULL) { } else if ((fp = fopen(path, "a+")) != NULL) {
fprintf(fp, "%s", config_file_top_comment); fprintf(fp, "%s", config_file_top_comment);
names = mg_get_valid_option_names(); names = mg_get_valid_option_names();
for (i = 0; names[i] != NULL; i += 3) { for (i = 0; names[i * 2] != NULL; i++) {
value = mg_get_option(ctx, names[i]); value = mg_get_option(ctx, names[i * 2]);
fprintf(fp, "# %s %s\n", names[i + 1], *value ? value : "<value>"); fprintf(fp, "# %s %s\n", names[i * 2], value ? value : "<value>");
} }
fclose(fp); fclose(fp);
} }
} }
#endif #endif
static void verify_document_root(const char *root) {
const char *p, *path;
char buf[PATH_MAX];
struct stat st;
path = root;
if ((p = strchr(root, ',')) != NULL && (size_t) (p - root) < sizeof(buf)) {
memcpy(buf, root, p - root);
buf[p - root] = '\0';
path = buf;
}
if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode)) {
die("Invalid root directory: [%s]: %s", root, strerror(errno));
}
}
static char *sdup(const char *str) { static char *sdup(const char *str) {
char *p; char *p;
if ((p = (char *) malloc(strlen(str) + 1)) != NULL) { if ((p = (char *) malloc(strlen(str) + 1)) != NULL) {
@@ -183,16 +183,16 @@ static char *sdup(const char *str) {
static void set_option(char **options, const char *name, const char *value) { static void set_option(char **options, const char *name, const char *value) {
int i; int i;
if (!strcmp(name, "document_root") || !(strcmp(name, "r"))) {
verify_document_root(value);
}
for (i = 0; i < MAX_OPTIONS - 3; i++) { for (i = 0; i < MAX_OPTIONS - 3; i++) {
if (options[i] == NULL) { if (options[i] == NULL) {
options[i] = sdup(name); options[i] = sdup(name);
options[i + 1] = sdup(value); options[i + 1] = sdup(value);
options[i + 2] = NULL; options[i + 2] = NULL;
break; break;
} else if (!strcmp(options[i], name)) {
free(options[i + 1]);
options[i + 1] = sdup(value);
break;
} }
} }
@@ -206,8 +206,6 @@ static void process_command_line_arguments(char *argv[], char **options) {
FILE *fp = NULL; FILE *fp = NULL;
size_t i, cmd_line_opts_start = 1, line_no = 0; size_t i, cmd_line_opts_start = 1, line_no = 0;
options[0] = NULL;
// Should we use a config file ? // Should we use a config file ?
if (argv[1] != NULL && argv[1][0] != '-') { if (argv[1] != NULL && argv[1][0] != '-') {
snprintf(config_file, sizeof(config_file), "%s", argv[1]); snprintf(config_file, sizeof(config_file), "%s", argv[1]);
@@ -268,7 +266,7 @@ static void process_command_line_arguments(char *argv[], char **options) {
} }
static void init_server_name(void) { static void init_server_name(void) {
snprintf(server_name, sizeof(server_name), "Mongoose web server v. %s", snprintf(server_name, sizeof(server_name), "Mongoose web server v.%s",
mg_version()); mg_version());
} }
@@ -278,6 +276,69 @@ static int log_message(const struct mg_connection *conn, const char *message) {
return 0; return 0;
} }
static int is_path_absolute(const char *path) {
#ifdef _WIN32
return path != NULL &&
((path[0] == '\\' && path[1] == '\\') || // UNC path, e.g. \\server\dir
(isalpha(path[0]) && path[1] == ':' && path[2] == '\\')); // E.g. X:\dir
#else
return path != NULL && path[0] == '/';
#endif
}
static char *get_option(char **options, const char *option_name) {
int i;
for (i = 0; options[i] != NULL; i++)
if (!strcmp(options[i], option_name))
return options[i + 1];
return NULL;
}
static void verify_existence(char **options, const char *option_name,
int must_be_dir) {
struct stat st;
const char *path = get_option(options, option_name);
if (path != NULL && (stat(path, &st) != 0 ||
((S_ISDIR(st.st_mode) ? 1 : 0) != must_be_dir))) {
die("Invalid path for %s: [%s]: (%s). Make sure that path is either "
"absolute, or it is relative to mongoose executable.",
option_name, path, strerror(errno));
}
}
static void set_absolute_path(char *options[], const char *option_name,
const char *path_to_mongoose_exe) {
char path[PATH_MAX], abs[PATH_MAX], *option_value;
const char *p;
// Check whether option is already set
option_value = get_option(options, option_name);
// If option is already set and it is an absolute path,
// leave it as it is -- it's already absolute.
if (option_value != NULL && !is_path_absolute(option_value)) {
// Not absolute. Use the directory where mongoose executable lives
// be the relative directory for everything.
// Extract mongoose executable directory into path.
if ((p = strrchr(path_to_mongoose_exe, DIRSEP)) == NULL) {
getcwd(path, sizeof(path));
} else {
snprintf(path, sizeof(path), "%.*s", (int) (p - path_to_mongoose_exe),
path_to_mongoose_exe);
}
strncat(path, "/", sizeof(path) - 1);
strncat(path, option_value, sizeof(path) - 1);
// Absolutize the path, and set the option
abs_path(path, abs, sizeof(abs));
set_option(options, option_name, abs);
}
}
static void start_mongoose(int argc, char *argv[]) { static void start_mongoose(int argc, char *argv[]) {
struct mg_callbacks callbacks; struct mg_callbacks callbacks;
char *options[MAX_OPTIONS]; char *options[MAX_OPTIONS];
@@ -297,14 +358,32 @@ static void start_mongoose(int argc, char *argv[]) {
show_usage_and_exit(); show_usage_and_exit();
} }
/* Update config based on command line arguments */ options[0] = NULL;
set_option(options, "document_root", ".");
// Update config based on command line arguments
process_command_line_arguments(argv, options); process_command_line_arguments(argv, options);
/* Setup signal handler: quit on Ctrl-C */ // Make sure we have absolute paths for files and directories
// https://github.com/valenok/mongoose/issues/181
set_absolute_path(options, "document_root", argv[0]);
set_absolute_path(options, "put_delete_auth_file", argv[0]);
set_absolute_path(options, "cgi_interpreter", argv[0]);
set_absolute_path(options, "access_log_file", argv[0]);
set_absolute_path(options, "error_log_file", argv[0]);
set_absolute_path(options, "global_auth_file", argv[0]);
set_absolute_path(options, "ssl_certificate", argv[0]);
// Make extra verification for certain options
verify_existence(options, "document_root", 1);
verify_existence(options, "cgi_interpreter", 0);
verify_existence(options, "ssl_certificate", 0);
// Setup signal handler: quit on Ctrl-C
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);
/* Start Mongoose */ // Start Mongoose
memset(&callbacks, 0, sizeof(callbacks)); memset(&callbacks, 0, sizeof(callbacks));
callbacks.log_message = &log_message; callbacks.log_message = &log_message;
ctx = mg_start(&callbacks, NULL, (const char **) options); ctx = mg_start(&callbacks, NULL, (const char **) options);
@@ -410,16 +489,16 @@ static void save_config(HWND hDlg, FILE *fp) {
fprintf(fp, "%s", config_file_top_comment); fprintf(fp, "%s", config_file_top_comment);
options = mg_get_valid_option_names(); options = mg_get_valid_option_names();
for (i = 0; options[i] != NULL; i += 3) { for (i = 0; options[i * 2] != NULL; i++) {
name = options[i + 1]; name = options[i * 2];
id = ID_CONTROLS + i / 3; id = ID_CONTROLS + i;
if (is_boolean_option(name)) { if (is_boolean_option(name)) {
snprintf(value, sizeof(value), "%s", snprintf(value, sizeof(value), "%s",
IsDlgButtonChecked(hDlg, id) ? "yes" : "no"); IsDlgButtonChecked(hDlg, id) ? "yes" : "no");
} else { } else {
GetDlgItemText(hDlg, id, value, sizeof(value)); GetDlgItemText(hDlg, id, value, sizeof(value));
} }
default_value = options[i + 2] == NULL ? "" : options[i + 2]; default_value = options[i * 2 + 1] == NULL ? "" : options[i * 2 + 1];
// If value is the same as default, skip it // If value is the same as default, skip it
if (strcmp(value, default_value) != 0) { if (strcmp(value, default_value) != 0) {
fprintf(fp, "%s %s\n", name, value); fprintf(fp, "%s %s\n", name, value);
@@ -450,23 +529,23 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP) {
EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE); EnableWindow(GetDlgItem(hDlg, ID_SAVE), TRUE);
break; break;
case ID_RESET_DEFAULTS: case ID_RESET_DEFAULTS:
for (i = 0; options[i] != NULL; i += 3) { for (i = 0; options[i * 2] != NULL; i++) {
name = options[i + 1]; name = options[i * 2];
value = options[i + 2] == NULL ? "" : options[i + 2]; value = options[i * 2 + 1] == NULL ? "" : options[i * 2 + 1];
if (is_boolean_option(name)) { if (is_boolean_option(name)) {
CheckDlgButton(hDlg, ID_CONTROLS + i / 3, !strcmp(value, "yes") ? CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
BST_CHECKED : BST_UNCHECKED); BST_CHECKED : BST_UNCHECKED);
} else { } else {
SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i / 3), value); SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), value);
} }
} }
break; break;
} }
for (i = 0; options[i] != NULL; i += 3) { for (i = 0; options[i * 2] != NULL; i++) {
name = options[i + 1]; name = options[i * 2];
if ((is_filename_option(name) || is_directory_option(name)) && if ((is_filename_option(name) || is_directory_option(name)) &&
LOWORD(wParam) == ID_CONTROLS + i / 3 + ID_FILE_BUTTONS_DELTA) { LOWORD(wParam) == ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA) {
OPENFILENAME of; OPENFILENAME of;
BROWSEINFO bi; BROWSEINFO bi;
char path[PATH_MAX] = ""; char path[PATH_MAX] = "";
@@ -491,7 +570,7 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP) {
} }
if (path[0] != '\0') { if (path[0] != '\0') {
SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i / 3), path); SetWindowText(GetDlgItem(hDlg, ID_CONTROLS + i), path);
} }
} }
} }
@@ -503,14 +582,14 @@ static BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP) {
SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_BIG, (LPARAM) hIcon); SendMessage(hDlg, WM_SETICON,(WPARAM) ICON_BIG, (LPARAM) hIcon);
SetWindowText(hDlg, "Mongoose settings"); SetWindowText(hDlg, "Mongoose settings");
SetFocus(GetDlgItem(hDlg, ID_SAVE)); SetFocus(GetDlgItem(hDlg, ID_SAVE));
for (i = 0; options[i] != NULL; i += 3) { for (i = 0; options[i * 2] != NULL; i++) {
name = options[i + 1]; name = options[i * 2];
value = mg_get_option(ctx, name); value = mg_get_option(ctx, name);
if (is_boolean_option(name)) { if (is_boolean_option(name)) {
CheckDlgButton(hDlg, ID_CONTROLS + i / 3, !strcmp(value, "yes") ? CheckDlgButton(hDlg, ID_CONTROLS + i, !strcmp(value, "yes") ?
BST_CHECKED : BST_UNCHECKED); BST_CHECKED : BST_UNCHECKED);
} else { } else {
SetDlgItemText(hDlg, ID_CONTROLS + i / 3, value == NULL ? "" : value); SetDlgItemText(hDlg, ID_CONTROLS + i, value == NULL ? "" : value);
} }
} }
break; break;
@@ -587,8 +666,8 @@ static void show_settings_dialog() {
p = mem + sizeof(dialog_header); p = mem + sizeof(dialog_header);
option_names = mg_get_valid_option_names(); option_names = mg_get_valid_option_names();
for (i = 0; option_names[i] != NULL; i += 3) { for (i = 0; option_names[i * 2] != NULL; i++) {
long_option_name = option_names[i + 1]; long_option_name = option_names[i * 2];
style = WS_CHILD | WS_VISIBLE | WS_TABSTOP; style = WS_CHILD | WS_VISIBLE | WS_TABSTOP;
x = 10 + (WIDTH / 2) * (nelems % 2); x = 10 + (WIDTH / 2) * (nelems % 2);
y = (nelems/2 + 1) * HEIGHT + 5; y = (nelems/2 + 1) * HEIGHT + 5;
@@ -606,7 +685,7 @@ static void show_settings_dialog() {
width -= 20; width -= 20;
cl = 0x81; cl = 0x81;
add_control(&p, dia, 0x80, add_control(&p, dia, 0x80,
ID_CONTROLS + (i / 3) + ID_FILE_BUTTONS_DELTA, ID_CONTROLS + i + ID_FILE_BUTTONS_DELTA,
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
(WORD) (x + width + LABEL_WIDTH + 5), (WORD) (x + width + LABEL_WIDTH + 5),
y, 15, 12, "..."); y, 15, 12, "...");
@@ -616,7 +695,7 @@ static void show_settings_dialog() {
} }
add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD, add_control(&p, dia, 0x82, ID_STATIC, WS_VISIBLE | WS_CHILD,
x, y, LABEL_WIDTH, HEIGHT, long_option_name); x, y, LABEL_WIDTH, HEIGHT, long_option_name);
add_control(&p, dia, cl, ID_CONTROLS + (i / 3), style, add_control(&p, dia, cl, ID_CONTROLS + i, style,
(WORD) (x + LABEL_WIDTH), y, width, 12, ""); (WORD) (x + LABEL_WIDTH), y, width, 12, "");
nelems++; nelems++;
} }
@@ -690,6 +769,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
char buf[200], *service_argv[] = {__argv[0], NULL}; char buf[200], *service_argv[] = {__argv[0], NULL};
POINT pt; POINT pt;
HMENU hMenu; HMENU hMenu;
static UINT s_uTaskbarRestart; // for taskbar creation
switch (msg) { switch (msg) {
case WM_CREATE: case WM_CREATE:
@@ -700,6 +780,7 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} else { } else {
start_mongoose(__argc, __argv); start_mongoose(__argc, __argv);
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
} }
break; break;
case WM_COMMAND: case WM_COMMAND:
@@ -757,6 +838,9 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
Shell_NotifyIcon(NIM_DELETE, &TrayIcon); Shell_NotifyIcon(NIM_DELETE, &TrayIcon);
PostQuitMessage(0); PostQuitMessage(0);
return 0; // We've just sent our own quit message, with proper hwnd. return 0; // We've just sent our own quit message, with proper hwnd.
default:
if (msg==s_uTaskbarRestart)
Shell_NotifyIcon(NIM_ADD, &TrayIcon);
} }
return DefWindowProc(hWnd, msg, wParam, lParam); return DefWindowProc(hWnd, msg, wParam, lParam);
+393
View File
@@ -0,0 +1,393 @@
#include "lua_5.2.1.h"
#ifdef _WIN32
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
int offset) {
HANDLE fh = (HANDLE) _get_osfhandle(fd);
HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
CloseHandle(mh);
return p;
}
#define munmap(x, y) UnmapViewOfFile(x)
#define MAP_FAILED NULL
#define MAP_PRIVATE 0
#define PROT_READ 0
#else
#include <sys/mman.h>
#endif
static const char *LUASOCKET = "luasocket";
// Forward declarations
static void handle_request(struct mg_connection *);
static int handle_lsp_request(struct mg_connection *, const char *,
struct file *, struct lua_State *);
static void reg_string(struct lua_State *L, const char *name, const char *val) {
lua_pushstring(L, name);
lua_pushstring(L, val);
lua_rawset(L, -3);
}
static void reg_int(struct lua_State *L, const char *name, int val) {
lua_pushstring(L, name);
lua_pushinteger(L, val);
lua_rawset(L, -3);
}
static void reg_function(struct lua_State *L, const char *name,
lua_CFunction func, struct mg_connection *conn) {
lua_pushstring(L, name);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, func, 1);
lua_rawset(L, -3);
}
static int lsp_sock_close(lua_State *L) {
if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
lua_getfield(L, -1, "sock");
closesocket((SOCKET) lua_tonumber(L, -1));
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static int lsp_sock_recv(lua_State *L) {
char buf[2000];
int n;
if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
lua_getfield(L, -1, "sock");
n = recv((SOCKET) lua_tonumber(L, -1), buf, sizeof(buf), 0);
if (n <= 0) {
lua_pushnil(L);
} else {
lua_pushlstring(L, buf, n);
}
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static int lsp_sock_send(lua_State *L) {
const char *buf;
size_t len, sent = 0;
int n, sock;
if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) {
buf = lua_tolstring(L, -1, &len);
lua_getfield(L, -2, "sock");
sock = (int) lua_tonumber(L, -1);
while (sent < len) {
if ((n = send(sock, buf + sent, len - sent, 0)) <= 0) {
break;
}
sent += n;
}
lua_pushnumber(L, n);
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static const struct luaL_Reg luasocket_methods[] = {
{"close", lsp_sock_close},
{"send", lsp_sock_send},
{"recv", lsp_sock_recv},
{NULL, NULL}
};
static int lsp_connect(lua_State *L) {
char ebuf[100];
SOCKET sock;
if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
sock = conn2(lua_tostring(L, -3), (int) lua_tonumber(L, -2),
(int) lua_tonumber(L, -1), ebuf, sizeof(ebuf));
if (sock == INVALID_SOCKET) {
return luaL_error(L, ebuf);
} else {
lua_newtable(L);
reg_int(L, "sock", sock);
reg_string(L, "host", lua_tostring(L, -4));
luaL_getmetatable(L, LUASOCKET);
lua_setmetatable(L, -2);
}
} else {
return luaL_error(L, "connect(host,port,is_ssl): invalid parameter given.");
}
return 1;
}
static int lsp_error(lua_State *L) {
lua_getglobal(L, "mg");
lua_getfield(L, -1, "onerror");
lua_pushvalue(L, -3);
lua_pcall(L, 1, 0, 0);
return 0;
}
// Silently stop processing chunks.
static void lsp_abort(lua_State *L) {
int top = lua_gettop(L);
lua_getglobal(L, "mg");
lua_pushnil(L);
lua_setfield(L, -2, "onerror");
lua_settop(L, top);
lua_pushstring(L, "aborting");
lua_error(L);
}
static int lsp(struct mg_connection *conn, const char *path,
const char *p, int64_t len, lua_State *L) {
int i, j, pos = 0, lines = 1, lualines = 0;
char chunkname[MG_BUF_LEN];
for (i = 0; i < len; i++) {
if (p[i] == '\n') lines++;
if (p[i] == '<' && p[i + 1] == '?') {
for (j = i + 1; j < len ; j++) {
if (p[j] == '\n') lualines++;
if (p[j] == '?' && p[j + 1] == '>') {
mg_write(conn, p + pos, i - pos);
snprintf(chunkname, sizeof(chunkname), "@%s+%i", path, lines);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, lsp_error, 1);
if (luaL_loadbuffer(L, p + (i + 2), j - (i + 2), chunkname)) {
// Syntax error or OOM. Error message is pushed on stack.
lua_pcall(L, 1, 0, 0);
} else {
// Success loading chunk. Call it.
lua_pcall(L, 0, 0, 1);
}
pos = j + 2;
i = pos - 1;
break;
}
}
if (lualines > 0) {
lines += lualines;
lualines = 0;
}
}
}
if (i > pos) {
mg_write(conn, p + pos, i - pos);
}
return 0;
}
static int lsp_write(lua_State *L) {
int i, num_args;
const char *str;
size_t size;
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
num_args = lua_gettop(L);
for (i = 1; i <= num_args; i++) {
if (lua_isstring(L, i)) {
str = lua_tolstring(L, i, &size);
mg_write(conn, str, size);
}
}
return 0;
}
static int lsp_read(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
char buf[1024];
int len = mg_read(conn, buf, sizeof(buf));
if (len <= 0) return 0;
lua_pushlstring(L, buf, len);
return 1;
}
// mg.include: Include another .lp file
static int lsp_include(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
struct file file = STRUCT_FILE_INITIALIZER;
if (handle_lsp_request(conn, lua_tostring(L, -1), &file, L)) {
// handle_lsp_request returned an error code, meaning an error occured in
// the included page and mg.onerror returned non-zero. Stop processing.
lsp_abort(L);
}
return 0;
}
// mg.cry: Log an error. Default value for mg.onerror.
static int lsp_cry(lua_State *L){
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
cry(conn, "%s", lua_tostring(L, -1));
return 0;
}
// mg.redirect: Redirect the request (internally).
static int lsp_redirect(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
conn->request_info.uri = lua_tostring(L, -1);
handle_request(conn);
lsp_abort(L);
return 0;
}
static void prepare_lua_environment(struct mg_connection *conn, lua_State *L) {
const struct mg_request_info *ri = mg_get_request_info(conn);
extern void luaL_openlibs(lua_State *);
int i;
luaL_openlibs(L);
#ifdef USE_LUA_SQLITE3
{ extern int luaopen_lsqlite3(lua_State *); luaopen_lsqlite3(L); }
#endif
luaL_newmetatable(L, LUASOCKET);
lua_pushliteral(L, "__index");
luaL_newlib(L, luasocket_methods);
lua_rawset(L, -3);
lua_pop(L, 1);
lua_register(L, "connect", lsp_connect);
if (conn == NULL) return;
// Register mg module
lua_newtable(L);
reg_function(L, "read", lsp_read, conn);
reg_function(L, "write", lsp_write, conn);
reg_function(L, "cry", lsp_cry, conn);
reg_function(L, "include", lsp_include, conn);
reg_function(L, "redirect", lsp_redirect, conn);
reg_string(L, "version", MONGOOSE_VERSION);
// Export request_info
lua_pushstring(L, "request_info");
lua_newtable(L);
reg_string(L, "request_method", ri->request_method);
reg_string(L, "uri", ri->uri);
reg_string(L, "http_version", ri->http_version);
reg_string(L, "query_string", ri->query_string);
reg_int(L, "remote_ip", ri->remote_ip);
reg_int(L, "remote_port", ri->remote_port);
reg_int(L, "num_headers", ri->num_headers);
lua_pushstring(L, "http_headers");
lua_newtable(L);
for (i = 0; i < ri->num_headers; i++) {
reg_string(L, ri->http_headers[i].name, ri->http_headers[i].value);
}
lua_rawset(L, -3);
lua_rawset(L, -3);
lua_setglobal(L, "mg");
// Register default mg.onerror function
luaL_dostring(L, "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
"debug.traceback(e, 1)) end");
}
static int lua_error_handler(lua_State *L) {
const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
lua_getglobal(L, "mg");
if (!lua_isnil(L, -1)) {
lua_getfield(L, -1, "write"); // call mg.write()
lua_pushstring(L, error_msg);
lua_pushliteral(L, "\n");
lua_call(L, 2, 0);
luaL_dostring(L, "mg.write(debug.traceback(), '\\n')");
} else {
printf("Lua error: [%s]\n", error_msg);
luaL_dostring(L, "print(debug.traceback(), '\\n')");
}
// TODO(lsm): leave the stack balanced
return 0;
}
void mg_exec_lua_script(struct mg_connection *conn, const char *path,
const void **exports) {
int i;
lua_State *L;
if (path != NULL && (L = luaL_newstate()) != NULL) {
prepare_lua_environment(conn, L);
lua_pushcclosure(L, &lua_error_handler, 0);
lua_pushglobaltable(L);
if (exports != NULL) {
for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
lua_pushstring(L, exports[i]);
lua_pushcclosure(L, (lua_CFunction) exports[i + 1], 0);
lua_rawset(L, -3);
}
}
if (luaL_loadfile(L, path) != 0) {
lua_error_handler(L);
}
lua_pcall(L, 0, 0, -2);
lua_close(L);
}
}
static void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
const char *fmt, ...) {
char buf[MG_BUF_LEN];
va_list ap;
int len;
va_start(ap, fmt);
len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (L == NULL) {
send_http_error(conn, 500, http_500_error, "%s", buf);
} else {
lua_pushstring(L, buf);
lua_error(L);
}
}
static int handle_lsp_request(struct mg_connection *conn, const char *path,
struct file *filep, struct lua_State *ls) {
void *p = NULL;
lua_State *L = NULL;
int error = 1;
// We need both mg_stat to get file size, and mg_fopen to get fd
if (!mg_stat(conn, path, filep) || !mg_fopen(conn, path, "r", filep)) {
lsp_send_err(conn, ls, "File [%s] not found", path);
} else if (filep->membuf == NULL &&
(p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
fileno(filep->fp), 0)) == MAP_FAILED) {
lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
fileno(filep->fp), strerror(errno));
} else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) {
send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
} else {
// We're not sending HTTP headers here, Lua page must do it.
if (ls == NULL) {
prepare_lua_environment(conn, L);
if (conn->ctx->callbacks.init_lua != NULL) {
conn->ctx->callbacks.init_lua(conn, L);
}
}
error = lsp(conn, path, filep->membuf == NULL ? p : filep->membuf,
filep->size, L);
}
if (L != NULL && ls == NULL) lua_close(L);
if (p != NULL) munmap(p, filep->size);
mg_fclose(filep);
return error;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+4207 -1165
View File
File diff suppressed because it is too large. Load diff
+111 -26
View File
@@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.7.15.2" #define SQLITE_VERSION "3.7.17"
#define SQLITE_VERSION_NUMBER 3007015 #define SQLITE_VERSION_NUMBER 3007017
#define SQLITE_SOURCE_ID "2013-01-09 11:53:05 c0e09560d26f0a6456be9dd3447f5311eb4f238f" #define SQLITE_SOURCE_ID "2013-05-20 00:56:22 118a3b35693b134d56ebd780123b7fd6f1497668"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@@ -288,7 +288,7 @@ typedef sqlite_uint64 sqlite3_uint64;
** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_blob_close | close] all [BLOB handles], and
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
** with the [sqlite3] object prior to attempting to close the object. ^If ** with the [sqlite3] object prior to attempting to close the object. ^If
** sqlite3_close() is called on a [database connection] that still has ** sqlite3_close_v2() is called on a [database connection] that still has
** outstanding [prepared statements], [BLOB handles], and/or ** outstanding [prepared statements], [BLOB handles], and/or
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
** of resources is deferred until all [prepared statements], [BLOB handles], ** of resources is deferred until all [prepared statements], [BLOB handles],
@@ -425,6 +425,8 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_FORMAT 24 /* Auxiliary database format error */ #define SQLITE_FORMAT 24 /* Auxiliary database format error */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */ #define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
/* end-of-error-codes */ /* end-of-error-codes */
@@ -475,6 +477,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
@@ -483,7 +486,19 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8))
#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8))
#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8))
#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8))
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
/* /*
** CAPI3REF: Flags For File Open Operations ** CAPI3REF: Flags For File Open Operations
@@ -723,6 +738,9 @@ struct sqlite3_io_methods {
void (*xShmBarrier)(sqlite3_file*); void (*xShmBarrier)(sqlite3_file*);
int (*xShmUnmap)(sqlite3_file*, int deleteFlag); int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */ /* Methods above are valid for version 2 */
int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */ /* Additional methods may be added in future releases */
}; };
@@ -859,7 +877,8 @@ struct sqlite3_io_methods {
** it is able to override built-in [PRAGMA] statements. ** it is able to override built-in [PRAGMA] statements.
** **
** <li>[[SQLITE_FCNTL_BUSYHANDLER]] ** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
** ^This file-control may be invoked by SQLite on the database file handle ** ^The [SQLITE_FCNTL_BUSYHANDLER]
** file-control may be invoked by SQLite on the database file handle
** shortly after it is opened in order to provide a custom VFS with access ** shortly after it is opened in order to provide a custom VFS with access
** to the connections busy-handler callback. The argument is of type (void **) ** to the connections busy-handler callback. The argument is of type (void **)
** - an array of two (void *) values. The first (void *) actually points ** - an array of two (void *) values. The first (void *) actually points
@@ -870,13 +889,24 @@ struct sqlite3_io_methods {
** current operation. ** current operation.
** **
** <li>[[SQLITE_FCNTL_TEMPFILENAME]] ** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
** ^Application can invoke this file-control to have SQLite generate a ** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control
** to have SQLite generate a
** temporary filename using the same algorithm that is followed to generate ** temporary filename using the same algorithm that is followed to generate
** temporary filenames for TEMP tables and other internal uses. The ** temporary filenames for TEMP tables and other internal uses. The
** argument should be a char** which will be filled with the filename ** argument should be a char** which will be filled with the filename
** written into memory obtained from [sqlite3_malloc()]. The caller should ** written into memory obtained from [sqlite3_malloc()]. The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak. ** invoke [sqlite3_free()] on the result to avoid a memory leak.
** **
** <li>[[SQLITE_FCNTL_MMAP_SIZE]]
** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the
** maximum number of bytes that will be used for memory-mapped I/O.
** The argument is a pointer to a value of type sqlite3_int64 that
** is an advisory maximum number of bytes in the file to memory map. The
** pointer is overwritten with the old value. The limit is not changed if
** the value originally pointed to is negative, and so the current limit
** can be queried by passing in a pointer to a negative number. This
** file-control is used internally to implement [PRAGMA mmap_size].
**
** </ul> ** </ul>
*/ */
#define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_LOCKSTATE 1
@@ -895,6 +925,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_PRAGMA 14
#define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_BUSYHANDLER 15
#define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_TEMPFILENAME 16
#define SQLITE_FCNTL_MMAP_SIZE 18
/* /*
** CAPI3REF: Mutex Handle ** CAPI3REF: Mutex Handle
@@ -1561,7 +1592,9 @@ struct sqlite3_mem_methods {
** page cache implementation into that object.)^ </dd> ** page cache implementation into that object.)^ </dd>
** **
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
** global [error log].
** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
** function with a call signature of void(*)(void*,int,const char*), ** function with a call signature of void(*)(void*,int,const char*),
** and a pointer to void. ^If the function pointer is not NULL, it is ** and a pointer to void. ^If the function pointer is not NULL, it is
** invoked by [sqlite3_log()] to process each logging event. ^If the ** invoked by [sqlite3_log()] to process each logging event. ^If the
@@ -1607,12 +1640,12 @@ struct sqlite3_mem_methods {
** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE ** <dt>SQLITE_CONFIG_PCACHE and SQLITE_CONFIG_GETPCACHE
** <dd> These options are obsolete and should not be used by new code. ** <dd> These options are obsolete and should not be used by new code.
** They are retained for backwards compatibility but are now no-ops. ** They are retained for backwards compatibility but are now no-ops.
** </dl> ** </dd>
** **
** [[SQLITE_CONFIG_SQLLOG]] ** [[SQLITE_CONFIG_SQLLOG]]
** <dt>SQLITE_CONFIG_SQLLOG ** <dt>SQLITE_CONFIG_SQLLOG
** <dd>This option is only available if sqlite is compiled with the ** <dd>This option is only available if sqlite is compiled with the
** SQLITE_ENABLE_SQLLOG pre-processor macro defined. The first argument should ** [SQLITE_ENABLE_SQLLOG] pre-processor macro defined. The first argument should
** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int). ** be a pointer to a function of type void(*)(void*,sqlite3*,const char*, int).
** The second should be of type (void*). The callback is invoked by the library ** The second should be of type (void*). The callback is invoked by the library
** in three separate circumstances, identified by the value passed as the ** in three separate circumstances, identified by the value passed as the
@@ -1622,7 +1655,23 @@ struct sqlite3_mem_methods {
** fourth parameter is 1, then the SQL statement that the third parameter ** fourth parameter is 1, then the SQL statement that the third parameter
** points to has just been executed. Or, if the fourth parameter is 2, then ** points to has just been executed. Or, if the fourth parameter is 2, then
** the connection being passed as the second parameter is being closed. The ** the connection being passed as the second parameter is being closed. The
** third parameter is passed NULL In this case. ** third parameter is passed NULL In this case. An example of using this
** configuration option can be seen in the "test_sqllog.c" source file in
** the canonical SQLite source tree.</dd>
**
** [[SQLITE_CONFIG_MMAP_SIZE]]
** <dt>SQLITE_CONFIG_MMAP_SIZE
** <dd>SQLITE_CONFIG_MMAP_SIZE takes two 64-bit integer (sqlite3_int64) values
** that are the default mmap size limit (the default setting for
** [PRAGMA mmap_size]) and the maximum allowed mmap size limit.
** The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_size] command, or by using the
** [SQLITE_FCNTL_MMAP_SIZE] file control. The maximum allowed mmap size
** cannot be changed at run-time. Nor may the maximum allowed mmap size
** exceed the compile-time maximum mmap size set by the
** [SQLITE_MAX_MMAP_SIZE] compile-time option.
** If either argument to this option is negative, then that argument is
** changed to its compile-time default.
** </dl> ** </dl>
*/ */
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1646,6 +1695,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
/* /*
** CAPI3REF: Database Connection Configuration Options ** CAPI3REF: Database Connection Configuration Options
@@ -2479,6 +2529,9 @@ SQLITE_API int sqlite3_set_authorizer(
** as each triggered subprogram is entered. The callbacks for triggers ** as each triggered subprogram is entered. The callbacks for triggers
** contain a UTF-8 SQL comment that identifies the trigger.)^ ** contain a UTF-8 SQL comment that identifies the trigger.)^
** **
** The [SQLITE_TRACE_SIZE_LIMIT] compile-time option can be used to limit
** the length of [bound parameter] expansion in the output of sqlite3_trace().
**
** ^The callback function registered by sqlite3_profile() is invoked ** ^The callback function registered by sqlite3_profile() is invoked
** as each SQL statement finishes. ^The profile callback contains ** as each SQL statement finishes. ^The profile callback contains
** the original statement text and an estimate of wall-clock time ** the original statement text and an estimate of wall-clock time
@@ -2670,7 +2723,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** sqlite3_open_v2(). ^Setting the cache parameter to "private" is ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
** a URI filename, its value overrides any behaviour requested by setting ** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
** </ul> ** </ul>
** **
@@ -3017,7 +3070,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** <li> ** <li>
** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** ^If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
** always used to do, [sqlite3_step()] will automatically recompile the SQL ** always used to do, [sqlite3_step()] will automatically recompile the SQL
** statement and try to run it again. ** statement and try to run it again. As many as [SQLITE_MAX_SCHEMA_RETRY]
** retries will occur before sqlite3_step() gives up and returns an error.
** </li> ** </li>
** **
** <li> ** <li>
@@ -3221,6 +3275,9 @@ typedef struct sqlite3_context sqlite3_context;
** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999). ** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
** **
** ^The third argument is the value to bind to the parameter. ** ^The third argument is the value to bind to the parameter.
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
** is ignored and the end result is the same as sqlite3_bind_null().
** **
** ^(In those routines that have a fourth argument, its value is the ** ^(In those routines that have a fourth argument, its value is the
** number of bytes in the parameter. To be clear: the value is the ** number of bytes in the parameter. To be clear: the value is the
@@ -3988,7 +4045,8 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void); SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void); SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64); SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
void*,sqlite3_int64);
#endif #endif
/* /*
@@ -4068,14 +4126,17 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
** In those cases, sqlite3_aggregate_context() might be called for the ** In those cases, sqlite3_aggregate_context() might be called for the
** first time from within xFinal().)^ ** first time from within xFinal().)^
** **
** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is ** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
** less than or equal to zero or if a memory allocate error occurs. ** when first called if N is less than or equal to zero or if a memory
** allocate error occurs.
** **
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is ** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
** determined by the N parameter on first successful call. Changing the ** determined by the N parameter on first successful call. Changing the
** value of N in subsequent call to sqlite3_aggregate_context() within ** value of N in subsequent call to sqlite3_aggregate_context() within
** the same aggregate function instance will not resize the memory ** the same aggregate function instance will not resize the memory
** allocation.)^ ** allocation.)^ Within the xFinal callback, it is customary to set
** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
** pointless memory allocations occur.
** **
** ^SQLite automatically frees the memory allocated by ** ^SQLite automatically frees the memory allocated by
** sqlite3_aggregate_context() when the aggregate query concludes. ** sqlite3_aggregate_context() when the aggregate query concludes.
@@ -4173,7 +4234,7 @@ SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(voi
** the content before returning. ** the content before returning.
** **
** The typedef is necessary to work around problems in certain ** The typedef is necessary to work around problems in certain
** C++ compilers. See ticket #2191. ** C++ compilers.
*/ */
typedef void (*sqlite3_destructor_type)(void*); typedef void (*sqlite3_destructor_type)(void*);
#define SQLITE_STATIC ((sqlite3_destructor_type)0) #define SQLITE_STATIC ((sqlite3_destructor_type)0)
@@ -4972,11 +5033,20 @@ SQLITE_API int sqlite3_table_column_metadata(
** ^This interface loads an SQLite extension library from the named file. ** ^This interface loads an SQLite extension library from the named file.
** **
** ^The sqlite3_load_extension() interface attempts to load an ** ^The sqlite3_load_extension() interface attempts to load an
** SQLite extension library contained in the file zFile. ** [SQLite extension] library contained in the file zFile. If
** the file cannot be loaded directly, attempts are made to load
** with various operating-system specific extensions added.
** So for example, if "samplelib" cannot be loaded, then names like
** "samplelib.so" or "samplelib.dylib" or "samplelib.dll" might
** be tried also.
** **
** ^The entry point is zProc. ** ^The entry point is zProc.
** ^zProc may be 0, in which case the name of the entry point ** ^(zProc may be 0, in which case SQLite will try to come up with an
** defaults to "sqlite3_extension_init". ** entry point name on its own. It first tries "sqlite3_extension_init".
** If that does not work, it constructs a name "sqlite3_X_init" where the
** X is consists of the lower-case equivalent of all ASCII alphabetic
** characters in the filename from the last "/" to the first following
** "." and omitting any initial "lib".)^
** ^The sqlite3_load_extension() interface returns ** ^The sqlite3_load_extension() interface returns
** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong. ** [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
** ^If an error occurs and pzErrMsg is not 0, then the ** ^If an error occurs and pzErrMsg is not 0, then the
@@ -5002,11 +5072,11 @@ SQLITE_API int sqlite3_load_extension(
** CAPI3REF: Enable Or Disable Extension Loading ** CAPI3REF: Enable Or Disable Extension Loading
** **
** ^So as not to open security holes in older applications that are ** ^So as not to open security holes in older applications that are
** unprepared to deal with extension loading, and as a means of disabling ** unprepared to deal with [extension loading], and as a means of disabling
** extension loading while evaluating user-entered SQL, the following API ** [extension loading] while evaluating user-entered SQL, the following API
** is provided to turn the [sqlite3_load_extension()] mechanism on and off. ** is provided to turn the [sqlite3_load_extension()] mechanism on and off.
** **
** ^Extension loading is off by default. See ticket #1863. ** ^Extension loading is off by default.
** ^Call the sqlite3_enable_load_extension() routine with onoff==1 ** ^Call the sqlite3_enable_load_extension() routine with onoff==1
** to turn extension loading on and call it with onoff==0 to turn ** to turn extension loading on and call it with onoff==0 to turn
** it back off again. ** it back off again.
@@ -5018,7 +5088,7 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
** **
** ^This interface causes the xEntryPoint() function to be invoked for ** ^This interface causes the xEntryPoint() function to be invoked for
** each new [database connection] that is created. The idea here is that ** each new [database connection] that is created. The idea here is that
** xEntryPoint() is the entry point for a statically linked SQLite extension ** xEntryPoint() is the entry point for a statically linked [SQLite extension]
** that is to be automatically loaded into all new database connections. ** that is to be automatically loaded into all new database connections.
** **
** ^(Even though the function prototype shows that xEntryPoint() takes ** ^(Even though the function prototype shows that xEntryPoint() takes
@@ -6369,7 +6439,7 @@ struct sqlite3_pcache_page {
** parameter to help it determined what action to take: ** parameter to help it determined what action to take:
** **
** <table border=1 width=85% align=center> ** <table border=1 width=85% align=center>
** <tr><th> createFlag <th> Behaviour when page is not already in cache ** <tr><th> createFlag <th> Behavior when page is not already in cache
** <tr><td> 0 <td> Do not allocate a new page. Return NULL. ** <tr><td> 0 <td> Do not allocate a new page. Return NULL.
** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so. ** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so.
** Otherwise return NULL. ** Otherwise return NULL.
@@ -6798,10 +6868,25 @@ SQLITE_API int sqlite3_unlock_notify(
SQLITE_API int sqlite3_stricmp(const char *, const char *); SQLITE_API int sqlite3_stricmp(const char *, const char *);
SQLITE_API int sqlite3_strnicmp(const char *, const char *, int); SQLITE_API int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: String Globbing
*
** ^The [sqlite3_strglob(P,X)] interface returns zero if string X matches
** the glob pattern P, and it returns non-zero if string X does not match
** the glob pattern P. ^The definition of glob pattern matching used in
** [sqlite3_strglob(P,X)] is the same as for the "X GLOB P" operator in the
** SQL dialect used by SQLite. ^The sqlite3_strglob(P,X) function is case
** sensitive.
**
** Note that this routine returns zero on a match and non-zero if the strings
** do not match, the same as [sqlite3_stricmp()] and [sqlite3_strnicmp()].
*/
SQLITE_API int sqlite3_strglob(const char *zGlob, const char *zStr);
/* /*
** CAPI3REF: Error Logging Interface ** CAPI3REF: Error Logging Interface
** **
** ^The [sqlite3_log()] interface writes a message into the error log ** ^The [sqlite3_log()] interface writes a message into the [error log]
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()]. ** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
** ^If logging is enabled, the zFormat string and subsequent arguments are ** ^If logging is enabled, the zFormat string and subsequent arguments are
** used with [sqlite3_snprintf()] to generate the final output string. ** used with [sqlite3_snprintf()] to generate the final output string.
+47 -19
View File
@@ -1,28 +1,56 @@
CFLAGS= -W -Wall -I.. -pthread -g CFLAGS = -W -Wall -I.. -pthread -g -pipe $(COPT)
DLL_FLAGS = -DLUA_COMPAT_ALL -I../build
all: ifeq ($(OS),Windows_NT)
OS=`uname`; \ else
test "$$OS" = Linux && LIBS="-ldl" ; \ UNAME_S := $(shell uname -s)
$(CC) $(CFLAGS) hello.c ../mongoose.c $$LIBS $(ADD) -o hello; DLL_FLAGS += -shared
$(CC) $(CFLAGS) upload.c ../mongoose.c $$LIBS $(ADD) -o upload;
$(CC) $(CFLAGS) post.c ../mongoose.c $$LIBS $(ADD) -o post; ifeq ($(UNAME_S),Linux)
$(CC) $(CFLAGS) -DUSE_WEBSOCKET websocket.c ../mongoose.c $$LIBS $(ADD) -o websocket; CFLAGS += -ldl
$(CC) $(CFLAGS) chat.c ../mongoose.c $$LIBS $(ADD) -o chat endif
ifeq ($(UNAME_S),Darwin)
# DLL_FLAGS += -bundle -undefined dynamic_lookup -dynamiclib
DLL_FLAGS += -flat_namespace -undefined suppress -dynamiclib
endif
endif
all: hello upload post websocket chat
hello:
$(CC) hello.c ../mongoose.c -o $@ $(CFLAGS)
upload:
$(CC) upload.c ../mongoose.c -o $@ $(CFLAGS)
post:
$(CC) post.c ../mongoose.c -o $@ $(CFLAGS)
websocket:
$(CC) -DUSE_WEBSOCKET websocket.c ../mongoose.c -o $@ $(CFLAGS)
chat:
$(CC) chat.c ../mongoose.c -o $@ $(CFLAGS)
lua_dll:
$(CC) lua_dll.c ../build/lua_5.2.1.c -o $@.so $(CFLAGS) $(DLL_FLAGS)
MSVC = e:/vc6 MSVC = ../../vc6
CL = $(MSVC)/bin/cl CL = $(MSVC)/bin/cl
CLFLAGS = /MD /TC /nologo $(DBG) /W3 /DNO_SSL \ CLFLAGS = /MD /TC /nologo $(DBG) /W3 /DNO_SSL \
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf \ /I$(MSVC)/include /I.. /Dsnprintf=_snprintf
/link /incremental:no /libpath:$(MSVC)/lib /machine:IX86 LFLAGS = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
windows: windows:
$(CL) upload.c ../mongoose.c $(CLFLAGS) $(CL) upload.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) hello.c ../mongoose.c $(CLFLAGS) $(CL) hello.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) upload.c ../mongoose.c $(CLFLAGS) $(CL) upload.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) post.c ../mongoose.c $(CLFLAGS) $(CL) post.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) post.c ../mongoose.c $(CLFLAGS) $(CL) post.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) /DUSE_WEBSOCKET websocket.c ../mongoose.c $(CLFLAGS) $(CL) /DUSE_WEBSOCKET websocket.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
#$(CL) lua_dll.c $(CLFLAGS) $(DLL_FLAGS) /DLL $(LFLAGS) /SUBSYSTEM:WINDOWS /ENTRY:luaopen_lua_dll /EXPORT:luaopen_lua_dll /out:lua_dll.dll
clean: clean:
rm -rf hello upload post websocket chat *.exe *.dSYM *.obj rm -rf hello upload post websocket chat *.exe *.dSYM *.obj .*o
+2 -1
View File
@@ -56,9 +56,10 @@ static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// Get session object for the connection. Caller must hold the lock. // Get session object for the connection. Caller must hold the lock.
static struct session *get_session(const struct mg_connection *conn) { static struct session *get_session(const struct mg_connection *conn) {
int i; int i;
const char *cookie = mg_get_header(conn, "Cookie");
char session_id[33]; char session_id[33];
time_t now = time(NULL); time_t now = time(NULL);
mg_get_cookie(conn, "session", session_id, sizeof(session_id)); mg_get_cookie(cookie, "session", session_id, sizeof(session_id));
for (i = 0; i < MAX_SESSIONS; i++) { for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire != 0 && if (sessions[i].expire != 0 &&
sessions[i].expire > now && sessions[i].expire > now &&
+46
View File
@@ -0,0 +1,46 @@
HTTP/1.0 200 OK
Content-Type: text/html
<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 mg.write('<span>' .. i .. '</span>&nbsp;') 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: [<?
local post_data = ''
if mg.request_info.request_method == 'POST' then
post_data = mg.read()
end
mg.write(post_data)
?>]
request method: [<? mg.write(mg.request_info.request_method) ?>]
IP/port: [<? mg.write(mg.request_info.remote_ip, ':',
mg.request_info.remote_port) ?>]
URI: [<? mg.write(mg.request_info.uri) ?>]
HTTP version [<? mg.write(mg.request_info.http_version) ?>]
HEADERS:
<?
for name, value in pairs(mg.request_info.http_headers) do
mg.write(name, ':', value, '\n')
end
?>
</pre>
</html>
+17
View File
@@ -0,0 +1,17 @@
#include <stdio.h>
#include "lua-5.2.1.h"
static int smile(lua_State *L) {
(void) L; // Unused
printf("%s\n", ":-)");
return 0;
}
int LUA_API luaopen_lua_dll(lua_State *L) {
static const struct luaL_Reg api[] = {
{"smile", smile},
{NULL, NULL},
};
luaL_openlib(L, "lua_dll", api, 0);
return 1;
}
+12 -44
View File
@@ -6,54 +6,22 @@
#include "mongoose.h" #include "mongoose.h"
static void websocket_ready_handler(struct mg_connection *conn) { static void websocket_ready_handler(struct mg_connection *conn) {
unsigned char buf[40]; static const char *message = "server ready";
buf[0] = 0x81; mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, message, strlen(message));
buf[1] = snprintf((char *) buf + 2, sizeof(buf) - 2, "%s", "server ready");
mg_write(conn, buf, 2 + buf[1]);
} }
static int websocket_data_handler(struct mg_connection *conn) { // Arguments:
unsigned char buf[200], reply[200]; // flags: first byte of websocket frame, see websocket RFC,
int n, i, mask_len, xor, msg_len, len; // http://tools.ietf.org/html/rfc6455, section 5.2
// data, data_len: payload data. Mask, if any, is already applied.
static int websocket_data_handler(struct mg_connection *conn, int flags,
char *data, size_t data_len) {
(void) flags; // Unused
mg_websocket_write(conn, WEBSOCKET_OPCODE_TEXT, data, data_len);
// Read message from the client. // Returning zero means stoping websocket conversation.
// 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 0; // 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 0; // 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);
// Returnint zero means stoping websocket conversation.
// Close the conversation if client has sent us "exit" string. // Close the conversation if client has sent us "exit" string.
return memcmp(reply + 2, "exit", 4); return memcmp(data, "exit", 4);
} }
int main(void) { int main(void) {
+6 -6
View File
@@ -1,6 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>WebSocket Test</title> <title>WebSocket Test</title>
<script language="javascript" type="text/javascript"> <script language="javascript" type="text/javascript">
var writeToScreen = function(message) { var writeToScreen = function(message) {
@@ -29,9 +29,9 @@
writeToScreen('<span style="color: red; ">ERROR: </span> ' + ev.data); writeToScreen('<span style="color: red; ">ERROR: </span> ' + ev.data);
}; };
}; };
</script> </script>
<style> div {font: small Verdana; } </style> <style> div {font: small Verdana; } </style>
<h2>Mongoose WebSocket Test</h2> <h2>Mongoose WebSocket Test</h2>
<div style="width: 400px; color: #aaa; padding: 1em; "> <div style="width: 400px; color: #aaa; padding: 1em; ">
This page code creates websocket to the URI "/foo", This page code creates websocket to the URI "/foo",
@@ -40,5 +40,5 @@
receiving the "exit" message. receiving the "exit" message.
</div> </div>
<div id="output"></div> <div id="output"></div>
</html> </html>
+848 -553
View File
File diff suppressed because it is too large. Load diff
+139 -34
View File
@@ -1,22 +1,19 @@
// Copyright (c) 2004-2012 Sergey Lyubka // Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013 Cesanta Software Limited
// All rights reserved
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // This library is dual-licensed: you can redistribute it and/or modify
// of this software and associated documentation files (the "Software"), to deal // it under the terms of the GNU General Public License version 2 as
// in the Software without restriction, including without limitation the rights // published by the Free Software Foundation. For the terms of this
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // license, see <http://www.gnu.org/licenses/>.
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // You are free to use this library under the terms of the GNU General
// all copies or substantial portions of the Software. // Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Alternatively, you can license this library under a commercial
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // license, as set out in <http://cesanta.com/products.html>.
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef MONGOOSE_HEADER_INCLUDED #ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED #define MONGOOSE_HEADER_INCLUDED
@@ -43,6 +40,7 @@ struct mg_request_info {
int remote_port; // Client's port int remote_port; // Client's port
int is_ssl; // 1 if SSL-ed, 0 if not int is_ssl; // 1 if SSL-ed, 0 if not
void *user_data; // User data pointer passed to mg_start() void *user_data; // User data pointer passed to mg_start()
void *conn_data; // Connection-specific, per-thread user data.
int num_headers; // Number of HTTP headers int num_headers; // Number of HTTP headers
struct mg_header { struct mg_header {
@@ -56,17 +54,85 @@ struct mg_request_info {
// which callbacks to invoke. For detailed description, see // which callbacks to invoke. For detailed description, see
// https://github.com/valenok/mongoose/blob/master/UserManual.md // https://github.com/valenok/mongoose/blob/master/UserManual.md
struct mg_callbacks { struct mg_callbacks {
// Called when mongoose has received new HTTP request.
// If callback returns non-zero,
// callback must process the request by sending valid HTTP headers and body,
// and mongoose will not do any further processing.
// If callback returns 0, mongoose processes the request itself. In this case,
// callback must not send any data to the client.
int (*begin_request)(struct mg_connection *); int (*begin_request)(struct mg_connection *);
// Called when mongoose has finished processing request.
void (*end_request)(const struct mg_connection *, int reply_status_code); void (*end_request)(const struct mg_connection *, int reply_status_code);
// Called when mongoose is about to log a message. If callback returns
// non-zero, mongoose does not log anything.
int (*log_message)(const struct mg_connection *, const char *message); int (*log_message)(const struct mg_connection *, const char *message);
int (*init_ssl)(void *ssl_context);
// Called when mongoose initializes SSL library.
int (*init_ssl)(void *ssl_context, void *user_data);
// Called when websocket request is received, before websocket handshake.
// If callback returns 0, mongoose proceeds with handshake, otherwise
// cinnection is closed immediately.
int (*websocket_connect)(const struct mg_connection *); int (*websocket_connect)(const struct mg_connection *);
// Called when websocket handshake is successfully completed, and
// connection is ready for data exchange.
void (*websocket_ready)(struct mg_connection *); void (*websocket_ready)(struct mg_connection *);
int (*websocket_data)(struct mg_connection *);
// Called when data frame has been received from the client.
// Parameters:
// bits: first byte of the websocket frame, see websocket RFC at
// http://tools.ietf.org/html/rfc6455, section 5.2
// data, data_len: payload, with mask (if any) already applied.
// Return value:
// non-0: keep this websocket connection opened.
// 0: close this websocket connection.
int (*websocket_data)(struct mg_connection *, int bits,
char *data, size_t data_len);
// Called when mongoose tries to open a file. Used to intercept file open
// calls, and serve file data from memory instead.
// Parameters:
// path: Full path to the file to open.
// data_len: Placeholder for the file size, if file is served from memory.
// Return value:
// NULL: do not serve file from memory, proceed with normal file open.
// non-NULL: pointer to the file contents in memory. data_len must be
// initilized with the size of the memory block.
const char * (*open_file)(const struct mg_connection *, const char * (*open_file)(const struct mg_connection *,
const char *path, size_t *data_len); const char *path, size_t *data_len);
// Called when mongoose is about to serve Lua server page (.lp file), if
// Lua support is enabled.
// Parameters:
// lua_context: "lua_State *" pointer.
void (*init_lua)(struct mg_connection *, void *lua_context); void (*init_lua)(struct mg_connection *, void *lua_context);
// Called when mongoose has uploaded a file to a temporary directory as a
// result of mg_upload() call.
// Parameters:
// file_file: full path name to the uploaded file.
void (*upload)(struct mg_connection *, const char *file_name); void (*upload)(struct mg_connection *, const char *file_name);
// Called at the beginning of mongoose's thread execution in the context of
// that thread. To be used to perform any extra per-thread initialization.
// Parameters:
// user_data: pointer passed to mg_start
// conn_data: per-connection, i.e. per-thread pointer. Can be used to
// store per-thread data, for example, database connection
// handles. Persistent between connections handled by the
// same thread.
// NOTE: this parameter is NULL for master thread, and non-NULL
// for worker threads.
void (*thread_start)(void *user_data, void **conn_data);
// Called when mongoose's thread is about to terminate.
// Same as thread_start() callback, but called when thread is about to be
// destroyed. Used to cleanup the state initialized by thread_start().
// Parameters: see thread_start().
void (*thread_stop)(void *user_data, void **conn_data);
}; };
// Start web server. // Start web server.
@@ -76,10 +142,12 @@ struct mg_callbacks {
// options: NULL terminated list of option_name, option_value pairs that // options: NULL terminated list of option_name, option_value pairs that
// specify Mongoose configuration parameters. // specify Mongoose configuration parameters.
// //
// Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom // Side-effects: on UNIX, ignores SIGPIPE signals. If custom
// processing is required for these, signal handlers must be set up // processing is required SIGPIPE, signal handler must be set up
// after calling mg_start(). // after calling mg_start().
// //
// Important: Mongoose does not install SIGCHLD handler. If CGI is used,
// SIGCHLD handler must be set up to reap CGI zombie processes.
// //
// Example: // Example:
// const char *options[] = { // const char *options[] = {
@@ -89,7 +157,7 @@ struct mg_callbacks {
// }; // };
// struct mg_context *ctx = mg_start(&my_func, NULL, options); // struct mg_context *ctx = mg_start(&my_func, NULL, options);
// //
// Please refer to http://code.google.com/p/mongoose/wiki/MongooseManual // Refer to https://github.com/valenok/mongoose/blob/master/UserManual.md
// for the list of valid option and their possible values. // for the list of valid option and their possible values.
// //
// Return: // Return:
@@ -117,7 +185,8 @@ const char *mg_get_option(const struct mg_context *ctx, const char *name);
// Return array of strings that represent valid configuration options. // Return array of strings that represent valid configuration options.
// For each option, a short name, long name, and default value is returned. // For each option, option name and default value is returned, i.e. the
// number of entries in the array equals to number_of_options x 2.
// Array is NULL terminated. // Array is NULL terminated.
const char **mg_get_valid_option_names(void); const char **mg_get_valid_option_names(void);
@@ -148,14 +217,37 @@ struct mg_request_info *mg_get_request_info(struct mg_connection *);
// Return: // Return:
// 0 when the connection has been closed // 0 when the connection has been closed
// -1 on error // -1 on error
// number of bytes written on success // >0 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 a websocket client wrapped in a websocket frame.
// It is unsafe to read/write to this connection from another thread.
// This function is available when mongoose is compiled with -DUSE_WEBSOCKET
//
// Return:
// 0 when the connection has been closed
// -1 on error
// >0 number of bytes written on success
int mg_websocket_write(struct mg_connection* conn, int opcode,
const char *data, size_t data_len);
// Opcodes, from http://tools.ietf.org/html/rfc6455
enum {
WEBSOCKET_OPCODE_CONTINUATION = 0x0,
WEBSOCKET_OPCODE_TEXT = 0x1,
WEBSOCKET_OPCODE_BINARY = 0x2,
WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
WEBSOCKET_OPCODE_PING = 0x9,
WEBSOCKET_OPCODE_PONG = 0xa
};
// Macros for enabling compiler-specific checks for printf-like arguments.
#undef PRINTF_FORMAT_STRING #undef PRINTF_FORMAT_STRING
#if _MSC_VER >= 1400 #if defined(_MSC_VER) && _MSC_VER >= 1400
#include <sal.h> #include <sal.h>
#if _MSC_VER > 1400 #if defined(_MSC_VER) && _MSC_VER > 1400
#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s #define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
#else #else
#define PRINTF_FORMAT_STRING(s) __format_string s #define PRINTF_FORMAT_STRING(s) __format_string s
@@ -170,11 +262,9 @@ int mg_write(struct mg_connection *, const void *buf, size_t len);
#define PRINTF_ARGS(x, y) #define PRINTF_ARGS(x, y)
#endif #endif
// Send data to the browser using printf() semantics. // Send data to the client 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.
// Below are the macros for enabling compiler-specific checks for
// printf-like arguments.
int mg_printf(struct mg_connection *, int mg_printf(struct mg_connection *,
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3); PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
@@ -184,6 +274,10 @@ void mg_send_file(struct mg_connection *conn, const char *path);
// Read data from the remote end, return number of bytes read. // Read data from the remote end, return number of bytes read.
// Return:
// 0 connection has been closed by peer. No more data could be read.
// < 0 read error. No more data could be read from the connection.
// > 0 number of bytes read into the buffer.
int mg_read(struct mg_connection *, void *buf, size_t len); int mg_read(struct mg_connection *, void *buf, size_t len);
@@ -209,7 +303,8 @@ const char *mg_get_header(const struct mg_connection *, const char *name);
// On success, length of the decoded variable. // On success, length of the decoded variable.
// On error: // On error:
// -1 (variable not found). // -1 (variable not found).
// -2 (destination buffer is NULL, zero length or too small to hold the decoded variable). // -2 (destination buffer is NULL, zero length or too small to hold the
// decoded variable).
// //
// Destination buffer is guaranteed to be '\0' - terminated if it is not // Destination buffer is guaranteed to be '\0' - terminated if it is not
// NULL or zero length. // NULL or zero length.
@@ -225,10 +320,12 @@ int mg_get_var(const char *data, size_t data_len,
// Return: // Return:
// On success, value length. // On success, value length.
// On error: // On error:
// -1 (either "Cookie:" header is not present at all or the requested parameter is not found). // -1 (either "Cookie:" header is not present at all or the requested
// -2 (destination buffer is NULL, zero length or too small to hold the value). // parameter is not found).
int mg_get_cookie(const struct mg_connection *, // -2 (destination buffer is NULL, zero length or too small to hold the
const char *cookie_name, char *buf, size_t buf_len); // value).
int mg_get_cookie(const char *cookie, const char *var_name,
char *buf, size_t buf_len);
// Download data from the remote web server. // Download data from the remote web server.
@@ -275,6 +372,14 @@ const char *mg_get_builtin_mime_type(const char *file_name);
// Return Mongoose version. // Return Mongoose version.
const char *mg_version(void); const char *mg_version(void);
// URL-decode input buffer into destination buffer.
// 0-terminate the destination buffer.
// form-url-encoded data differs from URI encoding in a way that it
// uses '+' as character for space, see RFC 1866 section 8.2.1
// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
// Return: length of the decoded data, or -1 if dst buffer is too small.
int mg_url_decode(const char *src, int src_len, char *dst,
int dst_len, int is_form_url_encoded);
// 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
@@ -282,7 +387,7 @@ const char *mg_version(void);
// 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[33], ...); char *mg_md5(char buf[33], ...);
#ifdef __cplusplus #ifdef __cplusplus
+3
View File
@@ -0,0 +1,3 @@
#!/usr/bin/env perl
print "Content-Type: text/plain\n\nhello\n";
+16 -11
View File
@@ -1,22 +1,25 @@
<? HTTP/1.0 200 OK
-- Lua server pages have full control over the output, including HTTP Content-Type: text/html
-- headers they send to the client. Send HTTP headers:
print('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') <html><body>
?><html><body>
<p>This is an example Lua server page served by <p>This is an example Lua server page served by
<a href="http://code.google.com/p/mongoose">Mongoose web server</a>. <a href="http://code.google.com/p/mongoose">Mongoose web server</a>.
Mongoose has Lua, Sqlite, and other functionality built in the binary. Mongoose has Lua, Sqlite, and other functionality built in the binary.
This example page stores the request in the Sqlite database, and shows This example page stores the request in the Sqlite database, and shows
all requests done previously.</p> all requests done previously.</p>
<p> Today is <? mg.write(os.date("%A")) ?>
<pre> <pre>
<? <?
-- for k,v in pairs(_G) do mg.write(k, '\n') end
-- Open database -- Open database
local db = sqlite3.open('requests.db') local db = sqlite3.open('requests.db')
-- Setup a trace callback, to show SQL statements we'll be executing. -- Setup a trace callback, to show SQL statements we'll be executing.
-- db:trace(function(data, sql) print('Executing: ' .. sql .. '\n') end, nil) -- db:trace(function(data, sql) mg.write('Executing: ', sql: '\n') end, nil)
-- Create a table if it is not created already -- Create a table if it is not created already
db:exec([[ db:exec([[
@@ -25,24 +28,26 @@ all requests done previously.</p>
timestamp NOT NULL, timestamp NOT NULL,
method NOT NULL, method NOT NULL,
uri NOT NULL, uri NOT NULL,
user_agent addr
); );
]]) ]])
-- Add entry about this request -- Add entry about this request
local stmt = db:prepare( local stmt = db:prepare(
'INSERT INTO requests VALUES(NULL, datetime("now"), ?, ?, ?);'); 'INSERT INTO requests VALUES(NULL, datetime("now"), ?, ?, ?);');
stmt:bind_values(request_info.request_method, request_info.uri, stmt:bind_values(mg.request_info.request_method,
request_info.http_headers['User-Agent']) mg.request_info.uri,
mg.request_info.remote_port)
stmt:step() stmt:step()
stmt:finalize() stmt:finalize()
-- Show all previous records -- Show all previous records
print('Previous requests:\n') mg.write('Previous requests:\n')
stmt = db:prepare('SELECT * FROM requests ORDER BY id DESC;') stmt = db:prepare('SELECT * FROM requests ORDER BY id DESC;')
while stmt:step() == sqlite3.ROW do while stmt:step() == sqlite3.ROW do
local v = stmt:get_values() local v = stmt:get_values()
print(v[1] .. ' ' .. v[2] .. ' ' .. v[3] .. ' ' mg.write(v[1] .. ' ' .. v[2] .. ' ' .. v[3] .. ' '
.. v[4] .. ' ' .. v[5] .. '\n') .. v[4] .. ' ' .. v[5] .. '\n')
end end
+1 -1
View File
@@ -1,5 +1,5 @@
<html><pre> <html><pre>
ssi_begin ssi_begin
<!--#include file="Makefile" --> <!--#include file="../build/Makefile" -->
ssi_end ssi_end
</pre></html> </pre></html>
+1 -1
View File
@@ -1,5 +1,5 @@
<html><pre> <html><pre>
ssi_begin ssi_begin
<!--#include file="/etc/passwd" --> <!--#include abspath="/etc/passwd" -->
ssi_end ssi_end
</pre></html> </pre></html>
+1 -1
View File
@@ -1,5 +1,5 @@
<html><pre> <html><pre>
ssi_begin ssi_begin
<!--#include file="c:\boot.ini" --> <!--#include abspath="c:\boot.ini" -->
ssi_end ssi_end
</pre></html> </pre></html>
+1 -1
View File
@@ -1,6 +1,6 @@
<html><pre> <html><pre>
ssi_begin ssi_begin
<!--#include "embed.c" --> <!--#include "unit_test.c" -->
ssi_end ssi_end
</pre></html> </pre></html>
+1 -1
View File
@@ -1,3 +1,3 @@
ssi_begin ssi_begin
<!--#include file="Makefile" --> <!--#include file="../build/Makefile" -->
ssi_end ssi_end
+29 -19
View File
@@ -4,6 +4,8 @@
use IO::Socket; use IO::Socket;
use File::Path; use File::Path;
use File::Basename;
use Cwd;
use strict; use strict;
use warnings; use warnings;
#use diagnostics; #use diagnostics;
@@ -16,12 +18,15 @@ my $num_requests;
my $dir_separator = on_windows() ? '\\' : '/'; my $dir_separator = on_windows() ? '\\' : '/';
my $copy_cmd = on_windows() ? 'copy' : 'cp'; my $copy_cmd = on_windows() ? 'copy' : 'cp';
my $test_dir_uri = "test_dir"; my $test_dir_uri = "test_dir";
my $root = 'test'; my $root = '../test';
my $test_dir = $root . $dir_separator. $test_dir_uri; my $abs_root = Cwd::abs_path(dirname($0) . $dir_separator . $root);
my $test_dir = $abs_root . $dir_separator. $test_dir_uri;
#print "$test_dir\n"; exit 0;
my $config = 'mongoose.conf'; my $config = 'mongoose.conf';
my $exe = '.' . $dir_separator . 'mongoose'; my $exe_ext = on_windows() ? '.exe' : '';
my $embed_exe = '.' . $dir_separator . 'embed'; my $mongoose_exe = '.' . $dir_separator . 'mongoose' . $exe_ext;
my $unit_test_exe = '.' . $dir_separator . 'unit_test'; my $embed_exe = '.' . $dir_separator . 'embed' . $exe_ext;
my $unit_test_exe = '.' . $dir_separator . 'unit_test' . $exe_ext;
my $exit_code = 0; my $exit_code = 0;
my @files_to_delete = ('debug.log', 'access.log', $config, "$root/a/put.txt", my @files_to_delete = ('debug.log', 'access.log', $config, "$root/a/put.txt",
@@ -51,9 +56,9 @@ sub get_num_of_log_entries {
# Send the request to the 127.0.0.1:$port and return the reply # Send the request to the 127.0.0.1:$port and return the reply
sub req { sub req {
my ($request, $inc, $timeout) = @_; my ($request, $inc, $timeout) = @_;
my $sock = IO::Socket::INET->new(Proto=>"tcp", my $sock = IO::Socket::INET->new(Proto => 6,
PeerAddr=>'127.0.0.1', PeerPort=>$port); PeerAddr => '127.0.0.1', PeerPort => $port);
fail("Cannot connect: $!") unless $sock; fail("Cannot connect to http://127.0.0.1:$port : $!") unless $sock;
$sock->autoflush(1); $sock->autoflush(1);
foreach my $byte (split //, $request) { foreach my $byte (split //, $request) {
last unless print $sock $byte; last unless print $sock $byte;
@@ -97,7 +102,6 @@ sub spawn {
if (on_windows()) { if (on_windows()) {
my @args = split /\s+/, $cmdline; my @args = split /\s+/, $cmdline;
my $executable = $args[0]; my $executable = $args[0];
$executable .= '.exe';
Win32::Spawn($executable, $cmdline, $pid); Win32::Spawn($executable, $cmdline, $pid);
die "Cannot spawn @_: $!" unless $pid; die "Cannot spawn @_: $!" unless $pid;
} else { } else {
@@ -154,23 +158,24 @@ if (scalar(@ARGV) > 0 and $ARGV[0] eq 'unit') {
# Make sure we load config file if no options are given. # Make sure we load config file if no options are given.
# Command line options override config files settings # Command line options override config files settings
write_file($config, "access_log_file access.log\n" . write_file($config, "access_log_file access.log\n" .
"document_root $root\n" .
"listening_ports 127.0.0.1:12345\n"); "listening_ports 127.0.0.1:12345\n");
spawn("$exe -p 127.0.0.1:$port"); spawn("$mongoose_exe -listening_ports 127.0.0.1:$port");
o("GET /test/hello.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'Loading config file'); o("GET /hello.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'Loading config file');
unlink $config; unlink $config;
kill_spawned_child(); kill_spawned_child();
# Spawn the server on port $port # Spawn the server on port $port
my $cmd = "$exe ". my $cmd = "$mongoose_exe ".
"-listening_ports 127.0.0.1:$port ". "-listening_ports 127.0.0.1:$port ".
"-access_log_file access.log ". "-access_log_file access.log ".
"-error_log_file debug.log ". "-error_log_file debug.log ".
"-cgi_environment CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " . "-cgi_environment CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
"-extra_mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " . "-extra_mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
'-put_delete_auth_file test/passfile ' . "-put_delete_auth_file $abs_root/passfile " .
'-access_control_list -0.0.0.0/0,+127.0.0.1 ' . '-access_control_list -0.0.0.0/0,+127.0.0.1 ' .
"-document_root $root ". "-document_root $root ".
"-hide_files_patterns **exploit.pl ". "-hide_files_patterns **exploit.PL ".
"-enable_keep_alive yes ". "-enable_keep_alive yes ".
"-url_rewrite_patterns /aiased=/etc/,/ta=$test_dir"; "-url_rewrite_patterns /aiased=/etc/,/ta=$test_dir";
$cmd .= ' -cgi_interpreter perl' if on_windows(); $cmd .= ' -cgi_interpreter perl' if on_windows();
@@ -243,8 +248,9 @@ write_file($path, read_file($root . $dir_separator . 'env.cgi'));
chmod(0755, $path); chmod(0755, $path);
o("GET /$test_dir_uri/x/ HTTP/1.0\n\n", "Content-Type: text/html\r\n\r\n", o("GET /$test_dir_uri/x/ HTTP/1.0\n\n", "Content-Type: text/html\r\n\r\n",
'index.cgi execution'); 'index.cgi execution');
o("GET /$test_dir_uri/x/ HTTP/1.0\n\n", o("GET /$test_dir_uri/x/ HTTP/1.0\n\n",
"SCRIPT_FILENAME=test/test_dir/x/index.cgi", 'SCRIPT_FILENAME'); "SCRIPT_FILENAME=$test_dir/x/index.cgi", 'SCRIPT_FILENAME');
o("GET /ta/x/ HTTP/1.0\n\n", "SCRIPT_NAME=/ta/x/index.cgi", o("GET /ta/x/ HTTP/1.0\n\n", "SCRIPT_NAME=/ta/x/index.cgi",
'Aliases SCRIPT_NAME'); 'Aliases SCRIPT_NAME');
o("GET /hello.txt HTTP/1.1\nConnection: close\n\n", 'Connection: close', o("GET /hello.txt HTTP/1.1\nConnection: close\n\n", 'Connection: close',
@@ -352,6 +358,8 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
unlink "$root/.htpasswd"; unlink "$root/.htpasswd";
o("GET /dir%20with%20spaces/hello.cgi HTTP/1.0\n\r\n",
'HTTP/1.1 200 OK.+hello', 'CGI script with spaces in path');
o("GET /env.cgi HTTP/1.0\n\r\n", 'HTTP/1.1 200 OK', 'GET CGI file'); o("GET /env.cgi HTTP/1.0\n\r\n", 'HTTP/1.1 200 OK', 'GET CGI file');
o("GET /bad2.cgi HTTP/1.0\n\n", "HTTP/1.1 123 Please pass me to the client\r", o("GET /bad2.cgi HTTP/1.0\n\n", "HTTP/1.1 123 Please pass me to the client\r",
'CGI Status code text'); 'CGI Status code text');
@@ -382,6 +390,8 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
o("GET /env.cgi HTTP/1.0\n\r\n", '\nCGI_BAZ=baz\n', '-cgi_env 3'); o("GET /env.cgi HTTP/1.0\n\r\n", '\nCGI_BAZ=baz\n', '-cgi_env 3');
o("GET /env.cgi/a/b/98 HTTP/1.0\n\r\n", 'PATH_INFO=/a/b/98\n', 'PATH_INFO'); o("GET /env.cgi/a/b/98 HTTP/1.0\n\r\n", 'PATH_INFO=/a/b/98\n', 'PATH_INFO');
o("GET /env.cgi/a/b/9 HTTP/1.0\n\r\n", 'PATH_INFO=/a/b/9\n', 'PATH_INFO'); o("GET /env.cgi/a/b/9 HTTP/1.0\n\r\n", 'PATH_INFO=/a/b/9\n', 'PATH_INFO');
o("GET /env.cgi/foo/bar?a=b HTTP/1.0\n\n",
'SCRIPT_NAME=/env.cgi\s', 'SCRIPT_NAME for CGI with PATH_INFO');
# Check that CGI's current directory is set to script's directory # Check that CGI's current directory is set to script's directory
my $copy_cmd = on_windows() ? 'copy' : 'cp'; my $copy_cmd = on_windows() ? 'copy' : 'cp';
@@ -401,7 +411,7 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
my $abs_path = on_windows() ? 'ssi6.shtml' : 'ssi5.shtml'; my $abs_path = on_windows() ? 'ssi6.shtml' : 'ssi5.shtml';
my $word = on_windows() ? 'boot loader' : 'root'; my $word = on_windows() ? 'boot loader' : 'root';
o("GET /$abs_path HTTP/1.0\n\n", o("GET /$abs_path HTTP/1.0\n\n",
"ssi_begin.+$word.+ssi_end", 'SSI #include file= (absolute)'); "ssi_begin.+$word.+ssi_end", 'SSI #include abspath');
o("GET /ssi7.shtml HTTP/1.0\n\n", o("GET /ssi7.shtml HTTP/1.0\n\n",
'ssi_begin.+Unit test.+ssi_end', 'SSI #include "..."'); 'ssi_begin.+Unit test.+ssi_end', 'SSI #include "..."');
o("GET /ssi8.shtml HTTP/1.0\n\n", o("GET /ssi8.shtml HTTP/1.0\n\n",
@@ -410,9 +420,9 @@ unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
# Manipulate the passwords file # Manipulate the passwords file
my $path = 'test_htpasswd'; my $path = 'test_htpasswd';
unlink $path; unlink $path;
system("$exe -A $path a b c") == 0 system("$mongoose_exe -A $path a b c") == 0
or fail("Cannot add user in a passwd file"); or fail("Cannot add user in a passwd file");
system("$exe -A $path a b c2") == 0 system("$mongoose_exe -A $path a b c2") == 0
or fail("Cannot edit user in a passwd file"); or fail("Cannot edit user in a passwd file");
my $content = read_file($path); my $content = read_file($path);
$content =~ /^b:a:\w+$/gs or fail("Bad content of the passwd file"); $content =~ /^b:a:\w+$/gs or fail("Bad content of the passwd file");
@@ -450,7 +460,7 @@ sub do_PUT_test {
} }
sub do_unit_test { sub do_unit_test {
my $target = on_windows() ? 'w' : 'u'; my $target = on_windows() ? 'wi' : 'un';
system("make $target") == 0 or fail("Unit test failed!"); system("make $target") == 0 or fail("Unit test failed!");
} }
+223 -37
View File
@@ -22,13 +22,28 @@
#define USE_WEBSOCKET #define USE_WEBSOCKET
#define USE_LUA #define USE_LUA
#ifndef _WIN32
#define __cdecl
#define USE_IPV6
#endif
// USE_* definitions must be made before #include "mongoose.c" !
#include "mongoose.c" #include "mongoose.c"
#define FATAL(str, line) do { \ static int s_total_tests = 0;
static int s_failed_tests = 0;
#define FAIL(str, line) do { \
printf("Fail on line %d: [%s]\n", line, str); \ printf("Fail on line %d: [%s]\n", line, str); \
abort(); \ s_failed_tests++; \
} while (0)
#define ASSERT(expr) do { \
s_total_tests++; \
if (!(expr)) FAIL(#expr, __LINE__); \
} while (0) } while (0)
#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
#define HTTP_PORT "56789" #define HTTP_PORT "56789"
#define HTTPS_PORT "56790" #define HTTPS_PORT "56790"
@@ -38,10 +53,6 @@
",127.0.0.1:" HTTPS_PORT "s" \ ",127.0.0.1:" HTTPS_PORT "s" \
",127.0.0.1:" HTTP_PORT2 ",127.0.0.1:" HTTP_PORT2
#ifndef _WIN32
#define __cdecl
#endif
static void test_parse_http_message() { static void test_parse_http_message() {
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";
@@ -52,6 +63,10 @@ static void test_parse_http_message() {
char req6[] = "G"; char req6[] = "G";
char req7[] = " blah "; char req7[] = " blah ";
char req8[] = " HTTP/1.1 200 OK \n\n"; char req8[] = " HTTP/1.1 200 OK \n\n";
char req9[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
ASSERT(parse_http_message(req9, sizeof(req9), &ri) == sizeof(req9) - 1);
ASSERT(ri.num_headers == 1);
ASSERT(parse_http_message(req1, sizeof(req1), &ri) == sizeof(req1) - 1); ASSERT(parse_http_message(req1, sizeof(req1), &ri) == sizeof(req1) - 1);
ASSERT(strcmp(ri.http_version, "1.1") == 0); ASSERT(strcmp(ri.http_version, "1.1") == 0);
@@ -147,7 +162,8 @@ static void test_match_prefix(void) {
ASSERT(match_prefix("*", 1, "/hello/") == 0); ASSERT(match_prefix("*", 1, "/hello/") == 0);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1); ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6); ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.a") == 6); ASSERT(match_prefix("**.a$|**.b$", 11, "/a/B.A") == 6);
ASSERT(match_prefix("**o$", 4, "HELLO") == 5);
} }
static void test_remove_double_dots() { static void test_remove_double_dots() {
@@ -187,6 +203,7 @@ static char *read_file(const char *path, int *size) {
static const char *fetch_data = "hello world!\n"; static const char *fetch_data = "hello world!\n";
static const char *inmemory_file_data = "hi there"; static const char *inmemory_file_data = "hi there";
static const char *upload_filename = "upload_test.txt"; static const char *upload_filename = "upload_test.txt";
static const char *upload_filename2 = "upload_test2.txt";
static const char *upload_ok_message = "upload successful"; static const char *upload_ok_message = "upload successful";
static const char *open_file_cb(const struct mg_connection *conn, static const char *open_file_cb(const struct mg_connection *conn,
@@ -200,16 +217,39 @@ static const char *open_file_cb(const struct mg_connection *conn,
} }
static void upload_cb(struct mg_connection *conn, const char *path) { static void upload_cb(struct mg_connection *conn, const char *path) {
const struct mg_request_info *ri = mg_get_request_info(conn);
char *p1, *p2; char *p1, *p2;
int len1, len2; int len1, len2;
ASSERT(!strcmp(path, "./upload_test.txt")); if (atoi(ri->query_string) == 1) {
ASSERT((p1 = read_file("mongoose.c", &len1)) != NULL); ASSERT(!strcmp(path, "./upload_test.txt"));
ASSERT((p2 = read_file(path, &len2)) != NULL); ASSERT((p1 = read_file("main.c", &len1)) != NULL);
ASSERT(len1 == len2); ASSERT((p2 = read_file(path, &len2)) != NULL);
ASSERT(memcmp(p1, p2, len1) == 0); ASSERT(len1 == len2);
free(p1), free(p2); ASSERT(memcmp(p1, p2, len1) == 0);
remove(upload_filename); free(p1), free(p2);
remove(upload_filename);
} else if (atoi(ri->query_string) == 2) {
if (!strcmp(path, "./upload_test.txt")) {
ASSERT((p1 = read_file("lua_5.2.1.h", &len1)) != NULL);
ASSERT((p2 = read_file(path, &len2)) != NULL);
ASSERT(len1 == len2);
ASSERT(memcmp(p1, p2, len1) == 0);
free(p1), free(p2);
remove(upload_filename);
} else if (!strcmp(path, "./upload_test2.txt")) {
ASSERT((p1 = read_file("mod_lua.c", &len1)) != NULL);
ASSERT((p2 = read_file(path, &len2)) != NULL);
ASSERT(len1 == len2);
ASSERT(memcmp(p1, p2, len1) == 0);
free(p1), free(p2);
remove(upload_filename);
} else {
ASSERT(0);
}
} else {
ASSERT(0);
}
mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s", mg_printf(conn, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\n\r\n%s",
(int) strlen(upload_ok_message), upload_ok_message); (int) strlen(upload_ok_message), upload_ok_message);
@@ -220,14 +260,15 @@ static int begin_request_handler_cb(struct mg_connection *conn) {
if (!strcmp(ri->uri, "/data")) { if (!strcmp(ri->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-Type: text/plain\r\n\r\n" "Content-Type: text/plain\r\n\r\n"
"%s", (int) strlen(fetch_data), fetch_data); "%s", fetch_data);
close_connection(conn);
return 1; return 1;
} }
if (!strcmp(ri->uri, "/upload")) { if (!strcmp(ri->uri, "/upload")) {
ASSERT(mg_upload(conn, ".") == 1); ASSERT(ri->query_string != NULL);
ASSERT(mg_upload(conn, ".") == atoi(ri->query_string));
} }
return 0; return 0;
@@ -241,13 +282,14 @@ static int log_message_cb(const struct mg_connection *conn, const char *msg) {
static const struct mg_callbacks CALLBACKS = { static const struct mg_callbacks CALLBACKS = {
&begin_request_handler_cb, NULL, &log_message_cb, NULL, NULL, NULL, NULL, &begin_request_handler_cb, NULL, &log_message_cb, NULL, NULL, NULL, NULL,
&open_file_cb, NULL, &upload_cb &open_file_cb, NULL, &upload_cb, NULL, NULL
}; };
static const char *OPTIONS[] = { static const char *OPTIONS[] = {
"document_root", ".", "document_root", ".",
"listening_ports", LISTENING_ADDR, "listening_ports", LISTENING_ADDR,
"ssl_certificate", "build/ssl_cert.pem", "enable_keep_alive", "yes",
"ssl_certificate", "ssl_cert.pem",
NULL, NULL,
}; };
@@ -286,17 +328,18 @@ static void test_mg_download(void) {
"GET / HTTP/1.0\r\n\r\n")) != NULL); "GET / HTTP/1.0\r\n\r\n")) != NULL);
mg_close_connection(conn); mg_close_connection(conn);
// Fetch mongoose.c, should succeed // Fetch main.c, should succeed
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
"GET /mongoose.c HTTP/1.0\r\n\r\n")) != NULL); "GET /main.c HTTP/1.0\r\n\r\n")) != NULL);
ASSERT(!strcmp(conn->request_info.uri, "200")); ASSERT(!strcmp(conn->request_info.uri, "200"));
ASSERT((p1 = read_conn(conn, &len1)) != NULL); ASSERT((p1 = read_conn(conn, &len1)) != NULL);
ASSERT((p2 = read_file("mongoose.c", &len2)) != NULL); ASSERT((p2 = read_file("main.c", &len2)) != NULL);
ASSERT(len1 == len2); ASSERT(len1 == len2);
ASSERT(memcmp(p1, p2, len1) == 0); ASSERT(memcmp(p1, p2, len1) == 0);
free(p1), free(p2); free(p1), free(p2);
mg_close_connection(conn); mg_close_connection(conn);
// Fetch in-memory file, should succeed. // Fetch in-memory file, should succeed.
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s", ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
"GET /blah HTTP/1.1\r\n\r\n")) != NULL); "GET /blah HTTP/1.1\r\n\r\n")) != NULL);
@@ -306,6 +349,15 @@ static void test_mg_download(void) {
free(p1); free(p1);
mg_close_connection(conn); mg_close_connection(conn);
// Fetch in-memory data with no Content-Length, should succeed.
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
"GET /data HTTP/1.1\r\n\r\n")) != NULL);
ASSERT((p1 = read_conn(conn, &len1)) != NULL);
ASSERT(len1 == (int) strlen(fetch_data));
ASSERT(memcmp(p1, fetch_data, len1) == 0);
free(p1);
mg_close_connection(conn);
// Test SSL redirect, IP address // Test SSL redirect, IP address
ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0, ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0,
ebuf, sizeof(ebuf), "%s", ebuf, sizeof(ebuf), "%s",
@@ -337,24 +389,27 @@ static void test_mg_upload(void) {
static const char *boundary = "OOO___MY_BOUNDARY___OOO"; static const char *boundary = "OOO___MY_BOUNDARY___OOO";
struct mg_context *ctx; struct mg_context *ctx;
struct mg_connection *conn; struct mg_connection *conn;
char ebuf[100], buf[20], *file_data, *post_data = NULL; char ebuf[100], buf[20], *file_data, *file2_data, *post_data;
int file_len, post_data_len; int file_len, file2_len, post_data_len;
ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL); ASSERT((ctx = mg_start(&CALLBACKS, NULL, OPTIONS)) != NULL);
ASSERT((file_data = read_file("mongoose.c", &file_len)) != NULL);
// Upload one file
ASSERT((file_data = read_file("main.c", &file_len)) != NULL);
post_data = NULL;
post_data_len = alloc_printf(&post_data, 0, post_data_len = alloc_printf(&post_data, 0,
"--%s\r\n" "--%s\r\n"
"Content-Disposition: form-data; " "Content-Disposition: form-data; "
"name=\"file\"; " "name=\"file\"; "
"filename=\"%s\"\r\n\r\n" "filename=\"%s\"\r\n\r\n"
"%.*s\r\n" "%.*s\r\n"
"--%s\r\n", "--%s--\r\n",
boundary, upload_filename, boundary, upload_filename,
file_len, file_data, boundary); file_len, file_data, boundary);
ASSERT(post_data_len > 0); ASSERT(post_data_len > 0);
ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1, ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1,
ebuf, sizeof(ebuf), ebuf, sizeof(ebuf),
"POST /upload HTTP/1.1\r\n" "POST /upload?1 HTTP/1.1\r\n"
"Content-Length: %d\r\n" "Content-Length: %d\r\n"
"Content-Type: multipart/form-data; " "Content-Type: multipart/form-data; "
"boundary=%s\r\n\r\n" "boundary=%s\r\n\r\n"
@@ -364,6 +419,47 @@ static void test_mg_upload(void) {
ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message)); ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message));
ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0); ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0);
mg_close_connection(conn); mg_close_connection(conn);
// Upload two files
ASSERT((file_data = read_file("lua_5.2.1.h", &file_len)) != NULL);
ASSERT((file2_data = read_file("mod_lua.c", &file2_len)) != NULL);
post_data = NULL;
post_data_len = alloc_printf(&post_data, 0,
// First file
"--%s\r\n"
"Content-Disposition: form-data; "
"name=\"file\"; "
"filename=\"%s\"\r\n\r\n"
"%.*s\r\n"
// Second file
"--%s\r\n"
"Content-Disposition: form-data; "
"name=\"file\"; "
"filename=\"%s\"\r\n\r\n"
"%.*s\r\n"
// Final boundary
"--%s--\r\n",
boundary, upload_filename,
file_len, file_data,
boundary, upload_filename2,
file2_len, file2_data,
boundary);
ASSERT(post_data_len > 0);
ASSERT((conn = mg_download("localhost", atoi(HTTPS_PORT), 1,
ebuf, sizeof(ebuf),
"POST /upload?2 HTTP/1.1\r\n"
"Content-Length: %d\r\n"
"Content-Type: multipart/form-data; "
"boundary=%s\r\n\r\n"
"%.*s", post_data_len, boundary,
post_data_len, post_data)) != NULL);
free(file_data), free(file2_data), free(post_data);
ASSERT(mg_read(conn, buf, sizeof(buf)) == (int) strlen(upload_ok_message));
ASSERT(memcmp(buf, upload_ok_message, strlen(upload_ok_message)) == 0);
mg_close_connection(conn);
mg_stop(ctx); mg_stop(ctx);
} }
@@ -466,13 +562,13 @@ static void test_lua(void) {
ASSERT(lua_gettop(L) == 0); ASSERT(lua_gettop(L) == 0);
check_lua_expr(L, "'hi'", "hi"); check_lua_expr(L, "'hi'", "hi");
check_lua_expr(L, "request_info.request_method", "POST"); check_lua_expr(L, "mg.request_info.request_method", "POST");
check_lua_expr(L, "request_info.uri", "/foo/bar"); check_lua_expr(L, "mg.request_info.uri", "/foo/bar");
check_lua_expr(L, "request_info.num_headers", "2"); check_lua_expr(L, "mg.request_info.num_headers", "2");
check_lua_expr(L, "request_info.remote_ip", "0"); check_lua_expr(L, "mg.request_info.remote_ip", "0");
check_lua_expr(L, "request_info.http_headers['Content-Length']", "12"); check_lua_expr(L, "mg.request_info.http_headers['Content-Length']", "12");
check_lua_expr(L, "request_info.http_headers['Connection']", "close"); check_lua_expr(L, "mg.request_info.http_headers['Connection']", "close");
(void) luaL_dostring(L, "post = read()"); (void) luaL_dostring(L, "post = mg.read()");
check_lua_expr(L, "# post", "12"); check_lua_expr(L, "# post", "12");
check_lua_expr(L, "post", "hello world!"); check_lua_expr(L, "post", "hello world!");
lua_close(L); lua_close(L);
@@ -576,7 +672,93 @@ static void test_api_calls(void) {
mg_stop(ctx); mg_stop(ctx);
} }
static void test_url_decode(void) {
char buf[100];
ASSERT(mg_url_decode("foo", 3, buf, 3, 0) == -1); // No space for \0
ASSERT(mg_url_decode("foo", 3, buf, 4, 0) == 3);
ASSERT(strcmp(buf, "foo") == 0);
ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 0) == 2);
ASSERT(strcmp(buf, "a+") == 0);
ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "a ") == 0);
ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
ASSERT(strcmp(buf, "%") == 0);
ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "%6") == 0);
ASSERT(mg_url_decode("%61", 3, buf, sizeof(buf), 1) == 1);
ASSERT(strcmp(buf, "a") == 0);
}
static void test_mg_strcasestr(void) {
static const char *big1 = "abcdef";
ASSERT(mg_strcasestr("Y", "X") == NULL);
ASSERT(mg_strcasestr("Y", "y") != NULL);
ASSERT(mg_strcasestr(big1, "X") == NULL);
ASSERT(mg_strcasestr(big1, "CD") == big1 + 2);
ASSERT(mg_strcasestr("aa", "AAB") == NULL);
}
static void test_mg_get_cookie(void) {
char buf[20];
ASSERT(mg_get_cookie("", "foo", NULL, sizeof(buf)) == -2);
ASSERT(mg_get_cookie("", "foo", buf, 0) == -2);
ASSERT(mg_get_cookie("", "foo", buf, sizeof(buf)) == -1);
ASSERT(mg_get_cookie("", NULL, buf, sizeof(buf)) == -1);
ASSERT(mg_get_cookie("a=1; b=2; c; d", "a", buf, sizeof(buf)) == 1);
ASSERT(strcmp(buf, "1") == 0);
ASSERT(mg_get_cookie("a=1; b=2; c; d", "b", buf, sizeof(buf)) == 1);
ASSERT(strcmp(buf, "2") == 0);
ASSERT(mg_get_cookie("a=1; b=123", "b", buf, sizeof(buf)) == 3);
ASSERT(strcmp(buf, "123") == 0);
ASSERT(mg_get_cookie("a=1; b=2; c; d", "c", buf, sizeof(buf)) == -1);
}
static void test_strtoll(void) {
ASSERT(strtoll("0", NULL, 10) == 0);
ASSERT(strtoll("123", NULL, 10) == 123);
ASSERT(strtoll("-34", NULL, 10) == -34);
ASSERT(strtoll("3566626116", NULL, 10) == 3566626116);
}
static void test_parse_port_string(void) {
static const char *valid[] = {
"1", "1s", "1r", "1.2.3.4:1", "1.2.3.4:1s", "1.2.3.4:1r",
#if defined(USE_IPV6)
"[::1]:123", "[3ffe:2a00:100:7031::1]:900",
#endif
NULL
};
static const char *invalid[] = {
"0", "99999", "1k", "1.2.3", "1.2.3.4:", "1.2.3.4:2p",
NULL
};
struct socket so;
struct vec vec;
int i;
for (i = 0; valid[i] != NULL; i++) {
vec.ptr = valid[i];
vec.len = strlen(vec.ptr);
ASSERT(parse_port_string(&vec, &so) != 0);
}
for (i = 0; invalid[i] != NULL; i++) {
vec.ptr = invalid[i];
vec.len = strlen(vec.ptr);
ASSERT(parse_port_string(&vec, &so) == 0);
}
}
int __cdecl main(void) { int __cdecl main(void) {
test_parse_port_string();
test_mg_strcasestr();
test_alloc_vprintf(); test_alloc_vprintf();
test_base64_encode(); test_base64_encode();
test_match_prefix(); test_match_prefix();
@@ -592,10 +774,14 @@ int __cdecl main(void) {
test_mg_upload(); test_mg_upload();
test_request_replies(); test_request_replies();
test_api_calls(); test_api_calls();
test_url_decode();
test_mg_get_cookie();
test_strtoll();
#ifdef USE_LUA #ifdef USE_LUA
test_lua(); test_lua();
#endif #endif
printf("%s\n", "PASSED"); printf("TOTAL TESTS: %d, FAILED: %d\n", s_total_tests, s_failed_tests);
return 0;
return s_failed_tests == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
} }