LCOV - code coverage report
Current view: top level - source/third_party/mongoose - mongoose.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 1480 0.0 %
Date: 2023-01-19 00:18:29 Functions: 0 116 0.0 %

          Line data    Source code
       1             : // Slightly modified version of Mongoose, by Wildfire Games, for 0 A.D.
       2             : // Diff against mongoose_original.c (from Hg rev 77615121d235) to see the changes.
       3             : // 
       4             : // Motivation for changes:
       5             : //  * For simplicity and consistency with the rest of the codebase, we compile
       6             : //    as C++ instead of C, requiring a few compatibility fixes.
       7             : //  * For quietness with our default warning flags, some warnings are
       8             : //    explicitly disabled.
       9             : //  * CGI and SSL are disabled since they're not needed.
      10             : //  * ws2_32 is linked explicitly here, instead of requiring more complexity
      11             : //    in the build system.
      12             : //  * To avoid debug spew, we disable DEBUG.
      13             : //  * Use memcopy to get rid of strict-aliasing warning
      14             : //  * Remove use of deprecated 'register' storage class
      15             : 
      16             : #define __STDC_LIMIT_MACROS
      17             : 
      18             : #ifdef _MSC_VER
      19             : # pragma warning(disable:4127) // conditional expression is constant
      20             : # pragma warning(disable:4100) // unreferenced formal parameter
      21             : # pragma warning(disable:4245) // signed/unsigned mismatch
      22             : # pragma warning(disable:4505) // unreferenced local function has been removed
      23             : # pragma warning(disable:4365) // signed unsigned mismatch
      24             : # pragma warning(disable:4191) // unsafe conversion
      25             : # pragma warning(disable:4820) // incorrect padding
      26             : # pragma warning(disable:4668) // macro error
      27             : # pragma warning(disable:4710) // function not inlined
      28             : # pragma warning(disable:4711) // selected for automatic inline expansion
      29             : # pragma comment(lib, "ws2_32.lib")
      30             : #endif
      31             : 
      32             : #ifdef __GNUC__
      33             : # pragma GCC diagnostic ignored "-Wunused-function"
      34             : # ifndef __clang__
      35             : #  pragma GCC diagnostic ignored "-Wunused-but-set-variable"
      36             : # endif
      37             : #endif
      38             : 
      39             : #define NO_CGI
      40             : #define NO_SSL
      41             : 
      42             : #undef DEBUG
      43             : 
      44             : #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
      45             : // Fix undefined PF_INET on FreeBSD
      46             : #include <sys/socket.h>
      47             : #endif
      48             : 
      49             : // Copyright (c) 2004-2011 Sergey Lyubka
      50             : //
      51             : // Permission is hereby granted, free of charge, to any person obtaining a copy
      52             : // of this software and associated documentation files (the "Software"), to deal
      53             : // in the Software without restriction, including without limitation the rights
      54             : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      55             : // copies of the Software, and to permit persons to whom the Software is
      56             : // furnished to do so, subject to the following conditions:
      57             : //
      58             : // The above copyright notice and this permission notice shall be included in
      59             : // all copies or substantial portions of the Software.
      60             : //
      61             : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      62             : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      63             : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      64             : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      65             : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      66             : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      67             : // THE SOFTWARE.
      68             : 
      69             : #if defined(_WIN32)
      70             : #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
      71             : #else
      72             : #define _XOPEN_SOURCE 600 // For flockfile() on Linux
      73             : #define _LARGEFILE_SOURCE // Enable 64-bit file offsets
      74             : #define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
      75             : #endif
      76             : 
      77             : #if defined(__SYMBIAN32__)
      78             : #define NO_SSL // SSL is not supported
      79             : #define NO_CGI // CGI is not supported
      80             : #define PATH_MAX FILENAME_MAX
      81             : #endif // __SYMBIAN32__
      82             : 
      83             : #ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
      84             : #include <sys/types.h>
      85             : #include <sys/stat.h>
      86             : #include <errno.h>
      87             : #include <signal.h>
      88             : #include <fcntl.h>
      89             : #endif // !_WIN32_WCE
      90             : 
      91             : #include <time.h>
      92             : #include <stdlib.h>
      93             : #include <stdarg.h>
      94             : #include <assert.h>
      95             : #include <string.h>
      96             : #include <ctype.h>
      97             : #include <limits.h>
      98             : #include <stddef.h>
      99             : #include <stdio.h>
     100             : 
     101             : #if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
     102             : #define _WIN32_WINNT 0x0400 // To make it link in VS2005
     103             : #include <windows.h>
     104             : 
     105             : #ifndef PATH_MAX
     106             : #define PATH_MAX MAX_PATH
     107             : #endif
     108             : 
     109             : #ifndef _WIN32_WCE
     110             : #include <process.h>
     111             : #include <direct.h>
     112             : #include <io.h>
     113             : #else // _WIN32_WCE
     114             : #include <winsock2.h>
     115             : #define NO_CGI // WinCE has no pipes
     116             : 
     117             : typedef long off_t;
     118             : #define BUFSIZ  4096
     119             : 
     120             : #define errno   GetLastError()
     121             : #define strerror(x)  _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
     122             : #endif // _WIN32_WCE
     123             : 
     124             : #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
     125             :       ((uint64_t)((uint32_t)(hi))) << 32))
     126             : #define RATE_DIFF 10000000 // 100 nsecs
     127             : #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
     128             : #define SYS2UNIX_TIME(lo, hi) \
     129             :   (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
     130             : 
     131             : // Visual Studio 6 does not know __func__ or __FUNCTION__
     132             : // The rest of MS compilers use __FUNCTION__, not C99 __func__
     133             : // Also use _strtoui64 on modern M$ compilers
     134             : #if defined(_MSC_VER) && _MSC_VER < 1300
     135             : #define STRX(x) #x
     136             : #define STR(x) STRX(x)
     137             : #define __func__ "line " STR(__LINE__)
     138             : #define strtoull(x, y, z) strtoul(x, y, z)
     139             : #define strtoll(x, y, z) strtol(x, y, z)
     140             : #else
     141             : #define __func__  __FUNCTION__
     142             : #define strtoull(x, y, z) _strtoui64(x, y, z)
     143             : #define strtoll(x, y, z) _strtoi64(x, y, z)
     144             : #endif // _MSC_VER
     145             : 
     146             : #define ERRNO   GetLastError()
     147             : #define NO_SOCKLEN_T
     148             : #define SSL_LIB   "ssleay32.dll"
     149             : #define CRYPTO_LIB  "libeay32.dll"
     150             : #define DIRSEP '\\'
     151             : #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
     152             : #define O_NONBLOCK  0
     153             : #if !defined(EWOULDBLOCK)
     154             : #define EWOULDBLOCK  WSAEWOULDBLOCK
     155             : #endif // !EWOULDBLOCK
     156             : #define _POSIX_
     157             : #define INT64_FMT  "I64d"
     158             : 
     159             : #define WINCDECL __cdecl
     160             : #define SHUT_WR 1
     161             : #define snprintf _snprintf
     162             : #define vsnprintf _vsnprintf
     163             : #define sleep(x) Sleep((x) * 1000)
     164             : 
     165             : #define pipe(x) _pipe(x, BUFSIZ, _O_BINARY)
     166             : #define popen(x, y) _popen(x, y)
     167             : #define pclose(x) _pclose(x)
     168             : #define close(x) _close(x)
     169             : #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
     170             : #define RTLD_LAZY  0
     171             : #define fseeko(x, y, z) fseek((x), (y), (z))
     172             : #define fdopen(x, y) _fdopen((x), (y))
     173             : #define write(x, y, z) _write((x), (y), (unsigned) z)
     174             : #define read(x, y, z) _read((x), (y), (unsigned) z)
     175             : #define flockfile(x) (void) 0
     176             : #define funlockfile(x) (void) 0
     177             : 
     178             : #if !defined(fileno)
     179             : #define fileno(x) _fileno(x)
     180             : #endif // !fileno MINGW #defines fileno
     181             : 
     182             : typedef HANDLE pthread_mutex_t;
     183             : typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
     184             : typedef DWORD pthread_t;
     185             : #define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
     186             : 
     187             : #if _MSC_VER < 1900
     188             : struct timespec {
     189             :   long tv_nsec;
     190             :   long tv_sec;
     191             : };
     192             : #endif
     193             : 
     194             : static int pthread_mutex_lock(pthread_mutex_t *);
     195             : static int pthread_mutex_unlock(pthread_mutex_t *);
     196             : static FILE *mg_fopen(const char *path, const char *mode);
     197             : 
     198             : #if defined(HAVE_STDINT)
     199             : #include <stdint.h>
     200             : #else
     201             : typedef unsigned int  uint32_t;
     202             : typedef unsigned short  uint16_t;
     203             : typedef unsigned __int64 uint64_t;
     204             : typedef __int64   int64_t;
     205             : #define INT64_MAX  9223372036854775807
     206             : #endif // HAVE_STDINT
     207             : 
     208             : // POSIX dirent interface
     209             : struct dirent {
     210             :   char d_name[PATH_MAX];
     211             : };
     212             : 
     213             : typedef struct DIR {
     214             :   HANDLE   handle;
     215             :   WIN32_FIND_DATAW info;
     216             :   struct dirent  result;
     217             : } DIR;
     218             : 
     219             : #else    // UNIX  specific
     220             : #include <sys/wait.h>
     221             : #include <sys/socket.h>
     222             : #include <sys/select.h>
     223             : #include <netinet/in.h>
     224             : #include <arpa/inet.h>
     225             : #include <sys/time.h>
     226             : #include <stdint.h>
     227             : #include <inttypes.h>
     228             : #include <netdb.h>
     229             : 
     230             : #include <pwd.h>
     231             : #include <unistd.h>
     232             : #include <dirent.h>
     233             : #if !defined(NO_SSL_DL) && !defined(NO_SSL)
     234             : #include <dlfcn.h>
     235             : #endif
     236             : #include <pthread.h>
     237             : #if defined(__MACH__)
     238             : #define SSL_LIB   "libssl.dylib"
     239             : #define CRYPTO_LIB  "libcrypto.dylib"
     240             : #else
     241             : #if !defined(SSL_LIB)
     242             : #define SSL_LIB   "libssl.so"
     243             : #endif
     244             : #if !defined(CRYPTO_LIB)
     245             : #define CRYPTO_LIB  "libcrypto.so"
     246             : #endif
     247             : #endif
     248             : #define DIRSEP   '/'
     249             : #define IS_DIRSEP_CHAR(c) ((c) == '/')
     250             : #ifndef O_BINARY
     251             : #define O_BINARY  0
     252             : #endif // O_BINARY
     253             : #define closesocket(a) close(a)
     254             : #define mg_fopen(x, y) fopen(x, y)
     255             : #define mg_mkdir(x, y) mkdir(x, y)
     256             : #define mg_remove(x) remove(x)
     257             : #define mg_rename(x, y) rename(x, y)
     258             : #define ERRNO errno
     259             : #define INVALID_SOCKET (-1)
     260             : #define INT64_FMT PRId64
     261             : typedef int SOCKET;
     262             : #define WINCDECL
     263             : 
     264             : #endif // End of Windows and UNIX specific includes
     265             : 
     266             : #include "mongoose.h"
     267             : 
     268             : #define MONGOOSE_VERSION "3.1"
     269             : #define PASSWORDS_FILE_NAME ".htpasswd"
     270             : #define CGI_ENVIRONMENT_SIZE 4096
     271             : #define MAX_CGI_ENVIR_VARS 64
     272             : #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
     273             : 
     274             : #ifdef _WIN32
     275             : static pthread_t pthread_self(void) {
     276             :   return GetCurrentThreadId();
     277             : }
     278             : #endif // _WIN32
     279             : 
     280             : #if defined(DEBUG)
     281             : #define DEBUG_TRACE(x) do { \
     282             :   flockfile(stdout); \
     283             :   printf("*** %lu.%p.%s.%d: ", \
     284             :          (unsigned long) time(NULL), (void *) pthread_self(), \
     285             :          __func__, __LINE__); \
     286             :   printf x; \
     287             :   putchar('\n'); \
     288             :   fflush(stdout); \
     289             :   funlockfile(stdout); \
     290             : } while (0)
     291             : #else
     292             : #define DEBUG_TRACE(x)
     293             : #endif // DEBUG
     294             : 
     295             : // Darwin prior to 7.0 and Win32 do not have socklen_t
     296             : #ifdef NO_SOCKLEN_T
     297             : typedef int socklen_t;
     298             : #endif // NO_SOCKLEN_T
     299             : 
     300             : typedef void * (*mg_thread_func_t)(void *);
     301             : 
     302             : static const char *http_500_error = "Internal Server Error";
     303             : 
     304             : // Snatched from OpenSSL includes. I put the prototypes here to be independent
     305             : // from the OpenSSL source installation. Having this, mongoose + SSL can be
     306             : // built on any system with binary SSL libraries installed.
     307             : typedef struct ssl_st SSL;
     308             : typedef struct ssl_method_st SSL_METHOD;
     309             : typedef struct ssl_ctx_st SSL_CTX;
     310             : 
     311             : #define SSL_ERROR_WANT_READ 2
     312             : #define SSL_ERROR_WANT_WRITE 3
     313             : #define SSL_FILETYPE_PEM 1
     314             : #define CRYPTO_LOCK  1
     315             : 
     316             : #if defined(NO_SSL_DL)
     317             : extern void SSL_free(SSL *);
     318             : extern int SSL_accept(SSL *);
     319             : extern int SSL_connect(SSL *);
     320             : extern int SSL_read(SSL *, void *, int);
     321             : extern int SSL_write(SSL *, const void *, int);
     322             : extern int SSL_get_error(const SSL *, int);
     323             : extern int SSL_set_fd(SSL *, int);
     324             : extern SSL *SSL_new(SSL_CTX *);
     325             : extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
     326             : extern SSL_METHOD *SSLv23_server_method(void);
     327             : extern int SSL_library_init(void);
     328             : extern void SSL_load_error_strings(void);
     329             : extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
     330             : extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
     331             : extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
     332             : extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
     333             : extern void SSL_CTX_free(SSL_CTX *);
     334             : extern unsigned long ERR_get_error(void);
     335             : extern char *ERR_error_string(unsigned long, char *);
     336             : extern int CRYPTO_num_locks(void);
     337             : extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
     338             : extern void CRYPTO_set_id_callback(unsigned long (*)(void));
     339             : #else
     340             : // Dynamically loaded SSL functionality
     341             : struct ssl_func {
     342             :   const char *name;   // SSL function name
     343             :   void  (*ptr)(void); // Function pointer
     344             : };
     345             : 
     346             : #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
     347             : #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
     348             : #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
     349             : #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
     350             : #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
     351             : #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
     352             : #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
     353             : #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
     354             : #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
     355             : #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
     356             : #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
     357             : #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
     358             :         const char *, int)) ssl_sw[11].ptr)
     359             : #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
     360             :         const char *, int)) ssl_sw[12].ptr)
     361             : #define SSL_CTX_set_default_passwd_cb \
     362             :   (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
     363             : #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
     364             : #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
     365             : #define SSL_CTX_use_certificate_chain_file \
     366             :   (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
     367             : 
     368             : #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
     369             : #define CRYPTO_set_locking_callback \
     370             :   (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
     371             : #define CRYPTO_set_id_callback \
     372             :   (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
     373             : #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
     374             : #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
     375             : 
     376             : // set_ssl_option() function updates this array.
     377             : // It loads SSL library dynamically and changes NULLs to the actual addresses
     378             : // of respective functions. The macros above (like SSL_connect()) are really
     379             : // just calling these functions indirectly via the pointer.
     380             : static struct ssl_func ssl_sw[] = {
     381             :   {"SSL_free",   NULL},
     382             :   {"SSL_accept",   NULL},
     383             :   {"SSL_connect",   NULL},
     384             :   {"SSL_read",   NULL},
     385             :   {"SSL_write",   NULL},
     386             :   {"SSL_get_error",  NULL},
     387             :   {"SSL_set_fd",   NULL},
     388             :   {"SSL_new",   NULL},
     389             :   {"SSL_CTX_new",   NULL},
     390             :   {"SSLv23_server_method", NULL},
     391             :   {"SSL_library_init",  NULL},
     392             :   {"SSL_CTX_use_PrivateKey_file", NULL},
     393             :   {"SSL_CTX_use_certificate_file",NULL},
     394             :   {"SSL_CTX_set_default_passwd_cb",NULL},
     395             :   {"SSL_CTX_free",  NULL},
     396             :   {"SSL_load_error_strings", NULL},
     397             :   {"SSL_CTX_use_certificate_chain_file", NULL},
     398             :   {NULL,    NULL}
     399             : };
     400             : 
     401             : // Similar array as ssl_sw. These functions could be located in different lib.
     402             : static struct ssl_func crypto_sw[] = {
     403             :   {"CRYPTO_num_locks",  NULL},
     404             :   {"CRYPTO_set_locking_callback", NULL},
     405             :   {"CRYPTO_set_id_callback", NULL},
     406             :   {"ERR_get_error",  NULL},
     407             :   {"ERR_error_string", NULL},
     408             :   {NULL,    NULL}
     409             : };
     410             : #endif // NO_SSL_DL
     411             : 
     412             : static const char *month_names[] = {
     413             :   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     414             :   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     415             : };
     416             : 
     417             : // Unified socket address. For IPv6 support, add IPv6 address structure
     418             : // in the union u.
     419             : struct usa {
     420             :   socklen_t len;
     421             :   union {
     422             :     struct sockaddr sa;
     423             :     struct sockaddr_in sin;
     424             :   } u;
     425             : };
     426             : 
     427             : // Describes a string (chunk of memory).
     428             : struct vec {
     429             :   const char *ptr;
     430             :   size_t len;
     431             : };
     432             : 
     433             : // Structure used by mg_stat() function. Uses 64 bit file length.
     434             : struct mgstat {
     435             :   int is_directory;  // Directory marker
     436             :   int64_t size;      // File size
     437             :   time_t mtime;      // Modification time
     438             : };
     439             : 
     440             : // Describes listening socket, or socket which was accept()-ed by the master
     441             : // thread and queued for future handling by the worker thread.
     442             : struct socket {
     443             :   struct socket *next;  // Linkage
     444             :   SOCKET sock;          // Listening socket
     445             :   struct usa lsa;       // Local socket address
     446             :   struct usa rsa;       // Remote socket address
     447             :   int is_ssl;           // Is socket SSL-ed
     448             :   int is_proxy;
     449             : };
     450             : 
     451             : enum {
     452             :   CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
     453             :   PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE,
     454             :   SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
     455             :   GLOBAL_PASSWORDS_FILE, INDEX_FILES,
     456             :   ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, MAX_REQUEST_SIZE,
     457             :   EXTRA_MIME_TYPES, LISTENING_PORTS,
     458             :   DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER,
     459             :   NUM_OPTIONS
     460             : };
     461             : 
     462             : static const char *config_options[] = {
     463             :   "C", "cgi_extensions", ".cgi,.pl,.php",
     464             :   "E", "cgi_environment", NULL,
     465             :   "G", "put_delete_passwords_file", NULL,
     466             :   "I", "cgi_interpreter", NULL,
     467             :   "P", "protect_uri", NULL,
     468             :   "R", "authentication_domain", "mydomain.com",
     469             :   "S", "ssi_extensions", ".shtml,.shtm",
     470             :   "a", "access_log_file", NULL,
     471             :   "c", "ssl_chain_file", NULL,
     472             :   "d", "enable_directory_listing", "yes",
     473             :   "e", "error_log_file", NULL,
     474             :   "g", "global_passwords_file", NULL,
     475             :   "i", "index_files", "index.html,index.htm,index.cgi",
     476             :   "k", "enable_keep_alive", "no",
     477             :   "l", "access_control_list", NULL,
     478             :   "M", "max_request_size", "16384",
     479             :   "m", "extra_mime_types", NULL,
     480             :   "p", "listening_ports", "8080",
     481             :   "r", "document_root",  ".",
     482             :   "s", "ssl_certificate", NULL,
     483             :   "t", "num_threads", "10",
     484             :   "u", "run_as_user", NULL,
     485             :   NULL
     486             : };
     487             : #define ENTRIES_PER_CONFIG_OPTION 3
     488             : 
     489             : struct mg_context {
     490             :   volatile int stop_flag;       // Should we stop event loop
     491             :   SSL_CTX *ssl_ctx;             // SSL context
     492             :   char *config[NUM_OPTIONS];    // Mongoose configuration parameters
     493             :   mg_callback_t user_callback;  // User-defined callback function
     494             :   void *user_data;              // User-defined data
     495             : 
     496             :   struct socket *listening_sockets;
     497             : 
     498             :   volatile int num_threads;  // Number of threads
     499             :   pthread_mutex_t mutex;     // Protects (max|num)_threads
     500             :   pthread_cond_t  cond;      // Condvar for tracking workers terminations
     501             : 
     502             :   struct socket queue[20];   // Accepted sockets
     503             :   volatile int sq_head;      // Head of the socket queue
     504             :   volatile int sq_tail;      // Tail of the socket queue
     505             :   pthread_cond_t sq_full;    // Singaled when socket is produced
     506             :   pthread_cond_t sq_empty;   // Signaled when socket is consumed
     507             : };
     508             : 
     509             : struct mg_connection {
     510             :   struct mg_connection *peer; // Remote target in proxy mode
     511             :   struct mg_request_info request_info;
     512             :   struct mg_context *ctx;
     513             :   SSL *ssl;                   // SSL descriptor
     514             :   struct socket client;       // Connected client
     515             :   time_t birth_time;          // Time connection was accepted
     516             :   int64_t num_bytes_sent;     // Total bytes sent to client
     517             :   int64_t content_len;        // Content-Length header value
     518             :   int64_t consumed_content;   // How many bytes of content is already read
     519             :   char *buf;                  // Buffer for received data
     520             :   int buf_size;               // Buffer size
     521             :   int request_len;            // Size of the request + headers in a buffer
     522             :   int data_len;               // Total size of data in a buffer
     523             : };
     524             : 
     525           0 : const char **mg_get_valid_option_names(void) {
     526           0 :   return config_options;
     527             : }
     528             : 
     529           0 : static void *call_user(struct mg_connection *conn, enum mg_event event) {
     530           0 :   conn->request_info.user_data = conn->ctx->user_data;
     531           0 :   return conn->ctx->user_callback == NULL ? NULL :
     532           0 :     conn->ctx->user_callback(event, conn, &conn->request_info);
     533             : }
     534             : 
     535           0 : static int get_option_index(const char *name) {
     536             :   int i;
     537             : 
     538           0 :   for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) {
     539           0 :     if (strcmp(config_options[i], name) == 0 ||
     540           0 :         strcmp(config_options[i + 1], name) == 0) {
     541           0 :       return i / ENTRIES_PER_CONFIG_OPTION;
     542             :     }
     543             :   }
     544           0 :   return -1;
     545             : }
     546             : 
     547           0 : const char *mg_get_option(const struct mg_context *ctx, const char *name) {
     548             :   int i;
     549           0 :   if ((i = get_option_index(name)) == -1) {
     550           0 :     return NULL;
     551           0 :   } else if (ctx->config[i] == NULL) {
     552           0 :     return "";
     553             :   } else {
     554           0 :     return ctx->config[i];
     555             :   }
     556             : }
     557             : 
     558             : // Print error message to the opened error log stream.
     559           0 : static void cry(struct mg_connection *conn, const char *fmt, ...) {
     560             :   char buf[BUFSIZ];
     561             :   va_list ap;
     562             :   FILE *fp;
     563             :   time_t timestamp;
     564             : 
     565           0 :   va_start(ap, fmt);
     566           0 :   (void) vsnprintf(buf, sizeof(buf), fmt, ap);
     567           0 :   va_end(ap);
     568             : 
     569             :   // Do not lock when getting the callback value, here and below.
     570             :   // I suppose this is fine, since function cannot disappear in the
     571             :   // same way string option can.
     572           0 :   conn->request_info.log_message = buf;
     573           0 :   if (call_user(conn, MG_EVENT_LOG) == NULL) {
     574           0 :     fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
     575           0 :       mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
     576             : 
     577           0 :     if (fp != NULL) {
     578           0 :       flockfile(fp);
     579           0 :       timestamp = time(NULL);
     580             : 
     581           0 :       (void) fprintf(fp,
     582             :           "[%010lu] [error] [client %s] ",
     583             :           (unsigned long) timestamp,
     584             :           inet_ntoa(conn->client.rsa.u.sin.sin_addr));
     585             : 
     586           0 :       if (conn->request_info.request_method != NULL) {
     587           0 :         (void) fprintf(fp, "%s %s: ",
     588             :             conn->request_info.request_method,
     589             :             conn->request_info.uri);
     590             :       }
     591             : 
     592           0 :       (void) fprintf(fp, "%s", buf);
     593           0 :       fputc('\n', fp);
     594           0 :       funlockfile(fp);
     595           0 :       if (fp != stderr) {
     596           0 :         fclose(fp);
     597             :       }
     598             :     }
     599             :   }
     600           0 :   conn->request_info.log_message = NULL;
     601           0 : }
     602             : 
     603             : // Return OpenSSL error message
     604           0 : static const char *ssl_error(void) {
     605             :   unsigned long err;
     606           0 :   err = ERR_get_error();
     607           0 :   return err == 0 ? "" : ERR_error_string(err, NULL);
     608             : }
     609             : 
     610             : // Return fake connection structure. Used for logging, if connection
     611             : // is not applicable at the moment of logging.
     612           0 : static struct mg_connection *fc(struct mg_context *ctx) {
     613             :   static struct mg_connection fake_connection;
     614           0 :   fake_connection.ctx = ctx;
     615           0 :   return &fake_connection;
     616             : }
     617             : 
     618           0 : const char *mg_version(void) {
     619           0 :   return MONGOOSE_VERSION;
     620             : }
     621             : 
     622           0 : static void mg_strlcpy(char *dst, const char *src, size_t n) {
     623           0 :   for (; *src != '\0' && n > 1; n--) {
     624           0 :     *dst++ = *src++;
     625             :   }
     626           0 :   *dst = '\0';
     627           0 : }
     628             : 
     629           0 : static int lowercase(const char *s) {
     630           0 :   return tolower(* (const unsigned char *) s);
     631             : }
     632             : 
     633           0 : static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
     634           0 :   int diff = 0;
     635             : 
     636           0 :   if (len > 0)
     637           0 :     do {
     638           0 :       diff = lowercase(s1++) - lowercase(s2++);
     639           0 :     } while (diff == 0 && s1[-1] != '\0' && --len > 0);
     640             : 
     641           0 :   return diff;
     642             : }
     643             : 
     644           0 : static int mg_strcasecmp(const char *s1, const char *s2) {
     645             :   int diff;
     646             : 
     647           0 :   do {
     648           0 :     diff = lowercase(s1++) - lowercase(s2++);
     649           0 :   } while (diff == 0 && s1[-1] != '\0');
     650             : 
     651           0 :   return diff;
     652             : }
     653             : 
     654           0 : static char * mg_strndup(const char *ptr, size_t len) {
     655             :   char *p;
     656             : 
     657           0 :   if ((p = (char *) malloc(len + 1)) != NULL) {
     658           0 :     mg_strlcpy(p, ptr, len + 1);
     659             :   }
     660             : 
     661           0 :   return p;
     662             : }
     663             : 
     664           0 : static char * mg_strdup(const char *str) {
     665           0 :   return mg_strndup(str, strlen(str));
     666             : }
     667             : 
     668             : // Like snprintf(), but never returns negative value, or the value
     669             : // that is larger than a supplied buffer.
     670             : // Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
     671             : // in his audit report.
     672           0 : static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
     673             :                         const char *fmt, va_list ap) {
     674             :   int n;
     675             : 
     676           0 :   if (buflen == 0)
     677           0 :     return 0;
     678             : 
     679           0 :   n = vsnprintf(buf, buflen, fmt, ap);
     680             : 
     681           0 :   if (n < 0) {
     682           0 :     cry(conn, "vsnprintf error");
     683           0 :     n = 0;
     684           0 :   } else if (n >= (int) buflen) {
     685           0 :     cry(conn, "truncating vsnprintf buffer: [%.*s]",
     686             :         n > 200 ? 200 : n, buf);
     687           0 :     n = (int) buflen - 1;
     688             :   }
     689           0 :   buf[n] = '\0';
     690             : 
     691           0 :   return n;
     692             : }
     693             : 
     694           0 : static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
     695             :                        const char *fmt, ...) {
     696             :   va_list ap;
     697             :   int n;
     698             : 
     699           0 :   va_start(ap, fmt);
     700           0 :   n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
     701           0 :   va_end(ap);
     702             : 
     703           0 :   return n;
     704             : }
     705             : 
     706             : // Skip the characters until one of the delimiters characters found.
     707             : // 0-terminate resulting word. Skip the delimiter and following whitespaces if any.
     708             : // Advance pointer to buffer to the next word. Return found 0-terminated word.
     709             : // Delimiters can be quoted with quotechar.
     710           0 : static char *skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar) {
     711             :   char *p, *begin_word, *end_word, *end_whitespace;
     712             : 
     713           0 :   begin_word = *buf;
     714           0 :   end_word = begin_word + strcspn(begin_word, delimiters);
     715             : 
     716             :   // Check for quotechar
     717           0 :   if (end_word > begin_word) {
     718           0 :     p = end_word - 1;
     719           0 :     while (*p == quotechar) {
     720             :       // If there is anything beyond end_word, copy it
     721           0 :       if (*end_word == '\0') {
     722           0 :         *p = '\0';
     723           0 :         break;
     724             :       } else {
     725           0 :         size_t end_off = strcspn(end_word + 1, delimiters);
     726           0 :         memmove (p, end_word, end_off + 1);
     727           0 :         p += end_off; // p must correspond to end_word - 1
     728           0 :         end_word += end_off + 1;
     729             :       }
     730             :     }
     731           0 :     for (p++; p < end_word; p++) {
     732           0 :       *p = '\0';
     733             :     }
     734             :   }
     735             : 
     736           0 :   if (*end_word == '\0') {
     737           0 :     *buf = end_word;
     738             :   } else {
     739           0 :     end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
     740             : 
     741           0 :     for (p = end_word; p < end_whitespace; p++) {
     742           0 :       *p = '\0';
     743             :     }
     744             : 
     745           0 :     *buf = end_whitespace;
     746             :   }
     747             : 
     748           0 :   return begin_word;
     749             : }
     750             : 
     751             : // Simplified version of skip_quoted without quote char
     752             : // and whitespace == delimiters
     753           0 : static char *skip(char **buf, const char *delimiters) {
     754           0 :   return skip_quoted(buf, delimiters, delimiters, 0);
     755             : }
     756             : 
     757             : 
     758             : // Return HTTP header value, or NULL if not found.
     759           0 : static const char *get_header(const struct mg_request_info *ri,
     760             :                               const char *name) {
     761             :   int i;
     762             : 
     763           0 :   for (i = 0; i < ri->num_headers; i++)
     764           0 :     if (!mg_strcasecmp(name, ri->http_headers[i].name))
     765           0 :       return ri->http_headers[i].value;
     766             : 
     767           0 :   return NULL;
     768             : }
     769             : 
     770           0 : const char *mg_get_header(const struct mg_connection *conn, const char *name) {
     771           0 :   return get_header(&conn->request_info, name);
     772             : }
     773             : 
     774             : // A helper function for traversing comma separated list of values.
     775             : // It returns a list pointer shifted to the next value, of NULL if the end
     776             : // of the list found.
     777             : // Value is stored in val vector. If value has form "x=y", then eq_val
     778             : // vector is initialized to point to the "y" part, and val vector length
     779             : // is adjusted to point only to "x".
     780           0 : static const char *next_option(const char *list, struct vec *val,
     781             :                                struct vec *eq_val) {
     782           0 :   if (list == NULL || *list == '\0') {
     783             :     // End of the list
     784           0 :     list = NULL;
     785             :   } else {
     786           0 :     val->ptr = list;
     787           0 :     if ((list = strchr(val->ptr, ',')) != NULL) {
     788             :       // Comma found. Store length and shift the list ptr
     789           0 :       val->len = list - val->ptr;
     790           0 :       list++;
     791             :     } else {
     792             :       // This value is the last one
     793           0 :       list = val->ptr + strlen(val->ptr);
     794           0 :       val->len = list - val->ptr;
     795             :     }
     796             : 
     797           0 :     if (eq_val != NULL) {
     798             :       // Value has form "x=y", adjust pointers and lengths
     799             :       // so that val points to "x", and eq_val points to "y".
     800           0 :       eq_val->len = 0;
     801           0 :       eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
     802           0 :       if (eq_val->ptr != NULL) {
     803           0 :         eq_val->ptr++;  // Skip over '=' character
     804           0 :         eq_val->len = val->ptr + val->len - eq_val->ptr;
     805           0 :         val->len = (eq_val->ptr - val->ptr) - 1;
     806             :       }
     807             :     }
     808             :   }
     809             : 
     810           0 :   return list;
     811             : }
     812             : 
     813           0 : static int match_extension(const char *path, const char *ext_list) {
     814             :   struct vec ext_vec;
     815             :   size_t path_len;
     816             : 
     817           0 :   path_len = strlen(path);
     818             : 
     819           0 :   while ((ext_list = next_option(ext_list, &ext_vec, NULL)) != NULL)
     820           0 :     if (ext_vec.len < path_len &&
     821           0 :         mg_strncasecmp(path + path_len - ext_vec.len,
     822             :           ext_vec.ptr, ext_vec.len) == 0)
     823           0 :       return 1;
     824             : 
     825           0 :   return 0;
     826             : }
     827             : 
     828             : // HTTP 1.1 assumes keep alive if "Connection:" header is not set
     829             : // This function must tolerate situations when connection info is not
     830             : // set up, for example if request parsing failed.
     831           0 : static int should_keep_alive(const struct mg_connection *conn) {
     832           0 :   const char *http_version = conn->request_info.http_version;
     833           0 :   const char *header = mg_get_header(conn, "Connection");
     834           0 :   return (header == NULL && http_version && !strcmp(http_version, "1.1")) ||
     835           0 :       (header != NULL && !mg_strcasecmp(header, "keep-alive"));
     836             : }
     837             : 
     838           0 : static const char *suggest_connection_header(const struct mg_connection *conn) {
     839           0 :   return should_keep_alive(conn) ? "keep-alive" : "close";
     840             : }
     841             : 
     842           0 : static void send_http_error(struct mg_connection *conn, int status,
     843             :                             const char *reason, const char *fmt, ...) {
     844             :   char buf[BUFSIZ];
     845             :   va_list ap;
     846             :   int len;
     847             : 
     848           0 :   conn->request_info.status_code = status;
     849             : 
     850           0 :   if (call_user(conn, MG_HTTP_ERROR) == NULL) {
     851           0 :     buf[0] = '\0';
     852           0 :     len = 0;
     853             : 
     854             :     // Errors 1xx, 204 and 304 MUST NOT send a body
     855           0 :     if (status > 199 && status != 204 && status != 304) {
     856           0 :       len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
     857           0 :       cry(conn, "%s", buf);
     858           0 :       buf[len++] = '\n';
     859             : 
     860           0 :       va_start(ap, fmt);
     861           0 :       len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
     862           0 :       va_end(ap);
     863             :     }
     864             :     DEBUG_TRACE(("[%s]", buf));
     865             : 
     866           0 :     mg_printf(conn, "HTTP/1.1 %d %s\r\n"
     867             :               "Content-Type: text/plain\r\n"
     868             :               "Content-Length: %d\r\n"
     869             :               "Connection: %s\r\n\r\n", status, reason, len,
     870             :               suggest_connection_header(conn));
     871           0 :     conn->num_bytes_sent += mg_printf(conn, "%s", buf);
     872             :   }
     873           0 : }
     874             : 
     875             : #if defined(_WIN32) && !defined(__SYMBIAN32__)
     876             : static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
     877             :   unused = NULL;
     878             :   *mutex = CreateMutex(NULL, FALSE, NULL);
     879             :   return *mutex == NULL ? -1 : 0;
     880             : }
     881             : 
     882             : static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
     883             :   return CloseHandle(*mutex) == 0 ? -1 : 0;
     884             : }
     885             : 
     886             : static int pthread_mutex_lock(pthread_mutex_t *mutex) {
     887             :   return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
     888             : }
     889             : 
     890             : static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
     891             :   return ReleaseMutex(*mutex) == 0 ? -1 : 0;
     892             : }
     893             : 
     894             : static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
     895             :   unused = NULL;
     896             :   cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
     897             :   cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
     898             :   return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
     899             : }
     900             : 
     901             : static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
     902             :   HANDLE handles[] = {cv->signal, cv->broadcast};
     903             :   ReleaseMutex(*mutex);
     904             :   WaitForMultipleObjects(2, handles, FALSE, INFINITE);
     905             :   return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
     906             : }
     907             : 
     908             : static int pthread_cond_signal(pthread_cond_t *cv) {
     909             :   return SetEvent(cv->signal) == 0 ? -1 : 0;
     910             : }
     911             : 
     912             : static int pthread_cond_broadcast(pthread_cond_t *cv) {
     913             :   // Implementation with PulseEvent() has race condition, see
     914             :   // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
     915             :   return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
     916             : }
     917             : 
     918             : static int pthread_cond_destroy(pthread_cond_t *cv) {
     919             :   return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
     920             : }
     921             : 
     922             : // For Windows, change all slashes to backslashes in path names.
     923             : static void change_slashes_to_backslashes(char *path) {
     924             :   int i;
     925             : 
     926             :   for (i = 0; path[i] != '\0'; i++) {
     927             :     if (path[i] == '/')
     928             :       path[i] = '\\';
     929             :     // i > 0 check is to preserve UNC paths, like \\server\file.txt
     930             :     if (path[i] == '\\' && i > 0)
     931             :       while (path[i + 1] == '\\' || path[i + 1] == '/')
     932             :         (void) memmove(path + i + 1,
     933             :             path + i + 2, strlen(path + i + 1));
     934             :   }
     935             : }
     936             : 
     937             : // Encode 'path' which is assumed UTF-8 string, into UNICODE string.
     938             : // wbuf and wbuf_len is a target buffer and its length.
     939             : static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
     940             :   char buf[PATH_MAX], buf2[PATH_MAX], *p;
     941             : 
     942             :   mg_strlcpy(buf, path, sizeof(buf));
     943             :   change_slashes_to_backslashes(buf);
     944             : 
     945             :   // Point p to the end of the file name
     946             :   p = buf + strlen(buf) - 1;
     947             : 
     948             :   // Trim trailing backslash character
     949             :   while (p > buf && *p == '\\' && p[-1] != ':') {
     950             :     *p-- = '\0';
     951             :   }
     952             : 
     953             :    // Protect from CGI code disclosure.
     954             :    // This is very nasty hole. Windows happily opens files with
     955             :    // some garbage in the end of file name. So fopen("a.cgi    ", "r")
     956             :    // actually opens "a.cgi", and does not return an error!
     957             :   if (*p == 0x20 ||               // No space at the end
     958             :       (*p == 0x2e && p > buf) ||  // No '.' but allow '.' as full path
     959             :       *p == 0x2b ||               // No '+'
     960             :       (*p & ~0x7f)) {             // And generally no non-ascii chars
     961             :     (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
     962             :     wbuf[0] = L'\0';
     963             :   } else {
     964             :     // Convert to Unicode and back. If doubly-converted string does not
     965             :     // match the original, something is fishy, reject.
     966             :     MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
     967             :     WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
     968             :                         NULL, NULL);
     969             :     if (strcmp(buf, buf2) != 0) {
     970             :       wbuf[0] = L'\0';
     971             :     }
     972             :   }
     973             : }
     974             : 
     975             : #if defined(_WIN32_WCE)
     976             : static time_t time(time_t *ptime) {
     977             :   time_t t;
     978             :   SYSTEMTIME st;
     979             :   FILETIME ft;
     980             : 
     981             :   GetSystemTime(&st);
     982             :   SystemTimeToFileTime(&st, &ft);
     983             :   t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
     984             : 
     985             :   if (ptime != NULL) {
     986             :     *ptime = t;
     987             :   }
     988             : 
     989             :   return t;
     990             : }
     991             : 
     992             : static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
     993             :   int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
     994             :   FILETIME ft, lft;
     995             :   SYSTEMTIME st;
     996             :   TIME_ZONE_INFORMATION tzinfo;
     997             : 
     998             :   if (ptm == NULL) {
     999             :     return NULL;
    1000             :   }
    1001             : 
    1002             :   * (int64_t *) &ft = t;
    1003             :   FileTimeToLocalFileTime(&ft, &lft);
    1004             :   FileTimeToSystemTime(&lft, &st);
    1005             :   ptm->tm_year = st.wYear - 1900;
    1006             :   ptm->tm_mon = st.wMonth - 1;
    1007             :   ptm->tm_wday = st.wDayOfWeek;
    1008             :   ptm->tm_mday = st.wDay;
    1009             :   ptm->tm_hour = st.wHour;
    1010             :   ptm->tm_min = st.wMinute;
    1011             :   ptm->tm_sec = st.wSecond;
    1012             :   ptm->tm_yday = 0; // hope nobody uses this
    1013             :   ptm->tm_isdst =
    1014             :     GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
    1015             : 
    1016             :   return ptm;
    1017             : }
    1018             : 
    1019             : static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
    1020             :   // FIXME(lsm): fix this.
    1021             :   return localtime(ptime, ptm);
    1022             : }
    1023             : 
    1024             : static size_t strftime(char *dst, size_t dst_size, const char *fmt,
    1025             :                        const struct tm *tm) {
    1026             :   (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
    1027             :   return 0;
    1028             : }
    1029             : #endif
    1030             : 
    1031             : static int mg_rename(const char* oldname, const char* newname) {
    1032             :   wchar_t woldbuf[PATH_MAX];
    1033             :   wchar_t wnewbuf[PATH_MAX];
    1034             : 
    1035             :   to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
    1036             :   to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
    1037             : 
    1038             :   return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
    1039             : }
    1040             : 
    1041             : 
    1042             : static FILE *mg_fopen(const char *path, const char *mode) {
    1043             :   wchar_t wbuf[PATH_MAX], wmode[20];
    1044             : 
    1045             :   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1046             :   MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
    1047             : 
    1048             :   return _wfopen(wbuf, wmode);
    1049             : }
    1050             : 
    1051             : static int mg_stat(const char *path, struct mgstat *stp) {
    1052             :   int ok = -1; // Error
    1053             :   wchar_t wbuf[PATH_MAX];
    1054             :   WIN32_FILE_ATTRIBUTE_DATA info;
    1055             : 
    1056             :   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1057             : 
    1058             :   if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
    1059             :     stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
    1060             :     stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
    1061             :                                info.ftLastWriteTime.dwHighDateTime);
    1062             :     stp->is_directory =
    1063             :       info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
    1064             :     ok = 0;  // Success
    1065             :   }
    1066             : 
    1067             :   return ok;
    1068             : }
    1069             : 
    1070             : static int mg_remove(const char *path) {
    1071             :   wchar_t wbuf[PATH_MAX];
    1072             :   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1073             :   return DeleteFileW(wbuf) ? 0 : -1;
    1074             : }
    1075             : 
    1076             : static int mg_mkdir(const char *path, int mode) {
    1077             :   char buf[PATH_MAX];
    1078             :   wchar_t wbuf[PATH_MAX];
    1079             : 
    1080             :   mode = 0; // Unused
    1081             :   mg_strlcpy(buf, path, sizeof(buf));
    1082             :   change_slashes_to_backslashes(buf);
    1083             : 
    1084             :   (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
    1085             : 
    1086             :   return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
    1087             : }
    1088             : 
    1089             : // Implementation of POSIX opendir/closedir/readdir for Windows.
    1090             : static DIR * opendir(const char *name) {
    1091             :   DIR *dir = NULL;
    1092             :   wchar_t wpath[PATH_MAX];
    1093             :   DWORD attrs;
    1094             : 
    1095             :   if (name == NULL) {
    1096             :     SetLastError(ERROR_BAD_ARGUMENTS);
    1097             :   } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
    1098             :     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    1099             :   } else {
    1100             :     to_unicode(name, wpath, ARRAY_SIZE(wpath));
    1101             :     attrs = GetFileAttributesW(wpath);
    1102             :     if (attrs != 0xFFFFFFFF &&
    1103             :         ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
    1104             :       (void) wcscat(wpath, L"\\*");
    1105             :       dir->handle = FindFirstFileW(wpath, &dir->info);
    1106             :       dir->result.d_name[0] = '\0';
    1107             :     } else {
    1108             :       free(dir);
    1109             :       dir = NULL;
    1110             :     }
    1111             :   }
    1112             : 
    1113             :   return dir;
    1114             : }
    1115             : 
    1116             : static int closedir(DIR *dir) {
    1117             :   int result = 0;
    1118             : 
    1119             :   if (dir != NULL) {
    1120             :     if (dir->handle != INVALID_HANDLE_VALUE)
    1121             :       result = FindClose(dir->handle) ? 0 : -1;
    1122             : 
    1123             :     free(dir);
    1124             :   } else {
    1125             :     result = -1;
    1126             :     SetLastError(ERROR_BAD_ARGUMENTS);
    1127             :   }
    1128             : 
    1129             :   return result;
    1130             : }
    1131             : 
    1132             : struct dirent * readdir(DIR *dir) {
    1133             :   struct dirent *result = 0;
    1134             : 
    1135             :   if (dir) {
    1136             :     if (dir->handle != INVALID_HANDLE_VALUE) {
    1137             :       result = &dir->result;
    1138             :       (void) WideCharToMultiByte(CP_UTF8, 0,
    1139             :           dir->info.cFileName, -1, result->d_name,
    1140             :           sizeof(result->d_name), NULL, NULL);
    1141             : 
    1142             :       if (!FindNextFileW(dir->handle, &dir->info)) {
    1143             :         (void) FindClose(dir->handle);
    1144             :         dir->handle = INVALID_HANDLE_VALUE;
    1145             :       }
    1146             : 
    1147             :     } else {
    1148             :       SetLastError(ERROR_FILE_NOT_FOUND);
    1149             :     }
    1150             :   } else {
    1151             :     SetLastError(ERROR_BAD_ARGUMENTS);
    1152             :   }
    1153             : 
    1154             :   return result;
    1155             : }
    1156             : 
    1157             : #define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
    1158             : 
    1159             : static int start_thread(struct mg_context *ctx, mg_thread_func_t f, void *p) {
    1160             :   return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
    1161             : }
    1162             : 
    1163             : static HANDLE dlopen(const char *dll_name, int flags) {
    1164             :   wchar_t wbuf[PATH_MAX];
    1165             :   flags = 0; // Unused
    1166             :   to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
    1167             :   return LoadLibraryW(wbuf);
    1168             : }
    1169             : 
    1170             : #if !defined(NO_CGI)
    1171             : #define SIGKILL 0
    1172             : static int kill(pid_t pid, int sig_num) {
    1173             :   (void) TerminateProcess(pid, sig_num);
    1174             :   (void) CloseHandle(pid);
    1175             :   return 0;
    1176             : }
    1177             : 
    1178             : static pid_t spawn_process(struct mg_connection *conn, const char *prog,
    1179             :                            char *envblk, char *envp[], int fd_stdin,
    1180             :                            int fd_stdout, const char *dir) {
    1181             :   HANDLE me;
    1182             :   char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX];
    1183             :   FILE *fp;
    1184             :   STARTUPINFOA si;
    1185             :   PROCESS_INFORMATION pi;
    1186             : 
    1187             :   envp = NULL; // Unused
    1188             : 
    1189             :   (void) memset(&si, 0, sizeof(si));
    1190             :   (void) memset(&pi, 0, sizeof(pi));
    1191             : 
    1192             :   // TODO(lsm): redirect CGI errors to the error log file
    1193             :   si.cb  = sizeof(si);
    1194             :   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    1195             :   si.wShowWindow = SW_HIDE;
    1196             : 
    1197             :   me = GetCurrentProcess();
    1198             :   (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
    1199             :       &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    1200             :   (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
    1201             :       &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    1202             : 
    1203             :   // If CGI file is a script, try to read the interpreter line
    1204             :   interp = conn->ctx->config[CGI_INTERPRETER];
    1205             :   if (interp == NULL) {
    1206             :     buf[2] = '\0';
    1207             :     mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s", dir, DIRSEP, prog);
    1208             :     if ((fp = fopen(cmdline, "r")) != NULL) {
    1209             :       (void) fgets(buf, sizeof(buf), fp);
    1210             :       if (buf[0] != '#' || buf[1] != '!') {
    1211             :         // First line does not start with "#!". Do not set interpreter.
    1212             :         buf[2] = '\0';
    1213             :       } else {
    1214             :         // Trim whitespaces in interpreter name
    1215             :         for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
    1216             :           *p = '\0';
    1217             :         }
    1218             :       }
    1219             :       (void) fclose(fp);
    1220             :     }
    1221             :     interp = buf + 2;
    1222             :   }
    1223             : 
    1224             :   (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s",
    1225             :                      interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog);
    1226             : 
    1227             :   DEBUG_TRACE(("Running [%s]", cmdline));
    1228             :   if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
    1229             :         CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
    1230             :     cry(conn, "%s: CreateProcess(%s): %d",
    1231             :         __func__, cmdline, ERRNO);
    1232             :     pi.hProcess = (pid_t) -1;
    1233             :   } else {
    1234             :     (void) close(fd_stdin);
    1235             :     (void) close(fd_stdout);
    1236             :   }
    1237             : 
    1238             :   (void) CloseHandle(si.hStdOutput);
    1239             :   (void) CloseHandle(si.hStdInput);
    1240             :   (void) CloseHandle(pi.hThread);
    1241             : 
    1242             :   return (pid_t) pi.hProcess;
    1243             : }
    1244             : #endif // !NO_CGI
    1245             : 
    1246             : static int set_non_blocking_mode(SOCKET sock) {
    1247             :   unsigned long on = 1;
    1248             :   return ioctlsocket(sock, FIONBIO, &on);
    1249             : }
    1250             : 
    1251             : #else
    1252           0 : static int mg_stat(const char *path, struct mgstat *stp) {
    1253             :   struct stat st;
    1254             :   int ok;
    1255             : 
    1256           0 :   if (stat(path, &st) == 0) {
    1257           0 :     ok = 0;
    1258           0 :     stp->size = st.st_size;
    1259           0 :     stp->mtime = st.st_mtime;
    1260           0 :     stp->is_directory = S_ISDIR(st.st_mode);
    1261             :   } else {
    1262           0 :     ok = -1;
    1263             :   }
    1264             : 
    1265           0 :   return ok;
    1266             : }
    1267             : 
    1268           0 : static void set_close_on_exec(int fd) {
    1269           0 :   (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
    1270           0 : }
    1271             : 
    1272           0 : static int start_thread(struct mg_context *ctx, mg_thread_func_t func,
    1273             :                         void *param) {
    1274             :   pthread_t thread_id;
    1275             :   pthread_attr_t attr;
    1276             :   int retval;
    1277             : 
    1278           0 :   (void) pthread_attr_init(&attr);
    1279           0 :   (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    1280             :   // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
    1281             :   // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
    1282             : 
    1283           0 :   if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) {
    1284           0 :     cry(fc(ctx), "%s: %s", __func__, strerror(retval));
    1285             :   }
    1286             : 
    1287           0 :   return retval;
    1288             : }
    1289             : 
    1290             : #ifndef NO_CGI
    1291             : static pid_t spawn_process(struct mg_connection *conn, const char *prog,
    1292             :                            char *envblk, char *envp[], int fd_stdin,
    1293             :                            int fd_stdout, const char *dir) {
    1294             :   pid_t pid;
    1295             :   const char *interp;
    1296             : 
    1297             :   envblk = NULL; // Unused
    1298             : 
    1299             :   if ((pid = fork()) == -1) {
    1300             :     // Parent
    1301             :     send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
    1302             :   } else if (pid == 0) {
    1303             :     // Child
    1304             :     if (chdir(dir) != 0) {
    1305             :       cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
    1306             :     } else if (dup2(fd_stdin, 0) == -1) {
    1307             :       cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
    1308             :     } else if (dup2(fd_stdout, 1) == -1) {
    1309             :       cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
    1310             :     } else {
    1311             :       (void) dup2(fd_stdout, 2);
    1312             :       (void) close(fd_stdin);
    1313             :       (void) close(fd_stdout);
    1314             : 
    1315             :       // Execute CGI program. No need to lock: new process
    1316             :       interp = conn->ctx->config[CGI_INTERPRETER];
    1317             :       if (interp == NULL) {
    1318             :         (void) execle(prog, prog, NULL, envp);
    1319             :         cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
    1320             :       } else {
    1321             :         (void) execle(interp, interp, prog, NULL, envp);
    1322             :         cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
    1323             :             strerror(ERRNO));
    1324             :       }
    1325             :     }
    1326             :     exit(EXIT_FAILURE);
    1327             :   } else {
    1328             :     // Parent. Close stdio descriptors
    1329             :     (void) close(fd_stdin);
    1330             :     (void) close(fd_stdout);
    1331             :   }
    1332             : 
    1333             :   return pid;
    1334             : }
    1335             : #endif // !NO_CGI
    1336             : 
    1337           0 : static int set_non_blocking_mode(SOCKET sock) {
    1338             :   int flags;
    1339             : 
    1340           0 :   flags = fcntl(sock, F_GETFL, 0);
    1341           0 :   (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
    1342             : 
    1343           0 :   return 0;
    1344             : }
    1345             : #endif // _WIN32
    1346             : 
    1347             : // Write data to the IO channel - opened file descriptor, socket or SSL
    1348             : // descriptor. Return number of bytes written.
    1349           0 : static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
    1350             :                     int64_t len) {
    1351             :   int64_t sent;
    1352             :   int n, k;
    1353             : 
    1354           0 :   sent = 0;
    1355           0 :   while (sent < len) {
    1356             : 
    1357             :     // How many bytes we send in this iteration
    1358           0 :     k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
    1359             : 
    1360           0 :     if (ssl != NULL) {
    1361           0 :       n = SSL_write(ssl, buf + sent, k);
    1362           0 :     } else if (fp != NULL) {
    1363           0 :       n = fwrite(buf + sent, 1, (size_t)k, fp);
    1364           0 :       if (ferror(fp))
    1365           0 :         n = -1;
    1366             :     } else {
    1367           0 :       n = send(sock, buf + sent, (size_t)k, 0);
    1368             :     }
    1369             : 
    1370           0 :     if (n < 0)
    1371           0 :       break;
    1372             : 
    1373           0 :     sent += n;
    1374             :   }
    1375             : 
    1376           0 :   return sent;
    1377             : }
    1378             : 
    1379             : // Read from IO channel - opened file descriptor, socket, or SSL descriptor.
    1380             : // Return number of bytes read.
    1381           0 : static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
    1382             :   int nread;
    1383             : 
    1384           0 :   if (ssl != NULL) {
    1385           0 :     nread = SSL_read(ssl, buf, len);
    1386           0 :   } else if (fp != NULL) {
    1387             :     // Use read() instead of fread(), because if we're reading from the CGI
    1388             :     // pipe, fread() may block until IO buffer is filled up. We cannot afford
    1389             :     // to block and must pass all read bytes immediately to the client.
    1390           0 :     nread = read(fileno(fp), buf, (size_t) len);
    1391           0 :     if (ferror(fp))
    1392           0 :       nread = -1;
    1393             :   } else {
    1394           0 :     nread = recv(sock, buf, (size_t) len, 0);
    1395             :   }
    1396             : 
    1397           0 :   return nread;
    1398             : }
    1399             : 
    1400           0 : int mg_read(struct mg_connection *conn, void *buf, size_t len) {
    1401             :   int n, buffered_len, nread;
    1402             :   const char *buffered;
    1403             : 
    1404           0 :   assert((conn->content_len == -1 && conn->consumed_content == 0) ||
    1405             :          conn->consumed_content <= conn->content_len);
    1406             :   DEBUG_TRACE(("%p %zu %lld %lld", buf, len,
    1407             :                conn->content_len, conn->consumed_content));
    1408           0 :   nread = 0;
    1409           0 :   if (conn->consumed_content < conn->content_len) {
    1410             : 
    1411             :     // Adjust number of bytes to read.
    1412           0 :     int64_t to_read = conn->content_len - conn->consumed_content;
    1413           0 :     if (to_read < (int64_t) len) {
    1414           0 :       len = (int) to_read;
    1415             :     }
    1416             : 
    1417             :     // How many bytes of data we have buffered in the request buffer?
    1418           0 :     buffered = conn->buf + conn->request_len + conn->consumed_content;
    1419           0 :     buffered_len = conn->data_len - conn->request_len;
    1420           0 :     assert(buffered_len >= 0);
    1421             : 
    1422             :     // Return buffered data back if we haven't done that yet.
    1423           0 :     if (conn->consumed_content < (int64_t) buffered_len) {
    1424           0 :       buffered_len -= (int) conn->consumed_content;
    1425           0 :       if (len < (size_t) buffered_len) {
    1426           0 :         buffered_len = len;
    1427             :       }
    1428           0 :       memcpy(buf, buffered, (size_t)buffered_len);
    1429           0 :       len -= buffered_len;
    1430           0 :       buf = (char *) buf + buffered_len;
    1431           0 :       conn->consumed_content += buffered_len;
    1432           0 :       nread = buffered_len;
    1433             :     }
    1434             : 
    1435             :     // We have returned all buffered data. Read new data from the remote socket.
    1436           0 :     while (len > 0) {
    1437           0 :       n = pull(NULL, conn->client.sock, conn->ssl, (char *) buf, (int) len);
    1438           0 :       if (n <= 0) {
    1439           0 :         break;
    1440             :       }
    1441           0 :       buf = (char *) buf + n;
    1442           0 :       conn->consumed_content += n;
    1443           0 :       nread += n;
    1444           0 :       len -= n;
    1445             :     }
    1446             :   }
    1447           0 :   return nread;
    1448             : }
    1449             : 
    1450           0 : int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
    1451           0 :   return (int) push(NULL, conn->client.sock, conn->ssl,
    1452           0 :       (const char *) buf, (int64_t) len);
    1453             : }
    1454             : 
    1455           0 : int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
    1456             :   char buf[BUFSIZ];
    1457             :   int len;
    1458             :   va_list ap;
    1459             : 
    1460           0 :   va_start(ap, fmt);
    1461           0 :   len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
    1462           0 :   va_end(ap);
    1463             : 
    1464           0 :   return mg_write(conn, buf, (size_t)len);
    1465             : }
    1466             : 
    1467             : // URL-decode input buffer into destination buffer.
    1468             : // 0-terminate the destination buffer. Return the length of decoded data.
    1469             : // form-url-encoded data differs from URI encoding in a way that it
    1470             : // uses '+' as character for space, see RFC 1866 section 8.2.1
    1471             : // http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
    1472           0 : static size_t url_decode(const char *src, size_t src_len, char *dst,
    1473             :                          size_t dst_len, int is_form_url_encoded) {
    1474             :   size_t i, j;
    1475             :   int a, b;
    1476             : #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
    1477             : 
    1478           0 :   for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
    1479           0 :     if (src[i] == '%' &&
    1480           0 :         isxdigit(* (const unsigned char *) (src + i + 1)) &&
    1481           0 :         isxdigit(* (const unsigned char *) (src + i + 2))) {
    1482           0 :       a = tolower(* (const unsigned char *) (src + i + 1));
    1483           0 :       b = tolower(* (const unsigned char *) (src + i + 2));
    1484           0 :       dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
    1485           0 :       i += 2;
    1486           0 :     } else if (is_form_url_encoded && src[i] == '+') {
    1487           0 :       dst[j] = ' ';
    1488             :     } else {
    1489           0 :       dst[j] = src[i];
    1490             :     }
    1491             :   }
    1492             : 
    1493           0 :   dst[j] = '\0'; // Null-terminate the destination
    1494             : 
    1495           0 :   return j;
    1496             : }
    1497             : 
    1498             : // Scan given buffer and fetch the value of the given variable.
    1499             : // It can be specified in query string, or in the POST data.
    1500             : // Return NULL if the variable not found, or allocated 0-terminated value.
    1501             : // It is caller's responsibility to free the returned value.
    1502           0 : int mg_get_var(const char *buf, size_t buf_len, const char *name,
    1503             :                char *dst, size_t dst_len) {
    1504             :   const char *p, *e, *s;
    1505             :   size_t name_len, len;
    1506             : 
    1507           0 :   name_len = strlen(name);
    1508           0 :   e = buf + buf_len;
    1509           0 :   len = -1;
    1510           0 :   dst[0] = '\0';
    1511             : 
    1512             :   // buf is "var1=val1&var2=val2...". Find variable first
    1513           0 :   for (p = buf; p != NULL && p + name_len < e; p++) {
    1514           0 :     if ((p == buf || p[-1] == '&') && p[name_len] == '=' &&
    1515           0 :         !mg_strncasecmp(name, p, name_len)) {
    1516             : 
    1517             :       // Point p to variable value
    1518           0 :       p += name_len + 1;
    1519             : 
    1520             :       // Point s to the end of the value
    1521           0 :       s = (const char *) memchr(p, '&', (size_t)(e - p));
    1522           0 :       if (s == NULL) {
    1523           0 :         s = e;
    1524             :       }
    1525           0 :       assert(s >= p);
    1526             : 
    1527             :       // Decode variable into destination buffer
    1528           0 :       if ((size_t) (s - p) < dst_len) {
    1529           0 :         len = url_decode(p, (size_t)(s - p), dst, dst_len, 1);
    1530             :       }
    1531           0 :       break;
    1532             :     }
    1533             :   }
    1534             : 
    1535           0 :   return len;
    1536             : }
    1537             : 
    1538           0 : int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
    1539             :                   char *dst, size_t dst_size) {
    1540             :   const char *s, *p, *end;
    1541           0 :   int name_len, len = -1;
    1542             : 
    1543           0 :   dst[0] = '\0';
    1544           0 :   if ((s = mg_get_header(conn, "Cookie")) == NULL) {
    1545           0 :     return 0;
    1546             :   }
    1547             : 
    1548           0 :   name_len = strlen(cookie_name);
    1549           0 :   end = s + strlen(s);
    1550             : 
    1551           0 :   for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
    1552           0 :     if (s[name_len] == '=') {
    1553           0 :       s += name_len + 1;
    1554           0 :       if ((p = strchr(s, ' ')) == NULL)
    1555           0 :         p = end;
    1556           0 :       if (p[-1] == ';')
    1557           0 :         p--;
    1558           0 :       if (*s == '"' && p[-1] == '"' && p > s + 1) {
    1559           0 :         s++;
    1560           0 :         p--;
    1561             :       }
    1562           0 :       if ((size_t) (p - s) < dst_size) {
    1563           0 :         len = (p - s) + 1;
    1564           0 :         mg_strlcpy(dst, s, (size_t)len);
    1565             :       }
    1566           0 :       break;
    1567             :     }
    1568             : 
    1569           0 :   return len;
    1570             : }
    1571             : 
    1572             : // Mongoose allows to specify multiple directories to serve,
    1573             : // like /var/www,/~bob=/home/bob. That means that root directory depends on URI.
    1574             : // This function returns root dir for given URI.
    1575           0 : static int get_document_root(const struct mg_connection *conn,
    1576             :                              struct vec *document_root) {
    1577             :   const char *root, *uri;
    1578             :   int len_of_matched_uri;
    1579             :   struct vec uri_vec, path_vec;
    1580             : 
    1581           0 :   uri = conn->request_info.uri;
    1582           0 :   len_of_matched_uri = 0;
    1583           0 :   root = next_option(conn->ctx->config[DOCUMENT_ROOT], document_root, NULL);
    1584             : 
    1585           0 :   while ((root = next_option(root, &uri_vec, &path_vec)) != NULL) {
    1586           0 :     if (memcmp(uri, uri_vec.ptr, uri_vec.len) == 0) {
    1587           0 :       *document_root = path_vec;
    1588           0 :       len_of_matched_uri = uri_vec.len;
    1589           0 :       break;
    1590             :     }
    1591             :   }
    1592             : 
    1593           0 :   return len_of_matched_uri;
    1594             : }
    1595             : 
    1596           0 : static void convert_uri_to_file_name(struct mg_connection *conn,
    1597             :                                      const char *uri, char *buf,
    1598             :                                      size_t buf_len) {
    1599           0 :   struct vec vec = {0};
    1600             :   int match_len;
    1601             : 
    1602           0 :   match_len = get_document_root(conn, &vec);
    1603           0 :   mg_snprintf(conn, buf, buf_len, "%.*s%s", (int) vec.len, vec.ptr, uri + match_len);
    1604             : 
    1605             : #if defined(_WIN32) && !defined(__SYMBIAN32__)
    1606             :   change_slashes_to_backslashes(buf);
    1607             : #endif // _WIN32
    1608             : 
    1609             :   DEBUG_TRACE(("[%s] -> [%s], [%.*s]", uri, buf, (int) vec.len, vec.ptr));
    1610           0 : }
    1611             : 
    1612           0 : static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
    1613           0 :   return (conn->ssl = SSL_new(conn->ctx->ssl_ctx)) != NULL &&
    1614           0 :     SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
    1615           0 :     func(conn->ssl) == 1;
    1616             : }
    1617             : 
    1618           0 : static struct mg_connection *mg_connect(struct mg_connection *conn,
    1619             :                                  const char *host, int port, int use_ssl) {
    1620           0 :   struct mg_connection *newconn = NULL;
    1621             :   struct sockaddr_in sin;
    1622             :   struct hostent *he;
    1623             :   int sock;
    1624             : 
    1625           0 :   if (conn->ctx->ssl_ctx == NULL && use_ssl) {
    1626           0 :     cry(conn, "%s: SSL is not initialized", __func__);
    1627           0 :   } else if ((he = gethostbyname(host)) == NULL) {
    1628           0 :     cry(conn, "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO));
    1629           0 :   } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
    1630           0 :     cry(conn, "%s: socket: %s", __func__, strerror(ERRNO));
    1631             :   } else {
    1632           0 :     sin.sin_family = AF_INET;
    1633           0 :     sin.sin_port = htons((uint16_t) port);
    1634           0 :     sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
    1635           0 :     if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
    1636           0 :       cry(conn, "%s: connect(%s:%d): %s", __func__, host, port,
    1637           0 :           strerror(ERRNO));
    1638           0 :       closesocket(sock);
    1639           0 :     } else if ((newconn = (struct mg_connection *)
    1640           0 :                 calloc(1, sizeof(*newconn))) == NULL) {
    1641           0 :       cry(conn, "%s: calloc: %s", __func__, strerror(ERRNO));
    1642           0 :       closesocket(sock);
    1643             :     } else {
    1644           0 :       newconn->client.sock = sock;
    1645           0 :       newconn->client.rsa.u.sin = sin;
    1646           0 :       if (use_ssl) {
    1647           0 :         sslize(newconn, SSL_connect);
    1648             :       }
    1649             :     }
    1650             :   }
    1651             : 
    1652           0 :   return newconn;
    1653             : }
    1654             : 
    1655             : // Check whether full request is buffered. Return:
    1656             : //   -1  if request is malformed
    1657             : //    0  if request is not yet fully buffered
    1658             : //   >0  actual request length, including last \r\n\r\n
    1659           0 : static int get_request_len(const char *buf, int buflen) {
    1660             :   const char *s, *e;
    1661           0 :   int len = 0;
    1662             : 
    1663             :   DEBUG_TRACE(("buf: %p, len: %d", buf, buflen));
    1664           0 :   for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
    1665             :     // Control characters are not allowed but >=128 is.
    1666           0 :     if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
    1667           0 :         *s != '\n' && * (const unsigned char *) s < 128) {
    1668           0 :       len = -1;
    1669           0 :     } else if (s[0] == '\n' && s[1] == '\n') {
    1670           0 :       len = (int) (s - buf) + 2;
    1671           0 :     } else if (s[0] == '\n' && &s[1] < e &&
    1672           0 :         s[1] == '\r' && s[2] == '\n') {
    1673           0 :       len = (int) (s - buf) + 3;
    1674             :     }
    1675             : 
    1676           0 :   return len;
    1677             : }
    1678             : 
    1679             : // Convert month to the month number. Return -1 on error, or month number
    1680           0 : static int get_month_index(const char *s) {
    1681             :   size_t i;
    1682             : 
    1683           0 :   for (i = 0; i < ARRAY_SIZE(month_names); i++)
    1684           0 :     if (!strcmp(s, month_names[i]))
    1685           0 :       return (int) i;
    1686             : 
    1687           0 :   return -1;
    1688             : }
    1689             : 
    1690             : // Parse UTC date-time string, and return the corresponding time_t value.
    1691           0 : static time_t parse_date_string(const char *datetime) {
    1692             :   static const unsigned short days_before_month[] = {
    1693             :     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
    1694             :   };
    1695             :   char month_str[32];
    1696             :   int second, minute, hour, day, month, year, leap_days, days;
    1697           0 :   time_t result = (time_t) 0;
    1698             : 
    1699           0 :   if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
    1700           0 :                &day, month_str, &year, &hour, &minute, &second) == 6) ||
    1701           0 :        (sscanf(datetime, "%d %3s %d %d:%d:%d",
    1702           0 :                &day, month_str, &year, &hour, &minute, &second) == 6) ||
    1703           0 :        (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
    1704           0 :                &day, month_str, &year, &hour, &minute, &second) == 6) ||
    1705           0 :        (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
    1706           0 :                &day, month_str, &year, &hour, &minute, &second) == 6)) &&
    1707           0 :       year > 1970 &&
    1708             :       (month = get_month_index(month_str)) != -1) {
    1709           0 :     year -= 1970;
    1710           0 :     leap_days = year / 4 - year / 100 + year / 400;
    1711           0 :     days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
    1712           0 :     result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
    1713             :   }
    1714             : 
    1715           0 :   return result;
    1716             : }
    1717             : 
    1718             : // Protect against directory disclosure attack by removing '..',
    1719             : // excessive '/' and '\' characters
    1720           0 : static void remove_double_dots_and_double_slashes(char *s) {
    1721           0 :   char *p = s;
    1722             : 
    1723           0 :   while (*s != '\0') {
    1724           0 :     *p++ = *s++;
    1725           0 :     if (s[-1] == '/' || s[-1] == '\\') {
    1726             :       // Skip all following slashes and backslashes
    1727           0 :       while (*s == '/' || *s == '\\') {
    1728           0 :         s++;
    1729             :       }
    1730             : 
    1731             :       // Skip all double-dots
    1732           0 :       while (*s == '.' && s[1] == '.') {
    1733           0 :         s += 2;
    1734             :       }
    1735             :     }
    1736             :   }
    1737           0 :   *p = '\0';
    1738           0 : }
    1739             : 
    1740             : static const struct {
    1741             :   const char *extension;
    1742             :   size_t ext_len;
    1743             :   const char *mime_type;
    1744             :   size_t mime_type_len;
    1745             : } builtin_mime_types[] = {
    1746             :   {".html", 5, "text/html",   9},
    1747             :   {".htm", 4, "text/html",   9},
    1748             :   {".shtm", 5, "text/html",   9},
    1749             :   {".shtml", 6, "text/html",   9},
    1750             :   {".css", 4, "text/css",   8},
    1751             :   {".js",  3, "application/x-javascript", 24},
    1752             :   {".ico", 4, "image/x-icon",   12},
    1753             :   {".gif", 4, "image/gif",   9},
    1754             :   {".jpg", 4, "image/jpeg",   10},
    1755             :   {".jpeg", 5, "image/jpeg",   10},
    1756             :   {".png", 4, "image/png",   9},
    1757             :   {".svg", 4, "image/svg+xml",  13},
    1758             :   {".torrent", 8, "application/x-bittorrent", 24},
    1759             :   {".wav", 4, "audio/x-wav",   11},
    1760             :   {".mp3", 4, "audio/x-mp3",   11},
    1761             :   {".mid", 4, "audio/mid",   9},
    1762             :   {".m3u", 4, "audio/x-mpegurl",  15},
    1763             :   {".ram", 4, "audio/x-pn-realaudio",  20},
    1764             :   {".xml", 4, "text/xml",   8},
    1765             :   {".xslt", 5, "application/xml",  15},
    1766             :   {".ra",  3, "audio/x-pn-realaudio",  20},
    1767             :   {".doc", 4, "application/msword",  19},
    1768             :   {".exe", 4, "application/octet-stream", 24},
    1769             :   {".zip", 4, "application/x-zip-compressed", 28},
    1770             :   {".xls", 4, "application/excel",  17},
    1771             :   {".tgz", 4, "application/x-tar-gz",  20},
    1772             :   {".tar", 4, "application/x-tar",  17},
    1773             :   {".gz",  3, "application/x-gunzip",  20},
    1774             :   {".arj", 4, "application/x-arj-compressed", 28},
    1775             :   {".rar", 4, "application/x-arj-compressed", 28},
    1776             :   {".rtf", 4, "application/rtf",  15},
    1777             :   {".pdf", 4, "application/pdf",  15},
    1778             :   {".swf", 4, "application/x-shockwave-flash",29},
    1779             :   {".mpg", 4, "video/mpeg",   10},
    1780             :   {".mpeg", 5, "video/mpeg",   10},
    1781             :   {".mp4", 4, "video/mp4", 9},
    1782             :   {".m4v", 4, "video/x-m4v", 11},
    1783             :   {".asf", 4, "video/x-ms-asf",  14},
    1784             :   {".avi", 4, "video/x-msvideo",  15},
    1785             :   {".bmp", 4, "image/bmp",   9},
    1786             :   {NULL,  0, NULL,    0}
    1787             : };
    1788             : 
    1789             : // Look at the "path" extension and figure what mime type it has.
    1790             : // Store mime type in the vector.
    1791           0 : static void get_mime_type(struct mg_context *ctx, const char *path,
    1792             :                           struct vec *vec) {
    1793             :   struct vec ext_vec, mime_vec;
    1794             :   const char *list, *ext;
    1795             :   size_t i, path_len;
    1796             : 
    1797           0 :   path_len = strlen(path);
    1798             : 
    1799             :   // Scan user-defined mime types first, in case user wants to
    1800             :   // override default mime types.
    1801           0 :   list = ctx->config[EXTRA_MIME_TYPES];
    1802           0 :   while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
    1803             :     // ext now points to the path suffix
    1804           0 :     ext = path + path_len - ext_vec.len;
    1805           0 :     if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
    1806           0 :       *vec = mime_vec;
    1807           0 :       return;
    1808             :     }
    1809             :   }
    1810             : 
    1811             :   // Now scan built-in mime types
    1812           0 :   for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
    1813           0 :     ext = path + (path_len - builtin_mime_types[i].ext_len);
    1814           0 :     if (path_len > builtin_mime_types[i].ext_len &&
    1815           0 :         mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
    1816           0 :       vec->ptr = builtin_mime_types[i].mime_type;
    1817           0 :       vec->len = builtin_mime_types[i].mime_type_len;
    1818           0 :       return;
    1819             :     }
    1820             :   }
    1821             : 
    1822             :   // Nothing found. Fall back to "text/plain"
    1823           0 :   vec->ptr = "text/plain";
    1824           0 :   vec->len = 10;
    1825             : }
    1826             : 
    1827             : #ifndef HAVE_MD5
    1828             : typedef struct MD5Context {
    1829             :   uint32_t buf[4];
    1830             :   uint32_t bits[2];
    1831             :   unsigned char in[64];
    1832             : } MD5_CTX;
    1833             : 
    1834             : #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
    1835             : #define byteReverse(buf, len) // Do nothing
    1836             : #else
    1837             : static void byteReverse(unsigned char *buf, unsigned longs) {
    1838             :   uint32_t t;
    1839             :   do {
    1840             :     t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
    1841             :       ((unsigned) buf[1] << 8 | buf[0]);
    1842             :     *(uint32_t *) buf = t;
    1843             :     buf += 4;
    1844             :   } while (--longs);
    1845             : }
    1846             : #endif
    1847             : 
    1848             : #define F1(x, y, z) (z ^ (x & (y ^ z)))
    1849             : #define F2(x, y, z) F1(z, x, y)
    1850             : #define F3(x, y, z) (x ^ y ^ z)
    1851             : #define F4(x, y, z) (y ^ (x | ~z))
    1852             : 
    1853             : #define MD5STEP(f, w, x, y, z, data, s) \
    1854             :   ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
    1855             : 
    1856             : // Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
    1857             : // initialization constants.
    1858           0 : static void MD5Init(MD5_CTX *ctx) {
    1859           0 :   ctx->buf[0] = 0x67452301;
    1860           0 :   ctx->buf[1] = 0xefcdab89;
    1861           0 :   ctx->buf[2] = 0x98badcfe;
    1862           0 :   ctx->buf[3] = 0x10325476;
    1863             : 
    1864           0 :   ctx->bits[0] = 0;
    1865           0 :   ctx->bits[1] = 0;
    1866           0 : }
    1867             : 
    1868           0 : static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
    1869             :   uint32_t a, b, c, d;
    1870             : 
    1871           0 :   a = buf[0];
    1872           0 :   b = buf[1];
    1873           0 :   c = buf[2];
    1874           0 :   d = buf[3];
    1875             : 
    1876           0 :   MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    1877           0 :   MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    1878           0 :   MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    1879           0 :   MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    1880           0 :   MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    1881           0 :   MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    1882           0 :   MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    1883           0 :   MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    1884           0 :   MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    1885           0 :   MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    1886           0 :   MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    1887           0 :   MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    1888           0 :   MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    1889           0 :   MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    1890           0 :   MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    1891           0 :   MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
    1892             : 
    1893           0 :   MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    1894           0 :   MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    1895           0 :   MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    1896           0 :   MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    1897           0 :   MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    1898           0 :   MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    1899           0 :   MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    1900           0 :   MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    1901           0 :   MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    1902           0 :   MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    1903           0 :   MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    1904           0 :   MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    1905           0 :   MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    1906           0 :   MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    1907           0 :   MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    1908           0 :   MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
    1909             : 
    1910           0 :   MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    1911           0 :   MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    1912           0 :   MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    1913           0 :   MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    1914           0 :   MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    1915           0 :   MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    1916           0 :   MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    1917           0 :   MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    1918           0 :   MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    1919           0 :   MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    1920           0 :   MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    1921           0 :   MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    1922           0 :   MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    1923           0 :   MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    1924           0 :   MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    1925           0 :   MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
    1926             : 
    1927           0 :   MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    1928           0 :   MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    1929           0 :   MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    1930           0 :   MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    1931           0 :   MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    1932           0 :   MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    1933           0 :   MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    1934           0 :   MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    1935           0 :   MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    1936           0 :   MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    1937           0 :   MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    1938           0 :   MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    1939           0 :   MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    1940           0 :   MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    1941           0 :   MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    1942           0 :   MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
    1943             : 
    1944           0 :   buf[0] += a;
    1945           0 :   buf[1] += b;
    1946           0 :   buf[2] += c;
    1947           0 :   buf[3] += d;
    1948           0 : }
    1949             : 
    1950           0 : static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
    1951             :   uint32_t t;
    1952             : 
    1953           0 :   t = ctx->bits[0];
    1954           0 :   if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
    1955           0 :     ctx->bits[1]++;
    1956           0 :   ctx->bits[1] += len >> 29;
    1957             : 
    1958           0 :   t = (t >> 3) & 0x3f;
    1959             : 
    1960           0 :   if (t) {
    1961           0 :     unsigned char *p = (unsigned char *) ctx->in + t;
    1962             : 
    1963           0 :     t = 64 - t;
    1964           0 :     if (len < t) {
    1965           0 :       memcpy(p, buf, len);
    1966           0 :       return;
    1967             :     }
    1968           0 :     memcpy(p, buf, t);
    1969             :     byteReverse(ctx->in, 16);
    1970           0 :     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    1971           0 :     buf += t;
    1972           0 :     len -= t;
    1973             :   }
    1974             : 
    1975           0 :   while (len >= 64) {
    1976           0 :     memcpy(ctx->in, buf, 64);
    1977             :     byteReverse(ctx->in, 16);
    1978           0 :     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    1979           0 :     buf += 64;
    1980           0 :     len -= 64;
    1981             :   }
    1982             : 
    1983           0 :   memcpy(ctx->in, buf, len);
    1984             : }
    1985             : 
    1986           0 : static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
    1987             :   unsigned count;
    1988             :   unsigned char *p;
    1989             : 
    1990           0 :   count = (ctx->bits[0] >> 3) & 0x3F;
    1991             : 
    1992           0 :   p = ctx->in + count;
    1993           0 :   *p++ = 0x80;
    1994           0 :   count = 64 - 1 - count;
    1995           0 :   if (count < 8) {
    1996           0 :     memset(p, 0, count);
    1997             :     byteReverse(ctx->in, 16);
    1998           0 :     MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    1999           0 :     memset(ctx->in, 0, 56);
    2000             :   } else {
    2001           0 :     memset(p, 0, count - 8);
    2002             :   }
    2003             :   byteReverse(ctx->in, 14);
    2004             : 
    2005           0 :   memcpy(ctx->in + 14 * sizeof(uint32_t), ctx->bits, sizeof(ctx->bits));
    2006             : 
    2007           0 :   MD5Transform(ctx->buf, (uint32_t *) ctx->in);
    2008             :   byteReverse((unsigned char *) ctx->buf, 4);
    2009           0 :   memcpy(digest, ctx->buf, 16);
    2010           0 :   memset((char *) ctx, 0, sizeof(*ctx));
    2011           0 : }
    2012             : #endif // !HAVE_MD5
    2013             : 
    2014             : // Stringify binary data. Output buffer must be twice as big as input,
    2015             : // because each byte takes 2 bytes in string representation
    2016           0 : static void bin2str(char *to, const unsigned char *p, size_t len) {
    2017             :   static const char *hex = "0123456789abcdef";
    2018             : 
    2019           0 :   for (; len--; p++) {
    2020           0 :     *to++ = hex[p[0] >> 4];
    2021           0 :     *to++ = hex[p[0] & 0x0f];
    2022             :   }
    2023           0 :   *to = '\0';
    2024           0 : }
    2025             : 
    2026             : // Return stringified MD5 hash for list of vectors. Buffer must be 33 bytes.
    2027           0 : void mg_md5(char *buf, ...) {
    2028             :   unsigned char hash[16];
    2029             :   const char *p;
    2030             :   va_list ap;
    2031             :   MD5_CTX ctx;
    2032             : 
    2033           0 :   MD5Init(&ctx);
    2034             : 
    2035           0 :   va_start(ap, buf);
    2036           0 :   while ((p = va_arg(ap, const char *)) != NULL) {
    2037           0 :     MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
    2038             :   }
    2039           0 :   va_end(ap);
    2040             : 
    2041           0 :   MD5Final(hash, &ctx);
    2042           0 :   bin2str(buf, hash, sizeof(hash));
    2043           0 : }
    2044             : 
    2045             : // Check the user's password, return 1 if OK
    2046           0 : static int check_password(const char *method, const char *ha1, const char *uri,
    2047             :                           const char *nonce, const char *nc, const char *cnonce,
    2048             :                           const char *qop, const char *response) {
    2049             :   char ha2[32 + 1], expected_response[32 + 1];
    2050             : 
    2051             :   // Some of the parameters may be NULL
    2052           0 :   if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
    2053           0 :       qop == NULL || response == NULL) {
    2054           0 :     return 0;
    2055             :   }
    2056             : 
    2057             :   // NOTE(lsm): due to a bug in MSIE, we do not compare the URI
    2058             :   // TODO(lsm): check for authentication timeout
    2059           0 :   if (// strcmp(dig->uri, c->ouri) != 0 ||
    2060           0 :       strlen(response) != 32
    2061             :       // || now - strtoul(dig->nonce, NULL, 10) > 3600
    2062             :       ) {
    2063           0 :     return 0;
    2064             :   }
    2065             : 
    2066           0 :   mg_md5(ha2, method, ":", uri, NULL);
    2067           0 :   mg_md5(expected_response, ha1, ":", nonce, ":", nc,
    2068             :       ":", cnonce, ":", qop, ":", ha2, NULL);
    2069             : 
    2070           0 :   return mg_strcasecmp(response, expected_response) == 0;
    2071             : }
    2072             : 
    2073             : // Use the global passwords file, if specified by auth_gpass option,
    2074             : // or search for .htpasswd in the requested directory.
    2075           0 : static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
    2076           0 :   struct mg_context *ctx = conn->ctx;
    2077             :   char name[PATH_MAX];
    2078             :   const char *p, *e;
    2079             :   struct mgstat st;
    2080             :   FILE *fp;
    2081             : 
    2082           0 :   if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) {
    2083             :     // Use global passwords file
    2084           0 :     fp =  mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r");
    2085           0 :     if (fp == NULL)
    2086           0 :       cry(fc(ctx), "fopen(%s): %s",
    2087           0 :           ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO));
    2088           0 :   } else if (!mg_stat(path, &st) && st.is_directory) {
    2089           0 :     (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s",
    2090             :         path, DIRSEP, PASSWORDS_FILE_NAME);
    2091           0 :     fp = mg_fopen(name, "r");
    2092             :   } else {
    2093             :      // Try to find .htpasswd in requested directory.
    2094           0 :     for (p = path, e = p + strlen(p) - 1; e > p; e--)
    2095           0 :       if (IS_DIRSEP_CHAR(*e))
    2096           0 :         break;
    2097           0 :     (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
    2098           0 :         (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME);
    2099           0 :     fp = mg_fopen(name, "r");
    2100             :   }
    2101             : 
    2102           0 :   return fp;
    2103             : }
    2104             : 
    2105             : // Parsed Authorization header
    2106             : struct ah {
    2107             :   char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
    2108             : };
    2109             : 
    2110           0 : static int parse_auth_header(struct mg_connection *conn, char *buf,
    2111             :                              size_t buf_size, struct ah *ah) {
    2112             :   char *name, *value, *s;
    2113             :   const char *auth_header;
    2114             : 
    2115           0 :   if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
    2116           0 :       mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
    2117           0 :     return 0;
    2118             :   }
    2119             : 
    2120             :   // Make modifiable copy of the auth header
    2121           0 :   (void) mg_strlcpy(buf, auth_header + 7, buf_size);
    2122             : 
    2123           0 :   s = buf;
    2124           0 :   (void) memset(ah, 0, sizeof(*ah));
    2125             : 
    2126             :   // Parse authorization header
    2127           0 :   for (;;) {
    2128             :     // Gobble initial spaces
    2129           0 :     while (isspace(* (unsigned char *) s)) {
    2130           0 :       s++;
    2131             :     }
    2132           0 :     name = skip_quoted(&s, "=", " ", 0);
    2133             :     // Value is either quote-delimited, or ends at first comma or space.
    2134           0 :     if (s[0] == '\"') {
    2135           0 :       s++;
    2136           0 :       value = skip_quoted(&s, "\"", " ", '\\');
    2137           0 :       if (s[0] == ',') {
    2138           0 :         s++;
    2139             :       }
    2140             :     } else {
    2141           0 :       value = skip_quoted(&s, ", ", " ", 0);  // IE uses commas, FF uses spaces
    2142             :     }
    2143           0 :     if (*name == '\0') {
    2144           0 :       break;
    2145             :     }
    2146             : 
    2147           0 :     if (!strcmp(name, "username")) {
    2148           0 :       ah->user = value;
    2149           0 :     } else if (!strcmp(name, "cnonce")) {
    2150           0 :       ah->cnonce = value;
    2151           0 :     } else if (!strcmp(name, "response")) {
    2152           0 :       ah->response = value;
    2153           0 :     } else if (!strcmp(name, "uri")) {
    2154           0 :       ah->uri = value;
    2155           0 :     } else if (!strcmp(name, "qop")) {
    2156           0 :       ah->qop = value;
    2157           0 :     } else if (!strcmp(name, "nc")) {
    2158           0 :       ah->nc = value;
    2159           0 :     } else if (!strcmp(name, "nonce")) {
    2160           0 :       ah->nonce = value;
    2161             :     }
    2162             :   }
    2163             : 
    2164             :   // CGI needs it as REMOTE_USER
    2165           0 :   if (ah->user != NULL) {
    2166           0 :     conn->request_info.remote_user = mg_strdup(ah->user);
    2167             :   } else {
    2168           0 :     return 0;
    2169             :   }
    2170             : 
    2171           0 :   return 1;
    2172             : }
    2173             : 
    2174             : // Authorize against the opened passwords file. Return 1 if authorized.
    2175           0 : static int authorize(struct mg_connection *conn, FILE *fp) {
    2176             :   struct ah ah;
    2177             :   char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ];
    2178             : 
    2179           0 :   if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
    2180           0 :     return 0;
    2181             :   }
    2182             : 
    2183             :   // Loop over passwords file
    2184           0 :   while (fgets(line, sizeof(line), fp) != NULL) {
    2185           0 :     if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
    2186           0 :       continue;
    2187             :     }
    2188             : 
    2189           0 :     if (!strcmp(ah.user, f_user) &&
    2190           0 :         !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
    2191             :       return check_password(
    2192           0 :             conn->request_info.request_method,
    2193           0 :             ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop,
    2194           0 :             ah.response);
    2195             :   }
    2196             : 
    2197           0 :   return 0;
    2198             : }
    2199             : 
    2200             : // Return 1 if request is authorised, 0 otherwise.
    2201           0 : static int check_authorization(struct mg_connection *conn, const char *path) {
    2202             :   FILE *fp;
    2203             :   char fname[PATH_MAX];
    2204             :   struct vec uri_vec, filename_vec;
    2205             :   const char *list;
    2206             :   int authorized;
    2207             : 
    2208           0 :   fp = NULL;
    2209           0 :   authorized = 1;
    2210             : 
    2211           0 :   list = conn->ctx->config[PROTECT_URI];
    2212           0 :   while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
    2213           0 :     if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
    2214           0 :       (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s",
    2215           0 :           (int) filename_vec.len, filename_vec.ptr);
    2216           0 :       if ((fp = mg_fopen(fname, "r")) == NULL) {
    2217           0 :         cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
    2218             :       }
    2219           0 :       break;
    2220             :     }
    2221             :   }
    2222             : 
    2223           0 :   if (fp == NULL) {
    2224           0 :     fp = open_auth_file(conn, path);
    2225             :   }
    2226             : 
    2227           0 :   if (fp != NULL) {
    2228           0 :     authorized = authorize(conn, fp);
    2229           0 :     (void) fclose(fp);
    2230             :   }
    2231             : 
    2232           0 :   return authorized;
    2233             : }
    2234             : 
    2235           0 : static void send_authorization_request(struct mg_connection *conn) {
    2236           0 :   conn->request_info.status_code = 401;
    2237           0 :   (void) mg_printf(conn,
    2238             :       "HTTP/1.1 401 Unauthorized\r\n"
    2239             :       "Content-Length: 0\r\n"
    2240             :       "WWW-Authenticate: Digest qop=\"auth\", "
    2241             :       "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
    2242           0 :       conn->ctx->config[AUTHENTICATION_DOMAIN],
    2243           0 :       (unsigned long) time(NULL));
    2244           0 : }
    2245             : 
    2246           0 : static int is_authorized_for_put(struct mg_connection *conn) {
    2247             :   FILE *fp;
    2248           0 :   int ret = 0;
    2249             : 
    2250           0 :   fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL :
    2251           0 :     mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r");
    2252             : 
    2253           0 :   if (fp != NULL) {
    2254           0 :     ret = authorize(conn, fp);
    2255           0 :     (void) fclose(fp);
    2256             :   }
    2257             : 
    2258           0 :   return ret;
    2259             : }
    2260             : 
    2261           0 : int mg_modify_passwords_file(const char *fname, const char *domain,
    2262             :                              const char *user, const char *pass) {
    2263             :   int found;
    2264             :   char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
    2265             :   FILE *fp, *fp2;
    2266             : 
    2267           0 :   found = 0;
    2268           0 :   fp = fp2 = NULL;
    2269             : 
    2270             :   // Regard empty password as no password - remove user record.
    2271           0 :   if (pass != NULL && pass[0] == '\0') {
    2272           0 :     pass = NULL;
    2273             :   }
    2274             : 
    2275           0 :   (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
    2276             : 
    2277             :   // Create the file if does not exist
    2278           0 :   if ((fp = mg_fopen(fname, "a+")) != NULL) {
    2279           0 :     (void) fclose(fp);
    2280             :   }
    2281             : 
    2282             :   // Open the given file and temporary file
    2283           0 :   if ((fp = mg_fopen(fname, "r")) == NULL) {
    2284           0 :     return 0;
    2285           0 :   } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) {
    2286           0 :     fclose(fp);
    2287           0 :     return 0;
    2288             :   }
    2289             : 
    2290             :   // Copy the stuff to temporary file
    2291           0 :   while (fgets(line, sizeof(line), fp) != NULL) {
    2292           0 :     if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
    2293           0 :       continue;
    2294             :     }
    2295             : 
    2296           0 :     if (!strcmp(u, user) && !strcmp(d, domain)) {
    2297           0 :       found++;
    2298           0 :       if (pass != NULL) {
    2299           0 :         mg_md5(ha1, user, ":", domain, ":", pass, NULL);
    2300           0 :         fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
    2301             :       }
    2302             :     } else {
    2303           0 :       (void) fprintf(fp2, "%s", line);
    2304             :     }
    2305             :   }
    2306             : 
    2307             :   // If new user, just add it
    2308           0 :   if (!found && pass != NULL) {
    2309           0 :     mg_md5(ha1, user, ":", domain, ":", pass, NULL);
    2310           0 :     (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
    2311             :   }
    2312             : 
    2313             :   // Close files
    2314           0 :   (void) fclose(fp);
    2315           0 :   (void) fclose(fp2);
    2316             : 
    2317             :   // Put the temp file in place of real file
    2318           0 :   (void) mg_remove(fname);
    2319           0 :   (void) mg_rename(tmp, fname);
    2320             : 
    2321           0 :   return 1;
    2322             : }
    2323             : 
    2324             : struct de {
    2325             :   struct mg_connection *conn;
    2326             :   char *file_name;
    2327             :   struct mgstat st;
    2328             : };
    2329             : 
    2330           0 : static void url_encode(const char *src, char *dst, size_t dst_len) {
    2331             :   static const char *dont_escape = "._-$,;~()";
    2332             :   static const char *hex = "0123456789abcdef";
    2333           0 :   const char *end = dst + dst_len - 1;
    2334             : 
    2335           0 :   for (; *src != '\0' && dst < end; src++, dst++) {
    2336           0 :     if (isalnum(*(const unsigned char *) src) ||
    2337           0 :         strchr(dont_escape, * (const unsigned char *) src) != NULL) {
    2338           0 :       *dst = *src;
    2339           0 :     } else if (dst + 2 < end) {
    2340           0 :       dst[0] = '%';
    2341           0 :       dst[1] = hex[(* (const unsigned char *) src) >> 4];
    2342           0 :       dst[2] = hex[(* (const unsigned char *) src) & 0xf];
    2343           0 :       dst += 2;
    2344             :     }
    2345             :   }
    2346             : 
    2347           0 :   *dst = '\0';
    2348           0 : }
    2349             : 
    2350           0 : static void print_dir_entry(struct de *de) {
    2351             :   char size[64], mod[64], href[PATH_MAX];
    2352             : 
    2353           0 :   if (de->st.is_directory) {
    2354           0 :     (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
    2355             :   } else {
    2356             :      // We use (signed) cast below because MSVC 6 compiler cannot
    2357             :      // convert unsigned __int64 to double. Sigh.
    2358           0 :     if (de->st.size < 1024) {
    2359           0 :       (void) mg_snprintf(de->conn, size, sizeof(size),
    2360           0 :           "%lu", (unsigned long) de->st.size);
    2361           0 :     } else if (de->st.size < 1024 * 1024) {
    2362           0 :       (void) mg_snprintf(de->conn, size, sizeof(size),
    2363           0 :           "%.1fk", (double) de->st.size / 1024.0);
    2364           0 :     } else if (de->st.size < 1024 * 1024 * 1024) {
    2365           0 :       (void) mg_snprintf(de->conn, size, sizeof(size),
    2366           0 :           "%.1fM", (double) de->st.size / 1048576);
    2367             :     } else {
    2368           0 :       (void) mg_snprintf(de->conn, size, sizeof(size),
    2369           0 :           "%.1fG", (double) de->st.size / 1073741824);
    2370             :     }
    2371             :   }
    2372           0 :   (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime));
    2373           0 :   url_encode(de->file_name, href, sizeof(href));
    2374           0 :   de->conn->num_bytes_sent += mg_printf(de->conn,
    2375             :       "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
    2376             :       "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
    2377           0 :       de->conn->request_info.uri, href, de->st.is_directory ? "/" : "",
    2378           0 :       de->file_name, de->st.is_directory ? "/" : "", mod, size);
    2379           0 : }
    2380             : 
    2381             : // This function is called from send_directory() and used for
    2382             : // sorting directory entries by size, or name, or modification time.
    2383             : // On windows, __cdecl specification is needed in case if project is built
    2384             : // with __stdcall convention. qsort always requires __cdels callback.
    2385           0 : static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
    2386           0 :   const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
    2387           0 :   const char *query_string = a->conn->request_info.query_string;
    2388           0 :   int cmp_result = 0;
    2389             : 
    2390           0 :   if (query_string == NULL) {
    2391           0 :     query_string = "na";
    2392             :   }
    2393             : 
    2394           0 :   if (a->st.is_directory && !b->st.is_directory) {
    2395           0 :     return -1;  // Always put directories on top
    2396           0 :   } else if (!a->st.is_directory && b->st.is_directory) {
    2397           0 :     return 1;   // Always put directories on top
    2398           0 :   } else if (*query_string == 'n') {
    2399           0 :     cmp_result = strcmp(a->file_name, b->file_name);
    2400           0 :   } else if (*query_string == 's') {
    2401           0 :     cmp_result = a->st.size == b->st.size ? 0 :
    2402           0 :       a->st.size > b->st.size ? 1 : -1;
    2403           0 :   } else if (*query_string == 'd') {
    2404           0 :     cmp_result = a->st.mtime == b->st.mtime ? 0 :
    2405           0 :       a->st.mtime > b->st.mtime ? 1 : -1;
    2406             :   }
    2407             : 
    2408           0 :   return query_string[1] == 'd' ? -cmp_result : cmp_result;
    2409             : }
    2410             : 
    2411           0 : static int scan_directory(struct mg_connection *conn, const char *dir,
    2412             :                           void *data, void (*cb)(struct de *, void *)) {
    2413             :   char path[PATH_MAX];
    2414             :   struct dirent *dp;
    2415             :   DIR *dirp;
    2416             :   struct de de;
    2417             : 
    2418           0 :   if ((dirp = opendir(dir)) == NULL) {
    2419           0 :     return 0;
    2420             :   } else {
    2421           0 :     de.conn = conn;
    2422             : 
    2423           0 :     while ((dp = readdir(dirp)) != NULL) {
    2424             :       // Do not show current dir and passwords file
    2425           0 :       if (!strcmp(dp->d_name, ".") ||
    2426           0 :           !strcmp(dp->d_name, "..") ||
    2427           0 :           !strcmp(dp->d_name, PASSWORDS_FILE_NAME))
    2428           0 :         continue;
    2429             : 
    2430           0 :       mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name);
    2431             : 
    2432             :       // If we don't memset stat structure to zero, mtime will have
    2433             :       // garbage and strftime() will segfault later on in
    2434             :       // print_dir_entry(). memset is required only if mg_stat()
    2435             :       // fails. For more details, see
    2436             :       // http://code.google.com/p/mongoose/issues/detail?id=79
    2437           0 :       if (mg_stat(path, &de.st) != 0) {
    2438           0 :         memset(&de.st, 0, sizeof(de.st));
    2439             :       }
    2440           0 :       de.file_name = dp->d_name;
    2441             : 
    2442           0 :       cb(&de, data);
    2443             :     }
    2444           0 :     (void) closedir(dirp);
    2445             :   }
    2446           0 :   return 1;
    2447             : }
    2448             : 
    2449             : struct dir_scan_data {
    2450             :   struct de *entries;
    2451             :   int num_entries;
    2452             :   int arr_size;
    2453             : };
    2454             : 
    2455           0 : static void dir_scan_callback(struct de *de, void *data) {
    2456           0 :   struct dir_scan_data *dsd = (struct dir_scan_data *) data;
    2457             : 
    2458           0 :   if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
    2459           0 :     dsd->arr_size *= 2;
    2460           0 :     dsd->entries = (struct de *) realloc(dsd->entries, dsd->arr_size *
    2461             :                                          sizeof(dsd->entries[0]));
    2462             :   }
    2463           0 :   if (dsd->entries == NULL) {
    2464             :     // TODO(lsm): propagate an error to the caller
    2465           0 :     dsd->num_entries = 0;
    2466             :   } else {
    2467           0 :     dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
    2468           0 :     dsd->entries[dsd->num_entries].st = de->st;
    2469           0 :     dsd->entries[dsd->num_entries].conn = de->conn;
    2470           0 :     dsd->num_entries++;
    2471             :   }
    2472           0 : }
    2473             : 
    2474           0 : static void handle_directory_request(struct mg_connection *conn,
    2475             :                                      const char *dir) {
    2476             :   int i, sort_direction;
    2477           0 :   struct dir_scan_data data = { NULL, 0, 128 };
    2478             : 
    2479           0 :   if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
    2480           0 :     send_http_error(conn, 500, "Cannot open directory",
    2481           0 :                     "Error: opendir(%s): %s", dir, strerror(ERRNO));
    2482           0 :     return;
    2483             :   }
    2484             : 
    2485           0 :   sort_direction = conn->request_info.query_string != NULL &&
    2486           0 :     conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
    2487             : 
    2488           0 :   mg_printf(conn, "%s",
    2489             :             "HTTP/1.1 200 OK\r\n"
    2490             :             "Connection: close\r\n"
    2491             :             "Content-Type: text/html; charset=utf-8\r\n\r\n");
    2492             : 
    2493           0 :   conn->num_bytes_sent += mg_printf(conn,
    2494             :       "<html><head><title>Index of %s</title>"
    2495             :       "<style>th {text-align: left;}</style></head>"
    2496             :       "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
    2497             :       "<tr><th><a href=\"?n%c\">Name</a></th>"
    2498             :       "<th><a href=\"?d%c\">Modified</a></th>"
    2499             :       "<th><a href=\"?s%c\">Size</a></th></tr>"
    2500             :       "<tr><td colspan=\"3\"><hr></td></tr>",
    2501             :       conn->request_info.uri, conn->request_info.uri,
    2502             :       sort_direction, sort_direction, sort_direction);
    2503             : 
    2504             :   // Print first entry - link to a parent directory
    2505           0 :   conn->num_bytes_sent += mg_printf(conn,
    2506             :       "<tr><td><a href=\"%s%s\">%s</a></td>"
    2507             :       "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
    2508             :       conn->request_info.uri, "..", "Parent directory", "-", "-");
    2509             : 
    2510             :   // Sort and print directory entries
    2511           0 :   qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
    2512             :         compare_dir_entries);
    2513           0 :   for (i = 0; i < data.num_entries; i++) {
    2514           0 :     print_dir_entry(&data.entries[i]);
    2515           0 :     free(data.entries[i].file_name);
    2516             :   }
    2517           0 :   free(data.entries);
    2518             : 
    2519           0 :   conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
    2520           0 :   conn->request_info.status_code = 200;
    2521             : }
    2522             : 
    2523             : // Send len bytes from the opened file to the client.
    2524           0 : static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
    2525             :   char buf[BUFSIZ];
    2526             :   int to_read, num_read, num_written;
    2527             : 
    2528           0 :   while (len > 0) {
    2529             :     // Calculate how much to read from the file in the buffer
    2530           0 :     to_read = sizeof(buf);
    2531           0 :     if ((int64_t) to_read > len)
    2532           0 :       to_read = (int) len;
    2533             : 
    2534             :     // Read from file, exit the loop on error
    2535           0 :     if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0)
    2536           0 :       break;
    2537             : 
    2538             :     // Send read bytes to the client, exit the loop on error
    2539           0 :     if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read)
    2540           0 :       break;
    2541             : 
    2542             :     // Both read and were successful, adjust counters
    2543           0 :     conn->num_bytes_sent += num_written;
    2544           0 :     len -= num_written;
    2545             :   }
    2546           0 : }
    2547             : 
    2548           0 : static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
    2549           0 :   return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
    2550             : }
    2551             : 
    2552           0 : static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
    2553           0 :   strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
    2554           0 : }
    2555             : 
    2556           0 : static void handle_file_request(struct mg_connection *conn, const char *path,
    2557             :                                 struct mgstat *stp) {
    2558             :   char date[64], lm[64], etag[64], range[64];
    2559           0 :   const char *msg = "OK", *hdr;
    2560           0 :   time_t curtime = time(NULL);
    2561             :   int64_t cl, r1, r2;
    2562             :   struct vec mime_vec;
    2563             :   FILE *fp;
    2564             :   int n;
    2565             : 
    2566           0 :   get_mime_type(conn->ctx, path, &mime_vec);
    2567           0 :   cl = stp->size;
    2568           0 :   conn->request_info.status_code = 200;
    2569           0 :   range[0] = '\0';
    2570             : 
    2571           0 :   if ((fp = mg_fopen(path, "rb")) == NULL) {
    2572           0 :     send_http_error(conn, 500, http_500_error,
    2573           0 :         "fopen(%s): %s", path, strerror(ERRNO));
    2574           0 :     return;
    2575             :   }
    2576           0 :   set_close_on_exec(fileno(fp));
    2577             : 
    2578             :   // If Range: header specified, act accordingly
    2579           0 :   r1 = r2 = 0;
    2580           0 :   hdr = mg_get_header(conn, "Range");
    2581           0 :   if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) {
    2582           0 :     conn->request_info.status_code = 206;
    2583           0 :     (void) fseeko(fp, (off_t) r1, SEEK_SET);
    2584           0 :     cl = n == 2 ? r2 - r1 + 1: cl - r1;
    2585           0 :     (void) mg_snprintf(conn, range, sizeof(range),
    2586             :         "Content-Range: bytes "
    2587             :         "%" INT64_FMT "-%"
    2588             :         INT64_FMT "/%" INT64_FMT "\r\n",
    2589           0 :         r1, r1 + cl - 1, stp->size);
    2590           0 :     msg = "Partial Content";
    2591             :   }
    2592             : 
    2593             :   // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
    2594             :   // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
    2595           0 :   gmt_time_string(date, sizeof(date), &curtime);
    2596           0 :   gmt_time_string(lm, sizeof(lm), &stp->mtime);
    2597           0 :   (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx",
    2598           0 :       (unsigned long) stp->mtime, (unsigned long) stp->size);
    2599             : 
    2600           0 :   (void) mg_printf(conn,
    2601             :       "HTTP/1.1 %d %s\r\n"
    2602             :       "Date: %s\r\n"
    2603             :       "Last-Modified: %s\r\n"
    2604             :       "Etag: \"%s\"\r\n"
    2605             :       "Content-Type: %.*s\r\n"
    2606             :       "Content-Length: %" INT64_FMT "\r\n"
    2607             :       "Connection: %s\r\n"
    2608             :       "Accept-Ranges: bytes\r\n"
    2609             :       "%s\r\n",
    2610             :       conn->request_info.status_code, msg, date, lm, etag,
    2611           0 :       (int) mime_vec.len, mime_vec.ptr, cl, suggest_connection_header(conn), range);
    2612             : 
    2613           0 :   if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
    2614           0 :     send_file_data(conn, fp, cl);
    2615             :   }
    2616           0 :   (void) fclose(fp);
    2617             : }
    2618             : 
    2619           0 : void mg_send_file(struct mg_connection *conn, const char *path) {
    2620             :   struct mgstat st;
    2621           0 :   if (mg_stat(path, &st) == 0) {
    2622           0 :     handle_file_request(conn, path, &st);
    2623             :   } else {
    2624           0 :     send_http_error(conn, 404, "Not Found", "%s", "File not found");
    2625             :   }
    2626           0 : }
    2627             : 
    2628             : 
    2629             : // Parse HTTP headers from the given buffer, advance buffer to the point
    2630             : // where parsing stopped.
    2631           0 : static void parse_http_headers(char **buf, struct mg_request_info *ri) {
    2632             :   int i;
    2633             : 
    2634           0 :   for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
    2635           0 :     ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
    2636           0 :     ri->http_headers[i].value = skip(buf, "\r\n");
    2637           0 :     if (ri->http_headers[i].name[0] == '\0')
    2638           0 :       break;
    2639           0 :     ri->num_headers = i + 1;
    2640             :   }
    2641           0 : }
    2642             : 
    2643           0 : static int is_valid_http_method(const char *method) {
    2644           0 :   return !strcmp(method, "GET") || !strcmp(method, "POST") ||
    2645           0 :     !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
    2646           0 :     !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
    2647           0 :     !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND");
    2648             : }
    2649             : 
    2650             : // Parse HTTP request, fill in mg_request_info structure.
    2651           0 : static int parse_http_request(char *buf, struct mg_request_info *ri) {
    2652           0 :   int status = 0;
    2653             : 
    2654             :   // RFC says that all initial whitespaces should be ingored
    2655           0 :   while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
    2656           0 :     buf++;
    2657             :   }
    2658             : 
    2659           0 :   ri->request_method = skip(&buf, " ");
    2660           0 :   ri->uri = skip(&buf, " ");
    2661           0 :   ri->http_version = skip(&buf, "\r\n");
    2662             : 
    2663           0 :   if (is_valid_http_method(ri->request_method) &&
    2664           0 :       strncmp(ri->http_version, "HTTP/", 5) == 0) {
    2665           0 :     ri->http_version += 5;   // Skip "HTTP/"
    2666           0 :     parse_http_headers(&buf, ri);
    2667           0 :     status = 1;
    2668             :   }
    2669             : 
    2670           0 :   return status;
    2671             : }
    2672             : 
    2673             : // Keep reading the input (either opened file descriptor fd, or socket sock,
    2674             : // or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
    2675             : // buffer (which marks the end of HTTP request). Buffer buf may already
    2676             : // have some data. The length of the data is stored in nread.
    2677             : // Upon every read operation, increase nread by the number of bytes read.
    2678           0 : static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz,
    2679             :                         int *nread) {
    2680             :   int n, request_len;
    2681             : 
    2682           0 :   request_len = 0;
    2683           0 :   while (*nread < bufsiz && request_len == 0) {
    2684           0 :     n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread);
    2685           0 :     if (n <= 0) {
    2686           0 :       break;
    2687             :     } else {
    2688           0 :       *nread += n;
    2689           0 :       request_len = get_request_len(buf, *nread);
    2690             :     }
    2691             :   }
    2692             : 
    2693           0 :   return request_len;
    2694             : }
    2695             : 
    2696             : // For given directory path, substitute it to valid index file.
    2697             : // Return 0 if index file has been found, -1 if not found.
    2698             : // If the file is found, it's stats is returned in stp.
    2699           0 : static int substitute_index_file(struct mg_connection *conn, char *path,
    2700             :                                  size_t path_len, struct mgstat *stp) {
    2701           0 :   const char *list = conn->ctx->config[INDEX_FILES];
    2702             :   struct mgstat st;
    2703             :   struct vec filename_vec;
    2704           0 :   size_t n = strlen(path);
    2705           0 :   int found = 0;
    2706             : 
    2707             :   // The 'path' given to us points to the directory. Remove all trailing
    2708             :   // directory separator characters from the end of the path, and
    2709             :   // then append single directory separator character.
    2710           0 :   while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) {
    2711           0 :     n--;
    2712             :   }
    2713           0 :   path[n] = DIRSEP;
    2714             : 
    2715             :   // Traverse index files list. For each entry, append it to the given
    2716             :   // path and see if the file exists. If it exists, break the loop
    2717           0 :   while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
    2718             : 
    2719             :     // Ignore too long entries that may overflow path buffer
    2720           0 :     if (filename_vec.len > path_len - n)
    2721           0 :       continue;
    2722             : 
    2723             :     // Prepare full path to the index file
    2724           0 :     (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
    2725             : 
    2726             :     // Does it exist?
    2727           0 :     if (mg_stat(path, &st) == 0) {
    2728             :       // Yes it does, break the loop
    2729           0 :       *stp = st;
    2730           0 :       found = 1;
    2731           0 :       break;
    2732             :     }
    2733             :   }
    2734             : 
    2735             :   // If no index file exists, restore directory path
    2736           0 :   if (!found) {
    2737           0 :     path[n] = '\0';
    2738             :   }
    2739             : 
    2740           0 :   return found;
    2741             : }
    2742             : 
    2743             : // Return True if we should reply 304 Not Modified.
    2744           0 : static int is_not_modified(const struct mg_connection *conn,
    2745             :                            const struct mgstat *stp) {
    2746           0 :   const char *ims = mg_get_header(conn, "If-Modified-Since");
    2747           0 :   return ims != NULL && stp->mtime <= parse_date_string(ims);
    2748             : }
    2749             : 
    2750           0 : static int forward_body_data(struct mg_connection *conn, FILE *fp,
    2751             :                              SOCKET sock, SSL *ssl) {
    2752             :   const char *expect, *buffered;
    2753             :   char buf[BUFSIZ];
    2754           0 :   int to_read, nread, buffered_len, success = 0;
    2755             : 
    2756           0 :   expect = mg_get_header(conn, "Expect");
    2757           0 :   assert(fp != NULL);
    2758             : 
    2759           0 :   if (conn->content_len == -1) {
    2760           0 :     send_http_error(conn, 411, "Length Required", "");
    2761           0 :   } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
    2762           0 :     send_http_error(conn, 417, "Expectation Failed", "");
    2763             :   } else {
    2764           0 :     if (expect != NULL) {
    2765           0 :       (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
    2766             :     }
    2767             : 
    2768           0 :     buffered = conn->buf + conn->request_len;
    2769           0 :     buffered_len = conn->data_len - conn->request_len;
    2770           0 :     assert(buffered_len >= 0);
    2771           0 :     assert(conn->consumed_content == 0);
    2772             : 
    2773           0 :     if (buffered_len > 0) {
    2774           0 :       if ((int64_t) buffered_len > conn->content_len) {
    2775           0 :         buffered_len = (int) conn->content_len;
    2776             :       }
    2777           0 :       push(fp, sock, ssl, buffered, (int64_t) buffered_len);
    2778           0 :       conn->consumed_content += buffered_len;
    2779             :     }
    2780             : 
    2781           0 :     while (conn->consumed_content < conn->content_len) {
    2782           0 :       to_read = sizeof(buf);
    2783           0 :       if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
    2784           0 :         to_read = (int) (conn->content_len - conn->consumed_content);
    2785             :       }
    2786           0 :       nread = pull(NULL, conn->client.sock, conn->ssl, buf, to_read);
    2787           0 :       if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
    2788           0 :         break;
    2789             :       }
    2790           0 :       conn->consumed_content += nread;
    2791             :     }
    2792             : 
    2793           0 :     if (conn->consumed_content == conn->content_len) {
    2794           0 :       success = 1;
    2795             :     }
    2796             : 
    2797             :     // Each error code path in this function must send an error
    2798           0 :     if (!success) {
    2799           0 :       send_http_error(conn, 577, http_500_error, "");
    2800             :     }
    2801             :   }
    2802             : 
    2803           0 :   return success;
    2804             : }
    2805             : 
    2806             : #if !defined(NO_CGI)
    2807             : // This structure helps to create an environment for the spawned CGI program.
    2808             : // Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
    2809             : // last element must be NULL.
    2810             : // However, on Windows there is a requirement that all these VARIABLE=VALUE\0
    2811             : // strings must reside in a contiguous buffer. The end of the buffer is
    2812             : // marked by two '\0' characters.
    2813             : // We satisfy both worlds: we create an envp array (which is vars), all
    2814             : // entries are actually pointers inside buf.
    2815             : struct cgi_env_block {
    2816             :   struct mg_connection *conn;
    2817             :   char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer
    2818             :   int len; // Space taken
    2819             :   char *vars[MAX_CGI_ENVIR_VARS]; // char **envp
    2820             :   int nvars; // Number of variables
    2821             : };
    2822             : 
    2823             : // Append VARIABLE=VALUE\0 string to the buffer, and add a respective
    2824             : // pointer into the vars array.
    2825             : static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
    2826             :   int n, space;
    2827             :   char *added;
    2828             :   va_list ap;
    2829             : 
    2830             :   // Calculate how much space is left in the buffer
    2831             :   space = sizeof(block->buf) - block->len - 2;
    2832             :   assert(space >= 0);
    2833             : 
    2834             :   // Make a pointer to the free space int the buffer
    2835             :   added = block->buf + block->len;
    2836             : 
    2837             :   // Copy VARIABLE=VALUE\0 string into the free space
    2838             :   va_start(ap, fmt);
    2839             :   n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
    2840             :   va_end(ap);
    2841             : 
    2842             :   // Make sure we do not overflow buffer and the envp array
    2843             :   if (n > 0 && n < space &&
    2844             :       block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
    2845             :     // Append a pointer to the added string into the envp array
    2846             :     block->vars[block->nvars++] = block->buf + block->len;
    2847             :     // Bump up used length counter. Include \0 terminator
    2848             :     block->len += n + 1;
    2849             :   }
    2850             : 
    2851             :   return added;
    2852             : }
    2853             : 
    2854             : static void prepare_cgi_environment(struct mg_connection *conn,
    2855             :                                     const char *prog,
    2856             :                                     struct cgi_env_block *blk) {
    2857             :   const char *s, *slash;
    2858             :   struct vec var_vec, root;
    2859             :   char *p;
    2860             :   int  i;
    2861             : 
    2862             :   blk->len = blk->nvars = 0;
    2863             :   blk->conn = conn;
    2864             : 
    2865             :   get_document_root(conn, &root);
    2866             : 
    2867             :   addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
    2868             :   addenv(blk, "SERVER_ROOT=%.*s", root.len, root.ptr);
    2869             :   addenv(blk, "DOCUMENT_ROOT=%.*s", root.len, root.ptr);
    2870             : 
    2871             :   // Prepare the environment block
    2872             :   addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
    2873             :   addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
    2874             :   addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
    2875             :   addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.u.sin.sin_port));
    2876             :   addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
    2877             :   addenv(blk, "REMOTE_ADDR=%s",
    2878             :       inet_ntoa(conn->client.rsa.u.sin.sin_addr));
    2879             :   addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
    2880             :   addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
    2881             : 
    2882             :   // SCRIPT_NAME
    2883             :   assert(conn->request_info.uri[0] == '/');
    2884             :   slash = strrchr(conn->request_info.uri, '/');
    2885             :   if ((s = strrchr(prog, '/')) == NULL)
    2886             :     s = prog;
    2887             :   addenv(blk, "SCRIPT_NAME=%.*s%s", slash - conn->request_info.uri,
    2888             :          conn->request_info.uri, s);
    2889             : 
    2890             :   addenv(blk, "SCRIPT_FILENAME=%s", prog);
    2891             :   addenv(blk, "PATH_TRANSLATED=%s", prog);
    2892             :   addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
    2893             : 
    2894             :   if ((s = mg_get_header(conn, "Content-Type")) != NULL)
    2895             :     addenv(blk, "CONTENT_TYPE=%s", s);
    2896             : 
    2897             :   if (conn->request_info.query_string != NULL)
    2898             :     addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
    2899             : 
    2900             :   if ((s = mg_get_header(conn, "Content-Length")) != NULL)
    2901             :     addenv(blk, "CONTENT_LENGTH=%s", s);
    2902             : 
    2903             :   if ((s = getenv("PATH")) != NULL)
    2904             :     addenv(blk, "PATH=%s", s);
    2905             : 
    2906             : #if defined(_WIN32)
    2907             :   if ((s = getenv("COMSPEC")) != NULL)
    2908             :     addenv(blk, "COMSPEC=%s", s);
    2909             :   if ((s = getenv("SYSTEMROOT")) != NULL)
    2910             :     addenv(blk, "SYSTEMROOT=%s", s);
    2911             : #else
    2912             :   if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
    2913             :     addenv(blk, "LD_LIBRARY_PATH=%s", s);
    2914             : #endif // _WIN32
    2915             : 
    2916             :   if ((s = getenv("PERLLIB")) != NULL)
    2917             :     addenv(blk, "PERLLIB=%s", s);
    2918             : 
    2919             :   if (conn->request_info.remote_user != NULL) {
    2920             :     addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
    2921             :     addenv(blk, "%s", "AUTH_TYPE=Digest");
    2922             :   }
    2923             : 
    2924             :   // Add all headers as HTTP_* variables
    2925             :   for (i = 0; i < conn->request_info.num_headers; i++) {
    2926             :     p = addenv(blk, "HTTP_%s=%s",
    2927             :         conn->request_info.http_headers[i].name,
    2928             :         conn->request_info.http_headers[i].value);
    2929             : 
    2930             :     // Convert variable name into uppercase, and change - to _
    2931             :     for (; *p != '=' && *p != '\0'; p++) {
    2932             :       if (*p == '-')
    2933             :         *p = '_';
    2934             :       *p = (char) toupper(* (unsigned char *) p);
    2935             :     }
    2936             :   }
    2937             : 
    2938             :   // Add user-specified variables
    2939             :   s = conn->ctx->config[CGI_ENVIRONMENT];
    2940             :   while ((s = next_option(s, &var_vec, NULL)) != NULL) {
    2941             :     addenv(blk, "%.*s", var_vec.len, var_vec.ptr);
    2942             :   }
    2943             : 
    2944             :   blk->vars[blk->nvars++] = NULL;
    2945             :   blk->buf[blk->len++] = '\0';
    2946             : 
    2947             :   assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
    2948             :   assert(blk->len > 0);
    2949             :   assert(blk->len < (int) sizeof(blk->buf));
    2950             : }
    2951             : 
    2952             : static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
    2953             :   int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
    2954             :   const char *status;
    2955             :   char buf[BUFSIZ], *pbuf, dir[PATH_MAX], *p;
    2956             :   struct mg_request_info ri;
    2957             :   struct cgi_env_block blk;
    2958             :   FILE *in, *out;
    2959             :   pid_t pid;
    2960             : 
    2961             :   prepare_cgi_environment(conn, prog, &blk);
    2962             : 
    2963             :   // CGI must be executed in its own directory. 'dir' must point to the
    2964             :   // directory containing executable program, 'p' must point to the
    2965             :   // executable program name relative to 'dir'.
    2966             :   (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
    2967             :   if ((p = strrchr(dir, DIRSEP)) != NULL) {
    2968             :     *p++ = '\0';
    2969             :   } else {
    2970             :     dir[0] = '.', dir[1] = '\0';
    2971             :     p = (char *) prog;
    2972             :   }
    2973             : 
    2974             :   pid = (pid_t) -1;
    2975             :   fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
    2976             :   in = out = NULL;
    2977             : 
    2978             :   if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
    2979             :     send_http_error(conn, 500, http_500_error,
    2980             :         "Cannot create CGI pipe: %s", strerror(ERRNO));
    2981             :     goto done;
    2982             :   } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars,
    2983             :           fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
    2984             :     goto done;
    2985             :   } else if ((in = fdopen(fd_stdin[1], "wb")) == NULL ||
    2986             :       (out = fdopen(fd_stdout[0], "rb")) == NULL) {
    2987             :     send_http_error(conn, 500, http_500_error,
    2988             :         "fopen: %s", strerror(ERRNO));
    2989             :     goto done;
    2990             :   }
    2991             : 
    2992             :   setbuf(in, NULL);
    2993             :   setbuf(out, NULL);
    2994             : 
    2995             :   // spawn_process() must close those!
    2996             :   // If we don't mark them as closed, close() attempt before
    2997             :   // return from this function throws an exception on Windows.
    2998             :   // Windows does not like when closed descriptor is closed again.
    2999             :   fd_stdin[0] = fd_stdout[1] = -1;
    3000             : 
    3001             :   // Send POST data to the CGI process if needed
    3002             :   if (!strcmp(conn->request_info.request_method, "POST") &&
    3003             :       !forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
    3004             :     goto done;
    3005             :   }
    3006             : 
    3007             :   // Now read CGI reply into a buffer. We need to set correct
    3008             :   // status code, thus we need to see all HTTP headers first.
    3009             :   // Do not send anything back to client, until we buffer in all
    3010             :   // HTTP headers.
    3011             :   data_len = 0;
    3012             :   headers_len = read_request(out, INVALID_SOCKET, NULL,
    3013             :       buf, sizeof(buf), &data_len);
    3014             :   if (headers_len <= 0) {
    3015             :     send_http_error(conn, 500, http_500_error,
    3016             :                     "CGI program sent malformed HTTP headers: [%.*s]",
    3017             :                     data_len, buf);
    3018             :     goto done;
    3019             :   }
    3020             :   pbuf = buf;
    3021             :   buf[headers_len - 1] = '\0';
    3022             :   parse_http_headers(&pbuf, &ri);
    3023             : 
    3024             :   // Make up and send the status line
    3025             :   status = get_header(&ri, "Status");
    3026             :   conn->request_info.status_code = status == NULL ? 200 : atoi(status);
    3027             :   (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n", conn->request_info.status_code);
    3028             : 
    3029             :   // Send headers
    3030             :   for (i = 0; i < ri.num_headers; i++) {
    3031             :     mg_printf(conn, "%s: %s\r\n",
    3032             :               ri.http_headers[i].name, ri.http_headers[i].value);
    3033             :   }
    3034             :   (void) mg_write(conn, "\r\n", 2);
    3035             : 
    3036             :   // Send chunk of data that may be read after the headers
    3037             :   conn->num_bytes_sent += mg_write(conn, buf + headers_len,
    3038             :                                    (size_t)(data_len - headers_len));
    3039             : 
    3040             :   // Read the rest of CGI output and send to the client
    3041             :   send_file_data(conn, out, INT64_MAX);
    3042             : 
    3043             : done:
    3044             :   if (pid != (pid_t) -1) {
    3045             :     kill(pid, SIGKILL);
    3046             :   }
    3047             :   if (fd_stdin[0] != -1) {
    3048             :     (void) close(fd_stdin[0]);
    3049             :   }
    3050             :   if (fd_stdout[1] != -1) {
    3051             :     (void) close(fd_stdout[1]);
    3052             :   }
    3053             : 
    3054             :   if (in != NULL) {
    3055             :     (void) fclose(in);
    3056             :   } else if (fd_stdin[1] != -1) {
    3057             :     (void) close(fd_stdin[1]);
    3058             :   }
    3059             : 
    3060             :   if (out != NULL) {
    3061             :     (void) fclose(out);
    3062             :   } else if (fd_stdout[0] != -1) {
    3063             :     (void) close(fd_stdout[0]);
    3064             :   }
    3065             : }
    3066             : #endif // !NO_CGI
    3067             : 
    3068             : // For a given PUT path, create all intermediate subdirectories
    3069             : // for given path. Return 0 if the path itself is a directory,
    3070             : // or -1 on error, 1 if OK.
    3071           0 : static int put_dir(const char *path) {
    3072             :   char buf[PATH_MAX];
    3073             :   const char *s, *p;
    3074             :   struct mgstat st;
    3075           0 :   int len, res = 1;
    3076             : 
    3077           0 :   for (s = p = path + 2; (p = strchr(s, DIRSEP)) != NULL; s = ++p) {
    3078           0 :     len = p - path;
    3079           0 :     if (len >= (int) sizeof(buf)) {
    3080           0 :       res = -1;
    3081           0 :       break;
    3082             :     }
    3083           0 :     memcpy(buf, path, len);
    3084           0 :     buf[len] = '\0';
    3085             : 
    3086             :     // Try to create intermediate directory
    3087             :     DEBUG_TRACE(("mkdir(%s)", buf));
    3088           0 :     if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0) {
    3089           0 :       res = -1;
    3090           0 :       break;
    3091             :     }
    3092             : 
    3093             :     // Is path itself a directory?
    3094           0 :     if (p[1] == '\0') {
    3095           0 :       res = 0;
    3096             :     }
    3097             :   }
    3098             : 
    3099           0 :   return res;
    3100             : }
    3101             : 
    3102           0 : static void put_file(struct mg_connection *conn, const char *path) {
    3103             :   struct mgstat st;
    3104             :   const char *range;
    3105             :   int64_t r1, r2;
    3106             :   FILE *fp;
    3107             :   int rc;
    3108             : 
    3109           0 :   conn->request_info.status_code = mg_stat(path, &st) == 0 ? 200 : 201;
    3110             : 
    3111           0 :   if ((rc = put_dir(path)) == 0) {
    3112           0 :     mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->request_info.status_code);
    3113           0 :   } else if (rc == -1) {
    3114           0 :     send_http_error(conn, 500, http_500_error,
    3115           0 :         "put_dir(%s): %s", path, strerror(ERRNO));
    3116           0 :   } else if ((fp = mg_fopen(path, "wb+")) == NULL) {
    3117           0 :     send_http_error(conn, 500, http_500_error,
    3118           0 :         "fopen(%s): %s", path, strerror(ERRNO));
    3119             :   } else {
    3120           0 :     set_close_on_exec(fileno(fp));
    3121           0 :     range = mg_get_header(conn, "Content-Range");
    3122           0 :     r1 = r2 = 0;
    3123           0 :     if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
    3124           0 :       conn->request_info.status_code = 206;
    3125             :       // TODO(lsm): handle seek error
    3126           0 :       (void) fseeko(fp, (off_t) r1, SEEK_SET);
    3127             :     }
    3128           0 :     if (forward_body_data(conn, fp, INVALID_SOCKET, NULL))
    3129           0 :       (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n",
    3130             :           conn->request_info.status_code);
    3131           0 :     (void) fclose(fp);
    3132             :   }
    3133           0 : }
    3134             : 
    3135             : static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
    3136             : 
    3137           0 : static void do_ssi_include(struct mg_connection *conn, const char *ssi,
    3138             :                            char *tag, int include_level) {
    3139             :   char file_name[BUFSIZ], path[PATH_MAX], *p;
    3140           0 :   struct vec root = {0};
    3141             :   int is_ssi;
    3142             :   FILE *fp;
    3143             : 
    3144           0 :   get_document_root(conn, &root);
    3145             : 
    3146             :   // sscanf() is safe here, since send_ssi_file() also uses buffer
    3147             :   // of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ.
    3148           0 :   if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
    3149             :     // File name is relative to the webserver root
    3150           0 :     (void) mg_snprintf(conn, path, sizeof(path), "%.*s%c%s",
    3151           0 :         (int) root.len, root.ptr, DIRSEP, file_name);
    3152           0 :   } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) {
    3153             :     // File name is relative to the webserver working directory
    3154             :     // or it is absolute system path
    3155           0 :     (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name);
    3156           0 :   } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
    3157             :     // File name is relative to the currect document
    3158           0 :     (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi);
    3159           0 :     if ((p = strrchr(path, DIRSEP)) != NULL) {
    3160           0 :       p[1] = '\0';
    3161             :     }
    3162           0 :     (void) mg_snprintf(conn, path + strlen(path),
    3163           0 :         sizeof(path) - strlen(path), "%s", file_name);
    3164             :   } else {
    3165           0 :     cry(conn, "Bad SSI #include: [%s]", tag);
    3166           0 :     return;
    3167             :   }
    3168             : 
    3169           0 :   if ((fp = mg_fopen(path, "rb")) == NULL) {
    3170           0 :     cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
    3171           0 :         tag, path, strerror(ERRNO));
    3172             :   } else {
    3173           0 :     set_close_on_exec(fileno(fp));
    3174           0 :     is_ssi = match_extension(path, conn->ctx->config[SSI_EXTENSIONS]);
    3175           0 :     if (is_ssi) {
    3176           0 :       send_ssi_file(conn, path, fp, include_level + 1);
    3177             :     } else {
    3178           0 :       send_file_data(conn, fp, INT64_MAX);
    3179             :     }
    3180           0 :     (void) fclose(fp);
    3181             :   }
    3182             : }
    3183             : 
    3184             : #if !defined(NO_POPEN)
    3185           0 : static void do_ssi_exec(struct mg_connection *conn, char *tag) {
    3186             :   char cmd[BUFSIZ];
    3187             :   FILE *fp;
    3188             : 
    3189           0 :   if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
    3190           0 :     cry(conn, "Bad SSI #exec: [%s]", tag);
    3191           0 :   } else if ((fp = popen(cmd, "r")) == NULL) {
    3192           0 :     cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
    3193             :   } else {
    3194           0 :     send_file_data(conn, fp, INT64_MAX);
    3195           0 :     (void) pclose(fp);
    3196             :   }
    3197           0 : }
    3198             : #endif // !NO_POPEN
    3199             : 
    3200           0 : static void send_ssi_file(struct mg_connection *conn, const char *path,
    3201             :                           FILE *fp, int include_level) {
    3202             :   char buf[BUFSIZ];
    3203             :   int ch, len, in_ssi_tag;
    3204             : 
    3205           0 :   if (include_level > 10) {
    3206           0 :     cry(conn, "SSI #include level is too deep (%s)", path);
    3207           0 :     return;
    3208             :   }
    3209             : 
    3210           0 :   in_ssi_tag = 0;
    3211           0 :   len = 0;
    3212             : 
    3213           0 :   while ((ch = fgetc(fp)) != EOF) {
    3214           0 :     if (in_ssi_tag && ch == '>') {
    3215           0 :       in_ssi_tag = 0;
    3216           0 :       buf[len++] = (char) ch;
    3217           0 :       buf[len] = '\0';
    3218           0 :       assert(len <= (int) sizeof(buf));
    3219           0 :       if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
    3220             :         // Not an SSI tag, pass it
    3221           0 :         (void) mg_write(conn, buf, (size_t)len);
    3222             :       } else {
    3223           0 :         if (!memcmp(buf + 5, "include", 7)) {
    3224           0 :           do_ssi_include(conn, path, buf + 12, include_level);
    3225             : #if !defined(NO_POPEN)
    3226           0 :         } else if (!memcmp(buf + 5, "exec", 4)) {
    3227           0 :           do_ssi_exec(conn, buf + 9);
    3228             : #endif // !NO_POPEN
    3229             :         } else {
    3230           0 :           cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
    3231             :         }
    3232             :       }
    3233           0 :       len = 0;
    3234           0 :     } else if (in_ssi_tag) {
    3235           0 :       if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
    3236             :         // Not an SSI tag
    3237           0 :         in_ssi_tag = 0;
    3238           0 :       } else if (len == (int) sizeof(buf) - 2) {
    3239           0 :         cry(conn, "%s: SSI tag is too large", path);
    3240           0 :         len = 0;
    3241             :       }
    3242           0 :       buf[len++] = ch & 0xff;
    3243           0 :     } else if (ch == '<') {
    3244           0 :       in_ssi_tag = 1;
    3245           0 :       if (len > 0) {
    3246           0 :         (void) mg_write(conn, buf, (size_t)len);
    3247             :       }
    3248           0 :       len = 0;
    3249           0 :       buf[len++] = ch & 0xff;
    3250             :     } else {
    3251           0 :       buf[len++] = ch & 0xff;
    3252           0 :       if (len == (int) sizeof(buf)) {
    3253           0 :         (void) mg_write(conn, buf, (size_t)len);
    3254           0 :         len = 0;
    3255             :       }
    3256             :     }
    3257             :   }
    3258             : 
    3259             :   // Send the rest of buffered data
    3260           0 :   if (len > 0) {
    3261           0 :     (void) mg_write(conn, buf, (size_t)len);
    3262             :   }
    3263             : }
    3264             : 
    3265           0 : static void handle_ssi_file_request(struct mg_connection *conn,
    3266             :                                     const char *path) {
    3267             :   FILE *fp;
    3268             : 
    3269           0 :   if ((fp = mg_fopen(path, "rb")) == NULL) {
    3270           0 :     send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
    3271           0 :                     strerror(ERRNO));
    3272             :   } else {
    3273           0 :     set_close_on_exec(fileno(fp));
    3274           0 :     mg_printf(conn, "HTTP/1.1 200 OK\r\n"
    3275             :               "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
    3276             :               suggest_connection_header(conn));
    3277           0 :     send_ssi_file(conn, path, fp, 0);
    3278           0 :     (void) fclose(fp);
    3279             :   }
    3280           0 : }
    3281             : 
    3282           0 : static void send_options(struct mg_connection *conn) {
    3283           0 :   conn->request_info.status_code = 200;
    3284             : 
    3285           0 :   (void) mg_printf(conn,
    3286             :       "HTTP/1.1 200 OK\r\n"
    3287             :       "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n"
    3288             :       "DAV: 1\r\n\r\n");
    3289           0 : }
    3290             : 
    3291             : // Writes PROPFIND properties for a collection element
    3292           0 : static void print_props(struct mg_connection *conn, const char* uri,
    3293             :                         struct mgstat* st) {
    3294             :   char mtime[64];
    3295           0 :   gmt_time_string(mtime, sizeof(mtime), &st->mtime);
    3296           0 :   conn->num_bytes_sent += mg_printf(conn,
    3297             :       "<d:response>"
    3298             :        "<d:href>%s</d:href>"
    3299             :        "<d:propstat>"
    3300             :         "<d:prop>"
    3301             :          "<d:resourcetype>%s</d:resourcetype>"
    3302             :          "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
    3303             :          "<d:getlastmodified>%s</d:getlastmodified>"
    3304             :         "</d:prop>"
    3305             :         "<d:status>HTTP/1.1 200 OK</d:status>"
    3306             :        "</d:propstat>"
    3307             :       "</d:response>\n",
    3308             :       uri,
    3309           0 :       st->is_directory ? "<d:collection/>" : "",
    3310             :       st->size,
    3311             :       mtime);
    3312           0 : }
    3313             : 
    3314           0 : static void print_dav_dir_entry(struct de *de, void *data) {
    3315             :   char href[PATH_MAX];
    3316           0 :   struct mg_connection *conn = (struct mg_connection *) data;
    3317           0 :   mg_snprintf(conn, href, sizeof(href), "%s%s",
    3318             :               conn->request_info.uri, de->file_name);
    3319           0 :   print_props(conn, href, &de->st);
    3320           0 : }
    3321             : 
    3322           0 : static void handle_propfind(struct mg_connection *conn, const char* path,
    3323             :                             struct mgstat* st) {
    3324           0 :   const char *depth = mg_get_header(conn, "Depth");
    3325             : 
    3326           0 :   conn->request_info.status_code = 207;
    3327           0 :   mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
    3328             :             "Connection: close\r\n"
    3329             :             "Content-Type: text/xml; charset=utf-8\r\n\r\n");
    3330             : 
    3331           0 :   conn->num_bytes_sent += mg_printf(conn,
    3332             :       "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    3333             :       "<d:multistatus xmlns:d='DAV:'>\n");
    3334             : 
    3335             :   // Print properties for the requested resource itself
    3336           0 :   print_props(conn, conn->request_info.uri, st);
    3337             : 
    3338             :   // If it is a directory, print directory entries too if Depth is not 0
    3339           0 :   if (st->is_directory &&
    3340           0 :       !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
    3341           0 :       (depth == NULL || strcmp(depth, "0") != 0)) {
    3342           0 :     scan_directory(conn, path, conn, &print_dav_dir_entry);
    3343             :   }
    3344             : 
    3345           0 :   conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
    3346           0 : }
    3347             : 
    3348             : // This is the heart of the Mongoose's logic.
    3349             : // This function is called when the request is read, parsed and validated,
    3350             : // and Mongoose must decide what action to take: serve a file, or
    3351             : // a directory, or call embedded function, etcetera.
    3352           0 : static void handle_request(struct mg_connection *conn) {
    3353           0 :   struct mg_request_info *ri = &conn->request_info;
    3354             :   char path[PATH_MAX];
    3355             :   int uri_len;
    3356             :   struct mgstat st;
    3357             : 
    3358           0 :   if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
    3359           0 :     * conn->request_info.query_string++ = '\0';
    3360             :   }
    3361           0 :   uri_len = strlen(ri->uri);
    3362           0 :   url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
    3363           0 :   remove_double_dots_and_double_slashes(ri->uri);
    3364           0 :   convert_uri_to_file_name(conn, ri->uri, path, sizeof(path));
    3365             : 
    3366             :   DEBUG_TRACE(("%s", ri->uri));
    3367           0 :   if (!check_authorization(conn, path)) {
    3368           0 :     send_authorization_request(conn);
    3369           0 :   } else if (call_user(conn, MG_NEW_REQUEST) != NULL) {
    3370             :     // Do nothing, callback has served the request
    3371           0 :   } else if (!strcmp(ri->request_method, "OPTIONS")) {
    3372           0 :     send_options(conn);
    3373           0 :   } else if (strstr(path, PASSWORDS_FILE_NAME)) {
    3374             :     // Do not allow to view passwords files
    3375           0 :     send_http_error(conn, 403, "Forbidden", "Access Forbidden");
    3376           0 :   } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
    3377           0 :     send_http_error(conn, 404, "Not Found", "Not Found");
    3378           0 :   } else if ((!strcmp(ri->request_method, "PUT") ||
    3379           0 :         !strcmp(ri->request_method, "DELETE")) &&
    3380           0 :       (conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ||
    3381           0 :        !is_authorized_for_put(conn))) {
    3382           0 :     send_authorization_request(conn);
    3383           0 :   } else if (!strcmp(ri->request_method, "PUT")) {
    3384           0 :     put_file(conn, path);
    3385           0 :   } else if (!strcmp(ri->request_method, "DELETE")) {
    3386           0 :     if (mg_remove(path) == 0) {
    3387           0 :       send_http_error(conn, 200, "OK", "");
    3388             :     } else {
    3389           0 :       send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
    3390           0 :                       strerror(ERRNO));
    3391             :     }
    3392           0 :   } else if (mg_stat(path, &st) != 0) {
    3393           0 :     send_http_error(conn, 404, "Not Found", "%s", "File not found");
    3394           0 :   } else if (st.is_directory && ri->uri[uri_len - 1] != '/') {
    3395           0 :     (void) mg_printf(conn,
    3396             :         "HTTP/1.1 301 Moved Permanently\r\n"
    3397             :         "Location: %s/\r\n\r\n", ri->uri);
    3398           0 :   } else if (!strcmp(ri->request_method, "PROPFIND")) {
    3399           0 :     handle_propfind(conn, path, &st);
    3400           0 :   } else if (st.is_directory &&
    3401           0 :              !substitute_index_file(conn, path, sizeof(path), &st)) {
    3402           0 :     if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
    3403           0 :       handle_directory_request(conn, path);
    3404             :     } else {
    3405           0 :       send_http_error(conn, 403, "Directory Listing Denied",
    3406             :           "Directory listing denied");
    3407             :     }
    3408             : #if !defined(NO_CGI)
    3409             :   } else if (match_extension(path, conn->ctx->config[CGI_EXTENSIONS])) {
    3410             :     if (strcmp(ri->request_method, "POST") &&
    3411             :         strcmp(ri->request_method, "GET")) {
    3412             :       send_http_error(conn, 501, "Not Implemented",
    3413             :           "Method %s is not implemented", ri->request_method);
    3414             :     } else {
    3415             :       handle_cgi_request(conn, path);
    3416             :     }
    3417             : #endif // !NO_CGI
    3418           0 :   } else if (match_extension(path, conn->ctx->config[SSI_EXTENSIONS])) {
    3419           0 :     handle_ssi_file_request(conn, path);
    3420           0 :   } else if (is_not_modified(conn, &st)) {
    3421           0 :     send_http_error(conn, 304, "Not Modified", "");
    3422             :   } else {
    3423           0 :     handle_file_request(conn, path, &st);
    3424             :   }
    3425           0 : }
    3426             : 
    3427           0 : static void close_all_listening_sockets(struct mg_context *ctx) {
    3428             :   struct socket *sp, *tmp;
    3429           0 :   for (sp = ctx->listening_sockets; sp != NULL; sp = tmp) {
    3430           0 :     tmp = sp->next;
    3431           0 :     (void) closesocket(sp->sock);
    3432           0 :     free(sp);
    3433             :   }
    3434           0 : }
    3435             : 
    3436             : // Valid listening port specification is: [ip_address:]port[s|p]
    3437             : // Examples: 80, 443s, 127.0.0.1:3128p, 1.2.3.4:8080sp
    3438           0 : static int parse_port_string(const struct vec *vec, struct socket *so) {
    3439           0 :   struct usa *usa = &so->lsa;
    3440             :   int a, b, c, d, port, len;
    3441             : 
    3442             :   // MacOS needs that. If we do not zero it, subsequent bind() will fail.
    3443           0 :   memset(so, 0, sizeof(*so));
    3444             : 
    3445           0 :   if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
    3446             :     // IP address to bind to is specified
    3447           0 :     usa->u.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
    3448           0 :   } else if (sscanf(vec->ptr, "%d%n", &port, &len) == 1) {
    3449             :     // Only port number is specified. Bind to all addresses
    3450           0 :     usa->u.sin.sin_addr.s_addr = htonl(INADDR_ANY);
    3451             :   } else {
    3452           0 :     return 0;
    3453             :   }
    3454           0 :   assert(len > 0 && len <= (int) vec->len);
    3455             : 
    3456           0 :   if (strchr("sp,", vec->ptr[len]) == NULL) {
    3457           0 :     return 0;
    3458             :   }
    3459             : 
    3460           0 :   so->is_ssl = vec->ptr[len] == 's';
    3461           0 :   so->is_proxy = vec->ptr[len] == 'p';
    3462           0 :   usa->len = sizeof(usa->u.sin);
    3463           0 :   usa->u.sin.sin_family = AF_INET;
    3464           0 :   usa->u.sin.sin_port = htons((uint16_t) port);
    3465             : 
    3466           0 :   return 1;
    3467             : }
    3468             : 
    3469           0 : static int set_ports_option(struct mg_context *ctx) {
    3470           0 :   const char *list = ctx->config[LISTENING_PORTS];
    3471           0 :   int on = 1, success = 1;
    3472             :   SOCKET sock;
    3473             :   struct vec vec;
    3474             :   struct socket so, *listener;
    3475             : 
    3476           0 :   while (success && (list = next_option(list, &vec, NULL)) != NULL) {
    3477           0 :     if (!parse_port_string(&vec, &so)) {
    3478           0 :       cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
    3479           0 :           __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]");
    3480           0 :       success = 0;
    3481           0 :     } else if (so.is_ssl && ctx->ssl_ctx == NULL) {
    3482           0 :       cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
    3483           0 :       success = 0;
    3484           0 :     } else if ((sock = socket(PF_INET, SOCK_STREAM, 6)) == INVALID_SOCKET ||
    3485             : #if !defined(_WIN32)
    3486             :                // On Windows, SO_REUSEADDR is recommended only for
    3487             :                // broadcast UDP sockets
    3488           0 :                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
    3489           0 :                           sizeof(on)) != 0 ||
    3490             : #endif // !_WIN32
    3491             :                // Set TCP keep-alive. This is needed because if HTTP-level
    3492             :                // keep-alive is enabled, and client resets the connection,
    3493             :                // server won't get TCP FIN or RST and will keep the connection
    3494             :                // open forever. With TCP keep-alive, next keep-alive
    3495             :                // handshake will figure out that the client is down and
    3496             :                // will close the server end.
    3497             :                // Thanks to Igor Klopov who suggested the patch.
    3498           0 :                setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (const char*) &on,
    3499           0 :                           sizeof(on)) != 0 ||
    3500           0 :                bind(sock, &so.lsa.u.sa, so.lsa.len) != 0 ||
    3501           0 :                listen(sock, 100) != 0) {
    3502           0 :       closesocket(sock);
    3503           0 :       cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__,
    3504           0 :           (int) vec.len, vec.ptr, strerror(ERRNO));
    3505           0 :       success = 0;
    3506           0 :     } else if ((listener = (struct socket *)
    3507           0 :                 calloc(1, sizeof(*listener))) == NULL) {
    3508           0 :       closesocket(sock);
    3509           0 :       cry(fc(ctx), "%s: %s", __func__, strerror(ERRNO));
    3510           0 :       success = 0;
    3511             :     } else {
    3512           0 :       *listener = so;
    3513           0 :       listener->sock = sock;
    3514           0 :       set_close_on_exec(listener->sock);
    3515           0 :       listener->next = ctx->listening_sockets;
    3516           0 :       ctx->listening_sockets = listener;
    3517             :     }
    3518             :   }
    3519             : 
    3520           0 :   if (!success) {
    3521           0 :     close_all_listening_sockets(ctx);
    3522             :   }
    3523             : 
    3524           0 :   return success;
    3525             : }
    3526             : 
    3527           0 : static void log_header(const struct mg_connection *conn, const char *header,
    3528             :                        FILE *fp) {
    3529             :   const char *header_value;
    3530             : 
    3531           0 :   if ((header_value = mg_get_header(conn, header)) == NULL) {
    3532           0 :     (void) fprintf(fp, "%s", " -");
    3533             :   } else {
    3534           0 :     (void) fprintf(fp, " \"%s\"", header_value);
    3535             :   }
    3536           0 : }
    3537             : 
    3538           0 : static void log_access(const struct mg_connection *conn) {
    3539             :   const struct mg_request_info *ri;
    3540             :   FILE *fp;
    3541             :   char date[64];
    3542             : 
    3543           0 :   fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
    3544           0 :     mg_fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
    3545             : 
    3546           0 :   if (fp == NULL)
    3547           0 :     return;
    3548             : 
    3549           0 :   (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
    3550           0 :       localtime(&conn->birth_time));
    3551             : 
    3552           0 :   ri = &conn->request_info;
    3553             : 
    3554           0 :   flockfile(fp);
    3555             : 
    3556           0 :   (void) fprintf(fp,
    3557             :       "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
    3558             :       inet_ntoa(conn->client.rsa.u.sin.sin_addr),
    3559           0 :       ri->remote_user == NULL ? "-" : ri->remote_user,
    3560             :       date,
    3561           0 :       ri->request_method ? ri->request_method : "-",
    3562           0 :       ri->uri ? ri->uri : "-",
    3563           0 :       ri->http_version,
    3564           0 :       conn->request_info.status_code, conn->num_bytes_sent);
    3565           0 :   log_header(conn, "Referer", fp);
    3566           0 :   log_header(conn, "User-Agent", fp);
    3567           0 :   (void) fputc('\n', fp);
    3568           0 :   (void) fflush(fp);
    3569             : 
    3570           0 :   funlockfile(fp);
    3571           0 :   (void) fclose(fp);
    3572             : }
    3573             : 
    3574           0 : static int isbyte(int n) {
    3575           0 :   return n >= 0 && n <= 255;
    3576             : }
    3577             : 
    3578             : // Verify given socket address against the ACL.
    3579             : // Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
    3580           0 : static int check_acl(struct mg_context *ctx, const struct usa *usa) {
    3581             :   int a, b, c, d, n, mask, allowed;
    3582             :   char flag;
    3583             :   uint32_t acl_subnet, acl_mask, remote_ip;
    3584             :   struct vec vec;
    3585           0 :   const char *list = ctx->config[ACCESS_CONTROL_LIST];
    3586             : 
    3587           0 :   if (list == NULL) {
    3588           0 :     return 1;
    3589             :   }
    3590             : 
    3591           0 :   (void) memcpy(&remote_ip, &usa->u.sin.sin_addr, sizeof(remote_ip));
    3592             : 
    3593             :   // If any ACL is set, deny by default
    3594           0 :   allowed = '-';
    3595             : 
    3596           0 :   while ((list = next_option(list, &vec, NULL)) != NULL) {
    3597           0 :     mask = 32;
    3598             : 
    3599           0 :     if (sscanf(vec.ptr, "%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) {
    3600           0 :       cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
    3601           0 :       return -1;
    3602           0 :     } else if (flag != '+' && flag != '-') {
    3603           0 :       cry(fc(ctx), "%s: flag must be + or -: [%s]", __func__, vec.ptr);
    3604           0 :       return -1;
    3605           0 :     } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
    3606           0 :       cry(fc(ctx), "%s: bad ip address: [%s]", __func__, vec.ptr);
    3607           0 :       return -1;
    3608           0 :     } else if (sscanf(vec.ptr + n, "/%d", &mask) == 0) {
    3609             :       // Do nothing, no mask specified
    3610           0 :     } else if (mask < 0 || mask > 32) {
    3611           0 :       cry(fc(ctx), "%s: bad subnet mask: %d [%s]", __func__, n, vec.ptr);
    3612           0 :       return -1;
    3613             :     }
    3614             : 
    3615           0 :     acl_subnet = (a << 24) | (b << 16) | (c << 8) | d;
    3616           0 :     acl_mask = mask ? 0xffffffffU << (32 - mask) : 0;
    3617             : 
    3618           0 :     if (acl_subnet == (ntohl(remote_ip) & acl_mask)) {
    3619           0 :       allowed = flag;
    3620             :     }
    3621             :   }
    3622             : 
    3623           0 :   return allowed == '+';
    3624             : }
    3625             : 
    3626           0 : static void add_to_set(SOCKET fd, fd_set *set, int *max_fd) {
    3627           0 :   FD_SET(fd, set);
    3628           0 :   if (fd > (SOCKET) *max_fd) {
    3629           0 :     *max_fd = (int) fd;
    3630             :   }
    3631           0 : }
    3632             : 
    3633             : #if !defined(_WIN32)
    3634           0 : static int set_uid_option(struct mg_context *ctx) {
    3635             :   struct passwd *pw;
    3636           0 :   const char *uid = ctx->config[RUN_AS_USER];
    3637           0 :   int success = 0;
    3638             : 
    3639           0 :   if (uid == NULL) {
    3640           0 :     success = 1;
    3641             :   } else {
    3642           0 :     if ((pw = getpwnam(uid)) == NULL) {
    3643           0 :       cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
    3644           0 :     } else if (setgid(pw->pw_gid) == -1) {
    3645           0 :       cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno));
    3646           0 :     } else if (setuid(pw->pw_uid) == -1) {
    3647           0 :       cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno));
    3648             :     } else {
    3649           0 :       success = 1;
    3650             :     }
    3651             :   }
    3652             : 
    3653           0 :   return success;
    3654             : }
    3655             : #endif // !_WIN32
    3656             : 
    3657             : #if !defined(NO_SSL)
    3658             : static pthread_mutex_t *ssl_mutexes;
    3659             : 
    3660             : static void ssl_locking_callback(int mode, int mutex_num, const char *file,
    3661             :                                  int line) {
    3662             :   line = 0;    // Unused
    3663             :   file = NULL; // Unused
    3664             : 
    3665             :   if (mode & CRYPTO_LOCK) {
    3666             :     (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
    3667             :   } else {
    3668             :     (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
    3669             :   }
    3670             : }
    3671             : 
    3672             : static unsigned long ssl_id_callback(void) {
    3673             :   return (unsigned long) pthread_self();
    3674             : }
    3675             : 
    3676             : #if !defined(NO_SSL_DL)
    3677             : static int load_dll(struct mg_context *ctx, const char *dll_name,
    3678             :                     struct ssl_func *sw) {
    3679             :   union {void *p; void (*fp)(void);} u;
    3680             :   void  *dll_handle;
    3681             :   struct ssl_func *fp;
    3682             : 
    3683             :   if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
    3684             :     cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
    3685             :     return 0;
    3686             :   }
    3687             : 
    3688             :   for (fp = sw; fp->name != NULL; fp++) {
    3689             : #ifdef _WIN32
    3690             :     // GetProcAddress() returns pointer to function
    3691             :     u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
    3692             : #else
    3693             :     // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
    3694             :     // function pointers. We need to use a union to make a cast.
    3695             :     u.p = dlsym(dll_handle, fp->name);
    3696             : #endif // _WIN32
    3697             :     if (u.fp == NULL) {
    3698             :       cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name);
    3699             :       return 0;
    3700             :     } else {
    3701             :       fp->ptr = u.fp;
    3702             :     }
    3703             :   }
    3704             : 
    3705             :   return 1;
    3706             : }
    3707             : #endif // NO_SSL_DL
    3708             : 
    3709             : // Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
    3710             : static int set_ssl_option(struct mg_context *ctx) {
    3711             :   struct mg_request_info request_info;
    3712             :   SSL_CTX *CTX;
    3713             :   int i, size;
    3714             :   const char *pem = ctx->config[SSL_CERTIFICATE];
    3715             :   const char *chain = ctx->config[SSL_CHAIN_FILE];
    3716             : 
    3717             :   if (pem == NULL) {
    3718             :     return 1;
    3719             :   }
    3720             : 
    3721             : #if !defined(NO_SSL_DL)
    3722             :   if (!load_dll(ctx, SSL_LIB, ssl_sw) ||
    3723             :       !load_dll(ctx, CRYPTO_LIB, crypto_sw)) {
    3724             :     return 0;
    3725             :   }
    3726             : #endif // NO_SSL_DL
    3727             : 
    3728             :   // Initialize SSL crap
    3729             :   SSL_library_init();
    3730             :   SSL_load_error_strings();
    3731             : 
    3732             :   if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
    3733             :     cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
    3734             :   } else if (ctx->user_callback != NULL) {
    3735             :     memset(&request_info, 0, sizeof(request_info));
    3736             :     request_info.user_data = ctx->user_data;
    3737             :     ctx->user_callback(MG_INIT_SSL, (struct mg_connection *) CTX,
    3738             :                        &request_info);
    3739             :   }
    3740             : 
    3741             :   if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem,
    3742             :         SSL_FILETYPE_PEM) == 0) {
    3743             :     cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
    3744             :     return 0;
    3745             :   } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem,
    3746             :         SSL_FILETYPE_PEM) == 0) {
    3747             :     cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
    3748             :     return 0;
    3749             :   }
    3750             : 
    3751             :   if (CTX != NULL && chain != NULL &&
    3752             :       SSL_CTX_use_certificate_chain_file(CTX, chain) == 0) {
    3753             :     cry(fc(ctx), "%s: cannot open %s: %s", NULL, chain, ssl_error());
    3754             :     return 0;
    3755             :   }
    3756             : 
    3757             :   // Initialize locking callbacks, needed for thread safety.
    3758             :   // http://www.openssl.org/support/faq.html#PROG1
    3759             :   size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
    3760             :   if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
    3761             :     cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
    3762             :     return 0;
    3763             :   }
    3764             : 
    3765             :   for (i = 0; i < CRYPTO_num_locks(); i++) {
    3766             :     pthread_mutex_init(&ssl_mutexes[i], NULL);
    3767             :   }
    3768             : 
    3769             :   CRYPTO_set_locking_callback(&ssl_locking_callback);
    3770             :   CRYPTO_set_id_callback(&ssl_id_callback);
    3771             : 
    3772             :   // Done with everything. Save the context.
    3773             :   ctx->ssl_ctx = CTX;
    3774             : 
    3775             :   return 1;
    3776             : }
    3777             : 
    3778             : static void uninitialize_ssl(struct mg_context *ctx) {
    3779             :   int i;
    3780             :   if (ctx->ssl_ctx != NULL) {
    3781             :     CRYPTO_set_locking_callback(NULL);
    3782             :     for (i = 0; i < CRYPTO_num_locks(); i++) {
    3783             :       pthread_mutex_destroy(&ssl_mutexes[i]);
    3784             :     }
    3785             :     CRYPTO_set_locking_callback(NULL);
    3786             :     CRYPTO_set_id_callback(NULL);
    3787             :   }
    3788             : }
    3789             : #endif // !NO_SSL
    3790             : 
    3791           0 : static int set_gpass_option(struct mg_context *ctx) {
    3792             :   struct mgstat mgstat;
    3793           0 :   const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
    3794           0 :   return path == NULL || mg_stat(path, &mgstat) == 0;
    3795             : }
    3796             : 
    3797           0 : static int set_acl_option(struct mg_context *ctx) {
    3798             :   struct usa fake;
    3799           0 :   return check_acl(ctx, &fake) != -1;
    3800             : }
    3801             : 
    3802           0 : static void reset_per_request_attributes(struct mg_connection *conn) {
    3803           0 :   struct mg_request_info *ri = &conn->request_info;
    3804             : 
    3805             :   // Reset request info attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
    3806           0 :   if (ri->remote_user != NULL) {
    3807           0 :     free((void *) ri->remote_user);
    3808             :   }
    3809           0 :   ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
    3810           0 :   ri->num_headers = 0;
    3811           0 :   ri->status_code = -1;
    3812             : 
    3813           0 :   conn->num_bytes_sent = conn->consumed_content = 0;
    3814           0 :   conn->content_len = -1;
    3815           0 :   conn->request_len = conn->data_len = 0;
    3816           0 : }
    3817             : 
    3818           0 : static void close_socket_gracefully(SOCKET sock) {
    3819             :   char buf[BUFSIZ];
    3820             :   struct linger linger;
    3821             :   int n;
    3822             : 
    3823             :   // Set linger option to avoid socket hanging out after close. This prevent
    3824             :   // ephemeral port exhaust problem under high QPS.
    3825           0 :   linger.l_onoff = 1;
    3826           0 :   linger.l_linger = 1;
    3827           0 :   setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char *) &linger, sizeof(linger));
    3828             : 
    3829             :   // Send FIN to the client
    3830           0 :   (void) shutdown(sock, SHUT_WR);
    3831           0 :   set_non_blocking_mode(sock);
    3832             : 
    3833             :   // Read and discard pending data. If we do not do that and close the
    3834             :   // socket, the data in the send buffer may be discarded. This
    3835             :   // behaviour is seen on Windows, when client keeps sending data
    3836             :   // when server decide to close the connection; then when client
    3837             :   // does recv() it gets no data back.
    3838           0 :   do {
    3839           0 :     n = pull(NULL, sock, NULL, buf, sizeof(buf));
    3840           0 :   } while (n > 0);
    3841             : 
    3842             :   // Now we know that our FIN is ACK-ed, safe to close
    3843           0 :   (void) closesocket(sock);
    3844           0 : }
    3845             : 
    3846           0 : static void close_connection(struct mg_connection *conn) {
    3847           0 :   if (conn->ssl) {
    3848           0 :     SSL_free(conn->ssl);
    3849           0 :     conn->ssl = NULL;
    3850             :   }
    3851             : 
    3852           0 :   if (conn->client.sock != INVALID_SOCKET) {
    3853           0 :     close_socket_gracefully(conn->client.sock);
    3854             :   }
    3855           0 : }
    3856             : 
    3857           0 : static void discard_current_request_from_buffer(struct mg_connection *conn) {
    3858             :   char *buffered;
    3859             :   int buffered_len, body_len;
    3860             : 
    3861           0 :   buffered = conn->buf + conn->request_len;
    3862           0 :   buffered_len = conn->data_len - conn->request_len;
    3863           0 :   assert(buffered_len >= 0);
    3864             : 
    3865           0 :   if (conn->content_len == -1) {
    3866           0 :     body_len = 0;
    3867           0 :   } else if (conn->content_len < (int64_t) buffered_len) {
    3868           0 :     body_len = (int) conn->content_len;
    3869             :   } else {
    3870           0 :     body_len = buffered_len;
    3871             :   }
    3872             : 
    3873           0 :   conn->data_len -= conn->request_len + body_len;
    3874           0 :   memmove(conn->buf, conn->buf + conn->request_len + body_len,
    3875           0 :           (size_t) conn->data_len);
    3876           0 : }
    3877             : 
    3878           0 : static int parse_url(const char *url, char *host, int *port) {
    3879             :   int len;
    3880             : 
    3881           0 :   if (sscanf(url, "%*[htps]://%1024[^:]:%d%n", host, port, &len) == 2 ||
    3882           0 :       sscanf(url, "%1024[^:]:%d%n", host, port, &len) == 2) {
    3883           0 :   } else if (sscanf(url, "%*[htps]://%1024[^/]%n", host, &len) == 1) {
    3884           0 :     *port = 80;
    3885             :   } else {
    3886           0 :     sscanf(url, "%1024[^/]%n", host, &len);
    3887           0 :     *port = 80;
    3888             :   }
    3889             :   DEBUG_TRACE(("Host:%s, port:%d", host, *port));
    3890             : 
    3891           0 :   return len;
    3892             : }
    3893             : 
    3894           0 : static void handle_proxy_request(struct mg_connection *conn) {
    3895           0 :   struct mg_request_info *ri = &conn->request_info;
    3896             :   char host[1025], buf[BUFSIZ];
    3897             :   int port, is_ssl, len, i, n;
    3898             : 
    3899             :   DEBUG_TRACE(("URL: %s", ri->uri));
    3900           0 :   if (ri->uri == NULL ||
    3901           0 :       ri->uri[0] == '/' ||
    3902           0 :       (len = parse_url(ri->uri, host, &port)) == 0) {
    3903           0 :     return;
    3904             :   }
    3905             : 
    3906           0 :   if (conn->peer == NULL) {
    3907           0 :     is_ssl = !strcmp(ri->request_method, "CONNECT");
    3908           0 :     if ((conn->peer = mg_connect(conn, host, port, is_ssl)) == NULL) {
    3909           0 :       return;
    3910             :     }
    3911           0 :     conn->peer->client.is_ssl = is_ssl;
    3912             :   }
    3913             :   
    3914             :   // Forward client's request to the target
    3915           0 :   mg_printf(conn->peer, "%s %s HTTP/%s\r\n", ri->request_method, ri->uri + len,
    3916             :             ri->http_version);
    3917             : 
    3918             :   // And also all headers. TODO(lsm): anonymize!
    3919           0 :   for (i = 0; i < ri->num_headers; i++) {
    3920           0 :     mg_printf(conn->peer, "%s: %s\r\n", ri->http_headers[i].name,
    3921             :               ri->http_headers[i].value);
    3922             :   }
    3923             :   // End of headers, final newline
    3924           0 :   mg_write(conn->peer, "\r\n", 2);
    3925             : 
    3926             :   // Read and forward body data if any
    3927           0 :   if (!strcmp(ri->request_method, "POST")) {
    3928           0 :     forward_body_data(conn, NULL, conn->peer->client.sock, conn->peer->ssl);
    3929             :   }
    3930             : 
    3931             :   // Read data from the target and forward it to the client
    3932           0 :   while ((n = pull(NULL, conn->peer->client.sock, conn->peer->ssl,
    3933           0 :                    buf, sizeof(buf))) > 0) {
    3934           0 :     if (mg_write(conn, buf, (size_t)n) != n) {
    3935           0 :       break;
    3936             :     }
    3937             :   }
    3938             : 
    3939           0 :   if (!conn->peer->client.is_ssl) {
    3940           0 :     close_connection(conn->peer);
    3941           0 :     free(conn->peer);
    3942           0 :     conn->peer = NULL;
    3943             :   }
    3944             : }
    3945             : 
    3946           0 : static int is_valid_uri(const char *uri) {
    3947             :   // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
    3948             :   // URI can be an asterisk (*) or should start with slash.
    3949           0 :   return (uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0'));
    3950             : }
    3951             : 
    3952           0 : static void process_new_connection(struct mg_connection *conn) {
    3953           0 :   struct mg_request_info *ri = &conn->request_info;
    3954             :   int keep_alive_enabled;
    3955             :   const char *cl;
    3956             : 
    3957           0 :   keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
    3958             : 
    3959           0 :   do {
    3960           0 :     reset_per_request_attributes(conn);
    3961             : 
    3962             :     // If next request is not pipelined, read it in
    3963           0 :     if ((conn->request_len = get_request_len(conn->buf, conn->data_len)) == 0) {
    3964           0 :       conn->request_len = read_request(NULL, conn->client.sock, conn->ssl,
    3965             :           conn->buf, conn->buf_size, &conn->data_len);
    3966             :     }
    3967           0 :     assert(conn->data_len >= conn->request_len);
    3968           0 :     if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
    3969           0 :       send_http_error(conn, 413, "Request Too Large", "");
    3970           0 :       return;
    3971           0 :     } if (conn->request_len <= 0) {
    3972           0 :       return;  // Remote end closed the connection
    3973             :     }
    3974             : 
    3975             :     // Nul-terminate the request cause parse_http_request() uses sscanf
    3976           0 :     conn->buf[conn->request_len - 1] = '\0';
    3977           0 :     if (!parse_http_request(conn->buf, ri) ||
    3978           0 :         (!conn->client.is_proxy && !is_valid_uri(ri->uri))) {
    3979             :       // Do not put garbage in the access log, just send it back to the client
    3980           0 :       send_http_error(conn, 400, "Bad Request",
    3981             :           "Cannot parse HTTP request: [%.*s]", conn->data_len, conn->buf);
    3982           0 :     } else if (strcmp(ri->http_version, "1.0") &&
    3983           0 :                strcmp(ri->http_version, "1.1")) {
    3984             :       // Request seems valid, but HTTP version is strange
    3985           0 :       send_http_error(conn, 505, "HTTP version not supported", "");
    3986           0 :       log_access(conn);
    3987             :     } else {
    3988             :       // Request is valid, handle it
    3989           0 :       cl = get_header(ri, "Content-Length");
    3990           0 :       conn->content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10);
    3991           0 :       conn->birth_time = time(NULL);
    3992           0 :       if (conn->client.is_proxy) {
    3993           0 :         handle_proxy_request(conn);
    3994             :       } else {
    3995           0 :         handle_request(conn);
    3996             :       }
    3997           0 :       log_access(conn);
    3998           0 :       discard_current_request_from_buffer(conn);
    3999             :     }
    4000             :     // conn->peer is not NULL only for SSL-ed proxy connections
    4001           0 :   } while (conn->ctx->stop_flag == 0 &&
    4002           0 :            (conn->peer || (keep_alive_enabled && should_keep_alive(conn))));
    4003             : }
    4004             : 
    4005             : // Worker threads take accepted socket from the queue
    4006           0 : static int consume_socket(struct mg_context *ctx, struct socket *sp) {
    4007           0 :   (void) pthread_mutex_lock(&ctx->mutex);
    4008             :   DEBUG_TRACE(("going idle"));
    4009             : 
    4010             :   // If the queue is empty, wait. We're idle at this point.
    4011           0 :   while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
    4012           0 :     pthread_cond_wait(&ctx->sq_full, &ctx->mutex);
    4013             :   }
    4014             : 
    4015             :   // If we're stopping, sq_head may be equal to sq_tail.
    4016           0 :   if (ctx->sq_head > ctx->sq_tail) {
    4017             :     // Copy socket from the queue and increment tail
    4018           0 :     *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)];
    4019           0 :     ctx->sq_tail++;
    4020             :     DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock));
    4021             : 
    4022             :     // Wrap pointers if needed
    4023           0 :     while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) {
    4024           0 :       ctx->sq_tail -= ARRAY_SIZE(ctx->queue);
    4025           0 :       ctx->sq_head -= ARRAY_SIZE(ctx->queue);
    4026             :     }
    4027             :   }
    4028             : 
    4029           0 :   (void) pthread_cond_signal(&ctx->sq_empty);
    4030           0 :   (void) pthread_mutex_unlock(&ctx->mutex);
    4031             : 
    4032           0 :   return !ctx->stop_flag;
    4033             : }
    4034             : 
    4035           0 : static void worker_thread(struct mg_context *ctx) {
    4036             :   struct mg_connection *conn;
    4037           0 :   int buf_size = atoi(ctx->config[MAX_REQUEST_SIZE]);
    4038             : 
    4039           0 :   conn = (struct mg_connection *) calloc(1, sizeof(*conn) + buf_size);
    4040           0 :   conn->buf_size = buf_size;
    4041           0 :   conn->buf = (char *) (conn + 1);
    4042           0 :   assert(conn != NULL);
    4043             : 
    4044             :   // Call consume_socket() even when ctx->stop_flag > 0, to let it signal
    4045             :   // sq_empty condvar to wake up the master waiting in produce_socket()
    4046           0 :   while (consume_socket(ctx, &conn->client)) {
    4047           0 :     conn->birth_time = time(NULL);
    4048           0 :     conn->ctx = ctx;
    4049             : 
    4050             :     // Fill in IP, port info early so even if SSL setup below fails,
    4051             :     // error handler would have the corresponding info.
    4052             :     // Thanks to Johannes Winkelmann for the patch.
    4053           0 :     conn->request_info.remote_port = ntohs(conn->client.rsa.u.sin.sin_port);
    4054           0 :     memcpy(&conn->request_info.remote_ip,
    4055           0 :            &conn->client.rsa.u.sin.sin_addr.s_addr, 4);
    4056           0 :     conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
    4057           0 :     conn->request_info.is_ssl = conn->client.is_ssl;
    4058             : 
    4059           0 :     if (!conn->client.is_ssl ||
    4060           0 :         (conn->client.is_ssl && sslize(conn, SSL_accept))) {
    4061           0 :       process_new_connection(conn);
    4062             :     }
    4063             : 
    4064           0 :     close_connection(conn);
    4065             :   }
    4066           0 :   free(conn);
    4067             : 
    4068             :   // Signal master that we're done with connection and exiting
    4069           0 :   (void) pthread_mutex_lock(&ctx->mutex);
    4070           0 :   ctx->num_threads--;
    4071           0 :   (void) pthread_cond_signal(&ctx->cond);
    4072           0 :   assert(ctx->num_threads >= 0);
    4073           0 :   (void) pthread_mutex_unlock(&ctx->mutex);
    4074             : 
    4075             :   DEBUG_TRACE(("exiting"));
    4076           0 : }
    4077             : 
    4078             : // Master thread adds accepted socket to a queue
    4079           0 : static void produce_socket(struct mg_context *ctx, const struct socket *sp) {
    4080           0 :   (void) pthread_mutex_lock(&ctx->mutex);
    4081             : 
    4082             :   // If the queue is full, wait
    4083           0 :   while (ctx->stop_flag == 0 &&
    4084           0 :          ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) {
    4085           0 :     (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex);
    4086             :   }
    4087             : 
    4088           0 :   if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) {
    4089             :     // Copy socket to the queue and increment head
    4090           0 :     ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp;
    4091           0 :     ctx->sq_head++;
    4092             :     DEBUG_TRACE(("queued socket %d", sp->sock));
    4093             :   }
    4094             : 
    4095           0 :   (void) pthread_cond_signal(&ctx->sq_full);
    4096           0 :   (void) pthread_mutex_unlock(&ctx->mutex);
    4097           0 : }
    4098             : 
    4099           0 : static void accept_new_connection(const struct socket *listener,
    4100             :                                   struct mg_context *ctx) {
    4101             :   struct socket accepted;
    4102             :   int allowed;
    4103             : 
    4104           0 :   accepted.rsa.len = sizeof(accepted.rsa.u.sin);
    4105           0 :   accepted.lsa = listener->lsa;
    4106           0 :   accepted.sock = accept(listener->sock, &accepted.rsa.u.sa, &accepted.rsa.len);
    4107           0 :   if (accepted.sock != INVALID_SOCKET) {
    4108           0 :     allowed = check_acl(ctx, &accepted.rsa);
    4109           0 :     if (allowed) {
    4110             :       // Put accepted socket structure into the queue
    4111             :       DEBUG_TRACE(("accepted socket %d", accepted.sock));
    4112           0 :       accepted.is_ssl = listener->is_ssl;
    4113           0 :       accepted.is_proxy = listener->is_proxy;
    4114           0 :       produce_socket(ctx, &accepted);
    4115             :     } else {
    4116           0 :       cry(fc(ctx), "%s: %s is not allowed to connect",
    4117             :           __func__, inet_ntoa(accepted.rsa.u.sin.sin_addr));
    4118           0 :       (void) closesocket(accepted.sock);
    4119             :     }
    4120             :   }
    4121           0 : }
    4122             : 
    4123           0 : static void master_thread(struct mg_context *ctx) {
    4124             :   fd_set read_set;
    4125             :   struct timeval tv;
    4126             :   struct socket *sp;
    4127             :   int max_fd;
    4128             : 
    4129           0 :   while (ctx->stop_flag == 0) {
    4130           0 :     FD_ZERO(&read_set);
    4131           0 :     max_fd = -1;
    4132             : 
    4133             :     // Add listening sockets to the read set
    4134           0 :     for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {
    4135           0 :       add_to_set(sp->sock, &read_set, &max_fd);
    4136             :     }
    4137             : 
    4138           0 :     tv.tv_sec = 0;
    4139           0 :     tv.tv_usec = 200 * 1000;
    4140             : 
    4141           0 :     if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
    4142             : #ifdef _WIN32
    4143             :       // On windows, if read_set and write_set are empty,
    4144             :       // select() returns "Invalid parameter" error
    4145             :       // (at least on my Windows XP Pro). So in this case, we sleep here.
    4146             :       sleep(1);
    4147             : #endif // _WIN32
    4148             :     } else {
    4149           0 :       for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {
    4150           0 :         if (ctx->stop_flag == 0 && FD_ISSET(sp->sock, &read_set)) {
    4151           0 :           accept_new_connection(sp, ctx);
    4152             :         }
    4153             :       }
    4154             :     }
    4155             :   }
    4156             :   DEBUG_TRACE(("stopping workers"));
    4157             : 
    4158             :   // Stop signal received: somebody called mg_stop. Quit.
    4159           0 :   close_all_listening_sockets(ctx);
    4160             : 
    4161             :   // Wakeup workers that are waiting for connections to handle.
    4162           0 :   pthread_cond_broadcast(&ctx->sq_full);
    4163             : 
    4164             :   // Wait until all threads finish
    4165           0 :   (void) pthread_mutex_lock(&ctx->mutex);
    4166           0 :   while (ctx->num_threads > 0) {
    4167           0 :     (void) pthread_cond_wait(&ctx->cond, &ctx->mutex);
    4168             :   }
    4169           0 :   (void) pthread_mutex_unlock(&ctx->mutex);
    4170             : 
    4171             :   // All threads exited, no sync is needed. Destroy mutex and condvars
    4172           0 :   (void) pthread_mutex_destroy(&ctx->mutex);
    4173           0 :   (void) pthread_cond_destroy(&ctx->cond);
    4174           0 :   (void) pthread_cond_destroy(&ctx->sq_empty);
    4175           0 :   (void) pthread_cond_destroy(&ctx->sq_full);
    4176             : 
    4177             : #if !defined(NO_SSL)
    4178             :   uninitialize_ssl(ctx);
    4179             : #endif
    4180             : 
    4181             :   // Signal mg_stop() that we're done
    4182           0 :   ctx->stop_flag = 2;
    4183             : 
    4184             :   DEBUG_TRACE(("exiting"));
    4185           0 : }
    4186             : 
    4187           0 : static void free_context(struct mg_context *ctx) {
    4188             :   int i;
    4189             : 
    4190             :   // Deallocate config parameters
    4191           0 :   for (i = 0; i < NUM_OPTIONS; i++) {
    4192           0 :     if (ctx->config[i] != NULL)
    4193           0 :       free(ctx->config[i]);
    4194             :   }
    4195             : 
    4196             :   // Deallocate SSL context
    4197           0 :   if (ctx->ssl_ctx != NULL) {
    4198           0 :     SSL_CTX_free(ctx->ssl_ctx);
    4199             :   }
    4200             : #ifndef NO_SSL
    4201             :   if (ssl_mutexes != NULL) {
    4202             :     free(ssl_mutexes);
    4203             :   }
    4204             : #endif // !NO_SSL
    4205             : 
    4206             :   // Deallocate context itself
    4207           0 :   free(ctx);
    4208           0 : }
    4209             : 
    4210           0 : void mg_stop(struct mg_context *ctx) {
    4211           0 :   ctx->stop_flag = 1;
    4212             : 
    4213             :   // Wait until mg_fini() stops
    4214           0 :   while (ctx->stop_flag != 2) {
    4215           0 :     (void) sleep(0);
    4216             :   }
    4217           0 :   free_context(ctx);
    4218             : 
    4219             : #if defined(_WIN32) && !defined(__SYMBIAN32__)
    4220             :   (void) WSACleanup();
    4221             : #endif // _WIN32
    4222           0 : }
    4223             : 
    4224           0 : struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,
    4225             :                             const char **options) {
    4226             :   struct mg_context *ctx;
    4227             :   const char *name, *value, *default_value;
    4228             :   int i;
    4229             : 
    4230             : #if defined(_WIN32) && !defined(__SYMBIAN32__)
    4231             :   WSADATA data;
    4232             :   WSAStartup(MAKEWORD(2,2), &data);
    4233             : #endif // _WIN32
    4234             : 
    4235             :   // Allocate context and initialize reasonable general case defaults.
    4236             :   // TODO(lsm): do proper error handling here.
    4237           0 :   ctx = (struct mg_context *) calloc(1, sizeof(*ctx));
    4238           0 :   ctx->user_callback = user_callback;
    4239           0 :   ctx->user_data = user_data;
    4240             : 
    4241           0 :   while (options && (name = *options++) != NULL) {
    4242           0 :     if ((i = get_option_index(name)) == -1) {
    4243           0 :       cry(fc(ctx), "Invalid option: %s", name);
    4244           0 :       free_context(ctx);
    4245           0 :       return NULL;
    4246           0 :     } else if ((value = *options++) == NULL) {
    4247           0 :       cry(fc(ctx), "%s: option value cannot be NULL", name);
    4248           0 :       free_context(ctx);
    4249           0 :       return NULL;
    4250             :     }
    4251           0 :     ctx->config[i] = mg_strdup(value);
    4252             :     DEBUG_TRACE(("[%s] -> [%s]", name, value));
    4253             :   }
    4254             : 
    4255             :   // Set default value if needed
    4256           0 :   for (i = 0; config_options[i * ENTRIES_PER_CONFIG_OPTION] != NULL; i++) {
    4257           0 :     default_value = config_options[i * ENTRIES_PER_CONFIG_OPTION + 2];
    4258           0 :     if (ctx->config[i] == NULL && default_value != NULL) {
    4259           0 :       ctx->config[i] = mg_strdup(default_value);
    4260             :       DEBUG_TRACE(("Setting default: [%s] -> [%s]",
    4261             :                    config_options[i * ENTRIES_PER_CONFIG_OPTION + 1],
    4262             :                    default_value));
    4263             :     }
    4264             :   }
    4265             : 
    4266             :   // NOTE(lsm): order is important here. SSL certificates must
    4267             :   // be initialized before listening ports. UID must be set last.
    4268           0 :   if (!set_gpass_option(ctx) ||
    4269             : #if !defined(NO_SSL)
    4270             :       !set_ssl_option(ctx) ||
    4271             : #endif
    4272           0 :       !set_ports_option(ctx) ||
    4273             : #if !defined(_WIN32)
    4274           0 :       !set_uid_option(ctx) ||
    4275             : #endif
    4276           0 :       !set_acl_option(ctx)) {
    4277           0 :     free_context(ctx);
    4278           0 :     return NULL;
    4279             :   }
    4280             : 
    4281             : #if !defined(_WIN32) && !defined(__SYMBIAN32__)
    4282             :   // Ignore SIGPIPE signal, so if browser cancels the request, it
    4283             :   // won't kill the whole process.
    4284           0 :   (void) signal(SIGPIPE, SIG_IGN);
    4285             :   // Also ignoring SIGCHLD to let the OS to reap zombies properly.
    4286           0 :   (void) signal(SIGCHLD, SIG_IGN);
    4287             : #endif // !_WIN32
    4288             : 
    4289           0 :   (void) pthread_mutex_init(&ctx->mutex, NULL);
    4290           0 :   (void) pthread_cond_init(&ctx->cond, NULL);
    4291           0 :   (void) pthread_cond_init(&ctx->sq_empty, NULL);
    4292           0 :   (void) pthread_cond_init(&ctx->sq_full, NULL);
    4293             : 
    4294             :   // Start master (listening) thread
    4295           0 :   start_thread(ctx, (mg_thread_func_t) master_thread, ctx);
    4296             : 
    4297             :   // Start worker threads
    4298           0 :   for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {
    4299           0 :     if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) {
    4300           0 :       cry(fc(ctx), "Cannot start worker thread: %d", ERRNO);
    4301             :     } else {
    4302           0 :       ctx->num_threads++;
    4303             :     }
    4304             :   }
    4305             : 
    4306           0 :   return ctx;
    4307             : }

Generated by: LCOV version 1.13