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 28 #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE 29 #include <sys/types.h> 46 #if defined(_WIN32) // Windows specific #includes and #defines 47 #define _WIN32_WINNT 0x0400 // To make it link in VS2005 51 #define PATH_MAX MAX_PATH 60 #define NO_CGI // WinCE has no pipes 65 #define errno GetLastError() 66 #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10) 69 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \ 70 ((uint64_t)((uint32_t)(hi))) << 32)) 71 #define RATE_DIFF 10000000 // 100 nsecs 72 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de) 73 #define SYS2UNIX_TIME(lo, hi) \ 74 (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF) 79 #if defined(_MSC_VER) && _MSC_VER < 1300 81 #define STR(x) STRX(x) 82 #define __func__ "line " STR(__LINE__) 83 #define strtoull(x, y, z) strtoul(x, y, z) 84 #define strtoll(x, y, z) strtol(x, y, z) 86 #define __func__ __FUNCTION__ 87 #define strtoull(x, y, z) _strtoui64(x, y, z) 88 #define strtoll(x, y, z) _strtoi64(x, y, z) 91 #define ERRNO GetLastError() 93 #define SSL_LIB "ssleay32.dll" 94 #define CRYPTO_LIB "libeay32.dll" 96 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\') 98 #if !defined(EWOULDBLOCK) 99 #define EWOULDBLOCK WSAEWOULDBLOCK 100 #endif // !EWOULDBLOCK 102 #define INT64_FMT "I64d" 104 #define WINCDECL __cdecl 106 #define snprintf _snprintf 107 #define vsnprintf _vsnprintf 108 #define sleep(x) Sleep((x) * 1000) 110 #define pipe(x) _pipe(x, BUFSIZ, _O_BINARY) 111 #define popen(x, y) _popen(x, y) 112 #define pclose(x) _pclose(x) 113 #define close(x) _close(x) 114 #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) 116 #define fseeko(x, y, z) fseek((x), (y), (z)) 117 #define fdopen(x, y) _fdopen((x), (y)) 118 #define write(x, y, z) _write((x), (y), (unsigned) z) 119 #define read(x, y, z) _read((x), (y), (unsigned) z) 120 #define flockfile(x) (void) 0 121 #define funlockfile(x) (void) 0 124 #define fileno(x) _fileno(x) 125 #endif // !fileno MINGW #defines fileno 127 typedef HANDLE pthread_mutex_t;
128 typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
129 typedef DWORD pthread_t;
130 #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here. 137 static int pthread_mutex_lock(pthread_mutex_t *);
138 static int pthread_mutex_unlock(pthread_mutex_t *);
139 static FILE *
mg_fopen(
const char *path,
const char *mode);
141 #if defined(HAVE_STDINT) 144 typedef unsigned int uint32_t;
145 typedef unsigned short uint16_t;
146 typedef unsigned __int64 uint64_t;
147 typedef __int64 int64_t;
148 #define INT64_MAX 9223372036854775807 149 #endif // HAVE_STDINT 153 char d_name[PATH_MAX];
158 WIN32_FIND_DATAW info;
159 struct dirent result;
162 #else // UNIX specific 163 #include <sys/wait.h> 164 #include <sys/socket.h> 165 #include <sys/select.h> 166 #include <netinet/in.h> 167 #include <arpa/inet.h> 168 #include <sys/time.h> 170 #include <inttypes.h> 176 #if !defined(NO_SSL_DL) && !defined(NO_SSL) 180 #if defined(__MACH__) 181 #define SSL_LIB "libssl.dylib" 182 #define CRYPTO_LIB "libcrypto.dylib" 184 #if !defined(SSL_LIB) 185 #define SSL_LIB "libssl.so" 187 #if !defined(CRYPTO_LIB) 188 #define CRYPTO_LIB "libcrypto.so" 192 #define IS_DIRSEP_CHAR(c) ((c) == '/') 194 #define closesocket(a) close(a) 195 #define mg_fopen(x, y) fopen(x, y) 196 #define mg_mkdir(x, y) mkdir(x, y) 197 #define mg_remove(x) remove(x) 198 #define mg_rename(x, y) rename(x, y) 200 #define INVALID_SOCKET (-1) 201 #define INT64_FMT PRId64 205 #endif // End of Windows and UNIX specific includes 209 #define MONGOOSE_VERSION "3.0" 210 #define PASSWORDS_FILE_NAME ".htpasswd" 211 #define CGI_ENVIRONMENT_SIZE 4096 212 #define MAX_CGI_ENVIR_VARS 64 213 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) 216 #define DEBUG_TRACE(x) do { \ 218 printf("*** %lu.%p.%s.%d: ", \ 219 (unsigned long) time(NULL), (void *) pthread_self(), \ 220 __func__, __LINE__); \ 224 funlockfile(stdout); \ 227 #define DEBUG_TRACE(x) 232 typedef int socklen_t;
233 #endif // NO_SOCKLEN_T 235 typedef void * (*mg_thread_func_t)(
void *);
242 typedef struct ssl_st
SSL;
246 #define SSL_ERROR_WANT_READ 2 247 #define SSL_ERROR_WANT_WRITE 3 248 #define SSL_FILETYPE_PEM 1 249 #define CRYPTO_LOCK 1 251 #if defined(NO_SSL_DL) 281 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) 282 #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) 283 #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) 284 #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) 285 #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) 286 #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5]) 287 #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) 288 #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) 289 #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) 290 #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) 291 #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) 292 #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ 293 const char *, int)) ssl_sw[11].ptr) 294 #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ 295 const char *, int)) ssl_sw[12].ptr) 296 #define SSL_CTX_set_default_passwd_cb \ 297 (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr) 298 #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) 299 #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) 300 #define SSL_CTX_use_certificate_chain_file \ 301 (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) 303 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) 304 #define CRYPTO_set_locking_callback \ 305 (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) 306 #define CRYPTO_set_id_callback \ 307 (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) 308 #define ERR_get_error (* (unsigned long (*)(void)) ssl_sw[3].ptr) 309 #define ERR_error_string (* (char * (*)(unsigned long, char *)) ssl_sw[4].ptr) 317 {
"SSL_accept", NULL},
318 {
"SSL_connect", NULL},
321 {
"SSL_get_error", NULL},
322 {
"SSL_set_fd", NULL},
324 {
"SSL_CTX_new", NULL},
325 {
"SSLv23_server_method", NULL},
326 {
"SSL_library_init", NULL},
327 {
"SSL_CTX_use_PrivateKey_file", NULL},
328 {
"SSL_CTX_use_certificate_file",NULL},
329 {
"SSL_CTX_set_default_passwd_cb",NULL},
330 {
"SSL_CTX_free", NULL},
331 {
"SSL_load_error_strings", NULL},
332 {
"SSL_CTX_use_certificate_chain_file", NULL},
338 {
"CRYPTO_num_locks", NULL},
339 {
"CRYPTO_set_locking_callback", NULL},
340 {
"CRYPTO_set_id_callback", NULL},
341 {
"ERR_get_error", NULL},
342 {
"ERR_error_string", NULL},
348 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
349 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec" 358 struct sockaddr_in sin;
398 "C",
"cgi_extensions",
".cgi,.pl,.php",
399 "E",
"cgi_environment", NULL,
400 "G",
"put_delete_passwords_file", NULL,
401 "I",
"cgi_interpreter", NULL,
402 "P",
"protect_uri", NULL,
403 "R",
"authentication_domain",
"mydomain.com",
404 "S",
"ssi_extensions",
".shtml,.shtm",
405 "a",
"access_log_file", NULL,
406 "c",
"ssl_chain_file", NULL,
407 "d",
"enable_directory_listing",
"yes",
408 "e",
"error_log_file", NULL,
409 "g",
"global_passwords_file", NULL,
410 "i",
"index_files",
"index.html,index.htm,index.cgi",
411 "k",
"enable_keep_alive",
"no",
412 "l",
"access_control_list", NULL,
413 "M",
"max_request_size",
"16384",
414 "m",
"extra_mime_types", NULL,
415 "p",
"listening_ports",
"8080",
416 "r",
"document_root",
".",
417 "s",
"ssl_certificate", NULL,
418 "t",
"num_threads",
"10",
419 "u",
"run_as_user", NULL,
420 "T",
"max_threads", NULL,
423 #define ENTRIES_PER_CONFIG_OPTION 3 478 if (strcmp(config_options[i], name) == 0 ||
479 strcmp(config_options[i + 1], name) == 0) {
490 }
else if (ctx->
config[i] == NULL) {
505 (void) vsnprintf(buf,
sizeof(buf), fmt, ap);
518 timestamp = time(NULL);
521 "[%010lu] [error] [client %s] ",
522 (
unsigned long) timestamp,
526 (void) fprintf(fp,
"%s %s: ",
531 (void) fprintf(fp,
"%s", buf);
553 fake_connection.
ctx =
ctx;
554 return &fake_connection;
561 static void mg_strlcpy(
register char *dst,
register const char *src,
size_t n) {
562 for (; *src !=
'\0' && n > 1; n--) {
569 return tolower(* (
const unsigned char *) s);
578 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
588 }
while (diff == 0 && s1[-1] !=
'\0');
596 if ((p = (
char *) malloc(len + 1)) != NULL) {
612 const char *fmt, va_list ap) {
618 n = vsnprintf(buf, buflen, fmt, ap);
621 cry(conn,
"vsnprintf error");
623 }
else if (n >= (
int) buflen) {
624 cry(conn,
"truncating vsnprintf buffer: [%.*s]",
625 n > 200 ? 200 : n, buf);
626 n = (int) buflen - 1;
634 const char *fmt, ...) {
649 static char *
skip_quoted(
char **
buf,
const char *delimiters,
const char *whitespace,
char quotechar) {
650 char *p, *begin_word, *end_word, *end_whitespace;
653 end_word = begin_word + strcspn(begin_word, delimiters);
656 if (end_word > begin_word) {
658 while (*p == quotechar) {
660 if (*end_word ==
'\0') {
664 size_t end_off = strcspn(end_word + 1, delimiters);
665 memmove (p, end_word, end_off + 1);
667 end_word += end_off + 1;
670 for (p++; p < end_word; p++) {
675 if (*end_word ==
'\0') {
678 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
680 for (p = end_word; p < end_whitespace; p++) {
684 *buf = end_whitespace;
691 static char *
skip(
char **
buf,
const char *delimiters) {
692 return skip_quoted(buf, delimiters, delimiters, 0);
719 struct vec *eq_val) {
720 if (list == NULL || *list ==
'\0') {
725 if ((list = strchr(val->
ptr,
',')) != NULL) {
727 val->
len = list - val->
ptr;
731 list = val->
ptr + strlen(val->
ptr);
732 val->
len = list - val->
ptr;
735 if (eq_val != NULL) {
741 eq_val->
ptr = memchr(val->
ptr,
'=', val->
len);
742 if (eq_val->
ptr != NULL) {
758 path_len = strlen(path);
760 while ((ext_list =
next_option(ext_list, &ext_vec, NULL)) != NULL)
761 if (ext_vec.
len < path_len &&
763 ext_vec.
ptr, ext_vec.
len) == 0)
776 return (header == NULL && http_version && !strcmp(http_version,
"1.1")) ||
785 const char *reason,
const char *fmt, ...) {
797 if (status > 199 && status != 204 && status != 304) {
798 len =
mg_snprintf(conn, buf,
sizeof(buf),
"Error %d: %s", status, reason);
799 cry(conn,
"%s", buf);
803 len +=
mg_vsnprintf(conn, buf + len,
sizeof(buf) - len, fmt, ap);
809 "Content-Type: text/plain\r\n" 810 "Content-Length: %d\r\n" 811 "Connection: %s\r\n\r\n", status, reason, len,
818 static int pthread_mutex_init(pthread_mutex_t *mutex,
void *unused) {
820 *mutex = CreateMutex(NULL, FALSE, NULL);
821 return *mutex == NULL ? -1 : 0;
824 static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
825 return CloseHandle(*mutex) == 0 ? -1 : 0;
828 static int pthread_mutex_lock(pthread_mutex_t *mutex) {
829 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
832 static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
833 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
836 static int pthread_cond_init(pthread_cond_t *cv,
const void *unused) {
838 cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
839 cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
840 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
843 static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
844 HANDLE handles[] = {cv->signal, cv->broadcast};
845 ReleaseMutex(*mutex);
846 WaitForMultipleObjects(2, handles, FALSE, INFINITE);
847 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
850 static int pthread_cond_signal(pthread_cond_t *cv) {
851 return SetEvent(cv->signal) == 0 ? -1 : 0;
854 static int pthread_cond_broadcast(pthread_cond_t *cv) {
857 return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
860 static int pthread_cond_destroy(pthread_cond_t *cv) {
861 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
864 static pthread_t pthread_self(
void) {
865 return GetCurrentThreadId();
869 static void change_slashes_to_backslashes(
char *path) {
872 for (i = 0; path[i] !=
'\0'; i++) {
876 if (path[i] ==
'\\' && i > 0)
877 while (path[i + 1] ==
'\\' || path[i + 1] ==
'/')
878 (void) memmove(path + i + 1,
879 path + i + 2, strlen(path + i + 1));
885 static void to_unicode(
const char *path,
wchar_t *wbuf,
size_t wbuf_len) {
886 char buf[PATH_MAX], *p;
889 change_slashes_to_backslashes(buf);
892 p = buf + strlen(buf) - 1;
895 while (p > buf && *p ==
'\\' && p[-1] !=
':') {
904 (*p == 0x2e && p > buf) ||
907 (void) fprintf(stderr,
"Rejecting suspicious path: [%s]", buf);
911 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int) wbuf_len);
914 #if defined(_WIN32_WCE) 915 static time_t time(time_t *ptime) {
921 SystemTimeToFileTime(&st, &ft);
922 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
931 static time_t mktime(
struct tm *ptm) {
935 st.wYear = ptm->tm_year + 1900;
936 st.wMonth = ptm->tm_mon + 1;
937 st.wDay = ptm->tm_mday;
938 st.wHour = ptm->tm_hour;
939 st.wMinute = ptm->tm_min;
940 st.wSecond = ptm->tm_sec;
941 st.wMilliseconds = 0;
943 SystemTimeToFileTime(&st, &ft);
944 LocalFileTimeToFileTime(&ft, &lft);
945 return (time_t) ((MAKEUQUAD(lft.dwLowDateTime, lft.dwHighDateTime) -
946 EPOCH_DIFF) / RATE_DIFF);
949 static struct tm *localtime(
const time_t *ptime,
struct tm *ptm) {
950 int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
953 TIME_ZONE_INFORMATION tzinfo;
959 * (int64_t *) &ft = t;
960 FileTimeToLocalFileTime(&ft, &lft);
961 FileTimeToSystemTime(&lft, &st);
962 ptm->tm_year = st.wYear - 1900;
963 ptm->tm_mon = st.wMonth - 1;
964 ptm->tm_wday = st.wDayOfWeek;
965 ptm->tm_mday = st.wDay;
966 ptm->tm_hour = st.wHour;
967 ptm->tm_min = st.wMinute;
968 ptm->tm_sec = st.wSecond;
971 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
976 static size_t strftime(
char *dst,
size_t dst_size,
const char *fmt,
977 const struct tm *tm) {
978 (void) snprintf(dst, dst_size,
"implement strftime() for WinCE");
983 static int mg_rename(
const char* oldname,
const char* newname) {
984 wchar_t woldbuf[PATH_MAX];
985 wchar_t wnewbuf[PATH_MAX];
987 to_unicode(oldname, woldbuf,
ARRAY_SIZE(woldbuf));
988 to_unicode(newname, wnewbuf,
ARRAY_SIZE(wnewbuf));
990 return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
994 static FILE *
mg_fopen(
const char *path,
const char *mode) {
995 wchar_t wbuf[PATH_MAX], wmode[20];
998 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode,
ARRAY_SIZE(wmode));
1000 return _wfopen(wbuf, wmode);
1005 wchar_t wbuf[PATH_MAX];
1006 WIN32_FILE_ATTRIBUTE_DATA info;
1010 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
1011 stp->
size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
1012 stp->
mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
1013 info.ftLastWriteTime.dwHighDateTime);
1015 info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1022 static int mg_remove(
const char *path) {
1023 wchar_t wbuf[PATH_MAX];
1025 return DeleteFileW(wbuf) ? 0 : -1;
1028 static int mg_mkdir(
const char *path,
int mode) {
1030 wchar_t wbuf[PATH_MAX];
1034 change_slashes_to_backslashes(buf);
1036 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf,
sizeof(wbuf));
1038 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1042 static DIR * opendir(
const char *name) {
1044 wchar_t wpath[PATH_MAX];
1048 SetLastError(ERROR_BAD_ARGUMENTS);
1049 }
else if ((dir = (DIR *) malloc(
sizeof(*dir))) == NULL) {
1050 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1053 attrs = GetFileAttributesW(wpath);
1054 if (attrs != 0xFFFFFFFF &&
1055 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1056 (void) wcscat(wpath, L
"\\*");
1057 dir->handle = FindFirstFileW(wpath, &dir->info);
1058 dir->result.d_name[0] =
'\0';
1068 static int closedir(DIR *dir) {
1072 if (dir->handle != INVALID_HANDLE_VALUE)
1073 result = FindClose(dir->handle) ? 0 : -1;
1078 SetLastError(ERROR_BAD_ARGUMENTS);
1084 struct dirent * readdir(DIR *dir) {
1085 struct dirent *result = 0;
1088 if (dir->handle != INVALID_HANDLE_VALUE) {
1089 result = &dir->result;
1090 (void) WideCharToMultiByte(CP_UTF8, 0,
1091 dir->info.cFileName, -1, result->d_name,
1092 sizeof(result->d_name), NULL, NULL);
1094 if (!FindNextFileW(dir->handle, &dir->info)) {
1095 (void) FindClose(dir->handle);
1096 dir->handle = INVALID_HANDLE_VALUE;
1100 SetLastError(ERROR_FILE_NOT_FOUND);
1103 SetLastError(ERROR_BAD_ARGUMENTS);
1109 #define set_close_on_exec(fd) // No FD_CLOEXEC on Windows 1116 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, param, 0,
1118 if (hThread != NULL) {
1119 (void) CloseHandle(hThread);
1122 return hThread == NULL ? -1 : 0;
1125 static HANDLE dlopen(
const char *dll_name,
int flags) {
1126 wchar_t wbuf[PATH_MAX];
1128 to_unicode(dll_name, wbuf,
ARRAY_SIZE(wbuf));
1129 return LoadLibraryW(wbuf);
1132 #if !defined(NO_CGI) 1134 static int kill(pid_t pid,
int sig_num) {
1135 (void) TerminateProcess(pid, sig_num);
1136 (void) CloseHandle(pid);
1141 char *envblk,
char *envp[],
int fd_stdin,
1142 int fd_stdout,
const char *dir) {
1144 char *p, *interp, cmdline[PATH_MAX],
buf[PATH_MAX];
1147 PROCESS_INFORMATION pi;
1151 (void) memset(&si, 0,
sizeof(si));
1152 (void) memset(&pi, 0,
sizeof(pi));
1156 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1157 si.wShowWindow = SW_HIDE;
1159 me = GetCurrentProcess();
1160 (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
1161 &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1162 (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
1163 &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1167 if (interp == NULL) {
1169 if ((fp = fopen(cmdline,
"r")) != NULL) {
1170 (void) fgets(buf,
sizeof(buf), fp);
1171 if (buf[0] !=
'#' || buf[1] !=
'!') {
1176 for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
1185 (void)
mg_snprintf(conn, cmdline,
sizeof(cmdline),
"%s%s%s%c%s",
1186 interp, interp[0] ==
'\0' ?
"" :
" ", dir,
DIRSEP, prog);
1189 if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
1190 CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
1191 cry(conn,
"%s: CreateProcess(%s): %d",
1192 __func__, cmdline,
ERRNO);
1193 pi.hProcess = (pid_t) -1;
1195 (void) close(fd_stdin);
1196 (void) close(fd_stdout);
1199 (void) CloseHandle(si.hStdOutput);
1200 (void) CloseHandle(si.hStdInput);
1201 (void) CloseHandle(pi.hThread);
1203 return (pid_t) pi.hProcess;
1208 unsigned long on = 1;
1209 return ioctlsocket(sock, FIONBIO, &on);
1217 if (stat(path, &st) == 0) {
1219 stp->
size = st.st_size;
1220 stp->
mtime = st.st_mtime;
1230 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
1235 pthread_t thread_id;
1236 pthread_attr_t attr;
1239 (void) pthread_attr_init(&attr);
1240 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1244 if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) {
1245 cry(
fc(ctx),
"%s: %s", __func__, strerror(retval));
1253 char *envblk,
char *envp[],
int fd_stdin,
1254 int fd_stdout,
const char *dir) {
1260 if ((pid = fork()) == -1) {
1263 }
else if (pid == 0) {
1265 if (chdir(dir) != 0) {
1266 cry(conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
1267 }
else if (dup2(fd_stdin, 0) == -1) {
1268 cry(conn,
"%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(
ERRNO));
1269 }
else if (dup2(fd_stdout, 1) == -1) {
1270 cry(conn,
"%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(
ERRNO));
1272 (void) dup2(fd_stdout, 2);
1273 (void) close(fd_stdin);
1274 (void) close(fd_stdout);
1278 if (interp == NULL) {
1279 (void) execle(prog, prog, NULL, envp);
1280 cry(conn,
"%s: execle(%s): %s", __func__, prog, strerror(
ERRNO));
1282 (void) execle(interp, interp, prog, NULL, envp);
1283 cry(conn,
"%s: execle(%s %s): %s", __func__, interp, prog,
1290 (void) close(fd_stdin);
1291 (void) close(fd_stdout);
1301 flags = fcntl(sock, F_GETFL, 0);
1302 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1316 while (sent < len) {
1319 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
1323 }
else if (fp != NULL) {
1324 n = fwrite(buf + sent, 1, (
size_t)k, fp);
1328 n = send(sock, buf + sent, (
size_t)k, 0);
1347 }
else if (fp != NULL) {
1351 nread = read(fileno(fp), buf, (
size_t) len);
1355 nread = recv(sock, buf, (
size_t) len, 0);
1362 int n, buffered_len, nread;
1363 const char *buffered;
1373 if (to_read < (int64_t) len) {
1374 len = (int) to_read;
1380 assert(buffered_len >= 0);
1385 if (len < (
size_t) buffered_len) {
1388 memcpy(buf, buffered, (
size_t)buffered_len);
1389 len -= buffered_len;
1390 buf = (
char *) buf + buffered_len;
1392 nread = buffered_len;
1401 buf = (
char *) buf + n;
1412 (
const char *) buf, (int64_t) len);
1424 return mg_write(conn, buf, (
size_t)len);
1432 static size_t url_decode(
const char *src,
size_t src_len,
char *dst,
1433 size_t dst_len,
int is_form_url_encoded) {
1436 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') 1438 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
1439 if (src[i] ==
'%' &&
1440 isxdigit(* (
const unsigned char *) (src + i + 1)) &&
1441 isxdigit(* (
const unsigned char *) (src + i + 2))) {
1442 a = tolower(* (
const unsigned char *) (src + i + 1));
1443 b = tolower(* (
const unsigned char *) (src + i + 2));
1446 }
else if (is_form_url_encoded && src[i] ==
'+') {
1463 char *dst,
size_t dst_len) {
1464 const char *p, *e, *
s;
1465 size_t name_len, len;
1467 name_len = strlen(name);
1473 for (p = buf; p != NULL && p + name_len < e; p++) {
1474 if ((p == buf || p[-1] ==
'&') && p[name_len] ==
'=' &&
1481 s = (
const char *) memchr(p,
'&', (
size_t)(e - p));
1488 if ((
size_t) (s - p) < dst_len) {
1489 len =
url_decode(p, (
size_t)(s - p), dst, dst_len, 1);
1499 char *dst,
size_t dst_size) {
1500 const char *
s, *p, *end;
1501 int name_len, len = -1;
1508 name_len = strlen(cookie_name);
1509 end = s + strlen(s);
1511 for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
1512 if (s[name_len] ==
'=') {
1514 if ((p = strchr(s,
' ')) == NULL)
1518 if (*s ==
'"' && p[-1] ==
'"' && p > s + 1) {
1522 if ((
size_t) (p - s) < dst_size) {
1536 struct vec *document_root) {
1537 const char *root, *uri;
1538 int len_of_matched_uri;
1539 struct vec uri_vec, path_vec;
1542 len_of_matched_uri = 0;
1545 while ((root =
next_option(root, &uri_vec, &path_vec)) != NULL) {
1546 if (memcmp(uri, uri_vec.
ptr, uri_vec.
len) == 0) {
1547 *document_root = path_vec;
1548 len_of_matched_uri = uri_vec.
len;
1553 return len_of_matched_uri;
1557 const char *uri,
char *
buf,
1566 change_slashes_to_backslashes(buf);
1575 func(conn->
ssl) == 1;
1579 const char *host,
int port,
int use_ssl) {
1581 struct sockaddr_in sin;
1586 cry(conn,
"%s: SSL is not initialized", __func__);
1587 }
else if ((he = gethostbyname(host)) == NULL) {
1588 cry(conn,
"%s: gethostbyname(%s): %s", __func__, host, strerror(
ERRNO));
1590 cry(conn,
"%s: socket: %s", __func__, strerror(
ERRNO));
1592 sin.sin_family = AF_INET;
1593 sin.sin_port = htons((uint16_t) port);
1594 sin.sin_addr = * (
struct in_addr *) he->h_addr_list[0];
1595 if (connect(sock, (
struct sockaddr *) &sin,
sizeof(sin)) != 0) {
1596 cry(conn,
"%s: connect(%s:%d): %s", __func__, host, port,
1599 }
else if ((newconn = calloc(1,
sizeof(*newconn))) == NULL) {
1600 cry(conn,
"%s: calloc: %s", __func__, strerror(
ERRNO));
1623 for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
1625 if (!isprint(* (
const unsigned char *) s) && *s !=
'\r' &&
1626 *s !=
'\n' && * (
const unsigned char *) s < 128) {
1628 }
else if (s[0] ==
'\n' && s[1] ==
'\n') {
1629 len = (int) (s - buf) + 2;
1630 }
else if (s[0] ==
'\n' && &s[1] < e &&
1631 s[1] ==
'\r' && s[2] ==
'\n') {
1632 len = (int) (s - buf) + 3;
1642 for (i = 0; i <
ARRAY_SIZE(month_names); i++)
1643 if (!strcmp(s, month_names[i]))
1651 time_t current_time;
1654 int sec, min, hour, mday, month, year;
1656 (void) memset(&tm, 0,
sizeof(tm));
1657 sec = min = hour = mday = month = year = 0;
1659 if (((sscanf(s,
"%d/%3s/%d %d:%d:%d",
1660 &mday, mon, &year, &hour, &min, &sec) == 6) ||
1661 (sscanf(s,
"%d %3s %d %d:%d:%d",
1662 &mday, mon, &year, &hour, &min, &sec) == 6) ||
1663 (sscanf(s,
"%*3s, %d %3s %d %d:%d:%d",
1664 &mday, mon, &year, &hour, &min, &sec) == 6) ||
1665 (sscanf(s,
"%d-%3s-%d %d:%d:%d",
1666 &mday, mon, &year, &hour, &min, &sec) == 6)) &&
1676 if (tm.tm_year > 1900) {
1678 }
else if (tm.tm_year < 70) {
1683 current_time = time(NULL);
1684 tmp = localtime(¤t_time);
1685 tm.tm_isdst = tmp->tm_isdst;
1695 while (*s !=
'\0') {
1697 if (s[-1] ==
'/' || s[-1] ==
'\\') {
1699 while (*s ==
'/' || *s ==
'\\') {
1704 while (*s ==
'.' && s[1] ==
'.') {
1712 static const struct {
1718 {
".html", 5,
"text/html", 9},
1719 {
".htm", 4,
"text/html", 9},
1720 {
".shtm", 5,
"text/html", 9},
1721 {
".shtml", 6,
"text/html", 9},
1722 {
".css", 4,
"text/css", 8},
1723 {
".js", 3,
"application/x-javascript", 24},
1724 {
".ico", 4,
"image/x-icon", 12},
1725 {
".gif", 4,
"image/gif", 9},
1726 {
".jpg", 4,
"image/jpeg", 10},
1727 {
".jpeg", 5,
"image/jpeg", 10},
1728 {
".png", 4,
"image/png", 9},
1729 {
".svg", 4,
"image/svg+xml", 13},
1730 {
".torrent", 8,
"application/x-bittorrent", 24},
1731 {
".wav", 4,
"audio/x-wav", 11},
1732 {
".mp3", 4,
"audio/x-mp3", 11},
1733 {
".mid", 4,
"audio/mid", 9},
1734 {
".m3u", 4,
"audio/x-mpegurl", 15},
1735 {
".ram", 4,
"audio/x-pn-realaudio", 20},
1736 {
".xml", 4,
"text/xml", 8},
1737 {
".xslt", 5,
"application/xml", 15},
1738 {
".ra", 3,
"audio/x-pn-realaudio", 20},
1739 {
".doc", 4,
"application/msword", 19},
1740 {
".exe", 4,
"application/octet-stream", 24},
1741 {
".zip", 4,
"application/x-zip-compressed", 28},
1742 {
".xls", 4,
"application/excel", 17},
1743 {
".tgz", 4,
"application/x-tar-gz", 20},
1744 {
".tar", 4,
"application/x-tar", 17},
1745 {
".gz", 3,
"application/x-gunzip", 20},
1746 {
".arj", 4,
"application/x-arj-compressed", 28},
1747 {
".rar", 4,
"application/x-arj-compressed", 28},
1748 {
".rtf", 4,
"application/rtf", 15},
1749 {
".pdf", 4,
"application/pdf", 15},
1750 {
".swf", 4,
"application/x-shockwave-flash",29},
1751 {
".mpg", 4,
"video/mpeg", 10},
1752 {
".mpeg", 5,
"video/mpeg", 10},
1753 {
".asf", 4,
"video/x-ms-asf", 14},
1754 {
".avi", 4,
"video/x-msvideo", 15},
1755 {
".bmp", 4,
"image/bmp", 9},
1763 struct vec ext_vec, mime_vec;
1764 const char *list, *ext;
1767 path_len = strlen(path);
1772 while ((list =
next_option(list, &ext_vec, &mime_vec)) != NULL) {
1774 ext = path + path_len - ext_vec.
len;
1793 vec->
ptr =
"text/plain";
1801 unsigned char in[64];
1804 #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234) 1805 #define byteReverse(buf, len) // Do nothing 1810 t = (uint32_t) ((
unsigned) buf[3] << 8 | buf[2]) << 16 |
1811 ((
unsigned) buf[1] << 8 | buf[0]);
1812 *(uint32_t *) buf = t;
1818 #define F1(x, y, z) (z ^ (x & (y ^ z))) 1819 #define F2(x, y, z) F1(z, x, y) 1820 #define F3(x, y, z) (x ^ y ^ z) 1821 #define F4(x, y, z) (y ^ (x | ~z)) 1823 #define MD5STEP(f, w, x, y, z, data, s) \ 1824 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) 1829 ctx->
buf[0] = 0x67452301;
1830 ctx->
buf[1] = 0xefcdab89;
1831 ctx->
buf[2] = 0x98badcfe;
1832 ctx->
buf[3] = 0x10325476;
1839 register uint32_t a, b, c,
d;
1846 MD5STEP(
F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1847 MD5STEP(
F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1848 MD5STEP(
F1, c, d, a, b, in[2] + 0x242070db, 17);
1849 MD5STEP(
F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1850 MD5STEP(
F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1851 MD5STEP(
F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1852 MD5STEP(
F1, c, d, a, b, in[6] + 0xa8304613, 17);
1853 MD5STEP(
F1, b, c, d, a, in[7] + 0xfd469501, 22);
1854 MD5STEP(
F1, a, b, c, d, in[8] + 0x698098d8, 7);
1855 MD5STEP(
F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1856 MD5STEP(
F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1857 MD5STEP(
F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1858 MD5STEP(
F1, a, b, c, d, in[12] + 0x6b901122, 7);
1859 MD5STEP(
F1, d, a, b, c, in[13] + 0xfd987193, 12);
1860 MD5STEP(
F1, c, d, a, b, in[14] + 0xa679438e, 17);
1861 MD5STEP(
F1, b, c, d, a, in[15] + 0x49b40821, 22);
1863 MD5STEP(
F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1864 MD5STEP(
F2, d, a, b, c, in[6] + 0xc040b340, 9);
1865 MD5STEP(
F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1866 MD5STEP(
F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1867 MD5STEP(
F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1868 MD5STEP(
F2, d, a, b, c, in[10] + 0x02441453, 9);
1869 MD5STEP(
F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1870 MD5STEP(
F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1871 MD5STEP(
F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1872 MD5STEP(
F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1873 MD5STEP(
F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1874 MD5STEP(
F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1875 MD5STEP(
F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1876 MD5STEP(
F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1877 MD5STEP(
F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1878 MD5STEP(
F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1880 MD5STEP(
F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1881 MD5STEP(
F3, d, a, b, c, in[8] + 0x8771f681, 11);
1882 MD5STEP(
F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1883 MD5STEP(
F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1884 MD5STEP(
F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1885 MD5STEP(
F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1886 MD5STEP(
F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1887 MD5STEP(
F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1888 MD5STEP(
F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1889 MD5STEP(
F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1890 MD5STEP(
F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1891 MD5STEP(
F3, b, c, d, a, in[6] + 0x04881d05, 23);
1892 MD5STEP(
F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1893 MD5STEP(
F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1894 MD5STEP(
F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1895 MD5STEP(
F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1897 MD5STEP(
F4, a, b, c, d, in[0] + 0xf4292244, 6);
1898 MD5STEP(
F4, d, a, b, c, in[7] + 0x432aff97, 10);
1899 MD5STEP(
F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1900 MD5STEP(
F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1901 MD5STEP(
F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1902 MD5STEP(
F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1903 MD5STEP(
F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1904 MD5STEP(
F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1905 MD5STEP(
F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1906 MD5STEP(
F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1907 MD5STEP(
F4, c, d, a, b, in[6] + 0xa3014314, 15);
1908 MD5STEP(
F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1909 MD5STEP(
F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1910 MD5STEP(
F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1911 MD5STEP(
F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1912 MD5STEP(
F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1924 if ((ctx->
bits[0] = t + ((uint32_t) len << 3)) < t)
1926 ctx->
bits[1] += len >> 29;
1928 t = (t >> 3) & 0x3f;
1931 unsigned char *p = (
unsigned char *) ctx->
in + t;
1935 memcpy(p, buf, len);
1946 memcpy(ctx->
in, buf, 64);
1953 memcpy(ctx->
in, buf, len);
1960 count = (ctx->
bits[0] >> 3) & 0x3F;
1962 p = ctx->
in + count;
1964 count = 64 - 1 - count;
1966 memset(p, 0, count);
1969 memset(ctx->
in, 0, 56);
1971 memset(p, 0, count - 8);
1975 ((uint32_t *) ctx->
in)[14] = ctx->
bits[0];
1976 ((uint32_t *) ctx->
in)[15] = ctx->
bits[1];
1980 memcpy(digest, ctx->
buf, 16);
1981 memset((
char *) ctx, 0,
sizeof(ctx));
1987 static void bin2str(
char *to,
const unsigned char *p,
size_t len) {
1988 static const char *hex =
"0123456789abcdef";
1990 for (; len--; p++) {
1991 *to++ = hex[p[0] >> 4];
1992 *to++ = hex[p[0] & 0x0f];
1999 unsigned char hash[16];
2007 while ((p = va_arg(ap,
const char *)) != NULL) {
2008 MD5Update(&ctx, (
const unsigned char *) p, (
unsigned) strlen(p));
2013 bin2str(buf, hash,
sizeof(hash));
2018 const char *nonce,
const char *nc,
const char *cnonce,
2019 const char *qop,
const char *response) {
2020 char ha2[32 + 1], expected_response[32 + 1];
2023 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
2024 qop == NULL || response == NULL) {
2031 strlen(response) != 32
2037 mg_md5(ha2, method,
":", uri, NULL);
2038 mg_md5(expected_response, ha1,
":", nonce,
":", nc,
2039 ":", cnonce,
":", qop,
":", ha2, NULL);
2048 char name[PATH_MAX];
2057 cry(
fc(ctx),
"fopen(%s): %s",
2060 (void)
mg_snprintf(conn, name,
sizeof(name),
"%s%c%s",
2065 for (p = path, e = p + strlen(p) - 1; e > p; e--)
2068 (void)
mg_snprintf(conn, name,
sizeof(name),
"%.*s%c%s",
2078 char *
user, *uri, *cnonce, *response, *qop, *nc, *nonce;
2083 char *name, *value, *
s;
2084 const char *auth_header;
2086 if ((auth_header =
mg_get_header(conn,
"Authorization")) == NULL ||
2092 (void)
mg_strlcpy(buf, auth_header + 7, buf_size);
2095 (void) memset(ah, 0,
sizeof(*ah));
2100 while (isspace(* (
unsigned char *) s)) {
2116 if (*name ==
'\0') {
2120 if (!strcmp(name,
"username")) {
2122 }
else if (!strcmp(name,
"cnonce")) {
2124 }
else if (!strcmp(name,
"response")) {
2126 }
else if (!strcmp(name,
"uri")) {
2128 }
else if (!strcmp(name,
"qop")) {
2130 }
else if (!strcmp(name,
"nc")) {
2132 }
else if (!strcmp(name,
"nonce")) {
2138 if (ah->
user != NULL) {
2150 char line[256], f_user[256], ha1[256], f_domain[256],
buf[BUFSIZ];
2157 while (fgets(line,
sizeof(line), fp) != NULL) {
2158 if (sscanf(line,
"%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
2162 if (!strcmp(ah.
user, f_user) &&
2176 char fname[PATH_MAX];
2177 struct vec uri_vec, filename_vec;
2185 while ((list =
next_option(list, &uri_vec, &filename_vec)) != NULL) {
2187 (void)
mg_snprintf(conn, fname,
sizeof(fname),
"%.*s",
2188 filename_vec.
len, filename_vec.
ptr);
2189 if ((fp =
mg_fopen(fname,
"r")) == NULL) {
2190 cry(conn,
"%s: cannot open %s: %s", __func__, fname, strerror(errno));
2211 "HTTP/1.1 401 Unauthorized\r\n" 2212 "WWW-Authenticate: Digest qop=\"auth\", " 2213 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
2215 (
unsigned long) time(NULL));
2234 const char *user,
const char *pass) {
2236 char line[512], u[512],
d[512], ha1[33], tmp[PATH_MAX];
2245 if (pass[0] ==
'\0') {
2249 (void) snprintf(tmp,
sizeof(tmp),
"%s.tmp", fname);
2252 if ((fp =
mg_fopen(fname,
"a+")) != NULL) {
2257 if ((fp =
mg_fopen(fname,
"r")) == NULL) {
2258 cry(
fc(ctx),
"Cannot open %s: %s", fname, strerror(errno));
2260 }
else if ((fp2 =
mg_fopen(tmp,
"w+")) == NULL) {
2261 cry(
fc(ctx),
"Cannot open %s: %s", tmp, strerror(errno));
2266 while (fgets(line,
sizeof(line), fp) != NULL) {
2267 if (sscanf(line,
"%[^:]:%[^:]:%*s", u, d) != 2) {
2271 if (!strcmp(u, user) && !strcmp(d, domain)) {
2274 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
2275 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
2278 (void) fprintf(fp2,
"%s", line);
2283 if (!found && pass != NULL) {
2284 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
2285 (void) fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
2305 static void url_encode(
const char *src,
char *dst,
size_t dst_len) {
2306 static const char *dont_escape =
"._-$,;~()";
2307 static const char *hex =
"0123456789abcdef";
2308 const char *end = dst + dst_len - 1;
2310 for (; *src !=
'\0' && dst < end; src++, dst++) {
2311 if (isalnum(*(
const unsigned char *) src) ||
2312 strchr(dont_escape, * (
const unsigned char *) src) != NULL) {
2314 }
else if (dst + 2 < end) {
2316 dst[1] = hex[(* (
const unsigned char *) src) >> 4];
2317 dst[2] = hex[(* (
const unsigned char *) src) & 0xf];
2326 char size[64], mod[64], href[PATH_MAX];
2329 (void)
mg_snprintf(de->
conn, size,
sizeof(size),
"%s",
"[DIRECTORY]");
2333 if (de->
st.
size < 1024) {
2335 "%lu", (
unsigned long) de->
st.
size);
2336 }
else if (de->
st.
size < 1024 * 1024) {
2338 "%.1fk", (double) de->
st.
size / 1024.0);
2339 }
else if (de->
st.
size < 1024 * 1024 * 1024) {
2341 "%.1fM", (double) de->
st.
size / 1048576);
2344 "%.1fG", (double) de->
st.
size / 1073741824);
2347 (void) strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M", localtime(&de->
st.
mtime));
2350 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>" 2351 "<td> %s</td><td> %s</td></tr>\n",
2361 const struct de *a = (
const struct de *) p1, *b = (
const struct de *) p2;
2365 if (query_string == NULL) {
2366 query_string =
"na";
2373 }
else if (*query_string ==
'n') {
2374 cmp_result = strcmp(a->
file_name, b->file_name);
2375 }
else if (*query_string ==
's') {
2376 cmp_result = a->
st.
size == b->st.size ? 0 :
2377 a->
st.
size > b->st.size ? 1 : -1;
2378 }
else if (*query_string ==
'd') {
2379 cmp_result = a->
st.
mtime == b->st.mtime ? 0 :
2380 a->
st.
mtime > b->st.mtime ? 1 : -1;
2383 return query_string[1] ==
'd' ? -cmp_result : cmp_result;
2390 struct de *entries = NULL;
2391 char path[PATH_MAX];
2392 int i, sort_direction, num_entries = 0, arr_size = 128;
2394 if ((dirp = opendir(dir)) == NULL) {
2396 "Error: opendir(%s): %s", path, strerror(
ERRNO));
2401 "HTTP/1.1 200 OK\r\n" 2402 "Connection: close\r\n" 2403 "Content-Type: text/html; charset=utf-8\r\n\r\n");
2408 while ((dp = readdir(dirp)) != NULL) {
2411 if (!strcmp(dp->d_name,
".") ||
2412 !strcmp(dp->d_name,
"..") ||
2416 if (entries == NULL || num_entries >= arr_size) {
2418 entries = (
struct de *) realloc(entries,
2419 arr_size *
sizeof(entries[0]));
2422 if (entries == NULL) {
2424 "%s",
"Error: cannot allocate memory");
2435 if (
mg_stat(path, &entries[num_entries].st) != 0) {
2436 memset(&entries[num_entries].st, 0,
sizeof(entries[num_entries].st));
2443 (void) closedir(dirp);
2446 "<html><head><title>Index of %s</title>" 2447 "<style>th {text-align: left;}</style></head>" 2448 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">" 2449 "<tr><th><a href=\"?n%c\">Name</a></th>" 2450 "<th><a href=\"?d%c\">Modified</a></th>" 2451 "<th><a href=\"?s%c\">Size</a></th></tr>" 2452 "<tr><td colspan=\"3\"><hr></td></tr>",
2454 sort_direction, sort_direction, sort_direction);
2458 "<tr><td><a href=\"%s%s\">%s</a></td>" 2459 "<td> %s</td><td> %s</td></tr>\n",
2464 for (i = 0; i < num_entries; i++) {
2477 int to_read, num_read, num_written;
2481 to_read =
sizeof(
buf);
2482 if ((int64_t) to_read > len)
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)
2505 char date[64], lm[64], etag[64], range[64];
2506 const char *fmt =
"%a, %d %b %Y %H:%M:%S %Z", *msg =
"OK", *hdr;
2507 time_t curtime = time(NULL);
2509 struct vec mime_vec;
2518 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
2520 "fopen(%s): %s", path, strerror(
ERRNO));
2530 (void) fseeko(fp, (off_t) r1, SEEK_SET);
2531 cl = n == 2 ? r2 - r1 + 1: cl - r1;
2533 "Content-Range: bytes " 2536 r1, r1 + cl - 1, stp->
size);
2537 msg =
"Partial Content";
2541 (void) strftime(date,
sizeof(date), fmt, localtime(&curtime));
2542 (void) strftime(lm,
sizeof(lm), fmt, localtime(&stp->
mtime));
2543 (void)
mg_snprintf(conn, etag,
sizeof(etag),
"%lx.%lx",
2544 (
unsigned long) stp->
mtime, (
unsigned long) stp->
size);
2547 "HTTP/1.1 %d %s\r\n" 2549 "Last-Modified: %s\r\n" 2551 "Content-Type: %.*s\r\n" 2553 "Connection: %s\r\n" 2554 "Accept-Ranges: bytes\r\n" 2580 return !strcmp(method,
"GET") || !strcmp(method,
"POST") ||
2581 !strcmp(method,
"HEAD") || !strcmp(method,
"CONNECT") ||
2582 !strcmp(method,
"PUT") || !strcmp(method,
"DELETE");
2590 while (*buf !=
'\0' && isspace(* (
unsigned char *) buf)) {
2618 while (*nread < bufsiz && request_len == 0) {
2619 n =
pull(fp, sock, ssl, buf + *nread, bufsiz - *nread);
2635 size_t path_len,
struct mgstat *stp) {
2638 struct vec filename_vec;
2639 size_t n = strlen(path);
2652 while ((list =
next_option(list, &filename_vec, NULL)) != NULL) {
2655 if (filename_vec.
len > path_len - n)
2662 if (
mg_stat(path, &st) == 0) {
2680 const struct mgstat *stp) {
2687 const char *expect, *buffered;
2689 int to_read, nread, buffered_len, success = 0;
2696 }
else if (expect != NULL &&
mg_strcasecmp(expect,
"100-continue")) {
2699 if (expect != NULL) {
2700 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
2705 assert(buffered_len >= 0);
2708 if (buffered_len > 0) {
2712 push(fp, sock, ssl, buffered, (int64_t) buffered_len);
2717 to_read =
sizeof(
buf);
2722 if (nread <= 0 ||
push(fp, sock, ssl, buf, nread) != nread) {
2741 #if !defined(NO_CGI) 2766 space =
sizeof(block->
buf) - block->
len - 2;
2770 added = block->
buf + block->
len;
2778 if (n > 0 && n < space &&
2783 block->
len += n + 1;
2792 const char *
s, *slash;
2793 struct vec var_vec, root;
2807 addenv(blk,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
2808 addenv(blk,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
2809 addenv(blk,
"%s",
"REDIRECT_STATUS=200");
2812 addenv(blk,
"REMOTE_ADDR=%s",
2820 if ((s = strrchr(prog,
'/')) == NULL)
2825 addenv(blk,
"SCRIPT_FILENAME=%s", prog);
2826 addenv(blk,
"PATH_TRANSLATED=%s", prog);
2827 addenv(blk,
"HTTPS=%s", conn->
ssl == NULL ?
"off" :
"on");
2830 addenv(blk,
"CONTENT_TYPE=%s", s);
2836 addenv(blk,
"CONTENT_LENGTH=%s", s);
2838 if ((s = getenv(
"PATH")) != NULL)
2839 addenv(blk,
"PATH=%s", s);
2842 if ((s = getenv(
"COMSPEC")) != NULL)
2843 addenv(blk,
"COMSPEC=%s", s);
2844 if ((s = getenv(
"SYSTEMROOT")) != NULL)
2845 addenv(blk,
"SYSTEMROOT=%s", s);
2847 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL)
2848 addenv(blk,
"LD_LIBRARY_PATH=%s", s);
2851 if ((s = getenv(
"PERLLIB")) != NULL)
2852 addenv(blk,
"PERLLIB=%s", s);
2856 addenv(blk,
"%s",
"AUTH_TYPE=Digest");
2861 p =
addenv(blk,
"HTTP_%s=%s",
2866 for (; *p !=
'=' && *p !=
'\0'; p++) {
2869 *p = (char) toupper(* (
unsigned char *) p);
2875 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
2880 blk->
buf[blk->
len++] =
'\0';
2883 assert(blk->
len > 0);
2884 assert(blk->
len < (
int)
sizeof(blk->
buf));
2888 int headers_len,
data_len, i, fd_stdin[2], fd_stdout[2];
2890 char buf[BUFSIZ], *pbuf, dir[PATH_MAX], *p;
2901 (void)
mg_snprintf(conn, dir,
sizeof(dir),
"%s", prog);
2902 if ((p = strrchr(dir,
DIRSEP)) != NULL) {
2905 dir[0] =
'.', dir[1] =
'\0';
2910 fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
2913 if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
2915 "Cannot create CGI pipe: %s", strerror(
ERRNO));
2918 fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
2920 }
else if ((in = fdopen(fd_stdin[1],
"wb")) == NULL ||
2921 (out = fdopen(fd_stdout[0],
"rb")) == NULL) {
2923 "fopen: %s", strerror(
ERRNO));
2934 fd_stdin[0] = fd_stdout[1] = -1;
2948 buf,
sizeof(buf), &data_len);
2949 if (headers_len <= 0) {
2951 "CGI program sent malformed HTTP headers: [%.*s]",
2956 buf[headers_len - 1] =
'\0';
2973 (
size_t)(data_len - headers_len));
2979 if (pid != (pid_t) -1) {
2981 #if !defined(_WIN32) 2982 do {}
while (waitpid(-1, &i, WNOHANG) > 0);
2985 if (fd_stdin[0] != -1) {
2986 (void) close(fd_stdin[0]);
2988 if (fd_stdout[1] != -1) {
2989 (void) close(fd_stdout[1]);
2994 }
else if (fd_stdin[1] != -1) {
2995 (void) close(fd_stdin[1]);
3000 }
else if (fd_stdout[0] != -1) {
3001 (void) close(fd_stdout[0]);
3015 for (s = p = path + 2; (p = strchr(s,
'/')) != NULL; s = ++p) {
3017 assert(len <
sizeof(buf));
3018 (void) memcpy(buf, path, len);
3044 if ((rc =
put_dir(path)) == 0) {
3046 }
else if (rc == -1) {
3048 "put_dir(%s): %s", path, strerror(
ERRNO));
3049 }
else if ((fp =
mg_fopen(path,
"wb+")) == NULL) {
3051 "fopen(%s): %s", path, strerror(
ERRNO));
3059 (void) fseeko(fp, (off_t) r1, SEEK_SET);
3062 (
void)
mg_printf(conn,
"HTTP/1.1 %d OK\r\n\r\n",
3071 char *tag,
int include_level) {
3072 char file_name[BUFSIZ], path[PATH_MAX], *p;
3081 if (sscanf(tag,
" virtual=\"%[^\"]\"", file_name) == 1) {
3083 (void)
mg_snprintf(conn, path,
sizeof(path),
"%.*s%c%s",
3085 }
else if (sscanf(tag,
" file=\"%[^\"]\"", file_name) == 1) {
3088 (void)
mg_snprintf(conn, path,
sizeof(path),
"%s", file_name);
3089 }
else if (sscanf(tag,
" \"%[^\"]\"", file_name) == 1) {
3091 (void)
mg_snprintf(conn, path,
sizeof(path),
"%s", ssi);
3092 if ((p = strrchr(path,
DIRSEP)) != NULL) {
3096 sizeof(path) - strlen(path),
"%s", file_name);
3098 cry(conn,
"Bad SSI #include: [%s]", tag);
3102 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
3103 cry(conn,
"Cannot open SSI #include: [%s]: fopen(%s): %s",
3104 tag, path, strerror(
ERRNO));
3117 #if !defined(NO_POPEN) 3122 if (sscanf(tag,
" \"%[^\"]\"", cmd) != 1) {
3123 cry(conn,
"Bad SSI #exec: [%s]", tag);
3124 }
else if ((fp = popen(cmd,
"r")) == NULL) {
3125 cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
3134 FILE *fp,
int include_level) {
3136 int ch,
len, in_ssi_tag;
3138 if (include_level > 10) {
3139 cry(conn,
"SSI #include level is too deep (%s)", path);
3146 while ((ch = fgetc(fp)) != EOF) {
3147 if (in_ssi_tag && ch ==
'>') {
3149 buf[len++] = (char) ch;
3151 assert(len <= (
int)
sizeof(buf));
3152 if (len < 6 || memcmp(buf,
"<!--#", 5) != 0) {
3156 if (!memcmp(buf + 5,
"include", 7)) {
3158 #if !defined(NO_POPEN) 3159 }
else if (!memcmp(buf + 5,
"exec", 4)) {
3163 cry(conn,
"%s: unknown SSI " "command: \"%s\"", path, buf);
3167 }
else if (in_ssi_tag) {
3168 if (len == 5 && memcmp(buf,
"<!--#", 5) != 0) {
3171 }
else if (len == (
int)
sizeof(buf) - 2) {
3172 cry(conn,
"%s: SSI tag is too large", path);
3175 buf[len++] = ch & 0xff;
3176 }
else if (ch ==
'<') {
3182 buf[len++] = ch & 0xff;
3184 buf[len++] = ch & 0xff;
3185 if (len == (
int)
sizeof(
buf)) {
3202 if ((fp =
mg_fopen(path,
"rb")) == NULL) {
3208 "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
3221 char path[PATH_MAX];
3228 uri_len = strlen(ri->
uri);
3229 (void)
url_decode(ri->
uri, (
size_t)uri_len, ri->
uri, (size_t)(uri_len + 1), 0);
3257 }
else if (
mg_stat(path, &st) != 0) {
3261 "HTTP/1.1 301 Moved Permanently\r\n" 3262 "Location: %s/\r\n\r\n", ri->
uri);
3269 "Directory listing denied");
3301 int a, b, c,
d, port,
len;
3304 memset(so, 0,
sizeof(*so));
3306 if (sscanf(vec->
ptr,
"%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
3308 usa->
u.
sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
3309 }
else if (sscanf(vec->
ptr,
"%d%n", &port, &len) == 1) {
3311 usa->
u.
sin.sin_addr.s_addr = htonl(INADDR_ANY);
3315 assert(len > 0 && len <= (
int) vec->
len);
3317 if (strchr(
"sp,", vec->
ptr[len]) == NULL) {
3323 usa->
len =
sizeof(usa->
u.
sin);
3324 usa->
u.
sin.sin_family = AF_INET;
3325 usa->
u.
sin.sin_port = htons((uint16_t) port);
3332 int reuseaddr = 1, success = 1;
3335 struct socket so, *listener;
3337 while (success && (list =
next_option(list, &vec, NULL)) != NULL) {
3339 cry(
fc(ctx),
"%s: %.*s: invalid port spec. Expecting list of: %s",
3340 __func__, vec.
len, vec.
ptr,
"[IP_ADDRESS:]PORT[s|p]");
3343 cry(
fc(ctx),
"Cannot add SSL socket, is -ssl_cert option set?");
3346 #
if !defined(_WIN32)
3349 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
3350 sizeof(reuseaddr)) != 0 ||
3353 listen(sock, 20) != 0) {
3355 cry(
fc(ctx),
"%s: cannot bind to %.*s: %s", __func__,
3358 }
else if ((listener = calloc(1,
sizeof(*listener))) == NULL) {
3360 cry(
fc(ctx),
"%s: %s", __func__, strerror(
ERRNO));
3380 const char *header_value;
3383 (void) fprintf(fp,
"%s",
" -");
3385 (void) fprintf(fp,
" \"%s\"", header_value);
3400 (void) strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z",
3408 "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
3418 (void) fputc(
'\n', fp);
3426 return n >= 0 && n <= 255;
3432 int a, b, c,
d, n, mask, allowed;
3434 uint32_t acl_subnet, acl_mask,
remote_ip;
3442 (void) memcpy(&remote_ip, &usa->
u.
sin.sin_addr,
sizeof(remote_ip));
3447 while ((list =
next_option(list, &vec, NULL)) != NULL) {
3450 if (sscanf(vec.
ptr,
"%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) {
3451 cry(
fc(ctx),
"%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
3453 }
else if (flag !=
'+' && flag !=
'-') {
3454 cry(
fc(ctx),
"%s: flag must be + or -: [%s]", __func__, vec.
ptr);
3457 cry(
fc(ctx),
"%s: bad ip address: [%s]", __func__, vec.
ptr);
3459 }
else if (sscanf(vec.
ptr + n,
"/%d", &mask) == 0) {
3461 }
else if (mask < 0 || mask > 32) {
3462 cry(
fc(ctx),
"%s: bad subnet mask: %d [%s]", __func__, n, vec.
ptr);
3466 acl_subnet = (a << 24) | (b << 16) | (c << 8) | d;
3467 acl_mask = mask ? 0xffffffffU << (32 - mask) : 0;
3469 if (acl_subnet == (ntohl(remote_ip) & acl_mask)) {
3474 return allowed ==
'+';
3479 if (fd > (
SOCKET) *max_fd) {
3484 #if !defined(_WIN32) 3493 if ((pw = getpwnam(uid)) == NULL) {
3494 cry(
fc(ctx),
"%s: unknown user [%s]", __func__, uid);
3495 }
else if (setgid(pw->pw_gid) == -1) {
3496 cry(
fc(ctx),
"%s: setgid(%s): %s", __func__, uid, strerror(errno));
3497 }
else if (setuid(pw->pw_uid) == -1) {
3498 cry(
fc(ctx),
"%s: setuid(%s): %s", __func__, uid, strerror(errno));
3508 #if !defined(NO_SSL) 3517 (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
3519 (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
3524 return (
unsigned long) pthread_self();
3527 #if !defined(NO_SSL_DL) 3530 union {
void *p; void (*fp)(void);} u;
3534 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
3535 cry(
fc(ctx),
"%s: cannot load %s", __func__, dll_name);
3539 for (fp = sw; fp->
name != NULL; fp++) {
3542 u.fp = (void (*)(void)) dlsym(dll_handle, fp->
name);
3546 u.p = dlsym(dll_handle, fp->
name);
3549 cry(
fc(ctx),
"%s: %s: cannot find %s", __func__, dll_name, fp->
name);
3571 #if !defined(NO_SSL_DL) 3590 cry(
fc(ctx),
"%s: cannot open %s: %s", __func__, pem,
ssl_error());
3598 if (CTX != NULL && chain != NULL &&
3600 cry(
fc(ctx),
"%s: cannot open %s: %s", NULL, chain,
ssl_error());
3607 if ((ssl_mutexes = (pthread_mutex_t *) malloc((
size_t)size)) == NULL) {
3608 cry(
fc(ctx),
"%s: cannot allocate mutexes: %s", __func__,
ssl_error());
3613 pthread_mutex_init(&ssl_mutexes[i], NULL);
3629 return path == NULL ||
mg_stat(path, &mgstat) == 0;
3658 (void) shutdown(sock, SHUT_WR);
3667 n =
pull(NULL, sock, NULL, buf,
sizeof(buf));
3687 int buffered_len, body_len;
3691 assert(buffered_len >= 0);
3695 }
else if (conn->
content_len < (int64_t) buffered_len) {
3698 body_len = buffered_len;
3705 static int parse_url(
const char *url,
char *host,
int *port) {
3712 if (!strncmp(url,
"http://", 7)) {
3716 if (sscanf(url,
"%1024[^:]:%d/%n", host, port, &len) == 2) {
3718 sscanf(url,
"%1024[^/]/%n", host, &len);
3723 return len > 0 && url[len - 1] ==
'/' ? len - 1 : len;
3728 char host[1025],
buf[BUFSIZ];
3729 int port,
is_ssl, len, i, n;
3737 if (conn->
peer == NULL) {
3739 if ((conn->
peer =
mg_connect(conn, host, port, is_ssl)) == NULL) {
3764 buf,
sizeof(buf))) > 0) {
3765 if (
mg_write(conn, buf, (
size_t)n) != n) {
3780 return (uri[0] ==
'/' || (uri[0] ==
'*' && uri[1] ==
'\0'));
3785 int keep_alive_enabled;
3812 "Cannot parse HTTP request: [%.*s]", conn->
data_len, conn->
buf);
3821 conn->
content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10);
3837 (void) pthread_mutex_lock(&ctx->
mutex);
3847 (void) pthread_mutex_unlock(&ctx->
mutex);
3863 (void) pthread_cond_signal(&ctx->
sq_empty);
3864 (void) pthread_mutex_unlock(&ctx->
mutex);
3873 conn = calloc(1,
sizeof(*conn) + buf_size);
3875 conn->
buf = (
char *) (conn + 1);
3876 assert(conn != NULL);
3878 (void) pthread_mutex_lock(&ctx->
mutex);
3880 (void) pthread_mutex_unlock(&ctx->
mutex);
3883 (void) pthread_mutex_lock(&ctx->
mutex);
3888 cry(
fc(ctx),
"Cannot start extra worker thread: %d",
ERRNO);
3893 (void) pthread_mutex_unlock(&ctx->
mutex);
3914 (void) pthread_mutex_lock(&ctx->
mutex);
3917 (void) pthread_mutex_unlock(&ctx->
mutex);
3920 (void) pthread_mutex_unlock(&ctx->
mutex);
3925 (void) pthread_mutex_lock(&ctx->
mutex);
3928 (void) pthread_cond_signal(&ctx->
cond);
3931 (void) pthread_mutex_unlock(&ctx->
mutex);
3938 (void) pthread_mutex_lock(&ctx->
mutex);
3951 (void) pthread_cond_signal(&ctx->
sq_full);
3952 (void) pthread_mutex_unlock(&ctx->
mutex);
3961 accepted.
lsa = listener->
lsa;
3972 cry(
fc(ctx),
"%s: %s is not allowed to connect",
3973 __func__, inet_ntoa(accepted.
rsa.
u.
sin.sin_addr));
3995 tv.tv_usec = 200 * 1000;
3997 if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
4006 if (FD_ISSET(sp->
sock, &read_set)) {
4018 pthread_cond_broadcast(&ctx->
sq_full);
4021 (void) pthread_mutex_lock(&ctx->
mutex);
4023 (void) pthread_cond_wait(&ctx->
cond, &ctx->
mutex);
4025 (void) pthread_mutex_unlock(&ctx->
mutex);
4028 (void) pthread_mutex_destroy(&ctx->
mutex);
4029 (void) pthread_cond_destroy(&ctx->
cond);
4030 (void) pthread_cond_destroy(&ctx->
sq_empty);
4031 (void) pthread_cond_destroy(&ctx->
sq_full);
4044 if (ctx->
config[i] != NULL)
4053 if (ssl_mutexes != NULL) {
4072 (void) WSACleanup();
4077 const char **options) {
4084 WSAStartup(MAKEWORD(2,2), &data);
4089 ctx = calloc(1,
sizeof(*ctx));
4093 while (options && (name = *options++) != NULL) {
4095 cry(
fc(ctx),
"Invalid option: %s", name);
4098 }
else if ((value = *options++) == NULL) {
4099 cry(
fc(ctx),
"%s: option value cannot be NULL", name);
4110 if (ctx->
config[i] == NULL && default_value != NULL) {
4128 #
if !defined(NO_SSL)
4132 #
if !defined(_WIN32)
4140 #if !defined(_WIN32) 4143 (void) signal(SIGPIPE, SIG_IGN);
4146 (void) pthread_mutex_init(&ctx->
mutex, NULL);
4147 (void) pthread_cond_init(&ctx->
cond, NULL);
4148 (void) pthread_cond_init(&ctx->
sq_empty, NULL);
4149 (void) pthread_cond_init(&ctx->
sq_full, NULL);
4157 cry(
fc(ctx),
"Cannot start worker thread: %d",
ERRNO);
static int set_non_blocking_mode(SOCKET sock)
static time_t parse_date_string(const char *s)
static void send_http_error(struct mg_connection *conn, int status, const char *reason, const char *fmt,...)
void *(* mg_thread_func_t)(void *)
static const char * ssl_error(void)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
static void put_file(struct mg_connection *conn, const char *path)
struct mg_request_info request_info
static void handle_directory_request(struct mg_connection *conn, const char *dir)
static void url_encode(const char *src, char *dst, size_t dst_len)
char buf[CGI_ENVIRONMENT_SIZE]
static void cry(struct mg_connection *conn, const char *fmt,...)
#define MAX_CGI_ENVIR_VARS
static char * addenv(struct cgi_env_block *block, const char *fmt,...)
static void convert_uri_to_file_name(struct mg_connection *conn, const char *uri, char *buf, size_t buf_len)
struct mg_connection * conn
static int get_option_index(const char *name)
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 log_header(const struct mg_connection *conn, const char *header, FILE *fp)
#define CGI_ENVIRONMENT_SIZE
static void remove_double_dots_and_double_slashes(char *s)
static int lowercase(const char *s)
static void parse_http_headers(char **buf, struct mg_request_info *ri)
static int set_ports_option(struct mg_context *ctx)
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
static int parse_http_request(char *buf, struct mg_request_info *ri)
static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt,...)
static int mg_strncasecmp(const char *s1, const char *s2, size_t len)
static void log_access(const struct mg_connection *conn)
static char * mg_strndup(const char *ptr, size_t len)
const char * mg_version(void)
static void free_context(struct mg_context *ctx)
static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
static int sslize(struct mg_connection *conn, int(*func)(SSL *))
static int match_extension(const char *path, const char *ext_list)
#define SSL_CTX_use_certificate_file
static int set_gpass_option(struct mg_context *ctx)
void mg_stop(struct mg_context *ctx)
struct mg_request_info::mg_header http_headers[64]
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
struct mg_context * mg_start(mg_callback_t user_callback, void *user_data, const char **options)
static const char * config_options[]
static int set_ssl_option(struct mg_context *ctx)
void *(* mg_callback_t)(enum mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info)
static pthread_mutex_t * ssl_mutexes
static int parse_url(const char *url, char *host, int *port)
static void add_to_set(SOCKET fd, fd_set *set, int *max_fd)
static unsigned long ssl_id_callback(void)
static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz, int *nread)
static int mg_strcasecmp(const char *s1, const char *s2)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
static void close_connection(struct mg_connection *conn)
int mg_get_var(const char *buf, size_t buf_len, const char *name, char *dst, size_t dst_len)
#define ENTRIES_PER_CONFIG_OPTION
const char ** mg_get_valid_option_names(void)
static void byteReverse(unsigned char *buf, unsigned longs)
static int is_not_modified(const struct mg_connection *conn, const struct mgstat *stp)
#define SSL_CTX_use_certificate_chain_file
static int check_authorization(struct mg_connection *conn, const char *path)
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
static const char * month_names[]
static void MD5Init(MD5_CTX *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)
#define SSLv23_server_method
#define IS_DIRSEP_CHAR(c)
static const char * get_header(const struct mg_request_info *ri, const char *name)
static void discard_current_request_from_buffer(struct mg_connection *conn)
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static int should_keep_alive(const struct mg_connection *conn)
static void process_new_connection(struct mg_connection *conn)
static void * call_user(struct mg_connection *conn, enum mg_event event)
static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, va_list ap)
static char * mg_strdup(const char *str)
#define MD5STEP(f, w, x, y, z, data, s)
struct socket * listening_sockets
mg_callback_t user_callback
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
static void master_thread(struct mg_context *ctx)
static struct ssl_func ssl_sw[]
static int is_authorized_for_put(struct mg_connection *conn)
int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, char *dst, size_t dst_size)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
int mg_read(struct mg_connection *conn, void *buf, size_t len)
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
const char * mg_get_header(const struct mg_connection *conn, const char *name)
static const char * http_500_error
static void close_socket_gracefully(SOCKET sock)
static int is_valid_http_method(const char *method)
int mg_modify_passwords_file(struct mg_context *ctx, const char *fname, const char *user, const char *pass)
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)
#define SSL_CTX_use_PrivateKey_file
struct ssl_method_st SSL_METHOD
static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
static void set_close_on_exec(int fd)
const char * mg_get_option(const struct mg_context *ctx, const char *name)
struct mg_connection * conn
static int get_document_root(const struct mg_connection *conn, struct vec *document_root)
static int get_request_len(const char *buf, int buflen)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
char * vars[MAX_CGI_ENVIR_VARS]
static int consume_socket(struct mg_context *ctx, struct socket *sp)
static void bin2str(char *to, const unsigned char *p, size_t len)
static int month_number_to_month_name(const char *s)
static struct mg_connection * fc(struct mg_context *ctx)
char * config[NUM_OPTIONS]
#define ARRAY_SIZE(array)
#define SSL_CTX_set_default_passwd_cb
static void print_dir_entry(struct de *de)
#define CRYPTO_set_id_callback
static void worker_thread(struct mg_context *ctx)
struct mg_connection * peer
struct ssl_ctx_st SSL_CTX
static char * skip(char **buf, const char *delimiters)
#define PASSWORDS_FILE_NAME
#define SSL_load_error_strings
static int set_acl_option(struct mg_context *ctx)
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
static const struct @1 builtin_mime_types[]
static size_t url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, int is_form_url_encoded)
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mgstat *stp)
static int set_uid_option(struct mg_context *ctx)
static struct ssl_func crypto_sw[]
static int mg_stat(const char *path, struct mgstat *stp)
static int is_valid_uri(const char *uri)
static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len)
static void close_all_listening_sockets(struct mg_context *ctx)
static void do_ssi_exec(struct mg_connection *conn, char *tag)
static void reset_per_request_attributes(struct mg_connection *conn)
static void handle_proxy_request(struct mg_connection *conn)
static int start_thread(struct mg_context *ctx, mg_thread_func_t func, void *param)
static int load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
static void MD5Final(unsigned char digest[16], MD5_CTX *ctx)
static FILE * open_auth_file(struct mg_connection *conn, const char *path)
void mg_md5(char *buf,...)
struct MD5Context MD5_CTX
static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_env_block *blk)
static struct mg_connection * mg_connect(struct mg_connection *conn, const char *host, int port, int use_ssl)
static int check_acl(struct mg_context *ctx, const struct usa *usa)
static int put_dir(const char *path)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path)
static void send_authorization_request(struct mg_connection *conn)
static void send_ssi_file(struct mg_connection *, const char *, FILE *, int)
static int parse_port_string(const struct vec *vec, struct socket *so)
static const char * suggest_connection_header(const struct mg_connection *conn)
static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len)
#define CRYPTO_set_locking_callback
static void handle_request(struct mg_connection *conn)