25 #if !defined(_CRT_SECURE_NO_WARNINGS) 26 #define _CRT_SECURE_NO_WARNINGS 29 #define _WIN32_WINNT 0x0501 32 #if defined(__GNUC__) && !defined(_GNU_SOURCE) 35 #if defined(__linux__) && !defined(_XOPEN_SOURCE) 36 #define _XOPEN_SOURCE 600 38 #ifndef _LARGEFILE_SOURCE 39 #define _LARGEFILE_SOURCE 41 #ifndef _FILE_OFFSET_BITS 42 #define _FILE_OFFSET_BITS 64 44 #ifndef __STDC_FORMAT_MACROS 45 #define __STDC_FORMAT_MACROS 47 #ifndef __STDC_LIMIT_MACROS 48 #define __STDC_LIMIT_MACROS 51 #define __EXTENSIONS__ 52 #define __inline inline 56 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 62 #pragma warning(disable : 4306) 64 #pragma warning(disable : 4127) 66 #pragma warning(disable : 4204) 68 #pragma warning(disable : 4820) 70 #pragma warning(disable : 4668) 72 #pragma warning(disable : 4255) 74 #pragma warning(disable : 4711) 81 #if defined(_MSC_VER) && (_MSC_VER >= 1600) 82 #define mg_static_assert static_assert 83 #elif defined(__cplusplus) && (__cplusplus >= 201103L) 84 #define mg_static_assert static_assert 85 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) 86 #define mg_static_assert _Static_assert 89 #define mg_static_assert(cond, txt) \ 90 extern char static_assert_replacement[(cond) ? 1 : -1] 94 "int data type size check");
96 "pointer data type size check");
102 #ifndef WIN32_LEAN_AND_MEAN 103 #define WIN32_LEAN_AND_MEAN 106 #if defined(__SYMBIAN32__) 109 #define PATH_MAX FILENAME_MAX 118 #ifndef IGNORE_UNUSED_RESULT 119 #define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1)) 123 #include <sys/types.h> 124 #include <sys/stat.h> 131 #include <AvailabilityMacros.h> 134 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12) 136 #define CLOCK_MONOTONIC (1) 137 #define CLOCK_REALTIME (2) 139 #include <sys/time.h> 140 #include <mach/clock.h> 141 #include <mach/mach.h> 142 #include <mach/mach_time.h> 147 int clock_gettime(
int clk_id,
struct timespec *t);
150 clock_gettime(
int clk_id,
struct timespec *t)
152 memset(t, 0,
sizeof(*t));
153 if (clk_id == CLOCK_REALTIME) {
155 int rv = gettimeofday(&now, NULL);
159 t->tv_sec = now.tv_sec;
160 t->tv_nsec = now.tv_usec * 1000;
163 }
else if (clk_id == CLOCK_MONOTONIC) {
164 static uint64_t clock_start_time = 0;
165 static mach_timebase_info_data_t timebase_ifo = {0, 0};
167 uint64_t now = mach_absolute_time();
169 if (clock_start_time == 0) {
170 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
172 assert(mach_status == KERN_SUCCESS);
177 clock_start_time = now;
180 now = (uint64_t)((
double)(now - clock_start_time)
181 * (
double)timebase_ifo.numer
182 / (double)timebase_ifo.denom);
184 t->tv_sec = now / 1000000000;
185 t->tv_nsec = now % 1000000000;
204 #ifndef MAX_WORKER_THREADS 205 #define MAX_WORKER_THREADS (1024 * 64) 207 #ifndef SOCKET_TIMEOUT_QUANTUM 208 #define SOCKET_TIMEOUT_QUANTUM (10000) 212 "worker threads must be a positive number");
214 #if defined(_WIN32) \ 215 && !defined(__SYMBIAN32__) 217 #include <winsock2.h> 218 #include <ws2tcpip.h> 222 #if !defined(PATH_MAX) 223 #define PATH_MAX (MAX_PATH) 226 #if !defined(PATH_MAX) 227 #define PATH_MAX (4096) 234 #define in_port_t u_short 247 #define errno ((int)(GetLastError())) 248 #define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10)) 251 #define MAKEUQUAD(lo, hi) \ 252 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32)) 253 #define RATE_DIFF (10000000) 254 #define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de)) 255 #define SYS2UNIX_TIME(lo, hi) \ 256 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)) 261 #if defined(_MSC_VER) 262 #if (_MSC_VER < 1300) 264 #define STR(x) STRX(x) 265 #define __func__ __FILE__ ":" STR(__LINE__) 266 #define strtoull(x, y, z) ((unsigned __int64)_atoi64(x)) 267 #define strtoll(x, y, z) (_atoi64(x)) 269 #define __func__ __FUNCTION__ 270 #define strtoull(x, y, z) (_strtoui64(x, y, z)) 271 #define strtoll(x, y, z) (_strtoi64(x, y, z)) 275 #define ERRNO ((int)(GetLastError())) 278 #if defined(_WIN64) || defined(__MINGW64__) 279 #define SSL_LIB "ssleay64.dll" 280 #define CRYPTO_LIB "libeay64.dll" 282 #define SSL_LIB "ssleay32.dll" 283 #define CRYPTO_LIB "libeay32.dll" 286 #define O_NONBLOCK (0) 290 #if !defined(EWOULDBLOCK) 291 #define EWOULDBLOCK WSAEWOULDBLOCK 294 #define INT64_FMT "I64d" 295 #define UINT64_FMT "I64u" 297 #define WINCDECL __cdecl 300 #define SHUT_BOTH (2) 301 #define vsnprintf_impl _vsnprintf 302 #define access _access 303 #define mg_sleep(x) (Sleep(x)) 305 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY) 307 #define popen(x, y) (_popen(x, y)) 310 #define pclose(x) (_pclose(x)) 312 #define close(x) (_close(x)) 313 #define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y))) 314 #define RTLD_LAZY (0) 315 #define fseeko(x, y, z) (_lseeki64(_fileno(x), (y), (z)) == -1 ? -1 : 0) 316 #define fdopen(x, y) (_fdopen((x), (y))) 317 #define write(x, y, z) (_write((x), (y), (unsigned)z)) 318 #define read(x, y, z) (_read((x), (y), (unsigned)z)) 319 #define flockfile(x) (EnterCriticalSection(&global_log_file_lock)) 320 #define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock)) 321 #define sleep(x) (Sleep((x)*1000)) 322 #define rmdir(x) (_rmdir(x)) 323 #define timegm(x) (_mkgmtime(x)) 326 #define fileno(x) (_fileno(x)) 329 typedef HANDLE pthread_mutex_t;
330 typedef DWORD pthread_key_t;
331 typedef HANDLE pthread_t;
333 CRITICAL_SECTION threadIdSec;
334 int waitingthreadcount;
335 pthread_t *waitingthreadhdls;
338 #ifndef __clockid_t_defined 339 typedef DWORD clockid_t;
341 #ifndef CLOCK_MONOTONIC 342 #define CLOCK_MONOTONIC (1) 344 #ifndef CLOCK_REALTIME 345 #define CLOCK_REALTIME (2) 348 #if defined(_MSC_VER) && (_MSC_VER >= 1900) 349 #define _TIMESPEC_DEFINED 351 #ifndef _TIMESPEC_DEFINED 360 static int pthread_mutex_lock(pthread_mutex_t *);
361 static int pthread_mutex_unlock(pthread_mutex_t *);
362 static void path_to_unicode(
const struct mg_connection *conn,
368 mg_fgets(
char *buf,
size_t size,
struct file *filep,
char **p);
371 #if defined(HAVE_STDINT) 374 typedef unsigned char uint8_t;
375 typedef unsigned short uint16_t;
376 typedef unsigned int uint32_t;
377 typedef unsigned __int64 uint64_t;
378 typedef __int64 int64_t;
379 #define INT64_MAX (9223372036854775807) 384 char d_name[PATH_MAX];
389 WIN32_FIND_DATAW info;
390 struct dirent result;
393 #if defined(_WIN32) && !defined(POLLIN) 400 #define POLLIN (0x0300) 405 #if defined(_MSC_VER) 406 #pragma comment(lib, "Ws2_32.lib") 412 #include <sys/wait.h> 413 #include <sys/socket.h> 414 #include <sys/poll.h> 415 #include <netinet/in.h> 416 #include <arpa/inet.h> 417 #include <sys/time.h> 418 #include <sys/utsname.h> 420 #include <inttypes.h> 422 #include <netinet/tcp.h> 426 typedef unsigned short int in_port_t;
433 #define vsnprintf_impl vsnprintf 435 #if !defined(NO_SSL_DL) && !defined(NO_SSL) 439 #if defined(__MACH__) 440 #define SSL_LIB "libssl.dylib" 441 #define CRYPTO_LIB "libcrypto.dylib" 443 #if !defined(SSL_LIB) 444 #define SSL_LIB "libssl.so" 446 #if !defined(CRYPTO_LIB) 447 #define CRYPTO_LIB "libcrypto.so" 453 #define closesocket(a) (close(a)) 454 #define mg_mkdir(conn, path, mode) (mkdir(path, mode)) 455 #define mg_remove(conn, x) (remove(x)) 456 #define mg_sleep(x) (usleep((x)*1000)) 457 #define mg_opendir(conn, x) (opendir(x)) 458 #define mg_closedir(x) (closedir(x)) 459 #define mg_readdir(x) (readdir(x)) 460 #define ERRNO (errno) 461 #define INVALID_SOCKET (-1) 462 #define INT64_FMT PRId64 463 #define UINT64_FMT PRIu64 469 #ifndef CLOCK_MONOTONIC 470 #define CLOCK_MONOTONIC CLOCK_REALTIME 481 #define socklen_t int 489 #define va_copy(x, y) ((x) = (y)) 495 #if defined(__MINGW32__) 497 #pragma GCC diagnostic push 498 #pragma GCC diagnostic ignored "-Wunused-function" 502 static CRITICAL_SECTION global_log_file_lock;
506 return GetCurrentThreadId();
513 void (*_ignored)(
void *)
520 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
527 pthread_key_delete(pthread_key_t key)
529 return TlsFree(key) ? 0 : 1;
534 pthread_setspecific(pthread_key_t key,
void *value)
536 return TlsSetValue(key, value) ? 0 : 1;
541 pthread_getspecific(pthread_key_t key)
543 return TlsGetValue(key);
546 #if defined(__MINGW32__) 548 #pragma GCC diagnostic pop 557 #define PASSWORDS_FILE_NAME ".htpasswd" 558 #define CGI_ENVIRONMENT_SIZE (4096) 559 #define MAX_CGI_ENVIR_VARS (256) 560 #define MG_BUF_LEN (8192) 562 #ifndef MAX_REQUEST_SIZE 563 #define MAX_REQUEST_SIZE (16384) 567 "request size length must be a positive number");
569 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) 571 #if !defined(DEBUG_TRACE) 575 static void DEBUG_TRACE_FUNC(
const char *func,
581 DEBUG_TRACE_FUNC(const
char *func,
unsigned line, const
char *fmt, ...)
585 printf(
"*** %lu.%p.%s.%u: ",
586 (
unsigned long)time(NULL),
587 (
void *)pthread_self(),
598 #define DEBUG_TRACE(fmt, ...) \ 599 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__) 602 #define DEBUG_TRACE(fmt, ...) \ 608 #if defined(MEMORY_DEBUGGING) 609 unsigned long mg_memory_debug_blockCount = 0;
610 unsigned long mg_memory_debug_totalMemUsed = 0;
614 mg_malloc_ex(
size_t size,
const char *
file,
unsigned line)
621 *(
size_t *)data = size;
622 mg_memory_debug_totalMemUsed += size;
623 mg_memory_debug_blockCount++;
624 memory = (
void *)(((
char *)
data) +
sizeof(
size_t));
628 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
631 mg_memory_debug_totalMemUsed,
632 mg_memory_debug_blockCount,
636 OutputDebugStringA(mallocStr);
646 mg_calloc_ex(
size_t count,
size_t size,
const char *
file,
unsigned line)
648 void *
data = mg_malloc_ex(size * count, file, line);
650 memset(data, 0, size);
657 mg_free_ex(
void *memory,
const char *file,
unsigned line)
660 void *
data = (
void *)(((
char *)memory) -
sizeof(size_t));
664 size = *(
size_t *)data;
665 mg_memory_debug_totalMemUsed -= size;
666 mg_memory_debug_blockCount--;
668 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
671 mg_memory_debug_totalMemUsed,
672 mg_memory_debug_blockCount,
676 OutputDebugStringA(mallocStr);
687 mg_realloc_ex(
void *memory,
size_t newsize,
const char *file,
unsigned line)
696 data = (
void *)(((
char *)memory) -
sizeof(size_t));
697 oldsize = *(
size_t *)data;
698 _realloc =
realloc(data, newsize +
sizeof(
size_t));
701 mg_memory_debug_totalMemUsed -= oldsize;
703 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
705 (
unsigned long)oldsize,
706 mg_memory_debug_totalMemUsed,
707 mg_memory_debug_blockCount,
711 OutputDebugStringA(mallocStr);
715 mg_memory_debug_totalMemUsed += newsize;
717 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
719 (
unsigned long)newsize,
720 mg_memory_debug_totalMemUsed,
721 mg_memory_debug_blockCount,
725 OutputDebugStringA(mallocStr);
729 *(
size_t *)data = newsize;
730 data = (
void *)(((
char *)
data) +
sizeof(
size_t));
733 OutputDebugStringA(
"MEM: realloc failed\n");
740 data = mg_malloc_ex(newsize, file, line);
744 mg_free_ex(memory, file, line);
750 #define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__) 751 #define mg_calloc(a, b) mg_calloc_ex(a, b, __FILE__, __LINE__) 752 #define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__) 753 #define mg_free(a) mg_free_ex(a, __FILE__, __LINE__) 757 static __inline
void *
763 static __inline
void *
769 static __inline
void *
784 static void mg_vsnprintf(
const struct mg_connection *conn,
791 static void mg_snprintf(
const struct mg_connection *conn,
818 #define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc 819 #define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc 820 #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc 821 #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free 822 #define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf 825 #define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf 828 #define MD5_STATIC static 833 typedef int socklen_t;
835 #define _DARWIN_UNLIMITED_SELECT 837 #define IP_ADDR_STR_LEN (50) 839 #if !defined(MSG_NOSIGNAL) 840 #define MSG_NOSIGNAL (0) 843 #if !defined(SOMAXCONN) 844 #define SOMAXCONN (100) 848 #if !defined(MGSQLEN) 852 #if defined(NO_SSL_DL) 853 #include <openssl/ssl.h> 854 #include <openssl/err.h> 855 #include <openssl/crypto.h> 856 #include <openssl/x509.h> 857 #include <openssl/pem.h> 863 typedef struct ssl_st
SSL;
868 #define SSL_CTRL_OPTIONS (32) 869 #define SSL_CTRL_CLEAR_OPTIONS (77) 870 #define SSL_CTRL_SET_ECDH_AUTO (94) 872 #define SSL_VERIFY_NONE (0) 873 #define SSL_VERIFY_PEER (1) 874 #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2) 875 #define SSL_VERIFY_CLIENT_ONCE (4) 876 #define SSL_OP_ALL ((long)(0x80000BFFUL)) 877 #define SSL_OP_NO_SSLv2 (0x01000000L) 878 #define SSL_OP_NO_SSLv3 (0x02000000L) 879 #define SSL_OP_NO_TLSv1 (0x04000000L) 880 #define SSL_OP_NO_TLSv1_2 (0x08000000L) 881 #define SSL_OP_NO_TLSv1_1 (0x10000000L) 882 #define SSL_OP_SINGLE_DH_USE (0x00100000L) 889 #define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr) 890 #define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr) 891 #define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr) 892 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr) 893 #define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr) 894 #define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr) 895 #define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr) 896 #define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr) 897 #define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr) 898 #define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr) 899 #define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr) 900 #define SSL_CTX_use_PrivateKey_file \ 901 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr) 902 #define SSL_CTX_use_certificate_file \ 903 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr) 904 #define SSL_CTX_set_default_passwd_cb \ 905 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr) 906 #define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr) 907 #define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr) 908 #define SSL_CTX_use_certificate_chain_file \ 909 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr) 910 #define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr) 911 #define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr) 912 #define SSL_CTX_set_verify \ 913 (*(void (*)(SSL_CTX *, \ 915 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr) 916 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr) 917 #define SSL_CTX_load_verify_locations \ 918 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr) 919 #define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr) 920 #define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr) 921 #define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr) 922 #define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr) 923 #define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr) 924 #define SSL_CIPHER_get_name \ 925 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr) 926 #define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr) 927 #define SSL_CTX_set_session_id_context \ 928 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr) 929 #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr) 930 #define SSL_CTX_set_cipher_list \ 931 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr) 932 #define SSL_CTX_set_options(ctx, op) \ 933 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL) 934 #define SSL_CTX_clear_options(ctx, op) \ 935 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL) 936 #define SSL_CTX_set_ecdh_auto(ctx, onoff) \ 937 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL) 939 #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr) 940 #define CRYPTO_set_locking_callback \ 941 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr) 942 #define CRYPTO_set_id_callback \ 943 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr) 944 #define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr) 945 #define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr) 946 #define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr) 947 #define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr) 948 #define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr) 949 #define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr) 950 #define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr) 951 #define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr) 958 static struct ssl_func
ssl_sw[] = {{
"SSL_free", NULL},
959 {
"SSL_accept", NULL},
960 {
"SSL_connect", NULL},
963 {
"SSL_get_error", NULL},
964 {
"SSL_set_fd", NULL},
966 {
"SSL_CTX_new", NULL},
967 {
"SSLv23_server_method", NULL},
968 {
"SSL_library_init", NULL},
969 {
"SSL_CTX_use_PrivateKey_file", NULL},
970 {
"SSL_CTX_use_certificate_file", NULL},
971 {
"SSL_CTX_set_default_passwd_cb", NULL},
972 {
"SSL_CTX_free", NULL},
973 {
"SSL_load_error_strings", NULL},
974 {
"SSL_CTX_use_certificate_chain_file", NULL},
975 {
"SSLv23_client_method", NULL},
976 {
"SSL_pending", NULL},
977 {
"SSL_CTX_set_verify", NULL},
978 {
"SSL_shutdown", NULL},
979 {
"SSL_CTX_load_verify_locations", NULL},
980 {
"SSL_CTX_set_default_verify_paths", NULL},
981 {
"SSL_CTX_set_verify_depth", NULL},
982 {
"SSL_get_peer_certificate", NULL},
983 {
"SSL_get_version", NULL},
984 {
"SSL_get_current_cipher", NULL},
985 {
"SSL_CIPHER_get_name", NULL},
986 {
"SSL_CTX_check_private_key", NULL},
987 {
"SSL_CTX_set_session_id_context", NULL},
988 {
"SSL_CTX_ctrl", NULL},
989 {
"SSL_CTX_set_cipher_list", NULL},
996 static struct ssl_func
crypto_sw[] = {{
"CRYPTO_num_locks", NULL},
997 {
"CRYPTO_set_locking_callback", NULL},
998 {
"CRYPTO_set_id_callback", NULL},
999 {
"ERR_get_error", NULL},
1000 {
"ERR_error_string", NULL},
1001 {
"ERR_remove_state", NULL},
1002 {
"ERR_free_strings", NULL},
1003 {
"ENGINE_cleanup", NULL},
1004 {
"CONF_modules_unload", NULL},
1005 {
"CRYPTO_cleanup_all_ex_data", NULL},
1006 {
"EVP_cleanup", NULL},
1012 #if !defined(NO_CACHING) 1031 struct sockaddr_in sin;
1032 #if defined(USE_IPV6) 1033 struct sockaddr_in6 sin6;
1045 time_t last_modified;
1053 #define STRUCT_FILE_INITIALIZER \ 1055 (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 \ 1064 unsigned char is_ssl;
1065 unsigned char ssl_redir;
1103 #if defined(USE_WEBSOCKET) 1108 #if defined(USE_LUA) 1110 LUA_SCRIPT_EXTENSIONS,
1111 LUA_SERVER_PAGE_EXTENSIONS,
1113 #if defined(USE_DUKTAPE) 1114 DUKTAPE_SCRIPT_EXTENSIONS,
1117 #if defined(USE_WEBSOCKET) 1120 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 1121 LUA_WEBSOCKET_EXTENSIONS,
1127 #if !defined(NO_CACHING) 1152 "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi," 1153 "index.shtml,index.php"},
1155 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
1176 #if defined(USE_WEBSOCKET) 1181 #if defined(USE_LUA) 1186 #if defined(USE_DUKTAPE) 1192 #if defined(USE_WEBSOCKET) 1195 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 1201 #if !defined(NO_CACHING) 1211 "config_options and enum not sync");
1215 struct mg_handler_info {
1239 struct mg_handler_info *next;
1243 volatile int stop_flag;
1250 struct socket *listening_sockets;
1251 in_port_t *listening_ports;
1252 unsigned int num_listening_sockets;
1255 running_worker_threads;
1256 pthread_mutex_t thread_mutex;
1259 struct socket queue[MGSQLEN];
1260 volatile int sq_head;
1261 volatile int sq_tail;
1264 pthread_t masterthreadid;
1267 pthread_t *workerthreadids;
1270 uint64_t auth_nonce_mask;
1271 pthread_mutex_t nonce_mutex;
1272 unsigned long nonce_count;
1277 struct mg_handler_info *handlers;
1279 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 1281 struct mg_shared_lua_websocket_list *shared_lua_websockets;
1285 struct ttimers *timers;
1290 struct mg_connection {
1292 struct mg_context *ctx;
1295 struct socket client;
1296 time_t conn_birth_time;
1298 struct timespec req_time;
1300 int64_t num_bytes_sent;
1301 int64_t content_len;
1302 int64_t consumed_content;
1305 size_t chunk_remainder;
1310 int in_error_handler;
1321 time_t last_throttle_time;
1322 int64_t last_throttle_bytes;
1323 pthread_mutex_t mutex;
1325 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 1326 void *lua_websocket_state;
1336 struct mg_workerTLS {
1338 unsigned long thread_idx;
1339 #if defined(_WIN32) && !defined(__SYMBIAN32__) 1340 HANDLE pthread_cond_helper_mutex;
1346 struct mg_connection *conn;
1352 #if defined(USE_WEBSOCKET) 1355 #define is_websocket_protocol(conn) (0) 1363 #if defined(_WIN32) && !defined(__SYMBIAN32__) 1367 ret = InterlockedIncrement((
volatile long *)addr);
1368 #elif defined(__GNUC__) \ 1369 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) 1370 ret = __sync_add_and_fetch(addr, 1);
1382 #if defined(_WIN32) && !defined(__SYMBIAN32__) 1386 ret = InterlockedDecrement((
volatile long *)addr);
1387 #elif defined(__GNUC__) \ 1388 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) 1389 ret = __sync_sub_and_fetch(addr, 1);
1396 #if !defined(NO_THREAD_NAME) 1397 #if defined(_WIN32) && defined(_MSC_VER) 1401 #pragma pack(push, 8) 1402 typedef struct tagTHREADNAME_INFO {
1409 #elif defined(__linux__) 1410 #include <sys/prctl.h> 1411 #include <sys/sendfile.h> 1418 char threadName[16 + 1];
1421 NULL, NULL, threadName,
sizeof(threadName),
"civetweb-%s", name);
1424 #if defined(_MSC_VER) 1428 THREADNAME_INFO info;
1429 info.dwType = 0x1000;
1430 info.szName = threadName;
1431 info.dwThreadID = ~0U;
1434 RaiseException(0x406D1388,
1436 sizeof(info) /
sizeof(ULONG_PTR),
1437 (ULONG_PTR *)&info);
1439 __except(EXCEPTION_EXECUTE_HANDLER)
1442 #elif defined(__MINGW32__) 1445 #elif defined(__GLIBC__) \ 1446 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12))) 1448 (
void)pthread_setname_np(pthread_self(), threadName);
1449 #elif defined(__linux__) 1451 (
void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
1462 #if defined(MG_LEGACY_INTERFACE) 1464 mg_get_valid_option_names(
void)
1494 if (!conn || !filep) {
1498 if (conn->ctx->callbacks.open_file) {
1499 filep->membuf = conn->ctx->callbacks.open_file(conn, path, &size);
1500 if (filep->membuf != NULL) {
1507 return filep->membuf != NULL;
1518 return filep->membuf != NULL || filep->fp != NULL;
1542 memset(filep, 0,
sizeof(*filep));
1544 if (stat(path, &st) == 0) {
1545 filep->size = (uint64_t)(st.st_size);
1550 wchar_t wbuf[PATH_MAX], wmode[20];
1551 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
1552 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode,
ARRAY_SIZE(wmode));
1553 filep->fp = _wfopen(wbuf, wmode);
1556 filep->fp = fopen(path, mode);
1567 if (filep != NULL && filep->fp != NULL) {
1576 for (; *src !=
'\0' && n > 1; n--) {
1586 return tolower(*(
const unsigned char *)s);
1598 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
1612 }
while (diff == 0 && s1[-1] !=
'\0');
1623 if ((p = (
char *)
mg_malloc(len + 1)) != NULL) {
1641 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
1643 if (big_len >= small_len) {
1644 for (i = 0; i <= (big_len - small_len); i++) {
1672 #pragma clang diagnostic push 1673 #pragma clang diagnostic ignored "-Wformat-nonliteral" 1679 ok = (n >= 0) && ((
size_t)n < buflen);
1682 #pragma clang diagnostic pop 1694 "truncating vsnprintf buffer: [%.*s]",
1695 (
int)((buflen > 200) ? 200 : (buflen - 1)),
1697 n = (int)buflen - 1;
1739 }
else if (!ctx || ctx->config[i] == NULL) {
1742 return ctx->config[i];
1750 return (conn == NULL) ? (
struct mg_context *)NULL : (conn->ctx);
1757 return (ctx == NULL) ? NULL : ctx->user_data;
1765 conn->request_info.conn_data =
data;
1774 return conn->request_info.conn_data;
1781 mg_get_ports(
const struct mg_context *ctx,
size_t size,
int *ports,
int *ssl)
1787 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
1788 ssl[i] = ctx->listening_sockets[i].is_ssl;
1789 ports[i] = ctx->listening_ports[i];
1805 memset(ports, 0,
sizeof(*ports) * (
size_t)size);
1809 if (!ctx->listening_sockets || !ctx->listening_ports) {
1813 for (i = 0; (i < size) && (i < (
int)ctx->num_listening_sockets); i++) {
1815 ports[
cnt].
port = ctx->listening_ports[i];
1816 ports[
cnt].
is_ssl = ctx->listening_sockets[i].is_ssl;
1819 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
1823 }
else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
1843 if (usa->sa.sa_family == AF_INET) {
1844 getnameinfo(&usa->sa,
1852 #if defined(USE_IPV6) 1853 else if (usa->sa.sa_family == AF_INET6) {
1854 getnameinfo(&usa->sa,
1873 tm = ((t != NULL) ? gmtime(t) : NULL);
1875 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", tm);
1877 mg_strlcpy(buf,
"Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
1878 buf[buf_len - 1] =
'\0';
1887 return (
double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0
E-9
1888 + (
double)(ts_now->tv_sec - ts_before->tv_sec);
1894 mg_cry(
const struct mg_connection *conn,
const char *fmt, ...)
1904 buf[
sizeof(buf) - 1] = 0;
1914 if ((conn->ctx->callbacks.log_message == NULL)
1915 || (conn->ctx->callbacks.log_message(conn, buf) == 0)) {
1926 if (fi.fp != NULL) {
1928 timestamp = time(NULL);
1932 "[%010lu] [error] [client %s] ",
1933 (
unsigned long)timestamp,
1936 if (conn->request_info.request_method != NULL) {
1939 conn->request_info.request_method,
1940 conn->request_info.request_uri);
1943 fprintf(fi.fp,
"%s", buf);
1955 static struct mg_connection *
1956 fc(
struct mg_context *ctx)
1958 static struct mg_connection fake_connection;
1959 fake_connection.ctx = ctx;
1960 return &fake_connection;
1977 return &conn->request_info;
1987 const char *delimiters,
1988 const char *whitespace,
1991 char *p, *begin_word, *end_word, *end_whitespace;
1994 end_word = begin_word + strcspn(begin_word, delimiters);
1997 if (end_word > begin_word) {
1999 while (*p == quotechar) {
2005 if (*end_word !=
'\0') {
2006 size_t end_off = strcspn(end_word + 1, delimiters);
2007 memmove(p, end_word, end_off + 1);
2009 end_word += end_off + 1;
2015 for (p++; p < end_word; p++) {
2020 if (*end_word ==
'\0') {
2023 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
2025 for (p = end_word; p < end_whitespace; p++) {
2029 *buf = end_whitespace;
2039 skip(
char **buf,
const char *delimiters)
2041 return skip_quoted(buf, delimiters, delimiters, 0);
2069 return get_header(&conn->request_info, name);
2085 if (val == NULL || list == NULL || *list ==
'\0') {
2090 while (*list ==
' ' || *list ==
'\t')
2094 if ((list = strchr(val->ptr,
',')) != NULL) {
2096 val->len = ((size_t)(list - val->ptr));
2100 list = val->ptr + strlen(val->ptr);
2101 val->len = ((size_t)(list - val->ptr));
2105 end = (int)val->len - 1;
2106 while (end >= 0 && (val->ptr[end] ==
' ' || val->ptr[end] ==
'\t'))
2108 val->len = (size_t)(end + 1);
2110 if (val->len == 0) {
2115 if (eq_val != NULL) {
2119 eq_val->ptr = (
const char *)memchr(val->ptr,
'=', val->len);
2120 if (eq_val->ptr != NULL) {
2122 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
2123 val->len = ((
size_t)(eq_val->ptr - val->ptr)) - 1;
2140 assert(option != NULL);
2141 assert(option[0] !=
'\0');
2143 while ((header =
next_option(header, &opt_vec, &eq_vec)) != NULL) {
2159 if ((or_str = (
const char *)memchr(pattern,
'|', pattern_len)) != NULL) {
2160 res =
match_prefix(pattern, (
size_t)(or_str - pattern), str);
2162 (
size_t)((pattern + pattern_len)
2167 for (i = 0, j = 0; i < pattern_len; i++, j++) {
2168 if (pattern[i] ==
'?' && str[j] !=
'\0') {
2170 }
else if (pattern[i] ==
'$') {
2171 return str[j] ==
'\0' ? j : -1;
2172 }
else if (pattern[i] ==
'*') {
2174 if (pattern[i] ==
'*') {
2176 len = (int)strlen(str + j);
2178 len = (int)strcspn(str + j,
"/");
2180 if (i == pattern_len) {
2184 res =
match_prefix(pattern + i, pattern_len - i, str + j + len);
2185 }
while (res == -1 && len-- > 0);
2186 return res == -1 ? -1 : j + res + len;
2202 const char *http_version = conn->request_info.http_version;
2204 if (conn->must_close || conn->internal_error || conn->status_code == 401
2207 || (header == NULL && http_version
2208 && 0 != strcmp(http_version,
"1.1"))) {
2220 if (!conn || !conn->ctx) {
2240 "Cache-Control: no-cache, no-store, " 2241 "must-revalidate, private, max-age=0\r\n" 2242 "Pragma: no-cache\r\n" 2250 #if !defined(NO_CACHING) 2270 return mg_printf(conn,
"Cache-Control: max-age=%u\r\n", (
unsigned)max_age);
2279 struct file *filep);
2282 mg_stat(
struct mg_connection *conn,
const char *path,
struct file *filep);
2292 switch (response_code) {
2297 return "Switching Protocols";
2299 return "Processing";
2309 return "Non-Authoritative Information";
2311 return "No Content";
2313 return "Reset Content";
2315 return "Partial Content";
2317 return "Multi-Status";
2319 return "Already Reported";
2326 return "Multiple Choices";
2328 return "Moved Permanently";
2334 return "Not Modified";
2338 return "Temporary Redirect";
2340 return "Permanent Redirect";
2344 return "Bad Request";
2346 return "Unauthorized";
2348 return "Payment Required";
2354 return "Method Not Allowed";
2356 return "Not Acceptable";
2358 return "Proxy Authentication Required";
2360 return "Request Time-out";
2366 return "Length Required";
2368 return "Precondition Failed";
2370 return "Request Entity Too Large";
2372 return "Request-URI Too Large";
2374 return "Unsupported Media Type";
2376 return "Requested range not satisfiable";
2378 return "Expectation Failed";
2381 return "Misdirected Request";
2383 return "Unproccessable entity";
2388 return "Failed Dependency";
2392 return "Upgrade Required";
2395 return "Precondition Required";
2397 return "Too Many Requests";
2400 return "Request Header Fields Too Large";
2403 return "Unavailable For Legal Reasons";
2408 return "Internal Server Error";
2410 return "Not Implemented";
2412 return "Bad Gateway";
2414 return "Service Unavailable";
2416 return "Gateway Time-out";
2418 return "HTTP Version not supported";
2420 return "Variant Also Negotiates";
2422 return "Insufficient Storage";
2425 return "Loop Detected";
2428 return "Not Extended";
2430 return "Network Authentication Required";
2435 return "I am a teapot";
2437 return "Authentication Timeout";
2439 return "Enhance Your Calm";
2441 return "Login Timeout";
2443 return "Bandwidth Limit Exceeded";
2448 mg_cry(conn,
"Unknown HTTP response code: %u", response_code);
2452 if (response_code >= 100 && response_code < 200) {
2454 return "Information";
2456 if (response_code >= 200 && response_code < 300) {
2460 if (response_code >= 300 && response_code < 400) {
2462 return "Redirection";
2464 if (response_code >= 400 && response_code < 500) {
2466 return "Client Error";
2468 if (response_code >= 500 && response_code < 600) {
2470 return "Server Error";
2485 send_http_error(struct mg_connection *conn,
int status, const
char *fmt, ...)
2489 int len, i, page_handler_found, scope, truncated;
2491 time_t curtime = time(NULL);
2492 const char *error_handler = NULL;
2494 const char *error_page_file_ext, *tstr;
2502 conn->status_code = status;
2503 if (conn->in_error_handler || conn->ctx->callbacks.http_error == NULL
2504 || conn->ctx->callbacks.http_error(conn, status)) {
2505 if (!conn->in_error_handler) {
2508 error_page_file_ext = conn->ctx->config[
INDEX_FILES];
2509 page_handler_found = 0;
2510 if (error_handler != NULL) {
2511 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
2547 len = (int)strlen(buf);
2549 tstr = strchr(error_page_file_ext,
'.');
2552 for (i = 1; i < 32 && tstr[i] != 0 && tstr[i] !=
',';
2554 buf[len + i - 1] = tstr[i];
2555 buf[len + i - 1] = 0;
2556 if (
mg_stat(conn, buf, &error_page_file)) {
2557 page_handler_found = 1;
2560 tstr = strchr(tstr + i,
'.');
2565 if (page_handler_found) {
2566 conn->in_error_handler = 1;
2568 conn->in_error_handler = 0;
2576 conn->must_close = 1;
2577 mg_printf(conn,
"HTTP/1.1 %d %s\r\n", status, status_text);
2581 "Connection: close\r\n\r\n",
2585 if (status > 199 && status != 204 && status != 304) {
2587 mg_printf(conn,
"Error %d: %s\n", status, status_text);
2604 #if defined(_WIN32) && !defined(__SYMBIAN32__) 2607 #if defined(__MINGW32__) 2609 #pragma GCC diagnostic push 2610 #pragma GCC diagnostic ignored "-Wunused-function" 2615 pthread_mutex_init(pthread_mutex_t *mutex,
void *unused)
2618 *mutex = CreateMutex(NULL,
FALSE, NULL);
2619 return *mutex == NULL ? -1 : 0;
2624 pthread_mutex_destroy(pthread_mutex_t *mutex)
2626 return CloseHandle(*mutex) == 0 ? -1 : 0;
2631 pthread_mutex_lock(pthread_mutex_t *mutex)
2633 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
2637 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS 2639 pthread_mutex_trylock(pthread_mutex_t *mutex)
2641 switch (WaitForSingleObject(*mutex, 0)) {
2653 pthread_mutex_unlock(pthread_mutex_t *mutex)
2655 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
2659 #ifndef WIN_PTHREADS_TIME_H 2661 clock_gettime(clockid_t clk_id,
struct timespec *tp)
2667 static double perfcnt_per_sec = 0.0;
2670 memset(tp, 0,
sizeof(*tp));
2671 if (clk_id == CLOCK_REALTIME) {
2672 GetSystemTimeAsFileTime(&ft);
2673 li.LowPart = ft.dwLowDateTime;
2674 li.HighPart = ft.dwHighDateTime;
2675 li.QuadPart -= 116444736000000000;
2676 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
2677 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
2679 }
else if (clk_id == CLOCK_MONOTONIC) {
2680 if (perfcnt_per_sec == 0.0) {
2681 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
2682 perfcnt_per_sec = 1.0 / li.QuadPart;
2684 if (perfcnt_per_sec != 0.0) {
2685 QueryPerformanceCounter((LARGE_INTEGER *)&li);
2686 d = li.QuadPart * perfcnt_per_sec;
2687 tp->tv_sec = (time_t)d;
2689 tp->tv_nsec = (long)(d * 1.0E9);
2704 InitializeCriticalSection(&cv->threadIdSec);
2705 cv->waitingthreadcount = 0;
2706 cv->waitingthreadhdls =
2708 return (cv->waitingthreadhdls != NULL) ? 0 : -1;
2714 pthread_mutex_t *mutex,
2715 const struct timespec *abstime)
2717 struct mg_workerTLS *tls =
2718 (
struct mg_workerTLS *)pthread_getspecific(sTlsKey);
2720 struct timespec tsnow;
2721 int64_t nsnow, nswaitabs, nswaitrel;
2724 EnterCriticalSection(&cv->threadIdSec);
2726 cv->waitingthreadhdls[cv->waitingthreadcount] =
2727 tls->pthread_cond_helper_mutex;
2728 cv->waitingthreadcount++;
2729 LeaveCriticalSection(&cv->threadIdSec);
2732 clock_gettime(CLOCK_REALTIME, &tsnow);
2733 nsnow = (((int64_t)tsnow.tv_sec) * 1000000000) + tsnow.tv_nsec;
2735 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
2736 nswaitrel = nswaitabs - nsnow;
2737 if (nswaitrel < 0) {
2740 mswaitrel = (DWORD)(nswaitrel / 1000000);
2742 mswaitrel = INFINITE;
2745 pthread_mutex_unlock(mutex);
2747 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
2748 pthread_mutex_lock(mutex);
2757 return pthread_cond_timedwait(cv, mutex, NULL);
2768 EnterCriticalSection(&cv->threadIdSec);
2769 if (cv->waitingthreadcount) {
2770 wkup = cv->waitingthreadhdls[0];
2771 ok = SetEvent(wkup);
2773 for (i = 1; i < cv->waitingthreadcount; i++) {
2774 cv->waitingthreadhdls[i - 1] = cv->waitingthreadhdls[i];
2776 cv->waitingthreadcount--;
2780 LeaveCriticalSection(&cv->threadIdSec);
2789 EnterCriticalSection(&cv->threadIdSec);
2790 while (cv->waitingthreadcount) {
2791 pthread_cond_signal(cv);
2793 LeaveCriticalSection(&cv->threadIdSec);
2802 EnterCriticalSection(&cv->threadIdSec);
2803 assert(cv->waitingthreadcount == 0);
2804 mg_free(cv->waitingthreadhdls);
2805 cv->waitingthreadhdls = 0;
2806 LeaveCriticalSection(&cv->threadIdSec);
2807 DeleteCriticalSection(&cv->threadIdSec);
2813 #if defined(__MINGW32__) 2815 #pragma GCC diagnostic pop 2821 change_slashes_to_backslashes(
char *path)
2825 for (i = 0; path[i] !=
'\0'; i++) {
2826 if (path[i] ==
'/') {
2832 if ((path[i] ==
'\\') && (i > 0)) {
2833 while (path[i + 1] ==
'\\' || path[i + 1] ==
'/') {
2834 (
void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
2842 mg_wcscasecmp(
const wchar_t *s1,
const wchar_t *s2)
2847 diff = tolower(*s1) - tolower(*s2);
2850 }
while (diff == 0 && s1[-1] !=
'\0');
2859 path_to_unicode(
const struct mg_connection *conn,
2864 char buf[PATH_MAX], buf2[PATH_MAX];
2865 wchar_t wbuf2[MAX_PATH + 1];
2866 DWORD long_len, err;
2867 int (*fcompare)(
const wchar_t *,
const wchar_t *) = mg_wcscasecmp;
2870 change_slashes_to_backslashes(buf);
2874 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
2875 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int)wbuf_len);
2876 WideCharToMultiByte(
2877 CP_UTF8, 0, wbuf, (
int)wbuf_len, buf2,
sizeof(buf2), NULL, NULL);
2878 if (strcmp(buf, buf2) != 0) {
2894 memset(wbuf2, 0,
ARRAY_SIZE(wbuf2) *
sizeof(
wchar_t));
2895 long_len = GetLongPathNameW(wbuf, wbuf2,
ARRAY_SIZE(wbuf2) - 1);
2896 if (long_len == 0) {
2897 err = GetLastError();
2898 if (err == ERROR_FILE_NOT_FOUND) {
2903 if ((long_len >=
ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
2910 #if defined(_WIN32_WCE) 2913 #if defined(__MINGW32__) 2915 #pragma GCC diagnostic push 2916 #pragma GCC diagnostic ignored "-Wunused-function" 2928 SystemTimeToFileTime(&st, &ft);
2929 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
2931 if (ptime != NULL) {
2940 localtime(
const time_t *ptime,
struct tm *ptm)
2942 int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
2945 TIME_ZONE_INFORMATION tzinfo;
2951 *(int64_t *)&ft = t;
2952 FileTimeToLocalFileTime(&ft, &lft);
2953 FileTimeToSystemTime(&lft, &st);
2954 ptm->tm_year = st.wYear - 1900;
2955 ptm->tm_mon = st.wMonth - 1;
2956 ptm->tm_wday = st.wDayOfWeek;
2957 ptm->tm_mday = st.wDay;
2958 ptm->tm_hour = st.wHour;
2959 ptm->tm_min = st.wMinute;
2960 ptm->tm_sec = st.wSecond;
2963 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
2970 gmtime(
const time_t *ptime,
struct tm *ptm)
2973 return localtime(ptime, ptm);
2978 strftime(
char *dst,
size_t dst_size,
const char *fmt,
const struct tm *tm)
2980 (
void)
mg_snprintf(NULL, dst, dst_size,
"implement strftime() for WinCE");
2985 #if defined(__MINGW32__) 2987 #pragma GCC diagnostic pop 2998 path_cannot_disclose_cgi(
const char *path)
3000 static const char *allowed_last_characters =
"_-";
3001 int last = path[strlen(path) - 1];
3002 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
3007 mg_stat(
struct mg_connection *conn,
const char *path,
struct file *filep)
3009 wchar_t wbuf[PATH_MAX];
3010 WIN32_FILE_ATTRIBUTE_DATA info;
3011 time_t creation_time;
3016 memset(filep, 0,
sizeof(*filep));
3021 filep->last_modified = time(NULL);
3031 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
3032 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
3033 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
3034 filep->last_modified =
3035 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
3036 info.ftLastWriteTime.dwHighDateTime);
3042 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
3043 info.ftCreationTime.dwHighDateTime);
3044 if (creation_time > filep->last_modified) {
3045 filep->last_modified = creation_time;
3048 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
3053 if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
3054 memset(filep, 0,
sizeof(*filep));
3066 mg_remove(
const struct mg_connection *conn,
const char *path)
3068 wchar_t wbuf[PATH_MAX];
3069 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
3070 return DeleteFileW(wbuf) ? 0 : -1;
3075 mg_mkdir(
const struct mg_connection *conn,
const char *path,
int mode)
3077 wchar_t wbuf[PATH_MAX];
3079 path_to_unicode(conn, path, wbuf,
ARRAY_SIZE(wbuf));
3080 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
3086 #if defined(__MINGW32__) 3088 #pragma GCC diagnostic push 3089 #pragma GCC diagnostic ignored "-Wunused-function" 3098 wchar_t wpath[PATH_MAX];
3102 SetLastError(ERROR_BAD_ARGUMENTS);
3103 }
else if ((dir = (DIR *)
mg_malloc(
sizeof(*dir))) == NULL) {
3104 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3106 path_to_unicode(conn, name, wpath,
ARRAY_SIZE(wpath));
3107 attrs = GetFileAttributesW(wpath);
3108 if (attrs != 0xFFFFFFFF && ((attrs & FILE_ATTRIBUTE_DIRECTORY)
3109 == FILE_ATTRIBUTE_DIRECTORY)) {
3110 (
void)wcscat(wpath,
L"\\*");
3111 dir->handle = FindFirstFileW(wpath, &dir->info);
3112 dir->result.d_name[0] =
'\0';
3130 result = FindClose(dir->handle) ? 0 : -1;
3135 SetLastError(ERROR_BAD_ARGUMENTS);
3142 static struct dirent *
3145 struct dirent *result = 0;
3149 result = &dir->result;
3150 (
void)WideCharToMultiByte(CP_UTF8,
3152 dir->info.cFileName,
3155 sizeof(result->d_name),
3159 if (!FindNextFileW(dir->handle, &dir->info)) {
3160 (
void)FindClose(dir->handle);
3165 SetLastError(ERROR_FILE_NOT_FOUND);
3168 SetLastError(ERROR_BAD_ARGUMENTS);
3177 poll(
struct pollfd *pfd,
unsigned int n,
int milliseconds)
3185 memset(&tv, 0,
sizeof(tv));
3186 tv.tv_sec = milliseconds / 1000;
3187 tv.tv_usec = (milliseconds % 1000) * 1000;
3190 for (i = 0; i <
n; i++) {
3191 FD_SET((SOCKET)pfd[i].fd, &
set);
3194 if (pfd[i].fd > maxfd) {
3199 if ((result = select((
int)maxfd + 1, &
set, NULL, NULL, &tv)) > 0) {
3200 for (i = 0; i <
n; i++) {
3201 if (FD_ISSET(pfd[i].fd, &
set)) {
3202 pfd[i].revents = POLLIN;
3211 #if defined(__MINGW32__) 3213 #pragma GCC diagnostic pop 3221 (
void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
3228 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) 3231 return ((_beginthread((
void(__cdecl *)(
void *))f, USE_STACK_SIZE, p)
3232 == ((uintptr_t)(-1
L)))
3237 (_beginthread((
void(__cdecl *)(
void *))f, 0, p) == ((uintptr_t)(-1
L)))
3248 pthread_t *threadidptr)
3251 HANDLE threadhandle;
3254 uip = _beginthreadex(NULL, 0, (
unsigned(__stdcall *)(
void *))f, p, 0, NULL);
3255 threadhandle = (HANDLE)uip;
3256 if ((uip != (uintptr_t)(-1
L)) && (threadidptr != NULL)) {
3257 *threadidptr = threadhandle;
3273 dwevent = WaitForSingleObject(threadid, INFINITE);
3274 if (dwevent == WAIT_FAILED) {
3277 if (dwevent == WAIT_OBJECT_0) {
3278 CloseHandle(threadid);
3286 #if !defined(NO_SSL_DL) 3289 #if defined(__MINGW32__) 3291 #pragma GCC diagnostic push 3292 #pragma GCC diagnostic ignored "-Wunused-function" 3297 dlopen(
const char *dll_name,
int flags)
3299 wchar_t wbuf[PATH_MAX];
3301 path_to_unicode(NULL, dll_name, wbuf,
ARRAY_SIZE(wbuf));
3302 return LoadLibraryW(wbuf);
3307 dlclose(
void *handle)
3311 if (FreeLibrary((HMODULE)handle) != 0) {
3321 #if defined(__MINGW32__) 3323 #pragma GCC diagnostic pop 3329 #if !defined(NO_CGI) 3333 kill(pid_t pid,
int sig_num)
3335 (
void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
3336 (
void)CloseHandle((HANDLE)pid);
3342 trim_trailing_whitespaces(
char *
s)
3344 char *
e = s + strlen(s) - 1;
3345 while (e > s && isspace(*(
unsigned char *)e)) {
3362 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
3363 cmdline[PATH_MAX], buf[PATH_MAX];
3367 PROCESS_INFORMATION
pi = {0};
3371 memset(&si, 0,
sizeof(si));
3374 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
3375 si.wShowWindow = SW_HIDE;
3377 me = GetCurrentProcess();
3379 (HANDLE)_get_osfhandle(fdin[0]),
3384 DUPLICATE_SAME_ACCESS);
3386 (HANDLE)_get_osfhandle(fdout[1]),
3391 DUPLICATE_SAME_ACCESS);
3393 (HANDLE)_get_osfhandle(fderr[1]),
3398 DUPLICATE_SAME_ACCESS);
3403 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
3404 HANDLE_FLAG_INHERIT,
3406 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
3407 HANDLE_FLAG_INHERIT,
3409 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
3410 HANDLE_FLAG_INHERIT,
3415 if (interp == NULL) {
3416 buf[0] = buf[1] =
'\0';
3420 conn, &truncated, cmdline,
sizeof(cmdline),
"%s/%s", dir, prog);
3423 pi.hProcess = (pid_t)-1;
3427 if (
mg_fopen(conn, cmdline,
"r", &file)) {
3428 p = (
char *)file.membuf;
3429 mg_fgets(buf,
sizeof(buf), &file, &p);
3431 buf[
sizeof(buf) - 1] =
'\0';
3434 if (buf[0] ==
'#' && buf[1] ==
'!') {
3435 trim_trailing_whitespaces(buf + 2);
3442 if (interp[0] !=
'\0') {
3443 GetFullPathNameA(interp,
sizeof(full_interp), full_interp, NULL);
3444 interp = full_interp;
3446 GetFullPathNameA(dir,
sizeof(full_dir), full_dir, NULL);
3448 if (interp[0] !=
'\0') {
3453 "\"%s\" \"%s\\%s\"",
3468 pi.hProcess = (pid_t)-1;
3473 if (CreateProcessA(NULL,
3478 CREATE_NEW_PROCESS_GROUP,
3484 conn,
"%s: CreateProcess(%s): %ld", __func__, cmdline, (
long)
ERRNO);
3485 pi.hProcess = (pid_t)-1;
3490 (
void)CloseHandle(si.hStdOutput);
3491 (
void)CloseHandle(si.hStdError);
3492 (
void)CloseHandle(si.hStdInput);
3493 if (pi.hThread != NULL) {
3494 (
void)CloseHandle(pi.hThread);
3497 return (pid_t)pi.hProcess;
3505 unsigned long on = 1;
3506 return ioctlsocket(sock, (
long)FIONBIO, &on);
3512 mg_stat(
struct mg_connection *conn,
const char *path,
struct file *filep)
3518 memset(filep, 0,
sizeof(*filep));
3524 if (0 == stat(path, &st)) {
3525 filep->size = (uint64_t)(st.st_size);
3526 filep->last_modified = st.st_mtime;
3527 filep->is_directory = S_ISDIR(st.st_mode);
3538 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
3541 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
3552 pthread_t thread_id;
3553 pthread_attr_t attr;
3556 (
void)pthread_attr_init(&attr);
3557 (
void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3559 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) 3562 (
void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
3565 result = pthread_create(&thread_id, &attr, func, param);
3566 pthread_attr_destroy(&attr);
3576 pthread_t *threadidptr)
3578 pthread_t thread_id;
3579 pthread_attr_t attr;
3582 (
void)pthread_attr_init(&attr);
3584 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) 3587 (
void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
3590 result = pthread_create(&thread_id, &attr, func, param);
3591 pthread_attr_destroy(&attr);
3592 if ((result == 0) && (threadidptr != NULL)) {
3593 *threadidptr = thread_id;
3605 result = pthread_join(threadid, NULL);
3630 if ((pid = fork()) == -1) {
3634 "Error: Creating CGI process\nfork(): %s",
3636 }
else if (pid == 0) {
3638 if (chdir(dir) != 0) {
3639 mg_cry(conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
3640 }
else if (dup2(fdin[0], 0) == -1) {
3642 "%s: dup2(%d, 0): %s",
3646 }
else if (dup2(fdout[1], 1) == -1) {
3648 "%s: dup2(%d, 1): %s",
3652 }
else if (dup2(fderr[1], 2) == -1) {
3654 "%s: dup2(%d, 2): %s",
3676 signal(SIGCHLD, SIG_DFL);
3679 if (interp == NULL) {
3680 (
void)execle(prog, prog, NULL, envp);
3682 "%s: execle(%s): %s",
3687 (
void)execle(interp, interp, prog, NULL, envp);
3689 "%s: execle(%s %s): %s",
3709 flags = fcntl(sock, F_GETFL, 0);
3710 (
void)fcntl(sock, F_SETFL, flags | O_NONBLOCK);
3722 static uint64_t lfsr = 0;
3723 static uint64_t lcg = 0;
3724 struct timespec now;
3726 memset(&now, 0,
sizeof(now));
3727 clock_gettime(CLOCK_MONOTONIC, &now);
3732 lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
3733 ^ ((uint64_t)(ptrdiff_t)&now) ^ (((uint64_t)time(NULL)) << 33);
3734 lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
3735 + (uint64_t)(ptrdiff_t)&now;
3739 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
3741 lcg = lcg * 6364136223846793005 + 1442695040888963407;
3747 return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec);
3762 struct timespec start, now;
3768 typedef size_t len_t;
3772 memset(&start, 0,
sizeof(start));
3773 memset(&now, 0,
sizeof(now));
3774 clock_gettime(CLOCK_MONOTONIC, &start);
3794 if ((err == 5 ) && (n == -1)) {
3806 n = (int)fwrite(buf, 1, (
size_t)len, fp);
3815 err = (n < 0) ?
ERRNO : 0;
3818 if (ctx->stop_flag) {
3822 if ((n > 0) || (n == 0 && len == 0)) {
3844 clock_gettime(CLOCK_MONOTONIC, &now);
3847 }
while ((timeout <= 0) || (
mg_difftimespec(&now, &start) <= timeout));
3864 double timeout = -1.0;
3865 int64_t
n, nwritten = 0;
3875 while (len > 0 && ctx->stop_flag == 0) {
3876 n =
push(ctx, fp, sock, ssl, buf + nwritten, (
int)len, timeout);
3878 if (nwritten == 0) {
3882 }
else if (n == 0) {
3897 pull(FILE *fp,
struct mg_connection *conn,
char *buf,
int len,
double timeout)
3900 struct timespec start, now;
3905 typedef size_t len_t;
3909 memset(&start, 0,
sizeof(start));
3910 memset(&now, 0,
sizeof(now));
3911 clock_gettime(CLOCK_MONOTONIC, &start);
3920 nread = (int)read(fileno(fp), buf, (size_t)len);
3921 err = (nread < 0) ?
ERRNO : 0;
3924 }
else if (conn->ssl != NULL) {
3925 nread =
SSL_read(conn->ssl, buf, len);
3928 if ((err == 5 ) && (nread == -1)) {
3940 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
3941 err = (nread < 0) ?
ERRNO : 0;
3944 if (conn->ctx->stop_flag) {
3948 if ((nread > 0) || (nread == 0 && len == 0)) {
3959 if (err == WSAEWOULDBLOCK) {
3962 }
else if (err == WSAETIMEDOUT) {
3974 if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) {
3992 clock_gettime(CLOCK_MONOTONIC, &now);
3994 }
while ((timeout <= 0) || (
mg_difftimespec(&now, &start) <= timeout));
4002 pull_all(FILE *fp,
struct mg_connection *conn,
char *buf,
int len)
4005 double timeout = -1.0;
4011 while (len > 0 && conn->ctx->stop_flag == 0) {
4012 n =
pull(fp, conn, buf + nread, len, timeout);
4018 }
else if (n == 0) {
4021 conn->consumed_content +=
n;
4042 to_read =
sizeof(buf);
4044 if (conn->is_chunked) {
4047 while (conn->is_chunked == 1) {
4048 nread =
mg_read(conn, buf, to_read);
4056 while (conn->consumed_content < conn->content_len) {
4058 > (
size_t)(conn->content_len - conn->consumed_content)) {
4059 to_read = (size_t)(conn->content_len - conn->consumed_content);
4062 nread =
mg_read(conn, buf, to_read);
4074 int64_t
n, buffered_len, nread;
4076 (int64_t)(len > INT_MAX ? INT_MAX : len);
4087 if (conn->consumed_content == 0 && conn->content_len == -1) {
4088 conn->content_len = INT64_MAX;
4089 conn->must_close = 1;
4093 if (conn->consumed_content < conn->content_len) {
4095 int64_t left_to_read = conn->content_len - conn->consumed_content;
4096 if (left_to_read < len64) {
4099 len64 = left_to_read;
4103 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
4104 - conn->consumed_content;
4105 if (buffered_len > 0) {
4106 if (len64 < buffered_len) {
4107 buffered_len = len64;
4109 body = conn->buf + conn->request_len + conn->consumed_content;
4110 memcpy(buf, body, (
size_t)buffered_len);
4111 len64 -= buffered_len;
4112 conn->consumed_content += buffered_len;
4113 nread += buffered_len;
4114 buf = (
char *)buf + buffered_len;
4120 if ((n =
pull_all(NULL, conn, (
char *)buf, (
int)len64)) >= 0) {
4123 nread = (nread > 0 ? nread :
n);
4137 conn->content_len++;
4146 mg_read(
struct mg_connection *conn,
void *buf,
size_t len)
4148 if (len > INT_MAX) {
4156 if (conn->is_chunked) {
4157 size_t all_read = 0;
4161 if (conn->is_chunked == 2) {
4166 if (conn->chunk_remainder) {
4170 ((conn->chunk_remainder > len) ? (len)
4171 : (conn->chunk_remainder));
4173 conn->content_len += (int)read_now;
4176 all_read += (size_t)read_ret;
4178 conn->chunk_remainder -= read_now;
4181 if (conn->chunk_remainder == 0) {
4195 unsigned long chunkSize = 0;
4197 for (i = 0; i < ((int)
sizeof(lenbuf) - 1); i++) {
4199 if (i > 0 && lenbuf[i] ==
'\r' && lenbuf[i - 1] !=
'\r') {
4202 if (i > 1 && lenbuf[i] ==
'\n' && lenbuf[i - 1] ==
'\r') {
4204 chunkSize = strtoul(lenbuf, &end, 16);
4205 if (chunkSize == 0) {
4207 conn->is_chunked = 2;
4211 if (!isalnum(lenbuf[i])) {
4216 if ((end == NULL) || (*end !=
'\r')) {
4220 if (chunkSize == 0) {
4224 conn->chunk_remainder = chunkSize;
4228 return (
int)all_read;
4235 mg_write(
struct mg_connection *conn,
const void *buf,
size_t len)
4238 int64_t
n,
total, allowed;
4244 if (conn->throttle > 0) {
4245 if ((now = time(NULL)) != conn->last_throttle_time) {
4246 conn->last_throttle_time = now;
4247 conn->last_throttle_bytes = 0;
4249 allowed = conn->throttle - conn->last_throttle_bytes;
4250 if (allowed > (int64_t)len) {
4251 allowed = (int64_t)len;
4258 (int64_t)allowed)) == allowed) {
4259 buf = (
const char *)buf + total;
4260 conn->last_throttle_bytes +=
total;
4261 while (total < (int64_t)len && conn->ctx->stop_flag == 0) {
4262 allowed = conn->throttle > (int64_t)len - total
4263 ? (int64_t)len -
total 4270 (int64_t)allowed)) != allowed) {
4274 conn->last_throttle_bytes = allowed;
4275 conn->last_throttle_time = time(NULL);
4276 buf = (
const char *)buf + n;
4315 (*buf)[size - 1] = 0;
4328 size_t prealloc_size,
4353 }
else if ((
size_t)(len) >= prealloc_size) {
4356 *out_buf = (
char *)
mg_malloc((
size_t)(len) + 1);
4374 *out_buf = prealloc_buf;
4382 mg_vprintf(
struct mg_connection *conn,
const char *fmt, va_list ap)
4388 if ((len =
alloc_vprintf(&buf, mem,
sizeof(mem), fmt, ap)) > 0) {
4389 len =
mg_write(conn, buf, (
size_t)len);
4391 if (buf != mem && buf != NULL) {
4418 int is_form_url_encoded)
4421 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') 4423 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
4424 if (i < src_len - 2 && src[i] ==
'%' 4425 && isxdigit(*(
const unsigned char *)(src + i + 1))
4426 && isxdigit(*(
const unsigned char *)(src + i + 2))) {
4427 a = tolower(*(
const unsigned char *)(src + i + 1));
4428 b = tolower(*(
const unsigned char *)(src + i + 2));
4431 }
else if (is_form_url_encoded && src[i] ==
'+') {
4440 return i >= src_len ? j : -1;
4451 return mg_get_var2(data, data_len, name, dst, dst_len, 0);
4463 const char *p, *
e, *
s;
4467 if (dst == NULL || dst_len == 0) {
4469 }
else if (data == NULL || name == NULL || data_len == 0) {
4473 name_len = strlen(name);
4474 e = data + data_len;
4479 for (p = data; p + name_len <
e; p++) {
4480 if ((p == data || p[-1] ==
'&') && p[name_len] ==
'=' 4486 s = (
const char *)memchr(p,
'&', (
size_t)(e - p));
4514 const char *var_name,
4518 const char *
s, *p, *end;
4519 int name_len, len = -1;
4521 if (dst == NULL || dst_size == 0) {
4523 }
else if (var_name == NULL || (s = cookie_header) == NULL) {
4527 name_len = (int)strlen(var_name);
4528 end = s + strlen(s);
4531 for (; (s =
mg_strcasestr(s, var_name)) != NULL; s += name_len) {
4532 if (s[name_len] ==
'=') {
4534 if ((p = strchr(s,
' ')) == NULL) {
4540 if (*s ==
'"' && p[-1] ==
'"' && p > s + 1) {
4544 if ((
size_t)(p -
s) < dst_size) {
4558 #if defined(USE_WEBSOCKET) || defined(USE_LUA) 4560 base64_encode(
const unsigned char *src,
int src_len,
char *dst)
4562 static const char *b64 =
4563 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4566 for (i = j = 0; i < src_len; i += 3) {
4568 b = i + 1 >= src_len ? 0 : src[i + 1];
4569 c = i + 2 >= src_len ? 0 : src[i + 2];
4571 dst[j++] = b64[a >> 2];
4572 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
4573 if (i + 1 < src_len) {
4574 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
4576 if (i + 2 < src_len) {
4577 dst[j++] = b64[c & 63];
4580 while (j % 4 != 0) {
4588 #if defined(USE_LUA) 4589 static unsigned char 4590 b64reverse(
char letter)
4592 if (letter >=
'A' && letter <=
'Z') {
4593 return letter -
'A';
4595 if (letter >=
'a' && letter <=
'z') {
4596 return letter -
'a' + 26;
4598 if (letter >=
'0' && letter <=
'9') {
4599 return letter -
'0' + 52;
4601 if (letter ==
'+') {
4604 if (letter ==
'/') {
4607 if (letter ==
'=') {
4615 base64_decode(
const unsigned char *src,
int src_len,
char *dst,
size_t *dst_len)
4618 unsigned char a,
b, c, d;
4622 for (i = 0; i < src_len; i += 4) {
4623 a = b64reverse(src[i]);
4628 b = b64reverse(i + 1 >= src_len ? 0 : src[i + 1]);
4633 c = b64reverse(i + 2 >= src_len ? 0 : src[i + 2]);
4638 d = b64reverse(i + 3 >= src_len ? 0 : src[i + 3]);
4643 dst[(*dst_len)++] = (a << 2) + (b >> 4);
4645 dst[(*dst_len)++] = (b << 4) + (c >> 2);
4647 dst[(*dst_len)++] = (c << 6) + d;
4660 const char *s = conn->request_info.request_method;
4661 return s != NULL && (!strcmp(s,
"PUT") || !strcmp(s,
"DELETE")
4662 || !strcmp(s,
"MKCOL") || !strcmp(s,
"PATCH"));
4671 size_t filename_buf_len,
4674 int *is_script_resource,
4675 int *is_websocket_request,
4676 int *is_put_or_delete_request
4681 #if !defined(NO_FILES) 4682 const char *uri = conn->request_info.local_uri;
4684 const char *rewrite;
4687 char gz_path[PATH_MAX];
4688 char const *accept_encoding;
4690 #if !defined(NO_CGI) || defined(USE_LUA) 4694 (
void)filename_buf_len;
4697 memset(filep, 0,
sizeof(*filep));
4700 *is_script_resource = 0;
4703 #if defined(USE_WEBSOCKET) 4705 #if !defined(NO_FILES) 4706 if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
4707 root = conn->ctx->config[WEBSOCKET_ROOT];
4711 *is_websocket_request = 0;
4714 #if !defined(NO_FILES) 4728 conn, &truncated, filename, filename_buf_len - 1,
"%s%s", root, uri);
4731 goto interpret_cleanup;
4734 rewrite = conn->ctx->config[
REWRITE];
4735 while ((rewrite =
next_option(rewrite, &a, &b)) != NULL) {
4736 if ((match_len =
match_prefix(a.ptr, a.len, uri)) > 0) {
4740 filename_buf_len - 1,
4750 goto interpret_cleanup;
4755 if (
mg_stat(conn, filename, filep)) {
4756 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) 4759 #
if !defined(NO_CGI)
4764 #
if defined(USE_LUA)
4765 ||
match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
4766 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
4769 #
if defined(USE_DUKTAPE)
4770 ||
match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
4772 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
4786 *is_script_resource = !*is_put_or_delete_request;
4799 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
4800 if (strstr(accept_encoding,
"gzip") != NULL) {
4802 conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", filename);
4805 goto interpret_cleanup;
4808 if (
mg_stat(conn, gz_path, filep)) {
4819 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) 4821 for (p = filename + strlen(filename); p > filename + 1; p--) {
4825 #
if !defined(NO_CGI)
4830 #
if defined(USE_LUA)
4831 ||
match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
4833 conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
4836 #
if defined(USE_DUKTAPE)
4838 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
4839 strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
4842 ) && mg_stat(conn, filename, filep)) {
4848 conn->path_info = p + 1;
4849 memmove(p + 2, p + 1, strlen(p + 1) + 1);
4852 *is_script_resource = 1;
4863 #if !defined(NO_FILES) 4866 memset(filep, 0,
sizeof(*filep));
4869 *is_script_resource = 0;
4870 *is_websocket_request = 0;
4871 *is_put_or_delete_request = 0;
4886 for (s = buf, e = s + buflen - 1; len <= 0 && s <
e; s++)
4888 if (!isprint(*(
const unsigned char *)s) && *s !=
'\r' && *s !=
'\n' 4889 && *(
const unsigned char *)s < 128) {
4894 }
else if (s[0] ==
'\n' && s[1] ==
'\n') {
4895 len = (int)(s - buf) + 2;
4896 }
else if (s[0] ==
'\n' && &s[1] < e && s[1] ==
'\r' && s[2] ==
'\n') {
4897 len = (int)(s - buf) + 3;
4904 #if !defined(NO_CACHING) 4925 char month_str[32] = {0};
4926 int second, minute, hour, day, month, year;
4927 time_t result = (time_t)0;
4930 if ((sscanf(datetime,
4931 "%d/%3s/%d %d:%d:%d",
4937 &second) == 6) || (sscanf(datetime,
4938 "%d %3s %d %d:%d:%d",
4945 || (sscanf(datetime,
4946 "%*3s, %d %3s %d %d:%d:%d",
4952 &second) == 6) || (sscanf(datetime,
4953 "%d-%3s-%d %d:%d:%d",
4961 if ((month >= 0) && (year >= 1970)) {
4962 memset(&tm, 0,
sizeof(tm));
4963 tm.tm_year = year - 1900;
4969 result = timegm(&tm);
4985 while (*s !=
'\0') {
4987 if (s[-1] ==
'/' || s[-1] ==
'\\') {
4989 while (s[0] !=
'\0') {
4990 if (s[0] ==
'/' || s[0] ==
'\\') {
4992 }
else if (s[0] ==
'.' && s[1] ==
'.') {
5004 static const struct {
5011 {
".doc", 4,
"application/msword"},
5012 {
".eps", 4,
"application/postscript"},
5013 {
".exe", 4,
"application/octet-stream"},
5014 {
".js", 3,
"application/javascript"},
5015 {
".json", 5,
"application/json"},
5016 {
".pdf", 4,
"application/pdf"},
5017 {
".ps", 3,
"application/postscript"},
5018 {
".rtf", 4,
"application/rtf"},
5019 {
".xhtml", 6,
"application/xhtml+xml"},
5020 {
".xsl", 4,
"application/xml"},
5021 {
".xslt", 5,
"application/xml"},
5024 {
".ttf", 4,
"application/font-sfnt"},
5025 {
".cff", 4,
"application/font-sfnt"},
5026 {
".otf", 4,
"application/font-sfnt"},
5027 {
".aat", 4,
"application/font-sfnt"},
5028 {
".sil", 4,
"application/font-sfnt"},
5029 {
".pfr", 4,
"application/font-tdpfr"},
5030 {
".woff", 5,
"application/font-woff"},
5033 {
".mp3", 4,
"audio/mpeg"},
5034 {
".oga", 4,
"audio/ogg"},
5035 {
".ogg", 4,
"audio/ogg"},
5038 {
".gif", 4,
"image/gif"},
5039 {
".ief", 4,
"image/ief"},
5040 {
".jpeg", 5,
"image/jpeg"},
5041 {
".jpg", 4,
"image/jpeg"},
5042 {
".jpm", 4,
"image/jpm"},
5043 {
".jpx", 4,
"image/jpx"},
5044 {
".png", 4,
"image/png"},
5045 {
".svg", 4,
"image/svg+xml"},
5046 {
".tif", 4,
"image/tiff"},
5047 {
".tiff", 5,
"image/tiff"},
5050 {
".wrl", 4,
"model/vrml"},
5053 {
".css", 4,
"text/css"},
5054 {
".csv", 4,
"text/csv"},
5055 {
".htm", 4,
"text/html"},
5056 {
".html", 5,
"text/html"},
5057 {
".sgm", 4,
"text/sgml"},
5058 {
".shtm", 5,
"text/html"},
5059 {
".shtml", 6,
"text/html"},
5060 {
".txt", 4,
"text/plain"},
5061 {
".xml", 4,
"text/xml"},
5064 {
".mov", 4,
"video/quicktime"},
5065 {
".mp4", 4,
"video/mp4"},
5066 {
".mpeg", 5,
"video/mpeg"},
5067 {
".mpg", 4,
"video/mpeg"},
5068 {
".ogv", 4,
"video/ogg"},
5069 {
".qt", 3,
"video/quicktime"},
5074 {
".arj", 4,
"application/x-arj-compressed"},
5075 {
".gz", 3,
"application/x-gunzip"},
5076 {
".rar", 4,
"application/x-arj-compressed"},
5077 {
".swf", 4,
"application/x-shockwave-flash"},
5078 {
".tar", 4,
"application/x-tar"},
5079 {
".tgz", 4,
"application/x-tar-gz"},
5080 {
".torrent", 8,
"application/x-bittorrent"},
5081 {
".ppt", 4,
"application/x-mspowerpoint"},
5082 {
".xls", 4,
"application/x-msexcel"},
5083 {
".zip", 4,
"application/x-zip-compressed"},
5087 {
".aif", 4,
"audio/x-aif"},
5088 {
".m3u", 4,
"audio/x-mpegurl"},
5089 {
".mid", 4,
"audio/x-midi"},
5090 {
".ra", 3,
"audio/x-pn-realaudio"},
5091 {
".ram", 4,
"audio/x-pn-realaudio"},
5092 {
".wav", 4,
"audio/x-wav"},
5093 {
".bmp", 4,
"image/bmp"},
5094 {
".ico", 4,
"image/x-icon"},
5095 {
".pct", 4,
"image/x-pct"},
5096 {
".pict", 5,
"image/pict"},
5097 {
".rgb", 4,
"image/x-rgb"},
5098 {
".webm", 5,
"video/webm"},
5099 {
".asf", 4,
"video/x-ms-asf"},
5100 {
".avi", 4,
"video/x-msvideo"},
5101 {
".m4v", 4,
"video/x-m4v"},
5111 path_len = strlen(path);
5121 return "text/plain";
5130 struct vec ext_vec, mime_vec;
5131 const char *list, *ext;
5134 path_len = strlen(path);
5136 if (ctx == NULL || vec == NULL) {
5143 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
5145 ext = path + path_len - ext_vec.len;
5153 vec->len = strlen(vec->ptr);
5160 bin2str(
char *to,
const unsigned char *p,
size_t len)
5162 static const char *hex =
"0123456789abcdef";
5164 for (; len--; p++) {
5165 *to++ = hex[p[0] >> 4];
5166 *to++ = hex[p[0] & 0x0f];
5184 while ((p = va_arg(ap,
const char *)) != NULL) {
5190 bin2str(buf, hash,
sizeof(hash));
5204 const char *response)
5206 char ha2[32 + 1], expected_response[32 + 1];
5209 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL
5211 || response == NULL) {
5216 if (strlen(response) != 32) {
5220 mg_md5(ha2, method,
":", uri, NULL);
5221 mg_md5(expected_response,
5244 if (conn != NULL && conn->ctx != NULL) {
5245 char name[PATH_MAX];
5250 if (gpass != NULL) {
5252 if (!
mg_fopen(conn, gpass,
"r", filep)) {
5254 mg_cry(conn,
"fopen(%s): %s", gpass, strerror(
ERRNO));
5260 }
else if (
mg_stat(conn, path, &file) && file.is_directory) {
5269 if (truncated || !
mg_fopen(conn, name,
"r", filep)) {
5271 mg_cry(conn,
"fopen(%s): %s", name, strerror(
ERRNO));
5276 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
5290 if (truncated || !
mg_fopen(conn, name,
"r", filep)) {
5292 mg_cry(conn,
"fopen(%s): %s", name, strerror(
ERRNO));
5302 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
5313 char *
name, *value, *
s;
5314 const char *auth_header;
5321 (
void)memset(ah, 0,
sizeof(*ah));
5322 if ((auth_header =
mg_get_header(conn,
"Authorization")) == NULL
5334 while (isspace(*(
unsigned char *)
s)) {
5349 if (*name ==
'\0') {
5353 if (!strcmp(name,
"username")) {
5355 }
else if (!strcmp(name,
"cnonce")) {
5357 }
else if (!strcmp(name,
"response")) {
5358 ah->response = value;
5359 }
else if (!strcmp(name,
"uri")) {
5361 }
else if (!strcmp(name,
"qop")) {
5363 }
else if (!strcmp(name,
"nc")) {
5365 }
else if (!strcmp(name,
"nonce")) {
5370 #ifndef NO_NONCE_CHECK 5372 if (ah->nonce == NULL) {
5376 nonce = strtoull(ah->nonce, &s, 10);
5377 if ((s == NULL) || (*s != 0)) {
5382 nonce ^= conn->ctx->auth_nonce_mask;
5392 if (nonce < (uint64_t)conn->ctx->start_time) {
5399 if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
5405 if (ah->user != NULL) {
5406 conn->request_info.remote_user =
mg_strdup(ah->user);
5416 mg_fgets(
char *buf,
size_t size,
struct file *filep,
char **p)
5426 if (filep->membuf != NULL && *p != NULL) {
5427 memend = (
const char *)&filep->membuf[filep->size];
5429 eof = (
char *)memchr(*p,
'\n', (
size_t)(memend - *p));
5435 len = (size_t)(eof - *p) > size - 1 ? size - 1 : (size_t)(eof - *p);
5436 memcpy(buf, *p, len);
5439 return len ? eof : NULL;
5440 }
else if (filep->fp != NULL) {
5441 return fgets(buf, (
int)size, filep->fp);
5447 struct read_auth_file_struct {
5448 struct mg_connection *conn;
5451 char buf[256 + 256 + 40];
5462 int is_authorized = 0;
5466 if (!filep || !workdata) {
5471 p = (
char *)filep->membuf;
5472 while (
mg_fgets(workdata->buf,
sizeof(workdata->buf), filep, &p) != NULL) {
5473 l = strlen(workdata->buf);
5475 if (isspace(workdata->buf[l - 1])
5476 || iscntrl(workdata->buf[l - 1])) {
5478 workdata->buf[
l] = 0;
5486 workdata->f_user = workdata->buf;
5488 if (workdata->f_user[0] ==
':') {
5491 if (workdata->f_user[1] ==
'#') {
5494 }
else if (!strncmp(workdata->f_user + 1,
"include=", 8)) {
5495 if (
mg_fopen(workdata->conn, workdata->f_user + 9,
"r", &fp)) {
5500 "%s: cannot open authorization file: %s",
5509 "%s: syntax error in authorization file: %s",
5515 workdata->f_domain = strchr(workdata->f_user,
':');
5516 if (workdata->f_domain == NULL) {
5518 "%s: syntax error in authorization file: %s",
5523 *(workdata->f_domain) = 0;
5524 (workdata->f_domain)++;
5526 workdata->f_ha1 = strchr(workdata->f_domain,
':');
5527 if (workdata->f_ha1 == NULL) {
5529 "%s: syntax error in authorization file: %s",
5534 *(workdata->f_ha1) = 0;
5535 (workdata->f_ha1)++;
5537 if (!strcmp(workdata->ah.user, workdata->f_user)
5538 && !strcmp(workdata->domain, workdata->f_domain)) {
5539 return check_password(workdata->conn->request_info.request_method,
5544 workdata->ah.cnonce,
5546 workdata->ah.response);
5550 return is_authorized;
5558 struct read_auth_file_struct workdata;
5561 if (!conn || !conn->ctx) {
5565 memset(&workdata, 0,
sizeof(workdata));
5566 workdata.conn = conn;
5581 char fname[PATH_MAX];
5582 struct vec uri_vec, filename_vec;
5585 int authorized = 1, truncated;
5587 if (!conn || !conn->ctx) {
5592 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
5593 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
5599 (
int)filename_vec.len,
5602 if (truncated || !
mg_fopen(conn, fname,
"r", &file)) {
5604 "%s: cannot open %s: %s",
5630 time_t curtime = time(NULL);
5632 if (conn && conn->ctx) {
5633 uint64_t nonce = (uint64_t)(conn->ctx->start_time);
5635 (
void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
5636 nonce += conn->ctx->nonce_count;
5637 ++conn->ctx->nonce_count;
5638 (
void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
5640 nonce ^= conn->ctx->auth_nonce_mask;
5641 conn->status_code = 401;
5642 conn->must_close = 1;
5646 mg_printf(conn,
"HTTP/1.1 401 Unauthorized\r\n");
5650 "Connection: %s\r\n" 5651 "Content-Length: 0\r\n" 5652 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " 5662 #if !defined(NO_FILES) 5671 if (passfile != NULL &&
mg_fopen(conn, passfile,
"r", &file)) {
5690 char line[512], u[512] =
"", d[512] =
"", ha1[33], tmp[PATH_MAX + 8];
5697 if (pass != NULL && pass[0] ==
'\0') {
5702 if (fname == NULL || domain == NULL || user == NULL) {
5708 if (strchr(user,
':') != NULL) {
5711 if (strchr(domain,
':') != NULL) {
5717 for (i = 0; i < 255 && user[i] != 0; i++) {
5718 if (iscntrl(user[i])) {
5725 for (i = 0; i < 255 && domain[i] != 0; i++) {
5726 if (iscntrl(domain[i])) {
5735 if ((strlen(fname) + 4) >= PATH_MAX) {
5741 strcat(tmp,
".tmp");
5745 if ((fp = fopen(fname,
"a+")) != NULL) {
5750 if ((fp = fopen(fname,
"r")) == NULL) {
5752 }
else if ((fp2 = fopen(tmp,
"w+")) == NULL) {
5758 while (fgets(line,
sizeof(line), fp) != NULL) {
5759 if (sscanf(line,
"%255[^:]:%255[^:]:%*s", u, d) != 2) {
5765 if (!strcmp(u, user) && !strcmp(d, domain)) {
5768 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
5769 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
5772 fprintf(fp2,
"%s", line);
5777 if (!found && pass != NULL) {
5778 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
5779 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
5797 return port < 0xffff;
5804 struct addrinfo hints, *res, *ressave;
5808 memset(&hints, 0,
sizeof(
struct addrinfo));
5809 hints.ai_family = af;
5811 gai_ret = getaddrinfo(src, NULL, &hints, &res);
5826 if (dstlen >= res->ai_addrlen) {
5827 memcpy(dst, res->ai_addr, res->ai_addrlen);
5833 freeaddrinfo(ressave);
5851 memset(sa, 0,
sizeof(*sa));
5883 "SSL is not initialized");
5887 if (
mg_inet_pton(AF_INET, host, &sa->sin,
sizeof(sa->sin))) {
5888 sa->sin.sin_port = htons((uint16_t)port);
5891 }
else if (
mg_inet_pton(AF_INET6, host, &sa->sin6,
sizeof(sa->sin6))) {
5892 sa->sin6.sin6_port = htons((uint16_t)port);
5894 }
else if (host[0] ==
'[') {
5897 size_t l = strlen(host + 1);
5898 char *
h = l > 1 ?
mg_strdup(host + 1) : NULL;
5901 if (
mg_inet_pton(AF_INET6, h, &sa->sin6,
sizeof(sa->sin6))) {
5902 sa->sin6.sin6_port = htons((uint16_t)port);
5921 *sock = socket(PF_INET, SOCK_STREAM, 0);
5924 else if (ip_ver == 6) {
5925 *sock = socket(PF_INET6, SOCK_STREAM, 0);
5942 && (connect(*sock, (
struct sockaddr *)&sa->sin,
sizeof(sa->sin))
5950 && (connect(*sock, (
struct sockaddr *)&sa->sin6,
sizeof(sa->sin6))
5962 "connect(%s:%d): %s",
5975 static const char *dont_escape =
"._-$,;~()";
5976 static const char *hex =
"0123456789abcdef";
5978 const char *end = dst + dst_len - 1;
5980 for (; *src !=
'\0' && pos < end; src++, pos++) {
5981 if (isalnum(*(
const unsigned char *)src)
5982 || strchr(dont_escape, *(
const unsigned char *)src) != NULL) {
5984 }
else if (pos + 2 < end) {
5986 pos[1] = hex[(*(
const unsigned char *)src) >> 4];
5987 pos[2] = hex[(*(
const unsigned char *)src) & 0xf];
5995 return (*src ==
'\0') ? (int)(pos - dst) : -1;
6002 char size[64], mod[64], href[PATH_MAX];
6005 if (de->file.is_directory) {
6015 if (de->file.size < 1024) {
6021 (
int)de->file.size);
6022 }
else if (de->file.size < 0x100000) {
6028 (
double)de->file.size / 1024.0);
6029 }
else if (de->file.size < 0x40000000) {
6035 (
double)de->file.size / 1048576);
6042 (
double)de->file.size / 1073741824);
6049 tm = localtime(&de->file.last_modified);
6051 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", tm);
6053 mg_strlcpy(mod,
"01-Jan-1970 00:00",
sizeof(mod));
6054 mod[
sizeof(mod) - 1] =
'\0';
6057 de->conn->num_bytes_sent +=
6059 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>" 6060 "<td> %s</td><td> %s</td></tr>\n",
6061 de->conn->request_info.local_uri,
6063 de->file.is_directory ?
"/" :
"",
6065 de->file.is_directory ?
"/" :
"",
6079 const struct de *
a = (
const struct de *)p1, *
b = (
const struct de *)
p2;
6080 const char *query_string = a->conn->request_info.query_string;
6083 if (query_string == NULL) {
6084 query_string =
"na";
6087 if (a->file.is_directory && !
b->file.is_directory) {
6089 }
else if (!a->file.is_directory &&
b->file.is_directory) {
6091 }
else if (*query_string ==
'n') {
6092 cmp_result = strcmp(a->file_name,
b->file_name);
6093 }
else if (*query_string ==
's') {
6094 cmp_result = a->file.size ==
b->file.size
6096 : a->file.size >
b->file.size ? 1 : -1;
6097 }
else if (*query_string ==
'd') {
6099 (a->file.last_modified ==
b->file.last_modified)
6101 : ((a->file.last_modified >
b->file.last_modified) ? 1
6105 return query_string[1] ==
'd' ? -cmp_result : cmp_result;
6114 if (conn && conn->ctx) {
6116 const char *pattern = conn->ctx->config[
HIDE_FILES];
6117 return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0
6129 void (*cb)(
struct de *,
void *))
6131 char path[PATH_MAX];
6137 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
6144 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")
6150 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
6157 memset(&de.file, 0,
sizeof(de.file));
6164 if (!
mg_stat(conn, path, &de.file)) {
6166 "%s: mg_stat(%s) failed: %s",
6171 de.file_name = dp->d_name;
6180 #if !defined(NO_FILES) 6184 char path[PATH_MAX];
6191 if ((dirp =
mg_opendir(conn, dir)) == NULL) {
6199 if (!strcmp(dp->d_name,
".") || !strcmp(dp->d_name,
"..")) {
6204 conn, &truncated, path,
sizeof(path),
"%s/%s", dir, dp->d_name);
6211 memset(&de.file, 0,
sizeof(de.file));
6219 if (!
mg_stat(conn, path, &de.file)) {
6221 "%s: mg_stat(%s) failed: %s",
6227 if (de.file.membuf == NULL) {
6229 if (de.file.is_directory) {
6253 struct dir_scan_data {
6255 unsigned int num_entries;
6256 unsigned int arr_size;
6265 if (new_ptr == NULL) {
6275 struct dir_scan_data *dsd = (
struct dir_scan_data *)data;
6277 if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
6280 (
struct de *)
realloc2(dsd->entries,
6281 dsd->arr_size *
sizeof(dsd->entries[0]));
6283 if (dsd->entries == NULL) {
6285 dsd->num_entries = 0;
6287 dsd->entries[dsd->num_entries].file_name =
mg_strdup(de->file_name);
6288 dsd->entries[dsd->num_entries].file = de->file;
6289 dsd->entries[dsd->num_entries].conn = de->conn;
6300 struct dir_scan_data data = {NULL, 0, 128};
6302 time_t curtime = time(NULL);
6307 "Error: Cannot open directory\nopendir(%s): %s",
6319 sort_direction = conn->request_info.query_string != NULL
6320 && conn->request_info.query_string[1] ==
'd' 6324 conn->must_close = 1;
6329 "Connection: close\r\n" 6330 "Content-Type: text/html; charset=utf-8\r\n\r\n",
6333 conn->num_bytes_sent +=
6335 "<html><head><title>Index of %s</title>" 6336 "<style>th {text-align: left;}</style></head>" 6337 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">" 6338 "<tr><th><a href=\"?n%c\">Name</a></th>" 6339 "<th><a href=\"?d%c\">Modified</a></th>" 6340 "<th><a href=\"?s%c\">Size</a></th></tr>" 6341 "<tr><td colspan=\"3\"><hr></td></tr>",
6342 conn->request_info.local_uri,
6343 conn->request_info.local_uri,
6349 conn->num_bytes_sent +=
6351 "<tr><td><a href=\"%s%s\">%s</a></td>" 6352 "<td> %s</td><td> %s</td></tr>\n",
6353 conn->request_info.local_uri,
6360 if (data.entries != NULL) {
6362 (
size_t)data.num_entries,
6363 sizeof(data.entries[0]),
6365 for (i = 0; i < data.num_entries; i++) {
6367 mg_free(data.entries[i].file_name);
6372 conn->num_bytes_sent +=
mg_printf(conn,
"%s",
"</table></body></html>");
6373 conn->status_code = 200;
6385 int to_read, num_read, num_written;
6388 if (!filep || !conn) {
6393 size = filep->size > INT64_MAX ? INT64_MAX : (int64_t)(filep->size);
6394 offset = offset < 0 ? 0 : offset > size ? size : offset;
6396 if (len > 0 && filep->membuf != NULL && size > 0) {
6398 if (len > size - offset) {
6399 len = size - offset;
6401 mg_write(conn, filep->membuf + offset, (
size_t)len);
6402 }
else if (len > 0 && filep->fp != NULL) {
6404 #if defined(__linux__) 6406 if (conn->throttle == 0 && conn->ssl == 0) {
6407 off_t sf_offs = (off_t)offset;
6409 int sf_file = fileno(filep->fp);
6416 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
6418 sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
6420 conn->num_bytes_sent += sf_sent;
6423 }
else if (loop_cnt == 0) {
6429 }
else if (sf_sent == 0) {
6435 }
while ((len > 0) && (sf_sent >= 0));
6444 offset = (int64_t)sf_offs;
6447 if ((offset > 0) && (fseeko(filep->fp, offset, SEEK_SET) != 0)) {
6448 mg_cry(conn,
"%s: fseeko() failed: %s", __func__, strerror(
ERRNO));
6453 "Error: Unable to access file at requested position.");
6457 to_read =
sizeof(buf);
6458 if ((int64_t)to_read > len) {
6463 if ((num_read = (
int)fread(buf, 1, (
size_t)to_read, filep->fp))
6469 if ((num_written =
mg_write(conn, buf, (
size_t)num_read))
6475 conn->num_bytes_sent += num_written;
6493 if (filep != NULL && buf != NULL) {
6499 (
unsigned long)filep->last_modified,
6508 if (filep != NULL && filep->fp != NULL) {
6512 if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
6514 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
6529 char date[64], lm[64], etag[64];
6531 const char *msg =
"OK", *hdr;
6532 time_t curtime = time(NULL);
6534 struct vec mime_vec;
6536 char gz_path[PATH_MAX];
6537 const char *encoding =
"";
6538 const char *cors1, *cors2, *cors3;
6540 if (conn == NULL || conn->ctx == NULL || filep == NULL) {
6544 if (mime_type == NULL) {
6548 mime_vec.len = strlen(mime_type);
6550 if (filep->size > INT64_MAX) {
6553 "Error: File size is too large to send\n%" INT64_FMT,
6556 cl = (int64_t)filep->size;
6557 conn->status_code = 200;
6563 if (filep->gzipped) {
6564 mg_snprintf(conn, &truncated, gz_path,
sizeof(gz_path),
"%s.gz", path);
6569 "Error: Path of zipped file too long (%s)",
6575 encoding =
"Content-Encoding: gzip\r\n";
6578 if (!
mg_fopen(conn, path,
"rb", filep)) {
6581 "Error: Cannot open file\nfopen(%s): %s",
6596 if (filep->gzipped) {
6601 "Error: Range requests in gzipped files are not supported");
6605 conn->status_code = 206;
6606 cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1 : cl - r1;
6611 "Content-Range: bytes " 6616 msg =
"Partial Content";
6625 cors1 =
"Access-Control-Allow-Origin: ";
6629 cors1 = cors2 = cors3 =
"";
6639 "HTTP/1.1 %d %s\r\n" 6650 "Last-Modified: %s\r\n" 6652 "Content-Type: %.*s\r\n" 6654 "Connection: %s\r\n" 6655 "Accept-Ranges: bytes\r\n" 6666 if (strcmp(conn->request_info.request_method,
"HEAD") != 0) {
6686 if (
mg_stat(conn, path, &file)) {
6687 if (file.is_directory) {
6698 "Error: Directory listing denied");
6716 put_dir(
struct mg_connection *conn,
const char *path)
6724 for (s = p = path + 2; (p = strchr(s,
'/')) != NULL; s = ++p) {
6725 len = (size_t)(p - path);
6726 if (len >=
sizeof(buf)) {
6731 memcpy(buf, path, len);
6757 mg_cry(conn,
"%s: Cannot remove invalid file %s", __func__, path);
6770 if (conn->consumed_content != 0) {
6771 mg_cry(conn,
"%s: Contents already consumed", __func__);
6786 if (
mg_fopen(conn, path,
"w", &fi) == 0) {
6790 ret =
mg_read(conn, buf,
sizeof(buf));
6792 n = (int)fwrite(buf, 1, (
size_t)ret, fi.fp);
6798 ret =
mg_read(conn, buf,
sizeof(buf));
6803 if (fclose(fi.fp) != 0) {
6827 while ((*dp !=
':') && (*dp !=
'\r') && (*dp != 0)) {
6835 if (dp[1] ==
'\n') {
6850 }
while (*dp ==
' ');
6853 *buf = strstr(dp,
"\r\n");
6866 if (*buf[0] ==
'\r') {
6877 return !strcmp(method,
"GET")
6878 || !strcmp(method,
"POST")
6879 || !strcmp(method,
"HEAD")
6880 || !strcmp(method,
"PUT")
6881 || !strcmp(method,
"DELETE")
6882 || !strcmp(method,
"OPTIONS")
6884 || !strcmp(method,
"CONNECT")
6886 || !strcmp(method,
"PROPFIND")
6887 || !strcmp(method,
"MKCOL")
6899 || !strcmp(method,
"PATCH");
6909 int is_request, request_length;
6917 if (request_length > 0) {
6924 buf[request_length - 1] =
'\0';
6927 while (*buf !=
'\0' && isspace(*(
unsigned char *)buf)) {
6937 if ((is_request && memcmp(ri->
http_version,
"HTTP/", 5) != 0)
6938 || (!is_request && memcmp(ri->
request_method,
"HTTP/", 5) != 0)) {
6939 request_length = -1;
6947 return request_length;
6958 struct mg_connection *conn,
6963 int request_len, n = 0;
6964 struct timespec last_action_time;
6965 double request_timeout;
6971 memset(&last_action_time, 0,
sizeof(last_action_time));
6977 request_timeout = -1.0;
6983 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
6986 (conn->ctx->stop_flag == 0) && (*nread < bufsiz) && (request_len == 0)
6988 <= request_timeout) || (request_timeout < 0))
6989 && ((n =
pull(fp, conn, buf + *nread, bufsiz - *nread, request_timeout))
6993 if (*nread > bufsiz) {
6997 if (request_timeout > 0.0) {
6998 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
7002 return (request_len <= 0 && n <= 0) ? -1 : request_len;
7005 #if !defined(NO_FILES) 7015 if (conn && conn->ctx) {
7016 const char *list = conn->ctx->config[
INDEX_FILES];
7018 struct vec filename_vec;
7019 size_t n = strlen(path);
7025 while (n > 0 && path[n - 1] ==
'/') {
7032 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
7034 if (filename_vec.len > path_len - (n + 2)) {
7039 mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
7042 if (
mg_stat(conn, path, &file)) {
7062 #if !defined(NO_CACHING) 7080 #if !defined(NO_CGI) || !defined(NO_FILES) 7084 const char *expect, *body;
7086 int to_read, nread, success = 0;
7087 int64_t buffered_len;
7088 double timeout = -1.0;
7104 if (conn->content_len == -1 && !conn->is_chunked) {
7109 "Error: Client did not specify content length");
7110 }
else if ((expect != NULL)
7115 "Error: Can not fulfill expectation %s",
7118 if (expect != NULL) {
7119 (
void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
7120 conn->status_code = 100;
7122 conn->status_code = 200;
7125 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
7126 - conn->consumed_content;
7131 if ((buffered_len < 0) || (conn->consumed_content != 0)) {
7136 if (buffered_len > 0) {
7137 if ((int64_t)buffered_len > conn->content_len) {
7138 buffered_len = (int)conn->content_len;
7140 body = conn->buf + conn->request_len + conn->consumed_content;
7141 push_all(conn->ctx, fp, sock, ssl, body, (int64_t)buffered_len);
7142 conn->consumed_content += buffered_len;
7146 while (conn->consumed_content < conn->content_len) {
7147 to_read =
sizeof(buf);
7148 if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
7149 to_read = (int)(conn->content_len - conn->consumed_content);
7151 nread =
pull(NULL, conn, buf, to_read, timeout);
7153 ||
push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) {
7156 conn->consumed_content += nread;
7159 if (conn->consumed_content == conn->content_len) {
7160 success = (nread >= 0);
7176 #if !defined(NO_CGI) 7185 struct cgi_environment {
7186 struct mg_connection *conn;
7198 static void addenv(
struct cgi_environment *env,
7205 addenv(
struct cgi_environment *env,
const char *fmt, ...)
7213 space = (env->buflen - env->bufused);
7216 n = strlen(fmt) + 2 + 128;
7226 "%s: Cannot allocate memory for CGI variable [%s]",
7233 space = (env->buflen - env->bufused);
7237 added = env->buf + env->bufused;
7241 mg_vsnprintf(env->conn, &truncated, added, (
size_t)space, fmt, ap);
7250 }
while (truncated);
7253 n = strlen(added) + 1;
7257 space = (env->varlen - env->varused);
7260 "%s: Cannot register CGI variable [%s]",
7267 env->var[env->varused] = added;
7275 struct cgi_environment *env)
7282 if (conn == NULL || prog == NULL || env == NULL) {
7289 env->buf = (
char *)
mg_malloc(env->buflen);
7292 env->var = (
char **)
mg_malloc(env->buflen *
sizeof(
char *));
7300 addenv(env,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
7301 addenv(env,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
7302 addenv(env,
"%s",
"REDIRECT_STATUS=200");
7304 #if defined(USE_IPV6) 7305 if (conn->client.lsa.sa.sa_family == AF_INET6) {
7306 addenv(env,
"SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
7310 addenv(env,
"SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
7314 addenv(env,
"REMOTE_ADDR=%s", src_addr);
7316 addenv(env,
"REQUEST_METHOD=%s", conn->request_info.request_method);
7317 addenv(env,
"REMOTE_PORT=%d", conn->request_info.remote_port);
7319 addenv(env,
"REQUEST_URI=%s", conn->request_info.request_uri);
7320 addenv(env,
"LOCAL_URI=%s", conn->request_info.local_uri);
7325 (
int)strlen(conn->request_info.local_uri)
7326 - ((conn->path_info == NULL) ? 0 : (
int)strlen(conn->path_info)),
7327 conn->request_info.local_uri);
7329 addenv(env,
"SCRIPT_FILENAME=%s", prog);
7330 if (conn->path_info == NULL) {
7334 "PATH_TRANSLATED=%s%s",
7339 addenv(env,
"HTTPS=%s", conn->ssl == NULL ?
"off" :
"on");
7342 addenv(env,
"CONTENT_TYPE=%s", s);
7344 if (conn->request_info.query_string != NULL) {
7345 addenv(env,
"QUERY_STRING=%s", conn->request_info.query_string);
7348 addenv(env,
"CONTENT_LENGTH=%s", s);
7350 if ((s = getenv(
"PATH")) != NULL) {
7351 addenv(env,
"PATH=%s", s);
7353 if (conn->path_info != NULL) {
7354 addenv(env,
"PATH_INFO=%s", conn->path_info);
7357 if (conn->status_code > 0) {
7359 addenv(env,
"STATUS=%d", conn->status_code);
7363 if ((s = getenv(
"COMSPEC")) != NULL) {
7364 addenv(env,
"COMSPEC=%s", s);
7366 if ((s = getenv(
"SYSTEMROOT")) != NULL) {
7367 addenv(env,
"SYSTEMROOT=%s", s);
7369 if ((s = getenv(
"SystemDrive")) != NULL) {
7370 addenv(env,
"SystemDrive=%s", s);
7372 if ((s = getenv(
"ProgramFiles")) != NULL) {
7373 addenv(env,
"ProgramFiles=%s", s);
7375 if ((s = getenv(
"ProgramFiles(x86)")) != NULL) {
7376 addenv(env,
"ProgramFiles(x86)=%s", s);
7379 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL) {
7380 addenv(env,
"LD_LIBRARY_PATH=%s", s);
7384 if ((s = getenv(
"PERLLIB")) != NULL) {
7385 addenv(env,
"PERLLIB=%s", s);
7388 if (conn->request_info.remote_user != NULL) {
7389 addenv(env,
"REMOTE_USER=%s", conn->request_info.remote_user);
7390 addenv(env,
"%s",
"AUTH_TYPE=Digest");
7394 for (i = 0; i < conn->request_info.num_headers; i++) {
7399 sizeof(http_var_name),
7401 conn->request_info.http_headers[i].name);
7405 "%s: HTTP header variable too long [%s]",
7407 conn->request_info.http_headers[i].name);
7412 for (p = http_var_name; *p !=
'\0'; p++) {
7416 *p = (char)toupper(*(
unsigned char *)p);
7422 conn->request_info.http_headers[i].value);
7427 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
7428 addenv(env,
"%.*s", (
int)var_vec.len, var_vec.ptr);
7431 env->var[env->varused] = NULL;
7432 env->buf[env->bufused] =
'\0';
7441 int headers_len, data_len, i, truncated;
7442 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
7443 const char *status, *status_text, *connection_state;
7444 char *pbuf, dir[PATH_MAX], *p;
7446 struct cgi_environment blk;
7447 FILE *in = NULL, *out = NULL, *err = NULL;
7449 pid_t pid = (pid_t)-1;
7465 mg_cry(conn,
"Error: CGI program \"%s\": Path too long", prog);
7470 if ((p = strrchr(dir,
'/')) != NULL) {
7473 dir[0] =
'.', dir[1] =
'\0';
7477 if (pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0) {
7478 status = strerror(
ERRNO);
7480 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
7483 send_http_error(conn, 500,
"Error: Cannot create CGI pipe: %s", status);
7487 pid =
spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
7489 if (pid == (pid_t)-1) {
7490 status = strerror(
ERRNO);
7492 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
7497 "Error: Cannot spawn CGI process [%s]: %s",
7518 fdin[0] = fdout[1] = fderr[1] = -1;
7520 if ((in = fdopen(fdin[1],
"wb")) == NULL) {
7521 status = strerror(
ERRNO);
7523 "Error: CGI program \"%s\": Can not open stdin: %s",
7528 "Error: CGI can not open fdin\nfopen: %s",
7533 if ((out = fdopen(fdout[0],
"rb")) == NULL) {
7534 status = strerror(
ERRNO);
7536 "Error: CGI program \"%s\": Can not open stdout: %s",
7541 "Error: CGI can not open fdout\nfopen: %s",
7546 if ((err = fdopen(fderr[0],
"rb")) == NULL) {
7547 status = strerror(
ERRNO);
7549 "Error: CGI program \"%s\": Can not open stderr: %s",
7554 "Error: CGI can not open fdout\nfopen: %s",
7564 if ((conn->request_info.content_length > 0) || conn->is_chunked) {
7569 "Error: CGI program \"%s\": Forward body data failed",
7589 "Error: Not enough memory for CGI buffer (%u bytes)",
7590 (
unsigned int)buflen);
7592 "Error: CGI program \"%s\": Not enough memory for buffer (%u " 7595 (
unsigned int)buflen);
7598 headers_len =
read_request(out, conn, buf, (
int)buflen, &data_len);
7599 if (headers_len <= 0) {
7603 i =
pull_all(err, conn, buf, (
int)buflen);
7606 "Error: CGI program \"%s\" sent error " 7613 "Error: CGI program \"%s\" sent error " 7620 "Error: CGI program sent malformed or too big " 7621 "(>%u bytes) HTTP headers: [%.*s]",
7628 "Error: CGI program sent malformed or too big " 7629 "(>%u bytes) HTTP headers: [%.*s]",
7638 buf[headers_len - 1] =
'\0';
7643 if ((status =
get_header(&ri,
"Status")) != NULL) {
7644 conn->status_code = atoi(status);
7645 status_text = status;
7646 while (isdigit(*(
const unsigned char *)status_text)
7647 || *status_text ==
' ') {
7650 }
else if (
get_header(&ri,
"Location") != NULL) {
7651 conn->status_code = 302;
7653 conn->status_code = 200;
7655 connection_state =
get_header(&ri,
"Connection");
7657 conn->must_close = 1;
7659 (
void)
mg_printf(conn,
"HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
7671 conn->num_bytes_sent +=
7672 mg_write(conn, buf + headers_len, (
size_t)(data_len - headers_len));
7681 if (pid != (pid_t)-1) {
7683 #if !defined(_WIN32) 7686 while (waitpid(pid, &st, 0) != -1)
7691 if (fdin[0] != -1) {
7694 if (fdout[1] != -1) {
7700 }
else if (fdin[1] != -1) {
7706 }
else if (fdout[0] != -1) {
7712 }
else if (fderr[0] != -1) {
7723 #if !defined(NO_FILES) 7725 mkcol(
struct mg_connection *conn,
const char *path)
7730 time_t curtime = time(NULL);
7738 memset(&de.file, 0,
sizeof(de.file));
7739 if (!
mg_stat(conn, path, &de.file)) {
7741 "%s: mg_stat(%s) failed: %s",
7747 if (de.file.last_modified) {
7750 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
7754 body_len = conn->data_len - conn->request_len;
7757 conn, 415,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
7764 conn->status_code = 201;
7767 "HTTP/1.1 %d Created\r\n" 7773 "Content-Length: 0\r\n" 7774 "Connection: %s\r\n\r\n",
7776 }
else if (rc == -1) {
7777 if (errno == EEXIST) {
7779 conn, 405,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
7780 }
else if (errno == EACCES) {
7782 conn, 403,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
7783 }
else if (errno == ENOENT) {
7785 conn, 409,
"Error: mkcol(%s): %s", path, strerror(
ERRNO));
7801 time_t curtime = time(NULL);
7807 if (
mg_stat(conn, path, &file)) {
7809 conn->status_code = 200;
7811 if (file.is_directory) {
7820 if (file.membuf != NULL) {
7825 "Error: Put not possible\nReplacing %s is not supported",
7831 if (access(path, W_OK) == 0) {
7833 conn->status_code = 200;
7839 "Error: Put not possible\nReplacing %s is not allowed",
7846 conn->status_code = 201;
7854 "HTTP/1.1 %d %s\r\n",
7860 "Content-Length: 0\r\n" 7861 "Connection: %s\r\n\r\n",
7874 "Error: Path too long\nput_dir(%s): %s",
7884 "Error: Can not create directory\nput_dir(%s): %s",
7891 if (!
mg_fopen(conn, path,
"wb+", &file) || file.fp == NULL) {
7895 "Error: Can not create file\nfopen(%s): %s",
7905 conn->status_code = 206;
7906 fseeko(file.fp, r1, SEEK_SET);
7919 "HTTP/1.1 %d %s\r\n",
7925 "Content-Length: 0\r\n" 7926 "Connection: %s\r\n\r\n",
7938 memset(&de.file, 0,
sizeof(de.file));
7939 if (!
mg_stat(conn, path, &de.file)) {
7943 "Error: Cannot delete file\nFile %s not found",
7948 if (de.file.membuf != NULL) {
7953 "Error: Delete not possible\nDeleting %s is not supported",
7958 if (de.file.is_directory) {
7971 if (access(path, W_OK) != 0) {
7976 "Error: Delete not possible\nDeleting %s is not allowed",
7989 "Error: Cannot delete file\nremove(%s): %s",
7998 send_ssi_file(
struct mg_connection *,
const char *,
struct file *,
int);
8019 if (sscanf(tag,
" virtual=\"%511[^\"]\"", file_name) == 1) {
8030 }
else if (sscanf(tag,
" abspath=\"%511[^\"]\"", file_name) == 1) {
8035 mg_snprintf(conn, &truncated, path,
sizeof(path),
"%s", file_name);
8037 }
else if (sscanf(tag,
" file=\"%511[^\"]\"", file_name) == 1
8038 || sscanf(tag,
" \"%511[^\"]\"", file_name) == 1) {
8044 if ((p = strrchr(path,
'/')) != NULL) {
8057 mg_cry(conn,
"Bad SSI #include: [%s]", tag);
8062 mg_cry(conn,
"SSI #include path length overflow: [%s]", tag);
8066 if (!
mg_fopen(conn, path,
"rb", &file)) {
8068 "Cannot open SSI #include: [%s]: fopen(%s): %s",
8086 #if !defined(NO_POPEN) 8090 char cmd[1024] =
"";
8093 if (sscanf(tag,
" \"%1023[^\"]\"", cmd) != 1) {
8094 mg_cry(conn,
"Bad SSI #exec: [%s]", tag);
8097 if ((file.fp = popen(cmd,
"r")) == NULL) {
8098 mg_cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
8111 if (filep == NULL) {
8114 if (filep->membuf != NULL && offset >= 0
8115 && ((
unsigned int)(offset)) < filep->size) {
8116 return ((
const unsigned char *)filep->membuf)[offset];
8117 }
else if (filep->fp != NULL) {
8118 return fgetc(filep->fp);
8132 int ch, offset, len, in_ssi_tag;
8134 if (include_level > 10) {
8135 mg_cry(conn,
"SSI #include level is too deep (%s)", path);
8139 in_ssi_tag = len = offset = 0;
8140 while ((ch =
mg_fgetc(filep, offset)) != EOF) {
8141 if (in_ssi_tag && ch ==
'>') {
8143 buf[len++] = (char)ch;
8146 if (len > (
int)
sizeof(buf)) {
8149 if (len < 6 || memcmp(buf,
"<!--#", 5) != 0) {
8153 if (!memcmp(buf + 5,
"include", 7)) {
8155 #if !defined(NO_POPEN) 8156 }
else if (!memcmp(buf + 5,
"exec", 4)) {
8168 }
else if (in_ssi_tag) {
8169 if (len == 5 && memcmp(buf,
"<!--#", 5) != 0) {
8172 }
else if (len == (
int)
sizeof(buf) - 2) {
8173 mg_cry(conn,
"%s: SSI tag is too large", path);
8176 buf[len++] = (char)(ch & 0xff);
8177 }
else if (ch ==
'<') {
8183 buf[len++] = (char)(ch & 0xff);
8185 buf[len++] = (char)(ch & 0xff);
8186 if (len == (
int)
sizeof(buf)) {
8206 time_t curtime = time(NULL);
8207 const char *cors1, *cors2, *cors3;
8209 if (conn == NULL || path == NULL || filep == NULL) {
8215 cors1 =
"Access-Control-Allow-Origin: ";
8219 cors1 = cors2 = cors3 =
"";
8222 if (!
mg_fopen(conn, path,
"rb", filep)) {
8227 "Error: Cannot read file\nfopen(%s): %s",
8231 conn->must_close = 1;
8239 "Content-Type: text/html\r\n" 8240 "Connection: %s\r\n\r\n",
8252 #if !defined(NO_FILES) 8257 time_t curtime = time(NULL);
8263 conn->status_code = 200;
8264 conn->must_close = 1;
8268 "HTTP/1.1 200 OK\r\n" 8271 "Connection: %s\r\n" 8272 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, " 8273 "PROPFIND, MKCOL\r\n" 8282 print_props(
struct mg_connection *conn,
const char *uri,
struct file *filep)
8286 if (conn == NULL || uri == NULL || filep == NULL) {
8291 conn->num_bytes_sent +=
8294 "<d:href>%s</d:href>" 8297 "<d:resourcetype>%s</d:resourcetype>" 8298 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>" 8299 "<d:getlastmodified>%s</d:getlastmodified>" 8301 "<d:status>HTTP/1.1 200 OK</d:status>" 8305 filep->is_directory ?
"<d:collection/>" :
"",
8314 char href[PATH_MAX];
8315 char href_encoded[PATH_MAX];
8318 struct mg_connection *conn = (
struct mg_connection *)data;
8327 conn->request_info.local_uri,
8344 time_t curtime = time(NULL);
8348 if (!conn || !path || !filep || !conn->ctx) {
8352 conn->must_close = 1;
8353 conn->status_code = 207;
8355 "HTTP/1.1 207 Multi-Status\r\n" 8360 "Connection: %s\r\n" 8361 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
8364 conn->num_bytes_sent +=
8366 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" 8367 "<d:multistatus xmlns:d='DAV:'>\n");
8370 print_props(conn, conn->request_info.local_uri, filep);
8373 if (filep && filep->is_directory
8375 && (depth == NULL || strcmp(depth,
"0") != 0)) {
8379 conn->num_bytes_sent +=
mg_printf(conn,
"%s\n",
"</d:multistatus>");
8387 (
void)pthread_mutex_lock(&conn->mutex);
8395 (
void)pthread_mutex_unlock(&conn->mutex);
8403 (
void)pthread_mutex_lock(&ctx->nonce_mutex);
8411 (
void)pthread_mutex_unlock(&ctx->nonce_mutex);
8415 #if defined(USE_TIMERS) 8416 #include "timer.inl" 8420 #include "mod_lua.inl" 8424 #include "mod_duktape.inl" 8427 #if defined(USE_WEBSOCKET) 8431 #define SHA1HANDSOFF 8444 static const int n = 1;
8445 return ((
char *)&n)[0] == 0;
8449 union char64long16 {
8450 unsigned char c[64];
8454 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 8458 blk0(
union char64long16 *block,
int i)
8461 if (!is_big_endian()) {
8462 block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00)
8463 | (rol(block->l[i], 8) & 0x00FF00FF);
8469 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \ 8470 ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \ 8472 #define R0(v, w, x, y, z, i) \ 8473 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ 8475 #define R1(v, w, x, y, z, i) \ 8476 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ 8478 #define R2(v, w, x, y, z, i) \ 8479 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ 8481 #define R3(v, w, x, y, z, i) \ 8482 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ 8484 #define R4(v, w, x, y, z, i) \ 8485 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ 8492 unsigned char buffer[64];
8497 SHA1Transform(uint32_t state[5],
const unsigned char buffer[64])
8499 uint32_t
a,
b, c, d,
e;
8500 union char64long16 block[1];
8502 memcpy(block, buffer, 64);
8508 R0(a, b, c, d, e, 0);
8509 R0(e, a, b, c, d, 1);
8510 R0(d, e, a, b, c, 2);
8511 R0(c, d, e, a, b, 3);
8512 R0(b, c, d, e, a, 4);
8513 R0(a, b, c, d, e, 5);
8514 R0(e, a, b, c, d, 6);
8515 R0(d, e, a, b, c, 7);
8516 R0(c, d, e, a, b, 8);
8517 R0(b, c, d, e, a, 9);
8518 R0(a, b, c, d, e, 10);
8519 R0(e, a, b, c, d, 11);
8520 R0(d, e, a, b, c, 12);
8521 R0(c, d, e, a, b, 13);
8522 R0(b, c, d, e, a, 14);
8523 R0(a, b, c, d, e, 15);
8524 R1(e, a, b, c, d, 16);
8525 R1(d, e, a, b, c, 17);
8526 R1(c, d, e, a, b, 18);
8527 R1(b, c, d, e, a, 19);
8528 R2(a, b, c, d, e, 20);
8529 R2(e, a, b, c, d, 21);
8530 R2(d, e, a, b, c, 22);
8531 R2(c, d, e, a, b, 23);
8532 R2(b, c, d, e, a, 24);
8533 R2(a, b, c, d, e, 25);
8534 R2(e, a, b, c, d, 26);
8535 R2(d, e, a, b, c, 27);
8536 R2(c, d, e, a, b, 28);
8537 R2(b, c, d, e, a, 29);
8538 R2(a, b, c, d, e, 30);
8539 R2(e, a, b, c, d, 31);
8540 R2(d, e, a, b, c, 32);
8541 R2(c, d, e, a, b, 33);
8542 R2(b, c, d, e, a, 34);
8543 R2(a, b, c, d, e, 35);
8544 R2(e, a, b, c, d, 36);
8545 R2(d, e, a, b, c, 37);
8546 R2(c, d, e, a, b, 38);
8547 R2(b, c, d, e, a, 39);
8548 R3(a, b, c, d, e, 40);
8549 R3(e, a, b, c, d, 41);
8550 R3(d, e, a, b, c, 42);
8551 R3(c, d, e, a, b, 43);
8552 R3(b, c, d, e, a, 44);
8553 R3(a, b, c, d, e, 45);
8554 R3(e, a, b, c, d, 46);
8555 R3(d, e, a, b, c, 47);
8556 R3(c, d, e, a, b, 48);
8557 R3(b, c, d, e, a, 49);
8558 R3(a, b, c, d, e, 50);
8559 R3(e, a, b, c, d, 51);
8560 R3(d, e, a, b, c, 52);
8561 R3(c, d, e, a, b, 53);
8562 R3(b, c, d, e, a, 54);
8563 R3(a, b, c, d, e, 55);
8564 R3(e, a, b, c, d, 56);
8565 R3(d, e, a, b, c, 57);
8566 R3(c, d, e, a, b, 58);
8567 R3(b, c, d, e, a, 59);
8568 R4(a, b, c, d, e, 60);
8569 R4(e, a, b, c, d, 61);
8570 R4(d, e, a, b, c, 62);
8571 R4(c, d, e, a, b, 63);
8572 R4(b, c, d, e, a, 64);
8573 R4(a, b, c, d, e, 65);
8574 R4(e, a, b, c, d, 66);
8575 R4(d, e, a, b, c, 67);
8576 R4(c, d, e, a, b, 68);
8577 R4(b, c, d, e, a, 69);
8578 R4(a, b, c, d, e, 70);
8579 R4(e, a, b, c, d, 71);
8580 R4(d, e, a, b, c, 72);
8581 R4(c, d, e, a, b, 73);
8582 R4(b, c, d, e, a, 74);
8583 R4(a, b, c, d, e, 75);
8584 R4(e, a, b, c, d, 76);
8585 R4(d, e, a, b, c, 77);
8586 R4(c, d, e, a, b, 78);
8587 R4(b, c, d, e, a, 79);
8593 a = b = c = d = e = 0;
8594 memset(block,
'\0',
sizeof(block));
8599 SHA1Init(SHA1_CTX *context)
8601 context->state[0] = 0x67452301;
8602 context->state[1] = 0xEFCDAB89;
8603 context->state[2] = 0x98BADCFE;
8604 context->state[3] = 0x10325476;
8605 context->state[4] = 0xC3D2E1F0;
8606 context->count[0] = context->count[1] = 0;
8611 SHA1Update(SHA1_CTX *context,
const unsigned char *data, uint32_t len)
8615 j = context->count[0];
8616 if ((context->count[0] += len << 3) < j) {
8617 context->count[1]++;
8619 context->count[1] += (len >> 29);
8621 if ((j + len) > 63) {
8622 memcpy(&context->buffer[j], data, (i = 64 - j));
8623 SHA1Transform(context->state, context->buffer);
8624 for (; i + 63 < len; i += 64) {
8625 SHA1Transform(context->state, &data[i]);
8630 memcpy(&context->buffer[j], &data[i], len - i);
8635 SHA1Final(
unsigned char digest[20], SHA1_CTX *context)
8638 unsigned char finalcount[8], c;
8640 for (i = 0; i < 8; i++) {
8641 finalcount[i] = (
unsigned char)((context->count[(i >= 4 ? 0 : 1)]
8642 >> ((3 - (i & 3)) * 8)) & 255);
8645 SHA1Update(context, &c, 1);
8646 while ((context->count[0] & 504) != 448) {
8648 SHA1Update(context, &c, 1);
8650 SHA1Update(context, finalcount, 8);
8651 for (i = 0; i < 20; i++) {
8652 digest[i] = (
unsigned char)((context->state[i >> 2]
8653 >> ((3 - (i & 3)) * 8)) & 255);
8655 memset(context,
'\0',
sizeof(*context));
8656 memset(&finalcount,
'\0',
sizeof(finalcount));
8662 send_websocket_handshake(
struct mg_connection *conn,
const char *websock_key)
8664 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8665 const char *protocol = NULL;
8666 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
8671 mg_snprintf(conn, &truncated, buf,
sizeof(buf),
"%s%s", websock_key, magic);
8673 conn->must_close = 1;
8678 SHA1Update(&sha_ctx, (
unsigned char *)buf, (uint32_t)strlen(buf));
8679 SHA1Final((
unsigned char *)sha, &sha_ctx);
8680 base64_encode((
unsigned char *)sha,
sizeof(sha), b64_sha);
8682 "HTTP/1.1 101 Switching Protocols\r\n" 8683 "Upgrade: websocket\r\n" 8684 "Connection: Upgrade\r\n" 8685 "Sec-WebSocket-Accept: %s\r\n",
8692 const char *
sep = strchr(protocol,
',');
8695 mg_printf(conn,
"Sec-WebSocket-Protocol: %s\r\n\r\n", protocol);
8708 "Sec-WebSocket-Protocol: %.*s\r\n\r\n",
8709 (
int)(sep - protocol),
8723 read_websocket(
struct mg_connection *conn,
8725 void *callback_data)
8731 unsigned char *buf = (
unsigned char *)conn->buf + conn->request_len;
8732 int n, error, exit_by_callback;
8738 size_t i, len, mask_len = 0, data_len = 0, header_len, body_len;
8743 unsigned char mask[4];
8752 double timeout = -1.0;
8754 if (conn->ctx->config[WEBSOCKET_TIMEOUT]) {
8755 timeout = atoi(conn->ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
8765 while (!conn->ctx->stop_flag) {
8767 assert(conn->data_len >= conn->request_len);
8768 if ((body_len = (
size_t)(conn->data_len - conn->request_len)) >= 2) {
8770 mask_len = buf[1] & 128 ? 4 : 0;
8771 if (len < 126 && body_len >= mask_len) {
8773 header_len = 2 + mask_len;
8774 }
else if (len == 126 && body_len >= 4 + mask_len) {
8775 header_len = 4 + mask_len;
8776 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
8777 }
else if (body_len >= 10 + mask_len) {
8778 header_len = 10 + mask_len;
8779 data_len = (((uint64_t)ntohl(*(uint32_t *)(
void *)&buf[2]))
8780 << 32) + ntohl(*(uint32_t *)(
void *)&buf[6]);
8784 if (header_len > 0 && body_len >= header_len) {
8787 if (data_len >
sizeof(mem)) {
8792 mg_cry(conn,
"websocket out of memory; closing connection");
8799 memcpy(mask, buf + header_len - mask_len,
sizeof(mask));
8801 memset(mask, 0,
sizeof(mask));
8806 assert(body_len >= header_len);
8807 if (data_len + header_len > body_len) {
8810 len = body_len - header_len;
8811 memcpy(data, buf + header_len, len);
8813 while (len < data_len) {
8815 NULL, conn, data + len, (
int)(data_len - len), timeout);
8823 mg_cry(conn,
"Websocket pull failed; closing connection");
8826 conn->data_len = conn->request_len;
8832 len = data_len + header_len;
8836 memcpy(data, buf + header_len, data_len);
8839 memmove(buf, buf + len, body_len - len);
8842 conn->data_len -= (int)len;
8847 for (i = 0; i < data_len; ++i) {
8848 data[i] ^= mask[i & 3];
8854 exit_by_callback = 0;
8855 if ((ws_data_handler != NULL)
8856 && !ws_data_handler(conn, mop, data, data_len, callback_data)) {
8857 exit_by_callback = 1;
8864 if (exit_by_callback
8876 conn->buf + conn->data_len,
8877 conn->buf_size - conn->data_len,
8882 conn->data_len +=
n;
8891 mg_websocket_write_exec(
struct mg_connection *conn,
8895 uint32_t masking_key)
8897 unsigned char header[14];
8898 size_t headerLen = 1;
8902 header[0] = 0x80 + (opcode & 0xF);
8905 if (dataLen < 126) {
8907 header[1] = (
unsigned char)dataLen;
8909 }
else if (dataLen <= 0xFFFF) {
8912 *(uint16_t *)(
void *)(header + 2) = htons((uint16_t)dataLen);
8917 *(uint32_t *)(
void *)(header + 2) = htonl((uint64_t)dataLen >> 32);
8918 *(uint32_t *)(
void *)(header + 6) = htonl(dataLen & 0xFFFFFFFF);
8925 *(uint32_t *)(
void *)(header + headerLen) = masking_key;
8936 retval =
mg_write(conn, header, headerLen);
8938 retval =
mg_write(conn, data, dataLen);
8951 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
8956 mask_data(
const char *in,
size_t in_len, uint32_t masking_key,
char *out)
8961 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
8963 while (i < (in_len - 3)) {
8964 *(uint32_t *)(
void *)(out + i) =
8965 *(uint32_t *)(
void *)(in + i) ^ masking_key;
8971 while (i < in_len) {
8972 *(uint8_t *)(
void *)(out + i) =
8973 *(uint8_t *)(
void *)(in + i)
8974 ^ *(((uint8_t *)&masking_key) + (i % 4));
8988 char *masked_data = (
char *)
mg_malloc(((dataLen + 7) / 4) * 4);
8989 uint32_t masking_key = (uint32_t)
get_random();
8991 if (masked_data == NULL) {
8994 "Cannot allocate buffer for masked websocket response: " 8999 mask_data(data, dataLen, masking_key, masked_data);
9001 retval = mg_websocket_write_exec(
9002 conn, opcode, masked_data, dataLen, masking_key);
9010 handle_websocket_request(
struct mg_connection *conn,
9012 int is_callback_resource,
9019 const char *websock_key =
mg_get_header(conn,
"Sec-WebSocket-Key");
9020 const char *version =
mg_get_header(conn,
"Sec-WebSocket-Version");
9021 int lua_websock = 0;
9023 #if !defined(USE_LUA) 9036 const char *key1 =
mg_get_header(conn,
"Sec-WebSocket-Key1");
9037 const char *key2 =
mg_get_header(conn,
"Sec-WebSocket-Key2");
9040 if ((key1 != NULL) && (key2 != NULL)) {
9042 conn->content_len = 8;
9043 if (8 ==
mg_read(conn, key3, 8)) {
9048 "Protocol upgrade to RFC 6455 required");
9059 if (version == NULL || strcmp(version,
"13") != 0) {
9069 if (is_callback_resource) {
9070 if (ws_connect_handler != NULL
9071 && ws_connect_handler(conn, cbData) != 0) {
9080 #if defined(USE_LUA) 9084 if (conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
9086 match_prefix(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS],
9088 conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
9094 conn->lua_websocket_state = lua_websocket_new(path, conn);
9095 if (!conn->lua_websocket_state) {
9104 if (!is_callback_resource && !lua_websock) {
9114 if (!send_websocket_handshake(conn, websock_key)) {
9120 if (is_callback_resource) {
9121 if (ws_ready_handler != NULL) {
9122 ws_ready_handler(conn, cbData);
9124 #if defined(USE_LUA) 9125 }
else if (lua_websock) {
9126 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
9134 if (is_callback_resource) {
9135 read_websocket(conn, ws_data_handler, cbData);
9136 #if defined(USE_LUA) 9137 }
else if (lua_websock) {
9138 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
9143 if (ws_close_handler) {
9144 ws_close_handler(conn, cbData);
9152 const char *upgrade, *connection;
9161 if (upgrade == NULL) {
9171 if (connection == NULL) {
9193 return n >= 0 && n <= 255;
9200 int n,
a,
b, c, d,
slash = 32, len = 0;
9202 if ((sscanf(spec,
"%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5
9203 || sscanf(spec,
"%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
isbyte(a)
9207 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
9209 *mask = slash ? 0xffffffffU << (32 -
slash) : 0;
9220 struct vec vec, val;
9225 while ((spec =
next_option(spec, &vec, &val)) != NULL) {
9227 if (sscanf(val.ptr,
"%lf%c", &v, &mult) < 1 || v < 0
9234 if (vec.len == 1 && vec.ptr[0] ==
'*') {
9236 }
else if (
parse_net(vec.ptr, &net, &mask) > 0) {
9237 if ((remote_ip & mask) == net) {
9255 return ntohl(*(
const uint32_t *)&conn->client.rsa.sin.sin_addr);
9263 #if defined(MG_LEGACY_INTERFACE) 9269 struct mg_upload_user_data {
9270 struct mg_connection *conn;
9271 const char *destination_dir;
9272 int num_uploaded_files;
9278 mg_upload_field_found(
const char *key,
9279 const char *filename,
9285 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
9289 mg_cry(fud->conn,
"%s: No filename set", __func__);
9297 fud->destination_dir,
9300 mg_cry(fud->conn,
"%s: File path too long", __func__);
9309 mg_upload_field_get(
const char *key,
9326 mg_upload_field_stored(
const char *path,
long long file_size,
void *user_data)
9328 struct mg_upload_user_data *fud = (
struct mg_upload_user_data *)user_data;
9331 fud->num_uploaded_files++;
9332 fud->conn->ctx->callbacks.upload(fud->conn, path);
9340 mg_upload(
struct mg_connection *conn,
const char *destination_dir)
9342 struct mg_upload_user_data fud = {conn, destination_dir, 0};
9344 mg_upload_field_get,
9345 mg_upload_field_stored,
9353 mg_cry(conn,
"%s: Error while parsing the request", __func__);
9356 return fud.num_uploaded_files;
9367 for (i = 0; idx == -1 && i < ctx->num_listening_sockets; i++) {
9368 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
9379 const char *host_header;
9383 hostlen =
sizeof(host);
9384 if (host_header != NULL) {
9388 host[hostlen - 1] =
'\0';
9389 pos = strchr(host,
':');
9404 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
9407 conn->ctx->listening_sockets[ssl_index].lsa.sin.sin_port),
9408 conn->request_info.local_uri,
9409 (conn->request_info.query_string == NULL) ?
"" :
"?",
9410 (conn->request_info.query_string == NULL)
9412 : conn->request_info.query_string);
9421 int is_delete_request,
9430 struct mg_handler_info *tmp_rh, **lastref;
9431 size_t urilen = strlen(uri);
9440 if (handler != NULL) {
9443 if (!is_delete_request && connect_handler == NULL
9444 && ready_handler == NULL
9445 && data_handler == NULL
9446 && close_handler == NULL) {
9449 if (auth_handler != NULL) {
9458 if (connect_handler != NULL || ready_handler != NULL
9459 || data_handler != NULL
9460 || close_handler != NULL) {
9463 if (!is_delete_request && (handler == NULL)) {
9466 if (auth_handler != NULL) {
9474 if (handler != NULL) {
9477 if (connect_handler != NULL || ready_handler != NULL
9478 || data_handler != NULL
9479 || close_handler != NULL) {
9482 if (!is_delete_request && (auth_handler == NULL)) {
9494 lastref = &(ctx->handlers);
9495 for (tmp_rh = ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
9496 if (tmp_rh->handler_type == handler_type) {
9497 if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) {
9498 if (!is_delete_request) {
9501 tmp_rh->handler = handler;
9503 tmp_rh->connect_handler = connect_handler;
9504 tmp_rh->ready_handler = ready_handler;
9505 tmp_rh->data_handler = data_handler;
9506 tmp_rh->close_handler = close_handler;
9508 tmp_rh->auth_handler = auth_handler;
9510 tmp_rh->cbdata = cbdata;
9513 *lastref = tmp_rh->next;
9521 lastref = &(tmp_rh->next);
9524 if (is_delete_request) {
9532 (
struct mg_handler_info *)
mg_calloc(
sizeof(
struct mg_handler_info), 1);
9533 if (tmp_rh == NULL) {
9535 mg_cry(
fc(ctx),
"%s",
"Cannot create new request handler struct, OOM");
9542 mg_cry(
fc(ctx),
"%s",
"Cannot create new request handler struct, OOM");
9545 tmp_rh->uri_len = urilen;
9547 tmp_rh->handler = handler;
9549 tmp_rh->connect_handler = connect_handler;
9550 tmp_rh->ready_handler = ready_handler;
9551 tmp_rh->data_handler = data_handler;
9552 tmp_rh->close_handler = close_handler;
9554 tmp_rh->auth_handler = auth_handler;
9556 tmp_rh->cbdata = cbdata;
9557 tmp_rh->handler_type = handler_type;
9558 tmp_rh->next = NULL;
9594 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
9595 && (data_handler == NULL)
9596 && (close_handler == NULL);
9645 size_t urilen = strlen(uri);
9646 struct mg_handler_info *tmp_rh;
9648 if (!conn || !conn->ctx) {
9655 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
9656 tmp_rh = tmp_rh->next) {
9657 if (tmp_rh->handler_type == handler_type) {
9658 if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) {
9660 *connect_handler = tmp_rh->connect_handler;
9661 *ready_handler = tmp_rh->ready_handler;
9662 *data_handler = tmp_rh->data_handler;
9663 *close_handler = tmp_rh->close_handler;
9665 *handler = tmp_rh->handler;
9667 *auth_handler = tmp_rh->auth_handler;
9669 *cbdata = tmp_rh->cbdata;
9677 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
9678 tmp_rh = tmp_rh->next) {
9679 if (tmp_rh->handler_type == handler_type) {
9680 if (tmp_rh->uri_len < urilen && uri[tmp_rh->uri_len] ==
'/' 9681 && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
9683 *connect_handler = tmp_rh->connect_handler;
9684 *ready_handler = tmp_rh->ready_handler;
9685 *data_handler = tmp_rh->data_handler;
9686 *close_handler = tmp_rh->close_handler;
9688 *handler = tmp_rh->handler;
9690 *auth_handler = tmp_rh->auth_handler;
9692 *cbdata = tmp_rh->cbdata;
9700 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
9701 tmp_rh = tmp_rh->next) {
9702 if (tmp_rh->handler_type == handler_type) {
9703 if (
match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
9705 *connect_handler = tmp_rh->connect_handler;
9706 *ready_handler = tmp_rh->ready_handler;
9707 *data_handler = tmp_rh->data_handler;
9708 *close_handler = tmp_rh->close_handler;
9710 *handler = tmp_rh->handler;
9712 *auth_handler = tmp_rh->auth_handler;
9714 *cbdata = tmp_rh->cbdata;
9727 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE) 9729 deprecated_websocket_connect_wrapper(
const struct mg_connection *conn,
9733 if (pcallbacks->websocket_connect) {
9734 return pcallbacks->websocket_connect(conn);
9742 deprecated_websocket_ready_wrapper(
struct mg_connection *conn,
void *cbdata)
9745 if (pcallbacks->websocket_ready) {
9746 pcallbacks->websocket_ready(conn);
9752 deprecated_websocket_data_wrapper(
struct mg_connection *conn,
9759 if (pcallbacks->websocket_data) {
9760 return pcallbacks->websocket_data(conn, bits, data, len);
9777 char path[PATH_MAX];
9778 int uri_len, ssl_index;
9779 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
9780 is_put_or_delete_request = 0, is_callback_resource = 0;
9788 void *callback_data = NULL;
9790 void *auth_callback_data = NULL;
9791 #if !defined(NO_FILES) 9792 time_t curtime = time(NULL);
9804 if ((conn->request_info.query_string = strchr(ri->
request_uri,
'?'))
9806 *((
char *)conn->request_info.query_string++) =
'\0';
9824 if (!conn->client.is_ssl && conn->client.ssl_redir) {
9826 if (ssl_index >= 0) {
9834 "Error: SSL forward not configured properly");
9835 mg_cry(conn,
"Can not redirect to SSL, no SSL port available");
9846 if (conn->ctx->callbacks.begin_request != NULL) {
9850 i = conn->ctx->callbacks.begin_request(conn);
9854 conn->status_code = i;
9856 }
else if (i == 0) {
9879 &ws_connect_handler,
9889 is_callback_resource = 1;
9890 is_script_resource = 1;
9893 no_callback_resource:
9897 is_callback_resource = 0;
9903 &is_script_resource,
9904 &is_websocket_request,
9905 &is_put_or_delete_request);
9918 &auth_callback_data)) {
9919 if (!auth_handler(conn, auth_callback_data)) {
9922 }
else if (is_put_or_delete_request && !is_script_resource
9923 && !is_callback_resource) {
9926 #if defined(NO_FILES) 9935 "%s method not allowed",
9936 conn->request_info.request_method);
9940 #if !defined(NO_FILES) 9963 if (is_callback_resource) {
9964 if (!is_websocket_request) {
9965 i = callback_handler(conn, callback_data);
9972 conn->status_code = i;
9986 &is_script_resource,
9987 &is_websocket_request,
9988 &is_put_or_delete_request);
9989 callback_handler = NULL;
9996 goto no_callback_resource;
9999 #if defined(USE_WEBSOCKET) 10000 handle_websocket_request(conn,
10002 is_callback_resource,
10003 ws_connect_handler,
10014 #if defined(USE_WEBSOCKET) 10015 if (is_websocket_request) {
10016 if (is_script_resource) {
10018 handle_websocket_request(conn,
10025 &conn->ctx->callbacks);
10027 #if defined(MG_LEGACY_INTERFACE) 10028 handle_websocket_request(
10031 !is_script_resource ,
10032 deprecated_websocket_connect_wrapper,
10033 deprecated_websocket_ready_wrapper,
10034 deprecated_websocket_data_wrapper,
10036 &conn->ctx->callbacks);
10045 #if defined(NO_FILES) 10060 if (is_script_resource) {
10066 if (is_put_or_delete_request) {
10087 "%s method not allowed",
10088 conn->request_info.request_method);
10100 if (file.is_directory && ri->
local_uri[uri_len - 1] !=
'/') {
10103 "HTTP/1.1 301 Moved Permanently\r\n" 10104 "Location: %s/\r\n" 10107 "Content-Length: 0\r\n" 10108 "Connection: %s\r\n\r\n",
10136 "%s method not allowed",
10137 conn->request_info.request_method);
10142 if (file.is_directory) {
10156 "Error: Directory listing denied");
10181 if (!conn || !conn->ctx) {
10187 }
else if (
match_prefix(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
10189 conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
10194 handle_lsp_request(conn, path, file, NULL);
10195 }
else if (
match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
10196 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
10201 mg_exec_lua_script(conn, path, NULL);
10203 #if defined(USE_DUKTAPE) 10204 }
else if (
match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
10206 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
10209 mg_exec_duktape_script(conn, path);
10211 #if !defined(NO_CGI) 10222 #if !defined(NO_CACHING) 10223 }
else if ((!conn->in_error_handler) &&
is_not_modified(conn, file)) {
10241 for (i = 0; i < ctx->num_listening_sockets; i++) {
10245 mg_free(ctx->listening_sockets);
10246 ctx->listening_sockets = NULL;
10247 mg_free(ctx->listening_ports);
10248 ctx->listening_ports = NULL;
10260 unsigned int a,
b, c, d, port;
10262 #if defined(USE_IPV6) 10263 char buf[100] = {0};
10269 memset(so, 0,
sizeof(*so));
10270 so->lsa.sin.sin_family = AF_INET;
10272 if (sscanf(vec->ptr,
"%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
10275 so->lsa.sin.sin_addr.s_addr =
10276 htonl((a << 24) | (b << 16) | (c << 8) | d);
10277 so->lsa.sin.sin_port = htons((uint16_t)port);
10278 #if defined(USE_IPV6) 10279 }
else if (sscanf(vec->ptr,
"[%49[^]]]:%u%n", buf, &port, &len) == 2
10281 AF_INET6, buf, &so->lsa.sin6,
sizeof(so->lsa.sin6))) {
10285 so->lsa.sin6.sin6_port = htons((uint16_t)port);
10287 }
else if (sscanf(vec->ptr,
"%u%n", &port, &len) == 1) {
10289 so->lsa.sin.sin_port = htons((uint16_t)port);
10298 if ((len < 0) && ((
unsigned)len > (
unsigned)vec->len)) {
10301 ch = vec->ptr[len];
10302 so->is_ssl = (ch ==
's');
10303 so->ssl_redir = (ch ==
'r');
10307 && (ch ==
'\0' || ch ==
's' || ch ==
'r' || ch ==
',');
10316 #if defined(USE_IPV6) 10320 struct socket so, *ptr;
10322 in_port_t *portPtr;
10326 int portsTotal = 0;
10333 memset(&so, 0,
sizeof(so));
10334 memset(&usa, 0,
sizeof(usa));
10337 while ((list =
next_option(list, &vec, NULL)) != NULL) {
10343 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
10347 "[IP_ADDRESS:]PORT[s|r]");
10351 if (so.is_ssl && ctx->ssl_ctx == NULL) {
10354 "Cannot add SSL socket (entry %i). Is -ssl_certificate " 10360 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
10363 mg_cry(
fc(ctx),
"cannot create socket (entry %i)", portsTotal);
10377 if (setsockopt(so.sock,
10379 SO_EXCLUSIVEADDRUSE,
10380 (SOCK_OPT_TYPE)&on,
10381 sizeof(on)) != 0) {
10384 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
10388 if (setsockopt(so.sock,
10391 (SOCK_OPT_TYPE)&on,
10392 sizeof(on)) != 0) {
10395 "cannot set socket option SO_REUSEADDR (entry %i)",
10400 #if defined(USE_IPV6) 10401 if (so.lsa.sa.sa_family == AF_INET6
10402 && setsockopt(so.sock,
10406 sizeof(off)) != 0) {
10409 "cannot set socket option IPV6_V6ONLY (entry %i)",
10414 if (so.lsa.sa.sa_family == AF_INET) {
10416 len =
sizeof(so.lsa.sin);
10417 if (bind(so.sock, &so.lsa.sa, len) != 0) {
10419 "cannot bind to %.*s: %d (%s)",
10429 #if defined(USE_IPV6) 10430 else if (so.lsa.sa.sa_family == AF_INET6) {
10432 len =
sizeof(so.lsa.sin6);
10433 if (bind(so.sock, &so.lsa.sa, len) != 0) {
10435 "cannot bind to IPv6 %.*s: %d (%s)",
10448 "cannot bind: address family not supported (entry %i)",
10456 "cannot listen to %.*s: %d (%s)",
10466 if (getsockname(so.sock, &(usa.sa), &len) != 0) {
10468 int err = (int)
ERRNO;
10470 "call to getsockname failed %.*s: %d (%s)",
10480 if ((ptr = (
struct socket *)
10482 (ctx->num_listening_sockets + 1)
10483 *
sizeof(ctx->listening_sockets[0]))) == NULL) {
10485 mg_cry(
fc(ctx),
"%s",
"Out of memory");
10492 (in_port_t *)
mg_realloc(ctx->listening_ports,
10493 (ctx->num_listening_sockets + 1)
10494 *
sizeof(ctx->listening_ports[0])))
10497 mg_cry(
fc(ctx),
"%s",
"Out of memory");
10505 ctx->listening_sockets = ptr;
10506 ctx->listening_sockets[ctx->num_listening_sockets] = so;
10507 ctx->listening_ports = portPtr;
10508 ctx->listening_ports[ctx->num_listening_sockets] =
10509 ntohs(usa.sin.sin_port);
10510 ctx->num_listening_sockets++;
10514 if (portsOk != portsTotal) {
10523 static const char *
10526 const char *header_value;
10528 if ((header_value =
mg_get_header(conn, header)) == NULL) {
10531 return header_value;
10544 const char *referer;
10545 const char *user_agent;
10549 if (!conn || !conn->ctx) {
10562 if (fi.fp == NULL && conn->ctx->callbacks.log_message == NULL) {
10566 tm = localtime(&conn->conn_birth_time);
10568 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z", tm);
10570 mg_strlcpy(date,
"01/Jan/1970:00:00:00 +0000",
sizeof(date));
10571 date[
sizeof(date) - 1] =
'\0';
10574 ri = &conn->request_info;
10578 user_agent =
header_val(conn,
"User-Agent");
10584 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
10586 ri->remote_user == NULL ?
"-" : ri->remote_user,
10588 ri->request_method ? ri->request_method :
"-",
10589 ri->request_uri ? ri->request_uri :
"-",
10590 ri->query_string ?
"?" :
"",
10591 ri->query_string ? ri->query_string :
"",
10594 conn->num_bytes_sent,
10598 if (conn->ctx->callbacks.log_access) {
10599 conn->ctx->callbacks.log_access(conn, buf);
10604 fprintf(fi.fp,
"%s\n", buf);
10606 funlockfile(fi.fp);
10619 uint32_t net, mask;
10626 allowed = list == NULL ?
'+' :
'-';
10628 while ((list =
next_option(list, &vec, NULL)) != NULL) {
10630 if ((flag !=
'+' && flag !=
'-')
10631 ||
parse_net(&vec.ptr[1], &net, &mask) == 0) {
10633 "%s: subnet must be [+|-]x.x.x.x[/x]",
10638 if (net == (remote_ip & mask)) {
10643 return allowed ==
'+';
10649 #if !defined(_WIN32) 10661 if ((pw = getpwnam(uid)) == NULL) {
10662 mg_cry(
fc(ctx),
"%s: unknown user [%s]", __func__, uid);
10663 }
else if (setgid(pw->
pw_gid) == -1) {
10665 "%s: setgid(%s): %s",
10669 }
else if (setgroups(0, NULL)) {
10671 "%s: setgroups(): %s",
10674 }
else if (setuid(pw->
pw_uid) == -1) {
10676 "%s: setuid(%s): %s",
10695 struct mg_workerTLS *tls = (
struct mg_workerTLS *)key;
10699 if (tls->is_master == 2) {
10700 tls->is_master = -3;
10704 pthread_setspecific(sTlsKey, NULL);
10708 #if !defined(NO_SSL) 10711 static unsigned long 10715 return GetCurrentThreadId();
10719 #pragma clang diagnostic push 10720 #pragma clang diagnostic ignored "-Wunreachable-code" 10728 if (
sizeof(pthread_t) >
sizeof(
unsigned long)) {
10731 struct mg_workerTLS *tls =
10732 (
struct mg_workerTLS *)pthread_getspecific(sTlsKey);
10736 tls = (
struct mg_workerTLS *)
mg_malloc(
sizeof(
struct mg_workerTLS));
10737 tls->is_master = -2;
10738 tls->thread_idx = (unsigned)
mg_atomic_inc(&thread_idx_max);
10739 pthread_setspecific(sTlsKey, tls);
10741 return tls->thread_idx;
10746 unsigned long ret = 0;
10747 pthread_t t = pthread_self();
10748 memcpy(&ret, &t,
sizeof(pthread_t));
10753 #pragma clang diagnostic pop 10767 static int reload_lock = 0;
10768 static long int data_check = 0;
10770 struct stat cert_buf;
10773 int should_verify_peer;
10776 && conn->ctx->callbacks.init_ssl == NULL) {
10781 if (stat(pem, &cert_buf) != -1) {
10782 t = (
long int)cert_buf.st_mtime;
10785 if (data_check != t) {
10788 should_verify_peer =
10793 if (should_verify_peer) {
10800 "SSL_CTX_load_verify_locations error: %s " 10801 "ssl_verify_peer requires setting " 10802 "either ssl_ca_path or ssl_ca_file. Is any of them " 10810 if (!reload_lock) {
10819 while (reload_lock) {
10852 if (conn->ssl == NULL) {
10856 ret =
SSL_set_fd(conn->ssl, conn->client.sock);
10869 ret = func(conn->ssl);
10887 static const char *
10904 (
void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
10906 (
void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
10911 #if !defined(NO_SSL_DL) 10913 load_dll(
struct mg_context *ctx,
const char *dll_name,
struct ssl_func *sw)
10920 struct ssl_func *fp;
10922 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
10923 mg_cry(
fc(ctx),
"%s: cannot load %s", __func__, dll_name);
10927 for (fp = sw; fp->name != NULL; fp++) {
10930 u.fp = (
void (*)(
void))dlsym(dll_handle, fp->name);
10935 u.p = dlsym(dll_handle, fp->name);
10937 if (u.fp == NULL) {
10939 "%s: %s: cannot find %s",
10943 dlclose(dll_handle);
10960 #if defined(SSL_ALREADY_INITIALIZED) 10963 static int cryptolib_users = 0;
10973 #if !defined(NO_SSL_DL) 10974 if (!cryptolib_dll_handle) {
10976 if (!cryptolib_dll_handle) {
10993 size =
sizeof(pthread_mutex_t) * ((
size_t)(i));
10994 if ((ssl_mutexes = (pthread_mutex_t *)
mg_malloc(size)) == NULL) {
10996 "%s: cannot allocate mutexes: %s",
11003 pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr);
11018 "%s: cannot open certificate file %s: %s",
11028 "%s: cannot open private key file %s: %s",
11037 "%s: certificate and private key do not match: %s",
11045 "%s: cannot use certificate chain file %s: %s",
11059 if (version_id > 0)
11061 if (version_id > 1)
11063 if (version_id > 2)
11065 if (version_id > 3)
11077 int should_verify_peer;
11078 const char *ca_path;
11079 const char *ca_file;
11080 int use_default_verify_paths;
11082 time_t now_rt = time(NULL);
11083 struct timespec now_mt;
11094 && ctx->callbacks.init_ssl == NULL) {
11102 #if !defined(NO_SSL_DL) 11103 if (!ssllib_dll_handle) {
11105 if (!ssllib_dll_handle) {
11130 (ctx->callbacks.init_ssl == NULL)
11132 : (ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data));
11137 if (callback_ret < 0) {
11138 mg_cry(
fc(ctx),
"SSL callback returned error: %i", callback_ret);
11141 if (callback_ret > 0) {
11151 clock_gettime(CLOCK_MONOTONIC, &now_mt);
11155 strlen(ctx->config[LISTENING_PORTS]));
11160 (
const unsigned char *)&ssl_context_id,
11161 sizeof(ssl_context_id));
11169 should_verify_peer =
11173 use_default_verify_paths =
11177 if (should_verify_peer) {
11183 "SSL_CTX_load_verify_locations error: %s " 11184 "ssl_verify_peer requires setting " 11185 "either ssl_ca_path or ssl_ca_file. Is any of them " 11196 if (use_default_verify_paths
11199 "SSL_CTX_set_default_verify_paths error: %s",
11243 pthread_mutex_destroy(&ssl_mutexes[i]);
11246 ssl_mutexes = NULL;
11258 if (path != NULL && !
mg_stat(
fc(ctx), path, &file)) {
11259 mg_cry(
fc(ctx),
"Cannot open %s: %s", path, strerror(
ERRNO));
11271 return check_acl(ctx, (uint32_t)0x7f000001UL) != -1;
11281 conn->path_info = NULL;
11282 conn->num_bytes_sent = conn->consumed_content = 0;
11283 conn->status_code = -1;
11284 conn->is_chunked = 0;
11285 conn->must_close = conn->request_len = conn->throttle = 0;
11286 conn->request_info.content_length = -1;
11287 conn->request_info.remote_user = NULL;
11288 conn->request_info.request_method = NULL;
11289 conn->request_info.request_uri = NULL;
11290 conn->request_info.local_uri = NULL;
11291 conn->request_info.uri = NULL;
11293 conn->request_info.http_version = NULL;
11294 conn->request_info.num_headers = 0;
11295 conn->data_len = 0;
11296 conn->chunk_remainder = 0;
11297 conn->internal_error = 0;
11304 int r0 = 0, r1, r2;
11309 DWORD tv = (DWORD)milliseconds;
11323 #if defined(TCP_USER_TIMEOUT) 11324 unsigned int uto = (
unsigned int)milliseconds;
11325 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (
const void *)&uto,
sizeof(uto));
11328 memset(&tv, 0,
sizeof(tv));
11329 tv.tv_sec = milliseconds / 1000;
11330 tv.tv_usec = (milliseconds * 1000) % 1000000;
11335 sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv,
sizeof(tv));
11337 sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv,
sizeof(tv));
11339 return r0 || r1 || r2;
11346 if (setsockopt(sock,
11349 (SOCK_OPT_TYPE)&nodelay_on,
11350 sizeof(nodelay_on)) != 0) {
11362 #if defined(_WIN32) 11366 struct linger linger;
11375 linger.l_onoff = 1;
11376 linger.l_linger = 1;
11378 if (setsockopt(conn->client.sock,
11382 sizeof(linger)) != 0) {
11384 "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
11390 shutdown(conn->client.sock, SHUT_WR);
11393 #if defined(_WIN32) 11402 NULL, conn, buf,
sizeof(buf), 1
E-10 );
11415 if (!conn || !conn->ctx) {
11419 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 11420 if (conn->lua_websocket_state) {
11421 lua_websocket_close(conn, conn->lua_websocket_state);
11422 conn->lua_websocket_state = NULL;
11427 if ((conn->ctx->callbacks.connection_close != NULL)
11428 && (conn->ctx->context_type == 1)) {
11429 conn->ctx->callbacks.connection_close(conn);
11434 conn->must_close = 1;
11437 if (conn->ssl != NULL) {
11460 struct mg_context *client_ctx = NULL;
11463 if (conn == NULL) {
11467 if (conn->ctx->context_type == 2) {
11468 client_ctx = conn->ctx;
11470 conn->ctx->stop_flag = 1;
11474 if (conn->client_ssl_ctx != NULL) {
11479 if (client_ctx != NULL) {
11481 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
11482 if (client_ctx->workerthreadids[i] != 0) {
11486 mg_free(client_ctx->workerthreadids);
11488 (
void)pthread_mutex_destroy(&conn->mutex);
11494 static struct mg_connection *
11500 static struct mg_context fake_ctx;
11501 struct mg_connection *conn = NULL;
11506 client_options->
host,
11507 client_options->
port,
11514 }
else if ((conn = (
struct mg_connection *)
11531 "SSL_CTX_new error");
11540 socklen_t len = (sa.sa.sa_family == AF_INET)
11541 ?
sizeof(conn->client.rsa.sin)
11542 :
sizeof(conn->client.rsa.sin6);
11543 struct sockaddr *psa =
11544 (sa.sa.sa_family == AF_INET)
11545 ? (
struct sockaddr *)&(conn->client.rsa.sin)
11546 : (
struct sockaddr *)&(conn->client.rsa.sin6);
11548 socklen_t len =
sizeof(conn->client.rsa.sin);
11549 struct sockaddr *psa = (
struct sockaddr *)&(conn->client.rsa.sin);
11553 conn->buf = (
char *)(conn + 1);
11554 conn->ctx = &fake_ctx;
11555 conn->client.sock = sock;
11556 conn->client.lsa = sa;
11558 if (getsockname(sock, psa, &len) != 0) {
11560 "%s: getsockname() failed: %s",
11565 conn->client.is_ssl = use_ssl ? 1 : 0;
11566 (
void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
11570 fake_ctx.ssl_ctx = conn->client_ssl_ctx;
11585 "Can not use SSL client certificate");
11607 "SSL connection error");
11623 char *error_buffer,
11624 size_t error_buffer_size)
11629 error_buffer_size);
11633 struct mg_connection *
11637 char *error_buffer,
11638 size_t error_buffer_size)
11641 memset(&opts, 0,
sizeof(opts));
11647 error_buffer_size);
11651 static const struct {
11656 {
"https://", 8, 443},
11658 {
"wss://", 6, 443},
11672 char *hostend, *portbegin, *portend;
11673 unsigned long port;
11679 if (uri[0] ==
'*' && uri[1] ==
'\0') {
11683 if (uri[0] ==
'/') {
11706 port = strtoul(portbegin + 1, &portend, 10);
11707 if ((portend != hostend) || !port || !
is_valid_port(port)) {
11720 static const char *
11723 const char *server_domain;
11724 size_t server_domain_len;
11725 size_t request_domain_len = 0;
11726 unsigned long port = 0;
11728 const char *hostbegin = NULL;
11729 const char *hostend = NULL;
11730 const char *portbegin;
11736 if (!server_domain) {
11739 server_domain_len = strlen(server_domain);
11740 if (!server_domain_len) {
11750 hostend = strchr(hostbegin,
'/');
11754 portbegin = strchr(hostbegin,
':');
11755 if ((!portbegin) || (portbegin > hostend)) {
11757 request_domain_len = (size_t)(hostend - hostbegin);
11759 port = strtoul(portbegin + 1, &portend, 10);
11760 if ((portend != hostend) || !port || !
is_valid_port(port)) {
11763 request_domain_len = (size_t)(portbegin - hostbegin);
11775 #if defined(USE_IPV6) 11776 if (conn->client.lsa.sa.sa_family == AF_INET6) {
11777 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
11784 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
11790 if ((request_domain_len != server_domain_len)
11791 || (0 != memcmp(server_domain, hostbegin, server_domain_len))) {
11801 getreq(
struct mg_connection *conn,
char *ebuf,
size_t ebuf_len,
int *err)
11805 if (ebuf_len > 0) {
11824 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
11826 conn->request_len =
11827 read_request(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
11830 if (conn->request_len >= 0 && conn->data_len < conn->request_len) {
11836 "Invalid request size");
11841 if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
11847 "Request Too Large");
11850 }
else if (conn->request_len <= 0) {
11851 if (conn->data_len > 0) {
11857 "Client sent malformed request");
11861 conn->must_close = 1;
11867 "Client did not send a request");
11873 &conn->request_info) <= 0) {
11884 if ((cl =
get_header(&conn->request_info,
"Content-Length")) != NULL) {
11886 char *endptr = NULL;
11887 conn->content_len = strtoll(cl, &endptr, 10);
11888 if (endptr == cl) {
11899 conn->request_info.content_length = conn->content_len;
11900 }
else if ((cl =
get_header(&conn->request_info,
"Transfer-Encoding"))
11903 conn->is_chunked = 1;
11904 }
else if (!
mg_strcasecmp(conn->request_info.request_method,
"POST")
11908 conn->content_len = -1;
11913 conn->content_len = -1;
11916 conn->content_len = 0;
11932 struct mg_context *octx = conn->ctx;
11933 struct mg_context rctx = *(conn->ctx);
11936 if (timeout >= 0) {
11937 mg_snprintf(conn, NULL, txt,
sizeof(txt),
"%i", timeout);
11945 ret =
getreq(conn, ebuf, ebuf_len, &err);
11950 conn->request_info.uri = conn->request_info.request_uri;
11954 return (ret == 0) ? -1 : +1;
11960 struct mg_connection *
11969 struct mg_connection *conn;
11980 if (conn != NULL) {
11988 "Error sending request");
11990 getreq(conn, ebuf, ebuf_len, &reqerr);
11994 conn->request_info.uri = conn->request_info.request_uri;
11999 if (ebuf[0] !=
'\0' && conn != NULL) {
12009 struct websocket_client_thread_data {
12010 struct mg_connection *conn;
12013 void *callback_data;
12017 #if defined(USE_WEBSOCKET) 12019 static unsigned __stdcall websocket_client_thread(
void *data)
12022 websocket_client_thread(
void *data)
12025 struct websocket_client_thread_data *cdata =
12026 (
struct websocket_client_thread_data *)data;
12030 if (cdata->conn->ctx) {
12031 if (cdata->conn->ctx->callbacks.init_thread) {
12034 cdata->conn->ctx->callbacks.init_thread(cdata->conn->ctx, 3);
12038 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
12040 DEBUG_TRACE(
"%s",
"Websocket client thread exited\n");
12042 if (cdata->close_handler != NULL) {
12043 cdata->close_handler(cdata->conn, cdata->callback_data);
12057 struct mg_connection *
12061 char *error_buffer,
12062 size_t error_buffer_size,
12064 const char *origin,
12069 struct mg_connection *conn = NULL;
12071 #if defined(USE_WEBSOCKET) 12072 struct mg_context *newctx = NULL;
12073 struct websocket_client_thread_data *thread_data;
12074 static const char *magic =
"x3JJHMbDL1EzLkh9GBhXDw==";
12075 static const char *handshake_req;
12077 if (origin != NULL) {
12078 handshake_req =
"GET %s HTTP/1.1\r\n" 12080 "Upgrade: websocket\r\n" 12081 "Connection: Upgrade\r\n" 12082 "Sec-WebSocket-Key: %s\r\n" 12083 "Sec-WebSocket-Version: 13\r\n" 12087 handshake_req =
"GET %s HTTP/1.1\r\n" 12089 "Upgrade: websocket\r\n" 12090 "Connection: Upgrade\r\n" 12091 "Sec-WebSocket-Key: %s\r\n" 12092 "Sec-WebSocket-Version: 13\r\n" 12109 if (conn == NULL || (strcmp(conn->request_info.request_uri,
"101") != 0)) {
12110 if (!*error_buffer) {
12117 "Unexpected server reply");
12119 DEBUG_TRACE(
"Websocket client connect error: %s\r\n", error_buffer);
12120 if (conn != NULL) {
12129 newctx = (
struct mg_context *)
mg_malloc(
sizeof(
struct mg_context));
12130 memcpy(newctx, conn->ctx,
sizeof(
struct mg_context));
12131 newctx->user_data = user_data;
12132 newctx->context_type = 2;
12133 newctx->cfg_worker_threads = 1;
12134 newctx->workerthreadids =
12135 (pthread_t *)
mg_calloc(newctx->cfg_worker_threads,
sizeof(pthread_t));
12136 conn->ctx = newctx;
12137 thread_data = (
struct websocket_client_thread_data *)
12138 mg_calloc(
sizeof(
struct websocket_client_thread_data), 1);
12139 thread_data->conn = conn;
12140 thread_data->data_handler = data_func;
12141 thread_data->close_handler = close_func;
12142 thread_data->callback_data = NULL;
12148 (
void *)thread_data,
12149 newctx->workerthreadids) != 0) {
12150 mg_free((
void *)thread_data);
12151 mg_free((
void *)newctx->workerthreadids);
12156 "Websocket client connect thread could not be started\r\n");
12163 (
void)error_buffer;
12164 (
void)error_buffer_size;
12179 if (conn && conn->ctx) {
12181 int keep_alive_enabled, keep_alive, discard_len;
12183 const char *hostend;
12184 int reqerr, uri_type;
12186 keep_alive_enabled =
12191 conn->data_len = 0;
12193 if (!
getreq(conn, ebuf,
sizeof(ebuf), &reqerr)) {
12207 "Bad HTTP version: [%s]",
12212 if (ebuf[0] ==
'\0') {
12213 uri_type =
get_uri_type(conn->request_info.request_uri);
12214 switch (uri_type) {
12217 conn->request_info.local_uri = NULL;
12221 conn->request_info.local_uri =
12222 conn->request_info.request_uri;
12228 conn->request_info.request_uri, conn);
12230 conn->request_info.local_uri = hostend;
12232 conn->request_info.local_uri = NULL;
12240 "Invalid URI: [%s]",
12247 conn->request_info.uri = conn->request_info.local_uri;
12250 if (ebuf[0] ==
'\0') {
12251 if (conn->request_info.local_uri) {
12254 if (conn->ctx->callbacks.end_request != NULL) {
12255 conn->ctx->callbacks.end_request(conn,
12256 conn->status_code);
12261 conn->must_close = 1;
12264 conn->must_close = 1;
12281 keep_alive = conn->ctx->stop_flag == 0 && keep_alive_enabled
12285 discard_len = conn->content_len >= 0 && conn->request_len > 0
12286 && conn->request_len + conn->content_len
12287 < (int64_t)conn->data_len
12288 ? (
int)(conn->request_len + conn->content_len)
12291 if (discard_len < 0)
12293 conn->data_len -= discard_len;
12294 if (conn->data_len > 0) {
12296 conn->buf + discard_len,
12297 (
size_t)conn->data_len);
12303 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
12307 }
while (keep_alive);
12316 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue))) 12321 (
void)pthread_mutex_lock(&ctx->thread_mutex);
12325 while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
12326 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
12330 if (ctx->sq_head > ctx->sq_tail) {
12332 *sp = ctx->queue[ctx->sq_tail %
QUEUE_SIZE(ctx)];
12335 DEBUG_TRACE(
"grabbed socket %d, going busy", sp ? sp->sock : -1);
12344 (
void)pthread_cond_signal(&ctx->sq_empty);
12345 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
12347 return !ctx->stop_flag;
12355 struct mg_context *ctx = (
struct mg_context *)thread_func_param;
12356 struct mg_connection *conn;
12357 struct mg_workerTLS tls;
12358 #if defined(MG_LEGACY_INTERFACE) 12366 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12367 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
12370 if (ctx->callbacks.init_thread) {
12372 ctx->callbacks.init_thread(ctx, 1);
12377 if (conn == NULL) {
12378 mg_cry(
fc(ctx),
"%s",
"Cannot create new connection struct, OOM");
12380 pthread_setspecific(sTlsKey, &tls);
12382 conn->buf = (
char *)(conn + 1);
12384 conn->request_info.user_data = ctx->user_data;
12388 (
void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
12394 conn->conn_birth_time = time(NULL);
12400 #if defined(USE_IPV6) 12401 if (conn->client.rsa.sa.sa_family == AF_INET6) {
12402 conn->request_info.remote_port =
12403 ntohs(conn->client.rsa.sin6.sin6_port);
12407 conn->request_info.remote_port =
12408 ntohs(conn->client.rsa.sin.sin_port);
12412 sizeof(conn->request_info.remote_addr),
12413 &conn->client.rsa);
12415 #if defined(MG_LEGACY_INTERFACE) 12417 addr = ntohl(conn->client.rsa.sin.sin_addr.s_addr);
12418 memcpy(&conn->request_info.remote_ip, &addr, 4);
12421 conn->request_info.is_ssl = conn->client.is_ssl;
12423 if (!conn->client.is_ssl
12438 (
void)pthread_mutex_lock(&ctx->thread_mutex);
12439 ctx->running_worker_threads--;
12440 (
void)pthread_cond_signal(&ctx->thread_cond);
12442 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
12444 pthread_setspecific(sTlsKey, NULL);
12445 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12446 CloseHandle(tls.pthread_cond_helper_mutex);
12448 pthread_mutex_destroy(&conn->mutex);
12458 static unsigned __stdcall
worker_thread(
void *thread_func_param)
12477 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue))) 12481 (
void)pthread_mutex_lock(&ctx->thread_mutex);
12484 while (ctx->stop_flag == 0
12485 && ctx->sq_head - ctx->sq_tail >=
QUEUE_SIZE(ctx)) {
12486 (
void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
12489 if (ctx->sq_head - ctx->sq_tail <
QUEUE_SIZE(ctx)) {
12491 ctx->queue[ctx->sq_head %
QUEUE_SIZE(ctx)] = *sp;
12493 DEBUG_TRACE(
"queued socket %d", sp ? sp->sock : -1);
12496 (
void)pthread_cond_signal(&ctx->sq_full);
12497 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
12507 socklen_t len =
sizeof(so.rsa);
12515 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
12517 }
else if (!
check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
12519 mg_cry(
fc(ctx),
"%s: %s is not allowed to connect", __func__, src_addr);
12526 so.is_ssl = listener->is_ssl;
12527 so.ssl_redir = listener->ssl_redir;
12528 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
12530 "%s: getsockname() failed: %s",
12542 if (setsockopt(so.sock,
12545 (SOCK_OPT_TYPE)&on,
12546 sizeof(on)) != 0) {
12548 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
12567 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
12596 struct mg_context *ctx = (
struct mg_context *)thread_func_param;
12597 struct mg_workerTLS tls;
12598 struct pollfd *pfd;
12600 unsigned int workerthreadcount;
12609 #if defined(_WIN32) 12610 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
12611 #elif defined(USE_MASTER_THREAD_PRIORITY) 12612 int min_prio = sched_get_priority_min(SCHED_RR);
12613 int max_prio = sched_get_priority_max(SCHED_RR);
12614 if ((min_prio >= 0) && (max_prio >= 0)
12615 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
12616 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
12617 struct sched_param sched_param = {0};
12618 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
12619 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
12624 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12625 tls.pthread_cond_helper_mutex = CreateEvent(NULL,
FALSE,
FALSE, NULL);
12628 pthread_setspecific(sTlsKey, &tls);
12630 if (ctx->callbacks.init_thread) {
12632 ctx->callbacks.init_thread(ctx, 0);
12636 ctx->start_time = time(NULL);
12640 (
struct pollfd *)
mg_calloc(ctx->num_listening_sockets,
sizeof(pfd[0]));
12641 while (pfd != NULL && ctx->stop_flag == 0) {
12642 for (i = 0; i < ctx->num_listening_sockets; i++) {
12643 pfd[i].fd = ctx->listening_sockets[i].sock;
12644 pfd[i].events = POLLIN;
12647 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
12648 for (i = 0; i < ctx->num_listening_sockets; i++) {
12654 if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
12667 pthread_cond_broadcast(&ctx->sq_full);
12670 (
void)pthread_mutex_lock(&ctx->thread_mutex);
12671 while (ctx->running_worker_threads > 0) {
12672 (
void)pthread_cond_wait(&ctx->thread_cond, &ctx->thread_mutex);
12674 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
12677 workerthreadcount = ctx->cfg_worker_threads;
12678 for (i = 0; i < workerthreadcount; i++) {
12679 if (ctx->workerthreadids[i] != 0) {
12684 #if !defined(NO_SSL) 12685 if (ctx->ssl_ctx != NULL) {
12691 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12692 CloseHandle(tls.pthread_cond_helper_mutex);
12694 pthread_setspecific(sTlsKey, NULL);
12699 ctx->stop_flag = 2;
12705 static unsigned __stdcall
master_thread(
void *thread_func_param)
12724 struct mg_handler_info *tmp_rh;
12730 if (ctx->callbacks.exit_context) {
12731 ctx->callbacks.exit_context(ctx);
12737 (
void)pthread_mutex_destroy(&ctx->thread_mutex);
12738 (
void)pthread_cond_destroy(&ctx->thread_cond);
12739 (
void)pthread_cond_destroy(&ctx->sq_empty);
12740 (
void)pthread_cond_destroy(&ctx->sq_full);
12743 (
void)pthread_mutex_destroy(&ctx->nonce_mutex);
12745 #if defined(USE_TIMERS) 12751 if (ctx->config[i] != NULL) {
12752 #if defined(_MSC_VER) 12753 #pragma warning(suppress : 6001) 12760 while (ctx->handlers) {
12761 tmp_rh = ctx->handlers;
12762 ctx->handlers = tmp_rh->next;
12769 if (ctx->ssl_ctx != NULL) {
12775 if (ctx->workerthreadids != NULL) {
12776 mg_free(ctx->workerthreadids);
12781 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12782 DeleteCriticalSection(&global_log_file_lock);
12784 #if !defined(_WIN32) 12785 pthread_mutexattr_destroy(&pthread_mutex_attr);
12788 pthread_key_delete(sTlsKey);
12809 mt = ctx->masterthreadid;
12814 ctx->masterthreadid = 0;
12815 ctx->stop_flag = 1;
12818 while (ctx->stop_flag != 2) {
12825 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12826 (
void)WSACleanup();
12834 #if defined(_WIN32) 12835 #if !defined(__SYMBIAN32__) 12837 DWORD dwVersion = 0;
12838 DWORD dwMajorVersion = 0;
12839 DWORD dwMinorVersion = 0;
12843 #pragma warning(push) 12845 #pragma warning(disable : 4996) 12847 dwVersion = GetVersion();
12849 #pragma warning(pop) 12852 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
12853 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
12854 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
12859 (
unsigned)dwMajorVersion,
12860 (
unsigned)dwMinorVersion);
12866 struct utsname name;
12867 memset(&name, 0,
sizeof(name));
12874 struct mg_context *
12877 const char **options)
12879 struct mg_context *ctx;
12880 const char *
name, *value, *default_value;
12881 int idx, ok, workerthreadcount;
12883 void (*exit_callback)(
const struct mg_context *ctx) = 0;
12885 struct mg_workerTLS tls;
12887 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12889 WSAStartup(MAKEWORD(2, 2), &data);
12893 if ((ctx = (
struct mg_context *)
mg_calloc(1,
sizeof(*ctx))) == NULL) {
12898 ctx->auth_nonce_mask =
12899 (uint64_t)
get_random() ^ (uint64_t)(ptrdiff_t)(options);
12903 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12904 InitializeCriticalSection(&global_log_file_lock);
12906 #if !defined(_WIN32) 12907 pthread_mutexattr_init(&pthread_mutex_attr);
12908 pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
12911 if (0 != pthread_key_create(&sTlsKey,
tls_dtor)) {
12916 mg_cry(
fc(ctx),
"Cannot initialize thread local storage");
12926 tls.is_master = -1;
12928 #if defined(_WIN32) && !defined(__SYMBIAN32__) 12929 tls.pthread_cond_helper_mutex = NULL;
12931 pthread_setspecific(sTlsKey, &tls);
12933 #if defined(USE_LUA) 12934 lua_init_optional_libraries();
12937 ok = 0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr);
12938 ok &= 0 == pthread_cond_init(&ctx->thread_cond, NULL);
12939 ok &= 0 == pthread_cond_init(&ctx->sq_empty, NULL);
12940 ok &= 0 == pthread_cond_init(&ctx->sq_full, NULL);
12941 ok &= 0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr);
12945 mg_cry(
fc(ctx),
"Cannot initialize thread synchronization objects");
12947 pthread_setspecific(sTlsKey, NULL);
12952 ctx->callbacks = *callbacks;
12954 ctx->callbacks.exit_context = 0;
12956 ctx->user_data = user_data;
12957 ctx->handlers = NULL;
12959 #if defined(USE_LUA) && defined(USE_WEBSOCKET) 12960 ctx->shared_lua_websockets = 0;
12963 while (options && (name = *options++) != NULL) {
12965 mg_cry(
fc(ctx),
"Invalid option: %s", name);
12967 pthread_setspecific(sTlsKey, NULL);
12969 }
else if ((value = *options++) == NULL) {
12970 mg_cry(
fc(ctx),
"%s: option value cannot be NULL", name);
12972 pthread_setspecific(sTlsKey, NULL);
12975 if (ctx->config[idx] != NULL) {
12976 mg_cry(
fc(ctx),
"warning: %s: duplicate option", name);
12986 if (ctx->config[i] == NULL && default_value != NULL) {
12987 ctx->config[i] =
mg_strdup(default_value);
12991 #if defined(NO_FILES) 12993 mg_cry(
fc(ctx),
"%s",
"Document root must not be set");
12995 pthread_setspecific(sTlsKey, NULL);
13005 #
if !defined(NO_SSL)
13009 #
if !defined(_WIN32)
13014 pthread_setspecific(sTlsKey, NULL);
13018 #if !defined(_WIN32) && !defined(__SYMBIAN32__) 13024 workerthreadcount = atoi(ctx->config[
NUM_THREADS]);
13027 mg_cry(
fc(ctx),
"Too many worker threads");
13029 pthread_setspecific(sTlsKey, NULL);
13033 if (workerthreadcount > 0) {
13034 ctx->cfg_worker_threads = ((
unsigned int)(workerthreadcount));
13035 ctx->workerthreadids =
13036 (pthread_t *)
mg_calloc(ctx->cfg_worker_threads,
sizeof(pthread_t));
13037 if (ctx->workerthreadids == NULL) {
13038 mg_cry(
fc(ctx),
"Not enough memory for worker thread ID array");
13040 pthread_setspecific(sTlsKey, NULL);
13045 #if defined(USE_TIMERS) 13046 if (timers_init(ctx) != 0) {
13047 mg_cry(
fc(ctx),
"Error creating timers");
13049 pthread_setspecific(sTlsKey, NULL);
13055 if (ctx->callbacks.init_context) {
13056 ctx->callbacks.init_context(ctx);
13058 ctx->callbacks.exit_context = exit_callback;
13059 ctx->context_type = 1;
13065 for (i = 0; i < ctx->cfg_worker_threads; i++) {
13066 (
void)pthread_mutex_lock(&ctx->thread_mutex);
13067 ctx->running_worker_threads++;
13068 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
13071 &ctx->workerthreadids[i]) != 0) {
13072 (
void)pthread_mutex_lock(&ctx->thread_mutex);
13073 ctx->running_worker_threads--;
13074 (
void)pthread_mutex_unlock(&ctx->thread_mutex);
13077 "Cannot start worker thread %i: error %ld",
13082 "Cannot create threads: error %ld",
13085 pthread_setspecific(sTlsKey, NULL);
13092 pthread_setspecific(sTlsKey, NULL);
13101 static const unsigned feature_set = 0
13105 #if !defined(NO_FILES) 13108 #if !defined(NO_SSL) 13111 #if !defined(NO_CGI) 13114 #if defined(USE_IPV6) 13117 #if defined(USE_WEBSOCKET) 13120 #if defined(USE_LUA) 13123 #if defined(USE_DUKTAPE) 13126 #if !defined(NO_CACHING) 13132 #if defined(MG_LEGACY_INTERFACE) 13135 #if defined(MEMORY_DEBUGGING) 13138 #if defined(USE_TIMERS) 13141 #if !defined(NO_NONCE_CHECK) 13144 #if !defined(NO_POPEN) 13148 return (feature & feature_set);
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)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
static void mg_fclose(struct file *filep)
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
size_t mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
#define SSL_CTX_set_ecdh_auto(ctx, onoff)
static int authorize(struct mg_connection *conn, struct file *filep)
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)
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)
#define PRINTF_ARGS(x, y)
#define mg_mkdir(conn, path, mode)
static struct ssl_func crypto_sw[]
static int set_uid_option(struct mg_context *ctx)
static const struct @129 abs_uri_protocols[]
static int set_acl_option(struct mg_context *ctx)
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT
#define is_websocket_protocol(conn)
static int consume_socket(struct mg_context *ctx, struct socket *sp)
void mg_unlock_context(struct mg_context *ctx)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
static void bin2str(char *to, const unsigned char *p, size_t len)
static void print_props(struct mg_connection *conn, const char *uri, struct file *filep)
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_request(struct mg_connection *conn)
const struct mg_option * mg_get_valid_options(void)
static void mg_vsnprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap)
static int refresh_trust(struct mg_connection *conn)
#define DEBUG_TRACE(fmt,...)
static void reset_per_request_attributes(struct mg_connection *conn)
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 const char * get_header(const struct mg_request_info *ri, const char *name)
#define MAX_WORKER_THREADS
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
struct mg_request_info::mg_header http_headers[64]
static void * master_thread(void *thread_func_param)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
#define CGI_ENVIRONMENT_SIZE
static const struct @128 builtin_mime_types[]
static void handle_static_file_request(struct mg_connection *conn, const char *path, struct file *filep, const char *mime_type)
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 int ssl_use_pem_file(struct mg_context *ctx, const char *pem)
static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_environment *env)
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 * load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
int(* mg_authorization_handler)(struct mg_connection *conn, void *cbdata)
static void close_connection(struct mg_connection *conn)
static void close_socket_gracefully(struct mg_connection *conn)
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
static int check_authorization(struct mg_connection *conn, const char *path)
const char * default_value
const char * mg_get_option(const struct mg_context *ctx, const char *name)
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 void parse_http_headers(char **buf, struct mg_request_info *ri)
static struct mg_connection * fc(struct mg_context *ctx)
static int read_request(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread)
static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
static void dir_scan_callback(struct de *de, void *data)
const char * request_method
static const char * mg_strcasestr(const char *big_str, const char *small_str)
static struct ssl_func ssl_sw[]
static int mg_atomic_dec(volatile int *addr)
#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 void handle_propfind(struct mg_connection *conn, const char *path, struct file *filep)
static int is_authorized_for_put(struct mg_connection *conn)
static void * cryptolib_dll_handle
static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
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 void send_authorization_request(struct mg_connection *conn)
static int is_valid_port(unsigned long port)
static int is_not_modified(const struct mg_connection *conn, const struct file *filep)
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)
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)
static const char * mg_fgets(char *buf, size_t size, struct file *filep, char **p)
static constexpr double L
static int set_tcp_nodelay(SOCKET sock, int nodelay_on)
static void * ssllib_dll_handle
static void send_http_error(struct mg_connection *, int, PRINTF_FORMAT_STRING(const char *fmt),...)
static const char * suggest_connection_header(const struct mg_connection *conn)
static int get_request_len(const char *buf, int buflen)
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 mg_fgetc(struct file *filep, int offset)
void mg_send_file(struct mg_connection *conn, const char *path)
static int set_non_blocking_mode(SOCKET sock)
#define SSLv23_client_method
#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 void print_dav_dir_entry(struct de *de, void *data)
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 void handle_file_based_request(struct mg_connection *conn, const char *path, struct file *filep)
static int mg_join_thread(pthread_t threadid)
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void(*cb)(struct de *, void *))
int mg_printf(struct mg_connection *conn, const char *fmt,...)
static pthread_mutexattr_t pthread_mutex_attr
char * mg_md5(char buf[33],...)
static int set_ssl_option(struct mg_context *ctx)
#define SSL_CTX_check_private_key
void(* mg_websocket_close_handler)(const struct mg_connection *, void *)
static time_t parse_date_string(const char *datetime)
static int is_file_opened(const struct file *filep)
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)
static void uninitialize_ssl(struct mg_context *ctx)
const void * SOCK_OPT_TYPE
static void * worker_thread_run(void *thread_func_param)
static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct file *filep)
struct ssl_method_st SSL_METHOD
static void addenv(struct cgi_environment *env, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
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 int initialize_ssl(struct mg_context *ctx)
int mg_url_encode(const char *src, char *dst, size_t dst_len)
static int push(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len, double timeout)
static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
#define SSL_CTX_set_default_verify_paths
static int is_put_or_delete_method(const struct mg_connection *conn)
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)
static char mg_getc(struct mg_connection *conn)
static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
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)
const char * mg_get_response_code_text(struct mg_connection *conn, int response_code)
static int mg_fopen(const struct mg_connection *conn, const char *path, const char *mode, struct file *filep)
CIVETWEB_API struct mg_connection * mg_connect_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size)
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
static const char * header_val(const struct mg_connection *conn, const char *header)
static int remove_directory(struct mg_connection *conn, const char *dir)
static void send_ssi_file(struct mg_connection *, const char *, struct file *, int)
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)
int mg_strcasecmp(const char *s1, const char *s2)
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 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
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)
const char * mg_get_header(const struct mg_connection *conn, const char *name)
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 CRYPTO_cleanup_all_ex_data
static int mg_atomic_inc(volatile int *addr)
#define CRYPTO_set_locking_callback
static uint32_t get_remote_ip(const struct mg_connection *conn)
static void fclose_on_exec(struct file *filep, struct mg_connection *conn)
static constexpr double s
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
int(* mg_websocket_connect_handler)(const struct mg_connection *, void *)
#define SSL_load_error_strings
static void process_new_connection(struct mg_connection *conn)
#define PASSWORDS_FILE_NAME
static void * worker_thread(void *thread_func_param)
static void interpret_uri(struct mg_connection *conn, char *filename, size_t filename_buf_len, struct file *filep, int *is_found, int *is_script_resource, int *is_websocket_request, int *is_put_or_delete_request)
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 void construct_etag(char *buf, size_t buf_len, const struct file *filep)
#define SSL_CTX_set_verify
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
static void mg_set_handler_type(struct mg_context *ctx, const char *uri, int handler_type, int is_delete_request, mg_request_handler handler, 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 STRUCT_FILE_INITIALIZER
void(* mg_websocket_ready_handler)(struct mg_connection *, void *)
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 read_auth_file(struct file *filep, struct read_auth_file_struct *workdata)
#define IGNORE_UNUSED_RESULT(a)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
static int parse_http_message(char *buf, int len, struct mg_request_info *ri)
static int sslize(struct mg_connection *conn, SSL_CTX *s, int(*func)(SSL *))
static void send_file_data(struct mg_connection *conn, struct file *filep, int64_t offset, int64_t len)
static void print_dir_entry(struct de *de)
static __inline void * mg_malloc(size_t a)
const char * mg_get_builtin_mime_type(const char *path)
static int set_sock_timeout(SOCKET sock, int milliseconds)
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 void open_auth_file(struct mg_connection *conn, const char *path, struct file *filep)
static int get_request_handler(struct mg_connection *conn, int handler_type, mg_request_handler *handler, 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)
void mg_lock_context(struct mg_context *ctx)
void *(* mg_thread_func_t)(void *)
#define SOCKET_TIMEOUT_QUANTUM
#define SSL_CTX_load_verify_locations
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[]
static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
static unsigned long ssl_id_callback(void)
static char * mg_strdup(const char *str)
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 char * skip(char **buf, const char *delimiters)
static int parse_port_string(const struct vec *vec, struct socket *so)
static int get_month_index(const char *s)
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
struct mg_context * mg_get_context(const struct mg_connection *conn)
static int is_file_in_memory(const struct mg_connection *conn, const char *path, struct file *filep)
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)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path, struct file *filep)
int mg_strncasecmp(const char *s1, const char *s2, size_t len)
static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
static long ssl_get_protocol(int version_id)
static void * realloc2(void *ptr, size_t size)