$search
00001 // Copyright (c) 2004-2010 Sergey Lyubka 00002 // 00003 // Permission is hereby granted, free of charge, to any person obtaining a copy 00004 // of this software and associated documentation files (the "Software"), to deal 00005 // in the Software without restriction, including without limitation the rights 00006 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00007 // copies of the Software, and to permit persons to whom the Software is 00008 // furnished to do so, subject to the following conditions: 00009 // 00010 // The above copyright notice and this permission notice shall be included in 00011 // all copies or substantial portions of the Software. 00012 // 00013 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00014 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00015 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00016 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00017 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00018 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00019 // THE SOFTWARE. 00020 00021 #if defined(_WIN32) 00022 #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 00023 #else 00024 #define _XOPEN_SOURCE 600 // For flockfile() on Linux 00025 #define _LARGEFILE_SOURCE // Enable 64-bit file offsets 00026 #endif 00027 00028 #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE 00029 #include <sys/types.h> 00030 #include <sys/stat.h> 00031 #include <errno.h> 00032 #include <signal.h> 00033 #include <fcntl.h> 00034 #endif // !_WIN32_WCE 00035 00036 #include <time.h> 00037 #include <stdlib.h> 00038 #include <stdarg.h> 00039 #include <assert.h> 00040 #include <string.h> 00041 #include <ctype.h> 00042 #include <limits.h> 00043 #include <stddef.h> 00044 #include <stdio.h> 00045 00046 #if defined(_WIN32) // Windows specific #includes and #defines 00047 #define _WIN32_WINNT 0x0400 // To make it link in VS2005 00048 #include <windows.h> 00049 00050 #ifndef PATH_MAX 00051 #define PATH_MAX MAX_PATH 00052 #endif 00053 00054 #ifndef _WIN32_WCE 00055 #include <process.h> 00056 #include <direct.h> 00057 #include <io.h> 00058 #else // _WIN32_WCE 00059 #include <winsock2.h> 00060 #define NO_CGI // WinCE has no pipes 00061 00062 typedef long off_t; 00063 #define BUFSIZ 4096 00064 00065 #define errno GetLastError() 00066 #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10) 00067 #endif // _WIN32_WCE 00068 00069 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \ 00070 ((uint64_t)((uint32_t)(hi))) << 32)) 00071 #define RATE_DIFF 10000000 // 100 nsecs 00072 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de) 00073 #define SYS2UNIX_TIME(lo, hi) \ 00074 (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF) 00075 00076 // Visual Studio 6 does not know __func__ or __FUNCTION__ 00077 // The rest of MS compilers use __FUNCTION__, not C99 __func__ 00078 // Also use _strtoui64 on modern M$ compilers 00079 #if defined(_MSC_VER) && _MSC_VER < 1300 00080 #define STRX(x) #x 00081 #define STR(x) STRX(x) 00082 #define __func__ "line " STR(__LINE__) 00083 #define strtoull(x, y, z) strtoul(x, y, z) 00084 #define strtoll(x, y, z) strtol(x, y, z) 00085 #else 00086 #define __func__ __FUNCTION__ 00087 #define strtoull(x, y, z) _strtoui64(x, y, z) 00088 #define strtoll(x, y, z) _strtoi64(x, y, z) 00089 #endif // _MSC_VER 00090 00091 #define ERRNO GetLastError() 00092 #define NO_SOCKLEN_T 00093 #define SSL_LIB "ssleay32.dll" 00094 #define CRYPTO_LIB "libeay32.dll" 00095 #define DIRSEP '\\' 00096 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\') 00097 #define O_NONBLOCK 0 00098 #if !defined(EWOULDBLOCK) 00099 #define EWOULDBLOCK WSAEWOULDBLOCK 00100 #endif // !EWOULDBLOCK 00101 #define _POSIX_ 00102 #define INT64_FMT "I64d" 00103 00104 #define WINCDECL __cdecl 00105 #define SHUT_WR 1 00106 #define snprintf _snprintf 00107 #define vsnprintf _vsnprintf 00108 #define sleep(x) Sleep((x) * 1000) 00109 00110 #define pipe(x) _pipe(x, BUFSIZ, _O_BINARY) 00111 #define popen(x, y) _popen(x, y) 00112 #define pclose(x) _pclose(x) 00113 #define close(x) _close(x) 00114 #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y)) 00115 #define RTLD_LAZY 0 00116 #define fseeko(x, y, z) fseek((x), (y), (z)) 00117 #define fdopen(x, y) _fdopen((x), (y)) 00118 #define write(x, y, z) _write((x), (y), (unsigned) z) 00119 #define read(x, y, z) _read((x), (y), (unsigned) z) 00120 #define flockfile(x) (void) 0 00121 #define funlockfile(x) (void) 0 00122 00123 #if !defined(fileno) 00124 #define fileno(x) _fileno(x) 00125 #endif // !fileno MINGW #defines fileno 00126 00127 typedef HANDLE pthread_mutex_t; 00128 typedef struct {HANDLE signal, broadcast;} pthread_cond_t; 00129 typedef DWORD pthread_t; 00130 #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here. 00131 00132 struct timespec { 00133 long tv_nsec; 00134 long tv_sec; 00135 }; 00136 00137 static int pthread_mutex_lock(pthread_mutex_t *); 00138 static int pthread_mutex_unlock(pthread_mutex_t *); 00139 static FILE *mg_fopen(const char *path, const char *mode); 00140 00141 #if defined(HAVE_STDINT) 00142 #include <stdint.h> 00143 #else 00144 typedef unsigned int uint32_t; 00145 typedef unsigned short uint16_t; 00146 typedef unsigned __int64 uint64_t; 00147 typedef __int64 int64_t; 00148 #define INT64_MAX 9223372036854775807 00149 #endif // HAVE_STDINT 00150 00151 // POSIX dirent interface 00152 struct dirent { 00153 char d_name[PATH_MAX]; 00154 }; 00155 00156 typedef struct DIR { 00157 HANDLE handle; 00158 WIN32_FIND_DATAW info; 00159 struct dirent result; 00160 } DIR; 00161 00162 #else // UNIX specific 00163 #include <sys/wait.h> 00164 #include <sys/socket.h> 00165 #include <sys/select.h> 00166 #include <netinet/in.h> 00167 #include <arpa/inet.h> 00168 #include <sys/time.h> 00169 #include <stdint.h> 00170 #include <inttypes.h> 00171 #include <netdb.h> 00172 00173 #include <pwd.h> 00174 #include <unistd.h> 00175 #include <dirent.h> 00176 #if !defined(NO_SSL_DL) && !defined(NO_SSL) 00177 #include <dlfcn.h> 00178 #endif 00179 #include <pthread.h> 00180 #if defined(__MACH__) 00181 #define SSL_LIB "libssl.dylib" 00182 #define CRYPTO_LIB "libcrypto.dylib" 00183 #else 00184 #if !defined(SSL_LIB) 00185 #define SSL_LIB "libssl.so" 00186 #endif 00187 #if !defined(CRYPTO_LIB) 00188 #define CRYPTO_LIB "libcrypto.so" 00189 #endif 00190 #endif 00191 #define DIRSEP '/' 00192 #define IS_DIRSEP_CHAR(c) ((c) == '/') 00193 #define O_BINARY 0 00194 #define closesocket(a) close(a) 00195 #define mg_fopen(x, y) fopen(x, y) 00196 #define mg_mkdir(x, y) mkdir(x, y) 00197 #define mg_remove(x) remove(x) 00198 #define mg_rename(x, y) rename(x, y) 00199 #define ERRNO errno 00200 #define INVALID_SOCKET (-1) 00201 #define INT64_FMT PRId64 00202 typedef int SOCKET; 00203 #define WINCDECL 00204 00205 #endif // End of Windows and UNIX specific includes 00206 00207 #include "mongoose.h" 00208 00209 #define MONGOOSE_VERSION "3.0" 00210 #define PASSWORDS_FILE_NAME ".htpasswd" 00211 #define CGI_ENVIRONMENT_SIZE 4096 00212 #define MAX_CGI_ENVIR_VARS 64 00213 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) 00214 00215 #if defined(DEBUG) 00216 #define DEBUG_TRACE(x) do { \ 00217 flockfile(stdout); \ 00218 printf("*** %lu.%p.%s.%d: ", \ 00219 (unsigned long) time(NULL), (void *) pthread_self(), \ 00220 __func__, __LINE__); \ 00221 printf x; \ 00222 putchar('\n'); \ 00223 fflush(stdout); \ 00224 funlockfile(stdout); \ 00225 } while (0) 00226 #else 00227 #define DEBUG_TRACE(x) 00228 #endif // DEBUG 00229 00230 // Darwin prior to 7.0 and Win32 do not have socklen_t 00231 #ifdef NO_SOCKLEN_T 00232 typedef int socklen_t; 00233 #endif // NO_SOCKLEN_T 00234 00235 typedef void * (*mg_thread_func_t)(void *); 00236 00237 static const char *http_500_error = "Internal Server Error"; 00238 00239 // Snatched from OpenSSL includes. I put the prototypes here to be independent 00240 // from the OpenSSL source installation. Having this, mongoose + SSL can be 00241 // built on any system with binary SSL libraries installed. 00242 typedef struct ssl_st SSL; 00243 typedef struct ssl_method_st SSL_METHOD; 00244 typedef struct ssl_ctx_st SSL_CTX; 00245 00246 #define SSL_ERROR_WANT_READ 2 00247 #define SSL_ERROR_WANT_WRITE 3 00248 #define SSL_FILETYPE_PEM 1 00249 #define CRYPTO_LOCK 1 00250 00251 #if defined(NO_SSL_DL) 00252 extern void SSL_free(SSL *); 00253 extern int SSL_accept(SSL *); 00254 extern int SSL_connect(SSL *); 00255 extern int SSL_read(SSL *, void *, int); 00256 extern int SSL_write(SSL *, const void *, int); 00257 extern int SSL_get_error(const SSL *, int); 00258 extern int SSL_set_fd(SSL *, int); 00259 extern SSL *SSL_new(SSL_CTX *); 00260 extern SSL_CTX *SSL_CTX_new(SSL_METHOD *); 00261 extern SSL_METHOD *SSLv23_server_method(void); 00262 extern int SSL_library_init(void); 00263 extern void SSL_load_error_strings(void); 00264 extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int); 00265 extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int); 00266 extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *); 00267 extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t); 00268 extern void SSL_CTX_free(SSL_CTX *); 00269 extern unsigned long ERR_get_error(void); 00270 extern char *ERR_error_string(unsigned long, char *); 00271 extern int CRYPTO_num_locks(void); 00272 extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int)); 00273 extern void CRYPTO_set_id_callback(unsigned long (*)(void)); 00274 #else 00275 // Dynamically loaded SSL functionality 00276 struct ssl_func { 00277 const char *name; // SSL function name 00278 void (*ptr)(void); // Function pointer 00279 }; 00280 00281 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr) 00282 #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr) 00283 #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr) 00284 #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr) 00285 #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr) 00286 #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5]) 00287 #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr) 00288 #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr) 00289 #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr) 00290 #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr) 00291 #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr) 00292 #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \ 00293 const char *, int)) ssl_sw[11].ptr) 00294 #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \ 00295 const char *, int)) ssl_sw[12].ptr) 00296 #define SSL_CTX_set_default_passwd_cb \ 00297 (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr) 00298 #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr) 00299 #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr) 00300 #define SSL_CTX_use_certificate_chain_file \ 00301 (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr) 00302 00303 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr) 00304 #define CRYPTO_set_locking_callback \ 00305 (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr) 00306 #define CRYPTO_set_id_callback \ 00307 (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr) 00308 #define ERR_get_error (* (unsigned long (*)(void)) ssl_sw[3].ptr) 00309 #define ERR_error_string (* (char * (*)(unsigned long, char *)) ssl_sw[4].ptr) 00310 00311 // set_ssl_option() function updates this array. 00312 // It loads SSL library dynamically and changes NULLs to the actual addresses 00313 // of respective functions. The macros above (like SSL_connect()) are really 00314 // just calling these functions indirectly via the pointer. 00315 static struct ssl_func ssl_sw[] = { 00316 {"SSL_free", NULL}, 00317 {"SSL_accept", NULL}, 00318 {"SSL_connect", NULL}, 00319 {"SSL_read", NULL}, 00320 {"SSL_write", NULL}, 00321 {"SSL_get_error", NULL}, 00322 {"SSL_set_fd", NULL}, 00323 {"SSL_new", NULL}, 00324 {"SSL_CTX_new", NULL}, 00325 {"SSLv23_server_method", NULL}, 00326 {"SSL_library_init", NULL}, 00327 {"SSL_CTX_use_PrivateKey_file", NULL}, 00328 {"SSL_CTX_use_certificate_file",NULL}, 00329 {"SSL_CTX_set_default_passwd_cb",NULL}, 00330 {"SSL_CTX_free", NULL}, 00331 {"SSL_load_error_strings", NULL}, 00332 {"SSL_CTX_use_certificate_chain_file", NULL}, 00333 {NULL, NULL} 00334 }; 00335 00336 // Similar array as ssl_sw. These functions could be located in different lib. 00337 static struct ssl_func crypto_sw[] = { 00338 {"CRYPTO_num_locks", NULL}, 00339 {"CRYPTO_set_locking_callback", NULL}, 00340 {"CRYPTO_set_id_callback", NULL}, 00341 {"ERR_get_error", NULL}, 00342 {"ERR_error_string", NULL}, 00343 {NULL, NULL} 00344 }; 00345 #endif // NO_SSL_DL 00346 00347 static const char *month_names[] = { 00348 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 00349 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 00350 }; 00351 00352 // Unified socket address. For IPv6 support, add IPv6 address structure 00353 // in the union u. 00354 struct usa { 00355 socklen_t len; 00356 union { 00357 struct sockaddr sa; 00358 struct sockaddr_in sin; 00359 } u; 00360 }; 00361 00362 // Describes a string (chunk of memory). 00363 struct vec { 00364 const char *ptr; 00365 size_t len; 00366 }; 00367 00368 // Structure used by mg_stat() function. Uses 64 bit file length. 00369 struct mgstat { 00370 int is_directory; // Directory marker 00371 int64_t size; // File size 00372 time_t mtime; // Modification time 00373 }; 00374 00375 // Describes listening socket, or socket which was accept()-ed by the master 00376 // thread and queued for future handling by the worker thread. 00377 struct socket { 00378 struct socket *next; // Linkage 00379 SOCKET sock; // Listening socket 00380 struct usa lsa; // Local socket address 00381 struct usa rsa; // Remote socket address 00382 int is_ssl; // Is socket SSL-ed 00383 int is_proxy; 00384 }; 00385 00386 enum { 00387 CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER, 00388 PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE, 00389 SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE, 00390 GLOBAL_PASSWORDS_FILE, INDEX_FILES, 00391 ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, MAX_REQUEST_SIZE, 00392 EXTRA_MIME_TYPES, LISTENING_PORTS, 00393 DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, 00394 MAX_THREADS, NUM_OPTIONS 00395 }; 00396 00397 static const char *config_options[] = { 00398 "C", "cgi_extensions", ".cgi,.pl,.php", 00399 "E", "cgi_environment", NULL, 00400 "G", "put_delete_passwords_file", NULL, 00401 "I", "cgi_interpreter", NULL, 00402 "P", "protect_uri", NULL, 00403 "R", "authentication_domain", "mydomain.com", 00404 "S", "ssi_extensions", ".shtml,.shtm", 00405 "a", "access_log_file", NULL, 00406 "c", "ssl_chain_file", NULL, 00407 "d", "enable_directory_listing", "yes", 00408 "e", "error_log_file", NULL, 00409 "g", "global_passwords_file", NULL, 00410 "i", "index_files", "index.html,index.htm,index.cgi", 00411 "k", "enable_keep_alive", "no", 00412 "l", "access_control_list", NULL, 00413 "M", "max_request_size", "16384", 00414 "m", "extra_mime_types", NULL, 00415 "p", "listening_ports", "8080", 00416 "r", "document_root", ".", 00417 "s", "ssl_certificate", NULL, 00418 "t", "num_threads", "10", 00419 "u", "run_as_user", NULL, 00420 "T", "max_threads", NULL, 00421 NULL 00422 }; 00423 #define ENTRIES_PER_CONFIG_OPTION 3 00424 00425 struct mg_context { 00426 int stop_flag; // Should we stop event loop 00427 SSL_CTX *ssl_ctx; // SSL context 00428 char *config[NUM_OPTIONS]; // Mongoose configuration parameters 00429 mg_callback_t user_callback; // User-defined callback function 00430 void *user_data; // User-defined data 00431 00432 struct socket *listening_sockets; 00433 00434 int num_threads; // Number of threads 00435 int idle_threads; // Number of inactive threads 00436 int base_threads; // Number of threads to maintain when idle 00437 int max_threads; // Limit on number of threads 00438 pthread_mutex_t mutex; // Protects (max|num)_threads 00439 pthread_cond_t cond; // Condvar for tracking workers terminations 00440 00441 struct socket queue[20]; // Accepted sockets 00442 int sq_head; // Head of the socket queue 00443 int sq_tail; // Tail of the socket queue 00444 pthread_cond_t sq_full; // Singaled when socket is produced 00445 pthread_cond_t sq_empty; // Signaled when socket is consumed 00446 }; 00447 00448 struct mg_connection { 00449 struct mg_connection *peer; // Remote target in proxy mode 00450 struct mg_request_info request_info; 00451 struct mg_context *ctx; 00452 SSL *ssl; // SSL descriptor 00453 struct socket client; // Connected client 00454 time_t birth_time; // Time connection was accepted 00455 int64_t num_bytes_sent; // Total bytes sent to client 00456 int64_t content_len; // Content-Length header value 00457 int64_t consumed_content; // How many bytes of content is already read 00458 char *buf; // Buffer for received data 00459 int buf_size; // Buffer size 00460 int request_len; // Size of the request + headers in a buffer 00461 int data_len; // Total size of data in a buffer 00462 }; 00463 00464 const char **mg_get_valid_option_names(void) { 00465 return config_options; 00466 } 00467 00468 static void *call_user(struct mg_connection *conn, enum mg_event event) { 00469 conn->request_info.user_data = conn->ctx->user_data; 00470 return conn->ctx->user_callback == NULL ? NULL : 00471 conn->ctx->user_callback(event, conn, &conn->request_info); 00472 } 00473 00474 static int get_option_index(const char *name) { 00475 int i; 00476 00477 for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) { 00478 if (strcmp(config_options[i], name) == 0 || 00479 strcmp(config_options[i + 1], name) == 0) { 00480 return i / ENTRIES_PER_CONFIG_OPTION; 00481 } 00482 } 00483 return -1; 00484 } 00485 00486 const char *mg_get_option(const struct mg_context *ctx, const char *name) { 00487 int i; 00488 if ((i = get_option_index(name)) == -1) { 00489 return NULL; 00490 } else if (ctx->config[i] == NULL) { 00491 return ""; 00492 } else { 00493 return ctx->config[i]; 00494 } 00495 } 00496 00497 // Print error message to the opened error log stream. 00498 static void cry(struct mg_connection *conn, const char *fmt, ...) { 00499 char buf[BUFSIZ]; 00500 va_list ap; 00501 FILE *fp; 00502 time_t timestamp; 00503 00504 va_start(ap, fmt); 00505 (void) vsnprintf(buf, sizeof(buf), fmt, ap); 00506 va_end(ap); 00507 00508 // Do not lock when getting the callback value, here and below. 00509 // I suppose this is fine, since function cannot disappear in the 00510 // same way string option can. 00511 conn->request_info.log_message = buf; 00512 if (call_user(conn, MG_EVENT_LOG) == NULL) { 00513 fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL : 00514 mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+"); 00515 00516 if (fp != NULL) { 00517 flockfile(fp); 00518 timestamp = time(NULL); 00519 00520 (void) fprintf(fp, 00521 "[%010lu] [error] [client %s] ", 00522 (unsigned long) timestamp, 00523 inet_ntoa(conn->client.rsa.u.sin.sin_addr)); 00524 00525 if (conn->request_info.request_method != NULL) { 00526 (void) fprintf(fp, "%s %s: ", 00527 conn->request_info.request_method, 00528 conn->request_info.uri); 00529 } 00530 00531 (void) fprintf(fp, "%s", buf); 00532 fputc('\n', fp); 00533 funlockfile(fp); 00534 if (fp != stderr) { 00535 fclose(fp); 00536 } 00537 } 00538 } 00539 conn->request_info.log_message = NULL; 00540 } 00541 00542 // Return OpenSSL error message 00543 static const char *ssl_error(void) { 00544 unsigned long err; 00545 err = ERR_get_error(); 00546 return err == 0 ? "" : ERR_error_string(err, NULL); 00547 } 00548 00549 // Return fake connection structure. Used for logging, if connection 00550 // is not applicable at the moment of logging. 00551 static struct mg_connection *fc(struct mg_context *ctx) { 00552 static struct mg_connection fake_connection; 00553 fake_connection.ctx = ctx; 00554 return &fake_connection; 00555 } 00556 00557 const char *mg_version(void) { 00558 return MONGOOSE_VERSION; 00559 } 00560 00561 static void mg_strlcpy(register char *dst, register const char *src, size_t n) { 00562 for (; *src != '\0' && n > 1; n--) { 00563 *dst++ = *src++; 00564 } 00565 *dst = '\0'; 00566 } 00567 00568 static int lowercase(const char *s) { 00569 return tolower(* (const unsigned char *) s); 00570 } 00571 00572 static int mg_strncasecmp(const char *s1, const char *s2, size_t len) { 00573 int diff = 0; 00574 00575 if (len > 0) 00576 do { 00577 diff = lowercase(s1++) - lowercase(s2++); 00578 } while (diff == 0 && s1[-1] != '\0' && --len > 0); 00579 00580 return diff; 00581 } 00582 00583 static int mg_strcasecmp(const char *s1, const char *s2) { 00584 int diff; 00585 00586 do { 00587 diff = lowercase(s1++) - lowercase(s2++); 00588 } while (diff == 0 && s1[-1] != '\0'); 00589 00590 return diff; 00591 } 00592 00593 static char * mg_strndup(const char *ptr, size_t len) { 00594 char *p; 00595 00596 if ((p = (char *) malloc(len + 1)) != NULL) { 00597 mg_strlcpy(p, ptr, len + 1); 00598 } 00599 00600 return p; 00601 } 00602 00603 static char * mg_strdup(const char *str) { 00604 return mg_strndup(str, strlen(str)); 00605 } 00606 00607 // Like snprintf(), but never returns negative value, or the value 00608 // that is larger than a supplied buffer. 00609 // Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability 00610 // in his audit report. 00611 static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, 00612 const char *fmt, va_list ap) { 00613 int n; 00614 00615 if (buflen == 0) 00616 return 0; 00617 00618 n = vsnprintf(buf, buflen, fmt, ap); 00619 00620 if (n < 0) { 00621 cry(conn, "vsnprintf error"); 00622 n = 0; 00623 } else if (n >= (int) buflen) { 00624 cry(conn, "truncating vsnprintf buffer: [%.*s]", 00625 n > 200 ? 200 : n, buf); 00626 n = (int) buflen - 1; 00627 } 00628 buf[n] = '\0'; 00629 00630 return n; 00631 } 00632 00633 static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, 00634 const char *fmt, ...) { 00635 va_list ap; 00636 int n; 00637 00638 va_start(ap, fmt); 00639 n = mg_vsnprintf(conn, buf, buflen, fmt, ap); 00640 va_end(ap); 00641 00642 return n; 00643 } 00644 00645 // Skip the characters until one of the delimiters characters found. 00646 // 0-terminate resulting word. Skip the delimiter and following whitespaces if any. 00647 // Advance pointer to buffer to the next word. Return found 0-terminated word. 00648 // Delimiters can be quoted with quotechar. 00649 static char *skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar) { 00650 char *p, *begin_word, *end_word, *end_whitespace; 00651 00652 begin_word = *buf; 00653 end_word = begin_word + strcspn(begin_word, delimiters); 00654 00655 /* Check for quotechar */ 00656 if (end_word > begin_word) { 00657 p = end_word - 1; 00658 while (*p == quotechar) { 00659 /* If there is anything beyond end_word, copy it */ 00660 if (*end_word == '\0') { 00661 *p = '\0'; 00662 break; 00663 } else { 00664 size_t end_off = strcspn(end_word + 1, delimiters); 00665 memmove (p, end_word, end_off + 1); 00666 p += end_off; /* p must correspond to end_word - 1 */ 00667 end_word += end_off + 1; 00668 } 00669 } 00670 for (p++; p < end_word; p++) { 00671 *p = '\0'; 00672 } 00673 } 00674 00675 if (*end_word == '\0') { 00676 *buf = end_word; 00677 } else { 00678 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace); 00679 00680 for (p = end_word; p < end_whitespace; p++) { 00681 *p = '\0'; 00682 } 00683 00684 *buf = end_whitespace; 00685 } 00686 00687 return begin_word; 00688 } 00689 00690 // Simplified version of skip_quoted without quote char and whitespace == delimiters 00691 static char *skip(char **buf, const char *delimiters) { 00692 return skip_quoted(buf, delimiters, delimiters, 0); 00693 } 00694 00695 00696 // Return HTTP header value, or NULL if not found. 00697 static const char *get_header(const struct mg_request_info *ri, 00698 const char *name) { 00699 int i; 00700 00701 for (i = 0; i < ri->num_headers; i++) 00702 if (!mg_strcasecmp(name, ri->http_headers[i].name)) 00703 return ri->http_headers[i].value; 00704 00705 return NULL; 00706 } 00707 00708 const char *mg_get_header(const struct mg_connection *conn, const char *name) { 00709 return get_header(&conn->request_info, name); 00710 } 00711 00712 // A helper function for traversing comma separated list of values. 00713 // It returns a list pointer shifted to the next value, of NULL if the end 00714 // of the list found. 00715 // Value is stored in val vector. If value has form "x=y", then eq_val 00716 // vector is initialized to point to the "y" part, and val vector length 00717 // is adjusted to point only to "x". 00718 static const char *next_option(const char *list, struct vec *val, 00719 struct vec *eq_val) { 00720 if (list == NULL || *list == '\0') { 00721 /* End of the list */ 00722 list = NULL; 00723 } else { 00724 val->ptr = list; 00725 if ((list = strchr(val->ptr, ',')) != NULL) { 00726 /* Comma found. Store length and shift the list ptr */ 00727 val->len = list - val->ptr; 00728 list++; 00729 } else { 00730 /* This value is the last one */ 00731 list = val->ptr + strlen(val->ptr); 00732 val->len = list - val->ptr; 00733 } 00734 00735 if (eq_val != NULL) { 00736 /* 00737 * Value has form "x=y", adjust pointers and lengths 00738 * so that val points to "x", and eq_val points to "y". 00739 */ 00740 eq_val->len = 0; 00741 eq_val->ptr = memchr(val->ptr, '=', val->len); 00742 if (eq_val->ptr != NULL) { 00743 eq_val->ptr++; /* Skip over '=' character */ 00744 eq_val->len = val->ptr + val->len - eq_val->ptr; 00745 val->len = (eq_val->ptr - val->ptr) - 1; 00746 } 00747 } 00748 } 00749 00750 return list; 00751 } 00752 00753 #if !defined(NO_CGI) 00754 static int match_extension(const char *path, const char *ext_list) { 00755 struct vec ext_vec; 00756 size_t path_len; 00757 00758 path_len = strlen(path); 00759 00760 while ((ext_list = next_option(ext_list, &ext_vec, NULL)) != NULL) 00761 if (ext_vec.len < path_len && 00762 mg_strncasecmp(path + path_len - ext_vec.len, 00763 ext_vec.ptr, ext_vec.len) == 0) 00764 return 1; 00765 00766 return 0; 00767 } 00768 #endif // !NO_CGI 00769 00770 // HTTP 1.1 assumes keep alive if "Connection:" header is not set 00771 // This function must tolerate situations when connection info is not 00772 // set up, for example if request parsing failed. 00773 static int should_keep_alive(const struct mg_connection *conn) { 00774 const char *http_version = conn->request_info.http_version; 00775 const char *header = mg_get_header(conn, "Connection"); 00776 return (header == NULL && http_version && !strcmp(http_version, "1.1")) || 00777 (header != NULL && !mg_strcasecmp(header, "keep-alive")); 00778 } 00779 00780 static const char *suggest_connection_header(const struct mg_connection *conn) { 00781 return should_keep_alive(conn) ? "keep-alive" : "close"; 00782 } 00783 00784 static void send_http_error(struct mg_connection *conn, int status, 00785 const char *reason, const char *fmt, ...) { 00786 char buf[BUFSIZ]; 00787 va_list ap; 00788 int len; 00789 00790 conn->request_info.status_code = status; 00791 00792 if (call_user(conn, MG_HTTP_ERROR) == NULL) { 00793 buf[0] = '\0'; 00794 len = 0; 00795 00796 /* Errors 1xx, 204 and 304 MUST NOT send a body */ 00797 if (status > 199 && status != 204 && status != 304) { 00798 len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason); 00799 cry(conn, "%s", buf); 00800 buf[len++] = '\n'; 00801 00802 va_start(ap, fmt); 00803 len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap); 00804 va_end(ap); 00805 } 00806 DEBUG_TRACE(("[%s]", buf)); 00807 00808 mg_printf(conn, "HTTP/1.1 %d %s\r\n" 00809 "Content-Type: text/plain\r\n" 00810 "Content-Length: %d\r\n" 00811 "Connection: %s\r\n\r\n", status, reason, len, 00812 suggest_connection_header(conn)); 00813 conn->num_bytes_sent += mg_printf(conn, "%s", buf); 00814 } 00815 } 00816 00817 #ifdef _WIN32 00818 static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) { 00819 unused = NULL; 00820 *mutex = CreateMutex(NULL, FALSE, NULL); 00821 return *mutex == NULL ? -1 : 0; 00822 } 00823 00824 static int pthread_mutex_destroy(pthread_mutex_t *mutex) { 00825 return CloseHandle(*mutex) == 0 ? -1 : 0; 00826 } 00827 00828 static int pthread_mutex_lock(pthread_mutex_t *mutex) { 00829 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1; 00830 } 00831 00832 static int pthread_mutex_unlock(pthread_mutex_t *mutex) { 00833 return ReleaseMutex(*mutex) == 0 ? -1 : 0; 00834 } 00835 00836 static int pthread_cond_init(pthread_cond_t *cv, const void *unused) { 00837 unused = NULL; 00838 cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL); 00839 cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL); 00840 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1; 00841 } 00842 00843 static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) { 00844 HANDLE handles[] = {cv->signal, cv->broadcast}; 00845 ReleaseMutex(*mutex); 00846 WaitForMultipleObjects(2, handles, FALSE, INFINITE); 00847 return ReleaseMutex(*mutex) == 0 ? -1 : 0; 00848 } 00849 00850 static int pthread_cond_signal(pthread_cond_t *cv) { 00851 return SetEvent(cv->signal) == 0 ? -1 : 0; 00852 } 00853 00854 static int pthread_cond_broadcast(pthread_cond_t *cv) { 00855 // Implementation with PulseEvent() has race condition, see 00856 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html 00857 return PulseEvent(cv->broadcast) == 0 ? -1 : 0; 00858 } 00859 00860 static int pthread_cond_destroy(pthread_cond_t *cv) { 00861 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1; 00862 } 00863 00864 static pthread_t pthread_self(void) { 00865 return GetCurrentThreadId(); 00866 } 00867 00868 // For Windows, change all slashes to backslashes in path names. 00869 static void change_slashes_to_backslashes(char *path) { 00870 int i; 00871 00872 for (i = 0; path[i] != '\0'; i++) { 00873 if (path[i] == '/') 00874 path[i] = '\\'; 00875 // i > 0 check is to preserve UNC paths, like \\server\file.txt 00876 if (path[i] == '\\' && i > 0) 00877 while (path[i + 1] == '\\' || path[i + 1] == '/') 00878 (void) memmove(path + i + 1, 00879 path + i + 2, strlen(path + i + 1)); 00880 } 00881 } 00882 00883 // Encode 'path' which is assumed UTF-8 string, into UNICODE string. 00884 // wbuf and wbuf_len is a target buffer and its length. 00885 static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) { 00886 char buf[PATH_MAX], *p; 00887 00888 mg_strlcpy(buf, path, sizeof(buf)); 00889 change_slashes_to_backslashes(buf); 00890 00891 // Point p to the end of the file name 00892 p = buf + strlen(buf) - 1; 00893 00894 // Trim trailing backslash character 00895 while (p > buf && *p == '\\' && p[-1] != ':') { 00896 *p-- = '\0'; 00897 } 00898 00899 // Protect from CGI code disclosure. 00900 // This is very nasty hole. Windows happily opens files with 00901 // some garbage in the end of file name. So fopen("a.cgi ", "r") 00902 // actually opens "a.cgi", and does not return an error! 00903 if (*p == 0x20 || // No space at the end 00904 (*p == 0x2e && p > buf) || // No '.' but allow '.' as full path 00905 *p == 0x2b || // No '+' 00906 (*p & ~0x7f)) { // And generally no non-ascii chars 00907 (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf); 00908 buf[0] = '\0'; 00909 } 00910 00911 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); 00912 } 00913 00914 #if defined(_WIN32_WCE) 00915 static time_t time(time_t *ptime) { 00916 time_t t; 00917 SYSTEMTIME st; 00918 FILETIME ft; 00919 00920 GetSystemTime(&st); 00921 SystemTimeToFileTime(&st, &ft); 00922 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime); 00923 00924 if (ptime != NULL) { 00925 *ptime = t; 00926 } 00927 00928 return t; 00929 } 00930 00931 static time_t mktime(struct tm *ptm) { 00932 SYSTEMTIME st; 00933 FILETIME ft, lft; 00934 00935 st.wYear = ptm->tm_year + 1900; 00936 st.wMonth = ptm->tm_mon + 1; 00937 st.wDay = ptm->tm_mday; 00938 st.wHour = ptm->tm_hour; 00939 st.wMinute = ptm->tm_min; 00940 st.wSecond = ptm->tm_sec; 00941 st.wMilliseconds = 0; 00942 00943 SystemTimeToFileTime(&st, &ft); 00944 LocalFileTimeToFileTime(&ft, &lft); 00945 return (time_t) ((MAKEUQUAD(lft.dwLowDateTime, lft.dwHighDateTime) - 00946 EPOCH_DIFF) / RATE_DIFF); 00947 } 00948 00949 static struct tm *localtime(const time_t *ptime, struct tm *ptm) { 00950 int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF; 00951 FILETIME ft, lft; 00952 SYSTEMTIME st; 00953 TIME_ZONE_INFORMATION tzinfo; 00954 00955 if (ptm == NULL) { 00956 return NULL; 00957 } 00958 00959 * (int64_t *) &ft = t; 00960 FileTimeToLocalFileTime(&ft, &lft); 00961 FileTimeToSystemTime(&lft, &st); 00962 ptm->tm_year = st.wYear - 1900; 00963 ptm->tm_mon = st.wMonth - 1; 00964 ptm->tm_wday = st.wDayOfWeek; 00965 ptm->tm_mday = st.wDay; 00966 ptm->tm_hour = st.wHour; 00967 ptm->tm_min = st.wMinute; 00968 ptm->tm_sec = st.wSecond; 00969 ptm->tm_yday = 0; // hope nobody uses this 00970 ptm->tm_isdst = 00971 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0; 00972 00973 return ptm; 00974 } 00975 00976 static size_t strftime(char *dst, size_t dst_size, const char *fmt, 00977 const struct tm *tm) { 00978 (void) snprintf(dst, dst_size, "implement strftime() for WinCE"); 00979 return 0; 00980 } 00981 #endif 00982 00983 static int mg_rename(const char* oldname, const char* newname) { 00984 wchar_t woldbuf[PATH_MAX]; 00985 wchar_t wnewbuf[PATH_MAX]; 00986 00987 to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf)); 00988 to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf)); 00989 00990 return MoveFileW(woldbuf, wnewbuf) ? 0 : -1; 00991 } 00992 00993 00994 static FILE *mg_fopen(const char *path, const char *mode) { 00995 wchar_t wbuf[PATH_MAX], wmode[20]; 00996 00997 to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); 00998 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode)); 00999 01000 return _wfopen(wbuf, wmode); 01001 } 01002 01003 static int mg_stat(const char *path, struct mgstat *stp) { 01004 int ok = -1; // Error 01005 wchar_t wbuf[PATH_MAX]; 01006 WIN32_FILE_ATTRIBUTE_DATA info; 01007 01008 to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); 01009 01010 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) { 01011 stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh); 01012 stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime, 01013 info.ftLastWriteTime.dwHighDateTime); 01014 stp->is_directory = 01015 info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; 01016 ok = 0; // Success 01017 } 01018 01019 return ok; 01020 } 01021 01022 static int mg_remove(const char *path) { 01023 wchar_t wbuf[PATH_MAX]; 01024 to_unicode(path, wbuf, ARRAY_SIZE(wbuf)); 01025 return DeleteFileW(wbuf) ? 0 : -1; 01026 } 01027 01028 static int mg_mkdir(const char *path, int mode) { 01029 char buf[PATH_MAX]; 01030 wchar_t wbuf[PATH_MAX]; 01031 01032 mode = 0; // Unused 01033 mg_strlcpy(buf, path, sizeof(buf)); 01034 change_slashes_to_backslashes(buf); 01035 01036 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf)); 01037 01038 return CreateDirectoryW(wbuf, NULL) ? 0 : -1; 01039 } 01040 01041 // Implementation of POSIX opendir/closedir/readdir for Windows. 01042 static DIR * opendir(const char *name) { 01043 DIR *dir = NULL; 01044 wchar_t wpath[PATH_MAX]; 01045 DWORD attrs; 01046 01047 if (name == NULL) { 01048 SetLastError(ERROR_BAD_ARGUMENTS); 01049 } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) { 01050 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 01051 } else { 01052 to_unicode(name, wpath, ARRAY_SIZE(wpath)); 01053 attrs = GetFileAttributesW(wpath); 01054 if (attrs != 0xFFFFFFFF && 01055 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) { 01056 (void) wcscat(wpath, L"\\*"); 01057 dir->handle = FindFirstFileW(wpath, &dir->info); 01058 dir->result.d_name[0] = '\0'; 01059 } else { 01060 free(dir); 01061 dir = NULL; 01062 } 01063 } 01064 01065 return dir; 01066 } 01067 01068 static int closedir(DIR *dir) { 01069 int result = 0; 01070 01071 if (dir != NULL) { 01072 if (dir->handle != INVALID_HANDLE_VALUE) 01073 result = FindClose(dir->handle) ? 0 : -1; 01074 01075 free(dir); 01076 } else { 01077 result = -1; 01078 SetLastError(ERROR_BAD_ARGUMENTS); 01079 } 01080 01081 return result; 01082 } 01083 01084 struct dirent * readdir(DIR *dir) { 01085 struct dirent *result = 0; 01086 01087 if (dir) { 01088 if (dir->handle != INVALID_HANDLE_VALUE) { 01089 result = &dir->result; 01090 (void) WideCharToMultiByte(CP_UTF8, 0, 01091 dir->info.cFileName, -1, result->d_name, 01092 sizeof(result->d_name), NULL, NULL); 01093 01094 if (!FindNextFileW(dir->handle, &dir->info)) { 01095 (void) FindClose(dir->handle); 01096 dir->handle = INVALID_HANDLE_VALUE; 01097 } 01098 01099 } else { 01100 SetLastError(ERROR_FILE_NOT_FOUND); 01101 } 01102 } else { 01103 SetLastError(ERROR_BAD_ARGUMENTS); 01104 } 01105 01106 return result; 01107 } 01108 01109 #define set_close_on_exec(fd) // No FD_CLOEXEC on Windows 01110 01111 static int start_thread(struct mg_context *ctx, mg_thread_func_t func, 01112 void *param) { 01113 HANDLE hThread; 01114 ctx = NULL; // Unused 01115 01116 hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, param, 0, 01117 NULL); 01118 if (hThread != NULL) { 01119 (void) CloseHandle(hThread); 01120 } 01121 01122 return hThread == NULL ? -1 : 0; 01123 } 01124 01125 static HANDLE dlopen(const char *dll_name, int flags) { 01126 wchar_t wbuf[PATH_MAX]; 01127 flags = 0; // Unused 01128 to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf)); 01129 return LoadLibraryW(wbuf); 01130 } 01131 01132 #if !defined(NO_CGI) 01133 #define SIGKILL 0 01134 static int kill(pid_t pid, int sig_num) { 01135 (void) TerminateProcess(pid, sig_num); 01136 (void) CloseHandle(pid); 01137 return 0; 01138 } 01139 01140 static pid_t spawn_process(struct mg_connection *conn, const char *prog, 01141 char *envblk, char *envp[], int fd_stdin, 01142 int fd_stdout, const char *dir) { 01143 HANDLE me; 01144 char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX]; 01145 FILE *fp; 01146 STARTUPINFOA si; 01147 PROCESS_INFORMATION pi; 01148 01149 envp = NULL; // Unused 01150 01151 (void) memset(&si, 0, sizeof(si)); 01152 (void) memset(&pi, 0, sizeof(pi)); 01153 01154 // TODO(lsm): redirect CGI errors to the error log file 01155 si.cb = sizeof(si); 01156 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; 01157 si.wShowWindow = SW_HIDE; 01158 01159 me = GetCurrentProcess(); 01160 (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me, 01161 &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); 01162 (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me, 01163 &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); 01164 01165 // If CGI file is a script, try to read the interpreter line 01166 interp = conn->ctx->config[CGI_INTERPRETER]; 01167 if (interp == NULL) { 01168 buf[2] = '\0'; 01169 if ((fp = fopen(cmdline, "r")) != NULL) { 01170 (void) fgets(buf, sizeof(buf), fp); 01171 if (buf[0] != '#' || buf[1] != '!') { 01172 // First line does not start with "#!". Do not set interpreter. 01173 buf[2] = '\0'; 01174 } else { 01175 // Trim whitespaces in interpreter name 01176 for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) { 01177 *p = '\0'; 01178 } 01179 } 01180 (void) fclose(fp); 01181 } 01182 interp = buf + 2; 01183 } 01184 01185 (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s", 01186 interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog); 01187 01188 DEBUG_TRACE(("Running [%s]", cmdline)); 01189 if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 01190 CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) { 01191 cry(conn, "%s: CreateProcess(%s): %d", 01192 __func__, cmdline, ERRNO); 01193 pi.hProcess = (pid_t) -1; 01194 } else { 01195 (void) close(fd_stdin); 01196 (void) close(fd_stdout); 01197 } 01198 01199 (void) CloseHandle(si.hStdOutput); 01200 (void) CloseHandle(si.hStdInput); 01201 (void) CloseHandle(pi.hThread); 01202 01203 return (pid_t) pi.hProcess; 01204 } 01205 #endif /* !NO_CGI */ 01206 01207 static int set_non_blocking_mode(SOCKET sock) { 01208 unsigned long on = 1; 01209 return ioctlsocket(sock, FIONBIO, &on); 01210 } 01211 01212 #else 01213 static int mg_stat(const char *path, struct mgstat *stp) { 01214 struct stat st; 01215 int ok; 01216 01217 if (stat(path, &st) == 0) { 01218 ok = 0; 01219 stp->size = st.st_size; 01220 stp->mtime = st.st_mtime; 01221 stp->is_directory = S_ISDIR(st.st_mode); 01222 } else { 01223 ok = -1; 01224 } 01225 01226 return ok; 01227 } 01228 01229 static void set_close_on_exec(int fd) { 01230 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 01231 } 01232 01233 static int start_thread(struct mg_context *ctx, mg_thread_func_t func, 01234 void *param) { 01235 pthread_t thread_id; 01236 pthread_attr_t attr; 01237 int retval; 01238 01239 (void) pthread_attr_init(&attr); 01240 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01241 // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled 01242 // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5); 01243 01244 if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) { 01245 cry(fc(ctx), "%s: %s", __func__, strerror(retval)); 01246 } 01247 01248 return retval; 01249 } 01250 01251 #ifndef NO_CGI 01252 static pid_t spawn_process(struct mg_connection *conn, const char *prog, 01253 char *envblk, char *envp[], int fd_stdin, 01254 int fd_stdout, const char *dir) { 01255 pid_t pid; 01256 const char *interp; 01257 01258 envblk = NULL; // Unused 01259 01260 if ((pid = fork()) == -1) { 01261 // Parent 01262 send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO)); 01263 } else if (pid == 0) { 01264 // Child 01265 if (chdir(dir) != 0) { 01266 cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO)); 01267 } else if (dup2(fd_stdin, 0) == -1) { 01268 cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO)); 01269 } else if (dup2(fd_stdout, 1) == -1) { 01270 cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO)); 01271 } else { 01272 (void) dup2(fd_stdout, 2); 01273 (void) close(fd_stdin); 01274 (void) close(fd_stdout); 01275 01276 // Execute CGI program. No need to lock: new process 01277 interp = conn->ctx->config[CGI_INTERPRETER]; 01278 if (interp == NULL) { 01279 (void) execle(prog, prog, NULL, envp); 01280 cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO)); 01281 } else { 01282 (void) execle(interp, interp, prog, NULL, envp); 01283 cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog, 01284 strerror(ERRNO)); 01285 } 01286 } 01287 exit(EXIT_FAILURE); 01288 } else { 01289 // Parent. Close stdio descriptors 01290 (void) close(fd_stdin); 01291 (void) close(fd_stdout); 01292 } 01293 01294 return pid; 01295 } 01296 #endif // !NO_CGI 01297 01298 static int set_non_blocking_mode(SOCKET sock) { 01299 int flags; 01300 01301 flags = fcntl(sock, F_GETFL, 0); 01302 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK); 01303 01304 return 0; 01305 } 01306 #endif // _WIN32 01307 01308 // Write data to the IO channel - opened file descriptor, socket or SSL 01309 // descriptor. Return number of bytes written. 01310 static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, 01311 int64_t len) { 01312 int64_t sent; 01313 int n, k; 01314 01315 sent = 0; 01316 while (sent < len) { 01317 01318 /* How many bytes we send in this iteration */ 01319 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent); 01320 01321 if (ssl != NULL) { 01322 n = SSL_write(ssl, buf + sent, k); 01323 } else if (fp != NULL) { 01324 n = fwrite(buf + sent, 1, (size_t)k, fp); 01325 if (ferror(fp)) 01326 n = -1; 01327 } else { 01328 n = send(sock, buf + sent, (size_t)k, 0); 01329 } 01330 01331 if (n < 0) 01332 break; 01333 01334 sent += n; 01335 } 01336 01337 return sent; 01338 } 01339 01340 // Read from IO channel - opened file descriptor, socket, or SSL descriptor. 01341 // Return number of bytes read. 01342 static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) { 01343 int nread; 01344 01345 if (ssl != NULL) { 01346 nread = SSL_read(ssl, buf, len); 01347 } else if (fp != NULL) { 01348 // Use read() instead of fread(), because if we're reading from the CGI 01349 // pipe, fread() may block until IO buffer is filled up. We cannot afford 01350 // to block and must pass all read bytes immediately to the client. 01351 nread = read(fileno(fp), buf, (size_t) len); 01352 if (ferror(fp)) 01353 nread = -1; 01354 } else { 01355 nread = recv(sock, buf, (size_t) len, 0); 01356 } 01357 01358 return nread; 01359 } 01360 01361 int mg_read(struct mg_connection *conn, void *buf, size_t len) { 01362 int n, buffered_len, nread; 01363 const char *buffered; 01364 01365 assert(conn->content_len >= conn->consumed_content); 01366 DEBUG_TRACE(("%p %zu %lld %lld", buf, len, 01367 conn->content_len, conn->consumed_content)); 01368 nread = 0; 01369 if (conn->consumed_content < conn->content_len) { 01370 01371 // Adjust number of bytes to read. 01372 int64_t to_read = conn->content_len - conn->consumed_content; 01373 if (to_read < (int64_t) len) { 01374 len = (int) to_read; 01375 } 01376 01377 // How many bytes of data we have buffered in the request buffer? 01378 buffered = conn->buf + conn->request_len + conn->consumed_content; 01379 buffered_len = conn->data_len - conn->request_len; 01380 assert(buffered_len >= 0); 01381 01382 // Return buffered data back if we haven't done that yet. 01383 if (conn->consumed_content < (int64_t) buffered_len) { 01384 buffered_len -= (int) conn->consumed_content; 01385 if (len < (size_t) buffered_len) { 01386 buffered_len = len; 01387 } 01388 memcpy(buf, buffered, (size_t)buffered_len); 01389 len -= buffered_len; 01390 buf = (char *) buf + buffered_len; 01391 conn->consumed_content += buffered_len; 01392 nread = buffered_len; 01393 } 01394 01395 // We have returned all buffered data. Read new data from the remote socket. 01396 while (len > 0) { 01397 n = pull(NULL, conn->client.sock, conn->ssl, (char *) buf, (int) len); 01398 if (n <= 0) { 01399 break; 01400 } 01401 buf = (char *) buf + n; 01402 conn->consumed_content += n; 01403 nread += n; 01404 len -= n; 01405 } 01406 } 01407 return nread; 01408 } 01409 01410 int mg_write(struct mg_connection *conn, const void *buf, size_t len) { 01411 return (int) push(NULL, conn->client.sock, conn->ssl, 01412 (const char *) buf, (int64_t) len); 01413 } 01414 01415 int mg_printf(struct mg_connection *conn, const char *fmt, ...) { 01416 char buf[BUFSIZ]; 01417 int len; 01418 va_list ap; 01419 01420 va_start(ap, fmt); 01421 len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap); 01422 va_end(ap); 01423 01424 return mg_write(conn, buf, (size_t)len); 01425 } 01426 01427 // URL-decode input buffer into destination buffer. 01428 // 0-terminate the destination buffer. Return the length of decoded data. 01429 // form-url-encoded data differs from URI encoding in a way that it 01430 // uses '+' as character for space, see RFC 1866 section 8.2.1 01431 // http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt 01432 static size_t url_decode(const char *src, size_t src_len, char *dst, 01433 size_t dst_len, int is_form_url_encoded) { 01434 size_t i, j; 01435 int a, b; 01436 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W') 01437 01438 for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) { 01439 if (src[i] == '%' && 01440 isxdigit(* (const unsigned char *) (src + i + 1)) && 01441 isxdigit(* (const unsigned char *) (src + i + 2))) { 01442 a = tolower(* (const unsigned char *) (src + i + 1)); 01443 b = tolower(* (const unsigned char *) (src + i + 2)); 01444 dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b)); 01445 i += 2; 01446 } else if (is_form_url_encoded && src[i] == '+') { 01447 dst[j] = ' '; 01448 } else { 01449 dst[j] = src[i]; 01450 } 01451 } 01452 01453 dst[j] = '\0'; /* Null-terminate the destination */ 01454 01455 return j; 01456 } 01457 01458 // Scan given buffer and fetch the value of the given variable. 01459 // It can be specified in query string, or in the POST data. 01460 // Return NULL if the variable not found, or allocated 0-terminated value. 01461 // It is caller's responsibility to free the returned value. 01462 int mg_get_var(const char *buf, size_t buf_len, const char *name, 01463 char *dst, size_t dst_len) { 01464 const char *p, *e, *s; 01465 size_t name_len, len; 01466 01467 name_len = strlen(name); 01468 e = buf + buf_len; 01469 len = -1; 01470 dst[0] = '\0'; 01471 01472 // buf is "var1=val1&var2=val2...". Find variable first 01473 for (p = buf; p != NULL && p + name_len < e; p++) { 01474 if ((p == buf || p[-1] == '&') && p[name_len] == '=' && 01475 !mg_strncasecmp(name, p, name_len)) { 01476 01477 // Point p to variable value 01478 p += name_len + 1; 01479 01480 // Point s to the end of the value 01481 s = (const char *) memchr(p, '&', (size_t)(e - p)); 01482 if (s == NULL) { 01483 s = e; 01484 } 01485 assert(s >= p); 01486 01487 // Decode variable into destination buffer 01488 if ((size_t) (s - p) < dst_len) { 01489 len = url_decode(p, (size_t)(s - p), dst, dst_len, 1); 01490 } 01491 break; 01492 } 01493 } 01494 01495 return len; 01496 } 01497 01498 int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name, 01499 char *dst, size_t dst_size) { 01500 const char *s, *p, *end; 01501 int name_len, len = -1; 01502 01503 dst[0] = '\0'; 01504 if ((s = mg_get_header(conn, "Cookie")) == NULL) { 01505 return 0; 01506 } 01507 01508 name_len = strlen(cookie_name); 01509 end = s + strlen(s); 01510 01511 for (; (s = strstr(s, cookie_name)) != NULL; s += name_len) 01512 if (s[name_len] == '=') { 01513 s += name_len + 1; 01514 if ((p = strchr(s, ' ')) == NULL) 01515 p = end; 01516 if (p[-1] == ';') 01517 p--; 01518 if (*s == '"' && p[-1] == '"' && p > s + 1) { 01519 s++; 01520 p--; 01521 } 01522 if ((size_t) (p - s) < dst_size) { 01523 len = (p - s) + 1; 01524 mg_strlcpy(dst, s, (size_t)len); 01525 } 01526 break; 01527 } 01528 01529 return len; 01530 } 01531 01532 // Mongoose allows to specify multiple directories to serve, 01533 // like /var/www,/~bob=/home/bob. That means that root directory depends on URI. 01534 // This function returns root dir for given URI. 01535 static int get_document_root(const struct mg_connection *conn, 01536 struct vec *document_root) { 01537 const char *root, *uri; 01538 int len_of_matched_uri; 01539 struct vec uri_vec, path_vec; 01540 01541 uri = conn->request_info.uri; 01542 len_of_matched_uri = 0; 01543 root = next_option(conn->ctx->config[DOCUMENT_ROOT], document_root, NULL); 01544 01545 while ((root = next_option(root, &uri_vec, &path_vec)) != NULL) { 01546 if (memcmp(uri, uri_vec.ptr, uri_vec.len) == 0) { 01547 *document_root = path_vec; 01548 len_of_matched_uri = uri_vec.len; 01549 break; 01550 } 01551 } 01552 01553 return len_of_matched_uri; 01554 } 01555 01556 static void convert_uri_to_file_name(struct mg_connection *conn, 01557 const char *uri, char *buf, 01558 size_t buf_len) { 01559 struct vec vec; 01560 int match_len; 01561 01562 match_len = get_document_root(conn, &vec); 01563 mg_snprintf(conn, buf, buf_len, "%.*s%s", vec.len, vec.ptr, uri + match_len); 01564 01565 #ifdef _WIN32 01566 change_slashes_to_backslashes(buf); 01567 #endif /* _WIN32 */ 01568 01569 DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr)); 01570 } 01571 01572 static int sslize(struct mg_connection *conn, int (*func)(SSL *)) { 01573 return (conn->ssl = SSL_new(conn->ctx->ssl_ctx)) != NULL && 01574 SSL_set_fd(conn->ssl, conn->client.sock) == 1 && 01575 func(conn->ssl) == 1; 01576 } 01577 01578 static struct mg_connection *mg_connect(struct mg_connection *conn, 01579 const char *host, int port, int use_ssl) { 01580 struct mg_connection *newconn = NULL; 01581 struct sockaddr_in sin; 01582 struct hostent *he; 01583 int sock; 01584 01585 if (conn->ctx->ssl_ctx == NULL && use_ssl) { 01586 cry(conn, "%s: SSL is not initialized", __func__); 01587 } else if ((he = gethostbyname(host)) == NULL) { 01588 cry(conn, "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO)); 01589 } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { 01590 cry(conn, "%s: socket: %s", __func__, strerror(ERRNO)); 01591 } else { 01592 sin.sin_family = AF_INET; 01593 sin.sin_port = htons((uint16_t) port); 01594 sin.sin_addr = * (struct in_addr *) he->h_addr_list[0]; 01595 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) { 01596 cry(conn, "%s: connect(%s:%d): %s", __func__, host, port, 01597 strerror(ERRNO)); 01598 closesocket(sock); 01599 } else if ((newconn = calloc(1, sizeof(*newconn))) == NULL) { 01600 cry(conn, "%s: calloc: %s", __func__, strerror(ERRNO)); 01601 closesocket(sock); 01602 } else { 01603 newconn->client.sock = sock; 01604 newconn->client.rsa.u.sin = sin; 01605 if (use_ssl) { 01606 sslize(newconn, SSL_connect); 01607 } 01608 } 01609 } 01610 01611 return newconn; 01612 } 01613 01614 // Check whether full request is buffered. Return: 01615 // -1 if request is malformed 01616 // 0 if request is not yet fully buffered 01617 // >0 actual request length, including last \r\n\r\n 01618 static int get_request_len(const char *buf, int buflen) { 01619 const char *s, *e; 01620 int len = 0; 01621 01622 DEBUG_TRACE(("buf: %p, len: %d", buf, buflen)); 01623 for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++) 01624 // Control characters are not allowed but >=128 is. 01625 if (!isprint(* (const unsigned char *) s) && *s != '\r' && 01626 *s != '\n' && * (const unsigned char *) s < 128) { 01627 len = -1; 01628 } else if (s[0] == '\n' && s[1] == '\n') { 01629 len = (int) (s - buf) + 2; 01630 } else if (s[0] == '\n' && &s[1] < e && 01631 s[1] == '\r' && s[2] == '\n') { 01632 len = (int) (s - buf) + 3; 01633 } 01634 01635 return len; 01636 } 01637 01638 // Convert month to the month number. Return -1 on error, or month number 01639 static int month_number_to_month_name(const char *s) { 01640 size_t i; 01641 01642 for (i = 0; i < ARRAY_SIZE(month_names); i++) 01643 if (!strcmp(s, month_names[i])) 01644 return (int) i; 01645 01646 return -1; 01647 } 01648 01649 // Parse date-time string, and return the corresponding time_t value 01650 static time_t parse_date_string(const char *s) { 01651 time_t current_time; 01652 struct tm tm, *tmp; 01653 char mon[32]; 01654 int sec, min, hour, mday, month, year; 01655 01656 (void) memset(&tm, 0, sizeof(tm)); 01657 sec = min = hour = mday = month = year = 0; 01658 01659 if (((sscanf(s, "%d/%3s/%d %d:%d:%d", 01660 &mday, mon, &year, &hour, &min, &sec) == 6) || 01661 (sscanf(s, "%d %3s %d %d:%d:%d", 01662 &mday, mon, &year, &hour, &min, &sec) == 6) || 01663 (sscanf(s, "%*3s, %d %3s %d %d:%d:%d", 01664 &mday, mon, &year, &hour, &min, &sec) == 6) || 01665 (sscanf(s, "%d-%3s-%d %d:%d:%d", 01666 &mday, mon, &year, &hour, &min, &sec) == 6)) && 01667 (month = month_number_to_month_name(mon)) != -1) { 01668 tm.tm_mday = mday; 01669 tm.tm_mon = month; 01670 tm.tm_year = year; 01671 tm.tm_hour = hour; 01672 tm.tm_min = min; 01673 tm.tm_sec = sec; 01674 } 01675 01676 if (tm.tm_year > 1900) { 01677 tm.tm_year -= 1900; 01678 } else if (tm.tm_year < 70) { 01679 tm.tm_year += 100; 01680 } 01681 01682 // Set Daylight Saving Time field 01683 current_time = time(NULL); 01684 tmp = localtime(¤t_time); 01685 tm.tm_isdst = tmp->tm_isdst; 01686 01687 return mktime(&tm); 01688 } 01689 01690 // Protect against directory disclosure attack by removing '..', 01691 // excessive '/' and '\' characters 01692 static void remove_double_dots_and_double_slashes(char *s) { 01693 char *p = s; 01694 01695 while (*s != '\0') { 01696 *p++ = *s++; 01697 if (s[-1] == '/' || s[-1] == '\\') { 01698 // Skip all following slashes and backslashes 01699 while (*s == '/' || *s == '\\') { 01700 s++; 01701 } 01702 01703 // Skip all double-dots 01704 while (*s == '.' && s[1] == '.') { 01705 s += 2; 01706 } 01707 } 01708 } 01709 *p = '\0'; 01710 } 01711 01712 static const struct { 01713 const char *extension; 01714 size_t ext_len; 01715 const char *mime_type; 01716 size_t mime_type_len; 01717 } builtin_mime_types[] = { 01718 {".html", 5, "text/html", 9}, 01719 {".htm", 4, "text/html", 9}, 01720 {".shtm", 5, "text/html", 9}, 01721 {".shtml", 6, "text/html", 9}, 01722 {".css", 4, "text/css", 8}, 01723 {".js", 3, "application/x-javascript", 24}, 01724 {".ico", 4, "image/x-icon", 12}, 01725 {".gif", 4, "image/gif", 9}, 01726 {".jpg", 4, "image/jpeg", 10}, 01727 {".jpeg", 5, "image/jpeg", 10}, 01728 {".png", 4, "image/png", 9}, 01729 {".svg", 4, "image/svg+xml", 13}, 01730 {".torrent", 8, "application/x-bittorrent", 24}, 01731 {".wav", 4, "audio/x-wav", 11}, 01732 {".mp3", 4, "audio/x-mp3", 11}, 01733 {".mid", 4, "audio/mid", 9}, 01734 {".m3u", 4, "audio/x-mpegurl", 15}, 01735 {".ram", 4, "audio/x-pn-realaudio", 20}, 01736 {".xml", 4, "text/xml", 8}, 01737 {".xslt", 5, "application/xml", 15}, 01738 {".ra", 3, "audio/x-pn-realaudio", 20}, 01739 {".doc", 4, "application/msword", 19}, 01740 {".exe", 4, "application/octet-stream", 24}, 01741 {".zip", 4, "application/x-zip-compressed", 28}, 01742 {".xls", 4, "application/excel", 17}, 01743 {".tgz", 4, "application/x-tar-gz", 20}, 01744 {".tar", 4, "application/x-tar", 17}, 01745 {".gz", 3, "application/x-gunzip", 20}, 01746 {".arj", 4, "application/x-arj-compressed", 28}, 01747 {".rar", 4, "application/x-arj-compressed", 28}, 01748 {".rtf", 4, "application/rtf", 15}, 01749 {".pdf", 4, "application/pdf", 15}, 01750 {".swf", 4, "application/x-shockwave-flash",29}, 01751 {".mpg", 4, "video/mpeg", 10}, 01752 {".mpeg", 5, "video/mpeg", 10}, 01753 {".asf", 4, "video/x-ms-asf", 14}, 01754 {".avi", 4, "video/x-msvideo", 15}, 01755 {".bmp", 4, "image/bmp", 9}, 01756 {NULL, 0, NULL, 0} 01757 }; 01758 01759 // Look at the "path" extension and figure what mime type it has. 01760 // Store mime type in the vector. 01761 static void get_mime_type(struct mg_context *ctx, const char *path, 01762 struct vec *vec) { 01763 struct vec ext_vec, mime_vec; 01764 const char *list, *ext; 01765 size_t i, path_len; 01766 01767 path_len = strlen(path); 01768 01769 // Scan user-defined mime types first, in case user wants to 01770 // override default mime types. 01771 list = ctx->config[EXTRA_MIME_TYPES]; 01772 while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) { 01773 // ext now points to the path suffix 01774 ext = path + path_len - ext_vec.len; 01775 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) { 01776 *vec = mime_vec; 01777 return; 01778 } 01779 } 01780 01781 // Now scan built-in mime types 01782 for (i = 0; builtin_mime_types[i].extension != NULL; i++) { 01783 ext = path + (path_len - builtin_mime_types[i].ext_len); 01784 if (path_len > builtin_mime_types[i].ext_len && 01785 mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) { 01786 vec->ptr = builtin_mime_types[i].mime_type; 01787 vec->len = builtin_mime_types[i].mime_type_len; 01788 return; 01789 } 01790 } 01791 01792 // Nothing found. Fall back to "text/plain" 01793 vec->ptr = "text/plain"; 01794 vec->len = 10; 01795 } 01796 01797 #ifndef HAVE_MD5 01798 typedef struct MD5Context { 01799 uint32_t buf[4]; 01800 uint32_t bits[2]; 01801 unsigned char in[64]; 01802 } MD5_CTX; 01803 01804 #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234) 01805 #define byteReverse(buf, len) // Do nothing 01806 #else 01807 static void byteReverse(unsigned char *buf, unsigned longs) { 01808 uint32_t t; 01809 do { 01810 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | 01811 ((unsigned) buf[1] << 8 | buf[0]); 01812 *(uint32_t *) buf = t; 01813 buf += 4; 01814 } while (--longs); 01815 } 01816 #endif 01817 01818 #define F1(x, y, z) (z ^ (x & (y ^ z))) 01819 #define F2(x, y, z) F1(z, x, y) 01820 #define F3(x, y, z) (x ^ y ^ z) 01821 #define F4(x, y, z) (y ^ (x | ~z)) 01822 01823 #define MD5STEP(f, w, x, y, z, data, s) \ 01824 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) 01825 01826 // Start MD5 accumulation. Set bit count to 0 and buffer to mysterious 01827 // initialization constants. 01828 static void MD5Init(MD5_CTX *ctx) { 01829 ctx->buf[0] = 0x67452301; 01830 ctx->buf[1] = 0xefcdab89; 01831 ctx->buf[2] = 0x98badcfe; 01832 ctx->buf[3] = 0x10325476; 01833 01834 ctx->bits[0] = 0; 01835 ctx->bits[1] = 0; 01836 } 01837 01838 static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { 01839 register uint32_t a, b, c, d; 01840 01841 a = buf[0]; 01842 b = buf[1]; 01843 c = buf[2]; 01844 d = buf[3]; 01845 01846 MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); 01847 MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); 01848 MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); 01849 MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); 01850 MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); 01851 MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); 01852 MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); 01853 MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); 01854 MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); 01855 MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); 01856 MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); 01857 MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); 01858 MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); 01859 MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); 01860 MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); 01861 MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); 01862 01863 MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); 01864 MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); 01865 MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); 01866 MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); 01867 MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); 01868 MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); 01869 MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); 01870 MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); 01871 MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); 01872 MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); 01873 MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); 01874 MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); 01875 MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); 01876 MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); 01877 MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); 01878 MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); 01879 01880 MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); 01881 MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); 01882 MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); 01883 MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); 01884 MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); 01885 MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); 01886 MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); 01887 MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); 01888 MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); 01889 MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); 01890 MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); 01891 MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); 01892 MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); 01893 MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); 01894 MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); 01895 MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); 01896 01897 MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); 01898 MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); 01899 MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); 01900 MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); 01901 MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); 01902 MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); 01903 MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); 01904 MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); 01905 MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); 01906 MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); 01907 MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); 01908 MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); 01909 MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); 01910 MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); 01911 MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); 01912 MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); 01913 01914 buf[0] += a; 01915 buf[1] += b; 01916 buf[2] += c; 01917 buf[3] += d; 01918 } 01919 01920 static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) { 01921 uint32_t t; 01922 01923 t = ctx->bits[0]; 01924 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) 01925 ctx->bits[1]++; 01926 ctx->bits[1] += len >> 29; 01927 01928 t = (t >> 3) & 0x3f; 01929 01930 if (t) { 01931 unsigned char *p = (unsigned char *) ctx->in + t; 01932 01933 t = 64 - t; 01934 if (len < t) { 01935 memcpy(p, buf, len); 01936 return; 01937 } 01938 memcpy(p, buf, t); 01939 byteReverse(ctx->in, 16); 01940 MD5Transform(ctx->buf, (uint32_t *) ctx->in); 01941 buf += t; 01942 len -= t; 01943 } 01944 01945 while (len >= 64) { 01946 memcpy(ctx->in, buf, 64); 01947 byteReverse(ctx->in, 16); 01948 MD5Transform(ctx->buf, (uint32_t *) ctx->in); 01949 buf += 64; 01950 len -= 64; 01951 } 01952 01953 memcpy(ctx->in, buf, len); 01954 } 01955 01956 static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) { 01957 unsigned count; 01958 unsigned char *p; 01959 01960 count = (ctx->bits[0] >> 3) & 0x3F; 01961 01962 p = ctx->in + count; 01963 *p++ = 0x80; 01964 count = 64 - 1 - count; 01965 if (count < 8) { 01966 memset(p, 0, count); 01967 byteReverse(ctx->in, 16); 01968 MD5Transform(ctx->buf, (uint32_t *) ctx->in); 01969 memset(ctx->in, 0, 56); 01970 } else { 01971 memset(p, 0, count - 8); 01972 } 01973 byteReverse(ctx->in, 14); 01974 01975 ((uint32_t *) ctx->in)[14] = ctx->bits[0]; 01976 ((uint32_t *) ctx->in)[15] = ctx->bits[1]; 01977 01978 MD5Transform(ctx->buf, (uint32_t *) ctx->in); 01979 byteReverse((unsigned char *) ctx->buf, 4); 01980 memcpy(digest, ctx->buf, 16); 01981 memset((char *) ctx, 0, sizeof(ctx)); 01982 } 01983 #endif // !HAVE_MD5 01984 01985 // Stringify binary data. Output buffer must be twice as big as input, 01986 // because each byte takes 2 bytes in string representation 01987 static void bin2str(char *to, const unsigned char *p, size_t len) { 01988 static const char *hex = "0123456789abcdef"; 01989 01990 for (; len--; p++) { 01991 *to++ = hex[p[0] >> 4]; 01992 *to++ = hex[p[0] & 0x0f]; 01993 } 01994 *to = '\0'; 01995 } 01996 01997 // Return stringified MD5 hash for list of vectors. Buffer must be 33 bytes. 01998 void mg_md5(char *buf, ...) { 01999 unsigned char hash[16]; 02000 const char *p; 02001 va_list ap; 02002 MD5_CTX ctx; 02003 02004 MD5Init(&ctx); 02005 02006 va_start(ap, buf); 02007 while ((p = va_arg(ap, const char *)) != NULL) { 02008 MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p)); 02009 } 02010 va_end(ap); 02011 02012 MD5Final(hash, &ctx); 02013 bin2str(buf, hash, sizeof(hash)); 02014 } 02015 02016 // Check the user's password, return 1 if OK 02017 static int check_password(const char *method, const char *ha1, const char *uri, 02018 const char *nonce, const char *nc, const char *cnonce, 02019 const char *qop, const char *response) { 02020 char ha2[32 + 1], expected_response[32 + 1]; 02021 02022 // Some of the parameters may be NULL 02023 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL || 02024 qop == NULL || response == NULL) { 02025 return 0; 02026 } 02027 02028 // NOTE(lsm): due to a bug in MSIE, we do not compare the URI 02029 // TODO(lsm): check for authentication timeout 02030 if (// strcmp(dig->uri, c->ouri) != 0 || 02031 strlen(response) != 32 02032 // || now - strtoul(dig->nonce, NULL, 10) > 3600 02033 ) { 02034 return 0; 02035 } 02036 02037 mg_md5(ha2, method, ":", uri, NULL); 02038 mg_md5(expected_response, ha1, ":", nonce, ":", nc, 02039 ":", cnonce, ":", qop, ":", ha2, NULL); 02040 02041 return mg_strcasecmp(response, expected_response) == 0; 02042 } 02043 02044 // Use the global passwords file, if specified by auth_gpass option, 02045 // or search for .htpasswd in the requested directory. 02046 static FILE *open_auth_file(struct mg_connection *conn, const char *path) { 02047 struct mg_context *ctx = conn->ctx; 02048 char name[PATH_MAX]; 02049 const char *p, *e; 02050 struct mgstat st; 02051 FILE *fp; 02052 02053 if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) { 02054 // Use global passwords file 02055 fp = mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r"); 02056 if (fp == NULL) 02057 cry(fc(ctx), "fopen(%s): %s", 02058 ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO)); 02059 } else if (!mg_stat(path, &st) && st.is_directory) { 02060 (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s", 02061 path, DIRSEP, PASSWORDS_FILE_NAME); 02062 fp = mg_fopen(name, "r"); 02063 } else { 02064 // Try to find .htpasswd in requested directory. 02065 for (p = path, e = p + strlen(p) - 1; e > p; e--) 02066 if (IS_DIRSEP_CHAR(*e)) 02067 break; 02068 (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s", 02069 (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME); 02070 fp = mg_fopen(name, "r"); 02071 } 02072 02073 return fp; 02074 } 02075 02076 // Parsed Authorization header 02077 struct ah { 02078 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce; 02079 }; 02080 02081 static int parse_auth_header(struct mg_connection *conn, char *buf, 02082 size_t buf_size, struct ah *ah) { 02083 char *name, *value, *s; 02084 const char *auth_header; 02085 02086 if ((auth_header = mg_get_header(conn, "Authorization")) == NULL || 02087 mg_strncasecmp(auth_header, "Digest ", 7) != 0) { 02088 return 0; 02089 } 02090 02091 // Make modifiable copy of the auth header 02092 (void) mg_strlcpy(buf, auth_header + 7, buf_size); 02093 02094 s = buf; 02095 (void) memset(ah, 0, sizeof(*ah)); 02096 02097 // Parse authorization header 02098 for (;;) { 02099 // Gobble initial spaces 02100 while (isspace(* (unsigned char *) s)) { 02101 s++; 02102 } 02103 name = skip_quoted(&s, "=", " ", 0); 02104 /* Value is either quote-delimited, or ends at first comma or space. */ 02105 if (s[0] == '\"') { 02106 s++; 02107 value = skip_quoted(&s, "\"", " ", '\\'); 02108 if (s[0] == ',') { 02109 s++; 02110 } 02111 } 02112 else 02113 { 02114 value = skip_quoted(&s, ", ", " ", 0); // IE uses commas, FF uses spaces 02115 } 02116 if (*name == '\0') { 02117 break; 02118 } 02119 02120 if (!strcmp(name, "username")) { 02121 ah->user = value; 02122 } else if (!strcmp(name, "cnonce")) { 02123 ah->cnonce = value; 02124 } else if (!strcmp(name, "response")) { 02125 ah->response = value; 02126 } else if (!strcmp(name, "uri")) { 02127 ah->uri = value; 02128 } else if (!strcmp(name, "qop")) { 02129 ah->qop = value; 02130 } else if (!strcmp(name, "nc")) { 02131 ah->nc = value; 02132 } else if (!strcmp(name, "nonce")) { 02133 ah->nonce = value; 02134 } 02135 } 02136 02137 // CGI needs it as REMOTE_USER 02138 if (ah->user != NULL) { 02139 conn->request_info.remote_user = mg_strdup(ah->user); 02140 } else { 02141 return 0; 02142 } 02143 02144 return 1; 02145 } 02146 02147 // Authorize against the opened passwords file. Return 1 if authorized. 02148 static int authorize(struct mg_connection *conn, FILE *fp) { 02149 struct ah ah; 02150 char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ]; 02151 02152 if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) { 02153 return 0; 02154 } 02155 02156 // Loop over passwords file 02157 while (fgets(line, sizeof(line), fp) != NULL) { 02158 if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) { 02159 continue; 02160 } 02161 02162 if (!strcmp(ah.user, f_user) && 02163 !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain)) 02164 return check_password( 02165 conn->request_info.request_method, 02166 ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop, 02167 ah.response); 02168 } 02169 02170 return 0; 02171 } 02172 02173 // Return 1 if request is authorised, 0 otherwise. 02174 static int check_authorization(struct mg_connection *conn, const char *path) { 02175 FILE *fp; 02176 char fname[PATH_MAX]; 02177 struct vec uri_vec, filename_vec; 02178 const char *list; 02179 int authorized; 02180 02181 fp = NULL; 02182 authorized = 1; 02183 02184 list = conn->ctx->config[PROTECT_URI]; 02185 while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) { 02186 if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) { 02187 (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s", 02188 filename_vec.len, filename_vec.ptr); 02189 if ((fp = mg_fopen(fname, "r")) == NULL) { 02190 cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno)); 02191 } 02192 break; 02193 } 02194 } 02195 02196 if (fp == NULL) { 02197 fp = open_auth_file(conn, path); 02198 } 02199 02200 if (fp != NULL) { 02201 authorized = authorize(conn, fp); 02202 (void) fclose(fp); 02203 } 02204 02205 return authorized; 02206 } 02207 02208 static void send_authorization_request(struct mg_connection *conn) { 02209 conn->request_info.status_code = 401; 02210 (void) mg_printf(conn, 02211 "HTTP/1.1 401 Unauthorized\r\n" 02212 "WWW-Authenticate: Digest qop=\"auth\", " 02213 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n", 02214 conn->ctx->config[AUTHENTICATION_DOMAIN], 02215 (unsigned long) time(NULL)); 02216 } 02217 02218 static int is_authorized_for_put(struct mg_connection *conn) { 02219 FILE *fp; 02220 int ret = 0; 02221 02222 fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL : 02223 mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r"); 02224 02225 if (fp != NULL) { 02226 ret = authorize(conn, fp); 02227 (void) fclose(fp); 02228 } 02229 02230 return ret; 02231 } 02232 02233 int mg_modify_passwords_file(struct mg_context *ctx, const char *fname, 02234 const char *user, const char *pass) { 02235 int found; 02236 char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX]; 02237 const char *domain; 02238 FILE *fp, *fp2; 02239 02240 found = 0; 02241 fp = fp2 = NULL; 02242 domain = ctx->config[AUTHENTICATION_DOMAIN]; 02243 02244 // Regard empty password as no password - remove user record. 02245 if (pass[0] == '\0') { 02246 pass = NULL; 02247 } 02248 02249 (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname); 02250 02251 // Create the file if does not exist 02252 if ((fp = mg_fopen(fname, "a+")) != NULL) { 02253 (void) fclose(fp); 02254 } 02255 02256 // Open the given file and temporary file 02257 if ((fp = mg_fopen(fname, "r")) == NULL) { 02258 cry(fc(ctx), "Cannot open %s: %s", fname, strerror(errno)); 02259 return 0; 02260 } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) { 02261 cry(fc(ctx), "Cannot open %s: %s", tmp, strerror(errno)); 02262 return 0; 02263 } 02264 02265 // Copy the stuff to temporary file 02266 while (fgets(line, sizeof(line), fp) != NULL) { 02267 if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) { 02268 continue; 02269 } 02270 02271 if (!strcmp(u, user) && !strcmp(d, domain)) { 02272 found++; 02273 if (pass != NULL) { 02274 mg_md5(ha1, user, ":", domain, ":", pass, NULL); 02275 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); 02276 } 02277 } else { 02278 (void) fprintf(fp2, "%s", line); 02279 } 02280 } 02281 02282 // If new user, just add it 02283 if (!found && pass != NULL) { 02284 mg_md5(ha1, user, ":", domain, ":", pass, NULL); 02285 (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1); 02286 } 02287 02288 // Close files 02289 (void) fclose(fp); 02290 (void) fclose(fp2); 02291 02292 // Put the temp file in place of real file 02293 (void) mg_remove(fname); 02294 (void) mg_rename(tmp, fname); 02295 02296 return 1; 02297 } 02298 02299 struct de { 02300 struct mg_connection *conn; 02301 char *file_name; 02302 struct mgstat st; 02303 }; 02304 02305 static void url_encode(const char *src, char *dst, size_t dst_len) { 02306 static const char *dont_escape = "._-$,;~()"; 02307 static const char *hex = "0123456789abcdef"; 02308 const char *end = dst + dst_len - 1; 02309 02310 for (; *src != '\0' && dst < end; src++, dst++) { 02311 if (isalnum(*(const unsigned char *) src) || 02312 strchr(dont_escape, * (const unsigned char *) src) != NULL) { 02313 *dst = *src; 02314 } else if (dst + 2 < end) { 02315 dst[0] = '%'; 02316 dst[1] = hex[(* (const unsigned char *) src) >> 4]; 02317 dst[2] = hex[(* (const unsigned char *) src) & 0xf]; 02318 dst += 2; 02319 } 02320 } 02321 02322 *dst = '\0'; 02323 } 02324 02325 static void print_dir_entry(struct de *de) { 02326 char size[64], mod[64], href[PATH_MAX]; 02327 02328 if (de->st.is_directory) { 02329 (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]"); 02330 } else { 02331 // We use (signed) cast below because MSVC 6 compiler cannot 02332 // convert unsigned __int64 to double. Sigh. 02333 if (de->st.size < 1024) { 02334 (void) mg_snprintf(de->conn, size, sizeof(size), 02335 "%lu", (unsigned long) de->st.size); 02336 } else if (de->st.size < 1024 * 1024) { 02337 (void) mg_snprintf(de->conn, size, sizeof(size), 02338 "%.1fk", (double) de->st.size / 1024.0); 02339 } else if (de->st.size < 1024 * 1024 * 1024) { 02340 (void) mg_snprintf(de->conn, size, sizeof(size), 02341 "%.1fM", (double) de->st.size / 1048576); 02342 } else { 02343 (void) mg_snprintf(de->conn, size, sizeof(size), 02344 "%.1fG", (double) de->st.size / 1073741824); 02345 } 02346 } 02347 (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime)); 02348 url_encode(de->file_name, href, sizeof(href)); 02349 de->conn->num_bytes_sent += mg_printf(de->conn, 02350 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>" 02351 "<td> %s</td><td> %s</td></tr>\n", 02352 de->conn->request_info.uri, href, de->st.is_directory ? "/" : "", 02353 de->file_name, de->st.is_directory ? "/" : "", mod, size); 02354 } 02355 02356 // This function is called from send_directory() and used for 02357 // sorting directory entries by size, or name, or modification time. 02358 // On windows, __cdecl specification is needed in case if project is built 02359 // with __stdcall convention. qsort always requires __cdels callback. 02360 static int WINCDECL compare_dir_entries(const void *p1, const void *p2) { 02361 const struct de *a = (const struct de *) p1, *b = (const struct de *) p2; 02362 const char *query_string = a->conn->request_info.query_string; 02363 int cmp_result = 0; 02364 02365 if (query_string == NULL) { 02366 query_string = "na"; 02367 } 02368 02369 if (a->st.is_directory && !b->st.is_directory) { 02370 return -1; // Always put directories on top 02371 } else if (!a->st.is_directory && b->st.is_directory) { 02372 return 1; // Always put directories on top 02373 } else if (*query_string == 'n') { 02374 cmp_result = strcmp(a->file_name, b->file_name); 02375 } else if (*query_string == 's') { 02376 cmp_result = a->st.size == b->st.size ? 0 : 02377 a->st.size > b->st.size ? 1 : -1; 02378 } else if (*query_string == 'd') { 02379 cmp_result = a->st.mtime == b->st.mtime ? 0 : 02380 a->st.mtime > b->st.mtime ? 1 : -1; 02381 } 02382 02383 return query_string[1] == 'd' ? -cmp_result : cmp_result; 02384 } 02385 02386 static void handle_directory_request(struct mg_connection *conn, 02387 const char *dir) { 02388 struct dirent *dp; 02389 DIR *dirp; 02390 struct de *entries = NULL; 02391 char path[PATH_MAX]; 02392 int i, sort_direction, num_entries = 0, arr_size = 128; 02393 02394 if ((dirp = opendir(dir)) == NULL) { 02395 send_http_error(conn, 500, "Cannot open directory", 02396 "Error: opendir(%s): %s", path, strerror(ERRNO)); 02397 return; 02398 } 02399 02400 (void) mg_printf(conn, "%s", 02401 "HTTP/1.1 200 OK\r\n" 02402 "Connection: close\r\n" 02403 "Content-Type: text/html; charset=utf-8\r\n\r\n"); 02404 02405 sort_direction = conn->request_info.query_string != NULL && 02406 conn->request_info.query_string[1] == 'd' ? 'a' : 'd'; 02407 02408 while ((dp = readdir(dirp)) != NULL) { 02409 02410 // Do not show current dir and passwords file 02411 if (!strcmp(dp->d_name, ".") || 02412 !strcmp(dp->d_name, "..") || 02413 !strcmp(dp->d_name, PASSWORDS_FILE_NAME)) 02414 continue; 02415 02416 if (entries == NULL || num_entries >= arr_size) { 02417 arr_size *= 2; 02418 entries = (struct de *) realloc(entries, 02419 arr_size * sizeof(entries[0])); 02420 } 02421 02422 if (entries == NULL) { 02423 send_http_error(conn, 500, "Cannot open directory", 02424 "%s", "Error: cannot allocate memory"); 02425 return; 02426 } 02427 02428 mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name); 02429 02430 // If we don't memset stat structure to zero, mtime will have 02431 // garbage and strftime() will segfault later on in 02432 // print_dir_entry(). memset is required only if mg_stat() 02433 // fails. For more details, see 02434 // http://code.google.com/p/mongoose/issues/detail?id=79 02435 if (mg_stat(path, &entries[num_entries].st) != 0) { 02436 memset(&entries[num_entries].st, 0, sizeof(entries[num_entries].st)); 02437 } 02438 02439 entries[num_entries].conn = conn; 02440 entries[num_entries].file_name = mg_strdup(dp->d_name); 02441 num_entries++; 02442 } 02443 (void) closedir(dirp); 02444 02445 conn->num_bytes_sent += mg_printf(conn, 02446 "<html><head><title>Index of %s</title>" 02447 "<style>th {text-align: left;}</style></head>" 02448 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">" 02449 "<tr><th><a href=\"?n%c\">Name</a></th>" 02450 "<th><a href=\"?d%c\">Modified</a></th>" 02451 "<th><a href=\"?s%c\">Size</a></th></tr>" 02452 "<tr><td colspan=\"3\"><hr></td></tr>", 02453 conn->request_info.uri, conn->request_info.uri, 02454 sort_direction, sort_direction, sort_direction); 02455 02456 // Print first entry - link to a parent directory 02457 conn->num_bytes_sent += mg_printf(conn, 02458 "<tr><td><a href=\"%s%s\">%s</a></td>" 02459 "<td> %s</td><td> %s</td></tr>\n", 02460 conn->request_info.uri, "..", "Parent directory", "-", "-"); 02461 02462 // Sort and print directory entries 02463 qsort(entries, (size_t)num_entries, sizeof(entries[0]), compare_dir_entries); 02464 for (i = 0; i < num_entries; i++) { 02465 print_dir_entry(&entries[i]); 02466 free(entries[i].file_name); 02467 } 02468 free(entries); 02469 02470 conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>"); 02471 conn->request_info.status_code = 200; 02472 } 02473 02474 // Send len bytes from the opened file to the client. 02475 static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) { 02476 char buf[BUFSIZ]; 02477 int to_read, num_read, num_written; 02478 02479 while (len > 0) { 02480 // Calculate how much to read from the file in the buffer 02481 to_read = sizeof(buf); 02482 if ((int64_t) to_read > len) 02483 to_read = (int) len; 02484 02485 // Read from file, exit the loop on error 02486 if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0) 02487 break; 02488 02489 // Send read bytes to the client, exit the loop on error 02490 if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read) 02491 break; 02492 02493 // Both read and were successful, adjust counters 02494 conn->num_bytes_sent += num_written; 02495 len -= num_written; 02496 } 02497 } 02498 02499 static int parse_range_header(const char *header, int64_t *a, int64_t *b) { 02500 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b); 02501 } 02502 02503 static void handle_file_request(struct mg_connection *conn, const char *path, 02504 struct mgstat *stp) { 02505 char date[64], lm[64], etag[64], range[64]; 02506 const char *fmt = "%a, %d %b %Y %H:%M:%S %Z", *msg = "OK", *hdr; 02507 time_t curtime = time(NULL); 02508 int64_t cl, r1, r2; 02509 struct vec mime_vec; 02510 FILE *fp; 02511 int n; 02512 02513 get_mime_type(conn->ctx, path, &mime_vec); 02514 cl = stp->size; 02515 conn->request_info.status_code = 200; 02516 range[0] = '\0'; 02517 02518 if ((fp = mg_fopen(path, "rb")) == NULL) { 02519 send_http_error(conn, 500, http_500_error, 02520 "fopen(%s): %s", path, strerror(ERRNO)); 02521 return; 02522 } 02523 set_close_on_exec(fileno(fp)); 02524 02525 // If Range: header specified, act accordingly 02526 r1 = r2 = 0; 02527 hdr = mg_get_header(conn, "Range"); 02528 if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) { 02529 conn->request_info.status_code = 206; 02530 (void) fseeko(fp, (off_t) r1, SEEK_SET); 02531 cl = n == 2 ? r2 - r1 + 1: cl - r1; 02532 (void) mg_snprintf(conn, range, sizeof(range), 02533 "Content-Range: bytes " 02534 "%" INT64_FMT "-%" 02535 INT64_FMT "/%" INT64_FMT "\r\n", 02536 r1, r1 + cl - 1, stp->size); 02537 msg = "Partial Content"; 02538 } 02539 02540 // Prepare Etag, Date, Last-Modified headers 02541 (void) strftime(date, sizeof(date), fmt, localtime(&curtime)); 02542 (void) strftime(lm, sizeof(lm), fmt, localtime(&stp->mtime)); 02543 (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx", 02544 (unsigned long) stp->mtime, (unsigned long) stp->size); 02545 02546 (void) mg_printf(conn, 02547 "HTTP/1.1 %d %s\r\n" 02548 "Date: %s\r\n" 02549 "Last-Modified: %s\r\n" 02550 "Etag: \"%s\"\r\n" 02551 "Content-Type: %.*s\r\n" 02552 "Content-Length: %" INT64_FMT "\r\n" 02553 "Connection: %s\r\n" 02554 "Accept-Ranges: bytes\r\n" 02555 "%s\r\n", 02556 conn->request_info.status_code, msg, date, lm, etag, 02557 mime_vec.len, mime_vec.ptr, cl, suggest_connection_header(conn), range); 02558 02559 if (strcmp(conn->request_info.request_method, "HEAD") != 0) { 02560 send_file_data(conn, fp, cl); 02561 } 02562 (void) fclose(fp); 02563 } 02564 02565 // Parse HTTP headers from the given buffer, advance buffer to the point 02566 // where parsing stopped. 02567 static void parse_http_headers(char **buf, struct mg_request_info *ri) { 02568 int i; 02569 02570 for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) { 02571 ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0); 02572 ri->http_headers[i].value = skip(buf, "\r\n"); 02573 if (ri->http_headers[i].name[0] == '\0') 02574 break; 02575 ri->num_headers = i + 1; 02576 } 02577 } 02578 02579 static int is_valid_http_method(const char *method) { 02580 return !strcmp(method, "GET") || !strcmp(method, "POST") || 02581 !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || 02582 !strcmp(method, "PUT") || !strcmp(method, "DELETE"); 02583 } 02584 02585 // Parse HTTP request, fill in mg_request_info structure. 02586 static int parse_http_request(char *buf, struct mg_request_info *ri) { 02587 int status = 0; 02588 02589 // RFC says that all initial whitespaces should be ingored 02590 while (*buf != '\0' && isspace(* (unsigned char *) buf)) { 02591 buf++; 02592 } 02593 02594 ri->request_method = skip(&buf, " "); 02595 ri->uri = skip(&buf, " "); 02596 ri->http_version = skip(&buf, "\r\n"); 02597 02598 if (is_valid_http_method(ri->request_method) && 02599 strncmp(ri->http_version, "HTTP/", 5) == 0) { 02600 ri->http_version += 5; /* Skip "HTTP/" */ 02601 parse_http_headers(&buf, ri); 02602 status = 1; 02603 } 02604 02605 return status; 02606 } 02607 02608 // Keep reading the input (either opened file descriptor fd, or socket sock, 02609 // or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the 02610 // buffer (which marks the end of HTTP request). Buffer buf may already 02611 // have some data. The length of the data is stored in nread. 02612 // Upon every read operation, increase nread by the number of bytes read. 02613 static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz, 02614 int *nread) { 02615 int n, request_len; 02616 02617 request_len = 0; 02618 while (*nread < bufsiz && request_len == 0) { 02619 n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread); 02620 if (n <= 0) { 02621 break; 02622 } else { 02623 *nread += n; 02624 request_len = get_request_len(buf, *nread); 02625 } 02626 } 02627 02628 return request_len; 02629 } 02630 02631 // For given directory path, substitute it to valid index file. 02632 // Return 0 if index file has been found, -1 if not found. 02633 // If the file is found, it's stats is returned in stp. 02634 static int substitute_index_file(struct mg_connection *conn, char *path, 02635 size_t path_len, struct mgstat *stp) { 02636 const char *list = conn->ctx->config[INDEX_FILES]; 02637 struct mgstat st; 02638 struct vec filename_vec; 02639 size_t n = strlen(path); 02640 int found = 0; 02641 02642 // The 'path' given to us points to the directory. Remove all trailing 02643 // directory separator characters from the end of the path, and 02644 // then append single directory separator character. 02645 while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) { 02646 n--; 02647 } 02648 path[n] = DIRSEP; 02649 02650 // Traverse index files list. For each entry, append it to the given 02651 // path and see if the file exists. If it exists, break the loop 02652 while ((list = next_option(list, &filename_vec, NULL)) != NULL) { 02653 02654 // Ignore too long entries that may overflow path buffer 02655 if (filename_vec.len > path_len - n) 02656 continue; 02657 02658 // Prepare full path to the index file 02659 (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1); 02660 02661 // Does it exist? 02662 if (mg_stat(path, &st) == 0) { 02663 // Yes it does, break the loop 02664 *stp = st; 02665 found = 1; 02666 break; 02667 } 02668 } 02669 02670 // If no index file exists, restore directory path 02671 if (!found) { 02672 path[n] = '\0'; 02673 } 02674 02675 return found; 02676 } 02677 02678 // Return True if we should reply 304 Not Modified. 02679 static int is_not_modified(const struct mg_connection *conn, 02680 const struct mgstat *stp) { 02681 const char *ims = mg_get_header(conn, "If-Modified-Since"); 02682 return ims != NULL && stp->mtime <= parse_date_string(ims); 02683 } 02684 02685 static int forward_body_data(struct mg_connection *conn, FILE *fp, 02686 SOCKET sock, SSL *ssl) { 02687 const char *expect, *buffered; 02688 char buf[BUFSIZ]; 02689 int to_read, nread, buffered_len, success = 0; 02690 02691 expect = mg_get_header(conn, "Expect"); 02692 assert(fp != NULL); 02693 02694 if (conn->content_len == -1) { 02695 send_http_error(conn, 411, "Length Required", ""); 02696 } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) { 02697 send_http_error(conn, 417, "Expectation Failed", ""); 02698 } else { 02699 if (expect != NULL) { 02700 (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n"); 02701 } 02702 02703 buffered = conn->buf + conn->request_len; 02704 buffered_len = conn->data_len - conn->request_len; 02705 assert(buffered_len >= 0); 02706 assert(conn->consumed_content == 0); 02707 02708 if (buffered_len > 0) { 02709 if ((int64_t) buffered_len > conn->content_len) { 02710 buffered_len = (int) conn->content_len; 02711 } 02712 push(fp, sock, ssl, buffered, (int64_t) buffered_len); 02713 conn->consumed_content += buffered_len; 02714 } 02715 02716 while (conn->consumed_content < conn->content_len) { 02717 to_read = sizeof(buf); 02718 if ((int64_t) to_read > conn->content_len - conn->consumed_content) { 02719 to_read = (int) (conn->content_len - conn->consumed_content); 02720 } 02721 nread = pull(NULL, conn->client.sock, conn->ssl, buf, to_read); 02722 if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) { 02723 break; 02724 } 02725 conn->consumed_content += nread; 02726 } 02727 02728 if (conn->consumed_content == conn->content_len) { 02729 success = 1; 02730 } 02731 02732 // Each error code path in this function must send an error 02733 if (!success) { 02734 send_http_error(conn, 577, http_500_error, ""); 02735 } 02736 } 02737 02738 return success; 02739 } 02740 02741 #if !defined(NO_CGI) 02742 // This structure helps to create an environment for the spawned CGI program. 02743 // Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings, 02744 // last element must be NULL. 02745 // However, on Windows there is a requirement that all these VARIABLE=VALUE\0 02746 // strings must reside in a contiguous buffer. The end of the buffer is 02747 // marked by two '\0' characters. 02748 // We satisfy both worlds: we create an envp array (which is vars), all 02749 // entries are actually pointers inside buf. 02750 struct cgi_env_block { 02751 struct mg_connection *conn; 02752 char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer 02753 int len; // Space taken 02754 char *vars[MAX_CGI_ENVIR_VARS]; // char **envp 02755 int nvars; // Number of variables 02756 }; 02757 02758 // Append VARIABLE=VALUE\0 string to the buffer, and add a respective 02759 // pointer into the vars array. 02760 static char *addenv(struct cgi_env_block *block, const char *fmt, ...) { 02761 int n, space; 02762 char *added; 02763 va_list ap; 02764 02765 // Calculate how much space is left in the buffer 02766 space = sizeof(block->buf) - block->len - 2; 02767 assert(space >= 0); 02768 02769 // Make a pointer to the free space int the buffer 02770 added = block->buf + block->len; 02771 02772 // Copy VARIABLE=VALUE\0 string into the free space 02773 va_start(ap, fmt); 02774 n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap); 02775 va_end(ap); 02776 02777 // Make sure we do not overflow buffer and the envp array 02778 if (n > 0 && n < space && 02779 block->nvars < (int) ARRAY_SIZE(block->vars) - 2) { 02780 // Append a pointer to the added string into the envp array 02781 block->vars[block->nvars++] = block->buf + block->len; 02782 // Bump up used length counter. Include \0 terminator 02783 block->len += n + 1; 02784 } 02785 02786 return added; 02787 } 02788 02789 static void prepare_cgi_environment(struct mg_connection *conn, 02790 const char *prog, 02791 struct cgi_env_block *blk) { 02792 const char *s, *slash; 02793 struct vec var_vec, root; 02794 char *p; 02795 int i; 02796 02797 blk->len = blk->nvars = 0; 02798 blk->conn = conn; 02799 02800 get_document_root(conn, &root); 02801 02802 addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]); 02803 addenv(blk, "SERVER_ROOT=%.*s", root.len, root.ptr); 02804 addenv(blk, "DOCUMENT_ROOT=%.*s", root.len, root.ptr); 02805 02806 // Prepare the environment block 02807 addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1"); 02808 addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1"); 02809 addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP 02810 addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.u.sin.sin_port)); 02811 addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method); 02812 addenv(blk, "REMOTE_ADDR=%s", 02813 inet_ntoa(conn->client.rsa.u.sin.sin_addr)); 02814 addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port); 02815 addenv(blk, "REQUEST_URI=%s", conn->request_info.uri); 02816 02817 // SCRIPT_NAME 02818 assert(conn->request_info.uri[0] == '/'); 02819 slash = strrchr(conn->request_info.uri, '/'); 02820 if ((s = strrchr(prog, '/')) == NULL) 02821 s = prog; 02822 addenv(blk, "SCRIPT_NAME=%.*s%s", slash - conn->request_info.uri, 02823 conn->request_info.uri, s); 02824 02825 addenv(blk, "SCRIPT_FILENAME=%s", prog); 02826 addenv(blk, "PATH_TRANSLATED=%s", prog); 02827 addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on"); 02828 02829 if ((s = mg_get_header(conn, "Content-Type")) != NULL) 02830 addenv(blk, "CONTENT_TYPE=%s", s); 02831 02832 if (conn->request_info.query_string != NULL) 02833 addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string); 02834 02835 if ((s = mg_get_header(conn, "Content-Length")) != NULL) 02836 addenv(blk, "CONTENT_LENGTH=%s", s); 02837 02838 if ((s = getenv("PATH")) != NULL) 02839 addenv(blk, "PATH=%s", s); 02840 02841 #if defined(_WIN32) 02842 if ((s = getenv("COMSPEC")) != NULL) 02843 addenv(blk, "COMSPEC=%s", s); 02844 if ((s = getenv("SYSTEMROOT")) != NULL) 02845 addenv(blk, "SYSTEMROOT=%s", s); 02846 #else 02847 if ((s = getenv("LD_LIBRARY_PATH")) != NULL) 02848 addenv(blk, "LD_LIBRARY_PATH=%s", s); 02849 #endif /* _WIN32 */ 02850 02851 if ((s = getenv("PERLLIB")) != NULL) 02852 addenv(blk, "PERLLIB=%s", s); 02853 02854 if (conn->request_info.remote_user != NULL) { 02855 addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user); 02856 addenv(blk, "%s", "AUTH_TYPE=Digest"); 02857 } 02858 02859 // Add all headers as HTTP_* variables 02860 for (i = 0; i < conn->request_info.num_headers; i++) { 02861 p = addenv(blk, "HTTP_%s=%s", 02862 conn->request_info.http_headers[i].name, 02863 conn->request_info.http_headers[i].value); 02864 02865 // Convert variable name into uppercase, and change - to _ 02866 for (; *p != '=' && *p != '\0'; p++) { 02867 if (*p == '-') 02868 *p = '_'; 02869 *p = (char) toupper(* (unsigned char *) p); 02870 } 02871 } 02872 02873 // Add user-specified variables 02874 s = conn->ctx->config[CGI_ENVIRONMENT]; 02875 while ((s = next_option(s, &var_vec, NULL)) != NULL) { 02876 addenv(blk, "%.*s", var_vec.len, var_vec.ptr); 02877 } 02878 02879 blk->vars[blk->nvars++] = NULL; 02880 blk->buf[blk->len++] = '\0'; 02881 02882 assert(blk->nvars < (int) ARRAY_SIZE(blk->vars)); 02883 assert(blk->len > 0); 02884 assert(blk->len < (int) sizeof(blk->buf)); 02885 } 02886 02887 static void handle_cgi_request(struct mg_connection *conn, const char *prog) { 02888 int headers_len, data_len, i, fd_stdin[2], fd_stdout[2]; 02889 const char *status; 02890 char buf[BUFSIZ], *pbuf, dir[PATH_MAX], *p; 02891 struct mg_request_info ri; 02892 struct cgi_env_block blk; 02893 FILE *in, *out; 02894 pid_t pid; 02895 02896 prepare_cgi_environment(conn, prog, &blk); 02897 02898 // CGI must be executed in its own directory. 'dir' must point to the 02899 // directory containing executable program, 'p' must point to the 02900 // executable program name relative to 'dir'. 02901 (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog); 02902 if ((p = strrchr(dir, DIRSEP)) != NULL) { 02903 *p++ = '\0'; 02904 } else { 02905 dir[0] = '.', dir[1] = '\0'; 02906 p = (char *) prog; 02907 } 02908 02909 pid = (pid_t) -1; 02910 fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1; 02911 in = out = NULL; 02912 02913 if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { 02914 send_http_error(conn, 500, http_500_error, 02915 "Cannot create CGI pipe: %s", strerror(ERRNO)); 02916 goto done; 02917 } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars, 02918 fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) { 02919 goto done; 02920 } else if ((in = fdopen(fd_stdin[1], "wb")) == NULL || 02921 (out = fdopen(fd_stdout[0], "rb")) == NULL) { 02922 send_http_error(conn, 500, http_500_error, 02923 "fopen: %s", strerror(ERRNO)); 02924 goto done; 02925 } 02926 02927 setbuf(in, NULL); 02928 setbuf(out, NULL); 02929 02930 // spawn_process() must close those! 02931 // If we don't mark them as closed, close() attempt before 02932 // return from this function throws an exception on Windows. 02933 // Windows does not like when closed descriptor is closed again. 02934 fd_stdin[0] = fd_stdout[1] = -1; 02935 02936 // Send POST data to the CGI process if needed 02937 if (!strcmp(conn->request_info.request_method, "POST") && 02938 !forward_body_data(conn, in, INVALID_SOCKET, NULL)) { 02939 goto done; 02940 } 02941 02942 // Now read CGI reply into a buffer. We need to set correct 02943 // status code, thus we need to see all HTTP headers first. 02944 // Do not send anything back to client, until we buffer in all 02945 // HTTP headers. 02946 data_len = 0; 02947 headers_len = read_request(out, INVALID_SOCKET, NULL, 02948 buf, sizeof(buf), &data_len); 02949 if (headers_len <= 0) { 02950 send_http_error(conn, 500, http_500_error, 02951 "CGI program sent malformed HTTP headers: [%.*s]", 02952 data_len, buf); 02953 goto done; 02954 } 02955 pbuf = buf; 02956 buf[headers_len - 1] = '\0'; 02957 parse_http_headers(&pbuf, &ri); 02958 02959 // Make up and send the status line 02960 status = get_header(&ri, "Status"); 02961 conn->request_info.status_code = status == NULL ? 200 : atoi(status); 02962 (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n", conn->request_info.status_code); 02963 02964 // Send headers 02965 for (i = 0; i < ri.num_headers; i++) { 02966 mg_printf(conn, "%s: %s\r\n", 02967 ri.http_headers[i].name, ri.http_headers[i].value); 02968 } 02969 (void) mg_write(conn, "\r\n", 2); 02970 02971 // Send chunk of data that may be read after the headers 02972 conn->num_bytes_sent += mg_write(conn, buf + headers_len, 02973 (size_t)(data_len - headers_len)); 02974 02975 // Read the rest of CGI output and send to the client 02976 send_file_data(conn, out, INT64_MAX); 02977 02978 done: 02979 if (pid != (pid_t) -1) { 02980 kill(pid, SIGKILL); 02981 #if !defined(_WIN32) 02982 do {} while (waitpid(-1, &i, WNOHANG) > 0); 02983 #endif 02984 } 02985 if (fd_stdin[0] != -1) { 02986 (void) close(fd_stdin[0]); 02987 } 02988 if (fd_stdout[1] != -1) { 02989 (void) close(fd_stdout[1]); 02990 } 02991 02992 if (in != NULL) { 02993 (void) fclose(in); 02994 } else if (fd_stdin[1] != -1) { 02995 (void) close(fd_stdin[1]); 02996 } 02997 02998 if (out != NULL) { 02999 (void) fclose(out); 03000 } else if (fd_stdout[0] != -1) { 03001 (void) close(fd_stdout[0]); 03002 } 03003 } 03004 #endif // !NO_CGI 03005 03006 // For a given PUT path, create all intermediate subdirectories 03007 // for given path. Return 0 if the path itself is a directory, 03008 // or -1 on error, 1 if OK. 03009 static int put_dir(const char *path) { 03010 char buf[PATH_MAX]; 03011 const char *s, *p; 03012 struct mgstat st; 03013 size_t len; 03014 03015 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) { 03016 len = p - path; 03017 assert(len < sizeof(buf)); 03018 (void) memcpy(buf, path, len); 03019 buf[len] = '\0'; 03020 03021 // Try to create intermediate directory 03022 if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0) { 03023 return -1; 03024 } 03025 03026 // Is path itself a directory? 03027 if (p[1] == '\0') { 03028 return 0; 03029 } 03030 } 03031 03032 return 1; 03033 } 03034 03035 static void put_file(struct mg_connection *conn, const char *path) { 03036 struct mgstat st; 03037 const char *range; 03038 int64_t r1, r2; 03039 FILE *fp; 03040 int rc; 03041 03042 conn->request_info.status_code = mg_stat(path, &st) == 0 ? 200 : 201; 03043 03044 if ((rc = put_dir(path)) == 0) { 03045 mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->request_info.status_code); 03046 } else if (rc == -1) { 03047 send_http_error(conn, 500, http_500_error, 03048 "put_dir(%s): %s", path, strerror(ERRNO)); 03049 } else if ((fp = mg_fopen(path, "wb+")) == NULL) { 03050 send_http_error(conn, 500, http_500_error, 03051 "fopen(%s): %s", path, strerror(ERRNO)); 03052 } else { 03053 set_close_on_exec(fileno(fp)); 03054 range = mg_get_header(conn, "Content-Range"); 03055 r1 = r2 = 0; 03056 if (range != NULL && parse_range_header(range, &r1, &r2) > 0) { 03057 conn->request_info.status_code = 206; 03058 // TODO(lsm): handle seek error 03059 (void) fseeko(fp, (off_t) r1, SEEK_SET); 03060 } 03061 if (forward_body_data(conn, fp, INVALID_SOCKET, NULL)) 03062 (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", 03063 conn->request_info.status_code); 03064 (void) fclose(fp); 03065 } 03066 } 03067 03068 static void send_ssi_file(struct mg_connection *, const char *, FILE *, int); 03069 03070 static void do_ssi_include(struct mg_connection *conn, const char *ssi, 03071 char *tag, int include_level) { 03072 char file_name[BUFSIZ], path[PATH_MAX], *p; 03073 struct vec root; 03074 int is_ssi; 03075 FILE *fp; 03076 03077 get_document_root(conn, &root); 03078 03079 // sscanf() is safe here, since send_ssi_file() also uses buffer 03080 // of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ. 03081 if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) { 03082 // File name is relative to the webserver root 03083 (void) mg_snprintf(conn, path, sizeof(path), "%.*s%c%s", 03084 root.len, root.ptr, DIRSEP, file_name); 03085 } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) { 03086 // File name is relative to the webserver working directory 03087 // or it is absolute system path 03088 (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name); 03089 } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) { 03090 // File name is relative to the currect document 03091 (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi); 03092 if ((p = strrchr(path, DIRSEP)) != NULL) { 03093 p[1] = '\0'; 03094 } 03095 (void) mg_snprintf(conn, path + strlen(path), 03096 sizeof(path) - strlen(path), "%s", file_name); 03097 } else { 03098 cry(conn, "Bad SSI #include: [%s]", tag); 03099 return; 03100 } 03101 03102 if ((fp = mg_fopen(path, "rb")) == NULL) { 03103 cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", 03104 tag, path, strerror(ERRNO)); 03105 } else { 03106 set_close_on_exec(fileno(fp)); 03107 is_ssi = match_extension(path, conn->ctx->config[SSI_EXTENSIONS]); 03108 if (is_ssi) { 03109 send_ssi_file(conn, path, fp, include_level + 1); 03110 } else { 03111 send_file_data(conn, fp, INT64_MAX); 03112 } 03113 (void) fclose(fp); 03114 } 03115 } 03116 03117 #if !defined(NO_POPEN) 03118 static void do_ssi_exec(struct mg_connection *conn, char *tag) { 03119 char cmd[BUFSIZ]; 03120 FILE *fp; 03121 03122 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) { 03123 cry(conn, "Bad SSI #exec: [%s]", tag); 03124 } else if ((fp = popen(cmd, "r")) == NULL) { 03125 cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO)); 03126 } else { 03127 send_file_data(conn, fp, INT64_MAX); 03128 (void) pclose(fp); 03129 } 03130 } 03131 #endif // !NO_POPEN 03132 03133 static void send_ssi_file(struct mg_connection *conn, const char *path, 03134 FILE *fp, int include_level) { 03135 char buf[BUFSIZ]; 03136 int ch, len, in_ssi_tag; 03137 03138 if (include_level > 10) { 03139 cry(conn, "SSI #include level is too deep (%s)", path); 03140 return; 03141 } 03142 03143 in_ssi_tag = 0; 03144 len = 0; 03145 03146 while ((ch = fgetc(fp)) != EOF) { 03147 if (in_ssi_tag && ch == '>') { 03148 in_ssi_tag = 0; 03149 buf[len++] = (char) ch; 03150 buf[len] = '\0'; 03151 assert(len <= (int) sizeof(buf)); 03152 if (len < 6 || memcmp(buf, "<!--#", 5) != 0) { 03153 // Not an SSI tag, pass it 03154 (void) mg_write(conn, buf, (size_t)len); 03155 } else { 03156 if (!memcmp(buf + 5, "include", 7)) { 03157 do_ssi_include(conn, path, buf + 12, include_level); 03158 #if !defined(NO_POPEN) 03159 } else if (!memcmp(buf + 5, "exec", 4)) { 03160 do_ssi_exec(conn, buf + 9); 03161 #endif // !NO_POPEN 03162 } else { 03163 cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf); 03164 } 03165 } 03166 len = 0; 03167 } else if (in_ssi_tag) { 03168 if (len == 5 && memcmp(buf, "<!--#", 5) != 0) { 03169 // Not an SSI tag 03170 in_ssi_tag = 0; 03171 } else if (len == (int) sizeof(buf) - 2) { 03172 cry(conn, "%s: SSI tag is too large", path); 03173 len = 0; 03174 } 03175 buf[len++] = ch & 0xff; 03176 } else if (ch == '<') { 03177 in_ssi_tag = 1; 03178 if (len > 0) { 03179 (void) mg_write(conn, buf, (size_t)len); 03180 } 03181 len = 0; 03182 buf[len++] = ch & 0xff; 03183 } else { 03184 buf[len++] = ch & 0xff; 03185 if (len == (int) sizeof(buf)) { 03186 (void) mg_write(conn, buf, (size_t)len); 03187 len = 0; 03188 } 03189 } 03190 } 03191 03192 // Send the rest of buffered data 03193 if (len > 0) { 03194 (void) mg_write(conn, buf, (size_t)len); 03195 } 03196 } 03197 03198 static void handle_ssi_file_request(struct mg_connection *conn, 03199 const char *path) { 03200 FILE *fp; 03201 03202 if ((fp = mg_fopen(path, "rb")) == NULL) { 03203 send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path, 03204 strerror(ERRNO)); 03205 } else { 03206 set_close_on_exec(fileno(fp)); 03207 mg_printf(conn, "HTTP/1.1 200 OK\r\n" 03208 "Content-Type: text/html\r\nConnection: %s\r\n\r\n", 03209 suggest_connection_header(conn)); 03210 send_ssi_file(conn, path, fp, 0); 03211 (void) fclose(fp); 03212 } 03213 } 03214 03215 // This is the heart of the Mongoose's logic. 03216 // This function is called when the request is read, parsed and validated, 03217 // and Mongoose must decide what action to take: serve a file, or 03218 // a directory, or call embedded function, etcetera. 03219 static void handle_request(struct mg_connection *conn) { 03220 struct mg_request_info *ri = &conn->request_info; 03221 char path[PATH_MAX]; 03222 int uri_len; 03223 struct mgstat st; 03224 03225 if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) { 03226 * conn->request_info.query_string++ = '\0'; 03227 } 03228 uri_len = strlen(ri->uri); 03229 (void) url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0); 03230 remove_double_dots_and_double_slashes(ri->uri); 03231 convert_uri_to_file_name(conn, ri->uri, path, sizeof(path)); 03232 03233 DEBUG_TRACE(("%s", ri->uri)); 03234 if (!check_authorization(conn, path)) { 03235 send_authorization_request(conn); 03236 } else if (call_user(conn, MG_NEW_REQUEST) != NULL) { 03237 // Do nothing, callback has served the request 03238 } else if (strstr(path, PASSWORDS_FILE_NAME)) { 03239 // Do not allow to view passwords files 03240 send_http_error(conn, 403, "Forbidden", "Access Forbidden"); 03241 } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) { 03242 send_http_error(conn, 404, "Not Found", "Not Found"); 03243 } else if ((!strcmp(ri->request_method, "PUT") || 03244 !strcmp(ri->request_method, "DELETE")) && 03245 (conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL || 03246 !is_authorized_for_put(conn))) { 03247 send_authorization_request(conn); 03248 } else if (!strcmp(ri->request_method, "PUT")) { 03249 put_file(conn, path); 03250 } else if (!strcmp(ri->request_method, "DELETE")) { 03251 if (mg_remove(path) == 0) { 03252 send_http_error(conn, 200, "OK", ""); 03253 } else { 03254 send_http_error(conn, 500, http_500_error, "remove(%s): %s", path, 03255 strerror(ERRNO)); 03256 } 03257 } else if (mg_stat(path, &st) != 0) { 03258 send_http_error(conn, 404, "Not Found", "%s", "File not found"); 03259 } else if (st.is_directory && ri->uri[uri_len - 1] != '/') { 03260 (void) mg_printf(conn, 03261 "HTTP/1.1 301 Moved Permanently\r\n" 03262 "Location: %s/\r\n\r\n", ri->uri); 03263 } else if (st.is_directory && 03264 !substitute_index_file(conn, path, sizeof(path), &st)) { 03265 if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) { 03266 handle_directory_request(conn, path); 03267 } else { 03268 send_http_error(conn, 403, "Directory Listing Denied", 03269 "Directory listing denied"); 03270 } 03271 } else if (match_extension(path, conn->ctx->config[CGI_EXTENSIONS])) { 03272 if (strcmp(ri->request_method, "POST") && 03273 strcmp(ri->request_method, "GET")) { 03274 send_http_error(conn, 501, "Not Implemented", 03275 "Method %s is not implemented", ri->request_method); 03276 } else { 03277 handle_cgi_request(conn, path); 03278 } 03279 } else if (match_extension(path, conn->ctx->config[SSI_EXTENSIONS])) { 03280 handle_ssi_file_request(conn, path); 03281 } else if (is_not_modified(conn, &st)) { 03282 send_http_error(conn, 304, "Not Modified", ""); 03283 } else { 03284 handle_file_request(conn, path, &st); 03285 } 03286 } 03287 03288 static void close_all_listening_sockets(struct mg_context *ctx) { 03289 struct socket *sp, *tmp; 03290 for (sp = ctx->listening_sockets; sp != NULL; sp = tmp) { 03291 tmp = sp->next; 03292 (void) closesocket(sp->sock); 03293 free(sp); 03294 } 03295 } 03296 03297 // Valid listening port specification is: [ip_address:]port[s|p] 03298 // Examples: 80, 443s, 127.0.0.1:3128p, 1.2.3.4:8080sp 03299 static int parse_port_string(const struct vec *vec, struct socket *so) { 03300 struct usa *usa = &so->lsa; 03301 int a, b, c, d, port, len; 03302 03303 // MacOS needs that. If we do not zero it, subsequent bind() will fail. 03304 memset(so, 0, sizeof(*so)); 03305 03306 if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) { 03307 // IP address to bind to is specified 03308 usa->u.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d); 03309 } else if (sscanf(vec->ptr, "%d%n", &port, &len) == 1) { 03310 // Only port number is specified. Bind to all addresses 03311 usa->u.sin.sin_addr.s_addr = htonl(INADDR_ANY); 03312 } else { 03313 return 0; 03314 } 03315 assert(len > 0 && len <= (int) vec->len); 03316 03317 if (strchr("sp,", vec->ptr[len]) == NULL) { 03318 return 0; 03319 } 03320 03321 so->is_ssl = vec->ptr[len] == 's'; 03322 so->is_proxy = vec->ptr[len] == 'p'; 03323 usa->len = sizeof(usa->u.sin); 03324 usa->u.sin.sin_family = AF_INET; 03325 usa->u.sin.sin_port = htons((uint16_t) port); 03326 03327 return 1; 03328 } 03329 03330 static int set_ports_option(struct mg_context *ctx) { 03331 const char *list = ctx->config[LISTENING_PORTS]; 03332 int reuseaddr = 1, success = 1; 03333 SOCKET sock; 03334 struct vec vec; 03335 struct socket so, *listener; 03336 03337 while (success && (list = next_option(list, &vec, NULL)) != NULL) { 03338 if (!parse_port_string(&vec, &so)) { 03339 cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s", 03340 __func__, vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]"); 03341 success = 0; 03342 } else if (so.is_ssl && ctx->ssl_ctx == NULL) { 03343 cry(fc(ctx), "Cannot add SSL socket, is -ssl_cert option set?"); 03344 success = 0; 03345 } else if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == INVALID_SOCKET || 03346 #if !defined(_WIN32) 03347 // On Windows, SO_REUSEADDR is recommended only for 03348 // broadcast UDP sockets 03349 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, 03350 sizeof(reuseaddr)) != 0 || 03351 #endif // !_WIN32 03352 bind(sock, &so.lsa.u.sa, so.lsa.len) != 0 || 03353 listen(sock, 20) != 0) { 03354 closesocket(sock); 03355 cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__, 03356 vec.len, vec.ptr, strerror(ERRNO)); 03357 success = 0; 03358 } else if ((listener = calloc(1, sizeof(*listener))) == NULL) { 03359 closesocket(sock); 03360 cry(fc(ctx), "%s: %s", __func__, strerror(ERRNO)); 03361 success = 0; 03362 } else { 03363 *listener = so; 03364 listener->sock = sock; 03365 set_close_on_exec(listener->sock); 03366 listener->next = ctx->listening_sockets; 03367 ctx->listening_sockets = listener; 03368 } 03369 } 03370 03371 if (!success) { 03372 close_all_listening_sockets(ctx); 03373 } 03374 03375 return success; 03376 } 03377 03378 static void log_header(const struct mg_connection *conn, const char *header, 03379 FILE *fp) { 03380 const char *header_value; 03381 03382 if ((header_value = mg_get_header(conn, header)) == NULL) { 03383 (void) fprintf(fp, "%s", " -"); 03384 } else { 03385 (void) fprintf(fp, " \"%s\"", header_value); 03386 } 03387 } 03388 03389 static void log_access(const struct mg_connection *conn) { 03390 const struct mg_request_info *ri; 03391 FILE *fp; 03392 char date[64]; 03393 03394 fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ? NULL : 03395 mg_fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+"); 03396 03397 if (fp == NULL) 03398 return; 03399 03400 (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", 03401 localtime(&conn->birth_time)); 03402 03403 ri = &conn->request_info; 03404 03405 flockfile(fp); 03406 03407 (void) fprintf(fp, 03408 "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT, 03409 inet_ntoa(conn->client.rsa.u.sin.sin_addr), 03410 ri->remote_user == NULL ? "-" : ri->remote_user, 03411 date, 03412 ri->request_method ? ri->request_method : "-", 03413 ri->uri ? ri->uri : "-", 03414 ri->http_version, 03415 conn->request_info.status_code, conn->num_bytes_sent); 03416 log_header(conn, "Referer", fp); 03417 log_header(conn, "User-Agent", fp); 03418 (void) fputc('\n', fp); 03419 (void) fflush(fp); 03420 03421 funlockfile(fp); 03422 (void) fclose(fp); 03423 } 03424 03425 static int isbyte(int n) { 03426 return n >= 0 && n <= 255; 03427 } 03428 03429 // Verify given socket address against the ACL. 03430 // Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. 03431 static int check_acl(struct mg_context *ctx, const struct usa *usa) { 03432 int a, b, c, d, n, mask, allowed; 03433 char flag; 03434 uint32_t acl_subnet, acl_mask, remote_ip; 03435 struct vec vec; 03436 const char *list = ctx->config[ACCESS_CONTROL_LIST]; 03437 03438 if (list == NULL) { 03439 return 1; 03440 } 03441 03442 (void) memcpy(&remote_ip, &usa->u.sin.sin_addr, sizeof(remote_ip)); 03443 03444 // If any ACL is set, deny by default 03445 allowed = '-'; 03446 03447 while ((list = next_option(list, &vec, NULL)) != NULL) { 03448 mask = 32; 03449 03450 if (sscanf(vec.ptr, "%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) { 03451 cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__); 03452 return -1; 03453 } else if (flag != '+' && flag != '-') { 03454 cry(fc(ctx), "%s: flag must be + or -: [%s]", __func__, vec.ptr); 03455 return -1; 03456 } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) { 03457 cry(fc(ctx), "%s: bad ip address: [%s]", __func__, vec.ptr); 03458 return -1; 03459 } else if (sscanf(vec.ptr + n, "/%d", &mask) == 0) { 03460 // Do nothing, no mask specified 03461 } else if (mask < 0 || mask > 32) { 03462 cry(fc(ctx), "%s: bad subnet mask: %d [%s]", __func__, n, vec.ptr); 03463 return -1; 03464 } 03465 03466 acl_subnet = (a << 24) | (b << 16) | (c << 8) | d; 03467 acl_mask = mask ? 0xffffffffU << (32 - mask) : 0; 03468 03469 if (acl_subnet == (ntohl(remote_ip) & acl_mask)) { 03470 allowed = flag; 03471 } 03472 } 03473 03474 return allowed == '+'; 03475 } 03476 03477 static void add_to_set(SOCKET fd, fd_set *set, int *max_fd) { 03478 FD_SET(fd, set); 03479 if (fd > (SOCKET) *max_fd) { 03480 *max_fd = (int) fd; 03481 } 03482 } 03483 03484 #if !defined(_WIN32) 03485 static int set_uid_option(struct mg_context *ctx) { 03486 struct passwd *pw; 03487 const char *uid = ctx->config[RUN_AS_USER]; 03488 int success = 0; 03489 03490 if (uid == NULL) { 03491 success = 1; 03492 } else { 03493 if ((pw = getpwnam(uid)) == NULL) { 03494 cry(fc(ctx), "%s: unknown user [%s]", __func__, uid); 03495 } else if (setgid(pw->pw_gid) == -1) { 03496 cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno)); 03497 } else if (setuid(pw->pw_uid) == -1) { 03498 cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno)); 03499 } else { 03500 success = 1; 03501 } 03502 } 03503 03504 return success; 03505 } 03506 #endif // !_WIN32 03507 03508 #if !defined(NO_SSL) 03509 static pthread_mutex_t *ssl_mutexes; 03510 03511 static void ssl_locking_callback(int mode, int mutex_num, const char *file, 03512 int line) { 03513 line = 0; // Unused 03514 file = NULL; // Unused 03515 03516 if (mode & CRYPTO_LOCK) { 03517 (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]); 03518 } else { 03519 (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]); 03520 } 03521 } 03522 03523 static unsigned long ssl_id_callback(void) { 03524 return (unsigned long) pthread_self(); 03525 } 03526 03527 #if !defined(NO_SSL_DL) 03528 static int load_dll(struct mg_context *ctx, const char *dll_name, 03529 struct ssl_func *sw) { 03530 union {void *p; void (*fp)(void);} u; 03531 void *dll_handle; 03532 struct ssl_func *fp; 03533 03534 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) { 03535 cry(fc(ctx), "%s: cannot load %s", __func__, dll_name); 03536 return 0; 03537 } 03538 03539 for (fp = sw; fp->name != NULL; fp++) { 03540 #ifdef _WIN32 03541 // GetProcAddress() returns pointer to function 03542 u.fp = (void (*)(void)) dlsym(dll_handle, fp->name); 03543 #else 03544 // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to 03545 // function pointers. We need to use a union to make a cast. 03546 u.p = dlsym(dll_handle, fp->name); 03547 #endif /* _WIN32 */ 03548 if (u.fp == NULL) { 03549 cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name); 03550 return 0; 03551 } else { 03552 fp->ptr = u.fp; 03553 } 03554 } 03555 03556 return 1; 03557 } 03558 #endif // NO_SSL_DL 03559 03560 // Dynamically load SSL library. Set up ctx->ssl_ctx pointer. 03561 static int set_ssl_option(struct mg_context *ctx) { 03562 SSL_CTX *CTX; 03563 int i, size; 03564 const char *pem = ctx->config[SSL_CERTIFICATE]; 03565 const char *chain = ctx->config[SSL_CHAIN_FILE]; 03566 03567 if (pem == NULL) { 03568 return 1; 03569 } 03570 03571 #if !defined(NO_SSL_DL) 03572 if (!load_dll(ctx, SSL_LIB, ssl_sw) || 03573 !load_dll(ctx, CRYPTO_LIB, crypto_sw)) { 03574 return 0; 03575 } 03576 #endif // NO_SSL_DL 03577 03578 // Initialize SSL crap 03579 SSL_library_init(); 03580 SSL_load_error_strings(); 03581 03582 if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) { 03583 cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error()); 03584 } else if (ctx->user_callback != NULL) { 03585 ctx->user_callback(MG_INIT_SSL, (struct mg_connection *) CTX, NULL); 03586 } 03587 03588 if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem, 03589 SSL_FILETYPE_PEM) == 0) { 03590 cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error()); 03591 return 0; 03592 } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem, 03593 SSL_FILETYPE_PEM) == 0) { 03594 cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error()); 03595 return 0; 03596 } 03597 03598 if (CTX != NULL && chain != NULL && 03599 SSL_CTX_use_certificate_chain_file(CTX, chain) == 0) { 03600 cry(fc(ctx), "%s: cannot open %s: %s", NULL, chain, ssl_error()); 03601 return 0; 03602 } 03603 03604 // Initialize locking callbacks, needed for thread safety. 03605 // http://www.openssl.org/support/faq.html#PROG1 03606 size = sizeof(pthread_mutex_t) * CRYPTO_num_locks(); 03607 if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) { 03608 cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); 03609 return 0; 03610 } 03611 03612 for (i = 0; i < CRYPTO_num_locks(); i++) { 03613 pthread_mutex_init(&ssl_mutexes[i], NULL); 03614 } 03615 03616 CRYPTO_set_locking_callback(&ssl_locking_callback); 03617 CRYPTO_set_id_callback(&ssl_id_callback); 03618 03619 // Done with everything. Save the context. 03620 ctx->ssl_ctx = CTX; 03621 03622 return 1; 03623 } 03624 #endif // !NO_SSL 03625 03626 static int set_gpass_option(struct mg_context *ctx) { 03627 struct mgstat mgstat; 03628 const char *path = ctx->config[GLOBAL_PASSWORDS_FILE]; 03629 return path == NULL || mg_stat(path, &mgstat) == 0; 03630 } 03631 03632 static int set_acl_option(struct mg_context *ctx) { 03633 struct usa fake; 03634 return check_acl(ctx, &fake) != -1; 03635 } 03636 03637 static void reset_per_request_attributes(struct mg_connection *conn) { 03638 struct mg_request_info *ri = &conn->request_info; 03639 03640 // Reset request info attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port 03641 if (ri->remote_user != NULL) { 03642 free((void *) ri->remote_user); 03643 } 03644 ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL; 03645 ri->num_headers = 0; 03646 ri->status_code = -1; 03647 03648 conn->num_bytes_sent = conn->consumed_content = 0; 03649 conn->content_len = -1; 03650 conn->request_len = conn->data_len = 0; 03651 } 03652 03653 static void close_socket_gracefully(SOCKET sock) { 03654 char buf[BUFSIZ]; 03655 int n; 03656 03657 // Send FIN to the client 03658 (void) shutdown(sock, SHUT_WR); 03659 set_non_blocking_mode(sock); 03660 03661 // Read and discard pending data. If we do not do that and close the 03662 // socket, the data in the send buffer may be discarded. This 03663 // behaviour is seen on Windows, when client keeps sending data 03664 // when server decide to close the connection; then when client 03665 // does recv() it gets no data back. 03666 do { 03667 n = pull(NULL, sock, NULL, buf, sizeof(buf)); 03668 } while (n > 0); 03669 03670 // Now we know that our FIN is ACK-ed, safe to close 03671 (void) closesocket(sock); 03672 } 03673 03674 static void close_connection(struct mg_connection *conn) { 03675 if (conn->ssl) { 03676 SSL_free(conn->ssl); 03677 conn->ssl = NULL; 03678 } 03679 03680 if (conn->client.sock != INVALID_SOCKET) { 03681 close_socket_gracefully(conn->client.sock); 03682 } 03683 } 03684 03685 static void discard_current_request_from_buffer(struct mg_connection *conn) { 03686 char *buffered; 03687 int buffered_len, body_len; 03688 03689 buffered = conn->buf + conn->request_len; 03690 buffered_len = conn->data_len - conn->request_len; 03691 assert(buffered_len >= 0); 03692 03693 if (conn->content_len == -1) { 03694 body_len = 0; 03695 } else if (conn->content_len < (int64_t) buffered_len) { 03696 body_len = (int) conn->content_len; 03697 } else { 03698 body_len = buffered_len; 03699 } 03700 03701 conn->data_len -= conn->request_len + body_len; 03702 memmove(conn->buf, conn->buf + conn->request_len + body_len, (size_t)conn->data_len); 03703 } 03704 03705 static int parse_url(const char *url, char *host, int *port) { 03706 int len; 03707 03708 if (url == NULL) { 03709 return 0; 03710 }; 03711 03712 if (!strncmp(url, "http://", 7)) { 03713 url += 7; 03714 } 03715 03716 if (sscanf(url, "%1024[^:]:%d/%n", host, port, &len) == 2) { 03717 } else { 03718 sscanf(url, "%1024[^/]/%n", host, &len); 03719 *port = 80; 03720 } 03721 DEBUG_TRACE(("Host:%s, port:%d", host, *port)); 03722 03723 return len > 0 && url[len - 1] == '/' ? len - 1 : len; 03724 } 03725 03726 static void handle_proxy_request(struct mg_connection *conn) { 03727 struct mg_request_info *ri = &conn->request_info; 03728 char host[1025], buf[BUFSIZ]; 03729 int port, is_ssl, len, i, n; 03730 03731 DEBUG_TRACE(("URL: %s", ri->uri)); 03732 if (conn->request_info.uri[0] == '/' || 03733 (len = parse_url(ri->uri, host, &port)) == 0) { 03734 return; 03735 } 03736 03737 if (conn->peer == NULL) { 03738 is_ssl = !strcmp(ri->request_method, "CONNECT"); 03739 if ((conn->peer = mg_connect(conn, host, port, is_ssl)) == NULL) { 03740 return; 03741 } 03742 conn->peer->client.is_ssl = is_ssl; 03743 } 03744 03745 // Forward client's request to the target 03746 mg_printf(conn->peer, "%s %s HTTP/%s\r\n", ri->request_method, ri->uri + len, 03747 ri->http_version); 03748 03749 // And also all headers. TODO(lsm): anonymize! 03750 for (i = 0; i < ri->num_headers; i++) { 03751 mg_printf(conn->peer, "%s: %s\r\n", ri->http_headers[i].name, 03752 ri->http_headers[i].value); 03753 } 03754 // End of headers, final newline 03755 mg_write(conn->peer, "\r\n", 2); 03756 03757 // Read and forward body data if any 03758 if (!strcmp(ri->request_method, "POST")) { 03759 forward_body_data(conn, NULL, conn->peer->client.sock, conn->peer->ssl); 03760 } 03761 03762 // Read data from the target and forward it to the client 03763 while ((n = pull(NULL, conn->peer->client.sock, conn->peer->ssl, 03764 buf, sizeof(buf))) > 0) { 03765 if (mg_write(conn, buf, (size_t)n) != n) { 03766 break; 03767 } 03768 } 03769 03770 if (!conn->peer->client.is_ssl) { 03771 close_connection(conn->peer); 03772 free(conn->peer); 03773 conn->peer = NULL; 03774 } 03775 } 03776 03777 static int is_valid_uri(const char *uri) { 03778 // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 03779 // URI can be an asterisk (*) or should start with slash. 03780 return (uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0')); 03781 } 03782 03783 static void process_new_connection(struct mg_connection *conn) { 03784 struct mg_request_info *ri = &conn->request_info; 03785 int keep_alive_enabled; 03786 const char *cl; 03787 03788 keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes"); 03789 03790 do { 03791 reset_per_request_attributes(conn); 03792 03793 // If next request is not pipelined, read it in 03794 if ((conn->request_len = get_request_len(conn->buf, conn->data_len)) == 0) { 03795 conn->request_len = read_request(NULL, conn->client.sock, conn->ssl, 03796 conn->buf, conn->buf_size, &conn->data_len); 03797 } 03798 assert(conn->data_len >= conn->request_len); 03799 if (conn->request_len == 0 && conn->data_len == conn->buf_size) { 03800 send_http_error(conn, 413, "Request Too Large", ""); 03801 return; 03802 } if (conn->request_len <= 0) { 03803 return; // Remote end closed the connection 03804 } 03805 03806 // Nul-terminate the request cause parse_http_request() uses sscanf 03807 conn->buf[conn->request_len - 1] = '\0'; 03808 if (!parse_http_request(conn->buf, ri) || 03809 (!conn->client.is_proxy && !is_valid_uri(ri->uri))) { 03810 // Do not put garbage in the access log, just send it back to the client 03811 send_http_error(conn, 400, "Bad Request", 03812 "Cannot parse HTTP request: [%.*s]", conn->data_len, conn->buf); 03813 } else if (strcmp(ri->http_version, "1.0") && 03814 strcmp(ri->http_version, "1.1")) { 03815 // Request seems valid, but HTTP version is strange 03816 send_http_error(conn, 505, "HTTP version not supported", ""); 03817 log_access(conn); 03818 } else { 03819 // Request is valid, handle it 03820 cl = get_header(ri, "Content-Length"); 03821 conn->content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10); 03822 conn->birth_time = time(NULL); 03823 if (conn->client.is_proxy) { 03824 handle_proxy_request(conn); 03825 } else { 03826 handle_request(conn); 03827 } 03828 log_access(conn); 03829 discard_current_request_from_buffer(conn); 03830 } 03831 // conn->peer is not NULL only for SSL-ed proxy connections 03832 } while (conn->peer || (keep_alive_enabled && should_keep_alive(conn))); 03833 } 03834 03835 // Worker threads take accepted socket from the queue 03836 static int consume_socket(struct mg_context *ctx, struct socket *sp) { 03837 (void) pthread_mutex_lock(&ctx->mutex); 03838 DEBUG_TRACE(("going idle")); 03839 03840 // If the queue is empty, wait. We're idle at this point. 03841 while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) { 03842 pthread_cond_wait(&ctx->sq_full, &ctx->mutex); 03843 } 03844 // Master thread could wake us up without putting a socket. 03845 // If this happens, it is time to exit. 03846 if (ctx->stop_flag) { 03847 (void) pthread_mutex_unlock(&ctx->mutex); 03848 return 0; 03849 } 03850 assert(ctx->sq_head > ctx->sq_tail); 03851 03852 // Copy socket from the queue and increment tail 03853 *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)]; 03854 ctx->sq_tail++; 03855 DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock)); 03856 03857 // Wrap pointers if needed 03858 while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) { 03859 ctx->sq_tail -= ARRAY_SIZE(ctx->queue); 03860 ctx->sq_head -= ARRAY_SIZE(ctx->queue); 03861 } 03862 03863 (void) pthread_cond_signal(&ctx->sq_empty); 03864 (void) pthread_mutex_unlock(&ctx->mutex); 03865 03866 return 1; 03867 } 03868 03869 static void worker_thread(struct mg_context *ctx) { 03870 struct mg_connection *conn; 03871 int buf_size = atoi(ctx->config[MAX_REQUEST_SIZE]); 03872 03873 conn = calloc(1, sizeof(*conn) + buf_size); 03874 conn->buf_size = buf_size; 03875 conn->buf = (char *) (conn + 1); 03876 assert(conn != NULL); 03877 03878 (void) pthread_mutex_lock(&ctx->mutex); 03879 ctx->idle_threads++; 03880 (void) pthread_mutex_unlock(&ctx->mutex); 03881 03882 while (ctx->stop_flag == 0 && consume_socket(ctx, &conn->client)) { 03883 (void) pthread_mutex_lock(&ctx->mutex); 03884 ctx->idle_threads--; 03885 assert(ctx->idle_threads >= 0); 03886 if (ctx->idle_threads == 0 && (ctx->max_threads == 0 || (ctx->num_threads < ctx->max_threads))) { 03887 if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) { 03888 cry(fc(ctx), "Cannot start extra worker thread: %d", ERRNO); 03889 } else { 03890 ctx->num_threads++; 03891 } 03892 } 03893 (void) pthread_mutex_unlock(&ctx->mutex); 03894 03895 conn->birth_time = time(NULL); 03896 conn->ctx = ctx; 03897 03898 // Fill in IP, port info early so even if SSL setup below fails, 03899 // error handler would have the corresponding info. 03900 // Thanks to Johannes Winkelmann for the patch. 03901 conn->request_info.remote_port = ntohs(conn->client.rsa.u.sin.sin_port); 03902 memcpy(&conn->request_info.remote_ip, 03903 &conn->client.rsa.u.sin.sin_addr.s_addr, 4); 03904 conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip); 03905 conn->request_info.is_ssl = conn->client.is_ssl; 03906 03907 if (!conn->client.is_ssl || 03908 (conn->client.is_ssl && sslize(conn, SSL_accept))) { 03909 process_new_connection(conn); 03910 } 03911 03912 close_connection(conn); 03913 03914 (void) pthread_mutex_lock(&ctx->mutex); 03915 ctx->idle_threads++; 03916 if (ctx->num_threads > ctx->base_threads && ctx->idle_threads > 1) { // todo: add some buffer here 03917 (void) pthread_mutex_unlock(&ctx->mutex); 03918 break; 03919 } 03920 (void) pthread_mutex_unlock(&ctx->mutex); 03921 } 03922 free(conn); 03923 03924 // Signal master that we're done with connection and exiting 03925 (void) pthread_mutex_lock(&ctx->mutex); 03926 ctx->num_threads--; 03927 ctx->idle_threads--; 03928 (void) pthread_cond_signal(&ctx->cond); 03929 assert(ctx->num_threads >= 0); 03930 assert(ctx->idle_threads >= 0); 03931 (void) pthread_mutex_unlock(&ctx->mutex); 03932 03933 DEBUG_TRACE(("exiting")); 03934 } 03935 03936 // Master thread adds accepted socket to a queue 03937 static void produce_socket(struct mg_context *ctx, const struct socket *sp) { 03938 (void) pthread_mutex_lock(&ctx->mutex); 03939 03940 // If the queue is full, wait 03941 while (ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) { 03942 (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex); 03943 } 03944 assert(ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)); 03945 03946 // Copy socket to the queue and increment head 03947 ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp; 03948 ctx->sq_head++; 03949 DEBUG_TRACE(("queued socket %d", sp->sock)); 03950 03951 (void) pthread_cond_signal(&ctx->sq_full); 03952 (void) pthread_mutex_unlock(&ctx->mutex); 03953 } 03954 03955 static void accept_new_connection(const struct socket *listener, 03956 struct mg_context *ctx) { 03957 struct socket accepted; 03958 int allowed; 03959 03960 accepted.rsa.len = sizeof(accepted.rsa.u.sin); 03961 accepted.lsa = listener->lsa; 03962 accepted.sock = accept(listener->sock, &accepted.rsa.u.sa, &accepted.rsa.len); 03963 if (accepted.sock != INVALID_SOCKET) { 03964 allowed = check_acl(ctx, &accepted.rsa); 03965 if (allowed) { 03966 // Put accepted socket structure into the queue 03967 DEBUG_TRACE(("accepted socket %d", accepted.sock)); 03968 accepted.is_ssl = listener->is_ssl; 03969 accepted.is_proxy = listener->is_proxy; 03970 produce_socket(ctx, &accepted); 03971 } else { 03972 cry(fc(ctx), "%s: %s is not allowed to connect", 03973 __func__, inet_ntoa(accepted.rsa.u.sin.sin_addr)); 03974 (void) closesocket(accepted.sock); 03975 } 03976 } 03977 } 03978 03979 static void master_thread(struct mg_context *ctx) { 03980 fd_set read_set; 03981 struct timeval tv; 03982 struct socket *sp; 03983 int max_fd; 03984 03985 while (ctx->stop_flag == 0) { 03986 FD_ZERO(&read_set); 03987 max_fd = -1; 03988 03989 // Add listening sockets to the read set 03990 for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) { 03991 add_to_set(sp->sock, &read_set, &max_fd); 03992 } 03993 03994 tv.tv_sec = 0; 03995 tv.tv_usec = 200 * 1000; 03996 03997 if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) { 03998 #ifdef _WIN32 03999 // On windows, if read_set and write_set are empty, 04000 // select() returns "Invalid parameter" error 04001 // (at least on my Windows XP Pro). So in this case, we sleep here. 04002 sleep(1); 04003 #endif // _WIN32 04004 } else { 04005 for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) { 04006 if (FD_ISSET(sp->sock, &read_set)) { 04007 accept_new_connection(sp, ctx); 04008 } 04009 } 04010 } 04011 } 04012 DEBUG_TRACE(("stopping workers")); 04013 04014 // Stop signal received: somebody called mg_stop. Quit. 04015 close_all_listening_sockets(ctx); 04016 04017 // Wakeup workers that are waiting for connections to handle. 04018 pthread_cond_broadcast(&ctx->sq_full); 04019 04020 // Wait until all threads finish 04021 (void) pthread_mutex_lock(&ctx->mutex); 04022 while (ctx->num_threads > 0) { 04023 (void) pthread_cond_wait(&ctx->cond, &ctx->mutex); 04024 } 04025 (void) pthread_mutex_unlock(&ctx->mutex); 04026 04027 // All threads exited, no sync is needed. Destroy mutex and condvars 04028 (void) pthread_mutex_destroy(&ctx->mutex); 04029 (void) pthread_cond_destroy(&ctx->cond); 04030 (void) pthread_cond_destroy(&ctx->sq_empty); 04031 (void) pthread_cond_destroy(&ctx->sq_full); 04032 04033 // Signal mg_stop() that we're done 04034 ctx->stop_flag = 2; 04035 04036 DEBUG_TRACE(("exiting")); 04037 } 04038 04039 static void free_context(struct mg_context *ctx) { 04040 int i; 04041 04042 // Deallocate config parameters 04043 for (i = 0; i < NUM_OPTIONS; i++) { 04044 if (ctx->config[i] != NULL) 04045 free(ctx->config[i]); 04046 } 04047 04048 // Deallocate SSL context 04049 if (ctx->ssl_ctx != NULL) { 04050 SSL_CTX_free(ctx->ssl_ctx); 04051 } 04052 #ifndef NO_SSL 04053 if (ssl_mutexes != NULL) { 04054 free(ssl_mutexes); 04055 } 04056 #endif // !NO_SSL 04057 04058 // Deallocate context itself 04059 free(ctx); 04060 } 04061 04062 void mg_stop(struct mg_context *ctx) { 04063 ctx->stop_flag = 1; 04064 04065 // Wait until mg_fini() stops 04066 while (ctx->stop_flag != 2) { 04067 (void) sleep(0); 04068 } 04069 free_context(ctx); 04070 04071 #if defined(_WIN32) 04072 (void) WSACleanup(); 04073 #endif // _WIN32 04074 } 04075 04076 struct mg_context *mg_start(mg_callback_t user_callback, void *user_data, 04077 const char **options) { 04078 struct mg_context *ctx; 04079 const char *name, *value, *default_value; 04080 int i; 04081 04082 #if defined(_WIN32) 04083 WSADATA data; 04084 WSAStartup(MAKEWORD(2,2), &data); 04085 #endif // _WIN32 04086 04087 // Allocate context and initialize reasonable general case defaults. 04088 // TODO(lsm): do proper error handling here. 04089 ctx = calloc(1, sizeof(*ctx)); 04090 ctx->user_callback = user_callback; 04091 ctx->user_data = user_data; 04092 04093 while (options && (name = *options++) != NULL) { 04094 if ((i = get_option_index(name)) == -1) { 04095 cry(fc(ctx), "Invalid option: %s", name); 04096 free_context(ctx); 04097 return NULL; 04098 } else if ((value = *options++) == NULL) { 04099 cry(fc(ctx), "%s: option value cannot be NULL", name); 04100 free_context(ctx); 04101 return NULL; 04102 } 04103 ctx->config[i] = mg_strdup(value); 04104 DEBUG_TRACE(("[%s] -> [%s]", name, value)); 04105 } 04106 04107 // Set default value if needed 04108 for (i = 0; config_options[i * ENTRIES_PER_CONFIG_OPTION] != NULL; i++) { 04109 default_value = config_options[i * ENTRIES_PER_CONFIG_OPTION + 2]; 04110 if (ctx->config[i] == NULL && default_value != NULL) { 04111 ctx->config[i] = mg_strdup(default_value); 04112 DEBUG_TRACE(("Setting default: [%s] -> [%s]", 04113 config_options[i * ENTRIES_PER_CONFIG_OPTION + 1], 04114 default_value)); 04115 } 04116 } 04117 04118 if (ctx->config[MAX_THREADS] == NULL) { 04119 ctx->config[MAX_THREADS] = ctx->config[NUM_THREADS]; 04120 } 04121 04122 ctx->base_threads = atoi(ctx->config[NUM_THREADS]); 04123 ctx->max_threads = atoi(ctx->config[MAX_THREADS]); 04124 04125 // NOTE(lsm): order is important here. SSL certificates must 04126 // be initialized before listening ports. UID must be set last. 04127 if (!set_gpass_option(ctx) || 04128 #if !defined(NO_SSL) 04129 !set_ssl_option(ctx) || 04130 #endif 04131 !set_ports_option(ctx) || 04132 #if !defined(_WIN32) 04133 !set_uid_option(ctx) || 04134 #endif 04135 !set_acl_option(ctx)) { 04136 free_context(ctx); 04137 return NULL; 04138 } 04139 04140 #if !defined(_WIN32) 04141 // Ignore SIGPIPE signal, so if browser cancels the request, it 04142 // won't kill the whole process. 04143 (void) signal(SIGPIPE, SIG_IGN); 04144 #endif // !_WIN32 04145 04146 (void) pthread_mutex_init(&ctx->mutex, NULL); 04147 (void) pthread_cond_init(&ctx->cond, NULL); 04148 (void) pthread_cond_init(&ctx->sq_empty, NULL); 04149 (void) pthread_cond_init(&ctx->sq_full, NULL); 04150 04151 // Start master (listening) thread 04152 start_thread(ctx, (mg_thread_func_t) master_thread, ctx); 04153 04154 // Start worker threads 04155 for (i = 0; i < ctx->base_threads; i++) { 04156 if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) { 04157 cry(fc(ctx), "Cannot start worker thread: %d", ERRNO); 04158 } else { 04159 ctx->num_threads++; 04160 } 04161 } 04162 04163 return ctx; 04164 }