You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2018/07/03 20:45:53 UTC

[1/6] celix git commit: CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

Repository: celix
Updated Branches:
  refs/heads/develop 3f24edf0b -> c4de9077d


http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/mongoose/root/index.html
----------------------------------------------------------------------
diff --git a/examples/celix-examples/mongoose/root/index.html b/examples/celix-examples/mongoose/root/index.html
deleted file mode 100644
index 255758f..0000000
--- a/examples/celix-examples/mongoose/root/index.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
- *Licensed to the Apache Software Foundation (ASF) under one
- *or more contributor license agreements.  See the NOTICE file
- *distributed with this work for additional information
- *regarding copyright ownership.  The ASF licenses this file
- *to you under the Apache License, Version 2.0 (the
- *"License"); you may not use this file except in compliance
- *with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unless required by applicable law or agreed to in writing,
- *software distributed under the License is distributed on an
- *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- *specific language governing permissions and limitations
- *under the License.
--->
-<div align="center"><FONT 
-color="#ffffff" size="+1"><MARQUEE bgcolor="#000080" 
-direction="right" loop="20" width="75%"><STRONG>
-Serving content from within a bundle works!!1!11!!
-</STRONG></MARQUEE></FONT></DIV>
\ No newline at end of file


[2/6] celix git commit: CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/mongoose/private/src/mongoose.c
----------------------------------------------------------------------
diff --git a/examples/celix-examples/mongoose/private/src/mongoose.c b/examples/celix-examples/mongoose/private/src/mongoose.c
deleted file mode 100644
index 1a1f87c..0000000
--- a/examples/celix-examples/mongoose/private/src/mongoose.c
+++ /dev/null
@@ -1,4076 +0,0 @@
-// Copyright (c) 2004-2010 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)
-#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
-#else
-#define _XOPEN_SOURCE 600 // For flockfile() on Linux
-#define _LARGEFILE_SOURCE // Enable 64-bit file offsets
-#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 <stdio.h>
-#include <sys/wait.h>
-
-#if defined(_WIN32)  // Windows specific #includes and #defines
-#define _WIN32_WINNT 0x0400 // To make it link in VS2005
-#include <windows.h>
-
-#ifndef PATH_MAX
-#define PATH_MAX MAX_PATH
-#endif
-
-#ifndef _WIN32_WCE
-#include <process.h>
-#include <direct.h>
-#include <io.h>
-#else // _WIN32_WCE
-#include <winsock2.h>
-#define NO_CGI // WinCE has no pipes
-
-typedef long off_t;
-#define BUFSIZ  4096
-
-#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__ "line " STR(__LINE__)
-#define strtoull(x, y, z) strtoul(x, y, z)
-#define strtoll(x, y, z) strtol(x, y, z)
-#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 DIRSEP '\\'
-#define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
-#define O_NONBLOCK  0
-#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 sleep(x) Sleep((x) * 1000)
-
-#define pipe(x) _pipe(x, BUFSIZ, _O_BINARY)
-#define popen(x, y) _popen(x, y)
-#define pclose(x) _pclose(x)
-#define close(x) _close(x)
-#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
-#define RTLD_LAZY  0
-#define fseeko(x, y, z) fseek((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) (void) 0
-#define funlockfile(x) (void) 0
-
-#if !defined(fileno)
-#define fileno(x) _fileno(x)
-#endif // !fileno MINGW #defines fileno
-
-typedef HANDLE pthread_mutex_t;
-typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
-typedef DWORD pthread_t;
-#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
-
-struct timespec {
-  long tv_nsec;
-  long tv_sec;
-};
-
-static int pthread_mutex_lock(pthread_mutex_t *);
-static int pthread_mutex_unlock(pthread_mutex_t *);
-static FILE *mg_fopen(const char *path, const char *mode);
-
-#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;
-
-#else    // UNIX  specific
-
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
-#include <netdb.h>
-
-#include <pwd.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#if defined(__MACH__)
-#define SSL_LIB   "libssl.dylib"
-#define CRYPTO_LIB  "libcrypto.dylib"
-#else
-#define SSL_LIB   "libssl.so"
-#define CRYPTO_LIB  "libcrypto.so"
-#endif
-#define DIRSEP   '/'
-#define IS_DIRSEP_CHAR(c) ((c) == '/')
-#define O_BINARY  0
-#define closesocket(a) close(a)
-#define mg_fopen(x, y) fopen(x, y)
-#define mg_mkdir(x, y) mkdir(x, y)
-#define mg_remove(x) remove(x)
-#define mg_rename(x, y) rename(x, y)
-#define ERRNO errno
-#define INVALID_SOCKET (-1)
-#define INT64_FMT PRId64
-typedef int SOCKET;
-#define WINCDECL
-
-#endif // End of Windows and UNIX specific includes
-
-#include "mongoose.h"
-
-#define MONGOOSE_VERSION "2.11"
-#define PASSWORDS_FILE_NAME ".htpasswd"
-#define CGI_ENVIRONMENT_SIZE 4096
-#define MAX_CGI_ENVIR_VARS 64
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
-
-#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)
-#else
-#define DEBUG_TRACE(x)
-#endif // DEBUG
-
-// Darwin prior to 7.0 and Win32 do not have socklen_t
-#ifdef NO_SOCKLEN_T
-typedef int socklen_t;
-#endif // NO_SOCKLEN_T
-
-typedef void * (*mg_thread_func_pt)(void *);
-
-static const char *http_500_error = "Internal Server Error";
-
-// Snatched from OpenSSL includes. I put the prototypes here to be independent
-// from the OpenSSL source installation. Having this, mongoose + SSL can be
-// built on any system with binary SSL libraries installed.
-typedef struct ssl_st SSL;
-typedef struct ssl_method_st SSL_METHOD;
-typedef struct ssl_ctx_st SSL_CTX;
-
-#define SSL_ERROR_WANT_READ 2
-#define SSL_ERROR_WANT_WRITE 3
-#define SSL_FILETYPE_PEM 1
-#define CRYPTO_LOCK  1
-
-#if defined(NO_SSL_DL)
-extern void SSL_free(SSL *);
-extern int SSL_accept(SSL *);
-extern int SSL_connect(SSL *);
-extern int SSL_read(SSL *, void *, int);
-extern int SSL_write(SSL *, const void *, int);
-extern int SSL_get_error(const SSL *, int);
-extern int SSL_set_fd(SSL *, int);
-extern SSL *SSL_new(SSL_CTX *);
-extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
-extern SSL_METHOD *SSLv23_server_method(void);
-extern int SSL_library_init(void);
-extern void SSL_load_error_strings(void);
-extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
-extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
-extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
-extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_pt);
-extern void SSL_CTX_free(SSL_CTX *);
-extern unsigned long ERR_get_error(void);
-extern char *ERR_error_string(unsigned long, char *);
-extern int CRYPTO_num_locks(void);
-extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
-extern void CRYPTO_set_id_callback(unsigned long (*)(void));
-#else
-// Dynamically loaded SSL functionality
-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])
-#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_pt)) 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 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)) ssl_sw[3].ptr)
-#define ERR_error_string (* (char * (*)(unsigned long, char *)) ssl_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},
-  {NULL,    NULL}
-};
-
-// Similar array as ssl_sw. These functions could be located in different lib.
-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_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.
-struct usa {
-  socklen_t len;
-  union {
-    struct sockaddr sa;
-    struct sockaddr_in sin;
-  } u;
-};
-
-// Describes a string (chunk of memory).
-struct vec {
-  const char *ptr;
-  size_t len;
-};
-
-// Structure used by mg_stat() function. Uses 64 bit file length.
-struct mgstat {
-  int is_directory;  // Directory marker
-  int64_t size;      // File size
-  time_t mtime;      // Modification time
-};
-
-// Describes listening socket, or socket which was accept()-ed by the master
-// thread and queued for future handling by the worker thread.
-struct socket {
-  struct socket *next;  // Linkage
-  SOCKET sock;          // Listening socket
-  struct usa lsa;       // Local socket address
-  struct usa rsa;       // Remote socket address
-  int is_ssl;           // Is socket SSL-ed
-  int is_proxy;
-};
-
-enum {
-  CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
-  PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE,
-  SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
-  GLOBAL_PASSWORDS_FILE, INDEX_FILES,
-  ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, MAX_REQUEST_SIZE,
-  EXTRA_MIME_TYPES, LISTENING_PORTS,
-  DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER,
-  NUM_OPTIONS
-};
-
-static const char *config_options[] = {
-  "C", "cgi_extensions", ".cgi,.pl,.php",
-  "E", "cgi_environment", NULL,
-  "G", "put_delete_passwords_file", NULL,
-  "I", "cgi_interpreter", NULL,
-  "P", "protect_uri", NULL,
-  "R", "authentication_domain", "mydomain.com",
-  "S", "ssi_extensions", ".shtml,.shtm",
-  "a", "access_log_file", NULL,
-  "c", "ssl_chain_file", NULL,
-  "d", "enable_directory_listing", "yes",
-  "e", "error_log_file", NULL,
-  "g", "global_passwords_file", NULL,
-  "i", "index_files", "index.html,index.htm,index.cgi",
-  "k", "enable_keep_alive", "no",
-  "l", "access_control_list", NULL,
-  "M", "max_request_size", "16384",
-  "m", "extra_mime_types", NULL,
-  "p", "listening_ports", "8080",
-  "r", "document_root",  ".",
-  "s", "ssl_certificate", NULL,
-  "t", "num_threads", "10",
-  "u", "run_as_user", NULL,
-  NULL
-};
-#define ENTRIES_PER_CONFIG_OPTION 3
-
-struct mg_context {
-  int stop_flag;                // Should we stop event loop
-  SSL_CTX *ssl_ctx;             // SSL context
-  char *config[NUM_OPTIONS];    // Mongoose configuration parameters
-  mg_callback_pt user_callback;  // User-defined callback function
-
-  struct socket *listening_sockets;
-
-  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[20];   // Accepted sockets
-  int sq_head;               // Head of the socket queue
-  int sq_tail;               // Tail of the socket queue
-  pthread_cond_t sq_full;    // Singaled when socket is produced
-  pthread_cond_t sq_empty;   // Signaled when socket is consumed
-};
-
-struct mg_connection {
-  struct mg_connection *peer; // Remote target in proxy mode
-  struct mg_request_info request_info;
-  struct mg_context *ctx;
-  SSL *ssl;                   // SSL descriptor
-  struct socket client;       // Connected client
-  time_t birth_time;          // Time connection was accepted
-  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 is already read
-  char *buf;                  // Buffer for received data
-  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
-};
-
-const char **mg_get_valid_option_names(void) {
-  return config_options;
-}
-
-static void *call_user(struct mg_connection *conn, enum mg_event event) {
-  return conn->ctx->user_callback == NULL ? NULL :
-    conn->ctx->user_callback(event, conn, &conn->request_info);
-}
-
-static int get_option_index(const char *name) {
-  int i;
-
-  for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) {
-    if (strcmp(config_options[i], name) == 0 ||
-        strcmp(config_options[i + 1], name) == 0) {
-      return i / ENTRIES_PER_CONFIG_OPTION;
-    }
-  }
-  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];
-  }
-}
-
-// Print error message to the opened error log stream.
-static void cry(struct mg_connection *conn, const char *fmt, ...) {
-  char buf[BUFSIZ];
-  va_list ap;
-  FILE *fp;
-  time_t timestamp;
-
-  va_start(ap, fmt);
-  (void) 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.
-  conn->request_info.log_message = buf;
-  if (call_user(conn, MG_EVENT_LOG) == NULL) {
-    fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
-      mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
-
-    if (fp != NULL) {
-      flockfile(fp);
-      timestamp = time(NULL);
-
-      (void) fprintf(fp,
-          "[%010lu] [error] [client %s] ",
-          (unsigned long) timestamp,
-          inet_ntoa(conn->client.rsa.u.sin.sin_addr));
-
-      if (conn->request_info.request_method != NULL) {
-        (void) fprintf(fp, "%s %s: ",
-            conn->request_info.request_method,
-            conn->request_info.uri);
-      }
-
-      (void) fprintf(fp, "%s", buf);
-      fputc('\n', fp);
-      funlockfile(fp);
-      if (fp != stderr) {
-        fclose(fp);
-      }
-    }
-  }
-  conn->request_info.log_message = NULL;
-}
-
-// Return OpenSSL error message
-static const char *ssl_error(void) {
-  unsigned long err;
-  err = ERR_get_error();
-  return err == 0 ? "" : ERR_error_string(err, NULL);
-}
-
-// 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 MONGOOSE_VERSION;
-}
-
-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(* (unsigned char *) s);
-}
-
-static 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 *) 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));
-}
-
-// Like snprintf(), but never returns negative value, or the 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) {
-    cry(conn, "vsnprintf error");
-    n = 0;
-  } else if (n >= (int) buflen) {
-    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,
-                       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;
-}
-
-// Skip the characters until one of the delimiters characters found.
-// 0-terminate resulting word. Skip the rest of the delimiters if any.
-// Advance pointer to buffer to the next word. Return found 0-terminated word.
-static char *skip(char **buf, const char *delimiters) {
-  char *p, *begin_word, *end_word, *end_delimiters;
-
-  begin_word = *buf;
-  end_word = begin_word + strcspn(begin_word, delimiters);
-  end_delimiters = end_word + strspn(end_word, delimiters);
-
-  for (p = end_word; p < end_delimiters; p++) {
-    *p = '\0';
-  }
-
-  *buf = end_delimiters;
-
-  return begin_word;
-}
-
-// 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 comma separated list of values.
-// It returns a list pointer shifted to the next value, of 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 = 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;
-}
-
-#if !defined(NO_CGI)
-static int match_extension(const char *path, const char *ext_list) {
-  struct vec ext_vec;
-  size_t path_len;
-
-  path_len = strlen(path);
-
-  while ((ext_list = next_option(ext_list, &ext_vec, NULL)) != NULL)
-    if (ext_vec.len < path_len &&
-        mg_strncasecmp(path + path_len - ext_vec.len,
-          ext_vec.ptr, ext_vec.len) == 0)
-      return 1;
-
-  return 0;
-}
-#endif // !NO_CGI
-
-// 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");
-  return (header == NULL && http_version && !strcmp(http_version, "1.1")) ||
-      (header != NULL && !strcmp(header, "keep-alive"));
-}
-
-static const char *suggest_connection_header(const struct mg_connection *conn) {
-  return should_keep_alive(conn) ? "keep-alive" : "close";
-}
-
-static void send_http_error(struct mg_connection *conn, int status,
-                            const char *reason, const char *fmt, ...) {
-  char buf[BUFSIZ];
-  va_list ap;
-  int len;
-
-  conn->request_info.status_code = status;
-
-  if (call_user(conn, MG_HTTP_ERROR) == NULL) {
-    buf[0] = '\0';
-    len = 0;
-
-    /* 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);
-      cry(conn, "%s", buf);
-      buf[len++] = '\n';
-
-      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-Type: text/plain\r\n"
-              "Content-Length: %d\r\n"
-              "Connection: %s\r\n\r\n", status, reason, len,
-              suggest_connection_header(conn));
-    conn->num_bytes_sent += mg_printf(conn, "%s", buf);
-  }
-}
-
-#ifdef _WIN32
-static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
-  unused = NULL;
-  *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_unlock(pthread_mutex_t *mutex) {
-  return ReleaseMutex(*mutex) == 0 ? -1 : 0;
-}
-
-static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
-  unused = NULL;
-  cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
-  cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
-  return cv->signal != NULL && cv->broadcast != NULL ? 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 ReleaseMutex(*mutex) == 0 ? -1 : 0;
-}
-
-static int pthread_cond_signal(pthread_cond_t *cv) {
-  return SetEvent(cv->signal) == 0 ? -1 : 0;
-}
-
-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;
-}
-
-static int pthread_cond_destroy(pthread_cond_t *cv) {
-  return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
-}
-
-static pthread_t pthread_self(void) {
-  return GetCurrentThreadId();
-}
-
-// 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], *p;
-
-  mg_strlcpy(buf, path, sizeof(buf));
-  change_slashes_to_backslashes(buf);
-
-  // Point p to the end of the file name
-  p = buf + strlen(buf) - 1;
-
-  // Trim trailing backslash character
-  while (p > buf && *p == '\\' && p[-1] != ':') {
-    *p-- = '\0';
-  }
-
-   // Protect from CGI code disclosure.
-   // This is very nasty hole. Windows happily opens files with
-   // some garbage in the end of file name. So fopen("a.cgi    ", "r")
-   // actually opens "a.cgi", and does not return an error!
-  if (*p == 0x20 ||               // No space at the end
-      (*p == 0x2e && p > buf) ||  // No '.' but allow '.' as full path
-      *p == 0x2b ||               // No '+'
-      (*p & ~0x7f)) {             // And generally no non-ascii chars
-    (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
-    buf[0] = '\0';
-  }
-
-  (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
-}
-
-#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 time_t mktime(struct tm *ptm) {
-  SYSTEMTIME st;
-  FILETIME ft, lft;
-
-  st.wYear = ptm->tm_year + 1900;
-  st.wMonth = ptm->tm_mon + 1;
-  st.wDay = ptm->tm_mday;
-  st.wHour = ptm->tm_hour;
-  st.wMinute = ptm->tm_min;
-  st.wSecond = ptm->tm_sec;
-  st.wMilliseconds = 0;
-
-  SystemTimeToFileTime(&st, &ft);
-  LocalFileTimeToFileTime(&ft, &lft);
-  return (time_t) ((MAKEUQUAD(lft.dwLowDateTime, lft.dwHighDateTime) -
-                    EPOCH_DIFF) / RATE_DIFF);
-}
-
-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 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
-
-static int mg_rename(const char* oldname, const char* newname) {
-  wchar_t woldbuf[PATH_MAX];
-  wchar_t wnewbuf[PATH_MAX];
-
-  to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
-  to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
-
-  return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
-}
-
-
-static FILE *mg_fopen(const char *path, const char *mode) {
-  wchar_t wbuf[PATH_MAX], wmode[20];
-
-  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
-  MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
-
-  return _wfopen(wbuf, wmode);
-}
-
-static int mg_stat(const char *path, struct mgstat *stp) {
-  int ok = -1; // Error
-  wchar_t wbuf[PATH_MAX];
-  WIN32_FILE_ATTRIBUTE_DATA info;
-
-  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
-
-  if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
-    stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
-    stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
-                               info.ftLastWriteTime.dwHighDateTime);
-    stp->is_directory =
-      info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
-    ok = 0;  // Success
-  }
-
-  return ok;
-}
-
-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];
-
-  mode = 0; // Unused
-  mg_strlcpy(buf, path, sizeof(buf));
-  change_slashes_to_backslashes(buf);
-
-  (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(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 *) 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 {
-      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;
-
-    free(dir);
-  } else {
-    result = -1;
-    SetLastError(ERROR_BAD_ARGUMENTS);
-  }
-
-  return result;
-}
-
-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;
-}
-
-#define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
-
-static int start_thread(struct mg_context *ctx, mg_thread_func_pt func,
-                        void *param) {
-  HANDLE hThread;
-  ctx = NULL; // Unused
-
-  hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, param, 0,
-                         NULL);
-  if (hThread != NULL) {
-    (void) CloseHandle(hThread);
-  }
-
-  return hThread == NULL ? -1 : 0;
-}
-
-static HANDLE dlopen(const char *dll_name, int flags) {
-  wchar_t wbuf[PATH_MAX];
-  flags = 0; // Unused
-  to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
-  return LoadLibraryW(wbuf);
-}
-
-#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 pid_t spawn_process(struct mg_connection *conn, const char *prog,
-                           char *envblk, char *envp[], int fd_stdin,
-                           int fd_stdout, const char *dir) {
-  HANDLE me;
-  char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX];
-  FILE *fp;
-  STARTUPINFOA si;
-  PROCESS_INFORMATION pi;
-
-  envp = NULL; // Unused
-
-  (void) memset(&si, 0, sizeof(si));
-  (void) memset(&pi, 0, sizeof(pi));
-
-  // TODO(lsm): redirect CGI errors to the error log file
-  si.cb  = sizeof(si);
-  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-  si.wShowWindow = SW_HIDE;
-
-  me = GetCurrentProcess();
-  (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
-      &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
-  (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), 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[2] = '\0';
-    if ((fp = fopen(cmdline, "r")) != NULL) {
-      (void) fgets(buf, sizeof(buf), fp);
-      if (buf[0] != '#' || buf[1] != '!') {
-        // First line does not start with "#!". Do not set interpreter.
-        buf[2] = '\0';
-      } else {
-        // Trim whitespaces in interpreter name
-        for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
-          *p = '\0';
-        }
-      }
-      (void) fclose(fp);
-    }
-    interp = buf + 2;
-  }
-
-  (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s",
-                     interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog);
-
-  DEBUG_TRACE(("Running [%s]", cmdline));
-  if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
-        CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
-    cry(conn, "%s: CreateProcess(%s): %d",
-        __func__, cmdline, ERRNO);
-    pi.hProcess = (pid_t) -1;
-  } else {
-    (void) close(fd_stdin);
-    (void) close(fd_stdout);
-  }
-
-  (void) CloseHandle(si.hStdOutput);
-  (void) CloseHandle(si.hStdInput);
-  (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(const char *path, struct mgstat *stp) {
-  struct stat st;
-  int ok;
-
-  if (stat(path, &st) == 0) {
-    ok = 0;
-    stp->size = st.st_size;
-    stp->mtime = st.st_mtime;
-    stp->is_directory = S_ISDIR(st.st_mode);
-  } else {
-    ok = -1;
-  }
-
-  return ok;
-}
-
-static void set_close_on_exec(int fd) {
-  (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
-}
-
-static int start_thread(struct mg_context *ctx, mg_thread_func_pt func,
-                        void *param) {
-  pthread_t thread_id;
-  pthread_attr_t attr;
-  int retval;
-
-  (void) pthread_attr_init(&attr);
-  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-  // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
-  // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
-
-  if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) {
-    cry(fc(ctx), "%s: %s", __func__, strerror(retval));
-  }
-
-  return retval;
-}
-
-#ifndef NO_CGI
-static pid_t spawn_process(struct mg_connection *conn, const char *prog,
-		__attribute__((unused)) char *envblk, char *envp[], int fd_stdin,
-                           int fd_stdout, const char *dir) {
-  pid_t pid;
-  const char *interp;
-
-  // envblk = NULL; // Unused
-
-  if ((pid = fork()) == -1) {
-    // Parent
-    send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
-  } else if (pid == 0) {
-    // Child
-    if (chdir(dir) != 0) {
-      cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
-    } else if (dup2(fd_stdin, 0) == -1) {
-      cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
-    } else if (dup2(fd_stdout, 1) == -1) {
-      cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
-    } else {
-      (void) dup2(fd_stdout, 2);
-      (void) close(fd_stdin);
-      (void) close(fd_stdout);
-
-      // Execute CGI program. No need to lock: new process
-      interp = conn->ctx->config[CGI_INTERPRETER];
-      if (interp == NULL) {
-        (void) execle(prog, prog, NULL, envp);
-        cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
-      } else {
-        (void) execle(interp, interp, prog, NULL, envp);
-        cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
-            strerror(ERRNO));
-      }
-    }
-    exit(EXIT_FAILURE);
-  } else {
-    // Parent. Close stdio descriptors
-    (void) close(fd_stdin);
-    (void) close(fd_stdout);
-  }
-
-  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;
-
-  sent = 0;
-  while (sent < len) {
-
-    /* How many bytes we send in this iteration */
-    k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
-
-    if (ssl != NULL) {
-      n = SSL_write(ssl, buf + sent, k);
-    } else if (fp != NULL) {
-      n = fwrite(buf + sent, 1, k, fp);
-      if (ferror(fp))
-        n = -1;
-    } else {
-      n = send(sock, buf + sent, k, 0);
-    }
-
-    if (n < 0)
-      break;
-
-    sent += n;
-  }
-
-  return sent;
-}
-
-// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
-// Return number of bytes read.
-static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
-  int nread;
-
-  if (ssl != NULL) {
-    nread = SSL_read(ssl, buf, len);
-  } else if (fp != NULL) {
-    nread = fread(buf, 1, (size_t) len, fp);
-    if (ferror(fp))
-      nread = -1;
-  } else {
-    nread = recv(sock, buf, (size_t) len, 0);
-  }
-
-  return nread;
-}
-
-int mg_read(struct mg_connection *conn, void *buf, size_t len) {
-  int n, buffered_len, nread;
-  const char *buffered;
-
-  assert(conn->content_len >= conn->consumed_content);
-  DEBUG_TRACE(("%p %zu %ld %ld", buf, len,
-               (long)conn->content_len, (long)conn->consumed_content));
-  nread = 0;
-  if (strcmp(conn->request_info.request_method, "POST") == 0 &&
-      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 = (int) to_read;
-    }
-
-    // How many bytes of data we have buffered in the request buffer?
-    buffered = conn->buf + conn->request_len;
-    buffered_len = conn->data_len - conn->request_len;
-    assert(buffered_len >= 0);
-
-    // Return buffered data back if we haven't done that yet.
-    if (conn->consumed_content < (int64_t) buffered_len) {
-      buffered_len -= (int) conn->consumed_content;
-      if (len < (size_t) buffered_len) {
-        buffered_len = len;
-      }
-      memcpy(buf, buffered, buffered_len);
-      len -= buffered_len;
-      buf = (char *) buf + buffered_len;
-      conn->consumed_content += buffered_len;
-      nread = buffered_len;
-    }
-
-    // We have returned all buffered data. Read new data from the remote socket.
-    while (len > 0) {
-      n = pull(NULL, conn->client.sock, conn->ssl, (char *) buf, (int) len);
-      if (n <= 0) {
-        break;
-      }
-      buf = (char *) buf + n;
-      conn->consumed_content += n;
-      nread += n;
-      len -= n;
-    }
-  }
-  return nread;
-}
-
-int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
-  return (int) push(NULL, conn->client.sock, conn->ssl,
-      (const char *) buf, (int64_t) len);
-}
-
-int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
-  char buf[BUFSIZ];
-  int len;
-  va_list ap;
-
-  va_start(ap, fmt);
-  len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
-  va_end(ap);
-
-  return mg_write(conn, buf, len);
-}
-
-// URL-decode input buffer into destination buffer.
-// 0-terminate the destination buffer. Return the length of decoded data.
-// form-url-encoded data differs from URI encoding in a way that it
-// uses '+' as character for space, see RFC 1866 section 8.2.1
-// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
-static size_t url_decode(const char *src, size_t src_len, char *dst,
-                         size_t dst_len, int is_form_url_encoded) {
-  size_t i, j;
-  int a, b;
-#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
-
-  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
-    if (src[i] == '%' &&
-        isxdigit(* (unsigned char *) (src + i + 1)) &&
-        isxdigit(* (unsigned char *) (src + i + 2))) {
-      a = tolower(* (unsigned char *) (src + i + 1));
-      b = tolower(* (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 j;
-}
-
-// Scan given buffer and fetch the value of the given variable.
-// It can be specified in query string, or in the POST data.
-// Return NULL if the variable not found, or allocated 0-terminated value.
-// It is caller's responsibility to free the returned value.
-int mg_get_var(const char *buf, size_t buf_len, const char *name,
-               char *dst, size_t dst_len) {
-  const char *p, *e, *s;
-  size_t name_len, len;
-
-  name_len = strlen(name);
-  e = buf + buf_len;
-  len = -1;
-  dst[0] = '\0';
-
-  // buf is "var1=val1&var2=val2...". Find variable first
-  for (p = buf; p != NULL && p + name_len < e; p++) {
-    if ((p == buf || p[-1] == '&') && p[name_len] == '=' &&
-        !mg_strncasecmp(name, p, name_len)) {
-
-      // Point p to variable value
-      p += name_len + 1;
-
-      // Point s to the end of the value
-      s = (const char *) memchr(p, '&', e - p);
-      if (s == NULL) {
-        s = e;
-      }
-      assert(s >= p);
-
-      // Decode variable into destination buffer
-      if ((size_t) (s - p) < dst_len) {
-        len = url_decode(p, s - p, dst, dst_len, 1);
-      }
-      break;
-    }
-  }
-
-  return len;
-}
-
-int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
-                  char *dst, size_t dst_size) {
-  const char *s, *p, *end;
-  int name_len, len = -1;
-
-  dst[0] = '\0';
-  if ((s = mg_get_header(conn, "Cookie")) == NULL) {
-    return 0;
-  }
-
-  name_len = strlen(cookie_name);
-  end = s + strlen(s);
-
-  for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
-    if (s[name_len] == '=') {
-      s += name_len + 1;
-      if ((p = strchr(s, ' ')) == NULL)
-        p = end;
-      if (p[-1] == ';')
-        p--;
-      if (*s == '"' && p[-1] == '"' && p > s + 1) {
-        s++;
-        p--;
-      }
-      if ((size_t) (p - s) < dst_size) {
-        len = (p - s) + 1;
-        mg_strlcpy(dst, s, len);
-      }
-      break;
-    }
-
-  return len;
-}
-
-// Mongoose allows to specify multiple directories to serve,
-// like /var/www,/~bob=/home/bob. That means that root directory depends on URI.
-// This function returns root dir for given URI.
-static int get_document_root(const struct mg_connection *conn,
-                             struct vec *document_root) {
-  const char *root, *uri;
-  int len_of_matched_uri;
-  struct vec uri_vec, path_vec;
-
-  uri = conn->request_info.uri;
-  len_of_matched_uri = 0;
-  root = next_option(conn->ctx->config[DOCUMENT_ROOT], document_root, NULL);
-
-  while ((root = next_option(root, &uri_vec, &path_vec)) != NULL) {
-    if (memcmp(uri, uri_vec.ptr, uri_vec.len) == 0) {
-      *document_root = path_vec;
-      len_of_matched_uri = uri_vec.len;
-      break;
-    }
-  }
-
-  return len_of_matched_uri;
-}
-
-static void convert_uri_to_file_name(struct mg_connection *conn,
-                                     const char *uri, char *buf,
-                                     size_t buf_len) {
-  struct vec vec;
-  int match_len;
-
-  match_len = get_document_root(conn, &vec);
-  mg_snprintf(conn, buf, buf_len, "%.*s%s", vec.len, vec.ptr, uri + match_len);
-
-#ifdef _WIN32
-  change_slashes_to_backslashes(buf);
-#endif /* _WIN32 */
-
-  DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr));
-}
-
-static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
-  return (conn->ssl = SSL_new(conn->ctx->ssl_ctx)) != NULL &&
-    SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
-    func(conn->ssl) == 1;
-}
-
-struct mg_connection *mg_connect(struct mg_connection *conn,
-                                 const char *host, int port, int use_ssl) {
-  struct mg_connection *newconn = NULL;
-  struct sockaddr_in sin;
-  struct hostent *he;
-  int sock;
-
-  if (conn->ctx->ssl_ctx == NULL && use_ssl) {
-    cry(conn, "%s: SSL is not initialized", __func__);
-  } else if ((he = gethostbyname(host)) == NULL) {
-    cry(conn, "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO));
-  } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
-    cry(conn, "%s: socket: %s", __func__, strerror(ERRNO));
-  } else {
-    sin.sin_family = AF_INET;
-    sin.sin_port = htons((uint16_t) port);
-    sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
-    if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
-      cry(conn, "%s: connect(%s:%d): %s", __func__, host, port,
-          strerror(ERRNO));
-      closesocket(sock);
-    } else if ((newconn = calloc(1, sizeof(*newconn))) == NULL) {
-      cry(conn, "%s: calloc: %s", __func__, strerror(ERRNO));
-      closesocket(sock);
-    } else {
-      newconn->client.sock = sock;
-      newconn->client.rsa.u.sin = sin;
-      if (use_ssl) {
-        sslize(newconn, SSL_connect);
-      }
-    }
-  }
-
-  return newconn;
-}
-
-// Check whether full request is buffered. Return:
-//   -1  if request is malformed
-//    0  if request is not yet fully buffered
-//   >0  actual request length, including last \r\n\r\n
-static int get_request_len(const char *buf, int buflen) {
-  const char *s, *e;
-  int len = 0;
-
-  DEBUG_TRACE(("buf: %p, len: %d", buf, buflen));
-  for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
-    // Control characters are not allowed but >=128 is.
-    if (!isprint(* (unsigned char *) s) && *s != '\r' &&
-        *s != '\n' && * (unsigned char *) s < 128) {
-      len = -1;
-    } else if (s[0] == '\n' && s[1] == '\n') {
-      len = (int) (s - buf) + 2;
-    } else if (s[0] == '\n' && &s[1] < e &&
-        s[1] == '\r' && s[2] == '\n') {
-      len = (int) (s - buf) + 3;
-    }
-
-  return len;
-}
-
-// Convert month to the month number. Return -1 on error, or month number
-static int month_number_to_month_name(const char *s) {
-  size_t i;
-
-  for (i = 0; i < ARRAY_SIZE(month_names); i++)
-    if (!strcmp(s, month_names[i]))
-      return (int) i;
-
-  return -1;
-}
-
-// Parse date-time string, and return the corresponding time_t value
-static time_t parse_date_string(const char *s) {
-  time_t current_time;
-  struct tm tm, *tmp;
-  char mon[32];
-  int sec, min, hour, mday, month, year;
-
-  (void) memset(&tm, 0, sizeof(tm));
-  sec = min = hour = mday = month = year = 0;
-
-  if (((sscanf(s, "%d/%3s/%d %d:%d:%d",
-            &mday, mon, &year, &hour, &min, &sec) == 6) ||
-        (sscanf(s, "%d %3s %d %d:%d:%d",
-                &mday, mon, &year, &hour, &min, &sec) == 6) ||
-        (sscanf(s, "%*3s, %d %3s %d %d:%d:%d",
-                &mday, mon, &year, &hour, &min, &sec) == 6) ||
-        (sscanf(s, "%d-%3s-%d %d:%d:%d",
-                &mday, mon, &year, &hour, &min, &sec) == 6)) &&
-      (month = month_number_to_month_name(mon)) != -1) {
-    tm.tm_mday = mday;
-    tm.tm_mon = month;
-    tm.tm_year = year;
-    tm.tm_hour = hour;
-    tm.tm_min = min;
-    tm.tm_sec = sec;
-  }
-
-  if (tm.tm_year > 1900) {
-    tm.tm_year -= 1900;
-  } else if (tm.tm_year < 70) {
-    tm.tm_year += 100;
-  }
-
-  // Set Daylight Saving Time field
-  current_time = time(NULL);
-  tmp = localtime(&current_time);
-  tm.tm_isdst = tmp->tm_isdst;
-
-  return mktime(&tm);
-}
-
-// Protect against directory disclosure attack by removing '..',
-// excessive '/' and '\' characters
-static void remove_double_dots_and_double_slashes(char *s) {
-  char *p = s;
-
-  while (*s != '\0') {
-    *p++ = *s++;
-    if (s[-1] == '/' || s[-1] == '\\') {
-      // Skip all following slashes and backslashes
-      while (*s == '/' || *s == '\\') {
-        s++;
-      }
-
-      // Skip all double-dots
-      while (*s == '.' && s[1] == '.') {
-        s += 2;
-      }
-    }
-  }
-  *p = '\0';
-}
-
-static const struct {
-  const char *extension;
-  size_t ext_len;
-  const char *mime_type;
-  size_t mime_type_len;
-} builtin_mime_types[] = {
-  {".html", 5, "text/html",   9},
-  {".htm", 4, "text/html",   9},
-  {".shtm", 5, "text/html",   9},
-  {".shtml", 6, "text/html",   9},
-  {".css", 4, "text/css",   8},
-  {".js",  3, "application/x-javascript", 24},
-  {".ico", 4, "image/x-icon",   12},
-  {".gif", 4, "image/gif",   9},
-  {".jpg", 4, "image/jpeg",   10},
-  {".jpeg", 5, "image/jpeg",   10},
-  {".png", 4, "image/png",   9},
-  {".svg", 4, "image/svg+xml",  13},
-  {".torrent", 8, "application/x-bittorrent", 24},
-  {".wav", 4, "audio/x-wav",   11},
-  {".mp3", 4, "audio/x-mp3",   11},
-  {".mid", 4, "audio/mid",   9},
-  {".m3u", 4, "audio/x-mpegurl",  15},
-  {".ram", 4, "audio/x-pn-realaudio",  20},
-  {".xml", 4, "text/xml",   8},
-  {".xslt", 5, "application/xml",  15},
-  {".ra",  3, "audio/x-pn-realaudio",  20},
-  {".doc", 4, "application/msword",  19},
-  {".exe", 4, "application/octet-stream", 24},
-  {".zip", 4, "application/x-zip-compressed", 28},
-  {".xls", 4, "application/excel",  17},
-  {".tgz", 4, "application/x-tar-gz",  20},
-  {".tar", 4, "application/x-tar",  17},
-  {".gz",  3, "application/x-gunzip",  20},
-  {".arj", 4, "application/x-arj-compressed", 28},
-  {".rar", 4, "application/x-arj-compressed", 28},
-  {".rtf", 4, "application/rtf",  15},
-  {".pdf", 4, "application/pdf",  15},
-  {".swf", 4, "application/x-shockwave-flash",29},
-  {".mpg", 4, "video/mpeg",   10},
-  {".mpeg", 5, "video/mpeg",   10},
-  {".asf", 4, "video/x-ms-asf",  14},
-  {".avi", 4, "video/x-msvideo",  15},
-  {".bmp", 4, "image/bmp",   9},
-  {NULL,  0, NULL,    0}
-};
-
-// Look at the "path" extension and figure what mime type it has.
-// Store mime type in the vector.
-static void get_mime_type(struct mg_context *ctx, const char *path,
-                          struct vec *vec) {
-  struct vec ext_vec, mime_vec;
-  const char *list, *ext;
-  size_t i, path_len;
-
-  path_len = strlen(path);
-
-  // Scan user-defined mime types first, in case user wants to
-  // override default mime types.
-  list = ctx->config[EXTRA_MIME_TYPES];
-  while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
-    // ext now points to the path suffix
-    ext = path + path_len - ext_vec.len;
-    if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
-      *vec = mime_vec;
-      return;
-    }
-  }
-
-  // Now scan built-in mime types
-  for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
-    ext = path + (path_len - builtin_mime_types[i].ext_len);
-    if (path_len > builtin_mime_types[i].ext_len &&
-        mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
-      vec->ptr = builtin_mime_types[i].mime_type;
-      vec->len = builtin_mime_types[i].mime_type_len;
-      return;
-    }
-  }
-
-  // Nothing found. Fall back to "text/plain"
-  vec->ptr = "text/plain";
-  vec->len = 10;
-}
-
-#ifndef HAVE_MD5
-typedef struct MD5Context {
-  uint32_t buf[4];
-  uint32_t bits[2];
-  unsigned char in[64];
-} MD5_CTX;
-
-#if __BYTE_ORDER == 1234
-#define byteReverse(buf, len) // Do nothing
-#else
-static void byteReverse(unsigned char *buf, unsigned longs) {
-  uint32_t t;
-  do {
-    t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-      ((unsigned) buf[1] << 8 | buf[0]);
-    *(uint32_t *) buf = t;
-    buf += 4;
-  } while (--longs);
-}
-#endif
-
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1(z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
-
-#define MD5STEP(f, w, x, y, z, data, s) \
-  ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
-
-// Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
-// initialization constants.
-static void MD5Init(MD5_CTX *ctx) {
-  ctx->buf[0] = 0x67452301;
-  ctx->buf[1] = 0xefcdab89;
-  ctx->buf[2] = 0x98badcfe;
-  ctx->buf[3] = 0x10325476;
-
-  ctx->bits[0] = 0;
-  ctx->bits[1] = 0;
-}
-
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
-  register uint32_t a, b, c, d;
-
-  a = buf[0];
-  b = buf[1];
-  c = buf[2];
-  d = buf[3];
-
-  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
-  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
-  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
-  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
-  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
-  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
-  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
-  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
-  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
-  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
-  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
-  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
-  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
-  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
-  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
-  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
-  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
-  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
-  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
-  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
-  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
-  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
-  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
-  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
-  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
-  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
-  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
-  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
-  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
-  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
-  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
-  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
-  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
-  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
-  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
-
-  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
-  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
-  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
-  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
-  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
-  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
-  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
-  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
-  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
-  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
-  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
-
-  buf[0] += a;
-  buf[1] += b;
-  buf[2] += c;
-  buf[3] += d;
-}
-
-static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
-  uint32_t t;
-
-  t = ctx->bits[0];
-  if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
-    ctx->bits[1]++;
-  ctx->bits[1] += len >> 29;
-
-  t = (t >> 3) & 0x3f;
-
-  if (t) {
-    unsigned char *p = (unsigned char *) ctx->in + t;
-
-    t = 64 - t;
-    if (len < t) {
-      memcpy(p, buf, len);
-      return;
-    }
-    memcpy(p, buf, t);
-    byteReverse(ctx->in, 16);
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-    buf += t;
-    len -= t;
-  }
-
-  while (len >= 64) {
-    memcpy(ctx->in, buf, 64);
-    byteReverse(ctx->in, 16);
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-    buf += 64;
-    len -= 64;
-  }
-
-  memcpy(ctx->in, buf, len);
-}
-
-static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
-  unsigned count;
-  unsigned char *p;
-
-  count = (ctx->bits[0] >> 3) & 0x3F;
-
-  p = ctx->in + count;
-  *p++ = 0x80;
-  count = 64 - 1 - count;
-  if (count < 8) {
-    memset(p, 0, count);
-    byteReverse(ctx->in, 16);
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-    memset(ctx->in, 0, 56);
-  } else {
-    memset(p, 0, count - 8);
-  }
-  byteReverse(ctx->in, 14);
-
-  ((uint32_t *) ctx->in)[14] = ctx->bits[0];
-  ((uint32_t *) ctx->in)[15] = ctx->bits[1];
-
-  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
-  byteReverse((unsigned char *) ctx->buf, 4);
-  memcpy(digest, ctx->buf, 16);
-  memset((char *) ctx, 0, sizeof(*ctx));
-}
-#endif // !HAVE_MD5
-
-// Stringify binary data. Output buffer must be twice as big as input,
-// because each byte takes 2 bytes in string representation
-static void bin2str(char *to, const unsigned char *p, size_t len) {
-  static const char *hex = "0123456789abcdef";
-
-  for (; len--; p++) {
-    *to++ = hex[p[0] >> 4];
-    *to++ = hex[p[0] & 0x0f];
-  }
-  *to = '\0';
-}
-
-// Return stringified MD5 hash for list of vectors. Buffer must be 33 bytes.
-void mg_md5(char *buf, ...) {
-  unsigned char hash[16];
-  const char *p;
-  va_list ap;
-  MD5_CTX ctx;
-
-  MD5Init(&ctx);
-
-  va_start(ap, buf);
-  while ((p = va_arg(ap, const char *)) != NULL) {
-    MD5Update(&ctx, (unsigned char *) p, (int) strlen(p));
-  }
-  va_end(ap);
-
-  MD5Final(hash, &ctx);
-  bin2str(buf, hash, sizeof(hash));
-}
-
-// Check the user's password, return 1 if OK
-static int check_password(const char *method, const char *ha1, const char *uri,
-                          const char *nonce, const char *nc, const char *cnonce,
-                          const char *qop, const char *response) {
-  char ha2[32 + 1], expected_response[32 + 1];
-
-  // NOTE(lsm): due to a bug in MSIE, we do not compare the URI
-  // TODO(lsm): check for authentication timeout
-  if (// strcmp(dig->uri, c->ouri) != 0 ||
-      strlen(response) != 32
-      // || now - strtoul(dig->nonce, NULL, 10) > 3600
-      ) {
-    return 0;
-  }
-
-  mg_md5(ha2, method, ":", uri, NULL);
-  mg_md5(expected_response, ha1, ":", nonce, ":", nc,
-      ":", cnonce, ":", qop, ":", ha2, NULL);
-
-  return mg_strcasecmp(response, expected_response) == 0;
-}
-
-// Use the global passwords file, if specified by auth_gpass option,
-// or search for .htpasswd in the requested directory.
-static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
-  struct mg_context *ctx = conn->ctx;
-  char name[PATH_MAX];
-  const char *p, *e;
-  struct mgstat st;
-  FILE *fp;
-
-  if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) {
-    // Use global passwords file
-    fp =  mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r");
-    if (fp == NULL)
-      cry(fc(ctx), "fopen(%s): %s",
-          ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO));
-  } else if (!mg_stat(path, &st) && st.is_directory) {
-    (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s",
-        path, DIRSEP, PASSWORDS_FILE_NAME);
-    fp = mg_fopen(name, "r");
-  } else {
-     // Try to find .htpasswd in requested directory.
-    for (p = path, e = p + strlen(p) - 1; e > p; e--)
-      if (IS_DIRSEP_CHAR(*e))
-        break;
-    (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
-        (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME);
-    fp = mg_fopen(name, "r");
-  }
-
-  return fp;
-}
-
-// Parsed Authorization header
-struct ah {
-  char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
-};
-
-static int parse_auth_header(struct mg_connection *conn, char *buf,
-                             size_t buf_size, struct ah *ah) {
-  char *name, *value, *s;
-  const char *auth_header;
-
-  if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
-      mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
-    return 0;
-  }
-
-  // Make modifiable copy of the auth header
-  (void) mg_strlcpy(buf, auth_header + 7, buf_size);
-
-  s = buf;
-  (void) memset(ah, 0, sizeof(*ah));
-
-  // Gobble initial spaces
-  while (isspace(* (unsigned char *) s)) {
-    s++;
-  }
-
-  // Parse authorization header
-  for (;;) {
-    name = skip(&s, "=");
-    value = skip(&s, " ");
-
-    // Handle commas: Digest username="a", realm="b", ...
-    if (value[strlen(value) - 1] == ',') {
-      value[strlen(value) - 1] = '\0';
-    }
-
-    // Trim double quotes around values
-    if (*value == '"') {
-      value++;
-      value[strlen(value) - 1] = '\0';
-    } else if (*value == '\0') {
-      break;
-    }
-
-    if (!strcmp(name, "username")) {
-      ah->user = value;
-    } else if (!strcmp(name, "cnonce")) {
-      ah->cnonce = value;
-    } else if (!strcmp(name, "response")) {
-      ah->response = value;
-    } else if (!strcmp(name, "uri")) {
-      ah->uri = value;
-    } else if (!strcmp(name, "qop")) {
-      ah->qop = value;
-    } else if (!strcmp(name, "nc")) {
-      ah->nc = value;
-    } else if (!strcmp(name, "nonce")) {
-      ah->nonce = value;
-    }
-  }
-
-  // CGI needs it as REMOTE_USER
-  if (ah->user != NULL) {
-    conn->request_info.remote_user = mg_strdup(ah->user);
-  }
-
-  return 1;
-}
-
-// Authorize against the opened passwords file. Return 1 if authorized.
-static int authorize(struct mg_connection *conn, FILE *fp) {
-  struct ah ah;
-  char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ];
-
-  if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
-    return 0;
-  }
-
-  // Loop over passwords file
-  while (fgets(line, sizeof(line), fp) != NULL) {
-    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
-      continue;
-    }
-
-    if (!strcmp(ah.user, f_user) &&
-        !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
-      return check_password(
-            conn->request_info.request_method,
-            ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop,
-            ah.response);
-  }
-
-  return 0;
-}
-
-// Return 1 if request is authorised, 0 otherwise.
-static int check_authorization(struct mg_connection *conn, const char *path) {
-  FILE *fp;
-  char fname[PATH_MAX];
-  struct vec uri_vec, filename_vec;
-  const char *list;
-  int authorized;
-
-  fp = NULL;
-  authorized = 1;
-
-  list = conn->ctx->config[PROTECT_URI];
-  while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
-    if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
-      (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s",
-          filename_vec.len, filename_vec.ptr);
-      if ((fp = mg_fopen(fname, "r")) == NULL) {
-        cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
-      }
-      break;
-    }
-  }
-
-  if (fp == NULL) {
-    fp = open_auth_file(conn, path);
-  }
-
-  if (fp != NULL) {
-    authorized = authorize(conn, fp);
-    (void) fclose(fp);
-  }
-
-  return authorized;
-}
-
-static void send_authorization_request(struct mg_connection *conn) {
-  conn->request_info.status_code = 401;
-  (void) mg_printf(conn,
-      "HTTP/1.1 401 Unauthorized\r\n"
-      "WWW-Authenticate: Digest qop=\"auth\", "
-      "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
-      conn->ctx->config[AUTHENTICATION_DOMAIN],
-      (unsigned long) time(NULL));
-}
-
-static int is_authorized_for_put(struct mg_connection *conn) {
-  FILE *fp;
-  int ret = 0;
-
-  fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL :
-    mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r");
-
-  if (fp != NULL) {
-    ret = authorize(conn, fp);
-    (void) fclose(fp);
-  }
-
-  return ret;
-}
-
-int mg_modify_passwords_file(struct mg_context *ctx, const char *fname,
-                             const char *user, const char *pass) {
-  int found;
-  char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
-  const char *domain;
-  FILE *fp, *fp2;
-
-  found = 0;
-  fp = fp2 = NULL;
-  domain = ctx->config[AUTHENTICATION_DOMAIN];
-
-  // Regard empty password as no password - remove user record.
-  if (pass[0] == '\0') {
-    pass = NULL;
-  }
-
-  (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
-
-  // Create the file if does not exist
-  if ((fp = mg_fopen(fname, "a+")) != NULL) {
-    (void) fclose(fp);
-  }
-
-  // Open the given file and temporary file
-  if ((fp = mg_fopen(fname, "r")) == NULL) {
-    cry(fc(ctx), "Cannot open %s: %s", fname, strerror(errno));
-    return 0;
-  } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) {
-    cry(fc(ctx), "Cannot open %s: %s", tmp, strerror(errno));
-    fclose(fp);
-    return 0;
-  }
-
-  // Copy the stuff to temporary file
-  while (fgets(line, sizeof(line), fp) != NULL) {
-    if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
-      continue;
-    }
-
-    if (!strcmp(u, user) && !strcmp(d, domain)) {
-      found++;
-      if (pass != NULL) {
-        mg_md5(ha1, user, ":", domain, ":", pass, NULL);
-        fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
-      }
-    } else {
-      (void) fprintf(fp2, "%s", line);
-    }
-  }
-
-  // If new user, just add it
-  if (!found && pass != NULL) {
-    mg_md5(ha1, user, ":", domain, ":", pass, NULL);
-    (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
-  }
-
-  // Close files
-  (void) fclose(fp);
-  (void) fclose(fp2);
-
-  // Put the temp file in place of real file
-  (void) mg_remove(fname);
-  (void) mg_rename(tmp, fname);
-
-  return 1;
-}
-
-struct de {
-  struct mg_connection *conn;
-  char *file_name;
-  struct mgstat st;
-};
-
-static void url_encode(const char *src, char *dst, size_t dst_len) {
-  static const char *dont_escape = "._-$,;~()";
-  static const char *hex = "0123456789abcdef";
-  const char *end = dst + dst_len - 1;
-
-  for (; *src != '\0' && dst < end; src++, dst++) {
-    if (isalnum(*(unsigned char *) src) ||
-        strchr(dont_escape, * (unsigned char *) src) != NULL) {
-      *dst = *src;
-    } else if (dst + 2 < end) {
-      dst[0] = '%';
-      dst[1] = hex[(* (unsigned char *) src) >> 4];
-      dst[2] = hex[(* (unsigned char *) src) & 0xf];
-      dst += 2;
-    }
-  }
-
-  *dst = '\0';
-}
-
-static void print_dir_entry(struct de *de) {
-  char size[64], mod[64], href[PATH_MAX];
-
-  if (de->st.is_directory) {
-    (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
-  } else {
-     // We use (signed) cast below because MSVC 6 compiler cannot
-     // convert unsigned __int64 to double. Sigh.
-    if (de->st.size < 1024) {
-      (void) mg_snprintf(de->conn, size, sizeof(size),
-          "%lu", (unsigned long) de->st.size);
-    } else if (de->st.size < 1024 * 1024) {
-      (void) mg_snprintf(de->conn, size, sizeof(size),
-          "%.1fk", (double) de->st.size / 1024.0);
-    } else if (de->st.size < 1024 * 1024 * 1024) {
-      (void) mg_snprintf(de->conn, size, sizeof(size),
-          "%.1fM", (double) de->st.size / 1048576);
-    } else {
-      (void) mg_snprintf(de->conn, size, sizeof(size),
-          "%.1fG", (double) de->st.size / 1073741824);
-    }
-  }
-  (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime));
-  url_encode(de->file_name, href, sizeof(href));
-  de->conn->num_bytes_sent += mg_printf(de->conn,
-      "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
-      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
-      de->conn->request_info.uri, href, de->st.is_directory ? "/" : "",
-      de->file_name, de->st.is_directory ? "/" : "", mod, size);
-}
-
-// This function is called from send_directory() and used for
-// sorting directory entries by size, or name, or modification time.
-// On windows, __cdecl specification is needed in case if project is built
-// with __stdcall convention. qsort always requires __cdels callback.
-static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
-  const struct de *a = (struct de *) p1, *b = (struct de *) p2;
-  const char *query_string = a->conn->request_info.query_string;
-  int cmp_result = 0;
-
-  if (query_string == NULL) {
-    query_string = "na";
-  }
-
-  if (a->st.is_directory && !b->st.is_directory) {
-    return -1;  // Always put directories on top
-  } else if (!a->st.is_directory && b->st.is_directory) {
-    return 1;   // Always put directories on top
-  } else if (*query_string == 'n') {
-    cmp_result = strcmp(a->file_name, b->file_name);
-  } else if (*query_string == 's') {
-    cmp_result = a->st.size == b->st.size ? 0 :
-      a->st.size > b->st.size ? 1 : -1;
-  } else if (*query_string == 'd') {
-    cmp_result = a->st.mtime == b->st.mtime ? 0 :
-      a->st.mtime > b->st.mtime ? 1 : -1;
-  }
-
-  return query_string[1] == 'd' ? -cmp_result : cmp_result;
-}
-
-static void handle_directory_request(struct mg_connection *conn,
-                                     const char *dir) {
-  struct dirent *dp;
-  DIR *dirp;
-  struct de *entries = NULL;
-  char path[PATH_MAX];
-  int i, sort_direction, num_entries = 0, arr_size = 128;
-
-  if ((dirp = opendir(dir)) == NULL) {
-    send_http_error(conn, 500, "Cannot open directory",
-        "Error: opendir(%s): %s", path, strerror(ERRNO));
-    return;
-  }
-
-  (void) mg_printf(conn, "%s",
-      "HTTP/1.1 200 OK\r\n"
-      "Connection: close\r\n"
-      "Content-Type: text/html; charset=utf-8\r\n\r\n");
-
-  sort_direction = conn->request_info.query_string != NULL &&
-    conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
-
-  while ((dp = readdir(dirp)) != NULL) {
-
-    // Do not show current dir and passwords file
-    if (!strcmp(dp->d_name, ".") ||
-        !strcmp(dp->d_name, "..") ||
-        !strcmp(dp->d_name, PASSWORDS_FILE_NAME))
-      continue;
-
-    if (entries == NULL || num_entries >= arr_size) {
-      arr_size *= 2;
-      entries = (struct de *) realloc(entries,
-          arr_size * sizeof(entries[0]));
-    }
-
-    if (entries == NULL) {
-      send_http_error(conn, 500, "Cannot open directory",
-          "%s", "Error: cannot allocate memory");
-      closedir(dirp);
-      return;
-    }
-
-    mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name);
-
-    // If we don't memset stat structure to zero, mtime will have
-    // garbage and strftime() will segfault later on in
-    // print_dir_entry(). memset is required only if mg_stat()
-    // fails. For more details, see
-    // http://code.google.com/p/mongoose/issues/detail?id=79
-    if (mg_stat(path, &entries[num_entries].st) != 0) {
-      memset(&entries[num_entries].st, 0, sizeof(entries[num_entries].st));
-    }
-
-    entries[num_entries].conn = conn;
-    entries[num_entries].file_name = mg_strdup(dp->d_name);
-    num_entries++;
-  }
-  (void) closedir(dirp);
-
-  conn->num_bytes_sent += mg_printf(conn,
-      "<html><head><title>Index of %s</title>"
-      "<style>th {text-align: left;}</style></head>"
-      "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
-      "<tr><th><a href=\"?n%c\">Name</a></th>"
-      "<th><a href=\"?d%c\">Modified</a></th>"
-      "<th><a href=\"?s%c\">Size</a></th></tr>"
-      "<tr><td colspan=\"3\"><hr></td></tr>",
-      conn->request_info.uri, conn->request_info.uri,
-      sort_direction, sort_direction, sort_direction);
-
-  // Print first entry - link to a parent directory
-  conn->num_bytes_sent += mg_printf(conn,
-      "<tr><td><a href=\"%s%s\">%s</a></td>"
-      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
-      conn->request_info.uri, "..", "Parent directory", "-", "-");
-
-  // Sort and print directory entries
-  if(entries!=NULL){
-	  qsort(entries, num_entries, sizeof(entries[0]), compare_dir_entries);
-	  for (i = 0; i < num_entries; i++) {
-		  print_dir_entry(&entries[i]);
-		  free(entries[i].file_name);
-	  }
-	  free(entries);
-  }
-
-  conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
-  conn->request_info.status_code = 200;
-}
-
-// Send len bytes from the opened file to the client.
-static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
-  char buf[BUFSIZ];
-  int to_read, num_read, num_written;
-
-  while (len > 0) {
-    // Calculate how much to read from the file in the buffer
-    to_read = sizeof(buf);
-    if ((int64_t) to_read > len)
-      to_read = (int) len;
-
-    // Read from file, exit the loop on error
-    if ((num_read = fread(buf, 1, to_read, fp)) == 0)
-      break;
-
-    // Send read bytes to the client, exit the loop on error
-    if ((num_written = mg_write(conn, buf, num_read)) != num_read)
-      break;
-
-    // Both read and were successful, adjust counters
-    conn->num_bytes_sent += num_written;
-    len -= num_written;
-  }
-}
-
-static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
-  return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
-}
-
-static void handle_file_request(struct mg_connection *conn, const char *path,
-                                struct mgstat *stp) {
-  char date[64], lm[64], etag[64], range[64];
-  const char *fmt = "%a, %d %b %Y %H:%M:%S %Z", *msg = "OK", *hdr;
-  time_t curtime = time(NULL);
-  int64_t cl, r1, r2;
-  struct vec mime_vec;
-  FILE *fp;
-  int n;
-
-  get_mime_type(conn->ctx, path, &mime_vec);
-  cl = stp->size;
-  conn->request_info.status_code = 200;
-  range[0] = '\0';
-
-  if ((fp = mg_fopen(path, "rb")) == NULL) {
-    send_http_error(conn, 500, http_500_error,
-        "fopen(%s): %s", path, strerror(ERRNO));
-    return;
-  }
-  set_close_on_exec(fileno(fp));
-
-  // If Range: header specified, act accordingly
-  r1 = r2 = 0;
-  hdr = mg_get_header(conn, "Range");
-  if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) {
-    conn->request_info.status_code = 206;
-    (void) fseeko(fp, (off_t) r1, SEEK_SET);
-    cl = n == 2 ? r2 - r1 + 1: cl - r1;
-    (void) mg_snprintf(conn, range, sizeof(range),
-        "Content-Range: bytes "
-        "%" INT64_FMT "-%"
-        INT64_FMT "/%" INT64_FMT "\r\n",
-        r1, r1 + cl - 1, stp->size);
-    msg = "Partial Content";
-  }
-
-  // Prepare Etag, Date, Last-Modified headers
-  (void) strftime(date, sizeof(date), fmt, localtime(&curtime));
-  (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->mtime));
-  (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx",
-      (unsigned long) stp->mtime, (unsigned long) stp->size);
-
-  (void) mg_printf(conn,
-      "HTTP/1.1 %d %s\r\n"
-      "Date: %s\r\n"
-      "Last-Modified: %s\r\n"
-      "Etag: \"%s\"\r\n"
-      "Content-Type: %.*s\r\n"
-      "Content-Length: %" INT64_FMT "\r\n"
-      "Connection: %s\r\n"
-      "Accept-Ranges: bytes\r\n"
-      "%s\r\n",
-      conn->request_info.status_code, msg, date, lm, etag,
-      mime_vec.len, mime_vec.ptr, cl, suggest_connection_header(conn), range);
-
-  if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
-    send_file_data(conn, fp, cl);
-  }
-  (void) fclose(fp);
-}
-
-// Parse HTTP headers from the given buffer, advance buffer to the point
-// where parsing stopped.
-static void parse_http_headers(char **buf, struct mg_request_info *ri) {
-  int i;
-
-  for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
-    ri->http_headers[i].name = skip(buf, ": ");
-    ri->http_headers[i].value = skip(buf, "\r\n");
-    if (ri->http_headers[i].name[0] == '\0')
-      break;
-    ri->num_headers = i + 1;
-  }
-}
-
-static int is_valid_http_method(const char *method) {
-  return !strcmp(method, "GET") || !strcmp(method, "POST") ||
-    !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
-    !strcmp(method, "PUT") || !strcmp(method, "DELETE");
-}
-
-// Parse HTTP request, fill in mg_request_info structure.
-static int parse_http_request(char *buf, struct mg_request_info *ri) {
-  int status = 0;
-
-  // RFC says that all initial whitespaces should be ingored
-  while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
-    buf++;
-  }
-
-  ri->request_method = skip(&buf, " ");
-  ri->uri = skip(&buf, " ");
-  ri->http_version = skip(&buf, "\r\n");
-
-  if (is_valid_http_method(ri->request_method) &&
-      strncmp(ri->http_version, "HTTP/", 5) == 0) {
-    ri->http_version += 5;   /* Skip "HTTP/" */
-    parse_http_headers(&buf, ri);
-    status = 1;
-  }
-
-  return status;
-}
-
-// Keep reading the input (either opened file descriptor fd, or socket sock,
-// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
-// buffer (which marks the end of HTTP request). Buffer buf may already
-// have some data. The length of the data is stored in nread.
-// Upon every read operation, increase nread by the number of bytes read.
-static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz,
-                        int *nread) {
-  int n, request_len;
-
-  request_len = 0;
-  while (*nread < bufsiz && request_len == 0) {
-    n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread);
-    if (n <= 0) {
-      break;
-    } else {
-      *nread += n;
-      request_len = get_request_len(buf, *nread);
-    }
-  }
-
-  return request_len;
-}
-
-// For given directory path, substitute it to valid index file.
-// Return 0 if index file has been found, -1 if not found.
-// If the file is found, it's stats is returned in stp.
-static int substitute_index_file(struct mg_connection *conn, char *path,
-                                 size_t path_len, struct mgstat *stp) {
-  const char *list = conn->ctx->config[INDEX_FILES];
-  struct mgstat st;
-  struct vec filename_vec;
-  size_t n = strlen(path);
-  int found = 0;
-
-  // The 'path' given to us points to the directory. Remove all trailing
-  // directory separator characters from the end of the path, and
-  // then append single directory separator character.
-  while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) {
-    n--;
-  }
-  path[n] = DIRSEP;
-
-  // Traverse index files list. For each entry, append it to the given
-  // path and see if the file exists. If it exists, break the loop
-  while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
-
-    // Ignore too long entries that may overflow path buffer
-    if (filename_vec.len > path_len - n)
-      continue;
-
-    // Prepare full path to the index file
-    (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
-
-    // Does it exist?
-    if (mg_stat(path, &st) == 0) {
-      // Yes it does, break the loop
-      *stp = st;
-      found = 1;
-      break;
-    }
-  }
-
-  // If no index file exists, restore directory path
-  if (!found) {
-    path[n] = '\0';
-  }
-
-  return found;
-}
-
-// Return True if we should reply 304 Not Modified.
-static int is_not_modified(const struct mg_connection *conn,
-                           const struct mgstat *stp) {
-  const char *ims = mg_get_header(conn, "If-Modified-Since");
-  return ims != NULL && stp->mtime <= parse_date_string(ims);
-}
-
-static int forward_body_data(struct mg_connection *conn, FILE *fp,
-                             SOCKET sock, SSL *ssl) {
-  const char *expect, *buffered;
-  char buf[BUFSIZ];
-  int to_read, nread, buffered_len, success = 0;
-
-  expect = mg_get_header(conn, "Expect");
-  assert(fp != NULL);
-
-  if (conn->content_len == -1) {
-    send_http_error(conn, 411, "Length Required", "");
-  } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
-    send_http_error(conn, 417, "Expectation Failed", "");
-  } else {
-    if (expect != NULL) {
-      (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
-    }
-
-    buffered = conn->buf + conn->request_len;
-    buffered_len = conn->data_len - conn->request_len;
-    assert(buffered_len >= 0);
-    assert(conn->consumed_content == 0);
-
-    if (buffered_len > 0) {
-      if ((int64_t) buffered_len > conn->content_len) {
-        buffered_len = (int) conn->content_len;
-      }
-      push(fp, sock, ssl, buffered, (int64_t) buffered_len);
-      conn->consumed_content += buffered_len;
-    }
-
-    while (conn->consumed_content < conn->content_len) {
-      to_read = sizeof(buf);
-      if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
-        to_read = (int) (conn->content_len - conn->consumed_content);
-      }
-      nread = pull(NULL, conn->client.sock, conn->ssl, buf, to_read);
-      if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
-        break;
-      }
-      conn->consumed_content += nread;
-    }
-
-    if (conn->consumed_content == conn->content_len) {
-      success = 1;
-    }
-
-    // Each error code path in this function must send an error
-    if (!success) {
-      send_http_error(conn, 577, http_500_error, "");
-    }
-  }
-
-  return success;
-}
-
-#if !defined(NO_CGI)
-// This structure helps to create an environment for the spawned CGI program.
-// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
-// last element must be NULL.
-// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
-// strings must reside in a contiguous buffer. The end of the buffer is
-// marked by two '\0' characters.
-// We satisfy both worlds: we create an envp array (which is vars), all
-// entries are actually pointers inside buf.
-struct cgi_env_block {
-  struct mg_connection *conn;
-  char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer
-  int len; // Space taken
-  char *vars[MAX_CGI_ENVIR_VARS]; // char **envp
-  int nvars; // Number of variables
-};
-
-// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
-// pointer into the vars array.
-static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
-  int n, space;
-  char *added;
-  va_list ap;
-
-  // Calculate how much space is left in the buffer
-  space = sizeof(block->buf) - block->len - 2;
-  assert(space >= 0);
-
-  // Make a pointer to the free space int the buffer
-  added = block->buf + block->len;
-
-  // Copy VARIABLE=VALUE\0 string into the free space
-  va_start(ap, fmt);
-  n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
-  va_end(ap);
-
-  // Make sure we do not overflow buffer and the envp array
-  if (n > 0 && n < space &&
-      block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
-    // Append a pointer to the added string into the envp array
-    block->vars[block->nvars++] = block->buf + block->len;
-    // Bump up used length counter. Include \0 terminator
-    block->len += n + 1;
-  }
-
-  return added;
-}
-
-static void prepare_cgi_environment(struct mg_connection *conn,
-                                    const char *prog,
-                                    struct cgi_env_block *blk) {
-  const char *s, *slash;
-  struct vec var_vec, root;
-  char *p;
-  int  i;
-
-  blk->len = blk->nvars = 0;
-  blk->conn = conn;
-
-  get_document_root(conn, &root);
-
-  addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
-  addenv(blk, "SERVER_ROOT=%.*s", root.len, root.ptr);
-  addenv(blk, "DOCUMENT_ROOT=%.*s", root.len, root.ptr);
-
-  // Prepare the environment block
-  addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
-  addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
-  addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
-  addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.u.sin.sin_port));
-  addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
-  addenv(blk, "REMOTE_ADDR=%s",
-      inet_ntoa(conn->client.rsa.u.sin.sin_addr));
-  addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
-  addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
-
-  // SCRIPT_NAME
-  assert(conn->request_info.uri[0] == '/');
-  slash = strrchr(conn->request_info.uri, '/');
-  if ((s = strrchr(prog, '/')) == NULL)
-    s = prog;
-  addenv(blk, "SCRIPT_NAME=%.*s%s", slash - conn->request_info.uri,
-         conn->request_info.uri, s);
-
-  addenv(blk, "SCRIPT_FILENAME=%s", prog);
-  addenv(blk, "PATH_TRANSLATED=%s", prog);
-  addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
-
-  if ((s = mg_get_header(conn, "Content-Type")) != NULL)
-    addenv(blk, "CONTENT_TYPE=%s", s);
-
-  if (conn->request_info.query_string != NULL)
-    addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
-
-  if ((s = mg_get_header(conn, "Content-Length")) != NULL)
-    addenv(blk, "CONTENT_LENGTH=%s", s);
-
-  if ((s = getenv("PATH")) != NULL)
-    addenv(blk, "PATH=%s", s);
-
-#if defined(_WIN32)
-  if ((s = getenv("COMSPEC")) != NULL)
-    addenv(blk, "COMSPEC=%s", s);
-  if ((s = getenv("SYSTEMROOT")) != NULL)
-    addenv(blk, "SYSTEMROOT=%s", s);
-#else
-  if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
-    addenv(blk, "LD_LIBRARY_PATH=%s", s);
-#endif /* _WIN32 */
-
-  if ((s = getenv("PERLLIB")) != NULL)
-    addenv(blk, "PERLLIB=%s", s);
-
-  if (conn->request_info.remote_user != NULL) {
-    addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
-    addenv(blk, "%s", "AUTH_TYPE=Digest");
-  }
-
-  // Add all headers as HTTP_* variables
-  for (i = 0; i < conn->request_info.num_headers; i++) {
-    p = addenv(blk, "HTTP_%s=%s",
-        conn->request_info.http_headers[i].name,
-        conn->request_info.http_headers[i].value);
-
-    // Convert variable name into uppercase, and change - to _
-    for (; *p != '=' && *p != '\0'; p++) {
-      if (*p == '-')
-        *p = '_';
-      *p = (char) toupper(* (unsigned char *) p);
-    }
-  }
-
-  // Add user-specified variables
-  s = conn->ctx->config[CGI_ENVIRONMENT];
-  while ((s = next_option(s, &var_vec, NULL)) != NULL) {
-    addenv(blk, "%.*s", var_vec.len, var_vec.ptr);
-  }
-
-  blk->vars[blk->nvars++] = NULL;
-  blk->buf[blk->len++] = '\0';
-
-  assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
-  assert(blk->len > 0);
-  assert(blk->len < (int) sizeof(blk->buf));
-}
-
-static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
-  int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
-  const char *status;
-  char buf[BUFSIZ], *pbuf, dir[PATH_MAX], *p;
-  struct mg_request_info ri;
-  struct cgi_env_block blk;
-  FILE *in, *out;
-  pid_t pid;
-
-  prepare_cgi_environment(conn, prog, &blk);
-
-  // CGI must be executed 

<TRUNCATED>

[5/6] celix git commit: CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/civetweb.c
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/civetweb/civetweb.c b/examples/celix-examples/civetweb/civetweb/civetweb.c
new file mode 100644
index 0000000..259663a
--- /dev/null
+++ b/examples/celix-examples/civetweb/civetweb/civetweb.c
@@ -0,0 +1,19792 @@
+/* Copyright (c) 2013-2018 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(__GNUC__) || defined(__MINGW32__)
+/* Disable unused macros warnings - not all defines are required
+ * for all systems and all compilers. */
+#pragma GCC diagnostic ignored "-Wunused-macros"
+/* A padding warning is just plain useless */
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+
+#if defined(__clang__) /* GCC does not (yet) support this pragma */
+/* We must set some flags for the headers we include. These flags
+ * are reserved ids according to C99, so we need to disable a
+ * warning for that. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreserved-id-macro"
+#endif
+
+#if defined(_WIN32)
+#if !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
+#endif
+#if !defined(_WIN32_WINNT) /* defined for tdm-gcc so we can use getnameinfo */
+#define _WIN32_WINNT 0x0501
+#endif
+#else
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE /* for setgroups(), pthread_setname_np() */
+#endif
+#if defined(__linux__) && !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
+#endif
+#if !defined(_LARGEFILE_SOURCE)
+#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
+#endif
+#if !defined(_FILE_OFFSET_BITS)
+#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
+#endif
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
+#endif
+#if !defined(__STDC_LIMIT_MACROS)
+#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
+#endif
+#if !defined(_DARWIN_UNLIMITED_SELECT)
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+#if defined(__sun)
+#define __EXTENSIONS__  /* to expose flockfile and friends in stdio.h */
+#define __inline inline /* not recognized on older compiler versions */
+#endif
+#endif
+
+#if defined(__clang__)
+/* Enable reserved-id-macro warning again. */
+#pragma GCC diagnostic pop
+#endif
+
+
+#if defined(USE_LUA)
+#define USE_TIMERS
+#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)
+/* padding added after data member */
+#pragma warning(disable : 4820)
+/* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
+#pragma warning(disable : 4668)
+/* no function prototype given: converting '()' to '(void)' */
+#pragma warning(disable : 4255)
+/* function has been selected for automatic inline expansion */
+#pragma warning(disable : 4711)
+#endif
+
+
+/* This code uses static_assert to check some conditions.
+ * Unfortunately some compilers still do not support it, so we have a
+ * replacement function here. */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201100L
+#define mg_static_assert _Static_assert
+#elif defined(__cplusplus) && __cplusplus >= 201103L
+#define mg_static_assert static_assert
+#else
+char static_assert_replacement[1];
+#define mg_static_assert(cond, txt)                                            \
+	extern char static_assert_replacement[(cond) ? 1 : -1]
+#endif
+
+mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
+"int data type size check");
+mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
+"pointer data type size check");
+mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
+
+
+/* Alternative queue is well tested and should be the new default */
+#if defined(NO_ALTERNATIVE_QUEUE)
+#if defined(ALTERNATIVE_QUEUE)
+#error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both"
+#endif
+#else
+#define ALTERNATIVE_QUEUE
+#endif
+
+
+/* DTL -- including winsock2.h works better if lean and mean */
+#if !defined(WIN32_LEAN_AND_MEAN)
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#if defined(__SYMBIAN32__)
+/* According to https://en.wikipedia.org/wiki/Symbian#History,
+ * Symbian is no longer maintained since 2014-01-01.
+ * Recent versions of CivetWeb are no longer tested for Symbian.
+ * It makes no sense, to support an abandoned operating system.
+ */
+#error "Symbian is no longer maintained. CivetWeb no longer supports Symbian."
+#define NO_SSL /* SSL is not supported */
+#define NO_CGI /* CGI is not supported */
+#define PATH_MAX FILENAME_MAX
+#endif /* __SYMBIAN32__ */
+
+
+#if !defined(CIVETWEB_HEADER_INCLUDED)
+/* Include the header file here, so the CivetWeb interface is defined for the
+ * entire implementation, including the following forward definitions. */
+#include "civetweb.h"
+#endif
+
+#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);
+
+#define DEBUG_TRACE(fmt, ...)                                                  \
+	DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
+
+#define NEED_DEBUG_TRACE_FUNC
+
+#else
+#define DEBUG_TRACE(fmt, ...)                                                  \
+	do {                                                                       \
+	} while (0)
+#endif /* DEBUG */
+#endif /* DEBUG_TRACE */
+
+
+#if !defined(DEBUG_ASSERT)
+#if defined(DEBUG)
+#define DEBUG_ASSERT(cond)                                                     \
+	do {                                                                       \
+		if (!(cond)) {                                                         \
+			DEBUG_TRACE("ASSERTION FAILED: %s", #cond);                        \
+			exit(2); /* Exit with error */                                     \
+		}                                                                      \
+	} while (0)
+#else
+#define DEBUG_ASSERT(cond)
+#endif /* DEBUG */
+#endif
+
+
+#if !defined(IGNORE_UNUSED_RESULT)
+#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
+#endif
+
+
+#if defined(__GNUC__) || defined(__MINGW32__)
+
+/* GCC unused function attribute seems fundamentally broken.
+ * Several attempts to tell the compiler "THIS FUNCTION MAY BE USED
+ * OR UNUSED" for individual functions failed.
+ * Either the compiler creates an "unused-function" warning if a
+ * function is not marked with __attribute__((unused)).
+ * On the other hand, if the function is marked with this attribute,
+ * but is used, the compiler raises a completely idiotic
+ * "used-but-marked-unused" warning - and
+ *   #pragma GCC diagnostic ignored "-Wused-but-marked-unused"
+ * raises error: unknown option after "#pragma GCC diagnostic".
+ * Disable this warning completely, until the GCC guys sober up
+ * again.
+ */
+
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#define FUNCTION_MAY_BE_UNUSED /* __attribute__((unused)) */
+
+#else
+#define FUNCTION_MAY_BE_UNUSED
+#endif
+
+
+/* Some ANSI #includes are not available on Windows CE */
+#if !defined(_WIN32_WCE)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#endif /* !_WIN32_WCE */
+
+
+#if defined(__clang__)
+/* When using -Weverything, clang does not accept it's own headers
+ * in a release build configuration. Disable what is too much in
+ * -Weverything. */
+#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
+#endif
+
+#if defined(__GNUC__) || defined(__MINGW32__)
+/* Who on earth came to the conclusion, using __DATE__ should rise
+ * an "expansion of date or time macro is not reproducible"
+ * warning. That's exactly what was intended by using this macro.
+ * Just disable this nonsense warning. */
+
+/* And disabling them does not work either:
+ * #pragma clang diagnostic ignored "-Wno-error=date-time"
+ * #pragma clang diagnostic ignored "-Wdate-time"
+ * So we just have to disable ALL warnings for some lines
+ * of code.
+ * This seems to be a known GCC bug, not resolved since 2012:
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
+ */
+#endif
+
+
+#if defined(__MACH__) /* Apple OSX section */
+
+#if defined(__clang__)
+#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
+/* Avoid warnings for Xcode 7. It seems it does no longer exist in Xcode 8 */
+#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
+#pragma clang diagnostic ignored "-Wno-keyword-macro"
+#endif
+#endif
+
+#define CLOCK_MONOTONIC (1)
+#define CLOCK_REALTIME (2)
+
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <mach/clock.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+
+/* clock_gettime is not implemented on OSX prior to 10.12 */
+static int
+_civet_clock_gettime(int clk_id, struct timespec *t)
+{
+memset(t, 0, sizeof(*t));
+if (clk_id == CLOCK_REALTIME) {
+struct timeval now;
+int rv = gettimeofday(&now, NULL);
+if (rv) {
+return rv;
+}
+t->tv_sec = now.tv_sec;
+t->tv_nsec = now.tv_usec * 1000;
+return 0;
+
+} else if (clk_id == CLOCK_MONOTONIC) {
+static uint64_t clock_start_time = 0;
+static mach_timebase_info_data_t timebase_ifo = {0, 0};
+
+uint64_t now = mach_absolute_time();
+
+if (clock_start_time == 0) {
+kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
+DEBUG_ASSERT(mach_status == KERN_SUCCESS);
+
+/* appease "unused variable" warning for release builds */
+(void)mach_status;
+
+clock_start_time = now;
+}
+
+now = (uint64_t)((double)(now - clock_start_time)
+* (double)timebase_ifo.numer
+/ (double)timebase_ifo.denom);
+
+t->tv_sec = now / 1000000000;
+t->tv_nsec = now % 1000000000;
+return 0;
+}
+return -1; /* EINVAL - Clock ID is unknown */
+}
+
+/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
+#if defined(__CLOCK_AVAILABILITY)
+/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be
+ * declared but it may be NULL at runtime. So we need to check before using
+ * it. */
+static int
+_civet_safe_clock_gettime(int clk_id, struct timespec *t)
+{
+if (clock_gettime) {
+return clock_gettime(clk_id, t);
+}
+return _civet_clock_gettime(clk_id, t);
+}
+#define clock_gettime _civet_safe_clock_gettime
+#else
+#define clock_gettime _civet_clock_gettime
+#endif
+
+#endif
+
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+
+/********************************************************************/
+/* CivetWeb configuration defines */
+/********************************************************************/
+
+/* Maximum number of threads that can be configured.
+ * The number of threads actually created depends on the "num_threads"
+ * configuration parameter, but this is the upper limit. */
+#if !defined(MAX_WORKER_THREADS)
+#define MAX_WORKER_THREADS (1024 * 64) /* in threads (count) */
+#endif
+
+/* Timeout interval for select/poll calls.
+ * The timeouts depend on "*_timeout_ms" configuration values, but long
+ * timeouts are split into timouts as small as SOCKET_TIMEOUT_QUANTUM.
+ * This reduces the time required to stop the server. */
+#if !defined(SOCKET_TIMEOUT_QUANTUM)
+#define SOCKET_TIMEOUT_QUANTUM (2000) /* in ms */
+#endif
+
+/* Do not try to compress files smaller than this limit. */
+#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT)
+#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024) /* in bytes */
+#endif
+
+#if !defined(PASSWORDS_FILE_NAME)
+#define PASSWORDS_FILE_NAME ".htpasswd"
+#endif
+
+/* Initial buffer size for all CGI environment variables. In case there is
+ * not enough space, another block is allocated. */
+#if !defined(CGI_ENVIRONMENT_SIZE)
+#define CGI_ENVIRONMENT_SIZE (4096) /* in bytes */
+#endif
+
+/* Maximum number of environment variables. */
+#if !defined(MAX_CGI_ENVIR_VARS)
+#define MAX_CGI_ENVIR_VARS (256) /* in variables (count) */
+#endif
+
+/* General purpose buffer size. */
+#if !defined(MG_BUF_LEN) /* in bytes */
+#define MG_BUF_LEN (1024 * 8)
+#endif
+
+/* Size of the accepted socket queue (in case the old queue implementation
+ * is used). */
+#if !defined(MGSQLEN)
+#define MGSQLEN (20) /* count */
+#endif
+
+
+/********************************************************************/
+
+/* Helper makros */
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+/* Standard defines */
+#if !defined(INT64_MAX)
+#define INT64_MAX (9223372036854775807)
+#endif
+
+#define SHUTDOWN_RD (0)
+#define SHUTDOWN_WR (1)
+#define SHUTDOWN_BOTH (2)
+
+mg_static_assert(MAX_WORKER_THREADS >= 1,
+"worker threads must be a positive number");
+
+mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8,
+"size_t data type size check");
+
+#if defined(_WIN32)   /* WINDOWS include block */
+#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
+#include <ws2tcpip.h>
+#include <windows.h>
+
+typedef const char *SOCK_OPT_TYPE;
+
+#if !defined(PATH_MAX)
+#define W_PATH_MAX (MAX_PATH)
+/* at most three UTF-8 chars per wchar_t */
+#define PATH_MAX (W_PATH_MAX * 3)
+#else
+#define W_PATH_MAX ((PATH_MAX + 2) / 3)
+#endif
+
+mg_static_assert(PATH_MAX >= 1, "path length must be a positive number");
+
+#if !defined(_IN_PORT_T)
+#if !defined(in_port_t)
+#define in_port_t u_short
+#endif
+#endif
+
+#if !defined(_WIN32_WCE)
+#include <process.h>
+#include <direct.h>
+#include <io.h>
+#else            /* _WIN32_WCE */
+#define NO_CGI   /* WinCE has no pipes */
+#define NO_POPEN /* WinCE has no popen */
+
+typedef long off_t;
+
+#define errno ((int)(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)
+#if (_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
+#endif /* _MSC_VER */
+
+#define ERRNO ((int)(GetLastError()))
+#define NO_SOCKLEN_T
+
+#if defined(_WIN64) || defined(__MINGW64__)
+#if !defined(SSL_LIB)
+#define SSL_LIB "ssleay64.dll"
+#endif
+#if !defined(CRYPTO_LIB)
+#define CRYPTO_LIB "libeay64.dll"
+#endif
+#else
+#if !defined(SSL_LIB)
+#define SSL_LIB "ssleay32.dll"
+#endif
+#if !defined(CRYPTO_LIB)
+#define CRYPTO_LIB "libeay32.dll"
+#endif
+#endif
+
+#define O_NONBLOCK (0)
+#if !defined(W_OK)
+#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
+#endif
+#if !defined(EWOULDBLOCK)
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif /* !EWOULDBLOCK */
+#define _POSIX_
+#define INT64_FMT "I64d"
+#define UINT64_FMT "I64u"
+
+#define WINCDECL __cdecl
+#define vsnprintf_impl _vsnprintf
+#define access _access
+#define mg_sleep(x) (Sleep(x))
+
+#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
+#if !defined(popen)
+#define popen(x, y) (_popen(x, y))
+#endif
+#if !defined(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)) == -1) ? -1 : 0)
+#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(_WIN64) || !defined(__MINGW32__)
+/* Only MinGW 32 bit is missing this function */
+#define timegm(x) (_mkgmtime(x))
+#else
+time_t timegm(struct tm *tm);
+#define NEED_TIMEGM
+#endif
+
+
+#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;
+struct mg_workerTLS *waiting_thread; /* The chain of threads */
+} pthread_cond_t;
+
+#if !defined(__clockid_t_defined)
+typedef DWORD clockid_t;
+#endif
+#if !defined(CLOCK_MONOTONIC)
+#define CLOCK_MONOTONIC (1)
+#endif
+#if !defined(CLOCK_REALTIME)
+#define CLOCK_REALTIME (2)
+#endif
+#if !defined(CLOCK_THREAD)
+#define CLOCK_THREAD (3)
+#endif
+#if !defined(CLOCK_PROCESS)
+#define CLOCK_PROCESS (4)
+#endif
+
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+#define _TIMESPEC_DEFINED
+#endif
+#if !defined(_TIMESPEC_DEFINED)
+struct timespec {
+time_t tv_sec; /* seconds */
+long tv_nsec;  /* nanoseconds */
+};
+#endif
+
+#if !defined(WIN_PTHREADS_TIME_H)
+#define MUST_IMPLEMENT_CLOCK_GETTIME
+#endif
+
+#if defined(MUST_IMPLEMENT_CLOCK_GETTIME)
+#define clock_gettime mg_clock_gettime
+static int
+clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+FILETIME ft;
+ULARGE_INTEGER li, li2;
+BOOL ok = FALSE;
+double d;
+static double perfcnt_per_sec = 0.0;
+static BOOL initialized = FALSE;
+
+if (!initialized) {
+QueryPerformanceFrequency((LARGE_INTEGER *)&li);
+perfcnt_per_sec = 1.0 / li.QuadPart;
+initialized = TRUE;
+}
+
+if (tp) {
+memset(tp, 0, sizeof(*tp));
+
+if (clk_id == CLOCK_REALTIME) {
+
+/* BEGIN: CLOCK_REALTIME = wall clock (date and time) */
+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;
+/* END: CLOCK_REALTIME */
+
+} else if (clk_id == CLOCK_MONOTONIC) {
+
+/* BEGIN: CLOCK_MONOTONIC = stopwatch (time differences) */
+QueryPerformanceCounter((LARGE_INTEGER *)&li);
+d = li.QuadPart * perfcnt_per_sec;
+tp->tv_sec = (time_t)d;
+d -= (double)tp->tv_sec;
+tp->tv_nsec = (long)(d * 1.0E9);
+ok = TRUE;
+/* END: CLOCK_MONOTONIC */
+
+} else if (clk_id == CLOCK_THREAD) {
+
+/* BEGIN: CLOCK_THREAD = CPU usage of thread */
+FILETIME t_create, t_exit, t_kernel, t_user;
+if (GetThreadTimes(GetCurrentThread(),
+&t_create,
+&t_exit,
+&t_kernel,
+&t_user)) {
+li.LowPart = t_user.dwLowDateTime;
+li.HighPart = t_user.dwHighDateTime;
+li2.LowPart = t_kernel.dwLowDateTime;
+li2.HighPart = t_kernel.dwHighDateTime;
+li.QuadPart += li2.QuadPart;
+tp->tv_sec = (time_t)(li.QuadPart / 10000000);
+tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
+ok = TRUE;
+}
+/* END: CLOCK_THREAD */
+
+} else if (clk_id == CLOCK_PROCESS) {
+
+/* BEGIN: CLOCK_PROCESS = CPU usage of process */
+FILETIME t_create, t_exit, t_kernel, t_user;
+if (GetProcessTimes(GetCurrentProcess(),
+&t_create,
+&t_exit,
+&t_kernel,
+&t_user)) {
+li.LowPart = t_user.dwLowDateTime;
+li.HighPart = t_user.dwHighDateTime;
+li2.LowPart = t_kernel.dwLowDateTime;
+li2.HighPart = t_kernel.dwHighDateTime;
+li.QuadPart += li2.QuadPart;
+tp->tv_sec = (time_t)(li.QuadPart / 10000000);
+tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
+ok = TRUE;
+}
+/* END: CLOCK_PROCESS */
+
+} else {
+
+/* BEGIN: unknown clock */
+/* ok = FALSE; already set by init */
+/* END: unknown clock */
+}
+}
+
+return ok ? 0 : -1;
+}
+#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 path_to_unicode(const struct mg_connection *conn,
+const char *path,
+wchar_t *wbuf,
+size_t wbuf_len);
+
+/* All file operations need to be rewritten to solve #246. */
+
+struct mg_file;
+
+static const char *
+mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p);
+
+
+/* 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(_WIN32)
+#if !defined(HAVE_POLL)
+struct pollfd {
+SOCKET fd;
+short events;
+short revents;
+};
+#endif
+#endif
+
+/* Mark required libraries */
+#if defined(_MSC_VER)
+#pragma comment(lib, "Ws2_32.lib")
+#endif
+
+#else /* defined(_WIN32) - WINDOWS vs UNIX include block */
+
+#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>
+#include <netinet/tcp.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 <grp.h>
+#include <dirent.h>
+#define vsnprintf_impl vsnprintf
+
+#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
+#if !defined(O_BINARY)
+#define O_BINARY (0)
+#endif /* O_BINARY */
+#define closesocket(a) (close(a))
+#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
+#define mg_remove(conn, x) (remove(x))
+#define mg_sleep(x) (usleep((x)*1000))
+#define mg_opendir(conn, x) (opendir(x))
+#define mg_closedir(x) (closedir(x))
+#define mg_readdir(x) (readdir(x))
+#define ERRNO (errno)
+#define INVALID_SOCKET (-1)
+#define INT64_FMT PRId64
+#define UINT64_FMT PRIu64
+typedef int SOCKET;
+#define WINCDECL
+
+#if defined(__hpux)
+/* HPUX 11 does not have monotonic, fall back to realtime */
+#if !defined(CLOCK_MONOTONIC)
+#define CLOCK_MONOTONIC CLOCK_REALTIME
+#endif
+
+/* HPUX defines socklen_t incorrectly as size_t which is 64bit on
+ * Itanium.  Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
+ * the prototypes use int* rather than socklen_t* which matches the
+ * actual library expectation.  When called with the wrong size arg
+ * accept() returns a zero client inet addr and check_acl() always
+ * fails.  Since socklen_t is widely used below, just force replace
+ * their typedef with int. - DTL
+ */
+#define socklen_t int
+#endif /* hpux */
+
+#endif /* defined(_WIN32) - WINDOWS vs UNIX include block */
+
+/* Maximum queue length for pending connections. This value is passed as
+ * parameter to the "listen" socket call. */
+#if !defined(SOMAXCONN)
+/* This symbol may be defined in winsock2.h so this must after that include */
+#define SOMAXCONN (100) /* in pending connections (count) */
+#endif
+
+/* In case our C library is missing "timegm", provide an implementation */
+#if defined(NEED_TIMEGM)
+static inline int
+is_leap(int y)
+{
+return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
+}
+
+static inline int
+count_leap(int y)
+{
+return (y - 1969) / 4 - (y - 1901) / 100 + (y - 1601) / 400;
+}
+
+time_t
+timegm(struct tm *tm)
+{
+static const unsigned short ydays[] = {
+0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
+int year = tm->tm_year + 1900;
+int mon = tm->tm_mon;
+int mday = tm->tm_mday - 1;
+int hour = tm->tm_hour;
+int min = tm->tm_min;
+int sec = tm->tm_sec;
+
+if (year < 1970 || mon < 0 || mon > 11 || mday < 0
+|| (mday >= ydays[mon + 1] - ydays[mon]
++ (mon == 1 && is_leap(year) ? 1 : 0)) || hour < 0
+|| hour > 23
+|| min < 0
+|| min > 59
+|| sec < 0
+|| sec > 60)
+return -1;
+
+time_t res = year - 1970;
+res *= 365;
+res += mday;
+res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0);
+res += count_leap(year);
+
+res *= 24;
+res += hour;
+res *= 60;
+res += min;
+res *= 60;
+res += sec;
+return res;
+}
+#endif /* NEED_TIMEGM */
+
+
+/* va_copy should always be a macro, C99 and C++11 - DTL */
+#if !defined(va_copy)
+#define va_copy(x, y) ((x) = (y))
+#endif
+
+
+#if defined(_WIN32)
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+static CRITICAL_SECTION global_log_file_lock;
+
+FUNCTION_MAY_BE_UNUSED
+static DWORD
+pthread_self(void)
+{
+return GetCurrentThreadId();
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+pthread_key_create(
+pthread_key_t *key,
+void (*_ignored)(void *) /* destructor not supported for Windows */
+)
+{
+(void)_ignored;
+
+if ((key != 0)) {
+*key = TlsAlloc();
+return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
+}
+return -2;
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+pthread_key_delete(pthread_key_t key)
+{
+return TlsFree(key) ? 0 : 1;
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+pthread_setspecific(pthread_key_t key, void *value)
+{
+return TlsSetValue(key, value) ? 0 : 1;
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static void *
+pthread_getspecific(pthread_key_t key)
+{
+return TlsGetValue(key);
+}
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL;
+#else
+static pthread_mutexattr_t pthread_mutex_attr;
+#endif /* _WIN32 */
+
+
+#if defined(_WIN32_WCE)
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+FUNCTION_MAY_BE_UNUSED
+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;
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static struct tm *
+localtime_s(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;
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static struct tm *
+gmtime_s(const time_t *ptime, struct tm *ptm)
+{
+/* FIXME(lsm): fix this. */
+return localtime_s(ptime, ptm);
+}
+
+
+static int mg_atomic_inc(volatile int *addr);
+static struct tm tm_array[MAX_WORKER_THREADS];
+static int tm_index = 0;
+
+
+FUNCTION_MAY_BE_UNUSED
+static struct tm *
+localtime(const time_t *ptime)
+{
+int i = mg_atomic_inc(&tm_index) % (sizeof(tm_array) / sizeof(tm_array[0]));
+return localtime_s(ptime, tm_array + i);
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static struct tm *
+gmtime(const time_t *ptime)
+{
+int i = mg_atomic_inc(&tm_index) % ARRAY_SIZE(tm_array);
+return gmtime_s(ptime, tm_array + i);
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static size_t
+strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm)
+{
+/* TODO: (void)mg_snprintf(NULL, dst, dst_size, "implement strftime()
+	 * for WinCE"); */
+return 0;
+}
+
+#define _beginthreadex(psec, stack, func, prm, flags, ptid)                    \
+	(uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid)
+
+#define remove(f) mg_remove(NULL, f)
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+rename(const char *a, const char *b)
+{
+wchar_t wa[W_PATH_MAX];
+wchar_t wb[W_PATH_MAX];
+path_to_unicode(NULL, a, wa, ARRAY_SIZE(wa));
+path_to_unicode(NULL, b, wb, ARRAY_SIZE(wb));
+
+return MoveFileW(wa, wb) ? 0 : -1;
+}
+
+
+struct stat {
+int64_t st_size;
+time_t st_mtime;
+};
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+stat(const char *name, struct stat *st)
+{
+wchar_t wbuf[W_PATH_MAX];
+WIN32_FILE_ATTRIBUTE_DATA attr;
+time_t creation_time, write_time;
+
+path_to_unicode(NULL, name, wbuf, ARRAY_SIZE(wbuf));
+memset(&attr, 0, sizeof(attr));
+
+GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr);
+st->st_size =
+(((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow;
+
+write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime,
+attr.ftLastWriteTime.dwHighDateTime);
+creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime,
+attr.ftCreationTime.dwHighDateTime);
+
+if (creation_time > write_time) {
+st->st_mtime = creation_time;
+} else {
+st->st_mtime = write_time;
+}
+return 0;
+}
+
+#define access(x, a) 1 /* not required anyway */
+
+/* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */
+/* Values from errno.h in Windows SDK (Visual Studio). */
+#define EEXIST 17
+#define EACCES 13
+#define ENOENT 2
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+#endif /* defined(_WIN32_WCE) */
+
+
+#if defined(__GNUC__) || defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#define GCC_VERSION                                                            \
+	(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION >= 40500
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif /* GCC_VERSION >= 40500 */
+#endif /* defined(__GNUC__) || defined(__MINGW32__) */
+#if defined(__clang__)
+/* Show no warning in case system functions are not used. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
+static pthread_mutex_t global_lock_mutex;
+
+
+#if defined(_WIN32)
+/* Forward declaration for Windows */
+FUNCTION_MAY_BE_UNUSED
+static int pthread_mutex_lock(pthread_mutex_t *mutex);
+
+FUNCTION_MAY_BE_UNUSED
+static int pthread_mutex_unlock(pthread_mutex_t *mutex);
+#endif
+
+
+FUNCTION_MAY_BE_UNUSED
+static void
+mg_global_lock(void)
+{
+(void)pthread_mutex_lock(&global_lock_mutex);
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static void
+mg_global_unlock(void)
+{
+(void)pthread_mutex_unlock(&global_lock_mutex);
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+mg_atomic_inc(volatile int *addr)
+{
+int ret;
+#if defined(_WIN32) && !defined(NO_ATOMICS)
+/* Depending on the SDK, this function uses either
+	 * (volatile unsigned int *) or (volatile LONG *),
+	 * so whatever you use, the other SDK is likely to raise a warning. */
+ret = InterlockedIncrement((volatile long *)addr);
+#elif defined(__GNUC__)                                                        \
+    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))           \
+    && !defined(NO_ATOMICS)
+ret = __sync_add_and_fetch(addr, 1);
+#else
+mg_global_lock();
+ret = (++(*addr));
+mg_global_unlock();
+#endif
+return ret;
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static int
+mg_atomic_dec(volatile int *addr)
+{
+int ret;
+#if defined(_WIN32) && !defined(NO_ATOMICS)
+/* Depending on the SDK, this function uses either
+	 * (volatile unsigned int *) or (volatile LONG *),
+	 * so whatever you use, the other SDK is likely to raise a warning. */
+ret = InterlockedDecrement((volatile long *)addr);
+#elif defined(__GNUC__)                                                        \
+    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))           \
+    && !defined(NO_ATOMICS)
+ret = __sync_sub_and_fetch(addr, 1);
+#else
+mg_global_lock();
+ret = (--(*addr));
+mg_global_unlock();
+#endif
+return ret;
+}
+
+
+#if defined(USE_SERVER_STATS)
+static int64_t
+mg_atomic_add(volatile int64_t *addr, int64_t value)
+{
+int64_t ret;
+#if defined(_WIN64) && !defined(NO_ATOMICS)
+ret = InterlockedAdd64(addr, value);
+#elif defined(__GNUC__)                                                        \
+    && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))           \
+    && !defined(NO_ATOMICS)
+ret = __sync_add_and_fetch(addr, value);
+#else
+mg_global_lock();
+*addr += value;
+ret = (*addr);
+mg_global_unlock();
+#endif
+return ret;
+}
+#endif
+
+
+#if defined(__GNUC__)
+/* Show no warning in case system functions are not used. */
+#if GCC_VERSION >= 40500
+#pragma GCC diagnostic pop
+#endif /* GCC_VERSION >= 40500 */
+#endif /* defined(__GNUC__) */
+#if defined(__clang__)
+/* Show no warning in case system functions are not used. */
+#pragma clang diagnostic pop
+#endif
+
+
+#if defined(USE_SERVER_STATS)
+
+struct mg_memory_stat {
+volatile int64_t totalMemUsed;
+volatile int64_t maxMemUsed;
+volatile int blockCount;
+};
+
+
+static struct mg_memory_stat *get_memory_stat(struct mg_context *ctx);
+
+
+static void *
+mg_malloc_ex(size_t size,
+struct mg_context *ctx,
+const char *file,
+unsigned line)
+{
+void *data = malloc(size + 2 * sizeof(uintptr_t));
+void *memory = 0;
+struct mg_memory_stat *mstat = get_memory_stat(ctx);
+
+#if defined(MEMORY_DEBUGGING)
+char mallocStr[256];
+#else
+(void)file;
+(void)line;
+#endif
+
+if (data) {
+int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size);
+if (mmem > mstat->maxMemUsed) {
+/* could use atomic compare exchange, but this
+			 * seems overkill for statistics data */
+mstat->maxMemUsed = mmem;
+}
+
+mg_atomic_inc(&mstat->blockCount);
+((uintptr_t *)data)[0] = size;
+((uintptr_t *)data)[1] = (uintptr_t)mstat;
+memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
+}
+
+#if defined(MEMORY_DEBUGGING)
+sprintf(mallocStr,
+"MEM: %p %5lu alloc   %7lu %4lu --- %s:%u\n",
+memory,
+(unsigned long)size,
+(unsigned long)mstat->totalMemUsed,
+(unsigned long)mstat->blockCount,
+file,
+line);
+#if defined(_WIN32)
+OutputDebugStringA(mallocStr);
+#else
+DEBUG_TRACE("%s", mallocStr);
+#endif
+#endif
+
+return memory;
+}
+
+
+static void *
+mg_calloc_ex(size_t count,
+size_t size,
+struct mg_context *ctx,
+const char *file,
+unsigned line)
+{
+void *data = mg_malloc_ex(size * count, ctx, file, line);
+
+if (data) {
+memset(data, 0, size * count);
+}
+return data;
+}
+
+
+static void
+mg_free_ex(void *memory, const char *file, unsigned line)
+{
+void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
+
+
+#if defined(MEMORY_DEBUGGING)
+char mallocStr[256];
+#else
+(void)file;
+(void)line;
+#endif
+
+if (memory) {
+uintptr_t size = ((uintptr_t *)data)[0];
+struct mg_memory_stat *mstat =
+(struct mg_memory_stat *)(((uintptr_t *)data)[1]);
+mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size);
+mg_atomic_dec(&mstat->blockCount);
+#if defined(MEMORY_DEBUGGING)
+sprintf(mallocStr,
+"MEM: %p %5lu free    %7lu %4lu --- %s:%u\n",
+memory,
+(unsigned long)size,
+(unsigned long)mstat->totalMemUsed,
+(unsigned long)mstat->blockCount,
+file,
+line);
+#if defined(_WIN32)
+OutputDebugStringA(mallocStr);
+#else
+DEBUG_TRACE("%s", mallocStr);
+#endif
+#endif
+free(data);
+}
+}
+
+
+static void *
+mg_realloc_ex(void *memory,
+size_t newsize,
+struct mg_context *ctx,
+const char *file,
+unsigned line)
+{
+void *data;
+void *_realloc;
+uintptr_t oldsize;
+
+#if defined(MEMORY_DEBUGGING)
+char mallocStr[256];
+#else
+(void)file;
+(void)line;
+#endif
+
+if (newsize) {
+if (memory) {
+/* Reallocate existing block */
+struct mg_memory_stat *mstat;
+data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
+oldsize = ((uintptr_t *)data)[0];
+mstat = (struct mg_memory_stat *)((uintptr_t *)data)[1];
+_realloc = realloc(data, newsize + 2 * sizeof(uintptr_t));
+if (_realloc) {
+data = _realloc;
+mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize);
+#if defined(MEMORY_DEBUGGING)
+sprintf(mallocStr,
+"MEM: %p %5lu r-free  %7lu %4lu --- %s:%u\n",
+memory,
+(unsigned long)oldsize,
+(unsigned long)mstat->totalMemUsed,
+(unsigned long)mstat->blockCount,
+file,
+line);
+#if defined(_WIN32)
+OutputDebugStringA(mallocStr);
+#else
+DEBUG_TRACE("%s", mallocStr);
+#endif
+#endif
+mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize);
+#if defined(MEMORY_DEBUGGING)
+sprintf(mallocStr,
+"MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
+memory,
+(unsigned long)newsize,
+(unsigned long)mstat->totalMemUsed,
+(unsigned long)mstat->blockCount,
+file,
+line);
+#if defined(_WIN32)
+OutputDebugStringA(mallocStr);
+#else
+DEBUG_TRACE("%s", mallocStr);
+#endif
+#endif
+*(uintptr_t *)data = newsize;
+data = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
+} else {
+#if defined(MEMORY_DEBUGGING)
+#if defined(_WIN32)
+OutputDebugStringA("MEM: realloc failed\n");
+#else
+DEBUG_TRACE("%s", "MEM: realloc failed\n");
+#endif
+#endif
+return _realloc;
+}
+} else {
+/* Allocate new block */
+data = mg_malloc_ex(newsize, ctx, file, line);
+}
+} else {
+/* Free existing block */
+data = 0;
+mg_free_ex(memory, file, line);
+}
+
+return data;
+}
+
+#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
+#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
+#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
+#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
+
+#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
+#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
+#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
+
+#else /* USE_SERVER_STATS */
+
+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);
+}
+
+#define mg_malloc_ctx(a, c) mg_malloc(a)
+#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
+#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
+#define mg_free_ctx(a, c) mg_free(a)
+
+#endif /* USE_SERVER_STATS */
+
+
+static void mg_vsnprintf(const struct mg_connection *conn,
+int *truncated,
+char *buf,
+size_t buflen,
+const char *fmt,
+va_list ap);
+
+static void mg_snprintf(const struct mg_connection *conn,
+int *truncated,
+char *buf,
+size_t buflen,
+PRINTF_FORMAT_STRING(const char *fmt),
+...) PRINTF_ARGS(5, 6);
+
+/* This following lines are just meant as a reminder to use the mg-functions
+ * for memory management */
+#if defined(malloc)
+#undef malloc
+#endif
+#if defined(calloc)
+#undef calloc
+#endif
+#if defined(realloc)
+#undef realloc
+#endif
+#if defined(free)
+#undef free
+#endif
+#if defined(snprintf)
+#undef snprintf
+#endif
+#if defined(vsnprintf)
+#undef vsnprintf
+#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 snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
+#if defined(_WIN32)
+/* vsnprintf must not be used in any system,
+ * but this define only works well for Windows. */
+#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
+#endif
+
+
+/* mg_init_library counter */
+static int mg_init_library_called = 0;
+
+#if !defined(NO_SSL)
+static int mg_ssl_initialized = 0;
+#endif
+
+static pthread_key_t sTlsKey; /* Thread local storage index */
+static int thread_idx_max = 0;
+
+#if defined(MG_LEGACY_INTERFACE)
+#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
+#endif
+
+struct mg_workerTLS {
+int is_master;
+unsigned long thread_idx;
+#if defined(_WIN32)
+HANDLE pthread_cond_helper_mutex;
+struct mg_workerTLS *next_waiting_thread;
+#endif
+#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
+char txtbuf[4];
+#endif
+};
+
+
+#if defined(__GNUC__) || defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#if GCC_VERSION >= 40500
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif /* GCC_VERSION >= 40500 */
+#endif /* defined(__GNUC__) || defined(__MINGW32__) */
+#if defined(__clang__)
+/* Show no warning in case system functions are not used. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+
+
+/* Get a unique thread ID as unsigned long, independent from the data type
+ * of thread IDs defined by the operating system API.
+ * If two calls to mg_current_thread_id  return the same value, they calls
+ * are done from the same thread. If they return different values, they are
+ * done from different threads. (Provided this function is used in the same
+ * process context and threads are not repeatedly created and deleted, but
+ * CivetWeb does not do that).
+ * This function must match the signature required for SSL id callbacks:
+ * CRYPTO_set_id_callback
+ */
+FUNCTION_MAY_BE_UNUSED
+static unsigned long
+mg_current_thread_id(void)
+{
+#if defined(_WIN32)
+return GetCurrentThreadId();
+#else
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+/* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
+ * or not, so one of the two conditions will be unreachable by construction.
+ * Unfortunately the C standard does not define a way to check this at
+ * compile time, since the #if preprocessor conditions can not use the sizeof
+ * operator as an argument. */
+#endif
+
+if (sizeof(pthread_t) > sizeof(unsigned long)) {
+/* This is the problematic case for CRYPTO_set_id_callback:
+		 * The OS pthread_t can not be cast to unsigned long. */
+struct mg_workerTLS *tls =
+(struct mg_workerTLS *)pthread_getspecific(sTlsKey);
+if (tls == NULL) {
+/* SSL called from an unknown thread: Create some thread index.
+			 */
+tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS));
+tls->is_master = -2; /* -2 means "3rd party thread" */
+tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
+pthread_setspecific(sTlsKey, tls);
+}
+return tls->thread_idx;
+} else {
+/* pthread_t may be any data type, so a simple cast to unsigned long
+		 * can rise a warning/error, depending on the platform.
+		 * Here memcpy is used as an anything-to-anything cast. */
+unsigned long ret = 0;
+pthread_t t = pthread_self();
+memcpy(&ret, &t, sizeof(pthread_t));
+return ret;
+}
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#endif
+}
+
+
+FUNCTION_MAY_BE_UNUSED
+static uint64_t
+mg_get_current_time_ns(void)
+{
+struct timespec tsnow;
+clock_gettime(CLOCK_REALTIME, &tsnow);
+return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
+}
+
+
+#if defined(__GNUC__)
+/* Show no warning in case system functions are not used. */
+#if GCC_VERSION >= 40500
+#pragma GCC diagnostic pop
+#endif /* GCC_VERSION >= 40500 */
+#endif /* defined(__GNUC__) */
+#if defined(__clang__)
+/* Show no warning in case system functions are not used. */
+#pragma clang diagnostic pop
+#endif
+
+
+#if defined(NEED_DEBUG_TRACE_FUNC)
+static void
+DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
+{
+va_list args;
+uint64_t nsnow;
+static uint64_t nslast;
+struct timespec tsnow;
+
+/* Get some operating system independent thread id */
+unsigned long thread_id = mg_current_thread_id();
+
+clock_gettime(CLOCK_REALTIME, &tsnow);
+nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000)
++ ((uint64_t)tsnow.tv_nsec);
+
+if (!nslast) {
+nslast = nsnow;
+}
+
+flockfile(stdout);
+printf("*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ",
+(unsigned long)tsnow.tv_sec,
+(unsigned long)tsnow.tv_nsec,
+nsnow - nslast,
+thread_id,
+func,
+line);
+va_start(args, fmt);
+vprintf(fmt, args);
+va_end(args);
+putchar('\n');
+fflush(stdout);
+funlockfile(stdout);
+nslast = nsnow;
+}
+#endif /* NEED_DEBUG_TRACE_FUNC */
+
+
+#define MD5_STATIC static
+#include "md5.inl"
+
+/* Darwin prior to 7.0 and Win32 do not have socklen_t */
+#if defined(NO_SOCKLEN_T)
+typedef int socklen_t;
+#endif /* NO_SOCKLEN_T */
+
+#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
+
+#if !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL (0)
+#endif
+
+
+#if defined(NO_SSL)
+typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
+typedef struct SSL_CTX SSL_CTX;
+#else
+#if defined(NO_SSL_DL)
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/engine.h>
+#include <openssl/conf.h>
+#include <openssl/dh.h>
+#include <openssl/bn.h>
+#include <openssl/opensslv.h>
+
+#if defined(WOLFSSL_VERSION)
+/* Additional defines for WolfSSL, see
+ * https://github.com/civetweb/civetweb/issues/583 */
+#include "wolfssl_extras.inl"
+#endif
+
+#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;
+typedef struct x509_store_ctx_st X509_STORE_CTX;
+typedef struct x509_name X509_NAME;
+typedef struct asn1_integer ASN1_INTEGER;
+typedef struct bignum BIGNUM;
+typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS;
+typedef struct evp_md EVP_MD;
+typedef struct x509 X509;
+
+
+#define SSL_CTRL_OPTIONS (32)
+#define SSL_CTRL_CLEAR_OPTIONS (77)
+#define SSL_CTRL_SET_ECDH_AUTO (94)
+
+#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L
+#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L
+#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
+
+#define SSL_VERIFY_NONE (0)
+#define SSL_VERIFY_PEER (1)
+#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
+#define SSL_VERIFY_CLIENT_ONCE (4)
+#define SSL_OP_ALL ((long)(0x80000BFFUL))
+#define SSL_OP_NO_SSLv2 (0x01000000L)
+#define SSL_OP_NO_SSLv3 (0x02000000L)
+#define SSL_OP_NO_TLSv1 (0x04000000L)
+#define SSL_OP_NO_TLSv1_2 (0x08000000L)
+#define SSL_OP_NO_TLSv1_1 (0x10000000L)
+#define SSL_OP_SINGLE_DH_USE (0x00100000L)
+#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L)
+#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L)
+#define SSL_OP_NO_COMPRESSION (0x00020000L)
+
+#define SSL_CB_HANDSHAKE_START (0x10)
+#define SSL_CB_HANDSHAKE_DONE (0x20)
+
+#define SSL_ERROR_NONE (0)
+#define SSL_ERROR_SSL (1)
+#define SSL_ERROR_WANT_READ (2)
+#define SSL_ERROR_WANT_WRITE (3)
+#define SSL_ERROR_WANT_X509_LOOKUP (4)
+#define SSL_ERROR_SYSCALL (5) /* see errno */
+#define SSL_ERROR_ZERO_RETURN (6)
+#define SSL_ERROR_WANT_CONNECT (7)
+#define SSL_ERROR_WANT_ACCEPT (8)
+
+#define TLSEXT_TYPE_server_name (0)
+#define TLSEXT_NAMETYPE_host_name (0)
+#define SSL_TLSEXT_ERR_OK (0)
+#define SSL_TLSEXT_ERR_ALERT_WARNING (1)
+#define SSL_TLSEXT_ERR_ALERT_FATAL (2)
+#define SSL_TLSEXT_ERR_NOACK (3)
+
+struct ssl_func {
+const char *name;  /* SSL function name */
+void (*ptr)(void); /* Function pointer */
+};
+
+
+#if defined(OPENSSL_API_1_1)
+
+#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 TLS_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr)
+#define OPENSSL_init_ssl                                                       \
+	(*(int (*)(uint64_t opts,                                                  \
+	           const OPENSSL_INIT_SETTINGS *settings))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_CTX_use_certificate_chain_file                                     \
+	(*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr)
+#define TLS_client_method (*(SSL_METHOD * (*)(void))ssl_sw[16].ptr)
+#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr)
+#define SSL_CTX_set_verify                                                     \
+	(*(void (*)(SSL_CTX *,                                                     \
+	            int,                                                           \
+	            int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18].ptr)
+#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr)
+#define SSL_CTX_load_verify_locations                                          \
+	(*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr)
+#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr)
+#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr)
+#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[23].ptr)
+#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr)
+#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[25].ptr)
+#define SSL_CIPHER_get_name                                                    \
+	(*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr)
+#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr)
+#define SSL_CTX_set_session_id_context                                         \
+	(*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr)
+#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr)
+#define SSL_CTX_set_cipher_list                                                \
+	(*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr)
+#define SSL_CTX_set_options                                                    \
+	(*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr)
+#define SSL_CTX_set_info_callback                                              \
+	(*(void (*)(SSL_CTX * ctx,                                                 \
+	            void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr)
+#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr)
+#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
+#define SSL_CTX_callback_ctrl                                                  \
+	(*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
+#define SSL_get_servername                                                     \
+	(*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
+#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *))ssl_sw[37].ptr)
+
+#define SSL_CTX_clear_options(ctx, op)                                         \
+	SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
+#define SSL_CTX_set_ecdh_auto(ctx, onoff)                                      \
+	SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
+
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
+#define SSL_CTX_set_tlsext_servername_callback(ctx, cb)                        \
+	SSL_CTX_callback_ctrl(ctx,                                                 \
+	                      SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,                   \
+	                      (void (*)(void))cb)
+#define SSL_CTX_set_tlsext_servername_arg(ctx, arg)                            \
+	SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg)
+
+#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
+#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
+
+#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
+#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
+
+#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr)
+#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr)
+#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[2].ptr)
+#define CONF_modules_unload (*(void (*)(int))crypto_sw[3].ptr)
+#define X509_free (*(void (*)(X509 *))crypto_sw[4].ptr)
+#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[5].ptr)
+#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[6].ptr)
+#define X509_NAME_oneline                                                      \
+	(*(char *(*)(X509_NAME *, char *, int))crypto_sw[7].ptr)
+#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[8].ptr)
+#define EVP_get_digestbyname                                                   \
+	(*(const EVP_MD *(*)(const char *))crypto_sw[9].ptr)
+#define EVP_Digest                                                             \
+	(*(int (*)(                                                                \
+	    const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
+	      crypto_sw[10].ptr)
+#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[11].ptr)
+#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[12].ptr)
+#define ASN1_INTEGER_to_BN                                                     \
+	(*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[13].ptr)
+#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[14].ptr)
+#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[15].ptr)
+
+#define OPENSSL_free(a) CRYPTO_free(a)
+
+
+/* init_ssl_ctx() 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},
+{"TLS_server_method", NULL},
+{"OPENSSL_init_ssl", 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_CTX_use_certificate_chain_file", NULL},
+{"TLS_client_method", NULL},
+{"SSL_pending", NULL},
+{"SSL_CTX_set_verify", NULL},
+{"SSL_shutdown", NULL},
+{"SSL_CTX_load_verify_locations", NULL},
+{"SSL_CTX_set_default_verify_paths", NULL},
+{"SSL_CTX_set_verify_depth", NULL},
+{"SSL_get_peer_certificate", NULL},
+{"SSL_get_version", NULL},
+{"SSL_get_current_cipher", NULL},
+{"SSL_CIPHER_get_name", NULL},
+{"SSL_CTX_check_private_key", NULL},
+{"SSL_CTX_set_session_id_context", NULL},
+{"SSL_CTX_ctrl", NULL},
+{"SSL_CTX_set_cipher_list", NULL},
+{"SSL_CTX_set_options", NULL},
+{"SSL_CTX_set_info_callback", NULL},
+{"SSL_get_ex_data", NULL},
+{"SSL_set_ex_data", NULL},
+{"SSL_CTX_callback_ctrl", NULL},
+{"SSL_get_servername", NULL},
+{"SSL_set_SSL_CTX", NULL},
+{NULL, NULL}};
+
+
+/* Similar array as ssl_sw. These functions could be located in different
+ * lib. */
+static struct ssl_func crypto_sw[] = {{"ERR_get_error", NULL},
+{"ERR_error_string", NULL},
+{"ERR_remove_state", NULL},
+{"CONF_modules_unload", NULL},
+{"X509_free", NULL},
+{"X509_get_subject_name", NULL},
+{"X509_get_issuer_name", NULL},
+{"X509_NAME_oneline", NULL},
+{"X509_get_serialNumber", NULL},
+{"EVP_get_digestbyname", NULL},
+{"EVP_Digest", NULL},
+{"i2d_X509", NULL},
+{"BN_bn2hex", NULL},
+{"ASN1_INTEGER_to_BN", NULL},
+{"BN_free", NULL},
+{"CRYPTO_free", NULL},
+{NULL, NULL}};
+#else
+
+#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 (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr)
+#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
+#define SSL_CTX_load_verify_locations                                          \
+	(*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
+#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
+#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
+#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr)
+#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
+#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr)
+#define SSL_CIPHER_get_name                                                    \
+	(*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
+#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
+#define SSL_CTX_set_session_id_context                                         \
+	(*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
+#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
+#define SSL_CTX_set_cipher_list                                                \
+	(*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
+#define SSL_CTX_set_info_callback                                              \
+	(*(void (*)(SSL_CTX *, void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr)
+#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr)
+#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
+#define SSL_CTX_callback_ctrl                                                  \
+	(*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
+#define SSL_get_servername                                                     \
+	(*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
+#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *))ssl_sw[37].ptr)
+
+#define SSL_CTX_set_options(ctx, op)                                           \
+	SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
+#define SSL_CTX_clear_options(ctx, op)                                         \
+	SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
+#define SSL_CTX_set_ecdh_auto(ctx, onoff)                                      \
+	SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
+
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
+#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
+#define SSL_CTX_set_tlsext_servername_callback(ctx, cb)                        \
+	SSL_CTX_callback_ctrl(ctx,                                                 \
+	                      SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,                   \
+	                      (void (*)(void))cb)
+#define SSL_CTX_set_tlsext_servername_arg(ctx, arg)                            \
+	SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg)
+
+#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
+#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
+
+#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
+#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
+
+#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)
+#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
+#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
+#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
+#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
+#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
+#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
+#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr)
+#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[12].ptr)
+#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[13].ptr)
+#define X509_NAME_oneline                                                      \
+	(*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
+#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr)
+#define i2c_ASN1_INTEGER                                                       \
+	(*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
+#define EVP_get_digestbyname                                                   \
+	(*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
+#define EVP_Digest                                                             \
+	(*(int (*)(                                                                \
+	    const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
+	      crypto_sw[18].ptr)
+#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
+#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr)
+#define ASN1_INTEGER_to_BN                                                     \
+	(*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[21].ptr)
+#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr)
+#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr)
+
+#define OPENSSL_free(a) CRYPTO_free(a)
+
+/* init_ssl_ctx() 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},
+{"SSL_CTX_load_verify_locations", NULL},
+{"SSL_CTX_set_default_verify_paths", NULL},
+{"SSL_CTX_set_verify_depth", NULL},
+{"SSL_get_peer_certificate", NULL},
+{"SSL_get_version", NULL},
+{"SSL_get_current_cipher", NULL},
+{"SSL_CIPHER_get_name", NULL},
+{"SSL_CTX_check_private_key", NULL},
+{"SSL_CTX_set_session_id_context", NULL},
+{"SSL_CTX_ctrl", NULL},
+{"SSL_CTX_set_cipher_list", NULL},
+{"SSL_CTX_set_info_callback", NULL},
+{"SSL_get_ex_data", NULL},
+{"SSL_set_ex_data", NULL},
+{"SSL_CTX_callback_ctrl", NULL},
+{"SSL_get_servername", NULL},
+{"SSL_set_SSL_CTX", NULL},
+{NULL, NULL}};
+
+
+/* Similar array as ssl_sw. These functions could be located in different
+ * lib. */
+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},
+{"ERR_remove_state", NULL},
+{"ERR_free_strings", NULL},
+{"ENGINE_cleanup", NULL},
+{"CONF_modules_unload", NULL},
+{"CRYPTO_cleanup_all_ex_data", NULL},
+{"EVP_cleanup", NULL},
+{"X509_free", NULL},
+{"X509_get_subject_name", NULL},
+{"X509_get_issuer_name", NULL},
+{"X509_NAME_oneline", NULL},
+{"X509_get_serialNumber", NULL},
+{"i2c_ASN1_INTEGER", NULL},
+{"EVP_get_digestbyname", NULL},
+{"EVP_Digest", NULL},
+{"i2d_X509", NULL},
+{"BN_bn2hex", NULL},
+{"ASN1_INTEGER_to_BN", NULL},
+{"BN_free", NULL},
+{"CRYPTO_free", NULL},
+{NULL, NULL}};
+#endif /* OPENSSL_API_1_1 */
+#endif /* NO_SSL_DL */
+#endif /* NO_SSL */
+
+
+#if !defined(NO_CACHING)
+static const char *month_names[] = {"Jan",
+"Feb",
+"Mar",
+"Apr",
+"May",
+"Jun",
+"Jul",
+"Aug",
+"Sep",
+"Oct",
+"Nov",
+"Dec"};
+#endif /* !NO_CACHING */
+
+/* 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 mg_file_stat {
+/* File properties filled by mg_stat: */
+uint64_t size;
+time_t last_modified;
+int is_directory; /* Set to 1 if mg_stat is called for a directory */
+int is_gzipped;   /* Set to 1 if the content is gzipped, in which
+	                   * case we need a "Content-Eencoding: gzip" header */
+int location;     /* 0 = nowhere, 1 = on disk, 2 = in memory */
+};
+
+struct mg_file_in_memory {
+char *p;
+uint32_t pos;
+char mode;
+};
+
+struct mg_file_access {
+/* File properties filled by mg_fopen: */
+FILE *fp;
+#if defined(MG_USE_OPEN_FILE)
+/* TODO (low): Remove obsolete "file in memory" implementation.
+	 * In an "early 2017" discussion at Google groups
+	 * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI
+	 * we decided to get rid of this feature (after some fade-out
+	 * phase). */
+const char *membuf;
+#endif
+};
+
+struct mg_file {
+struct mg_file_stat stat;
+struct mg_file_access access;
+};
+
+#if defined(MG_USE_OPEN_FILE)
+
+#define STRUCT_FILE_INITIALIZER                                                \
+	{                                                                          \
+		{                                                                      \
+			(uint64_t)0, (time_t)0, 0, 0, 0                                    \
+		}                                                                      \
+		,                                                                      \
+		{                                                                      \
+			(FILE *) NULL, (const char *)NULL                                  \
+		}                                                                      \
+	}
+
+#else
+
+#define STRUCT_FILE_INITIALIZER                                                \
+	{                                                                          \
+		{                                                                      \
+			(uint64_t)0, (time_t)0, 0, 0, 0                                    \
+		}                                                                      \
+		,                                                                      \
+		{                                                                      \
+			(FILE *) NULL                                                      \
+		}                                                                      \
+	}
+
+#endif
+
+
+/* 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 char is_ssl;    /* Is port SSL-ed */
+unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
+	                          * port */
+unsigned char in_use;    /* Is valid */
+};
+
+
+/* Enum const for all options must be in sync with
+ * static struct mg_option config_options[]
+ * This is tested in the unit test (test/private.c)
+ * "Private Config Options"
+ */
+enum {
+/* Once for each server */
+LISTENING_PORTS,
+NUM_THREADS,
+RUN_AS_USER,
+CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the
+                         * socket option typedef TCP_NODELAY. */
+MAX_REQUEST_SIZE,
+LINGER_TIMEOUT,
+#if defined(__linux__)
+ALLOW_SENDFILE_CALL,
+#endif
+#if defined(_WIN32)
+CASE_SENSITIVE_FILES,
+#endif
+THROTTLE,
+ACCESS_LOG_FILE,
+ERROR_LOG_FILE,
+ENABLE_KEEP_ALIVE,
+REQUEST_TIMEOUT,
+KEEP_ALIVE_TIMEOUT,
+#if defined(USE_WEBSOCKET)
+WEBSOCKET_TIMEOUT,
+ENABLE_WEBSOCKET_PING_PONG,
+#endif
+DECODE_URL,
+#if defined(USE_LUA)
+LUA_BACKGROUND_SCRIPT,
+LUA_BACKGROUND_SCRIPT_PARAMS,
+#endif
+#if defined(USE_TIMERS)
+CGI_TIMEOUT,
+#endif
+
+/* Once for each domain */
+DOCUMENT_ROOT,
+CGI_EXTENSIONS,
+CGI_ENVIRONMENT,
+PUT_DELETE_PASSWORDS_FILE,
+CGI_INTERPRETER,
+PROTECT_URI,
+AUTHENTICATION_DOMAIN,
+ENABLE_AUTH_DOMAIN_CHECK,
+SSI_EXTENSIONS,
+ENABLE_DIRECTORY_LISTING,
+GLOBAL_PASSWORDS_FILE,
+INDEX_FILES,
+ACCESS_CONTROL_LIST,
+EXTRA_MIME_TYPES,
+SSL_CERTIFICATE,
+SSL_CERTIFICATE_CHAIN,
+URL_REWRITE_PATTERN,
+HIDE_FILES,
+SSL_DO_VERIFY_PEER,
+SSL_CA_PATH,
+SSL_CA_FILE,
+SSL_VERIFY_DEPTH,
+SSL_DEFAULT_VERIFY_PATHS,
+SSL_CIPHER_LIST,
+SSL_PROTOCOL_VERSION,
+SSL_SHORT_TRUST,
+
+#if defined(USE_LUA)
+LUA_PRELOAD_FILE,
+LUA_SCRIPT_EXTENSIONS,
+LUA_SERVER_PAGE_EXTENSIONS,
+#if defined(MG_EXPERIMENTAL_INTERFACES)
+LUA_DEBUG_PARAMS,
+#endif
+#endif
+#if defined(USE_DUKTAPE)
+DUKTAPE_SCRIPT_EXTENSIONS,
+#endif
+
+#if defined(USE_WEBSOCKET)
+WEBSOCKET_ROOT,
+#endif
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+LUA_WEBSOCKET_EXTENSIONS,
+#endif
+
+ACCESS_CONTROL_ALLOW_ORIGIN,
+ACCESS_CONTROL_ALLOW_METHODS,
+ACCESS_CONTROL_ALLOW_HEADERS,
+ERROR_PAGES,
+#if !defined(NO_CACHING)
+STATIC_FILE_MAX_AGE,
+#endif
+#if !defined(NO_SSL)
+STRICT_HTTPS_MAX_AGE,
+#endif
+ADDITIONAL_HEADER,
+ALLOW_INDEX_SCRIPT_SUB_RES,
+
+NUM_OPTIONS
+};
+
+
+/* Config option name, config types, default value.
+ * Must be in the same order as the enum const above.
+ */
+static const struct mg_option config_options[] = {
+
+/* Once for each server */
+{"listening_ports", MG_CONFIG_TYPE_STRING_LIST, "8080"},
+{"num_threads", MG_CONFIG_TYPE_NUMBER, "50"},
+{"run_as_user", MG_CONFIG_TYPE_STRING, NULL},
+{"tcp_nodelay", MG_CONFIG_TYPE_NUMBER, "0"},
+{"max_request_size", MG_CONFIG_TYPE_NUMBER, "16384"},
+{"linger_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
+#if defined(__linux__)
+{"allow_sendfile_call", MG_CONFIG_TYPE_BOOLEAN, "yes"},
+#endif
+#if defined(_WIN32)
+{"case_sensitive", MG_CONFIG_TYPE_BOOLEAN, "no"},
+#endif
+{"throttle", MG_CONFIG_TYPE_STRING_LIST, NULL},
+{"access_log_file", MG_CONFIG_TYPE_FILE, NULL},
+{"error_log_file", MG_CONFIG_TYPE_FILE, NULL},
+{"enable_keep_alive", MG_CONFIG_TYPE_BOOLEAN, "no"},
+{"request_timeout_ms", MG_CONFIG_TYPE_NUMBER, "30000"},
+{"keep_alive_timeout_ms", MG_CONFIG_TYPE_NUMBER, "500"},
+#if defined(USE_WEBSOCKET)
+{"websocket_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
+{"enable_websocket_ping_pong", MG_CONFIG_TYPE_BOOLEAN, "no"},
+#endif
+{"decode_url", MG_CONFIG_TYPE_BOOLEAN, "yes"},
+#if defined(USE_LUA)
+{"lua_background_script", MG_CONFIG_TYPE_FILE, NULL},
+{"lua_background_script_params", MG_CONFIG_TYPE_STRING_LIST, NULL},
+#endif
+#if defined(USE_TIMERS)
+{"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
+#endif
+
+/* Once for each domain */
+{"document_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
+{"cgi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
+{"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
+{"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
+{"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
+{"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
+{"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
+{"enable_auth_domain_check", MG_CONFIG_TYPE_BOOLEAN, "yes"},
+{"ssi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"},
+{"enable_directory_listing", MG_CONFIG_TYPE_BOOLEAN, "yes"},
+{"global_auth_file", MG_CONFIG_TYPE_FILE, NULL},
+{"index_files",
+MG_CONFIG_TYPE_STRING_LIST,
+#if defined(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
+{"access_control_list", MG_CONFIG_TYPE_STRING_LIST, NULL},
+{"extra_mime_types", MG_CONFIG_TYPE_STRING_LIST, NULL},
+{"ssl_certificate", MG_CONFIG_TYPE_FILE, NULL},
+{"ssl_certificate_chain", MG_CONFIG_TYPE_FILE, NULL},
+{"url_rewrite_patterns", MG_CONFIG_TYPE_STRING_LIST, NULL},
+{"hide_files_patterns", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
+
+{"ssl_verify_peer", MG_CONFIG_TYPE_YES_NO_OPTIONAL, "no"},
+
+{"ssl_ca_path", MG_CONFIG_TYPE_DIRECTORY, NULL},
+{"ssl_ca_file", MG_CONFIG_TYPE_FILE, NULL},
+{"ssl_verify_depth", MG_CONFIG_TYPE_NUMBER, "9"},
+{"ssl_default_verify_paths", MG_CONFIG_TYPE_BOOLEAN, "yes"},
+{"ssl_cipher_list", MG_CONFIG_TYPE_STRING, NULL},
+{"ssl_protocol_version", MG_CONFIG_TYPE_NUMBER, "0"},
+{"ssl_short_trust", MG_CONFIG_TYPE_BOOLEAN, "no"},
+
+#if defined(USE_LUA)
+{"lua_preload_file", MG_CONFIG_TYPE_FILE, NULL},
+{"lua_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
+{"lua_server_page_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"},
+#if defined(MG_EXPERIMENTAL_INTERFACES)
+{"lua_debug", MG_CONFIG_TYPE_STRING, NULL},
+#endif
+#endif
+#if defined(USE_DUKTAPE)
+/* The support for duktape is still in alpha version state.
+     * The name of this config option might change. */
+{"duktape_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"},
+#endif
+
+#if defined(USE_WEBSOCKET)
+{"websocket_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
+#endif
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+{"lua_websocket_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
+#endif
+{"access_control_allow_origin", MG_CONFIG_TYPE_STRING, "*"},
+{"access_control_allow_methods", MG_CONFIG_TYPE_STRING, "*"},
+{"access_control_allow_headers", MG_CONFIG_TYPE_STRING, "*"},
+{"error_pages", MG_CONFIG_TYPE_DIRECTORY, NULL},
+#if !defined(NO_CACHING)
+{"static_file_max_age", MG_CONFIG_TYPE_NUMBER, "3600"},
+#endif
+#if !defined(NO_SSL)
+{"strict_transport_security_max_age", MG_CONFIG_TYPE_NUMBER, NULL},
+#endif
+{"additional_header", MG_CONFIG_TYPE_STRING_MULTILINE, NULL},
+{"allow_index_script_resource", MG_CONFIG_TYPE_BOOLEAN, "no"},
+
+{NULL, MG_CONFIG_TYPE_UNKNOWN, NULL}};
+
+
+/* Check if the config_options and the corresponding enum have compatible
+ * sizes. */
+mg_static_assert((sizeof(config_options) / sizeof(config_options[0]))
+== (NUM_OPTIONS + 1),
+"config_options and enum not sync");
+
+
+enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER };
+
+
+struct mg_handler_info {
+/* Name/Pattern of the URI. */
+char *uri;
+size_t uri_len;
+
+/* handler type */
+int handler_type;
+
+/* Handler for http/https or authorization requests. */
+mg_request_handler handler;
+unsigned int refcount;
+pthread_mutex_t refcount_mutex; /* Protects refcount */
+pthread_cond_t
+refcount_cond; /* Signaled when handler refcount is decremented */
+
+/* Handler for ws/wss (websocket) requests. */
+mg_websocket_connect_handler connect_handler;
+mg_websocket_ready_handler ready_handler;
+mg_websocket_data_handler data_handler;
+mg_websocket_close_handler close_handler;
+
+/* accepted subprotocols for ws/wss requests. */
+struct mg_websocket_subprotocols *subprotocols;
+
+/* Handler for authorization requests */
+mg_authorization_handler auth_handler;
+
+/* User supplied argument for the handler function. */
+void *cbdata;
+
+/* next handler in a linked list */
+struct mg_handler_info *next;
+};
+
+
+enum {
+CONTEXT_INVALID,
+CONTEXT_SERVER,
+CONTEXT_HTTP_CLIENT,
+CONTEXT_WS_CLIENT
+};
+
+
+struct mg_domain_context {
+SSL_CTX *ssl_ctx;                 /* SSL context */
+char *config[NUM_OPTIONS];        /* Civetweb configuration parameters */
+struct mg_handler_info *handlers; /* linked list of uri handlers */
+
+/* Server nonce */
+uint64_t auth_nonce_mask;  /* Mask for all nonce values */
+unsigned long nonce_count; /* Used nonces, used for authentication */
+
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+/* linked list of shared lua websockets */
+struct mg_shared_lua_websocket_list *shared_lua_websockets;
+#endif
+
+/* Linked list of domains */
+struct mg_domain_context *next;
+};
+
+
+struct mg_context {
+
+/* Part 1 - Physical context:
+	 * This holds threads, ports, timeouts, ...
+	 * set for the entire server, independent from the
+	 * addressed hostname.
+	 */
+
+/* Connection related */
+int context_type; /* See CONTEXT_* above */
+
+struct socket *listening_sockets;
+struct pollfd *listening_socket_fds;
+unsigned int num_listening_sockets;
+
+struct mg_connection *worker_connections; /* The connection struct, pre-
+	                                           * allocated for each worker */
+
+#if defined(USE_SERVER_STATS)
+int active_connections;
+int max_connections;
+int64_t total_connections;
+int64_t total_requests;
+int64_t total_data_read;
+int64_t total_data_written;
+#endif
+
+/* Thread related */
+volatile int stop_flag;       /* Should we stop event loop */
+pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */
+
+pthread_t masterthreadid; /* The master thread ID */
+unsigned int
+cfg_worker_threads;      /* The number of configured worker threads. */
+pthread_t *worker_threadids; /* The worker thread IDs */
+
+/* Connection to thread dispatching */
+#if defined(ALTERNATIVE_QUEUE)
+struct socket *client_socks;
+void **client_wait_events;
+#else
+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 */
+#endif
+
+/* Memory related */
+unsigned int max_request_size; /* The max request size */
+
+#if defined(USE_SERVER_STATS)
+struct mg_memory_stat ctx_memory;
+#endif
+
+/* Operating system related */
+char *systemName;  /* What operating system is running */
+time_t start_time; /* Server start time, used for authentication
+	                    * and for diagnstics. */
+
+#if defined(USE_TIMERS)
+struct ttimers *timers;
+#endif
+
+/* Lua specific: Background operations and shared websockets */
+#if defined(USE_LUA)
+void *lua_background_state;
+#endif
+
+/* Server nonce */
+pthread_mutex_t nonce_mutex; /* Protects nonce_count */
+
+/* Server callbacks */
+struct mg_callbacks callbacks; /* User-defined callback function */
+void *user_data;               /* User-defined data */
+
+/* Part 2 - Logical domain:
+	 * This holds hostname, TLS certificate, document root, ...
+	 * set for a domain hosted at the server.
+	 * There may be multiple domains hosted at one physical server.
+	 * The default domain "dd" is the first element of a list of
+	 * domains.
+	 */
+struct mg_domain_context dd; /* default domain */
+};
+
+
+#if defined(USE_SERVER_STATS)
+static struct mg_memory_stat mg_common_memory = {0, 0, 0};
+
+static struct mg_memory_stat *
+get_memory_stat(struct mg_context *ctx)
+{
+if (ctx) {
+return &(ctx->ctx_memory);
+}
+return &mg_common_memory;
+}
+#endif
+
+enum {
+CONNECTION_TYPE_INVALID,
+CONNECTION_TYPE_REQUEST,
+CONNECTION_TYPE_RESPONSE
+};
+
+struct mg_connection {
+int connection_type; /* see CONNECTION_TYPE_* above */
+
+struct mg_request_info request_info;
+struct mg_response_info response_info;
+
+struct mg_context *phys_ctx;
+struct mg_domain_context *dom_ctx;
+
+#if defined(USE_SERVER_STATS)
+int conn_state; /* 0 = undef, numerical value may change in different
+	                 * versions. For the current definition, see
+	                 * mg_get_connection_info_impl */
+#endif
+
+const char *host;         /* Host (HTTP/1.1 header or SNI) */
+SSL *ssl;                 /* SSL descriptor */
+SSL_CTX *client_ssl_ctx;  /* SSL context for client connections */
+struct socket client;     /* Connected client */
+time_t conn_birth_time;   /* Time (wall clock) when connection was
+	                           * established */
+struct timespec req_time; /* Time (since system start) when the 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 */
+int is_chunked;           /* Transfer-Encoding is chunked:
+	                           * 0 = not chunked,
+	                           * 1 = chunked, do data read yet,
+	                           * 2 = chunked, some data read,
+	                           * 3 = chunked, all data read
+	                           */
+size_t chunk_remainder;   /* Unread data from the last chunk */
+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 accept_gzip;      /* 1 if gzip encoding is accepted */
+int in_error_handler; /* 1 if in handler for user defined error
+	                       * pages */
+#if defined(USE_WEBSOCKET)
+int in_websocket_handling; /* 1 if in read_websocket */
+#endif
+int handled_requests; /* Number of requests handled by this connection
+	                         */
+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_(un)lock_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
+
+int thread_index; /* Thread index within ctx */
+};
+
+
+/* Directory entry */
+struct de {
+struct mg_connection *conn;
+char *file_name;
+struct mg_file_stat file;
+};
+
+
+#if defined(USE_WEBSOCKET)
+static int is_websocket_protocol(const struct mg_connection *conn);
+#else
+#define is_websocket_protocol(conn) (0)
+#endif
+
+
+#define mg_cry_internal(conn, fmt, ...)                                        \
+	mg_cry_internal_wrap(conn, __func__, __LINE__, fmt, __VA_ARGS__)
+
+static void mg_cry_internal_wrap(const struct mg_connection *conn,
+const char *func,
+unsigned line,
+const char *fmt,
+...) PRINTF_ARGS(4, 5);
+
+
+#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>
+#include <sys/sendfile.h>
+#if defined(ALTERNATIVE_QUEUE)
+#include <sys/eventfd.h>
+#endif /* ALTERNATIVE_QUEUE */
+
+
+#if defined(ALTERNATIVE_QUEUE)
+
+static void *
+event_create(void)
+{
+int evhdl = eventfd(0, EFD_CLOEXEC);
+int *ret;
+
+if (evhdl == -1) {
+/* Linux uses -1 on error, Windows NULL. */
+/* However, Linux does not return 0 on success either. */
+return 0;
+}
+
+ret = (int *)mg_malloc(sizeof(int));
+if (ret) {
+*ret = evhdl;
+} else {
+(void)close(evhdl);
+}
+
+return (void *)ret;
+}
+
+
+static int
+event_wait(void *eventhdl)
+{
+uint64_t u;
+int evhdl, s;
+
+if (!eventhdl) {
+/* error */
+return 0;
+}
+evhdl = *(int *)eventhdl;
+
+s = (int)read(evhdl, &u, sizeof(u));
+if (s != sizeof(u)) {
+/* error */
+return 0;
+}
+(void)u; /* the value is not required */
+return 1;
+}
+
+
+static int
+event_signal(void *eventhdl)
+{
+uint64_t u = 1;
+int evhdl, s;
+
+if (!eventhdl) {
+/* error */
+return 0;
+}
+evhdl = *(int *)eventhdl;
+
+s = (int)write(evhdl, &u, sizeof(u));
+if (s != sizeof(u)) {
+/* error */
+return 0;
+}
+return 1;
+}
+
+
+static void
+event_destroy(void *eventhdl)
+{
+int evhdl;
+
+if (!eventhdl) {
+/* error */
+return;
+}
+evhdl = *(int *)eventhdl;
+
+close(evhdl);
+mg_free(eventhdl);
+}
+
+
+#endif
+
+#endif
+
+
+#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
+
+struct posix_event {
+pthread_mutex_t mutex;
+pthread_cond_t cond;
+};
+
+
+static void *
+event_create(void)
+{
+struct posix_event *ret = mg_malloc(sizeof(struct posix_event));
+if (ret == 0) {
+/* out of memory */
+return 0;
+}
+if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
+/* pthread mutex not available */
+mg_free(ret);
+return 0;
+}
+if (0 != pthread_cond_init(&(ret->cond), NULL)) {
+/* pthread cond not available */
+pthread_mutex_destroy(&(ret->mutex));
+mg_free(ret);
+return 0;
+}
+return (void *)ret;
+}
+
+
+static int
+event_wait(void *eventhdl)
+{
+struct posix_event *ev = (struct posix_event *)eventhdl;
+pthread_mutex_lock(&(ev->mutex));
+pthread_cond_wait(&(ev->cond), &(ev->mutex));
+pthread_mutex_unlock(&(ev->mutex));
+return 1;
+}
+
+
+static int
+event_signal(void *eventhdl)
+{
+struct posix_event *ev = (struct posix_event *)eventhdl;
+pthread_mutex_lock(&(ev->mutex));
+pthread_cond_signal(&(ev->cond));
+pthread_mutex_unlock(&(ev->mutex));
+return 1;
+}
+
+
+static void
+event_destroy(void *eventhdl)
+{
+struct posix_event *ev = (struct posix_event *)eventhdl;
+pthread_cond_destroy(&(ev->cond));
+pthread_mutex_destroy(&(ev->mutex));
+mg_free(ev);
+}
+#endif
+
+
+static void
+mg_set_thread_name(const char *name)
+{
+char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
+
+mg_snprintf(
+NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name);
+
+#if defined(_WIN32)
+#if defined(_MSC_VER)
+/* Windows and Visual Studio Compiler */
+__try
+{
+THREADNAME_INFO info;
+info.dwType = 0x1000;
+info.szName = threadName;
+info.dwThreadID = ~0U;
+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(_GNU_SOURCE) && defined(__GLIBC__)                               \
+    && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
+/* pthread_setname_np first appeared in glibc in version 2.12*/
+(void)pthread_setname_np(pthread_self(), threadName);
+#elif defined(__linux__)
+/* on linux we can use the old prctl function */
+(void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
+#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)
+{
+/* This function is deprecated. Use mg_get_valid_options instead. */
+static const char *
+

<TRUNCATED>

[4/6] celix git commit: CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/civetweb.h
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/civetweb/civetweb.h b/examples/celix-examples/civetweb/civetweb/civetweb.h
new file mode 100644
index 0000000..5ecc75b
--- /dev/null
+++ b/examples/celix-examples/civetweb/civetweb/civetweb.h
@@ -0,0 +1,1498 @@
+/* Copyright (c) 2013-2017 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.
+ */
+
+#ifndef CIVETWEB_HEADER_INCLUDED
+#define CIVETWEB_HEADER_INCLUDED
+
+#define CIVETWEB_VERSION "1.11"
+#define CIVETWEB_VERSION_MAJOR (1)
+#define CIVETWEB_VERSION_MINOR (11)
+#define CIVETWEB_VERSION_PATCH (0)
+
+#ifndef CIVETWEB_API
+#if defined(_WIN32)
+#if defined(CIVETWEB_DLL_EXPORTS)
+#define CIVETWEB_API __declspec(dllexport)
+#elif defined(CIVETWEB_DLL_IMPORTS)
+#define CIVETWEB_API __declspec(dllimport)
+#else
+#define CIVETWEB_API
+#endif
+#elif __GNUC__ >= 4
+#define CIVETWEB_API __attribute__((visibility("default")))
+#else
+#define CIVETWEB_API
+#endif
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Init Features */
+enum {
+    MG_FEATURES_DEFAULT = 0x0u,
+
+    /* Support files from local directories */
+    /* Will only work, if NO_FILES is not set. */
+            MG_FEATURES_FILES = 0x1u,
+
+    /* Support transport layer security (TLS). */
+    /* SSL is still often used synonymously for TLS. */
+    /* Will only work, if NO_SSL is not set. */
+            MG_FEATURES_TLS = 0x2u,
+    MG_FEATURES_SSL = 0x2u,
+
+    /* Support common gateway interface (CGI). */
+    /* Will only work, if NO_CGI is not set. */
+            MG_FEATURES_CGI = 0x4u,
+
+    /* Support IPv6. */
+    /* Will only work, if USE_IPV6 is set. */
+            MG_FEATURES_IPV6 = 0x8u,
+
+    /* Support WebSocket protocol. */
+    /* Will only work, if USE_WEBSOCKET is set. */
+            MG_FEATURES_WEBSOCKET = 0x10u,
+
+    /* Support server side Lua scripting. */
+    /* Will only work, if USE_LUA is set. */
+            MG_FEATURES_LUA = 0x20u,
+
+    /* Support server side JavaScript scripting. */
+    /* Will only work, if USE_DUKTAPE is set. */
+            MG_FEATURES_SSJS = 0x40u,
+
+    /* Provide data required for caching files. */
+    /* Will only work, if NO_CACHING is not set. */
+            MG_FEATURES_CACHE = 0x80u,
+
+    /* Collect server status information. */
+    /* Will only work, if USE_SERVER_STATS is set. */
+            MG_FEATURES_STATS = 0x100u,
+
+    /* Support on-the-fly compression. */
+    /* Will only work, if USE_ZLIB is set. */
+            MG_FEATURES_COMPRESSION = 0x200u,
+
+    /* Collect server status information. */
+    /* Will only work, if USE_SERVER_STATS is set. */
+            MG_FEATURES_ALL = 0xFFFFu
+};
+
+
+/* Initialize this library. This should be called once before any other
+ * function from this library. This function is not guaranteed to be
+ * thread safe.
+ * Parameters:
+ *   features: bit mask for features to be initialized.
+ *             Note: The TLS libraries (like OpenSSL) is initialized
+ *                   only if the MG_FEATURES_TLS bit is set.
+ *                   Currently the other bits do not influence
+ *                   initialization, but this may change in future
+ *                   versions.
+ * Return value:
+ *   initialized features
+ *   0: error
+ */
+CIVETWEB_API unsigned mg_init_library(unsigned features);
+
+
+/* Un-initialize this library.
+ * Return value:
+ *   0: error
+ */
+CIVETWEB_API unsigned mg_exit_library(void);
+
+
+struct mg_context;    /* Handle for the HTTP service itself */
+struct mg_connection; /* Handle for the individual connection */
+
+
+/* Maximum number of headers */
+#define MG_MAX_HEADERS (64)
+
+struct mg_header {
+    const char *name;  /* HTTP header name */
+    const char *value; /* HTTP header value */
+};
+
+
+/* This structure contains information about the HTTP request. */
+struct mg_request_info {
+    const char *request_method;  /* "GET", "POST", etc */
+    const char *request_uri;     /* URL-decoded URI (absolute or relative,
+	                              * as in the request) */
+    const char *local_uri;       /* URL-decoded URI (relative). Can be NULL
+	                              * if the request_uri does not address a
+	                              * resource at the server host. */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-02-04, deprecated 2014-09-14 */
+    const char *uri;             /* Deprecated: use local_uri instead */
+#endif
+    const char *http_version; /* E.g. "1.0", "1.1" */
+    const char *query_string; /* URL part after '?', not including '?', or
+	                             NULL */
+    const char *remote_user;  /* Authenticated user, or NULL if no auth
+	                             used */
+    char remote_addr[48];     /* Client's IP address as a string. */
+
+    long long content_length; /* Length (in bytes) of the request body,
+	                             can be -1 if no length was given. */
+    int remote_port;          /* Client's port */
+    int is_ssl;               /* 1 if SSL-ed, 0 if not */
+    void *user_data;          /* User data pointer passed to mg_start() */
+    void *conn_data;          /* Connection-specific user data */
+
+    int num_headers; /* Number of HTTP headers */
+    struct mg_header
+            http_headers[MG_MAX_HEADERS]; /* Allocate maximum headers */
+
+    struct mg_client_cert *client_cert; /* Client certificate information */
+
+    const char *acceptedWebSocketSubprotocol; /* websocket subprotocol,
+	                                           * accepted during handshake */
+};
+
+
+/* This structure contains information about the HTTP request. */
+/* This structure may be extended in future versions. */
+struct mg_response_info {
+    int status_code;          /* E.g. 200 */
+    const char *status_text;  /* E.g. "OK" */
+    const char *http_version; /* E.g. "1.0", "1.1" */
+
+    long long content_length; /* Length (in bytes) of the request body,
+	                             can be -1 if no length was given. */
+
+    int num_headers; /* Number of HTTP headers */
+    struct mg_header
+            http_headers[MG_MAX_HEADERS]; /* Allocate maximum headers */
+};
+
+
+/* Client certificate information (part of mg_request_info) */
+/* New nomenclature. */
+struct mg_client_cert {
+    void *peer_cert;
+    const char *subject;
+    const char *issuer;
+    const char *serial;
+    const char *finger;
+};
+
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
+/* Old nomenclature. */
+struct client_cert {
+	const char *subject;
+	const char *issuer;
+	const char *serial;
+	const char *finger;
+};
+#endif
+
+
+/* This structure needs to be passed to mg_start(), to let civetweb know
+   which callbacks to invoke. For a detailed description, see
+   https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md */
+struct mg_callbacks {
+    /* Called when civetweb has received new HTTP request.
+       If the callback returns one, it must process the request
+       by sending valid HTTP headers and a body. Civetweb will not do
+       any further processing. Otherwise it must return zero.
+       Note that since V1.7 the "begin_request" function is called
+       before an authorization check. If an authorization check is
+       required, use a request_handler instead.
+       Return value:
+         0: civetweb will process the request itself. In this case,
+            the callback must not send any data to the client.
+         1-999: callback already processed the request. Civetweb will
+                not send any data after the callback returned. The
+                return code is stored as a HTTP status code for the
+                access log. */
+    int (*begin_request)(struct mg_connection *);
+
+    /* Called when civetweb has finished processing request. */
+    void (*end_request)(const struct mg_connection *, int reply_status_code);
+
+    /* Called when civetweb is about to log a message. If callback returns
+       non-zero, civetweb does not log anything. */
+    int (*log_message)(const struct mg_connection *, const char *message);
+
+    /* Called when civetweb is about to log access. If callback returns
+       non-zero, civetweb does not log anything. */
+    int (*log_access)(const struct mg_connection *, const char *message);
+
+    /* Called when civetweb initializes SSL library.
+       Parameters:
+         user_data: parameter user_data passed when starting the server.
+       Return value:
+         0: civetweb will set up the SSL certificate.
+         1: civetweb assumes the callback already set up the certificate.
+        -1: initializing ssl fails. */
+    int (*init_ssl)(void *ssl_context, void *user_data);
+
+    /* Called when civetweb is about to create or free a SSL_CTX.
+    Parameters:
+       ssl_ctx: SSL_CTX pointer. NULL at creation time, Not NULL when mg_context
+                will be freed
+         user_data: parameter user_data passed when starting the server.
+       Return value:
+         0: civetweb will continue to create the context, just as if the
+            callback would not be present.
+            The value in *ssl_ctx when the function returns is ignored.
+         1: civetweb will copy the value from *ssl_ctx to the civetweb context
+            and doesn't create its own.
+        -1: initializing ssl fails.*/
+    int (*external_ssl_ctx)(void **ssl_ctx, void *user_data);
+
+#if defined(MG_LEGACY_INTERFACE) /* 2015-08-19 */
+    /* Called when websocket request is received, before websocket handshake.
+	   Return value:
+	     0: civetweb proceeds with websocket handshake.
+	     1: connection is closed immediately.
+	   This callback is deprecated: Use mg_set_websocket_handler instead. */
+	int (*websocket_connect)(const struct mg_connection *);
+
+	/* Called when websocket handshake is successfully completed, and
+	   connection is ready for data exchange.
+	   This callback is deprecated: Use mg_set_websocket_handler instead. */
+	void (*websocket_ready)(struct mg_connection *);
+
+	/* Called when data frame has been received from the client.
+	   Parameters:
+	     bits: first byte of the websocket frame, see websocket RFC at
+	           http://tools.ietf.org/html/rfc6455, section 5.2
+	     data, data_len: payload, with mask (if any) already applied.
+	   Return value:
+	     1: keep this websocket connection open.
+	     0: close this websocket connection.
+	   This callback is deprecated: Use mg_set_websocket_handler instead. */
+	int (*websocket_data)(struct mg_connection *,
+	                      int bits,
+	                      char *data,
+	                      size_t data_len);
+#endif /* MG_LEGACY_INTERFACE */
+
+    /* Called when civetweb is closing a connection.  The per-context mutex is
+       locked when this is invoked.
+
+       Websockets:
+       Before mg_set_websocket_handler has been added, it was primarily useful
+       for noting when a websocket is closing, and used to remove it from any
+       application-maintained list of clients.
+       Using this callback for websocket connections is deprecated: Use
+       mg_set_websocket_handler instead.
+
+       Connection specific data:
+       If memory has been allocated for the connection specific user data
+       (mg_request_info->conn_data, mg_get_user_connection_data),
+       this is the last chance to free it.
+    */
+    void (*connection_close)(const struct mg_connection *);
+
+    /* Called when civetweb is about to serve Lua server page, if
+       Lua support is enabled.
+       Parameters:
+         conn: current connection.
+         lua_context: "lua_State *" pointer. */
+    void (*init_lua)(const struct mg_connection *conn, void *lua_context);
+
+#if defined(MG_LEGACY_INTERFACE) /* 2016-05-14 */
+    /* Called when civetweb has uploaded a file to a temporary directory as a
+	   result of mg_upload() call.
+	   Note that mg_upload is deprecated. Use mg_handle_form_request instead.
+	   Parameters:
+	     file_name: full path name to the uploaded file. */
+	void (*upload)(struct mg_connection *, const char *file_name);
+#endif
+
+    /* Called when civetweb is about to send HTTP error to the client.
+       Implementing this callback allows to create custom error pages.
+       Parameters:
+         conn: current connection.
+         status: HTTP error status code.
+         errmsg: error message text.
+       Return value:
+         1: run civetweb error handler.
+         0: callback already handled the error. */
+    int (*http_error)(struct mg_connection *conn,
+                      int status,
+                      const char *errmsg);
+
+    /* Called after civetweb context has been created, before requests
+       are processed.
+       Parameters:
+         ctx: context handle */
+    void (*init_context)(const struct mg_context *ctx);
+
+    /* Called when a new worker thread is initialized.
+       Parameters:
+         ctx: context handle
+         thread_type:
+           0 indicates the master thread
+           1 indicates a worker thread handling client connections
+           2 indicates an internal helper thread (timer thread)
+           */
+    void (*init_thread)(const struct mg_context *ctx, int thread_type);
+
+    /* Called when civetweb context is deleted.
+       Parameters:
+         ctx: context handle */
+    void (*exit_context)(const struct mg_context *ctx);
+
+    /* Called when initializing a new connection object.
+     * Can be used to initialize the connection specific user data
+     * (mg_request_info->conn_data, mg_get_user_connection_data).
+     * When the callback is called, it is not yet known if a
+     * valid HTTP(S) request will be made.
+     * Parameters:
+     *   conn: not yet fully initialized connection object
+     *   conn_data: output parameter, set to initialize the
+     *              connection specific user data
+     * Return value:
+     *   must be 0
+     *   Otherwise, the result is undefined
+     */
+    int (*init_connection)(const struct mg_connection *conn, void **conn_data);
+};
+
+
+/* Start web server.
+
+   Parameters:
+     callbacks: mg_callbacks structure with user-defined callbacks.
+     options: NULL terminated list of option_name, option_value pairs that
+              specify Civetweb configuration parameters.
+
+   Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
+      processing is required for these, signal handlers must be set up
+      after calling mg_start().
+
+
+   Example:
+     const char *options[] = {
+       "document_root", "/var/www",
+       "listening_ports", "80,443s",
+       NULL
+     };
+     struct mg_context *ctx = mg_start(&my_func, NULL, options);
+
+   Refer to https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md
+   for the list of valid option and their possible values.
+
+   Return:
+     web server context, or NULL on error. */
+CIVETWEB_API struct mg_context *mg_start(const struct mg_callbacks *callbacks,
+                                         void *user_data,
+                                         const char **configuration_options);
+
+
+/* Stop the web server.
+
+   Must be called last, when an application wants to stop the web server and
+   release all associated resources. This function blocks until all Civetweb
+   threads are stopped. Context pointer becomes invalid. */
+CIVETWEB_API void mg_stop(struct mg_context *);
+
+
+#if defined(MG_EXPERIMENTAL_INTERFACES)
+/* Add an additional domain to an already running web server.
+ *
+ * Parameters:
+ *   ctx: Context handle of a server started by mg_start.
+ *   options: NULL terminated list of option_name, option_value pairs that
+ *            specify CivetWeb configuration parameters.
+ *
+ * Return:
+ *   < 0 in case of an error
+ *    -1 for a parameter error
+ *    -2 invalid options
+ *    -3 initializing SSL failed
+ *    -4 mandatory domain option missing
+ *    -5 duplicate domain
+ *    -6 out of memory
+ *   > 0 index / handle of a new domain
+ */
+CIVETWEB_API int mg_start_domain(struct mg_context *ctx,
+                                 const char **configuration_options);
+#endif
+
+
+/* mg_request_handler
+
+   Called when a new request comes in.  This callback is URI based
+   and configured with mg_set_request_handler().
+
+   Parameters:
+      conn: current connection information.
+      cbdata: the callback data configured with mg_set_request_handler().
+   Returns:
+      0: the handler could not handle the request, so fall through.
+      1 - 999: the handler processed the request. The return code is
+               stored as a HTTP status code for the access log. */
+typedef int (*mg_request_handler)(struct mg_connection *conn, void *cbdata);
+
+
+/* mg_set_request_handler
+
+   Sets or removes a URI mapping for a request handler.
+   This function uses mg_lock_context internally.
+
+   URI's are ordered and prefixed URI's are supported. For example,
+   consider two URIs: /a/b and /a
+           /a   matches /a
+           /a/b matches /a/b
+           /a/c matches /a
+
+   Parameters:
+      ctx: server context
+      uri: the URI (exact or pattern) for the handler
+      handler: the callback handler to use when the URI is requested.
+               If NULL, an already registered handler for this URI will
+               be removed.
+               The URI used to remove a handler must match exactly the
+               one used to register it (not only a pattern match).
+      cbdata: the callback data to give to the handler when it is called. */
+CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx,
+                                         const char *uri,
+                                         mg_request_handler handler,
+                                         void *cbdata);
+
+
+/* Callback types for websocket handlers in C/C++.
+
+   mg_websocket_connect_handler
+       Is called when the client intends to establish a websocket connection,
+       before websocket handshake.
+       Return value:
+         0: civetweb proceeds with websocket handshake.
+         1: connection is closed immediately.
+
+   mg_websocket_ready_handler
+       Is called when websocket handshake is successfully completed, and
+       connection is ready for data exchange.
+
+   mg_websocket_data_handler
+       Is called when a data frame has been received from the client.
+       Parameters:
+         bits: first byte of the websocket frame, see websocket RFC at
+               http://tools.ietf.org/html/rfc6455, section 5.2
+         data, data_len: payload, with mask (if any) already applied.
+       Return value:
+         1: keep this websocket connection open.
+         0: close this websocket connection.
+
+   mg_connection_close_handler
+       Is called, when the connection is closed.*/
+typedef int (*mg_websocket_connect_handler)(const struct mg_connection *,
+                                            void *);
+typedef void (*mg_websocket_ready_handler)(struct mg_connection *, void *);
+typedef int (*mg_websocket_data_handler)(struct mg_connection *,
+                                         int,
+                                         char *,
+                                         size_t,
+                                         void *);
+typedef void (*mg_websocket_close_handler)(const struct mg_connection *,
+                                           void *);
+
+/* struct mg_websocket_subprotocols
+ *
+ * List of accepted subprotocols
+ */
+struct mg_websocket_subprotocols {
+    int nb_subprotocols;
+    char **subprotocols;
+};
+
+/* mg_set_websocket_handler
+
+   Set or remove handler functions for websocket connections.
+   This function works similar to mg_set_request_handler - see there. */
+CIVETWEB_API void
+mg_set_websocket_handler(struct mg_context *ctx,
+                         const char *uri,
+                         mg_websocket_connect_handler connect_handler,
+                         mg_websocket_ready_handler ready_handler,
+                         mg_websocket_data_handler data_handler,
+                         mg_websocket_close_handler close_handler,
+                         void *cbdata);
+
+/* mg_set_websocket_handler
+
+   Set or remove handler functions for websocket connections.
+   This function works similar to mg_set_request_handler - see there. */
+CIVETWEB_API void mg_set_websocket_handler_with_subprotocols(
+        struct mg_context *ctx,
+        const char *uri,
+        struct mg_websocket_subprotocols *subprotocols,
+        mg_websocket_connect_handler connect_handler,
+        mg_websocket_ready_handler ready_handler,
+        mg_websocket_data_handler data_handler,
+        mg_websocket_close_handler close_handler,
+        void *cbdata);
+
+
+/* mg_authorization_handler
+
+   Callback function definition for mg_set_auth_handler
+
+   Parameters:
+      conn: current connection information.
+      cbdata: the callback data configured with mg_set_request_handler().
+   Returns:
+      0: access denied
+      1: access granted
+ */
+typedef int (*mg_authorization_handler)(struct mg_connection *conn,
+                                        void *cbdata);
+
+
+/* mg_set_auth_handler
+
+   Sets or removes a URI mapping for an authorization handler.
+   This function works similar to mg_set_request_handler - see there. */
+CIVETWEB_API void mg_set_auth_handler(struct mg_context *ctx,
+                                      const char *uri,
+                                      mg_authorization_handler handler,
+                                      void *cbdata);
+
+
+/* Get the value of particular configuration parameter.
+   The value returned is read-only. Civetweb does not allow changing
+   configuration at run time.
+   If given parameter name is not valid, NULL is returned. For valid
+   names, return value is guaranteed to be non-NULL. If parameter is not
+   set, zero-length string is returned. */
+CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx,
+                                       const char *name);
+
+
+/* Get context from connection. */
+CIVETWEB_API struct mg_context *
+mg_get_context(const struct mg_connection *conn);
+
+
+/* Get user data passed to mg_start from context. */
+CIVETWEB_API void *mg_get_user_data(const struct mg_context *ctx);
+
+
+/* Set user data for the current connection. */
+/* Note: This function is deprecated. Use the init_connection callback
+   instead to initialize the user connection data pointer. It is
+   reccomended to supply a pointer to some user defined data structure
+   as conn_data initializer in init_connection. In case it is required
+   to change some data after the init_connection call, store another
+   data pointer in the user defined data structure and modify that
+   pointer. In either case, after the init_connection callback, only
+   calls to mg_get_user_connection_data should be required. */
+CIVETWEB_API void mg_set_user_connection_data(struct mg_connection *conn,
+                                              void *data);
+
+
+/* Get user data set for the current connection. */
+CIVETWEB_API void *
+mg_get_user_connection_data(const struct mg_connection *conn);
+
+
+/* Get a formatted link corresponding to the current request
+
+   Parameters:
+      conn: current connection information.
+      buf: string buffer (out)
+      buflen: length of the string buffer
+   Returns:
+      <0: error
+      >=0: ok */
+CIVETWEB_API int
+mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen);
+
+
+#if defined(MG_LEGACY_INTERFACE) /* 2014-02-21 */
+/* Return array of strings that represent valid configuration options.
+   For each option, option name and default value is returned, i.e. the
+   number of entries in the array equals to number_of_options x 2.
+   Array is NULL terminated. */
+/* Deprecated: Use mg_get_valid_options instead. */
+CIVETWEB_API const char **mg_get_valid_option_names(void);
+#endif
+
+
+struct mg_option {
+    const char *name;
+    int type;
+    const char *default_value;
+};
+
+/* Old nomenclature */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
+enum {
+	CONFIG_TYPE_UNKNOWN = 0x0,
+	CONFIG_TYPE_NUMBER = 0x1,
+	CONFIG_TYPE_STRING = 0x2,
+	CONFIG_TYPE_FILE = 0x3,
+	CONFIG_TYPE_DIRECTORY = 0x4,
+	CONFIG_TYPE_BOOLEAN = 0x5,
+	CONFIG_TYPE_EXT_PATTERN = 0x6,
+	CONFIG_TYPE_STRING_LIST = 0x7,
+	CONFIG_TYPE_STRING_MULTILINE = 0x8
+};
+#endif
+
+/* New nomenclature */
+enum {
+    MG_CONFIG_TYPE_UNKNOWN = 0x0,
+    MG_CONFIG_TYPE_NUMBER = 0x1,
+    MG_CONFIG_TYPE_STRING = 0x2,
+    MG_CONFIG_TYPE_FILE = 0x3,
+    MG_CONFIG_TYPE_DIRECTORY = 0x4,
+    MG_CONFIG_TYPE_BOOLEAN = 0x5,
+    MG_CONFIG_TYPE_EXT_PATTERN = 0x6,
+    MG_CONFIG_TYPE_STRING_LIST = 0x7,
+    MG_CONFIG_TYPE_STRING_MULTILINE = 0x8,
+    MG_CONFIG_TYPE_YES_NO_OPTIONAL = 0x9
+};
+
+/* Return array of struct mg_option, representing all valid configuration
+   options of civetweb.c.
+   The array is terminated by a NULL name option. */
+CIVETWEB_API const struct mg_option *mg_get_valid_options(void);
+
+
+struct mg_server_ports {
+    int protocol;    /* 1 = IPv4, 2 = IPv6, 3 = both */
+    int port;        /* port number */
+    int is_ssl;      /* https port: 0 = no, 1 = yes */
+    int is_redirect; /* redirect all requests: 0 = no, 1 = yes */
+    int _reserved1;
+    int _reserved2;
+    int _reserved3;
+    int _reserved4;
+};
+
+
+/* Get the list of ports that civetweb is listening on.
+   The parameter size is the size of the ports array in elements.
+   The caller is responsibility to allocate the required memory.
+   This function returns the number of struct mg_server_ports elements
+   filled in, or <0 in case of an error. */
+CIVETWEB_API int mg_get_server_ports(const struct mg_context *ctx,
+                                     int size,
+                                     struct mg_server_ports *ports);
+
+
+#if defined(MG_LEGACY_INTERFACE) /* 2017-04-02 */
+/* Deprecated: Use mg_get_server_ports instead. */
+CIVETWEB_API size_t
+mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl);
+#endif
+
+
+/* Add, edit or delete the entry in the passwords file.
+ *
+ * This function allows an application to manipulate .htpasswd files on the
+ * fly by adding, deleting and changing user records. This is one of the
+ * several ways of implementing authentication on the server side. For another,
+ * cookie-based way please refer to the examples/chat in the source tree.
+ *
+ * Parameter:
+ *   passwords_file_name: Path and name of a file storing multiple passwords
+ *   realm: HTTP authentication realm (authentication domain) name
+ *   user: User name
+ *   password:
+ *     If password is not NULL, entry modified or added.
+ *     If password is NULL, entry is deleted.
+ *
+ *  Return:
+ *    1 on success, 0 on error.
+ */
+CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name,
+                                          const char *realm,
+                                          const char *user,
+                                          const char *password);
+
+
+/* Return information associated with the request.
+ * Use this function to implement a server and get data about a request
+ * from a HTTP/HTTPS client.
+ * Note: Before CivetWeb 1.10, this function could be used to read
+ * a response from a server, when implementing a client, although the
+ * values were never returned in appropriate mg_request_info elements.
+ * It is strongly advised to use mg_get_response_info for clients.
+ */
+CIVETWEB_API const struct mg_request_info *
+mg_get_request_info(const struct mg_connection *);
+
+
+/* Return information associated with a HTTP/HTTPS response.
+ * Use this function in a client, to check the response from
+ * the server. */
+CIVETWEB_API const struct mg_response_info *
+mg_get_response_info(const struct mg_connection *);
+
+
+/* Send data to the client.
+   Return:
+    0   when the connection has been closed
+    -1  on error
+    >0  number of bytes written on success */
+CIVETWEB_API int mg_write(struct mg_connection *, const void *buf, size_t len);
+
+
+/* Send data to a websocket client wrapped in a websocket frame.  Uses
+   mg_lock_connection to ensure that the transmission is not interrupted,
+   i.e., when the application is proactively communicating and responding to
+   a request simultaneously.
+
+   Send data to a websocket client wrapped in a websocket frame.
+   This function is available when civetweb is compiled with -DUSE_WEBSOCKET
+
+   Return:
+    0   when the connection has been closed
+    -1  on error
+    >0  number of bytes written on success */
+CIVETWEB_API int mg_websocket_write(struct mg_connection *conn,
+                                    int opcode,
+                                    const char *data,
+                                    size_t data_len);
+
+
+/* Send data to a websocket server wrapped in a masked websocket frame.  Uses
+   mg_lock_connection to ensure that the transmission is not interrupted,
+   i.e., when the application is proactively communicating and responding to
+   a request simultaneously.
+
+   Send data to a websocket server wrapped in a masked websocket frame.
+   This function is available when civetweb is compiled with -DUSE_WEBSOCKET
+
+   Return:
+    0   when the connection has been closed
+    -1  on error
+    >0  number of bytes written on success */
+CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn,
+                                           int opcode,
+                                           const char *data,
+                                           size_t data_len);
+
+
+/* Blocks until unique access is obtained to this connection. Intended for use
+   with websockets only.
+   Invoke this before mg_write or mg_printf when communicating with a
+   websocket if your code has server-initiated communication as well as
+   communication in direct response to a message. */
+CIVETWEB_API void mg_lock_connection(struct mg_connection *conn);
+CIVETWEB_API void mg_unlock_connection(struct mg_connection *conn);
+
+
+#if defined(MG_LEGACY_INTERFACE) /* 2014-06-21 */
+#define mg_lock mg_lock_connection
+#define mg_unlock mg_unlock_connection
+#endif
+
+
+/* Lock server context.  This lock may be used to protect resources
+   that are shared between different connection/worker threads. */
+CIVETWEB_API void mg_lock_context(struct mg_context *ctx);
+CIVETWEB_API void mg_unlock_context(struct mg_context *ctx);
+
+
+/* Opcodes, from http://tools.ietf.org/html/rfc6455 */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
+enum {
+	WEBSOCKET_OPCODE_CONTINUATION = 0x0,
+	WEBSOCKET_OPCODE_TEXT = 0x1,
+	WEBSOCKET_OPCODE_BINARY = 0x2,
+	WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
+	WEBSOCKET_OPCODE_PING = 0x9,
+	WEBSOCKET_OPCODE_PONG = 0xa
+};
+#endif
+
+/* New nomenclature */
+enum {
+    MG_WEBSOCKET_OPCODE_CONTINUATION = 0x0,
+    MG_WEBSOCKET_OPCODE_TEXT = 0x1,
+    MG_WEBSOCKET_OPCODE_BINARY = 0x2,
+    MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
+    MG_WEBSOCKET_OPCODE_PING = 0x9,
+    MG_WEBSOCKET_OPCODE_PONG = 0xa
+};
+
+/* Macros for enabling compiler-specific checks for printf-like arguments. */
+#undef PRINTF_FORMAT_STRING
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#include <sal.h>
+#if defined(_MSC_VER) && _MSC_VER > 1400
+#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
+#else
+#define PRINTF_FORMAT_STRING(s) __format_string s
+#endif
+#else
+#define PRINTF_FORMAT_STRING(s) s
+#endif
+
+#ifdef __GNUC__
+#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
+#else
+#define PRINTF_ARGS(x, y)
+#endif
+
+
+/* Send data to the client using printf() semantics.
+   Works exactly like mg_write(), but allows to do message formatting. */
+CIVETWEB_API int mg_printf(struct mg_connection *,
+                           PRINTF_FORMAT_STRING(const char *fmt),
+                           ...) PRINTF_ARGS(2, 3);
+
+
+/* Send a part of the message body, if chunked transfer encoding is set.
+ * Only use this function after sending a complete HTTP request or response
+ * header with "Transfer-Encoding: chunked" set. */
+CIVETWEB_API int mg_send_chunk(struct mg_connection *conn,
+                               const char *chunk,
+                               unsigned int chunk_len);
+
+
+/* Send contents of the entire file together with HTTP headers.
+ * Parameters:
+ *   conn: Current connection information.
+ *   path: Full path to the file to send.
+ * This function has been superseded by mg_send_mime_file
+ */
+CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path);
+
+
+/* Send contents of the file without HTTP headers.
+ * The code must send a valid HTTP response header before using this function.
+ *
+ * Parameters:
+ *   conn: Current connection information.
+ *   path: Full path to the file to send.
+ *
+ * Return:
+ *   < 0   Error
+*/
+CIVETWEB_API int mg_send_file_body(struct mg_connection *conn,
+                                   const char *path);
+
+
+/* Send HTTP error reply. */
+CIVETWEB_API int mg_send_http_error(struct mg_connection *conn,
+                                    int status_code,
+                                    PRINTF_FORMAT_STRING(const char *fmt),
+                                    ...) PRINTF_ARGS(3, 4);
+
+
+/* Send "HTTP 200 OK" response header.
+ * After calling this function, use mg_write or mg_send_chunk to send the
+ * response body.
+ * Parameters:
+ *   conn: Current connection handle.
+ *   mime_type: Set Content-Type for the following content.
+ *   content_length: Size of the following content, if content_length >= 0.
+ *                   Will set transfer-encoding to chunked, if set to -1.
+ * Return:
+ *   < 0   Error
+ */
+CIVETWEB_API int mg_send_http_ok(struct mg_connection *conn,
+                                 const char *mime_type,
+                                 long long content_length);
+
+
+/* Send "HTTP 30x" redirect response.
+ * The response has content-size zero: do not send any body data after calling
+ * this function.
+ * Parameters:
+ *   conn: Current connection handle.
+ *   target_url: New location.
+ *   redirect_code: HTTP redirect type. Could be 301, 302, 303, 307, 308.
+ * Return:
+ *   < 0   Error (-1 send error, -2 parameter error)
+ */
+CIVETWEB_API int mg_send_http_redirect(struct mg_connection *conn,
+                                       const char *target_url,
+                                       int redirect_code);
+
+
+/* Send HTTP digest access authentication request.
+ * Browsers will send a user name and password in their next request, showing
+ * an authentication dialog if the password is not stored.
+ * Parameters:
+ *   conn: Current connection handle.
+ *   realm: Authentication realm. If NULL is supplied, the sever domain
+ *          set in the authentication_domain configuration is used.
+ * Return:
+ *   < 0   Error
+ */
+CIVETWEB_API int
+mg_send_digest_access_authentication_request(struct mg_connection *conn,
+                                             const char *realm);
+
+
+/* Check if the current request has a valid authentication token set.
+ * A file is used to provide a list of valid user names, realms and
+ * password hashes. The file can be created and modified using the
+ * mg_modify_passwords_file API function.
+ * Parameters:
+ *   conn: Current connection handle.
+ *   realm: Authentication realm. If NULL is supplied, the sever domain
+ *          set in the authentication_domain configuration is used.
+ *   filename: Path and name of a file storing multiple password hashes.
+ * Return:
+ *   > 0   Valid authentication
+ *   0     Invalid authentication
+ *   < 0   Error (all values < 0 should be considered as invalid
+ *         authentication, future error codes will have negative
+ *         numbers)
+ *   -1    Parameter error
+ *   -2    File not found
+ */
+CIVETWEB_API int
+mg_check_digest_access_authentication(struct mg_connection *conn,
+                                      const char *realm,
+                                      const char *filename);
+
+
+/* Send contents of the entire file together with HTTP headers.
+ * Parameters:
+ *   conn: Current connection handle.
+ *   path: Full path to the file to send.
+ *   mime_type: Content-Type for file.  NULL will cause the type to be
+ *              looked up by the file extension.
+ */
+CIVETWEB_API void mg_send_mime_file(struct mg_connection *conn,
+                                    const char *path,
+                                    const char *mime_type);
+
+
+/* Send contents of the entire file together with HTTP headers.
+   Parameters:
+     conn: Current connection information.
+     path: Full path to the file to send.
+     mime_type: Content-Type for file.  NULL will cause the type to be
+                looked up by the file extension.
+     additional_headers: Additional custom header fields appended to the header.
+                         Each header should start with an X-, to ensure it is
+                         not included twice.
+                         NULL does not append anything.
+*/
+CIVETWEB_API void mg_send_mime_file2(struct mg_connection *conn,
+                                     const char *path,
+                                     const char *mime_type,
+                                     const char *additional_headers);
+
+
+/* Store body data into a file. */
+CIVETWEB_API long long mg_store_body(struct mg_connection *conn,
+                                     const char *path);
+/* Read entire request body and store it in a file "path".
+   Return:
+     < 0   Error
+     >= 0  Number of bytes stored in file "path".
+*/
+
+
+/* Read data from the remote end, return number of bytes read.
+   Return:
+     0     connection has been closed by peer. No more data could be read.
+     < 0   read error. No more data could be read from the connection.
+     > 0   number of bytes read into the buffer. */
+CIVETWEB_API int mg_read(struct mg_connection *, void *buf, size_t len);
+
+
+/* Get the value of particular HTTP header.
+
+   This is a helper function. It traverses request_info->http_headers array,
+   and if the header is present in the array, returns its value. If it is
+   not present, NULL is returned. */
+CIVETWEB_API const char *mg_get_header(const struct mg_connection *,
+                                       const char *name);
+
+
+/* Get a value of particular form variable.
+
+   Parameters:
+     data: pointer to form-uri-encoded buffer. This could be either POST data,
+           or request_info.query_string.
+     data_len: length of the encoded data.
+     var_name: variable name to decode from the buffer
+     dst: destination buffer for the decoded variable
+     dst_len: length of the destination buffer
+
+   Return:
+     On success, length of the decoded variable.
+     On error:
+        -1 (variable not found).
+        -2 (destination buffer is NULL, zero length or too small to hold the
+            decoded variable).
+
+   Destination buffer is guaranteed to be '\0' - terminated if it is not
+   NULL or zero length. */
+CIVETWEB_API int mg_get_var(const char *data,
+                            size_t data_len,
+                            const char *var_name,
+                            char *dst,
+                            size_t dst_len);
+
+
+/* Get a value of particular form variable.
+
+   Parameters:
+     data: pointer to form-uri-encoded buffer. This could be either POST data,
+           or request_info.query_string.
+     data_len: length of the encoded data.
+     var_name: variable name to decode from the buffer
+     dst: destination buffer for the decoded variable
+     dst_len: length of the destination buffer
+     occurrence: which occurrence of the variable, 0 is the first, 1 the
+                 second...
+                this makes it possible to parse a query like
+                b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1
+
+   Return:
+     On success, length of the decoded variable.
+     On error:
+        -1 (variable not found).
+        -2 (destination buffer is NULL, zero length or too small to hold the
+            decoded variable).
+
+   Destination buffer is guaranteed to be '\0' - terminated if it is not
+   NULL or zero length. */
+CIVETWEB_API int mg_get_var2(const char *data,
+                             size_t data_len,
+                             const char *var_name,
+                             char *dst,
+                             size_t dst_len,
+                             size_t occurrence);
+
+
+/* Fetch value of certain cookie variable into the destination buffer.
+
+   Destination buffer is guaranteed to be '\0' - terminated. In case of
+   failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
+   parameter. This function returns only first occurrence.
+
+   Return:
+     On success, value length.
+     On error:
+        -1 (either "Cookie:" header is not present at all or the requested
+            parameter is not found).
+        -2 (destination buffer is NULL, zero length or too small to hold the
+            value). */
+CIVETWEB_API int mg_get_cookie(const char *cookie,
+                               const char *var_name,
+                               char *buf,
+                               size_t buf_len);
+
+
+/* Download data from the remote web server.
+     host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
+     port: port number, e.g. 80.
+     use_ssl: whether to use SSL connection.
+     error_buffer, error_buffer_size: error message placeholder.
+     request_fmt,...: HTTP request.
+   Return:
+     On success, valid pointer to the new connection, suitable for mg_read().
+     On error, NULL. error_buffer contains error message.
+   Example:
+     char ebuf[100];
+     struct mg_connection *conn;
+     conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
+                        "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
+ */
+CIVETWEB_API struct mg_connection *
+mg_download(const char *host,
+            int port,
+            int use_ssl,
+            char *error_buffer,
+            size_t error_buffer_size,
+            PRINTF_FORMAT_STRING(const char *request_fmt),
+            ...) PRINTF_ARGS(6, 7);
+
+
+/* Close the connection opened by mg_download(). */
+CIVETWEB_API void mg_close_connection(struct mg_connection *conn);
+
+
+#if defined(MG_LEGACY_INTERFACE) /* 2016-05-14 */
+/* File upload functionality. Each uploaded file gets saved into a temporary
+   file and MG_UPLOAD event is sent.
+   Return number of uploaded files.
+   Deprecated: Use mg_handle_form_request instead. */
+CIVETWEB_API int mg_upload(struct mg_connection *conn,
+                           const char *destination_dir);
+#endif
+
+
+/* This structure contains callback functions for handling form fields.
+   It is used as an argument to mg_handle_form_request. */
+struct mg_form_data_handler {
+    /* This callback function is called, if a new field has been found.
+     * The return value of this callback is used to define how the field
+     * should be processed.
+     *
+     * Parameters:
+     *   key: Name of the field ("name" property of the HTML input field).
+     *   filename: Name of a file to upload, at the client computer.
+     *             Only set for input fields of type "file", otherwise NULL.
+     *   path: Output parameter: File name (incl. path) to store the file
+     *         at the server computer. Only used if FORM_FIELD_STORAGE_STORE
+     *         is returned by this callback. Existing files will be
+     *         overwritten.
+     *   pathlen: Length of the buffer for path.
+     *   user_data: Value of the member user_data of mg_form_data_handler
+     *
+     * Return value:
+     *   The callback must return the intended storage for this field
+     *   (See FORM_FIELD_STORAGE_*).
+     */
+    int (*field_found)(const char *key,
+                       const char *filename,
+                       char *path,
+                       size_t pathlen,
+                       void *user_data);
+
+    /* If the "field_found" callback returned FORM_FIELD_STORAGE_GET,
+     * this callback will receive the field data.
+     *
+     * Parameters:
+     *   key: Name of the field ("name" property of the HTML input field).
+     *   value: Value of the input field.
+     *   user_data: Value of the member user_data of mg_form_data_handler
+     *
+     * Return value:
+     *   TODO: Needs to be defined.
+     */
+    int (*field_get)(const char *key,
+                     const char *value,
+                     size_t valuelen,
+                     void *user_data);
+
+    /* If the "field_found" callback returned FORM_FIELD_STORAGE_STORE,
+     * the data will be stored into a file. If the file has been written
+     * successfully, this callback will be called. This callback will
+     * not be called for only partially uploaded files. The
+     * mg_handle_form_request function will either store the file completely
+     * and call this callback, or it will remove any partial content and
+     * not call this callback function.
+     *
+     * Parameters:
+     *   path: Path of the file stored at the server.
+     *   file_size: Size of the stored file in bytes.
+     *   user_data: Value of the member user_data of mg_form_data_handler
+     *
+     * Return value:
+     *   TODO: Needs to be defined.
+     */
+    int (*field_store)(const char *path, long long file_size, void *user_data);
+
+    /* User supplied argument, passed to all callback functions. */
+    void *user_data;
+};
+
+
+/* Return values definition for the "field_found" callback in
+ * mg_form_data_handler. */
+#if defined(MG_LEGACY_INTERFACE) /* 2017-10-05 */
+enum {
+	/* Skip this field (neither get nor store it). Continue with the
+     * next field. */
+	FORM_FIELD_STORAGE_SKIP = 0x0,
+	/* Get the field value. */
+	FORM_FIELD_STORAGE_GET = 0x1,
+	/* Store the field value into a file. */
+	FORM_FIELD_STORAGE_STORE = 0x2,
+	/* Stop parsing this request. Skip the remaining fields. */
+	FORM_FIELD_STORAGE_ABORT = 0x10
+};
+#endif
+/* New nomenclature */
+enum {
+    /* Skip this field (neither get nor store it). Continue with the
+     * next field. */
+            MG_FORM_FIELD_STORAGE_SKIP = 0x0,
+    /* Get the field value. */
+            MG_FORM_FIELD_STORAGE_GET = 0x1,
+    /* Store the field value into a file. */
+            MG_FORM_FIELD_STORAGE_STORE = 0x2,
+    /* Stop parsing this request. Skip the remaining fields. */
+            MG_FORM_FIELD_STORAGE_ABORT = 0x10
+};
+
+/* Process form data.
+ * Returns the number of fields handled, or < 0 in case of an error.
+ * Note: It is possible that several fields are already handled successfully
+ * (e.g., stored into files), before the request handling is stopped with an
+ * error. In this case a number < 0 is returned as well.
+ * In any case, it is the duty of the caller to remove files once they are
+ * no longer required. */
+CIVETWEB_API int mg_handle_form_request(struct mg_connection *conn,
+                                        struct mg_form_data_handler *fdh);
+
+
+/* Convenience function -- create detached thread.
+   Return: 0 on success, non-0 on error. */
+typedef void *(*mg_thread_func_t)(void *);
+CIVETWEB_API int mg_start_thread(mg_thread_func_t f, void *p);
+
+
+/* Return builtin mime type for the given file name.
+   For unrecognized extensions, "text/plain" is returned. */
+CIVETWEB_API const char *mg_get_builtin_mime_type(const char *file_name);
+
+
+/* Get text representation of HTTP status code. */
+CIVETWEB_API const char *
+mg_get_response_code_text(const struct mg_connection *conn, int response_code);
+
+
+/* Return CivetWeb version. */
+CIVETWEB_API const char *mg_version(void);
+
+
+/* URL-decode input buffer into destination buffer.
+   0-terminate the destination buffer.
+   form-url-encoded data differs from URI encoding in a way that it
+   uses '+' as character for space, see RFC 1866 section 8.2.1
+   http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
+   Return: length of the decoded data, or -1 if dst buffer is too small. */
+CIVETWEB_API int mg_url_decode(const char *src,
+                               int src_len,
+                               char *dst,
+                               int dst_len,
+                               int is_form_url_encoded);
+
+
+/* URL-encode input buffer into destination buffer.
+   returns the length of the resulting buffer or -1
+   is the buffer is too small. */
+CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len);
+
+
+/* MD5 hash given strings.
+   Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
+   ASCIIz strings. When function returns, buf will contain human-readable
+   MD5 hash. Example:
+     char buf[33];
+     mg_md5(buf, "aa", "bb", NULL); */
+CIVETWEB_API char *mg_md5(char buf[33], ...);
+
+
+/* Print error message to the opened error log stream.
+   This utilizes the provided logging configuration.
+     conn: connection (not used for sending data, but to get perameters)
+     fmt: format string without the line return
+     ...: variable argument list
+   Example:
+     mg_cry(conn,"i like %s", "logging"); */
+CIVETWEB_API void mg_cry(const struct mg_connection *conn,
+                         PRINTF_FORMAT_STRING(const char *fmt),
+                         ...) PRINTF_ARGS(2, 3);
+
+
+/* utility methods to compare two buffers, case insensitive. */
+CIVETWEB_API int mg_strcasecmp(const char *s1, const char *s2);
+CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
+
+
+/* Connect to a websocket as a client
+   Parameters:
+     host: host to connect to, i.e. "echo.websocket.org" or "192.168.1.1" or
+   "localhost"
+     port: server port
+     use_ssl: make a secure connection to server
+     error_buffer, error_buffer_size: buffer for an error message
+     path: server path you are trying to connect to, i.e. if connection to
+   localhost/app, path should be "/app"
+     origin: value of the Origin HTTP header
+     data_func: callback that should be used when data is received from the
+   server
+     user_data: user supplied argument
+
+   Return:
+     On success, valid mg_connection object.
+     On error, NULL. Se error_buffer for details.
+*/
+CIVETWEB_API struct mg_connection *
+mg_connect_websocket_client(const char *host,
+                            int port,
+                            int use_ssl,
+                            char *error_buffer,
+                            size_t error_buffer_size,
+                            const char *path,
+                            const char *origin,
+                            mg_websocket_data_handler data_func,
+                            mg_websocket_close_handler close_func,
+                            void *user_data);
+
+
+/* Connect to a TCP server as a client (can be used to connect to a HTTP server)
+   Parameters:
+     host: host to connect to, i.e. "www.wikipedia.org" or "192.168.1.1" or
+   "localhost"
+     port: server port
+     use_ssl: make a secure connection to server
+     error_buffer, error_buffer_size: buffer for an error message
+
+   Return:
+     On success, valid mg_connection object.
+     On error, NULL. Se error_buffer for details.
+*/
+CIVETWEB_API struct mg_connection *mg_connect_client(const char *host,
+                                                     int port,
+                                                     int use_ssl,
+                                                     char *error_buffer,
+                                                     size_t error_buffer_size);
+
+
+struct mg_client_options {
+    const char *host;
+    int port;
+    const char *client_cert;
+    const char *server_cert;
+    /* TODO: add more data */
+};
+
+
+CIVETWEB_API struct mg_connection *
+mg_connect_client_secure(const struct mg_client_options *client_options,
+                         char *error_buffer,
+                         size_t error_buffer_size);
+
+
+enum { TIMEOUT_INFINITE = -1 };
+enum { MG_TIMEOUT_INFINITE = -1 };
+
+/* Wait for a response from the server
+   Parameters:
+     conn: connection
+     ebuf, ebuf_len: error message placeholder.
+     timeout: time to wait for a response in milliseconds (if < 0 then wait
+   forever)
+
+   Return:
+     On success, >= 0
+     On error/timeout, < 0
+*/
+CIVETWEB_API int mg_get_response(struct mg_connection *conn,
+                                 char *ebuf,
+                                 size_t ebuf_len,
+                                 int timeout);
+
+
+/* Check which features where set when the civetweb library has been compiled.
+   The function explicitly addresses compile time defines used when building
+   the library - it does not mean, the feature has been initialized using a
+   mg_init_library call.
+   mg_check_feature can be called anytime, even before mg_init_library has
+   been called.
+
+   Parameters:
+     feature: specifies which feature should be checked
+       The value is a bit mask. The individual bits are defined as:
+         1  serve files (NO_FILES not set)
+         2  support HTTPS (NO_SSL not set)
+         4  support CGI (NO_CGI not set)
+         8  support IPv6 (USE_IPV6 set)
+        16  support WebSocket (USE_WEBSOCKET set)
+        32  support Lua scripts and Lua server pages (USE_LUA is set)
+        64  support server side JavaScript (USE_DUKTAPE is set)
+       128  support caching (NO_CACHING not set)
+       256  support server statistics (USE_SERVER_STATS is set)
+       The result is undefined, if bits are set that do not represent a
+       defined feature (currently: feature >= 512).
+       The result is undefined, if no bit is set (feature == 0).
+
+   Return:
+     If feature is available, the corresponding bit is set
+     If feature is not available, the bit is 0
+*/
+CIVETWEB_API unsigned mg_check_feature(unsigned feature);
+
+
+/* Get information on the system. Useful for support requests.
+   Parameters:
+     buffer: Store system information as string here.
+     buflen: Length of buffer (including a byte required for a terminating 0).
+   Return:
+     Available size of system information, exluding a terminating 0.
+     The information is complete, if the return value is smaller than buflen.
+     The result is a JSON formatted string, the exact content may vary.
+   Note:
+     It is possible to determine the required buflen, by first calling this
+     function with buffer = NULL and buflen = NULL. The required buflen is
+     one byte more than the returned value.
+*/
+CIVETWEB_API int mg_get_system_info(char *buffer, int buflen);
+
+
+/* Get context information. Useful for server diagnosis.
+   Parameters:
+     ctx: Context handle
+     buffer: Store context information here.
+     buflen: Length of buffer (including a byte required for a terminating 0).
+   Return:
+     Available size of system information, exluding a terminating 0.
+     The information is complete, if the return value is smaller than buflen.
+     The result is a JSON formatted string, the exact content may vary.
+     Note:
+     It is possible to determine the required buflen, by first calling this
+     function with buffer = NULL and buflen = NULL. The required buflen is
+     one byte more than the returned value. However, since the available
+     context information changes, you should allocate a few bytes more.
+*/
+CIVETWEB_API int
+mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen);
+
+
+#ifdef MG_EXPERIMENTAL_INTERFACES
+/* Get connection information. Useful for server diagnosis.
+   Parameters:
+     ctx: Context handle
+     idx: Connection index
+     buffer: Store context information here.
+     buflen: Length of buffer (including a byte required for a terminating 0).
+   Return:
+     Available size of system information, exluding a terminating 0.
+     The information is complete, if the return value is smaller than buflen.
+     The result is a JSON formatted string, the exact content may vary.
+   Note:
+     It is possible to determine the required buflen, by first calling this
+     function with buffer = NULL and buflen = NULL. The required buflen is
+     one byte more than the returned value. However, since the available
+     context information changes, you should allocate a few bytes more.
+*/
+CIVETWEB_API int mg_get_connection_info(const struct mg_context *ctx,
+                                        int idx,
+                                        char *buffer,
+                                        int buflen);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CIVETWEB_HEADER_INCLUDED */
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/handle_form.inl
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/civetweb/handle_form.inl b/examples/celix-examples/civetweb/civetweb/handle_form.inl
new file mode 100644
index 0000000..e5511d5
--- /dev/null
+++ b/examples/celix-examples/civetweb/civetweb/handle_form.inl
@@ -0,0 +1,981 @@
+/* Copyright (c) 2016-2018 the Civetweb developers
+ *
+ * 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.
+ */
+
+
+static int
+url_encoded_field_found(const struct mg_connection *conn,
+                        const char *key,
+                        size_t key_len,
+                        const char *filename,
+                        size_t filename_len,
+                        char *path,
+                        size_t path_len,
+                        struct mg_form_data_handler *fdh)
+{
+	char key_dec[1024];
+	char filename_dec[1024];
+	int key_dec_len;
+	int filename_dec_len;
+	int ret;
+
+	key_dec_len =
+	    mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+
+	if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
+		return MG_FORM_FIELD_STORAGE_SKIP;
+	}
+
+	if (filename) {
+		filename_dec_len = mg_url_decode(filename,
+		                                 (int)filename_len,
+		                                 filename_dec,
+		                                 (int)sizeof(filename_dec),
+		                                 1);
+
+		if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
+		    || (filename_dec_len < 0)) {
+			/* Log error message and skip this field. */
+			mg_cry_internal(conn, "%s: Cannot decode filename", __func__);
+			return MG_FORM_FIELD_STORAGE_SKIP;
+		}
+	} else {
+		filename_dec[0] = 0;
+	}
+
+	ret =
+	    fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
+
+	if ((ret & 0xF) == MG_FORM_FIELD_STORAGE_GET) {
+		if (fdh->field_get == NULL) {
+			mg_cry_internal(conn,
+			                "%s: Function \"Get\" not available",
+			                __func__);
+			return MG_FORM_FIELD_STORAGE_SKIP;
+		}
+	}
+	if ((ret & 0xF) == MG_FORM_FIELD_STORAGE_STORE) {
+		if (fdh->field_store == NULL) {
+			mg_cry_internal(conn,
+			                "%s: Function \"Store\" not available",
+			                __func__);
+			return MG_FORM_FIELD_STORAGE_SKIP;
+		}
+	}
+
+	return ret;
+}
+
+
+static int
+url_encoded_field_get(const struct mg_connection *conn,
+                      const char *key,
+                      size_t key_len,
+                      const char *value,
+                      size_t value_len,
+                      struct mg_form_data_handler *fdh)
+{
+	char key_dec[1024];
+
+	char *value_dec = (char *)mg_malloc_ctx(value_len + 1, conn->phys_ctx);
+	int value_dec_len, ret;
+
+	if (!value_dec) {
+		/* Log error message and stop parsing the form data. */
+		mg_cry_internal(conn,
+		                "%s: Not enough memory (required: %lu)",
+		                __func__,
+		                (unsigned long)(value_len + 1));
+		return MG_FORM_FIELD_STORAGE_ABORT;
+	}
+
+	mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+
+	value_dec_len =
+	    mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
+
+	ret = fdh->field_get(key_dec,
+	                     value_dec,
+	                     (size_t)value_dec_len,
+	                     fdh->user_data);
+
+	mg_free(value_dec);
+
+	return ret;
+}
+
+
+static int
+unencoded_field_get(const struct mg_connection *conn,
+                    const char *key,
+                    size_t key_len,
+                    const char *value,
+                    size_t value_len,
+                    struct mg_form_data_handler *fdh)
+{
+	char key_dec[1024];
+	(void)conn;
+
+	mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+
+	return fdh->field_get(key_dec, value, value_len, fdh->user_data);
+}
+
+
+static int
+field_stored(const struct mg_connection *conn,
+             const char *path,
+             long long file_size,
+             struct mg_form_data_handler *fdh)
+{
+	/* Equivalent to "upload" callback of "mg_upload". */
+
+	(void)conn; /* we do not need mg_cry here, so conn is currently unused */
+
+	return fdh->field_store(path, file_size, fdh->user_data);
+}
+
+
+static const char *
+search_boundary(const char *buf,
+                size_t buf_len,
+                const char *boundary,
+                size_t boundary_len)
+{
+	/* We must do a binary search here, not a string search, since the buffer
+	 * may contain '\x00' bytes, if binary data is transferred. */
+	int clen = (int)buf_len - (int)boundary_len - 4;
+	int i;
+
+	for (i = 0; i <= clen; i++) {
+		if (!memcmp(buf + i, "\r\n--", 4)) {
+			if (!memcmp(buf + i + 4, boundary, boundary_len)) {
+				return buf + i;
+			}
+		}
+	}
+	return NULL;
+}
+
+
+int
+mg_handle_form_request(struct mg_connection *conn,
+                       struct mg_form_data_handler *fdh)
+{
+	const char *content_type;
+	char path[512];
+	char buf[1024]; /* Must not be smaller than ~900 - see sanity check */
+	int field_storage;
+	int buf_fill = 0;
+	int r;
+	int field_count = 0;
+	struct mg_file fstore = STRUCT_FILE_INITIALIZER;
+	int64_t file_size = 0; /* init here, to a avoid a false positive
+	                         "uninitialized variable used" warning */
+
+	int has_body_data =
+	    (conn->request_info.content_length > 0) || (conn->is_chunked);
+
+	/* There are three ways to encode data from a HTML form:
+	 * 1) method: GET (default)
+	 *    The form data is in the HTTP query string.
+	 * 2) method: POST, enctype: "application/x-www-form-urlencoded"
+	 *    The form data is in the request body.
+	 *    The body is url encoded (the default encoding for POST).
+	 * 3) method: POST, enctype: "multipart/form-data".
+	 *    The form data is in the request body of a multipart message.
+	 *    This is the typical way to handle file upload from a form.
+	 */
+
+	if (!has_body_data) {
+		const char *data;
+
+		if (0 != strcmp(conn->request_info.request_method, "GET")) {
+			/* No body data, but not a GET request.
+			 * This is not a valid form request. */
+			return -1;
+		}
+
+		/* GET request: form data is in the query string. */
+		/* The entire data has already been loaded, so there is no nead to
+		 * call mg_read. We just need to split the query string into key-value
+		 * pairs. */
+		data = conn->request_info.query_string;
+		if (!data) {
+			/* No query string. */
+			return -1;
+		}
+
+		/* Split data in a=1&b=xy&c=3&c=4 ... */
+		while (*data) {
+			const char *val = strchr(data, '=');
+			const char *next;
+			ptrdiff_t keylen, vallen;
+
+			if (!val) {
+				break;
+			}
+			keylen = val - data;
+
+			/* In every "field_found" callback we ask what to do with the
+			 * data ("field_storage"). This could be:
+			 * MG_FORM_FIELD_STORAGE_SKIP (0):
+			 *   ignore the value of this field
+			 * MG_FORM_FIELD_STORAGE_GET (1):
+			 *   read the data and call the get callback function
+			 * MG_FORM_FIELD_STORAGE_STORE (2):
+			 *   store the data in a file
+			 * MG_FORM_FIELD_STORAGE_READ (3):
+			 *   let the user read the data (for parsing long data on the fly)
+			 * MG_FORM_FIELD_STORAGE_ABORT (flag):
+			 *   stop parsing
+			 */
+			memset(path, 0, sizeof(path));
+			field_count++;
+			field_storage = url_encoded_field_found(conn,
+			                                        data,
+			                                        (size_t)keylen,
+			                                        NULL,
+			                                        0,
+			                                        path,
+			                                        sizeof(path) - 1,
+			                                        fdh);
+
+			val++;
+			next = strchr(val, '&');
+			if (next) {
+				vallen = next - val;
+				next++;
+			} else {
+				vallen = (ptrdiff_t)strlen(val);
+				next = val + vallen;
+			}
+
+			if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
+				/* Call callback */
+				url_encoded_field_get(
+				    conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
+			}
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
+				/* Store the content to a file */
+				if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
+					fstore.access.fp = NULL;
+				}
+				file_size = 0;
+				if (fstore.access.fp != NULL) {
+					size_t n = (size_t)
+					    fwrite(val, 1, (size_t)vallen, fstore.access.fp);
+					if ((n != (size_t)vallen) || (ferror(fstore.access.fp))) {
+						mg_cry_internal(conn,
+						                "%s: Cannot write file %s",
+						                __func__,
+						                path);
+						(void)mg_fclose(&fstore.access);
+						remove_bad_file(conn, path);
+					}
+					file_size += (int64_t)n;
+
+					if (fstore.access.fp) {
+						r = mg_fclose(&fstore.access);
+						if (r == 0) {
+							/* stored successfully */
+							field_stored(conn, path, file_size, fdh);
+						} else {
+							mg_cry_internal(conn,
+							                "%s: Error saving file %s",
+							                __func__,
+							                path);
+							remove_bad_file(conn, path);
+						}
+						fstore.access.fp = NULL;
+					}
+
+				} else {
+					mg_cry_internal(conn,
+					                "%s: Cannot create file %s",
+					                __func__,
+					                path);
+				}
+			}
+
+			/* if (field_storage == MG_FORM_FIELD_STORAGE_READ) { */
+			/* The idea of "field_storage=read" is to let the API user read
+			 * data chunk by chunk and to some data processing on the fly.
+			 * This should avoid the need to store data in the server:
+			 * It should neither be stored in memory, like
+			 * "field_storage=get" does, nor in a file like
+			 * "field_storage=store".
+			 * However, for a "GET" request this does not make any much
+			 * sense, since the data is already stored in memory, as it is
+			 * part of the query string.
+			 */
+			/* } */
+
+			if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+			    == MG_FORM_FIELD_STORAGE_ABORT) {
+				/* Stop parsing the request */
+				break;
+			}
+
+			/* Proceed to next entry */
+			data = next;
+		}
+
+		return field_count;
+	}
+
+	content_type = mg_get_header(conn, "Content-Type");
+
+	if (!content_type
+	    || !mg_strcasecmp(content_type, "APPLICATION/X-WWW-FORM-URLENCODED")
+	    || !mg_strcasecmp(content_type, "APPLICATION/WWW-FORM-URLENCODED")) {
+		/* The form data is in the request body data, encoded in key/value
+		 * pairs. */
+		int all_data_read = 0;
+
+		/* Read body data and split it in keys and values.
+		 * The encoding is like in the "GET" case above: a=1&b&c=3&c=4.
+		 * Here we use "POST", and read the data from the request body.
+		 * The data read on the fly, so it is not required to buffer the
+		 * entire request in memory before processing it. */
+		for (;;) {
+			const char *val;
+			const char *next;
+			ptrdiff_t keylen, vallen;
+			ptrdiff_t used;
+			int end_of_key_value_pair_found = 0;
+			int get_block;
+
+			if ((size_t)buf_fill < (sizeof(buf) - 1)) {
+
+				size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
+				r = mg_read(conn, buf + (size_t)buf_fill, to_read);
+				if (r < 0) {
+					/* read error */
+					return -1;
+				}
+				if (r != (int)to_read) {
+					/* TODO: Create a function to get "all_data_read" from
+					 * the conn object. All data is read if the Content-Length
+					 * has been reached, or if chunked encoding is used and
+					 * the end marker has been read, or if the connection has
+					 * been closed. */
+					all_data_read = 1;
+				}
+				buf_fill += r;
+				buf[buf_fill] = 0;
+				if (buf_fill < 1) {
+					break;
+				}
+			}
+
+			val = strchr(buf, '=');
+
+			if (!val) {
+				break;
+			}
+			keylen = val - buf;
+			val++;
+
+			/* Call callback */
+			memset(path, 0, sizeof(path));
+			field_count++;
+			field_storage = url_encoded_field_found(conn,
+			                                        buf,
+			                                        (size_t)keylen,
+			                                        NULL,
+			                                        0,
+			                                        path,
+			                                        sizeof(path) - 1,
+			                                        fdh);
+
+			if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+			    == MG_FORM_FIELD_STORAGE_ABORT) {
+				/* Stop parsing the request */
+				break;
+			}
+
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
+				if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
+					fstore.access.fp = NULL;
+				}
+				file_size = 0;
+				if (!fstore.access.fp) {
+					mg_cry_internal(conn,
+					                "%s: Cannot create file %s",
+					                __func__,
+					                path);
+				}
+			}
+
+			get_block = 0;
+			/* Loop to read values larger than sizeof(buf)-keylen-2 */
+			do {
+				next = strchr(val, '&');
+				if (next) {
+					vallen = next - val;
+					next++;
+					end_of_key_value_pair_found = 1;
+				} else {
+					vallen = (ptrdiff_t)strlen(val);
+					next = val + vallen;
+					end_of_key_value_pair_found = all_data_read;
+				}
+
+				if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
+#if 0
+					if (!end_of_key_value_pair_found && !all_data_read) {
+						/* This callback will deliver partial contents */
+					}
+#endif
+
+					/* Call callback */
+					url_encoded_field_get(conn,
+					                      ((get_block > 0) ? NULL : buf),
+					                      ((get_block > 0) ? 0
+					                                       : (size_t)keylen),
+					                      val,
+					                      (size_t)vallen,
+					                      fdh);
+					get_block++;
+				}
+				if (fstore.access.fp) {
+					size_t n = (size_t)
+					    fwrite(val, 1, (size_t)vallen, fstore.access.fp);
+					if ((n != (size_t)vallen) || (ferror(fstore.access.fp))) {
+						mg_cry_internal(conn,
+						                "%s: Cannot write file %s",
+						                __func__,
+						                path);
+						mg_fclose(&fstore.access);
+						remove_bad_file(conn, path);
+					}
+					file_size += (int64_t)n;
+				}
+
+				if (!end_of_key_value_pair_found) {
+					used = next - buf;
+					memmove(buf,
+					        buf + (size_t)used,
+					        sizeof(buf) - (size_t)used);
+					next = buf;
+					buf_fill -= (int)used;
+					if ((size_t)buf_fill < (sizeof(buf) - 1)) {
+
+						size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
+						r = mg_read(conn, buf + (size_t)buf_fill, to_read);
+						if (r < 0) {
+							/* read error */
+							if (fstore.access.fp) {
+								mg_fclose(&fstore.access);
+								remove_bad_file(conn, path);
+							}
+							return -1;
+						}
+						if (r != (int)to_read) {
+							/* TODO: Create a function to get "all_data_read"
+							 * from the conn object. All data is read if the
+							 * Content-Length has been reached, or if chunked
+							 * encoding is used and the end marker has been
+							 * read, or if the connection has been closed. */
+							all_data_read = 1;
+						}
+						buf_fill += r;
+						buf[buf_fill] = 0;
+						if (buf_fill < 1) {
+							break;
+						}
+						val = buf;
+					}
+				}
+
+			} while (!end_of_key_value_pair_found);
+
+			if (fstore.access.fp) {
+				r = mg_fclose(&fstore.access);
+				if (r == 0) {
+					/* stored successfully */
+					field_stored(conn, path, file_size, fdh);
+				} else {
+					mg_cry_internal(conn,
+					                "%s: Error saving file %s",
+					                __func__,
+					                path);
+					remove_bad_file(conn, path);
+				}
+				fstore.access.fp = NULL;
+			}
+
+			if (all_data_read && (buf_fill == 0)) {
+				/* nothing more to process */
+				break;
+			}
+
+			/* Proceed to next entry */
+			used = next - buf;
+			memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
+			buf_fill -= (int)used;
+		}
+
+		return field_count;
+	}
+
+	if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
+		/* The form data is in the request body data, encoded as multipart
+		 * content (see https://www.ietf.org/rfc/rfc1867.txt,
+		 * https://www.ietf.org/rfc/rfc2388.txt). */
+		char *boundary;
+		size_t bl;
+		ptrdiff_t used;
+		struct mg_request_info part_header;
+		char *hbuf;
+		const char *content_disp, *hend, *fbeg, *fend, *nbeg, *nend;
+		const char *next;
+		unsigned part_no;
+
+		memset(&part_header, 0, sizeof(part_header));
+
+		/* Skip all spaces between MULTIPART/FORM-DATA; and BOUNDARY= */
+		bl = 20;
+		while (content_type[bl] == ' ') {
+			bl++;
+		}
+
+		/* There has to be a BOUNDARY definition in the Content-Type header */
+		if (mg_strncasecmp(content_type + bl, "BOUNDARY=", 9)) {
+			/* Malformed request */
+			return -1;
+		}
+
+		/* Copy boundary string to variable "boundary" */
+		fbeg = content_type + bl + 9;
+		bl = strlen(fbeg);
+		boundary = (char *)mg_malloc(bl + 1);
+		if (!boundary) {
+			/* Out of memory */
+			mg_cry_internal(conn,
+			                "%s: Cannot allocate memory for boundary [%lu]",
+			                __func__,
+			                (unsigned long)bl);
+			return -1;
+		}
+		memcpy(boundary, fbeg, bl);
+		boundary[bl] = 0;
+
+		/* RFC 2046 permits the boundary string to be quoted. */
+		/* If the boundary is quoted, trim the quotes */
+		if (boundary[0] == '"') {
+			hbuf = strchr(boundary + 1, '"');
+			if ((!hbuf) || (*hbuf != '"')) {
+				/* Malformed request */
+				mg_free(boundary);
+				return -1;
+			}
+			*hbuf = 0;
+			memmove(boundary, boundary + 1, bl);
+			bl = strlen(boundary);
+		}
+
+		/* Do some sanity checks for boundary lengths */
+		if (bl > 70) {
+			/* From RFC 2046:
+			 * Boundary delimiters must not appear within the
+			 * encapsulated material, and must be no longer
+			 * than 70 characters, not counting the two
+			 * leading hyphens.
+			 */
+
+			/* The initial sanity check
+			 * (bl + 800 > sizeof(buf))
+			 * is no longer required, since sizeof(buf) == 1024
+			 *
+			 * Original comment:
+			 */
+			/* Sanity check:  The algorithm can not work if bl >= sizeof(buf),
+			 * and it will not work effectively, if the buf is only a few byte
+			 * larger than bl, or if buf can not hold the multipart header
+			 * plus the boundary.
+			 * Check some reasonable number here, that should be fulfilled by
+			 * any reasonable request from every browser. If it is not
+			 * fulfilled, it might be a hand-made request, intended to
+			 * interfere with the algorithm. */
+			mg_free(boundary);
+			return -1;
+		}
+		if (bl < 4) {
+			/* Sanity check:  A boundary string of less than 4 bytes makes
+			 * no sense either. */
+			mg_free(boundary);
+			return -1;
+		}
+
+		for (part_no = 0;; part_no++) {
+			size_t towrite, fnlen, n;
+			int get_block;
+
+			r = mg_read(conn,
+			            buf + (size_t)buf_fill,
+			            sizeof(buf) - 1 - (size_t)buf_fill);
+			if (r < 0) {
+				/* read error */
+				mg_free(boundary);
+				return -1;
+			}
+			buf_fill += r;
+			buf[buf_fill] = 0;
+			if (buf_fill < 1) {
+				/* No data */
+				mg_free(boundary);
+				return -1;
+			}
+
+			if (part_no == 0) {
+				int d = 0;
+				while ((buf[d] != '-') && (d < buf_fill)) {
+					d++;
+				}
+				if ((d > 0) && (buf[d] == '-')) {
+					memmove(buf, buf + d, (unsigned)buf_fill - (unsigned)d);
+					buf_fill -= d;
+					buf[buf_fill] = 0;
+				}
+			}
+
+			if (buf[0] != '-' || buf[1] != '-') {
+				/* Malformed request */
+				mg_free(boundary);
+				return -1;
+			}
+			if (0 != strncmp(buf + 2, boundary, bl)) {
+				/* Malformed request */
+				mg_free(boundary);
+				return -1;
+			}
+			if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
+				/* Every part must end with \r\n, if there is another part.
+				 * The end of the request has an extra -- */
+				if (((size_t)buf_fill != (size_t)(bl + 6))
+				    || (strncmp(buf + bl + 2, "--\r\n", 4))) {
+					/* Malformed request */
+					mg_free(boundary);
+					return -1;
+				}
+				/* End of the request */
+				break;
+			}
+
+			/* Next, we need to get the part header: Read until \r\n\r\n */
+			hbuf = buf + bl + 4;
+			hend = strstr(hbuf, "\r\n\r\n");
+			if (!hend) {
+				/* Malformed request */
+				mg_free(boundary);
+				return -1;
+			}
+
+			part_header.num_headers =
+			    parse_http_headers(&hbuf, part_header.http_headers);
+			if ((hend + 2) != hbuf) {
+				/* Malformed request */
+				mg_free(boundary);
+				return -1;
+			}
+
+			/* Skip \r\n\r\n */
+			hend += 4;
+
+			/* According to the RFC, every part has to have a header field like:
+			 * Content-Disposition: form-data; name="..." */
+			content_disp = get_header(part_header.http_headers,
+			                          part_header.num_headers,
+			                          "Content-Disposition");
+			if (!content_disp) {
+				/* Malformed request */
+				mg_free(boundary);
+				return -1;
+			}
+
+			/* Get the mandatory name="..." part of the Content-Disposition
+			 * header. */
+			nbeg = strstr(content_disp, "name=\"");
+			while ((nbeg != NULL) && (strcspn(nbeg - 1, ":,; \t") != 0)) {
+				/* It could be somethingname= instead of name= */
+				nbeg = strstr(nbeg + 1, "name=\"");
+			}
+
+			/* This line is not required, but otherwise some compilers
+			 * generate spurious warnings. */
+			nend = nbeg;
+			/* And others complain, the result is unused. */
+			(void)nend;
+
+			/* If name=" is found, search for the closing " */
+			if (nbeg) {
+				nbeg += 6;
+				nend = strchr(nbeg, '\"');
+				if (!nend) {
+					/* Malformed request */
+					mg_free(boundary);
+					return -1;
+				}
+			} else {
+				/* name= without quotes is also allowed */
+				nbeg = strstr(content_disp, "name=");
+				while ((nbeg != NULL) && (strcspn(nbeg - 1, ":,; \t") != 0)) {
+					/* It could be somethingname= instead of name= */
+					nbeg = strstr(nbeg + 1, "name=");
+				}
+				if (!nbeg) {
+					/* Malformed request */
+					mg_free(boundary);
+					return -1;
+				}
+				nbeg += 5;
+
+				/* RFC 2616 Sec. 2.2 defines a list of allowed
+				 * separators, but many of them make no sense
+				 * here, e.g. various brackets or slashes.
+				 * If they are used, probably someone is
+				 * trying to attack with curious hand made
+				 * requests. Only ; , space and tab seem to be
+				 * reasonable here. Ignore everything else. */
+				nend = nbeg + strcspn(nbeg, ",; \t");
+			}
+
+			/* Get the optional filename="..." part of the Content-Disposition
+			 * header. */
+			fbeg = strstr(content_disp, "filename=\"");
+			while ((fbeg != NULL) && (strcspn(fbeg - 1, ":,; \t") != 0)) {
+				/* It could be somethingfilename= instead of filename= */
+				fbeg = strstr(fbeg + 1, "filename=\"");
+			}
+
+			/* This line is not required, but otherwise some compilers
+			 * generate spurious warnings. */
+			fend = fbeg;
+
+			/* If filename=" is found, search for the closing " */
+			if (fbeg) {
+				fbeg += 10;
+				fend = strchr(fbeg, '\"');
+
+				if (!fend) {
+					/* Malformed request (the filename field is optional, but if
+					 * it exists, it needs to be terminated correctly). */
+					mg_free(boundary);
+					return -1;
+				}
+
+				/* TODO: check Content-Type */
+				/* Content-Type: application/octet-stream */
+			}
+			if (!fbeg) {
+				/* Try the same without quotes */
+				fbeg = strstr(content_disp, "filename=");
+				while ((fbeg != NULL) && (strcspn(fbeg - 1, ":,; \t") != 0)) {
+					/* It could be somethingfilename= instead of filename= */
+					fbeg = strstr(fbeg + 1, "filename=");
+				}
+				if (fbeg) {
+					fbeg += 9;
+					fend = fbeg + strcspn(fbeg, ",; \t");
+				}
+			}
+
+			if (!fbeg || !fend) {
+				fbeg = NULL;
+				fend = NULL;
+				fnlen = 0;
+			} else {
+				fnlen = (size_t)(fend - fbeg);
+			}
+
+			/* In theory, it could be possible that someone crafts
+			 * a request like name=filename=xyz. Check if name and
+			 * filename do not overlap. */
+			if (!(((ptrdiff_t)fbeg > (ptrdiff_t)nend)
+			      || ((ptrdiff_t)nbeg > (ptrdiff_t)fend))) {
+				mg_free(boundary);
+				return -1;
+			}
+
+			/* Call callback for new field */
+			memset(path, 0, sizeof(path));
+			field_count++;
+			field_storage = url_encoded_field_found(conn,
+			                                        nbeg,
+			                                        (size_t)(nend - nbeg),
+			                                        ((fnlen > 0) ? fbeg : NULL),
+			                                        fnlen,
+			                                        path,
+			                                        sizeof(path) - 1,
+			                                        fdh);
+
+			/* If the boundary is already in the buffer, get the address,
+			 * otherwise next will be NULL. */
+			next = search_boundary(hbuf,
+			                       (size_t)((buf - hbuf) + buf_fill),
+			                       boundary,
+			                       bl);
+
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
+				/* Store the content to a file */
+				if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fstore) == 0) {
+					fstore.access.fp = NULL;
+				}
+				file_size = 0;
+
+				if (!fstore.access.fp) {
+					mg_cry_internal(conn,
+					                "%s: Cannot create file %s",
+					                __func__,
+					                path);
+				}
+			}
+
+			get_block = 0;
+			while (!next) {
+				/* Set "towrite" to the number of bytes available
+				 * in the buffer */
+				towrite = (size_t)(buf - hend + buf_fill);
+				/* Subtract the boundary length, to deal with
+				 * cases the boundary is only partially stored
+				 * in the buffer. */
+				towrite -= bl + 4;
+
+				if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
+					unencoded_field_get(conn,
+					                    ((get_block > 0) ? NULL : nbeg),
+					                    ((get_block > 0)
+					                         ? 0
+					                         : (size_t)(nend - nbeg)),
+					                    hend,
+					                    towrite,
+					                    fdh);
+					get_block++;
+				}
+
+				if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
+					if (fstore.access.fp) {
+
+						/* Store the content of the buffer. */
+						n = (size_t)fwrite(hend, 1, towrite, fstore.access.fp);
+						if ((n != towrite) || (ferror(fstore.access.fp))) {
+							mg_cry_internal(conn,
+							                "%s: Cannot write file %s",
+							                __func__,
+							                path);
+							mg_fclose(&fstore.access);
+							remove_bad_file(conn, path);
+						}
+						file_size += (int64_t)n;
+					}
+				}
+
+				memmove(buf, hend + towrite, bl + 4);
+				buf_fill = (int)(bl + 4);
+				hend = buf;
+
+				/* Read new data */
+				r = mg_read(conn,
+				            buf + (size_t)buf_fill,
+				            sizeof(buf) - 1 - (size_t)buf_fill);
+				if (r < 0) {
+					/* read error */
+					if (fstore.access.fp) {
+						mg_fclose(&fstore.access);
+						remove_bad_file(conn, path);
+					}
+					mg_free(boundary);
+					return -1;
+				}
+				buf_fill += r;
+				buf[buf_fill] = 0;
+				/* buf_fill is at least 8 here */
+
+				/* Find boundary */
+				next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
+			}
+
+			towrite = (size_t)(next - hend);
+
+			if (field_storage == MG_FORM_FIELD_STORAGE_GET) {
+				/* Call callback */
+				unencoded_field_get(conn,
+				                    ((get_block > 0) ? NULL : nbeg),
+				                    ((get_block > 0) ? 0
+				                                     : (size_t)(nend - nbeg)),
+				                    hend,
+				                    towrite,
+				                    fdh);
+			}
+
+			if (field_storage == MG_FORM_FIELD_STORAGE_STORE) {
+
+				if (fstore.access.fp) {
+					n = (size_t)fwrite(hend, 1, towrite, fstore.access.fp);
+					if ((n != towrite) || (ferror(fstore.access.fp))) {
+						mg_cry_internal(conn,
+						                "%s: Cannot write file %s",
+						                __func__,
+						                path);
+						mg_fclose(&fstore.access);
+						remove_bad_file(conn, path);
+					} else {
+						file_size += (int64_t)n;
+						r = mg_fclose(&fstore.access);
+						if (r == 0) {
+							/* stored successfully */
+							field_stored(conn, path, file_size, fdh);
+						} else {
+							mg_cry_internal(conn,
+							                "%s: Error saving file %s",
+							                __func__,
+							                path);
+							remove_bad_file(conn, path);
+						}
+					}
+					fstore.access.fp = NULL;
+				}
+			}
+
+			if ((field_storage & MG_FORM_FIELD_STORAGE_ABORT)
+			    == MG_FORM_FIELD_STORAGE_ABORT) {
+				/* Stop parsing the request */
+				break;
+			}
+
+			/* Remove from the buffer */
+			used = next - buf + 2;
+			memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
+			buf_fill -= (int)used;
+		}
+
+		/* All parts handled */
+		mg_free(boundary);
+		return field_count;
+	}
+
+	/* Unknown Content-Type */
+	return -1;
+}
+
+
+/* End of handle_form.inl */


[3/6] celix git commit: CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

Posted by pn...@apache.org.
http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/md5.inl
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/civetweb/md5.inl b/examples/celix-examples/civetweb/civetweb/md5.inl
new file mode 100644
index 0000000..beb1cf9
--- /dev/null
+++ b/examples/celix-examples/civetweb/civetweb/md5.inl
@@ -0,0 +1,471 @@
+/*
+ * This an amalgamation of md5.c and md5.h into a single file
+ * with all static declaration to reduce linker conflicts
+ * in Civetweb.
+ *
+ * The MD5_STATIC declaration was added to facilitate static
+ * inclusion.
+ * No Face Press, LLC
+ */
+
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+    http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <gh...@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Removed support for non-ANSI compilers; removed
+    references to Ghostscript; clarified derivation from RFC 1321;
+    now handles byte order either statically or dynamically.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+    added conditionalization for C++ compilation from Martin
+    Purschke <pu...@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#if !defined(md5_INCLUDED)
+#define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t;  /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+	md5_word_t count[2]; /* message length in bits, lsw first */
+	md5_word_t abcd[4];  /* digest buffer */
+	md5_byte_t buf[64];  /* accumulate block */
+} md5_state_t;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Initialize the algorithm. */
+MD5_STATIC void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+MD5_STATIC void
+md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
+
+/* Finish the message and return the digest. */
+MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#if defined(__cplusplus)
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
+
+/*
+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321, whose
+  text is available at
+    http://www.ietf.org/rfc/rfc1321.txt
+  The code is derived from the text of the RFC, including the test suite
+  (section A.5) but excluding the rest of Appendix A.  It does not include
+  any code or documentation that is identified in the RFC as being
+  copyrighted.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <gh...@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+    either statically or dynamically; added missing #include <string.h>
+    in library.
+  2002-03-11 lpd Corrected argument list for main(), and added int return
+    type, in test program and T value program.
+  2002-02-21 lpd Added missing #include <stdio.h> in test program.
+  2000-07-03 lpd Patched to eliminate warnings about "constant is
+    unsigned in ANSI C, signed in traditional"; made test program
+    self-checking.
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#if !defined(MD5_STATIC)
+#include <string.h>
+#endif
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#if defined(ARCH_IS_BIG_ENDIAN)
+#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#define BYTE_ORDER (0)
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 (0x242070db)
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 (0x4787c62a)
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 (0x698098d8)
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 (0x6b901122)
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 (0x49b40821)
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 (0x265e5a51)
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 (0x02441453)
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 (0x21e1cde6)
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 (0x455a14ed)
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 (0x676f02d9)
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 (0x6d9d6122)
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 (0x4bdecfa9)
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 (0x289b7ec6)
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 (0x04881d05)
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 (0x1fa27cf8)
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 (0x432aff97)
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 (0x655b59c3)
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 (0x6fa87e4f)
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 (0x4e0811a1)
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 (0x2ad7d2bb)
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+	md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
+	           d = pms->abcd[3];
+	md5_word_t t;
+#if BYTE_ORDER > 0
+	/* Define storage only for big-endian CPUs. */
+	md5_word_t X[16];
+#else
+	/* Define storage for little-endian or both types of CPUs. */
+	md5_word_t xbuf[16];
+	const md5_word_t *X;
+#endif
+
+	{
+#if BYTE_ORDER == 0
+		/*
+		 * Determine dynamically whether this is a big-endian or
+		 * little-endian machine, since we can use a more efficient
+		 * algorithm on the latter.
+		 */
+		static const int w = 1;
+
+		if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+		{
+			/*
+			 * On little-endian machines, we can process properly aligned
+			 * data without copying it.
+			 */
+			if (!((data - (const md5_byte_t *)0) & 3)) {
+				/* data are properly aligned, a direct assignment is possible */
+				/* cast through a (void *) should avoid a compiler warning,
+				   see
+				   https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
+				   */
+				X = (const md5_word_t *)(const void *)data;
+			} else {
+				/* not aligned */
+				memcpy(xbuf, data, 64);
+				X = xbuf;
+			}
+		}
+#endif
+#if BYTE_ORDER == 0
+		else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+		{
+			/*
+			 * On big-endian machines, we must arrange the bytes in the
+			 * right order.
+			 */
+			const md5_byte_t *xp = data;
+			int i;
+
+#if BYTE_ORDER == 0
+			X = xbuf; /* (dynamic only) */
+#else
+#define xbuf X /* (static only) */
+#endif
+			for (i = 0; i < 16; ++i, xp += 4)
+				xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8)
+				          + (md5_word_t)(xp[2] << 16)
+				          + (md5_word_t)(xp[3] << 24);
+		}
+#endif
+	}
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/* Round 1. */
+/* Let [abcd k s i] denote the operation
+   a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)                                              \
+	t = a + F(b, c, d) + X[k] + Ti;                                            \
+	a = ROTATE_LEFT(t, s) + b
+
+	/* Do the following 16 operations. */
+	SET(a, b, c, d, 0, 7, T1);
+	SET(d, a, b, c, 1, 12, T2);
+	SET(c, d, a, b, 2, 17, T3);
+	SET(b, c, d, a, 3, 22, T4);
+	SET(a, b, c, d, 4, 7, T5);
+	SET(d, a, b, c, 5, 12, T6);
+	SET(c, d, a, b, 6, 17, T7);
+	SET(b, c, d, a, 7, 22, T8);
+	SET(a, b, c, d, 8, 7, T9);
+	SET(d, a, b, c, 9, 12, T10);
+	SET(c, d, a, b, 10, 17, T11);
+	SET(b, c, d, a, 11, 22, T12);
+	SET(a, b, c, d, 12, 7, T13);
+	SET(d, a, b, c, 13, 12, T14);
+	SET(c, d, a, b, 14, 17, T15);
+	SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+/* Round 2. */
+/* Let [abcd k s i] denote the operation
+     a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)                                              \
+	t = a + G(b, c, d) + X[k] + Ti;                                            \
+	a = ROTATE_LEFT(t, s) + b
+
+	/* Do the following 16 operations. */
+	SET(a, b, c, d, 1, 5, T17);
+	SET(d, a, b, c, 6, 9, T18);
+	SET(c, d, a, b, 11, 14, T19);
+	SET(b, c, d, a, 0, 20, T20);
+	SET(a, b, c, d, 5, 5, T21);
+	SET(d, a, b, c, 10, 9, T22);
+	SET(c, d, a, b, 15, 14, T23);
+	SET(b, c, d, a, 4, 20, T24);
+	SET(a, b, c, d, 9, 5, T25);
+	SET(d, a, b, c, 14, 9, T26);
+	SET(c, d, a, b, 3, 14, T27);
+	SET(b, c, d, a, 8, 20, T28);
+	SET(a, b, c, d, 13, 5, T29);
+	SET(d, a, b, c, 2, 9, T30);
+	SET(c, d, a, b, 7, 14, T31);
+	SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+/* Round 3. */
+/* Let [abcd k s t] denote the operation
+     a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)                                              \
+	t = a + H(b, c, d) + X[k] + Ti;                                            \
+	a = ROTATE_LEFT(t, s) + b
+
+	/* Do the following 16 operations. */
+	SET(a, b, c, d, 5, 4, T33);
+	SET(d, a, b, c, 8, 11, T34);
+	SET(c, d, a, b, 11, 16, T35);
+	SET(b, c, d, a, 14, 23, T36);
+	SET(a, b, c, d, 1, 4, T37);
+	SET(d, a, b, c, 4, 11, T38);
+	SET(c, d, a, b, 7, 16, T39);
+	SET(b, c, d, a, 10, 23, T40);
+	SET(a, b, c, d, 13, 4, T41);
+	SET(d, a, b, c, 0, 11, T42);
+	SET(c, d, a, b, 3, 16, T43);
+	SET(b, c, d, a, 6, 23, T44);
+	SET(a, b, c, d, 9, 4, T45);
+	SET(d, a, b, c, 12, 11, T46);
+	SET(c, d, a, b, 15, 16, T47);
+	SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+/* Round 4. */
+/* Let [abcd k s t] denote the operation
+     a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)                                              \
+	t = a + I(b, c, d) + X[k] + Ti;                                            \
+	a = ROTATE_LEFT(t, s) + b
+
+	/* Do the following 16 operations. */
+	SET(a, b, c, d, 0, 6, T49);
+	SET(d, a, b, c, 7, 10, T50);
+	SET(c, d, a, b, 14, 15, T51);
+	SET(b, c, d, a, 5, 21, T52);
+	SET(a, b, c, d, 12, 6, T53);
+	SET(d, a, b, c, 3, 10, T54);
+	SET(c, d, a, b, 10, 15, T55);
+	SET(b, c, d, a, 1, 21, T56);
+	SET(a, b, c, d, 8, 6, T57);
+	SET(d, a, b, c, 15, 10, T58);
+	SET(c, d, a, b, 6, 15, T59);
+	SET(b, c, d, a, 13, 21, T60);
+	SET(a, b, c, d, 4, 6, T61);
+	SET(d, a, b, c, 11, 10, T62);
+	SET(c, d, a, b, 2, 15, T63);
+	SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+	/* Then perform the following additions. (That is increment each
+	   of the four registers by the value it had before this block
+	   was started.) */
+	pms->abcd[0] += a;
+	pms->abcd[1] += b;
+	pms->abcd[2] += c;
+	pms->abcd[3] += d;
+}
+
+MD5_STATIC void
+md5_init(md5_state_t *pms)
+{
+	pms->count[0] = pms->count[1] = 0;
+	pms->abcd[0] = 0x67452301;
+	pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+	pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+	pms->abcd[3] = 0x10325476;
+}
+
+MD5_STATIC void
+md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
+{
+	const md5_byte_t *p = data;
+	size_t left = nbytes;
+	size_t offset = (pms->count[0] >> 3) & 63;
+	md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+	if (nbytes <= 0)
+		return;
+
+	/* Update the message length. */
+	pms->count[1] += (md5_word_t)(nbytes >> 29);
+	pms->count[0] += nbits;
+	if (pms->count[0] < nbits)
+		pms->count[1]++;
+
+	/* Process an initial partial block. */
+	if (offset) {
+		size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+		memcpy(pms->buf + offset, p, copy);
+		if (offset + copy < 64)
+			return;
+		p += copy;
+		left -= copy;
+		md5_process(pms, pms->buf);
+	}
+
+	/* Process full blocks. */
+	for (; left >= 64; p += 64, left -= 64)
+		md5_process(pms, p);
+
+	/* Process a final partial block. */
+	if (left)
+		memcpy(pms->buf, p, left);
+}
+
+MD5_STATIC void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+	static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	                                   0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	                                   0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	                                   0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	                                   0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+	md5_byte_t data[8];
+	int i;
+
+	/* Save the length before padding. */
+	for (i = 0; i < 8; ++i)
+		data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+	/* Pad to 56 bytes mod 64. */
+	md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+	/* Append the length. */
+	md5_append(pms, data, 8);
+	for (i = 0; i < 16; ++i)
+		digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+
+/* End of md5.inl */

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/sha1.inl
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/civetweb/sha1.inl b/examples/celix-examples/civetweb/civetweb/sha1.inl
new file mode 100644
index 0000000..0a2ae46
--- /dev/null
+++ b/examples/celix-examples/civetweb/civetweb/sha1.inl
@@ -0,0 +1,323 @@
+/*
+SHA-1 in C
+By Steve Reid <sr...@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jb...@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+    void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned int
+len)
+to
+    void SHA1Update(SHA_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it.  This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sr...@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Sa...@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 07/2002
+By Ralph Giles <gi...@ghostscript.com>
+Still 100% public domain
+modified for use with stdint types, autoconf
+code cleanup, removed attribution comments
+switched SHA1Final() argument order for consistency
+use SHA1_ prefix for public api
+move public api to sha1.h
+*/
+
+/*
+11/2016 adapted for CivetWeb:
+  include sha1.h in sha1.c,
+  rename to sha1.inl
+  remove unused #ifdef sections
+  make endian independent
+  align buffer to 4 bytes
+  remove unused variable assignments
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#include <string.h>
+#include <stdint.h>
+
+typedef struct {
+	uint32_t state[5];
+	uint32_t count[2];
+	uint8_t buffer[64];
+} SHA_CTX;
+
+#define SHA1_DIGEST_SIZE 20
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+
+
+typedef union {
+	uint8_t c[64];
+	uint32_t l[16];
+} CHAR64LONG16;
+
+
+static uint32_t
+blk0(CHAR64LONG16 *block, int i)
+{
+	static const uint32_t n = 1u;
+	if ((*((uint8_t *)(&n))) == 1) {
+		/* little endian / intel byte order */
+		block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00)
+		              | (rol(block->l[i], 8) & 0x00FF00FF);
+	}
+	return block->l[i];
+}
+
+#define blk(block, i)                                                          \
+	((block)->l[(i)&15] =                                                      \
+	     rol((block)->l[((i) + 13) & 15] ^ (block)->l[((i) + 8) & 15]          \
+	             ^ (block)->l[((i) + 2) & 15] ^ (block)->l[(i)&15],            \
+	         1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v, w, x, y, z, i)                                                   \
+	z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5);        \
+	w = rol(w, 30);
+#define R1(v, w, x, y, z, i)                                                   \
+	z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + rol(v, 5);         \
+	w = rol(w, 30);
+#define R2(v, w, x, y, z, i)                                                   \
+	z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + rol(v, 5);                 \
+	w = rol(w, 30);
+#define R3(v, w, x, y, z, i)                                                   \
+	z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + rol(v, 5);   \
+	w = rol(w, 30);
+#define R4(v, w, x, y, z, i)                                                   \
+	z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + rol(v, 5);                 \
+	w = rol(w, 30);
+
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+static void
+SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
+{
+	uint32_t a, b, c, d, e;
+
+	/* Must use an aligned, read/write buffer */
+	CHAR64LONG16 block[1];
+	memcpy(block, buffer, sizeof(block));
+
+	/* Copy context->state[] to working vars */
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+	e = state[4];
+
+	/* 4 rounds of 20 operations each. Loop unrolled. */
+	R0(a, b, c, d, e, 0);
+	R0(e, a, b, c, d, 1);
+	R0(d, e, a, b, c, 2);
+	R0(c, d, e, a, b, 3);
+	R0(b, c, d, e, a, 4);
+	R0(a, b, c, d, e, 5);
+	R0(e, a, b, c, d, 6);
+	R0(d, e, a, b, c, 7);
+	R0(c, d, e, a, b, 8);
+	R0(b, c, d, e, a, 9);
+	R0(a, b, c, d, e, 10);
+	R0(e, a, b, c, d, 11);
+	R0(d, e, a, b, c, 12);
+	R0(c, d, e, a, b, 13);
+	R0(b, c, d, e, a, 14);
+	R0(a, b, c, d, e, 15);
+	R1(e, a, b, c, d, 16);
+	R1(d, e, a, b, c, 17);
+	R1(c, d, e, a, b, 18);
+	R1(b, c, d, e, a, 19);
+	R2(a, b, c, d, e, 20);
+	R2(e, a, b, c, d, 21);
+	R2(d, e, a, b, c, 22);
+	R2(c, d, e, a, b, 23);
+	R2(b, c, d, e, a, 24);
+	R2(a, b, c, d, e, 25);
+	R2(e, a, b, c, d, 26);
+	R2(d, e, a, b, c, 27);
+	R2(c, d, e, a, b, 28);
+	R2(b, c, d, e, a, 29);
+	R2(a, b, c, d, e, 30);
+	R2(e, a, b, c, d, 31);
+	R2(d, e, a, b, c, 32);
+	R2(c, d, e, a, b, 33);
+	R2(b, c, d, e, a, 34);
+	R2(a, b, c, d, e, 35);
+	R2(e, a, b, c, d, 36);
+	R2(d, e, a, b, c, 37);
+	R2(c, d, e, a, b, 38);
+	R2(b, c, d, e, a, 39);
+	R3(a, b, c, d, e, 40);
+	R3(e, a, b, c, d, 41);
+	R3(d, e, a, b, c, 42);
+	R3(c, d, e, a, b, 43);
+	R3(b, c, d, e, a, 44);
+	R3(a, b, c, d, e, 45);
+	R3(e, a, b, c, d, 46);
+	R3(d, e, a, b, c, 47);
+	R3(c, d, e, a, b, 48);
+	R3(b, c, d, e, a, 49);
+	R3(a, b, c, d, e, 50);
+	R3(e, a, b, c, d, 51);
+	R3(d, e, a, b, c, 52);
+	R3(c, d, e, a, b, 53);
+	R3(b, c, d, e, a, 54);
+	R3(a, b, c, d, e, 55);
+	R3(e, a, b, c, d, 56);
+	R3(d, e, a, b, c, 57);
+	R3(c, d, e, a, b, 58);
+	R3(b, c, d, e, a, 59);
+	R4(a, b, c, d, e, 60);
+	R4(e, a, b, c, d, 61);
+	R4(d, e, a, b, c, 62);
+	R4(c, d, e, a, b, 63);
+	R4(b, c, d, e, a, 64);
+	R4(a, b, c, d, e, 65);
+	R4(e, a, b, c, d, 66);
+	R4(d, e, a, b, c, 67);
+	R4(c, d, e, a, b, 68);
+	R4(b, c, d, e, a, 69);
+	R4(a, b, c, d, e, 70);
+	R4(e, a, b, c, d, 71);
+	R4(d, e, a, b, c, 72);
+	R4(c, d, e, a, b, 73);
+	R4(b, c, d, e, a, 74);
+	R4(a, b, c, d, e, 75);
+	R4(e, a, b, c, d, 76);
+	R4(d, e, a, b, c, 77);
+	R4(c, d, e, a, b, 78);
+	R4(b, c, d, e, a, 79);
+
+	/* Add the working vars back into context.state[] */
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+	state[4] += e;
+}
+
+
+/* SHA1Init - Initialize new context */
+SHA_API void
+SHA1_Init(SHA_CTX *context)
+{
+	/* SHA1 initialization constants */
+	context->state[0] = 0x67452301;
+	context->state[1] = 0xEFCDAB89;
+	context->state[2] = 0x98BADCFE;
+	context->state[3] = 0x10325476;
+	context->state[4] = 0xC3D2E1F0;
+	context->count[0] = context->count[1] = 0;
+}
+
+
+SHA_API void
+SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
+{
+	uint32_t i, j;
+
+	j = context->count[0];
+	if ((context->count[0] += (len << 3)) < j) {
+		context->count[1]++;
+	}
+	context->count[1] += (len >> 29);
+	j = (j >> 3) & 63;
+	if ((j + len) > 63) {
+		i = 64 - j;
+		memcpy(&context->buffer[j], data, i);
+		SHA1_Transform(context->state, context->buffer);
+		for (; i + 63 < len; i += 64) {
+			SHA1_Transform(context->state, &data[i]);
+		}
+		j = 0;
+	} else {
+		i = 0;
+	}
+	memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+SHA_API void
+SHA1_Final(unsigned char *digest, SHA_CTX *context)
+{
+	uint32_t i;
+	uint8_t finalcount[8];
+
+	for (i = 0; i < 8; i++) {
+		finalcount[i] =
+		    (uint8_t)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8))
+		              & 255); /* Endian independent */
+	}
+	SHA1_Update(context, (uint8_t *)"\x80", 1);
+	while ((context->count[0] & 504) != 448) {
+		SHA1_Update(context, (uint8_t *)"\x00", 1);
+	}
+	SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
+	for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+		digest[i] =
+		    (uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+	}
+
+	/* Wipe variables */
+	memset(context, '\0', sizeof(*context));
+}
+
+
+/* End of sha1.inl */

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/civetweb/timer.inl
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/civetweb/timer.inl b/examples/celix-examples/civetweb/civetweb/timer.inl
new file mode 100644
index 0000000..eebbec0
--- /dev/null
+++ b/examples/celix-examples/civetweb/civetweb/timer.inl
@@ -0,0 +1,246 @@
+/* This file is part of the CivetWeb web server.
+ * See https://github.com/civetweb/civetweb/
+ * (C) 2014-2018 by the CivetWeb authors, MIT license.
+ */
+
+#if !defined(MAX_TIMERS)
+#define MAX_TIMERS MAX_WORKER_THREADS
+#endif
+
+typedef int (*taction)(void *arg);
+
+struct ttimer {
+	double time;
+	double period;
+	taction action;
+	void *arg;
+};
+
+struct ttimers {
+	pthread_t threadid;               /* Timer thread ID */
+	pthread_mutex_t mutex;            /* Protects timer lists */
+	struct ttimer timers[MAX_TIMERS]; /* List of timers */
+	unsigned timer_count;             /* Current size of timer list */
+};
+
+
+TIMER_API double
+timer_getcurrenttime(void)
+{
+#if defined(_WIN32)
+	/* GetTickCount returns milliseconds since system start as
+	 * unsigned 32 bit value. It will wrap around every 49.7 days.
+	 * We need to use a 64 bit counter (will wrap in 500 mio. years),
+	 * by adding the 32 bit difference since the last call to a
+	 * 64 bit counter. This algorithm will only work, if this
+	 * function is called at least once every 7 weeks. */
+	static DWORD last_tick;
+	static uint64_t now_tick64;
+
+	DWORD now_tick = GetTickCount();
+
+	now_tick64 += ((DWORD)(now_tick - last_tick));
+	last_tick = now_tick;
+	return (double)now_tick64 * 1.0E-3;
+#else
+	struct timespec now_ts;
+
+	clock_gettime(CLOCK_MONOTONIC, &now_ts);
+	return (double)now_ts.tv_sec + (double)now_ts.tv_nsec * 1.0E-9;
+#endif
+}
+
+
+TIMER_API int
+timer_add(struct mg_context *ctx,
+          double next_time,
+          double period,
+          int is_relative,
+          taction action,
+          void *arg)
+{
+	unsigned u, v;
+	int error = 0;
+	double now;
+
+	if (ctx->stop_flag) {
+		return 0;
+	}
+
+	now = timer_getcurrenttime();
+
+	/* HCP24: if is_relative = 0 and next_time < now
+	 *        action will be called so fast as possible
+	 *        if additional period > 0
+	 *        action will be called so fast as possible
+	 *        n times until (next_time + (n * period)) > now
+	 *        then the period is working
+	 * Solution:
+	 *        if next_time < now then we set next_time = now.
+	 *        The first callback will be so fast as possible (now)
+	 *        but the next callback on period
+	*/
+	if (is_relative) {
+		next_time += now;
+	}
+
+	/* You can not set timers into the past */
+	if (next_time < now) {
+		next_time = now;
+	}
+
+	pthread_mutex_lock(&ctx->timers->mutex);
+	if (ctx->timers->timer_count == MAX_TIMERS) {
+		error = 1;
+	} else {
+		/* Insert new timer into a sorted list. */
+		/* The linear list is still most efficient for short lists (small
+		 * number of timers) - if there are many timers, different
+		 * algorithms will work better. */
+		for (u = 0; u < ctx->timers->timer_count; u++) {
+			if (ctx->timers->timers[u].time > next_time) {
+				/* HCP24: moving all timers > next_time */
+				for (v = ctx->timers->timer_count; v > u; v--) {
+					ctx->timers->timers[v] = ctx->timers->timers[v - 1];
+				}
+				break;
+			}
+		}
+		ctx->timers->timers[u].time = next_time;
+		ctx->timers->timers[u].period = period;
+		ctx->timers->timers[u].action = action;
+		ctx->timers->timers[u].arg = arg;
+		ctx->timers->timer_count++;
+	}
+	pthread_mutex_unlock(&ctx->timers->mutex);
+	return error;
+}
+
+
+static void
+timer_thread_run(void *thread_func_param)
+{
+	struct mg_context *ctx = (struct mg_context *)thread_func_param;
+	double d;
+	unsigned u;
+	int re_schedule;
+	struct ttimer t;
+
+	mg_set_thread_name("timer");
+
+	if (ctx->callbacks.init_thread) {
+		/* Timer thread */
+		ctx->callbacks.init_thread(ctx, 2);
+	}
+
+	d = timer_getcurrenttime();
+
+	while (ctx->stop_flag == 0) {
+		pthread_mutex_lock(&ctx->timers->mutex);
+		if ((ctx->timers->timer_count > 0)
+		    && (d >= ctx->timers->timers[0].time)) {
+			t = ctx->timers->timers[0];
+			for (u = 1; u < ctx->timers->timer_count; u++) {
+				ctx->timers->timers[u - 1] = ctx->timers->timers[u];
+			}
+			ctx->timers->timer_count--;
+			pthread_mutex_unlock(&ctx->timers->mutex);
+			re_schedule = t.action(t.arg);
+			if (re_schedule && (t.period > 0)) {
+				timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg);
+			}
+			continue;
+		} else {
+			pthread_mutex_unlock(&ctx->timers->mutex);
+		}
+
+/* 10 ms seems reasonable.
+ * A faster loop (smaller sleep value) increases CPU load,
+ * a slower loop (higher sleep value) decreases timer accuracy.
+ */
+#if defined(_WIN32)
+		Sleep(10);
+#else
+		usleep(10000);
+#endif
+
+		d = timer_getcurrenttime();
+	}
+
+	pthread_mutex_lock(&ctx->timers->mutex);
+	ctx->timers->timer_count = 0;
+	pthread_mutex_unlock(&ctx->timers->mutex);
+}
+
+
+#if defined(_WIN32)
+static unsigned __stdcall timer_thread(void *thread_func_param)
+{
+	timer_thread_run(thread_func_param);
+	return 0;
+}
+#else
+static void *
+timer_thread(void *thread_func_param)
+{
+	struct sigaction sa;
+
+	/* Ignore SIGPIPE */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = SIG_IGN;
+	sigaction(SIGPIPE, &sa, NULL);
+
+	timer_thread_run(thread_func_param);
+	return NULL;
+}
+#endif /* _WIN32 */
+
+
+TIMER_API int
+timers_init(struct mg_context *ctx)
+{
+	/* Initialize timers data structure */
+	ctx->timers =
+	    (struct ttimers *)mg_calloc_ctx(sizeof(struct ttimers), 1, ctx);
+
+	if (!ctx->timers) {
+		return -1;
+	}
+
+	/* Initialize mutex */
+	if (0 != pthread_mutex_init(&ctx->timers->mutex, NULL)) {
+		mg_free((void *)(ctx->timers));
+		return -1;
+	}
+
+	/* For some systems timer_getcurrenttime does some initialization
+	 * during the first call. Call it once now, ignore the result. */
+	(void)timer_getcurrenttime();
+
+	/* Start timer thread */
+	mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid);
+
+	return 0;
+}
+
+
+TIMER_API void
+timers_exit(struct mg_context *ctx)
+{
+	if (ctx->timers) {
+		pthread_mutex_lock(&ctx->timers->mutex);
+		ctx->timers->timer_count = 0;
+
+		mg_join_thread(ctx->timers->threadid);
+
+		/* TODO: Do we really need to unlock the mutex, before
+		 * destroying it, if it's destroyed by the thread currently
+		 * owning the mutex? */
+		pthread_mutex_unlock(&ctx->timers->mutex);
+		(void)pthread_mutex_destroy(&ctx->timers->mutex);
+		mg_free(ctx->timers);
+	}
+}
+
+
+/* End of timer.inl */

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/resources/index.html
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/resources/index.html b/examples/celix-examples/civetweb/resources/index.html
new file mode 100644
index 0000000..ab46896
--- /dev/null
+++ b/examples/celix-examples/civetweb/resources/index.html
@@ -0,0 +1,34 @@
+<!--
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+-->
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8"/>
+    <title>Apache Celix Embedded Civetweb example</title>
+    <script src="script.js"></script>
+</head>
+<body>
+    <div>
+        <input type="text" id="command_input"/>
+        <input type="button" id="command_button" value="send"/>
+    </div>
+    <textarea rows="50" cols="80" id="console_output"></textarea>
+    <script>docReady();</script>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/resources/script.js
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/resources/script.js b/examples/celix-examples/civetweb/resources/script.js
new file mode 100644
index 0000000..588fbf6
--- /dev/null
+++ b/examples/celix-examples/civetweb/resources/script.js
@@ -0,0 +1,43 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+function docReady() {
+    var host = window.location.host;
+    var shellSocket = new WebSocket("ws://" + host + "/shellsocket");
+
+    shellSocket.onmessage = function (event) {
+        document.getElementById("console_output").value = event.data;
+    };
+    shellSocket.onopen = function (event) {
+        shellSocket.send("lb");
+    };
+
+    document.getElementById("command_button").onclick = function() {
+        input = document.getElementById("command_input").value;
+        shellSocket.send(input);
+    };
+
+    var input = document.getElementById("command_input");
+    input.addEventListener("keyup", function(event) {
+        event.preventDefault();
+        if (event.key === "Enter") {
+            document.getElementById("command_button").click();
+        }
+    });
+}

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/src/bundle_activator.c
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/src/bundle_activator.c b/examples/celix-examples/civetweb/src/bundle_activator.c
new file mode 100644
index 0000000..cae9616
--- /dev/null
+++ b/examples/celix-examples/civetweb/src/bundle_activator.c
@@ -0,0 +1,108 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements.  See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership.  The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+
+#include "celix_bundle_activator.h"
+#include "celix_bundle.h"
+#include "shell.h"
+
+#include <civetweb.h>
+#include <string.h>
+
+typedef struct activator_data {
+    celix_bundle_context_t *ctx;
+    char *root;
+    struct mg_context *mgCtx;
+} activator_data_t;
+
+struct use_shell_arg {
+    char *command;
+    struct mg_connection *conn;
+};
+
+static void useShell(void *handle, void *svc) {
+    shell_service_t *shell = svc;
+    struct use_shell_arg *arg = handle;
+    char *buf = NULL;
+    size_t size;
+    FILE *out = open_memstream(&buf, &size);
+    shell->executeCommand(shell->shell, (char*)arg->command, out, out);
+    fclose(out);
+    mg_websocket_write(arg->conn, MG_WEBSOCKET_OPCODE_TEXT, buf, size);
+};
+
+static int websocket_data_handler(struct mg_connection *conn, int bits, char *data, size_t data_len, void *handle) {
+    activator_data_t *act = handle;
+    struct use_shell_arg arg;
+    arg.conn = conn;
+
+    //NOTE data is a not null terminated string..
+    arg.command = calloc(data_len+1, sizeof(char));
+    memcpy(arg.command, data, data_len);
+    arg.command[data_len] = '\0';
+
+
+    bool called = celix_bundleContext_useService(act->ctx, OSGI_SHELL_SERVICE_NAME, &arg, useShell);
+    if (!called) {
+        fprintf(stderr, "No shell available!\n");
+    }
+
+    free(arg.command);
+    return 1; //keep open
+}
+
+
+static celix_status_t activator_start(activator_data_t *data, celix_bundle_context_t *ctx) {
+    data->ctx = ctx;
+
+    bundle_t *bnd = celix_bundleContext_getBundle(ctx);
+    data->root = celix_bundle_getEntry(bnd, "resources");
+
+    const char *options[] = {
+            "document_root", data->root,
+            "listening_ports", "8081",
+            "websocket_timeout_ms", "3600000",
+            NULL
+    };
+
+    if (data->root != NULL) {
+        data->mgCtx = mg_start(NULL, data, options);
+        mg_set_websocket_handler(data->mgCtx, "/shellsocket", NULL, NULL, websocket_data_handler, NULL, data);
+    }
+
+    if (data->mgCtx != NULL) {
+        fprintf(stdout, "Started civetweb at port %s\n", mg_get_option(data->mgCtx, "listening_ports"));
+    } else {
+        fprintf(stderr, "Error starting civetweb bundle\n");
+    }
+
+    return CELIX_SUCCESS;
+}
+
+static celix_status_t activator_stop(activator_data_t *data, celix_bundle_context_t *ctx) {
+    if (data->mgCtx != NULL) {
+        printf("Stopping civetweb\n");
+        mg_stop(data->mgCtx);
+        data->mgCtx = NULL;
+    }
+    free(data->root);
+    return CELIX_SUCCESS;
+}
+
+CELIX_GEN_BUNDLE_ACTIVATOR(activator_data_t, activator_start, activator_stop)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/mongoose/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/celix-examples/mongoose/CMakeLists.txt b/examples/celix-examples/mongoose/CMakeLists.txt
deleted file mode 100644
index d0e94ae..0000000
--- a/examples/celix-examples/mongoose/CMakeLists.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-# 
-#   http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-add_library(mongooselib STATIC private/src/mongoose.c)
-SET_TARGET_PROPERTIES(mongooselib PROPERTIES COMPILE_FLAGS -fPIC)
-
-SET(BUNDLE_SYMBOLICNAME "apache_celix_examples_mongoose")
-SET(BUNDLE_VERSION "0.0.1")
-
-include_directories("private/include")
-include_directories("${PROJECT_SOURCE_DIR}/utils/public/include")
-
-if(WIN32)
-	  set(LIBS wsock32)
-endif(WIN32)
-
-add_celix_bundle(mongoose
-    VERSION 0.0.1
-    SOURCES
-        private/src/activator
-        private/include/mongoose.h
-)
-
-celix_bundle_files(mongoose ${CMAKE_CURRENT_LIST_DIR}/root)
-
-target_link_libraries(mongoose PRIVATE mongooselib ${LIBS})
-
-add_celix_container("mongoose_deploy" BUNDLES Celix::shell Celix::shell_tui Celix::log_service mongoose)

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/mongoose/private/include/mongoose.h
----------------------------------------------------------------------
diff --git a/examples/celix-examples/mongoose/private/include/mongoose.h b/examples/celix-examples/mongoose/private/include/mongoose.h
deleted file mode 100644
index a846df4..0000000
--- a/examples/celix-examples/mongoose/private/include/mongoose.h
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2004-2010 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.
-
-#ifndef MONGOOSE_HEADER_INCLUDED
-#define  MONGOOSE_HEADER_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-struct mg_context;     // Handle for the HTTP service itself
-struct mg_connection;  // Handle for the individual connection
-
-
-// This structure contains information about the HTTP request.
-struct mg_request_info {
-  char *request_method;  // "GET", "POST", etc
-  char *uri;             // URL-decoded URI
-  char *http_version;    // E.g. "1.0", "1.1"
-  char *query_string;    // \0 - terminated
-  char *remote_user;     // Authenticated user
-  char *log_message;     // Mongoose error log message
-  long remote_ip;        // Client's IP address
-  int remote_port;       // Client's port
-  int status_code;       // HTTP reply status code
-  int is_ssl;            // 1 if SSL-ed, 0 if not
-  int num_headers;       // Number of headers
-  struct mg_header {
-    char *name;          // HTTP header name
-    char *value;         // HTTP header value
-  } http_headers[64];    // Maximum 64 headers
-};
-
-// Various events on which user-defined function is called by Mongoose.
-enum mg_event {
-  MG_NEW_REQUEST,   // New HTTP request has arrived from the client
-  MG_HTTP_ERROR,    // HTTP error must be returned to the client
-  MG_EVENT_LOG,     // Mongoose logs an event, request_info.log_message
-  MG_INIT_SSL,      // Mongoose initializes SSL. Instead of mg_connection *,
-                    // SSL context is passed to the callback function.
-};
-
-// Prototype for the user-defined function. Mongoose calls this function
-// on every event mentioned above.
-//
-// Parameters:
-//   event: which event has been triggered.
-//   conn: opaque connection handler. Could be used to read, write data to the
-//         client, etc. See functions below that accept "mg_connection *".
-//   request_info: Information about HTTP request.
-//
-// Return:
-//   If handler returns non-NULL, that means that handler has processed the
-//   request by sending appropriate HTTP reply to the client. Mongoose treats
-//   the request as served.
-//   If callback returns NULL, that means that callback has not processed
-//   the request. Handler must not send any data to the client in this case.
-//   Mongoose proceeds with request handling as if nothing happened.
-typedef void * (*mg_callback_pt)(enum mg_event event,
-                                struct mg_connection *conn,
-                                const struct mg_request_info *request_info);
-  
-
-// Start web server.
-//
-// Parameters:
-//   callback: user defined event handling function or NULL.
-//   options: NULL terminated list of option_name, option_value pairs that
-//            specify Mongoose configuration parameters.
-//
-// Example:
-//   const char *options[] = {
-//     "document_root", "/var/www",
-//     "listening_ports", "80,443s",
-//     NULL
-//   };
-//   struct mg_context *ctx = mg_start(&my_func, options);
-//
-// Please refer to http://code.google.com/p/mongoose/wiki/MongooseManual
-// for the list of valid option and their possible values.
-//
-// Return:
-//   web server context, or NULL on error.
-struct mg_context *mg_start(mg_callback_pt callback, const char **options);
-
-
-// Stop the web server.
-//
-// Must be called last, when an application wants to stop the web server and
-// release all associated resources. This function blocks until all Mongoose
-// threads are stopped. Context pointer becomes invalid.
-void mg_stop(struct mg_context *);
-
-
-// Get the value of particular configuration parameter.
-// The value returned is read-only. Mongoose does not allow changing
-// configuration at run time.
-// If given parameter name is not valid, NULL is returned. For valid
-// names, return value is guaranteed to be non-NULL. If parameter is not
-// set, zero-length string is returned.
-const char *mg_get_option(const struct mg_context *ctx, const char *name);
-
-
-// Return array of strings that represent valid configuration options.
-// For each option, a short name, long name, and default value is returned.
-// Array is NULL terminated.
-const char **mg_get_valid_option_names(void);
-
-
-// Add, edit or delete the entry in the passwords file.
-//
-// This function allows an application to manipulate .htpasswd files on the
-// fly by adding, deleting and changing user records. This is one of the
-// several ways of implementing authentication on the server side. For another,
-// cookie-based way please refer to the examples/chat.c in the source tree.
-//
-// If password is not NULL, entry is added (or modified if already exists).
-// If password is NULL, entry is deleted.
-//
-// Return:
-//   1 on success, 0 on error.
-int mg_modify_passwords_file(struct mg_context *ctx, 
-    const char *passwords_file_name, const char *user, const char *password);
-
-// Send data to the client.
-int mg_write(struct mg_connection *, const void *buf, size_t len);
-
-
-// Send data to the browser using printf() semantics.
-//
-// Works exactly like mg_write(), but allows to do message formatting.
-// Note that mg_printf() uses internal buffer of size IO_BUF_SIZE
-// (8 Kb by default) as temporary message storage for formatting. Do not
-// print data that is bigger than that, otherwise it will be truncated.
-int mg_printf(struct mg_connection *, const char *fmt, ...);
-
-
-// Read data from the remote end, return number of bytes read.
-int mg_read(struct mg_connection *, void *buf, size_t len);
-
-
-// Get the value of particular HTTP header.
-//
-// This is a helper function. It traverses request_info->http_headers array,
-// and if the header is present in the array, returns its value. If it is
-// not present, NULL is returned.
-const char *mg_get_header(const struct mg_connection *, const char *name);
-
-
-// Get a value of particular form variable.
-//
-// Parameters:
-//   data: pointer to form-uri-encoded buffer. This could be either POST data,
-//         or request_info.query_string.
-//   data_len: length of the encoded data.
-//   var_name: variable name to decode from the buffer
-//   buf: destination buffer for the decoded variable
-//   buf_len: length of the destination buffer
-//
-// Return:
-//   On success, length of the decoded variable.
-//   On error, -1 (variable not found, or destination buffer is too small).
-//
-// Destination buffer is guaranteed to be '\0' - terminated. In case of
-// failure, dst[0] == '\0'.
-int mg_get_var(const char *data, size_t data_len,
-    const char *var_name, char *buf, size_t buf_len);
-
-// Fetch value of certain cookie variable into the destination buffer.
-//
-// Destination buffer is guaranteed to be '\0' - terminated. In case of
-// failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
-// parameter. This function returns only first occurrence.
-//
-// Return:
-//   On success, value length.
-//   On error, -1 (either "Cookie:" header is not present at all, or the
-//   requested parameter is not found, or destination buffer is too small
-//   to hold the value).
-int mg_get_cookie(const struct mg_connection *,
-    const char *cookie_name, char *buf, size_t buf_len);
-
-
-// Return Mongoose version.
-const char *mg_version(void);
-
-
-// MD5 hash given strings.
-// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
-// asciiz strings. When function returns, buf will contain human-readable
-// MD5 hash. Example:
-//   char buf[33];
-//   mg_md5(buf, "aa", "bb", NULL);
-void mg_md5(char *buf, ...);
-
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif // MONGOOSE_HEADER_INCLUDED

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/mongoose/private/src/activator.c
----------------------------------------------------------------------
diff --git a/examples/celix-examples/mongoose/private/src/activator.c b/examples/celix-examples/mongoose/private/src/activator.c
deleted file mode 100644
index beea9df..0000000
--- a/examples/celix-examples/mongoose/private/src/activator.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- *Licensed to the Apache Software Foundation (ASF) under one
- *or more contributor license agreements.  See the NOTICE file
- *distributed with this work for additional information
- *regarding copyright ownership.  The ASF licenses this file
- *to you under the Apache License, Version 2.0 (the
- *"License"); you may not use this file except in compliance
- *with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *Unless required by applicable law or agreed to in writing,
- *software distributed under the License is distributed on an
- *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- *specific language governing permissions and limitations
- *under the License.
- */
-/*
- * activator.c
- *
- *  \date       Aug 20, 2010
- *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- *  \copyright	Apache License, Version 2.0
- */
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "bundle_activator.h"
-#include "mongoose.h"
-
-struct userData {
-	struct mg_context *ctx;
-    char* entry;
-};
-
-celix_status_t bundleActivator_create(bundle_context_pt  __attribute__((unused)) context, void **userData) {
-	*userData = calloc(1, sizeof(struct userData));
-	return CELIX_SUCCESS;
-}
-
-celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
-	bundle_pt bundle;
-	celix_status_t status = CELIX_SUCCESS;
-	struct userData * data = (struct userData *) userData;
-
-	if (bundleContext_getBundle(context, &bundle) == CELIX_SUCCESS) {
-		bundle_getEntry(bundle, "root", &data->entry);
-		const char *options[] = {
-			"document_root", data->entry,
-			"listening_ports", "8081",
-			NULL
-		};
-
-		data->ctx = mg_start(NULL, options);
-
-		if (data->ctx) {
-			printf("Mongoose started on: %s\n", mg_get_option(data->ctx, "listening_ports"));
-		}
-	} else {
-		status = CELIX_START_ERROR;
-	}
-
-	return status;
-}
-
-celix_status_t bundleActivator_stop(void * userData, bundle_context_pt  __attribute__((unused)) context) {
-	struct userData * data = (struct userData *) userData;
-	mg_stop(data->ctx);
-	printf("Mongoose stopped\n");
-	return CELIX_SUCCESS;
-}
-
-celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt  __attribute__((unused)) context) {
-	struct userData * data = (struct userData *) userData;
-    free(data->entry);
-	free(data);
-	return CELIX_SUCCESS;
-}


[6/6] celix git commit: CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

Posted by pn...@apache.org.
CELIX-451: Adds celix_bundle_dir for copying files. Also remove mongoose example and adds a new civetweb example.

- The celix_bundle_dir also copy files again if they are updated
- The mongoose example was removed, because the updated version of mongoose is now GPL
- The civetweb example also uses a websocket


Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/c4de9077
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/c4de9077
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/c4de9077

Branch: refs/heads/develop
Commit: c4de9077dce47e13f4a084aa493f3e05a94b8408
Parents: 3f24edf
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Tue Jul 3 22:43:27 2018 +0200
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Tue Jul 3 22:43:27 2018 +0200

----------------------------------------------------------------------
 cmake/cmake_celix/BundlePackaging.cmake         |    67 +-
 examples/celix-examples/CMakeLists.txt          |     2 +-
 examples/celix-examples/civetweb/CMakeLists.txt |    37 +
 .../celix-examples/civetweb/civetweb/civetweb.c | 19792 +++++++++++++++++
 .../celix-examples/civetweb/civetweb/civetweb.h |  1498 ++
 .../civetweb/civetweb/handle_form.inl           |   981 +
 .../celix-examples/civetweb/civetweb/md5.inl    |   471 +
 .../celix-examples/civetweb/civetweb/sha1.inl   |   323 +
 .../celix-examples/civetweb/civetweb/timer.inl  |   246 +
 .../civetweb/resources/index.html               |    34 +
 .../celix-examples/civetweb/resources/script.js |    43 +
 .../civetweb/src/bundle_activator.c             |   108 +
 examples/celix-examples/mongoose/CMakeLists.txt |    42 -
 .../mongoose/private/include/mongoose.h         |   218 -
 .../mongoose/private/src/activator.c            |    79 -
 .../mongoose/private/src/mongoose.c             |  4076 ----
 .../celix-examples/mongoose/root/index.html     |    23 -
 17 files changed, 23595 insertions(+), 4445 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/cmake/cmake_celix/BundlePackaging.cmake
----------------------------------------------------------------------
diff --git a/cmake/cmake_celix/BundlePackaging.cmake b/cmake/cmake_celix/BundlePackaging.cmake
index 6666d20..35f5c0a 100644
--- a/cmake/cmake_celix/BundlePackaging.cmake
+++ b/cmake/cmake_celix/BundlePackaging.cmake
@@ -340,15 +340,26 @@ function(celix_bundle_libs)
             endif()
             list(APPEND DEPS ${OUT}) 
         elseif (TARGET ${LIB})
+            get_target_property(TARGET_TYPE ${LIB} TYPE)
             #Assuming target
             #NOTE add_custom_command does not support generator expression in OUTPUT value (e.g. $<TARGET_FILE:${LIB}>)
             #Using a two step approach to be able to use add_custom_command instead of add_custom_target
             set(OUT "${BUNDLE_GEN_DIR}/lib-${LIBID}-copy-timestamp")
-            add_custom_command(OUTPUT ${OUT}
-                COMMAND ${CMAKE_COMMAND} -E touch ${OUT}
-                COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:${LIB}>" "${BUNDLE_DIR}/$<TARGET_SONAME_FILE_NAME:${LIB}>"
-                DEPENDS ${LIB}
-            )
+            if ("${TARGET_TYPE}" STREQUAL "STATIC_LIBRARY")
+                add_custom_command(OUTPUT ${OUT}
+                    COMMAND ${CMAKE_COMMAND} -E touch ${OUT}
+                    COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:${LIB}>" "${BUNDLE_DIR}/$<TARGET_FILE_NAME:${LIB}>"
+                    DEPENDS ${LIB}
+                )
+            elseif ("${TARGET_TYPE}" STREQUAL "SHARED_LIBRARY")
+                add_custom_command(OUTPUT ${OUT}
+                    COMMAND ${CMAKE_COMMAND} -E touch ${OUT}
+                    COMMAND ${CMAKE_COMMAND} -E copy_if_different "$<TARGET_FILE:${LIB}>" "${BUNDLE_DIR}/$<TARGET_SONAME_FILE_NAME:${LIB}>"
+                    DEPENDS ${LIB}
+                    )
+            else()
+                message(FATAL_ERROR "Unexptected target type (${TARGET_TYPE}) for target ${LIB}. Not a library")
+            endif()
             if (ADD_TO_MANIFEST)
                 list(APPEND LIBS "$<TARGET_SONAME_FILE_NAME:${LIB}>")
             endif()
@@ -404,9 +415,9 @@ function(bundle_files)
     message(DEPRECATION "bundle_files is deprecated, use celix_bundle_files instead.")
     celix_bundle_files(${ARGN})
 endfunction()
+#Note with celix_bundle_files, files are copied cmake generation time. Updates are not copied !!
 function(celix_bundle_files)
     #0 is bundle TARGET
-    #1..n is header name / header value
     list(GET ARGN 0 BUNDLE)
     list(REMOVE_AT ARGN 0)
 
@@ -427,6 +438,50 @@ function(celix_bundle_files)
     file(COPY ${FILES_UNPARSED_ARGUMENTS} DESTINATION ${DESTINATION})
 endfunction()
 
+#Note celix_bundle_dir copies the dir and can track changes.
+function(celix_bundle_dir)
+    #0 is bundle TARGET
+    list(GET ARGN 0 BUNDLE)
+    list(REMOVE_AT ARGN 0)
+
+    #1 is the input dir
+    list(GET ARGN 0 INPUT_DIR)
+    list(REMOVE_AT ARGN 0)
+
+    if (NOT BUNDLE OR NOT INPUT_DIR)
+        message(FATAL_ERROR "celix_bundle_dir must have atleast two arguments: BUNDLE_TARGET and INPUT_DIR!")
+    endif()
+
+    set(OPTIONS )
+    set(ONE_VAL_ARGS DESTINATION)
+    set(MULTI_VAL_ARGS )
+    cmake_parse_arguments(COPY "${OPTIONS}" "${ONE_VAL_ARGS}" "${MULTI_VAL_ARGS}" ${ARGN})
+
+    get_target_property(BUNDLE_DIR ${BUNDLE} "BUNDLE_CONTENT_DIR")
+    if (NOT COPY_DESTINATION)
+        set(DESTINATION "${BUNDLE_DIR}/${FILES_DESTINATION}")
+    else()
+        set(DESTINATION "${BUNDLE_DIR}")
+    endif()
+
+    set(COPY_CMAKE_SCRIPT "${CMAKE_BINARY_DIR}/celix/gen/bundles/${BUNDLE}/copy-${INPUT_DIR}.cmake")
+    file(WRITE ${COPY_CMAKE_SCRIPT}
+            "file(COPY ${CMAKE_CURRENT_LIST_DIR}/${INPUT_DIR} DESTINATION ${DESTINATION})")
+
+    set(TIMESTAMP "${CMAKE_BINARY_DIR}/celix/gen/bundles/${BUNDLE}/copy-${INPUT_DIR}.timestamp")
+    file(GLOB DIR_FILES ${INPUT_DIR})
+    add_custom_command(OUTPUT ${TIMESTAMP}
+            COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP}
+            COMMAND ${CMAKE_COMMAND} -P ${COPY_CMAKE_SCRIPT}
+            DEPENDS ${DIR_FILES}
+            COMMENT "Copying dir ${INPUT_DIR} to ${DESTINATION}"
+    )
+
+    get_target_property(DEPS ${BUNDLE} "BUNDLE_DEPEND_TARGETS")
+    list(APPEND DEPS "${TIMESTAMP}")
+    set_target_properties(${BUNDLE} PROPERTIES "BUNDLE_DEPEND_TARGETS" "${DEPS}")
+endfunction()
+
 function(bundle_headers)
     message(DEPRECATION "bundle_headers is deprecated, use celix_bundle_headers instead.")
     celix_bundle_headers(${ARGN})

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/celix-examples/CMakeLists.txt b/examples/celix-examples/CMakeLists.txt
index f11979f..86ed757 100644
--- a/examples/celix-examples/CMakeLists.txt
+++ b/examples/celix-examples/CMakeLists.txt
@@ -35,7 +35,7 @@ if (EXAMPLES)
     add_subdirectory(dm_example_cxx)
 
     if (NOT ANDROID)
-    	add_subdirectory(mongoose)
+        add_subdirectory(civetweb)
     endif()
     add_subdirectory(embedding)
     add_subdirectory(service_hook_example)

http://git-wip-us.apache.org/repos/asf/celix/blob/c4de9077/examples/celix-examples/civetweb/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/celix-examples/civetweb/CMakeLists.txt b/examples/celix-examples/civetweb/CMakeLists.txt
new file mode 100644
index 0000000..99926f9
--- /dev/null
+++ b/examples/celix-examples/civetweb/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+add_library(civetweb_static STATIC
+        civetweb/civetweb.c
+)
+target_include_directories(civetweb_static PUBLIC SYSTEM civetweb)
+target_compile_options(civetweb_static PRIVATE -Wno-format -Wno-implicit-function-declaration -DUSE_WEBSOCKET)
+
+add_celix_bundle(embedded_civetweb
+    VERSION 1.0.0
+    SOURCES src/bundle_activator.c
+)
+target_link_libraries(embedded_civetweb PRIVATE Celix::shell_api)
+celix_bundle_private_libs(embedded_civetweb civetweb_static)
+celix_bundle_dir(embedded_civetweb resources)
+
+add_celix_container(civetweb_example
+    BUNDLES
+        Celix::shell
+        Celix::shell_tui
+        embedded_civetweb
+)
\ No newline at end of file