15 #define __STDC_LIMIT_MACROS
18 # pragma warning(disable:4127) // conditional expression is constant
19 # pragma warning(disable:4100) // unreferenced formal parameter
20 # pragma warning(disable:4245) // signed/unsigned mismatch
21 # pragma warning(disable:4505) // unreferenced local function has been removed
22 # pragma comment(lib, "ws2_32.lib")
26 # define GCC_VERSION (__GNUC__*100 + __GNUC_MINOR__)
28 # if GCC_VERSION >= 402 // older GCCs don't support the diagnostic pragma at all
29 # pragma GCC diagnostic ignored "-Wunused-function"
31 # if GCC_VERSION >= 406 // new warning in 4.6
32 # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
41 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
43 #include <sys/socket.h>
67 #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
69 #define _XOPEN_SOURCE 600 // For flockfile() on Linux
70 #define _LARGEFILE_SOURCE // Enable 64-bit file offsets
71 #define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
74 #if defined(__SYMBIAN32__)
75 #define NO_SSL // SSL is not supported
76 #define NO_CGI // CGI is not supported
77 #define PATH_MAX FILENAME_MAX
78 #endif // __SYMBIAN32__
80 #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
81 #include <sys/types.h>
98 #if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
99 #define _WIN32_WINNT 0x0400 // To make it link in VS2005
103 #define PATH_MAX MAX_PATH
111 #include <winsock2.h>
112 #define NO_CGI // WinCE has no pipes
117 #define errno GetLastError()
118 #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
121 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
122 ((uint64_t)((uint32_t)(hi))) << 32))
123 #define RATE_DIFF 10000000 // 100 nsecs
124 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
125 #define SYS2UNIX_TIME(lo, hi) \
126 (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
131 #if defined(_MSC_VER) && _MSC_VER < 1300
133 #define STR(x) STRX(x)
134 #define __func__ "line " STR(__LINE__)
135 #define strtoull(x, y, z) strtoul(x, y, z)
136 #define strtoll(x, y, z) strtol(x, y, z)
138 #define __func__ __FUNCTION__
139 #define strtoull(x, y, z) _strtoui64(x, y, z)
140 #define strtoll(x, y, z) _strtoi64(x, y, z)
143 #define ERRNO GetLastError()
145 #define SSL_LIB "ssleay32.dll"
146 #define CRYPTO_LIB "libeay32.dll"
148 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
150 #if !defined(EWOULDBLOCK)
151 #define EWOULDBLOCK WSAEWOULDBLOCK
152 #endif // !EWOULDBLOCK
154 #define INT64_FMT "I64d"
156 #define WINCDECL __cdecl
158 #define snprintf _snprintf
159 #define vsnprintf _vsnprintf
160 #define sleep(x) Sleep((x) * 1000)
162 #define pipe(x) _pipe(x, BUFSIZ, _O_BINARY)
163 #define popen(x, y) _popen(x, y)
164 #define pclose(x) _pclose(x)
165 #define close(x) _close(x)
166 #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
168 #define fseeko(x, y, z) fseek((x), (y), (z))
169 #define fdopen(x, y) _fdopen((x), (y))
170 #define write(x, y, z) _write((x), (y), (unsigned) z)
171 #define read(x, y, z) _read((x), (y), (unsigned) z)
172 #define flockfile(x) (void) 0
173 #define funlockfile(x) (void) 0
176 #define fileno(x) _fileno(x)
177 #endif // !fileno MINGW #defines fileno
180 typedef struct {
HANDLE signal, broadcast;} pthread_cond_t;
182 #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
191 static FILE *
mg_fopen(
const char *path,
const char *mode);
193 #if defined(HAVE_STDINT)
200 #define INT64_MAX 9223372036854775807
201 #endif // HAVE_STDINT
210 WIN32_FIND_DATAW info;
211 struct dirent result;
214 #else // UNIX specific
215 #include <sys/wait.h>
216 #include <sys/socket.h>
217 #include <sys/select.h>
218 #include <netinet/in.h>
219 #include <arpa/inet.h>
220 #include <sys/time.h>
222 #include <inttypes.h>
228 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
232 #if defined(__MACH__)
233 #define SSL_LIB "libssl.dylib"
234 #define CRYPTO_LIB "libcrypto.dylib"
236 #if !defined(SSL_LIB)
237 #define SSL_LIB "libssl.so"
239 #if !defined(CRYPTO_LIB)
240 #define CRYPTO_LIB "libcrypto.so"
244 #define IS_DIRSEP_CHAR(c) ((c) == '/')
248 #define closesocket(a) close(a)
249 #define mg_fopen(x, y) fopen(x, y)
250 #define mg_mkdir(x, y) mkdir(x, y)
251 #define mg_remove(x) remove(x)
252 #define mg_rename(x, y) rename(x, y)
254 #define INVALID_SOCKET (-1)
255 #define INT64_FMT PRId64
259 #endif // End of Windows and UNIX specific includes
263 #define MONGOOSE_VERSION "3.1"
264 #define PASSWORDS_FILE_NAME ".htpasswd"
265 #define CGI_ENVIRONMENT_SIZE 4096
266 #define MAX_CGI_ENVIR_VARS 64
267 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
271 return GetCurrentThreadId();
276 #define DEBUG_TRACE(x) do { \
278 printf("*** %lu.%p.%s.%d: ", \
279 (unsigned long) time(NULL), (void *) pthread_self(), \
280 __func__, __LINE__); \
284 funlockfile(stdout); \
287 #define DEBUG_TRACE(x)
292 typedef int socklen_t;
293 #endif // NO_SOCKLEN_T
295 typedef void * (*mg_thread_func_t)(
void *);
302 typedef struct ssl_st
SSL;
306 #define SSL_ERROR_WANT_READ 2
307 #define SSL_ERROR_WANT_WRITE 3
308 #define SSL_FILETYPE_PEM 1
309 #define CRYPTO_LOCK 1
311 #if defined(NO_SSL_DL)
341 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
342 #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
343 #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
344 #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
345 #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
346 #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
347 #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
348 #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
349 #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
350 #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
351 #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
352 #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
353 const char *, int)) ssl_sw[11].ptr)
354 #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
355 const char *, int)) ssl_sw[12].ptr)
356 #define SSL_CTX_set_default_passwd_cb \
357 (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
358 #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
359 #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
360 #define SSL_CTX_use_certificate_chain_file \
361 (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
363 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
364 #define CRYPTO_set_locking_callback \
365 (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
366 #define CRYPTO_set_id_callback \
367 (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
368 #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
369 #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
377 {
"SSL_accept", NULL},
378 {
"SSL_connect", NULL},
381 {
"SSL_get_error", NULL},
382 {
"SSL_set_fd", NULL},
384 {
"SSL_CTX_new", NULL},
385 {
"SSLv23_server_method", NULL},
386 {
"SSL_library_init", NULL},
387 {
"SSL_CTX_use_PrivateKey_file", NULL},
388 {
"SSL_CTX_use_certificate_file",NULL},
389 {
"SSL_CTX_set_default_passwd_cb",NULL},
390 {
"SSL_CTX_free", NULL},
391 {
"SSL_load_error_strings", NULL},
392 {
"SSL_CTX_use_certificate_chain_file", NULL},
398 {
"CRYPTO_num_locks", NULL},
399 {
"CRYPTO_set_locking_callback", NULL},
400 {
"CRYPTO_set_id_callback", NULL},
401 {
"ERR_get_error", NULL},
402 {
"ERR_error_string", NULL},
408 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
409 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
458 "C",
"cgi_extensions",
".cgi,.pl,.php",
459 "E",
"cgi_environment", NULL,
460 "G",
"put_delete_passwords_file", NULL,
461 "I",
"cgi_interpreter", NULL,
462 "P",
"protect_uri", NULL,
463 "R",
"authentication_domain",
"mydomain.com",
464 "S",
"ssi_extensions",
".shtml,.shtm",
465 "a",
"access_log_file", NULL,
466 "c",
"ssl_chain_file", NULL,
467 "d",
"enable_directory_listing",
"yes",
468 "e",
"error_log_file", NULL,
469 "g",
"global_passwords_file", NULL,
470 "i",
"index_files",
"index.html,index.htm,index.cgi",
471 "k",
"enable_keep_alive",
"no",
472 "l",
"access_control_list", NULL,
473 "M",
"max_request_size",
"16384",
474 "m",
"extra_mime_types", NULL,
475 "p",
"listening_ports",
"8080",
476 "r",
"document_root",
".",
477 "s",
"ssl_certificate", NULL,
478 "t",
"num_threads",
"10",
479 "u",
"run_as_user", NULL,
482 #define ENTRIES_PER_CONFIG_OPTION 3
534 if (strcmp(config_options[i], name) == 0 ||
535 strcmp(config_options[i + 1], name) == 0) {
546 }
else if (ctx->
config[i] == NULL) {
561 (void) vsnprintf(buf,
sizeof(buf), fmt, ap);
574 timestamp = time(NULL);
577 "[%010lu] [error] [client %s] ",
578 (
unsigned long) timestamp,
582 (void) fprintf(fp,
"%s %s: ",
587 (void) fprintf(fp,
"%s", buf);
609 fake_connection.
ctx =
ctx;
610 return &fake_connection;
617 static void mg_strlcpy(
register char *dst,
register const char *src,
size_t n) {
618 for (; *src !=
'\0' && n > 1; n--) {
625 return tolower(* (
const unsigned char *) s);
634 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
644 }
while (diff == 0 && s1[-1] !=
'\0');
652 if ((p = (
char *) malloc(len + 1)) != NULL) {
668 const char *fmt, va_list ap) {
674 n = vsnprintf(buf, buflen, fmt, ap);
677 cry(conn,
"vsnprintf error");
679 }
else if (n >= (
int) buflen) {
680 cry(conn,
"truncating vsnprintf buffer: [%.*s]",
681 n > 200 ? 200 : n, buf);
682 n = (int) buflen - 1;
690 const char *fmt, ...) {
705 static char *
skip_quoted(
char **
buf,
const char *delimiters,
const char *whitespace,
char quotechar) {
706 char *p, *begin_word, *end_word, *end_whitespace;
709 end_word = begin_word + strcspn(begin_word, delimiters);
712 if (end_word > begin_word) {
714 while (*p == quotechar) {
716 if (*end_word ==
'\0') {
720 size_t end_off = strcspn(end_word + 1, delimiters);
721 memmove (p, end_word, end_off + 1);
723 end_word += end_off + 1;
726 for (p++; p < end_word; p++) {
731 if (*end_word ==
'\0') {
734 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
736 for (p = end_word; p < end_whitespace; p++) {
740 *buf = end_whitespace;
748 static char *
skip(
char **
buf,
const char *delimiters) {
749 return skip_quoted(buf, delimiters, delimiters, 0);
776 struct vec *eq_val) {
777 if (list == NULL || *list ==
'\0') {
782 if ((list = strchr(val->
ptr,
',')) != NULL) {
784 val->
len = list - val->
ptr;
788 list = val->
ptr + strlen(val->
ptr);
789 val->
len = list - val->
ptr;
792 if (eq_val != NULL) {
796 eq_val->
ptr = (
const char *) memchr(val->
ptr,
'=', val->
len);
797 if (eq_val->
ptr != NULL) {
812 path_len = strlen(path);
814 while ((ext_list =
next_option(ext_list, &ext_vec, NULL)) != NULL)
815 if (ext_vec.
len < path_len &&
817 ext_vec.
ptr, ext_vec.
len) == 0)
829 return (header == NULL && http_version && !strcmp(http_version,
"1.1")) ||
838 const char *reason,
const char *fmt, ...) {
850 if (status > 199 && status != 204 && status != 304) {
851 len =
mg_snprintf(conn, buf,
sizeof(buf),
"Error %d: %s", status, reason);
852 cry(conn,
"%s", buf);
856 len +=
mg_vsnprintf(conn, buf + len,
sizeof(buf) - len, fmt, ap);
862 "Content-Type: text/plain\r\n"
863 "Content-Length: %d\r\n"
864 "Connection: %s\r\n\r\n", status, reason, len,
870 #if defined(_WIN32) && !defined(__SYMBIAN32__)
873 *mutex = CreateMutex(NULL, FALSE, NULL);
874 return *mutex == NULL ? -1 : 0;
878 return CloseHandle(*mutex) == 0 ? -1 : 0;
882 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
886 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
889 static int pthread_cond_init(pthread_cond_t *cv,
const void *unused) {
891 cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
892 cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
893 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
896 static int pthread_cond_wait(pthread_cond_t *cv,
pthread_mutex_t *mutex) {
897 HANDLE handles[] = {cv->signal, cv->broadcast};
898 ReleaseMutex(*mutex);
899 WaitForMultipleObjects(2, handles, FALSE, INFINITE);
900 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
903 static int pthread_cond_signal(pthread_cond_t *cv) {
904 return SetEvent(cv->signal) == 0 ? -1 : 0;
907 static int pthread_cond_broadcast(pthread_cond_t *cv) {
910 return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
913 static int pthread_cond_destroy(pthread_cond_t *cv) {
914 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
918 static void change_slashes_to_backslashes(
char *path) {
921 for (i = 0; path[i] !=
'\0'; i++) {
925 if (path[i] ==
'\\' && i > 0)
926 while (path[i + 1] ==
'\\' || path[i + 1] ==
'/')
927 (void) memmove(path + i + 1,
928 path + i + 2, strlen(path + i + 1));
934 static void to_unicode(
const char *path,
wchar_t *wbuf,
size_t wbuf_len) {
938 change_slashes_to_backslashes(buf);
941 p = buf + strlen(buf) - 1;
944 while (p > buf && *p ==
'\\' && p[-1] !=
':') {
953 (*p == 0x2e && p > buf) ||
956 (void) fprintf(stderr,
"Rejecting suspicious path: [%s]", buf);
961 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int) wbuf_len);
962 WideCharToMultiByte(CP_UTF8, 0, wbuf, (
int) wbuf_len, buf2,
sizeof(buf2),
964 if (strcmp(buf, buf2) != 0) {
970 #if defined(_WIN32_WCE)
971 static time_t time(time_t *ptime) {
977 SystemTimeToFileTime(&st, &ft);
978 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
987 static struct tm *localtime(
const time_t *ptime,
struct tm *ptm) {
991 TIME_ZONE_INFORMATION tzinfo;
998 FileTimeToLocalFileTime(&ft, &lft);
999 FileTimeToSystemTime(&lft, &st);
1000 ptm->tm_year = st.wYear - 1900;
1001 ptm->tm_mon = st.wMonth - 1;
1002 ptm->tm_wday = st.wDayOfWeek;
1003 ptm->tm_mday = st.wDay;
1004 ptm->tm_hour = st.wHour;
1005 ptm->tm_min = st.wMinute;
1006 ptm->tm_sec = st.wSecond;
1009 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
1014 static struct tm *gmtime(
const time_t *ptime,
struct tm *ptm) {
1016 return localtime(ptime, ptm);
1019 static size_t strftime(
char *dst,
size_t dst_size,
const char *fmt,
1020 const struct tm *tm) {
1021 (void) snprintf(dst, dst_size,
"implement strftime() for WinCE");
1026 static int mg_rename(
const char* oldname,
const char* newname) {
1030 to_unicode(oldname, woldbuf,
ARRAY_SIZE(woldbuf));
1031 to_unicode(newname, wnewbuf,
ARRAY_SIZE(wnewbuf));
1033 return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
1037 static FILE *
mg_fopen(
const char *path,
const char *mode) {
1041 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode,
ARRAY_SIZE(wmode));
1043 return _wfopen(wbuf, wmode);
1049 WIN32_FILE_ATTRIBUTE_DATA info;
1053 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
1054 stp->
size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
1055 stp->
mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
1056 info.ftLastWriteTime.dwHighDateTime);
1058 info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1065 static int mg_remove(
const char *path) {
1068 return DeleteFileW(wbuf) ? 0 : -1;
1071 static int mg_mkdir(
const char *path,
int mode) {
1077 change_slashes_to_backslashes(buf);
1079 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf,
sizeof(wbuf));
1081 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1085 static DIR * opendir(
const char *name) {
1091 SetLastError(ERROR_BAD_ARGUMENTS);
1092 }
else if ((dir = (DIR *) malloc(
sizeof(*dir))) == NULL) {
1093 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1096 attrs = GetFileAttributesW(wpath);
1097 if (attrs != 0xFFFFFFFF &&
1098 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1099 (void) wcscat(wpath, L
"\\*");
1100 dir->handle = FindFirstFileW(wpath, &dir->info);
1101 dir->result.d_name[0] =
'\0';
1111 static int closedir(DIR *dir) {
1115 if (dir->handle != INVALID_HANDLE_VALUE)
1116 result = FindClose(dir->handle) ? 0 : -1;
1121 SetLastError(ERROR_BAD_ARGUMENTS);
1127 struct dirent * readdir(DIR *dir) {
1128 struct dirent *result = 0;
1131 if (dir->handle != INVALID_HANDLE_VALUE) {
1132 result = &dir->result;
1133 (void) WideCharToMultiByte(CP_UTF8, 0,
1134 dir->info.cFileName, -1, result->d_name,
1135 sizeof(result->d_name), NULL, NULL);
1137 if (!FindNextFileW(dir->handle, &dir->info)) {
1138 (void) FindClose(dir->handle);
1139 dir->handle = INVALID_HANDLE_VALUE;
1143 SetLastError(ERROR_FILE_NOT_FOUND);
1146 SetLastError(ERROR_BAD_ARGUMENTS);
1152 #define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
1155 return _beginthread((
void (__cdecl *)(
void *)) f, 0, p) == -1L ? -1 : 0;
1158 static HANDLE dlopen(
const char *dll_name,
int flags) {
1161 to_unicode(dll_name, wbuf,
ARRAY_SIZE(wbuf));
1162 return LoadLibraryW(wbuf);
1165 #if !defined(NO_CGI)
1167 static int kill(pid_t pid,
int sig_num) {
1168 (void) TerminateProcess(pid, sig_num);
1169 (void) CloseHandle(pid);
1174 char *envblk,
char *envp[],
int fd_stdin,
1175 int fd_stdout,
const char *dir) {
1180 PROCESS_INFORMATION pi;
1184 (void) memset(&si, 0,
sizeof(si));
1185 (void) memset(&pi, 0,
sizeof(pi));
1189 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1190 si.wShowWindow = SW_HIDE;
1192 me = GetCurrentProcess();
1193 (void) DuplicateHandle(me, (
HANDLE) _get_osfhandle(fd_stdin), me,
1194 &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1195 (void) DuplicateHandle(me, (
HANDLE) _get_osfhandle(fd_stdout), me,
1196 &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1200 if (interp == NULL) {
1203 if ((fp = fopen(cmdline,
"r")) != NULL) {
1204 (void) fgets(buf,
sizeof(buf), fp);
1205 if (buf[0] !=
'#' || buf[1] !=
'!') {
1210 for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
1219 (void)
mg_snprintf(conn, cmdline,
sizeof(cmdline),
"%s%s%s%c%s",
1220 interp, interp[0] ==
'\0' ?
"" :
" ", dir,
DIRSEP, prog);
1223 if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
1224 CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
1225 cry(conn,
"%s: CreateProcess(%s): %d",
1227 pi.hProcess = (pid_t) -1;
1229 (void) close(fd_stdin);
1230 (void) close(fd_stdout);
1233 (void) CloseHandle(si.hStdOutput);
1234 (void) CloseHandle(si.hStdInput);
1235 (void) CloseHandle(pi.hThread);
1237 return (pid_t) pi.hProcess;
1242 unsigned long on = 1;
1243 return ioctlsocket(sock, FIONBIO, &on);
1251 if (stat(path, &st) == 0) {
1253 stp->
size = st.st_size;
1254 stp->
mtime = st.st_mtime;
1264 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1270 pthread_attr_t attr;
1273 (void) pthread_attr_init(&attr);
1274 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1278 if ((retval =
pthread_create(&thread_id, &attr, func, param)) != 0) {
1287 char *envblk,
char *envp[],
int fd_stdin,
1288 int fd_stdout,
const char *dir) {
1294 if ((pid = fork()) == -1) {
1297 }
else if (pid == 0) {
1299 if (chdir(dir) != 0) {
1301 }
else if (dup2(fd_stdin, 0) == -1) {
1303 }
else if (dup2(fd_stdout, 1) == -1) {
1306 (void) dup2(fd_stdout, 2);
1307 (void) close(fd_stdin);
1308 (void) close(fd_stdout);
1312 if (interp == NULL) {
1313 (void) execle(prog, prog, NULL, envp);
1316 (void) execle(interp, interp, prog, NULL, envp);
1317 cry(conn,
"%s: execle(%s %s): %s",
__func__, interp, prog,
1324 (void) close(fd_stdin);
1325 (void) close(fd_stdout);
1335 flags = fcntl(sock, F_GETFL, 0);
1336 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1350 while (sent < len) {
1353 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
1357 }
else if (fp != NULL) {
1358 n = fwrite(buf + sent, 1, (
size_t)k, fp);
1362 n = send(sock, buf + sent, (
size_t)k, 0);
1381 }
else if (fp != NULL) {
1385 nread =
read(fileno(fp), buf, (
size_t) len);
1389 nread = recv(sock, buf, (
size_t) len, 0);
1396 int n, buffered_len, nread;
1397 const char *buffered;
1408 if (to_read < (
int64_t) len) {
1409 len = (int) to_read;
1415 assert(buffered_len >= 0);
1420 if (len < (
size_t) buffered_len) {
1423 memcpy(buf, buffered, (
size_t)buffered_len);
1424 len -= buffered_len;
1425 buf = (
char *) buf + buffered_len;
1427 nread = buffered_len;
1436 buf = (
char *) buf + n;
1447 (
const char *) buf, (
int64_t) len);
1459 return mg_write(conn, buf, (
size_t)len);
1467 static size_t url_decode(
const char *src,
size_t src_len,
char *dst,
1468 size_t dst_len,
int is_form_url_encoded) {
1471 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
1473 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
1474 if (src[i] ==
'%' &&
1475 isxdigit(* (
const unsigned char *) (src + i + 1)) &&
1476 isxdigit(* (
const unsigned char *) (src + i + 2))) {
1477 a = tolower(* (
const unsigned char *) (src + i + 1));
1478 b = tolower(* (
const unsigned char *) (src + i + 2));
1481 }
else if (is_form_url_encoded && src[i] ==
'+') {
1497 int mg_get_var(
const char *buf,
size_t buf_len,
const char *name,
1498 char *dst,
size_t dst_len) {
1499 const char *p, *e, *s;
1500 size_t name_len, len;
1502 name_len = strlen(name);
1508 for (p = buf; p != NULL && p + name_len < e; p++) {
1509 if ((p == buf || p[-1] ==
'&') && p[name_len] ==
'=' &&
1516 s = (
const char *) memchr(p,
'&', (
size_t)(e - p));
1523 if ((
size_t) (s - p) < dst_len) {
1524 len =
url_decode(p, (
size_t)(s - p), dst, dst_len, 1);
1534 char *dst,
size_t dst_size) {
1535 const char *s, *p, *end;
1536 int name_len, len = -1;
1543 name_len = strlen(cookie_name);
1544 end = s + strlen(s);
1546 for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
1547 if (s[name_len] ==
'=') {
1549 if ((p = strchr(s,
' ')) == NULL)
1553 if (*s ==
'"' && p[-1] ==
'"' && p > s + 1) {
1557 if ((
size_t) (p - s) < dst_size) {
1571 struct vec *document_root) {
1572 const char *root, *uri;
1573 int len_of_matched_uri;
1574 struct vec uri_vec, path_vec;
1577 len_of_matched_uri = 0;
1580 while ((root =
next_option(root, &uri_vec, &path_vec)) != NULL) {
1581 if (memcmp(uri, uri_vec.
ptr, uri_vec.
len) == 0) {
1582 *document_root = path_vec;
1583 len_of_matched_uri = uri_vec.
len;
1588 return len_of_matched_uri;
1592 const char *uri,
char *buf,
1594 struct vec vec = {0};
1598 mg_snprintf(conn, buf, buf_len,
"%.*s%s", (
int) vec.
len, vec.
ptr, uri + match_len);
1600 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1601 change_slashes_to_backslashes(buf);
1610 func(conn->
ssl) == 1;
1614 const char *host,
int port,
int use_ssl) {
1616 struct sockaddr_in sin;
1621 cry(conn,
"%s: SSL is not initialized",
__func__);
1622 }
else if ((he = gethostbyname(host)) == NULL) {
1627 sin.sin_family = AF_INET;
1628 sin.sin_port = htons((
uint16_t) port);
1629 sin.sin_addr = * (
struct in_addr *) he->h_addr_list[0];
1630 if (connect(sock, (
struct sockaddr *) &sin,
sizeof(sin)) != 0) {
1631 cry(conn,
"%s: connect(%s:%d): %s",
__func__, host, port,
1635 calloc(1,
sizeof(*newconn))) == NULL) {
1659 for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
1661 if (!isprint(* (
const unsigned char *) s) && *s !=
'\r' &&
1662 *s !=
'\n' && * (
const unsigned char *) s < 128) {
1664 }
else if (s[0] ==
'\n' && s[1] ==
'\n') {
1665 len = (int) (s - buf) + 2;
1666 }
else if (s[0] ==
'\n' && &s[1] < e &&
1667 s[1] ==
'\r' && s[2] ==
'\n') {
1668 len = (int) (s - buf) + 3;
1678 for (i = 0; i <
ARRAY_SIZE(month_names); i++)
1679 if (!strcmp(s, month_names[i]))
1687 static const unsigned short days_before_month[] = {
1688 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
1691 int second, minute, hour, day, month, year, leap_days, days;
1692 time_t result = (time_t) 0;
1694 if (((sscanf(datetime,
"%d/%3s/%d %d:%d:%d",
1695 &day, month_str, &year, &hour, &minute, &second) == 6) ||
1696 (sscanf(datetime,
"%d %3s %d %d:%d:%d",
1697 &day, month_str, &year, &hour, &minute, &second) == 6) ||
1698 (sscanf(datetime,
"%*3s, %d %3s %d %d:%d:%d",
1699 &day, month_str, &year, &hour, &minute, &second) == 6) ||
1700 (sscanf(datetime,
"%d-%3s-%d %d:%d:%d",
1701 &day, month_str, &year, &hour, &minute, &second) == 6)) &&
1705 leap_days = year / 4 - year / 100 + year / 400;
1706 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
1707 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
1718 while (*s !=
'\0') {
1720 if (s[-1] ==
'/' || s[-1] ==
'\\') {
1722 while (*s ==
'/' || *s ==
'\\') {
1727 while (*s ==
'.' && s[1] ==
'.') {
1735 static const struct {
1741 {
".html", 5,
"text/html", 9},
1742 {
".htm", 4,
"text/html", 9},
1743 {
".shtm", 5,
"text/html", 9},
1744 {
".shtml", 6,
"text/html", 9},
1745 {
".css", 4,
"text/css", 8},
1746 {
".js", 3,
"application/x-javascript", 24},
1747 {
".ico", 4,
"image/x-icon", 12},
1748 {
".gif", 4,
"image/gif", 9},
1749 {
".jpg", 4,
"image/jpeg", 10},
1750 {
".jpeg", 5,
"image/jpeg", 10},
1751 {
".png", 4,
"image/png", 9},
1752 {
".svg", 4,
"image/svg+xml", 13},
1753 {
".torrent", 8,
"application/x-bittorrent", 24},
1754 {
".wav", 4,
"audio/x-wav", 11},
1755 {
".mp3", 4,
"audio/x-mp3", 11},
1756 {
".mid", 4,
"audio/mid", 9},
1757 {
".m3u", 4,
"audio/x-mpegurl", 15},
1758 {
".ram", 4,
"audio/x-pn-realaudio", 20},
1759 {
".xml", 4,
"text/xml", 8},
1760 {
".xslt", 5,
"application/xml", 15},
1761 {
".ra", 3,
"audio/x-pn-realaudio", 20},
1762 {
".doc", 4,
"application/msword", 19},
1763 {
".exe", 4,
"application/octet-stream", 24},
1764 {
".zip", 4,
"application/x-zip-compressed", 28},
1765 {
".xls", 4,
"application/excel", 17},
1766 {
".tgz", 4,
"application/x-tar-gz", 20},
1767 {
".tar", 4,
"application/x-tar", 17},
1768 {
".gz", 3,
"application/x-gunzip", 20},
1769 {
".arj", 4,
"application/x-arj-compressed", 28},
1770 {
".rar", 4,
"application/x-arj-compressed", 28},
1771 {
".rtf", 4,
"application/rtf", 15},
1772 {
".pdf", 4,
"application/pdf", 15},
1773 {
".swf", 4,
"application/x-shockwave-flash",29},
1774 {
".mpg", 4,
"video/mpeg", 10},
1775 {
".mpeg", 5,
"video/mpeg", 10},
1776 {
".mp4", 4,
"video/mp4", 9},
1777 {
".m4v", 4,
"video/x-m4v", 11},
1778 {
".asf", 4,
"video/x-ms-asf", 14},
1779 {
".avi", 4,
"video/x-msvideo", 15},
1780 {
".bmp", 4,
"image/bmp", 9},
1788 struct vec ext_vec, mime_vec;
1789 const char *list, *ext;
1792 path_len = strlen(path);
1797 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
1799 ext = path + path_len - ext_vec.
len;
1818 vec->
ptr =
"text/plain";
1829 #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
1830 #define byteReverse(buf, len) // Do nothing
1835 t = (
uint32_t) ((
unsigned) buf[3] << 8 | buf[2]) << 16 |
1836 ((
unsigned) buf[1] << 8 | buf[0]);
1843 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1844 #define F2(x, y, z) F1(z, x, y)
1845 #define F3(x, y, z) (x ^ y ^ z)
1846 #define F4(x, y, z) (y ^ (x | ~z))
1848 #define MD5STEP(f, w, x, y, z, data, s) \
1849 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
1854 ctx->
buf[0] = 0x67452301;
1855 ctx->
buf[1] = 0xefcdab89;
1856 ctx->
buf[2] = 0x98badcfe;
1857 ctx->
buf[3] = 0x10325476;
1871 MD5STEP(
F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1872 MD5STEP(
F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1873 MD5STEP(
F1, c, d, a, b, in[2] + 0x242070db, 17);
1874 MD5STEP(
F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1875 MD5STEP(
F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1876 MD5STEP(
F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1877 MD5STEP(
F1, c, d, a, b, in[6] + 0xa8304613, 17);
1878 MD5STEP(
F1, b, c, d, a, in[7] + 0xfd469501, 22);
1879 MD5STEP(
F1, a, b, c, d, in[8] + 0x698098d8, 7);
1880 MD5STEP(
F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1881 MD5STEP(
F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1882 MD5STEP(
F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1883 MD5STEP(
F1, a, b, c, d, in[12] + 0x6b901122, 7);
1884 MD5STEP(
F1, d, a, b, c, in[13] + 0xfd987193, 12);
1885 MD5STEP(
F1, c, d, a, b, in[14] + 0xa679438e, 17);
1886 MD5STEP(
F1, b, c, d, a, in[15] + 0x49b40821, 22);
1888 MD5STEP(
F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1889 MD5STEP(
F2, d, a, b, c, in[6] + 0xc040b340, 9);
1890 MD5STEP(
F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1891 MD5STEP(
F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1892 MD5STEP(
F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1893 MD5STEP(
F2, d, a, b, c, in[10] + 0x02441453, 9);
1894 MD5STEP(
F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1895 MD5STEP(
F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1896 MD5STEP(
F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1897 MD5STEP(
F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1898 MD5STEP(
F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1899 MD5STEP(
F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1900 MD5STEP(
F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1901 MD5STEP(
F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1902 MD5STEP(
F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1903 MD5STEP(
F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1905 MD5STEP(
F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1906 MD5STEP(
F3, d, a, b, c, in[8] + 0x8771f681, 11);
1907 MD5STEP(
F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1908 MD5STEP(
F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1909 MD5STEP(
F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1910 MD5STEP(
F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1911 MD5STEP(
F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1912 MD5STEP(
F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1913 MD5STEP(
F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1914 MD5STEP(
F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1915 MD5STEP(
F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1916 MD5STEP(
F3, b, c, d, a, in[6] + 0x04881d05, 23);
1917 MD5STEP(
F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1918 MD5STEP(
F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1919 MD5STEP(
F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1920 MD5STEP(
F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1922 MD5STEP(
F4, a, b, c, d, in[0] + 0xf4292244, 6);
1923 MD5STEP(
F4, d, a, b, c, in[7] + 0x432aff97, 10);
1924 MD5STEP(
F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1925 MD5STEP(
F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1926 MD5STEP(
F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1927 MD5STEP(
F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1928 MD5STEP(
F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1929 MD5STEP(
F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1930 MD5STEP(
F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1931 MD5STEP(
F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1932 MD5STEP(
F4, c, d, a, b, in[6] + 0xa3014314, 15);
1933 MD5STEP(
F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1934 MD5STEP(
F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1935 MD5STEP(
F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1936 MD5STEP(
F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1937 MD5STEP(
F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1951 ctx->
bits[1] += len >> 29;
1953 t = (t >> 3) & 0x3f;
1956 unsigned char *p = (
unsigned char *) ctx->
in + t;
1960 memcpy(p, buf, len);
1971 memcpy(ctx->
in, buf, 64);
1978 memcpy(ctx->
in, buf, len);
1985 count = (ctx->
bits[0] >> 3) & 0x3F;
1987 p = ctx->
in + count;
1989 count = 64 - 1 - count;
1991 memset(p, 0, count);
1994 memset(ctx->
in, 0, 56);
1996 memset(p, 0, count - 8);
2004 memcpy(digest, ctx->
buf, 16);
2005 memset((
char *) ctx, 0,
sizeof(*ctx));
2011 static void bin2str(
char *to,
const unsigned char *p,
size_t len) {
2012 static const char *hex =
"0123456789abcdef";
2014 for (; len--; p++) {
2015 *to++ = hex[p[0] >> 4];
2016 *to++ = hex[p[0] & 0x0f];
2023 unsigned char hash[16];
2031 while ((p = va_arg(ap,
const char *)) != NULL) {
2032 MD5Update(&ctx, (
const unsigned char *) p, (
unsigned) strlen(p));
2037 bin2str(buf, hash,
sizeof(hash));
2042 const char *nonce,
const char *nc,
const char *cnonce,
2043 const char *qop,
const char *response) {
2044 char ha2[32 + 1], expected_response[32 + 1];
2047 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
2048 qop == NULL || response == NULL) {
2055 strlen(response) != 32
2061 mg_md5(ha2, method,
":", uri, NULL);
2062 mg_md5(expected_response, ha1,
":", nonce,
":", nc,
2063 ":", cnonce,
":", qop,
":", ha2, NULL);
2081 cry(
fc(ctx),
"fopen(%s): %s",
2084 (void)
mg_snprintf(conn, name,
sizeof(name),
"%s%c%s",
2089 for (p = path, e = p + strlen(p) - 1; e > p; e--)
2092 (void)
mg_snprintf(conn, name,
sizeof(name),
"%.*s%c%s",
2106 size_t buf_size,
struct ah *
ah) {
2107 char *name, *value, *s;
2108 const char *auth_header;
2110 if ((auth_header =
mg_get_header(conn,
"Authorization")) == NULL ||
2116 (void)
mg_strlcpy(buf, auth_header + 7, buf_size);
2119 (void) memset(ah, 0,
sizeof(*ah));
2124 while (isspace(* (
unsigned char *) s)) {
2138 if (*name ==
'\0') {
2142 if (!strcmp(name,
"username")) {
2144 }
else if (!strcmp(name,
"cnonce")) {
2146 }
else if (!strcmp(name,
"response")) {
2148 }
else if (!strcmp(name,
"uri")) {
2150 }
else if (!strcmp(name,
"qop")) {
2152 }
else if (!strcmp(name,
"nc")) {
2154 }
else if (!strcmp(name,
"nonce")) {
2160 if (ah->
user != NULL) {
2172 char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ];
2179 while (fgets(line,
sizeof(line), fp) != NULL) {
2180 if (sscanf(line,
"%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
2184 if (!strcmp(ah.
user, f_user) &&
2199 struct vec uri_vec, filename_vec;
2207 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
2209 (void)
mg_snprintf(conn, fname,
sizeof(fname),
"%.*s",
2210 (int) filename_vec.
len, filename_vec.
ptr);
2211 if ((fp =
mg_fopen(fname,
"r")) == NULL) {
2212 cry(conn,
"%s: cannot open %s: %s",
__func__, fname, strerror(errno));
2233 "HTTP/1.1 401 Unauthorized\r\n"
2234 "Content-Length: 0\r\n"
2235 "WWW-Authenticate: Digest qop=\"auth\", "
2236 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
2238 (
unsigned long) time(NULL));
2257 const char *user,
const char *pass) {
2259 char line[512], u[512], d[512], ha1[33], tmp[
PATH_MAX];
2266 if (pass != NULL && pass[0] ==
'\0') {
2270 (void) snprintf(tmp,
sizeof(tmp),
"%s.tmp", fname);
2273 if ((fp =
mg_fopen(fname,
"a+")) != NULL) {
2278 if ((fp =
mg_fopen(fname,
"r")) == NULL) {
2280 }
else if ((fp2 =
mg_fopen(tmp,
"w+")) == NULL) {
2286 while (fgets(line,
sizeof(line), fp) != NULL) {
2287 if (sscanf(line,
"%[^:]:%[^:]:%*s", u, d) != 2) {
2291 if (!strcmp(u, user) && !strcmp(d, domain)) {
2294 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
2295 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
2298 (void) fprintf(fp2,
"%s", line);
2303 if (!found && pass != NULL) {
2304 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
2305 (void) fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
2325 static void url_encode(
const char *src,
char *dst,
size_t dst_len) {
2326 static const char *dont_escape =
"._-$,;~()";
2327 static const char *hex =
"0123456789abcdef";
2328 const char *end = dst + dst_len - 1;
2330 for (; *src !=
'\0' && dst < end; src++, dst++) {
2331 if (isalnum(*(
const unsigned char *) src) ||
2332 strchr(dont_escape, * (
const unsigned char *) src) != NULL) {
2334 }
else if (dst + 2 < end) {
2336 dst[1] = hex[(* (
const unsigned char *) src) >> 4];
2337 dst[2] = hex[(* (
const unsigned char *) src) & 0xf];
2349 (void)
mg_snprintf(de->
conn, size,
sizeof(size),
"%s",
"[DIRECTORY]");
2353 if (de->
st.
size < 1024) {
2355 "%lu", (
unsigned long) de->
st.
size);
2356 }
else if (de->
st.
size < 1024 * 1024) {
2358 "%.1fk", (double) de->
st.
size / 1024.0);
2359 }
else if (de->
st.
size < 1024 * 1024 * 1024) {
2361 "%.1fM", (double) de->
st.
size / 1048576);
2364 "%.1fG", (double) de->
st.
size / 1073741824);
2367 (void) strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", localtime(&de->
st.
mtime));
2370 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
2371 "<td> %s</td><td> %s</td></tr>\n",
2381 const struct de *a = (
const struct de *) p1, *b = (
const struct de *) p2;
2385 if (query_string == NULL) {
2386 query_string =
"na";
2393 }
else if (*query_string ==
'n') {
2394 cmp_result = strcmp(a->
file_name, b->file_name);
2395 }
else if (*query_string ==
's') {
2396 cmp_result = a->
st.
size == b->st.size ? 0 :
2397 a->
st.
size > b->st.size ? 1 : -1;
2398 }
else if (*query_string ==
'd') {
2399 cmp_result = a->
st.
mtime == b->st.mtime ? 0 :
2400 a->
st.
mtime > b->st.mtime ? 1 : -1;
2403 return query_string[1] ==
'd' ? -cmp_result : cmp_result;
2407 void *data,
void (*cb)(
struct de *,
void *)) {
2413 if ((dirp = opendir(dir)) == NULL) {
2418 while ((dp = readdir(dirp)) != NULL) {
2420 if (!strcmp(dp->d_name,
".") ||
2421 !strcmp(dp->d_name,
"..") ||
2425 mg_snprintf(conn, path,
sizeof(path),
"%s%c%s", dir, DIRSEP, dp->d_name);
2433 memset(&de.
st, 0,
sizeof(de.
st));
2439 (void) closedir(dirp);
2471 int i, sort_direction;
2476 "Error: opendir(%s): %s", dir, strerror(
ERRNO));
2484 "HTTP/1.1 200 OK\r\n"
2485 "Connection: close\r\n"
2486 "Content-Type: text/html; charset=utf-8\r\n\r\n");
2489 "<html><head><title>Index of %s</title>"
2490 "<style>th {text-align: left;}</style></head>"
2491 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
2492 "<tr><th><a href=\"?n%c\">Name</a></th>"
2493 "<th><a href=\"?d%c\">Modified</a></th>"
2494 "<th><a href=\"?s%c\">Size</a></th></tr>"
2495 "<tr><td colspan=\"3\"><hr></td></tr>",
2497 sort_direction, sort_direction, sort_direction);
2501 "<tr><td><a href=\"%s%s\">%s</a></td>"
2502 "<td> %s</td><td> %s</td></tr>\n",
2521 int to_read, num_read, num_written;
2525 to_read =
sizeof(buf);
2527 to_read = (
int) len;
2530 if ((num_read = fread(buf, 1, (
size_t)to_read, fp)) == 0)
2534 if ((num_written =
mg_write(conn, buf, (
size_t)num_read)) != num_read)
2548 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
2553 char date[64], lm[64], etag[64], range[64];
2554 const char *msg =
"OK", *hdr;
2555 time_t curtime = time(NULL);
2557 struct vec mime_vec;
2566 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
2568 "fopen(%s): %s", path, strerror(
ERRNO));
2578 (void) fseeko(fp, (
off_t) r1, SEEK_SET);
2579 cl = n == 2 ? r2 - r1 + 1: cl - r1;
2581 "Content-Range: bytes "
2584 r1, r1 + cl - 1, stp->
size);
2585 msg =
"Partial Content";
2592 (void)
mg_snprintf(conn, etag,
sizeof(etag),
"%lx.%lx",
2593 (
unsigned long) stp->
mtime, (
unsigned long) stp->
size);
2596 "HTTP/1.1 %d %s\r\n"
2598 "Last-Modified: %s\r\n"
2600 "Content-Type: %.*s\r\n"
2602 "Connection: %s\r\n"
2603 "Accept-Ranges: bytes\r\n"
2616 if (
mg_stat(path, &st) == 0) {
2639 return !strcmp(method,
"GET") || !strcmp(method,
"POST") ||
2640 !strcmp(method,
"HEAD") || !strcmp(method,
"CONNECT") ||
2641 !strcmp(method,
"PUT") || !strcmp(method,
"DELETE") ||
2642 !strcmp(method,
"OPTIONS") || !strcmp(method,
"PROPFIND");
2650 while (*buf !=
'\0' && isspace(* (
unsigned char *) buf)) {
2678 while (*nread < bufsiz && request_len == 0) {
2679 n =
pull(fp, sock, ssl, buf + *nread, bufsiz - *nread);
2695 size_t path_len,
struct mgstat *stp) {
2698 struct vec filename_vec;
2699 size_t n = strlen(path);
2712 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
2715 if (filename_vec.
len > path_len - n)
2722 if (
mg_stat(path, &st) == 0) {
2740 const struct mgstat *stp) {
2747 const char *expect, *buffered;
2749 int to_read, nread, buffered_len, success = 0;
2756 }
else if (expect != NULL &&
mg_strcasecmp(expect,
"100-continue")) {
2759 if (expect != NULL) {
2760 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
2765 assert(buffered_len >= 0);
2768 if (buffered_len > 0) {
2772 push(fp, sock, ssl, buffered, (
int64_t) buffered_len);
2777 to_read =
sizeof(buf);
2782 if (nread <= 0 ||
push(fp, sock, ssl, buf, nread) != nread) {
2801 #if !defined(NO_CGI)
2826 space =
sizeof(block->
buf) - block->
len - 2;
2830 added = block->
buf + block->
len;
2838 if (n > 0 && n < space &&
2843 block->
len += n + 1;
2852 const char *s, *slash;
2853 struct vec var_vec, root;
2863 addenv(blk,
"SERVER_ROOT=%.*s", root.
len, root.ptr);
2864 addenv(blk,
"DOCUMENT_ROOT=%.*s", root.
len, root.ptr);
2867 addenv(blk,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
2868 addenv(blk,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
2869 addenv(blk,
"%s",
"REDIRECT_STATUS=200");
2872 addenv(blk,
"REMOTE_ADDR=%s",
2880 if ((s = strrchr(prog,
'/')) == NULL)
2885 addenv(blk,
"SCRIPT_FILENAME=%s", prog);
2886 addenv(blk,
"PATH_TRANSLATED=%s", prog);
2887 addenv(blk,
"HTTPS=%s", conn->
ssl == NULL ?
"off" :
"on");
2890 addenv(blk,
"CONTENT_TYPE=%s", s);
2896 addenv(blk,
"CONTENT_LENGTH=%s", s);
2898 if ((s = getenv(
"PATH")) != NULL)
2899 addenv(blk,
"PATH=%s", s);
2902 if ((s = getenv(
"COMSPEC")) != NULL)
2903 addenv(blk,
"COMSPEC=%s", s);
2904 if ((s = getenv(
"SYSTEMROOT")) != NULL)
2905 addenv(blk,
"SYSTEMROOT=%s", s);
2907 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL)
2908 addenv(blk,
"LD_LIBRARY_PATH=%s", s);
2911 if ((s = getenv(
"PERLLIB")) != NULL)
2912 addenv(blk,
"PERLLIB=%s", s);
2916 addenv(blk,
"%s",
"AUTH_TYPE=Digest");
2921 p =
addenv(blk,
"HTTP_%s=%s",
2926 for (; *p !=
'=' && *p !=
'\0'; p++) {
2929 *p = (char) toupper(* (
unsigned char *) p);
2935 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
2936 addenv(blk,
"%.*s", var_vec.
len, var_vec.ptr);
2940 blk->
buf[blk->
len++] =
'\0';
2943 assert(blk->
len > 0);
2944 assert(blk->
len < (
int)
sizeof(blk->
buf));
2948 int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
2950 char buf[BUFSIZ], *pbuf, dir[
PATH_MAX], *p;
2961 (void)
mg_snprintf(conn, dir,
sizeof(dir),
"%s", prog);
2962 if ((p = strrchr(dir, DIRSEP)) != NULL) {
2965 dir[0] =
'.', dir[1] =
'\0';
2970 fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
2973 if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
2975 "Cannot create CGI pipe: %s", strerror(
ERRNO));
2978 fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
2980 }
else if ((in = fdopen(fd_stdin[1],
"wb")) == NULL ||
2981 (out = fdopen(fd_stdout[0],
"rb")) == NULL) {
2983 "fopen: %s", strerror(
ERRNO));
2994 fd_stdin[0] = fd_stdout[1] = -1;
3008 buf,
sizeof(buf), &data_len);
3009 if (headers_len <= 0) {
3011 "CGI program sent malformed HTTP headers: [%.*s]",
3016 buf[headers_len - 1] =
'\0';
3025 for (i = 0; i < ri.num_headers; i++) {
3027 ri.http_headers[i].name, ri.http_headers[i].value);
3033 (
size_t)(data_len - headers_len));
3039 if (pid != (pid_t) -1) {
3042 if (fd_stdin[0] != -1) {
3043 (void) close(fd_stdin[0]);
3045 if (fd_stdout[1] != -1) {
3046 (void) close(fd_stdout[1]);
3051 }
else if (fd_stdin[1] != -1) {
3052 (void) close(fd_stdin[1]);
3057 }
else if (fd_stdout[0] != -1) {
3058 (void) close(fd_stdout[0]);
3072 for (s = p = path + 2; (p = strchr(s, DIRSEP)) != NULL; s = ++p) {
3074 if (len >= (
int)
sizeof(buf)) {
3078 memcpy(buf, path, len);
3106 if ((rc =
put_dir(path)) == 0) {
3108 }
else if (rc == -1) {
3110 "put_dir(%s): %s", path, strerror(
ERRNO));
3111 }
else if ((fp =
mg_fopen(path,
"wb+")) == NULL) {
3113 "fopen(%s): %s", path, strerror(
ERRNO));
3121 (void) fseeko(fp, (
off_t) r1, SEEK_SET);
3124 (
void)
mg_printf(conn,
"HTTP/1.1 %d OK\r\n\r\n",
3133 char *tag,
int include_level) {
3134 char file_name[BUFSIZ], path[
PATH_MAX], *p;
3135 struct vec root = {0};
3143 if (sscanf(tag,
" virtual=\"%[^\"]\"", file_name) == 1) {
3145 (void)
mg_snprintf(conn, path,
sizeof(path),
"%.*s%c%s",
3146 (int) root.
len, root.
ptr, DIRSEP, file_name);
3147 }
else if (sscanf(tag,
" file=\"%[^\"]\"", file_name) == 1) {
3150 (void)
mg_snprintf(conn, path,
sizeof(path),
"%s", file_name);
3151 }
else if (sscanf(tag,
" \"%[^\"]\"", file_name) == 1) {
3153 (void)
mg_snprintf(conn, path,
sizeof(path),
"%s", ssi);
3154 if ((p = strrchr(path, DIRSEP)) != NULL) {
3158 sizeof(path) - strlen(path),
"%s", file_name);
3160 cry(conn,
"Bad SSI #include: [%s]", tag);
3164 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
3165 cry(conn,
"Cannot open SSI #include: [%s]: fopen(%s): %s",
3166 tag, path, strerror(
ERRNO));
3179 #if !defined(NO_POPEN)
3184 if (sscanf(tag,
" \"%[^\"]\"", cmd) != 1) {
3185 cry(conn,
"Bad SSI #exec: [%s]", tag);
3186 }
else if ((fp = popen(cmd,
"r")) == NULL) {
3187 cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
3196 FILE *fp,
int include_level) {
3198 int ch,
len, in_ssi_tag;
3200 if (include_level > 10) {
3201 cry(conn,
"SSI #include level is too deep (%s)", path);
3208 while ((ch = fgetc(fp)) != EOF) {
3209 if (in_ssi_tag && ch ==
'>') {
3211 buf[len++] = (char) ch;
3213 assert(len <= (
int)
sizeof(buf));
3214 if (len < 6 || memcmp(buf,
"<!--#", 5) != 0) {
3218 if (!memcmp(buf + 5,
"include", 7)) {
3220 #if !defined(NO_POPEN)
3221 }
else if (!memcmp(buf + 5,
"exec", 4)) {
3225 cry(conn,
"%s: unknown SSI " "command: \"%s\"", path, buf);
3229 }
else if (in_ssi_tag) {
3230 if (len == 5 && memcmp(buf,
"<!--#", 5) != 0) {
3233 }
else if (len == (
int)
sizeof(buf) - 2) {
3234 cry(conn,
"%s: SSI tag is too large", path);
3237 buf[len++] = ch & 0xff;
3238 }
else if (ch ==
'<') {
3244 buf[len++] = ch & 0xff;
3246 buf[len++] = ch & 0xff;
3247 if (len == (
int)
sizeof(buf)) {
3264 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
3270 "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
3281 "HTTP/1.1 200 OK\r\n"
3282 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n"
3293 "<d:href>%s</d:href>"
3296 "<d:resourcetype>%s</d:resourcetype>"
3297 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3298 "<d:getlastmodified>%s</d:getlastmodified>"
3300 "<d:status>HTTP/1.1 200 OK</d:status>"
3322 mg_printf(conn,
"HTTP/1.1 207 Multi-Status\r\n"
3323 "Connection: close\r\n"
3324 "Content-Type: text/xml; charset=utf-8\r\n\r\n");
3327 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3328 "<d:multistatus xmlns:d='DAV:'>\n");
3336 (depth == NULL || strcmp(depth,
"0") != 0)) {
3356 uri_len = strlen(ri->
uri);
3387 }
else if (
mg_stat(path, &st) != 0) {
3391 "HTTP/1.1 301 Moved Permanently\r\n"
3392 "Location: %s/\r\n\r\n", ri->
uri);
3401 "Directory listing denied");
3403 #if !defined(NO_CGI)
3435 int a, b, c, d, port,
len;
3438 memset(so, 0,
sizeof(*so));
3440 if (sscanf(vec->
ptr,
"%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
3442 usa->
u.
sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
3443 }
else if (sscanf(vec->
ptr,
"%d%n", &port, &len) == 1) {
3445 usa->
u.
sin.sin_addr.s_addr = htonl(INADDR_ANY);
3449 assert(len > 0 && len <= (
int) vec->
len);
3451 if (strchr(
"sp,", vec->
ptr[len]) == NULL) {
3457 usa->
len =
sizeof(usa->
u.
sin);
3458 usa->
u.
sin.sin_family = AF_INET;
3466 int on = 1, success = 1;
3469 struct socket so, *listener;
3471 while (success && (list =
next_option(list, &vec, NULL)) != NULL) {
3473 cry(
fc(ctx),
"%s: %.*s: invalid port spec. Expecting list of: %s",
3477 cry(
fc(ctx),
"Cannot add SSL socket, is -ssl_certificate option set?");
3480 #
if !defined(_WIN32)
3483 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
3493 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (
const char*) &on,
3496 listen(sock, 100) != 0) {
3501 }
else if ((listener = (
struct socket *)
3502 calloc(1,
sizeof(*listener))) == NULL) {
3524 const char *header_value;
3527 (void) fprintf(fp,
"%s",
" -");
3529 (void) fprintf(fp,
" \"%s\"", header_value);
3544 (void) strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z",
3552 "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
3562 (void) fputc(
'\n', fp);
3570 return n >= 0 && n <= 255;
3576 int a, b, c, d, n, mask, allowed;
3586 (void) memcpy(&remote_ip, &usa->
u.
sin.sin_addr,
sizeof(remote_ip));
3591 while ((list =
next_option(list, &vec, NULL)) != NULL) {
3594 if (sscanf(vec.
ptr,
"%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) {
3595 cry(
fc(ctx),
"%s: subnet must be [+|-]x.x.x.x[/x]",
__func__);
3597 }
else if (flag !=
'+' && flag !=
'-') {
3603 }
else if (sscanf(vec.
ptr + n,
"/%d", &mask) == 0) {
3605 }
else if (mask < 0 || mask > 32) {
3610 acl_subnet = (a << 24) | (b << 16) | (c << 8) | d;
3611 acl_mask = mask ? 0xffffffff
U << (32 - mask) : 0;
3613 if (acl_subnet == (ntohl(remote_ip) & acl_mask)) {
3618 return allowed ==
'+';
3623 if (fd > (
SOCKET) *max_fd) {
3628 #if !defined(_WIN32)
3637 if ((pw = getpwnam(uid)) == NULL) {
3639 }
else if (setgid(pw->pw_gid) == -1) {
3640 cry(
fc(ctx),
"%s: setgid(%s): %s",
__func__, uid, strerror(errno));
3641 }
else if (setuid(pw->pw_uid) == -1) {
3642 cry(
fc(ctx),
"%s: setuid(%s): %s",
__func__, uid, strerror(errno));
3652 #if !defined(NO_SSL)
3671 #if !defined(NO_SSL_DL)
3674 union {
void *p; void (*fp)(void);} u;
3683 for (fp = sw; fp->
name != NULL; fp++) {
3686 u.fp = (void (*)(void))
dlsym(dll_handle, fp->
name);
3716 #if !defined(NO_SSL_DL)
3730 memset(&request_info, 0,
sizeof(request_info));
3731 request_info.user_data = ctx->
user_data;
3746 if (CTX != NULL && chain != NULL &&
3748 cry(
fc(ctx),
"%s: cannot open %s: %s", NULL, chain,
ssl_error());
3755 if ((ssl_mutexes = (
pthread_mutex_t *) malloc((
size_t)size)) == NULL) {
3789 return path == NULL ||
mg_stat(path, &mgstat) == 0;
3815 struct linger linger;
3821 linger.l_linger = 1;
3822 setsockopt(sock, SOL_SOCKET, SO_LINGER, (
const char *) &linger,
sizeof(linger));
3825 (void) shutdown(sock, SHUT_WR);
3834 n =
pull(NULL, sock, NULL, buf,
sizeof(buf));
3854 int buffered_len, body_len;
3858 assert(buffered_len >= 0);
3865 body_len = buffered_len;
3873 static int parse_url(
const char *url,
char *host,
int *port) {
3876 if (sscanf(url,
"%*[htps]://%1024[^:]:%d%n", host, port, &len) == 2 ||
3877 sscanf(url,
"%1024[^:]:%d%n", host, port, &len) == 2) {
3878 }
else if (sscanf(url,
"%*[htps]://%1024[^/]%n", host, &len) == 1) {
3881 sscanf(url,
"%1024[^/]%n", host, &len);
3891 char host[1025], buf[BUFSIZ];
3892 int port,
is_ssl, len, i, n;
3895 if (ri->
uri == NULL ||
3896 ri->
uri[0] ==
'/' ||
3901 if (conn->
peer == NULL) {
3903 if ((conn->
peer =
mg_connect(conn, host, port, is_ssl)) == NULL) {
3928 buf,
sizeof(buf))) > 0) {
3929 if (
mg_write(conn, buf, (
size_t)n) != n) {
3944 return (uri[0] ==
'/' || (uri[0] ==
'*' && uri[1] ==
'\0'));
3949 int keep_alive_enabled;
3976 "Cannot parse HTTP request: [%.*s]", conn->
data_len, conn->
buf);
3985 conn->
content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10);
4024 (void) pthread_cond_signal(&ctx->
sq_empty);
4036 conn->
buf = (
char *) (conn + 1);
4037 assert(conn != NULL);
4066 (void) pthread_cond_signal(&ctx->
cond);
4090 (void) pthread_cond_signal(&ctx->
sq_full);
4100 accepted.
lsa = listener->
lsa;
4111 cry(
fc(ctx),
"%s: %s is not allowed to connect",
4134 tv.tv_usec = 200 * 1000;
4136 if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
4157 pthread_cond_broadcast(&ctx->
sq_full);
4162 (void) pthread_cond_wait(&ctx->
cond, &ctx->
mutex);
4168 (void) pthread_cond_destroy(&ctx->
cond);
4169 (void) pthread_cond_destroy(&ctx->
sq_empty);
4170 (void) pthread_cond_destroy(&ctx->
sq_full);
4172 #if !defined(NO_SSL)
4187 if (ctx->
config[i] != NULL)
4196 if (ssl_mutexes != NULL) {
4214 #if defined(_WIN32) && !defined(__SYMBIAN32__)
4215 (void) WSACleanup();
4220 const char **options) {
4222 const char *name, *value, *default_value;
4225 #if defined(_WIN32) && !defined(__SYMBIAN32__)
4227 WSAStartup(MAKEWORD(2,2), &data);
4232 ctx = (
struct mg_context *) calloc(1,
sizeof(*ctx));
4236 while (options && (name = *options++) != NULL) {
4238 cry(
fc(ctx),
"Invalid option: %s", name);
4241 }
else if ((value = *options++) == NULL) {
4242 cry(
fc(ctx),
"%s: option value cannot be NULL", name);
4253 if (ctx->
config[i] == NULL && default_value != NULL) {
4268 #
if !defined(_WIN32)
4276 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
4279 (void) signal(SIGPIPE, SIG_IGN);
4281 (void) signal(SIGCHLD, SIG_IGN);
4285 (void) pthread_cond_init(&ctx->
cond, NULL);
4286 (void) pthread_cond_init(&ctx->
sq_empty, NULL);
4287 (void) pthread_cond_init(&ctx->
sq_full, NULL);
4295 cry(
fc(ctx),
"Cannot start worker thread: %d",
ERRNO);
static struct mg_connection * fc(struct mg_context *ctx)
static char * skip(char **buf, const char *delimiters)
static const char * ssl_error(void)
static char * mg_strdup(const char *str)
#define SSL_CTX_use_PrivateKey_file
static int authorize(struct mg_connection *conn, FILE *fp)
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
static int parse_port_string(const struct vec *vec, struct socket *so)
struct mg_request_info request_info
void *(* mg_callback_t)(enum mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info)
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mgstat *stp)
char buf[CGI_ENVIRONMENT_SIZE]
static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
static void url_encode(const char *src, char *dst, size_t dst_len)
#define SSL_CTX_use_certificate_file
unsigned sleep(unsigned sec)
#define MAX_CGI_ENVIR_VARS
static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt,...)
static int match_extension(const char *path, const char *ext_list)
static void free_context(struct mg_context *ctx)
static int check_password(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response)
static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len)
static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
static int get_month_index(const char *s)
#define CGI_ENVIRONMENT_SIZE
struct mg_connection * conn
static int set_non_blocking_mode(SOCKET sock)
static int start_thread(struct mg_context *ctx, mg_thread_func_t func, void *param)
static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, va_list ap)
void *(* mg_thread_func_t)(void *)
#define ENTRIES_PER_CONFIG_OPTION
static void out(const wchar_t *fmt,...)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
static int should_keep_alive(const struct mg_connection *conn)
static int get_option_index(const char *name)
int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, char *dst, size_t dst_size)
static void print_props(struct mg_connection *conn, const char *uri, struct mgstat *st)
struct mg_request_info::mg_header http_headers[64]
struct MD5Context MD5_CTX
static void handle_propfind(struct mg_connection *conn, const char *path, struct mgstat *st)
static void handle_request(struct mg_connection *conn)
static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
static int set_uid_option(struct mg_context *ctx)
static FILE * open_auth_file(struct mg_connection *conn, const char *path)
static const char * config_options[]
static int check_authorization(struct mg_connection *conn, const char *path)
static void log_access(const struct mg_connection *conn)
static void add_to_set(SOCKET fd, fd_set *set, int *max_fd)
static void reset_per_request_attributes(struct mg_connection *conn)
#define PASSWORDS_FILE_NAME
static struct ssl_func crypto_sw[]
static const char * get_header(const struct mg_request_info *ri, const char *name)
static void send_options(struct mg_connection *conn)
struct ssl_ctx_st SSL_CTX
#define SSL_load_error_strings
void mg_md5(char *buf,...)
static struct ssl_func ssl_sw[]
static char * mg_strndup(const char *ptr, size_t len)
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
static unsigned long ssl_id_callback(void)
#define SSLv23_server_method
static int lowercase(const char *s)
static void remove_double_dots_and_double_slashes(char *s)
static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len)
static int get_document_root(const struct mg_connection *conn, struct vec *document_root)
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
static void uninitialize_ssl(struct mg_context *ctx)
#define SSL_CTX_set_default_passwd_cb
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
static int mg_strncasecmp(const char *s1, const char *s2, size_t len)
static int is_not_modified(const struct mg_connection *conn, const struct mgstat *stp)
unsigned long long uint64_t
static int set_acl_option(struct mg_context *ctx)
int pthread_create(pthread_t *thread_id, const void *attr, void *(*func)(void *), void *arg)
static struct mg_connection * mg_connect(struct mg_connection *conn, const char *host, int port, int use_ssl)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
#define CRYPTO_set_id_callback
static void handle_file_request(struct mg_connection *conn, const char *path, struct mgstat *stp)
static void * call_user(struct mg_connection *conn, enum mg_event event)
static void discard_current_request_from_buffer(struct mg_connection *conn)
static void cry(struct mg_connection *conn, const char *fmt,...)
static void close_all_listening_sockets(struct mg_context *ctx)
mg_callback_t user_callback
const char * mg_version(void)
static const char * suggest_connection_header(const struct mg_connection *conn)
void * dlopen(const char *so_name, int flags)
int read(int fd, void *buf, size_t nbytes)
static void close_socket_gracefully(SOCKET sock)
static void master_thread(struct mg_context *ctx)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
int pthread_mutex_lock(pthread_mutex_t *m)
int mg_get_var(const char *buf, size_t buf_len, const char *name, char *dst, size_t dst_len)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
static int mg_strcasecmp(const char *s1, const char *s2)
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
static char * addenv(struct cgi_env_block *block, const char *fmt,...)
void * dlsym(void *handle, const char *sym_name)
static void do_ssi_exec(struct mg_connection *conn, char *tag)
#define MD5STEP(f, w, x, y, z, data, s)
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
static void parse_http_headers(char **buf, struct mg_request_info *ri)
static int is_authorized_for_put(struct mg_connection *conn)
struct socket * listening_sockets
struct mg_connection * conn
int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *)
static void worker_thread(struct mg_context *ctx)
static const char * month_names[]
static void set_close_on_exec(int fd)
static int is_valid_http_method(const char *method)
char * vars[MAX_CGI_ENVIR_VARS]
static void send_authorization_request(struct mg_connection *conn)
static void byteReverse(unsigned char *buf, unsigned longs)
const char * mg_get_option(const struct mg_context *ctx, const char *name)
static int set_ports_option(struct mg_context *ctx)
static void handle_directory_request(struct mg_connection *conn, const char *dir)
static const char * http_500_error
const char * mg_get_header(const struct mg_connection *conn, const char *name)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
static void dir_scan_callback(struct de *de, void *data)
static void handle_proxy_request(struct mg_connection *conn)
static void MD5Init(MD5_CTX *ctx)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
const char ** mg_get_valid_option_names(void)
static void print_dav_dir_entry(struct de *de, void *data)
static void print_dir_entry(struct de *de)
static void put_file(struct mg_connection *conn, const char *path)
static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fd_stdin, int fd_stdout, const char *dir)
static size_t url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int is_form_url_encoded)
int pthread_mutex_unlock(pthread_mutex_t *m)
char * config[NUM_OPTIONS]
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void(*cb)(struct de *, void *))
static void process_new_connection(struct mg_connection *conn)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
static void convert_uri_to_file_name(struct mg_connection *conn, const char *uri, char *buf, size_t buf_len)
static int get_request_len(const char *buf, int buflen)
#define ARRAY_SIZE(array)
static int check_acl(struct mg_context *ctx, const struct usa *usa)
static void send_http_error(struct mg_connection *conn, int status, const char *reason, const char *fmt,...)
static void send_ssi_file(struct mg_connection *, const char *, FILE *, int)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
#define IS_DIRSEP_CHAR(c)
#define CRYPTO_set_locking_callback
static int load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
static void log_header(const struct mg_connection *conn, const char *header, FILE *fp)
static Handle handle(size_t idx, u64 tag)
static int put_dir(const char *path)
#define SSL_CTX_use_certificate_chain_file
static int set_gpass_option(struct mg_context *ctx)
void mg_send_file(struct mg_connection *conn, const char *path)
static time_t parse_date_string(const char *datetime)
int pthread_mutex_destroy(pthread_mutex_t *m)
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz, int *nread)
struct mg_context * mg_start(mg_callback_t user_callback, void *user_data, const char **options)
static int sslize(struct mg_connection *conn, int(*func)(SSL *))
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
struct mg_connection * peer
static int mg_stat(const char *path, struct mgstat *stp)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path)
static int consume_socket(struct mg_context *ctx, struct socket *sp)
static pthread_mutex_t * ssl_mutexes
static int parse_url(const char *url, char *host, int *port)
static struct @64 builtin_mime_types[]
static void MD5Final(unsigned char digest[16], MD5_CTX *ctx)
static void close_connection(struct mg_connection *conn)
static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_env_block *blk)
static int parse_http_request(char *buf, struct mg_request_info *ri)
struct ssl_method_st SSL_METHOD
void mg_stop(struct mg_context *ctx)
static int is_valid_uri(const char *uri)
static void bin2str(char *to, const unsigned char *p, size_t len)
static int set_ssl_option(struct mg_context *ctx)