]> git.mxchange.org Git - flightgear.git/commitdiff
Pull in latest mongoose HEAD
authorTorsten Dreyer <torsten@t3r.de>
Fri, 29 May 2015 09:33:06 +0000 (11:33 +0200)
committerTorsten Dreyer <torsten@t3r.de>
Fri, 29 May 2015 09:33:06 +0000 (11:33 +0200)
3rdparty/mongoose/mongoose.c
3rdparty/mongoose/mongoose.h

index 84c2d609456696a2c43480aa35ff264de625c7e4..600c6feddd589cef0633cff74b2f10fe1ff45047 100644 (file)
@@ -14,8 +14,6 @@
 //
 // Alternatively, you can license this library under a commercial
 // license, as set out in <http://cesanta.com/>.
-//
-// $Date: 2014-09-16 06:47:40 UTC $
 
 #ifdef NOEMBED_NET_SKELETON
 #include "net_skeleton.h"
@@ -36,8 +34,6 @@
 //
 // Alternatively, you can license this software under a commercial
 // license, as set out in <http://cesanta.com/>.
-//
-// $Date: 2014-09-28 05:04:41 UTC $
 
 #ifndef NS_SKELETON_HEADER_INCLUDED
 #define NS_SKELETON_HEADER_INCLUDED
 #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
+#endif
 #define __STDC_FORMAT_MACROS    // <inttypes.h> wants this for C++
 #define __STDC_LIMIT_MACROS     // C++ wants that for INT64_MAX
 #ifndef _LARGEFILE_SOURCE
 #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
+
+#ifdef __OS2__
+#define _MMAP_DECLARED          // Prevent dummy mmap() declaration in stdio.h
+#endif
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <assert.h>
 #ifdef _WIN32
 #ifdef _MSC_VER
 #pragma comment(lib, "ws2_32.lib")    // Linking with winsock library
+#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>
 #include <process.h>
 #ifndef EINPROGRESS
@@ -124,7 +143,12 @@ typedef struct _stati64 ns_stat_t;
 #include <sys/socket.h>
 #include <sys/select.h>
 #define closesocket(x) close(x)
+#ifndef __OS2__
 #define __cdecl
+#else
+#include <sys/time.h>
+typedef int socklen_t;
+#endif
 #define INVALID_SOCKET (-1)
 #define to64(x) strtoll(x, NULL, 10)
 typedef int sock_t;
@@ -214,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;
@@ -255,7 +280,7 @@ struct ns_connection *ns_bind(struct ns_mgr *, const char *,
 struct ns_connection *ns_connect(struct ns_mgr *, const char *,
                                  ns_callback_t, void *);
 
-int ns_send(struct ns_connection *, const void *buf, int len);
+int ns_send(struct ns_connection *, const void *buf, size_t len);
 int ns_printf(struct ns_connection *, const char *fmt, ...);
 int ns_vprintf(struct ns_connection *, const char *fmt, va_list ap);
 
@@ -305,12 +330,18 @@ int ns_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
 #define NS_FREE free
 #endif
 
+#ifndef NS_CALLOC
+#define NS_CALLOC calloc
+#endif
+
+#define NS_CTL_MSG_MESSAGE_SIZE     (8 * 1024)
+#define NS_READ_BUFFER_SIZE         2048
 #define NS_UDP_RECEIVE_BUFFER_SIZE  2000
 #define NS_VPRINTF_BUFFER_SIZE      500
 
 struct ctl_msg {
   ns_callback_t callback;
-  char message[1024 * 8];
+  char message[NS_CTL_MSG_MESSAGE_SIZE];
 };
 
 void iobuf_resize(struct iobuf *io, size_t new_size) {
@@ -341,6 +372,11 @@ size_t iobuf_append(struct iobuf *io, const void *buf, size_t len) {
   assert(io != NULL);
   assert(io->len <= io->size);
 
+  /* check overflow */
+  if (len > ~(size_t)0 - (size_t)(io->buf + io->len)) {
+    return 0;
+  }
+
   if (len <= 0) {
   } else if (io->len + len <= io->size) {
     memcpy(io->buf + io->len, buf, len);
@@ -366,7 +402,8 @@ void iobuf_remove(struct iobuf *io, size_t n) {
 
 static size_t ns_out(struct ns_connection *nc, const void *buf, size_t len) {
   if (nc->flags & NSF_UDP) {
-    long n = sendto(nc->sock, buf, len, 0, &nc->sa.sa, sizeof(nc->sa.sin));
+    long n = sendto(nc->sock, (const char *) buf, len, 0, &nc->sa.sa,
+                    sizeof(nc->sa.sin));
     DBG(("%p %d send %ld (%d %s)", nc, nc->sock, n, errno, strerror(errno)));
     return n < 0 ? 0 : n;
   } else {
@@ -427,7 +464,7 @@ int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
     // succeed or out of memory.
     *buf = NULL;
     while (len < 0) {
-      if (*buf) free(*buf);
+      if (*buf) NS_FREE(*buf);
       size *= 2;
       if ((*buf = (char *) NS_MALLOC(size)) == NULL) break;
       va_copy(ap_copy, ap);
@@ -456,7 +493,7 @@ int ns_vprintf(struct ns_connection *nc, const char *fmt, va_list ap) {
     ns_out(nc, buf, len);
   }
   if (buf != mem && buf != NULL) {
-    free(buf);
+    NS_FREE(buf);
   }
 
   return len;
@@ -490,7 +527,7 @@ static void hexdump(struct ns_connection *nc, const char *path,
       ns_hexdump(io->buf + (ev == NS_SEND ? 0 : io->len) -
         (ev == NS_SEND ? 0 : num_bytes), num_bytes, buf, buf_size);
       fprintf(fp, "%s", buf);
-      free(buf);
+      NS_FREE(buf);
     }
     fclose(fp);
   }
@@ -589,6 +626,28 @@ int ns_socketpair(sock_t sp[2]) {
 
 // TODO(lsm): use non-blocking resolver
 static int ns_resolve2(const char *host, struct in_addr *ina) {
+#ifdef NS_ENABLE_GETADDRINFO
+  int rv = 0;
+  struct addrinfo hints, *servinfo, *p;
+  struct sockaddr_in *h = NULL;
+
+  memset(&hints, 0, sizeof hints);
+  hints.ai_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+
+  if((rv = getaddrinfo(host, NULL , NULL, &servinfo)) != 0) {
+    DBG(("getaddrinfo(%s) failed: %s", host, strerror(errno)));
+    return 0;
+  }
+
+  for(p = servinfo; p != NULL; p = p->ai_next) {
+    memcpy(&h, &p->ai_addr, sizeof(struct sockaddr_in *));
+    memcpy(ina, &h->sin_addr, sizeof(ina));
+  }
+
+  freeaddrinfo(servinfo);
+  return 1;
+#else
   struct hostent *he;
   if ((he = gethostbyname(host)) == NULL) {
     DBG(("gethostbyname(%s) failed: %s", host, strerror(errno)));
@@ -597,6 +656,7 @@ static int ns_resolve2(const char *host, struct in_addr *ina) {
     return 1;
   }
   return 0;
+#endif
 }
 
 // Resolve FDQN "host", store IP address in the "ip".
@@ -655,8 +715,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;
   }
 
@@ -868,7 +928,7 @@ static int ns_ssl_err(struct ns_connection *conn, int res) {
 #endif
 
 static void ns_read_from_socket(struct ns_connection *conn) {
-  char buf[2048];
+  char buf[NS_READ_BUFFER_SIZE];
   int n = 0;
 
   if (conn->flags & NSF_CONNECTING) {
@@ -889,6 +949,7 @@ static void ns_read_from_socket(struct ns_connection *conn) {
       } else {
         ok = 1;
       }
+      conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
     }
 #endif
     conn->flags &= ~NSF_CONNECTING;
@@ -917,6 +978,7 @@ static void ns_read_from_socket(struct ns_connection *conn) {
       int ssl_err = ns_ssl_err(conn, res);
       if (res == 1) {
         conn->flags |= NSF_SSL_HANDSHAKE_DONE;
+        conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
       } else if (ssl_err == SSL_ERROR_WANT_READ ||
                  ssl_err == SSL_ERROR_WANT_WRITE) {
         return; // Call us again
@@ -954,6 +1016,8 @@ static void ns_write_to_socket(struct ns_connection *conn) {
       } else {
         conn->flags |= NSF_CLOSE_IMMEDIATELY;
       }
+    } else {
+      conn->flags &= ~(NSF_WANT_READ | NSF_WANT_WRITE);
     }
   } else
 #endif
@@ -969,14 +1033,14 @@ static void ns_write_to_socket(struct ns_connection *conn) {
   }
 }
 
-int ns_send(struct ns_connection *conn, const void *buf, int len) {
+int ns_send(struct ns_connection *conn, const void *buf, size_t len) {
   return (int) ns_out(conn, buf, len);
 }
 
 static void ns_handle_udp(struct ns_connection *ls) {
   struct ns_connection nc;
   char buf[NS_UDP_RECEIVE_BUFFER_SIZE];
-  int n;
+  ssize_t n;
   socklen_t s_len = sizeof(nc.sa);
 
   memset(&nc, 0, sizeof(nc));
@@ -1000,7 +1064,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;
@@ -1024,18 +1088,19 @@ time_t ns_mgr_poll(struct ns_mgr *mgr, int milli) {
     if (!(conn->flags & (NSF_LISTENING | NSF_CONNECTING))) {
       ns_call(conn, NS_POLL, &current_time);
     }
-    if (!(conn->flags & NSF_WANT_WRITE)) {
-      //DBG(("%p read_set", conn));
-      ns_add_to_set(conn->sock, &read_set, &max_fd);
-    }
-    if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
-        (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
-         !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
-      //DBG(("%p write_set", conn));
-      ns_add_to_set(conn->sock, &write_set, &max_fd);
-    }
     if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
       ns_close_conn(conn);
+    } else {
+      if (!(conn->flags & NSF_WANT_WRITE)) {
+        //DBG(("%p read_set", conn));
+        ns_add_to_set(conn->sock, &read_set, &max_fd);
+      }
+      if (((conn->flags & NSF_CONNECTING) && !(conn->flags & NSF_WANT_READ)) ||
+          (conn->send_iobuf.len > 0 && !(conn->flags & NSF_CONNECTING) &&
+           !(conn->flags & NSF_BUFFER_BUT_DONT_SEND))) {
+        //DBG(("%p write_set", conn));
+        ns_add_to_set(conn->sock, &write_set, &max_fd);
+      }
     }
   }
 
@@ -1247,21 +1312,21 @@ void ns_mgr_free(struct ns_mgr *s) {
 #define fopen(x, y) mg_fopen((x), (y))
 #define open(x, y, z) mg_open((x), (y), (z))
 #define close(x) _close(x)
+#define fileno(x) _fileno(x)
 #define lseek(x, y, z) _lseeki64((x), (y), (z))
+#define read(x, y, z) _read((x), (y), (z))
+#define write(x, y, z) _write((x), (y), (z))
 #define popen(x, y) _popen((x), (y))
 #define pclose(x) _pclose(x)
 #define mkdir(x, y) _mkdir(x)
+#define rmdir(x) _rmdir(x)
+#define strdup(x) _strdup(x)
 #ifndef __func__
 #define STRX(x) #x
 #define STR(x) STRX(x)
 #define __func__ __FILE__ ":" STR(__LINE__)
 #endif
-/* MINGW has adopted the MSVC formatting for 64-bit ints as of gcc 4.4 till 4.8*/
-#if (defined(__MINGW32__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4 && __GNUC_MINOR__ < 8))) || defined(_MSC_VER)
 #define INT64_FMT   "I64d"
-#else
-#define INT64_FMT   "lld"
-#endif
 #define flockfile(x)      ((void) (x))
 #define funlockfile(x)    ((void) (x))
 typedef struct _stati64 file_stat_t;
@@ -1269,11 +1334,18 @@ typedef HANDLE process_id_t;
 
 #else                    ////////////// UNIX specific defines and includes
 
+#if !defined(MONGOOSE_NO_FILESYSTEM) &&\
+    (!defined(MONGOOSE_NO_DAV) || !defined(MONGOOSE_NO_DIRECTORY_LISTING))
 #include <dirent.h>
+#endif
+#if !defined(MONGOOSE_NO_FILESYSTEM) && !defined(MONGOOSE_NO_DL)
 #include <dlfcn.h>
+#endif
 #include <inttypes.h>
 #include <pwd.h>
+#if !defined(O_BINARY)
 #define O_BINARY 0
+#endif
 #define INT64_FMT PRId64
 typedef struct stat file_stat_t;
 typedef pid_t process_id_t;
@@ -1307,13 +1379,15 @@ typedef pid_t process_id_t;
 #define MONGOOSE_IDLE_TIMEOUT_SECONDS 300
 #endif
 
-#ifdef NS_DISABLE_SOCKETPAIR
+#if defined(NS_DISABLE_SOCKETPAIR) && !defined(MONGOOSE_NO_CGI)
 #define MONGOOSE_NO_CGI
 #endif
 
 #ifdef MONGOOSE_NO_FILESYSTEM
 #define MONGOOSE_NO_AUTH
+#if !defined(MONGOOSE_NO_CGI)
 #define MONGOOSE_NO_CGI
+#endif
 #define MONGOOSE_NO_DAV
 #define MONGOOSE_NO_DIRECTORY_LISTING
 #define MONGOOSE_NO_LOGGING
@@ -1323,7 +1397,7 @@ typedef pid_t process_id_t;
 
 struct vec {
   const char *ptr;
-  int len;
+  size_t len;
 };
 
 // For directory listing and WevDAV support
@@ -1333,7 +1407,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
@@ -1346,6 +1420,7 @@ enum {
   CGI_PATTERN,
 #endif
   DAV_AUTH_FILE,
+  DAV_ROOT,
   DOCUMENT_ROOT,
 #ifndef MONGOOSE_NO_DIRECTORY_LISTING
   ENABLE_DIRECTORY_LISTING,
@@ -1384,6 +1459,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",
@@ -1428,7 +1504,7 @@ enum endpoint_type {
 };
 
 #define MG_HEADERS_SENT NSF_USER_1
-#define MG_LONG_RUNNING NSF_USER_2
+#define MG_USING_CHUNKED_API NSF_USER_2
 #define MG_CGI_CONN NSF_USER_3
 #define MG_PROXY_CONN NSF_USER_4
 #define MG_PROXY_DONT_PARSE NSF_USER_5
@@ -1443,7 +1519,7 @@ struct connection {
   char *request;
   int64_t num_bytes_recv; // Total number of bytes received
   int64_t cl;             // Reply content length, for Range support
-  int request_len;  // Request length, including last \r\n after last header
+  ssize_t request_len;  // Request length, including last \r\n after last header
 };
 
 #define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
@@ -1463,7 +1539,7 @@ static const struct {
   {".shtm", 5, "text/html"},
   {".shtml", 6, "text/html"},
   {".css", 4, "text/css"},
-  {".js",  3, "application/x-javascript"},
+  {".js",  3, "application/javascript"},
   {".ico", 4, "image/x-icon"},
   {".gif", 4, "image/gif"},
   {".jpg", 4, "image/jpeg"},
@@ -1508,11 +1584,11 @@ static const struct {
   {NULL,  0, NULL}
 };
 
-#ifndef MONGOOSE_NO_THREADS
+#ifdef MONGOOSE_ENABLE_THREADS
 void *mg_start_thread(void *(*f)(void *), void *p) {
   return ns_start_thread(f, p);
 }
-#endif  // MONGOOSE_NO_THREADS
+#endif  // MONGOOSE_ENABLE_THREADS
 
 #ifndef MONGOOSE_NO_MMAP
 #ifdef _WIN32
@@ -1528,6 +1604,37 @@ static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
 #define MAP_FAILED NULL
 #define MAP_PRIVATE 0
 #define PROT_READ 0
+#elif defined(__OS2__)
+static void *mmap(void *addr, int64_t len, int prot, int flags, int fd,
+                  int offset) {
+  void *p;
+
+  int pos = lseek( fd, 0, SEEK_CUR ); /* Get a current position */
+
+  if (pos == -1)
+    return NULL;
+
+  /* Seek to offset offset */
+  if (lseek( fd, offset, SEEK_SET) == -1)
+    return NULL;
+
+  p = malloc(len);
+
+  /* Read in a file */
+  if (!p || read(fd, p, len) == -1) {
+    free(p);
+    p = NULL;
+  }
+
+  /* Restore the position */
+  lseek(fd, pos, SEEK_SET);
+
+  return p;
+}
+#define munmap(x, y)  free(x)
+#define MAP_FAILED NULL
+#define MAP_PRIVATE 0
+#define PROT_READ 0
 #else
 #include <sys/mman.h>
 #endif
@@ -1654,9 +1761,9 @@ static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
 //   -1  if request is malformed
 //    0  if request is not yet fully buffered
 //   >0  actual request length, including last \r\n\r\n
-static int get_request_len(const char *s, int buf_len) {
+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.
@@ -1844,13 +1951,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;
 }
 
@@ -1869,6 +1984,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);
@@ -1888,9 +2005,9 @@ 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);
-  free(tp);
+  NS_FREE(tp);
   _endthread();
   return NULL;
 }
@@ -1911,14 +2028,14 @@ static void *pull_from_stdout(void *arg) {
   CloseHandle(tp->hPipe);
   shutdown(tp->s, 2);  // Without this, IO thread may get truncated data
   closesocket(tp->s);
-  free(tp);
+  NS_FREE(tp);
   _endthread();
   return NULL;
 }
 
 static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
                                void *(*func)(void *)) {
-  struct threadparam *tp = (struct threadparam *)malloc(sizeof(*tp));
+  struct threadparam *tp = (struct threadparam *)NS_MALLOC(sizeof(*tp));
   if (tp != NULL) {
     tp->s = sock;
     tp->hPipe = hPipe;
@@ -2247,7 +2364,7 @@ static void on_cgi_data(struct ns_connection *nc) {
   // If reply has not been parsed yet, parse it
   if (conn->ns_conn->flags & NSF_BUFFER_BUT_DONT_SEND) {
     struct iobuf *io = &conn->ns_conn->send_iobuf;
-    int s_len = sizeof(cgi_status) - 1;
+    size_t s_len = sizeof(cgi_status) - 1;
     int len = get_request_len(io->buf + s_len, io->len - s_len);
     char buf[MAX_REQUEST_SIZE], *s = buf;
 
@@ -2277,7 +2394,7 @@ static void on_cgi_data(struct ns_connection *nc) {
 #endif  // !MONGOOSE_NO_CGI
 
 static char *mg_strdup(const char *str) {
-  char *copy = (char *) malloc(strlen(str) + 1);
+  char *copy = (char *) NS_MALLOC(strlen(str) + 1);
   if (copy != NULL) {
     strcpy(copy, str);
   }
@@ -2339,7 +2456,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; }
       }
     }
@@ -2347,13 +2466,14 @@ static void remove_double_dots_and_double_slashes(char *s) {
   *p = '\0';
 }
 
-int mg_url_decode(const char *src, int src_len, char *dst,
-                  int dst_len, int is_form_url_encoded) {
-  int i, j, a, b;
-#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
+int mg_url_decode(const char *src, size_t src_len, char *dst,
+                  size_t dst_len, int is_form_url_encoded) {
+  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));
@@ -2375,14 +2495,16 @@ int mg_url_decode(const char *src, int 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 int parse_http_message(char *buf, int len, struct mg_connection *ri) {
+static size_t parse_http_message(char *buf, size_t len,
+                                 struct mg_connection *ri) {
   int is_request, n;
 
   // Reset the connection. Make sure that we don't touch fields that are
@@ -2390,9 +2512,11 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) {
   ri->request_method = ri->uri = ri->http_version = ri->query_string = NULL;
   ri->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
+  // RFC says that all initial whitespaces should be ignored
   while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
     buf++;
   }
@@ -2405,7 +2529,7 @@ static int parse_http_message(char *buf, int 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;
@@ -2464,7 +2588,7 @@ const char *mg_get_header(const struct mg_connection *ri, const char *s) {
 }
 
 // Perform case-insensitive match of string against pattern
-int mg_match_prefix(const char *pattern, int pattern_len, const char *str) {
+int mg_match_prefix(const char *pattern, ssize_t pattern_len, const char *str) {
   const char *or_str;
   int len, res, i = 0, j = 0;
 
@@ -2536,6 +2660,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];
@@ -2548,19 +2678,25 @@ 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;
 #endif
   const char *uri = conn->mg_conn.uri;
   const char *domain = mg_get_header(&conn->mg_conn, "Host");
+  // 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) {
     const char *colon = strchr(domain, ':');
-    int domain_len = colon == NULL ? (int) strlen(domain) : colon - domain;
+    size_t domain_len = colon == NULL ? strlen(domain) : colon - domain;
 
     while ((rewrites = next_option(rewrites, &a, &b)) != NULL) {
       if (a.len > 1 && a.ptr[0] == '@' && a.len == domain_len + 1 &&
@@ -2620,25 +2756,29 @@ static int should_keep_alive(const struct mg_connection *conn) {
      (header == NULL && http_version && !strcmp(http_version, "1.1")));
 }
 
-size_t mg_write(struct mg_connection *c, const void *buf, int len) {
+size_t mg_write(struct mg_connection *c, const void *buf, size_t len) {
   struct connection *conn = MG_CONN_2_CONN(c);
   ns_send(conn->ns_conn, buf, len);
   return conn->ns_conn->send_iobuf.len;
 }
 
 void mg_send_status(struct mg_connection *c, int status) {
+  struct connection *conn = MG_CONN_2_CONN(c);
   if (c->status_code == 0) {
     c->status_code = status;
     mg_printf(c, "HTTP/1.1 %d %s\r\n", status, status_code_to_str(status));
   }
+  conn->ns_conn->flags |= MG_USING_CHUNKED_API;
 }
 
 void mg_send_header(struct mg_connection *c, const char *name, const char *v) {
+  struct connection *conn = MG_CONN_2_CONN(c);
   if (c->status_code == 0) {
     c->status_code = 200;
     mg_printf(c, "HTTP/1.1 %d %s\r\n", 200, status_code_to_str(200));
   }
   mg_printf(c, "%s: %s\r\n", name, v);
+  conn->ns_conn->flags |= MG_USING_CHUNKED_API;
 }
 
 static void terminate_headers(struct mg_connection *c) {
@@ -2658,22 +2798,30 @@ 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);
   }
   if (buf != mem && buf != NULL) {
-    free(buf);
+    NS_FREE(buf);
   }
   return conn->ns_conn->send_iobuf.len;
 }
@@ -2780,8 +2928,8 @@ static void SHA1Init(SHA1_CTX *context) {
 }
 
 static void SHA1Update(SHA1_CTX *context, const unsigned char *data,
-                       uint32_t len) {
-  uint32_t i, j;
+                       size_t len) {
+  size_t i, j;
 
   j = context->count[0];
   if ((context->count[0] += len << 3) < j)
@@ -2869,10 +3017,10 @@ static void send_websocket_handshake(struct mg_connection *conn,
   mg_write(conn, buf, strlen(buf));
 }
 
-static int deliver_websocket_frame(struct connection *conn) {
+static size_t deliver_websocket_frame(struct connection *conn) {
   // Having buf unsigned char * is important, as it is used below in arithmetic
   unsigned char *buf = (unsigned char *) conn->ns_conn->recv_iobuf.buf;
-  int i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
+  size_t i, len, buf_len = conn->ns_conn->recv_iobuf.len, frame_len = 0,
       mask_len = 0, header_len = 0, data_len = 0, buffered = 0;
 
   if (buf_len >= 2) {
@@ -2883,10 +3031,10 @@ static int deliver_websocket_frame(struct connection *conn) {
       header_len = 2 + mask_len;
     } else if (len == 126 && buf_len >= 4 + mask_len) {
       header_len = 4 + mask_len;
-      data_len = ((((int) buf[2]) << 8) + buf[3]);
+      data_len = ((((size_t) buf[2]) << 8) + buf[3]);
     } else if (buf_len >= 10 + mask_len) {
       header_len = 10 + mask_len;
-      data_len = (int) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
+      data_len = (size_t) (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
         htonl(* (uint32_t *) &buf[6]);
     }
   }
@@ -2907,7 +3055,8 @@ static int 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);
@@ -2917,12 +3066,17 @@ static int deliver_websocket_frame(struct connection *conn) {
 }
 
 size_t mg_websocket_write(struct mg_connection *conn, int opcode,
-                       const char *data, size_t data_len) {
+                          const char *data, size_t data_len) {
     unsigned char mem[4192], *copy = mem;
     size_t copy_len = 0;
 
+    /* Check overflow */
+    if (data_len > ~(size_t)0 - (size_t)10) {
+      return 0;
+    }
+
     if (data_len + 10 > sizeof(mem) &&
-        (copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
+        (copy = (unsigned char *) NS_MALLOC(data_len + 10)) == NULL) {
       return 0;
     }
 
@@ -2942,10 +3096,11 @@ size_t mg_websocket_write(struct mg_connection *conn, int opcode,
       copy_len = 4 + data_len;
     } else {
       // 64-bit length field
+      const uint32_t hi = htonl((uint32_t) ((uint64_t) data_len >> 32));
+      const uint32_t lo = htonl(data_len & 0xffffffff);
       copy[1] = 127;
-      * (uint32_t *) (copy + 2) = (uint32_t)
-        htonl((uint32_t) ((uint64_t) data_len >> 32));
-      * (uint32_t *) (copy + 6) = (uint32_t) htonl(data_len & 0xffffffff);
+      memcpy(copy+2,&hi,sizeof(hi));
+      memcpy(copy+6,&lo,sizeof(lo));
       memcpy(copy + 10, data, data_len);
       copy_len = 10 + data_len;
     }
@@ -2954,7 +3109,7 @@ size_t mg_websocket_write(struct mg_connection *conn, int opcode,
       mg_write(conn, copy, copy_len);
     }
     if (copy != mem) {
-      free(copy);
+      NS_FREE(copy);
     }
 
     // If we send closing frame, schedule a connection to be closed after
@@ -2979,7 +3134,7 @@ size_t mg_websocket_printf(struct mg_connection *conn, int opcode,
   va_end(ap);
 
   if (buf != mem && buf != NULL) {
-    free(buf);
+    NS_FREE(buf);
   }
 
   return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len;
@@ -3014,7 +3169,8 @@ static int call_request_handler(struct connection *conn) {
   int result;
   conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
   if ((result = call_user(conn, MG_REQUEST)) == MG_TRUE) {
-    if (conn->ns_conn->flags & MG_HEADERS_SENT) {
+    if (conn->ns_conn->flags & MG_USING_CHUNKED_API) {
+      terminate_headers(&conn->mg_conn);
       write_terminating_chunk(conn);
     }
     close_local_endpoint(conn);
@@ -3141,7 +3297,8 @@ static int find_index_file(struct connection *conn, char *path,
   const char *list = conn->server->config_options[INDEX_FILES];
   file_stat_t st;
   struct vec filename_vec;
-  size_t n = strlen(path), found = 0;
+  size_t n = strlen(path);
+  int found = 0;
 
   // The 'path' given to us points to the directory. Remove all trailing
   // directory separator characters from the end of the path, and
@@ -3155,8 +3312,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
@@ -3176,7 +3337,8 @@ 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;
@@ -3194,7 +3356,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;
@@ -3224,7 +3386,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);
+  t = st->st_mtime; // store in local variable for NDK compile
+  gmt_time_string(lm, sizeof(lm), &t);
   construct_etag(etag, sizeof(etag), st);
 
   n = mg_snprintf(headers, sizeof(headers),
@@ -3292,7 +3455,7 @@ static DIR *opendir(const char *name) {
 
   if (name == NULL) {
     SetLastError(ERROR_BAD_ARGUMENTS);
-  } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
+  } else if ((dir = (DIR *) NS_MALLOC(sizeof(*dir))) == NULL) {
     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
   } else {
     to_wchar(name, wpath, ARRAY_SIZE(wpath));
@@ -3303,7 +3466,7 @@ static DIR *opendir(const char *name) {
       dir->handle = FindFirstFileW(wpath, &dir->info);
       dir->result.d_name[0] = '\0';
     } else {
-      free(dir);
+      NS_FREE(dir);
       dir = NULL;
     }
   }
@@ -3318,7 +3481,7 @@ static int closedir(DIR *dir) {
     if (dir->handle != INVALID_HANDLE_VALUE)
       result = FindClose(dir->handle) ? 0 : -1;
 
-    free(dir);
+    NS_FREE(dir);
   } else {
     result = -1;
     SetLastError(ERROR_BAD_ARGUMENTS);
@@ -3373,11 +3536,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 *)
-           realloc(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
-        // Memset new chunk to zero, otherwize st_mtime will have garbage which
+           NS_REALLOC(*arr, (inc + arr_size) * sizeof(**arr))) != NULL) {
+        // 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);
@@ -3399,7 +3562,7 @@ static int scan_directory(struct connection *conn, const char *dir,
   return arr_ind;
 }
 
-int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
+size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len) {
   static const char *dont_escape = "._-$,;~()";
   static const char *hex = "0123456789abcdef";
   size_t i = 0, j = 0;
@@ -3428,6 +3591,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]");
@@ -3444,7 +3608,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));
+  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,
                   "<tr><td><a href=\"%s%s\">%s%s</a></td>"
@@ -3499,12 +3664,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]);
-    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);
   }
-  free(arr);
 
   write_terminating_chunk(conn);
   close_local_endpoint(conn);
@@ -3515,8 +3682,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;  // store in local variable for NDK compile
+  gmt_time_string(mtime, sizeof(mtime), &t);
   mg_printf(&conn->mg_conn,
       "<d:response>"
        "<d:href>%s</d:href>"
@@ -3572,9 +3739,9 @@ static void handle_propfind(struct connection *conn, const char *path,
         struct dir_entry *de = &arr[i];
         mg_url_encode(de->file_name, strlen(de->file_name), buf, sizeof(buf));
         print_props(conn, buf, &de->st);
-        free(de->file_name);
+        NS_FREE(de->file_name);
       }
-      free(arr);
+      NS_FREE(arr);
     }
     ns_send(conn->ns_conn, footer, sizeof(footer) - 1);
   }
@@ -3696,7 +3863,7 @@ static void handle_put(struct connection *conn, const char *path) {
 static void forward_put_data(struct connection *conn) {
   struct iobuf *io = &conn->ns_conn->recv_iobuf;
   size_t k = conn->cl < (int64_t) io->len ? conn->cl : (int64_t) io->len;   // To write
-  int n = write(conn->endpoint.fd, io->buf, k);   // Write them!
+  size_t n = write(conn->endpoint.fd, io->buf, k);   // Write them!
   if (n > 0) {
     iobuf_remove(io, n);
     conn->cl -= n;
@@ -3721,6 +3888,7 @@ 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],
@@ -3754,6 +3922,23 @@ static FILE *open_auth_file(struct connection *conn, const char *path,
 }
 
 #if !defined(HAVE_MD5) && !defined(MONGOOSE_NO_AUTH)
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
 typedef struct MD5Context {
   uint32_t buf[4];
   uint32_t bits[2];
@@ -4058,33 +4243,28 @@ 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, int str_len, const char *var_name,
+static int parse_header(const char *str, size_t str_len, const char *var_name,
                         char *buf, size_t buf_size) {
-  int ch = ' ', len = 0, n = strlen(var_name);
+  int ch = ' ', ch1 = ',', len = 0;
+  size_t n = strlen(var_name);
   const char *p, *end = str + str_len, *s = NULL;
 
   if (buf != NULL && buf_size > 0) buf[0] = '\0';
 
   // Find where variable starts
   for (s = str; s != NULL && s + n < end; s++) {
-    if ((s == str || s[-1] == ' ' || s[-1] == ',') && s[n] == '=' &&
+    if ((s == str || s[-1] == ch || s[-1] == ch1) && s[n] == '=' &&
         !memcmp(s, var_name, n)) break;
   }
 
   if (s != NULL && &s[n + 1] < end) {
     s += n + 1;
-    if (*s == '"' || *s == '\'') ch = *s++;
+    if (*s == '"' || *s == '\'') ch = ch1 = *s++;
     p = s;
-    while (p < end && p[0] != ch && p[0] != ',' && len < (int) buf_size) {
-      if (p[0] == '\\' && p[1] == ch) p++;
+    while (p < end && p[0] != ch && p[0] != ch1 && len < (int) buf_size) {
+      if (ch == ch1 && p[0] == '\\' && p[1] == ch) p++;
       buf[len++] = *p++;
     }
     if (len >= (int) buf_size || (ch != ' ' && *p != ch)) {
@@ -4109,7 +4289,7 @@ static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
 
 static void send_file_data(struct mg_connection *conn, FILE *fp) {
   char buf[IOBUF_SIZE];
-  int n;
+  size_t n;
   while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
     mg_write(conn, buf, n);
   }
@@ -4133,7 +4313,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';
@@ -4544,7 +4724,11 @@ static void try_parse(struct connection *conn) {
     // If request is buffered in, remove it from the iobuf. This is because
     // iobuf could be reallocated, and pointers in parsed request could
     // become invalid.
-    conn->request = (char *) malloc(conn->request_len);
+    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);
@@ -4638,7 +4822,7 @@ static void call_http_client_handler(struct connection *conn) {
   iobuf_remove(&conn->ns_conn->recv_iobuf, conn->mg_conn.content_len);
   conn->mg_conn.status_code = 0;
   conn->cl = conn->num_bytes_recv = conn->request_len = 0;
-  free(conn->request);
+  NS_FREE(conn->request);
   conn->request = NULL;
 }
 
@@ -4662,7 +4846,7 @@ struct mg_connection *mg_connect(struct mg_server *server, const char *addr) {
   nsconn = ns_connect(&server->ns_mgr, addr, mg_ev_handler, NULL);
   if (nsconn == NULL) return 0;
 
-  if ((conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
+  if ((conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
     nsconn->flags |= NSF_CLOSE_IMMEDIATELY;
     return 0;
   }
@@ -4754,8 +4938,8 @@ static void close_local_endpoint(struct connection *conn) {
 
   // Gobble possible POST data sent to the URI handler
   iobuf_free(&conn->ns_conn->recv_iobuf);
-  free(conn->request);
-  free(conn->path_info);
+  NS_FREE(conn->request);
+  NS_FREE(conn->path_info);
   conn->endpoint.nc = NULL;
   conn->request = conn->path_info = NULL;
 
@@ -4763,7 +4947,7 @@ static void close_local_endpoint(struct connection *conn) {
   conn->cl = conn->num_bytes_recv = conn->request_len = 0;
   conn->ns_conn->flags &= ~(NSF_FINISHED_SENDING_DATA |
                             NSF_BUFFER_BUT_DONT_SEND | NSF_CLOSE_IMMEDIATELY |
-                            MG_HEADERS_SENT | MG_LONG_RUNNING);
+                            MG_HEADERS_SENT | MG_USING_CHUNKED_API);
 
   // Do not memset() the whole structure, as some of the fields
   // (IP addresses & ports, server_param) must survive. Nullify the rest.
@@ -4781,7 +4965,7 @@ static void close_local_endpoint(struct connection *conn) {
 
 static void transfer_file_data(struct connection *conn) {
   char buf[IOBUF_SIZE];
-  int n;
+  size_t n;
 
   // If output buffer is too big, don't send anything. Wait until
   // mongoose drains already buffered data to the client.
@@ -4802,7 +4986,7 @@ static void transfer_file_data(struct connection *conn) {
   }
 }
 
-int mg_poll_server(struct mg_server *server, int milliseconds) {
+time_t mg_poll_server(struct mg_server *server, int milliseconds) {
   return ns_mgr_poll(&server->ns_mgr, milliseconds);
 }
 
@@ -4813,9 +4997,9 @@ void mg_destroy_server(struct mg_server **server) {
 
     ns_mgr_free(&s->ns_mgr);
     for (i = 0; i < (int) ARRAY_SIZE(s->config_options); i++) {
-      free(s->config_options[i]);  // It is OK to free(NULL)
+      NS_FREE(s->config_options[i]);  // It is OK to free(NULL)
     }
-    free(s);
+    NS_FREE(s);
     *server = NULL;
   }
 }
@@ -4831,20 +5015,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
@@ -4852,6 +5033,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;
 
@@ -4877,16 +5060,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++;
@@ -4941,8 +5129,16 @@ void mg_copy_listeners(struct mg_server *s, struct mg_server *to) {
   for (c = ns_next(&s->ns_mgr, NULL); c != NULL; c = ns_next(&s->ns_mgr, c)) {
     struct ns_connection *tmp;
     if ((c->flags & NSF_LISTENING) &&
-        (tmp = (struct ns_connection *) malloc(sizeof(*tmp))) != NULL) {
+        (tmp = (struct ns_connection *) NS_MALLOC(sizeof(*tmp))) != NULL) {
       memcpy(tmp, c, sizeof(*tmp));
+
+#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);
     }
@@ -4988,7 +5184,7 @@ const char *mg_set_option(struct mg_server *server, const char *name,
   }
 
   if (*v != NULL) {
-    free(*v);
+    NS_FREE(*v);
     *v = NULL;
   }
 
@@ -4998,25 +5194,44 @@ 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);
-        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;
 #endif
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(MONGOOSE_NO_USER)
   } else if (ind == RUN_AS_USER) {
     struct passwd *pw;
     if ((pw = getpwnam(value)) == NULL) {
@@ -5050,7 +5265,7 @@ static void on_accept(struct ns_connection *nc, union socket_address *sa) {
 
   if (!check_acl(server->config_options[ACCESS_CONTROL_LIST],
                  ntohl(* (uint32_t *) &sa->sin.sin_addr)) ||
-      (conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
+      (conn = (struct connection *) NS_CALLOC(1, sizeof(*conn))) == NULL) {
     nc->flags |= NSF_CLOSE_IMMEDIATELY;
   } else {
     // Circularly link two connection structures
@@ -5077,31 +5292,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:
@@ -5162,7 +5378,7 @@ static void mg_ev_handler(struct ns_connection *nc, int ev, void *p) {
         call_user(conn, MG_CLOSE);
         close_local_endpoint(conn);
         conn->ns_conn = NULL;
-        free(conn);
+        NS_FREE(conn);
       }
       break;
 
@@ -5173,6 +5389,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) {
@@ -5209,7 +5430,7 @@ static void iter2(struct ns_connection *nc, int ev, void *param) {
   (void) ev;
 
   //DBG(("%p [%s]", conn, msg));
-  if (sscanf(msg, "%p %n", &func, &n) && func != NULL) {
+  if (sscanf(msg, "%p %n", &func, &n) && func != NULL && conn != NULL) {
     conn->mg_conn.callback_param = (void *) (msg + n);
     func(&conn->mg_conn, MG_POLL);
   }
@@ -5242,7 +5463,7 @@ const char *mg_get_option(const struct mg_server *server, const char *name) {
 }
 
 struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
-  struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
+  struct mg_server *server = (struct mg_server *) NS_CALLOC(1, sizeof(*server));
   ns_mgr_init(&server->ns_mgr, server_data);
   set_default_option_values(server->config_options);
   server->event_handler = handler;
index 96c8c90b1f7b507c11d79650b03c4b607a90452a..f2c47a5ce837ea7cf2c503f9217e75ccaf443161 100644 (file)
@@ -2,28 +2,27 @@
 // Copyright (c) 2013-2014 Cesanta Software Limited
 // All rights reserved
 //
-// This library is dual-licensed: you can redistribute it and/or modify
+// This software is dual-licensed: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License version 2 as
 // published by the Free Software Foundation. For the terms of this
 // license, see <http://www.gnu.org/licenses/>.
 //
-// You are free to use this library under the terms of the GNU General
+// You are free to use this software under the terms of the GNU General
 // Public License, but WITHOUT ANY WARRANTY; without even the implied
 // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 // See the GNU General Public License for more details.
 //
-// Alternatively, you can license this library under a commercial
+// Alternatively, you can license this software under a commercial
 // license, as set out in <http://cesanta.com/>.
-//
-// $Date: 2014-09-09 17:07:55 UTC $
 
 #ifndef MONGOOSE_HEADER_INCLUDED
 #define  MONGOOSE_HEADER_INCLUDED
 
-#define MONGOOSE_VERSION "5.5"
+#define MONGOOSE_VERSION "5.6"
 
 #include <stdio.h>      // required for FILE
 #include <stddef.h>     // required for size_t
+#include <sys/types.h>  // required for time_t
 
 #ifdef __cplusplus
 extern "C" {
@@ -53,7 +52,7 @@ struct mg_connection {
   int is_websocket;           // Connection is a websocket connection
   int status_code;            // HTTP status code for HTTP error handler
   int wsbits;                 // First byte of the websocket frame
-  void *server_param;         // Parameter passed to mg_add_uri_handler()
+  void *server_param;         // Parameter passed to mg_create_server()
   void *connection_param;     // Placeholder for connection-specific data
   void *callback_param;
 };
@@ -61,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
@@ -90,7 +90,7 @@ enum {
 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);
-int mg_poll_server(struct mg_server *, int milliseconds);
+time_t mg_poll_server(struct mg_server *, int milliseconds);
 const char **mg_get_valid_option_names(void);
 const char *mg_get_option(const struct mg_server *server, const char *name);
 void mg_copy_listeners(struct mg_server *from, struct mg_server *to);
@@ -104,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_write(struct mg_connection *, const void *buf, int len);
+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);
@@ -119,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,
@@ -130,8 +134,8 @@ int mg_parse_multipart(const char *buf, int buf_len,
 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);
-int mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
-int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int);
+size_t mg_url_encode(const char *src, size_t s_len, char *dst, size_t dst_len);
+int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int);
 int mg_terminate_ssl(struct mg_connection *c, const char *cert);
 int mg_forward(struct mg_connection *c, const char *addr);
 void *mg_mmap(FILE *fp, size_t size);