23#if defined(__GNUC__) || defined(__MINGW32__)
25 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
26#if GCC_VERSION >= 40500
32#if defined(GCC_DIAGNOSTIC)
35#pragma GCC diagnostic ignored "-Wunused-macros"
37#pragma GCC diagnostic ignored "-Wpadded"
44#pragma GCC diagnostic push
45#pragma GCC diagnostic ignored "-Wreserved-id-macro"
49#if !defined(_CRT_SECURE_NO_WARNINGS)
50#define _CRT_SECURE_NO_WARNINGS
52#if !defined(_WIN32_WINNT)
53#define _WIN32_WINNT 0x0501
56#if !defined(_GNU_SOURCE)
59#if defined(__linux__) && !defined(_XOPEN_SOURCE)
60#define _XOPEN_SOURCE 600
62#if !defined(_LARGEFILE_SOURCE)
63#define _LARGEFILE_SOURCE
65#if !defined(_FILE_OFFSET_BITS)
66#define _FILE_OFFSET_BITS 64
68#if !defined(__STDC_FORMAT_MACROS)
69#define __STDC_FORMAT_MACROS
71#if !defined(__STDC_LIMIT_MACROS)
72#define __STDC_LIMIT_MACROS
74#if !defined(_DARWIN_UNLIMITED_SELECT)
75#define _DARWIN_UNLIMITED_SELECT
79#define __inline inline
85#pragma GCC diagnostic pop
95#pragma warning(disable : 4306)
97#pragma warning(disable : 4127)
99#pragma warning(disable : 4204)
101#pragma warning(disable : 4820)
103#pragma warning(disable : 4668)
105#pragma warning(disable : 4255)
107#pragma warning(disable : 4711)
114#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201100L
115#define mg_static_assert _Static_assert
116#elif defined(__cplusplus) && __cplusplus >= 201103L
117#define mg_static_assert static_assert
120#define mg_static_assert(cond, txt) \
121 extern char static_assert_replacement[(cond) ? 1 : -1]
125 "int data type size check");
127 "pointer data type size check");
132#if defined(NO_ALTERNATIVE_QUEUE)
133#if defined(ALTERNATIVE_QUEUE)
134#error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both"
137#define ALTERNATIVE_QUEUE
142#if !defined(WIN32_LEAN_AND_MEAN)
143#define WIN32_LEAN_AND_MEAN
146#if defined(__SYMBIAN32__)
152#error "Symbian is no longer maintained. CivetWeb no longer supports Symbian."
155#define PATH_MAX FILENAME_MAX
159#if !defined(CIVETWEB_HEADER_INCLUDED)
165#if !defined(DEBUG_TRACE)
167static void DEBUG_TRACE_FUNC(
const char *func,
172#define DEBUG_TRACE(fmt, ...) \
173 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
175#define NEED_DEBUG_TRACE_FUNC
178#define DEBUG_TRACE(fmt, ...) \
185#if !defined(DEBUG_ASSERT)
187#define DEBUG_ASSERT(cond) \
190 DEBUG_TRACE("ASSERTION FAILED: %s", #cond); \
195#define DEBUG_ASSERT(cond)
200#if defined(__GNUC__) && defined(GCC_INSTRUMENTATION)
201void __cyg_profile_func_enter(
void *this_fn,
void *call_site)
202 __attribute__((no_instrument_function));
204void __cyg_profile_func_exit(
void *this_fn,
void *call_site)
205 __attribute__((no_instrument_function));
208__cyg_profile_func_enter(
void *this_fn,
void *call_site)
210 if ((
void *)this_fn != (
void *)printf) {
211 printf(
"E %p %p\n", this_fn, call_site);
216__cyg_profile_func_exit(
void *this_fn,
void *call_site)
218 if ((
void *)this_fn != (
void *)printf) {
219 printf(
"X %p %p\n", this_fn, call_site);
225#if !defined(IGNORE_UNUSED_RESULT)
226#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
230#if defined(__GNUC__) || defined(__MINGW32__)
246#pragma GCC diagnostic ignored "-Wunused-function"
248#define FUNCTION_MAY_BE_UNUSED
251#define FUNCTION_MAY_BE_UNUSED
256#if !defined(_WIN32_WCE)
261#include <sys/types.h>
265#if defined(__clang__)
269#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
272#if defined(__GNUC__) || defined(__MINGW32__)
291#if defined(__clang__)
292#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
294#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
295#pragma clang diagnostic ignored "-Wno-keyword-macro"
299#define CLOCK_MONOTONIC (1)
300#define CLOCK_REALTIME (2)
302#include <mach/clock.h>
303#include <mach/mach.h>
304#include <mach/mach_time.h>
305#include <sys/errno.h>
310_civet_clock_gettime(
int clk_id,
struct timespec *t)
312 memset(t, 0,
sizeof(*t));
313 if (clk_id == CLOCK_REALTIME) {
315 int rv = gettimeofday(&now, NULL);
319 t->tv_sec = now.tv_sec;
320 t->tv_nsec = now.tv_usec * 1000;
323 }
else if (clk_id == CLOCK_MONOTONIC) {
324 static uint64_t clock_start_time = 0;
325 static mach_timebase_info_data_t timebase_ifo = {0, 0};
327 uint64_t now = mach_absolute_time();
329 if (clock_start_time == 0) {
330 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
336 clock_start_time = now;
339 now = (uint64_t)((
double)(now - clock_start_time)
340 * (
double)timebase_ifo.numer
341 / (
double)timebase_ifo.denom);
343 t->tv_sec = now / 1000000000;
344 t->tv_nsec = now % 1000000000;
351#if defined(__CLOCK_AVAILABILITY)
356_civet_safe_clock_gettime(
int clk_id,
struct timespec *t)
359 return clock_gettime(clk_id, t);
361 return _civet_clock_gettime(clk_id, t);
363#define clock_gettime _civet_safe_clock_gettime
365#define clock_gettime _civet_clock_gettime
388#if !defined(MAX_WORKER_THREADS)
389#define MAX_WORKER_THREADS (1024 * 64)
396#if !defined(SOCKET_TIMEOUT_QUANTUM)
397#define SOCKET_TIMEOUT_QUANTUM (2000)
401#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT)
402#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024)
405#if !defined(PASSWORDS_FILE_NAME)
406#define PASSWORDS_FILE_NAME ".htpasswd"
411#if !defined(CGI_ENVIRONMENT_SIZE)
412#define CGI_ENVIRONMENT_SIZE (4096)
416#if !defined(MAX_CGI_ENVIR_VARS)
417#define MAX_CGI_ENVIR_VARS (256)
421#if !defined(MG_BUF_LEN)
422#define MG_BUF_LEN (1024 * 8)
435#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
438#if !defined(INT64_MAX)
439#define INT64_MAX (9223372036854775807)
442#define SHUTDOWN_RD (0)
443#define SHUTDOWN_WR (1)
444#define SHUTDOWN_BOTH (2)
447 "worker threads must be a positive number");
450 "size_t data type size check");
459#if !defined(PATH_MAX)
460#define W_PATH_MAX (MAX_PATH)
462#define PATH_MAX (W_PATH_MAX * 3)
464#define W_PATH_MAX ((PATH_MAX + 2) / 3)
469#if !defined(_IN_PORT_T)
470#if !defined(in_port_t)
471#define in_port_t u_short
475#if !defined(_WIN32_WCE)
485#define errno ((int)(GetLastError()))
486#define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
489#define MAKEUQUAD(lo, hi) \
490 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
491#define RATE_DIFF (10000000)
492#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
493#define SYS2UNIX_TIME(lo, hi) \
494 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
502#define STR(x) STRX(x)
503#define __func__ __FILE__ ":" STR(__LINE__)
504#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
505#define strtoll(x, y, z) (_atoi64(x))
507#define __func__ __FUNCTION__
508#define strtoull(x, y, z) (_strtoui64(x, y, z))
509#define strtoll(x, y, z) (_strtoi64(x, y, z))
513#define ERRNO ((int)(GetLastError()))
516#if defined(_WIN64) || defined(__MINGW64__)
518#define SSL_LIB "ssleay64.dll"
520#if !defined(CRYPTO_LIB)
521#define CRYPTO_LIB "libeay64.dll"
525#define SSL_LIB "ssleay32.dll"
527#if !defined(CRYPTO_LIB)
528#define CRYPTO_LIB "libeay32.dll"
532#define O_NONBLOCK (0)
536#if !defined(EWOULDBLOCK)
537#define EWOULDBLOCK WSAEWOULDBLOCK
540#define INT64_FMT "I64d"
541#define UINT64_FMT "I64u"
543#define WINCDECL __cdecl
544#define vsnprintf_impl _vsnprintf
545#define access _access
546#define mg_sleep(x) (Sleep(x))
548#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
550#define popen(x, y) (_popen(x, y))
553#define pclose(x) (_pclose(x))
555#define close(x) (_close(x))
556#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
558#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
559#define fdopen(x, y) (_fdopen((x), (y)))
560#define write(x, y, z) (_write((x), (y), (unsigned)z))
561#define read(x, y, z) (_read((x), (y), (unsigned)z))
562#define flockfile(x) (EnterCriticalSection(&global_log_file_lock))
563#define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock))
564#define sleep(x) (Sleep((x)*1000))
565#define rmdir(x) (_rmdir(x))
566#if defined(_WIN64) || !defined(__MINGW32__)
568#define timegm(x) (_mkgmtime(x))
570time_t timegm(
struct tm *tm);
576#define fileno(x) (_fileno(x))
579typedef HANDLE pthread_mutex_t;
580typedef DWORD pthread_key_t;
581typedef HANDLE pthread_t;
583 CRITICAL_SECTION threadIdSec;
587#if !defined(__clockid_t_defined)
588typedef DWORD clockid_t;
590#if !defined(CLOCK_MONOTONIC)
591#define CLOCK_MONOTONIC (1)
593#if !defined(CLOCK_REALTIME)
594#define CLOCK_REALTIME (2)
596#if !defined(CLOCK_THREAD)
597#define CLOCK_THREAD (3)
599#if !defined(CLOCK_PROCESS)
600#define CLOCK_PROCESS (4)
604#if defined(_MSC_VER) && (_MSC_VER >= 1900)
605#define _TIMESPEC_DEFINED
607#if !defined(_TIMESPEC_DEFINED)
614#if !defined(WIN_PTHREADS_TIME_H)
615#define MUST_IMPLEMENT_CLOCK_GETTIME
618#if defined(MUST_IMPLEMENT_CLOCK_GETTIME)
619#define clock_gettime mg_clock_gettime
621clock_gettime(clockid_t clk_id,
struct timespec *tp)
624 ULARGE_INTEGER li, li2;
627 static double perfcnt_per_sec = 0.0;
631 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
632 perfcnt_per_sec = 1.0 / li.QuadPart;
637 memset(tp, 0,
sizeof(*tp));
639 if (clk_id == CLOCK_REALTIME) {
642 GetSystemTimeAsFileTime(&ft);
643 li.LowPart = ft.dwLowDateTime;
644 li.HighPart = ft.dwHighDateTime;
645 li.QuadPart -= 116444736000000000;
646 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
647 tp->tv_nsec = (
long)(li.QuadPart % 10000000) * 100;
651 }
else if (clk_id == CLOCK_MONOTONIC) {
654 QueryPerformanceCounter((LARGE_INTEGER *)&li);
655 d = li.QuadPart * perfcnt_per_sec;
656 tp->tv_sec = (time_t)
d;
658 tp->tv_nsec = (
long)(
d * 1.0E9);
662 }
else if (clk_id == CLOCK_THREAD) {
665 FILETIME t_create, t_exit, t_kernel, t_user;
666 if (GetThreadTimes(GetCurrentThread(),
671 li.LowPart = t_user.dwLowDateTime;
672 li.HighPart = t_user.dwHighDateTime;
673 li2.LowPart = t_kernel.dwLowDateTime;
674 li2.HighPart = t_kernel.dwHighDateTime;
675 li.QuadPart += li2.QuadPart;
676 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
677 tp->tv_nsec = (
long)(li.QuadPart % 10000000) * 100;
682 }
else if (clk_id == CLOCK_PROCESS) {
685 FILETIME t_create, t_exit, t_kernel, t_user;
686 if (GetProcessTimes(GetCurrentProcess(),
691 li.LowPart = t_user.dwLowDateTime;
692 li.HighPart = t_user.dwHighDateTime;
693 li2.LowPart = t_kernel.dwLowDateTime;
694 li2.HighPart = t_kernel.dwHighDateTime;
695 li.QuadPart += li2.QuadPart;
696 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
697 tp->tv_nsec = (
long)(li.QuadPart % 10000000) * 100;
717static int pthread_mutex_lock(pthread_mutex_t *);
718static int pthread_mutex_unlock(pthread_mutex_t *);
734 char d_name[PATH_MAX];
739 WIN32_FIND_DATAW info;
740 struct dirent result;
744#if !defined(HAVE_POLL)
755#pragma comment(lib, "Ws2_32.lib")
760#include <arpa/inet.h>
763#include <netinet/in.h>
764#include <netinet/tcp.h>
767#include <sys/socket.h>
769#include <sys/utsname.h>
774typedef unsigned short int in_port_t;
781#define vsnprintf_impl vsnprintf
783#if !defined(NO_SSL_DL) && !defined(NO_SSL)
788#define SSL_LIB "libssl.dylib"
789#define CRYPTO_LIB "libcrypto.dylib"
792#define SSL_LIB "libssl.so"
794#if !defined(CRYPTO_LIB)
795#define CRYPTO_LIB "libcrypto.so"
798#if !defined(O_BINARY)
801#define closesocket(a) (close(a))
802#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
803#define mg_remove(conn, x) (remove(x))
804#define mg_sleep(x) (usleep((x)*1000))
805#define mg_opendir(conn, x) (opendir(x))
806#define mg_closedir(x) (closedir(x))
807#define mg_readdir(x) (readdir(x))
809#define INVALID_SOCKET (-1)
810#define INT64_FMT PRId64
811#define UINT64_FMT PRIu64
817#if !defined(CLOCK_MONOTONIC)
818#define CLOCK_MONOTONIC CLOCK_REALTIME
836#if !defined(SOMAXCONN)
838#define SOMAXCONN (100)
842#if defined(NEED_TIMEGM)
846 return (
y % 4 == 0 &&
y % 100 != 0) ||
y % 400 == 0;
852 return (
y - 1969) / 4 - (
y - 1901) / 100 + (
y - 1601) / 400;
858 static const unsigned short ydays[] = {
859 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
860 int year = tm->tm_year + 1900;
861 int mon = tm->tm_mon;
862 int mday = tm->tm_mday - 1;
863 int hour = tm->tm_hour;
864 int min = tm->tm_min;
865 int sec = tm->tm_sec;
867 if (year < 1970 || mon < 0 || mon > 11 || mday < 0
868 || (mday >= ydays[mon + 1] - ydays[mon]
869 + (mon == 1 && is_leap(year) ? 1 : 0))
870 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60)
873 time_t res = year - 1970;
876 res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0);
877 res += count_leap(year);
892#define va_copy(x, y) ((x) = (y))
899#if defined(GCC_DIAGNOSTIC)
901#pragma GCC diagnostic push
902#pragma GCC diagnostic ignored "-Wunused-function"
906static CRITICAL_SECTION global_log_file_lock;
912 return GetCurrentThreadId();
920 void (*_ignored)(
void *)
927 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
935pthread_key_delete(pthread_key_t key)
937 return TlsFree(key) ? 0 : 1;
943pthread_setspecific(pthread_key_t key,
void *value)
945 return TlsSetValue(key, value) ? 0 : 1;
951pthread_getspecific(pthread_key_t key)
953 return TlsGetValue(key);
956#if defined(GCC_DIAGNOSTIC)
958#pragma GCC diagnostic pop
967#if defined(_WIN32_WCE)
970#if defined(GCC_DIAGNOSTIC)
972#pragma GCC diagnostic push
973#pragma GCC diagnostic ignored "-Wunused-function"
986 SystemTimeToFileTime(&st, &ft);
987 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
999localtime_s(
const time_t *ptime,
struct tm *ptm)
1001 int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
1004 TIME_ZONE_INFORMATION tzinfo;
1010 *(int64_t *)&ft = t;
1011 FileTimeToLocalFileTime(&ft, &lft);
1012 FileTimeToSystemTime(&lft, &st);
1013 ptm->tm_year = st.wYear - 1900;
1014 ptm->tm_mon = st.wMonth - 1;
1015 ptm->tm_wday = st.wDayOfWeek;
1016 ptm->tm_mday = st.wDay;
1017 ptm->tm_hour = st.wHour;
1018 ptm->tm_min = st.wMinute;
1019 ptm->tm_sec = st.wSecond;
1022 (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0;
1030gmtime_s(
const time_t *ptime,
struct tm *ptm)
1033 return localtime_s(ptime, ptm);
1039static int tm_index = 0;
1044localtime(
const time_t *ptime)
1046 int i =
mg_atomic_inc(&tm_index) % (
sizeof(tm_array) /
sizeof(tm_array[0]));
1047 return localtime_s(ptime, tm_array + i);
1053gmtime(
const time_t *ptime)
1056 return gmtime_s(ptime, tm_array + i);
1062strftime(
char *dst,
size_t dst_size,
const char *fmt,
const struct tm *tm)
1069#define _beginthreadex(psec, stack, func, prm, flags, ptid) \
1070 (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid)
1072#define remove(f) mg_remove(NULL, f)
1077rename(
const char *
a,
const char *
b)
1079 wchar_t wa[W_PATH_MAX];
1080 wchar_t wb[W_PATH_MAX];
1084 return MoveFileW(wa, wb) ? 0 : -1;
1096stat(
const char *
name,
struct stat *st)
1098 wchar_t wbuf[W_PATH_MAX];
1099 WIN32_FILE_ATTRIBUTE_DATA attr;
1100 time_t creation_time, write_time;
1103 memset(&attr, 0,
sizeof(attr));
1105 GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr);
1107 (((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow;
1109 write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime,
1110 attr.ftLastWriteTime.dwHighDateTime);
1111 creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime,
1112 attr.ftCreationTime.dwHighDateTime);
1114 if (creation_time > write_time) {
1115 st->st_mtime = creation_time;
1117 st->st_mtime = write_time;
1122#define access(x, a) 1
1130#if defined(GCC_DIAGNOSTIC)
1132#pragma GCC diagnostic pop
1138#if defined(GCC_DIAGNOSTIC)
1140#pragma GCC diagnostic push
1141#pragma GCC diagnostic ignored "-Wunused-function"
1143#if defined(__clang__)
1145#pragma clang diagnostic push
1146#pragma clang diagnostic ignored "-Wunused-function"
1155static int pthread_mutex_lock(pthread_mutex_t *mutex);
1158static int pthread_mutex_unlock(pthread_mutex_t *mutex);
1183#if defined(_WIN32) && !defined(NO_ATOMICS)
1187 ret = InterlockedIncrement((
volatile long *)addr);
1188#elif defined(__GNUC__) \
1189 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1190 && !defined(NO_ATOMICS)
1191 ret = __sync_add_and_fetch(addr, 1);
1206#if defined(_WIN32) && !defined(NO_ATOMICS)
1210 ret = InterlockedDecrement((
volatile long *)addr);
1211#elif defined(__GNUC__) \
1212 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1213 && !defined(NO_ATOMICS)
1214 ret = __sync_sub_and_fetch(addr, 1);
1224#if defined(USE_SERVER_STATS)
1226mg_atomic_add(
volatile int64_t *addr, int64_t value)
1229#if defined(_WIN64) && !defined(NO_ATOMICS)
1230 ret = InterlockedAdd64(addr, value);
1231#elif defined(__GNUC__) \
1232 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1233 && !defined(NO_ATOMICS)
1234 ret = __sync_add_and_fetch(addr, value);
1246#if defined(GCC_DIAGNOSTIC)
1248#pragma GCC diagnostic pop
1250#if defined(__clang__)
1252#pragma clang diagnostic pop
1256#if defined(USE_SERVER_STATS)
1258struct mg_memory_stat {
1259 volatile int64_t totalMemUsed;
1260 volatile int64_t maxMemUsed;
1261 volatile int blockCount;
1265static struct mg_memory_stat *get_memory_stat(
struct mg_context *ctx);
1269mg_malloc_ex(
size_t size,
1274 void *data =
malloc(
size + 2 *
sizeof(uintptr_t));
1276 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1278#if defined(MEMORY_DEBUGGING)
1279 char mallocStr[256];
1286 int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)
size);
1287 if (mmem > mstat->maxMemUsed) {
1290 mstat->maxMemUsed = mmem;
1294 ((uintptr_t *)data)[0] =
size;
1295 ((uintptr_t *)data)[1] = (uintptr_t)mstat;
1296 memory = (
void *)(((
char *)data) + 2 *
sizeof(uintptr_t));
1299#if defined(MEMORY_DEBUGGING)
1301 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1303 (
unsigned long)
size,
1304 (
unsigned long)mstat->totalMemUsed,
1305 (
unsigned long)mstat->blockCount,
1309 OutputDebugStringA(mallocStr);
1320mg_calloc_ex(
size_t count,
1326 void *data = mg_malloc_ex(
size * count, ctx,
file,
line);
1329 memset(data, 0,
size * count);
1336mg_free_ex(
void *memory,
const char *
file,
unsigned line)
1338 void *data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1341#if defined(MEMORY_DEBUGGING)
1342 char mallocStr[256];
1349 uintptr_t
size = ((uintptr_t *)data)[0];
1350 struct mg_memory_stat *mstat =
1351 (
struct mg_memory_stat *)(((uintptr_t *)data)[1]);
1352 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)
size);
1354#if defined(MEMORY_DEBUGGING)
1356 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1358 (
unsigned long)
size,
1359 (
unsigned long)mstat->totalMemUsed,
1360 (
unsigned long)mstat->blockCount,
1364 OutputDebugStringA(mallocStr);
1375mg_realloc_ex(
void *memory,
1385#if defined(MEMORY_DEBUGGING)
1386 char mallocStr[256];
1395 struct mg_memory_stat *mstat;
1396 data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1397 oldsize = ((uintptr_t *)data)[0];
1398 mstat = (
struct mg_memory_stat *)((uintptr_t *)data)[1];
1399 _realloc =
realloc(data, newsize + 2 *
sizeof(uintptr_t));
1402 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize);
1403#if defined(MEMORY_DEBUGGING)
1405 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1407 (
unsigned long)oldsize,
1408 (
unsigned long)mstat->totalMemUsed,
1409 (
unsigned long)mstat->blockCount,
1413 OutputDebugStringA(mallocStr);
1418 mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize);
1419#if defined(MEMORY_DEBUGGING)
1421 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1423 (
unsigned long)newsize,
1424 (
unsigned long)mstat->totalMemUsed,
1425 (
unsigned long)mstat->blockCount,
1429 OutputDebugStringA(mallocStr);
1434 *(uintptr_t *)data = newsize;
1435 data = (
void *)(((
char *)data) + 2 *
sizeof(uintptr_t));
1437#if defined(MEMORY_DEBUGGING)
1439 OutputDebugStringA(
"MEM: realloc failed\n");
1448 data = mg_malloc_ex(newsize, ctx,
file,
line);
1459#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
1460#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
1461#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
1462#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1464#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
1465#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
1466#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
1470static __inline
void *
1476static __inline
void *
1482static __inline
void *
1494#define mg_malloc_ctx(a, c) mg_malloc(a)
1495#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
1496#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
1497#define mg_free_ctx(a, c) mg_free(a)
1530#if defined(snprintf)
1533#if defined(vsnprintf)
1536#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1537#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1538#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1539#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1540#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
1544#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1558#if defined(MG_LEGACY_INTERFACE)
1559#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
1566 HANDLE pthread_cond_helper_mutex;
1569#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
1575#if defined(GCC_DIAGNOSTIC)
1577#pragma GCC diagnostic push
1578#pragma GCC diagnostic ignored "-Wunused-function"
1580#if defined(__clang__)
1582#pragma clang diagnostic push
1583#pragma clang diagnostic ignored "-Wunused-function"
1602 return GetCurrentThreadId();
1605#if defined(__clang__)
1606#pragma clang diagnostic push
1607#pragma clang diagnostic ignored "-Wunreachable-code"
1615 if (
sizeof(pthread_t) >
sizeof(
unsigned long)) {
1626 pthread_setspecific(
sTlsKey, tls);
1633 unsigned long ret = 0;
1634 pthread_t t = pthread_self();
1635 memcpy(&ret, &t,
sizeof(pthread_t));
1639#if defined(__clang__)
1640#pragma clang diagnostic pop
1651 struct timespec tsnow;
1652 clock_gettime(CLOCK_REALTIME, &tsnow);
1653 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1657#if defined(GCC_DIAGNOSTIC)
1659#pragma GCC diagnostic pop
1661#if defined(__clang__)
1663#pragma clang diagnostic pop
1667#if defined(NEED_DEBUG_TRACE_FUNC)
1669DEBUG_TRACE_FUNC(
const char *func,
unsigned line,
const char *fmt, ...)
1673 static uint64_t nslast;
1674 struct timespec tsnow;
1679 clock_gettime(CLOCK_REALTIME, &tsnow);
1680 nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000)
1681 + ((uint64_t)tsnow.tv_nsec);
1688 printf(
"*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ",
1689 (
unsigned long)tsnow.tv_sec,
1690 (
unsigned long)tsnow.tv_nsec,
1695 va_start(args, fmt);
1700 funlockfile(stdout);
1706#define MD5_STATIC static
1710#if defined(NO_SOCKLEN_T)
1711typedef int socklen_t;
1714#define IP_ADDR_STR_LEN (50)
1716#if !defined(MSG_NOSIGNAL)
1717#define MSG_NOSIGNAL (0)
1725#if defined(NO_SSL_DL)
1726#include <openssl/bn.h>
1727#include <openssl/conf.h>
1728#include <openssl/crypto.h>
1729#include <openssl/dh.h>
1730#include <openssl/engine.h>
1731#include <openssl/err.h>
1732#include <openssl/opensslv.h>
1733#include <openssl/pem.h>
1734#include <openssl/ssl.h>
1735#include <openssl/tls1.h>
1736#include <openssl/x509.h>
1738#if defined(WOLFSSL_VERSION)
1741#include "wolfssl_extras.inl"
1744#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1746#if !defined(OPENSSL_API_1_1)
1747#define OPENSSL_API_1_1
1749#define OPENSSL_REMOVE_THREAD_STATE()
1751#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_thread_state(NULL)
1772#define SSL_CTRL_OPTIONS (32)
1773#define SSL_CTRL_CLEAR_OPTIONS (77)
1774#define SSL_CTRL_SET_ECDH_AUTO (94)
1776#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L
1777#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L
1778#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
1780#define SSL_VERIFY_NONE (0)
1781#define SSL_VERIFY_PEER (1)
1782#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
1783#define SSL_VERIFY_CLIENT_ONCE (4)
1784#define SSL_OP_ALL ((long)(0x80000BFFUL))
1785#define SSL_OP_NO_SSLv2 (0x01000000L)
1786#define SSL_OP_NO_SSLv3 (0x02000000L)
1787#define SSL_OP_NO_TLSv1 (0x04000000L)
1788#define SSL_OP_NO_TLSv1_2 (0x08000000L)
1789#define SSL_OP_NO_TLSv1_1 (0x10000000L)
1790#define SSL_OP_SINGLE_DH_USE (0x00100000L)
1791#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L)
1792#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L)
1793#define SSL_OP_NO_COMPRESSION (0x00020000L)
1795#define SSL_CB_HANDSHAKE_START (0x10)
1796#define SSL_CB_HANDSHAKE_DONE (0x20)
1798#define SSL_ERROR_NONE (0)
1799#define SSL_ERROR_SSL (1)
1800#define SSL_ERROR_WANT_READ (2)
1801#define SSL_ERROR_WANT_WRITE (3)
1802#define SSL_ERROR_WANT_X509_LOOKUP (4)
1803#define SSL_ERROR_SYSCALL (5)
1804#define SSL_ERROR_ZERO_RETURN (6)
1805#define SSL_ERROR_WANT_CONNECT (7)
1806#define SSL_ERROR_WANT_ACCEPT (8)
1808#define TLSEXT_TYPE_server_name (0)
1809#define TLSEXT_NAMETYPE_host_name (0)
1810#define SSL_TLSEXT_ERR_OK (0)
1811#define SSL_TLSEXT_ERR_ALERT_WARNING (1)
1812#define SSL_TLSEXT_ERR_ALERT_FATAL (2)
1813#define SSL_TLSEXT_ERR_NOACK (3)
1821#if defined(OPENSSL_API_1_1)
1823#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
1824#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
1825#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
1826#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
1827#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
1828#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
1829#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
1830#define SSL_new (*(SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
1831#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
1832#define TLS_server_method (*(SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
1833#define OPENSSL_init_ssl \
1834 (*(int (*)(uint64_t opts, \
1835 const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10] \
1837#define SSL_CTX_use_PrivateKey_file \
1838 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
1839#define SSL_CTX_use_certificate_file \
1840 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
1841#define SSL_CTX_set_default_passwd_cb \
1842 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
1843#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
1844#define SSL_CTX_use_certificate_chain_file \
1845 (*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr)
1846#define TLS_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[16].ptr)
1847#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr)
1848#define SSL_CTX_set_verify \
1849 (*(void (*)(SSL_CTX *, \
1851 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18] \
1853#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr)
1854#define SSL_CTX_load_verify_locations \
1855 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr)
1856#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr)
1857#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr)
1858#define SSL_get_peer_certificate (*(X509 * (*)(SSL *)) ssl_sw[23].ptr)
1859#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr)
1860#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *)) ssl_sw[25].ptr)
1861#define SSL_CIPHER_get_name \
1862 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr)
1863#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr)
1864#define SSL_CTX_set_session_id_context \
1865 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr)
1866#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr)
1867#define SSL_CTX_set_cipher_list \
1868 (*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr)
1869#define SSL_CTX_set_options \
1870 (*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr)
1871#define SSL_CTX_set_info_callback \
1872 (*(void (*)(SSL_CTX * ctx, void (*callback)(const SSL *, int, int))) \
1875#define SSL_get_ex_data (*(char *(*)(const SSL *, int))ssl_sw[33].ptr)
1876#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
1877#define SSL_CTX_callback_ctrl \
1878 (*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
1879#define SSL_get_servername \
1880 (*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
1881#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *)) ssl_sw[37].ptr)
1882#define SSL_ctrl (*(long (*)(SSL *, int, long, void *))ssl_sw[38].ptr)
1884#define SSL_CTX_clear_options(ctx, op) \
1885 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
1886#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
1887 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
1889#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
1890#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
1891#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
1892#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
1893 SSL_CTX_callback_ctrl(ctx, \
1894 SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
1896#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
1897 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg)
1898#define SSL_set_tlsext_host_name(ctx, arg) \
1899 SSL_ctrl(ctx, SSL_CTRL_SET_TLSEXT_HOSTNAME, 0, (void *)arg)
1901#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
1902#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
1904#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
1905#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
1907#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr)
1908#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr)
1909#define CONF_modules_unload (*(void (*)(int))crypto_sw[2].ptr)
1910#define X509_free (*(void (*)(X509 *))crypto_sw[3].ptr)
1911#define X509_get_subject_name (*(X509_NAME * (*)(X509 *)) crypto_sw[4].ptr)
1912#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *)) crypto_sw[5].ptr)
1913#define X509_NAME_oneline \
1914 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[6].ptr)
1915#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *)) crypto_sw[7].ptr)
1916#define EVP_get_digestbyname \
1917 (*(const EVP_MD *(*)(const char *))crypto_sw[8].ptr)
1920 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
1923#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[10].ptr)
1924#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[11].ptr)
1925#define ASN1_INTEGER_to_BN \
1926 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn)) crypto_sw[12].ptr)
1927#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[13].ptr)
1928#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[14].ptr)
1930#define OPENSSL_free(a) CRYPTO_free(a)
1932#define OPENSSL_REMOVE_THREAD_STATE()
1939 {
"SSL_accept", NULL},
1940 {
"SSL_connect", NULL},
1942 {
"SSL_write", NULL},
1943 {
"SSL_get_error", NULL},
1944 {
"SSL_set_fd", NULL},
1946 {
"SSL_CTX_new", NULL},
1947 {
"TLS_server_method", NULL},
1948 {
"OPENSSL_init_ssl", NULL},
1949 {
"SSL_CTX_use_PrivateKey_file", NULL},
1950 {
"SSL_CTX_use_certificate_file", NULL},
1951 {
"SSL_CTX_set_default_passwd_cb", NULL},
1952 {
"SSL_CTX_free", NULL},
1953 {
"SSL_CTX_use_certificate_chain_file", NULL},
1954 {
"TLS_client_method", NULL},
1955 {
"SSL_pending", NULL},
1956 {
"SSL_CTX_set_verify", NULL},
1957 {
"SSL_shutdown", NULL},
1958 {
"SSL_CTX_load_verify_locations", NULL},
1959 {
"SSL_CTX_set_default_verify_paths", NULL},
1960 {
"SSL_CTX_set_verify_depth", NULL},
1961 {
"SSL_get_peer_certificate", NULL},
1962 {
"SSL_get_version", NULL},
1963 {
"SSL_get_current_cipher", NULL},
1964 {
"SSL_CIPHER_get_name", NULL},
1965 {
"SSL_CTX_check_private_key", NULL},
1966 {
"SSL_CTX_set_session_id_context", NULL},
1967 {
"SSL_CTX_ctrl", NULL},
1968 {
"SSL_CTX_set_cipher_list", NULL},
1969 {
"SSL_CTX_set_options", NULL},
1970 {
"SSL_CTX_set_info_callback", NULL},
1971 {
"SSL_get_ex_data", NULL},
1972 {
"SSL_set_ex_data", NULL},
1973 {
"SSL_CTX_callback_ctrl", NULL},
1974 {
"SSL_get_servername", NULL},
1975 {
"SSL_set_SSL_CTX", NULL},
1983 {
"ERR_error_string", NULL},
1984 {
"CONF_modules_unload", NULL},
1985 {
"X509_free", NULL},
1986 {
"X509_get_subject_name", NULL},
1987 {
"X509_get_issuer_name", NULL},
1988 {
"X509_NAME_oneline", NULL},
1989 {
"X509_get_serialNumber", NULL},
1990 {
"EVP_get_digestbyname", NULL},
1991 {
"EVP_Digest", NULL},
1993 {
"BN_bn2hex", NULL},
1994 {
"ASN1_INTEGER_to_BN", NULL},
1996 {
"CRYPTO_free", NULL},
2000#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
2001#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
2002#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
2003#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
2004#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
2005#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
2006#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
2007#define SSL_new (*(SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
2008#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
2009#define SSLv23_server_method (*(SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
2010#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
2011#define SSL_CTX_use_PrivateKey_file \
2012 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
2013#define SSL_CTX_use_certificate_file \
2014 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
2015#define SSL_CTX_set_default_passwd_cb \
2016 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
2017#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
2018#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
2019#define SSL_CTX_use_certificate_chain_file \
2020 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
2021#define SSLv23_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
2022#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
2023#define SSL_CTX_set_verify \
2024 (*(void (*)(SSL_CTX *, \
2026 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19] \
2028#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
2029#define SSL_CTX_load_verify_locations \
2030 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
2031#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
2032#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
2033#define SSL_get_peer_certificate (*(X509 * (*)(SSL *)) ssl_sw[24].ptr)
2034#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
2035#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *)) ssl_sw[26].ptr)
2036#define SSL_CIPHER_get_name \
2037 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
2038#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
2039#define SSL_CTX_set_session_id_context \
2040 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
2041#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
2042#define SSL_CTX_set_cipher_list \
2043 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
2044#define SSL_CTX_set_info_callback \
2045 (*(void (*)(SSL_CTX *, void (*callback)(const SSL *, int, int)))ssl_sw[32] \
2047#define SSL_get_ex_data (*(char *(*)(const SSL *, int))ssl_sw[33].ptr)
2048#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
2049#define SSL_CTX_callback_ctrl \
2050 (*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
2051#define SSL_get_servername \
2052 (*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
2053#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *)) ssl_sw[37].ptr)
2054#define SSL_ctrl (*(long (*)(SSL *, int, long, void *))ssl_sw[38].ptr)
2056#define SSL_CTX_set_options(ctx, op) \
2057 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
2058#define SSL_CTX_clear_options(ctx, op) \
2059 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
2060#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
2061 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
2063#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
2064#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
2065#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
2066#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
2067 SSL_CTX_callback_ctrl(ctx, \
2068 SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
2070#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
2071 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg)
2072#define SSL_set_tlsext_host_name(ctx, arg) \
2073 SSL_ctrl(ctx, SSL_CTRL_SET_TLSEXT_HOSTNAME, 0, (void *)arg)
2075#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
2076#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
2078#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
2079#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
2081#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
2082#define CRYPTO_set_locking_callback \
2083 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
2084#define CRYPTO_set_id_callback \
2085 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
2086#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
2087#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
2088#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
2089#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
2090#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
2091#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
2092#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
2093#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
2094#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr)
2095#define X509_get_subject_name (*(X509_NAME * (*)(X509 *)) crypto_sw[12].ptr)
2096#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *)) crypto_sw[13].ptr)
2097#define X509_NAME_oneline \
2098 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
2099#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *)) crypto_sw[15].ptr)
2100#define i2c_ASN1_INTEGER \
2101 (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
2102#define EVP_get_digestbyname \
2103 (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
2106 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
2109#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
2110#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr)
2111#define ASN1_INTEGER_to_BN \
2112 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn)) crypto_sw[21].ptr)
2113#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr)
2114#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr)
2116#define OPENSSL_free(a) CRYPTO_free(a)
2121#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_state(0)
2128 {
"SSL_accept", NULL},
2129 {
"SSL_connect", NULL},
2131 {
"SSL_write", NULL},
2132 {
"SSL_get_error", NULL},
2133 {
"SSL_set_fd", NULL},
2135 {
"SSL_CTX_new", NULL},
2136 {
"SSLv23_server_method", NULL},
2137 {
"SSL_library_init", NULL},
2138 {
"SSL_CTX_use_PrivateKey_file", NULL},
2139 {
"SSL_CTX_use_certificate_file", NULL},
2140 {
"SSL_CTX_set_default_passwd_cb", NULL},
2141 {
"SSL_CTX_free", NULL},
2142 {
"SSL_load_error_strings", NULL},
2143 {
"SSL_CTX_use_certificate_chain_file", NULL},
2144 {
"SSLv23_client_method", NULL},
2145 {
"SSL_pending", NULL},
2146 {
"SSL_CTX_set_verify", NULL},
2147 {
"SSL_shutdown", NULL},
2148 {
"SSL_CTX_load_verify_locations", NULL},
2149 {
"SSL_CTX_set_default_verify_paths", NULL},
2150 {
"SSL_CTX_set_verify_depth", NULL},
2151 {
"SSL_get_peer_certificate", NULL},
2152 {
"SSL_get_version", NULL},
2153 {
"SSL_get_current_cipher", NULL},
2154 {
"SSL_CIPHER_get_name", NULL},
2155 {
"SSL_CTX_check_private_key", NULL},
2156 {
"SSL_CTX_set_session_id_context", NULL},
2157 {
"SSL_CTX_ctrl", NULL},
2158 {
"SSL_CTX_set_cipher_list", NULL},
2159 {
"SSL_CTX_set_info_callback", NULL},
2160 {
"SSL_get_ex_data", NULL},
2161 {
"SSL_set_ex_data", NULL},
2162 {
"SSL_CTX_callback_ctrl", NULL},
2163 {
"SSL_get_servername", NULL},
2164 {
"SSL_set_SSL_CTX", NULL},
2172 {
"CRYPTO_set_locking_callback", NULL},
2173 {
"CRYPTO_set_id_callback", NULL},
2174 {
"ERR_get_error", NULL},
2175 {
"ERR_error_string", NULL},
2176 {
"ERR_remove_state", NULL},
2177 {
"ERR_free_strings", NULL},
2178 {
"ENGINE_cleanup", NULL},
2179 {
"CONF_modules_unload", NULL},
2180 {
"CRYPTO_cleanup_all_ex_data", NULL},
2181 {
"EVP_cleanup", NULL},
2182 {
"X509_free", NULL},
2183 {
"X509_get_subject_name", NULL},
2184 {
"X509_get_issuer_name", NULL},
2185 {
"X509_NAME_oneline", NULL},
2186 {
"X509_get_serialNumber", NULL},
2187 {
"i2c_ASN1_INTEGER", NULL},
2188 {
"EVP_get_digestbyname", NULL},
2189 {
"EVP_Digest", NULL},
2191 {
"BN_bn2hex", NULL},
2192 {
"ASN1_INTEGER_to_BN", NULL},
2194 {
"CRYPTO_free", NULL},
2201#if !defined(NO_CACHING)
2222#if defined(USE_IPV6)
2223 struct sockaddr_in6 sin6;
2252#if defined(MG_USE_OPEN_FILE)
2267#if defined(MG_USE_OPEN_FILE)
2269#define STRUCT_FILE_INITIALIZER \
2271 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
2273 (FILE *)NULL, (const char *)NULL \
2279#define STRUCT_FILE_INITIALIZER \
2281 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
2317#if defined(__linux__)
2318 ALLOW_SENDFILE_CALL,
2321 CASE_SENSITIVE_FILES,
2329#if defined(USE_WEBSOCKET)
2331 ENABLE_WEBSOCKET_PING_PONG,
2335 LUA_BACKGROUND_SCRIPT,
2336 LUA_BACKGROUND_SCRIPT_PARAMS,
2338#if defined(USE_TIMERS)
2372 LUA_SCRIPT_EXTENSIONS,
2373 LUA_SERVER_PAGE_EXTENSIONS,
2374#if defined(MG_EXPERIMENTAL_INTERFACES)
2378#if defined(USE_DUKTAPE)
2379 DUKTAPE_SCRIPT_EXTENSIONS,
2382#if defined(USE_WEBSOCKET)
2385#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2386 LUA_WEBSOCKET_EXTENSIONS,
2393#if !defined(NO_CACHING)
2418#if defined(__linux__)
2430#if defined(USE_WEBSOCKET)
2439#if defined(USE_TIMERS)
2458 "index.xhtml,index.html,index.htm,"
2459 "index.lp,index.lsp,index.lua,index.cgi,"
2460 "index.shtml,index.php"},
2462 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2485#if defined(MG_EXPERIMENTAL_INTERFACES)
2489#if defined(USE_DUKTAPE)
2495#if defined(USE_WEBSOCKET)
2498#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2505#if !defined(NO_CACHING)
2521 "config_options and enum not sync");
2579#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2581 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2607#if defined(USE_SERVER_STATS)
2608 int active_connections;
2609 int max_connections;
2610 int64_t total_connections;
2611 int64_t total_requests;
2612 int64_t total_data_read;
2613 int64_t total_data_written;
2626#if defined(ALTERNATIVE_QUEUE)
2631 volatile int sq_head;
2632 volatile int sq_tail;
2640#if defined(USE_SERVER_STATS)
2641 struct mg_memory_stat ctx_memory;
2649#if defined(USE_TIMERS)
2650 struct ttimers *timers;
2655 void *lua_background_state;
2676#if defined(USE_SERVER_STATS)
2677static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2679static struct mg_memory_stat *
2683 return &(ctx->ctx_memory);
2685 return &mg_common_memory;
2704#if defined(USE_SERVER_STATS)
2735#if defined(USE_WEBSOCKET)
2736 int in_websocket_handling;
2751#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2752 void *lua_websocket_state;
2767#if defined(USE_WEBSOCKET)
2770#define is_websocket_protocol(conn) (0)
2774#define mg_cry_internal(conn, fmt, ...) \
2775 mg_cry_internal_wrap(conn, __func__, __LINE__, fmt, __VA_ARGS__)
2784#if !defined(NO_THREAD_NAME)
2785#if defined(_WIN32) && defined(_MSC_VER)
2789#pragma pack(push, 8)
2790typedef struct tagTHREADNAME_INFO {
2798#elif defined(__linux__)
2800#include <sys/prctl.h>
2801#include <sys/sendfile.h>
2802#if defined(ALTERNATIVE_QUEUE)
2803#include <sys/eventfd.h>
2807#if defined(ALTERNATIVE_QUEUE)
2812 int evhdl = eventfd(0, EFD_CLOEXEC);
2842 evhdl = *(
int *)eventhdl;
2844 s = (
int)read(evhdl, &u,
sizeof(u));
2845 if (s !=
sizeof(u)) {
2864 evhdl = *(
int *)eventhdl;
2866 s = (
int)write(evhdl, &u,
sizeof(u));
2867 if (s !=
sizeof(u)) {
2884 evhdl = *(
int *)eventhdl;
2896#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
2912 if (0 != pthread_mutex_init(&(ret->
mutex), NULL)) {
2917 if (0 != pthread_cond_init(&(ret->
cond), NULL)) {
2919 pthread_mutex_destroy(&(ret->
mutex));
2931 pthread_mutex_lock(&(ev->
mutex));
2932 pthread_cond_wait(&(ev->
cond), &(ev->
mutex));
2933 pthread_mutex_unlock(&(ev->
mutex));
2942 pthread_mutex_lock(&(ev->
mutex));
2943 pthread_cond_signal(&(ev->
cond));
2944 pthread_mutex_unlock(&(ev->
mutex));
2953 pthread_cond_destroy(&(ev->
cond));
2954 pthread_mutex_destroy(&(ev->
mutex));
2963 char threadName[16 + 1];
2966 NULL, NULL, threadName,
sizeof(threadName),
"civetweb-%s",
name);
2969#if defined(_MSC_VER)
2972 THREADNAME_INFO info;
2973 info.dwType = 0x1000;
2974 info.szName = threadName;
2975 info.dwThreadID = ~0U;
2978 RaiseException(0x406D1388,
2980 sizeof(info) /
sizeof(ULONG_PTR),
2981 (ULONG_PTR *)&info);
2982 } __except (EXCEPTION_EXECUTE_HANDLER) {
2984#elif defined(__MINGW32__)
2987#elif defined(_GNU_SOURCE) && defined(__GLIBC__) \
2988 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
2990#if defined(__MACH__)
2992 (
void)pthread_setname_np(threadName);
2994 (
void)pthread_setname_np(pthread_self(), threadName);
2996#elif defined(__linux__)
2998 (
void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
3009#if defined(MG_LEGACY_INTERFACE)
3011mg_get_valid_option_names(
void)
3036#define MG_FOPEN_MODE_NONE (0)
3039#define MG_FOPEN_MODE_READ (1)
3042#define MG_FOPEN_MODE_WRITE (2)
3045#define MG_FOPEN_MODE_APPEND (4)
3057#if defined(MG_USE_OPEN_FILE)
3060 const char *buf = NULL;
3072 if (filep == NULL) {
3083 filep->
access.membuf = buf;
3098 return (buf != NULL);
3126#if defined(MG_USE_OPEN_FILE)
3127 return (fileacc->membuf != NULL) || (fileacc->
fp != NULL);
3129 return (fileacc->
fp != NULL);
3157#if defined(MG_USE_OPEN_FILE)
3158 filep->
access.membuf = NULL;
3174 wchar_t wbuf[W_PATH_MAX];
3175 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
3178 filep->
access.
fp = _wfopen(wbuf, L
"rb");
3181 filep->
access.
fp = _wfopen(wbuf, L
"wb");
3184 filep->
access.
fp = _wfopen(wbuf, L
"ab");
3192 filep->
access.
fp = fopen(path,
"r");
3195 filep->
access.
fp = fopen(path,
"w");
3198 filep->
access.
fp = fopen(path,
"a");
3215#if defined(MG_USE_OPEN_FILE)
3219 return (filep->
access.membuf != NULL);
3234 if (fileacc != NULL) {
3235 if (fileacc->
fp != NULL) {
3236 ret = fclose(fileacc->
fp);
3237#if defined(MG_USE_OPEN_FILE)
3238 }
else if (fileacc->membuf != NULL) {
3243 memset(fileacc, 0,
sizeof(*fileacc));
3252 for (; *src !=
'\0' &&
n > 1;
n--) {
3262 return tolower(*(
const unsigned char *)s);
3274 }
while (diff == 0 &&
s1[-1] !=
'\0' && --len > 0);
3288 }
while (diff == 0 &&
s1[-1] !=
'\0');
3325 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3327 if (big_len >= small_len) {
3328 for (i = 0; i <= (big_len - small_len); i++) {
3358#if defined(__clang__)
3359#pragma clang diagnostic push
3360#pragma clang diagnostic ignored "-Wformat-nonliteral"
3366 ok = (
n >= 0) && ((
size_t)
n < buflen);
3368#if defined(__clang__)
3369#pragma clang diagnostic pop
3381 "truncating vsnprintf buffer: [%.*s]",
3382 (
int)((buflen > 200) ? 200 : (buflen - 1)),
3384 n = (
int)buflen - 1;
3426 }
else if (!ctx || ctx->
dd.
config[i] == NULL) {
3433#define mg_get_option DO_NOT_USE_THIS_FUNCTION_INTERNALLY__access_directly
3445 return (ctx == NULL) ? NULL : ctx->
user_data;
3468#if defined(MG_LEGACY_INTERFACE)
3471mg_get_ports(
const struct mg_context *ctx,
size_t size,
int *ports,
int *ssl)
3480#if defined(USE_IPV6)
3502 memset(ports, 0,
sizeof(*ports) * (
size_t)
size);
3513#if defined(USE_IPV6)
3546 if (
usa->
sa.sa_family == AF_INET) {
3547 getnameinfo(&
usa->
sa,
3555#if defined(USE_IPV6)
3556 else if (
usa->
sa.sa_family == AF_INET6) {
3557 getnameinfo(&
usa->
sa,
3574#if !defined(REENTRANT_TIME)
3577 tm = ((t != NULL) ? gmtime(t) : NULL);
3581 struct tm *tm = &_tm;
3586 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", tm);
3588 mg_strlcpy(buf,
"Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3589 buf[buf_len - 1] =
'\0';
3598 return (
double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3599 + (
double)(ts_now->tv_sec - ts_before->tv_sec);
3603#if defined(MG_EXTERNAL_FUNCTION_mg_cry_internal_impl)
3609#include "external_mg_cry_internal_impl.inl"
3628#if defined(GCC_DIAGNOSTIC)
3629#pragma GCC diagnostic push
3630#pragma GCC diagnostic ignored "-Wformat-nonliteral"
3635#if defined(GCC_DIAGNOSTIC)
3636#pragma GCC diagnostic pop
3639 buf[
sizeof(buf) - 1] = 0;
3668 timestamp = time(NULL);
3672 "[%010lu] [error] [client %s] ",
3673 (
unsigned long)timestamp,
3722#define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
3733 return &fake_connection;
3750#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3757 if (strlen(txt) == 3) {
3758 memcpy(tls->txtbuf, txt, 4);
3760 strcpy(tls->txtbuf,
"ERR");
3797#if defined(__clang__)
3798#pragma clang diagnostic push
3799#pragma clang diagnostic ignored "-Wunreachable-code"
3811 : (ri->
is_ssl ?
"https" :
"http"));
3815#if defined(__clang__)
3816#pragma clang diagnostic pop
3824 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3859#if defined(USE_IPV6)
3860 int is_ipv6 = (conn->
client.
lsa.
sa.sa_family == AF_INET6);
3861 int port = is_ipv6 ? htons(conn->
client.
lsa.sin6.sin6_port)
3866 int def_port = ri->
is_ssl ? 443 : 80;
3867 int auth_domain_check_enabled =
3871 const char *server_domain =
3877 if (port != def_port) {
3878 sprintf(portstr,
":%u", (
unsigned)port);
3883 if (!auth_domain_check_enabled || !server_domain) {
3889 server_domain = server_ip;
3916 const char *delimiters,
3917 const char *whitespace,
3920 char *p, *begin_word, *end_word, *end_whitespace;
3923 end_word = begin_word + strcspn(begin_word, delimiters);
3926 if (end_word > begin_word) {
3928 while (*p == quotechar) {
3935 if (*end_word !=
'\0') {
3936 size_t end_off = strcspn(end_word + 1, delimiters);
3937 memmove(p, end_word, end_off + 1);
3939 end_word += end_off + 1;
3945 for (p++; p < end_word; p++) {
3950 if (*end_word ==
'\0') {
3954#if defined(GCC_DIAGNOSTIC)
3956#pragma GCC diagnostic push
3957#pragma GCC diagnostic ignored "-Wsign-conversion"
3960 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3962#if defined(GCC_DIAGNOSTIC)
3963#pragma GCC diagnostic pop
3966 for (p = end_word; p < end_whitespace; p++) {
3970 *buf = end_whitespace;
3982 for (i = 0; i < num_hdr; i++) {
3984 return hdr[i].
value;
3992#if defined(USE_WEBSOCKET)
3999 int output_max_size)
4065 if (val == NULL || list == NULL || *list ==
'\0') {
4071 while (*list ==
' ' || *list ==
'\t')
4075 if ((list = strchr(val->
ptr,
',')) != NULL) {
4077 val->
len = ((size_t)(list - val->
ptr));
4081 list = val->
ptr + strlen(val->
ptr);
4082 val->
len = ((size_t)(list - val->
ptr));
4087 while (end >= 0 && ((val->
ptr[end] ==
' ') || (val->
ptr[end] ==
'\t')))
4089 val->
len = (size_t)(end + 1);
4091 if (val->
len == 0) {
4096 if (eq_val != NULL) {
4100 eq_val->
ptr = (
const char *)memchr(val->
ptr,
'=', val->
len);
4101 if (eq_val->
ptr != NULL) {
4103 eq_val->
len = ((size_t)(val->
ptr - eq_val->
ptr)) + val->
len;
4104 val->
len = ((size_t)(eq_val->
ptr - val->
ptr)) - 1;
4125 while ((header =
next_option(header, &opt_vec, &eq_vec)) != NULL) {
4139 ptrdiff_t i, j,
len, res;
4141 if ((or_str = (
const char *)memchr(pattern,
'|', pattern_len)) != NULL) {
4142 res =
match_prefix(pattern, (
size_t)(or_str - pattern), str);
4143 return (res > 0) ? res
4145 (
size_t)((pattern + pattern_len)
4150 for (i = 0, j = 0; (i < (ptrdiff_t)pattern_len); i++, j++) {
4151 if ((pattern[i] ==
'?') && (str[j] !=
'\0')) {
4153 }
else if (pattern[i] ==
'$') {
4154 return (str[j] ==
'\0') ? j : -1;
4155 }
else if (pattern[i] ==
'*') {
4157 if (pattern[i] ==
'*') {
4159 len = strlen(str + j);
4161 len = strcspn(str + j,
"/");
4163 if (i == (ptrdiff_t)pattern_len) {
4168 }
while (res == -1 &&
len-- > 0);
4169 return (res == -1) ? -1 : j + res +
len;
4174 return (ptrdiff_t)j;
4184 const char *http_version;
4210 if (http_version && (0 == strcmp(http_version,
"1.1"))) {
4223 if (!conn || !conn->
dom_ctx) {
4243 "Cache-Control: no-cache, no-store, "
4244 "must-revalidate, private, max-age=0\r\n"
4245 "Pragma: no-cache\r\n"
4253#if !defined(NO_CACHING)
4274 return mg_printf(conn,
"Cache-Control: max-age=%u\r\n", (
unsigned)max_age);
4292 "Strict-Transport-Security: max-age=%u\r\n",
4298 if (header && header[0]) {
4318 switch (response_code) {
4323 return "Switching Protocols";
4325 return "Processing";
4335 return "Non-Authoritative Information";
4337 return "No Content";
4339 return "Reset Content";
4341 return "Partial Content";
4343 return "Multi-Status";
4346 return "Already Reported";
4353 return "Multiple Choices";
4355 return "Moved Permanently";
4361 return "Not Modified";
4365 return "Temporary Redirect";
4367 return "Permanent Redirect";
4371 return "Bad Request";
4373 return "Unauthorized";
4375 return "Payment Required";
4381 return "Method Not Allowed";
4383 return "Not Acceptable";
4385 return "Proxy Authentication Required";
4387 return "Request Time-out";
4393 return "Length Required";
4395 return "Precondition Failed";
4397 return "Request Entity Too Large";
4399 return "Request-URI Too Large";
4401 return "Unsupported Media Type";
4403 return "Requested range not satisfiable";
4406 return "Expectation Failed";
4409 return "Misdirected Request";
4411 return "Unproccessable entity";
4416 return "Failed Dependency";
4420 return "Upgrade Required";
4423 return "Precondition Required";
4425 return "Too Many Requests";
4428 return "Request Header Fields Too Large";
4431 return "Unavailable For Legal Reasons";
4436 return "Internal Server Error";
4438 return "Not Implemented";
4440 return "Bad Gateway";
4442 return "Service Unavailable";
4444 return "Gateway Time-out";
4446 return "HTTP Version not supported";
4448 return "Variant Also Negotiates";
4450 return "Insufficient Storage";
4453 return "Loop Detected";
4456 return "Not Extended";
4458 return "Network Authentication Required";
4464 return "I am a teapot";
4466 return "Authentication Timeout";
4468 return "Enhance Your Calm";
4470 return "Login Timeout";
4472 return "Bandwidth Limit Exceeded";
4478 "Unknown HTTP response code: %u",
4483 if (response_code >= 100 && response_code < 200) {
4485 return "Information";
4487 if (response_code >= 200 && response_code < 300) {
4491 if (response_code >= 300 && response_code < 400) {
4493 return "Redirection";
4495 if (response_code >= 400 && response_code < 500) {
4497 return "Client Error";
4499 if (response_code >= 500 && response_code < 600) {
4501 return "Server Error";
4517 char path_buf[PATH_MAX];
4519 int len, i, page_handler_found, scope, truncated, has_body;
4521 time_t curtime = time(NULL);
4522 const char *error_handler = NULL;
4524 const char *error_page_file_ext, *tstr;
4525 int handled_by_callback = 0;
4529 if ((conn == NULL) || (fmt == NULL)) {
4537 has_body = ((status > 199) && (status != 204) && (status != 304));
4545 mg_vsnprintf(conn, NULL, errmsg_buf,
sizeof(errmsg_buf), fmt, ap);
4548 DEBUG_TRACE(
"Error %i - [%s]", status, errmsg_buf);
4558 handled_by_callback =
4564 if (!handled_by_callback) {
4568 "Recursion when handling error %u - fall back to default",
4574 page_handler_found = 0;
4576 if (error_handler != NULL) {
4577 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4583 sizeof(path_buf) - 32,
4594 sizeof(path_buf) - 32,
4603 sizeof(path_buf) - 32,
4614 len = (
int)strlen(path_buf);
4616 tstr = strchr(error_page_file_ext,
'.');
4620 (i < 32) && (tstr[i] != 0) && (tstr[i] !=
',');
4625 path_buf[len + i - 1] = tstr[i];
4630 path_buf[len + i - 1] = 0;
4632 if (
mg_stat(conn, path_buf, &error_page_file.
stat)) {
4635 page_handler_found = 1;
4641 tstr = strchr(tstr + i,
'.');
4646 if (page_handler_found) {
4658 mg_printf(conn,
"HTTP/1.1 %d %s\r\n", status, status_text);
4664 "Content-Type: text/plain; charset=utf-8\r\n");
4668 "Connection: close\r\n\r\n",
4674 mg_printf(conn,
"Error %d: %s\n", status, status_text);
4675 mg_write(conn, errmsg_buf, strlen(errmsg_buf));
4703 long long content_length)
4706 time_t curtime = time(NULL);
4716 "HTTP/1.1 200 OK\r\n"
4717 "Content-Type: %s\r\n"
4719 "Connection: %s\r\n",
4726 if (content_length < 0) {
4727 mg_printf(conn,
"Transfer-Encoding: chunked\r\n\r\n");
4731 (uint64_t)content_length);
4740 const char *target_url,
4754 const char *redirect_text;
4756 size_t content_len = 0;
4760 if (redirect_code == 0) {
4761 redirect_code = 307;
4765 if ((redirect_code != 301) && (redirect_code != 302)
4766 && (redirect_code != 303) && (redirect_code != 307)
4767 && (redirect_code != 308)) {
4776 if ((target_url == NULL) || (*target_url == 0)) {
4780#if defined(MG_SEND_REDIRECT_BODY)
4808 "<html><head>%s</head><body><a href=\"%s\">%s</a></body></html>",
4812 content_len = strlen(reply);
4820 "HTTP/1.1 %i %s\r\n"
4822 "Content-Length: %u\r\n"
4823 "Connection: %s\r\n\r\n",
4827 (
unsigned int)content_len,
4834 ret =
mg_write(conn, reply, content_len);
4838 return (ret > 0) ? ret : -1;
4845#if defined(GCC_DIAGNOSTIC)
4847#pragma GCC diagnostic push
4848#pragma GCC diagnostic ignored "-Wunused-function"
4854pthread_mutex_init(pthread_mutex_t *mutex,
void *unused)
4857 *mutex = CreateMutex(NULL,
FALSE, NULL);
4858 return (*mutex == NULL) ? -1 : 0;
4863pthread_mutex_destroy(pthread_mutex_t *mutex)
4865 return (CloseHandle(*mutex) == 0) ? -1 : 0;
4871pthread_mutex_lock(pthread_mutex_t *mutex)
4873 return (WaitForSingleObject(*mutex, (DWORD)INFINITE) == WAIT_OBJECT_0) ? 0
4878#if defined(ENABLE_UNUSED_PTHREAD_FUNCTIONS)
4881pthread_mutex_trylock(pthread_mutex_t *mutex)
4883 switch (WaitForSingleObject(*mutex, 0)) {
4896pthread_mutex_unlock(pthread_mutex_t *mutex)
4898 return (ReleaseMutex(*mutex) == 0) ? -1 : 0;
4907 InitializeCriticalSection(&cv->threadIdSec);
4908 cv->waiting_thread = NULL;
4916 pthread_mutex_t *mutex,
4922 int64_t nsnow, nswaitabs, nswaitrel;
4925 EnterCriticalSection(&cv->threadIdSec);
4927 ptls = &cv->waiting_thread;
4928 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
4930 tls->next_waiting_thread = NULL;
4932 LeaveCriticalSection(&cv->threadIdSec);
4937 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4938 nswaitrel = nswaitabs - nsnow;
4939 if (nswaitrel < 0) {
4942 mswaitrel = (DWORD)(nswaitrel / 1000000);
4944 mswaitrel = (DWORD)INFINITE;
4947 pthread_mutex_unlock(mutex);
4949 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
4952 EnterCriticalSection(&cv->threadIdSec);
4953 ptls = &cv->waiting_thread;
4954 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
4956 *ptls = tls->next_waiting_thread;
4961 LeaveCriticalSection(&cv->threadIdSec);
4963 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4968 pthread_mutex_lock(mutex);
4978 return pthread_cond_timedwait(cv, mutex, NULL);
4989 EnterCriticalSection(&cv->threadIdSec);
4990 if (cv->waiting_thread) {
4991 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4992 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
4994 ok = SetEvent(wkup);
4997 LeaveCriticalSection(&cv->threadIdSec);
5007 EnterCriticalSection(&cv->threadIdSec);
5008 while (cv->waiting_thread) {
5009 pthread_cond_signal(cv);
5011 LeaveCriticalSection(&cv->threadIdSec);
5021 EnterCriticalSection(&cv->threadIdSec);
5023 LeaveCriticalSection(&cv->threadIdSec);
5024 DeleteCriticalSection(&cv->threadIdSec);
5030#if defined(ALTERNATIVE_QUEUE)
5035 return (
void *)CreateEvent(NULL,
FALSE,
FALSE, NULL);
5043 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
5044 return (res == WAIT_OBJECT_0);
5052 return (
int)SetEvent((HANDLE)eventhdl);
5060 CloseHandle((HANDLE)eventhdl);
5065#if defined(GCC_DIAGNOSTIC)
5067#pragma GCC diagnostic pop
5073change_slashes_to_backslashes(
char *path)
5077 for (i = 0; path[i] !=
'\0'; i++) {
5078 if (path[i] ==
'/') {
5084 if ((path[i] ==
'\\') && (i > 0)) {
5085 while ((path[i + 1] ==
'\\') || (path[i + 1] ==
'/')) {
5086 (
void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
5094mg_wcscasecmp(
const wchar_t *
s1,
const wchar_t *s2)
5099 diff = tolower(*
s1) - tolower(*s2);
5102 }
while ((diff == 0) && (
s1[-1] !=
'\0'));
5116 char buf[PATH_MAX], buf2[PATH_MAX];
5117 wchar_t wbuf2[W_PATH_MAX + 1];
5118 DWORD long_len, err;
5119 int (*fcompare)(
const wchar_t *,
const wchar_t *) = mg_wcscasecmp;
5122 change_slashes_to_backslashes(buf);
5126 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
5127 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int)wbuf_len);
5128 WideCharToMultiByte(
5129 CP_UTF8, 0, wbuf, (
int)wbuf_len, buf2,
sizeof(buf2), NULL, NULL);
5130 if (strcmp(buf, buf2) != 0) {
5153#if !defined(_WIN32_WCE)
5155 memset(wbuf2, 0,
ARRAY_SIZE(wbuf2) *
sizeof(
wchar_t));
5156 long_len = GetLongPathNameW(wbuf, wbuf2,
ARRAY_SIZE(wbuf2) - 1);
5157 if (long_len == 0) {
5158 err = GetLastError();
5159 if (err == ERROR_FILE_NOT_FOUND) {
5164 if ((long_len >=
ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
5173 if (strchr(path,
'~')) {
5185path_cannot_disclose_cgi(
const char *path)
5187 static const char *allowed_last_characters =
"_-";
5188 int last = path[strlen(path) - 1];
5189 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
5198 wchar_t wbuf[W_PATH_MAX];
5199 WIN32_FILE_ATTRIBUTE_DATA info;
5200 time_t creation_time;
5205 memset(filep, 0,
sizeof(*filep));
5236 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5237 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
5238 filep->
size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
5240 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
5241 info.ftLastWriteTime.dwHighDateTime);
5247 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
5248 info.ftCreationTime.dwHighDateTime);
5253 filep->
is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
5258 if (!filep->
is_directory && !path_cannot_disclose_cgi(path)) {
5259 memset(filep, 0,
sizeof(*filep));
5273 wchar_t wbuf[W_PATH_MAX];
5274 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5275 return DeleteFileW(wbuf) ? 0 : -1;
5282 wchar_t wbuf[W_PATH_MAX];
5284 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5285 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
5291#if defined(GCC_DIAGNOSTIC)
5293#pragma GCC diagnostic push
5294#pragma GCC diagnostic ignored "-Wunused-function"
5304 wchar_t wpath[W_PATH_MAX];
5308 SetLastError(ERROR_BAD_ARGUMENTS);
5309 }
else if ((dir = (DIR *)
mg_malloc(
sizeof(*dir))) == NULL) {
5310 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5313 attrs = GetFileAttributesW(wpath);
5314 if ((wcslen(wpath) + 2 <
ARRAY_SIZE(wpath)) && (attrs != 0xFFFFFFFF)
5315 && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
5316 (
void)wcscat(wpath, L
"\\*");
5317 dir->handle = FindFirstFileW(wpath, &dir->info);
5318 dir->result.d_name[0] =
'\0';
5337 result = FindClose(dir->handle) ? 0 : -1;
5342 SetLastError(ERROR_BAD_ARGUMENTS);
5350static struct dirent *
5353 struct dirent *result = 0;
5357 result = &dir->result;
5358 (
void)WideCharToMultiByte(CP_UTF8,
5360 dir->info.cFileName,
5363 sizeof(result->d_name),
5367 if (!FindNextFileW(dir->handle, &dir->info)) {
5368 (
void)FindClose(dir->handle);
5373 SetLastError(ERROR_FILE_NOT_FOUND);
5376 SetLastError(ERROR_BAD_ARGUMENTS);
5383#if !defined(HAVE_POLL)
5390poll(
struct pollfd *pfd,
unsigned int n,
int milliseconds)
5399 memset(&tv, 0,
sizeof(tv));
5400 tv.tv_sec = milliseconds / 1000;
5401 tv.tv_usec = (milliseconds % 1000) * 1000;
5405 for (i = 0; i <
n; i++) {
5406 if (pfd[i].events & POLLIN) {
5407 FD_SET((
SOCKET)pfd[i].fd, &rset);
5408 }
else if (pfd[i].events & POLLOUT) {
5409 FD_SET((
SOCKET)pfd[i].fd, &wset);
5413 if (pfd[i].fd > maxfd) {
5418 if ((result = select((
int)maxfd + 1, &rset, &wset, NULL, &tv)) > 0) {
5419 for (i = 0; i <
n; i++) {
5420 if (FD_ISSET(pfd[i].fd, &rset)) {
5421 pfd[i].revents |= POLLIN;
5423 if (FD_ISSET(pfd[i].fd, &wset)) {
5424 pfd[i].revents |= POLLOUT;
5441#if defined(GCC_DIAGNOSTIC)
5443#pragma GCC diagnostic pop
5451#if defined(_WIN32_WCE)
5454 (
void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
5462#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5466 return ((_beginthread((
void(__cdecl *)(
void *))
f, USE_STACK_SIZE, p)
5467 == ((uintptr_t)(-1L)))
5472 (_beginthread((
void(__cdecl *)(
void *))
f, 0, p) == ((uintptr_t)(-1L)))
5483 pthread_t *threadidptr)
5486 HANDLE threadhandle;
5489 uip = _beginthreadex(NULL, 0, (
unsigned(__stdcall *)(
void *))
f, p, 0, NULL);
5490 threadhandle = (HANDLE)uip;
5491 if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
5492 *threadidptr = threadhandle;
5508 dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE);
5509 if (dwevent == WAIT_FAILED) {
5512 if (dwevent == WAIT_OBJECT_0) {
5513 CloseHandle(threadid);
5521#if !defined(NO_SSL_DL) && !defined(NO_SSL)
5525#if defined(GCC_DIAGNOSTIC)
5527#pragma GCC diagnostic push
5528#pragma GCC diagnostic ignored "-Wunused-function"
5534dlopen(
const char *dll_name,
int flags)
5536 wchar_t wbuf[W_PATH_MAX];
5538 path_to_unicode(NULL, dll_name, wbuf,
ARRAY_SIZE(wbuf));
5539 return LoadLibraryW(wbuf);
5545dlclose(
void *handle)
5549 if (FreeLibrary((HMODULE)handle) != 0) {
5559#if defined(GCC_DIAGNOSTIC)
5561#pragma GCC diagnostic pop
5572kill(pid_t pid,
int sig_num)
5574 (
void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
5575 (
void)CloseHandle((HANDLE)pid);
5580#if !defined(WNOHANG)
5586waitpid(pid_t pid,
int *status,
int flags)
5588 DWORD timeout = INFINITE;
5593 if ((flags | WNOHANG) == WNOHANG) {
5597 waitres = WaitForSingleObject((HANDLE)pid, timeout);
5598 if (waitres == WAIT_OBJECT_0) {
5601 if (waitres == WAIT_TIMEOUT) {
5609trim_trailing_whitespaces(
char *s)
5611 char *
e = s + strlen(s) - 1;
5612 while ((
e > s) && isspace(*(
unsigned char *)
e)) {
5629 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
5630 cmdline[PATH_MAX], buf[PATH_MAX];
5634 PROCESS_INFORMATION pi = {0};
5638 memset(&si, 0,
sizeof(si));
5641 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5642 si.wShowWindow = SW_HIDE;
5644 me = GetCurrentProcess();
5646 (HANDLE)_get_osfhandle(fdin[0]),
5651 DUPLICATE_SAME_ACCESS);
5653 (HANDLE)_get_osfhandle(fdout[1]),
5658 DUPLICATE_SAME_ACCESS);
5660 (HANDLE)_get_osfhandle(fderr[1]),
5665 DUPLICATE_SAME_ACCESS);
5670 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5671 HANDLE_FLAG_INHERIT,
5673 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5674 HANDLE_FLAG_INHERIT,
5676 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5677 HANDLE_FLAG_INHERIT,
5682 if (interp == NULL) {
5683 buf[0] = buf[1] =
'\0';
5687 conn, &truncated, cmdline,
sizeof(cmdline),
"%s/%s", dir, prog);
5690 pi.hProcess = (pid_t)-1;
5695#if defined(MG_USE_OPEN_FILE)
5696 p = (
char *)
file.access.membuf;
5702 buf[
sizeof(buf) - 1] =
'\0';
5705 if ((buf[0] ==
'#') && (buf[1] ==
'!')) {
5706 trim_trailing_whitespaces(buf + 2);
5713 if (interp[0] !=
'\0') {
5714 GetFullPathNameA(interp,
sizeof(full_interp), full_interp, NULL);
5715 interp = full_interp;
5717 GetFullPathNameA(dir,
sizeof(full_dir), full_dir, NULL);
5719 if (interp[0] !=
'\0') {
5724 "\"%s\" \"%s\\%s\"",
5739 pi.hProcess = (pid_t)-1;
5744 if (CreateProcessA(NULL,
5749 CREATE_NEW_PROCESS_GROUP,
5756 conn,
"%s: CreateProcess(%s): %ld", __func__, cmdline, (
long)
ERRNO);
5757 pi.hProcess = (pid_t)-1;
5762 (
void)CloseHandle(si.hStdOutput);
5763 (
void)CloseHandle(si.hStdError);
5764 (
void)CloseHandle(si.hStdInput);
5765 if (pi.hThread != NULL) {
5766 (
void)CloseHandle(pi.hThread);
5769 return (pid_t)pi.hProcess;
5777 unsigned long non_blocking = 0;
5778 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5784 unsigned long non_blocking = 1;
5785 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5799 memset(filep, 0,
sizeof(*filep));
5815 if (0 ==
stat(path, &st)) {
5816 filep->
size = (uint64_t)(st.st_size);
5829 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5832 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5843 pthread_t thread_id;
5844 pthread_attr_t attr;
5847 (
void)pthread_attr_init(&attr);
5848 (
void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5850#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5853 (
void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5856 result = pthread_create(&thread_id, &attr, func, param);
5857 pthread_attr_destroy(&attr);
5867 pthread_t *threadidptr)
5869 pthread_t thread_id;
5870 pthread_attr_t attr;
5873 (
void)pthread_attr_init(&attr);
5875#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5878 (
void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5881 result = pthread_create(&thread_id, &attr, func, param);
5882 pthread_attr_destroy(&attr);
5883 if ((result == 0) && (threadidptr != NULL)) {
5884 *threadidptr = thread_id;
5896 result = pthread_join(threadid, NULL);
5921 if ((pid = fork()) == -1) {
5925 "Error: Creating CGI process\nfork(): %s",
5927 }
else if (pid == 0) {
5929 if (chdir(dir) != 0) {
5931 conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
5932 }
else if (dup2(fdin[0], 0) == -1) {
5934 "%s: dup2(%d, 0): %s",
5938 }
else if (dup2(fdout[1], 1) == -1) {
5940 "%s: dup2(%d, 1): %s",
5944 }
else if (dup2(fderr[1], 2) == -1) {
5946 "%s: dup2(%d, 2): %s",
5954 (
void)close(fdin[0]);
5955 (
void)close(fdout[1]);
5956 (
void)close(fderr[1]);
5959 (
void)close(fdin[1]);
5960 (
void)close(fdout[0]);
5961 (
void)close(fderr[0]);
5968 signal(SIGCHLD, SIG_DFL);
5971 if (interp == NULL) {
5972 (
void)execle(prog, prog, NULL, envp);
5974 "%s: execle(%s): %s",
5979 (
void)execle(interp, interp, prog, NULL, envp);
5981 "%s: execle(%s %s): %s",
5999 int flags = fcntl(sock, F_GETFL, 0);
6004 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
6013 int flags = fcntl(sock, F_GETFL, 0);
6018 if (fcntl(sock, F_SETFL, flags & (~(
int)(O_NONBLOCK))) < 0) {
6032 static uint64_t lfsr = 0;
6033 static uint64_t lcg = 0;
6044 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
6046 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
6054 return (lfsr ^ lcg ^ now);
6062 volatile int *stop_server)
6077 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
6078 ms_now = milliseconds;
6081 result = poll(pfd,
n, ms_now);
6089 if (milliseconds > 0) {
6090 milliseconds -= ms_now;
6093 }
while (milliseconds != 0);
6116 uint64_t start = 0, now = 0, timeout_ns = 0;
6123 typedef size_t len_t;
6129 timeout_ns = (uint64_t)(timeout * 1.0E9);
6166 n = (
int)fwrite(buf, 1, (
size_t)len, fp);
6175 err = (
n < 0) ?
ERRNO : 0;
6177 if (err == WSAEWOULDBLOCK) {
6182 if (err == EWOULDBLOCK) {
6197 if ((
n > 0) || ((
n == 0) && (len == 0))) {
6223 struct pollfd pfd[1];
6227 pfd[0].events = POLLOUT;
6239 if ((now - start) > timeout_ns) {
6261 double timeout = -1.0;
6262 int64_t
n, nwritten = 0;
6272 while ((len > 0) && (ctx->
stop_flag == 0)) {
6273 n =
push_inner(ctx, fp, sock, ssl, buf + nwritten, (
int)len, timeout);
6275 if (nwritten == 0) {
6279 }
else if (
n == 0) {
6309 typedef size_t len_t;
6321#if !defined(_WIN32_WCE)
6326 nread = (
int)read(fileno(fp), buf, (size_t)len);
6329 nread = (
int)fread(buf, 1, (
size_t)len, fp);
6331 err = (nread < 0) ?
ERRNO : 0;
6332 if ((nread == 0) && (len > 0)) {
6338 }
else if ((conn->
ssl != NULL)
6343 if (ssl_pending > len) {
6362 }
else if (conn->
ssl != NULL) {
6364 struct pollfd pfd[1];
6368 pfd[0].events = POLLIN;
6371 (
int)(timeout * 1000.0),
6393 }
else if (pollres < 0) {
6403 struct pollfd pfd[1];
6407 pfd[0].events = POLLIN;
6410 (
int)(timeout * 1000.0),
6417 err = (nread < 0) ?
ERRNO : 0;
6422 }
else if (pollres < 0) {
6435 if ((nread > 0) || ((nread == 0) && (len == 0))) {
6443 if (err == WSAEWOULDBLOCK) {
6447 }
else if (err == WSAETIMEDOUT) {
6451 }
else if (err == WSAECONNABORTED) {
6464 if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == EINTR)) {
6492 double timeout = -1.0;
6493 uint64_t start_time = 0, now = 0, timeout_ns = 0;
6498 if (timeout >= 0.0) {
6500 timeout_ns = (uint64_t)(timeout * 1.0E9);
6504 n =
pull_inner(fp, conn, buf + nread, len, timeout);
6510 }
else if (
n == -1) {
6512 if (timeout >= 0.0) {
6514 if ((now - start_time) <= timeout_ns) {
6519 }
else if (
n == 0) {
6543 to_read =
sizeof(buf);
6549 nread =
mg_read(conn, buf, to_read);
6563 nread =
mg_read(conn, buf, to_read);
6575 int64_t
n, buffered_len, nread;
6577 (int64_t)((len > INT_MAX) ? INT_MAX : len);
6605 if (left_to_read < len64) {
6609 len64 = left_to_read;
6615 if (buffered_len > 0) {
6616 if (len64 < buffered_len) {
6617 buffered_len = len64;
6620 memcpy(buf, body, (
size_t)buffered_len);
6621 len64 -= buffered_len;
6623 nread += buffered_len;
6624 buf = (
char *)buf + buffered_len;
6630 if ((
n =
pull_all(NULL, conn, (
char *)buf, (
int)len64)) >= 0) {
6633 nread = ((nread > 0) ? nread :
n);
6657 if (len > INT_MAX) {
6666 size_t all_read = 0;
6690 all_read += (size_t)read_ret;
6692 len -= (size_t)read_ret;
6701 if ((
x1 !=
'\r') || (
x2 !=
'\n')) {
6712 unsigned long chunkSize = 0;
6714 for (i = 0; i < ((
int)
sizeof(lenbuf) - 1); i++) {
6717 if ((i > 0) && (lenbuf[i] ==
'\r')
6718 && (lenbuf[i - 1] !=
'\r')) {
6721 if ((i > 1) && (lenbuf[i] ==
'\n')
6722 && (lenbuf[i - 1] ==
'\r')) {
6724 chunkSize = strtoul(lenbuf, &end, 16);
6725 if (chunkSize == 0) {
6731 if (!isxdigit(lenbuf[i])) {
6736 if ((end == NULL) || (*end !=
'\r')) {
6740 if (chunkSize == 0) {
6748 return (
int)all_read;
6758 int64_t
n,
total, allowed;
6770 if (allowed > (int64_t)len) {
6771 allowed = (int64_t)len;
6780 buf = (
const char *)buf +
total;
6784 ? (int64_t)len -
total
6798 buf = (
const char *)buf +
n;
6821 unsigned int chunk_len)
6829 sprintf(lenbuf,
"%x\r\n", chunk_len);
6830 lenbuf_len = strlen(lenbuf);
6833 ret =
mg_write(conn, lenbuf, lenbuf_len);
6834 if (ret != (
int)lenbuf_len) {
6839 ret =
mg_write(conn, chunk, chunk_len);
6840 if (ret != (
int)chunk_len) {
6855#if defined(GCC_DIAGNOSTIC)
6858#pragma GCC diagnostic push
6859#pragma GCC diagnostic ignored "-Wformat-nonliteral"
6886 (*buf)[
size - 1] = 0;
6900 size_t prealloc_size,
6926 }
else if ((
size_t)(len) >= prealloc_size) {
6929 *out_buf = (
char *)
mg_malloc((
size_t)(len) + 1);
6947 *out_buf = prealloc_buf;
6954#if defined(GCC_DIAGNOSTIC)
6956#pragma GCC diagnostic pop
6967 if ((len =
alloc_vprintf(&buf, mem,
sizeof(mem), fmt, ap)) > 0) {
6968 len =
mg_write(conn, buf, (
size_t)len);
6970 if ((buf != mem) && (buf != NULL)) {
6997 int is_form_url_encoded)
7000#define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
7002 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
7003 if ((i < src_len - 2) && (src[i] ==
'%')
7004 && isxdigit(*(
const unsigned char *)(src + i + 1))
7005 && isxdigit(*(
const unsigned char *)(src + i + 2))) {
7006 a = tolower(*(
const unsigned char *)(src + i + 1));
7007 b = tolower(*(
const unsigned char *)(src + i + 2));
7010 }
else if (is_form_url_encoded && (src[i] ==
'+')) {
7019 return (i >= src_len) ? j : -1;
7042 const char *p, *
e, *s;
7046 if ((dst == NULL) || (dst_len == 0)) {
7048 }
else if ((data == NULL) || (
name == NULL) || (data_len == 0)) {
7052 name_len = strlen(
name);
7053 e = data + data_len;
7058 for (p = data; p + name_len <
e; p++) {
7059 if (((p == data) || (p[-1] ==
'&')) && (p[name_len] ==
'=')
7065 s = (
const char *)memchr(p,
'&', (
size_t)(
e - p));
7094 const char *var_name,
7098 const char *s, *p, *end;
7099 int name_len, len = -1;
7101 if ((dst == NULL) || (dst_size == 0)) {
7106 if ((var_name == NULL) || ((s = cookie_header) == NULL)) {
7110 name_len = (
int)strlen(var_name);
7111 end = s + strlen(s);
7112 for (; (s =
mg_strcasestr(s, var_name)) != NULL; s += name_len) {
7113 if (s[name_len] ==
'=') {
7115 if ((s == cookie_header) || (s[-1] ==
' ')) {
7117 if ((p = strchr(s,
' ')) == NULL) {
7123 if ((*s ==
'"') && (p[-1] ==
'"') && (p > s + 1)) {
7127 if ((
size_t)(p - s) < dst_size) {
7141#if defined(USE_WEBSOCKET) || defined(USE_LUA)
7143base64_encode(
const unsigned char *src,
int src_len,
char *dst)
7145 static const char *b64 =
7146 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7149 for (i = j = 0; i < src_len; i += 3) {
7151 b = ((i + 1) >= src_len) ? 0 : src[i + 1];
7152 c = ((i + 2) >= src_len) ? 0 : src[i + 2];
7154 dst[j++] = b64[
a >> 2];
7155 dst[j++] = b64[((
a & 3) << 4) | (
b >> 4)];
7156 if (i + 1 < src_len) {
7157 dst[j++] = b64[(
b & 15) << 2 | (
c >> 6)];
7159 if (i + 2 < src_len) {
7160 dst[j++] = b64[
c & 63];
7163 while (j % 4 != 0) {
7173b64reverse(
char letter)
7175 if ((letter >=
'A') && (letter <=
'Z')) {
7176 return letter -
'A';
7178 if ((letter >=
'a') && (letter <=
'z')) {
7179 return letter -
'a' + 26;
7181 if ((letter >=
'0') && (letter <=
'9')) {
7182 return letter -
'0' + 52;
7184 if (letter ==
'+') {
7187 if (letter ==
'/') {
7190 if (letter ==
'=') {
7198base64_decode(
const unsigned char *src,
int src_len,
char *dst,
size_t *dst_len)
7201 unsigned char a,
b,
c,
d;
7205 for (i = 0; i < src_len; i += 4) {
7206 a = b64reverse(src[i]);
7211 b = b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]);
7216 c = b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]);
7221 d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
7226 dst[(*dst_len)++] = (
a << 2) + (
b >> 4);
7228 dst[(*dst_len)++] = (
b << 4) + (
c >> 2);
7230 dst[(*dst_len)++] = (
c << 6) +
d;
7245 && (!strcmp(s,
"PUT") || !strcmp(s,
"DELETE")
7246 || !strcmp(s,
"MKCOL") || !strcmp(s,
"PATCH"));
7252#if !defined(NO_FILES)
7256 const char *filename
7275#if defined(USE_DUKTAPE)
7302 struct vec filename_vec;
7303 size_t n = strlen(path);
7309 while ((
n > 0) && (path[
n - 1] ==
'/')) {
7316 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
7318 if ((filename_vec.
len + 1) > (path_len - (
n + 1))) {
7326 if (
mg_stat(conn, path, filestat)) {
7346 size_t filename_buf_len,
7349 int *is_script_resource,
7350 int *is_websocket_request,
7351 int *is_put_or_delete_request
7354 char const *accept_encoding;
7356#if !defined(NO_FILES)
7359 const char *rewrite;
7361 ptrdiff_t match_len;
7362 char gz_path[PATH_MAX];
7364#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7366 size_t tmp_str_len, sep_pos;
7367 int allow_substitute_script_subresources;
7370 (
void)filename_buf_len;
7374 memset(filestat, 0,
sizeof(*filestat));
7377 *is_script_resource = 0;
7384#if defined(USE_WEBSOCKET)
7386#if !defined(NO_FILES)
7387 if (*is_websocket_request && conn->
dom_ctx->
config[WEBSOCKET_ROOT]) {
7392 *is_websocket_request = 0;
7397 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
7398 if (strstr(accept_encoding,
"gzip") != NULL) {
7403#if !defined(NO_FILES)
7419 conn, &truncated, filename, filename_buf_len - 1,
"%s%s", root, uri);
7422 goto interpret_cleanup;
7432 filename_buf_len - 1,
7442 goto interpret_cleanup;
7448 if (
mg_stat(conn, filename, filestat)) {
7449 int uri_len = (
int)strlen(uri);
7450 int is_uri_end_slash = (uri_len > 0) && (uri[uri_len - 1] ==
'/');
7468 *is_script_resource = (!*is_put_or_delete_request);
7477 memset(&tmp_filestat, 0,
sizeof(tmp_filestat));
7480 conn, filename, filename_buf_len, &tmp_filestat)) {
7484 *filestat = tmp_filestat;
7488 *is_script_resource = 1;
7491 *is_script_resource = 0;
7492 *is_found = (
mg_stat(conn, filename, filestat) ? 1 : 0);
7510 conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", filename);
7513 goto interpret_cleanup;
7516 if (
mg_stat(conn, gz_path, filestat)) {
7526#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7529 tmp_str_len = strlen(filename);
7533 goto interpret_cleanup;
7535 memcpy(tmp_str, filename, tmp_str_len + 1);
7538 allow_substitute_script_subresources =
7542 sep_pos = tmp_str_len;
7543 while (sep_pos > 0) {
7545 if (tmp_str[sep_pos] ==
'/') {
7546 int is_script = 0, does_exist = 0;
7548 tmp_str[sep_pos] = 0;
7551 does_exist =
mg_stat(conn, tmp_str, filestat);
7554 if (does_exist && is_script) {
7555 filename[sep_pos] = 0;
7556 memmove(filename + sep_pos + 2,
7557 filename + sep_pos + 1,
7558 strlen(filename + sep_pos + 1) + 1);
7559 conn->
path_info = filename + sep_pos + 1;
7560 filename[sep_pos + 1] =
'/';
7561 *is_script_resource = 1;
7566 if (allow_substitute_script_subresources) {
7568 conn, tmp_str, tmp_str_len + PATH_MAX, filestat)) {
7575 DEBUG_TRACE(
"Substitute script %s serving path %s",
7593 goto interpret_cleanup;
7595 sep_pos = strlen(tmp_str);
7596 filename[sep_pos] = 0;
7597 conn->
path_info = filename + sep_pos + 1;
7598 *is_script_resource = 1;
7609 filename[sep_pos] = 0;
7611 *is_script_resource = 0;
7618 tmp_str[sep_pos] =
'/';
7628#if !defined(NO_FILES)
7631 memset(filestat, 0,
sizeof(*filestat));
7634 *is_script_resource = 0;
7635 *is_websocket_request = 0;
7636 *is_put_or_delete_request = 0;
7649 for (i = 0; i < buflen; i++) {
7651 const unsigned char c = ((
const unsigned char *)buf)[i];
7653 if ((
c < 128) && ((char)
c !=
'\r') && ((char)
c !=
'\n')
7659 if (i < buflen - 1) {
7660 if ((buf[i] ==
'\n') && (buf[i + 1] ==
'\n')) {
7669 if (i < buflen - 3) {
7670 if ((buf[i] ==
'\r') && (buf[i + 1] ==
'\n') && (buf[i + 2] ==
'\r')
7671 && (buf[i + 3] ==
'\n')) {
7682#if !defined(NO_CACHING)
7703 char month_str[32] = {0};
7704 int second, minute, hour, day, month, year;
7705 time_t result = (time_t)0;
7708 if ((sscanf(datetime,
7709 "%d/%3s/%d %d:%d:%d",
7717 || (sscanf(datetime,
7718 "%d %3s %d %d:%d:%d",
7726 || (sscanf(datetime,
7727 "%*3s, %d %3s %d %d:%d:%d",
7735 || (sscanf(datetime,
7736 "%d-%3s-%d %d:%d:%d",
7745 if ((month >= 0) && (year >= 1970)) {
7746 memset(&tm, 0,
sizeof(tm));
7747 tm.tm_year = year - 1900;
7753 result = timegm(&tm);
7769 while ((s[0] ==
'.') && (s[1] ==
'.')) {
7773 while (*s !=
'\0') {
7775 if ((s[-1] ==
'/') || (s[-1] ==
'\\')) {
7777 while (s[0] !=
'\0') {
7778 if ((s[0] ==
'/') || (s[0] ==
'\\')) {
7780 }
else if ((s[0] ==
'.') && (s[1] ==
'.')) {
7792static const struct {
7800 {
".doc", 4,
"application/msword"},
7801 {
".eps", 4,
"application/postscript"},
7802 {
".exe", 4,
"application/octet-stream"},
7803 {
".js", 3,
"application/javascript"},
7804 {
".json", 5,
"application/json"},
7805 {
".pdf", 4,
"application/pdf"},
7806 {
".ps", 3,
"application/postscript"},
7807 {
".rtf", 4,
"application/rtf"},
7808 {
".xhtml", 6,
"application/xhtml+xml"},
7809 {
".xsl", 4,
"application/xml"},
7810 {
".xslt", 5,
"application/xml"},
7813 {
".ttf", 4,
"application/font-sfnt"},
7814 {
".cff", 4,
"application/font-sfnt"},
7815 {
".otf", 4,
"application/font-sfnt"},
7816 {
".aat", 4,
"application/font-sfnt"},
7817 {
".sil", 4,
"application/font-sfnt"},
7818 {
".pfr", 4,
"application/font-tdpfr"},
7819 {
".woff", 5,
"application/font-woff"},
7822 {
".mp3", 4,
"audio/mpeg"},
7823 {
".oga", 4,
"audio/ogg"},
7824 {
".ogg", 4,
"audio/ogg"},
7827 {
".gif", 4,
"image/gif"},
7828 {
".ief", 4,
"image/ief"},
7829 {
".jpeg", 5,
"image/jpeg"},
7830 {
".jpg", 4,
"image/jpeg"},
7831 {
".jpm", 4,
"image/jpm"},
7832 {
".jpx", 4,
"image/jpx"},
7833 {
".png", 4,
"image/png"},
7834 {
".svg", 4,
"image/svg+xml"},
7835 {
".tif", 4,
"image/tiff"},
7836 {
".tiff", 5,
"image/tiff"},
7839 {
".wrl", 4,
"model/vrml"},
7842 {
".css", 4,
"text/css"},
7843 {
".csv", 4,
"text/csv"},
7844 {
".htm", 4,
"text/html"},
7845 {
".html", 5,
"text/html"},
7846 {
".sgm", 4,
"text/sgml"},
7847 {
".shtm", 5,
"text/html"},
7848 {
".shtml", 6,
"text/html"},
7849 {
".txt", 4,
"text/plain"},
7850 {
".xml", 4,
"text/xml"},
7853 {
".mov", 4,
"video/quicktime"},
7854 {
".mp4", 4,
"video/mp4"},
7855 {
".mpeg", 5,
"video/mpeg"},
7856 {
".mpg", 4,
"video/mpeg"},
7857 {
".ogv", 4,
"video/ogg"},
7858 {
".qt", 3,
"video/quicktime"},
7863 {
".arj", 4,
"application/x-arj-compressed"},
7864 {
".gz", 3,
"application/x-gunzip"},
7865 {
".rar", 4,
"application/x-arj-compressed"},
7866 {
".swf", 4,
"application/x-shockwave-flash"},
7867 {
".tar", 4,
"application/x-tar"},
7868 {
".tgz", 4,
"application/x-tar-gz"},
7869 {
".torrent", 8,
"application/x-bittorrent"},
7870 {
".ppt", 4,
"application/x-mspowerpoint"},
7871 {
".xls", 4,
"application/x-msexcel"},
7872 {
".zip", 4,
"application/x-zip-compressed"},
7876 {
".aif", 4,
"audio/x-aif"},
7877 {
".m3u", 4,
"audio/x-mpegurl"},
7878 {
".mid", 4,
"audio/x-midi"},
7879 {
".ra", 3,
"audio/x-pn-realaudio"},
7880 {
".ram", 4,
"audio/x-pn-realaudio"},
7881 {
".wav", 4,
"audio/x-wav"},
7882 {
".bmp", 4,
"image/bmp"},
7883 {
".ico", 4,
"image/x-icon"},
7884 {
".pct", 4,
"image/x-pct"},
7885 {
".pict", 5,
"image/pict"},
7886 {
".rgb", 4,
"image/x-rgb"},
7887 {
".webm", 5,
"video/webm"},
7888 {
".asf", 4,
"video/x-ms-asf"},
7889 {
".avi", 4,
"video/x-msvideo"},
7890 {
".m4v", 4,
"video/x-m4v"},
7900 path_len = strlen(path);
7910 return "text/plain";
7919 struct vec ext_vec, mime_vec;
7920 const char *list, *ext;
7923 path_len = strlen(path);
7925 if ((conn == NULL) || (
vec == NULL)) {
7927 memset(
vec,
'\0',
sizeof(
struct vec));
7935 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
7937 ext = path + path_len - ext_vec.
len;
7954 static const char *hex =
"0123456789abcdef";
7956 for (;
len--; p++) {
7957 *to++ = hex[p[0] >> 4];
7958 *to++ = hex[p[0] & 0x0f];
7977 while ((p = va_arg(ap,
const char *)) != NULL) {
7983 bin2str(buf, hash,
sizeof(hash));
7997 const char *response)
7999 char ha2[32 + 1], expected_response[32 + 1];
8002 if ((method == NULL) || (nonce == NULL) || (nc == NULL) || (cnonce == NULL)
8003 || (qop == NULL) || (response == NULL)) {
8008 if (strlen(response) != 32) {
8012 mg_md5(ha2, method,
":", uri, NULL);
8013 mg_md5(expected_response,
8038 if ((conn != NULL) && (conn->
dom_ctx != NULL)) {
8039 char name[PATH_MAX];
8044 if (gpass != NULL) {
8078 for (p = path,
e = p + strlen(p) - 1;
e > p;
e--) {
8119 char *
name, *value, *s;
8120 const char *auth_header;
8128 if (((auth_header =
mg_get_header(conn,
"Authorization")) == NULL)
8140 while (isspace(*(
unsigned char *)s)) {
8156 if (*
name ==
'\0') {
8160 if (!strcmp(
name,
"username")) {
8162 }
else if (!strcmp(
name,
"cnonce")) {
8164 }
else if (!strcmp(
name,
"response")) {
8166 }
else if (!strcmp(
name,
"uri")) {
8168 }
else if (!strcmp(
name,
"qop")) {
8170 }
else if (!strcmp(
name,
"nc")) {
8172 }
else if (!strcmp(
name,
"nonce")) {
8177#if !defined(NO_NONCE_CHECK)
8183 nonce = strtoull(
ah->
nonce, &s, 10);
8184 if ((s == NULL) || (*s != 0)) {
8229#if defined(MG_USE_OPEN_FILE)
8241#if defined(MG_USE_OPEN_FILE)
8242 if ((filep->
access.membuf != NULL) && (*p != NULL)) {
8245 eof = (
char *)memchr(*p,
'\n', (
size_t)(memend - *p));
8252 ((size_t)(eof - *p) > (
size - 1)) ? (
size - 1) : (size_t)(eof - *p);
8253 memcpy(buf, *p, len);
8256 return len ? eof : NULL;
8272#define INITIAL_DEPTH 9
8273#if INITIAL_DEPTH <= 0
8274#error Bad INITIAL_DEPTH for recursion, set to at least 1
8294 int is_authorized = 0;
8298 if (!filep || !workdata || (0 == depth)) {
8303#if defined(MG_USE_OPEN_FILE)
8304 p = (
char *)filep->
access.membuf;
8306 while (
mg_fgets(workdata->
buf,
sizeof(workdata->
buf), filep, &p) != NULL) {
8307 l = strlen(workdata->
buf);
8309 if (isspace(workdata->
buf[
l - 1])
8310 || iscntrl(workdata->
buf[
l - 1])) {
8312 workdata->
buf[
l] = 0;
8322 if (workdata->
f_user[0] ==
':') {
8326 if (workdata->
f_user[1] ==
'#') {
8329 }
else if (!strncmp(workdata->
f_user + 1,
"include=", 8)) {
8342 if (is_authorized) {
8343 return is_authorized;
8347 "%s: cannot open authorization file: %s",
8356 "%s: syntax error in authorization file: %s",
8365 "%s: syntax error in authorization file: %s",
8374 if (workdata->
f_ha1 == NULL) {
8376 "%s: syntax error in authorization file: %s",
8381 *(
char *)(workdata->
f_ha1) = 0;
8382 (workdata->
f_ha1)++;
8397 return is_authorized;
8412 memset(&workdata, 0,
sizeof(workdata));
8433 const char *filename)
8438 if (!conn || !filename) {
8457 char fname[PATH_MAX];
8458 struct vec uri_vec, filename_vec;
8461 int authorized = 1, truncated;
8463 if (!conn || !conn->
dom_ctx) {
8468 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
8475 (
int)filename_vec.
len,
8481 "%s: cannot open %s: %s",
8508 time_t curtime = time(NULL);
8526 mg_printf(conn,
"HTTP/1.1 401 Unauthorized\r\n");
8531 "Connection: %s\r\n"
8532 "Content-Length: 0\r\n"
8533 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
8557#if !defined(NO_FILES)
8566 if (passfile != NULL
8586 char line[512], u[512] =
"",
d[512] =
"", ha1[33], tmp[PATH_MAX + 8];
8593 if ((pass != NULL) && (pass[0] ==
'\0')) {
8598 if ((fname == NULL) || (domain == NULL) || (user == NULL)) {
8605 if (strchr(user,
':') != NULL) {
8608 if (strchr(domain,
':') != NULL) {
8614 for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
8615 if (iscntrl(user[i])) {
8622 for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
8623 if (iscntrl(domain[i])) {
8632 if ((strlen(fname) + 4) >= PATH_MAX) {
8638 strcat(tmp,
".tmp");
8642 if ((fp = fopen(fname,
"a+")) != NULL) {
8647 if ((fp = fopen(fname,
"r")) == NULL) {
8649 }
else if ((fp2 = fopen(tmp,
"w+")) == NULL) {
8655 while (fgets(
line,
sizeof(
line), fp) != NULL) {
8656 if (sscanf(
line,
"%255[^:]:%255[^:]:%*s", u,
d) != 2) {
8662 if (!strcmp(u, user) && !strcmp(
d, domain)) {
8665 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
8666 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
8669 fprintf(fp2,
"%s",
line);
8674 if (!found && (pass != NULL)) {
8675 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
8676 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
8694 return (port <= 0xffff);
8701 struct addrinfo hints, *res, *ressave;
8705 memset(&hints, 0,
sizeof(
struct addrinfo));
8706 hints.ai_family = af;
8708 gai_ret = getaddrinfo(src, NULL, &hints, &res);
8723 if (dstlen >= (
size_t)res->ai_addrlen) {
8724 memcpy(dst, res->ai_addr, res->ai_addrlen);
8730 freeaddrinfo(ressave);
8750 memset(sa, 0,
sizeof(*sa));
8777#if !defined(NO_SSL_DL)
8778#if defined(OPENSSL_API_1_1)
8779 if (use_ssl && (TLS_client_method == NULL)) {
8785 "SSL is not initialized");
8795 "SSL is not initialized");
8808 sa->
sin.sin_family = AF_INET;
8809 sa->
sin.sin_port = htons((uint16_t)port);
8811#if defined(USE_IPV6)
8812 }
else if (
mg_inet_pton(AF_INET6, host, &sa->sin6,
sizeof(sa->sin6))) {
8813 sa->sin6.sin6_family = AF_INET6;
8814 sa->sin6.sin6_port = htons((uint16_t)port);
8816 }
else if (host[0] ==
'[') {
8819 size_t l = strlen(host + 1);
8823 if (
mg_inet_pton(AF_INET6,
h, &sa->sin6,
sizeof(sa->sin6))) {
8824 sa->sin6.sin6_family = AF_INET6;
8825 sa->sin6.sin6_port = htons((uint16_t)port);
8844 *sock =
socket(PF_INET, SOCK_STREAM, 0);
8846#if defined(USE_IPV6)
8847 else if (ip_ver == 6) {
8848 *sock =
socket(PF_INET6, SOCK_STREAM, 0);
8867 "Cannot set socket to non-blocking: %s",
8878 conn_ret = connect(*sock,
8879 (
struct sockaddr *)((
void *)&sa->
sin),
8882#if defined(USE_IPV6)
8883 else if (ip_ver == 6) {
8885 conn_ret = connect(*sock,
8886 (
struct sockaddr *)((
void *)&sa->sin6),
8892 if (conn_ret != 0) {
8893 DWORD err = WSAGetLastError();
8894 conn_ret = (
int)err;
8895#if !defined(EINPROGRESS)
8896#define EINPROGRESS (WSAEWOULDBLOCK)
8901 if ((conn_ret != 0) && (conn_ret != EINPROGRESS)) {
8904 void *psockerr = &sockerr;
8907 int len = (
int)
sizeof(sockerr);
8909 socklen_t len = (socklen_t)
sizeof(sockerr);
8913 struct pollfd pfd[1];
8915 int ms_wait = 10000;
8923 pfd[0].events = POLLOUT;
8932 "connect(%s:%d): timeout",
8941 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, (
char *)psockerr, &len);
8943 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, psockerr, &len);
8946 if ((ret != 0) || (sockerr != 0)) {
8952 "connect(%s:%d): error %s",
8969 static const char *dont_escape =
"._-$,;~()";
8970 static const char *hex =
"0123456789abcdef";
8972 const char *end = dst + dst_len - 1;
8974 for (; ((*src !=
'\0') && (pos < end)); src++, pos++) {
8975 if (isalnum(*(
const unsigned char *)src)
8976 || (strchr(dont_escape, *(
const unsigned char *)src) != NULL)) {
8978 }
else if (pos + 2 < end) {
8980 pos[1] = hex[(*(
const unsigned char *)src) >> 4];
8981 pos[2] = hex[(*(
const unsigned char *)src) & 0xf];
8989 return (*src ==
'\0') ? (
int)(pos - dst) : -1;
8999 char size[64], mod[64];
9000#if defined(REENTRANT_TIME)
9002 struct tm *tm = &_tm;
9007 hrefsize = PATH_MAX * 3;
9056#if defined(REENTRANT_TIME)
9062 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", tm);
9064 mg_strlcpy(mod,
"01-Jan-1970 00:00",
sizeof(mod));
9065 mod[
sizeof(mod) - 1] =
'\0';
9069 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
9070 "<td> %s</td><td> %s</td></tr>\n",
9091 const struct de *
a = (
const struct de *)p1, *
b = (
const struct de *)p2;
9095 if (query_string == NULL) {
9096 query_string =
"na";
9099 if (
a->file.is_directory && !
b->file.is_directory) {
9101 }
else if (!
a->file.is_directory &&
b->file.is_directory) {
9103 }
else if (*query_string ==
'n') {
9104 cmp_result = strcmp(
a->file_name,
b->file_name);
9105 }
else if (*query_string ==
's') {
9106 cmp_result = (
a->file.size ==
b->file.size)
9108 : ((
a->file.size >
b->file.size) ? 1 : -1);
9109 }
else if (*query_string ==
'd') {
9111 (
a->file.last_modified ==
b->file.last_modified)
9113 : ((
a->file.last_modified >
b->file.last_modified) ? 1
9117 return (query_string[1] ==
'd') ? -cmp_result : cmp_result;
9129 return (
match_prefix(pw_pattern, strlen(pw_pattern), path) > 0)
9130 || ((pattern != NULL)
9131 && (
match_prefix(pattern, strlen(pattern), path) > 0));
9141 int (*cb)(
struct de *,
void *))
9143 char path[PATH_MAX];
9156 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")
9162 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
9178 "%s: mg_stat(%s) failed: %s",
9192#if !defined(NO_FILES)
9196 char path[PATH_MAX];
9211 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")) {
9216 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
9233 "%s: mg_stat(%s) failed: %s",
9273 if (new_ptr == NULL) {
9312 time_t curtime = time(NULL);
9317 "Error: Cannot open directory\nopendir(%s): %s",
9340 "Connection: close\r\n"
9341 "Content-Type: text/html; charset=utf-8\r\n\r\n",
9344 "<html><head><title>Index of %s</title>"
9345 "<style>th {text-align: left;}</style></head>"
9346 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
9347 "<tr><th><a href=\"?n%c\">Name</a></th>"
9348 "<th><a href=\"?d%c\">Modified</a></th>"
9349 "<th><a href=\"?s%c\">Size</a></th></tr>"
9350 "<tr><td colspan=\"3\"><hr></td></tr>",
9359 "<tr><td><a href=\"%s%s\">%s</a></td>"
9360 "<td> %s</td><td> %s</td></tr>\n",
9380 mg_printf(conn,
"%s",
"</table></body></html>");
9393 int to_read, num_read, num_written;
9396 if (!filep || !conn) {
9403 offset = (offset < 0) ? 0 : ((offset >
size) ?
size : offset);
9405#if defined(MG_USE_OPEN_FILE)
9406 if ((len > 0) && (filep->
access.membuf != NULL) && (
size > 0)) {
9408 if (len >
size - offset) {
9409 len =
size - offset;
9414 if (len > 0 && filep->
access.
fp != NULL) {
9416#if defined(__linux__)
9421 off_t sf_offs = (off_t)offset;
9423 int sf_file = fileno(filep->
access.
fp);
9430 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
9432 sendfile(conn->
client.
sock, sf_file, &sf_offs, sf_tosend);
9436 }
else if (loop_cnt == 0) {
9442 }
else if (sf_sent == 0) {
9448 }
while ((len > 0) && (sf_sent >= 0));
9457 offset = (int64_t)sf_offs;
9460 if ((offset > 0) && (fseeko(filep->
access.
fp, offset, SEEK_SET) != 0)) {
9462 "%s: fseeko() failed: %s",
9469 "Error: Unable to access file at requested position.");
9473 to_read =
sizeof(buf);
9474 if ((int64_t)to_read > len) {
9480 (
int)fread(buf, 1, (
size_t)to_read, filep->
access.
fp))
9486 if ((num_written =
mg_write(conn, buf, (
size_t)num_read))
9509 if ((filestat != NULL) && (buf != NULL)) {
9524 if (filep != NULL && filep->
fp != NULL) {
9528 if (fcntl(fileno(filep->
fp), F_SETFD, FD_CLOEXEC) != 0) {
9530 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
9539#if defined(USE_ZLIB)
9540#include "mod_zlib.inl"
9549 const char *additional_headers)
9551 char date[64], lm[64], etag[64];
9553 const char *msg =
"OK", *hdr;
9554 time_t curtime = time(NULL);
9556 struct vec mime_vec;
9558 char gz_path[PATH_MAX];
9559 const char *encoding =
"";
9560 const char *cors1, *cors2, *cors3;
9561 int is_head_request;
9563#if defined(USE_ZLIB)
9567 int allow_on_the_fly_compression = 1;
9570 if ((conn == NULL) || (conn->
dom_ctx == NULL) || (filep == NULL)) {
9585 "Error: File size is too large to send\n%" INT64_FMT,
9593#if defined(USE_ZLIB)
9598 allow_on_the_fly_compression = 0;
9603 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
9608 "Error: Path of zipped file too long (%s)",
9614 encoding =
"Content-Encoding: gzip\r\n";
9616#if defined(USE_ZLIB)
9618 allow_on_the_fly_compression = 0;
9625 "Error: Cannot open file\nfopen(%s): %s",
9638 && (r1 >= 0) && (r2 >= 0)) {
9646 "Error: Range requests in gzipped files are not supported");
9652 cl = (
n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
9657 "Content-Range: bytes "
9662 msg =
"Partial Content";
9664#if defined(USE_ZLIB)
9666 allow_on_the_fly_compression = 0;
9672#if defined(USE_ZLIB)
9675 allow_on_the_fly_compression = 0;
9687 cors1 =
"Access-Control-Allow-Origin: ";
9691 cors1 = cors2 = cors3 =
"";
9703 "HTTP/1.1 %d %s\r\n"
9706 "Last-Modified: %s\r\n"
9708 "Content-Type: %.*s\r\n"
9709 "Connection: %s\r\n",
9724#if defined(USE_ZLIB)
9726 if (allow_on_the_fly_compression) {
9730 "Content-Encoding: gzip\r\n"
9731 "Transfer-Encoding: chunked\r\n");
9740 "Accept-Ranges: bytes\r\n"
9750 if (additional_headers != NULL) {
9753 (
int)strlen(additional_headers),
9754 additional_headers);
9759 if (!is_head_request) {
9760#if defined(USE_ZLIB)
9761 if (allow_on_the_fly_compression) {
9763 send_compressed_data(conn, filep);
9789#if !defined(NO_CACHING)
9809 char date[64], lm[64], etag[64];
9810 time_t curtime = time(NULL);
9812 if ((conn == NULL) || (filep == NULL)) {
9821 "HTTP/1.1 %d %s\r\n"
9829 "Last-Modified: %s\r\n"
9831 "Connection: %s\r\n"
9860 const char *additional_headers)
9870#if !defined(NO_CACHING)
9876 if (
file.stat.is_directory) {
9884 "Error: Directory listing denied");
9911 for (s = p = path + 2; (p = strchr(s,
'/')) != NULL; s = ++p) {
9912 len = (size_t)(p - path);
9913 if (len >=
sizeof(buf)) {
9918 memcpy(buf, path, len);
9945 "%s: Cannot remove invalid file %s",
9980 ret =
mg_read(conn, buf,
sizeof(buf));
9990 ret =
mg_read(conn, buf,
sizeof(buf));
10014 while (isgraph(**ppw)) {
10021 if ((**ppw !=
'\r') && (**ppw !=
'\n')) {
10026 if (**ppw !=
' ') {
10035 }
while ((**ppw) && isspace(**ppw));
10040 if (!isgraph(**ppw)) {
10058 int num_headers = 0;
10062 while ((*dp !=
':') && (*dp >= 33) && (*dp <= 126)) {
10077 hdr[i].name = *buf;
10080 }
while (*dp ==
' ');
10084 *buf = dp + strcspn(dp,
"\r\n");
10085 if (((*buf)[0] !=
'\r') || ((*buf)[1] !=
'\n')) {
10089 num_headers = i + 1;
10099 if ((*buf)[0] ==
'\r') {
10104 return num_headers;
10121 {
"GET", 0, 1, 1, 1, 1},
10122 {
"POST", 1, 1, 0, 0, 0},
10123 {
"PUT", 1, 0, 0, 1, 0},
10124 {
"DELETE", 0, 0, 0, 1, 0},
10125 {
"HEAD", 0, 0, 1, 1, 1},
10126 {
"OPTIONS", 0, 0, 1, 1, 0},
10127 {
"CONNECT", 1, 1, 0, 0, 0},
10131 {
"PATCH", 1, 0, 0, 0, 0},
10135 {
"PROPFIND", 0, 1, 1, 1, 0},
10141 {
"MKCOL", 0, 0, 0, 1, 0},
10163 {
"REPORT", 1, 1, 1, 1, 1},
10170 {NULL, 0, 0, 0, 0, 0}
10185 if (!strcmp(
m->name, method)) {
10213 int request_length;
10225 while ((len > 0) && isspace(*(
unsigned char *)buf)) {
10237 if (iscntrl(*(
unsigned char *)buf)) {
10243 if (request_length <= 0) {
10244 return request_length;
10246 buf[request_length - 1] =
'\0';
10248 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
10293 return request_length + init_skip;
10300 int response_length;
10312 while ((len > 0) && isspace(*(
unsigned char *)buf)) {
10324 if (iscntrl(*(
unsigned char *)buf)) {
10330 if (response_length <= 0) {
10331 return response_length;
10333 buf[response_length - 1] =
'\0';
10335 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
10341 if (strncmp(buf,
"HTTP/", 5) != 0) {
10346 if (!isgraph(buf[0])) {
10363 l = strtol(tmp, &tmp2, 10);
10364 if ((
l < 100) || (
l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
10375 while (isprint(*buf)) {
10378 if ((*buf !=
'\r') && (*buf !=
'\n')) {
10385 }
while ((*buf) && isspace(*buf));
10395 return response_length + init_skip;
10411 int request_len,
n = 0;
10412 struct timespec last_action_time;
10413 double request_timeout;
10419 memset(&last_action_time, 0,
sizeof(last_action_time));
10425 request_timeout = -1.0;
10437 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
10439 while (request_len == 0) {
10446 if (*nread >= bufsiz) {
10452 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
10464 if ((request_len == 0) && (request_timeout >= 0)) {
10466 > request_timeout) {
10470 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
10474 return request_len;
10478#if !defined(NO_CGI) || !defined(NO_FILES)
10482 const char *expect, *body;
10484 int to_read, nread, success = 0;
10485 int64_t buffered_len;
10486 double timeout = -1.0;
10507 "Error: Client did not specify content length");
10508 }
else if ((expect != NULL)
10514 "Error: Can not fulfill expectation %s",
10517 if (expect != NULL) {
10518 (
void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
10535 if (buffered_len > 0) {
10541 conn->
phys_ctx, fp, sock, ssl, body, (int64_t)buffered_len);
10547 to_read =
sizeof(buf);
10551 nread =
pull_inner(NULL, conn, buf, to_read, timeout);
10566 success = (nread >= 0);
10583#if defined(USE_TIMERS)
10585#define TIMER_API static
10586#include "timer.inl"
10591#if !defined(NO_CGI)
10630 space = (env->buflen - env->bufused);
10633 n = strlen(fmt) + 2 + 128;
10644 "%s: Cannot allocate memory for CGI variable [%s]",
10651 space = (env->buflen - env->bufused);
10655 added = env->buf + env->bufused;
10659 mg_vsnprintf(env->conn, &truncated, added, (
size_t)space, fmt, ap);
10668 }
while (truncated);
10671 n = strlen(added) + 1;
10675 space = (env->varlen - env->varused);
10678 "%s: Cannot register CGI variable [%s]",
10685 env->var[env->varused] = added;
10697 struct vec var_vec;
10699 int i, truncated, uri_len;
10701 if ((conn == NULL) || (prog == NULL) || (env == NULL)) {
10709 if (env->
buf == NULL) {
10711 "%s: Not enough memory for environmental buffer",
10719 if (env->
var == NULL) {
10721 "%s: Not enough memory for environmental variables",
10733 addenv(env,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
10734 addenv(env,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
10735 addenv(env,
"%s",
"REDIRECT_STATUS=200");
10737#if defined(USE_IPV6)
10739 addenv(env,
"SERVER_PORT=%d", ntohs(conn->
client.
lsa.sin6.sin6_port));
10747 addenv(env,
"REMOTE_ADDR=%s", src_addr);
10763 const char *index_file = strrchr(prog,
'/');
10766 "SCRIPT_NAME=%s%s",
10774 "SCRIPT_NAME=%.*s",
10775 uri_len - (
int)strlen(conn->
path_info),
10779 addenv(env,
"SCRIPT_FILENAME=%s", prog);
10784 "PATH_TRANSLATED=%s%s",
10789 addenv(env,
"HTTPS=%s", (conn->
ssl == NULL) ?
"off" :
"on");
10792 addenv(env,
"CONTENT_TYPE=%s", s);
10798 addenv(env,
"CONTENT_LENGTH=%s", s);
10800 if ((s = getenv(
"PATH")) != NULL) {
10801 addenv(env,
"PATH=%s", s);
10813 if ((s = getenv(
"COMSPEC")) != NULL) {
10814 addenv(env,
"COMSPEC=%s", s);
10816 if ((s = getenv(
"SYSTEMROOT")) != NULL) {
10817 addenv(env,
"SYSTEMROOT=%s", s);
10819 if ((s = getenv(
"SystemDrive")) != NULL) {
10820 addenv(env,
"SystemDrive=%s", s);
10822 if ((s = getenv(
"ProgramFiles")) != NULL) {
10823 addenv(env,
"ProgramFiles=%s", s);
10825 if ((s = getenv(
"ProgramFiles(x86)")) != NULL) {
10826 addenv(env,
"ProgramFiles(x86)=%s", s);
10829 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL) {
10830 addenv(env,
"LD_LIBRARY_PATH=%s", s);
10834 if ((s = getenv(
"PERLLIB")) != NULL) {
10835 addenv(env,
"PERLLIB=%s", s);
10840 addenv(env,
"%s",
"AUTH_TYPE=Digest");
10849 sizeof(http_var_name),
10855 "%s: HTTP header variable too long [%s]",
10862 for (p = http_var_name; *p !=
'\0'; p++) {
10866 *p = (char)toupper(*(
unsigned char *)p);
10877 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
10905 ret_pid = waitpid(proc->
pid, &status, WNOHANG);
10906 if ((ret_pid != (pid_t)-1) && (status == 0)) {
10909 kill(proc->
pid, SIGABRT);
10912 while (waitpid(proc->
pid, &status, 0) != (pid_t)-1)
10915 DEBUG_TRACE(
"CGI timer: Child process %p already stopped\n", proc->
pid);
10933 int headers_len, data_len, i, truncated;
10934 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
10935 const char *status, *status_text, *connection_state;
10936 char *pbuf, dir[PATH_MAX], *p;
10939 FILE *in = NULL, *out = NULL, *err = NULL;
10941 pid_t pid = (pid_t)-1;
10944#if defined(USE_TIMERS)
10945 double cgi_timeout = -1.0;
10948 cgi_timeout = atof(conn->
dom_ctx->
config[CGI_TIMEOUT]) * 0.001;
10952 if (conn == NULL) {
10971 mg_cry_internal(conn,
"Error: CGI program \"%s\": Path too long", prog);
10976 if ((p = strrchr(dir,
'/')) != NULL) {
10984 if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) {
10985 status = strerror(
ERRNO);
10988 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
10993 "Error: Cannot create CGI pipe: %s",
11000 if (proc == NULL) {
11001 mg_cry_internal(conn,
"Error: CGI program \"%s\": Out or memory", prog);
11009 if (
pid == (pid_t)-1) {
11010 status = strerror(
ERRNO);
11013 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
11018 "Error: Cannot spawn CGI process [%s]: %s",
11030#if defined(USE_TIMERS)
11031 if (cgi_timeout > 0.0) {
11056 (
void)close(fdin[0]);
11057 (
void)close(fdout[1]);
11058 (
void)close(fderr[1]);
11059 fdin[0] = fdout[1] = fderr[1] = -1;
11061 if ((in = fdopen(fdin[1],
"wb")) == NULL) {
11062 status = strerror(
ERRNO);
11064 "Error: CGI program \"%s\": Can not open stdin: %s",
11069 "Error: CGI can not open fdin\nfopen: %s",
11074 if ((out = fdopen(fdout[0],
"rb")) == NULL) {
11075 status = strerror(
ERRNO);
11077 "Error: CGI program \"%s\": Can not open stdout: %s",
11082 "Error: CGI can not open fdout\nfopen: %s",
11087 if ((err = fdopen(fderr[0],
"rb")) == NULL) {
11088 status = strerror(
ERRNO);
11090 "Error: CGI program \"%s\": Can not open stderr: %s",
11095 "Error: CGI can not open fderr\nfopen: %s",
11114 "Error: CGI program \"%s\": Forward body data failed",
11134 "Error: Not enough memory for CGI buffer (%u bytes)",
11135 (
unsigned int)buflen);
11138 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
11141 (
unsigned int)buflen);
11146 headers_len =
read_message(out, conn, buf, (
int)buflen, &data_len);
11147 DEBUG_TRACE(
"CGI: response: %li", (
signed long)headers_len);
11149 if (headers_len <= 0) {
11153 i =
pull_all(err, conn, buf, (
int)buflen);
11158 "Error: CGI program \"%s\" sent error "
11166 "Error: CGI program \"%s\" failed.",
11172 "Error: CGI program sent malformed or too big "
11173 "(>%u bytes) HTTP headers: [%.*s]",
11180 "Error: CGI program sent malformed or too big "
11181 "(>%u bytes) HTTP headers: [%.*s]",
11192 buf[headers_len - 1] =
'\0';
11196 status_text =
"OK";
11200 status_text = status;
11201 while (isdigit(*(
const unsigned char *)status_text)
11202 || *status_text ==
' ') {
11231 mg_write(conn, buf + headers_len, (
size_t)(data_len - headers_len));
11242 if (
pid != (pid_t)-1) {
11246 if (fdin[0] != -1) {
11249 if (fdout[1] != -1) {
11255 }
else if (fdin[1] != -1) {
11261 }
else if (fdout[0] != -1) {
11267 }
else if (fderr[0] != -1) {
11278#if !defined(NO_FILES)
11285 time_t curtime = time(NULL);
11287 if (
conn == NULL) {
11297 "%s: mg_stat(%s) failed: %s",
11308 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11313 if (body_len > 0) {
11315 conn, 415,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11325 "HTTP/1.1 %d Created\r\n"
11332 "Content-Length: 0\r\n"
11333 "Connection: %s\r\n\r\n",
11336 if (errno == EEXIST) {
11338 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11339 }
else if (errno == EACCES) {
11341 conn, 403,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11342 }
else if (errno == ENOENT) {
11344 conn, 409,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11347 conn, 500,
"fopen(%s): %s", path, strerror(
ERRNO));
11361 time_t curtime = time(NULL);
11363 if (conn == NULL) {
11371 if (
file.stat.is_directory) {
11380#if defined(MG_USE_OPEN_FILE)
11381 if (
file.access.membuf != NULL) {
11385 "Error: Put not possible\nReplacing %s "
11386 "is not supported",
11393 if (
access(path, W_OK) == 0) {
11401 "Error: Put not possible\nReplacing %s is not allowed",
11416 "HTTP/1.1 %d %s\r\n",
11423 "Content-Length: 0\r\n"
11424 "Connection: %s\r\n\r\n",
11437 "Error: Path too long\nput_dir(%s): %s",
11447 "Error: Can not create directory\nput_dir(%s): %s",
11456 ||
file.access.fp == NULL) {
11460 "Error: Can not create file\nfopen(%s): %s",
11471 fseeko(
file.access.fp, r1, SEEK_SET);
11490 "HTTP/1.1 %d %s\r\n",
11497 "Content-Length: 0\r\n"
11498 "Connection: %s\r\n\r\n",
11513 "Error: Cannot delete file\nFile %s not found",
11519 if (
de.access.membuf != NULL) {
11524 "Error: Delete not possible\nDeleting %s is not supported",
11543 if (access(path, W_OK) != 0) {
11548 "Error: Delete not possible\nDeleting %s is not allowed",
11561 "Error: Cannot delete file\nremove(%s): %s",
11584 if (conn == NULL) {
11591 if (sscanf(tag,
" virtual=\"%511[^\"]\"", file_name) == 1) {
11593 file_name[511] = 0;
11602 }
else if (sscanf(tag,
" abspath=\"%511[^\"]\"", file_name) == 1) {
11605 file_name[511] = 0;
11607 mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", file_name);
11609 }
else if ((sscanf(tag,
" file=\"%511[^\"]\"", file_name) == 1)
11610 || (sscanf(tag,
" \"%511[^\"]\"", file_name) == 1)) {
11612 file_name[511] = 0;
11616 if ((p = strrchr(path,
'/')) != NULL) {
11619 len = strlen(path);
11623 sizeof(path) - len,
11634 mg_cry_internal(conn,
"SSI #include path length overflow: [%s]", tag);
11640 "Cannot open SSI #include: [%s]: fopen(%s): %s",
11659#if !defined(NO_POPEN)
11663 char cmd[1024] =
"";
11666 if (sscanf(tag,
" \"%1023[^\"]\"", cmd) != 1) {
11670 if ((
file.access.fp = popen(cmd,
"r")) == NULL) {
11672 "Cannot SSI #exec: [%s]: %s",
11677 pclose(
file.access.fp);
11689 if (filep == NULL) {
11692#if defined(MG_USE_OPEN_FILE)
11693 if ((filep->
access.membuf != NULL) && (offset >= 0)
11694 && (((
unsigned int)(offset)) < filep->
stat.
size)) {
11695 return ((
const unsigned char *)filep->
access.membuf)[offset];
11713 int ch, offset, len, in_tag, in_ssi_tag;
11715 if (include_level > 10) {
11720 in_tag = in_ssi_tag = len = offset = 0;
11723 while ((ch =
mg_fgetc(filep, offset++)) != EOF) {
11736 if ((len > 12) && !memcmp(buf + 5,
"include", 7)) {
11738#if !defined(NO_POPEN)
11739 }
else if ((len > 9) && !memcmp(buf + 5,
"exec", 4)) {
11750 in_ssi_tag = in_tag = 0;
11762 buf[len++] = (char)(ch & 0xff);
11764 if ((len == 5) && !memcmp(buf,
"<!--#", 5)) {
11769 if ((len + 2) > (
int)
sizeof(buf)) {
11795 buf[len++] = (char)(ch & 0xff);
11797 if (len == (
int)
sizeof(buf)) {
11818 time_t curtime = time(NULL);
11819 const char *cors1, *cors2, *cors3;
11821 if ((conn == NULL) || (path == NULL) || (filep == NULL)) {
11827 cors1 =
"Access-Control-Allow-Origin: ";
11831 cors1 = cors2 = cors3 =
"";
11839 "Error: Cannot read file\nfopen(%s): %s",
11846 mg_printf(conn,
"HTTP/1.1 200 OK\r\n");
11852 "Content-Type: text/html\r\n"
11853 "Connection: %s\r\n\r\n",
11865#if !defined(NO_FILES)
11870 time_t curtime = time(NULL);
11884 "HTTP/1.1 200 OK\r\n"
11886 "Connection: %s\r\n"
11887 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
11888 "PROPFIND, MKCOL\r\n"
11905 if ((conn == NULL) || (uri == NULL) || (filep == NULL)) {
11912 "<d:href>%s</d:href>"
11915 "<d:resourcetype>%s</d:resourcetype>"
11916 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
11917 "<d:getlastmodified>%s</d:getlastmodified>"
11919 "<d:status>HTTP/1.1 200 OK</d:status>"
11932 char href[PATH_MAX];
11936 if (!
de || !conn) {
11948 size_t href_encoded_size;
11949 char *href_encoded;
11951 href_encoded_size = PATH_MAX * 3;
11952 href_encoded = (
char *)
mg_malloc(href_encoded_size);
11953 if (href_encoded == NULL) {
11972 time_t curtime = time(NULL);
11976 if (!conn || !path || !filep || !conn->
dom_ctx) {
11983 "HTTP/1.1 207 Multi-Status\r\n"
11989 "Connection: %s\r\n"
11990 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
11994 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
11995 "<d:multistatus xmlns:d='DAV:'>\n");
12005 && ((depth == NULL) || (strcmp(depth,
"0") != 0))) {
12009 mg_printf(conn,
"%s\n",
"</d:multistatus>");
12017 (
void)pthread_mutex_lock(&conn->
mutex);
12025 (
void)pthread_mutex_unlock(&conn->
mutex);
12046#if defined(USE_LUA)
12047#include "mod_lua.inl"
12050#if defined(USE_DUKTAPE)
12051#include "mod_duktape.inl"
12054#if defined(USE_WEBSOCKET)
12056#if !defined(NO_SSL_DL)
12057#if !defined(OPENSSL_API_3_0)
12058#define SHA_API static
12064send_websocket_handshake(
struct mg_connection *conn,
const char *websock_key)
12066 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
12067 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
12068#if !defined(OPENSSL_API_3_0)
12082#if defined(OPENSSL_API_3_0)
12083 EVP_Digest((
unsigned char *)
buf, (uint32_t)strlen(
buf), (
unsigned char *)sha,
12090 base64_encode((
unsigned char *)sha,
sizeof(sha), b64_sha);
12092 "HTTP/1.1 101 Switching Protocols\r\n"
12093 "Upgrade: websocket\r\n"
12094 "Connection: Upgrade\r\n"
12095 "Sec-WebSocket-Accept: %s\r\n",
12099 "Sec-WebSocket-Protocol: %s\r\n\r\n",
12109#if !defined(MG_MAX_UNANSWERED_PING)
12115#define MG_MAX_UNANSWERED_PING (5)
12122 void *callback_data)
12129 int n, error, exit_by_callback;
12136 size_t i, len, mask_len = 0, header_len, body_len;
12142 unsigned char mask[4];
12147 unsigned char mem[4096];
12152 double timeout = -1.0;
12153 int enable_ping_pong = 0;
12154 int ping_count = 0;
12163 timeout = atoi(conn->
dom_ctx->
config[WEBSOCKET_TIMEOUT]) / 1000.0;
12170 DEBUG_TRACE(
"Websocket connection %s:%u start data processing loop",
12173 conn->in_websocket_handling = 1;
12182 len =
buf[1] & 127;
12183 mask_len = (
buf[1] & 128) ? 4 : 0;
12184 if ((len < 126) && (body_len >= mask_len)) {
12187 header_len = 2 + mask_len;
12188 }
else if ((len == 126) && (body_len >= (4 + mask_len))) {
12190 header_len = 4 + mask_len;
12192 }
else if (body_len >= (10 + mask_len)) {
12195 memcpy(&l1, &
buf[2], 4);
12196 memcpy(&l2, &
buf[6], 4);
12197 header_len = 10 + mask_len;
12198 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
12200 if (
data_len > (uint64_t)0x7FFF0000ul) {
12205 "websocket out of memory; closing connection");
12211 if ((header_len > 0) && (body_len >= header_len)) {
12213 unsigned char *data = mem;
12215 if ((
size_t)
data_len > (
size_t)
sizeof(mem)) {
12218 if (data == NULL) {
12224 "websocket out of memory; closing connection");
12230 if (mask_len > 0) {
12231 memcpy(mask,
buf + header_len - mask_len,
sizeof(mask));
12233 memset(mask, 0,
sizeof(mask));
12239 if (
data_len + (uint64_t)header_len > (uint64_t)body_len) {
12242 len = body_len - header_len;
12243 memcpy(data,
buf + header_len, len);
12245 while ((uint64_t)len <
data_len) {
12248 (
char *)(data + len),
12254 }
else if (
n > 0) {
12265 "Websocket pull failed; closing connection");
12282 len = (size_t)
data_len + header_len;
12287 memcpy(data,
buf + header_len, (
size_t)
data_len);
12290 memmove(
buf,
buf + len, body_len - len);
12297 if (mask_len > 0) {
12298 for (i = 0; i < (size_t)
data_len; i++) {
12299 data[i] ^= mask[i & 3];
12303 exit_by_callback = 0;
12311 }
else if (enable_ping_pong
12331 if ((ws_data_handler != NULL)
12332 && !ws_data_handler(conn,
12337 exit_by_callback = 1;
12346 if (exit_by_callback) {
12347 DEBUG_TRACE(
"Callback requests to close connection from %s:%u",
12354 DEBUG_TRACE(
"Message requests to close connection from %s:%u",
12382 if (ping_count > MG_MAX_UNANSWERED_PING) {
12384 DEBUG_TRACE(
"Too many (%i) unanswered ping from %s:%u "
12385 "- closing connection",
12391 if (enable_ping_pong) {
12417 conn->in_websocket_handling = 0;
12418 DEBUG_TRACE(
"Websocket connection %s:%u left data processing loop",
12429 uint32_t masking_key)
12431 unsigned char header[14];
12435#if defined(GCC_DIAGNOSTIC)
12437#pragma GCC diagnostic push
12438#pragma GCC diagnostic ignored "-Wconversion"
12441 header[0] = 0x80u | (
unsigned char)((
unsigned)opcode & 0xf);
12443#if defined(GCC_DIAGNOSTIC)
12444#pragma GCC diagnostic pop
12448 if (dataLen < 126) {
12450 header[1] = (
unsigned char)dataLen;
12452 }
else if (dataLen <= 0xFFFF) {
12454 uint16_t len = htons((uint16_t)dataLen);
12456 memcpy(header + 2, &len, 2);
12460 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
12461 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
12463 memcpy(header + 2, &len1, 4);
12464 memcpy(header + 6, &len2, 4);
12471 memcpy(header + headerLen, &masking_key, 4);
12488 retval =
mg_write(conn, header, headerLen);
12489 if (retval != (
int)headerLen) {
12494 retval =
mg_write(conn, data, dataLen);
12511 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
12516mask_data(
const char *in,
size_t in_len, uint32_t masking_key,
char *out)
12521 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
12523 while (i < (in_len - 3)) {
12524 *(uint32_t *)(
void *)(out + i) =
12525 *(uint32_t *)(
void *)(in + i) ^ masking_key;
12531 while (i < in_len) {
12532 *(
uint8_t *)(
void *)(out + i) =
12534 ^ *(((
uint8_t *)&masking_key) + (i % 4));
12548 char *masked_data =
12550 uint32_t masking_key = 0;
12552 if (masked_data == NULL) {
12556 "Cannot allocate buffer for masked websocket response: "
12564 }
while (masking_key == 0);
12566 mask_data(data, dataLen, masking_key, masked_data);
12568 retval = mg_websocket_write_exec(
12569 conn, opcode, masked_data, dataLen, masking_key);
12579 int is_callback_resource,
12587 const char *websock_key =
mg_get_header(conn,
"Sec-WebSocket-Key");
12588 const char *version =
mg_get_header(conn,
"Sec-WebSocket-Version");
12589 ptrdiff_t lua_websock = 0;
12591#if !defined(USE_LUA)
12597 if (!websock_key) {
12604 const char *key1 =
mg_get_header(conn,
"Sec-WebSocket-Key1");
12605 const char *key2 =
mg_get_header(conn,
"Sec-WebSocket-Key2");
12608 if ((key1 != NULL) && (key2 != NULL)) {
12611 if (8 ==
mg_read(conn, key3, 8)) {
12616 "Protocol upgrade to RFC 6455 required");
12627 if ((version == NULL) || (strcmp(version,
"13") != 0)) {
12637 if (is_callback_resource) {
12639 const char *protocols[64];
12640 int nbSubprotocolHeader = get_req_headers(&conn->
request_info,
12641 "Sec-WebSocket-Protocol",
12644 if ((nbSubprotocolHeader > 0) && subprotocols) {
12648 const char *
sep, *curSubProtocol,
12649 *acceptedWebSocketSubprotocol = NULL;
12654 const char *protocol = protocols[
cnt];
12657 sep = strchr(protocol,
',');
12658 curSubProtocol = protocol;
12659 len =
sep ? (
unsigned long)(sep - protocol)
12660 : (unsigned
long)strlen(protocol);
12661 while (sep && isspace(*++sep))
12668 && (strncmp(curSubProtocol,
12672 acceptedWebSocketSubprotocol =
12677 }
while (sep && !acceptedWebSocketSubprotocol);
12678 }
while (++cnt < nbSubprotocolHeader
12679 && !acceptedWebSocketSubprotocol);
12682 acceptedWebSocketSubprotocol;
12684 }
else if (nbSubprotocolHeader > 0) {
12686 const char *protocol = protocols[0];
12691 const char *
sep = strrchr(protocol,
',');
12704 while (isspace(*++sep)) {
12711 if ((ws_connect_handler != NULL)
12712 && (ws_connect_handler(conn, cbData) != 0)) {
12722#if defined(USE_LUA)
12735 conn->lua_websocket_state = lua_websocket_new(path, conn);
12736 if (!conn->lua_websocket_state) {
12745 if (!is_callback_resource && !lua_websock) {
12755 if (!send_websocket_handshake(conn, websock_key)) {
12761 if (is_callback_resource) {
12762 if (ws_ready_handler != NULL) {
12763 ws_ready_handler(conn, cbData);
12765#if defined(USE_LUA)
12766 }
else if (lua_websock) {
12767 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
12775 if (is_callback_resource) {
12776 read_websocket(conn, ws_data_handler, cbData);
12777#if defined(USE_LUA)
12778 }
else if (lua_websock) {
12779 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
12784 if (ws_close_handler) {
12785 ws_close_handler(conn, cbData);
12793 const char *upgrade, *connection;
12802 if (upgrade == NULL) {
12812 if (connection == NULL) {
12834 return (
n >= 0) && (
n <= 255);
12843 if (((sscanf(spec,
"%d.%d.%d.%d/%d%n", &
a, &
b, &
c, &
d, &
slash, &
n) == 5)
12844 || (sscanf(spec,
"%d.%d.%d.%d%n", &
a, &
b, &
c, &
d, &
n) == 4))
12848 *net = ((uint32_t)
a << 24) | ((uint32_t)
b << 16) | ((uint32_t)
c << 8)
12850 *mask =
slash ? (0xffffffffU << (32 -
slash)) : 0;
12862 uint32_t net, mask;
12868 if ((val.
ptr == NULL) || (sscanf(val.
ptr,
"%lf%c", &
v, &mult) < 1)
12871 && (mult !=
','))) {
12876 : ((
lowercase(&mult) ==
'm') ? 1048576 : 1);
12880 if ((remote_ip & mask) == net) {
12898 return ntohl(*(
const uint32_t *)&conn->
client.
rsa.
sin.sin_addr);
12906#if defined(MG_LEGACY_INTERFACE)
12912struct mg_upload_user_data {
12914 const char *destination_dir;
12915 int num_uploaded_files;
12921mg_upload_field_found(
const char *key,
12922 const char *filename,
12928 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
12933 return FORM_FIELD_STORAGE_ABORT;
12940 fud->destination_dir,
12944 return FORM_FIELD_STORAGE_ABORT;
12946 return FORM_FIELD_STORAGE_STORE;
12952mg_upload_field_get(
const char *key,
12969mg_upload_field_stored(
const char *path,
long long file_size,
void *user_data)
12971 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
12974 fud->num_uploaded_files++;
12975 fud->conn->phys_ctx->callbacks.upload(fud->conn, path);
12983mg_upload(
struct mg_connection *conn,
const char *destination_dir)
12985 struct mg_upload_user_data fud = {conn, destination_dir, 0};
12987 mg_upload_field_get,
12988 mg_upload_field_stored,
12996 mg_cry_internal(conn,
"%s: Error while parsing the request", __func__);
12999 return fud.num_uploaded_files;
13010 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
13024 size_t buflen =
sizeof(buf);
13030 if (host_header != NULL) {
13036 buf[buflen - 1] =
'\0';
13038 while (isspace(*host)) {
13044 if (*host ==
'[') {
13045 pos = strchr(host,
']');
13048 DEBUG_TRACE(
"%s",
"Host name format error '[' without ']'");
13055 pos = strchr(host,
':');
13119 int redirect_code = 308;
13126 sizeof(target_url),
13127 "https://%s:%d%s%s%s",
13130#
if defined(USE_IPV6)
13134 .
lsa.sin6.sin6_port)
13194 int is_delete_request,
13205 size_t urilen = strlen(
uri);
13235 if (!is_delete_request && (
handler == NULL)) {
13258 if (!phys_ctx || !dom_ctx) {
13266 for (tmp_rh = dom_ctx->
handlers; tmp_rh != NULL; tmp_rh = tmp_rh->
next) {
13268 if ((urilen == tmp_rh->
uri_len) && !strcmp(tmp_rh->
uri,
uri)) {
13269 if (!is_delete_request) {
13298 *lastref = tmp_rh->
next;
13306 lastref = &(tmp_rh->
next);
13309 if (is_delete_request) {
13320 if (tmp_rh == NULL) {
13324 "Cannot create new request handler struct, OOM");
13328 if (!tmp_rh->
uri) {
13333 "Cannot create new request handler struct, OOM");
13345 if (0 != pthread_cond_init(&tmp_rh->
refcount_cond, NULL)) {
13365 tmp_rh->
next = NULL;
13480 if (request_info) {
13481 const char *uri = request_info->
local_uri;
13482 size_t urilen = strlen(uri);
13493 tmp_rh = tmp_rh->
next) {
13495 if ((urilen == tmp_rh->
uri_len) && !strcmp(tmp_rh->
uri,
uri)) {
13506 *handler_info = tmp_rh;
13519 tmp_rh = tmp_rh->
next) {
13533 *handler_info = tmp_rh;
13546 tmp_rh = tmp_rh->
next) {
13559 *handler_info = tmp_rh;
13591#if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
13593deprecated_websocket_connect_wrapper(
const struct mg_connection *conn,
13597 if (pcallbacks->websocket_connect) {
13598 return pcallbacks->websocket_connect(conn);
13606deprecated_websocket_ready_wrapper(
struct mg_connection *conn,
void *cbdata)
13609 if (pcallbacks->websocket_ready) {
13610 pcallbacks->websocket_ready(conn);
13616deprecated_websocket_data_wrapper(
struct mg_connection *conn,
13623 if (pcallbacks->websocket_data) {
13624 return pcallbacks->websocket_data(conn, bits, data, len);
13640 char path[PATH_MAX];
13641 int uri_len, ssl_index;
13642 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
13643 is_put_or_delete_request = 0, is_callback_resource = 0;
13653 void *callback_data = NULL;
13655 void *auth_callback_data = NULL;
13657 time_t curtime = time(NULL);
13672 if (ssl_index >= 0) {
13680 "Error: SSL forward not configured properly");
13683 "Can not redirect to SSL, no SSL port available");
13720 }
else if (i == 0) {
13738 const char *cors_meth_cfg =
13740 const char *cors_orig_cfg =
13742 const char *cors_origin =
13746 "Access-Control-Request-Method");
13751 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
13752 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
13753 && (cors_origin != NULL) && (cors_acrm != NULL)) {
13757 const char *cors_acrh =
13760 "Access-Control-Request-Headers");
13764 "HTTP/1.1 200 OK\r\n"
13766 "Access-Control-Allow-Origin: %s\r\n"
13767 "Access-Control-Allow-Methods: %s\r\n"
13768 "Content-Length: 0\r\n"
13769 "Connection: %s\r\n",
13772 ((cors_meth_cfg[0] ==
'*') ? cors_acrm : cors_meth_cfg),
13775 if (cors_acrh != NULL) {
13777 const char *cors_hdr_cfg =
13780 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
13787 "Access-Control-Allow-Headers: %s\r\n",
13788 ((cors_hdr_cfg[0] ==
'*') ? cors_acrh
13792 mg_printf(conn,
"Access-Control-Max-Age: 60\r\n");
13805#if defined(USE_WEBSOCKET)
13815 &ws_connect_handler,
13826 is_callback_resource = 1;
13827 is_script_resource = 1;
13830 no_callback_resource:
13835 is_callback_resource = 0;
13841 &is_script_resource,
13842 &is_websocket_request,
13843 &is_put_or_delete_request);
13857 &auth_callback_data,
13859 if (!auth_handler(conn, auth_callback_data)) {
13862 }
else if (is_put_or_delete_request && !is_script_resource
13863 && !is_callback_resource) {
13866#if defined(NO_FILES)
13875 "%s method not allowed",
13880#if !defined(NO_FILES)
13903 if (is_callback_resource) {
13904 if (!is_websocket_request) {
13905 i = callback_handler(conn, callback_data);
13939 &is_script_resource,
13940 &is_websocket_request,
13941 &is_put_or_delete_request);
13942 callback_handler = NULL;
13953 goto no_callback_resource;
13956#if defined(USE_WEBSOCKET)
13957 handle_websocket_request(conn,
13959 is_callback_resource,
13961 ws_connect_handler,
13972#if defined(USE_WEBSOCKET)
13973 if (is_websocket_request) {
13974 if (is_script_resource) {
13978 handle_websocket_request(conn,
13992#if defined(MG_LEGACY_INTERFACE)
13993 handle_websocket_request(
13996 !is_script_resource ,
13998 deprecated_websocket_connect_wrapper,
13999 deprecated_websocket_ready_wrapper,
14000 deprecated_websocket_data_wrapper,
14011#if defined(NO_FILES)
14026 if (is_script_resource) {
14032 if (is_put_or_delete_request) {
14053 "%s method not allowed",
14066 if (
file.stat.is_directory && (uri_len > 0)
14067 && (ri->
local_uri[uri_len - 1] !=
'/')) {
14070 "HTTP/1.1 301 Moved Permanently\r\n"
14071 "Location: %s/\r\n"
14074 "Content-Length: 0\r\n"
14075 "Connection: %s\r\n",
14105 "%s method not allowed",
14111 if (
file.stat.is_directory) {
14122 "Error: Directory listing denied");
14138 if (!conn || !conn->
dom_ctx) {
14143#if defined(USE_LUA)
14154 handle_lsp_request(conn, path,
file, NULL);
14170 mg_exec_lua_script(conn, path, NULL);
14176#if defined(USE_DUKTAPE)
14184 mg_exec_duktape_script(conn, path);
14190#if !defined(NO_CGI)
14213#if !defined(NO_CACHING)
14261 unsigned int a,
b,
c,
d, port;
14264#if defined(USE_IPV6)
14265 char buf[100] = {0};
14271 memset(so, 0,
sizeof(*so));
14272 so->
lsa.
sin.sin_family = AF_INET;
14280 if (sscanf(
vec->
ptr,
"%u.%u.%u.%u:%u%n", &
a, &
b, &
c, &
d, &port, &len)
14283 so->
lsa.
sin.sin_addr.s_addr =
14284 htonl((
a << 24) | (
b << 16) | (
c << 8) |
d);
14285 so->
lsa.
sin.sin_port = htons((uint16_t)port);
14288#if defined(USE_IPV6)
14289 }
else if (sscanf(
vec->
ptr,
"[%49[^]]]:%u%n", buf, &port, &len) == 2
14291 AF_INET6, buf, &so->
lsa.sin6,
sizeof(so->
lsa.sin6))) {
14295 so->
lsa.sin6.sin6_port = htons((uint16_t)port);
14299 }
else if ((
vec->
ptr[0] ==
'+')
14300 && (sscanf(
vec->
ptr + 1,
"%u%n", &port, &len) == 1)) {
14306#if defined(USE_IPV6)
14308 so->
lsa.sin6.sin6_family = AF_INET6;
14309 so->
lsa.sin6.sin6_port = htons((uint16_t)port);
14310 *ip_version = 4 + 6;
14313 so->
lsa.
sin.sin_port = htons((uint16_t)port);
14317 }
else if (sscanf(
vec->
ptr,
"%u%n", &port, &len) == 1) {
14319 so->
lsa.
sin.sin_port = htons((uint16_t)port);
14322 }
else if ((cb = strchr(
vec->
ptr,
':')) != NULL) {
14332 char hostname[256];
14333 size_t hostnlen = (size_t)(cb -
vec->
ptr);
14335 if (hostnlen >=
sizeof(hostname)) {
14341 memcpy(hostname,
vec->
ptr, hostnlen);
14342 hostname[hostnlen] = 0;
14346 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
14348 so->
lsa.
sin.sin_family = AF_INET;
14349 so->
lsa.
sin.sin_port = htons((uint16_t)port);
14350 len += (
int)(hostnlen + 1);
14355#if defined(USE_IPV6)
14359 sizeof(so->
lsa.sin6))) {
14360 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
14362 so->
lsa.sin6.sin6_family = AF_INET6;
14363 so->
lsa.
sin.sin_port = htons((uint16_t)port);
14364 len += (
int)(hostnlen + 1);
14379 if ((len < 0) && ((unsigned)len > (
unsigned)
vec->
len)) {
14384 so->
is_ssl = (ch ==
's');
14389 && ((ch ==
'\0') || (ch ==
's') || (ch ==
'r') || (ch ==
','))) {
14439 int portslen = (
int)strlen(ports);
14440 char prevIsNumber = 0;
14442 for (i = 0; i < portslen; i++) {
14443 if (prevIsNumber && (ports[i] ==
's' || ports[i] ==
'r')) {
14446 if (ports[i] >=
'0' && ports[i] <=
'9') {
14462#if defined(USE_IPV6)
14468 struct pollfd *pfd;
14473 int portsTotal = 0;
14480 memset(&so, 0,
sizeof(so));
14481 memset(&
usa, 0,
sizeof(
usa));
14492 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
14496 "[IP_ADDRESS:]PORT[s|r]");
14500#if !defined(NO_SSL)
14504 "Cannot add SSL socket (entry %i)",
14514 "cannot create socket (entry %i)",
14529 if (setsockopt(so.
sock,
14531 SO_EXCLUSIVEADDRUSE,
14539 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
14543 if (setsockopt(so.
sock,
14552 "cannot set socket option SO_REUSEADDR (entry %i)",
14557 if (ip_version > 4) {
14559#if defined(USE_IPV6)
14560 if (ip_version > 6) {
14561 if (so.
lsa.
sa.sa_family == AF_INET6
14562 && setsockopt(so.
sock,
14572 "cannot set socket option IPV6_V6ONLY=off (entry %i)",
14576 if (so.
lsa.
sa.sa_family == AF_INET6
14577 && setsockopt(so.
sock,
14587 "cannot set socket option IPV6_V6ONLY=on (entry %i)",
14599 if (so.
lsa.
sa.sa_family == AF_INET) {
14601 len =
sizeof(so.
lsa.
sin);
14602 if (bind(so.
sock, &so.
lsa.
sa, len) != 0) {
14604 "cannot bind to %.*s: %d (%s)",
14614#if defined(USE_IPV6)
14615 else if (so.
lsa.
sa.sa_family == AF_INET6) {
14617 len =
sizeof(so.
lsa.sin6);
14618 if (bind(so.
sock, &so.
lsa.
sa, len) != 0) {
14620 "cannot bind to IPv6 %.*s: %d (%s)",
14634 "cannot bind: address family not supported (entry %i)",
14644 "cannot listen to %.*s: %d (%s)",
14654 if ((getsockname(so.
sock, &(
usa.
sa), &len) != 0)
14655 || (
usa.
sa.sa_family != so.
lsa.
sa.sa_family)) {
14659 "call to getsockname failed %.*s: %d (%s)",
14670#if defined(USE_IPV6)
14671 if (so.
lsa.
sa.sa_family == AF_INET6) {
14672 so.
lsa.sin6.sin6_port =
usa.sin6.sin6_port;
14679 if ((ptr = (
struct socket *)
14692 if ((pfd = (
struct pollfd *)
14714 if (portsOk != portsTotal) {
14726 const char *header_value;
14728 if ((header_value =
mg_get_header(conn, header)) == NULL) {
14731 return header_value;
14736#if defined(MG_EXTERNAL_FUNCTION_log_access)
14738#include "external_log_access.inl"
14749 const char *referer;
14750 const char *user_agent;
14754 if (!conn || !conn->
dom_ctx) {
14779 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z", tm);
14781 mg_strlcpy(date,
"01/Jan/1970:00:00:00 +0000",
sizeof(date));
14782 date[
sizeof(date) - 1] =
'\0';
14789 user_agent =
header_val(conn,
"User-Agent");
14795 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
14816 if (fprintf(fi.
access.
fp,
"%s\n", buf) < 1) {
14828 "Error writing log file %s",
14844 uint32_t net, mask;
14851 allowed = (list == NULL) ?
'+' :
'-';
14855 if ((flag !=
'+' && flag !=
'-')
14858 "%s: subnet must be [+|-]x.x.x.x[/x]",
14863 if (net == (remote_ip & mask)) {
14868 return allowed ==
'+';
14874#if !defined(_WIN32)
14882 const uid_t curr_uid = getuid();
14885 const struct passwd *to_pw = NULL;
14887 if (run_as_user != NULL && (to_pw = getpwnam(run_as_user)) == NULL) {
14891 "%s: unknown user [%s]",
14894 }
else if (run_as_user == NULL || curr_uid == to_pw->
pw_uid) {
14901 if (setgid(to_pw->
pw_gid) == -1) {
14903 "%s: setgid(%s): %s",
14907 }
else if (setgroups(0, NULL) == -1) {
14909 "%s: setgroups(): %s",
14912 }
else if (setuid(to_pw->
pw_uid) == -1) {
14914 "%s: setuid(%s): %s",
14941 pthread_setspecific(
sTlsKey, NULL);
14945#if !defined(NO_SSL)
14950 const char *chain);
14957 static int reload_lock = 0;
14958 static long int data_check = 0;
14959 volatile int *p_reload_lock = (
volatile int *)&reload_lock;
14961 struct stat cert_buf;
14965 int should_verify_peer;
14973 if (chain == NULL) {
14982 if (stat(pem, &cert_buf) != -1) {
14983 t = (
long int)cert_buf.st_mtime;
14986 if (data_check != t) {
14989 should_verify_peer = 0;
14993 should_verify_peer = 1;
14997 should_verify_peer = 1;
15001 if (should_verify_peer) {
15010 "SSL_CTX_load_verify_locations error: %s "
15011 "ssl_verify_peer requires setting "
15012 "either ssl_ca_path or ssl_ca_file. Is any of them "
15025 *p_reload_lock = 0;
15029 while (*p_reload_lock) {
15036#if defined(OPENSSL_API_1_1)
15044 int (*func)(
SSL *),
15045 volatile int *stop_server,
15068 if (conn->
ssl == NULL) {
15073 ret =
SSL_set_fd(conn->ssl, conn->client.sock);
15083 if (client_options) {
15092 for (i = 16; i <= 1024; i *= 2) {
15093 ret = func(conn->ssl);
15103 if (*stop_server) {
15152 const char hexdigit[] =
"0123456789abcdef";
15154 if ((memlen <= 0) || (buflen <= 0)) {
15157 if (buflen < (3 * memlen)) {
15161 for (i = 0; i < memlen; i++) {
15163 buf[3 * i - 1] =
' ';
15165 buf[3 * i] = hexdigit[(((
uint8_t *)mem)[i] >> 4) & 0xF];
15166 buf[3 * i + 1] = hexdigit[((
uint8_t *)mem)[i] & 0xF];
15168 buf[3 * memlen - 1] = 0;
15179 char str_subject[1024];
15180 char str_issuer[1024];
15181 char str_finger[1024];
15182 unsigned char buf[256];
15183 char *str_serial = NULL;
15186 unsigned char *tmp_buf;
15187 unsigned char *tmp_p;
15214 tmp_buf = (ilen > 0)
15222 tmp_buf, (
unsigned)ilen, buf, &ulen, digest, NULL)) {
15229 buf, (
int)ulen, str_finger, (
int)
sizeof(str_finger))) {
15248 "Out of memory: Cannot allocate memory for client "
15259#if defined(OPENSSL_API_1_1)
15277#if !defined(NO_SSL_DL)
15290 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
15295 "%s: cannot load %s",
15302 for (fp = sw; fp->
name != NULL; fp++) {
15310 u.p = dlsym(dll_handle, fp->
name);
15312 if (u.fp == NULL) {
15318 "%s: %s: cannot find %s",
15324 size_t cur_len = strlen(ebuf);
15329 ebuf_len - cur_len - 3,
15334 strcat(ebuf,
"...");
15346 (
void)dlclose(dll_handle);
15360#if defined(SSL_ALREADY_INITIALIZED)
15370#if defined(OPENSSL_API_1_1)
15371 if (ebuf_len > 0) {
15375#if !defined(NO_SSL_DL)
15383 "%s: error loading library %s",
15400 if (ebuf_len > 0) {
15404#if !defined(NO_SSL_DL)
15412 "%s: error loading library %s",
15429 if (num_locks < 0) {
15432 size =
sizeof(pthread_mutex_t) * ((
size_t)(num_locks));
15435 if (num_locks == 0) {
15448 "%s: cannot allocate mutexes: %s",
15456 for (i = 0; i < num_locks; i++) {
15462 "%s: error initializing mutex %i of %i",
15477#if !defined(NO_SSL_DL)
15481#if !defined(OPENSSL_API_1_1)
15490#if defined(OPENSSL_API_1_1)
15492 OPENSSL_init_ssl(0, NULL);
15514 "%s: cannot open certificate file %s: %s",
15524 "%s: cannot open private key file %s: %s",
15533 "%s: certificate and private key do not match: %s",
15550 "%s: cannot use certificate chain file %s: %s",
15561#if defined(OPENSSL_API_1_1)
15562static unsigned long
15565 long unsigned ret = (
long unsigned)
SSL_OP_ALL;
15566 if (version_id > 0)
15568 if (version_id > 1)
15570 if (version_id > 2)
15572 if (version_id > 3)
15581 if (version_id > 0)
15583 if (version_id > 1)
15585 if (version_id > 2)
15587 if (version_id > 3)
15627#if defined(GCC_DIAGNOSTIC)
15628#pragma GCC diagnostic push
15629#pragma GCC diagnostic ignored "-Wcast-align"
15635#if defined(GCC_DIAGNOSTIC)
15636#pragma GCC diagnostic pop
15643 if ((ctx == NULL) || (conn->
phys_ctx == ctx)) {
15644 DEBUG_TRACE(
"%s",
"internal error - assertion failed");
15654 if ((servername == NULL) || (*servername == 0)) {
15655 DEBUG_TRACE(
"%s",
"SSL connection not supporting SNI");
15661 DEBUG_TRACE(
"TLS connection to host %s", servername);
15693 int should_verify_peer;
15694 int peer_certificate_optional;
15695 const char *ca_path;
15696 const char *ca_file;
15697 int use_default_verify_paths;
15699 struct timespec now_mt;
15704#if defined(OPENSSL_API_1_1)
15707 "SSL_CTX_new (server) error: %s",
15714 "SSL_CTX_new (server) error: %s",
15730#if !defined(NO_SSL_DL)
15762 if (callback_ret < 0) {
15764 "SSL callback returned error: %i",
15768 if (callback_ret > 0) {
15776 clock_gettime(CLOCK_MONOTONIC, &now_mt);
15789 (
unsigned char *)ssl_context_id,
15790 sizeof(ssl_context_id));
15800 should_verify_peer = 0;
15801 peer_certificate_optional = 0;
15805 should_verify_peer = 1;
15806 peer_certificate_optional = 0;
15811 should_verify_peer = 1;
15812 peer_certificate_optional = 1;
15816 use_default_verify_paths =
15821 if (should_verify_peer) {
15827 "SSL_CTX_load_verify_locations error: %s "
15828 "ssl_verify_peer requires setting "
15829 "either ssl_ca_path or ssl_ca_file. "
15830 "Is any of them present in the "
15836 if (peer_certificate_optional) {
15845 if (use_default_verify_paths
15848 "SSL_CTX_set_default_verify_paths error: %s",
15864 "SSL_CTX_set_cipher_list error: %s",
15890 dom_ctx = &(phys_ctx->
dd);
15905 if (callback_ret < 0) {
15907 "external_ssl_ctx callback returned error: %i",
15910 }
else if (callback_ret > 0) {
15929 "Initializing SSL failed: -%s is not set",
15935 if (chain == NULL) {
15938 if ((chain != NULL) && (*chain == 0)) {
15954#if defined(OPENSSL_API_1_1)
15999 dom_ctx = &(phys_ctx->
dd);
16002 if ((path != NULL) && !
mg_stat(
fc(phys_ctx), path, &
file.stat)) {
16004 "Cannot open %s: %s",
16018 return check_acl(phys_ctx, (uint32_t)0x7f000001UL) != -1;
16055#if defined(MG_LEGACY_INTERFACE)
16069set_sock_timeout(
SOCKET sock,
int milliseconds)
16071 int r0 = 0, r1, r2;
16076 DWORD tv = (DWORD)milliseconds;
16090#if defined(TCP_USER_TIMEOUT)
16091 unsigned int uto = (
unsigned int)milliseconds;
16092 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (
const void *)&uto,
sizeof(uto));
16095 memset(&tv, 0,
sizeof(tv));
16096 tv.tv_sec = milliseconds / 1000;
16097 tv.tv_usec = (milliseconds * 1000) % 1000000;
16102 sock, SOL_SOCKET, SO_RCVTIMEO, (
SOCK_OPT_TYPE)&tv,
sizeof(tv));
16104 sock, SOL_SOCKET, SO_SNDTIMEO, (
SOCK_OPT_TYPE)&tv,
sizeof(tv));
16106 return r0 || r1 || r2;
16114 if (setsockopt(sock,
16118 sizeof(nodelay_on))
16135 struct linger linger;
16136 int error_code = 0;
16137 int linger_timeout = -2;
16138 socklen_t opt_len =
sizeof(error_code);
16161 n =
pull_inner(NULL, conn, buf,
sizeof(buf), 1.0);
16170 if (linger_timeout >= 0) {
16173 linger.l_onoff = 1;
16175#if defined(_MSC_VER)
16176#pragma warning(push)
16177#pragma warning(disable : 4244)
16179#if defined(GCC_DIAGNOSTIC)
16180#pragma GCC diagnostic push
16181#pragma GCC diagnostic ignored "-Wconversion"
16187 linger.l_linger = (linger_timeout + 999) / 1000;
16189#if defined(GCC_DIAGNOSTIC)
16190#pragma GCC diagnostic pop
16192#if defined(_MSC_VER)
16193#pragma warning(pop)
16197 linger.l_onoff = 0;
16198 linger.l_linger = 0;
16201 if (linger_timeout < -1) {
16207 (
char *)&error_code,
16217 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
16220 }
else if (error_code == ECONNRESET) {
16234 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
16251#if defined(USE_SERVER_STATS)
16252 conn->conn_state = 6;
16255#if defined(USE_LUA) && defined(USE_WEBSOCKET)
16256 if (conn->lua_websocket_state) {
16257 lua_websocket_close(conn, conn->lua_websocket_state);
16258 conn->lua_websocket_state = NULL;
16280#if defined(USE_SERVER_STATS)
16281 conn->conn_state = 7;
16284#if !defined(NO_SSL)
16285 if (conn->
ssl != NULL) {
16306#if defined(USE_SERVER_STATS)
16307 conn->conn_state = 8;
16315#if defined(USE_WEBSOCKET)
16319 if ((conn == NULL) || (conn->
phys_ctx == NULL)) {
16323#if defined(USE_WEBSOCKET)
16325 if (conn->in_websocket_handling) {
16358#if !defined(NO_SSL)
16364#if defined(USE_WEBSOCKET)
16365 if (client_ctx != NULL) {
16369 (
void)pthread_mutex_destroy(&conn->
mutex);
16395 struct sockaddr *psa;
16398 unsigned max_req_size =
16402 size_t conn_size = ((
sizeof(
struct mg_connection) + 7) >> 3) << 3;
16403 size_t ctx_size = ((
sizeof(
struct mg_context) + 7) >> 3) << 3;
16408 if (conn == NULL) {
16418#if defined(GCC_DIAGNOSTIC)
16419#pragma GCC diagnostic push
16420#pragma GCC diagnostic ignored "-Wcast-align"
16426#if defined(GCC_DIAGNOSTIC)
16427#pragma GCC diagnostic pop
16430 conn->
buf = (((
char *)conn) + conn_size + ctx_size);
16436 client_options->
host,
16437 client_options->
port,
16449#if !defined(NO_SSL)
16450#if defined(OPENSSL_API_1_1)
16457 "SSL_CTX_new error");
16470 "SSL_CTX_new error");
16479#if defined(USE_IPV6)
16480 len = (sa.
sa.sa_family == AF_INET) ?
sizeof(conn->
client.
rsa.
sin)
16482 psa = (sa.
sa.sa_family == AF_INET)
16484 : (
struct sockaddr *)&(conn->
client.
rsa.sin6);
16493 if (getsockname(sock, psa, &len) != 0) {
16495 "%s: getsockname() failed: %s",
16506 "Can not create mutex");
16507#if !defined(NO_SSL)
16516#if !defined(NO_SSL)
16536 "Can not use SSL client certificate");
16562 "SSL connection error");
16573 "Cannot set non-blocking mode for client %s:%i",
16574 client_options->
host,
16575 client_options->
port);
16584 char *error_buffer,
16585 size_t error_buffer_size)
16590 error_buffer_size);
16598 char *error_buffer,
16599 size_t error_buffer_size)
16602 memset(&opts, 0,
sizeof(opts));
16608 error_buffer_size);
16612static const struct {
16617 {
"https://", 8, 443},
16619 {
"wss://", 6, 443},
16633 const char *hostend, *portbegin;
16635 unsigned long port;
16641 if ((uri[0] ==
'*') && (uri[1] ==
'\0')) {
16652 for (i = 0; uri[i] != 0; i++) {
16657 if (uri[i] > 126) {
16680 if (uri[0] ==
'/') {
16704 port = strtoul(portbegin + 1, &portend, 10);
16705 if ((portend != hostend) || (port <= 0) || !
is_valid_port(port)) {
16721 const char *server_domain;
16722 size_t server_domain_len;
16723 size_t request_domain_len = 0;
16724 unsigned long port = 0;
16725 int i, auth_domain_check_enabled;
16726 const char *hostbegin = NULL;
16727 const char *hostend = NULL;
16728 const char *portbegin;
16731 auth_domain_check_enabled =
16743 hostend = strchr(hostbegin,
'/');
16747 portbegin = strchr(hostbegin,
':');
16748 if ((!portbegin) || (portbegin > hostend)) {
16750 request_domain_len = (size_t)(hostend - hostbegin);
16752 port = strtoul(portbegin + 1, &portend, 10);
16753 if ((portend != hostend) || (port <= 0)
16757 request_domain_len = (size_t)(portbegin - hostbegin);
16771#if defined(USE_IPV6)
16773 if (ntohs(conn->
client.
lsa.sin6.sin6_port) != port) {
16794 if (auth_domain_check_enabled) {
16796 server_domain_len = strlen(server_domain);
16797 if ((server_domain_len == 0) || (hostbegin == NULL)) {
16800 if ((request_domain_len == server_domain_len)
16801 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
16804 if (request_domain_len < (server_domain_len + 2)) {
16811 if (hostbegin[request_domain_len - server_domain_len - 1] !=
'.') {
16818 != memcmp(server_domain,
16819 hostbegin + request_domain_len - server_domain_len,
16820 server_domain_len)) {
16835 if (ebuf_len > 0) {
16854 clock_gettime(CLOCK_MONOTONIC, &(conn->
req_time));
16865 "Invalid message size");
16876 "Message too large");
16888 "Malformed message");
16898 "No data received");
16937 "Bad request: Host mismatch");
16948 char *endptr = NULL;
16950 if (endptr == cl) {
16964 "Transfer-Encoding"))
17026 char *endptr = NULL;
17028 if (endptr == cl) {
17046 "Transfer-Encoding"))
17068 char *save_timeout;
17071 if (ebuf_len > 0) {
17081 "Parameter error");
17088 if (timeout >= 0) {
17089 mg_snprintf(conn, NULL, txt,
sizeof(txt),
"%i", timeout);
17095 new_timeout = NULL;
17102#if defined(MG_LEGACY_INTERFACE)
17111 return (ret == 0) ? -1 : +1;
17129 if (ebuf_len > 0) {
17138 if (conn != NULL) {
17146 "Error sending request");
17150#if defined(MG_LEGACY_INTERFACE)
17160 if ((ebuf[0] !=
'\0') && (conn != NULL)) {
17178#if defined(USE_WEBSOCKET)
17180static unsigned __stdcall websocket_client_thread(
void *data)
17183websocket_client_thread(
void *data)
17189#if !defined(_WIN32)
17190 struct sigaction sa;
17193 memset(&sa, 0,
sizeof(sa));
17194 sa.sa_handler = SIG_IGN;
17195 sigaction(SIGPIPE, &sa, NULL);
17211 DEBUG_TRACE(
"%s",
"Websocket client thread exited\n");
17236 char *error_buffer,
17237 size_t error_buffer_size,
17239 const char *origin,
17246#if defined(USE_WEBSOCKET)
17249 static const char *magic =
"x3JJHMbDL1EzLkh9GBhXDw==";
17250 static const char *handshake_req;
17252 if (origin != NULL) {
17253 handshake_req =
"GET %s HTTP/1.1\r\n"
17255 "Upgrade: websocket\r\n"
17256 "Connection: Upgrade\r\n"
17257 "Sec-WebSocket-Key: %s\r\n"
17258 "Sec-WebSocket-Version: 13\r\n"
17262 handshake_req =
"GET %s HTTP/1.1\r\n"
17264 "Upgrade: websocket\r\n"
17265 "Connection: Upgrade\r\n"
17266 "Sec-WebSocket-Key: %s\r\n"
17267 "Sec-WebSocket-Version: 13\r\n"
17271#if defined(__clang__)
17272#pragma clang diagnostic push
17273#pragma clang diagnostic ignored "-Wformat-nonliteral"
17288#if defined(__clang__)
17289#pragma clang diagnostic pop
17293 if (
conn == NULL) {
17294 if (!*error_buffer) {
17300 "Unexpected error");
17310 if (!*error_buffer) {
17316 "Unexpected server reply");
17319 DEBUG_TRACE(
"Websocket client connect error: %s\r\n", error_buffer);
17347 if (!thread_data) {
17363 (
void *)thread_data,
17366 mg_free((
void *)thread_data);
17372 "Websocket client connect thread could not be started\r\n");
17380 (
void)error_buffer;
17381 (
void)error_buffer_size;
17398 int keep_alive_enabled =
17401 if (!keep_alive_enabled) {
17411#if defined(USE_SERVER_STATS)
17412 conn->conn_state = 2;
17418 void *conn_data = NULL;
17435 int keep_alive, discard_len;
17437 const char *hostend;
17438 int reqerr, uri_type;
17440#if defined(USE_SERVER_STATS)
17442 mg_atomic_add(&(conn->
phys_ctx->total_connections), 1);
17443 if (mcon > (conn->
phys_ctx->max_connections)) {
17446 conn->
phys_ctx->max_connections = mcon;
17452 DEBUG_TRACE(
"Start processing connection from %s",
17459 DEBUG_TRACE(
"calling get_request (%i times for this connection)",
17462#if defined(USE_SERVER_STATS)
17463 conn->conn_state = 3;
17466 if (!
get_request(conn, ebuf,
sizeof(ebuf), &reqerr)) {
17480 "Bad HTTP version: [%s]",
17485 if (ebuf[0] ==
'\0') {
17487 switch (uri_type) {
17518#if defined(MG_LEGACY_INTERFACE)
17526 (ebuf[0] ? ebuf :
"none"));
17528 if (ebuf[0] ==
'\0') {
17532#if defined(USE_SERVER_STATS)
17533 conn->conn_state = 4;
17537#if defined(USE_SERVER_STATS)
17538 conn->conn_state = 5;
17540 mg_atomic_add(&(conn->
phys_ctx->total_data_read),
17542 mg_atomic_add(&(conn->
phys_ctx->total_data_written),
17585 if (discard_len < 0) {
17587 (
long int)discard_len);
17592 DEBUG_TRACE(
"discard_len = %lu", (
long unsigned)discard_len);
17593 memmove(conn->
buf, conn->
buf + discard_len, (
size_t)conn->
data_len);
17600 DEBUG_TRACE(
"internal error: data_len = %li, buf_size = %li",
17608 }
while (keep_alive);
17610 DEBUG_TRACE(
"Done processing connection from %s (%f sec)",
17616#if defined(USE_SERVER_STATS)
17623#if defined(ALTERNATIVE_QUEUE)
17664#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17666 (
void)thread_index;
17672 while ((ctx->sq_head == ctx->sq_tail) && (ctx->
stop_flag == 0)) {
17677 if (ctx->sq_head > ctx->sq_tail) {
17679 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
17685 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
17686 ctx->sq_tail -= QUEUE_SIZE(ctx);
17687 ctx->sq_head -= QUEUE_SIZE(ctx);
17691 (
void)pthread_cond_signal(&ctx->sq_empty);
17703#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17711 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
17715 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
17717 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
17722 (
void)pthread_cond_signal(&ctx->sq_full);
17741#if defined(MG_LEGACY_INTERFACE)
17750 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
17754 pthread_setspecific(
sTlsKey, &tls);
17762 if (((
int)thread_args->
index < 0)
17763 || ((
unsigned)thread_args->
index
17766 "Internal error: Invalid worker index %i",
17767 (
int)thread_args->
index);
17776 if (conn->
buf == NULL) {
17778 "Out of memory: Cannot allocate buffer for worker %i",
17779 (
int)thread_args->
index);
17799#if defined(USE_SERVER_STATS)
17800 conn->conn_state = 1;
17803#if defined(ALTERNATIVE_QUEUE)
17819#if defined(USE_IPV6)
17822 ntohs(conn->
client.
rsa.sin6.sin6_port);
17834 DEBUG_TRACE(
"Start processing connection from %s",
17840#if !defined(NO_SSL)
17886 pthread_setspecific(
sTlsKey, NULL);
17888 CloseHandle(tls.pthread_cond_helper_mutex);
17890 pthread_mutex_destroy(&conn->
mutex);
17897#if defined(USE_SERVER_STATS)
17898 conn->conn_state = 9;
17908static unsigned __stdcall
worker_thread(
void *thread_func_param)
17922 struct sigaction sa;
17925 memset(&sa, 0,
sizeof(sa));
17926 sa.sa_handler = SIG_IGN;
17927 sigaction(SIGPIPE, &sa, NULL);
17943 socklen_t len =
sizeof(so.
rsa);
17948 }
else if (!
check_acl(ctx, ntohl(*(uint32_t *)&so.
rsa.
sin.sin_addr))) {
17951 "%s: %s is not allowed to connect",
17961 if (getsockname(so.
sock, &so.
lsa.
sa, &len) != 0) {
17963 "%s: getsockname() failed: %s",
17975 if (setsockopt(so.
sock,
17983 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
18000 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
18026 struct pollfd *pfd;
18028 unsigned int workerthreadcount;
18038 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
18039#elif defined(USE_MASTER_THREAD_PRIORITY)
18040 int min_prio = sched_get_priority_min(SCHED_RR);
18041 int max_prio = sched_get_priority_max(SCHED_RR);
18042 if ((min_prio >= 0) && (max_prio >= 0)
18043 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
18044 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
18045 struct sched_param sched_param = {0};
18046 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
18047 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
18053 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
18056 pthread_setspecific(
sTlsKey, &tls);
18071 pfd[i].events = POLLIN;
18081 if ((ctx->
stop_flag == 0) && (pfd[i].revents & POLLIN)) {
18096#if defined(ALTERNATIVE_QUEUE)
18106 pthread_cond_broadcast(&ctx->sq_full);
18112 for (i = 0; i < workerthreadcount; i++) {
18118#if defined(USE_LUA)
18120 if (ctx->lua_background_state) {
18121 lua_State *lstate = (lua_State *)ctx->lua_background_state;
18122 lua_getglobal(lstate, LUABACKGROUNDPARAMS);
18123 if (lua_istable(lstate, -1)) {
18124 reg_boolean(lstate,
"shutdown", 1);
18125 lua_pop(lstate, 1);
18129 ctx->lua_background_state = 0;
18136 CloseHandle(tls.pthread_cond_helper_mutex);
18138 pthread_setspecific(
sTlsKey, NULL);
18149static unsigned __stdcall
master_thread(
void *thread_func_param)
18158 struct sigaction sa;
18161 memset(&sa, 0,
sizeof(sa));
18162 sa.sa_handler = SIG_IGN;
18163 sigaction(SIGPIPE, &sa, NULL);
18189#if defined(ALTERNATIVE_QUEUE)
18191 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18196 (
void)pthread_cond_destroy(&ctx->sq_empty);
18197 (
void)pthread_cond_destroy(&ctx->sq_full);
18203#if defined(USE_TIMERS)
18210#if defined(_MSC_VER)
18211#pragma warning(suppress : 6001)
18229#if !defined(NO_SSL)
18232 void *ssl_ctx = (
void *)ctx->
dd.
ssl_ctx;
18238 if (callback_ret == 0) {
18293 (
void)WSACleanup();
18302#if !defined(__SYMBIAN32__)
18303#if defined(_WIN32_WCE)
18307 DWORD dwVersion = 0;
18308 DWORD dwMajorVersion = 0;
18309 DWORD dwMinorVersion = 0;
18311 BOOL wowRet, isWoW =
FALSE;
18313#if defined(_MSC_VER)
18314#pragma warning(push)
18316#pragma warning(disable : 4996)
18318 dwVersion = GetVersion();
18319#if defined(_MSC_VER)
18320#pragma warning(pop)
18323 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18324 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18325 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
18328 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
18332 (
unsigned)dwMajorVersion,
18333 (
unsigned)dwMinorVersion,
18334 (wowRet ? (isWoW ?
" (WoW64)" :
"") :
" (?)"));
18342 struct utsname
name;
18353 const char **options)
18356 const char *
name, *value, *default_value;
18357 int idx, ok, workerthreadcount;
18366 WSAStartup(MAKEWORD(2, 2), &data);
18376 (uint64_t)
get_random() ^ (uint64_t)(ptrdiff_t)(options);
18381 const char *ports_option =
18385 const char **run_options = options;
18389 while (*run_options) {
18390 if (!strcmp(*run_options, optname)) {
18391 ports_option = run_options[1];
18409 tls.pthread_cond_helper_mutex = NULL;
18411 pthread_setspecific(
sTlsKey, &tls);
18414#if !defined(ALTERNATIVE_QUEUE)
18415 ok &= (0 == pthread_cond_init(&ctx->sq_empty, NULL));
18416 ok &= (0 == pthread_cond_init(&ctx->sq_full, NULL));
18424 "Cannot initialize thread synchronization objects");
18426 pthread_setspecific(
sTlsKey, NULL);
18439#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18440 ctx->
dd.shared_lua_websockets = NULL;
18444 while (options && (
name = *options++) != NULL) {
18448 pthread_setspecific(
sTlsKey, NULL);
18450 }
else if ((value = *options++) == NULL) {
18453 pthread_setspecific(
sTlsKey, NULL);
18456 if (ctx->
dd.
config[idx] != NULL) {
18467 if ((ctx->
dd.
config[i] == NULL) && (default_value != NULL)) {
18477 pthread_setspecific(
sTlsKey, NULL);
18488 pthread_setspecific(
sTlsKey, NULL);
18492 if (workerthreadcount <= 0) {
18495 pthread_setspecific(
sTlsKey, NULL);
18500#if defined(NO_FILES)
18504 pthread_setspecific(
sTlsKey, NULL);
18511#if defined(USE_LUA)
18513 if (ctx->
dd.
config[LUA_BACKGROUND_SCRIPT] != NULL) {
18515 struct vec opt_vec;
18517 const char *sparams;
18518 lua_State *state = mg_prepare_lua_context_script(
18519 ctx->
dd.
config[LUA_BACKGROUND_SCRIPT], ctx, ebuf,
sizeof(ebuf));
18523 pthread_setspecific(
sTlsKey, NULL);
18526 ctx->lua_background_state = (
void *)state;
18528 lua_newtable(state);
18529 reg_boolean(state,
"shutdown", 0);
18531 sparams = ctx->
dd.
config[LUA_BACKGROUND_SCRIPT_PARAMS];
18533 while ((sparams =
next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
18535 state, opt_vec.
ptr, opt_vec.
len, eq_vec.
ptr, eq_vec.
len);
18539 lua_setglobal(state, LUABACKGROUNDPARAMS);
18542 ctx->lua_background_state = 0;
18549#
if !defined(NO_SSL)
18553#
if !defined(_WIN32)
18558 pthread_setspecific(
sTlsKey, NULL);
18570 "Not enough memory for worker thread ID array");
18572 pthread_setspecific(
sTlsKey, NULL);
18582 "Not enough memory for worker thread connection array");
18584 pthread_setspecific(
sTlsKey, NULL);
18589#if defined(ALTERNATIVE_QUEUE)
18597 "Not enough memory for worker event array");
18600 pthread_setspecific(
sTlsKey, NULL);
18611 "Not enough memory for worker socket array");
18615 pthread_setspecific(
sTlsKey, NULL);
18619 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18631 pthread_setspecific(
sTlsKey, NULL);
18638#if defined(USE_TIMERS)
18639 if (timers_init(ctx) != 0) {
18642 pthread_setspecific(
sTlsKey, NULL);
18679 "Cannot start worker thread %i: error %ld",
18684 "Cannot create threads: error %ld",
18687 pthread_setspecific(
sTlsKey, NULL);
18694 pthread_setspecific(
sTlsKey, NULL);
18699#if defined(MG_EXPERIMENTAL_INTERFACES)
18702mg_start_domain(
struct mg_context *
ctx,
const char **options)
18706 const char *default_value;
18711 if ((ctx == NULL) || (ctx->
stop_flag != 0) || (options == NULL)) {
18724 while (options && (
name = *options++) != NULL) {
18729 }
else if ((value = *options++) == NULL) {
18734 if (new_dom->
config[idx] != NULL) {
18753 default_value = ctx->
dd.
config[i];
18754 if ((new_dom->
config[i] == NULL) && (default_value != NULL)) {
18760 new_dom->
next = NULL;
18765#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18766 new_dom->shared_lua_websockets = NULL;
18785 "domain %s already in use",
18794 if (dom->
next == NULL) {
18795 dom->
next = new_dom;
18813 static const unsigned feature_set = 0
18817#if !defined(NO_FILES)
18820#if !defined(NO_SSL)
18823#if !defined(NO_CGI)
18826#if defined(USE_IPV6)
18829#if defined(USE_WEBSOCKET)
18832#if defined(USE_LUA)
18835#if defined(USE_DUKTAPE)
18838#if !defined(NO_CACHING)
18841#if defined(USE_SERVER_STATS)
18844#if defined(USE_ZLIB)
18850#if defined(MG_LEGACY_INTERFACE)
18853#if defined(MG_EXPERIMENTAL_INTERFACES)
18856#if defined(MEMORY_DEBUGGING)
18859#if defined(USE_TIMERS)
18862#if !defined(NO_NONCE_CHECK)
18865#if !defined(NO_POPEN)
18869 return (feature & feature_set);
18874#define strcat0(a, b) \
18876 if ((a != NULL) && (b != NULL)) { \
18888 int system_info_length = 0;
18891 const char *eol =
"\r\n";
18893 const char *eol =
"\n";
18896 const char *eoobj =
"}";
18897 int reserved_len = (
int)strlen(eoobj) + (
int)strlen(eol);
18899 if ((buffer == NULL) || (buflen < 1)) {
18905 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
18906 system_info_length += (
int)strlen(block);
18907 if (system_info_length < buflen) {
18918 "\"version\" : \"%s\",%s",
18921 system_info_length += (
int)strlen(block);
18922 if (system_info_length < buflen) {
18930 DWORD dwVersion = 0;
18931 DWORD dwMajorVersion = 0;
18932 DWORD dwMinorVersion = 0;
18935 GetSystemInfo(&si);
18937#if defined(_MSC_VER)
18938#pragma warning(push)
18940#pragma warning(disable : 4996)
18942 dwVersion = GetVersion();
18943#if defined(_MSC_VER)
18944#pragma warning(pop)
18947 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18948 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18954 "\"os\" : \"Windows %u.%u\",%s",
18955 (
unsigned)dwMajorVersion,
18956 (
unsigned)dwMinorVersion,
18958 system_info_length += (
int)strlen(block);
18959 if (system_info_length < buflen) {
18967 "\"cpu\" : \"type %u, cores %u, mask %x\",%s",
18968 (
unsigned)si.wProcessorArchitecture,
18969 (
unsigned)si.dwNumberOfProcessors,
18970 (
unsigned)si.dwActiveProcessorMask,
18972 system_info_length += (
int)strlen(block);
18973 if (system_info_length < buflen) {
18977 struct utsname
name;
18985 "\"os\" : \"%s %s (%s) - %s\",%s",
18991 system_info_length += (
int)strlen(block);
18992 if (system_info_length < buflen) {
19004 "\"features\" : %lu,%s"
19005 "\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\",%s",
19019 system_info_length += (
int)strlen(block);
19020 if (system_info_length < buflen) {
19024#if defined(USE_LUA)
19029 "\"lua_version\" : \"%u (%s)\",%s",
19030 (
unsigned)LUA_VERSION_NUM,
19033 system_info_length += (
int)strlen(block);
19034 if (system_info_length < buflen) {
19038#if defined(USE_DUKTAPE)
19043 "\"javascript\" : \"Duktape %u.%u.%u\",%s",
19044 (
unsigned)DUK_VERSION / 10000,
19045 ((
unsigned)DUK_VERSION / 100) % 100,
19046 (
unsigned)DUK_VERSION % 100,
19048 system_info_length += (
int)strlen(block);
19049 if (system_info_length < buflen) {
19057#if defined(GCC_DIAGNOSTIC)
19058#if GCC_VERSION >= 50000
19059#pragma GCC diagnostic push
19061#pragma GCC diagnostic ignored "-Wdate-time"
19068 "\"build\" : \"%s\",%s",
19072#if defined(GCC_DIAGNOSTIC)
19073#if GCC_VERSION >= 50000
19074#pragma GCC diagnostic pop
19078 system_info_length += (
int)strlen(block);
19079 if (system_info_length < buflen) {
19088#if defined(_MSC_VER)
19093 "\"compiler\" : \"MSC: %u (%u)\",%s",
19094 (
unsigned)_MSC_VER,
19095 (
unsigned)_MSC_FULL_VER,
19097 system_info_length += (
int)strlen(block);
19098 if (system_info_length < buflen) {
19101#elif defined(__MINGW64__)
19106 "\"compiler\" : \"MinGW64: %u.%u\",%s",
19107 (
unsigned)__MINGW64_VERSION_MAJOR,
19108 (
unsigned)__MINGW64_VERSION_MINOR,
19110 system_info_length += (
int)strlen(block);
19111 if (system_info_length < buflen) {
19118 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19119 (
unsigned)__MINGW32_MAJOR_VERSION,
19120 (
unsigned)__MINGW32_MINOR_VERSION,
19122 system_info_length += (
int)strlen(block);
19123 if (system_info_length < buflen) {
19126#elif defined(__MINGW32__)
19131 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19132 (
unsigned)__MINGW32_MAJOR_VERSION,
19133 (
unsigned)__MINGW32_MINOR_VERSION,
19135 system_info_length += (
int)strlen(block);
19136 if (system_info_length < buflen) {
19139#elif defined(__clang__)
19144 "\"compiler\" : \"clang: %u.%u.%u (%s)\",%s",
19147 __clang_patchlevel__,
19150 system_info_length += (
int)strlen(block);
19151 if (system_info_length < buflen) {
19154#elif defined(__GNUC__)
19159 "\"compiler\" : \"gcc: %u.%u.%u\",%s",
19160 (
unsigned)__GNUC__,
19161 (
unsigned)__GNUC_MINOR__,
19162 (
unsigned)__GNUC_PATCHLEVEL__,
19164 system_info_length += (
int)strlen(block);
19165 if (system_info_length < buflen) {
19168#elif defined(__INTEL_COMPILER)
19173 "\"compiler\" : \"Intel C/C++: %u\",%s",
19174 (
unsigned)__INTEL_COMPILER,
19176 system_info_length += (
int)strlen(block);
19177 if (system_info_length < buflen) {
19180#elif defined(__BORLANDC__)
19185 "\"compiler\" : \"Borland C: 0x%x\",%s",
19186 (
unsigned)__BORLANDC__,
19188 system_info_length += (
int)strlen(block);
19189 if (system_info_length < buflen) {
19192#elif defined(__SUNPRO_C)
19197 "\"compiler\" : \"Solaris: 0x%x\",%s",
19198 (
unsigned)__SUNPRO_C,
19200 system_info_length += (
int)strlen(block);
19201 if (system_info_length < buflen) {
19209 "\"compiler\" : \"other\",%s",
19211 system_info_length += (
int)strlen(block);
19212 if (system_info_length < buflen) {
19225 "\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, "
19227 "ptr:%u, size:%u, time:%u\"%s",
19228 (
unsigned)
sizeof(
short),
19229 (
unsigned)
sizeof(
int),
19230 (
unsigned)
sizeof(
long),
19231 (
unsigned)
sizeof(
long long),
19232 (
unsigned)
sizeof(
float),
19233 (
unsigned)
sizeof(
double),
19234 (
unsigned)
sizeof(
long double),
19235 (
unsigned)
sizeof(
char),
19236 (
unsigned)
sizeof(
wchar_t),
19237 (
unsigned)
sizeof(
void *),
19238 (
unsigned)
sizeof(
size_t),
19239 (
unsigned)
sizeof(time_t),
19241 system_info_length += (
int)strlen(block);
19242 if (system_info_length < buflen) {
19248 if ((buflen > 0) && buffer && buffer[0]) {
19249 if (system_info_length < buflen) {
19254 system_info_length += reserved_len;
19256 return system_info_length;
19260#if defined(USE_SERVER_STATS)
19264mg_get_context_info_impl(
const struct mg_context *ctx,
char *buffer,
int buflen)
19268 int context_info_length = 0;
19271 const char *eol =
"\r\n";
19273 const char *eol =
"\n";
19275 struct mg_memory_stat *ms = get_memory_stat((
struct mg_context *)ctx);
19277 const char *eoobj =
"}";
19278 int reserved_len = (
int)strlen(eoobj) + (
int)strlen(eol);
19280 if ((buffer == NULL) || (buflen < 1)) {
19286 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
19287 context_info_length += (
int)strlen(block);
19288 if (context_info_length < buflen) {
19299 "\"blocks\" : %i,%s"
19313 context_info_length += (
int)strlen(block);
19314 if (context_info_length + reserved_len < buflen) {
19322 char start_time_str[64] = {0};
19323 char now_str[64] = {0};
19325 time_t now = time(NULL);
19332 "\"connections\" : {%s"
19333 "\"active\" : %i,%s"
19334 "\"maxActive\" : %i,%s"
19338 ctx->active_connections,
19340 ctx->max_connections,
19342 ctx->total_connections,
19346 context_info_length += (
int)strlen(block);
19347 if (context_info_length + reserved_len < buflen) {
19356 "\"requests\" : {%s"
19360 ctx->total_requests,
19364 context_info_length += (
int)strlen(block);
19365 if (context_info_length + reserved_len < buflen) {
19379 ctx->total_data_read,
19381 ctx->total_data_written,
19385 context_info_length += (
int)strlen(block);
19386 if (context_info_length + reserved_len < buflen) {
19392 sizeof(start_time_str) - 1,
19401 "\"uptime\" : %.0f,%s"
19402 "\"start\" : \"%s\",%s"
19403 "\"now\" : \"%s\"%s"
19406 difftime(now, start_time),
19414 context_info_length += (
int)strlen(block);
19415 if (context_info_length + reserved_len < buflen) {
19421 if ((buflen > 0) && buffer && buffer[0]) {
19422 if (context_info_length < buflen) {
19427 context_info_length += reserved_len;
19429 return context_info_length;
19434#if defined(MG_EXPERIMENTAL_INTERFACES)
19438mg_get_connection_info_impl(
const struct mg_context *ctx,
19446 int connection_info_length = 0;
19448 const char *state_str =
"unknown";
19451 const char *eol =
"\r\n";
19453 const char *eol =
"\n";
19456 const char *eoobj =
"}";
19457 int reserved_len = (
int)strlen(eoobj) + (
int)strlen(eol);
19459 if ((buffer == NULL) || (buflen < 1)) {
19465 if ((ctx == NULL) || (idx < 0)) {
19480 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
19481 connection_info_length += (
int)strlen(block);
19482 if (connection_info_length < buflen) {
19489#if defined(USE_SERVER_STATS)
19490 state = conn->conn_state;
19495 state_str =
"undefined";
19498 state_str =
"not used";
19501 state_str =
"init";
19504 state_str =
"ready";
19507 state_str =
"processing";
19510 state_str =
"processed";
19513 state_str =
"to close";
19516 state_str =
"closing";
19519 state_str =
"closed";
19522 state_str =
"done";
19528 if ((state >= 3) && (state < 9)) {
19533 "\"connection\" : {%s"
19535 "\"protocol\" : \"%s\",%s"
19536 "\"addr\" : \"%s\",%s"
19539 "\"handled_requests\" : %u%s"
19554 connection_info_length += (
int)strlen(block);
19555 if (connection_info_length + reserved_len < buflen) {
19561 if ((state >= 4) && (state < 6)) {
19566 "\"request_info\" : {%s"
19567 "\"method\" : \"%s\",%s"
19568 "\"uri\" : \"%s\",%s"
19569 "\"query\" : %s%s%s%s"
19582 connection_info_length += (
int)strlen(block);
19583 if (connection_info_length + reserved_len < buflen) {
19589 if ((state >= 2) && (state < 9)) {
19590 char start_time_str[64] = {0};
19591 char now_str[64] = {0};
19593 time_t now = time(NULL);
19596 sizeof(start_time_str) - 1,
19605 "\"uptime\" : %.0f,%s"
19606 "\"start\" : \"%s\",%s"
19607 "\"now\" : \"%s\"%s"
19610 difftime(now, start_time),
19618 connection_info_length += (
int)strlen(block);
19619 if (connection_info_length + reserved_len < buflen) {
19631 "\"name\" : \"%s\",%s"
19638 connection_info_length += (
int)strlen(block);
19639 if (connection_info_length + reserved_len < buflen) {
19661 connection_info_length += (
int)strlen(block);
19662 if (connection_info_length + reserved_len < buflen) {
19672 "\"state\" : \"%s\"%s",
19676 connection_info_length += (
int)strlen(block);
19677 if (connection_info_length + reserved_len < buflen) {
19682 if ((buflen > 0) && buffer && buffer[0]) {
19683 if (connection_info_length < buflen) {
19688 connection_info_length += reserved_len;
19690 return connection_info_length;
19700 if ((buffer == NULL) || (buflen < 1)) {
19715#if defined(USE_SERVER_STATS)
19716 if ((buffer == NULL) || (buflen < 1)) {
19717 return mg_get_context_info_impl(ctx, NULL, 0);
19721 return mg_get_context_info_impl(ctx, buffer, buflen);
19725 if ((buffer != NULL) && (buflen > 0)) {
19733#if defined(MG_EXPERIMENTAL_INTERFACES)
19735mg_get_connection_info(
const struct mg_context *ctx,
19740 if ((buffer == NULL) || (buflen < 1)) {
19741 return mg_get_connection_info_impl(ctx, idx, NULL, 0);
19745 return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
19756#if !defined(NO_SSL)
19761 unsigned features_inited = features_to_init;
19781 InitializeCriticalSection(&global_log_file_lock);
19783#if !defined(_WIN32)
19788#if defined(USE_LUA)
19789 lua_init_optional_libraries();
19795#if !defined(NO_SSL)
19802 DEBUG_TRACE(
"Initializing SSL failed: %s", ebuf);
19816 WSAStartup(MAKEWORD(2, 2), &data);
19824 return features_inited;
19841 (
void)WSACleanup();
19843#if !defined(NO_SSL)
19851 (
void)DeleteCriticalSection(&global_log_file_lock);
19853#if !defined(_WIN32)
19859#if defined(USE_LUA)
19860 lua_exit_optional_libraries();
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
static const double x2[5]
static const double x1[5]
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
static unsigned int total
#define INVALID_HANDLE_VALUE
R__EXTERN C unsigned int sleep(unsigned int seconds)
static void process_new_connection(struct mg_connection *conn)
static int set_tcp_nodelay(SOCKET sock, int nodelay_on)
#define SSL_CTX_use_certificate_file
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)
void mg_send_mime_file2(struct mg_connection *conn, const char *path, const char *mime_type, const char *additional_headers)
static pthread_key_t sTlsKey
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
static void open_auth_file(struct mg_connection *conn, const char *path, struct mg_file *filep)
char static_assert_replacement[1]
int mg_strncasecmp(const char *s1, const char *s2, size_t len)
#define SSL_CTX_check_private_key
static int check_authorization(struct mg_connection *conn, const char *path)
#define mg_malloc_ctx(a, c)
static int mg_fgetc(struct mg_file *filep, int offset)
struct asn1_integer ASN1_INTEGER
#define X509_NAME_oneline
static char mg_getc(struct mg_connection *conn)
static int mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
void mg_unlock_connection(struct mg_connection *conn)
static void mkcol(struct mg_connection *conn, const char *path)
static void remove_bad_file(const struct mg_connection *conn, const char *path)
static const struct @145 abs_uri_protocols[]
const struct mg_option * mg_get_valid_options(void)
#define SSL_set_tlsext_host_name(ctx, arg)
int mg_get_server_ports(const struct mg_context *ctx, int size, struct mg_server_ports *ports)
static int set_non_blocking_mode(SOCKET sock)
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
int mg_send_http_error(struct mg_connection *conn, int status, const char *fmt,...)
static const char * get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
static void mg_cry_internal_impl(const struct mg_connection *conn, const char *func, unsigned line, const char *fmt, va_list ap)
void mg_lock_context(struct mg_context *ctx)
#define SSL_OP_CIPHER_SERVER_PREFERENCE
#define MAX_WORKER_THREADS
static int send_additional_header(struct mg_connection *conn)
#define SSL_load_error_strings
static void put_file(struct mg_connection *conn, const char *path)
struct ssl_ctx_st SSL_CTX
static void do_ssi_exec(struct mg_connection *conn, char *tag)
static void tls_dtor(void *key)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
const void * SOCK_OPT_TYPE
static int header_has_option(const char *header, const char *option)
int mg_send_http_redirect(struct mg_connection *conn, const char *target_url, int redirect_code)
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
#define SSL_set_app_data(s, arg)
#define SSL_get_peer_certificate
#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)
#define is_websocket_protocol(conn)
static int put_dir(struct mg_connection *conn, const char *path)
static void * realloc2(void *ptr, size_t size)
#define SSL_OP_SINGLE_DH_USE
static int print_dav_dir_entry(struct de *de, void *data)
static void delete_file(struct mg_connection *conn, const char *path)
static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
#define mg_calloc_ctx(a, b, c)
static FUNCTION_MAY_BE_UNUSED int mg_atomic_inc(volatile int *addr)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
static int should_keep_alive(const struct mg_connection *conn)
static __inline void * mg_malloc(size_t a)
#define SSL_get_app_data(s)
static int mg_fopen(const struct mg_connection *conn, const char *path, int mode, struct mg_file *filep)
#define OPENSSL_REMOVE_THREAD_STATE()
static int send_no_cache_header(struct mg_connection *conn)
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 int ssl_use_pem_file(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *pem, const char *chain)
static void mg_cry_internal_wrap(const struct mg_connection *conn, const char *func, unsigned line, const char *fmt,...) PRINTF_ARGS(4
static const char * ssl_error(void)
static int must_hide_file(struct mg_connection *conn, const char *path)
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
#define CONF_modules_unload
#define mg_remove(conn, x)
int mg_send_http_ok(struct mg_connection *conn, const char *mime_type, long long content_length)
static void close_all_listening_sockets(struct mg_context *ctx)
void mg_send_file(struct mg_connection *conn, const char *path)
#define SSL_TLSEXT_ERR_OK
static void send_authorization_request(struct mg_connection *conn, const char *realm)
static int check_password(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response)
#define X509_get_subject_name
#define SSL_TLSEXT_ERR_NOACK
static const struct mg_option config_options[]
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS
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)
static const char * mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p)
const char * mg_get_response_code_text(const struct mg_connection *conn, int response_code)
static int get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS])
static int set_uid_option(struct mg_context *phys_ctx)
static void remove_double_dots_and_double_slashes(char *s)
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 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)
#define SSL_CTX_set_ecdh_auto(ctx, onoff)
#define FUNCTION_MAY_BE_UNUSED
static pthread_mutex_t * ssl_mutexes
void mg_set_user_connection_data(struct mg_connection *conn, void *data)
#define SSLv23_client_method
static int get_option_index(const char *name)
static int abort_process(void *data)
static char * mg_strdup(const char *str)
static void addenv(struct cgi_environment *env, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
const struct mg_response_info * mg_get_response_info(const struct mg_connection *conn)
static int initialize_ssl(char *ebuf, size_t ebuf_len)
static __inline void * mg_realloc(void *a, size_t b)
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
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
long long mg_store_body(struct mg_connection *conn, const char *path)
struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
#define DEBUG_ASSERT(cond)
static int pull_inner(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
static int mg_poll(struct pollfd *pfd, unsigned int n, int milliseconds, volatile int *stop_server)
int mg_get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int timeout)
#define MG_FILE_COMPRESSION_SIZE_LIMIT
static struct mg_connection * mg_connect_client_impl(const struct mg_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len)
unsigned mg_check_feature(unsigned feature)
static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
static int mg_send_http_error_impl(struct mg_connection *conn, int status, const char *fmt, va_list args)
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
#define SSL_CTX_clear_options(ctx, op)
#define MG_FOPEN_MODE_READ
static int open_file_in_memory(const struct mg_connection *conn, const char *path, struct mg_file *filep, int mode)
#define SSL_OP_NO_COMPRESSION
static int extention_matches_script(struct mg_connection *conn, const char *filename)
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 const char * alloc_get_host(struct mg_connection *conn)
static pthread_mutexattr_t pthread_mutex_attr
#define SSL_ERROR_SYSCALL
#define SSL_CTX_load_verify_locations
void mg_unlock_context(struct mg_context *ctx)
#define SSL_ERROR_WANT_READ
static int ssl_servername_callback(SSL *ssl, int *ad, void *arg)
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
static void fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
int mg_start_thread(mg_thread_func_t func, void *param)
static void * load_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw)
static const char * get_header(const struct mg_header *hdr, int num_hdr, const char *name)
static struct mg_http_method_info http_methods[]
static int event_signal(void *eventhdl)
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 connect_socket(struct mg_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa)
unsigned mg_init_library(unsigned features)
struct mg_connection * mg_connect_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size)
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
static void master_thread_run(void *thread_func_param)
static int set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
static int skip_to_end_of_word_and_terminate(char **ppw, int eol)
static int get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len)
#define ARRAY_SIZE(array)
static int parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
static int get_first_ssl_listener_index(const struct mg_context *ctx)
#define SSL_CTX_use_PrivateKey_file
struct ssl_method_st SSL_METHOD
void mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type)
const char * mg_get_header(const struct mg_connection *conn, const char *name)
#define mg_mkdir(conn, path, mode)
static uint32_t get_remote_ip(const struct mg_connection *conn)
static int hexdump2string(void *mem, int memlen, char *buf, int buflen)
static void handle_directory_request(struct mg_connection *conn, const char *dir)
static int set_ports_option(struct mg_context *phys_ctx)
static int read_auth_file(struct mg_file *filep, struct read_auth_file_struct *workdata, int depth)
static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
unsigned mg_exit_library(void)
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb)
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
int mg_send_digest_access_authentication_request(struct mg_connection *conn, const char *realm)
static void print_props(struct mg_connection *conn, const char *uri, struct mg_file_stat *filep)
static const char * mg_strcasestr(const char *big_str, const char *small_str)
struct mg_connection * mg_connect_websocket_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
static 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)
#define ASN1_INTEGER_to_BN
#define SSL_ERROR_WANT_ACCEPT
@ CONNECTION_TYPE_RESPONSE
@ CONNECTION_TYPE_INVALID
@ CONNECTION_TYPE_REQUEST
static void bin2str(char *to, const unsigned char *p, size_t len)
const struct mg_request_info * mg_get_request_info(const struct mg_connection *conn)
#define SSL_ERROR_WANT_X509_LOOKUP
#define MG_FOPEN_MODE_APPEND
char * mg_md5(char buf[33],...)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
#define SSL_CB_HANDSHAKE_START
static const char * suggest_connection_header(const struct mg_connection *conn)
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)
int mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
static int prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_environment *env)
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)
#define SSL_ERROR_WANT_CONNECT
static void send_options(struct mg_connection *conn)
static int lowercase(const char *s)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
static void event_destroy(void *eventhdl)
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 X509_get_serialNumber
#define DEBUG_TRACE(fmt,...)
static void get_system_name(char **sysName)
int mg_url_encode(const char *src, char *dst, size_t dst_len)
static void handler_info_wait_unused(struct mg_handler_info *handler_info)
static const char * header_val(const struct mg_connection *conn, const char *header)
#define CRYPTO_set_locking_callback
struct ossl_init_settings_st OPENSSL_INIT_SETTINGS
#define mg_cry_internal(conn, fmt,...)
static int set_acl_option(struct mg_context *phys_ctx)
static void mg_set_thread_name(const char *name)
static void get_mime_type(struct mg_connection *conn, const char *path, struct vec *vec)
static int set_blocking_mode(SOCKET sock)
#define CRYPTO_cleanup_all_ex_data
CIVETWEB_API struct mg_connection * mg_connect_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size)
static void send_file_data(struct mg_connection *conn, struct mg_file *filep, int64_t offset, int64_t len)
#define MAX_CGI_ENVIR_VARS
static int sslize(struct mg_connection *conn, SSL_CTX *s, int(*func)(SSL *), volatile int *stop_server, const struct mg_client_options *client_options)
static char * mg_strdup_ctx(const char *str, struct mg_context *ctx)
static void set_close_on_exec(SOCKET fd, struct mg_connection *conn)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
#define SSL_CTX_set_cipher_list
int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence)
static int is_not_modified(const struct mg_connection *conn, const struct mg_file_stat *filestat)
static const char * get_proto_name(const struct mg_connection *conn)
static void * master_thread(void *thread_func_param)
#define SSL_CTX_set_verify_depth
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)
#define SSL_CTX_set_info_callback
static void handler_info_release(struct mg_handler_info *handler_info)
void mg_close_connection(struct mg_connection *conn)
static int is_valid_port(unsigned long port)
static void handle_propfind(struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
#define SSL_get_servername
#define mg_realloc_ctx(a, b, c)
#define SSL_CTX_use_certificate_chain_file
struct x509_name X509_NAME
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 SSL_CTX_set_default_verify_paths
static int print_dir_entry(struct de *de)
#define MG_FOPEN_MODE_WRITE
void * mg_get_user_connection_data(const struct mg_connection *conn)
static int authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm)
static void send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int)
#define mg_static_assert(cond, txt)
#define SOCKET_TIMEOUT_QUANTUM
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static ptrdiff_t match_prefix(const char *pattern, size_t pattern_len, const char *str)
int mg_send_chunk(struct mg_connection *conn, const char *chunk, unsigned int chunk_len)
#define EVP_get_digestbyname
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 void ssl_get_client_cert_info(struct mg_connection *conn)
static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
static int is_in_script_path(const struct mg_connection *conn, const char *path)
static double mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
static void free_context(struct mg_context *ctx)
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
static void construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
int mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
static int thread_idx_max
static int cryptolib_users
static int64_t push_all(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
static const char * month_names[]
static int refresh_trust(struct mg_connection *conn)
static struct ssl_func ssl_sw[]
static void mg_vsnprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap)
static int event_wait(void *eventhdl)
static int should_decode_url(const struct mg_connection *conn)
static void uninitialize_ssl(void)
#define TLSEXT_NAMETYPE_host_name
#define SSL_CTX_set_options(ctx, op)
static void handle_request(struct mg_connection *conn)
static int mg_get_system_info_impl(char *buffer, int buflen)
static void * worker_thread_run(struct worker_thread_args *thread_args)
#define SSL_CTX_set_verify
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 void handle_cgi_request(struct mg_connection *conn, const char *prog)
static void handler_info_acquire(struct mg_handler_info *handler_info)
static int parse_http_response(char *buf, int len, struct mg_response_info *ri)
static void * cryptolib_dll_handle
#define MG_FOPEN_MODE_NONE
#define CRYPTO_set_id_callback
const char * mg_get_builtin_mime_type(const char *path)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
#define IGNORE_UNUSED_RESULT(a)
static FUNCTION_MAY_BE_UNUSED int mg_atomic_dec(volatile int *addr)
#define X509_get_issuer_name
static void discard_unread_request_data(struct mg_connection *conn)
int mg_strcasecmp(const char *s1, const char *s2)
static int mg_fclose(struct mg_file_access *fileacc)
static struct mg_connection * fc(struct mg_context *ctx)
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
static int send_static_cache_header(struct mg_connection *conn)
#define SSL_CTX_set_session_id_context
static struct mg_context common_client_context
static void * worker_thread(void *thread_func_param)
#define SSL_CB_HANDSHAKE_DONE
static __inline void mg_free(void *a)
int mg_check_digest_access_authentication(struct mg_connection *conn, const char *realm, const char *filename)
static int mg_join_thread(pthread_t threadid)
int mg_get_system_info(char *buffer, int buflen)
static void handle_not_modified_static_file_request(struct mg_connection *conn, struct mg_file *filep)
static int init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
static void close_socket_gracefully(struct mg_connection *conn)
struct mg_context * mg_get_context(const struct mg_connection *conn)
static int is_ssl_port_used(const char *ports)
static void init_connection(struct mg_connection *conn)
struct x509_store_ctx_st X509_STORE_CTX
static struct ssl_func crypto_sw[]
static int dir_scan_callback(struct de *de, void *data)
static int get_month_index(const char *s)
void mg_set_websocket_handler_with_subprotocols(struct mg_context *ctx, const char *uri, struct mg_websocket_subprotocols *subprotocols, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
static int mg_ssl_initialized
static void * ssllib_dll_handle
#define OPENSSL_INIT_LOAD_SSL_STRINGS
static const struct @144 builtin_mime_types[]
@ ENABLE_DIRECTORY_LISTING
@ ACCESS_CONTROL_ALLOW_ORIGIN
@ ALLOW_INDEX_SCRIPT_SUB_RES
@ ACCESS_CONTROL_ALLOW_HEADERS
@ SSL_DEFAULT_VERIFY_PATHS
@ ACCESS_CONTROL_ALLOW_METHODS
@ PUT_DELETE_PASSWORDS_FILE
@ ENABLE_AUTH_DOMAIN_CHECK
#define PASSWORDS_FILE_NAME
static void log_access(const struct mg_connection *conn)
#define SSLv23_server_method
static void close_connection(struct mg_connection *conn)
#define SSL_OP_NO_TLSv1_1
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mg_file_stat *filestat)
static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
void mg_stop(struct mg_context *ctx)
#define STRUCT_FILE_INITIALIZER
#define SSL_CTX_set_tlsext_servername_arg(ctx, arg)
static FUNCTION_MAY_BE_UNUSED void mg_global_unlock(void)
void * mg_get_user_data(const struct mg_context *ctx)
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 int check_acl(struct mg_context *phys_ctx, uint32_t remote_ip)
const char * mg_version(void)
void mg_set_auth_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
static uint64_t get_random(void)
void mg_lock_connection(struct mg_connection *conn)
int mg_send_file_body(struct mg_connection *conn, const char *path)
static void * event_create(void)
static int is_valid_http_method(const char *method)
#define SSL_ERROR_WANT_WRITE
static int is_file_in_memory(const struct mg_connection *conn, const char *path)
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)
int(* mg_authorization_handler)(struct mg_connection *conn, void *cbdata)
CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
@ MG_FEATURES_COMPRESSION
void(* mg_websocket_ready_handler)(struct mg_connection *, void *)
CIVETWEB_API int mg_handle_form_request(struct mg_connection *conn, struct mg_form_data_handler *fdh)
#define PRINTF_ARGS(x, y)
@ 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
@ MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE
@ MG_WEBSOCKET_OPCODE_PONG
@ MG_WEBSOCKET_OPCODE_PING
int(* mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *)
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
void(* mg_websocket_close_handler)(const struct mg_connection *, void *)
int(* mg_websocket_connect_handler)(const struct mg_connection *, void *)
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
MD5_STATIC void md5_init(md5_state_t *pms)
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
RooArgList L(Args_t &&... args)
SHA_API void SHA1_Init(SHA_CTX *context)
SHA_API void SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
SHA_API void SHA1_Final(unsigned char *digest, SHA_CTX *context)
struct mg_connection * conn
struct mg_connection * conn
int(* init_ssl)(void *ssl_context, void *user_data)
int(* log_message)(const struct mg_connection *, const char *message)
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)
void(* init_thread)(const struct mg_context *ctx, int thread_type)
int(* external_ssl_ctx)(void **ssl_ctx, void *user_data)
int(* begin_request)(struct mg_connection *)
int(* log_access)(const struct mg_connection *, const char *message)
void(* init_context)(const struct mg_context *ctx)
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
int64_t last_throttle_bytes
pthread_t * worker_threadids
struct socket * client_socks
struct mg_connection * worker_connections
struct socket * listening_sockets
pthread_mutex_t thread_mutex
struct mg_callbacks callbacks
struct mg_domain_context dd
struct pollfd * listening_socket_fds
void ** client_wait_events
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
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
pthread_mutex_t refcount_mutex
struct mg_handler_info * next
pthread_cond_t refcount_cond
mg_websocket_connect_handler connect_handler
struct mg_websocket_subprotocols * subprotocols
mg_websocket_data_handler data_handler
mg_websocket_ready_handler ready_handler
const char * default_value
struct mg_header http_headers[MG_MAX_HEADERS]
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]
struct mg_connection * conn
mg_websocket_close_handler close_handler
mg_websocket_data_handler data_handler
struct mg_connection * conn
static void output(int code)