celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pnol...@apache.org
Subject [4/8] celix git commit: CELIX-417: Refactors CMake usage for the RSA bundles
Date Fri, 24 Nov 2017 10:59:12 GMT
http://git-wip-us.apache.org/repos/asf/celix/blob/27a2aa75/remote_services/discovery_common/src/civetweb.c
----------------------------------------------------------------------
diff --git a/remote_services/discovery_common/src/civetweb.c b/remote_services/discovery_common/src/civetweb.c
deleted file mode 100644
index a6093b7..0000000
--- a/remote_services/discovery_common/src/civetweb.c
+++ /dev/null
@@ -1,7907 +0,0 @@
-	/* 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 */
-#endif
-#else
-#ifdef __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
-#endif
-
-#if defined (_MSC_VER)
-/* '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 */
-#pragma warning (disable : 4204)
-#endif
-
-/* 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 PATH_MAX FILENAME_MAX
-#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 */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#endif /* !_WIN32_WCE */
-
-#include <time.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdio.h>
-
-#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 */
-#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 */
-
-typedef long off_t;
-
-#define errno   GetLastError()
-#define strerror(x)  _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
-#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 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 */
-#if defined(_MSC_VER) && _MSC_VER < 1300
-#define STRX(x) #x
-#define STR(x) STRX(x)
-#define __func__ __FILE__ ":" STR(__LINE__)
-#define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
-#define strtoll(x, y, z) _atoi64(x)
-#else
-#define __func__  __FUNCTION__
-#define strtoull(x, y, z) _strtoui64(x, y, z)
-#define strtoll(x, y, z) _strtoi64(x, y, z)
-#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 */
-#define _POSIX_
-#define INT64_FMT  "I64d"
-
-#define WINCDECL __cdecl
-#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)
-#ifndef popen
-#define popen(x, y) _popen(x, y)
-#endif
-#ifndef pclose
-#define pclose(x) _pclose(x)
-#endif
-#define close(x) _close(x)
-#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
-#define RTLD_LAZY  0
-#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
-#define fdopen(x, y) _fdopen((x), (y))
-#define write(x, y, z) _write((x), (y), (unsigned) z)
-#define read(x, y, z) _read((x), (y), (unsigned) z)
-#define flockfile(x) EnterCriticalSection(&global_log_file_lock)
-#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
-#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 */
-
-#if !defined(fileno)
-#define fileno(x) _fileno(x)
-#endif /* !fileno MINGW #defines fileno */
-
-typedef HANDLE pthread_mutex_t;
-typedef DWORD pthread_key_t;
-typedef HANDLE pthread_t;
-typedef struct {
-    CRITICAL_SECTION threadIdSec;
-    int waitingthreadcount;        /* The number of threads queued. */
-    pthread_t *waitingthreadhdls;  /* The thread handles. */
-} pthread_cond_t;
-
-#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 *);
-static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
-struct file;
-static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
-
-#if defined(HAVE_STDINT)
-#include <stdint.h>
-#else
-typedef unsigned int  uint32_t;
-typedef unsigned short  uint16_t;
-typedef unsigned __int64 uint64_t;
-typedef __int64   int64_t;
-#define INT64_MAX  9223372036854775807
-#endif /* HAVE_STDINT */
-
-/* POSIX dirent interface */
-struct dirent {
-    char d_name[PATH_MAX];
-};
-
-typedef struct DIR {
-    HANDLE   handle;
-    WIN32_FIND_DATAW info;
-    struct dirent  result;
-} DIR;
-
-#if !defined(USE_IPV6) && defined(_WIN32)
-#ifndef HAVE_POLL
-struct pollfd {
-    SOCKET fd;
-    short events;
-    short revents;
-};
-#define POLLIN 1
-#endif
-#endif
-
-/* Mark required libraries */
-#ifdef _MSC_VER
-#pragma comment(lib, "Ws2_32.lib")
-#endif
-
-#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>
-#include <dirent.h>
-#if !defined(NO_SSL_DL) && !defined(NO_SSL)
-#include <dlfcn.h>
-#endif
-#include <pthread.h>
-#if defined(__MACH__)
-#define SSL_LIB   "libssl.dylib"
-#define CRYPTO_LIB  "libcrypto.dylib"
-#else
-#if !defined(SSL_LIB)
-#define SSL_LIB   "libssl.so"
-#endif
-#if !defined(CRYPTO_LIB)
-#define CRYPTO_LIB  "libcrypto.so"
-#endif
-#endif
-#ifndef O_BINARY
-#define O_BINARY  0
-#endif /* O_BINARY */
-#define closesocket(a) close(a)
-#define mg_mkdir(x, y) mkdir(x, y)
-#define mg_remove(x) remove(x)
-#define mg_sleep(x) usleep((x) * 1000)
-#define ERRNO errno
-#define INVALID_SOCKET (-1)
-#define INT64_FMT PRId64
-typedef int SOCKET;
-#define WINCDECL
-
-#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 PASSWORDS_FILE_NAME ".htpasswd"
-#define CGI_ENVIRONMENT_SIZE 4096
-#define MAX_CGI_ENVIR_VARS 64
-#define MG_BUF_LEN 8192
-#ifndef MAX_REQUEST_SIZE
-#define MAX_REQUEST_SIZE 16384
-#endif
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
-
-#if !defined(DEBUG_TRACE)
-#if defined(CWDEBUG)
-
-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);
-}
-
-#define DEBUG_TRACE(fmt, ...) DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
-
-#else
-#define DEBUG_TRACE(fmt, ...)
-#endif /* CWDEBUG */
-#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
-        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;
-
-    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 */
-#define _DARWIN_UNLIMITED_SELECT
-
-#define IP_ADDR_STR_LEN 50  /* IPv6 hex string is 46 chars */
-
-#if !defined(MSG_NOSIGNAL)
-#define MSG_NOSIGNAL 0
-#endif
-
-#if !defined(SOMAXCONN)
-#define SOMAXCONN 100
-#endif
-
-#if !defined(PATH_MAX)
-#define PATH_MAX 4096
-#endif
-
-/* Size of the accepted socket queue */
-#if !defined(MGSQLEN)
-#define MGSQLEN 20
-#endif
-
-#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. */
-
-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 */
-};
-
-#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
-#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
-#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
-#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
-#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
-#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
-#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
-#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
-#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
-#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
-#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
-#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
-        const char *, int)) ssl_sw[11].ptr)
-#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
-        const char *, int)) ssl_sw[12].ptr)
-#define SSL_CTX_set_default_passwd_cb \
-  (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
-#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
-#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
-#define SSL_CTX_use_certificate_chain_file \
-  (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
-#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
-#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
-#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
-#define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
-
-#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
-#define CRYPTO_set_locking_callback \
-  (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
-#define CRYPTO_set_id_callback \
-  (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
-#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. */
-static struct ssl_func ssl_sw[] = {
-    {"SSL_free",   NULL},
-    {"SSL_accept",   NULL},
-    {"SSL_connect",   NULL},
-    {"SSL_read",   NULL},
-    {"SSL_write",   NULL},
-    {"SSL_get_error",  NULL},
-    {"SSL_set_fd",   NULL},
-    {"SSL_new",   NULL},
-    {"SSL_CTX_new",   NULL},
-    {"SSLv23_server_method", NULL},
-    {"SSL_library_init",  NULL},
-    {"SSL_CTX_use_PrivateKey_file", NULL},
-    {"SSL_CTX_use_certificate_file",NULL},
-    {"SSL_CTX_set_default_passwd_cb",NULL},
-    {"SSL_CTX_free",  NULL},
-    {"SSL_load_error_strings", NULL},
-    {"SSL_CTX_use_certificate_chain_file", NULL},
-    {"SSLv23_client_method", NULL},
-    {"SSL_pending", NULL},
-    {"SSL_CTX_set_verify", NULL},
-    {"SSL_shutdown",   NULL},
-    {NULL,    NULL}
-};
-
-/* 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},
-    {"CRYPTO_set_locking_callback", NULL},
-    {"CRYPTO_set_id_callback", NULL},
-    {"ERR_get_error",  NULL},
-    {"ERR_error_string", NULL},
-    {NULL,    NULL}
-};
-#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. */
-union usa {
-    struct sockaddr sa;
-    struct sockaddr_in sin;
-#if defined(USE_IPV6)
-    struct sockaddr_in6 sin6;
-#endif
-};
-
-/* Describes a string (chunk of memory). */
-struct vec {
-    const char *ptr;
-    size_t len;
-};
-
-struct file {
-    int is_directory;
-    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 */
-    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. */
-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 */
-};
-
-/* 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,
-    ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
-    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
-};
-
-/* 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 */
-    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 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 */
-
-    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 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
-};
-
-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()) ... */
-        filep->size = size;
-    }
-    return filep->membuf != NULL;
-}
-
-static int is_file_opened(const struct file *filep)
-{
-    return filep->membuf != NULL || filep->fp != NULL;
-}
-
-static int mg_fopen(struct mg_connection *conn, const char *path,
-                    const char *mode, struct file *filep)
-{
-    if (!is_file_in_memory(conn, path, filep)) {
-#ifdef _WIN32
-        wchar_t wbuf[PATH_MAX], wmode[20];
-        to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
-        MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
-        filep->fp = _wfopen(wbuf, wmode);
-#else
-        filep->fp = fopen(path, mode);
-#endif
-    }
-
-    return is_file_opened(filep);
-}
-
-static void mg_fclose(struct file *filep)
-{
-    if (filep != NULL && filep->fp != NULL) {
-        fclose(filep->fp);
-    }
-}
-
-static void mg_strlcpy(register char *dst, register const char *src, size_t n)
-{
-    for (; *src != '\0' && n > 1; n--) {
-        *dst++ = *src++;
-    }
-    *dst = '\0';
-}
-
-static int lowercase(const char *s)
-{
-    return tolower(* (const unsigned char *) s);
-}
-
-int mg_strncasecmp(const char *s1, const char *s2, size_t len)
-{
-    int diff = 0;
-
-    if (len > 0)
-        do {
-            diff = lowercase(s1++) - lowercase(s2++);
-        } while (diff == 0 && s1[-1] != '\0' && --len > 0);
-
-    return diff;
-}
-
-static int mg_strcasecmp(const char *s1, const char *s2)
-{
-    int diff;
-
-    do {
-        diff = lowercase(s1++) - lowercase(s2++);
-    } while (diff == 0 && s1[-1] != '\0');
-
-    return diff;
-}
-
-static char * mg_strndup(const char *ptr, size_t len)
-{
-    char *p;
-
-    if ((p = (char *) mg_malloc(len + 1)) != NULL) {
-        mg_strlcpy(p, ptr, len + 1);
-    }
-
-    return p;
-}
-
-static char * mg_strdup(const char *str)
-{
-    return mg_strndup(str, strlen(str));
-}
-
-static const char *mg_strcasestr(const char *big_str, const char *small_str)
-{
-    int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str);
-
-    for (i = 0; i <= big_len - small_len; i++) {
-        if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
-            return big_str + i;
-        }
-    }
-
-    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. */
-static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
-                        const char *fmt, va_list ap)
-{
-    int n;
-
-    if (buflen == 0)
-        return 0;
-
-    n = vsnprintf(buf, buflen, fmt, ap);
-
-    if (n < 0) {
-        mg_cry(conn, "vsnprintf error");
-        n = 0;
-    } else if (n >= (int) buflen) {
-        mg_cry(conn, "truncating vsnprintf buffer: [%.*s]",
-               n > 200 ? 200 : n, buf);
-        n = (int) buflen - 1;
-    }
-    buf[n] = '\0';
-
-    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);
-        }
-    }
-}
-
-/* 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;
-}
-
-/* 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)
-{
-    char *p, *begin_word, *end_word, *end_whitespace;
-
-    begin_word = *buf;
-    end_word = begin_word + strcspn(begin_word, delimiters);
-
-    /* Check for quotechar */
-    if (end_word > begin_word) {
-        p = end_word - 1;
-        while (*p == quotechar) {
-            /* 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 */
-                end_word += end_off + 1;
-            }
-        }
-        for (p++; p < end_word; p++) {
-            *p = '\0';
-        }
-    }
-
-    if (*end_word == '\0') {
-        *buf = end_word;
-    } else {
-        end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
-
-        for (p = end_word; p < end_whitespace; p++) {
-            *p = '\0';
-        }
-
-        *buf = end_whitespace;
-    }
-
-    return begin_word;
-}
-
-/* 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. */
-static const char *get_header(const struct mg_request_info *ri,
-                              const char *name)
-{
-    int i;
-
-    for (i = 0; i < ri->num_headers; i++)
-        if (!mg_strcasecmp(name, ri->http_headers[i].name))
-            return ri->http_headers[i].value;
-
-    return NULL;
-}
-
-const char *mg_get_header(const struct mg_connection *conn, const char *name)
-{
-    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". */
-static const char *next_option(const char *list, struct vec *val,
-                               struct vec *eq_val)
-{
-    if (list == NULL || *list == '\0') {
-        /* 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 */
-            val->len = list - val->ptr;
-            list++;
-        } else {
-            /* 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". */
-            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->len = val->ptr + val->len - eq_val->ptr;
-                val->len = (eq_val->ptr - val->ptr) - 1;
-            }
-        }
-    }
-
-    return list;
-}
-
-/* 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;
-    int i, j, len, res;
-
-    if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
-        res = match_prefix(pattern, (int)(or_str - pattern), str);
-        return res > 0 ? res :
-               match_prefix(or_str + 1, (int)((pattern + pattern_len) - (or_str + 1)), str);
-    }
-
-    i = j = 0;
-    for (; i < pattern_len; i++, j++) {
-        if (pattern[i] == '?' && str[j] != '\0') {
-            continue;
-        } else if (pattern[i] == '$') {
-            return str[j] == '\0' ? j : -1;
-        } else if (pattern[i] == '*') {
-            i++;
-            if (pattern[i] == '*') {
-                i++;
-                len = (int) strlen(str + j);
-            } else {
-                len = (int) strcspn(str + j, "/");
-            }
-            if (i == pattern_len) {
-                return j + len;
-            }
-            do {
-                res = match_prefix(pattern + i, pattern_len - i, str + j + len);
-            } while (res == -1 && len-- > 0);
-            return res == -1 ? -1 : j + res + len;
-        } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
-            return -1;
-        }
-    }
-    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. */
-static int should_keep_alive(const struct mg_connection *conn)
-{
-    const char *http_version = conn->request_info.http_version;
-    const char *header = mg_get_header(conn, "Connection");
-    if (conn->must_close ||
-        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 && 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);
-
-
-static void send_http_error(struct mg_connection *conn, int status,
-                            const char *reason, const char *fmt, ...)
-{
-    char buf[MG_BUF_LEN];
-    va_list ap;
-    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->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 */
-        if (status > 199 && status != 204 && status != 304) {
-            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);
-
-        mg_printf(conn, "HTTP/1.1 %d %s\r\n"
-                        "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);
-    }
-}
-
-#if defined(_WIN32) && !defined(__SYMBIAN32__)
-static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
-{
-    (void) unused;
-    *mutex = CreateMutex(NULL, FALSE, NULL);
-    return *mutex == NULL ? -1 : 0;
-}
-
-static int pthread_mutex_destroy(pthread_mutex_t *mutex)
-{
-    return CloseHandle(*mutex) == 0 ? -1 : 0;
-}
-
-static int pthread_mutex_lock(pthread_mutex_t *mutex)
-{
-    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)
-{
-    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;
-    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)
-{
-    return pthread_cond_timedwait(cv, mutex, NULL);
-}
-
-static int pthread_cond_signal(pthread_cond_t *cv)
-{
-    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)
-{
-    EnterCriticalSection(&cv->threadIdSec);
-    while (cv->waitingthreadcount) {
-        pthread_cond_signal(cv);
-    }
-    LeaveCriticalSection(&cv->threadIdSec);
-
-    return 0;
-}
-
-static int pthread_cond_destroy(pthread_cond_t *cv)
-{
-    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. */
-static void change_slashes_to_backslashes(char *path)
-{
-    int i;
-
-    for (i = 0; path[i] != '\0'; i++) {
-        if (path[i] == '/')
-            path[i] = '\\';
-        /* 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,
-                               path + i + 2, strlen(path + i + 1));
-    }
-}
-
-/* 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];
-
-    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. */
-    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),
-                        NULL, NULL);
-    if (strcmp(buf, buf2) != 0) {
-        wbuf[0] = L'\0';
-    }
-}
-
-#if defined(_WIN32_WCE)
-static time_t time(time_t *ptime)
-{
-    time_t t;
-    SYSTEMTIME st;
-    FILETIME ft;
-
-    GetSystemTime(&st);
-    SystemTimeToFileTime(&st, &ft);
-    t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
-
-    if (ptime != NULL) {
-        *ptime = t;
-    }
-
-    return t;
-}
-
-static struct tm *localtime(const time_t *ptime, struct tm *ptm)
-{
-    int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
-    FILETIME ft, lft;
-    SYSTEMTIME st;
-    TIME_ZONE_INFORMATION tzinfo;
-
-    if (ptm == NULL) {
-        return NULL;
-    }
-
-    * (int64_t *) &ft = t;
-    FileTimeToLocalFileTime(&ft, &lft);
-    FileTimeToSystemTime(&lft, &st);
-    ptm->tm_year = st.wYear - 1900;
-    ptm->tm_mon = st.wMonth - 1;
-    ptm->tm_wday = st.wDayOfWeek;
-    ptm->tm_mday = st.wDay;
-    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_isdst =
-        GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
-
-    return ptm;
-}
-
-static struct tm *gmtime(const time_t *ptime, struct tm *ptm)
-{
-    /* FIXME(lsm): fix this. */
-    return localtime(ptime, ptm);
-}
-
-static size_t strftime(char *dst, size_t dst_size, const char *fmt,
-                       const struct tm *tm)
-{
-    (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
-    return 0;
-}
-#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. */
-static int path_cannot_disclose_cgi(const char *path)
-{
-    static const char *allowed_last_characters = "_-";
-    int last = path[strlen(path) - 1];
-    return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
-}
-
-static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
-{
-    wchar_t wbuf[PATH_MAX];
-    WIN32_FILE_ATTRIBUTE_DATA info;
-
-    if (!is_file_in_memory(conn, path, filep)) {
-        to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
-        if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
-            filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
-            filep->modification_time = SYS2UNIX_TIME(
-                                           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 (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
-                memset(filep, 0, sizeof(*filep));
-            }
-        }
-    }
-
-    return filep->membuf != NULL || filep->modification_time != 0;
-}
-
-static int mg_remove(const char *path)
-{
-    wchar_t wbuf[PATH_MAX];
-    to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
-    return DeleteFileW(wbuf) ? 0 : -1;
-}
-
-static int mg_mkdir(const char *path, int mode)
-{
-    char buf[PATH_MAX];
-    wchar_t wbuf[PATH_MAX];
-
-    (void) mode;
-    mg_strlcpy(buf, path, sizeof(buf));
-    change_slashes_to_backslashes(buf);
-
-    (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
-
-    return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
-}
-
-/* Implementation of POSIX opendir/closedir/readdir for Windows. */
-static DIR * opendir(const char *name)
-{
-    DIR *dir = NULL;
-    wchar_t wpath[PATH_MAX];
-    DWORD attrs;
-
-    if (name == NULL) {
-        SetLastError(ERROR_BAD_ARGUMENTS);
-    } else if ((dir = (DIR *) mg_malloc(sizeof(*dir))) == NULL) {
-        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    } else {
-        to_unicode(name, wpath, ARRAY_SIZE(wpath));
-        attrs = GetFileAttributesW(wpath);
-        if (attrs != 0xFFFFFFFF &&
-            ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
-            (void) wcscat(wpath, L"\\*");
-            dir->handle = FindFirstFileW(wpath, &dir->info);
-            dir->result.d_name[0] = '\0';
-        } else {
-            mg_free(dir);
-            dir = NULL;
-        }
-    }
-
-    return dir;
-}
-
-static int closedir(DIR *dir)
-{
-    int result = 0;
-
-    if (dir != NULL) {
-        if (dir->handle != INVALID_HANDLE_VALUE)
-            result = FindClose(dir->handle) ? 0 : -1;
-
-        mg_free(dir);
-    } else {
-        result = -1;
-        SetLastError(ERROR_BAD_ARGUMENTS);
-    }
-
-    return result;
-}
-
-static struct dirent *readdir(DIR *dir)
-{
-    struct dirent *result = 0;
-
-    if (dir) {
-        if (dir->handle != INVALID_HANDLE_VALUE) {
-            result = &dir->result;
-            (void) WideCharToMultiByte(CP_UTF8, 0,
-                                       dir->info.cFileName, -1, result->d_name,
-                                       sizeof(result->d_name), NULL, NULL);
-
-            if (!FindNextFileW(dir->handle, &dir->info)) {
-                (void) FindClose(dir->handle);
-                dir->handle = INVALID_HANDLE_VALUE;
-            }
-
-        } else {
-            SetLastError(ERROR_FILE_NOT_FOUND);
-        }
-    } else {
-        SetLastError(ERROR_BAD_ARGUMENTS);
-    }
-
-    return result;
-}
-
-#ifndef HAVE_POLL
-static int poll(struct pollfd *pfd, int n, int milliseconds)
-{
-    struct timeval tv;
-    fd_set set;
-    int i, result;
-    SOCKET maxfd = 0;
-
-    tv.tv_sec = milliseconds / 1000;
-    tv.tv_usec = (milliseconds % 1000) * 1000;
-    FD_ZERO(&set);
-
-    for (i = 0; i < n; i++) {
-        FD_SET((SOCKET) pfd[i].fd, &set);
-        pfd[i].revents = 0;
-
-        if (pfd[i].fd > maxfd) {
-            maxfd = pfd[i].fd;
-        }
-    }
-
-    if ((result = select((int)maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
-        for (i = 0; i < n; i++) {
-            if (FD_ISSET(pfd[i].fd, &set)) {
-                pfd[i].revents = POLLIN;
-            }
-        }
-    }
-
-    return result;
-}
-#endif /* HAVE_POLL */
-
-static void set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
-{
-    (void) conn; /* Unused. */
-    (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
-}
-
-int mg_start_thread(mg_thread_func_t f, void *p)
-{
-#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. */
-
-static int mg_start_thread_with_id(unsigned (__stdcall *f)(void *), void *p,
-                                   pthread_t *threadidptr)
-{
-    uintptr_t uip;
-    HANDLE threadhandle;
-    int result = -1;
-
-    uip = _beginthreadex(NULL, 0, (unsigned (__stdcall *)(void *)) f, p, 0,
-                         NULL);
-    threadhandle = (HANDLE) uip;
-    if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
-        *threadidptr = threadhandle;
-        result = 0;
-    }
-
-    return result;
-}
-
-/* Wait for a thread to finish. */
-
-static int mg_join_thread(pthread_t threadid)
-{
-    int result;
-    DWORD dwevent;
-
-    result = -1;
-    dwevent = WaitForSingleObject(threadid, INFINITE);
-    if (dwevent == WAIT_FAILED) {
-        int err;
-
-        err = GetLastError();
-        DEBUG_TRACE("WaitForSingleObject() failed, error %d", err);
-    } else {
-        if (dwevent == WAIT_OBJECT_0) {
-            CloseHandle(threadid);
-            result = 0;
-        }
-    }
-
-    return result;
-}
-
-static HANDLE dlopen(const char *dll_name, int flags)
-{
-    wchar_t wbuf[PATH_MAX];
-    (void) flags;
-    to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
-    return LoadLibraryW(wbuf);
-}
-
-static int dlclose(void *handle)
-{
-    int result;
-
-    if (FreeLibrary((HMODULE) handle) != 0) {
-        result = 0;
-    } else {
-        result = -1;
-    }
-
-    return result;
-}
-
-#if !defined(NO_CGI)
-#define SIGKILL 0
-static int kill(pid_t pid, int sig_num)
-{
-    (void) TerminateProcess(pid, sig_num);
-    (void) CloseHandle(pid);
-    return 0;
-}
-
-static void trim_trailing_whitespaces(char *s)
-{
-    char *e = s + strlen(s) - 1;
-    while (e > s && isspace(* (unsigned char *) e)) {
-        *e-- = '\0';
-    }
-}
-
-static pid_t spawn_process(struct mg_connection *conn, const char *prog,
-                           char *envblk, char *envp[], int fdin,
-                           int fdout, const char *dir)
-{
-    HANDLE me;
-    char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
-         cmdline[PATH_MAX], buf[PATH_MAX];
-    struct file file = STRUCT_FILE_INITIALIZER;
-    STARTUPINFOA si;
-    PROCESS_INFORMATION pi = { 0 };
-
-    (void) envp;
-
-    memset(&si, 0, sizeof(si));
-    si.cb = sizeof(si);
-
-    /* TODO(lsm): redirect CGI errors to the error log file */
-    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-    si.wShowWindow = SW_HIDE;
-
-    me = GetCurrentProcess();
-    DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
-                    &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
-    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 */
-    interp = conn->ctx->config[CGI_INTERPRETER];
-    if (interp == NULL) {
-        buf[0] = buf[1] = '\0';
-
-        /* 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;
-            mg_fgets(buf, sizeof(buf), &file, &p);
-            mg_fclose(&file);
-            buf[sizeof(buf) - 1] = '\0';
-        }
-
-        if (buf[0] == '#' && buf[1] == '!') {
-            trim_trailing_whitespaces(buf + 2);
-        } else {
-            buf[2] = '\0';
-        }
-        interp = buf + 2;
-    }
-
-    if (interp[0] != '\0') {
-        GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
-        interp = full_interp;
-    }
-    GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
-
-    mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"",
-                interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
-
-    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",
-               __func__, cmdline, ERRNO);
-        pi.hProcess = (pid_t) -1;
-    }
-
-    (void) CloseHandle(si.hStdOutput);
-    (void) CloseHandle(si.hStdInput);
-    if (pi.hThread != NULL)
-        (void) CloseHandle(pi.hThread);
-
-    return (pid_t) pi.hProcess;
-}
-#endif /* !NO_CGI */
-
-static int set_non_blocking_mode(SOCKET sock)
-{
-    unsigned long on = 1;
-    return ioctlsocket(sock, FIONBIO, &on);
-}
-
-#else
-static int mg_stat(struct mg_connection *conn, const char *path,
-                   struct file *filep)
-{
-    struct stat st;
-
-    if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) {
-        filep->size = st.st_size;
-        filep->modification_time = st.st_mtime;
-        filep->is_directory = S_ISDIR(st.st_mode);
-    } else {
-        filep->modification_time = (time_t) 0;
-    }
-
-    return filep->membuf != NULL || filep->modification_time != (time_t) 0;
-}
-
-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));
-        }
-    }
-}
-
-int mg_start_thread(mg_thread_func_t func, void *param)
-{
-    pthread_t thread_id;
-    pthread_attr_t attr;
-    int result;
-
-    (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 */
-    (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);
-
-    return result;
-}
-
-/* Start a thread storing the thread context. */
-
-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;
-    int result;
-
-    (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 */
-    (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 ((result == 0) && (threadidptr != NULL)) {
-        *threadidptr = thread_id;
-    }
-    return result;
-}
-
-/* Wait for a thread to finish. */
-
-static int mg_join_thread(pthread_t threadid)
-{
-    int result;
-
-    result = pthread_join(threadid, NULL);
-    return result;
-}
-
-#ifndef NO_CGI
-static pid_t spawn_process(struct mg_connection *conn, const char *prog,
-                           char *envblk, char *envp[], int fdin,
-                           int fdout, const char *dir)
-{
-    pid_t pid;
-    const char *interp;
-
-    (void) envblk;
-
-    if ((pid = fork()) == -1) {
-        /* Parent */
-        send_http_error(conn, 500, NULL,
-            "Error: Creating CGI process\nfork(): %s", strerror(ERRNO));
-    } else if (pid == 0) {
-        /* Child */
-        if (chdir(dir) != 0) {
-            mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
-        } else if (dup2(fdin, 0) == -1) {
-            mg_cry(conn, "%s: dup2(%d, 0): %s", __func__, fdin, strerror(ERRNO));
-        } 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. */
-            (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. */
-            signal(SIGCHLD, SIG_DFL);
-
-            interp = conn->ctx->config[CGI_INTERPRETER];
-            if (interp == NULL) {
-                (void) execle(prog, prog, NULL, envp);
-                mg_cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
-            } else {
-                (void) execle(interp, interp, prog, NULL, envp);
-                mg_cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
-                       strerror(ERRNO));
-            }
-        }
-        exit(EXIT_FAILURE);
-    }
-
-    return pid;
-}
-#endif /* !NO_CGI */
-
-static int set_non_blocking_mode(SOCKET sock)
-{
-    int flags;
-
-    flags = fcntl(sock, F_GETFL, 0);
-    (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
-
-    return 0;
-}
-#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)
-{
-    int64_t sent;
-    int n, k;
-
-    (void) ssl;  /* Get rid of warning */
-    sent = 0;
-    while (sent < len) {
-
-        /* How many bytes we send in this iteration */
-        k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
-
-#ifndef NO_SSL
-        if (ssl != NULL) {
-            n = SSL_write(ssl, buf + sent, k);
-        } else
-#endif
-            if (fp != NULL) {
-                n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
-                if (ferror(fp))
-                    n = -1;
-            } else {
-                n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
-            }
-
-        if (n <= 0)
-            break;
-
-        sent += n;
-    }
-
-    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. */
-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. */
-        nread = read(fileno(fp), buf, (size_t) len);
-#ifndef NO_SSL
-    } else if (conn->ssl != NULL) {
-        nread = SSL_read(conn->ssl, buf, len);
-#endif
-    } else {
-        nread = recv(conn->client.sock, buf, (size_t) len, 0);
-    }
-
-    return conn->ctx->stop_flag ? -1 : nread;
-}
-
-static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
-{
-    int n, nread = 0;
-
-    while (len > 0 && conn->ctx->stop_flag == 0) {
-        n = pull(fp, conn, buf + nread, len);
-        if (n < 0) {
-            nread = n;  /* Propagate the error */
-            break;
-        } else if (n == 0) {
-            break;  /* No more data to read */
-        } else {
-            conn->consumed_content += n;
-            nread += n;
-            len -= n;
-        }
-    }
-
-    return nread;
-}
-
-int mg_read(struct mg_connection *conn, void *buf, size_t len)
-{
-    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 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 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 */
-        buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len - conn->consumed_content;
-        if (buffered_len > 0) {
-            if (len64 < buffered_len) {
-                buffered_len = len64;
-            }
-            body = conn->buf + conn->request_len + conn->consumed_content;
-            memcpy(buf, body, (size_t) 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. */
-        if ((n = pull_all(NULL, conn, (char *) buf, (int)len64)) >= 0) {
-            nread += n;
-        } else {
-            nread = (nread > 0 ? nread : n);
-        }
-    }
-    return (int)nread;
-}
-
-int mg_write(struct mg_connection *conn, const void *buf, size_t len)
-{
-    time_t now;
-    int64_t n, total, allowed;
-
-    if (conn->throttle > 0) {
-        if ((now = time(NULL)) != conn->last_throttle_time) {
-            conn->last_throttle_time = now;
-            conn->last_throttle_bytes = 0;
-        }
-        allowed = conn->throttle - conn->last_throttle_bytes;
-        if (allowed > (int64_t) len) {
-            allowed = len;
-        }
-        if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
-                          (int64_t) allowed)) == allowed) {
-            buf = (char *) buf + total;
-            conn->last_throttle_bytes += total;
-            while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
-                allowed = conn->throttle > (int64_t) len - total ?
-                          (int64_t) len - total : conn->throttle;
-                if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
-                              (int64_t) allowed)) != allowed) {
-                    break;
-                }
-                sleep(1);
-                conn->last_throttle_bytes = allowed;
-                conn->last_throttle_time = time(NULL);
-                buf = (char *) buf + n;
-                total += n;
-            }
-        }
-    } else {
-        total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
-                     (int64_t) len);
-    }
-    return (int) total;
-}
-
-/* Alternative alloc_vprintf() for non-compliant C runtimes */
-static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
-{
-    va_list ap_copy;
-    int size = MG_BUF_LEN;
-    int len = -1;
-
-    *buf = NULL;
-    while (len == -1) {
-        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);
-        va_end(ap_copy);
-    }
-
-    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. */
-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. */
-    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.
-        */
-        va_copy(ap_copy, ap);
-        len = alloc_vprintf2(buf, fmt, ap);
-        va_end(ap_copy);
-    } else if (len > (int) size &&
-               (size = len + 1) > 0 &&
-               (*buf = (char *) mg_malloc(size)) == NULL) {
-        len = -1;  /* Allocation failed, mark failure */
-    } else {
-        va_copy(ap_copy, ap);
-        IGNORE_UNUSED_RESULT(vsnprintf(*buf, size, fmt, ap_copy));
-        va_end(ap_copy);
-    }
-
-    return len;
-}
-
-int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
-{
-    char mem[MG_BUF_LEN], *buf = mem;
-    int len;
-
-    if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
-        len = mg_write(conn, buf, (size_t) len);
-    }
-    if (buf != mem && buf != NULL) {
-        mg_free(buf);
-    }
-
-    return len;
-}
-
-int mg_printf(struct mg_connection *conn, const char *fmt, ...)
-{
-    va_list ap;
-    int result;
-
-    va_start(ap, fmt);
-    result = mg_vprintf(conn, fmt, ap);
-    va_end(ap);
-
-    return result;
-}
-
-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')
-
-    for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
-        if (i < src_len - 2 && src[i] == '%' &&
-            isxdigit(* (const unsigned char *) (src + i + 1)) &&
-            isxdigit(* (const unsigned char *) (src + i + 2))) {
-            a = tolower(* (const unsigned char *) (src + i + 1));
-            b = tolower(* (const unsigned char *) (src + i + 2));
-            dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
-            i += 2;
-        } else if (is_form_url_encoded && src[i] == '+') {
-            dst[j] = ' ';
-        } else {
-            dst[j] = src[i];
-        }
-    }
-
-    dst[j] = '\0'; /* Null-terminate the destination */
-
-    return i >= src_len ? j : -1;
-}
-
-int mg_get_var(const char *data, size_t data_len, const char *name,
-               char *dst, size_t dst_len)
-{
-    return mg_get_var2(data,data_len,name,dst,dst_len,0);
-}
-
-int mg_get_var2(const char *data, size_t data_len, const char *name,
-                char *dst, size_t dst_len, size_t occurrence)
-{
-    const char *p, *e, *s;
-    size_t name_len;
-    int len;
-
-    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 */
-        for (p = data; p + name_len < e; p++) {
-            if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
-                !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
-
-                /* Point p to variable value */
-                p += name_len + 1;
-
-                /* Point s to the end of the value */
-                s = (const char *) memchr(p, '&', (size_t)(e - p));
-                if (s == NULL) {
-                    s = e;
-                }
-                assert(s >= p);
-
-                /* Decode variable into destination buffer */
-                len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
-
-                /* Redirect error code from -1 to -2 (destination buffer too
-                   small). */
-                if (len == -1) {
-                    len = -2;
-                }
-                break;
-            }
-        }
-    }
-
-    return len;
-}
-
-int mg_get_cookie(const char *cookie_header, const char *var_name,
-                  char *dst, size_t dst_size)
-{
-    const char *s, *p, *end;
-    int name_len, len = -1;
-
-    if (dst == NULL || dst_size == 0) {
-        len = -2;
-    } else if (var_name == NULL || (s = cookie_header) == NULL) {
-        len = -1;
-        dst[0] = '\0';
-    } else {
-        name_len = (int) strlen(var_name);
-        end = s + strlen(s);
-        dst[0] = '\0';
-
-        for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
-

<TRUNCATED>

Mime
View raw message