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


jpeg_streamer
Author(s): Ken Tossell
autogenerated on Mon Jun 10 2019 12:51:47