mongoose.c
Go to the documentation of this file.
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(&current_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>&nbsp;%s</td><td>&nbsp;&nbsp;%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>&nbsp;%s</td><td>&nbsp;&nbsp;%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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


jpeg_streamer
Author(s): Ken Tossell/ktossell@umd.edu
autogenerated on Sat Jul 27 2013 22:46:56