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 0x0502
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(__ZEPHYR__)
195#include <sys/socket.h>
198#include <zephyr/kernel.h>
203#define MAX_WORKER_THREADS (CONFIG_MAX_PTHREAD_COUNT - 2)
205#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
206#define ZEPHYR_STACK_SIZE USE_STACK_SIZE
208#define ZEPHYR_STACK_SIZE (1024 * 16)
211K_THREAD_STACK_DEFINE(civetweb_main_stack, ZEPHYR_STACK_SIZE);
212K_THREAD_STACK_ARRAY_DEFINE(civetweb_worker_stacks,
216static int zephyr_worker_stack_index;
220#if !defined(CIVETWEB_HEADER_INCLUDED)
226#if !defined(DEBUG_TRACE)
228static void DEBUG_TRACE_FUNC(
const char *func,
233#define DEBUG_TRACE(fmt, ...) \
234 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
236#define NEED_DEBUG_TRACE_FUNC
237#if !defined(DEBUG_TRACE_STREAM)
238#define DEBUG_TRACE_STREAM stdout
242#define DEBUG_TRACE(fmt, ...) \
249#if !defined(DEBUG_ASSERT)
252#define DEBUG_ASSERT(cond) \
255 DEBUG_TRACE("ASSERTION FAILED: %s", #cond); \
260#define DEBUG_ASSERT(cond)
265#if defined(__GNUC__) && defined(GCC_INSTRUMENTATION)
266void __cyg_profile_func_enter(
void *this_fn,
void *call_site)
267 __attribute__((no_instrument_function));
269void __cyg_profile_func_exit(
void *this_fn,
void *call_site)
270 __attribute__((no_instrument_function));
273__cyg_profile_func_enter(
void *this_fn,
void *call_site)
275 if ((
void *)this_fn != (
void *)
printf) {
276 printf(
"E %p %p\n", this_fn, call_site);
281__cyg_profile_func_exit(
void *this_fn,
void *call_site)
283 if ((
void *)this_fn != (
void *)
printf) {
284 printf(
"X %p %p\n", this_fn, call_site);
290#if !defined(IGNORE_UNUSED_RESULT)
291#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
295#if defined(__GNUC__) || defined(__MINGW32__)
311#pragma GCC diagnostic ignored "-Wunused-function"
313#define FUNCTION_MAY_BE_UNUSED
316#define FUNCTION_MAY_BE_UNUSED
321#if !defined(_WIN32_WCE) && !defined(__ZEPHYR__)
327#include <sys/types.h>
331#if defined(__clang__)
335#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
338#if defined(__GNUC__) || defined(__MINGW32__)
355#if defined(__MACH__) && defined(__APPLE__)
357#if defined(__clang__)
358#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
360#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
361#pragma clang diagnostic ignored "-Wno-keyword-macro"
365#ifndef CLOCK_MONOTONIC
366#define CLOCK_MONOTONIC (1)
368#ifndef CLOCK_REALTIME
369#define CLOCK_REALTIME (2)
372#include <mach/clock.h>
373#include <mach/mach.h>
374#include <mach/mach_time.h>
375#include <sys/errno.h>
380_civet_clock_gettime(
int clk_id,
struct timespec *t)
382 memset(t, 0,
sizeof(*t));
383 if (clk_id == CLOCK_REALTIME) {
385 int rv = gettimeofday(&now,
NULL);
389 t->tv_sec = now.tv_sec;
390 t->tv_nsec = now.tv_usec * 1000;
393 }
else if (clk_id == CLOCK_MONOTONIC) {
394 static uint64_t clock_start_time = 0;
395 static mach_timebase_info_data_t timebase_ifo = {0, 0};
397 uint64_t now = mach_absolute_time();
399 if (clock_start_time == 0) {
400 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
406 clock_start_time = now;
409 now = (uint64_t)((
double)(now - clock_start_time)
410 * (
double)timebase_ifo.numer
411 / (double)timebase_ifo.denom);
413 t->tv_sec = now / 1000000000;
414 t->tv_nsec = now % 1000000000;
421#if defined(__CLOCK_AVAILABILITY)
426_civet_safe_clock_gettime(
int clk_id,
struct timespec *t)
429 return clock_gettime(clk_id, t);
431 return _civet_clock_gettime(clk_id, t);
433#define clock_gettime _civet_safe_clock_gettime
435#define clock_gettime _civet_clock_gettime
442#define ERROR_TRY_AGAIN(err) ((err) == WSAEWOULDBLOCK)
447#define ERROR_TRY_AGAIN(err) \
448 (((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR))
464#if !defined(MAX_WORKER_THREADS)
465#define MAX_WORKER_THREADS (1024 * 64)
472#if !defined(SOCKET_TIMEOUT_QUANTUM)
473#define SOCKET_TIMEOUT_QUANTUM (2000)
477#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT)
478#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024)
481#if !defined(PASSWORDS_FILE_NAME)
482#define PASSWORDS_FILE_NAME ".htpasswd"
487#if !defined(CGI_ENVIRONMENT_SIZE)
488#define CGI_ENVIRONMENT_SIZE (4096)
492#if !defined(MAX_CGI_ENVIR_VARS)
493#define MAX_CGI_ENVIR_VARS (256)
497#if !defined(MG_BUF_LEN)
498#define MG_BUF_LEN (1024 * 8)
505#if !defined(ARRAY_SIZE)
506#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
512#if !defined(INT64_MAX)
513#define INT64_MAX (9223372036854775807)
516#define SHUTDOWN_RD (0)
517#define SHUTDOWN_WR (1)
518#define SHUTDOWN_BOTH (2)
521 "worker threads must be a positive number");
524 "size_t data type size check");
542#define UTF8_PATH_MAX (3 * 260)
545#define UTF16_PATH_MAX (260)
547#if !defined(_IN_PORT_T)
548#if !defined(in_port_t)
549#define in_port_t u_short
553#if defined(_WIN32_WCE)
554#error "WinCE support has ended"
562#define MAKEUQUAD(lo, hi) \
563 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
564#define RATE_DIFF (10000000)
565#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
566#define SYS2UNIX_TIME(lo, hi) \
567 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
575#define STR(x) STRX(x)
576#define __func__ __FILE__ ":" STR(__LINE__)
577#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
578#define strtoll(x, y, z) (_atoi64(x))
580#define __func__ __FUNCTION__
581#define strtoull(x, y, z) (_strtoui64(x, y, z))
582#define strtoll(x, y, z) (_strtoi64(x, y, z))
587#define ERRNO ((int)(GetLastError()))
591#if defined(_WIN64) || defined(__MINGW64__)
594#if defined(OPENSSL_API_3_0)
595#define SSL_LIB "libssl-3-x64.dll"
596#define CRYPTO_LIB "libcrypto-3-x64.dll"
599#if defined(OPENSSL_API_1_1)
600#define SSL_LIB "libssl-1_1-x64.dll"
601#define CRYPTO_LIB "libcrypto-1_1-x64.dll"
604#if defined(OPENSSL_API_1_0)
605#define SSL_LIB "ssleay64.dll"
606#define CRYPTO_LIB "libeay64.dll"
613#if defined(OPENSSL_API_3_0)
614#define SSL_LIB "libssl-3.dll"
615#define CRYPTO_LIB "libcrypto-3.dll"
618#if defined(OPENSSL_API_1_1)
619#define SSL_LIB "libssl-1_1.dll"
620#define CRYPTO_LIB "libcrypto-1_1.dll"
623#if defined(OPENSSL_API_1_0)
624#define SSL_LIB "ssleay32.dll"
625#define CRYPTO_LIB "libeay32.dll"
632#define O_NONBLOCK (0)
637#define INT64_FMT "I64d"
638#define UINT64_FMT "I64u"
640#define WINCDECL __cdecl
641#define vsnprintf_impl _vsnprintf
642#define access _access
643#define mg_sleep(x) (Sleep(x))
645#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
647#define popen(x, y) (_popen(x, y))
650#define pclose(x) (_pclose(x))
652#define close(x) (_close(x))
653#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
655#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
656#define fdopen(x, y) (_fdopen((x), (y)))
657#define write(x, y, z) (_write((x), (y), (unsigned)z))
658#define read(x, y, z) (_read((x), (y), (unsigned)z))
659#define flockfile(x) ((void)pthread_mutex_lock(&global_log_file_lock))
660#define funlockfile(x) ((void)pthread_mutex_unlock(&global_log_file_lock))
661#define sleep(x) (Sleep((x)*1000))
662#define rmdir(x) (_rmdir(x))
663#if defined(_WIN64) || !defined(__MINGW32__)
665#define timegm(x) (_mkgmtime(x))
667time_t timegm(
struct tm *tm);
673#define fileno(x) (_fileno(x))
677 CRITICAL_SECTION sec;
679typedef DWORD pthread_key_t;
680typedef HANDLE pthread_t;
682 pthread_mutex_t threadIdSec;
686#if !defined(__clockid_t_defined)
687typedef DWORD clockid_t;
689#if !defined(CLOCK_MONOTONIC)
690#define CLOCK_MONOTONIC (1)
692#if !defined(CLOCK_REALTIME)
693#define CLOCK_REALTIME (2)
695#if !defined(CLOCK_THREAD)
696#define CLOCK_THREAD (3)
698#if !defined(CLOCK_PROCESS)
699#define CLOCK_PROCESS (4)
703#if defined(_MSC_VER) && (_MSC_VER >= 1900)
704#define _TIMESPEC_DEFINED
706#if !defined(_TIMESPEC_DEFINED)
713#if !defined(WIN_PTHREADS_TIME_H)
714#define MUST_IMPLEMENT_CLOCK_GETTIME
717#if defined(MUST_IMPLEMENT_CLOCK_GETTIME)
718#define clock_gettime mg_clock_gettime
720clock_gettime(clockid_t clk_id,
struct timespec *tp)
723 ULARGE_INTEGER li, li2;
726 static double perfcnt_per_sec = 0.0;
727 static BOOL initialized =
FALSE;
730 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
731 perfcnt_per_sec = 1.0 / li.QuadPart;
736 memset(tp, 0,
sizeof(*tp));
738 if (clk_id == CLOCK_REALTIME) {
741 GetSystemTimeAsFileTime(&ft);
742 li.LowPart = ft.dwLowDateTime;
743 li.HighPart = ft.dwHighDateTime;
744 li.QuadPart -= 116444736000000000;
745 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
746 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
750 }
else if (clk_id == CLOCK_MONOTONIC) {
753 QueryPerformanceCounter((LARGE_INTEGER *)&li);
754 d = li.QuadPart * perfcnt_per_sec;
755 tp->tv_sec = (time_t)d;
756 d -= (double)tp->tv_sec;
757 tp->tv_nsec = (long)(d * 1.0E9);
761 }
else if (clk_id == CLOCK_THREAD) {
764 FILETIME t_create, t_exit, t_kernel, t_user;
765 if (GetThreadTimes(GetCurrentThread(),
770 li.LowPart = t_user.dwLowDateTime;
771 li.HighPart = t_user.dwHighDateTime;
772 li2.LowPart = t_kernel.dwLowDateTime;
773 li2.HighPart = t_kernel.dwHighDateTime;
774 li.QuadPart += li2.QuadPart;
775 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
776 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
781 }
else if (clk_id == CLOCK_PROCESS) {
784 FILETIME t_create, t_exit, t_kernel, t_user;
785 if (GetProcessTimes(GetCurrentProcess(),
790 li.LowPart = t_user.dwLowDateTime;
791 li.HighPart = t_user.dwHighDateTime;
792 li2.LowPart = t_kernel.dwLowDateTime;
793 li2.HighPart = t_kernel.dwHighDateTime;
794 li.QuadPart += li2.QuadPart;
795 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
796 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
816static int pthread_mutex_lock(pthread_mutex_t *);
817static int pthread_mutex_unlock(pthread_mutex_t *);
827static const char *
mg_fgets(
char *buf,
size_t size,
struct mg_file *filep);
837 WIN32_FIND_DATAW info;
838 struct dirent result;
841#if defined(HAVE_POLL)
842#define mg_pollfd pollfd
853#pragma comment(lib, "Ws2_32.lib")
861#define UTF8_PATH_MAX (PATH_MAX)
866typedef unsigned short int in_port_t;
869#if !defined(__ZEPHYR__)
870#include <arpa/inet.h>
876#include <netinet/in.h>
877#include <netinet/tcp.h>
886#include <sys/socket.h>
888#include <sys/utsname.h>
892#if defined(USE_X_DOM_SOCKET)
897#define vsnprintf_impl vsnprintf
899#if !defined(NO_SSL_DL) && !defined(NO_SSL)
903#if defined(__MACH__) && defined(__APPLE__)
904#define SSL_LIB "libssl.dylib"
905#define CRYPTO_LIB "libcrypto.dylib"
908#define SSL_LIB "libssl.so"
910#if !defined(CRYPTO_LIB)
911#define CRYPTO_LIB "libcrypto.so"
914#if !defined(O_BINARY)
917#define closesocket(a) (close(a))
918#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
919#define mg_remove(conn, x) (remove(x))
920#define mg_sleep(x) (usleep((x)*1000))
921#define mg_opendir(conn, x) (opendir(x))
922#define mg_closedir(x) (closedir(x))
923#define mg_readdir(x) (readdir(x))
925#define INVALID_SOCKET (-1)
926#define INT64_FMT PRId64
927#define UINT64_FMT PRIu64
933#if !defined(CLOCK_MONOTONIC)
934#define CLOCK_MONOTONIC CLOCK_REALTIME
948#define mg_pollfd pollfd
953#if defined(NEED_TIMEGM)
957 return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
963 return (y - 1969) / 4 - (y - 1901) / 100 + (y - 1601) / 400;
969 static const unsigned short ydays[] = {
970 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
971 int year = tm->tm_year + 1900;
972 int mon = tm->tm_mon;
973 int mday = tm->tm_mday - 1;
974 int hour = tm->tm_hour;
975 int min = tm->tm_min;
976 int sec = tm->tm_sec;
978 if (year < 1970 || mon < 0 || mon > 11 || mday < 0
979 || (mday >= ydays[mon + 1] - ydays[mon]
980 + (mon == 1 && is_leap(year) ? 1 : 0))
981 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60)
984 time_t res = year - 1970;
987 res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0);
988 res += count_leap(year);
1002#if !defined(va_copy)
1003#define va_copy(x, y) ((x) = (y))
1010#if defined(GCC_DIAGNOSTIC)
1012#pragma GCC diagnostic push
1013#pragma GCC diagnostic ignored "-Wunused-function"
1017static pthread_mutex_t global_log_file_lock;
1023 return GetCurrentThreadId();
1031 void (*_ignored)(
void *)
1038 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
1046pthread_key_delete(pthread_key_t key)
1048 return TlsFree(key) ? 0 : 1;
1054pthread_setspecific(pthread_key_t key,
void *
value)
1056 return TlsSetValue(key,
value) ? 0 : 1;
1062pthread_getspecific(pthread_key_t key)
1064 return TlsGetValue(key);
1067#if defined(GCC_DIAGNOSTIC)
1069#pragma GCC diagnostic pop
1078#if defined(GCC_DIAGNOSTIC)
1080#pragma GCC diagnostic push
1081#pragma GCC diagnostic ignored "-Wunused-function"
1083#if defined(__clang__)
1085#pragma clang diagnostic push
1086#pragma clang diagnostic ignored "-Wunused-function"
1110#elif defined(_WIN32)
1125#if defined(_WIN64) && !defined(NO_ATOMICS)
1126 ret = InterlockedIncrement64(addr);
1127#elif defined(_WIN32) && !defined(NO_ATOMICS)
1128 ret = InterlockedIncrement(addr);
1129#elif defined(__GNUC__) \
1130 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1131 && !defined(NO_ATOMICS)
1132 ret = __sync_add_and_fetch(addr, 1);
1148#if defined(_WIN64) && !defined(NO_ATOMICS)
1149 ret = InterlockedDecrement64(addr);
1150#elif defined(_WIN32) && !defined(NO_ATOMICS)
1151 ret = InterlockedDecrement(addr);
1152#elif defined(__GNUC__) \
1153 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1154 && !defined(NO_ATOMICS)
1155 ret = __sync_sub_and_fetch(addr, 1);
1165#if defined(USE_SERVER_STATS) || defined(STOP_FLAG_NEEDS_LOCK)
1167mg_atomic_add(
volatile ptrdiff_t *addr, ptrdiff_t
value)
1171#if defined(_WIN64) && !defined(NO_ATOMICS)
1172 ret = InterlockedAdd64(addr,
value);
1173#elif defined(_WIN32) && !defined(NO_ATOMICS)
1174 ret = InterlockedExchangeAdd(addr,
value) +
value;
1175#elif defined(__GNUC__) \
1176 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1177 && !defined(NO_ATOMICS)
1178 ret = __sync_add_and_fetch(addr,
value);
1191mg_atomic_compare_and_swap(
volatile ptrdiff_t *addr,
1197#if defined(_WIN64) && !defined(NO_ATOMICS)
1198 ret = InterlockedCompareExchange64(addr, newval, oldval);
1199#elif defined(_WIN32) && !defined(NO_ATOMICS)
1200 ret = InterlockedCompareExchange(addr, newval, oldval);
1201#elif defined(__GNUC__) \
1202 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1203 && !defined(NO_ATOMICS)
1204 ret = __sync_val_compare_and_swap(addr, oldval, newval);
1208 if ((ret != newval) && (ret == oldval)) {
1218mg_atomic_max(
volatile ptrdiff_t *addr, ptrdiff_t
value)
1220 register ptrdiff_t tmp = *addr;
1222#if defined(_WIN64) && !defined(NO_ATOMICS)
1223 while (tmp <
value) {
1224 tmp = InterlockedCompareExchange64(addr,
value, tmp);
1226#elif defined(_WIN32) && !defined(NO_ATOMICS)
1227 while (tmp <
value) {
1228 tmp = InterlockedCompareExchange(addr,
value, tmp);
1230#elif defined(__GNUC__) \
1231 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1232 && !defined(NO_ATOMICS)
1233 while (tmp <
value) {
1234 tmp = __sync_val_compare_and_swap(addr, tmp,
value);
1238 if (*addr <
value) {
1247mg_atomic_add64(
volatile int64_t *addr, int64_t
value)
1251#if defined(_WIN64) && !defined(NO_ATOMICS)
1252 ret = InterlockedAdd64(addr,
value);
1253#elif defined(_WIN32) && !defined(NO_ATOMICS)
1254 ret = InterlockedExchangeAdd64(addr,
value) +
value;
1255#elif defined(__GNUC__) \
1256 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1257 && !defined(NO_ATOMICS)
1258 ret = __sync_add_and_fetch(addr,
value);
1270#if defined(GCC_DIAGNOSTIC)
1272#pragma GCC diagnostic pop
1274#if defined(__clang__)
1276#pragma clang diagnostic pop
1280#if defined(USE_SERVER_STATS)
1282struct mg_memory_stat {
1283 volatile ptrdiff_t totalMemUsed;
1284 volatile ptrdiff_t maxMemUsed;
1285 volatile ptrdiff_t blockCount;
1289static struct mg_memory_stat *get_memory_stat(
struct mg_context *ctx);
1293mg_malloc_ex(
size_t size,
1298 void *data =
malloc(size + 2 *
sizeof(uintptr_t));
1300 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1302#if defined(MEMORY_DEBUGGING)
1303 char mallocStr[256];
1310 ptrdiff_t mmem = mg_atomic_add(&mstat->totalMemUsed, (ptrdiff_t)size);
1311 mg_atomic_max(&mstat->maxMemUsed, mmem);
1314 ((uintptr_t *)data)[0] = size;
1315 ((uintptr_t *)data)[1] = (uintptr_t)mstat;
1316 memory = (
void *)(((
char *)data) + 2 *
sizeof(uintptr_t));
1319#if defined(MEMORY_DEBUGGING)
1321 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1323 (
unsigned long)size,
1324 (
unsigned long)mstat->totalMemUsed,
1325 (
unsigned long)mstat->blockCount,
1336mg_calloc_ex(
size_t count,
1342 void *data = mg_malloc_ex(size * count, ctx, file, line);
1345 memset(data, 0, size * count);
1352mg_free_ex(
void *memory,
const char *file,
unsigned line)
1354#if defined(MEMORY_DEBUGGING)
1355 char mallocStr[256];
1362 void *data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1363 uintptr_t size = ((uintptr_t *)data)[0];
1364 struct mg_memory_stat *mstat =
1365 (
struct mg_memory_stat *)(((uintptr_t *)data)[1]);
1366 mg_atomic_add(&mstat->totalMemUsed, -(ptrdiff_t)size);
1369#if defined(MEMORY_DEBUGGING)
1371 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1373 (
unsigned long)size,
1374 (
unsigned long)mstat->totalMemUsed,
1375 (
unsigned long)mstat->blockCount,
1386mg_realloc_ex(
void *memory,
1396#if defined(MEMORY_DEBUGGING)
1397 char mallocStr[256];
1406 struct mg_memory_stat *mstat;
1407 data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1408 oldsize = ((uintptr_t *)data)[0];
1409 mstat = (
struct mg_memory_stat *)((uintptr_t *)data)[1];
1410 _realloc =
realloc(data, newsize + 2 *
sizeof(uintptr_t));
1413 mg_atomic_add(&mstat->totalMemUsed, -(ptrdiff_t)oldsize);
1414#if defined(MEMORY_DEBUGGING)
1416 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1418 (
unsigned long)oldsize,
1419 (
unsigned long)mstat->totalMemUsed,
1420 (
unsigned long)mstat->blockCount,
1425 mg_atomic_add(&mstat->totalMemUsed, (ptrdiff_t)newsize);
1427#if defined(MEMORY_DEBUGGING)
1429 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1431 (
unsigned long)newsize,
1432 (
unsigned long)mstat->totalMemUsed,
1433 (
unsigned long)mstat->blockCount,
1438 *(uintptr_t *)data = newsize;
1439 data = (
void *)(((
char *)data) + 2 *
sizeof(uintptr_t));
1441#if defined(MEMORY_DEBUGGING)
1448 data = mg_malloc_ex(newsize, ctx, file, line);
1453 mg_free_ex(memory, file, line);
1460#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
1461#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
1462#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
1463#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1465#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
1466#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
1467#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
1473static __inline
void *
1479static __inline
void *
1485static __inline
void *
1497#define mg_malloc_ctx(a, c) mg_malloc(a)
1498#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
1499#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
1500#define mg_free_ctx(a, c) mg_free(a)
1533#if defined(snprintf)
1536#if defined(vsnprintf)
1539#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1540#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1541#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1542#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1543#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
1547#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1555#if defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
1556 || defined(OPENSSL_API_3_0)
1557static int mg_openssl_initialized = 0;
1559#if !defined(OPENSSL_API_1_0) && !defined(OPENSSL_API_1_1) \
1560 && !defined(OPENSSL_API_3_0) && !defined(USE_MBEDTLS)
1561#error "Please define OPENSSL_API_#_# or USE_MBEDTLS"
1563#if defined(OPENSSL_API_1_0) && defined(OPENSSL_API_1_1)
1564#error "Multiple OPENSSL_API versions defined"
1566#if defined(OPENSSL_API_1_1) && defined(OPENSSL_API_3_0)
1567#error "Multiple OPENSSL_API versions defined"
1569#if defined(OPENSSL_API_1_0) && defined(OPENSSL_API_3_0)
1570#error "Multiple OPENSSL_API versions defined"
1572#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
1573 || defined(OPENSSL_API_3_0)) \
1574 && defined(USE_MBEDTLS)
1575#error "Multiple SSL libraries defined"
1583#if defined(MG_LEGACY_INTERFACE)
1584#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
1592 HANDLE pthread_cond_helper_mutex;
1596#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
1602#if defined(GCC_DIAGNOSTIC)
1604#pragma GCC diagnostic push
1605#pragma GCC diagnostic ignored "-Wunused-function"
1607#if defined(__clang__)
1609#pragma clang diagnostic push
1610#pragma clang diagnostic ignored "-Wunused-function"
1629 return GetCurrentThreadId();
1632#if defined(__clang__)
1633#pragma clang diagnostic push
1634#pragma clang diagnostic ignored "-Wunreachable-code"
1642 if (
sizeof(pthread_t) >
sizeof(
unsigned long)) {
1653 pthread_setspecific(
sTlsKey, tls);
1660 unsigned long ret = 0;
1661 pthread_t t = pthread_self();
1662 memcpy(&ret, &t,
sizeof(pthread_t));
1666#if defined(__clang__)
1667#pragma clang diagnostic pop
1678 struct timespec tsnow;
1679 clock_gettime(CLOCK_REALTIME, &tsnow);
1680 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1684#if defined(GCC_DIAGNOSTIC)
1686#pragma GCC diagnostic pop
1688#if defined(__clang__)
1690#pragma clang diagnostic pop
1694#if defined(NEED_DEBUG_TRACE_FUNC)
1696DEBUG_TRACE_FUNC(
const char *func,
unsigned line,
const char *fmt, ...)
1699 struct timespec tsnow;
1704 clock_gettime(CLOCK_REALTIME, &tsnow);
1706 flockfile(DEBUG_TRACE_STREAM);
1707 fprintf(DEBUG_TRACE_STREAM,
1708 "*** %lu.%09lu %lu %s:%u: ",
1709 (
unsigned long)tsnow.tv_sec,
1710 (
unsigned long)tsnow.tv_nsec,
1714 va_start(args, fmt);
1715 vfprintf(DEBUG_TRACE_STREAM, fmt, args);
1717 putc(
'\n', DEBUG_TRACE_STREAM);
1718 fflush(DEBUG_TRACE_STREAM);
1719 funlockfile(DEBUG_TRACE_STREAM);
1724#define MD5_STATIC static
1728#if defined(NO_SOCKLEN_T)
1729typedef int socklen_t;
1732#define IP_ADDR_STR_LEN (50)
1734#if !defined(MSG_NOSIGNAL)
1735#define MSG_NOSIGNAL (0)
1740#if defined(USE_MBEDTLS)
1742#include "mod_mbedtls.inl"
1744#elif defined(NO_SSL)
1746typedef struct SSL SSL;
1747typedef struct SSL_CTX SSL_CTX;
1749#elif defined(NO_SSL_DL)
1751#include <openssl/bn.h>
1752#include <openssl/conf.h>
1753#include <openssl/crypto.h>
1754#include <openssl/dh.h>
1755#include <openssl/engine.h>
1756#include <openssl/err.h>
1757#include <openssl/opensslv.h>
1758#include <openssl/pem.h>
1759#include <openssl/ssl.h>
1760#include <openssl/tls1.h>
1761#include <openssl/x509.h>
1763#if defined(WOLFSSL_VERSION)
1766#include "wolfssl_extras.inl"
1769#if defined(OPENSSL_IS_BORINGSSL)
1780#define CONF_modules_unload(a) ((void)0)
1781#define ENGINE_cleanup() ((void)0)
1785#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1786#if !defined(OPENSSL_API_3_0)
1787#define OPENSSL_API_3_0
1789#define OPENSSL_REMOVE_THREAD_STATE()
1791#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1792#if !defined(OPENSSL_API_1_1)
1793#define OPENSSL_API_1_1
1795#define OPENSSL_REMOVE_THREAD_STATE()
1797#if !defined(OPENSSL_API_1_0)
1798#define OPENSSL_API_1_0
1800#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_thread_state(NULL)
1809#include "openssl_dl.inl"
1814#if !defined(NO_CACHING)
1835#if defined(USE_IPV6)
1836 struct sockaddr_in6 sin6;
1838#if defined(USE_X_DOM_SOCKET)
1839 struct sockaddr_un sun;
1843#if defined(USE_X_DOM_SOCKET)
1844static unsigned short
1847 if (
s->sa.sa_family == AF_INET)
1848 return s->
sin.sin_port;
1849#if defined(USE_IPV6)
1850 if (
s->sa.sa_family == AF_INET6)
1851 return s->sin6.sin6_port;
1856#if defined(USE_IPV6)
1857#define USA_IN_PORT_UNSAFE(s) \
1858 (((s)->sa.sa_family == AF_INET6) ? (s)->sin6.sin6_port : (s)->sin.sin_port)
1860#define USA_IN_PORT_UNSAFE(s) ((s)->sin.sin_port)
1891#define STRUCT_FILE_INITIALIZER \
1893 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
1929#if defined(__linux__)
1930 ALLOW_SENDFILE_CALL,
1933 CASE_SENSITIVE_FILES,
1939#if defined(USE_WEBSOCKET)
1941 ENABLE_WEBSOCKET_PING_PONG,
1946 LUA_BACKGROUND_SCRIPT,
1947 LUA_BACKGROUND_SCRIPT_PARAMS,
1949#if defined(USE_HTTP2)
1963#if defined(USE_TIMERS)
1972#if defined(USE_TIMERS)
1977#if defined(USE_4_CGI)
1981 CGI3_INTERPRETER_ARGS,
1982#if defined(USE_TIMERS)
1990 CGI4_INTERPRETER_ARGS,
1991#if defined(USE_TIMERS)
2024 LUA_SCRIPT_EXTENSIONS,
2025 LUA_SERVER_PAGE_EXTENSIONS,
2026#if defined(MG_EXPERIMENTAL_INTERFACES)
2030#if defined(USE_DUKTAPE)
2031 DUKTAPE_SCRIPT_EXTENSIONS,
2034#if defined(USE_WEBSOCKET)
2037#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2038 LUA_WEBSOCKET_EXTENSIONS,
2045#if !defined(NO_CACHING)
2073#if defined(__linux__)
2083#if defined(USE_WEBSOCKET)
2093#if defined(USE_HTTP2)
2107#if defined(USE_TIMERS)
2116#if defined(USE_TIMERS)
2121#if defined(USE_4_CGI)
2126#if defined(USE_TIMERS)
2135#if defined(USE_TIMERS)
2153 "index.xhtml,index.html,index.htm,"
2154 "index.lp,index.lsp,index.lua,index.cgi,"
2155 "index.shtml,index.php"},
2157 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2185#if defined(MG_EXPERIMENTAL_INTERFACES)
2189#if defined(USE_DUKTAPE)
2195#if defined(USE_WEBSOCKET)
2198#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2205#if !defined(NO_CACHING)
2222 "config_options and enum not sync");
2279#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2281 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2292#if defined(STOP_FLAG_NEEDS_LOCK)
2315 sf = mg_atomic_compare_and_swap(f, *f, v);
2322#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0)
2323#define STOP_FLAG_IS_TWO(f) ((*(f)) == 2)
2324#define STOP_FLAG_ASSIGN(f, v) ((*(f)) = (v))
2329#if !defined(NUM_WEBDAV_LOCKS)
2330#define NUM_WEBDAV_LOCKS 10
2332#if !defined(LOCK_DURATION_S)
2333#define LOCK_DURATION_S 60
2363#if defined(USE_SERVER_STATS)
2364 volatile ptrdiff_t active_connections;
2365 volatile ptrdiff_t max_active_connections;
2366 volatile ptrdiff_t total_connections;
2367 volatile ptrdiff_t total_requests;
2368 volatile int64_t total_data_read;
2369 volatile int64_t total_data_written;
2383#if defined(ALTERNATIVE_QUEUE)
2384 struct socket *client_socks;
2385 void **client_wait_events;
2395#if defined(USE_SERVER_STATS)
2403#if defined(USE_SERVER_STATS)
2404 struct mg_memory_stat ctx_memory;
2415#if defined(USE_TIMERS)
2416 struct ttimers *timers;
2421 void *lua_background_state;
2422 pthread_mutex_t lua_bg_mutex;
2423 int lua_bg_log_available;
2446#if defined(USE_SERVER_STATS)
2447static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2449static struct mg_memory_stat *
2453 return &(ctx->ctx_memory);
2455 return &mg_common_memory;
2472#if defined(USE_HTTP2)
2473#if !defined(HTTP2_DYN_TABLE_SIZE)
2474#define HTTP2_DYN_TABLE_SIZE (256)
2477struct mg_http2_connection {
2479 uint32_t dyn_table_size;
2480 struct mg_header dyn_table[HTTP2_DYN_TABLE_SIZE];
2490#if defined(USE_HTTP2)
2491 struct mg_http2_connection http2;
2500#if defined(USE_SERVER_STATS)
2510#if defined(USE_SERVER_STATS)
2511 time_t conn_close_time;
2513 double processing_time;
2539#if defined(USE_WEBSOCKET)
2540 int in_websocket_handling;
2542#if defined(USE_ZLIB) && defined(USE_WEBSOCKET) \
2543 && defined(MG_EXPERIMENTAL_INTERFACES)
2545 int websocket_deflate_server_max_windows_bits;
2546 int websocket_deflate_client_max_windows_bits;
2547 int websocket_deflate_server_no_context_takeover;
2548 int websocket_deflate_client_no_context_takeover;
2549 int websocket_deflate_initialized;
2550 int websocket_deflate_flush;
2551 z_stream websocket_deflate_state;
2552 z_stream websocket_inflate_state;
2567#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2568 void *lua_websocket_state;
2583#define mg_cry_internal(conn, fmt, ...) \
2584 mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__)
2586#define mg_cry_ctx_internal(ctx, fmt, ...) \
2587 mg_cry_internal_wrap(NULL, ctx, __func__, __LINE__, fmt, __VA_ARGS__)
2597#if !defined(NO_THREAD_NAME)
2598#if defined(_WIN32) && defined(_MSC_VER)
2602#pragma pack(push, 8)
2603typedef struct tagTHREADNAME_INFO {
2611#elif defined(__linux__)
2613#include <sys/prctl.h>
2614#include <sys/sendfile.h>
2615#if defined(ALTERNATIVE_QUEUE)
2616#include <sys/eventfd.h>
2620#if defined(ALTERNATIVE_QUEUE)
2625 int evhdl = eventfd(0, EFD_CLOEXEC);
2646event_wait(
void *eventhdl)
2655 evhdl = *(
int *)eventhdl;
2657 s = (int)read(evhdl, &u,
sizeof(u));
2658 if (
s !=
sizeof(u)) {
2668event_signal(
void *eventhdl)
2677 evhdl = *(
int *)eventhdl;
2679 s = (int)write(evhdl, &u,
sizeof(u));
2680 if (
s !=
sizeof(u)) {
2689event_destroy(
void *eventhdl)
2697 evhdl = *(
int *)eventhdl;
2709#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
2712 pthread_mutex_t
mutex;
2713 pthread_cond_t
cond;
2721 struct posix_event *ret =
mg_malloc(
sizeof(
struct posix_event));
2726 if (0 != pthread_mutex_init(&(ret->mutex),
NULL)) {
2731 if (0 != pthread_cond_init(&(ret->cond),
NULL)) {
2733 pthread_mutex_destroy(&(ret->mutex));
2743event_wait(
void *eventhdl)
2745 struct posix_event *ev = (
struct posix_event *)eventhdl;
2746 pthread_mutex_lock(&(ev->mutex));
2747 while (!ev->signaled) {
2748 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2751 pthread_mutex_unlock(&(ev->mutex));
2757event_signal(
void *eventhdl)
2759 struct posix_event *ev = (
struct posix_event *)eventhdl;
2760 pthread_mutex_lock(&(ev->mutex));
2761 pthread_cond_signal(&(ev->cond));
2763 pthread_mutex_unlock(&(ev->mutex));
2769event_destroy(
void *eventhdl)
2771 struct posix_event *ev = (
struct posix_event *)eventhdl;
2772 pthread_cond_destroy(&(ev->cond));
2773 pthread_mutex_destroy(&(ev->mutex));
2782 char threadName[16 + 1];
2785 NULL,
NULL, threadName,
sizeof(threadName),
"civetweb-%s",
name);
2788#if defined(_MSC_VER)
2791 THREADNAME_INFO info;
2792 info.dwType = 0x1000;
2793 info.szName = threadName;
2794 info.dwThreadID = ~0U;
2797 RaiseException(0x406D1388,
2799 sizeof(info) /
sizeof(ULONG_PTR),
2800 (ULONG_PTR *)&info);
2801 } __except (EXCEPTION_EXECUTE_HANDLER) {
2803#elif defined(__MINGW32__)
2806#elif defined(_GNU_SOURCE) && defined(__GLIBC__) \
2807 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
2809#if defined(__MACH__) && defined(__APPLE__)
2811 (void)pthread_setname_np(threadName);
2813 (void)pthread_setname_np(pthread_self(), threadName);
2815#elif defined(__linux__)
2821 (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
2840#define MG_FOPEN_MODE_NONE (0)
2843#define MG_FOPEN_MODE_READ (1)
2846#define MG_FOPEN_MODE_WRITE (2)
2849#define MG_FOPEN_MODE_APPEND (4)
2859 return (fileacc->
fp !=
NULL);
2863#if !defined(NO_FILESYSTEMS)
2873 const uint8_t *c = (
const uint8_t *)path;
2876 if ((c ==
NULL) || (c[0] == 0)) {
2887 if ((*c ==
'>') || (*c ==
'<') || (*c ==
'|')) {
2891 if ((*c ==
'*') || (*c ==
'?')) {
2942 wchar_t wbuf[UTF16_PATH_MAX];
2943 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
2946 filep->
access.
fp = _wfopen(wbuf, L
"rb");
2949 filep->
access.
fp = _wfopen(wbuf, L
"wb");
2952 filep->
access.
fp = _wfopen(wbuf, L
"ab");
2960 filep->
access.
fp = fopen(path,
"r");
2963 filep->
access.
fp = fopen(path,
"w");
2966 filep->
access.
fp = fopen(path,
"a");
2989 if (fileacc !=
NULL) {
2990 if (fileacc->
fp !=
NULL) {
2991 ret = fclose(fileacc->
fp);
2994 memset(fileacc, 0,
sizeof(*fileacc));
3004 for (; *src !=
'\0' && n > 1; n--) {
3014 return tolower((
unsigned char)*
s);
3026 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
3040 }
while (diff == 0 && s1[-1] !=
'\0');
3077 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3079 if (big_len >= small_len) {
3080 for (i = 0; i <= (big_len - small_len); i++) {
3110#if defined(__clang__)
3111#pragma clang diagnostic push
3112#pragma clang diagnostic ignored "-Wformat-nonliteral"
3118 ok = (n >= 0) && ((
size_t)n < buflen);
3120#if defined(__clang__)
3121#pragma clang diagnostic pop
3133 "truncating vsnprintf buffer: [%.*s]",
3134 (
int)((buflen > 200) ? 200 : (buflen - 1)),
3136 n = (int)buflen - 1;
3185#define mg_get_option DO_NOT_USE_THIS_FUNCTION_INTERNALLY__access_directly
3227 if (const_conn !=
NULL) {
3257 memset(ports, 0,
sizeof(*ports) * (
size_t)size);
3287#if defined(USE_X_DOM_SOCKET) && !defined(UNIX_DOMAIN_SOCKET_SERVER_NAME)
3288#define UNIX_DOMAIN_SOCKET_SERVER_NAME "*"
3300 if (
usa->
sa.sa_family == AF_INET) {
3301 getnameinfo(&
usa->
sa,
3309#if defined(USE_IPV6)
3310 else if (
usa->
sa.sa_family == AF_INET6) {
3311 getnameinfo(&
usa->
sa,
3320#if defined(USE_X_DOM_SOCKET)
3321 else if (
usa->
sa.sa_family == AF_UNIX) {
3343#if !defined(REENTRANT_TIME)
3346 tm = ((t !=
NULL) ? gmtime(t) :
NULL);
3350 struct tm *tm = &_tm;
3355 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", tm);
3357 mg_strlcpy(buf,
"Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3366 return (
double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3367 + (
double)(ts_now->tv_sec - ts_before->tv_sec);
3371#if defined(MG_EXTERNAL_FUNCTION_mg_cry_internal_impl)
3377#include "external_mg_cry_internal_impl.inl"
3378#elif !defined(NO_FILESYSTEMS)
3396#if defined(GCC_DIAGNOSTIC)
3397#pragma GCC diagnostic push
3398#pragma GCC diagnostic ignored "-Wformat-nonliteral"
3403#if defined(GCC_DIAGNOSTIC)
3404#pragma GCC diagnostic pop
3407 buf[
sizeof(buf) - 1] = 0;
3409 DEBUG_TRACE(
"mg_cry called from %s:%u: %s", func, line, buf);
3436 timestamp = time(
NULL);
3440 "[%010lu] [error] [client %s] ",
3441 (
unsigned long)timestamp,
3463#error Must either enable filesystems or provide a custom mg_cry_internal_impl implementation
3510#define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
3526#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3533 if (strlen(txt) == 3) {
3534 memcpy(tls->txtbuf, txt, 4);
3536 strcpy(tls->txtbuf,
"ERR");
3541 ((
struct mg_connection *)conn)->request_info.local_uri_raw =
3576#if defined(__clang__)
3577#pragma clang diagnostic push
3578#pragma clang diagnostic ignored "-Wunreachable-code"
3589 ? (ri->
is_ssl ?
"wss" :
"ws")
3590 : (ri->
is_ssl ?
"https" :
"http"));
3594#if defined(__clang__)
3595#pragma clang diagnostic pop
3604 const char *define_proto,
3606 const char *define_uri)
3608 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3618 (define_uri !=
NULL)
3621 int port = (define_port > 0) ? define_port : ri->
server_port;
3624 size_t uri_encoded_len;
3630 uri_encoded_len = strlen(uri) * 3 + 1;
3632 if (uri_encoded ==
NULL) {
3638 for (i = j = 0; uri_encoded[i]; j++) {
3639 if (!strncmp(uri_encoded + i,
"%2f", 3)) {
3640 uri_encoded[j] =
'/';
3643 uri_encoded[j] = uri_encoded[i++];
3646 uri_encoded[j] =
'\0';
3648#if defined(USE_X_DOM_SOCKET)
3659 const char *server_name = UNIX_DOMAIN_SOCKET_SERVER_NAME;
3676 if ((0 == strcmp(define_proto,
"https"))
3677 || (0 == strcmp(define_proto,
"wss"))) {
3687#if defined(USE_IPV6)
3688 int is_ipv6 = (conn->
client.
lsa.
sa.sa_family == AF_INET6);
3690 int auth_domain_check_enabled =
3695 const char *server_domain =
3702 sprintf(portstr,
":%u", (
unsigned)port);
3707 if (!auth_domain_check_enabled || !server_domain) {
3713 server_domain = server_ip;
3720#
if defined(USE_IPV6)
3723 (is_ipv6 && (server_domain == server_ip)) ?
"[" :
"",
3725 (is_ipv6 && (server_domain == server_ip)) ?
"]" :
"",
3758 const char *delimiters,
3759 const char *whitespace,
3762 char *p, *begin_word, *end_word, *end_whitespace;
3765 end_word = begin_word + strcspn(begin_word, delimiters);
3768 if (end_word > begin_word) {
3770 while (*p == quotechar) {
3776 if (*end_word !=
'\0') {
3777 size_t end_off = strcspn(end_word + 1, delimiters);
3778 memmove(p, end_word, end_off + 1);
3780 end_word += end_off + 1;
3786 for (p++; p < end_word; p++) {
3791 if (*end_word ==
'\0') {
3795#if defined(GCC_DIAGNOSTIC)
3797#pragma GCC diagnostic push
3798#pragma GCC diagnostic ignored "-Wsign-conversion"
3801 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3803#if defined(GCC_DIAGNOSTIC)
3804#pragma GCC diagnostic pop
3807 for (p = end_word; p < end_whitespace; p++) {
3811 *buf = end_whitespace;
3823 for (i = 0; i < num_hdr; i++) {
3825 return hdr[i].
value;
3839 int output_max_size)
3844 for (i = 0; i < ri->
num_headers && cnt < output_max_size; i++) {
3904 if (val ==
NULL || list ==
NULL || *list ==
'\0') {
3910 while (*list ==
' ' || *list ==
'\t')
3914 if ((list = strchr(val->
ptr,
',')) !=
NULL) {
3916 val->
len = ((size_t)(list - val->
ptr));
3920 list = val->
ptr + strlen(val->
ptr);
3921 val->
len = ((size_t)(list - val->
ptr));
3925 end = (int)val->
len - 1;
3926 while (end >= 0 && ((val->
ptr[end] ==
' ') || (val->
ptr[end] ==
'\t')))
3928 val->
len = (size_t)(end) + (size_t)(1);
3930 if (val->
len == 0) {
3935 if (eq_val !=
NULL) {
3939 eq_val->
ptr = (
const char *)memchr(val->
ptr,
'=', val->
len);
3942 eq_val->
len = ((size_t)(val->
ptr - eq_val->
ptr)) + val->
len;
3943 val->
len = ((size_t)(eq_val->
ptr - val->
ptr)) - 1;
3986 const char *http_version;
4012 if (http_version && (0 == strcmp(http_version,
"1.1"))) {
4025 if (!conn || !conn->
dom_ctx) {
4036 if (!conn || !conn->
dom_ctx) {
4052#include "response.inl"
4061 "no-cache, no-store, "
4062 "must-revalidate, private, max-age=0",
4076#if !defined(NO_CACHING)
4080 const char *cache_control =
4084 if (cache_control !=
NULL) {
4111 conn,
NULL, val,
sizeof(val),
"max-age=%lu", (
unsigned long)max_age);
4136 (
unsigned long)max_age);
4142 if (header && header[0]) {
4152 const char *cors_orig_cfg =
4155 if (cors_orig_cfg && *cors_orig_cfg && origin_hdr && *origin_hdr) {
4161 "Access-Control-Allow-Origin",
4168#if !defined(NO_FILESYSTEMS)
4182 switch (response_code) {
4187 return "Switching Protocols";
4189 return "Processing";
4199 return "Non-Authoritative Information";
4201 return "No Content";
4203 return "Reset Content";
4205 return "Partial Content";
4207 return "Multi-Status";
4210 return "Already Reported";
4217 return "Multiple Choices";
4219 return "Moved Permanently";
4225 return "Not Modified";
4229 return "Temporary Redirect";
4231 return "Permanent Redirect";
4235 return "Bad Request";
4237 return "Unauthorized";
4239 return "Payment Required";
4245 return "Method Not Allowed";
4247 return "Not Acceptable";
4249 return "Proxy Authentication Required";
4251 return "Request Time-out";
4257 return "Length Required";
4259 return "Precondition Failed";
4261 return "Request Entity Too Large";
4263 return "Request-URI Too Large";
4265 return "Unsupported Media Type";
4267 return "Requested range not satisfiable";
4270 return "Expectation Failed";
4273 return "Misdirected Request";
4275 return "Unproccessable entity";
4280 return "Failed Dependency";
4284 return "Upgrade Required";
4287 return "Precondition Required";
4289 return "Too Many Requests";
4292 return "Request Header Fields Too Large";
4295 return "Unavailable For Legal Reasons";
4300 return "Internal Server Error";
4302 return "Not Implemented";
4304 return "Bad Gateway";
4306 return "Service Unavailable";
4308 return "Gateway Time-out";
4310 return "HTTP Version not supported";
4312 return "Variant Also Negotiates";
4314 return "Insufficient Storage";
4317 return "Loop Detected";
4320 return "Not Extended";
4322 return "Network Authentication Required";
4328 return "I am a teapot";
4330 return "Authentication Timeout";
4332 return "Enhance Your Calm";
4334 return "Login Timeout";
4336 return "Bandwidth Limit Exceeded";
4342 "Unknown HTTP response code: %u",
4347 if (response_code >= 100 && response_code < 200) {
4349 return "Information";
4351 if (response_code >= 200 && response_code < 300) {
4355 if (response_code >= 300 && response_code < 400) {
4357 return "Redirection";
4359 if (response_code >= 400 && response_code < 500) {
4361 return "Client Error";
4363 if (response_code >= 500 && response_code < 600) {
4365 return "Server Error";
4384#if !defined(NO_FILESYSTEMS)
4386 int len, i, page_handler_found, scope, truncated;
4387 const char *error_handler =
NULL;
4389 const char *error_page_file_ext, *tstr;
4391 int handled_by_callback = 0;
4393 if ((conn ==
NULL) || (fmt ==
NULL)) {
4401 has_body = ((status > 199) && (status != 204) && (status != 304));
4412 DEBUG_TRACE(
"Error %i - [%s]", status, errmsg_buf);
4422 handled_by_callback =
4428 if (!handled_by_callback) {
4432 "Recursion when handling error %u - fall back to default",
4434#if !defined(NO_FILESYSTEMS)
4439 page_handler_found = 0;
4441 if (error_handler !=
NULL) {
4442 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4448 sizeof(path_buf) - 32,
4459 sizeof(path_buf) - 32,
4468 sizeof(path_buf) - 32,
4483 path_buf[
sizeof(path_buf) - 32] = 0;
4484 len = (int)strlen(path_buf);
4485 if (len > (
int)
sizeof(path_buf) - 32) {
4486 len = (int)
sizeof(path_buf) - 32;
4490 tstr = strchr(error_page_file_ext,
'.');
4494 (i < 32) && (tstr[i] != 0) && (tstr[i] !=
',');
4499 path_buf[len + i - 1] = tstr[i];
4504 path_buf[len + i - 1] = 0;
4506 if (
mg_stat(conn, path_buf, &error_page_file.
stat)) {
4509 page_handler_found = 1;
4517 tstr = strchr(tstr + i,
'.');
4522 if (page_handler_found) {
4540 "text/plain; charset=utf-8",
4549 mg_printf(conn,
"Error %d: %s\n", status, status_text);
4550 mg_write(conn, errmsg_buf, strlen(errmsg_buf));
4578 long long content_length)
4590 if (content_length < 0) {
4604 (uint64_t)content_length);
4619 const char *target_url,
4634#if defined(MG_SEND_REDIRECT_BODY)
4636 size_t content_len = 0;
4637 char content_len_text[32];
4641 if (redirect_code == 0) {
4642 redirect_code = 307;
4646 if ((redirect_code != 301) && (redirect_code != 302)
4647 && (redirect_code != 303) && (redirect_code != 307)
4648 && (redirect_code != 308)) {
4654 if ((target_url ==
NULL) || (*target_url == 0)) {
4658#if defined(MG_SEND_REDIRECT_BODY)
4685 sizeof(redirect_body),
4686 "<html><head>%s</head><body><a href=\"%s\">%s</a></body></html>",
4690 content_len = strlen(reply);
4691 sprintf(content_len_text,
"%lu", (
unsigned long)content_len);
4697 if ((redirect_code == 301) || (redirect_code == 308)) {
4706#if defined(MG_SEND_REDIRECT_BODY)
4714#if defined(MG_SEND_REDIRECT_BODY)
4718 ret =
mg_write(conn, redirect_body, content_len);
4729#if defined(GCC_DIAGNOSTIC)
4731#pragma GCC diagnostic push
4732#pragma GCC diagnostic ignored "-Wunused-function"
4737pthread_mutex_init(pthread_mutex_t *
mutex,
void *
unused)
4741 InitializeCriticalSection(&
mutex->sec);
4747pthread_mutex_destroy(pthread_mutex_t *
mutex)
4749 DeleteCriticalSection(&
mutex->sec);
4755pthread_mutex_lock(pthread_mutex_t *
mutex)
4757 EnterCriticalSection(&
mutex->sec);
4763pthread_mutex_unlock(pthread_mutex_t *
mutex)
4765 LeaveCriticalSection(&
mutex->sec);
4772pthread_cond_init(pthread_cond_t *cv,
const void *
unused)
4776 cv->waiting_thread =
NULL;
4783pthread_cond_timedwait(pthread_cond_t *cv,
4784 pthread_mutex_t *
mutex,
4790 uint64_t nsnow, nswaitabs;
4794 pthread_mutex_lock(&cv->threadIdSec);
4796 ptls = &cv->waiting_thread;
4797 for (; *ptls !=
NULL; ptls = &(*ptls)->next_waiting_thread)
4799 tls->next_waiting_thread =
NULL;
4801 pthread_mutex_unlock(&cv->threadIdSec);
4806 (((uint64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4807 nswaitrel = nswaitabs - nsnow;
4808 if (nswaitrel < 0) {
4811 mswaitrel = (DWORD)(nswaitrel / 1000000);
4813 mswaitrel = (DWORD)INFINITE;
4816 pthread_mutex_unlock(
mutex);
4818 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
4821 pthread_mutex_lock(&cv->threadIdSec);
4822 ptls = &cv->waiting_thread;
4823 for (; *ptls !=
NULL; ptls = &(*ptls)->next_waiting_thread) {
4825 *ptls = tls->next_waiting_thread;
4830 pthread_mutex_unlock(&cv->threadIdSec);
4832 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4837 pthread_mutex_lock(
mutex);
4845pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *
mutex)
4847 return pthread_cond_timedwait(cv,
mutex,
NULL);
4853pthread_cond_signal(pthread_cond_t *cv)
4858 pthread_mutex_lock(&cv->threadIdSec);
4859 if (cv->waiting_thread) {
4860 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4861 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
4863 ok = SetEvent(wkup);
4866 pthread_mutex_unlock(&cv->threadIdSec);
4874pthread_cond_broadcast(pthread_cond_t *cv)
4876 pthread_mutex_lock(&cv->threadIdSec);
4877 while (cv->waiting_thread) {
4878 pthread_cond_signal(cv);
4880 pthread_mutex_unlock(&cv->threadIdSec);
4888pthread_cond_destroy(pthread_cond_t *cv)
4890 pthread_mutex_lock(&cv->threadIdSec);
4892 pthread_mutex_unlock(&cv->threadIdSec);
4893 pthread_mutex_destroy(&cv->threadIdSec);
4899#if defined(ALTERNATIVE_QUEUE)
4910event_wait(
void *eventhdl)
4912 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
4913 return (res == WAIT_OBJECT_0);
4919event_signal(
void *eventhdl)
4921 return (
int)SetEvent((HANDLE)eventhdl);
4927event_destroy(
void *eventhdl)
4929 CloseHandle((HANDLE)eventhdl);
4934#if defined(GCC_DIAGNOSTIC)
4936#pragma GCC diagnostic pop
4942change_slashes_to_backslashes(
char *path)
4946 for (i = 0; path[i] !=
'\0'; i++) {
4947 if (path[i] ==
'/') {
4953 if ((i > 0) && (path[i] ==
'\\')) {
4954 while ((path[i + 1] ==
'\\') || (path[i + 1] ==
'/')) {
4955 (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
4963mg_wcscasecmp(
const wchar_t *s1,
const wchar_t *s2)
4968 diff = ((*s1 >= L
'A') && (*s1 <= L
'Z') ? (*s1 - L
'A' + L
'a') : *s1)
4969 - ((*s2 >= L
'A') && (*s2 <= L
'Z') ? (*s2 - L
'A' + L
'a') : *s2);
4972 }
while ((diff == 0) && (s1[-1] != L
'\0'));
4987 wchar_t wbuf2[UTF16_PATH_MAX + 1];
4988 DWORD long_len, err;
4989 int (*fcompare)(
const wchar_t *,
const wchar_t *) = mg_wcscasecmp;
4992 change_slashes_to_backslashes(buf);
4996 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
4997 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int)wbuf_len);
4998 WideCharToMultiByte(
4999 CP_UTF8, 0, wbuf, (
int)wbuf_len, buf2,
sizeof(buf2),
NULL,
NULL);
5000 if (strcmp(buf, buf2) != 0) {
5024 memset(wbuf2, 0,
ARRAY_SIZE(wbuf2) *
sizeof(
wchar_t));
5025 long_len = GetLongPathNameW(wbuf, wbuf2,
ARRAY_SIZE(wbuf2) - 1);
5026 if (long_len == 0) {
5027 err = GetLastError();
5028 if (err == ERROR_FILE_NOT_FOUND) {
5033 if ((long_len >=
ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
5040#if !defined(NO_FILESYSTEMS)
5047 wchar_t wbuf[UTF16_PATH_MAX];
5048 WIN32_FILE_ATTRIBUTE_DATA info;
5049 time_t creation_time;
5055 memset(filep, 0,
sizeof(*filep));
5061 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5066 if ((len > 0) && (path[len - 1] !=
' ') && (path[len - 1] !=
'.')
5067 && (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0)) {
5068 filep->
size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
5070 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
5071 info.ftLastWriteTime.dwHighDateTime);
5077 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
5078 info.ftCreationTime.dwHighDateTime);
5083 filep->
is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
5095 wchar_t wbuf[UTF16_PATH_MAX];
5096 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5097 return DeleteFileW(wbuf) ? 0 : -1;
5104 wchar_t wbuf[UTF16_PATH_MAX];
5106 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5107 return CreateDirectoryW(wbuf,
NULL) ? 0 : -1;
5113#if defined(GCC_DIAGNOSTIC)
5115#pragma GCC diagnostic push
5116#pragma GCC diagnostic ignored "-Wunused-function"
5126 wchar_t wpath[UTF16_PATH_MAX];
5130 SetLastError(ERROR_BAD_ARGUMENTS);
5131 }
else if ((dir = (DIR *)
mg_malloc(
sizeof(*dir))) ==
NULL) {
5132 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5135 attrs = GetFileAttributesW(wpath);
5136 if ((wcslen(wpath) + 2 <
ARRAY_SIZE(wpath)) && (attrs != 0xFFFFFFFF)
5137 && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
5138 (void)wcscat(wpath, L
"\\*");
5139 dir->handle = FindFirstFileW(wpath, &dir->info);
5140 dir->result.d_name[0] =
'\0';
5158 if (dir->handle != INVALID_HANDLE_VALUE)
5159 result = FindClose(dir->handle) ? 0 : -1;
5164 SetLastError(ERROR_BAD_ARGUMENTS);
5172static struct dirent *
5175 struct dirent *result = 0;
5178 if (dir->handle != INVALID_HANDLE_VALUE) {
5179 result = &dir->result;
5180 (void)WideCharToMultiByte(CP_UTF8,
5182 dir->info.cFileName,
5185 sizeof(result->d_name),
5189 if (!FindNextFileW(dir->handle, &dir->info)) {
5190 (void)FindClose(dir->handle);
5191 dir->handle = INVALID_HANDLE_VALUE;
5195 SetLastError(ERROR_FILE_NOT_FOUND);
5198 SetLastError(ERROR_BAD_ARGUMENTS);
5205#if !defined(HAVE_POLL)
5217poll(
struct mg_pollfd *pfd,
unsigned int n,
int milliseconds)
5227 memset(&tv, 0,
sizeof(tv));
5228 tv.tv_sec = milliseconds / 1000;
5229 tv.tv_usec = (milliseconds % 1000) * 1000;
5234 for (i = 0; i < n; i++) {
5235 if (pfd[i].events & (POLLIN | POLLOUT | POLLERR)) {
5236 if (pfd[i].events & POLLIN) {
5237 FD_SET(pfd[i].fd, &rset);
5239 if (pfd[i].events & POLLOUT) {
5240 FD_SET(pfd[i].fd, &wset);
5243 FD_SET(pfd[i].fd, &eset);
5247 if (pfd[i].fd > maxfd) {
5252 if ((result = select((
int)maxfd + 1, &rset, &wset, &eset, &tv)) > 0) {
5253 for (i = 0; i < n; i++) {
5254 if (FD_ISSET(pfd[i].fd, &rset)) {
5255 pfd[i].revents |= POLLIN;
5257 if (FD_ISSET(pfd[i].fd, &wset)) {
5258 pfd[i].revents |= POLLOUT;
5260 if (FD_ISSET(pfd[i].fd, &eset)) {
5261 pfd[i].revents |= POLLERR;
5278#if defined(GCC_DIAGNOSTIC)
5280#pragma GCC diagnostic pop
5292 (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
5299#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5303 return ((_beginthread((
void(__cdecl *)(
void *))f, USE_STACK_SIZE, p)
5304 == ((uintptr_t)(-1L)))
5309 (_beginthread((
void(__cdecl *)(
void *))f, 0, p) == ((uintptr_t)(-1L)))
5320 pthread_t *threadidptr)
5323 HANDLE threadhandle;
5326 uip = _beginthreadex(
NULL, 0, f, p, 0,
NULL);
5327 threadhandle = (HANDLE)uip;
5328 if ((uip != 0) && (threadidptr !=
NULL)) {
5329 *threadidptr = threadhandle;
5345 dwevent = WaitForSingleObject(
threadid, (DWORD)INFINITE);
5346 if (dwevent == WAIT_FAILED) {
5349 if (dwevent == WAIT_OBJECT_0) {
5358#if !defined(NO_SSL_DL) && !defined(NO_SSL)
5362#if defined(GCC_DIAGNOSTIC)
5364#pragma GCC diagnostic push
5365#pragma GCC diagnostic ignored "-Wunused-function"
5371dlopen(
const char *dll_name,
int flags)
5373 wchar_t wbuf[UTF16_PATH_MAX];
5376 return LoadLibraryW(wbuf);
5382dlclose(
void *handle)
5386 if (FreeLibrary((HMODULE)handle) != 0) {
5396#if defined(GCC_DIAGNOSTIC)
5398#pragma GCC diagnostic pop
5409kill(pid_t pid,
int sig_num)
5411 (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
5412 (void)CloseHandle((HANDLE)pid);
5417#if !defined(WNOHANG)
5423waitpid(pid_t pid,
int *status,
int flags)
5425 DWORD timeout = INFINITE;
5430 if ((flags | WNOHANG) == WNOHANG) {
5434 waitres = WaitForSingleObject((HANDLE)pid, timeout);
5435 if (waitres == WAIT_OBJECT_0) {
5438 if (waitres == WAIT_TIMEOUT) {
5446trim_trailing_whitespaces(
char *
s)
5448 char *e =
s + strlen(
s);
5449 while ((e >
s) && isspace((
unsigned char)e[-1])) {
5468 char *interp_arg = 0;
5473 PROCESS_INFORMATION pi = {0};
5477 memset(&si, 0,
sizeof(si));
5480 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5481 si.wShowWindow = SW_HIDE;
5483 me = GetCurrentProcess();
5485 (HANDLE)_get_osfhandle(fdin[0]),
5490 DUPLICATE_SAME_ACCESS);
5492 (HANDLE)_get_osfhandle(fdout[1]),
5497 DUPLICATE_SAME_ACCESS);
5499 (HANDLE)_get_osfhandle(fderr[1]),
5504 DUPLICATE_SAME_ACCESS);
5509 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5510 HANDLE_FLAG_INHERIT,
5512 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5513 HANDLE_FLAG_INHERIT,
5515 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5516 HANDLE_FLAG_INHERIT,
5522 if (interp !=
NULL) {
5530 buf[0] = buf[1] =
'\0';
5534 conn, &truncated, cmdline,
sizeof(cmdline),
"%s/%s", dir, prog);
5537 pi.hProcess = (pid_t)-1;
5547 buf[
sizeof(buf) - 1] =
'\0';
5550 if ((buf[0] ==
'#') && (buf[1] ==
'!')) {
5551 trim_trailing_whitespaces(buf + 2);
5558 GetFullPathNameA(dir,
sizeof(full_dir), full_dir,
NULL);
5560 if (interp[0] !=
'\0') {
5562 if ((interp_arg != 0) && (interp_arg[0] != 0)) {
5567 "\"%s\" %s \"%s\\%s\"",
5577 "\"%s\" \"%s\\%s\"",
5594 pi.hProcess = (pid_t)-1;
5599 if (CreateProcessA(
NULL,
5604 CREATE_NEW_PROCESS_GROUP,
5611 conn,
"%s: CreateProcess(%s): %ld", __func__, cmdline, (
long)
ERRNO);
5612 pi.hProcess = (pid_t)-1;
5617 (void)CloseHandle(si.hStdOutput);
5618 (void)CloseHandle(si.hStdError);
5619 (void)CloseHandle(si.hStdInput);
5620 if (pi.hThread !=
NULL) {
5621 (void)CloseHandle(pi.hThread);
5624 return (pid_t)pi.hProcess;
5632 unsigned long non_blocking = 0;
5633 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5640 unsigned long non_blocking = 1;
5641 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5648#if !defined(NO_FILESYSTEMS)
5658 memset(filep, 0,
sizeof(*filep));
5664 if (0 == stat(path, &st)) {
5665 filep->
size = (uint64_t)(st.st_size);
5681#if defined(__ZEPHYR__)
5686 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5690 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5702 pthread_t thread_id;
5703 pthread_attr_t attr;
5706 (void)pthread_attr_init(&attr);
5707 (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5709#if defined(__ZEPHYR__)
5710 pthread_attr_setstack(&attr, &civetweb_main_stack, ZEPHYR_STACK_SIZE);
5711#elif defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5714 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5717 result = pthread_create(&thread_id, &attr, func, param);
5718 pthread_attr_destroy(&attr);
5728 pthread_t *threadidptr)
5730 pthread_t thread_id;
5731 pthread_attr_t attr;
5734 (void)pthread_attr_init(&attr);
5736#if defined(__ZEPHYR__)
5737 pthread_attr_setstack(&attr,
5738 &civetweb_worker_stacks[zephyr_worker_stack_index++],
5740#elif defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5743 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5746 result = pthread_create(&thread_id, &attr, func, param);
5747 pthread_attr_destroy(&attr);
5748 if ((result == 0) && (threadidptr !=
NULL)) {
5749 *threadidptr = thread_id;
5783 if ((pid = fork()) == -1) {
5786 }
else if (pid != 0) {
5794 if (chdir(dir) != 0) {
5796 conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
5797 }
else if (dup2(fdin[0], 0) == -1) {
5799 "%s: dup2(%d, 0): %s",
5803 }
else if (dup2(fdout[1], 1) == -1) {
5805 "%s: dup2(%d, 1): %s",
5809 }
else if (dup2(fderr[1], 2) == -1) {
5811 "%s: dup2(%d, 2): %s",
5816 struct sigaction sa;
5821 (void)close(fdin[0]);
5822 (void)close(fdout[1]);
5823 (void)close(fderr[1]);
5826 (void)close(fdin[1]);
5827 (void)close(fdout[0]);
5828 (void)close(fderr[0]);
5835 memset(&sa, 0,
sizeof(sa));
5836 sa.sa_handler = SIG_DFL;
5837 sigaction(SIGCHLD, &sa,
NULL);
5840 if (interp ==
NULL) {
5842 (void)execle(prog, prog,
NULL, envp);
5844 "%s: execle(%s): %s",
5850 const char *interp_args =
5854 if ((interp_args !=
NULL) && (interp_args[0] != 0)) {
5855 (void)execle(interp, interp, interp_args, prog,
NULL, envp);
5857 (void)execle(interp, interp, prog,
NULL, envp);
5860 "%s: execle(%s %s): %s",
5878 int flags = fcntl(sock, F_GETFL, 0);
5883 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
5892 int flags = fcntl(sock, F_GETFL, 0);
5897 if (fcntl(sock, F_SETFL, flags & (~(
int)(O_NONBLOCK))) < 0) {
5911 static uint64_t lfsr = 0;
5912 static uint64_t lcg = 0;
5923 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
5925 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
5933 return (lfsr ^ lcg ^ now);
5948 int check_pollerr = 0;
5949 if ((n == 1) && ((pfd[0].events & POLLERR) == 0)) {
5951 pfd[0].events |= POLLERR;
5963 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
5964 ms_now = milliseconds;
5967 result = poll(pfd, n, ms_now);
5974 && ((pfd[0].revents & (POLLIN | POLLOUT | POLLERR))
5984 if (milliseconds > 0) {
5985 milliseconds -= ms_now;
5988 }
while (milliseconds > 0);
6011 uint64_t start = 0, now = 0, timeout_ns = 0;
6018 typedef size_t len_t;
6024 timeout_ns = (uint64_t)(timeout * 1.0E9);
6031#if defined(NO_SSL) && !defined(USE_MBEDTLS)
6041#if defined(USE_MBEDTLS)
6043 n = mbed_ssl_write(ssl, (
const unsigned char *)buf, len);
6045 if ((n == MBEDTLS_ERR_SSL_WANT_READ)
6046 || (n == MBEDTLS_ERR_SSL_WANT_WRITE)
6047 || n == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
6050 fprintf(stderr,
"SSL write failed, error %d\n", n);
6057#elif !defined(NO_SSL)
6060 n = SSL_write(ssl, buf, len);
6062 err = SSL_get_error(ssl, n);
6063 if ((err == SSL_ERROR_SYSCALL) && (n == -1)) {
6065 }
else if ((err == SSL_ERROR_WANT_READ)
6066 || (err == SSL_ERROR_WANT_WRITE)) {
6081 n = (int)
fwrite(buf, 1, (
size_t)len, fp);
6090 err = (n < 0) ?
ERRNO : 0;
6105 if ((n > 0) || ((n == 0) && (len == 0))) {
6135 pfd[0].events = POLLOUT;
6147 if ((now - start) > timeout_ns) {
6169 double timeout = -1.0;
6170 int n, nwritten = 0;
6179 if (timeout <= 0.0) {
6185 n =
push_inner(ctx, fp, sock, ssl, buf + nwritten, len, timeout);
6187 if (nwritten == 0) {
6191 }
else if (n == 0) {
6221 typedef size_t len_t;
6234 nread = (int)read(fileno(fp), buf, (size_t)len);
6236 err = (nread < 0) ?
ERRNO : 0;
6237 if ((nread == 0) && (len > 0)) {
6242#if defined(USE_MBEDTLS)
6243 }
else if (conn->
ssl !=
NULL) {
6248 to_read = mbedtls_ssl_get_bytes_avail(conn->
ssl);
6260 pfd[0].events = POLLIN;
6266 (
int)(timeout * 1000.0),
6275 nread = mbed_ssl_read(conn->
ssl, (
unsigned char *)buf, to_read);
6277 if ((nread == MBEDTLS_ERR_SSL_WANT_READ)
6278 || (nread == MBEDTLS_ERR_SSL_WANT_WRITE)
6279 || nread == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) {
6282 fprintf(stderr,
"SSL read failed, error %d\n", nread);
6289 }
else if (pollres < 0) {
6297#elif !defined(NO_SSL)
6298 }
else if (conn->
ssl !=
NULL) {
6303 if ((ssl_pending = SSL_pending(conn->
ssl)) > 0) {
6307 if (ssl_pending > len) {
6313 pfd[0].events = POLLIN;
6316 (
int)(timeout * 1000.0),
6325 SSL_read(conn->
ssl, buf, (ssl_pending > 0) ? ssl_pending : len);
6327 err = SSL_get_error(conn->
ssl, nread);
6328 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
6330 }
else if ((err == SSL_ERROR_WANT_READ)
6331 || (err == SSL_ERROR_WANT_WRITE)) {
6343 }
else if (pollres < 0) {
6357 pfd[0].events = POLLIN;
6360 (
int)(timeout * 1000.0),
6366 nread = (int)recv(conn->
client.
sock, buf, (len_t)len, 0);
6367 err = (nread < 0) ?
ERRNO : 0;
6372 }
else if (pollres < 0) {
6385 if ((nread > 0) || ((nread == 0) && (len == 0))) {
6393 if (err == WSAEWOULDBLOCK) {
6397 }
else if (err == WSAETIMEDOUT) {
6401 }
else if (err == WSAECONNABORTED) {
6442 double timeout = -1.0;
6443 uint64_t start_time = 0, now = 0, timeout_ns = 0;
6448 if (timeout <= 0.0) {
6453 timeout_ns = (uint64_t)(timeout * 1.0E9);
6456 n =
pull_inner(fp, conn, buf + nread, len, timeout);
6462 }
else if (n == -1) {
6464 if (timeout >= 0.0) {
6466 if ((now - start_time) <= timeout_ns) {
6471 }
else if (n == 0) {
6488 while (
mg_read(conn, buf,
sizeof(buf)) > 0)
6496 int64_t content_len, n, buffered_len, nread;
6498 (int64_t)((len > INT_MAX) ? INT_MAX : len);
6510 if (content_len < 0) {
6519 if (left_to_read < len64) {
6523 len64 = left_to_read;
6529 if (buffered_len > 0) {
6530 if (len64 < buffered_len) {
6531 buffered_len = len64;
6534 memcpy(buf,
body, (
size_t)buffered_len);
6535 len64 -= buffered_len;
6537 nread += buffered_len;
6538 buf = (
char *)buf + buffered_len;
6544 if ((n =
pull_all(
NULL, conn, (
char *)buf, (
int)len64)) >= 0) {
6548 nread = ((nread > 0) ? nread : n);
6564#if defined(USE_SERVER_STATS)
6565 struct timespec tnow;
6566 conn->conn_state = 4;
6572#if defined(USE_SERVER_STATS)
6573 conn->conn_state = 5;
6575 clock_gettime(CLOCK_MONOTONIC, &tnow);
6579 mg_atomic_add64(&(conn->
phys_ctx->total_data_written),
6593#if defined(USE_HTTP2)
6595#error "HTTP2 requires ALPN, ALPN requires SSL/TLS"
6602 if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) { \
6603 http2_must_use_http1(conn); \
6604 DEBUG_TRACE("%s", "must use HTTP/1.x"); \
6616 if (len > INT_MAX) {
6625 size_t all_read = 0;
6639 int read_ret =
mg_read_inner(conn, (
char *)buf + all_read, len);
6647 all_read += (size_t)read_ret;
6648 len -= (size_t)read_ret;
6656 || (x[1] !=
'\n')) {
6668 unsigned long chunkSize = 0;
6670 for (i = 0; i < (
sizeof(lenbuf) - 1); i++) {
6675 if ((i > 0) && (lenbuf[i] ==
';')) {
6689 && lenbuf[i] !=
'\r');
6691 if ((i > 0) && (lenbuf[i] ==
'\r')
6692 && (lenbuf[i - 1] !=
'\r')) {
6695 if ((i > 1) && (lenbuf[i] ==
'\n')
6696 && (lenbuf[i - 1] ==
'\r')) {
6698 chunkSize = strtoul(lenbuf, &end, 16);
6699 if (chunkSize == 0) {
6705 if (!isxdigit((
unsigned char)lenbuf[i])) {
6711 if ((end ==
NULL) || (*end !=
'\r')) {
6737 while (crlf_count < 4 && conn->is_chunked == 3) {
6740 if ((crlf_count == 0 || crlf_count == 2)) {
6741 if (lenbuf[0] ==
'\r')
6749 if (lenbuf[0] ==
'\n')
6772 return (
int)all_read;
6782 int n, total, allowed;
6787 if (len > INT_MAX) {
6793#if defined(USE_HTTP2)
6795 http2_data_frame_head(conn, len, 0);
6805 if (allowed > (
int)len) {
6816 if (total == allowed) {
6818 buf = (
const char *)buf + total;
6820 while ((total < (
int)len)
6822 allowed = (conn->
throttle > ((int)len - total))
6839 buf = (
const char *)buf + n;
6862 unsigned int chunk_len)
6870 sprintf(lenbuf,
"%x\r\n", chunk_len);
6871 lenbuf_len = strlen(lenbuf);
6874 ret =
mg_write(conn, lenbuf, lenbuf_len);
6875 if (ret != (
int)lenbuf_len) {
6881 if (ret != (
int)chunk_len) {
6896#if defined(GCC_DIAGNOSTIC)
6899#pragma GCC diagnostic push
6900#pragma GCC diagnostic ignored "-Wformat-nonliteral"
6927 (*buf)[size - 1] = 0;
6941 size_t prealloc_size,
6967 }
else if ((
size_t)(len) >= prealloc_size) {
6970 *out_buf = (
char *)
mg_malloc((
size_t)(len) + 1);
6988 *out_buf = prealloc_buf;
7009#if defined(GCC_DIAGNOSTIC)
7011#pragma GCC diagnostic pop
7022 if ((len =
alloc_vprintf(&buf, mem,
sizeof(mem), fmt, ap)) > 0) {
7023 len =
mg_write(conn, buf, (
size_t)len);
7052 int is_form_url_encoded)
7055#define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
7057 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
7058 if ((i < src_len - 2) && (src[i] ==
'%')
7059 && isxdigit((
unsigned char)src[i + 1])
7060 && isxdigit((
unsigned char)src[i + 2])) {
7061 a = tolower((
unsigned char)src[i + 1]);
7062 b = tolower((
unsigned char)src[i + 2]);
7065 }
else if (is_form_url_encoded && (src[i] ==
'+')) {
7074 return (i >= src_len) ? j : -1;
7082 int len = (int)strlen(buf);
7106 const char *p, *e, *
s;
7110 if ((dst ==
NULL) || (dst_len == 0)) {
7112 }
else if ((data ==
NULL) || (
name ==
NULL) || (data_len == 0)) {
7116 name_len = strlen(
name);
7117 e = data + data_len;
7122 for (p = data; p + name_len < e; p++) {
7123 if (((p == data) || (p[-1] ==
'&')) && (p[name_len] ==
'=')
7129 s = (
const char *)memchr(p,
'&', (
size_t)(e - p));
7159 unsigned num_form_fields)
7170 if ((form_fields ==
NULL) && (num_form_fields == 0)) {
7186 if ((form_fields ==
NULL) || ((
int)num_form_fields <= 0)) {
7191 for (i = 0; i < (int)num_form_fields; i++) {
7193 while ((*data ==
' ') || (*data ==
'\t')) {
7201 form_fields[num].
name = data;
7205 while ((*b != 0) && (*b !=
'&') && (*b !=
'=')) {
7212 }
else if (*b ==
'&') {
7220 form_fields[num].
value = data;
7227 b = strchr(data,
'&');
7240 for (i = 0; i < num; i++) {
7241 if (form_fields[i].
name) {
7244 if (form_fields[i].
value) {
7257 const char *var_name,
7261 const char *
s, *p, *end;
7262 int name_len, len = -1;
7264 if ((dst ==
NULL) || (dst_size == 0)) {
7269 if ((var_name ==
NULL) || ((
s = cookie_header) ==
NULL)) {
7273 name_len = (int)strlen(var_name);
7274 end =
s + strlen(
s);
7276 if (
s[name_len] ==
'=') {
7278 if ((
s == cookie_header) || (
s[-1] ==
' ')) {
7280 if ((p = strchr(
s,
' ')) ==
NULL) {
7286 if ((*
s ==
'"') && (p[-1] ==
'"') && (p >
s + 1)) {
7290 if ((
size_t)(p -
s) < dst_size) {
7310 static const char *b64 =
7311 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7315 if (dst_len !=
NULL) {
7319 size_t expected_len = ((src_len + 2) / 3) * 4 + 1;
7320 if (*dst_len < expected_len) {
7324 *dst_len = expected_len;
7329 for (i = j = 0; i < src_len; i += 3) {
7331 b = ((i + 1) >= src_len) ? 0 : src[i + 1];
7332 c = ((i + 2) >= src_len) ? 0 : src[i + 2];
7334 dst[j++] = b64[
a >> 2];
7335 dst[j++] = b64[((
a & 3) << 4) | (b >> 4)];
7336 if (i + 1 < src_len) {
7337 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
7339 if (i + 2 < src_len) {
7340 dst[j++] = b64[c & 63];
7343 while (j % 4 != 0) {
7348 if (dst_len !=
NULL) {
7349 *dst_len = (size_t)j;
7360 if ((letter >=
'A') && (letter <=
'Z')) {
7361 return (
unsigned char)(letter -
'A');
7363 if ((letter >=
'a') && (letter <=
'z')) {
7364 return (
unsigned char)(letter -
'a' + 26);
7366 if ((letter >=
'0') && (letter <=
'9')) {
7367 return (
unsigned char)(letter -
'0' + 52);
7369 if (letter ==
'+') {
7372 if (letter ==
'/') {
7375 if (letter ==
'=') {
7389 unsigned char a, b, c, d;
7390 size_t dst_len_limit = (size_t)-1;
7391 size_t dst_len_used = 0;
7393 if (dst_len !=
NULL) {
7394 dst_len_limit = *dst_len;
7398 for (i = 0; i < src_len; i += 4) {
7405 b =
b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]);
7410 c =
b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]);
7415 d =
b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
7421 if (dst_len_used < dst_len_limit) {
7422 dst[dst_len_used] = (
unsigned char)((
unsigned char)(
a << 2)
7423 + (
unsigned char)(b >> 4));
7428 if (dst_len_used < dst_len_limit) {
7430 dst[dst_len_used] = (
unsigned char)((
unsigned char)(b << 4)
7431 + (
unsigned char)(c >> 2));
7435 if (dst_len_used < dst_len_limit) {
7437 (
unsigned char)((
unsigned char)(c << 6) + d);
7445 if (dst_len_used < dst_len_limit) {
7446 dst[dst_len_used] =
'\0';
7449 if (dst_len !=
NULL) {
7450 *dst_len = dst_len_used;
7453 if (dst_len_used > dst_len_limit) {
7470 return (!strcmp(
s,
"PUT") || !strcmp(
s,
"DELETE")
7471 || !strcmp(
s,
"MKCOL") || !strcmp(
s,
"PATCH")
7472 || !strcmp(
s,
"LOCK") || !strcmp(
s,
"UNLOCK")
7473 || !strcmp(
s,
"PROPPATCH") || !strcmp(
s,
"MOVE")
7474 || !strcmp(
s,
"COPY"));
7493 return (!strcmp(
s,
"PROPFIND") || !strcmp(
s,
"PROPPATCH")
7494 || !strcmp(
s,
"LOCK") || !strcmp(
s,
"UNLOCK")
7495 || !strcmp(
s,
"MOVE") || !strcmp(
s,
"COPY"));
7502#if !defined(NO_FILES)
7506 const char *filename
7510 int cgi_config_idx, inc, max;
7514 if (match_prefix_strlen(conn->
dom_ctx->
config[LUA_SCRIPT_EXTENSIONS],
7520#if defined(USE_DUKTAPE)
7521 if (match_prefix_strlen(conn->
dom_ctx->
config[DUKTAPE_SCRIPT_EXTENSIONS],
7530 for (cgi_config_idx = 0; cgi_config_idx < max; cgi_config_idx += inc) {
7532 && (match_prefix_strlen(
7552 const char *filename
7556 if (match_prefix_strlen(conn->
dom_ctx->
config[LUA_SERVER_PAGE_EXTENSIONS],
7580 struct vec filename_vec;
7581 size_t n = strlen(path);
7587 while ((n > 0) && (path[n - 1] ==
'/')) {
7596 if ((filename_vec.
len + 1) > (path_len - (n + 1))) {
7604 if (
mg_stat(conn, path, filestat)) {
7624 size_t filename_buf_len,
7627 int *is_script_resource,
7628 int *is_websocket_request,
7629 int *is_put_or_delete_request,
7630 int *is_webdav_request,
7631 int *is_template_text
7634 char const *accept_encoding;
7636#if !defined(NO_FILES)
7639 const char *rewrite;
7641 ptrdiff_t match_len;
7644#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7646 size_t tmp_str_len, sep_pos;
7647 int allow_substitute_script_subresources;
7650 (void)filename_buf_len;
7654 memset(filestat, 0,
sizeof(*filestat));
7657 *is_script_resource = 0;
7658 *is_template_text = 0;
7669#if defined(USE_WEBSOCKET)
7671#if !defined(NO_FILES)
7672 if ((*is_websocket_request) && conn->
dom_ctx->
config[WEBSOCKET_ROOT]) {
7677 *is_websocket_request = 0;
7683 if (strstr(accept_encoding,
"gzip") !=
NULL) {
7688#if !defined(NO_FILES)
7705 conn, &truncated, filename, filename_buf_len - 1,
"%s%s", root, uri);
7708 goto interpret_cleanup;
7714 if ((match_len = match_prefix(
a.ptr,
a.len, uri)) > 0) {
7718 filename_buf_len - 1,
7728 goto interpret_cleanup;
7734 if (
mg_stat(conn, filename, filestat)) {
7735 int uri_len = (int)strlen(uri);
7736 int is_uri_end_slash = (uri_len > 0) && (uri[uri_len - 1] ==
'/');
7754 *is_script_resource = (!*is_put_or_delete_request);
7764 *is_template_text = (!*is_put_or_delete_request);
7771 && (!*is_webdav_request)) {
7775 memset(&tmp_filestat, 0,
sizeof(tmp_filestat));
7778 conn, filename, filename_buf_len, &tmp_filestat)) {
7782 *filestat = tmp_filestat;
7786 *is_script_resource = 1;
7789 *is_template_text = 1;
7792 *is_script_resource = 0;
7793 *is_found = (
mg_stat(conn, filename, filestat) ? 1 : 0);
7811 conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", filename);
7814 goto interpret_cleanup;
7817 if (
mg_stat(conn, gz_path, filestat)) {
7827#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7830 tmp_str_len = strlen(filename);
7835 goto interpret_cleanup;
7837 memcpy(tmp_str, filename, tmp_str_len + 1);
7840 allow_substitute_script_subresources =
7843 if (*is_webdav_request) {
7849 sep_pos = tmp_str_len;
7850 while (sep_pos > 0) {
7852 if (tmp_str[sep_pos] ==
'/') {
7853 int is_script = 0, does_exist = 0;
7855 tmp_str[sep_pos] = 0;
7858 does_exist =
mg_stat(conn, tmp_str, filestat);
7861 if (does_exist && is_script) {
7862 filename[sep_pos] = 0;
7863 memmove(filename + sep_pos + 2,
7864 filename + sep_pos + 1,
7865 strlen(filename + sep_pos + 1) + 1);
7866 conn->
path_info = filename + sep_pos + 1;
7867 filename[sep_pos + 1] =
'/';
7868 *is_script_resource = 1;
7873 if (allow_substitute_script_subresources) {
7880 size_t script_name_len = strlen(tmp_str);
7884 char *subres_name = filename + sep_pos;
7885 size_t subres_name_len = strlen(subres_name);
7887 DEBUG_TRACE(
"Substitute script %s serving path %s",
7892 if ((script_name_len + subres_name_len + 2)
7893 >= filename_buf_len) {
7895 goto interpret_cleanup;
7899 filename + script_name_len + 1;
7900 memmove(conn->
path_info, subres_name, subres_name_len);
7902 memcpy(filename, tmp_str, script_name_len + 1);
7904 *is_script_resource = 1;
7915 filename[sep_pos] = 0;
7917 *is_script_resource = 0;
7924 tmp_str[sep_pos] =
'/';
7934#if !defined(NO_FILES)
7937 memset(filestat, 0,
sizeof(*filestat));
7940 *is_script_resource = 0;
7941 *is_websocket_request = 0;
7942 *is_put_or_delete_request = 0;
7955 for (i = 0; i < buflen; i++) {
7957 const unsigned char c = (
unsigned char)buf[i];
7959 if ((c < 128) && ((char)c !=
'\r') && ((char)c !=
'\n')
7965 if (i < buflen - 1) {
7966 if ((buf[i] ==
'\n') && (buf[i + 1] ==
'\n')) {
7973 if (i < buflen - 3) {
7974 if ((buf[i] ==
'\r') && (buf[i + 1] ==
'\n') && (buf[i + 2] ==
'\r')
7975 && (buf[i + 3] ==
'\n')) {
7986#if !defined(NO_CACHING)
8007 char month_str[32] = {0};
8008 int second, minute, hour, day, month, year;
8009 time_t result = (time_t)0;
8012 if ((sscanf(datetime,
8013 "%d/%3s/%d %d:%d:%d",
8021 || (sscanf(datetime,
8022 "%d %3s %d %d:%d:%d",
8030 || (sscanf(datetime,
8031 "%*3s, %d %3s %d %d:%d:%d",
8039 || (sscanf(datetime,
8040 "%d-%3s-%d %d:%d:%d",
8049 if ((month >= 0) && (year >= 1970)) {
8050 memset(&tm, 0,
sizeof(tm));
8051 tm.tm_year = year - 1900;
8057 result = timegm(&tm);
8074 char *out_end = inout;
8107 if (!strncmp(in,
"../", 3)) {
8109 }
else if (!strncmp(in,
"./", 2)) {
8118 else if (!strncmp(in,
"/./", 3)) {
8120 }
else if (!strcmp(in,
"/.")) {
8131 else if (!strncmp(in,
"/../", 4)) {
8133 if (inout != out_end) {
8137 }
while ((inout != out_end) && (*out_end !=
'/'));
8139 }
else if (!strcmp(in,
"/..")) {
8141 if (inout != out_end) {
8145 }
while ((inout != out_end) && (*out_end !=
'/'));
8153 else if (!strcmp(in,
".") || !strcmp(in,
"..")) {
8168 }
while ((*in != 0) && (*in !=
'/'));
8184 out_end = in = inout;
8188 char *in_ahead = in;
8191 }
while (*in_ahead ==
'.');
8192 if (*in_ahead ==
'/') {
8194 if ((out_end != inout) && (out_end[-1] ==
'/')) {
8198 }
else if (*in_ahead == 0) {
8204 }
while (in != in_ahead);
8206 }
else if (*in ==
'/') {
8211 }
while (*in ==
'/');
8221static const struct {
8229 {
".bin", 4,
"application/octet-stream"},
8230 {
".deb", 4,
"application/octet-stream"},
8231 {
".dmg", 4,
"application/octet-stream"},
8232 {
".dll", 4,
"application/octet-stream"},
8233 {
".doc", 4,
"application/msword"},
8234 {
".eps", 4,
"application/postscript"},
8235 {
".exe", 4,
"application/octet-stream"},
8236 {
".iso", 4,
"application/octet-stream"},
8237 {
".js", 3,
"application/javascript"},
8238 {
".json", 5,
"application/json"},
8239 {
".msi", 4,
"application/octet-stream"},
8240 {
".pdf", 4,
"application/pdf"},
8241 {
".ps", 3,
"application/postscript"},
8242 {
".rtf", 4,
"application/rtf"},
8243 {
".xhtml", 6,
"application/xhtml+xml"},
8244 {
".xsl", 4,
"application/xml"},
8245 {
".xslt", 5,
"application/xml"},
8248 {
".ttf", 4,
"application/font-sfnt"},
8249 {
".cff", 4,
"application/font-sfnt"},
8250 {
".otf", 4,
"application/font-sfnt"},
8251 {
".aat", 4,
"application/font-sfnt"},
8252 {
".sil", 4,
"application/font-sfnt"},
8253 {
".pfr", 4,
"application/font-tdpfr"},
8254 {
".woff", 5,
"application/font-woff"},
8255 {
".woff2", 6,
"application/font-woff2"},
8258 {
".mp3", 4,
"audio/mpeg"},
8259 {
".oga", 4,
"audio/ogg"},
8260 {
".ogg", 4,
"audio/ogg"},
8263 {
".gif", 4,
"image/gif"},
8264 {
".ief", 4,
"image/ief"},
8265 {
".jpeg", 5,
"image/jpeg"},
8266 {
".jpg", 4,
"image/jpeg"},
8267 {
".jpm", 4,
"image/jpm"},
8268 {
".jpx", 4,
"image/jpx"},
8269 {
".png", 4,
"image/png"},
8270 {
".svg", 4,
"image/svg+xml"},
8271 {
".tif", 4,
"image/tiff"},
8272 {
".tiff", 5,
"image/tiff"},
8275 {
".wrl", 4,
"model/vrml"},
8278 {
".css", 4,
"text/css"},
8279 {
".csv", 4,
"text/csv"},
8280 {
".htm", 4,
"text/html"},
8281 {
".html", 5,
"text/html"},
8282 {
".sgm", 4,
"text/sgml"},
8283 {
".shtm", 5,
"text/html"},
8284 {
".shtml", 6,
"text/html"},
8285 {
".txt", 4,
"text/plain"},
8286 {
".xml", 4,
"text/xml"},
8289 {
".mov", 4,
"video/quicktime"},
8290 {
".mp4", 4,
"video/mp4"},
8291 {
".mpeg", 5,
"video/mpeg"},
8292 {
".mpg", 4,
"video/mpeg"},
8293 {
".ogv", 4,
"video/ogg"},
8294 {
".qt", 3,
"video/quicktime"},
8299 {
".arj", 4,
"application/x-arj-compressed"},
8300 {
".gz", 3,
"application/x-gunzip"},
8301 {
".rar", 4,
"application/x-arj-compressed"},
8302 {
".swf", 4,
"application/x-shockwave-flash"},
8303 {
".tar", 4,
"application/x-tar"},
8304 {
".tgz", 4,
"application/x-tar-gz"},
8305 {
".torrent", 8,
"application/x-bittorrent"},
8306 {
".ppt", 4,
"application/x-mspowerpoint"},
8307 {
".xls", 4,
"application/x-msexcel"},
8308 {
".zip", 4,
"application/x-zip-compressed"},
8312 {
".flac", 5,
"audio/flac"},
8313 {
".aif", 4,
"audio/x-aif"},
8314 {
".m3u", 4,
"audio/x-mpegurl"},
8315 {
".mid", 4,
"audio/x-midi"},
8316 {
".ra", 3,
"audio/x-pn-realaudio"},
8317 {
".ram", 4,
"audio/x-pn-realaudio"},
8318 {
".wav", 4,
"audio/x-wav"},
8319 {
".bmp", 4,
"image/bmp"},
8320 {
".ico", 4,
"image/x-icon"},
8321 {
".pct", 4,
"image/x-pct"},
8322 {
".pict", 5,
"image/pict"},
8323 {
".rgb", 4,
"image/x-rgb"},
8324 {
".webm", 5,
"video/webm"},
8325 {
".asf", 4,
"video/x-ms-asf"},
8326 {
".avi", 4,
"video/x-msvideo"},
8327 {
".m4v", 4,
"video/x-m4v"},
8337 path_len = strlen(path);
8347 return "text/plain";
8356 struct vec ext_vec, mime_vec;
8357 const char *list, *ext;
8360 path_len = strlen(path);
8364 memset(
vec,
'\0',
sizeof(
struct vec));
8374 ext = path + path_len - ext_vec.
len;
8391 static const char *hex =
"0123456789abcdef";
8393 for (;
len--; p++) {
8394 *to++ = hex[p[0] >> 4];
8395 *to++ = hex[p[0] & 0x0f];
8406 md5_byte_t hash[16];
8414 while ((p = va_arg(ap,
const char *)) !=
NULL) {
8415 md5_append(&ctx, (
const md5_byte_t *)p, strlen(p));
8419 md5_finish(&ctx, hash);
8420 bin2str(buf, hash,
sizeof(hash));
8434 const char *response)
8436 char ha2[32 + 1], expected_response[32 + 1];
8439 if ((method ==
NULL) || (nonce ==
NULL) || (nc ==
NULL) || (cnonce ==
NULL)
8440 || (qop ==
NULL) || (response ==
NULL)) {
8445 if (strlen(response) != 32) {
8450 mg_md5(expected_response,
8468#if !defined(NO_FILESYSTEMS)
8482 if (gpass !=
NULL) {
8516 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
8561 const char *auth_header;
8568 (void)memset(
ah, 0,
sizeof(*
ah));
8571 if (auth_header ==
NULL) {
8578 const char *userpw_b64 = auth_header + 6;
8579 size_t userpw_b64_len = strlen(userpw_b64);
8580 size_t buf_len_r = buf_size;
8582 userpw_b64, userpw_b64_len, (
unsigned char *)buf, &buf_len_r)
8586 split = strchr(buf,
':');
8611 (void)
mg_strlcpy(buf, auth_header + 7, buf_size);
8617 while (isspace((
unsigned char)*
s)) {
8633 if (*
name ==
'\0') {
8637 if (!strcmp(
name,
"username")) {
8639 }
else if (!strcmp(
name,
"cnonce")) {
8641 }
else if (!strcmp(
name,
"response")) {
8643 }
else if (!strcmp(
name,
"uri")) {
8645 }
else if (!strcmp(
name,
"qop")) {
8647 }
else if (!strcmp(
name,
"nc")) {
8649 }
else if (!strcmp(
name,
"nonce")) {
8654#if !defined(NO_NONCE_CHECK)
8660 nonce = strtoull(
ah->
nonce, &
s, 10);
8661 if ((
s ==
NULL) || (*
s != 0)) {
8703 return fgets(buf, (
int)size, filep->
access.
fp);
8715#define INITIAL_DEPTH 9
8716#if INITIAL_DEPTH <= 0
8717#error Bad INITIAL_DEPTH for recursion, set to at least 1
8720#if !defined(NO_FILESYSTEMS)
8737 int is_authorized = 0;
8741 if (!filep || !workdata || (0 ==
depth)) {
8747 l = strlen(workdata->
buf);
8749 if (isspace((
unsigned char)workdata->
buf[l - 1])
8750 || iscntrl((
unsigned char)workdata->
buf[l - 1])) {
8752 workdata->
buf[l] = 0;
8762 if (workdata->
f_user[0] ==
':') {
8766 if (workdata->
f_user[1] ==
'#') {
8769 }
else if (!strncmp(workdata->
f_user + 1,
"include=", 8)) {
8782 if (is_authorized) {
8783 return is_authorized;
8787 "%s: cannot open authorization file: %s",
8796 "%s: syntax error in authorization file: %s",
8805 "%s: syntax error in authorization file: %s",
8816 "%s: syntax error in authorization file: %s",
8821 *(
char *)(workdata->
f_ha1) = 0;
8822 (workdata->
f_ha1)++;
8826 switch (workdata->
ah.
type) {
8837 return 0 == memcmp(workdata->
f_ha1, md5, 33);
8855 return is_authorized;
8870 memset(&workdata, 0,
sizeof(workdata));
8895 const char *filename)
8900 if (!conn || !filename) {
8920#if !defined(NO_FILESYSTEMS)
8922 struct vec uri_vec, filename_vec;
8925 int authorized = 1, truncated;
8927 if (!conn || !conn->
dom_ctx) {
8939 (
int)filename_vec.
len,
8945 "%s: cannot open %s: %s",
9003 "Digest qop=\"auth\", realm=\"%s\", "
9033#if !defined(NO_FILES)
9043 if (passfile !=
NULL
9062 int found = 0, i, result = 1;
9063 char line[512], u[256], d[256], h[256];
9064 struct stat st = {0};
9066 char *temp_file =
NULL;
9067 int temp_file_offs = 0;
9070 if ((ha1 !=
NULL) && (ha1[0] ==
'\0')) {
9075 if ((fname ==
NULL) || (domain ==
NULL) || (user ==
NULL)) {
9081 if (strchr(user,
':') !=
NULL) {
9084 if (strchr(domain,
':') !=
NULL) {
9090 for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
9091 if (iscntrl((
unsigned char)user[i])) {
9098 for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
9099 if (iscntrl((
unsigned char)domain[i])) {
9113 if (0 == stat(fname, &st)) {
9115 if (st.st_size > 10485760) {
9121 temp_buf_len = (int)st.st_size + 1024;
9124 temp_file = (
char *)
mg_calloc((
size_t)temp_buf_len, 1);
9131 fp = fopen(fname,
"r");
9139 while ((fgets(line,
sizeof(line), fp) !=
NULL)
9140 && ((temp_file_offs + 600) < temp_buf_len)) {
9142 if (sscanf(line,
"%255[^:]:%255[^:]:%255s", u, d, h) != 3) {
9149 if (!strcmp(u, user) && !strcmp(d, domain)) {
9152 if ((ha1 !=
NULL) && (!found)) {
9153 i = sprintf(temp_file + temp_file_offs,
9163 temp_file_offs += i;
9168 i = sprintf(temp_file + temp_file_offs,
"%s:%s:%s\n", u, d, h);
9174 temp_file_offs += i;
9181 fp = fopen(fname,
"w");
9189 if (fchmod(fileno(fp), S_IRUSR | S_IWUSR) != 0) {
9194 if ((temp_file !=
NULL) && (temp_file_offs > 0)) {
9196 if (
fwrite(temp_file, 1, (
size_t)temp_file_offs, fp)
9197 != (
size_t)temp_file_offs) {
9203 if ((ha1 !=
NULL) && (!found)) {
9204 if (fprintf(fp,
"%s:%s:%s\n", user, domain, ha1) < 6) {
9210 if (fclose(fp) != 0) {
9226 if ((fname ==
NULL) || (domain ==
NULL) || (user ==
NULL)) {
9229 if ((pass ==
NULL) || (pass[0] == 0)) {
9233 mg_md5(ha1buf, user,
":", domain,
":", pass,
NULL);
9241 return (port <= 0xffff);
9246mg_inet_pton(
int af,
const char *src,
void *dst,
size_t dstlen,
int resolve_src)
9248 struct addrinfo hints, *res, *ressave;
9252 memset(&hints, 0,
sizeof(
struct addrinfo));
9253 hints.ai_family = af;
9255 hints.ai_flags = AI_NUMERICHOST;
9258 gai_ret = getaddrinfo(src,
NULL, &hints, &res);
9273 if ((dstlen >= (
size_t)res->ai_addrlen)
9274 && (res->ai_addr->sa_family == af)) {
9275 memcpy(dst, res->ai_addr, res->ai_addrlen);
9281 freeaddrinfo(ressave);
9301 memset(sa, 0,
sizeof(*sa));
9309 error->text_buffer_size,
9316#if defined(USE_X_DOM_SOCKET)
9319 size_t hostlen = strlen(host);
9320 if (hostlen >=
sizeof(sa->sun.sun_path)) {
9326 error->text_buffer_size,
9328 "host length exceeds limit");
9340 error->text_buffer_size,
9347#if !defined(NO_SSL) && !defined(USE_MBEDTLS) && !defined(NO_SSL_DL)
9348#if defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)
9349 if (use_ssl && (TLS_client_method ==
NULL)) {
9355 error->text_buffer_size,
9357 "SSL is not initialized");
9362 if (use_ssl && (SSLv23_client_method ==
NULL)) {
9368 error->text_buffer_size,
9370 "SSL is not initialized");
9379#if defined(USE_X_DOM_SOCKET)
9381 size_t hostlen = strlen(host);
9384 sa->sun.sun_family = AF_UNIX;
9385 memset(sa->sun.sun_path, 0,
sizeof(sa->sun.sun_path));
9386 memcpy(sa->sun.sun_path, host, hostlen);
9390 sa->
sin.sin_port = htons((uint16_t)port);
9392#if defined(USE_IPV6)
9393 }
else if (
mg_inet_pton(AF_INET6, host, &sa->sin6,
sizeof(sa->sin6), 1)) {
9394 sa->sin6.sin6_port = htons((uint16_t)port);
9396 }
else if (host[0] ==
'[') {
9399 size_t l = strlen(host + 1);
9403 if (
mg_inet_pton(AF_INET6, h, &sa->sin6,
sizeof(sa->sin6), 0)) {
9404 sa->sin6.sin6_port = htons((uint16_t)port);
9418 error->text_buffer_size,
9426 *sock =
socket(PF_INET, SOCK_STREAM, 0);
9428#if defined(USE_IPV6)
9429 else if (ip_ver == 6) {
9430 *sock =
socket(PF_INET6, SOCK_STREAM, 0);
9433#if defined(USE_X_DOM_SOCKET)
9434 else if (ip_ver == -99) {
9435 *sock =
socket(AF_UNIX, SOCK_STREAM, 0);
9446 error->text_buffer_size,
9460 error->text_buffer_size,
9461 "Cannot set socket to non-blocking: %s",
9473 conn_ret = connect(*sock,
9474 (
struct sockaddr *)((
void *)&sa->
sin),
9477#if defined(USE_IPV6)
9478 else if (ip_ver == 6) {
9480 conn_ret = connect(*sock,
9481 (
struct sockaddr *)((
void *)&sa->sin6),
9485#if defined(USE_X_DOM_SOCKET)
9486 else if (ip_ver == -99) {
9488 conn_ret = connect(*sock,
9489 (
struct sockaddr *)((
void *)&sa->sun),
9494 if (conn_ret != 0) {
9499 if ((conn_ret != 0) && (sockerr == WSAEWOULDBLOCK)) {
9501 if ((conn_ret != 0) && (sockerr == EINPROGRESS)) {
9504 void *psockerr = &sockerr;
9508 int len = (int)
sizeof(sockerr);
9510 socklen_t len = (socklen_t)
sizeof(sockerr);
9516 int ms_wait = 10000;
9526 pfd[0].events = POLLOUT;
9536 error->text_buffer_size,
9537 "connect(%s:%d): timeout",
9547 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, (
char *)psockerr, &len);
9549 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, psockerr, &len);
9552 if ((ret == 0) && (sockerr == 0)) {
9557 if (conn_ret != 0) {
9565 error->text_buffer_size,
9566 "connect(%s:%d): error %s",
9583 static const char *dont_escape =
"._-$,;~()";
9584 static const char *hex =
"0123456789abcdef";
9586 const char *end = dst + dst_len - 1;
9588 for (; ((*src !=
'\0') && (pos < end)); src++, pos++) {
9589 if (isalnum((
unsigned char)*src)
9590 || (strchr(dont_escape, *src) !=
NULL)) {
9592 }
else if (pos + 2 < end) {
9594 pos[1] = hex[(
unsigned char)*src >> 4];
9595 pos[2] = hex[(
unsigned char)*src & 0xf];
9603 return (*src ==
'\0') ? (int)(pos - dst) : -1;
9611 size_t namesize, escsize, i;
9612 char *href, *esc, *p;
9613 char size[64], mod[64];
9614#if defined(REENTRANT_TIME)
9616 struct tm *tm = &_tm;
9624 href = (
char *)
mg_malloc(namesize * 3 + escsize);
9632 esc = href + namesize * 3;
9633 for (i = 0, p = esc;
de->
file_name[i]; i++, p += strlen(p)) {
9637 }
else if (*p ==
'<') {
9639 }
else if (*p ==
'>') {
9689#if defined(REENTRANT_TIME)
9695 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", tm);
9697 mg_strlcpy(mod,
"01-Jan-1970 00:00",
sizeof(mod));
9700 "<tr><td><a href=\"%s%s\">%s%s</a></td>"
9701 "<td> %s</td><td> %s</td></tr>\n",
9718 const char *query_string = (
const char *)(
arg !=
NULL ?
arg :
"");
9720 const struct de *
a = (
const struct de *)p1, *b = (
const struct de *)p2;
9723 if ((query_string ==
NULL) || (query_string[0] ==
'\0')) {
9728 if (
a->file.is_directory && !b->file.is_directory) {
9730 }
else if (!
a->file.is_directory && b->file.is_directory) {
9735 if (*query_string ==
's') {
9736 cmp_result = (
a->file.size == b->file.size)
9738 : ((
a->file.size > b->file.size) ? 1 : -1);
9739 }
else if (*query_string ==
'd') {
9741 (
a->file.last_modified == b->file.last_modified)
9743 : ((
a->file.last_modified > b->file.last_modified) ? 1
9751 if (cmp_result == 0) {
9752 cmp_result = strcmp(
a->file_name, b->file_name);
9756 return (query_string[1] ==
'd') ? -cmp_result : cmp_result;
9768 return (match_prefix_strlen(pw_pattern, path) > 0)
9769 || (match_prefix_strlen(pattern, path) > 0);
9775#if !defined(NO_FILESYSTEMS)
9780 int (*cb)(
struct de *,
void *))
9794 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")
9800 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
9816 "%s: mg_stat(%s) failed: %s",
9822 if (cb(&
de, data)) {
9834#if !defined(NO_FILES)
9852 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")) {
9857 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
9874 "%s: mg_stat(%s) failed: %s",
9909#if !defined(NO_FILESYSTEMS)
9921 dsd->
arr_size * 2 *
sizeof(entries[0]));
9922 if (entries ==
NULL) {
9947 char date[64], *esc, *p;
9949 time_t curtime = time(
NULL);
9958 "Error: Cannot open directory\nopendir(%s): %s",
9968 if (title[strcspn(title,
"&<>")]) {
9970 esc = (
char *)
mg_malloc(strlen(title) * 5 + 1);
9972 for (i = 0, p = esc; title[i]; i++, p += strlen(p)) {
9976 }
else if (*p ==
'<') {
9978 }
else if (*p ==
'>') {
10001 "text/html; charset=utf-8",
10010 "<html><head><title>Index of %s</title>"
10011 "<style>th {text-align: left;}</style></head>"
10012 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
10013 "<tr><th><a href=\"?n%c\">Name</a></th>"
10014 "<th><a href=\"?d%c\">Modified</a></th>"
10015 "<th><a href=\"?s%c\">Size</a></th></tr>"
10016 "<tr><td colspan=\"3\"><hr></td></tr>",
10026 "<tr><td><a href=\"%s\">%s</a></td>"
10027 "<td> %s</td><td> %s</td></tr>\n",
10029 "Parent directory",
10047 mg_printf(conn,
"%s",
"</table></pre></body></html>");
10062 int to_read, num_read, num_written;
10065 if (!filep || !conn) {
10072 offset = (offset < 0) ? 0 : ((offset > size) ? size : offset);
10076#if defined(__linux__)
10081 off_t sf_offs = (off_t)offset;
10083 int sf_file = fileno(filep->
access.
fp);
10090 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
10092 sendfile(conn->
client.
sock, sf_file, &sf_offs, sf_tosend);
10096 }
else if (loop_cnt == 0) {
10102 }
else if (sf_sent == 0) {
10108 }
while ((len > 0) && (sf_sent >= 0));
10117 offset = (int64_t)sf_offs;
10120 if ((offset > 0) && (fseeko(filep->
access.
fp, offset, SEEK_SET) != 0)) {
10122 "%s: fseeko() failed: %s",
10129 "Error: Unable to access file at requested position.");
10142 to_read = no_buffering ? 1 :
sizeof(buf);
10143 if ((int64_t)to_read > len) {
10144 to_read = (int)len;
10155 if ((num_written =
mg_write(conn, buf, (
size_t)num_read))
10161 len -= num_written;
10171 return sscanf(header,
10183 if ((filestat !=
NULL) && (buf !=
NULL)) {
10202 if (fcntl(fileno(filep->
fp), F_SETFD, FD_CLOEXEC) != 0) {
10204 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
10213#if defined(USE_ZLIB)
10214#include "mod_zlib.inl"
10218#if !defined(NO_FILESYSTEMS)
10224 const char *additional_headers)
10226 char lm[64], etag[64];
10228 const char *range_hdr;
10229 int64_t cl, r1, r2;
10230 struct vec mime_vec;
10233 const char *encoding = 0;
10234 int is_head_request;
10236#if defined(USE_ZLIB)
10240 int allow_on_the_fly_compression = 1;
10258 "Error: File size is too large to send\n%" INT64_FMT,
10266#if defined(USE_ZLIB)
10271 allow_on_the_fly_compression = 0;
10280 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
10285 "Error: Path of zipped file too long (%s)",
10293#if defined(USE_ZLIB)
10295 allow_on_the_fly_compression = 0;
10301 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
10303 if (!truncated &&
mg_stat(conn, gz_path, &file_stat)
10306 filep->
stat = file_stat;
10311#if defined(USE_ZLIB)
10313 allow_on_the_fly_compression = 0;
10321 "Error: Cannot open file\nfopen(%s): %s",
10332 if ((range_hdr !=
NULL)
10342 "Error: Range requests in gzipped files are not supported");
10348 cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
10359#if defined(USE_ZLIB)
10361 allow_on_the_fly_compression = 0;
10367#if defined(USE_ZLIB)
10370 allow_on_the_fly_compression = 0;
10386 (
int)mime_vec.
len);
10390#if defined(USE_ZLIB)
10392 if (allow_on_the_fly_compression) {
10421 if (range[0] != 0) {
10427 if ((additional_headers !=
NULL) && (*additional_headers != 0)) {
10434 if (!is_head_request) {
10435#if defined(USE_ZLIB)
10436 if (allow_on_the_fly_compression) {
10438 send_compressed_data(conn, filep);
10465#if !defined(NO_CACHING)
10472 const char *ims =
mg_get_header(conn,
"If-Modified-Since");
10486 char lm[64], etag[64];
10488 if ((conn ==
NULL) || (filep ==
NULL)) {
10508#if !defined(NO_FILESYSTEMS)
10529 const char *additional_headers)
10539#if !defined(NO_CACHING)
10553 "Error: Directory listing denied");
10557 conn, path, &file,
mime_type, additional_headers);
10580 for (
s = p = path + 2; (p = strchr(
s,
'/')) !=
NULL;
s = ++p) {
10581 len = (size_t)(p - path);
10582 if (len >=
sizeof(buf)) {
10587 memcpy(buf, path, len);
10599 if (p[1] ==
'\0') {
10614 "%s: Cannot remove invalid file %s",
10649 ret =
mg_read(conn, buf,
sizeof(buf));
10659 ret =
mg_read(conn, buf,
sizeof(buf));
10684 while (isgraph((
unsigned char)**ppw)) {
10691 if ((**ppw !=
'\r') && (**ppw !=
'\n')) {
10696 if (**ppw !=
' ') {
10705 }
while (isspace((
unsigned char)**ppw));
10710 if (!isgraph((
unsigned char)**ppw)) {
10728 int num_headers = 0;
10734 while ((*dp !=
':') && (*dp >= 33) && (*dp <= 126)) {
10743 while (*dp ==
' ') {
10755 hdr[i].name = *buf;
10760 }
while ((*dp ==
' ') || (*dp ==
'\t'));
10766 while ((*dp != 0) && (*dp !=
'\r') && (*dp !=
'\n')) {
10782 num_headers = i + 1;
10789 if ((dp[0] ==
'\r') || (dp[0] ==
'\n')) {
10798 return num_headers;
10815 {
"GET", 0, 1, 1, 1, 1},
10816 {
"POST", 1, 1, 0, 0, 0},
10817 {
"PUT", 1, 0, 0, 1, 0},
10818 {
"DELETE", 0, 0, 0, 1, 0},
10819 {
"HEAD", 0, 0, 1, 1, 1},
10820 {
"OPTIONS", 0, 0, 1, 1, 0},
10821 {
"CONNECT", 1, 1, 0, 0, 0},
10825 {
"PATCH", 1, 0, 0, 0, 0},
10829 {
"PROPFIND", 0, 1, 1, 1, 0},
10835 {
"MKCOL", 0, 0, 0, 1, 0},
10848 {
"LOCK", 1, 1, 0, 0, 0},
10849 {
"UNLOCK", 1, 0, 0, 0, 0},
10850 {
"PROPPATCH", 1, 1, 0, 0, 0},
10851 {
"COPY", 1, 0, 0, 0, 0},
10852 {
"MOVE", 1, 1, 0, 0, 0},
10863 {
"REPORT", 1, 1, 1, 1, 1},
10870 {
NULL, 0, 0, 0, 0, 0}
10889 if (!strcmp(m->
name, method)) {
10917 int request_length;
10929 while ((len > 0) && isspace((
unsigned char)*buf)) {
10941 if (iscntrl((
unsigned char)*buf)) {
10947 if (request_length <= 0) {
10948 return request_length;
10950 buf[request_length - 1] =
'\0';
10952 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
10996 return request_length + init_skip;
11003 int response_length;
11015 while ((len > 0) && isspace((
unsigned char)*buf)) {
11027 if (iscntrl((
unsigned char)*buf)) {
11033 if (response_length <= 0) {
11034 return response_length;
11036 buf[response_length - 1] =
'\0';
11038 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
11044 if (strncmp(buf,
"HTTP/", 5) != 0) {
11049 if (!isgraph((
unsigned char)buf[0])) {
11066 l = strtol(tmp, &tmp2, 10);
11067 if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
11078 while (isprint((
unsigned char)*buf)) {
11081 if ((*buf !=
'\r') && (*buf !=
'\n')) {
11088 }
while (isspace((
unsigned char)*buf));
11097 return response_length + init_skip;
11113 int request_len, n = 0;
11114 struct timespec last_action_time;
11115 double request_timeout;
11121 memset(&last_action_time, 0,
sizeof(last_action_time));
11142 while (request_len == 0) {
11149 if (*nread >= bufsiz) {
11155 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
11162 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
11169 if ((request_len == 0) && (request_timeout >= 0)) {
11171 > request_timeout) {
11178 return request_len;
11182#if !defined(NO_CGI) || !defined(NO_FILES)
11186 const char *expect;
11206 if (expect !=
NULL) {
11207 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
11221 int nread =
mg_read(conn, buf,
sizeof(buf));
11223 success = (nread == 0);
11245#if defined(USE_TIMERS)
11247#define TIMER_API static
11248#include "timer.inl"
11253#if !defined(NO_CGI)
11286 size_t i, n, space;
11291 if ((env->varlen - env->varused) < 2) {
11293 "%s: Cannot register CGI variable [%s]",
11300 space = (env->buflen - env->bufused);
11307 added = (
char *)
mg_realloc_ctx(env->buf, n, env->conn->phys_ctx);
11312 "%s: Cannot allocate memory for CGI variable [%s]",
11320 for (i = 0, n = 0; i < env->varused; i++) {
11321 env->var[i] = added + n;
11322 n += strlen(added + n) + 1;
11324 space = (env->buflen - env->bufused);
11328 added = env->buf + env->bufused;
11332 mg_vsnprintf(env->conn, &truncated, added, space - 1, fmt, ap);
11340 }
while (truncated);
11343 n = strlen(added) + 1;
11347 env->var[env->varused] = added;
11357 int cgi_config_idx)
11360 struct vec var_vec;
11362 int i, truncated, uri_len;
11364 if ((conn ==
NULL) || (prog ==
NULL) || (env ==
NULL)) {
11374 "%s: Not enough memory for environmental buffer",
11384 "%s: Not enough memory for environmental variables",
11396 addenv(env,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
11397 addenv(env,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
11398 addenv(env,
"%s",
"REDIRECT_STATUS=200");
11403 addenv(env,
"REMOTE_ADDR=%s", src_addr);
11420 const char *index_file = strrchr(prog,
'/');
11423 "SCRIPT_NAME=%s%s",
11431 "SCRIPT_NAME=%.*s",
11432 uri_len - (
int)strlen(conn->
path_info),
11436 addenv(env,
"SCRIPT_FILENAME=%s", prog);
11441 "PATH_TRANSLATED=%s%s",
11446 addenv(env,
"HTTPS=%s", (conn->
ssl ==
NULL) ?
"off" :
"on");
11449 addenv(env,
"CONTENT_TYPE=%s",
s);
11455 addenv(env,
"CONTENT_LENGTH=%s",
s);
11457 if ((
s = getenv(
"PATH")) !=
NULL) {
11470 if ((
s = getenv(
"COMSPEC")) !=
NULL) {
11471 addenv(env,
"COMSPEC=%s",
s);
11473 if ((
s = getenv(
"SYSTEMROOT")) !=
NULL) {
11474 addenv(env,
"SYSTEMROOT=%s",
s);
11476 if ((
s = getenv(
"SystemDrive")) !=
NULL) {
11477 addenv(env,
"SystemDrive=%s",
s);
11479 if ((
s = getenv(
"ProgramFiles")) !=
NULL) {
11480 addenv(env,
"ProgramFiles=%s",
s);
11482 if ((
s = getenv(
"ProgramFiles(x86)")) !=
NULL) {
11483 addenv(env,
"ProgramFiles(x86)=%s",
s);
11486 if ((
s = getenv(
"LD_LIBRARY_PATH")) !=
NULL) {
11487 addenv(env,
"LD_LIBRARY_PATH=%s",
s);
11491 if ((
s = getenv(
"PERLLIB")) !=
NULL) {
11492 addenv(env,
"PERLLIB=%s",
s);
11497 addenv(env,
"%s",
"AUTH_TYPE=Digest");
11506 sizeof(http_var_name),
11512 "%s: HTTP header variable too long [%s]",
11519 for (p = http_var_name; *p !=
'\0'; p++) {
11523 *p = (char)toupper((
unsigned char)*p);
11562 ret_pid = waitpid(proc->
pid, &status, WNOHANG);
11563 if ((ret_pid != (pid_t)-1) && (status == 0)) {
11566 kill(proc->
pid, SIGABRT);
11569 while (waitpid(proc->
pid, &status, 0) != (pid_t)-1)
11572 DEBUG_TRACE(
"CGI timer: Child process %d already stopped\n", proc->
pid);
11589 int cgi_config_idx)
11593 int headers_len, data_len, i, truncated;
11594 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
11595 const char *status, *status_text;
11601 pid_t pid = (pid_t)-1;
11604 int no_buffering = 0;
11606#if defined(USE_TIMERS)
11607 double cgi_timeout;
11611 atof(conn->
dom_ctx->
config[CGI_TIMEOUT + cgi_config_idx]) * 0.001;
11617 if (cfg_buffering !=
NULL) {
11635 (void)
mg_snprintf(conn, &truncated, dir,
sizeof(dir),
"%s", prog);
11638 mg_cry_internal(conn,
"Error: CGI program \"%s\": Path too long", prog);
11643 if ((p = strrchr(dir,
'/')) !=
NULL) {
11651 if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) {
11652 status = strerror(
ERRNO);
11655 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
11660 "Error: Cannot create CGI pipe: %s",
11667 if (proc ==
NULL) {
11668 mg_cry_internal(conn,
"Error: CGI program \"%s\": Out or memory", prog);
11675 conn, p, blk.
buf, blk.
var, fdin, fdout, fderr, dir, cgi_config_idx);
11677 if (
pid == (pid_t)-1) {
11678 status = strerror(
ERRNO);
11681 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
11694#if defined(USE_TIMERS)
11695 if (cgi_timeout > 0.0) {
11713 (void)close(fdin[0]);
11714 (void)close(fdout[1]);
11715 (void)close(fderr[1]);
11716 fdin[0] = fdout[1] = fderr[1] = -1;
11718 if (((in = fdopen(fdin[1],
"wb")) ==
NULL)
11719 || ((out = fdopen(fdout[0],
"rb")) ==
NULL)
11720 || ((err = fdopen(fderr[0],
"rb")) ==
NULL)) {
11721 status = strerror(
ERRNO);
11723 "Error: CGI program \"%s\": Can not open fd: %s",
11728 "Error: CGI can not open fd\nfdopen: %s",
11747 "Error: CGI program \"%s\": Forward body data failed",
11767 "Error: Not enough memory for CGI buffer (%u bytes)",
11768 (
unsigned int)buflen);
11771 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
11774 (
unsigned int)buflen);
11779 headers_len =
read_message(out, conn, buf, (
int)buflen, &data_len);
11780 DEBUG_TRACE(
"CGI: response: %li", (
signed long)headers_len);
11782 if (headers_len <= 0) {
11786 i =
pull_all(err, conn, buf, (
int)buflen);
11791 "Error: CGI program \"%s\" sent error "
11799 "Error: CGI program \"%s\" failed.",
11805 "Error: CGI program sent malformed or too big "
11806 "(>%u bytes) HTTP headers: [%.*s]",
11813 "Error: CGI program sent malformed or too big "
11814 "(>%u bytes) HTTP headers: [%.*s]",
11825 buf[headers_len - 1] =
'\0';
11829 status_text =
"OK";
11833 status_text = status;
11834 while (isdigit((
unsigned char)*status_text) || *status_text ==
' ') {
11865 mg_write(conn, buf + headers_len, (
size_t)(data_len - headers_len));
11876 if (
pid != (pid_t)-1) {
11880 if (fdin[0] != -1) {
11883 if (fdout[1] != -1) {
11886 if (fderr[1] != -1) {
11892 }
else if (fdin[1] != -1) {
11898 }
else if (fdout[0] != -1) {
11904 }
else if (fderr[0] != -1) {
11913#if !defined(NO_FILES)
11920 if (conn ==
NULL) {
11930 "%s: mg_stat(%s) failed: %s",
11941 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11946 if (body_len > 0) {
11948 conn, 415,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11964 int http_status = 500;
11979 "Error processing %s: %s",
11996 const char *overwrite_hdr;
11997 const char *destination_hdr;
11999 int rc, dest_uri_type;
12000 int http_status = 400;
12001 int do_overwrite = 0;
12002 int destination_ok = 0;
12006 if (conn ==
NULL) {
12013 if ((overwrite_hdr !=
NULL) && (toupper(overwrite_hdr[0]) ==
'T')) {
12017 if ((destination_hdr ==
NULL) || (destination_hdr[0] == 0)) {
12022 if (root !=
NULL) {
12023 char *local_dest =
NULL;
12025 if (dest_uri_type == 2) {
12027 }
else if ((dest_uri_type == 3) || (dest_uri_type == 4)) {
12031 size_t len = strlen(h);
12036 if (local_dest !=
NULL) {
12038 if (local_dest[0] ==
'/') {
12039 int trunc_check = 0;
12047 if (trunc_check == 0) {
12048 destination_ok = 1;
12055 if (!destination_ok) {
12061 if (
mg_stat(conn, dest_path, &ignored)) {
12063 if (do_overwrite) {
12065 if (0 != remove(dest_path)) {
12069 "Cannot overwrite file: %s",
12077 "Destination already exists: %s",
12084 DEBUG_TRACE(
"%s %s to %s", (do_copy ?
"copy" :
"move"), path, dest_path);
12088 wchar_t wSource[UTF16_PATH_MAX];
12089 wchar_t wDest[UTF16_PATH_MAX];
12092 path_to_unicode(conn, path, wSource,
ARRAY_SIZE(wSource));
12093 path_to_unicode(conn, dest_path, wDest,
ARRAY_SIZE(wDest));
12095 ok = CopyFileW(wSource, wDest, do_overwrite ?
FALSE :
TRUE);
12097 ok = MoveFileExW(wSource,
12099 do_overwrite ? MOVEFILE_REPLACE_EXISTING : 0);
12104 DWORD lastErr = GetLastError();
12105 if (lastErr == ERROR_ALREADY_EXISTS) {
12108 "Destination already exists: %s",
12127 rc = rename(path, dest_path);
12165 if (conn ==
NULL) {
12185 if (
access(path, W_OK) == 0) {
12192 "Error: Put not possible\nReplacing %s is not allowed",
12224 "Error: Path too long\nput_dir(%s): %s",
12234 "Error: Can not create directory\nput_dir(%s): %s",
12247 "Error: Can not create file\nfopen(%s): %s",
12258 if (0 != fseeko(file.
access.
fp, r1, SEEK_SET)) {
12261 "Error: Internal error processing file %s",
12301 "Error: Cannot delete file\nFile %s not found",
12321 if (access(path, W_OK) != 0) {
12326 "Error: Delete not possible\nDeleting %s is not allowed",
12344 "Error: Cannot delete file\nremove(%s): %s",
12352#if !defined(NO_FILESYSTEMS)
12368 if (conn ==
NULL) {
12375 if (sscanf(tag,
" virtual=\"%511[^\"]\"", file_name) == 1) {
12377 file_name[511] = 0;
12386 }
else if (sscanf(tag,
" abspath=\"%511[^\"]\"", file_name) == 1) {
12389 file_name[511] = 0;
12391 mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", file_name);
12393 }
else if ((sscanf(tag,
" file=\"%511[^\"]\"", file_name) == 1)
12394 || (sscanf(tag,
" \"%511[^\"]\"", file_name) == 1)) {
12396 file_name[511] = 0;
12397 (void)
mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", ssi);
12400 if ((p = strrchr(path,
'/')) !=
NULL) {
12403 len = strlen(path);
12407 sizeof(path) - len,
12418 mg_cry_internal(conn,
"SSI #include path length overflow: [%s]", tag);
12424 "Cannot open SSI #include: [%s]: fopen(%s): %s",
12441#if !defined(NO_POPEN)
12445 char cmd[1024] =
"";
12448 if (sscanf(tag,
" \"%1023[^\"]\"", cmd) != 1) {
12454 "Cannot SSI #exec: [%s]: %s",
12469 if (filep ==
NULL) {
12488 int ch, len, in_tag, in_ssi_tag;
12490 if (include_level > 10) {
12495 in_tag = in_ssi_tag = len = 0;
12498 while ((ch =
mg_fgetc(filep)) != EOF) {
12511 if ((len > 12) && !memcmp(buf + 5,
"include", 7)) {
12513#if !defined(NO_POPEN)
12514 }
else if ((len > 9) && !memcmp(buf + 5,
"exec", 4)) {
12525 in_ssi_tag = in_tag = 0;
12530 (void)
mg_write(conn, buf, (
size_t)len);
12537 buf[len++] = (char)(ch & 0xff);
12539 if ((len == 5) && !memcmp(buf,
"<!--#", 5)) {
12544 if ((len + 2) > (int)
sizeof(buf)) {
12561 (void)
mg_write(conn, buf, (
size_t)len);
12570 buf[len++] = (char)(ch & 0xff);
12572 if (len == (
int)
sizeof(buf)) {
12593 time_t curtime = time(
NULL);
12595 if ((conn ==
NULL) || (path ==
NULL) || (filep ==
NULL)) {
12604 "Error: Cannot read file\nfopen(%s): %s",
12630#if !defined(NO_FILES)
12669 size_t link_concat_len;
12675 link_concat_len = strlen(uri) + strlen(
name) + 1;
12677 if (!link_concat) {
12680 strcpy(link_concat, uri);
12681 strcat(link_concat,
name);
12685 conn, link_buf,
sizeof(link_buf),
NULL, 0, link_concat);
12700 "<d:href>%s</d:href>"
12703 "<d:resourcetype>%s</d:resourcetype>"
12704 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
12705 "<d:getlastmodified>%s</d:getlastmodified>"
12706 "<d:lockdiscovery>",
12714 if (!strcmp(dav_lock[i].
path, link_buf)) {
12717 "<d:locktype><d:write/></d:locktype>"
12718 "<d:lockscope><d:exclusive/></d:lockscope>"
12719 "<d:depth>0</d:depth>"
12720 "<d:owner>%s</d:owner>"
12721 "<d:timeout>Second-%u</d:timeout>"
12723 "<d:href>%s</d:href>"
12725 "</d:activelock>\n",
12728 dav_lock[i].
token);
12733 "</d:lockdiscovery>"
12735 "<d:status>HTTP/1.1 200 OK</d:status>"
12737 "</d:response>\n");
12765 if (!conn || !path || !filep || !conn->
dom_ctx) {
12776 "application/xml; charset=utf-8",
12782 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
12783 "<d:multistatus xmlns:d='DAV:'>\n");
12797 mg_printf(conn,
"%s\n",
"</d:multistatus>");
12806 uint64_t new_locktime;
12807 int lock_index = -1;
12809 uint64_t LOCK_DURATION_NS =
12828 while (lock_index < 0) {
12831 if (!strcmp(dav_lock[i].
path, link_buf)) {
12834 dav_lock[i].
locktime = new_locktime;
12840 > (dav_lock[i].
locktime + LOCK_DURATION_NS)) {
12842 dav_lock[i].
path[0] = 0;
12855 if (dav_lock[i].
path[0] == 0) {
12868 sizeof(dav_lock[i].
path));
12871 sizeof(dav_lock[i].
user));
12876 if (lock_index < 0) {
12878 uint64_t oldest_locktime = dav_lock[0].
locktime;
12881 if (dav_lock[i].
locktime < oldest_locktime) {
12882 oldest_locktime = dav_lock[i].
locktime;
12887 dav_lock[lock_index].
path[0] = 0;
12899 "application/xml; charset=utf-8",
12906 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
12907 "<d:prop xmlns:d=\"DAV:\">\n"
12908 " <d:lockdiscovery>\n"
12909 " <d:activelock>\n"
12910 " <d:lockscope><d:exclusive/></d:lockscope>\n"
12911 " <d:locktype><d:write/></d:locktype>\n"
12913 " <d:href>%s</d:href>\n"
12915 " <d:timeout>Second-%u</d:timeout>\n"
12916 " <d:locktoken><d:href>%s</d:href></d:locktoken>\n"
12918 " <d:href>%s</d:href>\n"
12920 " </d:activelock>\n"
12921 " </d:lockdiscovery>\n"
12923 dav_lock[lock_index].
user,
12925 dav_lock[lock_index].
token,
12926 dav_lock[lock_index].
path);
12947 if (!strcmp(dav_lock[lock_index].
path, link_buf)) {
12979 "application/xml; charset=utf-8",
12987 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
12988 "<d:multistatus xmlns:d='DAV:'>\n"
12989 "<d:response>\n<d:href>%s</d:href>\n",
12992 "<d:propstat><d:status>HTTP/1.1 403 "
12993 "Forbidden</d:status></d:propstat>\n");
12994 mg_printf(conn,
"%s\n",
"</d:response></d:multistatus>");
13003 (void)pthread_mutex_lock(&conn->
mutex);
13012 (void)pthread_mutex_unlock(&conn->
mutex);
13035#if defined(USE_LUA)
13036#include "mod_lua.inl"
13039#if defined(USE_DUKTAPE)
13040#include "mod_duktape.inl"
13043#if defined(USE_WEBSOCKET)
13045#if !defined(NO_SSL_DL)
13046#if !defined(OPENSSL_API_3_0)
13047#define SHA_API static
13053send_websocket_handshake(
struct mg_connection *conn,
const char *websock_key)
13055 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
13056 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
13057 size_t dst_len =
sizeof(b64_sha);
13058#if !defined(OPENSSL_API_3_0)
13064 mg_snprintf(conn, &truncated, buf,
sizeof(buf),
"%s%s", websock_key, magic);
13072#if defined(OPENSSL_API_3_0)
13073 EVP_Digest((
unsigned char *)buf,
13074 (uint32_t)strlen(buf),
13075 (
unsigned char *)sha,
13077 EVP_get_digestbyname(
"sha1"),
13080 SHA1_Init(&sha_ctx);
13081 SHA1_Update(&sha_ctx, (
unsigned char *)buf, (uint32_t)strlen(buf));
13082 SHA1_Final((
unsigned char *)sha, &sha_ctx);
13086 "HTTP/1.1 101 Switching Protocols\r\n"
13087 "Upgrade: websocket\r\n"
13088 "Connection: Upgrade\r\n"
13089 "Sec-WebSocket-Accept: %s\r\n",
13092#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13094 websocket_deflate_response(conn);
13099 "Sec-WebSocket-Protocol: %s\r\n\r\n",
13109#if !defined(MG_MAX_UNANSWERED_PING)
13115#define MG_MAX_UNANSWERED_PING (5)
13122 void *callback_data)
13128 unsigned char *buf = (
unsigned char *)conn->
buf + conn->
request_len;
13129 int n,
error, exit_by_callback;
13136 size_t i, len, mask_len = 0, header_len, body_len;
13137 uint64_t data_len = 0;
13142 unsigned char mask[4];
13147 unsigned char mem[4096];
13151 double timeout = -1.0;
13152 int enable_ping_pong = 0;
13153 int ping_count = 0;
13162 timeout = atoi(conn->
dom_ctx->
config[WEBSOCKET_TIMEOUT]) / 1000.0;
13167 if (timeout <= 0.0) {
13172 DEBUG_TRACE(
"Websocket connection %s:%u start data processing loop",
13175 conn->in_websocket_handling = 1;
13185 len = buf[1] & 127;
13186 mask_len = (buf[1] & 128) ? 4 : 0;
13187 if ((len < 126) && (body_len >= mask_len)) {
13190 header_len = 2 + mask_len;
13191 }
else if ((len == 126) && (body_len >= (4 + mask_len))) {
13193 header_len = 4 + mask_len;
13194 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
13195 }
else if (body_len >= (10 + mask_len)) {
13198 memcpy(&l1, &buf[2], 4);
13199 memcpy(&l2, &buf[6], 4);
13200 header_len = 10 + mask_len;
13201 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
13203 if (data_len > (uint64_t)0x7FFF0000ul) {
13208 "websocket out of memory; closing connection");
13214 if ((header_len > 0) && (body_len >= header_len)) {
13216 unsigned char *data = mem;
13218 if ((
size_t)data_len > (
size_t)
sizeof(mem)) {
13221 if (data ==
NULL) {
13227 "websocket out of memory; closing connection");
13233 if (mask_len > 0) {
13234 memcpy(
mask, buf + header_len - mask_len,
sizeof(
mask));
13242 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
13245 len = body_len - header_len;
13246 memcpy(data, buf + header_len, len);
13248 while ((uint64_t)len < data_len) {
13251 (
char *)(data + len),
13252 (
int)(data_len - len),
13257 }
else if (n > 0) {
13268 "Websocket pull failed; closing connection");
13285 len = (size_t)data_len + header_len;
13290 memcpy(data, buf + header_len, (
size_t)data_len);
13293 memmove(buf, buf + len, body_len - len);
13300 if (mask_len > 0) {
13301 for (i = 0; i < (size_t)data_len; i++) {
13302 data[i] ^=
mask[i & 3];
13306 exit_by_callback = 0;
13314 }
else if (enable_ping_pong
13333 if (ws_data_handler !=
NULL) {
13334#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13337 if (!conn->websocket_deflate_initialized) {
13338 if (websocket_deflate_initialize(conn, 1) != Z_OK)
13339 exit_by_callback = 1;
13341 if (!exit_by_callback) {
13342 size_t inflate_buf_size_old = 0;
13343 size_t inflate_buf_size =
13347 Bytef *inflated =
NULL;
13348 Bytef *new_mem =
NULL;
13349 conn->websocket_inflate_state.avail_in =
13350 (uInt)(data_len + 4);
13351 conn->websocket_inflate_state.next_in = data;
13353 data[data_len] =
'\x00';
13354 data[data_len + 1] =
'\x00';
13355 data[data_len + 2] =
'\xff';
13356 data[data_len + 3] =
'\xff';
13358 if (inflate_buf_size_old == 0) {
13363 inflate_buf_size *= 2;
13368 if (new_mem ==
NULL) {
13371 "Out of memory: Cannot allocate "
13372 "inflate buffer of %lu bytes",
13373 (
unsigned long)inflate_buf_size);
13374 exit_by_callback = 1;
13377 inflated = new_mem;
13378 conn->websocket_inflate_state.avail_out =
13379 (uInt)(inflate_buf_size
13380 - inflate_buf_size_old);
13381 conn->websocket_inflate_state.next_out =
13382 inflated + inflate_buf_size_old;
13383 ret = inflate(&conn->websocket_inflate_state,
13385 if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR
13386 || ret == Z_MEM_ERROR) {
13389 "ZLIB inflate error: %i %s",
13391 (conn->websocket_inflate_state.msg
13392 ? conn->websocket_inflate_state.msg
13393 :
"<no error message>"));
13394 exit_by_callback = 1;
13397 inflate_buf_size_old = inflate_buf_size;
13399 }
while (conn->websocket_inflate_state.avail_out
13401 inflate_buf_size -=
13402 conn->websocket_inflate_state.avail_out;
13403 if (!ws_data_handler(conn,
13408 exit_by_callback = 1;
13414 if (!ws_data_handler(conn,
13419 exit_by_callback = 1;
13429 if (exit_by_callback) {
13430 DEBUG_TRACE(
"Callback requests to close connection from %s:%u",
13437 DEBUG_TRACE(
"Message requests to close connection from %s:%u",
13466 if (ping_count > MG_MAX_UNANSWERED_PING) {
13468 DEBUG_TRACE(
"Too many (%i) unanswered ping from %s:%u "
13469 "- closing connection",
13475 if (enable_ping_pong) {
13501 conn->in_websocket_handling = 0;
13502 DEBUG_TRACE(
"Websocket connection %s:%u left data processing loop",
13513 uint32_t masking_key)
13515 unsigned char header[14];
13519#if defined(GCC_DIAGNOSTIC)
13521#pragma GCC diagnostic push
13522#pragma GCC diagnostic ignored "-Wconversion"
13538#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13539 size_t deflated_size = 0;
13540 Bytef *deflated = 0;
13542 int use_deflate = dataLen > 100 * 1024 && conn->
accept_gzip;
13545 if (!conn->websocket_deflate_initialized) {
13546 if (websocket_deflate_initialize(conn, 1) != Z_OK)
13551 header[0] = 0xC0u | (
unsigned char)((
unsigned)opcode & 0xf);
13552 conn->websocket_deflate_state.avail_in = (uInt)dataLen;
13553 conn->websocket_deflate_state.next_in = (
unsigned char *)data;
13554 deflated_size = (size_t)compressBound((uLong)dataLen);
13555 deflated =
mg_calloc(deflated_size,
sizeof(Bytef));
13556 if (deflated ==
NULL) {
13559 "Out of memory: Cannot allocate deflate buffer of %lu bytes",
13560 (
unsigned long)deflated_size);
13564 conn->websocket_deflate_state.avail_out = (uInt)deflated_size;
13565 conn->websocket_deflate_state.next_out = deflated;
13566 deflate(&conn->websocket_deflate_state, conn->websocket_deflate_flush);
13567 dataLen = deflated_size - conn->websocket_deflate_state.avail_out
13571 header[0] = 0x80u | (
unsigned char)((
unsigned)opcode & 0xf);
13573#if defined(GCC_DIAGNOSTIC)
13574#pragma GCC diagnostic pop
13578 if (dataLen < 126) {
13580 header[1] = (
unsigned char)dataLen;
13582 }
else if (dataLen <= 0xFFFF) {
13584 uint16_t len = htons((uint16_t)dataLen);
13586 memcpy(header + 2, &len, 2);
13590 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
13591 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
13593 memcpy(header + 2, &len1, 4);
13594 memcpy(header + 6, &len2, 4);
13601 memcpy(header + headerLen, &masking_key, 4);
13605 retval =
mg_write(conn, header, headerLen);
13606 if (retval != (
int)headerLen) {
13611#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13613 retval =
mg_write(conn, deflated, dataLen);
13617 retval =
mg_write(conn, data, dataLen);
13635 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
13640mask_data(
const char *in,
size_t in_len, uint32_t masking_key,
char *out)
13645 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
13647 while (i < (in_len - 3)) {
13648 *(uint32_t *)(
void *)(out + i) =
13649 *(uint32_t *)(
void *)(in + i) ^ masking_key;
13655 while (i < in_len) {
13656 *(uint8_t *)(
void *)(out + i) =
13657 *(uint8_t *)(
void *)(in + i)
13658 ^ *(((uint8_t *)&masking_key) + (i % 4));
13672 char *masked_data =
13674 uint32_t masking_key = 0;
13676 if (masked_data ==
NULL) {
13680 "Cannot allocate buffer for masked websocket response: "
13688 }
while (masking_key == 0);
13690 mask_data(data, dataLen, masking_key, masked_data);
13692 retval = mg_websocket_write_exec(
13693 conn, opcode, masked_data, dataLen, masking_key);
13703 int is_callback_resource,
13711 const char *websock_key =
mg_get_header(conn,
"Sec-WebSocket-Key");
13712 const char *version =
mg_get_header(conn,
"Sec-WebSocket-Version");
13713 ptrdiff_t lua_websock = 0;
13715#if !defined(USE_LUA)
13721 if (!websock_key) {
13728 const char *key1 =
mg_get_header(conn,
"Sec-WebSocket-Key1");
13729 const char *key2 =
mg_get_header(conn,
"Sec-WebSocket-Key2");
13732 if ((key1 !=
NULL) && (key2 !=
NULL)) {
13735 if (8 ==
mg_read(conn, key3, 8)) {
13740 "Protocol upgrade to RFC 6455 required");
13751 if ((version ==
NULL) || (strcmp(version,
"13") != 0)) {
13761 if (is_callback_resource) {
13763 const char *protocols[64];
13765 "Sec-WebSocket-Protocol",
13769 if ((nbSubprotocolHeader > 0) && subprotocols) {
13773 const char *sep, *curSubProtocol,
13774 *acceptedWebSocketSubprotocol =
NULL;
13777 for (headerNo = 0; headerNo < nbSubprotocolHeader; headerNo++) {
13779 const char *protocol = protocols[headerNo];
13780 curSubProtocol = protocol;
13783 while (!acceptedWebSocketSubprotocol && (*curSubProtocol)) {
13785 while ((*curSubProtocol ==
' ') || (*curSubProtocol ==
','))
13787 sep = strchr(curSubProtocol,
',');
13789 len = (size_t)(sep - curSubProtocol);
13791 len = strlen(curSubProtocol);
13798 && (strncmp(curSubProtocol,
13802 acceptedWebSocketSubprotocol =
13807 curSubProtocol += len;
13812 acceptedWebSocketSubprotocol;
13815#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13816 websocket_deflate_negotiate(conn);
13819 if ((ws_connect_handler !=
NULL)
13820 && (ws_connect_handler(conn, cbData) != 0)) {
13830#if defined(USE_LUA)
13835 lua_websock = match_prefix_strlen(
13839 if (lua_websock > 0) {
13841 conn->lua_websocket_state = lua_websocket_new(
path, conn);
13842 if (!conn->lua_websocket_state) {
13851 if (!is_callback_resource && !lua_websock) {
13861 if (!send_websocket_handshake(conn, websock_key)) {
13867 if (is_callback_resource) {
13868 if (ws_ready_handler !=
NULL) {
13869 ws_ready_handler(conn, cbData);
13871#if defined(USE_LUA)
13872 }
else if (lua_websock) {
13873 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
13881 if (is_callback_resource) {
13882 read_websocket(conn, ws_data_handler, cbData);
13883#if defined(USE_LUA)
13884 }
else if (lua_websock) {
13885 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
13889#if defined(USE_ZLIB) && defined(MG_EXPERIMENTAL_INTERFACES)
13891 if (conn->websocket_deflate_initialized) {
13892 deflateEnd(&conn->websocket_deflate_state);
13893 inflateEnd(&conn->websocket_inflate_state);
13898 if (ws_close_handler) {
13899 ws_close_handler(conn, cbData);
13914 const char *connection_headers[8];
13915 const char *upgrade_to;
13916 int connection_header_count, i, should_upgrade;
13928 connection_headers,
13930 should_upgrade = 0;
13931 for (i = 0; i < connection_header_count; i++) {
13932 if (0 !=
mg_strcasestr(connection_headers[i],
"upgrade")) {
13933 should_upgrade = 1;
13936 if (!should_upgrade) {
13941 if (upgrade_to ==
NULL) {
13969 unsigned int a, b, c, d, slash;
13971 if (sscanf(
vec->
ptr,
"%u.%u.%u.%u/%u%n", &
a, &b, &c, &d, &slash, &n)
13976 if (sscanf(
vec->
ptr,
"%u.%u.%u.%u%n", &
a, &b, &c, &d, &n)
13984 if ((n > 0) && ((
size_t)n ==
vec->
len)) {
13985 if ((
a < 256) && (b < 256) && (c < 256) && (d < 256) && (slash < 33)) {
13987 if (sa->
sa.sa_family == AF_INET) {
13988 uint32_t ip = ntohl(sa->
sin.sin_addr.s_addr);
13989 uint32_t net = ((uint32_t)
a << 24) | ((uint32_t)b << 16)
13990 | ((uint32_t)c << 8) | (uint32_t)d;
13991 uint32_t
mask = slash ? (0xFFFFFFFFu << (32 - slash)) : 0;
13992 return (ip &
mask) == net;
13997#if defined(USE_IPV6)
14002 if (sscanf(
vec->
ptr,
"[%49[^]]]/%u%n", ad, &slash, &n) != 2) {
14004 if (sscanf(
vec->
ptr,
"[%49[^]]]%n", ad, &n) != 1) {
14009 if ((n <= 0) && no_strict) {
14011 p = strchr(
vec->
ptr,
'/');
14013 if (((
size_t)(p -
vec->
ptr) <
sizeof(ad))
14014 && (sscanf(p,
"/%u%n", &slash, &n) == 1)) {
14015 n += (int)(p -
vec->
ptr);
14020 }
else if (
vec->
len <
sizeof(ad)) {
14027 if ((n > 0) && ((
size_t)n ==
vec->
len) && (slash < 129)) {
14031 while (isxdigit((
unsigned char)*p) || (*p ==
'.') || (*p ==
':')) {
14032 if (*(p++) ==
':') {
14036 if ((*p ==
'\0') && (c >= 2)) {
14037 struct sockaddr_in6 sin6;
14041 if (sa->
sa.sa_family != AF_INET6) {
14044 if (
mg_inet_pton(AF_INET6, ad, &sin6,
sizeof(sin6), 0)) {
14046 for (i = 0; i < 16; i++) {
14047 uint8_t ip = sa->sin6.sin6_addr.s6_addr[i];
14048 uint8_t net = sin6.sin6_addr.s6_addr[i];
14051 if (8 * i + 8 < slash) {
14053 }
else if (8 * i < slash) {
14054 mask = (uint8_t)(0xFFu << (8 * i + 8 - slash));
14056 if ((ip &
mask) != net) {
14085 || (sscanf(val.
ptr,
"%lf%c", &v, &mult)
14091 && (mult !=
','))) {
14096 : ((
lowercase(&mult) ==
'm') ? 1048576 : 1);
14101 if (matched >= 0) {
14117#include "handle_form.inl"
14126 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
14138 const char *host_header =
14144 if (host_header !=
NULL) {
14149 if (*host_header ==
'[') {
14150 pos = strchr(host_header,
']');
14153 DEBUG_TRACE(
"%s",
"Host name format error '[' without ']'");
14157 host->
ptr = host_header;
14158 host->
len = (size_t)(pos + 1 - host_header);
14161 pos = strchr(host_header,
':');
14163 host->
len = (size_t)(pos - host_header);
14165 host->
len = strlen(host_header);
14167 host->
ptr = host_header;
14187 if ((strlen(sslhost) != host.
len)
14190 DEBUG_TRACE(
"Host mismatch: SNI: %s, HTTPS: %.*s",
14202 size_t domNameLen = strlen(domName);
14203 if ((domNameLen == host.
len)
14221 conn->
ssl ?
"S" :
"",
14239 const char *expect_proto =
14243 int redirect_code = 308;
14250 conn, target_url,
sizeof(target_url), expect_proto, port,
NULL)
14254 size_t slen1 = strlen(target_url);
14256 if ((slen1 + slen2 + 2) <
sizeof(target_url)) {
14257 target_url[slen1] =
'?';
14258 memcpy(target_url + slen1 + 1,
14261 target_url[slen1 + slen2 + 1] = 0;
14284 int is_delete_request,
14295 size_t urilen = strlen(
uri);
14353 if (!phys_ctx || !dom_ctx) {
14364 tmp_rh = tmp_rh->
next) {
14366 && (urilen == tmp_rh->
uri_len) && !strcmp(tmp_rh->
uri,
uri)) {
14367 if (!is_delete_request) {
14404 *lastref = tmp_rh->
next;
14411 lastref = &(tmp_rh->
next);
14413 }
while (tmp_rh !=
NULL);
14415 if (is_delete_request) {
14426 if (tmp_rh ==
NULL) {
14430 "Cannot create new request handler struct, OOM");
14434 if (!tmp_rh->
uri) {
14439 "Cannot create new request handler struct, OOM");
14573 if (request_info) {
14574 const char *uri = request_info->
local_uri;
14575 size_t urilen = strlen(uri);
14585 for (step = 0; step < 3; step++) {
14587 tmp_rh = tmp_rh->
next) {
14593 matched = (tmp_rh->
uri_len == urilen)
14594 && (strcmp(tmp_rh->
uri,
uri) == 0);
14595 }
else if (step == 1) {
14623 *handler_info = tmp_rh;
14655#if defined(USE_WEBSOCKET) && defined(MG_EXPERIMENTAL_INTERFACES)
14657experimental_websocket_client_data_wrapper(
struct mg_connection *conn,
14664 if (pcallbacks->websocket_data) {
14665 return pcallbacks->websocket_data(conn, bits, data, len);
14673experimental_websocket_client_close_wrapper(
const struct mg_connection *conn,
14690 if (handler_info !=
NULL) {
14708 int uri_len, ssl_index;
14709 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
14710 is_put_or_delete_request = 0, is_callback_resource = 0,
14711 is_template_text_file = 0, is_webdav_request = 0;
14721 void *callback_data =
NULL;
14723 void *auth_callback_data =
NULL;
14725 time_t curtime = time(
NULL);
14744 if (ssl_index >= 0) {
14754 "Error: SSL forward not configured properly");
14757 "Can not redirect to SSL, no SSL port available");
14811 DEBUG_TRACE(
"%s",
"begin_request handled request");
14813 }
else if (i == 0) {
14817 DEBUG_TRACE(
"%s",
"done (undocumented behavior)");
14832 const char *cors_meth_cfg =
14834 const char *cors_orig_cfg =
14836 const char *cors_origin =
14840 "Access-Control-Request-Method");
14845 if ((cors_meth_cfg !=
NULL) && (*cors_meth_cfg != 0)
14846 && (cors_orig_cfg !=
NULL) && (*cors_orig_cfg != 0)
14847 && (cors_origin !=
NULL) && (cors_acrm !=
NULL)) {
14850 const char *cors_acrh =
14853 "Access-Control-Request-Headers");
14857 "HTTP/1.1 200 OK\r\n"
14859 "Access-Control-Allow-Origin: %s\r\n"
14860 "Access-Control-Allow-Methods: %s\r\n"
14861 "Content-Length: 0\r\n"
14862 "Connection: %s\r\n",
14865 ((cors_meth_cfg[0] ==
'*') ? cors_acrm : cors_meth_cfg),
14868 if (cors_acrh !=
NULL) {
14870 const char *cors_hdr_cfg =
14873 if ((cors_hdr_cfg !=
NULL) && (*cors_hdr_cfg != 0)) {
14880 "Access-Control-Allow-Headers: %s\r\n",
14881 ((cors_hdr_cfg[0] ==
'*') ? cors_acrh
14885 mg_printf(conn,
"Access-Control-Max-Age: 60\r\n");
14898#if defined(USE_WEBSOCKET)
14904 if (is_websocket_request) {
14913 &ws_connect_handler,
14923 is_callback_resource = 1;
14924 is_script_resource = 1;
14928 is_webdav_request = 0;
14930 no_callback_resource:
14935 is_callback_resource = 0;
14941 &is_script_resource,
14942 &is_websocket_request,
14943 &is_put_or_delete_request,
14944 &is_webdav_request,
14945 &is_template_text_file);
14949 if (is_webdav_request) {
14952 if (webdav_enable[0] !=
'y') {
14955 "%s method not allowed",
14973 &auth_callback_data,
14975 if (!auth_handler(conn, auth_callback_data)) {
14979 DEBUG_TRACE(
"%s",
"auth handler rejected request");
14982 }
else if (is_put_or_delete_request && !is_script_resource
14983 && !is_callback_resource) {
14987#if defined(NO_FILES)
15000 "%s method not allowed",
15002 DEBUG_TRACE(
"%s",
"all file based put/delete requests rejected");
15006#if !defined(NO_FILES)
15012 DEBUG_TRACE(
"%s",
"file write needs authorization");
15026 DEBUG_TRACE(
"%s",
"access authorization required");
15034 if (is_callback_resource) {
15036 if (!is_websocket_request) {
15037 i = callback_handler(conn, callback_data);
15068 callback_handler =
NULL;
15079 goto no_callback_resource;
15082#if defined(USE_WEBSOCKET)
15083 handle_websocket_request(conn,
15085 is_callback_resource,
15087 ws_connect_handler,
15099#if defined(USE_WEBSOCKET)
15100 if (is_websocket_request) {
15102 if (is_script_resource) {
15106 handle_websocket_request(conn,
15127#if defined(NO_FILES)
15143 if (is_script_resource) {
15154 if (is_put_or_delete_request) {
15224 "%s method not allowed",
15236 DEBUG_TRACE(
"handling %s request to %s: file not found",
15244 && (ri->
local_uri[uri_len - 1] !=
'/')) {
15258 strcat(new_path,
"/");
15261 strcat(new_path,
"?");
15267 DEBUG_TRACE(
"%s request to %s: directory redirection sent",
15296 "%s method not allowed",
15314 "Error: Directory listing denied");
15321 if (is_template_text_file) {
15324 DEBUG_TRACE(
"handling %s request to %s done (template)",
15331#if !defined(NO_CACHING)
15335 DEBUG_TRACE(
"handling %s request to %s done (not modified)",
15344 DEBUG_TRACE(
"handling %s request to %s done (static)",
15352#if !defined(NO_FILESYSTEMS)
15358#if !defined(NO_CGI)
15359 int cgi_config_idx, inc, max;
15362 if (!conn || !conn->
dom_ctx) {
15366#if defined(USE_LUA)
15367 if (match_prefix_strlen(conn->
dom_ctx->
config[LUA_SERVER_PAGE_EXTENSIONS],
15373 handle_lsp_request(conn, path, file,
NULL);
15381 if (match_prefix_strlen(conn->
dom_ctx->
config[LUA_SCRIPT_EXTENSIONS], path)
15386 mg_exec_lua_script(conn, path,
NULL);
15395#if defined(USE_DUKTAPE)
15396 if (match_prefix_strlen(conn->
dom_ctx->
config[DUKTAPE_SCRIPT_EXTENSIONS],
15401 mg_exec_duktape_script(conn, path);
15410#if !defined(NO_CGI)
15413 for (cgi_config_idx = 0; cgi_config_idx < max; cgi_config_idx += inc) {
15415 if (match_prefix_strlen(
15442#if !defined(NO_CACHING)
15465#if defined(USE_X_DOM_SOCKET)
15503 unsigned int a, b, c, d;
15505 unsigned long portUL;
15509#if defined(USE_IPV6)
15510 char buf[100] = {0};
15516 memset(so, 0,
sizeof(*so));
15517 so->
lsa.
sin.sin_family = AF_INET;
15526 "%u.%u.%u.%u:%u%n",
15537 so->
lsa.
sin.sin_addr.s_addr =
15538 htonl((
a << 24) | (b << 16) | (c << 8) | d);
15539 so->
lsa.
sin.sin_port = htons((uint16_t)port);
15542#if defined(USE_IPV6)
15543 }
else if (sscanf(
vec->
ptr,
"[%49[^]]]:%u%n", buf, &port, &len) == 2
15544 && ((
size_t)len <= vec->len)
15546 AF_INET6, buf, &so->
lsa.sin6,
sizeof(so->
lsa.sin6), 0)) {
15550 so->
lsa.sin6.sin6_port = htons((uint16_t)port);
15554 }
else if ((
vec->
ptr[0] ==
'+')
15555 && (sscanf(
vec->
ptr + 1,
"%u%n", &port, &len)
15565#if defined(USE_IPV6)
15567 so->
lsa.sin6.sin6_family = AF_INET6;
15568 so->
lsa.sin6.sin6_port = htons((uint16_t)port);
15569 *ip_version = 4 + 6;
15572 so->
lsa.
sin.sin_port = htons((uint16_t)port);
15577 && (
vec->
ptr != endptr)) {
15578 len = (int)(endptr -
vec->
ptr);
15579 port = (uint16_t)portUL;
15581 so->
lsa.
sin.sin_port = htons((uint16_t)port);
15584 }
else if ((cb = strchr(
vec->
ptr,
':')) !=
NULL) {
15594 char hostname[256];
15595 size_t hostnlen = (size_t)(cb -
vec->
ptr);
15597 if ((hostnlen >=
vec->
len) || (hostnlen >=
sizeof(hostname))) {
15606 AF_INET, hostname, &so->
lsa.
sin,
sizeof(so->
lsa.
sin), 1)) {
15607 if (sscanf(cb + 1,
"%u%n", &port, &len)
15613 so->
lsa.
sin.sin_port = htons((uint16_t)port);
15614 len += (int)(hostnlen + 1);
15618#if defined(USE_IPV6)
15622 sizeof(so->
lsa.sin6),
15624 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
15626 so->
lsa.sin6.sin6_port = htons((uint16_t)port);
15627 len += (int)(hostnlen + 1);
15636#if defined(USE_X_DOM_SOCKET)
15638 }
else if (
vec->
ptr[0] ==
'x') {
15640 if (
vec->
len <
sizeof(so->
lsa.sun.sun_path)) {
15642 so->
lsa.sun.sun_family = AF_UNIX;
15643 memset(so->
lsa.sun.sun_path, 0,
sizeof(so->
lsa.sun.sun_path));
15661 && (((
size_t)len ==
vec->
len) || (((
size_t)len + 1) ==
vec->
len))) {
15663 ch = ((size_t)len < vec->len) ?
vec->
ptr[len] :
'\0';
15664 so->
is_ssl = (ch ==
's');
15666 if ((ch ==
'\0') || (ch ==
's') || (ch ==
'r')) {
15717 int portslen = (int)strlen(ports);
15718 char prevIsNumber = 0;
15720 for (i = 0; i < portslen; i++) {
15721 if (prevIsNumber && (ports[i] ==
's' || ports[i] ==
'r')) {
15724 if (ports[i] >=
'0' && ports[i] <=
'9') {
15740#if defined(USE_IPV6)
15751 int portsTotal = 0;
15754 const char *opt_txt;
15755 long opt_listen_backlog;
15761 memset(&so, 0,
sizeof(so));
15762 memset(&
usa, 0,
sizeof(
usa));
15773 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
15777 "[IP_ADDRESS:]PORT[s|r]");
15781#if !defined(NO_SSL)
15785 "Cannot add SSL socket (entry %i)",
15797 (ip_version == 99) ? ( 0) : ( 6)))
15801 "cannot create socket (entry %i)",
15816 if (setsockopt(so.
sock,
15818 SO_EXCLUSIVEADDRUSE,
15826 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
15830 if (setsockopt(so.
sock,
15840 "cannot set socket option SO_REUSEADDR (entry %i)",
15845#if defined(USE_X_DOM_SOCKET)
15846 if (ip_version == 99) {
15851 if (ip_version > 4) {
15853#if defined(USE_IPV6)
15854 if (ip_version > 6) {
15855 if (so.
lsa.
sa.sa_family == AF_INET6
15856 && setsockopt(so.
sock,
15865 "cannot set socket option "
15866 "IPV6_V6ONLY=off (entry %i)",
15870 if (so.
lsa.
sa.sa_family == AF_INET6
15871 && setsockopt(so.
sock,
15880 "cannot set socket option "
15881 "IPV6_V6ONLY=on (entry %i)",
15893 if (so.
lsa.
sa.sa_family == AF_INET) {
15895 len =
sizeof(so.
lsa.
sin);
15896 if (bind(so.
sock, &so.
lsa.
sa, len) != 0) {
15898 "cannot bind to %.*s: %d (%s)",
15908#if defined(USE_IPV6)
15909 else if (so.
lsa.
sa.sa_family == AF_INET6) {
15911 len =
sizeof(so.
lsa.sin6);
15912 if (bind(so.
sock, &so.
lsa.
sa, len) != 0) {
15914 "cannot bind to IPv6 %.*s: %d (%s)",
15925#if defined(USE_X_DOM_SOCKET)
15926 else if (so.
lsa.
sa.sa_family == AF_UNIX) {
15928 len =
sizeof(so.
lsa.sun);
15929 if (bind(so.
sock, &so.
lsa.
sa, len) != 0) {
15931 "cannot bind to unix socket %s: %d (%s)",
15932 so.
lsa.sun.sun_path,
15944 "cannot bind: address family not supported (entry %i)",
15952 opt_listen_backlog = strtol(opt_txt,
NULL, 10);
15953 if ((opt_listen_backlog > INT_MAX) || (opt_listen_backlog < 1)) {
15955 "%s value \"%s\" is invalid",
15963 if (listen(so.
sock, (
int)opt_listen_backlog) != 0) {
15966 "cannot listen to %.*s: %d (%s)",
15976 if ((getsockname(so.
sock, &(
usa.
sa), &len) != 0)
15977 || (
usa.
sa.sa_family != so.
lsa.
sa.sa_family)) {
15979 int err = (int)
ERRNO;
15981 "call to getsockname failed %.*s: %d (%s)",
15992#if defined(USE_IPV6)
15993 if (so.
lsa.
sa.sa_family == AF_INET6) {
15994 so.
lsa.sin6.sin6_port =
usa.sin6.sin6_port;
16001 if ((ptr = (
struct socket *)
16036 if (portsOk != portsTotal) {
16048 const char *header_value;
16053 return header_value;
16058#if defined(MG_EXTERNAL_FUNCTION_log_access)
16059#include "external_log_access.inl"
16060#elif !defined(NO_FILESYSTEMS)
16068#if defined(REENTRANT_TIME)
16070 struct tm *tm = &_tm;
16075 const char *referer;
16076 const char *user_agent;
16078 char log_buf[4096];
16080 if (!conn || !conn->
dom_ctx) {
16087#if defined(USE_LUA)
16088 if (conn->
phys_ctx->lua_bg_log_available) {
16092 pthread_mutex_lock(&ctx->lua_bg_mutex);
16095 prepare_lua_request_info_inner(conn, lstate);
16096 push_lua_response_log_data(conn, lstate);
16104 pthread_mutex_unlock(&ctx->lua_bg_mutex);
16111 if ((len == 0) || (*txt == 0)) {
16113 pthread_mutex_unlock(&ctx->lua_bg_mutex);
16117 if (len >=
sizeof(log_buf)) {
16118 len =
sizeof(log_buf) - 1;
16120 memcpy(log_buf, txt, len);
16124 lua_cry(conn, ret, lstate,
"lua_background_script",
"log");
16126 pthread_mutex_unlock(&ctx->lua_bg_mutex);
16151#if defined(REENTRANT_TIME)
16157 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z", tm);
16159 mg_strlcpy(date,
"01/Jan/1970:00:00:00 +0000",
sizeof(date));
16166 user_agent =
header_val(conn,
"User-Agent");
16172 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT
16203 if (fprintf(fi.
access.
fp,
"%s\n", log_buf) < 1) {
16215 "Error writing log file %s",
16221#error "Either enable filesystems or provide a custom log_access implementation"
16231 int allowed, flag, matched;
16238 allowed = (list ==
NULL) ?
'+' :
'-';
16243 if ((
vec.
len > 0) && ((flag ==
'+') || (flag ==
'-'))) {
16250 "%s: subnet must be [+|-]IP-addr[/x]",
16259 return allowed ==
'+';
16265#if !defined(_WIN32) && !defined(__ZEPHYR__)
16273 const uid_t curr_uid = getuid();
16276 const struct passwd *to_pw =
NULL;
16278 if ((run_as_user !=
NULL) && (to_pw = getpwnam(run_as_user)) ==
NULL) {
16282 "%s: unknown user [%s]",
16285 }
else if ((run_as_user ==
NULL) || (curr_uid == to_pw->pw_uid)) {
16292 if (setgid(to_pw->pw_gid) == -1) {
16294 "%s: setgid(%s): %s",
16298 }
else if (setgroups(0,
NULL) == -1) {
16300 "%s: setgroups(): %s",
16303 }
else if (setuid(to_pw->pw_uid) == -1) {
16305 "%s: setuid(%s): %s",
16336#if defined(USE_MBEDTLS)
16347 dom_ctx = &(phys_ctx->
dd);
16357 fprintf(stderr,
"ssl_ctx malloc failed\n");
16367#elif !defined(NO_SSL)
16372 const char *chain);
16379 struct stat cert_buf;
16383 int should_verify_peer;
16391 if (chain ==
NULL) {
16399 if (stat(pem, &cert_buf) != -1) {
16400 t = (int64_t)cert_buf.st_mtime;
16407 should_verify_peer = 0;
16411 should_verify_peer = 1;
16415 should_verify_peer = 1;
16419 if (should_verify_peer) {
16429 "SSL_CTX_load_verify_locations error: %s "
16430 "ssl_verify_peer requires setting "
16431 "either ssl_ca_path or ssl_ca_file. Is any of them "
16449#if defined(OPENSSL_API_1_1)
16456 int (*func)(SSL *),
16461 unsigned timeout = 1024;
16484 OPENSSL_REMOVE_THREAD_STATE();
16487 SSL_set_app_data(conn->
ssl, (
char *)conn);
16489 ret = SSL_set_fd(conn->ssl, conn->client.sock);
16492 SSL_free(conn->ssl);
16494 OPENSSL_REMOVE_THREAD_STATE();
16498 if (client_options) {
16500 SSL_set_tlsext_host_name(conn->ssl, client_options->
host_name);
16510 timeout = (unsigned)to;
16517 for (i = 0; i <= timeout; i += 50) {
16520 ret = func(conn->ssl);
16522 err = SSL_get_error(conn->ssl, ret);
16523 if ((err == SSL_ERROR_WANT_CONNECT)
16524 || (err == SSL_ERROR_WANT_ACCEPT)
16525 || (err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE)
16526 || (err == SSL_ERROR_WANT_X509_LOOKUP)) {
16531 if (err == SSL_ERROR_WANT_X509_LOOKUP) {
16540 pfd.fd = conn->client.sock;
16541 pfd.events = ((err == SSL_ERROR_WANT_CONNECT)
16542 || (err == SSL_ERROR_WANT_WRITE))
16546 mg_poll(&pfd, 1, 50, &(conn->phys_ctx->stop_flag));
16554 }
else if (err == SSL_ERROR_SYSCALL) {
16573 SSL_free(conn->ssl);
16575 OPENSSL_REMOVE_THREAD_STATE();
16588 err = ERR_get_error();
16589 return ((err == 0) ?
"" : ERR_error_string(err,
NULL));
16597 const char hexdigit[] =
"0123456789abcdef";
16599 if ((memlen <= 0) || (buflen <= 0)) {
16602 if (buflen < (3 * memlen)) {
16606 for (i = 0; i < memlen; i++) {
16608 buf[3 * i - 1] =
' ';
16610 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
16611 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
16613 buf[3 * memlen - 1] = 0;
16623 X509 *cert = SSL_get_peer_certificate(conn->
ssl);
16625 char str_buf[1024];
16626 unsigned char buf[256];
16627 char *str_serial =
NULL;
16630 unsigned char *tmp_buf;
16631 unsigned char *tmp_p;
16634 const EVP_MD *digest = EVP_get_digestbyname(
"sha1");
16637 X509_NAME *subj = X509_get_subject_name(cert);
16638 X509_NAME *iss = X509_get_issuer_name(cert);
16641 ASN1_INTEGER *serial = X509_get_serialNumber(cert);
16644 BIGNUM *serial_bn = ASN1_INTEGER_to_BN(serial,
NULL);
16646 str_serial = BN_bn2hex(serial_bn);
16647 BN_free(serial_bn);
16653 (void)X509_NAME_oneline(subj, str_buf, (
int)
sizeof(str_buf));
16655 (void)X509_NAME_oneline(iss, str_buf, (
int)
sizeof(str_buf));
16663 ilen = i2d_X509(cert,
NULL);
16664 tmp_buf = (ilen > 0)
16670 (void)i2d_X509(cert, &tmp_p);
16672 tmp_buf, (
unsigned)ilen, buf, &ulen, digest,
NULL)) {
16678 if (!
hexdump2string(buf, (
int)ulen, str_buf, (
int)
sizeof(str_buf))) {
16687 OPENSSL_free(str_serial);
16694#if defined(OPENSSL_API_1_1)
16704 (void)pthread_mutex_lock(&
ssl_mutexes[mutex_num]);
16706 (void)pthread_mutex_unlock(&
ssl_mutexes[mutex_num]);
16712#if !defined(NO_SSL_DL)
16717 const char *dll_name,
16718 struct ssl_func *sw,
16719 int *feature_missing)
16726 struct ssl_func *fp;
16730 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) ==
NULL) {
16735 "%s: cannot load %s",
16742 for (fp = sw; fp->name !=
NULL; fp++) {
16745 u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
16750 u.p = dlsym(dll_handle, fp->name);
16756 if (u.fp ==
NULL) {
16758 if (feature_missing) {
16759 feature_missing[fp->required]++;
16761 if (fp->required == TLS_Mandatory) {
16770 "%s: %s: cannot find %s",
16778 size_t cur_len = strlen(ebuf);
16779 if (!truncated && ((ebuf_len - cur_len) > 3)) {
16783 ebuf_len - cur_len - 3,
16788 strcat(ebuf,
"...");
16797 (void)dlclose(dll_handle);
16811#if defined(SSL_ALREADY_INITIALIZED)
16823#if !defined(OPENSSL_API_1_1) && !defined(OPENSSL_API_3_0)
16828 if (ebuf_len > 0) {
16832#if !defined(NO_SSL_DL)
16834 memset(tls_feature_missing, 0,
sizeof(tls_feature_missing));
16836 ebuf, ebuf_len,
CRYPTO_LIB, crypto_sw, tls_feature_missing);
16842 "%s: error loading library %s",
16855#if !defined(OPENSSL_API_1_1) && !defined(OPENSSL_API_3_0)
16859 num_locks = CRYPTO_num_locks();
16860 if (num_locks < 0) {
16863 size =
sizeof(pthread_mutex_t) * ((
size_t)(num_locks));
16866 if (num_locks == 0) {
16879 "%s: cannot allocate mutexes: %s",
16887 for (i = 0; i < num_locks; i++) {
16893 "%s: error initializing mutex %i of %i",
16908#if !defined(NO_SSL_DL)
16913#if !defined(OPENSSL_API_1_1)
16922#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
16923 && !defined(NO_SSL_DL)
16925 OPENSSL_init_ssl(0,
NULL);
16926 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
16927 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS,
16931 SSL_library_init();
16932 SSL_load_error_strings();
16945 if (SSL_CTX_use_certificate_file(dom_ctx->
ssl_ctx, pem, 1) == 0) {
16947 "%s: cannot open certificate file %s: %s",
16955 if (SSL_CTX_use_PrivateKey_file(dom_ctx->
ssl_ctx, pem, 1) == 0) {
16957 "%s: cannot open private key file %s: %s",
16964 if (SSL_CTX_check_private_key(dom_ctx->
ssl_ctx) == 0) {
16966 "%s: certificate and private key do not match: %s",
16981 if (SSL_CTX_use_certificate_chain_file(dom_ctx->
ssl_ctx, chain) == 0) {
16983 "%s: cannot use certificate chain file %s: %s",
16994#if defined(OPENSSL_API_1_1)
16995static unsigned long
16998 long unsigned ret = (
long unsigned)SSL_OP_ALL;
16999 if (version_id > 0)
17000 ret |= SSL_OP_NO_SSLv2;
17001 if (version_id > 1)
17002 ret |= SSL_OP_NO_SSLv3;
17003 if (version_id > 2)
17004 ret |= SSL_OP_NO_TLSv1;
17005 if (version_id > 3)
17006 ret |= SSL_OP_NO_TLSv1_1;
17007 if (version_id > 4)
17008 ret |= SSL_OP_NO_TLSv1_2;
17009#if defined(SSL_OP_NO_TLSv1_3)
17010 if (version_id > 5)
17011 ret |= SSL_OP_NO_TLSv1_3;
17019 unsigned long ret = (
unsigned long)SSL_OP_ALL;
17020 if (version_id > 0)
17021 ret |= SSL_OP_NO_SSLv2;
17022 if (version_id > 1)
17023 ret |= SSL_OP_NO_SSLv3;
17024 if (version_id > 2)
17025 ret |= SSL_OP_NO_TLSv1;
17026 if (version_id > 3)
17027 ret |= SSL_OP_NO_TLSv1_1;
17028 if (version_id > 4)
17029 ret |= SSL_OP_NO_TLSv1_2;
17030#if defined(SSL_OP_NO_TLSv1_3)
17031 if (version_id > 5)
17032 ret |= SSL_OP_NO_TLSv1_3;
17054 if (what & SSL_CB_HANDSHAKE_START) {
17055 SSL_get_app_data(ssl);
17057 if (what & SSL_CB_HANDSHAKE_DONE) {
17068#if defined(GCC_DIAGNOSTIC)
17069#pragma GCC diagnostic push
17070#pragma GCC diagnostic ignored "-Wcast-align"
17076#if defined(GCC_DIAGNOSTIC)
17077#pragma GCC diagnostic pop
17080 const char *servername = SSL_get_servername(
ssl, TLSEXT_NAMETYPE_host_name);
17087 return SSL_TLSEXT_ERR_NOACK;
17097 if ((servername ==
NULL) || (*servername == 0)) {
17098 DEBUG_TRACE(
"%s",
"SSL connection not supporting SNI");
17102 return SSL_TLSEXT_ERR_NOACK;
17105 DEBUG_TRACE(
"TLS connection to host %s", servername);
17129 return SSL_TLSEXT_ERR_OK;
17133#if defined(USE_ALPN)
17134static const char alpn_proto_list[] =
"\x02h2\x08http/1.1\x08http/1.0";
17135static const char *alpn_proto_order_http1[] = {alpn_proto_list + 3,
17136 alpn_proto_list + 3 + 8,
17138#if defined(USE_HTTP2)
17139static const char *alpn_proto_order_http2[] = {alpn_proto_list,
17140 alpn_proto_list + 3,
17141 alpn_proto_list + 3 + 8,
17146alpn_select_cb(SSL *
ssl,
17147 const unsigned char **out,
17148 unsigned char *outlen,
17149 const unsigned char *in,
17150 unsigned int inlen,
17154 unsigned int i, j, enable_http2 = 0;
17155 const char **alpn_proto_order = alpn_proto_order_http1;
17165 return SSL_TLSEXT_ERR_NOACK;
17168#if defined(USE_HTTP2)
17169 enable_http2 = (0 == strcmp(dom_ctx->
config[ENABLE_HTTP2],
"yes"));
17170 if (enable_http2) {
17171 alpn_proto_order = alpn_proto_order_http2;
17175 for (j = 0; alpn_proto_order[j] !=
NULL; j++) {
17177 const char *
alpn_proto = alpn_proto_order[j];
17179 for (i = 0; i < inlen; i++) {
17184 return SSL_TLSEXT_ERR_OK;
17190 return SSL_TLSEXT_ERR_NOACK;
17195next_protos_advertised_cb(SSL *ssl,
17196 const unsigned char **data,
17201 *data = (
const unsigned char *)alpn_proto_list;
17202 *len = (
unsigned int)strlen((
const char *)data);
17207 return SSL_TLSEXT_ERR_OK;
17214 unsigned int alpn_len = (
unsigned int)strlen((
char *)alpn_proto_list);
17215 int ret = SSL_CTX_set_alpn_protos(dom_ctx->
ssl_ctx,
17216 (
const unsigned char *)alpn_proto_list,
17220 "SSL_CTX_set_alpn_protos error: %s",
17224 SSL_CTX_set_alpn_select_cb(dom_ctx->
ssl_ctx,
17228 SSL_CTX_set_next_protos_advertised_cb(dom_ctx->
ssl_ctx,
17229 next_protos_advertised_cb,
17245 int should_verify_peer;
17246 int peer_certificate_optional;
17247 const char *ca_path;
17248 const char *ca_file;
17249 int use_default_verify_paths;
17251 struct timespec now_mt;
17252 md5_byte_t ssl_context_id[16];
17253 md5_state_t md5state;
17255 int ssl_cache_timeout;
17257#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
17258 && !defined(NO_SSL_DL)
17259 if ((dom_ctx->
ssl_ctx = SSL_CTX_new(TLS_server_method())) ==
NULL) {
17261 "SSL_CTX_new (server) error: %s",
17266 if ((dom_ctx->
ssl_ctx = SSL_CTX_new(SSLv23_server_method())) ==
NULL) {
17268 "SSL_CTX_new (server) error: %s",
17274#if defined(SSL_OP_NO_TLSv1_3)
17275 SSL_CTX_clear_options(dom_ctx->
ssl_ctx,
17276 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1
17277 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2
17278 | SSL_OP_NO_TLSv1_3);
17280 SSL_CTX_clear_options(dom_ctx->
ssl_ctx,
17281 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1
17282 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
17287 SSL_CTX_set_options(dom_ctx->
ssl_ctx, SSL_OP_SINGLE_DH_USE);
17288 SSL_CTX_set_options(dom_ctx->
ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
17289 SSL_CTX_set_options(dom_ctx->
ssl_ctx,
17290 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
17291 SSL_CTX_set_options(dom_ctx->
ssl_ctx, SSL_OP_NO_COMPRESSION);
17293#if defined(SSL_OP_NO_RENEGOTIATION)
17294 SSL_CTX_set_options(dom_ctx->
ssl_ctx, SSL_OP_NO_RENEGOTIATION);
17297#if !defined(NO_SSL_DL)
17298 SSL_CTX_set_ecdh_auto(dom_ctx->
ssl_ctx, 1);
17316 SSL_CTX_set_tlsext_servername_callback(dom_ctx->
ssl_ctx,
17328 if (callback_ret < 0) {
17330 "SSL callback returned error: %i",
17334 if (callback_ret > 0) {
17350 if (callback_ret < 0) {
17352 "Domain SSL callback returned error: %i",
17356 if (callback_ret > 0) {
17363 md5_init(&md5state);
17364 clock_gettime(CLOCK_MONOTONIC, &now_mt);
17365 md5_append(&md5state, (
const md5_byte_t *)&now_mt,
sizeof(now_mt));
17366 md5_append(&md5state,
17369 md5_append(&md5state,
17372 md5_append(&md5state, (
const md5_byte_t *)phys_ctx,
sizeof(*phys_ctx));
17373 md5_append(&md5state, (
const md5_byte_t *)dom_ctx,
sizeof(*dom_ctx));
17374 md5_finish(&md5state, ssl_context_id);
17376 SSL_CTX_set_session_id_context(dom_ctx->
ssl_ctx,
17377 (
unsigned char *)ssl_context_id,
17378 sizeof(ssl_context_id));
17388 should_verify_peer = 0;
17389 peer_certificate_optional = 0;
17393 should_verify_peer = 1;
17398 should_verify_peer = 1;
17399 peer_certificate_optional = 1;
17403 use_default_verify_paths =
17408 if (should_verify_peer) {
17411 if (SSL_CTX_load_verify_locations(dom_ctx->
ssl_ctx, ca_file, ca_path)
17414 "SSL_CTX_load_verify_locations error: %s "
17415 "ssl_verify_peer requires setting "
17416 "either ssl_ca_path or ssl_ca_file. "
17417 "Is any of them present in the "
17423 if (peer_certificate_optional) {
17424 SSL_CTX_set_verify(dom_ctx->
ssl_ctx, SSL_VERIFY_PEER,
NULL);
17426 SSL_CTX_set_verify(dom_ctx->
ssl_ctx,
17428 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
17432 if (use_default_verify_paths
17433 && (SSL_CTX_set_default_verify_paths(dom_ctx->
ssl_ctx) != 1)) {
17435 "SSL_CTX_set_default_verify_paths error: %s",
17442 SSL_CTX_set_verify_depth(dom_ctx->
ssl_ctx, verify_depth);
17447 if (SSL_CTX_set_cipher_list(dom_ctx->
ssl_ctx,
17451 "SSL_CTX_set_cipher_list error: %s",
17460 if (ssl_cache_timeout > 0) {
17461 SSL_CTX_set_session_cache_mode(dom_ctx->
ssl_ctx, SSL_SESS_CACHE_BOTH);
17464 SSL_CTX_set_timeout(dom_ctx->
ssl_ctx, (
long)ssl_cache_timeout);
17467#if defined(USE_ALPN)
17469#if !defined(NO_SSL_DL)
17470 if (!tls_feature_missing[TLS_ALPN])
17473 init_alpn(phys_ctx, dom_ctx);
17498 dom_ctx = &(phys_ctx->
dd);
17513 if (callback_ret < 0) {
17516 "external_ssl_ctx callback returned error: %i",
17519 }
else if (callback_ret > 0) {
17522 dom_ctx->
ssl_ctx = (SSL_CTX *)ssl_ctx;
17540 if (callback_ret < 0) {
17544 "external_ssl_ctx_domain callback returned error: %i",
17547 }
else if (callback_ret > 0) {
17549 dom_ctx->
ssl_ctx = (SSL_CTX *)ssl_ctx;
17568 "Initializing SSL failed: -%s is not set",
17575 if (chain ==
NULL) {
17579 if ((chain !=
NULL) && (*chain == 0)) {
17596#if defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)
17604 CONF_modules_unload(1);
17614 CRYPTO_set_locking_callback(
NULL);
17615 CRYPTO_set_id_callback(
NULL);
17617 CONF_modules_unload(1);
17618 ERR_free_strings();
17620 CRYPTO_cleanup_all_ex_data();
17621 OPENSSL_REMOVE_THREAD_STATE();
17623 for (i = 0; i < CRYPTO_num_locks(); i++) {
17634#if !defined(NO_FILESYSTEMS)
17649 "Cannot open %s: %s",
17665 memset(&
sa, 0,
sizeof(
sa));
17666#if defined(USE_IPV6)
17667 sa.sin6.sin6_family = AF_INET6;
17669 sa.sin.sin_family = AF_INET;
17711#if defined(USE_SERVER_STATS)
17712 conn->processing_time = 0;
17720 if ((so->
lsa.
sa.sa_family == AF_INET)
17721 || (so->
lsa.
sa.sa_family == AF_INET6)) {
17723 if (setsockopt(so->
sock,
17727 sizeof(nodelay_on))
17738#if !defined(__ZEPHYR__)
17746 struct linger linger;
17747 int error_code = 0;
17748 int linger_timeout = -2;
17749 socklen_t opt_len =
sizeof(error_code);
17780 if (linger_timeout >= 0) {
17783 linger.l_onoff = 1;
17785#if defined(_MSC_VER)
17786#pragma warning(push)
17787#pragma warning(disable : 4244)
17789#if defined(GCC_DIAGNOSTIC)
17790#pragma GCC diagnostic push
17791#pragma GCC diagnostic ignored "-Wconversion"
17797 linger.l_linger = (linger_timeout + 999) / 1000;
17799#if defined(GCC_DIAGNOSTIC)
17800#pragma GCC diagnostic pop
17802#if defined(_MSC_VER)
17803#pragma warning(pop)
17807 linger.l_onoff = 0;
17808 linger.l_linger = 0;
17811 if (linger_timeout < -1) {
17817 (
char *)&error_code,
17827 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
17831 }
else if (error_code == WSAECONNRESET) {
17833 }
else if (error_code == ECONNRESET) {
17848 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
17866#if defined(USE_SERVER_STATS)
17867 conn->conn_state = 6;
17870#if defined(USE_LUA) && defined(USE_WEBSOCKET)
17871 if (conn->lua_websocket_state) {
17872 lua_websocket_close(conn, conn->lua_websocket_state);
17873 conn->lua_websocket_state =
NULL;
17894#if defined(USE_SERVER_STATS)
17895 conn->conn_state = 7;
17898#if defined(USE_MBEDTLS)
17900 mbed_ssl_close(conn->
ssl);
17903#elif !defined(NO_SSL)
17907 SSL_shutdown(conn->
ssl);
17908 SSL_free(conn->
ssl);
17909 OPENSSL_REMOVE_THREAD_STATE();
17914#if defined(__ZEPHYR__)
17931#if defined(USE_SERVER_STATS)
17932 conn->conn_state = 8;
17944#if defined(USE_WEBSOCKET)
17946 if (conn->in_websocket_handling) {
17974#if !defined(NO_SSL) && !defined(USE_MBEDTLS)
17982#if defined(USE_WEBSOCKET)
17985 (void)pthread_mutex_destroy(&conn->
mutex);
17988 (void)pthread_mutex_destroy(&conn->
mutex);
17993 (void)pthread_mutex_destroy(&conn->
mutex);
18009 struct sockaddr *psa;
18012 unsigned max_req_size =
18016 size_t conn_size = ((
sizeof(
struct mg_connection) + 7) >> 3) << 3;
18017 size_t ctx_size = ((
sizeof(
struct mg_context) + 7) >> 3) << 3;
18018 size_t alloc_size = conn_size + ctx_size + max_req_size;
18026 error->code_sub = 0;
18027 if (
error->text_buffer_size > 0) {
18028 error->text[0] = 0;
18032 if (conn ==
NULL) {
18035 error->code_sub = (unsigned)alloc_size;
18039 error->text_buffer_size,
18046#if defined(GCC_DIAGNOSTIC)
18047#pragma GCC diagnostic push
18048#pragma GCC diagnostic ignored "-Wcast-align"
18054#if defined(GCC_DIAGNOSTIC)
18055#pragma GCC diagnostic pop
18058 conn->
buf = (((
char *)conn) + conn_size + ctx_size);
18059 conn->
buf_size = (int)max_req_size;
18064 client_options->
host,
18065 client_options->
port,
18076#if !defined(NO_SSL) && !defined(USE_MBEDTLS)
18077#if (defined(OPENSSL_API_1_1) || defined(OPENSSL_API_3_0)) \
18078 && !defined(NO_SSL_DL)
18088 error->text_buffer_size,
18089 "SSL_CTX_new error: %s",
18101 && (conn->
dom_ctx->
ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
18108 error->text_buffer_size,
18109 "SSL_CTX_new error: %s",
18121#if defined(USE_IPV6)
18122 len = (sa.
sa.sa_family == AF_INET) ?
sizeof(conn->
client.
rsa.
sin)
18124 psa = (sa.
sa.sa_family == AF_INET)
18126 : (
struct sockaddr *)&(conn->
client.
rsa.sin6);
18135 if (getsockname(sock, psa, &len) != 0) {
18137 "%s: getsockname() failed: %s",
18150 error->text_buffer_size,
18151 "Can not create mutex");
18153#if !defined(NO_SSL) && !defined(USE_MBEDTLS)
18161#if !defined(NO_SSL) && !defined(USE_MBEDTLS)
18180 error->text_buffer_size,
18181 "Can not use SSL client certificate");
18201 error->text_buffer_size,
18202 "SSL_CTX_load_verify_locations error: %s",
18215 if (!
sslize(conn, SSL_connect, client_options)) {
18221 error->text_buffer_size,
18222 "SSL connection error");
18238 char *error_buffer,
18239 size_t error_buffer_size)
18244 memset(&init, 0,
sizeof(init));
18246 error.text_buffer_size = error_buffer_size;
18247 error.text = error_buffer;
18256 char *error_buffer,
18257 size_t error_buffer_size)
18263 memset(&init, 0,
sizeof(init));
18266 error.text_buffer_size = error_buffer_size;
18267 error.text = error_buffer;
18269 memset(&opts, 0,
sizeof(opts));
18280#if defined(MG_EXPERIMENTAL_INTERFACES)
18282mg_connect_client2(
const char *host,
18283 const char *protocol,
18296 error->code_sub = 0;
18297 if (
error->text_buffer_size > 0) {
18302 if ((host ==
NULL) || (protocol ==
NULL)) {
18308 error->text_buffer_size,
18310 "Invalid parameters");
18322#if defined(USE_WEBSOCKET)
18336 error->text_buffer_size,
18337 "Protocol %s not supported",
18346#if defined(USE_WEBSOCKET)
18355 (path ? path :
""),
18357 experimental_websocket_client_data_wrapper,
18358 experimental_websocket_client_close_wrapper,
18359 (void *)init->callbacks);
18368 memset(&opts, 0,
sizeof(opts));
18377static const struct {
18382 {
"https://", 8, 443},
18384 {
"wss://", 6, 443},
18398 const char *hostend, *portbegin;
18400 unsigned long port;
18406 if ((uri[0] ==
'*') && (uri[1] ==
'\0')) {
18417 for (i = 0; uri[i] != 0; i++) {
18426 if (uri[0] ==
'/') {
18450 port = strtoul(portbegin + 1, &portend, 10);
18451 if ((portend != hostend) || (port <= 0) || !
is_valid_port(port)) {
18467 const char *server_domain;
18468 size_t server_domain_len;
18469 size_t request_domain_len = 0;
18470 unsigned long port = 0;
18471 int i, auth_domain_check_enabled;
18472 const char *hostbegin =
NULL;
18473 const char *hostend =
NULL;
18474 const char *portbegin;
18477 auth_domain_check_enabled =
18489 hostend = strchr(hostbegin,
'/');
18493 portbegin = strchr(hostbegin,
':');
18494 if ((!portbegin) || (portbegin > hostend)) {
18496 request_domain_len = (size_t)(hostend - hostbegin);
18498 port = strtoul(portbegin + 1, &portend, 10);
18499 if ((portend != hostend) || (port <= 0)
18503 request_domain_len = (size_t)(portbegin - hostbegin);
18530 if (auth_domain_check_enabled) {
18532 server_domain_len = strlen(server_domain);
18533 if ((server_domain_len == 0) || (hostbegin ==
NULL)) {
18536 if ((request_domain_len == server_domain_len)
18537 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
18540 if (request_domain_len < (server_domain_len + 2)) {
18547 if (hostbegin[request_domain_len - server_domain_len - 1] !=
'.') {
18554 != memcmp(server_domain,
18555 hostbegin + request_domain_len - server_domain_len,
18556 server_domain_len)) {
18571 if (ebuf_len > 0) {
18591 clock_gettime(CLOCK_MONOTONIC, &(conn->
req_time));
18602 "Invalid message size");
18613 "Message too large");
18625 "Malformed message");
18635 "No data received");
18676 "Bad request: Host mismatch");
18684 "Accept-Encoding"))
18686 && strstr(cl,
"gzip")) {
18692 "Transfer-Encoding"))
18712 char *endptr =
NULL;
18764 "Transfer-Encoding"))
18783 char *endptr =
NULL;
18829 char *save_timeout;
18832 if (ebuf_len > 0) {
18842 "Parameter error");
18852 if (timeout >= 0) {
18856 new_timeout =
NULL;
18869 return (ret == 0) ? -1 : +1;
18887 if (ebuf_len > 0) {
18896 if (conn !=
NULL) {
18904 "Error sending request");
18916 if ((ebuf[0] !=
'\0') && (conn !=
NULL)) {
18934#if defined(USE_WEBSOCKET)
18936static unsigned __stdcall websocket_client_thread(
void *data)
18939websocket_client_thread(
void *data)
18945 void *user_thread_ptr =
NULL;
18947#if !defined(_WIN32) && !defined(__ZEPHYR__)
18948 struct sigaction sa;
18951 memset(&sa, 0,
sizeof(sa));
18952 sa.sa_handler = SIG_IGN;
18953 sigaction(SIGPIPE, &sa,
NULL);
18969 DEBUG_TRACE(
"%s",
"Websocket client thread exited\n");
18999 char *error_buffer,
19000 size_t error_buffer_size,
19002 const char *origin,
19003 const char *extensions,
19010#if defined(USE_WEBSOCKET)
19012 static const char *magic =
"x3JJHMbDL1EzLkh9GBhXDw==";
19014 const char *host = client_options->
host;
19020 memset(&init, 0,
sizeof(init));
19022 error.text_buffer_size = error_buffer_size;
19023 error.text = error_buffer;
19025#if defined(__clang__)
19026#pragma clang diagnostic push
19027#pragma clang diagnostic ignored "-Wformat-nonliteral"
19034 if (conn ==
NULL) {
19036 if (!error_buffer[0]) {
19042 "Unexpected error");
19047 if (origin !=
NULL) {
19048 if (extensions !=
NULL) {
19050 "GET %s HTTP/1.1\r\n"
19052 "Upgrade: websocket\r\n"
19053 "Connection: Upgrade\r\n"
19054 "Sec-WebSocket-Key: %s\r\n"
19055 "Sec-WebSocket-Version: 13\r\n"
19056 "Sec-WebSocket-Extensions: %s\r\n"
19066 "GET %s HTTP/1.1\r\n"
19068 "Upgrade: websocket\r\n"
19069 "Connection: Upgrade\r\n"
19070 "Sec-WebSocket-Key: %s\r\n"
19071 "Sec-WebSocket-Version: 13\r\n"
19081 if (extensions !=
NULL) {
19083 "GET %s HTTP/1.1\r\n"
19085 "Upgrade: websocket\r\n"
19086 "Connection: Upgrade\r\n"
19087 "Sec-WebSocket-Key: %s\r\n"
19088 "Sec-WebSocket-Version: 13\r\n"
19089 "Sec-WebSocket-Extensions: %s\r\n"
19097 "GET %s HTTP/1.1\r\n"
19099 "Upgrade: websocket\r\n"
19100 "Connection: Upgrade\r\n"
19101 "Sec-WebSocket-Key: %s\r\n"
19102 "Sec-WebSocket-Version: 13\r\n"
19115 "Error sending request");
19121 if (!
get_response(conn, error_buffer, error_buffer_size, &i)) {
19128#if defined(__clang__)
19129#pragma clang diagnostic pop
19137 if (!*error_buffer) {
19143 "Unexpected server reply");
19146 DEBUG_TRACE(
"Websocket client connect error: %s\r\n", error_buffer);
19153 if (!thread_data) {
19190 "Websocket client connect thread could not be started\r\n");
19195 (void)client_options;
19197 (void)error_buffer;
19198 (void)error_buffer_size;
19215 char *error_buffer,
19216 size_t error_buffer_size,
19218 const char *origin,
19224 memset(&client_options, 0,
sizeof(client_options));
19244 char *error_buffer,
19245 size_t error_buffer_size,
19247 const char *origin,
19252 if (!client_options) {
19272 char *error_buffer,
19273 size_t error_buffer_size,
19275 const char *origin,
19276 const char *extensions,
19282 memset(&client_options, 0,
sizeof(client_options));
19302 char *error_buffer,
19303 size_t error_buffer_size,
19305 const char *origin,
19306 const char *extensions,
19311 if (!client_options) {
19332 int keep_alive_enabled =
19335 if (!keep_alive_enabled) {
19347#if defined(USE_SERVER_STATS)
19348 conn->conn_state = 2;
19354 void *conn_data =
NULL;
19371 int keep_alive, discard_len;
19373 const char *hostend;
19374 int reqerr, uri_type;
19376#if defined(USE_SERVER_STATS)
19378 mg_atomic_add(&(conn->
phys_ctx->total_connections), 1);
19379 mg_atomic_max(&(conn->
phys_ctx->max_active_connections), mcon);
19382 DEBUG_TRACE(
"Start processing connection from %s",
19388 DEBUG_TRACE(
"calling get_request (%i times for this connection)",
19391#if defined(USE_SERVER_STATS)
19392 conn->conn_state = 3;
19395 if (!
get_request(conn, ebuf,
sizeof(ebuf), &reqerr)) {
19411 "Bad HTTP version: [%s]",
19416 if (ebuf[0] ==
'\0') {
19418 switch (uri_type) {
19454 if (ebuf[0] !=
'\0') {
19474 (ebuf[0] ? ebuf :
"none"));
19476 if (ebuf[0] ==
'\0') {
19491 free_buffered_response_header_list(conn);
19527 conn->
buf + discard_len,
19536 DEBUG_TRACE(
"internal error: data_len = %li, buf_size = %li",
19542 }
while (keep_alive);
19544 DEBUG_TRACE(
"Done processing connection from %s (%f sec)",
19550#if defined(USE_SERVER_STATS)
19557#if defined(ALTERNATIVE_QUEUE)
19567 if (ctx->client_socks[i].in_use == 2) {
19569 if ((ctx->client_socks[i].in_use == 2) && !ctx->
stop_flag) {
19570 ctx->client_socks[i] = *sp;
19571 ctx->client_socks[i].in_use = 1;
19574 (void)event_signal(ctx->client_wait_events[i]);
19594 ctx->client_socks[thread_index].in_use = 2;
19597 event_wait(ctx->client_wait_events[thread_index]);
19600 *sp = ctx->client_socks[thread_index];
19626 (void)thread_index;
19652 (void)pthread_cond_signal(&ctx->
sq_empty);
19671 && (queue_filled >= ctx->
sq_size)) {
19673#if defined(USE_SERVER_STATS)
19674 if (queue_filled > ctx->sq_max_fill) {
19675 ctx->sq_max_fill = queue_filled;
19683 if (queue_filled < ctx->sq_size) {
19691#if defined(USE_SERVER_STATS)
19692 if (queue_filled > ctx->sq_max_fill) {
19693 ctx->sq_max_fill = queue_filled;
19697 (void)pthread_cond_signal(&ctx->
sq_full);
19719 pthread_setspecific(
sTlsKey, &tls);
19733 if ((thread_index < 0)
19736 "Internal error: Invalid worker index %i",
19748 "Out of memory: Cannot allocate buffer for worker %i",
19768#if defined(USE_SERVER_STATS)
19769 conn->conn_state = 1;
19780#if defined(USE_SERVER_STATS)
19781 conn->conn_close_time = 0;
19807#if defined(USE_MBEDTLS)
19809 if (mbed_ssl_accept(&(conn->
ssl),
19825#elif !defined(NO_SSL)
19837#if defined(USE_HTTP2)
19839 && (!memcmp(tls.
alpn_proto,
"\x02h2", 3))) {
19847 process_new_http2_connection(conn);
19892#if defined(USE_SERVER_STATS)
19893 conn->conn_close_time = time(
NULL);
19905 CloseHandle(tls.pthread_cond_helper_mutex);
19907 pthread_mutex_destroy(&conn->
mutex);
19920#if defined(USE_SERVER_STATS)
19921 conn->conn_state = 9;
19930static unsigned __stdcall
worker_thread(
void *thread_func_param)
19939#if !defined(__ZEPHYR__)
19940 struct sigaction sa;
19943 memset(&sa, 0,
sizeof(sa));
19944 sa.sa_handler = SIG_IGN;
19945 sigaction(SIGPIPE, &sa,
NULL);
19961 socklen_t len =
sizeof(so.
rsa);
19962#if !defined(__ZEPHYR__)
19965 memset(&so, 0,
sizeof(so));
19972 "%s: %s is not allowed to connect",
19982 if (getsockname(so.
sock, &so.
lsa.
sa, &len) != 0) {
19984 "%s: getsockname() failed: %s",
19989#if !defined(__ZEPHYR__)
19990 if ((so.
lsa.
sa.sa_family == AF_INET)
19991 || (so.
lsa.
sa.sa_family == AF_INET6)) {
19999 if (setsockopt(so.
sock,
20007 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
20026 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
20049 unsigned int workerthreadcount;
20059 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
20060#elif defined(USE_MASTER_THREAD_PRIORITY)
20061 int min_prio = sched_get_priority_min(SCHED_RR);
20062 int max_prio = sched_get_priority_max(SCHED_RR);
20063 if ((min_prio >= 0) && (max_prio >= 0)
20064 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
20065 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
20066 struct sched_param sched_param = {0};
20067 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
20068 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
20077 pthread_setspecific(
sTlsKey, &tls);
20087#if defined(USE_LUA)
20088 if (ctx->lua_background_state) {
20090 pthread_mutex_lock(&ctx->lua_bg_mutex);
20101 "lua_background_script",
20111 ctx->lua_bg_log_available = 1;
20115 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20127 pfd[i].events = POLLIN;
20142 && (pfd[i].revents & POLLIN)) {
20156#if defined(ALTERNATIVE_QUEUE)
20158 event_signal(ctx->client_wait_events[i]);
20162 pthread_cond_broadcast(&ctx->
sq_full);
20168 for (i = 0; i < workerthreadcount; i++) {
20174#if defined(USE_LUA)
20176 if (ctx->lua_background_state) {
20178 ctx->lua_bg_log_available = 0;
20181 pthread_mutex_lock(&ctx->lua_bg_mutex);
20190 "lua_background_script",
20194 DEBUG_TRACE(
"Close Lua background state %p", lstate);
20197 ctx->lua_background_state = 0;
20198 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20211 CloseHandle(tls.pthread_cond_helper_mutex);
20224static unsigned __stdcall
master_thread(
void *thread_func_param)
20233#if !defined(__ZEPHYR__)
20234 struct sigaction sa;
20237 memset(&sa, 0,
sizeof(sa));
20238 sa.sa_handler = SIG_IGN;
20239 sigaction(SIGPIPE, &sa,
NULL);
20268#if defined(ALTERNATIVE_QUEUE)
20270 if (ctx->client_wait_events !=
NULL) {
20271 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
20272 event_destroy(ctx->client_wait_events[i]);
20274 mg_free(ctx->client_wait_events);
20277 (void)pthread_cond_destroy(&ctx->
sq_empty);
20278 (void)pthread_cond_destroy(&ctx->
sq_full);
20285#if defined(USE_LUA)
20286 (void)pthread_mutex_destroy(&ctx->lua_bg_mutex);
20292#if defined(_MSC_VER)
20293#pragma warning(suppress : 6001)
20307#if defined(USE_MBEDTLS)
20314#elif !defined(NO_SSL)
20317 void *ssl_ctx = (
void *)ctx->
dd.
ssl_ctx;
20323 if (callback_ret == 0) {
20366#if defined(USE_TIMERS)
20379#if defined(USE_LUA)
20393 DWORD dwVersion = 0;
20394 DWORD dwMajorVersion = 0;
20395 DWORD dwMinorVersion = 0;
20397 BOOL wowRet, isWoW =
FALSE;
20399#if defined(_MSC_VER)
20400#pragma warning(push)
20402#pragma warning(disable : 4996)
20404 dwVersion = GetVersion();
20405#if defined(_MSC_VER)
20406#pragma warning(pop)
20409 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
20410 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
20411 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
20414 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
20418 (
unsigned)dwMajorVersion,
20419 (
unsigned)dwMinorVersion,
20420 (wowRet ? (isWoW ?
" (WoW64)" :
"") :
" (?)"));
20424#elif defined(__ZEPHYR__)
20427 struct utsname
name;
20441 const char **run_options = options;
20445 while (*run_options) {
20446 if (!strcmp(*run_options, optname)) {
20447 ports_option = run_options[1];
20467 const char *
name, *
value, *default_value;
20468 int idx, ok, workerthreadcount;
20471 void (*exit_callback)(
const struct mg_context *ctx) = 0;
20472 const char **options =
20479 error->code_sub = 0;
20480 if (
error->text_buffer_size > 0) {
20497 error->text_buffer_size,
20499 "Library uninitialized");
20509 error->code_sub = (unsigned)
sizeof(*ctx);
20513 error->text_buffer_size,
20522 (uint64_t)
get_random() ^ (uint64_t)(ptrdiff_t)(options);
20531 tls.pthread_cond_helper_mutex =
NULL;
20533 pthread_setspecific(
sTlsKey, &tls);
20536#if !defined(ALTERNATIVE_QUEUE)
20538 ok &= (0 == pthread_cond_init(&ctx->
sq_full,
NULL));
20542#if defined(USE_LUA)
20546 unsigned error_id = (unsigned)
ERRNO;
20547 const char *err_msg =
20548 "Cannot initialize thread synchronization objects";
20555 error->code_sub = error_id;
20559 error->text_buffer_size,
20582#if defined(USE_LUA)
20587 while (options && (
name = *options++) !=
NULL) {
20593 error->code_sub = (unsigned)-1;
20597 error->text_buffer_size,
20598 "Invalid configuration option: %s",
20606 }
else if ((
value = *options++) ==
NULL) {
20610 error->code_sub = (unsigned)idx;
20614 error->text_buffer_size,
20615 "Invalid configuration option value: %s",
20653 error->text_buffer_size,
20654 "Invalid configuration option value: %s",
20665#if !defined(ALTERNATIVE_QUEUE)
20677 error->text_buffer_size,
20678 "Invalid configuration option value: %s",
20690 "Out of memory: Cannot allocate %s",
20694 error->code_sub = (unsigned)itmp * (
unsigned)
sizeof(
struct socket);
20698 error->text_buffer_size,
20699 "Out of memory: Cannot allocate %s",
20714 if (workerthreadcount <= 0) {
20725 error->text_buffer_size,
20726 "Invalid configuration option value: %s",
20736#if defined(NO_FILES)
20745 error->text_buffer_size,
20746 "Invalid configuration option value: %s",
20758#if defined(USE_LUA)
20760 ctx->lua_bg_log_available = 0;
20763 struct vec opt_vec;
20765 const char *sparams;
20767 memset(ebuf, 0,
sizeof(ebuf));
20768 pthread_mutex_lock(&ctx->lua_bg_mutex);
20771 lua_State *state = mg_lua_context_script_prepare(
20772 ctx->
dd.
config[LUA_BACKGROUND_SCRIPT], ctx, ebuf,
sizeof(ebuf));
20775 "lua_background_script load error: %s",
20782 error->text_buffer_size,
20783 "Error in script %s: %s",
20788 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20796 sparams = ctx->
dd.
config[LUA_BACKGROUND_SCRIPT_PARAMS];
20797 if (sparams && sparams[0]) {
20802 while ((sparams =
next_option(sparams, &opt_vec, &eq_vec))
20805 state, opt_vec.
ptr, opt_vec.
len, eq_vec.
ptr, eq_vec.
len);
20814 state = mg_lua_context_script_run(state,
20815 ctx->
dd.
config[LUA_BACKGROUND_SCRIPT],
20821 "lua_background_script start error: %s",
20828 error->text_buffer_size,
20829 "Error in script %s: %s",
20833 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20841 ctx->lua_background_state = (
void *)state;
20842 pthread_mutex_unlock(&ctx->lua_bg_mutex);
20845 ctx->lua_background_state = 0;
20850#if !defined(NO_FILESYSTEMS)
20852 const char *err_msg =
"Invalid global password file";
20861 error->text_buffer_size,
20871#if defined(USE_MBEDTLS)
20872 if (!mg_sslctx_init(ctx,
NULL)) {
20873 const char *err_msg =
"Error initializing SSL context";
20882 error->text_buffer_size,
20892#elif !defined(NO_SSL)
20894 const char *err_msg =
"Error initializing SSL context";
20903 error->text_buffer_size,
20915 const char *err_msg =
"Failed to setup server ports";
20924 error->text_buffer_size,
20934#if !defined(_WIN32) && !defined(__ZEPHYR__)
20936 const char *err_msg =
"Failed to run as configured user";
20945 error->text_buffer_size,
20957 const char *err_msg =
"Failed to setup access control list";
20966 error->text_buffer_size,
20982 const char *err_msg =
"Not enough memory for worker thread ID array";
20992 error->text_buffer_size,
21006 const char *err_msg =
21007 "Not enough memory for worker thread connection array";
21017 error->text_buffer_size,
21027#if defined(ALTERNATIVE_QUEUE)
21028 ctx->client_wait_events =
21030 sizeof(ctx->client_wait_events[0]),
21032 if (ctx->client_wait_events ==
NULL) {
21033 const char *err_msg =
"Not enough memory for worker event array";
21040 * (
unsigned)
sizeof(ctx->client_wait_events[0]);
21044 error->text_buffer_size,
21054 ctx->client_socks =
21056 sizeof(ctx->client_socks[0]),
21058 if (ctx->client_socks ==
NULL) {
21059 const char *err_msg =
"Not enough memory for worker socket array";
21061 mg_free(ctx->client_wait_events);
21067 * (
unsigned)
sizeof(ctx->client_socks[0]);
21071 error->text_buffer_size,
21081 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
21082 ctx->client_wait_events[i] = event_create();
21083 if (ctx->client_wait_events[i] == 0) {
21084 const char *err_msg =
"Error creating worker event %i";
21088 event_destroy(ctx->client_wait_events[i]);
21091 mg_free(ctx->client_wait_events);
21100 error->text_buffer_size,
21112#if defined(USE_TIMERS)
21113 if (timers_init(ctx) != 0) {
21114 const char *err_msg =
"Error creating timers";
21123 error->text_buffer_size,
21153 long error_no = (long)
ERRNO;
21160 "Cannot start worker thread %i: error %ld",
21173 "Cannot create threads: error %ld",
21178 error->code_sub = (unsigned)error_no;
21183 error->text_buffer_size,
21184 "Cannot create first worker thread: error %ld",
21207 const char **options)
21221 const char **options,
21226 const char *default_value;
21233 error->code_sub = 0;
21234 if (
error->text_buffer_size > 0) {
21239 if ((ctx ==
NULL) || (options ==
NULL)) {
21245 error->text_buffer_size,
21247 "Invalid parameters");
21258 error->text_buffer_size,
21260 "Server already stopped");
21276 error->text_buffer_size,
21284 while (options && (
name = *options++) !=
NULL) {
21290 error->code_sub = (unsigned)-1;
21294 error->text_buffer_size,
21295 "Invalid option: %s",
21300 }
else if ((
value = *options++) ==
NULL) {
21304 error->code_sub = (unsigned)idx;
21308 error->text_buffer_size,
21309 "Invalid option value: %s",
21334 error->text_buffer_size,
21335 "Mandatory option %s missing",
21345 default_value = ctx->
dd.
config[i];
21356#if defined(USE_LUA) && defined(USE_WEBSOCKET)
21357 new_dom->shared_lua_websockets =
NULL;
21360#if !defined(NO_SSL) && !defined(USE_MBEDTLS)
21368 error->text_buffer_size,
21370 "Initializing SSL context failed");
21387 "domain %s already in use",
21394 error->text_buffer_size,
21395 "Domain %s specified by %s is already in use",
21408 dom->
next = new_dom;
21432 static const unsigned feature_set = 0
21436#if !defined(NO_FILES)
21439#if !defined(NO_SSL) || defined(USE_MBEDTLS)
21442#if !defined(NO_CGI)
21445#if defined(USE_IPV6)
21448#if defined(USE_WEBSOCKET)
21451#if defined(USE_LUA)
21454#if defined(USE_DUKTAPE)
21457#if !defined(NO_CACHING)
21460#if defined(USE_SERVER_STATS)
21463#if defined(USE_ZLIB)
21466#if defined(USE_HTTP2)
21469#if defined(USE_X_DOM_SOCKET)
21475#if defined(MG_LEGACY_INTERFACE)
21478#if defined(MG_EXPERIMENTAL_INTERFACES)
21481#if !defined(NO_RESPONSE_BUFFERING)
21484#if defined(MEMORY_DEBUGGING)
21488 return (feature & feature_set);
21495 size_t len = strlen(src);
21498 if ((
size_t)(end - *dst) > len) {
21514 char *end, *append_eoobj =
NULL,
block[256];
21515 size_t system_info_length = 0;
21518 static const char eol[] =
"\r\n", eoobj[] =
"\r\n}\r\n";
21520 static const char eol[] =
"\n", eoobj[] =
"\n}\n";
21523 if ((buffer ==
NULL) || (buflen < 1)) {
21528 end = buffer + buflen;
21530 if (buflen > (
int)(
sizeof(eoobj) - 1)) {
21532 append_eoobj = buffer;
21534 end -=
sizeof(eoobj) - 1;
21547 "%s\"version\" : \"%s\"",
21556 DWORD dwVersion = 0;
21557 DWORD dwMajorVersion = 0;
21558 DWORD dwMinorVersion = 0;
21561 GetSystemInfo(&si);
21563#if defined(_MSC_VER)
21564#pragma warning(push)
21566#pragma warning(disable : 4996)
21568 dwVersion = GetVersion();
21569#if defined(_MSC_VER)
21570#pragma warning(pop)
21573 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
21574 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
21580 ",%s\"os\" : \"Windows %u.%u\"",
21582 (
unsigned)dwMajorVersion,
21583 (
unsigned)dwMinorVersion);
21590 ",%s\"cpu\" : \"type %u, cores %u, mask %x\"",
21592 (
unsigned)si.wProcessorArchitecture,
21593 (
unsigned)si.dwNumberOfProcessors,
21594 (
unsigned)si.dwActiveProcessorMask);
21596#elif defined(__ZEPHYR__)
21601 ",%s\"os\" : \"%s %s\"",
21607 struct utsname
name;
21615 ",%s\"os\" : \"%s %s (%s) - %s\"",
21631 ",%s\"features\" : %lu"
21632 ",%s\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\"",
21648#if defined(USE_LUA)
21653 ",%s\"lua_version\" : \"%u (%s)\"",
21659#if defined(USE_DUKTAPE)
21664 ",%s\"javascript\" : \"Duktape %u.%u.%u\"",
21675#if defined(BUILD_DATE)
21676 const char *bd = BUILD_DATE;
21678#if defined(GCC_DIAGNOSTIC)
21679#if GCC_VERSION >= 40900
21680#pragma GCC diagnostic push
21684#pragma GCC diagnostic ignored "-Wdate-time"
21687 const char *bd = __DATE__;
21688#if defined(GCC_DIAGNOSTIC)
21689#if GCC_VERSION >= 40900
21690#pragma GCC diagnostic pop
21704#if defined(_MSC_VER)
21709 ",%s\"compiler\" : \"MSC: %u (%u)\"",
21711 (
unsigned)_MSC_VER,
21712 (
unsigned)_MSC_FULL_VER);
21714#elif defined(__MINGW64__)
21719 ",%s\"compiler\" : \"MinGW64: %u.%u\"",
21721 (
unsigned)__MINGW64_VERSION_MAJOR,
21722 (
unsigned)__MINGW64_VERSION_MINOR);
21728 ",%s\"compiler\" : \"MinGW32: %u.%u\"",
21730 (
unsigned)__MINGW32_MAJOR_VERSION,
21731 (
unsigned)__MINGW32_MINOR_VERSION);
21733#elif defined(__MINGW32__)
21738 ",%s\"compiler\" : \"MinGW32: %u.%u\"",
21740 (
unsigned)__MINGW32_MAJOR_VERSION,
21741 (
unsigned)__MINGW32_MINOR_VERSION);
21743#elif defined(__clang__)
21748 ",%s\"compiler\" : \"clang: %u.%u.%u (%s)\"",
21752 __clang_patchlevel__,
21753 __clang_version__);
21755#elif defined(__GNUC__)
21760 ",%s\"compiler\" : \"gcc: %u.%u.%u\"",
21762 (
unsigned)__GNUC__,
21763 (
unsigned)__GNUC_MINOR__,
21764 (
unsigned)__GNUC_PATCHLEVEL__);
21766#elif defined(__INTEL_COMPILER)
21771 ",%s\"compiler\" : \"Intel C/C++: %u\"",
21773 (
unsigned)__INTEL_COMPILER);
21775#elif defined(__BORLANDC__)
21780 ",%s\"compiler\" : \"Borland C: 0x%x\"",
21782 (
unsigned)__BORLANDC__);
21784#elif defined(__SUNPRO_C)
21789 ",%s\"compiler\" : \"Solaris: 0x%x\"",
21791 (
unsigned)__SUNPRO_C);
21798 ",%s\"compiler\" : \"other\"",
21811 ",%s\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, "
21813 "ptr:%u, size:%u, time:%u\"",
21815 (
unsigned)
sizeof(
short),
21816 (
unsigned)
sizeof(
int),
21817 (
unsigned)
sizeof(
long),
21818 (
unsigned)
sizeof(
long long),
21819 (
unsigned)
sizeof(
float),
21820 (
unsigned)
sizeof(
double),
21821 (
unsigned)
sizeof(
long double),
21822 (
unsigned)
sizeof(
char),
21823 (
unsigned)
sizeof(
wchar_t),
21824 (
unsigned)
sizeof(
void *),
21825 (
unsigned)
sizeof(
size_t),
21826 (
unsigned)
sizeof(time_t));
21831 if (append_eoobj) {
21832 strcat(append_eoobj, eoobj);
21834 system_info_length +=
sizeof(eoobj) - 1;
21836 return (
int)system_info_length;
21845#if defined(USE_SERVER_STATS)
21846 char *end, *append_eoobj =
NULL,
block[256];
21847 size_t context_info_length = 0;
21850 static const char eol[] =
"\r\n", eoobj[] =
"\r\n}\r\n";
21852 static const char eol[] =
"\n", eoobj[] =
"\n}\n";
21854 struct mg_memory_stat *ms = get_memory_stat((
struct mg_context *)ctx);
21856 if ((buffer ==
NULL) || (buflen < 1)) {
21861 end = buffer + buflen;
21863 if (buflen > (
int)(
sizeof(eoobj) - 1)) {
21865 append_eoobj = buffer;
21866 end -=
sizeof(eoobj) - 1;
21873 int blockCount = (int)ms->blockCount;
21874 int64_t totalMemUsed = ms->totalMemUsed;
21875 int64_t maxMemUsed = ms->maxMemUsed;
21876 if (totalMemUsed > maxMemUsed) {
21877 maxMemUsed = totalMemUsed;
21884 "%s\"memory\" : {%s"
21885 "\"blocks\" : %i,%s"
21903 char start_time_str[64] = {0};
21904 char now_str[64] = {0};
21906 time_t now = time(
NULL);
21907 int64_t total_data_read, total_data_written;
21908 int active_connections = (int)ctx->active_connections;
21909 int max_active_connections = (int)ctx->max_active_connections;
21910 int total_connections = (int)ctx->total_connections;
21911 if (active_connections > max_active_connections) {
21912 max_active_connections = active_connections;
21914 if (active_connections > total_connections) {
21915 total_connections = active_connections;
21923 ",%s\"connections\" : {%s"
21924 "\"active\" : %i,%s"
21925 "\"maxActive\" : %i,%s"
21930 active_connections,
21932 max_active_connections,
21939#if !defined(ALTERNATIVE_QUEUE)
21944 ",%s\"queue\" : {%s"
21945 "\"length\" : %i,%s"
21946 "\"filled\" : %i,%s"
21947 "\"maxFilled\" : %i,%s"
21968 ",%s\"requests\" : {%s"
21969 "\"total\" : %lu%s"
21973 (
unsigned long)ctx->total_requests,
21979 mg_atomic_add64((
volatile int64_t *)&ctx->total_data_read, 0);
21980 total_data_written =
21981 mg_atomic_add64((
volatile int64_t *)&ctx->total_data_written, 0);
21986 ",%s\"data\" : {%s"
21994 total_data_written,
22000 sizeof(start_time_str) - 1,
22008 ",%s\"time\" : {%s"
22009 "\"uptime\" : %.0f,%s"
22010 "\"start\" : \"%s\",%s"
22011 "\"now\" : \"%s\"%s"
22015 difftime(now, start_time),
22025 if (append_eoobj) {
22026 strcat(append_eoobj, eoobj);
22028 context_info_length +=
sizeof(eoobj) - 1;
22030 return (
int)context_info_length;
22033 if ((buffer !=
NULL) && (buflen > 0)) {
22045 if (conn !=
NULL) {
22051#if defined(MG_EXPERIMENTAL_INTERFACES)
22055mg_get_connection_info(
const struct mg_context *ctx,
22062 char *end, *append_eoobj =
NULL,
block[256];
22063 size_t connection_info_length = 0;
22065 const char *state_str =
"unknown";
22068 static const char eol[] =
"\r\n", eoobj[] =
"\r\n}\r\n";
22070 static const char eol[] =
"\n", eoobj[] =
"\n}\n";
22073 if ((buffer ==
NULL) || (buflen < 1)) {
22078 end = buffer + buflen;
22080 if (buflen > (
int)(
sizeof(eoobj) - 1)) {
22082 append_eoobj = buffer;
22083 end -=
sizeof(eoobj) - 1;
22086 if ((ctx ==
NULL) || (idx < 0)) {
22101 connection_info_length +=
mg_str_append(&buffer, end,
"{");
22106#if defined(USE_SERVER_STATS)
22107 state = conn->conn_state;
22112 state_str =
"undefined";
22115 state_str =
"not used";
22118 state_str =
"init";
22121 state_str =
"ready";
22124 state_str =
"processing";
22127 state_str =
"processed";
22130 state_str =
"to close";
22133 state_str =
"closing";
22136 state_str =
"closed";
22139 state_str =
"done";
22145 if ((state >= 3) && (state < 9)) {
22150 "%s\"connection\" : {%s"
22152 "\"protocol\" : \"%s\",%s"
22153 "\"addr\" : \"%s\",%s"
22156 "\"handled_requests\" : %u%s"
22174 if ((state >= 4) && (state < 6)) {
22179 "%s%s\"request_info\" : {%s"
22180 "\"method\" : \"%s\",%s"
22181 "\"uri\" : \"%s\",%s"
22182 "\"query\" : %s%s%s%s"
22184 (connection_info_length > 1 ?
"," :
""),
22199 if ((state >= 2) && (state < 9)) {
22200 char start_time_str[64] = {0};
22201 char close_time_str[64] = {0};
22203 time_t close_time = 0;
22207 sizeof(start_time_str) - 1,
22209#if defined(USE_SERVER_STATS)
22210 close_time = conn->conn_close_time;
22212 if (close_time != 0) {
22213 time_diff = difftime(close_time, start_time);
22215 sizeof(close_time_str) - 1,
22218 time_t now = time(
NULL);
22219 time_diff = difftime(now, start_time);
22220 close_time_str[0] = 0;
22227 "%s%s\"time\" : {%s"
22228 "\"uptime\" : %.0f,%s"
22229 "\"start\" : \"%s\",%s"
22230 "\"closed\" : \"%s\"%s"
22232 (connection_info_length > 1 ?
"," :
""),
22250 "%s%s\"user\" : {%s"
22251 "\"name\" : \"%s\",%s"
22253 (connection_info_length > 1 ?
"," :
""),
22267 "%s%s\"data\" : {%s"
22271 (connection_info_length > 1 ?
"," :
""),
22274 conn->consumed_content,
22276 conn->num_bytes_sent,
22286 "%s%s\"state\" : \"%s\"",
22287 (connection_info_length > 1 ?
"," :
""),
22293 if (append_eoobj) {
22294 strcat(append_eoobj, eoobj);
22296 connection_info_length +=
sizeof(eoobj) - 1;
22298 return (
int)connection_info_length;
22309 int handler_info_len = 0;
22315 if (buflen > handler_info_len+ tmp_rh->
uri_len) {
22316 memcpy(buffer+handler_info_len, tmp_rh->
uri, tmp_rh->
uri_len);
22318 handler_info_len += tmp_rh->
uri_len;
22331 (void) tmp_rh->auth_handler;
22338 return handler_info_len;
22350 unsigned features_inited = features_to_init;
22366 int file_mutex_init = 1;
22369 int mutexattr_init = 1;
22374 if (key_create == 0) {
22378 if (file_mutex_init == 0) {
22381 failed = wsa = WSAStartup(MAKEWORD(2, 2), &data);
22385 if (mutexattr_init == 0) {
22387 PTHREAD_MUTEX_RECURSIVE);
22395 (void)WSACleanup();
22397 if (file_mutex_init == 0) {
22398 (void)pthread_mutex_destroy(&global_log_file_lock);
22401 if (mutexattr_init == 0) {
22405 if (key_create == 0) {
22406 (void)pthread_key_delete(
sTlsKey);
22439#if defined(USE_LUA)
22440 lua_init_optional_libraries();
22443#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
22444 || defined(OPENSSL_API_3_0)) \
22445 && !defined(NO_SSL)
22448 if (!mg_openssl_initialized) {
22451 mg_openssl_initialized = 1;
22454 DEBUG_TRACE(
"Initializing SSL failed: %s", ebuf);
22471 return features_inited;
22487#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1)) && !defined(NO_SSL)
22488 if (mg_openssl_initialized) {
22490 mg_openssl_initialized = 0;
22495 (void)WSACleanup();
22496 (void)pthread_mutex_destroy(&global_log_file_lock);
22501 (void)pthread_key_delete(
sTlsKey);
22503#if defined(USE_LUA)
22504 lua_exit_optional_libraries();
static void process_new_connection(struct mg_connection *conn)
CIVETWEB_API int mg_start_domain(struct mg_context *ctx, const char **options)
CIVETWEB_API void mg_lock_context(struct mg_context *ctx)
static int is_authorized_for_put(struct mg_connection *conn)
static int consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
static int parse_http_request(char *buf, int len, struct mg_request_info *ri)
static pthread_key_t sTlsKey
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
CIVETWEB_API int mg_start_domain2(struct mg_context *ctx, const char **options, struct mg_error_data *error)
static void open_auth_file(struct mg_connection *conn, const char *path, struct mg_file *filep)
char static_assert_replacement[1]
CIVETWEB_API const char * mg_version(void)
@ ENABLE_DIRECTORY_LISTING
@ ACCESS_CONTROL_ALLOW_ORIGIN
@ 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
CIVETWEB_API void mg_set_websocket_handler_with_subprotocols(struct mg_context *ctx, const char *uri, struct mg_websocket_subprotocols *subprotocols, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
CIVETWEB_API const char * mg_get_response_code_text(const struct mg_connection *conn, int response_code)
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)
static void remove_bad_file(const struct mg_connection *conn, const char *path)
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)
static void mg_cry_internal_wrap(const struct mg_connection *conn, struct mg_context *ctx, const char *func, unsigned line, const char *fmt,...) PRINTF_ARGS(5
CIVETWEB_API void mg_lock_connection(struct mg_connection *conn)
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)
CIVETWEB_API void * mg_get_thread_pointer(const struct mg_connection *conn)
#define MAX_WORKER_THREADS
CIVETWEB_API int mg_base64_encode(const unsigned char *src, size_t src_len, char *dst, size_t *dst_len)
CIVETWEB_API void * mg_get_user_data(const struct mg_context *ctx)
static void put_file(struct mg_connection *conn, const char *path)
CIVETWEB_API long long mg_store_body(struct mg_connection *conn, const char *path)
CIVETWEB_API void mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type)
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)
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,...)
CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len)
#define mg_opendir(conn, x)
static FUNCTION_MAY_BE_UNUSED uint64_t mg_get_current_time_ns(void)
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)
CIVETWEB_API struct mg_context * mg_start2(struct mg_init_data *init, struct mg_error_data *error)
static void send_static_cache_header(struct mg_connection *conn)
CIVETWEB_API void mg_unlock_connection(struct mg_connection *conn)
CIVETWEB_API const char * mg_get_header(const struct mg_connection *conn, const char *name)
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)
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)
CIVETWEB_API int mg_start_thread(mg_thread_func_t func, void *param)
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,...)
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 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)
CIVETWEB_API void mg_set_websocket_handler(struct mg_context *ctx, const char *uri, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
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 *)
#define mg_remove(conn, x)
static int mg_poll(struct mg_pollfd *pfd, unsigned int n, int milliseconds, const stop_flag_t *stop_flag)
CIVETWEB_API int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
static void close_all_listening_sockets(struct mg_context *ctx)
CIVETWEB_API int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence)
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)
CIVETWEB_API void mg_unlock_context(struct mg_context *ctx)
CIVETWEB_API int mg_base64_decode(const char *src, size_t src_len, unsigned char *dst, size_t *dst_len)
static int check_acl(struct mg_context *phys_ctx, const union usa *sa)
static const struct mg_option config_options[]
static FUNCTION_MAY_BE_UNUSED unsigned long mg_current_thread_id(void)
static const struct mg_http_method_info * get_http_method_info(const char *method)
#define STOP_FLAG_IS_ZERO(f)
CIVETWEB_API void mg_stop(struct mg_context *ctx)
static int get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS])
static int set_uid_option(struct mg_context *phys_ctx)
static int switch_domain_context(struct mg_connection *conn)
CIVETWEB_API int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
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 void static void mg_set_thread_name(const char *name)
CIVETWEB_API int mg_send_file_body(struct mg_connection *conn, const char *path)
static int get_option_index(const char *name)
CIVETWEB_API int mg_get_server_ports(const struct mg_context *ctx, int size, struct mg_server_port *ports)
static char * mg_strdup(const char *str)
static void addenv(struct cgi_environment *env, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
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]
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
#define CGI_ENVIRONMENT_SIZE
static long ssl_get_protocol(int version_id)
static int mg_init_library_called
#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)
#define MG_FILE_COMPRESSION_SIZE_LIMIT
#define USA_IN_PORT_UNSAFE(s)
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)
#define MG_FOPEN_MODE_READ
#define STOP_FLAG_ASSIGN(f, v)
CIVETWEB_API int mg_strcasecmp(const char *s1, const char *s2)
CIVETWEB_API struct mg_connection * mg_connect_websocket_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
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 pthread_mutexattr_t pthread_mutex_attr
CIVETWEB_API int mg_send_digest_access_authentication_request(struct mg_connection *conn, const char *realm)
static int ssl_servername_callback(SSL *ssl, int *ad, void *arg)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
CIVETWEB_API struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
CIVETWEB_API const struct mg_response_info * mg_get_response_info(const struct mg_connection *conn)
static void fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
static const char * get_header(const struct mg_header *hdr, int num_hdr, const char *name)
static FUNCTION_MAY_BE_UNUSED ptrdiff_t mg_atomic_dec(volatile ptrdiff_t *addr)
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)
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)
CIVETWEB_API int mg_get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int timeout)
static int set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
CIVETWEB_API 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)
static int skip_to_end_of_word_and_terminate(char **ppw, int eol)
CIVETWEB_API int mg_write(struct mg_connection *conn, const void *buf, size_t len)
CIVETWEB_API unsigned mg_exit_library(void)
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)
#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)
CIVETWEB_API struct mg_context * mg_get_context(const struct mg_connection *conn)
static int get_first_ssl_listener_index(const struct mg_context *ctx)
CIVETWEB_API int mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
#define mg_mkdir(conn, path, mode)
static const struct @6 abs_uri_protocols[]
static const struct @5 builtin_mime_types[]
CIVETWEB_API int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
static int hexdump2string(void *mem, int memlen, char *buf, int buflen)
static const struct mg_http_method_info http_methods[]
static void handle_directory_request(struct mg_connection *conn, const char *dir)
static int set_ports_option(struct mg_context *phys_ctx)
CIVETWEB_API const char * mg_get_builtin_mime_type(const char *path)
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)
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)
static const char * mg_strcasestr(const char *big_str, const char *small_str)
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)
CIVETWEB_API int mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
CIVETWEB_API 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)
CIVETWEB_API void mg_set_user_connection_data(const struct mg_connection *const_conn, void *data)
static int set_throttle(const char *spec, const union usa *rsa, const char *uri)
static void mg_snprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(5
static void ssl_info_callback(const SSL *ssl, int what, int ret)
CIVETWEB_API const struct mg_option * mg_get_valid_options(void)
static void bin2str(char *to, const unsigned char *p, size_t len)
#define MG_FOPEN_MODE_APPEND
CIVETWEB_API const struct mg_request_info * mg_get_request_info(const struct mg_connection *conn)
#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
CIVETWEB_API void mg_set_auth_handler(struct mg_context *ctx, const char *uri, mg_authorization_handler handler, void *cbdata)
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)
CIVETWEB_API int mg_check_digest_access_authentication(struct mg_connection *conn, const char *realm, const char *filename)
static void uninitialize_openssl(void)
static int parse_match_net(const struct vec *vec, const union usa *sa, int no_strict)
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)
CIVETWEB_API void * mg_get_user_connection_data(const struct mg_connection *conn)
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)
CIVETWEB_API char * mg_md5(char buf[33],...)
CIVETWEB_API int mg_get_var(const char *data, size_t data_len, const char *name, 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)
CIVETWEB_API void mg_disable_connection_keep_alive(struct mg_connection *conn)
static void get_mime_type(struct mg_connection *conn, const char *path, struct vec *vec)
static int set_blocking_mode(SOCKET sock)
CIVETWEB_API struct mg_connection * mg_connect_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size)
#define MAX_CGI_ENVIR_VARS
static char * mg_strdup_ctx(const char *str, struct mg_context *ctx)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
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)
CIVETWEB_API int mg_modify_passwords_file_ha1(const char *fname, const char *domain, const char *user, const char *ha1)
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)
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
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)
CIVETWEB_API int mg_send_chunk(struct mg_connection *conn, const char *chunk, unsigned int chunk_len)
@ CONNECTION_TYPE_RESPONSE
@ CONNECTION_TYPE_INVALID
@ CONNECTION_TYPE_REQUEST
#define mg_static_assert(cond, txt)
#define SOCKET_TIMEOUT_QUANTUM
CIVETWEB_API struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static void dav_mkcol(struct mg_connection *conn, const char *path)
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)
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)
CIVETWEB_API unsigned mg_init_library(unsigned features)
static void construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
CIVETWEB_API void mg_send_mime_file2(struct mg_connection *conn, const char *path, const char *mime_type, const char *additional_headers)
static FUNCTION_MAY_BE_UNUSED ptrdiff_t mg_atomic_inc(volatile ptrdiff_t *addr)
static int refresh_trust(struct mg_connection *conn)
CIVETWEB_API int mg_send_http_error(struct mg_connection *conn, int status, const char *fmt,...)
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)
CIVETWEB_API int mg_send_http_redirect(struct mg_connection *conn, const char *target_url, int redirect_code)
#define ERROR_TRY_AGAIN(err)
static void send_cors_header(struct mg_connection *conn)
CIVETWEB_API int mg_printf(struct mg_connection *conn, const char *fmt,...)
static unsigned char b64reverse(char letter)
CIVETWEB_API struct mg_connection * mg_connect_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size)
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)
CIVETWEB_API unsigned mg_check_feature(unsigned feature)
static void * cryptolib_dll_handle
static const char * mg_fgets(char *buf, size_t size, struct mg_file *filep)
#define IGNORE_UNUSED_RESULT(a)
static void discard_unread_request_data(struct mg_connection *conn)
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)
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)
@ PROTOCOL_TYPE_WEBSOCKET
static __inline void mg_free(void *a)
static void handle_request_stat_log(struct mg_connection *conn)
CIVETWEB_API 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)
static int mg_join_thread(pthread_t threadid)
CIVETWEB_API void * mg_get_user_context_data(const struct mg_connection *conn)
CIVETWEB_API int mg_send_http_ok(struct mg_connection *conn, const char *mime_type, long long content_length)
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)
CIVETWEB_API void mg_close_connection(struct mg_connection *conn)
static int is_ssl_port_used(const char *ports)
static void init_connection(struct mg_connection *conn)
CIVETWEB_API int mg_split_form_urlencoded(char *data, struct mg_header *form_fields, unsigned num_form_fields)
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)
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)
static void * ssllib_dll_handle
static int mg_fgetc(struct mg_file *filep)
CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
static void handle_cgi_request(struct mg_connection *conn, const char *prog, int cgi_config_idx)
#define PASSWORDS_FILE_NAME
CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path)
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)
#define STRUCT_FILE_INITIALIZER
static volatile ptrdiff_t thread_idx_max
CIVETWEB_API int mg_get_system_info(char *buffer, int buflen)
static FUNCTION_MAY_BE_UNUSED void mg_global_unlock(void)
static FUNCTION_MAY_BE_UNUSED void mg_global_lock(void)
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)
static uint64_t get_random(void)
CIVETWEB_API int mg_read(struct mg_connection *conn, void *buf, size_t len)
CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len)
static int is_valid_http_method(const char *method)
static void url_decode_in_place(char *buf)
@ MG_FEATURES_X_DOMAIN_SOCKET
@ MG_FEATURES_COMPRESSION
@ 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
CIVETWEB_API int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
void *(* mg_thread_func_t)(void *)
#define PRINTF_FORMAT_STRING(s)
CIVETWEB_API int mg_response_header_send(struct mg_connection *conn)
int(* mg_authorization_handler)(struct mg_connection *conn, void *cbdata)
CIVETWEB_API int mg_response_header_add(struct mg_connection *conn, const char *header, const char *value, int value_len)
CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
void(* mg_websocket_ready_handler)(struct mg_connection *, void *)
#define PRINTF_ARGS(x, y)
@ MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE
@ MG_WEBSOCKET_OPCODE_PONG
@ MG_WEBSOCKET_OPCODE_PING
@ 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
int(* mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *)
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
CIVETWEB_API 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 *)
CIVETWEB_API int mg_response_header_add_lines(struct mg_connection *conn, const char *http1_headers)
CURL_EXTERN int void * arg
LUA_API void lua_pushstring(lua_State *L, const char *s)
LUA_API int lua_toboolean(lua_State *L, int idx)
LUA_API const char * lua_tolstring(lua_State *L, int idx, size_t *len)
LUA_API int lua_type(lua_State *L, int idx)
LUA_API void lua_rawset(lua_State *L, int idx)
static void block(LexState *ls)
static int cond(LexState *ls)
static void chunk(LexState *ls)
static void close_func(LexState *ls)
static void body(LexState *ls, expdesc *e, int needself, int line)
LUA_API void lua_close(lua_State *L)
#define lua_getglobal(L, s)
static const char * output
static void error(LoadState *S, const char *why)
#define lua_pcall(L, n, r, f)
CURL_EXTERN CURLMcode curl_socket_t s
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
pthread_t * worker_threadids
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_pollfd * listening_socket_fds
struct mg_domain_context dd
struct twebdav_lock webdav_lock[NUM_WEBDAV_LOCKS]
unsigned int num_listening_sockets
unsigned int max_request_size
unsigned int cfg_worker_threads
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
const char * default_value
struct mg_header http_headers[MG_MAX_HEADERS]
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
const char * http_version
struct mg_header http_headers[MG_MAX_HEADERS]
const char ** subprotocols
struct mg_connection * conn
char user[UTF8_PATH_MAX *2]
char path[UTF8_PATH_MAX *2]
mg_websocket_close_handler close_handler
mg_websocket_data_handler data_handler
struct mg_connection * conn