Compare commits

..
122 Commits
Author SHA1 Message Date
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
xant 9e118c8a31 bugfix: set the correct status if we still have pending data 2014-01-31 19:09:12 +01:00
34 changed files with 2261 additions and 1769 deletions

No files matched your search

+2 -2
View File
@@ -5,7 +5,7 @@ All rights reserved
This code 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.
license, see <http://www.gnu.org/licenses>.
You are free to use this code under the terms of the GNU General
Public License, but WITHOUT ANY WARRANTY; without even the implied
@@ -13,4 +13,4 @@ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
Alternatively, you can license this code under a commercial
license, as set out in http://cesanta.com/products.html.
license, as set out in <http://cesanta.com/>.
+6 -3
View File
@@ -1,14 +1,17 @@
# Mongoose Web Server
Mongoose is easy to use, powerful, embeddable web server.
* [Downloads](http://cesanta.com/downloads.html)
* [Documentation](http://cesanta.com/docs.html)
* [Mailing list](http://groups.google.com/group/mongoose-users)
* [Downloads & Documentation](http://cesanta.com/mongoose.shtml)
* [How to use Lua Server Pages](http://cesanta.com/docs/Lua.shtml)
* [How to create basic website with Mongoose](http://cesanta.com/docs/BasicWebsite.shtml)
* [How to create PHP website with Mongoose](http://cesanta.com/docs/PhpWebsite.shtml)
* [Embedding Guide](http://cesanta.com/docs/Embed.shtml)
# Features
- Works on Windows, Mac, UNIX/Linux, iPhone, Android, and many other platforms
- CGI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, URL rewrite, file blacklist, IP-based ACL, Windows service
- CGI, SSI, SSL, Digest auth, Websocket, WEbDAV, Resumed download, URL rewrite, file blacklist, Custom error pages, Virtual hosts, IP-based ACL, Windows service
- Scripting and database support ([Lua](http://lua.org) +
[Sqlite](http://sqlite.org), see
[dirscan.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/dirscan.lp) ),
+86 -53
View File
@@ -7,8 +7,7 @@ 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.
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.
@@ -17,10 +16,7 @@ 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()`.
of active connections and configuration parameters.
Side-effect: on UNIX, `mg_create_server()` ignores SIGPIPE signals. If custom
processing is required SIGPIPE, signal handler must be set up after
@@ -38,57 +34,80 @@ 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,
Sets a particular server option. 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
will not access filesystem at all. `mg_set_option()` 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
`mg_poll_server()` (Mongoose 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
Performs one iteration of IO loop by iterating over all
active connections, performing `select()` syscall on all sockets with a timeout
of `milliseconds` number of milliseconds. When `select()` returns, Mongoose
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).
mutex-protect `struct mg_server *`, therefore only single thread
(Mongoose thread) should make Mongoose calls.
void mg_set_auth_handler(struct mg_server *, mg_handler_t handler);
`mg_poll_server()` calls user-specified event handler when certain events
occur. Sequence of events for the accepted connection is this:
Sets authorization handler. Called by Mongoose on each request, before
performing any other action. Handler can return either `MG_AUTH_OK` or
`MG_AUTH_FAIL`. If `handler` returns `MG_AUTH_FAIL`, then Mongoose sends
digest authorization request to the client. If `handler returns `MG_AUTH_OK`,
then mongoose proceeds with handling the request. Handler function can use
`mg_authorize_digest()` function to verify authorization, or implement any other
custom authorization mechanism.
* `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
handler returns `MG_FALSE`, then Mongoose does not serve the request but
sends authorization request to the client. If `MG_TRUE` is returned,
then Mongoose continues on with the request.
* `MG_REQUEST` - Mongoose asks event handler to serve the request. If
event handler serves the request by sending a reply,
it should return `MG_TRUE`. Otherwise,
it should return `MG_FALSE` which tells Mongoose that request is not
served and Mongoose should serve it. For example, event handler might
choose to serve only RESTful API requests with URIs that start with
certain prefix, and let Mongoose serve all static files.
If event handler decides to serve the request, but doesn't have
all the data at the moment, it should return `MG_MORE`. That tells
Mongoose to send `MG_POLL` events on each iteration of `mg_poll_server()`
void mg_set_request_handler(struct mg_server *, mg_handler_t handler);
`mg_connection::connection_param` pointer is a placeholder to keep
user-specific data. For example, handler could decide to open a DB
connection and store DB connection handle in `connection_param`.
* `MG_POLL` is sent only to those connections which returned `MG_MORE`.
Event handler should try to complete the reply. If reply is completed,
then event handler should return `MG_TRUE`. Otherwise, it should
return `MG_FALSE`, and polling will continue until
handler returns `MG_TRUE`.
* `MG_HTTP_ERROR` sent when Mongoose is about to send HTTP error back
to the client. Event handler can choose to send a reply itself, in which
case event handler must return `MG_TRUE`. Otherwise, event handler must
return `MG_FALSE`
* `MG_CLOSE` is sent when the connection is closed. This event is used
to cleanup per-connection state stored in `connection_param`
if it was allocated.
Sets a request handler. When set, `handler` will be called for each request.
Possible return values from a handler function are `MG_REQUEST_NOT_PROCESSED`,
`MG_REQUEST_PROCESSED` and `MG_REQUEST_CALL_AGAIN`. If handler returns
`MG_REQUEST_NOT_PROCESSED`, mongoose will proceed with handling the request.
If handler returns `MG_REQUEST_PROCESSED`, that signals mongoose that handler
has already processed the connection, and mongoose will skip to the next
request. `MG_REQUEST_CALL_AGAIN` tells mongoose to call request handler
again and again on each `mg_poll_server()` iteration.
Sequence of events for the client connection is this:
When mongoose buffers in HTTP request and successfully parses it, it calls
appropriate URI handler immediately for GET requests. For POST requests,
* `MG_CONNECT` sent when Mongoose has connected to the remote host.
This event is sent to the connection initiated by `mg_connect()` call.
Connection status is held in `mg_connection::status_code`: if zero,
then connection was successful, otherwise connection was not established.
User should send a request upon successful connection.
* `MG_REPLY` is sent when response has been received from the remote host.
* `MG_CLOSE` same as for the accepted connection.
When mongoose buffers in HTTP request and successfully parses it, it sends
`MG_REQUEST` event for GET requests immediately. 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
websocket frame in memory, and calls event 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
@@ -96,18 +115,8 @@ 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_data()` should be used. Note that
websocket handler must return either `MG_CLIENT_CLOSE` or `MG_CLIENT_CONTINUE`
value.
To reply to the plain HTTP client, `mg_write_data()` 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.
Hanlder should return either `MG_ERROR_PROCESSED` or `MG_ERROR_NOT_PROCESSED`.
If handler returns `MG_ERROR_NOT_PROCESSED`, 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);
@@ -124,16 +133,22 @@ 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);
void mg_iterate_over_connections(struct mg_server *, mg_handler_t func);
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.
connections at any time. This function could be called from the Mongoose thread
only. When it returns, Mongoose thread calls `func()` for each active
connection.
It is allowed to call `mg_send_data()` or `mg_websocket_write()` within a
callback, cause `func` is executed in the context of the Mongoose thread.
void mg_wakeup_server(struct mg_server *);
Makes `mg_poll_server()` that could be sleeping in the `select()` syscall
to break the call and return. This function can be called from any thread.
It is designed to let other threads wake up Mongoose thread from the sleep
and let it do a fresh new IO iteration over all connection. Usually it is done
when other threads decides there is new data ready to be sent by Mongoose.
void mg_send_status(struct mg_connection *, int status_code);
void mg_send_header(struct mg_connection *, const char *name,
@@ -206,3 +221,21 @@ 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.
int mg_parse_multipart(const char *buf, int buf_len,
char *var_name, int var_name_len,
char *file_name, int file_name_len,
const char **data, int *data_len);
Parses a buffer that contains multipart form data. Stores chunk name
in a `var_name` buffer. If chunk is an uploaded file, then `file_name`
will have a file name. `data` and `data_len` will point to the chunk data.
Returns number of bytes to skip to the next chunk.
struct mg_connection *mg_connect(struct mg_server *server,
const char *host, int port, int use_ssl);
Create connection to the remote host. Returns `NULL` on error, non-null
if the connection has been scheduled for connection. Upon a connection,
Mongoose will send `MG_CONNECT` event to the event handler.
+2 -2
View File
@@ -7,7 +7,7 @@ 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`
- Run `/path-to-ndk/ndk-build -C /path-to-mongoose/examples`
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.
@@ -15,7 +15,7 @@ Note : You dont need root access to run mongoose on Android.
- 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)
![screenshot](http://cesanta.com/images/android_build.png)
Notes:
+34
View File
@@ -0,0 +1,34 @@
How To Create A PHP Website With Mongoose
===========================================
## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
![screenshot](http://cesanta.com/images/tut_basic/tut1.png)
## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
![screenshot](http://cesanta.com/images/tut_basic/tut2.png)
## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML code:
![screenshot](http://cesanta.com/images/tut_basic/tut3.png)
## 4. Save this file as `index.html`:
![screenshot](http://cesanta.com/images/tut_basic/tut4.png)
## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
![screenshot](http://cesanta.com/images/tut_basic/tut5.png)
## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
![screenshot](http://cesanta.com/images/tut_basic/tut6.png)
## 7. Click on the mongoose icon and choose "Start browser" menu:
![screenshot](http://cesanta.com/images/tut_basic/tut7.png)
## 8. A browser will popup displaying `index.html` file. Now, you can expand your website by adding more content.
![screenshot](http://cesanta.com/images/tut_basic/tut8.png)
+102 -37
View File
@@ -13,34 +13,77 @@ Embedding Mongoose is done in two steps:
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
struct mg_server *server = mg_create_server(NULL, NULL);
mg_set_option(server, "document_root", "."); // Serve current directory
mg_set_option(server, "listening_port", "8080"); // Open 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
To compile it, put `mongoose.c`, `mongoose.h` and `app.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
cc app.c mongoose.c -pthread -o app # on Unix
cl.exe 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
It is possible to generate HTML page content. Mongoose can call user-defined
function when certain events occur.
That function is called _an event handler_, and it is the second parameter
to `mg_create_server()` function. Here is the example event handler function:
int event_handler(struct mg_connection *conn, enum mg_event ev) {
switch (ev) {
case MG_AUTH: return MG_TRUE;
default: return MG_FALSE;
}
}
Event handler is called by Mongoose with `struct mg_connection *`
pointer and an event number. `struct mg_connection *conn`
has all information about the request: HTTP headers, POST or websocket
data buffer, etcetera.
data buffer, etcetera. `enum mg_event ev` tells which exactly event is sent.
For each event, an event handler returns a value which tells Mongoose how
to behave.
The sequence of events for every connection is this:
* `MG_AUTH` - Mongoose asks whether this connection is authorized. If event
handler returns `MG_FALSE`, then Mongoose does not serve the request but
sends authorization request to the client. If `MG_TRUE` is returned,
then Mongoose continues on with the request.
* `MG_REQUEST` - Mongoose asks event handler to serve the request. If
event handler serves the request by sending a reply,
it should return `MG_TRUE`. Otherwise,
it should return `MG_FALSE` which tells Mongoose that request is not
served and Mongoose should serve it. For example, event handler might
choose to serve only RESTful API requests with URIs that start with
certain prefix, and let Mongoose serve all static files.
If event handler decides to serve the request, but doesn't have
all the data at the moment, it should return `MG_MORE`. That tells
Mongoose to send `MG_POLL` events on each iteration of `mg_poll_server()`
`mg_connection::connection_param` pointer is a placeholder to keep
user-specific data. For example, handler could decide to open a DB
connection and store DB connection handle in `connection_param`.
* `MG_POLL` is sent only to those connections which returned `MG_MORE`.
Event handler should try to complete the reply. If reply is completed,
then event handler should return `MG_TRUE`. Otherwise, it should
return `MG_FALSE`, and polling will continue until
handler returns `MG_TRUE`.
* `MG_CLOSE` is sent when the connection is closed. This event is used
to cleanup per-connection state stored in `connection_param`
if it was allocated.
Let's extend our minimal application example and
create an URI that will be served by user's C code. The app will handle
@@ -50,22 +93,46 @@ 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;
static int event_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_AUTH) {
return MG_TRUE; // Authorize all requests
} else if (ev == MG_REQUEST && !strcmp(conn->uri, "/hello")) {
mg_printf_data(conn, "%s", "Hello world");
return MG_TRUE; // Mark as processed
} else {
return MG_FALSE; // Rest of the events are not processed
}
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
struct mg_server *server = mg_create_server(NULL, event_handler);
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
for (;;) {
mg_poll_server(server, 1000); // Infinite loop, Ctrl-C to stop
}
mg_destroy_server(&server);
return 0;
}
## Example code
Mongoose source code contains a well-commented example code, listed below:
* [hello.c](https://github.com/cesanta/mongoose/blob/master/examples/hello.c)
a minimalistic hello world example
* [post.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to handle form input
* [upload.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to upload files
* [websocket.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates websocket usage
* [auth.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates API-controlled Digest authorization
* [mjpg.c](https://github.com/cesanta/mongoose/blob/master/examples/mjpg.c) demonstrates MJPEG streaming implementation
## Compilation flags
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
@@ -73,6 +140,12 @@ 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.
Note that some flags start with `NS_` prefix. This is because Mongoose uses
[Net Skeleton](http://github.com/cesanta/net_skeleton) as a low-level
networking engine. If user code has `#include <net_skeleton.h>`, then
all Net Skeleton functions will be available too.
-DMONGOOSE_NO_AUTH Disable MD5 authorization support
-DMONGOOSE_NO_CGI Disable CGI support
-DMONGOOSE_NO_DAV Disable WebDAV support
@@ -84,25 +157,17 @@ a couple of kilobytes to the executable size, and also has some runtime penalty.
-DMONGOOSE_NO_WEBSOCKET Disable WebSocket support
-DMONGOOSE_USE_IDLE_TIMEOUT_SECONDS=X Idle connection timeout, default is 30
-DMONGOOSE_USE_IPV6 Enable IPv6 support
-DMONGOOSE_USE_LUA Enable Lua scripting
-DMONGOOSE_USE_LUA_SQLITE3 Enable sqlite3 binding for Lua
-DMONGOOSE_USE_SSL Enable SSL
-DMONGOOSE_USE_POST_SIZE_LIMIT=X POST requests larger than X will be
rejected, not set by default
-DMONGOOSE_USE_EXTRA_HTTP_HEADERS=X Append X to the HTTP headers
for static files, empty by default
-DMONGOOSE_USE_STACK_SIZE=X Let mg_start_thread() use stack
size X, default is OS default
-DMONGOOSE_ENABLE_DEBUG Enables debug messages on stdout, very noisy
Mongoose source code contains a well-commented example code, listed below:
* [hello.c](https://github.com/cesanta/mongoose/blob/master/examples/hello.c)
a minimalistic hello world example
* [post.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to handle form input
* [upload.c](https://github.com/cesanta/mongoose/blob/master/examples/post.c)
shows how to upload files
* [websocket.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates websocket usage
* [auth.c](https://github.com/cesanta/mongoose/blob/master/examples/websocket.c) demonstrates API-controlled Digest authorization
-DNS_ENABLE_DEBUG Enables debug messages on stdout, very noisy
-DNS_ENABLE_SSL Enable SSL
-DNS_ENABLE_IPV6 Enable IPv6 support
-DNS_ENABLE_HEXDUMP Enables hexdump of sent and received traffic
-DNS_STACK_SIZE=X Sets stack size to X for ns_start_thread()
-DNS_DISABLE_THREADS Disable threads support
-DNS_DISABLE_SOCKETPAIR For systems without loopback interface
+19
View File
@@ -0,0 +1,19 @@
How To Share Files With Mongoose
===========================================
## 1. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside the directory you want to share:
![screenshot](http://cesanta.com/images/tut_sharing/tut1.png)
## 2. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
![screenshot](http://cesanta.com/images/tut_sharing/tut2.png)
## 3. Click on the mongoose icon and choose "Start browser" menu:
![screenshot](http://cesanta.com/images/tut_sharing/tut3.png)
## 4. A browser will popup displaying files. That's all! To access those files from another computer, start a browser and type `http://<your_machine_ip_address>:8080/` in the address bar.
![screenshot](http://cesanta.com/images/tut_sharing/tut4.png)
## Tip: to find out what is your machine IP address, take a look at http://windows.microsoft.com/en-us/windows/find-computers-ip-address
+9 -17
View File
@@ -4,16 +4,16 @@ 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
for it's speed and small size. Mongoose uses Lua version 5.2.3, the
documentation for it can be found at
[Lua 5.2 reference manual](http://www.lua.org/manual/5.2/).
To create a Lua Page, make a file that is called `<something>.lp`. For example,
let's say it is going to be `my_page.lp`. It is important to have a file
To create a Lua Page, make a file that is called `ANY_NAME.lp`. For example,
`my_page.lp`. It is important to have a file
name that ends up with `.lp`, cause this is the way mongoose recognises
Lua Page file. The contents of the file, just like
with PHP, is HTML with embedded Lua code. Lua code must be enclosed within
`<? ?>` blocks, and can appear anywhere on the page.
`&lt;? ?&gt;` blocks, and can appear anywhere on the page.
Mongoose does not send HTTP headers for Lua pages. Therefore,
every Lua Page must begin with HTTP status line and headers, like this:
@@ -27,26 +27,18 @@ 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.
Information about the request is available via the `mg.request_info` object.
I contains request method, all headers, etcetera. Please refer to
`struct mg_request_info` definition in
[mongoose.h](https://github.com/cesanta/mongoose/blob/master/mongoose.h)
to see what is available 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.
to see what is available via the `mg.request_info` object.
Check out [prime_numbers.lp](https://github.com/cesanta/mongoose/blob/master/examples/lua/prime_numbers.lp) for some example.
Mongoose exports the following to the Lua server page:
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:
@@ -56,4 +48,4 @@ to include the content of another file, one can write:
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.
variable is visible in all following blocks.
+28 -21
View File
@@ -10,7 +10,7 @@ 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
the last match wins. Example: `$ mongoose -access_control_list -0.0.0.0/0,+192.168/16` to deny all acccesses except those from `192.168/16` subnet. To learn
more about subnet masks, see the
[Wikipedia page on Subnetwork](http://en.wikipedia.org/wiki/Subnetwork)
@@ -24,27 +24,32 @@ mongoose executable. Default: not set, no query logging is done.
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
Path to an executable to be used use as an interpreter for __all__ CGI scripts
regardless script extension. 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.
or file paths relative to the directory where mongoose executable 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`.
**Note**: PHP scripts must use `php-cgi.exe`, 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.
use `/path/to/cgi-bin/**.cgi` as a pattern. Note that **full file path** is
matched against the pattern, not the URI.
When Mongoose starts CGI program, it creates new environment for it (in
contrast, usually child program inherits the environment from parent). Several
environment variables however are inherited from Mongoose's environment,
they are: `PATH`, `TMP`, `TEMP`, `TMPDIR`, `PERLLIB`, `MONGOOSE_CGI`. On UNIX
it is also `LD_LIBRARY_PATH`. On Windows it is also `COMSPEC`, `SYSTEMROOT`,
`SystemDrive`, `ProgramFiles`, `ProgramFiles(x86)`, `CommonProgramFiles(x86)`.
Default: `**.cgi$|**.pl$|**.php$`
@@ -60,10 +65,6 @@ 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:
@@ -86,7 +87,7 @@ must be for a file name only, not including directory name, e.g.
not set.
### idle\_timeout\_ms
Timeout for idle connections. Default: 30000 (30 seconds)
Timeout for idle connections in milliseconds. Default: `30000` (30 seconds)
### index_files
Comma-separated list of files to be treated as directory index
@@ -107,7 +108,7 @@ will bind to all addresses. Default: 8080.
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
$ sudo mongoose -listening_port 80 -run_as_user nobody
Default: not set.
@@ -116,17 +117,20 @@ 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,
requested URI, then `document_root` is ignored. Instead,
`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. If `uri_patters`
`uri_pattern`, as all mongoose patterns, is a prefix pattern. If `uri_pattern`
is a number, then it is treated as HTTP error code, and `file_or_directory_path`
should be an URI to redirect to. Mongoose will issue `302` temporary redirect
to the specified URI, appending two parameters:
`?code=<http_error_code&orig_uri=<original_uri>`.
to the specified URI with following parameters:
`?code=HTTP_ERROR_CODE&orig_uri=ORIGINAL_URI&query_string=QUERY_STRING`.
This makes it possible to serve many directories outside from `document_root`,
redirect all requests to scripts, and do other tricky things. Examples:
If `uri_pattern` starts with `@` symbol, then Mongoose compares
it with the `HOST` header of the request. If they are equal, Mongoose sets
document root to `file_or_directory_path`, implementing virtual hosts support.
Examples:
# Redirect all accesses to `.doc` files to a special script
mongoose -url_rewrites **.doc$=/path/to/cgi-bin/handle_doc.cgi
@@ -137,4 +141,7 @@ redirect all requests to scripts, and do other tricky things. Examples:
# Redirect 404 errors to a specific error page
mongoose -url_rewrites 404=/cgi-bin/error.cgi
# Virtual hosts example: serve foo.com domain from different directory
mongoose -url_rewrites @foo.com=/var/www/foo.com
Default: not set.
+49
View File
@@ -0,0 +1,49 @@
How To Create A PHP Website With Mongoose
===========================================
## 1. Create a directory which will contain your website files. For example, on drive `C:\`, create a directory called `my_website`:
![screenshot](http://cesanta.com/images/tut_php/tut1.png)
## 2. Inside `my_website` directory, create a new file called "index". This will be the default web page shown when the website is visited.
![screenshot](http://cesanta.com/images/tut_php/tut2.png)
## 3. Open index file with your favorite editor (for example, Notepad) and enter some HTML / PHP code:
![screenshot](http://cesanta.com/images/tut_php/tut3.png)
## 4. Save this file as `index.php`:
![screenshot](http://cesanta.com/images/tut_php/tut4.png)
## 5. Download Mongoose executable from http://cesanta.com/mongoose.shtml and copy the executable inside `my_website` directory:
![screenshot](http://cesanta.com/images/tut_php/tut5.png)
## 6. Double-click mongoose executable. An icon will appear on a system tray in the bottom right corner of the desktop:
![screenshot](http://cesanta.com/images/tut_php/tut6.png)
## 7. Download PHP 5.3 zip (do NOT download PHP 5.5 cause you might have missing DLLs problem) from http://windows.php.net/download and extract it to `C:\php5` directory:
![screenshot](http://cesanta.com/images/tut_php/tut7.png)
## 8. Click on the mongoose icon and choose "Edit Settings" menu.:
![screenshot](http://cesanta.com/images/tut_php/tut8.png)
## 9. A settings dialog will appear. Click on `cgi_interpreter` button:
![screenshot](http://cesanta.com/images/tut_php/tut9.png)
## 10. Choose `C:\php5\php-cgi.exe` and click "Save Settings":
![screenshot](http://cesanta.com/images/tut_php/tut10.png)
## 11. Click on the mongoose icon and choose "Start browser" menu:
![screenshot](http://cesanta.com/images/tut_php/tut11.png)
## 12. A browser will popup displaying `index.php`.
![screenshot](http://cesanta.com/images/tut_php/tut12.png)
+11 -10
View File
@@ -2,13 +2,13 @@
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,
to share any directory, just drop mongoose executable 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
Right-click on the icon to pop up a menu, where it is possible to stop
mongoose, or configure it.
On UNIX, `mongoose` is a command line utility. Running `mongoose` in
@@ -68,17 +68,18 @@ 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.
** 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
# Pattern Meaning
**.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:
+40 -32
View File
@@ -1,54 +1,62 @@
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
DLL_FLAGS = -DLUA_COMPAT_ALL -I../build
CFLAGS = -W -Wall -I.. -pthread -g -pipe $(CFLAGS_EXTRA)
RM = rm -rf
OUT = -o $@
ifeq ($(OS),Windows_NT)
MSVC = ../../vc6
RM = del /q /f
OUT =
CC = $(MSVC)/bin/cl
CFLAGS = /MD /TC /nologo /W3 /I$(MSVC)/include /I..
CFLAGS += /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
CFLAGS += $(CFLAGS_EXTRA)
else
UNAME_S := $(shell uname -s)
DLL_FLAGS += -shared
ifeq ($(UNAME_S),Linux)
CFLAGS += -ldl
endif
ifeq ($(UNAME_S),Darwin)
# DLL_FLAGS += -bundle -undefined dynamic_lookup -dynamiclib
DLL_FLAGS += -flat_namespace -undefined suppress -dynamiclib
endif
endif
all: websocket_html.c
$(CC) hello.c ../mongoose.c -o hello $(CFLAGS)
$(CC) websocket.c websocket_html.c ../mongoose.c -o websocket $(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) auth.c ../mongoose.c -o auth $(CFLAGS)
$(CC) server.c ../mongoose.c -o server $(CFLAGS)
all: hello websocket server post multi_threaded upload auth
# To enable Lua in a server, uncomment following lines
LUA = ../lua-5.2.3/src
#CFLAGS += -I$(LUA) -L$(LUA) -llua -DMONGOOSE_USE_LUA
server: server.c ../mongoose.c
$(CC) server.c ../mongoose.c $(OUT) $(CFLAGS)
hello: hello.c ../mongoose.c
$(CC) hello.c ../mongoose.c $(OUT) $(CFLAGS)
websocket: websocket_html.c websocket.c ../mongoose.c
$(CC) websocket.c websocket_html.c ../mongoose.c $(OUT) $(CFLAGS)
post: post.c ../mongoose.c
$(CC) post.c ../mongoose.c $(OUT) $(CFLAGS)
multi_threaded: multi_threaded.c ../mongoose.c
$(CC) multi_threaded.c ../mongoose.c $(OUT) $(CFLAGS)
upload: upload.c ../mongoose.c
$(CC) upload.c ../mongoose.c $(OUT) $(CFLAGS)
auth: auth.c ../mongoose.c
$(CC) auth.c ../mongoose.c $(OUT) $(CFLAGS)
mjpg: mjpg.c ../mongoose.c
$(CC) mjpg.c ../mongoose.c $(OUT) $(CFLAGS)
# $(CC) chat.c ../mongoose.c -o chat $(CFLAGS)
# $(CC) lua_dll.c ../build/lua_5.2.1.c -o $@.so $(CFLAGS) $(DLL_FLAGS)
websocket_html.c: websocket.html
perl mkdata.pl $< > $@
MSVC = ../../vc6
CL = $(MSVC)/bin/cl
CLFLAGS = /MD /TC /nologo $(DBG) /W3 \
/I$(MSVC)/include /I.. /Dsnprintf=_snprintf
LFLAGS = /link /incremental:no /libpath:$(MSVC)/lib /machine:IX86
windows: websocket_html.c
$(CL) hello.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) websocket.c websocket_html.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) auth.c ../mongoose.c $(CLFLAGS) $(LFLAGS)
$(CL) server.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
u:
g++ unit_test.c -Wall -W -pedantic -lssl -g -O0 $(CFLAGS_EXTRA) && ./a.out
clean:
-@$(RM) hello upload post websocket chat *.exe *.dSYM *.obj .*o
-@$(RM) hello mjpg upload post websocket auth server multi_threaded websocket_html.c *.exe *.dSYM *.obj .*o
+15 -11
View File
@@ -2,25 +2,29 @@
#include <string.h>
#include "mongoose.h"
static int auth_handler(struct mg_connection *conn) {
int result = MG_AUTH_FAIL; // Not authorized
FILE *fp;
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
// To populate passwords file, do
// mongoose -A my_passwords.txt mydomain.com admin admin
if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
result = mg_authorize_digest(conn, fp);
fclose(fp);
if (ev == MG_AUTH) {
int result = MG_FALSE; // Not authorized
FILE *fp;
// To populate passwords file, do
// mongoose -A my_passwords.txt mydomain.com admin admin
if ((fp = fopen("my_passwords.txt", "r")) != NULL) {
result = mg_authorize_digest(conn, fp);
fclose(fp);
}
return result;
}
return result;
return MG_FALSE;
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
struct mg_server *server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
mg_set_option(server, "document_root", ".");
mg_set_auth_handler(server, auth_handler);
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
+8 -379
View File
@@ -1,386 +1,15 @@
// This file is part of the Mongoose project, http://code.google.com/p/mongoose
// It implements an online chat server. For more details,
// see the documentation on the project web site.
// To test the application,
// 1. type "make" in the directory where this file lives
// 2. point your browser to http://127.0.0.1:8081
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <pthread.h>
#include "mongoose.h"
#define MAX_USER_LEN 20
#define MAX_MESSAGE_LEN 100
#define MAX_MESSAGES 5
#define MAX_SESSIONS 2
#define SESSION_TTL 120
static const char *authorize_url = "/authorize";
static const char *login_url = "/login.html";
static const char *ajax_reply_start =
"HTTP/1.1 200 OK\r\n"
"Cache: no-cache\r\n"
"Content-Type: application/x-javascript\r\n"
"\r\n";
// Describes single message sent to a chat. If user is empty (0 length),
// the message is then originated from the server itself.
struct message {
long id; // Message ID
char user[MAX_USER_LEN]; // User that have sent the message
char text[MAX_MESSAGE_LEN]; // Message text
time_t timestamp; // Message timestamp, UTC
};
// Describes web session.
struct session {
char session_id[33]; // Session ID, must be unique
char random[20]; // Random data used for extra user validation
char user[MAX_USER_LEN]; // Authenticated user
time_t expire; // Expiration timestamp, UTC
};
static struct message messages[MAX_MESSAGES]; // Ringbuffer for messages
static struct session sessions[MAX_SESSIONS]; // Current sessions
static long last_message_id;
// Protects messages, sessions, last_message_id
static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// Get session object for the connection. Caller must hold the lock.
static struct session *get_session(const struct mg_connection *conn) {
int i;
const char *cookie = mg_get_header(conn, "Cookie");
char session_id[33];
time_t now = time(NULL);
mg_get_cookie(cookie, "session", session_id, sizeof(session_id));
for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire != 0 &&
sessions[i].expire > now &&
strcmp(sessions[i].session_id, session_id) == 0) {
break;
}
}
return i == MAX_SESSIONS ? NULL : &sessions[i];
}
static void get_qsvar(const struct mg_request_info *request_info,
const char *name, char *dst, size_t dst_len) {
const char *qs = request_info->query_string;
mg_get_var(qs, strlen(qs == NULL ? "" : qs), name, dst, dst_len);
}
// Get a get of messages with IDs greater than last_id and transform them
// into a JSON string. Return that string to the caller. The string is
// dynamically allocated, caller must free it. If there are no messages,
// NULL is returned.
static char *messages_to_json(long last_id) {
const struct message *message;
int max_msgs, len;
char buf[sizeof(messages)]; // Large enough to hold all messages
// Read-lock the ringbuffer. Loop over all messages, making a JSON string.
pthread_rwlock_rdlock(&rwlock);
len = 0;
max_msgs = sizeof(messages) / sizeof(messages[0]);
// If client is too far behind, return all messages.
if (last_message_id - last_id > max_msgs) {
last_id = last_message_id - max_msgs;
}
for (; last_id < last_message_id; last_id++) {
message = &messages[last_id % max_msgs];
if (message->timestamp == 0) {
break;
}
// buf is allocated on stack and hopefully is large enough to hold all
// messages (it may be too small if the ringbuffer is full and all
// messages are large. in this case asserts will trigger).
len += snprintf(buf + len, sizeof(buf) - len,
"{user: '%s', text: '%s', timestamp: %lu, id: %lu},",
message->user, message->text, message->timestamp, message->id);
assert(len > 0);
assert((size_t) len < sizeof(buf));
}
pthread_rwlock_unlock(&rwlock);
return len == 0 ? NULL : strdup(buf);
}
// If "callback" param is present in query string, this is JSONP call.
// Return 1 in this case, or 0 if "callback" is not specified.
// Wrap an output in Javascript function call.
static int handle_jsonp(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char cb[64];
get_qsvar(request_info, "callback", cb, sizeof(cb));
if (cb[0] != '\0') {
mg_printf(conn, "%s(", cb);
}
return cb[0] == '\0' ? 0 : 1;
}
// A handler for the /ajax/get_messages endpoint.
// Return a list of messages with ID greater than requested.
static void ajax_get_messages(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char last_id[32], *json;
int is_jsonp;
mg_printf(conn, "%s", ajax_reply_start);
is_jsonp = handle_jsonp(conn, request_info);
get_qsvar(request_info, "last_id", last_id, sizeof(last_id));
if ((json = messages_to_json(strtoul(last_id, NULL, 10))) != NULL) {
mg_printf(conn, "[%s]", json);
free(json);
}
if (is_jsonp) {
mg_printf(conn, "%s", ")");
}
}
// Allocate new message. Caller must hold the lock.
static struct message *new_message(void) {
static int size = sizeof(messages) / sizeof(messages[0]);
struct message *message = &messages[last_message_id % size];
message->id = last_message_id++;
message->timestamp = time(0);
return message;
}
static void my_strlcpy(char *dst, const char *src, size_t len) {
strncpy(dst, src, len);
dst[len - 1] = '\0';
}
// A handler for the /ajax/send_message endpoint.
static void ajax_send_message(struct mg_connection *conn,
const struct mg_request_info *request_info) {
struct message *message;
struct session *session;
char text[sizeof(message->text) - 1];
int is_jsonp;
mg_printf(conn, "%s", ajax_reply_start);
is_jsonp = handle_jsonp(conn, request_info);
get_qsvar(request_info, "text", text, sizeof(text));
if (text[0] != '\0') {
// We have a message to store. Write-lock the ringbuffer,
// grab the next message and copy data into it.
pthread_rwlock_wrlock(&rwlock);
message = new_message();
// TODO(lsm): JSON-encode all text strings
session = get_session(conn);
assert(session != NULL);
my_strlcpy(message->text, text, sizeof(text));
my_strlcpy(message->user, session->user, sizeof(message->user));
pthread_rwlock_unlock(&rwlock);
}
mg_printf(conn, "%s", text[0] == '\0' ? "false" : "true");
if (is_jsonp) {
mg_printf(conn, "%s", ")");
}
}
// Redirect user to the login form. In the cookie, store the original URL
// we came from, so that after the authorization we could redirect back.
static void redirect_to_login(struct mg_connection *conn,
const struct mg_request_info *request_info) {
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Set-Cookie: original_url=%s\r\n"
"Location: %s\r\n\r\n",
request_info->uri, login_url);
}
// Return 1 if username/password is allowed, 0 otherwise.
static int check_password(const char *user, const char *password) {
// In production environment we should ask an authentication system
// to authenticate the user.
// Here however we do trivial check that user and password are not empty
return (user[0] && password[0]);
}
// Allocate new session object
static struct session *new_session(void) {
int i;
time_t now = time(NULL);
pthread_rwlock_wrlock(&rwlock);
for (i = 0; i < MAX_SESSIONS; i++) {
if (sessions[i].expire == 0 || sessions[i].expire < now) {
sessions[i].expire = time(0) + SESSION_TTL;
break;
}
}
pthread_rwlock_unlock(&rwlock);
return i == MAX_SESSIONS ? NULL : &sessions[i];
}
// Generate session ID. buf must be 33 bytes in size.
// Note that it is easy to steal session cookies by sniffing traffic.
// This is why all communication must be SSL-ed.
static void generate_session_id(char *buf, const char *random,
const char *user) {
mg_md5(buf, random, user, NULL);
}
static void send_server_message(const char *fmt, ...) {
va_list ap;
struct message *message;
pthread_rwlock_wrlock(&rwlock);
message = new_message();
message->user[0] = '\0'; // Empty user indicates server message
va_start(ap, fmt);
vsnprintf(message->text, sizeof(message->text), fmt, ap);
va_end(ap);
pthread_rwlock_unlock(&rwlock);
}
// A handler for the /authorize endpoint.
// Login page form sends user name and password to this endpoint.
static void authorize(struct mg_connection *conn,
const struct mg_request_info *request_info) {
char user[MAX_USER_LEN], password[MAX_USER_LEN];
struct session *session;
// Fetch user name and password.
get_qsvar(request_info, "user", user, sizeof(user));
get_qsvar(request_info, "password", password, sizeof(password));
if (check_password(user, password) && (session = new_session()) != NULL) {
// Authentication success:
// 1. create new session
// 2. set session ID token in the cookie
// 3. remove original_url from the cookie - not needed anymore
// 4. redirect client back to the original URL
//
// The most secure way is to stay HTTPS all the time. However, just to
// show the technique, we redirect to HTTP after the successful
// authentication. The danger of doing this is that session cookie can
// be stolen and an attacker may impersonate the user.
// Secure application must use HTTPS all the time.
my_strlcpy(session->user, user, sizeof(session->user));
snprintf(session->random, sizeof(session->random), "%d", rand());
generate_session_id(session->session_id, session->random, session->user);
send_server_message("<%s> joined", session->user);
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Set-Cookie: session=%s; max-age=3600; http-only\r\n" // Session ID
"Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code
"Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url
"Location: /\r\n\r\n",
session->session_id, session->user);
} else {
// Authentication failure, redirect to login.
redirect_to_login(conn, request_info);
}
}
// Return 1 if request is authorized, 0 otherwise.
static int is_authorized(const struct mg_connection *conn,
const struct mg_request_info *request_info) {
struct session *session;
char valid_id[33];
int authorized = 0;
// Always authorize accesses to login page and to authorize URI
if (!strcmp(request_info->uri, login_url) ||
!strcmp(request_info->uri, authorize_url)) {
return 1;
}
pthread_rwlock_rdlock(&rwlock);
if ((session = get_session(conn)) != NULL) {
generate_session_id(valid_id, session->random, session->user);
if (strcmp(valid_id, session->session_id) == 0) {
session->expire = time(0) + SESSION_TTL;
authorized = 1;
}
}
pthread_rwlock_unlock(&rwlock);
return authorized;
}
static void redirect_to_ssl(struct mg_connection *conn,
const struct mg_request_info *request_info) {
const char *p, *host = mg_get_header(conn, "Host");
if (host != NULL && (p = strchr(host, ':')) != NULL) {
mg_printf(conn, "HTTP/1.1 302 Found\r\n"
"Location: https://%.*s:8082/%s:8082\r\n\r\n",
(int) (p - host), host, request_info->uri);
} else {
mg_printf(conn, "%s", "HTTP/1.1 500 Error\r\n\r\nHost: header is not set");
}
}
static int event_handler(struct mg_event *event) {
struct mg_request_info *request_info = event->request_info;
struct mg_connection *conn = event->conn;
int result = 1;
if (event->type != MG_REQUEST_BEGIN) return 0;
if (!request_info->is_ssl) {
redirect_to_ssl(conn, request_info);
} else if (!is_authorized(conn, request_info)) {
redirect_to_login(conn, request_info);
} else if (strcmp(request_info->uri, authorize_url) == 0) {
authorize(conn, request_info);
} else if (strcmp(request_info->uri, "/ajax/get_messages") == 0) {
ajax_get_messages(conn, request_info);
} else if (strcmp(request_info->uri, "/ajax/send_message") == 0) {
ajax_send_message(conn, request_info);
} else {
// No suitable handler found, mark as not processed. Mongoose will
// try to serve the request.
result = 0;
}
return result;
}
static const char *options[] = {
"document_root", "html",
"listening_ports", "8081,8082s",
"ssl_certificate", "ssl_cert.pem",
"num_threads", "5",
NULL
};
int main(void) {
struct mg_context *ctx;
struct mg_server *server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080");
mg_set_option(server, "document_root", "chat_html_root");
// Initialize random number generator. It will be used later on for
// the session identifier creation.
srand((unsigned) time(0));
// Setup and start Mongoose
if ((ctx = mg_start(options, event_handler, NULL)) == NULL) {
printf("%s\n", "Cannot start chat server, fatal exit");
exit(EXIT_FAILURE);
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
// Wait until enter is pressed, then exit
printf("Chat server started on ports %s, press enter to quit.\n",
mg_get_option(ctx, "listening_ports"));
getchar();
mg_stop(ctx);
printf("%s\n", "Chat server stopped.");
return EXIT_SUCCESS;
return 0;
}
// vim:ts=2:sw=2:et
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -3,7 +3,7 @@
var chat = {
// Backend URL, string.
// 'http://backend.address.com' or '' if backend is the same as frontend
backendUrl: '',
backendUrl: 'api.lp',
maxVisibleMessages: 10,
errorMessageFadeOutTimeoutMs: 2000,
errorMessageFadeOutTimer: null,
@@ -20,7 +20,7 @@ chat.refresh = function(data) {
if (data === undefined) {
return;
}
$.each(data, function(index, entry) {
var row = $('<div>').addClass('message-row').appendTo('#mml');
var timestamp = (new Date(entry.timestamp * 1000)).toLocaleTimeString();
@@ -49,9 +49,7 @@ chat.refresh = function(data) {
chat.getMessages = function(enter_loop) {
$.ajax({
dataType: 'jsonp',
url: chat.backendUrl + '/ajax/get_messages',
data: {last_id: chat.lastMessageId},
data: {last_id: chat.lastMessageId, cmd: 'get_messages'},
success: chat.refresh,
error: function() {
},
@@ -82,9 +80,7 @@ chat.handleMessageInput = function(ev) {
return;
//input.disabled = true;
$.ajax({
dataType: 'jsonp',
url: chat.backendUrl + '/ajax/send_message',
data: {text: input.value},
data: { text: input.value, cmd: 'send_message' },
success: function(ev) {
input.value = '';
input.disabled = false;
@@ -98,6 +94,10 @@ chat.handleMessageInput = function(ev) {
};
$(document).ready(function() {
$.ajaxSetup({
dataType: 'json',
url: chat.backendUrl
});
$('.menu-item').click(chat.handleMenuItemClick);
$('.message-input').keypress(chat.handleMessageInput);
chat.getMessages(true);
File renamed without changes.
+2 -2
View File
@@ -23,7 +23,7 @@ static int index_html(struct mg_connection *conn) {
}
}
return n < sizeof(buf) ? 1 : 0;
return n < sizeof(buf) ? MG_REQUEST_PROCESSED : MG_REQUEST_CALL_AGAIN;
}
int main(void) {
@@ -32,7 +32,7 @@ int main(void) {
// Create and configure the server
server = mg_create_server(NULL);
mg_set_option(server, "listening_port", "8080");
mg_add_uri_handler(server, "/", index_html);
mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
+12 -6
View File
@@ -2,19 +2,25 @@
#include <string.h>
#include "mongoose.h"
// This function will be called by mongoose on every new request
static int index_html(struct mg_connection *conn) {
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
return MG_REQUEST_PROCESSED;
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
int result = MG_FALSE;
if (ev == MG_REQUEST) {
mg_printf_data(conn, "Hello! Requested URI is [%s]", conn->uri);
result = MG_TRUE;
} else if (ev == MG_AUTH) {
result = MG_TRUE;
}
return result;
}
int main(void) {
struct mg_server *server;
// Create and configure the server
server = mg_create_server(NULL);
server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
+12
View File
@@ -0,0 +1,12 @@
LOCAL_PATH := $(call my-dir)/../..
include $(CLEAR_VARS)
# To build with lua support, uncomment two lines below:
#LUA_SOURCES := build/lua_5.2.1.c build/sqlite3.c build/lsqlite3.c
#LUA_FLAGS := -I$(LOCAL_PATH)/build -DTHREADSAFE=1 -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DUSE_LUA -DUSE_LUA_SQLITE3 -DLUA_COMPAT_ALL -D"getlocaledecpoint() ='.'"
LOCAL_CFLAGS := -std=c99 -O2 -W -Wall -pthread -pipe $(LUA_FLAGS) $(COPT)
LOCAL_MODULE := mongoose
LOCAL_SRC_FILES := examples/server.c mongoose.c $(LUA_SOURCES)
include $(BUILD_EXECUTABLE)
+94
View File
@@ -0,0 +1,94 @@
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "mongoose.h"
static void send_file(struct mg_connection *conn, const char *path) {
char buf[1024];
struct stat st;
int n;
FILE *fp;
if (stat(path, &st) == 0 && (fp = fopen(path, "rb")) != NULL) {
mg_printf(conn, "--myboundary\r\nContent-Type: image/jpeg\r\n"
"Content-Length: %zu\r\n\r\n", st.st_size);
while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
mg_write(conn, buf, n);
}
fclose(fp);
mg_write(conn, "\r\n", 2);
}
}
struct conn_state {
int file_index;
time_t last_poll;
};
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
const char **file_names = (const char **) conn->server_param;
struct conn_state *state;
int result = MG_FALSE;
if (ev == MG_REQUEST) {
mg_printf(conn, "%s",
"HTTP/1.0 200 OK\r\n" "Cache-Control: no-cache\r\n"
"Pragma: no-cache\r\nExpires: Thu, 01 Dec 1994 16:00:00 GMT\r\n"
"Connection: close\r\nContent-Type: multipart/x-mixed-replace; "
"boundary=--myboundary\r\n\r\n");
send_file(conn, file_names[0]);
state = (struct conn_state *) malloc(sizeof(*state));
conn->connection_param = state;
state->file_index = 1; // First file is already sent
state->last_poll = time(NULL);
result = MG_MORE;
} else if (ev == MG_POLL) {
time_t now = time(NULL);
state = (struct conn_state *) conn->connection_param;
if (state != NULL && now > state->last_poll) {
if (file_names[state->file_index] != NULL) {
send_file(conn, file_names[state->file_index]);
state->file_index++;
if (file_names[state->file_index] == NULL) {
result = MG_TRUE; // No more images, close connection
}
}
state->last_poll = now;
}
} else if (ev == MG_CLOSE) {
free(conn->connection_param);
conn->connection_param = NULL;
} else if (ev == MG_AUTH) {
result = MG_TRUE;
}
return result;
}
int main(int argc, char *argv[]) {
struct mg_server *server;
if (argc < 3) {
printf("Usage: %s image1.jpg image2.jpg ...\n", argv[0]);
return 1;
}
server = mg_create_server(&argv[1], ev_handler);
mg_set_option(server, "listening_port", "8080");
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
+13 -10
View File
@@ -2,11 +2,17 @@
// Start a browser and hit refresh couple of times. The replies will
// come from both server instances.
static int request_handler(struct mg_connection *conn) {
mg_send_header(conn, "Content-Type", "text/plain");
mg_printf_data(conn, "This is a reply from server instance # %s",
(char *) conn->server_param);
return MG_REQUEST_PROCESSED;
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
mg_send_header(conn, "Content-Type", "text/plain");
mg_printf_data(conn, "This is a reply from server instance # %s",
(char *) conn->server_param);
return MG_TRUE;
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
static void *serve(void *server) {
@@ -17,11 +23,8 @@ static void *serve(void *server) {
int main(void) {
struct mg_server *server1, *server2;
server1 = mg_create_server((void *) "1");
server2 = mg_create_server((void *) "2");
mg_set_request_handler(server1, request_handler);
mg_set_request_handler(server2, request_handler);
server1 = mg_create_server((void *) "1", ev_handler);
server2 = mg_create_server((void *) "2", ev_handler);
// Make both server1 and server2 listen on the same socket
mg_set_option(server1, "listening_port", "8080");
+16 -4
View File
@@ -10,7 +10,7 @@ static const char *html_form =
"<input type=\"submit\" />"
"</form></body></html>";
static int handler(struct mg_connection *conn) {
static void send_reply(struct mg_connection *conn) {
char var1[500], var2[500];
if (strcmp(conn->uri, "/handle_post_request") == 0) {
@@ -33,18 +33,30 @@ static int handler(struct mg_connection *conn) {
// Show HTML form.
mg_send_data(conn, html_form, strlen(html_form));
}
}
return MG_REQUEST_PROCESSED;
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
send_reply(conn);
return MG_TRUE;
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
struct mg_server *server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
mg_set_request_handler(server, handler);
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
mg_poll_server(server, 1000);
}
mg_destroy_server(&server);
return 0;
}
+5 -1
View File
@@ -25,6 +25,7 @@
#define _WIN32_WINNT 0x500 // Enable MIIM_BITMAP
#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
#define _XOPEN_SOURCE 600 // For PATH_MAX on linux
#undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h
#include <sys/stat.h>
#include <stdio.h>
@@ -36,6 +37,7 @@
#include <stddef.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include "mongoose.h"
@@ -146,6 +148,8 @@ static void show_usage_and_exit(void) {
exit(EXIT_FAILURE);
}
#define EV_HANDLER NULL
static char *sdup(const char *str) {
char *p;
if ((p = (char *) malloc(strlen(str) + 1)) != NULL) {
@@ -379,7 +383,7 @@ static void start_mongoose(int argc, char *argv[]) {
char *options[MAX_OPTIONS];
int i;
if ((server = mg_create_server(NULL)) == NULL) {
if ((server = mg_create_server(NULL, EV_HANDLER)) == NULL) {
die("%s", "Failed to start Mongoose.");
}
+80 -207
View File
@@ -3,13 +3,13 @@
// cl unit_test.c /MD
#ifndef _WIN32
#define MONGOOSE_USE_IPV6
#define MONGOOSE_USE_SSL
#define NS_ENABLE_IPV6
#define NS_ENABLE_SSL
#endif
#define MONGOOSE_USE_POST_SIZE_LIMIT 999
#define MONGOOSE_POST_SIZE_LIMIT 999
// USE_* definitions must be made before #include "mongoose.c" !
#include "mongoose.c"
#include "../mongoose.c"
#define FAIL(str, line) do { \
printf("Fail on line %d: [%s]\n", line, str); \
@@ -280,32 +280,6 @@ static const char *test_to64(void) {
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[] = {
"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);
}
ASSERT(parse_port_string("0", &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=="};
@@ -365,60 +339,60 @@ static const char *test_next_option(void) {
return NULL;
}
static int cb1(struct mg_connection *conn) {
int result = MG_REQUEST_NOT_PROCESSED;
if (!strcmp(conn->uri, "/cb1")) {
mg_printf(conn, "%s %s %s",
conn->server_param == NULL ? "?" : (char *) conn->server_param,
conn->connection_param == NULL ? "?" : "!", conn->remote_ip);
result = MG_REQUEST_PROCESSED;
static int evh1(struct mg_connection *conn, enum mg_event ev) {
char *buf = (char *) conn->connection_param;
int result = MG_FALSE;
switch (ev) {
case MG_CONNECT:
mg_printf(conn, "GET %s HTTP/1.0\r\n\r\n",
buf[0] == '1' ? "/cb1" : "/non_exist");
result = MG_TRUE;
break;
case MG_HTTP_ERROR:
mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
result = MG_TRUE;
break;
case MG_REQUEST:
if (!strcmp(conn->uri, "/cb1")) {
mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\n%s %s %s",
(char *) conn->server_param,
buf == NULL ? "?" : "!", conn->remote_ip);
result = MG_TRUE;
}
break;
case MG_REPLY:
if (buf != NULL) {
sprintf(buf + 1, "%.*s", (int) conn->content_len, conn->content);
}
break;
case MG_AUTH:
result = MG_TRUE;
break;
default:
break;
}
return result;
}
static int error_handler(struct mg_connection *conn) {
mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
return MG_ERROR_PROCESSED;
}
static int ts1(struct mg_connection *conn) {
if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "%s", "GET /cb1 HTTP/1.0\r\n\r\n");
return MG_CLIENT_CONTINUE;
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
sprintf((char *) conn->connection_param, "%.*s",
(int) conn->content_len, conn->content);
}
return MG_CLIENT_CLOSE;
}
static int ts2(struct mg_connection *conn) {
if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "%s", "GET /non_exist HTTP/1.0\r\n\r\n");
return MG_CLIENT_CONTINUE;
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
sprintf((char *) conn->connection_param, "%s %.*s",
conn->uri, (int) conn->content_len, conn->content);
}
return MG_CLIENT_CLOSE;
}
static const char *test_server(void) {
char buf1[100] = "", buf2[100] = "";
struct mg_server *server = mg_create_server((void *) "foo");
char buf1[100] = "1", buf2[100] = "2";
struct mg_server *server = mg_create_server((void *) "foo", evh1);
struct mg_connection *conn;
ASSERT(server != NULL);
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
mg_set_request_handler(server, cb1);
mg_set_http_error_handler(server, error_handler);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts1, buf1) == 1);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts2, buf2) == 1);
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0)) != NULL);
conn->connection_param = buf1;
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0)) != NULL);
conn->connection_param = buf2;
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
ASSERT(strcmp(buf1, "foo ? 127.0.0.1") == 0);
ASSERT(strcmp(buf2, "404 ERR: 404") == 0);
ASSERT(strcmp(buf1, "1foo ? 127.0.0.1") == 0);
ASSERT(strcmp(buf2, "2ERR: 404") == 0);
ASSERT(strcmp(static_config_options[URL_REWRITES * 2], "url_rewrites") == 0);
mg_destroy_server(&server);
@@ -426,90 +400,6 @@ static const char *test_server(void) {
return NULL;
}
// This http client sends two requests using one connection
static int cb2(struct mg_connection *conn) {
const char *file1 = "mongoose.h", *file2 = "mongoose.c", *file_name = file2;
char *buf = (char *) conn->connection_param, *file_data;
int file_len, ret_val = 1;
switch (conn->status_code) {
case MG_CONNECT_SUCCESS:
mg_printf(conn, "GET /%s HTTP/1.1\r\n\r\n", file1);
strcat(buf, "a");
ret_val = 0;
break;
case MG_CONNECT_FAILURE: strcat(buf, "b"); break;
case MG_DOWNLOAD_FAILURE: strcat(buf, "c"); break;
case MG_DOWNLOAD_SUCCESS:
if (!strcmp(buf, "a")) {
// Send second request
mg_printf(conn, "GET /%s HTTP/1.1\r\n\r\n", file2);
file_name = file1;
}
if ((file_data = read_file(file_name, &file_len)) != NULL) {
if ((size_t) file_len == conn->content_len &&
memcmp(file_data, conn->content, file_len) == 0) {
strcat(buf, "d");
} else {
strcat(buf, "f");
}
free(file_data);
}
ret_val = !strcmp(buf, "ad") ? 0 : 1;
break;
default: strcat(buf, "e"); break;
}
return ret_val;
}
static int cb4h(struct mg_connection *conn) {
int result = MG_REQUEST_NOT_PROCESSED;
if (!strcmp(conn->uri, "/x")) {
mg_send_data(conn, ":-)", 3);
result = MG_REQUEST_PROCESSED;
}
return result;
}
static int cb4(struct mg_connection *conn) {
if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "%s", "POST /x HTTP/1.0\r\nContent-Length: 999999\r\n\r\n");
return MG_CLIENT_CONTINUE;
} else {
sprintf((char *) conn->connection_param, "%.*s",
(int) conn->content_len, conn->content);
}
return MG_CLIENT_CLOSE;
}
static int cb3(struct mg_connection *conn) {
sprintf((char *) conn->connection_param, "%d", conn->status_code);
return MG_CLIENT_CLOSE;
}
static const char *test_mg_connect(void) {
char buf2[40] = "", buf3[40] = "", buf4[40] = "";
struct mg_server *server = mg_create_server(NULL);
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
mg_set_request_handler(server, cb4h);
ASSERT(mg_connect(server, "", 0, 0, NULL, NULL) == 0);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1);
ASSERT(mg_connect(server, "127.0.0.1", 29, 0, cb3, buf3) == 1);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb4, buf4) == 1);
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
ASSERT(strcmp(buf2, "add") == 0);
ASSERT(strcmp(buf3, "1") == 0);
ASSERT(strcmp(buf4, "500 Server Error\nPOST size > 999") == 0);
mg_destroy_server(&server);
return NULL;
}
#define DISP "Content-Disposition: form/data; "
#define CRLF "\r\n"
#define BOUNDARY "--xyz"
@@ -545,49 +435,36 @@ static const char *test_parse_multipart(void) {
return NULL;
}
static int us1(struct mg_connection *conn) {
static const char *file_name = "mongoose.h";
char *cp = (char *) conn->connection_param;
int file_size;
static int evh2(struct mg_connection *conn, enum mg_event ev) {
char *file_data, *cp = (char *) conn->connection_param;
int file_size, result = MG_FALSE;
if (conn->status_code == MG_CONNECT_SUCCESS) {
mg_printf(conn, "GET /%s HTTP/1.0\r\n\r\n", cp);
return 0;
} else if (conn->status_code == MG_DOWNLOAD_SUCCESS) {
char *file_data = read_file(file_name, &file_size);
sprintf(cp, "%d %s", (size_t) file_size == conn->content_len &&
memcmp(file_data, conn->content, file_size) == 0 ? 1 : 0,
conn->query_string == NULL ? "?" : conn->query_string);
free(file_data);
} else if (conn->status_code == MG_CONNECT_FAILURE) {
sprintf(cp, "%s", "cf");
} else {
sprintf(cp, "%s", "df");
switch (ev) {
case MG_AUTH:
result = MG_TRUE;
break;
case MG_CONNECT:
mg_printf(conn, "GET /%s HTTP/1.0\r\n\r\n", cp);
result = MG_TRUE;
break;
case MG_REQUEST:
break;
case MG_REPLY:
file_data = read_file("unit_test.c", &file_size);
sprintf(cp, "%d %s", (size_t) file_size == conn->content_len &&
memcmp(file_data, conn->content, file_size) == 0 ? 1 : 0,
conn->query_string == NULL ? "?" : conn->query_string);
free(file_data);
break;
default:
break;
}
return 1;
return result;
}
#ifdef MONGOOSE_USE_SSL
static const char *test_ssl(void) {
static const char *ssl_cert = "examples/ssl_cert.pem";
char buf1[100] = "mongoose.h";
struct mg_server *server = mg_create_server(NULL);
ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
ASSERT(mg_set_option(server, "ssl_certificate", ssl_cert) == NULL);
ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 1, us1, buf1) == 1);
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
ASSERT(strcmp(buf1, "1 ?") == 0);
mg_destroy_server(&server);
return NULL;
}
#endif
static const char *test_mg_set_option(void) {
struct mg_server *server = mg_create_server(NULL);
struct mg_server *server = mg_create_server(NULL, NULL);
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
mg_destroy_server(&server);
@@ -596,18 +473,19 @@ static const char *test_mg_set_option(void) {
static const char *test_rewrites(void) {
char buf1[100] = "xx";
struct mg_server *server = mg_create_server(NULL);
struct mg_server *server = mg_create_server(NULL, evh2);
struct mg_connection *conn;
const char *port;
ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
ASSERT(mg_set_option(server, "document_root", ".") == NULL);
ASSERT(mg_set_option(server, "url_rewrites", "/xx=./mongoose.h") == NULL);
ASSERT(mg_connect(server, "127.0.0.1",
atoi(mg_get_option(server, "listening_port")),
0, us1, buf1) == 1);
ASSERT(mg_set_option(server, "url_rewrites", "/xx=unit_test.c") == NULL);
ASSERT((port = mg_get_option(server, "listening_port")) != NULL);
ASSERT((conn = mg_connect(server, "127.0.0.1", atoi(port), 0)) != NULL);
conn->connection_param = buf1;
{ int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
//printf("[%s]\n", buf1);
ASSERT(strcmp(buf1, "1 ?") == 0);
mg_destroy_server(&server);
return NULL;
@@ -618,7 +496,6 @@ static const char *run_all_tests(void) {
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);
@@ -626,13 +503,9 @@ static const char *run_all_tests(void) {
RUN_TEST(test_get_var);
RUN_TEST(test_next_option);
RUN_TEST(test_parse_multipart);
RUN_TEST(test_server);
RUN_TEST(test_mg_connect);
RUN_TEST(test_mg_set_option);
RUN_TEST(test_server);
RUN_TEST(test_rewrites);
#ifdef MONGOOSE_USE_SSL
RUN_TEST(test_ssl);
#endif
return NULL;
}
+12 -4
View File
@@ -5,7 +5,7 @@
#include <string.h>
#include "mongoose.h"
static int index_html(struct mg_connection *conn) {
static void send_index_page(struct mg_connection *conn) {
const char *data;
int data_len;
char var_name[100], file_name[100];
@@ -29,17 +29,25 @@ static int index_html(struct mg_connection *conn) {
}
mg_printf_data(conn, "%s", "</body></html>");
}
return MG_REQUEST_PROCESSED;
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
send_index_page(conn);
return MG_TRUE;
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
int main(void) {
struct mg_server *server;
// Create and configure the server
server = mg_create_server(NULL);
server = mg_create_server(NULL, ev_handler);
mg_set_option(server, "listening_port", "8080");
mg_set_request_handler(server, index_html);
// Serve request. Hit Ctrl-C to terminate the program
printf("Starting on port %s\n", mg_get_option(server, "listening_port"));
+28 -12
View File
@@ -1,18 +1,24 @@
#include <string.h>
#include <time.h>
#include "mongoose.h"
#ifdef _WIN32
#define snprintf _snprintf
#endif
extern const char *find_embedded_file(const char *, size_t *);
static int iterate_callback(struct mg_connection *c) {
if (c->is_websocket) {
static int iterate_callback(struct mg_connection *c, enum mg_event ev) {
static int counter = 0;
if (ev == MG_POLL && c->is_websocket) {
char buf[20];
int len = snprintf(buf, sizeof(buf), "%d", * (int *) c->connection_param);
int len = snprintf(buf, sizeof(buf), "%d", counter++);
mg_websocket_write(c, 1, buf, len);
}
return MG_REQUEST_PROCESSED;
return MG_TRUE;
}
static int index_html(struct mg_connection *conn) {
static int send_reply(struct mg_connection *conn) {
size_t index_size;
const char *index_html = find_embedded_file("websocket.html", &index_size);
@@ -22,27 +28,37 @@ static int index_html(struct mg_connection *conn) {
// Echo websocket data back to the client.
mg_websocket_write(conn, 1, conn->content, conn->content_len);
return conn->content_len == 4 && !memcmp(conn->content, "exit", 4) ?
MG_CLIENT_CLOSE : MG_CLIENT_CONTINUE;
MG_FALSE : MG_TRUE;
} else {
mg_send_header(conn, "Content-Type", "text/html");
mg_send_data(conn, index_html, index_size);
return MG_REQUEST_PROCESSED;
return MG_TRUE;
}
}
static int ev_handler(struct mg_connection *conn, enum mg_event ev) {
if (ev == MG_REQUEST) {
return send_reply(conn);
} else if (ev == MG_AUTH) {
return MG_TRUE;
} else {
return MG_FALSE;
}
}
int main(void) {
struct mg_server *server = mg_create_server(NULL);
unsigned int current_timer = 0, last_timer = 0;
struct mg_server *server = mg_create_server(NULL, ev_handler);
time_t current_timer = 0, last_timer = time(NULL);
mg_set_option(server, "listening_port", "8080");
mg_set_request_handler(server, index_html);
printf("Started on port %s\n", mg_get_option(server, "listening_port"));
for (;;) {
current_timer = mg_poll_server(server, 100);
mg_poll_server(server, 100);
current_timer = time(NULL);
if (current_timer - last_timer > 0) {
last_timer = current_timer;
mg_iterate_over_connections(server, iterate_callback, &current_timer);
mg_iterate_over_connections(server, iterate_callback);
}
}
+1 -1
View File
@@ -30,7 +30,7 @@
out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
num_messages++;
}
if (num_messages > 15) {
if (num_messages > 3) {
websocket.send('exit');
}
};
+1540 -926
View File
File diff suppressed because it is too large. Load diff
+27 -21
View File
@@ -20,7 +20,7 @@
#ifndef MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_HEADER_INCLUDED
#define MONGOOSE_VERSION "5.2"
#define MONGOOSE_VERSION "5.3"
#include <stdio.h> // required for FILE
#include <stddef.h> // required for size_t
@@ -58,21 +58,31 @@ struct mg_connection {
};
struct mg_server; // Opaque structure describing server instance
typedef int (*mg_handler_t)(struct mg_connection *);
enum mg_result { MG_FALSE, MG_TRUE, MG_MORE };
enum mg_event {
MG_POLL = 100, // Callback return value is ignored
MG_CONNECT, // If callback returns MG_FALSE, connect fails
MG_AUTH, // If callback returns MG_FALSE, authentication fails
MG_REQUEST, // If callback returns MG_FALSE, Mongoose continues with req
MG_REPLY, // If callback returns MG_FALSE, Mongoose closes connection
MG_CLOSE, // Connection is closed
MG_LUA, // Called before LSP page invoked
MG_HTTP_ERROR // If callback returns MG_FALSE, Mongoose continues with err
};
typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
// Server management functions
struct mg_server *mg_create_server(void *server_param);
struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
void mg_destroy_server(struct mg_server **);
const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
unsigned int mg_poll_server(struct mg_server *, int milliseconds);
void mg_set_request_handler(struct mg_server *, mg_handler_t);
void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
void mg_set_auth_handler(struct mg_server *, mg_handler_t);
int mg_poll_server(struct mg_server *, int milliseconds);
const char **mg_get_valid_option_names(void);
const char *mg_get_option(const struct mg_server *server, const char *name);
void mg_set_listening_socket(struct mg_server *, int sock);
int mg_get_listening_socket(struct mg_server *);
void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
void mg_iterate_over_connections(struct mg_server *, mg_handler_t);
void mg_wakeup_server(struct mg_server *);
struct mg_connection *mg_connect(struct mg_server *, const char *, int, int);
// Connection management functions
void mg_send_status(struct mg_connection *, int status_code);
@@ -102,19 +112,15 @@ void *mg_start_thread(void *(*func)(void *), void *param);
char *mg_md5(char buf[33], ...);
int mg_authorize_digest(struct mg_connection *c, FILE *fp);
// Callback function return codes
enum { MG_REQUEST_NOT_PROCESSED, MG_REQUEST_PROCESSED, MG_REQUEST_CALL_AGAIN };
enum { MG_AUTH_FAIL, MG_AUTH_OK };
enum { MG_ERROR_NOT_PROCESSED, MG_ERROR_PROCESSED };
enum { MG_CLIENT_CONTINUE, MG_CLIENT_CLOSE };
// HTTP client events
enum {
MG_CONNECT_SUCCESS, MG_CONNECT_FAILURE,
MG_DOWNLOAD_SUCCESS, MG_DOWNLOAD_FAILURE
};
int mg_connect(struct mg_server *, const char *host, int port, int use_ssl,
mg_handler_t handler, void *param);
// Lua utility functions
#ifdef MONGOOSE_USE_LUA
#include <lua.h>
#include <lauxlib.h>
void reg_string(lua_State *L, const char *name, const char *val);
void reg_int(lua_State *L, const char *name, int val);
void reg_function(lua_State *L, const char *,
lua_CFunction, struct mg_connection *);
#endif
#ifdef __cplusplus
}