Repository: celix Updated Branches: refs/heads/develop 3b36eb2f8 -> 654f4252c refs/heads/feature/CELIX-247_android_support 654f4252c -> 13d3fec22
http://git-wip-us.apache.org/repos/asf/celix/blob/654f4252/remote_services/utils/private/src/civetweb.c ---------------------------------------------------------------------- diff --git a/remote_services/utils/private/src/civetweb.c b/remote_services/utils/private/src/civetweb.c index 0069307..94009c9 100644 --- a/remote_services/utils/private/src/civetweb.c +++ b/remote_services/utils/private/src/civetweb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015 the Civetweb developers + /* Copyright (c) 2013-2015 the Civetweb developers * Copyright (c) 2004-2013 Sergey Lyubka * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,77 +24,41 @@ #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */ #endif -#ifndef _WIN32_WINNT /* defined for tdm-gcc so we can use getnameinfo */ -#define _WIN32_WINNT 0x0501 -#endif #else -#if defined(__GNUC__) && !defined(_GNU_SOURCE) -#define _GNU_SOURCE /* for setgroups() */ -#endif #ifdef __linux__ -#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */ +#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */ #endif #ifndef _LARGEFILE_SOURCE -#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */ +#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */ #endif #ifndef _FILE_OFFSET_BITS -#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */ +#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */ #endif #ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */ +#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */ #endif #ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */ -#endif -#ifdef __sun -#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */ -#define __inline inline /* not recognized on older compiler versions */ +#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */ #endif #endif -#if defined(_MSC_VER) +#if defined (_MSC_VER) /* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */ -#pragma warning(disable : 4306) +#pragma warning (disable : 4306 ) /* conditional expression is constant: introduced by FD_SET(..) */ -#pragma warning(disable : 4127) +#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) +#pragma warning (disable : 4204) #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(_MSC_VER) && (_MSC_VER >= 1600) -#define mg_static_assert static_assert -#elif defined(__cplusplus) && (__cplusplus >= 201103L) -#define mg_static_assert static_assert -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) -#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] +/* Disable WIN32_LEAN_AND_MEAN. + This makes windows.h always include winsock2.h */ +#if defined(WIN32_LEAN_AND_MEAN) +#undef WIN32_LEAN_AND_MEAN #endif -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"); -/* mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t data - * type size check"); */ - -/* DTL -- including winsock2.h works better if lean and mean */ -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN +#if defined USE_IPV6 && defined(_WIN32) +#include <ws2tcpip.h> #endif #if defined(__SYMBIAN32__) @@ -104,7 +68,7 @@ mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); #endif /* __SYMBIAN32__ */ #ifndef IGNORE_UNUSED_RESULT -#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) +#define IGNORE_UNUSED_RESULT(a) (void)((a) && 1) #endif #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */ @@ -115,61 +79,6 @@ mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check"); #include <fcntl.h> #endif /* !_WIN32_WCE */ -#ifdef __MACH__ - -#define CLOCK_MONOTONIC (1) -#define CLOCK_REALTIME (2) - -#include <sys/time.h> -#include <mach/clock.h> -#include <mach/mach.h> -#include <mach/mach_time.h> -#include <assert.h> - -/* clock_gettime is not implemented on OSX */ -int clock_gettime(int clk_id, struct timespec *t); - -int clock_gettime(int clk_id, struct timespec *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 start_time = 0; - static mach_timebase_info_data_t timebase_ifo = {0, 0}; - - uint64_t now = mach_absolute_time(); - - if (start_time == 0) { - kern_return_t mach_status = mach_timebase_info(&timebase_ifo); -#if defined(DEBUG) - assert(mach_status == KERN_SUCCESS); -#else - /* appease "unused variable" warning for release builds */ - (void)mach_status; -#endif - start_time = now; - } - - now = - (uint64_t)((double)(now - 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 */ -} -#endif - #include <time.h> #include <stdlib.h> #include <stdarg.h> @@ -181,32 +90,21 @@ int clock_gettime(int clk_id, struct timespec *t) #include <stdio.h> #ifndef MAX_WORKER_THREADS -#define MAX_WORKER_THREADS (1024 * 64) -#endif -#ifndef SOCKET_TIMEOUT_QUANTUM -#define SOCKET_TIMEOUT_QUANTUM (10000) +#define MAX_WORKER_THREADS (1024*64) #endif -mg_static_assert(MAX_WORKER_THREADS >= 1, - "worker threads must be a positive number"); - #if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */ -#include <windows.h> -#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */ -#include <ws2tcpip.h> - -typedef const char *SOCK_OPT_TYPE; - -#if !defined(PATH_MAX) -#define PATH_MAX (MAX_PATH) +#if defined(_MSC_VER) && _MSC_VER <= 1400 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */ #endif +#include <windows.h> +typedef const char * SOCK_OPT_TYPE; -#if !defined(PATH_MAX) -#define PATH_MAX (4096) +#ifndef PATH_MAX +#define PATH_MAX MAX_PATH #endif -mg_static_assert(PATH_MAX >= 1, "path length must be a positive number"); - #ifndef _IN_PORT_T #ifndef in_port_t #define in_port_t u_short @@ -217,96 +115,94 @@ mg_static_assert(PATH_MAX >= 1, "path length must be a positive number"); #include <process.h> #include <direct.h> #include <io.h> -#else /* _WIN32_WCE */ +#else /* _WIN32_WCE */ #define NO_CGI /* WinCE has no pipes */ typedef long off_t; -#define errno ((int)(GetLastError())) -#define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10)) +#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)) +#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) + The rest of MS compilers use __FUNCTION__, not C99 __func__ + Also use _strtoui64 on modern M$ compilers */ +#if defined(_MSC_VER) && _MSC_VER < 1300 #define STRX(x) #x #define STR(x) STRX(x) #define __func__ __FILE__ ":" STR(__LINE__) -#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x)) -#define strtoll(x, y, z) (_atoi64(x)) +#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 +#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 ((int)(GetLastError())) +#define ERRNO GetLastError() #define NO_SOCKLEN_T -#define SSL_LIB "ssleay32.dll" -#define CRYPTO_LIB "libeay32.dll" -#define O_NONBLOCK (0) -#ifndef W_OK +#define SSL_LIB "ssleay32.dll" +#define CRYPTO_LIB "libeay32.dll" +#define O_NONBLOCK 0 #define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */ -#endif #if !defined(EWOULDBLOCK) -#define EWOULDBLOCK WSAEWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK #endif /* !EWOULDBLOCK */ #define _POSIX_ -#define INT64_FMT "I64d" +#define INT64_FMT "I64d" #define WINCDECL __cdecl -#define SHUT_RD (0) -#define SHUT_WR (1) -#define SHUT_BOTH (2) +#define SHUT_WR 1 #define snprintf _snprintf #define vsnprintf _vsnprintf #define access _access -#define mg_sleep(x) (Sleep(x)) +#define mg_sleep(x) Sleep(x) #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) #ifndef popen -#define popen(x, y) (_popen(x, y)) +#define popen(x, y) _popen(x, y) #endif #ifndef pclose -#define pclose(x) (_pclose(x)) -#endif -#define close(x) (_close(x)) -#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y))) -#define RTLD_LAZY (0) -#define fseeko(x, y, z) (_lseeki64(_fileno(x), (y), (z))) -#define fdopen(x, y) (_fdopen((x), (y))) -#define write(x, y, z) (_write((x), (y), (unsigned)z)) -#define read(x, y, z) (_read((x), (y), (unsigned)z)) -#define flockfile(x) (EnterCriticalSection(&global_log_file_lock)) -#define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock)) -#define sleep(x) (Sleep((x)*1000)) -#define rmdir(x) (_rmdir(x)) +#define pclose(x) _pclose(x) +#endif +#define close(x) _close(x) +#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) +#define RTLD_LAZY 0 +#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z)) +#define fdopen(x, y) _fdopen((x), (y)) +#define write(x, y, z) _write((x), (y), (unsigned) z) +#define read(x, y, z) _read((x), (y), (unsigned) z) +#define flockfile(x) EnterCriticalSection(&global_log_file_lock) +#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock) +#define sleep(x) Sleep((x) * 1000) +#define rmdir(x) _rmdir(x) #if defined(USE_LUA) && defined(USE_WEBSOCKET) #define USE_TIMERS #endif +#if !defined(va_copy) +#define va_copy(x, y) x = y +#endif /* !va_copy MINGW #defines va_copy */ + #if !defined(fileno) -#define fileno(x) (_fileno(x)) +#define fileno(x) _fileno(x) #endif /* !fileno MINGW #defines fileno */ typedef HANDLE pthread_mutex_t; typedef DWORD pthread_key_t; typedef HANDLE pthread_t; typedef struct { - CRITICAL_SECTION threadIdSec; - int waitingthreadcount; /* The number of threads queued. */ - pthread_t *waitingthreadhdls; /* The thread handles. */ + CRITICAL_SECTION threadIdSec; + int waitingthreadcount; /* The number of threads queued. */ + pthread_t *waitingthreadhdls; /* The thread handles. */ } pthread_cond_t; #ifndef __clockid_t_defined @@ -316,13 +212,13 @@ typedef DWORD clockid_t; #define CLOCK_MONOTONIC (1) #endif #ifndef CLOCK_REALTIME -#define CLOCK_REALTIME (2) +#define CLOCK_REALTIME (2) #endif #ifndef _TIMESPEC_DEFINED struct timespec { - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ }; #endif @@ -337,41 +233,41 @@ static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p); #if defined(HAVE_STDINT) #include <stdint.h> #else -typedef unsigned int uint32_t; -typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned short uint16_t; typedef unsigned __int64 uint64_t; -typedef __int64 int64_t; -#define INT64_MAX (9223372036854775807) +typedef __int64 int64_t; +#define INT64_MAX 9223372036854775807 #endif /* HAVE_STDINT */ /* POSIX dirent interface */ struct dirent { - char d_name[PATH_MAX]; + char d_name[PATH_MAX]; }; typedef struct DIR { - HANDLE handle; - WIN32_FIND_DATAW info; - struct dirent result; + HANDLE handle; + WIN32_FIND_DATAW info; + struct dirent result; } DIR; -#if defined(_WIN32) && !defined(POLLIN) +#if !defined(USE_IPV6) && defined(_WIN32) #ifndef HAVE_POLL struct pollfd { - SOCKET fd; - short events; - short revents; + SOCKET fd; + short events; + short revents; }; -#define POLLIN (0x0300) +#define POLLIN 1 #endif #endif /* Mark required libraries */ -#if defined(_MSC_VER) +#ifdef _MSC_VER #pragma comment(lib, "Ws2_32.lib") #endif -#else /* UNIX specific */ +#else /* UNIX specific */ #include <sys/wait.h> #include <sys/socket.h> #include <sys/poll.h> @@ -382,320 +278,252 @@ struct pollfd { #include <stdint.h> #include <inttypes.h> #include <netdb.h> -typedef const void *SOCK_OPT_TYPE; +typedef const void * SOCK_OPT_TYPE; -#if defined(ANDROID) +//#if defined(ANDROID) typedef unsigned short int in_port_t; -#endif +//#endif #include <pwd.h> #include <unistd.h> -#include <grp.h> #include <dirent.h> #if !defined(NO_SSL_DL) && !defined(NO_SSL) #include <dlfcn.h> #endif #include <pthread.h> #if defined(__MACH__) -#define SSL_LIB "libssl.dylib" -#define CRYPTO_LIB "libcrypto.dylib" +#define SSL_LIB "libssl.dylib" +#define CRYPTO_LIB "libcrypto.dylib" #else #if !defined(SSL_LIB) -#define SSL_LIB "libssl.so" +#define SSL_LIB "libssl.so" #endif #if !defined(CRYPTO_LIB) -#define CRYPTO_LIB "libcrypto.so" +#define CRYPTO_LIB "libcrypto.so" #endif #endif #ifndef O_BINARY -#define O_BINARY (0) +#define O_BINARY 0 #endif /* O_BINARY */ -#define closesocket(a) (close(a)) -#define mg_mkdir(x, y) (mkdir(x, y)) -#define mg_remove(x) (remove(x)) -#define mg_sleep(x) (usleep((x)*1000)) -#define ERRNO (errno) +#define closesocket(a) close(a) +#define mg_mkdir(x, y) mkdir(x, y) +#define mg_remove(x) remove(x) +#define mg_sleep(x) usleep((x) * 1000) +#define ERRNO errno #define INVALID_SOCKET (-1) #define INT64_FMT PRId64 typedef int SOCKET; #define WINCDECL -#if defined(__hpux) -/* HPUX 11 does not have monotonic, fall back to realtime */ -#ifndef 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 /* End of Windows and UNIX specific includes */ -/* va_copy should always be a macro, C99 and C++11 - DTL */ -#ifndef va_copy -#define va_copy(x, y) ((x) = (y)) -#endif - #ifdef _WIN32 static CRITICAL_SECTION global_log_file_lock; -static DWORD pthread_self(void) { return GetCurrentThreadId(); } +static DWORD pthread_self(void) +{ + return GetCurrentThreadId(); +} -static int pthread_key_create( - pthread_key_t *key, - void (*_must_be_zero)( - void *) /* destructor function not supported for windows */) +int pthread_key_create(pthread_key_t *key, void (*_must_be_zero)(void*) /* destructor function not supported for windows */) { - assert(_must_be_zero == NULL); - if ((key != 0) && (_must_be_zero == NULL)) { - *key = TlsAlloc(); - return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1; - } - return -2; + assert(_must_be_zero == NULL); + if ((key!=0) && (_must_be_zero == NULL)) { + *key = TlsAlloc(); + return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1; + } + return -2; } -static int pthread_key_delete(pthread_key_t key) +int pthread_key_delete(pthread_key_t key) { - return TlsFree(key) ? 0 : 1; + return TlsFree(key) ? 0 : 1; } -static int pthread_setspecific(pthread_key_t key, void *value) +int pthread_setspecific(pthread_key_t key, void * value) { - return TlsSetValue(key, value) ? 0 : 1; + return TlsSetValue(key, value) ? 0 : 1; } -#ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS -static void *pthread_getspecific(pthread_key_t key) { return TlsGetValue(key); } -#endif +void *pthread_getspecific(pthread_key_t key) +{ + return TlsGetValue(key); +} #endif /* _WIN32 */ + #include "civetweb.h" #define PASSWORDS_FILE_NAME ".htpasswd" -#define CGI_ENVIRONMENT_SIZE (4096) -#define MAX_CGI_ENVIR_VARS (64) -#define MG_BUF_LEN (8192) - +#define CGI_ENVIRONMENT_SIZE 4096 +#define MAX_CGI_ENVIR_VARS 64 +#define MG_BUF_LEN 8192 #ifndef MAX_REQUEST_SIZE -#define MAX_REQUEST_SIZE (16384) +#define MAX_REQUEST_SIZE 16384 #endif - -mg_static_assert(MAX_REQUEST_SIZE >= 256, - "request size length must be a positive number"); - #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) #if !defined(DEBUG_TRACE) #if defined(DEBUG) -static void DEBUG_TRACE_FUNC(const char *func, - unsigned line, - PRINTF_FORMAT_STRING(const char *fmt), - ...) PRINTF_ARGS(3, 4); +static void DEBUG_TRACE_FUNC(const char *func, unsigned line, PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(3, 4); -static void -DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) -{ - va_list args; - flockfile(stdout); - printf("*** %lu.%p.%s.%u: ", - (unsigned long)time(NULL), - (void *)pthread_self(), - func, - line); - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - putchar('\n'); - fflush(stdout); - funlockfile(stdout); +static void DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...) { + + va_list args; + flockfile(stdout); + printf("*** %lu.%p.%s.%u: ", + (unsigned long) time(NULL), (void *) pthread_self(), + func, line); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + putchar('\n'); + fflush(stdout); + funlockfile(stdout); } -#define DEBUG_TRACE(fmt, ...) \ - DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) +#define DEBUG_TRACE(fmt, ...) DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) #else -#define DEBUG_TRACE(fmt, ...) \ - do { \ - } while (0) +#define DEBUG_TRACE(fmt, ...) #endif /* DEBUG */ #endif /* DEBUG_TRACE */ #if defined(MEMORY_DEBUGGING) -unsigned long mg_memory_debug_blockCount = 0; -unsigned long mg_memory_debug_totalMemUsed = 0; - -static void *mg_malloc_ex(size_t size, const char *file, unsigned line) -{ - void *data = malloc(size + sizeof(size_t)); - void *memory = 0; - char mallocStr[256]; - - if (data) { - *(size_t *)data = size; - mg_memory_debug_totalMemUsed += size; - mg_memory_debug_blockCount++; - memory = (void *)(((char *)data) + sizeof(size_t)); - } - - sprintf(mallocStr, - "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", - memory, - (unsigned long)size, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, - file, - line); +static unsigned long blockCount = 0; +static unsigned long totalMemUsed = 0; + +static void * mg_malloc_ex(size_t size, const char * file, unsigned line) { + + void * data = malloc(size + sizeof(size_t)); + void * memory = 0; + char mallocStr[256]; + + if (data) { + *(size_t*)data = size; + totalMemUsed += size; + blockCount++; + memory = (void *)(((char*)data)+sizeof(size_t)); + } + + sprintf(mallocStr, "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line); #if defined(_WIN32) - OutputDebugStringA(mallocStr); + OutputDebugStringA(mallocStr); #else - DEBUG_TRACE("%s", mallocStr); + DEBUG_TRACE("%s", mallocStr); #endif - return memory; + return memory; } -static void * -mg_calloc_ex(size_t count, size_t size, const char *file, unsigned line) -{ - void *data = mg_malloc_ex(size * count, file, line); - if (data) { - memset(data, 0, size); - } - return data; +static void * mg_calloc_ex(size_t count, size_t size, const char * file, unsigned line) { + + void * data = mg_malloc_ex(size*count, file, line); + if (data) memset(data, 0, size); + + return data; } -static void mg_free_ex(void *memory, const char *file, unsigned line) -{ - char mallocStr[256]; - void *data = (void *)(((char *)memory) - sizeof(size_t)); - size_t size; +static void mg_free_ex(void * memory, const char * file, unsigned line) { - if (memory) { - size = *(size_t *)data; - mg_memory_debug_totalMemUsed -= size; - mg_memory_debug_blockCount--; - sprintf(mallocStr, - "MEM: %p %5lu free %7lu %4lu --- %s:%u\n", - memory, - (unsigned long)size, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, - file, - line); + char mallocStr[256]; + void * data = (void *)(((char*)memory)-sizeof(size_t)); + size_t size; + + if (memory) { + size = *(size_t*)data; + totalMemUsed -= size; + blockCount--; + sprintf(mallocStr, "MEM: %p %5lu free %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line); #if defined(_WIN32) - OutputDebugStringA(mallocStr); + OutputDebugStringA(mallocStr); #else - DEBUG_TRACE("%s", mallocStr); + DEBUG_TRACE("%s", mallocStr); #endif - free(data); - } -} - -static void * -mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line) -{ - char mallocStr[256]; - void *data; - void *_realloc; - size_t oldsize; - - if (newsize) { - if (memory) { - data = (void *)(((char *)memory) - sizeof(size_t)); - oldsize = *(size_t *)data; - _realloc = realloc(data, newsize + sizeof(size_t)); - if (_realloc) { - data = _realloc; - mg_memory_debug_totalMemUsed -= oldsize; - sprintf(mallocStr, - "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", - memory, - (unsigned long)oldsize, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, - file, - line); + free(data); + } +} + +static void * mg_realloc_ex(void * memory, size_t newsize, const char * file, unsigned line) { + + char mallocStr[256]; + void * data; + void * _realloc; + size_t oldsize; + + if (newsize) { + if (memory) { + data = (void *)(((char*)memory)-sizeof(size_t)); + oldsize = *(size_t*)data; + _realloc = realloc(data, newsize+sizeof(size_t)); + if (_realloc) { + data = _realloc; + totalMemUsed -= oldsize; + sprintf(mallocStr, "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", memory, (unsigned long)oldsize, totalMemUsed, blockCount, file, line); #if defined(_WIN32) - OutputDebugStringA(mallocStr); + OutputDebugStringA(mallocStr); #else - DEBUG_TRACE("%s", mallocStr); + DEBUG_TRACE("%s", mallocStr); #endif - mg_memory_debug_totalMemUsed += newsize; - sprintf(mallocStr, - "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", - memory, - (unsigned long)newsize, - mg_memory_debug_totalMemUsed, - mg_memory_debug_blockCount, - file, - line); + totalMemUsed += newsize; + sprintf(mallocStr, "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)newsize, totalMemUsed, blockCount, file, line); #if defined(_WIN32) - OutputDebugStringA(mallocStr); + OutputDebugStringA(mallocStr); #else - DEBUG_TRACE("%s", mallocStr); + DEBUG_TRACE("%s", mallocStr); #endif - *(size_t *)data = newsize; - data = (void *)(((char *)data) + sizeof(size_t)); - } else { + *(size_t*)data = newsize; + data = (void *)(((char*)data)+sizeof(size_t)); + } else { #if defined(_WIN32) - OutputDebugStringA("MEM: realloc failed\n"); + OutputDebugStringA("MEM: realloc failed\n"); #else - DEBUG_TRACE("%s", "MEM: realloc failed\n"); + DEBUG_TRACE("%s", "MEM: realloc failed\n"); #endif - return _realloc; - } - } else { - data = mg_malloc_ex(newsize, file, line); - } - } else { - data = 0; - mg_free_ex(memory, file, line); - } + return _realloc; + } + } else { + data = mg_malloc_ex(newsize, file, line); + } + } else { + data = 0; + mg_free_ex(memory, file, line); + } - return data; + return data; } -#define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__) -#define mg_calloc(a, b) mg_calloc_ex(a, b, __FILE__, __LINE__) -#define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__) -#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) +#define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__) +#define mg_calloc(a,b) mg_calloc_ex(a, b, __FILE__, __LINE__) +#define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__) +#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) #else - -static __inline void *mg_malloc(size_t a) { return malloc(a); } -static __inline void *mg_calloc(size_t a, size_t b) { return calloc(a, b); } -static __inline void *mg_realloc(void *a, size_t b) { return realloc(a, b); } -static __inline void mg_free(void *a) { free(a); } - +static __inline void * mg_malloc(size_t a) {return malloc(a);} +static __inline void * mg_calloc(size_t a, size_t b) {return calloc(a, b);} +static __inline void * mg_realloc(void * a, size_t b) {return realloc(a, b);} +static __inline void mg_free(void * a) {free(a);} #endif -/* This following lines are just meant as a reminder to use the mg-functions - * for memory management */ +/* This following lines are just meant as a reminder to use the mg-functions for memory management */ #ifdef malloc -#undef malloc + #undef malloc #endif #ifdef calloc -#undef calloc + #undef calloc #endif #ifdef realloc -#undef realloc + #undef realloc #endif #ifdef free -#undef free + #undef free #endif -#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc -#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc +#define 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 free DO_NOT_USE_THIS_FUNCTION__USE_mg_free + #define MD5_STATIC static #include "md5.inl" @@ -706,19 +534,23 @@ typedef int socklen_t; #endif /* NO_SOCKLEN_T */ #define _DARWIN_UNLIMITED_SELECT -#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */ +#define IP_ADDR_STR_LEN 50 /* IPv6 hex string is 46 chars */ #if !defined(MSG_NOSIGNAL) -#define MSG_NOSIGNAL (0) +#define MSG_NOSIGNAL 0 #endif #if !defined(SOMAXCONN) -#define SOMAXCONN (100) +#define SOMAXCONN 100 +#endif + +#if !defined(PATH_MAX) +#define PATH_MAX 4096 #endif /* Size of the accepted socket queue */ #if !defined(MGSQLEN) -#define MGSQLEN (20) +#define MGSQLEN 20 #endif #if defined(NO_SSL_DL) @@ -726,374 +558,308 @@ typedef int socklen_t; #include <openssl/err.h> #else /* SSL loaded dynamically from DLL. - * I put the prototypes here to be independent from OpenSSL source - * installation. */ + I put the prototypes here to be independent from OpenSSL source + installation. */ typedef struct ssl_st SSL; typedef struct ssl_method_st SSL_METHOD; typedef struct ssl_ctx_st SSL_CTX; struct ssl_func { - const char *name; /* SSL function name */ - void (*ptr)(void); /* Function pointer */ + const char *name; /* SSL function name */ + void (*ptr)(void); /* Function pointer */ }; -#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) -#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) -#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) -#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) -#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) -#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) -#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) -#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) -#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) -#define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) -#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr) -#define SSL_CTX_use_PrivateKey_file \ - (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) -#define SSL_CTX_use_certificate_file \ - (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) -#define SSL_CTX_set_default_passwd_cb \ - (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) -#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) -#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr) -#define SSL_CTX_use_certificate_chain_file \ - (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr) -#define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr) -#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr) -#define SSL_CTX_set_verify (*(void (*)(SSL_CTX *, int, int))ssl_sw[19].ptr) -#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr) - -#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) -#define CRYPTO_set_locking_callback \ - (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr) -#define CRYPTO_set_id_callback \ - (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr) -#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr) -#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr) +#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) +#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) +#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) +#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) +#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) +#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr) +#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) +#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) +#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) +#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) +#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) +#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ + const char *, int)) ssl_sw[11].ptr) +#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ + const char *, int)) ssl_sw[12].ptr) +#define SSL_CTX_set_default_passwd_cb \ + (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr) +#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) +#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) +#define SSL_CTX_use_certificate_chain_file \ + (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) +#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr) +#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr) +#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr) +#define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr) + +#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) +#define CRYPTO_set_locking_callback \ + (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) +#define CRYPTO_set_id_callback \ + (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) +#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr) +#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr) /* set_ssl_option() function updates this array. - * It loads SSL library dynamically and changes NULLs to the actual addresses - * of respective functions. The macros above (like SSL_connect()) are really - * just calling these functions indirectly via the pointer. */ -static struct ssl_func ssl_sw[] = {{"SSL_free", NULL}, - {"SSL_accept", NULL}, - {"SSL_connect", NULL}, - {"SSL_read", NULL}, - {"SSL_write", NULL}, - {"SSL_get_error", NULL}, - {"SSL_set_fd", NULL}, - {"SSL_new", NULL}, - {"SSL_CTX_new", NULL}, - {"SSLv23_server_method", NULL}, - {"SSL_library_init", NULL}, - {"SSL_CTX_use_PrivateKey_file", NULL}, - {"SSL_CTX_use_certificate_file", NULL}, - {"SSL_CTX_set_default_passwd_cb", NULL}, - {"SSL_CTX_free", NULL}, - {"SSL_load_error_strings", NULL}, - {"SSL_CTX_use_certificate_chain_file", NULL}, - {"SSLv23_client_method", NULL}, - {"SSL_pending", NULL}, - {"SSL_CTX_set_verify", NULL}, - {"SSL_shutdown", NULL}, - {NULL, NULL}}; + It loads SSL library dynamically and changes NULLs to the actual addresses + of respective functions. The macros above (like SSL_connect()) are really + just calling these functions indirectly via the pointer. */ +static struct ssl_func ssl_sw[] = { + {"SSL_free", NULL}, + {"SSL_accept", NULL}, + {"SSL_connect", NULL}, + {"SSL_read", NULL}, + {"SSL_write", NULL}, + {"SSL_get_error", NULL}, + {"SSL_set_fd", NULL}, + {"SSL_new", NULL}, + {"SSL_CTX_new", NULL}, + {"SSLv23_server_method", NULL}, + {"SSL_library_init", NULL}, + {"SSL_CTX_use_PrivateKey_file", NULL}, + {"SSL_CTX_use_certificate_file",NULL}, + {"SSL_CTX_set_default_passwd_cb",NULL}, + {"SSL_CTX_free", NULL}, + {"SSL_load_error_strings", NULL}, + {"SSL_CTX_use_certificate_chain_file", NULL}, + {"SSLv23_client_method", NULL}, + {"SSL_pending", NULL}, + {"SSL_CTX_set_verify", NULL}, + {"SSL_shutdown", NULL}, + {NULL, NULL} +}; /* Similar array as ssl_sw. These functions could be located in different - * lib. */ + lib. */ #if !defined(NO_SSL) -static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL}, - {"CRYPTO_set_locking_callback", NULL}, - {"CRYPTO_set_id_callback", NULL}, - {"ERR_get_error", NULL}, - {"ERR_error_string", NULL}, - {NULL, NULL}}; +static struct ssl_func crypto_sw[] = { + {"CRYPTO_num_locks", NULL}, + {"CRYPTO_set_locking_callback", NULL}, + {"CRYPTO_set_id_callback", NULL}, + {"ERR_get_error", NULL}, + {"ERR_error_string", NULL}, + {NULL, NULL} +}; #endif /* NO_SSL */ #endif /* NO_SSL_DL */ -static const char *month_names[] = {"Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec"}; - -/* Unified socket address. For IPv6 support, add IPv6 address structure in the - * union u. */ +static const char *month_names[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +/* Unified socket address. For IPv6 support, add IPv6 address structure + in the union u. */ union usa { - struct sockaddr sa; - struct sockaddr_in sin; + struct sockaddr sa; + struct sockaddr_in sin; #if defined(USE_IPV6) - struct sockaddr_in6 sin6; + struct sockaddr_in6 sin6; #endif }; /* Describes a string (chunk of memory). */ struct vec { - const char *ptr; - size_t len; + const char *ptr; + size_t len; }; struct file { - uint64_t size; - time_t last_modified; - FILE *fp; - const char *membuf; /* Non-NULL if file data is in memory */ - int is_directory; - int gzipped; /* set to 1 if the content is gzipped - * in which case we need a content-encoding: gzip header */ + int is_directory; + time_t modification_time; + int64_t size; + FILE *fp; + const char *membuf; /* Non-NULL if file data is in memory */ + /* set to 1 if the content is gzipped + in which case we need a content-encoding: gzip header */ + int gzipped; }; -#define STRUCT_FILE_INITIALIZER \ - { \ - (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 \ - } +#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0} /* Describes listening socket, or socket which was accept()-ed by the master - * thread and queued for future handling by the worker thread. */ + 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 */ + SOCKET sock; /* Listening socket */ + union usa lsa; /* Local socket address */ + union usa rsa; /* Remote socket address */ + unsigned is_ssl:1; /* Is port SSL-ed */ + unsigned ssl_redir:1; /* Is port supposed to redirect everything to SSL + port */ }; /* NOTE(lsm): this enum shoulds be in sync with the config_options below. */ enum { - CGI_EXTENSIONS, - CGI_ENVIRONMENT, - PUT_DELETE_PASSWORDS_FILE, - CGI_INTERPRETER, - PROTECT_URI, - AUTHENTICATION_DOMAIN, - SSI_EXTENSIONS, - THROTTLE, - ACCESS_LOG_FILE, - ENABLE_DIRECTORY_LISTING, - ERROR_LOG_FILE, - GLOBAL_PASSWORDS_FILE, - INDEX_FILES, - ENABLE_KEEP_ALIVE, - ACCESS_CONTROL_LIST, - EXTRA_MIME_TYPES, - LISTENING_PORTS, - DOCUMENT_ROOT, - SSL_CERTIFICATE, - NUM_THREADS, - RUN_AS_USER, - REWRITE, - HIDE_FILES, - REQUEST_TIMEOUT, -#if defined(USE_WEBSOCKET) - WEBSOCKET_TIMEOUT, -#endif - DECODE_URL, + CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, + PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE, + ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, + GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, + EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE, + NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT, + DECODE_URL, #if defined(USE_LUA) - LUA_PRELOAD_FILE, - LUA_SCRIPT_EXTENSIONS, - LUA_SERVER_PAGE_EXTENSIONS, + LUA_PRELOAD_FILE, LUA_SCRIPT_EXTENSIONS, LUA_SERVER_PAGE_EXTENSIONS, #endif #if defined(USE_WEBSOCKET) - WEBSOCKET_ROOT, + WEBSOCKET_ROOT, #endif #if defined(USE_LUA) && defined(USE_WEBSOCKET) - LUA_WEBSOCKET_EXTENSIONS, + LUA_WEBSOCKET_EXTENSIONS, #endif - ACCESS_CONTROL_ALLOW_ORIGIN, - ERROR_PAGES, + ACCESS_CONTROL_ALLOW_ORIGIN, ERROR_PAGES, - NUM_OPTIONS + NUM_OPTIONS }; /* Config option name, config types, default value */ static struct mg_option config_options[] = { - {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"}, - {"cgi_environment", CONFIG_TYPE_STRING, NULL}, - {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL}, - {"cgi_interpreter", CONFIG_TYPE_FILE, NULL}, - {"protect_uri", CONFIG_TYPE_STRING, NULL}, - {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"}, - {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"}, - {"throttle", CONFIG_TYPE_STRING, NULL}, - {"access_log_file", CONFIG_TYPE_FILE, NULL}, - {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"}, - {"error_log_file", CONFIG_TYPE_FILE, NULL}, - {"global_auth_file", CONFIG_TYPE_FILE, NULL}, - {"index_files", - CONFIG_TYPE_STRING, + {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"}, + {"cgi_environment", CONFIG_TYPE_STRING, NULL}, + {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL}, + {"cgi_interpreter", CONFIG_TYPE_FILE, NULL}, + {"protect_uri", CONFIG_TYPE_STRING, NULL}, + {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"}, + {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"}, + {"throttle", CONFIG_TYPE_STRING, NULL}, + {"access_log_file", CONFIG_TYPE_FILE, NULL}, + {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"}, + {"error_log_file", CONFIG_TYPE_FILE, NULL}, + {"global_auth_file", CONFIG_TYPE_FILE, NULL}, + {"index_files", CONFIG_TYPE_STRING, #ifdef USE_LUA - "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi," - "index.shtml,index.php"}, + "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,index.shtml,index.php"}, #else - "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"}, -#endif - {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"}, - {"access_control_list", CONFIG_TYPE_STRING, NULL}, - {"extra_mime_types", CONFIG_TYPE_STRING, NULL}, - {"listening_ports", CONFIG_TYPE_STRING, "8080"}, - {"document_root", CONFIG_TYPE_DIRECTORY, NULL}, - {"ssl_certificate", CONFIG_TYPE_FILE, NULL}, - {"num_threads", CONFIG_TYPE_NUMBER, "50"}, - {"run_as_user", CONFIG_TYPE_STRING, NULL}, - {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL}, - {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL}, - {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"}, -#if defined(USE_WEBSOCKET) - {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"}, -#endif - {"decode_url", CONFIG_TYPE_BOOLEAN, "yes"}, + "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"}, +#endif + {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"}, + {"access_control_list", CONFIG_TYPE_STRING, NULL}, + {"extra_mime_types", CONFIG_TYPE_STRING, NULL}, + {"listening_ports", CONFIG_TYPE_STRING, "8080"}, + {"document_root", CONFIG_TYPE_DIRECTORY, NULL}, + {"ssl_certificate", CONFIG_TYPE_FILE, NULL}, + {"num_threads", CONFIG_TYPE_NUMBER, "50"}, + {"run_as_user", CONFIG_TYPE_STRING, NULL}, + {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL}, + {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL}, + {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"}, + {"decode_url", CONFIG_TYPE_BOOLEAN, "yes"}, #if defined(USE_LUA) - {"lua_preload_file", CONFIG_TYPE_FILE, NULL}, - {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, - {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"}, + {"lua_preload_file", CONFIG_TYPE_FILE, NULL}, + {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, + {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"}, #endif #if defined(USE_WEBSOCKET) - {"websocket_root", CONFIG_TYPE_DIRECTORY, NULL}, + {"websocket_root", CONFIG_TYPE_DIRECTORY, NULL}, #endif #if defined(USE_LUA) && defined(USE_WEBSOCKET) - {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, + {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"}, #endif - {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"}, - {"error_pages", CONFIG_TYPE_DIRECTORY, NULL}, - - {NULL, CONFIG_TYPE_UNKNOWN, NULL}}; - - -/* 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"); + {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"}, + {"error_pages", CONFIG_TYPE_DIRECTORY, NULL}, + {NULL, CONFIG_TYPE_UNKNOWN, NULL} +}; struct mg_request_handler_info { - /* Name/Pattern of the URI. */ - char *uri; - size_t uri_len; - - /* URI type: ws/wss (websocket) or http/https (web page). */ - int is_websocket_handler; - - /* Handler for http/https requests. */ - mg_request_handler handler; - - /* 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; + char *uri; + size_t uri_len; + mg_request_handler handler; - /* User supplied argument for the handler function. */ - void *cbdata; - - /* next request handler in a linked list */ - struct mg_request_handler_info *next; + void *cbdata; + struct mg_request_handler_info *next; }; struct mg_context { - volatile int stop_flag; /* Should we stop event loop */ - SSL_CTX *ssl_ctx; /* SSL context */ - char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */ - struct mg_callbacks callbacks; /* User-defined callback function */ - void *user_data; /* User-defined data */ - int context_type; /* 1 = server context, 2 = client context */ - - struct socket *listening_sockets; - in_port_t *listening_ports; - unsigned int num_listening_sockets; - - volatile int num_threads; /* Number of threads */ - pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */ - pthread_cond_t thread_cond; /* Condvar for tracking workers terminations */ - - struct socket queue[MGSQLEN]; /* Accepted sockets */ - volatile int sq_head; /* Head of the socket queue */ - volatile int sq_tail; /* Tail of the socket queue */ - pthread_cond_t sq_full; /* Signaled when socket is produced */ - pthread_cond_t sq_empty; /* Signaled when socket is consumed */ - pthread_t masterthreadid; /* The master thread ID */ - unsigned int workerthreadcount; /* The amount of worker threads. */ - pthread_t *workerthreadids; /* The worker thread IDs */ - - unsigned long start_time; /* Server start time, used for authentication */ - pthread_mutex_t nonce_mutex; /* Protects nonce_count */ - unsigned long nonce_count; /* Used nonces, used for authentication */ - - char *systemName; /* What operating system is running */ - - /* linked list of uri handlers */ - struct mg_request_handler_info *request_handlers; + volatile int stop_flag; /* Should we stop event loop */ + SSL_CTX *ssl_ctx; /* SSL context */ + char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */ + struct mg_callbacks callbacks; /* User-defined callback function */ + void *user_data; /* User-defined data */ + int context_type; /* 1 = server context, 2 = client context */ + + struct socket *listening_sockets; + in_port_t *listening_ports; + int num_listening_sockets; + + volatile int num_threads; /* Number of threads */ + pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */ + pthread_cond_t thread_cond; /* Condvar for tracking workers terminations */ + + struct socket queue[MGSQLEN]; /* Accepted sockets */ + volatile int sq_head; /* Head of the socket queue */ + volatile int sq_tail; /* Tail of the socket queue */ + pthread_cond_t sq_full; /* Signaled when socket is produced */ + pthread_cond_t sq_empty; /* Signaled when socket is consumed */ + pthread_t masterthreadid; /* The master thread ID */ + int workerthreadcount; /* The amount of worker threads. */ + pthread_t *workerthreadids; /* The worker thread IDs */ + + unsigned long start_time; /* Server start time, used for authentication */ + pthread_mutex_t nonce_mutex; /* Protects nonce_count */ + unsigned long nonce_count; /* Used nonces, used for authentication */ + + char *systemName; /* What operating system is running */ + + /* linked list of uri handlers */ + struct mg_request_handler_info *request_handlers; #if defined(USE_LUA) && defined(USE_WEBSOCKET) - /* linked list of shared lua websockets */ - struct mg_shared_lua_websocket_list *shared_lua_websockets; + /* linked list of shared lua websockets */ + struct mg_shared_lua_websocket_list *shared_lua_websockets; #endif #ifdef USE_TIMERS - struct ttimers *timers; + struct ttimers * timers; #endif }; struct mg_connection { - struct mg_request_info request_info; - struct mg_context *ctx; - SSL *ssl; /* SSL descriptor */ - SSL_CTX *client_ssl_ctx; /* SSL context for client connections */ - struct socket client; /* Connected client */ - time_t 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=no, 1=yes: - * data available, 2: 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 in_error_handler; /* 1 if in handler for user defined error - * pages */ - int buf_size; /* Buffer size */ - int request_len; /* Size of the request + headers in a buffer */ - int data_len; /* Total size of data in a buffer */ - int status_code; /* HTTP reply status code, e.g. 200 */ - int throttle; /* Throttling, bytes/sec. <= 0 means no - * throttle */ - time_t last_throttle_time; /* Last time throttled data was sent */ - int64_t last_throttle_bytes; /* Bytes sent this second */ - pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure - * atomic transmissions for websockets */ + struct mg_request_info request_info; + struct mg_context *ctx; + SSL *ssl; /* SSL descriptor */ + SSL_CTX *client_ssl_ctx; /* SSL context for client connections */ + struct socket client; /* Connected client */ + time_t birth_time; /* Time when request was received */ + int64_t num_bytes_sent; /* Total bytes sent to client */ + int64_t content_len; /* Content-Length header value */ + int64_t consumed_content; /* How many bytes of content have been read */ + char *buf; /* Buffer for received data */ + char *path_info; /* PATH_INFO part of the URL */ + int must_close; /* 1 if connection must be closed */ + int in_error_handler; /* 1 if in handler for user defined error pages */ + int buf_size; /* Buffer size */ + int request_len; /* Size of the request + headers in a buffer */ + int data_len; /* Total size of data in a buffer */ + int status_code; /* HTTP reply status code, e.g. 200 */ + int throttle; /* Throttling, bytes/sec. <= 0 means no throttle */ + time_t last_throttle_time; /* Last time throttled data was sent */ + int64_t last_throttle_bytes; /* Bytes sent this second */ + pthread_mutex_t mutex; /* Used by mg_lock_connection/mg_unlock_connection to ensure atomic transmissions for websockets */ #if defined(USE_LUA) && defined(USE_WEBSOCKET) - void *lua_websocket_state; /* Lua_State for a websocket connection */ + void * lua_websocket_state; /* Lua_State for a websocket connection */ #endif }; -static pthread_key_t sTlsKey; /* Thread local storage index */ +static pthread_key_t sTlsKey; /* Thread local storage index */ static int sTlsInit = 0; struct mg_workerTLS { - int is_master; + int is_master; #if defined(_WIN32) && !defined(__SYMBIAN32__) - HANDLE pthread_cond_helper_mutex; + HANDLE pthread_cond_helper_mutex; #endif }; /* Directory entry */ struct de { - struct mg_connection *conn; - char *file_name; - struct file file; + struct mg_connection *conn; + char *file_name; + struct file file; }; #if defined(USE_WEBSOCKET) @@ -1102,5690 +868,4450 @@ static int is_websocket_protocol(const struct mg_connection *conn); #define is_websocket_protocol(conn) (0) #endif -static int mg_atomic_inc(volatile int *addr) +int mg_atomic_inc(volatile int * addr) { - int ret; + int ret; #if defined(_WIN32) && !defined(__SYMBIAN32__) - /* 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); + ret = InterlockedIncrement((volatile unsigned int *) addr); #elif defined(__GNUC__) - ret = __sync_add_and_fetch(addr, 1); + ret = __sync_add_and_fetch(addr, 1); #else - ret = (++(*addr)); + ret = (++(*addr)); #endif - return ret; + return ret; } -static int mg_atomic_dec(volatile int *addr) +int mg_atomic_dec(volatile int * addr) { - int ret; + int ret; #if defined(_WIN32) && !defined(__SYMBIAN32__) - /* 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); + ret = InterlockedDecrement((volatile unsigned int *) addr); #elif defined(__GNUC__) - ret = __sync_sub_and_fetch(addr, 1); + ret = __sync_sub_and_fetch(addr, 1); #else - ret = (--(*addr)); + ret = (--(*addr)); #endif - return ret; + return ret; } #if !defined(NO_THREAD_NAME) #if defined(_WIN32) && defined(_MSC_VER) /* Set the thread name for debugging purposes in Visual Studio - * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx - */ -#pragma pack(push, 8) -typedef struct tagTHREADNAME_INFO { - DWORD dwType; /* Must be 0x1000. */ - LPCSTR szName; /* Pointer to name (in user addr space). */ - DWORD dwThreadID; /* Thread ID (-1=caller thread). */ - DWORD dwFlags; /* Reserved for future use, must be zero. */ + http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx +*/ +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; /* Must be 0x1000. */ + LPCSTR szName; /* Pointer to name (in user addr space). */ + DWORD dwThreadID; /* Thread ID (-1=caller thread). */ + DWORD dwFlags; /* Reserved for future use, must be zero. */ } THREADNAME_INFO; #pragma pack(pop) #elif defined(__linux__) #include <sys/prctl.h> #endif -static void mg_set_thread_name(const char *name) +void mg_set_thread_name(const char* name) { - char threadName[16]; /* Max. thread length in Linux/OSX/.. */ - - /* TODO (low): use strcpy and strcat instad of snprintf, use server name, - * don't - * return */ - if (snprintf(threadName, sizeof(threadName), "civetweb-%s", name) < 0) { - return; - } + char threadName[16]; /* Max. thread length in Linux/OSX/.. */ - threadName[sizeof(threadName) - 1] = 0; + if (snprintf(threadName, sizeof(threadName), "civetweb-%s", name)<0) return; + threadName[sizeof(threadName)-1] = 0; #if defined(_WIN32) #if defined(_MSC_VER) - /* Windows and Visual Studio Compiler */ - __try - { - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = threadName; - info.dwThreadID = ~0U; - info.dwFlags = 0; - - RaiseException(0x406D1388, - 0, - sizeof(info) / sizeof(ULONG_PTR), - (ULONG_PTR *)&info); - } - __except(EXCEPTION_EXECUTE_HANDLER) {} + /* Windows and Visual Studio Compiler */ + __try + { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = -1; + info.dwFlags = 0; + + RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } #elif defined(__MINGW32__) - /* No option known to set thread name for MinGW */ - ; + /* No option known to set thread name for MinGW */ #endif #elif defined(__linux__) - /* Linux */ - (void)prctl(PR_SET_NAME, threadName, 0, 0, 0); + /* Linux */ + (void)prctl(PR_SET_NAME,threadName,0,0,0); #elif defined(__APPLE__) || defined(__MACH__) - /* OS X (TODO: test) */ - (void)pthread_setname_np(threadName); + /* OS X (TODO: test) */ + (void)pthread_setname_np(threadName); #elif defined(BSD) || defined(__FreeBSD__) || defined(__OpenBSD__) - /* BSD (TODO: test) */ - pthread_set_name_np(pthread_self(), threadName); -#elif defined(__AIX__) || defined(_AIX) || defined(__hpux) || defined(__sun) -/* pthread_set_name_np seems to be missing on AIX, hpux, sun, ... */ + /* BSD (TODO: test) */ + pthread_set_name_np(pthread_self(), threadName); #else - /* POSIX */ - (void)pthread_setname_np(pthread_self(), threadName); + /* POSIX */ + (void)pthread_setname_np(pthread_self(), threadName); #endif } #else /* !defined(NO_THREAD_NAME) */ -void mg_set_thread_name(const char *threadName) {} +void mg_set_thread_name(const char* threadName) {} #endif #if defined(MG_LEGACY_INTERFACE) const char **mg_get_valid_option_names(void) { - static const char * - data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0}; - int i; + static const char * data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0}; + int i; - for (i = 0; config_options[i].name != NULL; i++) { - data[i * 2] = config_options[i].name; - data[i * 2 + 1] = config_options[i].default_value; - } + for (i=0; config_options[i].name != NULL; i++) { + data[i * 2] = config_options[i].name; + data[i * 2 + 1] = config_options[i].default_value; + } - return data; + return data; } #endif -const struct mg_option *mg_get_valid_options(void) { return config_options; } - -static int is_file_in_memory(struct mg_connection *conn, - const char *path, - struct file *filep) +const struct mg_option *mg_get_valid_options(void) { - size_t size = 0; - if (!conn || !filep) { - return 0; - } + return config_options; +} - filep->last_modified = (time_t)0; - if ((filep->membuf = - conn->ctx->callbacks.open_file == NULL - ? NULL - : conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) { - /* NOTE: override filep->size only on success. Otherwise, it might - * break constructs like if (!mg_stat() || !mg_fopen()) ... */ - filep->size = size; - } - return filep->membuf != NULL; +static int is_file_in_memory(struct mg_connection *conn, const char *path, + struct file *filep) +{ + size_t size = 0; + if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL : + conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) { + /* NOTE: override filep->size only on success. Otherwise, it might + break constructs like if (!mg_stat() || !mg_fopen()) ... */ + filep->size = size; + } + return filep->membuf != NULL; } static int is_file_opened(const struct file *filep) { - if (!filep) { - return 0; - } - - return filep->membuf != NULL || filep->fp != NULL; + return filep->membuf != NULL || filep->fp != NULL; } -static int mg_fopen(struct mg_connection *conn, - const char *path, - const char *mode, - struct file *filep) +static int mg_fopen(struct mg_connection *conn, const char *path, + const char *mode, struct file *filep) { - if (!filep) { - return 0; - } - - if (!is_file_in_memory(conn, path, filep)) { + if (!is_file_in_memory(conn, path, filep)) { #ifdef _WIN32 - wchar_t wbuf[PATH_MAX], wmode[20]; - to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); - MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); - filep->fp = _wfopen(wbuf, wmode); + wchar_t wbuf[PATH_MAX], wmode[20]; + to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); + filep->fp = _wfopen(wbuf, wmode); #else - filep->fp = fopen(path, mode); + filep->fp = fopen(path, mode); #endif - } + } - return is_file_opened(filep); + return is_file_opened(filep); } static void mg_fclose(struct file *filep) { - if (filep != NULL && filep->fp != NULL) { - fclose(filep->fp); - } + if (filep != NULL && filep->fp != NULL) { + fclose(filep->fp); + } } static void mg_strlcpy(register char *dst, register const char *src, size_t n) { - for (; *src != '\0' && n > 1; n--) { - *dst++ = *src++; - } - *dst = '\0'; + for (; *src != '\0' && n > 1; n--) { + *dst++ = *src++; + } + *dst = '\0'; } static int lowercase(const char *s) { - return tolower(*(const unsigned char *)s); + return tolower(* (const unsigned char *) s); } int mg_strncasecmp(const char *s1, const char *s2, size_t len) { - int diff = 0; + int diff = 0; - if (len > 0) { - do { - diff = lowercase(s1++) - lowercase(s2++); - } while (diff == 0 && s1[-1] != '\0' && --len > 0); - } + if (len > 0) + do { + diff = lowercase(s1++) - lowercase(s2++); + } while (diff == 0 && s1[-1] != '\0' && --len > 0); - return diff; + return diff; } static int mg_strcasecmp(const char *s1, const char *s2) { - int diff; + int diff; - do { - diff = lowercase(s1++) - lowercase(s2++); - } while (diff == 0 && s1[-1] != '\0'); + do { + diff = lowercase(s1++) - lowercase(s2++); + } while (diff == 0 && s1[-1] != '\0'); - return diff; + return diff; } -static char *mg_strndup(const char *ptr, size_t len) +static char * mg_strndup(const char *ptr, size_t len) { - char *p; + char *p; - if ((p = (char *)mg_malloc(len + 1)) != NULL) { - mg_strlcpy(p, ptr, len + 1); - } + if ((p = (char *) mg_malloc(len + 1)) != NULL) { + mg_strlcpy(p, ptr, len + 1); + } - return p; + return p; } -static char *mg_strdup(const char *str) { return mg_strndup(str, strlen(str)); } +static char * mg_strdup(const char *str) +{ + return mg_strndup(str, strlen(str)); +} static const char *mg_strcasestr(const char *big_str, const char *small_str) { - size_t i, big_len = strlen(big_str), small_len = strlen(small_str); + int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str); - if (big_len >= small_len) { - for (i = 0; i <= (big_len - small_len); i++) { - if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) { - return big_str + i; - } - } - } + for (i = 0; i <= big_len - small_len; i++) { + if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) { + return big_str + i; + } + } - return NULL; + return NULL; } /* Like snprintf(), but never returns negative value, or a value - * that is larger than a supplied buffer. - * Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability - * in his audit report. */ -static int mg_vsnprintf(struct mg_connection *conn, - char *buf, - size_t buflen, - const char *fmt, - va_list ap) -{ - int n; - - if (buflen == 0) { - return 0; - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wformat-nonliteral" -/* Using fmt as a non-literal is intended here, since it is mostly called - * indirectly by mg_snprintf */ -#endif + 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; - n = vsnprintf(buf, buflen, fmt, ap); + if (buflen == 0) + return 0; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + n = vsnprintf(buf, buflen, fmt, ap); - if (n < 0) { - mg_cry(conn, "vsnprintf error"); - n = 0; - } else if (n >= (int)buflen) { - mg_cry(conn, - "truncating vsnprintf buffer: [%.*s]", - n > 200 ? 200 : n, - buf); - n = (int)buflen - 1; - } - buf[n] = '\0'; + if (n < 0) { + mg_cry(conn, "vsnprintf error"); + n = 0; + } else if (n >= (int) buflen) { + mg_cry(conn, "truncating vsnprintf buffer: [%.*s]", + n > 200 ? 200 : n, buf); + n = (int) buflen - 1; + } + buf[n] = '\0'; - return n; + return n; } -static int mg_snprintf(struct mg_connection *conn, - char *buf, - size_t buflen, - PRINTF_FORMAT_STRING(const char *fmt), - ...) PRINTF_ARGS(4, 5); +static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, + PRINTF_FORMAT_STRING(const char *fmt), ...) +PRINTF_ARGS(4, 5); -static int mg_snprintf( - struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, ...) +static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, + const char *fmt, ...) { - va_list ap; - int n; + va_list ap; + int n; - va_start(ap, fmt); - n = mg_vsnprintf(conn, buf, buflen, fmt, ap); - va_end(ap); + va_start(ap, fmt); + n = mg_vsnprintf(conn, buf, buflen, fmt, ap); + va_end(ap); - return n; + return n; } static int get_option_index(const char *name) { - int i; + int i; - for (i = 0; config_options[i].name != NULL; i++) { - if (strcmp(config_options[i].name, name) == 0) { - return i; - } - } - return -1; + for (i = 0; config_options[i].name != NULL; i++) { + if (strcmp(config_options[i].name, name) == 0) { + return i; + } + } + return -1; } const char *mg_get_option(const struct mg_context *ctx, const char *name) { - int i; - if ((i = get_option_index(name)) == -1) { - return NULL; - } else if (!ctx || ctx->config[i] == NULL) { - return ""; - } else { - return ctx->config[i]; - } -} - -struct mg_context *mg_get_context(const struct mg_connection *conn) -{ - return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx); -} - -void *mg_get_user_data(const struct mg_context *ctx) -{ - return (ctx == NULL) ? NULL : ctx->user_data; + int i; + if ((i = get_option_index(name)) == -1) { + return NULL; + } else if (ctx->config[i] == NULL) { + return ""; + } else { + return ctx->config[i]; + } } -void mg_set_user_connection_data(const struct mg_connection *conn, void *data) +struct mg_context *mg_get_context(struct mg_connection * conn) { - if (conn != NULL) { - ((struct mg_connection *)conn)->request_info.conn_data = data; - } + return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx); } -void *mg_get_user_connection_data(const struct mg_connection *conn) +void *mg_get_user_data(struct mg_context *ctx) { - if (conn != NULL) { - return conn->request_info.conn_data; - } - return NULL; + return (ctx == NULL) ? NULL : ctx->user_data; } -size_t -mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl) +size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl) { - size_t i; - if (!ctx) { - return 0; - } - for (i = 0; i < size && i < ctx->num_listening_sockets; i++) { - ssl[i] = ctx->listening_sockets[i].is_ssl; - ports[i] = ctx->listening_ports[i]; - } - return i; + size_t i; + for (i = 0; i < size && i < (size_t)ctx->num_listening_sockets; i++) + { + ssl[i] = ctx->listening_sockets[i].is_ssl; + ports[i] = ctx->listening_ports[i]; + } + return i; } -static void sockaddr_to_string(char *buf, size_t len, const union usa *usa) +static void sockaddr_to_string(char *buf, size_t len, + const union usa *usa) { - buf[0] = '\0'; - - if (!usa) { - return; - } - - if (usa->sa.sa_family == AF_INET) { - getnameinfo(&usa->sa, - sizeof(usa->sin), - buf, - (unsigned)len, - NULL, - 0, - NI_NUMERICHOST); - } + buf[0] = '\0'; #if defined(USE_IPV6) - else if (usa->sa.sa_family == AF_INET6) { - getnameinfo(&usa->sa, - sizeof(usa->sin6), - buf, - (unsigned)len, - NULL, - 0, - NI_NUMERICHOST); - } + inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ? + (void *) &usa->sin.sin_addr : + (void *) &usa->sin6.sin6_addr, buf, len); +#elif defined(_WIN32) + /* Only Windows Vista (and newer) have inet_ntop() */ + mg_strlcpy(buf, inet_ntoa(usa->sin.sin_addr), len); +#else + inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len); #endif } -/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be - * included in all responses other than 100, 101, 5xx. */ +/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be included in all responses other than 100, 101, 5xx. */ static void gmt_time_string(char *buf, size_t buf_len, time_t *t) { - struct tm *tm; - - tm = gmtime(t); - if (tm != NULL) { - strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm); - } else { - mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len); - buf[buf_len - 1] = '\0'; - } -} + struct tm *tm; -/* difftime for struct timespec. Return value is in seconds. */ -static double mg_difftimespec(const struct timespec *ts_now, - const struct timespec *ts_before) -{ - return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9 + - (double)(ts_now->tv_sec - ts_before->tv_sec); + tm = gmtime(t); + if (tm != NULL) { + strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm); + } else { + mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len); + buf[buf_len - 1] = '\0'; + } } /* Print error message to the opened error log stream. */ -void mg_cry(const struct mg_connection *conn, const char *fmt, ...) -{ - char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN]; - va_list ap; - FILE *fp; - time_t timestamp; - - va_start(ap, fmt); - IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap)); - va_end(ap); - - /* Do not lock when getting the callback value, here and below. - * I suppose this is fine, since function cannot disappear in the - * same way string option can. */ - if (conn && (conn->ctx->callbacks.log_message == NULL || - conn->ctx->callbacks.log_message(conn, buf) == 0)) { - fp = conn->ctx->config[ERROR_LOG_FILE] == NULL - ? NULL - : fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); - - if (fp != NULL) { - flockfile(fp); - timestamp = time(NULL); - - sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); - fprintf(fp, - "[%010lu] [error] [client %s] ", - (unsigned long)timestamp, - src_addr); - - if (conn->request_info.request_method != NULL) { - fprintf(fp, - "%s %s: ", - conn->request_info.request_method, - conn->request_info.uri); - } - - fprintf(fp, "%s", buf); - fputc('\n', fp); - funlockfile(fp); - fclose(fp); - } - } +void mg_cry(struct mg_connection *conn, const char *fmt, ...) +{ + char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN]; + va_list ap; + FILE *fp; + time_t timestamp; + + va_start(ap, fmt); + IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap)); + va_end(ap); + + /* Do not lock when getting the callback value, here and below. + I suppose this is fine, since function cannot disappear in the + same way string option can. */ + if (conn->ctx->callbacks.log_message == NULL || + conn->ctx->callbacks.log_message(conn, buf) == 0) { + fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : + fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); + + if (fp != NULL) { + flockfile(fp); + timestamp = time(NULL); + + sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa); + fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp, + src_addr); + + if (conn->request_info.request_method != NULL) { + fprintf(fp, "%s %s: ", conn->request_info.request_method, + conn->request_info.uri); + } + + fprintf(fp, "%s", buf); + fputc('\n', fp); + funlockfile(fp); + fclose(fp); + } + } } /* Return fake connection structure. Used for logging, if connection - * is not applicable at the moment of logging. */ + 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; + static struct mg_connection fake_connection; + fake_connection.ctx = ctx; + return &fake_connection; } -const char *mg_version(void) { return CIVETWEB_VERSION; } +const char *mg_version(void) +{ + return CIVETWEB_VERSION; +} -const struct mg_request_info * -mg_get_request_info(const struct mg_connection *conn) +struct mg_request_info *mg_get_request_info(struct mg_connection *conn) { - if (!conn) { - return NULL; - } - return &conn->request_info; + return &conn->request_info; } /* Skip the characters until one of the delimiters characters found. - * 0-terminate resulting word. Skip the delimiter and following whitespaces. - * Advance pointer to buffer to the next word. Return found 0-terminated word. - * Delimiters can be quoted with quotechar. */ -static char *skip_quoted(char **buf, - const char *delimiters, - const char *whitespace, - char quotechar) -{ - char *p, *begin_word, *end_word, *end_whitespace; - - begin_word = *buf; - end_word = begin_word + strcspn(begin_word, delimiters); - - /* Check for quotechar */ - if (end_word > begin_word) { - p = end_word - 1; - while (*p == quotechar) { - /* TODO (bel, low): it seems this code is never reached, so - * quotechar is actually not needed - check if this code may be - * droped */ - - /* If there is anything beyond end_word, copy it */ - if (*end_word == '\0') { - *p = '\0'; - break; - } else { - size_t end_off = strcspn(end_word + 1, delimiters); - memmove(p, end_word, end_off + 1); - p += end_off; /* p must correspond to end_word - 1 */ - end_word += end_off + 1; - } - } - for (p++; p < end_word; p++) { - *p = '\0'; - } - } - - if (*end_word == '\0') { - *buf = end_word; - } else { - end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); - - for (p = end_word; p < end_whitespace; p++) { - *p = '\0'; - } - - *buf = end_whitespace; - } - - return begin_word; + 0-terminate resulting word. Skip the delimiter and following whitespaces. + Advance pointer to buffer to the next word. Return found 0-terminated word. + Delimiters can be quoted with quotechar. */ +static char *skip_quoted(char **buf, const char *delimiters, + const char *whitespace, char quotechar) +{ + char *p, *begin_word, *end_word, *end_whitespace; + + begin_word = *buf; + end_word = begin_word + strcspn(begin_word, delimiters); + + /* Check for quotechar */ + if (end_word > begin_word) { + p = end_word - 1; + while (*p == quotechar) { + /* TODO (bel): it seems this code is never reached, so quotechar is actually + not needed - check if this code may be droped */ + + /* If there is anything beyond end_word, copy it */ + if (*end_word == '\0') { + *p = '\0'; + break; + } else { + size_t end_off = strcspn(end_word + 1, delimiters); + memmove (p, end_word, end_off + 1); + p += end_off; /* p must correspond to end_word - 1 */ + end_word += end_off + 1; + } + } + for (p++; p < end_word; p++) { + *p = '\0'; + } + } + + if (*end_word == '\0') { + *buf = end_word; + } else { + end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); + + for (p = end_word; p < end_whitespace; p++) { + *p = '\0'; + } + + *buf = end_whitespace; + } + + return begin_word; } /* Simplified version of skip_quoted without quote char - * and whitespace == delimiters */ + and whitespace == delimiters */ static char *skip(char **buf, const char *delimiters) { - return skip_quoted(buf, delimiters, delimiters, 0); + return skip_quoted(buf, delimiters, delimiters, 0); } + /* Return HTTP header value, or NULL if not found. */ static const char *get_header(const struct mg_request_info *ri, const char *name) { - int i; - if (ri) { - for (i = 0; i < ri->num_headers; i++) { - if (!mg_strcasecmp(name, ri->http_headers[i].name)) { - return ri->http_headers[i].value; - } - } - } + 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; + return NULL; } const char *mg_get_header(const struct mg_connection *conn, const char *name) { - if (!conn) { - return NULL; - } - - return get_header(&conn->request_info, name); + return get_header(&conn->request_info, name); } /* A helper function for traversing a comma separated list of values. - * It returns a list pointer shifted to the next value, or NULL if the end - * of the list found. - * Value is stored in val vector. If value has form "x=y", then eq_val - * vector is initialized to point to the "y" part, and val vector length - * is adjusted to point only to "x". */ -static const char * -next_option(const char *list, struct vec *val, struct vec *eq_val) -{ - if (val == NULL || 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 = ((size_t)(list - val->ptr)); - list++; - } else { - /* This value is the last one */ - list = val->ptr + strlen(val->ptr); - val->len = ((size_t)(list - val->ptr)); - } - - if (eq_val != NULL) { - /* Value has form "x=y", adjust pointers and lengths - * so that val points to "x", and eq_val points to "y". */ - eq_val->len = 0; - eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len); - if (eq_val->ptr != NULL) { - eq_val->ptr++; /* Skip over '=' character */ - eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len; - val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1; - } - } - } - - return list; + It returns a list pointer shifted to the next value, or NULL if the end + of the list found. + Value is stored in val vector. If value has form "x=y", then eq_val + vector is initialized to point to the "y" part, and val vector length + is adjusted to point only to "x". */ +static const char *next_option(const char *list, struct vec *val, + struct vec *eq_val) +{ + if (list == NULL || *list == '\0') { + /* End of the list */ + list = NULL; + } else { + val->ptr = list; + if ((list = strchr(val->ptr, ',')) != NULL) { + /* Comma found. Store length and shift the list ptr */ + val->len = list - val->ptr; + list++; + } else { + /* This value is the last one */ + list = val->ptr + strlen(val->ptr); + val->len = list - val->ptr; + } + + if (eq_val != NULL) { + /* Value has form "x=y", adjust pointers and lengths + so that val points to "x", and eq_val points to "y". */ + eq_val->len = 0; + eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len); + if (eq_val->ptr != NULL) { + eq_val->ptr++; /* Skip over '=' character */ + eq_val->len = val->ptr + val->len - eq_val->ptr; + val->len = (eq_val->ptr - val->ptr) - 1; + } + } + } + + return list; } /* Perform case-insensitive match of string against pattern */ -static int -match_prefix(const char *pattern, size_t pattern_len, const char *str) -{ - const char *or_str; - size_t i; - int j, len, res; - - if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) { - res = match_prefix(pattern, (size_t)(or_str - pattern), str); - return res > 0 ? res : match_prefix(or_str + 1, - (size_t)((pattern + pattern_len) - - (or_str + 1)), - str); - } - - for (i = 0, j = 0; i < pattern_len; i++, j++) { - if (pattern[i] == '?' && str[j] != '\0') { - continue; - } else if (pattern[i] == '$') { - return str[j] == '\0' ? j : -1; - } else if (pattern[i] == '*') { - i++; - if (pattern[i] == '*') { - i++; - len = (int)strlen(str + j); - } else { - len = (int)strcspn(str + j, "/"); - } - if (i == pattern_len) { - return j + len; - } - do { - res = match_prefix(pattern + i, pattern_len - i, str + j + len); - } while (res == -1 && len-- > 0); - return res == -1 ? -1 : j + res + len; - } else if (lowercase(&pattern[i]) != lowercase(&str[j])) { - return -1; - } - } - return j; +static int match_prefix(const char *pattern, int pattern_len, const char *str) +{ + const char *or_str; + int i, j, len, res; + + if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) { + res = match_prefix(pattern, (int)(or_str - pattern), str); + return res > 0 ? res : + match_prefix(or_str + 1, (int)((pattern + pattern_len) - (or_str + 1)), str); + } + + i = j = 0; + for (; i < pattern_len; i++, j++) { + if (pattern[i] == '?' && str[j] != '\0') { + continue; + } else if (pattern[i] == '$') { + return str[j] == '\0' ? j : -1; + } else if (pattern[i] == '*') { + i++; + if (pattern[i] == '*') { + i++; + len = (int) strlen(str + j); + } else { + len = (int) strcspn(str + j, "/"); + } + if (i == pattern_len) { + return j + len; + } + do { + res = match_prefix(pattern + i, pattern_len - i, str + j + len); + } while (res == -1 && len-- > 0); + return res == -1 ? -1 : j + res + len; + } else if (lowercase(&pattern[i]) != lowercase(&str[j])) { + return -1; + } + } + return j; } /* HTTP 1.1 assumes keep alive if "Connection:" header is not set - * This function must tolerate situations when connection info is not - * set up, for example if request parsing failed. */ + 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) { - if (conn != NULL) { - const char *http_version = conn->request_info.http_version; - const char *header = mg_get_header(conn, "Connection"); - if (conn->must_close || conn->status_code == 401 || - mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 || - (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) || - (header == NULL && http_version && - 0 != strcmp(http_version, "1.1"))) { - return 0; - } - return 1; - } - return 0; + const char *http_version = conn->request_info.http_version; + const char *header = mg_get_header(conn, "Connection"); + if (conn->must_close || + conn->status_code == 401 || + mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 || + (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) || + (header == NULL && http_version && 0!=strcmp(http_version, "1.1"))) { + return 0; + } + return 1; } static int should_decode_url(const struct mg_connection *conn) { - if (!conn || !conn->ctx) { - return 0; - } - - return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0); + return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0); } static const char *suggest_connection_header(const struct mg_connection *conn) { - return should_keep_alive(conn) ? "keep-alive" : "close"; -} - -static void handle_file_based_request(struct mg_connection *conn, - const char *path, - struct file *filep); -static int -mg_stat(struct mg_connection *conn, const char *path, struct file *filep); - -static const char *mg_get_response_code_text(int response_code, - struct mg_connection *conn) -{ - switch (response_code) { - /* RFC2616 Section 10.1 - Informational 1xx */ - case 100: - return "Continue"; /* RFC2616 Section 10.1.1 */ - case 101: - return "Switching Protocols"; /* RFC2616 Section 10.1.2 */ - case 102: - return "Processing"; /* RFC2518 Section 10.1 */ - - /* RFC2616 Section 10.2 - Successful 2xx */ - case 200: - return "OK"; /* RFC2616 Section 10.2.1 */ - case 201: - return "Created"; /* RFC2616 Section 10.2.2 */ - case 202: - return "Accepted"; /* RFC2616 Section 10.2.3 */ - case 203: - return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */ - case 204: - return "No Content"; /* RFC2616 Section 10.2.5 */ - case 205: - return "Reset Content"; /* RFC2616 Section 10.2.6 */ - case 206: - return "Partial Content"; /* RFC2616 Section 10.2.7 */ - case 207: - return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */ - - /* RFC2616 Section 10.3 - Redirection 3xx */ - case 300: - return "Multiple Choices"; /* RFC2616 Section 10.3.1 */ - case 301: - return "Moved Permanently"; /* RFC2616 Section 10.3.2 */ - case 302: - return "Found"; /* RFC2616 Section 10.3.3 */ - case 303: - return "See Other"; /* RFC2616 Section 10.3.4 */ - case 304: - return " <TRUNCATED>