23#if defined(__GNUC__) || defined(__MINGW32__)
26 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
28#if GCC_VERSION >= 40500
34#if defined(GCC_DIAGNOSTIC)
37#pragma GCC diagnostic ignored "-Wunused-macros"
39#pragma GCC diagnostic ignored "-Wpadded"
46#pragma GCC diagnostic push
47#pragma GCC diagnostic ignored "-Wreserved-id-macro"
51#if !defined(_CRT_SECURE_NO_WARNINGS)
52#define _CRT_SECURE_NO_WARNINGS
54#if !defined(_WIN32_WINNT)
55#define _WIN32_WINNT 0x0601
58#if !defined(_GNU_SOURCE)
61#if defined(__linux__) && !defined(_XOPEN_SOURCE)
62#define _XOPEN_SOURCE 600
64#if defined(__LSB_VERSION__) || defined(__sun)
68#if !defined(_LARGEFILE_SOURCE)
69#define _LARGEFILE_SOURCE
71#if !defined(_FILE_OFFSET_BITS)
72#define _FILE_OFFSET_BITS 64
74#if !defined(__STDC_FORMAT_MACROS)
75#define __STDC_FORMAT_MACROS
77#if !defined(__STDC_LIMIT_MACROS)
78#define __STDC_LIMIT_MACROS
80#if !defined(_DARWIN_UNLIMITED_SELECT)
81#define _DARWIN_UNLIMITED_SELECT
85#define __inline inline
91#pragma GCC diagnostic pop
101#pragma warning(disable : 4306)
103#pragma warning(disable : 4127)
105#pragma warning(disable : 4204)
107#pragma warning(disable : 4820)
109#pragma warning(disable : 4668)
111#pragma warning(disable : 4255)
113#pragma warning(disable : 4711)
120#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201100L
121#define mg_static_assert _Static_assert
122#elif defined(__cplusplus) && __cplusplus >= 201103L
123#define mg_static_assert static_assert
126#define mg_static_assert(cond, txt) \
127 extern char static_assert_replacement[(cond) ? 1 : -1]
131 "int data type size check");
133 "pointer data type size check");
145#if defined(NO_ALTERNATIVE_QUEUE) && defined(ALTERNATIVE_QUEUE)
148 "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE (or none of them), but not both"
150#if !defined(NO_ALTERNATIVE_QUEUE) && !defined(ALTERNATIVE_QUEUE)
152#define NO_ALTERNATIVE_QUEUE
155#if defined(NO_FILESYSTEMS) && !defined(NO_FILES)
170#error "Inconsistent build flags, NO_FILESYSTEMS requires NO_FILES"
174#if !defined(WIN32_LEAN_AND_MEAN)
175#define WIN32_LEAN_AND_MEAN
178#if defined(__SYMBIAN32__)
183#error "Symbian is no longer maintained. CivetWeb no longer supports Symbian."
186#if defined(__rtems__)
187#include <rtems/version.h>
190#if defined(__ZEPHYR__)
199#include <sys/socket.h>
202#include <zephyr/kernel.h>
207#define MAX_WORKER_THREADS (CONFIG_MAX_PTHREAD_COUNT - 2)
209#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
210#define ZEPHYR_STACK_SIZE USE_STACK_SIZE
212#define ZEPHYR_STACK_SIZE (1024 * 16)
215K_THREAD_STACK_DEFINE(civetweb_main_stack, ZEPHYR_STACK_SIZE);
216K_THREAD_STACK_ARRAY_DEFINE(civetweb_worker_stacks,
220static int zephyr_worker_stack_index;
224#if !defined(CIVETWEB_HEADER_INCLUDED)
230#if !defined(DEBUG_TRACE)
232static void DEBUG_TRACE_FUNC(
const char *func,
237#define DEBUG_TRACE(fmt, ...) \
238 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
240#define NEED_DEBUG_TRACE_FUNC
241#if !defined(DEBUG_TRACE_STREAM)
242#define DEBUG_TRACE_STREAM stderr
246#define DEBUG_TRACE(fmt, ...) \
253#if !defined(DEBUG_ASSERT)
256#define DEBUG_ASSERT(cond) \
259 DEBUG_TRACE("ASSERTION FAILED: %s", #cond); \
264#define DEBUG_ASSERT(cond)
269#if defined(__GNUC__) && defined(GCC_INSTRUMENTATION)
270void __cyg_profile_func_enter(
void *this_fn,
void *call_site)
271 __attribute__((no_instrument_function));
273void __cyg_profile_func_exit(
void *this_fn,
void *call_site)
274 __attribute__((no_instrument_function));
277__cyg_profile_func_enter(
void *this_fn,
void *call_site)
279 if ((
void *)this_fn != (
void *)printf) {
280 printf(
"E %p %p\n", this_fn, call_site);
285__cyg_profile_func_exit(
void *this_fn,
void *call_site)
287 if ((
void *)this_fn != (
void *)printf) {
288 printf(
"X %p %p\n", this_fn, call_site);
294#if !defined(IGNORE_UNUSED_RESULT)
295#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
299#if defined(__GNUC__) || defined(__MINGW32__)
315#pragma GCC diagnostic ignored "-Wunused-function"
317#define FUNCTION_MAY_BE_UNUSED
320#define FUNCTION_MAY_BE_UNUSED
325#if !defined(_WIN32_WCE) && !defined(__ZEPHYR__)
331#include <sys/types.h>
335#if defined(__clang__)
339#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
342#if defined(__GNUC__) || defined(__MINGW32__)
359#if defined(__MACH__) && defined(__APPLE__)
361#if defined(__clang__)
362#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
364#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
365#pragma clang diagnostic ignored "-Wno-keyword-macro"
369#ifndef CLOCK_MONOTONIC
370#define CLOCK_MONOTONIC (1)
372#ifndef CLOCK_REALTIME
373#define CLOCK_REALTIME (2)
376#include <mach/clock.h>
377#include <mach/mach.h>
378#include <mach/mach_time.h>
379#include <sys/errno.h>
384_civet_clock_gettime(
int clk_id,
struct timespec *t)
386 memset(t, 0,
sizeof(*t));
387 if (clk_id == CLOCK_REALTIME) {
389 int rv = gettimeofday(&now, NULL);
393 t->tv_sec = now.tv_sec;
394 t->tv_nsec = now.tv_usec * 1000;
397 }
else if (clk_id == CLOCK_MONOTONIC) {
398 static uint64_t clock_start_time = 0;
399 static mach_timebase_info_data_t timebase_ifo = {0, 0};
401 uint64_t now = mach_absolute_time();
403 if (clock_start_time == 0) {
404 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
410 clock_start_time = now;
413 now = (uint64_t)((
double)(now - clock_start_time)
414 * (
double)timebase_ifo.numer
415 / (
double)timebase_ifo.denom);
417 t->tv_sec = now / 1000000000;
418 t->tv_nsec = now % 1000000000;
425#if defined(__CLOCK_AVAILABILITY)
430_civet_safe_clock_gettime(
int clk_id,
struct timespec *t)
433 return clock_gettime(clk_id, t);
435 return _civet_clock_gettime(clk_id, t);
437#define clock_gettime _civet_safe_clock_gettime
439#define clock_gettime _civet_clock_gettime
446#define ERROR_TRY_AGAIN(err) ((err) == WSAEWOULDBLOCK)
451#define ERROR_TRY_AGAIN(err) \
452 (((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR))
468#if !defined(MAX_WORKER_THREADS)
469#define MAX_WORKER_THREADS (1024 * 64)
476#if !defined(SOCKET_TIMEOUT_QUANTUM)
477#define SOCKET_TIMEOUT_QUANTUM (2000)
481#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT)
482#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024)
485#if !defined(PASSWORDS_FILE_NAME)
486#define PASSWORDS_FILE_NAME ".htpasswd"
491#if !defined(CGI_ENVIRONMENT_SIZE)
492#define CGI_ENVIRONMENT_SIZE (4096)
496#if !defined(MAX_CGI_ENVIR_VARS)
497#define MAX_CGI_ENVIR_VARS (256)
501#if !defined(MG_BUF_LEN)
502#define MG_BUF_LEN (1024 * 8)
509#if !defined(ARRAY_SIZE)
510#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
516#if !defined(INT64_MAX)
517#define INT64_MAX (9223372036854775807)
520#define SHUTDOWN_RD (0)
521#define SHUTDOWN_WR (1)
522#define SHUTDOWN_BOTH (2)
525 "worker threads must be a positive number");
528 "size_t data type size check");
546#define UTF8_PATH_MAX (3 * 260)
549#define UTF16_PATH_MAX (260)
551#if !defined(_IN_PORT_T)
552#if !defined(in_port_t)
553#define in_port_t u_short
557#if defined(_WIN32_WCE)
558#error "WinCE support has ended"
566#define MAKEUQUAD(lo, hi) \
567 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
568#define RATE_DIFF (10000000)
569#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
570#define SYS2UNIX_TIME(lo, hi) \
571 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
579#define STR(x) STRX(x)
580#define __func__ __FILE__ ":" STR(__LINE__)
581#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
582#define strtoll(x, y, z) (_atoi64(x))
584#define __func__ __FUNCTION__
585#define strtoull(x, y, z) (_strtoui64(x, y, z))
586#define strtoll(x, y, z) (_strtoi64(x, y, z))
591#define ERRNO ((int)(GetLastError()))
595#if defined(_WIN64) || defined(__MINGW64__)
598#if defined(OPENSSL_API_3_0)
599#define SSL_LIB "libssl-3-x64.dll"
600#define CRYPTO_LIB "libcrypto-3-x64.dll"
603#if defined(OPENSSL_API_1_1)
604#define SSL_LIB "libssl-1_1-x64.dll"
605#define CRYPTO_LIB "libcrypto-1_1-x64.dll"
608#if defined(OPENSSL_API_1_0)
609#define SSL_LIB "ssleay64.dll"
610#define CRYPTO_LIB "libeay64.dll"
617#if defined(OPENSSL_API_3_0)
618#define SSL_LIB "libssl-3.dll"
619#define CRYPTO_LIB "libcrypto-3.dll"
622#if defined(OPENSSL_API_1_1)
623#define SSL_LIB "libssl-1_1.dll"
624#define CRYPTO_LIB "libcrypto-1_1.dll"
627#if defined(OPENSSL_API_1_0)
628#define SSL_LIB "ssleay32.dll"
629#define CRYPTO_LIB "libeay32.dll"
636#define O_NONBLOCK (0)
641#define INT64_FMT "I64d"
642#define UINT64_FMT "I64u"
644#define WINCDECL __cdecl
645#define vsnprintf_impl _vsnprintf
646#define access _access
647#define mg_sleep(x) (Sleep(x))
649#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
651#define popen(x, y) (_popen(x, y))
654#define pclose(x) (_pclose(x))
656#define close(x) (_close(x))
657#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
659#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
660#define fdopen(x, y) (_fdopen((x), (y)))
661#define write(x, y, z) (_write((x), (y), (unsigned)z))
662#define read(x, y, z) (_read((x), (y), (unsigned)z))
663#define flockfile(x) ((void)pthread_mutex_lock(&global_log_file_lock))
664#define funlockfile(x) ((void)pthread_mutex_unlock(&global_log_file_lock))
665#define sleep(x) (Sleep((x)*1000))
666#define rmdir(x) (_rmdir(x))
667#if defined(_WIN64) || !defined(__MINGW32__)
669#define timegm(x) (_mkgmtime(x))
671time_t timegm(
struct tm *tm);
677#define fileno(x) (_fileno(x))
681 CRITICAL_SECTION sec;
683typedef DWORD pthread_key_t;
684typedef HANDLE pthread_t;
686 pthread_mutex_t threadIdSec;
690#if !defined(__clockid_t_defined)
691typedef DWORD clockid_t;
693#if !defined(CLOCK_MONOTONIC)
694#define CLOCK_MONOTONIC (1)
696#if !defined(CLOCK_REALTIME)
697#define CLOCK_REALTIME (2)
699#if !defined(CLOCK_THREAD)
700#define CLOCK_THREAD (3)
702#if !defined(CLOCK_PROCESS)
703#define CLOCK_PROCESS (4)
707#if defined(_MSC_VER) && (_MSC_VER >= 1900)
708#define _TIMESPEC_DEFINED
710#if !defined(_TIMESPEC_DEFINED)
717#if !defined(WIN_PTHREADS_TIME_H)
718#define MUST_IMPLEMENT_CLOCK_GETTIME
721#if defined(MUST_IMPLEMENT_CLOCK_GETTIME)
722#define clock_gettime mg_clock_gettime
724clock_gettime(clockid_t clk_id,
struct timespec *tp)
727 ULARGE_INTEGER li, li2;
730 static double perfcnt_per_sec = 0.0;
731 static BOOL initialized = FALSE;
734 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
735 perfcnt_per_sec = 1.0 / li.QuadPart;
740 memset(tp, 0,
sizeof(*tp));
742 if (clk_id == CLOCK_REALTIME) {
745 GetSystemTimeAsFileTime(&ft);
746 li.LowPart = ft.dwLowDateTime;
747 li.HighPart = ft.dwHighDateTime;
748 li.QuadPart -= 116444736000000000;
749 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
750 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
754 }
else if (clk_id == CLOCK_MONOTONIC) {
757 QueryPerformanceCounter((LARGE_INTEGER *)&li);
758 d = li.QuadPart * perfcnt_per_sec;
759 tp->tv_sec = (time_t)
d;
761 tp->tv_nsec = (long)(
d * 1.0E9);
765 }
else if (clk_id == CLOCK_THREAD) {
768 FILETIME t_create, t_exit, t_kernel, t_user;
769 if (GetThreadTimes(GetCurrentThread(),
774 li.LowPart = t_user.dwLowDateTime;
775 li.HighPart = t_user.dwHighDateTime;
776 li2.LowPart = t_kernel.dwLowDateTime;
777 li2.HighPart = t_kernel.dwHighDateTime;
778 li.QuadPart += li2.QuadPart;
779 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
780 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
785 }
else if (clk_id == CLOCK_PROCESS) {
788 FILETIME t_create, t_exit, t_kernel, t_user;
789 if (GetProcessTimes(GetCurrentProcess(),
794 li.LowPart = t_user.dwLowDateTime;
795 li.HighPart = t_user.dwHighDateTime;
796 li2.LowPart = t_kernel.dwLowDateTime;
797 li2.HighPart = t_kernel.dwHighDateTime;
798 li.QuadPart += li2.QuadPart;
799 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
800 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
820static int pthread_mutex_lock(pthread_mutex_t *);
821static int pthread_mutex_unlock(pthread_mutex_t *);
841 WIN32_FIND_DATAW info;
845#if defined(HAVE_POLL)
846#define mg_pollfd pollfd
857#pragma comment(lib, "Ws2_32.lib")
865#define UTF8_PATH_MAX (PATH_MAX)
870typedef unsigned short int in_port_t;
873#if !defined(__ZEPHYR__)
874#include <arpa/inet.h>
880#include <netinet/in.h>
881#include <netinet/tcp.h>
890#include <sys/socket.h>
892#if !defined(__rtems__)
893#include <sys/utsname.h>
898#if defined(USE_X_DOM_SOCKET)
903#define vsnprintf_impl vsnprintf
905#if !defined(NO_SSL_DL) && !defined(NO_SSL)
909#if defined(__MACH__) && defined(__APPLE__)
911#if defined(OPENSSL_API_3_0)
912#define SSL_LIB "libssl.3.dylib"
913#define CRYPTO_LIB "libcrypto.3.dylib"
916#if defined(OPENSSL_API_1_1)
917#define SSL_LIB "libssl.1.1.dylib"
918#define CRYPTO_LIB "libcrypto.1.1.dylib"
921#if defined(OPENSSL_API_1_0)
922#define SSL_LIB "libssl.1.0.dylib"
923#define CRYPTO_LIB "libcrypto.1.0.dylib"
928#define SSL_LIB "libssl.so"
930#if !defined(CRYPTO_LIB)
931#define CRYPTO_LIB "libcrypto.so"
934#if !defined(O_BINARY)
937#define closesocket(a) (close(a))
938#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
939#define mg_remove(conn, x) (remove(x))
940#define mg_sleep(x) (usleep((x)*1000))
941#define mg_opendir(conn, x) (opendir(x))
942#define mg_closedir(x) (closedir(x))
943#define mg_readdir(x) (readdir(x))
945#define INVALID_SOCKET (-1)
946#define INT64_FMT PRId64
947#define UINT64_FMT PRIu64
953#if !defined(CLOCK_MONOTONIC)
954#define CLOCK_MONOTONIC CLOCK_REALTIME
968#define mg_pollfd pollfd
973#if defined(NEED_TIMEGM)
977 return (
y % 4 == 0 &&
y % 100 != 0) ||
y % 400 == 0;
983 return (
y - 1969) / 4 - (
y - 1901) / 100 + (
y - 1601) / 400;
989 static const unsigned short ydays[] = {
990 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
991 int year = tm->tm_year + 1900;
992 int mon = tm->tm_mon;
993 int mday = tm->tm_mday - 1;
994 int hour = tm->tm_hour;
995 int min = tm->tm_min;
996 int sec = tm->tm_sec;
998 if (year < 1970 || mon < 0 || mon > 11 || mday < 0
999 || (mday >= ydays[mon + 1] - ydays[mon]
1000 + (mon == 1 && is_leap(year) ? 1 : 0))
1001 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60)
1004 time_t res = year - 1970;
1007 res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0);
1008 res += count_leap(year);
1022#if !defined(va_copy)
1023#define va_copy(x, y) ((x) = (y))
1030#if defined(GCC_DIAGNOSTIC)
1032#pragma GCC diagnostic push
1033#pragma GCC diagnostic ignored "-Wunused-function"
1037static pthread_mutex_t global_log_file_lock;
1043 return GetCurrentThreadId();
1051 void (*_ignored)(
void *)
1058 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
1066pthread_key_delete(pthread_key_t key)
1068 return TlsFree(key) ? 0 : 1;
1074pthread_setspecific(pthread_key_t key,
void *
value)
1076 return TlsSetValue(key,
value) ? 0 : 1;
1082pthread_getspecific(pthread_key_t key)
1084 return TlsGetValue(key);
1087#if defined(GCC_DIAGNOSTIC)
1089#pragma GCC diagnostic pop
1098#if defined(GCC_DIAGNOSTIC)
1100#pragma GCC diagnostic push
1101#pragma GCC diagnostic ignored "-Wunused-function"
1103#if defined(__clang__)
1105#pragma clang diagnostic push
1106#pragma clang diagnostic ignored "-Wunused-function"
1129mg_static_assert(SIZE_MAX == 0xFFFFFFFFFFFFFFFFu,
"Mismatch for atomic types");
1130#elif defined(_WIN32)
1145#if defined(_WIN64) && !defined(NO_ATOMICS)
1146 ret = InterlockedIncrement64(addr);
1147#elif defined(_WIN32) && !defined(NO_ATOMICS)
1151 static_assert(
sizeof(ptrdiff_t) ==
sizeof(LONG),
"Size mismatch");
1152 static_assert(
sizeof(ptrdiff_t) ==
sizeof(int32_t),
"Size mismatch");
1153 ret = InterlockedIncrement((LONG *)addr);
1155 ret = InterlockedIncrement(addr);
1157#elif defined(__GNUC__) \
1158 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1159 && !defined(NO_ATOMICS)
1160 ret = __sync_add_and_fetch(addr, 1);
1176#if defined(_WIN64) && !defined(NO_ATOMICS)
1177 ret = InterlockedDecrement64(addr);
1178#elif defined(_WIN32) && !defined(NO_ATOMICS)
1181 static_assert(
sizeof(ptrdiff_t) ==
sizeof(LONG),
"Size mismatch");
1182 static_assert(
sizeof(ptrdiff_t) ==
sizeof(int32_t),
"Size mismatch");
1183 ret = InterlockedDecrement((LONG *)addr);
1185 ret = InterlockedDecrement(addr);
1187#elif defined(__GNUC__) \
1188 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1189 && !defined(NO_ATOMICS)
1190 ret = __sync_sub_and_fetch(addr, 1);
1200#if defined(USE_SERVER_STATS) || defined(STOP_FLAG_NEEDS_LOCK)
1202mg_atomic_add(
volatile ptrdiff_t *addr, ptrdiff_t
value)
1206#if defined(_WIN64) && !defined(NO_ATOMICS)
1207 ret = InterlockedAdd64(addr,
value);
1208#elif defined(_WIN32) && !defined(NO_ATOMICS)
1210#elif defined(__GNUC__) \
1211 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1212 && !defined(NO_ATOMICS)
1213 ret = __sync_add_and_fetch(addr,
value);
1226mg_atomic_compare_and_swap(
volatile ptrdiff_t *addr,
1232#if defined(_WIN64) && !defined(NO_ATOMICS)
1233 ret = InterlockedCompareExchange64(addr, newval, oldval);
1234#elif defined(_WIN32) && !defined(NO_ATOMICS)
1235 ret = InterlockedCompareExchange(addr, newval, oldval);
1236#elif defined(__GNUC__) \
1237 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1238 && !defined(NO_ATOMICS)
1239 ret = __sync_val_compare_and_swap(addr, oldval, newval);
1243 if ((
ret != newval) && (
ret == oldval)) {
1253mg_atomic_max(
volatile ptrdiff_t *addr, ptrdiff_t
value)
1255 register ptrdiff_t tmp = *addr;
1257#if defined(_WIN64) && !defined(NO_ATOMICS)
1258 while (tmp <
value) {
1259 tmp = InterlockedCompareExchange64(addr,
value, tmp);
1261#elif defined(_WIN32) && !defined(NO_ATOMICS)
1262 while (tmp <
value) {
1263 tmp = InterlockedCompareExchange(addr,
value, tmp);
1265#elif defined(__GNUC__) \
1266 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1267 && !defined(NO_ATOMICS)
1268 while (tmp <
value) {
1269 tmp = __sync_val_compare_and_swap(addr, tmp,
value);
1273 if (*addr <
value) {
1282mg_atomic_add64(
volatile int64_t *addr, int64_t
value)
1286#if defined(_WIN64) && !defined(NO_ATOMICS)
1287 ret = InterlockedAdd64(addr,
value);
1288#elif defined(_WIN32) && !defined(NO_ATOMICS)
1290#elif defined(__GNUC__) \
1291 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1292 && !defined(NO_ATOMICS)
1293 ret = __sync_add_and_fetch(addr,
value);
1305#if defined(GCC_DIAGNOSTIC)
1307#pragma GCC diagnostic pop
1309#if defined(__clang__)
1311#pragma clang diagnostic pop
1315#if defined(USE_SERVER_STATS)
1317struct mg_memory_stat {
1318 volatile ptrdiff_t totalMemUsed;
1319 volatile ptrdiff_t maxMemUsed;
1320 volatile ptrdiff_t blockCount;
1324static struct mg_memory_stat *get_memory_stat(
struct mg_context *ctx);
1328mg_malloc_ex(
size_t size,
1335 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1337#if defined(MEMORY_DEBUGGING)
1338 char mallocStr[256];
1345 uintptr_t *tmp = (uintptr_t *)
data;
1346 ptrdiff_t mmem = mg_atomic_add(&mstat->totalMemUsed, (ptrdiff_t)
size);
1347 mg_atomic_max(&mstat->maxMemUsed, mmem);
1350 tmp[1] = (uintptr_t)mstat;
1351 memory = (
void *)&tmp[2];
1354#if defined(MEMORY_DEBUGGING)
1356 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1358 (
unsigned long)
size,
1359 (
unsigned long)mstat->totalMemUsed,
1360 (
unsigned long)mstat->blockCount,
1371mg_calloc_ex(
size_t count,
1377 void *
data = mg_malloc_ex(
size * count, ctx, file,
line);
1387mg_free_ex(
void *memory,
const char *file,
unsigned line)
1389#if defined(MEMORY_DEBUGGING)
1390 char mallocStr[256];
1397 void *
data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1398 uintptr_t
size = ((uintptr_t *)
data)[0];
1399 struct mg_memory_stat *mstat =
1400 (
struct mg_memory_stat *)(((uintptr_t *)
data)[1]);
1401 mg_atomic_add(&mstat->totalMemUsed, -(ptrdiff_t)
size);
1404#if defined(MEMORY_DEBUGGING)
1406 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1408 (
unsigned long)
size,
1409 (
unsigned long)mstat->totalMemUsed,
1410 (
unsigned long)mstat->blockCount,
1421mg_realloc_ex(
void *memory,
1431#if defined(MEMORY_DEBUGGING)
1432 char mallocStr[256];
1441 struct mg_memory_stat *mstat;
1442 data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1443 oldsize = ((uintptr_t *)
data)[0];
1444 mstat = (
struct mg_memory_stat *)((uintptr_t *)
data)[1];
1445 _realloc =
realloc(
data, newsize + 2 *
sizeof(uintptr_t));
1448 mg_atomic_add(&mstat->totalMemUsed, -(ptrdiff_t)oldsize);
1449#if defined(MEMORY_DEBUGGING)
1451 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1453 (
unsigned long)oldsize,
1454 (
unsigned long)mstat->totalMemUsed,
1455 (
unsigned long)mstat->blockCount,
1460 mg_atomic_add(&mstat->totalMemUsed, (ptrdiff_t)newsize);
1462#if defined(MEMORY_DEBUGGING)
1464 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1466 (
unsigned long)newsize,
1467 (
unsigned long)mstat->totalMemUsed,
1468 (
unsigned long)mstat->blockCount,
1473 *(uintptr_t *)
data = newsize;
1474 data = (
void *)(((
char *)
data) + 2 *
sizeof(uintptr_t));
1476#if defined(MEMORY_DEBUGGING)
1483 data = mg_malloc_ex(newsize, ctx, file,
line);
1488 mg_free_ex(memory, file,
line);
1495#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
1496#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
1497#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
1498#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1500#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
1501#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
1502#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
1508static __inline
void *
1514static __inline
void *
1520static __inline
void *
1532#define mg_malloc_ctx(a, c) mg_malloc(a)
1533#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
1534#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
1535#define mg_free_ctx(a, c) mg_free(a)
1568#if defined(snprintf)
1571#if defined(vsnprintf)
1575#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1576#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1577#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1578#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1579#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
1584#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1592#if defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
1593 || defined(OPENSSL_API_3_0)
1594static int mg_openssl_initialized = 0;
1596#if !defined(OPENSSL_API_1_0) && !defined(OPENSSL_API_1_1) \
1597 && !defined(OPENSSL_API_3_0) && !defined(USE_MBEDTLS) \
1598 && !defined(USE_GNUTLS)
1599#error "Please define OPENSSL_API_#_# or USE_MBEDTLS or USE_GNUTLS"
1601#if defined(OPENSSL_API_1_0) && defined(OPENSSL_API_1_1)
1602#error "Multiple OPENSSL_API versions defined"
1604#if defined(OPENSSL_API_1_1) && defined(OPENSSL_API_3_0)
1605#error "Multiple OPENSSL_API versions defined"
1607#if defined(OPENSSL_API_1_0) && defined(OPENSSL_API_3_0)
1608#error "Multiple OPENSSL_API versions defined"
1610#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
1611 || defined(OPENSSL_API_3_0)) \
1612 && (defined(USE_MBEDTLS) || defined(USE_GNUTLS))
1613#error "Multiple SSL libraries defined"
1615#if defined(USE_MBEDTLS) && defined(USE_GNUTLS)
1616#error "Multiple SSL libraries defined"
1624#if defined(MG_LEGACY_INTERFACE)
1625#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
1633 HANDLE pthread_cond_helper_mutex;
1637#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
1643#if defined(GCC_DIAGNOSTIC)
1645#pragma GCC diagnostic push
1646#pragma GCC diagnostic ignored "-Wunused-function"
1648#if defined(__clang__)
1650#pragma clang diagnostic push
1651#pragma clang diagnostic ignored "-Wunused-function"
1670 return GetCurrentThreadId();
1673#if defined(__clang__)
1674#pragma clang diagnostic push
1675#pragma clang diagnostic ignored "-Wunreachable-code"
1683 if (
sizeof(pthread_t) >
sizeof(
unsigned long)) {
1694 pthread_setspecific(
sTlsKey, tls);
1701 unsigned long ret = 0;
1702 pthread_t t = pthread_self();
1703 memcpy(&
ret, &t,
sizeof(pthread_t));
1707#if defined(__clang__)
1708#pragma clang diagnostic pop
1719 struct timespec tsnow;
1720 clock_gettime(CLOCK_REALTIME, &tsnow);
1721 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1725#if defined(GCC_DIAGNOSTIC)
1727#pragma GCC diagnostic pop
1729#if defined(__clang__)
1731#pragma clang diagnostic pop
1735#if defined(NEED_DEBUG_TRACE_FUNC)
1737DEBUG_TRACE_FUNC(
const char *func,
unsigned line,
const char *fmt, ...)
1740 struct timespec tsnow;
1745 clock_gettime(CLOCK_REALTIME, &tsnow);
1747 flockfile(DEBUG_TRACE_STREAM);
1748 fprintf(DEBUG_TRACE_STREAM,
1749 "*** %lu.%09lu %lu %s:%u: ",
1750 (
unsigned long)tsnow.tv_sec,
1751 (
unsigned long)tsnow.tv_nsec,
1755 va_start(args, fmt);
1756 vfprintf(DEBUG_TRACE_STREAM, fmt, args);
1758 putc(
'\n', DEBUG_TRACE_STREAM);
1759 fflush(DEBUG_TRACE_STREAM);
1760 funlockfile(DEBUG_TRACE_STREAM);
1765#define MD5_STATIC static
1769#if defined(NO_SOCKLEN_T)
1770typedef int socklen_t;
1773#define IP_ADDR_STR_LEN (50)
1775#if !defined(MSG_NOSIGNAL)
1776#define MSG_NOSIGNAL (0)
1781#if defined(USE_MBEDTLS)
1783#include "mod_mbedtls.inl"
1785#elif defined(USE_GNUTLS)
1787#include "mod_gnutls.inl"
1789#elif defined(NO_SSL)
1794#elif defined(NO_SSL_DL)
1796#include <openssl/bn.h>
1797#include <openssl/conf.h>
1798#include <openssl/crypto.h>
1799#include <openssl/dh.h>
1802#include <openssl/err.h>
1803#include <openssl/opensslv.h>
1804#include <openssl/pem.h>
1805#include <openssl/ssl.h>
1806#include <openssl/tls1.h>
1807#include <openssl/x509.h>
1809#if defined(WOLFSSL_VERSION)
1812#include "wolfssl_extras.inl"
1815#if defined(OPENSSL_IS_BORINGSSL)
1826#define CONF_modules_unload(a) ((void)0)
1827#define ENGINE_cleanup() ((void)0)
1831#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1832#if !defined(OPENSSL_API_3_0)
1833#define OPENSSL_API_3_0
1835#define OPENSSL_REMOVE_THREAD_STATE()
1837#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1838#if !defined(OPENSSL_API_1_1)
1839#define OPENSSL_API_1_1
1841#define OPENSSL_REMOVE_THREAD_STATE()
1843#if !defined(OPENSSL_API_1_0)
1844#define OPENSSL_API_1_0
1846#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_thread_state(NULL)
1860#if !defined(NO_CACHING)
1881#if defined(USE_IPV6)
1882 struct sockaddr_in6 sin6;
1884#if defined(USE_X_DOM_SOCKET)
1885 struct sockaddr_un sun;
1889#if defined(USE_X_DOM_SOCKET)
1890static unsigned short
1893 if (s->
sa.sa_family == AF_INET)
1894 return s->
sin.sin_port;
1895#if defined(USE_IPV6)
1896 if (s->
sa.sa_family == AF_INET6)
1897 return s->sin6.sin6_port;
1902#if defined(USE_IPV6)
1903#define USA_IN_PORT_UNSAFE(s) \
1904 (((s)->sa.sa_family == AF_INET6) ? (s)->sin6.sin6_port : (s)->sin.sin_port)
1906#define USA_IN_PORT_UNSAFE(s) ((s)->sin.sin_port)
1937#define STRUCT_FILE_INITIALIZER \
1939 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
1978#if defined(__linux__)
1979 ALLOW_SENDFILE_CALL,
1982 CASE_SENSITIVE_FILES,
1988#if defined(USE_WEBSOCKET)
1990 ENABLE_WEBSOCKET_PING_PONG,
1995 LUA_BACKGROUND_SCRIPT,
1996 LUA_BACKGROUND_SCRIPT_PARAMS,
1998#if defined(USE_HTTP2)
2013#if defined(USE_TIMERS)
2022#if defined(USE_TIMERS)
2027#if defined(USE_4_CGI)
2031 CGI3_INTERPRETER_ARGS,
2032#if defined(USE_TIMERS)
2040 CGI4_INTERPRETER_ARGS,
2041#if defined(USE_TIMERS)
2074 LUA_SCRIPT_EXTENSIONS,
2075 LUA_SERVER_PAGE_EXTENSIONS,
2076#if defined(MG_EXPERIMENTAL_INTERFACES)
2080#if defined(USE_DUKTAPE)
2081 DUKTAPE_SCRIPT_EXTENSIONS,
2084#if defined(USE_WEBSOCKET)
2086 FALLBACK_WEBSOCKET_ROOT,
2088#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2089 LUA_WEBSOCKET_EXTENSIONS,
2098#if !defined(NO_CACHING)
2127#if defined(__linux__)
2137#if defined(USE_WEBSOCKET)
2147#if defined(USE_HTTP2)
2162#if defined(USE_TIMERS)
2171#if defined(USE_TIMERS)
2176#if defined(USE_4_CGI)
2181#if defined(USE_TIMERS)
2190#if defined(USE_TIMERS)
2208 "index.xhtml,index.html,index.htm,"
2209 "index.lp,index.lsp,index.lua,index.cgi,"
2210 "index.shtml,index.php"},
2212 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2240#if defined(MG_EXPERIMENTAL_INTERFACES)
2244#if defined(USE_DUKTAPE)
2250#if defined(USE_WEBSOCKET)
2254#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2263#if !defined(NO_CACHING)
2280 "config_options and enum not sync");
2337#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2339 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2350#if defined(STOP_FLAG_NEEDS_LOCK)
2373 sf = mg_atomic_compare_and_swap(
f,
2374 __atomic_load_n(
f, __ATOMIC_SEQ_CST),
2382#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0)
2383#define STOP_FLAG_IS_TWO(f) ((*(f)) == 2)
2384#define STOP_FLAG_ASSIGN(f, v) ((*(f)) = (v))
2389#if !defined(NUM_WEBDAV_LOCKS)
2390#define NUM_WEBDAV_LOCKS 10
2392#if !defined(LOCK_DURATION_S)
2393#define LOCK_DURATION_S 60
2423#if defined(USE_SERVER_STATS)
2424 volatile ptrdiff_t active_connections;
2425 volatile ptrdiff_t max_active_connections;
2426 volatile ptrdiff_t total_connections;
2427 volatile ptrdiff_t total_requests;
2428 volatile int64_t total_data_read;
2429 volatile int64_t total_data_written;
2451#if defined(ALTERNATIVE_QUEUE)
2452 struct socket *client_socks;
2453 void **client_wait_events;
2463#if defined(USE_SERVER_STATS)
2471#if defined(USE_SERVER_STATS)
2472 struct mg_memory_stat ctx_memory;
2483#if defined(USE_TIMERS)
2484 struct ttimers *timers;
2489 void *lua_background_state;
2490 pthread_mutex_t lua_bg_mutex;
2491 int lua_bg_log_available;
2519#if defined(USE_SERVER_STATS)
2520static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2522static struct mg_memory_stat *
2526 return &(ctx->ctx_memory);
2528 return &mg_common_memory;
2545#if defined(USE_HTTP2)
2546#if !defined(HTTP2_DYN_TABLE_SIZE)
2547#define HTTP2_DYN_TABLE_SIZE (256)
2550struct mg_http2_connection {
2552 uint32_t dyn_table_size;
2553 struct mg_header dyn_table[HTTP2_DYN_TABLE_SIZE];
2563#if defined(USE_HTTP2)
2564 struct mg_http2_connection http2;
2573#if defined(USE_SERVER_STATS)
2582#if defined(USE_SERVER_STATS)
2583 time_t conn_close_time;
2585 double processing_time;
2611#if defined(USE_WEBSOCKET)
2612 int in_websocket_handling;
2614#if defined(USE_ZLIB) && defined(USE_WEBSOCKET) \
2615 && defined(MG_EXPERIMENTAL_INTERFACES)
2617 int websocket_deflate_server_max_windows_bits;
2618 int websocket_deflate_client_max_windows_bits;
2619 int websocket_deflate_server_no_context_takeover;
2620 int websocket_deflate_client_no_context_takeover;
2621 int websocket_deflate_initialized;
2622 int websocket_deflate_flush;
2623 z_stream websocket_deflate_state;
2624 z_stream websocket_inflate_state;
2639#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2640 void *lua_websocket_state;
2655#define mg_cry_internal(conn, fmt, ...) \
2656 mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__)
2658#define mg_cry_ctx_internal(ctx, fmt, ...) \
2659 mg_cry_internal_wrap(NULL, ctx, __func__, __LINE__, fmt, __VA_ARGS__)
2669#if !defined(NO_THREAD_NAME)
2670#if defined(_WIN32) && defined(_MSC_VER)
2674#pragma pack(push, 8)
2675typedef struct tagTHREADNAME_INFO {
2683#elif defined(__linux__)
2685#include <sys/prctl.h>
2686#include <sys/sendfile.h>
2687#if defined(ALTERNATIVE_QUEUE)
2688#include <sys/eventfd.h>
2692#if defined(ALTERNATIVE_QUEUE)
2697 int evhdl = eventfd(0, EFD_CLOEXEC);
2718event_wait(
void *eventhdl)
2727 evhdl = *(
int *)eventhdl;
2729 s = (
int)read(evhdl, &u,
sizeof(u));
2730 if (s !=
sizeof(u)) {
2740event_signal(
void *eventhdl)
2749 evhdl = *(
int *)eventhdl;
2751 s = (
int)write(evhdl, &u,
sizeof(u));
2752 if (s !=
sizeof(u)) {
2761event_destroy(
void *eventhdl)
2769 evhdl = *(
int *)eventhdl;
2781#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
2784 pthread_mutex_t mutex;
2785 pthread_cond_t cond;
2793 struct posix_event *
ret =
mg_malloc(
sizeof(
struct posix_event));
2798 if (0 != pthread_mutex_init(&(
ret->mutex), NULL)) {
2803 if (0 != pthread_cond_init(&(
ret->cond), NULL)) {
2805 pthread_mutex_destroy(&(
ret->mutex));
2815event_wait(
void *eventhdl)
2817 struct posix_event *ev = (
struct posix_event *)eventhdl;
2818 pthread_mutex_lock(&(ev->mutex));
2819 while (!ev->signaled) {
2820 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2823 pthread_mutex_unlock(&(ev->mutex));
2829event_signal(
void *eventhdl)
2831 struct posix_event *ev = (
struct posix_event *)eventhdl;
2832 pthread_mutex_lock(&(ev->mutex));
2833 pthread_cond_signal(&(ev->cond));
2835 pthread_mutex_unlock(&(ev->mutex));
2841event_destroy(
void *eventhdl)
2843 struct posix_event *ev = (
struct posix_event *)eventhdl;
2844 pthread_cond_destroy(&(ev->cond));
2845 pthread_mutex_destroy(&(ev->mutex));
2854 char threadName[16 + 1];
2857 NULL, NULL, threadName,
sizeof(threadName),
"civetweb-%s",
name);
2860#if defined(_MSC_VER)
2863 THREADNAME_INFO info;
2864 info.dwType = 0x1000;
2865 info.szName = threadName;
2866 info.dwThreadID = ~0U;
2869 RaiseException(0x406D1388,
2871 sizeof(info) /
sizeof(ULONG_PTR),
2872 (ULONG_PTR *)&info);
2873 } __except (EXCEPTION_EXECUTE_HANDLER) {
2875#elif defined(__MINGW32__)
2878#elif defined(_GNU_SOURCE) && defined(__GLIBC__) \
2879 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
2881#if defined(__MACH__) && defined(__APPLE__)
2883 (void)pthread_setname_np(threadName);
2885 (void)pthread_setname_np(pthread_self(), threadName);
2887#elif defined(__linux__)
2893 (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
2912#define MG_FOPEN_MODE_NONE (0)
2915#define MG_FOPEN_MODE_READ (1)
2918#define MG_FOPEN_MODE_WRITE (2)
2921#define MG_FOPEN_MODE_APPEND (4)
2931 return (fileacc->
fp != NULL);
2935#if !defined(NO_FILESYSTEMS)
2945 const uint8_t *
c = (
const uint8_t *)path;
2948 if ((
c == NULL) || (
c[0] == 0)) {
2959 if ((*
c ==
'>') || (*
c ==
'<') || (*
c ==
'|')) {
2963 if ((*
c ==
'*') || (*
c ==
'?')) {
3014 wchar_t wbuf[UTF16_PATH_MAX];
3015 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
3018 filep->
access.
fp = _wfopen(wbuf, L
"rb");
3021 filep->
access.
fp = _wfopen(wbuf, L
"wb");
3024 filep->
access.
fp = _wfopen(wbuf, L
"ab");
3032 filep->
access.
fp = fopen(path,
"r");
3035 filep->
access.
fp = fopen(path,
"w");
3038 filep->
access.
fp = fopen(path,
"a");
3061 if (fileacc != NULL) {
3062 if (fileacc->
fp != NULL) {
3063 ret = fclose(fileacc->
fp);
3066 memset(fileacc, 0,
sizeof(*fileacc));
3076 for (; *
src !=
'\0' &&
n > 1;
n--) {
3086 return tolower((
unsigned char)*s);
3098 }
while (diff == 0 &&
s1[-1] !=
'\0' && --
len > 0);
3112 }
while (diff == 0 &&
s1[-1] !=
'\0');
3149 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3151 if (big_len >= small_len) {
3152 for (i = 0; i <= (big_len - small_len); i++) {
3182#if defined(__clang__)
3183#pragma clang diagnostic push
3184#pragma clang diagnostic ignored "-Wformat-nonliteral"
3190 ok = (
n >= 0) && ((
size_t)
n < buflen);
3192#if defined(__clang__)
3193#pragma clang diagnostic pop
3205 "truncating vsnprintf buffer: [%.*s]",
3206 (
int)((buflen > 200) ? 200 : (buflen - 1)),
3208 n = (
int)buflen - 1;
3250 }
else if (!ctx || ctx->
dd.
config[i] == NULL) {
3257#define mg_get_option DO_NOT_USE_THIS_FUNCTION_INTERNALLY__access_directly
3269 return (ctx == NULL) ? NULL : ctx->
user_data;
3299 if (const_conn != NULL) {
3329 memset(ports, 0,
sizeof(*ports) * (
size_t)
size);
3361#if defined(USE_X_DOM_SOCKET) && !defined(UNIX_DOMAIN_SOCKET_SERVER_NAME)
3362#define UNIX_DOMAIN_SOCKET_SERVER_NAME "*"
3374 if (
usa->
sa.sa_family == AF_INET) {
3375 getnameinfo(&
usa->
sa,
3383#if defined(USE_IPV6)
3384 else if (
usa->
sa.sa_family == AF_INET6) {
3385 getnameinfo(&
usa->
sa,
3394#if defined(USE_X_DOM_SOCKET)
3395 else if (
usa->
sa.sa_family == AF_UNIX) {
3417#if !defined(REENTRANT_TIME)
3420 tm = ((t != NULL) ? gmtime(t) : NULL);
3424 struct tm *tm = &_tm;
3429 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", tm);
3431 mg_strlcpy(buf,
"Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3440 return (
double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3441 + (
double)(ts_now->tv_sec - ts_before->tv_sec);
3445#if defined(MG_EXTERNAL_FUNCTION_mg_cry_internal_impl)
3451#include "external_mg_cry_internal_impl.inl"
3452#elif !defined(NO_FILESYSTEMS)
3470#if defined(GCC_DIAGNOSTIC)
3471#pragma GCC diagnostic push
3472#pragma GCC diagnostic ignored "-Wformat-nonliteral"
3477#if defined(GCC_DIAGNOSTIC)
3478#pragma GCC diagnostic pop
3481 buf[
sizeof(buf) - 1] = 0;
3510 timestamp = time(NULL);
3514 "[%010lu] [error] [client %s] ",
3515 (
unsigned long)timestamp,
3537#error Must either enable filesystems or provide a custom mg_cry_internal_impl implementation
3584#define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
3600#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3607 if (strlen(txt) == 3) {
3608 memcpy(tls->txtbuf, txt, 4);
3610 strcpy(tls->txtbuf,
"ERR");
3650#if defined(__clang__)
3651#pragma clang diagnostic push
3652#pragma clang diagnostic ignored "-Wunreachable-code"
3663 ? (ri->
is_ssl ?
"wss" :
"ws")
3664 : (ri->
is_ssl ?
"https" :
"http"));
3668#if defined(__clang__)
3669#pragma clang diagnostic pop
3678 const char *define_proto,
3680 const char *define_uri)
3682 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3692 (define_uri != NULL)
3695 int port = (define_port > 0) ? define_port : ri->
server_port;
3698 size_t uri_encoded_len;
3704 uri_encoded_len = strlen(uri) * 3 + 1;
3706 if (uri_encoded == NULL) {
3712 for (i = j = 0; uri_encoded[i]; j++) {
3713 if (!strncmp(uri_encoded + i,
"%2f", 3)) {
3714 uri_encoded[j] =
'/';
3717 uri_encoded[j] = uri_encoded[i++];
3720 uri_encoded[j] =
'\0';
3722#if defined(USE_X_DOM_SOCKET)
3733 const char *server_name = UNIX_DOMAIN_SOCKET_SERVER_NAME;
3750 if ((0 == strcmp(define_proto,
"https"))
3751 || (0 == strcmp(define_proto,
"wss"))) {
3761#if defined(USE_IPV6)
3762 int is_ipv6 = (conn->
client.
lsa.
sa.sa_family == AF_INET6);
3764 int auth_domain_check_enabled =
3769 const char *server_domain =
3776 sprintf(portstr,
":%u", (
unsigned)port);
3781 if (!auth_domain_check_enabled || !server_domain) {
3787 server_domain = server_ip;
3794#
if defined(USE_IPV6)
3797 (is_ipv6 && (server_domain == server_ip)) ?
"[" :
"",
3799 (is_ipv6 && (server_domain == server_ip)) ?
"]" :
"",
3832 const char *delimiters,
3833 const char *whitespace,
3836 char *p, *begin_word, *end_word, *end_whitespace;
3839 end_word = begin_word + strcspn(begin_word, delimiters);
3842 if (end_word > begin_word) {
3844 while (*p == quotechar) {
3850 if (*end_word !=
'\0') {
3851 size_t end_off = strcspn(end_word + 1, delimiters);
3852 memmove(p, end_word, end_off + 1);
3854 end_word += end_off + 1;
3860 for (p++; p < end_word; p++) {
3865 if (*end_word ==
'\0') {
3869#if defined(GCC_DIAGNOSTIC)
3871#pragma GCC diagnostic push
3872#pragma GCC diagnostic ignored "-Wsign-conversion"
3875 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3877#if defined(GCC_DIAGNOSTIC)
3878#pragma GCC diagnostic pop
3881 for (p = end_word; p < end_whitespace; p++) {
3885 *buf = end_whitespace;
3897 for (i = 0; i < num_hdr; i++) {
3899 return hdr[i].
value;
3912 const char **output,
3913 int output_max_size)
3918 for (i = 0; i < ri->
num_headers && cnt < output_max_size; i++) {
3978 if (val == NULL || list == NULL || *list ==
'\0') {
3984 while (*list ==
' ' || *list ==
'\t')
3988 if ((list = strchr(val->
ptr,
',')) != NULL) {
3990 val->
len = ((size_t)(list - val->
ptr));
3994 list = val->
ptr + strlen(val->
ptr);
3995 val->
len = ((size_t)(list - val->
ptr));
4000 while (end >= 0 && ((val->
ptr[end] ==
' ') || (val->
ptr[end] ==
'\t')))
4002 val->
len = (size_t)(end) + (size_t)(1);
4004 if (val->
len == 0) {
4009 if (eq_val != NULL) {
4013 eq_val->
ptr = (
const char *)memchr(val->
ptr,
'=', val->
len);
4014 if (eq_val->
ptr != NULL) {
4016 eq_val->
len = ((size_t)(val->
ptr - eq_val->
ptr)) + val->
len;
4017 val->
len = ((size_t)(eq_val->
ptr - val->
ptr)) - 1;
4038 while ((header =
next_option(header, &opt_vec, &eq_vec)) != NULL) {
4060 const char *http_version;
4086 if (http_version && (0 == strcmp(http_version,
"1.1"))) {
4099 if (!conn || !conn->
dom_ctx) {
4110 if (!conn || !conn->
dom_ctx) {
4135 "no-cache, no-store, "
4136 "must-revalidate, private, max-age=0",
4150#if !defined(NO_CACHING)
4154 const char *cache_control =
4158 if (cache_control != NULL) {
4185 conn, NULL, val,
sizeof(val),
"max-age=%lu", (
unsigned long)max_age);
4210 (
unsigned long)max_age);
4218 if (header && header[0]) {
4228 const char *cors_orig_cfg =
4230 const char *cors_cred_cfg =
4232 const char *cors_hdr_cfg =
4234 const char *cors_exphdr_cfg =
4236 const char *cors_meth_cfg =
4239 if (cors_orig_cfg && *cors_orig_cfg && origin_hdr && *origin_hdr) {
4245 "Access-Control-Allow-Origin",
4250 if (cors_cred_cfg && *cors_cred_cfg && origin_hdr && *origin_hdr) {
4255 "Access-Control-Allow-Credentials",
4260 if (cors_hdr_cfg && *cors_hdr_cfg) {
4262 "Access-Control-Allow-Headers",
4267 if (cors_exphdr_cfg && *cors_exphdr_cfg) {
4269 "Access-Control-Expose-Headers",
4274 if (cors_meth_cfg && *cors_meth_cfg) {
4276 "Access-Control-Allow-Methods",
4283#if !defined(NO_FILESYSTEMS)
4297 switch (response_code) {
4302 return "Switching Protocols";
4304 return "Processing";
4314 return "Non-Authoritative Information";
4316 return "No Content";
4318 return "Reset Content";
4320 return "Partial Content";
4322 return "Multi-Status";
4325 return "Already Reported";
4332 return "Multiple Choices";
4334 return "Moved Permanently";
4340 return "Not Modified";
4344 return "Temporary Redirect";
4346 return "Permanent Redirect";
4350 return "Bad Request";
4352 return "Unauthorized";
4354 return "Payment Required";
4360 return "Method Not Allowed";
4362 return "Not Acceptable";
4364 return "Proxy Authentication Required";
4366 return "Request Time-out";
4372 return "Length Required";
4374 return "Precondition Failed";
4376 return "Request Entity Too Large";
4378 return "Request-URI Too Large";
4380 return "Unsupported Media Type";
4382 return "Requested range not satisfiable";
4385 return "Expectation Failed";
4388 return "Misdirected Request";
4390 return "Unproccessable entity";
4395 return "Failed Dependency";
4399 return "Upgrade Required";
4402 return "Precondition Required";
4404 return "Too Many Requests";
4407 return "Request Header Fields Too Large";
4410 return "Unavailable For Legal Reasons";
4415 return "Internal Server Error";
4417 return "Not Implemented";
4419 return "Bad Gateway";
4421 return "Service Unavailable";
4423 return "Gateway Time-out";
4425 return "HTTP Version not supported";
4427 return "Variant Also Negotiates";
4429 return "Insufficient Storage";
4432 return "Loop Detected";
4435 return "Not Extended";
4437 return "Network Authentication Required";
4443 return "I am a teapot";
4445 return "Authentication Timeout";
4447 return "Enhance Your Calm";
4449 return "Login Timeout";
4451 return "Bandwidth Limit Exceeded";
4457 "Unknown HTTP response code: %u",
4462 if (response_code >= 100 && response_code < 200) {
4464 return "Information";
4466 if (response_code >= 200 && response_code < 300) {
4470 if (response_code >= 300 && response_code < 400) {
4472 return "Redirection";
4474 if (response_code >= 400 && response_code < 500) {
4476 return "Client Error";
4478 if (response_code >= 500 && response_code < 600) {
4480 return "Server Error";
4499#if !defined(NO_FILESYSTEMS)
4501 int len, i, page_handler_found, scope, truncated;
4502 const char *error_handler = NULL;
4504 const char *error_page_file_ext, *tstr;
4506 int handled_by_callback = 0;
4508 if ((conn == NULL) || (fmt == NULL)) {
4516 has_body = ((status > 199) && (status != 204) && (status != 304));
4524 mg_vsnprintf(conn, NULL, errmsg_buf,
sizeof(errmsg_buf), fmt, ap);
4527 DEBUG_TRACE(
"Error %i - [%s]", status, errmsg_buf);
4537 handled_by_callback =
4543 if (!handled_by_callback) {
4547 "Recursion when handling error %u - fall back to default",
4549#if !defined(NO_FILESYSTEMS)
4554 page_handler_found = 0;
4556 if (error_handler != NULL) {
4557 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4563 sizeof(path_buf) - 32,
4574 sizeof(path_buf) - 32,
4583 sizeof(path_buf) - 32,
4598 path_buf[
sizeof(path_buf) - 32] = 0;
4599 len = (
int)strlen(path_buf);
4600 if (
len > (
int)
sizeof(path_buf) - 32) {
4601 len = (
int)
sizeof(path_buf) - 32;
4605 tstr = strchr(error_page_file_ext,
'.');
4609 (i < 32) && (tstr[i] != 0) && (tstr[i] !=
',');
4614 path_buf[
len + i - 1] = tstr[i];
4619 path_buf[
len + i - 1] = 0;
4621 if (
mg_stat(conn, path_buf, &error_page_file.
stat)) {
4624 page_handler_found = 1;
4632 tstr = strchr(tstr + i,
'.');
4637 if (page_handler_found) {
4655 "text/plain; charset=utf-8",
4664 mg_printf(conn,
"Error %d: %s\n", status, status_text);
4665 mg_write(conn, errmsg_buf, strlen(errmsg_buf));
4693 long long content_length)
4705 if (content_length < 0) {
4719 (uint64_t)content_length);
4734 const char *target_url,
4749#if defined(MG_SEND_REDIRECT_BODY)
4751 size_t content_len = 0;
4752 char content_len_text[32];
4756 if (redirect_code == 0) {
4757 redirect_code = 307;
4761 if ((redirect_code != 301) && (redirect_code != 302)
4762 && (redirect_code != 303) && (redirect_code != 307)
4763 && (redirect_code != 308)) {
4769 if ((target_url == NULL) || (*target_url == 0)) {
4773#if defined(MG_SEND_REDIRECT_BODY)
4800 sizeof(redirect_body),
4801 "<html><head>%s</head><body><a href=\"%s\">%s</a></body></html>",
4805 content_len = strlen(reply);
4806 sprintf(content_len_text,
"%lu", (
unsigned long)content_len);
4812 if ((redirect_code == 301) || (redirect_code == 308)) {
4821#if defined(MG_SEND_REDIRECT_BODY)
4829#if defined(MG_SEND_REDIRECT_BODY)
4844#if defined(GCC_DIAGNOSTIC)
4846#pragma GCC diagnostic push
4847#pragma GCC diagnostic ignored "-Wunused-function"
4852pthread_mutex_init(pthread_mutex_t *mutex,
void *unused)
4856 InitializeCriticalSection(&mutex->sec);
4862pthread_mutex_destroy(pthread_mutex_t *mutex)
4864 DeleteCriticalSection(&mutex->sec);
4870pthread_mutex_lock(pthread_mutex_t *mutex)
4872 EnterCriticalSection(&mutex->sec);
4878pthread_mutex_unlock(pthread_mutex_t *mutex)
4880 LeaveCriticalSection(&mutex->sec);
4891 cv->waiting_thread = NULL;
4899 pthread_mutex_t *mutex,
4905 uint64_t nsnow, nswaitabs;
4909 pthread_mutex_lock(&cv->threadIdSec);
4911 ptls = &cv->waiting_thread;
4912 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
4914 tls->next_waiting_thread = NULL;
4916 pthread_mutex_unlock(&cv->threadIdSec);
4921 (((uint64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4922 nswaitrel = nswaitabs - nsnow;
4923 if (nswaitrel < 0) {
4926 mswaitrel = (DWORD)(nswaitrel / 1000000);
4928 mswaitrel = (DWORD)INFINITE;
4931 pthread_mutex_unlock(mutex);
4933 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
4936 pthread_mutex_lock(&cv->threadIdSec);
4937 ptls = &cv->waiting_thread;
4938 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
4940 *ptls = tls->next_waiting_thread;
4945 pthread_mutex_unlock(&cv->threadIdSec);
4947 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4952 pthread_mutex_lock(mutex);
4962 return pthread_cond_timedwait(cv, mutex, NULL);
4973 pthread_mutex_lock(&cv->threadIdSec);
4974 if (cv->waiting_thread) {
4975 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4976 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
4978 ok = SetEvent(wkup);
4981 pthread_mutex_unlock(&cv->threadIdSec);
4991 pthread_mutex_lock(&cv->threadIdSec);
4992 while (cv->waiting_thread) {
4993 pthread_cond_signal(cv);
4995 pthread_mutex_unlock(&cv->threadIdSec);
5005 pthread_mutex_lock(&cv->threadIdSec);
5007 pthread_mutex_unlock(&cv->threadIdSec);
5008 pthread_mutex_destroy(&cv->threadIdSec);
5014#if defined(ALTERNATIVE_QUEUE)
5019 return (
void *)CreateEvent(NULL, FALSE, FALSE, NULL);
5025event_wait(
void *eventhdl)
5027 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
5028 return (res == WAIT_OBJECT_0);
5034event_signal(
void *eventhdl)
5036 return (
int)SetEvent((HANDLE)eventhdl);
5042event_destroy(
void *eventhdl)
5044 CloseHandle((HANDLE)eventhdl);
5049#if defined(GCC_DIAGNOSTIC)
5051#pragma GCC diagnostic pop
5057change_slashes_to_backslashes(
char *path)
5061 for (i = 0; path[i] !=
'\0'; i++) {
5062 if (path[i] ==
'/') {
5068 if ((i > 0) && (path[i] ==
'\\')) {
5069 while ((path[i + 1] ==
'\\') || (path[i + 1] ==
'/')) {
5070 (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
5078mg_wcscasecmp(
const wchar_t *
s1,
const wchar_t *s2)
5083 diff = ((*
s1 >=
L'A') && (*
s1 <=
L'Z') ? (*
s1 -
L'A' +
L'a') : *
s1)
5084 - ((*s2 >= L
'A') && (*s2 <= L
'Z') ? (*s2 - L
'A' + L
'a') : *s2);
5087 }
while ((diff == 0) && (
s1[-1] != L
'\0'));
5102 wchar_t wbuf2[UTF16_PATH_MAX + 1];
5103 DWORD long_len,
err;
5104 int (*fcompare)(
const wchar_t *,
const wchar_t *) = mg_wcscasecmp;
5107 change_slashes_to_backslashes(buf);
5111 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
5112 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int)wbuf_len);
5113 WideCharToMultiByte(
5114 CP_UTF8, 0, wbuf, (
int)wbuf_len, buf2,
sizeof(buf2), NULL, NULL);
5115 if (strcmp(buf, buf2) != 0) {
5139 memset(wbuf2, 0,
ARRAY_SIZE(wbuf2) *
sizeof(
wchar_t));
5140 long_len = GetLongPathNameW(wbuf, wbuf2,
ARRAY_SIZE(wbuf2) - 1);
5141 if (long_len == 0) {
5142 err = GetLastError();
5143 if (
err == ERROR_FILE_NOT_FOUND) {
5148 if ((long_len >=
ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
5155#if !defined(NO_FILESYSTEMS)
5162 wchar_t wbuf[UTF16_PATH_MAX];
5163 WIN32_FILE_ATTRIBUTE_DATA info;
5164 time_t creation_time;
5170 memset(filep, 0,
sizeof(*filep));
5176 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5181 if ((
len > 0) && (path[
len - 1] !=
' ') && (path[
len - 1] !=
'.')
5182 && (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0)) {
5183 filep->
size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
5185 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
5186 info.ftLastWriteTime.dwHighDateTime);
5192 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
5193 info.ftCreationTime.dwHighDateTime);
5198 filep->
is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
5210 wchar_t wbuf[UTF16_PATH_MAX];
5211 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5212 return DeleteFileW(wbuf) ? 0 : -1;
5219 wchar_t wbuf[UTF16_PATH_MAX];
5221 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5222 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
5228#if defined(GCC_DIAGNOSTIC)
5230#pragma GCC diagnostic push
5231#pragma GCC diagnostic ignored "-Wunused-function"
5241 wchar_t wpath[UTF16_PATH_MAX];
5245 SetLastError(ERROR_BAD_ARGUMENTS);
5246 }
else if ((dir = (DIR *)
mg_malloc(
sizeof(*dir))) == NULL) {
5247 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5250 attrs = GetFileAttributesW(wpath);
5251 if ((wcslen(wpath) + 2 <
ARRAY_SIZE(wpath)) && (attrs != 0xFFFFFFFF)
5252 && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
5253 (void)wcscat(wpath, L
"\\*");
5254 dir->handle = FindFirstFileW(wpath, &dir->info);
5255 dir->result.d_name[0] =
'\0';
5274 result = FindClose(dir->handle) ? 0 : -1;
5279 SetLastError(ERROR_BAD_ARGUMENTS);
5287static struct dirent *
5290 struct dirent *
result = 0;
5295 (void)WideCharToMultiByte(CP_UTF8,
5297 dir->info.cFileName,
5304 if (!FindNextFileW(dir->handle, &dir->info)) {
5305 (void)FindClose(dir->handle);
5310 SetLastError(ERROR_FILE_NOT_FOUND);
5313 SetLastError(ERROR_BAD_ARGUMENTS);
5320#if !defined(HAVE_POLL)
5332poll(
struct mg_pollfd *pfd,
unsigned int n,
int milliseconds)
5342 memset(&tv, 0,
sizeof(tv));
5343 tv.tv_sec = milliseconds / 1000;
5344 tv.tv_usec = (milliseconds % 1000) * 1000;
5349 for (i = 0; i <
n; i++) {
5350 if (pfd[i].events & (POLLIN | POLLOUT | POLLERR)) {
5351 if (pfd[i].events & POLLIN) {
5352 FD_SET(pfd[i].fd, &rset);
5354 if (pfd[i].events & POLLOUT) {
5355 FD_SET(pfd[i].fd, &wset);
5358 FD_SET(pfd[i].fd, &eset);
5362 if (pfd[i].fd > maxfd) {
5367 if ((
result = select((
int)maxfd + 1, &rset, &wset, &eset, &tv)) > 0) {
5368 for (i = 0; i <
n; i++) {
5369 if (FD_ISSET(pfd[i].fd, &rset)) {
5370 pfd[i].revents |= POLLIN;
5372 if (FD_ISSET(pfd[i].fd, &wset)) {
5373 pfd[i].revents |= POLLOUT;
5375 if (FD_ISSET(pfd[i].fd, &eset)) {
5376 pfd[i].revents |= POLLERR;
5393#if defined(GCC_DIAGNOSTIC)
5395#pragma GCC diagnostic pop
5407 (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
5414#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5418 return ((_beginthread((
void(__cdecl *)(
void *))
f, USE_STACK_SIZE, p)
5419 == ((uintptr_t)(-1L)))
5424 (_beginthread((
void(__cdecl *)(
void *))
f, 0, p) == ((uintptr_t)(-1L)))
5435 pthread_t *threadidptr)
5438 HANDLE threadhandle;
5441 uip = _beginthreadex(NULL, 0,
f, p, 0, NULL);
5442 threadhandle = (HANDLE)uip;
5443 if ((uip != 0) && (threadidptr != NULL)) {
5444 *threadidptr = threadhandle;
5460 dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE);
5461 if (dwevent == WAIT_FAILED) {
5464 if (dwevent == WAIT_OBJECT_0) {
5465 CloseHandle(threadid);
5473#if !defined(NO_SSL_DL) && !defined(NO_SSL)
5477#if defined(GCC_DIAGNOSTIC)
5479#pragma GCC diagnostic push
5480#pragma GCC diagnostic ignored "-Wunused-function"
5486dlopen(
const char *dll_name,
int flags)
5488 wchar_t wbuf[UTF16_PATH_MAX];
5490 path_to_unicode(NULL, dll_name, wbuf,
ARRAY_SIZE(wbuf));
5491 return LoadLibraryW(wbuf);
5497dlclose(
void *handle)
5501 if (FreeLibrary((HMODULE)handle) != 0) {
5511#if defined(GCC_DIAGNOSTIC)
5513#pragma GCC diagnostic pop
5524kill(pid_t pid,
int sig_num)
5526 (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
5527 (void)CloseHandle((HANDLE)pid);
5532#if !defined(WNOHANG)
5538waitpid(pid_t pid,
int *status,
int flags)
5540 DWORD timeout = INFINITE;
5545 if ((flags | WNOHANG) == WNOHANG) {
5549 waitres = WaitForSingleObject((HANDLE)pid, timeout);
5550 if (waitres == WAIT_OBJECT_0) {
5553 if (waitres == WAIT_TIMEOUT) {
5561trim_trailing_whitespaces(
char *s)
5563 char *
e = s + strlen(s);
5564 while ((
e > s) && isspace((
unsigned char)
e[-1])) {
5583 char *interp_arg = 0;
5588 PROCESS_INFORMATION pi = {0};
5592 memset(&si, 0,
sizeof(si));
5595 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5596 si.wShowWindow = SW_HIDE;
5598 me = GetCurrentProcess();
5600 (HANDLE)_get_osfhandle(fdin[0]),
5605 DUPLICATE_SAME_ACCESS);
5607 (HANDLE)_get_osfhandle(fdout[1]),
5612 DUPLICATE_SAME_ACCESS);
5614 (HANDLE)_get_osfhandle(fderr[1]),
5619 DUPLICATE_SAME_ACCESS);
5624 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5625 HANDLE_FLAG_INHERIT,
5627 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5628 HANDLE_FLAG_INHERIT,
5630 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5631 HANDLE_FLAG_INHERIT,
5637 if (interp != NULL) {
5645 buf[0] = buf[1] =
'\0';
5649 conn, &truncated, cmdline,
sizeof(cmdline),
"%s/%s", dir, prog);
5652 pi.hProcess = (pid_t)-1;
5662 buf[
sizeof(buf) - 1] =
'\0';
5665 if ((buf[0] ==
'#') && (buf[1] ==
'!')) {
5666 trim_trailing_whitespaces(buf + 2);
5673 GetFullPathNameA(dir,
sizeof(full_dir), full_dir, NULL);
5675 if (interp[0] !=
'\0') {
5677 if ((interp_arg != 0) && (interp_arg[0] != 0)) {
5682 "\"%s\" %s \"%s\\%s\"",
5692 "\"%s\" \"%s\\%s\"",
5709 pi.hProcess = (pid_t)-1;
5714 if (CreateProcessA(NULL,
5719 CREATE_NEW_PROCESS_GROUP,
5726 conn,
"%s: CreateProcess(%s): %ld", __func__, cmdline, (
long)
ERRNO);
5727 pi.hProcess = (pid_t)-1;
5732 (void)CloseHandle(si.hStdOutput);
5733 (void)CloseHandle(si.hStdError);
5734 (void)CloseHandle(si.hStdInput);
5735 if (pi.hThread != NULL) {
5736 (void)CloseHandle(pi.hThread);
5739 return (pid_t)pi.hProcess;
5747 unsigned long non_blocking = 0;
5748 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5755 unsigned long non_blocking = 1;
5756 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5763#if !defined(NO_FILESYSTEMS)
5773 memset(filep, 0,
sizeof(*filep));
5779 if (0 == stat(path, &st)) {
5780 filep->
size = (uint64_t)(st.st_size);
5796#if defined(__ZEPHYR__)
5801 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5805 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5817 pthread_t thread_id;
5818 pthread_attr_t
attr;
5821 (void)pthread_attr_init(&
attr);
5822 (void)pthread_attr_setdetachstate(&
attr, PTHREAD_CREATE_DETACHED);
5824#if defined(__ZEPHYR__)
5825 pthread_attr_setstack(&
attr, &civetweb_main_stack, ZEPHYR_STACK_SIZE);
5826#elif defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5829 (void)pthread_attr_setstacksize(&
attr, USE_STACK_SIZE);
5832 result = pthread_create(&thread_id, &
attr, func, param);
5833 pthread_attr_destroy(&
attr);
5843 pthread_t *threadidptr)
5845 pthread_t thread_id;
5846 pthread_attr_t
attr;
5849 (void)pthread_attr_init(&
attr);
5851#if defined(__ZEPHYR__)
5852 pthread_attr_setstack(&
attr,
5853 &civetweb_worker_stacks[zephyr_worker_stack_index++],
5855#elif defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5858 (void)pthread_attr_setstacksize(&
attr, USE_STACK_SIZE);
5861 result = pthread_create(&thread_id, &
attr, func, param);
5862 pthread_attr_destroy(&
attr);
5863 if ((
result == 0) && (threadidptr != NULL)) {
5864 *threadidptr = thread_id;
5876 result = pthread_join(threadid, NULL);
5898 if ((pid = fork()) == -1) {
5901 }
else if (pid != 0) {
5909 if (chdir(dir) != 0) {
5911 conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
5912 }
else if (dup2(fdin[0], 0) == -1) {
5914 "%s: dup2(%d, 0): %s",
5918 }
else if (dup2(fdout[1], 1) == -1) {
5920 "%s: dup2(%d, 1): %s",
5924 }
else if (dup2(fderr[1], 2) == -1) {
5926 "%s: dup2(%d, 2): %s",
5931 struct sigaction sa;
5936 (void)close(fdin[0]);
5937 (void)close(fdout[1]);
5938 (void)close(fderr[1]);
5941 (void)close(fdin[1]);
5942 (void)close(fdout[0]);
5943 (void)close(fderr[0]);
5950 memset(&sa, 0,
sizeof(sa));
5951 sa.sa_handler = SIG_DFL;
5952 sigaction(SIGCHLD, &sa, NULL);
5955 if (interp == NULL) {
5957 (void)execle(prog, prog, NULL, envp);
5959 "%s: execle(%s): %s",
5965 const char *interp_args =
5969 if ((interp_args != NULL) && (interp_args[0] != 0)) {
5970 (void)execle(interp, interp, interp_args, prog, NULL, envp);
5972 (void)execle(interp, interp, prog, NULL, envp);
5975 "%s: execle(%s %s): %s",
5993 int flags = fcntl(sock, F_GETFL, 0);
5998 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
6007 int flags = fcntl(sock, F_GETFL, 0);
6012 if (fcntl(sock, F_SETFL, flags & (~(
int)(O_NONBLOCK))) < 0) {
6026 static uint64_t lfsr = 0;
6027 static uint64_t lcg = 0;
6038 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
6040 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
6048 return (lfsr ^ lcg ^ now);
6063 int check_pollerr = 0;
6064 if ((
n == 1) && ((pfd[0].events & POLLERR) == 0)) {
6066 pfd[0].events |= POLLERR;
6078 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
6079 ms_now = milliseconds;
6082 result = poll(pfd,
n, ms_now);
6089 && ((pfd[0].revents & (POLLIN | POLLOUT | POLLERR))
6099 if (milliseconds > 0) {
6100 milliseconds -= ms_now;
6103 }
while (milliseconds > 0);
6126 uint64_t
start = 0, now = 0, timeout_ns = 0;
6133 typedef size_t len_t;
6139 timeout_ns = (uint64_t)(timeout * 1.0E9);
6146#if defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS)
6156#if defined(USE_MBEDTLS)
6158 n = mbed_ssl_write(ssl, (
const unsigned char *)buf,
len);
6160 if ((
n == MBEDTLS_ERR_SSL_WANT_READ)
6161 || (
n == MBEDTLS_ERR_SSL_WANT_WRITE)
6162 ||
n == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
6165 fprintf(stderr,
"SSL write failed, error %d\n",
n);
6172#elif defined(USE_GNUTLS)
6174 n = gtls_ssl_write(ssl, (
const unsigned char *)buf, (
size_t)
len);
6177 "SSL write failed (%d): %s",
6179 gnutls_strerror(
n));
6185#elif !defined(NO_SSL)
6188 n = SSL_write(ssl, buf,
len);
6190 err = SSL_get_error(ssl,
n);
6209 n = (
int)fwrite(buf, 1, (
size_t)
len, fp);
6233 if ((
n > 0) || ((
n == 0) && (
len == 0))) {
6261 unsigned int num_sock = 1;
6264 pfd[0].events = POLLOUT;
6268 pfd[num_sock].events = POLLIN;
6283 if ((now -
start) > timeout_ns) {
6305 double timeout = -1.0;
6306 int n, nwritten = 0;
6315 if (timeout <= 0.0) {
6321 n =
push_inner(ctx, fp, sock, ssl, buf + nwritten,
len, timeout);
6323 if (nwritten == 0) {
6327 }
else if (
n == 0) {
6357 typedef size_t len_t;
6370 nread = (
int)read(fileno(fp), buf, (
size_t)
len);
6373 if ((nread == 0) && (
len > 0)) {
6378#if defined(USE_MBEDTLS)
6379 }
else if (conn->
ssl != NULL) {
6383 unsigned int num_sock = 1;
6385 to_read = mbedtls_ssl_get_bytes_avail(conn->
ssl);
6397 pfd[0].events = POLLIN;
6402 pfd[num_sock].events = POLLIN;
6410 (
int)(timeout * 1000.0),
6419 nread = mbed_ssl_read(conn->
ssl, (
unsigned char *)buf, to_read);
6421 if ((nread == MBEDTLS_ERR_SSL_WANT_READ)
6422 || (nread == MBEDTLS_ERR_SSL_WANT_WRITE)
6423 || nread == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
6426 fprintf(stderr,
"SSL read failed, error %d\n", nread);
6433 }
else if (pollres < 0) {
6441#elif defined(USE_GNUTLS)
6442 }
else if (conn->
ssl != NULL) {
6446 unsigned int num_sock = 1;
6448 to_read = gnutls_record_check_pending(conn->
ssl->sess);
6456 if (to_read > (
size_t)
len)
6457 to_read = (size_t)
len;
6460 pfd[0].events = POLLIN;
6465 pfd[num_sock].events = POLLIN;
6469 to_read = (size_t)
len;
6473 (
int)(timeout * 1000.0),
6482 nread = gtls_ssl_read(conn->
ssl, (
unsigned char *)buf, to_read);
6485 "SSL read failed (%d): %s",
6487 gnutls_strerror(nread));
6492 }
else if (pollres < 0) {
6500#elif !defined(NO_SSL)
6501 }
else if (conn->
ssl != NULL) {
6505 unsigned int num_sock = 1;
6507 if ((ssl_pending = SSL_pending(conn->
ssl)) > 0) {
6511 if (ssl_pending >
len) {
6517 pfd[0].events = POLLIN;
6522 pfd[num_sock].events = POLLIN;
6528 (
int)(timeout * 1000.0),
6537 SSL_read(conn->
ssl, buf, (ssl_pending > 0) ? ssl_pending :
len);
6539 err = SSL_get_error(conn->
ssl, nread);
6555 }
else if (pollres < 0) {
6567 unsigned int num_sock = 1;
6570 pfd[0].events = POLLIN;
6575 pfd[num_sock].events = POLLIN;
6581 (
int)(timeout * 1000.0),
6593 }
else if (pollres < 0) {
6606 if ((nread > 0) || ((nread == 0) && (
len == 0))) {
6614 if (
err == WSAEWOULDBLOCK) {
6618 }
else if (
err == WSAETIMEDOUT) {
6622 }
else if (
err == WSAECONNABORTED) {
6663 double timeout = -1.0;
6664 uint64_t start_time = 0, now = 0, timeout_ns = 0;
6669 if (timeout <= 0.0) {
6674 timeout_ns = (uint64_t)(timeout * 1.0E9);
6683 }
else if (
n == -1) {
6685 if (timeout >= 0.0) {
6687 if ((now - start_time) <= timeout_ns) {
6692 }
else if (
n == 0) {
6709 while (
mg_read(conn, buf,
sizeof(buf)) > 0)
6717 int64_t content_len,
n, buffered_len, nread;
6719 (int64_t)((
len > INT_MAX) ? INT_MAX :
len);
6731 if (content_len < 0) {
6740 if (left_to_read < len64) {
6744 len64 = left_to_read;
6750 if (buffered_len > 0) {
6751 if (len64 < buffered_len) {
6752 buffered_len = len64;
6755 memcpy(buf, body, (
size_t)buffered_len);
6756 len64 -= buffered_len;
6758 nread += buffered_len;
6759 buf = (
char *)buf + buffered_len;
6765 if ((
n =
pull_all(NULL, conn, (
char *)buf, (
int)len64)) >= 0) {
6769 nread = ((nread > 0) ? nread :
n);
6785#if defined(USE_SERVER_STATS)
6786 struct timespec tnow;
6787 conn->conn_state = 4;
6793#if defined(USE_SERVER_STATS)
6794 conn->conn_state = 5;
6796 clock_gettime(CLOCK_MONOTONIC, &tnow);
6800 mg_atomic_add64(&(conn->
phys_ctx->total_data_written),
6814#if defined(USE_HTTP2)
6816#error "HTTP2 requires ALPN, ALPN requires SSL/TLS"
6823 if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) { \
6824 http2_must_use_http1(conn); \
6825 DEBUG_TRACE("%s", "must use HTTP/1.x"); \
6837 if (
len > INT_MAX) {
6846 size_t all_read = 0;
6868 all_read += (size_t)read_ret;
6869 len -= (size_t)read_ret;
6877 || (
x[1] !=
'\n')) {
6889 unsigned long chunkSize = 0;
6891 for (i = 0; i < (
sizeof(lenbuf) - 1); i++) {
6896 if ((i > 0) && (lenbuf[i] ==
';')) {
6910 && lenbuf[i] !=
'\r');
6912 if ((i > 0) && (lenbuf[i] ==
'\r')
6913 && (lenbuf[i - 1] !=
'\r')) {
6916 if ((i > 1) && (lenbuf[i] ==
'\n')
6917 && (lenbuf[i - 1] ==
'\r')) {
6919 chunkSize = strtoul(lenbuf, &end, 16);
6920 if (chunkSize == 0) {
6926 if (!isxdigit((
unsigned char)lenbuf[i])) {
6932 if ((end == NULL) || (*end !=
'\r')) {
6958 while (crlf_count < 4 && conn->is_chunked == 3) {
6961 if ((crlf_count == 0 || crlf_count == 2)) {
6962 if (lenbuf[0] ==
'\r')
6970 if (lenbuf[0] ==
'\n')
6993 return (
int)all_read;
7008 if (
len > INT_MAX) {
7014#if defined(USE_HTTP2)
7016 http2_data_frame_head(conn,
len, 0);
7026 if (allowed > (
int)
len) {
7037 if (
total == allowed) {
7039 buf = (
const char *)buf +
total;
7060 buf = (
const char *)buf +
n;
7083 unsigned int chunk_len)
7091 sprintf(lenbuf,
"%x\r\n", chunk_len);
7092 lenbuf_len = strlen(lenbuf);
7096 if (
ret != (
int)lenbuf_len) {
7102 if (
ret != (
int)chunk_len) {
7117#if defined(GCC_DIAGNOSTIC)
7120#pragma GCC diagnostic push
7121#pragma GCC diagnostic ignored "-Wformat-nonliteral"
7148 (*buf)[
size - 1] = 0;
7162 size_t prealloc_size,
7188 }
else if ((
size_t)(
len) >= prealloc_size) {
7209 *out_buf = prealloc_buf;
7230#if defined(GCC_DIAGNOSTIC)
7232#pragma GCC diagnostic pop
7273 int is_form_url_encoded)
7276#define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
7278 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
7279 if ((i < src_len - 2) && (
src[i] ==
'%')
7280 && isxdigit((
unsigned char)
src[i + 1])
7281 && isxdigit((
unsigned char)
src[i + 2])) {
7282 a = tolower((
unsigned char)
src[i + 1]);
7283 b = tolower((
unsigned char)
src[i + 2]);
7286 }
else if (is_form_url_encoded && (
src[i] ==
'+')) {
7295 return (i >= src_len) ? j : -1;
7303 int len = (
int)strlen(buf);
7327 const char *p, *
e, *s;
7331 if ((dst == NULL) || (dst_len == 0)) {
7333 }
else if ((
data == NULL) || (
name == NULL) || (data_len == 0)) {
7337 name_len = strlen(
name);
7338 e =
data + data_len;
7343 for (p =
data; p + name_len <
e; p++) {
7344 if (((p ==
data) || (p[-1] ==
'&')) && (p[name_len] ==
'=')
7350 s = (
const char *)memchr(p,
'&', (
size_t)(
e - p));
7380 unsigned num_form_fields)
7391 if ((form_fields == NULL) && (num_form_fields == 0)) {
7407 if ((form_fields == NULL) || ((
int)num_form_fields <= 0)) {
7412 for (i = 0; i < (
int)num_form_fields; i++) {
7414 while ((*
data ==
' ') || (*
data ==
'\t')) {
7426 while ((*
b != 0) && (*
b !=
'&') && (*
b !=
'=')) {
7432 form_fields[num].
value = NULL;
7433 }
else if (*
b ==
'&') {
7435 form_fields[num].
value = NULL;
7448 b = strchr(
data,
'&');
7461 for (i = 0; i < num; i++) {
7462 if (form_fields[i].
name) {
7465 if (form_fields[i].
value) {
7478 const char *var_name,
7482 const char *s, *p, *end;
7483 int name_len,
len = -1;
7485 if ((dst == NULL) || (dst_size == 0)) {
7490 if ((var_name == NULL) || ((s = cookie_header) == NULL)) {
7494 name_len = (
int)strlen(var_name);
7495 end = s + strlen(s);
7496 for (; (s =
mg_strcasestr(s, var_name)) != NULL; s += name_len) {
7497 if (s[name_len] ==
'=') {
7499 if ((s == cookie_header) || (s[-1] ==
' ')) {
7501 if ((p = strchr(s,
' ')) == NULL) {
7507 if ((*s ==
'"') && (p[-1] ==
'"') && (p > s + 1)) {
7511 if ((
size_t)(p - s) < dst_size) {
7531 static const char *b64 =
7532 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7536 if (dst_len != NULL) {
7540 size_t expected_len = ((src_len + 2) / 3) * 4 + 1;
7541 if (*dst_len < expected_len) {
7545 *dst_len = expected_len;
7550 for (i = j = 0; i < src_len; i += 3) {
7552 b = ((i + 1) >= src_len) ? 0 :
src[i + 1];
7553 c = ((i + 2) >= src_len) ? 0 :
src[i + 2];
7555 dst[j++] = b64[
a >> 2];
7556 dst[j++] = b64[((
a & 3) << 4) | (
b >> 4)];
7557 if (i + 1 < src_len) {
7558 dst[j++] = b64[(
b & 15) << 2 | (
c >> 6)];
7560 if (i + 2 < src_len) {
7561 dst[j++] = b64[
c & 63];
7564 while (j % 4 != 0) {
7569 if (dst_len != NULL) {
7570 *dst_len = (size_t)j;
7581 if ((letter >=
'A') && (letter <=
'Z')) {
7582 return (
unsigned char)(letter -
'A');
7584 if ((letter >=
'a') && (letter <=
'z')) {
7585 return (
unsigned char)(letter -
'a' + 26);
7587 if ((letter >=
'0') && (letter <=
'9')) {
7588 return (
unsigned char)(letter -
'0' + 52);
7590 if (letter ==
'+') {
7593 if (letter ==
'/') {
7596 if (letter ==
'=') {
7610 unsigned char a,
b,
c,
d;
7611 size_t dst_len_limit = (size_t)-1;
7612 size_t dst_len_used = 0;
7614 if (dst_len != NULL) {
7615 dst_len_limit = *dst_len;
7619 for (i = 0; i < src_len; i += 4) {
7642 if (dst_len_used < dst_len_limit) {
7643 dst[dst_len_used] = (
unsigned char)((
unsigned char)(
a << 2)
7644 + (
unsigned char)(
b >> 4));
7649 if (dst_len_used < dst_len_limit) {
7651 dst[dst_len_used] = (
unsigned char)((
unsigned char)(
b << 4)
7652 + (
unsigned char)(
c >> 2));
7656 if (dst_len_used < dst_len_limit) {
7658 (
unsigned char)((
unsigned char)(
c << 6) +
d);
7666 if (dst_len_used < dst_len_limit) {
7667 dst[dst_len_used] =
'\0';
7670 if (dst_len != NULL) {
7671 *dst_len = dst_len_used;
7674 if (dst_len_used > dst_len_limit) {
7691 return (!strcmp(s,
"PUT") || !strcmp(s,
"DELETE")
7692 || !strcmp(s,
"MKCOL") || !strcmp(s,
"PATCH")
7693 || !strcmp(s,
"LOCK") || !strcmp(s,
"UNLOCK")
7694 || !strcmp(s,
"PROPPATCH") || !strcmp(s,
"MOVE")
7695 || !strcmp(s,
"COPY"));
7714 return (!strcmp(s,
"PROPFIND") || !strcmp(s,
"PROPPATCH")
7715 || !strcmp(s,
"LOCK") || !strcmp(s,
"UNLOCK")
7716 || !strcmp(s,
"MOVE") || !strcmp(s,
"COPY"));
7723#if !defined(NO_FILES)
7731 int cgi_config_idx, inc, max;
7741#if defined(USE_DUKTAPE)
7751 for (cgi_config_idx = 0; cgi_config_idx < max; cgi_config_idx += inc) {
7801 struct vec filename_vec;
7802 size_t n = strlen(path);
7808 while ((
n > 0) && (path[
n - 1] ==
'/')) {
7815 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
7817 if ((filename_vec.
len + 1) > (path_len - (
n + 1))) {
7825 if (
mg_stat(conn, path, filestat)) {
7851 const char *fallback_root_prefix =
7853 if ((root_prefix) && (fallback_root_prefix)) {
7854 const size_t root_prefix_len = strlen(root_prefix);
7855 if ((strncmp(path, root_prefix, root_prefix_len) == 0)) {
7858 size_t sub_path_len;
7860 const size_t fallback_root_prefix_len =
7861 strlen(fallback_root_prefix);
7862 const char *sub_path = path + root_prefix_len;
7863 while (*sub_path ==
'/') {
7866 sub_path_len = strlen(sub_path);
7868 if (((fallback_root_prefix_len + 1 + sub_path_len + 1)
7869 <
sizeof(scratch_path))) {
7873 strcpy(scratch_path, fallback_root_prefix);
7874 nul = strchr(scratch_path,
'\0');
7875 if ((nul > scratch_path) && (*(nul - 1) !=
'/')) {
7879 strcat(scratch_path, sub_path);
7882 sizeof(scratch_path),
7900 size_t filename_buf_len,
7903 int *is_script_resource,
7904 int *is_websocket_request,
7905 int *is_put_or_delete_request,
7906 int *is_webdav_request,
7907 int *is_template_text
7910 char const *accept_encoding;
7912#if !defined(NO_FILES)
7918 const char *rewrite;
7920 ptrdiff_t match_len;
7924#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7926 size_t tmp_str_len, sep_pos;
7927 int allow_substitute_script_subresources;
7930 (void)filename_buf_len;
7934 memset(filestat, 0,
sizeof(*filestat));
7937 *is_script_resource = 0;
7938 *is_template_text = 0;
7949#if defined(USE_WEBSOCKET)
7951#if !defined(NO_FILES)
7952 if ((*is_websocket_request) && conn->
dom_ctx->
config[WEBSOCKET_ROOT]) {
7958 *is_websocket_request = 0;
7963 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
7964 if (strstr(accept_encoding,
"gzip") != NULL) {
7969#if !defined(NO_FILES)
7974 if (
roots[0] == NULL) {
7980 for (i = 0;
roots[i] != NULL; i++) {
7989 filename_buf_len - 1,
7995 goto interpret_cleanup;
8005 filename_buf_len - 1,
8015 goto interpret_cleanup;
8028 int uri_len = (
int)strlen(uri);
8029 int is_uri_end_slash = (uri_len > 0) && (uri[uri_len - 1] ==
'/');
8047 *is_script_resource = (!*is_put_or_delete_request);
8057 *is_template_text = (!*is_put_or_delete_request);
8064 && (!*is_webdav_request)) {
8068 memset(&tmp_filestat, 0,
sizeof(tmp_filestat));
8071 conn,
filename, filename_buf_len, &tmp_filestat)) {
8075 *filestat = tmp_filestat;
8079 *is_script_resource = 1;
8082 *is_template_text = 1;
8085 *is_script_resource = 0;
8104 conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz",
filename);
8107 goto interpret_cleanup;
8110 if (
mg_stat(conn, gz_path, filestat)) {
8120#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
8128 goto interpret_cleanup;
8130 memcpy(tmp_str,
filename, tmp_str_len + 1);
8133 allow_substitute_script_subresources =
8136 if (*is_webdav_request) {
8142 sep_pos = tmp_str_len;
8143 while (sep_pos > 0) {
8145 if (tmp_str[sep_pos] ==
'/') {
8146 int is_script = 0, does_exist = 0;
8148 tmp_str[sep_pos] = 0;
8151 does_exist =
mg_stat(conn, tmp_str, filestat);
8154 if (does_exist && is_script) {
8158 strlen(
filename + sep_pos + 1) + 1);
8161 *is_script_resource = 1;
8166 if (allow_substitute_script_subresources) {
8173 size_t script_name_len = strlen(tmp_str);
8177 char *subres_name =
filename + sep_pos;
8178 size_t subres_name_len = strlen(subres_name);
8180 DEBUG_TRACE(
"Substitute script %s serving path %s",
8185 if ((script_name_len + subres_name_len + 2)
8186 >= filename_buf_len) {
8188 goto interpret_cleanup;
8193 memmove(conn->
path_info, subres_name, subres_name_len);
8195 memcpy(
filename, tmp_str, script_name_len + 1);
8197 *is_script_resource = 1;
8210 *is_script_resource = 0;
8217 tmp_str[sep_pos] =
'/';
8227#if !defined(NO_FILES)
8230 memset(filestat, 0,
sizeof(*filestat));
8233 *is_script_resource = 0;
8234 *is_websocket_request = 0;
8235 *is_put_or_delete_request = 0;
8248 for (i = 0; i < buflen; i++) {
8250 const unsigned char c = (
unsigned char)buf[i];
8252 if ((
c < 128) && ((
char)
c !=
'\r') && ((
char)
c !=
'\n')
8258 if (i < buflen - 1) {
8259 if ((buf[i] ==
'\n') && (buf[i + 1] ==
'\n')) {
8266 if (i < buflen - 3) {
8267 if ((buf[i] ==
'\r') && (buf[i + 1] ==
'\n') && (buf[i + 2] ==
'\r')
8268 && (buf[i + 3] ==
'\n')) {
8279#if !defined(NO_CACHING)
8300 char month_str[32] = {0};
8301 int second, minute, hour, day, month, year;
8302 time_t
result = (time_t)0;
8305 if ((sscanf(datetime,
8306 "%d/%3s/%d %d:%d:%d",
8314 || (sscanf(datetime,
8315 "%d %3s %d %d:%d:%d",
8323 || (sscanf(datetime,
8324 "%*3s, %d %3s %d %d:%d:%d",
8332 || (sscanf(datetime,
8333 "%d-%3s-%d %d:%d:%d",
8342 if ((month >= 0) && (year >= 1970)) {
8343 memset(&tm, 0,
sizeof(tm));
8344 tm.tm_year = year - 1900;
8367 char *out_end = inout;
8400 if (!strncmp(in,
"../", 3)) {
8402 }
else if (!strncmp(in,
"./", 2)) {
8411 else if (!strncmp(in,
"/./", 3)) {
8413 }
else if (!strcmp(in,
"/.")) {
8424 else if (!strncmp(in,
"/../", 4)) {
8426 if (inout != out_end) {
8430 }
while ((inout != out_end) && (*out_end !=
'/'));
8432 }
else if (!strcmp(in,
"/..")) {
8434 if (inout != out_end) {
8438 }
while ((inout != out_end) && (*out_end !=
'/'));
8446 else if (!strcmp(in,
".") || !strcmp(in,
"..")) {
8461 }
while ((*in != 0) && (*in !=
'/'));
8477 out_end = in = inout;
8481 char *in_ahead = in;
8484 }
while (*in_ahead ==
'.');
8485 if (*in_ahead ==
'/') {
8487 if ((out_end != inout) && (out_end[-1] ==
'/')) {
8491 }
else if (*in_ahead == 0) {
8497 }
while (in != in_ahead);
8499 }
else if (*in ==
'/') {
8504 }
while (*in ==
'/');
8514static const struct {
8522 {
".bin", 4,
"application/octet-stream"},
8523 {
".cer", 4,
"application/pkix-cert"},
8524 {
".crl", 4,
"application/pkix-crl"},
8525 {
".crt", 4,
"application/pkix-cert"},
8526 {
".deb", 4,
"application/octet-stream"},
8527 {
".dmg", 4,
"application/octet-stream"},
8528 {
".dll", 4,
"application/octet-stream"},
8529 {
".doc", 4,
"application/msword"},
8530 {
".eps", 4,
"application/postscript"},
8531 {
".exe", 4,
"application/octet-stream"},
8532 {
".iso", 4,
"application/octet-stream"},
8533 {
".js", 3,
"application/javascript"},
8534 {
".json", 5,
"application/json"},
8535 {
".mjs", 4,
"application/javascript"},
8536 {
".msi", 4,
"application/octet-stream"},
8537 {
".pem", 4,
"application/x-pem-file"},
8538 {
".pdf", 4,
"application/pdf"},
8539 {
".ps", 3,
"application/postscript"},
8540 {
".rtf", 4,
"application/rtf"},
8541 {
".wasm", 5,
"application/wasm"},
8542 {
".xhtml", 6,
"application/xhtml+xml"},
8543 {
".xsl", 4,
"application/xml"},
8544 {
".xslt", 5,
"application/xml"},
8547 {
".ttf", 4,
"application/font-sfnt"},
8548 {
".cff", 4,
"application/font-sfnt"},
8549 {
".otf", 4,
"application/font-sfnt"},
8550 {
".aat", 4,
"application/font-sfnt"},
8551 {
".sil", 4,
"application/font-sfnt"},
8552 {
".pfr", 4,
"application/font-tdpfr"},
8553 {
".woff", 5,
"application/font-woff"},
8554 {
".woff2", 6,
"application/font-woff2"},
8557 {
".mp3", 4,
"audio/mpeg"},
8558 {
".oga", 4,
"audio/ogg"},
8559 {
".ogg", 4,
"audio/ogg"},
8562 {
".gif", 4,
"image/gif"},
8563 {
".ief", 4,
"image/ief"},
8564 {
".jpeg", 5,
"image/jpeg"},
8565 {
".jpg", 4,
"image/jpeg"},
8566 {
".jpm", 4,
"image/jpm"},
8567 {
".jpx", 4,
"image/jpx"},
8568 {
".png", 4,
"image/png"},
8569 {
".svg", 4,
"image/svg+xml"},
8570 {
".tif", 4,
"image/tiff"},
8571 {
".tiff", 5,
"image/tiff"},
8574 {
".wrl", 4,
"model/vrml"},
8577 {
".css", 4,
"text/css"},
8578 {
".csv", 4,
"text/csv"},
8579 {
".htm", 4,
"text/html"},
8580 {
".html", 5,
"text/html"},
8581 {
".sgm", 4,
"text/sgml"},
8582 {
".shtm", 5,
"text/html"},
8583 {
".shtml", 6,
"text/html"},
8584 {
".txt", 4,
"text/plain"},
8585 {
".xml", 4,
"text/xml"},
8588 {
".mov", 4,
"video/quicktime"},
8589 {
".mp4", 4,
"video/mp4"},
8590 {
".mpeg", 5,
"video/mpeg"},
8591 {
".mpg", 4,
"video/mpeg"},
8592 {
".ogv", 4,
"video/ogg"},
8593 {
".qt", 3,
"video/quicktime"},
8598 {
".arj", 4,
"application/x-arj-compressed"},
8599 {
".gz", 3,
"application/x-gunzip"},
8600 {
".rar", 4,
"application/x-arj-compressed"},
8601 {
".swf", 4,
"application/x-shockwave-flash"},
8602 {
".tar", 4,
"application/x-tar"},
8603 {
".tgz", 4,
"application/x-tar-gz"},
8604 {
".torrent", 8,
"application/x-bittorrent"},
8605 {
".ppt", 4,
"application/x-mspowerpoint"},
8606 {
".xls", 4,
"application/x-msexcel"},
8607 {
".zip", 4,
"application/x-zip-compressed"},
8611 {
".flac", 5,
"audio/flac"},
8612 {
".aif", 4,
"audio/x-aif"},
8613 {
".m3u", 4,
"audio/x-mpegurl"},
8614 {
".mid", 4,
"audio/x-midi"},
8615 {
".ra", 3,
"audio/x-pn-realaudio"},
8616 {
".ram", 4,
"audio/x-pn-realaudio"},
8617 {
".wav", 4,
"audio/x-wav"},
8618 {
".bmp", 4,
"image/bmp"},
8619 {
".ico", 4,
"image/x-icon"},
8620 {
".pct", 4,
"image/x-pct"},
8621 {
".pict", 5,
"image/pict"},
8622 {
".rgb", 4,
"image/x-rgb"},
8623 {
".webm", 5,
"video/webm"},
8624 {
".asf", 4,
"video/x-ms-asf"},
8625 {
".avi", 4,
"video/x-msvideo"},
8626 {
".m4v", 4,
"video/x-m4v"},
8636 path_len = strlen(path);
8646 return "text/plain";
8655 struct vec ext_vec, mime_vec;
8656 const char *list, *ext;
8659 path_len = strlen(path);
8661 if ((conn == NULL) || (
vec == NULL)) {
8663 memset(
vec,
'\0',
sizeof(
struct vec));
8671 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
8673 ext = path + path_len - ext_vec.
len;
8690 static const char *hex =
"0123456789abcdef";
8692 for (;
len--; p++) {
8693 *to++ = hex[p[0] >> 4];
8694 *to++ = hex[p[0] & 0x0f];
8713 while ((p = va_arg(ap,
const char *)) != NULL) {
8719 bin2str(buf, hash,
sizeof(hash));
8733 const char *response)
8735 char ha2[32 + 1], expected_response[32 + 1];
8738 if ((method == NULL) || (nonce == NULL) || (nc == NULL) || (cnonce == NULL)
8739 || (qop == NULL) || (response == NULL)) {
8744 if (strlen(response) != 32) {
8748 mg_md5(ha2, method,
":", uri, NULL);
8749 mg_md5(expected_response,
8767#if !defined(NO_FILESYSTEMS)
8775 if ((conn != NULL) && (conn->
dom_ctx != NULL)) {
8781 if (gpass != NULL) {
8815 for (p = path,
e = p + strlen(p) - 1;
e > p;
e--) {
8877 const char *userpw_b64 = ah + 6;
8878 size_t userpw_b64_len = strlen(userpw_b64);
8879 size_t buf_len_r = buf_size;
8881 userpw_b64, userpw_b64_len, (
unsigned char *)buf, &buf_len_r)
8885 split = strchr(buf,
':');
8916 while (isspace((
unsigned char)*s)) {
8932 if (*
name ==
'\0') {
8936 if (!strcmp(
name,
"username")) {
8938 }
else if (!strcmp(
name,
"cnonce")) {
8940 }
else if (!strcmp(
name,
"response")) {
8942 }
else if (!strcmp(
name,
"uri")) {
8944 }
else if (!strcmp(
name,
"qop")) {
8946 }
else if (!strcmp(
name,
"nc")) {
8948 }
else if (!strcmp(
name,
"nonce")) {
8953#if !defined(NO_NONCE_CHECK)
8960 if ((s == NULL) || (*s != 0)) {
9014#define INITIAL_DEPTH 9
9015#if INITIAL_DEPTH <= 0
9016#error Bad INITIAL_DEPTH for recursion, set to at least 1
9019#if !defined(NO_FILESYSTEMS)
9036 int is_authorized = 0;
9040 if (!filep || !workdata || (0 == depth)) {
9045 while (
mg_fgets(workdata->
buf,
sizeof(workdata->
buf), filep) != NULL) {
9046 l = strlen(workdata->
buf);
9048 if (isspace((
unsigned char)workdata->
buf[
l - 1])
9049 || iscntrl((
unsigned char)workdata->
buf[
l - 1])) {
9051 workdata->
buf[
l] = 0;
9061 if (workdata->
f_user[0] ==
':') {
9065 if (workdata->
f_user[1] ==
'#') {
9068 }
else if (!strncmp(workdata->
f_user + 1,
"include=", 8)) {
9081 if (is_authorized) {
9082 return is_authorized;
9086 "%s: cannot open authorization file: %s",
9095 "%s: syntax error in authorization file: %s",
9104 "%s: syntax error in authorization file: %s",
9113 if (workdata->
f_ha1 == NULL) {
9115 "%s: syntax error in authorization file: %s",
9120 *(
char *)(workdata->
f_ha1) = 0;
9121 (workdata->
f_ha1)++;
9136 return 0 == memcmp(workdata->
f_ha1, md5, 33);
9154 return is_authorized;
9169 memset(&workdata, 0,
sizeof(workdata));
9219#if !defined(NO_FILESYSTEMS)
9221 struct vec uri_vec, filename_vec;
9224 int authorized = 1, truncated;
9226 if (!conn || !conn->
dom_ctx) {
9231 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
9238 (
int)filename_vec.
len,
9244 "%s: cannot open %s: %s",
9258 authorized =
authorize(conn, &file, NULL);
9302 "Digest qop=\"auth\", realm=\"%s\", "
9332#if !defined(NO_FILES)
9342 if (passfile != NULL
9361 int found = 0, i,
result = 1;
9362 char line[512], u[256],
d[256],
h[256];
9363 struct stat st = {0};
9365 char *temp_file = NULL;
9366 int temp_file_offs = 0;
9369 if ((ha1 != NULL) && (ha1[0] ==
'\0')) {
9374 if ((fname == NULL) || (domain == NULL) || (user == NULL)) {
9380 if (strchr(user,
':') != NULL) {
9383 if (strchr(domain,
':') != NULL) {
9389 for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
9390 if (iscntrl((
unsigned char)user[i])) {
9397 for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
9398 if (iscntrl((
unsigned char)domain[i])) {
9412 if (0 == stat(fname, &st)) {
9414 if (st.st_size > 10485760) {
9420 temp_buf_len = (
int)st.st_size + 1024;
9423 temp_file = (
char *)
mg_calloc((
size_t)temp_buf_len, 1);
9430 fp = fopen(fname,
"r");
9438 while ((fgets(
line,
sizeof(
line), fp) != NULL)
9439 && ((temp_file_offs + 600) < temp_buf_len)) {
9441 if (sscanf(
line,
"%255[^:]:%255[^:]:%255s", u,
d,
h) != 3) {
9448 if (!strcmp(u, user) && !strcmp(
d, domain)) {
9451 if ((ha1 != NULL) && (!found)) {
9452 i = sprintf(temp_file + temp_file_offs,
9462 temp_file_offs += i;
9467 i = sprintf(temp_file + temp_file_offs,
"%s:%s:%s\n", u,
d,
h);
9473 temp_file_offs += i;
9480 fp = fopen(fname,
"w");
9488 if (fchmod(fileno(fp), S_IRUSR | S_IWUSR) != 0) {
9493 if ((temp_file != NULL) && (temp_file_offs > 0)) {
9495 if (fwrite(temp_file, 1, (
size_t)temp_file_offs, fp)
9496 != (
size_t)temp_file_offs) {
9502 if ((ha1 != NULL) && (!found)) {
9503 if (fprintf(fp,
"%s:%s:%s\n", user, domain, ha1) < 6) {
9509 if (fclose(fp) != 0) {
9525 if ((fname == NULL) || (domain == NULL) || (user == NULL)) {
9528 if ((pass == NULL) || (pass[0] == 0)) {
9532 mg_md5(ha1buf, user,
":", domain,
":", pass, NULL);
9540 return (port <= 0xffff);
9547 struct addrinfo hints, *res, *ressave;
9551 memset(&hints, 0,
sizeof(
struct addrinfo));
9552 hints.ai_family = af;
9554 hints.ai_flags = AI_NUMERICHOST;
9557 gai_ret = getaddrinfo(
src, NULL, &hints, &res);
9572 if ((dstlen >= (
size_t)res->ai_addrlen)
9573 && (res->ai_addr->sa_family == af)) {
9574 memcpy(dst, res->ai_addr, res->ai_addrlen);
9580 freeaddrinfo(ressave);
9600 memset(sa, 0,
sizeof(*sa));
9603 if (error != NULL) {
9615#if defined(USE_X_DOM_SOCKET)
9618 size_t hostlen = strlen(host);
9619 if (hostlen >=
sizeof(sa->sun.sun_path)) {
9620 if (error != NULL) {
9627 "host length exceeds limit");
9634 if (error != NULL) {
9646#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS) \
9647 && !defined(NO_SSL_DL)
9648#if defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)
9649 if (use_ssl && (TLS_client_method == NULL)) {
9650 if (error != NULL) {
9657 "SSL is not initialized");
9662 if (use_ssl && (SSLv23_client_method == NULL)) {
9670 "SSL is not initialized");
9679#if defined(USE_X_DOM_SOCKET)
9681 size_t hostlen = strlen(host);
9684 sa->sun.sun_family = AF_UNIX;
9685 memset(sa->sun.sun_path, 0,
sizeof(sa->sun.sun_path));
9686 memcpy(sa->sun.sun_path, host, hostlen);
9690 sa->
sin.sin_port = htons((uint16_t)port);
9692#if defined(USE_IPV6)
9693 }
else if (
mg_inet_pton(AF_INET6, host, &sa->sin6,
sizeof(sa->sin6), 1)) {
9694 sa->sin6.sin6_port = htons((uint16_t)port);
9696 }
else if (host[0] ==
'[') {
9699 size_t l = strlen(host + 1);
9703 if (
mg_inet_pton(AF_INET6,
h, &sa->sin6,
sizeof(sa->sin6), 0)) {
9704 sa->sin6.sin6_port = htons((uint16_t)port);
9713 if (error != NULL) {
9726 *sock =
socket(PF_INET, SOCK_STREAM, 0);
9728#if defined(USE_IPV6)
9729 else if (ip_ver == 6) {
9730 *sock =
socket(PF_INET6, SOCK_STREAM, 0);
9733#if defined(USE_X_DOM_SOCKET)
9734 else if (ip_ver == -99) {
9735 *sock =
socket(AF_UNIX, SOCK_STREAM, 0);
9740 if (error != NULL) {
9754 if (error != NULL) {
9761 "Cannot set socket to non-blocking: %s",
9773 conn_ret = connect(*sock,
9774 (
struct sockaddr *)((
void *)&sa->
sin),
9777#if defined(USE_IPV6)
9778 else if (ip_ver == 6) {
9780 conn_ret = connect(*sock,
9781 (
struct sockaddr *)((
void *)&sa->sin6),
9785#if defined(USE_X_DOM_SOCKET)
9786 else if (ip_ver == -99) {
9788 conn_ret = connect(*sock,
9789 (
struct sockaddr *)((
void *)&sa->sun),
9794 if (conn_ret != 0) {
9799 if ((conn_ret != 0) && (sockerr == WSAEWOULDBLOCK)) {
9801 if ((conn_ret != 0) && (sockerr == EINPROGRESS)) {
9804 void *psockerr = &sockerr;
9808 int len = (
int)
sizeof(sockerr);
9810 socklen_t
len = (socklen_t)
sizeof(sockerr);
9816 int ms_wait = 10000;
9818 unsigned int num_sock = 1;
9826 pfd[0].events = POLLOUT;
9830 pfd[num_sock].events = POLLIN;
9839 if (error != NULL) {
9845 "connect(%s:%d): timeout",
9855 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, (
char *)psockerr, &
len);
9857 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, psockerr, &
len);
9860 if ((
ret == 0) && (sockerr == 0)) {
9865 if (conn_ret != 0) {
9867 if (error != NULL) {
9874 "connect(%s:%d): error %s",
9891 static const char *dont_escape =
"._-$,;~()";
9892 static const char *hex =
"0123456789abcdef";
9894 const char *end = dst + dst_len - 1;
9896 for (; ((*
src !=
'\0') && (pos < end));
src++, pos++) {
9897 if (isalnum((
unsigned char)*
src)
9898 || (strchr(dont_escape, *
src) != NULL)) {
9900 }
else if (pos + 2 < end) {
9902 pos[1] = hex[(
unsigned char)*
src >> 4];
9903 pos[2] = hex[(
unsigned char)*
src & 0xf];
9911 return (*
src ==
'\0') ? (
int)(pos - dst) : -1;
9919 size_t namesize, escsize, i;
9920 char *href, *
esc, *p;
9921 char size[64], mod[64];
9922#if defined(REENTRANT_TIME)
9924 struct tm *tm = &_tm;
9932 href = (
char *)
mg_malloc(namesize * 3 + escsize);
9940 esc = href + namesize * 3;
9945 }
else if (*p ==
'<') {
9947 }
else if (*p ==
'>') {
9997#if defined(REENTRANT_TIME)
10003 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", tm);
10005 mg_strlcpy(mod,
"01-Jan-1970 00:00",
sizeof(mod));
10008 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
10009 "<td> %s</td><td> %s</td></tr>\n",
10026 const char *query_string = (
const char *)(arg != NULL ? arg :
"");
10028 const struct de *
a = (
const struct de *)p1, *
b = (
const struct de *)p2;
10029 int cmp_result = 0;
10031 if ((query_string == NULL) || (query_string[0] ==
'\0')) {
10032 query_string =
"n";
10036 if (
a->file.is_directory && !
b->file.is_directory) {
10038 }
else if (!
a->file.is_directory &&
b->file.is_directory) {
10043 if (*query_string ==
's') {
10044 cmp_result = (
a->file.size ==
b->file.size)
10046 : ((
a->file.size >
b->file.size) ? 1 : -1);
10047 }
else if (*query_string ==
'd') {
10049 (
a->file.last_modified ==
b->file.last_modified)
10051 : ((
a->file.last_modified >
b->file.last_modified) ? 1
10059 if (cmp_result == 0) {
10060 cmp_result = strcmp(
a->file_name,
b->file_name);
10064 return (query_string[1] ==
'd') ? -cmp_result : cmp_result;
10083#if !defined(NO_FILESYSTEMS)
10088 int (*cb)(
struct de *,
void *))
10096 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
10102 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")
10108 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
10124 "%s: mg_stat(%s) failed: %s",
10142#if !defined(NO_FILES)
10153 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
10160 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")) {
10165 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
10182 "%s: mg_stat(%s) failed: %s",
10217#if !defined(NO_FILESYSTEMS)
10229 dsd->
arr_size * 2 *
sizeof(entries[0]));
10230 if (entries == NULL) {
10253 int sort_direction;
10255 char date[64], *
esc, *p;
10257 time_t curtime = time(NULL);
10266 "Error: Cannot open directory\nopendir(%s): %s",
10276 if (title[strcspn(title,
"&<>")]) {
10280 for (i = 0, p =
esc; title[i]; i++, p += strlen(p)) {
10283 strcpy(p,
"&");
10284 }
else if (*p ==
'<') {
10286 }
else if (*p ==
'>') {
10309 "text/html; charset=utf-8",
10318 "<html><head><title>Index of %s</title>"
10319 "<style>th {text-align: left;}</style></head>"
10320 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
10321 "<tr><th><a href=\"?n%c\">Name</a></th>"
10322 "<th><a href=\"?d%c\">Modified</a></th>"
10323 "<th><a href=\"?s%c\">Size</a></th></tr>"
10324 "<tr><td colspan=\"3\"><hr></td></tr>",
10334 "<tr><td><a href=\"%s\">%s</a></td>"
10335 "<td> %s</td><td> %s</td></tr>\n",
10337 "Parent directory",
10342 if (
data.entries != NULL) {
10345 sizeof(
data.entries[0]),
10348 for (i = 0; i <
data.num_entries; i++) {
10355 mg_printf(conn,
"%s",
"</table></pre></body></html>");
10370 int to_read, num_read, num_written;
10373 if (!filep || !conn) {
10384#if defined(__linux__)
10389 off_t sf_offs = (off_t)
offset;
10391 int sf_file = fileno(filep->
access.
fp);
10398 (size_t)((
len < 0x7FFFF000) ?
len : 0x7FFFF000);
10400 sendfile(conn->
client.
sock, sf_file, &sf_offs, sf_tosend);
10404 }
else if (loop_cnt == 0) {
10410 }
else if (sf_sent == 0) {
10416 }
while ((
len > 0) && (sf_sent >= 0));
10425 offset = (int64_t)sf_offs;
10430 "%s: fseeko() failed: %s",
10437 "Error: Unable to access file at requested position.");
10450 to_read = no_buffering ? 1 :
sizeof(buf);
10451 if ((int64_t)to_read >
len) {
10466 if ((num_written =
mg_write(conn, buf, (
size_t)num_read))
10472 len -= num_written;
10482 return sscanf(header,
10494 if ((filestat != NULL) && (buf != NULL)) {
10509 if (filep != NULL && filep->
fp != NULL) {
10513 if (fcntl(fileno(filep->
fp), F_SETFD, FD_CLOEXEC) != 0) {
10515 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
10524#if defined(USE_ZLIB)
10525#include "mod_zlib.inl"
10529#if !defined(NO_FILESYSTEMS)
10535 const char *additional_headers)
10537 char lm[64], etag[64];
10539 const char *range_hdr;
10540 int64_t cl, r1, r2;
10541 struct vec mime_vec;
10544 const char *encoding = 0;
10545 int is_head_request;
10547#if defined(USE_ZLIB)
10551 int allow_on_the_fly_compression = 1;
10554 if ((conn == NULL) || (conn->
dom_ctx == NULL) || (filep == NULL)) {
10569 "Error: File size is too large to send\n%" INT64_FMT,
10577#if defined(USE_ZLIB)
10582 allow_on_the_fly_compression = 0;
10591 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
10596 "Error: Path of zipped file too long (%s)",
10604#if defined(USE_ZLIB)
10606 allow_on_the_fly_compression = 0;
10608 }
else if ((conn->
accept_gzip) && (range_hdr == NULL)
10612 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
10614 if (!truncated &&
mg_stat(conn, gz_path, &file_stat)
10617 filep->
stat = file_stat;
10622#if defined(USE_ZLIB)
10624 allow_on_the_fly_compression = 0;
10632 "Error: Cannot open file\nfopen(%s): %s",
10643 if ((range_hdr != NULL)
10653 "Error: Range requests in gzipped files are not supported");
10659 cl = (
n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
10670#if defined(USE_ZLIB)
10672 allow_on_the_fly_compression = 0;
10678#if defined(USE_ZLIB)
10681 allow_on_the_fly_compression = 0;
10697 (
int)mime_vec.
len);
10701#if defined(USE_ZLIB)
10703 if (allow_on_the_fly_compression) {
10732 if (range[0] != 0) {
10738 if ((additional_headers != NULL) && (*additional_headers != 0)) {
10745 if (!is_head_request) {
10746#if defined(USE_ZLIB)
10747 if (allow_on_the_fly_compression) {
10749 send_compressed_data(conn, filep);
10776#if !defined(NO_CACHING)
10783 const char *ims =
mg_get_header(conn,
"If-Modified-Since");
10797 char lm[64], etag[64];
10799 if ((conn == NULL) || (filep == NULL)) {
10819#if !defined(NO_FILESYSTEMS)
10840 const char *additional_headers)
10850#if !defined(NO_CACHING)
10864 "Error: Directory listing denied");
10868 conn, path, &file,
mime_type, additional_headers);
10891 for (s = p = path + 2; (p = strchr(s,
'/')) != NULL; s = ++p) {
10892 len = (size_t)(p - path);
10893 if (
len >=
sizeof(buf)) {
10898 memcpy(buf, path,
len);
10910 if (p[1] ==
'\0') {
10925 "%s: Cannot remove invalid file %s",
10996 while ((
unsigned char)**ppw > 127 || isgraph((
unsigned char)**ppw)) {
11003 if ((**ppw !=
'\r') && (**ppw !=
'\n')) {
11008 if (**ppw !=
' ') {
11017 }
while (isspace((
unsigned char)**ppw));
11022 if (!isgraph((
unsigned char)**ppw)) {
11040 int num_headers = 0;
11046 while ((*dp !=
':') && (*dp >= 33) && (*dp <= 126)) {
11055 while (*dp ==
' ') {
11067 hdr[i].name = *buf;
11072 }
while ((*dp ==
' ') || (*dp ==
'\t'));
11078 while ((*dp != 0) && (*dp !=
'\r') && (*dp !=
'\n')) {
11094 num_headers = i + 1;
11101 if ((dp[0] ==
'\r') || (dp[0] ==
'\n')) {
11112 return num_headers;
11129 {
"GET", 0, 1, 1, 1, 1},
11130 {
"POST", 1, 1, 0, 0, 0},
11131 {
"PUT", 1, 0, 0, 1, 0},
11132 {
"DELETE", 0, 0, 0, 1, 0},
11133 {
"HEAD", 0, 0, 1, 1, 1},
11134 {
"OPTIONS", 0, 0, 1, 1, 0},
11135 {
"CONNECT", 1, 1, 0, 0, 0},
11139 {
"PATCH", 1, 0, 0, 0, 0},
11143 {
"PROPFIND", 0, 1, 1, 1, 0},
11149 {
"MKCOL", 0, 0, 0, 1, 0},
11162 {
"LOCK", 1, 1, 0, 0, 0},
11163 {
"UNLOCK", 1, 0, 0, 0, 0},
11164 {
"PROPPATCH", 1, 1, 0, 0, 0},
11165 {
"COPY", 1, 0, 0, 0, 0},
11166 {
"MOVE", 1, 1, 0, 0, 0},
11177 {
"REPORT", 1, 1, 1, 1, 1},
11184 {NULL, 0, 0, 0, 0, 0}
11203 if (!strcmp(
m->name, method)) {
11231 int request_length;
11243 while ((
len > 0) && isspace((
unsigned char)*buf)) {
11255 if (iscntrl((
unsigned char)*buf)) {
11261 if (request_length <= 0) {
11262 return request_length;
11264 buf[request_length - 1] =
'\0';
11266 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
11310 return request_length + init_skip;
11317 int response_length;
11329 while ((
len > 0) && isspace((
unsigned char)*buf)) {
11341 if (iscntrl((
unsigned char)*buf)) {
11347 if (response_length <= 0) {
11348 return response_length;
11350 buf[response_length - 1] =
'\0';
11352 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
11358 if (strncmp(buf,
"HTTP/", 5) != 0) {
11363 if (!isgraph((
unsigned char)buf[0])) {
11380 l = strtol(tmp, &tmp2, 10);
11381 if ((
l < 100) || (
l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
11392 while (isprint((
unsigned char)*buf)) {
11395 if ((*buf !=
'\r') && (*buf !=
'\n')) {
11402 }
while (isspace((
unsigned char)*buf));
11411 return response_length + init_skip;
11427 int request_len,
n = 0;
11428 struct timespec last_action_time;
11429 double request_timeout;
11435 memset(&last_action_time, 0,
sizeof(last_action_time));
11456 while (request_len == 0) {
11463 if (*nread >= bufsiz) {
11469 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
11476 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
11483 if ((
n <= 0) && (request_timeout >= 0)) {
11485 > request_timeout) {
11492 return request_len;
11496#if !defined(NO_CGI) || !defined(NO_FILES)
11500 const char *expect;
11515 if ((expect != NULL) && (
mg_strcasecmp(expect,
"100-continue") != 0)) {
11520 if (expect != NULL) {
11521 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
11535 int nread =
mg_read(conn, buf,
sizeof(buf));
11537 success = (nread == 0);
11559#if defined(USE_TIMERS)
11561#define TIMER_API static
11562#include "timer.inl"
11567#if !defined(NO_CGI)
11600 size_t i,
n, space;
11605 if ((env->varlen - env->varused) < 2) {
11606 mg_cry_internal(env->conn,
11607 "%s: Cannot register CGI variable [%s]",
11614 space = (env->buflen - env->bufused);
11620 n = env->buflen + CGI_ENVIRONMENT_SIZE;
11621 added = (char *)mg_realloc_ctx(env->buf, n, env->conn->phys_ctx);
11626 "%s: Cannot allocate memory for CGI variable [%s]",
11634 for (i = 0, n = 0; i < env->varused; i++) {
11635 env->var[i] = added + n;
11636 n += strlen(added + n) + 1;
11638 space = (env->buflen - env->bufused);
11642 added = env->buf + env->bufused;
11646 mg_vsnprintf(env->conn, &truncated, added, space - 1, fmt, ap);
11654 }
while (truncated);
11657 n = strlen(added) + 1;
11671 int cgi_config_idx)
11674 struct vec var_vec;
11676 int i, truncated, uri_len;
11678 if ((conn == NULL) || (prog == NULL) || (env == NULL)) {
11686 if (env->
buf == NULL) {
11688 "%s: Not enough memory for environmental buffer",
11696 if (env->
var == NULL) {
11698 "%s: Not enough memory for environmental variables",
11709 "FALLBACK_DOCUMENT_ROOT=%s",
11715 addenv(env,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
11716 addenv(env,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
11717 addenv(env,
"%s",
"REDIRECT_STATUS=200");
11722 addenv(env,
"REMOTE_ADDR=%s", src_addr);
11739 const char *index_file = strrchr(prog,
'/');
11742 "SCRIPT_NAME=%s%s",
11750 "SCRIPT_NAME=%.*s",
11751 uri_len - (
int)strlen(conn->
path_info),
11755 addenv(env,
"SCRIPT_FILENAME=%s", prog);
11760 "PATH_TRANSLATED=%s%s",
11765 addenv(env,
"HTTPS=%s", (conn->
ssl == NULL) ?
"off" :
"on");
11768 addenv(env,
"CONTENT_TYPE=%s", s);
11774 addenv(env,
"CONTENT_LENGTH=%s", s);
11776 if ((s = getenv(
"PATH")) != NULL) {
11777 addenv(env,
"PATH=%s", s);
11789 if ((s = getenv(
"COMSPEC")) != NULL) {
11790 addenv(env,
"COMSPEC=%s", s);
11792 if ((s = getenv(
"SYSTEMROOT")) != NULL) {
11793 addenv(env,
"SYSTEMROOT=%s", s);
11795 if ((s = getenv(
"SystemDrive")) != NULL) {
11796 addenv(env,
"SystemDrive=%s", s);
11798 if ((s = getenv(
"ProgramFiles")) != NULL) {
11799 addenv(env,
"ProgramFiles=%s", s);
11801 if ((s = getenv(
"ProgramFiles(x86)")) != NULL) {
11802 addenv(env,
"ProgramFiles(x86)=%s", s);
11805 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL) {
11806 addenv(env,
"LD_LIBRARY_PATH=%s", s);
11810 if ((s = getenv(
"PERLLIB")) != NULL) {
11811 addenv(env,
"PERLLIB=%s", s);
11816 addenv(env,
"%s",
"AUTH_TYPE=Digest");
11825 sizeof(http_var_name),
11831 "%s: HTTP header variable too long [%s]",
11838 for (p = http_var_name; *p !=
'\0'; p++) {
11842 *p = (char)toupper((
unsigned char)*p);
11853 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
11881 ret_pid = waitpid(proc->
pid, &status, WNOHANG);
11882 if ((ret_pid != (pid_t)-1) && (status == 0)) {
11885 kill(proc->
pid, SIGABRT);
11888 while (waitpid(proc->
pid, &status, 0) != (pid_t)-1)
11891 DEBUG_TRACE(
"CGI timer: Child process %d already stopped\n", proc->
pid);
11908 int cgi_config_idx)
11912 int headers_len, data_len, i, truncated;
11913 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
11914 const char *status, *status_text;
11918 FILE *in = NULL, *out = NULL, *
err = NULL;
11920 pid_t pid = (pid_t)-1;
11923 int no_buffering = 0;
11925#if defined(USE_TIMERS)
11926 double cgi_timeout;
11930 atof(conn->
dom_ctx->
config[CGI_TIMEOUT + cgi_config_idx]) * 0.001;
11936 if (cfg_buffering != NULL) {
11954 (void)
mg_snprintf(conn, &truncated, dir,
sizeof(dir),
"%s", prog);
11957 mg_cry_internal(conn,
"Error: CGI program \"%s\": Path too long", prog);
11962 if ((p = strrchr(dir,
'/')) != NULL) {
11970 if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) {
11971 status = strerror(
ERRNO);
11974 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
11979 "Error: Cannot create CGI pipe: %s",
11986 if (proc == NULL) {
11987 mg_cry_internal(conn,
"Error: CGI program \"%s\": Out or memory", prog);
11994 conn, p,
blk.buf,
blk.var, fdin, fdout, fderr, dir, cgi_config_idx);
11996 if (
pid == (pid_t)-1) {
11997 status = strerror(
ERRNO);
12000 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
12013#if defined(USE_TIMERS)
12014 if (cgi_timeout > 0.0) {
12032 (void)close(fdin[0]);
12033 (void)close(fdout[1]);
12034 (void)close(fderr[1]);
12035 fdin[0] = fdout[1] = fderr[1] = -1;
12037 if (((in = fdopen(fdin[1],
"wb")) == NULL)
12038 || ((out = fdopen(fdout[0],
"rb")) == NULL)
12039 || ((
err = fdopen(fderr[0],
"rb")) == NULL)) {
12040 status = strerror(
ERRNO);
12042 "Error: CGI program \"%s\": Can not open fd: %s",
12047 "Error: CGI can not open fd\nfdopen: %s",
12066 "Error: CGI program \"%s\": Forward body data failed",
12086 "Error: Not enough memory for CGI buffer (%u bytes)",
12087 (
unsigned int)buflen);
12090 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
12093 (
unsigned int)buflen);
12098 headers_len =
read_message(out, conn, buf, (
int)buflen, &data_len);
12099 DEBUG_TRACE(
"CGI: response: %li", (
signed long)headers_len);
12101 if (headers_len <= 0) {
12110 "Error: CGI program \"%s\" sent error "
12118 "Error: CGI program \"%s\" failed.",
12124 "Error: CGI program sent malformed or too big "
12125 "(>%u bytes) HTTP headers: [%.*s]",
12132 "Error: CGI program sent malformed or too big "
12133 "(>%u bytes) HTTP headers: [%.*s]",
12144 buf[headers_len - 1] =
'\0';
12148 status_text =
"OK";
12152 status_text = status;
12153 while (isdigit((
unsigned char)*status_text) || *status_text ==
' ') {
12184 mg_write(conn, buf + headers_len, (
size_t)(data_len - headers_len));
12195 if (
pid != (pid_t)-1) {
12199 if (fdin[0] != -1) {
12202 if (fdout[1] != -1) {
12205 if (fderr[1] != -1) {
12211 }
else if (fdin[1] != -1) {
12217 }
else if (fdout[0] != -1) {
12223 }
else if (fderr[0] != -1) {
12232#if !defined(NO_FILES)
12239 if (conn == NULL) {
12249 "%s: mg_stat(%s) failed: %s",
12260 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
12265 if (body_len > 0) {
12267 conn, 415,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
12283 int http_status = 500;
12298 "Error processing %s: %s",
12315 const char *overwrite_hdr;
12316 const char *destination_hdr;
12318 int rc, dest_uri_type;
12319 int http_status = 400;
12320 int do_overwrite = 0;
12321 int destination_ok = 0;
12325 if (conn == NULL) {
12332 if ((overwrite_hdr != NULL) && (toupper(overwrite_hdr[0]) ==
'T')) {
12336 if ((destination_hdr == NULL) || (destination_hdr[0] == 0)) {
12341 if (root != NULL) {
12342 char *local_dest = NULL;
12344 if (dest_uri_type == 2) {
12346 }
else if ((dest_uri_type == 3) || (dest_uri_type == 4)) {
12350 size_t len = strlen(
h);
12355 if (local_dest != NULL) {
12357 if (local_dest[0] ==
'/') {
12358 int trunc_check = 0;
12366 if (trunc_check == 0) {
12367 destination_ok = 1;
12374 if (!destination_ok) {
12380 if (
mg_stat(conn, dest_path, &ignored)) {
12382 if (do_overwrite) {
12384 if (0 != remove(dest_path)) {
12388 "Cannot overwrite file: %s",
12396 "Destination already exists: %s",
12403 DEBUG_TRACE(
"%s %s to %s", (do_copy ?
"copy" :
"move"), path, dest_path);
12407 wchar_t wSource[UTF16_PATH_MAX];
12408 wchar_t wDest[UTF16_PATH_MAX];
12411 path_to_unicode(conn, path, wSource,
ARRAY_SIZE(wSource));
12412 path_to_unicode(conn, dest_path, wDest,
ARRAY_SIZE(wDest));
12414 ok = CopyFileW(wSource, wDest, do_overwrite ? FALSE : TRUE);
12416 ok = MoveFileExW(wSource,
12418 do_overwrite ? MOVEFILE_REPLACE_EXISTING : 0);
12423 DWORD lastErr = GetLastError();
12424 if (lastErr == ERROR_ALREADY_EXISTS) {
12427 "Destination already exists: %s",
12446 rc = rename(path, dest_path);
12484 if (conn == NULL) {
12504 if (
access(path, W_OK) == 0) {
12511 "Error: Put not possible\nReplacing %s is not allowed",
12543 "Error: Path too long\nput_dir(%s): %s",
12553 "Error: Can not create directory\nput_dir(%s): %s",
12566 "Error: Can not create file\nfopen(%s): %s",
12577 if (0 != fseeko(file.
access.
fp, r1, SEEK_SET)) {
12580 "Error: Internal error processing file %s",
12620 "Error: Cannot delete file\nFile %s not found",
12640 if (access(path, W_OK) != 0) {
12645 "Error: Delete not possible\nDeleting %s is not allowed",
12663 "Error: Cannot delete file\nremove(%s): %s",
12671#if !defined(NO_FILESYSTEMS)
12687 if (conn == NULL) {
12694 if (sscanf(tag,
" virtual=\"%511[^\"]\"", file_name) == 1) {
12696 file_name[511] = 0;
12705 }
else if (sscanf(tag,
" abspath=\"%511[^\"]\"", file_name) == 1) {
12708 file_name[511] = 0;
12710 mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", file_name);
12712 }
else if ((sscanf(tag,
" file=\"%511[^\"]\"", file_name) == 1)
12713 || (sscanf(tag,
" \"%511[^\"]\"", file_name) == 1)) {
12715 file_name[511] = 0;
12716 (void)
mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", ssi);
12719 if ((p = strrchr(path,
'/')) != NULL) {
12722 len = strlen(path);
12726 sizeof(path) -
len,
12737 mg_cry_internal(conn,
"SSI #include path length overflow: [%s]", tag);
12743 "Cannot open SSI #include: [%s]: fopen(%s): %s",
12760#if !defined(NO_POPEN)
12764 char cmd[1024] =
"";
12767 if (sscanf(tag,
" \"%1023[^\"]\"", cmd) != 1) {
12771 if ((file.
access.
fp = popen(cmd,
"r")) == NULL) {
12773 "Cannot SSI #exec: [%s]: %s",
12788 if (filep == NULL) {
12807 int ch,
len, in_tag, in_ssi_tag;
12809 if (include_level > 10) {
12814 in_tag = in_ssi_tag =
len = 0;
12817 while ((ch =
mg_fgetc(filep)) != EOF) {
12830 if ((
len > 12) && !memcmp(buf + 5,
"include", 7)) {
12832#if !defined(NO_POPEN)
12833 }
else if ((
len > 9) && !memcmp(buf + 5,
"exec", 4)) {
12844 in_ssi_tag = in_tag = 0;
12856 buf[
len++] = (char)(ch & 0xff);
12858 if ((
len == 5) && !memcmp(buf,
"<!--#", 5)) {
12863 if ((
len + 2) > (
int)
sizeof(buf)) {
12889 buf[
len++] = (char)(ch & 0xff);
12891 if (
len == (
int)
sizeof(buf)) {
12912 time_t curtime = time(NULL);
12914 if ((conn == NULL) || (path == NULL) || (filep == NULL)) {
12923 "Error: Cannot read file\nfopen(%s): %s",
12949#if !defined(NO_FILES)
12988 size_t link_concat_len;
12990 if ((conn == NULL) || (uri == NULL) || (
name == NULL) || (filep == NULL)) {
12994 link_concat_len = strlen(uri) + strlen(
name) + 1;
12996 if (!link_concat) {
12999 strcpy(link_concat, uri);
13000 strcat(link_concat,
name);
13004 conn, link_buf,
sizeof(link_buf), NULL, 0, link_concat);
13019 "<d:href>%s</d:href>"
13022 "<d:resourcetype>%s</d:resourcetype>"
13023 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
13024 "<d:getlastmodified>%s</d:getlastmodified>"
13025 "<d:lockdiscovery>",
13033 if (!strcmp(dav_lock[i].
path, link_buf)) {
13036 "<d:locktype><d:write/></d:locktype>"
13037 "<d:lockscope><d:exclusive/></d:lockscope>"
13038 "<d:depth>0</d:depth>"
13039 "<d:owner>%s</d:owner>"
13040 "<d:timeout>Second-%u</d:timeout>"
13042 "<d:href>%s</d:href>"
13044 "</d:activelock>\n",
13047 dav_lock[i].
token);
13052 "</d:lockdiscovery>"
13054 "<d:status>HTTP/1.1 200 OK</d:status>"
13056 "</d:response>\n");
13084 if (!conn || !path || !filep || !conn->
dom_ctx) {
13095 "application/xml; charset=utf-8",
13101 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
13102 "<d:multistatus xmlns:d='DAV:'>\n");
13112 && ((depth == NULL) || (strcmp(depth,
"0") != 0))) {
13116 mg_printf(conn,
"%s\n",
"</d:multistatus>");
13125 uint64_t new_locktime;
13126 int lock_index = -1;
13128 uint64_t LOCK_DURATION_NS =
13150 while (lock_index < 0) {
13153 if (!strcmp(dav_lock[i].
path, link_buf)) {
13156 dav_lock[i].
locktime = new_locktime;
13162 > (dav_lock[i].
locktime + LOCK_DURATION_NS)) {
13164 dav_lock[i].
path[0] = 0;
13177 if (dav_lock[i].
path[0] == 0) {
13190 sizeof(dav_lock[i].
path));
13193 sizeof(dav_lock[i].
user));
13198 if (lock_index < 0) {
13200 uint64_t oldest_locktime = dav_lock[0].
locktime;
13203 if (dav_lock[i].
locktime < oldest_locktime) {
13204 oldest_locktime = dav_lock[i].
locktime;
13209 dav_lock[lock_index].
path[0] = 0;
13221 "application/xml; charset=utf-8",
13228 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
13229 "<d:prop xmlns:d=\"DAV:\">\n"
13230 " <d:lockdiscovery>\n"
13231 " <d:activelock>\n"
13232 " <d:lockscope><d:exclusive/></d:lockscope>\n"
13233 " <d:locktype><d:write/></d:locktype>\n"
13235 " <d:href>%s</d:href>\n"
13237 " <d:timeout>Second-%u</d:timeout>\n"
13238 " <d:locktoken><d:href>%s</d:href></d:locktoken>\n"
13240 " <d:href>%s</d:href>\n"
13242 " </d:activelock>\n"
13243 " </d:lockdiscovery>\n"
13245 dav_lock[lock_index].
user,
13247 dav_lock[lock_index].
token,
13248 dav_lock[lock_index].
path);
13269 if (!strcmp(dav_lock[lock_index].
path, link_buf)) {
13301 "application/xml; charset=utf-8",
13309 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
13310 "<d:multistatus xmlns:d='DAV:'>\n"
13311 "<d:response>\n<d:href>%s</d:href>\n",
13314 "<d:propstat><d:status>HTTP/1.1 403 "
13315 "Forbidden</d:status></d:propstat>\n");
13316 mg_printf(conn,
"%s\n",
"</d:response></d:multistatus>");
13325 (void)pthread_mutex_lock(&conn->
mutex);
13334 (void)pthread_mutex_unlock(&conn->
mutex);
13357#if defined(USE_LUA)
13358#include "mod_lua.inl"
13361#if defined(USE_DUKTAPE)
13362#include "mod_duktape.inl"
13365#if defined(USE_WEBSOCKET)
13367#if !defined(NO_SSL_DL)
13368#if !defined(OPENSSL_API_3_0)
13369#define SHA_API static
13375send_websocket_handshake(
struct mg_connection *conn,
const char *websock_key)
13377 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
13378 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
13379 size_t dst_len =
sizeof(b64_sha);
13380#if !defined(OPENSSL_API_3_0)
13386 mg_snprintf(conn, &truncated, buf,
sizeof(buf),
"%s%s", websock_key, magic);
13394#if defined(OPENSSL_API_3_0)
13395 EVP_Digest((
unsigned char *)buf,
13396 (uint32_t)strlen(buf),
13397 (
unsigned char *)sha,
13399 EVP_get_digestbyname(
"sha1"),
13403 SHA1_Update(&sha_ctx, (
unsigned char *)buf, (uint32_t)strlen(buf));
13408 "HTTP/1.1 101 Switching Protocols\r\n"
13409 "Upgrade: websocket\r\n"
13410 "Connection: Upgrade\r\n"
13411 "Sec-WebSocket-Accept: %s\r\n",
13414#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13416 websocket_deflate_response(conn);
13421 "Sec-WebSocket-Protocol: %s\r\n\r\n",
13431#if !defined(MG_MAX_UNANSWERED_PING)
13437#define MG_MAX_UNANSWERED_PING (5)
13444 void *callback_data)
13450 unsigned char *buf = (
unsigned char *)conn->
buf + conn->
request_len;
13451 int n, error, exit_by_callback;
13458 size_t i,
len, mask_len = 0, header_len, body_len;
13459 uint64_t data_len = 0;
13464 unsigned char mask[4];
13469 unsigned char mem[4096];
13473 double timeout = -1.0;
13474 int enable_ping_pong = 0;
13475 int ping_count = 0;
13484 timeout = atoi(conn->
dom_ctx->
config[WEBSOCKET_TIMEOUT]) / 1000.0;
13489 if (timeout <= 0.0) {
13494 DEBUG_TRACE(
"Websocket connection %s:%u start data processing loop",
13497 conn->in_websocket_handling = 1;
13507 len = buf[1] & 127;
13508 mask_len = (buf[1] & 128) ? 4 : 0;
13509 if ((
len < 126) && (body_len >= mask_len)) {
13512 header_len = 2 + mask_len;
13513 }
else if ((
len == 126) && (body_len >= (4 + mask_len))) {
13515 header_len = 4 + mask_len;
13516 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
13517 }
else if (body_len >= (10 + mask_len)) {
13520 memcpy(&l1, &buf[2], 4);
13521 memcpy(&l2, &buf[6], 4);
13522 header_len = 10 + mask_len;
13523 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
13525 if (data_len > (uint64_t)0x7FFF0000ul) {
13530 "websocket out of memory; closing connection");
13536 if ((header_len > 0) && (body_len >= header_len)) {
13538 unsigned char *
data = mem;
13540 if ((
size_t)data_len > (
size_t)
sizeof(mem)) {
13543 if (
data == NULL) {
13549 "websocket out of memory; closing connection");
13555 if (mask_len > 0) {
13556 memcpy(
mask, buf + header_len - mask_len,
sizeof(
mask));
13564 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
13567 len = body_len - header_len;
13568 memcpy(
data, buf + header_len,
len);
13570 while ((uint64_t)
len < data_len) {
13574 (
int)(data_len -
len),
13579 }
else if (
n > 0) {
13590 "Websocket pull failed; closing connection");
13607 len = (size_t)data_len + header_len;
13612 memcpy(
data, buf + header_len, (
size_t)data_len);
13615 memmove(buf, buf +
len, body_len -
len);
13622 if (mask_len > 0) {
13623 for (i = 0; i < (size_t)data_len; i++) {
13628 exit_by_callback = 0;
13636 }
else if (enable_ping_pong
13655 if (ws_data_handler != NULL) {
13656#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13659 if (!conn->websocket_deflate_initialized) {
13660 if (websocket_deflate_initialize(conn, 1) != Z_OK)
13661 exit_by_callback = 1;
13663 if (!exit_by_callback) {
13664 size_t inflate_buf_size_old = 0;
13665 size_t inflate_buf_size =
13669 Bytef *inflated = NULL;
13670 Bytef *new_mem = NULL;
13671 conn->websocket_inflate_state.avail_in =
13672 (uInt)(data_len + 4);
13673 conn->websocket_inflate_state.next_in =
data;
13675 data[data_len] =
'\x00';
13676 data[data_len + 1] =
'\x00';
13677 data[data_len + 2] =
'\xff';
13678 data[data_len + 3] =
'\xff';
13680 if (inflate_buf_size_old == 0) {
13685 inflate_buf_size *= 2;
13690 if (new_mem == NULL) {
13693 "Out of memory: Cannot allocate "
13694 "inflate buffer of %lu bytes",
13695 (
unsigned long)inflate_buf_size);
13696 exit_by_callback = 1;
13699 inflated = new_mem;
13700 conn->websocket_inflate_state.avail_out =
13701 (uInt)(inflate_buf_size
13702 - inflate_buf_size_old);
13703 conn->websocket_inflate_state.next_out =
13704 inflated + inflate_buf_size_old;
13705 ret = inflate(&conn->websocket_inflate_state,
13707 if (
ret == Z_NEED_DICT ||
ret == Z_DATA_ERROR
13708 ||
ret == Z_MEM_ERROR) {
13711 "ZLIB inflate error: %i %s",
13713 (conn->websocket_inflate_state.msg
13714 ? conn->websocket_inflate_state.msg
13715 :
"<no error message>"));
13716 exit_by_callback = 1;
13719 inflate_buf_size_old = inflate_buf_size;
13721 }
while (conn->websocket_inflate_state.avail_out
13723 inflate_buf_size -=
13724 conn->websocket_inflate_state.avail_out;
13725 if (!ws_data_handler(conn,
13730 exit_by_callback = 1;
13736 if (!ws_data_handler(conn,
13741 exit_by_callback = 1;
13751 if (exit_by_callback) {
13752 DEBUG_TRACE(
"Callback requests to close connection from %s:%u",
13759 DEBUG_TRACE(
"Message requests to close connection from %s:%u",
13788 if (ping_count > MG_MAX_UNANSWERED_PING) {
13790 DEBUG_TRACE(
"Too many (%i) unanswered ping from %s:%u "
13791 "- closing connection",
13797 if (enable_ping_pong) {
13823 conn->in_websocket_handling = 0;
13824 DEBUG_TRACE(
"Websocket connection %s:%u left data processing loop",
13835 uint32_t masking_key)
13837 unsigned char header[14];
13841#if defined(GCC_DIAGNOSTIC)
13843#pragma GCC diagnostic push
13844#pragma GCC diagnostic ignored "-Wconversion"
13860#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13861 size_t deflated_size = 0;
13862 Bytef *deflated = 0;
13864 int use_deflate = dataLen > 100 * 1024 && conn->
accept_gzip;
13867 if (!conn->websocket_deflate_initialized) {
13868 if (websocket_deflate_initialize(conn, 1) != Z_OK)
13873 header[0] = 0xC0u | (
unsigned char)((
unsigned)opcode & 0xf);
13874 conn->websocket_deflate_state.avail_in = (uInt)dataLen;
13875 conn->websocket_deflate_state.next_in = (
unsigned char *)
data;
13876 deflated_size = (size_t)compressBound((uLong)dataLen);
13877 deflated =
mg_calloc(deflated_size,
sizeof(Bytef));
13878 if (deflated == NULL) {
13881 "Out of memory: Cannot allocate deflate buffer of %lu bytes",
13882 (
unsigned long)deflated_size);
13886 conn->websocket_deflate_state.avail_out = (uInt)deflated_size;
13887 conn->websocket_deflate_state.next_out = deflated;
13888 deflate(&conn->websocket_deflate_state, conn->websocket_deflate_flush);
13889 dataLen = deflated_size - conn->websocket_deflate_state.avail_out
13893 header[0] = 0x80u | (
unsigned char)((
unsigned)opcode & 0xf);
13895#if defined(GCC_DIAGNOSTIC)
13896#pragma GCC diagnostic pop
13900 if (dataLen < 126) {
13902 header[1] = (
unsigned char)dataLen;
13904 }
else if (dataLen <= 0xFFFF) {
13906 uint16_t
len = htons((uint16_t)dataLen);
13908 memcpy(header + 2, &
len, 2);
13912 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
13913 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
13915 memcpy(header + 2, &len1, 4);
13916 memcpy(header + 6, &len2, 4);
13923 memcpy(header + headerLen, &masking_key, 4);
13927 retval =
mg_write(conn, header, headerLen);
13928 if (retval != (
int)headerLen) {
13933#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13935 retval =
mg_write(conn, deflated, dataLen);
13957 return mg_websocket_write_exec(conn, opcode,
data, dataLen, 0);
13962mask_data(
const char *in,
size_t in_len, uint32_t masking_key,
char *out)
13967 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
13969 while (i < (in_len - 3)) {
13970 *(uint32_t *)(
void *)(out + i) =
13971 *(uint32_t *)(
void *)(in + i) ^ masking_key;
13977 while (i < in_len) {
13978 *(uint8_t *)(
void *)(out + i) =
13979 *(uint8_t *)(
void *)(in + i)
13980 ^ *(((uint8_t *)&masking_key) + (i % 4));
13994 char *masked_data =
13996 uint32_t masking_key = 0;
13998 if (masked_data == NULL) {
14002 "Cannot allocate buffer for masked websocket response: "
14010 }
while (masking_key == 0);
14012 mask_data(
data, dataLen, masking_key, masked_data);
14014 retval = mg_websocket_write_exec(
14015 conn, opcode, masked_data, dataLen, masking_key);
14025 int is_callback_resource,
14033 const char *websock_key =
mg_get_header(conn,
"Sec-WebSocket-Key");
14034 const char *version =
mg_get_header(conn,
"Sec-WebSocket-Version");
14035 ptrdiff_t lua_websock = 0;
14037#if !defined(USE_LUA)
14043 if (!websock_key) {
14050 const char *key1 =
mg_get_header(conn,
"Sec-WebSocket-Key1");
14051 const char *key2 =
mg_get_header(conn,
"Sec-WebSocket-Key2");
14054 if ((key1 != NULL) && (key2 != NULL)) {
14057 if (8 ==
mg_read(conn, key3, 8)) {
14062 "Protocol upgrade to RFC 6455 required");
14073 if ((version == NULL) || (strcmp(version,
"13") != 0)) {
14083 if (is_callback_resource) {
14085 const char *protocols[64];
14087 "Sec-WebSocket-Protocol",
14091 if ((nbSubprotocolHeader > 0) && subprotocols) {
14095 const char *
sep, *curSubProtocol,
14096 *acceptedWebSocketSubprotocol = NULL;
14099 for (headerNo = 0; headerNo < nbSubprotocolHeader; headerNo++) {
14101 const char *protocol = protocols[headerNo];
14102 curSubProtocol = protocol;
14105 while (!acceptedWebSocketSubprotocol && (*curSubProtocol)) {
14107 while ((*curSubProtocol ==
' ') || (*curSubProtocol ==
','))
14109 sep = strchr(curSubProtocol,
',');
14111 len = (size_t)(sep - curSubProtocol);
14113 len = strlen(curSubProtocol);
14120 && (strncmp(curSubProtocol,
14124 acceptedWebSocketSubprotocol =
14129 curSubProtocol +=
len;
14134 acceptedWebSocketSubprotocol;
14137#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
14138 websocket_deflate_negotiate(conn);
14141 if ((ws_connect_handler != NULL)
14142 && (ws_connect_handler(conn, cbData) != 0)) {
14152#if defined(USE_LUA)
14161 if (lua_websock > 0) {
14163 conn->lua_websocket_state = lua_websocket_new(
path, conn);
14164 if (!conn->lua_websocket_state) {
14173 if (!is_callback_resource && !lua_websock) {
14183 if (!send_websocket_handshake(conn, websock_key)) {
14189 if (is_callback_resource) {
14190 if (ws_ready_handler != NULL) {
14191 ws_ready_handler(conn, cbData);
14193#if defined(USE_LUA)
14194 }
else if (lua_websock) {
14195 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
14203 if (is_callback_resource) {
14204 read_websocket(conn, ws_data_handler, cbData);
14205#if defined(USE_LUA)
14206 }
else if (lua_websock) {
14207 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
14211#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
14213 if (conn->websocket_deflate_initialized) {
14214 deflateEnd(&conn->websocket_deflate_state);
14215 inflateEnd(&conn->websocket_inflate_state);
14220 if (ws_close_handler) {
14221 ws_close_handler(conn, cbData);
14236 const char *connection_headers[8];
14237 const char *upgrade_to;
14238 int connection_header_count, i, should_upgrade;
14250 connection_headers,
14252 should_upgrade = 0;
14253 for (i = 0; i < connection_header_count; i++) {
14254 if (0 !=
mg_strcasestr(connection_headers[i],
"upgrade")) {
14255 should_upgrade = 1;
14258 if (!should_upgrade) {
14263 if (upgrade_to == NULL) {
14298 if (sscanf(
vec->
ptr,
"%u.%u.%u.%u%n", &
a, &
b, &
c, &
d, &
n)
14306 if ((
n > 0) && ((
size_t)
n ==
vec->
len)) {
14307 if ((
a < 256) && (
b < 256) && (
c < 256) && (
d < 256) && (
slash < 33)) {
14309 if (sa->
sa.sa_family == AF_INET) {
14310 uint32_t ip = ntohl(sa->
sin.sin_addr.s_addr);
14311 uint32_t net = ((uint32_t)
a << 24) | ((uint32_t)
b << 16)
14312 | ((uint32_t)
c << 8) | (uint32_t)
d;
14314 return (ip &
mask) == net;
14319#if defined(USE_IPV6)
14324 if (sscanf(
vec->
ptr,
"[%49[^]]]/%u%n", ad, &
slash, &
n) != 2) {
14326 if (sscanf(
vec->
ptr,
"[%49[^]]]%n", ad, &
n) != 1) {
14331 if ((
n <= 0) && no_strict) {
14333 p = strchr(
vec->
ptr,
'/');
14335 if (((
size_t)(p -
vec->
ptr) <
sizeof(ad))
14336 && (sscanf(p,
"/%u%n", &
slash, &
n) == 1)) {
14342 }
else if (
vec->
len <
sizeof(ad)) {
14353 while (isxdigit((
unsigned char)*p) || (*p ==
'.') || (*p ==
':')) {
14354 if (*(p++) ==
':') {
14358 if ((*p ==
'\0') && (
c >= 2)) {
14359 struct sockaddr_in6 sin6;
14363 if (sa->
sa.sa_family != AF_INET6) {
14366 if (
mg_inet_pton(AF_INET6, ad, &sin6,
sizeof(sin6), 0)) {
14368 for (i = 0; i < 16; i++) {
14369 uint8_t ip = sa->sin6.sin6_addr.s6_addr[i];
14370 uint8_t net = sin6.sin6_addr.s6_addr[i];
14373 if (8 * i + 8 <
slash) {
14375 }
else if (8 * i <
slash) {
14376 mask = (uint8_t)(0xFFu << (8 * i + 8 -
slash));
14378 if ((ip &
mask) != net) {
14406 if ((val.
ptr == NULL)
14407 || (sscanf(val.
ptr,
"%lf%c", &
v, &mult)
14413 && (mult !=
','))) {
14418 : ((
lowercase(&mult) ==
'm') ? 1048576 : 1);
14423 if (matched >= 0) {
14460 const char *host_header =
14466 if (host_header != NULL) {
14471 if (*host_header ==
'[') {
14472 pos = strchr(host_header,
']');
14475 DEBUG_TRACE(
"%s",
"Host name format error '[' without ']'");
14479 host->
ptr = host_header;
14480 host->
len = (size_t)(pos + 1 - host_header);
14483 pos = strchr(host_header,
':');
14485 host->
len = (size_t)(pos - host_header);
14487 host->
len = strlen(host_header);
14489 host->
ptr = host_header;
14509 if ((strlen(sslhost) != host.
len)
14512 DEBUG_TRACE(
"Host mismatch: SNI: %s, HTTPS: %.*s",
14524 size_t domNameLen = strlen(domName);
14525 if ((domNameLen == host.
len)
14543 conn->
ssl ?
"S" :
"",
14561 const char *expect_proto =
14565 int redirect_code = 308;
14572 conn, target_url,
sizeof(target_url), expect_proto, port, NULL)
14576 size_t slen1 = strlen(target_url);
14578 if ((slen1 + slen2 + 2) <
sizeof(target_url)) {
14579 target_url[slen1] =
'?';
14580 memcpy(target_url + slen1 + 1,
14583 target_url[slen1 + slen2 + 1] = 0;
14606 int is_delete_request,
14617 size_t urilen = strlen(
uri);
14648 if (!is_delete_request && (
handler == NULL)) {
14675 if (!phys_ctx || !dom_ctx) {
14685 for (tmp_rh = dom_ctx->
handlers; tmp_rh != NULL;
14686 tmp_rh = tmp_rh->
next) {
14688 && (urilen == tmp_rh->
uri_len) && !strcmp(tmp_rh->
uri,
uri)) {
14689 if (!is_delete_request) {
14726 *lastref = tmp_rh->
next;
14733 lastref = &(tmp_rh->
next);
14735 }
while (tmp_rh != NULL);
14737 if (is_delete_request) {
14748 if (tmp_rh == NULL) {
14752 "Cannot create new request handler struct, OOM");
14756 if (!tmp_rh->
uri) {
14761 "Cannot create new request handler struct, OOM");
14780 tmp_rh->
next = NULL;
14895 if (request_info) {
14896 const char *uri = request_info->
local_uri;
14897 size_t urilen = strlen(uri);
14907 for (step = 0; step < 3; step++) {
14909 tmp_rh = tmp_rh->
next) {
14915 matched = (tmp_rh->
uri_len == urilen)
14916 && (strcmp(tmp_rh->
uri,
uri) == 0);
14917 }
else if (step == 1) {
14945 *handler_info = tmp_rh;
14977#if defined(USE_WEBSOCKET) && defined(MG_EXPERIMENTAL_INTERFACES)
14979experimental_websocket_client_data_wrapper(
struct mg_connection *conn,
14986 if (pcallbacks->websocket_data) {
14987 return pcallbacks->websocket_data(conn, bits,
data,
len);
14995experimental_websocket_client_close_wrapper(
const struct mg_connection *conn,
15012 if (handler_info != NULL) {
15030 int uri_len, ssl_index;
15031 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
15032 is_put_or_delete_request = 0, is_callback_resource = 0,
15033 is_template_text_file = 0, is_webdav_request = 0;
15043 void *callback_data = NULL;
15045 void *auth_callback_data = NULL;
15047 time_t curtime = time(NULL);
15066 if (ssl_index >= 0) {
15076 "Error: SSL forward not configured properly");
15079 "Can not redirect to SSL, no SSL port available");
15133 DEBUG_TRACE(
"%s",
"begin_request handled request");
15135 }
else if (i == 0) {
15139 DEBUG_TRACE(
"%s",
"done (undocumented behavior)");
15154 const char *cors_meth_cfg =
15156 const char *cors_orig_cfg =
15158 const char *cors_origin =
15162 "Access-Control-Request-Method");
15167 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
15168 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
15169 && (cors_origin != NULL) && (cors_acrm != NULL)) {
15172 const char *cors_acrh =
15175 "Access-Control-Request-Headers");
15176 const char *cors_cred_cfg =
15178 const char *cors_exphdr_cfg =
15183 "HTTP/1.1 200 OK\r\n"
15185 "Access-Control-Allow-Origin: %s\r\n"
15186 "Access-Control-Allow-Methods: %s\r\n"
15187 "Content-Length: 0\r\n"
15188 "Connection: %s\r\n",
15191 ((cors_meth_cfg[0] ==
'*') ? cors_acrm : cors_meth_cfg),
15194 if (cors_cred_cfg && *cors_cred_cfg) {
15196 "Access-Control-Allow-Credentials: %s\r\n",
15200 if (cors_exphdr_cfg && *cors_exphdr_cfg) {
15202 "Access-Control-Expose-Headers: %s\r\n",
15206 if (cors_acrh || (cors_cred_cfg && *cors_cred_cfg)) {
15208 const char *cors_hdr_cfg =
15211 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
15218 "Access-Control-Allow-Headers: %s\r\n",
15219 ((cors_hdr_cfg[0] ==
'*') ? cors_acrh
15223 mg_printf(conn,
"Access-Control-Max-Age: 60\r\n");
15236#if defined(USE_WEBSOCKET)
15242 if (is_websocket_request) {
15251 &ws_connect_handler,
15261 is_callback_resource = 1;
15262 is_script_resource = 1;
15266 is_webdav_request = 0;
15268 no_callback_resource:
15273 is_callback_resource = 0;
15279 &is_script_resource,
15280 &is_websocket_request,
15281 &is_put_or_delete_request,
15282 &is_webdav_request,
15283 &is_template_text_file);
15287 if (is_webdav_request) {
15290 if (webdav_enable[0] !=
'y') {
15293 "%s method not allowed",
15311 &auth_callback_data,
15313 if (!auth_handler(conn, auth_callback_data)) {
15317 DEBUG_TRACE(
"%s",
"auth handler rejected request");
15320 }
else if (is_put_or_delete_request && !is_script_resource
15321 && !is_callback_resource) {
15325#if defined(NO_FILES)
15338 "%s method not allowed",
15340 DEBUG_TRACE(
"%s",
"all file based put/delete requests rejected");
15344#if !defined(NO_FILES)
15350 DEBUG_TRACE(
"%s",
"file write needs authorization");
15364 DEBUG_TRACE(
"%s",
"access authorization required");
15372 if (is_callback_resource) {
15374 if (!is_websocket_request) {
15375 i = callback_handler(conn, callback_data);
15406 callback_handler = NULL;
15417 goto no_callback_resource;
15420#if defined(USE_WEBSOCKET)
15421 handle_websocket_request(conn,
15423 is_callback_resource,
15425 ws_connect_handler,
15437#if defined(USE_WEBSOCKET)
15438 if (is_websocket_request) {
15440 if (is_script_resource) {
15444 handle_websocket_request(conn,
15465#if defined(NO_FILES)
15481 if (is_script_resource) {
15492 if (is_put_or_delete_request) {
15562 "%s method not allowed",
15574 DEBUG_TRACE(
"handling %s request to %s: file not found",
15582 && (ri->
local_uri[uri_len - 1] !=
'/')) {
15596 strcat(new_path,
"/");
15599 strcat(new_path,
"?");
15605 DEBUG_TRACE(
"%s request to %s: directory redirection sent",
15634 "%s method not allowed",
15652 "Error: Directory listing denied");
15659 if (is_template_text_file) {
15662 DEBUG_TRACE(
"handling %s request to %s done (template)",
15669#if !defined(NO_CACHING)
15673 DEBUG_TRACE(
"handling %s request to %s done (not modified)",
15682 DEBUG_TRACE(
"handling %s request to %s done (static)",
15690#if !defined(NO_FILESYSTEMS)
15696#if !defined(NO_CGI)
15697 int cgi_config_idx, inc, max;
15700 if (!conn || !conn->
dom_ctx) {
15704#if defined(USE_LUA)
15711 handle_lsp_request(conn, path, file, NULL);
15724 mg_exec_lua_script(conn, path, NULL);
15733#if defined(USE_DUKTAPE)
15739 mg_exec_duktape_script(conn, path);
15748#if !defined(NO_CGI)
15751 for (cgi_config_idx = 0; cgi_config_idx < max; cgi_config_idx += inc) {
15780#if !defined(NO_CACHING)
15803#if defined(USE_X_DOM_SOCKET)
15841 unsigned int a,
b,
c,
d;
15843 unsigned long portUL;
15847#if defined(USE_IPV6)
15848 char buf[100] = {0};
15854 memset(
so, 0,
sizeof(*
so));
15855 so->lsa.sin.sin_family = AF_INET;
15864 "%u.%u.%u.%u:%u%n",
15875 so->lsa.sin.sin_addr.s_addr =
15876 htonl((
a << 24) | (
b << 16) | (
c << 8) |
d);
15877 so->lsa.sin.sin_port = htons((uint16_t)port);
15880#if defined(USE_IPV6)
15881 }
else if (sscanf(
vec->
ptr,
"[%49[^]]]:%u%n", buf, &port, &
len) == 2
15884 AF_INET6, buf, &
so->lsa.sin6,
sizeof(
so->lsa.sin6), 0)) {
15888 so->lsa.sin6.sin6_port = htons((uint16_t)port);
15892 }
else if ((
vec->
ptr[0] ==
'+')
15893 && (sscanf(
vec->
ptr + 1,
"%u%n", &port, &
len)
15903#if defined(USE_IPV6)
15905 so->lsa.sin6.sin6_family = AF_INET6;
15906 so->lsa.sin6.sin6_port = htons((uint16_t)port);
15907 *ip_version = 4 + 6;
15910 so->lsa.sin.sin_port = htons((uint16_t)port);
15915 && (
vec->
ptr != endptr)) {
15917 port = (uint16_t)portUL;
15919 so->lsa.sin.sin_port = htons((uint16_t)port);
15922 }
else if ((cb = strchr(
vec->
ptr,
':')) != NULL) {
15932 char hostname[256];
15933 size_t hostnlen = (size_t)(cb -
vec->
ptr);
15935 if ((hostnlen >=
vec->
len) || (hostnlen >=
sizeof(hostname))) {
15944 AF_INET, hostname, &
so->lsa.sin,
sizeof(
so->lsa.sin), 1)) {
15945 if (sscanf(cb + 1,
"%u%n", &port, &
len)
15951 so->lsa.sin.sin_port = htons((uint16_t)port);
15952 len += (
int)(hostnlen + 1);
15956#if defined(USE_IPV6)
15960 sizeof(
so->lsa.sin6),
15962 if (sscanf(cb + 1,
"%u%n", &port, &
len) == 1) {
15964 so->lsa.sin6.sin6_port = htons((uint16_t)port);
15965 len += (
int)(hostnlen + 1);
15974#if defined(USE_X_DOM_SOCKET)
15976 }
else if (
vec->
ptr[0] ==
'x') {
15978 if (
vec->
len <
sizeof(
so->lsa.sun.sun_path)) {
15980 so->lsa.sun.sun_family = AF_UNIX;
15981 memset(
so->lsa.sun.sun_path, 0,
sizeof(
so->lsa.sun.sun_path));
15982 memcpy(
so->lsa.sun.sun_path, (
char *)
vec->
ptr + 1,
vec->
len - 1);
16000 int bad_suffix = 0;
16005 unsigned char *opt = NULL;
16008 opt = &
so->is_optional;
16011 opt = &
so->ssl_redir;
16020 if ((opt) && (*opt == 0))
16028 if ((bad_suffix == 0) && ((
so->is_ssl == 0) || (
so->ssl_redir == 0))) {
16079 int portslen = (
int)strlen(ports);
16080 char prevIsNumber = 0;
16082 for (i = 0; i < portslen; i++) {
16083 if (prevIsNumber) {
16084 int suffixCharIdx = (ports[i] ==
'o')
16087 if (ports[suffixCharIdx] ==
's'
16088 || ports[suffixCharIdx] ==
'r') {
16092 if (ports[i] >=
'0' && ports[i] <=
'9') {
16108#if defined(USE_IPV6)
16119 int portsTotal = 0;
16122 const char *opt_txt;
16123 long opt_listen_backlog;
16129 memset(&
so, 0,
sizeof(
so));
16130 memset(&
usa, 0,
sizeof(
usa));
16141 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
16145 "[IP_ADDRESS:]PORT[s|r]");
16149#if !defined(NO_SSL)
16153 "Cannot add SSL socket (entry %i)",
16165 (ip_version == 99) ? ( 0) : ( 6)))
16169 "cannot create socket (entry %i)",
16171 if (
so.is_optional) {
16188 if (setsockopt(
so.sock,
16190 SO_EXCLUSIVEADDRUSE,
16198 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
16202 if (setsockopt(
so.sock,
16212 "cannot set socket option SO_REUSEADDR (entry %i)",
16217#if defined(USE_X_DOM_SOCKET)
16218 if (ip_version == 99) {
16223 if (ip_version > 4) {
16225#if defined(USE_IPV6)
16226 if (ip_version > 6) {
16227 if (
so.lsa.sa.sa_family == AF_INET6
16228 && setsockopt(
so.sock,
16237 "cannot set socket option "
16238 "IPV6_V6ONLY=off (entry %i)",
16242 if (
so.lsa.sa.sa_family == AF_INET6
16243 && setsockopt(
so.sock,
16252 "cannot set socket option "
16253 "IPV6_V6ONLY=on (entry %i)",
16260 if (
so.is_optional) {
16269 if (
so.lsa.sa.sa_family == AF_INET) {
16271 len =
sizeof(
so.lsa.sin);
16272 if (bind(
so.sock, &
so.lsa.sa,
len) != 0) {
16274 "cannot bind to %.*s: %d (%s)",
16281 if (
so.is_optional) {
16288#if defined(USE_IPV6)
16289 else if (
so.lsa.sa.sa_family == AF_INET6) {
16291 len =
sizeof(
so.lsa.sin6);
16292 if (bind(
so.sock, &
so.lsa.sa,
len) != 0) {
16294 "cannot bind to IPv6 %.*s: %d (%s)",
16301 if (
so.is_optional) {
16309#if defined(USE_X_DOM_SOCKET)
16310 else if (
so.lsa.sa.sa_family == AF_UNIX) {
16312 len =
sizeof(
so.lsa.sun);
16313 if (bind(
so.sock, &
so.lsa.sa,
len) != 0) {
16315 "cannot bind to unix socket %s: %d (%s)",
16316 so.lsa.sun.sun_path,
16321 if (
so.is_optional) {
16332 "cannot bind: address family not supported (entry %i)",
16340 opt_listen_backlog = strtol(opt_txt, NULL, 10);
16341 if ((opt_listen_backlog > INT_MAX) || (opt_listen_backlog < 1)) {
16343 "%s value \"%s\" is invalid",
16351 if (listen(
so.sock, (
int)opt_listen_backlog) != 0) {
16354 "cannot listen to %.*s: %d (%s)",
16364 if ((getsockname(
so.sock, &(
usa.
sa), &
len) != 0)
16365 || (
usa.
sa.sa_family !=
so.lsa.sa.sa_family)) {
16369 "call to getsockname failed %.*s: %d (%s)",
16380#if defined(USE_IPV6)
16381 if (
so.lsa.sa.sa_family == AF_INET6) {
16382 so.lsa.sin6.sin6_port =
usa.sin6.sin6_port;
16386 so.lsa.sin.sin_port =
usa.
sin.sin_port;
16389 if ((ptr = (
struct socket *)
16429 if (portsOk != portsTotal) {
16441 const char *header_value;
16443 if ((header_value =
mg_get_header(conn, header)) == NULL) {
16446 return header_value;
16451#if defined(MG_EXTERNAL_FUNCTION_log_access)
16452#include "external_log_access.inl"
16453#elif !defined(NO_FILESYSTEMS)
16461#if defined(REENTRANT_TIME)
16463 struct tm *tm = &_tm;
16468 const char *referer;
16469 const char *user_agent;
16471 char log_buf[4096];
16473 if (!conn || !conn->
dom_ctx) {
16480#if defined(USE_LUA)
16481 if (conn->
phys_ctx->lua_bg_log_available) {
16484 lua_State *lstate = (lua_State *)ctx->lua_background_state;
16485 pthread_mutex_lock(&ctx->lua_bg_mutex);
16487 lua_getglobal(lstate,
"log");
16488 prepare_lua_request_info_inner(conn, lstate);
16489 push_lua_response_log_data(conn, lstate);
16491 ret = lua_pcall(lstate, 2, 1, 0);
16493 int t = lua_type(lstate, -1);
16494 if (t == LUA_TBOOLEAN) {
16495 if (lua_toboolean(lstate, -1) == 0) {
16497 pthread_mutex_unlock(&ctx->lua_bg_mutex);
16501 }
else if (t == LUA_TSTRING) {
16503 const char *txt = lua_tolstring(lstate, -1, &
len);
16504 if ((
len == 0) || (*txt == 0)) {
16506 pthread_mutex_unlock(&ctx->lua_bg_mutex);
16510 if (
len >=
sizeof(log_buf)) {
16511 len =
sizeof(log_buf) - 1;
16513 memcpy(log_buf, txt,
len);
16517 lua_cry(conn,
ret, lstate,
"lua_background_script",
"log");
16519 pthread_mutex_unlock(&ctx->lua_bg_mutex);
16544#if defined(REENTRANT_TIME)
16550 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z", tm);
16552 mg_strlcpy(date,
"01/Jan/1970:00:00:00 +0000",
sizeof(date));
16559 user_agent =
header_val(conn,
"User-Agent");
16565 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT
16596 if (fprintf(fi.
access.
fp,
"%s\n", log_buf) < 1) {
16608 "Error writing log file %s",
16614#error "Either enable filesystems or provide a custom log_access implementation"
16624 int allowed, flag, matched;
16631 allowed = (list == NULL) ?
'+' :
'-';
16636 if ((
vec.
len > 0) && ((flag ==
'+') || (flag ==
'-'))) {
16643 "%s: subnet must be [+|-]IP-addr[/x]",
16652 return allowed ==
'+';
16658#if !defined(_WIN32) && !defined(__ZEPHYR__)
16666 const uid_t curr_uid = getuid();
16669 const struct passwd *to_pw = NULL;
16671 if ((run_as_user != NULL) && (to_pw = getpwnam(run_as_user)) == NULL) {
16675 "%s: unknown user [%s]",
16678 }
else if ((run_as_user == NULL) || (curr_uid == to_pw->
pw_uid)) {
16685 if (setgid(to_pw->
pw_gid) == -1) {
16687 "%s: setgid(%s): %s",
16691 }
else if (setgroups(0, NULL) == -1) {
16693 "%s: setgroups(): %s",
16696 }
else if (setuid(to_pw->
pw_uid) == -1) {
16698 "%s: setuid(%s): %s",
16725 pthread_setspecific(
sTlsKey, NULL);
16729#if defined(USE_MBEDTLS)
16740 dom_ctx = &(phys_ctx->
dd);
16749 if (dom_ctx->
ssl_ctx == NULL) {
16750 fprintf(stderr,
"ssl_ctx malloc failed\n");
16760#elif defined(USE_GNUTLS)
16771 dom_ctx = &(phys_ctx->
dd);
16780 if (dom_ctx->
ssl_ctx == NULL) {
16781 fprintf(stderr,
"ssl_ctx malloc failed\n");
16791#elif !defined(NO_SSL)
16796 const char *chain);
16803 struct stat cert_buf;
16807 int should_verify_peer;
16815 if (chain == NULL) {
16823 if (stat(pem, &cert_buf) != -1) {
16824 t = (int64_t)cert_buf.st_mtime;
16831 should_verify_peer = 0;
16835 should_verify_peer = 1;
16839 should_verify_peer = 1;
16843 if (should_verify_peer) {
16853 "SSL_CTX_load_verify_locations error: %s "
16854 "ssl_verify_peer requires setting "
16855 "either ssl_ca_path or ssl_ca_file. Is any of them "
16873#if defined(OPENSSL_API_1_1)
16880 int (*func)(
SSL *),
16885 unsigned timeout = 1024;
16906 if (conn->
ssl == NULL) {
16908 OPENSSL_REMOVE_THREAD_STATE();
16911 SSL_set_app_data(conn->
ssl, (
char *)conn);
16913 ret = SSL_set_fd(conn->ssl, conn->client.sock);
16916 SSL_free(conn->ssl);
16918 OPENSSL_REMOVE_THREAD_STATE();
16922 if (client_options) {
16924 SSL_set_tlsext_host_name(conn->ssl, client_options->
host_name);
16934 timeout = (unsigned)to;
16941 for (i = 0; i <= timeout; i += 50) {
16944 ret = func(conn->ssl);
16946 err = SSL_get_error(conn->ssl,
ret);
16964 unsigned int num_sock = 1;
16965 pfd[0].fd = conn->client.sock;
16973 conn->phys_ctx->thread_shutdown_notification_socket;
16974 pfd[num_sock].events = POLLIN;
16981 &(conn->phys_ctx->stop_flag));
17008 SSL_free(conn->ssl);
17010 OPENSSL_REMOVE_THREAD_STATE();
17023 err = ERR_get_error();
17024 return ((
err == 0) ?
"" : ERR_error_string(
err, NULL));
17032 const char hexdigit[] =
"0123456789abcdef";
17034 if ((memlen <= 0) || (buflen <= 0)) {
17037 if (buflen < (3 * memlen)) {
17041 for (i = 0; i < memlen; i++) {
17043 buf[3 * i - 1] =
' ';
17045 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
17046 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
17048 buf[3 * memlen - 1] = 0;
17058 X509 *cert = SSL_get_peer_certificate(conn->
ssl);
17060 char str_buf[1024];
17061 unsigned char buf[256];
17062 char *str_serial = NULL;
17065 unsigned char *tmp_buf;
17066 unsigned char *tmp_p;
17069 const EVP_MD *digest = EVP_get_digestbyname(
"sha1");
17072 X509_NAME *subj = X509_get_subject_name(cert);
17073 X509_NAME *iss = X509_get_issuer_name(cert);
17079 BIGNUM *serial_bn = ASN1_INTEGER_to_BN(serial, NULL);
17081 str_serial = BN_bn2hex(serial_bn);
17082 BN_free(serial_bn);
17088 (void)X509_NAME_oneline(subj, str_buf, (
int)
sizeof(str_buf));
17090 (void)X509_NAME_oneline(iss, str_buf, (
int)
sizeof(str_buf));
17098 ilen = i2d_X509(cert, NULL);
17099 tmp_buf = (ilen > 0)
17105 (void)i2d_X509(cert, &tmp_p);
17107 tmp_buf, (
unsigned)ilen, buf, &ulen, digest, NULL)) {
17113 if (!
hexdump2string(buf, (
int)ulen, str_buf, (
int)
sizeof(str_buf))) {
17122 OPENSSL_free(str_serial);
17129#if defined(OPENSSL_API_1_1)
17139 (void)pthread_mutex_lock(&
ssl_mutexes[mutex_num]);
17141 (void)pthread_mutex_unlock(&
ssl_mutexes[mutex_num]);
17147#if !defined(NO_SSL_DL)
17152 const char *dll_name,
17154 int *feature_missing)
17165 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
17170 "%s: cannot load %s",
17177 for (fp = sw; fp->
name != NULL; fp++) {
17180 u.fp = (void (*)(void))dlsym(dll_handle, fp->
name);
17185 u.p = dlsym(dll_handle, fp->
name);
17191 if (u.fp == NULL) {
17193 if (feature_missing) {
17205 "%s: %s: cannot find %s",
17213 size_t cur_len = strlen(ebuf);
17214 if (!truncated && ((ebuf_len - cur_len) > 3)) {
17218 ebuf_len - cur_len - 3,
17223 strcat(ebuf,
"...");
17232 (void)dlclose(dll_handle);
17246#if defined(SSL_ALREADY_INITIALIZED)
17258#if !defined(OPENSSL_API_1_1) && !defined(OPENSSL_API_3_0)
17263 if (ebuf_len > 0) {
17267#if !defined(NO_SSL_DL)
17277 "%s: error loading library %s",
17290#if !defined(OPENSSL_API_1_1) && !defined(OPENSSL_API_3_0)
17294 num_locks = CRYPTO_num_locks();
17295 if (num_locks < 0) {
17298 size =
sizeof(pthread_mutex_t) * ((
size_t)(num_locks));
17301 if (num_locks == 0) {
17314 "%s: cannot allocate mutexes: %s",
17322 for (i = 0; i < num_locks; i++) {
17328 "%s: error initializing mutex %i of %i",
17343#if !defined(NO_SSL_DL)
17348#if !defined(OPENSSL_API_1_1)
17357#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
17358 && !defined(NO_SSL_DL)
17360 OPENSSL_init_ssl(0, NULL);
17366 SSL_library_init();
17367 SSL_load_error_strings();
17380 if (SSL_CTX_use_certificate_file(dom_ctx->
ssl_ctx, pem, 1) == 0) {
17382 "%s: cannot open certificate file %s: %s",
17390 if (SSL_CTX_use_PrivateKey_file(dom_ctx->
ssl_ctx, pem, 1) == 0) {
17392 "%s: cannot open private key file %s: %s",
17399 if (SSL_CTX_check_private_key(dom_ctx->
ssl_ctx) == 0) {
17401 "%s: certificate and private key do not match: %s",
17416 if (SSL_CTX_use_certificate_chain_file(dom_ctx->
ssl_ctx, chain) == 0) {
17418 "%s: cannot use certificate chain file %s: %s",
17429#if defined(OPENSSL_API_1_1)
17430static unsigned long
17434 if (version_id > 0)
17436 if (version_id > 1)
17438 if (version_id > 2)
17440 if (version_id > 3)
17442 if (version_id > 4)
17444#if defined(SSL_OP_NO_TLSv1_3)
17445 if (version_id > 5)
17455 if (version_id > 0)
17457 if (version_id > 1)
17459 if (version_id > 2)
17461 if (version_id > 3)
17463 if (version_id > 4)
17465#if defined(SSL_OP_NO_TLSv1_3)
17466 if (version_id > 5)
17490 SSL_get_app_data(ssl);
17503#if defined(GCC_DIAGNOSTIC)
17504#pragma GCC diagnostic push
17505#pragma GCC diagnostic ignored "-Wcast-align"
17511#if defined(GCC_DIAGNOSTIC)
17512#pragma GCC diagnostic pop
17520 if ((conn == NULL) || (conn->
phys_ctx == NULL)) {
17532 if ((servername == NULL) || (*servername == 0)) {
17533 DEBUG_TRACE(
"%s",
"SSL connection not supporting SNI");
17540 DEBUG_TRACE(
"TLS connection to host %s", servername);
17568#if defined(USE_ALPN)
17569static const char alpn_proto_list[] =
"\x02h2\x08http/1.1\x08http/1.0";
17570static const char *alpn_proto_order_http1[] = {alpn_proto_list + 3,
17571 alpn_proto_list + 3 + 8,
17573#if defined(USE_HTTP2)
17574static const char *alpn_proto_order_http2[] = {alpn_proto_list,
17575 alpn_proto_list + 3,
17576 alpn_proto_list + 3 + 8,
17582 const unsigned char **out,
17583 unsigned char *outlen,
17584 const unsigned char *in,
17585 unsigned int inlen,
17589 unsigned int i, j, enable_http2 = 0;
17590 const char **alpn_proto_order = alpn_proto_order_http1;
17603#if defined(USE_HTTP2)
17604 enable_http2 = (0 == strcmp(dom_ctx->
config[ENABLE_HTTP2],
"yes"));
17605 if (enable_http2) {
17606 alpn_proto_order = alpn_proto_order_http2;
17610 for (j = 0; alpn_proto_order[j] != NULL; j++) {
17612 const char *
alpn_proto = alpn_proto_order[j];
17614 for (i = 0; i < inlen; i++) {
17630next_protos_advertised_cb(
SSL *ssl,
17631 const unsigned char **
data,
17636 *
data = (
const unsigned char *)alpn_proto_list;
17637 *
len = (
unsigned int)strlen((
const char *)
data);
17649 unsigned int alpn_len = (
unsigned int)strlen((
char *)alpn_proto_list);
17650 int ret = SSL_CTX_set_alpn_protos(dom_ctx->
ssl_ctx,
17651 (
const unsigned char *)alpn_proto_list,
17655 "SSL_CTX_set_alpn_protos error: %s",
17659 SSL_CTX_set_alpn_select_cb(dom_ctx->
ssl_ctx,
17663 SSL_CTX_set_next_protos_advertised_cb(dom_ctx->
ssl_ctx,
17664 next_protos_advertised_cb,
17680 int should_verify_peer;
17681 int peer_certificate_optional;
17682 const char *ca_path;
17683 const char *ca_file;
17684 int use_default_verify_paths;
17686 struct timespec now_mt;
17690 int ssl_cache_timeout;
17692#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
17693 && !defined(NO_SSL_DL)
17694 if ((dom_ctx->
ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
17696 "SSL_CTX_new (server) error: %s",
17701 if ((dom_ctx->
ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
17703 "SSL_CTX_new (server) error: %s",
17709#if defined(SSL_OP_NO_TLSv1_3)
17710 SSL_CTX_clear_options(dom_ctx->
ssl_ctx,
17715 SSL_CTX_clear_options(dom_ctx->
ssl_ctx,
17724 SSL_CTX_set_options(dom_ctx->
ssl_ctx,
17728#if defined(SSL_OP_NO_RENEGOTIATION)
17732#if !defined(NO_SSL_DL)
17733 SSL_CTX_set_ecdh_auto(dom_ctx->
ssl_ctx, 1);
17751 SSL_CTX_set_tlsext_servername_callback(dom_ctx->
ssl_ctx,
17763 if (callback_ret < 0) {
17765 "SSL callback returned error: %i",
17769 if (callback_ret > 0) {
17785 if (callback_ret < 0) {
17787 "Domain SSL callback returned error: %i",
17791 if (callback_ret > 0) {
17799 clock_gettime(CLOCK_MONOTONIC, &now_mt);
17811 SSL_CTX_set_session_id_context(dom_ctx->
ssl_ctx,
17812 (
unsigned char *)ssl_context_id,
17813 sizeof(ssl_context_id));
17823 should_verify_peer = 0;
17824 peer_certificate_optional = 0;
17828 should_verify_peer = 1;
17833 should_verify_peer = 1;
17834 peer_certificate_optional = 1;
17838 use_default_verify_paths =
17843 if (should_verify_peer) {
17846 if (SSL_CTX_load_verify_locations(dom_ctx->
ssl_ctx, ca_file, ca_path)
17849 "SSL_CTX_load_verify_locations error: %s "
17850 "ssl_verify_peer requires setting "
17851 "either ssl_ca_path or ssl_ca_file. "
17852 "Is any of them present in the "
17858 if (peer_certificate_optional) {
17861 SSL_CTX_set_verify(dom_ctx->
ssl_ctx,
17867 if (use_default_verify_paths
17868 && (SSL_CTX_set_default_verify_paths(dom_ctx->
ssl_ctx) != 1)) {
17870 "SSL_CTX_set_default_verify_paths error: %s",
17877 SSL_CTX_set_verify_depth(dom_ctx->
ssl_ctx, verify_depth);
17882 if (SSL_CTX_set_cipher_list(dom_ctx->
ssl_ctx,
17886 "SSL_CTX_set_cipher_list error: %s",
17895 if (ssl_cache_timeout > 0) {
17899 SSL_CTX_set_timeout(dom_ctx->
ssl_ctx, (
long)ssl_cache_timeout);
17902#if defined(USE_ALPN)
17904#if !defined(NO_SSL_DL)
17908 init_alpn(phys_ctx, dom_ctx);
17933 dom_ctx = &(phys_ctx->
dd);
17948 if (callback_ret < 0) {
17951 "external_ssl_ctx callback returned error: %i",
17954 }
else if (callback_ret > 0) {
17975 if (callback_ret < 0) {
17979 "external_ssl_ctx_domain callback returned error: %i",
17982 }
else if (callback_ret > 0) {
18003 "Initializing SSL failed: -%s is not set",
18010 if (chain == NULL) {
18014 if ((chain != NULL) && (*chain == 0)) {
18031#if defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)
18039 CONF_modules_unload(1);
18049 CRYPTO_set_locking_callback(NULL);
18050 CRYPTO_set_id_callback(NULL);
18052 CONF_modules_unload(1);
18053 ERR_free_strings();
18055 CRYPTO_cleanup_all_ex_data();
18056 OPENSSL_REMOVE_THREAD_STATE();
18058 for (i = 0; i < CRYPTO_num_locks(); i++) {
18069#if !defined(NO_FILESYSTEMS)
18084 "Cannot open %s: %s",
18100 memset(&
sa, 0,
sizeof(
sa));
18101#if defined(USE_IPV6)
18102 sa.sin6.sin6_family = AF_INET6;
18104 sa.sin.sin_family = AF_INET;
18146#if defined(USE_SERVER_STATS)
18147 conn->processing_time = 0;
18155 if ((
so->lsa.sa.sa_family == AF_INET)
18156 || (
so->lsa.sa.sa_family == AF_INET6)) {
18158 if (setsockopt(
so->sock,
18162 sizeof(nodelay_on))
18173#if !defined(__ZEPHYR__)
18181 struct linger linger;
18182 int error_code = 0;
18183 int linger_timeout = -2;
18184 socklen_t opt_len =
sizeof(error_code);
18206 n =
pull_inner(NULL, conn, buf,
sizeof(buf), 1.0);
18215 if (linger_timeout >= 0) {
18218 linger.l_onoff = 1;
18220#if defined(_MSC_VER)
18221#pragma warning(push)
18222#pragma warning(disable : 4244)
18224#if defined(GCC_DIAGNOSTIC)
18225#pragma GCC diagnostic push
18226#pragma GCC diagnostic ignored "-Wconversion"
18232 linger.l_linger = (linger_timeout + 999) / 1000;
18234#if defined(GCC_DIAGNOSTIC)
18235#pragma GCC diagnostic pop
18237#if defined(_MSC_VER)
18238#pragma warning(pop)
18242 linger.l_onoff = 0;
18243 linger.l_linger = 0;
18246 if (linger_timeout < -1) {
18252 (
char *)&error_code,
18262 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
18266 }
else if (error_code == WSAECONNRESET) {
18268 }
else if (error_code == ECONNRESET) {
18283 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
18301#if defined(USE_SERVER_STATS)
18302 conn->conn_state = 6;
18305#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18306 if (conn->lua_websocket_state) {
18307 lua_websocket_close(conn, conn->lua_websocket_state);
18308 conn->lua_websocket_state = NULL;
18329#if defined(USE_SERVER_STATS)
18330 conn->conn_state = 7;
18333#if defined(USE_MBEDTLS)
18334 if (conn->
ssl != NULL) {
18335 mbed_ssl_close(conn->
ssl);
18338#elif defined(USE_GNUTLS)
18339 if (conn->
ssl != NULL) {
18340 gtls_ssl_close(conn->
ssl);
18343#elif !defined(NO_SSL)
18344 if (conn->
ssl != NULL) {
18347 SSL_shutdown(conn->
ssl);
18348 SSL_free(conn->
ssl);
18349 OPENSSL_REMOVE_THREAD_STATE();
18354#if defined(__ZEPHYR__)
18371#if defined(USE_SERVER_STATS)
18372 conn->conn_state = 8;
18380 if ((conn == NULL) || (conn->
phys_ctx == NULL)) {
18384#if defined(USE_WEBSOCKET)
18386 if (conn->in_websocket_handling) {
18414#if !defined(NO_SSL) && !defined(USE_MBEDTLS) \
18415 && !defined(USE_GNUTLS)
18423#if defined(USE_WEBSOCKET)
18426 (void)pthread_mutex_destroy(&conn->
mutex);
18429 (void)pthread_mutex_destroy(&conn->
mutex);
18434 (void)pthread_mutex_destroy(&conn->
mutex);
18450 struct sockaddr *psa;
18453 unsigned max_req_size =
18457 size_t conn_size = ((
sizeof(
struct mg_connection) + 7) >> 3) << 3;
18458 size_t ctx_size = ((
sizeof(
struct mg_context) + 7) >> 3) << 3;
18459 size_t alloc_size = conn_size + ctx_size + max_req_size;
18465 if (error != NULL) {
18469 error->
text[0] = 0;
18473 if (conn == NULL) {
18474 if (error != NULL) {
18476 error->
code_sub = (unsigned)alloc_size;
18487#if defined(GCC_DIAGNOSTIC)
18488#pragma GCC diagnostic push
18489#pragma GCC diagnostic ignored "-Wcast-align"
18495#if defined(GCC_DIAGNOSTIC)
18496#pragma GCC diagnostic pop
18499 conn->
buf = (((
char *)conn) + conn_size + ctx_size);
18505 client_options->
host,
18506 client_options->
port,
18517#if !defined(NO_SSL) && !defined(USE_MBEDTLS) \
18518 && !defined(USE_GNUTLS)
18519#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
18520 && !defined(NO_SSL_DL)
18525 if (error != NULL) {
18531 "SSL_CTX_new error: %s",
18543 && (conn->
dom_ctx->
ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
18545 if (error != NULL) {
18551 "SSL_CTX_new error: %s",
18563#if defined(USE_IPV6)
18566 psa = (sa.
sa.sa_family == AF_INET)
18568 : (
struct sockaddr *)&(conn->
client.
rsa.sin6);
18577 if (getsockname(sock, psa, &
len) != 0) {
18579 "%s: getsockname() failed: %s",
18586 if (error != NULL) {
18593 "Can not create mutex");
18595#if !defined(NO_SSL) && !defined(USE_MBEDTLS) \
18596 && !defined(USE_GNUTLS)
18604#if !defined(NO_SSL) && !defined(USE_MBEDTLS) \
18605 && !defined(USE_GNUTLS)
18619 if (error != NULL) {
18625 "Can not use SSL client certificate");
18640 if (error != NULL) {
18646 "SSL_CTX_load_verify_locations error: %s",
18659 if (!
sslize(conn, SSL_connect, client_options)) {
18660 if (error != NULL) {
18666 "SSL connection error");
18682 char *error_buffer,
18683 size_t error_buffer_size)
18688 memset(&init, 0,
sizeof(init));
18689 memset(&error, 0,
sizeof(error));
18691 error.
text = error_buffer;
18700 char *error_buffer,
18701 size_t error_buffer_size)
18707 memset(&init, 0,
sizeof(init));
18709 memset(&error, 0,
sizeof(error));
18711 error.
text = error_buffer;
18713 memset(&opts, 0,
sizeof(opts));
18724#if defined(MG_EXPERIMENTAL_INTERFACES)
18726mg_connect_client2(
const char *host,
18727 const char *protocol,
18738 if (error != NULL) {
18746 if ((host == NULL) || (protocol == NULL)) {
18747 if (error != NULL) {
18754 "Invalid parameters");
18766#if defined(USE_WEBSOCKET)
18775 if (error != NULL) {
18781 "Protocol %s not supported",
18790#if defined(USE_WEBSOCKET)
18797 ((error != NULL) ? error->
text : NULL),
18799 (path ? path :
""),
18801 experimental_websocket_client_data_wrapper,
18802 experimental_websocket_client_close_wrapper,
18812 memset(&opts, 0,
sizeof(opts));
18821static const struct {
18826 {
"https://", 8, 443},
18828 {
"wss://", 6, 443},
18842 const char *hostend, *portbegin;
18844 unsigned long port;
18850 if ((uri[0] ==
'*') && (uri[1] ==
'\0')) {
18861 for (i = 0; uri[i] != 0; i++) {
18862 if ((
unsigned char)uri[i] < 33) {
18870 if (uri[0] ==
'/') {
18894 port = strtoul(portbegin + 1, &portend, 10);
18895 if ((portend != hostend) || (port <= 0) || !
is_valid_port(port)) {
18911 const char *server_domain;
18912 size_t server_domain_len;
18913 size_t request_domain_len = 0;
18914 unsigned long port = 0;
18915 int i, auth_domain_check_enabled;
18916 const char *hostbegin = NULL;
18917 const char *hostend = NULL;
18918 const char *portbegin;
18921 auth_domain_check_enabled =
18933 hostend = strchr(hostbegin,
'/');
18937 portbegin = strchr(hostbegin,
':');
18938 if ((!portbegin) || (portbegin > hostend)) {
18940 request_domain_len = (size_t)(hostend - hostbegin);
18942 port = strtoul(portbegin + 1, &portend, 10);
18943 if ((portend != hostend) || (port <= 0)
18947 request_domain_len = (size_t)(portbegin - hostbegin);
18974 if (auth_domain_check_enabled) {
18976 server_domain_len = strlen(server_domain);
18977 if ((server_domain_len == 0) || (hostbegin == NULL)) {
18980 if ((request_domain_len == server_domain_len)
18981 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
18984 if (request_domain_len < (server_domain_len + 2)) {
18991 if (hostbegin[request_domain_len - server_domain_len - 1] !=
'.') {
18998 != memcmp(server_domain,
18999 hostbegin + request_domain_len - server_domain_len,
19000 server_domain_len)) {
19015 if (ebuf_len > 0) {
19035 clock_gettime(CLOCK_MONOTONIC, &(conn->
req_time));
19046 "Invalid message size");
19057 "Message too large");
19070 :
"Malformed message");
19080 "No data received");
19121 "Bad request: Host mismatch");
19129 "Accept-Encoding"))
19131 && strstr(cl,
"gzip")) {
19137 "Transfer-Encoding"))
19157 char *endptr = NULL;
19209 "Transfer-Encoding"))
19228 char *endptr = NULL;
19274 char *save_timeout;
19277 if (ebuf_len > 0) {
19287 "Parameter error");
19297 if (timeout >= 0) {
19298 mg_snprintf(conn, NULL, txt,
sizeof(txt),
"%i", timeout);
19301 new_timeout = NULL;
19314 return (
ret == 0) ? -1 : +1;
19332 if (ebuf_len > 0) {
19341 if (conn != NULL) {
19349 "Error sending request");
19361 if ((ebuf[0] !=
'\0') && (conn != NULL)) {
19379#if defined(USE_WEBSOCKET)
19381static unsigned __stdcall websocket_client_thread(
void *
data)
19384websocket_client_thread(
void *
data)
19390 void *user_thread_ptr = NULL;
19392#if !defined(_WIN32) && !defined(__ZEPHYR__)
19393 struct sigaction sa;
19396 memset(&sa, 0,
sizeof(sa));
19397 sa.sa_handler = SIG_IGN;
19398 sigaction(SIGPIPE, &sa, NULL);
19414 DEBUG_TRACE(
"%s",
"Websocket client thread exited\n");
19441#if defined(USE_WEBSOCKET)
19443generate_websocket_magic(
char *magic25)
19446 unsigned char buffer[2 *
sizeof(rnd)];
19449 memcpy(buffer, &rnd,
sizeof(rnd));
19451 memcpy(buffer +
sizeof(rnd), &rnd,
sizeof(rnd));
19453 size_t dst_len = 24 + 1;
19462 char *error_buffer,
19463 size_t error_buffer_size,
19465 const char *origin,
19466 const char *extensions,
19473#if defined(USE_WEBSOCKET)
19476 generate_websocket_magic(magic);
19478 const char *host = client_options->
host;
19484 memset(&init, 0,
sizeof(init));
19485 memset(&error, 0,
sizeof(error));
19487 error.
text = error_buffer;
19489#if defined(__clang__)
19490#pragma clang diagnostic push
19491#pragma clang diagnostic ignored "-Wformat-nonliteral"
19498 if (conn == NULL) {
19500 if (!error_buffer[0]) {
19506 "Unexpected error");
19511 if (origin != NULL) {
19512 if (extensions != NULL) {
19514 "GET %s HTTP/1.1\r\n"
19516 "Upgrade: websocket\r\n"
19517 "Connection: Upgrade\r\n"
19518 "Sec-WebSocket-Key: %s\r\n"
19519 "Sec-WebSocket-Version: 13\r\n"
19520 "Sec-WebSocket-Extensions: %s\r\n"
19530 "GET %s HTTP/1.1\r\n"
19532 "Upgrade: websocket\r\n"
19533 "Connection: Upgrade\r\n"
19534 "Sec-WebSocket-Key: %s\r\n"
19535 "Sec-WebSocket-Version: 13\r\n"
19545 if (extensions != NULL) {
19547 "GET %s HTTP/1.1\r\n"
19549 "Upgrade: websocket\r\n"
19550 "Connection: Upgrade\r\n"
19551 "Sec-WebSocket-Key: %s\r\n"
19552 "Sec-WebSocket-Version: 13\r\n"
19553 "Sec-WebSocket-Extensions: %s\r\n"
19561 "GET %s HTTP/1.1\r\n"
19563 "Upgrade: websocket\r\n"
19564 "Connection: Upgrade\r\n"
19565 "Sec-WebSocket-Key: %s\r\n"
19566 "Sec-WebSocket-Version: 13\r\n"
19579 "Error sending request");
19585 if (!
get_response(conn, error_buffer, error_buffer_size, &i)) {
19592#if defined(__clang__)
19593#pragma clang diagnostic pop
19601 if (!*error_buffer) {
19607 "Unexpected server reply");
19610 DEBUG_TRACE(
"Websocket client connect error: %s\r\n", error_buffer);
19617 if (!thread_data) {
19655 "Websocket client connect thread could not be started\r\n");
19660 (void)client_options;
19662 (void)error_buffer;
19663 (void)error_buffer_size;
19680 char *error_buffer,
19681 size_t error_buffer_size,
19683 const char *origin,
19689 memset(&client_options, 0,
sizeof(client_options));
19712 char *error_buffer,
19713 size_t error_buffer_size,
19715 const char *origin,
19720 if (!client_options) {
19740 char *error_buffer,
19741 size_t error_buffer_size,
19743 const char *origin,
19744 const char *extensions,
19750 memset(&client_options, 0,
sizeof(client_options));
19770 char *error_buffer,
19771 size_t error_buffer_size,
19773 const char *origin,
19774 const char *extensions,
19779 if (!client_options) {
19800 int keep_alive_enabled =
19803 if (!keep_alive_enabled) {
19815#if defined(USE_SERVER_STATS)
19816 conn->conn_state = 2;
19822 void *conn_data = NULL;
19839 int keep_alive, discard_len;
19841 const char *hostend;
19842 int reqerr, uri_type;
19844#if defined(USE_SERVER_STATS)
19846 mg_atomic_add(&(conn->
phys_ctx->total_connections), 1);
19847 mg_atomic_max(&(conn->
phys_ctx->max_active_connections), mcon);
19850 DEBUG_TRACE(
"Start processing connection from %s",
19856 DEBUG_TRACE(
"calling get_request (%i times for this connection)",
19859#if defined(USE_SERVER_STATS)
19860 conn->conn_state = 3;
19863 if (!
get_request(conn, ebuf,
sizeof(ebuf), &reqerr)) {
19879 "Bad HTTP version: [%s]",
19884 if (ebuf[0] ==
'\0') {
19886 switch (uri_type) {
19922 if (ebuf[0] !=
'\0') {
19942 (ebuf[0] ? ebuf :
"none"));
19944 if (ebuf[0] ==
'\0') {
19995 conn->
buf + discard_len,
20004 DEBUG_TRACE(
"internal error: data_len = %li, buf_size = %li",
20010 }
while (keep_alive);
20012 DEBUG_TRACE(
"Done processing connection from %s (%f sec)",
20018#if defined(USE_SERVER_STATS)
20026 int only_if_no_idle_threads);
20028#if defined(ALTERNATIVE_QUEUE)
20042 if (ctx->client_socks[i].in_use == 2) {
20044 if ((ctx->client_socks[i].in_use == 2) && !ctx->
stop_flag) {
20045 ctx->client_socks[i] = *sp;
20046 ctx->client_socks[i].in_use = 1;
20049 (void)event_signal(ctx->client_wait_events[i]);
20068 int counter_was_preincremented)
20072 if (counter_was_preincremented
20077 ctx->client_socks[thread_index].in_use = 2;
20080 event_wait(ctx->client_wait_events[thread_index]);
20083 *sp = ctx->client_socks[thread_index];
20111 int counter_was_preincremented)
20113 (void)thread_index;
20117 if (counter_was_preincremented
20144 (void)pthread_cond_signal(&ctx->
sq_empty);
20165 && (queue_filled >= ctx->
sq_size)) {
20167#if defined(USE_SERVER_STATS)
20168 if (queue_filled > ctx->sq_max_fill) {
20169 ctx->sq_max_fill = queue_filled;
20177 if (queue_filled < ctx->sq_size) {
20185#if defined(USE_SERVER_STATS)
20186 if (queue_filled > ctx->sq_max_fill) {
20187 ctx->sq_max_fill = queue_filled;
20191 (void)pthread_cond_signal(&ctx->
sq_full);
20207 int first_call_to_consume_socket = 1;
20214 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
20218 pthread_setspecific(
sTlsKey, &tls);
20232 if ((thread_index < 0)
20235 "Internal error: Invalid worker index %i",
20244 if (conn->
buf == NULL) {
20247 "Out of memory: Cannot allocate buffer for worker %i",
20267#if defined(USE_SERVER_STATS)
20268 conn->conn_state = 1;
20275 ctx, &conn->
client, thread_index, first_call_to_consume_socket)) {
20276 first_call_to_consume_socket = 0;
20281#if defined(USE_SERVER_STATS)
20282 conn->conn_close_time = 0;
20308#if defined(USE_MBEDTLS)
20310 if (mbed_ssl_accept(&(conn->
ssl),
20326#elif defined(USE_GNUTLS)
20328 if (gtls_ssl_accept(&(conn->
ssl),
20344#elif !defined(NO_SSL)
20346 if (
sslize(conn, SSL_accept, NULL)) {
20356#if defined(USE_HTTP2)
20358 && (!memcmp(tls.
alpn_proto,
"\x02h2", 3))) {
20366 process_new_http2_connection(conn);
20411#if defined(USE_SERVER_STATS)
20412 conn->conn_close_time = time(NULL);
20422 pthread_setspecific(
sTlsKey, NULL);
20424 CloseHandle(tls.pthread_cond_helper_mutex);
20426 pthread_mutex_destroy(&conn->
mutex);
20439#if defined(USE_SERVER_STATS)
20440 conn->conn_state = 9;
20449static unsigned __stdcall
worker_thread(
void *thread_func_param)
20458#if !defined(__ZEPHYR__)
20459 struct sigaction sa;
20462 memset(&sa, 0,
sizeof(sa));
20463 sa.sa_handler = SIG_IGN;
20464 sigaction(SIGPIPE, &sa, NULL);
20480 socklen_t
len =
sizeof(
so.rsa);
20481#if !defined(__ZEPHYR__)
20484 memset(&
so, 0,
sizeof(
so));
20486 if ((
so.sock = accept(listener->
sock, &
so.rsa.sa, &
len))
20491 "%s: %s is not allowed to connect",
20502 if (getsockname(
so.sock, &
so.lsa.sa, &
len) != 0) {
20504 "%s: getsockname() failed: %s",
20509#if !defined(__ZEPHYR__)
20510 if ((
so.lsa.sa.sa_family == AF_INET)
20511 || (
so.lsa.sa.sa_family == AF_INET6)) {
20519 if (setsockopt(
so.sock,
20527 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
20546 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
20569 unsigned int workerthreadcount;
20579 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
20580#elif defined(USE_MASTER_THREAD_PRIORITY)
20581 int min_prio = sched_get_priority_min(SCHED_RR);
20582 int max_prio = sched_get_priority_max(SCHED_RR);
20583 if ((min_prio >= 0) && (max_prio >= 0)
20584 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
20585 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
20586 struct sched_param sched_param = {0};
20587 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
20588 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
20594 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
20597 pthread_setspecific(
sTlsKey, &tls);
20607#if defined(USE_LUA)
20608 if (ctx->lua_background_state) {
20609 lua_State *lstate = (lua_State *)ctx->lua_background_state;
20610 pthread_mutex_lock(&ctx->lua_bg_mutex);
20613 lua_getglobal(lstate,
"start");
20614 if (lua_type(lstate, -1) == LUA_TFUNCTION) {
20615 int ret = lua_pcall(lstate, 0, 0, 0);
20621 "lua_background_script",
20625 lua_pop(lstate, 1);
20629 lua_getglobal(lstate,
"log");
20630 if (lua_type(lstate, -1) == LUA_TFUNCTION) {
20631 ctx->lua_bg_log_available = 1;
20633 lua_pop(lstate, 1);
20635 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20647 pfd[i].events = POLLIN;
20671 && (pfd[i].revents & POLLIN)) {
20685#if defined(ALTERNATIVE_QUEUE)
20687 event_signal(ctx->client_wait_events[i]);
20691 pthread_cond_broadcast(&ctx->
sq_full);
20697 for (i = 0; i < workerthreadcount; i++) {
20703#if defined(USE_LUA)
20705 if (ctx->lua_background_state) {
20706 lua_State *lstate = (lua_State *)ctx->lua_background_state;
20707 ctx->lua_bg_log_available = 0;
20710 pthread_mutex_lock(&ctx->lua_bg_mutex);
20711 lua_getglobal(lstate,
"stop");
20712 if (lua_type(lstate, -1) == LUA_TFUNCTION) {
20713 int ret = lua_pcall(lstate, 0, 0, 0);
20719 "lua_background_script",
20723 DEBUG_TRACE(
"Close Lua background state %p", lstate);
20726 ctx->lua_background_state = 0;
20727 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20740 CloseHandle(tls.pthread_cond_helper_mutex);
20742 pthread_setspecific(
sTlsKey, NULL);
20753static unsigned __stdcall
master_thread(
void *thread_func_param)
20762#if !defined(__ZEPHYR__)
20763 struct sigaction sa;
20766 memset(&sa, 0,
sizeof(sa));
20767 sa.sa_handler = SIG_IGN;
20768 sigaction(SIGPIPE, &sa, NULL);
20797#if defined(ALTERNATIVE_QUEUE)
20799 if (ctx->client_wait_events != NULL) {
20801 event_destroy(ctx->client_wait_events[i]);
20803 mg_free(ctx->client_wait_events);
20806 (void)pthread_cond_destroy(&ctx->
sq_empty);
20807 (void)pthread_cond_destroy(&ctx->
sq_full);
20814#if defined(USE_LUA)
20815 (void)pthread_mutex_destroy(&ctx->lua_bg_mutex);
20829#if defined(_MSC_VER)
20830#pragma warning(suppress : 6001)
20844#if defined(USE_MBEDTLS)
20851#elif defined(USE_GNUTLS)
20858#elif !defined(NO_SSL)
20861 void *ssl_ctx = (
void *)ctx->
dd.
ssl_ctx;
20867 if (callback_ret == 0) {
20916#if defined(USE_TIMERS)
20929#if defined(USE_LUA)
20943 DWORD dwVersion = 0;
20944 DWORD dwMajorVersion = 0;
20945 DWORD dwMinorVersion = 0;
20947 BOOL wowRet, isWoW = FALSE;
20949#if defined(_MSC_VER)
20950#pragma warning(push)
20952#pragma warning(disable : 4996)
20954 dwVersion = GetVersion();
20955#if defined(_MSC_VER)
20956#pragma warning(pop)
20959 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
20960 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
20961 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
20964 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
20968 (
unsigned)dwMajorVersion,
20969 (
unsigned)dwMinorVersion,
20970 (wowRet ? (isWoW ?
" (WoW64)" :
"") :
" (?)"));
20974#elif defined(__rtems__)
20976#elif defined(__ZEPHYR__)
20979 struct utsname
name;
20993 const char **run_options = options;
20997 while (*run_options) {
20998 if (!strcmp(*run_options, optname)) {
20999 ports_option = run_options[1];
21015#if !defined(HAVE_SOCKETPAIR) && !defined(_WIN32)
21016#define HAVE_SOCKETPAIR 1
21022 int temp[2] = {-1, -1};
21029#if defined(HAVE_SOCKETPAIR)
21030 int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, temp);
21042 asock =
socket(PF_INET, SOCK_STREAM, 0);
21044 struct sockaddr_in addr;
21045 struct sockaddr *pa = (
struct sockaddr *)&addr;
21046 socklen_t addrLen =
sizeof(addr);
21048 memset(&addr, 0,
sizeof(addr));
21049 addr.sin_family = AF_INET;
21050 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
21053 if ((bind(asock, pa,
sizeof(addr)) == 0)
21054 && (getsockname(asock, pa, &addrLen) == 0)
21055 && (listen(asock, 1) == 0)) {
21056 temp[0] =
socket(PF_INET, SOCK_STREAM, 0);
21057 if ((temp[0] >= 0) && (connect(temp[0], pa,
sizeof(addr)) == 0)) {
21058 temp[1] = accept(asock, pa, &addrLen);
21059 if (temp[1] >= 0) {
21092#if defined(ALTERNATIVE_QUEUE)
21095 if ((only_if_no_idle_threads)
21128 const char *
name, *
value, *default_value;
21129 int idx, ok, prespawnthreadcount, workerthreadcount;
21132 void (*exit_callback)(
const struct mg_context *ctx) = 0;
21133 const char **options =
21138 if (error != NULL) {
21153 if (error != NULL) {
21160 "Library uninitialized");
21168 if (error != NULL) {
21170 error->
code_sub = (unsigned)
sizeof(*ctx);
21183 (uint64_t)
get_random() ^ (uint64_t)(ptrdiff_t)(options);
21192 tls.pthread_cond_helper_mutex = NULL;
21194 pthread_setspecific(
sTlsKey, &tls);
21197#if !defined(ALTERNATIVE_QUEUE)
21198 ok &= (0 == pthread_cond_init(&ctx->
sq_empty, NULL));
21199 ok &= (0 == pthread_cond_init(&ctx->
sq_full, NULL));
21203#if defined(USE_LUA)
21216 unsigned error_id = (unsigned)
ERRNO;
21217 const char *err_msg =
21218 "Cannot initialize thread synchronization objects";
21223 if (error != NULL) {
21235 pthread_setspecific(
sTlsKey, NULL);
21239 if ((init != NULL) && (init->
callbacks != NULL)) {
21252#if defined(USE_LUA)
21257 while (options && (
name = *options++) != NULL) {
21261 if (error != NULL) {
21268 "Invalid configuration option: %s",
21273 pthread_setspecific(
sTlsKey, NULL);
21276 }
else if ((
value = *options++) == NULL) {
21278 if (error != NULL) {
21285 "Invalid configuration option value: %s",
21290 pthread_setspecific(
sTlsKey, NULL);
21293 if (ctx->
dd.
config[idx] != NULL) {
21306 if ((ctx->
dd.
config[i] == NULL) && (default_value != NULL)) {
21317 if (error != NULL) {
21324 "Invalid configuration option value: %s",
21329 pthread_setspecific(
sTlsKey, NULL);
21335#if !defined(ALTERNATIVE_QUEUE)
21341 if (error != NULL) {
21348 "Invalid configuration option value: %s",
21353 pthread_setspecific(
sTlsKey, NULL);
21358 if (ctx->
squeue == NULL) {
21360 "Out of memory: Cannot allocate %s",
21362 if (error != NULL) {
21364 error->
code_sub = (unsigned)itmp * (
unsigned)
sizeof(
struct socket);
21369 "Out of memory: Cannot allocate %s",
21374 pthread_setspecific(
sTlsKey, NULL);
21384 if ((prespawnthreadcount < 0)
21385 || (prespawnthreadcount > workerthreadcount)) {
21386 prespawnthreadcount =
21391 if (workerthreadcount <= 0) {
21396 if (error != NULL) {
21403 "Invalid configuration option value: %s",
21408 pthread_setspecific(
sTlsKey, NULL);
21413#if defined(NO_FILES)
21416 if (error != NULL) {
21423 "Invalid configuration option value: %s",
21428 pthread_setspecific(
sTlsKey, NULL);
21435#if defined(USE_LUA)
21437 ctx->lua_bg_log_available = 0;
21438 if (ctx->
dd.
config[LUA_BACKGROUND_SCRIPT] != NULL) {
21440 struct vec opt_vec;
21442 const char *sparams;
21444 memset(ebuf, 0,
sizeof(ebuf));
21445 pthread_mutex_lock(&ctx->lua_bg_mutex);
21448 lua_State *state = mg_lua_context_script_prepare(
21449 ctx->
dd.
config[LUA_BACKGROUND_SCRIPT], ctx, ebuf,
sizeof(ebuf));
21452 "lua_background_script load error: %s",
21454 if (error != NULL) {
21460 "Error in script %s: %s",
21465 pthread_mutex_unlock(&ctx->lua_bg_mutex);
21468 pthread_setspecific(
sTlsKey, NULL);
21473 sparams = ctx->
dd.
config[LUA_BACKGROUND_SCRIPT_PARAMS];
21474 if (sparams && sparams[0]) {
21475 lua_getglobal(state,
"mg");
21476 lua_pushstring(state,
"params");
21477 lua_newtable(state);
21479 while ((sparams =
next_option(sparams, &opt_vec, &eq_vec))
21482 state, opt_vec.
ptr, opt_vec.
len, eq_vec.
ptr, eq_vec.
len);
21486 lua_rawset(state, -3);
21491 state = mg_lua_context_script_run(state,
21492 ctx->
dd.
config[LUA_BACKGROUND_SCRIPT],
21498 "lua_background_script start error: %s",
21500 if (error != NULL) {
21506 "Error in script %s: %s",
21510 pthread_mutex_unlock(&ctx->lua_bg_mutex);
21513 pthread_setspecific(
sTlsKey, NULL);
21518 ctx->lua_background_state = (
void *)state;
21519 pthread_mutex_unlock(&ctx->lua_bg_mutex);
21522 ctx->lua_background_state = 0;
21527#if !defined(NO_FILESYSTEMS)
21529 const char *err_msg =
"Invalid global password file";
21533 if (error != NULL) {
21543 pthread_setspecific(
sTlsKey, NULL);
21548#if defined(USE_MBEDTLS) || defined(USE_GNUTLS)
21549 if (!mg_sslctx_init(ctx, NULL)) {
21550 const char *err_msg =
"Error initializing SSL context";
21554 if (error != NULL) {
21565 pthread_setspecific(
sTlsKey, NULL);
21569#elif !defined(NO_SSL)
21571 const char *err_msg =
"Error initializing SSL context";
21575 if (error != NULL) {
21586 pthread_setspecific(
sTlsKey, NULL);
21592 const char *err_msg =
"Failed to setup server ports";
21596 if (error != NULL) {
21607 pthread_setspecific(
sTlsKey, NULL);
21611#if !defined(_WIN32) && !defined(__ZEPHYR__)
21613 const char *err_msg =
"Failed to run as configured user";
21617 if (error != NULL) {
21628 pthread_setspecific(
sTlsKey, NULL);
21634 const char *err_msg =
"Failed to setup access control list";
21638 if (error != NULL) {
21649 pthread_setspecific(
sTlsKey, NULL);
21660 const char *err_msg =
"Not enough memory for worker thread ID array";
21663 if (error != NULL) {
21666 * (
unsigned)
sizeof(pthread_t);
21676 pthread_setspecific(
sTlsKey, NULL);
21684 const char *err_msg =
21685 "Not enough memory for worker thread connection array";
21688 if (error != NULL) {
21701 pthread_setspecific(
sTlsKey, NULL);
21705#if defined(ALTERNATIVE_QUEUE)
21706 ctx->client_wait_events =
21708 sizeof(ctx->client_wait_events[0]),
21710 if (ctx->client_wait_events == NULL) {
21711 const char *err_msg =
"Not enough memory for worker event array";
21715 if (error != NULL) {
21718 * (
unsigned)
sizeof(ctx->client_wait_events[0]);
21728 pthread_setspecific(
sTlsKey, NULL);
21732 ctx->client_socks =
21734 sizeof(ctx->client_socks[0]),
21736 if (ctx->client_socks == NULL) {
21737 const char *err_msg =
"Not enough memory for worker socket array";
21739 mg_free(ctx->client_wait_events);
21742 if (error != NULL) {
21745 * (
unsigned)
sizeof(ctx->client_socks[0]);
21755 pthread_setspecific(
sTlsKey, NULL);
21760 ctx->client_wait_events[i] = event_create();
21761 if (ctx->client_wait_events[i] == 0) {
21762 const char *err_msg =
"Error creating worker event %i";
21766 event_destroy(ctx->client_wait_events[i]);
21769 mg_free(ctx->client_wait_events);
21772 if (error != NULL) {
21784 pthread_setspecific(
sTlsKey, NULL);
21790#if defined(USE_TIMERS)
21791 if (timers_init(ctx) != 0) {
21792 const char *err_msg =
"Error creating timers";
21795 if (error != NULL) {
21807 pthread_setspecific(
sTlsKey, NULL);
21823 for (i = 0; (
int)i < prespawnthreadcount; i++) {
21826 long error_no = (long)
ERRNO;
21833 "Cannot start worker thread %i: error %ld",
21846 "Cannot create threads: error %ld",
21849 if (error != NULL) {
21851 error->
code_sub = (unsigned)error_no;
21857 "Cannot create first worker thread: error %ld",
21862 pthread_setspecific(
sTlsKey, NULL);
21872 pthread_setspecific(
sTlsKey, NULL);
21880 const char **options)
21894 const char **options,
21899 const char *default_value;
21904 if (error != NULL) {
21912 if ((ctx == NULL) || (options == NULL)) {
21913 if (error != NULL) {
21920 "Invalid parameters");
21926 if (error != NULL) {
21933 "Server already stopped");
21943 if (error != NULL) {
21957 while (options && (
name = *options++) != NULL) {
21961 if (error != NULL) {
21968 "Invalid option: %s",
21973 }
else if ((
value = *options++) == NULL) {
21975 if (error != NULL) {
21982 "Invalid option value: %s",
21988 if (new_dom->
config[idx] != NULL) {
22001 if (error != NULL) {
22008 "Mandatory option %s missing",
22018 default_value = ctx->
dd.
config[i];
22019 if ((new_dom->
config[i] == NULL) && (default_value != NULL)) {
22025 new_dom->
next = NULL;
22029#if defined(USE_LUA) && defined(USE_WEBSOCKET)
22030 new_dom->shared_lua_websockets = NULL;
22033#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(USE_GNUTLS)
22036 if (error != NULL) {
22043 "Initializing SSL context failed");
22060 "domain %s already in use",
22062 if (error != NULL) {
22068 "Domain %s specified by %s is already in use",
22080 if (dom->
next == NULL) {
22081 dom->
next = new_dom;
22105 static const unsigned feature_set = 0
22109#if !defined(NO_FILES)
22112#if !defined(NO_SSL) || defined(USE_MBEDTLS) || defined(USE_GNUTLS)
22115#if !defined(NO_CGI)
22118#if defined(USE_IPV6)
22121#if defined(USE_WEBSOCKET)
22124#if defined(USE_LUA)
22127#if defined(USE_DUKTAPE)
22130#if !defined(NO_CACHING)
22133#if defined(USE_SERVER_STATS)
22136#if defined(USE_ZLIB)
22139#if defined(USE_HTTP2)
22142#if defined(USE_X_DOM_SOCKET)
22148#if defined(MG_LEGACY_INTERFACE)
22151#if defined(MG_EXPERIMENTAL_INTERFACES)
22154#if !defined(NO_RESPONSE_BUFFERING)
22157#if defined(MEMORY_DEBUGGING)
22161 return (feature & feature_set);
22168 size_t len = strlen(
src);
22171 if ((
size_t)(end - *dst) >
len) {
22187 char *end, *append_eoobj = NULL, block[256];
22188 size_t system_info_length = 0;
22191 static const char eol[] =
"\r\n", eoobj[] =
"\r\n}\r\n";
22193 static const char eol[] =
"\n", eoobj[] =
"\n}\n";
22196 if ((buffer == NULL) || (buflen < 1)) {
22201 end = buffer + buflen;
22203 if (buflen > (
int)(
sizeof(eoobj) - 1)) {
22205 append_eoobj = buffer;
22207 end -=
sizeof(eoobj) - 1;
22220 "%s\"version\" : \"%s\"",
22229 DWORD dwVersion = 0;
22230 DWORD dwMajorVersion = 0;
22231 DWORD dwMinorVersion = 0;
22234 GetSystemInfo(&si);
22236#if defined(_MSC_VER)
22237#pragma warning(push)
22239#pragma warning(disable : 4996)
22241 dwVersion = GetVersion();
22242#if defined(_MSC_VER)
22243#pragma warning(pop)
22246 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
22247 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
22253 ",%s\"os\" : \"Windows %u.%u\"",
22255 (
unsigned)dwMajorVersion,
22256 (
unsigned)dwMinorVersion);
22263 ",%s\"cpu\" : \"type %u, cores %u, mask %x\"",
22265 (
unsigned)si.wProcessorArchitecture,
22266 (
unsigned)si.dwNumberOfProcessors,
22267 (
unsigned)si.dwActiveProcessorMask);
22269#elif defined(__rtems__)
22274 ",%s\"os\" : \"%s %s\"",
22279#elif defined(__ZEPHYR__)
22284 ",%s\"os\" : \"%s\"",
22290 struct utsname
name;
22298 ",%s\"os\" : \"%s %s (%s) - %s\"",
22314 ",%s\"features\" : %lu"
22315 ",%s\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\"",
22331#if defined(USE_LUA)
22336 ",%s\"lua_version\" : \"%u (%s)\"",
22338 (
unsigned)LUA_VERSION_NUM,
22342#if defined(USE_DUKTAPE)
22347 ",%s\"javascript\" : \"Duktape %u.%u.%u\"",
22349 (
unsigned)DUK_VERSION / 10000,
22350 ((
unsigned)DUK_VERSION / 100) % 100,
22351 (
unsigned)DUK_VERSION % 100);
22358#if defined(BUILD_DATE)
22359 const char *bd = BUILD_DATE;
22361#if defined(GCC_DIAGNOSTIC)
22362#if GCC_VERSION >= 40900
22363#pragma GCC diagnostic push
22367#pragma GCC diagnostic ignored "-Wdate-time"
22370 const char *bd = __DATE__;
22371#if defined(GCC_DIAGNOSTIC)
22372#if GCC_VERSION >= 40900
22373#pragma GCC diagnostic pop
22379 NULL, NULL, block,
sizeof(block),
",%s\"build\" : \"%s\"", eol, bd);
22387#if defined(_MSC_VER)
22392 ",%s\"compiler\" : \"MSC: %u (%u)\"",
22394 (
unsigned)_MSC_VER,
22395 (
unsigned)_MSC_FULL_VER);
22397#elif defined(__MINGW64__)
22402 ",%s\"compiler\" : \"MinGW64: %u.%u\"",
22404 (
unsigned)__MINGW64_VERSION_MAJOR,
22405 (
unsigned)__MINGW64_VERSION_MINOR);
22411 ",%s\"compiler\" : \"MinGW32: %u.%u\"",
22413 (
unsigned)__MINGW32_MAJOR_VERSION,
22414 (
unsigned)__MINGW32_MINOR_VERSION);
22416#elif defined(__MINGW32__)
22421 ",%s\"compiler\" : \"MinGW32: %u.%u\"",
22423 (
unsigned)__MINGW32_MAJOR_VERSION,
22424 (
unsigned)__MINGW32_MINOR_VERSION);
22426#elif defined(__clang__)
22431 ",%s\"compiler\" : \"clang: %u.%u.%u (%s)\"",
22435 __clang_patchlevel__,
22436 __clang_version__);
22438#elif defined(__GNUC__)
22443 ",%s\"compiler\" : \"gcc: %u.%u.%u\"",
22445 (
unsigned)__GNUC__,
22446 (
unsigned)__GNUC_MINOR__,
22447 (
unsigned)__GNUC_PATCHLEVEL__);
22449#elif defined(__INTEL_COMPILER)
22454 ",%s\"compiler\" : \"Intel C/C++: %u\"",
22456 (
unsigned)__INTEL_COMPILER);
22458#elif defined(__BORLANDC__)
22463 ",%s\"compiler\" : \"Borland C: 0x%x\"",
22465 (
unsigned)__BORLANDC__);
22467#elif defined(__SUNPRO_C)
22472 ",%s\"compiler\" : \"Solaris: 0x%x\"",
22474 (
unsigned)__SUNPRO_C);
22481 ",%s\"compiler\" : \"other\"",
22494 ",%s\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, "
22496 "ptr:%u, size:%u, time:%u\"",
22498 (
unsigned)
sizeof(
short),
22499 (
unsigned)
sizeof(
int),
22500 (
unsigned)
sizeof(
long),
22501 (
unsigned)
sizeof(
long long),
22502 (
unsigned)
sizeof(
float),
22503 (
unsigned)
sizeof(
double),
22504 (
unsigned)
sizeof(
long double),
22505 (
unsigned)
sizeof(
char),
22506 (
unsigned)
sizeof(
wchar_t),
22507 (
unsigned)
sizeof(
void *),
22508 (
unsigned)
sizeof(
size_t),
22509 (
unsigned)
sizeof(time_t));
22514 if (append_eoobj) {
22515 strcat(append_eoobj, eoobj);
22517 system_info_length +=
sizeof(eoobj) - 1;
22519 return (
int)system_info_length;
22528#if defined(USE_SERVER_STATS)
22529 char *end, *append_eoobj = NULL, block[256];
22530 size_t context_info_length = 0;
22533 static const char eol[] =
"\r\n", eoobj[] =
"\r\n}\r\n";
22535 static const char eol[] =
"\n", eoobj[] =
"\n}\n";
22537 struct mg_memory_stat *ms = get_memory_stat((
struct mg_context *)ctx);
22539 if ((buffer == NULL) || (buflen < 1)) {
22544 end = buffer + buflen;
22546 if (buflen > (
int)(
sizeof(eoobj) - 1)) {
22548 append_eoobj = buffer;
22549 end -=
sizeof(eoobj) - 1;
22556 int blockCount = (
int)ms->blockCount;
22557 int64_t totalMemUsed = ms->totalMemUsed;
22558 int64_t maxMemUsed = ms->maxMemUsed;
22559 if (totalMemUsed > maxMemUsed) {
22560 maxMemUsed = totalMemUsed;
22567 "%s\"memory\" : {%s"
22568 "\"blocks\" : %i,%s"
22586 char start_time_str[64] = {0};
22587 char now_str[64] = {0};
22589 time_t now = time(NULL);
22590 int64_t total_data_read, total_data_written;
22591 int active_connections = (
int)ctx->active_connections;
22592 int max_active_connections = (
int)ctx->max_active_connections;
22593 int total_connections = (
int)ctx->total_connections;
22594 if (active_connections > max_active_connections) {
22595 max_active_connections = active_connections;
22597 if (active_connections > total_connections) {
22598 total_connections = active_connections;
22606 ",%s\"connections\" : {%s"
22607 "\"active\" : %i,%s"
22608 "\"maxActive\" : %i,%s"
22613 active_connections,
22615 max_active_connections,
22622#if !defined(ALTERNATIVE_QUEUE)
22627 ",%s\"queue\" : {%s"
22628 "\"length\" : %i,%s"
22629 "\"filled\" : %i,%s"
22630 "\"maxFilled\" : %i,%s"
22651 ",%s\"requests\" : {%s"
22652 "\"total\" : %lu%s"
22656 (
unsigned long)ctx->total_requests,
22662 mg_atomic_add64((
volatile int64_t *)&ctx->total_data_read, 0);
22663 total_data_written =
22664 mg_atomic_add64((
volatile int64_t *)&ctx->total_data_written, 0);
22669 ",%s\"data\" : {%s"
22677 total_data_written,
22683 sizeof(start_time_str) - 1,
22691 ",%s\"time\" : {%s"
22692 "\"uptime\" : %.0f,%s"
22693 "\"start\" : \"%s\",%s"
22694 "\"now\" : \"%s\"%s"
22698 difftime(now, start_time),
22708 if (append_eoobj) {
22709 strcat(append_eoobj, eoobj);
22711 context_info_length +=
sizeof(eoobj) - 1;
22713 return (
int)context_info_length;
22716 if ((buffer != NULL) && (buflen > 0)) {
22728 if (conn != NULL) {
22734#if defined(MG_EXPERIMENTAL_INTERFACES)
22738mg_get_connection_info(
const struct mg_context *ctx,
22745 char *end, *append_eoobj = NULL, block[256];
22746 size_t connection_info_length = 0;
22748 const char *state_str =
"unknown";
22751 static const char eol[] =
"\r\n", eoobj[] =
"\r\n}\r\n";
22753 static const char eol[] =
"\n", eoobj[] =
"\n}\n";
22756 if ((buffer == NULL) || (buflen < 1)) {
22761 end = buffer + buflen;
22763 if (buflen > (
int)(
sizeof(eoobj) - 1)) {
22765 append_eoobj = buffer;
22766 end -=
sizeof(eoobj) - 1;
22769 if ((ctx == NULL) || (idx < 0)) {
22784 connection_info_length +=
mg_str_append(&buffer, end,
"{");
22789#if defined(USE_SERVER_STATS)
22790 state = conn->conn_state;
22795 state_str =
"undefined";
22798 state_str =
"not used";
22801 state_str =
"init";
22804 state_str =
"ready";
22807 state_str =
"processing";
22810 state_str =
"processed";
22813 state_str =
"to close";
22816 state_str =
"closing";
22819 state_str =
"closed";
22822 state_str =
"done";
22828 if ((state >= 3) && (state < 9)) {
22833 "%s\"connection\" : {%s"
22835 "\"protocol\" : \"%s\",%s"
22836 "\"addr\" : \"%s\",%s"
22839 "\"handled_requests\" : %u%s"
22853 connection_info_length +=
mg_str_append(&buffer, end, block);
22857 if ((state >= 4) && (state < 6)) {
22862 "%s%s\"request_info\" : {%s"
22863 "\"method\" : \"%s\",%s"
22864 "\"uri\" : \"%s\",%s"
22865 "\"query\" : %s%s%s%s"
22867 (connection_info_length > 1 ?
"," :
""),
22878 connection_info_length +=
mg_str_append(&buffer, end, block);
22882 if ((state >= 2) && (state < 9)) {
22883 char start_time_str[64] = {0};
22884 char close_time_str[64] = {0};
22886 time_t close_time = 0;
22890 sizeof(start_time_str) - 1,
22892#if defined(USE_SERVER_STATS)
22893 close_time = conn->conn_close_time;
22895 if (close_time != 0) {
22896 time_diff = difftime(close_time, start_time);
22898 sizeof(close_time_str) - 1,
22901 time_t now = time(NULL);
22902 time_diff = difftime(now, start_time);
22903 close_time_str[0] = 0;
22910 "%s%s\"time\" : {%s"
22911 "\"uptime\" : %.0f,%s"
22912 "\"start\" : \"%s\",%s"
22913 "\"closed\" : \"%s\"%s"
22915 (connection_info_length > 1 ?
"," :
""),
22924 connection_info_length +=
mg_str_append(&buffer, end, block);
22933 "%s%s\"user\" : {%s"
22934 "\"name\" : \"%s\",%s"
22936 (connection_info_length > 1 ?
"," :
""),
22941 connection_info_length +=
mg_str_append(&buffer, end, block);
22950 "%s%s\"data\" : {%s"
22954 (connection_info_length > 1 ?
"," :
""),
22961 connection_info_length +=
mg_str_append(&buffer, end, block);
22969 "%s%s\"state\" : \"%s\"",
22970 (connection_info_length > 1 ?
"," :
""),
22973 connection_info_length +=
mg_str_append(&buffer, end, block);
22976 if (append_eoobj) {
22977 strcat(append_eoobj, eoobj);
22979 connection_info_length +=
sizeof(eoobj) - 1;
22981 return (
int)connection_info_length;
22992 int handler_info_len = 0;
22996 for (tmp_rh = ctx->
dd.
handlers; tmp_rh != NULL; tmp_rh = tmp_rh->
next) {
22998 if (buflen > handler_info_len + tmp_rh->
uri_len) {
22999 memcpy(buffer + handler_info_len, tmp_rh->
uri, tmp_rh->
uri_len);
23001 handler_info_len += tmp_rh->
uri_len;
23021 return handler_info_len;
23033 unsigned features_inited = features_to_init;
23049 int file_mutex_init = 1;
23052 int mutexattr_init = 1;
23057 if (key_create == 0) {
23061 if (file_mutex_init == 0) {
23064 failed = wsa = WSAStartup(MAKEWORD(2, 2), &
data);
23068 if (mutexattr_init == 0) {
23070 PTHREAD_MUTEX_RECURSIVE);
23078 (void)WSACleanup();
23080 if (file_mutex_init == 0) {
23081 (void)pthread_mutex_destroy(&global_log_file_lock);
23084 if (mutexattr_init == 0) {
23088 if (key_create == 0) {
23089 (void)pthread_key_delete(
sTlsKey);
23122#if defined(USE_LUA)
23123 lua_init_optional_libraries();
23126#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
23127 || defined(OPENSSL_API_3_0)) \
23128 && !defined(NO_SSL)
23131 if (!mg_openssl_initialized) {
23134 mg_openssl_initialized = 1;
23137 DEBUG_TRACE(
"Initializing SSL failed: %s", ebuf);
23154 return features_inited;
23170#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1)) && !defined(NO_SSL)
23171 if (mg_openssl_initialized) {
23173 mg_openssl_initialized = 0;
23178 (void)WSACleanup();
23179 (void)pthread_mutex_destroy(&global_log_file_lock);
23184 (void)pthread_key_delete(
sTlsKey);
23186#if defined(USE_LUA)
23187 lua_exit_optional_libraries();
static int esc(const char **)
Map escape sequences into their equivalent symbols.
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
static unsigned int total
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void on
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
#define INVALID_HANDLE_VALUE
unsigned int sleep(unsigned int seconds)
static void process_new_connection(struct mg_connection *conn)
@ ENABLE_DIRECTORY_LISTING
@ ACCESS_CONTROL_ALLOW_ORIGIN
@ ACCESS_CONTROL_EXPOSE_HEADERS
@ ALLOW_INDEX_SCRIPT_SUB_RES
@ ACCESS_CONTROL_ALLOW_HEADERS
@ SSL_DEFAULT_VERIFY_PATHS
@ ACCESS_CONTROL_ALLOW_METHODS
@ STATIC_FILE_CACHE_CONTROL
@ PUT_DELETE_PASSWORDS_FILE
@ ENABLE_AUTH_DOMAIN_CHECK
@ ACCESS_CONTROL_ALLOW_CREDENTIALS
static int is_authorized_for_put(struct mg_connection *conn)
static int parse_http_request(char *buf, int len, struct mg_request_info *ri)
void mg_send_mime_file2(struct mg_connection *conn, const char *path, const char *mime_type, const char *additional_headers)
static pthread_key_t sTlsKey
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
static void open_auth_file(struct mg_connection *conn, const char *path, struct mg_file *filep)
int mg_strncasecmp(const char *s1, const char *s2, size_t len)
static int check_authorization(struct mg_connection *conn, const char *path)
#define mg_malloc_ctx(a, c)
static void redirect_to_https_port(struct mg_connection *conn, int port)
static int should_switch_to_protocol(const struct mg_connection *conn)
void mg_unlock_connection(struct mg_connection *conn)
static void remove_bad_file(const struct mg_connection *conn, const char *path)
const struct mg_option * mg_get_valid_options(void)
static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin[2], int fdout[2], int fderr[2], const char *dir, int cgi_config_idx)
static int print_dir_entry(struct mg_connection *conn, struct de *de)
static int mg_path_suspicious(const struct mg_connection *conn, const char *path)
static int set_non_blocking_mode(SOCKET sock)
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
int mg_send_http_error(struct mg_connection *conn, int status, const char *fmt,...)
static const char * get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
static void mg_cry_internal_impl(const struct mg_connection *conn, const char *func, unsigned line, const char *fmt, va_list ap)
void mg_lock_context(struct mg_context *ctx)
#define MAX_WORKER_THREADS
int mg_base64_decode(const char *src, size_t src_len, unsigned char *dst, size_t *dst_len)
static void put_file(struct mg_connection *conn, const char *path)
static void do_ssi_exec(struct mg_connection *conn, char *tag)
static void tls_dtor(void *key)
static int is_civetweb_webdav_method(const struct mg_connection *conn)
const void * SOCK_OPT_TYPE
static int header_has_option(const char *header, const char *option)
int mg_send_http_redirect(struct mg_connection *conn, const char *target_url, int redirect_code)
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
static int ssl_get_client_cert_info(const struct mg_connection *conn, struct mg_client_cert *client_cert)
#define mg_cry_ctx_internal(ctx, fmt,...)
static void mg_snprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt,...)
#define mg_opendir(conn, x)
static char * mg_strndup_ctx(const char *ptr, size_t len, struct mg_context *ctx)
static int put_dir(struct mg_connection *conn, const char *path)
static void send_static_cache_header(struct mg_connection *conn)
static int mg_socketpair(int *sockA, int *sockB)
static ptrdiff_t mg_atomic_dec(volatile ptrdiff_t *addr)
static int print_dav_dir_entry(struct de *de, void *data)
static void delete_file(struct mg_connection *conn, const char *path)
#define mg_calloc_ctx(a, b, c)
struct mg_connection * mg_connect_websocket_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
int mg_get_server_ports(const struct mg_context *ctx, int size, struct mg_server_port *ports)
static ptrdiff_t mg_atomic_inc(volatile ptrdiff_t *addr)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
static int abort_cgi_process(void *data)
static int should_keep_alive(const struct mg_connection *conn)
static __inline void * mg_malloc(size_t a)
@ CONNECTION_TYPE_RESPONSE
@ CONNECTION_TYPE_INVALID
@ CONNECTION_TYPE_REQUEST
static int mg_fopen(const struct mg_connection *conn, const char *path, int mode, struct mg_file *filep)
static int alloc_printf(char **out_buf, const char *fmt,...)
void mg_disable_connection_keep_alive(struct mg_connection *conn)
static int connect_socket(struct mg_context *ctx, const char *host, int port, int use_ssl, struct mg_error_data *error, SOCKET *sock, union usa *sa)
static void mg_global_lock(void)
static void handle_static_file_request(struct mg_connection *conn, const char *path, struct mg_file *filep, const char *mime_type, const char *additional_headers)
static void dav_move_file(struct mg_connection *conn, const char *path, int do_copy)
static int ssl_use_pem_file(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *pem, const char *chain)
static const char * ssl_error(void)
static int must_hide_file(struct mg_connection *conn, const char *path)
static void dav_proppatch(struct mg_connection *conn, const char *path)
static void log_access(const struct mg_connection *)
struct mg_connection * mg_connect_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size)
#define mg_remove(conn, x)
int mg_send_http_ok(struct mg_connection *conn, const char *mime_type, long long content_length)
static void close_all_listening_sockets(struct mg_context *ctx)
void mg_send_file(struct mg_connection *conn, const char *path)
static void send_authorization_request(struct mg_connection *conn, const char *realm)
static int get_req_headers(const struct mg_request_info *ri, const char *name, const char **output, int output_max_size)
static int check_acl(struct mg_context *phys_ctx, const union usa *sa)
static const struct mg_option config_options[]
static const struct mg_http_method_info * get_http_method_info(const char *method)
#define STOP_FLAG_IS_ZERO(f)
const char * mg_get_response_code_text(const struct mg_connection *conn, int response_code)
static int get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
static void mg_cry_internal_wrap(const struct mg_connection *conn, struct mg_context *ctx, const char *func, unsigned line, const char *fmt,...)
static int set_uid_option(struct mg_context *phys_ctx)
static int switch_domain_context(struct mg_connection *conn)
static struct mg_connection * fake_connection(struct mg_connection *fc, struct mg_context *ctx)
static void reset_per_request_attributes(struct mg_connection *conn)
static void handle_file_based_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
static int compare_dir_entries(const void *p1, const void *p2, void *arg)
#define FUNCTION_MAY_BE_UNUSED
static pthread_mutex_t * ssl_mutexes
static int get_option_index(const char *name)
static char * mg_strdup(const char *str)
static void send_no_cache_header(struct mg_connection *conn)
static void master_thread_run(struct mg_context *ctx)
static const char month_names[][4]
const struct mg_response_info * mg_get_response_info(const struct mg_connection *conn)
static __inline void * mg_realloc(void *a, size_t b)
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
static volatile ptrdiff_t cryptolib_users
static void send_file_data(struct mg_connection *conn, struct mg_file *filep, int64_t offset, int64_t len, int no_buffering)
static int get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
static pthread_mutex_t global_lock_mutex
struct mg_context * mg_start2(struct mg_init_data *init, struct mg_error_data *error)
#define CGI_ENVIRONMENT_SIZE
static int parse_http_headers(char **buf, struct mg_header hdr[(64)])
static long ssl_get_protocol(int version_id)
void * mg_get_user_context_data(const struct mg_connection *conn)
static int mg_init_library_called
long long mg_store_body(struct mg_connection *conn, const char *path)
struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
#define DEBUG_ASSERT(cond)
static size_t mg_str_append(char **dst, char *end, const char *src)
static int pull_inner(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
int mg_get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int timeout)
#define MG_FILE_COMPRESSION_SIZE_LIMIT
#define USA_IN_PORT_UNSAFE(s)
unsigned mg_check_feature(unsigned feature)
static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
static int mg_send_http_error_impl(struct mg_connection *conn, int status, const char *fmt, va_list args)
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
#define MG_FOPEN_MODE_READ
#define STOP_FLAG_ASSIGN(f, v)
static int extention_matches_script(struct mg_connection *conn, const char *filename)
static void get_host_from_request_info(struct vec *host, const struct mg_request_info *ri)
static const struct @243147061004330160235326056313274363054075327066 builtin_mime_types[]
void mg_set_websocket_handler(struct mg_context *ctx, const char *uri, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
int mg_start_domain(struct mg_context *ctx, const char **options)
static pthread_mutexattr_t pthread_mutex_attr
void mg_unlock_context(struct mg_context *ctx)
static int ssl_servername_callback(SSL *ssl, int *ad, void *arg)
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
@ PROTOCOL_TYPE_WEBSOCKET
static void fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
int mg_start_thread(mg_thread_func_t func, void *param)
static const char * get_header(const struct mg_header *hdr, int num_hdr, const char *name)
static int mg_inet_pton(int af, const char *src, void *dst, size_t dstlen, int resolve_src)
static int init_ssl_ctx_impl(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *pem, const char *chain)
unsigned mg_init_library(unsigned features)
struct mg_connection * mg_connect_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size)
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
static void dav_lock_file(struct mg_connection *conn, const char *path)
static int set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
static int skip_to_end_of_word_and_terminate(char **ppw, int eol)
static int get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
static int set_tcp_nodelay(const struct socket *so, int nodelay_on)
int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len)
#define ARRAY_SIZE(array)
static void dav_unlock_file(struct mg_connection *conn, const char *path)
static int parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
static int get_first_ssl_listener_index(const struct mg_context *ctx)
void mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type)
const char * mg_get_header(const struct mg_connection *conn, const char *name)
#define mg_mkdir(conn, path, mode)
static const struct @323220224333115126333326051144331011300172200104 abs_uri_protocols[]
int mg_split_form_urlencoded(char *data, struct mg_header *form_fields, unsigned num_form_fields)
static int hexdump2string(void *mem, int memlen, char *buf, int buflen)
static const struct mg_http_method_info http_methods[]
static int mg_poll(struct pollfd *pfd, unsigned int n, int milliseconds, const stop_flag_t *stop_flag)
static void handle_directory_request(struct mg_connection *conn, const char *dir)
static int set_ports_option(struct mg_context *phys_ctx)
static int read_auth_file(struct mg_file *filep, struct read_auth_file_struct *workdata, int depth)
static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
unsigned mg_exit_library(void)
static void * load_tls_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw, int *feature_missing)
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
int mg_send_digest_access_authentication_request(struct mg_connection *conn, const char *realm)
static const char * mg_strcasestr(const char *big_str, const char *small_str)
struct mg_connection * mg_connect_websocket_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
static int set_throttle(const char *spec, const union usa *rsa, const char *uri)
static void ssl_info_callback(const SSL *ssl, int what, int ret)
static void bin2str(char *to, const unsigned char *p, size_t len)
const struct mg_request_info * mg_get_request_info(const struct mg_connection *conn)
static int substitute_index_file_aux(struct mg_connection *conn, char *path, size_t path_len, struct mg_file_stat *filestat)
#define MG_FOPEN_MODE_APPEND
char * mg_md5(char buf[33],...)
#define STOP_FLAG_IS_TWO(f)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
static const char * suggest_connection_header(const struct mg_connection *conn)
static char * all_methods
static int alloc_vprintf(char **out_buf, char *prealloc_buf, size_t prealloc_size, const char *fmt, va_list ap)
static time_t parse_date_string(const char *datetime)
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
static void uninitialize_openssl(void)
int mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
static int parse_match_net(const struct vec *vec, const union usa *sa, int no_strict)
int mg_modify_passwords_file_ha1(const char *fname, const char *domain, const char *user, const char *ha1)
static void send_options(struct mg_connection *conn)
static int lowercase(const char *s)
static void release_handler_ref(struct mg_connection *conn, struct mg_handler_info *handler_info)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
static int mg_stat(const struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
static int get_uri_type(const char *uri)
#define DEBUG_TRACE(fmt,...)
static void get_system_name(char **sysName)
int mg_url_encode(const char *src, char *dst, size_t dst_len)
static const char * header_val(const struct mg_connection *conn, const char *header)
#define mg_cry_internal(conn, fmt,...)
static int set_acl_option(struct mg_context *phys_ctx)
static void mg_set_thread_name(const char *name)
static void get_mime_type(struct mg_connection *conn, const char *path, struct vec *vec)
static int set_blocking_mode(SOCKET sock)
#define MAX_CGI_ENVIR_VARS
static char * mg_strdup_ctx(const char *str, struct mg_context *ctx)
struct mg_connection * mg_connect_websocket_client_extensions(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, const char *extensions, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
void mg_set_user_connection_data(const struct mg_connection *const_conn, void *data)
int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence)
static int is_not_modified(const struct mg_connection *conn, const struct mg_file_stat *filestat)
static void worker_thread_run(struct mg_connection *conn)
static int prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_environment *env, int cgi_config_idx)
static const char * get_proto_name(const struct mg_connection *conn)
static void * master_thread(void *thread_func_param)
static void mg_set_handler_type(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *uri, int handler_type, int is_delete_request, mg_request_handler handler, struct mg_websocket_subprotocols *subprotocols, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, mg_authorization_handler auth_handler, void *cbdata)
static int is_file_opened(const struct mg_file_access *fileacc)
static int get_http_header_len(const char *buf, int buflen)
struct mg_connection * mg_connect_websocket_client_secure_extensions(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, const char *extensions, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
void mg_close_connection(struct mg_connection *conn)
static int is_valid_port(unsigned long port)
static void handle_propfind(struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
static void interpret_uri(struct mg_connection *conn, char *filename, size_t filename_buf_len, struct mg_file_stat *filestat, int *is_found, int *is_script_resource, int *is_websocket_request, int *is_put_or_delete_request, int *is_webdav_request, int *is_template_text)
static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
#define mg_realloc_ctx(a, b, c)
static void send_additional_header(struct mg_connection *conn)
static int push_all(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len)
static int is_put_or_delete_method(const struct mg_connection *conn)
static int read_message(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread)
#define MG_FOPEN_MODE_WRITE
void * mg_get_user_connection_data(const struct mg_connection *conn)
static int authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm)
static void send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int)
#define mg_static_assert(cond, txt)
#define SOCKET_TIMEOUT_QUANTUM
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static void dav_mkcol(struct mg_connection *conn, const char *path)
int mg_send_chunk(struct mg_connection *conn, const char *chunk, unsigned int chunk_len)
static void remove_dot_segments(char *inout)
static int get_request_handler(struct mg_connection *conn, int handler_type, mg_request_handler *handler, struct mg_websocket_subprotocols **subprotocols, mg_websocket_connect_handler *connect_handler, mg_websocket_ready_handler *ready_handler, mg_websocket_data_handler *data_handler, mg_websocket_close_handler *close_handler, mg_authorization_handler *auth_handler, void **cbdata, struct mg_handler_info **handler_info)
void mg_set_auth_handler(struct mg_context *ctx, const char *uri, mg_authorization_handler handler, void *cbdata)
int mg_start_domain2(struct mg_context *ctx, const char **options, struct mg_error_data *error)
static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
static int extention_matches_template_text(struct mg_connection *conn, const char *filename)
static int is_in_script_path(const struct mg_connection *conn, const char *path)
static int should_decode_query_string(const struct mg_connection *conn)
static double mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
static void free_context(struct mg_context *ctx)
static int sslize(struct mg_connection *conn, int(*func)(SSL *), const struct mg_client_options *client_options)
static void legacy_init(const char **options)
static void construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
int mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
static int mg_start_worker_thread(struct mg_context *ctx, int only_if_no_idle_threads)
static int refresh_trust(struct mg_connection *conn)
void * mg_get_thread_pointer(const struct mg_connection *conn)
static void mg_vsnprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap)
static int should_decode_url(const struct mg_connection *conn)
static int mg_construct_local_link(const struct mg_connection *conn, char *buf, size_t buflen, const char *define_proto, int define_port, const char *define_uri)
static int consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index, int counter_was_preincremented)
char static_assert_replacement[1]
#define ERROR_TRY_AGAIN(err)
static void send_cors_header(struct mg_connection *conn)
static unsigned char b64reverse(char letter)
static unsigned long mg_current_thread_id(void)
static void mg_strlcpy(char *dst, const char *src, size_t n)
static int remove_directory(struct mg_connection *conn, const char *dir)
static const char * get_http_version(const struct mg_connection *conn)
static __inline void * mg_calloc(size_t a, size_t b)
static int check_password_digest(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response)
static void handle_request(struct mg_connection *)
static int parse_http_response(char *buf, int len, struct mg_response_info *ri)
static void * cryptolib_dll_handle
static uint64_t mg_get_current_time_ns(void)
const char * mg_get_builtin_mime_type(const char *path)
static const char * mg_fgets(char *buf, size_t size, struct mg_file *filep)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
#define IGNORE_UNUSED_RESULT(a)
static void addenv(struct cgi_environment *env, const char *fmt,...)
static void discard_unread_request_data(struct mg_connection *conn)
int mg_strcasecmp(const char *s1, const char *s2)
static int mg_fclose(struct mg_file_access *fileacc)
static struct mg_connection * mg_connect_websocket_client_impl(const struct mg_client_options *client_options, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, const char *extensions, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
static void * worker_thread(void *thread_func_param)
static struct mg_connection * mg_connect_client_impl(const struct mg_client_options *client_options, int use_ssl, struct mg_init_data *init, struct mg_error_data *error)
static __inline void mg_free(void *a)
static void handle_request_stat_log(struct mg_connection *conn)
int mg_check_digest_access_authentication(struct mg_connection *conn, const char *realm, const char *filename)
static int mg_join_thread(pthread_t threadid)
static void mg_global_unlock(void)
int mg_get_system_info(char *buffer, int buflen)
static void handle_not_modified_static_file_request(struct mg_connection *conn, struct mg_file *filep)
static int init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
static void close_socket_gracefully(struct mg_connection *conn)
struct mg_context * mg_get_context(const struct mg_connection *conn)
static int is_ssl_port_used(const char *ports)
static void init_connection(struct mg_connection *conn)
static int print_props(struct mg_connection *conn, const char *uri, const char *name, struct mg_file_stat *filep)
static int dir_scan_callback(struct de *de, void *data)
int mg_base64_encode(const unsigned char *src, size_t src_len, char *dst, size_t *dst_len)
static void set_close_on_exec(int fd, const struct mg_connection *conn, struct mg_context *ctx)
static int get_month_index(const char *s)
void mg_set_websocket_handler_with_subprotocols(struct mg_context *ctx, const char *uri, struct mg_websocket_subprotocols *subprotocols, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
static void * ssllib_dll_handle
static int mg_fgetc(struct mg_file *filep)
static void handle_cgi_request(struct mg_connection *conn, const char *prog, int cgi_config_idx)
#define PASSWORDS_FILE_NAME
static void close_connection(struct mg_connection *conn)
static int initialize_openssl(char *ebuf, size_t ebuf_len)
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mg_file_stat *filestat)
void mg_stop(struct mg_context *ctx)
#define STRUCT_FILE_INITIALIZER
static volatile ptrdiff_t thread_idx_max
void * mg_get_user_data(const struct mg_context *ctx)
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, int(*cb)(struct de *, void *))
static int push_inner(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len, double timeout)
const char * mg_version(void)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct auth_header *auth_header)
static uint64_t get_random(void)
void mg_lock_connection(struct mg_connection *conn)
int mg_send_file_body(struct mg_connection *conn, const char *path)
static int is_valid_http_method(const char *method)
static void url_decode_in_place(char *buf)
int mg_websocket_client_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
int mg_response_header_add(struct mg_connection *conn, const char *header, const char *value, int value_len)
void *(* mg_thread_func_t)(void *)
int mg_response_header_send(struct mg_connection *conn)
@ MG_FEATURES_X_DOMAIN_SOCKET
@ MG_FEATURES_COMPRESSION
int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
@ MG_CONFIG_TYPE_DIRECTORY
@ MG_CONFIG_TYPE_EXT_PATTERN
@ MG_CONFIG_TYPE_STRING_MULTILINE
@ MG_CONFIG_TYPE_STRING_LIST
@ MG_CONFIG_TYPE_YES_NO_OPTIONAL
#define PRINTF_FORMAT_STRING(s)
int(* mg_authorization_handler)(struct mg_connection *conn, void *cbdata)
void(* mg_websocket_ready_handler)(struct mg_connection *, void *)
int mg_response_header_add_lines(struct mg_connection *conn, const char *http1_headers)
@ MG_ERROR_DATA_CODE_TLS_CONNECT_ERROR
@ MG_ERROR_DATA_CODE_INIT_LIBRARY_FAILED
@ MG_ERROR_DATA_CODE_OS_ERROR
@ MG_ERROR_DATA_CODE_MISSING_OPTION
@ MG_ERROR_DATA_CODE_CONNECT_FAILED
@ MG_ERROR_DATA_CODE_DUPLICATE_DOMAIN
@ MG_ERROR_DATA_CODE_INVALID_OPTION
@ MG_ERROR_DATA_CODE_TLS_SERVER_CERT_ERROR
@ MG_ERROR_DATA_CODE_INIT_ACL_FAILED
@ MG_ERROR_DATA_CODE_SCRIPT_ERROR
@ MG_ERROR_DATA_CODE_CONNECT_TIMEOUT
@ MG_ERROR_DATA_CODE_INIT_PORTS_FAILED
@ MG_ERROR_DATA_CODE_INVALID_PARAM
@ MG_ERROR_DATA_CODE_OUT_OF_MEMORY
@ MG_ERROR_DATA_CODE_HOST_NOT_FOUND
@ MG_ERROR_DATA_CODE_INIT_TLS_FAILED
@ MG_ERROR_DATA_CODE_INIT_USER_FAILED
@ MG_ERROR_DATA_CODE_SERVER_STOPPED
@ MG_ERROR_DATA_CODE_INVALID_PASS_FILE
@ MG_ERROR_DATA_CODE_TLS_CLIENT_CERT_ERROR
@ MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE
@ MG_WEBSOCKET_OPCODE_PONG
@ MG_WEBSOCKET_OPCODE_PING
#define PRINTF_ARGS(x, y)
int(* mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *)
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
int mg_response_header_start(struct mg_connection *conn, int status)
void(* mg_websocket_close_handler)(const struct mg_connection *, void *)
int(* mg_websocket_connect_handler)(const struct mg_connection *, void *)
static ptrdiff_t match_prefix_strlen(const char *pattern, const char *str)
static ptrdiff_t match_prefix(const char *pattern, size_t pattern_len, const char *str)
struct md5_state_s md5_state_t
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
MD5_STATIC void md5_init(md5_state_t *pms)
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
RooArgList L(Args_t &&... args)
struct asn1_integer ASN1_INTEGER
#define SSL_OP_CIPHER_SERVER_PREFERENCE
struct ssl_ctx_st SSL_CTX
#define SSL_OP_NO_TLSv1_3
#define SSL_OP_SINGLE_DH_USE
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT
#define SSL_SESS_CACHE_BOTH
#define SSL_TLSEXT_ERR_OK
#define SSL_TLSEXT_ERR_NOACK
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS
#define SSL_OP_NO_COMPRESSION
#define SSL_ERROR_SYSCALL
#define SSL_ERROR_WANT_READ
#define SSL_ERROR_WANT_ACCEPT
#define SSL_ERROR_WANT_X509_LOOKUP
#define SSL_CB_HANDSHAKE_START
#define SSL_ERROR_WANT_CONNECT
#define SSL_OP_NO_TLSv1_2
#define SSL_OP_NO_RENEGOTIATION
struct x509_name X509_NAME
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
#define TLSEXT_NAMETYPE_host_name
#define SSL_CB_HANDSHAKE_DONE
#define OPENSSL_INIT_LOAD_SSL_STRINGS
#define SSL_OP_NO_TLSv1_1
static int tls_feature_missing[TLS_END_OF_LIST]
#define SSL_ERROR_WANT_WRITE
static void free_buffered_response_header_list(struct mg_connection *conn)
SHA_API void SHA1_Init(SHA_CTX *context)
SHA_API void SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
SHA_API void SHA1_Final(unsigned char *digest, SHA_CTX *context)
static void mg_sort(void *data, size_t elemcount, size_t elemsize, int(*compfunc)(const void *data1, const void *data2, void *userarg), void *userarg)
struct mg_connection * conn
int(* init_ssl)(void *ssl_ctx, void *user_data)
int(* log_message)(const struct mg_connection *, const char *message)
void *(* init_thread)(const struct mg_context *ctx, int thread_type)
void(* end_request)(const struct mg_connection *, int reply_status_code)
int(* init_connection)(const struct mg_connection *conn, void **conn_data)
void(* connection_close)(const struct mg_connection *)
int(* http_error)(struct mg_connection *conn, int status, const char *errmsg)
void(* exit_context)(const struct mg_context *ctx)
int(* init_ssl_domain)(const char *server_domain, void *ssl_ctx, void *user_data)
int(* external_ssl_ctx)(void **ssl_ctx, void *user_data)
void(* exit_thread)(const struct mg_context *ctx, int thread_type, void *thread_pointer)
int(* begin_request)(struct mg_connection *)
int(* log_access)(const struct mg_connection *, const char *message)
void(* init_context)(const struct mg_context *ctx)
void(* connection_closed)(const struct mg_connection *)
int(* external_ssl_ctx_domain)(const char *server_domain, void **ssl_ctx, void *user_data)
time_t last_throttle_time
struct mg_response_info response_info
struct mg_request_info request_info
struct mg_context * phys_ctx
struct mg_domain_context * dom_ctx
int thread_shutdown_notification_socket
pthread_t * worker_threadids
unsigned int idle_worker_thread_count
unsigned int spawned_worker_threads
unsigned long starter_thread_idx
struct mg_connection * worker_connections
struct socket * listening_sockets
pthread_mutex_t thread_mutex
struct mg_callbacks callbacks
struct mg_domain_context dd
struct pollfd * listening_socket_fds
int user_shutdown_notification_socket
unsigned int cfg_max_worker_threads
struct twebdav_lock webdav_lock[10]
unsigned int num_listening_sockets
unsigned int max_request_size
pthread_mutex_t nonce_mutex
char * config[NUM_OPTIONS]
unsigned long nonce_count
int64_t ssl_cert_last_mtime
struct mg_domain_context * next
struct mg_handler_info * handlers
struct mg_file_access access
mg_request_handler handler
mg_authorization_handler auth_handler
mg_websocket_close_handler close_handler
struct mg_handler_info * next
mg_websocket_connect_handler connect_handler
struct mg_websocket_subprotocols * subprotocols
mg_websocket_data_handler data_handler
mg_websocket_ready_handler ready_handler
const struct mg_callbacks * callbacks
const char ** configuration_options
struct mg_header http_headers[(64)]
const char * local_uri_raw
const char * request_method
struct mg_client_cert * client_cert
const char * query_string
const char * http_version
const char * acceptedWebSocketSubprotocol
struct mg_header http_headers[(64)]
const char * http_version
const char ** subprotocols
struct auth_header auth_header
struct mg_connection * conn
unsigned char is_optional
enum ssl_func_category required
mg_websocket_close_handler close_handler
mg_websocket_data_handler data_handler
struct mg_connection * conn