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 2015/07/04 13:21:04 UTC
[12/16] celix git commit: CELIX-245: Update civetweb
http://git-wip-us.apache.org/repos/asf/celix/blob/3de9cafd/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 5c1b5ae..0069307 100644
--- a/remote_services/utils/private/src/civetweb.c
+++ b/remote_services/utils/private/src/civetweb.c
@@ -24,41 +24,77 @@
#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 */
+#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 */
#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)
+#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
-/* Disable WIN32_LEAN_AND_MEAN.
- This makes windows.h always include winsock2.h */
-#if defined(WIN32_LEAN_AND_MEAN)
-#undef WIN32_LEAN_AND_MEAN
+/* 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]
#endif
-#if defined USE_IPV6 && defined(_WIN32)
-#include <ws2tcpip.h>
+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
#endif
#if defined(__SYMBIAN32__)
@@ -68,7 +104,7 @@
#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 */
@@ -79,6 +115,61 @@
#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>
@@ -90,21 +181,32 @@
#include <stdio.h>
#ifndef MAX_WORKER_THREADS
-#define MAX_WORKER_THREADS (1024*64)
+#define MAX_WORKER_THREADS (1024 * 64)
+#endif
+#ifndef SOCKET_TIMEOUT_QUANTUM
+#define SOCKET_TIMEOUT_QUANTUM (10000)
#endif
+mg_static_assert(MAX_WORKER_THREADS >= 1,
+ "worker threads must be a positive number");
+
#if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */
-#if defined(_MSC_VER) && _MSC_VER <= 1400
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */
-#endif
#include <windows.h>
-typedef const char * SOCK_OPT_TYPE;
+#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
+#include <ws2tcpip.h>
+
+typedef const char *SOCK_OPT_TYPE;
-#ifndef PATH_MAX
-#define PATH_MAX MAX_PATH
+#if !defined(PATH_MAX)
+#define PATH_MAX (MAX_PATH)
+#endif
+
+#if !defined(PATH_MAX)
+#define PATH_MAX (4096)
#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
@@ -115,94 +217,96 @@ typedef const char * SOCK_OPT_TYPE;
#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 GetLastError()
-#define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
+#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)
+#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
+ * 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)
+#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)
+#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 GetLastError()
+#define ERRNO ((int)(GetLastError()))
#define NO_SOCKLEN_T
-#define SSL_LIB "ssleay32.dll"
-#define CRYPTO_LIB "libeay32.dll"
-#define O_NONBLOCK 0
+#define SSL_LIB "ssleay32.dll"
+#define CRYPTO_LIB "libeay32.dll"
+#define O_NONBLOCK (0)
+#ifndef W_OK
#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_WR 1
+#define SHUT_RD (0)
+#define SHUT_WR (1)
+#define SHUT_BOTH (2)
#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
@@ -212,13 +316,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
@@ -233,41 +337,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(USE_IPV6) && defined(_WIN32)
+#if defined(_WIN32) && !defined(POLLIN)
#ifndef HAVE_POLL
struct pollfd {
- SOCKET fd;
- short events;
- short revents;
+ SOCKET fd;
+ short events;
+ short revents;
};
-#define POLLIN 1
+#define POLLIN (0x0300)
#endif
#endif
/* Mark required libraries */
-#ifdef _MSC_VER
+#if defined(_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>
@@ -278,7 +382,7 @@ 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)
typedef unsigned short int in_port_t;
@@ -286,244 +390,312 @@ typedef unsigned short int in_port_t;
#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(); }
-int pthread_key_create(pthread_key_t *key, void (*_must_be_zero)(void*) /* destructor function not supported for windows */)
+static 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;
}
-int pthread_key_delete(pthread_key_t key)
+static int pthread_key_delete(pthread_key_t key)
{
- return TlsFree(key) ? 0 : 1;
+ return TlsFree(key) ? 0 : 1;
}
-int pthread_setspecific(pthread_key_t key, void * value)
+static int pthread_setspecific(pthread_key_t key, void *value)
{
- return TlsSetValue(key, value) ? 0 : 1;
+ return TlsSetValue(key, value) ? 0 : 1;
}
-void *pthread_getspecific(pthread_key_t key)
-{
- return TlsGetValue(key);
-}
+#ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
+static void *pthread_getspecific(pthread_key_t key) { return TlsGetValue(key); }
+#endif
#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, const char *fmt, ...) {
+static void DEBUG_TRACE_FUNC(const char *func,
+ unsigned line,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(3, 4);
- 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, ...)
+#define DEBUG_TRACE(fmt, ...) \
+ do { \
+ } while (0)
#endif /* DEBUG */
#endif /* DEBUG_TRACE */
#if defined(MEMORY_DEBUGGING)
-static unsigned long blockCount = 0;
-static unsigned long totalMemUsed = 0;
-
-static void * mg_malloc_ex(size_t size, const char * file, unsigned line) {
-
- void * data = malloc(size + sizeof(size_t));
- void * memory = 0;
- char mallocStr[256];
-
- if (data) {
- *(size_t*)data = size;
- totalMemUsed += size;
- blockCount++;
- memory = (void *)(((char*)data)+sizeof(size_t));
- }
-
- sprintf(mallocStr, "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)size, totalMemUsed, blockCount, file, line);
+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);
#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)
+{
+ 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 (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);
#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;
- totalMemUsed -= oldsize;
- sprintf(mallocStr, "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", memory, (unsigned long)oldsize, totalMemUsed, 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;
+ 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);
#if defined(_WIN32)
- OutputDebugStringA(mallocStr);
+ OutputDebugStringA(mallocStr);
#else
- DEBUG_TRACE("%s", mallocStr);
+ DEBUG_TRACE("%s", mallocStr);
#endif
- totalMemUsed += newsize;
- sprintf(mallocStr, "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", memory, (unsigned long)newsize, totalMemUsed, blockCount, file, line);
+ 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);
#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"
@@ -534,23 +706,19 @@ 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
-#endif
-
-#if !defined(PATH_MAX)
-#define PATH_MAX 4096
+#define SOMAXCONN (100)
#endif
/* Size of the accepted socket queue */
#if !defined(MGSQLEN)
-#define MGSQLEN 20
+#define MGSQLEN (20)
#endif
#if defined(NO_SSL_DL)
@@ -558,308 +726,374 @@ 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 {
- 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;
+ 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 */
};
-#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
+#define STRUCT_FILE_INITIALIZER \
+ { \
+ (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 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 is_ssl:1; /* Is port SSL-ed */
- unsigned ssl_redir:1; /* Is port supposed to redirect everything to SSL
- port */
+ SOCKET sock; /* Listening socket */
+ union usa lsa; /* Local socket address */
+ union usa rsa; /* Remote socket address */
+ unsigned char is_ssl; /* Is port SSL-ed */
+ unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
+ * port */
};
/* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
enum {
- CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
- PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
- ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
- GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
- EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
- NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
- DECODE_URL,
+ 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,
#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"},
- {"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"},
+#if defined(USE_WEBSOCKET)
+ {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
+#endif
+ {"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},
+ {"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");
- {NULL, CONFIG_TYPE_UNKNOWN, NULL}
-};
struct mg_request_handler_info {
- char *uri;
- size_t uri_len;
- mg_request_handler handler;
+ /* 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;
+
+ /* User supplied argument for the handler function. */
+ void *cbdata;
- void *cbdata;
- struct mg_request_handler_info *next;
+ /* next request handler in a linked list */
+ struct mg_request_handler_info *next;
};
struct mg_context {
- volatile int stop_flag; /* Should we stop event loop */
- SSL_CTX *ssl_ctx; /* SSL context */
- char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
- struct mg_callbacks callbacks; /* User-defined callback function */
- void *user_data; /* User-defined data */
- int context_type; /* 1 = server context, 2 = client context */
-
- struct socket *listening_sockets;
- in_port_t *listening_ports;
- int num_listening_sockets;
-
- volatile int num_threads; /* Number of threads */
- pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */
- pthread_cond_t thread_cond; /* Condvar for tracking workers terminations */
-
- struct socket queue[MGSQLEN]; /* Accepted sockets */
- volatile int sq_head; /* Head of the socket queue */
- volatile int sq_tail; /* Tail of the socket queue */
- pthread_cond_t sq_full; /* Signaled when socket is produced */
- pthread_cond_t sq_empty; /* Signaled when socket is consumed */
- pthread_t masterthreadid; /* The master thread ID */
- int workerthreadcount; /* The amount of worker threads. */
- pthread_t *workerthreadids; /* The worker thread IDs */
-
- unsigned long start_time; /* Server start time, used for authentication */
- pthread_mutex_t nonce_mutex; /* Protects nonce_count */
- unsigned long nonce_count; /* Used nonces, used for authentication */
-
- char *systemName; /* What operating system is running */
-
- /* linked list of uri handlers */
- struct mg_request_handler_info *request_handlers;
+ 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;
#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 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 */
+ 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 */
#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)
@@ -868,4450 +1102,5690 @@ static int is_websocket_protocol(const struct mg_connection *conn);
#define is_websocket_protocol(conn) (0)
#endif
-int mg_atomic_inc(volatile int * addr)
+static int mg_atomic_inc(volatile int *addr)
{
- int ret;
+ int ret;
#if defined(_WIN32) && !defined(__SYMBIAN32__)
- ret = InterlockedIncrement((volatile unsigned int *) addr);
+ /* 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__)
- ret = __sync_add_and_fetch(addr, 1);
+ ret = __sync_add_and_fetch(addr, 1);
#else
- ret = (++(*addr));
+ ret = (++(*addr));
#endif
- return ret;
+ return ret;
}
-int mg_atomic_dec(volatile int * addr)
+static int mg_atomic_dec(volatile int *addr)
{
- int ret;
+ int ret;
#if defined(_WIN32) && !defined(__SYMBIAN32__)
- ret = InterlockedDecrement((volatile unsigned int *) addr);
+ /* 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__)
- 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
-void mg_set_thread_name(const char* name)
+static void mg_set_thread_name(const char *name)
{
- char threadName[16]; /* Max. thread length in Linux/OSX/.. */
+ char threadName[16]; /* Max. thread length in Linux/OSX/.. */
- if (snprintf(threadName, sizeof(threadName), "civetweb-%s", name)<0) return;
- threadName[sizeof(threadName)-1] = 0;
+ /* 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;
+ }
+
+ threadName[sizeof(threadName) - 1] = 0;
#if defined(_WIN32)
#if defined(_MSC_VER)
- /* Windows and Visual Studio Compiler */
- __try
- {
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = threadName;
- info.dwThreadID = -1;
- info.dwFlags = 0;
-
- RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- }
+ /* 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 */
+ /* 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);
+ /* 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, ... */
#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;
-}
-
+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,
+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;
+ size_t size = 0;
+ if (!conn || !filep) {
+ return 0;
+ }
+
+ 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_opened(const struct file *filep)
{
- return filep->membuf != NULL || filep->fp != NULL;
+ if (!filep) {
+ return 0;
+ }
+
+ 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 (!is_file_in_memory(conn, path, filep)) {
+ if (!filep) {
+ return 0;
+ }
+
+ 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)
{
- int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str);
+ size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
- for (i = 0; i <= big_len - small_len; i++) {
- if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
- return big_str + i;
- }
- }
+ 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;
+ }
+ }
+ }
- 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;
+ * 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
- if (buflen == 0)
- return 0;
+ n = vsnprintf(buf, buflen, fmt, ap);
- n = vsnprintf(buf, buflen, fmt, ap);
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
- 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->config[i] == NULL) {
- return "";
- } else {
- return ctx->config[i];
- }
+ 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;
}
-struct mg_context *mg_get_context(struct mg_connection * conn)
+void mg_set_user_connection_data(const struct mg_connection *conn, void *data)
{
- return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
+ if (conn != NULL) {
+ ((struct mg_connection *)conn)->request_info.conn_data = data;
+ }
}
-void *mg_get_user_data(struct mg_context *ctx)
+void *mg_get_user_connection_data(const struct mg_connection *conn)
{
- return (ctx == NULL) ? NULL : ctx->user_data;
+ if (conn != NULL) {
+ return conn->request_info.conn_data;
+ }
+ return NULL;
}
-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;
- 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;
+ 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;
}
-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';
+ 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);
+ }
#if defined(USE_IPV6)
- inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
- (void *) &usa->sin.sin_addr :
- (void *) &usa->sin6.sin6_addr, buf, len);
-#elif defined(_WIN32)
- /* Only Windows Vista (and newer) have inet_ntop() */
- mg_strlcpy(buf, inet_ntoa(usa->sin.sin_addr), len);
-#else
- inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
+ else if (usa->sa.sa_family == AF_INET6) {
+ getnameinfo(&usa->sa,
+ sizeof(usa->sin6),
+ buf,
+ (unsigned)len,
+ NULL,
+ 0,
+ NI_NUMERICHOST);
+ }
#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;
+ 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';
+ }
+}
- 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';
- }
+/* 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);
}
/* Print error message to the opened error log stream. */
-void mg_cry(struct mg_connection *conn, const char *fmt, ...)
-{
- char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
- va_list ap;
- FILE *fp;
- time_t timestamp;
-
- va_start(ap, fmt);
- IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap));
- va_end(ap);
-
- /* Do not lock when getting the callback value, here and below.
- I suppose this is fine, since function cannot disappear in the
- same way string option can. */
- if (conn->ctx->callbacks.log_message == NULL ||
- conn->ctx->callbacks.log_message(conn, buf) == 0) {
- fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
- fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
-
- if (fp != NULL) {
- flockfile(fp);
- timestamp = time(NULL);
-
- sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
- fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
- src_addr);
-
- if (conn->request_info.request_method != NULL) {
- fprintf(fp, "%s %s: ", conn->request_info.request_method,
- conn->request_info.uri);
- }
-
- fprintf(fp, "%s", buf);
- fputc('\n', fp);
- funlockfile(fp);
- fclose(fp);
- }
- }
+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);
+ }
+ }
}
/* 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; }
-struct mg_request_info *mg_get_request_info(struct mg_connection *conn)
+const struct mg_request_info *
+mg_get_request_info(const struct mg_connection *conn)
{
- return &conn->request_info;
+ if (!conn) {
+ return NULL;
+ }
+ return &conn->request_info;
}
/* Skip the characters until one of the delimiters characters found.
- 0-terminate resulting word. Skip the delimiter and following whitespaces.
- Advance pointer to buffer to the next word. Return found 0-terminated word.
- Delimiters can be quoted with quotechar. */
-static char *skip_quoted(char **buf, const char *delimiters,
- const char *whitespace, char quotechar)
-{
- char *p, *begin_word, *end_word, *end_whitespace;
-
- begin_word = *buf;
- end_word = begin_word + strcspn(begin_word, delimiters);
-
- /* Check for quotechar */
- if (end_word > begin_word) {
- p = end_word - 1;
- while (*p == quotechar) {
- /* TODO (bel): it seems this code is never reached, so quotechar is actually
- not needed - check if this code may be droped */
-
- /* If there is anything beyond end_word, copy it */
- if (*end_word == '\0') {
- *p = '\0';
- break;
- } else {
- size_t end_off = strcspn(end_word + 1, delimiters);
- memmove (p, end_word, end_off + 1);
- p += end_off; /* p must correspond to end_word - 1 */
- end_word += end_off + 1;
- }
- }
- for (p++; p < end_word; p++) {
- *p = '\0';
- }
- }
-
- if (*end_word == '\0') {
- *buf = end_word;
- } else {
- end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
-
- for (p = end_word; p < end_whitespace; p++) {
- *p = '\0';
- }
-
- *buf = end_whitespace;
- }
-
- return begin_word;
+ * 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;
}
/* 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;
-
- 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;
+ 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;
+ }
+ }
+ }
- return NULL;
+ return NULL;
}
const char *mg_get_header(const struct mg_connection *conn, const char *name)
{
- return get_header(&conn->request_info, name);
+ if (!conn) {
+ return NULL;
+ }
+
+ return get_header(&conn->request_info, name);
}
/* A helper function for traversing a comma separated list of values.
- It returns a list pointer shifted to the next value, or NULL if the end
- of the list found.
- Value is stored in val vector. If value has form "x=y", then eq_val
- vector is initialized to point to the "y" part, and val vector length
- is adjusted to point only to "x". */
-static const char *next_option(const char *list, struct vec *val,
- struct vec *eq_val)
-{
- if (list == NULL || *list == '\0') {
- /* End of the list */
- list = NULL;
- } else {
- val->ptr = list;
- if ((list = strchr(val->ptr, ',')) != NULL) {
- /* Comma found. Store length and shift the list ptr */
- val->len = list - val->ptr;
- list++;
- } else {
- /* This value is the last one */
- list = val->ptr + strlen(val->ptr);
- val->len = list - val->ptr;
- }
-
- if (eq_val != NULL) {
- /* Value has form "x=y", adjust pointers and lengths
- so that val points to "x", and eq_val points to "y". */
- eq_val->len = 0;
- eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
- if (eq_val->ptr != NULL) {
- eq_val->ptr++; /* Skip over '=' character */
- eq_val->len = val->ptr + val->len - eq_val->ptr;
- val->len = (eq_val->ptr - val->ptr) - 1;
- }
- }
- }
-
- return list;
+ * 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;
}
/* Perform case-insensitive match of string against pattern */
-static int match_prefix(const char *pattern, int pattern_len, const char *str)
-{
- const char *or_str;
- int i, j, len, res;
-
- if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
- res = match_prefix(pattern, (int)(or_str - pattern), str);
- return res > 0 ? res :
- match_prefix(or_str + 1, (int)((pattern + pattern_len) - (or_str + 1)), str);
- }
-
- i = j = 0;
- for (; i < pattern_len; i++, j++) {
- if (pattern[i] == '?' && str[j] != '\0') {
- continue;
- } else if (pattern[i] == '$') {
- return str[j] == '\0' ? j : -1;
- } else if (pattern[i] == '*') {
- i++;
- if (pattern[i] == '*') {
- i++;
- len = (int) strlen(str + j);
- } else {
- len = (int) strcspn(str + j, "/");
- }
- if (i == pattern_len) {
- return j + len;
- }
- do {
- res = match_prefix(pattern + i, pattern_len - i, str + j + len);
- } while (res == -1 && len-- > 0);
- return res == -1 ? -1 : j + res + len;
- } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
- return -1;
- }
- }
- return j;
+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;
}
/* 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)
{
- 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;
+ 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;
}
static int should_decode_url(const struct mg_connection *conn)
{
- return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0);
+ if (!conn || !conn->ctx) {
+ return 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 "Not Modified"; /* RFC2616 Section 10.3.5 */
- case 305: return "Use Proxy"; /* RFC2616 Section 10.3.6 */
- case 307: return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
-
- /* RFC2616 Section 10.4 - Client Error 4xx */
- case 400: return "Bad Request"; /* RFC2616 Section 10.4.1 */
- case 401: return "Unauthorized"; /* RFC2616 Section 10.4.2 */
- case 402: return "Payment Required"; /* RFC2616 Section 10.4.3 */
- case 403: return "Forbidden"; /* RFC2616 Section 10.4.4 */
- case 404: return "Not Found"; /* RFC2616 Section 10.4.5 */
- case 405: return "Method Not Allowed"; /* RFC2616 Section 10.
<TRUNCATED>