diff --git a/3rdparty/mongoose/docs/ReleaseNotes.md b/3rdparty/mongoose/docs/ReleaseNotes.md index 2b45b99a466..24874f824a0 100644 --- a/3rdparty/mongoose/docs/ReleaseNotes.md +++ b/3rdparty/mongoose/docs/ReleaseNotes.md @@ -1,5 +1,30 @@ # Mongoose Release Notes +## Release 5.6, 2015-03-17 + +Changes in Libmongoose library: + +- Added `-dav_root` configuration option that gives an ability to mount + a different root directory (not document_root) +- Fixes for build under Win23 and MinGW +- Bugfix: Double dots removal +- Bugfix: final chunked response double-send +- Fixed compilation in 64-bit environments +- Added OS/2 compatibility +- Added `getaddrinfo()` call and `NS_ENABLE_GETADDRINFO` +- Various SSL-related fixes +- Added integer overflow protection in `iobuf_append()` and `deliver_websocket_frame()` +- Fixed NetBSD build +- Enabled `NS_ENABLE_IPV6` build for Visual Studio 2008+ +- Enhanced comma detection in `parse_header()` +- Fixed unchanged memory accesses on ARM +- Added ability to use custom memory allocator through NS_MALLOC, NS_FREE, NS_REALLOC + +Changes in Mongoose binary: + +- Added `-start_browser` option to disable automatic browser launch +- Added experimental SSL support. To listen on HTTPS port, use `ssl://PORT:SSL_CERT` format. For example, to listen on HTTP port 8080 and HTTPS port 8043, use `-listening_port 8080,ssl://8043:ssl_cert.pem` + ## Release 5.5, October 28 2014 Changes in Libmongoose library: diff --git a/3rdparty/mongoose/examples/.gitignore b/3rdparty/mongoose/examples/.gitignore new file mode 100644 index 00000000000..b883f1fdc6d --- /dev/null +++ b/3rdparty/mongoose/examples/.gitignore @@ -0,0 +1 @@ +*.exe diff --git a/3rdparty/mongoose/examples/Makefile b/3rdparty/mongoose/examples/Makefile index 2964d37e9fb..43483c3f860 100644 --- a/3rdparty/mongoose/examples/Makefile +++ b/3rdparty/mongoose/examples/Makefile @@ -3,13 +3,18 @@ SUBDIRS = $(sort $(filter-out csharp/, $(dir $(wildcard */)))) X = $(SUBDIRS) +ifdef WINDIR + # appending the Winsock2 library at the end of the compiler + # invocation + CFLAGS_EXTRA += -lws2_32 +endif .PHONY: $(SUBDIRS) all: $(SUBDIRS) $(SUBDIRS): - @$(MAKE) -C $@ + @$(MAKE) CFLAGS_EXTRA="$(CFLAGS_EXTRA)" -C $@ clean: - for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done \ No newline at end of file + for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done diff --git a/3rdparty/mongoose/examples/web_server/web_server.c b/3rdparty/mongoose/examples/web_server/web_server.c index 07fda84ed17..03c13d0aab2 100644 --- a/3rdparty/mongoose/examples/web_server/web_server.c +++ b/3rdparty/mongoose/examples/web_server/web_server.c @@ -71,12 +71,7 @@ static char server_name[50]; // Set by init_server_name() static char s_config_file[PATH_MAX]; // Set by process_command_line_arguments static struct mg_server *server; // Set by start_mongoose() static const char *s_default_document_root = "."; -#ifndef NS_ENABLE_SSL static const char *s_default_listening_port = "8080"; -#else -static const char *s_default_listening_port = "ssl://8443:certs/cert.pem"; -#endif - static char **s_argv = { NULL }; static void set_options(char *argv[]); @@ -101,11 +96,8 @@ static void __cdecl signal_handler(int sig_num) { } static void vnotify(const char *fmt, va_list ap, int must_exit) { - char msg[200]; - - vsnprintf(msg, sizeof(msg), fmt, ap); - fprintf(stderr, "%s\n", msg); - + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); if (must_exit) { exit(EXIT_FAILURE); } diff --git a/3rdparty/mongoose/mongoose.c b/3rdparty/mongoose/mongoose.c index 550c3bd2415..d85f6ff3c0a 100644 --- a/3rdparty/mongoose/mongoose.c +++ b/3rdparty/mongoose/mongoose.c @@ -34,8 +34,6 @@ // // Alternatively, you can license this software under a commercial // license, as set out in . -// -// $Date: 2014-09-28 05:04:41 UTC $ #ifndef NS_SKELETON_HEADER_INCLUDED #define NS_SKELETON_HEADER_INCLUDED @@ -46,7 +44,9 @@ #undef _UNICODE // Use multibyte encoding on Windows #define _MBCS // Use multibyte encoding on Windows #define _INTEGRAL_MAX_BITS 64 // Enable _stati64() on Windows +#ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005+ +#endif #undef WIN32_LEAN_AND_MEAN // Let windows.h always include winsock2.h #ifdef __Linux__ #define _XOPEN_SOURCE 600 // For flockfile() on Linux @@ -63,6 +63,10 @@ #pragma warning (disable : 4204) // missing c99 support #endif +#ifndef MONGOOSE_ENABLE_THREADS +#define NS_DISABLE_THREADS +#endif + #ifdef __OS2__ #define _MMAP_DECLARED // Prevent dummy mmap() declaration in stdio.h #endif @@ -618,8 +622,6 @@ static int ns_resolve2(const char *host, struct in_addr *ina) { int rv = 0; struct addrinfo hints, *servinfo, *p; struct sockaddr_in *h = NULL; - char *ip = NS_MALLOC(17); - memset(ip, '\0', 17); memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; @@ -705,8 +707,8 @@ static int ns_parse_address(const char *str, union socket_address *sa, sa->sin.sin_port = htons((uint16_t) port); } - if (*use_ssl && (sscanf(str + len, ":%99[^:]:%99[^:]%n", cert, ca, &n) == 2 || - sscanf(str + len, ":%99[^:]%n", cert, &n) == 1)) { + if (*use_ssl && (sscanf(str + len, ":%99[^:,]:%99[^:,]%n", cert, ca, &n) == 2 || + sscanf(str + len, ":%99[^:,]%n", cert, &n) == 1)) { len += n; } @@ -1387,7 +1389,7 @@ typedef pid_t process_id_t; struct vec { const char *ptr; - uintptr_t len; + size_t len; }; // For directory listing and WevDAV support @@ -1410,6 +1412,7 @@ enum { CGI_PATTERN, #endif DAV_AUTH_FILE, + DAV_ROOT, DOCUMENT_ROOT, #ifndef MONGOOSE_NO_DIRECTORY_LISTING ENABLE_DIRECTORY_LISTING, @@ -1448,6 +1451,7 @@ static const char *static_config_options[] = { "cgi_pattern", DEFAULT_CGI_PATTERN, #endif "dav_auth_file", NULL, + "dav_root", NULL, "document_root", NULL, #ifndef MONGOOSE_NO_DIRECTORY_LISTING "enable_directory_listing", "yes", @@ -1751,7 +1755,7 @@ static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) { // >0 actual request length, including last \r\n\r\n static int get_request_len(const char *s, size_t buf_len) { const unsigned char *buf = (unsigned char *) s; - int i; + size_t i; for (i = 0; i < buf_len; i++) { // Control characters are not allowed but >=128 are. @@ -1791,7 +1795,7 @@ static char *skip(char **buf, const char *delimiters) { // Parse HTTP headers from the given buffer, advance buffer to the point // where parsing stopped. static void parse_http_headers(char **buf, struct mg_connection *ri) { - int i; + size_t i; for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) { ri->http_headers[i].name = skip(buf, ": "); @@ -2343,12 +2347,12 @@ static void on_cgi_data(struct ns_connection *nc) { if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) { struct iobuf *io = &conn->ns_conn->send_iobuf; size_t s_len = sizeof(cgi_status) - 1; - ssize_t len = get_request_len(io->buf + s_len, io->len - s_len); + int len = get_request_len(io->buf + s_len, io->len - s_len); char buf[MAX_REQUEST_SIZE], *s = buf; if (len == 0) return; - if (len < 0 || len > sizeof(buf)) { + if (len < 0 || len > (int) sizeof(buf)) { len = io->len; iobuf_remove(io, io->len); send_http_error(conn, 500, "CGI program sent malformed headers: [%.*s]", @@ -2434,7 +2438,9 @@ static void remove_double_dots_and_double_slashes(char *s) { // Skip all following slashes, backslashes and double-dots while (s[0] != '\0') { if (s[0] == '/' || s[0] == '\\') { s++; } - else if (s[0] == '.' && s[1] == '.') { s += 2; } + else if (s[0] == '.' && (s[1] == '/' || s[1] == '\\')) { s += 2; } + else if (s[0] == '.' && s[1] == '.' && s[2] == '\0') { s += 2; } + else if (s[0] == '.' && s[1] == '.' && (s[2] == '/' || s[2] == '\\')) { s += 3; } else { break; } } } @@ -2444,11 +2450,12 @@ static void remove_double_dots_and_double_slashes(char *s) { int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int is_form_url_encoded) { - int i, j, a, b; -#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') + size_t i, j = 0; + int a, b; +#define HEXTOI(x) (isdigit(x) ? (x) - '0' : (x) - 'W') for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { - if (src[i] == '%' && i < src_len - 2 && + if (src[i] == '%' && i + 2 < src_len && isxdigit(* (const unsigned char *) (src + i + 1)) && isxdigit(* (const unsigned char *) (src + i + 2))) { a = tolower(* (const unsigned char *) (src + i + 1)); @@ -2470,14 +2477,16 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, static int is_valid_http_method(const char *s) { return !strcmp(s, "GET") || !strcmp(s, "POST") || !strcmp(s, "HEAD") || !strcmp(s, "CONNECT") || !strcmp(s, "PUT") || !strcmp(s, "DELETE") || - !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL"); + !strcmp(s, "OPTIONS") || !strcmp(s, "PROPFIND") || !strcmp(s, "MKCOL") || + !strcmp(s, "PATCH"); } // Parse HTTP request, fill in mg_request structure. // This function modifies the buffer by NUL-terminating // HTTP request components, header names and header values. // Note that len must point to the last \n of HTTP headers. -static size_t parse_http_message(char *buf, size_t len, struct mg_connection *ri) { +static size_t parse_http_message(char *buf, size_t len, + struct mg_connection *ri) { int is_request, n; // Reset the connection. Make sure that we don't touch fields that are @@ -2485,6 +2494,8 @@ static size_t parse_http_message(char *buf, size_t len, struct mg_connection *ri ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL; ri->num_headers = ri->status_code = ri->is_websocket = ri->content_len = 0; + if (len < 1) return ~0; + buf[len - 1] = '\0'; // RFC says that all initial whitespaces should be ingored @@ -2500,7 +2511,7 @@ static size_t parse_http_message(char *buf, size_t len, struct mg_connection *ri is_request = is_valid_http_method(ri->request_method); if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) { - len = -1; + len = ~0; } else { if (is_request) { ri->http_version += 5; @@ -2631,6 +2642,12 @@ void mg_template(struct mg_connection *conn, const char *s, } #ifndef MONGOOSE_NO_FILESYSTEM +static int is_dav_request(const struct connection *conn) { + const char *s = conn->mg_conn.request_method; + return !strcmp(s, "PUT") || !strcmp(s, "DELETE") || + !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND"); +} + static int must_hide_file(struct connection *conn, const char *path) { const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$"; const char *pattern = conn->server->config_options[HIDE_FILES_PATTERN]; @@ -2643,7 +2660,12 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf, size_t buf_len, file_stat_t *st) { struct vec a, b; const char *rewrites = conn->server->config_options[URL_REWRITES]; - const char *root = conn->server->config_options[DOCUMENT_ROOT]; + const char *root = +#ifndef MONGOOSE_NO_DAV + is_dav_request(conn) && conn->server->config_options[DAV_ROOT] != NULL ? + conn->server->config_options[DAV_ROOT] : +#endif + conn->server->config_options[DOCUMENT_ROOT]; #ifndef MONGOOSE_NO_CGI const char *cgi_pat = conn->server->config_options[CGI_PATTERN]; char *p; @@ -2655,7 +2677,7 @@ static int convert_uri_to_file_name(struct connection *conn, char *buf, // Perform virtual hosting rewrites if (rewrites != NULL && domain != NULL) { const char *colon = strchr(domain, ':'); - ssize_t domain_len = colon == NULL ? strlen(domain) : colon - domain; + size_t domain_len = colon == NULL ? strlen(domain) : colon - domain; while ((rewrites = next_option(rewrites, &a, &b)) != NULL) { if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 && @@ -3262,8 +3284,12 @@ static int find_index_file(struct connection *conn, char *path, // path and see if the file exists. If it exists, break the loop while ((list = next_option(list, &filename_vec, NULL)) != NULL) { + if (path_len <= n + 2) { + continue; + } + // Ignore too long entries that may overflow path buffer - if (filename_vec.len > (int) (path_len - (n + 2))) + if (filename_vec.len > (path_len - (n + 2))) continue; // Prepare full path to the index file @@ -3331,7 +3357,8 @@ 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); - gmt_time_string(lm, sizeof(lm), &st->st_mtime); + time_t t = st->st_mtime; + gmt_time_string(lm, sizeof(lm), &t); construct_etag(etag, sizeof(etag), st); n = mg_snprintf(headers, sizeof(headers), @@ -3551,7 +3578,8 @@ static void print_dir_entry(const struct dir_entry *de) { mg_snprintf(size, sizeof(size), "%.1fG", (double) fsize / 1073741824); } } - strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.st_mtime)); + time_t t = de->st.st_mtime; + 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, "%s%s" @@ -3622,8 +3650,8 @@ 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]; - - gmt_time_string(mtime, sizeof(mtime), &stp->st_mtime); + time_t t = stp->st_mtime; + gmt_time_string(mtime, sizeof(mtime), &t); mg_printf(&conn->mg_conn, "" "%s" @@ -4182,12 +4210,6 @@ static int is_authorized_for_dav(struct connection *conn) { return authorized; } - -static int is_dav_request(const struct connection *conn) { - const char *s = conn->mg_conn.request_method; - return !strcmp(s, "PUT") || !strcmp(s, "DELETE") || - !strcmp(s, "MKCOL") || !strcmp(s, "PROPFIND"); -} #endif // MONGOOSE_NO_AUTH static int parse_header(const char *str, size_t str_len, const char *var_name, @@ -5123,20 +5145,38 @@ const char *mg_set_option(struct mg_server *server, const char *name, DBG(("%s [%s]", name, *v)); if (ind == LISTENING_PORT) { + 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 + * the user, we rewrite all 0 port to chosen values. + */ while ((value = next_option(value, &vec, NULL)) != NULL) { struct ns_connection *c = ns_bind(&server->ns_mgr, vec.ptr, mg_ev_handler, NULL); - if (c== NULL) { + if (c == NULL) { error_msg = "Cannot bind to port"; break; } else { - char buf[100]; - ns_sock_to_str(c->sock, buf, sizeof(buf), 2); - NS_FREE(*v); - *v = mg_strdup(buf); + char buf2[50], cert[100], ca[100]; + union socket_address sa; + int proto, use_ssl; + + ns_parse_address(vec.ptr, &sa, &proto, &use_ssl, cert, ca); + ns_sock_to_str(c->sock, buf2, sizeof(buf2), + memchr(vec.ptr, ':', vec.len) == NULL ? 2 : 3); + + n += snprintf(buf + n, sizeof(buf) - n, "%s%s%s%s%s%s%s", + n > 0 ? "," : "", + use_ssl ? "ssl://" : "", + buf2, cert[0] ? ":" : "", cert, ca[0] ? ":" : "", ca); } } + buf[sizeof(buf) - 1] = '\0'; + NS_FREE(*v); + *v = mg_strdup(buf); #ifndef MONGOOSE_NO_FILESYSTEM } else if (ind == HEXDUMP_FILE) { server->ns_mgr.hexdump_file = *v; diff --git a/3rdparty/mongoose/test/unit_test.c b/3rdparty/mongoose/test/unit_test.c index 39e36ae02ef..6492317bcbd 100644 --- a/3rdparty/mongoose/test/unit_test.c +++ b/3rdparty/mongoose/test/unit_test.c @@ -120,8 +120,8 @@ static const char *test_parse_http_message() { ASSERT(strcmp(ri.http_version, "1.1") == 0); ASSERT(ri.num_headers == 0); - ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == -1); - ASSERT(parse_http_message(req6, 0, &ri) == -1); + ASSERT(parse_http_message(req2, sizeof(req2) - 1, &ri) == (size_t) ~0); + ASSERT(parse_http_message(req6, 0, &ri) == (size_t) ~0); ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1); // TODO(lsm): Fix this. Header value may span multiple lines. @@ -198,17 +198,19 @@ static const char *test_match_prefix(void) { } static const char *test_remove_double_dots() { - struct { char before[20], after[20]; } data[] = { + struct { char before[30], after[30]; } data[] = { {"////a", "/a"}, - {"/.....", "/."}, - {"/......", "/"}, + {"/.....", "/....."}, + {"/......", "/......"}, {"...", "..."}, - {"/...///", "/./"}, + {"/...///", "/.../"}, {"/a...///", "/a.../"}, {"/.x", "/.x"}, {"/\\", "/"}, {"/a\\", "/a\\"}, - {"/a\\\\...", "/a\\."}, + {"/a\\\\...", "/a\\..."}, + {"foo/x..y/././y/../../..", "foo/x..y/y/"}, + {"foo/..x", "foo/..x"}, }; size_t i; @@ -261,6 +263,7 @@ static const char *test_url_decode(void) { ASSERT(strcmp(buf, "a ") == 0); ASSERT(mg_url_decode("%61", 1, buf, sizeof(buf), 1) == 1); + printf("[%s]\n", buf); ASSERT(strcmp(buf, "%") == 0); ASSERT(mg_url_decode("%61", 2, buf, sizeof(buf), 1) == 2);