diff options
-rw-r--r-- | 3rdparty/mongoose/README.md | 32 | ||||
-rw-r--r-- | 3rdparty/mongoose/docs/ReleaseNotes.md | 4 | ||||
-rw-r--r-- | 3rdparty/mongoose/examples/array_vars/Makefile | 21 | ||||
-rw-r--r-- | 3rdparty/mongoose/examples/array_vars/array_vars.c | 45 | ||||
-rw-r--r-- | 3rdparty/mongoose/examples/cookie_authentication/cookie_auth.c | 1 | ||||
-rw-r--r-- | 3rdparty/mongoose/examples/file_upload/file_upload.c | 14 | ||||
-rw-r--r-- | 3rdparty/mongoose/examples/web_server/Makefile | 8 | ||||
-rw-r--r-- | 3rdparty/mongoose/examples/web_server/web_server.c | 2 | ||||
-rw-r--r-- | 3rdparty/mongoose/mongoose.c | 228 | ||||
-rw-r--r-- | 3rdparty/mongoose/mongoose.h | 7 | ||||
-rw-r--r-- | 3rdparty/mongoose/test/unit_test.c | 30 |
11 files changed, 281 insertions, 111 deletions
diff --git a/3rdparty/mongoose/README.md b/3rdparty/mongoose/README.md index c0dcc2aaaf8..4b4fc3219ba 100644 --- a/3rdparty/mongoose/README.md +++ b/3rdparty/mongoose/README.md @@ -1,5 +1,7 @@ # <img src="http://cesanta.com/images/mongoose_logo.png" width="64" height="64"> Mongoose Web Server +[](https://gitter.im/cesanta/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + Mongoose is the most easy to use web server on the planet. A web server of choice for Web developers (PHP, Ruby, Python, etc) and Web designers. Mongoose is built on top of Libmongoose embedded library, which can turn @@ -45,24 +47,13 @@ Download, double-click to start, run browser -- that's all!   -# Acknowledgements - -Mongoose made better thanks to the contribution of following people: - -Arnout Vandecappelle, Benoît Amiaux, Boris Pek, Cody Hanson, Colin Leitner, -Daniel Oaks, Eric Bakan, Erik Oomen, Filipp Kovalev, Ger Hobbelt, -Hendrik Polczynski, Igor Okulist, Jay, Joe Mucchiello, John Safranek, -José Miguel Gonçalves, Shueng Chuan, Katerina Blinova, Konstantin Sorokin, -Marin Atanasov, Matt Healy, Mitch Hendrickson, Nigel Stewart, Pavel Khlebovich, -Sebastian Reinhard, Stefan Doehla, abadc0de, nullable.type, -T.Barmann, D.Hughes, J.C.Sloan, R.Romeo, L.E.Spencer, S.Kotay, R.M.Shorter, -W.Mar, J.Wilander, Santa from Memphis, S.Davies, C.Beck, -O.M.Vilhunen, C.Radik, G.Woodcock, M.Szczepkowski, -Eternal Lands Dev Team, T.Tollet, C.Tangerino, G.Karsai, A.Bourgett, -C.Blakemore, D.Fonaryov, T.Andrle, O.IJsselmuiden, R.Womack, M.Tomlinson, -A.Slåttå, L.Farrell, J.D.P.Ballestero, V.Albaev, B.Harker, T.Scheffel, H.Klein, -R.Merit, T.Bennett, H.Solis, A.Zincenko, M.S., S.Krul, K.Cooke, S.McCallum, -F.Morenius, and 10 others. +# Contributions + +People who have agreed to the +[Cesanta CLA](http://cesanta.com/contributors_la.html) +can make contributions. Note that the CLA isn't a copyright +_assigment_ but rather a copyright _license_. +You retain the copyright on your contributions. # Licensing @@ -72,11 +63,11 @@ source licenses. The GPLv2 open source License does not generally permit incorporating this software into non-open source programs. For those customers who do not wish to comply with the GPLv2 open source license requirements, -[Cesanta Software](http://cesanta.com) offers a full, +[Cesanta](http://cesanta.com) offers a full, royalty-free commercial license and professional support without any of the GPL restrictions. -# Other products by Cesanta Software: simple and effective +# Other products by Cesanta - [Fossa](http://github.com/cesanta/fossa) - Multi-protocol networking library - [SSL Wrapper](https://github.com/cesanta/ssl_wrapper) - application to @@ -84,3 +75,4 @@ without any of the GPL restrictions. - [Frozen](https://github.com/cesanta/frozen) - JSON parser and generator - [SLRE](https://github.com/cesanta/slre) - Super Light Regular Expression library +- [V7](https://github.com/cesanta/v7) - Embedded JavaScript engine diff --git a/3rdparty/mongoose/docs/ReleaseNotes.md b/3rdparty/mongoose/docs/ReleaseNotes.md index 24874f824a0..10fd4592609 100644 --- a/3rdparty/mongoose/docs/ReleaseNotes.md +++ b/3rdparty/mongoose/docs/ReleaseNotes.md @@ -168,7 +168,7 @@ Changes in pre-compiled binaries: since mongoose buffers all data prior to calling the callback * keep-alive support is the default * Dropped SSI support and throttling support - * Several configuraition parameters are gone: + * Several configuration parameters are gone: * `cgi_environment` (replaced with MONGOOSE_CGI), * `protect_uri` (not useful) * `ssi_pattern` (SSI support is gone) @@ -214,5 +214,5 @@ Changes in pre-compiled binaries: * Couple of bugfixes, thanks to contributors -Eearlier release notes could be found by searching +Earlier release notes could be found by searching [Mongoose mailing list](https://groups.google.com/forum/#!forum/mongoose-users) diff --git a/3rdparty/mongoose/examples/array_vars/Makefile b/3rdparty/mongoose/examples/array_vars/Makefile new file mode 100644 index 00000000000..5ce2d1db6cb --- /dev/null +++ b/3rdparty/mongoose/examples/array_vars/Makefile @@ -0,0 +1,21 @@ +# Copyright (c) 2014 Cesanta Software +# All rights reserved + +PROG = array_vars +CFLAGS = -W -Wall -I../.. -pthread -g -O0 $(CFLAGS_EXTRA) +SOURCES = $(PROG).c ../../mongoose.c + +all: $(PROG) + +run: $(PROG) + ./$(PROG) + +$(PROG): $(SOURCES) Makefile + $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) + +win: + wine cl $(SOURCES) /MD /nologo /DNDEBUG /O1 /I../.. /Fe$(PROG).exe + wine $(PROG).exe + +clean: + rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib *.gc* diff --git a/3rdparty/mongoose/examples/array_vars/array_vars.c b/3rdparty/mongoose/examples/array_vars/array_vars.c new file mode 100644 index 00000000000..d631a7b0c79 --- /dev/null +++ b/3rdparty/mongoose/examples/array_vars/array_vars.c @@ -0,0 +1,45 @@ +// Copyright (c) 2014 Cesanta Software +// All rights reserved +// +// This example demostrates how to use array get variables using mg_get_n_var +// $Date: 2014-09-09 22:20:23 UTC $ + +#include <stdio.h> +#include <string.h> +#include "mongoose.h" + +static int ev_handler(struct mg_connection *conn, enum mg_event ev) { + switch (ev) { + case MG_AUTH: return MG_TRUE; + case MG_REQUEST: + { + mg_printf_data(conn, "Hello! Requested URI is [%s] ", conn->uri); + char buffer[1024]; + int i, ret; + for(i=0; (ret = mg_get_var_n(conn, "foo[]", buffer, 1024, i)) > 0; i++) + mg_printf_data(conn, "\nfoo[%d] = %s", i, buffer); + + return MG_TRUE; + } + default: return MG_FALSE; + } +} + +int main(void) { + struct mg_server *server; + + // Create and configure the server + server = mg_create_server(NULL, ev_handler); + mg_set_option(server, "listening_port", "8080"); + + // Serve request. Hit Ctrl-C to terminate the program + printf("Starting on port %s\n", mg_get_option(server, "listening_port")); + for (;;) { + mg_poll_server(server, 1000); + } + + // Cleanup, and free server instance + mg_destroy_server(&server); + + return 0; +} diff --git a/3rdparty/mongoose/examples/cookie_authentication/cookie_auth.c b/3rdparty/mongoose/examples/cookie_authentication/cookie_auth.c index f3621faeed7..c35e0445ef2 100644 --- a/3rdparty/mongoose/examples/cookie_authentication/cookie_auth.c +++ b/3rdparty/mongoose/examples/cookie_authentication/cookie_auth.c @@ -58,6 +58,7 @@ static int check_login_form_submission(struct mg_connection *conn) { mg_printf(conn, "HTTP/1.1 302 Moved\r\n" "Set-Cookie: ssid=%s; expire=\"%s\"; http-only; HttpOnly;\r\n" + "Content-Length: 0\r\n" "Location: /\r\n\r\n", ssid, expire); return MG_TRUE; diff --git a/3rdparty/mongoose/examples/file_upload/file_upload.c b/3rdparty/mongoose/examples/file_upload/file_upload.c index f0c6a1a4238..eedfc837c57 100644 --- a/3rdparty/mongoose/examples/file_upload/file_upload.c +++ b/3rdparty/mongoose/examples/file_upload/file_upload.c @@ -7,23 +7,25 @@ static int send_index_page(struct mg_connection *conn) { const char *data; - int data_len, ofs = 0; + int data_len, n1, n2; char var_name[100], file_name[100]; mg_printf_data(conn, "%s", "<html><body>Upload example." "<form method=\"POST\" action=\"/handle_post_request\" " " enctype=\"multipart/form-data\">" - "<input type=\"file\" name=\"file\" /> <br/>" + "<input type=\"file\" name=\"file1\" /> <br/>" + "<input type=\"file\" name=\"file2\" /> <br/>" "<input type=\"submit\" value=\"Upload\" />" "</form>"); - while ((ofs = mg_parse_multipart(conn->content + ofs, conn->content_len - ofs, - var_name, sizeof(var_name), - file_name, sizeof(file_name), - &data, &data_len)) > 0) { + n1 = n2 = 0; + while ((n2 = mg_parse_multipart(conn->content + n1, conn->content_len - n1, + var_name, sizeof(var_name), file_name, + sizeof(file_name), &data, &data_len)) > 0) { mg_printf_data(conn, "var: %s, file_name: %s, size: %d bytes<br>", var_name, file_name, data_len); + n1 += n2; } mg_printf_data(conn, "%s", "</body></html>"); diff --git a/3rdparty/mongoose/examples/web_server/Makefile b/3rdparty/mongoose/examples/web_server/Makefile index ee9bc1b0476..4f9eacb6d06 100644 --- a/3rdparty/mongoose/examples/web_server/Makefile +++ b/3rdparty/mongoose/examples/web_server/Makefile @@ -2,7 +2,7 @@ # All rights reserved PROG = web_server -CFLAGS = -W -Wall -I../.. -pthread -g -O0 -DMONGOOSE_ENABLE_THREADS $(CFLAGS_EXTRA) +CFLAGS = -W -Wall -I../.. -g -O0 $(CFLAGS_EXTRA) SOURCES = $(PROG).c ../../mongoose.c OPENSSL_FLAGS = -DNS_ENABLE_SSL -lssl @@ -13,16 +13,18 @@ SOURCES_POLAR = $(SOURCES) $(POLARSSLCOMPAT_PATH)/polarssl_compat.c INCDIR_POLAR = -I$(POLARSSLCOMPAT_PATH) -I$(POLARSSL_PATH)/include LDFLAGS_POLAR = -L$(POLARSSL_PATH)/lib -lmbedtls CFLAGS_POLAR = $(CFLAGS) $(INCDIR_POLAR) -DNS_ENABLE_SSL -# $(PROG): $(SOURCES) $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) +$(PROG).exe: $(SOURCES) + cl -Fo $(PROG) $(SOURCES) -nologo -MD -I../.. + openssl: $(CC) -o $(PROG) $(SOURCES) $(CFLAGS) $(OPENSSL_FLAGS) polarssl: $(CC) -o $(PROG) $(SOURCES_POLAR) $(LDFLAGS_POLAR) $(CFLAGS_POLAR) - + clean: rm -rf $(PROG) *.exe *.dSYM *.obj *.exp .*o *.lib diff --git a/3rdparty/mongoose/examples/web_server/web_server.c b/3rdparty/mongoose/examples/web_server/web_server.c index 03c13d0aab2..4d256a8fedf 100644 --- a/3rdparty/mongoose/examples/web_server/web_server.c +++ b/3rdparty/mongoose/examples/web_server/web_server.c @@ -40,7 +40,9 @@ #define DIRSEP '\\' #define snprintf _snprintf #define vsnprintf _vsnprintf +#ifndef sleep #define sleep(x) Sleep((x) * 1000) +#endif #define abs_path(rel, abs, abs_size) _fullpath((abs), (rel), (abs_size)) #define SIGCHLD 0 typedef struct _stat file_stat_t; diff --git a/3rdparty/mongoose/mongoose.c b/3rdparty/mongoose/mongoose.c index a12ccdac5d7..c3f72621ab9 100644 --- a/3rdparty/mongoose/mongoose.c +++ b/3rdparty/mongoose/mongoose.c @@ -63,6 +63,10 @@ #pragma warning (disable : 4204) // missing c99 support #endif +#if defined(_WIN32) && !defined(MONGOOSE_NO_CGI) +#define MONGOOSE_ENABLE_THREADS /* Windows uses stdio threads for CGI */ +#endif + #ifndef MONGOOSE_ENABLE_THREADS #define NS_DISABLE_THREADS #endif @@ -91,6 +95,9 @@ #include <BaseTsd.h> typedef SSIZE_T ssize_t; #endif +#ifndef FD_SETSIZE +#define FD_SETSIZE 1024 +#endif #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h> @@ -231,6 +238,7 @@ struct ns_connection { sock_t sock; // Socket union socket_address sa; // Peer address + size_t recv_iobuf_limit; /* Max size of recv buffer */ struct iobuf recv_iobuf; // Received data struct iobuf send_iobuf; // Data scheduled for sending SSL *ssl; @@ -250,6 +258,7 @@ struct ns_connection { #define NSF_WANT_WRITE (1 << 6) #define NSF_LISTENING (1 << 7) #define NSF_UDP (1 << 8) +#define NSF_DISCARD (1 << 9) #define NSF_USER_1 (1 << 20) #define NSF_USER_2 (1 << 21) @@ -326,6 +335,7 @@ int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len); #define NS_CALLOC calloc #endif +#define NS_MAX_SOCKETPAIR_ATTEMPTS 10 #define NS_CTL_MSG_MESSAGE_SIZE (8 * 1024) #define NS_READ_BUFFER_SIZE 2048 #define NS_UDP_RECEIVE_BUFFER_SIZE 2000 @@ -854,7 +864,17 @@ static int ns_is_error(int n) { #ifdef _WIN32 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK #endif - ); + ) +#ifdef NS_ENABLE_SSL + /* + * OpenSSL can return an error when the peer is closing the socket. + * We don't encounter this error with openssl actually, but it's returned + * by our polarssl <-> openssl wrapper who tries to speak the openssl API + * as we understood it. + */ + || n == SSL_AD_CLOSE_NOTIFY +#endif + ; } void ns_sock_to_str(sock_t sock, char *buf, size_t len, int flags) { @@ -1056,7 +1076,7 @@ static void ns_handle_udp(struct ns_connection *ls) { } static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) { - if (sock != INVALID_SOCKET) { + if ( (sock != INVALID_SOCKET) && (sock < FD_SETSIZE) ) { FD_SET(sock, set); if (*max_fd == INVALID_SOCKET || sock > *max_fd) { *max_fd = sock; @@ -1099,7 +1119,9 @@ time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) { tv.tv_sec = milli / 1000; tv.tv_usec = (milli % 1000) * 1000; - if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) > 0) { + if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) < 0) { + return 0; + } else { // select() might have been waiting for a long time, reset current_time // now to prevent last_io_time being set to the past. current_time = time(NULL); @@ -1250,9 +1272,12 @@ void ns_mgr_init(struct ns_mgr *s, void *user_data) { #endif #ifndef NS_DISABLE_SOCKETPAIR - do { - ns_socketpair2(s->ctl, SOCK_DGRAM); - } while (s->ctl[0] == INVALID_SOCKET); + { + int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS; + do { + ns_socketpair2(s->ctl, SOCK_DGRAM); + } while (s->ctl[0] == INVALID_SOCKET && ++attempts < max_attempts); + } #endif #ifdef NS_ENABLE_SSL @@ -1404,7 +1429,7 @@ struct dir_entry { file_stat_t st; }; -// NOTE(lsm): this enum shoulds be in sync with the config_options. +// NOTE(lsm): this enum should be in sync with the config_options. enum { ACCESS_CONTROL_LIST, #ifndef MONGOOSE_NO_FILESYSTEM @@ -1948,13 +1973,21 @@ static void write_chunk(struct connection *conn, const char *buf, int len) { } size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) { - struct connection *c = MG_CONN_2_CONN(conn); va_list ap; + int ret; va_start(ap, fmt); - ns_vprintf(c->ns_conn, fmt, ap); + ret = mg_vprintf(conn, fmt, ap); va_end(ap); + return ret; +} + +size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) { + struct connection *c = MG_CONN_2_CONN(conn); + + ns_vprintf(c->ns_conn, fmt, ap); + return c->ns_conn->send_iobuf.len; } @@ -1973,6 +2006,8 @@ struct threadparam { static int wait_until_ready(sock_t sock, int for_read) { fd_set set; + if ( (sock == INVALID_SOCKET) || (sock >= FD_SETSIZE) ) + return 0; FD_ZERO(&set); FD_SET(sock, &set); select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0); @@ -1992,7 +2027,7 @@ static void *push_to_stdin(void *arg) { if (!WriteFile(tp->hPipe, buf + sent, n - sent, &k, 0)) stop = 1; } } - DBG(("%s", "FORWARED EVERYTHING TO CGI")); + DBG(("%s", "FORWARDED EVERYTHING TO CGI")); CloseHandle(tp->hPipe); NS_FREE(tp); _endthread(); @@ -2312,9 +2347,17 @@ static void open_cgi_endpoint(struct connection *conn, const char *prog) { // Try to create socketpair in a loop until success. ns_socketpair() // can be interrupted by a signal and fail. // TODO(lsm): use sigaction to restart interrupted syscall - do { - ns_socketpair(fds); - } while (fds[0] == INVALID_SOCKET); + { + int attempts = 0, max_attempts = NS_MAX_SOCKETPAIR_ATTEMPTS; + do { + ns_socketpair(fds); + } while (fds[0] == INVALID_SOCKET && ++attempts < max_attempts); + + if (fds[0] == INVALID_SOCKET) { + closesocket(fds[0]); + send_http_error(conn, 500, "ns_socketpair() failed"); + } + } if (start_process(conn->server->config_options[CGI_INTERPRETER], prog, blk.buf, blk.vars, dir, fds[1]) != 0) { @@ -2503,7 +2546,7 @@ static size_t parse_http_message(char *buf, size_t len, buf[len - 1] = '\0'; - // RFC says that all initial whitespaces should be ingored + // RFC says that all initial whitespaces should be ignored while (*buf != '\0' && isspace(* (unsigned char *) buf)) { buf++; } @@ -2677,7 +2720,8 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf, #endif const char *uri = conn->mg_conn.uri; const char *domain = mg_get_header(&conn->mg_conn, "Host"); - size_t match_len, root_len = root == NULL ? 0 : strlen(root); + // Important: match_len has to be declared as int, unless rewrites break. + int match_len, root_len = root == NULL ? 0 : strlen(root); // Perform virtual hosting rewrites if (rewrites != NULL && domain != NULL) { @@ -2784,16 +2828,24 @@ size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) { } size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) { - struct connection *conn = MG_CONN_2_CONN(c); va_list ap; + int ret; + + va_start(ap, fmt); + ret = mg_vprintf_data(c, fmt, ap); + va_end(ap); + + return ret; +} + +size_t mg_vprintf_data(struct mg_connection *c, const char *fmt, va_list ap) { + struct connection *conn = MG_CONN_2_CONN(c); int len; char mem[IOBUF_SIZE], *buf = mem; terminate_headers(c); - va_start(ap, fmt); len = ns_avprintf(&buf, sizeof(mem), fmt, ap); - va_end(ap); if (len >= 0) { write_chunk((struct connection *) conn, buf, len); @@ -2816,7 +2868,7 @@ static int is_big_endian(void) { // Copyright(c) By Steve Reid <steve@edmweb.com> #define SHA1HANDSOFF #if defined(__sun) -//#include "solarisfixes.h" +#include "solarisfixes.h" #endif union char64long16 { unsigned char c[64]; uint32_t l[16]; }; @@ -3033,7 +3085,8 @@ static size_t deliver_websocket_frame(struct connection *conn) { } // Call the handler and remove frame from the iobuf - if (call_user(conn, MG_REQUEST) == MG_FALSE) { + if (call_user(conn, MG_REQUEST) == MG_FALSE || + (buf[0] & 0x0f) == WEBSOCKET_OPCODE_CONNECTION_CLOSE) { conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA; } iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len); @@ -3314,14 +3367,17 @@ static int find_index_file(struct connection *conn, char *path, // If no index file exists, restore directory path if (!found) { - path[n] = '\0'; + path[n] = '/'; + path[n + 1] = '\0'; } return found; } static int parse_range_header(const char *header, int64_t *a, int64_t *b) { - return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); +// return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); +// return sscanf(header, "bytes=%ld-%ld" INT64_FMT, a, b); + return 0; } static void gmt_time_string(char *buf, size_t buf_len, time_t *t) { @@ -3332,7 +3388,7 @@ static void open_file_endpoint(struct connection *conn, const char *path, file_stat_t *st, const char *extra_headers) { char date[64], lm[64], etag[64], range[64], headers[1000]; const char *msg = "OK", *hdr; - time_t curtime = time(NULL); + time_t t, curtime = time(NULL); int64_t r1, r2; struct vec mime_vec; int n; @@ -3362,7 +3418,7 @@ static void open_file_endpoint(struct connection *conn, const char *path, // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 gmt_time_string(date, sizeof(date), &curtime); - time_t t = st->st_mtime; + t = st->st_mtime; // store in local variable for NDK compile gmt_time_string(lm, sizeof(lm), &t); construct_etag(etag, sizeof(etag), st); @@ -3512,11 +3568,11 @@ static int scan_directory(struct connection *conn, const char *dir, } mg_snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name); - // Resize the array if nesessary + // Resize the array if necessary if (arr_ind >= arr_size) { if ((p = (struct dir_entry *) NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) { - // Memset new chunk to zero, otherwize st_mtime will have garbage which + // Memset new chunk to zero, otherwise st_mtime will have garbage which // can make strftime() segfault, see // http://code.google.com/p/mongoose/issues/detail?id=79 memset(p + arr_size, 0, sizeof(**arr) * inc); @@ -3567,6 +3623,7 @@ static void print_dir_entry(const struct dir_entry *de) { int64_t fsize = de->st.st_size; int is_dir = S_ISDIR(de->st.st_mode); const char *slash = is_dir ? "/" : ""; + time_t t; if (is_dir) { mg_snprintf(size, sizeof(size), "%s", "[DIRECTORY]"); @@ -3583,7 +3640,7 @@ static void print_dir_entry(const struct dir_entry *de) { mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824); } } - time_t t = de->st.st_mtime; + t = de->st.st_mtime; // store in local variable for NDK compile strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&t)); mg_url_encode(de->file_name, strlen(de->file_name), href, sizeof(href)); mg_printf_data(&de->conn->mg_conn, @@ -3639,12 +3696,14 @@ static void send_directory_listing(struct connection *conn, const char *dir) { sort_direction, sort_direction, sort_direction); num_entries = scan_directory(conn, dir, &arr); - qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries); - for (i = 0; i < num_entries; i++) { - print_dir_entry(&arr[i]); - NS_FREE(arr[i].file_name); + if (arr) { + qsort(arr, num_entries, sizeof(arr[0]), compare_dir_entries); + for (i = 0; i < num_entries; i++) { + print_dir_entry(&arr[i]); + NS_FREE(arr[i].file_name); + } + NS_FREE(arr); } - NS_FREE(arr); write_terminating_chunk(conn); close_local_endpoint(conn); @@ -3655,7 +3714,7 @@ static void send_directory_listing(struct connection *conn, const char *dir) { static void print_props(struct connection *conn, const char *uri, file_stat_t *stp) { char mtime[64]; - time_t t = stp->st_mtime; + time_t t = stp->st_mtime; // store in local variable for NDK compile gmt_time_string(mtime, sizeof(mtime), &t); mg_printf(&conn->mg_conn, "<d:response>" @@ -3861,11 +3920,16 @@ void mg_send_digest_auth_request(struct mg_connection *c) { c->status_code = 401; mg_printf(c, "HTTP/1.1 401 Unauthorized\r\n" + "Content-Length: 0\r\n" "WWW-Authenticate: Digest qop=\"auth\", " "realm=\"%s\", nonce=\"%lu\"\r\n\r\n", conn->server->config_options[AUTH_DOMAIN], (unsigned long) time(NULL)); - close_local_endpoint(conn); + if (conn->cl > 0) { + conn->ns_conn->flags |= NSF_DISCARD; + } else { + close_local_endpoint(conn); + } } // Use the global passwords file, if specified by auth_gpass option, @@ -4285,7 +4349,7 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi, mg_snprintf(path, sizeof(path), "%s", file_name); } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 || sscanf(tag, " \"%[^\"]\"", file_name) == 1) { - // File name is relative to the currect document + // File name is relative to the current document mg_snprintf(path, sizeof(path), "%s", ssi); if ((p = strrchr(path, '/')) != NULL) { p[1] = '\0'; @@ -4697,6 +4761,10 @@ static void try_parse(struct connection *conn) { // iobuf could be reallocated, and pointers in parsed request could // become invalid. conn->request = (char *) NS_MALLOC(conn->request_len); + if (conn->request == NULL) { + conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY; + return; + } memcpy(conn->request, io->buf, conn->request_len); //DBG(("%p [%.*s]", conn, conn->request_len, conn->request)); iobuf_remove(io, conn->request_len); @@ -4734,6 +4802,19 @@ static void on_recv_data(struct connection *conn) { return; } + if (conn->ns_conn->flags & NSF_DISCARD) { + size_t n = conn->cl; + if (n > io->len) { + n = io->len; + } + iobuf_remove(io, n); + conn->cl -= n; + if (conn->cl == 0) { + close_local_endpoint(conn); + } + return; + } + try_parse(conn); DBG(("%p %d %lu %d", conn, conn->request_len, (unsigned long)io->len, conn->ns_conn->flags)); @@ -4913,7 +4994,7 @@ static void close_local_endpoint(struct connection *conn) { conn->endpoint_type = EP_NONE; conn->cl = conn->num_bytes_recv = conn->request_len = 0; - conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA | + conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA | NSF_DISCARD | NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY | MG_HEADERS_SENT | MG_USING_CHUNKED_API); @@ -4921,7 +5002,7 @@ static void close_local_endpoint(struct connection *conn) { // (IP addresses & ports, server_param) must survive. Nullify the rest. c->request_method = c->uri = c->http_version = c->query_string = NULL; c->num_headers = c->status_code = c->is_websocket = c->content_len = 0; - c->connection_param = c->callback_param = NULL; + c->callback_param = NULL; if (keep_alive) { on_recv_data(conn); // Can call us recursively if pipelining is used @@ -4983,20 +5064,17 @@ struct mg_connection *mg_next(struct mg_server *s, struct mg_connection *c) { } static int get_var(const char *data, size_t data_len, const char *name, - char *dst, size_t dst_len) { - const char *p, *e, *s; + char *dst, size_t dst_len, int n) { + const char *p, *e = data + data_len, *s; size_t name_len; - int len; + int i = 0, len = -1; if (dst == NULL || dst_len == 0) { len = -2; } else if (data == NULL || name == NULL || data_len == 0) { - len = -1; dst[0] = '\0'; } else { name_len = strlen(name); - e = data + data_len; - len = -1; dst[0] = '\0'; // data is "var1=val1&var2=val2...". Find variable first @@ -5004,6 +5082,8 @@ static int get_var(const char *data, size_t data_len, const char *name, if ((p == data || p[-1] == '&') && p[name_len] == '=' && !mg_strncasecmp(name, p, name_len)) { + if (n != i++) continue; + // Point p to variable value p += name_len + 1; @@ -5029,16 +5109,21 @@ static int get_var(const char *data, size_t data_len, const char *name, return len; } -int mg_get_var(const struct mg_connection *conn, const char *name, - char *dst, size_t dst_len) { +int mg_get_var_n(const struct mg_connection *conn, const char *name, + char *dst, size_t dst_len, int n) { int len = get_var(conn->query_string, conn->query_string == NULL ? 0 : - strlen(conn->query_string), name, dst, dst_len); - if (len < 0) { - len = get_var(conn->content, conn->content_len, name, dst, dst_len); + strlen(conn->query_string), name, dst, dst_len, n); + if (len == -1) { + len = get_var(conn->content, conn->content_len, name, dst, dst_len, n); } return len; } +int mg_get_var(const struct mg_connection *conn, const char *name, + char *dst, size_t dst_len) { + return mg_get_var_n(conn, name, dst, dst_len, 0); +} + static int get_line_len(const char *buf, int buf_len) { int len = 0; while (len < buf_len && buf[len] != '\n') len++; @@ -5095,6 +5180,14 @@ void mg_copy_listeners(struct mg_server *s, struct mg_server *to) { if ((c->flags & NSF_LISTENING) && (tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) { memcpy(tmp, c, sizeof(*tmp)); + +#if defined(NS_ENABLE_SSL) && defined(HEADER_SSL_H) + /* OpenSSL only. See https://github.com/cesanta/mongoose/issues/441 */ + if (tmp->ssl_ctx != NULL) { + tmp->ssl_ctx->references++; + } +#endif + tmp->mgr = &to->ns_mgr; ns_add_conn(tmp->mgr, tmp); } @@ -5153,6 +5246,7 @@ const char *mg_set_option(struct mg_server *server, const char *name, char buf[500] = ""; size_t n = 0; struct vec vec; + /* * Ports can be specified as 0, meaning that OS has to choose any * free port that is available. In order to pass chosen port number to @@ -5247,31 +5341,32 @@ static void process_udp(struct ns_connection *nc) { //ns_printf(nc, "%s", "HTTP/1.0 200 OK\r\n\r\n"); } -static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) { - struct connection *conn = (struct connection *) nc->user_data; - - // Send NS event to the handler. Note that call_user won't send an event - // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well. #ifdef MONGOOSE_SEND_NS_EVENTS - { - struct connection *conn = (struct connection *) nc->user_data; +static void send_ns_event(struct ns_connection *nc, int ev, void *p) { + struct connection *conn = (struct connection *) nc->user_data; + if (conn != NULL) { void *param[2] = { nc, p }; - if (conn != NULL) conn->mg_conn.callback_param = param; + conn->mg_conn.callback_param = param; call_user(conn, (enum mg_event) ev); } +} +#else +static void send_ns_event(struct ns_connection *nc, int ev, void *p) { + (void) nc; (void) p; (void) ev; +} #endif +static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) { + struct connection *conn = (struct connection *) nc->user_data; + + // Send NS event to the handler. Note that call_user won't send an event + // if conn == NULL. Therefore, repeat this for NS_ACCEPT event as well. + send_ns_event(nc, ev, p); + switch (ev) { case NS_ACCEPT: on_accept(nc, (union socket_address *) p); -#ifdef MONGOOSE_SEND_NS_EVENTS - { - struct connection *conn = (struct connection *) nc->user_data; - void *param[2] = { nc, p }; - if (conn != NULL) conn->mg_conn.callback_param = param; - call_user(conn, (enum mg_event) ev); - } -#endif + send_ns_event(nc, ev, p); break; case NS_CONNECT: @@ -5343,6 +5438,11 @@ static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) { write_terminating_chunk(conn); } close_local_endpoint(conn); + /* + * MG_POLL callback returned MG_TRUE, + * i.e. data is sent, set corresponding flag + */ + conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA; } if (conn->endpoint_type == EP_FILE) { diff --git a/3rdparty/mongoose/mongoose.h b/3rdparty/mongoose/mongoose.h index a434758dea1..f2c47a5ce83 100644 --- a/3rdparty/mongoose/mongoose.h +++ b/3rdparty/mongoose/mongoose.h @@ -60,7 +60,8 @@ struct mg_connection { struct mg_server; // Opaque structure describing server instance enum mg_result { MG_FALSE, MG_TRUE, MG_MORE }; enum mg_event { - MG_POLL = 100, // Callback return value is ignored + MG_POLL = 100, // If callback returns MG_TRUE connection closes + // after all of data is sent 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 @@ -103,8 +104,10 @@ void mg_send_status(struct mg_connection *, int status_code); void mg_send_header(struct mg_connection *, const char *name, const char *val); size_t mg_send_data(struct mg_connection *, const void *data, int data_len); size_t mg_printf_data(struct mg_connection *, const char *format, ...); +size_t mg_vprintf_data(struct mg_connection *, const char *format, va_list ap); size_t mg_write(struct mg_connection *, const void *buf, size_t len); size_t mg_printf(struct mg_connection *conn, const char *fmt, ...); +size_t mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap); size_t mg_websocket_write(struct mg_connection *, int opcode, const char *data, size_t data_len); @@ -118,6 +121,8 @@ const char *mg_get_header(const struct mg_connection *, const char *name); const char *mg_get_mime_type(const char *name, const char *default_mime_type); int mg_get_var(const struct mg_connection *conn, const char *var_name, char *buf, size_t buf_len); +int mg_get_var_n(const struct mg_connection *conn, const char *var_name, + char *buf, size_t buf_len, int n); int mg_parse_header(const char *hdr, const char *var_name, char *buf, size_t); int mg_parse_multipart(const char *buf, int buf_len, char *var_name, int var_name_len, diff --git a/3rdparty/mongoose/test/unit_test.c b/3rdparty/mongoose/test/unit_test.c index 6492317bcbd..615cb6ad08c 100644 --- a/3rdparty/mongoose/test/unit_test.c +++ b/3rdparty/mongoose/test/unit_test.c @@ -169,6 +169,7 @@ static const char *test_match_prefix(void) { ASSERT(mg_match_prefix("/api", 4, "/api") == 4); ASSERT(mg_match_prefix("/a/", 3, "/a/b/c") == 3); ASSERT(mg_match_prefix("/a/", 3, "/ab/c") == -1); + ASSERT(mg_match_prefix("/blog/", 6, "/") == -1); ASSERT(mg_match_prefix("/*/", 3, "/ab/c") == 4); ASSERT(mg_match_prefix("**", 2, "/a/b/c") == 6); ASSERT(mg_match_prefix("/*", 2, "/a/b/c") == 2); @@ -223,29 +224,28 @@ static const char *test_remove_double_dots() { } static const char *test_get_var(void) { - static const char *post[] = { - "a=1&&b=2&d&=&c=3%20&e=", - "q=&st=2012%2F11%2F13+17%3A05&et=&team_id=", - NULL - }; + static const char *data = "a=1&&b=2&d&=&c=3%20&e=&k=aa&a=23"; + static const char *data2 = "q=&st=2012%2F11%2F13+17%3A05&et=&team_id="; char buf[20]; - ASSERT(get_var(post[0], strlen(post[0]), "a", buf, sizeof(buf)) == 1); + ASSERT(get_var(data, strlen(data), "a", buf, sizeof(buf), 0) == 1); ASSERT(buf[0] == '1' && buf[1] == '\0'); - ASSERT(get_var(post[0], strlen(post[0]), "b", buf, sizeof(buf)) == 1); + ASSERT(get_var(data, strlen(data), "a", buf, sizeof(buf), 1) == 2); + ASSERT(strcmp(buf, "23") == 0); + ASSERT(get_var(data, strlen(data), "b", buf, sizeof(buf), 0) == 1); ASSERT(buf[0] == '2' && buf[1] == '\0'); - ASSERT(get_var(post[0], strlen(post[0]), "c", buf, sizeof(buf)) == 2); + ASSERT(get_var(data, strlen(data), "c", buf, sizeof(buf), 0) == 2); ASSERT(buf[0] == '3' && buf[1] == ' ' && buf[2] == '\0'); - ASSERT(get_var(post[0], strlen(post[0]), "e", buf, sizeof(buf)) == 0); + ASSERT(get_var(data, strlen(data), "e", buf, sizeof(buf), 0) == 0); ASSERT(buf[0] == '\0'); - ASSERT(get_var(post[0], strlen(post[0]), "d", buf, sizeof(buf)) == -1); - ASSERT(get_var(post[0], strlen(post[0]), "c", buf, 2) == -2); + ASSERT(get_var(data, strlen(data), "d", buf, sizeof(buf), 0) == -1); + ASSERT(get_var(data, strlen(data), "c", buf, 2, 0) == -2); - ASSERT(get_var(post[0], strlen(post[0]), "x", NULL, 10) == -2); - ASSERT(get_var(post[0], strlen(post[0]), "x", buf, 0) == -2); - ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 16) == -2); - ASSERT(get_var(post[1], strlen(post[1]), "st", buf, 17) == 16); + ASSERT(get_var(data, strlen(data), "x", NULL, 10, 0) == -2); + ASSERT(get_var(data, strlen(data), "x", buf, 0, 0) == -2); + ASSERT(get_var(data2, strlen(data2), "st", buf, 16, 0) == -2); + ASSERT(get_var(data2, strlen(data2), "st", buf, 17, 0) == 16); return NULL; } |