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;
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) 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);
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) {