Changeset b5d2d4a in rtems


Ignore:
Timestamp:
Dec 3, 2013, 11:42:26 PM (6 years ago)
Author:
Nick Withers <nick.withers@…>
Branches:
4.11, master
Children:
df217b0b
Parents:
0adc8a7
git-author:
Nick Withers <nick.withers@…> (12/03/13 23:42:26)
git-committer:
Sebastian Huber <sebastian.huber@…> (12/04/13 09:09:16)
Message:

Update to Mongoose 3.9 at the last point before the MIT -> GPL license change

[That is, https://github.com/cesanta/mongoose/commit/04fc209644b414d915c446bb1815b55e9fe63acc. See https://groups.google.com/forum/#!topic/mongoose-users/aafbOnHonkI]

The RTEMS patches described in the following emails and made to the previous Mongoose base have been applied:

...as well as a patch very similar to that discussed at http://forums.bannister.org/ubbthreads.php?ubb=showflat&topic=7600&gonew=1 to provide poll() (which might be able to go away soon, with incoming RTEMS poll() support)

mg_connect(), mg_url_encode() and mg_vprintf() were additionally marked "static" to silence warnings.

mongoose.1 appears to have been removed from the upstream distribution.

Note that the API's changed, for example:

  • A struct mg_callbacks must now be provided to mg_start(). Initialise members to NULL to disable various types of callbacks
  • Callback interfaces have changed significantly in general
  • The short form of options (e.g., "u" instead of "run_as_user") are no longer available (upstream)
  • The "max_request_size" options has been removed
Files:
1 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • cpukit/mghttpd/mongoose.c

    r0adc8a7 rb5d2d4a  
    1 // Copyright (c) 2004-2011 Sergey Lyubka
     1// Copyright (c) 2004-2013 Sergey Lyubka
    22//
    33// Permission is hereby granted, free of charge, to any person obtaining a copy
     
    2020
    2121#if HAVE_CONFIG_H
    22   #include "config.h"
     22#include "config.h"
    2323#endif
    2424
     
    2929
    3030#if defined(_WIN32)
     31#if !defined(_CRT_SECURE_NO_WARNINGS)
    3132#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
     33#endif
    3234#else
     35#ifdef __linux__
    3336#define _XOPEN_SOURCE 600     // For flockfile() on Linux
     37#endif
    3438#define _LARGEFILE_SOURCE     // Enable 64-bit file offsets
    3539#define __STDC_FORMAT_MACROS  // <inttypes.h> wants this for C++
    3640#define __STDC_LIMIT_MACROS   // C++ wants that for INT64_MAX
     41#endif
     42
     43#if defined (_MSC_VER)
     44// conditional expression is constant: introduced by FD_SET(..)
     45#pragma warning (disable : 4127)
     46// non-constant aggregate initializer: issued due to missing C99 support
     47#pragma warning (disable : 4204)
     48#endif
     49
     50// Disable WIN32_LEAN_AND_MEAN.
     51// This makes windows.h always include winsock2.h
     52#ifdef WIN32_LEAN_AND_MEAN
     53#undef WIN32_LEAN_AND_MEAN
    3754#endif
    3855
     
    6279
    6380#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
     81#undef _WIN32_WINNT
    6482#define _WIN32_WINNT 0x0400 // To make it link in VS2005
    6583#include <windows.h>
     
    7492#include <io.h>
    7593#else // _WIN32_WCE
    76 #include <winsock2.h>
    77 #include <ws2tcpip.h>
    7894#define NO_CGI // WinCE has no pipes
    7995
    8096typedef long off_t;
    81 #define BUFSIZ  4096
    8297
    8398#define errno   GetLastError()
     
    98113#define STRX(x) #x
    99114#define STR(x) STRX(x)
    100 #define __func__ "line " STR(__LINE__)
    101 #define strtoull(x, y, z) strtoul(x, y, z)
    102 #define strtoll(x, y, z) strtol(x, y, z)
     115#define __func__ __FILE__ ":" STR(__LINE__)
     116#define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
     117#define strtoll(x, y, z) _atoi64(x)
    103118#else
    104119#define __func__  __FUNCTION__
     
    111126#define SSL_LIB   "ssleay32.dll"
    112127#define CRYPTO_LIB  "libeay32.dll"
    113 #define DIRSEP '\\'
    114 #define IS_DIRSEP_CHAR(c) ((c) == '/' || (c) == '\\')
    115128#define O_NONBLOCK  0
    116129#if !defined(EWOULDBLOCK)
     
    126139#define mg_sleep(x) Sleep(x)
    127140
    128 #define pipe(x) _pipe(x, BUFSIZ, _O_BINARY)
     141#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
     142#ifndef popen
    129143#define popen(x, y) _popen(x, y)
     144#endif
     145#ifndef pclose
    130146#define pclose(x) _pclose(x)
     147#endif
    131148#define close(x) _close(x)
    132149#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
    133150#define RTLD_LAZY  0
    134 #define fseeko(x, y, z) fseek((x), (y), (z))
     151#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
    135152#define fdopen(x, y) _fdopen((x), (y))
    136153#define write(x, y, z) _write((x), (y), (unsigned) z)
     
    138155#define flockfile(x) EnterCriticalSection(&global_log_file_lock)
    139156#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
     157#define sleep(x) Sleep((x) * 1000)
     158#define rmdir(x) _rmdir(x)
     159
     160#if !defined(va_copy)
     161#define va_copy(x, y) x = y
     162#endif // !va_copy MINGW #defines va_copy
    140163
    141164#if !defined(fileno)
     
    148171#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
    149172
    150 struct timespec {
    151   long tv_nsec;
    152   long tv_sec;
    153 };
    154 
    155173static int pthread_mutex_lock(pthread_mutex_t *);
    156174static int pthread_mutex_unlock(pthread_mutex_t *);
    157 static FILE *mg_fopen(const char *path, const char *mode);
     175static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
     176struct file;
     177static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
    158178
    159179#if defined(HAVE_STDINT)
     
    178198} DIR;
    179199
     200
     201// Mark required libraries
     202#ifdef _MSC_VER
     203#pragma comment(lib, "Ws2_32.lib")
     204#endif
     205
    180206#else    // UNIX  specific
    181207#include <sys/wait.h>
    182208#include <sys/socket.h>
    183209#include <sys/select.h>
     210#ifdef HAVE_POLL
     211#include <sys/poll.h>
     212#endif
    184213#include <netinet/in.h>
    185214#include <arpa/inet.h>
     
    207236#endif
    208237#endif
    209 #define DIRSEP   '/'
    210 #define IS_DIRSEP_CHAR(c) ((c) == '/')
    211238#ifndef O_BINARY
    212239#define O_BINARY  0
    213240#endif // O_BINARY
    214241#define closesocket(a) close(a)
    215 #define mg_fopen(x, y) fopen(x, y)
    216242#define mg_mkdir(x, y) mkdir(x, y)
    217243#define mg_remove(x) remove(x)
    218 #define mg_rename(x, y) rename(x, y)
    219244#define mg_sleep(x) usleep((x) * 1000)
    220245#define ERRNO errno
     
    226251#endif // End of Windows and UNIX specific includes
    227252
     253#ifndef HAVE_POLL
     254struct pollfd {
     255  SOCKET fd;
     256  short events;
     257  short revents;
     258};
     259#define POLLIN 1
     260#endif
     261
    228262#include "mongoose.h"
    229263
    230 #define MONGOOSE_VERSION "3.2"
     264#define MONGOOSE_VERSION "3.9"
    231265#define PASSWORDS_FILE_NAME ".htpasswd"
    232266#define CGI_ENVIRONMENT_SIZE 4096
    233267#define MAX_CGI_ENVIR_VARS 64
     268#define MG_BUF_LEN 8192
     269#define MAX_REQUEST_SIZE 16384
    234270#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
    235271
     
    241277#endif // _WIN32
    242278
     279#ifdef DEBUG_TRACE
     280#undef DEBUG_TRACE
     281#define DEBUG_TRACE(x)
     282#else
    243283#if defined(DEBUG)
    244284#define DEBUG_TRACE(x) do { \
     
    255295#define DEBUG_TRACE(x)
    256296#endif // DEBUG
     297#endif // DEBUG_TRACE
    257298
    258299// Darwin prior to 7.0 and Win32 do not have socklen_t
     
    260301typedef int socklen_t;
    261302#endif // NO_SOCKLEN_T
     303#define _DARWIN_UNLIMITED_SELECT
     304
     305#define IP_ADDR_STR_LEN 50  // IPv6 hex string is 46 chars
    262306
    263307#if !defined(MSG_NOSIGNAL)
     
    265309#endif
    266310
    267 typedef void * (*mg_thread_func_t)(void *);
     311#if !defined(SOMAXCONN)
     312#define SOMAXCONN 100
     313#endif
     314
     315#if !defined(PATH_MAX)
     316#define PATH_MAX 4096
     317#endif
     318
     319// Size of the accepted socket queue
     320#if !defined(MGSQLEN)
     321#define MGSQLEN 20
     322#endif
    268323
    269324static const char *http_500_error = "Internal Server Error";
    270325
    271 // Snatched from OpenSSL includes. I put the prototypes here to be independent
    272 // from the OpenSSL source installation. Having this, mongoose + SSL can be
    273 // built on any system with binary SSL libraries installed.
     326#if defined(NO_SSL_DL)
     327#include <openssl/ssl.h>
     328#include <openssl/err.h>
     329#else
     330// SSL loaded dynamically from DLL.
     331// I put the prototypes here to be independent from OpenSSL source installation.
    274332typedef struct ssl_st SSL;
    275333typedef struct ssl_method_st SSL_METHOD;
    276334typedef struct ssl_ctx_st SSL_CTX;
    277335
    278 #define SSL_ERROR_WANT_READ 2
    279 #define SSL_ERROR_WANT_WRITE 3
    280 #define SSL_FILETYPE_PEM 1
    281 #define CRYPTO_LOCK  1
    282 
    283 #if defined(NO_SSL_DL)
    284 extern void SSL_free(SSL *);
    285 extern int SSL_accept(SSL *);
    286 extern int SSL_connect(SSL *);
    287 extern int SSL_read(SSL *, void *, int);
    288 extern int SSL_write(SSL *, const void *, int);
    289 extern int SSL_get_error(const SSL *, int);
    290 extern int SSL_set_fd(SSL *, int);
    291 extern SSL *SSL_new(SSL_CTX *);
    292 extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
    293 extern SSL_METHOD *SSLv23_server_method(void);
    294 extern int SSL_library_init(void);
    295 extern void SSL_load_error_strings(void);
    296 extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
    297 extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
    298 extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
    299 extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
    300 extern void SSL_CTX_free(SSL_CTX *);
    301 extern unsigned long ERR_get_error(void);
    302 extern char *ERR_error_string(unsigned long, char *);
    303 extern int CRYPTO_num_locks(void);
    304 extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
    305 extern void CRYPTO_set_id_callback(unsigned long (*)(void));
    306 #else
    307 // Dynamically loaded SSL functionality
    308336struct ssl_func {
    309337  const char *name;   // SSL function name
     
    332360#define SSL_CTX_use_certificate_chain_file \
    333361  (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
     362#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
     363#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
     364#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
     365#define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
    334366
    335367#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
     
    363395  {"SSL_load_error_strings", NULL},
    364396  {"SSL_CTX_use_certificate_chain_file", NULL},
     397  {"SSLv23_client_method", NULL},
     398  {"SSL_pending", NULL},
     399  {"SSL_CTX_set_verify", NULL},
     400  {"SSL_shutdown",   NULL},
    365401  {NULL,    NULL}
    366402};
     
    400436};
    401437
    402 // Structure used by mg_stat() function. Uses 64 bit file length.
    403 struct mgstat {
    404   int is_directory;  // Directory marker
    405   int64_t size;      // File size
    406   time_t mtime;      // Modification time
     438struct file {
     439  int is_directory;
     440  time_t modification_time;
     441  int64_t size;
     442  FILE *fp;
     443  const char *membuf;   // Non-NULL if file data is in memory
     444  // set to 1 if the content is gzipped
     445  // in which case we need a content-encoding: gzip header
     446  int gzipped;
    407447};
     448#define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
    408449
    409450// Describes listening socket, or socket which was accept()-ed by the master
    410451// thread and queued for future handling by the worker thread.
    411452struct socket {
    412   struct socket *next;  // Linkage
    413453  SOCKET sock;          // Listening socket
    414454  union usa lsa;        // Local socket address
    415455  union usa rsa;        // Remote socket address
    416   int is_ssl;           // Is socket SSL-ed
     456  unsigned is_ssl:1;    // Is port SSL-ed
     457  unsigned ssl_redir:1; // Is port supposed to redirect everything to SSL port
    417458};
    418459
     460// NOTE(lsm): this enum shoulds be in sync with the config_options below.
    419461enum {
    420462  CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
    421   PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, ACCESS_LOG_FILE,
    422   SSL_CHAIN_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
    423   GLOBAL_PASSWORDS_FILE, INDEX_FILES,
    424   ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST, MAX_REQUEST_SIZE,
    425   EXTRA_MIME_TYPES, LISTENING_PORTS,
    426   DOCUMENT_ROOT, SSL_CERTIFICATE, NUM_THREADS, RUN_AS_USER, REWRITE,
     463  PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
     464  ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
     465  GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
     466  EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
     467  NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES, REQUEST_TIMEOUT,
    427468  THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_POLICY,
    428469  NUM_OPTIONS
     
    430471
    431472static const char *config_options[] = {
    432   "C", "cgi_pattern", "**.cgi$|**.pl$|**.php$",
    433   "E", "cgi_environment", NULL,
    434   "G", "put_delete_passwords_file", NULL,
    435   "I", "cgi_interpreter", NULL,
    436   "P", "protect_uri", NULL,
    437   "R", "authentication_domain", "mydomain.com",
    438   "S", "ssi_pattern", "**.shtml$|**.shtm$",
    439   "a", "access_log_file", NULL,
    440   "c", "ssl_chain_file", NULL,
    441   "d", "enable_directory_listing", "yes",
    442   "e", "error_log_file", NULL,
    443   "g", "global_passwords_file", NULL,
    444   "i", "index_files", "index.html,index.htm,index.cgi,index.shtml,index.php",
    445   "k", "enable_keep_alive", "no",
    446   "l", "access_control_list", NULL,
    447   "M", "max_request_size", "16384",
    448   "m", "extra_mime_types", NULL,
    449   "p", "listening_ports", "8080",
    450   "r", "document_root",  ".",
    451   "s", "ssl_certificate", NULL,
    452   "t", "num_threads", "10",
    453   "u", "run_as_user", NULL,
    454   "w", "url_rewrite_patterns", NULL,
    455   "x", "thread_stack_size", NULL,
    456   "y", "thread_priority", NULL,
    457   "z", "thread_policy", NULL,
     473  "cgi_pattern", "**.cgi$|**.pl$|**.php$",
     474  "cgi_environment", NULL,
     475  "put_delete_auth_file", NULL,
     476  "cgi_interpreter", NULL,
     477  "protect_uri", NULL,
     478  "authentication_domain", "mydomain.com",
     479  "ssi_pattern", "**.shtml$|**.shtm$",
     480  "throttle", NULL,
     481  "access_log_file", NULL,
     482  "enable_directory_listing", "yes",
     483  "error_log_file", NULL,
     484  "global_auth_file", NULL,
     485  "index_files",
     486    "index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
     487  "enable_keep_alive", "no",
     488  "access_control_list", NULL,
     489  "extra_mime_types", NULL,
     490  "listening_ports", "8080",
     491  "document_root",  NULL,
     492  "ssl_certificate", NULL,
     493  "num_threads", "50",
     494  "run_as_user", NULL,
     495  "url_rewrite_patterns", NULL,
     496  "hide_files_patterns", NULL,
     497  "request_timeout_ms", "30000",
     498  "thread_stack_size", NULL,
     499  "thread_priority", NULL,
     500  "thread_policy", NULL,
    458501  NULL
    459502};
    460 #define ENTRIES_PER_CONFIG_OPTION 3
    461503
    462504struct mg_context {
    463   volatile int stop_flag;       // Should we stop event loop
    464   SSL_CTX *ssl_ctx;             // SSL context
    465   char *config[NUM_OPTIONS];    // Mongoose configuration parameters
    466   mg_callback_t user_callback;  // User-defined callback function
    467   void *user_data;              // User-defined data
     505  volatile int stop_flag;         // Should we stop event loop
     506  SSL_CTX *ssl_ctx;               // SSL context
     507  char *config[NUM_OPTIONS];      // Mongoose configuration parameters
     508  struct mg_callbacks callbacks;  // User-defined callback function
     509  void *user_data;                // User-defined data
    468510
    469511  struct socket *listening_sockets;
     512  int num_listening_sockets;
    470513
    471514  volatile int num_threads;  // Number of threads
     
    473516  pthread_cond_t  cond;      // Condvar for tracking workers terminations
    474517
    475   struct socket queue[20];   // Accepted sockets
     518  struct socket queue[MGSQLEN];   // Accepted sockets
    476519  volatile int sq_head;      // Head of the socket queue
    477520  volatile int sq_tail;      // Tail of the socket queue
    478   pthread_cond_t sq_full;    // Singaled when socket is produced
     521  pthread_cond_t sq_full;    // Signaled when socket is produced
    479522  pthread_cond_t sq_empty;   // Signaled when socket is consumed
    480523};
     
    484527  struct mg_context *ctx;
    485528  SSL *ssl;                   // SSL descriptor
     529  SSL_CTX *client_ssl_ctx;    // SSL context for client connections
    486530  struct socket client;       // Connected client
    487   time_t birth_time;          // Time connection was accepted
     531  time_t birth_time;          // Time when request was received
    488532  int64_t num_bytes_sent;     // Total bytes sent to client
    489533  int64_t content_len;        // Content-Length header value
    490   int64_t consumed_content;   // How many bytes of content is already read
     534  int64_t consumed_content;   // How many bytes of content have been read
    491535  char *buf;                  // Buffer for received data
    492536  char *path_info;            // PATH_INFO part of the URL
     
    495539  int request_len;            // Size of the request + headers in a buffer
    496540  int data_len;               // Total size of data in a buffer
     541  int status_code;            // HTTP reply status code, e.g. 200
     542  int throttle;               // Throttling, bytes/sec. <= 0 means no throttle
     543  time_t last_throttle_time;  // Last time throttled data was sent
     544  int64_t last_throttle_bytes;// Bytes sent this second
     545};
     546
     547// Directory entry
     548struct de {
     549  struct mg_connection *conn;
     550  char *file_name;
     551  struct file file;
    497552};
    498553
     
    501556}
    502557
    503 static void *call_user(struct mg_connection *conn, enum mg_event event) {
    504   conn->request_info.user_data = conn->ctx->user_data;
    505   return conn->ctx->user_callback == NULL ? NULL :
    506     conn->ctx->user_callback(event, conn, &conn->request_info);
     558static int is_file_in_memory(struct mg_connection *conn, const char *path,
     559                             struct file *filep) {
     560  size_t size = 0;
     561  if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
     562       conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
     563    // NOTE: override filep->size only on success. Otherwise, it might break
     564    // constructs like if (!mg_stat() || !mg_fopen()) ...
     565    filep->size = size;
     566  }
     567  return filep->membuf != NULL;
     568}
     569
     570static int is_file_opened(const struct file *filep) {
     571  return filep->membuf != NULL || filep->fp != NULL;
     572}
     573
     574static int mg_fopen(struct mg_connection *conn, const char *path,
     575                    const char *mode, struct file *filep) {
     576  if (!is_file_in_memory(conn, path, filep)) {
     577#ifdef _WIN32
     578    wchar_t wbuf[PATH_MAX], wmode[20];
     579    to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
     580    MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
     581    filep->fp = _wfopen(wbuf, wmode);
     582#else
     583    filep->fp = fopen(path, mode);
     584#endif
     585  }
     586
     587  return is_file_opened(filep);
     588}
     589
     590static void mg_fclose(struct file *filep) {
     591  if (filep != NULL && filep->fp != NULL) {
     592    fclose(filep->fp);
     593  }
    507594}
    508595
     
    510597  int i;
    511598
    512   for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) {
    513     if (strcmp(config_options[i], name) == 0 ||
    514         strcmp(config_options[i + 1], name) == 0) {
    515       return i / ENTRIES_PER_CONFIG_OPTION;
     599  for (i = 0; config_options[i * 2] != NULL; i++) {
     600    if (strcmp(config_options[i * 2], name) == 0) {
     601      return i;
    516602    }
    517603  }
     
    545631}
    546632
     633static void cry(struct mg_connection *conn,
     634                PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
     635
    547636// Print error message to the opened error log stream.
    548637static void cry(struct mg_connection *conn, const char *fmt, ...) {
    549   char buf[BUFSIZ], src_addr[20];
     638  char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
    550639  va_list ap;
    551640  FILE *fp;
     
    559648  // I suppose this is fine, since function cannot disappear in the
    560649  // same way string option can.
    561   conn->request_info.log_message = buf;
    562   if (call_user(conn, MG_EVENT_LOG) == NULL) {
    563     fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
    564       mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
     650  if (conn->ctx->callbacks.log_message == NULL ||
     651      conn->ctx->callbacks.log_message(conn, buf) == 0) {
     652    fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
     653      fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
    565654
    566655    if (fp != NULL) {
     
    577666      }
    578667
    579       (void) fprintf(fp, "%s", buf);
     668      fprintf(fp, "%s", buf);
    580669      fputc('\n', fp);
    581670      funlockfile(fp);
    582       if (fp != stderr) {
    583         fclose(fp);
    584       }
    585     }
    586   }
    587   conn->request_info.log_message = NULL;
     671      fclose(fp);
     672    }
     673  }
    588674}
    589675
     
    600686}
    601687
     688struct mg_request_info *mg_get_request_info(struct mg_connection *conn) {
     689  return &conn->request_info;
     690}
     691
    602692static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
    603693  for (; *src != '\0' && n > 1; n--) {
     
    646736}
    647737
    648 // Like snprintf(), but never returns negative value, or the value
     738static const char *mg_strcasestr(const char *big_str, const char *small_str) {
     739  int i, big_len = strlen(big_str), small_len = strlen(small_str);
     740
     741  for (i = 0; i <= big_len - small_len; i++) {
     742    if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
     743      return big_str + i;
     744    }
     745  }
     746
     747  return NULL;
     748}
     749
     750// Like snprintf(), but never returns negative value, or a value
    649751// that is larger than a supplied buffer.
    650752// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
     
    673775
    674776static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
     777                       PRINTF_FORMAT_STRING(const char *fmt), ...)
     778  PRINTF_ARGS(4, 5);
     779
     780static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
    675781                       const char *fmt, ...) {
    676782  va_list ap;
     
    685791
    686792// Skip the characters until one of the delimiters characters found.
    687 // 0-terminate resulting word. Skip the delimiter and following whitespaces if any.
     793// 0-terminate resulting word. Skip the delimiter and following whitespaces.
    688794// Advance pointer to buffer to the next word. Return found 0-terminated word.
    689795// Delimiters can be quoted with quotechar.
    690 static char *skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar) {
     796static char *skip_quoted(char **buf, const char *delimiters,
     797                         const char *whitespace, char quotechar) {
    691798  char *p, *begin_word, *end_word, *end_whitespace;
    692799
     
    700807      // If there is anything beyond end_word, copy it
    701808      if (*end_word == '\0') {
     809
    702810        *p = '\0';
    703811        break;
     
    752860}
    753861
    754 // A helper function for traversing comma separated list of values.
    755 // It returns a list pointer shifted to the next value, of NULL if the end
     862// A helper function for traversing a comma separated list of values.
     863// It returns a list pointer shifted to the next value, or NULL if the end
    756864// of the list found.
    757865// Value is stored in val vector. If value has form "x=y", then eq_val
     
    791899}
    792900
     901// Perform case-insensitive match of string against pattern
    793902static int match_prefix(const char *pattern, int pattern_len, const char *str) {
    794903  const char *or_str;
     
    812921      if (pattern[i] == '*') {
    813922        i++;
    814         len = strlen(str + j);
     923        len = (int) strlen(str + j);
    815924      } else {
    816         len = strcspn(str + j, "/");
     925        len = (int) strcspn(str + j, "/");
    817926      }
    818927      if (i == pattern_len) {
     
    823932      } while (res == -1 && len-- > 0);
    824933      return res == -1 ? -1 : j + res + len;
    825     } else if (pattern[i] != str[j]) {
     934    } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
    826935      return -1;
    827936    }
     
    837946  const char *header = mg_get_header(conn, "Connection");
    838947  if (conn->must_close ||
    839       conn->request_info.status_code == 401 ||
     948      conn->status_code == 401 ||
    840949      mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
    841950      (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
     
    850959}
    851960
     961static void send_http_error(struct mg_connection *, int, const char *,
     962                            PRINTF_FORMAT_STRING(const char *fmt), ...)
     963  PRINTF_ARGS(4, 5);
     964
     965
    852966static void send_http_error(struct mg_connection *conn, int status,
    853967                            const char *reason, const char *fmt, ...) {
    854   char buf[BUFSIZ];
     968  char buf[MG_BUF_LEN];
    855969  va_list ap;
    856   int len;
    857 
    858   conn->request_info.status_code = status;
    859 
    860   if (call_user(conn, MG_HTTP_ERROR) == NULL) {
     970  int len = 0;
     971
     972  conn->status_code = status;
     973  if (conn->ctx->callbacks.http_error == NULL ||
     974      conn->ctx->callbacks.http_error(conn, status)) {
    861975    buf[0] = '\0';
    862     len = 0;
    863976
    864977    // Errors 1xx, 204 and 304 MUST NOT send a body
    865978    if (status > 199 && status != 204 && status != 304) {
    866979      len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
    867       cry(conn, "%s", buf);
    868980      buf[len++] = '\n';
    869981
     
    875987
    876988    mg_printf(conn, "HTTP/1.1 %d %s\r\n"
    877               "Content-Type: text/plain\r\n"
    878989              "Content-Length: %d\r\n"
    879990              "Connection: %s\r\n\r\n", status, reason, len,
     
    885996#if defined(_WIN32) && !defined(__SYMBIAN32__)
    886997static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
    887   unused = NULL;
     998  (void) unused;
    888999  *mutex = CreateMutex(NULL, FALSE, NULL);
    8891000  return *mutex == NULL ? -1 : 0;
     
    9031014
    9041015static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
    905   unused = NULL;
     1016  (void) unused;
    9061017  cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
    9071018  cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
     
    9481059// wbuf and wbuf_len is a target buffer and its length.
    9491060static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
    950   char buf[PATH_MAX], buf2[PATH_MAX], *p;
     1061  char buf[PATH_MAX], buf2[PATH_MAX];
    9511062
    9521063  mg_strlcpy(buf, path, sizeof(buf));
    9531064  change_slashes_to_backslashes(buf);
    9541065
    955   // Point p to the end of the file name
    956   p = buf + strlen(buf) - 1;
    957 
    958   // Trim trailing backslash character
    959   while (p > buf && *p == '\\' && p[-1] != ':') {
    960     *p-- = '\0';
    961   }
    962 
    963    // Protect from CGI code disclosure.
    964    // This is very nasty hole. Windows happily opens files with
    965    // some garbage in the end of file name. So fopen("a.cgi    ", "r")
    966    // actually opens "a.cgi", and does not return an error!
    967   if (*p == 0x20 ||               // No space at the end
    968       (*p == 0x2e && p > buf) ||  // No '.' but allow '.' as full path
    969       *p == 0x2b ||               // No '+'
    970       (*p & ~0x7f)) {             // And generally no non-ascii chars
    971     (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
     1066  // Convert to Unicode and back. If doubly-converted string does not
     1067  // match the original, something is fishy, reject.
     1068  memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
     1069  MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
     1070  WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
     1071                      NULL, NULL);
     1072  if (strcmp(buf, buf2) != 0) {
    9721073    wbuf[0] = L'\0';
    973   } else {
    974     // Convert to Unicode and back. If doubly-converted string does not
    975     // match the original, something is fishy, reject.
    976     memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
    977     MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
    978     WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
    979                         NULL, NULL);
    980     if (strcmp(buf, buf2) != 0) {
    981       wbuf[0] = L'\0';
    982     }
    9831074  }
    9841075}
     
    10401131#endif
    10411132
    1042 static int mg_rename(const char* oldname, const char* newname) {
    1043   wchar_t woldbuf[PATH_MAX];
    1044   wchar_t wnewbuf[PATH_MAX];
    1045 
    1046   to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
    1047   to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
    1048 
    1049   return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
    1050 }
    1051 
    1052 
    1053 static FILE *mg_fopen(const char *path, const char *mode) {
    1054   wchar_t wbuf[PATH_MAX], wmode[20];
    1055 
    1056   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1057   MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
    1058 
    1059   return _wfopen(wbuf, wmode);
    1060 }
    1061 
    1062 static int mg_stat(const char *path, struct mgstat *stp) {
    1063   int ok = -1; // Error
     1133// Windows happily opens files with some garbage at the end of file name.
     1134// For example, fopen("a.cgi    ", "r") on Windows successfully opens
     1135// "a.cgi", despite one would expect an error back.
     1136// This function returns non-0 if path ends with some garbage.
     1137static int path_cannot_disclose_cgi(const char *path) {
     1138  static const char *allowed_last_characters = "_-";
     1139  int last = path[strlen(path) - 1];
     1140  return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
     1141}
     1142
     1143static int mg_stat(struct mg_connection *conn, const char *path,
     1144                   struct file *filep) {
    10641145  wchar_t wbuf[PATH_MAX];
    10651146  WIN32_FILE_ATTRIBUTE_DATA info;
    10661147
    1067   to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
    1068 
    1069   if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
    1070     stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
    1071     stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
    1072                                info.ftLastWriteTime.dwHighDateTime);
    1073     stp->is_directory =
    1074       info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
    1075     ok = 0;  // Success
    1076   }
    1077 
    1078   return ok;
     1148  if (!is_file_in_memory(conn, path, filep)) {
     1149    to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
     1150    if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
     1151      filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
     1152      filep->modification_time = SYS2UNIX_TIME(
     1153          info.ftLastWriteTime.dwLowDateTime,
     1154          info.ftLastWriteTime.dwHighDateTime);
     1155      filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
     1156      // If file name is fishy, reset the file structure and return error.
     1157      // Note it is important to reset, not just return the error, cause
     1158      // functions like is_file_opened() check the struct.
     1159      if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
     1160        memset(filep, 0, sizeof(*filep));
     1161      }
     1162    }
     1163  }
     1164
     1165  return filep->membuf != NULL || filep->modification_time != 0;
    10791166}
    10801167
     
    10891176  wchar_t wbuf[PATH_MAX];
    10901177
    1091   mode = 0; // Unused
     1178  (void) mode;
    10921179  mg_strlcpy(buf, path, sizeof(buf));
    10931180  change_slashes_to_backslashes(buf);
    10941181
    1095   (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
     1182  (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
    10961183
    10971184  return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
     
    11661253}
    11671254
    1168 #define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
    1169 
    1170 static int start_thread(struct mg_context *ctx, mg_thread_func_t f, void *p) {
    1171   return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
     1255static void set_close_on_exec(SOCKET sock) {
     1256  (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
     1257}
     1258
     1259int mg_start_thread(mg_thread_func_t f, void *p) {
     1260  return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
    11721261}
    11731262
    11741263static HANDLE dlopen(const char *dll_name, int flags) {
    11751264  wchar_t wbuf[PATH_MAX];
    1176   flags = 0; // Unused
     1265  (void) flags;
    11771266  to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
    11781267  return LoadLibraryW(wbuf);
     
    11871276}
    11881277
     1278static void trim_trailing_whitespaces(char *s) {
     1279  char *e = s + strlen(s) - 1;
     1280  while (e > s && isspace(* (unsigned char *) e)) {
     1281    *e-- = '\0';
     1282  }
     1283}
     1284
    11891285static pid_t spawn_process(struct mg_connection *conn, const char *prog,
    1190                            char *envblk, char *envp[], int fd_stdin,
    1191                            int fd_stdout, const char *dir) {
     1286                           char *envblk, char *envp[], int fdin,
     1287                           int fdout, const char *dir) {
    11921288  HANDLE me;
    1193   char *p, *interp, cmdline[PATH_MAX], buf[PATH_MAX];
    1194   FILE *fp;
    1195   STARTUPINFOA si = { sizeof(si) };
     1289  char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
     1290       cmdline[PATH_MAX], buf[PATH_MAX];
     1291  struct file file = STRUCT_FILE_INITIALIZER;
     1292  STARTUPINFOA si;
    11961293  PROCESS_INFORMATION pi = { 0 };
    11971294
    1198   envp = NULL; // Unused
     1295  (void) envp;
     1296
     1297  memset(&si, 0, sizeof(si));
     1298  si.cb = sizeof(si);
    11991299
    12001300  // TODO(lsm): redirect CGI errors to the error log file
     
    12031303
    12041304  me = GetCurrentProcess();
    1205   (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
    1206       &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    1207   (void) DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
    1208       &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
     1305  DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
     1306                  &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
     1307  DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
     1308                  &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
    12091309
    12101310  // If CGI file is a script, try to read the interpreter line
    12111311  interp = conn->ctx->config[CGI_INTERPRETER];
    12121312  if (interp == NULL) {
    1213     buf[2] = '\0';
    1214     mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%c%s", dir, DIRSEP, prog);
    1215     if ((fp = fopen(cmdline, "r")) != NULL) {
    1216       (void) fgets(buf, sizeof(buf), fp);
    1217       if (buf[0] != '#' || buf[1] != '!') {
    1218         // First line does not start with "#!". Do not set interpreter.
    1219         buf[2] = '\0';
    1220       } else {
    1221         // Trim whitespaces in interpreter name
    1222         for (p = &buf[strlen(buf) - 1]; p > buf && isspace(*p); p--) {
    1223           *p = '\0';
    1224         }
    1225       }
    1226       (void) fclose(fp);
     1313    buf[0] = buf[1] = '\0';
     1314
     1315    // Read the first line of the script into the buffer
     1316    snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
     1317    if (mg_fopen(conn, cmdline, "r", &file)) {
     1318      p = (char *) file.membuf;
     1319      mg_fgets(buf, sizeof(buf), &file, &p);
     1320      mg_fclose(&file);
     1321      buf[sizeof(buf) - 1] = '\0';
     1322    }
     1323
     1324    if (buf[0] == '#' && buf[1] == '!') {
     1325      trim_trailing_whitespaces(buf + 2);
     1326    } else {
     1327      buf[2] = '\0';
    12271328    }
    12281329    interp = buf + 2;
    12291330  }
    12301331
    1231   (void) mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s%c%s",
    1232                      interp, interp[0] == '\0' ? "" : " ", dir, DIRSEP, prog);
     1332  if (interp[0] != '\0') {
     1333    GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
     1334    interp = full_interp;
     1335  }
     1336  GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
     1337
     1338  mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"",
     1339              interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
    12331340
    12341341  DEBUG_TRACE(("Running [%s]", cmdline));
    12351342  if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
    1236         CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
    1237     cry(conn, "%s: CreateProcess(%s): %d",
     1343        CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
     1344    cry(conn, "%s: CreateProcess(%s): %ld",
    12381345        __func__, cmdline, ERRNO);
    12391346    pi.hProcess = (pid_t) -1;
    1240   } else {
    1241     (void) close(fd_stdin);
    1242     (void) close(fd_stdout);
    12431347  }
    12441348
     
    12571361
    12581362#else
    1259 static int mg_stat(const char *path, struct mgstat *stp) {
     1363static int mg_stat(struct mg_connection *conn, const char *path,
     1364                   struct file *filep) {
    12601365  struct stat st;
    1261   int ok;
    1262 
    1263   if (stat(path, &st) == 0) {
    1264     ok = 0;
    1265     stp->size = st.st_size;
    1266     stp->mtime = st.st_mtime;
    1267     stp->is_directory = S_ISDIR(st.st_mode);
     1366
     1367  if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) {
     1368    filep->size = st.st_size;
     1369    filep->modification_time = st.st_mtime;
     1370    filep->is_directory = S_ISDIR(st.st_mode);
    12681371  } else {
    1269     ok = -1;
    1270   }
    1271 
    1272   return ok;
     1372    filep->modification_time = (time_t) 0;
     1373  }
     1374
     1375  return filep->membuf != NULL || filep->modification_time != (time_t) 0;
    12731376}
    12741377
    12751378static void set_close_on_exec(int fd) {
    1276   (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
    1277 }
    1278 
    1279 static int start_thread(struct mg_context *ctx, mg_thread_func_t func,
    1280                         void *param) {
     1379  fcntl(fd, F_SETFD, FD_CLOEXEC);
     1380}
     1381
     1382int mg_start_thread(mg_thread_func_t func, void *param) {
    12811383  pthread_t thread_id;
    12821384  pthread_attr_t attr;
    1283   int retval;
     1385  int result;
     1386  struct mg_context* ctx = param;
    12841387  char* stacksize = ctx->config[THREAD_STACK_SIZE];
    12851388  char* priority = ctx->config[THREAD_PRIORITY];
     
    12891392  (void) pthread_attr_init(&attr);
    12901393  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    1291   // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
    1292   // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
     1394
     1395#if USE_STACK_SIZE > 1
     1396  // Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384; Can be overridden
     1397  if (stacksize == NULL)
     1398    (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
     1399#endif
    12931400
    12941401  if (stacksize != NULL) {
     
    13381445  }
    13391446
    1340   if ((retval = pthread_create(&thread_id, &attr, func, param)) != 0) {
    1341     cry(fc(ctx), "%s: %s", __func__, strerror(retval));
    1342   }
    1343 
    1344   return retval;
     1447  result = pthread_create(&thread_id, &attr, func, param);
     1448  pthread_attr_destroy(&attr);
     1449
     1450  return result;
    13451451}
    13461452
    13471453#ifndef NO_CGI
    13481454static pid_t spawn_process(struct mg_connection *conn, const char *prog,
    1349                            char *envblk, char *envp[], int fd_stdin,
    1350                            int fd_stdout, const char *dir) {
     1455                           char *envblk, char *envp[], int fdin,
     1456                           int fdout, const char *dir) {
    13511457  pid_t pid;
    13521458  const char *interp;
    13531459
    1354   envblk = NULL; // Unused
     1460  (void) envblk;
    13551461
    13561462  if ((pid = fork()) == -1) {
     
    13611467    if (chdir(dir) != 0) {
    13621468      cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
    1363     } else if (dup2(fd_stdin, 0) == -1) {
    1364       cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
    1365     } else if (dup2(fd_stdout, 1) == -1) {
    1366       cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
     1469    } else if (dup2(fdin, 0) == -1) {
     1470      cry(conn, "%s: dup2(%d, 0): %s", __func__, fdin, strerror(ERRNO));
     1471    } else if (dup2(fdout, 1) == -1) {
     1472      cry(conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO));
    13671473    } else {
    1368       (void) dup2(fd_stdout, 2);
    1369       (void) close(fd_stdin);
    1370       (void) close(fd_stdout);
    1371 
    1372       // Execute CGI program. No need to lock: new process
     1474      // Not redirecting stderr to stdout, to avoid output being littered
     1475      // with the error messages.
     1476      (void) close(fdin);
     1477      (void) close(fdout);
     1478
     1479      // After exec, all signal handlers are restored to their default values,
     1480      // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's
     1481      // implementation, SIGCHLD's handler will leave unchanged after exec
     1482      // if it was set to be ignored. Restore it to default action.
     1483      signal(SIGCHLD, SIG_DFL);
     1484
    13731485      interp = conn->ctx->config[CGI_INTERPRETER];
    13741486      if (interp == NULL) {
     
    13821494    }
    13831495    exit(EXIT_FAILURE);
    1384   } else {
    1385     // Parent. Close stdio descriptors
    1386     (void) close(fd_stdin);
    1387     (void) close(fd_stdout);
    13881496  }
    13891497
     
    14011509}
    14021510#endif // _WIN32
     1511
     1512#ifndef HAVE_POLL
     1513static int poll(struct pollfd *pfd, int n, int milliseconds) {
     1514  struct timeval tv;
     1515  fd_set set;
     1516  int i, result;
     1517  SOCKET maxfd = 0;
     1518
     1519  tv.tv_sec = milliseconds / 1000;
     1520  tv.tv_usec = (milliseconds % 1000) * 1000;
     1521  FD_ZERO(&set);
     1522
     1523  for (i = 0; i < n; i++) {
     1524    FD_SET((SOCKET) pfd[i].fd, &set);
     1525    pfd[i].revents = 0;
     1526
     1527    if (pfd[i].fd > maxfd) {
     1528        maxfd = pfd[i].fd;
     1529    }
     1530  }
     1531
     1532  if ((result = select(maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
     1533    for (i = 0; i < n; i++) {
     1534      if (FD_ISSET(pfd[i].fd, &set)) {
     1535        pfd[i].revents = POLLIN;
     1536      }
     1537    }
     1538  }
     1539
     1540  return result;
     1541}
     1542#endif // HAVE_POLL
    14031543
    14041544// Write data to the IO channel - opened file descriptor, socket or SSL
     
    14091549  int n, k;
    14101550
     1551  (void) ssl;  // Get rid of warning
    14111552  sent = 0;
    14121553  while (sent < len) {
     
    14151556    k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
    14161557
     1558#ifndef NO_SSL
    14171559    if (ssl != NULL) {
    14181560      n = SSL_write(ssl, buf + sent, k);
    1419     } else if (fp != NULL) {
    1420       n = fwrite(buf + sent, 1, (size_t) k, fp);
     1561    } else
     1562#endif
     1563      if (fp != NULL) {
     1564      n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
    14211565      if (ferror(fp))
    14221566        n = -1;
     
    14251569    }
    14261570
    1427     if (n < 0)
     1571    if (n <= 0)
    14281572      break;
    14291573
     
    14351579
    14361580// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
    1437 // Return number of bytes read.
    1438 static int pull(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int len) {
     1581// Return negative value on error, or number of bytes read on success.
     1582static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
    14391583  int nread;
    14401584
    1441   if (ssl != NULL) {
    1442     nread = SSL_read(ssl, buf, len);
    1443   } else if (fp != NULL) {
     1585  if (fp != NULL) {
    14441586    // Use read() instead of fread(), because if we're reading from the CGI
    14451587    // pipe, fread() may block until IO buffer is filled up. We cannot afford
    14461588    // to block and must pass all read bytes immediately to the client.
    14471589    nread = read(fileno(fp), buf, (size_t) len);
    1448     if (ferror(fp))
    1449       nread = -1;
     1590#ifndef NO_SSL
     1591  } else if (conn->ssl != NULL) {
     1592    nread = SSL_read(conn->ssl, buf, len);
     1593#endif
    14501594  } else {
    1451     nread = recv(sock, buf, (size_t) len, 0);
     1595    nread = recv(conn->client.sock, buf, (size_t) len, 0);
     1596  }
     1597
     1598  return conn->ctx->stop_flag ? -1 : nread;
     1599}
     1600
     1601static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len) {
     1602  int n, nread = 0;
     1603
     1604  while (len > 0 && conn->ctx->stop_flag == 0) {
     1605    n = pull(fp, conn, buf + nread, len);
     1606    if (n < 0) {
     1607      nread = n;  // Propagate the error
     1608      break;
     1609    } else if (n == 0) {
     1610      break;  // No more data to read
     1611    } else {
     1612      conn->consumed_content += n;
     1613      nread += n;
     1614      len -= n;
     1615    }
    14521616  }
    14531617
     
    14571621int mg_read(struct mg_connection *conn, void *buf, size_t len) {
    14581622  int n, buffered_len, nread;
    1459   const char *buffered;
    1460 
    1461   assert((conn->content_len == -1 && conn->consumed_content == 0) ||
    1462          conn->consumed_content <= conn->content_len);
    1463   DEBUG_TRACE(("%p %zu %lld %lld", buf, len,
    1464                conn->content_len, conn->consumed_content));
     1623  const char *body;
     1624
     1625  // If Content-Length is not set, read until socket is closed
     1626  if (conn->consumed_content == 0 && conn->content_len == 0) {
     1627    conn->content_len = INT64_MAX;
     1628    conn->must_close = 1;
     1629  }
     1630
    14651631  nread = 0;
    14661632  if (conn->consumed_content < conn->content_len) {
    1467 
    14681633    // Adjust number of bytes to read.
    14691634    int64_t to_read = conn->content_len - conn->consumed_content;
    14701635    if (to_read < (int64_t) len) {
    1471       len = (int) to_read;
    1472     }
    1473 
    1474     // How many bytes of data we have buffered in the request buffer?
    1475     buffered = conn->buf + conn->request_len + conn->consumed_content;
    1476     buffered_len = conn->data_len - conn->request_len;
    1477     assert(buffered_len >= 0);
    1478 
    1479     // Return buffered data back if we haven't done that yet.
    1480     if (conn->consumed_content < (int64_t) buffered_len) {
    1481       buffered_len -= (int) conn->consumed_content;
     1636      len = (size_t) to_read;
     1637    }
     1638
     1639    // Return buffered data
     1640    body = conn->buf + conn->request_len + conn->consumed_content;
     1641    buffered_len = &conn->buf[conn->data_len] - body;
     1642    if (buffered_len > 0) {
    14821643      if (len < (size_t) buffered_len) {
    1483         buffered_len = len;
     1644        buffered_len = (int) len;
    14841645      }
    1485       memcpy(buf, buffered, (size_t)buffered_len);
     1646      memcpy(buf, body, (size_t) buffered_len);
    14861647      len -= buffered_len;
     1648      conn->consumed_content += buffered_len;
     1649      nread += buffered_len;
    14871650      buf = (char *) buf + buffered_len;
    1488       conn->consumed_content += buffered_len;
    1489       nread = buffered_len;
    14901651    }
    14911652
    14921653    // We have returned all buffered data. Read new data from the remote socket.
    1493     while (len > 0) {
    1494       n = pull(NULL, conn->client.sock, conn->ssl, (char *) buf, (int) len);
    1495       if (n <= 0) {
    1496         break;
     1654    n = pull_all(NULL, conn, (char *) buf, (int) len);
     1655    nread = n >= 0 ? nread + n : n;
     1656  }
     1657  return nread;
     1658}
     1659
     1660int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
     1661  time_t now;
     1662  int64_t n, total, allowed;
     1663
     1664  if (conn->throttle > 0) {
     1665    if ((now = time(NULL)) != conn->last_throttle_time) {
     1666      conn->last_throttle_time = now;
     1667      conn->last_throttle_bytes = 0;
     1668    }
     1669    allowed = conn->throttle - conn->last_throttle_bytes;
     1670    if (allowed > (int64_t) len) {
     1671      allowed = len;
     1672    }
     1673    if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
     1674                      (int64_t) allowed)) == allowed) {
     1675      buf = (char *) buf + total;
     1676      conn->last_throttle_bytes += total;
     1677      while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
     1678        allowed = conn->throttle > (int64_t) len - total ?
     1679          (int64_t) len - total : conn->throttle;
     1680        if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
     1681                      (int64_t) allowed)) != allowed) {
     1682          break;
     1683        }
     1684        sleep(1);
     1685        conn->last_throttle_bytes = allowed;
     1686        conn->last_throttle_time = time(NULL);
     1687        buf = (char *) buf + n;
     1688        total += n;
    14971689      }
    1498       buf = (char *) buf + n;
    1499       conn->consumed_content += n;
    1500       nread += n;
    1501       len -= n;
    1502     }
    1503   }
    1504   return nread;
    1505 }
    1506 
    1507 int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
    1508   return (int) push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
    1509                     (int64_t) len);
     1690    }
     1691  } else {
     1692    total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
     1693                 (int64_t) len);
     1694  }
     1695  return (int) total;
     1696}
     1697
     1698// Alternative alloc_vprintf() for non-compliant C runtimes
     1699static int alloc_vprintf2(char **buf, const char *fmt, va_list ap) {
     1700  va_list ap_copy;
     1701  int size = MG_BUF_LEN;
     1702  int len = -1;
     1703
     1704  *buf = NULL;
     1705  while (len == -1) {
     1706    if (*buf) free(*buf);
     1707    *buf = malloc(size *= 4);
     1708    if (!*buf) break;
     1709    va_copy(ap_copy, ap);
     1710    len = vsnprintf(*buf, size, fmt, ap_copy);
     1711  }
     1712
     1713  return len;
     1714}
     1715
     1716// Print message to buffer. If buffer is large enough to hold the message,
     1717// return buffer. If buffer is to small, allocate large enough buffer on heap,
     1718// and return allocated buffer.
     1719static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
     1720  va_list ap_copy;
     1721  int len;
     1722
     1723  // Windows is not standard-compliant, and vsnprintf() returns -1 if
     1724  // buffer is too small. Also, older versions of msvcrt.dll do not have
     1725  // _vscprintf().  However, if size is 0, vsnprintf() behaves correctly.
     1726  // Therefore, we make two passes: on first pass, get required message length.
     1727  // On second pass, actually print the message.
     1728  va_copy(ap_copy, ap);
     1729  len = vsnprintf(NULL, 0, fmt, ap_copy);
     1730
     1731  if (len < 0) {
     1732    // C runtime is not standard compliant, vsnprintf() returned -1.
     1733    // Switch to alternative code path that uses incremental allocations.
     1734    va_copy(ap_copy, ap);
     1735    len = alloc_vprintf2(buf, fmt, ap);
     1736  } else if (len > (int) size &&
     1737      (size = len + 1) > 0 &&
     1738      (*buf = (char *) malloc(size)) == NULL) {
     1739    len = -1;  // Allocation failed, mark failure
     1740  } else {
     1741    va_copy(ap_copy, ap);
     1742    vsnprintf(*buf, size, fmt, ap_copy);
     1743  }
     1744
     1745  return len;
     1746}
     1747
     1748static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap) {
     1749  char mem[MG_BUF_LEN], *buf = mem;
     1750  int len;
     1751
     1752  if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
     1753    len = mg_write(conn, buf, (size_t) len);
     1754  }
     1755  if (buf != mem && buf != NULL) {
     1756    free(buf);
     1757  }
     1758
     1759  return len;
    15101760}
    15111761
    15121762int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
    1513   char buf[BUFSIZ];
    1514   int len;
    15151763  va_list ap;
    1516 
    15171764  va_start(ap, fmt);
    1518   len = mg_vsnprintf(conn, buf, sizeof(buf), fmt, ap);
    1519   va_end(ap);
    1520 
    1521   return mg_write(conn, buf, (size_t)len);
    1522 }
    1523 
    1524 // URL-decode input buffer into destination buffer.
    1525 // 0-terminate the destination buffer. Return the length of decoded data.
    1526 // form-url-encoded data differs from URI encoding in a way that it
    1527 // uses '+' as character for space, see RFC 1866 section 8.2.1
    1528 // http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
    1529 static size_t url_decode(const char *src, size_t src_len, char *dst,
    1530                          size_t dst_len, int is_form_url_encoded) {
    1531   size_t i, j;
    1532   int a, b;
     1765  return mg_vprintf(conn, fmt, ap);
     1766}
     1767
     1768int mg_url_decode(const char *src, int src_len, char *dst,
     1769                  int dst_len, int is_form_url_encoded) {
     1770  int i, j, a, b;
    15331771#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
    15341772
    15351773  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
    1536     if (src[i] == '%' &&
     1774    if (src[i] == '%' && i < src_len - 2 &&
    15371775        isxdigit(* (const unsigned char *) (src + i + 1)) &&
    15381776        isxdigit(* (const unsigned char *) (src + i + 2))) {
     
    15501788  dst[j] = '\0'; // Null-terminate the destination
    15511789
    1552   return j;
    1553 }
    1554 
    1555 // Scan given buffer and fetch the value of the given variable.
    1556 // It can be specified in query string, or in the POST data.
    1557 // Return NULL if the variable not found, or allocated 0-terminated value.
    1558 // It is caller's responsibility to free the returned value.
    1559 int mg_get_var(const char *buf, size_t buf_len, const char *name,
     1790  return i >= src_len ? j : -1;
     1791}
     1792
     1793int mg_get_var(const char *data, size_t data_len, const char *name,
    15601794               char *dst, size_t dst_len) {
    15611795  const char *p, *e, *s;
    1562   size_t name_len, len;
    1563 
    1564   name_len = strlen(name);
    1565   e = buf + buf_len;
    1566   len = -1;
    1567   dst[0] = '\0';
    1568 
    1569   // buf is "var1=val1&var2=val2...". Find variable first
    1570   for (p = buf; p != NULL && p + name_len < e; p++) {
    1571     if ((p == buf || p[-1] == '&') && p[name_len] == '=' &&
    1572         !mg_strncasecmp(name, p, name_len)) {
    1573 
    1574       // Point p to variable value
    1575       p += name_len + 1;
    1576 
    1577       // Point s to the end of the value
    1578       s = (const char *) memchr(p, '&', (size_t)(e - p));
    1579       if (s == NULL) {
    1580         s = e;
     1796  size_t name_len;
     1797  int len;
     1798
     1799  if (dst == NULL || dst_len == 0) {
     1800    len = -2;
     1801  } else if (data == NULL || name == NULL || data_len == 0) {
     1802    len = -1;
     1803    dst[0] = '\0';
     1804  } else {
     1805    name_len = strlen(name);
     1806    e = data + data_len;
     1807    len = -1;
     1808    dst[0] = '\0';
     1809
     1810    // data is "var1=val1&var2=val2...". Find variable first
     1811    for (p = data; p + name_len < e; p++) {
     1812      if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
     1813          !mg_strncasecmp(name, p, name_len)) {
     1814
     1815        // Point p to variable value
     1816        p += name_len + 1;
     1817
     1818        // Point s to the end of the value
     1819        s = (const char *) memchr(p, '&', (size_t)(e - p));
     1820        if (s == NULL) {
     1821          s = e;
     1822        }
     1823        assert(s >= p);
     1824
     1825        // Decode variable into destination buffer
     1826        len = mg_url_decode(p, (size_t)(s - p), dst, dst_len, 1);
     1827
     1828        // Redirect error code from -1 to -2 (destination buffer too small).
     1829        if (len == -1) {
     1830          len = -2;
     1831        }
     1832        break;
    15811833      }
    1582       assert(s >= p);
    1583 
    1584       // Decode variable into destination buffer
    1585       if ((size_t) (s - p) < dst_len) {
    1586         len = url_decode(p, (size_t)(s - p), dst, dst_len, 1);
    1587       }
    1588       break;
    15891834    }
    15901835  }
     
    15931838}
    15941839
    1595 int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
     1840int mg_get_cookie(const char *cookie_header, const char *var_name,
    15961841                  char *dst, size_t dst_size) {
    15971842  const char *s, *p, *end;
    15981843  int name_len, len = -1;
    15991844
    1600   dst[0] = '\0';
    1601   if ((s = mg_get_header(conn, "Cookie")) == NULL) {
    1602     return 0;
    1603   }
    1604 
    1605   name_len = strlen(cookie_name);
    1606   end = s + strlen(s);
    1607 
    1608   for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
    1609     if (s[name_len] == '=') {
    1610       s += name_len + 1;
    1611       if ((p = strchr(s, ' ')) == NULL)
    1612         p = end;
    1613       if (p[-1] == ';')
    1614         p--;
    1615       if (*s == '"' && p[-1] == '"' && p > s + 1) {
    1616         s++;
    1617         p--;
     1845  if (dst == NULL || dst_size == 0) {
     1846    len = -2;
     1847  } else if (var_name == NULL || (s = cookie_header) == NULL) {
     1848    len = -1;
     1849    dst[0] = '\0';
     1850  } else {
     1851    name_len = (int) strlen(var_name);
     1852    end = s + strlen(s);
     1853    dst[0] = '\0';
     1854
     1855    for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
     1856      if (s[name_len] == '=') {
     1857        s += name_len + 1;
     1858        if ((p = strchr(s, ' ')) == NULL)
     1859          p = end;
     1860        if (p[-1] == ';')
     1861          p--;
     1862        if (*s == '"' && p[-1] == '"' && p > s + 1) {
     1863          s++;
     1864          p--;
     1865        }
     1866        if ((size_t) (p - s) < dst_size) {
     1867          len = p - s;
     1868          mg_strlcpy(dst, s, (size_t) len + 1);
     1869        } else {
     1870          len = -3;
     1871        }
     1872        break;
    16181873      }
    1619       if ((size_t) (p - s) < dst_size) {
    1620         len = (p - s) + 1;
    1621         mg_strlcpy(dst, s, (size_t)len);
    1622       }
    1623       break;
    1624     }
    1625 
     1874    }
     1875  }
    16261876  return len;
    16271877}
    16281878
    1629 static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
    1630                                     size_t buf_len, struct mgstat *st) {
     1879static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
     1880                                     size_t buf_len, struct file *filep) {
    16311881  struct vec a, b;
    1632   const char *rewrite, *uri = conn->request_info.uri;
     1882  const char *rewrite, *uri = conn->request_info.uri,
     1883        *root = conn->ctx->config[DOCUMENT_ROOT];
    16331884  char *p;
    1634   int match_len, stat_result;
    1635 
    1636   buf_len--;  // This is because memmove() for PATH_INFO may shift part
    1637               // of the path one byte on the right.
    1638   mg_snprintf(conn, buf, buf_len, "%s%s", conn->ctx->config[DOCUMENT_ROOT],
    1639               uri);
     1885  int match_len;
     1886  char gz_path[PATH_MAX];
     1887  char const* accept_encoding;
     1888
     1889  // Using buf_len - 1 because memmove() for PATH_INFO may shift part
     1890  // of the path one byte on the right.
     1891  // If document_root is NULL, leave the file empty.
     1892  mg_snprintf(conn, buf, buf_len - 1, "%s%s",
     1893              root == NULL ? "" : root,
     1894              root == NULL ? "" : uri);
    16401895
    16411896  rewrite = conn->ctx->config[REWRITE];
    16421897  while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
    16431898    if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
    1644       mg_snprintf(conn, buf, buf_len, "%.*s%s", b.len, b.ptr, uri + match_len);
     1899      mg_snprintf(conn, buf, buf_len - 1, "%.*s%s", (int) b.len, b.ptr,
     1900                  uri + match_len);
    16451901      break;
    16461902    }
    16471903  }
    16481904
    1649 #if defined(_WIN32) && !defined(__SYMBIAN32__)
    1650   //change_slashes_to_backslashes(buf);
    1651 #endif // _WIN32
    1652 
    1653   if ((stat_result = mg_stat(buf, st)) != 0) {
    1654     // Support PATH_INFO for CGI scripts.
    1655     for (p = buf + strlen(buf); p > buf + 1; p--) {
    1656       if (*p == '/') {
    1657         *p = '\0';
    1658         if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
    1659                          strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
    1660             (stat_result = mg_stat(buf, st)) == 0) {
    1661           // Shift PATH_INFO block one character right, e.g.
    1662           //  "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
    1663           // conn->path_info is pointing to the local variable "path" declared
    1664           // in handle_request(), so PATH_INFO not valid after
    1665           // handle_request returns.
    1666           conn->path_info = p + 1;
    1667           memmove(p + 2, p + 1, strlen(p + 1) + 1);  // +1 is for trailing \0
    1668           p[1] = '/';
    1669           break;
    1670         } else {
    1671           *p = '/';
    1672           stat_result = -1;
    1673         }
     1905  if (mg_stat(conn, buf, filep)) return;
     1906
     1907  // if we can't find the actual file, look for the file
     1908  // with the same name but a .gz extension. If we find it,
     1909  // use that and set the gzipped flag in the file struct
     1910  // to indicate that the response need to have the content-
     1911  // encoding: gzip header
     1912  // we can only do this if the browser declares support
     1913  if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
     1914    if (strstr(accept_encoding,"gzip") != NULL) {
     1915      snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
     1916      if (mg_stat(conn, gz_path, filep)) {
     1917        filep->gzipped = 1;
     1918        return;
    16741919      }
    16751920    }
    16761921  }
    16771922
    1678   return stat_result;
    1679 }
    1680 
    1681 static int sslize(struct mg_connection *conn, int (*func)(SSL *)) {
    1682   return (conn->ssl = SSL_new(conn->ctx->ssl_ctx)) != NULL &&
    1683     SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
    1684     func(conn->ssl) == 1;
     1923  // Support PATH_INFO for CGI scripts.
     1924  for (p = buf + strlen(buf); p > buf + 1; p--) {
     1925    if (*p == '/') {
     1926      *p = '\0';
     1927      if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
     1928                       strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
     1929          mg_stat(conn, buf, filep)) {
     1930        // Shift PATH_INFO block one character right, e.g.
     1931        //  "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
     1932        // conn->path_info is pointing to the local variable "path" declared
     1933        // in handle_request(), so PATH_INFO is not valid after
     1934        // handle_request returns.
     1935        conn->path_info = p + 1;
     1936        memmove(p + 2, p + 1, strlen(p + 1) + 1);  // +1 is for trailing \0
     1937        p[1] = '/';
     1938        break;
     1939      } else {
     1940        *p = '/';
     1941      }
     1942    }
     1943  }
    16851944}
    16861945
     
    16931952  int len = 0;
    16941953
    1695   DEBUG_TRACE(("buf: %p, len: %d", buf, buflen));
    16961954  for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
    16971955    // Control characters are not allowed but >=128 is.
     
    16991957        *s != '\n' && * (const unsigned char *) s < 128) {
    17001958      len = -1;
     1959      break;  // [i_a] abort scan as soon as one malformed character is found;
     1960              // don't let subsequent \r\n\r\n win us over anyhow
    17011961    } else if (s[0] == '\n' && s[1] == '\n') {
    17021962      len = (int) (s - buf) + 2;
     
    17181978
    17191979  return -1;
     1980}
     1981
     1982static int num_leap_years(int year) {
     1983  return year / 4 - year / 100 + year / 400;
    17201984}
    17211985
     
    17392003      year > 1970 &&
    17402004      (month = get_month_index(month_str)) != -1) {
     2005    leap_days = num_leap_years(year) - num_leap_years(1970);
    17412006    year -= 1970;
    1742     leap_days = year / 4 - year / 100 + year / 400;
    17432007    days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
    17442008    result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
     
    17552019  while (*s != '\0') {
    17562020    *p++ = *s++;
    1757     if (IS_DIRSEP_CHAR(s[-1])) {
    1758       // Skip all following slashes and backslashes
    1759       while (IS_DIRSEP_CHAR(s[0])) {
    1760         s++;
    1761       }
    1762 
    1763       // Skip all double-dots
    1764       while (*s == '.' && s[1] == '.') {
    1765         s += 2;
     2021    if (s[-1] == '/' || s[-1] == '\\') {
     2022      // Skip all following slashes, backslashes and double-dots
     2023      while (s[0] != '\0') {
     2024        if (s[0] == '/' || s[0] == '\\') {
     2025          s++;
     2026        } else if (s[0] == '.' && s[1] == '.') {
     2027          s += 2;
     2028        } else {
     2029          break;
     2030        }
    17662031      }
    17672032    }
     
    17742039  size_t ext_len;
    17752040  const char *mime_type;
    1776   size_t mime_type_len;
    17772041} builtin_mime_types[] = {
    1778   {".html", 5, "text/html",   9},
    1779   {".htm", 4, "text/html",   9},
    1780   {".shtm", 5, "text/html",   9},
    1781   {".shtml", 6, "text/html",   9},
    1782   {".css", 4, "text/css",   8},
    1783   {".js",  3, "application/x-javascript", 24},
    1784   {".ico", 4, "image/x-icon",   12},
    1785   {".gif", 4, "image/gif",   9},
    1786   {".jpg", 4, "image/jpeg",   10},
    1787   {".jpeg", 5, "image/jpeg",   10},
    1788   {".png", 4, "image/png",   9},
    1789   {".svg", 4, "image/svg+xml",  13},
    1790   {".torrent", 8, "application/x-bittorrent", 24},
    1791   {".wav", 4, "audio/x-wav",   11},
    1792   {".mp3", 4, "audio/x-mp3",   11},
    1793   {".mid", 4, "audio/mid",   9},
    1794   {".m3u", 4, "audio/x-mpegurl",  15},
    1795   {".ram", 4, "audio/x-pn-realaudio",  20},
    1796   {".xml", 4, "text/xml",   8},
    1797   {".xslt", 5, "application/xml",  15},
    1798   {".ra",  3, "audio/x-pn-realaudio",  20},
    1799   {".doc", 4, "application/msword",  19},
    1800   {".exe", 4, "application/octet-stream", 24},
    1801   {".zip", 4, "application/x-zip-compressed", 28},
    1802   {".xls", 4, "application/excel",  17},
    1803   {".tgz", 4, "application/x-tar-gz",  20},
    1804   {".tar", 4, "application/x-tar",  17},
    1805   {".gz",  3, "application/x-gunzip",  20},
    1806   {".arj", 4, "application/x-arj-compressed", 28},
    1807   {".rar", 4, "application/x-arj-compressed", 28},
    1808   {".rtf", 4, "application/rtf",  15},
    1809   {".pdf", 4, "application/pdf",  15},
    1810   {".swf", 4, "application/x-shockwave-flash",29},
    1811   {".mpg", 4, "video/mpeg",   10},
    1812   {".mpeg", 5, "video/mpeg",   10},
    1813   {".mp4", 4, "video/mp4", 9},
    1814   {".m4v", 4, "video/x-m4v", 11},
    1815   {".asf", 4, "video/x-ms-asf",  14},
    1816   {".avi", 4, "video/x-msvideo",  15},
    1817   {".bmp", 4, "image/bmp",   9},
    1818   {NULL,  0, NULL,    0}
     2042  {".html", 5, "text/html"},
     2043  {".htm", 4, "text/html"},
     2044  {".shtm", 5, "text/html"},
     2045  {".shtml", 6, "text/html"},
     2046  {".css", 4, "text/css"},
     2047  {".js",  3, "application/x-javascript"},
     2048  {".ico", 4, "image/x-icon"},
     2049  {".gif", 4, "image/gif"},
     2050  {".jpg", 4, "image/jpeg"},
     2051  {".jpeg", 5, "image/jpeg"},
     2052  {".png", 4, "image/png"},
     2053  {".svg", 4, "image/svg+xml"},
     2054  {".txt", 4, "text/plain"},
     2055  {".torrent", 8, "application/x-bittorrent"},
     2056  {".wav", 4, "audio/x-wav"},
     2057  {".mp3", 4, "audio/x-mp3"},
     2058  {".mid", 4, "audio/mid"},
     2059  {".m3u", 4, "audio/x-mpegurl"},
     2060  {".ogg", 4, "audio/ogg"},
     2061  {".ram", 4, "audio/x-pn-realaudio"},
     2062  {".xml", 4, "text/xml"},
     2063  {".json",  5, "text/json"},
     2064  {".xslt", 5, "application/xml"},
     2065  {".xsl", 4, "application/xml"},
     2066  {".ra",  3, "audio/x-pn-realaudio"},
     2067  {".doc", 4, "application/msword"},
     2068  {".exe", 4, "application/octet-stream"},
     2069  {".zip", 4, "application/x-zip-compressed"},
     2070  {".xls", 4, "application/excel"},
     2071  {".tgz", 4, "application/x-tar-gz"},
     2072  {".tar", 4, "application/x-tar"},
     2073  {".gz",  3, "application/x-gunzip"},
     2074  {".arj", 4, "application/x-arj-compressed"},
     2075  {".rar", 4, "application/x-arj-compressed"},
     2076  {".rtf", 4, "application/rtf"},
     2077  {".pdf", 4, "application/pdf"},
     2078  {".swf", 4, "application/x-shockwave-flash"},
     2079  {".mpg", 4, "video/mpeg"},
     2080  {".webm", 5, "video/webm"},
     2081  {".mpeg", 5, "video/mpeg"},
     2082  {".mov", 4, "video/quicktime"},
     2083  {".mp4", 4, "video/mp4"},
     2084  {".m4v", 4, "video/x-m4v"},
     2085  {".asf", 4, "video/x-ms-asf"},
     2086  {".avi", 4, "video/x-msvideo"},
     2087  {".bmp", 4, "image/bmp"},
     2088  {".ttf", 4, "application/x-font-ttf"},
     2089  {NULL,  0, NULL}
    18192090};
     2091
     2092const char *mg_get_builtin_mime_type(const char *path) {
     2093  const char *ext;
     2094  size_t i, path_len;
     2095
     2096  path_len = strlen(path);
     2097
     2098  for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
     2099    ext = path + (path_len - builtin_mime_types[i].ext_len);
     2100    if (path_len > builtin_mime_types[i].ext_len &&
     2101        mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
     2102      return builtin_mime_types[i].mime_type;
     2103    }
     2104  }
     2105
     2106  return "text/plain";
     2107}
    18202108
    18212109// Look at the "path" extension and figure what mime type it has.
     
    18252113  struct vec ext_vec, mime_vec;
    18262114  const char *list, *ext;
    1827   size_t i, path_len;
     2115  size_t path_len;
    18282116
    18292117  path_len = strlen(path);
     
    18412129  }
    18422130
    1843   // Now scan built-in mime types
    1844   for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
    1845     ext = path + (path_len - builtin_mime_types[i].ext_len);
    1846     if (path_len > builtin_mime_types[i].ext_len &&
    1847         mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
    1848       vec->ptr = builtin_mime_types[i].mime_type;
    1849       vec->len = builtin_mime_types[i].mime_type_len;
    1850       return;
    1851     }
    1852   }
    1853 
    1854   // Nothing found. Fall back to "text/plain"
    1855   vec->ptr = "text/plain";
    1856   vec->len = 10;
     2131  vec->ptr = mg_get_builtin_mime_type(path);
     2132  vec->len = strlen(vec->ptr);
     2133}
     2134
     2135static int is_big_endian(void) {
     2136  static const int n = 1;
     2137  return ((char *) &n)[0] == 0;
    18572138}
    18582139
     
    18642145} MD5_CTX;
    18652146
    1866 #if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
    1867 #define byteReverse(buf, len) // Do nothing
    1868 #else
    18692147static void byteReverse(unsigned char *buf, unsigned longs) {
    18702148  uint32_t t;
    1871   do {
    1872     t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
    1873       ((unsigned) buf[1] << 8 | buf[0]);
    1874     *(uint32_t *) buf = t;
    1875     buf += 4;
    1876   } while (--longs);
    1877 }
    1878 #endif
     2149
     2150  // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN
     2151  if (is_big_endian()) {
     2152    do {
     2153      t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
     2154        ((unsigned) buf[1] << 8 | buf[0]);
     2155      * (uint32_t *) buf = t;
     2156      buf += 4;
     2157    } while (--longs);
     2158  }
     2159}
    18792160
    18802161#define F1(x, y, z) (z ^ (x & (y ^ z)))
     
    20192300  unsigned count;
    20202301  unsigned char *p;
     2302  uint32_t *a;
    20212303
    20222304  count = (ctx->bits[0] >> 3) & 0x3F;
     
    20352317  byteReverse(ctx->in, 14);
    20362318
    2037   ((uint32_t *) ctx->in)[14] = ctx->bits[0];
    2038   ((uint32_t *) ctx->in)[15] = ctx->bits[1];
     2319  a = (uint32_t *)ctx->in;
     2320  a[14] = ctx->bits[0];
     2321  a[15] = ctx->bits[1];
    20392322
    20402323  MD5Transform(ctx->buf, (uint32_t *) ctx->in);
     
    20572340}
    20582341
    2059 // Return stringified MD5 hash for list of vectors. Buffer must be 33 bytes.
    2060 void mg_md5(char *buf, ...) {
     2342// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
     2343char *mg_md5(char buf[33], ...) {
    20612344  unsigned char hash[16];
    20622345  const char *p;
     
    20742357  MD5Final(hash, &ctx);
    20752358  bin2str(buf, hash, sizeof(hash));
     2359  return buf;
    20762360}
    20772361
     
    21062390// Use the global passwords file, if specified by auth_gpass option,
    21072391// or search for .htpasswd in the requested directory.
    2108 static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
    2109   struct mg_context *ctx = conn->ctx;
     2392static void open_auth_file(struct mg_connection *conn, const char *path,
     2393                           struct file *filep) {
    21102394  char name[PATH_MAX];
    2111   const char *p, *e;
    2112   struct mgstat st;
    2113   FILE *fp;
    2114 
    2115   if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) {
     2395  const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
     2396  struct file file = STRUCT_FILE_INITIALIZER;
     2397
     2398  if (gpass != NULL) {
    21162399    // Use global passwords file
    2117     fp =  mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r");
    2118     if (fp == NULL)
    2119       cry(fc(ctx), "fopen(%s): %s",
    2120           ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO));
    2121   } else if (!mg_stat(path, &st) && st.is_directory) {
    2122     (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s",
    2123         path, DIRSEP, PASSWORDS_FILE_NAME);
    2124     fp = mg_fopen(name, "r");
     2400    if (!mg_fopen(conn, gpass, "r", filep)) {
     2401      cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
     2402    }
     2403    // Important: using local struct file to test path for is_directory flag.
     2404    // If filep is used, mg_stat() makes it appear as if auth file was opened.
     2405  } else if (mg_stat(conn, path, &file) && file.is_directory) {
     2406    mg_snprintf(conn, name, sizeof(name), "%s%c%s",
     2407                path, '/', PASSWORDS_FILE_NAME);
     2408    mg_fopen(conn, name, "r", filep);
    21252409  } else {
    21262410     // Try to find .htpasswd in requested directory.
    21272411    for (p = path, e = p + strlen(p) - 1; e > p; e--)
    2128       if (IS_DIRSEP_CHAR(*e))
     2412      if (e[0] == '/')
    21292413        break;
    2130     (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
    2131         (int) (e - p), p, DIRSEP, PASSWORDS_FILE_NAME);
    2132     fp = mg_fopen(name, "r");
    2133   }
    2134 
    2135   return fp;
     2414    mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
     2415                (int) (e - p), p, '/', PASSWORDS_FILE_NAME);
     2416    mg_fopen(conn, name, "r", filep);
     2417  }
    21362418}
    21372419
     
    21412423};
    21422424
     2425// Return 1 on success. Always initializes the ah structure.
    21432426static int parse_auth_header(struct mg_connection *conn, char *buf,
    21442427                             size_t buf_size, struct ah *ah) {
     
    21462429  const char *auth_header;
    21472430
     2431  (void) memset(ah, 0, sizeof(*ah));
    21482432  if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
    21492433      mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
     
    21532437  // Make modifiable copy of the auth header
    21542438  (void) mg_strlcpy(buf, auth_header + 7, buf_size);
    2155 
    21562439  s = buf;
    2157   (void) memset(ah, 0, sizeof(*ah));
    21582440
    21592441  // Parse authorization header
     
    22052487}
    22062488
     2489static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p) {
     2490  char *eof;
     2491  size_t len;
     2492  char *memend;
     2493
     2494  if (filep->membuf != NULL && *p != NULL) {
     2495    memend = (char *) &filep->membuf[filep->size];
     2496    eof = (char *) memchr(*p, '\n', memend - *p); // Search for \n from p till the end of stream
     2497    if (eof != NULL) {
     2498      eof += 1; // Include \n
     2499    } else {
     2500      eof = memend; // Copy remaining data
     2501    }
     2502    len = (size_t) (eof - *p) > size - 1 ? size - 1 : (size_t) (eof - *p);
     2503    memcpy(buf, *p, len);
     2504    buf[len] = '\0';
     2505    *p += len;
     2506    return len ? eof : NULL;
     2507  } else if (filep->fp != NULL) {
     2508    return fgets(buf, size, filep->fp);
     2509  } else {
     2510    return NULL;
     2511  }
     2512}
     2513
    22072514// Authorize against the opened passwords file. Return 1 if authorized.
    2208 static int authorize(struct mg_connection *conn, FILE *fp) {
     2515static int authorize(struct mg_connection *conn, struct file *filep) {
    22092516  struct ah ah;
    2210   char line[256], f_user[256], ha1[256], f_domain[256], buf[BUFSIZ];
     2517  char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN], *p;
    22112518
    22122519  if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
     
    22152522
    22162523  // Loop over passwords file
    2217   while (fgets(line, sizeof(line), fp) != NULL) {
     2524  p = (char *) filep->membuf;
     2525  while (mg_fgets(line, sizeof(line), filep, &p) != NULL) {
    22182526    if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
    22192527      continue;
     
    22222530    if (!strcmp(ah.user, f_user) &&
    22232531        !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
    2224       return check_password(
    2225             conn->request_info.request_method,
    2226             ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop,
    2227             ah.response);
     2532      return check_password(conn->request_info.request_method, ha1, ah.uri,
     2533                            ah.nonce, ah.nc, ah.cnonce, ah.qop, ah.response);
    22282534  }
    22292535
     
    22332539// Return 1 if request is authorised, 0 otherwise.
    22342540static int check_authorization(struct mg_connection *conn, const char *path) {
    2235   FILE *fp;
    22362541  char fname[PATH_MAX];
    22372542  struct vec uri_vec, filename_vec;
    22382543  const char *list;
    2239   int authorized;
    2240 
    2241   fp = NULL;
    2242   authorized = 1;
     2544  struct file file = STRUCT_FILE_INITIALIZER;
     2545  int authorized = 1;
    22432546
    22442547  list = conn->ctx->config[PROTECT_URI];
    22452548  while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
    22462549    if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
    2247       (void) mg_snprintf(conn, fname, sizeof(fname), "%.*s",
    2248           filename_vec.len, filename_vec.ptr);
    2249       if ((fp = mg_fopen(fname, "r")) == NULL) {
     2550      mg_snprintf(conn, fname, sizeof(fname), "%.*s",
     2551                  (int) filename_vec.len, filename_vec.ptr);
     2552      if (!mg_fopen(conn, fname, "r", &file)) {
    22502553        cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
    22512554      }
     
    22542557  }
    22552558
    2256   if (fp == NULL) {
    2257     fp = open_auth_file(conn, path);
    2258   }
    2259 
    2260   if (fp != NULL) {
    2261     authorized = authorize(conn, fp);
    2262     (void) fclose(fp);
     2559  if (!is_file_opened(&file)) {
     2560    open_auth_file(conn, path, &file);
     2561  }
     2562
     2563  if (is_file_opened(&file)) {
     2564    authorized = authorize(conn, &file);
     2565    mg_fclose(&file);
    22632566  }
    22642567
     
    22672570
    22682571static void send_authorization_request(struct mg_connection *conn) {
    2269   conn->request_info.status_code = 401;
    2270   (void) mg_printf(conn,
    2271       "HTTP/1.1 401 Unauthorized\r\n"
    2272       "Content-Length: 0\r\n"
    2273       "WWW-Authenticate: Digest qop=\"auth\", "
    2274       "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
    2275       conn->ctx->config[AUTHENTICATION_DOMAIN],
    2276       (unsigned long) time(NULL));
     2572  conn->status_code = 401;
     2573  mg_printf(conn,
     2574            "HTTP/1.1 401 Unauthorized\r\n"
     2575            "Content-Length: 0\r\n"
     2576            "WWW-Authenticate: Digest qop=\"auth\", "
     2577            "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
     2578            conn->ctx->config[AUTHENTICATION_DOMAIN],
     2579            (unsigned long) time(NULL));
    22772580}
    22782581
    22792582static int is_authorized_for_put(struct mg_connection *conn) {
    2280   FILE *fp;
     2583  struct file file = STRUCT_FILE_INITIALIZER;
     2584  const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
    22812585  int ret = 0;
    22822586
    2283   fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL :
    2284     mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r");
    2285 
    2286   if (fp != NULL) {
    2287     ret = authorize(conn, fp);
    2288     (void) fclose(fp);
     2587  if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
     2588    ret = authorize(conn, &file);
     2589    mg_fclose(&file);
    22892590  }
    22902591
     
    23092610
    23102611  // Create the file if does not exist
    2311   if ((fp = mg_fopen(fname, "a+")) != NULL) {
     2612  if ((fp = fopen(fname, "a+")) != NULL) {
    23122613    (void) fclose(fp);
    23132614  }
    23142615
    23152616  // Open the given file and temporary file
    2316   if ((fp = mg_fopen(fname, "r")) == NULL) {
     2617  if ((fp = fopen(fname, "r")) == NULL) {
    23172618    return 0;
    2318   } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) {
     2619  } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
    23192620    fclose(fp);
    23202621    return 0;
     
    23342635      }
    23352636    } else {
    2336       (void) fprintf(fp2, "%s", line);
     2637      fprintf(fp2, "%s", line);
    23372638    }
    23382639  }
     
    23412642  if (!found && pass != NULL) {
    23422643    mg_md5(ha1, user, ":", domain, ":", pass, NULL);
    2343     (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
     2644    fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
    23442645  }
    23452646
    23462647  // Close files
    2347   (void) fclose(fp);
    2348   (void) fclose(fp2);
     2648  fclose(fp);
     2649  fclose(fp2);
    23492650
    23502651  // Put the temp file in place of real file
    2351   (void) mg_remove(fname);
    2352   (void) mg_rename(tmp, fname);
     2652  remove(fname);
     2653  rename(tmp, fname);
    23532654
    23542655  return 1;
    23552656}
    23562657
    2357 struct de {
    2358   struct mg_connection *conn;
    2359   char *file_name;
    2360   struct mgstat st;
    2361 };
    2362 
    2363 static void url_encode(const char *src, char *dst, size_t dst_len) {
     2658static SOCKET conn2(const char *host, int port, int use_ssl,
     2659                    char *ebuf, size_t ebuf_len) {
     2660  struct sockaddr_in sin;
     2661  struct hostent *he;
     2662  SOCKET sock = INVALID_SOCKET;
     2663
     2664  if (host == NULL) {
     2665    snprintf(ebuf, ebuf_len, "%s", "NULL host");
     2666  } else if (use_ssl && SSLv23_client_method == NULL) {
     2667    snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
     2668    // TODO(lsm): use something threadsafe instead of gethostbyname()
     2669  } else if ((he = gethostbyname(host)) == NULL) {
     2670    snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
     2671  } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
     2672    snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
     2673  } else {
     2674    set_close_on_exec(sock);
     2675    sin.sin_family = AF_INET;
     2676    sin.sin_port = htons((uint16_t) port);
     2677    sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
     2678    if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
     2679      snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
     2680               host, port, strerror(ERRNO));
     2681      closesocket(sock);
     2682      sock = INVALID_SOCKET;
     2683    }
     2684  }
     2685  return sock;
     2686}
     2687
     2688
     2689
     2690static void mg_url_encode(const char *src, char *dst, size_t dst_len) {
    23642691  static const char *dont_escape = "._-$,;~()";
    23652692  static const char *hex = "0123456789abcdef";
     
    23842711  char size[64], mod[64], href[PATH_MAX];
    23852712
    2386   if (de->st.is_directory) {
    2387     (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
     2713  if (de->file.is_directory) {
     2714    mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
    23882715  } else {
    23892716     // We use (signed) cast below because MSVC 6 compiler cannot
    23902717     // convert unsigned __int64 to double. Sigh.
    2391     if (de->st.size < 1024) {
    2392       (void) mg_snprintf(de->conn, size, sizeof(size),
    2393           "%lu", (unsigned long) de->st.size);
    2394     } else if (de->st.size < 1024 * 1024) {
    2395       (void) mg_snprintf(de->conn, size, sizeof(size),
    2396           "%.1fk", (double) de->st.size / 1024.0);
    2397     } else if (de->st.size < 1024 * 1024 * 1024) {
    2398       (void) mg_snprintf(de->conn, size, sizeof(size),
    2399           "%.1fM", (double) de->st.size / 1048576);
     2718    if (de->file.size < 1024) {
     2719      mg_snprintf(de->conn, size, sizeof(size), "%d", (int) de->file.size);
     2720    } else if (de->file.size < 0x100000) {
     2721      mg_snprintf(de->conn, size, sizeof(size),
     2722                  "%.1fk", (double) de->file.size / 1024.0);
     2723    } else if (de->file.size < 0x40000000) {
     2724      mg_snprintf(de->conn, size, sizeof(size),
     2725                  "%.1fM", (double) de->file.size / 1048576);
    24002726    } else {
    2401       (void) mg_snprintf(de->conn, size, sizeof(size),
    2402           "%.1fG", (double) de->st.size / 1073741824);
    2403     }
    2404   }
    2405   (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime));
    2406   url_encode(de->file_name, href, sizeof(href));
     2727      mg_snprintf(de->conn, size, sizeof(size),
     2728                  "%.1fG", (double) de->file.size / 1073741824);
     2729    }
     2730  }
     2731  strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
     2732           localtime(&de->file.modification_time));
     2733  mg_url_encode(de->file_name, href, sizeof(href));
    24072734  de->conn->num_bytes_sent += mg_printf(de->conn,
    24082735      "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
    24092736      "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
    2410       de->conn->request_info.uri, href, de->st.is_directory ? "/" : "",
    2411       de->file_name, de->st.is_directory ? "/" : "", mod, size);
     2737      de->conn->request_info.uri, href, de->file.is_directory ? "/" : "",
     2738      de->file_name, de->file.is_directory ? "/" : "", mod, size);
    24122739}
    24132740
     
    24252752  }
    24262753
    2427   if (a->st.is_directory && !b->st.is_directory) {
     2754  if (a->file.is_directory && !b->file.is_directory) {
    24282755    return -1;  // Always put directories on top
    2429   } else if (!a->st.is_directory && b->st.is_directory) {
     2756  } else if (!a->file.is_directory && b->file.is_directory) {
    24302757    return 1;   // Always put directories on top
    24312758  } else if (*query_string == 'n') {
    24322759    cmp_result = strcmp(a->file_name, b->file_name);
    24332760  } else if (*query_string == 's') {
    2434     cmp_result = a->st.size == b->st.size ? 0 :
    2435       a->st.size > b->st.size ? 1 : -1;
     2761    cmp_result = a->file.size == b->file.size ? 0 :
     2762      a->file.size > b->file.size ? 1 : -1;
    24362763  } else if (*query_string == 'd') {
    2437     cmp_result = a->st.mtime == b->st.mtime ? 0 :
    2438       a->st.mtime > b->st.mtime ? 1 : -1;
     2764    cmp_result = a->file.modification_time == b->file.modification_time ? 0 :
     2765      a->file.modification_time > b->file.modification_time ? 1 : -1;
    24392766  }
    24402767
    24412768  return query_string[1] == 'd' ? -cmp_result : cmp_result;
     2769}
     2770
     2771static int must_hide_file(struct mg_connection *conn, const char *path) {
     2772  const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
     2773  const char *pattern = conn->ctx->config[HIDE_FILES];
     2774  return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
     2775    (pattern != NULL && match_prefix(pattern, strlen(pattern), path) > 0);
    24422776}
    24432777
     
    24552789
    24562790    while ((dp = readdir(dirp)) != NULL) {
    2457       // Do not show current dir and passwords file
     2791      // Do not show current dir and hidden files
    24582792      if (!strcmp(dp->d_name, ".") ||
    24592793          !strcmp(dp->d_name, "..") ||
    2460           !strcmp(dp->d_name, PASSWORDS_FILE_NAME))
     2794          must_hide_file(conn, dp->d_name)) {
    24612795        continue;
    2462 
    2463       mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, DIRSEP, dp->d_name);
     2796      }
     2797
     2798      mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
    24642799
    24652800      // If we don't memset stat structure to zero, mtime will have
     
    24682803      // fails. For more details, see
    24692804      // http://code.google.com/p/mongoose/issues/detail?id=79
    2470       if (mg_stat(path, &de.st) != 0) {
    2471         memset(&de.st, 0, sizeof(de.st));
     2805      memset(&de.file, 0, sizeof(de.file));
     2806      mg_stat(conn, path, &de.file);
     2807
     2808      de.file_name = dp->d_name;
     2809      cb(&de, data);
     2810    }
     2811    (void) closedir(dirp);
     2812  }
     2813  return 1;
     2814}
     2815
     2816static int remove_directory(struct mg_connection *conn, const char *dir) {
     2817  char path[PATH_MAX];
     2818  struct dirent *dp;
     2819  DIR *dirp;
     2820  struct de de;
     2821
     2822  if ((dirp = opendir(dir)) == NULL) {
     2823    return 0;
     2824  } else {
     2825    de.conn = conn;
     2826
     2827    while ((dp = readdir(dirp)) != NULL) {
     2828      // Do not show current dir (but show hidden files as they will also be removed)
     2829      if (!strcmp(dp->d_name, ".") ||
     2830          !strcmp(dp->d_name, "..")) {
     2831        continue;
    24722832      }
    2473       de.file_name = dp->d_name;
    2474 
    2475       cb(&de, data);
     2833
     2834      mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
     2835
     2836      // If we don't memset stat structure to zero, mtime will have
     2837      // garbage and strftime() will segfault later on in
     2838      // print_dir_entry(). memset is required only if mg_stat()
     2839      // fails. For more details, see
     2840      // http://code.google.com/p/mongoose/issues/detail?id=79
     2841      memset(&de.file, 0, sizeof(de.file));
     2842      mg_stat(conn, path, &de.file);
     2843      if(de.file.modification_time) {
     2844          if(de.file.is_directory) {
     2845              remove_directory(conn, path);
     2846          } else {
     2847              mg_remove(path);
     2848          }
     2849      }
     2850
    24762851    }
    24772852    (void) closedir(dirp);
    2478   }
     2853
     2854    rmdir(dir);
     2855  }
     2856
    24792857  return 1;
    24802858}
     
    24862864};
    24872865
     2866// Behaves like realloc(), but frees original pointer on failure
     2867static void *realloc2(void *ptr, size_t size) {
     2868  void *new_ptr = realloc(ptr, size);
     2869  if (new_ptr == NULL) {
     2870    free(ptr);
     2871  }
     2872  return new_ptr;
     2873}
     2874
    24882875static void dir_scan_callback(struct de *de, void *data) {
    24892876  struct dir_scan_data *dsd = (struct dir_scan_data *) data;
     
    24912878  if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
    24922879    dsd->arr_size *= 2;
    2493     dsd->entries = (struct de *) realloc(dsd->entries, dsd->arr_size *
    2494                                          sizeof(dsd->entries[0]));
     2880    dsd->entries = (struct de *) realloc2(dsd->entries, dsd->arr_size *
     2881                                          sizeof(dsd->entries[0]));
    24952882  }
    24962883  if (dsd->entries == NULL) {
     
    24992886  } else {
    25002887    dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
    2501     dsd->entries[dsd->num_entries].st = de->st;
     2888    dsd->entries[dsd->num_entries].file = de->file;
    25022889    dsd->entries[dsd->num_entries].conn = de->conn;
    25032890    dsd->num_entries++;
     
    25522939
    25532940  conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
    2554   conn->request_info.status_code = 200;
     2941  conn->status_code = 200;
    25552942}
    25562943
    25572944// Send len bytes from the opened file to the client.
    2558 static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
    2559   char buf[BUFSIZ];
     2945static void send_file_data(struct mg_connection *conn, struct file *filep,
     2946                           int64_t offset, int64_t len) {
     2947  char buf[MG_BUF_LEN];
    25602948  int to_read, num_read, num_written;
    25612949
    2562   while (len > 0) {
    2563     // Calculate how much to read from the file in the buffer
    2564     to_read = sizeof(buf);
    2565     if ((int64_t) to_read > len)
    2566       to_read = (int) len;
    2567 
    2568     // Read from file, exit the loop on error
    2569     if ((num_read = fread(buf, 1, (size_t)to_read, fp)) == 0)
    2570       break;
    2571 
    2572     // Send read bytes to the client, exit the loop on error
    2573     if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read)
    2574       break;
    2575 
    2576     // Both read and were successful, adjust counters
    2577     conn->num_bytes_sent += num_written;
    2578     len -= num_written;
     2950  // Sanity check the offset
     2951  offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset;
     2952
     2953  if (len > 0 && filep->membuf != NULL && filep->size > 0) {
     2954    if (len > filep->size - offset) {
     2955      len = filep->size - offset;
     2956    }
     2957    mg_write(conn, filep->membuf + offset, (size_t) len);
     2958  } else if (len > 0 && filep->fp != NULL) {
     2959    fseeko(filep->fp, offset, SEEK_SET);
     2960    while (len > 0) {
     2961      // Calculate how much to read from the file in the buffer
     2962      to_read = sizeof(buf);
     2963      if ((int64_t) to_read > len) {
     2964        to_read = (int) len;
     2965      }
     2966
     2967      // Read from file, exit the loop on error
     2968      if ((num_read = fread(buf, 1, (size_t) to_read, filep->fp)) <= 0) {
     2969        break;
     2970      }
     2971
     2972      // Send read bytes to the client, exit the loop on error
     2973      if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
     2974        break;
     2975      }
     2976
     2977      // Both read and were successful, adjust counters
     2978      conn->num_bytes_sent += num_written;
     2979      len -= num_written;
     2980    }
    25792981  }
    25802982}
     
    25882990}
    25892991
     2992static void construct_etag(char *buf, size_t buf_len,
     2993                           const struct file *filep) {
     2994  snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
     2995           (unsigned long) filep->modification_time, filep->size);
     2996}
     2997
     2998static void fclose_on_exec(struct file *filep) {
     2999  if (filep != NULL && filep->fp != NULL) {
     3000#ifndef _WIN32
     3001    fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC);
     3002#endif
     3003  }
     3004}
     3005
    25903006static void handle_file_request(struct mg_connection *conn, const char *path,
    2591                                 struct mgstat *stp) {
     3007                                struct file *filep) {
    25923008  char date[64], lm[64], etag[64], range[64];
    25933009  const char *msg = "OK", *hdr;
     
    25953011  int64_t cl, r1, r2;
    25963012  struct vec mime_vec;
    2597   FILE *fp;
    25983013  int n;
     3014  char gz_path[PATH_MAX];
     3015  char const* encoding = "";
    25993016
    26003017  get_mime_type(conn->ctx, path, &mime_vec);
    2601   cl = stp->size;
    2602   conn->request_info.status_code = 200;
     3018  cl = filep->size;
     3019  conn->status_code = 200;
    26033020  range[0] = '\0';
    26043021
    2605   if ((fp = mg_fopen(path, "rb")) == NULL) {
     3022  // if this file is in fact a pre-gzipped file, rewrite its filename
     3023  // it's important to rewrite the filename after resolving
     3024  // the mime type from it, to preserve the actual file's type
     3025  if (filep->gzipped) {
     3026    snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
     3027    path = gz_path;
     3028    encoding = "Content-Encoding: gzip\r\n";
     3029  }
     3030
     3031  if (!mg_fopen(conn, path, "rb", filep)) {
    26063032    send_http_error(conn, 500, http_500_error,
    2607         "fopen(%s): %s", path, strerror(ERRNO));
     3033                    "fopen(%s): %s", path, strerror(ERRNO));
    26083034    return;
    26093035  }
    2610   set_close_on_exec(fileno(fp));
     3036
     3037  fclose_on_exec(filep);
    26113038
    26123039  // If Range: header specified, act accordingly
    26133040  r1 = r2 = 0;
    26143041  hdr = mg_get_header(conn, "Range");
    2615   if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) {
    2616     conn->request_info.status_code = 206;
    2617     (void) fseeko(fp, (off_t) r1, SEEK_SET);
    2618     cl = n == 2 ? r2 - r1 + 1: cl - r1;
    2619     (void) mg_snprintf(conn, range, sizeof(range),
    2620         "Content-Range: bytes "
    2621         "%" INT64_FMT "-%"
    2622         INT64_FMT "/%" INT64_FMT "\r\n",
    2623         r1, r1 + cl - 1, stp->size);
     3042  if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
     3043      r1 >= 0 && r2 >= 0) {
     3044    // actually, range requests don't play well with a pre-gzipped
     3045    // file (since the range is specified in the uncmpressed space)
     3046    if (filep->gzipped) {
     3047      send_http_error(conn, 501, "Not Implemented", "range requests in gzipped files are not supported");
     3048      return;
     3049    }
     3050    conn->status_code = 206;
     3051    cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
     3052    mg_snprintf(conn, range, sizeof(range),
     3053                "Content-Range: bytes "
     3054                "%" INT64_FMT "-%"
     3055                INT64_FMT "/%" INT64_FMT "\r\n",
     3056                r1, r1 + cl - 1, filep->size);
    26243057    msg = "Partial Content";
    26253058  }
     
    26283061  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
    26293062  gmt_time_string(date, sizeof(date), &curtime);
    2630   gmt_time_string(lm, sizeof(lm), &stp->mtime);
    2631   (void) mg_snprintf(conn, etag, sizeof(etag), "%lx.%lx",
    2632       (unsigned long) stp->mtime, (unsigned long) stp->size);
     3063  gmt_time_string(lm, sizeof(lm), &filep->modification_time);
     3064  construct_etag(etag, sizeof(etag), filep);
    26333065
    26343066  (void) mg_printf(conn,
     
    26363068      "Date: %s\r\n"
    26373069      "Last-Modified: %s\r\n"
    2638       "Etag: \"%s\"\r\n"
     3070      "Etag: %s\r\n"
    26393071      "Content-Type: %.*s\r\n"
    26403072      "Content-Length: %" INT64_FMT "\r\n"
    26413073      "Connection: %s\r\n"
    26423074      "Accept-Ranges: bytes\r\n"
    2643       "%s\r\n",
    2644       conn->request_info.status_code, msg, date, lm, etag, (int) mime_vec.len,
    2645       mime_vec.ptr, cl, suggest_connection_header(conn), range);
     3075      "%s%s\r\n",
     3076      conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
     3077      mime_vec.ptr, cl, suggest_connection_header(conn), range, encoding);
    26463078
    26473079  if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
    2648     send_file_data(conn, fp, cl);
    2649   }
    2650   (void) fclose(fp);
     3080    send_file_data(conn, filep, r1, cl);
     3081  }
     3082  mg_fclose(filep);
    26513083}
    26523084
    26533085void mg_send_file(struct mg_connection *conn, const char *path) {
    2654   struct mgstat st;
    2655   if (mg_stat(path, &st) == 0) {
    2656     handle_file_request(conn, path, &st);
     3086  struct file file = STRUCT_FILE_INITIALIZER;
     3087  if (mg_stat(conn, path, &file)) {
     3088    handle_file_request(conn, path, &file);
    26573089  } else {
    26583090    send_http_error(conn, 404, "Not Found", "%s", "File not found");
     
    26793111    !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
    26803112    !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
    2681     !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND");
     3113    !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
     3114    || !strcmp(method, "MKCOL")
     3115          ;
    26823116}
    26833117
    26843118// Parse HTTP request, fill in mg_request_info structure.
    2685 static int parse_http_request(char *buf, struct mg_request_info *ri) {
    2686   int status = 0;
    2687 
    2688   // RFC says that all initial whitespaces should be ingored
    2689   while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
    2690     buf++;
    2691   }
    2692 
    2693   ri->request_method = skip(&buf, " ");
    2694   ri->uri = skip(&buf, " ");
    2695   ri->http_version = skip(&buf, "\r\n");
    2696 
    2697   if (is_valid_http_method(ri->request_method) &&
    2698       strncmp(ri->http_version, "HTTP/", 5) == 0) {
    2699     ri->http_version += 5;   // Skip "HTTP/"
    2700     parse_http_headers(&buf, ri);
    2701     status = 1;
    2702   }
    2703 
    2704   return status;
     3119// This function modifies the buffer by NUL-terminating
     3120// HTTP request components, header names and header values.
     3121static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
     3122  int is_request, request_length = get_request_len(buf, len);
     3123  if (request_length > 0) {
     3124    // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
     3125    ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
     3126    ri->num_headers = 0;
     3127
     3128    buf[request_length - 1] = '\0';
     3129
     3130    // RFC says that all initial whitespaces should be ingored
     3131    while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
     3132      buf++;
     3133    }
     3134    ri->request_method = skip(&buf, " ");
     3135    ri->uri = skip(&buf, " ");
     3136    ri->http_version = skip(&buf, "\r\n");
     3137
     3138    // HTTP message could be either HTTP request or HTTP response, e.g.
     3139    // "GET / HTTP/1.0 ...." or  "HTTP/1.0 200 OK ..."
     3140    is_request = is_valid_http_method(ri->request_method);
     3141    if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
     3142        (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
     3143      request_length = -1;
     3144    } else {
     3145      if (is_request) {
     3146        ri->http_version += 5;
     3147      }
     3148      parse_http_headers(&buf, ri);
     3149    }
     3150  }
     3151  return request_length;
    27053152}
    27063153
     
    27103157// have some data. The length of the data is stored in nread.
    27113158// Upon every read operation, increase nread by the number of bytes read.
    2712 static int read_request(FILE *fp, SOCKET sock, SSL *ssl, char *buf, int bufsiz,
    2713                         int *nread) {
     3159static int read_request(FILE *fp, struct mg_connection *conn,
     3160                        char *buf, int bufsiz, int *nread) {
    27143161  int request_len, n = 0;
    27153162
    2716   do {
     3163  request_len = get_request_len(buf, *nread);
     3164  while (conn->ctx->stop_flag == 0 &&
     3165         *nread < bufsiz && request_len == 0 &&
     3166         (n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
     3167    *nread += n;
     3168    assert(*nread <= bufsiz);
    27173169    request_len = get_request_len(buf, *nread);
    2718     if (request_len == 0 &&
    2719         (n = pull(fp, sock, ssl, buf + *nread, bufsiz - *nread)) > 0) {
    2720       *nread += n;
    2721     }
    2722   } while (*nread < bufsiz && request_len == 0 && n > 0);
    2723 
    2724   return request_len;
     3170  }
     3171
     3172  return request_len <= 0 && n <= 0 ? -1 : request_len;
    27253173}
    27263174
     
    27293177// If the file is found, it's stats is returned in stp.
    27303178static int substitute_index_file(struct mg_connection *conn, char *path,
    2731                                  size_t path_len, struct mgstat *stp) {
     3179                                 size_t path_len, struct file *filep) {
    27323180  const char *list = conn->ctx->config[INDEX_FILES];
    2733   struct mgstat st;
     3181  struct file file = STRUCT_FILE_INITIALIZER;
    27343182  struct vec filename_vec;
    27353183  size_t n = strlen(path);
     
    27393187  // directory separator characters from the end of the path, and
    27403188  // then append single directory separator character.
    2741   while (n > 0 && IS_DIRSEP_CHAR(path[n - 1])) {
     3189  while (n > 0 && path[n - 1] == '/') {
    27423190    n--;
    27433191  }
    2744   path[n] = DIRSEP;
     3192  path[n] = '/';
    27453193
    27463194  // Traverse index files list. For each entry, append it to the given
     
    27533201
    27543202    // Prepare full path to the index file
    2755     (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
     3203    mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
    27563204
    27573205    // Does it exist?
    2758     if (mg_stat(path, &st) == 0) {
     3206    if (mg_stat(conn, path, &file)) {
    27593207      // Yes it does, break the loop
    2760       *stp = st;
     3208      *filep = file;
    27613209      found = 1;
    27623210      break;
     
    27743222// Return True if we should reply 304 Not Modified.
    27753223static int is_not_modified(const struct mg_connection *conn,
    2776                            const struct mgstat *stp) {
     3224                           const struct file *filep) {
     3225  char etag[64];
    27773226  const char *ims = mg_get_header(conn, "If-Modified-Since");
    2778   return ims != NULL && stp->mtime <= parse_date_string(ims);
     3227  const char *inm = mg_get_header(conn, "If-None-Match");
     3228  construct_etag(etag, sizeof(etag), filep);
     3229  return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
     3230    (ims != NULL && filep->modification_time <= parse_date_string(ims));
    27793231}
    27803232
    27813233static int forward_body_data(struct mg_connection *conn, FILE *fp,
    27823234                             SOCKET sock, SSL *ssl) {
    2783   const char *expect, *buffered;
    2784   char buf[BUFSIZ];
     3235  const char *expect, *body;
     3236  char buf[MG_BUF_LEN];
    27853237  int to_read, nread, buffered_len, success = 0;
    27863238
     
    27893241
    27903242  if (conn->content_len == -1) {
    2791     send_http_error(conn, 411, "Length Required", "");
     3243    send_http_error(conn, 411, "Length Required", "%s", "");
    27923244  } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
    2793     send_http_error(conn, 417, "Expectation Failed", "");
     3245    send_http_error(conn, 417, "Expectation Failed", "%s", "");
    27943246  } else {
    27953247    if (expect != NULL) {
     
    27973249    }
    27983250
    2799     buffered = conn->buf + conn->request_len;
    2800     buffered_len = conn->data_len - conn->request_len;
     3251    body = conn->buf + conn->request_len + conn->consumed_content;
     3252    buffered_len = &conn->buf[conn->data_len] - body;
    28013253    assert(buffered_len >= 0);
    28023254    assert(conn->consumed_content == 0);
     
    28063258        buffered_len = (int) conn->content_len;
    28073259      }
    2808       push(fp, sock, ssl, buffered, (int64_t) buffered_len);
     3260      push(fp, sock, ssl, body, (int64_t) buffered_len);
    28093261      conn->consumed_content += buffered_len;
    28103262    }
    28113263
     3264    nread = 0;
    28123265    while (conn->consumed_content < conn->content_len) {
    28133266      to_read = sizeof(buf);
     
    28153268        to_read = (int) (conn->content_len - conn->consumed_content);
    28163269      }
    2817       nread = pull(NULL, conn->client.sock, conn->ssl, buf, to_read);
     3270      nread = pull(NULL, conn, buf, to_read);
    28183271      if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
    28193272        break;
     
    28233276
    28243277    if (conn->consumed_content == conn->content_len) {
    2825       success = 1;
     3278      success = nread >= 0;
    28263279    }
    28273280
    28283281    // Each error code path in this function must send an error
    28293282    if (!success) {
    2830       send_http_error(conn, 577, http_500_error, "");
     3283      send_http_error(conn, 577, http_500_error, "%s", "");
    28313284    }
    28323285  }
     
    28523305};
    28533306
     3307static char *addenv(struct cgi_env_block *block,
     3308                    PRINTF_FORMAT_STRING(const char *fmt), ...)
     3309  PRINTF_ARGS(2, 3);
     3310
    28543311// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
    28553312// pointer into the vars array.
     
    28723329
    28733330  // Make sure we do not overflow buffer and the envp array
    2874   if (n > 0 && n < space &&
     3331  if (n > 0 && n + 1 < space &&
    28753332      block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
    28763333    // Append a pointer to the added string into the envp array
    2877     block->vars[block->nvars++] = block->buf + block->len;
     3334    block->vars[block->nvars++] = added;
    28783335    // Bump up used length counter. Include \0 terminator
    28793336    block->len += n + 1;
     3337  } else {
     3338    cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt);
    28803339  }
    28813340
     
    28883347  const char *s, *slash;
    28893348  struct vec var_vec;
    2890   char *p, src_addr[20];
     3349  char *p, src_addr[IP_ADDR_STR_LEN];
    28913350  int  i;
    28923351
     
    28983357  addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
    28993358  addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
     3359  addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", mg_version());
    29003360
    29013361  // Prepare the environment block
     
    29173377  if ((s = strrchr(prog, '/')) == NULL)
    29183378    s = prog;
    2919   addenv(blk, "SCRIPT_NAME=%.*s%s", slash - conn->request_info.uri,
     3379  addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri),
    29203380         conn->request_info.uri, s);
    29213381
     
    29493409  if ((s = getenv("SystemDrive")) != NULL) {
    29503410    addenv(blk, "SystemDrive=%s", s);
     3411  }
     3412  if ((s = getenv("ProgramFiles")) != NULL) {
     3413    addenv(blk, "ProgramFiles=%s", s);
     3414  }
     3415  if ((s = getenv("ProgramFiles(x86)")) != NULL) {
     3416    addenv(blk, "ProgramFiles(x86)=%s", s);
    29513417  }
    29523418#else
     
    29803446  s = conn->ctx->config[CGI_ENVIRONMENT];
    29813447  while ((s = next_option(s, &var_vec, NULL)) != NULL) {
    2982     addenv(blk, "%.*s", var_vec.len, var_vec.ptr);
     3448    addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr);
    29833449  }
    29843450
     
    29923458
    29933459static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
    2994   int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
     3460  int headers_len, data_len, i, fdin[2], fdout[2];
    29953461  const char *status, *status_text;
    29963462  char buf[16384], *pbuf, dir[PATH_MAX], *p;
    29973463  struct mg_request_info ri;
    29983464  struct cgi_env_block blk;
    2999   FILE *in, *out;
    3000   pid_t pid;
     3465  FILE *in = NULL, *out = NULL;
     3466  struct file fout = STRUCT_FILE_INITIALIZER;
     3467  pid_t pid = (pid_t) -1;
    30013468
    30023469  prepare_cgi_environment(conn, prog, &blk);
     
    30063473  // executable program name relative to 'dir'.
    30073474  (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
    3008   if ((p = strrchr(dir, DIRSEP)) != NULL) {
     3475  if ((p = strrchr(dir, '/')) != NULL) {
    30093476    *p++ = '\0';
    30103477  } else {
     
    30133480  }
    30143481
    3015   pid = (pid_t) -1;
    3016   fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
    3017   in = out = NULL;
    3018 
    3019   if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
     3482  if (pipe(fdin) != 0 || pipe(fdout) != 0) {
    30203483    send_http_error(conn, 500, http_500_error,
    30213484        "Cannot create CGI pipe: %s", strerror(ERRNO));
    30223485    goto done;
    3023   } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars,
    3024           fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
     3486  }
     3487
     3488  pid = spawn_process(conn, p, blk.buf, blk.vars, fdin[0], fdout[1], dir);
     3489  if (pid == (pid_t) -1) {
     3490    send_http_error(conn, 500, http_500_error,
     3491        "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
    30253492    goto done;
    3026   } else if ((in = fdopen(fd_stdin[1], "wb")) == NULL ||
    3027       (out = fdopen(fd_stdout[0], "rb")) == NULL) {
     3493  }
     3494
     3495  // Make sure child closes all pipe descriptors. It must dup them to 0,1
     3496  set_close_on_exec(fdin[0]);
     3497  set_close_on_exec(fdin[1]);
     3498  set_close_on_exec(fdout[0]);
     3499  set_close_on_exec(fdout[1]);
     3500
     3501  // Parent closes only one side of the pipes.
     3502  // If we don't mark them as closed, close() attempt before
     3503  // return from this function throws an exception on Windows.
     3504  // Windows does not like when closed descriptor is closed again.
     3505  (void) close(fdin[0]);
     3506  (void) close(fdout[1]);
     3507  fdin[0] = fdout[1] = -1;
     3508
     3509
     3510  if ((in = fdopen(fdin[1], "wb")) == NULL ||
     3511      (out = fdopen(fdout[0], "rb")) == NULL) {
    30283512    send_http_error(conn, 500, http_500_error,
    30293513        "fopen: %s", strerror(ERRNO));
     
    30333517  setbuf(in, NULL);
    30343518  setbuf(out, NULL);
    3035 
    3036   // spawn_process() must close those!
    3037   // If we don't mark them as closed, close() attempt before
    3038   // return from this function throws an exception on Windows.
    3039   // Windows does not like when closed descriptor is closed again.
    3040   fd_stdin[0] = fd_stdout[1] = -1;
     3519  fout.fp = out;
    30413520
    30423521  // Send POST data to the CGI process if needed
     
    30453524    goto done;
    30463525  }
     3526
     3527  // Close so child gets an EOF.
     3528  fclose(in);
     3529  in = NULL;
     3530  fdin[1] = -1;
    30473531
    30483532  // Now read CGI reply into a buffer. We need to set correct
     
    30513535  // HTTP headers.
    30523536  data_len = 0;
    3053   headers_len = read_request(out, INVALID_SOCKET, NULL,
    3054                              buf, sizeof(buf), &data_len);
     3537  headers_len = read_request(out, conn, buf, sizeof(buf), &data_len);
    30553538  if (headers_len <= 0) {
    30563539    send_http_error(conn, 500, http_500_error,
    3057                     "CGI program sent malformed HTTP headers: [%.*s]",
    3058                     data_len, buf);
     3540                    "CGI program sent malformed or too big (>%u bytes) "
     3541                    "HTTP headers: [%.*s]",
     3542                    (unsigned) sizeof(buf), data_len, buf);
    30593543    goto done;
    30603544  }
     
    30663550  status_text = "OK";
    30673551  if ((status = get_header(&ri, "Status")) != NULL) {
    3068     conn->request_info.status_code = atoi(status);
     3552    conn->status_code = atoi(status);
    30693553    status_text = status;
    30703554    while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
     
    30723556    }
    30733557  } else if (get_header(&ri, "Location") != NULL) {
    3074     conn->request_info.status_code = 302;
     3558    conn->status_code = 302;
    30753559  } else {
    3076     conn->request_info.status_code = 200;
     3560    conn->status_code = 200;
    30773561  }
    30783562  if (get_header(&ri, "Connection") != NULL &&
     
    30803564    conn->must_close = 1;
    30813565  }
    3082   (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->request_info.status_code,
     3566  (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code,
    30833567                   status_text);
    30843568
     
    30883572              ri.http_headers[i].name, ri.http_headers[i].value);
    30893573  }
    3090   (void) mg_write(conn, "\r\n", 2);
    3091 
    3092   // Send chunk of data that may be read after the headers
     3574  mg_write(conn, "\r\n", 2);
     3575
     3576  // Send chunk of data that may have been read after the headers
    30933577  conn->num_bytes_sent += mg_write(conn, buf + headers_len,
    30943578                                   (size_t)(data_len - headers_len));
    30953579
    30963580  // Read the rest of CGI output and send to the client
    3097   send_file_data(conn, out, INT64_MAX);
     3581  send_file_data(conn, &fout, 0, INT64_MAX);
    30983582
    30993583done:
     
    31013585    kill(pid, SIGKILL);
    31023586  }
    3103   if (fd_stdin[0] != -1) {
    3104     (void) close(fd_stdin[0]);
    3105   }
    3106   if (fd_stdout[1] != -1) {
    3107     (void) close(fd_stdout[1]);
     3587  if (fdin[0] != -1) {
     3588    close(fdin[0]);
     3589  }
     3590  if (fdout[1] != -1) {
     3591    close(fdout[1]);
    31083592  }
    31093593
    31103594  if (in != NULL) {
    3111     (void) fclose(in);
    3112   } else if (fd_stdin[1] != -1) {
    3113     (void) close(fd_stdin[1]);
     3595    fclose(in);
     3596  } else if (fdin[1] != -1) {
     3597    close(fdin[1]);
    31143598  }
    31153599
    31163600  if (out != NULL) {
    3117     (void) fclose(out);
    3118   } else if (fd_stdout[0] != -1) {
    3119     (void) close(fd_stdout[0]);
     3601    fclose(out);
     3602  } else if (fdout[0] != -1) {
     3603    close(fdout[0]);
    31203604  }
    31213605}
     
    31253609// for given path. Return 0 if the path itself is a directory,
    31263610// or -1 on error, 1 if OK.
    3127 static int put_dir(const char *path) {
     3611static int put_dir(struct mg_connection *conn, const char *path) {
    31283612  char buf[PATH_MAX];
    31293613  const char *s, *p;
    3130   struct mgstat st;
     3614  struct file file = STRUCT_FILE_INITIALIZER;
    31313615  int len, res = 1;
    31323616
    3133   for (s = p = path + 2; (p = strchr(s, DIRSEP)) != NULL; s = ++p) {
     3617  for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
    31343618    len = p - path;
    31353619    if (len >= (int) sizeof(buf)) {
     
    31423626    // Try to create intermediate directory
    31433627    DEBUG_TRACE(("mkdir(%s)", buf));
    3144     if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0) {
     3628    if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
    31453629      res = -1;
    31463630      break;
     
    31563640}
    31573641
     3642static void mkcol(struct mg_connection *conn, const char *path) {
     3643  int rc, body_len;
     3644  struct de de;
     3645  memset(&de.file, 0, sizeof(de.file));
     3646  mg_stat(conn, path, &de.file);
     3647
     3648  if(de.file.modification_time) {
     3649      send_http_error(conn, 405, "Method Not Allowed",
     3650                      "mkcol(%s): %s", path, strerror(ERRNO));
     3651      return;
     3652  }
     3653
     3654  body_len = conn->data_len - conn->request_len;
     3655  if(body_len > 0) {
     3656      send_http_error(conn, 415, "Unsupported media type",
     3657                      "mkcol(%s): %s", path, strerror(ERRNO));
     3658      return;
     3659  }
     3660
     3661  rc = mg_mkdir(path, 0755);
     3662
     3663  if (rc == 0) {
     3664    conn->status_code = 201;
     3665    mg_printf(conn, "HTTP/1.1 %d Created\r\n\r\n", conn->status_code);
     3666  } else if (rc == -1) {
     3667      if(errno == EEXIST)
     3668        send_http_error(conn, 405, "Method Not Allowed",
     3669                      "mkcol(%s): %s", path, strerror(ERRNO));
     3670      else if(errno == EACCES)
     3671          send_http_error(conn, 403, "Forbidden",
     3672                        "mkcol(%s): %s", path, strerror(ERRNO));
     3673      else if(errno == ENOENT)
     3674          send_http_error(conn, 409, "Conflict",
     3675                        "mkcol(%s): %s", path, strerror(ERRNO));
     3676      else
     3677          send_http_error(conn, 500, http_500_error,
     3678                          "fopen(%s): %s", path, strerror(ERRNO));
     3679  }
     3680}
     3681
    31583682static void put_file(struct mg_connection *conn, const char *path) {
    3159   struct mgstat st;
     3683  struct file file = STRUCT_FILE_INITIALIZER;
    31603684  const char *range;
    31613685  int64_t r1, r2;
    3162   FILE *fp;
    31633686  int rc;
    31643687
    3165   conn->request_info.status_code = mg_stat(path, &st) == 0 ? 200 : 201;
    3166 
    3167   if ((rc = put_dir(path)) == 0) {
    3168     mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->request_info.status_code);
     3688  conn->status_code = mg_stat(conn, path, &file) ? 200 : 201;
     3689
     3690  if ((rc = put_dir(conn, path)) == 0) {
     3691    mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
    31693692  } else if (rc == -1) {
    31703693    send_http_error(conn, 500, http_500_error,
    3171         "put_dir(%s): %s", path, strerror(ERRNO));
    3172   } else if ((fp = mg_fopen(path, "wb+")) == NULL) {
     3694                    "put_dir(%s): %s", path, strerror(ERRNO));
     3695  } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
     3696    mg_fclose(&file);
    31733697    send_http_error(conn, 500, http_500_error,
    3174         "fopen(%s): %s", path, strerror(ERRNO));
     3698                    "fopen(%s): %s", path, strerror(ERRNO));
    31753699  } else {
    3176     set_close_on_exec(fileno(fp));
     3700    fclose_on_exec(&file);
    31773701    range = mg_get_header(conn, "Content-Range");
    31783702    r1 = r2 = 0;
    31793703    if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
    3180       conn->request_info.status_code = 206;
    3181       // TODO(lsm): handle seek error
    3182       (void) fseeko(fp, (off_t) r1, SEEK_SET);
    3183     }
    3184     if (forward_body_data(conn, fp, INVALID_SOCKET, NULL))
    3185       (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n",
    3186           conn->request_info.status_code);
    3187     (void) fclose(fp);
    3188   }
    3189 }
    3190 
    3191 static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
     3704      conn->status_code = 206;
     3705      fseeko(file.fp, r1, SEEK_SET);
     3706    }
     3707    if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
     3708      conn->status_code = 500;
     3709    }
     3710    mg_printf(conn, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
     3711              conn->status_code);
     3712    mg_fclose(&file);
     3713  }
     3714}
     3715
     3716static void send_ssi_file(struct mg_connection *, const char *,
     3717                          struct file *, int);
    31923718
    31933719static void do_ssi_include(struct mg_connection *conn, const char *ssi,
    31943720                           char *tag, int include_level) {
    3195   char file_name[BUFSIZ], path[PATH_MAX], *p;
    3196   FILE *fp;
     3721  char file_name[MG_BUF_LEN], path[PATH_MAX], *p;
     3722  struct file file = STRUCT_FILE_INITIALIZER;
    31973723
    31983724  // sscanf() is safe here, since send_ssi_file() also uses buffer
    3199   // of size BUFSIZ to get the tag. So strlen(tag) is always < BUFSIZ.
     3725  // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
    32003726  if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
    32013727    // File name is relative to the webserver root
    32023728    (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s",
    3203         conn->ctx->config[DOCUMENT_ROOT], DIRSEP, file_name);
    3204   } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) {
     3729        conn->ctx->config[DOCUMENT_ROOT], '/', file_name);
     3730  } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
    32053731    // File name is relative to the webserver working directory
    32063732    // or it is absolute system path
    32073733    (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name);
    3208   } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
     3734  } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
     3735             sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
    32093736    // File name is relative to the currect document
    32103737    (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi);
    3211     if ((p = strrchr(path, DIRSEP)) != NULL) {
     3738    if ((p = strrchr(path, '/')) != NULL) {
    32123739      p[1] = '\0';
    32133740    }
     
    32193746  }
    32203747
    3221   if ((fp = mg_fopen(path, "rb")) == NULL) {
     3748  if (!mg_fopen(conn, path, "rb", &file)) {
    32223749    cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
    32233750        tag, path, strerror(ERRNO));
    32243751  } else {
    3225     set_close_on_exec(fileno(fp));
     3752    fclose_on_exec(&file);
    32263753    if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
    32273754                     strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
    3228       send_ssi_file(conn, path, fp, include_level + 1);
     3755      send_ssi_file(conn, path, &file, include_level + 1);
    32293756    } else {
    3230       send_file_data(conn, fp, INT64_MAX);
    3231     }
    3232     (void) fclose(fp);
     3757      send_file_data(conn, &file, 0, INT64_MAX);
     3758    }
     3759    mg_fclose(&file);
    32333760  }
    32343761}
     
    32363763#if !defined(NO_POPEN)
    32373764static void do_ssi_exec(struct mg_connection *conn, char *tag) {
    3238   char cmd[BUFSIZ];
    3239   FILE *fp;
     3765  char cmd[MG_BUF_LEN];
     3766  struct file file = STRUCT_FILE_INITIALIZER;
    32403767
    32413768  if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
    32423769    cry(conn, "Bad SSI #exec: [%s]", tag);
    3243   } else if ((fp = popen(cmd, "r")) == NULL) {
     3770  } else if ((file.fp = popen(cmd, "r")) == NULL) {
    32443771    cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
    32453772  } else {
    3246     send_file_data(conn, fp, INT64_MAX);
    3247     (void) pclose(fp);
     3773    send_file_data(conn, &file, 0, INT64_MAX);
     3774    pclose(file.fp);
    32483775  }
    32493776}
    32503777#endif // !NO_POPEN
    32513778
     3779static int mg_fgetc(struct file *filep, int offset) {
     3780  if (filep->membuf != NULL && offset >=0 && offset < filep->size) {
     3781    return ((unsigned char *) filep->membuf)[offset];
     3782  } else if (filep->fp != NULL) {
     3783    return fgetc(filep->fp);
     3784  } else {
     3785    return EOF;
     3786  }
     3787}
     3788
    32523789static void send_ssi_file(struct mg_connection *conn, const char *path,
    3253                           FILE *fp, int include_level) {
    3254   char buf[BUFSIZ];
    3255   int ch, len, in_ssi_tag;
     3790                          struct file *filep, int include_level) {
     3791  char buf[MG_BUF_LEN];
     3792  int ch, offset, len, in_ssi_tag;
    32563793
    32573794  if (include_level > 10) {
     
    32603797  }
    32613798
    3262   in_ssi_tag = 0;
    3263   len = 0;
    3264 
    3265   while ((ch = fgetc(fp)) != EOF) {
     3799  in_ssi_tag = len = offset = 0;
     3800  while ((ch = mg_fgetc(filep, offset)) != EOF) {
    32663801    if (in_ssi_tag && ch == '>') {
    32673802      in_ssi_tag = 0;
     
    32713806      if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
    32723807        // Not an SSI tag, pass it
    3273         (void) mg_write(conn, buf, (size_t)len);
     3808        (void) mg_write(conn, buf, (size_t) len);
    32743809      } else {
    32753810        if (!memcmp(buf + 5, "include", 7)) {
     
    32963831      in_ssi_tag = 1;
    32973832      if (len > 0) {
    3298         (void) mg_write(conn, buf, (size_t)len);
     3833        mg_write(conn, buf, (size_t) len);
    32993834      }
    33003835      len = 0;
     
    33033838      buf[len++] = ch & 0xff;
    33043839      if (len == (int) sizeof(buf)) {
    3305         (void) mg_write(conn, buf, (size_t)len);
     3840        mg_write(conn, buf, (size_t) len);
    33063841        len = 0;
    33073842      }
     
    33113846  // Send the rest of buffered data
    33123847  if (len > 0) {
    3313     (void) mg_write(conn, buf, (size_t)len);
     3848    mg_write(conn, buf, (size_t) len);
    33143849  }
    33153850}
     
    33173852static void handle_ssi_file_request(struct mg_connection *conn,
    33183853                                    const char *path) {
    3319   FILE *fp;
    3320 
    3321   if ((fp = mg_fopen(path, "rb")) == NULL) {
     3854  struct file file = STRUCT_FILE_INITIALIZER;
     3855
     3856  if (!mg_fopen(conn, path, "rb", &file)) {
    33223857    send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
    33233858                    strerror(ERRNO));
    33243859  } else {
    33253860    conn->must_close = 1;
    3326     set_close_on_exec(fileno(fp));
     3861    fclose_on_exec(&file);
    33273862    mg_printf(conn, "HTTP/1.1 200 OK\r\n"
    33283863              "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
    33293864              suggest_connection_header(conn));
    3330     send_ssi_file(conn, path, fp, 0);
    3331     (void) fclose(fp);
     3865    send_ssi_file(conn, path, &file, 0);
     3866    mg_fclose(&file);
    33323867  }
    33333868}
    33343869
    33353870static void send_options(struct mg_connection *conn) {
    3336   conn->request_info.status_code = 200;
    3337 
    3338   (void) mg_printf(conn,
    3339       "HTTP/1.1 200 OK\r\n"
    3340       "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n"
    3341       "DAV: 1\r\n\r\n");
     3871  conn->status_code = 200;
     3872
     3873  mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n"
     3874            "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
     3875            "DAV: 1\r\n\r\n");
    33423876}
    33433877
    33443878// Writes PROPFIND properties for a collection element
    33453879static void print_props(struct mg_connection *conn, const char* uri,
    3346                         struct mgstat* st) {
     3880                        struct file *filep) {
    33473881  char mtime[64];
    3348   gmt_time_string(mtime, sizeof(mtime), &st->mtime);
     3882  gmt_time_string(mtime, sizeof(mtime), &filep->modification_time);
    33493883  conn->num_bytes_sent += mg_printf(conn,
    33503884      "<d:response>"
     
    33603894      "</d:response>\n",
    33613895      uri,
    3362       st->is_directory ? "<d:collection/>" : "",
    3363       st->size,
     3896      filep->is_directory ? "<d:collection/>" : "",
     3897      filep->size,
    33643898      mtime);
    33653899}
     
    33673901static void print_dav_dir_entry(struct de *de, void *data) {
    33683902  char href[PATH_MAX];
     3903  char href_encoded[PATH_MAX];
    33693904  struct mg_connection *conn = (struct mg_connection *) data;
    33703905  mg_snprintf(conn, href, sizeof(href), "%s%s",
    33713906              conn->request_info.uri, de->file_name);
    3372   print_props(conn, href, &de->st);
    3373 }
    3374 
    3375 static void handle_propfind(struct mg_connection *conn, const char* path,
    3376                             struct mgstat* st) {
     3907  mg_url_encode(href, href_encoded, PATH_MAX-1);
     3908  print_props(conn, href_encoded, &de->file);
     3909}
     3910
     3911static void handle_propfind(struct mg_connection *conn, const char *path,
     3912                            struct file *filep) {
    33773913  const char *depth = mg_get_header(conn, "Depth");
    33783914
    33793915  conn->must_close = 1;
    3380   conn->request_info.status_code = 207;
     3916  conn->status_code = 207;
    33813917  mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
    33823918            "Connection: close\r\n"
     
    33883924
    33893925  // Print properties for the requested resource itself
    3390   print_props(conn, conn->request_info.uri, st);
     3926  print_props(conn, conn->request_info.uri, filep);
    33913927
    33923928  // If it is a directory, print directory entries too if Depth is not 0
    3393   if (st->is_directory &&
     3929  if (filep->is_directory &&
    33943930      !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
    33953931      (depth == NULL || strcmp(depth, "0") != 0)) {
     
    33983934
    33993935  conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
     3936}
     3937
     3938#if defined(USE_WEBSOCKET)
     3939
     3940// START OF SHA-1 code
     3941// Copyright(c) By Steve Reid <steve@edmweb.com>
     3942#define SHA1HANDSOFF
     3943#if defined(__sun)
     3944#include "solarisfixes.h"
     3945#endif
     3946
     3947union char64long16 { unsigned char c[64]; uint32_t l[16]; };
     3948
     3949#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
     3950
     3951static uint32_t blk0(union char64long16 *block, int i) {
     3952  // Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN
     3953  if (!is_big_endian()) {
     3954    block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
     3955      (rol(block->l[i], 8) & 0x00FF00FF);
     3956  }
     3957  return block->l[i];
     3958}
     3959
     3960#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
     3961    ^block->l[(i+2)&15]^block->l[i&15],1))
     3962#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
     3963#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
     3964#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
     3965#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
     3966#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
     3967
     3968typedef struct {
     3969    uint32_t state[5];
     3970    uint32_t count[2];
     3971    unsigned char buffer[64];
     3972} SHA1_CTX;
     3973
     3974static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
     3975  uint32_t a, b, c, d, e;
     3976  union char64long16 block[1];
     3977
     3978  memcpy(block, buffer, 64);
     3979  a = state[0];
     3980  b = state[1];
     3981  c = state[2];
     3982  d = state[3];
     3983  e = state[4];
     3984  R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
     3985  R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
     3986  R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
     3987  R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
     3988  R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
     3989  R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
     3990  R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
     3991  R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
     3992  R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
     3993  R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
     3994  R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
     3995  R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
     3996  R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
     3997  R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
     3998  R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
     3999  R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
     4000  R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
     4001  R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
     4002  R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
     4003  R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
     4004  state[0] += a;
     4005  state[1] += b;
     4006  state[2] += c;
     4007  state[3] += d;
     4008  state[4] += e;
     4009  a = b = c = d = e = 0;
     4010  memset(block, '\0', sizeof(block));
     4011}
     4012
     4013static void SHA1Init(SHA1_CTX* context) {
     4014  context->state[0] = 0x67452301;
     4015  context->state[1] = 0xEFCDAB89;
     4016  context->state[2] = 0x98BADCFE;
     4017  context->state[3] = 0x10325476;
     4018  context->state[4] = 0xC3D2E1F0;
     4019  context->count[0] = context->count[1] = 0;
     4020}
     4021
     4022static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
     4023                       uint32_t len) {
     4024  uint32_t i, j;
     4025
     4026  j = context->count[0];
     4027  if ((context->count[0] += len << 3) < j)
     4028    context->count[1]++;
     4029  context->count[1] += (len>>29);
     4030  j = (j >> 3) & 63;
     4031  if ((j + len) > 63) {
     4032    memcpy(&context->buffer[j], data, (i = 64-j));
     4033    SHA1Transform(context->state, context->buffer);
     4034    for ( ; i + 63 < len; i += 64) {
     4035      SHA1Transform(context->state, &data[i]);
     4036    }
     4037    j = 0;
     4038  }
     4039  else i = 0;
     4040  memcpy(&context->buffer[j], &data[i], len - i);
     4041}
     4042
     4043static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
     4044  unsigned i;
     4045  unsigned char finalcount[8], c;
     4046
     4047  for (i = 0; i < 8; i++) {
     4048    finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
     4049                                     >> ((3-(i & 3)) * 8) ) & 255);
     4050  }
     4051  c = 0200;
     4052  SHA1Update(context, &c, 1);
     4053  while ((context->count[0] & 504) != 448) {
     4054    c = 0000;
     4055    SHA1Update(context, &c, 1);
     4056  }
     4057  SHA1Update(context, finalcount, 8);
     4058  for (i = 0; i < 20; i++) {
     4059    digest[i] = (unsigned char)
     4060      ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
     4061  }
     4062  memset(context, '\0', sizeof(*context));
     4063  memset(&finalcount, '\0', sizeof(finalcount));
     4064}
     4065// END OF SHA1 CODE
     4066
     4067static void base64_encode(const unsigned char *src, int src_len, char *dst) {
     4068  static const char *b64 =
     4069    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     4070  int i, j, a, b, c;
     4071
     4072  for (i = j = 0; i < src_len; i += 3) {
     4073    a = src[i];
     4074    b = i + 1 >= src_len ? 0 : src[i + 1];
     4075    c = i + 2 >= src_len ? 0 : src[i + 2];
     4076
     4077    dst[j++] = b64[a >> 2];
     4078    dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
     4079    if (i + 1 < src_len) {
     4080      dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
     4081    }
     4082    if (i + 2 < src_len) {
     4083      dst[j++] = b64[c & 63];
     4084    }
     4085  }
     4086  while (j % 4 != 0) {
     4087    dst[j++] = '=';
     4088  }
     4089  dst[j++] = '\0';
     4090}
     4091
     4092static void send_websocket_handshake(struct mg_connection *conn) {
     4093  static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
     4094  char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
     4095  SHA1_CTX sha_ctx;
     4096
     4097  mg_snprintf(conn, buf, sizeof(buf), "%s%s",
     4098              mg_get_header(conn, "Sec-WebSocket-Key"), magic);
     4099  SHA1Init(&sha_ctx);
     4100  SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
     4101  SHA1Final((unsigned char *) sha, &sha_ctx);
     4102  base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
     4103  mg_printf(conn, "%s%s%s",
     4104            "HTTP/1.1 101 Switching Protocols\r\n"
     4105            "Upgrade: websocket\r\n"
     4106            "Connection: Upgrade\r\n"
     4107            "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
     4108}
     4109
     4110static void read_websocket(struct mg_connection *conn) {
     4111  // Pointer to the beginning of the portion of the incoming websocket message
     4112  // queue. The original websocket upgrade request is never removed,
     4113  // so the queue begins after it.
     4114  unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
     4115  int bits, n, stop = 0;
     4116  size_t i, len, mask_len, data_len, header_len, body_len;
     4117  // data points to the place where the message is stored when passed to the
     4118  // websocket_data callback. This is either mem on the stack,
     4119  // or a dynamically allocated buffer if it is too large.
     4120  char mem[4 * 1024], mask[4], *data;
     4121
     4122  assert(conn->content_len == 0);
     4123
     4124  // Loop continuously, reading messages from the socket, invoking the callback,
     4125  // and waiting repeatedly until an error occurs.
     4126  while (!stop) {
     4127    header_len = 0;
     4128    // body_len is the length of the entire queue in bytes
     4129    // len is the length of the current message
     4130    // data_len is the length of the current message's data payload
     4131    // header_len is the length of the current message's header
     4132    if ((body_len = conn->data_len - conn->request_len) >= 2) {
     4133      len = buf[1] & 127;
     4134      mask_len = buf[1] & 128 ? 4 : 0;
     4135      if (len < 126 && body_len >= mask_len) {
     4136        data_len = len;
     4137        header_len = 2 + mask_len;
     4138      } else if (len == 126 && body_len >= 4 + mask_len) {
     4139        header_len = 4 + mask_len;
     4140        data_len = ((((int) buf[2]) << 8) + buf[3]);
     4141      } else if (body_len >= 10 + mask_len) {
     4142        header_len = 10 + mask_len;
     4143        data_len = (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
     4144          htonl(* (uint32_t *) &buf[6]);
     4145      }
     4146    }
     4147
     4148    // Data layout is as follows:
     4149    //  conn->buf               buf
     4150    //     v                     v              frame1           | frame2
     4151    //     |---------------------|----------------|--------------|-------
     4152    //     |                     |<--header_len-->|<--data_len-->|
     4153    //     |<-conn->request_len->|<-----body_len----------->|
     4154    //     |<-------------------conn->data_len------------->|
     4155
     4156    if (header_len > 0) {
     4157      // Allocate space to hold websocket payload
     4158      data = mem;
     4159      if (data_len > sizeof(mem) && (data = malloc(data_len)) == NULL) {
     4160        // Allocation failed, exit the loop and then close the connection
     4161        // TODO: notify user about the failure
     4162        break;
     4163      }
     4164
     4165      // Save mask and bits, otherwise it may be clobbered by memmove below
     4166      bits = buf[0];
     4167      memcpy(mask, buf + header_len - mask_len, mask_len);
     4168
     4169      // Read frame payload into the allocated buffer.
     4170      assert(body_len >= header_len);
     4171      if (data_len + header_len > body_len) {
     4172        len = body_len - header_len;
     4173        memcpy(data, buf + header_len, len);
     4174        // TODO: handle pull error
     4175        pull_all(NULL, conn, data + len, data_len - len);
     4176        conn->data_len = conn->request_len;
     4177      } else {
     4178        len = data_len + header_len;
     4179        memcpy(data, buf + header_len, data_len);
     4180        memmove(buf, buf + len, body_len - len);
     4181        conn->data_len -= len;
     4182      }
     4183
     4184      // Apply mask if necessary
     4185      if (mask_len > 0) {
     4186        for (i = 0; i < data_len; i++) {
     4187          data[i] ^= mask[i % 4];
     4188        }
     4189      }
     4190
     4191      // Exit the loop if callback signalled to exit,
     4192      // or "connection close" opcode received.
     4193      if ((bits & WEBSOCKET_OPCODE_CONNECTION_CLOSE) ||
     4194          (conn->ctx->callbacks.websocket_data != NULL &&
     4195           !conn->ctx->callbacks.websocket_data(conn, bits, data, data_len))) {
     4196        stop = 1;
     4197      }
     4198
     4199      if (data != mem) {
     4200        free(data);
     4201      }
     4202      // Not breaking the loop, process next websocket frame.
     4203    } else {
     4204      // Buffering websocket request
     4205      if ((n = pull(NULL, conn, conn->buf + conn->data_len,
     4206                    conn->buf_size - conn->data_len)) <= 0) {
     4207        break;
     4208      }
     4209      conn->data_len += n;
     4210    }
     4211  }
     4212}
     4213
     4214int mg_websocket_write(struct mg_connection* conn, int opcode,
     4215                       const char *data, size_t data_len) {
     4216    unsigned char *copy;
     4217    size_t copy_len = 0;
     4218    int retval = -1;
     4219
     4220    if ((copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
     4221      return -1;
     4222    }
     4223
     4224    copy[0] = 0x80 + (opcode & 0x0f);
     4225
     4226    // Frame format: http://tools.ietf.org/html/rfc6455#section-5.2
     4227    if (data_len < 126) {
     4228      // Inline 7-bit length field
     4229      copy[1] = data_len;
     4230      memcpy(copy + 2, data, data_len);
     4231      copy_len = 2 + data_len;
     4232    } else if (data_len <= 0xFFFF) {
     4233      // 16-bit length field
     4234      copy[1] = 126;
     4235      * (uint16_t *) (copy + 2) = htons(data_len);
     4236      memcpy(copy + 4, data, data_len);
     4237      copy_len = 4 + data_len;
     4238    } else {
     4239      // 64-bit length field
     4240      copy[1] = 127;
     4241      * (uint32_t *) (copy + 2) = htonl((uint64_t) data_len >> 32);
     4242      * (uint32_t *) (copy + 6) = htonl(data_len & 0xffffffff);
     4243      memcpy(copy + 10, data, data_len);
     4244      copy_len = 10 + data_len;
     4245    }
     4246
     4247    // Not thread safe
     4248    if (copy_len > 0) {
     4249      retval = mg_write(conn, copy, copy_len);
     4250    }
     4251    free(copy);
     4252
     4253    return retval;
     4254}
     4255
     4256static void handle_websocket_request(struct mg_connection *conn) {
     4257  const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
     4258  if (version == NULL || strcmp(version, "13") != 0) {
     4259    send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
     4260  } else if (conn->ctx->callbacks.websocket_connect != NULL &&
     4261             conn->ctx->callbacks.websocket_connect(conn) != 0) {
     4262    // Callback has returned non-zero, do not proceed with handshake
     4263  } else {
     4264    send_websocket_handshake(conn);
     4265    if (conn->ctx->callbacks.websocket_ready != NULL) {
     4266      conn->ctx->callbacks.websocket_ready(conn);
     4267    }
     4268    read_websocket(conn);
     4269  }
     4270}
     4271
     4272static int is_websocket_request(const struct mg_connection *conn) {
     4273  const char *host, *upgrade, *connection, *version, *key;
     4274
     4275  host = mg_get_header(conn, "Host");
     4276  upgrade = mg_get_header(conn, "Upgrade");
     4277  connection = mg_get_header(conn, "Connection");
     4278  key = mg_get_header(conn, "Sec-WebSocket-Key");
     4279  version = mg_get_header(conn, "Sec-WebSocket-Version");
     4280
     4281  return host != NULL && upgrade != NULL && connection != NULL &&
     4282    key != NULL && version != NULL &&
     4283    mg_strcasestr(upgrade, "websocket") != NULL &&
     4284    mg_strcasestr(connection, "Upgrade") != NULL;
     4285}
     4286#endif // !USE_WEBSOCKET
     4287
     4288static int isbyte(int n) {
     4289  return n >= 0 && n <= 255;
     4290}
     4291
     4292static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
     4293  int n, a, b, c, d, slash = 32, len = 0;
     4294
     4295  if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
     4296      sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
     4297      isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
     4298      slash >= 0 && slash < 33) {
     4299    len = n;
     4300    *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
     4301    *mask = slash ? 0xffffffffU << (32 - slash) : 0;
     4302  }
     4303
     4304  return len;
     4305}
     4306
     4307static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) {
     4308  int throttle = 0;
     4309  struct vec vec, val;
     4310  uint32_t net, mask;
     4311  char mult;
     4312  double v;
     4313
     4314  while ((spec = next_option(spec, &vec, &val)) != NULL) {
     4315    mult = ',';
     4316    if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0 ||
     4317        (lowercase(&mult) != 'k' && lowercase(&mult) != 'm' && mult != ',')) {
     4318      continue;
     4319    }
     4320    v *= lowercase(&mult) == 'k' ? 1024 : lowercase(&mult) == 'm' ? 1048576 : 1;
     4321    if (vec.len == 1 && vec.ptr[0] == '*') {
     4322      throttle = (int) v;
     4323    } else if (parse_net(vec.ptr, &net, &mask) > 0) {
     4324      if ((remote_ip & mask) == net) {
     4325        throttle = (int) v;
     4326      }
     4327    } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
     4328      throttle = (int) v;
     4329    }
     4330  }
     4331
     4332  return throttle;
     4333}
     4334
     4335static uint32_t get_remote_ip(const struct mg_connection *conn) {
     4336  return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
     4337}
     4338
     4339#ifdef USE_LUA
     4340#include "mod_lua.c"
     4341#endif // USE_LUA
     4342
     4343int mg_upload(struct mg_connection *conn, const char *destination_dir) {
     4344  const char *content_type_header, *boundary_start;
     4345  char buf[MG_BUF_LEN], path[PATH_MAX], fname[1024], boundary[100], *s;
     4346  FILE *fp;
     4347  int bl, n, i, j, headers_len, boundary_len, eof,
     4348      len = 0, num_uploaded_files = 0;
     4349
     4350  // Request looks like this:
     4351  //
     4352  // POST /upload HTTP/1.1
     4353  // Host: 127.0.0.1:8080
     4354  // Content-Length: 244894
     4355  // Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRVr
     4356  //
     4357  // ------WebKitFormBoundaryRVr
     4358  // Content-Disposition: form-data; name="file"; filename="accum.png"
     4359  // Content-Type: image/png
     4360  //
     4361  //  <89>PNG
     4362  //  <PNG DATA>
     4363  // ------WebKitFormBoundaryRVr
     4364
     4365  // Extract boundary string from the Content-Type header
     4366  if ((content_type_header = mg_get_header(conn, "Content-Type")) == NULL ||
     4367      (boundary_start = mg_strcasestr(content_type_header,
     4368                                      "boundary=")) == NULL ||
     4369      (sscanf(boundary_start, "boundary=\"%99[^\"]\"", boundary) == 0 &&
     4370       sscanf(boundary_start, "boundary=%99s", boundary) == 0) ||
     4371      boundary[0] == '\0') {
     4372    return num_uploaded_files;
     4373  }
     4374
     4375  boundary_len = strlen(boundary);
     4376  bl = boundary_len + 4;  // \r\n--<boundary>
     4377  for (;;) {
     4378    // Pull in headers
     4379    assert(len >= 0 && len <= (int) sizeof(buf));
     4380    while ((n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0) {
     4381      len += n;
     4382    }
     4383    if ((headers_len = get_request_len(buf, len)) <= 0) {
     4384      break;
     4385    }
     4386
     4387    // Fetch file name.
     4388    fname[0] = '\0';
     4389    for (i = j = 0; i < headers_len; i++) {
     4390      if (buf[i] == '\r' && buf[i + 1] == '\n') {
     4391        buf[i] = buf[i + 1] = '\0';
     4392        // TODO(lsm): don't expect filename to be the 3rd field,
     4393        // parse the header properly instead.
     4394        sscanf(&buf[j], "Content-Disposition: %*s %*s filename=\"%1023[^\"]",
     4395               fname);
     4396        j = i + 2;
     4397      }
     4398    }
     4399
     4400    // Give up if the headers are not what we expect
     4401    if (fname[0] == '\0') {
     4402      break;
     4403    }
     4404
     4405    // Move data to the beginning of the buffer
     4406    assert(len >= headers_len);
     4407    memmove(buf, &buf[headers_len], len - headers_len);
     4408    len -= headers_len;
     4409
     4410    // We open the file with exclusive lock held. This guarantee us
     4411    // there is no other thread can save into the same file simultaneously.
     4412    fp = NULL;
     4413    // Construct destination file name. Do not allow paths to have slashes.
     4414    if ((s = strrchr(fname, '/')) == NULL &&
     4415        (s = strrchr(fname, '\\')) == NULL) {
     4416      s = fname;
     4417    }
     4418
     4419    // Open file in binary mode. TODO: set an exclusive lock.
     4420    snprintf(path, sizeof(path), "%s/%s", destination_dir, s);
     4421    if ((fp = fopen(path, "wb")) == NULL) {
     4422      break;
     4423    }
     4424
     4425    // Read POST data, write into file until boundary is found.
     4426    eof = n = 0;
     4427    do {
     4428      len += n;
     4429      for (i = 0; i < len - bl; i++) {
     4430        if (!memcmp(&buf[i], "\r\n--", 4) &&
     4431            !memcmp(&buf[i + 4], boundary, boundary_len)) {
     4432          // Found boundary, that's the end of file data.
     4433          fwrite(buf, 1, i, fp);
     4434          eof = 1;
     4435          memmove(buf, &buf[i + bl], len - (i + bl));
     4436          len -= i + bl;
     4437          break;
     4438        }
     4439      }
     4440      if (!eof && len > bl) {
     4441        fwrite(buf, 1, len - bl, fp);
     4442        memmove(buf, &buf[len - bl], bl);
     4443        len = bl;
     4444      }
     4445    } while (!eof && (n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0);
     4446    fclose(fp);
     4447    if (eof) {
     4448      num_uploaded_files++;
     4449      if (conn->ctx->callbacks.upload != NULL) {
     4450        conn->ctx->callbacks.upload(conn, path);
     4451      }
     4452    }
     4453  }
     4454
     4455  return num_uploaded_files;
     4456}
     4457
     4458static int is_put_or_delete_request(const struct mg_connection *conn) {
     4459  const char *s = conn->request_info.request_method;
     4460  return s != NULL && (!strcmp(s, "PUT") ||
     4461                       !strcmp(s, "DELETE") ||
     4462                       !strcmp(s, "MKCOL"));
     4463}
     4464
     4465static int get_first_ssl_listener_index(const struct mg_context *ctx) {
     4466  int i, index = -1;
     4467  for (i = 0; index == -1 && i < ctx->num_listening_sockets; i++) {
     4468    index = ctx->listening_sockets[i].is_ssl ? i : -1;
     4469  }
     4470  return index;
     4471}
     4472
     4473static void redirect_to_https_port(struct mg_connection *conn, int ssl_index) {
     4474  char host[1025];
     4475  const char *host_header;
     4476
     4477  if ((host_header = mg_get_header(conn, "Host")) == NULL ||
     4478      sscanf(host_header, "%1024[^:]", host) == 0) {
     4479    // Cannot get host from the Host: header. Fallback to our IP address.
     4480    sockaddr_to_string(host, sizeof(host), &conn->client.lsa);
     4481  }
     4482
     4483  mg_printf(conn, "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s\r\n\r\n",
     4484            host, (int) ntohs(conn->ctx->listening_sockets[ssl_index].
     4485                              lsa.sin.sin_port), conn->request_info.uri);
    34004486}
    34014487
     
    34074493  struct mg_request_info *ri = &conn->request_info;
    34084494  char path[PATH_MAX];
    3409   int stat_result, uri_len;
    3410   struct mgstat st;
     4495  int uri_len, ssl_index;
     4496  struct file file = STRUCT_FILE_INITIALIZER;
    34114497
    34124498  if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
    3413     * conn->request_info.query_string++ = '\0';
    3414   }
    3415   uri_len = strlen(ri->uri);
    3416   url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
    3417   remove_double_dots_and_double_slashes(ri->uri);
    3418   stat_result = convert_uri_to_file_name(conn, path, sizeof(path), &st);
     4499    * ((char *) conn->request_info.query_string++) = '\0';
     4500  }
     4501  uri_len = (int) strlen(ri->uri);
     4502  mg_url_decode(ri->uri, uri_len, (char *) ri->uri, uri_len + 1, 0);
     4503  remove_double_dots_and_double_slashes((char *) ri->uri);
     4504  convert_uri_to_file_name(conn, path, sizeof(path), &file);
     4505  conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
     4506                                get_remote_ip(conn), ri->uri);
    34194507
    34204508  DEBUG_TRACE(("%s", ri->uri));
    3421   if (!check_authorization(conn, path)) {
     4509  // Perform redirect and auth checks before calling begin_request() handler.
     4510  // Otherwise, begin_request() would need to perform auth checks and redirects.
     4511  if (!conn->client.is_ssl && conn->client.ssl_redir &&
     4512      (ssl_index = get_first_ssl_listener_index(conn->ctx)) > -1) {
     4513    redirect_to_https_port(conn, ssl_index);
     4514  } else if (!is_put_or_delete_request(conn) &&
     4515             !check_authorization(conn, path)) {
    34224516    send_authorization_request(conn);
    3423   } else if (call_user(conn, MG_NEW_REQUEST) != NULL) {
     4517  } else if (conn->ctx->callbacks.begin_request != NULL &&
     4518      conn->ctx->callbacks.begin_request(conn)) {
    34244519    // Do nothing, callback has served the request
     4520#if defined(USE_WEBSOCKET)
     4521  } else if (is_websocket_request(conn)) {
     4522    handle_websocket_request(conn);
     4523#endif
    34254524  } else if (!strcmp(ri->request_method, "OPTIONS")) {
    34264525    send_options(conn);
    3427   } else if (strstr(path, PASSWORDS_FILE_NAME)) {
    3428     // Do not allow to view passwords files
    3429     send_http_error(conn, 403, "Forbidden", "Access Forbidden");
    34304526  } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
    34314527    send_http_error(conn, 404, "Not Found", "Not Found");
    3432   } else if ((!strcmp(ri->request_method, "PUT") ||
    3433         !strcmp(ri->request_method, "DELETE")) &&
    3434       (conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ||
    3435        !is_authorized_for_put(conn))) {
     4528  } else if (is_put_or_delete_request(conn) &&
     4529             (is_authorized_for_put(conn) != 1)) {
    34364530    send_authorization_request(conn);
    34374531  } else if (!strcmp(ri->request_method, "PUT")) {
    34384532    put_file(conn, path);
     4533  } else if (!strcmp(ri->request_method, "MKCOL")) {
     4534    mkcol(conn, path);
    34394535  } else if (!strcmp(ri->request_method, "DELETE")) {
    3440     if (mg_remove(path) == 0) {
    3441       send_http_error(conn, 200, "OK", "");
    3442     } else {
    3443       send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
    3444                       strerror(ERRNO));
    3445     }
    3446   } else if (stat_result != 0) {
     4536      struct de de;
     4537      memset(&de.file, 0, sizeof(de.file));
     4538      if(!mg_stat(conn, path, &de.file)) {
     4539          send_http_error(conn, 404, "Not Found", "%s", "File not found");
     4540      } else {
     4541          if(de.file.modification_time) {
     4542              if(de.file.is_directory) {
     4543                  remove_directory(conn, path);
     4544                  send_http_error(conn, 204, "No Content", "%s", "");
     4545              } else if (mg_remove(path) == 0) {
     4546                  send_http_error(conn, 204, "No Content", "%s", "");
     4547              } else {
     4548                  send_http_error(conn, 423, "Locked", "remove(%s): %s", path,
     4549                          strerror(ERRNO));
     4550              }
     4551          }
     4552          else {
     4553              send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
     4554                    strerror(ERRNO));
     4555          }
     4556      }
     4557  } else if ((file.membuf == NULL && file.modification_time == (time_t) 0) ||
     4558             must_hide_file(conn, path)) {
    34474559    send_http_error(conn, 404, "Not Found", "%s", "File not found");
    3448   } else if (st.is_directory && ri->uri[uri_len - 1] != '/') {
    3449     (void) mg_printf(conn,
    3450         "HTTP/1.1 301 Moved Permanently\r\n"
    3451         "Location: %s/\r\n\r\n", ri->uri);
     4560  } else if (file.is_directory && ri->uri[uri_len - 1] != '/') {
     4561    mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"
     4562              "Location: %s/\r\n\r\n", ri->uri);
    34524563  } else if (!strcmp(ri->request_method, "PROPFIND")) {
    3453     handle_propfind(conn, path, &st);
    3454   } else if (st.is_directory &&
    3455              !substitute_index_file(conn, path, sizeof(path), &st)) {
     4564    handle_propfind(conn, path, &file);
     4565  } else if (file.is_directory &&
     4566             !substitute_index_file(conn, path, sizeof(path), &file)) {
    34564567    if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
    34574568      handle_directory_request(conn, path);
     
    34604571          "Directory listing denied");
    34614572    }
     4573#ifdef USE_LUA
     4574  } else if (match_prefix("**.lp$", 6, path) > 0) {
     4575    handle_lsp_request(conn, path, &file, NULL);
     4576#endif
    34624577#if !defined(NO_CGI)
    34634578  } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
     
    34654580                          path) > 0) {
    34664581    if (strcmp(ri->request_method, "POST") &&
     4582        strcmp(ri->request_method, "HEAD") &&
    34674583        strcmp(ri->request_method, "GET")) {
    34684584      send_http_error(conn, 501, "Not Implemented",
     
    34764592                          path) > 0) {
    34774593    handle_ssi_file_request(conn, path);
    3478   } else if (is_not_modified(conn, &st)) {
    3479     send_http_error(conn, 304, "Not Modified", "");
     4594  } else if (is_not_modified(conn, &file)) {
     4595    send_http_error(conn, 304, "Not Modified", "%s", "");
    34804596  } else {
    3481     handle_file_request(conn, path, &st);
     4597    handle_file_request(conn, path, &file);
    34824598  }
    34834599}
    34844600
    34854601static void close_all_listening_sockets(struct mg_context *ctx) {
    3486   struct socket *sp, *tmp;
    3487   for (sp = ctx->listening_sockets; sp != NULL; sp = tmp) {
    3488     tmp = sp->next;
    3489     (void) closesocket(sp->sock);
    3490     free(sp);
    3491   }
     4602  int i;
     4603  for (i = 0; i < ctx->num_listening_sockets; i++) {
     4604    closesocket(ctx->listening_sockets[i].sock);
     4605  }
     4606  free(ctx->listening_sockets);
     4607}
     4608
     4609static int is_valid_port(unsigned int port) {
     4610  return port > 0 && port < 0xffff;
    34924611}
    34934612
    34944613// Valid listening port specification is: [ip_address:]port[s]
    3495 // Examples: 80, 443s, 127.0.0.1:3128,1.2.3.4:8080s
     4614// Examples: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
    34964615// TODO(lsm): add parsing of the IPv6 address
    34974616static int parse_port_string(const struct vec *vec, struct socket *so) {
    3498   int a, b, c, d, port, len;
     4617  unsigned int a, b, c, d, ch, len, port;
     4618#if defined(USE_IPV6)
     4619  char buf[100];
     4620#endif
    34994621
    35004622  // MacOS needs that. If we do not zero it, subsequent bind() will fail.
     
    35024624  // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
    35034625  memset(so, 0, sizeof(*so));
    3504 
    3505   if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
    3506     // Bind to a specific IPv4 address
     4626  so->lsa.sin.sin_family = AF_INET;
     4627
     4628  if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
     4629    // Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
    35074630    so->lsa.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
    3508   } else if (sscanf(vec->ptr, "%d%n", &port, &len) != 1 ||
    3509              len <= 0 ||
    3510              len > (int) vec->len ||
    3511              (vec->ptr[len] && vec->ptr[len] != 's' && vec->ptr[len] != ',')) {
    3512     return 0;
    3513   }
    3514 
    3515   so->is_ssl = vec->ptr[len] == 's';
     4631    so->lsa.sin.sin_port = htons((uint16_t) port);
    35164632#if defined(USE_IPV6)
    3517   so->lsa.sin6.sin6_family = AF_INET6;
    3518   so->lsa.sin6.sin6_port = htons((uint16_t) port);
    3519 #else
    3520   so->lsa.sin.sin_family = AF_INET;
    3521   so->lsa.sin.sin_port = htons((uint16_t) port);
     4633
     4634  } else if (sscanf(vec->ptr, "[%49[^]]]:%d%n", buf, &port, &len) == 2 &&
     4635             inet_pton(AF_INET6, buf, &so->lsa.sin6.sin6_addr)) {
     4636    // IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
     4637    so->lsa.sin6.sin6_family = AF_INET6;
     4638    so->lsa.sin6.sin6_port = htons((uint16_t) port);
    35224639#endif
    3523 
    3524   return 1;
     4640  } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
     4641    // If only port is specified, bind to IPv4, INADDR_ANY
     4642    so->lsa.sin.sin_port = htons((uint16_t) port);
     4643  } else {
     4644    port = len = 0;   // Parsing failure. Make port invalid.
     4645  }
     4646
     4647  ch = vec->ptr[len];  // Next character after the port number
     4648  so->is_ssl = ch == 's';
     4649  so->ssl_redir = ch == 'r';
     4650
     4651  // Make sure the port is valid and vector ends with 's', 'r' or ','
     4652  return is_valid_port(port) &&
     4653    (ch == '\0' || ch == 's' || ch == 'r' || ch == ',');
    35254654}
    35264655
     
    35284657  const char *list = ctx->config[LISTENING_PORTS];
    35294658  int on = 1, success = 1;
    3530   SOCKET sock;
     4659#if defined(USE_IPV6)
     4660  int off = 0;
     4661#endif
    35314662  struct vec vec;
    3532   struct socket so, *listener;
     4663  struct socket so, *ptr;
    35334664
    35344665  while (success && (list = next_option(list, &vec, NULL)) != NULL) {
    35354666    if (!parse_port_string(&vec, &so)) {
    35364667      cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
    3537           __func__, vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]");
     4668          __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|r]");
    35384669      success = 0;
    35394670    } else if (so.is_ssl && ctx->ssl_ctx == NULL) {
    35404671      cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
    35414672      success = 0;
    3542     } else if ((sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) ==
     4673    } else if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) ==
    35434674               INVALID_SOCKET ||
    3544 #if !defined(_WIN32)
    35454675               // On Windows, SO_REUSEADDR is recommended only for
    35464676               // broadcast UDP sockets
    3547                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on,
    3548                           sizeof(on)) != 0 ||
    3549 #endif // !_WIN32
    3550                // Set TCP keep-alive. This is needed because if HTTP-level
    3551                // keep-alive is enabled, and client resets the connection,
    3552                // server won't get TCP FIN or RST and will keep the connection
    3553                // open forever. With TCP keep-alive, next keep-alive
    3554                // handshake will figure out that the client is down and
    3555                // will close the server end.
    3556                // Thanks to Igor Klopov who suggested the patch.
    3557                setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &on,
    3558                           sizeof(on)) != 0 ||
    3559                bind(sock, &so.lsa.sa, sizeof(so.lsa)) != 0 ||
    3560                listen(sock, 100) != 0) {
    3561       closesocket(sock);
    3562       cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__,
    3563           vec.len, vec.ptr, strerror(ERRNO));
     4677               setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR,
     4678                          (void *) &on, sizeof(on)) != 0 ||
     4679#if defined(USE_IPV6)
     4680               (so.lsa.sa.sa_family == AF_INET6 &&
     4681                setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &off,
     4682                           sizeof(off)) != 0) ||
     4683#endif
     4684               bind(so.sock, &so.lsa.sa, so.lsa.sa.sa_family == AF_INET ?
     4685                    sizeof(so.lsa.sin) : sizeof(so.lsa)) != 0 ||
     4686               listen(so.sock, SOMAXCONN) != 0) {
     4687      cry(fc(ctx), "%s: cannot bind to %.*s: %d (%s)", __func__,
     4688          (int) vec.len, vec.ptr, ERRNO, strerror(errno));
     4689      closesocket(so.sock);
    35644690      success = 0;
    3565     } else if ((listener = (struct socket *)
    3566                 calloc(1, sizeof(*listener))) == NULL) {
    3567       closesocket(sock);
    3568       cry(fc(ctx), "%s: %s", __func__, strerror(ERRNO));
     4691    } else if ((ptr = (struct socket *) realloc(ctx->listening_sockets,
     4692                              (ctx->num_listening_sockets + 1) *
     4693                              sizeof(ctx->listening_sockets[0]))) == NULL) {
     4694      closesocket(so.sock);
    35694695      success = 0;
    35704696    } else {
    3571       *listener = so;
    3572       listener->sock = sock;
    3573       set_close_on_exec(listener->sock);
    3574       listener->next = ctx->listening_sockets;
    3575       ctx->listening_sockets = listener;
     4697      set_close_on_exec(so.sock);
     4698      ctx->listening_sockets = ptr;
     4699      ctx->listening_sockets[ctx->num_listening_sockets] = so;
     4700      ctx->num_listening_sockets++;
    35764701    }
    35774702  }
     
    35984723  const struct mg_request_info *ri;
    35994724  FILE *fp;
    3600   char date[64], src_addr[20];
     4725  char date[64], src_addr[IP_ADDR_STR_LEN];
    36014726
    36024727  fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ?  NULL :
    3603     mg_fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
     4728    fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
    36044729
    36054730  if (fp == NULL)
     
    36174742          ri->request_method ? ri->request_method : "-",
    36184743          ri->uri ? ri->uri : "-", ri->http_version,
    3619           conn->request_info.status_code, conn->num_bytes_sent);
     4744          conn->status_code, conn->num_bytes_sent);
    36204745  log_header(conn, "Referer", fp);
    36214746  log_header(conn, "User-Agent", fp);
     
    36274752}
    36284753
    3629 static int isbyte(int n) {
    3630   return n >= 0 && n <= 255;
    3631 }
    3632 
    36334754// Verify given socket address against the ACL.
    36344755// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
    3635 static int check_acl(struct mg_context *ctx, const union usa *usa) {
    3636   int a, b, c, d, n, mask, allowed;
    3637   char flag;
    3638   uint32_t acl_subnet, acl_mask, remote_ip;
     4756static int check_acl(struct mg_context *ctx, uint32_t remote_ip) {
     4757  int allowed, flag;
     4758  uint32_t net, mask;
    36394759  struct vec vec;
    36404760  const char *list = ctx->config[ACCESS_CONTROL_LIST];
    36414761
    3642   if (list == NULL) {
    3643     return 1;
    3644   }
    3645 
    3646   (void) memcpy(&remote_ip, &usa->sin.sin_addr, sizeof(remote_ip));
    3647 
    36484762  // If any ACL is set, deny by default
    3649   allowed = '-';
     4763  allowed = list == NULL ? '+' : '-';
    36504764
    36514765  while ((list = next_option(list, &vec, NULL)) != NULL) {
    3652     mask = 32;
    3653 
    3654     if (sscanf(vec.ptr, "%c%d.%d.%d.%d%n", &flag, &a, &b, &c, &d, &n) != 5) {
     4766    flag = vec.ptr[0];
     4767    if ((flag != '+' && flag != '-') ||
     4768        parse_net(&vec.ptr[1], &net, &mask) == 0) {
    36554769      cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
    36564770      return -1;
    3657     } else if (flag != '+' && flag != '-') {
    3658       cry(fc(ctx), "%s: flag must be + or -: [%s]", __func__, vec.ptr);
    3659       return -1;
    3660     } else if (!isbyte(a)||!isbyte(b)||!isbyte(c)||!isbyte(d)) {
    3661       cry(fc(ctx), "%s: bad ip address: [%s]", __func__, vec.ptr);
    3662       return -1;
    3663     } else if (sscanf(vec.ptr + n, "/%d", &mask) == 0) {
    3664       // Do nothing, no mask specified
    3665     } else if (mask < 0 || mask > 32) {
    3666       cry(fc(ctx), "%s: bad subnet mask: %d [%s]", __func__, n, vec.ptr);
    3667       return -1;
    3668     }
    3669 
    3670     acl_subnet = (a << 24) | (b << 16) | (c << 8) | d;
    3671     acl_mask = mask ? 0xffffffffU << (32 - mask) : 0;
    3672 
    3673     if (acl_subnet == (ntohl(remote_ip) & acl_mask)) {
     4771    }
     4772
     4773    if (net == (remote_ip & mask)) {
    36744774      allowed = flag;
    36754775    }
     
    36774777
    36784778  return allowed == '+';
    3679 }
    3680 
    3681 static void add_to_set(SOCKET fd, fd_set *set, int *max_fd) {
    3682   FD_SET(fd, set);
    3683   if (fd > (SOCKET) *max_fd) {
    3684     *max_fd = (int) fd;
    3685   }
    36864779}
    36874780
     
    37134806static pthread_mutex_t *ssl_mutexes;
    37144807
     4808static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) {
     4809  return (conn->ssl = SSL_new(s)) != NULL &&
     4810    SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
     4811    func(conn->ssl) == 1;
     4812}
     4813
    37154814// Return OpenSSL error message
    37164815static const char *ssl_error(void) {
     
    37224821static void ssl_locking_callback(int mode, int mutex_num, const char *file,
    37234822                                 int line) {
    3724   line = 0;    // Unused
    3725   file = NULL; // Unused
    3726 
    3727   if (mode & CRYPTO_LOCK) {
     4823  (void) line;
     4824  (void) file;
     4825
     4826  if (mode & 1) {  // 1 is CRYPTO_LOCK
    37284827    (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
    37294828  } else {
     
    37714870// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
    37724871static int set_ssl_option(struct mg_context *ctx) {
    3773   struct mg_request_info request_info;
    3774   SSL_CTX *CTX;
    37754872  int i, size;
    3776   const char *pem = ctx->config[SSL_CERTIFICATE];
    3777   const char *chain = ctx->config[SSL_CHAIN_FILE];
    3778 
    3779   if (pem == NULL) {
     4873  const char *pem;
     4874
     4875  // If PEM file is not specified and the init_ssl callback
     4876  // is not specified, skip SSL initialization.
     4877  if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL &&
     4878      ctx->callbacks.init_ssl == NULL) {
    37804879    return 1;
    37814880  }
     
    37884887#endif // NO_SSL_DL
    37894888
    3790   // Initialize SSL crap
     4889  // Initialize SSL library
    37914890  SSL_library_init();
    37924891  SSL_load_error_strings();
    37934892
    3794   if ((CTX = SSL_CTX_new(SSLv23_server_method())) == NULL) {
    3795     cry(fc(ctx), "SSL_CTX_new error: %s", ssl_error());
    3796   } else if (ctx->user_callback != NULL) {
    3797     memset(&request_info, 0, sizeof(request_info));
    3798     request_info.user_data = ctx->user_data;
    3799     ctx->user_callback(MG_INIT_SSL, (struct mg_connection *) CTX,
    3800                        &request_info);
    3801   }
    3802 
    3803   if (CTX != NULL && SSL_CTX_use_certificate_file(CTX, pem,
    3804         SSL_FILETYPE_PEM) == 0) {
     4893  if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
     4894    cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
     4895    return 0;
     4896  }
     4897
     4898  // If user callback returned non-NULL, that means that user callback has
     4899  // set up certificate itself. In this case, skip sertificate setting.
     4900  if ((ctx->callbacks.init_ssl == NULL ||
     4901       !ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data)) &&
     4902      (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
     4903       SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0)) {
    38054904    cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
    38064905    return 0;
    3807   } else if (CTX != NULL && SSL_CTX_use_PrivateKey_file(CTX, pem,
    3808         SSL_FILETYPE_PEM) == 0) {
    3809     cry(fc(ctx), "%s: cannot open %s: %s", NULL, pem, ssl_error());
    3810     return 0;
    3811   }
    3812 
    3813   if (CTX != NULL && chain != NULL &&
    3814       SSL_CTX_use_certificate_chain_file(CTX, chain) == 0) {
    3815     cry(fc(ctx), "%s: cannot open %s: %s", NULL, chain, ssl_error());
    3816     return 0;
     4906  }
     4907
     4908  if (pem != NULL) {
     4909    (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
    38174910  }
    38184911
     
    38324925  CRYPTO_set_id_callback(&ssl_id_callback);
    38334926
    3834   // Done with everything. Save the context.
    3835   ctx->ssl_ctx = CTX;
    3836 
    38374927  return 1;
    38384928}
     
    38524942
    38534943static int set_gpass_option(struct mg_context *ctx) {
    3854   struct mgstat mgstat;
     4944  struct file file = STRUCT_FILE_INITIALIZER;
    38554945  const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
    3856   return path == NULL || mg_stat(path, &mgstat) == 0;
     4946  if (path != NULL && !mg_stat(fc(ctx), path, &file)) {
     4947    cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
     4948    return 0;
     4949  }
     4950  return 1;
    38574951}
    38584952
    38594953static int set_acl_option(struct mg_context *ctx) {
    3860   union usa fake;
    3861   return check_acl(ctx, &fake) != -1;
     4954  return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
    38624955}
    38634956
    38644957static void reset_per_request_attributes(struct mg_connection *conn) {
    3865   struct mg_request_info *ri = &conn->request_info;
    3866 
    3867   // Reset request info attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
    3868   ri->remote_user = ri->request_method = ri->uri = ri->http_version =
    3869     conn->path_info = NULL;
    3870   ri->num_headers = 0;
    3871   ri->status_code = -1;
    3872 
     4958  conn->path_info = NULL;
    38734959  conn->num_bytes_sent = conn->consumed_content = 0;
    3874   conn->content_len = -1;
    3875   conn->request_len = conn->data_len = 0;
    3876   conn->must_close = 0;
    3877 }
    3878 
    3879 static void close_socket_gracefully(SOCKET sock) {
    3880   char buf[BUFSIZ];
     4960  conn->status_code = -1;
     4961  conn->must_close = conn->request_len = conn->throttle = 0;
     4962}
     4963
     4964static void close_socket_gracefully(struct mg_connection *conn) {
     4965#if defined(_WIN32)
     4966  char buf[MG_BUF_LEN];
     4967  int n;
     4968#endif
    38814969  struct linger linger;
    3882   int n;
    38834970
    38844971  // Set linger option to avoid socket hanging out after close. This prevent
     
    38864973  linger.l_onoff = 1;
    38874974  linger.l_linger = 1;
    3888   setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));
     4975  setsockopt(conn->client.sock, SOL_SOCKET, SO_LINGER,
     4976             (char *) &linger, sizeof(linger));
    38894977
    38904978  // Send FIN to the client
    3891   (void) shutdown(sock, SHUT_WR);
    3892   set_non_blocking_mode(sock);
    3893 
    3894   // Read and discard pending data. If we do not do that and close the
     4979  shutdown(conn->client.sock, SHUT_WR);
     4980  set_non_blocking_mode(conn->client.sock);
     4981
     4982#if defined(_WIN32)
     4983  // Read and discard pending incoming data. If we do not do that and close the
    38954984  // socket, the data in the send buffer may be discarded. This
    38964985  // behaviour is seen on Windows, when client keeps sending data
    3897   // when server decide to close the connection; then when client
     4986  // when server decides to close the connection; then when client
    38984987  // does recv() it gets no data back.
    38994988  do {
    3900     n = pull(NULL, sock, NULL, buf, sizeof(buf));
     4989    n = pull(NULL, conn, buf, sizeof(buf));
    39014990  } while (n > 0);
     4991#endif
    39024992
    39034993  // Now we know that our FIN is ACK-ed, safe to close
    3904   (void) closesocket(sock);
     4994  closesocket(conn->client.sock);
    39054995}
    39064996
    39074997static void close_connection(struct mg_connection *conn) {
    3908   if (conn->ssl) {
     4998  conn->must_close = 1;
     4999
     5000#ifndef NO_SSL
     5001  if (conn->ssl != NULL) {
     5002    // Run SSL_shutdown twice to ensure completly close SSL connection
     5003    SSL_shutdown(conn->ssl);
    39095004    SSL_free(conn->ssl);
    39105005    conn->ssl = NULL;
    39115006  }
    3912 
     5007#endif
    39135008  if (conn->client.sock != INVALID_SOCKET) {
    3914     close_socket_gracefully(conn->client.sock);
    3915   }
    3916 }
    3917 
    3918 static void discard_current_request_from_buffer(struct mg_connection *conn) {
    3919   char *buffered;
    3920   int buffered_len, body_len;
    3921 
    3922   buffered = conn->buf + conn->request_len;
    3923   buffered_len = conn->data_len - conn->request_len;
    3924   assert(buffered_len >= 0);
    3925 
    3926   if (conn->content_len <= 0) {
    3927     // Protect from negative Content-Length, too
    3928     body_len = 0;
    3929   } else if (conn->content_len < (int64_t) buffered_len) {
    3930     body_len = (int) conn->content_len;
     5009    close_socket_gracefully(conn);
     5010    conn->client.sock = INVALID_SOCKET;
     5011  }
     5012}
     5013
     5014void mg_close_connection(struct mg_connection *conn) {
     5015#ifndef NO_SSL
     5016  if (conn->client_ssl_ctx != NULL) {
     5017    SSL_CTX_free((SSL_CTX *) conn->client_ssl_ctx);
     5018  }
     5019#endif
     5020  close_connection(conn);
     5021  free(conn);
     5022}
     5023
     5024static struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
     5025                                        char *ebuf, size_t ebuf_len) {
     5026  static struct mg_context fake_ctx;
     5027  struct mg_connection *conn = NULL;
     5028  SOCKET sock;
     5029
     5030  if ((sock = conn2(host, port, use_ssl, ebuf, ebuf_len)) == INVALID_SOCKET) {
     5031  } else if ((conn = (struct mg_connection *)
     5032              calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
     5033    snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
     5034    closesocket(sock);
     5035#ifndef NO_SSL
     5036  } else if (use_ssl && (conn->client_ssl_ctx =
     5037                         SSL_CTX_new(SSLv23_client_method())) == NULL) {
     5038    snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
     5039    closesocket(sock);
     5040    free(conn);
     5041    conn = NULL;
     5042#endif // NO_SSL
    39315043  } else {
    3932     body_len = buffered_len;
    3933   }
    3934 
    3935   conn->data_len -= conn->request_len + body_len;
    3936   memmove(conn->buf, conn->buf + conn->request_len + body_len,
    3937           (size_t) conn->data_len);
     5044    socklen_t len = sizeof(struct sockaddr);
     5045    conn->buf_size = MAX_REQUEST_SIZE;
     5046    conn->buf = (char *) (conn + 1);
     5047    conn->ctx = &fake_ctx;
     5048    conn->client.sock = sock;
     5049    getsockname(sock, &conn->client.rsa.sa, &len);
     5050    conn->client.is_ssl = use_ssl;
     5051#ifndef NO_SSL
     5052    if (use_ssl) {
     5053      // SSL_CTX_set_verify call is needed to switch off server certificate
     5054      // checking, which is off by default in OpenSSL and on in yaSSL.
     5055      SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
     5056      sslize(conn, conn->client_ssl_ctx, SSL_connect);
     5057    }
     5058#endif
     5059  }
     5060
     5061  return conn;
    39385062}
    39395063
     
    39445068}
    39455069
     5070static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len) {
     5071  const char *cl;
     5072
     5073  ebuf[0] = '\0';
     5074  reset_per_request_attributes(conn);
     5075  conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
     5076                                   &conn->data_len);
     5077  assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
     5078
     5079  if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
     5080    snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
     5081  } else if (conn->request_len <= 0) {
     5082    snprintf(ebuf, ebuf_len, "%s", "Client closed connection");
     5083  } else if (parse_http_message(conn->buf, conn->buf_size,
     5084                                &conn->request_info) <= 0) {
     5085    snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf);
     5086  } else {
     5087    // Request is valid
     5088    if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
     5089      conn->content_len = strtoll(cl, NULL, 10);
     5090    } else if (!mg_strcasecmp(conn->request_info.request_method, "POST") ||
     5091               !mg_strcasecmp(conn->request_info.request_method, "PUT")) {
     5092      conn->content_len = -1;
     5093    } else {
     5094      conn->content_len = 0;
     5095    }
     5096    conn->birth_time = time(NULL);
     5097  }
     5098  return ebuf[0] == '\0';
     5099}
     5100
     5101struct mg_connection *mg_download(const char *host, int port, int use_ssl,
     5102                                  char *ebuf, size_t ebuf_len,
     5103                                  const char *fmt, ...) {
     5104  struct mg_connection *conn;
     5105  va_list ap;
     5106
     5107  va_start(ap, fmt);
     5108  ebuf[0] = '\0';
     5109  if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
     5110  } else if (mg_vprintf(conn, fmt, ap) <= 0) {
     5111    snprintf(ebuf, ebuf_len, "%s", "Error sending request");
     5112  } else {
     5113    getreq(conn, ebuf, ebuf_len);
     5114  }
     5115  if (ebuf[0] != '\0' && conn != NULL) {
     5116    mg_close_connection(conn);
     5117    conn = NULL;
     5118  }
     5119
     5120  return conn;
     5121}
     5122
    39465123static void process_new_connection(struct mg_connection *conn) {
    39475124  struct mg_request_info *ri = &conn->request_info;
    3948   int keep_alive_enabled;
    3949   const char *cl;
     5125  int keep_alive_enabled, keep_alive, discard_len;
     5126  char ebuf[100];
    39505127
    39515128  keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
    3952 
     5129  keep_alive = 0;
     5130
     5131  // Important: on new connection, reset the receiving buffer. Credit goes
     5132  // to crule42.
     5133  conn->data_len = 0;
    39535134  do {
    3954     reset_per_request_attributes(conn);
    3955     conn->request_len = read_request(NULL, conn->client.sock, conn->ssl,
    3956                                      conn->buf, conn->buf_size,
    3957                                      &conn->data_len);
    3958     assert(conn->data_len >= conn->request_len);
    3959     if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
    3960       send_http_error(conn, 413, "Request Too Large", "");
    3961       return;
    3962     } if (conn->request_len <= 0) {
    3963       return;  // Remote end closed the connection
    3964     }
    3965 
    3966     // Nul-terminate the request cause parse_http_request() uses sscanf
    3967     conn->buf[conn->request_len - 1] = '\0';
    3968     if (!parse_http_request(conn->buf, ri) || !is_valid_uri(ri->uri)) {
    3969       // Do not put garbage in the access log, just send it back to the client
    3970       send_http_error(conn, 400, "Bad Request",
    3971           "Cannot parse HTTP request: [%.*s]", conn->data_len, conn->buf);
     5135    if (!getreq(conn, ebuf, sizeof(ebuf))) {
     5136      send_http_error(conn, 500, "Server Error", "%s", ebuf);
     5137      conn->must_close = 1;
     5138    } else if (!is_valid_uri(conn->request_info.uri)) {
     5139      snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
     5140      send_http_error(conn, 400, "Bad Request", "%s", ebuf);
    39725141    } else if (strcmp(ri->http_version, "1.0") &&
    39735142               strcmp(ri->http_version, "1.1")) {
    3974       // Request seems valid, but HTTP version is strange
    3975       send_http_error(conn, 505, "HTTP version not supported", "");
     5143      snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
     5144      send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
     5145    }
     5146
     5147    if (ebuf[0] == '\0') {
     5148      handle_request(conn);
     5149      if (conn->ctx->callbacks.end_request != NULL) {
     5150        conn->ctx->callbacks.end_request(conn, conn->status_code);
     5151      }
    39765152      log_access(conn);
    3977     } else {
    3978       // Request is valid, handle it
    3979       cl = get_header(ri, "Content-Length");
    3980       conn->content_len = cl == NULL ? -1 : strtoll(cl, NULL, 10);
    3981       conn->birth_time = time(NULL);
    3982       handle_request(conn);
    3983       call_user(conn, MG_REQUEST_COMPLETE);
    3984       log_access(conn);
    3985       discard_current_request_from_buffer(conn);
    39865153    }
    39875154    if (ri->remote_user != NULL) {
    39885155      free((void *) ri->remote_user);
    3989     }
    3990   } while (conn->ctx->stop_flag == 0 &&
    3991            keep_alive_enabled &&
    3992            should_keep_alive(conn));
     5156      // Important! When having connections with and without auth
     5157      // would cause double free and then crash
     5158      ri->remote_user = NULL;
     5159    }
     5160
     5161    // NOTE(lsm): order is important here. should_keep_alive() call
     5162    // is using parsed request, which will be invalid after memmove's below.
     5163    // Therefore, memorize should_keep_alive() result now for later use
     5164    // in loop exit condition.
     5165    keep_alive = conn->ctx->stop_flag == 0 && keep_alive_enabled &&
     5166      conn->content_len >= 0 && should_keep_alive(conn);
     5167
     5168    // Discard all buffered data for this request
     5169    discard_len = conn->content_len >= 0 && conn->request_len > 0 &&
     5170      conn->request_len + conn->content_len < (int64_t) conn->data_len ?
     5171      (int) (conn->request_len + conn->content_len) : conn->data_len;
     5172    assert(discard_len >= 0);
     5173    memmove(conn->buf, conn->buf + discard_len, conn->data_len - discard_len);
     5174    conn->data_len -= discard_len;
     5175    assert(conn->data_len >= 0);
     5176    assert(conn->data_len <= conn->buf_size);
     5177  } while (keep_alive);
    39935178}
    39945179
     
    40235208}
    40245209
    4025 static void worker_thread(struct mg_context *ctx) {
     5210static void *worker_thread(void *thread_func_param) {
     5211  struct mg_context *ctx = (struct mg_context *) thread_func_param;
    40265212  struct mg_connection *conn;
    4027   int buf_size = atoi(ctx->config[MAX_REQUEST_SIZE]);
    4028 
    4029   conn = (struct mg_connection *) calloc(1, sizeof(*conn) + buf_size);
     5213
     5214  conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
    40305215  if (conn == NULL) {
    40315216    cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
    4032     return;
    4033   }
    4034   conn->buf_size = buf_size;
    4035   conn->buf = (char *) (conn + 1);
    4036 
    4037   // Call consume_socket() even when ctx->stop_flag > 0, to let it signal
    4038   // sq_empty condvar to wake up the master waiting in produce_socket()
    4039   while (consume_socket(ctx, &conn->client)) {
    4040     conn->birth_time = time(NULL);
     5217  } else {
     5218    conn->buf_size = MAX_REQUEST_SIZE;
     5219    conn->buf = (char *) (conn + 1);
    40415220    conn->ctx = ctx;
    4042 
    4043     // Fill in IP, port info early so even if SSL setup below fails,
    4044     // error handler would have the corresponding info.
    4045     // Thanks to Johannes Winkelmann for the patch.
    4046     // TODO(lsm): Fix IPv6 case
    4047     conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
    4048     memcpy(&conn->request_info.remote_ip,
    4049            &conn->client.rsa.sin.sin_addr.s_addr, 4);
    4050     conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
    4051     conn->request_info.is_ssl = conn->client.is_ssl;
    4052 
    4053     if (!conn->client.is_ssl ||
    4054         (conn->client.is_ssl && sslize(conn, SSL_accept))) {
    4055       process_new_connection(conn);
    4056     }
    4057 
    4058     close_connection(conn);
    4059   }
    4060   free(conn);
     5221    conn->request_info.user_data = ctx->user_data;
     5222
     5223    // Call consume_socket() even when ctx->stop_flag > 0, to let it signal
     5224    // sq_empty condvar to wake up the master waiting in produce_socket()
     5225    while (consume_socket(ctx, &conn->client)) {
     5226      conn->birth_time = time(NULL);
     5227
     5228      // Fill in IP, port info early so even if SSL setup below fails,
     5229      // error handler would have the corresponding info.
     5230      // Thanks to Johannes Winkelmann for the patch.
     5231      // TODO(lsm): Fix IPv6 case
     5232      conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
     5233      memcpy(&conn->request_info.remote_ip,
     5234             &conn->client.rsa.sin.sin_addr.s_addr, 4);
     5235      conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
     5236      conn->request_info.is_ssl = conn->client.is_ssl;
     5237
     5238      if (!conn->client.is_ssl
     5239#ifndef NO_SSL
     5240          || sslize(conn, conn->ctx->ssl_ctx, SSL_accept)
     5241#endif
     5242         ) {
     5243        process_new_connection(conn);
     5244      }
     5245
     5246      close_connection(conn);
     5247    }
     5248    free(conn);
     5249  }
    40615250
    40625251  // Signal master that we're done with connection and exiting
     
    40685257
    40695258  DEBUG_TRACE(("exiting"));
     5259  return NULL;
    40705260}
    40715261
     
    40915281}
    40925282
     5283static int set_sock_timeout(SOCKET sock, int milliseconds) {
     5284#ifdef _WIN32
     5285  DWORD t = milliseconds;
     5286#else
     5287  struct timeval t;
     5288  t.tv_sec = milliseconds / 1000;
     5289  t.tv_usec = (milliseconds * 1000) % 1000000;
     5290#endif
     5291  return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *) &t, sizeof(t)) ||
     5292    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *) &t, sizeof(t));
     5293}
     5294
    40935295static void accept_new_connection(const struct socket *listener,
    40945296                                  struct mg_context *ctx) {
    4095   struct socket accepted;
    4096   char src_addr[20];
    4097   socklen_t len;
    4098   int allowed;
    4099 
    4100   len = sizeof(accepted.rsa);
    4101   accepted.lsa = listener->lsa;
    4102   accepted.sock = accept(listener->sock, &accepted.rsa.sa, &len);
    4103   if (accepted.sock != INVALID_SOCKET) {
    4104     allowed = check_acl(ctx, &accepted.rsa);
    4105     if (allowed) {
    4106       // Put accepted socket structure into the queue
    4107       DEBUG_TRACE(("accepted socket %d", accepted.sock));
    4108       accepted.is_ssl = listener->is_ssl;
    4109       produce_socket(ctx, &accepted);
    4110     } else {
    4111       sockaddr_to_string(src_addr, sizeof(src_addr), &accepted.rsa);
    4112       cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
    4113       (void) closesocket(accepted.sock);
    4114     }
    4115   }
    4116 }
    4117 
    4118 static void master_thread(struct mg_context *ctx) {
    4119   fd_set read_set;
    4120   struct timeval tv;
    4121   struct socket *sp;
    4122   int max_fd;
     5297  struct socket so;
     5298  char src_addr[IP_ADDR_STR_LEN];
     5299  socklen_t len = sizeof(so.rsa);
     5300  int on = 1;
     5301
     5302  if ((so.sock = accept(listener->sock, &so.rsa.sa, &len)) == INVALID_SOCKET) {
     5303  } else if (!check_acl(ctx, ntohl(* (uint32_t *) &so.rsa.sin.sin_addr))) {
     5304    sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
     5305    cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
     5306    closesocket(so.sock);
     5307  } else {
     5308    // Put so socket structure into the queue
     5309    DEBUG_TRACE(("Accepted socket %d", (int) so.sock));
     5310    set_close_on_exec(so.sock);
     5311    so.is_ssl = listener->is_ssl;
     5312    so.ssl_redir = listener->ssl_redir;
     5313    getsockname(so.sock, &so.lsa.sa, &len);
     5314    // Set TCP keep-alive. This is needed because if HTTP-level keep-alive
     5315    // is enabled, and client resets the connection, server won't get
     5316    // TCP FIN or RST and will keep the connection open forever. With TCP
     5317    // keep-alive, next keep-alive handshake will figure out that the client
     5318    // is down and will close the server end.
     5319    // Thanks to Igor Klopov who suggested the patch.
     5320    setsockopt(so.sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &on, sizeof(on));
     5321    set_sock_timeout(so.sock, atoi(ctx->config[REQUEST_TIMEOUT]));
     5322    produce_socket(ctx, &so);
     5323  }
     5324}
     5325
     5326static void *master_thread(void *thread_func_param) {
     5327  struct mg_context *ctx = (struct mg_context *) thread_func_param;
     5328  struct pollfd *pfd;
     5329  int i;
    41235330
    41245331  // Increase priority of the master thread
     
    41265333  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
    41275334#endif
    4128  
     5335
    41295336#if defined(ISSUE_317)
    41305337  struct sched_param sched_param;
     
    41335340#endif
    41345341
    4135   while (ctx->stop_flag == 0) {
    4136     FD_ZERO(&read_set);
    4137     max_fd = -1;
    4138 
    4139     // Add listening sockets to the read set
    4140     for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {
    4141       add_to_set(sp->sock, &read_set, &max_fd);
    4142     }
    4143 
    4144     tv.tv_sec = 0;
    4145     tv.tv_usec = 200 * 1000;
    4146 
    4147     if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
    4148 #ifdef _WIN32
    4149       // On windows, if read_set and write_set are empty,
    4150       // select() returns "Invalid parameter" error
    4151       // (at least on my Windows XP Pro). So in this case, we sleep here.
    4152       mg_sleep(1000);
    4153 #endif // _WIN32
    4154     } else {
    4155       for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {
    4156         if (ctx->stop_flag == 0 && FD_ISSET(sp->sock, &read_set)) {
    4157           accept_new_connection(sp, ctx);
     5342  pfd = (struct pollfd *) calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
     5343  while (pfd != NULL && ctx->stop_flag == 0) {
     5344    for (i = 0; i < ctx->num_listening_sockets; i++) {
     5345      pfd[i].fd = ctx->listening_sockets[i].sock;
     5346      pfd[i].events = POLLIN;
     5347    }
     5348
     5349    if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
     5350      for (i = 0; i < ctx->num_listening_sockets; i++) {
     5351        // NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
     5352        // successfull poll, and POLLIN is defined as (POLLRDNORM | POLLRDBAND)
     5353        // Therefore, we're checking pfd[i].revents & POLLIN, not
     5354        // pfd[i].revents == POLLIN.
     5355        if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
     5356          accept_new_connection(&ctx->listening_sockets[i], ctx);
    41585357        }
    41595358      }
    41605359    }
    41615360  }
     5361  free(pfd);
    41625362  DEBUG_TRACE(("stopping workers"));
    41635363
     
    41845384  uninitialize_ssl(ctx);
    41855385#endif
    4186 
    4187   // Signal mg_stop() that we're done
     5386  DEBUG_TRACE(("exiting"));
     5387
     5388  // Signal mg_stop() that we're done.
     5389  // WARNING: This must be the very last thing this
     5390  // thread does, as ctx becomes invalid after this line.
    41885391  ctx->stop_flag = 2;
    4189 
    4190   DEBUG_TRACE(("exiting"));
     5392  return NULL;
    41915393}
    41925394
     
    42005402  }
    42015403
     5404#ifndef NO_SSL
    42025405  // Deallocate SSL context
    42035406  if (ctx->ssl_ctx != NULL) {
    42045407    SSL_CTX_free(ctx->ssl_ctx);
    42055408  }
    4206 #ifndef NO_SSL
    42075409  if (ssl_mutexes != NULL) {
    42085410    free(ssl_mutexes);
     5411    ssl_mutexes = NULL;
    42095412  }
    42105413#endif // !NO_SSL
     
    42195422  // Wait until mg_fini() stops
    42205423  while (ctx->stop_flag != 2) {
    4221     mg_sleep(10);
     5424    (void) mg_sleep(10);
    42225425  }
    42235426  free_context(ctx);
     
    42285431}
    42295432
    4230 struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,
     5433struct mg_context *mg_start(const struct mg_callbacks *callbacks,
     5434                            void *user_data,
    42315435                            const char **options) {
    42325436  struct mg_context *ctx;
     
    42425446  // Allocate context and initialize reasonable general case defaults.
    42435447  // TODO(lsm): do proper error handling here.
    4244   ctx = (struct mg_context *) calloc(1, sizeof(*ctx));
    4245   ctx->user_callback = user_callback;
     5448  if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
     5449    return NULL;
     5450  }
     5451  ctx->callbacks = *callbacks;
    42465452  ctx->user_data = user_data;
    42475453
     
    42575463    }
    42585464    if (ctx->config[i] != NULL) {
    4259       cry(fc(ctx), "%s: duplicate option", name);
     5465      cry(fc(ctx), "warning: %s: duplicate option", name);
     5466      free(ctx->config[i]);
    42605467    }
    42615468    ctx->config[i] = mg_strdup(value);
     
    42645471
    42655472  // Set default value if needed
    4266   for (i = 0; config_options[i * ENTRIES_PER_CONFIG_OPTION] != NULL; i++) {
    4267     default_value = config_options[i * ENTRIES_PER_CONFIG_OPTION + 2];
     5473  for (i = 0; config_options[i * 2] != NULL; i++) {
     5474    default_value = config_options[i * 2 + 1];
    42685475    if (ctx->config[i] == NULL && default_value != NULL) {
    42695476      ctx->config[i] = mg_strdup(default_value);
    4270       DEBUG_TRACE(("Setting default: [%s] -> [%s]",
    4271                    config_options[i * ENTRIES_PER_CONFIG_OPTION + 1],
    4272                    default_value));
    42735477    }
    42745478  }
     
    43035507
    43045508  // Start master (listening) thread
    4305   start_thread(ctx, (mg_thread_func_t) master_thread, ctx);
     5509  mg_start_thread(master_thread, ctx);
    43065510
    43075511  // Start worker threads
    43085512  for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {
    4309     if (start_thread(ctx, (mg_thread_func_t) worker_thread, ctx) != 0) {
    4310       cry(fc(ctx), "Cannot start worker thread: %d", ERRNO);
     5513    if (mg_start_thread(worker_thread, ctx) != 0) {
     5514      cry(fc(ctx), "Cannot start worker thread: %ld", (long) ERRNO);
    43115515    } else {
    43125516      ctx->num_threads++;
  • cpukit/mghttpd/mongoose.h

    r0adc8a7 rb5d2d4a  
    1 // Copyright (c) 2004-2011 Sergey Lyubka
     1// Copyright (c) 2004-2012 Sergey Lyubka
    22//
    33// Permission is hereby granted, free of charge, to any person obtaining a copy
     
    2222#define  MONGOOSE_HEADER_INCLUDED
    2323
     24#include <stdio.h>
    2425#include <stddef.h>
    2526
     
    3435// This structure contains information about the HTTP request.
    3536struct mg_request_info {
    36   void *user_data;       // User-defined pointer passed to mg_start()
    37   char *request_method;  // "GET", "POST", etc
    38   char *uri;             // URL-decoded URI
    39   char *http_version;    // E.g. "1.0", "1.1"
    40   char *query_string;    // URL part after '?' (not including '?') or NULL
    41   char *remote_user;     // Authenticated user, or NULL if no auth used
    42   char *log_message;     // Mongoose error log message, MG_EVENT_LOG only
    43   long remote_ip;        // Client's IP address
    44   int remote_port;       // Client's port
    45   int status_code;       // HTTP reply status code, e.g. 200
    46   int is_ssl;            // 1 if SSL-ed, 0 if not
    47   int num_headers;       // Number of headers
     37  const char *request_method; // "GET", "POST", etc
     38  const char *uri;            // URL-decoded URI
     39  const char *http_version;   // E.g. "1.0", "1.1"
     40  const char *query_string;   // URL part after '?', not including '?', or NULL
     41  const char *remote_user;    // Authenticated user, or NULL if no auth used
     42  long remote_ip;             // Client's IP address
     43  int remote_port;            // Client's port
     44  int is_ssl;                 // 1 if SSL-ed, 0 if not
     45  void *user_data;            // User data pointer passed to mg_start()
     46  void *conn_data;            // Connection-specific user data
     47
     48  int num_headers;            // Number of HTTP headers
    4849  struct mg_header {
    49     char *name;          // HTTP header name
    50     char *value;         // HTTP header value
    51   } http_headers[64];    // Maximum 64 headers
     50    const char *name;         // HTTP header name
     51    const char *value;        // HTTP header value
     52  } http_headers[64];         // Maximum 64 headers
    5253};
    5354
    54 // Various events on which user-defined function is called by Mongoose.
    55 enum mg_event {
    56   MG_NEW_REQUEST,   // New HTTP request has arrived from the client
    57   MG_HTTP_ERROR,    // HTTP error must be returned to the client
    58   MG_EVENT_LOG,     // Mongoose logs an event, request_info.log_message
    59   MG_INIT_SSL,      // Mongoose initializes SSL. Instead of mg_connection *,
    60                     // SSL context is passed to the callback function.
    61   MG_REQUEST_COMPLETE  // Mongoose has finished handling the request
     55
     56// This structure needs to be passed to mg_start(), to let mongoose know
     57// which callbacks to invoke. For detailed description, see
     58// https://github.com/valenok/mongoose/blob/master/UserManual.md
     59struct mg_callbacks {
     60  // Called when mongoose has received new HTTP request.
     61  // If callback returns non-zero,
     62  // callback must process the request by sending valid HTTP headers and body,
     63  // and mongoose will not do any further processing.
     64  // If callback returns 0, mongoose processes the request itself. In this case,
     65  // callback must not send any data to the client.
     66  int  (*begin_request)(struct mg_connection *);
     67
     68  // Called when mongoose has finished processing request.
     69  void (*end_request)(const struct mg_connection *, int reply_status_code);
     70
     71  // Called when mongoose is about to log a message. If callback returns
     72  // non-zero, mongoose does not log anything.
     73  int  (*log_message)(const struct mg_connection *, const char *message);
     74
     75  // Called when mongoose initializes SSL library.
     76  int  (*init_ssl)(void *ssl_context, void *user_data);
     77
     78  // Called when websocket request is received, before websocket handshake.
     79  // If callback returns 0, mongoose proceeds with handshake, otherwise
     80  // cinnection is closed immediately.
     81  int (*websocket_connect)(const struct mg_connection *);
     82
     83  // Called when websocket handshake is successfully completed, and
     84  // connection is ready for data exchange.
     85  void (*websocket_ready)(struct mg_connection *);
     86
     87  // Called when data frame has been received from the client.
     88  // Parameters:
     89  //    bits: first byte of the websocket frame, see websocket RFC at
     90  //          http://tools.ietf.org/html/rfc6455, section 5.2
     91  //    data, data_len: payload, with mask (if any) already applied.
     92  // Return value:
     93  //    non-0: keep this websocket connection opened.
     94  //    0:     close this websocket connection.
     95  int  (*websocket_data)(struct mg_connection *, int bits,
     96                         char *data, size_t data_len);
     97
     98  // Called when mongoose tries to open a file. Used to intercept file open
     99  // calls, and serve file data from memory instead.
     100  // Parameters:
     101  //    path:     Full path to the file to open.
     102  //    data_len: Placeholder for the file size, if file is served from memory.
     103  // Return value:
     104  //    NULL: do not serve file from memory, proceed with normal file open.
     105  //    non-NULL: pointer to the file contents in memory. data_len must be
     106  //              initilized with the size of the memory block.
     107  const char * (*open_file)(const struct mg_connection *,
     108                             const char *path, size_t *data_len);
     109
     110  // Called when mongoose is about to serve Lua server page (.lp file), if
     111  // Lua support is enabled.
     112  // Parameters:
     113  //   lua_context: "lua_State *" pointer.
     114  void (*init_lua)(struct mg_connection *, void *lua_context);
     115
     116  // Called when mongoose has uploaded a file to a temporary directory as a
     117  // result of mg_upload() call.
     118  // Parameters:
     119  //    file_file: full path name to the uploaded file.
     120  void (*upload)(struct mg_connection *, const char *file_name);
     121
     122  // Called when mongoose is about to send HTTP error to the client.
     123  // Implementing this callback allows to create custom error pages.
     124  // Parameters:
     125  //   status: HTTP error status code.
     126  int  (*http_error)(struct mg_connection *, int status);
    62127};
    63128
    64 // Prototype for the user-defined function. Mongoose calls this function
    65 // on every MG_* event.
     129// Start web server.
    66130//
    67131// Parameters:
    68 //   event: which event has been triggered.
    69 //   conn: opaque connection handler. Could be used to read, write data to the
    70 //         client, etc. See functions below that have "mg_connection *" arg.
    71 //   request_info: Information about HTTP request.
    72 //
    73 // Return:
    74 //   If handler returns non-NULL, that means that handler has processed the
    75 //   request by sending appropriate HTTP reply to the client. Mongoose treats
    76 //   the request as served.
    77 //   If handler returns NULL, that means that handler has not processed
    78 //   the request. Handler must not send any data to the client in this case.
    79 //   Mongoose proceeds with request handling as if nothing happened.
    80 typedef void * (*mg_callback_t)(enum mg_event event,
    81                                 struct mg_connection *conn,
    82                                 const struct mg_request_info *request_info);
    83 
    84 
    85 // Start web server.
    86 //
    87 // Parameters:
    88 //   callback: user defined event handling function or NULL.
     132//   callbacks: mg_callbacks structure with user-defined callbacks.
    89133//   options: NULL terminated list of option_name, option_value pairs that
    90134//            specify Mongoose configuration parameters.
     
    103147//   struct mg_context *ctx = mg_start(&my_func, NULL, options);
    104148//
    105 // Please refer to http://code.google.com/p/mongoose/wiki/MongooseManual
     149// Refer to https://github.com/valenok/mongoose/blob/master/UserManual.md
    106150// for the list of valid option and their possible values.
    107151//
    108152// Return:
    109153//   web server context, or NULL on error.
    110 struct mg_context *mg_start(mg_callback_t callback, void *user_data,
    111                             const char **options);
     154struct mg_context *mg_start(const struct mg_callbacks *callbacks,
     155                            void *user_data,
     156                            const char **configuration_options);
    112157
    113158
     
    130175
    131176// Return array of strings that represent valid configuration options.
    132 // For each option, a short name, long name, and default value is returned.
     177// For each option, option name and default value is returned, i.e. the
     178// number of entries in the array equals to number_of_options x 2.
    133179// Array is NULL terminated.
    134180const char **mg_get_valid_option_names(void);
     
    152198                             const char *password);
    153199
     200
     201// Return information associated with the request.
     202struct mg_request_info *mg_get_request_info(struct mg_connection *);
     203
     204
    154205// Send data to the client.
     206// Return:
     207//  0   when the connection has been closed
     208//  -1  on error
     209//  >0  number of bytes written on success
    155210int mg_write(struct mg_connection *, const void *buf, size_t len);
    156211
    157212
    158 // Send data to the browser using printf() semantics.
    159 //
    160 // Works exactly like mg_write(), but allows to do message formatting.  Note
    161 // that mg_printf() uses internal buffer of size BUFSIZ defined in <stdio.h>
    162 // (8 KiB on most Linux systems) as temporary message storage for formatting.
    163 // Do not print data that is bigger than that, otherwise it will be truncated.
    164 int mg_printf(struct mg_connection *, const char *fmt, ...)
     213// Send data to a websocket client wrapped in a websocket frame.
     214// It is unsafe to read/write to this connection from another thread.
     215// This function is available when mongoose is compiled with -DUSE_WEBSOCKET
     216//
     217// Return:
     218//  0   when the connection has been closed
     219//  -1  on error
     220//  >0  number of bytes written on success
     221int mg_websocket_write(struct mg_connection* conn, int opcode,
     222                       const char *data, size_t data_len);
     223
     224// Opcodes, from http://tools.ietf.org/html/rfc6455
     225enum {
     226  WEBSOCKET_OPCODE_CONTINUATION = 0x0,
     227  WEBSOCKET_OPCODE_TEXT = 0x1,
     228  WEBSOCKET_OPCODE_BINARY = 0x2,
     229  WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
     230  WEBSOCKET_OPCODE_PING = 0x9,
     231  WEBSOCKET_OPCODE_PONG = 0xa
     232};
     233
     234
     235// Macros for enabling compiler-specific checks for printf-like arguments.
     236#undef PRINTF_FORMAT_STRING
     237#if defined(_MSC_VER) && _MSC_VER >= 1400
     238#include <sal.h>
     239#if defined(_MSC_VER) && _MSC_VER > 1400
     240#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
     241#else
     242#define PRINTF_FORMAT_STRING(s) __format_string s
     243#endif
     244#else
     245#define PRINTF_FORMAT_STRING(s) s
     246#endif
     247
    165248#ifdef __GNUC__
    166 __attribute__((format(printf, 2, 3)))
     249#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
     250#else
     251#define PRINTF_ARGS(x, y)
    167252#endif
    168 ;
     253
     254// Send data to the client using printf() semantics.
     255//
     256// Works exactly like mg_write(), but allows to do message formatting.
     257int mg_printf(struct mg_connection *,
     258              PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
    169259
    170260
     
    174264
    175265// Read data from the remote end, return number of bytes read.
     266// Return:
     267//   0     connection has been closed by peer. No more data could be read.
     268//   < 0   read error. No more data could be read from the connection.
     269//   > 0   number of bytes read into the buffer.
    176270int mg_read(struct mg_connection *, void *buf, size_t len);
    177271
     
    192286//   data_len: length of the encoded data.
    193287//   var_name: variable name to decode from the buffer
    194 //   buf: destination buffer for the decoded variable
    195 //   buf_len: length of the destination buffer
     288//   dst: destination buffer for the decoded variable
     289//   dst_len: length of the destination buffer
    196290//
    197291// Return:
    198292//   On success, length of the decoded variable.
    199 //   On error, -1 (variable not found, or destination buffer is too small).
    200 //
    201 // Destination buffer is guaranteed to be '\0' - terminated. In case of
    202 // failure, dst[0] == '\0'.
     293//   On error:
     294//      -1 (variable not found).
     295//      -2 (destination buffer is NULL, zero length or too small to hold the
     296//          decoded variable).
     297//
     298// Destination buffer is guaranteed to be '\0' - terminated if it is not
     299// NULL or zero length.
    203300int mg_get_var(const char *data, size_t data_len,
    204                const char *var_name, char *buf, size_t buf_len);
     301               const char *var_name, char *dst, size_t dst_len);
    205302
    206303// Fetch value of certain cookie variable into the destination buffer.
     
    212309// Return:
    213310//   On success, value length.
    214 //   On error, 0 (either "Cookie:" header is not present at all, or the
    215 //   requested parameter is not found, or destination buffer is too small
    216 //   to hold the value).
    217 int mg_get_cookie(const struct mg_connection *,
    218                   const char *cookie_name, char *buf, size_t buf_len);
     311//   On error:
     312//      -1 (either "Cookie:" header is not present at all or the requested
     313//          parameter is not found).
     314//      -2 (destination buffer is NULL, zero length or too small to hold the
     315//          value).
     316int mg_get_cookie(const char *cookie, const char *var_name,
     317                  char *buf, size_t buf_len);
     318
     319
     320// Download data from the remote web server.
     321//   host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
     322//   port: port number, e.g. 80.
     323//   use_ssl: wether to use SSL connection.
     324//   error_buffer, error_buffer_size: error message placeholder.
     325//   request_fmt,...: HTTP request.
     326// Return:
     327//   On success, valid pointer to the new connection, suitable for mg_read().
     328//   On error, NULL. error_buffer contains error message.
     329// Example:
     330//   char ebuf[100];
     331//   struct mg_connection *conn;
     332//   conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
     333//                      "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
     334struct mg_connection *mg_download(const char *host, int port, int use_ssl,
     335                                  char *error_buffer, size_t error_buffer_size,
     336                                  PRINTF_FORMAT_STRING(const char *request_fmt),
     337                                  ...) PRINTF_ARGS(6, 7);
     338
     339
     340// Close the connection opened by mg_download().
     341void mg_close_connection(struct mg_connection *conn);
     342
     343
     344// File upload functionality. Each uploaded file gets saved into a temporary
     345// file and MG_UPLOAD event is sent.
     346// Return number of uploaded files.
     347int mg_upload(struct mg_connection *conn, const char *destination_dir);
     348
     349
     350// Convenience function -- create detached thread.
     351// Return: 0 on success, non-0 on error.
     352typedef void * (*mg_thread_func_t)(void *);
     353int mg_start_thread(mg_thread_func_t f, void *p);
     354
     355
     356// Return builtin mime type for the given file name.
     357// For unrecognized extensions, "text/plain" is returned.
     358const char *mg_get_builtin_mime_type(const char *file_name);
    219359
    220360
     
    222362const char *mg_version(void);
    223363
     364// URL-decode input buffer into destination buffer.
     365// 0-terminate the destination buffer.
     366// form-url-encoded data differs from URI encoding in a way that it
     367// uses '+' as character for space, see RFC 1866 section 8.2.1
     368// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
     369// Return: length of the decoded data, or -1 if dst buffer is too small.
     370int mg_url_decode(const char *src, int src_len, char *dst,
     371                  int dst_len, int is_form_url_encoded);
    224372
    225373// MD5 hash given strings.
    226374// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
    227 // asciiz strings. When function returns, buf will contain human-readable
     375// ASCIIz strings. When function returns, buf will contain human-readable
    228376// MD5 hash. Example:
    229377//   char buf[33];
    230378//   mg_md5(buf, "aa", "bb", NULL);
    231 void mg_md5(char *buf, ...);
     379char *mg_md5(char buf[33], ...);
    232380
    233381
  • testsuites/libtests/mghttpd01/init.c

    r0adc8a7 rb5d2d4a  
    4545                        "Date: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" \
    4646                        "Last-Modified: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" \
    47                         "Etag: \"21dae500.a2\"\r\n" \
     47                        "Etag: \"21dae500.162\"\r\n" \
    4848                        "Content-Type: text/html\r\n" \
    4949                        "Content-Length: 162\r\n" \
     
    8181}
    8282
    83 typedef struct {
    84   char *string;
    85   int size;
    86 } printctx;
    87 
    88 static void *callback(enum mg_event event,
    89     struct mg_connection *conn,
    90     const struct mg_request_info *request_info)
    91 {
    92   if (event == MG_NEW_REQUEST) {
    93     int cbacktest = strncmp(request_info->uri, CBACKTEST_URI, sizeof(CBACKTEST_URI));
    94     if (cbacktest == 0)
    95     {
    96       mg_write(conn, CBACKTEST_TXT, sizeof(CBACKTEST_TXT));
    97 
    98       /* Mark as processed */
    99       return "";
    100     }
     83static int callback(struct mg_connection *conn)
     84{
     85  int cbacktest = strncmp(mg_get_request_info(conn)->uri, CBACKTEST_URI, sizeof(CBACKTEST_URI));
     86  if (cbacktest == 0)
     87  {
     88    mg_write(conn, CBACKTEST_TXT, sizeof(CBACKTEST_TXT));
     89
     90    /* Mark as processed */
     91    return 1;
    10192  }
    102   return NULL;
     93
     94  return 0;
    10395}
    10496
     
    173165static void test_mongoose(void)
    174166{
     167  const struct mg_callbacks callbacks = {
     168    .begin_request = callback
     169  };
    175170  const char *options[] = {
    176171    "listening_ports", "80",
    177     "document_root", "/www/",
     172    "document_root", "/www",
    178173    "num_threads", "1",
    179     "max_request_size", "2048",
    180174    "thread_stack_size", "16384",
    181175    "thread_priority", "250",
    182176    "thread_policy", "o",
    183177    NULL};
     178  const struct mg_callbacks callbacks2 = {
     179    NULL
     180  };
    184181  const char *options2[] = {
    185182    "listening_ports", "8080",
    186     "document_root", "/www2/",
     183    "document_root", "/www2",
    187184    "num_threads", "1",
    188185    "thread_stack_size", "16384",
    189     "max_request_size", "2048",
    190186    NULL};
    191187
    192   struct mg_context *mg1 = mg_start(&callback, NULL, options);
    193   struct mg_context *mg2 = mg_start(NULL, NULL, options2);
     188  struct mg_context *mg1 = mg_start(&callbacks, NULL, options);
     189  struct mg_context *mg2 = mg_start(&callbacks2, NULL, options2);
    194190
    195191  test_mg_index_html();
Note: See TracChangeset for help on using the changeset viewer.