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;
584 struct mg_workerTLS *waiting_thread;
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;
628 static BOOL initialized =
FALSE;
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;
657 d -= (double)tp->tv_sec;
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 *);
719static void path_to_unicode(
const struct mg_connection *conn,
729mg_fgets(
char *buf,
size_t size,
struct mg_file *filep,
char **p);
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,
1270 struct mg_context *ctx,
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,
1322 struct mg_context *ctx,
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,
1377 struct mg_context *ctx,
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)
1502static void mg_vsnprintf(
const struct mg_connection *conn,
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
1562struct mg_workerTLS {
1564 unsigned long thread_idx;
1566 HANDLE pthread_cond_helper_mutex;
1567 struct mg_workerTLS *next_waiting_thread;
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)) {
1618 struct mg_workerTLS *tls =
1619 (
struct mg_workerTLS *)pthread_getspecific(
sTlsKey);
1623 tls = (
struct mg_workerTLS *)
mg_malloc(
sizeof(
struct mg_workerTLS));
1624 tls->is_master = -2;
1626 pthread_setspecific(
sTlsKey, tls);
1628 return tls->thread_idx;
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()
1938static struct ssl_func
ssl_sw[] = {{
"SSL_free", NULL},
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},
1982static struct ssl_func
crypto_sw[] = {{
"ERR_get_error", 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)
2127static struct ssl_func
ssl_sw[] = {{
"SSL_free", NULL},
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},
2171static struct ssl_func
crypto_sw[] = {{
"CRYPTO_num_locks", 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)
2221 struct sockaddr_in
sin;
2222#if defined(USE_IPV6)
2223 struct sockaddr_in6 sin6;
2233struct mg_file_stat {
2236 time_t last_modified;
2243struct mg_file_in_memory {
2249struct mg_file_access {
2252#if defined(MG_USE_OPEN_FILE)
2263 struct mg_file_stat stat;
2264 struct mg_file_access access;
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}, \
2296 unsigned char is_ssl;
2297 unsigned char ssl_redir;
2299 unsigned char in_use;
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");
2527struct mg_handler_info {
2537 unsigned int refcount;
2538 pthread_mutex_t refcount_mutex;
2558 struct mg_handler_info *next;
2570struct mg_domain_context {
2573 struct mg_handler_info *handlers;
2576 uint64_t auth_nonce_mask;
2577 unsigned long nonce_count;
2579#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2581 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2585 struct mg_domain_context *next;
2600 struct socket *listening_sockets;
2601 struct pollfd *listening_socket_fds;
2602 unsigned int num_listening_sockets;
2604 struct mg_connection *worker_connections;
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;
2617 volatile int stop_flag;
2618 pthread_mutex_t thread_mutex;
2620 pthread_t masterthreadid;
2623 pthread_t *worker_threadids;
2626#if defined(ALTERNATIVE_QUEUE)
2627 struct socket *client_socks;
2628 void **client_wait_events;
2631 volatile int sq_head;
2632 volatile int sq_tail;
2638 unsigned int max_request_size;
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;
2659 pthread_mutex_t nonce_mutex;
2672 struct mg_domain_context dd;
2676#if defined(USE_SERVER_STATS)
2677static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2679static struct mg_memory_stat *
2680get_memory_stat(
struct mg_context *ctx)
2683 return &(ctx->ctx_memory);
2685 return &mg_common_memory;
2695struct mg_connection {
2696 int connection_type;
2701 struct mg_context *phys_ctx;
2702 struct mg_domain_context *dom_ctx;
2704#if defined(USE_SERVER_STATS)
2713 struct socket client;
2714 time_t conn_birth_time;
2716 struct timespec req_time;
2718 int64_t num_bytes_sent;
2719 int64_t content_len;
2720 int64_t consumed_content;
2727 size_t chunk_remainder;
2733 int in_error_handler;
2735#if defined(USE_WEBSOCKET)
2736 int in_websocket_handling;
2738 int handled_requests;
2747 time_t last_throttle_time;
2748 int64_t last_throttle_bytes;
2749 pthread_mutex_t mutex;
2751#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2752 void *lua_websocket_state;
2761 struct mg_connection *conn;
2763 struct mg_file_stat
file;
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)
2899 pthread_mutex_t mutex;
2907 struct posix_event *ret =
mg_malloc(
sizeof(
struct posix_event));
2912 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
2917 if (0 != pthread_cond_init(&(ret->cond), NULL)) {
2919 pthread_mutex_destroy(&(ret->mutex));
2930 struct posix_event *ev = (
struct posix_event *)eventhdl;
2931 pthread_mutex_lock(&(ev->mutex));
2932 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2933 pthread_mutex_unlock(&(ev->mutex));
2941 struct posix_event *ev = (
struct posix_event *)eventhdl;
2942 pthread_mutex_lock(&(ev->mutex));
2943 pthread_cond_signal(&(ev->cond));
2944 pthread_mutex_unlock(&(ev->mutex));
2952 struct posix_event *ev = (
struct posix_event *)eventhdl;
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)
3054 struct mg_file *filep,
3057#if defined(MG_USE_OPEN_FILE)
3060 const char *buf = NULL;
3069 if (conn->phys_ctx->callbacks.open_file) {
3070 buf = conn->phys_ctx->callbacks.open_file(conn, path, &size);
3072 if (filep == NULL) {
3083 filep->access.membuf = buf;
3084 filep->access.fp = NULL;
3087 filep->stat.size = size;
3091 filep->stat.last_modified = time(NULL);
3093 filep->stat.is_directory = 0;
3094 filep->stat.is_gzipped = 0;
3098 return (buf != NULL);
3126#if defined(MG_USE_OPEN_FILE)
3127 return (fileacc->membuf != NULL) || (fileacc->fp != NULL);
3129 return (fileacc->fp != NULL);
3134static int mg_stat(
const struct mg_connection *conn,
3136 struct mg_file_stat *filep);
3149 struct mg_file *filep)
3156 filep->access.fp = NULL;
3157#if defined(MG_USE_OPEN_FILE)
3158 filep->access.membuf = NULL;
3165 found =
mg_stat(conn, path, &(filep->stat));
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");
3207 found =
mg_stat(conn, path, &(filep->stat));
3212 return (filep->access.fp != NULL);
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) {
3429 return ctx->dd.config[i];
3433#define mg_get_option DO_NOT_USE_THIS_FUNCTION_INTERNALLY__access_directly
3438 return (conn == NULL) ? (
struct mg_context *)NULL : (conn->phys_ctx);
3445 return (ctx == NULL) ? NULL : ctx->user_data;
3453 conn->request_info.conn_data = data;
3462 return conn->request_info.conn_data;
3468#if defined(MG_LEGACY_INTERFACE)
3471mg_get_ports(
const struct mg_context *ctx,
size_t size,
int *ports,
int *ssl)
3477 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
3478 ssl[i] = ctx->listening_sockets[i].is_ssl;
3480#if defined(USE_IPV6)
3481 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3482 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3485 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
3502 memset(ports, 0,
sizeof(*ports) * (
size_t)size);
3506 if (!ctx->listening_sockets) {
3510 for (i = 0; (i < size) && (i < (
int)ctx->num_listening_sockets); i++) {
3513#if defined(USE_IPV6)
3514 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3515 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3518 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
3519 ports[
cnt].
is_ssl = ctx->listening_sockets[i].is_ssl;
3522 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
3526 }
else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
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;
3651 if ((conn->phys_ctx->callbacks.log_message == NULL)
3652 || (conn->phys_ctx->callbacks.log_message(conn, buf) == 0)) {
3660 fi.access.fp = NULL;
3663 fi.access.fp = NULL;
3666 if (fi.access.fp != NULL) {
3667 flockfile(fi.access.fp);
3668 timestamp = time(NULL);
3671 fprintf(fi.access.fp,
3672 "[%010lu] [error] [client %s] ",
3673 (
unsigned long)timestamp,
3676 if (conn->request_info.request_method != NULL) {
3677 fprintf(fi.access.fp,
3679 conn->request_info.request_method,
3680 conn->request_info.request_uri
3681 ? conn->request_info.request_uri
3685 fprintf(fi.access.fp,
"%s", buf);
3686 fputc(
'\n', fi.access.fp);
3687 fflush(fi.access.fp);
3688 funlockfile(fi.access.fp);
3713mg_cry(
const struct mg_connection *conn,
const char *fmt, ...)
3722#define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
3727static struct mg_connection *
3728fc(
struct mg_context *ctx)
3730 static struct mg_connection fake_connection;
3731 fake_connection.phys_ctx = ctx;
3732 fake_connection.dom_ctx = &(ctx->dd);
3733 return &fake_connection;
3750#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3753 struct mg_workerTLS *tls =
3754 (
struct mg_workerTLS *)pthread_getspecific(
sTlsKey);
3756 sprintf(txt,
"%03i", conn->response_info.status_code);
3757 if (strlen(txt) == 3) {
3758 memcpy(tls->txtbuf, txt, 4);
3760 strcpy(tls->txtbuf,
"ERR");
3763 ((
struct mg_connection *)conn)->request_info.local_uri =
3764 ((
struct mg_connection *)conn)->request_info.request_uri =
3767 ((
struct mg_connection *)conn)->request_info.num_headers =
3768 conn->response_info.num_headers;
3769 memcpy(((
struct mg_connection *)conn)->request_info.http_headers,
3770 conn->response_info.http_headers,
3771 sizeof(conn->response_info.http_headers));
3777 return &conn->request_info;
3790 return &conn->response_info;
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)
3862 : htons(conn->client.lsa.sin.sin_port);
3864 int port = htons(conn->client.lsa.sin.sin_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)
4023 return get_header(conn->request_info.http_headers,
4024 conn->request_info.num_headers,
4028 return get_header(conn->response_info.http_headers,
4029 conn->response_info.num_headers,
4044 return conn->request_info.http_version;
4047 return conn->response_info.http_version;
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));
4086 end = (int)val->len - 1;
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) {
4167 res =
match_prefix(pattern + i, pattern_len - i, str + j + 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;
4188 if ((conn == NULL) || conn->must_close) {
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]) {
4308 struct mg_file *filep);
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)) {
4534 conn->status_code = status;
4537 has_body = ((status > 199) && (status != 204) && (status != 304));
4541 || (!conn->in_error_handler
4542 && (conn->phys_ctx->callbacks.http_error != NULL))) {
4545 mg_vsnprintf(conn, NULL, errmsg_buf,
sizeof(errmsg_buf), fmt, ap);
4548 DEBUG_TRACE(
"Error %i - [%s]", status, errmsg_buf);
4554 if (!conn->in_error_handler
4555 && (conn->phys_ctx->callbacks.http_error != NULL)) {
4557 conn->in_error_handler = 1;
4558 handled_by_callback =
4559 (conn->phys_ctx->callbacks.http_error(conn, status, errmsg_buf)
4561 conn->in_error_handler = 0;
4564 if (!handled_by_callback) {
4566 if (conn->in_error_handler) {
4568 "Recursion when handling error %u - fall back to default",
4572 error_handler = conn->dom_ctx->config[
ERROR_PAGES];
4573 error_page_file_ext = conn->dom_ctx->config[
INDEX_FILES];
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) {
4647 conn->in_error_handler = 1;
4649 conn->in_error_handler = 0;
4657 conn->must_close = 1;
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,
4833 if (0 != strcmp(conn->request_info.request_method,
"HEAD")) {
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,
4919 struct mg_workerTLS **ptls,
4920 *tls = (
struct mg_workerTLS *)pthread_getspecific(
sTlsKey);
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'));
5111path_to_unicode(
const struct mg_connection *conn,
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) {
5144 if (conn->dom_ctx->config[CASE_SENSITIVE_FILES]
5145 && !
mg_strcasecmp(conn->dom_ctx->config[CASE_SENSITIVE_FILES],
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;
5194mg_stat(
const struct mg_connection *conn,
5196 struct mg_file_stat *filep)
5198 wchar_t wbuf[W_PATH_MAX];
5199 WIN32_FILE_ATTRIBUTE_DATA info;
5200 time_t creation_time;
5205 memset(filep, 0,
sizeof(*filep));
5215 filep->size = tmp_file.stat.size;
5216 filep->location = 2;
5224 filep->last_modified = time(NULL);
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);
5239 filep->last_modified =
5240 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
5241 info.ftLastWriteTime.dwHighDateTime);
5247 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
5248 info.ftCreationTime.dwHighDateTime);
5249 if (creation_time > filep->last_modified) {
5250 filep->last_modified = creation_time;
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));
5271mg_remove(
const struct mg_connection *conn,
const char *path)
5273 wchar_t wbuf[W_PATH_MAX];
5274 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
5275 return DeleteFileW(wbuf) ? 0 : -1;
5280mg_mkdir(
const struct mg_connection *conn,
const char *path,
int mode)
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);
5793 struct mg_file_stat *filep)
5799 memset(filep, 0,
sizeof(*filep));
5807 filep->size = tmp_file.stat.size;
5808 filep->last_modified = time(NULL);
5809 filep->location = 2;
5815 if (0 == stat(path, &st)) {
5816 filep->size = (uint64_t)(st.st_size);
5817 filep->last_modified = st.st_mtime;
5818 filep->is_directory = S_ISDIR(st.st_mode);
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",
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) {
6193 if (ctx->stop_flag) {
6197 if ((
n > 0) || ((
n == 0) && (len == 0))) {
6223 struct pollfd pfd[1];
6227 pfd[0].events = POLLOUT;
6228 pollres =
mg_poll(pfd, 1, (
int)(ms_wait), &(ctx->stop_flag));
6229 if (ctx->stop_flag) {
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) {
6299 struct mg_connection *conn,
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)
6339 && ((ssl_pending =
SSL_pending(conn->ssl)) > 0)) {
6343 if (ssl_pending > len) {
6346 nread =
SSL_read(conn->ssl, buf, ssl_pending);
6362 }
else if (conn->ssl != NULL) {
6364 struct pollfd pfd[1];
6367 pfd[0].fd = conn->client.sock;
6368 pfd[0].events = POLLIN;
6371 (
int)(timeout * 1000.0),
6372 &(conn->phys_ctx->stop_flag));
6373 if (conn->phys_ctx->stop_flag) {
6377 nread =
SSL_read(conn->ssl, buf, len);
6393 }
else if (pollres < 0) {
6403 struct pollfd pfd[1];
6406 pfd[0].fd = conn->client.sock;
6407 pfd[0].events = POLLIN;
6410 (
int)(timeout * 1000.0),
6411 &(conn->phys_ctx->stop_flag));
6412 if (conn->phys_ctx->stop_flag) {
6416 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
6417 err = (nread < 0) ?
ERRNO : 0;
6422 }
else if (pollres < 0) {
6431 if (conn->phys_ctx->stop_flag) {
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)) {
6489pull_all(FILE *fp,
struct mg_connection *conn,
char *buf,
int len)
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);
6503 while ((len > 0) && (conn->phys_ctx->stop_flag == 0)) {
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) {
6522 conn->consumed_content +=
n;
6543 to_read =
sizeof(buf);
6545 if (conn->is_chunked) {
6548 while (conn->is_chunked != 3) {
6549 nread =
mg_read(conn, buf, to_read);
6557 while (conn->consumed_content < conn->content_len) {
6559 > (
size_t)(conn->content_len - conn->consumed_content)) {
6560 to_read = (size_t)(conn->content_len - conn->consumed_content);
6563 nread =
mg_read(conn, buf, to_read);
6575 int64_t
n, buffered_len, nread;
6577 (int64_t)((len > INT_MAX) ? INT_MAX : len);
6589 if (conn->consumed_content == 0) {
6590 if (conn->is_chunked == 1) {
6591 conn->content_len = len64;
6592 conn->is_chunked = 2;
6593 }
else if (conn->content_len == -1) {
6597 conn->must_close = 1;
6602 if (conn->consumed_content < conn->content_len) {
6604 int64_t left_to_read = conn->content_len - conn->consumed_content;
6605 if (left_to_read < len64) {
6609 len64 = left_to_read;
6613 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
6614 - conn->consumed_content;
6615 if (buffered_len > 0) {
6616 if (len64 < buffered_len) {
6617 buffered_len = len64;
6619 body = conn->buf + conn->request_len + conn->consumed_content;
6620 memcpy(buf, body, (
size_t)buffered_len);
6621 len64 -= buffered_len;
6622 conn->consumed_content += 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);
6655mg_read(
struct mg_connection *conn,
void *buf,
size_t len)
6657 if (len > INT_MAX) {
6665 if (conn->is_chunked) {
6666 size_t all_read = 0;
6669 if (conn->is_chunked == 3) {
6674 if (conn->chunk_remainder) {
6678 ((conn->chunk_remainder > len) ? (len)
6679 : (conn->chunk_remainder));
6681 conn->content_len += (int)read_now;
6690 all_read += (size_t)read_ret;
6691 conn->chunk_remainder -= (size_t)read_ret;
6692 len -= (size_t)read_ret;
6694 if (conn->chunk_remainder == 0) {
6698 conn->content_len += 2;
6701 if ((
x1 !=
'\r') || (
x2 !=
'\n')) {
6712 unsigned long chunkSize = 0;
6714 for (i = 0; i < ((int)
sizeof(lenbuf) - 1); i++) {
6715 conn->content_len++;
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) {
6727 conn->is_chunked = 3;
6731 if (!isxdigit(lenbuf[i])) {
6736 if ((end == NULL) || (*end !=
'\r')) {
6740 if (chunkSize == 0) {
6744 conn->chunk_remainder = chunkSize;
6748 return (
int)all_read;
6755mg_write(
struct mg_connection *conn,
const void *buf,
size_t len)
6758 int64_t
n,
total, allowed;
6764 if (conn->throttle > 0) {
6765 if ((now = time(NULL)) != conn->last_throttle_time) {
6766 conn->last_throttle_time = now;
6767 conn->last_throttle_bytes = 0;
6769 allowed = conn->throttle - conn->last_throttle_bytes;
6770 if (allowed > (int64_t)len) {
6771 allowed = (int64_t)len;
6780 buf = (
const char *)buf +
total;
6781 conn->last_throttle_bytes +=
total;
6782 while ((
total < (int64_t)len) && (conn->phys_ctx->stop_flag == 0)) {
6783 allowed = (conn->throttle > ((int64_t)len -
total))
6784 ? (int64_t)len -
total
6796 conn->last_throttle_bytes = allowed;
6797 conn->last_throttle_time = time(NULL);
6798 buf = (
const char *)buf +
n;
6811 conn->num_bytes_sent +=
total;
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
6961mg_vprintf(
struct mg_connection *conn,
const char *fmt, va_list ap)
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);
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;
7243 const char *
s = conn->request_info.request_method;
7245 && (!strcmp(
s,
"PUT") || !strcmp(
s,
"DELETE")
7246 || !strcmp(
s,
"MKCOL") || !strcmp(
s,
"PATCH"));
7252#if !defined(NO_FILES)
7255 struct mg_connection *conn,
7256 const char *filename
7268 if (
match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
7269 strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
7275#if defined(USE_DUKTAPE)
7276 if (
match_prefix(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
7277 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
7299 struct mg_file_stat *filestat)
7301 const char *list = conn->dom_ctx->config[
INDEX_FILES];
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))) {
7323 mg_strlcpy(path +
n + 1, filename_vec.ptr, filename_vec.len + 1);
7326 if (
mg_stat(conn, path, filestat)) {
7346 size_t filename_buf_len,
7347 struct mg_file_stat *filestat,
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)
7357 const char *uri = conn->request_info.local_uri;
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]) {
7388 root = conn->dom_ctx->config[WEBSOCKET_ROOT];
7392 *is_websocket_request = 0;
7396 conn->accept_gzip = 0;
7397 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
7398 if (strstr(accept_encoding,
"gzip") != NULL) {
7399 conn->accept_gzip = 1;
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);
7473 if (filestat->is_directory && is_uri_end_slash) {
7476 struct mg_file_stat tmp_filestat;
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);
7508 if (conn->accept_gzip) {
7510 conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", filename);
7513 goto interpret_cleanup;
7516 if (
mg_stat(conn, gz_path, filestat)) {
7518 filestat->is_gzipped = 1;
7526#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7529 tmp_str_len = strlen(filename);
7530 tmp_str = (
char *)
mg_malloc_ctx(tmp_str_len + PATH_MAX + 1, conn->phys_ctx);
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;
7610 conn->path_info = 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;
7945 vec->len = strlen(vec->ptr);
7952bin2str(
char *to,
const unsigned char *p,
size_t 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,
8036 struct mg_file *filep)
8038 if ((conn != NULL) && (conn->dom_ctx != NULL)) {
8039 char name[PATH_MAX];
8044 if (gpass != NULL) {
8057 }
else if (
mg_stat(conn, path, &filep->stat)
8058 && filep->stat.is_directory) {
8078 for (p = path,
e = p + strlen(p) - 1;
e > p;
e--) {
8108 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
8119 char *
name, *value, *
s;
8120 const char *auth_header;
8127 (
void)memset(ah, 0,
sizeof(*ah));
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")) {
8165 ah->response = value;
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)
8179 if (ah->nonce == NULL) {
8183 nonce = strtoull(ah->nonce, &
s, 10);
8184 if ((
s == NULL) || (*
s != 0)) {
8189 nonce ^= conn->dom_ctx->auth_nonce_mask;
8199 if (nonce < (uint64_t)conn->phys_ctx->start_time) {
8206 if (nonce >= ((uint64_t)conn->phys_ctx->start_time
8207 + conn->dom_ctx->nonce_count)) {
8215 if (ah->user != NULL) {
8216 conn->request_info.remote_user =
8227mg_fgets(
char *buf,
size_t size,
struct mg_file *filep,
char **p)
8229#if defined(MG_USE_OPEN_FILE)
8241#if defined(MG_USE_OPEN_FILE)
8242 if ((filep->access.membuf != NULL) && (*p != NULL)) {
8243 memend = (
const char *)&filep->access.membuf[filep->stat.size];
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;
8259 if (filep->access.fp != NULL) {
8260 return fgets(buf, (
int)size, filep->access.fp);
8272#define INITIAL_DEPTH 9
8273#if INITIAL_DEPTH <= 0
8274#error Bad INITIAL_DEPTH for recursion, set to at least 1
8277struct read_auth_file_struct {
8278 struct mg_connection *conn;
8281 char buf[256 + 256 + 40];
8283 const char *f_domain;
8290 struct read_auth_file_struct *workdata,
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;
8320 workdata->f_user = workdata->buf;
8322 if (workdata->f_user[0] ==
':') {
8326 if (workdata->f_user[1] ==
'#') {
8329 }
else if (!strncmp(workdata->f_user + 1,
"include=", 8)) {
8331 workdata->f_user + 9,
8342 if (is_authorized) {
8343 return is_authorized;
8347 "%s: cannot open authorization file: %s",
8356 "%s: syntax error in authorization file: %s",
8362 workdata->f_domain = strchr(workdata->f_user,
':');
8363 if (workdata->f_domain == NULL) {
8365 "%s: syntax error in authorization file: %s",
8370 *(
char *)(workdata->f_domain) = 0;
8371 (workdata->f_domain)++;
8373 workdata->f_ha1 = strchr(workdata->f_domain,
':');
8374 if (workdata->f_ha1 == NULL) {
8376 "%s: syntax error in authorization file: %s",
8381 *(
char *)(workdata->f_ha1) = 0;
8382 (workdata->f_ha1)++;
8384 if (!strcmp(workdata->ah.user, workdata->f_user)
8385 && !strcmp(workdata->domain, workdata->f_domain)) {
8386 return check_password(workdata->conn->request_info.request_method,
8391 workdata->ah.cnonce,
8393 workdata->ah.response);
8397 return is_authorized;
8403authorize(
struct mg_connection *conn,
struct mg_file *filep,
const char *realm)
8405 struct read_auth_file_struct workdata;
8408 if (!conn || !conn->dom_ctx) {
8412 memset(&workdata, 0,
sizeof(workdata));
8413 workdata.conn = conn;
8420 workdata.domain = realm;
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) {
8469 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
8475 (
int)filename_vec.len,
8481 "%s: cannot open %s: %s",
8508 time_t curtime = time(NULL);
8509 uint64_t nonce = (uint64_t)(conn->phys_ctx->start_time);
8515 (
void)pthread_mutex_lock(&conn->phys_ctx->nonce_mutex);
8516 nonce += conn->dom_ctx->nonce_count;
8517 ++conn->dom_ctx->nonce_count;
8518 (
void)pthread_mutex_unlock(&conn->phys_ctx->nonce_mutex);
8520 nonce ^= conn->dom_ctx->auth_nonce_mask;
8521 conn->status_code = 401;
8522 conn->must_close = 1;
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\", "
8549 if (conn && conn->dom_ctx) {
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");
8807 if (
mg_inet_pton(AF_INET, host, &sa->sin,
sizeof(sa->sin))) {
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;
8924 pollres =
mg_poll(pfd, 1, (
int)(ms_wait), &(ctx->stop_flag));
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;
9012 if (de->file.is_directory) {
9022 if (de->file.size < 1024) {
9028 (
int)de->file.size);
9029 }
else if (de->file.size < 0x100000) {
9035 (
double)de->file.size / 1024.0);
9036 }
else if (de->file.size < 0x40000000) {
9042 (
double)de->file.size / 1048576);
9049 (
double)de->file.size / 1073741824);
9056#if defined(REENTRANT_TIME)
9057 localtime_r(&de->file.last_modified, tm);
9059 tm = localtime(&de->file.last_modified);
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",
9071 de->conn->request_info.local_uri,
9073 de->file.is_directory ?
"/" :
"",
9075 de->file.is_directory ?
"/" :
"",
9091 const struct de *
a = (
const struct de *)p1, *
b = (
const struct de *)p2;
9092 const char *query_string =
a->conn->request_info.query_string;
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;
9126 if (conn && conn->dom_ctx) {
9128 const char *pattern = conn->dom_ctx->config[
HIDE_FILES];
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];
9149 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
9156 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")
9162 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
9169 memset(&de.file, 0,
sizeof(de.file));
9176 if (!
mg_stat(conn, path, &de.file)) {
9178 "%s: mg_stat(%s) failed: %s",
9183 de.file_name = dp->d_name;
9192#if !defined(NO_FILES)
9196 char path[PATH_MAX];
9203 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
9211 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")) {
9216 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
9223 memset(&de.file, 0,
sizeof(de.file));
9231 if (!
mg_stat(conn, path, &de.file)) {
9233 "%s: mg_stat(%s) failed: %s",
9240 if (de.file.is_directory) {
9261struct dir_scan_data {
9263 unsigned int num_entries;
9264 unsigned int arr_size;
9273 if (new_ptr == NULL) {
9283 struct dir_scan_data *dsd = (
struct dir_scan_data *)data;
9285 if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
9288 (
struct de *)
realloc2(dsd->entries,
9289 dsd->arr_size *
sizeof(dsd->entries[0]));
9291 if (dsd->entries == NULL) {
9293 dsd->num_entries = 0;
9295 dsd->entries[dsd->num_entries].file_name =
mg_strdup(de->file_name);
9296 dsd->entries[dsd->num_entries].file = de->file;
9297 dsd->entries[dsd->num_entries].conn = de->conn;
9310 struct dir_scan_data data = {NULL, 0, 128};
9312 time_t curtime = time(NULL);
9317 "Error: Cannot open directory\nopendir(%s): %s",
9329 sort_direction = ((conn->request_info.query_string != NULL)
9330 && (conn->request_info.query_string[1] ==
'd'))
9334 conn->must_close = 1;
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>",
9351 conn->request_info.local_uri,
9352 conn->request_info.local_uri,
9359 "<tr><td><a href=\"%s%s\">%s</a></td>"
9360 "<td> %s</td><td> %s</td></tr>\n",
9361 conn->request_info.local_uri,
9368 if (data.entries != NULL) {
9370 (
size_t)data.num_entries,
9371 sizeof(data.entries[0]),
9373 for (i = 0; i < data.num_entries; i++) {
9375 mg_free(data.entries[i].file_name);
9380 mg_printf(conn,
"%s",
"</table></body></html>");
9381 conn->status_code = 200;
9388 struct mg_file *filep,
9393 int to_read, num_read, num_written;
9396 if (!filep || !conn) {
9402 : (int64_t)(filep->stat.size);
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;
9411 mg_write(conn, filep->access.membuf + offset, (
size_t)len);
9414 if (len > 0 && filep->access.fp != NULL) {
9416#if defined(__linux__)
9418 if ((conn->ssl == 0) && (conn->throttle == 0)
9419 && (!
mg_strcasecmp(conn->dom_ctx->config[ALLOW_SENDFILE_CALL],
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)) {
9515 (
unsigned long)filestat->last_modified,
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"
9547 struct mg_file *filep,
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)) {
9574 is_head_request = !strcmp(conn->request_info.request_method,
"HEAD");
9585 "Error: File size is too large to send\n%" INT64_FMT,
9589 cl = (int64_t)filep->stat.size;
9590 conn->status_code = 200;
9593#
if defined(USE_ZLIB)
9597 if (!conn->accept_gzip) {
9598 allow_on_the_fly_compression = 0;
9602 if (filep->stat.is_gzipped) {
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)) {
9641 if (filep->stat.is_gzipped) {
9646 "Error: Range requests in gzipped files are not supported");
9651 conn->status_code = 206;
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)
9793 const struct mg_file_stat *filestat)
9807 struct mg_file *filep)
9809 char date[64], lm[64], etag[64];
9810 time_t curtime = time(NULL);
9812 if ((conn == NULL) || (filep == NULL)) {
9815 conn->status_code = 304;
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");
9903put_dir(
struct mg_connection *conn,
const char *path)
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",
9960 if (conn->consumed_content != 0) {
9980 ret =
mg_read(conn, buf,
sizeof(buf));
9982 n = (int)fwrite(buf, 1, (
size_t)ret, fi.access.fp);
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;
10108struct mg_http_method_info {
10110 int request_has_body;
10111 int response_has_body;
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}
10175static const struct mg_http_method_info *
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;
10406 struct mg_connection *conn,
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));
10423 request_timeout = atof(conn->dom_ctx->config[
REQUEST_TIMEOUT]) / 1000.0;
10425 request_timeout = -1.0;
10427 if (conn->handled_requests > 0) {
10437 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
10439 while (request_len == 0) {
10441 if (conn->phys_ctx->stop_flag != 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;
10502 if ((conn->content_len == -1) && (!conn->is_chunked)) {
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");
10519 conn->status_code = 100;
10521 conn->status_code = 200;
10524 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
10525 - conn->consumed_content;
10530 if ((buffered_len < 0) || (conn->consumed_content != 0)) {
10535 if (buffered_len > 0) {
10536 if ((int64_t)buffered_len > conn->content_len) {
10537 buffered_len = (int)conn->content_len;
10539 body = conn->buf + conn->request_len + conn->consumed_content;
10541 conn->phys_ctx, fp, sock, ssl, body, (int64_t)buffered_len);
10542 conn->consumed_content += buffered_len;
10546 while (conn->consumed_content < conn->content_len) {
10547 to_read =
sizeof(buf);
10548 if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
10549 to_read = (int)(conn->content_len - conn->consumed_content);
10551 nread =
pull_inner(NULL, conn, buf, to_read, timeout);
10557 if (
push_all(conn->phys_ctx, fp, sock, ssl, buf, nread)
10562 conn->consumed_content += nread;
10565 if (conn->consumed_content == conn->content_len) {
10566 success = (nread >= 0);
10583#if defined(USE_TIMERS)
10585#define TIMER_API static
10586#include "timer.inl"
10591#if !defined(NO_CGI)
10602struct cgi_environment {
10603 struct mg_connection *conn;
10622addenv(struct cgi_environment *env, const
char *fmt, ...)
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;
10694 struct cgi_environment *env)
10697 struct vec var_vec;
10699 int i, truncated, uri_len;
10701 if ((conn == NULL) || (prog == NULL) || (env == NULL)) {
10708 env->buf = (
char *)
mg_malloc_ctx(env->buflen, conn->phys_ctx);
10709 if (env->buf == NULL) {
10711 "%s: Not enough memory for environmental buffer",
10718 (
char **)
mg_malloc_ctx(env->buflen *
sizeof(
char *), conn->phys_ctx);
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)
10738 if (conn->client.lsa.sa.sa_family == AF_INET6) {
10739 addenv(env,
"SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
10743 addenv(env,
"SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
10747 addenv(env,
"REMOTE_ADDR=%s", src_addr);
10749 addenv(env,
"REQUEST_METHOD=%s", conn->request_info.request_method);
10750 addenv(env,
"REMOTE_PORT=%d", conn->request_info.remote_port);
10752 addenv(env,
"REQUEST_URI=%s", conn->request_info.request_uri);
10753 addenv(env,
"LOCAL_URI=%s", conn->request_info.local_uri);
10756 uri_len = (int)strlen(conn->request_info.local_uri);
10757 if (conn->path_info == NULL) {
10758 if (conn->request_info.local_uri[uri_len - 1] !=
'/') {
10760 addenv(env,
"SCRIPT_NAME=%s", conn->request_info.local_uri);
10763 const char *index_file = strrchr(prog,
'/');
10766 "SCRIPT_NAME=%s%s",
10767 conn->request_info.local_uri,
10774 "SCRIPT_NAME=%.*s",
10775 uri_len - (
int)strlen(conn->path_info),
10776 conn->request_info.local_uri);
10779 addenv(env,
"SCRIPT_FILENAME=%s", prog);
10780 if (conn->path_info == NULL) {
10784 "PATH_TRANSLATED=%s%s",
10789 addenv(env,
"HTTPS=%s", (conn->ssl == NULL) ?
"off" :
"on");
10792 addenv(env,
"CONTENT_TYPE=%s",
s);
10794 if (conn->request_info.query_string != NULL) {
10795 addenv(env,
"QUERY_STRING=%s", conn->request_info.query_string);
10798 addenv(env,
"CONTENT_LENGTH=%s",
s);
10800 if ((
s = getenv(
"PATH")) != NULL) {
10803 if (conn->path_info != NULL) {
10804 addenv(env,
"PATH_INFO=%s", conn->path_info);
10807 if (conn->status_code > 0) {
10809 addenv(env,
"STATUS=%d", conn->status_code);
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);
10838 if (conn->request_info.remote_user != NULL) {
10839 addenv(env,
"REMOTE_USER=%s", conn->request_info.remote_user);
10840 addenv(env,
"%s",
"AUTH_TYPE=Digest");
10844 for (i = 0; i < conn->request_info.num_headers; i++) {
10849 sizeof(http_var_name),
10851 conn->request_info.http_headers[i].name);
10855 "%s: HTTP header variable too long [%s]",
10857 conn->request_info.http_headers[i].name);
10862 for (p = http_var_name; *p !=
'\0'; p++) {
10866 *p = (char)toupper(*(
unsigned char *)p);
10872 conn->request_info.http_headers[i].value);
10878 addenv(env,
"%.*s", (
int)var_vec.len, var_vec.ptr);
10881 env->var[env->varused] = NULL;
10882 env->buf[env->bufused] =
'\0';
10889struct process_control_data {
10900 struct process_control_data *proc = (
struct process_control_data *)data;
10905 ret_pid = waitpid(proc->pid, &status, WNOHANG);
10906 if ((ret_pid != (pid_t)-1) && (status == 0)) {
10908 DEBUG_TRACE(
"CGI timer: Stop child process %p\n", proc->pid);
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;
10938 struct cgi_environment
blk;
10939 FILE *in = NULL, *out = NULL, *err = NULL;
10941 pid_t pid = (pid_t)-1;
10942 struct process_control_data *proc = NULL;
10944#if defined(USE_TIMERS)
10945 double cgi_timeout = -1.0;
10946 if (conn->dom_ctx->config[CGI_TIMEOUT]) {
10948 cgi_timeout = atof(conn->dom_ctx->config[CGI_TIMEOUT]) * 0.001;
10952 if (conn == NULL) {
10957 buflen = conn->phys_ctx->max_request_size;
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",
10998 proc = (
struct process_control_data *)
10999 mg_malloc_ctx(
sizeof(
struct process_control_data), conn->phys_ctx);
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",
11028 proc->references = 1;
11030#if defined(USE_TIMERS)
11031 if (cgi_timeout > 0.0) {
11032 proc->references = 2;
11035 timer_add(conn->phys_ctx,
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",
11103 fout.access.fp = out;
11105 if ((conn->request_info.content_length != 0) || (conn->is_chunked)) {
11107 (
signed long long)conn->request_info.content_length);
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";
11199 conn->status_code = atoi(status);
11200 status_text = status;
11201 while (isdigit(*(
const unsigned char *)status_text)
11202 || *status_text ==
' ') {
11207 conn->status_code = 307;
11209 conn->status_code = 200;
11214 conn->must_close = 1;
11217 DEBUG_TRACE(
"CGI: response %u %s", conn->status_code, status_text);
11219 (
void)
mg_printf(conn,
"HTTP/1.1 %d %s\r\n", conn->status_code, 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)
11280mkcol(
struct mg_connection *conn,
const char *path)
11285 time_t curtime = time(NULL);
11287 if (conn == NULL) {
11294 memset(&de.file, 0,
sizeof(de.file));
11295 if (!
mg_stat(conn, path, &de.file)) {
11297 "%s: mg_stat(%s) failed: %s",
11303 if (de.file.last_modified) {
11308 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11312 body_len = conn->data_len - conn->request_len;
11313 if (body_len > 0) {
11315 conn, 415,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
11322 conn->status_code = 201;
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) {
11369 conn->status_code = 200;
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) {
11395 conn->status_code = 200;
11401 "Error: Put not possible\nReplacing %s is not allowed",
11408 conn->status_code = 201;
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",
11470 conn->status_code = 206;
11471 fseeko(
file.access.fp, r1, SEEK_SET);
11485 conn->status_code = 507;
11490 "HTTP/1.1 %d %s\r\n",
11497 "Content-Length: 0\r\n"
11498 "Connection: %s\r\n\r\n",
11508 memset(&de.file, 0,
sizeof(de.file));
11509 if (!
mg_stat(conn, path, &de.file)) {
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",
11530 if (de.file.is_directory) {
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",
11570send_ssi_file(
struct mg_connection *,
const char *,
struct mg_file *,
int);
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];
11698 if (filep->access.fp != NULL) {
11699 return fgetc(filep->access.fp);
11709 struct mg_file *filep,
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)) {
11815 struct mg_file *filep)
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",
11843 conn->must_close = 1;
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);
11876 conn->status_code = 200;
11877 conn->must_close = 1;
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"
11901 struct mg_file_stat *filep)
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>"
11923 filep->is_directory ?
"<d:collection/>" :
"",
11932 char href[PATH_MAX];
11935 struct mg_connection *conn = (
struct mg_connection *)data;
11936 if (!de || !conn) {
11944 conn->request_info.local_uri,
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) {
11968 struct mg_file_stat *filep)
11972 time_t curtime = time(NULL);
11976 if (!conn || !path || !filep || !conn->dom_ctx) {
11980 conn->must_close = 1;
11981 conn->status_code = 207;
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");
11998 print_props(conn, conn->request_info.local_uri, filep);
12002 if (filep->is_directory
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);
12033 (
void)pthread_mutex_lock(&ctx->nonce_mutex);
12041 (
void)pthread_mutex_unlock(&ctx->nonce_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#define SHA_API static
12062send_websocket_handshake(
struct mg_connection *conn,
const char *websock_key)
12064 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
12065 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
12070 mg_snprintf(conn, &truncated, buf,
sizeof(buf),
"%s%s", websock_key, magic);
12072 conn->must_close = 1;
12079 SHA1_Update(&sha_ctx, (
unsigned char *)buf, (uint32_t)strlen(buf));
12081 base64_encode((
unsigned char *)sha,
sizeof(sha), b64_sha);
12083 "HTTP/1.1 101 Switching Protocols\r\n"
12084 "Upgrade: websocket\r\n"
12085 "Connection: Upgrade\r\n"
12086 "Sec-WebSocket-Accept: %s\r\n",
12088 if (conn->request_info.acceptedWebSocketSubprotocol) {
12090 "Sec-WebSocket-Protocol: %s\r\n\r\n",
12091 conn->request_info.acceptedWebSocketSubprotocol);
12100#if !defined(MG_MAX_UNANSWERED_PING)
12106#define MG_MAX_UNANSWERED_PING (5)
12111read_websocket(
struct mg_connection *conn,
12113 void *callback_data)
12119 unsigned char *buf = (
unsigned char *)conn->buf + conn->request_len;
12120 int n, error, exit_by_callback;
12127 size_t i, len, mask_len = 0, header_len, body_len;
12128 uint64_t data_len = 0;
12133 unsigned char mask[4];
12138 unsigned char mem[4096];
12143 double timeout = -1.0;
12144 int enable_ping_pong = 0;
12145 int ping_count = 0;
12147 if (conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG]) {
12149 !
mg_strcasecmp(conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG],
12153 if (conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) {
12154 timeout = atoi(conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
12161 DEBUG_TRACE(
"Websocket connection %s:%u start data processing loop",
12162 conn->request_info.remote_addr,
12163 conn->request_info.remote_port);
12164 conn->in_websocket_handling = 1;
12169 while (!conn->phys_ctx->stop_flag && !conn->must_close) {
12172 if ((body_len = (
size_t)(conn->data_len - conn->request_len)) >= 2) {
12173 len = buf[1] & 127;
12174 mask_len = (buf[1] & 128) ? 4 : 0;
12175 if ((len < 126) && (body_len >= mask_len)) {
12178 header_len = 2 + mask_len;
12179 }
else if ((len == 126) && (body_len >= (4 + mask_len))) {
12181 header_len = 4 + mask_len;
12182 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
12183 }
else if (body_len >= (10 + mask_len)) {
12186 memcpy(&l1, &buf[2], 4);
12187 memcpy(&l2, &buf[6], 4);
12188 header_len = 10 + mask_len;
12189 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
12191 if (data_len > (uint64_t)0x7FFF0000ul) {
12196 "websocket out of memory; closing connection");
12202 if ((header_len > 0) && (body_len >= header_len)) {
12204 unsigned char *data = mem;
12206 if ((
size_t)data_len > (
size_t)
sizeof(mem)) {
12209 if (data == NULL) {
12215 "websocket out of memory; closing connection");
12221 if (mask_len > 0) {
12222 memcpy(mask, buf + header_len - mask_len,
sizeof(mask));
12224 memset(mask, 0,
sizeof(mask));
12230 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
12233 len = body_len - header_len;
12234 memcpy(data, buf + header_len, len);
12236 while ((uint64_t)len < data_len) {
12239 (
char *)(data + len),
12240 (
int)(data_len - len),
12245 }
else if (
n > 0) {
12256 "Websocket pull failed; closing connection");
12263 conn->data_len = conn->request_len;
12273 len = (size_t)data_len + header_len;
12278 memcpy(data, buf + header_len, (
size_t)data_len);
12281 memmove(buf, buf + len, body_len - len);
12284 conn->data_len -= (int)len;
12288 if (mask_len > 0) {
12289 for (i = 0; i < (size_t)data_len; i++) {
12290 data[i] ^= mask[i & 3];
12294 exit_by_callback = 0;
12298 conn->request_info.remote_addr,
12299 conn->request_info.remote_port);
12302 }
else if (enable_ping_pong
12306 conn->request_info.remote_addr,
12307 conn->request_info.remote_port);
12322 if ((ws_data_handler != NULL)
12323 && !ws_data_handler(conn,
12328 exit_by_callback = 1;
12337 if (exit_by_callback) {
12338 DEBUG_TRACE(
"Callback requests to close connection from %s:%u",
12339 conn->request_info.remote_addr,
12340 conn->request_info.remote_port);
12345 DEBUG_TRACE(
"Message requests to close connection from %s:%u",
12346 conn->request_info.remote_addr,
12347 conn->request_info.remote_port);
12357 conn->buf + conn->data_len,
12358 conn->buf_size - conn->data_len,
12363 conn->request_info.remote_addr,
12364 conn->request_info.remote_port);
12368 conn->data_len +=
n;
12372 if (!conn->phys_ctx->stop_flag && !conn->must_close) {
12373 if (ping_count > MG_MAX_UNANSWERED_PING) {
12375 DEBUG_TRACE(
"Too many (%i) unanswered ping from %s:%u "
12376 "- closing connection",
12378 conn->request_info.remote_addr,
12379 conn->request_info.remote_port);
12382 if (enable_ping_pong) {
12385 conn->request_info.remote_addr,
12386 conn->request_info.remote_port);
12408 conn->in_websocket_handling = 0;
12409 DEBUG_TRACE(
"Websocket connection %s:%u left data processing loop",
12410 conn->request_info.remote_addr,
12411 conn->request_info.remote_port);
12416mg_websocket_write_exec(
struct mg_connection *conn,
12420 uint32_t masking_key)
12422 unsigned char header[14];
12426#if defined(GCC_DIAGNOSTIC)
12428#pragma GCC diagnostic push
12429#pragma GCC diagnostic ignored "-Wconversion"
12432 header[0] = 0x80u | (
unsigned char)((
unsigned)opcode & 0xf);
12434#if defined(GCC_DIAGNOSTIC)
12435#pragma GCC diagnostic pop
12439 if (dataLen < 126) {
12441 header[1] = (
unsigned char)dataLen;
12443 }
else if (dataLen <= 0xFFFF) {
12445 uint16_t len = htons((uint16_t)dataLen);
12447 memcpy(header + 2, &len, 2);
12451 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
12452 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
12454 memcpy(header + 2, &len1, 4);
12455 memcpy(header + 6, &len2, 4);
12462 memcpy(header + headerLen, &masking_key, 4);
12479 retval =
mg_write(conn, header, headerLen);
12480 if (retval != (
int)headerLen) {
12485 retval =
mg_write(conn, data, dataLen);
12502 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
12507mask_data(
const char *in,
size_t in_len, uint32_t masking_key,
char *out)
12512 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
12514 while (i < (in_len - 3)) {
12515 *(uint32_t *)(
void *)(out + i) =
12516 *(uint32_t *)(
void *)(in + i) ^ masking_key;
12522 while (i < in_len) {
12523 *(uint8_t *)(
void *)(out + i) =
12524 *(uint8_t *)(
void *)(in + i)
12525 ^ *(((uint8_t *)&masking_key) + (i % 4));
12539 char *masked_data =
12540 (
char *)
mg_malloc_ctx(((dataLen + 7) / 4) * 4, conn->phys_ctx);
12541 uint32_t masking_key = 0;
12543 if (masked_data == NULL) {
12547 "Cannot allocate buffer for masked websocket response: "
12555 }
while (masking_key == 0);
12557 mask_data(data, dataLen, masking_key, masked_data);
12559 retval = mg_websocket_write_exec(
12560 conn, opcode, masked_data, dataLen, masking_key);
12568handle_websocket_request(
struct mg_connection *conn,
12570 int is_callback_resource,
12578 const char *websock_key =
mg_get_header(conn,
"Sec-WebSocket-Key");
12579 const char *version =
mg_get_header(conn,
"Sec-WebSocket-Version");
12580 ptrdiff_t lua_websock = 0;
12582#if !defined(USE_LUA)
12588 if (!websock_key) {
12595 const char *key1 =
mg_get_header(conn,
"Sec-WebSocket-Key1");
12596 const char *key2 =
mg_get_header(conn,
"Sec-WebSocket-Key2");
12599 if ((key1 != NULL) && (key2 != NULL)) {
12601 conn->content_len = 8;
12602 if (8 ==
mg_read(conn, key3, 8)) {
12607 "Protocol upgrade to RFC 6455 required");
12618 if ((version == NULL) || (strcmp(version,
"13") != 0)) {
12628 if (is_callback_resource) {
12630 const char *protocols[64];
12631 int nbSubprotocolHeader = get_req_headers(&conn->request_info,
12632 "Sec-WebSocket-Protocol",
12635 if ((nbSubprotocolHeader > 0) && subprotocols) {
12639 const char *
sep, *curSubProtocol,
12640 *acceptedWebSocketSubprotocol = NULL;
12645 const char *protocol = protocols[
cnt];
12648 sep = strchr(protocol,
',');
12649 curSubProtocol = protocol;
12650 len =
sep ? (
unsigned long)(
sep - protocol)
12651 : (unsigned long)strlen(protocol);
12652 while (
sep && isspace(*++
sep))
12659 && (strncmp(curSubProtocol,
12663 acceptedWebSocketSubprotocol =
12668 }
while (
sep && !acceptedWebSocketSubprotocol);
12669 }
while (++
cnt < nbSubprotocolHeader
12670 && !acceptedWebSocketSubprotocol);
12672 conn->request_info.acceptedWebSocketSubprotocol =
12673 acceptedWebSocketSubprotocol;
12675 }
else if (nbSubprotocolHeader > 0) {
12677 const char *protocol = protocols[0];
12682 const char *
sep = strrchr(protocol,
',');
12685 conn->request_info.acceptedWebSocketSubprotocol = protocol;
12695 while (isspace(*++
sep)) {
12698 conn->request_info.acceptedWebSocketSubprotocol =
sep;
12702 if ((ws_connect_handler != NULL)
12703 && (ws_connect_handler(conn, cbData) != 0)) {
12713#if defined(USE_LUA)
12717 if (conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
12719 conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS],
12720 strlen(conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
12726 conn->lua_websocket_state = lua_websocket_new(path, conn);
12727 if (!conn->lua_websocket_state) {
12736 if (!is_callback_resource && !lua_websock) {
12746 if (!send_websocket_handshake(conn, websock_key)) {
12752 if (is_callback_resource) {
12753 if (ws_ready_handler != NULL) {
12754 ws_ready_handler(conn, cbData);
12756#if defined(USE_LUA)
12757 }
else if (lua_websock) {
12758 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
12766 if (is_callback_resource) {
12767 read_websocket(conn, ws_data_handler, cbData);
12768#if defined(USE_LUA)
12769 }
else if (lua_websock) {
12770 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
12775 if (ws_close_handler) {
12776 ws_close_handler(conn, cbData);
12784 const char *upgrade, *connection;
12793 if (upgrade == NULL) {
12803 if (connection == NULL) {
12825 return (
n >= 0) && (
n <= 255);
12834 if (((sscanf(spec,
"%d.%d.%d.%d/%d%n", &
a, &
b, &
c, &
d, &
slash, &
n) == 5)
12835 || (sscanf(spec,
"%d.%d.%d.%d%n", &
a, &
b, &
c, &
d, &
n) == 4))
12839 *net = ((uint32_t)
a << 24) | ((uint32_t)
b << 16) | ((uint32_t)
c << 8)
12841 *mask =
slash ? (0xffffffffU << (32 -
slash)) : 0;
12852 struct vec vec, val;
12853 uint32_t net, mask;
12857 while ((spec =
next_option(spec, &vec, &val)) != NULL) {
12859 if ((val.ptr == NULL) || (sscanf(val.ptr,
"%lf%c", &
v, &mult) < 1)
12862 && (mult !=
','))) {
12867 : ((
lowercase(&mult) ==
'm') ? 1048576 : 1);
12868 if (vec.len == 1 && vec.ptr[0] ==
'*') {
12870 }
else if (
parse_net(vec.ptr, &net, &mask) > 0) {
12871 if ((remote_ip & mask) == net) {
12889 return ntohl(*(
const uint32_t *)&conn->client.rsa.sin.sin_addr);
12897#if defined(MG_LEGACY_INTERFACE)
12903struct mg_upload_user_data {
12904 struct mg_connection *conn;
12905 const char *destination_dir;
12906 int num_uploaded_files;
12912mg_upload_field_found(
const char *key,
12913 const char *filename,
12919 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
12924 return FORM_FIELD_STORAGE_ABORT;
12931 fud->destination_dir,
12935 return FORM_FIELD_STORAGE_ABORT;
12937 return FORM_FIELD_STORAGE_STORE;
12943mg_upload_field_get(
const char *key,
12960mg_upload_field_stored(
const char *path,
long long file_size,
void *user_data)
12962 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
12965 fud->num_uploaded_files++;
12966 fud->conn->phys_ctx->callbacks.upload(fud->conn, path);
12974mg_upload(
struct mg_connection *conn,
const char *destination_dir)
12976 struct mg_upload_user_data fud = {conn, destination_dir, 0};
12978 mg_upload_field_get,
12979 mg_upload_field_stored,
12987 mg_cry_internal(conn,
"%s: Error while parsing the request", __func__);
12990 return fud.num_uploaded_files;
13001 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
13002 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
13015 size_t buflen =
sizeof(buf);
13016 const char *host_header =
get_header(conn->request_info.http_headers,
13017 conn->request_info.num_headers,
13021 if (host_header != NULL) {
13027 buf[buflen - 1] =
'\0';
13029 while (isspace(*host)) {
13035 if (*host ==
'[') {
13036 pos = strchr(host,
']');
13039 DEBUG_TRACE(
"%s",
"Host name format error '[' without ']'");
13046 pos = strchr(host,
':');
13056 if (sslhost && (conn->dom_ctx != &(conn->phys_ctx->dd))) {
13069 struct mg_domain_context *dom = &(conn->phys_ctx->dd);
13078 conn->dom_ctx = dom;
13104 conn->must_close = 1;
13110 int redirect_code = 308;
13117 sizeof(target_url),
13118 "https://%s:%d%s%s%s",
13121#
if defined(USE_IPV6)
13122 (conn->phys_ctx->listening_sockets[ssl_index].lsa.sa.sa_family
13124 ? (
int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13125 .lsa.sin6.sin6_port)
13128 (
int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13129 .lsa.sin.sin_port),
13130 conn->request_info.local_uri,
13131 (conn->request_info.query_string == NULL) ?
"" :
"?",
13132 (conn->request_info.query_string == NULL)
13134 : conn->request_info.query_string);
13152 pthread_mutex_lock(&handler_info->refcount_mutex);
13153 handler_info->refcount++;
13154 pthread_mutex_unlock(&handler_info->refcount_mutex);
13161 pthread_mutex_lock(&handler_info->refcount_mutex);
13162 handler_info->refcount--;
13163 pthread_cond_signal(&handler_info->refcount_cond);
13164 pthread_mutex_unlock(&handler_info->refcount_mutex);
13171 pthread_mutex_lock(&handler_info->refcount_mutex);
13172 while (handler_info->refcount) {
13173 pthread_cond_wait(&handler_info->refcount_cond,
13174 &handler_info->refcount_mutex);
13176 pthread_mutex_unlock(&handler_info->refcount_mutex);
13182 struct mg_domain_context *dom_ctx,
13185 int is_delete_request,
13195 struct mg_handler_info *tmp_rh, **lastref;
13196 size_t urilen = strlen(uri);
13200 DEBUG_ASSERT(is_delete_request || connect_handler != NULL
13201 || ready_handler != NULL || data_handler != NULL
13202 || close_handler != NULL);
13205 if (handler != NULL) {
13208 if (!is_delete_request && (connect_handler == NULL)
13209 && (ready_handler == NULL) && (data_handler == NULL)
13210 && (close_handler == NULL)) {
13213 if (auth_handler != NULL) {
13217 DEBUG_ASSERT(connect_handler == NULL && ready_handler == NULL
13218 && data_handler == NULL && close_handler == NULL);
13222 if ((connect_handler != NULL) || (ready_handler != NULL)
13223 || (data_handler != NULL) || (close_handler != NULL)) {
13226 if (!is_delete_request && (handler == NULL)) {
13229 if (auth_handler != NULL) {
13234 DEBUG_ASSERT(connect_handler == NULL && ready_handler == NULL
13235 && data_handler == NULL && close_handler == NULL);
13237 if (handler != NULL) {
13240 if ((connect_handler != NULL) || (ready_handler != NULL)
13241 || (data_handler != NULL) || (close_handler != NULL)) {
13244 if (!is_delete_request && (auth_handler == NULL)) {
13249 if (!phys_ctx || !dom_ctx) {
13256 lastref = &(dom_ctx->handlers);
13257 for (tmp_rh = dom_ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
13258 if (tmp_rh->handler_type == handler_type) {
13259 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13260 if (!is_delete_request) {
13267 tmp_rh->handler = handler;
13269 tmp_rh->subprotocols = subprotocols;
13270 tmp_rh->connect_handler = connect_handler;
13271 tmp_rh->ready_handler = ready_handler;
13272 tmp_rh->data_handler = data_handler;
13273 tmp_rh->close_handler = close_handler;
13275 tmp_rh->auth_handler = auth_handler;
13277 tmp_rh->cbdata = cbdata;
13286 pthread_cond_destroy(&tmp_rh->refcount_cond);
13287 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13289 *lastref = tmp_rh->next;
13297 lastref = &(tmp_rh->next);
13300 if (is_delete_request) {
13308 (
struct mg_handler_info *)
mg_calloc_ctx(
sizeof(
struct mg_handler_info),
13311 if (tmp_rh == NULL) {
13315 "Cannot create new request handler struct, OOM");
13319 if (!tmp_rh->uri) {
13324 "Cannot create new request handler struct, OOM");
13327 tmp_rh->uri_len = urilen;
13330 if (0 != pthread_mutex_init(&tmp_rh->refcount_mutex, NULL)) {
13336 if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
13338 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13343 tmp_rh->refcount = 0;
13344 tmp_rh->handler = handler;
13346 tmp_rh->subprotocols = subprotocols;
13347 tmp_rh->connect_handler = connect_handler;
13348 tmp_rh->ready_handler = ready_handler;
13349 tmp_rh->data_handler = data_handler;
13350 tmp_rh->close_handler = close_handler;
13352 tmp_rh->auth_handler = auth_handler;
13354 tmp_rh->cbdata = cbdata;
13355 tmp_rh->handler_type = handler_type;
13356 tmp_rh->next = NULL;
13407 struct mg_context *ctx,
13416 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
13417 && (data_handler == NULL)
13418 && (close_handler == NULL);
13468 struct mg_handler_info **handler_info)
13471 if (request_info) {
13472 const char *uri = request_info->
local_uri;
13473 size_t urilen = strlen(uri);
13474 struct mg_handler_info *tmp_rh;
13476 if (!conn || !conn->phys_ctx || !conn->dom_ctx) {
13483 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13484 tmp_rh = tmp_rh->next) {
13485 if (tmp_rh->handler_type == handler_type) {
13486 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13489 *connect_handler = tmp_rh->connect_handler;
13490 *ready_handler = tmp_rh->ready_handler;
13491 *data_handler = tmp_rh->data_handler;
13492 *close_handler = tmp_rh->close_handler;
13494 *handler = tmp_rh->handler;
13497 *handler_info = tmp_rh;
13499 *auth_handler = tmp_rh->auth_handler;
13501 *cbdata = tmp_rh->cbdata;
13509 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13510 tmp_rh = tmp_rh->next) {
13511 if (tmp_rh->handler_type == handler_type) {
13512 if ((tmp_rh->uri_len < urilen) && (uri[tmp_rh->uri_len] ==
'/')
13513 && (memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0)) {
13516 *connect_handler = tmp_rh->connect_handler;
13517 *ready_handler = tmp_rh->ready_handler;
13518 *data_handler = tmp_rh->data_handler;
13519 *close_handler = tmp_rh->close_handler;
13521 *handler = tmp_rh->handler;
13524 *handler_info = tmp_rh;
13526 *auth_handler = tmp_rh->auth_handler;
13528 *cbdata = tmp_rh->cbdata;
13536 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13537 tmp_rh = tmp_rh->next) {
13538 if (tmp_rh->handler_type == handler_type) {
13539 if (
match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
13542 *connect_handler = tmp_rh->connect_handler;
13543 *ready_handler = tmp_rh->ready_handler;
13544 *data_handler = tmp_rh->data_handler;
13545 *close_handler = tmp_rh->close_handler;
13547 *handler = tmp_rh->handler;
13550 *handler_info = tmp_rh;
13552 *auth_handler = tmp_rh->auth_handler;
13554 *cbdata = tmp_rh->cbdata;
13582#if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
13584deprecated_websocket_connect_wrapper(
const struct mg_connection *conn,
13588 if (pcallbacks->websocket_connect) {
13589 return pcallbacks->websocket_connect(conn);
13597deprecated_websocket_ready_wrapper(
struct mg_connection *conn,
void *cbdata)
13600 if (pcallbacks->websocket_ready) {
13601 pcallbacks->websocket_ready(conn);
13607deprecated_websocket_data_wrapper(
struct mg_connection *conn,
13614 if (pcallbacks->websocket_data) {
13615 return pcallbacks->websocket_data(conn, bits, data, len);
13631 char path[PATH_MAX];
13632 int uri_len, ssl_index;
13633 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
13634 is_put_or_delete_request = 0, is_callback_resource = 0;
13638 struct mg_handler_info *handler_info = NULL;
13644 void *callback_data = NULL;
13646 void *auth_callback_data = NULL;
13648 time_t curtime = time(NULL);
13655 if ((conn->request_info.query_string = strchr(ri->
request_uri,
'?'))
13657 *((
char *)conn->request_info.query_string++) =
'\0';
13661 if (!conn->client.is_ssl && conn->client.ssl_redir) {
13663 if (ssl_index >= 0) {
13671 "Error: SSL forward not configured properly");
13674 "Can not redirect to SSL, no SSL port available");
13700 if (conn->phys_ctx->callbacks.begin_request != NULL) {
13704 i = conn->phys_ctx->callbacks.begin_request(conn);
13708 conn->status_code = i;
13711 }
else if (i == 0) {
13729 const char *cors_meth_cfg =
13731 const char *cors_orig_cfg =
13733 const char *cors_origin =
13737 "Access-Control-Request-Method");
13742 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
13743 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
13744 && (cors_origin != NULL) && (cors_acrm != NULL)) {
13748 const char *cors_acrh =
13751 "Access-Control-Request-Headers");
13755 "HTTP/1.1 200 OK\r\n"
13757 "Access-Control-Allow-Origin: %s\r\n"
13758 "Access-Control-Allow-Methods: %s\r\n"
13759 "Content-Length: 0\r\n"
13760 "Connection: %s\r\n",
13763 ((cors_meth_cfg[0] ==
'*') ? cors_acrm : cors_meth_cfg),
13766 if (cors_acrh != NULL) {
13768 const char *cors_hdr_cfg =
13771 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
13778 "Access-Control-Allow-Headers: %s\r\n",
13779 ((cors_hdr_cfg[0] ==
'*') ? cors_acrh
13783 mg_printf(conn,
"Access-Control-Max-Age: 60\r\n");
13796#if defined(USE_WEBSOCKET)
13806 &ws_connect_handler,
13817 is_callback_resource = 1;
13818 is_script_resource = 1;
13821 no_callback_resource:
13826 is_callback_resource = 0;
13832 &is_script_resource,
13833 &is_websocket_request,
13834 &is_put_or_delete_request);
13848 &auth_callback_data,
13850 if (!auth_handler(conn, auth_callback_data)) {
13853 }
else if (is_put_or_delete_request && !is_script_resource
13854 && !is_callback_resource) {
13857#if defined(NO_FILES)
13866 "%s method not allowed",
13867 conn->request_info.request_method);
13871#if !defined(NO_FILES)
13894 if (is_callback_resource) {
13895 if (!is_websocket_request) {
13896 i = callback_handler(conn, callback_data);
13905 conn->status_code = i;
13930 &is_script_resource,
13931 &is_websocket_request,
13932 &is_put_or_delete_request);
13933 callback_handler = NULL;
13944 goto no_callback_resource;
13947#if defined(USE_WEBSOCKET)
13948 handle_websocket_request(conn,
13950 is_callback_resource,
13952 ws_connect_handler,
13963#if defined(USE_WEBSOCKET)
13964 if (is_websocket_request) {
13965 if (is_script_resource) {
13969 handle_websocket_request(conn,
13977 conn->phys_ctx->user_data);
13983#if defined(MG_LEGACY_INTERFACE)
13984 handle_websocket_request(
13987 !is_script_resource ,
13989 deprecated_websocket_connect_wrapper,
13990 deprecated_websocket_ready_wrapper,
13991 deprecated_websocket_data_wrapper,
13993 conn->phys_ctx->user_data);
14002#if defined(NO_FILES)
14017 if (is_script_resource) {
14023 if (is_put_or_delete_request) {
14044 "%s method not allowed",
14045 conn->request_info.request_method);
14057 if (
file.stat.is_directory && (uri_len > 0)
14058 && (ri->
local_uri[uri_len - 1] !=
'/')) {
14061 "HTTP/1.1 301 Moved Permanently\r\n"
14062 "Location: %s/\r\n"
14065 "Content-Length: 0\r\n"
14066 "Connection: %s\r\n",
14096 "%s method not allowed",
14097 conn->request_info.request_method);
14102 if (
file.stat.is_directory) {
14113 "Error: Directory listing denied");
14127 struct mg_file *
file)
14129 if (!conn || !conn->dom_ctx) {
14134#if defined(USE_LUA)
14136 conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
14137 strlen(conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
14145 handle_lsp_request(conn, path,
file, NULL);
14151 }
else if (
match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
14153 conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
14161 mg_exec_lua_script(conn, path, NULL);
14167#if defined(USE_DUKTAPE)
14169 conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
14170 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
14175 mg_exec_duktape_script(conn, path);
14181#if !defined(NO_CGI)
14204#if !defined(NO_CACHING)
14205 }
else if ((!conn->in_error_handler)
14224 for (i = 0; i < ctx->num_listening_sockets; i++) {
14228 mg_free(ctx->listening_sockets);
14229 ctx->listening_sockets = NULL;
14230 mg_free(ctx->listening_socket_fds);
14231 ctx->listening_socket_fds = NULL;
14252 unsigned int a,
b,
c,
d, port;
14255#if defined(USE_IPV6)
14256 char buf[100] = {0};
14262 memset(so, 0,
sizeof(*so));
14263 so->lsa.sin.sin_family = AF_INET;
14271 if (sscanf(vec->ptr,
"%u.%u.%u.%u:%u%n", &
a, &
b, &
c, &
d, &port, &len)
14274 so->lsa.sin.sin_addr.s_addr =
14275 htonl((
a << 24) | (
b << 16) | (
c << 8) |
d);
14276 so->lsa.sin.sin_port = htons((uint16_t)port);
14279#if defined(USE_IPV6)
14280 }
else if (sscanf(vec->ptr,
"[%49[^]]]:%u%n", buf, &port, &len) == 2
14282 AF_INET6, buf, &so->lsa.sin6,
sizeof(so->lsa.sin6))) {
14286 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14290 }
else if ((vec->ptr[0] ==
'+')
14291 && (sscanf(vec->ptr + 1,
"%u%n", &port, &len) == 1)) {
14297#if defined(USE_IPV6)
14299 so->lsa.sin6.sin6_family = AF_INET6;
14300 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14301 *ip_version = 4 + 6;
14304 so->lsa.sin.sin_port = htons((uint16_t)port);
14308 }
else if (sscanf(vec->ptr,
"%u%n", &port, &len) == 1) {
14310 so->lsa.sin.sin_port = htons((uint16_t)port);
14313 }
else if ((cb = strchr(vec->ptr,
':')) != NULL) {
14323 char hostname[256];
14324 size_t hostnlen = (size_t)(cb - vec->ptr);
14326 if (hostnlen >=
sizeof(hostname)) {
14332 memcpy(hostname, vec->ptr, hostnlen);
14333 hostname[hostnlen] = 0;
14336 AF_INET, vec->ptr, &so->lsa.sin,
sizeof(so->lsa.sin))) {
14337 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
14339 so->lsa.sin.sin_family = AF_INET;
14340 so->lsa.sin.sin_port = htons((uint16_t)port);
14341 len += (int)(hostnlen + 1);
14346#if defined(USE_IPV6)
14350 sizeof(so->lsa.sin6))) {
14351 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
14353 so->lsa.sin6.sin6_family = AF_INET6;
14354 so->lsa.sin.sin_port = htons((uint16_t)port);
14355 len += (int)(hostnlen + 1);
14370 if ((len < 0) && ((unsigned)len > (
unsigned)vec->len)) {
14374 ch = vec->ptr[len];
14375 so->is_ssl = (ch ==
's');
14376 so->ssl_redir = (ch ==
'r');
14380 && ((ch ==
'\0') || (ch ==
's') || (ch ==
'r') || (ch ==
','))) {
14430 int portslen = (int)strlen(ports);
14431 char prevIsNumber = 0;
14433 for (i = 0; i < portslen; i++) {
14434 if (prevIsNumber && (ports[i] ==
's' || ports[i] ==
'r')) {
14437 if (ports[i] >=
'0' && ports[i] <=
'9') {
14453#if defined(USE_IPV6)
14457 struct socket so, *ptr;
14459 struct pollfd *pfd;
14464 int portsTotal = 0;
14471 memset(&so, 0,
sizeof(so));
14472 memset(&usa, 0,
sizeof(usa));
14476 while ((list =
next_option(list, &vec, NULL)) != NULL) {
14483 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
14487 "[IP_ADDRESS:]PORT[s|r]");
14491#if !defined(NO_SSL)
14492 if (so.is_ssl && phys_ctx->dd.ssl_ctx == NULL) {
14495 "Cannot add SSL socket (entry %i)",
14501 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
14505 "cannot create socket (entry %i)",
14520 if (setsockopt(so.sock,
14522 SO_EXCLUSIVEADDRUSE,
14530 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
14534 if (setsockopt(so.sock,
14543 "cannot set socket option SO_REUSEADDR (entry %i)",
14548 if (ip_version > 4) {
14550#if defined(USE_IPV6)
14551 if (ip_version > 6) {
14552 if (so.lsa.sa.sa_family == AF_INET6
14553 && setsockopt(so.sock,
14563 "cannot set socket option IPV6_V6ONLY=off (entry %i)",
14567 if (so.lsa.sa.sa_family == AF_INET6
14568 && setsockopt(so.sock,
14578 "cannot set socket option IPV6_V6ONLY=on (entry %i)",
14590 if (so.lsa.sa.sa_family == AF_INET) {
14592 len =
sizeof(so.lsa.sin);
14593 if (bind(so.sock, &so.lsa.sa, len) != 0) {
14595 "cannot bind to %.*s: %d (%s)",
14605#if defined(USE_IPV6)
14606 else if (so.lsa.sa.sa_family == AF_INET6) {
14608 len =
sizeof(so.lsa.sin6);
14609 if (bind(so.sock, &so.lsa.sa, len) != 0) {
14611 "cannot bind to IPv6 %.*s: %d (%s)",
14625 "cannot bind: address family not supported (entry %i)",
14635 "cannot listen to %.*s: %d (%s)",
14645 if ((getsockname(so.sock, &(usa.sa), &len) != 0)
14646 || (usa.sa.sa_family != so.lsa.sa.sa_family)) {
14648 int err = (int)
ERRNO;
14650 "call to getsockname failed %.*s: %d (%s)",
14661#if defined(USE_IPV6)
14662 if (so.lsa.sa.sa_family == AF_INET6) {
14663 so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
14667 so.lsa.sin.sin_port = usa.sin.sin_port;
14670 if ((ptr = (
struct socket *)
14672 (phys_ctx->num_listening_sockets + 1)
14673 *
sizeof(phys_ctx->listening_sockets[0]),
14683 if ((pfd = (
struct pollfd *)
14685 (phys_ctx->num_listening_sockets + 1)
14686 *
sizeof(phys_ctx->listening_socket_fds[0]),
14698 phys_ctx->listening_sockets = ptr;
14699 phys_ctx->listening_sockets[phys_ctx->num_listening_sockets] = so;
14700 phys_ctx->listening_socket_fds = pfd;
14701 phys_ctx->num_listening_sockets++;
14705 if (portsOk != portsTotal) {
14717 const char *header_value;
14719 if ((header_value =
mg_get_header(conn, header)) == NULL) {
14722 return header_value;
14727#if defined(MG_EXTERNAL_FUNCTION_log_access)
14728static void log_access(
const struct mg_connection *conn);
14729#include "external_log_access.inl"
14740 const char *referer;
14741 const char *user_agent;
14745 if (!conn || !conn->dom_ctx) {
14755 fi.access.fp = NULL;
14758 fi.access.fp = NULL;
14763 if ((fi.access.fp == NULL)
14764 && (conn->phys_ctx->callbacks.log_access == NULL)) {
14768 tm = localtime(&conn->conn_birth_time);
14770 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z", tm);
14772 mg_strlcpy(date,
"01/Jan/1970:00:00:00 +0000",
sizeof(date));
14773 date[
sizeof(date) - 1] =
'\0';
14776 ri = &conn->request_info;
14780 user_agent =
header_val(conn,
"User-Agent");
14786 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
14796 conn->num_bytes_sent,
14800 if (conn->phys_ctx->callbacks.log_access) {
14801 conn->phys_ctx->callbacks.log_access(conn, buf);
14804 if (fi.access.fp) {
14806 flockfile(fi.access.fp);
14807 if (fprintf(fi.access.fp,
"%s\n", buf) < 1) {
14810 if (fflush(fi.access.fp) != 0) {
14813 funlockfile(fi.access.fp);
14819 "Error writing log file %s",
14835 uint32_t net, mask;
14842 allowed = (list == NULL) ?
'+' :
'-';
14844 while ((list =
next_option(list, &vec, NULL)) != NULL) {
14846 if ((flag !=
'+' && flag !=
'-')
14847 || (
parse_net(&vec.ptr[1], &net, &mask) == 0)) {
14849 "%s: subnet must be [+|-]x.x.x.x[/x]",
14854 if (net == (remote_ip & mask)) {
14859 return allowed ==
'+';
14865#if !defined(_WIN32)
14873 const uid_t curr_uid = getuid();
14875 const char *run_as_user = phys_ctx->dd.config[
RUN_AS_USER];
14876 const struct passwd *to_pw = NULL;
14878 if (run_as_user != NULL && (to_pw = getpwnam(run_as_user)) == NULL) {
14882 "%s: unknown user [%s]",
14885 }
else if (run_as_user == NULL || curr_uid == to_pw->
pw_uid) {
14892 if (setgid(to_pw->
pw_gid) == -1) {
14894 "%s: setgid(%s): %s",
14898 }
else if (setgroups(0, NULL) == -1) {
14900 "%s: setgroups(): %s",
14903 }
else if (setuid(to_pw->
pw_uid) == -1) {
14905 "%s: setuid(%s): %s",
14923 struct mg_workerTLS *tls = (
struct mg_workerTLS *)key;
14927 if (tls->is_master == 2) {
14928 tls->is_master = -3;
14932 pthread_setspecific(
sTlsKey, NULL);
14936#if !defined(NO_SSL)
14939 struct mg_domain_context *dom_ctx,
14941 const char *chain);
14948 static int reload_lock = 0;
14949 static long int data_check = 0;
14950 volatile int *p_reload_lock = (
volatile int *)&reload_lock;
14952 struct stat cert_buf;
14956 int should_verify_peer;
14964 if (chain == NULL) {
14973 if (stat(pem, &cert_buf) != -1) {
14974 t = (
long int)cert_buf.st_mtime;
14977 if (data_check != t) {
14980 should_verify_peer = 0;
14984 should_verify_peer = 1;
14988 should_verify_peer = 1;
14992 if (should_verify_peer) {
14993 char *ca_path = conn->dom_ctx->config[
SSL_CA_PATH];
14994 char *ca_file = conn->dom_ctx->config[
SSL_CA_FILE];
15000 fc(conn->phys_ctx),
15001 "SSL_CTX_load_verify_locations error: %s "
15002 "ssl_verify_peer requires setting "
15003 "either ssl_ca_path or ssl_ca_file. Is any of them "
15016 *p_reload_lock = 0;
15020 while (*p_reload_lock) {
15027#if defined(OPENSSL_API_1_1)
15035 int (*func)(
SSL *),
15036 volatile int *stop_server,
15059 if (conn->ssl == NULL) {
15064 ret =
SSL_set_fd(conn->ssl, conn->client.sock);
15074 if (client_options) {
15083 for (i = 16; i <= 1024; i *= 2) {
15084 ret = func(conn->ssl);
15094 if (*stop_server) {
15143 const char hexdigit[] =
"0123456789abcdef";
15145 if ((memlen <= 0) || (buflen <= 0)) {
15148 if (buflen < (3 * memlen)) {
15152 for (i = 0; i < memlen; i++) {
15154 buf[3 * i - 1] =
' ';
15156 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
15157 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
15159 buf[3 * memlen - 1] = 0;
15170 char str_subject[1024];
15171 char str_issuer[1024];
15172 char str_finger[1024];
15173 unsigned char buf[256];
15174 char *str_serial = NULL;
15177 unsigned char *tmp_buf;
15178 unsigned char *tmp_p;
15205 tmp_buf = (ilen > 0)
15213 tmp_buf, (
unsigned)ilen, buf, &ulen, digest, NULL)) {
15220 buf, (
int)ulen, str_finger, (
int)
sizeof(str_finger))) {
15226 if (conn->request_info.client_cert) {
15227 conn->request_info.client_cert->peer_cert = (
void *)cert;
15228 conn->request_info.client_cert->subject =
15230 conn->request_info.client_cert->issuer =
15232 conn->request_info.client_cert->serial =
15234 conn->request_info.client_cert->finger =
15239 "Out of memory: Cannot allocate memory for client "
15250#if defined(OPENSSL_API_1_1)
15268#if !defined(NO_SSL_DL)
15270load_dll(
char *ebuf,
size_t ebuf_len,
const char *dll_name,
struct ssl_func *sw)
15277 struct ssl_func *fp;
15281 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
15286 "%s: cannot load %s",
15293 for (fp = sw; fp->name != NULL; fp++) {
15296 u.fp = (
void (*)(
void))dlsym(dll_handle, fp->name);
15301 u.p = dlsym(dll_handle, fp->name);
15303 if (u.fp == NULL) {
15309 "%s: %s: cannot find %s",
15315 size_t cur_len = strlen(ebuf);
15320 ebuf_len - cur_len - 3,
15325 strcat(ebuf,
"...");
15337 (
void)dlclose(dll_handle);
15351#if defined(SSL_ALREADY_INITIALIZED)
15361#if defined(OPENSSL_API_1_1)
15362 if (ebuf_len > 0) {
15366#if !defined(NO_SSL_DL)
15374 "%s: error loading library %s",
15391 if (ebuf_len > 0) {
15395#if !defined(NO_SSL_DL)
15403 "%s: error loading library %s",
15420 if (num_locks < 0) {
15423 size =
sizeof(pthread_mutex_t) * ((
size_t)(num_locks));
15426 if (num_locks == 0) {
15439 "%s: cannot allocate mutexes: %s",
15447 for (i = 0; i < num_locks; i++) {
15453 "%s: error initializing mutex %i of %i",
15468#if !defined(NO_SSL_DL)
15472#if !defined(OPENSSL_API_1_1)
15481#if defined(OPENSSL_API_1_1)
15483 OPENSSL_init_ssl(0, NULL);
15499 struct mg_domain_context *dom_ctx,
15505 "%s: cannot open certificate file %s: %s",
15515 "%s: cannot open private key file %s: %s",
15524 "%s: certificate and private key do not match: %s",
15541 "%s: cannot use certificate chain file %s: %s",
15552#if defined(OPENSSL_API_1_1)
15553static unsigned long
15556 long unsigned ret = (
long unsigned)
SSL_OP_ALL;
15557 if (version_id > 0)
15559 if (version_id > 1)
15561 if (version_id > 2)
15563 if (version_id > 3)
15572 if (version_id > 0)
15574 if (version_id > 1)
15576 if (version_id > 2)
15578 if (version_id > 3)
15614 struct mg_context *ctx = (
struct mg_context *)arg;
15615 struct mg_domain_context *dom =
15616 (
struct mg_domain_context *)ctx ? &(ctx->dd) : NULL;
15618#if defined(GCC_DIAGNOSTIC)
15619#pragma GCC diagnostic push
15620#pragma GCC diagnostic ignored "-Wcast-align"
15624 struct mg_connection *conn = (
struct mg_connection *)
SSL_get_app_data(ssl);
15626#if defined(GCC_DIAGNOSTIC)
15627#pragma GCC diagnostic pop
15634 if ((ctx == NULL) || (conn->phys_ctx == ctx)) {
15635 DEBUG_TRACE(
"%s",
"internal error - assertion failed");
15645 if ((servername == NULL) || (*servername == 0)) {
15646 DEBUG_TRACE(
"%s",
"SSL connection not supporting SNI");
15647 conn->dom_ctx = &(ctx->dd);
15652 DEBUG_TRACE(
"TLS connection to host %s", servername);
15661 conn->dom_ctx = dom;
15670 conn->dom_ctx = &(ctx->dd);
15679 struct mg_domain_context *dom_ctx,
15684 int should_verify_peer;
15685 int peer_certificate_optional;
15686 const char *ca_path;
15687 const char *ca_file;
15688 int use_default_verify_paths;
15690 struct timespec now_mt;
15695#if defined(OPENSSL_API_1_1)
15696 if ((dom_ctx->ssl_ctx =
SSL_CTX_new(TLS_server_method())) == NULL) {
15698 "SSL_CTX_new (server) error: %s",
15705 "SSL_CTX_new (server) error: %s",
15721#if !defined(NO_SSL_DL)
15745 callback_ret = (phys_ctx->callbacks.init_ssl == NULL)
15747 : (phys_ctx->callbacks.init_ssl(dom_ctx->ssl_ctx,
15748 phys_ctx->user_data));
15753 if (callback_ret < 0) {
15755 "SSL callback returned error: %i",
15759 if (callback_ret > 0) {
15767 clock_gettime(CLOCK_MONOTONIC, &now_mt);
15780 (
unsigned char *)ssl_context_id,
15781 sizeof(ssl_context_id));
15791 should_verify_peer = 0;
15792 peer_certificate_optional = 0;
15796 should_verify_peer = 1;
15797 peer_certificate_optional = 0;
15802 should_verify_peer = 1;
15803 peer_certificate_optional = 1;
15807 use_default_verify_paths =
15812 if (should_verify_peer) {
15818 "SSL_CTX_load_verify_locations error: %s "
15819 "ssl_verify_peer requires setting "
15820 "either ssl_ca_path or ssl_ca_file. "
15821 "Is any of them present in the "
15827 if (peer_certificate_optional) {
15836 if (use_default_verify_paths
15839 "SSL_CTX_set_default_verify_paths error: %s",
15855 "SSL_CTX_set_cipher_list error: %s",
15881 dom_ctx = &(phys_ctx->dd);
15891 (phys_ctx->callbacks.external_ssl_ctx == NULL)
15893 : (phys_ctx->callbacks.external_ssl_ctx(&ssl_ctx,
15894 phys_ctx->user_data));
15896 if (callback_ret < 0) {
15898 "external_ssl_ctx callback returned error: %i",
15901 }
else if (callback_ret > 0) {
15902 dom_ctx->ssl_ctx = (
SSL_CTX *)ssl_ctx;
15915 && (phys_ctx->callbacks.init_ssl == NULL)) {
15920 "Initializing SSL failed: -%s is not set",
15926 if (chain == NULL) {
15929 if ((chain != NULL) && (*chain == 0)) {
15945#if defined(OPENSSL_API_1_1)
15990 dom_ctx = &(phys_ctx->dd);
15993 if ((path != NULL) && !
mg_stat(
fc(phys_ctx), path, &
file.stat)) {
15995 "Cannot open %s: %s",
16009 return check_acl(phys_ctx, (uint32_t)0x7f000001UL) != -1;
16019 conn->connection_type =
16022 conn->num_bytes_sent = conn->consumed_content = 0;
16024 conn->path_info = NULL;
16025 conn->status_code = -1;
16026 conn->content_len = -1;
16027 conn->is_chunked = 0;
16028 conn->must_close = 0;
16029 conn->request_len = 0;
16030 conn->throttle = 0;
16031 conn->data_len = 0;
16032 conn->chunk_remainder = 0;
16033 conn->accept_gzip = 0;
16035 conn->response_info.content_length = conn->request_info.content_length = -1;
16036 conn->response_info.http_version = conn->request_info.http_version = NULL;
16037 conn->response_info.num_headers = conn->request_info.num_headers = 0;
16038 conn->response_info.status_text = NULL;
16039 conn->response_info.status_code = 0;
16041 conn->request_info.remote_user = NULL;
16042 conn->request_info.request_method = NULL;
16043 conn->request_info.request_uri = NULL;
16044 conn->request_info.local_uri = NULL;
16046#if defined(MG_LEGACY_INTERFACE)
16048 conn->request_info.uri = NULL;
16060set_sock_timeout(
SOCKET sock,
int milliseconds)
16062 int r0 = 0, r1, r2;
16067 DWORD tv = (DWORD)milliseconds;
16081#if defined(TCP_USER_TIMEOUT)
16082 unsigned int uto = (
unsigned int)milliseconds;
16083 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (
const void *)&uto,
sizeof(uto));
16086 memset(&tv, 0,
sizeof(tv));
16087 tv.tv_sec = milliseconds / 1000;
16088 tv.tv_usec = (milliseconds * 1000) % 1000000;
16093 sock, SOL_SOCKET, SO_RCVTIMEO, (
SOCK_OPT_TYPE)&tv,
sizeof(tv));
16095 sock, SOL_SOCKET, SO_SNDTIMEO, (
SOCK_OPT_TYPE)&tv,
sizeof(tv));
16097 return r0 || r1 || r2;
16105 if (setsockopt(sock,
16109 sizeof(nodelay_on))
16126 struct linger linger;
16127 int error_code = 0;
16128 int linger_timeout = -2;
16129 socklen_t opt_len =
sizeof(error_code);
16152 n =
pull_inner(NULL, conn, buf,
sizeof(buf), 1.0);
16161 if (linger_timeout >= 0) {
16164 linger.l_onoff = 1;
16166#if defined(_MSC_VER)
16167#pragma warning(push)
16168#pragma warning(disable : 4244)
16170#if defined(GCC_DIAGNOSTIC)
16171#pragma GCC diagnostic push
16172#pragma GCC diagnostic ignored "-Wconversion"
16178 linger.l_linger = (linger_timeout + 999) / 1000;
16180#if defined(GCC_DIAGNOSTIC)
16181#pragma GCC diagnostic pop
16183#if defined(_MSC_VER)
16184#pragma warning(pop)
16188 linger.l_onoff = 0;
16189 linger.l_linger = 0;
16192 if (linger_timeout < -1) {
16194 }
else if (getsockopt(conn->client.sock,
16198 (
char *)&error_code,
16208 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
16211 }
else if (error_code == ECONNRESET) {
16217 if (setsockopt(conn->client.sock,
16225 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
16242#if defined(USE_SERVER_STATS)
16243 conn->conn_state = 6;
16246#if defined(USE_LUA) && defined(USE_WEBSOCKET)
16247 if (conn->lua_websocket_state) {
16248 lua_websocket_close(conn, conn->lua_websocket_state);
16249 conn->lua_websocket_state = NULL;
16256 conn->must_close = 1;
16259 if (conn->phys_ctx->callbacks.connection_close != NULL) {
16261 conn->phys_ctx->callbacks.connection_close(conn);
16271#if defined(USE_SERVER_STATS)
16272 conn->conn_state = 7;
16275#if !defined(NO_SSL)
16276 if (conn->ssl != NULL) {
16297#if defined(USE_SERVER_STATS)
16298 conn->conn_state = 8;
16306#if defined(USE_WEBSOCKET)
16307 struct mg_context *client_ctx = NULL;
16310 if ((conn == NULL) || (conn->phys_ctx == NULL)) {
16314#if defined(USE_WEBSOCKET)
16316 if (conn->in_websocket_handling) {
16318 conn->must_close = 1;
16327 client_ctx = conn->phys_ctx;
16330 client_ctx->stop_flag = 1;
16331 conn->must_close = 1;
16339 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
16340 if (client_ctx->worker_threadids[i] != 0) {
16349#if !defined(NO_SSL)
16350 if (conn->client_ssl_ctx != NULL) {
16355#if defined(USE_WEBSOCKET)
16356 if (client_ctx != NULL) {
16358 mg_free(client_ctx->worker_threadids);
16360 (
void)pthread_mutex_destroy(&conn->mutex);
16377static struct mg_connection *
16383 struct mg_connection *conn = NULL;
16386 struct sockaddr *psa;
16389 unsigned max_req_size =
16393 size_t conn_size = ((
sizeof(
struct mg_connection) + 7) >> 3) << 3;
16394 size_t ctx_size = ((
sizeof(
struct mg_context) + 7) >> 3) << 3;
16399 if (conn == NULL) {
16409#if defined(GCC_DIAGNOSTIC)
16410#pragma GCC diagnostic push
16411#pragma GCC diagnostic ignored "-Wcast-align"
16415 conn->phys_ctx = (
struct mg_context *)(((
char *)conn) + conn_size);
16417#if defined(GCC_DIAGNOSTIC)
16418#pragma GCC diagnostic pop
16421 conn->buf = (((
char *)conn) + conn_size + ctx_size);
16422 conn->buf_size = (int)max_req_size;
16424 conn->dom_ctx = &(conn->phys_ctx->dd);
16427 client_options->
host,
16428 client_options->
port,
16440#if !defined(NO_SSL)
16441#if defined(OPENSSL_API_1_1)
16443 && (conn->client_ssl_ctx =
SSL_CTX_new(TLS_client_method())) == NULL) {
16448 "SSL_CTX_new error");
16461 "SSL_CTX_new error");
16470#if defined(USE_IPV6)
16471 len = (sa.sa.sa_family == AF_INET) ?
sizeof(conn->client.rsa.sin)
16472 :
sizeof(conn->client.rsa.sin6);
16473 psa = (sa.sa.sa_family == AF_INET)
16474 ? (
struct sockaddr *)&(conn->client.rsa.sin)
16475 : (
struct sockaddr *)&(conn->client.rsa.sin6);
16477 len =
sizeof(conn->client.rsa.sin);
16478 psa = (
struct sockaddr *)&(conn->client.rsa.sin);
16481 conn->client.sock = sock;
16482 conn->client.lsa = sa;
16484 if (getsockname(sock, psa, &len) != 0) {
16486 "%s: getsockname() failed: %s",
16491 conn->client.is_ssl = use_ssl ? 1 : 0;
16497 "Can not create mutex");
16498#if !defined(NO_SSL)
16507#if !defined(NO_SSL)
16527 "Can not use SSL client certificate");
16545 conn->client_ssl_ctx,
16547 &(conn->phys_ctx->stop_flag),
16553 "SSL connection error");
16564 "Cannot set non-blocking mode for client %s:%i",
16565 client_options->
host,
16566 client_options->
port);
16575 char *error_buffer,
16576 size_t error_buffer_size)
16581 error_buffer_size);
16585struct mg_connection *
16589 char *error_buffer,
16590 size_t error_buffer_size)
16593 memset(&opts, 0,
sizeof(opts));
16599 error_buffer_size);
16603static const struct {
16608 {
"https://", 8, 443},
16610 {
"wss://", 6, 443},
16624 const char *hostend, *portbegin;
16626 unsigned long port;
16632 if ((uri[0] ==
'*') && (uri[1] ==
'\0')) {
16643 for (i = 0; uri[i] != 0; i++) {
16648 if (uri[i] > 126) {
16671 if (uri[0] ==
'/') {
16695 port = strtoul(portbegin + 1, &portend, 10);
16696 if ((portend != hostend) || (port <= 0) || !
is_valid_port(port)) {
16712 const char *server_domain;
16713 size_t server_domain_len;
16714 size_t request_domain_len = 0;
16715 unsigned long port = 0;
16716 int i, auth_domain_check_enabled;
16717 const char *hostbegin = NULL;
16718 const char *hostend = NULL;
16719 const char *portbegin;
16722 auth_domain_check_enabled =
16734 hostend = strchr(hostbegin,
'/');
16738 portbegin = strchr(hostbegin,
':');
16739 if ((!portbegin) || (portbegin > hostend)) {
16741 request_domain_len = (size_t)(hostend - hostbegin);
16743 port = strtoul(portbegin + 1, &portend, 10);
16744 if ((portend != hostend) || (port <= 0)
16748 request_domain_len = (size_t)(portbegin - hostbegin);
16762#if defined(USE_IPV6)
16763 if (conn->client.lsa.sa.sa_family == AF_INET6) {
16764 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
16771 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
16785 if (auth_domain_check_enabled) {
16787 server_domain_len = strlen(server_domain);
16788 if ((server_domain_len == 0) || (hostbegin == NULL)) {
16791 if ((request_domain_len == server_domain_len)
16792 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
16795 if (request_domain_len < (server_domain_len + 2)) {
16802 if (hostbegin[request_domain_len - server_domain_len - 1] !=
'.') {
16809 != memcmp(server_domain,
16810 hostbegin + request_domain_len - server_domain_len,
16811 server_domain_len)) {
16824get_message(
struct mg_connection *conn,
char *ebuf,
size_t ebuf_len,
int *err)
16826 if (ebuf_len > 0) {
16845 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
16847 conn->request_len =
16848 read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
16849 DEBUG_ASSERT(conn->request_len < 0 || conn->data_len >= conn->request_len);
16850 if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) {
16856 "Invalid message size");
16861 if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) {
16867 "Message too large");
16872 if (conn->request_len <= 0) {
16873 if (conn->data_len > 0) {
16879 "Malformed message");
16883 conn->must_close = 1;
16889 "No data received");
16899get_request(
struct mg_connection *conn,
char *ebuf,
size_t ebuf_len,
int *err)
16928 "Bad request: Host mismatch");
16934 if ((cl =
get_header(conn->request_info.http_headers,
16935 conn->request_info.num_headers,
16939 char *endptr = NULL;
16940 conn->content_len = strtoll(cl, &endptr, 10);
16941 if (endptr == cl) {
16952 conn->request_info.content_length = conn->content_len;
16953 }
else if ((cl =
get_header(conn->request_info.http_headers,
16954 conn->request_info.num_headers,
16955 "Transfer-Encoding"))
16958 conn->is_chunked = 1;
16959 conn->content_len = -1;
16961 const struct mg_http_method_info *meth =
16974 if (meth->request_has_body) {
16976 conn->content_len = -1;
16979 conn->content_len = 0;
17012 if ((cl =
get_header(conn->response_info.http_headers,
17013 conn->response_info.num_headers,
17017 char *endptr = NULL;
17018 conn->content_len = strtoll(cl, &endptr, 10);
17019 if (endptr == cl) {
17030 conn->response_info.content_length = conn->content_len;
17033 conn->request_info.content_length = conn->content_len;
17035 }
else if ((cl =
get_header(conn->response_info.http_headers,
17036 conn->response_info.num_headers,
17037 "Transfer-Encoding"))
17040 conn->is_chunked = 1;
17041 conn->content_len = -1;
17043 conn->content_len = -1;
17059 char *save_timeout;
17062 if (ebuf_len > 0) {
17072 "Parameter error");
17079 if (timeout >= 0) {
17080 mg_snprintf(conn, NULL, txt,
sizeof(txt),
"%i", timeout);
17086 new_timeout = NULL;
17093#if defined(MG_LEGACY_INTERFACE)
17096 conn->request_info.uri = conn->request_info.request_uri;
17098 conn->request_info.local_uri = conn->request_info.request_uri;
17102 return (ret == 0) ? -1 : +1;
17106struct mg_connection *
17115 struct mg_connection *conn;
17120 if (ebuf_len > 0) {
17129 if (conn != NULL) {
17137 "Error sending request");
17141#if defined(MG_LEGACY_INTERFACE)
17144 conn->request_info.uri = conn->request_info.request_uri;
17146 conn->request_info.local_uri = conn->request_info.request_uri;
17151 if ((ebuf[0] !=
'\0') && (conn != NULL)) {
17161struct websocket_client_thread_data {
17162 struct mg_connection *conn;
17165 void *callback_data;
17169#if defined(USE_WEBSOCKET)
17171static unsigned __stdcall websocket_client_thread(
void *data)
17174websocket_client_thread(
void *data)
17177 struct websocket_client_thread_data *cdata =
17178 (
struct websocket_client_thread_data *)data;
17180#if !defined(_WIN32)
17181 struct sigaction sa;
17184 memset(&sa, 0,
sizeof(sa));
17185 sa.sa_handler = SIG_IGN;
17186 sigaction(SIGPIPE, &sa, NULL);
17191 if (cdata->conn->phys_ctx) {
17192 if (cdata->conn->phys_ctx->callbacks.init_thread) {
17195 cdata->conn->phys_ctx->callbacks.init_thread(cdata->conn->phys_ctx,
17200 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
17202 DEBUG_TRACE(
"%s",
"Websocket client thread exited\n");
17204 if (cdata->close_handler != NULL) {
17205 cdata->close_handler(cdata->conn, cdata->callback_data);
17210 cdata->conn->phys_ctx->stop_flag = 2;
17223struct mg_connection *
17227 char *error_buffer,
17228 size_t error_buffer_size,
17230 const char *origin,
17235 struct mg_connection *conn = NULL;
17237#if defined(USE_WEBSOCKET)
17238 struct mg_context *newctx = NULL;
17239 struct websocket_client_thread_data *thread_data;
17240 static const char *magic =
"x3JJHMbDL1EzLkh9GBhXDw==";
17241 static const char *handshake_req;
17243 if (origin != NULL) {
17244 handshake_req =
"GET %s HTTP/1.1\r\n"
17246 "Upgrade: websocket\r\n"
17247 "Connection: Upgrade\r\n"
17248 "Sec-WebSocket-Key: %s\r\n"
17249 "Sec-WebSocket-Version: 13\r\n"
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#if defined(__clang__)
17263#pragma clang diagnostic push
17264#pragma clang diagnostic ignored "-Wformat-nonliteral"
17279#if defined(__clang__)
17280#pragma clang diagnostic pop
17284 if (conn == NULL) {
17285 if (!*error_buffer) {
17291 "Unexpected error");
17296 if (conn->response_info.status_code != 101) {
17301 if (!*error_buffer) {
17307 "Unexpected server reply");
17310 DEBUG_TRACE(
"Websocket client connect error: %s\r\n", error_buffer);
17317 newctx = (
struct mg_context *)
mg_malloc(
sizeof(
struct mg_context));
17324 memcpy(newctx, conn->phys_ctx,
sizeof(
struct mg_context));
17325 newctx->user_data = user_data;
17327 newctx->cfg_worker_threads = 1;
17328 newctx->worker_threadids =
17333 conn->phys_ctx = newctx;
17334 conn->dom_ctx = &(newctx->dd);
17336 thread_data = (
struct websocket_client_thread_data *)
17337 mg_calloc_ctx(
sizeof(
struct websocket_client_thread_data), 1, newctx);
17338 if (!thread_data) {
17345 thread_data->conn = conn;
17346 thread_data->data_handler = data_func;
17347 thread_data->close_handler = close_func;
17348 thread_data->callback_data = user_data;
17354 (
void *)thread_data,
17355 newctx->worker_threadids)
17357 mg_free((
void *)thread_data);
17358 mg_free((
void *)newctx->worker_threadids);
17363 "Websocket client connect thread could not be started\r\n");
17371 (
void)error_buffer;
17372 (
void)error_buffer_size;
17389 int keep_alive_enabled =
17392 if (!keep_alive_enabled) {
17393 conn->must_close = 1;
17398 conn->data_len = 0;
17399 conn->handled_requests = 0;
17402#if defined(USE_SERVER_STATS)
17403 conn->conn_state = 2;
17407 if (conn->phys_ctx->callbacks.init_connection != NULL) {
17409 void *conn_data = NULL;
17410 conn->phys_ctx->callbacks.init_connection(conn, &conn_data);
17426 int keep_alive, discard_len;
17428 const char *hostend;
17429 int reqerr, uri_type;
17431#if defined(USE_SERVER_STATS)
17432 int mcon =
mg_atomic_inc(&(conn->phys_ctx->active_connections));
17433 mg_atomic_add(&(conn->phys_ctx->total_connections), 1);
17434 if (mcon > (conn->phys_ctx->max_connections)) {
17437 conn->phys_ctx->max_connections = mcon;
17443 DEBUG_TRACE(
"Start processing connection from %s",
17444 conn->request_info.remote_addr);
17450 DEBUG_TRACE(
"calling get_request (%i times for this connection)",
17451 conn->handled_requests + 1);
17453#if defined(USE_SERVER_STATS)
17454 conn->conn_state = 3;
17457 if (!
get_request(conn, ebuf,
sizeof(ebuf), &reqerr)) {
17471 "Bad HTTP version: [%s]",
17476 if (ebuf[0] ==
'\0') {
17477 uri_type =
get_uri_type(conn->request_info.request_uri);
17478 switch (uri_type) {
17481 conn->request_info.local_uri = NULL;
17485 conn->request_info.local_uri = conn->request_info.request_uri;
17491 conn->request_info.request_uri, conn);
17493 conn->request_info.local_uri = hostend;
17495 conn->request_info.local_uri = NULL;
17505 conn->request_info.local_uri = NULL;
17509#if defined(MG_LEGACY_INTERFACE)
17511 conn->request_info.uri = conn->request_info.local_uri;
17517 (ebuf[0] ? ebuf :
"none"));
17519 if (ebuf[0] ==
'\0') {
17520 if (conn->request_info.local_uri) {
17523#if defined(USE_SERVER_STATS)
17524 conn->conn_state = 4;
17528#if defined(USE_SERVER_STATS)
17529 conn->conn_state = 5;
17531 mg_atomic_add(&(conn->phys_ctx->total_data_read),
17532 conn->consumed_content);
17533 mg_atomic_add(&(conn->phys_ctx->total_data_written),
17534 conn->num_bytes_sent);
17539 if (conn->phys_ctx->callbacks.end_request != NULL) {
17540 conn->phys_ctx->callbacks.end_request(conn,
17541 conn->status_code);
17547 conn->must_close = 1;
17550 conn->must_close = 1;
17566 && (conn->content_len >= 0);
17570 discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
17571 && ((conn->request_len + conn->content_len)
17572 < (int64_t)conn->data_len))
17573 ? (int)(conn->request_len + conn->content_len)
17576 if (discard_len < 0) {
17578 (
long int)discard_len);
17581 conn->data_len -= discard_len;
17582 if (conn->data_len > 0) {
17583 DEBUG_TRACE(
"discard_len = %lu", (
long unsigned)discard_len);
17584 memmove(conn->buf, conn->buf + discard_len, (
size_t)conn->data_len);
17590 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
17591 DEBUG_TRACE(
"internal error: data_len = %li, buf_size = %li",
17592 (
long int)conn->data_len,
17593 (
long int)conn->buf_size);
17597 conn->handled_requests++;
17599 }
while (keep_alive);
17601 DEBUG_TRACE(
"Done processing connection from %s (%f sec)",
17602 conn->request_info.remote_addr,
17603 difftime(time(NULL), conn->conn_birth_time));
17607#if defined(USE_SERVER_STATS)
17608 mg_atomic_add(&(conn->phys_ctx->total_requests), conn->handled_requests);
17614#if defined(ALTERNATIVE_QUEUE)
17621 while (!ctx->stop_flag) {
17622 for (i = 0; i < ctx->cfg_worker_threads; i++) {
17624 if (ctx->client_socks[i].in_use == 0) {
17625 ctx->client_socks[i] = *sp;
17626 ctx->client_socks[i].in_use = 1;
17641 ctx->client_socks[thread_index].in_use = 0;
17642 event_wait(ctx->client_wait_events[thread_index]);
17643 *sp = ctx->client_socks[thread_index];
17644 DEBUG_TRACE(
"grabbed socket %d, going busy", sp ? sp->sock : -1);
17646 return !ctx->stop_flag;
17653consume_socket(
struct mg_context *ctx,
struct socket *sp,
int thread_index)
17655#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17657 (
void)thread_index;
17659 (
void)pthread_mutex_lock(&ctx->thread_mutex);
17663 while ((ctx->sq_head == ctx->sq_tail) && (ctx->stop_flag == 0)) {
17664 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
17668 if (ctx->sq_head > ctx->sq_tail) {
17670 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
17673 DEBUG_TRACE(
"grabbed socket %d, going busy", sp ? sp->sock : -1);
17676 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
17677 ctx->sq_tail -= QUEUE_SIZE(ctx);
17678 ctx->sq_head -= QUEUE_SIZE(ctx);
17682 (
void)pthread_cond_signal(&ctx->sq_empty);
17683 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
17685 return !ctx->stop_flag;
17694#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17698 (
void)pthread_mutex_lock(&ctx->thread_mutex);
17701 while ((ctx->stop_flag == 0)
17702 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
17703 (
void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
17706 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
17708 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
17710 DEBUG_TRACE(
"queued socket %d", sp ? sp->sock : -1);
17713 (
void)pthread_cond_signal(&ctx->sq_full);
17714 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
17720struct worker_thread_args {
17721 struct mg_context *ctx;
17729 struct mg_context *ctx = thread_args->ctx;
17730 struct mg_connection *conn;
17731 struct mg_workerTLS tls;
17732#if defined(MG_LEGACY_INTERFACE)
17741 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
17745 pthread_setspecific(
sTlsKey, &tls);
17747 if (ctx->callbacks.init_thread) {
17749 ctx->callbacks.init_thread(ctx, 1);
17753 if (((
int)thread_args->index < 0)
17754 || ((
unsigned)thread_args->index
17755 >= (
unsigned)ctx->cfg_worker_threads)) {
17757 "Internal error: Invalid worker index %i",
17758 (
int)thread_args->index);
17761 conn = ctx->worker_connections + thread_args->index;
17766 conn->buf = (
char *)
mg_malloc_ctx(ctx->max_request_size, conn->phys_ctx);
17767 if (conn->buf == NULL) {
17769 "Out of memory: Cannot allocate buffer for worker %i",
17770 (
int)thread_args->index);
17773 conn->buf_size = (int)ctx->max_request_size;
17775 conn->phys_ctx = ctx;
17776 conn->dom_ctx = &(ctx->dd);
17779 conn->thread_index = thread_args->index;
17780 conn->request_info.user_data = ctx->user_data;
17790#if defined(USE_SERVER_STATS)
17791 conn->conn_state = 1;
17794#if defined(ALTERNATIVE_QUEUE)
17795 while ((ctx->stop_flag == 0)
17801 while (
consume_socket(ctx, &conn->client, conn->thread_index)) {
17804 conn->conn_birth_time = time(NULL);
17810#if defined(USE_IPV6)
17811 if (conn->client.rsa.sa.sa_family == AF_INET6) {
17812 conn->request_info.remote_port =
17813 ntohs(conn->client.rsa.sin6.sin6_port);
17817 conn->request_info.remote_port =
17818 ntohs(conn->client.rsa.sin.sin_port);
17822 sizeof(conn->request_info.remote_addr),
17823 &conn->client.rsa);
17825 DEBUG_TRACE(
"Start processing connection from %s",
17826 conn->request_info.remote_addr);
17828 conn->request_info.is_ssl = conn->client.is_ssl;
17830 if (conn->client.is_ssl) {
17831#if !defined(NO_SSL)
17834 conn->dom_ctx->ssl_ctx,
17836 &(conn->phys_ctx->stop_flag),
17847 if (conn->request_info.client_cert) {
17848 mg_free((
void *)(conn->request_info.client_cert->subject));
17849 mg_free((
void *)(conn->request_info.client_cert->issuer));
17850 mg_free((
void *)(conn->request_info.client_cert->serial));
17851 mg_free((
void *)(conn->request_info.client_cert->finger));
17854 (
X509 *)conn->request_info.client_cert->peer_cert);
17855 conn->request_info.client_cert->peer_cert = 0;
17856 conn->request_info.client_cert->subject = 0;
17857 conn->request_info.client_cert->issuer = 0;
17858 conn->request_info.client_cert->serial = 0;
17859 conn->request_info.client_cert->finger = 0;
17860 mg_free(conn->request_info.client_cert);
17861 conn->request_info.client_cert = 0;
17877 pthread_setspecific(
sTlsKey, NULL);
17879 CloseHandle(tls.pthread_cond_helper_mutex);
17881 pthread_mutex_destroy(&conn->mutex);
17884 conn->buf_size = 0;
17888#if defined(USE_SERVER_STATS)
17889 conn->conn_state = 9;
17899static unsigned __stdcall
worker_thread(
void *thread_func_param)
17901 struct worker_thread_args *pwta =
17902 (
struct worker_thread_args *)thread_func_param;
17911 struct worker_thread_args *pwta =
17912 (
struct worker_thread_args *)thread_func_param;
17913 struct sigaction sa;
17916 memset(&sa, 0,
sizeof(sa));
17917 sa.sa_handler = SIG_IGN;
17918 sigaction(SIGPIPE, &sa, NULL);
17934 socklen_t len =
sizeof(so.rsa);
17937 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
17939 }
else if (!
check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
17942 "%s: %s is not allowed to connect",
17950 so.is_ssl = listener->is_ssl;
17951 so.ssl_redir = listener->ssl_redir;
17952 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
17954 "%s: getsockname() failed: %s",
17966 if (setsockopt(so.sock,
17974 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
17991 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
18015 struct mg_context *ctx = (
struct mg_context *)thread_func_param;
18016 struct mg_workerTLS tls;
18017 struct pollfd *pfd;
18019 unsigned int workerthreadcount;
18029 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
18030#elif defined(USE_MASTER_THREAD_PRIORITY)
18031 int min_prio = sched_get_priority_min(SCHED_RR);
18032 int max_prio = sched_get_priority_max(SCHED_RR);
18033 if ((min_prio >= 0) && (max_prio >= 0)
18034 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
18035 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
18036 struct sched_param sched_param = {0};
18037 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
18038 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
18044 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
18047 pthread_setspecific(
sTlsKey, &tls);
18049 if (ctx->callbacks.init_thread) {
18051 ctx->callbacks.init_thread(ctx, 0);
18055 ctx->start_time = time(NULL);
18058 pfd = ctx->listening_socket_fds;
18059 while (ctx->stop_flag == 0) {
18060 for (i = 0; i < ctx->num_listening_sockets; i++) {
18061 pfd[i].fd = ctx->listening_sockets[i].sock;
18062 pfd[i].events = POLLIN;
18065 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
18066 for (i = 0; i < ctx->num_listening_sockets; i++) {
18072 if ((ctx->stop_flag == 0) && (pfd[i].revents & POLLIN)) {
18086 (
void)pthread_mutex_lock(&ctx->thread_mutex);
18087#if defined(ALTERNATIVE_QUEUE)
18088 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18092 if (ctx->client_socks[i].in_use) {
18097 pthread_cond_broadcast(&ctx->sq_full);
18099 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
18102 workerthreadcount = ctx->cfg_worker_threads;
18103 for (i = 0; i < workerthreadcount; i++) {
18104 if (ctx->worker_threadids[i] != 0) {
18109#if defined(USE_LUA)
18111 if (ctx->lua_background_state) {
18112 lua_State *lstate = (lua_State *)ctx->lua_background_state;
18113 lua_getglobal(lstate, LUABACKGROUNDPARAMS);
18114 if (lua_istable(lstate, -1)) {
18115 reg_boolean(lstate,
"shutdown", 1);
18116 lua_pop(lstate, 1);
18120 ctx->lua_background_state = 0;
18127 CloseHandle(tls.pthread_cond_helper_mutex);
18129 pthread_setspecific(
sTlsKey, NULL);
18134 ctx->stop_flag = 2;
18140static unsigned __stdcall
master_thread(
void *thread_func_param)
18149 struct sigaction sa;
18152 memset(&sa, 0,
sizeof(sa));
18153 sa.sa_handler = SIG_IGN;
18154 sigaction(SIGPIPE, &sa, NULL);
18166 struct mg_handler_info *tmp_rh;
18172 if (ctx->callbacks.exit_context) {
18173 ctx->callbacks.exit_context(ctx);
18179 (
void)pthread_mutex_destroy(&ctx->thread_mutex);
18180#if defined(ALTERNATIVE_QUEUE)
18182 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18185 mg_free(ctx->client_wait_events);
18187 (
void)pthread_cond_destroy(&ctx->sq_empty);
18188 (
void)pthread_cond_destroy(&ctx->sq_full);
18192 (
void)pthread_mutex_destroy(&ctx->nonce_mutex);
18194#if defined(USE_TIMERS)
18200 if (ctx->dd.config[i] != NULL) {
18201#if defined(_MSC_VER)
18202#pragma warning(suppress : 6001)
18209 while (ctx->dd.handlers) {
18210 tmp_rh = ctx->dd.handlers;
18211 ctx->dd.handlers = tmp_rh->next;
18213 pthread_cond_destroy(&tmp_rh->refcount_cond);
18214 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
18220#if !defined(NO_SSL)
18222 if (ctx->dd.ssl_ctx != NULL) {
18223 void *ssl_ctx = (
void *)ctx->dd.ssl_ctx;
18225 (ctx->callbacks.external_ssl_ctx == NULL)
18227 : (ctx->callbacks.external_ssl_ctx(&ssl_ctx, ctx->user_data));
18229 if (callback_ret == 0) {
18238 if (ctx->worker_threadids != NULL) {
18239 mg_free(ctx->worker_threadids);
18243 if (ctx->worker_connections != NULL) {
18244 mg_free(ctx->worker_connections);
18265 mt = ctx->masterthreadid;
18270 ctx->masterthreadid = 0;
18273 ctx->stop_flag = 1;
18276 while (ctx->stop_flag != 2) {
18284 (
void)WSACleanup();
18293#if !defined(__SYMBIAN32__)
18294#if defined(_WIN32_WCE)
18298 DWORD dwVersion = 0;
18299 DWORD dwMajorVersion = 0;
18300 DWORD dwMinorVersion = 0;
18302 BOOL wowRet, isWoW =
FALSE;
18304#if defined(_MSC_VER)
18305#pragma warning(push)
18307#pragma warning(disable : 4996)
18309 dwVersion = GetVersion();
18310#if defined(_MSC_VER)
18311#pragma warning(pop)
18314 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18315 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18316 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
18319 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
18323 (
unsigned)dwMajorVersion,
18324 (
unsigned)dwMinorVersion,
18325 (wowRet ? (isWoW ?
" (WoW64)" :
"") :
" (?)"));
18333 struct utsname
name;
18344 const char **options)
18346 struct mg_context *ctx;
18347 const char *
name, *value, *default_value;
18348 int idx, ok, workerthreadcount;
18351 void (*exit_callback)(
const struct mg_context *ctx) = 0;
18353 struct mg_workerTLS tls;
18357 WSAStartup(MAKEWORD(2, 2), &data);
18361 if ((ctx = (
struct mg_context *)
mg_calloc(1,
sizeof(*ctx))) == NULL) {
18366 ctx->dd.auth_nonce_mask =
18367 (uint64_t)
get_random() ^ (uint64_t)(ptrdiff_t)(options);
18372 const char *ports_option =
18376 const char **run_options = options;
18380 while (*run_options) {
18381 if (!strcmp(*run_options, optname)) {
18382 ports_option = run_options[1];
18397 tls.is_master = -1;
18400 tls.pthread_cond_helper_mutex = NULL;
18402 pthread_setspecific(
sTlsKey, &tls);
18405#if !defined(ALTERNATIVE_QUEUE)
18406 ok &= (0 == pthread_cond_init(&ctx->sq_empty, NULL));
18407 ok &= (0 == pthread_cond_init(&ctx->sq_full, NULL));
18415 "Cannot initialize thread synchronization objects");
18417 pthread_setspecific(
sTlsKey, NULL);
18422 ctx->callbacks = *callbacks;
18424 ctx->callbacks.exit_context = 0;
18426 ctx->user_data = user_data;
18427 ctx->dd.handlers = NULL;
18428 ctx->dd.next = NULL;
18430#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18431 ctx->dd.shared_lua_websockets = NULL;
18435 while (options && (
name = *options++) != NULL) {
18439 pthread_setspecific(
sTlsKey, NULL);
18441 }
else if ((value = *options++) == NULL) {
18444 pthread_setspecific(
sTlsKey, NULL);
18447 if (ctx->dd.config[idx] != NULL) {
18449 mg_free(ctx->dd.config[idx]);
18458 if ((ctx->dd.config[i] == NULL) && (default_value != NULL)) {
18468 pthread_setspecific(
sTlsKey, NULL);
18471 ctx->max_request_size = (unsigned)itmp;
18474 workerthreadcount = atoi(ctx->dd.config[
NUM_THREADS]);
18479 pthread_setspecific(
sTlsKey, NULL);
18483 if (workerthreadcount <= 0) {
18486 pthread_setspecific(
sTlsKey, NULL);
18491#if defined(NO_FILES)
18495 pthread_setspecific(
sTlsKey, NULL);
18502#if defined(USE_LUA)
18504 if (ctx->dd.config[LUA_BACKGROUND_SCRIPT] != NULL) {
18506 struct vec opt_vec;
18508 const char *sparams;
18509 lua_State *state = mg_prepare_lua_context_script(
18510 ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf,
sizeof(ebuf));
18514 pthread_setspecific(
sTlsKey, NULL);
18517 ctx->lua_background_state = (
void *)state;
18519 lua_newtable(state);
18520 reg_boolean(state,
"shutdown", 0);
18522 sparams = ctx->dd.config[LUA_BACKGROUND_SCRIPT_PARAMS];
18524 while ((sparams =
next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
18526 state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
18530 lua_setglobal(state, LUABACKGROUNDPARAMS);
18533 ctx->lua_background_state = 0;
18540#
if !defined(NO_SSL)
18544#
if !defined(_WIN32)
18549 pthread_setspecific(
sTlsKey, NULL);
18553 ctx->cfg_worker_threads = ((
unsigned int)(workerthreadcount));
18554 ctx->worker_threadids = (pthread_t *)
mg_calloc_ctx(ctx->cfg_worker_threads,
18558 if (ctx->worker_threadids == NULL) {
18561 "Not enough memory for worker thread ID array");
18563 pthread_setspecific(
sTlsKey, NULL);
18566 ctx->worker_connections =
18567 (
struct mg_connection *)
mg_calloc_ctx(ctx->cfg_worker_threads,
18568 sizeof(
struct mg_connection),
18570 if (ctx->worker_connections == NULL) {
18573 "Not enough memory for worker thread connection array");
18575 pthread_setspecific(
sTlsKey, NULL);
18580#if defined(ALTERNATIVE_QUEUE)
18581 ctx->client_wait_events =
18583 ctx->cfg_worker_threads,
18585 if (ctx->client_wait_events == NULL) {
18588 "Not enough memory for worker event array");
18589 mg_free(ctx->worker_threadids);
18591 pthread_setspecific(
sTlsKey, NULL);
18595 ctx->client_socks =
18596 (
struct socket *)
mg_calloc_ctx(
sizeof(ctx->client_socks[0]),
18597 ctx->cfg_worker_threads,
18599 if (ctx->client_socks == NULL) {
18602 "Not enough memory for worker socket array");
18603 mg_free(ctx->client_wait_events);
18604 mg_free(ctx->worker_threadids);
18606 pthread_setspecific(
sTlsKey, NULL);
18610 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18612 if (ctx->client_wait_events[i] == 0) {
18619 mg_free(ctx->client_wait_events);
18620 mg_free(ctx->worker_threadids);
18622 pthread_setspecific(
sTlsKey, NULL);
18629#if defined(USE_TIMERS)
18630 if (timers_init(ctx) != 0) {
18633 pthread_setspecific(
sTlsKey, NULL);
18639 if (ctx->callbacks.init_context) {
18640 ctx->callbacks.init_context(ctx);
18642 ctx->callbacks.exit_context = exit_callback;
18649 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18650 struct worker_thread_args *wta = (
struct worker_thread_args *)
18654 wta->index = (int)i;
18660 &ctx->worker_threadids[i])
18670 "Cannot start worker thread %i: error %ld",
18675 "Cannot create threads: error %ld",
18678 pthread_setspecific(
sTlsKey, NULL);
18685 pthread_setspecific(
sTlsKey, NULL);
18690#if defined(MG_EXPERIMENTAL_INTERFACES)
18693mg_start_domain(
struct mg_context *ctx,
const char **options)
18697 const char *default_value;
18698 struct mg_domain_context *new_dom;
18699 struct mg_domain_context *dom;
18702 if ((ctx == NULL) || (ctx->stop_flag != 0) || (options == NULL)) {
18706 new_dom = (
struct mg_domain_context *)
18715 while (options && (
name = *options++) != NULL) {
18720 }
else if ((value = *options++) == NULL) {
18725 if (new_dom->config[idx] != NULL) {
18727 mg_free(new_dom->config[idx]);
18744 default_value = ctx->dd.config[i];
18745 if ((new_dom->config[i] == NULL) && (default_value != NULL)) {
18750 new_dom->handlers = NULL;
18751 new_dom->next = NULL;
18752 new_dom->nonce_count = 0;
18753 new_dom->auth_nonce_mask =
18756#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18757 new_dom->shared_lua_websockets = NULL;
18776 "domain %s already in use",
18785 if (dom->next == NULL) {
18786 dom->next = new_dom;
18804 static const unsigned feature_set = 0
18808#if !defined(NO_FILES)
18811#if !defined(NO_SSL)
18814#if !defined(NO_CGI)
18817#if defined(USE_IPV6)
18820#if defined(USE_WEBSOCKET)
18823#if defined(USE_LUA)
18826#if defined(USE_DUKTAPE)
18829#if !defined(NO_CACHING)
18832#if defined(USE_SERVER_STATS)
18835#if defined(USE_ZLIB)
18841#if defined(MG_LEGACY_INTERFACE)
18844#if defined(MG_EXPERIMENTAL_INTERFACES)
18847#if defined(MEMORY_DEBUGGING)
18850#if defined(USE_TIMERS)
18853#if !defined(NO_NONCE_CHECK)
18856#if !defined(NO_POPEN)
18860 return (feature & feature_set);
18865#define strcat0(a, b) \
18867 if ((a != NULL) && (b != NULL)) { \
18879 int system_info_length = 0;
18882 const char *eol =
"\r\n";
18884 const char *eol =
"\n";
18887 const char *eoobj =
"}";
18888 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
18890 if ((buffer == NULL) || (buflen < 1)) {
18896 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
18897 system_info_length += (int)strlen(block);
18898 if (system_info_length < buflen) {
18909 "\"version\" : \"%s\",%s",
18912 system_info_length += (int)strlen(block);
18913 if (system_info_length < buflen) {
18921 DWORD dwVersion = 0;
18922 DWORD dwMajorVersion = 0;
18923 DWORD dwMinorVersion = 0;
18926 GetSystemInfo(&si);
18928#if defined(_MSC_VER)
18929#pragma warning(push)
18931#pragma warning(disable : 4996)
18933 dwVersion = GetVersion();
18934#if defined(_MSC_VER)
18935#pragma warning(pop)
18938 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18939 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18945 "\"os\" : \"Windows %u.%u\",%s",
18946 (
unsigned)dwMajorVersion,
18947 (
unsigned)dwMinorVersion,
18949 system_info_length += (int)strlen(block);
18950 if (system_info_length < buflen) {
18958 "\"cpu\" : \"type %u, cores %u, mask %x\",%s",
18959 (
unsigned)si.wProcessorArchitecture,
18960 (
unsigned)si.dwNumberOfProcessors,
18961 (
unsigned)si.dwActiveProcessorMask,
18963 system_info_length += (int)strlen(block);
18964 if (system_info_length < buflen) {
18968 struct utsname
name;
18976 "\"os\" : \"%s %s (%s) - %s\",%s",
18982 system_info_length += (int)strlen(block);
18983 if (system_info_length < buflen) {
18995 "\"features\" : %lu,%s"
18996 "\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\",%s",
19010 system_info_length += (int)strlen(block);
19011 if (system_info_length < buflen) {
19015#if defined(USE_LUA)
19020 "\"lua_version\" : \"%u (%s)\",%s",
19021 (
unsigned)LUA_VERSION_NUM,
19024 system_info_length += (int)strlen(block);
19025 if (system_info_length < buflen) {
19029#if defined(USE_DUKTAPE)
19034 "\"javascript\" : \"Duktape %u.%u.%u\",%s",
19035 (
unsigned)DUK_VERSION / 10000,
19036 ((
unsigned)DUK_VERSION / 100) % 100,
19037 (
unsigned)DUK_VERSION % 100,
19039 system_info_length += (int)strlen(block);
19040 if (system_info_length < buflen) {
19048#if defined(GCC_DIAGNOSTIC)
19049#if GCC_VERSION >= 50000
19050#pragma GCC diagnostic push
19052#pragma GCC diagnostic ignored "-Wdate-time"
19059 "\"build\" : \"%s\",%s",
19063#if defined(GCC_DIAGNOSTIC)
19064#if GCC_VERSION >= 50000
19065#pragma GCC diagnostic pop
19069 system_info_length += (int)strlen(block);
19070 if (system_info_length < buflen) {
19079#if defined(_MSC_VER)
19084 "\"compiler\" : \"MSC: %u (%u)\",%s",
19085 (
unsigned)_MSC_VER,
19086 (
unsigned)_MSC_FULL_VER,
19088 system_info_length += (int)strlen(block);
19089 if (system_info_length < buflen) {
19092#elif defined(__MINGW64__)
19097 "\"compiler\" : \"MinGW64: %u.%u\",%s",
19098 (
unsigned)__MINGW64_VERSION_MAJOR,
19099 (
unsigned)__MINGW64_VERSION_MINOR,
19101 system_info_length += (int)strlen(block);
19102 if (system_info_length < buflen) {
19109 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19110 (
unsigned)__MINGW32_MAJOR_VERSION,
19111 (
unsigned)__MINGW32_MINOR_VERSION,
19113 system_info_length += (int)strlen(block);
19114 if (system_info_length < buflen) {
19117#elif defined(__MINGW32__)
19122 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19123 (
unsigned)__MINGW32_MAJOR_VERSION,
19124 (
unsigned)__MINGW32_MINOR_VERSION,
19126 system_info_length += (int)strlen(block);
19127 if (system_info_length < buflen) {
19130#elif defined(__clang__)
19135 "\"compiler\" : \"clang: %u.%u.%u (%s)\",%s",
19138 __clang_patchlevel__,
19141 system_info_length += (int)strlen(block);
19142 if (system_info_length < buflen) {
19145#elif defined(__GNUC__)
19150 "\"compiler\" : \"gcc: %u.%u.%u\",%s",
19151 (
unsigned)__GNUC__,
19152 (
unsigned)__GNUC_MINOR__,
19153 (
unsigned)__GNUC_PATCHLEVEL__,
19155 system_info_length += (int)strlen(block);
19156 if (system_info_length < buflen) {
19159#elif defined(__INTEL_COMPILER)
19164 "\"compiler\" : \"Intel C/C++: %u\",%s",
19165 (
unsigned)__INTEL_COMPILER,
19167 system_info_length += (int)strlen(block);
19168 if (system_info_length < buflen) {
19171#elif defined(__BORLANDC__)
19176 "\"compiler\" : \"Borland C: 0x%x\",%s",
19177 (
unsigned)__BORLANDC__,
19179 system_info_length += (int)strlen(block);
19180 if (system_info_length < buflen) {
19183#elif defined(__SUNPRO_C)
19188 "\"compiler\" : \"Solaris: 0x%x\",%s",
19189 (
unsigned)__SUNPRO_C,
19191 system_info_length += (int)strlen(block);
19192 if (system_info_length < buflen) {
19200 "\"compiler\" : \"other\",%s",
19202 system_info_length += (int)strlen(block);
19203 if (system_info_length < buflen) {
19216 "\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, "
19218 "ptr:%u, size:%u, time:%u\"%s",
19219 (
unsigned)
sizeof(
short),
19220 (
unsigned)
sizeof(
int),
19221 (
unsigned)
sizeof(
long),
19222 (
unsigned)
sizeof(
long long),
19223 (
unsigned)
sizeof(
float),
19224 (
unsigned)
sizeof(
double),
19225 (
unsigned)
sizeof(
long double),
19226 (
unsigned)
sizeof(
char),
19227 (
unsigned)
sizeof(
wchar_t),
19228 (
unsigned)
sizeof(
void *),
19229 (
unsigned)
sizeof(
size_t),
19230 (
unsigned)
sizeof(time_t),
19232 system_info_length += (int)strlen(block);
19233 if (system_info_length < buflen) {
19239 if ((buflen > 0) && buffer && buffer[0]) {
19240 if (system_info_length < buflen) {
19245 system_info_length += reserved_len;
19247 return system_info_length;
19251#if defined(USE_SERVER_STATS)
19255mg_get_context_info_impl(
const struct mg_context *ctx,
char *buffer,
int buflen)
19259 int context_info_length = 0;
19262 const char *eol =
"\r\n";
19264 const char *eol =
"\n";
19266 struct mg_memory_stat *
ms = get_memory_stat((
struct mg_context *)ctx);
19268 const char *eoobj =
"}";
19269 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
19271 if ((buffer == NULL) || (buflen < 1)) {
19277 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
19278 context_info_length += (int)strlen(block);
19279 if (context_info_length < buflen) {
19290 "\"blocks\" : %i,%s"
19304 context_info_length += (int)strlen(block);
19305 if (context_info_length + reserved_len < buflen) {
19313 char start_time_str[64] = {0};
19314 char now_str[64] = {0};
19315 time_t start_time = ctx->start_time;
19316 time_t now = time(NULL);
19323 "\"connections\" : {%s"
19324 "\"active\" : %i,%s"
19325 "\"maxActive\" : %i,%s"
19329 ctx->active_connections,
19331 ctx->max_connections,
19333 ctx->total_connections,
19337 context_info_length += (int)strlen(block);
19338 if (context_info_length + reserved_len < buflen) {
19347 "\"requests\" : {%s"
19351 ctx->total_requests,
19355 context_info_length += (int)strlen(block);
19356 if (context_info_length + reserved_len < buflen) {
19370 ctx->total_data_read,
19372 ctx->total_data_written,
19376 context_info_length += (int)strlen(block);
19377 if (context_info_length + reserved_len < buflen) {
19383 sizeof(start_time_str) - 1,
19392 "\"uptime\" : %.0f,%s"
19393 "\"start\" : \"%s\",%s"
19394 "\"now\" : \"%s\"%s"
19397 difftime(now, start_time),
19405 context_info_length += (int)strlen(block);
19406 if (context_info_length + reserved_len < buflen) {
19412 if ((buflen > 0) && buffer && buffer[0]) {
19413 if (context_info_length < buflen) {
19418 context_info_length += reserved_len;
19420 return context_info_length;
19425#if defined(MG_EXPERIMENTAL_INTERFACES)
19429mg_get_connection_info_impl(
const struct mg_context *ctx,
19434 const struct mg_connection *conn;
19437 int connection_info_length = 0;
19439 const char *state_str =
"unknown";
19442 const char *eol =
"\r\n";
19444 const char *eol =
"\n";
19447 const char *eoobj =
"}";
19448 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
19450 if ((buffer == NULL) || (buflen < 1)) {
19456 if ((ctx == NULL) || (idx < 0)) {
19461 if ((
unsigned)idx >= ctx->cfg_worker_threads) {
19468 conn = (ctx->worker_connections) + idx;
19471 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
19472 connection_info_length += (int)strlen(block);
19473 if (connection_info_length < buflen) {
19478 ri = &(conn->request_info);
19480#if defined(USE_SERVER_STATS)
19481 state = conn->conn_state;
19486 state_str =
"undefined";
19489 state_str =
"not used";
19492 state_str =
"init";
19495 state_str =
"ready";
19498 state_str =
"processing";
19501 state_str =
"processed";
19504 state_str =
"to close";
19507 state_str =
"closing";
19510 state_str =
"closed";
19513 state_str =
"done";
19519 if ((state >= 3) && (state < 9)) {
19524 "\"connection\" : {%s"
19526 "\"protocol\" : \"%s\",%s"
19527 "\"addr\" : \"%s\",%s"
19530 "\"handled_requests\" : %u%s"
19541 conn->handled_requests,
19545 connection_info_length += (int)strlen(block);
19546 if (connection_info_length + reserved_len < buflen) {
19552 if ((state >= 4) && (state < 6)) {
19557 "\"request_info\" : {%s"
19558 "\"method\" : \"%s\",%s"
19559 "\"uri\" : \"%s\",%s"
19560 "\"query\" : %s%s%s%s"
19573 connection_info_length += (int)strlen(block);
19574 if (connection_info_length + reserved_len < buflen) {
19580 if ((state >= 2) && (state < 9)) {
19581 char start_time_str[64] = {0};
19582 char now_str[64] = {0};
19583 time_t start_time = conn->conn_birth_time;
19584 time_t now = time(NULL);
19587 sizeof(start_time_str) - 1,
19596 "\"uptime\" : %.0f,%s"
19597 "\"start\" : \"%s\",%s"
19598 "\"now\" : \"%s\"%s"
19601 difftime(now, start_time),
19609 connection_info_length += (int)strlen(block);
19610 if (connection_info_length + reserved_len < buflen) {
19622 "\"name\" : \"%s\",%s"
19629 connection_info_length += (int)strlen(block);
19630 if (connection_info_length + reserved_len < buflen) {
19646 conn->consumed_content,
19648 conn->num_bytes_sent,
19652 connection_info_length += (int)strlen(block);
19653 if (connection_info_length + reserved_len < buflen) {
19663 "\"state\" : \"%s\"%s",
19667 connection_info_length += (int)strlen(block);
19668 if (connection_info_length + reserved_len < buflen) {
19673 if ((buflen > 0) && buffer && buffer[0]) {
19674 if (connection_info_length < buflen) {
19679 connection_info_length += reserved_len;
19681 return connection_info_length;
19691 if ((buffer == NULL) || (buflen < 1)) {
19706#if defined(USE_SERVER_STATS)
19707 if ((buffer == NULL) || (buflen < 1)) {
19708 return mg_get_context_info_impl(ctx, NULL, 0);
19712 return mg_get_context_info_impl(ctx, buffer, buflen);
19716 if ((buffer != NULL) && (buflen > 0)) {
19724#if defined(MG_EXPERIMENTAL_INTERFACES)
19726mg_get_connection_info(
const struct mg_context *ctx,
19731 if ((buffer == NULL) || (buflen < 1)) {
19732 return mg_get_connection_info_impl(ctx, idx, NULL, 0);
19736 return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
19747#if !defined(NO_SSL)
19752 unsigned features_inited = features_to_init;
19772 InitializeCriticalSection(&global_log_file_lock);
19774#if !defined(_WIN32)
19779#if defined(USE_LUA)
19780 lua_init_optional_libraries();
19786#if !defined(NO_SSL)
19793 DEBUG_TRACE(
"Initializing SSL failed: %s", ebuf);
19807 WSAStartup(MAKEWORD(2, 2), &data);
19815 return features_inited;
19832 (
void)WSACleanup();
19834#if !defined(NO_SSL)
19842 (
void)DeleteCriticalSection(&global_log_file_lock);
19844#if !defined(_WIN32)
19850#if defined(USE_LUA)
19851 lua_exit_optional_libraries();
static const double x2[5]
static const double x1[5]
static unsigned int total
#define INVALID_HANDLE_VALUE
R__EXTERN C unsigned int sleep(unsigned int seconds)
typedef void((*Func_t)())
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)
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
@ 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 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)
static const struct @139 builtin_mime_types[]
#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 const struct @140 abs_uri_protocols[]
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
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)
@ CONNECTION_TYPE_RESPONSE
@ CONNECTION_TYPE_INVALID
@ CONNECTION_TYPE_REQUEST
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
#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)
@ 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
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 *)
@ MG_FEATURES_COMPRESSION
#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)
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)
@ MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE
@ MG_WEBSOCKET_OPCODE_PONG
@ MG_WEBSOCKET_OPCODE_PING
#define PRINTF_ARGS(x, y)
int(* mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *)
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
void(* mg_websocket_close_handler)(const struct mg_connection *, void *)
int(* mg_websocket_connect_handler)(const struct mg_connection *, void *)
struct md5_state_s md5_state_t
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
MD5_STATIC void md5_init(md5_state_t *pms)
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
static constexpr double s
static constexpr double pi
static constexpr double second
static constexpr double ms
static constexpr double L
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)
void(* exit_context)(const struct mg_context *ctx)
const char * default_value
struct mg_header http_headers[MG_MAX_HEADERS]
const char * request_method
const char * query_string
const char * http_version
const char * http_version
struct mg_header http_headers[MG_MAX_HEADERS]
static void output(int code)