22 #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
24 #define _XOPEN_SOURCE 600 // For flockfile() on Linux
25 #define _LARGEFILE_SOURCE // Enable 64-bit file offsets
26 #define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
29 #if defined(__SYMBIAN32__)
30 #define NO_SSL // SSL is not supported
31 #define NO_CGI // CGI is not supported
32 #define PATH_MAX FILENAME_MAX
33 #endif // __SYMBIAN32__
35 #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
36 #include <sys/types.h>
53 #if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
54 #define _WIN32_WINNT 0x0400 // To make it link in VS2005
58 #define PATH_MAX MAX_PATH
67 #define NO_CGI // WinCE has no pipes
72 #define errno GetLastError()
73 #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
76 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
77 ((uint64_t)((uint32_t)(hi))) << 32))
78 #define RATE_DIFF 10000000 // 100 nsecs
79 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
80 #define SYS2UNIX_TIME(lo, hi) \
81 (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
86 #if defined(_MSC_VER) && _MSC_VER < 1300
88 #define STR(x) STRX(x)
89 #define __func__ "line " STR(__LINE__)
90 #define strtoull(x, y, z) strtoul(x, y, z)
91 #define strtoll(x, y, z) strtol(x, y, z)
93 #define __func__ __FUNCTION__
94 #define strtoull(x, y, z) _strtoui64(x, y, z)
95 #define strtoll(x, y, z) _strtoi64(x, y, z)
98 #define ERRNO GetLastError()
100 #define SSL_LIB "ssleay32.dll"
101 #define CRYPTO_LIB "libeay32.dll"
103 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
105 #if !defined(EWOULDBLOCK)
106 #define EWOULDBLOCK WSAEWOULDBLOCK
107 #endif // !EWOULDBLOCK
109 #define INT64_FMT "I64d"
111 #define WINCDECL __cdecl
113 #define snprintf _snprintf
114 #define vsnprintf _vsnprintf
115 #define sleep(x) Sleep((x) * 1000)
117 #define pipe(x) _pipe(x, BUFSIZ, _O_BINARY)
118 #define popen(x, y) _popen(x, y)
119 #define pclose(x) _pclose(x)
120 #define close(x) _close(x)
121 #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
123 #define fseeko(x, y, z) fseek((x), (y), (z))
124 #define fdopen(x, y) _fdopen((x), (y))
125 #define write(x, y, z) _write((x), (y), (unsigned) z)
126 #define read(x, y, z) _read((x), (y), (unsigned) z)
127 #define flockfile(x) (void) 0
128 #define funlockfile(x) (void) 0
131 #define fileno(x) _fileno(x)
132 #endif // !fileno MINGW #defines fileno
135 typedef struct {
HANDLE signal, broadcast;} pthread_cond_t;
137 #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
146 static FILE *
mg_fopen(
const char *path,
const char *mode);
148 #if defined(HAVE_STDINT)
155 #define INT64_MAX 9223372036854775807
156 #endif // HAVE_STDINT
165 WIN32_FIND_DATAW info;
166 struct dirent result;
169 #else // UNIX specific
170 #include <sys/wait.h>
171 #include <sys/socket.h>
172 #include <sys/select.h>
173 #include <netinet/in.h>
174 #include <arpa/inet.h>
175 #include <sys/time.h>
177 #include <inttypes.h>
183 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
187 #if defined(__MACH__)
188 #define SSL_LIB "libssl.dylib"
189 #define CRYPTO_LIB "libcrypto.dylib"
191 #if !defined(SSL_LIB)
192 #define SSL_LIB "libssl.so"
194 #if !defined(CRYPTO_LIB)
195 #define CRYPTO_LIB "libcrypto.so"
199 #define IS_DIRSEP_CHAR(c) ((c) == '/')
203 #define closesocket(a) close(a)
204 #define mg_fopen(x, y) fopen(x, y)
205 #define mg_mkdir(x, y) mkdir(x, y)
206 #define mg_remove(x) remove(x)
207 #define mg_rename(x, y) rename(x, y)
209 #define INVALID_SOCKET (-1)
210 #define INT64_FMT PRId64
214 #endif // End of Windows and UNIX specific includes
218 #define MONGOOSE_VERSION "3.1"
219 #define PASSWORDS_FILE_NAME ".htpasswd"
220 #define CGI_ENVIRONMENT_SIZE 4096
221 #define MAX_CGI_ENVIR_VARS 64
222 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
226 return GetCurrentThreadId();
231 #define DEBUG_TRACE(x) do { \
233 printf("*** %lu.%p.%s.%d: ", \
234 (unsigned long) time(NULL), (void *) pthread_self(), \
235 __func__, __LINE__); \
239 funlockfile(stdout); \
242 #define DEBUG_TRACE(x)
247 typedef int socklen_t;
248 #endif // NO_SOCKLEN_T
250 typedef void * (*mg_thread_func_t)(
void *);
257 typedef struct ssl_st
SSL;
261 #define SSL_ERROR_WANT_READ 2
262 #define SSL_ERROR_WANT_WRITE 3
263 #define SSL_FILETYPE_PEM 1
264 #define CRYPTO_LOCK 1
266 #if defined(NO_SSL_DL)
296 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
297 #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
298 #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
299 #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
300 #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
301 #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
302 #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
303 #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
304 #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
305 #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
306 #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
307 #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
308 const char *, int)) ssl_sw[11].ptr)
309 #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
310 const char *, int)) ssl_sw[12].ptr)
311 #define SSL_CTX_set_default_passwd_cb \
312 (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
313 #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
314 #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
315 #define SSL_CTX_use_certificate_chain_file \
316 (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
318 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
319 #define CRYPTO_set_locking_callback \
320 (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
321 #define CRYPTO_set_id_callback \
322 (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
323 #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
324 #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
332 {
"SSL_accept", NULL},
333 {
"SSL_connect", NULL},
336 {
"SSL_get_error", NULL},
337 {
"SSL_set_fd", NULL},
339 {
"SSL_CTX_new", NULL},
340 {
"SSLv23_server_method", NULL},
341 {
"SSL_library_init", NULL},
342 {
"SSL_CTX_use_PrivateKey_file", NULL},
343 {
"SSL_CTX_use_certificate_file",NULL},
344 {
"SSL_CTX_set_default_passwd_cb",NULL},
345 {
"SSL_CTX_free", NULL},
346 {
"SSL_load_error_strings", NULL},
347 {
"SSL_CTX_use_certificate_chain_file", NULL},
353 {
"CRYPTO_num_locks", NULL},
354 {
"CRYPTO_set_locking_callback", NULL},
355 {
"CRYPTO_set_id_callback", NULL},
356 {
"ERR_get_error", NULL},
357 {
"ERR_error_string", NULL},
363 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
364 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
373 struct sockaddr_in
sin;
413 "C",
"cgi_extensions",
".cgi,.pl,.php",
414 "E",
"cgi_environment", NULL,
415 "G",
"put_delete_passwords_file", NULL,
416 "I",
"cgi_interpreter", NULL,
417 "P",
"protect_uri", NULL,
418 "R",
"authentication_domain",
"mydomain.com",
419 "S",
"ssi_extensions",
".shtml,.shtm",
420 "a",
"access_log_file", NULL,
421 "c",
"ssl_chain_file", NULL,
422 "d",
"enable_directory_listing",
"yes",
423 "e",
"error_log_file", NULL,
424 "g",
"global_passwords_file", NULL,
425 "i",
"index_files",
"index.html,index.htm,index.cgi",
426 "k",
"enable_keep_alive",
"no",
427 "l",
"access_control_list", NULL,
428 "M",
"max_request_size",
"16384",
429 "m",
"extra_mime_types", NULL,
430 "p",
"listening_ports",
"8080",
431 "r",
"document_root",
".",
432 "s",
"ssl_certificate", NULL,
433 "t",
"num_threads",
"10",
434 "u",
"run_as_user", NULL,
437 #define ENTRIES_PER_CONFIG_OPTION 3
489 if (strcmp(config_options[i], name) == 0 ||
490 strcmp(config_options[i + 1], name) == 0) {
501 }
else if (ctx->
config[i] == NULL) {
516 (void) vsnprintf(buf,
sizeof(buf), fmt, ap);
529 timestamp = time(NULL);
532 "[%010lu] [error] [client %s] ",
533 (
unsigned long) timestamp,
537 (void) fprintf(fp,
"%s %s: ",
542 (void) fprintf(fp,
"%s", buf);
564 fake_connection.
ctx =
ctx;
565 return &fake_connection;
572 static void mg_strlcpy(
register char *dst,
register const char *src,
size_t n) {
573 for (; *src !=
'\0' && n > 1; n--) {
580 return tolower(* (
const unsigned char *) s);
589 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
599 }
while (diff == 0 && s1[-1] !=
'\0');
607 if ((p = (
char *) malloc(len + 1)) != NULL) {
623 const char *fmt, va_list ap) {
629 n = vsnprintf(buf, buflen, fmt, ap);
632 cry(conn,
"vsnprintf error");
634 }
else if (n >= (
int) buflen) {
635 cry(conn,
"truncating vsnprintf buffer: [%.*s]",
636 n > 200 ? 200 : n, buf);
637 n = (int) buflen - 1;
645 const char *fmt, ...) {
660 static char *
skip_quoted(
char **
buf,
const char *delimiters,
const char *whitespace,
char quotechar) {
661 char *p, *begin_word, *end_word, *end_whitespace;
664 end_word = begin_word + strcspn(begin_word, delimiters);
667 if (end_word > begin_word) {
669 while (*p == quotechar) {
671 if (*end_word ==
'\0') {
675 size_t end_off = strcspn(end_word + 1, delimiters);
676 memmove (p, end_word, end_off + 1);
678 end_word += end_off + 1;
681 for (p++; p < end_word; p++) {
686 if (*end_word ==
'\0') {
689 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
691 for (p = end_word; p < end_whitespace; p++) {
695 *buf = end_whitespace;
703 static char *
skip(
char **
buf,
const char *delimiters) {
704 return skip_quoted(buf, delimiters, delimiters, 0);
731 struct vec *eq_val) {
732 if (list == NULL || *list ==
'\0') {
737 if ((list = strchr(val->
ptr,
',')) != NULL) {
739 val->
len = list - val->
ptr;
743 list = val->
ptr + strlen(val->
ptr);
744 val->
len = list - val->
ptr;
747 if (eq_val != NULL) {
751 eq_val->
ptr = (
const char *) memchr(val->
ptr,
'=', val->
len);
752 if (eq_val->
ptr != NULL) {
767 path_len = strlen(path);
769 while ((ext_list =
next_option(ext_list, &ext_vec, NULL)) != NULL)
770 if (ext_vec.
len < path_len &&
772 ext_vec.
ptr, ext_vec.
len) == 0)
784 return (header == NULL && http_version && !strcmp(http_version,
"1.1")) ||
793 const char *reason,
const char *fmt, ...) {
805 if (status > 199 && status != 204 && status != 304) {
806 len =
mg_snprintf(conn, buf,
sizeof(buf),
"Error %d: %s", status, reason);
807 cry(conn,
"%s", buf);
811 len +=
mg_vsnprintf(conn, buf + len,
sizeof(buf) - len, fmt, ap);
817 "Content-Type: text/plain\r\n"
818 "Content-Length: %d\r\n"
819 "Connection: %s\r\n\r\n", status, reason, len,
825 #if defined(_WIN32) && !defined(__SYMBIAN32__)
828 *mutex = CreateMutex(NULL, FALSE, NULL);
829 return *mutex == NULL ? -1 : 0;
833 return CloseHandle(*mutex) == 0 ? -1 : 0;
837 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
841 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
844 static int pthread_cond_init(pthread_cond_t *cv,
const void *unused) {
846 cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
847 cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
848 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
851 static int pthread_cond_wait(pthread_cond_t *cv,
pthread_mutex_t *mutex) {
852 HANDLE handles[] = {cv->signal, cv->broadcast};
853 ReleaseMutex(*mutex);
854 WaitForMultipleObjects(2, handles, FALSE, INFINITE);
855 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
858 static int pthread_cond_signal(pthread_cond_t *cv) {
859 return SetEvent(cv->signal) == 0 ? -1 : 0;
862 static int pthread_cond_broadcast(pthread_cond_t *cv) {
865 return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
868 static int pthread_cond_destroy(pthread_cond_t *cv) {
869 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
873 static void change_slashes_to_backslashes(
char *path) {
876 for (i = 0; path[i] !=
'\0'; i++) {
880 if (path[i] ==
'\\' && i > 0)
881 while (path[i + 1] ==
'\\' || path[i + 1] ==
'/')
882 (void) memmove(path + i + 1,
883 path + i + 2, strlen(path + i + 1));
889 static void to_unicode(
const char *path,
wchar_t *wbuf,
size_t wbuf_len) {
893 change_slashes_to_backslashes(buf);
896 p = buf + strlen(buf) - 1;
899 while (p > buf && *p ==
'\\' && p[-1] !=
':') {
908 (*p == 0x2e && p > buf) ||
911 (void) fprintf(stderr,
"Rejecting suspicious path: [%s]", buf);
916 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int) wbuf_len);
917 WideCharToMultiByte(CP_UTF8, 0, wbuf, (
int) wbuf_len, buf2,
sizeof(buf2),
919 if (strcmp(buf, buf2) != 0) {
925 #if defined(_WIN32_WCE)
926 static time_t time(time_t *ptime) {
932 SystemTimeToFileTime(&st, &ft);
933 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
942 static struct tm *localtime(
const time_t *ptime,
struct tm *ptm) {
946 TIME_ZONE_INFORMATION tzinfo;
953 FileTimeToLocalFileTime(&ft, &lft);
954 FileTimeToSystemTime(&lft, &st);
955 ptm->tm_year = st.wYear - 1900;
956 ptm->tm_mon = st.wMonth - 1;
957 ptm->tm_wday = st.wDayOfWeek;
958 ptm->tm_mday = st.wDay;
959 ptm->tm_hour = st.wHour;
960 ptm->tm_min = st.wMinute;
961 ptm->tm_sec = st.wSecond;
964 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
969 static struct tm *gmtime(
const time_t *ptime,
struct tm *ptm) {
971 return localtime(ptime, ptm);
974 static size_t strftime(
char *dst,
size_t dst_size,
const char *fmt,
975 const struct tm *tm) {
976 (void) snprintf(dst, dst_size,
"implement strftime() for WinCE");
981 static int mg_rename(
const char* oldname,
const char* newname) {
985 to_unicode(oldname, woldbuf,
ARRAY_SIZE(woldbuf));
986 to_unicode(newname, wnewbuf,
ARRAY_SIZE(wnewbuf));
988 return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
992 static FILE *
mg_fopen(
const char *path,
const char *mode) {
996 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode,
ARRAY_SIZE(wmode));
998 return _wfopen(wbuf, wmode);
1004 WIN32_FILE_ATTRIBUTE_DATA info;
1008 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
1009 stp->
size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
1010 stp->
mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
1011 info.ftLastWriteTime.dwHighDateTime);
1013 info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1020 static int mg_remove(
const char *path) {
1023 return DeleteFileW(wbuf) ? 0 : -1;
1026 static int mg_mkdir(
const char *path,
int mode) {
1032 change_slashes_to_backslashes(buf);
1034 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf,
sizeof(wbuf));
1036 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1040 static DIR * opendir(
const char *name) {
1046 SetLastError(ERROR_BAD_ARGUMENTS);
1047 }
else if ((dir = (DIR *) malloc(
sizeof(*dir))) == NULL) {
1048 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1051 attrs = GetFileAttributesW(wpath);
1052 if (attrs != 0xFFFFFFFF &&
1053 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1054 (void) wcscat(wpath, L
"\\*");
1055 dir->handle = FindFirstFileW(wpath, &dir->info);
1056 dir->result.d_name[0] =
'\0';
1066 static int closedir(DIR *dir) {
1070 if (dir->handle != INVALID_HANDLE_VALUE)
1071 result = FindClose(dir->handle) ? 0 : -1;
1076 SetLastError(ERROR_BAD_ARGUMENTS);
1082 struct dirent * readdir(DIR *dir) {
1083 struct dirent *result = 0;
1086 if (dir->handle != INVALID_HANDLE_VALUE) {
1087 result = &dir->result;
1088 (void) WideCharToMultiByte(CP_UTF8, 0,
1089 dir->info.cFileName, -1, result->d_name,
1090 sizeof(result->d_name), NULL, NULL);
1092 if (!FindNextFileW(dir->handle, &dir->info)) {
1093 (void) FindClose(dir->handle);
1094 dir->handle = INVALID_HANDLE_VALUE;
1098 SetLastError(ERROR_FILE_NOT_FOUND);
1101 SetLastError(ERROR_BAD_ARGUMENTS);
1107 #define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
1110 return _beginthread((
void (__cdecl *)(
void *)) f, 0, p) == -1L ? -1 : 0;
1113 static HANDLE dlopen(
const char *dll_name,
int flags) {
1116 to_unicode(dll_name, wbuf,
ARRAY_SIZE(wbuf));
1117 return LoadLibraryW(wbuf);
1120 #if !defined(NO_CGI)
1122 static int kill(pid_t pid,
int sig_num) {
1123 (void) TerminateProcess(pid, sig_num);
1124 (void) CloseHandle(pid);
1129 char *envblk,
char *envp[],
int fd_stdin,
1130 int fd_stdout,
const char *dir) {
1135 PROCESS_INFORMATION pi;
1139 (void) memset(&si, 0,
sizeof(si));
1140 (void) memset(&pi, 0,
sizeof(pi));
1144 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1145 si.wShowWindow = SW_HIDE;
1147 me = GetCurrentProcess();
1148 (void) DuplicateHandle(me, (
HANDLE) _get_osfhandle(fd_stdin), me,
1149 &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1150 (void) DuplicateHandle(me, (
HANDLE) _get_osfhandle(fd_stdout), me,
1151 &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1155 if (interp == NULL) {
1158 if ((fp = fopen(cmdline,
"r")) != NULL) {
1159 (void) fgets(buf,
sizeof(buf), fp);
1160 if (buf[0] !=
'#' || buf[1] !=
'!') {
1165 for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
1174 (void)
mg_snprintf(conn, cmdline,
sizeof(cmdline),
"%s%s%s%c%s",
1175 interp, interp[0] ==
'\0' ?
"" :
" ", dir,
DIRSEP, prog);
1178 if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
1179 CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
1180 cry(conn,
"%s: CreateProcess(%s): %d",
1182 pi.hProcess = (pid_t) -1;
1184 (void) close(fd_stdin);
1185 (void) close(fd_stdout);
1188 (void) CloseHandle(si.hStdOutput);
1189 (void) CloseHandle(si.hStdInput);
1190 (void) CloseHandle(pi.hThread);
1192 return (pid_t) pi.hProcess;
1197 unsigned long on = 1;
1198 return ioctlsocket(sock, FIONBIO, &on);
1206 if (stat(path, &st) == 0) {
1208 stp->
size = st.st_size;
1209 stp->
mtime = st.st_mtime;
1219 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1225 pthread_attr_t attr;
1228 (void) pthread_attr_init(&attr);
1229 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1233 if ((retval =
pthread_create(&thread_id, &attr, func, param)) != 0) {
1242 char *envblk,
char *envp[],
int fd_stdin,
1243 int fd_stdout,
const char *dir) {
1249 if ((pid = fork()) == -1) {
1252 }
else if (pid == 0) {
1254 if (chdir(dir) != 0) {
1256 }
else if (dup2(fd_stdin, 0) == -1) {
1258 }
else if (dup2(fd_stdout, 1) == -1) {
1261 (void) dup2(fd_stdout, 2);
1262 (void) close(fd_stdin);
1263 (void) close(fd_stdout);
1267 if (interp == NULL) {
1268 (void) execle(prog, prog, NULL, envp);
1271 (void) execle(interp, interp, prog, NULL, envp);
1272 cry(conn,
"%s: execle(%s %s): %s",
__func__, interp, prog,
1279 (void) close(fd_stdin);
1280 (void) close(fd_stdout);
1290 flags = fcntl(sock, F_GETFL, 0);
1291 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1305 while (sent < len) {
1308 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
1312 }
else if (fp != NULL) {
1313 n = fwrite(buf + sent, 1, (
size_t)k, fp);
1317 n = send(sock, buf + sent, (
size_t)k, 0);
1336 }
else if (fp != NULL) {
1340 nread =
read(fileno(fp), buf, (
size_t) len);
1344 nread = recv(sock, buf, (
size_t) len, 0);
1351 int n, buffered_len, nread;
1352 const char *buffered;
1363 if (to_read < (
int64_t) len) {
1364 len = (int) to_read;
1370 assert(buffered_len >= 0);
1375 if (len < (
size_t) buffered_len) {
1378 memcpy(buf, buffered, (
size_t)buffered_len);
1379 len -= buffered_len;
1380 buf = (
char *) buf + buffered_len;
1382 nread = buffered_len;
1391 buf = (
char *) buf + n;
1402 (
const char *) buf, (
int64_t) len);
1414 return mg_write(conn, buf, (
size_t)len);
1422 static size_t url_decode(
const char *src,
size_t src_len,
char *dst,
1423 size_t dst_len,
int is_form_url_encoded) {
1426 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
1428 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
1429 if (src[i] ==
'%' &&
1430 isxdigit(* (
const unsigned char *) (src + i + 1)) &&
1431 isxdigit(* (
const unsigned char *) (src + i + 2))) {
1432 a = tolower(* (
const unsigned char *) (src + i + 1));
1433 b = tolower(* (
const unsigned char *) (src + i + 2));
1436 }
else if (is_form_url_encoded && src[i] ==
'+') {
1452 int mg_get_var(
const char *buf,
size_t buf_len,
const char *name,
1453 char *dst,
size_t dst_len) {
1454 const char *p, *e, *s;
1455 size_t name_len, len;
1457 name_len = strlen(name);
1463 for (p = buf; p != NULL && p + name_len < e; p++) {
1464 if ((p == buf || p[-1] ==
'&') && p[name_len] ==
'=' &&
1471 s = (
const char *) memchr(p,
'&', (
size_t)(e - p));
1478 if ((
size_t) (s - p) < dst_len) {
1479 len =
url_decode(p, (
size_t)(s - p), dst, dst_len, 1);
1489 char *dst,
size_t dst_size) {
1490 const char *s, *p, *end;
1491 int name_len, len = -1;
1498 name_len = strlen(cookie_name);
1499 end = s + strlen(s);
1501 for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
1502 if (s[name_len] ==
'=') {
1504 if ((p = strchr(s,
' ')) == NULL)
1508 if (*s ==
'"' && p[-1] ==
'"' && p > s + 1) {
1512 if ((
size_t) (p - s) < dst_size) {
1526 struct vec *document_root) {
1527 const char *root, *uri;
1528 int len_of_matched_uri;
1529 struct vec uri_vec, path_vec;
1532 len_of_matched_uri = 0;
1535 while ((root =
next_option(root, &uri_vec, &path_vec)) != NULL) {
1536 if (memcmp(uri, uri_vec.
ptr, uri_vec.
len) == 0) {
1537 *document_root = path_vec;
1538 len_of_matched_uri = uri_vec.
len;
1543 return len_of_matched_uri;
1547 const char *uri,
char *buf,
1555 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1556 change_slashes_to_backslashes(buf);
1565 func(conn->
ssl) == 1;
1569 const char *host,
int port,
int use_ssl) {
1571 struct sockaddr_in sin;
1576 cry(conn,
"%s: SSL is not initialized",
__func__);
1577 }
else if ((he = gethostbyname(host)) == NULL) {
1582 sin.sin_family = AF_INET;
1583 sin.sin_port = htons((
uint16_t) port);
1584 sin.sin_addr = * (
struct in_addr *) he->h_addr_list[0];
1585 if (connect(sock, (
struct sockaddr *) &sin,
sizeof(sin)) != 0) {
1586 cry(conn,
"%s: connect(%s:%d): %s",
__func__, host, port,
1590 calloc(1,
sizeof(*newconn))) == NULL) {
1614 for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
1616 if (!isprint(* (
const unsigned char *) s) && *s !=
'\r' &&
1617 *s !=
'\n' && * (
const unsigned char *) s < 128) {
1619 }
else if (s[0] ==
'\n' && s[1] ==
'\n') {
1620 len = (int) (s - buf) + 2;
1621 }
else if (s[0] ==
'\n' && &s[1] < e &&
1622 s[1] ==
'\r' && s[2] ==
'\n') {
1623 len = (int) (s - buf) + 3;
1633 for (i = 0; i <
ARRAY_SIZE(month_names); i++)
1634 if (!strcmp(s, month_names[i]))
1642 static const unsigned short days_before_month[] = {
1643 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
1646 int second, minute, hour, day, month, year, leap_days, days;
1647 time_t result = (time_t) 0;
1649 if (((sscanf(datetime,
"%d/%3s/%d %d:%d:%d",
1650 &day, month_str, &year, &hour, &minute, &second) == 6) ||
1651 (sscanf(datetime,
"%d %3s %d %d:%d:%d",
1652 &day, month_str, &year, &hour, &minute, &second) == 6) ||
1653 (sscanf(datetime,
"%*3s, %d %3s %d %d:%d:%d",
1654 &day, month_str, &year, &hour, &minute, &second) == 6) ||
1655 (sscanf(datetime,
"%d-%3s-%d %d:%d:%d",
1656 &day, month_str, &year, &hour, &minute, &second) == 6)) &&
1660 leap_days = year / 4 - year / 100 + year / 400;
1661 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
1662 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
1673 while (*s !=
'\0') {
1675 if (s[-1] ==
'/' || s[-1] ==
'\\') {
1677 while (*s ==
'/' || *s ==
'\\') {
1682 while (*s ==
'.' && s[1] ==
'.') {
1690 static const struct {
1696 {
".html", 5,
"text/html", 9},
1697 {
".htm", 4,
"text/html", 9},
1698 {
".shtm", 5,
"text/html", 9},
1699 {
".shtml", 6,
"text/html", 9},
1700 {
".css", 4,
"text/css", 8},
1701 {
".js", 3,
"application/x-javascript", 24},
1702 {
".ico", 4,
"image/x-icon", 12},
1703 {
".gif", 4,
"image/gif", 9},
1704 {
".jpg", 4,
"image/jpeg", 10},
1705 {
".jpeg", 5,
"image/jpeg", 10},
1706 {
".png", 4,
"image/png", 9},
1707 {
".svg", 4,
"image/svg+xml", 13},
1708 {
".torrent", 8,
"application/x-bittorrent", 24},
1709 {
".wav", 4,
"audio/x-wav", 11},
1710 {
".mp3", 4,
"audio/x-mp3", 11},
1711 {
".mid", 4,
"audio/mid", 9},
1712 {
".m3u", 4,
"audio/x-mpegurl", 15},
1713 {
".ram", 4,
"audio/x-pn-realaudio", 20},
1714 {
".xml", 4,
"text/xml", 8},
1715 {
".xslt", 5,
"application/xml", 15},
1716 {
".ra", 3,
"audio/x-pn-realaudio", 20},
1717 {
".doc", 4,
"application/msword", 19},
1718 {
".exe", 4,
"application/octet-stream", 24},
1719 {
".zip", 4,
"application/x-zip-compressed", 28},
1720 {
".xls", 4,
"application/excel", 17},
1721 {
".tgz", 4,
"application/x-tar-gz", 20},
1722 {
".tar", 4,
"application/x-tar", 17},
1723 {
".gz", 3,
"application/x-gunzip", 20},
1724 {
".arj", 4,
"application/x-arj-compressed", 28},
1725 {
".rar", 4,
"application/x-arj-compressed", 28},
1726 {
".rtf", 4,
"application/rtf", 15},
1727 {
".pdf", 4,
"application/pdf", 15},
1728 {
".swf", 4,
"application/x-shockwave-flash",29},
1729 {
".mpg", 4,
"video/mpeg", 10},
1730 {
".mpeg", 5,
"video/mpeg", 10},
1731 {
".mp4", 4,
"video/mp4", 9},
1732 {
".m4v", 4,
"video/x-m4v", 11},
1733 {
".asf", 4,
"video/x-ms-asf", 14},
1734 {
".avi", 4,
"video/x-msvideo", 15},
1735 {
".bmp", 4,
"image/bmp", 9},
1743 struct vec ext_vec, mime_vec;
1744 const char *list, *ext;
1747 path_len = strlen(path);
1752 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
1754 ext = path + path_len - ext_vec.
len;
1773 vec->
ptr =
"text/plain";
1781 unsigned char in[64];
1784 #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
1785 #define byteReverse(buf, len) // Do nothing
1790 t = (
uint32_t) ((
unsigned) buf[3] << 8 | buf[2]) << 16 |
1791 ((
unsigned) buf[1] << 8 | buf[0]);
1798 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1799 #define F2(x, y, z) F1(z, x, y)
1800 #define F3(x, y, z) (x ^ y ^ z)
1801 #define F4(x, y, z) (y ^ (x | ~z))
1803 #define MD5STEP(f, w, x, y, z, data, s) \
1804 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
1809 ctx->
buf[0] = 0x67452301;
1810 ctx->
buf[1] = 0xefcdab89;
1811 ctx->
buf[2] = 0x98badcfe;
1812 ctx->
buf[3] = 0x10325476;
1826 MD5STEP(
F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1827 MD5STEP(
F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1828 MD5STEP(
F1, c, d, a, b, in[2] + 0x242070db, 17);
1829 MD5STEP(
F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1830 MD5STEP(
F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1831 MD5STEP(
F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1832 MD5STEP(
F1, c, d, a, b, in[6] + 0xa8304613, 17);
1833 MD5STEP(
F1, b, c, d, a, in[7] + 0xfd469501, 22);
1834 MD5STEP(
F1, a, b, c, d, in[8] + 0x698098d8, 7);
1835 MD5STEP(
F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1836 MD5STEP(
F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1837 MD5STEP(
F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1838 MD5STEP(
F1, a, b, c, d, in[12] + 0x6b901122, 7);
1839 MD5STEP(
F1, d, a, b, c, in[13] + 0xfd987193, 12);
1840 MD5STEP(
F1, c, d, a, b, in[14] + 0xa679438e, 17);
1841 MD5STEP(
F1, b, c, d, a, in[15] + 0x49b40821, 22);
1843 MD5STEP(
F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1844 MD5STEP(
F2, d, a, b, c, in[6] + 0xc040b340, 9);
1845 MD5STEP(
F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1846 MD5STEP(
F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1847 MD5STEP(
F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1848 MD5STEP(
F2, d, a, b, c, in[10] + 0x02441453, 9);
1849 MD5STEP(
F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1850 MD5STEP(
F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1851 MD5STEP(
F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1852 MD5STEP(
F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1853 MD5STEP(
F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1854 MD5STEP(
F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1855 MD5STEP(
F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1856 MD5STEP(
F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1857 MD5STEP(
F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1858 MD5STEP(
F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1860 MD5STEP(
F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1861 MD5STEP(
F3, d, a, b, c, in[8] + 0x8771f681, 11);
1862 MD5STEP(
F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1863 MD5STEP(
F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1864 MD5STEP(
F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1865 MD5STEP(
F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1866 MD5STEP(
F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1867 MD5STEP(
F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1868 MD5STEP(
F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1869 MD5STEP(
F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1870 MD5STEP(
F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1871 MD5STEP(
F3, b, c, d, a, in[6] + 0x04881d05, 23);
1872 MD5STEP(
F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1873 MD5STEP(
F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1874 MD5STEP(
F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1875 MD5STEP(
F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1877 MD5STEP(
F4, a, b, c, d, in[0] + 0xf4292244, 6);
1878 MD5STEP(
F4, d, a, b, c, in[7] + 0x432aff97, 10);
1879 MD5STEP(
F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1880 MD5STEP(
F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1881 MD5STEP(
F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1882 MD5STEP(
F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1883 MD5STEP(
F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1884 MD5STEP(
F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1885 MD5STEP(
F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1886 MD5STEP(
F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1887 MD5STEP(
F4, c, d, a, b, in[6] + 0xa3014314, 15);
1888 MD5STEP(
F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1889 MD5STEP(
F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1890 MD5STEP(
F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1891 MD5STEP(
F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1892 MD5STEP(
F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1906 ctx->
bits[1] += len >> 29;
1908 t = (t >> 3) & 0x3f;
1911 unsigned char *p = (
unsigned char *) ctx->
in + t;
1915 memcpy(p, buf, len);
1926 memcpy(ctx->
in, buf, 64);
1933 memcpy(ctx->
in, buf, len);
1940 count = (ctx->
bits[0] >> 3) & 0x3F;
1942 p = ctx->
in + count;
1944 count = 64 - 1 - count;
1946 memset(p, 0, count);
1949 memset(ctx->
in, 0, 56);
1951 memset(p, 0, count - 8);
1960 memcpy(digest, ctx->
buf, 16);
1961 memset((
char *) ctx, 0,
sizeof(*ctx));
1967 static void bin2str(
char *to,
const unsigned char *p,
size_t len) {
1968 static const char *hex =
"0123456789abcdef";
1970 for (; len--; p++) {
1971 *to++ = hex[p[0] >> 4];
1972 *to++ = hex[p[0] & 0x0f];
1979 unsigned char hash[16];
1987 while ((p = va_arg(ap,
const char *)) != NULL) {
1988 MD5Update(&ctx, (
const unsigned char *) p, (
unsigned) strlen(p));
1993 bin2str(buf, hash,
sizeof(hash));
1998 const char *nonce,
const char *nc,
const char *cnonce,
1999 const char *qop,
const char *response) {
2000 char ha2[32 + 1], expected_response[32 + 1];
2003 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
2004 qop == NULL || response == NULL) {
2011 strlen(response) != 32
2017 mg_md5(ha2, method,
":", uri, NULL);
2018 mg_md5(expected_response, ha1,
":", nonce,
":", nc,
2019 ":", cnonce,
":", qop,
":", ha2, NULL);
2037 cry(
fc(ctx),
"fopen(%s): %s",
2040 (void)
mg_snprintf(conn, name,
sizeof(name),
"%s%c%s",
2045 for (p = path, e = p + strlen(p) - 1; e > p; e--)
2048 (void)
mg_snprintf(conn, name,
sizeof(name),
"%.*s%c%s",
2062 size_t buf_size,
struct ah *
ah) {
2063 char *name, *value, *s;
2064 const char *auth_header;
2066 if ((auth_header =
mg_get_header(conn,
"Authorization")) == NULL ||
2072 (void)
mg_strlcpy(buf, auth_header + 7, buf_size);
2075 (void) memset(ah, 0,
sizeof(*ah));
2080 while (isspace(* (
unsigned char *) s)) {
2094 if (*name ==
'\0') {
2098 if (!strcmp(name,
"username")) {
2100 }
else if (!strcmp(name,
"cnonce")) {
2102 }
else if (!strcmp(name,
"response")) {
2104 }
else if (!strcmp(name,
"uri")) {
2106 }
else if (!strcmp(name,
"qop")) {
2108 }
else if (!strcmp(name,
"nc")) {
2110 }
else if (!strcmp(name,
"nonce")) {
2116 if (ah->
user != NULL) {
2128 char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ];
2135 while (fgets(line,
sizeof(line), fp) != NULL) {
2136 if (sscanf(line,
"%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
2140 if (!strcmp(ah.
user, f_user) &&
2155 struct vec uri_vec, filename_vec;
2163 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
2165 (void)
mg_snprintf(conn, fname,
sizeof(fname),
"%.*s",
2166 filename_vec.
len, filename_vec.
ptr);
2167 if ((fp =
mg_fopen(fname,
"r")) == NULL) {
2168 cry(conn,
"%s: cannot open %s: %s",
__func__, fname, strerror(errno));
2189 "HTTP/1.1 401 Unauthorized\r\n"
2190 "Content-Length: 0\r\n"
2191 "WWW-Authenticate: Digest qop=\"auth\", "
2192 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
2194 (
unsigned long) time(NULL));
2213 const char *user,
const char *pass) {
2215 char line[512], u[512], d[512], ha1[33], tmp[
PATH_MAX];
2222 if (pass != NULL && pass[0] ==
'\0') {
2226 (void) snprintf(tmp,
sizeof(tmp),
"%s.tmp", fname);
2229 if ((fp =
mg_fopen(fname,
"a+")) != NULL) {
2234 if ((fp =
mg_fopen(fname,
"r")) == NULL) {
2236 }
else if ((fp2 =
mg_fopen(tmp,
"w+")) == NULL) {
2242 while (fgets(line,
sizeof(line), fp) != NULL) {
2243 if (sscanf(line,
"%[^:]:%[^:]:%*s", u, d) != 2) {
2247 if (!strcmp(u, user) && !strcmp(d, domain)) {
2250 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
2251 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
2254 (void) fprintf(fp2,
"%s", line);
2259 if (!found && pass != NULL) {
2260 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
2261 (void) fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
2281 static void url_encode(
const char *src,
char *dst,
size_t dst_len) {
2282 static const char *dont_escape =
"._-$,;~()";
2283 static const char *hex =
"0123456789abcdef";
2284 const char *end = dst + dst_len - 1;
2286 for (; *src !=
'\0' && dst < end; src++, dst++) {
2287 if (isalnum(*(
const unsigned char *) src) ||
2288 strchr(dont_escape, * (
const unsigned char *) src) != NULL) {
2290 }
else if (dst + 2 < end) {
2292 dst[1] = hex[(* (
const unsigned char *) src) >> 4];
2293 dst[2] = hex[(* (
const unsigned char *) src) & 0xf];
2305 (void)
mg_snprintf(de->
conn, size,
sizeof(size),
"%s",
"[DIRECTORY]");
2309 if (de->
st.
size < 1024) {
2311 "%lu", (
unsigned long) de->
st.
size);
2312 }
else if (de->
st.
size < 1024 * 1024) {
2314 "%.1fk", (double) de->
st.
size / 1024.0);
2315 }
else if (de->
st.
size < 1024 * 1024 * 1024) {
2317 "%.1fM", (double) de->
st.
size / 1048576);
2320 "%.1fG", (double) de->
st.
size / 1073741824);
2323 (void) strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", localtime(&de->
st.
mtime));
2326 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
2327 "<td> %s</td><td> %s</td></tr>\n",
2337 const struct de *a = (
const struct de *) p1, *b = (
const struct de *) p2;
2341 if (query_string == NULL) {
2342 query_string =
"na";
2349 }
else if (*query_string ==
'n') {
2350 cmp_result = strcmp(a->
file_name, b->file_name);
2351 }
else if (*query_string ==
's') {
2352 cmp_result = a->
st.
size == b->st.size ? 0 :
2353 a->
st.
size > b->st.size ? 1 : -1;
2354 }
else if (*query_string ==
'd') {
2355 cmp_result = a->
st.
mtime == b->st.mtime ? 0 :
2356 a->
st.
mtime > b->st.mtime ? 1 : -1;
2359 return query_string[1] ==
'd' ? -cmp_result : cmp_result;
2363 void *data,
void (*cb)(
struct de *,
void *)) {
2369 if ((dirp = opendir(dir)) == NULL) {
2374 while ((dp = readdir(dirp)) != NULL) {
2376 if (!strcmp(dp->d_name,
".") ||
2377 !strcmp(dp->d_name,
"..") ||
2381 mg_snprintf(conn, path,
sizeof(path),
"%s%c%s", dir, DIRSEP, dp->d_name);
2389 memset(&de.
st, 0,
sizeof(de.
st));
2395 (void) closedir(dirp);
2427 int i, sort_direction;
2432 "Error: opendir(%s): %s", dir, strerror(
ERRNO));
2440 "HTTP/1.1 200 OK\r\n"
2441 "Connection: close\r\n"
2442 "Content-Type: text/html; charset=utf-8\r\n\r\n");
2445 "<html><head><title>Index of %s</title>"
2446 "<style>th {text-align: left;}</style></head>"
2447 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
2448 "<tr><th><a href=\"?n%c\">Name</a></th>"
2449 "<th><a href=\"?d%c\">Modified</a></th>"
2450 "<th><a href=\"?s%c\">Size</a></th></tr>"
2451 "<tr><td colspan=\"3\"><hr></td></tr>",
2453 sort_direction, sort_direction, sort_direction);
2457 "<tr><td><a href=\"%s%s\">%s</a></td>"
2458 "<td> %s</td><td> %s</td></tr>\n",
2477 int to_read, num_read, num_written;
2481 to_read =
sizeof(buf);
2483 to_read = (
int) len;
2486 if ((num_read = fread(buf, 1, (
size_t)to_read, fp)) == 0)
2490 if ((num_written =
mg_write(conn, buf, (
size_t)num_read)) != num_read)
2504 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
2509 char date[64], lm[64], etag[64], range[64];
2510 const char *msg =
"OK", *hdr;
2511 time_t curtime = time(NULL);
2513 struct vec mime_vec;
2522 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
2524 "fopen(%s): %s", path, strerror(
ERRNO));
2534 (void) fseeko(fp, (
off_t) r1, SEEK_SET);
2535 cl = n == 2 ? r2 - r1 + 1: cl - r1;
2537 "Content-Range: bytes "
2540 r1, r1 + cl - 1, stp->
size);
2541 msg =
"Partial Content";
2548 (void)
mg_snprintf(conn, etag,
sizeof(etag),
"%lx.%lx",
2549 (
unsigned long) stp->
mtime, (
unsigned long) stp->
size);
2552 "HTTP/1.1 %d %s\r\n"
2554 "Last-Modified: %s\r\n"
2556 "Content-Type: %.*s\r\n"
2558 "Connection: %s\r\n"
2559 "Accept-Ranges: bytes\r\n"
2572 if (
mg_stat(path, &st) == 0) {
2595 return !strcmp(method,
"GET") || !strcmp(method,
"POST") ||
2596 !strcmp(method,
"HEAD") || !strcmp(method,
"CONNECT") ||
2597 !strcmp(method,
"PUT") || !strcmp(method,
"DELETE") ||
2598 !strcmp(method,
"OPTIONS") || !strcmp(method,
"PROPFIND");
2606 while (*buf !=
'\0' && isspace(* (
unsigned char *) buf)) {
2634 while (*nread < bufsiz && request_len == 0) {
2635 n =
pull(fp, sock, ssl, buf + *nread, bufsiz - *nread);
2651 size_t path_len,
struct mgstat *stp) {
2654 struct vec filename_vec;
2655 size_t n = strlen(path);
2668 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
2671 if (filename_vec.
len > path_len - n)
2678 if (
mg_stat(path, &st) == 0) {
2696 const struct mgstat *stp) {
2703 const char *expect, *buffered;
2705 int to_read, nread, buffered_len, success = 0;
2712 }
else if (expect != NULL &&
mg_strcasecmp(expect,
"100-continue")) {
2715 if (expect != NULL) {
2716 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
2721 assert(buffered_len >= 0);
2724 if (buffered_len > 0) {
2728 push(fp, sock, ssl, buffered, (
int64_t) buffered_len);
2733 to_read =
sizeof(buf);
2738 if (nread <= 0 ||
push(fp, sock, ssl, buf, nread) != nread) {
2757 #if !defined(NO_CGI)
2782 space =
sizeof(block->
buf) - block->
len - 2;
2786 added = block->
buf + block->
len;
2794 if (n > 0 && n < space &&
2799 block->
len += n + 1;
2808 const char *s, *slash;
2809 struct vec var_vec, root;
2823 addenv(blk,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
2824 addenv(blk,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
2825 addenv(blk,
"%s",
"REDIRECT_STATUS=200");
2828 addenv(blk,
"REMOTE_ADDR=%s",
2836 if ((s = strrchr(prog,
'/')) == NULL)
2841 addenv(blk,
"SCRIPT_FILENAME=%s", prog);
2842 addenv(blk,
"PATH_TRANSLATED=%s", prog);
2843 addenv(blk,
"HTTPS=%s", conn->
ssl == NULL ?
"off" :
"on");
2846 addenv(blk,
"CONTENT_TYPE=%s", s);
2852 addenv(blk,
"CONTENT_LENGTH=%s", s);
2854 if ((s = getenv(
"PATH")) != NULL)
2855 addenv(blk,
"PATH=%s", s);
2858 if ((s = getenv(
"COMSPEC")) != NULL)
2859 addenv(blk,
"COMSPEC=%s", s);
2860 if ((s = getenv(
"SYSTEMROOT")) != NULL)
2861 addenv(blk,
"SYSTEMROOT=%s", s);
2863 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL)
2864 addenv(blk,
"LD_LIBRARY_PATH=%s", s);
2867 if ((s = getenv(
"PERLLIB")) != NULL)
2868 addenv(blk,
"PERLLIB=%s", s);
2872 addenv(blk,
"%s",
"AUTH_TYPE=Digest");
2877 p =
addenv(blk,
"HTTP_%s=%s",
2882 for (; *p !=
'=' && *p !=
'\0'; p++) {
2885 *p = (char) toupper(* (
unsigned char *) p);
2891 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
2896 blk->
buf[blk->
len++] =
'\0';
2899 assert(blk->
len > 0);
2900 assert(blk->
len < (
int)
sizeof(blk->
buf));
2904 int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
2906 char buf[BUFSIZ], *pbuf, dir[
PATH_MAX], *p;
2917 (void)
mg_snprintf(conn, dir,
sizeof(dir),
"%s", prog);
2918 if ((p = strrchr(dir, DIRSEP)) != NULL) {
2921 dir[0] =
'.', dir[1] =
'\0';
2926 fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
2929 if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
2931 "Cannot create CGI pipe: %s", strerror(
ERRNO));
2934 fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
2936 }
else if ((in = fdopen(fd_stdin[1],
"wb")) == NULL ||
2937 (out = fdopen(fd_stdout[0],
"rb")) == NULL) {
2939 "fopen: %s", strerror(
ERRNO));
2950 fd_stdin[0] = fd_stdout[1] = -1;
2964 buf,
sizeof(buf), &data_len);
2965 if (headers_len <= 0) {
2967 "CGI program sent malformed HTTP headers: [%.*s]",
2972 buf[headers_len - 1] =
'\0';
2989 (
size_t)(data_len - headers_len));
2995 if (pid != (pid_t) -1) {
2998 if (fd_stdin[0] != -1) {
2999 (void) close(fd_stdin[0]);
3001 if (fd_stdout[1] != -1) {
3002 (void) close(fd_stdout[1]);
3007 }
else if (fd_stdin[1] != -1) {
3008 (void) close(fd_stdin[1]);
3013 }
else if (fd_stdout[0] != -1) {
3014 (void) close(fd_stdout[0]);
3028 for (s = p = path + 2; (p = strchr(s, DIRSEP)) != NULL; s = ++p) {
3030 if (len >= (
int)
sizeof(buf)) {
3034 memcpy(buf, path, len);
3062 if ((rc =
put_dir(path)) == 0) {
3064 }
else if (rc == -1) {
3066 "put_dir(%s): %s", path, strerror(
ERRNO));
3067 }
else if ((fp =
mg_fopen(path,
"wb+")) == NULL) {
3069 "fopen(%s): %s", path, strerror(
ERRNO));
3077 (void) fseeko(fp, (
off_t) r1, SEEK_SET);
3080 (
void)
mg_printf(conn,
"HTTP/1.1 %d OK\r\n\r\n",
3089 char *tag,
int include_level) {
3090 char file_name[BUFSIZ], path[
PATH_MAX], *p;
3099 if (sscanf(tag,
" virtual=\"%[^\"]\"", file_name) == 1) {
3101 (void)
mg_snprintf(conn, path,
sizeof(path),
"%.*s%c%s",
3103 }
else if (sscanf(tag,
" file=\"%[^\"]\"", file_name) == 1) {
3106 (void)
mg_snprintf(conn, path,
sizeof(path),
"%s", file_name);
3107 }
else if (sscanf(tag,
" \"%[^\"]\"", file_name) == 1) {
3109 (void)
mg_snprintf(conn, path,
sizeof(path),
"%s", ssi);
3110 if ((p = strrchr(path, DIRSEP)) != NULL) {
3114 sizeof(path) - strlen(path),
"%s", file_name);
3116 cry(conn,
"Bad SSI #include: [%s]", tag);
3120 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
3121 cry(conn,
"Cannot open SSI #include: [%s]: fopen(%s): %s",
3122 tag, path, strerror(
ERRNO));
3135 #if !defined(NO_POPEN)
3140 if (sscanf(tag,
" \"%[^\"]\"", cmd) != 1) {
3141 cry(conn,
"Bad SSI #exec: [%s]", tag);
3142 }
else if ((fp = popen(cmd,
"r")) == NULL) {
3143 cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
3152 FILE *fp,
int include_level) {
3154 int ch,
len, in_ssi_tag;
3156 if (include_level > 10) {
3157 cry(conn,
"SSI #include level is too deep (%s)", path);
3164 while ((ch = fgetc(fp)) != EOF) {
3165 if (in_ssi_tag && ch ==
'>') {
3167 buf[len++] = (char) ch;
3169 assert(len <= (
int)
sizeof(buf));
3170 if (len < 6 || memcmp(buf,
"<!--#", 5) != 0) {
3174 if (!memcmp(buf + 5,
"include", 7)) {
3176 #if !defined(NO_POPEN)
3177 }
else if (!memcmp(buf + 5,
"exec", 4)) {
3181 cry(conn,
"%s: unknown SSI " "command: \"%s\"", path, buf);
3185 }
else if (in_ssi_tag) {
3186 if (len == 5 && memcmp(buf,
"<!--#", 5) != 0) {
3189 }
else if (len == (
int)
sizeof(buf) - 2) {
3190 cry(conn,
"%s: SSI tag is too large", path);
3193 buf[len++] = ch & 0xff;
3194 }
else if (ch ==
'<') {
3200 buf[len++] = ch & 0xff;
3202 buf[len++] = ch & 0xff;
3203 if (len == (
int)
sizeof(buf)) {
3220 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
3226 "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
3237 "HTTP/1.1 200 OK\r\n"
3238 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n"
3249 "<d:href>%s</d:href>"
3252 "<d:resourcetype>%s</d:resourcetype>"
3253 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
3254 "<d:getlastmodified>%s</d:getlastmodified>"
3256 "<d:status>HTTP/1.1 200 OK</d:status>"
3278 mg_printf(conn,
"HTTP/1.1 207 Multi-Status\r\n"
3279 "Connection: close\r\n"
3280 "Content-Type: text/xml; charset=utf-8\r\n\r\n");
3283 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
3284 "<d:multistatus xmlns:d='DAV:'>\n");
3292 (depth == NULL || strcmp(depth,
"0") != 0)) {
3312 uri_len = strlen(ri->
uri);
3343 }
else if (
mg_stat(path, &st) != 0) {
3347 "HTTP/1.1 301 Moved Permanently\r\n"
3348 "Location: %s/\r\n\r\n", ri->
uri);
3357 "Directory listing denied");
3359 #if !defined(NO_CGI)
3391 int a, b, c, d, port,
len;
3394 memset(so, 0,
sizeof(*so));
3396 if (sscanf(vec->
ptr,
"%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
3398 usa->
u.
sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
3399 }
else if (sscanf(vec->
ptr,
"%d%n", &port, &len) == 1) {
3401 usa->
u.
sin.sin_addr.s_addr = htonl(INADDR_ANY);
3405 assert(len > 0 && len <= (
int) vec->
len);
3407 if (strchr(
"sp,", vec->
ptr[len]) == NULL) {
3413 usa->
len =
sizeof(usa->
u.
sin);
3414 usa->
u.
sin.sin_family = AF_INET;
3422 int on = 1, success = 1;
3425 struct socket so, *listener;
3427 while (success && (list =
next_option(list, &vec, NULL)) != NULL) {
3429 cry(
fc(ctx),
"%s: %.*s: invalid port spec. Expecting list of: %s",
3433 cry(
fc(ctx),
"Cannot add SSL socket, is -ssl_certificate option set?");
3436 #
if !defined(_WIN32)
3439 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
3449 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (
void *) &on,
3452 listen(sock, 100) != 0) {
3457 }
else if ((listener = (
struct socket *)
3458 calloc(1,
sizeof(*listener))) == NULL) {
3480 const char *header_value;
3483 (void) fprintf(fp,
"%s",
" -");
3485 (void) fprintf(fp,
" \"%s\"", header_value);
3500 (void) strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z",
3508 "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
3518 (void) fputc(
'\n', fp);
3526 return n >= 0 && n <= 255;
3532 int a, b, c, d, n, mask, allowed;
3542 (void) memcpy(&remote_ip, &usa->
u.
sin.sin_addr,
sizeof(remote_ip));
3547 while ((list =
next_option(list, &vec, NULL)) != NULL) {
3550 if (sscanf(vec.
ptr,
"%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) {
3551 cry(
fc(ctx),
"%s: subnet must be [+|-]x.x.x.x[/x]",
__func__);
3553 }
else if (flag !=
'+' && flag !=
'-') {
3559 }
else if (sscanf(vec.
ptr + n,
"/%d", &mask) == 0) {
3561 }
else if (mask < 0 || mask > 32) {
3566 acl_subnet = (a << 24) | (b << 16) | (c << 8) | d;
3567 acl_mask = mask ? 0xffffffff
U << (32 - mask) : 0;
3569 if (acl_subnet == (ntohl(remote_ip) & acl_mask)) {
3574 return allowed ==
'+';
3579 if (fd > (
SOCKET) *max_fd) {
3584 #if !defined(_WIN32)
3593 if ((pw = getpwnam(uid)) == NULL) {
3595 }
else if (setgid(pw->pw_gid) == -1) {
3596 cry(
fc(ctx),
"%s: setgid(%s): %s",
__func__, uid, strerror(errno));
3597 }
else if (setuid(pw->pw_uid) == -1) {
3598 cry(
fc(ctx),
"%s: setuid(%s): %s",
__func__, uid, strerror(errno));
3608 #if !defined(NO_SSL)
3627 #if !defined(NO_SSL_DL)
3630 union {
void *p; void (*fp)(void);} u;
3639 for (fp = sw; fp->
name != NULL; fp++) {
3642 u.fp = (void (*)(void))
dlsym(dll_handle, fp->
name);
3672 #if !defined(NO_SSL_DL)
3686 memset(&request_info, 0,
sizeof(request_info));
3702 if (CTX != NULL && chain != NULL &&
3704 cry(
fc(ctx),
"%s: cannot open %s: %s", NULL, chain,
ssl_error());
3711 if ((ssl_mutexes = (
pthread_mutex_t *) malloc((
size_t)size)) == NULL) {
3745 return path == NULL ||
mg_stat(path, &mgstat) == 0;
3771 struct linger linger;
3777 linger.l_linger = 1;
3778 setsockopt(sock, SOL_SOCKET, SO_LINGER, (
void *) &linger,
sizeof(linger));
3781 (void) shutdown(sock, SHUT_WR);
3790 n =
pull(NULL, sock, NULL, buf,
sizeof(buf));
3810 int buffered_len, body_len;
3814 assert(buffered_len >= 0);
3821 body_len = buffered_len;
3829 static int parse_url(
const char *url,
char *host,
int *port) {
3832 if (sscanf(url,
"%*[htps]://%1024[^:]:%d%n", host, port, &len) == 2 ||
3833 sscanf(url,
"%1024[^:]:%d%n", host, port, &len) == 2) {
3834 }
else if (sscanf(url,
"%*[htps]://%1024[^/]%n", host, &len) == 1) {
3837 sscanf(url,
"%1024[^/]%n", host, &len);
3847 char host[1025], buf[BUFSIZ];
3848 int port,
is_ssl, len, i, n;
3851 if (ri->
uri == NULL ||
3852 ri->
uri[0] ==
'/' ||
3857 if (conn->
peer == NULL) {
3859 if ((conn->
peer =
mg_connect(conn, host, port, is_ssl)) == NULL) {
3884 buf,
sizeof(buf))) > 0) {
3885 if (
mg_write(conn, buf, (
size_t)n) != n) {
3900 return (uri[0] ==
'/' || (uri[0] ==
'*' && uri[1] ==
'\0'));
3905 int keep_alive_enabled;
3932 "Cannot parse HTTP request: [%.*s]", conn->
data_len, conn->
buf);
3941 conn->
content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10);
3980 (void) pthread_cond_signal(&ctx->
sq_empty);
3992 conn->
buf = (
char *) (conn + 1);
3993 assert(conn != NULL);
4022 (void) pthread_cond_signal(&ctx->
cond);
4046 (void) pthread_cond_signal(&ctx->
sq_full);
4056 accepted.
lsa = listener->
lsa;
4067 cry(
fc(ctx),
"%s: %s is not allowed to connect",
4090 tv.tv_usec = 200 * 1000;
4092 if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
4113 pthread_cond_broadcast(&ctx->
sq_full);
4118 (void) pthread_cond_wait(&ctx->
cond, &ctx->
mutex);
4124 (void) pthread_cond_destroy(&ctx->
cond);
4125 (void) pthread_cond_destroy(&ctx->
sq_empty);
4126 (void) pthread_cond_destroy(&ctx->
sq_full);
4128 #if !defined(NO_SSL)
4143 if (ctx->
config[i] != NULL)
4152 if (ssl_mutexes != NULL) {
4170 #if defined(_WIN32) && !defined(__SYMBIAN32__)
4171 (void) WSACleanup();
4176 const char **options) {
4178 const char *name, *value, *default_value;
4181 #if defined(_WIN32) && !defined(__SYMBIAN32__)
4183 WSAStartup(MAKEWORD(2,2), &data);
4188 ctx = (
struct mg_context *) calloc(1,
sizeof(*ctx));
4192 while (options && (name = *options++) != NULL) {
4194 cry(
fc(ctx),
"Invalid option: %s", name);
4197 }
else if ((value = *options++) == NULL) {
4198 cry(
fc(ctx),
"%s: option value cannot be NULL", name);
4209 if (ctx->
config[i] == NULL && default_value != NULL) {
4224 #
if !defined(_WIN32)
4232 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
4235 (void) signal(SIGPIPE, SIG_IGN);
4237 (void) signal(SIGCHLD, SIG_IGN);
4241 (void) pthread_cond_init(&ctx->
cond, NULL);
4242 (void) pthread_cond_init(&ctx->
sq_empty, NULL);
4243 (void) pthread_cond_init(&ctx->
sq_full, NULL);
4251 cry(
fc(ctx),
"Cannot start worker thread: %d",
ERRNO);
static int parse_port_string(const struct vec *vec, struct socket *so)
#define CRYPTO_set_id_callback
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
#define MD5STEP(f, w, x, y, z, data, s)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
static int mg_stat(const char *path, struct mgstat *stp)
static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
static int should_keep_alive(const struct mg_connection *conn)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
static void print_props(struct mg_connection *conn, const char *uri, struct mgstat *st)
#define SSL_CTX_set_default_passwd_cb
#define SSL_CTX_use_PrivateKey_file
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)
char buf[CGI_ENVIRONMENT_SIZE]
#define IS_DIRSEP_CHAR(c)
static void send_ssi_file(struct mg_connection *, const char *, FILE *, int)
static int start_thread(struct mg_context *ctx, mg_thread_func_t func, void *param)
static void byteReverse(unsigned char *buf, unsigned longs)
unsigned sleep(unsigned sec)
static void print_dir_entry(struct de *de)
static int get_month_index(const char *s)
static void reset_per_request_attributes(struct mg_connection *conn)
static struct ssl_func crypto_sw[]
struct mg_connection * conn
static void send_options(struct mg_connection *conn)
void *(* mg_thread_func_t)(void *)
static int get_option_index(const char *name)
static void put_file(struct mg_connection *conn, const char *path)
static void out(const wchar_t *fmt,...)
static const char * ssl_error(void)
static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
static void send_authorization_request(struct mg_connection *conn)
static int mg_strncasecmp(const char *s1, const char *s2, size_t len)
int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, char *dst, size_t dst_size)
static const char * config_options[]
static int set_acl_option(struct mg_context *ctx)
struct mg_request_info::mg_header http_headers[64]
struct MD5Context MD5_CTX
#define SSLv23_server_method
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
static int check_authorization(struct mg_connection *conn, const char *path)
static void send_http_error(struct mg_connection *conn, int status, const char *reason, const char *fmt,...)
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path)
#define SSL_CTX_use_certificate_chain_file
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mgstat *stp)
static struct mg_connection * mg_connect(struct mg_connection *conn, const char *host, int port, int use_ssl)
static void close_all_listening_sockets(struct mg_context *ctx)
static void cry(struct mg_connection *conn, const char *fmt,...)
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void(*cb)(struct de *, void *))
struct ssl_ctx_st SSL_CTX
static void handle_proxy_request(struct mg_connection *conn)
void mg_md5(char *buf,...)
static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, va_list ap)
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
static unsigned long ssl_id_callback(void)
static struct @67 builtin_mime_types[]
static void url_encode(const char *src, char *dst, size_t dst_len)
static int check_acl(struct mg_context *ctx, const struct usa *usa)
static char * skip(char **buf, const char *delimiters)
static void close_connection(struct mg_connection *conn)
static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz, int *nread)
static int set_uid_option(struct mg_context *ctx)
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
static void uninitialize_ssl(struct mg_context *ctx)
static int match_extension(const char *path, const char *ext_list)
static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
static void * call_user(struct mg_connection *conn, enum mg_event event)
static int set_non_blocking_mode(SOCKET sock)
unsigned long long uint64_t
static void handle_file_request(struct mg_connection *conn, const char *path, struct mgstat *stp)
static int authorize(struct mg_connection *conn, FILE *fp)
static void discard_current_request_from_buffer(struct mg_connection *conn)
static void parse_http_headers(char **buf, struct mg_request_info *ri)
static void log_header(const struct mg_connection *conn, const char *header, FILE *fp)
int pthread_create(pthread_t *thread_id, const void *attr, void *(*func)(void *), void *arg)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
static int get_document_root(const struct mg_connection *conn, struct vec *document_root)
static time_t parse_date_string(const char *datetime)
mg_callback_t user_callback
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
static size_t url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int is_form_url_encoded)
const char * mg_version(void)
void * dlopen(const char *so_name, int flags)
int read(int fd, void *buf, size_t nbytes)
static void free_context(struct mg_context *ctx)
static void close_socket_gracefully(SOCKET sock)
static int mg_strcasecmp(const char *s1, const char *s2)
static void convert_uri_to_file_name(struct mg_connection *conn, const char *uri, char *buf, size_t buf_len)
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 int WINCDECL compare_dir_entries(const void *p1, const void *p2)
static void remove_double_dots_and_double_slashes(char *s)
static char * addenv(struct cgi_env_block *block, const char *fmt,...)
static void do_ssi_exec(struct mg_connection *conn, char *tag)
static void set_close_on_exec(int fd)
void * dlsym(void *handle, const char *sym_name)
static char * mg_strdup(const char *str)
#define MAX_CGI_ENVIR_VARS
static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len)
static void process_new_connection(struct mg_connection *conn)
struct socket * listening_sockets
struct mg_connection * conn
static int is_authorized_for_put(struct mg_connection *conn)
int pthread_mutex_init(pthread_mutex_t *m, const pthread_mutexattr_t *)
static void handle_directory_request(struct mg_connection *conn, const char *dir)
char * vars[MAX_CGI_ENVIR_VARS]
static int consume_socket(struct mg_context *ctx, struct socket *sp)
static const char * get_header(const struct mg_request_info *ri, const char *name)
const char * mg_get_option(const struct mg_context *ctx, const char *name)
#define PASSWORDS_FILE_NAME
static int set_gpass_option(struct mg_context *ctx)
#define SSL_load_error_strings
const char * mg_get_header(const struct mg_connection *conn, const char *name)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
#define CGI_ENVIRONMENT_SIZE
static int lowercase(const char *s)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
static void bin2str(char *to, const unsigned char *p, size_t len)
static int set_ports_option(struct mg_context *ctx)
static int sslize(struct mg_connection *conn, int(*func)(SSL *))
static char * mg_strndup(const char *ptr, size_t len)
const char ** mg_get_valid_option_names(void)
static void add_to_set(SOCKET fd, fd_set *set, int *max_fd)
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 int is_not_modified(const struct mg_connection *conn, const struct mgstat *stp)
int pthread_mutex_unlock(pthread_mutex_t *m)
char * config[NUM_OPTIONS]
#define ENTRIES_PER_CONFIG_OPTION
static const char * month_names[]
static int is_valid_uri(const char *uri)
static void handle_propfind(struct mg_connection *conn, const char *path, struct mgstat *st)
#define ARRAY_SIZE(array)
static int parse_url(const char *url, char *host, int *port)
static void MD5Final(unsigned char digest[16], MD5_CTX *ctx)
static void handle_request(struct mg_connection *conn)
static int get_request_len(const char *buf, int buflen)
static void worker_thread(struct mg_context *ctx)
static int load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
static Handle handle(size_t idx, u64 tag)
static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
static int is_valid_http_method(const char *method)
#define SSL_CTX_use_certificate_file
static const char * suggest_connection_header(const struct mg_connection *conn)
void mg_send_file(struct mg_connection *conn, const char *path)
static void log_access(const struct mg_connection *conn)
int pthread_mutex_destroy(pthread_mutex_t *m)
struct mg_context * mg_start(mg_callback_t user_callback, void *user_data, const char **options)
static struct mg_connection * fc(struct mg_context *ctx)
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt,...)
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
struct mg_connection * peer
static void master_thread(struct mg_context *ctx)
static int put_dir(const char *path)
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
static pthread_mutex_t * ssl_mutexes
static FILE * open_auth_file(struct mg_connection *conn, const char *path)
static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_env_block *blk)
static void MD5Init(MD5_CTX *ctx)
static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len)
struct ssl_method_st SSL_METHOD
void mg_stop(struct mg_context *ctx)
static int parse_http_request(char *buf, struct mg_request_info *ri)
#define CRYPTO_set_locking_callback
static const char * http_500_error
static void dir_scan_callback(struct de *de, void *data)
static struct ssl_func ssl_sw[]
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 gmt_time_string(char *buf, size_t buf_len, time_t *t)
static int set_ssl_option(struct mg_context *ctx)
static void print_dav_dir_entry(struct de *de, void *data)