24 #if !defined(_CRT_SECURE_NO_WARNINGS) 25 #define _CRT_SECURE_NO_WARNINGS 28 #define _WIN32_WINNT 0x0501 31 #if !defined(_GNU_SOURCE) 34 #if defined(__linux__) && !defined(_XOPEN_SOURCE) 35 #define _XOPEN_SOURCE 600 37 #ifndef _LARGEFILE_SOURCE 38 #define _LARGEFILE_SOURCE 40 #ifndef _FILE_OFFSET_BITS 41 #define _FILE_OFFSET_BITS 64 43 #ifndef __STDC_FORMAT_MACROS 44 #define __STDC_FORMAT_MACROS 46 #ifndef __STDC_LIMIT_MACROS 47 #define __STDC_LIMIT_MACROS 50 #define __EXTENSIONS__ 51 #define __inline inline 61 #pragma warning(disable : 4306) 63 #pragma warning(disable : 4127) 65 #pragma warning(disable : 4204) 67 #pragma warning(disable : 4820) 69 #pragma warning(disable : 4668) 71 #pragma warning(disable : 4255) 73 #pragma warning(disable : 4711) 80 #if defined(_MSC_VER) && (_MSC_VER >= 1600) 81 #define mg_static_assert static_assert 82 #elif defined(__cplusplus) && (__cplusplus >= 201103L) 83 #define mg_static_assert static_assert 84 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) 85 #define mg_static_assert _Static_assert 88 #define mg_static_assert(cond, txt) \ 89 extern char static_assert_replacement[(cond) ? 1 : -1] 93 "int data type size check");
95 "pointer data type size check");
100 #ifdef NO_ALTERNATIVE_QUEUE 101 #ifdef ALTERNATIVE_QUEUE 102 #error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both" 105 #define ALTERNATIVE_QUEUE 110 #ifndef WIN32_LEAN_AND_MEAN 111 #define WIN32_LEAN_AND_MEAN 114 #if defined(__SYMBIAN32__) 123 "Symbian is no longer maintained. CivetWeb will drop Symbian support." 126 #define PATH_MAX FILENAME_MAX 130 #ifndef CIVETWEB_HEADER_INCLUDED 137 #ifndef IGNORE_UNUSED_RESULT 138 #define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) 142 #if defined(__GNUC__) || defined(__MINGW32__) 158 #pragma GCC diagnostic ignored "-Wunused-function" 160 #define FUNCTION_MAY_BE_UNUSED 163 #define FUNCTION_MAY_BE_UNUSED 168 #include <sys/types.h> 169 #include <sys/stat.h> 180 #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" 183 #if defined(__GNUC__) || defined(__MINGW32__) 201 #if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8)) 203 #pragma clang diagnostic ignored "-Wno-reserved-id-macro" 204 #pragma clang diagnostic ignored "-Wno-keyword-macro" 208 #define CLOCK_MONOTONIC (1) 209 #define CLOCK_REALTIME (2) 211 #include <sys/errno.h> 212 #include <sys/time.h> 213 #include <mach/clock.h> 214 #include <mach/mach.h> 215 #include <mach/mach_time.h> 220 _civet_clock_gettime(
int clk_id,
struct timespec *t)
222 memset(t, 0,
sizeof(*t));
223 if (clk_id == CLOCK_REALTIME) {
225 int rv = gettimeofday(&now, NULL);
229 t->tv_sec = now.tv_sec;
230 t->tv_nsec = now.tv_usec * 1000;
233 }
else if (clk_id == CLOCK_MONOTONIC) {
234 static uint64_t clock_start_time = 0;
235 static mach_timebase_info_data_t timebase_ifo = {0, 0};
237 uint64_t now = mach_absolute_time();
239 if (clock_start_time == 0) {
240 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
242 assert(mach_status == KERN_SUCCESS);
247 clock_start_time = now;
250 now = (uint64_t)((
double)(now - clock_start_time)
251 * (
double)timebase_ifo.numer
252 / (double)timebase_ifo.denom);
254 t->tv_sec = now / 1000000000;
255 t->tv_nsec = now % 1000000000;
262 #ifdef __CLOCK_AVAILABILITY 267 _civet_safe_clock_gettime(
int clk_id,
struct timespec *t)
270 return clock_gettime(clk_id, t);
272 return _civet_clock_gettime(clk_id, t);
274 #define clock_gettime _civet_safe_clock_gettime 276 #define clock_gettime _civet_clock_gettime 294 #define INT64_MAX (9223372036854775807) 298 #ifndef MAX_WORKER_THREADS 299 #define MAX_WORKER_THREADS (1024 * 64) 302 #ifndef SOCKET_TIMEOUT_QUANTUM 303 #define SOCKET_TIMEOUT_QUANTUM (2000) 306 #define SHUTDOWN_RD (0) 307 #define SHUTDOWN_WR (1) 308 #define SHUTDOWN_BOTH (2) 311 "worker threads must be a positive number");
314 "size_t data type size check");
316 #if defined(_WIN32) \ 317 && !defined(__SYMBIAN32__) 319 #include <winsock2.h> 320 #include <ws2tcpip.h> 324 #if !defined(PATH_MAX) 325 #define PATH_MAX (MAX_PATH) 328 #if !defined(PATH_MAX) 329 #define PATH_MAX (4096) 336 #define in_port_t u_short 350 #define errno ((int)(GetLastError())) 351 #define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10)) 354 #define MAKEUQUAD(lo, hi) \ 355 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32)) 356 #define RATE_DIFF (10000000) 357 #define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de)) 358 #define SYS2UNIX_TIME(lo, hi) \ 359 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)) 364 #if defined(_MSC_VER) 365 #if (_MSC_VER < 1300) 367 #define STR(x) STRX(x) 368 #define __func__ __FILE__ ":" STR(__LINE__) 369 #define strtoull(x, y, z) ((unsigned __int64)_atoi64(x)) 370 #define strtoll(x, y, z) (_atoi64(x)) 372 #define __func__ __FUNCTION__ 373 #define strtoull(x, y, z) (_strtoui64(x, y, z)) 374 #define strtoll(x, y, z) (_strtoi64(x, y, z)) 378 #define ERRNO ((int)(GetLastError())) 381 #if defined(_WIN64) || defined(__MINGW64__) 382 #define SSL_LIB "ssleay64.dll" 383 #define CRYPTO_LIB "libeay64.dll" 385 #define SSL_LIB "ssleay32.dll" 386 #define CRYPTO_LIB "libeay32.dll" 389 #define O_NONBLOCK (0) 393 #if !defined(EWOULDBLOCK) 394 #define EWOULDBLOCK WSAEWOULDBLOCK 397 #define INT64_FMT "I64d" 398 #define UINT64_FMT "I64u" 400 #define WINCDECL __cdecl 401 #define vsnprintf_impl _vsnprintf 402 #define access _access 403 #define mg_sleep(x) (Sleep(x)) 405 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) 407 #define popen(x, y) (_popen(x, y)) 410 #define pclose(x) (_pclose(x)) 412 #define close(x) (_close(x)) 413 #define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y))) 414 #define RTLD_LAZY (0) 415 #define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0) 416 #define fdopen(x, y) (_fdopen((x), (y))) 417 #define write(x, y, z) (_write((x), (y), (unsigned)z)) 418 #define read(x, y, z) (_read((x), (y), (unsigned)z)) 419 #define flockfile(x) (EnterCriticalSection(&global_log_file_lock)) 420 #define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock)) 421 #define sleep(x) (Sleep((x)*1000)) 422 #define rmdir(x) (_rmdir(x)) 423 #define timegm(x) (_mkgmtime(x)) 426 #define fileno(x) (_fileno(x)) 429 typedef HANDLE pthread_mutex_t;
430 typedef DWORD pthread_key_t;
431 typedef HANDLE pthread_t;
433 CRITICAL_SECTION threadIdSec;
434 struct mg_workerTLS *waiting_thread;
437 #ifndef __clockid_t_defined 438 typedef DWORD clockid_t;
440 #ifndef CLOCK_MONOTONIC 441 #define CLOCK_MONOTONIC (1) 443 #ifndef CLOCK_REALTIME 444 #define CLOCK_REALTIME (2) 447 #define CLOCK_THREAD (3) 449 #ifndef CLOCK_PROCESS 450 #define CLOCK_PROCESS (4) 454 #if defined(_MSC_VER) && (_MSC_VER >= 1900) 455 #define _TIMESPEC_DEFINED 457 #ifndef _TIMESPEC_DEFINED 464 #if !defined(WIN_PTHREADS_TIME_H) 465 #define MUST_IMPLEMENT_CLOCK_GETTIME 468 #ifdef MUST_IMPLEMENT_CLOCK_GETTIME 469 #define clock_gettime mg_clock_gettime 471 clock_gettime(clockid_t clk_id,
struct timespec *tp)
474 ULARGE_INTEGER li, li2;
477 static double perfcnt_per_sec = 0.0;
480 memset(tp, 0,
sizeof(*tp));
482 if (clk_id == CLOCK_REALTIME) {
485 GetSystemTimeAsFileTime(&ft);
486 li.LowPart = ft.dwLowDateTime;
487 li.HighPart = ft.dwHighDateTime;
488 li.QuadPart -= 116444736000000000;
489 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
490 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
494 }
else if (clk_id == CLOCK_MONOTONIC) {
497 if (perfcnt_per_sec == 0.0) {
498 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
499 perfcnt_per_sec = 1.0 / li.QuadPart;
501 if (perfcnt_per_sec != 0.0) {
502 QueryPerformanceCounter((LARGE_INTEGER *)&li);
503 d = li.QuadPart * perfcnt_per_sec;
504 tp->tv_sec = (time_t)d;
506 tp->tv_nsec = (long)(d * 1.0E9);
511 }
else if (clk_id == CLOCK_THREAD) {
514 FILETIME t_create, t_exit, t_kernel, t_user;
515 if (GetThreadTimes(GetCurrentThread(),
520 li.LowPart = t_user.dwLowDateTime;
521 li.HighPart = t_user.dwHighDateTime;
522 li2.LowPart = t_kernel.dwLowDateTime;
523 li2.HighPart = t_kernel.dwHighDateTime;
524 li.QuadPart += li2.QuadPart;
525 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
526 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
531 }
else if (clk_id == CLOCK_PROCESS) {
534 FILETIME t_create, t_exit, t_kernel, t_user;
535 if (GetProcessTimes(GetCurrentProcess(),
540 li.LowPart = t_user.dwLowDateTime;
541 li.HighPart = t_user.dwHighDateTime;
542 li2.LowPart = t_kernel.dwLowDateTime;
543 li2.HighPart = t_kernel.dwHighDateTime;
544 li.QuadPart += li2.QuadPart;
545 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
546 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
566 static int pthread_mutex_lock(pthread_mutex_t *);
567 static int pthread_mutex_unlock(pthread_mutex_t *);
568 static void path_to_unicode(
const struct mg_connection *conn,
580 mg_fgets(
char *buf,
size_t size,
struct mg_file *filep,
char **p);
585 char d_name[PATH_MAX];
590 WIN32_FIND_DATAW info;
591 struct dirent result;
594 #if defined(_WIN32) && !defined(POLLIN) 601 #define POLLIN (0x0300) 606 #if defined(_MSC_VER) 607 #pragma comment(lib, "Ws2_32.lib") 613 #include <sys/wait.h> 614 #include <sys/socket.h> 615 #include <sys/poll.h> 616 #include <netinet/in.h> 617 #include <arpa/inet.h> 618 #include <sys/time.h> 619 #include <sys/utsname.h> 621 #include <inttypes.h> 623 #include <netinet/tcp.h> 627 typedef unsigned short int in_port_t;
634 #define vsnprintf_impl vsnprintf 636 #if !defined(NO_SSL_DL) && !defined(NO_SSL) 640 #if defined(__MACH__) 641 #define SSL_LIB "libssl.dylib" 642 #define CRYPTO_LIB "libcrypto.dylib" 644 #if !defined(SSL_LIB) 645 #define SSL_LIB "libssl.so" 647 #if !defined(CRYPTO_LIB) 648 #define CRYPTO_LIB "libcrypto.so" 654 #define closesocket(a) (close(a)) 655 #define mg_mkdir(conn, path, mode) (mkdir(path, mode)) 656 #define mg_remove(conn, x) (remove(x)) 657 #define mg_sleep(x) (usleep((x)*1000)) 658 #define mg_opendir(conn, x) (opendir(x)) 659 #define mg_closedir(x) (closedir(x)) 660 #define mg_readdir(x) (readdir(x)) 661 #define ERRNO (errno) 662 #define INVALID_SOCKET (-1) 663 #define INT64_FMT PRId64 664 #define UINT64_FMT PRIu64 670 #ifndef CLOCK_MONOTONIC 671 #define CLOCK_MONOTONIC CLOCK_REALTIME 682 #define socklen_t int 690 #define va_copy(x, y) ((x) = (y)) 696 #if defined(__MINGW32__) 698 #pragma GCC diagnostic push 699 #pragma GCC diagnostic ignored "-Wunused-function" 703 static CRITICAL_SECTION global_log_file_lock;
709 return GetCurrentThreadId();
717 void (*_ignored)(
void *)
724 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
732 pthread_key_delete(pthread_key_t key)
734 return TlsFree(key) ? 0 : 1;
740 pthread_setspecific(pthread_key_t key,
void *value)
742 return TlsSetValue(key, value) ? 0 : 1;
748 pthread_getspecific(pthread_key_t key)
750 return TlsGetValue(key);
753 #if defined(__MINGW32__) 755 #pragma GCC diagnostic pop 764 #define PASSWORDS_FILE_NAME ".htpasswd" 765 #define CGI_ENVIRONMENT_SIZE (4096) 766 #define MAX_CGI_ENVIR_VARS (256) 767 #define MG_BUF_LEN (8192) 769 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) 772 #if defined(_WIN32_WCE) 775 #if defined(__MINGW32__) 777 #pragma GCC diagnostic push 778 #pragma GCC diagnostic ignored "-Wunused-function" 791 SystemTimeToFileTime(&st, &ft);
792 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
804 localtime_s(
const time_t *ptime,
struct tm *ptm)
806 int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
809 TIME_ZONE_INFORMATION tzinfo;
816 FileTimeToLocalFileTime(&ft, &lft);
817 FileTimeToSystemTime(&lft, &st);
818 ptm->tm_year = st.wYear - 1900;
819 ptm->tm_mon = st.wMonth - 1;
820 ptm->tm_wday = st.wDayOfWeek;
821 ptm->tm_mday = st.wDay;
822 ptm->tm_hour = st.wHour;
823 ptm->tm_min = st.wMinute;
824 ptm->tm_sec = st.wSecond;
827 (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0;
835 gmtime_s(
const time_t *ptime,
struct tm *ptm)
838 return localtime_s(ptime, ptm);
843 static struct tm tm_array[MAX_WORKER_THREADS];
844 static int tm_index = 0;
849 localtime(
const time_t *ptime)
851 int i =
mg_atomic_inc(&tm_index) % (
sizeof(tm_array) /
sizeof(tm_array[0]));
852 return localtime_s(ptime, tm_array + i);
858 gmtime(
const time_t *ptime)
861 return gmtime_s(ptime, tm_array + i);
867 strftime(
char *dst,
size_t dst_size,
const char *fmt,
const struct tm *tm)
874 #define _beginthreadex(psec, stack, func, prm, flags, ptid) \ 875 (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid) 877 #define remove(f) mg_remove(NULL, f) 882 rename(
const char *
a,
const char *
b)
884 wchar_t wa[PATH_MAX];
885 wchar_t wb[PATH_MAX];
889 return MoveFileW(wa, wb) ? 0 : -1;
901 stat(
const char *
name,
struct stat *st)
903 wchar_t wbuf[PATH_MAX];
904 WIN32_FILE_ATTRIBUTE_DATA attr;
905 time_t creation_time, write_time;
907 path_to_unicode(NULL, name, wbuf,
ARRAY_SIZE(wbuf));
908 memset(&attr, 0,
sizeof(attr));
910 GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr);
912 (((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow;
914 write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime,
915 attr.ftLastWriteTime.dwHighDateTime);
916 creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime,
917 attr.ftCreationTime.dwHighDateTime);
919 if (creation_time > write_time) {
920 st->st_mtime = creation_time;
922 st->st_mtime = write_time;
927 #define access(x, a) 1 935 #if defined(__MINGW32__) 937 #pragma GCC diagnostic pop 943 #if defined(__GNUC__) || defined(__MINGW32__) 945 #define GCC_VERSION \ 946 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 947 #if GCC_VERSION >= 40500 948 #pragma GCC diagnostic push 949 #pragma GCC diagnostic ignored "-Wunused-function" 952 #if defined(__clang__) 954 #pragma clang diagnostic push 955 #pragma clang diagnostic ignored "-Wunused-function" 961 #if defined(_WIN32) && !defined(__SYMBIAN32__) 964 static int pthread_mutex_lock(pthread_mutex_t *mutex);
967 static int pthread_mutex_unlock(pthread_mutex_t *mutex);
975 (
void)pthread_mutex_lock(&global_lock_mutex);
983 (
void)pthread_mutex_unlock(&global_lock_mutex);
992 #if defined(_WIN32) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS) 996 ret = InterlockedIncrement((
volatile long *)addr);
997 #elif defined(__GNUC__) \ 998 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ 999 && !defined(NO_ATOMICS) 1000 ret = __sync_add_and_fetch(addr, 1);
1015 #if defined(_WIN32) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS) 1019 ret = InterlockedDecrement((
volatile long *)addr);
1020 #elif defined(__GNUC__) \ 1021 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ 1022 && !defined(NO_ATOMICS) 1023 ret = __sync_sub_and_fetch(addr, 1);
1033 #if defined(USE_SERVER_STATS) 1035 mg_atomic_add(
volatile int64_t *addr, int64_t value)
1038 #if defined(_WIN64) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS) 1039 ret = InterlockedAdd64(addr, value);
1040 #elif defined(__GNUC__) \ 1041 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \ 1042 && !defined(NO_ATOMICS) 1043 ret = __sync_add_and_fetch(addr, value);
1055 #if defined(__GNUC__) 1057 #if GCC_VERSION >= 40500 1058 #pragma GCC diagnostic pop 1061 #if defined(__clang__) 1063 #pragma clang diagnostic pop 1067 #if defined(USE_SERVER_STATS) 1069 struct mg_memory_stat {
1070 volatile int64_t totalMemUsed;
1071 volatile int64_t maxMemUsed;
1072 volatile int blockCount;
1076 static struct mg_memory_stat *get_memory_stat(
struct mg_context *ctx);
1080 mg_malloc_ex(
size_t size,
1081 struct mg_context *ctx,
1085 void *
data =
malloc(size + 2 *
sizeof(uintptr_t));
1087 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1089 #if defined(MEMORY_DEBUGGING) 1090 char mallocStr[256];
1097 int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size);
1098 if (mmem > mstat->maxMemUsed) {
1101 mstat->maxMemUsed = mmem;
1105 ((uintptr_t *)data)[0] = size;
1106 ((uintptr_t *)data)[1] = (uintptr_t)mstat;
1107 memory = (
void *)(((
char *)
data) + 2 *
sizeof(uintptr_t));
1110 #if defined(MEMORY_DEBUGGING) 1112 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1114 (
unsigned long)size,
1115 (
unsigned long)mstat->totalMemUsed,
1116 (
unsigned long)mstat->blockCount,
1120 OutputDebugStringA(mallocStr);
1131 mg_calloc_ex(
size_t count,
1133 struct mg_context *ctx,
1137 void *
data = mg_malloc_ex(size * count, ctx, file, line);
1140 memset(data, 0, size * count);
1147 mg_free_ex(
void *memory,
const char *file,
unsigned line)
1149 void *
data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1152 #if defined(MEMORY_DEBUGGING) 1153 char mallocStr[256];
1160 uintptr_t size = ((uintptr_t *)data)[0];
1161 struct mg_memory_stat *mstat =
1162 (
struct mg_memory_stat *)(((uintptr_t *)
data)[1]);
1163 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size);
1165 #if defined(MEMORY_DEBUGGING) 1167 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1169 (
unsigned long)size,
1170 (
unsigned long)mstat->totalMemUsed,
1171 (
unsigned long)mstat->blockCount,
1175 OutputDebugStringA(mallocStr);
1186 mg_realloc_ex(
void *memory,
1188 struct mg_context *ctx,
1196 #if defined(MEMORY_DEBUGGING) 1197 char mallocStr[256];
1206 struct mg_memory_stat *mstat;
1207 data = (
void *)(((
char *)memory) - 2 *
sizeof(uintptr_t));
1208 oldsize = ((uintptr_t *)data)[0];
1209 mstat = (
struct mg_memory_stat *)((uintptr_t *)
data)[1];
1210 _realloc =
realloc(data, newsize + 2 *
sizeof(uintptr_t));
1213 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize);
1214 #if defined(MEMORY_DEBUGGING) 1216 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1218 (
unsigned long)oldsize,
1219 (
unsigned long)mstat->totalMemUsed,
1220 (
unsigned long)mstat->blockCount,
1224 OutputDebugStringA(mallocStr);
1229 mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize);
1230 #if defined(MEMORY_DEBUGGING) 1232 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1234 (
unsigned long)newsize,
1235 (
unsigned long)mstat->totalMemUsed,
1236 (
unsigned long)mstat->blockCount,
1240 OutputDebugStringA(mallocStr);
1245 *(uintptr_t *)data = newsize;
1246 data = (
void *)(((
char *)
data) + 2 *
sizeof(uintptr_t));
1248 #if defined(MEMORY_DEBUGGING) 1250 OutputDebugStringA(
"MEM: realloc failed\n");
1259 data = mg_malloc_ex(newsize, ctx, file, line);
1264 mg_free_ex(memory, file, line);
1270 #define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__) 1271 #define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__) 1272 #define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__) 1273 #define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) 1275 #define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__) 1276 #define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__) 1277 #define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__) 1281 static __inline
void *
1287 static __inline
void *
1293 static __inline
void *
1299 static __inline
void 1305 #define mg_malloc_ctx(a, c) mg_malloc(a) 1306 #define mg_calloc_ctx(a, b, c) mg_calloc(a, b) 1307 #define mg_realloc_ctx(a, b, c) mg_realloc(a, b) 1308 #define mg_free_ctx(a, c) mg_free(a) 1313 static void mg_vsnprintf(
const struct mg_connection *conn,
1320 static void mg_snprintf(
const struct mg_connection *conn,
1347 #define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc 1348 #define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc 1349 #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc 1350 #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free 1351 #define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf 1354 #define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf 1361 #if !defined(NO_SSL) 1369 struct mg_workerTLS {
1371 unsigned long thread_idx;
1372 #if defined(_WIN32) && !defined(__SYMBIAN32__) 1373 HANDLE pthread_cond_helper_mutex;
1374 struct mg_workerTLS *next_waiting_thread;
1379 #if defined(__GNUC__) || defined(__MINGW32__) 1381 #if GCC_VERSION >= 40500 1382 #pragma GCC diagnostic push 1383 #pragma GCC diagnostic ignored "-Wunused-function" 1386 #if defined(__clang__) 1388 #pragma clang diagnostic push 1389 #pragma clang diagnostic ignored "-Wunused-function" 1404 static unsigned long 1408 return GetCurrentThreadId();
1412 #pragma clang diagnostic push 1413 #pragma clang diagnostic ignored "-Wunreachable-code" 1421 if (
sizeof(pthread_t) >
sizeof(
unsigned long)) {
1424 struct mg_workerTLS *tls =
1425 (
struct mg_workerTLS *)pthread_getspecific(sTlsKey);
1429 tls = (
struct mg_workerTLS *)
mg_malloc(
sizeof(
struct mg_workerTLS));
1430 tls->is_master = -2;
1432 pthread_setspecific(sTlsKey, tls);
1434 return tls->thread_idx;
1439 unsigned long ret = 0;
1440 pthread_t t = pthread_self();
1441 memcpy(&ret, &t,
sizeof(pthread_t));
1446 #pragma clang diagnostic pop 1457 struct timespec tsnow;
1458 clock_gettime(CLOCK_REALTIME, &tsnow);
1459 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1463 #if defined(__GNUC__) 1465 #if GCC_VERSION >= 40500 1466 #pragma GCC diagnostic pop 1469 #if defined(__clang__) 1471 #pragma clang diagnostic pop 1475 #if !defined(DEBUG_TRACE) 1477 static void DEBUG_TRACE_FUNC(
const char *func,
1483 DEBUG_TRACE_FUNC(const
char *func,
unsigned line, const
char *fmt, ...)
1487 static uint64_t nslast;
1488 struct timespec tsnow;
1493 clock_gettime(CLOCK_REALTIME, &tsnow);
1494 nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000)
1495 + ((uint64_t)tsnow.tv_nsec);
1502 printf(
"*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ",
1503 (
unsigned long)tsnow.tv_sec,
1504 (
unsigned long)tsnow.tv_nsec,
1509 va_start(args, fmt);
1514 funlockfile(stdout);
1518 #define DEBUG_TRACE(fmt, ...) \ 1519 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) 1522 #define DEBUG_TRACE(fmt, ...) \ 1529 #define MD5_STATIC static 1534 typedef int socklen_t;
1536 #define _DARWIN_UNLIMITED_SELECT 1538 #define IP_ADDR_STR_LEN (50) 1540 #if !defined(MSG_NOSIGNAL) 1541 #define MSG_NOSIGNAL (0) 1544 #if !defined(SOMAXCONN) 1545 #define SOMAXCONN (100) 1549 #if !defined(MGSQLEN) 1550 #define MGSQLEN (20) 1558 #if defined(NO_SSL_DL) 1559 #include <openssl/ssl.h> 1560 #include <openssl/err.h> 1561 #include <openssl/crypto.h> 1562 #include <openssl/x509.h> 1563 #include <openssl/pem.h> 1564 #include <openssl/engine.h> 1565 #include <openssl/conf.h> 1566 #include <openssl/dh.h> 1567 #include <openssl/bn.h> 1568 #include <openssl/opensslv.h> 1587 #define SSL_CTRL_OPTIONS (32) 1588 #define SSL_CTRL_CLEAR_OPTIONS (77) 1589 #define SSL_CTRL_SET_ECDH_AUTO (94) 1591 #define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L 1592 #define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L 1593 #define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L 1595 #define SSL_VERIFY_NONE (0) 1596 #define SSL_VERIFY_PEER (1) 1597 #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2) 1598 #define SSL_VERIFY_CLIENT_ONCE (4) 1599 #define SSL_OP_ALL ((long)(0x80000BFFUL)) 1600 #define SSL_OP_NO_SSLv2 (0x01000000L) 1601 #define SSL_OP_NO_SSLv3 (0x02000000L) 1602 #define SSL_OP_NO_TLSv1 (0x04000000L) 1603 #define SSL_OP_NO_TLSv1_2 (0x08000000L) 1604 #define SSL_OP_NO_TLSv1_1 (0x10000000L) 1605 #define SSL_OP_SINGLE_DH_USE (0x00100000L) 1606 #define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L) 1607 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L) 1608 #define SSL_OP_NO_COMPRESSION (0x00020000L) 1610 #define SSL_CB_HANDSHAKE_START (0x10) 1611 #define SSL_CB_HANDSHAKE_DONE (0x20) 1613 #define SSL_ERROR_NONE (0) 1614 #define SSL_ERROR_SSL (1) 1615 #define SSL_ERROR_WANT_READ (2) 1616 #define SSL_ERROR_WANT_WRITE (3) 1617 #define SSL_ERROR_WANT_X509_LOOKUP (4) 1618 #define SSL_ERROR_SYSCALL (5) 1619 #define SSL_ERROR_ZERO_RETURN (6) 1620 #define SSL_ERROR_WANT_CONNECT (7) 1621 #define SSL_ERROR_WANT_ACCEPT (8) 1630 #ifdef OPENSSL_API_1_1 1632 #define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) 1633 #define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) 1634 #define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) 1635 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) 1636 #define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) 1637 #define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) 1638 #define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) 1639 #define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) 1640 #define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) 1641 #define TLS_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) 1642 #define OPENSSL_init_ssl \ 1643 (*(int (*)(uint64_t opts, \ 1644 const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10].ptr) 1645 #define SSL_CTX_use_PrivateKey_file \ 1646 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) 1647 #define SSL_CTX_use_certificate_file \ 1648 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) 1649 #define SSL_CTX_set_default_passwd_cb \ 1650 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) 1651 #define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) 1652 #define SSL_CTX_use_certificate_chain_file \ 1653 (*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr) 1654 #define TLS_client_method (*(SSL_METHOD * (*)(void))ssl_sw[16].ptr) 1655 #define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr) 1656 #define SSL_CTX_set_verify \ 1657 (*(void (*)(SSL_CTX *, \ 1659 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18].ptr) 1660 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr) 1661 #define SSL_CTX_load_verify_locations \ 1662 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr) 1663 #define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr) 1664 #define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr) 1665 #define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[23].ptr) 1666 #define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr) 1667 #define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[25].ptr) 1668 #define SSL_CIPHER_get_name \ 1669 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr) 1670 #define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr) 1671 #define SSL_CTX_set_session_id_context \ 1672 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr) 1673 #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr) 1674 #define SSL_CTX_set_cipher_list \ 1675 (*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr) 1676 #define SSL_CTX_set_options \ 1677 (*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr) 1678 #define SSL_CTX_set_info_callback \ 1679 (*(void (*)(SSL_CTX * ctx, \ 1680 void (*callback)(const SSL * s, int, int)))ssl_sw[32].ptr) 1681 #define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr) 1682 #define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr) 1684 #define SSL_CTX_clear_options(ctx, op) \ 1685 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL) 1686 #define SSL_CTX_set_ecdh_auto(ctx, onoff) \ 1687 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) 1689 #define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) 1690 #define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) 1692 #define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) 1693 #define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) 1695 #define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr) 1696 #define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr) 1697 #define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[2].ptr) 1698 #define CONF_modules_unload (*(void (*)(int))crypto_sw[3].ptr) 1699 #define X509_free (*(void (*)(X509 *))crypto_sw[4].ptr) 1700 #define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[5].ptr) 1701 #define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[6].ptr) 1702 #define X509_NAME_oneline \ 1703 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[7].ptr) 1704 #define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[8].ptr) 1705 #define EVP_get_digestbyname \ 1706 (*(const EVP_MD *(*)(const char *))crypto_sw[9].ptr) 1707 #define EVP_Digest \ 1709 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \ 1711 #define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[11].ptr) 1712 #define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[12].ptr) 1713 #define ASN1_INTEGER_to_BN \ 1714 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[13].ptr) 1715 #define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[14].ptr) 1716 #define CRYPTO_free (*(void (*)(void *addr))crypto_sw[15].ptr) 1718 #define OPENSSL_free(a) CRYPTO_free(a) 1725 static struct ssl_func ssl_sw[] = {{
"SSL_free", NULL},
1726 {
"SSL_accept", NULL},
1727 {
"SSL_connect", NULL},
1729 {
"SSL_write", NULL},
1730 {
"SSL_get_error", NULL},
1731 {
"SSL_set_fd", NULL},
1733 {
"SSL_CTX_new", NULL},
1734 {
"TLS_server_method", NULL},
1735 {
"OPENSSL_init_ssl", NULL},
1736 {
"SSL_CTX_use_PrivateKey_file", NULL},
1737 {
"SSL_CTX_use_certificate_file", NULL},
1738 {
"SSL_CTX_set_default_passwd_cb", NULL},
1739 {
"SSL_CTX_free", NULL},
1740 {
"SSL_CTX_use_certificate_chain_file", NULL},
1741 {
"TLS_client_method", NULL},
1742 {
"SSL_pending", NULL},
1743 {
"SSL_CTX_set_verify", NULL},
1744 {
"SSL_shutdown", NULL},
1745 {
"SSL_CTX_load_verify_locations", NULL},
1746 {
"SSL_CTX_set_default_verify_paths", NULL},
1747 {
"SSL_CTX_set_verify_depth", NULL},
1748 {
"SSL_get_peer_certificate", NULL},
1749 {
"SSL_get_version", NULL},
1750 {
"SSL_get_current_cipher", NULL},
1751 {
"SSL_CIPHER_get_name", NULL},
1752 {
"SSL_CTX_check_private_key", NULL},
1753 {
"SSL_CTX_set_session_id_context", NULL},
1754 {
"SSL_CTX_ctrl", NULL},
1755 {
"SSL_CTX_set_cipher_list", NULL},
1756 {
"SSL_CTX_set_options", NULL},
1757 {
"SSL_CTX_set_info_callback", NULL},
1758 {
"SSL_get_ex_data", NULL},
1759 {
"SSL_set_ex_data", NULL},
1765 static struct ssl_func crypto_sw[] = {{
"ERR_get_error", NULL},
1766 {
"ERR_error_string", NULL},
1767 {
"ERR_remove_state", NULL},
1768 {
"CONF_modules_unload", NULL},
1769 {
"X509_free", NULL},
1770 {
"X509_get_subject_name", NULL},
1771 {
"X509_get_issuer_name", NULL},
1772 {
"X509_NAME_oneline", NULL},
1773 {
"X509_get_serialNumber", NULL},
1774 {
"EVP_get_digestbyname", NULL},
1775 {
"EVP_Digest", NULL},
1777 {
"BN_bn2hex", NULL},
1778 {
"ASN1_INTEGER_to_BN", NULL},
1780 {
"CRYPTO_free", NULL},
1784 #define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) 1785 #define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) 1786 #define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) 1787 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) 1788 #define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) 1789 #define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) 1790 #define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) 1791 #define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) 1792 #define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) 1793 #define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) 1794 #define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr) 1795 #define SSL_CTX_use_PrivateKey_file \ 1796 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) 1797 #define SSL_CTX_use_certificate_file \ 1798 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) 1799 #define SSL_CTX_set_default_passwd_cb \ 1800 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) 1801 #define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) 1802 #define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr) 1803 #define SSL_CTX_use_certificate_chain_file \ 1804 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr) 1805 #define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr) 1806 #define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr) 1807 #define SSL_CTX_set_verify \ 1808 (*(void (*)(SSL_CTX *, \ 1810 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr) 1811 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr) 1812 #define SSL_CTX_load_verify_locations \ 1813 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr) 1814 #define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr) 1815 #define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr) 1816 #define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr) 1817 #define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr) 1818 #define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr) 1819 #define SSL_CIPHER_get_name \ 1820 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr) 1821 #define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr) 1822 #define SSL_CTX_set_session_id_context \ 1823 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr) 1824 #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr) 1825 #define SSL_CTX_set_cipher_list \ 1826 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr) 1827 #define SSL_CTX_set_info_callback \ 1828 (*(void (*)(SSL_CTX * ctx, \ 1829 void (*callback)(const SSL * s, int, int)))ssl_sw[32].ptr) 1830 #define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr) 1831 #define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr) 1833 #define SSL_CTX_set_options(ctx, op) \ 1834 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL) 1835 #define SSL_CTX_clear_options(ctx, op) \ 1836 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL) 1837 #define SSL_CTX_set_ecdh_auto(ctx, onoff) \ 1838 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) 1841 #define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) 1842 #define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) 1844 #define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) 1845 #define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) 1847 #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) 1848 #define CRYPTO_set_locking_callback \ 1849 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr) 1850 #define CRYPTO_set_id_callback \ 1851 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr) 1852 #define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr) 1853 #define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr) 1854 #define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr) 1855 #define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr) 1856 #define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr) 1857 #define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr) 1858 #define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr) 1859 #define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr) 1860 #define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr) 1861 #define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[12].ptr) 1862 #define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[13].ptr) 1863 #define X509_NAME_oneline \ 1864 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr) 1865 #define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr) 1866 #define i2c_ASN1_INTEGER \ 1867 (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr) 1868 #define EVP_get_digestbyname \ 1869 (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr) 1870 #define EVP_Digest \ 1872 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \ 1874 #define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr) 1875 #define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr) 1876 #define ASN1_INTEGER_to_BN \ 1877 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[21].ptr) 1878 #define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr) 1879 #define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr) 1881 #define OPENSSL_free(a) CRYPTO_free(a) 1887 static struct ssl_func ssl_sw[] = {{
"SSL_free", NULL},
1888 {
"SSL_accept", NULL},
1889 {
"SSL_connect", NULL},
1891 {
"SSL_write", NULL},
1892 {
"SSL_get_error", NULL},
1893 {
"SSL_set_fd", NULL},
1895 {
"SSL_CTX_new", NULL},
1896 {
"SSLv23_server_method", NULL},
1897 {
"SSL_library_init", NULL},
1898 {
"SSL_CTX_use_PrivateKey_file", NULL},
1899 {
"SSL_CTX_use_certificate_file", NULL},
1900 {
"SSL_CTX_set_default_passwd_cb", NULL},
1901 {
"SSL_CTX_free", NULL},
1902 {
"SSL_load_error_strings", NULL},
1903 {
"SSL_CTX_use_certificate_chain_file", NULL},
1904 {
"SSLv23_client_method", NULL},
1905 {
"SSL_pending", NULL},
1906 {
"SSL_CTX_set_verify", NULL},
1907 {
"SSL_shutdown", NULL},
1908 {
"SSL_CTX_load_verify_locations", NULL},
1909 {
"SSL_CTX_set_default_verify_paths", NULL},
1910 {
"SSL_CTX_set_verify_depth", NULL},
1911 {
"SSL_get_peer_certificate", NULL},
1912 {
"SSL_get_version", NULL},
1913 {
"SSL_get_current_cipher", NULL},
1914 {
"SSL_CIPHER_get_name", NULL},
1915 {
"SSL_CTX_check_private_key", NULL},
1916 {
"SSL_CTX_set_session_id_context", NULL},
1917 {
"SSL_CTX_ctrl", NULL},
1918 {
"SSL_CTX_set_cipher_list", NULL},
1919 {
"SSL_CTX_set_info_callback", NULL},
1920 {
"SSL_get_ex_data", NULL},
1921 {
"SSL_set_ex_data", NULL},
1927 static struct ssl_func crypto_sw[] = {{
"CRYPTO_num_locks", NULL},
1928 {
"CRYPTO_set_locking_callback", NULL},
1929 {
"CRYPTO_set_id_callback", NULL},
1930 {
"ERR_get_error", NULL},
1931 {
"ERR_error_string", NULL},
1932 {
"ERR_remove_state", NULL},
1933 {
"ERR_free_strings", NULL},
1934 {
"ENGINE_cleanup", NULL},
1935 {
"CONF_modules_unload", NULL},
1936 {
"CRYPTO_cleanup_all_ex_data", NULL},
1937 {
"EVP_cleanup", NULL},
1938 {
"X509_free", NULL},
1939 {
"X509_get_subject_name", NULL},
1940 {
"X509_get_issuer_name", NULL},
1941 {
"X509_NAME_oneline", NULL},
1942 {
"X509_get_serialNumber", NULL},
1943 {
"i2c_ASN1_INTEGER", NULL},
1944 {
"EVP_get_digestbyname", NULL},
1945 {
"EVP_Digest", NULL},
1947 {
"BN_bn2hex", NULL},
1948 {
"ASN1_INTEGER_to_BN", NULL},
1950 {
"CRYPTO_free", NULL},
1957 #if !defined(NO_CACHING) 1977 struct sockaddr_in sin;
1978 #if defined(USE_IPV6) 1979 struct sockaddr_in6 sin6;
1989 struct mg_file_stat {
1992 time_t last_modified;
1999 struct mg_file_in_memory {
2005 struct mg_file_access {
2015 struct mg_file_stat stat;
2016 struct mg_file_access access;
2019 #define STRUCT_FILE_INITIALIZER \ 2022 (uint64_t)0, (time_t)0, 0, 0, 0 \ 2026 (FILE *) NULL, (const char *)NULL \ 2036 unsigned char is_ssl;
2037 unsigned char ssl_redir;
2039 unsigned char in_use;
2081 #if defined(USE_WEBSOCKET) 2087 #if defined(USE_LUA) 2089 LUA_SCRIPT_EXTENSIONS,
2090 LUA_SERVER_PAGE_EXTENSIONS,
2092 #if defined(USE_DUKTAPE) 2093 DUKTAPE_SCRIPT_EXTENSIONS,
2096 #if defined(USE_WEBSOCKET) 2099 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 2100 LUA_WEBSOCKET_EXTENSIONS,
2109 #if !defined(NO_CACHING) 2112 #if !defined(NO_SSL) 2115 #if defined(__linux__) 2116 ALLOW_SENDFILE_CALL,
2119 CASE_SENSITIVE_FILES,
2121 #if defined(USE_LUA) 2122 LUA_BACKGROUND_SCRIPT,
2123 LUA_BACKGROUND_SCRIPT_PARAMS,
2151 "index.xhtml,index.html,index.htm," 2152 "index.lp,index.lsp,index.lua,index.cgi," 2153 "index.shtml,index.php"},
2155 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2182 #if defined(USE_WEBSOCKET) 2187 #if defined(USE_LUA) 2192 #if defined(USE_DUKTAPE) 2198 #if defined(USE_WEBSOCKET) 2201 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 2209 #if !defined(NO_CACHING) 2212 #if !defined(NO_SSL) 2215 #if defined(__linux__) 2221 #if defined(USE_LUA) 2236 "config_options and enum not sync");
2242 struct mg_handler_info {
2269 struct mg_handler_info *next;
2282 volatile int stop_flag;
2289 struct socket *listening_sockets;
2290 struct pollfd *listening_socket_fds;
2291 unsigned int num_listening_sockets;
2293 pthread_mutex_t thread_mutex;
2295 #ifdef ALTERNATIVE_QUEUE 2296 struct socket *client_socks;
2297 void **client_wait_events;
2299 struct socket queue[MGSQLEN];
2300 volatile int sq_head;
2301 volatile int sq_tail;
2306 unsigned int max_request_size;
2308 pthread_t masterthreadid;
2311 pthread_t *worker_threadids;
2312 struct mg_connection *worker_connections;
2318 uint64_t auth_nonce_mask;
2319 pthread_mutex_t nonce_mutex;
2320 unsigned long nonce_count;
2325 struct mg_handler_info *handlers;
2327 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 2329 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2332 #if defined(USE_TIMERS) 2333 struct ttimers *timers;
2336 #if defined(USE_LUA) 2337 void *lua_background_state;
2340 #if defined(USE_SERVER_STATS) 2341 int active_connections;
2342 int max_connections;
2343 int64_t total_connections;
2344 int64_t total_requests;
2345 struct mg_memory_stat ctx_memory;
2346 int64_t total_data_read;
2347 int64_t total_data_written;
2352 #if defined(USE_SERVER_STATS) 2353 static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2355 static struct mg_memory_stat *
2356 get_memory_stat(
struct mg_context *ctx)
2359 return &(ctx->ctx_memory);
2361 return &mg_common_memory;
2371 struct mg_connection {
2372 int connection_type;
2377 struct mg_context *ctx;
2379 #if defined(USE_SERVER_STATS) 2387 struct socket client;
2388 time_t conn_birth_time;
2390 struct timespec req_time;
2392 int64_t num_bytes_sent;
2393 int64_t content_len;
2394 int64_t consumed_content;
2401 size_t chunk_remainder;
2407 int in_error_handler;
2409 #if defined(USE_WEBSOCKET) 2410 int in_websocket_handling;
2412 int handled_requests;
2421 time_t last_throttle_time;
2422 int64_t last_throttle_bytes;
2423 pthread_mutex_t mutex;
2425 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 2426 void *lua_websocket_state;
2435 struct mg_connection *conn;
2437 struct mg_file_stat file;
2441 #if defined(USE_WEBSOCKET) 2444 #define is_websocket_protocol(conn) (0) 2448 #if !defined(NO_THREAD_NAME) 2449 #if defined(_WIN32) && defined(_MSC_VER) 2453 #pragma pack(push, 8) 2454 typedef struct tagTHREADNAME_INFO {
2462 #elif defined(__linux__) 2464 #include <sys/prctl.h> 2465 #include <sys/sendfile.h> 2466 #ifdef ALTERNATIVE_QUEUE 2467 #include <sys/eventfd.h> 2471 #if defined(ALTERNATIVE_QUEUE) 2475 #pragma clang diagnostic push 2476 #pragma clang diagnostic ignored "-Wunreachable-code" 2484 #if defined(__GNUC__) || defined(__MINGW32__) 2488 #pragma GCC diagnostic push 2489 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" 2490 #pragma GCC diagnostic ignored "-Wpointer-to-int-cast" 2497 int evhdl = eventfd(0, EFD_CLOEXEC);
2505 if (
sizeof(
int) ==
sizeof(
void *)) {
2506 ret = (
void *)evhdl;
2526 if (
sizeof(
int) ==
sizeof(
void *)) {
2527 evhdl = (int)eventhdl;
2533 evhdl = *(
int *)eventhdl;
2536 s = (int)read(evhdl, &u,
sizeof(u));
2537 if (s !=
sizeof(uint64_t)) {
2552 if (
sizeof(
int) ==
sizeof(
void *)) {
2553 evhdl = (int)eventhdl;
2559 evhdl = *(
int *)eventhdl;
2562 s = (int)write(evhdl, &u,
sizeof(u));
2563 if (s !=
sizeof(uint64_t)) {
2576 if (
sizeof(
int) ==
sizeof(
void *)) {
2577 evhdl = (int)eventhdl;
2584 evhdl = *(
int *)eventhdl;
2591 #if defined(__GNUC__) || defined(__MINGW32__) 2592 #pragma GCC diagnostic pop 2596 #pragma clang diagnostic pop 2604 #if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE) 2606 struct posix_event {
2607 pthread_mutex_t mutex;
2615 struct posix_event *ret =
mg_malloc(
sizeof(
struct posix_event));
2620 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
2625 if (0 != pthread_cond_init(&(ret->cond), NULL)) {
2627 pthread_mutex_destroy(&(ret->mutex));
2638 struct posix_event *ev = (
struct posix_event *)eventhdl;
2639 pthread_mutex_lock(&(ev->mutex));
2640 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2641 pthread_mutex_unlock(&(ev->mutex));
2649 struct posix_event *ev = (
struct posix_event *)eventhdl;
2650 pthread_mutex_lock(&(ev->mutex));
2651 pthread_cond_signal(&(ev->cond));
2652 pthread_mutex_unlock(&(ev->mutex));
2660 struct posix_event *ev = (
struct posix_event *)eventhdl;
2661 pthread_cond_destroy(&(ev->cond));
2662 pthread_mutex_destroy(&(ev->mutex));
2671 char threadName[16 + 1];
2674 NULL, NULL, threadName,
sizeof(threadName),
"civetweb-%s", name);
2677 #if defined(_MSC_VER) 2681 THREADNAME_INFO info;
2682 info.dwType = 0x1000;
2683 info.szName = threadName;
2684 info.dwThreadID = ~0U;
2687 RaiseException(0x406D1388,
2689 sizeof(info) /
sizeof(ULONG_PTR),
2690 (ULONG_PTR *)&info);
2692 __except(EXCEPTION_EXECUTE_HANDLER)
2695 #elif defined(__MINGW32__) 2698 #elif defined(_GNU_SOURCE) && defined(__GLIBC__) \ 2699 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12))) 2701 (
void)pthread_setname_np(pthread_self(), threadName);
2702 #elif defined(__linux__) 2704 (
void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
2715 #if defined(MG_LEGACY_INTERFACE) 2717 mg_get_valid_option_names(
void)
2742 #define MG_FOPEN_MODE_NONE (0) 2745 #define MG_FOPEN_MODE_READ (1) 2748 #define MG_FOPEN_MODE_WRITE (2) 2751 #define MG_FOPEN_MODE_APPEND (4) 2760 struct mg_file *filep,
2763 #if defined(MG_USE_OPEN_FILE) 2766 const char *buf = NULL;
2775 if (conn->ctx->callbacks.open_file) {
2776 buf = conn->ctx->callbacks.open_file(conn, path, &size);
2778 if (filep == NULL) {
2789 filep->access.membuf = buf;
2790 filep->access.fp = NULL;
2793 filep->stat.size = size;
2797 filep->stat.last_modified = time(NULL);
2799 filep->stat.is_directory = 0;
2800 filep->stat.is_gzipped = 0;
2804 return (buf != NULL);
2831 return (fileacc->membuf != NULL) || (fileacc->fp != NULL);
2835 static int mg_stat(
const struct mg_connection *conn,
2837 struct mg_file_stat *filep);
2850 struct mg_file *filep)
2857 filep->access.fp = NULL;
2858 filep->access.membuf = NULL;
2864 found =
mg_stat(conn, path, &(filep->stat));
2873 wchar_t wbuf[PATH_MAX];
2874 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
2877 filep->access.fp = _wfopen(wbuf,
L"rb");
2880 filep->access.fp = _wfopen(wbuf,
L"wb");
2883 filep->access.fp = _wfopen(wbuf,
L"ab");
2891 filep->access.fp = fopen(path,
"r");
2894 filep->access.fp = fopen(path,
"w");
2897 filep->access.fp = fopen(path,
"a");
2906 found =
mg_stat(conn, path, &(filep->stat));
2911 return (filep->access.fp != NULL);
2917 return (filep->access.membuf != NULL);
2931 if (fileacc != NULL) {
2932 if (fileacc->fp != NULL) {
2933 ret = fclose(fileacc->fp);
2934 }
else if (fileacc->membuf != NULL) {
2938 memset(fileacc, 0,
sizeof(*fileacc));
2947 for (; *src !=
'\0' && n > 1; n--) {
2957 return tolower(*(
const unsigned char *)s);
2969 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
2983 }
while (diff == 0 && s1[-1] !=
'\0');
2994 if ((p = (
char *)
mg_malloc(len + 1)) != NULL) {
3012 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3014 if (big_len >= small_len) {
3015 for (i = 0; i <= (big_len - small_len); i++) {
3046 #pragma clang diagnostic push 3047 #pragma clang diagnostic ignored "-Wformat-nonliteral" 3053 ok = (n >= 0) && ((
size_t)n < buflen);
3056 #pragma clang diagnostic pop 3068 "truncating vsnprintf buffer: [%.*s]",
3069 (
int)((buflen > 200) ? 200 : (buflen - 1)),
3071 n = (int)buflen - 1;
3113 }
else if (!ctx || ctx->config[i] == NULL) {
3116 return ctx->config[i];
3124 return (conn == NULL) ? (
struct mg_context *)NULL : (conn->ctx);
3131 return (ctx == NULL) ? NULL : ctx->user_data;
3139 conn->request_info.conn_data =
data;
3148 return conn->request_info.conn_data;
3154 #if defined(MG_LEGACY_INTERFACE) 3157 mg_get_ports(
const struct mg_context *ctx,
size_t size,
int *ports,
int *ssl)
3163 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
3164 ssl[i] = ctx->listening_sockets[i].is_ssl;
3166 #if defined(USE_IPV6) 3167 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3168 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3171 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
3188 memset(ports, 0,
sizeof(*ports) * (
size_t)size);
3192 if (!ctx->listening_sockets) {
3196 for (i = 0; (i < size) && (i < (
int)ctx->num_listening_sockets); i++) {
3199 #if defined(USE_IPV6) 3200 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3201 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3204 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
3205 ports[
cnt].
is_ssl = ctx->listening_sockets[i].is_ssl;
3208 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
3212 }
else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
3232 if (usa->sa.sa_family == AF_INET) {
3233 getnameinfo(&usa->sa,
3241 #if defined(USE_IPV6) 3242 else if (usa->sa.sa_family == AF_INET6) {
3243 getnameinfo(&usa->sa,
3262 tm = ((t != NULL) ? gmtime(t) : NULL);
3264 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", tm);
3266 mg_strlcpy(buf,
"Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3267 buf[buf_len - 1] =
'\0';
3276 return (
double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0
E-9
3277 + (
double)(ts_now->tv_sec - ts_before->tv_sec);
3283 mg_cry(
const struct mg_connection *conn,
const char *fmt, ...)
3293 buf[
sizeof(buf) - 1] = 0;
3305 if ((conn->ctx->callbacks.log_message == NULL)
3306 || (conn->ctx->callbacks.log_message(conn, buf) == 0)) {
3313 fi.access.fp = NULL;
3316 fi.access.fp = NULL;
3319 if (fi.access.fp != NULL) {
3320 flockfile(fi.access.fp);
3321 timestamp = time(NULL);
3324 fprintf(fi.access.fp,
3325 "[%010lu] [error] [client %s] ",
3326 (
unsigned long)timestamp,
3329 if (conn->request_info.request_method != NULL) {
3330 fprintf(fi.access.fp,
3332 conn->request_info.request_method,
3333 conn->request_info.request_uri
3334 ? conn->request_info.request_uri
3338 fprintf(fi.access.fp,
"%s", buf);
3339 fputc(
'\n', fi.access.fp);
3340 fflush(fi.access.fp);
3341 funlockfile(fi.access.fp);
3351 static struct mg_connection *
3352 fc(
struct mg_context *ctx)
3354 static struct mg_connection fake_connection;
3355 fake_connection.ctx = ctx;
3356 return &fake_connection;
3375 static char txt[16];
3376 sprintf(txt,
"%03i", conn->response_info.status_code);
3378 ((
struct mg_connection *)conn)->request_info.local_uri =
3379 ((
struct mg_connection *)conn)->request_info.request_uri =
3382 ((
struct mg_connection *)conn)->request_info.num_headers =
3383 conn->response_info.num_headers;
3384 memcpy(((
struct mg_connection *)conn)->request_info.http_headers,
3385 conn->response_info.http_headers,
3386 sizeof(conn->response_info.http_headers));
3392 return &conn->request_info;
3405 return &conn->response_info;
3413 #pragma clang diagnostic push 3414 #pragma clang diagnostic ignored "-Wunreachable-code" 3426 : (ri->
is_ssl ?
"https" :
"http"));
3431 #pragma clang diagnostic pop 3439 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3467 #if defined(USE_IPV6) 3468 int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6);
3469 int port = is_ipv6 ? htons(conn->client.lsa.sin6.sin6_port)
3470 : htons(conn->client.lsa.sin.sin_port);
3472 int port = htons(conn->client.lsa.sin.sin_port);
3474 int def_port = ri->
is_ssl ? 443 : 80;
3475 int auth_domain_check_enabled =
3479 const char *server_domain =
3485 if (port != def_port) {
3486 sprintf(portstr,
":%u", (
unsigned)port);
3491 if (!auth_domain_check_enabled || !server_domain) {
3497 server_domain = server_ip;
3524 const char *delimiters,
3525 const char *whitespace,
3528 char *p, *begin_word, *end_word, *end_whitespace;
3531 end_word = begin_word + strcspn(begin_word, delimiters);
3534 if (end_word > begin_word) {
3536 while (*p == quotechar) {
3543 if (*end_word !=
'\0') {
3544 size_t end_off = strcspn(end_word + 1, delimiters);
3545 memmove(p, end_word, end_off + 1);
3547 end_word += end_off + 1;
3553 for (p++; p < end_word; p++) {
3558 if (*end_word ==
'\0') {
3562 #if defined(__GNUC__) || defined(__MINGW32__) 3564 #if GCC_VERSION >= 40500 3565 #pragma GCC diagnostic push 3566 #pragma GCC diagnostic ignored "-Wsign-conversion" 3570 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3572 #if defined(__GNUC__) || defined(__MINGW32__) 3573 #if GCC_VERSION >= 40500 3574 #pragma GCC diagnostic pop 3578 for (p = end_word; p < end_whitespace; p++) {
3582 *buf = end_whitespace;
3594 for (i = 0; i < num_hdr; i++) {
3596 return hdr[i].
value;
3604 #if defined(USE_WEBSOCKET) 3611 int output_max_size)
3616 for (i = 0; i < ri->
num_headers && cnt < output_max_size; i++) {
3635 return get_header(conn->request_info.http_headers,
3636 conn->request_info.num_headers,
3640 return get_header(conn->response_info.http_headers,
3641 conn->request_info.num_headers,
3656 return conn->request_info.http_version;
3659 return conn->response_info.http_version;
3677 if (val == NULL || list == NULL || *list ==
'\0') {
3683 while (*list ==
' ' || *list ==
'\t')
3687 if ((list = strchr(val->ptr,
',')) != NULL) {
3689 val->len = ((size_t)(list - val->ptr));
3693 list = val->ptr + strlen(val->ptr);
3694 val->len = ((size_t)(list - val->ptr));
3698 end = (int)val->len - 1;
3699 while (end >= 0 && ((val->ptr[end] ==
' ') || (val->ptr[end] ==
'\t')))
3701 val->len = (size_t)(end + 1);
3703 if (val->len == 0) {
3708 if (eq_val != NULL) {
3712 eq_val->ptr = (
const char *)memchr(val->ptr,
'=', val->len);
3713 if (eq_val->ptr != NULL) {
3715 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
3716 val->len = ((
size_t)(eq_val->ptr - val->ptr)) - 1;
3739 while ((header =
next_option(header, &opt_vec, &eq_vec)) != NULL) {
3756 if ((or_str = (
const char *)memchr(pattern,
'|', pattern_len)) != NULL) {
3757 res =
match_prefix(pattern, (
size_t)(or_str - pattern), str);
3759 (
size_t)((pattern + pattern_len)
3764 for (i = 0, j = 0; (i < pattern_len); i++, j++) {
3765 if ((pattern[i] ==
'?') && (str[j] !=
'\0')) {
3767 }
else if (pattern[i] ==
'$') {
3768 return (str[j] ==
'\0') ? j : -1;
3769 }
else if (pattern[i] ==
'*') {
3771 if (pattern[i] ==
'*') {
3773 len = (int)strlen(str + j);
3775 len = (int)strcspn(str + j,
"/");
3777 if (i == pattern_len) {
3781 res =
match_prefix(pattern + i, pattern_len - i, str + j + len);
3782 }
while (res == -1 && len-- > 0);
3783 return (res == -1) ? -1 : j + res + len;
3798 const char *http_version;
3802 if ((conn == NULL) || conn->must_close) {
3824 if (http_version && (0 == strcmp(http_version,
"1.1"))) {
3837 if (!conn || !conn->ctx) {
3857 "Cache-Control: no-cache, no-store, " 3858 "must-revalidate, private, max-age=0\r\n" 3859 "Pragma: no-cache\r\n" 3867 #if !defined(NO_CACHING) 3888 return mg_printf(conn,
"Cache-Control: max-age=%u\r\n", (
unsigned)max_age);
3901 #if !defined(NO_SSL) 3906 "Strict-Transport-Security: max-age=%u\r\n",
3912 if (header && header[0]) {
3922 struct mg_file *filep);
3932 switch (response_code) {
3937 return "Switching Protocols";
3939 return "Processing";
3949 return "Non-Authoritative Information";
3951 return "No Content";
3953 return "Reset Content";
3955 return "Partial Content";
3957 return "Multi-Status";
3960 return "Already Reported";
3967 return "Multiple Choices";
3969 return "Moved Permanently";
3975 return "Not Modified";
3979 return "Temporary Redirect";
3981 return "Permanent Redirect";
3985 return "Bad Request";
3987 return "Unauthorized";
3989 return "Payment Required";
3995 return "Method Not Allowed";
3997 return "Not Acceptable";
3999 return "Proxy Authentication Required";
4001 return "Request Time-out";
4007 return "Length Required";
4009 return "Precondition Failed";
4011 return "Request Entity Too Large";
4013 return "Request-URI Too Large";
4015 return "Unsupported Media Type";
4017 return "Requested range not satisfiable";
4020 return "Expectation Failed";
4023 return "Misdirected Request";
4025 return "Unproccessable entity";
4030 return "Failed Dependency";
4034 return "Upgrade Required";
4037 return "Precondition Required";
4039 return "Too Many Requests";
4042 return "Request Header Fields Too Large";
4045 return "Unavailable For Legal Reasons";
4050 return "Internal Server Error";
4052 return "Not Implemented";
4054 return "Bad Gateway";
4056 return "Service Unavailable";
4058 return "Gateway Time-out";
4060 return "HTTP Version not supported";
4062 return "Variant Also Negotiates";
4064 return "Insufficient Storage";
4067 return "Loop Detected";
4070 return "Not Extended";
4072 return "Network Authentication Required";
4078 return "I am a teapot";
4080 return "Authentication Timeout";
4082 return "Enhance Your Calm";
4084 return "Login Timeout";
4086 return "Bandwidth Limit Exceeded";
4091 mg_cry(conn,
"Unknown HTTP response code: %u", response_code);
4095 if (response_code >= 100 && response_code < 200) {
4097 return "Information";
4099 if (response_code >= 200 && response_code < 300) {
4103 if (response_code >= 300 && response_code < 400) {
4105 return "Redirection";
4107 if (response_code >= 400 && response_code < 500) {
4109 return "Client Error";
4111 if (response_code >= 500 && response_code < 600) {
4113 return "Server Error";
4127 int len, i, page_handler_found, scope, truncated, has_body;
4129 time_t curtime = time(NULL);
4130 const char *error_handler = NULL;
4132 const char *error_page_file_ext, *tstr;
4140 conn->status_code = status;
4141 if (conn->in_error_handler || (conn->ctx->callbacks.http_error == NULL)
4142 || conn->ctx->callbacks.http_error(conn, status)) {
4145 if (conn->in_error_handler) {
4147 "Recursion when handling error %u - fall back to default",
4152 error_page_file_ext = conn->ctx->config[
INDEX_FILES];
4153 page_handler_found = 0;
4155 if (error_handler != NULL) {
4156 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4193 len = (int)strlen(buf);
4195 tstr = strchr(error_page_file_ext,
'.');
4199 (i < 32) && (tstr[i] != 0) && (tstr[i] !=
',');
4201 buf[len + i - 1] = tstr[i];
4202 buf[len + i - 1] = 0;
4204 if (
mg_stat(conn, buf, &error_page_file.stat)) {
4206 page_handler_found = 1;
4209 DEBUG_TRACE(
"Check error page %s - not found", buf);
4211 tstr = strchr(tstr + i,
'.');
4216 if (page_handler_found) {
4217 conn->in_error_handler = 1;
4219 conn->in_error_handler = 0;
4228 has_body = ((status > 199) && (status != 204) && (status != 304));
4230 conn->must_close = 1;
4231 mg_printf(conn,
"HTTP/1.1 %d %s\r\n", status, status_text);
4237 "Content-Type: text/plain; charset=utf-8\r\n");
4241 "Connection: close\r\n\r\n",
4246 mg_printf(conn,
"Error %d: %s\n", status, status_text);
4263 #if defined(_WIN32) && !defined(__SYMBIAN32__) 4266 #if defined(__MINGW32__) 4268 #pragma GCC diagnostic push 4269 #pragma GCC diagnostic ignored "-Wunused-function" 4275 pthread_mutex_init(pthread_mutex_t *mutex,
void *unused)
4278 *mutex = CreateMutex(NULL,
FALSE, NULL);
4279 return (*mutex == NULL) ? -1 : 0;
4284 pthread_mutex_destroy(pthread_mutex_t *mutex)
4286 return (CloseHandle(*mutex) == 0) ? -1 : 0;
4292 pthread_mutex_lock(pthread_mutex_t *mutex)
4294 return (WaitForSingleObject(*mutex, (DWORD)INFINITE) == WAIT_OBJECT_0) ? 0
4299 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS 4302 pthread_mutex_trylock(pthread_mutex_t *mutex)
4304 switch (WaitForSingleObject(*mutex, 0)) {
4317 pthread_mutex_unlock(pthread_mutex_t *mutex)
4319 return (ReleaseMutex(*mutex) == 0) ? -1 : 0;
4328 InitializeCriticalSection(&cv->threadIdSec);
4329 cv->waiting_thread = NULL;
4337 pthread_mutex_t *mutex,
4338 const struct timespec *abstime)
4340 struct mg_workerTLS **ptls,
4341 *tls = (
struct mg_workerTLS *)pthread_getspecific(sTlsKey);
4343 int64_t nsnow, nswaitabs, nswaitrel;
4346 EnterCriticalSection(&cv->threadIdSec);
4348 ptls = &cv->waiting_thread;
4349 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
4351 tls->next_waiting_thread = NULL;
4353 LeaveCriticalSection(&cv->threadIdSec);
4358 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4359 nswaitrel = nswaitabs - nsnow;
4360 if (nswaitrel < 0) {
4363 mswaitrel = (DWORD)(nswaitrel / 1000000);
4365 mswaitrel = (DWORD)INFINITE;
4368 pthread_mutex_unlock(mutex);
4370 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
4373 EnterCriticalSection(&cv->threadIdSec);
4374 ptls = &cv->waiting_thread;
4375 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
4377 *ptls = tls->next_waiting_thread;
4382 LeaveCriticalSection(&cv->threadIdSec);
4384 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4389 pthread_mutex_lock(mutex);
4399 return pthread_cond_timedwait(cv, mutex, NULL);
4410 EnterCriticalSection(&cv->threadIdSec);
4411 if (cv->waiting_thread) {
4412 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4413 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
4415 ok = SetEvent(wkup);
4418 LeaveCriticalSection(&cv->threadIdSec);
4428 EnterCriticalSection(&cv->threadIdSec);
4429 while (cv->waiting_thread) {
4430 pthread_cond_signal(cv);
4432 LeaveCriticalSection(&cv->threadIdSec);
4442 EnterCriticalSection(&cv->threadIdSec);
4443 assert(cv->waiting_thread == NULL);
4444 LeaveCriticalSection(&cv->threadIdSec);
4445 DeleteCriticalSection(&cv->threadIdSec);
4451 #ifdef ALTERNATIVE_QUEUE 4456 return (
void *)CreateEvent(NULL,
FALSE,
FALSE, NULL);
4464 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
4465 return (res == WAIT_OBJECT_0);
4473 return (
int)SetEvent((HANDLE)eventhdl);
4481 CloseHandle((HANDLE)eventhdl);
4486 #if defined(__MINGW32__) 4488 #pragma GCC diagnostic pop 4494 change_slashes_to_backslashes(
char *path)
4498 for (i = 0; path[i] !=
'\0'; i++) {
4499 if (path[i] ==
'/') {
4505 if ((path[i] ==
'\\') && (i > 0)) {
4506 while ((path[i + 1] ==
'\\') || (path[i + 1] ==
'/')) {
4507 (
void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
4515 mg_wcscasecmp(
const wchar_t *
s1,
const wchar_t *s2)
4520 diff = tolower(*s1) - tolower(*s2);
4523 }
while ((diff == 0) && (s1[-1] !=
'\0'));
4532 path_to_unicode(
const struct mg_connection *conn,
4537 char buf[PATH_MAX], buf2[PATH_MAX];
4538 wchar_t wbuf2[MAX_PATH + 1];
4539 DWORD long_len, err;
4540 int (*fcompare)(
const wchar_t *,
const wchar_t *) = mg_wcscasecmp;
4543 change_slashes_to_backslashes(buf);
4547 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
4548 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int)wbuf_len);
4549 WideCharToMultiByte(
4550 CP_UTF8, 0, wbuf, (
int)wbuf_len, buf2,
sizeof(buf2), NULL, NULL);
4551 if (strcmp(buf, buf2) != 0) {
4565 if (conn->ctx->config[CASE_SENSITIVE_FILES]
4566 && !
mg_strcasecmp(conn->ctx->config[CASE_SENSITIVE_FILES],
"yes")) {
4573 #if !defined(_WIN32_WCE) 4575 memset(wbuf2, 0,
ARRAY_SIZE(wbuf2) *
sizeof(
wchar_t));
4576 long_len = GetLongPathNameW(wbuf, wbuf2,
ARRAY_SIZE(wbuf2) - 1);
4577 if (long_len == 0) {
4578 err = GetLastError();
4579 if (err == ERROR_FILE_NOT_FOUND) {
4584 if ((long_len >=
ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
4593 if (strchr(path,
'~')) {
4605 path_cannot_disclose_cgi(
const char *path)
4607 static const char *allowed_last_characters =
"_-";
4608 int last = path[strlen(path) - 1];
4609 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
4614 mg_stat(
const struct mg_connection *conn,
4616 struct mg_file_stat *filep)
4618 wchar_t wbuf[PATH_MAX];
4619 WIN32_FILE_ATTRIBUTE_DATA info;
4620 time_t creation_time;
4625 memset(filep, 0,
sizeof(*filep));
4635 filep->size = tmp_file.stat.size;
4636 filep->location = 2;
4644 filep->last_modified = time(NULL);
4656 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
4657 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
4658 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
4659 filep->last_modified =
4660 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
4661 info.ftLastWriteTime.dwHighDateTime);
4667 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
4668 info.ftCreationTime.dwHighDateTime);
4669 if (creation_time > filep->last_modified) {
4670 filep->last_modified = creation_time;
4673 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
4678 if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
4679 memset(filep, 0,
sizeof(*filep));
4691 mg_remove(
const struct mg_connection *conn,
const char *path)
4693 wchar_t wbuf[PATH_MAX];
4694 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
4695 return DeleteFileW(wbuf) ? 0 : -1;
4700 mg_mkdir(
const struct mg_connection *conn,
const char *path,
int mode)
4702 wchar_t wbuf[PATH_MAX];
4704 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
4705 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
4711 #if defined(__MINGW32__) 4713 #pragma GCC diagnostic push 4714 #pragma GCC diagnostic ignored "-Wunused-function" 4721 mg_opendir(
const struct mg_connection *conn,
const char *name)
4724 wchar_t wpath[PATH_MAX];
4728 SetLastError(ERROR_BAD_ARGUMENTS);
4729 }
else if ((dir = (DIR *)
mg_malloc(
sizeof(*dir))) == NULL) {
4730 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4732 path_to_unicode(conn, name, wpath,
ARRAY_SIZE(wpath));
4733 attrs = GetFileAttributesW(wpath);
4734 if (attrs != 0xFFFFFFFF && ((attrs & FILE_ATTRIBUTE_DIRECTORY)
4735 == FILE_ATTRIBUTE_DIRECTORY)) {
4736 (
void)wcscat(wpath,
L"\\*");
4737 dir->handle = FindFirstFileW(wpath, &dir->info);
4738 dir->result.d_name[0] =
'\0';
4757 result = FindClose(dir->handle) ? 0 : -1;
4762 SetLastError(ERROR_BAD_ARGUMENTS);
4770 static struct dirent *
4773 struct dirent *result = 0;
4777 result = &dir->result;
4778 (
void)WideCharToMultiByte(CP_UTF8,
4780 dir->info.cFileName,
4783 sizeof(result->d_name),
4787 if (!FindNextFileW(dir->handle, &dir->info)) {
4788 (
void)FindClose(dir->handle);
4793 SetLastError(ERROR_FILE_NOT_FOUND);
4796 SetLastError(ERROR_BAD_ARGUMENTS);
4806 poll(
struct pollfd *pfd,
unsigned int n,
int milliseconds)
4814 memset(&tv, 0,
sizeof(tv));
4815 tv.tv_sec = milliseconds / 1000;
4816 tv.tv_usec = (milliseconds % 1000) * 1000;
4819 for (i = 0; i <
n; i++) {
4820 FD_SET((SOCKET)pfd[i].fd, &
set);
4823 if (pfd[i].fd > maxfd) {
4828 if ((result = select((
int)maxfd + 1, &
set, NULL, NULL, &tv)) > 0) {
4829 for (i = 0; i <
n; i++) {
4830 if (FD_ISSET(pfd[i].fd, &
set)) {
4831 pfd[i].revents = POLLIN;
4848 #if defined(__MINGW32__) 4850 #pragma GCC diagnostic pop 4858 #if defined(_WIN32_WCE) 4861 (
void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
4869 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) 4873 return ((_beginthread((
void(__cdecl *)(
void *))f, USE_STACK_SIZE, p)
4874 == ((uintptr_t)(-1
L)))
4879 (_beginthread((
void(__cdecl *)(
void *))f, 0, p) == ((uintptr_t)(-1
L)))
4890 pthread_t *threadidptr)
4893 HANDLE threadhandle;
4896 uip = _beginthreadex(NULL, 0, (
unsigned(__stdcall *)(
void *))f, p, 0, NULL);
4897 threadhandle = (HANDLE)uip;
4898 if ((uip != (uintptr_t)(-1
L)) && (threadidptr != NULL)) {
4899 *threadidptr = threadhandle;
4915 dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE);
4916 if (dwevent == WAIT_FAILED) {
4919 if (dwevent == WAIT_OBJECT_0) {
4920 CloseHandle(threadid);
4928 #if !defined(NO_SSL_DL) && !defined(NO_SSL) 4932 #if defined(__MINGW32__) 4934 #pragma GCC diagnostic push 4935 #pragma GCC diagnostic ignored "-Wunused-function" 4941 dlopen(
const char *dll_name,
int flags)
4943 wchar_t wbuf[PATH_MAX];
4945 path_to_unicode(NULL, dll_name, wbuf,
ARRAY_SIZE(wbuf));
4946 return LoadLibraryW(wbuf);
4952 dlclose(
void *handle)
4956 if (FreeLibrary((HMODULE)handle) != 0) {
4966 #if defined(__MINGW32__) 4968 #pragma GCC diagnostic pop 4974 #if !defined(NO_CGI) 4978 kill(pid_t pid,
int sig_num)
4980 (
void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
4981 (
void)CloseHandle((HANDLE)pid);
4987 trim_trailing_whitespaces(
char *
s)
4989 char *
e = s + strlen(s) - 1;
4990 while ((e > s) && isspace(*(
unsigned char *)e)) {
5007 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
5008 cmdline[PATH_MAX], buf[PATH_MAX];
5012 PROCESS_INFORMATION
pi = {0};
5016 memset(&si, 0,
sizeof(si));
5019 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5020 si.wShowWindow = SW_HIDE;
5022 me = GetCurrentProcess();
5024 (HANDLE)_get_osfhandle(fdin[0]),
5029 DUPLICATE_SAME_ACCESS);
5031 (HANDLE)_get_osfhandle(fdout[1]),
5036 DUPLICATE_SAME_ACCESS);
5038 (HANDLE)_get_osfhandle(fderr[1]),
5043 DUPLICATE_SAME_ACCESS);
5048 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5049 HANDLE_FLAG_INHERIT,
5051 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5052 HANDLE_FLAG_INHERIT,
5054 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5055 HANDLE_FLAG_INHERIT,
5060 if (interp == NULL) {
5061 buf[0] = buf[1] =
'\0';
5065 conn, &truncated, cmdline,
sizeof(cmdline),
"%s/%s", dir, prog);
5068 pi.hProcess = (pid_t)-1;
5073 p = (
char *)file.access.membuf;
5074 mg_fgets(buf,
sizeof(buf), &file, &p);
5076 buf[
sizeof(buf) - 1] =
'\0';
5079 if ((buf[0] ==
'#') && (buf[1] ==
'!')) {
5080 trim_trailing_whitespaces(buf + 2);
5087 if (interp[0] !=
'\0') {
5088 GetFullPathNameA(interp,
sizeof(full_interp), full_interp, NULL);
5089 interp = full_interp;
5091 GetFullPathNameA(dir,
sizeof(full_dir), full_dir, NULL);
5093 if (interp[0] !=
'\0') {
5098 "\"%s\" \"%s\\%s\"",
5113 pi.hProcess = (pid_t)-1;
5118 if (CreateProcessA(NULL,
5123 CREATE_NEW_PROCESS_GROUP,
5129 conn,
"%s: CreateProcess(%s): %ld", __func__, cmdline, (
long)
ERRNO);
5130 pi.hProcess = (pid_t)-1;
5135 (
void)CloseHandle(si.hStdOutput);
5136 (
void)CloseHandle(si.hStdError);
5137 (
void)CloseHandle(si.hStdInput);
5138 if (pi.hThread != NULL) {
5139 (
void)CloseHandle(pi.hThread);
5142 return (pid_t)pi.hProcess;
5150 unsigned long non_blocking = 0;
5151 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5157 unsigned long non_blocking = 1;
5158 return ioctlsocket(sock, (
long)FIONBIO, &non_blocking);
5165 struct mg_file_stat *filep)
5171 memset(filep, 0,
sizeof(*filep));
5179 filep->size = tmp_file.stat.size;
5180 filep->last_modified = time(NULL);
5181 filep->location = 2;
5187 if (0 == stat(path, &st)) {
5188 filep->size = (uint64_t)(st.st_size);
5189 filep->last_modified = st.st_mtime;
5190 filep->is_directory = S_ISDIR(st.st_mode);
5201 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5204 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5215 pthread_t thread_id;
5216 pthread_attr_t attr;
5219 (
void)pthread_attr_init(&attr);
5220 (
void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5222 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) 5225 (
void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5228 result = pthread_create(&thread_id, &attr, func, param);
5229 pthread_attr_destroy(&attr);
5239 pthread_t *threadidptr)
5241 pthread_t thread_id;
5242 pthread_attr_t attr;
5245 (
void)pthread_attr_init(&attr);
5247 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) 5250 (
void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5253 result = pthread_create(&thread_id, &attr, func, param);
5254 pthread_attr_destroy(&attr);
5255 if ((result == 0) && (threadidptr != NULL)) {
5256 *threadidptr = thread_id;
5268 result = pthread_join(threadid, NULL);
5293 if ((pid = fork()) == -1) {
5297 "Error: Creating CGI process\nfork(): %s",
5299 }
else if (pid == 0) {
5301 if (chdir(dir) != 0) {
5302 mg_cry(conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
5303 }
else if (dup2(fdin[0], 0) == -1) {
5305 "%s: dup2(%d, 0): %s",
5309 }
else if (dup2(fdout[1], 1) == -1) {
5311 "%s: dup2(%d, 1): %s",
5315 }
else if (dup2(fderr[1], 2) == -1) {
5317 "%s: dup2(%d, 2): %s",
5339 signal(SIGCHLD, SIG_DFL);
5342 if (interp == NULL) {
5343 (
void)execle(prog, prog, NULL, envp);
5345 "%s: execle(%s): %s",
5350 (
void)execle(interp, interp, prog, NULL, envp);
5352 "%s: execle(%s %s): %s",
5370 int flags = fcntl(sock, F_GETFL, 0);
5375 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
5384 int flags = fcntl(sock, F_GETFL, 0);
5389 if (fcntl(sock, F_SETFL, flags & (~(
int)(O_NONBLOCK))) < 0) {
5403 static uint64_t lfsr = 0;
5404 static uint64_t lcg = 0;
5415 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
5417 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
5425 return (lfsr ^ lcg ^ now);
5433 volatile int *stop_server)
5448 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
5449 ms_now = milliseconds;
5452 result = poll(pfd, n, ms_now);
5460 if (milliseconds > 0) {
5461 milliseconds -= ms_now;
5464 }
while (milliseconds != 0);
5487 uint64_t start = 0, now = 0, timeout_ns = 0;
5494 typedef size_t len_t;
5500 timeout_ns = (uint64_t)(timeout * 1.0E9);
5537 n = (int)fwrite(buf, 1, (
size_t)len, fp);
5546 err = (n < 0) ?
ERRNO : 0;
5548 if (err == WSAEWOULDBLOCK) {
5553 if (err == EWOULDBLOCK) {
5564 if (ctx->stop_flag) {
5568 if ((n > 0) || ((n == 0) && (len == 0))) {
5591 mg_sleep(ms_wait > 10 ? 10 : ms_wait);
5598 #if defined(__GNUC__) || defined(__MINGW32__) 5602 #pragma GCC diagnostic push 5603 #pragma GCC diagnostic ignored "-Wsign-conversion" 5607 FD_SET(sock, &wfds);
5608 tv.tv_sec = (time_t)(ms_wait / 1000);
5609 tv.tv_usec = (long)((ms_wait % 1000) * 1000);
5611 sret = select((
int)sock + 1, NULL, &wfds, NULL, &tv);
5613 #if defined(__GNUC__) || defined(__MINGW32__) 5614 #pragma GCC diagnostic pop 5626 if ((now - start) > timeout_ns) {
5648 double timeout = -1.0;
5649 int64_t
n, nwritten = 0;
5659 while ((len > 0) && (ctx->stop_flag == 0)) {
5660 n =
push_inner(ctx, fp, sock, ssl, buf + nwritten, (
int)len, timeout);
5662 if (nwritten == 0) {
5666 }
else if (n == 0) {
5686 struct mg_connection *conn,
5696 typedef size_t len_t;
5708 #if !defined(_WIN32_WCE) 5713 nread = (int)read(fileno(fp), buf, (size_t)len);
5716 nread = (int)fread(buf, 1, (
size_t)len, fp);
5718 err = (nread < 0) ?
ERRNO : 0;
5719 if ((nread == 0) && (len > 0)) {
5725 }
else if ((conn->ssl != NULL)
5726 && ((ssl_pending =
SSL_pending(conn->ssl)) > 0)) {
5730 if (ssl_pending > len) {
5733 nread =
SSL_read(conn->ssl, buf, ssl_pending);
5749 }
else if (conn->ssl != NULL) {
5751 struct pollfd pfd[1];
5754 pfd[0].fd = conn->client.sock;
5755 pfd[0].events = POLLIN;
5757 mg_poll(pfd, 1, (
int)(timeout * 1000.0), &(conn->ctx->stop_flag));
5758 if (conn->ctx->stop_flag) {
5762 nread =
SSL_read(conn->ssl, buf, len);
5778 }
else if (pollres < 0) {
5788 struct pollfd pfd[1];
5791 pfd[0].fd = conn->client.sock;
5792 pfd[0].events = POLLIN;
5794 mg_poll(pfd, 1, (
int)(timeout * 1000.0), &(conn->ctx->stop_flag));
5795 if (conn->ctx->stop_flag) {
5799 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
5800 err = (nread < 0) ?
ERRNO : 0;
5805 }
else if (pollres < 0) {
5814 if (conn->ctx->stop_flag) {
5818 if ((nread > 0) || ((nread == 0) && (len == 0))) {
5826 if (err == WSAEWOULDBLOCK) {
5830 }
else if (err == WSAETIMEDOUT) {
5834 }
else if (err == WSAECONNABORTED) {
5847 if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == EINTR)) {
5872 pull_all(FILE *fp,
struct mg_connection *conn,
char *buf,
int len)
5875 double timeout = -1.0;
5876 uint64_t start_time = 0, now = 0, timeout_ns = 0;
5881 if (timeout >= 0.0) {
5883 timeout_ns = (uint64_t)(timeout * 1.0E9);
5886 while ((len > 0) && (conn->ctx->stop_flag == 0)) {
5887 n =
pull_inner(fp, conn, buf + nread, len, timeout);
5893 }
else if (n == -1) {
5895 if (timeout >= 0.0) {
5897 if ((now - start_time) <= timeout_ns) {
5902 }
else if (n == 0) {
5905 conn->consumed_content +=
n;
5926 to_read =
sizeof(buf);
5928 if (conn->is_chunked) {
5931 while (conn->is_chunked != 3) {
5932 nread =
mg_read(conn, buf, to_read);
5940 while (conn->consumed_content < conn->content_len) {
5942 > (
size_t)(conn->content_len - conn->consumed_content)) {
5943 to_read = (size_t)(conn->content_len - conn->consumed_content);
5946 nread =
mg_read(conn, buf, to_read);
5958 int64_t
n, buffered_len, nread;
5960 (int64_t)((len > INT_MAX) ? INT_MAX : len);
5972 if (conn->consumed_content == 0) {
5973 if (conn->is_chunked == 1) {
5974 conn->content_len = len64;
5975 conn->is_chunked = 2;
5976 }
else if (conn->content_len == -1) {
5980 conn->must_close = 1;
5985 if (conn->consumed_content < conn->content_len) {
5987 int64_t left_to_read = conn->content_len - conn->consumed_content;
5988 if (left_to_read < len64) {
5992 len64 = left_to_read;
5996 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
5997 - conn->consumed_content;
5998 if (buffered_len > 0) {
5999 if (len64 < buffered_len) {
6000 buffered_len = len64;
6002 body = conn->buf + conn->request_len + conn->consumed_content;
6003 memcpy(buf, body, (
size_t)buffered_len);
6004 len64 -= buffered_len;
6005 conn->consumed_content += buffered_len;
6006 nread += buffered_len;
6007 buf = (
char *)buf + buffered_len;
6013 if ((n =
pull_all(NULL, conn, (
char *)buf, (
int)len64)) >= 0) {
6016 nread = ((nread > 0) ? nread : n);
6038 mg_read(
struct mg_connection *conn,
void *buf,
size_t len)
6040 if (len > INT_MAX) {
6048 if (conn->is_chunked) {
6049 size_t all_read = 0;
6052 if (conn->is_chunked == 3) {
6057 if (conn->chunk_remainder) {
6061 ((conn->chunk_remainder > len) ? (len)
6062 : (conn->chunk_remainder));
6064 conn->content_len += (int)read_now;
6073 all_read += (size_t)read_ret;
6074 conn->chunk_remainder -= (size_t)read_ret;
6075 len -= (size_t)read_ret;
6077 if (conn->chunk_remainder == 0) {
6081 conn->content_len += 2;
6084 if ((x1 !=
'\r') || (x2 !=
'\n')) {
6095 unsigned long chunkSize = 0;
6097 for (i = 0; i < ((int)
sizeof(lenbuf) - 1); i++) {
6098 conn->content_len++;
6100 if ((i > 0) && (lenbuf[i] ==
'\r')
6101 && (lenbuf[i - 1] !=
'\r')) {
6104 if ((i > 1) && (lenbuf[i] ==
'\n')
6105 && (lenbuf[i - 1] ==
'\r')) {
6107 chunkSize = strtoul(lenbuf, &end, 16);
6108 if (chunkSize == 0) {
6110 conn->is_chunked = 3;
6114 if (!isxdigit(lenbuf[i])) {
6119 if ((end == NULL) || (*end !=
'\r')) {
6123 if (chunkSize == 0) {
6127 conn->chunk_remainder = chunkSize;
6131 return (
int)all_read;
6138 mg_write(
struct mg_connection *conn,
const void *buf,
size_t len)
6141 int64_t
n,
total, allowed;
6147 if (conn->throttle > 0) {
6148 if ((now = time(NULL)) != conn->last_throttle_time) {
6149 conn->last_throttle_time = now;
6150 conn->last_throttle_bytes = 0;
6152 allowed = conn->throttle - conn->last_throttle_bytes;
6153 if (allowed > (int64_t)len) {
6154 allowed = (int64_t)len;
6161 (int64_t)allowed)) == allowed) {
6162 buf = (
const char *)buf + total;
6163 conn->last_throttle_bytes +=
total;
6164 while ((total < (int64_t)len) && (conn->ctx->stop_flag == 0)) {
6165 allowed = (conn->throttle > ((int64_t)len - total))
6166 ? (int64_t)len -
total 6173 (int64_t)allowed)) != allowed) {
6177 conn->last_throttle_bytes = allowed;
6178 conn->last_throttle_time = time(NULL);
6179 buf = (
const char *)buf + n;
6192 conn->num_bytes_sent +=
total;
6202 unsigned int chunk_len)
6210 sprintf(lenbuf,
"%x\r\n", chunk_len);
6211 lenbuf_len = strlen(lenbuf);
6214 ret =
mg_write(conn, lenbuf, lenbuf_len);
6215 if (ret != (
int)lenbuf_len) {
6220 ret =
mg_write(conn, chunk, chunk_len);
6221 if (ret != (
int)chunk_len) {
6259 (*buf)[size - 1] = 0;
6273 size_t prealloc_size,
6299 }
else if ((
size_t)(len) >= prealloc_size) {
6302 *out_buf = (
char *)
mg_malloc((
size_t)(len) + 1);
6320 *out_buf = prealloc_buf;
6328 mg_vprintf(
struct mg_connection *conn,
const char *fmt, va_list ap)
6334 if ((len =
alloc_vprintf(&buf, mem,
sizeof(mem), fmt, ap)) > 0) {
6335 len =
mg_write(conn, buf, (
size_t)len);
6337 if ((buf != mem) && (buf != NULL)) {
6364 int is_form_url_encoded)
6367 #define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W')) 6369 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
6370 if ((i < src_len - 2) && (src[i] ==
'%')
6371 && isxdigit(*(
const unsigned char *)(src + i + 1))
6372 && isxdigit(*(
const unsigned char *)(src + i + 2))) {
6373 a = tolower(*(
const unsigned char *)(src + i + 1));
6374 b = tolower(*(
const unsigned char *)(src + i + 2));
6377 }
else if (is_form_url_encoded && (src[i] ==
'+')) {
6386 return (i >= src_len) ? j : -1;
6397 return mg_get_var2(data, data_len, name, dst, dst_len, 0);
6409 const char *p, *
e, *
s;
6413 if ((dst == NULL) || (dst_len == 0)) {
6415 }
else if ((data == NULL) || (name == NULL) || (data_len == 0)) {
6419 name_len = strlen(name);
6420 e = data + data_len;
6425 for (p = data; p + name_len <
e; p++) {
6426 if (((p == data) || (p[-1] ==
'&')) && (p[name_len] ==
'=')
6432 s = (
const char *)memchr(p,
'&', (
size_t)(e - p));
6461 const char *var_name,
6465 const char *
s, *p, *end;
6466 int name_len, len = -1;
6468 if ((dst == NULL) || (dst_size == 0)) {
6473 if ((var_name == NULL) || ((s = cookie_header) == NULL)) {
6477 name_len = (int)strlen(var_name);
6478 end = s + strlen(s);
6479 for (; (s =
mg_strcasestr(s, var_name)) != NULL; s += name_len) {
6480 if (s[name_len] ==
'=') {
6482 if ((s == cookie_header) || (s[-1] ==
' ')) {
6484 if ((p = strchr(s,
' ')) == NULL) {
6490 if ((*s ==
'"') && (p[-1] ==
'"') && (p > s + 1)) {
6494 if ((
size_t)(p -
s) < dst_size) {
6508 #if defined(USE_WEBSOCKET) || defined(USE_LUA) 6510 base64_encode(
const unsigned char *src,
int src_len,
char *dst)
6512 static const char *b64 =
6513 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6516 for (i = j = 0; i < src_len; i += 3) {
6518 b = ((i + 1) >= src_len) ? 0 : src[i + 1];
6519 c = ((i + 2) >= src_len) ? 0 : src[i + 2];
6521 dst[j++] = b64[a >> 2];
6522 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
6523 if (i + 1 < src_len) {
6524 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
6526 if (i + 2 < src_len) {
6527 dst[j++] = b64[c & 63];
6530 while (j % 4 != 0) {
6538 #if defined(USE_LUA) 6539 static unsigned char 6540 b64reverse(
char letter)
6542 if ((letter >=
'A') && (letter <=
'Z')) {
6543 return letter -
'A';
6545 if ((letter >=
'a') && (letter <=
'z')) {
6546 return letter -
'a' + 26;
6548 if ((letter >=
'0') && (letter <=
'9')) {
6549 return letter -
'0' + 52;
6551 if (letter ==
'+') {
6554 if (letter ==
'/') {
6557 if (letter ==
'=') {
6565 base64_decode(
const unsigned char *src,
int src_len,
char *dst,
size_t *dst_len)
6568 unsigned char a,
b,
c,
d;
6572 for (i = 0; i < src_len; i += 4) {
6573 a = b64reverse(src[i]);
6578 b = b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]);
6583 c = b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]);
6588 d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
6593 dst[(*dst_len)++] = (a << 2) + (b >> 4);
6595 dst[(*dst_len)++] = (b << 4) + (c >> 2);
6597 dst[(*dst_len)++] = (c << 6) + d;
6610 const char *s = conn->request_info.request_method;
6611 return (s != NULL) && (!strcmp(s,
"PUT") || !strcmp(s,
"DELETE")
6612 || !strcmp(s,
"MKCOL") || !strcmp(s,
"PATCH"));
6618 #if !defined(NO_FILES) 6621 struct mg_connection *conn,
6622 const char *filename
6625 #if !defined(NO_CGI) 6632 #if defined(USE_LUA) 6633 if (
match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
6634 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
6639 #if defined(USE_DUKTAPE) 6640 if (
match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
6641 strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
6662 struct mg_file_stat *filestat)
6664 const char *list = conn->ctx->config[
INDEX_FILES];
6665 struct vec filename_vec;
6666 size_t n = strlen(path);
6672 while ((n > 0) && (path[n - 1] ==
'/')) {
6679 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
6681 if (filename_vec.len > (path_len - (n + 2))) {
6686 mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
6689 if (
mg_stat(conn, path, filestat)) {
6709 size_t filename_buf_len,
6710 struct mg_file_stat *filestat,
6712 int *is_script_resource,
6713 int *is_websocket_request,
6714 int *is_put_or_delete_request
6717 char const *accept_encoding;
6719 #if !defined(NO_FILES) 6720 const char *uri = conn->request_info.local_uri;
6722 const char *rewrite;
6725 char gz_path[PATH_MAX];
6727 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) 6729 size_t tmp_str_len, sep_pos;
6730 int allow_substitute_script_subresources;
6733 (
void)filename_buf_len;
6737 memset(filestat, 0,
sizeof(*filestat));
6740 *is_script_resource = 0;
6747 #if defined(USE_WEBSOCKET) 6749 #if !defined(NO_FILES) 6750 if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
6751 root = conn->ctx->config[WEBSOCKET_ROOT];
6755 *is_websocket_request = 0;
6759 conn->accept_gzip = 0;
6760 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
6761 if (strstr(accept_encoding,
"gzip") != NULL) {
6762 conn->accept_gzip = 1;
6766 #if !defined(NO_FILES) 6782 conn, &truncated, filename, filename_buf_len - 1,
"%s%s", root, uri);
6785 goto interpret_cleanup;
6790 while ((rewrite =
next_option(rewrite, &a, &b)) != NULL) {
6791 if ((match_len =
match_prefix(a.ptr, a.len, uri)) > 0) {
6795 filename_buf_len - 1,
6805 goto interpret_cleanup;
6811 if (
mg_stat(conn, filename, filestat)) {
6828 *is_script_resource = (!*is_put_or_delete_request);
6833 if (filestat->is_directory) {
6836 struct mg_file_stat tmp_filestat;
6837 memset(&tmp_filestat, 0,
sizeof(tmp_filestat));
6840 conn, filename, filename_buf_len, &tmp_filestat)) {
6844 *filestat = tmp_filestat;
6848 *is_script_resource = 1;
6851 *is_script_resource = 0;
6852 *is_found = (
mg_stat(conn, filename, filestat) ? 1 : 0);
6868 if (conn->accept_gzip) {
6870 conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", filename);
6873 goto interpret_cleanup;
6876 if (
mg_stat(conn, gz_path, filestat)) {
6878 filestat->is_gzipped = 1;
6886 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) 6889 tmp_str_len = strlen(filename);
6890 tmp_str = (
char *)
mg_malloc_ctx(tmp_str_len + PATH_MAX + 1, conn->ctx);
6893 goto interpret_cleanup;
6895 memcpy(tmp_str, filename, tmp_str_len + 1);
6898 allow_substitute_script_subresources =
6901 sep_pos = tmp_str_len;
6902 while (sep_pos > 0) {
6904 if (tmp_str[sep_pos] ==
'/') {
6905 int is_script = 0, does_exist = 0;
6907 tmp_str[sep_pos] = 0;
6910 does_exist =
mg_stat(conn, tmp_str, filestat);
6913 if (does_exist && is_script) {
6914 filename[sep_pos] = 0;
6915 memmove(filename + sep_pos + 2,
6916 filename + sep_pos + 1,
6917 strlen(filename + sep_pos + 1) + 1);
6918 conn->path_info = filename + sep_pos + 1;
6919 filename[sep_pos + 1] =
'/';
6920 *is_script_resource = 1;
6925 if (allow_substitute_script_subresources) {
6927 conn, tmp_str, tmp_str_len + PATH_MAX, filestat)) {
6934 DEBUG_TRACE(
"Substitute script %s serving path %s",
6939 tmp_str2 =
mg_strdup(filename + sep_pos + 1);
6951 goto interpret_cleanup;
6953 sep_pos = strlen(tmp_str);
6954 filename[sep_pos] = 0;
6955 conn->path_info = filename + sep_pos + 1;
6956 *is_script_resource = 1;
6967 filename[sep_pos] = 0;
6968 conn->path_info = 0;
6969 *is_script_resource = 0;
6976 tmp_str[sep_pos] =
'/';
6986 #if !defined(NO_FILES) 6989 memset(filestat, 0,
sizeof(*filestat));
6992 *is_script_resource = 0;
6993 *is_websocket_request = 0;
6994 *is_put_or_delete_request = 0;
7007 for (i = 0; i < buflen; i++) {
7009 const unsigned char c = ((
const unsigned char *)buf)[i];
7011 if ((c < 128) && ((char)c !=
'\r') && ((char)c !=
'\n')
7017 if (i < buflen - 1) {
7018 if ((buf[i] ==
'\n') && (buf[i + 1] ==
'\n')) {
7027 if (i < buflen - 3) {
7028 if ((buf[i] ==
'\r') && (buf[i + 1] ==
'\n') && (buf[i + 2] ==
'\r')
7029 && (buf[i + 3] ==
'\n')) {
7040 #if !defined(NO_CACHING) 7061 char month_str[32] = {0};
7062 int second, minute, hour, day, month, year;
7063 time_t result = (time_t)0;
7066 if ((sscanf(datetime,
7067 "%d/%3s/%d %d:%d:%d",
7073 &second) == 6) || (sscanf(datetime,
7074 "%d %3s %d %d:%d:%d",
7081 || (sscanf(datetime,
7082 "%*3s, %d %3s %d %d:%d:%d",
7088 &second) == 6) || (sscanf(datetime,
7089 "%d-%3s-%d %d:%d:%d",
7097 if ((month >= 0) && (year >= 1970)) {
7098 memset(&tm, 0,
sizeof(tm));
7099 tm.tm_year = year - 1900;
7105 result = timegm(&tm);
7121 while ((s[0] ==
'.') && (s[1] ==
'.')) {
7125 while (*s !=
'\0') {
7127 if ((s[-1] ==
'/') || (s[-1] ==
'\\')) {
7129 while (s[0] !=
'\0') {
7130 if ((s[0] ==
'/') || (s[0] ==
'\\')) {
7132 }
else if ((s[0] ==
'.') && (s[1] ==
'.')) {
7144 static const struct {
7152 {
".doc", 4,
"application/msword"},
7153 {
".eps", 4,
"application/postscript"},
7154 {
".exe", 4,
"application/octet-stream"},
7155 {
".js", 3,
"application/javascript"},
7156 {
".json", 5,
"application/json"},
7157 {
".pdf", 4,
"application/pdf"},
7158 {
".ps", 3,
"application/postscript"},
7159 {
".rtf", 4,
"application/rtf"},
7160 {
".xhtml", 6,
"application/xhtml+xml"},
7161 {
".xsl", 4,
"application/xml"},
7162 {
".xslt", 5,
"application/xml"},
7165 {
".ttf", 4,
"application/font-sfnt"},
7166 {
".cff", 4,
"application/font-sfnt"},
7167 {
".otf", 4,
"application/font-sfnt"},
7168 {
".aat", 4,
"application/font-sfnt"},
7169 {
".sil", 4,
"application/font-sfnt"},
7170 {
".pfr", 4,
"application/font-tdpfr"},
7171 {
".woff", 5,
"application/font-woff"},
7174 {
".mp3", 4,
"audio/mpeg"},
7175 {
".oga", 4,
"audio/ogg"},
7176 {
".ogg", 4,
"audio/ogg"},
7179 {
".gif", 4,
"image/gif"},
7180 {
".ief", 4,
"image/ief"},
7181 {
".jpeg", 5,
"image/jpeg"},
7182 {
".jpg", 4,
"image/jpeg"},
7183 {
".jpm", 4,
"image/jpm"},
7184 {
".jpx", 4,
"image/jpx"},
7185 {
".png", 4,
"image/png"},
7186 {
".svg", 4,
"image/svg+xml"},
7187 {
".tif", 4,
"image/tiff"},
7188 {
".tiff", 5,
"image/tiff"},
7191 {
".wrl", 4,
"model/vrml"},
7194 {
".css", 4,
"text/css"},
7195 {
".csv", 4,
"text/csv"},
7196 {
".htm", 4,
"text/html"},
7197 {
".html", 5,
"text/html"},
7198 {
".sgm", 4,
"text/sgml"},
7199 {
".shtm", 5,
"text/html"},
7200 {
".shtml", 6,
"text/html"},
7201 {
".txt", 4,
"text/plain"},
7202 {
".xml", 4,
"text/xml"},
7205 {
".mov", 4,
"video/quicktime"},
7206 {
".mp4", 4,
"video/mp4"},
7207 {
".mpeg", 5,
"video/mpeg"},
7208 {
".mpg", 4,
"video/mpeg"},
7209 {
".ogv", 4,
"video/ogg"},
7210 {
".qt", 3,
"video/quicktime"},
7215 {
".arj", 4,
"application/x-arj-compressed"},
7216 {
".gz", 3,
"application/x-gunzip"},
7217 {
".rar", 4,
"application/x-arj-compressed"},
7218 {
".swf", 4,
"application/x-shockwave-flash"},
7219 {
".tar", 4,
"application/x-tar"},
7220 {
".tgz", 4,
"application/x-tar-gz"},
7221 {
".torrent", 8,
"application/x-bittorrent"},
7222 {
".ppt", 4,
"application/x-mspowerpoint"},
7223 {
".xls", 4,
"application/x-msexcel"},
7224 {
".zip", 4,
"application/x-zip-compressed"},
7228 {
".aif", 4,
"audio/x-aif"},
7229 {
".m3u", 4,
"audio/x-mpegurl"},
7230 {
".mid", 4,
"audio/x-midi"},
7231 {
".ra", 3,
"audio/x-pn-realaudio"},
7232 {
".ram", 4,
"audio/x-pn-realaudio"},
7233 {
".wav", 4,
"audio/x-wav"},
7234 {
".bmp", 4,
"image/bmp"},
7235 {
".ico", 4,
"image/x-icon"},
7236 {
".pct", 4,
"image/x-pct"},
7237 {
".pict", 5,
"image/pict"},
7238 {
".rgb", 4,
"image/x-rgb"},
7239 {
".webm", 5,
"video/webm"},
7240 {
".asf", 4,
"video/x-ms-asf"},
7241 {
".avi", 4,
"video/x-msvideo"},
7242 {
".m4v", 4,
"video/x-m4v"},
7252 path_len = strlen(path);
7262 return "text/plain";
7271 struct vec ext_vec, mime_vec;
7272 const char *list, *ext;
7275 path_len = strlen(path);
7277 if ((ctx == NULL) || (vec == NULL)) {
7279 memset(vec,
'\0',
sizeof(
struct vec));
7287 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
7289 ext = path + path_len - ext_vec.len;
7297 vec->len = strlen(vec->ptr);
7304 bin2str(
char *to,
const unsigned char *p,
size_t len)
7306 static const char *hex =
"0123456789abcdef";
7308 for (; len--; p++) {
7309 *to++ = hex[p[0] >> 4];
7310 *to++ = hex[p[0] & 0x0f];
7329 while ((p = va_arg(ap,
const char *)) != NULL) {
7335 bin2str(buf, hash,
sizeof(hash));
7349 const char *response)
7351 char ha2[32 + 1], expected_response[32 + 1];
7354 if ((method == NULL) || (nonce == NULL) || (nc == NULL) || (cnonce == NULL)
7355 || (qop == NULL) || (response == NULL)) {
7360 if (strlen(response) != 32) {
7364 mg_md5(ha2, method,
":", uri, NULL);
7365 mg_md5(expected_response,
7388 struct mg_file *filep)
7390 if ((conn != NULL) && (conn->ctx != NULL)) {
7391 char name[PATH_MAX];
7395 if (gpass != NULL) {
7400 mg_cry(conn,
"fopen(%s): %s", gpass, strerror(
ERRNO));
7408 }
else if (
mg_stat(conn, path, &filep->stat)
7409 && filep->stat.is_directory) {
7428 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
7457 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
7468 char *
name, *value, *
s;
7469 const char *auth_header;
7476 (
void)memset(ah, 0,
sizeof(*ah));
7477 if (((auth_header =
mg_get_header(conn,
"Authorization")) == NULL)
7489 while (isspace(*(
unsigned char *)
s)) {
7505 if (*name ==
'\0') {
7509 if (!strcmp(name,
"username")) {
7511 }
else if (!strcmp(name,
"cnonce")) {
7513 }
else if (!strcmp(name,
"response")) {
7514 ah->response = value;
7515 }
else if (!strcmp(name,
"uri")) {
7517 }
else if (!strcmp(name,
"qop")) {
7519 }
else if (!strcmp(name,
"nc")) {
7521 }
else if (!strcmp(name,
"nonce")) {
7526 #ifndef NO_NONCE_CHECK 7528 if (ah->nonce == NULL) {
7532 nonce = strtoull(ah->nonce, &s, 10);
7533 if ((s == NULL) || (*s != 0)) {
7538 nonce ^= conn->ctx->auth_nonce_mask;
7548 if (nonce < (uint64_t)conn->ctx->start_time) {
7555 if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
7563 if (ah->user != NULL) {
7564 conn->request_info.remote_user =
mg_strdup(ah->user);
7574 mg_fgets(
char *buf,
size_t size,
struct mg_file *filep,
char **p)
7584 if ((filep->access.membuf != NULL) && (*p != NULL)) {
7585 memend = (
const char *)&filep->access.membuf[filep->stat.size];
7587 eof = (
char *)memchr(*p,
'\n', (
size_t)(memend - *p));
7594 ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (
size_t)(eof - *p);
7595 memcpy(buf, *p, len);
7598 return len ? eof : NULL;
7599 }
else if (filep->access.fp != NULL) {
7600 return fgets(buf, (
int)size, filep->access.fp);
7612 #define INITIAL_DEPTH 9 7613 #if INITIAL_DEPTH <= 0 7614 #error Bad INITIAL_DEPTH for recursion, set to at least 1 7617 struct read_auth_file_struct {
7618 struct mg_connection *conn;
7621 char buf[256 + 256 + 40];
7623 const char *f_domain;
7630 struct read_auth_file_struct *workdata,
7634 int is_authorized = 0;
7638 if (!filep || !workdata || (0 == depth)) {
7643 p = (
char *)filep->access.membuf;
7644 while (
mg_fgets(workdata->buf,
sizeof(workdata->buf), filep, &p) != NULL) {
7645 l = strlen(workdata->buf);
7647 if (isspace(workdata->buf[l - 1])
7648 || iscntrl(workdata->buf[l - 1])) {
7650 workdata->buf[
l] = 0;
7658 workdata->f_user = workdata->buf;
7660 if (workdata->f_user[0] ==
':') {
7664 if (workdata->f_user[1] ==
'#') {
7667 }
else if (!strncmp(workdata->f_user + 1,
"include=", 8)) {
7669 workdata->f_user + 9,
7680 if (is_authorized) {
7681 return is_authorized;
7685 "%s: cannot open authorization file: %s",
7694 "%s: syntax error in authorization file: %s",
7700 workdata->f_domain = strchr(workdata->f_user,
':');
7701 if (workdata->f_domain == NULL) {
7703 "%s: syntax error in authorization file: %s",
7708 *(
char *)(workdata->f_domain) = 0;
7709 (workdata->f_domain)++;
7711 workdata->f_ha1 = strchr(workdata->f_domain,
':');
7712 if (workdata->f_ha1 == NULL) {
7714 "%s: syntax error in authorization file: %s",
7719 *(
char *)(workdata->f_ha1) = 0;
7720 (workdata->f_ha1)++;
7722 if (!strcmp(workdata->ah.user, workdata->f_user)
7723 && !strcmp(workdata->domain, workdata->f_domain)) {
7724 return check_password(workdata->conn->request_info.request_method,
7729 workdata->ah.cnonce,
7731 workdata->ah.response);
7735 return is_authorized;
7741 authorize(
struct mg_connection *conn,
struct mg_file *filep,
const char *realm)
7743 struct read_auth_file_struct workdata;
7746 if (!conn || !conn->ctx) {
7750 memset(&workdata, 0,
sizeof(workdata));
7751 workdata.conn = conn;
7758 workdata.domain = realm;
7771 const char *filename)
7776 if (!conn || !filename) {
7795 char fname[PATH_MAX];
7796 struct vec uri_vec, filename_vec;
7799 int authorized = 1, truncated;
7801 if (!conn || !conn->ctx) {
7806 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
7807 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
7813 (
int)filename_vec.len,
7819 "%s: cannot open %s: %s",
7833 authorized =
authorize(conn, &file, NULL);
7846 time_t curtime = time(NULL);
7847 uint64_t nonce = (uint64_t)(conn->ctx->start_time);
7853 (
void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
7854 nonce += conn->ctx->nonce_count;
7855 ++conn->ctx->nonce_count;
7856 (
void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
7858 nonce ^= conn->ctx->auth_nonce_mask;
7859 conn->status_code = 401;
7860 conn->must_close = 1;
7864 mg_printf(conn,
"HTTP/1.1 401 Unauthorized\r\n");
7869 "Connection: %s\r\n" 7870 "Content-Length: 0\r\n" 7871 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " 7887 if (conn && conn->ctx) {
7895 #if !defined(NO_FILES) 7904 if (passfile != NULL
7924 char line[512], u[512] =
"", d[512] =
"", ha1[33], tmp[PATH_MAX + 8];
7931 if ((pass != NULL) && (pass[0] ==
'\0')) {
7936 if ((fname == NULL) || (domain == NULL) || (user == NULL)) {
7943 if (strchr(user,
':') != NULL) {
7946 if (strchr(domain,
':') != NULL) {
7952 for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
7953 if (iscntrl(user[i])) {
7960 for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
7961 if (iscntrl(domain[i])) {
7970 if ((strlen(fname) + 4) >= PATH_MAX) {
7976 strcat(tmp,
".tmp");
7980 if ((fp = fopen(fname,
"a+")) != NULL) {
7985 if ((fp = fopen(fname,
"r")) == NULL) {
7987 }
else if ((fp2 = fopen(tmp,
"w+")) == NULL) {
7993 while (fgets(line,
sizeof(line), fp) != NULL) {
7994 if (sscanf(line,
"%255[^:]:%255[^:]:%*s", u, d) != 2) {
8000 if (!strcmp(u, user) && !strcmp(d, domain)) {
8003 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
8004 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
8007 fprintf(fp2,
"%s", line);
8012 if (!found && (pass != NULL)) {
8013 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
8014 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
8032 return (port <= 0xffff);
8039 struct addrinfo hints, *res, *ressave;
8043 memset(&hints, 0,
sizeof(
struct addrinfo));
8044 hints.ai_family = af;
8046 gai_ret = getaddrinfo(src, NULL, &hints, &res);
8061 if (dstlen >= (
size_t)res->ai_addrlen) {
8062 memcpy(dst, res->ai_addr, res->ai_addrlen);
8068 freeaddrinfo(ressave);
8086 memset(sa, 0,
sizeof(*sa));
8112 #if !defined(NO_SSL) 8113 #if !defined(NO_SSL_DL) 8114 #ifdef OPENSSL_API_1_1 8115 if (use_ssl && (TLS_client_method == NULL)) {
8121 "SSL is not initialized");
8131 "SSL is not initialized");
8143 if (
mg_inet_pton(AF_INET, host, &sa->sin,
sizeof(sa->sin))) {
8144 sa->sin.sin_family = AF_INET;
8145 sa->sin.sin_port = htons((uint16_t)port);
8148 }
else if (
mg_inet_pton(AF_INET6, host, &sa->sin6,
sizeof(sa->sin6))) {
8149 sa->sin6.sin6_family = AF_INET6;
8150 sa->sin6.sin6_port = htons((uint16_t)port);
8152 }
else if (host[0] ==
'[') {
8155 size_t l = strlen(host + 1);
8156 char *
h = (l > 1) ?
mg_strdup(host + 1) : NULL;
8159 if (
mg_inet_pton(AF_INET6, h, &sa->sin6,
sizeof(sa->sin6))) {
8160 sa->sin6.sin6_family = AF_INET6;
8161 sa->sin6.sin6_port = htons((uint16_t)port);
8180 *sock = socket(PF_INET, SOCK_STREAM, 0);
8183 else if (ip_ver == 6) {
8184 *sock = socket(PF_INET6, SOCK_STREAM, 0);
8201 && (connect(*sock, (
struct sockaddr *)&sa->sin,
sizeof(sa->sin))
8214 && (connect(*sock, (
struct sockaddr *)&sa->sin6,
sizeof(sa->sin6))
8231 "connect(%s:%d): %s",
8245 static const char *dont_escape =
"._-$,;~()";
8246 static const char *hex =
"0123456789abcdef";
8248 const char *end = dst + dst_len - 1;
8250 for (; ((*src !=
'\0') && (pos < end)); src++, pos++) {
8251 if (isalnum(*(
const unsigned char *)src)
8252 || (strchr(dont_escape, *(
const unsigned char *)src) != NULL)) {
8254 }
else if (pos + 2 < end) {
8256 pos[1] = hex[(*(
const unsigned char *)src) >> 4];
8257 pos[2] = hex[(*(
const unsigned char *)src) & 0xf];
8265 return (*src ==
'\0') ? (int)(pos - dst) : -1;
8275 char size[64], mod[64];
8278 hrefsize = PATH_MAX * 3;
8283 if (de->file.is_directory) {
8293 if (de->file.size < 1024) {
8299 (
int)de->file.size);
8300 }
else if (de->file.size < 0x100000) {
8306 (
double)de->file.size / 1024.0);
8307 }
else if (de->file.size < 0x40000000) {
8313 (
double)de->file.size / 1048576);
8320 (
double)de->file.size / 1073741824);
8327 tm = localtime(&de->file.last_modified);
8329 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", tm);
8331 mg_strlcpy(mod,
"01-Jan-1970 00:00",
sizeof(mod));
8332 mod[
sizeof(mod) - 1] =
'\0';
8336 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>" 8337 "<td> %s</td><td> %s</td></tr>\n",
8338 de->conn->request_info.local_uri,
8340 de->file.is_directory ?
"/" :
"",
8342 de->file.is_directory ?
"/" :
"",
8358 const struct de *a = (
const struct de *)p1, *b = (
const struct de *)
p2;
8359 const char *query_string = a->conn->request_info.query_string;
8362 if (query_string == NULL) {
8363 query_string =
"na";
8366 if (a->file.is_directory && !b->file.is_directory) {
8368 }
else if (!a->file.is_directory && b->file.is_directory) {
8370 }
else if (*query_string ==
'n') {
8371 cmp_result = strcmp(a->file_name, b->file_name);
8372 }
else if (*query_string ==
's') {
8373 cmp_result = (a->file.size == b->file.size)
8375 : ((a->file.size > b->file.size) ? 1 : -1);
8376 }
else if (*query_string ==
'd') {
8378 (a->file.last_modified == b->file.last_modified)
8380 : ((a->file.last_modified > b->file.last_modified) ? 1
8384 return (query_string[1] ==
'd') ? -cmp_result : cmp_result;
8393 if (conn && conn->ctx) {
8395 const char *pattern = conn->ctx->config[
HIDE_FILES];
8396 return (
match_prefix(pw_pattern, strlen(pw_pattern), path) > 0)
8397 || ((pattern != NULL)
8398 && (
match_prefix(pattern, strlen(pattern), path) > 0));
8408 int (*cb)(
struct de *,
void *))
8410 char path[PATH_MAX];
8416 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
8423 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")
8429 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
8436 memset(&de.file, 0,
sizeof(de.file));
8443 if (!
mg_stat(conn, path, &de.file)) {
8445 "%s: mg_stat(%s) failed: %s",
8450 de.file_name = dp->d_name;
8459 #if !defined(NO_FILES) 8463 char path[PATH_MAX];
8470 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
8478 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")) {
8483 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
8490 memset(&de.file, 0,
sizeof(de.file));
8498 if (!
mg_stat(conn, path, &de.file)) {
8500 "%s: mg_stat(%s) failed: %s",
8507 if (de.file.is_directory) {
8528 struct dir_scan_data {
8530 unsigned int num_entries;
8531 unsigned int arr_size;
8540 if (new_ptr == NULL) {
8550 struct dir_scan_data *dsd = (
struct dir_scan_data *)data;
8552 if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
8555 (
struct de *)
realloc2(dsd->entries,
8556 dsd->arr_size *
sizeof(dsd->entries[0]));
8558 if (dsd->entries == NULL) {
8560 dsd->num_entries = 0;
8562 dsd->entries[dsd->num_entries].file_name =
mg_strdup(de->file_name);
8563 dsd->entries[dsd->num_entries].file = de->file;
8564 dsd->entries[dsd->num_entries].conn = de->conn;
8577 struct dir_scan_data data = {NULL, 0, 128};
8579 time_t curtime = time(NULL);
8584 "Error: Cannot open directory\nopendir(%s): %s",
8596 sort_direction = ((conn->request_info.query_string != NULL)
8597 && (conn->request_info.query_string[1] ==
'd'))
8601 conn->must_close = 1;
8607 "Connection: close\r\n" 8608 "Content-Type: text/html; charset=utf-8\r\n\r\n",
8611 "<html><head><title>Index of %s</title>" 8612 "<style>th {text-align: left;}</style></head>" 8613 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">" 8614 "<tr><th><a href=\"?n%c\">Name</a></th>" 8615 "<th><a href=\"?d%c\">Modified</a></th>" 8616 "<th><a href=\"?s%c\">Size</a></th></tr>" 8617 "<tr><td colspan=\"3\"><hr></td></tr>",
8618 conn->request_info.local_uri,
8619 conn->request_info.local_uri,
8626 "<tr><td><a href=\"%s%s\">%s</a></td>" 8627 "<td> %s</td><td> %s</td></tr>\n",
8628 conn->request_info.local_uri,
8635 if (data.entries != NULL) {
8637 (
size_t)data.num_entries,
8638 sizeof(data.entries[0]),
8640 for (i = 0; i < data.num_entries; i++) {
8642 mg_free(data.entries[i].file_name);
8647 mg_printf(conn,
"%s",
"</table></body></html>");
8648 conn->status_code = 200;
8655 struct mg_file *filep,
8660 int to_read, num_read, num_written;
8663 if (!filep || !conn) {
8669 : (int64_t)(filep->stat.size);
8670 offset = (offset < 0) ? 0 : ((offset > size) ? size : offset);
8672 if ((len > 0) && (filep->access.membuf != NULL) && (size > 0)) {
8674 if (len > size - offset) {
8675 len = size - offset;
8677 mg_write(conn, filep->access.membuf + offset, (
size_t)len);
8678 }
else if (len > 0 && filep->access.fp != NULL) {
8680 #if defined(__linux__) 8682 if ((conn->ssl == 0) && (conn->throttle == 0)
8685 off_t sf_offs = (off_t)offset;
8687 int sf_file = fileno(filep->access.fp);
8694 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
8696 sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
8700 }
else if (loop_cnt == 0) {
8706 }
else if (sf_sent == 0) {
8712 }
while ((len > 0) && (sf_sent >= 0));
8721 offset = (int64_t)sf_offs;
8724 if ((offset > 0) && (fseeko(filep->access.fp, offset, SEEK_SET) != 0)) {
8725 mg_cry(conn,
"%s: fseeko() failed: %s", __func__, strerror(
ERRNO));
8730 "Error: Unable to access file at requested position.");
8734 to_read =
sizeof(buf);
8735 if ((int64_t)to_read > len) {
8741 (
int)fread(buf, 1, (
size_t)to_read, filep->access.fp))
8747 if ((num_written =
mg_write(conn, buf, (
size_t)num_read))
8770 if ((filestat != NULL) && (buf != NULL)) {
8776 (
unsigned long)filestat->last_modified,
8785 if (filep != NULL && filep->fp != NULL) {
8789 if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
8791 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
8803 struct mg_file *filep,
8805 const char *additional_headers)
8807 char date[64], lm[64], etag[64];
8809 const char *msg =
"OK", *hdr;
8810 time_t curtime = time(NULL);
8812 struct vec mime_vec;
8814 char gz_path[PATH_MAX];
8815 const char *encoding =
"";
8816 const char *cors1, *cors2, *cors3;
8817 int allow_on_the_fly_compression;
8819 if ((conn == NULL) || (conn->ctx == NULL) || (filep == NULL)) {
8823 if (mime_type == NULL) {
8827 mime_vec.len = strlen(mime_type);
8832 "Error: File size is too large to send\n%" INT64_FMT,
8836 cl = (int64_t)filep->stat.size;
8837 conn->status_code = 200;
8843 allow_on_the_fly_compression = conn->accept_gzip;
8845 if (filep->stat.is_gzipped) {
8846 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
8851 "Error: Path of zipped file too long (%s)",
8857 encoding =
"Content-Encoding: gzip\r\n";
8860 allow_on_the_fly_compression = 0;
8866 "Error: Cannot open file\nfopen(%s): %s",
8878 && (r1 >= 0) && (r2 >= 0)) {
8881 if (filep->stat.is_gzipped) {
8886 "Error: Range requests in gzipped files are not supported");
8891 conn->status_code = 206;
8892 cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
8897 "Content-Range: bytes " 8902 msg =
"Partial Content";
8905 allow_on_the_fly_compression = 0;
8915 cors1 =
"Access-Control-Allow-Origin: ";
8919 cors1 = cors2 = cors3 =
"";
8930 if (allow_on_the_fly_compression) {
8942 "HTTP/1.1 %d %s\r\n" 8955 "Last-Modified: %s\r\n" 8957 "Content-Type: %.*s\r\n" 8959 "Connection: %s\r\n" 8960 "Accept-Ranges: bytes\r\n" 8974 if (additional_headers != NULL) {
8977 (
int)strlen(additional_headers),
8978 additional_headers);
8983 if (strcmp(conn->request_info.request_method,
"HEAD") != 0) {
8990 #if !defined(NO_CACHING) 8993 struct mg_file *filep)
8995 char date[64], lm[64], etag[64];
8996 time_t curtime = time(NULL);
8998 if ((conn == NULL) || (filep == NULL)) {
9001 conn->status_code = 304;
9007 "HTTP/1.1 %d %s\r\n" 9015 "Last-Modified: %s\r\n" 9017 "Connection: %s\r\n" 9046 const char *additional_headers)
9055 if (
mg_stat(conn, path, &file.stat)) {
9056 if (file.stat.is_directory) {
9064 "Error: Directory listing denied");
9068 conn, path, &file, mime_type, additional_headers);
9083 put_dir(
struct mg_connection *conn,
const char *path)
9091 for (s = p = path + 2; (p = strchr(s,
'/')) != NULL; s = ++p) {
9092 len = (size_t)(p - path);
9093 if (len >=
sizeof(buf)) {
9098 memcpy(buf, path, len);
9103 if (!
mg_stat(conn, buf, &file.stat) &&
mg_mkdir(conn, buf, 0755) != 0) {
9124 mg_cry(conn,
"%s: Cannot remove invalid file %s", __func__, path);
9137 if (conn->consumed_content != 0) {
9138 mg_cry(conn,
"%s: Contents already consumed", __func__);
9157 ret =
mg_read(conn, buf,
sizeof(buf));
9159 n = (int)fwrite(buf, 1, (
size_t)ret, fi.access.fp);
9167 ret =
mg_read(conn, buf,
sizeof(buf));
9191 while (isgraph(**ppw)) {
9198 if ((**ppw !=
'\r') && (**ppw !=
'\n')) {
9212 }
while ((**ppw) && isspace(**ppw));
9217 if (!isgraph(**ppw)) {
9235 int num_headers = 0;
9237 for (i = 0; i < (int)MG_MAX_HEADERS; i++) {
9239 while ((*dp !=
':') && (*dp >= 33) && (*dp <= 126)) {
9257 }
while (*dp ==
' ');
9261 *buf = dp + strcspn(dp,
"\r\n");
9262 if (((*buf)[0] !=
'\r') || ((*buf)[1] !=
'\n')) {
9266 num_headers = i + 1;
9276 if ((*buf)[0] ==
'\r') {
9285 struct mg_http_method_info {
9287 int request_has_body;
9288 int response_has_body;
9298 {
"GET", 0, 1, 1, 1, 1},
9299 {
"POST", 1, 1, 0, 0, 0},
9300 {
"PUT", 1, 0, 0, 1, 0},
9301 {
"DELETE", 0, 0, 0, 1, 0},
9302 {
"HEAD", 0, 0, 1, 1, 1},
9303 {
"OPTIONS", 0, 0, 1, 1, 0},
9304 {
"CONNECT", 1, 1, 0, 0, 0},
9308 {
"PATCH", 1, 0, 0, 0, 0},
9312 {
"PROPFIND", 0, 1, 1, 1, 0},
9318 {
"MKCOL", 0, 0, 0, 1, 0},
9340 {
"REPORT", 1, 1, 1, 1, 1},
9347 {NULL, 0, 0, 0, 0, 0}
9352 static const struct mg_http_method_info *
9362 if (!strcmp(m->name, method)) {
9402 while ((len > 0) && isspace(*(
unsigned char *)buf)) {
9414 if (iscntrl(*(
unsigned char *)buf)) {
9420 if (request_length <= 0) {
9421 return request_length;
9423 buf[request_length - 1] =
'\0';
9425 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
9470 return request_length + init_skip;
9477 int response_length;
9489 while ((len > 0) && isspace(*(
unsigned char *)buf)) {
9501 if (iscntrl(*(
unsigned char *)buf)) {
9507 if (response_length <= 0) {
9508 return response_length;
9510 buf[response_length - 1] =
'\0';
9519 while ((*buf !=
'\0') && isspace(*(
unsigned char *)buf)) {
9522 if ((*buf == 0) || (*buf ==
'\r') || (*buf ==
'\n')) {
9528 if (strncmp(buf,
"HTTP/", 5) != 0) {
9533 if (!isgraph(buf[0])) {
9550 l = strtol(tmp, &tmp2, 10);
9551 if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
9562 while (isprint(*buf)) {
9565 if ((*buf !=
'\r') && (*buf !=
'\n')) {
9572 }
while ((*buf) && isspace(*buf));
9582 return response_length + init_skip;
9593 struct mg_connection *conn,
9598 int request_len, n = 0;
9599 struct timespec last_action_time;
9600 double request_timeout;
9606 memset(&last_action_time, 0,
sizeof(last_action_time));
9612 request_timeout = -1.0;
9614 if (conn->handled_requests > 0) {
9624 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
9626 while (request_len == 0) {
9628 if (conn->ctx->stop_flag != 0) {
9633 if (*nread >= bufsiz) {
9639 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
9651 if ((request_len == 0) && (request_timeout >= 0)) {
9653 > request_timeout) {
9657 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
9665 #if !defined(NO_CACHING) 9669 const struct mg_file_stat *filestat)
9683 #if !defined(NO_CGI) || !defined(NO_FILES) 9687 const char *expect, *body;
9689 int to_read, nread, success = 0;
9690 int64_t buffered_len;
9691 double timeout = -1.0;
9707 if ((conn->content_len == -1) && (!conn->is_chunked)) {
9712 "Error: Client did not specify content length");
9713 }
else if ((expect != NULL)
9719 "Error: Can not fulfill expectation %s",
9722 if (expect != NULL) {
9723 (
void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
9724 conn->status_code = 100;
9726 conn->status_code = 200;
9729 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
9730 - conn->consumed_content;
9735 if ((buffered_len < 0) || (conn->consumed_content != 0)) {
9740 if (buffered_len > 0) {
9741 if ((int64_t)buffered_len > conn->content_len) {
9742 buffered_len = (int)conn->content_len;
9744 body = conn->buf + conn->request_len + conn->consumed_content;
9745 push_all(conn->ctx, fp, sock, ssl, body, (int64_t)buffered_len);
9746 conn->consumed_content += buffered_len;
9750 while (conn->consumed_content < conn->content_len) {
9751 to_read =
sizeof(buf);
9752 if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
9753 to_read = (int)(conn->content_len - conn->consumed_content);
9755 nread =
pull_inner(NULL, conn, buf, to_read, timeout);
9761 if (
push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) {
9765 conn->consumed_content += nread;
9768 if (conn->consumed_content == conn->content_len) {
9769 success = (nread >= 0);
9785 #if !defined(NO_CGI) 9796 struct cgi_environment {
9797 struct mg_connection *conn;
9809 static void addenv(
struct cgi_environment *env,
9816 addenv(
struct cgi_environment *env,
const char *fmt, ...)
9824 space = (env->buflen - env->bufused);
9827 n = strlen(fmt) + 2 + 128;
9837 "%s: Cannot allocate memory for CGI variable [%s]",
9844 space = (env->buflen - env->bufused);
9848 added = env->buf + env->bufused;
9852 mg_vsnprintf(env->conn, &truncated, added, (
size_t)space, fmt, ap);
9861 }
while (truncated);
9864 n = strlen(added) + 1;
9868 space = (env->varlen - env->varused);
9871 "%s: Cannot register CGI variable [%s]",
9878 env->var[env->varused] = added;
9887 struct cgi_environment *env)
9892 int i, truncated, uri_len;
9894 if ((conn == NULL) || (prog == NULL) || (env == NULL)) {
9902 if (env->buf == NULL) {
9904 "%s: Not enough memory for environmental buffer",
9910 env->var = (
char **)
mg_malloc_ctx(env->buflen *
sizeof(
char *), conn->ctx);
9911 if (env->var == NULL) {
9913 "%s: Not enough memory for environmental variables",
9925 addenv(env,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
9926 addenv(env,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
9927 addenv(env,
"%s",
"REDIRECT_STATUS=200");
9929 #if defined(USE_IPV6) 9930 if (conn->client.lsa.sa.sa_family == AF_INET6) {
9931 addenv(env,
"SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
9935 addenv(env,
"SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
9939 addenv(env,
"REMOTE_ADDR=%s", src_addr);
9941 addenv(env,
"REQUEST_METHOD=%s", conn->request_info.request_method);
9942 addenv(env,
"REMOTE_PORT=%d", conn->request_info.remote_port);
9944 addenv(env,
"REQUEST_URI=%s", conn->request_info.request_uri);
9945 addenv(env,
"LOCAL_URI=%s", conn->request_info.local_uri);
9948 uri_len = (int)strlen(conn->request_info.local_uri);
9949 if (conn->path_info == NULL) {
9950 if (conn->request_info.local_uri[uri_len - 1] !=
'/') {
9952 addenv(env,
"SCRIPT_NAME=%s", conn->request_info.local_uri);
9955 const char *index_file = strrchr(prog,
'/');
9959 conn->request_info.local_uri,
9967 uri_len - (
int)strlen(conn->path_info),
9968 conn->request_info.local_uri);
9971 addenv(env,
"SCRIPT_FILENAME=%s", prog);
9972 if (conn->path_info == NULL) {
9976 "PATH_TRANSLATED=%s%s",
9981 addenv(env,
"HTTPS=%s", (conn->ssl == NULL) ?
"off" :
"on");
9984 addenv(env,
"CONTENT_TYPE=%s", s);
9986 if (conn->request_info.query_string != NULL) {
9987 addenv(env,
"QUERY_STRING=%s", conn->request_info.query_string);
9990 addenv(env,
"CONTENT_LENGTH=%s", s);
9992 if ((s = getenv(
"PATH")) != NULL) {
9993 addenv(env,
"PATH=%s", s);
9995 if (conn->path_info != NULL) {
9996 addenv(env,
"PATH_INFO=%s", conn->path_info);
9999 if (conn->status_code > 0) {
10001 addenv(env,
"STATUS=%d", conn->status_code);
10004 #if defined(_WIN32) 10005 if ((s = getenv(
"COMSPEC")) != NULL) {
10006 addenv(env,
"COMSPEC=%s", s);
10008 if ((s = getenv(
"SYSTEMROOT")) != NULL) {
10009 addenv(env,
"SYSTEMROOT=%s", s);
10011 if ((s = getenv(
"SystemDrive")) != NULL) {
10012 addenv(env,
"SystemDrive=%s", s);
10014 if ((s = getenv(
"ProgramFiles")) != NULL) {
10015 addenv(env,
"ProgramFiles=%s", s);
10017 if ((s = getenv(
"ProgramFiles(x86)")) != NULL) {
10018 addenv(env,
"ProgramFiles(x86)=%s", s);
10021 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL) {
10022 addenv(env,
"LD_LIBRARY_PATH=%s", s);
10026 if ((s = getenv(
"PERLLIB")) != NULL) {
10027 addenv(env,
"PERLLIB=%s", s);
10030 if (conn->request_info.remote_user != NULL) {
10031 addenv(env,
"REMOTE_USER=%s", conn->request_info.remote_user);
10032 addenv(env,
"%s",
"AUTH_TYPE=Digest");
10036 for (i = 0; i < conn->request_info.num_headers; i++) {
10041 sizeof(http_var_name),
10043 conn->request_info.http_headers[i].name);
10047 "%s: HTTP header variable too long [%s]",
10049 conn->request_info.http_headers[i].name);
10054 for (p = http_var_name; *p !=
'\0'; p++) {
10058 *p = (char)toupper(*(
unsigned char *)p);
10064 conn->request_info.http_headers[i].value);
10069 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
10070 addenv(env,
"%.*s", (
int)var_vec.len, var_vec.ptr);
10073 env->var[env->varused] = NULL;
10074 env->buf[env->bufused] =
'\0';
10085 int headers_len, data_len, i, truncated;
10086 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
10087 const char *status, *status_text, *connection_state;
10088 char *pbuf, dir[PATH_MAX], *p;
10090 struct cgi_environment blk;
10091 FILE *in = NULL, *out = NULL, *err = NULL;
10093 pid_t pid = (pid_t)-1;
10095 if (conn == NULL) {
10114 mg_cry(conn,
"Error: CGI program \"%s\": Path too long", prog);
10119 if ((p = strrchr(dir,
'/')) != NULL) {
10127 if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) {
10128 status = strerror(
ERRNO);
10130 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
10135 "Error: Cannot create CGI pipe: %s",
10141 pid =
spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
10143 if (pid == (pid_t)-1) {
10144 status = strerror(
ERRNO);
10146 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
10151 "Error: Cannot spawn CGI process [%s]: %s",
10173 fdin[0] = fdout[1] = fderr[1] = -1;
10175 if ((in = fdopen(fdin[1],
"wb")) == NULL) {
10176 status = strerror(
ERRNO);
10178 "Error: CGI program \"%s\": Can not open stdin: %s",
10183 "Error: CGI can not open fdin\nfopen: %s",
10188 if ((out = fdopen(fdout[0],
"rb")) == NULL) {
10189 status = strerror(
ERRNO);
10191 "Error: CGI program \"%s\": Can not open stdout: %s",
10196 "Error: CGI can not open fdout\nfopen: %s",
10201 if ((err = fdopen(fderr[0],
"rb")) == NULL) {
10202 status = strerror(
ERRNO);
10204 "Error: CGI program \"%s\": Can not open stderr: %s",
10209 "Error: CGI can not open fdout\nfopen: %s",
10217 fout.access.fp = out;
10219 if ((conn->request_info.content_length != 0) || (conn->is_chunked)) {
10221 (
signed long long)conn->request_info.content_length);
10227 "Error: CGI program \"%s\": Forward body data failed",
10247 "Error: Not enough memory for CGI buffer (%u bytes)",
10248 (
unsigned int)buflen);
10250 "Error: CGI program \"%s\": Not enough memory for buffer (%u " 10253 (
unsigned int)buflen);
10258 headers_len =
read_message(out, conn, buf, (
int)buflen, &data_len);
10259 DEBUG_TRACE(
"CGI: response: %li", (
signed long)headers_len);
10261 if (headers_len <= 0) {
10265 i =
pull_all(err, conn, buf, (
int)buflen);
10268 "Error: CGI program \"%s\" sent error " 10275 "Error: CGI program \"%s\" sent error " 10282 "Error: CGI program sent malformed or too big " 10283 "(>%u bytes) HTTP headers: [%.*s]",
10290 "Error: CGI program sent malformed or too big " 10291 "(>%u bytes) HTTP headers: [%.*s]",
10301 buf[headers_len - 1] =
'\0';
10305 status_text =
"OK";
10308 conn->status_code = atoi(status);
10309 status_text = status;
10310 while (isdigit(*(
const unsigned char *)status_text)
10311 || *status_text ==
' ') {
10316 conn->status_code = 302;
10318 conn->status_code = 200;
10323 conn->must_close = 1;
10326 DEBUG_TRACE(
"CGI: response %u %s", conn->status_code, status_text);
10328 (
void)
mg_printf(conn,
"HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
10340 mg_write(conn, buf + headers_len, (
size_t)(data_len - headers_len));
10351 if (pid != (pid_t)-1) {
10352 kill(pid, SIGKILL);
10353 #if !defined(_WIN32) 10356 while (waitpid(pid, &st, 0) != -1)
10361 if (fdin[0] != -1) {
10364 if (fdout[1] != -1) {
10370 }
else if (fdin[1] != -1) {
10376 }
else if (fdout[0] != -1) {
10382 }
else if (fderr[0] != -1) {
10393 #if !defined(NO_FILES) 10395 mkcol(
struct mg_connection *conn,
const char *path)
10400 time_t curtime = time(NULL);
10402 if (conn == NULL) {
10409 memset(&de.file, 0,
sizeof(de.file));
10410 if (!
mg_stat(conn, path, &de.file)) {
10412 "%s: mg_stat(%s) failed: %s",
10418 if (de.file.last_modified) {
10423 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
10427 body_len = conn->data_len - conn->request_len;
10428 if (body_len > 0) {
10430 conn, 415,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
10437 conn->status_code = 201;
10440 "HTTP/1.1 %d Created\r\n" 10447 "Content-Length: 0\r\n" 10448 "Connection: %s\r\n\r\n",
10450 }
else if (rc == -1) {
10451 if (errno == EEXIST) {
10453 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
10454 }
else if (errno == EACCES) {
10456 conn, 403,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
10457 }
else if (errno == ENOENT) {
10459 conn, 409,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
10462 conn, 500,
"fopen(%s): %s", path, strerror(
ERRNO));
10476 time_t curtime = time(NULL);
10478 if (conn == NULL) {
10482 if (
mg_stat(conn, path, &file.stat)) {
10484 conn->status_code = 200;
10486 if (file.stat.is_directory) {
10495 if (file.access.membuf != NULL) {
10499 "Error: Put not possible\nReplacing %s " 10500 "is not supported",
10506 if (access(path, W_OK) == 0) {
10508 conn->status_code = 200;
10514 "Error: Put not possible\nReplacing %s is not allowed",
10521 conn->status_code = 201;
10529 "HTTP/1.1 %d %s\r\n",
10536 "Content-Length: 0\r\n" 10537 "Connection: %s\r\n\r\n",
10550 "Error: Path too long\nput_dir(%s): %s",
10560 "Error: Can not create directory\nput_dir(%s): %s",
10569 || file.access.fp == NULL) {
10573 "Error: Can not create file\nfopen(%s): %s",
10583 conn->status_code = 206;
10584 fseeko(file.access.fp, r1, SEEK_SET);
10598 conn->status_code = 507;
10603 "HTTP/1.1 %d %s\r\n",
10610 "Content-Length: 0\r\n" 10611 "Connection: %s\r\n\r\n",
10621 memset(&de.file, 0,
sizeof(de.file));
10622 if (!
mg_stat(conn, path, &de.file)) {
10626 "Error: Cannot delete file\nFile %s not found",
10632 if (de.access.membuf != NULL) {
10637 "Error: Delete not possible\nDeleting %s is not supported",
10643 if (de.file.is_directory) {
10656 if (access(path, W_OK) != 0) {
10661 "Error: Delete not possible\nDeleting %s is not allowed",
10674 "Error: Cannot delete file\nremove(%s): %s",
10683 send_ssi_file(
struct mg_connection *,
const char *,
struct mg_file *,
int);
10697 if (conn == NULL) {
10704 if (sscanf(tag,
" virtual=\"%511[^\"]\"", file_name) == 1) {
10706 file_name[511] = 0;
10715 }
else if (sscanf(tag,
" abspath=\"%511[^\"]\"", file_name) == 1) {
10718 file_name[511] = 0;
10720 mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", file_name);
10722 }
else if ((sscanf(tag,
" file=\"%511[^\"]\"", file_name) == 1)
10723 || (sscanf(tag,
" \"%511[^\"]\"", file_name) == 1)) {
10725 file_name[511] = 0;
10729 if ((p = strrchr(path,
'/')) != NULL) {
10732 len = strlen(path);
10736 sizeof(path) - len,
10742 mg_cry(conn,
"Bad SSI #include: [%s]", tag);
10747 mg_cry(conn,
"SSI #include path length overflow: [%s]", tag);
10753 "Cannot open SSI #include: [%s]: fopen(%s): %s",
10771 #if !defined(NO_POPEN) 10775 char cmd[1024] =
"";
10778 if (sscanf(tag,
" \"%1023[^\"]\"", cmd) != 1) {
10779 mg_cry(conn,
"Bad SSI #exec: [%s]", tag);
10782 if ((file.access.fp = popen(cmd,
"r")) == NULL) {
10783 mg_cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
10786 pclose(file.access.fp);
10796 if (filep == NULL) {
10799 if ((filep->access.membuf != NULL) && (offset >= 0)
10800 && (((
unsigned int)(offset)) < filep->stat.size)) {
10801 return ((
const unsigned char *)filep->access.membuf)[offset];
10802 }
else if (filep->access.fp != NULL) {
10803 return fgetc(filep->access.fp);
10813 struct mg_file *filep,
10817 int ch, offset, len, in_tag, in_ssi_tag;
10819 if (include_level > 10) {
10820 mg_cry(conn,
"SSI #include level is too deep (%s)", path);
10824 in_tag = in_ssi_tag = len = offset = 0;
10827 while ((ch =
mg_fgetc(filep, offset++)) != EOF) {
10840 if (!memcmp(buf + 5,
"include", 7)) {
10842 #if !defined(NO_POPEN) 10843 }
else if (!memcmp(buf + 5,
"exec", 4)) {
10854 in_ssi_tag = in_tag = 0;
10866 buf[len++] = (char)(ch & 0xff);
10868 if ((len == 5) && !memcmp(buf,
"<!--#", 5)) {
10873 if ((len + 2) > (int)
sizeof(buf)) {
10875 mg_cry(conn,
"%s: tag is too large", path);
10895 buf[len++] = (char)(ch & 0xff);
10897 if (len == (
int)
sizeof(buf)) {
10915 struct mg_file *filep)
10918 time_t curtime = time(NULL);
10919 const char *cors1, *cors2, *cors3;
10921 if ((conn == NULL) || (path == NULL) || (filep == NULL)) {
10927 cors1 =
"Access-Control-Allow-Origin: ";
10931 cors1 = cors2 = cors3 =
"";
10939 "Error: Cannot read file\nfopen(%s): %s",
10943 conn->must_close = 1;
10946 mg_printf(conn,
"HTTP/1.1 200 OK\r\n");
10952 "Content-Type: text/html\r\n" 10953 "Connection: %s\r\n\r\n",
10965 #if !defined(NO_FILES) 10970 time_t curtime = time(NULL);
10976 conn->status_code = 200;
10977 conn->must_close = 1;
10984 "HTTP/1.1 200 OK\r\n" 10986 "Connection: %s\r\n" 10987 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, " 10988 "PROPFIND, MKCOL\r\n" 11001 struct mg_file_stat *filep)
11005 if ((conn == NULL) || (uri == NULL) || (filep == NULL)) {
11012 "<d:href>%s</d:href>" 11015 "<d:resourcetype>%s</d:resourcetype>" 11016 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>" 11017 "<d:getlastmodified>%s</d:getlastmodified>" 11019 "<d:status>HTTP/1.1 200 OK</d:status>" 11023 filep->is_directory ?
"<d:collection/>" :
"",
11032 char href[PATH_MAX];
11035 struct mg_connection *conn = (
struct mg_connection *)data;
11036 if (!de || !conn) {
11044 conn->request_info.local_uri,
11048 size_t href_encoded_size;
11049 char *href_encoded;
11051 href_encoded_size = PATH_MAX * 3;
11052 href_encoded = (
char *)
mg_malloc(href_encoded_size);
11053 if (href_encoded == NULL) {
11068 struct mg_file_stat *filep)
11072 time_t curtime = time(NULL);
11076 if (!conn || !path || !filep || !conn->ctx) {
11080 conn->must_close = 1;
11081 conn->status_code = 207;
11083 "HTTP/1.1 207 Multi-Status\r\n" 11089 "Connection: %s\r\n" 11090 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
11094 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 11095 "<d:multistatus xmlns:d='DAV:'>\n");
11098 print_props(conn, conn->request_info.local_uri, filep);
11102 if (filep && filep->is_directory
11104 && ((depth == NULL) || (strcmp(depth,
"0") != 0))) {
11108 mg_printf(conn,
"%s\n",
"</d:multistatus>");
11116 (
void)pthread_mutex_lock(&conn->mutex);
11124 (
void)pthread_mutex_unlock(&conn->mutex);
11132 (
void)pthread_mutex_lock(&ctx->nonce_mutex);
11140 (
void)pthread_mutex_unlock(&ctx->nonce_mutex);
11144 #if defined(USE_TIMERS) 11145 #define TIMER_API static 11146 #include "timer.inl" 11150 #include "mod_lua.inl" 11154 #include "mod_duktape.inl" 11157 #if defined(USE_WEBSOCKET) 11159 #if !defined(NO_SSL_DL) 11160 #define SHA_API static 11165 send_websocket_handshake(
struct mg_connection *conn,
const char *websock_key)
11167 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
11168 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
11173 mg_snprintf(conn, &truncated, buf,
sizeof(buf),
"%s%s", websock_key, magic);
11175 conn->must_close = 1;
11180 SHA1_Update(&sha_ctx, (
unsigned char *)buf, (uint32_t)strlen(buf));
11182 base64_encode((
unsigned char *)sha,
sizeof(sha), b64_sha);
11184 "HTTP/1.1 101 Switching Protocols\r\n" 11185 "Upgrade: websocket\r\n" 11186 "Connection: Upgrade\r\n" 11187 "Sec-WebSocket-Accept: %s\r\n",
11189 if (conn->request_info.acceptedWebSocketSubprotocol) {
11191 "Sec-WebSocket-Protocol: %s\r\n\r\n",
11192 conn->request_info.acceptedWebSocketSubprotocol);
11202 read_websocket(
struct mg_connection *conn,
11204 void *callback_data)
11210 unsigned char *buf = (
unsigned char *)conn->buf + conn->request_len;
11211 int n, error, exit_by_callback;
11217 size_t i, len, mask_len = 0, header_len, body_len;
11218 uint64_t data_len = 0;
11223 unsigned char mask[4];
11229 unsigned char mem[4096];
11231 double timeout = -1.0;
11233 if (conn->ctx->config[WEBSOCKET_TIMEOUT]) {
11234 timeout = atoi(conn->ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
11240 conn->in_websocket_handling = 1;
11245 while (!conn->ctx->stop_flag && !conn->must_close) {
11247 assert(conn->data_len >= conn->request_len);
11248 if ((body_len = (
size_t)(conn->data_len - conn->request_len)) >= 2) {
11249 len = buf[1] & 127;
11250 mask_len = (buf[1] & 128) ? 4 : 0;
11251 if ((len < 126) && (body_len >= mask_len)) {
11254 header_len = 2 + mask_len;
11255 }
else if ((len == 126) && (body_len >= (4 + mask_len))) {
11257 header_len = 4 + mask_len;
11258 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
11259 }
else if (body_len >= (10 + mask_len)) {
11262 memcpy(&l1, &buf[2], 4);
11263 memcpy(&l2, &buf[6], 4);
11264 header_len = 10 + mask_len;
11265 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
11267 if (data_len > (uint64_t)0x7FFF0000ul) {
11269 mg_cry(conn,
"websocket out of memory; closing connection");
11275 if ((header_len > 0) && (body_len >= header_len)) {
11277 unsigned char *data = mem;
11279 if ((
size_t)data_len > (
size_t)
sizeof(mem)) {
11281 (
unsigned char *)
mg_malloc_ctx((
size_t)data_len, conn->ctx);
11282 if (data == NULL) {
11285 mg_cry(conn,
"websocket out of memory; closing connection");
11291 if (mask_len > 0) {
11292 memcpy(mask, buf + header_len - mask_len,
sizeof(mask));
11294 memset(mask, 0,
sizeof(mask));
11299 assert(body_len >= header_len);
11300 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
11303 len = body_len - header_len;
11304 memcpy(data, buf + header_len, len);
11306 while ((uint64_t)len < data_len) {
11309 (
char *)(data + len),
11310 (
int)(data_len - len),
11315 }
else if (n > 0) {
11323 mg_cry(conn,
"Websocket pull failed; closing connection");
11330 conn->data_len = conn->request_len;
11340 len = (size_t)data_len + header_len;
11345 memcpy(data, buf + header_len, (
size_t)data_len);
11348 memmove(buf, buf + len, body_len - len);
11351 conn->data_len -= (int)len;
11355 if (mask_len > 0) {
11356 for (i = 0; i < (size_t)data_len; i++) {
11357 data[i] ^= mask[i & 3];
11363 exit_by_callback = 0;
11364 if ((ws_data_handler != NULL)
11365 && !ws_data_handler(conn,
11370 exit_by_callback = 1;
11377 if (exit_by_callback
11389 conn->buf + conn->data_len,
11390 conn->buf_size - conn->data_len,
11397 conn->data_len +=
n;
11406 conn->in_websocket_handling = 0;
11411 mg_websocket_write_exec(
struct mg_connection *conn,
11415 uint32_t masking_key)
11417 unsigned char header[14];
11418 size_t headerLen = 1;
11422 #if defined(__GNUC__) || defined(__MINGW32__) 11424 #pragma GCC diagnostic push 11425 #pragma GCC diagnostic ignored "-Wconversion" 11428 header[0] = 0x80u | (
unsigned char)((
unsigned)opcode & 0xf);
11430 #if defined(__GNUC__) || defined(__MINGW32__) 11431 #pragma GCC diagnostic pop 11435 if (dataLen < 126) {
11437 header[1] = (
unsigned char)dataLen;
11439 }
else if (dataLen <= 0xFFFF) {
11441 uint16_t len = htons((uint16_t)dataLen);
11443 memcpy(header + 2, &len, 2);
11447 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
11448 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
11450 memcpy(header + 2, &len1, 4);
11451 memcpy(header + 6, &len2, 4);
11458 memcpy(header + headerLen, &masking_key, 4);
11476 retval =
mg_write(conn, header, headerLen);
11478 retval =
mg_write(conn, data, dataLen);
11493 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
11498 mask_data(
const char *in,
size_t in_len, uint32_t masking_key,
char *out)
11503 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
11505 while (i < (in_len - 3)) {
11506 *(uint32_t *)(
void *)(out + i) =
11507 *(uint32_t *)(
void *)(in + i) ^ masking_key;
11513 while (i < in_len) {
11514 *(uint8_t *)(
void *)(out + i) =
11515 *(uint8_t *)(
void *)(in + i)
11516 ^ *(((uint8_t *)&masking_key) + (i % 4));
11530 char *masked_data =
11532 uint32_t masking_key = (uint32_t)
get_random();
11534 if (masked_data == NULL) {
11537 "Cannot allocate buffer for masked websocket response: " 11542 mask_data(data, dataLen, masking_key, masked_data);
11544 retval = mg_websocket_write_exec(
11545 conn, opcode, masked_data, dataLen, masking_key);
11553 handle_websocket_request(
struct mg_connection *conn,
11555 int is_callback_resource,
11563 const char *websock_key =
mg_get_header(conn,
"Sec-WebSocket-Key");
11564 const char *version =
mg_get_header(conn,
"Sec-WebSocket-Version");
11565 int lua_websock = 0;
11567 #if !defined(USE_LUA) 11573 if (!websock_key) {
11580 const char *key1 =
mg_get_header(conn,
"Sec-WebSocket-Key1");
11581 const char *key2 =
mg_get_header(conn,
"Sec-WebSocket-Key2");
11584 if ((key1 != NULL) && (key2 != NULL)) {
11586 conn->content_len = 8;
11587 if (8 ==
mg_read(conn, key3, 8)) {
11592 "Protocol upgrade to RFC 6455 required");
11603 if ((version == NULL) || (strcmp(version,
"13") != 0)) {
11613 if (is_callback_resource) {
11615 const char *protocols[64];
11616 int nbSubprotocolHeader = get_req_headers(&conn->request_info,
11617 "Sec-WebSocket-Protocol",
11620 if ((nbSubprotocolHeader > 0) && subprotocols) {
11624 const char *
sep, *curSubProtocol,
11625 *acceptedWebSocketSubprotocol = NULL;
11630 const char *protocol = protocols[
cnt];
11633 sep = strchr(protocol,
',');
11634 curSubProtocol = protocol;
11635 len = sep ? (
unsigned long)(sep - protocol)
11636 : (
unsigned long)strlen(protocol);
11637 while (sep && isspace(*++sep))
11644 && (strncmp(curSubProtocol,
11647 acceptedWebSocketSubprotocol =
11652 }
while (sep && !acceptedWebSocketSubprotocol);
11653 }
while (++cnt < nbSubprotocolHeader
11654 && !acceptedWebSocketSubprotocol);
11656 conn->request_info.acceptedWebSocketSubprotocol =
11657 acceptedWebSocketSubprotocol;
11658 }
else if (nbSubprotocolHeader > 0) {
11660 const char *protocol = protocols[0];
11665 const char *
sep = strrchr(protocol,
',');
11668 conn->request_info.acceptedWebSocketSubprotocol = protocol;
11678 while (isspace(*++sep)) {
11681 conn->request_info.acceptedWebSocketSubprotocol =
sep;
11685 if ((ws_connect_handler != NULL)
11686 && (ws_connect_handler(conn, cbData) != 0)) {
11695 #if defined(USE_LUA) 11699 if (conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
11701 match_prefix(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS],
11703 conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
11709 conn->lua_websocket_state = lua_websocket_new(path, conn);
11710 if (!conn->lua_websocket_state) {
11719 if (!is_callback_resource && !lua_websock) {
11729 if (!send_websocket_handshake(conn, websock_key)) {
11735 if (is_callback_resource) {
11736 if (ws_ready_handler != NULL) {
11737 ws_ready_handler(conn, cbData);
11739 #if defined(USE_LUA) 11740 }
else if (lua_websock) {
11741 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
11749 if (is_callback_resource) {
11750 read_websocket(conn, ws_data_handler, cbData);
11751 #if defined(USE_LUA) 11752 }
else if (lua_websock) {
11753 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
11758 if (ws_close_handler) {
11759 ws_close_handler(conn, cbData);
11767 const char *upgrade, *connection;
11776 if (upgrade == NULL) {
11786 if (connection == NULL) {
11808 return (n >= 0) && (n <= 255);
11817 if (((sscanf(spec,
"%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5)
11818 || (sscanf(spec,
"%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4))
11822 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
11824 *mask = slash ? (0xffffffffU << (32 -
slash)) : 0;
11835 struct vec vec, val;
11836 uint32_t net, mask;
11840 while ((spec =
next_option(spec, &vec, &val)) != NULL) {
11842 if ((val.ptr == NULL) || (sscanf(val.ptr,
"%lf%c", &v, &mult) < 1)
11843 || (v < 0) || ((
lowercase(&mult) !=
'k')
11844 && (
lowercase(&mult) !=
'm') && (mult !=
','))) {
11849 : ((
lowercase(&mult) ==
'm') ? 1048576 : 1);
11850 if (vec.len == 1 && vec.ptr[0] ==
'*') {
11852 }
else if (
parse_net(vec.ptr, &net, &mask) > 0) {
11853 if ((remote_ip & mask) == net) {
11871 return ntohl(*(
const uint32_t *)&conn->client.rsa.sin.sin_addr);
11879 #if defined(MG_LEGACY_INTERFACE) 11885 struct mg_upload_user_data {
11886 struct mg_connection *conn;
11887 const char *destination_dir;
11888 int num_uploaded_files;
11894 mg_upload_field_found(
const char *key,
11895 const char *filename,
11901 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
11905 mg_cry(fud->conn,
"%s: No filename set", __func__);
11913 fud->destination_dir,
11916 mg_cry(fud->conn,
"%s: File path too long", __func__);
11925 mg_upload_field_get(
const char *key,
11942 mg_upload_field_stored(
const char *path,
long long file_size,
void *user_data)
11944 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
11947 fud->num_uploaded_files++;
11948 fud->conn->ctx->callbacks.upload(fud->conn, path);
11956 mg_upload(
struct mg_connection *conn,
const char *destination_dir)
11958 struct mg_upload_user_data fud = {conn, destination_dir, 0};
11960 mg_upload_field_get,
11961 mg_upload_field_stored,
11969 mg_cry(conn,
"%s: Error while parsing the request", __func__);
11972 return fud.num_uploaded_files;
11983 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
11984 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
11995 const char *host_header;
11999 hostlen =
sizeof(host);
12000 if (host_header != NULL) {
12004 host[hostlen - 1] =
'\0';
12005 pos = strchr(host,
':');
12020 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
12022 #
if defined(USE_IPV6)
12023 (conn->ctx->listening_sockets[ssl_index].lsa.sa.sa_family
12025 ? (
int)ntohs(conn->ctx->listening_sockets[ssl_index]
12026 .lsa.sin6.sin6_port)
12029 (
int)ntohs(conn->ctx->listening_sockets[ssl_index]
12030 .lsa.sin.sin_port),
12031 conn->request_info.local_uri,
12032 (conn->request_info.query_string == NULL) ?
"" :
"?",
12033 (conn->request_info.query_string == NULL)
12035 : conn->request_info.query_string);
12044 int is_delete_request,
12054 struct mg_handler_info *tmp_rh, **lastref;
12055 size_t urilen = strlen(uri);
12064 if (handler != NULL) {
12067 if (!is_delete_request && (connect_handler == NULL)
12068 && (ready_handler == NULL) && (data_handler == NULL)
12069 && (close_handler == NULL)) {
12072 if (auth_handler != NULL) {
12081 if ((connect_handler != NULL) || (ready_handler != NULL)
12082 || (data_handler != NULL) || (close_handler != NULL)) {
12085 if (!is_delete_request && (handler == NULL)) {
12088 if (auth_handler != NULL) {
12096 if (handler != NULL) {
12099 if ((connect_handler != NULL) || (ready_handler != NULL)
12100 || (data_handler != NULL) || (close_handler != NULL)) {
12103 if (!is_delete_request && (auth_handler == NULL)) {
12115 lastref = &(ctx->handlers);
12116 for (tmp_rh = ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
12117 if (tmp_rh->handler_type == handler_type) {
12118 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
12119 if (!is_delete_request) {
12122 tmp_rh->handler = handler;
12124 tmp_rh->subprotocols = subprotocols;
12125 tmp_rh->connect_handler = connect_handler;
12126 tmp_rh->ready_handler = ready_handler;
12127 tmp_rh->data_handler = data_handler;
12128 tmp_rh->close_handler = close_handler;
12130 tmp_rh->auth_handler = auth_handler;
12132 tmp_rh->cbdata = cbdata;
12135 *lastref = tmp_rh->next;
12143 lastref = &(tmp_rh->next);
12146 if (is_delete_request) {
12154 (
struct mg_handler_info *)
mg_calloc_ctx(
sizeof(
struct mg_handler_info),
12157 if (tmp_rh == NULL) {
12159 mg_cry(
fc(ctx),
"%s",
"Cannot create new request handler struct, OOM");
12163 if (!tmp_rh->uri) {
12166 mg_cry(
fc(ctx),
"%s",
"Cannot create new request handler struct, OOM");
12169 tmp_rh->uri_len = urilen;
12171 tmp_rh->handler = handler;
12173 tmp_rh->subprotocols = subprotocols;
12174 tmp_rh->connect_handler = connect_handler;
12175 tmp_rh->ready_handler = ready_handler;
12176 tmp_rh->data_handler = data_handler;
12177 tmp_rh->close_handler = close_handler;
12179 tmp_rh->auth_handler = auth_handler;
12181 tmp_rh->cbdata = cbdata;
12182 tmp_rh->handler_type = handler_type;
12183 tmp_rh->next = NULL;
12233 struct mg_context *ctx,
12242 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
12243 && (data_handler == NULL)
12244 && (close_handler == NULL);
12294 if (request_info) {
12295 const char *uri = request_info->
local_uri;
12296 size_t urilen = strlen(uri);
12297 struct mg_handler_info *tmp_rh;
12299 if (!conn || !conn->ctx) {
12306 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
12307 tmp_rh = tmp_rh->next) {
12308 if (tmp_rh->handler_type == handler_type) {
12309 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
12311 *subprotocols = tmp_rh->subprotocols;
12312 *connect_handler = tmp_rh->connect_handler;
12313 *ready_handler = tmp_rh->ready_handler;
12314 *data_handler = tmp_rh->data_handler;
12315 *close_handler = tmp_rh->close_handler;
12317 *handler = tmp_rh->handler;
12319 *auth_handler = tmp_rh->auth_handler;
12321 *cbdata = tmp_rh->cbdata;
12329 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
12330 tmp_rh = tmp_rh->next) {
12331 if (tmp_rh->handler_type == handler_type) {
12332 if ((tmp_rh->uri_len < urilen) && (uri[tmp_rh->uri_len] ==
'/')
12333 && (memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0)) {
12335 *subprotocols = tmp_rh->subprotocols;
12336 *connect_handler = tmp_rh->connect_handler;
12337 *ready_handler = tmp_rh->ready_handler;
12338 *data_handler = tmp_rh->data_handler;
12339 *close_handler = tmp_rh->close_handler;
12341 *handler = tmp_rh->handler;
12343 *auth_handler = tmp_rh->auth_handler;
12345 *cbdata = tmp_rh->cbdata;
12353 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
12354 tmp_rh = tmp_rh->next) {
12355 if (tmp_rh->handler_type == handler_type) {
12356 if (
match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
12358 *subprotocols = tmp_rh->subprotocols;
12359 *connect_handler = tmp_rh->connect_handler;
12360 *ready_handler = tmp_rh->ready_handler;
12361 *data_handler = tmp_rh->data_handler;
12362 *close_handler = tmp_rh->close_handler;
12364 *handler = tmp_rh->handler;
12366 *auth_handler = tmp_rh->auth_handler;
12368 *cbdata = tmp_rh->cbdata;
12396 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE) 12398 deprecated_websocket_connect_wrapper(
const struct mg_connection *conn,
12402 if (pcallbacks->websocket_connect) {
12403 return pcallbacks->websocket_connect(conn);
12411 deprecated_websocket_ready_wrapper(
struct mg_connection *conn,
void *cbdata)
12414 if (pcallbacks->websocket_ready) {
12415 pcallbacks->websocket_ready(conn);
12421 deprecated_websocket_data_wrapper(
struct mg_connection *conn,
12428 if (pcallbacks->websocket_data) {
12429 return pcallbacks->websocket_data(conn, bits, data, len);
12445 char path[PATH_MAX];
12446 int uri_len, ssl_index;
12447 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
12448 is_put_or_delete_request = 0, is_callback_resource = 0;
12457 void *callback_data = NULL;
12459 void *auth_callback_data = NULL;
12461 time_t curtime = time(NULL);
12468 if ((conn->request_info.query_string = strchr(ri->
request_uri,
'?'))
12470 *((
char *)conn->request_info.query_string++) =
'\0';
12474 if (!conn->client.is_ssl && conn->client.ssl_redir) {
12476 if (ssl_index >= 0) {
12484 "Error: SSL forward not configured properly");
12485 mg_cry(conn,
"Can not redirect to SSL, no SSL port available");
12511 if (conn->ctx->callbacks.begin_request != NULL) {
12515 i = conn->ctx->callbacks.begin_request(conn);
12519 conn->status_code = i;
12522 }
else if (i == 0) {
12540 const char *cors_meth_cfg =
12542 const char *cors_orig_cfg =
12544 const char *cors_origin =
12548 "Access-Control-Request-Method");
12553 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
12554 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
12555 && (cors_origin != NULL) && (cors_acrm != NULL)) {
12559 const char *cors_acrh =
12562 "Access-Control-Request-Headers");
12566 "HTTP/1.1 200 OK\r\n" 12568 "Access-Control-Allow-Origin: %s\r\n" 12569 "Access-Control-Allow-Methods: %s\r\n" 12570 "Content-Length: 0\r\n" 12571 "Connection: %s\r\n",
12574 ((cors_meth_cfg[0] ==
'*') ? cors_acrm : cors_meth_cfg),
12577 if (cors_acrh != NULL) {
12579 const char *cors_hdr_cfg =
12582 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
12589 "Access-Control-Allow-Headers: %s\r\n",
12590 ((cors_hdr_cfg[0] ==
'*') ? cors_acrh
12594 mg_printf(conn,
"Access-Control-Max-Age: 60\r\n");
12607 #if defined(USE_WEBSOCKET) 12617 &ws_connect_handler,
12627 is_callback_resource = 1;
12628 is_script_resource = 1;
12631 no_callback_resource:
12635 is_callback_resource = 0;
12641 &is_script_resource,
12642 &is_websocket_request,
12643 &is_put_or_delete_request);
12657 &auth_callback_data)) {
12658 if (!auth_handler(conn, auth_callback_data)) {
12661 }
else if (is_put_or_delete_request && !is_script_resource
12662 && !is_callback_resource) {
12665 #if defined(NO_FILES) 12674 "%s method not allowed",
12675 conn->request_info.request_method);
12679 #if !defined(NO_FILES) 12702 if (is_callback_resource) {
12703 if (!is_websocket_request) {
12704 i = callback_handler(conn, callback_data);
12709 conn->status_code = i;
12734 &is_script_resource,
12735 &is_websocket_request,
12736 &is_put_or_delete_request);
12737 callback_handler = NULL;
12748 goto no_callback_resource;
12751 #if defined(USE_WEBSOCKET) 12752 handle_websocket_request(conn,
12754 is_callback_resource,
12756 ws_connect_handler,
12767 #if defined(USE_WEBSOCKET) 12768 if (is_websocket_request) {
12769 if (is_script_resource) {
12773 handle_websocket_request(conn,
12781 &conn->ctx->callbacks);
12787 #if defined(MG_LEGACY_INTERFACE) 12788 handle_websocket_request(
12791 !is_script_resource ,
12793 deprecated_websocket_connect_wrapper,
12794 deprecated_websocket_ready_wrapper,
12795 deprecated_websocket_data_wrapper,
12797 &conn->ctx->callbacks);
12806 #if defined(NO_FILES) 12821 if (is_script_resource) {
12827 if (is_put_or_delete_request) {
12848 "%s method not allowed",
12849 conn->request_info.request_method);
12861 if (file.stat.is_directory && (uri_len > 0)
12862 && (ri->
local_uri[uri_len - 1] !=
'/')) {
12865 "HTTP/1.1 301 Moved Permanently\r\n" 12866 "Location: %s/\r\n" 12869 "Content-Length: 0\r\n" 12870 "Connection: %s\r\n",
12900 "%s method not allowed",
12901 conn->request_info.request_method);
12906 if (file.stat.is_directory) {
12917 "Error: Directory listing denied");
12937 struct mg_file *file)
12939 if (!conn || !conn->ctx) {
12945 }
else if (
match_prefix(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
12947 conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
12954 handle_lsp_request(conn, path, file, NULL);
12960 }
else if (
match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
12961 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
12968 mg_exec_lua_script(conn, path, NULL);
12974 #if defined(USE_DUKTAPE) 12975 }
else if (
match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
12977 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
12981 mg_exec_duktape_script(conn, path);
12987 #if !defined(NO_CGI) 13008 #if !defined(NO_CACHING) 13009 }
else if ((!conn->in_error_handler)
13028 for (i = 0; i < ctx->num_listening_sockets; i++) {
13032 mg_free(ctx->listening_sockets);
13033 ctx->listening_sockets = NULL;
13034 mg_free(ctx->listening_socket_fds);
13035 ctx->listening_socket_fds = NULL;
13056 unsigned int a,
b,
c,
d, port;
13059 #if defined(USE_IPV6) 13060 char buf[100] = {0};
13066 memset(so, 0,
sizeof(*so));
13067 so->lsa.sin.sin_family = AF_INET;
13075 if (sscanf(vec->ptr,
"%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
13078 so->lsa.sin.sin_addr.s_addr =
13079 htonl((a << 24) | (b << 16) | (c << 8) | d);
13080 so->lsa.sin.sin_port = htons((uint16_t)port);
13083 #if defined(USE_IPV6) 13084 }
else if (sscanf(vec->ptr,
"[%49[^]]]:%u%n", buf, &port, &len) == 2
13086 AF_INET6, buf, &so->lsa.sin6,
sizeof(so->lsa.sin6))) {
13090 so->lsa.sin6.sin6_port = htons((uint16_t)port);
13094 }
else if ((vec->ptr[0] ==
'+')
13095 && (sscanf(vec->ptr + 1,
"%u%n", &port, &len) == 1)) {
13101 #if defined(USE_IPV6) 13103 so->lsa.sin6.sin6_family = AF_INET6;
13104 so->lsa.sin6.sin6_port = htons((uint16_t)port);
13105 *ip_version = 4 + 6;
13108 so->lsa.sin.sin_port = htons((uint16_t)port);
13112 }
else if (sscanf(vec->ptr,
"%u%n", &port, &len) == 1) {
13114 so->lsa.sin.sin_port = htons((uint16_t)port);
13117 }
else if ((cb = strchr(vec->ptr,
':')) != NULL) {
13129 AF_INET, vec->ptr, &so->lsa.sin,
sizeof(so->lsa.sin))) {
13130 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
13132 so->lsa.sin.sin_family = AF_INET;
13133 so->lsa.sin.sin_port = htons((uint16_t)port);
13134 len += (int)(cb - vec->ptr) + 1;
13139 #if defined(USE_IPV6) 13143 sizeof(so->lsa.sin6))) {
13144 if (sscanf(cb + 1,
"%u%n", &port, &len) == 1) {
13146 so->lsa.sin6.sin6_family = AF_INET6;
13147 so->lsa.sin.sin_port = htons((uint16_t)port);
13148 len += (int)(cb - vec->ptr) + 1;
13164 if ((len < 0) && ((unsigned)len > (
unsigned)vec->len)) {
13168 ch = vec->ptr[len];
13169 so->is_ssl = (ch ==
's');
13170 so->ssl_redir = (ch ==
'r');
13174 && ((ch ==
'\0') || (ch ==
's') || (ch ==
'r') || (ch ==
','))) {
13189 #if defined(USE_IPV6) 13193 struct socket so, *ptr;
13195 struct pollfd *pfd;
13200 int portsTotal = 0;
13207 memset(&so, 0,
sizeof(so));
13208 memset(&usa, 0,
sizeof(usa));
13212 while ((list =
next_option(list, &vec, NULL)) != NULL) {
13218 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
13222 "[IP_ADDRESS:]PORT[s|r]");
13226 #if !defined(NO_SSL) 13227 if (so.is_ssl && ctx->ssl_ctx == NULL) {
13230 "Cannot add SSL socket (entry %i). Is -ssl_certificate " 13237 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
13240 mg_cry(
fc(ctx),
"cannot create socket (entry %i)", portsTotal);
13254 if (setsockopt(so.sock,
13256 SO_EXCLUSIVEADDRUSE,
13257 (SOCK_OPT_TYPE)&on,
13258 sizeof(on)) != 0) {
13262 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
13266 if (setsockopt(so.sock,
13269 (SOCK_OPT_TYPE)&on,
13270 sizeof(on)) != 0) {
13274 "cannot set socket option SO_REUSEADDR (entry %i)",
13279 if (ip_version > 4) {
13280 #if defined(USE_IPV6) 13281 if (ip_version == 6) {
13282 if (so.lsa.sa.sa_family == AF_INET6
13283 && setsockopt(so.sock,
13287 sizeof(off)) != 0) {
13291 "cannot set socket option IPV6_V6ONLY (entry %i)",
13296 mg_cry(
fc(ctx),
"IPv6 not available");
13303 if (so.lsa.sa.sa_family == AF_INET) {
13305 len =
sizeof(so.lsa.sin);
13306 if (bind(so.sock, &so.lsa.sa, len) != 0) {
13308 "cannot bind to %.*s: %d (%s)",
13318 #if defined(USE_IPV6) 13319 else if (so.lsa.sa.sa_family == AF_INET6) {
13321 len =
sizeof(so.lsa.sin6);
13322 if (bind(so.sock, &so.lsa.sa, len) != 0) {
13324 "cannot bind to IPv6 %.*s: %d (%s)",
13337 "cannot bind: address family not supported (entry %i)",
13347 "cannot listen to %.*s: %d (%s)",
13357 if ((getsockname(so.sock, &(usa.sa), &len) != 0)
13358 || (usa.sa.sa_family != so.lsa.sa.sa_family)) {
13360 int err = (int)
ERRNO;
13362 "call to getsockname failed %.*s: %d (%s)",
13373 #if defined(USE_IPV6) 13374 if (so.lsa.sa.sa_family == AF_INET6) {
13375 so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
13379 so.lsa.sin.sin_port = usa.sin.sin_port;
13382 if ((ptr = (
struct socket *)
13384 (ctx->num_listening_sockets + 1)
13385 *
sizeof(ctx->listening_sockets[0]),
13388 mg_cry(
fc(ctx),
"%s",
"Out of memory");
13394 if ((pfd = (
struct pollfd *)
13396 (ctx->num_listening_sockets + 1)
13397 *
sizeof(ctx->listening_socket_fds[0]),
13400 mg_cry(
fc(ctx),
"%s",
"Out of memory");
13408 ctx->listening_sockets = ptr;
13409 ctx->listening_sockets[ctx->num_listening_sockets] = so;
13410 ctx->listening_socket_fds = pfd;
13411 ctx->num_listening_sockets++;
13415 if (portsOk != portsTotal) {
13424 static const char *
13427 const char *header_value;
13429 if ((header_value =
mg_get_header(conn, header)) == NULL) {
13432 return header_value;
13445 const char *referer;
13446 const char *user_agent;
13450 if (!conn || !conn->ctx) {
13459 fi.access.fp = NULL;
13462 fi.access.fp = NULL;
13467 if ((fi.access.fp == NULL) && (conn->ctx->callbacks.log_access == NULL)) {
13471 tm = localtime(&conn->conn_birth_time);
13473 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z", tm);
13475 mg_strlcpy(date,
"01/Jan/1970:00:00:00 +0000",
sizeof(date));
13476 date[
sizeof(date) - 1] =
'\0';
13479 ri = &conn->request_info;
13483 user_agent =
header_val(conn,
"User-Agent");
13489 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
13491 (ri->remote_user == NULL) ?
"-" : ri->remote_user,
13493 ri->request_method ? ri->request_method :
"-",
13494 ri->request_uri ? ri->request_uri :
"-",
13495 ri->query_string ?
"?" :
"",
13496 ri->query_string ? ri->query_string :
"",
13499 conn->num_bytes_sent,
13503 if (conn->ctx->callbacks.log_access) {
13504 conn->ctx->callbacks.log_access(conn, buf);
13507 if (fi.access.fp) {
13509 flockfile(fi.access.fp);
13510 if (fprintf(fi.access.fp,
"%s\n", buf) < 1) {
13513 if (fflush(fi.access.fp) != 0) {
13516 funlockfile(fi.access.fp);
13522 "Error writing log file %s",
13536 uint32_t net, mask;
13543 allowed = (list == NULL) ?
'+' :
'-';
13545 while ((list =
next_option(list, &vec, NULL)) != NULL) {
13547 if ((flag !=
'+' && flag !=
'-')
13548 || (
parse_net(&vec.ptr[1], &net, &mask) == 0)) {
13550 "%s: subnet must be [+|-]x.x.x.x[/x]",
13555 if (net == (remote_ip & mask)) {
13560 return allowed ==
'+';
13566 #if !defined(_WIN32) 13578 if ((pw = getpwnam(uid)) == NULL) {
13579 mg_cry(
fc(ctx),
"%s: unknown user [%s]", __func__, uid);
13580 }
else if (setgid(pw->
pw_gid) == -1) {
13582 "%s: setgid(%s): %s",
13586 }
else if (setgroups(0, NULL)) {
13588 "%s: setgroups(): %s",
13591 }
else if (setuid(pw->
pw_uid) == -1) {
13593 "%s: setuid(%s): %s",
13612 struct mg_workerTLS *tls = (
struct mg_workerTLS *)key;
13616 if (tls->is_master == 2) {
13617 tls->is_master = -3;
13621 pthread_setspecific(sTlsKey, NULL);
13625 #if !defined(NO_SSL) 13628 ssl_use_pem_file(
struct mg_context *ctx,
const char *pem,
const char *chain);
13635 static int reload_lock = 0;
13636 static long int data_check = 0;
13637 volatile int *p_reload_lock = (
volatile int *)&reload_lock;
13639 struct stat cert_buf;
13643 int should_verify_peer;
13651 if (chain == NULL) {
13660 if (stat(pem, &cert_buf) != -1) {
13661 t = (
long int)cert_buf.st_mtime;
13664 if (data_check != t) {
13667 should_verify_peer = 0;
13671 should_verify_peer = 1;
13673 "optional") == 0) {
13674 should_verify_peer = 1;
13678 if (should_verify_peer) {
13685 "SSL_CTX_load_verify_locations error: %s " 13686 "ssl_verify_peer requires setting " 13687 "either ssl_ca_path or ssl_ca_file. Is any of them " 13699 *p_reload_lock = 0;
13703 while (*p_reload_lock) {
13710 #ifdef OPENSSL_API_1_1 13718 int (*func)(
SSL *),
13719 volatile int *stop_server)
13741 if (conn->ssl == NULL) {
13746 ret =
SSL_set_fd(conn->ssl, conn->client.sock);
13754 #ifndef OPENSSL_API_1_1 13763 for (i = 16; i <= 1024; i *= 2) {
13764 ret = func(conn->ssl);
13774 if (*stop_server) {
13803 #ifndef OPENSSL_API_1_1 13814 static const char *
13827 const char hexdigit[] =
"0123456789abcdef";
13829 if ((memlen <= 0) || (buflen <= 0)) {
13832 if (buflen < (3 * memlen)) {
13836 for (i = 0; i < memlen; i++) {
13838 buf[3 * i - 1] =
' ';
13840 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
13841 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
13843 buf[3 * memlen - 1] = 0;
13854 char str_subject[1024];
13855 char str_issuer[1024];
13856 char str_finger[1024];
13857 unsigned char buf[256];
13858 char *str_serial = NULL;
13861 unsigned char *tmp_buf;
13862 unsigned char *tmp_p;
13891 ? (
unsigned char *)
mg_malloc_ctx((
unsigned)ilen + 1, conn->ctx)
13897 tmp_buf, (
unsigned)ilen, buf, &ulen, digest, NULL)) {
13904 buf, (
int)ulen, str_finger, (
int)
sizeof(str_finger))) {
13910 if (conn->request_info.client_cert) {
13911 conn->request_info.client_cert->subject =
mg_strdup(str_subject);
13912 conn->request_info.client_cert->issuer =
mg_strdup(str_issuer);
13913 conn->request_info.client_cert->serial =
mg_strdup(str_serial);
13914 conn->request_info.client_cert->finger =
mg_strdup(str_finger);
13917 "Out of memory: Cannot allocate memory for client " 13931 #ifdef OPENSSL_API_1_1 13941 (
void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
13943 (
void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
13949 #if !defined(NO_SSL_DL) 13951 load_dll(
char *ebuf,
size_t ebuf_len,
const char *dll_name,
struct ssl_func *sw)
13958 struct ssl_func *fp;
13962 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
13967 "%s: cannot load %s",
13974 for (fp = sw; fp->name != NULL; fp++) {
13977 u.fp = (
void (*)(
void))dlsym(dll_handle, fp->name);
13982 u.p = dlsym(dll_handle, fp->name);
13984 if (u.fp == NULL) {
13990 "%s: %s: cannot find %s",
13996 size_t cur_len = strlen(ebuf);
14001 ebuf_len - cur_len - 3,
14006 strcat(ebuf,
"...");
14018 (
void)dlclose(dll_handle);
14032 #if defined(SSL_ALREADY_INITIALIZED) 14035 static int cryptolib_users = 0;
14042 #ifdef OPENSSL_API_1_1 14043 if (ebuf_len > 0) {
14047 #if !defined(NO_SSL_DL) 14048 if (!cryptolib_dll_handle) {
14050 if (!cryptolib_dll_handle) {
14064 if (ebuf_len > 0) {
14068 #if !defined(NO_SSL_DL) 14069 if (!cryptolib_dll_handle) {
14071 if (!cryptolib_dll_handle) {
14088 size =
sizeof(pthread_mutex_t) * ((
size_t)(i));
14091 ssl_mutexes = NULL;
14092 }
else if ((ssl_mutexes = (pthread_mutex_t *)
mg_malloc(size)) == NULL) {
14097 "%s: cannot allocate mutexes: %s",
14105 pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr);
14121 "%s: cannot open certificate file %s: %s",
14131 "%s: cannot open private key file %s: %s",
14140 "%s: certificate and private key do not match: %s",
14157 "%s: cannot use certificate chain file %s: %s",
14168 #ifdef OPENSSL_API_1_1 14169 static unsigned long 14173 if (version_id > 0)
14175 if (version_id > 1)
14177 if (version_id > 2)
14179 if (version_id > 3)
14188 if (version_id > 0)
14190 if (version_id > 1)
14192 if (version_id > 2)
14194 if (version_id > 3)
14227 int should_verify_peer;
14228 int peer_certificate_optional;
14229 const char *ca_path;
14230 const char *ca_file;
14231 int use_default_verify_paths;
14233 time_t now_rt = time(NULL);
14234 struct timespec now_mt;
14246 && ctx->callbacks.init_ssl == NULL) {
14250 if (chain == NULL) {
14253 if ((chain != NULL) && (*chain == 0)) {
14262 #if !defined(NO_SSL_DL) 14263 if (!ssllib_dll_handle) {
14265 if (!ssllib_dll_handle) {
14272 #ifdef OPENSSL_API_1_1 14274 OPENSSL_init_ssl(0, NULL);
14279 if ((ctx->ssl_ctx =
SSL_CTX_new(TLS_server_method())) == NULL) {
14304 #if !defined(NO_SSL_DL) 14324 (ctx->callbacks.init_ssl == NULL)
14326 : (ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data));
14331 if (callback_ret < 0) {
14332 mg_cry(
fc(ctx),
"SSL callback returned error: %i", callback_ret);
14335 if (callback_ret > 0) {
14345 clock_gettime(CLOCK_MONOTONIC, &now_mt);
14349 strlen(ctx->config[LISTENING_PORTS]));
14354 (
const unsigned char *)&ssl_context_id,
14355 sizeof(ssl_context_id));
14365 should_verify_peer = 0;
14366 peer_certificate_optional = 0;
14370 should_verify_peer = 1;
14371 peer_certificate_optional = 0;
14375 should_verify_peer = 1;
14376 peer_certificate_optional = 1;
14380 use_default_verify_paths =
14384 if (should_verify_peer) {
14390 "SSL_CTX_load_verify_locations error: %s " 14391 "ssl_verify_peer requires setting " 14392 "either ssl_ca_path or ssl_ca_file. Is any of them " 14399 if (peer_certificate_optional) {
14408 if (use_default_verify_paths
14411 "SSL_CTX_set_default_verify_paths error: %s",
14436 #ifdef OPENSSL_API_1_1 14464 pthread_mutex_destroy(&ssl_mutexes[i]);
14467 ssl_mutexes = NULL;
14480 if ((path != NULL) && !
mg_stat(
fc(ctx), path, &file.stat)) {
14481 mg_cry(
fc(ctx),
"Cannot open %s: %s", path, strerror(
ERRNO));
14493 return check_acl(ctx, (uint32_t)0x7f000001UL) != -1;
14503 conn->connection_type =
14506 conn->num_bytes_sent = conn->consumed_content = 0;
14508 conn->path_info = NULL;
14509 conn->status_code = -1;
14510 conn->content_len = -1;
14511 conn->is_chunked = 0;
14512 conn->must_close = 0;
14513 conn->request_len = 0;
14514 conn->throttle = 0;
14515 conn->data_len = 0;
14516 conn->chunk_remainder = 0;
14517 conn->accept_gzip = 0;
14519 conn->response_info.content_length = conn->request_info.content_length = -1;
14520 conn->response_info.http_version = conn->request_info.http_version = NULL;
14521 conn->response_info.num_headers = conn->request_info.num_headers = 0;
14522 conn->response_info.status_text = NULL;
14523 conn->response_info.status_code = 0;
14525 conn->request_info.remote_user = NULL;
14526 conn->request_info.request_method = NULL;
14527 conn->request_info.request_uri = NULL;
14528 conn->request_info.local_uri = NULL;
14530 #if defined(MG_LEGACY_INTERFACE) 14532 conn->request_info.uri = NULL;
14544 set_sock_timeout(SOCKET sock,
int milliseconds)
14546 int r0 = 0, r1, r2;
14551 DWORD tv = (DWORD)milliseconds;
14565 #if defined(TCP_USER_TIMEOUT) 14566 unsigned int uto = (
unsigned int)milliseconds;
14567 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (
const void *)&uto,
sizeof(uto));
14570 memset(&tv, 0,
sizeof(tv));
14571 tv.tv_sec = milliseconds / 1000;
14572 tv.tv_usec = (milliseconds * 1000) % 1000000;
14577 sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv,
sizeof(tv));
14579 sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv,
sizeof(tv));
14581 return r0 || r1 || r2;
14589 if (setsockopt(sock,
14592 (SOCK_OPT_TYPE)&nodelay_on,
14593 sizeof(nodelay_on)) != 0) {
14605 #if defined(_WIN32) 14609 struct linger linger;
14610 int error_code = 0;
14611 int linger_timeout = -2;
14612 socklen_t opt_len =
sizeof(error_code);
14627 #if defined(_WIN32) 14635 n =
pull_inner(NULL, conn, buf,
sizeof(buf), 1.0);
14644 if (linger_timeout >= 0) {
14647 linger.l_onoff = 1;
14649 #if defined(_MSC_VER) 14650 #pragma warning(push) 14651 #pragma warning(disable : 4244) 14653 #if defined(__GNUC__) || defined(__MINGW32__) 14654 #pragma GCC diagnostic push 14655 #pragma GCC diagnostic ignored "-Wconversion" 14661 linger.l_linger = (linger_timeout + 999) / 1000;
14663 #if defined(__GNUC__) || defined(__MINGW32__) 14664 #pragma GCC diagnostic pop 14666 #if defined(_MSC_VER) 14667 #pragma warning(pop) 14671 linger.l_onoff = 0;
14672 linger.l_linger = 0;
14675 if (linger_timeout < -1) {
14677 }
else if (getsockopt(conn->client.sock,
14680 (
char *)&error_code,
14686 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
14689 }
else if (error_code == ECONNRESET) {
14695 if (setsockopt(conn->client.sock,
14699 sizeof(linger)) != 0) {
14701 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
14718 #if defined(USE_SERVER_STATS) 14719 conn->conn_state = 6;
14722 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 14723 if (conn->lua_websocket_state) {
14724 lua_websocket_close(conn, conn->lua_websocket_state);
14725 conn->lua_websocket_state = NULL;
14732 conn->must_close = 1;
14735 if (conn->ctx->callbacks.connection_close != NULL) {
14737 conn->ctx->callbacks.connection_close(conn);
14747 #if defined(USE_SERVER_STATS) 14748 conn->conn_state = 7;
14752 if (conn->ssl != NULL) {
14759 #ifndef OPENSSL_API_1_1 14772 #if defined(USE_SERVER_STATS) 14773 conn->conn_state = 8;
14781 #if defined(USE_WEBSOCKET) 14782 struct mg_context *client_ctx = NULL;
14785 if ((conn == NULL) || (conn->ctx == NULL)) {
14789 #if defined(USE_WEBSOCKET) 14791 if (conn->in_websocket_handling) {
14793 conn->must_close = 1;
14802 client_ctx = conn->ctx;
14805 conn->ctx->stop_flag = 1;
14806 conn->must_close = 1;
14814 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
14815 if (client_ctx->worker_threadids[i] != 0) {
14825 if (conn->client_ssl_ctx != NULL) {
14830 #if defined(USE_WEBSOCKET) 14831 if (client_ctx != NULL) {
14833 mg_free(client_ctx->worker_threadids);
14835 (
void)pthread_mutex_destroy(&conn->mutex);
14852 static struct mg_connection *
14858 struct mg_connection *conn = NULL;
14861 struct sockaddr *psa;
14864 unsigned max_req_size =
14868 size_t conn_size = ((
sizeof(
struct mg_connection) + 7) >> 3) << 3;
14869 size_t ctx_size = ((
sizeof(
struct mg_context) + 7) >> 3) << 3;
14872 conn_size + ctx_size
14876 if (conn == NULL) {
14886 conn->ctx = (
struct mg_context *)(((
char *)conn) + conn_size);
14887 conn->buf = (((
char *)conn) + conn_size + ctx_size);
14888 conn->buf_size = (int)max_req_size;
14892 client_options->
host,
14893 client_options->
port,
14906 #ifdef OPENSSL_API_1_1 14908 && (conn->client_ssl_ctx =
SSL_CTX_new(TLS_client_method())) == NULL) {
14913 "SSL_CTX_new error");
14926 "SSL_CTX_new error");
14936 len = (sa.sa.sa_family == AF_INET) ?
sizeof(conn->client.rsa.sin)
14937 :
sizeof(conn->client.rsa.sin6);
14938 psa = (sa.sa.sa_family == AF_INET)
14939 ? (
struct sockaddr *)&(conn->client.rsa.sin)
14940 : (
struct sockaddr *)&(conn->client.rsa.sin6);
14942 len =
sizeof(conn->client.rsa.sin);
14943 psa = (
struct sockaddr *)&(conn->client.rsa.sin);
14946 conn->client.sock = sock;
14947 conn->client.lsa = sa;
14949 if (getsockname(sock, psa, &len) != 0) {
14950 mg_cry(conn,
"%s: getsockname() failed: %s", __func__, strerror(
ERRNO));
14953 conn->client.is_ssl = use_ssl ? 1 : 0;
14954 (
void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
14975 "Can not use SSL client certificate");
14993 conn->client_ssl_ctx,
14995 &(conn->ctx->stop_flag))) {
15000 "SSL connection error");
15020 char *error_buffer,
15021 size_t error_buffer_size)
15026 error_buffer_size);
15030 struct mg_connection *
15034 char *error_buffer,
15035 size_t error_buffer_size)
15038 memset(&opts, 0,
sizeof(opts));
15044 error_buffer_size);
15048 static const struct {
15053 {
"https://", 8, 443},
15055 {
"wss://", 6, 443},
15069 const char *hostend, *portbegin;
15071 unsigned long port;
15077 if ((uri[0] ==
'*') && (uri[1] ==
'\0')) {
15088 for (i = 0; uri[i] != 0; i++) {
15093 if (uri[i] > 126) {
15116 if (uri[0] ==
'/') {
15139 port = strtoul(portbegin + 1, &portend, 10);
15140 if ((portend != hostend) || (port <= 0) || !
is_valid_port(port)) {
15153 static const char *
15156 const char *server_domain;
15157 size_t server_domain_len;
15158 size_t request_domain_len = 0;
15159 unsigned long port = 0;
15160 int i, auth_domain_check_enabled;
15161 const char *hostbegin = NULL;
15162 const char *hostend = NULL;
15163 const char *portbegin;
15166 auth_domain_check_enabled =
15169 if (!auth_domain_check_enabled) {
15174 if (!server_domain) {
15177 server_domain_len = strlen(server_domain);
15178 if (!server_domain_len) {
15190 hostend = strchr(hostbegin,
'/');
15194 portbegin = strchr(hostbegin,
':');
15195 if ((!portbegin) || (portbegin > hostend)) {
15197 request_domain_len = (size_t)(hostend - hostbegin);
15199 port = strtoul(portbegin + 1, &portend, 10);
15200 if ((portend != hostend) || (port <= 0)
15204 request_domain_len = (size_t)(portbegin - hostbegin);
15218 #if defined(USE_IPV6) 15219 if (conn->client.lsa.sa.sa_family == AF_INET6) {
15220 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
15227 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
15241 if (auth_domain_check_enabled) {
15242 if ((request_domain_len == server_domain_len)
15243 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
15246 if (request_domain_len < (server_domain_len + 2)) {
15256 if (hostbegin[request_domain_len - server_domain_len - 1] !=
'.') {
15262 if (0 != memcmp(server_domain,
15263 hostbegin + request_domain_len - server_domain_len,
15264 server_domain_len)) {
15277 get_message(
struct mg_connection *conn,
char *ebuf,
size_t ebuf_len,
int *err)
15279 if (ebuf_len > 0) {
15298 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
15300 conn->request_len =
15301 read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
15304 if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) {
15310 "Invalid message size");
15315 if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) {
15321 "Message too large");
15326 if (conn->request_len <= 0) {
15327 if (conn->data_len > 0) {
15333 "Malformed message");
15337 conn->must_close = 1;
15343 "No data received");
15353 get_request(
struct mg_connection *conn,
char *ebuf,
size_t ebuf_len,
int *err)
15373 if ((cl =
get_header(conn->request_info.http_headers,
15374 conn->request_info.num_headers,
15375 "Content-Length")) != NULL) {
15377 char *endptr = NULL;
15378 conn->content_len = strtoll(cl, &endptr, 10);
15379 if (endptr == cl) {
15390 conn->request_info.content_length = conn->content_len;
15391 }
else if ((cl =
get_header(conn->request_info.http_headers,
15392 conn->request_info.num_headers,
15393 "Transfer-Encoding")) != NULL
15395 conn->is_chunked = 1;
15396 conn->content_len = -1;
15398 ->request_has_body) {
15400 conn->content_len = -1;
15403 conn->content_len = 0;
15413 get_response(
struct mg_connection *conn,
char *ebuf,
size_t ebuf_len,
int *err)
15433 if ((cl =
get_header(conn->response_info.http_headers,
15434 conn->response_info.num_headers,
15435 "Content-Length")) != NULL) {
15437 char *endptr = NULL;
15438 conn->content_len = strtoll(cl, &endptr, 10);
15439 if (endptr == cl) {
15450 conn->response_info.content_length = conn->content_len;
15453 conn->request_info.content_length = conn->content_len;
15455 }
else if ((cl =
get_header(conn->response_info.http_headers,
15456 conn->response_info.num_headers,
15457 "Transfer-Encoding")) != NULL
15459 conn->is_chunked = 1;
15460 conn->content_len = -1;
15462 conn->content_len = -1;
15478 struct mg_context *octx;
15479 struct mg_context rctx;
15481 if (ebuf_len > 0) {
15491 "Parameter error");
15497 rctx = *(conn->ctx);
15499 if (timeout >= 0) {
15500 mg_snprintf(conn, NULL, txt,
sizeof(txt),
"%i", timeout);
15513 #if defined(MG_LEGACY_INTERFACE) 15516 conn->request_info.uri = conn->request_info.request_uri;
15518 conn->request_info.local_uri = conn->request_info.request_uri;
15522 return (ret == 0) ? -1 : +1;
15526 struct mg_connection *
15535 struct mg_connection *conn;
15540 if (ebuf_len > 0) {
15549 if (conn != NULL) {
15557 "Error sending request");
15561 #if defined(MG_LEGACY_INTERFACE) 15564 conn->request_info.uri = conn->request_info.request_uri;
15566 conn->request_info.local_uri = conn->request_info.request_uri;
15571 if ((ebuf[0] !=
'\0') && (conn != NULL)) {
15581 struct websocket_client_thread_data {
15582 struct mg_connection *conn;
15585 void *callback_data;
15589 #if defined(USE_WEBSOCKET) 15591 static unsigned __stdcall websocket_client_thread(
void *data)
15594 websocket_client_thread(
void *data)
15597 struct websocket_client_thread_data *cdata =
15598 (
struct websocket_client_thread_data *)data;
15602 if (cdata->conn->ctx) {
15603 if (cdata->conn->ctx->callbacks.init_thread) {
15606 cdata->conn->ctx->callbacks.init_thread(cdata->conn->ctx, 3);
15610 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
15612 DEBUG_TRACE(
"%s",
"Websocket client thread exited\n");
15614 if (cdata->close_handler != NULL) {
15615 cdata->close_handler(cdata->conn, cdata->callback_data);
15620 cdata->conn->ctx->stop_flag = 2;
15633 struct mg_connection *
15637 char *error_buffer,
15638 size_t error_buffer_size,
15640 const char *origin,
15645 struct mg_connection *conn = NULL;
15647 #if defined(USE_WEBSOCKET) 15648 struct mg_context *newctx = NULL;
15649 struct websocket_client_thread_data *thread_data;
15650 static const char *magic =
"x3JJHMbDL1EzLkh9GBhXDw==";
15651 static const char *handshake_req;
15653 if (origin != NULL) {
15654 handshake_req =
"GET %s HTTP/1.1\r\n" 15656 "Upgrade: websocket\r\n" 15657 "Connection: Upgrade\r\n" 15658 "Sec-WebSocket-Key: %s\r\n" 15659 "Sec-WebSocket-Version: 13\r\n" 15663 handshake_req =
"GET %s HTTP/1.1\r\n" 15665 "Upgrade: websocket\r\n" 15666 "Connection: Upgrade\r\n" 15667 "Sec-WebSocket-Key: %s\r\n" 15668 "Sec-WebSocket-Version: 13\r\n" 15685 if (conn == NULL) {
15686 if (!*error_buffer) {
15692 "Unexpected error");
15697 if (conn->response_info.status_code != 101) {
15702 if (!*error_buffer) {
15708 "Unexpected server reply");
15711 DEBUG_TRACE(
"Websocket client connect error: %s\r\n", error_buffer);
15718 newctx = (
struct mg_context *)
mg_malloc(
sizeof(
struct mg_context));
15719 memcpy(newctx, conn->ctx,
sizeof(
struct mg_context));
15720 newctx->user_data = user_data;
15722 newctx->cfg_worker_threads = 1;
15723 newctx->worker_threadids =
15727 conn->ctx = newctx;
15728 thread_data = (
struct websocket_client_thread_data *)
15729 mg_calloc_ctx(
sizeof(
struct websocket_client_thread_data), 1, newctx);
15730 thread_data->conn = conn;
15731 thread_data->data_handler = data_func;
15732 thread_data->close_handler = close_func;
15733 thread_data->callback_data = user_data;
15739 (
void *)thread_data,
15740 newctx->worker_threadids) != 0) {
15741 mg_free((
void *)thread_data);
15742 mg_free((
void *)newctx->worker_threadids);
15747 "Websocket client connect thread could not be started\r\n");
15755 (
void)error_buffer;
15756 (
void)error_buffer_size;
15773 int keep_alive_enabled =
15776 if (!keep_alive_enabled) {
15777 conn->must_close = 1;
15782 conn->data_len = 0;
15783 conn->handled_requests = 0;
15786 #if defined(USE_SERVER_STATS) 15787 conn->conn_state = 2;
15791 if (conn->ctx->callbacks.init_connection != NULL) {
15793 void *conn_data = NULL;
15794 conn->ctx->callbacks.init_connection(conn, &conn_data);
15810 int keep_alive, discard_len;
15812 const char *hostend;
15813 int reqerr, uri_type;
15815 #if defined(USE_SERVER_STATS) 15816 int mcon =
mg_atomic_inc(&(conn->ctx->active_connections));
15817 mg_atomic_add(&(conn->ctx->total_connections), 1);
15818 if (mcon > (conn->ctx->max_connections)) {
15821 conn->ctx->max_connections = mcon;
15827 DEBUG_TRACE(
"Start processing connection from %s",
15828 conn->request_info.remote_addr);
15834 DEBUG_TRACE(
"calling get_request (%i times for this connection)",
15835 conn->handled_requests + 1);
15837 #if defined(USE_SERVER_STATS) 15838 conn->conn_state = 3;
15841 if (!
get_request(conn, ebuf,
sizeof(ebuf), &reqerr)) {
15855 "Bad HTTP version: [%s]",
15860 if (ebuf[0] ==
'\0') {
15861 uri_type =
get_uri_type(conn->request_info.request_uri);
15862 switch (uri_type) {
15865 conn->request_info.local_uri = NULL;
15869 conn->request_info.local_uri = conn->request_info.request_uri;
15875 conn->request_info.request_uri, conn);
15877 conn->request_info.local_uri = hostend;
15879 conn->request_info.local_uri = NULL;
15889 conn->request_info.local_uri = NULL;
15893 #if defined(MG_LEGACY_INTERFACE) 15895 conn->request_info.uri = conn->request_info.local_uri;
15901 (ebuf[0] ? ebuf :
"none"));
15903 if (ebuf[0] ==
'\0') {
15904 if (conn->request_info.local_uri) {
15907 #if defined(USE_SERVER_STATS) 15908 conn->conn_state = 4;
15912 #if defined(USE_SERVER_STATS) 15913 conn->conn_state = 5;
15915 mg_atomic_add(&(conn->ctx->total_data_read),
15916 conn->consumed_content);
15917 mg_atomic_add(&(conn->ctx->total_data_written),
15918 conn->num_bytes_sent);
15923 if (conn->ctx->callbacks.end_request != NULL) {
15924 conn->ctx->callbacks.end_request(conn, conn->status_code);
15930 conn->must_close = 1;
15933 conn->must_close = 1;
15949 && (conn->content_len >= 0);
15953 discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
15954 && ((conn->request_len + conn->content_len)
15955 < (int64_t)conn->data_len))
15956 ? (int)(conn->request_len + conn->content_len)
15959 if (discard_len < 0) {
15961 (
long int)discard_len);
15964 conn->data_len -= discard_len;
15965 if (conn->data_len > 0) {
15966 DEBUG_TRACE(
"discard_len = %lu", (
long unsigned)discard_len);
15967 memmove(conn->buf, conn->buf + discard_len, (
size_t)conn->data_len);
15973 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
15974 DEBUG_TRACE(
"internal error: data_len = %li, buf_size = %li",
15975 (
long int)conn->data_len,
15976 (
long int)conn->buf_size);
15980 conn->handled_requests++;
15982 }
while (keep_alive);
15984 DEBUG_TRACE(
"Done processing connection from %s (%f sec)",
15985 conn->request_info.remote_addr,
15986 difftime(time(NULL), conn->conn_birth_time));
15990 #if defined(USE_SERVER_STATS) 15991 mg_atomic_add(&(conn->ctx->total_requests), conn->handled_requests);
15997 #if defined(ALTERNATIVE_QUEUE) 16005 for (i = 0; i < ctx->cfg_worker_threads; i++) {
16007 if (ctx->client_socks[i].in_use == 0) {
16008 ctx->client_socks[i] = *sp;
16009 ctx->client_socks[i].in_use = 1;
16024 ctx->client_socks[thread_index].in_use = 0;
16025 event_wait(ctx->client_wait_events[thread_index]);
16026 *sp = ctx->client_socks[thread_index];
16027 DEBUG_TRACE(
"grabbed socket %d, going busy", sp ? sp->sock : -1);
16029 return !ctx->stop_flag;
16036 consume_socket(
struct mg_context *ctx,
struct socket *sp,
int thread_index)
16038 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue))) 16040 (
void)thread_index;
16042 (
void)pthread_mutex_lock(&ctx->thread_mutex);
16046 while ((ctx->sq_head == ctx->sq_tail) && (ctx->stop_flag == 0)) {
16047 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
16051 if (ctx->sq_head > ctx->sq_tail) {
16053 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
16056 DEBUG_TRACE(
"grabbed socket %d, going busy", sp ? sp->sock : -1);
16059 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
16060 ctx->sq_tail -= QUEUE_SIZE(ctx);
16061 ctx->sq_head -= QUEUE_SIZE(ctx);
16065 (
void)pthread_cond_signal(&ctx->sq_empty);
16066 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
16068 return !ctx->stop_flag;
16077 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue))) 16081 (
void)pthread_mutex_lock(&ctx->thread_mutex);
16084 while ((ctx->stop_flag == 0)
16085 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
16086 (
void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
16089 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
16091 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
16093 DEBUG_TRACE(
"queued socket %d", sp ? sp->sock : -1);
16096 (
void)pthread_cond_signal(&ctx->sq_full);
16097 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
16103 struct worker_thread_args {
16104 struct mg_context *ctx;
16112 struct mg_context *ctx = thread_args->ctx;
16113 struct mg_connection *conn;
16114 struct mg_workerTLS tls;
16115 #if defined(MG_LEGACY_INTERFACE) 16123 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16124 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
16128 pthread_setspecific(sTlsKey, &tls);
16130 if (ctx->callbacks.init_thread) {
16132 ctx->callbacks.init_thread(ctx, 1);
16136 if (((
int)thread_args->index < 0)
16137 || ((
unsigned)thread_args->index
16138 >= (
unsigned)ctx->cfg_worker_threads)) {
16140 "Internal error: Invalid worker index %i",
16141 (
int)thread_args->index);
16144 conn = ctx->worker_connections + thread_args->index;
16149 conn->buf = (
char *)
mg_malloc_ctx(ctx->max_request_size, conn->ctx);
16150 if (conn->buf == NULL) {
16152 "Out of memory: Cannot allocate buffer for worker %i",
16153 (
int)thread_args->index);
16156 conn->buf_size = (int)ctx->max_request_size;
16159 conn->thread_index = thread_args->index;
16160 conn->request_info.user_data = ctx->user_data;
16164 (
void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
16166 #if defined(USE_SERVER_STATS) 16167 conn->conn_state = 1;
16173 while (
consume_socket(ctx, &conn->client, conn->thread_index)) {
16174 conn->conn_birth_time = time(NULL);
16180 #if defined(USE_IPV6) 16181 if (conn->client.rsa.sa.sa_family == AF_INET6) {
16182 conn->request_info.remote_port =
16183 ntohs(conn->client.rsa.sin6.sin6_port);
16187 conn->request_info.remote_port =
16188 ntohs(conn->client.rsa.sin.sin_port);
16192 sizeof(conn->request_info.remote_addr),
16193 &conn->client.rsa);
16195 DEBUG_TRACE(
"Start processing connection from %s",
16196 conn->request_info.remote_addr);
16198 #if defined(MG_LEGACY_INTERFACE) 16200 addr = ntohl(conn->client.rsa.sin.sin_addr.s_addr);
16201 memcpy(&conn->request_info.remote_ip, &addr, 4);
16204 conn->request_info.is_ssl = conn->client.is_ssl;
16206 if (conn->client.is_ssl) {
16210 conn->ctx->ssl_ctx,
16212 &(conn->ctx->stop_flag))) {
16220 if (conn->request_info.client_cert) {
16221 mg_free((
void *)(conn->request_info.client_cert->subject));
16222 mg_free((
void *)(conn->request_info.client_cert->issuer));
16223 mg_free((
void *)(conn->request_info.client_cert->serial));
16224 mg_free((
void *)(conn->request_info.client_cert->finger));
16225 conn->request_info.client_cert->subject = 0;
16226 conn->request_info.client_cert->issuer = 0;
16227 conn->request_info.client_cert->serial = 0;
16228 conn->request_info.client_cert->finger = 0;
16229 mg_free(conn->request_info.client_cert);
16230 conn->request_info.client_cert = 0;
16243 pthread_setspecific(sTlsKey, NULL);
16244 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16245 CloseHandle(tls.pthread_cond_helper_mutex);
16247 pthread_mutex_destroy(&conn->mutex);
16250 conn->buf_size = 0;
16254 #if defined(USE_SERVER_STATS) 16255 conn->conn_state = 9;
16265 static unsigned __stdcall
worker_thread(
void *thread_func_param)
16267 struct worker_thread_args *pwta =
16268 (
struct worker_thread_args *)thread_func_param;
16277 struct worker_thread_args *pwta =
16278 (
struct worker_thread_args *)thread_func_param;
16291 socklen_t len =
sizeof(so.rsa);
16298 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
16300 }
else if (!
check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
16302 mg_cry(
fc(ctx),
"%s: %s is not allowed to connect", __func__, src_addr);
16308 so.is_ssl = listener->is_ssl;
16309 so.ssl_redir = listener->ssl_redir;
16310 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
16312 "%s: getsockname() failed: %s",
16324 if (setsockopt(so.sock,
16327 (SOCK_OPT_TYPE)&on,
16328 sizeof(on)) != 0) {
16330 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
16346 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
16370 struct mg_context *ctx = (
struct mg_context *)thread_func_param;
16371 struct mg_workerTLS tls;
16372 struct pollfd *pfd;
16374 unsigned int workerthreadcount;
16383 #if defined(_WIN32) 16384 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
16385 #elif defined(USE_MASTER_THREAD_PRIORITY) 16386 int min_prio = sched_get_priority_min(SCHED_RR);
16387 int max_prio = sched_get_priority_max(SCHED_RR);
16388 if ((min_prio >= 0) && (max_prio >= 0)
16389 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
16390 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
16391 struct sched_param sched_param = {0};
16392 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
16393 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
16398 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16399 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
16402 pthread_setspecific(sTlsKey, &tls);
16404 if (ctx->callbacks.init_thread) {
16406 ctx->callbacks.init_thread(ctx, 0);
16410 ctx->start_time = time(NULL);
16413 pfd = ctx->listening_socket_fds;
16414 while (ctx->stop_flag == 0) {
16415 for (i = 0; i < ctx->num_listening_sockets; i++) {
16416 pfd[i].fd = ctx->listening_sockets[i].sock;
16417 pfd[i].events = POLLIN;
16420 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
16421 for (i = 0; i < ctx->num_listening_sockets; i++) {
16427 if ((ctx->stop_flag == 0) && (pfd[i].revents & POLLIN)) {
16441 (
void)pthread_mutex_lock(&ctx->thread_mutex);
16442 #if defined(ALTERNATIVE_QUEUE) 16443 for (i = 0; i < ctx->cfg_worker_threads; i++) {
16447 if (ctx->client_socks[i].in_use) {
16452 pthread_cond_broadcast(&ctx->sq_full);
16454 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
16457 workerthreadcount = ctx->cfg_worker_threads;
16458 for (i = 0; i < workerthreadcount; i++) {
16459 if (ctx->worker_threadids[i] != 0) {
16464 #if defined(USE_LUA) 16466 if (ctx->lua_background_state) {
16467 lua_State *lstate = (lua_State *)ctx->lua_background_state;
16468 lua_getglobal(lstate, LUABACKGROUNDPARAMS);
16469 if (lua_istable(lstate, -1)) {
16470 reg_boolean(lstate,
"shutdown", 1);
16471 lua_pop(lstate, 1);
16475 ctx->lua_background_state = 0;
16481 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16482 CloseHandle(tls.pthread_cond_helper_mutex);
16484 pthread_setspecific(sTlsKey, NULL);
16489 ctx->stop_flag = 2;
16495 static unsigned __stdcall
master_thread(
void *thread_func_param)
16514 struct mg_handler_info *tmp_rh;
16520 if (ctx->callbacks.exit_context) {
16521 ctx->callbacks.exit_context(ctx);
16527 (
void)pthread_mutex_destroy(&ctx->thread_mutex);
16528 #if defined(ALTERNATIVE_QUEUE) 16530 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
16533 mg_free(ctx->client_wait_events);
16535 (
void)pthread_cond_destroy(&ctx->sq_empty);
16536 (
void)pthread_cond_destroy(&ctx->sq_full);
16540 (
void)pthread_mutex_destroy(&ctx->nonce_mutex);
16542 #if defined(USE_TIMERS) 16548 if (ctx->config[i] != NULL) {
16549 #if defined(_MSC_VER) 16550 #pragma warning(suppress : 6001) 16557 while (ctx->handlers) {
16558 tmp_rh = ctx->handlers;
16559 ctx->handlers = tmp_rh->next;
16566 if (ctx->ssl_ctx != NULL) {
16572 if (ctx->worker_threadids != NULL) {
16573 mg_free(ctx->worker_threadids);
16577 if (ctx->worker_connections != NULL) {
16578 mg_free(ctx->worker_connections);
16599 mt = ctx->masterthreadid;
16604 ctx->masterthreadid = 0;
16607 ctx->stop_flag = 1;
16610 while (ctx->stop_flag != 2) {
16617 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16618 (
void)WSACleanup();
16626 #if defined(_WIN32) 16627 #if !defined(__SYMBIAN32__) 16628 #if defined(_WIN32_WCE) 16632 DWORD dwVersion = 0;
16633 DWORD dwMajorVersion = 0;
16634 DWORD dwMinorVersion = 0;
16636 BOOL wowRet, isWoW =
FALSE;
16639 #pragma warning(push) 16641 #pragma warning(disable : 4996) 16643 dwVersion = GetVersion();
16645 #pragma warning(pop) 16648 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
16649 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
16650 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
16653 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
16657 (
unsigned)dwMajorVersion,
16658 (
unsigned)dwMinorVersion,
16659 (wowRet ? (isWoW ?
" (WoW64)" :
"") :
" (?)"));
16667 struct utsname name;
16668 memset(&name, 0,
sizeof(name));
16675 struct mg_context *
16678 const char **options)
16680 struct mg_context *ctx;
16681 const char *
name, *value, *default_value;
16682 int idx, ok, workerthreadcount;
16685 void (*exit_callback)(
const struct mg_context *ctx) = 0;
16687 struct mg_workerTLS tls;
16689 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16691 WSAStartup(MAKEWORD(2, 2), &data);
16695 if ((ctx = (
struct mg_context *)
mg_calloc(1,
sizeof(*ctx))) == NULL) {
16700 ctx->auth_nonce_mask =
16701 (uint64_t)
get_random() ^ (uint64_t)(ptrdiff_t)(options);
16703 if (mg_init_library_called == 0) {
16709 tls.is_master = -1;
16711 #if defined(_WIN32) && !defined(__SYMBIAN32__) 16712 tls.pthread_cond_helper_mutex = NULL;
16714 pthread_setspecific(sTlsKey, &tls);
16716 ok = 0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr);
16717 #if !defined(ALTERNATIVE_QUEUE) 16718 ok &= 0 == pthread_cond_init(&ctx->sq_empty, NULL);
16719 ok &= 0 == pthread_cond_init(&ctx->sq_full, NULL);
16721 ok &= 0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr);
16725 mg_cry(
fc(ctx),
"Cannot initialize thread synchronization objects");
16727 pthread_setspecific(sTlsKey, NULL);
16732 ctx->callbacks = *callbacks;
16734 ctx->callbacks.exit_context = 0;
16736 ctx->user_data = user_data;
16737 ctx->handlers = NULL;
16739 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 16740 ctx->shared_lua_websockets = 0;
16743 while (options && (name = *options++) != NULL) {
16745 mg_cry(
fc(ctx),
"Invalid option: %s", name);
16747 pthread_setspecific(sTlsKey, NULL);
16749 }
else if ((value = *options++) == NULL) {
16750 mg_cry(
fc(ctx),
"%s: option value cannot be NULL", name);
16752 pthread_setspecific(sTlsKey, NULL);
16755 if (ctx->config[idx] != NULL) {
16756 mg_cry(
fc(ctx),
"warning: %s: duplicate option", name);
16766 if ((ctx->config[i] == NULL) && (default_value != NULL)) {
16767 ctx->config[i] =
mg_strdup(default_value);
16774 mg_cry(
fc(ctx),
"max_request_size too small");
16776 pthread_setspecific(sTlsKey, NULL);
16779 ctx->max_request_size = (unsigned)itmp;
16781 workerthreadcount = atoi(ctx->config[
NUM_THREADS]);
16783 if (workerthreadcount > MAX_WORKER_THREADS) {
16784 mg_cry(
fc(ctx),
"Too many worker threads");
16786 pthread_setspecific(sTlsKey, NULL);
16790 if (workerthreadcount <= 0) {
16791 mg_cry(
fc(ctx),
"Invalid number of worker threads");
16793 pthread_setspecific(sTlsKey, NULL);
16797 #if defined(NO_FILES) 16799 mg_cry(
fc(ctx),
"%s",
"Document root must not be set");
16801 pthread_setspecific(sTlsKey, NULL);
16808 #if defined(USE_LUA) 16810 if (ctx->config[LUA_BACKGROUND_SCRIPT] != NULL) {
16812 lua_State *state = (
void *)mg_prepare_lua_context_script(
16813 ctx->config[LUA_BACKGROUND_SCRIPT], ctx, ebuf,
sizeof(ebuf));
16815 mg_cry(
fc(ctx),
"lua_background_script error: %s", ebuf);
16817 pthread_setspecific(sTlsKey, NULL);
16820 ctx->lua_background_state = (
void *)state;
16822 lua_newtable(state);
16823 reg_boolean(state,
"shutdown", 0);
16825 struct vec opt_vec;
16827 const char *sparams = ctx->config[LUA_BACKGROUND_SCRIPT_PARAMS];
16829 while ((sparams =
next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
16831 state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
16835 lua_setglobal(state, LUABACKGROUNDPARAMS);
16838 ctx->lua_background_state = 0;
16845 #
if !defined(NO_SSL)
16849 #
if !defined(_WIN32)
16854 pthread_setspecific(sTlsKey, NULL);
16858 #if !defined(_WIN32) && !defined(__SYMBIAN32__) 16864 ctx->cfg_worker_threads = ((
unsigned int)(workerthreadcount));
16865 ctx->worker_threadids = (pthread_t *)
mg_calloc_ctx(ctx->cfg_worker_threads,
16868 if (ctx->worker_threadids == NULL) {
16869 mg_cry(
fc(ctx),
"Not enough memory for worker thread ID array");
16871 pthread_setspecific(sTlsKey, NULL);
16874 ctx->worker_connections =
16875 (
struct mg_connection *)
mg_calloc_ctx(ctx->cfg_worker_threads,
16876 sizeof(
struct mg_connection),
16878 if (ctx->worker_connections == NULL) {
16879 mg_cry(
fc(ctx),
"Not enough memory for worker thread connection array");
16881 pthread_setspecific(sTlsKey, NULL);
16886 #if defined(ALTERNATIVE_QUEUE) 16887 ctx->client_wait_events =
16889 ctx->cfg_worker_threads,
16891 if (ctx->client_wait_events == NULL) {
16892 mg_cry(
fc(ctx),
"Not enough memory for worker event array");
16893 mg_free(ctx->worker_threadids);
16895 pthread_setspecific(sTlsKey, NULL);
16899 ctx->client_socks =
16900 (
struct socket *)
mg_calloc_ctx(
sizeof(ctx->client_socks[0]),
16901 ctx->cfg_worker_threads,
16903 if (ctx->client_wait_events == NULL) {
16904 mg_cry(
fc(ctx),
"Not enough memory for worker socket array");
16906 mg_free(ctx->worker_threadids);
16908 pthread_setspecific(sTlsKey, NULL);
16912 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
16914 if (ctx->client_wait_events[i] == 0) {
16915 mg_cry(
fc(ctx),
"Error creating worker event %i", i);
16921 mg_free(ctx->worker_threadids);
16923 pthread_setspecific(sTlsKey, NULL);
16930 #if defined(USE_TIMERS) 16931 if (timers_init(ctx) != 0) {
16932 mg_cry(
fc(ctx),
"Error creating timers");
16934 pthread_setspecific(sTlsKey, NULL);
16940 if (ctx->callbacks.init_context) {
16941 ctx->callbacks.init_context(ctx);
16943 ctx->callbacks.exit_context = exit_callback;
16950 for (i = 0; i < ctx->cfg_worker_threads; i++) {
16951 struct worker_thread_args *wta = (
struct worker_thread_args *)
16955 wta->index = (int)i;
16961 &ctx->worker_threadids[i]) != 0)) {
16970 "Cannot start worker thread %i: error %ld",
16975 "Cannot create threads: error %ld",
16978 pthread_setspecific(sTlsKey, NULL);
16985 pthread_setspecific(sTlsKey, NULL);
16994 static const unsigned feature_set = 0
16998 #if !defined(NO_FILES) 17001 #if !defined(NO_SSL) 17004 #if !defined(NO_CGI) 17007 #if defined(USE_IPV6) 17010 #if defined(USE_WEBSOCKET) 17013 #if defined(USE_LUA) 17016 #if defined(USE_DUKTAPE) 17019 #if !defined(NO_CACHING) 17022 #if defined(USE_SERVER_STATS) 17028 #if defined(MG_LEGACY_INTERFACE) 17031 #if defined(MEMORY_DEBUGGING) 17034 #if defined(USE_TIMERS) 17037 #if !defined(NO_NONCE_CHECK) 17040 #if !defined(NO_POPEN) 17044 return (feature & feature_set);
17049 #define strcat0(a, b) \ 17051 if ((a != NULL) && (b != NULL)) { \ 17063 int system_info_length = 0;
17065 #if defined(_WIN32) 17066 const char *eol =
"\r\n";
17068 const char *eol =
"\n";
17071 const char *eoobj =
"}";
17072 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
17074 if ((buffer == NULL) || (buflen < 1)) {
17080 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
17081 system_info_length += (int)strlen(block);
17082 if (system_info_length < buflen) {
17093 "\"version\" : \"%s\",%s",
17096 system_info_length += (int)strlen(block);
17097 if (system_info_length < buflen) {
17104 #if defined(_WIN32) 17105 #if !defined(__SYMBIAN32__) 17106 DWORD dwVersion = 0;
17107 DWORD dwMajorVersion = 0;
17108 DWORD dwMinorVersion = 0;
17111 GetSystemInfo(&si);
17114 #pragma warning(push) 17116 #pragma warning(disable : 4996) 17118 dwVersion = GetVersion();
17120 #pragma warning(pop) 17123 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
17124 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
17130 "\"os\" : \"Windows %u.%u\",%s",
17131 (
unsigned)dwMajorVersion,
17132 (
unsigned)dwMinorVersion,
17134 system_info_length += (int)strlen(block);
17135 if (system_info_length < buflen) {
17143 "\"cpu\" : \"type %u, cores %u, mask %x\",%s",
17144 (
unsigned)si.wProcessorArchitecture,
17145 (
unsigned)si.dwNumberOfProcessors,
17146 (
unsigned)si.dwActiveProcessorMask,
17148 system_info_length += (int)strlen(block);
17149 if (system_info_length < buflen) {
17154 mg_snprintf(NULL, NULL, block,
sizeof(block),
"%s - Symbian%s", eol);
17155 system_info_length += (int)strlen(block);
17156 if (system_info_length < buflen) {
17161 struct utsname name;
17162 memset(&name, 0,
sizeof(name));
17169 "\"os\" : \"%s %s (%s) - %s\",%s",
17175 system_info_length += (int)strlen(block);
17176 if (system_info_length < buflen) {
17188 "\"features\" : %lu,%s" 17189 "\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\",%s",
17202 system_info_length += (int)strlen(block);
17203 if (system_info_length < buflen) {
17212 "\"lua_version\" : \"%u (%s)\",%s",
17213 (
unsigned)LUA_VERSION_NUM,
17216 system_info_length += (int)strlen(block);
17217 if (system_info_length < buflen) {
17221 #if defined(USE_DUKTAPE) 17226 "\"javascript\" : \"Duktape %u.%u.%u\",%s",
17227 (
unsigned)DUK_VERSION / 10000,
17228 ((
unsigned)DUK_VERSION / 100) % 100,
17229 (
unsigned)DUK_VERSION % 100,
17231 system_info_length += (int)strlen(block);
17232 if (system_info_length < buflen) {
17252 "\"build\" : \"%s\",%s",
17260 system_info_length += (int)strlen(block);
17261 if (system_info_length < buflen) {
17270 #if defined(_MSC_VER) 17275 "\"compiler\" : \"MSC: %u (%u)\",%s",
17276 (
unsigned)_MSC_VER,
17277 (
unsigned)_MSC_FULL_VER,
17279 system_info_length += (int)strlen(block);
17280 if (system_info_length < buflen) {
17283 #elif defined(__MINGW64__) 17288 "\"compiler\" : \"MinGW64: %u.%u\",%s",
17289 (
unsigned)__MINGW64_VERSION_MAJOR,
17290 (
unsigned)__MINGW64_VERSION_MINOR,
17292 system_info_length += (int)strlen(block);
17293 if (system_info_length < buflen) {
17300 "\"compiler\" : \"MinGW32: %u.%u\",%s",
17301 (
unsigned)__MINGW32_MAJOR_VERSION,
17302 (
unsigned)__MINGW32_MINOR_VERSION,
17304 system_info_length += (int)strlen(block);
17305 if (system_info_length < buflen) {
17308 #elif defined(__MINGW32__) 17313 "\"compiler\" : \"MinGW32: %u.%u\",%s",
17314 (
unsigned)__MINGW32_MAJOR_VERSION,
17315 (
unsigned)__MINGW32_MINOR_VERSION,
17317 system_info_length += (int)strlen(block);
17318 if (system_info_length < buflen) {
17321 #elif defined(__clang__) 17326 "\"compiler\" : \"clang: %u.%u.%u (%s)\",%s",
17329 __clang_patchlevel__,
17332 system_info_length += (int)strlen(block);
17333 if (system_info_length < buflen) {
17336 #elif defined(__GNUC__) 17341 "\"compiler\" : \"gcc: %u.%u.%u\",%s",
17342 (
unsigned)__GNUC__,
17343 (
unsigned)__GNUC_MINOR__,
17344 (
unsigned)__GNUC_PATCHLEVEL__,
17346 system_info_length += (int)strlen(block);
17347 if (system_info_length < buflen) {
17350 #elif defined(__INTEL_COMPILER) 17355 "\"compiler\" : \"Intel C/C++: %u\",%s",
17356 (
unsigned)__INTEL_COMPILER,
17358 system_info_length += (int)strlen(block);
17359 if (system_info_length < buflen) {
17362 #elif defined(__BORLANDC__) 17367 "\"compiler\" : \"Borland C: 0x%x\",%s",
17368 (
unsigned)__BORLANDC__,
17370 system_info_length += (int)strlen(block);
17371 if (system_info_length < buflen) {
17374 #elif defined(__SUNPRO_C) 17379 "\"compiler\" : \"Solaris: 0x%x\",%s",
17380 (
unsigned)__SUNPRO_C,
17382 system_info_length += (int)strlen(block);
17383 if (system_info_length < buflen) {
17391 "\"compiler\" : \"other\",%s",
17393 system_info_length += (int)strlen(block);
17394 if (system_info_length < buflen) {
17408 "\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, char:%u/%u, " 17409 "ptr:%u, size:%u, time:%u\"%s",
17410 (
unsigned)
sizeof(
short),
17411 (
unsigned)
sizeof(
int),
17412 (
unsigned)
sizeof(
long),
17413 (
unsigned)
sizeof(
long long),
17414 (
unsigned)
sizeof(
float),
17415 (
unsigned)
sizeof(
double),
17416 (
unsigned)
sizeof(
long double),
17417 (
unsigned)
sizeof(
char),
17418 (
unsigned)
sizeof(
wchar_t),
17419 (
unsigned)
sizeof(
void *),
17420 (
unsigned)
sizeof(
size_t),
17421 (
unsigned)
sizeof(time_t),
17423 system_info_length += (int)strlen(block);
17424 if (system_info_length < buflen) {
17430 if ((buflen > 0) && buffer && buffer[0]) {
17431 if (system_info_length < buflen) {
17436 system_info_length += reserved_len;
17438 return system_info_length;
17442 #if defined(USE_SERVER_STATS) 17446 mg_get_context_info_impl(
const struct mg_context *ctx,
char *buffer,
int buflen)
17450 int context_info_length = 0;
17452 #if defined(_WIN32) 17453 const char *eol =
"\r\n";
17455 const char *eol =
"\n";
17457 struct mg_memory_stat *
ms = get_memory_stat((
struct mg_context *)ctx);
17459 const char *eoobj =
"}";
17460 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
17462 if ((buffer == NULL) || (buflen < 1)) {
17468 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
17469 context_info_length += (int)strlen(block);
17470 if (context_info_length < buflen) {
17481 "\"blocks\" : %i,%s" 17495 context_info_length += (int)strlen(block);
17496 if (context_info_length + reserved_len < buflen) {
17508 "\"connections\" : {%s" 17509 "\"active\" : %i,%s" 17510 "\"maxActive\" : %i,%s" 17514 ctx->active_connections,
17516 ctx->max_connections,
17518 ctx->total_connections,
17522 context_info_length += (int)strlen(block);
17523 if (context_info_length + reserved_len < buflen) {
17534 "\"requests\" : {%s" 17538 ctx->total_requests,
17542 context_info_length += (int)strlen(block);
17543 if (context_info_length + reserved_len < buflen) {
17559 ctx->total_data_read,
17561 ctx->total_data_written,
17565 context_info_length += (int)strlen(block);
17566 if (context_info_length + reserved_len < buflen) {
17573 char start_time_str[64] = {0};
17574 char now_str[64] = {0};
17575 time_t start_time = ctx->start_time;
17576 time_t now = time(NULL);
17579 sizeof(start_time_str) - 1,
17588 "\"uptime\" : %.0f,%s" 17589 "\"start\" : \"%s\",%s" 17590 "\"now\" : \"%s\"%s" 17593 difftime(now, start_time),
17601 context_info_length += (int)strlen(block);
17602 if (context_info_length + reserved_len < buflen) {
17608 if ((buflen > 0) && buffer && buffer[0]) {
17609 if (context_info_length < buflen) {
17614 context_info_length += reserved_len;
17616 return context_info_length;
17621 #ifdef MG_EXPERIMENTAL_INTERFACES 17625 mg_get_connection_info_impl(
const struct mg_context *ctx,
17630 const struct mg_connection *conn;
17633 int connection_info_length = 0;
17635 const char *state_str =
"unknown";
17637 #if defined(_WIN32) 17638 const char *eol =
"\r\n";
17640 const char *eol =
"\n";
17643 const char *eoobj =
"}";
17644 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
17646 if ((buffer == NULL) || (buflen < 1)) {
17652 if ((ctx == NULL) || (idx < 0)) {
17657 if ((
unsigned)idx >= ctx->cfg_worker_threads) {
17664 conn = (ctx->worker_connections) + idx;
17667 mg_snprintf(NULL, NULL, block,
sizeof(block),
"{%s", eol);
17668 connection_info_length += (int)strlen(block);
17669 if (connection_info_length < buflen) {
17674 ri = &(conn->request_info);
17676 #if defined(USE_SERVER_STATS) 17677 state = conn->conn_state;
17682 state_str =
"undefined";
17685 state_str =
"not used";
17688 state_str =
"init";
17691 state_str =
"ready";
17694 state_str =
"processing";
17697 state_str =
"processed";
17700 state_str =
"to close";
17703 state_str =
"closing";
17706 state_str =
"closed";
17709 state_str =
"done";
17715 if ((state >= 3) && (state < 9)) {
17720 "\"connection\" : {%s" 17722 "\"protocol\" : \"%s\",%s" 17723 "\"addr\" : \"%s\",%s" 17726 "\"handled_requests\" : %u%s" 17737 conn->handled_requests,
17741 connection_info_length += (int)strlen(block);
17742 if (connection_info_length + reserved_len < buflen) {
17748 if ((state >= 4) && (state < 6)) {
17753 "\"request_info\" : {%s" 17754 "\"method\" : \"%s\",%s" 17755 "\"uri\" : \"%s\",%s" 17756 "\"query\" : %s%s%s%s" 17769 connection_info_length += (int)strlen(block);
17770 if (connection_info_length + reserved_len < buflen) {
17776 if ((state >= 2) && (state < 9)) {
17777 char start_time_str[64] = {0};
17778 char now_str[64] = {0};
17779 time_t start_time = conn->conn_birth_time;
17780 time_t now = time(NULL);
17783 sizeof(start_time_str) - 1,
17792 "\"uptime\" : %.0f,%s" 17793 "\"start\" : \"%s\",%s" 17794 "\"now\" : \"%s\"%s" 17797 difftime(now, start_time),
17805 connection_info_length += (int)strlen(block);
17806 if (connection_info_length + reserved_len < buflen) {
17818 "\"name\" : \"%s\",%s" 17825 connection_info_length += (int)strlen(block);
17826 if (connection_info_length + reserved_len < buflen) {
17842 conn->consumed_content,
17844 conn->num_bytes_sent,
17848 connection_info_length += (int)strlen(block);
17849 if (connection_info_length + reserved_len < buflen) {
17859 "\"state\" : \"%s\"%s",
17863 connection_info_length += (int)strlen(block);
17864 if (connection_info_length + reserved_len < buflen) {
17869 if ((buflen > 0) && buffer && buffer[0]) {
17870 if (connection_info_length < buflen) {
17875 connection_info_length += reserved_len;
17877 return connection_info_length;
17887 if ((buffer == NULL) || (buflen < 1)) {
17902 #if defined(USE_SERVER_STATS) 17903 if ((buffer == NULL) || (buflen < 1)) {
17904 return mg_get_context_info_impl(ctx, NULL, 0);
17908 return mg_get_context_info_impl(ctx, buffer, buflen);
17912 if ((buffer != NULL) && (buflen > 0)) {
17920 #ifdef MG_EXPERIMENTAL_INTERFACES 17922 mg_get_connection_info(
const struct mg_context *ctx,
17927 if ((buffer == NULL) || (buflen < 1)) {
17928 return mg_get_connection_info_impl(ctx, idx, NULL, 0);
17932 return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
17943 #if !defined(NO_SSL) 17948 unsigned features_inited = features_to_init;
17950 if (mg_init_library_called <= 0) {
17952 if (0 != pthread_mutex_init(&global_lock_mutex, NULL)) {
17959 if (mg_init_library_called <= 0) {
17960 if (0 != pthread_key_create(&sTlsKey,
tls_dtor)) {
17966 #if defined(_WIN32) && !defined(__SYMBIAN32__) 17967 InitializeCriticalSection(&global_log_file_lock);
17969 #if !defined(_WIN32) 17970 pthread_mutexattr_init(&pthread_mutex_attr);
17971 pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
17974 #if defined(USE_LUA) 17975 lua_init_optional_libraries();
17980 #if !defined(NO_SSL) 17981 if (features_to_init & 2) {
17982 if (!mg_ssl_initialized) {
17984 mg_ssl_initialized = 1;
17988 features_inited &= ~(2u);
17997 if (mg_init_library_called <= 0) {
17998 #if defined(_WIN32) && !defined(__SYMBIAN32__) 18000 WSAStartup(MAKEWORD(2, 2), &data);
18002 mg_init_library_called = 1;
18004 mg_init_library_called++;
18009 return features_inited;
18017 if (mg_init_library_called <= 0) {
18023 mg_init_library_called--;
18024 if (mg_init_library_called == 0) {
18025 #if defined(_WIN32) && !defined(__SYMBIAN32__) 18026 (
void)WSACleanup();
18028 #if !defined(NO_SSL) 18029 if (mg_ssl_initialized) {
18031 mg_ssl_initialized = 0;
18035 #if defined(_WIN32) && !defined(__SYMBIAN32__) 18036 (
void)DeleteCriticalSection(&global_log_file_lock);
18038 #if !defined(_WIN32) 18039 (
void)pthread_mutexattr_destroy(&pthread_mutex_attr);
18042 (
void)pthread_key_delete(sTlsKey);
18044 #if defined(USE_LUA) 18045 lua_exit_optional_libraries();
18049 (
void)pthread_mutex_destroy(&global_lock_mutex);
int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence)
#define mg_remove(conn, x)
#define MAX_CGI_ENVIR_VARS
static int set_ports_option(struct mg_context *ctx)
int mg_get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int timeout)
#define SSL_set_app_data(s, arg)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
static void close_all_listening_sockets(struct mg_context *ctx)
struct md5_state_s md5_state_t
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
static int hexdump2string(void *mem, int memlen, char *buf, int buflen)
static const char * mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p)
#define SSL_CTX_set_ecdh_auto(ctx, onoff)
static int print_dir_entry(struct de *de)
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS])
#define SSL_CB_HANDSHAKE_DONE
static int cryptolib_users
#define CRYPTO_set_id_callback
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)
static constexpr double pi
static char * mg_strndup(const char *ptr, size_t len)
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
int mg_get_server_ports(const struct mg_context *ctx, int size, struct mg_server_ports *ports)
#define SSL_CTX_use_certificate_chain_file
void mg_set_user_connection_data(struct mg_connection *conn, void *data)
int mg_start_thread(mg_thread_func_t func, void *param)
static int send_no_cache_header(struct mg_connection *conn)
#define X509_get_subject_name
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
#define INVALID_HANDLE_VALUE
static int check_acl(struct mg_context *ctx, uint32_t remote_ip)
static void ssl_get_client_cert_info(struct mg_connection *conn)
#define PRINTF_ARGS(x, y)
#define mg_mkdir(conn, path, mode)
static int mg_poll(struct pollfd *pfd, unsigned int n, int milliseconds, volatile int *stop_server)
static struct ssl_func crypto_sw[]
static int set_uid_option(struct mg_context *ctx)
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)
int mg_check_digest_access_authentication(struct mg_connection *conn, const char *realm, const char *filename)
static int mg_fopen(const struct mg_connection *conn, const char *path, int mode, struct mg_file *filep)
static const char * get_header(const struct mg_header *hdr, int num_hdr, const char *name)
#define SSL_ERROR_WANT_READ
static void uninitialize_ssl(void)
static int set_acl_option(struct mg_context *ctx)
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT
#define is_websocket_protocol(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)
void mg_unlock_context(struct mg_context *ctx)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
static void ssl_info_callback(const SSL *ssl, int what, int ret)
static void bin2str(char *to, const unsigned char *p, size_t len)
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
const char * mg_version(void)
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
static void handle_file_based_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
static void handle_request(struct mg_connection *conn)
static int is_in_script_path(const struct mg_connection *conn, const char *path)
const struct mg_option * mg_get_valid_options(void)
static int parse_http_response(char *buf, int len, struct mg_response_info *ri)
static void mg_vsnprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap)
static int prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_environment *env)
static int refresh_trust(struct mg_connection *conn)
#define DEBUG_TRACE(fmt,...)
static void reset_per_request_attributes(struct mg_connection *conn)
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS
static void * event_create(void)
void mg_stop(struct mg_context *ctx)
void(* exit_context)(const struct mg_context *ctx)
static void remove_double_dots_and_double_slashes(char *s)
#define ARRAY_SIZE(array)
static int get_uri_type(const char *uri)
void mg_cry(const struct mg_connection *conn, const char *fmt,...)
static int get_option_index(const char *name)
static int open_file_in_memory(const struct mg_connection *conn, const char *path, struct mg_file *filep, int mode)
#define MAX_WORKER_THREADS
static int ssl_use_pem_file(struct mg_context *ctx, const char *pem, const char *chain)
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
static FUNCTION_MAY_BE_UNUSED int mg_atomic_inc(volatile int *addr)
const struct mg_response_info * mg_get_response_info(const struct mg_connection *conn)
static const char * get_proto_name(const struct mg_connection *conn)
static void * master_thread(void *thread_func_param)
unsigned mg_exit_library(void)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
#define CGI_ENVIRONMENT_SIZE
void mg_unlock_connection(struct mg_connection *conn)
static pthread_mutex_t * ssl_mutexes
static void remove_bad_file(const struct mg_connection *conn, const char *path)
static double mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
static int match_prefix(const char *pattern, size_t pattern_len, const char *str)
static void handle_propfind(struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
int(* mg_authorization_handler)(struct mg_connection *conn, void *cbdata)
static void close_connection(struct mg_connection *conn)
#define X509_get_issuer_name
#define ASN1_INTEGER_to_BN
#define SSL_get_peer_certificate
static void close_socket_gracefully(struct mg_connection *conn)
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
#define SSL_CTX_set_info_callback
static void handle_ssi_file_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
static FUNCTION_MAY_BE_UNUSED uint64_t mg_get_current_time_ns(void)
static int check_authorization(struct mg_connection *conn, const char *path)
static int extention_matches_script(struct mg_connection *conn, const char *filename)
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)
const char * default_value
const char * mg_get_option(const struct mg_context *ctx, const char *name)
static int read_auth_file(struct mg_file *filep, struct read_auth_file_struct *workdata, int depth)
static void handle_not_modified_static_file_request(struct mg_connection *conn, struct mg_file *filep)
void mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type)
static int header_has_option(const char *header, const char *option)
static int should_decode_url(const struct mg_connection *conn)
#define SSL_OP_SINGLE_DH_USE
#define PRINTF_FORMAT_STRING(s)
static int skip_to_end_of_word_and_terminate(char **ppw, int eol)
static int is_not_modified(const struct mg_connection *conn, const struct mg_file_stat *filestat)
static int mg_ssl_initialized
static struct mg_connection * fc(struct mg_context *ctx)
static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
static void open_auth_file(struct mg_connection *conn, const char *path, struct mg_file *filep)
static const double x2[5]
const char * request_method
static const char * mg_strcasestr(const char *big_str, const char *small_str)
static int initialize_ssl(char *ebuf, size_t ebuf_len)
static struct mg_http_method_info http_methods[]
static struct ssl_func ssl_sw[]
#define SSL_OP_NO_TLSv1_1
#define SSL_CTX_clear_options(ctx, op)
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)
void mg_set_auth_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
#define mg_static_assert(cond, txt)
static int is_authorized_for_put(struct mg_connection *conn)
int mg_send_digest_access_authentication_request(struct mg_connection *conn, const char *realm)
static void * cryptolib_dll_handle
static int thread_idx_max
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
#define SSL_CTX_set_session_id_context
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
static double p2(double t, double a, double b, double c)
static int read_message(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread)
static int is_valid_port(unsigned long port)
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
#define SSL_CTX_use_PrivateKey_file
static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
static int get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
struct x509_name X509_NAME
struct mg_connection * mg_connect_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size)
static void master_thread_run(void *thread_func_param)
SHA_API void SHA1_Init(SHA_CTX *context)
static constexpr double L
static int set_blocking_mode(SOCKET sock)
static int set_tcp_nodelay(SOCKET sock, int nodelay_on)
static void * ssllib_dll_handle
static void init_connection(struct mg_connection *conn)
static const char * suggest_connection_header(const struct mg_connection *conn)
static void mg_set_thread_name(const char *name)
static struct mg_option config_options[]
long long mg_store_body(struct mg_connection *conn, const char *path)
static int sslize(struct mg_connection *conn, SSL_CTX *s, int(*func)(SSL *), volatile int *stop_server)
static int parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
void mg_send_file(struct mg_connection *conn, const char *path)
static int set_non_blocking_mode(SOCKET sock)
#define SSLv23_client_method
const char * mg_get_response_code_text(const struct mg_connection *conn, int response_code)
#define SSL_CTX_set_verify_depth
static struct mg_connection * mg_connect_client_impl(const struct mg_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len)
static __inline void * mg_calloc(size_t a, size_t b)
static int get_first_ssl_listener_index(const struct mg_context *ctx)
int(* mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *)
static constexpr double second
#define SSL_CTX_use_certificate_file
static void get_system_name(char **sysName)
static int mg_join_thread(pthread_t threadid)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
struct asn1_integer ASN1_INTEGER
static pthread_mutexattr_t pthread_mutex_attr
static FUNCTION_MAY_BE_UNUSED void mg_global_unlock(void)
static int dir_scan_callback(struct de *de, void *data)
char * mg_md5(char buf[33],...)
static int set_ssl_option(struct mg_context *ctx)
#define SSL_CTX_check_private_key
static const struct mg_http_method_info * get_http_method_info(const char *method)
void(* mg_websocket_close_handler)(const struct mg_connection *, void *)
static time_t parse_date_string(const char *datetime)
#define EVP_get_digestbyname
#define SSL_ERROR_WANT_CONNECT
static const char * ssl_error(void)
static void mkcol(struct mg_connection *conn, const char *path)
static int mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
static const char * get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
const void * SOCK_OPT_TYPE
static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
struct ssl_method_st SSL_METHOD
static void addenv(struct cgi_environment *env, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
static int mg_fgetc(struct mg_file *filep, int offset)
static int64_t push_all(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
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)
static void event_destroy(void *eventhdl)
static int push_inner(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len, double timeout)
static struct mg_context common_client_context
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mg_file_stat *filestat)
static void print_props(struct mg_connection *conn, const char *uri, struct mg_file_stat *filep)
int mg_url_encode(const char *src, char *dst, size_t dst_len)
#define OPENSSL_INIT_LOAD_SSL_STRINGS
static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
#define SSL_CTX_set_default_verify_paths
static int consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
static int get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
void mg_send_mime_file2(struct mg_connection *conn, const char *path, const char *mime_type, const char *additional_headers)
static int is_put_or_delete_method(const struct mg_connection *conn)
#define mg_malloc_ctx(a, c)
static __inline void mg_free(void *a)
unsigned mg_check_feature(unsigned feature)
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
static double p1(double t, double a, double b)
static int put_dir(struct mg_connection *conn, const char *path)
static int must_hide_file(struct mg_connection *conn, const char *path)
struct mg_header http_headers[MG_MAX_HEADERS]
static char mg_getc(struct mg_connection *conn)
const char * http_version
void mg_lock_connection(struct mg_connection *conn)
static __inline void * mg_realloc(void *a, size_t b)
static void put_file(struct mg_connection *conn, const char *path)
CIVETWEB_API struct mg_connection * mg_connect_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size)
#define mg_calloc_ctx(a, b, c)
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
int mg_send_chunk(struct mg_connection *conn, const char *chunk, unsigned int chunk_len)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, int(*cb)(struct de *, void *))
static const char * header_val(const struct mg_connection *conn, const char *header)
static constexpr double ms
static int remove_directory(struct mg_connection *conn, const char *dir)
constexpr Double_t E()
Base of natural log: .
int mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
int mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
static int should_keep_alive(const struct mg_connection *conn)
void mg_close_connection(struct mg_connection *conn)
static void handle_directory_request(struct mg_connection *conn, const char *dir)
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
static void send_file_data(struct mg_connection *conn, struct mg_file *filep, int64_t offset, int64_t len)
int mg_strcasecmp(const char *s1, const char *s2)
#define X509_NAME_oneline
static void tls_dtor(void *key)
static int lowercase(const char *s)
struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
static int mg_stat(const struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
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 unsigned int total
#define SSL_OP_CIPHER_SERVER_PREFERENCE
static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
static const double x1[5]
const char * mg_get_header(const struct mg_connection *conn, const char *name)
static int mg_fclose(struct mg_file_access *fileacc)
#define SSL_ERROR_WANT_WRITE
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
struct x509_store_ctx_st X509_STORE_CTX
CIVETWEB_API int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
static int send_static_cache_header(struct mg_connection *conn)
void * mg_get_user_data(const struct mg_context *ctx)
static void discard_unread_request_data(struct mg_connection *conn)
char static_assert_replacement[1]
#define SSL_CB_HANDSHAKE_START
#define CRYPTO_cleanup_all_ex_data
#define MG_FOPEN_MODE_WRITE
static void fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
#define CRYPTO_set_locking_callback
struct ossl_init_settings_st OPENSSL_INIT_SETTINGS
static uint32_t get_remote_ip(const struct mg_connection *conn)
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)
static FUNCTION_MAY_BE_UNUSED unsigned long mg_current_thread_id(void)
#define MG_FOPEN_MODE_READ
static constexpr double s
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
struct mg_header http_headers[MG_MAX_HEADERS]
static int is_file_in_memory(const struct mg_connection *conn, const char *path)
int(* mg_websocket_connect_handler)(const struct mg_connection *, void *)
#define SSL_load_error_strings
static void send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int)
#define X509_get_serialNumber
#define SSL_get_app_data(s)
static void process_new_connection(struct mg_connection *conn)
static void * worker_thread_run(struct worker_thread_args *thread_args)
#define PASSWORDS_FILE_NAME
static const char * get_http_version(const struct mg_connection *conn)
#define SSL_OP_NO_COMPRESSION
static void * worker_thread(void *thread_func_param)
static int mg_get_system_info_impl(char *buffer, int buflen)
R__EXTERN C unsigned int sleep(unsigned int seconds)
#define mg_opendir(conn, x)
static int alloc_vprintf(char **out_buf, char *prealloc_buf, size_t prealloc_size, const char *fmt, va_list ap)
static int pull_inner(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
#define SSL_CTX_set_verify
static FUNCTION_MAY_BE_UNUSED void mg_global_lock(void)
const struct mg_request_info * mg_get_request_info(const struct mg_connection *conn)
static int is_valid_http_method(const char *method)
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)
static void delete_file(struct mg_connection *conn, const char *path)
typedef void((*Func_t)())
#define SSL_CTX_set_cipher_list
#define SSL_CTX_set_options(ctx, op)
#define SSLv23_server_method
#define STRUCT_FILE_INITIALIZER
#define mg_realloc_ctx(a, b, c)
void(* mg_websocket_ready_handler)(struct mg_connection *, void *)
static int authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm)
static void set_close_on_exec(SOCKET fd, struct mg_connection *conn)
static void do_ssi_exec(struct mg_connection *conn, char *tag)
static int get_http_header_len(const char *buf, int buflen)
static int event_wait(void *eventhdl)
static int print_dav_dir_entry(struct de *de, void *data)
#define IGNORE_UNUSED_RESULT(a)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
static int send_additional_header(struct mg_connection *conn)
static __inline void * mg_malloc(size_t a)
const char * mg_get_builtin_mime_type(const char *path)
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
struct ssl_ctx_st SSL_CTX
void * mg_get_user_connection_data(const struct mg_connection *conn)
static uint64_t get_random(void)
static void send_options(struct mg_connection *conn)
static int event_signal(void *eventhdl)
SHA_API void SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
void mg_lock_context(struct mg_context *ctx)
void *(* mg_thread_func_t)(void *)
#define SOCKET_TIMEOUT_QUANTUM
static const struct @133 abs_uri_protocols[]
unsigned mg_init_library(unsigned features)
static void mg_set_handler_type(struct mg_context *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)
#define MG_FOPEN_MODE_APPEND
#define SSL_CTX_load_verify_locations
static int is_file_opened(const struct mg_file_access *fileacc)
CIVETWEB_API int mg_handle_form_request(struct mg_connection *conn, struct mg_form_data_handler *fdh)
static pthread_key_t sTlsKey
static int set_gpass_option(struct mg_context *ctx)
static const char * month_names[]
SHA_API void SHA1_Final(unsigned char *digest, SHA_CTX *context)
static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
static int mg_init_library_called
CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
const char * query_string
#define FUNCTION_MAY_BE_UNUSED
static char * mg_strdup(const char *str)
static pthread_mutex_t global_lock_mutex
MD5_STATIC void md5_init(md5_state_t *pms)
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
#define CONF_modules_unload
static void free_context(struct mg_context *ctx)
int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len)
void mg_set_websocket_handler(struct mg_context *ctx, const char *uri, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
static const struct @132 builtin_mime_types[]
static int parse_http_request(char *buf, int len, struct mg_request_info *ri)
void mg_send_http_error(struct mg_connection *conn, int status, const char *fmt,...)
#define SSL_ERROR_WANT_ACCEPT
static int get_month_index(const char *s)
static FUNCTION_MAY_BE_UNUSED int mg_atomic_dec(volatile int *addr)
const char * http_version
#define MG_FOPEN_MODE_NONE
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
static void * load_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw)
struct mg_context * mg_get_context(const struct mg_connection *conn)
static void construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
static void log_access(const struct mg_connection *conn)
int mg_get_system_info(char *buffer, int buflen)
#define SSL_ERROR_SYSCALL
int mg_strncasecmp(const char *s1, const char *s2, size_t len)
static int get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
static void send_authorization_request(struct mg_connection *conn, const char *realm)
static long ssl_get_protocol(int version_id)
static void * realloc2(void *ptr, size_t size)