celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From abroekh...@apache.org
Subject svn commit: r1654979 [2/2] - in /celix/trunk/remote_services: discovery/private/src/endpoint_discovery_poller.c utils/private/include/civetweb.h utils/private/src/civetweb.c
Date Tue, 27 Jan 2015 06:28:24 GMT
Modified: celix/trunk/remote_services/utils/private/src/civetweb.c
URL: http://svn.apache.org/viewvc/celix/trunk/remote_services/utils/private/src/civetweb.c?rev=1654979&r1=1654978&r2=1654979&view=diff
==============================================================================
--- celix/trunk/remote_services/utils/private/src/civetweb.c (original)
+++ celix/trunk/remote_services/utils/private/src/civetweb.c Tue Jan 27 06:28:23 2015
@@ -1,66 +1,83 @@
-// Copyright (c) 2004-2013 Sergey Lyubka
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
+/* Copyright (c) 2013-2015 the Civetweb developers
+ * Copyright (c) 2004-2013 Sergey Lyubka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
 
 #if defined(_WIN32)
 #if !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
+#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
 #endif
 #else
 #ifdef __linux__
-#define _XOPEN_SOURCE 600     // For flockfile() on Linux
+#define _XOPEN_SOURCE 600     /* For flockfile() on Linux */
+#endif
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE     /* For fseeko(), ftello() */
+#endif
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64  /* Use 64-bit file offsets by default */
+#endif
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS  /* <inttypes.h> wants this for C++ */
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS   /* C++ wants that for INT64_MAX */
 #endif
-#define _LARGEFILE_SOURCE     // Enable 64-bit file offsets
-#define __STDC_FORMAT_MACROS  // <inttypes.h> wants this for C++
-#define __STDC_LIMIT_MACROS   // C++ wants that for INT64_MAX
 #endif
 
 #if defined (_MSC_VER)
-// conditional expression is constant: introduced by FD_SET(..)
+/* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
+#pragma warning (disable : 4306 )
+/* conditional expression is constant: introduced by FD_SET(..) */
 #pragma warning (disable : 4127)
-// non-constant aggregate initializer: issued due to missing C99 support
+/* non-constant aggregate initializer: issued due to missing C99 support */
 #pragma warning (disable : 4204)
 #endif
 
-// Disable WIN32_LEAN_AND_MEAN.
-// This makes windows.h always include winsock2.h
-#ifdef WIN32_LEAN_AND_MEAN
+/* Disable WIN32_LEAN_AND_MEAN.
+   This makes windows.h always include winsock2.h */
+#if defined(WIN32_LEAN_AND_MEAN)
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
+#if defined USE_IPV6 && defined(_WIN32)
+#include <ws2tcpip.h>
+#endif
+
 #if defined(__SYMBIAN32__)
-#define NO_SSL // SSL is not supported
-#define NO_CGI // CGI is not supported
+#define NO_SSL /* SSL is not supported */
+#define NO_CGI /* CGI is not supported */
 #define PATH_MAX FILENAME_MAX
-#endif // __SYMBIAN32__
+#endif /* __SYMBIAN32__ */
 
 #ifndef IGNORE_UNUSED_RESULT
 #define IGNORE_UNUSED_RESULT(a) (void)((a) && 1)
 #endif
 
-#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
+#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <signal.h>
 #include <fcntl.h>
-#endif // !_WIN32_WCE
+#endif /* !_WIN32_WCE */
 
 #include <time.h>
 #include <stdlib.h>
@@ -72,38 +89,51 @@
 #include <stddef.h>
 #include <stdio.h>
 
-#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
+#ifndef MAX_WORKER_THREADS
+#define MAX_WORKER_THREADS (1024*64)
+#endif
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */
+#if defined(_MSC_VER) && _MSC_VER <= 1400
 #undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0400 // To make it link in VS2005
+#define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */
+#endif
 #include <windows.h>
+typedef const char * SOCK_OPT_TYPE;
 
 #ifndef PATH_MAX
 #define PATH_MAX MAX_PATH
 #endif
 
+#ifndef _IN_PORT_T
+#ifndef in_port_t
+#define in_port_t u_short
+#endif
+#endif
+
 #ifndef _WIN32_WCE
 #include <process.h>
 #include <direct.h>
 #include <io.h>
-#else // _WIN32_WCE
-#define NO_CGI // WinCE has no pipes
+#else /* _WIN32_WCE */
+#define NO_CGI /* WinCE has no pipes */
 
 typedef long off_t;
 
 #define errno   GetLastError()
 #define strerror(x)  _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
-#endif // _WIN32_WCE
+#endif /* _WIN32_WCE */
 
 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
       ((uint64_t)((uint32_t)(hi))) << 32))
-#define RATE_DIFF 10000000 // 100 nsecs
+#define RATE_DIFF 10000000 /* 100 nsecs */
 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
 #define SYS2UNIX_TIME(lo, hi) \
   (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
 
-// Visual Studio 6 does not know __func__ or __FUNCTION__
-// The rest of MS compilers use __FUNCTION__, not C99 __func__
-// Also use _strtoui64 on modern M$ compilers
+/* Visual Studio 6 does not know __func__ or __FUNCTION__
+   The rest of MS compilers use __FUNCTION__, not C99 __func__
+   Also use _strtoui64 on modern M$ compilers */
 #if defined(_MSC_VER) && _MSC_VER < 1300
 #define STRX(x) #x
 #define STR(x) STRX(x)
@@ -114,16 +144,17 @@ typedef long off_t;
 #define __func__  __FUNCTION__
 #define strtoull(x, y, z) _strtoui64(x, y, z)
 #define strtoll(x, y, z) _strtoi64(x, y, z)
-#endif // _MSC_VER
+#endif /* _MSC_VER */
 
 #define ERRNO   GetLastError()
 #define NO_SOCKLEN_T
 #define SSL_LIB   "ssleay32.dll"
 #define CRYPTO_LIB  "libeay32.dll"
 #define O_NONBLOCK  0
+#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
 #if !defined(EWOULDBLOCK)
 #define EWOULDBLOCK  WSAEWOULDBLOCK
-#endif // !EWOULDBLOCK
+#endif /* !EWOULDBLOCK */
 #define _POSIX_
 #define INT64_FMT  "I64d"
 
@@ -131,6 +162,7 @@ typedef long off_t;
 #define SHUT_WR 1
 #define snprintf _snprintf
 #define vsnprintf _vsnprintf
+#define access _access
 #define mg_sleep(x) Sleep(x)
 
 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
@@ -152,20 +184,45 @@ typedef long off_t;
 #define sleep(x) Sleep((x) * 1000)
 #define rmdir(x) _rmdir(x)
 
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+#define USE_TIMERS
+#endif
+
 #if !defined(va_copy)
 #define va_copy(x, y) x = y
-#endif // !va_copy MINGW #defines va_copy
+#endif /* !va_copy MINGW #defines va_copy */
 
 #if !defined(fileno)
 #define fileno(x) _fileno(x)
-#endif // !fileno MINGW #defines fileno
+#endif /* !fileno MINGW #defines fileno */
 
 typedef HANDLE pthread_mutex_t;
+typedef DWORD pthread_key_t;
+typedef HANDLE pthread_t;
 typedef struct {
-    HANDLE signal, broadcast;
+    CRITICAL_SECTION threadIdSec;
+    int waitingthreadcount;        /* The number of threads queued. */
+    pthread_t *waitingthreadhdls;  /* The thread handles. */
 } pthread_cond_t;
-typedef HANDLE pthread_t;
-#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
+
+#ifndef __clockid_t_defined
+typedef DWORD clockid_t;
+#endif
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC (1)
+#endif
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME  (2)
+#endif
+
+#ifndef _TIMESPEC_DEFINED
+struct timespec {
+    time_t   tv_sec;        /* seconds */
+    long     tv_nsec;       /* nanoseconds */
+};
+#endif
+
+#define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
 
 static int pthread_mutex_lock(pthread_mutex_t *);
 static int pthread_mutex_unlock(pthread_mutex_t *);
@@ -181,9 +238,9 @@ typedef unsigned short  uint16_t;
 typedef unsigned __int64 uint64_t;
 typedef __int64   int64_t;
 #define INT64_MAX  9223372036854775807
-#endif // HAVE_STDINT
+#endif /* HAVE_STDINT */
 
-// POSIX dirent interface
+/* POSIX dirent interface */
 struct dirent {
     char d_name[PATH_MAX];
 };
@@ -194,6 +251,7 @@ typedef struct DIR {
     struct dirent  result;
 } DIR;
 
+#if !defined(USE_IPV6) && defined(_WIN32)
 #ifndef HAVE_POLL
 struct pollfd {
     SOCKET fd;
@@ -202,23 +260,29 @@ struct pollfd {
 };
 #define POLLIN 1
 #endif
+#endif
 
-
-// Mark required libraries
+/* Mark required libraries */
 #ifdef _MSC_VER
 #pragma comment(lib, "Ws2_32.lib")
 #endif
 
-#else    // UNIX  specific
+#else    /* UNIX  specific */
 #include <sys/wait.h>
 #include <sys/socket.h>
 #include <sys/poll.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/time.h>
+#include <sys/utsname.h>
 #include <stdint.h>
 #include <inttypes.h>
 #include <netdb.h>
+typedef const void * SOCK_OPT_TYPE;
+
+#if defined(ANDROID)
+typedef unsigned short int in_port_t;
+#endif
 
 #include <pwd.h>
 #include <unistd.h>
@@ -240,7 +304,7 @@ struct pollfd {
 #endif
 #ifndef O_BINARY
 #define O_BINARY  0
-#endif // O_BINARY
+#endif /* O_BINARY */
 #define closesocket(a) close(a)
 #define mg_mkdir(x, y) mkdir(x, y)
 #define mg_remove(x) remove(x)
@@ -251,11 +315,44 @@ struct pollfd {
 typedef int SOCKET;
 #define WINCDECL
 
-#endif // End of Windows and UNIX specific includes
+#endif /* End of Windows and UNIX specific includes */
+
+#ifdef _WIN32
+static CRITICAL_SECTION global_log_file_lock;
+static DWORD pthread_self(void)
+{
+    return GetCurrentThreadId();
+}
+
+int pthread_key_create(pthread_key_t *key, void (*_must_be_zero)(void*) /* destructor function not supported for windows */)
+{
+    assert(_must_be_zero == NULL);
+    if ((key!=0) && (_must_be_zero == NULL)) {
+        *key = TlsAlloc();
+        return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
+    }
+    return -2;
+}
+
+int pthread_key_delete(pthread_key_t key)
+{
+    return TlsFree(key) ? 0 : 1;
+}
+
+int pthread_setspecific(pthread_key_t key, void * value)
+{
+    return TlsSetValue(key, value) ? 0 : 1;
+}
+
+void *pthread_getspecific(pthread_key_t key)
+{
+    return TlsGetValue(key);
+}
+#endif /* _WIN32 */
+
 
 #include "civetweb.h"
 
-#define CIVETWEB_VERSION "1.5"
 #define PASSWORDS_FILE_NAME ".htpasswd"
 #define CGI_ENVIRONMENT_SIZE 4096
 #define MAX_CGI_ENVIR_VARS 64
@@ -265,44 +362,179 @@ typedef int SOCKET;
 #endif
 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
 
-#ifdef _WIN32
-static CRITICAL_SECTION global_log_file_lock;
-static DWORD pthread_self(void)
-{
-    return GetCurrentThreadId();
+#if !defined(DEBUG_TRACE)
+#if defined(DEBUG)
+
+static void DEBUG_TRACE_FUNC(const char *func, unsigned line, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4);
+
+static void DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) {
+
+  va_list args;
+  flockfile(stdout);
+  printf("*** %lu.%p.%s.%u: ",
+         (unsigned long) time(NULL), (void *) pthread_self(),
+         func, line);
+  va_start(args, fmt);
+  vprintf(fmt, args);
+  va_end(args);
+  putchar('\n');
+  fflush(stdout);
+  funlockfile(stdout);
 }
-#endif // _WIN32
 
-#define MD5_STATIC static
-#include "md5.inl"
+#define DEBUG_TRACE(fmt, ...) DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
 
-#ifdef DEBUG_TRACE
-#undef DEBUG_TRACE
-#define DEBUG_TRACE(x)
 #else
-#if defined(DEBUG)
-#define DEBUG_TRACE(x) do { \
-  flockfile(stdout); \
-  printf("*** %lu.%p.%s.%d: ", \
-         (unsigned long) time(NULL), (void *) pthread_self(), \
-         __func__, __LINE__); \
-  printf x; \
-  putchar('\n'); \
-  fflush(stdout); \
-  funlockfile(stdout); \
-} while (0)
+#define DEBUG_TRACE(fmt, ...)
+#endif /* DEBUG */
+#endif /* DEBUG_TRACE */
+
+#if defined(MEMORY_DEBUGGING)
+static unsigned long blockCount = 0;
+static unsigned long totalMemUsed = 0;
+
+static void * mg_malloc_ex(size_t size, const char * file, unsigned line) {
+
+    void * data = malloc(size + sizeof(size_t));
+    void * memory = 0;
+    char mallocStr[256];
+
+    if (data) {
+        *(size_t*)data = size;
+        totalMemUsed += size;
+        blockCount++;
+        memory = (void *)(((char*)data)+sizeof(size_t));
+    }
+
+    sprintf(mallocStr, "MEM: %p %5lu alloc   %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line);
+#if defined(_WIN32)
+    OutputDebugStringA(mallocStr);
+#else
+    DEBUG_TRACE("%s", mallocStr);
+#endif
+
+    return memory;
+}
+
+static void * mg_calloc_ex(size_t count, size_t size, const char * file, unsigned line) {
+
+    void * data = mg_malloc_ex(size*count, file, line);
+    if (data) memset(data, 0, size);
+
+    return data;
+}
+
+static void mg_free_ex(void * memory, const char * file, unsigned line) {
+
+    char mallocStr[256];
+    void * data = (void *)(((char*)memory)-sizeof(size_t));
+    size_t size;
+
+    if (memory) {
+        size = *(size_t*)data;
+        totalMemUsed -= size;
+        blockCount--;
+        sprintf(mallocStr, "MEM: %p %5lu free    %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line);
+#if defined(_WIN32)
+        OutputDebugStringA(mallocStr);
 #else
-#define DEBUG_TRACE(x)
-#endif // DEBUG
-#endif // DEBUG_TRACE
+        DEBUG_TRACE("%s", mallocStr);
+#endif
+
+        free(data);
+    }
+}
+
+static void * mg_realloc_ex(void * memory, size_t newsize, const char * file, unsigned line) {
+
+    char mallocStr[256];
+    void * data;
+    void * _realloc;
+    size_t oldsize;
 
-// Darwin prior to 7.0 and Win32 do not have socklen_t
+    if (newsize) {
+        if (memory) {
+            data = (void *)(((char*)memory)-sizeof(size_t));
+            oldsize = *(size_t*)data;
+            _realloc = realloc(data, newsize+sizeof(size_t));
+            if (_realloc) {
+                data = _realloc;
+                totalMemUsed -= oldsize;
+                sprintf(mallocStr, "MEM: %p %5lu r-free  %7lu %4lu --- %s:%u\n", memory, (unsigned long)oldsize, totalMemUsed, blockCount, file, line);
+#if defined(_WIN32)
+                OutputDebugStringA(mallocStr);
+#else
+                DEBUG_TRACE("%s", mallocStr);
+#endif
+                totalMemUsed += newsize;
+                sprintf(mallocStr, "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)newsize, totalMemUsed, blockCount, file, line);
+#if defined(_WIN32)
+                OutputDebugStringA(mallocStr);
+#else
+                DEBUG_TRACE("%s", mallocStr);
+#endif
+                *(size_t*)data = newsize;
+                data = (void *)(((char*)data)+sizeof(size_t));
+            } else {
+#if defined(_WIN32)
+                OutputDebugStringA("MEM: realloc failed\n");
+#else
+                DEBUG_TRACE("%s", "MEM: realloc failed\n");
+#endif
+                return _realloc;
+            }
+        } else {
+            data = mg_malloc_ex(newsize, file, line);
+        }
+    } else {
+        data = 0;
+        mg_free_ex(memory, file, line);
+    }
+
+    return data;
+}
+
+#define mg_malloc(a)      mg_malloc_ex(a, __FILE__, __LINE__)
+#define mg_calloc(a,b)    mg_calloc_ex(a, b, __FILE__, __LINE__)
+#define mg_realloc(a, b)  mg_realloc_ex(a, b, __FILE__, __LINE__)
+#define mg_free(a)        mg_free_ex(a, __FILE__, __LINE__)
+
+#else
+static __inline void * mg_malloc(size_t a)             {return malloc(a);}
+static __inline void * mg_calloc(size_t a, size_t b)   {return calloc(a, b);}
+static __inline void * mg_realloc(void * a, size_t b)  {return realloc(a, b);}
+static __inline void   mg_free(void * a)               {free(a);}
+#endif
+
+/* This following lines are just meant as a reminder to use the mg-functions for memory management */
+#ifdef malloc
+    #undef malloc
+#endif
+#ifdef calloc
+    #undef calloc
+#endif
+#ifdef realloc
+    #undef realloc
+#endif
+#ifdef free
+    #undef free
+#endif
+#define malloc  DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
+#define calloc  DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
+#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
+#define free    DO_NOT_USE_THIS_FUNCTION__USE_mg_free
+
+
+#define MD5_STATIC static
+#include "md5.inl"
+
+/* Darwin prior to 7.0 and Win32 do not have socklen_t */
 #ifdef NO_SOCKLEN_T
 typedef int socklen_t;
-#endif // NO_SOCKLEN_T
+#endif /* NO_SOCKLEN_T */
 #define _DARWIN_UNLIMITED_SELECT
 
-#define IP_ADDR_STR_LEN 50  // IPv6 hex string is 46 chars
+#define IP_ADDR_STR_LEN 50  /* IPv6 hex string is 46 chars */
 
 #if !defined(MSG_NOSIGNAL)
 #define MSG_NOSIGNAL 0
@@ -316,26 +548,26 @@ typedef int socklen_t;
 #define PATH_MAX 4096
 #endif
 
-// Size of the accepted socket queue
+/* Size of the accepted socket queue */
 #if !defined(MGSQLEN)
 #define MGSQLEN 20
 #endif
 
-static const char *http_500_error = "Internal Server Error";
-
 #if defined(NO_SSL_DL)
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #else
-// SSL loaded dynamically from DLL.
-// I put the prototypes here to be independent from OpenSSL source installation.
+/* SSL loaded dynamically from DLL.
+   I put the prototypes here to be independent from OpenSSL source
+   installation. */
+
 typedef struct ssl_st SSL;
 typedef struct ssl_method_st SSL_METHOD;
 typedef struct ssl_ctx_st SSL_CTX;
 
 struct ssl_func {
-    const char *name;   // SSL function name
-    void  (*ptr)(void); // Function pointer
+    const char *name;   /* SSL function name */
+    void  (*ptr)(void); /* Function pointer */
 };
 
 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
@@ -372,10 +604,10 @@ struct ssl_func {
 #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
 #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
 
-// set_ssl_option() function updates this array.
-// It loads SSL library dynamically and changes NULLs to the actual addresses
-// of respective functions. The macros above (like SSL_connect()) are really
-// just calling these functions indirectly via the pointer.
+/* set_ssl_option() function updates this array.
+   It loads SSL library dynamically and changes NULLs to the actual addresses
+   of respective functions. The macros above (like SSL_connect()) are really
+   just calling these functions indirectly via the pointer. */
 static struct ssl_func ssl_sw[] = {
     {"SSL_free",   NULL},
     {"SSL_accept",   NULL},
@@ -401,7 +633,8 @@ static struct ssl_func ssl_sw[] = {
     {NULL,    NULL}
 };
 
-// Similar array as ssl_sw. These functions could be located in different lib.
+/* Similar array as ssl_sw. These functions could be located in different
+   lib. */
 #if !defined(NO_SSL)
 static struct ssl_func crypto_sw[] = {
     {"CRYPTO_num_locks",  NULL},
@@ -411,16 +644,16 @@ static struct ssl_func crypto_sw[] = {
     {"ERR_error_string", NULL},
     {NULL,    NULL}
 };
-#endif // NO_SSL
-#endif // NO_SSL_DL
+#endif /* NO_SSL */
+#endif /* NO_SSL_DL */
 
 static const char *month_names[] = {
     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 };
 
-// Unified socket address. For IPv6 support, add IPv6 address structure
-// in the union u.
+/* Unified socket address. For IPv6 support, add IPv6 address structure
+   in the union u. */
 union usa {
     struct sockaddr sa;
     struct sockaddr_in sin;
@@ -429,7 +662,7 @@ union usa {
 #endif
 };
 
-// Describes a string (chunk of memory).
+/* Describes a string (chunk of memory). */
 struct vec {
     const char *ptr;
     size_t len;
@@ -440,24 +673,25 @@ struct file {
     time_t modification_time;
     int64_t size;
     FILE *fp;
-    const char *membuf;   // Non-NULL if file data is in memory
-    // set to 1 if the content is gzipped
-    // in which case we need a content-encoding: gzip header
+    const char *membuf;   /* Non-NULL if file data is in memory */
+    /* set to 1 if the content is gzipped
+       in which case we need a content-encoding: gzip header */
     int gzipped;
 };
 #define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
 
-// Describes listening socket, or socket which was accept()-ed by the master
-// thread and queued for future handling by the worker thread.
+/* Describes listening socket, or socket which was accept()-ed by the master
+   thread and queued for future handling by the worker thread. */
 struct socket {
-    SOCKET sock;          // Listening socket
-    union usa lsa;        // Local socket address
-    union usa rsa;        // Remote socket address
-    unsigned is_ssl:1;    // Is port SSL-ed
-    unsigned ssl_redir:1; // Is port supposed to redirect everything to SSL port
+    SOCKET sock;          /* Listening socket */
+    union usa lsa;        /* Local socket address */
+    union usa rsa;        /* Remote socket address */
+    unsigned is_ssl:1;    /* Is port SSL-ed */
+    unsigned ssl_redir:1; /* Is port supposed to redirect everything to SSL
+                             port */
 };
 
-// NOTE(lsm): this enum shoulds be in sync with the config_options below.
+/* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
 enum {
     CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
     PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
@@ -465,118 +699,292 @@ enum {
     GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
     EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
     NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
+    DECODE_URL,
+
+#if defined(USE_LUA)
+    LUA_PRELOAD_FILE, LUA_SCRIPT_EXTENSIONS, LUA_SERVER_PAGE_EXTENSIONS,
+#endif
+#if defined(USE_WEBSOCKET)
+    WEBSOCKET_ROOT,
+#endif
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+    LUA_WEBSOCKET_EXTENSIONS,
+#endif
+    ACCESS_CONTROL_ALLOW_ORIGIN, ERROR_PAGES,
+
     NUM_OPTIONS
 };
 
-static const char *config_options[] = {
-    "cgi_pattern", "**.cgi$|**.pl$|**.php$",
-    "cgi_environment", NULL,
-    "put_delete_auth_file", NULL,
-    "cgi_interpreter", NULL,
-    "protect_uri", NULL,
-    "authentication_domain", "mydomain.com",
-    "ssi_pattern", "**.shtml$|**.shtm$",
-    "throttle", NULL,
-    "access_log_file", NULL,
-    "enable_directory_listing", "yes",
-    "error_log_file", NULL,
-    "global_auth_file", NULL,
-    "index_files",
-    "index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
-    "enable_keep_alive", "no",
-    "access_control_list", NULL,
-    "extra_mime_types", NULL,
-    "listening_ports", "8080",
-    "document_root",  NULL,
-    "ssl_certificate", NULL,
-    "num_threads", "50",
-    "run_as_user", NULL,
-    "url_rewrite_patterns", NULL,
-    "hide_files_patterns", NULL,
-    "request_timeout_ms", "30000",
-    NULL
+/* Config option name, config types, default value */
+static struct mg_option config_options[] = {
+    {"cgi_pattern",                 CONFIG_TYPE_EXT_PATTERN,   "**.cgi$|**.pl$|**.php$"},
+    {"cgi_environment",             CONFIG_TYPE_STRING,        NULL},
+    {"put_delete_auth_file",        CONFIG_TYPE_FILE,          NULL},
+    {"cgi_interpreter",             CONFIG_TYPE_FILE,          NULL},
+    {"protect_uri",                 CONFIG_TYPE_STRING,        NULL},
+    {"authentication_domain",       CONFIG_TYPE_STRING,        "mydomain.com"},
+    {"ssi_pattern",                 CONFIG_TYPE_EXT_PATTERN,   "**.shtml$|**.shtm$"},
+    {"throttle",                    CONFIG_TYPE_STRING,        NULL},
+    {"access_log_file",             CONFIG_TYPE_FILE,          NULL},
+    {"enable_directory_listing",    CONFIG_TYPE_BOOLEAN,       "yes"},
+    {"error_log_file",              CONFIG_TYPE_FILE,          NULL},
+    {"global_auth_file",            CONFIG_TYPE_FILE,          NULL},
+    {"index_files",                 CONFIG_TYPE_STRING,
+#ifdef USE_LUA
+    "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,index.shtml,index.php"},
+#else
+    "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
+#endif
+    {"enable_keep_alive",           CONFIG_TYPE_BOOLEAN,       "no"},
+    {"access_control_list",         CONFIG_TYPE_STRING,        NULL},
+    {"extra_mime_types",            CONFIG_TYPE_STRING,        NULL},
+    {"listening_ports",             CONFIG_TYPE_STRING,        "8080"},
+    {"document_root",               CONFIG_TYPE_DIRECTORY,     NULL},
+    {"ssl_certificate",             CONFIG_TYPE_FILE,          NULL},
+    {"num_threads",                 CONFIG_TYPE_NUMBER,        "50"},
+    {"run_as_user",                 CONFIG_TYPE_STRING,        NULL},
+    {"url_rewrite_patterns",        CONFIG_TYPE_STRING,        NULL},
+    {"hide_files_patterns",         CONFIG_TYPE_EXT_PATTERN,   NULL},
+    {"request_timeout_ms",          CONFIG_TYPE_NUMBER,        "30000"},
+    {"decode_url",                  CONFIG_TYPE_BOOLEAN,       "yes"},
+
+#if defined(USE_LUA)
+    {"lua_preload_file",            CONFIG_TYPE_FILE,          NULL},
+    {"lua_script_pattern",          CONFIG_TYPE_EXT_PATTERN,   "**.lua$"},
+    {"lua_server_page_pattern",     CONFIG_TYPE_EXT_PATTERN,   "**.lp$|**.lsp$"},
+#endif
+#if defined(USE_WEBSOCKET)
+    {"websocket_root",              CONFIG_TYPE_DIRECTORY,     NULL},
+#endif
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+    {"lua_websocket_pattern",       CONFIG_TYPE_EXT_PATTERN,   "**.lua$"},
+#endif
+    {"access_control_allow_origin", CONFIG_TYPE_STRING,        "*"},
+    {"error_pages",                 CONFIG_TYPE_DIRECTORY,     NULL},
+
+    {NULL, CONFIG_TYPE_UNKNOWN, NULL}
 };
 
 struct mg_request_handler_info {
     char *uri;
     size_t uri_len;
     mg_request_handler handler;
+
     void *cbdata;
     struct mg_request_handler_info *next;
 };
 
 struct mg_context {
-    volatile int stop_flag;         // Should we stop event loop
-    void *ssllib_dll_handle;        // Store the ssl library handle.
-    void *cryptolib_dll_handle;     // Store the crypto library handle.
-    SSL_CTX *ssl_ctx;               // SSL context
-    char *config[NUM_OPTIONS];      // Civetweb configuration parameters
-    struct mg_callbacks callbacks;  // User-defined callback function
-    void *user_data;                // User-defined data
+    volatile int stop_flag;         /* Should we stop event loop */
+    SSL_CTX *ssl_ctx;               /* SSL context */
+    char *config[NUM_OPTIONS];      /* Civetweb configuration parameters */
+    struct mg_callbacks callbacks;  /* User-defined callback function */
+    void *user_data;                /* User-defined data */
+    int context_type;               /* 1 = server context, 2 = client context */
 
     struct socket *listening_sockets;
+    in_port_t *listening_ports;
     int num_listening_sockets;
 
-    volatile int num_threads;  // Number of threads
-    pthread_mutex_t mutex;     // Protects (max|num)_threads
-    pthread_cond_t  cond;      // Condvar for tracking workers terminations
-
-    struct socket queue[MGSQLEN];   // Accepted sockets
-    volatile int sq_head;      // Head of the socket queue
-    volatile int sq_tail;      // Tail of the socket queue
-    pthread_cond_t sq_full;    // Signaled when socket is produced
-    pthread_cond_t sq_empty;   // Signaled when socket is consumed
-    pthread_t masterthreadid;  // The master thread ID.
-    int workerthreadcount;     // The amount of worker threads.
-    pthread_t *workerthreadids;// The worker thread IDs.
+    volatile int num_threads;       /* Number of threads */
+    pthread_mutex_t thread_mutex;   /* Protects (max|num)_threads */
+    pthread_cond_t thread_cond;     /* Condvar for tracking workers terminations */
+
+    struct socket queue[MGSQLEN];   /* Accepted sockets */
+    volatile int sq_head;           /* Head of the socket queue */
+    volatile int sq_tail;           /* Tail of the socket queue */
+    pthread_cond_t sq_full;         /* Signaled when socket is produced */
+    pthread_cond_t sq_empty;        /* Signaled when socket is consumed */
+    pthread_t masterthreadid;       /* The master thread ID */
+    int workerthreadcount;          /* The amount of worker threads. */
+    pthread_t *workerthreadids;     /* The worker thread IDs */
+
+    unsigned long start_time;       /* Server start time, used for authentication */
+    pthread_mutex_t nonce_mutex;    /* Protects nonce_count */
+    unsigned long nonce_count;      /* Used nonces, used for authentication */
 
-    // linked list of uri handlers
+    char *systemName;               /* What operating system is running */
+
+    /* linked list of uri handlers */
     struct mg_request_handler_info *request_handlers;
+
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+    /* linked list of shared lua websockets */
+    struct mg_shared_lua_websocket_list *shared_lua_websockets;
+#endif
+
+#ifdef USE_TIMERS
+    struct ttimers * timers;
+#endif
 };
 
 struct mg_connection {
     struct mg_request_info request_info;
     struct mg_context *ctx;
-    SSL *ssl;                   // SSL descriptor
-    SSL_CTX *client_ssl_ctx;    // SSL context for client connections
-    struct socket client;       // Connected client
-    time_t birth_time;          // Time when request was received
-    int64_t num_bytes_sent;     // Total bytes sent to client
-    int64_t content_len;        // Content-Length header value
-    int64_t consumed_content;   // How many bytes of content have been read
-    char *buf;                  // Buffer for received data
-    char *path_info;            // PATH_INFO part of the URL
-    int must_close;             // 1 if connection must be closed
-    int buf_size;               // Buffer size
-    int request_len;            // Size of the request + headers in a buffer
-    int data_len;               // Total size of data in a buffer
-    int status_code;            // HTTP reply status code, e.g. 200
-    int throttle;               // Throttling, bytes/sec. <= 0 means no throttle
-    time_t last_throttle_time;  // Last time throttled data was sent
-    int64_t last_throttle_bytes;// Bytes sent this second
-    pthread_mutex_t mutex;      // Used by mg_lock/mg_unlock to ensure atomic transmissions for websockets
+    SSL *ssl;                       /* SSL descriptor */
+    SSL_CTX *client_ssl_ctx;        /* SSL context for client connections */
+    struct socket client;           /* Connected client */
+    time_t birth_time;              /* Time when request was received */
+    int64_t num_bytes_sent;         /* Total bytes sent to client */
+    int64_t content_len;            /* Content-Length header value */
+    int64_t consumed_content;       /* How many bytes of content have been read */
+    char *buf;                      /* Buffer for received data */
+    char *path_info;                /* PATH_INFO part of the URL */
+    int must_close;                 /* 1 if connection must be closed */
+    int in_error_handler;           /* 1 if in handler for user defined error pages */
+    int buf_size;                   /* Buffer size */
+    int request_len;                /* Size of the request + headers in a buffer */
+    int data_len;                   /* Total size of data in a buffer */
+    int status_code;                /* HTTP reply status code, e.g. 200 */
+    int throttle;                   /* Throttling, bytes/sec. <= 0 means no throttle */
+    time_t last_throttle_time;      /* Last time throttled data was sent */
+    int64_t last_throttle_bytes;    /* Bytes sent this second */
+    pthread_mutex_t mutex;          /* Used by mg_lock_connection/mg_unlock_connection to ensure atomic transmissions for websockets */
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+    void * lua_websocket_state;     /* Lua_State for a websocket connection */
+#endif
 };
 
-// Directory entry
+static pthread_key_t sTlsKey;  /* Thread local storage index */
+static int sTlsInit = 0;
+
+struct mg_workerTLS {
+    int is_master;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+    HANDLE pthread_cond_helper_mutex;
+#endif
+};
+
+/* Directory entry */
 struct de {
     struct mg_connection *conn;
     char *file_name;
     struct file file;
 };
 
+#if defined(USE_WEBSOCKET)
+static int is_websocket_protocol(const struct mg_connection *conn);
+#else
+#define is_websocket_protocol(conn) (0)
+#endif
+
+int mg_atomic_inc(volatile int * addr)
+{
+    int ret;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+    ret = InterlockedIncrement((volatile unsigned int *) addr);
+#elif defined(__GNUC__)
+    ret = __sync_add_and_fetch(addr, 1);
+#else
+    ret = (++(*addr));
+#endif
+    return ret;
+}
+
+int mg_atomic_dec(volatile int * addr)
+{
+    int ret;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+    ret = InterlockedDecrement((volatile unsigned int *) addr);
+#elif defined(__GNUC__)
+    ret = __sync_sub_and_fetch(addr, 1);
+#else
+    ret = (--(*addr));
+#endif
+    return ret;
+}
+
+#if !defined(NO_THREAD_NAME)
+#if defined(_WIN32) && defined(_MSC_VER)
+/* Set the thread name for debugging purposes in Visual Studio
+   http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+*/
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+   DWORD dwType;     /* Must be 0x1000. */
+   LPCSTR szName;    /* Pointer to name (in user addr space). */
+   DWORD dwThreadID; /* Thread ID (-1=caller thread). */
+   DWORD dwFlags;    /* Reserved for future use, must be zero. */
+} THREADNAME_INFO;
+#pragma pack(pop)
+#elif defined(__linux__)
+#include <sys/prctl.h>
+#endif
+
+void mg_set_thread_name(const char* name)
+{
+    char threadName[16]; /* Max. thread length in Linux/OSX/.. */
+
+    if (snprintf(threadName, sizeof(threadName), "civetweb-%s", name)<0) return;
+    threadName[sizeof(threadName)-1] = 0;
+
+#if defined(_WIN32)
+#if defined(_MSC_VER)
+    /* Windows and Visual Studio Compiler */
+    __try
+    {
+        THREADNAME_INFO info;
+        info.dwType     = 0x1000;
+        info.szName     = threadName;
+        info.dwThreadID = -1;
+        info.dwFlags    = 0;
+
+        RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
+    }
+    __except(EXCEPTION_EXECUTE_HANDLER)
+    {
+    }
+#elif defined(__MINGW32__)
+   /* No option known to set thread name for MinGW */
+#endif
+#elif defined(__linux__)
+   /* Linux */
+   (void)prctl(PR_SET_NAME,threadName,0,0,0);
+#elif defined(__APPLE__) || defined(__MACH__)
+   /* OS X (TODO: test) */
+   (void)pthread_setname_np(threadName);
+#elif defined(BSD) || defined(__FreeBSD__) || defined(__OpenBSD__)
+   /* BSD (TODO: test) */
+   pthread_set_name_np(pthread_self(), threadName);
+#else
+   /* POSIX */
+   (void)pthread_setname_np(pthread_self(), threadName);
+#endif
+}
+#else /* !defined(NO_THREAD_NAME) */
+void mg_set_thread_name(const char* threadName) {}
+#endif
+
+#if defined(MG_LEGACY_INTERFACE)
 const char **mg_get_valid_option_names(void)
 {
+    static const char * data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0};
+    int i;
+
+    for (i=0; config_options[i].name != NULL; i++) {
+        data[i * 2] = config_options[i].name;
+        data[i * 2 + 1] = config_options[i].default_value;
+    }
+
+    return data;
+}
+#endif
+
+const struct mg_option *mg_get_valid_options(void)
+{
     return config_options;
 }
 
+
 static int is_file_in_memory(struct mg_connection *conn, const char *path,
                              struct file *filep)
 {
     size_t size = 0;
     if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
                          conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
-        // NOTE: override filep->size only on success. Otherwise, it might break
-        // constructs like if (!mg_stat() || !mg_fopen()) ...
+        /* NOTE: override filep->size only on success. Otherwise, it might
+           break constructs like if (!mg_stat() || !mg_fopen()) ... */
         filep->size = size;
     }
     return filep->membuf != NULL;
@@ -611,106 +1019,6 @@ static void mg_fclose(struct file *filep
     }
 }
 
-static int get_option_index(const char *name)
-{
-    int i;
-
-    for (i = 0; config_options[i * 2] != NULL; i++) {
-        if (strcmp(config_options[i * 2], name) == 0) {
-            return i;
-        }
-    }
-    return -1;
-}
-
-const char *mg_get_option(const struct mg_context *ctx, const char *name)
-{
-    int i;
-    if ((i = get_option_index(name)) == -1) {
-        return NULL;
-    } else if (ctx->config[i] == NULL) {
-        return "";
-    } else {
-        return ctx->config[i];
-    }
-}
-
-static void sockaddr_to_string(char *buf, size_t len,
-                               const union usa *usa)
-{
-    buf[0] = '\0';
-#if defined(USE_IPV6)
-    inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
-              (void *) &usa->sin.sin_addr :
-              (void *) &usa->sin6.sin6_addr, buf, len);
-#elif defined(_WIN32)
-    // Only Windoze Vista (and newer) have inet_ntop()
-    strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
-#else
-    inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
-#endif
-}
-
-// Print error message to the opened error log stream.
-void mg_cry(struct mg_connection *conn, const char *fmt, ...)
-{
-    char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
-    va_list ap;
-    FILE *fp;
-    time_t timestamp;
-
-    va_start(ap, fmt);
-    IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap));
-    va_end(ap);
-
-    // Do not lock when getting the callback value, here and below.
-    // I suppose this is fine, since function cannot disappear in the
-    // same way string option can.
-    if (conn->ctx->callbacks.log_message == NULL ||
-        conn->ctx->callbacks.log_message(conn, buf) == 0) {
-        fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
-             fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
-
-        if (fp != NULL) {
-            flockfile(fp);
-            timestamp = time(NULL);
-
-            sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
-            fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
-                    src_addr);
-
-            if (conn->request_info.request_method != NULL) {
-                fprintf(fp, "%s %s: ", conn->request_info.request_method,
-                        conn->request_info.uri);
-            }
-
-            fprintf(fp, "%s", buf);
-            fputc('\n', fp);
-            funlockfile(fp);
-            fclose(fp);
-        }
-    }
-}
-
-// Return fake connection structure. Used for logging, if connection
-// is not applicable at the moment of logging.
-static struct mg_connection *fc(struct mg_context *ctx)
-{
-    static struct mg_connection fake_connection;
-    fake_connection.ctx = ctx;
-    return &fake_connection;
-}
-
-const char *mg_version(void)
-{
-    return CIVETWEB_VERSION;
-}
-
-struct mg_request_info *mg_get_request_info(struct mg_connection *conn)
-{
-    return &conn->request_info;
-}
-
 static void mg_strlcpy(register char *dst, register const char *src, size_t n)
 {
     for (; *src != '\0' && n > 1; n--) {
@@ -751,7 +1059,7 @@ static char * mg_strndup(const char *ptr
 {
     char *p;
 
-    if ((p = (char *) malloc(len + 1)) != NULL) {
+    if ((p = (char *) mg_malloc(len + 1)) != NULL) {
         mg_strlcpy(p, ptr, len + 1);
     }
 
@@ -776,10 +1084,10 @@ static const char *mg_strcasestr(const c
     return NULL;
 }
 
-// Like snprintf(), but never returns negative value, or a value
-// that is larger than a supplied buffer.
-// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
-// in his audit report.
+/* Like snprintf(), but never returns negative value, or a value
+   that is larger than a supplied buffer.
+   Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
+   in his audit report. */
 static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
                         const char *fmt, va_list ap)
 {
@@ -800,30 +1108,165 @@ static int mg_vsnprintf(struct mg_connec
     }
     buf[n] = '\0';
 
-    return n;
+    return n;
+}
+
+static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
+                       PRINTF_FORMAT_STRING(const char *fmt), ...)
+PRINTF_ARGS(4, 5);
+
+static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
+                       const char *fmt, ...)
+{
+    va_list ap;
+    int n;
+
+    va_start(ap, fmt);
+    n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
+    va_end(ap);
+
+    return n;
+}
+
+static int get_option_index(const char *name)
+{
+    int i;
+
+    for (i = 0; config_options[i].name != NULL; i++) {
+        if (strcmp(config_options[i].name, name) == 0) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+const char *mg_get_option(const struct mg_context *ctx, const char *name)
+{
+    int i;
+    if ((i = get_option_index(name)) == -1) {
+        return NULL;
+    } else if (ctx->config[i] == NULL) {
+        return "";
+    } else {
+        return ctx->config[i];
+    }
+}
+
+struct mg_context *mg_get_context(struct mg_connection * conn)
+{
+    return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
+}
+
+void *mg_get_user_data(struct mg_context *ctx)
+{
+    return (ctx == NULL) ? NULL : ctx->user_data;
+}
+
+size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl)
+{
+    size_t i;
+    for (i = 0; i < size && i < (size_t)ctx->num_listening_sockets; i++)
+    {
+        ssl[i] = ctx->listening_sockets[i].is_ssl;
+        ports[i] = ctx->listening_ports[i];
+    }
+    return i;
+}
+
+static void sockaddr_to_string(char *buf, size_t len,
+                               const union usa *usa)
+{
+    buf[0] = '\0';
+#if defined(USE_IPV6)
+    inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
+              (void *) &usa->sin.sin_addr :
+              (void *) &usa->sin6.sin6_addr, buf, len);
+#elif defined(_WIN32)
+    /* Only Windows Vista (and newer) have inet_ntop() */
+    mg_strlcpy(buf, inet_ntoa(usa->sin.sin_addr), len);
+#else
+    inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
+#endif
+}
+
+/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be included in all responses other than 100, 101, 5xx. */
+static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
+{
+    struct tm *tm;
+
+    tm = gmtime(t);
+    if (tm != NULL) {
+        strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
+    } else {
+        mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
+        buf[buf_len - 1] = '\0';
+    }
+}
+
+/* Print error message to the opened error log stream. */
+void mg_cry(struct mg_connection *conn, const char *fmt, ...)
+{
+    char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
+    va_list ap;
+    FILE *fp;
+    time_t timestamp;
+
+    va_start(ap, fmt);
+    IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap));
+    va_end(ap);
+
+    /* Do not lock when getting the callback value, here and below.
+       I suppose this is fine, since function cannot disappear in the
+       same way string option can. */
+    if (conn->ctx->callbacks.log_message == NULL ||
+        conn->ctx->callbacks.log_message(conn, buf) == 0) {
+        fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
+             fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
+
+        if (fp != NULL) {
+            flockfile(fp);
+            timestamp = time(NULL);
+
+            sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+            fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
+                    src_addr);
+
+            if (conn->request_info.request_method != NULL) {
+                fprintf(fp, "%s %s: ", conn->request_info.request_method,
+                        conn->request_info.uri);
+            }
+
+            fprintf(fp, "%s", buf);
+            fputc('\n', fp);
+            funlockfile(fp);
+            fclose(fp);
+        }
+    }
 }
 
-static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
-                       PRINTF_FORMAT_STRING(const char *fmt), ...)
-PRINTF_ARGS(4, 5);
-
-static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
-                       const char *fmt, ...)
+/* Return fake connection structure. Used for logging, if connection
+   is not applicable at the moment of logging. */
+static struct mg_connection *fc(struct mg_context *ctx)
 {
-    va_list ap;
-    int n;
+    static struct mg_connection fake_connection;
+    fake_connection.ctx = ctx;
+    return &fake_connection;
+}
 
-    va_start(ap, fmt);
-    n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
-    va_end(ap);
+const char *mg_version(void)
+{
+    return CIVETWEB_VERSION;
+}
 
-    return n;
+struct mg_request_info *mg_get_request_info(struct mg_connection *conn)
+{
+    return &conn->request_info;
 }
 
-// Skip the characters until one of the delimiters characters found.
-// 0-terminate resulting word. Skip the delimiter and following whitespaces.
-// Advance pointer to buffer to the next word. Return found 0-terminated word.
-// Delimiters can be quoted with quotechar.
+/* Skip the characters until one of the delimiters characters found.
+   0-terminate resulting word. Skip the delimiter and following whitespaces.
+   Advance pointer to buffer to the next word. Return found 0-terminated word.
+   Delimiters can be quoted with quotechar. */
 static char *skip_quoted(char **buf, const char *delimiters,
                          const char *whitespace, char quotechar)
 {
@@ -832,18 +1275,21 @@ static char *skip_quoted(char **buf, con
     begin_word = *buf;
     end_word = begin_word + strcspn(begin_word, delimiters);
 
-    // Check for quotechar
+    /* Check for quotechar */
     if (end_word > begin_word) {
         p = end_word - 1;
         while (*p == quotechar) {
-            // If there is anything beyond end_word, copy it
+            /* TODO (bel): it seems this code is never reached, so quotechar is actually
+               not needed - check if this code may be droped */
+
+            /* If there is anything beyond end_word, copy it */
             if (*end_word == '\0') {
                 *p = '\0';
                 break;
             } else {
                 size_t end_off = strcspn(end_word + 1, delimiters);
                 memmove (p, end_word, end_off + 1);
-                p += end_off; // p must correspond to end_word - 1
+                p += end_off; /* p must correspond to end_word - 1 */
                 end_word += end_off + 1;
             }
         }
@@ -867,15 +1313,15 @@ static char *skip_quoted(char **buf, con
     return begin_word;
 }
 
-// Simplified version of skip_quoted without quote char
-// and whitespace == delimiters
+/* Simplified version of skip_quoted without quote char
+   and whitespace == delimiters */
 static char *skip(char **buf, const char *delimiters)
 {
     return skip_quoted(buf, delimiters, delimiters, 0);
 }
 
 
-// Return HTTP header value, or NULL if not found.
+/* Return HTTP header value, or NULL if not found. */
 static const char *get_header(const struct mg_request_info *ri,
                               const char *name)
 {
@@ -893,37 +1339,37 @@ const char *mg_get_header(const struct m
     return get_header(&conn->request_info, name);
 }
 
-// A helper function for traversing a comma separated list of values.
-// It returns a list pointer shifted to the next value, or NULL if the end
-// of the list found.
-// Value is stored in val vector. If value has form "x=y", then eq_val
-// vector is initialized to point to the "y" part, and val vector length
-// is adjusted to point only to "x".
+/* A helper function for traversing a comma separated list of values.
+   It returns a list pointer shifted to the next value, or NULL if the end
+   of the list found.
+   Value is stored in val vector. If value has form "x=y", then eq_val
+   vector is initialized to point to the "y" part, and val vector length
+   is adjusted to point only to "x". */
 static const char *next_option(const char *list, struct vec *val,
                                struct vec *eq_val)
 {
     if (list == NULL || *list == '\0') {
-        // End of the list
+        /* End of the list */
         list = NULL;
     } else {
         val->ptr = list;
         if ((list = strchr(val->ptr, ',')) != NULL) {
-            // Comma found. Store length and shift the list ptr
+            /* Comma found. Store length and shift the list ptr */
             val->len = list - val->ptr;
             list++;
         } else {
-            // This value is the last one
+            /* This value is the last one */
             list = val->ptr + strlen(val->ptr);
             val->len = list - val->ptr;
         }
 
         if (eq_val != NULL) {
-            // Value has form "x=y", adjust pointers and lengths
-            // so that val points to "x", and eq_val points to "y".
+            /* Value has form "x=y", adjust pointers and lengths
+               so that val points to "x", and eq_val points to "y". */
             eq_val->len = 0;
             eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
             if (eq_val->ptr != NULL) {
-                eq_val->ptr++;  // Skip over '=' character
+                eq_val->ptr++;  /* Skip over '=' character */
                 eq_val->len = val->ptr + val->len - eq_val->ptr;
                 val->len = (eq_val->ptr - val->ptr) - 1;
             }
@@ -933,7 +1379,7 @@ static const char *next_option(const cha
     return list;
 }
 
-// Perform case-insensitive match of string against pattern
+/* Perform case-insensitive match of string against pattern */
 static int match_prefix(const char *pattern, int pattern_len, const char *str)
 {
     const char *or_str;
@@ -946,7 +1392,6 @@ static int match_prefix(const char *patt
     }
 
     i = j = 0;
-    res = -1;
     for (; i < pattern_len; i++, j++) {
         if (pattern[i] == '?' && str[j] != '\0') {
             continue;
@@ -974,9 +1419,9 @@ static int match_prefix(const char *patt
     return j;
 }
 
-// HTTP 1.1 assumes keep alive if "Connection:" header is not set
-// This function must tolerate situations when connection info is not
-// set up, for example if request parsing failed.
+/* HTTP 1.1 assumes keep alive if "Connection:" header is not set
+   This function must tolerate situations when connection info is not
+   set up, for example if request parsing failed. */
 static int should_keep_alive(const struct mg_connection *conn)
 {
     const char *http_version = conn->request_info.http_version;
@@ -985,17 +1430,138 @@ static int should_keep_alive(const struc
         conn->status_code == 401 ||
         mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
         (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
-        (header == NULL && http_version && strcmp(http_version, "1.1"))) {
+        (header == NULL && http_version && 0!=strcmp(http_version, "1.1"))) {
         return 0;
     }
     return 1;
 }
 
+static int should_decode_url(const struct mg_connection *conn)
+{
+    return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0);
+}
+
 static const char *suggest_connection_header(const struct mg_connection *conn)
 {
     return should_keep_alive(conn) ? "keep-alive" : "close";
 }
 
+static void handle_file_based_request(struct mg_connection *conn, const char *path, struct file *filep);
+static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep);
+
+static const char *mg_get_response_code_text(int response_code, struct mg_connection *conn)
+{
+    switch (response_code)
+    {
+    /* RFC2616 Section 10.1 - Informational 1xx */
+    case 100: return "Continue"; /* RFC2616 Section 10.1.1 */
+    case 101: return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
+    case 102: return "Processing"; /* RFC2518 Section 10.1 */
+
+    /* RFC2616 Section 10.2 - Successful 2xx */
+    case 200: return "OK"; /* RFC2616 Section 10.2.1 */
+    case 201: return "Created"; /* RFC2616 Section 10.2.2 */
+    case 202: return "Accepted"; /* RFC2616 Section 10.2.3 */
+    case 203: return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
+    case 204: return "No Content"; /* RFC2616 Section 10.2.5 */
+    case 205: return "Reset Content"; /* RFC2616 Section 10.2.6 */
+    case 206: return "Partial Content"; /* RFC2616 Section 10.2.7 */
+    case 207: return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */
+
+    /* RFC2616 Section 10.3 - Redirection 3xx */
+    case 300: return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
+    case 301: return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
+    case 302: return "Found"; /* RFC2616 Section 10.3.3 */
+    case 303: return "See Other"; /* RFC2616 Section 10.3.4 */
+    case 304: return "Not Modified"; /* RFC2616 Section 10.3.5 */
+    case 305: return "Use Proxy"; /* RFC2616 Section 10.3.6 */
+    case 307: return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
+
+    /* RFC2616 Section 10.4 - Client Error 4xx */
+    case 400: return "Bad Request"; /* RFC2616 Section 10.4.1 */
+    case 401: return "Unauthorized"; /* RFC2616 Section 10.4.2 */
+    case 402: return "Payment Required"; /* RFC2616 Section 10.4.3 */
+    case 403: return "Forbidden"; /* RFC2616 Section 10.4.4 */
+    case 404: return "Not Found"; /* RFC2616 Section 10.4.5 */
+    case 405: return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
+    case 406: return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
+    case 407: return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
+    case 408: return "Request Time-out"; /* RFC2616 Section 10.4.9 */
+    case 409: return "Conflict"; /* RFC2616 Section 10.4.10 */
+    case 410: return "Gone"; /* RFC2616 Section 10.4.11 */
+    case 411: return "Length Required"; /* RFC2616 Section 10.4.12 */
+    case 412: return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
+    case 413: return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
+    case 414: return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
+    case 415: return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
+    case 416: return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */
+    case 417: return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
+    case 422: return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918 Section 11.2 */
+    case 423: return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
+    case 424: return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918 Section 11.4 */
+    case 428: return "Precondition Required"; /* RFC 6585, Section 3 */
+    case 429: return "Too Many Requests"; /* RFC 6585, Section 4 */
+    case 431: return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
+
+    /* RFC2616 Section 10.5 - Server Error 5xx */
+    case 500: return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
+    case 501: return "Not Implemented"; /* RFC2616 Section 10.5.2 */
+    case 502: return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
+    case 503: return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
+    case 504: return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
+    case 505: return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
+    case 507: return "Insufficient Storage"; /* RFC2518 Section 10.6, , RFC4918 Section 11.5 */
+    case 511: return "Network Authentication Required"; /* RFC 6585, Section 6 */
+
+    /* Other RFCs */
+    case 426: return "Upgrade Required"; /* RFC 2817 */
+
+    /* Return codes from non normative RFCs: */
+    /* Informative and experimental RFCs, "de facto" standards due to common use, ... */
+    case 208: return "Already Reported"; /* RFC5842 Section 7.1 */
+    case 226: return "IM used"; /* RFC3229 Section 10.4.1 */
+    case 308: return "Permanent Redirect"; /* RFC7238 Section 3 */
+    case 418: return "I am a teapot"; /* RFC2324 Section 2.3.2 */
+    case 419: return "Authentication Timeout"; /* common use */
+    case 451: return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05, Section 3 */
+    case 506: return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
+    case 508: return "Loop Detected"; /* RFC5842 Section 7.1 */
+    case 510: return "Not Extended"; /* RFC 2774, Section 7 */
+
+    default:
+        /* This error code is unknown. This should not happen. */
+        if (conn) {
+            mg_cry(conn, "Unknown HTTP response code: %u", response_code);
+        }
+
+        /* Return at least a category according to RFC 2616 Section 10. */
+        if (response_code>=100 && response_code<200) {
+            /* Unknown informational status code */
+            return "Information";
+        }
+        if (response_code>=200 && response_code<300) {
+            /* Unknown success code */
+            return "Success";
+        }
+        if (response_code>=300 && response_code<400) {
+            /* Unknown redirection code */
+            return "Redirection";
+        }
+        if (response_code>=400 && response_code<500) {
+            /* Unknown request error code */
+            return "Client Error";
+        }
+        if (response_code>=500 && response_code<600) {
+            /* Unknown server error code */
+            return "Server Error";
+        }
+
+        /* Response code not even within reasonable range */
+        return "";
+    }
+}
+
+
 static void send_http_error(struct mg_connection *, int, const char *,
                             PRINTF_FORMAT_STRING(const char *fmt), ...)
 PRINTF_ARGS(4, 5);
@@ -1006,28 +1572,83 @@ static void send_http_error(struct mg_co
 {
     char buf[MG_BUF_LEN];
     va_list ap;
-    int len = 0;
+    int len = 0, i, page_handler_found, scope;
+    char date[64];
+    time_t curtime = time(NULL);
+    const char *error_handler = NULL;
+    struct file error_page_file = STRUCT_FILE_INITIALIZER;
+    const char *error_page_file_ext, *tstr;
+
+    if (!reason) {
+        reason = mg_get_response_code_text(status, conn);
+    }
 
     conn->status_code = status;
-    if (conn->ctx->callbacks.http_error == NULL ||
+    if (conn->in_error_handler ||
+        conn->ctx->callbacks.http_error == NULL ||
         conn->ctx->callbacks.http_error(conn, status)) {
+
+        if (!conn->in_error_handler) {
+            /* Send user defined error pages, if defined */
+            error_handler = conn->ctx->config[ERROR_PAGES];
+            error_page_file_ext = conn->ctx->config[INDEX_FILES];
+            page_handler_found = 0;
+            if (error_handler != NULL) {
+                for (scope=1; (scope<=3) && !page_handler_found; scope++) {
+                    switch (scope) {
+                    case 1:
+                        len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror%03u.", error_handler, status);
+                        break;
+                    case 2:
+                        len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror%01uxx.", error_handler, status/100);
+                        break;
+                    default:
+                        len = mg_snprintf(conn, buf, sizeof(buf)-32, "%serror.", error_handler);
+                        break;
+                    }
+                    tstr = strchr(error_page_file_ext, '.');
+                    while (tstr) {
+                        for (i=1; i<32 && tstr[i]!=0 && tstr[i]!=','; i++) buf[len+i-1]=tstr[i];
+                        buf[len+i-1]=0;
+                        if (mg_stat(conn, buf, &error_page_file)) {
+                            page_handler_found = 1;
+                            break;
+                        }
+                        tstr = strchr(tstr+i, '.');
+                    }
+                }
+            }
+
+            if (page_handler_found) {
+                conn->in_error_handler = 1;
+                handle_file_based_request(conn, buf, &error_page_file);
+                conn->in_error_handler = 0;
+                return;
+            }
+        }
+
         buf[0] = '\0';
+        gmt_time_string(date, sizeof(date), &curtime);
 
-        // Errors 1xx, 204 and 304 MUST NOT send a body
+        /* Errors 1xx, 204 and 304 MUST NOT send a body */
         if (status > 199 && status != 204 && status != 304) {
-            len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
-            buf[len++] = '\n';
+            len = mg_snprintf(conn, buf, sizeof(buf)-1, "Error %d: %s", status, reason);
+            buf[len] = '\n';
+            len++;
+            buf[len] = 0;
 
             va_start(ap, fmt);
             len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
             va_end(ap);
         }
-        DEBUG_TRACE(("[%s]", buf));
+        DEBUG_TRACE("[%s]", buf);
 
         mg_printf(conn, "HTTP/1.1 %d %s\r\n"
-                  "Content-Length: %d\r\n"
-                  "Connection: %s\r\n\r\n", status, reason, len,
-                  suggest_connection_header(conn));
+                        "Content-Length: %d\r\n"
+                        "Date: %s\r\n"
+                        "Connection: %s\r\n\r\n",
+                        status, reason, len, date,
+                        suggest_connection_header(conn));
         conn->num_bytes_sent += mg_printf(conn, "%s", buf);
     }
 }
@@ -1047,7 +1668,18 @@ static int pthread_mutex_destroy(pthread
 
 static int pthread_mutex_lock(pthread_mutex_t *mutex)
 {
-    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
+    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
+}
+
+static int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+    switch (WaitForSingleObject(*mutex, 0)) {
+        case WAIT_OBJECT_0:
+            return 0;
+        case WAIT_TIMEOUT:
+            return -2; /* EBUSY */
+    }
+    return -1;
 }
 
 static int pthread_mutex_unlock(pthread_mutex_t *mutex)
@@ -1055,40 +1687,137 @@ static int pthread_mutex_unlock(pthread_
     return ReleaseMutex(*mutex) == 0 ? -1 : 0;
 }
 
+#ifndef WIN_PTHREADS_TIME_H
+static int clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+    FILETIME ft;
+    ULARGE_INTEGER li;
+    BOOL ok = FALSE;
+    double d;
+    static double perfcnt_per_sec = 0.0;
+
+    if (tp) {
+        if (clk_id == CLOCK_REALTIME) {
+            GetSystemTimeAsFileTime(&ft);
+            li.LowPart = ft.dwLowDateTime;
+            li.HighPart = ft.dwHighDateTime;
+            li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
+            tp->tv_sec = (time_t)(li.QuadPart / 10000000);
+            tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
+            ok = TRUE;
+        } else if (clk_id == CLOCK_MONOTONIC) {
+            if (perfcnt_per_sec == 0.0) {
+                QueryPerformanceFrequency((LARGE_INTEGER *) &li);
+                perfcnt_per_sec = 1.0 / li.QuadPart;
+            }
+            if (perfcnt_per_sec != 0.0) {
+                QueryPerformanceCounter((LARGE_INTEGER *) &li);
+                d = li.QuadPart * perfcnt_per_sec;
+                tp->tv_sec = (time_t)d;
+                d -= tp->tv_sec;
+                tp->tv_nsec = (long)(d*1.0E9);
+                ok = TRUE;
+            }
+        }
+    }
+
+    return ok ? 0 : -1;
+}
+#endif
+
 static int pthread_cond_init(pthread_cond_t *cv, const void *unused)
 {
     (void) unused;
-    cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
-    cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
-    return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
+    InitializeCriticalSection(&cv->threadIdSec);
+    cv->waitingthreadcount = 0;
+    cv->waitingthreadhdls = (pthread_t *) mg_calloc(MAX_WORKER_THREADS, sizeof(pthread_t));
+    return (cv->waitingthreadhdls!=NULL) ? 0 : -1;
+}
+
+static int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec * abstime)
+{
+    struct mg_workerTLS * tls = (struct mg_workerTLS *)TlsGetValue(sTlsKey);
+    int ok;
+    struct timespec tsnow;
+    int64_t nsnow, nswaitabs, nswaitrel;
+    DWORD mswaitrel;
+
+    EnterCriticalSection(&cv->threadIdSec);
+    assert(cv->waitingthreadcount < MAX_WORKER_THREADS);
+    cv->waitingthreadhdls[cv->waitingthreadcount] = tls->pthread_cond_helper_mutex;
+    cv->waitingthreadcount++;
+    LeaveCriticalSection(&cv->threadIdSec);
+
+    if (abstime) {
+        clock_gettime(CLOCK_REALTIME, &tsnow);
+        nsnow = (((uint64_t)tsnow.tv_sec)*1000000000) + tsnow.tv_nsec;
+        nswaitabs = (((uint64_t)abstime->tv_sec)*1000000000) + abstime->tv_nsec;
+        nswaitrel = nswaitabs - nsnow;
+        if (nswaitrel<0) nswaitrel=0;
+        mswaitrel = (DWORD)(nswaitrel / 1000000);
+    } else {
+        mswaitrel = INFINITE;
+    }
+
+    pthread_mutex_unlock(mutex);
+    ok = (WAIT_OBJECT_0 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
+    pthread_mutex_lock(mutex);
+
+    return ok ? 0 : -1;
 }
 
 static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
 {
-    HANDLE handles[] = {cv->signal, cv->broadcast};
-    ReleaseMutex(*mutex);
-    WaitForMultipleObjects(2, handles, FALSE, INFINITE);
-    return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
+    return pthread_cond_timedwait(cv, mutex, NULL);
 }
 
 static int pthread_cond_signal(pthread_cond_t *cv)
 {
-    return SetEvent(cv->signal) == 0 ? -1 : 0;
+    int i;
+    HANDLE wkup = NULL;
+    BOOL ok = FALSE;
+
+    EnterCriticalSection(&cv->threadIdSec);
+    if (cv->waitingthreadcount) {
+        wkup = cv->waitingthreadhdls[0];
+        ok = SetEvent(wkup);
+
+        for (i=1; i<cv->waitingthreadcount; i++) {
+            cv->waitingthreadhdls[i-1] = cv->waitingthreadhdls[i];
+        }
+        cv->waitingthreadcount--;
+
+        assert(ok);
+    }
+    LeaveCriticalSection(&cv->threadIdSec);
+
+    return ok ? 0 : 1;
 }
 
 static int pthread_cond_broadcast(pthread_cond_t *cv)
 {
-    // Implementation with PulseEvent() has race condition, see
-    // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
-    return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
+    EnterCriticalSection(&cv->threadIdSec);
+    while (cv->waitingthreadcount) {
+        pthread_cond_signal(cv);
+    }
+    LeaveCriticalSection(&cv->threadIdSec);
+
+    return 0;
 }
 
 static int pthread_cond_destroy(pthread_cond_t *cv)
 {
-    return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
+    EnterCriticalSection(&cv->threadIdSec);
+    assert(cv->waitingthreadcount==0);
+    mg_free(cv->waitingthreadhdls);
+    cv->waitingthreadhdls = 0;
+    LeaveCriticalSection(&cv->threadIdSec);
+    DeleteCriticalSection(&cv->threadIdSec);
+
+    return 0;
 }
 
-// For Windows, change all slashes to backslashes in path names.
+/* For Windows, change all slashes to backslashes in path names. */
 static void change_slashes_to_backslashes(char *path)
 {
     int i;
@@ -1096,7 +1825,7 @@ static void change_slashes_to_backslashe
     for (i = 0; path[i] != '\0'; i++) {
         if (path[i] == '/')
             path[i] = '\\';
-        // i > 0 check is to preserve UNC paths, like \\server\file.txt
+        /* i > 0 check is to preserve UNC paths, like \\server\file.txt */
         if (path[i] == '\\' && i > 0)
             while (path[i + 1] == '\\' || path[i + 1] == '/')
                 (void) memmove(path + i + 1,
@@ -1104,8 +1833,8 @@ static void change_slashes_to_backslashe
     }
 }
 
-// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
-// wbuf and wbuf_len is a target buffer and its length.
+/* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
+   wbuf and wbuf_len is a target buffer and its length. */
 static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len)
 {
     char buf[PATH_MAX], buf2[PATH_MAX];
@@ -1113,8 +1842,8 @@ static void to_unicode(const char *path,
     mg_strlcpy(buf, path, sizeof(buf));
     change_slashes_to_backslashes(buf);
 
-    // Convert to Unicode and back. If doubly-converted string does not
-    // match the original, something is fishy, reject.
+    /* Convert to Unicode and back. If doubly-converted string does not
+       match the original, something is fishy, reject. */
     memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
     MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
     WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
@@ -1163,7 +1892,7 @@ static struct tm *localtime(const time_t
     ptm->tm_hour = st.wHour;
     ptm->tm_min = st.wMinute;
     ptm->tm_sec = st.wSecond;
-    ptm->tm_yday = 0; // hope nobody uses this
+    ptm->tm_yday = 0; /* hope nobody uses this */
     ptm->tm_isdst =
         GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
 
@@ -1172,7 +1901,7 @@ static struct tm *localtime(const time_t
 
 static struct tm *gmtime(const time_t *ptime, struct tm *ptm)
 {
-    // FIXME(lsm): fix this.
+    /* FIXME(lsm): fix this. */
     return localtime(ptime, ptm);
 }
 
@@ -1184,10 +1913,10 @@ static size_t strftime(char *dst, size_t
 }
 #endif
 
-// Windows happily opens files with some garbage at the end of file name.
-// For example, fopen("a.cgi    ", "r") on Windows successfully opens
-// "a.cgi", despite one would expect an error back.
-// This function returns non-0 if path ends with some garbage.
+/* Windows happily opens files with some garbage at the end of file name.
+   For example, fopen("a.cgi    ", "r") on Windows successfully opens
+   "a.cgi", despite one would expect an error back.
+   This function returns non-0 if path ends with some garbage. */
 static int path_cannot_disclose_cgi(const char *path)
 {
     static const char *allowed_last_characters = "_-";
@@ -1195,8 +1924,7 @@ static int path_cannot_disclose_cgi(cons
     return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
 }
 
-static int mg_stat(struct mg_connection *conn, const char *path,
-                   struct file *filep)
+static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
 {
     wchar_t wbuf[PATH_MAX];
     WIN32_FILE_ATTRIBUTE_DATA info;
@@ -1209,9 +1937,10 @@ static int mg_stat(struct mg_connection
                                            info.ftLastWriteTime.dwLowDateTime,
                                            info.ftLastWriteTime.dwHighDateTime);
             filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
-            // If file name is fishy, reset the file structure and return error.
-            // Note it is important to reset, not just return the error, cause
-            // functions like is_file_opened() check the struct.
+            /* If file name is fishy, reset the file structure and return
+               error.
+               Note it is important to reset, not just return the error, cause
+               functions like is_file_opened() check the struct. */
             if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
                 memset(filep, 0, sizeof(*filep));
             }
@@ -1242,7 +1971,7 @@ static int mg_mkdir(const char *path, in
     return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
 }
 
-// Implementation of POSIX opendir/closedir/readdir for Windows.
+/* Implementation of POSIX opendir/closedir/readdir for Windows. */
 static DIR * opendir(const char *name)
 {
     DIR *dir = NULL;
@@ -1251,7 +1980,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 *) mg_malloc(sizeof(*dir))) == NULL) {
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
     } else {
         to_unicode(name, wpath, ARRAY_SIZE(wpath));
@@ -1262,7 +1991,7 @@ static DIR * opendir(const char *name)
             dir->handle = FindFirstFileW(wpath, &dir->info);
             dir->result.d_name[0] = '\0';
         } else {
-            free(dir);
+            mg_free(dir);
             dir = NULL;
         }
     }
@@ -1278,7 +2007,7 @@ static int closedir(DIR *dir)
         if (dir->handle != INVALID_HANDLE_VALUE)
             result = FindClose(dir->handle) ? 0 : -1;
 
-        free(dir);
+        mg_free(dir);
     } else {
         result = -1;
         SetLastError(ERROR_BAD_ARGUMENTS);
@@ -1344,7 +2073,7 @@ static int poll(struct pollfd *pfd, int
 
     return result;
 }
-#endif // HAVE_POLL
+#endif /* HAVE_POLL */
 
 static void set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
 {
@@ -1354,7 +2083,12 @@ static void set_close_on_exec(SOCKET soc
 
 int mg_start_thread(mg_thread_func_t f, void *p)
 {
-    return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
+#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
+    /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 */
+    return ((_beginthread((void (__cdecl *)(void *)) f, USE_STACK_SIZE, p) == ((uintptr_t)(-1L))) ? -1 : 0);
+#else
+    return ((_beginthread((void (__cdecl *)(void *)) f, 0, p) == ((uintptr_t)(-1L))) ? -1 : 0);
+#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
 }
 
 /* Start a thread storing the thread context. */
@@ -1364,15 +2098,15 @@ static int mg_start_thread_with_id(unsig
 {
     uintptr_t uip;
     HANDLE threadhandle;
-    int result;
+    int result = -1;
 
     uip = _beginthreadex(NULL, 0, (unsigned (__stdcall *)(void *)) f, p, 0,
                          NULL);
     threadhandle = (HANDLE) uip;
-    if (threadidptr != NULL) {
+    if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
         *threadidptr = threadhandle;
+        result = 0;
     }
-    result = (threadhandle == NULL) ? -1 : 0;
 
     return result;
 }
@@ -1390,7 +2124,7 @@ static int mg_join_thread(pthread_t thre
         int err;
 
         err = GetLastError();
-        DEBUG_TRACE(("WaitForSingleObject() failed, error %d", err));
+        DEBUG_TRACE("WaitForSingleObject() failed, error %d", err);
     } else {
         if (dwevent == WAIT_OBJECT_0) {
             CloseHandle(threadid);
@@ -1413,7 +2147,7 @@ static int dlclose(void *handle)
 {
     int result;
 
-    if (FreeLibrary(handle) != 0) {
+    if (FreeLibrary((HMODULE) handle) != 0) {
         result = 0;
     } else {
         result = -1;
@@ -1455,7 +2189,7 @@ static pid_t spawn_process(struct mg_con
     memset(&si, 0, sizeof(si));
     si.cb = sizeof(si);
 
-    // TODO(lsm): redirect CGI errors to the error log file
+    /* TODO(lsm): redirect CGI errors to the error log file */
     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
     si.wShowWindow = SW_HIDE;
 
@@ -1465,12 +2199,12 @@ static pid_t spawn_process(struct mg_con
     DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
                     &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
 
-    // If CGI file is a script, try to read the interpreter line
+    /* If CGI file is a script, try to read the interpreter line */
     interp = conn->ctx->config[CGI_INTERPRETER];
     if (interp == NULL) {
         buf[0] = buf[1] = '\0';
 
-        // Read the first line of the script into the buffer
+        /* Read the first line of the script into the buffer */
         snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
         if (mg_fopen(conn, cmdline, "r", &file)) {
             p = (char *) file.membuf;
@@ -1496,7 +2230,7 @@ static pid_t spawn_process(struct mg_con
     mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"",
                 interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
 
-    DEBUG_TRACE(("Running [%s]", cmdline));
+    DEBUG_TRACE("Running [%s]", cmdline);
     if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
                        CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
         mg_cry(conn, "%s: CreateProcess(%s): %ld",
@@ -1511,7 +2245,7 @@ static pid_t spawn_process(struct mg_con
 
     return (pid_t) pi.hProcess;
 }
-#endif // !NO_CGI
+#endif /* !NO_CGI */
 
 static int set_non_blocking_mode(SOCKET sock)
 {
@@ -1539,9 +2273,9 @@ static int mg_stat(struct mg_connection
 static void set_close_on_exec(int fd, struct mg_connection *conn /* may be null */)
 {
     if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
-        if (conn)
-            mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
-                   __func__, strerror(ERRNO));
+        if (conn) {
+            mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s", __func__, strerror(ERRNO));
+        }
     }
 }
 
@@ -1554,10 +2288,11 @@ int mg_start_thread(mg_thread_func_t fun
     (void) pthread_attr_init(&attr);
     (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
-#if defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1
-    // Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
+#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
+    /* Compile-time option to control stack size,
+       e.g. -DUSE_STACK_SIZE=16384 */
     (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
-#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
+#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
 
     result = pthread_create(&thread_id, &attr, func, param);
     pthread_attr_destroy(&attr);
@@ -1567,8 +2302,7 @@ int mg_start_thread(mg_thread_func_t fun
 
 /* Start a thread storing the thread context. */
 
-static int mg_start_thread_with_id(mg_thread_func_t func, void *param,
-                                   pthread_t *threadidptr)
+static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
 {
     pthread_t thread_id;
     pthread_attr_t attr;
@@ -1576,14 +2310,15 @@ static int mg_start_thread_with_id(mg_th
 
     (void) pthread_attr_init(&attr);
 
-#if defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1
-    // Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
+#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
+    /* Compile-time option to control stack size,
+       e.g. -DUSE_STACK_SIZE=16384 */
     (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
 
     result = pthread_create(&thread_id, &attr, func, param);
     pthread_attr_destroy(&attr);
-    if (threadidptr != NULL) {
+    if ((result == 0) && (threadidptr != NULL)) {
         *threadidptr = thread_id;
     }
     return result;
@@ -1610,10 +2345,11 @@ static pid_t spawn_process(struct mg_con
     (void) envblk;
 
     if ((pid = fork()) == -1) {
-        // Parent
-        send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
+        /* Parent */
+        send_http_error(conn, 500, NULL,
+            "Error: Creating CGI process\nfork(): %s", strerror(ERRNO));
     } else if (pid == 0) {
-        // Child
+        /* Child */
         if (chdir(dir) != 0) {
             mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
         } else if (dup2(fdin, 0) == -1) {
@@ -1621,15 +2357,16 @@ static pid_t spawn_process(struct mg_con
         } else if (dup2(fdout, 1) == -1) {
             mg_cry(conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO));
         } else {
-            // Not redirecting stderr to stdout, to avoid output being littered
-            // with the error messages.
+            /* Not redirecting stderr to stdout, to avoid output being littered
+               with the error messages. */
             (void) close(fdin);
             (void) close(fdout);
 
-            // After exec, all signal handlers are restored to their default values,
-            // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
-            // implementation, SIGCHLD's handler will leave unchanged after exec
-            // if it was set to be ignored. Restore it to default action.
+            /* After exec, all signal handlers are restored to their default
+               values, with one exception of SIGCHLD. According to
+               POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
+               leave unchanged after exec if it was set to be ignored. Restore
+               it to default action. */
             signal(SIGCHLD, SIG_DFL);
 
             interp = conn->ctx->config[CGI_INTERPRETER];
@@ -1647,7 +2384,7 @@ static pid_t spawn_process(struct mg_con
 
     return pid;
 }
-#endif // !NO_CGI
+#endif /* !NO_CGI */
 
 static int set_non_blocking_mode(SOCKET sock)
 {
@@ -1658,21 +2395,20 @@ static int set_non_blocking_mode(SOCKET
 
     return 0;
 }
-#endif // _WIN32
+#endif /* _WIN32 */
 
-// Write data to the IO channel - opened file descriptor, socket or SSL
-// descriptor. Return number of bytes written.
-static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
-                    int64_t len)
+/* Write data to the IO channel - opened file descriptor, socket or SSL
+   descriptor. Return number of bytes written. */
+static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
 {
     int64_t sent;
     int n, k;
 
-    (void) ssl;  // Get rid of warning
+    (void) ssl;  /* Get rid of warning */
     sent = 0;
     while (sent < len) {
 
-        // How many bytes we send in this iteration
+        /* How many bytes we send in this iteration */
         k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
 
 #ifndef NO_SSL
@@ -1697,16 +2433,17 @@ static int64_t push(FILE *fp, SOCKET soc
     return sent;
 }
 
-// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
-// Return negative value on error, or number of bytes read on success.
+/* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
+   Return negative value on error, or number of bytes read on success. */
 static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
 {
     int nread;
 
     if (fp != NULL) {
-        // Use read() instead of fread(), because if we're reading from the CGI
-        // pipe, fread() may block until IO buffer is filled up. We cannot afford
-        // to block and must pass all read bytes immediately to the client.
+        /* Use read() instead of fread(), because if we're reading from the
+           CGI pipe, fread() may block until IO buffer is filled up. We cannot
+           afford to block and must pass all read bytes immediately to the
+           client. */
         nread = read(fileno(fp), buf, (size_t) len);
 #ifndef NO_SSL
     } else if (conn->ssl != NULL) {
@@ -1726,10 +2463,10 @@ static int pull_all(FILE *fp, struct mg_
     while (len > 0 && conn->ctx->stop_flag == 0) {
         n = pull(fp, conn, buf + nread, len);
         if (n < 0) {
-            nread = n;  // Propagate the error
+            nread = n;  /* Propagate the error */
             break;
         } else if (n == 0) {
-            break;  // No more data to read
+            break;  /* No more data to read */
         } else {
             conn->consumed_content += n;
             nread += n;
@@ -1742,42 +2479,48 @@ static int pull_all(FILE *fp, struct mg_
 
 int mg_read(struct mg_connection *conn, void *buf, size_t len)
 {
-    int n, buffered_len, nread;
+    int64_t n, buffered_len, nread;
+    int64_t len64 = (int64_t)(len > INT_MAX ? INT_MAX : len); /* since the return value is int, we may not read more bytes */
     const char *body;
 
-    // If Content-Length is not set, read until socket is closed
-    if (conn->consumed_content == 0 && conn->content_len == 0) {
+    /* If Content-Length is not set for a PUT or POST request, read until socket is closed */
+    if (conn->consumed_content == 0 && conn->content_len == -1) {
         conn->content_len = INT64_MAX;
         conn->must_close = 1;
     }
 
     nread = 0;
     if (conn->consumed_content < conn->content_len) {
-        // Adjust number of bytes to read.
-        int64_t to_read = conn->content_len - conn->consumed_content;
-        if (to_read < (int64_t) len) {
-            len = (size_t) to_read;
+        /* Adjust number of bytes to read. */
+        int64_t left_to_read = conn->content_len - conn->consumed_content;
+        if (left_to_read < len64) {
+            /* Do not reade more than the total content length of the request. */
+            len64 = left_to_read;
         }
 
-        // Return buffered data
-        body = conn->buf + conn->request_len + conn->consumed_content;
-        buffered_len = (int)(&conn->buf[conn->data_len] - body);
+        /* Return buffered data */
+        buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len - conn->consumed_content;
         if (buffered_len > 0) {
-            if (len < (size_t) buffered_len) {
-                buffered_len = (int) len;
+            if (len64 < buffered_len) {
+                buffered_len = len64;
             }
+            body = conn->buf + conn->request_len + conn->consumed_content;
             memcpy(buf, body, (size_t) buffered_len);
-            len -= buffered_len;
+            len64 -= buffered_len;
             conn->consumed_content += buffered_len;
             nread += buffered_len;
             buf = (char *) buf + buffered_len;
         }
 
-        // We have returned all buffered data. Read new data from the remote socket.
-        n = pull_all(NULL, conn, (char *) buf, (int) len);
-        nread = n >= 0 ? nread + n : n;
+        /* We have returned all buffered data. Read new data from the remote
+           socket. */
+        if ((n = pull_all(NULL, conn, (char *) buf, (int)len64)) >= 0) {
+            nread += n;
+        } else {
+            nread = (nread > 0 ? nread : n);
+        }
     }
-    return nread;
+    return (int)nread;
 }
 
 int mg_write(struct mg_connection *conn, const void *buf, size_t len)
@@ -1819,7 +2562,7 @@ int mg_write(struct mg_connection *conn,
     return (int) total;
 }
 
-// Alternative alloc_vprintf() for non-compliant C runtimes
+/* Alternative alloc_vprintf() for non-compliant C runtimes */
 static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
 {
     va_list ap_copy;
@@ -1828,8 +2571,8 @@ static int alloc_vprintf2(char **buf, co
 
     *buf = NULL;
     while (len == -1) {
-        if (*buf) free(*buf);
-        *buf = (char *)malloc(size *= 4);
+        if (*buf) mg_free(*buf);
+        *buf = (char *)mg_malloc(size *= 4);
         if (!*buf) break;
         va_copy(ap_copy, ap);
         len = vsnprintf(*buf, size, fmt, ap_copy);
@@ -1839,33 +2582,35 @@ static int alloc_vprintf2(char **buf, co
     return len;
 }
 
-// Print message to buffer. If buffer is large enough to hold the message,
-// return buffer. If buffer is to small, allocate large enough buffer on heap,
-// and return allocated buffer.
+/* Print message to buffer. If buffer is large enough to hold the message,
+   return buffer. If buffer is to small, allocate large enough buffer on heap,
+   and return allocated buffer. */
 static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
 {
     va_list ap_copy;
     int len;
 
-    // Windows is not standard-compliant, and vsnprintf() returns -1 if
-    // buffer is too small. Also, older versions of msvcrt.dll do not have
-    // _vscprintf().  However, if size is 0, vsnprintf() behaves correctly.
-    // Therefore, we make two passes: on first pass, get required message length.
-    // On second pass, actually print the message.
+    /* Windows is not standard-compliant, and vsnprintf() returns -1 if
+       buffer is too small. Also, older versions of msvcrt.dll do not have
+       _vscprintf().  However, if size is 0, vsnprintf() behaves correctly.
+       Therefore, we make two passes: on first pass, get required message
+       length.
+       On second pass, actually print the message. */
     va_copy(ap_copy, ap);
     len = vsnprintf(NULL, 0, fmt, ap_copy);
     va_end(ap_copy);
 
     if (len < 0) {
-        // C runtime is not standard compliant, vsnprintf() returned -1.
-        // Switch to alternative code path that uses incremental allocations.
+        /* C runtime is not standard compliant, vsnprintf() returned -1.
+           Switch to alternative code path that uses incremental allocations.
+        */
         va_copy(ap_copy, ap);

[... 5065 lines stripped ...]


Mime
View raw message