Compare commits

...
91 Commits
Author SHA1 Message Date
Sergey Lyubka 409c12a851 Better logic for port resolving 2015-03-18 17:25:46 +00:00
Sergey Lyubka bcdcbf20ee Release 5.6 2015-03-18 17:25:31 +00:00
Sergey Lyubka 8fc5b5a55f Add contribution section to readme 2015-03-18 15:45:52 +00:00
Sergey Lyubka faeedb2930 Sync main 2015-03-18 09:37:52 +00:00
Sergey Lyubka c8e8f94ffe Sync main 2015-03-17 17:35:31 +00:00
Sergey Lyubka 22aeb6111b Update ReleaseNotes 2015-03-17 17:01:16 +00:00
Sergey Lyubka 2d1d2e6534 SIZE_MAX is not defined on MSVC6, use (size_t) ~0 2015-03-17 17:00:59 +00:00
Sergey Lyubka 05c88a98fc Introduce -dav_root option 2015-03-17 15:34:56 +00:00
Marko Mikulicic 5224afb946 Merge pull request #485 from dsrosario/fix_remove_double_dots 2015-03-17 16:07:46 +01:00
Dinis Rosário 3bd79c7cd5 Fix remove_double_dots_and_double_slashes removing all the dots leading http server to serve wrong URI
If the uri is something like '/js/...jquery.js', remove_double_dots_and_double_slashes will remove the 3 dots and the http server will serves the /js/jquery.js file.
remove_double_dots_and_double_slashes should check if a dot or double dots is followed by a slash (or backslash) and only remove this to avoid disclosure attack.
2015-03-17 16:04:59 +01:00
Sergey Lyubka c52e0744cb Squashed warnings after size_t change 2015-03-17 13:18:15 +00:00
Sergey Lyubka 6c09c303d0 Merge pull request #456 from sebgod/fix-win32-examples-using-extra
Enable building of example/Makefile on Win32
2015-03-17 11:45:36 +00:00
Sergey Lyubka b6fde06990 Merge pull request #486 from mmicko/master
Compile fix
2015-03-16 16:52:48 +00:00
Miodrag Milanovic af892c9726 compile fix for visual studio 2015-03-14 09:02:25 +01:00
Miodrag Milanovic df7ad13680 Compile fix 2015-03-13 20:15:19 +01:00
Sergey Lyubka 057c2d4b42 Merge pull request #484 from davidmilligan/master
fix compiler warnings for 64 bit compilation
2015-03-10 18:40:16 +00:00
David Milligan 6c9b43bcf5 fix compiler warnings for 64 bit compilation 2015-03-09 20:01:09 -04:00
Sergey Lyubka a91438acae Fix #477 2015-03-09 16:09:05 +00:00
Sergey Lyubka a6fa51dbc2 Merge pull request #481 from cesanta/web_server_ssl
web_server_ssl
2015-03-06 14:39:50 +00:00
Alexander Alashkin 6ceac6c84c web_server_ssl 2015-03-06 15:08:57 +02:00
Sergey Lyubka 288efe3c23 Add -DMONGOOSE_ENABLE_THREADS to other examples 2015-03-06 09:29:56 +00:00
Sergey Lyubka 5207545a8b Add -DMONGOOSE_ENABLE_THREADS to proxy server example 2015-03-06 09:28:27 +00:00
Sergey Lyubka 716d524f9b Add -DMONGOOSE_ENABLE_THREADS to Makefile 2015-03-06 09:25:30 +00:00
Sergey Lyubka a434bab767 Merge pull request #480 from cesanta/polarssl_examples_1
websocket_ssl_proxy sample for polarsll
2015-03-06 09:03:38 +00:00
Alexander Alashkin e9633a8d2d websocket_ssl_proxy 2015-03-06 09:32:08 +02:00
Sergey Lyubka c7b6a6f0ea Added mg_websocket_printf() 2015-03-05 10:54:51 +00:00
Sergey Lyubka 6cdb9f7ed3 Merge pull request #474 from mmicko/master
OS/2 patches by KO Myung-Hun
2015-03-04 17:18:16 +00:00
Sergey Lyubka 4502dd0c86 s/MONGOOSE_NO_THREADS/MONGOOSE_ENABLE_THREADS 2015-03-03 18:59:23 +00:00
Sergey Lyubka 95055f6048 Add winsock2.h include for win32 2015-03-03 18:32:14 +00:00
Sergey Lyubka 2c36532ec4 Merge pull request #465 from doug16rogers/vs9-compile-ipv6
Allow for compilation in Visual Studio with NS_ENABLE_IPV6.
2015-03-03 18:28:07 +00:00
Sergey Lyubka f2b0b9c737 Fix Win32 build in mg_websocket_write() 2015-02-24 13:32:22 +00:00
Sergey Lyubka b3866439a0 Fix mg_create_server() signature 2015-02-24 13:17:11 +00:00
Miodrag Milanovic 4f2205a667 OS/2 patches by KO Myung-Hun
Upstream patch from MAME project
2015-02-24 11:12:09 +01:00
Sergey Lyubka 6cec1d36a8 Merge pull request #463 from CurlyMoo/patch-1
Replace obsolete gethostbyname by getaddrinfo
2015-02-19 11:48:35 +00:00
CurlyMoo 4238370ae1 Check for getaddrinfo availability. 2015-02-19 12:09:34 +01:00
Sergey Lyubka b4924b715e Merge pull request #473 from mmicko/master
Fix for MINGW builds
2015-02-17 16:19:37 +00:00
Miodrag Milanovic 7a0385dcac Fix for MINGW builds 2015-02-17 11:08:23 +01:00
Sergey Lyubka 44a146faf6 SSL fixes 2015-02-16 18:34:07 +00:00
Sergey Lyubka 53a55da7bc Add type cast in ns_out() 2015-02-16 18:19:15 +00:00
Sergey Lyubka bf44277764 Define _XOPEN_SOURCE for MinGW build 2015-02-16 18:17:30 +00:00
Sergey Lyubka a2e1da6e30 Add overflow checks 2015-02-12 19:12:58 +00:00
Sergey Lyubka bef3f85ba8 Merge pull request #466 from 0-wiz-0/master
Only define _XOPEN_SOURCE on Linux.
2015-02-10 18:07:07 +00:00
Thomas Klausner eb72a63cca Only define _XOPEN_SOURCE on Linux.
Fixes the build on NetBSD.

The comment says it's only needed on Linux, and AFAIK Linux
is the only operating system that only adds symbols when it's defined;
others, like NetBSD or Solaris, also hide symbols.

Signed-off-by: Thomas Klausner <wiz@NetBSD.org>
2015-01-29 15:02:26 +01:00
Doug Rogers f19bbc73cc Allow for compilation in Visual Studio 9 (2008) with NS_ENABLE_IPV6. 2015-01-29 00:12:35 -05:00
Sergey Lyubka 25326b3b12 net skeleton -> fossa 2015-01-28 12:33:48 +00:00
CurlyMoo 10ee430bfd Add debug line and adapt to styling guide
Replaced tabs with spaces.
2015-01-27 22:55:13 +01:00
CurlyMoo 10d0bfdab4 Replace obsolete gethostbyname by getaddrinfo
This also protect against the latest glibc bug
2015-01-27 22:45:34 +01:00
Sergey Lyubka 6b6637c337 Adopt SSL guide to current way of setting SSL cert. 2015-01-21 17:41:45 +00:00
Sergey Lyubka 878acca213 Removed Lua docs 2015-01-21 17:30:30 +00:00
Sergey Lyubka ace9285966 Updated years 2015-01-19 18:25:14 +00:00
Sergey Lyubka cdc167b0cc Merge pull request #459 from joshcriz/patch-1
Update Makefile
2015-01-19 16:32:24 +00:00
Josh Criz a0dd396b95 Update Makefile
Fixing typo in 'clean' section
2015-01-16 17:59:08 -06:00
Sebastian Godelet 8082501b9c Enable building of example/Makefile on Win32
Adding example/.gitignore to ignore *.exe
Appending -lws2_32 at the end of CFLAGS_EXTRA if running make on
Windows to enable easy compiling under that platform.
Obsoletes pull request #454
2015-01-10 16:41:58 +08:00
Sergey Lyubka e4ad3010be Fix #416 2014-12-30 03:56:29 +00:00
Sergey Lyubka 03a82ef848 Merge pull request #452 from CurlyMoo/patch-2
Typo
2014-12-27 18:25:09 +00:00
CurlyMoo 9459d69dcc Typo 2014-12-27 18:35:09 +01:00
Sergey Lyubka b28662362d Merge pull request #449 from ursine/patch-1
64-bit length fields on ARM don't work
2014-12-21 20:54:52 +00:00
Sergey Lyubka 66450bf3d1 Merge pull request #450 from sebgod/master
mongoose.c: using application/javascript for .js
2014-12-21 16:07:12 +00:00
Sebastian Godelet 478ca05e7a mongoose.c: using application/javascript for .js
As of http://www.rfc-editor.org/rfc/rfc4329.txt, the preferred MIME type
for JavaScript is application/javascript.
2014-12-21 22:16:05 +08:00
Gary Coulbourne 8cad0a72f9 64-bit length fields on ARM don't work
ARM only allows aligned accesses.  GCC generated unaligned accesses for the copy buffer, but ARM forces alignment, causing the first two bytes to be trampled.  I changed the mechanism to create two temporaries and memcpy them in.  It now works on ARM (and x86) for large websocket chunks.
2014-12-17 19:14:30 -05:00
Sergey Lyubka 31178f4d48 Typo fixed in the comment 2014-12-15 12:03:50 +00:00
Sergey Lyubka 7a5485493e Added md5 copyright 2014-12-11 18:01:58 +00:00
Sergey Lyubka d3cbb160f5 Removed travis config file 2014-12-01 11:33:16 +00:00
Sergey Lyubka 45ff2c2c19 Removed $Date$ marker 2014-11-28 14:16:49 +00:00
Sergey Lyubka c3db7b141b Removed $Date$ from header 2014-11-28 12:21:36 +00:00
Sergey Lyubka 0a0ea36ace Fix examples/proxy_server build 2014-11-24 19:33:24 +00:00
Sergey Lyubka 72ed954721 Merge pull request #440 from zapline/patch-1
Update ReleaseNotes.md(spell mistake)
2014-11-20 07:35:24 +00:00
zapline 33e035273a Update ReleaseNotes.md
spell mistake
2014-11-20 09:58:29 +08:00
Sergey Lyubka 223f36c130 Updated Readme 2014-11-17 15:50:02 +00:00
Sergey Lyubka 4c0bc5bd03 Updated Readme 2014-11-17 15:49:37 +00:00
Sergey Lyubka 808a5f6f53 Update README.md 2014-11-13 13:48:43 +00:00
Sergey Lyubka 404e635665 Fixed Android build 2014-11-12 22:16:32 +00:00
Sergey Lyubka 9d7a60a63f Merge pull request #433 from jhnwkmn/malloc
Consistent use of NS_MALLOC, NS_FREE and NS_REALLOC
2014-11-10 10:35:07 +00:00
Johan Wikman ba9c74187b Consistent use of NS_MALLOC, NS_FREE and NS_REALLOC
malloc(), free() and realloc() were used in a number of places.
Added NS_CALLOC as well.
2014-11-10 08:29:19 +02:00
Sergey Lyubka e9d4847cbb Merge pull request #432 from jhnwkmn/o_binary
O_BINARY might be defined.
2014-11-09 10:06:16 +00:00
Sergey Lyubka ea76de07ee Merge pull request #436 from jhnwkmn/no-cgi
MONGOOSE_NO_CGI needs special handling.
2014-11-09 10:04:54 +00:00
Sergey Lyubka 5a8c468ff7 Merge pull request #435 from jhnwkmn/size-macros
Added size macros.
2014-11-09 10:01:59 +00:00
Sergey Lyubka 5b143a6237 Merge pull request #434 from jhnwkmn/no-user
Added MONGOOSE_NO_USER configuration define.
2014-11-09 09:56:31 +00:00
Sergey Lyubka d244a7fdfd Merge pull request #437 from jhnwkmn/nsf-close-immediately
If socket is about to be closed do not add to [read|write]_set.
2014-11-09 09:55:13 +00:00
Johan Wikman 300a27de99 If socket is about to be closed do not add to [read|write]_set.
If NSG_CLOSE_IMMEDIATELY is on, then the socket will be closed,
which means that (if the socket was added to either read_set or
write_set) the subsequent select will in turn be performed on a
socket that has been closed.

Standard socket implementations seem to ignore a descriptor
referring to a closed socket but LWIP
(http://savannah.nongnu.org/projects/lwip/) crashes. So better
not to add to the sets.
2014-11-07 15:48:23 +02:00
Johan Wikman 04a15a0c10 MONGOOSE_NO_CGI needs special handling.
MONGOOSE_NO_CGI is implied by both NS_DISABLE_SOCKETPAIR and
MONGOOSE_NO_FILESYSTEM. Thus, so as not to get complaints about
the same define being defined twice, some extra checks are needed.
2014-11-07 15:29:25 +02:00
Johan Wikman f0f6ae05aa Added size macros.
On very resource constraind devices you need to be able to
control the size of all buffers and structures placed on the
stack.
2014-11-07 14:31:44 +02:00
Johan Wikman 8a7d535d92 Added MONGOOSE_NO_USER configuration define.
Low-end systems, not running a proper OS, may not have the
concept of a user.
2014-11-07 14:01:13 +02:00
Sergey Lyubka e7ac6024de Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-11-07 10:05:51 +00:00
Sergey Lyubka 9981b99ac8 Extra NULL check in iter2(). Fix #430 2014-11-07 10:05:42 +00:00
Johan Wikman 87a36c0c30 O_BINARY might be defined.
Some unix environments defines O_BINARY.
2014-11-07 12:02:11 +02:00
Sergey Lyubka f2b13761c0 Merge pull request #431 from jhnwkmn/reduce-includes
Conditionally include dirent.h and dlfcn.h
2014-11-07 09:51:30 +00:00
Johan Wikman 9786478a31 Conditionally include dirent.h and dlfcn.h
If you do not have a filesystem or do not support dav or
dynamic loading, the corresponding header files need not
be included (some environments might not have them).
2014-11-07 11:05:51 +02:00
Sergey Lyubka 7d236d7f33 Merge pull request #429 from AlexAltea/master
Added #define's for deprecated POSIX names
2014-11-01 20:39:34 +00:00
Alexandro Sánchez Bach e098a7292d Added #define's for deprecated POSIX names 2014-10-30 23:07:48 +01:00
Sergey Lyubka 632b3a38a9 5.5 -> 5.6 2014-10-28 11:43:51 +00:00
24 changed files with 443 additions and 279 deletions

No files matched your search

-20
View File
@@ -1,20 +0,0 @@
language: cpp
env:
matrix:
- MONGOOSE_NO_SOCKETPAIR
- MONGOOSE_NO_FILESYSTEM
- MONGOOSE_NO_AUTH
- MONGOOSE_NO_DAV
- MONGOOSE_NO_DIRECTORY_LISTING
- MONGOOSE_NO_LOGGING
- MONGOOSE_NO_SSI
- MONGOOSE_NO_DL
- MONGOOSE_NO_WEBSOCKET
compiler:
- gcc
- clang
script:
- cd test && make
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com> Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
Copyright (c) 2013 Cesanta Software Limited Copyright (c) 2013-2015 Cesanta Software Limited
All rights reserved All rights reserved
This code is dual-licensed: you can redistribute it and/or modify This code is dual-licensed: you can redistribute it and/or modify
+13 -23
View File
@@ -11,9 +11,11 @@ manufacturing, finance, research, automotive, gaming, IT.
* [Mailing list](http://groups.google.com/group/mongoose-users) * [Mailing list](http://groups.google.com/group/mongoose-users)
* [Downloads](http://cesanta.com/mongoose.shtml) * [Downloads](http://cesanta.com/products.shtml)
* [Documentation](http://cesanta.com/docs.shtml) * [Documentation](http://cesanta.com/docs.shtml)
Check out Fossa - our [embedded multi-protocol library](https://github.com/cesanta/fossa) with TCP,UDP,HTTP,Websocket,MQTT,DNS support, designed for Internet Of Things!
# Features # Features
- Works on Windows, Mac, UNIX/Linux, iPhone, Android eCos, QNX - Works on Windows, Mac, UNIX/Linux, iPhone, Android eCos, QNX
@@ -43,24 +45,13 @@ Download, double-click to start, run browser -- that's all!
![shot3](http://cesanta.com/images/tut_sharing/tut3.png) ![shot3](http://cesanta.com/images/tut_sharing/tut3.png)
![shot4](http://cesanta.com/images/tut_sharing/tut4.png) ![shot4](http://cesanta.com/images/tut_sharing/tut4.png)
# Acknowledgements # Contributions
Mongoose made better thanks to the contribution of following people: People who have agreed to the
[Cesanta CLA](http://cesanta.com/contributors_la.html)
Arnout Vandecappelle, Benoît Amiaux, Boris Pek, Cody Hanson, Colin Leitner, can make contributions. Note that the CLA isn't a copyright
Daniel Oaks, Eric Bakan, Erik Oomen, Filipp Kovalev, Ger Hobbelt, _assigment_ but rather a copyright _license_.
Hendrik Polczynski, Igor Okulist, Jay, Joe Mucchiello, John Safranek, You retain the copyright on your contributions.
José Miguel Gonçalves, Shueng Chuan, Katerina Blinova, Konstantin Sorokin,
Marin Atanasov, Matt Healy, Mitch Hendrickson, Nigel Stewart, Pavel Khlebovich,
Sebastian Reinhard, Stefan Doehla, abadc0de, nullable.type,
T.Barmann, D.Hughes, J.C.Sloan, R.Romeo, L.E.Spencer, S.Kotay, R.M.Shorter,
W.Mar, J.Wilander, Santa from Memphis, S.Davies, C.Beck,
O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski,
Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett,
C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson,
A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein,
R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum,
F.Morenius, and 10 others.
# Licensing # Licensing
@@ -70,17 +61,16 @@ source licenses. The GPLv2 open source License does not generally permit
incorporating this software into non-open source programs. incorporating this software into non-open source programs.
For those customers who do not wish to comply with the GPLv2 open For those customers who do not wish to comply with the GPLv2 open
source license requirements, source license requirements,
[Cesanta Software](http://cesanta.com) offers a full, [Cesanta](http://cesanta.com) offers a full,
royalty-free commercial license and professional support royalty-free commercial license and professional support
without any of the GPL restrictions. without any of the GPL restrictions.
# Other products by Cesanta Software: simple and effective # Other products by Cesanta
- [Fossa](http://github.com/cesanta/fossa) - Multi-protocol networking library
- [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to - [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to
secure network communications secure network communications
- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator - [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression - [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
library library
- [Net Skeleton](https://github.com/cesanta/net_skeleton) - framework for - [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine
building network applications
- [SLDR](https://github.com/cesanta/sldr) - Super Light DNS Resolver
-12
View File
@@ -1,12 +0,0 @@
LOCAL_PATH := $(call my-dir)/../..
include $(CLEAR_VARS)
# To build with lua support, uncomment two lines below:
#LUA_SOURCES := build/lua_5.2.1.c build/sqlite3.c build/lsqlite3.c
#LUA_FLAGS := -I$(LOCAL_PATH)/build -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DUSE_LUA -DUSE_LUA_SQLITE3 -DLUA_COMPAT_ALL -D"getlocaledecpoint() ='.'"
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(LUA_FLAGS) $(COPT)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := examples/server.c mongoose.c $(LUA_SOURCES)
include $(BUILD_EXECUTABLE)
+7 -4
View File
@@ -1,6 +1,6 @@
# Mongoose API Reference # Mongoose API Reference
struct mg_server *mg_create_server(void *server_param); struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
Creates web server instance. Returns opaque instance pointer, or NULL if Creates web server instance. Returns opaque instance pointer, or NULL if
there is not enough memory. `server_param`: Could be any pointer, or NULL. there is not enough memory. `server_param`: Could be any pointer, or NULL.
@@ -183,11 +183,14 @@ points to a directory, Mongoose will show directory listing. If this function
is used, no calls to `mg_send*` or `mg_printf*` functions must be made, and is used, no calls to `mg_send*` or `mg_printf*` functions must be made, and
event handler must return `MG_MORE`. event handler must return `MG_MORE`.
int mg_websocket_write(struct mg_connection* conn, int opcode, size_t mg_websocket_write(struct mg_connection* conn, int opcode,
const char *data, size_t data_len); const char *data, size_t data_len);
size_t mg_websocket_printf(struct mg_connection* conn, int opcode,
const char *fmt, ...);
Similar to `mg_write()`, but wraps the data into a websocket frame with a
given websocket `opcode`. Similar to `mg_write()` and `mg_printf()`, but wraps the data into a
websocket frame with a given websocket `opcode`.
const char *mg_get_header(const struct mg_connection *, const char *name); const char *mg_get_header(const struct mg_connection *, const char *name);
+1 -1
View File
@@ -7,7 +7,7 @@ Note : You dont need root access to run mongoose on Android.
- Clone Mongoose Git repo - Clone Mongoose Git repo
- Download the Android NDK from [http://developer.android.com/tools/sdk/ndk/index.html](http://developer.android.com/tools/sdk/ndk/index.html) - 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/examples` - Run `/path-to-ndk/ndk-build -C /path/to/mongoose`
That should generate mongoose/lib/armeabi/mongoose That should generate mongoose/lib/armeabi/mongoose
- Using the adb tool (you need to have Android SDK installed for that), - Using the adb tool (you need to have Android SDK installed for that),
push the generated mongoose binary to `/data/local` folder on device. push the generated mongoose binary to `/data/local` folder on device.
+3 -1
View File
@@ -149,8 +149,10 @@ all Net Skeleton functions will be available too.
-DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing -DMONGOOSE_NO_DIRECTORY_LISTING Disable directory listing
-DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only -DMONGOOSE_NO_FILESYSTEM Disables all file IO, serving from memory only
-DMONGOOSE_NO_LOGGING Disable access/error logging -DMONGOOSE_NO_LOGGING Disable access/error logging
-DMONGOOSE_NO_THREADS -DMONGOOSE_ENABLE_THREADS Enable mg_start_thread() function
-DMONGOOSE_NO_WEBSOCKET Disable WebSocket support -DMONGOOSE_NO_WEBSOCKET Disable WebSocket support
-DMONGOOSE_NO_USER No concept of a user on used platform.
(Platform does not provide getpwnam, setgid or setuid)
-DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30 -DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
-DMONGOOSE_USE_LUA Enable Lua scripting -DMONGOOSE_USE_LUA Enable Lua scripting
-51
View File
@@ -1,51 +0,0 @@
# Mongoose Lua Server Pages
Pre-built Windows and Mac mongoose binaries support Lua Server Pages
functionality.
That means it is possible to write PHP-like scripts with mongoose
using Lua programming language instead of PHP. Lua is known
for it's speed and small size. Mongoose uses Lua version 5.2.3, 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 a file that is called `ANY_NAME.lp`. For example,
`my_page.lp`. It is important to have a file
name that ends up with `.lp`, cause this is the way mongoose recognises
Lua Page file. The contents of the file, just like
with PHP, is HTML with embedded Lua code. Lua code must be enclosed within
`&lt;? ?&gt;` blocks, and can appear anywhere on the page.
Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP status line and headers, like this:
<? mg.write('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n') ?>
<html><body>
<span>Today is:</span> <? mg.write(os.date("%A")) ?>
</body></html>
Note that this example uses function `mg.write()`, which prints data to the
web page. Using function `mg.write()` is the way to generate web content from
inside Lua code. In addition to `mg.write()`, all standard library functions
are accessible from the Lua code (please check reference manual for details).
Information about the request is available via the `mg.request_info` object.
I contains request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in
[mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h)
to see what is available via the `mg.request_info` object.
Check out [prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp) for some example.
Mongoose exports the following to the Lua Server Page:
mg.write(str) -- writes string to the client
mg.onerror(msg) -- error handler, can be overridden
mg.request_info -- a table with request information
Using Lua scripting it is easy to emulate SSI functionality. For example,
to include the content of another file, one can write:
<? mg.write(io.open('MY_FILE.TXT'):read('*all')) ?>
To serve a Lua Page, mongoose creates Lua context. That context is used for
all Lua blocks within the page. That means, all Lua blocks on the same page
share the same context. If one block defines a variable, for example, that
variable is visible in all following blocks.
+27 -2
View File
@@ -1,12 +1,37 @@
# Mongoose Release Notes # Mongoose Release Notes
## Release 5.6, 2015-03-17
Changes in Libmongoose library:
- Added `-dav_root` configuration option that gives an ability to mount
a different root directory (not document_root)
- Fixes for build under Win23 and MinGW
- Bugfix: Double dots removal
- Bugfix: final chunked response double-send
- Fixed compilation in 64-bit environments
- Added OS/2 compatibility
- Added `getaddrinfo()` call and `NS_ENABLE_GETADDRINFO`
- Various SSL-related fixes
- Added integer overflow protection in `iobuf_append()` and `deliver_websocket_frame()`
- Fixed NetBSD build
- Enabled `NS_ENABLE_IPV6` build for Visual Studio 2008+
- Enhanced comma detection in `parse_header()`
- Fixed unchanged memory accesses on ARM
- Added ability to use custom memory allocator through NS_MALLOC, NS_FREE, NS_REALLOC
Changes in Mongoose binary:
- Added `-start_browser` option to disable automatic browser launch
- Added experimental SSL support. To listen on HTTPS port, use `ssl://PORT:SSL_CERT` format. For example, to listen on HTTP port 8080 and HTTPS port 8043, use `-listening_port 8080,ssl://8043:ssl_cert.pem`
## Release 5.5, October 28 2014 ## Release 5.5, October 28 2014
Changes in Libmongoose library: Changes in Libmongoose library:
- Added new API function: `mg_forward()` for proxying functionality - Added new API function: `mg_forward()` for proxying functionality
- Added new API function: `mg_send_file_data()` for sending file data - Added new API function: `mg_send_file_data()` for sending file data
- Added new utility API functions: `mg_mmap() and mg_munpap()` - Added new utility API functions: `mg_mmap() and mg_munmap()`
- Changed the way SSL settings are handled: removed `ssl_certificate` and - Changed the way SSL settings are handled: removed `ssl_certificate` and
`ssl_ca_certificate` options, and instead made `listening_port` accept `ssl_ca_certificate` options, and instead made `listening_port` accept
`ssl://PORT:SSL_CERT:CA_CERT` notation `ssl://PORT:SSL_CERT:CA_CERT` notation
@@ -82,7 +107,7 @@ Changes in Libmongoose library:
Changes in pre-compiled binaries: Changes in pre-compiled binaries:
* New awesome Mongoose logos buy our designer Katrin - thanks Katrin! * New awesome Mongoose logos by our designer Katrin - thanks Katrin!
Check them out at http://cesanta.com/products.shtml Check them out at http://cesanta.com/products.shtml
* Added Lua Server Pages support to the free version, quick intro is at * Added Lua Server Pages support to the free version, quick intro is at
http://cesanta.com/docs/Lua.shtml http://cesanta.com/docs/Lua.shtml
+4 -9
View File
@@ -1,20 +1,15 @@
# Mongoose SSL guide # Mongoose SSL guide
SSL is a protocol that makes web communication secure. To enable SSL SSL is a protocol that makes web communication secure. To enable SSL
in mongoose, 3 steps are required: in mongoose, 2 steps are required:
1. Valid certificate file must be created 1. Create valid SSL certificate file
2. `ssl_certificate` options must be set to contain path to the 2. Append SSL certificate file path to the `listening_ports` option
certificate file.
3. `listening_ports` option must contain a port number with letter `s`
appended to it, which instructs Mongoose to use SSL for all connections
made to that port.
Below is the `mongoose.conf` file snippet for typical SSL setup: Below is the `mongoose.conf` file snippet for typical SSL setup:
document_root www_root # Serve files in www_root directory document_root www_root # Serve files in www_root directory
listening_ports 80r,443s # Redirect all HTTP requests to HTTPS listening_ports 80,443:cert.pem # Listen on ports 80 and 443
ssl_certificate ssl_cert.pem # Location of certificate file
## How to create SSL certificate file ## How to create SSL certificate file
+1
View File
@@ -0,0 +1 @@
*.exe
+6 -1
View File
@@ -3,13 +3,18 @@
SUBDIRS = $(sort $(filter-out csharp/, $(dir $(wildcard */)))) SUBDIRS = $(sort $(filter-out csharp/, $(dir $(wildcard */))))
X = $(SUBDIRS) X = $(SUBDIRS)
ifdef WINDIR
# appending the Winsock2 library at the end of the compiler
# invocation
CFLAGS_EXTRA += -lws2_32
endif
.PHONY: $(SUBDIRS) .PHONY: $(SUBDIRS)
all: $(SUBDIRS) all: $(SUBDIRS)
$(SUBDIRS): $(SUBDIRS):
@$(MAKE) -C $@ @$(MAKE) CFLAGS_EXTRA="$(CFLAGS_EXTRA)" -C $@
clean: clean:
for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done
+1 -1
View File
@@ -9,4 +9,4 @@ unix: $(SOURCES)
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
clean: clean:
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib rm -rf $(PROG) *.exe *.dSYM *.obj *.exp *.o *.lib
+1 -1
View File
@@ -2,7 +2,7 @@
# All rights reserved # All rights reserved
PROG = multi_threaded_server PROG = multi_threaded_server
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA)
SOURCES = $(PROG).c ../../mongoose.c SOURCES = $(PROG).c ../../mongoose.c
$(PROG): $(SOURCES) $(PROG): $(SOURCES)
+1 -1
View File
@@ -3,7 +3,7 @@
PROG = proxy_server PROG = proxy_server
FLAGS = -I../.. -DNS_ENABLE_SSL FLAGS = -I../.. -DNS_ENABLE_SSL
CFLAGS = -W -Wall -g -O0 -pthread -lssl $(FLAGS) $(CFLAGS_EXTRA) CFLAGS = -W -Wall -g -O0 -pthread -lssl -DMONGOOSE_ENABLE_THREADS $(FLAGS) $(CFLAGS_EXTRA)
SOURCES = $(PROG).c ../../mongoose.c SOURCES = $(PROG).c ../../mongoose.c
unix: $(SOURCES) unix: $(SOURCES)
+2 -12
View File
@@ -160,20 +160,13 @@ static void setopt(struct mg_server *s, const char *opt, const char *val) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
const char *cert = NULL, *ca_cert = NULL, *port = "2014"; const char *port = "2014", *dump = NULL, *root = "proxy_web_root";
const char *mitm = NULL, *dump = NULL, *root = "proxy_web_root";
int i; int i;
// Parse command line options // Parse command line options
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-ca_cert") == 0 && i + 1 < argc) { if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
ca_cert = argv[++i];
} else if (strcmp(argv[i], "-cert") == 0 && i + 1 < argc) {
cert = argv[++i];
} else if (strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
port = argv[++i]; port = argv[++i];
} else if (strcmp(argv[i], "-mitm") == 0 && i + 1 < argc) {
mitm = argv[++i];
} else if (strcmp(argv[i], "-root") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "-root") == 0 && i + 1 < argc) {
root = argv[++i]; root = argv[++i];
} else if (strcmp(argv[i], "-dump") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "-dump") == 0 && i + 1 < argc) {
@@ -191,10 +184,7 @@ int main(int argc, char *argv[]) {
setopt(s_server, "enable_proxy", "yes"); setopt(s_server, "enable_proxy", "yes");
setopt(s_server, "document_root", root); setopt(s_server, "document_root", root);
setopt(s_server, "listening_port", port); setopt(s_server, "listening_port", port);
setopt(s_server, "ssl_certificate", cert);
setopt(s_server, "ssl_ca_certificate", ca_cert);
setopt(s_server, "hexdump_file", dump); setopt(s_server, "hexdump_file", dump);
setopt(s_server, "ssl_mitm_certs", mitm);
// Start two SSE pushing threads // Start two SSE pushing threads
mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_1"); mg_start_thread(sse_pusher_thread_func, (void *) "sse_pusher_thread_1");
+17 -1
View File
@@ -2,11 +2,27 @@
# All rights reserved # All rights reserved
PROG = web_server PROG = web_server
CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA)
SOURCES = $(PROG).c ../../mongoose.c SOURCES = $(PROG).c ../../mongoose.c
OPENSSL_FLAGS = -DNS_ENABLE_SSL -lssl
# PolarSSL paths and flags
POLARSSL_PATH = /usr/local
POLARSSLCOMPAT_PATH = ./../../../polar
SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -DNS_ENABLE_SSL
#
$(PROG): $(SOURCES) $(PROG): $(SOURCES)
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(CC) -o $(PROG) $(SOURCES) $(CFLAGS)
openssl:
$(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(OPENSSL_FLAGS)
polarssl:
$(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
clean: clean:
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
+46
View File
@@ -0,0 +1,46 @@
-----BEGIN CERTIFICATE-----
MIIC+zCCAeOgAwIBAgIJAPhB8jbL+G82MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCTEyNy4wLjAuMTAeFw0xNTAzMDYxMjQzMzNaFw0yNTAzMDMxMjQzMzNaMBQx
EjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBALi3b3daMgzUEROKob1Caf68i+//cTRkPdBJv2cOBak21CdQzY0Nvx73GLzf
5TKB347BCHNbYRKGJXDbYdmFp20/WeBHkY7RS3Ad2Q5lzyx66u9PxNx7hJIiqBgF
58VU+E3o/I+o8QNIoOT+wtCiq3Nwkp+zGBJmS32rzMEV9bcKxSzMrkfRhF+XAREd
DwM9vfPg6WRb/b+vv06uvVwcw390RprLautGfBdaRddVYkIAKJGRRTqZAvTRFW1J
FcIVOxlN+iA7qP7xjr3tUP78qMmlu0MXsHrUR2cgfveZK2sdUW5G804yHsU5sC8l
FbtLKMEOyLsk2bEIScOXgum7g2sCAwEAAaNQME4wHQYDVR0OBBYEFHtLzUqAsXkH
Il8S5sMhJuVhRJLdMB8GA1UdIwQYMBaAFHtLzUqAsXkHIl8S5sMhJuVhRJLdMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAEzHc0AOr+qs0OFvWMfcSMi7
O/aYlLS6f7Sos+lli69+61EcmCTJVarVeAVUsAoqmzBKDbeOpAK1hGX6/GGcXjR2
BmuU0hUKyX9l1lwdMKU45BayH/riElwnvAyj2GxKoPpdIjlHns4SAITOCUx9NfpM
agd7kjolton0ZQ5DI/2a43PkqHv1lY4Dp60wJlxit9U68bsGOycCJ/BsAyrPROb2
D1MkpMBIdfHc8uxRywM3/l9buFX8yrrMUGOYKgfjDwdzbj0iwIixoGpHL7IfeBtu
dvGO/g2rEhbtAP+xIgOR3GvzqjZh30er3no7zjDMn65tTME18Aq3tBQY7vPDKms=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4t293WjIM1BET
iqG9Qmn+vIvv/3E0ZD3QSb9nDgWpNtQnUM2NDb8e9xi83+Uygd+OwQhzW2EShiVw
22HZhadtP1ngR5GO0UtwHdkOZc8seurvT8Tce4SSIqgYBefFVPhN6PyPqPEDSKDk
/sLQoqtzcJKfsxgSZkt9q8zBFfW3CsUszK5H0YRflwERHQ8DPb3z4OlkW/2/r79O
rr1cHMN/dEaay2rrRnwXWkXXVWJCACiRkUU6mQL00RVtSRXCFTsZTfogO6j+8Y69
7VD+/KjJpbtDF7B61EdnIH73mStrHVFuRvNOMh7FObAvJRW7SyjBDsi7JNmxCEnD
l4Lpu4NrAgMBAAECggEAaFuqbAHXOQwuwZ2XFzgIblTTsrncmT7w9VZU/sIbTKif
X771AnX7vmDX5w2PjeN2DE7emV3NEAwd5w7qz1wFZWFfQ6jrgYaZWjRixxGZ5IVl
aeLlU7OtCGrwEPJ1KTWCO3IgDoHh+Hr1+6o7Imhk+QlmrTcfqHWGvO9s9MGVWt2S
RLAnSTFiOe5brdJnmlqq1sKZmnLmpydBaPUOYpZGAgRasrjdMZB+lZOazd1x23/5
GAcm0rDREMnO9b2Jt+TNEZHT6d5KpVoExztZEZj8QCLXoic/SpFIqHGtpNlQXa+d
BVqgQbIYjO8ldldxZ8YIyJDVF+9e/uBBwu6jBIIsEQKBgQDspEHCyyuh4LG+7BbZ
eXlsfCxPTM6K9w31ZwHAwRtAuGqrOrE+pFJG9CEsFZbAI1aOGmZZdjexuSMcOlXl
TIVJTQHoFtoGEsanYEXO4O1t02Ab/DCYSpXusXUraRBRPpsTC77Sh5mxLUNd23d9
NhnDBuwChAmC+IYexjkXeqPYFwKBgQDH08PEd+2PVo4MD8UVKUlEcgoyCr6ESiyp
HfYyhhfd5x3DbZLoKCkunDfBs/hakQk8DA2nn4tl4ZjfmzXmX0EBx+E5YTdYshW7
ZcjN5x64B5PEOAR/NZA6agNlp3XGXXXgX+gnN6pgE49eVU22nZ4G+QBKD6NcCviB
LBPUxMbvzQKBgHgZYRqonGtaqzsXfP1AjmSFnMNeWtDiU95BOf2Gw/sT3WcrsXr2
UJ+cFR3XkxvOk4YpVdp/igKT0ILqBGAMdvTdtWMB/gLpEpMt5B/7veRoS7XIRy1z
ZSawP6QZfWOOX4vKAT29/j2SmEcRNFKC245EfBFGy8EBuqfxuFX3MyJfAoGBAJ0y
tjsErVmpma1baosvI3g4zlR3p1CimWehLmCopHXorr1iocMIdP0535L+ZU258y3N
vaA0HpFTW9PsYgaMwLMJ7uAY3lVkIzx84e849i2HqHMgLkl0dbW+WFXL2xblxylv
yU2wuNNED/EB4lTawcpycAvTKYvrBXt4lVE4S9exAoGAGl6vZV3zyw4jpIw4uDfk
LTPYUrghFDDGKExyeOnC/W9pqR2veqzfBz02C3jqwhewoqgAcnNc2sg0rJmM+6Oz
Z2mmGZTHO9xR++7+W7e8AkQBbS6TB8a+7yNcM4USLP+b9sX5N+8gFhFs9tG7j/no
G44qLsJ/yve7/QsOA37uEMs=
-----END PRIVATE KEY-----
+2 -5
View File
@@ -96,11 +96,8 @@ static void __cdecl signal_handler(int sig_num) {
} }
static void vnotify(const char *fmt, va_list ap, int must_exit) { static void vnotify(const char *fmt, va_list ap, int must_exit) {
char msg[200]; vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
vsnprintf(msg, sizeof(msg), fmt, ap);
fprintf(stderr, "%s\n", msg);
if (must_exit) { if (must_exit) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
+15 -3
View File
@@ -2,14 +2,26 @@
# All rights reserved # All rights reserved
PROG = ws_ssl PROG = ws_ssl
CFLAGS = -W -Wall -I../.. -I. -pthread -g -O0 $(CFLAGS_EXTRA) CFLAGS = -W -Wall -I../.. -I. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS -DNS_ENABLE_SSL -DSSL_WRAPPER_USE_AS_LIBRARY $(CFLAGS_EXTRA)
LDFLAGS = -lssl
SOURCES = ws_ssl.c ../../mongoose.c ssl_wrapper.c SOURCES = ws_ssl.c ../../mongoose.c ssl_wrapper.c
# PolarSSL paths and flags
POLARSSL_PATH = /usr/local
POLARSSLCOMPAT_PATH = ./../../../polar
SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c
INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include
LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls
CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR)
#
all: $(PROG) all: $(PROG)
$(PROG): $(SOURCES) $(PROG): $(SOURCES)
$(CC) -o $(PROG) $(SOURCES) \ $(CC) -o $(PROG) $(SOURCES) $(LDFLAGS) $(CFLAGS)
-DNS_ENABLE_SSL -DSSL_WRAPPER_USE_AS_LIBRARY -lssl $(CFLAGS)
polarssl: $(SOURCES_POLAR)
$(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR)
clean: clean:
rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib
+8
View File
@@ -0,0 +1,8 @@
LOCAL_PATH := $(call my-dir)/..
include $(CLEAR_VARS)
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(COPT)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := examples/web_server/web_server.c mongoose.c
include $(BUILD_EXECUTABLE)
+264 -110
View File
@@ -14,8 +14,6 @@
// //
// Alternatively, you can license this library under a commercial // Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/>. // license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-16 06:47:40 UTC $
#ifdef NOEMBED_NET_SKELETON #ifdef NOEMBED_NET_SKELETON
#include "net_skeleton.h" #include "net_skeleton.h"
@@ -36,8 +34,6 @@
// //
// Alternatively, you can license this software under a commercial // Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>. // license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-28 05:04:41 UTC $
#ifndef NS_SKELETON_HEADER_INCLUDED #ifndef NS_SKELETON_HEADER_INCLUDED
#define NS_SKELETON_HEADER_INCLUDED #define NS_SKELETON_HEADER_INCLUDED
@@ -50,7 +46,9 @@
#define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows #define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+ #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+
#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h #undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h
#ifdef __Linux__
#define _XOPEN_SOURCE 600 // For flockfile() on Linux #define _XOPEN_SOURCE 600 // For flockfile() on Linux
#endif
#define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++ #define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX #define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX
#ifndef _LARGEFILE_SOURCE #ifndef _LARGEFILE_SOURCE
@@ -80,7 +78,11 @@
#ifdef _WIN32 #ifdef _WIN32
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib") // Linking with winsock library #pragma comment(lib, "ws2_32.lib") // Linking with winsock library
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif #endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h> #include <windows.h>
#include <process.h> #include <process.h>
#ifndef EINPROGRESS #ifndef EINPROGRESS
@@ -124,7 +126,12 @@ typedef struct _stati64 ns_stat_t;
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/select.h> #include <sys/select.h>
#define closesocket(x) close(x) #define closesocket(x) close(x)
#ifndef __OS2__
#define __cdecl #define __cdecl
#else
#include <sys/time.h>
typedef int socklen_t;
#endif
#define INVALID_SOCKET (-1) #define INVALID_SOCKET (-1)
#define to64(x) strtoll(x, NULL, 10) #define to64(x) strtoll(x, NULL, 10)
typedef int sock_t; typedef int sock_t;
@@ -255,7 +262,7 @@ struct ns_connection *ns_bind(struct ns_mgr *, const char *,
struct ns_connection *ns_connect(struct ns_mgr *, const char *, struct ns_connection *ns_connect(struct ns_mgr *, const char *,
ns_callback_t, void *); ns_callback_t, void *);
int ns_send(struct ns_connection *, const void *buf, int len); int ns_send(struct ns_connection *, const void *buf, size_t len);
int ns_printf(struct ns_connection *, const char *fmt, ...); int ns_printf(struct ns_connection *, const char *fmt, ...);
int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap); int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
@@ -305,12 +312,18 @@ int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
#define NS_FREE free #define NS_FREE free
#endif #endif
#ifndef NS_CALLOC
#define NS_CALLOC calloc
#endif
#define NS_CTL_MSG_MESSAGE_SIZE (8 * 1024)
#define NS_READ_BUFFER_SIZE 2048
#define NS_UDP_RECEIVE_BUFFER_SIZE 2000 #define NS_UDP_RECEIVE_BUFFER_SIZE 2000
#define NS_VPRINTF_BUFFER_SIZE 500 #define NS_VPRINTF_BUFFER_SIZE 500
struct ctl_msg { struct ctl_msg {
ns_callback_t callback; ns_callback_t callback;
char message[1024 * 8]; char message[NS_CTL_MSG_MESSAGE_SIZE];
}; };
void iobuf_resize(struct iobuf *io, size_t new_size) { void iobuf_resize(struct iobuf *io, size_t new_size) {
@@ -341,6 +354,11 @@ size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
assert(io != NULL); assert(io != NULL);
assert(io->len <= io->size); assert(io->len <= io->size);
/* check overflow */
if (len > ~(size_t)0 - (size_t)(io->buf + io->len)) {
return 0;
}
if (len <= 0) { if (len <= 0) {
} else if (io->len + len <= io->size) { } else if (io->len + len <= io->size) {
memcpy(io->buf + io->len, buf, len); memcpy(io->buf + io->len, buf, len);
@@ -366,7 +384,8 @@ void iobuf_remove(struct iobuf *io, size_t n) {
static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) { static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
if (nc->flags & NSF_UDP) { if (nc->flags & NSF_UDP) {
long n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin)); long n = sendto(nc->sock, (const char *) buf, len, 0, &nc->sa.sa,
sizeof(nc->sa.sin));
DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno))); DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno)));
return n < 0 ? 0 : n; return n < 0 ? 0 : n;
} else { } else {
@@ -427,7 +446,7 @@ int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
// succeed or out of memory. // succeed or out of memory.
*buf = NULL; *buf = NULL;
while (len < 0) { while (len < 0) {
if (*buf) free(*buf); if (*buf) NS_FREE(*buf);
size *= 2; size *= 2;
if ((*buf = (char *) NS_MALLOC(size)) == NULL) break; if ((*buf = (char *) NS_MALLOC(size)) == NULL) break;
va_copy(ap_copy, ap); va_copy(ap_copy, ap);
@@ -456,7 +475,7 @@ int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) {
ns_out(nc, buf, len); ns_out(nc, buf, len);
} }
if (buf != mem && buf != NULL) { if (buf != mem && buf != NULL) {
free(buf); NS_FREE(buf);
} }
return len; return len;
@@ -490,7 +509,7 @@ static void hexdump(struct ns_connection *nc, const char *path,
ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) - ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) -
(ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size); (ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size);
fprintf(fp, "%s", buf); fprintf(fp, "%s", buf);
free(buf); NS_FREE(buf);
} }
fclose(fp); fclose(fp);
} }
@@ -589,6 +608,30 @@ int ns_socketpair(sock_t sp[2]) {
// TODO(lsm): use non-blocking resolver // TODO(lsm): use non-blocking resolver
static int ns_resolve2(const char *host, struct in_addr *ina) { static int ns_resolve2(const char *host, struct in_addr *ina) {
#ifdef NS_ENABLE_GETADDRINFO
int rv = 0;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *h = NULL;
char *ip = NS_MALLOC(17);
memset(ip, '\0', 17);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(host, NULL , NULL, &servinfo)) != 0) {
DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno)));
return 0;
}
for(p = servinfo; p != NULL; p = p->ai_next) {
memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
memcpy(ina, &h->sin_addr, sizeof(ina));
}
freeaddrinfo(servinfo);
return 1;
#else
struct hostent *he; struct hostent *he;
if ((he = gethostbyname(host)) == NULL) { if ((he = gethostbyname(host)) == NULL) {
DBG(("gethostbyname(%s) failed: %s", host, strerror(errno))); DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
@@ -597,6 +640,7 @@ static int ns_resolve2(const char *host, struct in_addr *ina) {
return 1; return 1;
} }
return 0; return 0;
#endif
} }
// Resolve FDQN "host", store IP address in the "ip". // Resolve FDQN "host", store IP address in the "ip".
@@ -655,8 +699,8 @@ static int ns_parse_address(const char *str, union socket_address *sa,
sa->sin.sin_port = htons((uint16_t) port); sa->sin.sin_port = htons((uint16_t) port);
} }
if (*use_ssl && (sscanf(str + len, ":%99[^:]:%99[^:]%n", cert, ca, &n) == 2 || if (*use_ssl && (sscanf(str + len, ":%99[^:,]:%99[^:,]%n", cert, ca, &n) == 2 ||
sscanf(str + len, ":%99[^:]%n", cert, &n) == 1)) { sscanf(str + len, ":%99[^:,]%n", cert, &n) == 1)) {
len += n; len += n;
} }
@@ -868,7 +912,7 @@ static int ns_ssl_err(struct ns_connection *conn, int res) {
#endif #endif
static void ns_read_from_socket(struct ns_connection *conn) { static void ns_read_from_socket(struct ns_connection *conn) {
char buf[2048]; char buf[NS_READ_BUFFER_SIZE];
int n = 0; int n = 0;
if (conn->flags & NSF_CONNECTING) { if (conn->flags & NSF_CONNECTING) {
@@ -889,6 +933,7 @@ static void ns_read_from_socket(struct ns_connection *conn) {
} else { } else {
ok = 1; ok = 1;
} }
conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
} }
#endif #endif
conn->flags &= ~NSF_CONNECTING; conn->flags &= ~NSF_CONNECTING;
@@ -917,6 +962,7 @@ static void ns_read_from_socket(struct ns_connection *conn) {
int ssl_err = ns_ssl_err(conn, res); int ssl_err = ns_ssl_err(conn, res);
if (res == 1) { if (res == 1) {
conn->flags |= NSF_SSL_HANDSHAKE_DONE; conn->flags |= NSF_SSL_HANDSHAKE_DONE;
conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
} else if (ssl_err == SSL_ERROR_WANT_READ || } else if (ssl_err == SSL_ERROR_WANT_READ ||
ssl_err == SSL_ERROR_WANT_WRITE) { ssl_err == SSL_ERROR_WANT_WRITE) {
return; // Call us again return; // Call us again
@@ -954,6 +1000,8 @@ static void ns_write_to_socket(struct ns_connection *conn) {
} else { } else {
conn->flags |= NSF_CLOSE_IMMEDIATELY; conn->flags |= NSF_CLOSE_IMMEDIATELY;
} }
} else {
conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
} }
} else } else
#endif #endif
@@ -969,14 +1017,14 @@ static void ns_write_to_socket(struct ns_connection *conn) {
} }
} }
int ns_send(struct ns_connection *conn, const void *buf, int len) { int ns_send(struct ns_connection *conn, const void *buf, size_t len) {
return (int) ns_out(conn, buf, len); return (int) ns_out(conn, buf, len);
} }
static void ns_handle_udp(struct ns_connection *ls) { static void ns_handle_udp(struct ns_connection *ls) {
struct ns_connection nc; struct ns_connection nc;
char buf[NS_UDP_RECEIVE_BUFFER_SIZE]; char buf[NS_UDP_RECEIVE_BUFFER_SIZE];
int n; ssize_t n;
socklen_t s_len = sizeof(nc.sa); socklen_t s_len = sizeof(nc.sa);
memset(&nc, 0, sizeof(nc)); memset(&nc, 0, sizeof(nc));
@@ -1024,6 +1072,9 @@ time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) { if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) {
ns_call(conn, NS_POLL, &current_time); ns_call(conn, NS_POLL, &current_time);
} }
if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
ns_close_conn(conn);
} else {
if (!(conn->flags & NSF_WANT_WRITE)) { if (!(conn->flags & NSF_WANT_WRITE)) {
//DBG(("%p read_set", conn)); //DBG(("%p read_set", conn));
ns_add_to_set(conn->sock, &read_set, &max_fd); ns_add_to_set(conn->sock, &read_set, &max_fd);
@@ -1034,8 +1085,6 @@ time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
//DBG(("%p write_set", conn)); //DBG(("%p write_set", conn));
ns_add_to_set(conn->sock, &write_set, &max_fd); ns_add_to_set(conn->sock, &write_set, &max_fd);
} }
if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
ns_close_conn(conn);
} }
} }
@@ -1247,21 +1296,21 @@ void ns_mgr_free(struct ns_mgr *s) {
#define fopen(x, y) mg_fopen((x), (y)) #define fopen(x, y) mg_fopen((x), (y))
#define open(x, y, z) mg_open((x), (y), (z)) #define open(x, y, z) mg_open((x), (y), (z))
#define close(x) _close(x) #define close(x) _close(x)
#define fileno(x) _fileno(x)
#define lseek(x, y, z) _lseeki64((x), (y), (z)) #define lseek(x, y, z) _lseeki64((x), (y), (z))
#define read(x, y, z) _read((x), (y), (z))
#define write(x, y, z) _write((x), (y), (z))
#define popen(x, y) _popen((x), (y)) #define popen(x, y) _popen((x), (y))
#define pclose(x) _pclose(x) #define pclose(x) _pclose(x)
#define mkdir(x, y) _mkdir(x) #define mkdir(x, y) _mkdir(x)
#define rmdir(x) _rmdir(x)
#define strdup(x) _strdup(x)
#ifndef __func__ #ifndef __func__
#define STRX(x) #x #define STRX(x) #x
#define STR(x) STRX(x) #define STR(x) STRX(x)
#define __func__ __FILE__ ":" STR(__LINE__) #define __func__ __FILE__ ":" STR(__LINE__)
#endif #endif
/* MINGW has adopted the MSVC formatting for 64-bit ints as of gcc 4.4 till 4.8*/
#if (defined(__MINGW32__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ < 8))) || defined(_MSC_VER)
#define INT64_FMT "I64d" #define INT64_FMT "I64d"
#else
#define INT64_FMT "lld"
#endif
#define flockfile(x) ((void) (x)) #define flockfile(x) ((void) (x))
#define funlockfile(x) ((void) (x)) #define funlockfile(x) ((void) (x))
typedef struct _stati64 file_stat_t; typedef struct _stati64 file_stat_t;
@@ -1269,11 +1318,18 @@ typedef HANDLE process_id_t;
#else ////////////// UNIX specific defines and includes #else ////////////// UNIX specific defines and includes
#if !defined(MONGOOSE_NO_FILESYSTEM) &&\
(!defined(MONGOOSE_NO_DAV) || !defined(MONGOOSE_NO_DIRECTORY_LISTING))
#include <dirent.h> #include <dirent.h>
#endif
#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_DL)
#include <dlfcn.h> #include <dlfcn.h>
#endif
#include <inttypes.h> #include <inttypes.h>
#include <pwd.h> #include <pwd.h>
#if !defined(O_BINARY)
#define O_BINARY 0 #define O_BINARY 0
#endif
#define INT64_FMT PRId64 #define INT64_FMT PRId64
typedef struct stat file_stat_t; typedef struct stat file_stat_t;
typedef pid_t process_id_t; typedef pid_t process_id_t;
@@ -1307,13 +1363,15 @@ typedef pid_t process_id_t;
#define MONGOOSE_IDLE_TIMEOUT_SECONDS 300 #define MONGOOSE_IDLE_TIMEOUT_SECONDS 300
#endif #endif
#ifdef NS_DISABLE_SOCKETPAIR #if defined(NS_DISABLE_SOCKETPAIR) && !defined(MONGOOSE_NO_CGI)
#define MONGOOSE_NO_CGI #define MONGOOSE_NO_CGI
#endif #endif
#ifdef MONGOOSE_NO_FILESYSTEM #ifdef MONGOOSE_NO_FILESYSTEM
#define MONGOOSE_NO_AUTH #define MONGOOSE_NO_AUTH
#if !defined(MONGOOSE_NO_CGI)
#define MONGOOSE_NO_CGI #define MONGOOSE_NO_CGI
#endif
#define MONGOOSE_NO_DAV #define MONGOOSE_NO_DAV
#define MONGOOSE_NO_DIRECTORY_LISTING #define MONGOOSE_NO_DIRECTORY_LISTING
#define MONGOOSE_NO_LOGGING #define MONGOOSE_NO_LOGGING
@@ -1323,7 +1381,7 @@ typedef pid_t process_id_t;
struct vec { struct vec {
const char *ptr; const char *ptr;
int len; size_t len;
}; };
// For directory listing and WevDAV support // For directory listing and WevDAV support
@@ -1346,6 +1404,7 @@ enum {
CGI_PATTERN, CGI_PATTERN,
#endif #endif
DAV_AUTH_FILE, DAV_AUTH_FILE,
DAV_ROOT,
DOCUMENT_ROOT, DOCUMENT_ROOT,
#ifndef MONGOOSE_NO_DIRECTORY_LISTING #ifndef MONGOOSE_NO_DIRECTORY_LISTING
ENABLE_DIRECTORY_LISTING, ENABLE_DIRECTORY_LISTING,
@@ -1384,6 +1443,7 @@ static const char *static_config_options[] = {
"cgi_pattern", DEFAULT_CGI_PATTERN, "cgi_pattern", DEFAULT_CGI_PATTERN,
#endif #endif
"dav_auth_file", NULL, "dav_auth_file", NULL,
"dav_root", NULL,
"document_root", NULL, "document_root", NULL,
#ifndef MONGOOSE_NO_DIRECTORY_LISTING #ifndef MONGOOSE_NO_DIRECTORY_LISTING
"enable_directory_listing", "yes", "enable_directory_listing", "yes",
@@ -1428,7 +1488,7 @@ enum endpoint_type {
}; };
#define MG_HEADERS_SENT NSF_USER_1 #define MG_HEADERS_SENT NSF_USER_1
#define MG_LONG_RUNNING NSF_USER_2 #define MG_USING_CHUNKED_API NSF_USER_2
#define MG_CGI_CONN NSF_USER_3 #define MG_CGI_CONN NSF_USER_3
#define MG_PROXY_CONN NSF_USER_4 #define MG_PROXY_CONN NSF_USER_4
#define MG_PROXY_DONT_PARSE NSF_USER_5 #define MG_PROXY_DONT_PARSE NSF_USER_5
@@ -1443,7 +1503,7 @@ struct connection {
char *request; char *request;
int64_t num_bytes_recv; // Total number of bytes received int64_t num_bytes_recv; // Total number of bytes received
int64_t cl; // Reply content length, for Range support int64_t cl; // Reply content length, for Range support
int request_len; // Request length, including last \r\n after last header ssize_t request_len; // Request length, including last \r\n after last header
}; };
#define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \ #define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
@@ -1463,7 +1523,7 @@ static const struct {
{".shtm", 5, "text/html"}, {".shtm", 5, "text/html"},
{".shtml", 6, "text/html"}, {".shtml", 6, "text/html"},
{".css", 4, "text/css"}, {".css", 4, "text/css"},
{".js", 3, "application/x-javascript"}, {".js", 3, "application/javascript"},
{".ico", 4, "image/x-icon"}, {".ico", 4, "image/x-icon"},
{".gif", 4, "image/gif"}, {".gif", 4, "image/gif"},
{".jpg", 4, "image/jpeg"}, {".jpg", 4, "image/jpeg"},
@@ -1508,11 +1568,11 @@ static const struct {
{NULL, 0, NULL} {NULL, 0, NULL}
}; };
#ifndef MONGOOSE_NO_THREADS #ifdef MONGOOSE_ENABLE_THREADS
void *mg_start_thread(void *(*f)(void *), void *p) { void *mg_start_thread(void *(*f)(void *), void *p) {
return ns_start_thread(f, p); return ns_start_thread(f, p);
} }
#endif // MONGOOSE_NO_THREADS #endif // MONGOOSE_ENABLE_THREADS
#ifndef MONGOOSE_NO_MMAP #ifndef MONGOOSE_NO_MMAP
#ifdef _WIN32 #ifdef _WIN32
@@ -1528,6 +1588,37 @@ static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
#define MAP_FAILED NULL #define MAP_FAILED NULL
#define MAP_PRIVATE 0 #define MAP_PRIVATE 0
#define PROT_READ 0 #define PROT_READ 0
#elif defined(__OS2__)
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
int offset) {
void *p;
int pos = lseek( fd, 0, SEEK_CUR ); /* Get a current position */
if (pos == -1)
return NULL;
/* Seek to offset offset */
if (lseek( fd, offset, SEEK_SET) == -1)
return NULL;
p = malloc(len);
/* Read in a file */
if (!p || read(fd, p, len) == -1) {
free(p);
p = NULL;
}
/* Restore the position */
lseek(fd, pos, SEEK_SET);
return p;
}
#define munmap(x, y) free(x)
#define MAP_FAILED NULL
#define MAP_PRIVATE 0
#define PROT_READ 0
#else #else
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
@@ -1654,9 +1745,9 @@ static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
// -1 if request is malformed // -1 if request is malformed
// 0 if request is not yet fully buffered // 0 if request is not yet fully buffered
// >0 actual request length, including last \r\n\r\n // >0 actual request length, including last \r\n\r\n
static int get_request_len(const char *s, int buf_len) { static int get_request_len(const char *s, size_t buf_len) {
const unsigned char *buf = (unsigned char *) s; const unsigned char *buf = (unsigned char *) s;
int i; size_t i;
for (i = 0; i < buf_len; i++) { for (i = 0; i < buf_len; i++) {
// Control characters are not allowed but >=128 are. // Control characters are not allowed but >=128 are.
@@ -1890,7 +1981,7 @@ static void *push_to_stdin(void *arg) {
} }
DBG(("%s", "FORWARED EVERYTHING TO CGI")); DBG(("%s", "FORWARED EVERYTHING TO CGI"));
CloseHandle(tp->hPipe); CloseHandle(tp->hPipe);
free(tp); NS_FREE(tp);
_endthread(); _endthread();
return NULL; return NULL;
} }
@@ -1911,14 +2002,14 @@ static void *pull_from_stdout(void *arg) {
CloseHandle(tp->hPipe); CloseHandle(tp->hPipe);
shutdown(tp->s, 2); // Without this, IO thread may get truncated data shutdown(tp->s, 2); // Without this, IO thread may get truncated data
closesocket(tp->s); closesocket(tp->s);
free(tp); NS_FREE(tp);
_endthread(); _endthread();
return NULL; return NULL;
} }
static void spawn_stdio_thread(sock_t sock, HANDLE hPipe, static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
void *(*func)(void *)) { void *(*func)(void *)) {
struct threadparam *tp = (struct threadparam *)malloc(sizeof(*tp)); struct threadparam *tp = (struct threadparam *)NS_MALLOC(sizeof(*tp));
if (tp != NULL) { if (tp != NULL) {
tp->s = sock; tp->s = sock;
tp->hPipe = hPipe; tp->hPipe = hPipe;
@@ -2247,7 +2338,7 @@ static void on_cgi_data(struct ns_connection *nc) {
// If reply has not been parsed yet, parse it // If reply has not been parsed yet, parse it
if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) { if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) {
struct iobuf *io = &conn->ns_conn->send_iobuf; struct iobuf *io = &conn->ns_conn->send_iobuf;
int s_len = sizeof(cgi_status) - 1; size_t s_len = sizeof(cgi_status) - 1;
int len = get_request_len(io->buf + s_len, io->len - s_len); int len = get_request_len(io->buf + s_len, io->len - s_len);
char buf[MAX_REQUEST_SIZE], *s = buf; char buf[MAX_REQUEST_SIZE], *s = buf;
@@ -2277,7 +2368,7 @@ static void on_cgi_data(struct ns_connection *nc) {
#endif // !MONGOOSE_NO_CGI #endif // !MONGOOSE_NO_CGI
static char *mg_strdup(const char *str) { static char *mg_strdup(const char *str) {
char *copy = (char *) malloc(strlen(str) + 1); char *copy = (char *) NS_MALLOC(strlen(str) + 1);
if (copy != NULL) { if (copy != NULL) {
strcpy(copy, str); strcpy(copy, str);
} }
@@ -2339,7 +2430,9 @@ static void remove_double_dots_and_double_slashes(char *s) {
// Skip all following slashes, backslashes and double-dots // Skip all following slashes, backslashes and double-dots
while (s[0] != '\0') { while (s[0] != '\0') {
if (s[0] == '/' || s[0] == '\\') { s++; } if (s[0] == '/' || s[0] == '\\') { s++; }
else if (s[0] == '.' && s[1] == '.') { s += 2; } else if (s[0] == '.' && (s[1] == '/' || s[1] == '\\')) { s += 2; }
else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { s += 2; }
else if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\')) { s += 3; }
else { break; } else { break; }
} }
} }
@@ -2347,13 +2440,14 @@ static void remove_double_dots_and_double_slashes(char *s) {
*p = '\0'; *p = '\0';
} }
int mg_url_decode(const char *src, int src_len, char *dst, int mg_url_decode(const char *src, size_t src_len, char *dst,
int dst_len, int is_form_url_encoded) { size_t dst_len, int is_form_url_encoded) {
int i, j, a, b; size_t i, j = 0;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') int a, b;
#define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'W')
for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
if (src[i] == '%' && i < src_len - 2 && if (src[i] == '%' && i + 2 < src_len &&
isxdigit(* (const unsigned char *) (src + i + 1)) && isxdigit(* (const unsigned char *) (src + i + 1)) &&
isxdigit(* (const unsigned char *) (src + i + 2))) { isxdigit(* (const unsigned char *) (src + i + 2))) {
a = tolower(* (const unsigned char *) (src + i + 1)); a = tolower(* (const unsigned char *) (src + i + 1));
@@ -2382,7 +2476,8 @@ static int is_valid_http_method(const char *s) {
// This function modifies the buffer by NUL-terminating // This function modifies the buffer by NUL-terminating
// HTTP request components, header names and header values. // HTTP request components, header names and header values.
// Note that len must point to the last \n of HTTP headers. // Note that len must point to the last \n of HTTP headers.
static int parse_http_message(char *buf, int len, struct mg_connection *ri) { static size_t parse_http_message(char *buf, size_t len,
struct mg_connection *ri) {
int is_request, n; int is_request, n;
// Reset the connection. Make sure that we don't touch fields that are // Reset the connection. Make sure that we don't touch fields that are
@@ -2390,6 +2485,8 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL; ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL;
ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0; ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0;
if (len < 1) return ~0;
buf[len - 1] = '\0'; buf[len - 1] = '\0';
// RFC says that all initial whitespaces should be ingored // RFC says that all initial whitespaces should be ingored
@@ -2405,7 +2502,7 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
is_request = is_valid_http_method(ri->request_method); is_request = is_valid_http_method(ri->request_method);
if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) || if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
(!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
len = -1; len = ~0;
} else { } else {
if (is_request) { if (is_request) {
ri->http_version += 5; ri->http_version += 5;
@@ -2464,7 +2561,7 @@ const char *mg_get_header(const struct mg_connection *ri, const char *s) {
} }
// Perform case-insensitive match of string against pattern // Perform case-insensitive match of string against pattern
int mg_match_prefix(const char *pattern, int pattern_len, const char *str) { int mg_match_prefix(const char *pattern, ssize_t pattern_len, const char *str) {
const char *or_str; const char *or_str;
int len, res, i = 0, j = 0; int len, res, i = 0, j = 0;
@@ -2536,6 +2633,12 @@ void mg_template(struct mg_connection *conn, const char *s,
} }
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
static int is_dav_request(const struct connection *conn) {
const char *s = conn->mg_conn.request_method;
return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
!strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
}
static int must_hide_file(struct connection *conn, const char *path) { static int must_hide_file(struct connection *conn, const char *path) {
const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$"; const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN]; const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN];
@@ -2548,19 +2651,24 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf,
size_t buf_len, file_stat_t *st) { size_t buf_len, file_stat_t *st) {
struct vec a, b; struct vec a, b;
const char *rewrites = conn->server->config_options[URL_REWRITES]; const char *rewrites = conn->server->config_options[URL_REWRITES];
const char *root = conn->server->config_options[DOCUMENT_ROOT]; const char *root =
#ifndef MONGOOSE_NO_DAV
is_dav_request(conn) && conn->server->config_options[DAV_ROOT] != NULL ?
conn->server->config_options[DAV_ROOT] :
#endif
conn->server->config_options[DOCUMENT_ROOT];
#ifndef MONGOOSE_NO_CGI #ifndef MONGOOSE_NO_CGI
const char *cgi_pat = conn->server->config_options[CGI_PATTERN]; const char *cgi_pat = conn->server->config_options[CGI_PATTERN];
char *p; char *p;
#endif #endif
const char *uri = conn->mg_conn.uri; const char *uri = conn->mg_conn.uri;
const char *domain = mg_get_header(&conn->mg_conn, "Host"); const char *domain = mg_get_header(&conn->mg_conn, "Host");
int match_len, root_len = root == NULL ? 0 : strlen(root); size_t match_len, root_len = root == NULL ? 0 : strlen(root);
// Perform virtual hosting rewrites // Perform virtual hosting rewrites
if (rewrites != NULL && domain != NULL) { if (rewrites != NULL && domain != NULL) {
const char *colon = strchr(domain, ':'); const char *colon = strchr(domain, ':');
int domain_len = colon == NULL ? (int) strlen(domain) : colon - domain; size_t domain_len = colon == NULL ? strlen(domain) : colon - domain;
while ((rewrites = next_option(rewrites, &a, &b)) != NULL) { while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 && if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 &&
@@ -2620,25 +2728,29 @@ static int should_keep_alive(const struct mg_connection *conn) {
(header == NULL && http_version && !strcmp(http_version, "1.1"))); (header == NULL && http_version && !strcmp(http_version, "1.1")));
} }
size_t mg_write(struct mg_connection *c, const void *buf, int len) { size_t mg_write(struct mg_connection *c, const void *buf, size_t len) {
struct connection *conn = MG_CONN_2_CONN(c); struct connection *conn = MG_CONN_2_CONN(c);
ns_send(conn->ns_conn, buf, len); ns_send(conn->ns_conn, buf, len);
return conn->ns_conn->send_iobuf.len; return conn->ns_conn->send_iobuf.len;
} }
void mg_send_status(struct mg_connection *c, int status) { void mg_send_status(struct mg_connection *c, int status) {
struct connection *conn = MG_CONN_2_CONN(c);
if (c->status_code == 0) { if (c->status_code == 0) {
c->status_code = status; c->status_code = status;
mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status)); mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status));
} }
conn->ns_conn->flags |= MG_USING_CHUNKED_API;
} }
void mg_send_header(struct mg_connection *c, const char *name, const char *v) { void mg_send_header(struct mg_connection *c, const char *name, const char *v) {
struct connection *conn = MG_CONN_2_CONN(c);
if (c->status_code == 0) { if (c->status_code == 0) {
c->status_code = 200; c->status_code = 200;
mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200)); mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200));
} }
mg_printf(c, "%s: %s\r\n", name, v); mg_printf(c, "%s: %s\r\n", name, v);
conn->ns_conn->flags |= MG_USING_CHUNKED_API;
} }
static void terminate_headers(struct mg_connection *c) { static void terminate_headers(struct mg_connection *c) {
@@ -2673,7 +2785,7 @@ size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) {
write_chunk((struct connection *) conn, buf, len); write_chunk((struct connection *) conn, buf, len);
} }
if (buf != mem && buf != NULL) { if (buf != mem && buf != NULL) {
free(buf); NS_FREE(buf);
} }
return conn->ns_conn->send_iobuf.len; return conn->ns_conn->send_iobuf.len;
} }
@@ -2780,8 +2892,8 @@ static void SHA1Init(SHA1_CTX *context) {
} }
static void SHA1Update(SHA1_CTX *context, const unsigned char *data, static void SHA1Update(SHA1_CTX *context, const unsigned char *data,
uint32_t len) { size_t len) {
uint32_t i, j; size_t i, j;
j = context->count[0]; j = context->count[0];
if ((context->count[0] += len << 3) < j) if ((context->count[0] += len << 3) < j)
@@ -2869,10 +2981,10 @@ static void send_websocket_handshake(struct mg_connection *conn,
mg_write(conn, buf, strlen(buf)); mg_write(conn, buf, strlen(buf));
} }
static int deliver_websocket_frame(struct connection *conn) { static size_t deliver_websocket_frame(struct connection *conn) {
// Having buf unsigned char * is important, as it is used below in arithmetic // Having buf unsigned char * is important, as it is used below in arithmetic
unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf; unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf;
int i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0, size_t i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
mask_len = 0, header_len = 0, data_len = 0, buffered = 0; mask_len = 0, header_len = 0, data_len = 0, buffered = 0;
if (buf_len >= 2) { if (buf_len >= 2) {
@@ -2883,10 +2995,10 @@ static int deliver_websocket_frame(struct connection *conn) {
header_len = 2 + mask_len; header_len = 2 + mask_len;
} else if (len == 126 && buf_len >= 4 + mask_len) { } else if (len == 126 && buf_len >= 4 + mask_len) {
header_len = 4 + mask_len; header_len = 4 + mask_len;
data_len = ((((int) buf[2]) << 8) + buf[3]); data_len = ((((size_t) buf[2]) << 8) + buf[3]);
} else if (buf_len >= 10 + mask_len) { } else if (buf_len >= 10 + mask_len) {
header_len = 10 + mask_len; header_len = 10 + mask_len;
data_len = (int) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) + data_len = (size_t) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
htonl(* (uint32_t *) &buf[6]); htonl(* (uint32_t *) &buf[6]);
} }
} }
@@ -2921,8 +3033,13 @@ size_t mg_websocket_write(struct mg_connection *conn, int opcode,
unsigned char mem[4192], *copy = mem; unsigned char mem[4192], *copy = mem;
size_t copy_len = 0; size_t copy_len = 0;
/* Check overflow */
if (data_len > ~(size_t)0 - (size_t)10) {
return 0;
}
if (data_len + 10 > sizeof(mem) && if (data_len + 10 > sizeof(mem) &&
(copy = (unsigned char *) malloc(data_len + 10)) == NULL) { (copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) {
return 0; return 0;
} }
@@ -2942,10 +3059,11 @@ size_t mg_websocket_write(struct mg_connection *conn, int opcode,
copy_len = 4 + data_len; copy_len = 4 + data_len;
} else { } else {
// 64-bit length field // 64-bit length field
const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32));
const uint32_t lo = htonl(data_len & 0xffffffff);
copy[1] = 127; copy[1] = 127;
* (uint32_t *) (copy + 2) = (uint32_t) memcpy(copy+2,&hi,sizeof(hi));
htonl((uint32_t) ((uint64_t) data_len >> 32)); memcpy(copy+6,&lo,sizeof(lo));
* (uint32_t *) (copy + 6) = (uint32_t) htonl(data_len & 0xffffffff);
memcpy(copy + 10, data, data_len); memcpy(copy + 10, data, data_len);
copy_len = 10 + data_len; copy_len = 10 + data_len;
} }
@@ -2954,7 +3072,7 @@ size_t mg_websocket_write(struct mg_connection *conn, int opcode,
mg_write(conn, copy, copy_len); mg_write(conn, copy, copy_len);
} }
if (copy != mem) { if (copy != mem) {
free(copy); NS_FREE(copy);
} }
// If we send closing frame, schedule a connection to be closed after // If we send closing frame, schedule a connection to be closed after
@@ -2979,7 +3097,7 @@ size_t mg_websocket_printf(struct mg_connection *conn, int opcode,
va_end(ap); va_end(ap);
if (buf != mem && buf != NULL) { if (buf != mem && buf != NULL) {
free(buf); NS_FREE(buf);
} }
return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
@@ -3014,7 +3132,8 @@ static int call_request_handler(struct connection *conn) {
int result; int result;
conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf; conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) { if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
if (conn->ns_conn->flags & MG_HEADERS_SENT) { if (conn->ns_conn->flags & MG_USING_CHUNKED_API) {
terminate_headers(&conn->mg_conn);
write_terminating_chunk(conn); write_terminating_chunk(conn);
} }
close_local_endpoint(conn); close_local_endpoint(conn);
@@ -3141,7 +3260,8 @@ static int find_index_file(struct connection *conn, char *path,
const char *list = conn->server->config_options[INDEX_FILES]; const char *list = conn->server->config_options[INDEX_FILES];
file_stat_t st; file_stat_t st;
struct vec filename_vec; struct vec filename_vec;
size_t n = strlen(path), found = 0; size_t n = strlen(path);
int found = 0;
// The 'path' given to us points to the directory. Remove all trailing // The 'path' given to us points to the directory. Remove all trailing
// directory separator characters from the end of the path, and // directory separator characters from the end of the path, and
@@ -3155,8 +3275,12 @@ static int find_index_file(struct connection *conn, char *path,
// path and see if the file exists. If it exists, break the loop // path and see if the file exists. If it exists, break the loop
while ((list = next_option(list, &filename_vec, NULL)) != NULL) { while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
if (path_len <= n + 2) {
continue;
}
// Ignore too long entries that may overflow path buffer // Ignore too long entries that may overflow path buffer
if (filename_vec.len > (int) (path_len - (n + 2))) if (filename_vec.len > (path_len - (n + 2)))
continue; continue;
// Prepare full path to the index file // Prepare full path to the index file
@@ -3292,7 +3416,7 @@ static DIR *opendir(const char *name) {
if (name == NULL) { if (name == NULL) {
SetLastError(ERROR_BAD_ARGUMENTS); SetLastError(ERROR_BAD_ARGUMENTS);
} else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) { } else if ((dir = (DIR *) NS_MALLOC(sizeof(*dir))) == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
} else { } else {
to_wchar(name, wpath, ARRAY_SIZE(wpath)); to_wchar(name, wpath, ARRAY_SIZE(wpath));
@@ -3303,7 +3427,7 @@ static DIR *opendir(const char *name) {
dir->handle = FindFirstFileW(wpath, &dir->info); dir->handle = FindFirstFileW(wpath, &dir->info);
dir->result.d_name[0] = '\0'; dir->result.d_name[0] = '\0';
} else { } else {
free(dir); NS_FREE(dir);
dir = NULL; dir = NULL;
} }
} }
@@ -3318,7 +3442,7 @@ static int closedir(DIR *dir) {
if (dir->handle != INVALID_HANDLE_VALUE) if (dir->handle != INVALID_HANDLE_VALUE)
result = FindClose(dir->handle) ? 0 : -1; result = FindClose(dir->handle) ? 0 : -1;
free(dir); NS_FREE(dir);
} else { } else {
result = -1; result = -1;
SetLastError(ERROR_BAD_ARGUMENTS); SetLastError(ERROR_BAD_ARGUMENTS);
@@ -3376,7 +3500,7 @@ static int scan_directory(struct connection *conn, const char *dir,
// Resize the array if nesessary // Resize the array if nesessary
if (arr_ind >= arr_size) { if (arr_ind >= arr_size) {
if ((p = (struct dir_entry *) if ((p = (struct dir_entry *)
realloc(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) { NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
// Memset new chunk to zero, otherwize st_mtime will have garbage which // Memset new chunk to zero, otherwize st_mtime will have garbage which
// can make strftime() segfault, see // can make strftime() segfault, see
// http://code.google.com/p/mongoose/issues/detail?id=79 // http://code.google.com/p/mongoose/issues/detail?id=79
@@ -3399,7 +3523,7 @@ static int scan_directory(struct connection *conn, const char *dir,
return arr_ind; return arr_ind;
} }
int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) { size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
static const char *dont_escape = "._-$,;~()"; static const char *dont_escape = "._-$,;~()";
static const char *hex = "0123456789abcdef"; static const char *hex = "0123456789abcdef";
size_t i = 0, j = 0; size_t i = 0, j = 0;
@@ -3502,9 +3626,9 @@ static void send_directory_listing(struct connection *conn, const char *dir) {
qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries); qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries);
for (i = 0; i < num_entries; i++) { for (i = 0; i < num_entries; i++) {
print_dir_entry(&arr[i]); print_dir_entry(&arr[i]);
free(arr[i].file_name); NS_FREE(arr[i].file_name);
} }
free(arr); NS_FREE(arr);
write_terminating_chunk(conn); write_terminating_chunk(conn);
close_local_endpoint(conn); close_local_endpoint(conn);
@@ -3572,9 +3696,9 @@ static void handle_propfind(struct connection *conn, const char *path,
struct dir_entry *de = &arr[i]; struct dir_entry *de = &arr[i];
mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf)); mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
print_props(conn, buf, &de->st); print_props(conn, buf, &de->st);
free(de->file_name); NS_FREE(de->file_name);
} }
free(arr); NS_FREE(arr);
} }
ns_send(conn->ns_conn, footer, sizeof(footer) - 1); ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
} }
@@ -3696,7 +3820,7 @@ static void handle_put(struct connection *conn, const char *path) {
static void forward_put_data(struct connection *conn) { static void forward_put_data(struct connection *conn) {
struct iobuf *io = &conn->ns_conn->recv_iobuf; struct iobuf *io = &conn->ns_conn->recv_iobuf;
size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len; // To write size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len; // To write
int n = write(conn->endpoint.fd, io->buf, k); // Write them! size_t n = write(conn->endpoint.fd, io->buf, k); // Write them!
if (n > 0) { if (n > 0) {
iobuf_remove(io, n); iobuf_remove(io, n);
conn->cl -= n; conn->cl -= n;
@@ -3754,6 +3878,23 @@ static FILE *open_auth_file(struct connection *conn, const char *path,
} }
#if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH) #if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
typedef struct MD5Context { typedef struct MD5Context {
uint32_t buf[4]; uint32_t buf[4];
uint32_t bits[2]; uint32_t bits[2];
@@ -4058,33 +4199,28 @@ static int is_authorized_for_dav(struct connection *conn) {
return authorized; return authorized;
} }
static int is_dav_request(const struct connection *conn) {
const char *s = conn->mg_conn.request_method;
return !strcmp(s, "PUT") || !strcmp(s, "DELETE") ||
!strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND");
}
#endif // MONGOOSE_NO_AUTH #endif // MONGOOSE_NO_AUTH
static int parse_header(const char *str, int str_len, const char *var_name, static int parse_header(const char *str, size_t str_len, const char *var_name,
char *buf, size_t buf_size) { char *buf, size_t buf_size) {
int ch = ' ', len = 0, n = strlen(var_name); int ch = ' ', ch1 = ',', len = 0;
size_t n = strlen(var_name);
const char *p, *end = str + str_len, *s = NULL; const char *p, *end = str + str_len, *s = NULL;
if (buf != NULL && buf_size > 0) buf[0] = '\0'; if (buf != NULL && buf_size > 0) buf[0] = '\0';
// Find where variable starts // Find where variable starts
for (s = str; s != NULL && s + n < end; s++) { for (s = str; s != NULL && s + n < end; s++) {
if ((s == str || s[-1] == ' ' || s[-1] == ',') && s[n] == '=' && if ((s == str || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
!memcmp(s, var_name, n)) break; !memcmp(s, var_name, n)) break;
} }
if (s != NULL && &s[n + 1] < end) { if (s != NULL && &s[n + 1] < end) {
s += n + 1; s += n + 1;
if (*s == '"' || *s == '\'') ch = *s++; if (*s == '"' || *s == '\'') ch = ch1 = *s++;
p = s; p = s;
while (p < end && p[0] != ch && p[0] != ',' && len < (int) buf_size) { while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
if (p[0] == '\\' && p[1] == ch) p++; if (ch == ch1 && p[0] == '\\' && p[1] == ch) p++;
buf[len++] = *p++; buf[len++] = *p++;
} }
if (len >= (int) buf_size || (ch != ' ' && *p != ch)) { if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
@@ -4109,7 +4245,7 @@ static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
static void send_file_data(struct mg_connection *conn, FILE *fp) { static void send_file_data(struct mg_connection *conn, FILE *fp) {
char buf[IOBUF_SIZE]; char buf[IOBUF_SIZE];
int n; size_t n;
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
mg_write(conn, buf, n); mg_write(conn, buf, n);
} }
@@ -4544,7 +4680,7 @@ static void try_parse(struct connection *conn) {
// If request is buffered in, remove it from the iobuf. This is because // If request is buffered in, remove it from the iobuf. This is because
// iobuf could be reallocated, and pointers in parsed request could // iobuf could be reallocated, and pointers in parsed request could
// become invalid. // become invalid.
conn->request = (char *) malloc(conn->request_len); conn->request = (char *) NS_MALLOC(conn->request_len);
memcpy(conn->request, io->buf, conn->request_len); memcpy(conn->request, io->buf, conn->request_len);
//DBG(("%p [%.*s]", conn, conn->request_len, conn->request)); //DBG(("%p [%.*s]", conn, conn->request_len, conn->request));
iobuf_remove(io, conn->request_len); iobuf_remove(io, conn->request_len);
@@ -4638,7 +4774,7 @@ static void call_http_client_handler(struct connection *conn) {
iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len); iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
conn->mg_conn.status_code = 0; conn->mg_conn.status_code = 0;
conn->cl = conn->num_bytes_recv = conn->request_len = 0; conn->cl = conn->num_bytes_recv = conn->request_len = 0;
free(conn->request); NS_FREE(conn->request);
conn->request = NULL; conn->request = NULL;
} }
@@ -4662,7 +4798,7 @@ struct mg_connection *mg_connect(struct mg_server *server, const char *addr) {
nsconn = ns_connect(&server->ns_mgr, addr, mg_ev_handler, NULL); nsconn = ns_connect(&server->ns_mgr, addr, mg_ev_handler, NULL);
if (nsconn == NULL) return 0; if (nsconn == NULL) return 0;
if ((conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) { if ((conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
nsconn->flags |= NSF_CLOSE_IMMEDIATELY; nsconn->flags |= NSF_CLOSE_IMMEDIATELY;
return 0; return 0;
} }
@@ -4754,8 +4890,8 @@ static void close_local_endpoint(struct connection *conn) {
// Gobble possible POST data sent to the URI handler // Gobble possible POST data sent to the URI handler
iobuf_free(&conn->ns_conn->recv_iobuf); iobuf_free(&conn->ns_conn->recv_iobuf);
free(conn->request); NS_FREE(conn->request);
free(conn->path_info); NS_FREE(conn->path_info);
conn->endpoint.nc = NULL; conn->endpoint.nc = NULL;
conn->request = conn->path_info = NULL; conn->request = conn->path_info = NULL;
@@ -4763,7 +4899,7 @@ static void close_local_endpoint(struct connection *conn) {
conn->cl = conn->num_bytes_recv = conn->request_len = 0; conn->cl = conn->num_bytes_recv = conn->request_len = 0;
conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA | conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY | NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
MG_HEADERS_SENT | MG_LONG_RUNNING); MG_HEADERS_SENT | MG_USING_CHUNKED_API);
// Do not memset() the whole structure, as some of the fields // Do not memset() the whole structure, as some of the fields
// (IP addresses & ports, server_param) must survive. Nullify the rest. // (IP addresses & ports, server_param) must survive. Nullify the rest.
@@ -4781,7 +4917,7 @@ static void close_local_endpoint(struct connection *conn) {
static void transfer_file_data(struct connection *conn) { static void transfer_file_data(struct connection *conn) {
char buf[IOBUF_SIZE]; char buf[IOBUF_SIZE];
int n; size_t n;
// If output buffer is too big, don't send anything. Wait until // If output buffer is too big, don't send anything. Wait until
// mongoose drains already buffered data to the client. // mongoose drains already buffered data to the client.
@@ -4802,7 +4938,7 @@ static void transfer_file_data(struct connection *conn) {
} }
} }
int mg_poll_server(struct mg_server *server, int milliseconds) { time_t mg_poll_server(struct mg_server *server, int milliseconds) {
return ns_mgr_poll(&server->ns_mgr, milliseconds); return ns_mgr_poll(&server->ns_mgr, milliseconds);
} }
@@ -4813,9 +4949,9 @@ void mg_destroy_server(struct mg_server **server) {
ns_mgr_free(&s->ns_mgr); ns_mgr_free(&s->ns_mgr);
for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) { for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
free(s->config_options[i]); // It is OK to free(NULL) NS_FREE(s->config_options[i]); // It is OK to free(NULL)
} }
free(s); NS_FREE(s);
*server = NULL; *server = NULL;
} }
} }
@@ -4941,7 +5077,7 @@ void mg_copy_listeners(struct mg_server *s, struct mg_server *to) {
for (c = ns_next(&s->ns_mgr, NULL); c != NULL; c = ns_next(&s->ns_mgr, c)) { for (c = ns_next(&s->ns_mgr, NULL); c != NULL; c = ns_next(&s->ns_mgr, c)) {
struct ns_connection *tmp; struct ns_connection *tmp;
if ((c->flags & NSF_LISTENING) && if ((c->flags & NSF_LISTENING) &&
(tmp = (struct ns_connection *) malloc(sizeof(*tmp))) != NULL) { (tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) {
memcpy(tmp, c, sizeof(*tmp)); memcpy(tmp, c, sizeof(*tmp));
tmp->mgr = &to->ns_mgr; tmp->mgr = &to->ns_mgr;
ns_add_conn(tmp->mgr, tmp); ns_add_conn(tmp->mgr, tmp);
@@ -4988,7 +5124,7 @@ const char *mg_set_option(struct mg_server *server, const char *name,
} }
if (*v != NULL) { if (*v != NULL) {
free(*v); NS_FREE(*v);
*v = NULL; *v = NULL;
} }
@@ -4998,7 +5134,14 @@ const char *mg_set_option(struct mg_server *server, const char *name,
DBG(("%s [%s]", name, *v)); DBG(("%s [%s]", name, *v));
if (ind == LISTENING_PORT) { if (ind == LISTENING_PORT) {
char buf[500] = "";
size_t n = 0;
struct vec vec; struct vec vec;
/*
* Ports can be specified as 0, meaning that OS has to choose any
* free port that is available. In order to pass chosen port number to
* the user, we rewrite all 0 port to chosen values.
*/
while ((value = next_option(value, &vec, NULL)) != NULL) { while ((value = next_option(value, &vec, NULL)) != NULL) {
struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr, struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr,
mg_ev_handler, NULL); mg_ev_handler, NULL);
@@ -5006,17 +5149,28 @@ const char *mg_set_option(struct mg_server *server, const char *name,
error_msg = "Cannot bind to port"; error_msg = "Cannot bind to port";
break; break;
} else { } else {
char buf[100]; char buf2[50], cert[100], ca[100];
ns_sock_to_str(c->sock, buf, sizeof(buf), 2); union socket_address sa;
free(*v); int proto, use_ssl;
ns_parse_address(vec.ptr, &sa, &proto, &use_ssl, cert, ca);
ns_sock_to_str(c->sock, buf2, sizeof(buf2),
memchr(vec.ptr, ':', vec.len) == NULL ? 2 : 3);
n += snprintf(buf + n, sizeof(buf) - n, "%s%s%s%s%s%s%s",
n > 0 ? "," : "",
use_ssl ? "ssl://" : "",
buf2, cert[0] ? ":" : "", cert, ca[0] ? ":" : "", ca);
}
}
buf[sizeof(buf) - 1] = '\0';
NS_FREE(*v);
*v = mg_strdup(buf); *v = mg_strdup(buf);
}
}
#ifndef MONGOOSE_NO_FILESYSTEM #ifndef MONGOOSE_NO_FILESYSTEM
} else if (ind == HEXDUMP_FILE) { } else if (ind == HEXDUMP_FILE) {
server->ns_mgr.hexdump_file = *v; server->ns_mgr.hexdump_file = *v;
#endif #endif
#ifndef _WIN32 #if !defined(_WIN32) && !defined(MONGOOSE_NO_USER)
} else if (ind == RUN_AS_USER) { } else if (ind == RUN_AS_USER) {
struct passwd *pw; struct passwd *pw;
if ((pw = getpwnam(value)) == NULL) { if ((pw = getpwnam(value)) == NULL) {
@@ -5050,7 +5204,7 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
if (!check_acl(server->config_options[ACCESS_CONTROL_LIST], if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
ntohl(* (uint32_t *) &sa->sin.sin_addr)) || ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
(conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) { (conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
nc->flags |= NSF_CLOSE_IMMEDIATELY; nc->flags |= NSF_CLOSE_IMMEDIATELY;
} else { } else {
// Circularly link two connection structures // Circularly link two connection structures
@@ -5162,7 +5316,7 @@ static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
call_user(conn, MG_CLOSE); call_user(conn, MG_CLOSE);
close_local_endpoint(conn); close_local_endpoint(conn);
conn->ns_conn = NULL; conn->ns_conn = NULL;
free(conn); NS_FREE(conn);
} }
break; break;
@@ -5209,7 +5363,7 @@ static void iter2(struct ns_connection *nc, int ev, void *param) {
(void) ev; (void) ev;
//DBG(("%p [%s]", conn, msg)); //DBG(("%p [%s]", conn, msg));
if (sscanf(msg, "%p %n", &func, &n) && func != NULL) { if (sscanf(msg, "%p %n", &func, &n) && func != NULL && conn != NULL) {
conn->mg_conn.callback_param = (void *) (msg + n); conn->mg_conn.callback_param = (void *) (msg + n);
func(&conn->mg_conn, MG_POLL); func(&conn->mg_conn, MG_POLL);
} }
@@ -5242,7 +5396,7 @@ const char *mg_get_option(const struct mg_server *server, const char *name) {
} }
struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) { struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server)); struct mg_server *server = (struct mg_server *) NS_CALLOC(1, sizeof(*server));
ns_mgr_init(&server->ns_mgr, server_data); ns_mgr_init(&server->ns_mgr, server_data);
set_default_option_values(server->config_options); set_default_option_values(server->config_options);
server->event_handler = handler; server->event_handler = handler;
+10 -11
View File
@@ -2,28 +2,27 @@
// Copyright (c) 2013-2014 Cesanta Software Limited // Copyright (c) 2013-2014 Cesanta Software Limited
// All rights reserved // All rights reserved
// //
// This library is dual-licensed: you can redistribute it and/or modify // This software is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this // published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>. // license, see <http://www.gnu.org/licenses/>.
// //
// You are free to use this library under the terms of the GNU General // You are free to use this software under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied // Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details. // See the GNU General Public License for more details.
// //
// Alternatively, you can license this library under a commercial // Alternatively, you can license this software under a commercial
// license, as set out in <http://cesanta.com/>. // license, as set out in <http://cesanta.com/>.
//
// $Date: 2014-09-09 17:07:55 UTC $
#ifndef MONGOOSE_HEADER_INCLUDED #ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED #define MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_VERSION "5.5" #define MONGOOSE_VERSION "5.6"
#include <stdio.h> // required for FILE #include <stdio.h> // required for FILE
#include <stddef.h> // required for size_t #include <stddef.h> // required for size_t
#include <sys/types.h> // required for time_t
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -53,7 +52,7 @@ struct mg_connection {
int is_websocket; // Connection is a websocket connection int is_websocket; // Connection is a websocket connection
int status_code; // HTTP status code for HTTP error handler int status_code; // HTTP status code for HTTP error handler
int wsbits; // First byte of the websocket frame int wsbits; // First byte of the websocket frame
void *server_param; // Parameter passed to mg_add_uri_handler() void *server_param; // Parameter passed to mg_create_server()
void *connection_param; // Placeholder for connection-specific data void *connection_param; // Placeholder for connection-specific data
void *callback_param; void *callback_param;
}; };
@@ -90,7 +89,7 @@ enum {
struct mg_server *mg_create_server(void *server_param, mg_handler_t handler); struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
void mg_destroy_server(struct mg_server **); void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val); const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
int mg_poll_server(struct mg_server *, int milliseconds); time_t mg_poll_server(struct mg_server *, int milliseconds);
const char **mg_get_valid_option_names(void); const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name); const char *mg_get_option(const struct mg_server *server, const char *name);
void mg_copy_listeners(struct mg_server *from, struct mg_server *to); void mg_copy_listeners(struct mg_server *from, struct mg_server *to);
@@ -104,7 +103,7 @@ void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name, const char *val); void mg_send_header(struct mg_connection *, const char *name, const char *val);
size_t mg_send_data(struct mg_connection *, const void *data, int data_len); size_t mg_send_data(struct mg_connection *, const void *data, int data_len);
size_t mg_printf_data(struct mg_connection *, const char *format, ...); size_t mg_printf_data(struct mg_connection *, const char *format, ...);
size_t mg_write(struct mg_connection *, const void *buf, int len); size_t mg_write(struct mg_connection *, const void *buf, size_t len);
size_t mg_printf(struct mg_connection *conn, const char *fmt, ...); size_t mg_printf(struct mg_connection *conn, const char *fmt, ...);
size_t mg_websocket_write(struct mg_connection *, int opcode, size_t mg_websocket_write(struct mg_connection *, int opcode,
@@ -130,8 +129,8 @@ int mg_parse_multipart(const char *buf, int buf_len,
void *mg_start_thread(void *(*func)(void *), void *param); void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...); char *mg_md5(char buf[33], ...);
int mg_authorize_digest(struct mg_connection *c, FILE *fp); int mg_authorize_digest(struct mg_connection *c, FILE *fp);
int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len); size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int); int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int);
int mg_terminate_ssl(struct mg_connection *c, const char *cert); int mg_terminate_ssl(struct mg_connection *c, const char *cert);
int mg_forward(struct mg_connection *c, const char *addr); int mg_forward(struct mg_connection *c, const char *addr);
void *mg_mmap(FILE *fp, size_t size); void *mg_mmap(FILE *fp, size_t size);
+13 -9
View File
@@ -120,8 +120,8 @@ static const char *test_parse_http_message() {
ASSERT(strcmp(ri.http_version, "1.1") == 0); ASSERT(strcmp(ri.http_version, "1.1") == 0);
ASSERT(ri.num_headers == 0); ASSERT(ri.num_headers == 0);
ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == -1); ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == (size_t) ~0);
ASSERT(parse_http_message(req6, 0, &ri) == -1); ASSERT(parse_http_message(req6, 0, &ri) == (size_t) ~0);
ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1); ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1);
// TODO(lsm): Fix this. Header value may span multiple lines. // TODO(lsm): Fix this. Header value may span multiple lines.
@@ -198,17 +198,19 @@ static const char *test_match_prefix(void) {
} }
static const char *test_remove_double_dots() { static const char *test_remove_double_dots() {
struct { char before[20], after[20]; } data[] = { struct { char before[30], after[30]; } data[] = {
{"////a", "/a"}, {"////a", "/a"},
{"/.....", "/."}, {"/.....", "/....."},
{"/......", "/"}, {"/......", "/......"},
{"...", "..."}, {"...", "..."},
{"/...///", "/./"}, {"/...///", "/.../"},
{"/a...///", "/a.../"}, {"/a...///", "/a.../"},
{"/.x", "/.x"}, {"/.x", "/.x"},
{"/\\", "/"}, {"/\\", "/"},
{"/a\\", "/a\\"}, {"/a\\", "/a\\"},
{"/a\\\\...", "/a\\."}, {"/a\\\\...", "/a\\..."},
{"foo/x..y/././y/../../..", "foo/x..y/y/"},
{"foo/..x", "foo/..x"},
}; };
size_t i; size_t i;
@@ -261,6 +263,7 @@ static const char *test_url_decode(void) {
ASSERT(strcmp(buf, "a ") == 0); ASSERT(strcmp(buf, "a ") == 0);
ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1); ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
printf("[%s]\n", buf);
ASSERT(strcmp(buf, "%") == 0); ASSERT(strcmp(buf, "%") == 0);
ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2); ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
@@ -306,9 +309,9 @@ static const char *test_base64_encode(void) {
} }
static const char *test_mg_parse_header(void) { static const char *test_mg_parse_header(void) {
const char *str = "xx=1 kl yy, ert=234 kl=123, " const char *str = "xx=1 kl yy, ert=234 kl=123, uri=\"/?name=x,y\", "
"ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234"; "ii=\"12\\\"34\" zz='aa bb',tt=2,gf=\"xx d=1234";
char buf[10]; char buf[20];
ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0); ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0);
ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3); ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3);
ASSERT(strcmp(buf, "234") == 0); ASSERT(strcmp(buf, "234") == 0);
@@ -331,6 +334,7 @@ static const char *test_mg_parse_header(void) {
ASSERT(strcmp(buf, "12\"34") == 0); ASSERT(strcmp(buf, "12\"34") == 0);
ASSERT(mg_parse_header(str, "tt", buf, sizeof(buf)) == 1); ASSERT(mg_parse_header(str, "tt", buf, sizeof(buf)) == 1);
ASSERT(strcmp(buf, "2") == 0); ASSERT(strcmp(buf, "2") == 0);
ASSERT(mg_parse_header(str, "uri", buf, sizeof(buf)) == 10);
return NULL; return NULL;
} }