ROOT  6.06/09
Reference Guide
civetweb.c
Go to the documentation of this file.
1 /* Copyright (c) 2004-2013 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 
22 #if defined(_WIN32)
23 #if !defined(_CRT_SECURE_NO_WARNINGS)
24 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
25 #endif
26 #else
27 #ifdef __linux__
28 #define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
29 #endif
30 #define _LARGEFILE_SOURCE /* Enable 64-bit file offsets */
31 #define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
32 #define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
33 #endif
34 
35 #if defined (_MSC_VER)
36 /* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
37 #pragma warning (disable : 4306 )
38 /* conditional expression is constant: introduced by FD_SET(..) */
39 #pragma warning (disable : 4127)
40 /* non-constant aggregate initializer: issued due to missing C99 support */
41 #pragma warning (disable : 4204)
42 #endif
43 
44 /* Disable WIN32_LEAN_AND_MEAN.
45  This makes windows.h always include winsock2.h */
46 #if defined(WIN32_LEAN_AND_MEAN) && (_MSC_VER <= 1400)
47 #undef WIN32_LEAN_AND_MEAN
48 #endif
49 
50 #if defined USE_IPV6 && defined(_WIN32)
51 #include <ws2tcpip.h>
52 #endif
53 
54 #if defined(__SYMBIAN32__)
55 #define NO_SSL /* SSL is not supported */
56 #define NO_CGI /* CGI is not supported */
57 #define PATH_MAX FILENAME_MAX
58 #endif /* __SYMBIAN32__ */
59 
60 #ifndef IGNORE_UNUSED_RESULT
61 #define IGNORE_UNUSED_RESULT(a) (void)((a) && 1)
62 #endif
63 
64 #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #include <errno.h>
68 #include <signal.h>
69 #include <fcntl.h>
70 #endif /* !_WIN32_WCE */
71 
72 #include <time.h>
73 #include <stdlib.h>
74 #include <stdarg.h>
75 #include <assert.h>
76 #include <string.h>
77 #include <ctype.h>
78 #include <limits.h>
79 #include <stddef.h>
80 #include <stdio.h>
81 
82 #define MAX_WORKER_THREADS 1024
83 
84 #if defined(_WIN32) && !defined(__SYMBIAN32__) /* Windows specific */
85 #if defined(_MSC_VER) && _MSC_VER <= 1400
86 #undef _WIN32_WINNT
87 #define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */
88 #endif
89 #include <windows.h>
90 
91 #ifndef PATH_MAX
92 #define PATH_MAX MAX_PATH
93 #endif
94 
95 #ifndef _IN_PORT_T
96 #ifndef in_port_t
97 #define in_port_t u_short
98 #endif
99 #endif
100 
101 #ifndef _WIN32_WCE
102 #include <process.h>
103 #include <direct.h>
104 #include <io.h>
105 #else /* _WIN32_WCE */
106 #define NO_CGI /* WinCE has no pipes */
107 
108 typedef long off_t;
109 
110 #define errno GetLastError()
111 #define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
112 #endif /* _WIN32_WCE */
113 
114 #define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
115  ((uint64_t)((uint32_t)(hi))) << 32))
116 #define RATE_DIFF 10000000 /* 100 nsecs */
117 #define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
118 #define SYS2UNIX_TIME(lo, hi) \
119  (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
120 
121 /* Visual Studio 6 does not know __func__ or __FUNCTION__
122  The rest of MS compilers use __FUNCTION__, not C99 __func__
123  Also use _strtoui64 on modern M$ compilers */
124 #if defined(_MSC_VER) && _MSC_VER < 1300
125 #define STRX(x) #x
126 #define STR(x) STRX(x)
127 #define __func__ __FILE__ ":" STR(__LINE__)
128 #define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
129 #define strtoll(x, y, z) _atoi64(x)
130 #else
131 #define __func__ __FUNCTION__
132 #define strtoull(x, y, z) _strtoui64(x, y, z)
133 #define strtoll(x, y, z) _strtoi64(x, y, z)
134 #endif /* _MSC_VER */
135 
136 #define ERRNO GetLastError()
137 #define NO_SOCKLEN_T
138 #define SSL_LIB "ssleay32.dll"
139 #define CRYPTO_LIB "libeay32.dll"
140 #define O_NONBLOCK 0
141 #if !defined(EWOULDBLOCK)
142 #define EWOULDBLOCK WSAEWOULDBLOCK
143 #endif /* !EWOULDBLOCK */
144 #define _POSIX_
145 #define INT64_FMT "I64d"
146 
147 #define WINCDECL __cdecl
148 #define SHUT_WR 1
149 #define snprintf _snprintf
150 #define vsnprintf _vsnprintf
151 #define mg_sleep(x) Sleep(x)
152 
153 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
154 #ifndef popen
155 #define popen(x, y) _popen(x, y)
156 #endif
157 #ifndef pclose
158 #define pclose(x) _pclose(x)
159 #endif
160 #define close(x) _close(x)
161 #define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
162 #define RTLD_LAZY 0
163 #define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
164 #define fdopen(x, y) _fdopen((x), (y))
165 #define write(x, y, z) _write((x), (y), (unsigned) z)
166 #define read(x, y, z) _read((x), (y), (unsigned) z)
167 #define flockfile(x) EnterCriticalSection(&global_log_file_lock)
168 #define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
169 #define sleep(x) Sleep((x) * 1000)
170 #define rmdir(x) _rmdir(x)
171 
172 #if !defined(va_copy)
173 #define va_copy(x, y) x = y
174 #endif /* !va_copy MINGW #defines va_copy */
175 
176 #if !defined(fileno)
177 #define fileno(x) _fileno(x)
178 #endif /* !fileno MINGW #defines fileno */
179 
180 typedef HANDLE pthread_mutex_t;
181 typedef DWORD pthread_key_t;
182 typedef HANDLE pthread_t;
183 typedef struct {
184  CRITICAL_SECTION threadIdSec;
185  int waitingthreadcount; /* The number of threads queued. */
186  pthread_t *waitingthreadhdls; /* The thread handles. */
188 
189 typedef DWORD clockid_t;
190 #define CLOCK_MONOTONIC (1)
191 #define CLOCK_REALTIME (2)
192 
193 struct timespec {
194  time_t tv_sec; /* seconds */
195  long tv_nsec; /* nanoseconds */
196 };
197 
198 #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
199 
200 static int pthread_mutex_lock(pthread_mutex_t *);
201 static int pthread_mutex_unlock(pthread_mutex_t *);
202 static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len);
203 struct file;
204 static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p);
205 
206 #if defined(HAVE_STDINT)
207 #include <stdint.h>
208 #else
209 typedef unsigned int uint32_t;
210 typedef unsigned short uint16_t;
211 typedef unsigned __int64 uint64_t;
212 typedef __int64 int64_t;
213 #define INT64_MAX 9223372036854775807
214 #endif /* HAVE_STDINT */
215 
216 /* POSIX dirent interface */
217 struct dirent {
218  char d_name[PATH_MAX];
219 };
220 
221 typedef struct DIR {
222  HANDLE handle;
223  WIN32_FIND_DATAW info;
224  struct dirent result;
225 } DIR;
226 
227 #if !defined(USE_IPV6) && defined(_WIN32)
228 #ifndef HAVE_POLL
229 struct pollfd {
230  SOCKET fd;
231  short events;
232  short revents;
233 };
234 #define POLLIN 1
235 #endif
236 #endif
237 
238 /* Mark required libraries */
239 #ifdef _MSC_VER
240 #pragma comment(lib, "Ws2_32.lib")
241 #endif
242 
243 #else /* UNIX specific */
244 #include <sys/wait.h>
245 #include <sys/socket.h>
246 #include <sys/poll.h>
247 #include <netinet/in.h>
248 #include <arpa/inet.h>
249 #include <sys/time.h>
250 #include <stdint.h>
251 #include <inttypes.h>
252 #include <netdb.h>
253 
254 #include <pwd.h>
255 #include <unistd.h>
256 #include <dirent.h>
257 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
258 #include <dlfcn.h>
259 #endif
260 #include <pthread.h>
261 #if defined(__MACH__)
262 #define SSL_LIB "libssl.dylib"
263 #define CRYPTO_LIB "libcrypto.dylib"
264 #else
265 #if !defined(SSL_LIB)
266 #define SSL_LIB "libssl.so"
267 #endif
268 #if !defined(CRYPTO_LIB)
269 #define CRYPTO_LIB "libcrypto.so"
270 #endif
271 #endif
272 #ifndef O_BINARY
273 #define O_BINARY 0
274 #endif /* O_BINARY */
275 #define closesocket(a) close(a)
276 #define mg_mkdir(x, y) mkdir(x, y)
277 #define mg_remove(x) remove(x)
278 #define mg_sleep(x) usleep((x) * 1000)
279 #define ERRNO errno
280 #define INVALID_SOCKET (-1)
281 #define INT64_FMT PRId64
282 typedef int SOCKET;
283 #define WINCDECL
284 
285 #endif /* End of Windows and UNIX specific includes */
286 
287 #include "civetweb.h"
288 
289 #define PASSWORDS_FILE_NAME ".htpasswd"
290 #define CGI_ENVIRONMENT_SIZE 4096
291 #define MAX_CGI_ENVIR_VARS 64
292 #define MG_BUF_LEN 8192
293 #ifndef MAX_REQUEST_SIZE
294 #define MAX_REQUEST_SIZE 16384
295 #endif
296 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
297 
298 #ifdef _WIN32
299 static CRITICAL_SECTION global_log_file_lock;
300 static DWORD pthread_self(void)
301 {
302  return GetCurrentThreadId();
303 }
304 
305 int pthread_key_create(pthread_key_t *key, void (*_must_be_zero)(void*) /* destructor function not supported for windows */)
306 {
307  assert(_must_be_zero == NULL);
308  if ((key!=0) && (_must_be_zero == NULL)) {
309  *key = TlsAlloc();
310  return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
311  }
312  return -2;
313 }
314 
315 int pthread_key_delete(pthread_key_t key)
316 {
317  return TlsFree(key) ? 0 : 1;
318 }
319 
320 int pthread_setspecific(pthread_key_t key, void * value)
321 {
322  return TlsSetValue(key, value) ? 0 : 1;
323 }
324 
325 void *pthread_getspecific(pthread_key_t key)
326 {
327  return TlsGetValue(key);
328 }
329 #endif /* _WIN32 */
330 
331 #define MD5_STATIC static
332 #include "md5.inl"
333 
334 #ifdef DEBUG_TRACE
335 #undef DEBUG_TRACE
336 #define DEBUG_TRACE(x)
337 #else
338 #if defined(DEBUG)
339 #define DEBUG_TRACE(x) do { \
340  flockfile(stdout); \
341  printf("*** %lu.%p.%s.%d: ", \
342  (unsigned long) time(NULL), (void *) pthread_self(), \
343  __func__, __LINE__); \
344  printf x; \
345  putchar('\n'); \
346  fflush(stdout); \
347  funlockfile(stdout); \
348 } while (0)
349 #else
350 #define DEBUG_TRACE(x)
351 #endif /* DEBUG */
352 #endif /* DEBUG_TRACE */
353 
354 /* Darwin prior to 7.0 and Win32 do not have socklen_t */
355 #ifdef NO_SOCKLEN_T
356 typedef int socklen_t;
357 #endif /* NO_SOCKLEN_T */
358 #define _DARWIN_UNLIMITED_SELECT
359 
360 #define IP_ADDR_STR_LEN 50 /* IPv6 hex string is 46 chars */
361 
362 #if !defined(MSG_NOSIGNAL)
363 #define MSG_NOSIGNAL 0
364 #endif
365 
366 #if !defined(SOMAXCONN)
367 #define SOMAXCONN 100
368 #endif
369 
370 #if !defined(PATH_MAX)
371 #define PATH_MAX 4096
372 #endif
373 
374 /* Size of the accepted socket queue */
375 #if !defined(MGSQLEN)
376 #define MGSQLEN 20
377 #endif
378 
379 static const char *http_500_error = "Internal Server Error";
380 
381 #if defined(NO_SSL_DL)
382 #include <openssl/ssl.h>
383 #include <openssl/err.h>
384 #else
385 /* SSL loaded dynamically from DLL.
386  I put the prototypes here to be independent from OpenSSL source
387  installation. */
388 
389 typedef struct ssl_st SSL;
390 typedef struct ssl_method_st SSL_METHOD;
391 typedef struct ssl_ctx_st SSL_CTX;
392 
393 struct ssl_func {
394  const char *name; /* SSL function name */
395  void (*ptr)(void); /* Function pointer */
396 };
397 
398 #define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
399 #define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
400 #define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
401 #define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
402 #define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
403 #define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
404 #define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
405 #define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
406 #define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
407 #define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
408 #define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
409 #define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
410  const char *, int)) ssl_sw[11].ptr)
411 #define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
412  const char *, int)) ssl_sw[12].ptr)
413 #define SSL_CTX_set_default_passwd_cb \
414  (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
415 #define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
416 #define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
417 #define SSL_CTX_use_certificate_chain_file \
418  (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
419 #define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
420 #define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
421 #define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
422 #define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
423 
424 #define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
425 #define CRYPTO_set_locking_callback \
426  (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
427 #define CRYPTO_set_id_callback \
428  (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
429 #define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
430 #define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
431 
432 /* set_ssl_option() function updates this array.
433  It loads SSL library dynamically and changes NULLs to the actual addresses
434  of respective functions. The macros above (like SSL_connect()) are really
435  just calling these functions indirectly via the pointer. */
436 static struct ssl_func ssl_sw[] = {
437  {"SSL_free", NULL},
438  {"SSL_accept", NULL},
439  {"SSL_connect", NULL},
440  {"SSL_read", NULL},
441  {"SSL_write", NULL},
442  {"SSL_get_error", NULL},
443  {"SSL_set_fd", NULL},
444  {"SSL_new", NULL},
445  {"SSL_CTX_new", NULL},
446  {"SSLv23_server_method", NULL},
447  {"SSL_library_init", NULL},
448  {"SSL_CTX_use_PrivateKey_file", NULL},
449  {"SSL_CTX_use_certificate_file",NULL},
450  {"SSL_CTX_set_default_passwd_cb",NULL},
451  {"SSL_CTX_free", NULL},
452  {"SSL_load_error_strings", NULL},
453  {"SSL_CTX_use_certificate_chain_file", NULL},
454  {"SSLv23_client_method", NULL},
455  {"SSL_pending", NULL},
456  {"SSL_CTX_set_verify", NULL},
457  {"SSL_shutdown", NULL},
458  {NULL, NULL}
459 };
460 
461 /* Similar array as ssl_sw. These functions could be located in different
462  lib. */
463 #if !defined(NO_SSL)
464 static struct ssl_func crypto_sw[] = {
465  {"CRYPTO_num_locks", NULL},
466  {"CRYPTO_set_locking_callback", NULL},
467  {"CRYPTO_set_id_callback", NULL},
468  {"ERR_get_error", NULL},
469  {"ERR_error_string", NULL},
470  {NULL, NULL}
471 };
472 #endif /* NO_SSL */
473 #endif /* NO_SSL_DL */
474 
475 static const char *month_names[] = {
476  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
477  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
478 };
479 
480 /* Unified socket address. For IPv6 support, add IPv6 address structure
481  in the union u. */
482 union usa {
483  struct sockaddr sa;
484  struct sockaddr_in sin;
485 #if defined(USE_IPV6)
486  struct sockaddr_in6 sin6;
487 #endif
488 };
489 
490 /* Describes a string (chunk of memory). */
491 struct vec {
492  const char *ptr;
493  size_t len;
494 };
495 
496 struct file {
497  int is_directory;
498  time_t modification_time;
499  int64_t size;
500  FILE *fp;
501  const char *membuf; /* Non-NULL if file data is in memory */
502  /* set to 1 if the content is gzipped
503  in which case we need a content-encoding: gzip header */
504  int gzipped;
505 };
506 #define STRUCT_FILE_INITIALIZER {0, 0, 0, NULL, NULL, 0}
507 
508 /* Describes listening socket, or socket which was accept()-ed by the master
509  thread and queued for future handling by the worker thread. */
510 struct socket {
511  SOCKET sock; /* Listening socket */
512  union usa lsa; /* Local socket address */
513  union usa rsa; /* Remote socket address */
514  unsigned is_ssl:1; /* Is port SSL-ed */
515  unsigned ssl_redir:1; /* Is port supposed to redirect everything to SSL
516  port */
517 };
518 
519 /* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
520 enum {
527 
528 #if defined(USE_LUA)
529  LUA_SCRIPT_EXTENSIONS, LUA_SERVER_PAGE_EXTENSIONS,
530 #endif
531 #if defined(USE_WEBSOCKET)
532  WEBSOCKET_ROOT,
533 #endif
534 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
535  LUA_WEBSOCKET_EXTENSIONS,
536 #endif
537 
539 };
540 
541 static const char *config_options[] = {
542  "cgi_pattern", "**.cgi$|**.pl$|**.php$",
543  "cgi_environment", NULL,
544  "put_delete_auth_file", NULL,
545  "cgi_interpreter", NULL,
546  "protect_uri", NULL,
547  "authentication_domain", "mydomain.com",
548  "ssi_pattern", "**.shtml$|**.shtm$",
549  "throttle", NULL,
550  "access_log_file", NULL,
551  "enable_directory_listing", "yes",
552  "error_log_file", NULL,
553  "global_auth_file", NULL,
554  "index_files",
555 #ifdef USE_LUA
556  "index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,index.shtml,index.php",
557 #else
558  "index.html,index.htm,index.cgi,index.shtml,index.php",
559 #endif
560  "enable_keep_alive", "no",
561  "access_control_list", NULL,
562  "extra_mime_types", NULL,
563  "listening_ports", "8080",
564  "document_root", NULL,
565  "ssl_certificate", NULL,
566  "num_threads", "50",
567  "run_as_user", NULL,
568  "url_rewrite_patterns", NULL,
569  "hide_files_patterns", NULL,
570  "request_timeout_ms", "30000",
571 
572 #if defined(USE_LUA)
573  "lua_script_pattern", "**.lua$",
574  "lua_server_page_pattern", "**.lp$|**.lsp$",
575 #endif
576 #if defined(USE_WEBSOCKET)
577  "websocket_root", NULL,
578 #endif
579 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
580  "lua_websocket_pattern", "**.lua$",
581 #endif
582 
583  NULL
584 };
585 
586 struct mg_request_handler_info {
587  char *uri;
588  size_t uri_len;
589  mg_request_handler handler;
590  void *cbdata;
591  struct mg_request_handler_info *next;
592 };
593 
594 struct mg_context {
595  volatile int stop_flag; /* Should we stop event loop */
596  void *ssllib_dll_handle; /* Store the ssl library handle. */
597  void *cryptolib_dll_handle; /* Store the crypto library handle. */
598  SSL_CTX *ssl_ctx; /* SSL context */
599  char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
600  struct mg_callbacks callbacks; /* User-defined callback function */
601  void *user_data; /* User-defined data */
602 
603  struct socket *listening_sockets;
604  in_port_t *listening_ports;
605  int num_listening_sockets;
606 
607  volatile int num_threads; /* Number of threads */
608  pthread_mutex_t mutex; /* Protects (max|num)_threads */
609  pthread_cond_t cond; /* Condvar for tracking workers terminations */
610 
611  struct socket queue[MGSQLEN]; /* Accepted sockets */
612  volatile int sq_head; /* Head of the socket queue */
613  volatile int sq_tail; /* Tail of the socket queue */
614  pthread_cond_t sq_full; /* Signaled when socket is produced */
615  pthread_cond_t sq_empty; /* Signaled when socket is consumed */
616  pthread_t masterthreadid; /* The master thread ID. */
617  int workerthreadcount; /* The amount of worker threads. */
618  pthread_t *workerthreadids;/* The worker thread IDs. */
619 
620  /* linked list of uri handlers */
621  struct mg_request_handler_info *request_handlers;
622 };
623 
624 struct mg_connection {
625  struct mg_request_info request_info;
626  struct mg_context *ctx;
627  SSL *ssl; /* SSL descriptor */
628  SSL_CTX *client_ssl_ctx; /* SSL context for client connections */
629  struct socket client; /* Connected client */
630  time_t birth_time; /* Time when request was received */
631  int64_t num_bytes_sent; /* Total bytes sent to client */
632  int64_t content_len; /* Content-Length header value */
633  int64_t consumed_content; /* How many bytes of content have been read */
634  char *buf; /* Buffer for received data */
635  char *path_info; /* PATH_INFO part of the URL */
636  int must_close; /* 1 if connection must be closed */
637  int buf_size; /* Buffer size */
638  int request_len; /* Size of the request + headers in a buffer */
639  int data_len; /* Total size of data in a buffer */
640  int status_code; /* HTTP reply status code, e.g. 200 */
641  int throttle; /* Throttling, bytes/sec. <= 0 means no
642  throttle */
643  time_t last_throttle_time; /* Last time throttled data was sent */
644  int64_t last_throttle_bytes;/* Bytes sent this second */
645  pthread_mutex_t mutex; /* Used by mg_lock/mg_unlock to ensure atomic
646  transmissions for websockets */
647 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
648  void * lua_websocket_state; /* Lua_State for a websocket connection */
649 #endif
650 };
651 
652 static pthread_key_t sTlsKey; /* Thread local storage index */
653 static int sTlsInit = 0;
654 
655 struct mg_workerTLS {
656  int is_master;
657 #if defined(_WIN32) && !defined(__SYMBIAN32__)
658  HANDLE pthread_cond_helper_mutex;
659 #endif
660 };
661 
662 /* Directory entry */
663 struct de {
664  struct mg_connection *conn;
665  char *file_name;
666  struct file file;
667 };
668 
669 #if defined(USE_WEBSOCKET)
670 static int is_websocket_request(const struct mg_connection *conn);
671 #endif
672 
673 const char **mg_get_valid_option_names(void)
674 {
675  return config_options;
676 }
677 
678 static int is_file_in_memory(struct mg_connection *conn, const char *path,
679  struct file *filep)
680 {
681  size_t size = 0;
682  if ((filep->membuf = conn->ctx->callbacks.open_file == NULL ? NULL :
683  conn->ctx->callbacks.open_file(conn, path, &size)) != NULL) {
684  /* NOTE: override filep->size only on success. Otherwise, it might
685  break constructs like if (!mg_stat() || !mg_fopen()) ... */
686  filep->size = size;
687  }
688  return filep->membuf != NULL;
689 }
690 
691 static int is_file_opened(const struct file *filep)
692 {
693  return filep->membuf != NULL || filep->fp != NULL;
694 }
695 
696 const struct mg_context *mg_get_context(const struct mg_connection *conn)
697 {
698  return conn == NULL ? NULL : conn->ctx;
699 }
700 
701 void *mg_get_user_data(const struct mg_context *ctx)
702 {
703  return ctx == NULL ? NULL : ctx->user_data;
704 }
705 
706 
707 static int mg_fopen(struct mg_connection *conn, const char *path,
708  const char *mode, struct file *filep)
709 {
710  if (!is_file_in_memory(conn, path, filep)) {
711 #ifdef _WIN32
712  wchar_t wbuf[PATH_MAX], wmode[20];
713  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
714  MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
715  filep->fp = _wfopen(wbuf, wmode);
716 #else
717  filep->fp = fopen(path, mode);
718 #endif
719  }
720 
721  return is_file_opened(filep);
722 }
723 
724 static void mg_fclose(struct file *filep)
725 {
726  if (filep != NULL && filep->fp != NULL) {
727  fclose(filep->fp);
728  }
729 }
730 
731 static int get_option_index(const char *name)
732 {
733  int i;
734 
735  for (i = 0; config_options[i * 2] != NULL; i++) {
736  if (strcmp(config_options[i * 2], name) == 0) {
737  return i;
738  }
739  }
740  return -1;
741 }
742 
743 const char *mg_get_option(const struct mg_context *ctx, const char *name)
744 {
745  int i;
746  if ((i = get_option_index(name)) == -1) {
747  return NULL;
748  } else if (ctx->config[i] == NULL) {
749  return "";
750  } else {
751  return ctx->config[i];
752  }
753 }
754 
755 size_t mg_get_ports(const struct mg_context *ctx, size_t size, int* ports, int* ssl)
756 {
757  size_t i;
758  for (i = 0; i < size && i < (size_t)ctx->num_listening_sockets; i++)
759  {
760  ssl[i] = ctx->listening_sockets[i].is_ssl;
761  ports[i] = ctx->listening_ports[i];
762  }
763  return i;
764 }
765 
766 static void sockaddr_to_string(char *buf, size_t len,
767  const union usa *usa)
768 {
769  buf[0] = '\0';
770 #if defined(USE_IPV6)
771  inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
772  (void *) &usa->sin.sin_addr :
773  (void *) &usa->sin6.sin6_addr, buf, len);
774 #elif defined(_WIN32)
775  /* Only Windows Vista (and newer) have inet_ntop() */
776  strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
777 #else
778  inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
779 #endif
780 }
781 
782 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be included in all responses other than 100, 101, 5xx. */
783 static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
784 {
785  struct tm *tm;
786 
787  tm = gmtime(t);
788  if (tm != NULL) {
789  strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
790  } else {
791  strncpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
792  buf[buf_len - 1] = '\0';
793  }
794 }
795 
796 /* Print error message to the opened error log stream. */
797 void mg_cry(struct mg_connection *conn, const char *fmt, ...)
798 {
799  char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
800  va_list ap;
801  FILE *fp;
802  time_t timestamp;
803 
804  va_start(ap, fmt);
805  IGNORE_UNUSED_RESULT(vsnprintf(buf, sizeof(buf), fmt, ap));
806  va_end(ap);
807 
808  /* Do not lock when getting the callback value, here and below.
809  I suppose this is fine, since function cannot disappear in the
810  same way string option can. */
811  if (conn->ctx->callbacks.log_message == NULL ||
812  conn->ctx->callbacks.log_message(conn, buf) == 0) {
813  fp = conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
814  fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
815 
816  if (fp != NULL) {
817  flockfile(fp);
818  timestamp = time(NULL);
819 
820  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
821  fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
822  src_addr);
823 
824  if (conn->request_info.request_method != NULL) {
825  fprintf(fp, "%s %s: ", conn->request_info.request_method,
826  conn->request_info.uri);
827  }
828 
829  fprintf(fp, "%s", buf);
830  fputc('\n', fp);
831  funlockfile(fp);
832  fclose(fp);
833  }
834  }
835 }
836 
837 /* Return fake connection structure. Used for logging, if connection
838  is not applicable at the moment of logging. */
839 static struct mg_connection *fc(struct mg_context *ctx)
840 {
841  static struct mg_connection fake_connection;
842  fake_connection.ctx = ctx;
843  return &fake_connection;
844 }
845 
846 const char *mg_version(void)
847 {
848  return CIVETWEB_VERSION;
849 }
850 
851 struct mg_request_info *mg_get_request_info(struct mg_connection *conn)
852 {
853  return &conn->request_info;
854 }
855 
856 static void mg_strlcpy(register char *dst, register const char *src, size_t n)
857 {
858  for (; *src != '\0' && n > 1; n--) {
859  *dst++ = *src++;
860  }
861  *dst = '\0';
862 }
863 
864 static int lowercase(const char *s)
865 {
866  return tolower(* (const unsigned char *) s);
867 }
868 
869 int mg_strncasecmp(const char *s1, const char *s2, size_t len)
870 {
871  int diff = 0;
872 
873  if (len > 0)
874  do {
875  diff = lowercase(s1++) - lowercase(s2++);
876  } while (diff == 0 && s1[-1] != '\0' && --len > 0);
877 
878  return diff;
879 }
880 
881 static int mg_strcasecmp(const char *s1, const char *s2)
882 {
883  int diff;
884 
885  do {
886  diff = lowercase(s1++) - lowercase(s2++);
887  } while (diff == 0 && s1[-1] != '\0');
888 
889  return diff;
890 }
891 
892 static char * mg_strndup(const char *ptr, size_t len)
893 {
894  char *p;
895 
896  if ((p = (char *) malloc(len + 1)) != NULL) {
897  mg_strlcpy(p, ptr, len + 1);
898  }
899 
900  return p;
901 }
902 
903 static char * mg_strdup(const char *str)
904 {
905  return mg_strndup(str, strlen(str));
906 }
907 
908 static const char *mg_strcasestr(const char *big_str, const char *small_str)
909 {
910  int i, big_len = (int)strlen(big_str), small_len = (int)strlen(small_str);
911 
912  for (i = 0; i <= big_len - small_len; i++) {
913  if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
914  return big_str + i;
915  }
916  }
917 
918  return NULL;
919 }
920 
921 /* Like snprintf(), but never returns negative value, or a value
922  that is larger than a supplied buffer.
923  Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
924  in his audit report. */
925 static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
926  const char *fmt, va_list ap)
927 {
928  int n;
929 
930  if (buflen == 0)
931  return 0;
932 
933  n = vsnprintf(buf, buflen, fmt, ap);
934 
935  if (n < 0) {
936  mg_cry(conn, "vsnprintf error");
937  n = 0;
938  } else if (n >= (int) buflen) {
939  mg_cry(conn, "truncating vsnprintf buffer: [%.*s]",
940  n > 200 ? 200 : n, buf);
941  n = (int) buflen - 1;
942  }
943  buf[n] = '\0';
944 
945  return n;
946 }
947 
948 static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
949  PRINTF_FORMAT_STRING(const char *fmt), ...)
950 PRINTF_ARGS(4, 5);
951 
952 static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
953  const char *fmt, ...)
954 {
955  va_list ap;
956  int n;
957 
958  va_start(ap, fmt);
959  n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
960  va_end(ap);
961 
962  return n;
963 }
964 
965 /* Skip the characters until one of the delimiters characters found.
966  0-terminate resulting word. Skip the delimiter and following whitespaces.
967  Advance pointer to buffer to the next word. Return found 0-terminated word.
968  Delimiters can be quoted with quotechar. */
969 static char *skip_quoted(char **buf, const char *delimiters,
970  const char *whitespace, char quotechar)
971 {
972  char *p, *begin_word, *end_word, *end_whitespace;
973 
974  begin_word = *buf;
975  end_word = begin_word + strcspn(begin_word, delimiters);
976 
977  /* Check for quotechar */
978  if (end_word > begin_word) {
979  p = end_word - 1;
980  while (*p == quotechar) {
981  /* If there is anything beyond end_word, copy it */
982  if (*end_word == '\0') {
983  *p = '\0';
984  break;
985  } else {
986  size_t end_off = strcspn(end_word + 1, delimiters);
987  memmove (p, end_word, end_off + 1);
988  p += end_off; /* p must correspond to end_word - 1 */
989  end_word += end_off + 1;
990  }
991  }
992  for (p++; p < end_word; p++) {
993  *p = '\0';
994  }
995  }
996 
997  if (*end_word == '\0') {
998  *buf = end_word;
999  } else {
1000  end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
1001 
1002  for (p = end_word; p < end_whitespace; p++) {
1003  *p = '\0';
1004  }
1005 
1006  *buf = end_whitespace;
1007  }
1008 
1009  return begin_word;
1010 }
1011 
1012 /* Simplified version of skip_quoted without quote char
1013  and whitespace == delimiters */
1014 static char *skip(char **buf, const char *delimiters)
1015 {
1016  return skip_quoted(buf, delimiters, delimiters, 0);
1017 }
1018 
1019 
1020 /* Return HTTP header value, or NULL if not found. */
1021 static const char *get_header(const struct mg_request_info *ri,
1022  const char *name)
1023 {
1024  int i;
1025 
1026  for (i = 0; i < ri->num_headers; i++)
1027  if (!mg_strcasecmp(name, ri->http_headers[i].name))
1028  return ri->http_headers[i].value;
1029 
1030  return NULL;
1031 }
1032 
1033 const char *mg_get_header(const struct mg_connection *conn, const char *name)
1034 {
1035  return get_header(&conn->request_info, name);
1036 }
1037 
1038 /* A helper function for traversing a comma separated list of values.
1039  It returns a list pointer shifted to the next value, or NULL if the end
1040  of the list found.
1041  Value is stored in val vector. If value has form "x=y", then eq_val
1042  vector is initialized to point to the "y" part, and val vector length
1043  is adjusted to point only to "x". */
1044 static const char *next_option(const char *list, struct vec *val,
1045  struct vec *eq_val)
1046 {
1047  if (list == NULL || *list == '\0') {
1048  /* End of the list */
1049  list = NULL;
1050  } else {
1051  val->ptr = list;
1052  if ((list = strchr(val->ptr, ',')) != NULL) {
1053  /* Comma found. Store length and shift the list ptr */
1054  val->len = list - val->ptr;
1055  list++;
1056  } else {
1057  /* This value is the last one */
1058  list = val->ptr + strlen(val->ptr);
1059  val->len = list - val->ptr;
1060  }
1061 
1062  if (eq_val != NULL) {
1063  /* Value has form "x=y", adjust pointers and lengths
1064  so that val points to "x", and eq_val points to "y". */
1065  eq_val->len = 0;
1066  eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
1067  if (eq_val->ptr != NULL) {
1068  eq_val->ptr++; /* Skip over '=' character */
1069  eq_val->len = val->ptr + val->len - eq_val->ptr;
1070  val->len = (eq_val->ptr - val->ptr) - 1;
1071  }
1072  }
1073  }
1074 
1075  return list;
1076 }
1077 
1078 /* Perform case-insensitive match of string against pattern */
1079 static int match_prefix(const char *pattern, int pattern_len, const char *str)
1080 {
1081  const char *or_str;
1082  int i, j, len, res;
1083 
1084  if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
1085  res = match_prefix(pattern, (int)(or_str - pattern), str);
1086  return res > 0 ? res :
1087  match_prefix(or_str + 1, (int)((pattern + pattern_len) - (or_str + 1)), str);
1088  }
1089 
1090  i = j = 0;
1091  res = -1;
1092  for (; i < pattern_len; i++, j++) {
1093  if (pattern[i] == '?' && str[j] != '\0') {
1094  continue;
1095  } else if (pattern[i] == '$') {
1096  return str[j] == '\0' ? j : -1;
1097  } else if (pattern[i] == '*') {
1098  i++;
1099  if (pattern[i] == '*') {
1100  i++;
1101  len = (int) strlen(str + j);
1102  } else {
1103  len = (int) strcspn(str + j, "/");
1104  }
1105  if (i == pattern_len) {
1106  return j + len;
1107  }
1108  do {
1109  res = match_prefix(pattern + i, pattern_len - i, str + j + len);
1110  } while (res == -1 && len-- > 0);
1111  return res == -1 ? -1 : j + res + len;
1112  } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
1113  return -1;
1114  }
1115  }
1116  return j;
1117 }
1118 
1119 /* HTTP 1.1 assumes keep alive if "Connection:" header is not set
1120  This function must tolerate situations when connection info is not
1121  set up, for example if request parsing failed. */
1122 static int should_keep_alive(const struct mg_connection *conn)
1123 {
1124  const char *http_version = conn->request_info.http_version;
1125  const char *header = mg_get_header(conn, "Connection");
1126  if (conn->must_close ||
1127  conn->status_code == 401 ||
1128  mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
1129  (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
1130  (header == NULL && http_version && strcmp(http_version, "1.1"))) {
1131  return 0;
1132  }
1133  return 1;
1134 }
1135 
1136 static const char *suggest_connection_header(const struct mg_connection *conn)
1137 {
1138  return should_keep_alive(conn) ? "keep-alive" : "close";
1139 }
1140 
1141 static void send_http_error(struct mg_connection *, int, const char *,
1142  PRINTF_FORMAT_STRING(const char *fmt), ...)
1143 PRINTF_ARGS(4, 5);
1144 
1145 
1146 static void send_http_error(struct mg_connection *conn, int status,
1147  const char *reason, const char *fmt, ...)
1148 {
1149  char buf[MG_BUF_LEN];
1150  va_list ap;
1151  int len = 0;
1152  char date[64];
1153  time_t curtime = time(NULL);
1154 
1155  conn->status_code = status;
1156  if (conn->ctx->callbacks.http_error == NULL ||
1157  conn->ctx->callbacks.http_error(conn, status)) {
1158  buf[0] = '\0';
1159 
1160  gmt_time_string(date, sizeof(date), &curtime);
1161 
1162  /* Errors 1xx, 204 and 304 MUST NOT send a body */
1163  if (status > 199 && status != 204 && status != 304) {
1164  len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
1165  buf[len++] = '\n';
1166 
1167  va_start(ap, fmt);
1168  len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
1169  va_end(ap);
1170  }
1171  DEBUG_TRACE(("[%s]", buf));
1172 
1173  mg_printf(conn, "HTTP/1.1 %d %s\r\n"
1174  "Content-Length: %d\r\n"
1175  "Date: %s\r\n"
1176  "Connection: %s\r\n\r\n",
1177  status, reason, len, date,
1179  conn->num_bytes_sent += mg_printf(conn, "%s", buf);
1180  }
1181 }
1182 
1183 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1184 static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
1185 {
1186  (void) unused;
1187  *mutex = CreateMutex(NULL, FALSE, NULL);
1188  return *mutex == NULL ? -1 : 0;
1189 }
1190 
1191 static int pthread_mutex_destroy(pthread_mutex_t *mutex)
1192 {
1193  return CloseHandle(*mutex) == 0 ? -1 : 0;
1194 }
1195 
1196 static int pthread_mutex_lock(pthread_mutex_t *mutex)
1197 {
1198  return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1199 }
1200 
1201 static int pthread_mutex_unlock(pthread_mutex_t *mutex)
1202 {
1203  return ReleaseMutex(*mutex) == 0 ? -1 : 0;
1204 }
1205 
1206 static int clock_gettime(clockid_t clk_id, struct timespec *tp)
1207 {
1208  FILETIME ft;
1209  ULARGE_INTEGER li;
1210  BOOL ok = FALSE;
1211  double d;
1212  static double perfcnt_per_sec = 0.0;
1213 
1214  if (tp) {
1215  if (clk_id == CLOCK_REALTIME) {
1216  GetSystemTimeAsFileTime(&ft);
1217  li.LowPart = ft.dwLowDateTime;
1218  li.HighPart = ft.dwHighDateTime;
1219  li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
1220  tp->tv_sec = (time_t)(li.QuadPart / 10000000);
1221  tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
1222  ok = TRUE;
1223  } else if (clk_id == CLOCK_MONOTONIC) {
1224  if (perfcnt_per_sec==0) {
1225  QueryPerformanceFrequency((LARGE_INTEGER *) &li);
1226  perfcnt_per_sec = 1.0 / li.QuadPart;
1227  }
1228  if (perfcnt_per_sec!=0) {
1229  QueryPerformanceCounter((LARGE_INTEGER *) &li);
1230  d = li.QuadPart * perfcnt_per_sec;
1231  tp->tv_sec = (time_t)d;
1232  d -= tp->tv_sec;
1233  tp->tv_nsec = (long)(d*1.0E9);
1234  ok = TRUE;
1235  }
1236  }
1237  }
1238 
1239  return ok ? 0 : -1;
1240 }
1241 
1242 static int pthread_cond_init(pthread_cond_t *cv, const void *unused)
1243 {
1244  (void) unused;
1245  InitializeCriticalSection(&cv->threadIdSec);
1246  cv->waitingthreadcount = 0;
1247  cv->waitingthreadhdls = calloc(MAX_WORKER_THREADS, sizeof(pthread_t));
1248  return (cv->waitingthreadhdls!=NULL) ? 0 : -1;
1249 }
1250 
1251 static int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mutex, const struct timespec * abstime)
1252 {
1253  struct mg_workerTLS * tls = (struct mg_workerTLS *)TlsGetValue(sTlsKey);
1254  int ok;
1255  struct timespec tsnow;
1256  int64_t nsnow, nswaitabs, nswaitrel;
1257  DWORD mswaitrel;
1258 
1259  EnterCriticalSection(&cv->threadIdSec);
1260  assert(cv->waitingthreadcount < MAX_WORKER_THREADS);
1261  cv->waitingthreadhdls[cv->waitingthreadcount] = tls->pthread_cond_helper_mutex;
1262  cv->waitingthreadcount++;
1263  LeaveCriticalSection(&cv->threadIdSec);
1264 
1265  if (abstime) {
1266  clock_gettime(CLOCK_REALTIME, &tsnow);
1267  nsnow = (((uint64_t)tsnow.tv_sec)<<32) + tsnow.tv_nsec;
1268  nswaitabs = (((uint64_t)abstime->tv_sec)<<32) + abstime->tv_nsec;
1269  nswaitrel = nswaitabs - nsnow;
1270  if (nswaitrel<0) nswaitrel=0;
1271  mswaitrel = (DWORD)(nswaitrel / 1000000);
1272  } else {
1273  mswaitrel = INFINITE;
1274  }
1275 
1276  pthread_mutex_unlock(mutex);
1277  ok = (WAIT_OBJECT_0 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
1278  pthread_mutex_lock(mutex);
1279 
1280  return ok ? 0 : -1;
1281 }
1282 
1283 static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
1284 {
1285  return pthread_cond_timedwait(cv, mutex, NULL);
1286 }
1287 
1288 static int pthread_cond_signal(pthread_cond_t *cv)
1289 {
1290  int i;
1291  HANDLE wkup = NULL;
1292  BOOL ok = FALSE;
1293 
1294  EnterCriticalSection(&cv->threadIdSec);
1295  if (cv->waitingthreadcount) {
1296  wkup = cv->waitingthreadhdls[0];
1297  ok = SetEvent(wkup);
1298 
1299  for (i=1; i<cv->waitingthreadcount; i++) {
1300  cv->waitingthreadhdls[i-1] = cv->waitingthreadhdls[i];
1301  }
1302  cv->waitingthreadcount--;
1303 
1304  assert(ok);
1305  }
1306  LeaveCriticalSection(&cv->threadIdSec);
1307 
1308  return ok ? 0 : 1;
1309 }
1310 
1311 static int pthread_cond_broadcast(pthread_cond_t *cv)
1312 {
1313  EnterCriticalSection(&cv->threadIdSec);
1314  while (cv->waitingthreadcount) {
1315  pthread_cond_signal(cv);
1316  }
1317  LeaveCriticalSection(&cv->threadIdSec);
1318 
1319  return 0;
1320 }
1321 
1322 static int pthread_cond_destroy(pthread_cond_t *cv)
1323 {
1324  EnterCriticalSection(&cv->threadIdSec);
1325  assert(cv->waitingthreadcount==0);
1326  cv->waitingthreadhdls = 0;
1327  free(cv->waitingthreadhdls);
1328  LeaveCriticalSection(&cv->threadIdSec);
1329  DeleteCriticalSection(&cv->threadIdSec);
1330 
1331  return 0;
1332 }
1333 
1334 /* For Windows, change all slashes to backslashes in path names. */
1335 static void change_slashes_to_backslashes(char *path)
1336 {
1337  int i;
1338 
1339  for (i = 0; path[i] != '\0'; i++) {
1340  if (path[i] == '/')
1341  path[i] = '\\';
1342  /* i > 0 check is to preserve UNC paths, like \\server\file.txt */
1343  if (path[i] == '\\' && i > 0)
1344  while (path[i + 1] == '\\' || path[i + 1] == '/')
1345  (void) memmove(path + i + 1,
1346  path + i + 2, strlen(path + i + 1));
1347  }
1348 }
1349 
1350 /* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
1351  wbuf and wbuf_len is a target buffer and its length. */
1352 static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len)
1353 {
1354  char buf[PATH_MAX], buf2[PATH_MAX];
1355 
1356  mg_strlcpy(buf, path, sizeof(buf));
1357  change_slashes_to_backslashes(buf);
1358 
1359  /* Convert to Unicode and back. If doubly-converted string does not
1360  match the original, something is fishy, reject. */
1361  memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1362  MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1363  WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1364  NULL, NULL);
1365  if (strcmp(buf, buf2) != 0) {
1366  wbuf[0] = L'\0';
1367  }
1368 }
1369 
1370 #if defined(_WIN32_WCE)
1371 static time_t time(time_t *ptime)
1372 {
1373  time_t t;
1374  SYSTEMTIME st;
1375  FILETIME ft;
1376 
1377  GetSystemTime(&st);
1378  SystemTimeToFileTime(&st, &ft);
1379  t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
1380 
1381  if (ptime != NULL) {
1382  *ptime = t;
1383  }
1384 
1385  return t;
1386 }
1387 
1388 static struct tm *localtime(const time_t *ptime, struct tm *ptm)
1389 {
1390  int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
1391  FILETIME ft, lft;
1392  SYSTEMTIME st;
1393  TIME_ZONE_INFORMATION tzinfo;
1394 
1395  if (ptm == NULL) {
1396  return NULL;
1397  }
1398 
1399  * (int64_t *) &ft = t;
1400  FileTimeToLocalFileTime(&ft, &lft);
1401  FileTimeToSystemTime(&lft, &st);
1402  ptm->tm_year = st.wYear - 1900;
1403  ptm->tm_mon = st.wMonth - 1;
1404  ptm->tm_wday = st.wDayOfWeek;
1405  ptm->tm_mday = st.wDay;
1406  ptm->tm_hour = st.wHour;
1407  ptm->tm_min = st.wMinute;
1408  ptm->tm_sec = st.wSecond;
1409  ptm->tm_yday = 0; /* hope nobody uses this */
1410  ptm->tm_isdst =
1411  GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
1412 
1413  return ptm;
1414 }
1415 
1416 static struct tm *gmtime(const time_t *ptime, struct tm *ptm)
1417 {
1418  /* FIXME(lsm): fix this. */
1419  return localtime(ptime, ptm);
1420 }
1421 
1422 static size_t strftime(char *dst, size_t dst_size, const char *fmt,
1423  const struct tm *tm)
1424 {
1425  (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
1426  return 0;
1427 }
1428 #endif
1429 
1430 /* Windows happily opens files with some garbage at the end of file name.
1431  For example, fopen("a.cgi ", "r") on Windows successfully opens
1432  "a.cgi", despite one would expect an error back.
1433  This function returns non-0 if path ends with some garbage. */
1434 static int path_cannot_disclose_cgi(const char *path)
1435 {
1436  static const char *allowed_last_characters = "_-";
1437  int last = path[strlen(path) - 1];
1438  return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
1439 }
1440 
1441 static int mg_stat(struct mg_connection *conn, const char *path,
1442  struct file *filep)
1443 {
1444  wchar_t wbuf[PATH_MAX];
1445  WIN32_FILE_ATTRIBUTE_DATA info;
1446 
1447  if (!is_file_in_memory(conn, path, filep)) {
1448  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
1449  if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
1450  filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
1451  filep->modification_time = SYS2UNIX_TIME(
1452  info.ftLastWriteTime.dwLowDateTime,
1453  info.ftLastWriteTime.dwHighDateTime);
1454  filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
1455  /* If file name is fishy, reset the file structure and return
1456  error.
1457  Note it is important to reset, not just return the error, cause
1458  functions like is_file_opened() check the struct. */
1459  if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
1460  memset(filep, 0, sizeof(*filep));
1461  }
1462  }
1463  }
1464 
1465  return filep->membuf != NULL || filep->modification_time != 0;
1466 }
1467 
1468 static int mg_remove(const char *path)
1469 {
1470  wchar_t wbuf[PATH_MAX];
1471  to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
1472  return DeleteFileW(wbuf) ? 0 : -1;
1473 }
1474 
1475 static int mg_mkdir(const char *path, int mode)
1476 {
1477  char buf[PATH_MAX];
1478  wchar_t wbuf[PATH_MAX];
1479 
1480  (void) mode;
1481  mg_strlcpy(buf, path, sizeof(buf));
1482  change_slashes_to_backslashes(buf);
1483 
1484  (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, ARRAY_SIZE(wbuf));
1485 
1486  return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1487 }
1488 
1489 /* Implementation of POSIX opendir/closedir/readdir for Windows. */
1490 static DIR * opendir(const char *name)
1491 {
1492  DIR *dir = NULL;
1493  wchar_t wpath[PATH_MAX];
1494  DWORD attrs;
1495 
1496  if (name == NULL) {
1497  SetLastError(ERROR_BAD_ARGUMENTS);
1498  } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
1499  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1500  } else {
1501  to_unicode(name, wpath, ARRAY_SIZE(wpath));
1502  attrs = GetFileAttributesW(wpath);
1503  if (attrs != 0xFFFFFFFF &&
1504  ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1505  (void) wcscat(wpath, L"\\*");
1506  dir->handle = FindFirstFileW(wpath, &dir->info);
1507  dir->result.d_name[0] = '\0';
1508  } else {
1509  free(dir);
1510  dir = NULL;
1511  }
1512  }
1513 
1514  return dir;
1515 }
1516 
1517 static int closedir(DIR *dir)
1518 {
1519  int result = 0;
1520 
1521  if (dir != NULL) {
1522  if (dir->handle != INVALID_HANDLE_VALUE)
1523  result = FindClose(dir->handle) ? 0 : -1;
1524 
1525  free(dir);
1526  } else {
1527  result = -1;
1528  SetLastError(ERROR_BAD_ARGUMENTS);
1529  }
1530 
1531  return result;
1532 }
1533 
1534 static struct dirent *readdir(DIR *dir)
1535 {
1536  struct dirent *result = 0;
1537 
1538  if (dir) {
1539  if (dir->handle != INVALID_HANDLE_VALUE) {
1540  result = &dir->result;
1541  (void) WideCharToMultiByte(CP_UTF8, 0,
1542  dir->info.cFileName, -1, result->d_name,
1543  sizeof(result->d_name), NULL, NULL);
1544 
1545  if (!FindNextFileW(dir->handle, &dir->info)) {
1546  (void) FindClose(dir->handle);
1547  dir->handle = INVALID_HANDLE_VALUE;
1548  }
1549 
1550  } else {
1551  SetLastError(ERROR_FILE_NOT_FOUND);
1552  }
1553  } else {
1554  SetLastError(ERROR_BAD_ARGUMENTS);
1555  }
1556 
1557  return result;
1558 }
1559 
1560 #ifndef HAVE_POLL
1561 static int poll(struct pollfd *pfd, int n, int milliseconds)
1562 {
1563  struct timeval tv;
1564  fd_set set;
1565  int i, result;
1566  SOCKET maxfd = 0;
1567 
1568  tv.tv_sec = milliseconds / 1000;
1569  tv.tv_usec = (milliseconds % 1000) * 1000;
1570  FD_ZERO(&set);
1571 
1572  for (i = 0; i < n; i++) {
1573  FD_SET((SOCKET) pfd[i].fd, &set);
1574  pfd[i].revents = 0;
1575 
1576  if (pfd[i].fd > maxfd) {
1577  maxfd = pfd[i].fd;
1578  }
1579  }
1580 
1581  if ((result = select((int)maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
1582  for (i = 0; i < n; i++) {
1583  if (FD_ISSET(pfd[i].fd, &set)) {
1584  pfd[i].revents = POLLIN;
1585  }
1586  }
1587  }
1588 
1589  return result;
1590 }
1591 #endif /* HAVE_POLL */
1592 
1593 static void set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
1594 {
1595  (void) conn; /* Unused. */
1596  (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
1597 }
1598 
1599 int mg_start_thread(mg_thread_func_t f, void *p)
1600 {
1601 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
1602  /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384 */
1603  return (long)_beginthread((void (__cdecl *)(void *)) f, USE_STACK_SIZE, p) == -1L ? -1 : 0;
1604 #else
1605  return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
1606 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
1607 }
1608 
1609 /* Start a thread storing the thread context. */
1610 
1611 static int mg_start_thread_with_id(unsigned (__stdcall *f)(void *), void *p,
1612  pthread_t *threadidptr)
1613 {
1614  uintptr_t uip;
1615  HANDLE threadhandle;
1616  int result;
1617 
1618  uip = _beginthreadex(NULL, 0, (unsigned (__stdcall *)(void *)) f, p, 0,
1619  NULL);
1620  threadhandle = (HANDLE) uip;
1621  if (threadidptr != NULL) {
1622  *threadidptr = threadhandle;
1623  }
1624  result = (threadhandle == NULL) ? -1 : 0;
1625 
1626  return result;
1627 }
1628 
1629 /* Wait for a thread to finish. */
1630 
1631 static int mg_join_thread(pthread_t threadid)
1632 {
1633  int result;
1634  DWORD dwevent;
1635 
1636  result = -1;
1637  dwevent = WaitForSingleObject(threadid, INFINITE);
1638  if (dwevent == WAIT_FAILED) {
1639  int err;
1640 
1641  err = GetLastError();
1642  DEBUG_TRACE(("WaitForSingleObject() failed, error %d", err));
1643  } else {
1644  if (dwevent == WAIT_OBJECT_0) {
1645  CloseHandle(threadid);
1646  result = 0;
1647  }
1648  }
1649 
1650  return result;
1651 }
1652 
1653 static HANDLE dlopen(const char *dll_name, int flags)
1654 {
1655  wchar_t wbuf[PATH_MAX];
1656  (void) flags;
1657  to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
1658  return LoadLibraryW(wbuf);
1659 }
1660 
1661 static int dlclose(void *handle)
1662 {
1663  int result;
1664 
1665  if (FreeLibrary(handle) != 0) {
1666  result = 0;
1667  } else {
1668  result = -1;
1669  }
1670 
1671  return result;
1672 }
1673 
1674 #if !defined(NO_CGI)
1675 #define SIGKILL 0
1676 static int kill(pid_t pid, int sig_num)
1677 {
1678  (void) TerminateProcess(pid, sig_num);
1679  (void) CloseHandle(pid);
1680  return 0;
1681 }
1682 
1683 static void trim_trailing_whitespaces(char *s)
1684 {
1685  char *e = s + strlen(s) - 1;
1686  while (e > s && isspace(* (unsigned char *) e)) {
1687  *e-- = '\0';
1688  }
1689 }
1690 
1691 static pid_t spawn_process(struct mg_connection *conn, const char *prog,
1692  char *envblk, char *envp[], int fdin,
1693  int fdout, const char *dir)
1694 {
1695  HANDLE me;
1696  char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
1697  cmdline[PATH_MAX], buf[PATH_MAX];
1698  struct file file = STRUCT_FILE_INITIALIZER;
1699  STARTUPINFOA si;
1700  PROCESS_INFORMATION pi = { 0 };
1701 
1702  (void) envp;
1703 
1704  memset(&si, 0, sizeof(si));
1705  si.cb = sizeof(si);
1706 
1707  /* TODO(lsm): redirect CGI errors to the error log file */
1708  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1709  si.wShowWindow = SW_HIDE;
1710 
1711  me = GetCurrentProcess();
1712  DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
1713  &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1714  DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
1715  &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
1716 
1717  /* If CGI file is a script, try to read the interpreter line */
1718  interp = conn->ctx->config[CGI_INTERPRETER];
1719  if (interp == NULL) {
1720  buf[0] = buf[1] = '\0';
1721 
1722  /* Read the first line of the script into the buffer */
1723  snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
1724  if (mg_fopen(conn, cmdline, "r", &file)) {
1725  p = (char *) file.membuf;
1726  mg_fgets(buf, sizeof(buf), &file, &p);
1727  mg_fclose(&file);
1728  buf[sizeof(buf) - 1] = '\0';
1729  }
1730 
1731  if (buf[0] == '#' && buf[1] == '!') {
1732  trim_trailing_whitespaces(buf + 2);
1733  } else {
1734  buf[2] = '\0';
1735  }
1736  interp = buf + 2;
1737  }
1738 
1739  if (interp[0] != '\0') {
1740  GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
1741  interp = full_interp;
1742  }
1743  GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
1744 
1745  mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s\"%s\\%s\"",
1746  interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
1747 
1748  DEBUG_TRACE(("Running [%s]", cmdline));
1749  if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
1750  CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &pi) == 0) {
1751  mg_cry(conn, "%s: CreateProcess(%s): %ld",
1752  __func__, cmdline, ERRNO);
1753  pi.hProcess = (pid_t) -1;
1754  }
1755 
1756  (void) CloseHandle(si.hStdOutput);
1757  (void) CloseHandle(si.hStdInput);
1758  if (pi.hThread != NULL)
1759  (void) CloseHandle(pi.hThread);
1760 
1761  return (pid_t) pi.hProcess;
1762 }
1763 #endif /* !NO_CGI */
1764 
1765 static int set_non_blocking_mode(SOCKET sock)
1766 {
1767  unsigned long on = 1;
1768  return ioctlsocket(sock, FIONBIO, &on);
1769 }
1770 
1771 #else
1772 static int mg_stat(struct mg_connection *conn, const char *path,
1773  struct file *filep)
1774 {
1775  struct stat st;
1776 
1777  if (!is_file_in_memory(conn, path, filep) && !stat(path, &st)) {
1778  filep->size = st.st_size;
1779  filep->modification_time = st.st_mtime;
1780  filep->is_directory = S_ISDIR(st.st_mode);
1781  } else {
1782  filep->modification_time = (time_t) 0;
1783  }
1784 
1785  return filep->membuf != NULL || filep->modification_time != (time_t) 0;
1786 }
1787 
1788 static void set_close_on_exec(int fd, struct mg_connection *conn /* may be null */)
1789 {
1790  if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
1791  if (conn)
1792  mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
1793  __func__, strerror(ERRNO));
1794  }
1795 }
1796 
1798 {
1799  pthread_t thread_id;
1800  pthread_attr_t attr;
1801  int result;
1802 
1803  (void) pthread_attr_init(&attr);
1804  (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1805 
1806 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
1807  /* Compile-time option to control stack size,
1808  e.g. -DUSE_STACK_SIZE=16384 */
1809  (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
1810 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
1811 
1812  result = pthread_create(&thread_id, &attr, func, param);
1813  pthread_attr_destroy(&attr);
1814 
1815  return result;
1816 }
1817 
1818 /* Start a thread storing the thread context. */
1819 
1821  pthread_t *threadidptr)
1822 {
1823  pthread_t thread_id;
1824  pthread_attr_t attr;
1825  int result;
1826 
1827  (void) pthread_attr_init(&attr);
1828 
1829 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
1830  /* Compile-time option to control stack size,
1831  e.g. -DUSE_STACK_SIZE=16384 */
1832  (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
1833 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
1834 
1835  result = pthread_create(&thread_id, &attr, func, param);
1836  pthread_attr_destroy(&attr);
1837  if (threadidptr != NULL) {
1838  *threadidptr = thread_id;
1839  }
1840  return result;
1841 }
1842 
1843 /* Wait for a thread to finish. */
1844 
1845 static int mg_join_thread(pthread_t threadid)
1846 {
1847  int result;
1848 
1849  result = pthread_join(threadid, NULL);
1850  return result;
1851 }
1852 
1853 #ifndef NO_CGI
1854 static pid_t spawn_process(struct mg_connection *conn, const char *prog,
1855  char *envblk, char *envp[], int fdin,
1856  int fdout, const char *dir)
1857 {
1858  pid_t pid;
1859  const char *interp;
1860 
1861  (void) envblk;
1862 
1863  if ((pid = fork()) == -1) {
1864  /* Parent */
1865  send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
1866  } else if (pid == 0) {
1867  /* Child */
1868  if (chdir(dir) != 0) {
1869  mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
1870  } else if (dup2(fdin, 0) == -1) {
1871  mg_cry(conn, "%s: dup2(%d, 0): %s", __func__, fdin, strerror(ERRNO));
1872  } else if (dup2(fdout, 1) == -1) {
1873  mg_cry(conn, "%s: dup2(%d, 1): %s", __func__, fdout, strerror(ERRNO));
1874  } else {
1875  /* Not redirecting stderr to stdout, to avoid output being littered
1876  with the error messages. */
1877  (void) close(fdin);
1878  (void) close(fdout);
1879 
1880  /* After exec, all signal handlers are restored to their default
1881  values, with one exception of SIGCHLD. According to
1882  POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
1883  leave unchanged after exec if it was set to be ignored. Restore
1884  it to default action. */
1885  signal(SIGCHLD, SIG_DFL);
1886 
1887  interp = conn->ctx->config[CGI_INTERPRETER];
1888  if (interp == NULL) {
1889  (void) execle(prog, prog, NULL, envp);
1890  mg_cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
1891  } else {
1892  (void) execle(interp, interp, prog, NULL, envp);
1893  mg_cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
1894  strerror(ERRNO));
1895  }
1896  }
1897  exit(EXIT_FAILURE);
1898  }
1899 
1900  return pid;
1901 }
1902 #endif /* !NO_CGI */
1903 
1904 static int set_non_blocking_mode(SOCKET sock)
1905 {
1906  int flags;
1907 
1908  flags = fcntl(sock, F_GETFL, 0);
1909  (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1910 
1911  return 0;
1912 }
1913 #endif /* _WIN32 */
1914 
1915 /* Write data to the IO channel - opened file descriptor, socket or SSL
1916  descriptor. Return number of bytes written. */
1917 static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
1918  int64_t len)
1919 {
1920  int64_t sent;
1921  int n, k;
1922 
1923  (void) ssl; /* Get rid of warning */
1924  sent = 0;
1925  while (sent < len) {
1926 
1927  /* How many bytes we send in this iteration */
1928  k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
1929 
1930 #ifndef NO_SSL
1931  if (ssl != NULL) {
1932  n = SSL_write(ssl, buf + sent, k);
1933  } else
1934 #endif
1935  if (fp != NULL) {
1936  n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
1937  if (ferror(fp))
1938  n = -1;
1939  } else {
1940  n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
1941  }
1942 
1943  if (n <= 0)
1944  break;
1945 
1946  sent += n;
1947  }
1948 
1949  return sent;
1950 }
1951 
1952 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
1953  Return negative value on error, or number of bytes read on success. */
1954 static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
1955 {
1956  int nread;
1957 
1958  if (fp != NULL) {
1959  /* Use read() instead of fread(), because if we're reading from the
1960  CGI pipe, fread() may block until IO buffer is filled up. We cannot
1961  afford to block and must pass all read bytes immediately to the
1962  client. */
1963  nread = read(fileno(fp), buf, (size_t) len);
1964 #ifndef NO_SSL
1965  } else if (conn->ssl != NULL) {
1966  nread = SSL_read(conn->ssl, buf, len);
1967 #endif
1968  } else {
1969  nread = recv(conn->client.sock, buf, (size_t) len, 0);
1970  }
1971 
1972  return conn->ctx->stop_flag ? -1 : nread;
1973 }
1974 
1975 static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
1976 {
1977  int n, nread = 0;
1978 
1979  while (len > 0 && conn->ctx->stop_flag == 0) {
1980  n = pull(fp, conn, buf + nread, len);
1981  if (n < 0) {
1982  nread = n; /* Propagate the error */
1983  break;
1984  } else if (n == 0) {
1985  break; /* No more data to read */
1986  } else {
1987  conn->consumed_content += n;
1988  nread += n;
1989  len -= n;
1990  }
1991  }
1992 
1993  return nread;
1994 }
1995 
1996 int mg_read(struct mg_connection *conn, void *buf, size_t len)
1997 {
1998  int n, buffered_len, nread;
1999  const char *body;
2000 
2001  /* If Content-Length is not set, read until socket is closed */
2002  if (conn->consumed_content == 0 && conn->content_len == 0) {
2003  conn->content_len = INT64_MAX;
2004  conn->must_close = 1;
2005  }
2006 
2007  nread = 0;
2008  if (conn->consumed_content < conn->content_len) {
2009  /* Adjust number of bytes to read. */
2010  int64_t to_read = conn->content_len - conn->consumed_content;
2011  if (to_read < (int64_t) len) {
2012  len = (size_t) to_read;
2013  }
2014 
2015  /* Return buffered data */
2016  body = conn->buf + conn->request_len + conn->consumed_content;
2017  buffered_len = (int)(&conn->buf[conn->data_len] - body);
2018  if (buffered_len > 0) {
2019  if (len < (size_t) buffered_len) {
2020  buffered_len = (int) len;
2021  }
2022  memcpy(buf, body, (size_t) buffered_len);
2023  len -= buffered_len;
2024  conn->consumed_content += buffered_len;
2025  nread += buffered_len;
2026  buf = (char *) buf + buffered_len;
2027  }
2028 
2029  /* We have returned all buffered data. Read new data from the remote
2030  socket. */
2031  n = pull_all(NULL, conn, (char *) buf, (int) len);
2032  nread = n >= 0 ? nread + n : n;
2033  }
2034  return nread;
2035 }
2036 
2037 int mg_write(struct mg_connection *conn, const void *buf, size_t len)
2038 {
2039  time_t now;
2040  int64_t n, total, allowed;
2041 
2042  if (conn->throttle > 0) {
2043  if ((now = time(NULL)) != conn->last_throttle_time) {
2044  conn->last_throttle_time = now;
2045  conn->last_throttle_bytes = 0;
2046  }
2047  allowed = conn->throttle - conn->last_throttle_bytes;
2048  if (allowed > (int64_t) len) {
2049  allowed = len;
2050  }
2051  if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
2052  (int64_t) allowed)) == allowed) {
2053  buf = (char *) buf + total;
2054  conn->last_throttle_bytes += total;
2055  while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
2056  allowed = conn->throttle > (int64_t) len - total ?
2057  (int64_t) len - total : conn->throttle;
2058  if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
2059  (int64_t) allowed)) != allowed) {
2060  break;
2061  }
2062  sleep(1);
2063  conn->last_throttle_bytes = allowed;
2064  conn->last_throttle_time = time(NULL);
2065  buf = (char *) buf + n;
2066  total += n;
2067  }
2068  }
2069  } else {
2070  total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
2071  (int64_t) len);
2072  }
2073  return (int) total;
2074 }
2075 
2076 /* Alternative alloc_vprintf() for non-compliant C runtimes */
2077 static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
2078 {
2079  va_list ap_copy;
2080  int size = MG_BUF_LEN;
2081  int len = -1;
2082 
2083  *buf = NULL;
2084  while (len == -1) {
2085  if (*buf) free(*buf);
2086  *buf = (char *)malloc(size *= 4);
2087  if (!*buf) break;
2088  va_copy(ap_copy, ap);
2089  len = vsnprintf(*buf, size, fmt, ap_copy);
2090  va_end(ap_copy);
2091  }
2092 
2093  return len;
2094 }
2095 
2096 /* Print message to buffer. If buffer is large enough to hold the message,
2097  return buffer. If buffer is to small, allocate large enough buffer on heap,
2098  and return allocated buffer. */
2099 static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
2100 {
2101  va_list ap_copy;
2102  int len;
2103 
2104  /* Windows is not standard-compliant, and vsnprintf() returns -1 if
2105  buffer is too small. Also, older versions of msvcrt.dll do not have
2106  _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
2107  Therefore, we make two passes: on first pass, get required message
2108  length.
2109  On second pass, actually print the message. */
2110  va_copy(ap_copy, ap);
2111  len = vsnprintf(NULL, 0, fmt, ap_copy);
2112  va_end(ap_copy);
2113 
2114  if (len < 0) {
2115  /* C runtime is not standard compliant, vsnprintf() returned -1.
2116  Switch to alternative code path that uses incremental allocations.
2117  */
2118  va_copy(ap_copy, ap);
2119  len = alloc_vprintf2(buf, fmt, ap);
2120  va_end(ap_copy);
2121  } else if (len > (int) size &&
2122  (size = len + 1) > 0 &&
2123  (*buf = (char *) malloc(size)) == NULL) {
2124  len = -1; /* Allocation failed, mark failure */
2125  } else {
2126  va_copy(ap_copy, ap);
2127  IGNORE_UNUSED_RESULT(vsnprintf(*buf, size, fmt, ap_copy));
2128  va_end(ap_copy);
2129  }
2130 
2131  return len;
2132 }
2133 
2134 int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap);
2135 
2136 int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
2137 {
2138  char mem[MG_BUF_LEN], *buf = mem;
2139  int len;
2140 
2141  if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
2142  len = mg_write(conn, buf, (size_t) len);
2143  }
2144  if (buf != mem && buf != NULL) {
2145  free(buf);
2146  }
2147 
2148  return len;
2149 }
2150 
2151 int mg_printf(struct mg_connection *conn, const char *fmt, ...)
2152 {
2153  va_list ap;
2154  int result;
2155 
2156  va_start(ap, fmt);
2157  result = mg_vprintf(conn, fmt, ap);
2158  va_end(ap);
2159 
2160  return result;
2161 }
2162 
2163 int mg_url_decode(const char *src, int src_len, char *dst,
2164  int dst_len, int is_form_url_encoded)
2165 {
2166  int i, j, a, b;
2167 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
2168 
2169  for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
2170  if (src[i] == '%' && i < src_len - 2 &&
2171  isxdigit(* (const unsigned char *) (src + i + 1)) &&
2172  isxdigit(* (const unsigned char *) (src + i + 2))) {
2173  a = tolower(* (const unsigned char *) (src + i + 1));
2174  b = tolower(* (const unsigned char *) (src + i + 2));
2175  dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
2176  i += 2;
2177  } else if (is_form_url_encoded && src[i] == '+') {
2178  dst[j] = ' ';
2179  } else {
2180  dst[j] = src[i];
2181  }
2182  }
2183 
2184  dst[j] = '\0'; /* Null-terminate the destination */
2185 
2186  return i >= src_len ? j : -1;
2187 }
2188 
2189 int mg_get_var(const char *data, size_t data_len, const char *name,
2190  char *dst, size_t dst_len)
2191 {
2192  return mg_get_var2(data,data_len,name,dst,dst_len,0);
2193 }
2194 
2195 int mg_get_var2(const char *data, size_t data_len, const char *name,
2196  char *dst, size_t dst_len, size_t occurrence)
2197 {
2198  const char *p, *e, *s;
2199  size_t name_len;
2200  int len;
2201 
2202  if (dst == NULL || dst_len == 0) {
2203  len = -2;
2204  } else if (data == NULL || name == NULL || data_len == 0) {
2205  len = -1;
2206  dst[0] = '\0';
2207  } else {
2208  name_len = strlen(name);
2209  e = data + data_len;
2210  len = -1;
2211  dst[0] = '\0';
2212 
2213  /* data is "var1=val1&var2=val2...". Find variable first */
2214  for (p = data; p + name_len < e; p++) {
2215  if ((p == data || p[-1] == '&') && p[name_len] == '=' &&
2216  !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
2217 
2218  /* Point p to variable value */
2219  p += name_len + 1;
2220 
2221  /* Point s to the end of the value */
2222  s = (const char *) memchr(p, '&', (size_t)(e - p));
2223  if (s == NULL) {
2224  s = e;
2225  }
2226  assert(s >= p);
2227 
2228  /* Decode variable into destination buffer */
2229  len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
2230 
2231  /* Redirect error code from -1 to -2 (destination buffer too
2232  small). */
2233  if (len == -1) {
2234  len = -2;
2235  }
2236  break;
2237  }
2238  }
2239  }
2240 
2241  return len;
2242 }
2243 
2244 int mg_get_cookie(const char *cookie_header, const char *var_name,
2245  char *dst, size_t dst_size)
2246 {
2247  const char *s, *p, *end;
2248  int name_len, len = -1;
2249 
2250  if (dst == NULL || dst_size == 0) {
2251  len = -2;
2252  } else if (var_name == NULL || (s = cookie_header) == NULL) {
2253  len = -1;
2254  dst[0] = '\0';
2255  } else {
2256  name_len = (int) strlen(var_name);
2257  end = s + strlen(s);
2258  dst[0] = '\0';
2259 
2260  for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
2261  if (s[name_len] == '=') {
2262  s += name_len + 1;
2263  if ((p = strchr(s, ' ')) == NULL)
2264  p = end;
2265  if (p[-1] == ';')
2266  p--;
2267  if (*s == '"' && p[-1] == '"' && p > s + 1) {
2268  s++;
2269  p--;
2270  }
2271  if ((size_t) (p - s) < dst_size) {
2272  len = (int)(p - s);
2273  mg_strlcpy(dst, s, (size_t) len + 1);
2274  } else {
2275  len = -3;
2276  }
2277  break;
2278  }
2279  }
2280  }
2281  return len;
2282 }
2283 
2284 static void convert_uri_to_file_name(struct mg_connection *conn, char *buf,
2285  size_t buf_len, struct file *filep,
2286  int * is_script_ressource)
2287 {
2288  struct vec a, b;
2289  const char *rewrite, *uri = conn->request_info.uri,
2290  *root = conn->ctx->config[DOCUMENT_ROOT];
2291  char *p;
2292  int match_len;
2293  char gz_path[PATH_MAX];
2294  char const* accept_encoding;
2295 
2296  *is_script_ressource = 0;
2297 
2298 #if defined(USE_WEBSOCKET)
2299  if (is_websocket_request(conn) && conn->ctx->config[WEBSOCKET_ROOT]) {
2300  root = conn->ctx->config[WEBSOCKET_ROOT];
2301  }
2302 #endif
2303 
2304  /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
2305  of the path one byte on the right.
2306  If document_root is NULL, leave the file empty. */
2307  mg_snprintf(conn, buf, buf_len - 1, "%s%s",
2308  root == NULL ? "" : root,
2309  root == NULL ? "" : uri);
2310 
2311  rewrite = conn->ctx->config[REWRITE];
2312  while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
2313  if ((match_len = match_prefix(a.ptr, (int) a.len, uri)) > 0) {
2314  mg_snprintf(conn, buf, buf_len - 1, "%.*s%s", (int) b.len, b.ptr,
2315  uri + match_len);
2316  break;
2317  }
2318  }
2319 
2320  if (mg_stat(conn, buf, filep)) return;
2321 
2322  /* if we can't find the actual file, look for the file
2323  with the same name but a .gz extension. If we find it,
2324  use that and set the gzipped flag in the file struct
2325  to indicate that the response need to have the content-
2326  encoding: gzip header
2327  we can only do this if the browser declares support */
2328  if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
2329  if (strstr(accept_encoding,"gzip") != NULL) {
2330  snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
2331  if (mg_stat(conn, gz_path, filep)) {
2332  filep->gzipped = 1;
2333  return;
2334  }
2335  }
2336  }
2337 
2338  /* Support PATH_INFO for CGI scripts. */
2339  for (p = buf + strlen(buf); p > buf + 1; p--) {
2340  if (*p == '/') {
2341  *p = '\0';
2342  if ((match_prefix(conn->ctx->config[CGI_EXTENSIONS],
2343  (int)strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0
2344 #ifdef USE_LUA
2345  ||
2346  match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
2347  (int)strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]), buf) > 0
2348 #endif
2349  ) && mg_stat(conn, buf, filep)) {
2350  /* Shift PATH_INFO block one character right, e.g.
2351  "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
2352  conn->path_info is pointing to the local variable "path"
2353  declared in handle_request(), so PATH_INFO is not valid
2354  after handle_request returns. */
2355  conn->path_info = p + 1;
2356  memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for
2357  trailing \0 */
2358  p[1] = '/';
2359  *is_script_ressource = 1;
2360  break;
2361  } else {
2362  *p = '/';
2363  }
2364  }
2365  }
2366 }
2367 
2368 /* Check whether full request is buffered. Return:
2369  -1 if request is malformed
2370  0 if request is not yet fully buffered
2371  >0 actual request length, including last \r\n\r\n */
2372 static int get_request_len(const char *buf, int buflen)
2373 {
2374  const char *s, *e;
2375  int len = 0;
2376 
2377  for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
2378  /* Control characters are not allowed but >=128 is. */
2379  if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
2380  *s != '\n' && * (const unsigned char *) s < 128) {
2381  len = -1;
2382  break; /* [i_a] abort scan as soon as one malformed character is
2383  found; */
2384  /* don't let subsequent \r\n\r\n win us over anyhow */
2385  } else if (s[0] == '\n' && s[1] == '\n') {
2386  len = (int) (s - buf) + 2;
2387  } else if (s[0] == '\n' && &s[1] < e &&
2388  s[1] == '\r' && s[2] == '\n') {
2389  len = (int) (s - buf) + 3;
2390  }
2391 
2392  return len;
2393 }
2394 
2395 /* Convert month to the month number. Return -1 on error, or month number */
2396 static int get_month_index(const char *s)
2397 {
2398  size_t i;
2399 
2400  for (i = 0; i < ARRAY_SIZE(month_names); i++)
2401  if (!strcmp(s, month_names[i]))
2402  return (int) i;
2403 
2404  return -1;
2405 }
2406 
2407 static int num_leap_years(int year)
2408 {
2409  return year / 4 - year / 100 + year / 400;
2410 }
2411 
2412 /* Parse UTC date-time string, and return the corresponding time_t value. */
2413 static time_t parse_date_string(const char *datetime)
2414 {
2415  static const unsigned short days_before_month[] = {
2416  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
2417  };
2418  char month_str[32];
2419  int second, minute, hour, day, month, year, leap_days, days;
2420  time_t result = (time_t) 0;
2421 
2422  if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
2423  &day, month_str, &year, &hour, &minute, &second) == 6) ||
2424  (sscanf(datetime, "%d %3s %d %d:%d:%d",
2425  &day, month_str, &year, &hour, &minute, &second) == 6) ||
2426  (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
2427  &day, month_str, &year, &hour, &minute, &second) == 6) ||
2428  (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
2429  &day, month_str, &year, &hour, &minute, &second) == 6)) &&
2430  year > 1970 &&
2431  (month = get_month_index(month_str)) != -1) {
2432  leap_days = num_leap_years(year) - num_leap_years(1970);
2433  year -= 1970;
2434  days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
2435  result = (time_t) days * 24 * 3600 + (time_t) hour * 3600 +
2436  minute * 60 + second;
2437  }
2438 
2439  return result;
2440 }
2441 
2442 /* Protect against directory disclosure attack by removing '..',
2443  excessive '/' and '\' characters */
2445 {
2446  char *p = s;
2447 
2448  while (*s != '\0') {
2449  *p++ = *s++;
2450  if (s[-1] == '/' || s[-1] == '\\') {
2451  /* Skip all following slashes, backslashes and double-dots */
2452  while (s[0] != '\0') {
2453  if (s[0] == '/' || s[0] == '\\') {
2454  s++;
2455  } else if (s[0] == '.' && s[1] == '.') {
2456  s += 2;
2457  } else {
2458  break;
2459  }
2460  }
2461  }
2462  }
2463  *p = '\0';
2464 }
2465 
2466 static const struct {
2467  const char *extension;
2468  size_t ext_len;
2469  const char *mime_type;
2470 } builtin_mime_types[] = {
2471  /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
2472  application types */
2473  {".doc", 4, "application/msword"},
2474  {".eps", 4, "application/postscript"},
2475  {".exe", 4, "application/octet-stream"},
2476  {".js", 3, "application/javascript"},
2477  {".json", 5, "application/json"},
2478  {".pdf", 4, "application/pdf"},
2479  {".ps", 3, "application/postscript"},
2480  {".rtf", 4, "application/rtf"},
2481  {".xhtml", 6, "application/xhtml+xml"},
2482  {".xsl", 4, "application/xml"},
2483  {".xslt", 5, "application/xml"},
2484 
2485  /* audio */
2486  {".mp3", 4, "audio/mpeg"},
2487  {".oga", 4, "audio/ogg"},
2488  {".ogg", 4, "audio/ogg"},
2489 
2490  /* image */
2491  {".gif", 4, "image/gif"},
2492  {".ief", 4, "image/ief"},
2493  {".jpeg", 5, "image/jpeg"},
2494  {".jpg", 4, "image/jpeg"},
2495  {".jpm", 4, "image/jpm"},
2496  {".jpx", 4, "image/jpx"},
2497  {".png", 4, "image/png"},
2498  {".svg", 4, "image/svg+xml"},
2499  {".tif", 4, "image/tiff"},
2500  {".tiff", 5, "image/tiff"},
2501 
2502  /* model */
2503  {".wrl", 4, "model/vrml"},
2504 
2505  /* text */
2506  {".css", 4, "text/css"},
2507  {".csv", 4, "text/csv"},
2508  {".htm", 4, "text/html"},
2509  {".html", 5, "text/html"},
2510  {".sgm", 4, "text/sgml"},
2511  {".shtm", 5, "text/html"},
2512  {".shtml", 6, "text/html"},
2513  {".txt", 4, "text/plain"},
2514  {".xml", 4, "text/xml"},
2515 
2516  /* video */
2517  {".mov", 4, "video/quicktime"},
2518  {".mp4", 4, "video/mp4"},
2519  {".mpeg", 5, "video/mpeg"},
2520  {".mpg", 4, "video/mpeg"},
2521  {".ogv", 4, "video/ogg"},
2522  {".qt", 3, "video/quicktime"},
2523 
2524  /* not registered types
2525  (http://reference.sitepoint.com/html/mime-types-full,
2526  http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
2527  {".arj", 4, "application/x-arj-compressed"},
2528  {".gz", 3, "application/x-gunzip"},
2529  {".rar", 4, "application/x-arj-compressed"},
2530  {".swf", 4, "application/x-shockwave-flash"},
2531  {".tar", 4, "application/x-tar"},
2532  {".tgz", 4, "application/x-tar-gz"},
2533  {".torrent", 8, "application/x-bittorrent"},
2534  {".ppt", 4, "application/x-mspowerpoint"},
2535  {".xls", 4, "application/x-msexcel"},
2536  {".zip", 4, "application/x-zip-compressed"},
2537  {".aac", 4, "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
2538  {".aif", 4, "audio/x-aif"},
2539  {".m3u", 4, "audio/x-mpegurl"},
2540  {".mid", 4, "audio/x-midi"},
2541  {".ra", 3, "audio/x-pn-realaudio"},
2542  {".ram", 4, "audio/x-pn-realaudio"},
2543  {".wav", 4, "audio/x-wav"},
2544  {".bmp", 4, "image/bmp"},
2545  {".ico", 4, "image/x-icon"},
2546  {".pct", 4, "image/x-pct"},
2547  {".pict", 5, "image/pict"},
2548  {".rgb", 4, "image/x-rgb"},
2549  {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
2550  {".asf", 4, "video/x-ms-asf"},
2551  {".avi", 4, "video/x-msvideo"},
2552  {".m4v", 4, "video/x-m4v"},
2553  {NULL, 0, NULL}
2554 };
2555 
2556 const char *mg_get_builtin_mime_type(const char *path)
2557 {
2558  const char *ext;
2559  size_t i, path_len;
2560 
2561  path_len = strlen(path);
2562 
2563  for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
2564  ext = path + (path_len - builtin_mime_types[i].ext_len);
2565  if (path_len > builtin_mime_types[i].ext_len &&
2566  mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
2567  return builtin_mime_types[i].mime_type;
2568  }
2569  }
2570 
2571  return "text/plain";
2572 }
2573 
2574 /* Look at the "path" extension and figure what mime type it has.
2575  Store mime type in the vector. */
2576 static void get_mime_type(struct mg_context *ctx, const char *path,
2577  struct vec *vec)
2578 {
2579  struct vec ext_vec, mime_vec;
2580  const char *list, *ext;
2581  size_t path_len;
2582 
2583  path_len = strlen(path);
2584 
2585  /* Scan user-defined mime types first, in case user wants to
2586  override default mime types. */
2587  list = ctx->config[EXTRA_MIME_TYPES];
2588  while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
2589  /* ext now points to the path suffix */
2590  ext = path + path_len - ext_vec.len;
2591  if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
2592  *vec = mime_vec;
2593  return;
2594  }
2595  }
2596 
2597  vec->ptr = mg_get_builtin_mime_type(path);
2598  vec->len = strlen(vec->ptr);
2599 }
2600 
2601 /* Stringify binary data. Output buffer must be twice as big as input,
2602  because each byte takes 2 bytes in string representation */
2603 static void bin2str(char *to, const unsigned char *p, size_t len)
2604 {
2605  static const char *hex = "0123456789abcdef";
2606 
2607  for (; len--; p++) {
2608  *to++ = hex[p[0] >> 4];
2609  *to++ = hex[p[0] & 0x0f];
2610  }
2611  *to = '\0';
2612 }
2613 
2614 /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
2615 char *mg_md5(char buf[33], ...)
2616 {
2617  md5_byte_t hash[16];
2618  const char *p;
2619  va_list ap;
2620  md5_state_t ctx;
2621 
2622  md5_init(&ctx);
2623 
2624  va_start(ap, buf);
2625  while ((p = va_arg(ap, const char *)) != NULL) {
2626  md5_append(&ctx, (const md5_byte_t *) p, (int) strlen(p));
2627  }
2628  va_end(ap);
2629 
2630  md5_finish(&ctx, hash);
2631  bin2str(buf, hash, sizeof(hash));
2632  return buf;
2633 }
2634 
2635 /* Check the user's password, return 1 if OK */
2636 static int check_password(const char *method, const char *ha1, const char *uri,
2637  const char *nonce, const char *nc, const char *cnonce,
2638  const char *qop, const char *response)
2639 {
2640  char ha2[32 + 1], expected_response[32 + 1];
2641 
2642  /* Some of the parameters may be NULL */
2643  if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
2644  qop == NULL || response == NULL) {
2645  return 0;
2646  }
2647 
2648  /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
2649  /* TODO(lsm): check for authentication timeout */
2650  if (/* strcmp(dig->uri, c->ouri) != 0 || */
2651  strlen(response) != 32
2652  /* || now - strtoul(dig->nonce, NULL, 10) > 3600 */
2653  ) {
2654  return 0;
2655  }
2656 
2657  mg_md5(ha2, method, ":", uri, NULL);
2658  mg_md5(expected_response, ha1, ":", nonce, ":", nc,
2659  ":", cnonce, ":", qop, ":", ha2, NULL);
2660 
2661  return mg_strcasecmp(response, expected_response) == 0;
2662 }
2663 
2664 /* Use the global passwords file, if specified by auth_gpass option,
2665  or search for .htpasswd in the requested directory. */
2666 static void open_auth_file(struct mg_connection *conn, const char *path,
2667  struct file *filep)
2668 {
2669  char name[PATH_MAX];
2670  const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
2671  struct file file = STRUCT_FILE_INITIALIZER;
2672 
2673  if (gpass != NULL) {
2674  /* Use global passwords file */
2675  if (!mg_fopen(conn, gpass, "r", filep)) {
2676 #ifdef DEBUG
2677  mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
2678 #endif
2679  }
2680  /* Important: using local struct file to test path for is_directory
2681  flag.
2682  If filep is used, mg_stat() makes it appear as if auth file was
2683  opened. */
2684  } else if (mg_stat(conn, path, &file) && file.is_directory) {
2685  mg_snprintf(conn, name, sizeof(name), "%s%c%s",
2686  path, '/', PASSWORDS_FILE_NAME);
2687  if (!mg_fopen(conn, name, "r", filep)) {
2688 #ifdef DEBUG
2689  mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
2690 #endif
2691  }
2692  } else {
2693  /* Try to find .htpasswd in requested directory. */
2694  for (p = path, e = p + strlen(p) - 1; e > p; e--)
2695  if (e[0] == '/')
2696  break;
2697  mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
2698  (int) (e - p), p, '/', PASSWORDS_FILE_NAME);
2699  if (!mg_fopen(conn, name, "r", filep)) {
2700 #ifdef DEBUG
2701  mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
2702 #endif
2703  }
2704  }
2705 }
2706 
2707 /* Parsed Authorization header */
2708 struct ah {
2709  char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
2710 };
2711 
2712 /* Return 1 on success. Always initializes the ah structure. */
2713 static int parse_auth_header(struct mg_connection *conn, char *buf,
2714  size_t buf_size, struct ah *ah)
2715 {
2716  char *name, *value, *s;
2717  const char *auth_header;
2718 
2719  (void) memset(ah, 0, sizeof(*ah));
2720  if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
2721  mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
2722  return 0;
2723  }
2724 
2725  /* Make modifiable copy of the auth header */
2726  (void) mg_strlcpy(buf, auth_header + 7, buf_size);
2727  s = buf;
2728 
2729  /* Parse authorization header */
2730  for (;;) {
2731  /* Gobble initial spaces */
2732  while (isspace(* (unsigned char *) s)) {
2733  s++;
2734  }
2735  name = skip_quoted(&s, "=", " ", 0);
2736  /* Value is either quote-delimited, or ends at first comma or space. */
2737  if (s[0] == '\"') {
2738  s++;
2739  value = skip_quoted(&s, "\"", " ", '\\');
2740  if (s[0] == ',') {
2741  s++;
2742  }
2743  } else {
2744  value = skip_quoted(&s, ", ", " ", 0); /* IE uses commas, FF uses
2745  spaces */
2746  }
2747  if (*name == '\0') {
2748  break;
2749  }
2750 
2751  if (!strcmp(name, "username")) {
2752  ah->user = value;
2753  } else if (!strcmp(name, "cnonce")) {
2754  ah->cnonce = value;
2755  } else if (!strcmp(name, "response")) {
2756  ah->response = value;
2757  } else if (!strcmp(name, "uri")) {
2758  ah->uri = value;
2759  } else if (!strcmp(name, "qop")) {
2760  ah->qop = value;
2761  } else if (!strcmp(name, "nc")) {
2762  ah->nc = value;
2763  } else if (!strcmp(name, "nonce")) {
2764  ah->nonce = value;
2765  }
2766  }
2767 
2768  /* CGI needs it as REMOTE_USER */
2769  if (ah->user != NULL) {
2770  conn->request_info.remote_user = mg_strdup(ah->user);
2771  } else {
2772  return 0;
2773  }
2774 
2775  return 1;
2776 }
2777 
2778 static char *mg_fgets(char *buf, size_t size, struct file *filep, char **p)
2779 {
2780  char *eof;
2781  size_t len;
2782  char *memend;
2783 
2784  if (filep->membuf != NULL && *p != NULL) {
2785  memend = (char *) &filep->membuf[filep->size];
2786  eof = (char *) memchr(*p, '\n', memend - *p); /* Search for \n from p
2787  till the end of
2788  stream */
2789  if (eof != NULL) {
2790  eof += 1; /* Include \n */
2791  } else {
2792  eof = memend; /* Copy remaining data */
2793  }
2794  len = (size_t) (eof - *p) > size - 1 ? size - 1 : (size_t) (eof - *p);
2795  memcpy(buf, *p, len);
2796  buf[len] = '\0';
2797  *p += len;
2798  return len ? eof : NULL;
2799  } else if (filep->fp != NULL) {
2800  return fgets(buf, (int)size, filep->fp);
2801  } else {
2802  return NULL;
2803  }
2804 }
2805 
2806 /* Authorize against the opened passwords file. Return 1 if authorized. */
2807 static int authorize(struct mg_connection *conn, struct file *filep)
2808 {
2809  struct ah ah;
2810  char line[256], f_user[256] = "", ha1[256] = "", f_domain[256] = "", buf[MG_BUF_LEN], *p;
2811 
2812  if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
2813  return 0;
2814  }
2815 
2816  /* Loop over passwords file */
2817  p = (char *) filep->membuf;
2818  while (mg_fgets(line, sizeof(line), filep, &p) != NULL) {
2819  if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
2820  continue;
2821  }
2822 
2823  if (!strcmp(ah.user, f_user) &&
2824  !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
2825  return check_password(conn->request_info.request_method, ha1, ah.uri,
2826  ah.nonce, ah.nc, ah.cnonce, ah.qop, ah.response);
2827  }
2828 
2829  return 0;
2830 }
2831 
2832 /* Return 1 if request is authorised, 0 otherwise. */
2833 static int check_authorization(struct mg_connection *conn, const char *path)
2834 {
2835  char fname[PATH_MAX];
2836  struct vec uri_vec, filename_vec;
2837  const char *list;
2838  struct file file = STRUCT_FILE_INITIALIZER;
2839  int authorized = 1;
2840 
2841  list = conn->ctx->config[PROTECT_URI];
2842  while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
2843  if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
2844  mg_snprintf(conn, fname, sizeof(fname), "%.*s",
2845  (int) filename_vec.len, filename_vec.ptr);
2846  if (!mg_fopen(conn, fname, "r", &file)) {
2847  mg_cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
2848  }
2849  break;
2850  }
2851  }
2852 
2853  if (!is_file_opened(&file)) {
2854  open_auth_file(conn, path, &file);
2855  }
2856 
2857  if (is_file_opened(&file)) {
2858  authorized = authorize(conn, &file);
2859  mg_fclose(&file);
2860  }
2861 
2862  return authorized;
2863 }
2864 
2865 static void send_authorization_request(struct mg_connection *conn)
2866 {
2867  char date[64];
2868  time_t curtime = time(NULL);
2869 
2870  conn->status_code = 401;
2871  conn->must_close = 1;
2872 
2873  gmt_time_string(date, sizeof(date), &curtime);
2874 
2875  mg_printf(conn,
2876  "HTTP/1.1 401 Unauthorized\r\n"
2877  "Date: %s\r\n"
2878  "Connection: %s\r\n"
2879  "Content-Length: 0\r\n"
2880  "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
2881  date, suggest_connection_header(conn),
2882  conn->ctx->config[AUTHENTICATION_DOMAIN],
2883  (unsigned long) time(NULL));
2884 }
2885 
2886 static int is_authorized_for_put(struct mg_connection *conn)
2887 {
2888  struct file file = STRUCT_FILE_INITIALIZER;
2889  const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
2890  int ret = 0;
2891 
2892  if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
2893  ret = authorize(conn, &file);
2894  mg_fclose(&file);
2895  }
2896 
2897  return ret;
2898 }
2899 
2900 int mg_modify_passwords_file(const char *fname, const char *domain,
2901  const char *user, const char *pass)
2902 {
2903  int found;
2904  char line[512], u[512] = "", d[512] ="", ha1[33], tmp[PATH_MAX+1];
2905  FILE *fp, *fp2;
2906 
2907  found = 0;
2908  fp = fp2 = NULL;
2909 
2910  /* Regard empty password as no password - remove user record. */
2911  if (pass != NULL && pass[0] == '\0') {
2912  pass = NULL;
2913  }
2914 
2915  (void) snprintf(tmp, sizeof(tmp) - 1, "%s.tmp", fname);
2916  tmp[sizeof(tmp) - 1] = 0;
2917 
2918  /* Create the file if does not exist */
2919  if ((fp = fopen(fname, "a+")) != NULL) {
2920  (void) fclose(fp);
2921  }
2922 
2923  /* Open the given file and temporary file */
2924  if ((fp = fopen(fname, "r")) == NULL) {
2925  return 0;
2926  } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
2927  fclose(fp);
2928  return 0;
2929  }
2930 
2931  /* Copy the stuff to temporary file */
2932  while (fgets(line, sizeof(line), fp) != NULL) {
2933  if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
2934  continue;
2935  }
2936 
2937  if (!strcmp(u, user) && !strcmp(d, domain)) {
2938  found++;
2939  if (pass != NULL) {
2940  mg_md5(ha1, user, ":", domain, ":", pass, NULL);
2941  fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
2942  }
2943  } else {
2944  fprintf(fp2, "%s", line);
2945  }
2946  }
2947 
2948  /* If new user, just add it */
2949  if (!found && pass != NULL) {
2950  mg_md5(ha1, user, ":", domain, ":", pass, NULL);
2951  fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
2952  }
2953 
2954  /* Close files */
2955  fclose(fp);
2956  fclose(fp2);
2957 
2958  /* Put the temp file in place of real file */
2959  IGNORE_UNUSED_RESULT(remove(fname));
2960  IGNORE_UNUSED_RESULT(rename(tmp, fname));
2961 
2962  return 1;
2963 }
2964 
2965 static SOCKET conn2(struct mg_context *ctx /* may be null */, const char *host, int port,
2966  int use_ssl, char *ebuf, size_t ebuf_len)
2967 {
2968  struct sockaddr_in sain;
2969  struct hostent *he;
2970  SOCKET sock = INVALID_SOCKET;
2971 
2972  if (host == NULL) {
2973  snprintf(ebuf, ebuf_len, "%s", "NULL host");
2974  } else if (use_ssl && SSLv23_client_method == NULL) {
2975  snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
2976  /* TODO(lsm): use something threadsafe instead of gethostbyname() */
2977  } else if ((he = gethostbyname(host)) == NULL) {
2978  snprintf(ebuf, ebuf_len, "gethostbyname(%s): %s", host, strerror(ERRNO));
2979  } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
2980  snprintf(ebuf, ebuf_len, "socket(): %s", strerror(ERRNO));
2981  } else {
2982  set_close_on_exec(sock, fc(ctx));
2983  memset(&sain, '\0', sizeof(sain));
2984  sain.sin_family = AF_INET;
2985  sain.sin_port = htons((uint16_t) port);
2986  sain.sin_addr = * (struct in_addr *) he->h_addr_list[0];
2987  if (connect(sock, (struct sockaddr *) &sain, sizeof(sain)) != 0) {
2988  snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
2989  host, port, strerror(ERRNO));
2990  closesocket(sock);
2991  sock = INVALID_SOCKET;
2992  }
2993  }
2994  return sock;
2995 }
2996 
2997 int mg_url_encode(const char *src, char *dst, size_t dst_len)
2998 {
2999  static const char *dont_escape = "._-$,;~()";
3000  static const char *hex = "0123456789abcdef";
3001  char *pos = dst;
3002  const char *end = dst + dst_len - 1;
3003 
3004  for (; *src != '\0' && pos < end; src++, pos++) {
3005  if (isalnum(*(const unsigned char *) src) ||
3006  strchr(dont_escape, * (const unsigned char *) src) != NULL) {
3007  *pos = *src;
3008  } else if (pos + 2 < end) {
3009  pos[0] = '%';
3010  pos[1] = hex[(* (const unsigned char *) src) >> 4];
3011  pos[2] = hex[(* (const unsigned char *) src) & 0xf];
3012  pos += 2;
3013  } else {
3014  return -1;
3015  }
3016  }
3017 
3018  *pos = '\0';
3019  return (*src == '\0') ? (int)(pos - dst) : -1;
3020 }
3021 
3022 static void print_dir_entry(struct de *de)
3023 {
3024  char size[64], mod[64], href[PATH_MAX];
3025  struct tm *tm;
3026 
3027  if (de->file.is_directory) {
3028  mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
3029  } else {
3030  /* We use (signed) cast below because MSVC 6 compiler cannot
3031  convert unsigned __int64 to double. Sigh. */
3032  if (de->file.size < 1024) {
3033  mg_snprintf(de->conn, size, sizeof(size), "%d", (int) de->file.size);
3034  } else if (de->file.size < 0x100000) {
3035  mg_snprintf(de->conn, size, sizeof(size),
3036  "%.1fk", (double) de->file.size / 1024.0);
3037  } else if (de->file.size < 0x40000000) {
3038  mg_snprintf(de->conn, size, sizeof(size),
3039  "%.1fM", (double) de->file.size / 1048576);
3040  } else {
3041  mg_snprintf(de->conn, size, sizeof(size),
3042  "%.1fG", (double) de->file.size / 1073741824);
3043  }
3044  }
3045  tm = localtime(&de->file.modification_time);
3046  if (tm != NULL) {
3047  strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
3048  } else {
3049  strncpy(mod, "01-Jan-1970 00:00", sizeof(mod));
3050  mod[sizeof(mod) - 1] = '\0';
3051  }
3052  mg_url_encode(de->file_name, href, sizeof(href));
3053  de->conn->num_bytes_sent += mg_printf(de->conn,
3054  "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
3055  "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
3056  de->conn->request_info.uri, href, de->file.is_directory ? "/" : "",
3057  de->file_name, de->file.is_directory ? "/" : "", mod, size);
3058 }
3059 
3060 /* This function is called from send_directory() and used for
3061  sorting directory entries by size, or name, or modification time.
3062  On windows, __cdecl specification is needed in case if project is built
3063  with __stdcall convention. qsort always requires __cdels callback. */
3064 static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
3065 {
3066  const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
3067  const char *query_string = a->conn->request_info.query_string;
3068  int cmp_result = 0;
3069 
3070  if (query_string == NULL) {
3071  query_string = "na";
3072  }
3073 
3074  if (a->file.is_directory && !b->file.is_directory) {
3075  return -1; /* Always put directories on top */
3076  } else if (!a->file.is_directory && b->file.is_directory) {
3077  return 1; /* Always put directories on top */
3078  } else if (*query_string == 'n') {
3079  cmp_result = strcmp(a->file_name, b->file_name);
3080  } else if (*query_string == 's') {
3081  cmp_result = a->file.size == b->file.size ? 0 :
3082  a->file.size > b->file.size ? 1 : -1;
3083  } else if (*query_string == 'd') {
3084  cmp_result = a->file.modification_time == b->file.modification_time ? 0 :
3085  a->file.modification_time > b->file.modification_time ? 1 : -1;
3086  }
3087 
3088  return query_string[1] == 'd' ? -cmp_result : cmp_result;
3089 }
3090 
3091 static int must_hide_file(struct mg_connection *conn, const char *path)
3092 {
3093  const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
3094  const char *pattern = conn->ctx->config[HIDE_FILES];
3095  return match_prefix(pw_pattern, (int)strlen(pw_pattern), path) > 0 ||
3096  (pattern != NULL && match_prefix(pattern, (int)strlen(pattern), path) > 0);
3097 }
3098 
3099 static int scan_directory(struct mg_connection *conn, const char *dir,
3100  void *data, void (*cb)(struct de *, void *))
3101 {
3102  char path[PATH_MAX];
3103  struct dirent *dp;
3104  DIR *dirp;
3105  struct de de;
3106 
3107  if ((dirp = opendir(dir)) == NULL) {
3108  return 0;
3109  } else {
3110  de.conn = conn;
3111 
3112  while ((dp = readdir(dirp)) != NULL) {
3113  /* Do not show current dir and hidden files */
3114  if (!strcmp(dp->d_name, ".") ||
3115  !strcmp(dp->d_name, "..") ||
3116  must_hide_file(conn, dp->d_name)) {
3117  continue;
3118  }
3119 
3120  mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3121 
3122  /* If we don't memset stat structure to zero, mtime will have
3123  garbage and strftime() will segfault later on in
3124  print_dir_entry(). memset is required only if mg_stat()
3125  fails. For more details, see
3126  http://code.google.com/p/mongoose/issues/detail?id=79 */
3127  memset(&de.file, 0, sizeof(de.file));
3128  if (!mg_stat(conn, path, &de.file)) {
3129  mg_cry(conn, "%s: mg_stat(%s) failed: %s",
3130  __func__, path, strerror(ERRNO));
3131  }
3132 
3133  de.file_name = dp->d_name;
3134  cb(&de, data);
3135  }
3136  (void) closedir(dirp);
3137  }
3138  return 1;
3139 }
3140 
3141 static int remove_directory(struct mg_connection *conn, const char *dir)
3142 {
3143  char path[PATH_MAX];
3144  struct dirent *dp;
3145  DIR *dirp;
3146  struct de de;
3147 
3148  if ((dirp = opendir(dir)) == NULL) {
3149  return 0;
3150  } else {
3151  de.conn = conn;
3152 
3153  while ((dp = readdir(dirp)) != NULL) {
3154  /* Do not show current dir (but show hidden files as they will
3155  also be removed) */
3156  if (!strcmp(dp->d_name, ".") ||
3157  !strcmp(dp->d_name, "..")) {
3158  continue;
3159  }
3160 
3161  mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
3162 
3163  /* If we don't memset stat structure to zero, mtime will have
3164  garbage and strftime() will segfault later on in
3165  print_dir_entry(). memset is required only if mg_stat()
3166  fails. For more details, see
3167  http://code.google.com/p/mongoose/issues/detail?id=79 */
3168  memset(&de.file, 0, sizeof(de.file));
3169  if (!mg_stat(conn, path, &de.file)) {
3170  mg_cry(conn, "%s: mg_stat(%s) failed: %s",
3171  __func__, path, strerror(ERRNO));
3172  }
3173  if(de.file.modification_time) {
3174  if(de.file.is_directory) {
3175  remove_directory(conn, path);
3176  } else {
3177  mg_remove(path);
3178  }
3179  }
3180 
3181  }
3182  (void) closedir(dirp);
3183 
3184  IGNORE_UNUSED_RESULT(rmdir(dir));
3185  }
3186 
3187  return 1;
3188 }
3189 
3190 struct dir_scan_data {
3191  struct de *entries;
3192  int num_entries;
3193  int arr_size;
3194 };
3195 
3196 /* Behaves like realloc(), but frees original pointer on failure */
3197 static void *realloc2(void *ptr, size_t size)
3198 {
3199  void *new_ptr = realloc(ptr, size);
3200  if (new_ptr == NULL) {
3201  free(ptr);
3202  }
3203  return new_ptr;
3204 }
3205 
3206 static void dir_scan_callback(struct de *de, void *data)
3207 {
3208  struct dir_scan_data *dsd = (struct dir_scan_data *) data;
3209 
3210  if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
3211  dsd->arr_size *= 2;
3212  dsd->entries = (struct de *) realloc2(dsd->entries, dsd->arr_size *
3213  sizeof(dsd->entries[0]));
3214  }
3215  if (dsd->entries == NULL) {
3216  /* TODO(lsm): propagate an error to the caller */
3217  dsd->num_entries = 0;
3218  } else {
3219  dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
3220  dsd->entries[dsd->num_entries].file = de->file;
3221  dsd->entries[dsd->num_entries].conn = de->conn;
3222  dsd->num_entries++;
3223  }
3224 }
3225 
3226 static void handle_directory_request(struct mg_connection *conn,
3227  const char *dir)
3228 {
3229  int i, sort_direction;
3230  struct dir_scan_data data = { NULL, 0, 128 };
3231  char date[64];
3232  time_t curtime = time(NULL);
3233 
3234  if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
3235  send_http_error(conn, 500, "Cannot open directory",
3236  "Error: opendir(%s): %s", dir, strerror(ERRNO));
3237  return;
3238  }
3239 
3240  gmt_time_string(date, sizeof(date), &curtime);
3241 
3242  sort_direction = conn->request_info.query_string != NULL &&
3243  conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
3244 
3245  conn->must_close = 1;
3246  mg_printf(conn, "HTTP/1.1 200 OK\r\n"
3247  "Date: %s\r\n"
3248  "Connection: close\r\n"
3249  "Content-Type: text/html; charset=utf-8\r\n\r\n",
3250  date);
3251 
3252  conn->num_bytes_sent += mg_printf(conn,
3253  "<html><head><title>Index of %s</title>"
3254  "<style>th {text-align: left;}</style></head>"
3255  "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
3256  "<tr><th><a href=\"?n%c\">Name</a></th>"
3257  "<th><a href=\"?d%c\">Modified</a></th>"
3258  "<th><a href=\"?s%c\">Size</a></th></tr>"
3259  "<tr><td colspan=\"3\"><hr></td></tr>",
3260  conn->request_info.uri, conn->request_info.uri,
3261  sort_direction, sort_direction, sort_direction);
3262 
3263  /* Print first entry - link to a parent directory */
3264  conn->num_bytes_sent += mg_printf(conn,
3265  "<tr><td><a href=\"%s%s\">%s</a></td>"
3266  "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
3267  conn->request_info.uri, "..", "Parent directory", "-", "-");
3268 
3269  /* Sort and print directory entries */
3270  if (data.entries != NULL) {
3271  qsort(data.entries, (size_t) data.num_entries,
3272  sizeof(data.entries[0]), compare_dir_entries);
3273  for (i = 0; i < data.num_entries; i++) {
3274  print_dir_entry(&data.entries[i]);
3275  free(data.entries[i].file_name);
3276  }
3277  free(data.entries);
3278  }
3279 
3280  conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
3281  conn->status_code = 200;
3282 }
3283 
3284 /* Send len bytes from the opened file to the client. */
3285 static void send_file_data(struct mg_connection *conn, struct file *filep,
3286  int64_t offset, int64_t len)
3287 {
3288  char buf[MG_BUF_LEN];
3289  int to_read, num_read, num_written;
3290 
3291  /* Sanity check the offset */
3292  offset = offset < 0 ? 0 : offset > filep->size ? filep->size : offset;
3293 
3294  if (len > 0 && filep->membuf != NULL && filep->size > 0) {
3295  if (len > filep->size - offset) {
3296  len = filep->size - offset;
3297  }
3298  mg_write(conn, filep->membuf + offset, (size_t) len);
3299  } else if (len > 0 && filep->fp != NULL) {
3300  if (offset > 0 && fseeko(filep->fp, offset, SEEK_SET) != 0) {
3301  mg_cry(conn, "%s: fseeko() failed: %s",
3302  __func__, strerror(ERRNO));
3303  }
3304  while (len > 0) {
3305  /* Calculate how much to read from the file in the buffer */
3306  to_read = sizeof(buf);
3307  if ((int64_t) to_read > len) {
3308  to_read = (int) len;
3309  }
3310 
3311  /* Read from file, exit the loop on error */
3312  if ((num_read = (int) fread(buf, 1, (size_t) to_read, filep->fp)) <= 0) {
3313  break;
3314  }
3315 
3316  /* Send read bytes to the client, exit the loop on error */
3317  if ((num_written = mg_write(conn, buf, (size_t) num_read)) != num_read) {
3318  break;
3319  }
3320 
3321  /* Both read and were successful, adjust counters */
3322  conn->num_bytes_sent += num_written;
3323  len -= num_written;
3324  }
3325  }
3326 }
3327 
3328 static int parse_range_header(const char *header, int64_t *a, int64_t *b)
3329 {
3330  return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
3331 }
3332 
3333 static void construct_etag(char *buf, size_t buf_len,
3334  const struct file *filep)
3335 {
3336  snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
3337  (unsigned long) filep->modification_time, filep->size);
3338 }
3339 
3340 static void fclose_on_exec(struct file *filep, struct mg_connection *conn)
3341 {
3342  if (filep != NULL && filep->fp != NULL) {
3343 #ifdef _WIN32
3344  (void) conn; /* Unused. */
3345 #else
3346  if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
3347  mg_cry(conn, "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
3348  __func__, strerror(ERRNO));
3349  }
3350 #endif
3351  }
3352 }
3353 
3354 static void handle_file_request(struct mg_connection *conn, const char *path,
3355  struct file *filep)
3356 {
3357  char date[64], lm[64], etag[64], range[64];
3358  const char *msg = "OK", *hdr;
3359  time_t curtime = time(NULL);
3360  int64_t cl, r1, r2;
3361  struct vec mime_vec;
3362  int n;
3363  char gz_path[PATH_MAX];
3364  char const* encoding = "";
3365 
3366  get_mime_type(conn->ctx, path, &mime_vec);
3367  cl = filep->size;
3368  conn->status_code = 200;
3369  range[0] = '\0';
3370 
3371  /* if this file is in fact a pre-gzipped file, rewrite its filename
3372  it's important to rewrite the filename after resolving
3373  the mime type from it, to preserve the actual file's type */
3374  if (filep->gzipped) {
3375  snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
3376  path = gz_path;
3377  encoding = "Content-Encoding: gzip\r\n";
3378  }
3379 
3380  if (!mg_fopen(conn, path, "rb", filep)) {
3381  send_http_error(conn, 500, http_500_error,
3382  "fopen(%s): %s", path, strerror(ERRNO));
3383  return;
3384  }
3385 
3386  fclose_on_exec(filep, conn);
3387 
3388  /* If Range: header specified, act accordingly */
3389  r1 = r2 = 0;
3390  hdr = mg_get_header(conn, "Range");
3391  if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 &&
3392  r1 >= 0 && r2 >= 0) {
3393  /* actually, range requests don't play well with a pre-gzipped
3394  file (since the range is specified in the uncompressed space) */
3395  if (filep->gzipped) {
3396  send_http_error(conn, 501, "Not Implemented", "range requests in gzipped files are not supported");
3397  mg_fclose(filep);
3398  return;
3399  }
3400  conn->status_code = 206;
3401 cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
3402  mg_snprintf(conn, range, sizeof(range),
3403  "Content-Range: bytes "
3404  "%" INT64_FMT "-%"
3405  INT64_FMT "/%" INT64_FMT "\r\n",
3406  r1, r1 + cl - 1, filep->size);
3407  msg = "Partial Content";
3408  }
3409 
3410  /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
3411  http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
3412  gmt_time_string(date, sizeof(date), &curtime);
3413  gmt_time_string(lm, sizeof(lm), &filep->modification_time);
3414  construct_etag(etag, sizeof(etag), filep);
3415 
3416  (void) mg_printf(conn,
3417  "HTTP/1.1 %d %s\r\n"
3418  "Date: %s\r\n"
3419  "Last-Modified: %s\r\n"
3420  "Etag: %s\r\n"
3421  "Content-Type: %.*s\r\n"
3422  "Content-Length: %" INT64_FMT "\r\n"
3423  "Connection: %s\r\n"
3424  "Accept-Ranges: bytes\r\n"
3425  "%s%s\r\n",
3426  conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
3427  mime_vec.ptr, cl, suggest_connection_header(conn), range, encoding);
3428 
3429  if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
3430  send_file_data(conn, filep, r1, cl);
3431  }
3432  mg_fclose(filep);
3433 }
3434 
3435 void mg_send_file(struct mg_connection *conn, const char *path)
3436 {
3437  struct file file = STRUCT_FILE_INITIALIZER;
3438  if (mg_stat(conn, path, &file)) {
3439  handle_file_request(conn, path, &file);
3440  } else {
3441  send_http_error(conn, 404, "Not Found", "%s", "File not found");
3442  }
3443 }
3444 
3445 
3446 /* Parse HTTP headers from the given buffer, advance buffer to the point
3447  where parsing stopped. */
3448 static void parse_http_headers(char **buf, struct mg_request_info *ri)
3449 {
3450  int i;
3451 
3452  ri->num_headers = 0;
3453  for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
3454  ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
3455  ri->http_headers[i].value = skip(buf, "\r\n");
3456  if (ri->http_headers[i].name[0] == '\0')
3457  break;
3458  ri->num_headers = i + 1;
3459  }
3460 }
3461 
3462 static int is_valid_http_method(const char *method)
3463 {
3464  return !strcmp(method, "GET") || !strcmp(method, "POST") ||
3465  !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
3466  !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
3467  !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
3468  || !strcmp(method, "MKCOL")
3469  ;
3470 }
3471 
3472 /* Parse HTTP request, fill in mg_request_info structure.
3473  This function modifies the buffer by NUL-terminating
3474  HTTP request components, header names and header values. */
3475 static int parse_http_message(char *buf, int len, struct mg_request_info *ri)
3476 {
3477  int is_request, request_length = get_request_len(buf, len);
3478  if (request_length > 0) {
3479  /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port */
3480  ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
3481  ri->num_headers = 0;
3482 
3483  buf[request_length - 1] = '\0';
3484 
3485  /* RFC says that all initial whitespaces should be ingored */
3486  while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
3487  buf++;
3488  }
3489  ri->request_method = skip(&buf, " ");
3490  ri->uri = skip(&buf, " ");
3491  ri->http_version = skip(&buf, "\r\n");
3492 
3493  /* HTTP message could be either HTTP request or HTTP response, e.g.
3494  "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
3495  is_request = is_valid_http_method(ri->request_method);
3496  if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0) ||
3497  (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
3498  request_length = -1;
3499  } else {
3500  if (is_request) {
3501  ri->http_version += 5;
3502  }
3503  parse_http_headers(&buf, ri);
3504  }
3505  }
3506  return request_length;
3507 }
3508 
3509 /* Keep reading the input (either opened file descriptor fd, or socket sock,
3510  or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
3511  buffer (which marks the end of HTTP request). Buffer buf may already
3512  have some data. The length of the data is stored in nread.
3513  Upon every read operation, increase nread by the number of bytes read. */
3514 static int read_request(FILE *fp, struct mg_connection *conn,
3515  char *buf, int bufsiz, int *nread)
3516 {
3517  int request_len, n = 0;
3518 
3519  request_len = get_request_len(buf, *nread);
3520  while (conn->ctx->stop_flag == 0 &&
3521  *nread < bufsiz && request_len == 0 &&
3522  (n = pull(fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
3523  *nread += n;
3524  assert(*nread <= bufsiz);
3525  request_len = get_request_len(buf, *nread);
3526  }
3527 
3528  return request_len <= 0 && n <= 0 ? -1 : request_len;
3529 }
3530 
3531 /* For given directory path, substitute it to valid index file.
3532  Return 1 if index file has been found, 0 if not found.
3533  If the file is found, it's stats is returned in stp. */
3534 static int substitute_index_file(struct mg_connection *conn, char *path,
3535  size_t path_len, struct file *filep)
3536 {
3537  const char *list = conn->ctx->config[INDEX_FILES];
3538  struct file file = STRUCT_FILE_INITIALIZER;
3539  struct vec filename_vec;
3540  size_t n = strlen(path);
3541  int found = 0;
3542 
3543  /* The 'path' given to us points to the directory. Remove all trailing
3544  directory separator characters from the end of the path, and
3545  then append single directory separator character. */
3546  while (n > 0 && path[n - 1] == '/') {
3547  n--;
3548  }
3549  path[n] = '/';
3550 
3551  /* Traverse index files list. For each entry, append it to the given
3552  path and see if the file exists. If it exists, break the loop */
3553  while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
3554 
3555  /* Ignore too long entries that may overflow path buffer */
3556  if (filename_vec.len > path_len - (n + 2))
3557  continue;
3558 
3559  /* Prepare full path to the index file */
3560  mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
3561 
3562  /* Does it exist? */
3563  if (mg_stat(conn, path, &file)) {
3564  /* Yes it does, break the loop */
3565  *filep = file;
3566  found = 1;
3567  break;
3568  }
3569  }
3570 
3571  /* If no index file exists, restore directory path */
3572  if (!found) {
3573  path[n] = '\0';
3574  }
3575 
3576  return found;
3577 }
3578 
3579 /* Return True if we should reply 304 Not Modified. */
3580 static int is_not_modified(const struct mg_connection *conn,
3581  const struct file *filep)
3582 {
3583  char etag[64];
3584  const char *ims = mg_get_header(conn, "If-Modified-Since");
3585  const char *inm = mg_get_header(conn, "If-None-Match");
3586  construct_etag(etag, sizeof(etag), filep);
3587  return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
3588  (ims != NULL && filep->modification_time <= parse_date_string(ims));
3589 }
3590 
3591 static int forward_body_data(struct mg_connection *conn, FILE *fp,
3592  SOCKET sock, SSL *ssl)
3593 {
3594  const char *expect, *body;
3595  char buf[MG_BUF_LEN];
3596  int to_read, nread, buffered_len, success = 0;
3597 
3598  expect = mg_get_header(conn, "Expect");
3599  assert(fp != NULL);
3600 
3601  if (conn->content_len == -1) {
3602  send_http_error(conn, 411, "Length Required", "%s", "");
3603  } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
3604  send_http_error(conn, 417, "Expectation Failed", "%s", "");
3605  } else {
3606  if (expect != NULL) {
3607  (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
3608  }
3609 
3610  body = conn->buf + conn->request_len + conn->consumed_content;
3611  buffered_len = (int)(&conn->buf[conn->data_len] - body);
3612  assert(buffered_len >= 0);
3613  assert(conn->consumed_content == 0);
3614 
3615  if (buffered_len > 0) {
3616  if ((int64_t) buffered_len > conn->content_len) {
3617  buffered_len = (int) conn->content_len;
3618  }
3619  push(fp, sock, ssl, body, (int64_t) buffered_len);
3620  conn->consumed_content += buffered_len;
3621  }
3622 
3623  nread = 0;
3624  while (conn->consumed_content < conn->content_len) {
3625  to_read = sizeof(buf);
3626  if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
3627  to_read = (int) (conn->content_len - conn->consumed_content);
3628  }
3629  nread = pull(NULL, conn, buf, to_read);
3630  if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
3631  break;
3632  }
3633  conn->consumed_content += nread;
3634  }
3635 
3636  if (conn->consumed_content == conn->content_len) {
3637  success = nread >= 0;
3638  }
3639 
3640  /* Each error code path in this function must send an error */
3641  if (!success) {
3642  send_http_error(conn, 577, http_500_error, "%s", "");
3643  }
3644  }
3645 
3646  return success;
3647 }
3648 
3649 #if !defined(NO_CGI)
3650 /* This structure helps to create an environment for the spawned CGI program.
3651  Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
3652  last element must be NULL.
3653  However, on Windows there is a requirement that all these VARIABLE=VALUE\0
3654  strings must reside in a contiguous buffer. The end of the buffer is
3655  marked by two '\0' characters.
3656  We satisfy both worlds: we create an envp array (which is vars), all
3657  entries are actually pointers inside buf. */
3658 struct cgi_env_block {
3659  struct mg_connection *conn;
3660  char buf[CGI_ENVIRONMENT_SIZE]; /* Environment buffer */
3661  int len; /* Space taken */
3662  char *vars[MAX_CGI_ENVIR_VARS]; /* char **envp */
3663  int nvars; /* Number of variables */
3664 };
3665 
3666 static char *addenv(struct cgi_env_block *block,
3667  PRINTF_FORMAT_STRING(const char *fmt), ...)
3668 PRINTF_ARGS(2, 3);
3669 
3670 /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
3671  pointer into the vars array. */
3672 static char *addenv(struct cgi_env_block *block, const char *fmt, ...)
3673 {
3674  int n, space;
3675  char *added;
3676  va_list ap;
3677 
3678  /* Calculate how much space is left in the buffer */
3679  space = sizeof(block->buf) - block->len - 2;
3680  assert(space >= 0);
3681 
3682  /* Make a pointer to the free space int the buffer */
3683  added = block->buf + block->len;
3684 
3685  /* Copy VARIABLE=VALUE\0 string into the free space */
3686  va_start(ap, fmt);
3687  n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
3688  va_end(ap);
3689 
3690  /* Make sure we do not overflow buffer and the envp array */
3691  if (n > 0 && n + 1 < space &&
3692  block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
3693  /* Append a pointer to the added string into the envp array */
3694  block->vars[block->nvars++] = added;
3695  /* Bump up used length counter. Include \0 terminator */
3696  block->len += n + 1;
3697  } else {
3698  mg_cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt);
3699  }
3700 
3701  return added;
3702 }
3703 
3704 static void prepare_cgi_environment(struct mg_connection *conn,
3705  const char *prog,
3706  struct cgi_env_block *blk)
3707 {
3708  const char *s, *slash;
3709  struct vec var_vec;
3710  char *p, src_addr[IP_ADDR_STR_LEN];
3711  int i;
3712 
3713  blk->len = blk->nvars = 0;
3714  blk->conn = conn;
3715  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
3716 
3717  addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
3718  addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
3719  addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
3720  addenv(blk, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
3721 
3722  /* Prepare the environment block */
3723  addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
3724  addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
3725  addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
3726 
3727  /* TODO(lsm): fix this for IPv6 case */
3728  addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
3729 
3730  addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
3731  addenv(blk, "REMOTE_ADDR=%s", src_addr);
3732  addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
3733  addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
3734 
3735  /* SCRIPT_NAME */
3736  assert(conn->request_info.uri[0] == '/');
3737  slash = strrchr(conn->request_info.uri, '/');
3738  if ((s = strrchr(prog, '/')) == NULL)
3739  s = prog;
3740  addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri),
3741  conn->request_info.uri, s);
3742 
3743  addenv(blk, "SCRIPT_FILENAME=%s", prog);
3744  addenv(blk, "PATH_TRANSLATED=%s", prog);
3745  addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
3746 
3747  if ((s = mg_get_header(conn, "Content-Type")) != NULL)
3748  addenv(blk, "CONTENT_TYPE=%s", s);
3749 
3750  if (conn->request_info.query_string != NULL)
3751  addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
3752 
3753  if ((s = mg_get_header(conn, "Content-Length")) != NULL)
3754  addenv(blk, "CONTENT_LENGTH=%s", s);
3755 
3756  if ((s = getenv("PATH")) != NULL)
3757  addenv(blk, "PATH=%s", s);
3758 
3759  if (conn->path_info != NULL) {
3760  addenv(blk, "PATH_INFO=%s", conn->path_info);
3761  }
3762 
3763 #if defined(_WIN32)
3764  if ((s = getenv("COMSPEC")) != NULL) {
3765  addenv(blk, "COMSPEC=%s", s);
3766  }
3767  if ((s = getenv("SYSTEMROOT")) != NULL) {
3768  addenv(blk, "SYSTEMROOT=%s", s);
3769  }
3770  if ((s = getenv("SystemDrive")) != NULL) {
3771  addenv(blk, "SystemDrive=%s", s);
3772  }
3773  if ((s = getenv("ProgramFiles")) != NULL) {
3774  addenv(blk, "ProgramFiles=%s", s);
3775  }
3776  if ((s = getenv("ProgramFiles(x86)")) != NULL) {
3777  addenv(blk, "ProgramFiles(x86)=%s", s);
3778  }
3779 #else
3780  if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
3781  addenv(blk, "LD_LIBRARY_PATH=%s", s);
3782 #endif /* _WIN32 */
3783 
3784  if ((s = getenv("PERLLIB")) != NULL)
3785  addenv(blk, "PERLLIB=%s", s);
3786 
3787  if (conn->request_info.remote_user != NULL) {
3788  addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
3789  addenv(blk, "%s", "AUTH_TYPE=Digest");
3790  }
3791 
3792  /* Add all headers as HTTP_* variables */
3793  for (i = 0; i < conn->request_info.num_headers; i++) {
3794  p = addenv(blk, "HTTP_%s=%s",
3795  conn->request_info.http_headers[i].name,
3796  conn->request_info.http_headers[i].value);
3797 
3798  /* Convert variable name into uppercase, and change - to _ */
3799  for (; *p != '=' && *p != '\0'; p++) {
3800  if (*p == '-')
3801  *p = '_';
3802  *p = (char) toupper(* (unsigned char *) p);
3803  }
3804  }
3805 
3806  /* Add user-specified variables */
3807  s = conn->ctx->config[CGI_ENVIRONMENT];
3808  while ((s = next_option(s, &var_vec, NULL)) != NULL) {
3809  addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr);
3810  }
3811 
3812  blk->vars[blk->nvars++] = NULL;
3813  blk->buf[blk->len++] = '\0';
3814 
3815  assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
3816  assert(blk->len > 0);
3817  assert(blk->len < (int) sizeof(blk->buf));
3818 }
3819 
3820 static void handle_cgi_request(struct mg_connection *conn, const char *prog)
3821 {
3822  char *buf;
3823  size_t buflen;
3824  int headers_len, data_len, i, fdin[2] = { 0, 0 }, fdout[2] = { 0, 0 };
3825  const char *status, *status_text, *connection_state;
3826  char *pbuf, dir[PATH_MAX], *p;
3827  struct mg_request_info ri;
3828  struct cgi_env_block blk;
3829  FILE *in = NULL, *out = NULL;
3830  struct file fout = STRUCT_FILE_INITIALIZER;
3831  pid_t pid = (pid_t) -1;
3832 
3833  buf = NULL;
3834  buflen = 16384;
3835  prepare_cgi_environment(conn, prog, &blk);
3836 
3837  /* CGI must be executed in its own directory. 'dir' must point to the
3838  directory containing executable program, 'p' must point to the
3839  executable program name relative to 'dir'. */
3840  (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
3841  if ((p = strrchr(dir, '/')) != NULL) {
3842  *p++ = '\0';
3843  } else {
3844  dir[0] = '.', dir[1] = '\0';
3845  p = (char *) prog;
3846  }
3847 
3848  if (pipe(fdin) != 0 || pipe(fdout) != 0) {
3849  send_http_error(conn, 500, http_500_error,
3850  "Cannot create CGI pipe: %s", strerror(ERRNO));
3851  goto done;
3852  }
3853 
3854  pid = spawn_process(conn, p, blk.buf, blk.vars, fdin[0], fdout[1], dir);
3855  if (pid == (pid_t) -1) {
3856  send_http_error(conn, 500, http_500_error,
3857  "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
3858  goto done;
3859  }
3860 
3861  /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
3862  set_close_on_exec(fdin[0], conn);
3863  set_close_on_exec(fdin[1], conn);
3864  set_close_on_exec(fdout[0], conn);
3865  set_close_on_exec(fdout[1], conn);
3866 
3867  /* Parent closes only one side of the pipes.
3868  If we don't mark them as closed, close() attempt before
3869  return from this function throws an exception on Windows.
3870  Windows does not like when closed descriptor is closed again. */
3871  (void) close(fdin[0]);
3872  (void) close(fdout[1]);
3873  fdin[0] = fdout[1] = -1;
3874 
3875 
3876  if ((in = fdopen(fdin[1], "wb")) == NULL ||
3877  (out = fdopen(fdout[0], "rb")) == NULL) {
3878  send_http_error(conn, 500, http_500_error,
3879  "fopen: %s", strerror(ERRNO));
3880  goto done;
3881  }
3882 
3883  setbuf(in, NULL);
3884  setbuf(out, NULL);
3885  fout.fp = out;
3886 
3887  /* Send POST data to the CGI process if needed */
3888  if (!strcmp(conn->request_info.request_method, "POST") &&
3889  !forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
3890  goto done;
3891  }
3892 
3893  /* Close so child gets an EOF. */
3894  fclose(in);
3895  in = NULL;
3896  fdin[1] = -1;
3897 
3898  /* Now read CGI reply into a buffer. We need to set correct
3899  status code, thus we need to see all HTTP headers first.
3900  Do not send anything back to client, until we buffer in all
3901  HTTP headers. */
3902  data_len = 0;
3903  buf = malloc(buflen);
3904  if (buf == NULL) {
3905  send_http_error(conn, 500, http_500_error,
3906  "Not enough memory for buffer (%u bytes)",
3907  (unsigned int) buflen);
3908  goto done;
3909  }
3910  headers_len = read_request(out, conn, buf, (int) buflen, &data_len);
3911  if (headers_len <= 0) {
3912  send_http_error(conn, 500, http_500_error,
3913  "CGI program sent malformed or too big (>%u bytes) "
3914  "HTTP headers: [%.*s]",
3915  (unsigned) buflen, data_len, buf);
3916  goto done;
3917  }
3918  pbuf = buf;
3919  buf[headers_len - 1] = '\0';
3920  parse_http_headers(&pbuf, &ri);
3921 
3922  /* Make up and send the status line */
3923  status_text = "OK";
3924  if ((status = get_header(&ri, "Status")) != NULL) {
3925  conn->status_code = atoi(status);
3926  status_text = status;
3927  while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
3928  status_text++;
3929  }
3930  } else if (get_header(&ri, "Location") != NULL) {
3931  conn->status_code = 302;
3932  } else {
3933  conn->status_code = 200;
3934  }
3935  connection_state = get_header(&ri, "Connection");
3936  if (connection_state == NULL ||
3937  mg_strcasecmp(connection_state, "keep-alive")) {
3938  conn->must_close = 1;
3939  }
3940  (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code,
3941  status_text);
3942 
3943  /* Send headers */
3944  for (i = 0; i < ri.num_headers; i++) {
3945  mg_printf(conn, "%s: %s\r\n",
3946  ri.http_headers[i].name, ri.http_headers[i].value);
3947  }
3948  mg_write(conn, "\r\n", 2);
3949 
3950  /* Send chunk of data that may have been read after the headers */
3951  conn->num_bytes_sent += mg_write(conn, buf + headers_len,
3952  (size_t)(data_len - headers_len));
3953 
3954  /* Read the rest of CGI output and send to the client */
3955  send_file_data(conn, &fout, 0, INT64_MAX);
3956 
3957 done:
3958  if (pid != (pid_t) -1) {
3959  kill(pid, SIGKILL);
3960 #if !defined(_WIN32)
3961  {
3962  int st;
3963  while (waitpid(pid, &st, 0) != -1); /* clean zombies */
3964  }
3965 #endif
3966  }
3967  if (fdin[0] != -1) {
3968  close(fdin[0]);
3969  }
3970  if (fdout[1] != -1) {
3971  close(fdout[1]);
3972  }
3973 
3974  if (in != NULL) {
3975  fclose(in);
3976  } else if (fdin[1] != -1) {
3977  close(fdin[1]);
3978  }
3979 
3980  if (out != NULL) {
3981  fclose(out);
3982  } else if (fdout[0] != -1) {
3983  close(fdout[0]);
3984  }
3985  if (buf != NULL) {
3986  free(buf);
3987  }
3988 }
3989 #endif /* !NO_CGI */
3990 
3991 /* For a given PUT path, create all intermediate subdirectories
3992  for given path. Return 0 if the path itself is a directory,
3993  or -1 on error, 1 if OK. */
3994 static int put_dir(struct mg_connection *conn, const char *path)
3995 {
3996  char buf[PATH_MAX];
3997  const char *s, *p;
3998  struct file file = STRUCT_FILE_INITIALIZER;
3999  int len, res = 1;
4000 
4001  for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
4002  len = (int)(p - path);
4003  if (len >= (int) sizeof(buf)) {
4004  res = -1;
4005  break;
4006  }
4007  memcpy(buf, path, len);
4008  buf[len] = '\0';
4009 
4010  /* Try to create intermediate directory */
4011  DEBUG_TRACE(("mkdir(%s)", buf));
4012  if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
4013  res = -1;
4014  break;
4015  }
4016 
4017  /* Is path itself a directory? */
4018  if (p[1] == '\0') {
4019  res = 0;
4020  }
4021  }
4022 
4023  return res;
4024 }
4025 
4026 static void mkcol(struct mg_connection *conn, const char *path)
4027 {
4028  int rc, body_len;
4029  struct de de;
4030  char date[64];
4031  time_t curtime = time(NULL);
4032 
4033  memset(&de.file, 0, sizeof(de.file));
4034  if (!mg_stat(conn, path, &de.file)) {
4035  mg_cry(conn, "%s: mg_stat(%s) failed: %s",
4036  __func__, path, strerror(ERRNO));
4037  }
4038 
4039  if(de.file.modification_time) {
4040  send_http_error(conn, 405, "Method Not Allowed",
4041  "mkcol(%s): %s", path, strerror(ERRNO));
4042  return;
4043  }
4044 
4045  body_len = conn->data_len - conn->request_len;
4046  if(body_len > 0) {
4047  send_http_error(conn, 415, "Unsupported media type",
4048  "mkcol(%s): %s", path, strerror(ERRNO));
4049  return;
4050  }
4051 
4052  rc = mg_mkdir(path, 0755);
4053 
4054  if (rc == 0) {
4055  conn->status_code = 201;
4056  gmt_time_string(date, sizeof(date), &curtime);
4057  mg_printf(conn, "HTTP/1.1 %d Created\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n",
4058  conn->status_code, date, suggest_connection_header(conn));
4059  } else if (rc == -1) {
4060  if(errno == EEXIST)
4061  send_http_error(conn, 405, "Method Not Allowed",
4062  "mkcol(%s): %s", path, strerror(ERRNO));
4063  else if(errno == EACCES)
4064  send_http_error(conn, 403, "Forbidden",
4065  "mkcol(%s): %s", path, strerror(ERRNO));
4066  else if(errno == ENOENT)
4067  send_http_error(conn, 409, "Conflict",
4068  "mkcol(%s): %s", path, strerror(ERRNO));
4069  else
4070  send_http_error(conn, 500, http_500_error,
4071  "fopen(%s): %s", path, strerror(ERRNO));
4072  }
4073 }
4074 
4075 static void put_file(struct mg_connection *conn, const char *path)
4076 {
4077  struct file file = STRUCT_FILE_INITIALIZER;
4078  const char *range;
4079  int64_t r1, r2;
4080  int rc;
4081  char date[64];
4082  time_t curtime = time(NULL);
4083 
4084  conn->status_code = mg_stat(conn, path, &file) ? 200 : 201;
4085 
4086  if ((rc = put_dir(conn, path)) == 0) {
4087  gmt_time_string(date, sizeof(date), &curtime);
4088  mg_printf(conn, "HTTP/1.1 %d OK\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n",
4089  conn->status_code, date, suggest_connection_header(conn));
4090  } else if (rc == -1) {
4091  send_http_error(conn, 500, http_500_error,
4092  "put_dir(%s): %s", path, strerror(ERRNO));
4093  } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
4094  mg_fclose(&file);
4095  send_http_error(conn, 500, http_500_error,
4096  "fopen(%s): %s", path, strerror(ERRNO));
4097  } else {
4098  fclose_on_exec(&file, conn);
4099  range = mg_get_header(conn, "Content-Range");
4100  r1 = r2 = 0;
4101  if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
4102  conn->status_code = 206;
4103  fseeko(file.fp, r1, SEEK_SET);
4104  }
4105  if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
4106  conn->status_code = 500;
4107  }
4108  gmt_time_string(date, sizeof(date), &curtime);
4109  mg_printf(conn, "HTTP/1.1 %d OK\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n",
4110  conn->status_code, date, suggest_connection_header(conn));
4111  mg_fclose(&file);
4112  }
4113 }
4114 
4115 static void send_ssi_file(struct mg_connection *, const char *,
4116  struct file *, int);
4117 
4118 static void do_ssi_include(struct mg_connection *conn, const char *ssi,
4119  char *tag, int include_level)
4120 {
4121  char file_name[MG_BUF_LEN], path[PATH_MAX], *p;
4122  struct file file = STRUCT_FILE_INITIALIZER;
4123 
4124  /* sscanf() is safe here, since send_ssi_file() also uses buffer
4125  of size MG_BUF_LEN to get the tag. So strlen(tag) is
4126  always < MG_BUF_LEN. */
4127  if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
4128  /* File name is relative to the webserver root */
4129  (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s",
4130  conn->ctx->config[DOCUMENT_ROOT], '/', file_name);
4131  } else if (sscanf(tag, " abspath=\"%[^\"]\"", file_name) == 1) {
4132  /* File name is relative to the webserver working directory
4133  or it is absolute system path */
4134  (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name);
4135  } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1 ||
4136  sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
4137  /* File name is relative to the currect document */
4138  (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi);
4139  if ((p = strrchr(path, '/')) != NULL) {
4140  p[1] = '\0';
4141  }
4142  (void) mg_snprintf(conn, path + strlen(path),
4143  sizeof(path) - strlen(path), "%s", file_name);
4144  } else {
4145  mg_cry(conn, "Bad SSI #include: [%s]", tag);
4146  return;
4147  }
4148 
4149  if (!mg_fopen(conn, path, "rb", &file)) {
4150  mg_cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
4151  tag, path, strerror(ERRNO));
4152  } else {
4153  fclose_on_exec(&file, conn);
4154  if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
4155  (int)strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
4156  send_ssi_file(conn, path, &file, include_level + 1);
4157  } else {
4158  send_file_data(conn, &file, 0, INT64_MAX);
4159  }
4160  mg_fclose(&file);
4161  }
4162 }
4163 
4164 #if !defined(NO_POPEN)
4165 static void do_ssi_exec(struct mg_connection *conn, char *tag)
4166 {
4167  char cmd[MG_BUF_LEN] = "";
4168  struct file file = STRUCT_FILE_INITIALIZER;
4169 
4170  if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
4171  mg_cry(conn, "Bad SSI #exec: [%s]", tag);
4172  } else if ((file.fp = popen(cmd, "r")) == NULL) {
4173  mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
4174  } else {
4175  send_file_data(conn, &file, 0, INT64_MAX);
4176  pclose(file.fp);
4177  }
4178 }
4179 #endif /* !NO_POPEN */
4180 
4181 static int mg_fgetc(struct file *filep, int offset)
4182 {
4183  if (filep->membuf != NULL && offset >=0 && offset < filep->size) {
4184  return ((unsigned char *) filep->membuf)[offset];
4185  } else if (filep->fp != NULL) {
4186  return fgetc(filep->fp);
4187  } else {
4188  return EOF;
4189  }
4190 }
4191 
4192 static void send_ssi_file(struct mg_connection *conn, const char *path,
4193  struct file *filep, int include_level)
4194 {
4195  char buf[MG_BUF_LEN];
4196  int ch, offset, len, in_ssi_tag;
4197 
4198  if (include_level > 10) {
4199  mg_cry(conn, "SSI #include level is too deep (%s)", path);
4200  return;
4201  }
4202 
4203  in_ssi_tag = len = offset = 0;
4204  while ((ch = mg_fgetc(filep, offset)) != EOF) {
4205  if (in_ssi_tag && ch == '>') {
4206  in_ssi_tag = 0;
4207  buf[len++] = (char) ch;
4208  buf[len] = '\0';
4209  assert(len <= (int) sizeof(buf));
4210  if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
4211  /* Not an SSI tag, pass it */
4212  (void) mg_write(conn, buf, (size_t) len);
4213  } else {
4214  if (!memcmp(buf + 5, "include", 7)) {
4215  do_ssi_include(conn, path, buf + 12, include_level);
4216 #if !defined(NO_POPEN)
4217  } else if (!memcmp(buf + 5, "exec", 4)) {
4218  do_ssi_exec(conn, buf + 9);
4219 #endif /* !NO_POPEN */
4220  } else {
4221  mg_cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
4222  }
4223  }
4224  len = 0;
4225  } else if (in_ssi_tag) {
4226  if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
4227  /* Not an SSI tag */
4228  in_ssi_tag = 0;
4229  } else if (len == (int) sizeof(buf) - 2) {
4230  mg_cry(conn, "%s: SSI tag is too large", path);
4231  len = 0;
4232  }
4233  buf[len++] = ch & 0xff;
4234  } else if (ch == '<') {
4235  in_ssi_tag = 1;
4236  if (len > 0) {
4237  mg_write(conn, buf, (size_t) len);
4238  }
4239  len = 0;
4240  buf[len++] = ch & 0xff;
4241  } else {
4242  buf[len++] = ch & 0xff;
4243  if (len == (int) sizeof(buf)) {
4244  mg_write(conn, buf, (size_t) len);
4245  len = 0;
4246  }
4247  }
4248  }
4249 
4250  /* Send the rest of buffered data */
4251  if (len > 0) {
4252  mg_write(conn, buf, (size_t) len);
4253  }
4254 }
4255 
4256 static void handle_ssi_file_request(struct mg_connection *conn,
4257  const char *path)
4258 {
4259  struct file file = STRUCT_FILE_INITIALIZER;
4260  char date[64];
4261  time_t curtime = time(NULL);
4262 
4263  if (!mg_fopen(conn, path, "rb", &file)) {
4264  send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
4265  strerror(ERRNO));
4266  } else {
4267  conn->must_close = 1;
4268  gmt_time_string(date, sizeof(date), &curtime);
4269  fclose_on_exec(&file, conn);
4270  mg_printf(conn, "HTTP/1.1 200 OK\r\n"
4271  "Date: %s\r\n"
4272  "Content-Type: text/html\r\n"
4273  "Connection: %s\r\n\r\n",
4274  date, suggest_connection_header(conn));
4275  send_ssi_file(conn, path, &file, 0);
4276  mg_fclose(&file);
4277  }
4278 }
4279 
4280 static void send_options(struct mg_connection *conn)
4281 {
4282  char date[64];
4283  time_t curtime = time(NULL);
4284 
4285  conn->status_code = 200;
4286  conn->must_close = 1;
4287  gmt_time_string(date, sizeof(date), &curtime);
4288 
4289  mg_printf(conn, "HTTP/1.1 200 OK\r\n"
4290  "Date: %s\r\n"
4291  "Connection: %s\r\n"
4292  "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
4293  "DAV: 1\r\n\r\n",
4294  date, suggest_connection_header(conn));
4295 }
4296 
4297 /* Writes PROPFIND properties for a collection element */
4298 static void print_props(struct mg_connection *conn, const char* uri,
4299  struct file *filep)
4300 {
4301  char mtime[64];
4302  gmt_time_string(mtime, sizeof(mtime), &filep->modification_time);
4303  conn->num_bytes_sent += mg_printf(conn,
4304  "<d:response>"
4305  "<d:href>%s</d:href>"
4306  "<d:propstat>"
4307  "<d:prop>"
4308  "<d:resourcetype>%s</d:resourcetype>"
4309  "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
4310  "<d:getlastmodified>%s</d:getlastmodified>"
4311  "</d:prop>"
4312  "<d:status>HTTP/1.1 200 OK</d:status>"
4313  "</d:propstat>"
4314  "</d:response>\n",
4315  uri,
4316  filep->is_directory ? "<d:collection/>" : "",
4317  filep->size,
4318  mtime);
4319 }
4320 
4321 static void print_dav_dir_entry(struct de *de, void *data)
4322 {
4323  char href[PATH_MAX];
4324  char href_encoded[PATH_MAX];
4325  struct mg_connection *conn = (struct mg_connection *) data;
4326  mg_snprintf(conn, href, sizeof(href), "%s%s",
4327  conn->request_info.uri, de->file_name);
4328  mg_url_encode(href, href_encoded, PATH_MAX-1);
4329  print_props(conn, href_encoded, &de->file);
4330 }
4331 
4332 static void handle_propfind(struct mg_connection *conn, const char *path,
4333  struct file *filep)
4334 {
4335  const char *depth = mg_get_header(conn, "Depth");
4336  char date[64];
4337  time_t curtime = time(NULL);
4338 
4339  gmt_time_string(date, sizeof(date), &curtime);
4340 
4341  conn->must_close = 1;
4342  conn->status_code = 207;
4343  mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
4344  "Date: %s\r\n"
4345  "Connection: %s\r\n"
4346  "Content-Type: text/xml; charset=utf-8\r\n\r\n",
4347  date, suggest_connection_header(conn));
4348 
4349  conn->num_bytes_sent += mg_printf(conn,
4350  "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
4351  "<d:multistatus xmlns:d='DAV:'>\n");
4352 
4353  /* Print properties for the requested resource itself */
4354  print_props(conn, conn->request_info.uri, filep);
4355 
4356  /* If it is a directory, print directory entries too if Depth is not 0 */
4357  if (filep->is_directory &&
4358  !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
4359  (depth == NULL || strcmp(depth, "0") != 0)) {
4360  scan_directory(conn, path, conn, &print_dav_dir_entry);
4361  }
4362 
4363  conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
4364 }
4365 
4366 void mg_lock(struct mg_connection* conn)
4367 {
4368  (void) pthread_mutex_lock(&conn->mutex);
4369 }
4370 
4371 void mg_unlock(struct mg_connection* conn)
4372 {
4373  (void) pthread_mutex_unlock(&conn->mutex);
4374 }
4375 
4376 #ifdef USE_LUA
4377 #include "mod_lua.inl"
4378 #endif /* USE_LUA */
4379 
4380 #if defined(USE_WEBSOCKET)
4381 
4382 /* START OF SHA-1 code
4383  Copyright(c) By Steve Reid <steve@edmweb.com> */
4384 #define SHA1HANDSOFF
4385 #if defined(__sun)
4386 #include "solarisfixes.h"
4387 #endif
4388 
4389 static int is_big_endian(void)
4390 {
4391  static const int n = 1;
4392  return ((char *) &n)[0] == 0;
4393 }
4394 
4395 union char64long16 {
4396  unsigned char c[64];
4397  uint32_t l[16];
4398 };
4399 
4400 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
4401 
4402 static uint32_t blk0(union char64long16 *block, int i)
4403 {
4404  /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
4405  if (!is_big_endian()) {
4406  block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
4407  (rol(block->l[i], 8) & 0x00FF00FF);
4408  }
4409  return block->l[i];
4410 }
4411 
4412 #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
4413  ^block->l[(i+2)&15]^block->l[i&15],1))
4414 #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
4415 #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
4416 #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
4417 #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
4418 #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
4419 
4420 typedef struct {
4421  uint32_t state[5];
4422  uint32_t count[2];
4423  unsigned char buffer[64];
4424 } SHA1_CTX;
4425 
4426 static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
4427 {
4428  uint32_t a, b, c, d, e;
4429  union char64long16 block[1];
4430 
4431  memcpy(block, buffer, 64);
4432  a = state[0];
4433  b = state[1];
4434  c = state[2];
4435  d = state[3];
4436  e = state[4];
4437  R0(a,b,c,d,e, 0);
4438  R0(e,a,b,c,d, 1);
4439  R0(d,e,a,b,c, 2);
4440  R0(c,d,e,a,b, 3);
4441  R0(b,c,d,e,a, 4);
4442  R0(a,b,c,d,e, 5);
4443  R0(e,a,b,c,d, 6);
4444  R0(d,e,a,b,c, 7);
4445  R0(c,d,e,a,b, 8);
4446  R0(b,c,d,e,a, 9);
4447  R0(a,b,c,d,e,10);
4448  R0(e,a,b,c,d,11);
4449  R0(d,e,a,b,c,12);
4450  R0(c,d,e,a,b,13);
4451  R0(b,c,d,e,a,14);
4452  R0(a,b,c,d,e,15);
4453  R1(e,a,b,c,d,16);
4454  R1(d,e,a,b,c,17);
4455  R1(c,d,e,a,b,18);
4456  R1(b,c,d,e,a,19);
4457  R2(a,b,c,d,e,20);
4458  R2(e,a,b,c,d,21);
4459  R2(d,e,a,b,c,22);
4460  R2(c,d,e,a,b,23);
4461  R2(b,c,d,e,a,24);
4462  R2(a,b,c,d,e,25);
4463  R2(e,a,b,c,d,26);
4464  R2(d,e,a,b,c,27);
4465  R2(c,d,e,a,b,28);
4466  R2(b,c,d,e,a,29);
4467  R2(a,b,c,d,e,30);
4468  R2(e,a,b,c,d,31);
4469  R2(d,e,a,b,c,32);
4470  R2(c,d,e,a,b,33);
4471  R2(b,c,d,e,a,34);
4472  R2(a,b,c,d,e,35);
4473  R2(e,a,b,c,d,36);
4474  R2(d,e,a,b,c,37);
4475  R2(c,d,e,a,b,38);
4476  R2(b,c,d,e,a,39);
4477  R3(a,b,c,d,e,40);
4478  R3(e,a,b,c,d,41);
4479  R3(d,e,a,b,c,42);
4480  R3(c,d,e,a,b,43);
4481  R3(b,c,d,e,a,44);
4482  R3(a,b,c,d,e,45);
4483  R3(e,a,b,c,d,46);
4484  R3(d,e,a,b,c,47);
4485  R3(c,d,e,a,b,48);
4486  R3(b,c,d,e,a,49);
4487  R3(a,b,c,d,e,50);
4488  R3(e,a,b,c,d,51);
4489  R3(d,e,a,b,c,52);
4490  R3(c,d,e,a,b,53);
4491  R3(b,c,d,e,a,54);
4492  R3(a,b,c,d,e,55);
4493  R3(e,a,b,c,d,56);
4494  R3(d,e,a,b,c,57);
4495  R3(c,d,e,a,b,58);
4496  R3(b,c,d,e,a,59);
4497  R4(a,b,c,d,e,60);
4498  R4(e,a,b,c,d,61);
4499  R4(d,e,a,b,c,62);
4500  R4(c,d,e,a,b,63);
4501  R4(b,c,d,e,a,64);
4502  R4(a,b,c,d,e,65);
4503  R4(e,a,b,c,d,66);
4504  R4(d,e,a,b,c,67);
4505  R4(c,d,e,a,b,68);
4506  R4(b,c,d,e,a,69);
4507  R4(a,b,c,d,e,70);
4508  R4(e,a,b,c,d,71);
4509  R4(d,e,a,b,c,72);
4510  R4(c,d,e,a,b,73);
4511  R4(b,c,d,e,a,74);
4512  R4(a,b,c,d,e,75);
4513  R4(e,a,b,c,d,76);
4514  R4(d,e,a,b,c,77);
4515  R4(c,d,e,a,b,78);
4516  R4(b,c,d,e,a,79);
4517  state[0] += a;
4518  state[1] += b;
4519  state[2] += c;
4520  state[3] += d;
4521  state[4] += e;
4522  a = b = c = d = e = 0;
4523  memset(block, '\0', sizeof(block));
4524 }
4525 
4526 static void SHA1Init(SHA1_CTX* context)
4527 {
4528  context->state[0] = 0x67452301;
4529  context->state[1] = 0xEFCDAB89;
4530  context->state[2] = 0x98BADCFE;
4531  context->state[3] = 0x10325476;
4532  context->state[4] = 0xC3D2E1F0;
4533  context->count[0] = context->count[1] = 0;
4534 }
4535 
4536 static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
4537  uint32_t len)
4538 {
4539  uint32_t i, j;
4540 
4541  j = context->count[0];
4542  if ((context->count[0] += len << 3) < j)
4543  context->count[1]++;
4544  context->count[1] += (len>>29);
4545  j = (j >> 3) & 63;
4546  if ((j + len) > 63) {
4547  memcpy(&context->buffer[j], data, (i = 64-j));
4548  SHA1Transform(context->state, context->buffer);
4549  for ( ; i + 63 < len; i += 64) {
4550  SHA1Transform(context->state, &data[i]);
4551  }
4552  j = 0;
4553  } else i = 0;
4554  memcpy(&context->buffer[j], &data[i], len - i);
4555 }
4556 
4557 static void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
4558 {
4559  unsigned i;
4560  unsigned char finalcount[8], c;
4561 
4562  for (i = 0; i < 8; i++) {
4563  finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
4564  >> ((3-(i & 3)) * 8) ) & 255);
4565  }
4566  c = 0200;
4567  SHA1Update(context, &c, 1);
4568  while ((context->count[0] & 504) != 448) {
4569  c = 0000;
4570  SHA1Update(context, &c, 1);
4571  }
4572  SHA1Update(context, finalcount, 8);
4573  for (i = 0; i < 20; i++) {
4574  digest[i] = (unsigned char)
4575  ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
4576  }
4577  memset(context, '\0', sizeof(*context));
4578  memset(&finalcount, '\0', sizeof(finalcount));
4579 }
4580 /* END OF SHA1 CODE */
4581 
4582 static void base64_encode(const unsigned char *src, int src_len, char *dst)
4583 {
4584  static const char *b64 =
4585  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4586  int i, j, a, b, c;
4587 
4588  for (i = j = 0; i < src_len; i += 3) {
4589  a = src[i];
4590  b = i + 1 >= src_len ? 0 : src[i + 1];
4591  c = i + 2 >= src_len ? 0 : src[i + 2];
4592 
4593  dst[j++] = b64[a >> 2];
4594  dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
4595  if (i + 1 < src_len) {
4596  dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
4597  }
4598  if (i + 2 < src_len) {
4599  dst[j++] = b64[c & 63];
4600  }
4601  }
4602  while (j % 4 != 0) {
4603  dst[j++] = '=';
4604  }
4605  dst[j++] = '\0';
4606 }
4607 
4608 static void send_websocket_handshake(struct mg_connection *conn)
4609 {
4610  static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4611  char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
4612  SHA1_CTX sha_ctx;
4613 
4614  mg_snprintf(conn, buf, sizeof(buf), "%s%s",
4615  mg_get_header(conn, "Sec-WebSocket-Key"), magic);
4616  SHA1Init(&sha_ctx);
4617  SHA1Update(&sha_ctx, (unsigned char *) buf, (uint32_t)strlen(buf));
4618  SHA1Final((unsigned char *) sha, &sha_ctx);
4619  base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
4620  mg_printf(conn, "%s%s%s",
4621  "HTTP/1.1 101 Switching Protocols\r\n"
4622  "Upgrade: websocket\r\n"
4623  "Connection: Upgrade\r\n"
4624  "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
4625 }
4626 
4627 static void read_websocket(struct mg_connection *conn)
4628 {
4629  /* Pointer to the beginning of the portion of the incoming websocket
4630  message queue.
4631  The original websocket upgrade request is never removed, so the queue
4632  begins after it. */
4633  unsigned char *buf = (unsigned char *) conn->buf + conn->request_len;
4634  int n, error;
4635 
4636  /* body_len is the length of the entire queue in bytes
4637  len is the length of the current message
4638  data_len is the length of the current message's data payload
4639  header_len is the length of the current message's header */
4640  size_t i, len, mask_len, data_len, header_len, body_len;
4641 
4642  /* "The masking key is a 32-bit value chosen at random by the client."
4643  http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5 */
4644  unsigned char mask[4];
4645 
4646  /* data points to the place where the message is stored when passed to the
4647  websocket_data callback. This is either mem on the stack, or a
4648  dynamically allocated buffer if it is too large. */
4649  char mem[4096];
4650  char *data = mem;
4651  unsigned char mop; /* mask flag and opcode */
4652 
4653  /* Loop continuously, reading messages from the socket, invoking the
4654  callback, and waiting repeatedly until an error occurs. */
4655  assert(conn->content_len == 0);
4656  for (;;) {
4657  header_len = 0;
4658  assert(conn->data_len >= conn->request_len);
4659  if ((body_len = conn->data_len - conn->request_len) >= 2) {
4660  len = buf[1] & 127;
4661  mask_len = buf[1] & 128 ? 4 : 0;
4662  if (len < 126 && body_len >= mask_len) {
4663  data_len = len;
4664  header_len = 2 + mask_len;
4665  } else if (len == 126 && body_len >= 4 + mask_len) {
4666  header_len = 4 + mask_len;
4667  data_len = ((((int) buf[2]) << 8) + buf[3]);
4668  } else if (body_len >= 10 + mask_len) {
4669  header_len = 10 + mask_len;
4670  data_len = (((uint64_t) ntohl(* (uint32_t *) &buf[2])) << 32) +
4671  ntohl(* (uint32_t *) &buf[6]);
4672  }
4673  }
4674 
4675  if (header_len > 0) {
4676  /* Allocate space to hold websocket payload */
4677  data = mem;
4678  if (data_len > sizeof(mem)) {
4679  data = (char *)malloc(data_len);
4680  if (data == NULL) {
4681  /* Allocation failed, exit the loop and then close the
4682  connection */
4683  mg_cry(conn, "websocket malloc() failed; closing connection");
4684  break;
4685  }
4686  }
4687 
4688  /* Copy the mask before we shift the queue and destroy it */
4689  if (mask_len > 0) {
4690  *(uint32_t*)mask = *(uint32_t*)(buf + header_len - mask_len);
4691  } else {
4692  *(uint32_t*)mask = 0;
4693  }
4694 
4695  /* Read frame payload from the first message in the queue into
4696  data and advance the queue by moving the memory in place. */
4697  assert(body_len >= header_len);
4698  if (data_len + header_len > body_len) {
4699  mop = buf[0]; /* current mask and opcode */
4700  /* Overflow case */
4701  len = body_len - header_len;
4702  memcpy(data, buf + header_len, len);
4703  error = 0;
4704  while (len < data_len) {
4705  int n = pull(NULL, conn, data + len, (int)(data_len - len));
4706  if (n < 0) {
4707  error = 1;
4708  break;
4709  }
4710  len += n;
4711  }
4712  if (error) {
4713  mg_cry(conn, "Websocket pull failed; closing connection");
4714  break;
4715  }
4716  conn->data_len = conn->request_len;
4717  } else {
4718  mop = buf[0]; /* current mask and opcode, overwritten by memmove() */
4719  /* Length of the message being read at the front of the
4720  queue */
4721  len = data_len + header_len;
4722 
4723  /* Copy the data payload into the data pointer for the
4724  callback */
4725  memcpy(data, buf + header_len, data_len);
4726 
4727  /* Move the queue forward len bytes */
4728  memmove(buf, buf + len, body_len - len);
4729 
4730  /* Mark the queue as advanced */
4731  conn->data_len -= (int)len;
4732  }
4733 
4734  /* Apply mask if necessary */
4735  if (mask_len > 0) {
4736  for (i = 0; i < data_len; ++i) {
4737  data[i] ^= mask[i & 3];
4738  }
4739  }
4740 
4741  /* Exit the loop if callback signalled to exit,
4742  or "connection close" opcode received. */
4743  if ((conn->ctx->callbacks.websocket_data != NULL &&
4744 #ifdef USE_LUA
4745  (conn->lua_websocket_state == NULL) &&
4746 #endif
4747  !conn->ctx->callbacks.websocket_data(conn, mop, data, data_len)) ||
4748 #ifdef USE_LUA
4749  (conn->lua_websocket_state &&
4750  !lua_websocket_data(conn, mop, data, data_len)) ||
4751 #endif
4752  (buf[0] & 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE) { /* Opcode == 8, connection close */
4753  break;
4754  }
4755 
4756  if (data != mem) {
4757  free(data);
4758  }
4759  /* Not breaking the loop, process next websocket frame. */
4760  } else {
4761  /* Read from the socket into the next available location in the
4762  message queue. */
4763  if ((n = pull(NULL, conn, conn->buf + conn->data_len,
4764  conn->buf_size - conn->data_len)) <= 0) {
4765  /* Error, no bytes read */
4766  break;
4767  }
4768  conn->data_len += n;
4769  }
4770  }
4771 }
4772 
4773 int mg_websocket_write(struct mg_connection* conn, int opcode, const char* data, size_t dataLen)
4774 {
4775  unsigned char header[10];
4776  size_t headerLen = 1;
4777 
4778  int retval = -1;
4779 
4780  header[0] = 0x80 + (opcode & 0xF);
4781 
4782  /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
4783  if (dataLen < 126) {
4784  /* inline 7-bit length field */
4785  header[1] = (unsigned char)dataLen;
4786  headerLen = 2;
4787  } else if (dataLen <= 0xFFFF) {
4788  /* 16-bit length field */
4789  header[1] = 126;
4790  *(uint16_t*)(header + 2) = htons((uint16_t)dataLen);
4791  headerLen = 4;
4792  } else {
4793  /* 64-bit length field */
4794  header[1] = 127;
4795  *(uint32_t*)(header + 2) = htonl((uint64_t)dataLen >> 32);
4796  *(uint32_t*)(header + 6) = htonl(dataLen & 0xFFFFFFFF);
4797  headerLen = 10;
4798  }
4799 
4800  /* Note that POSIX/Winsock's send() is threadsafe
4801  http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
4802  but mongoose's mg_printf/mg_write is not (because of the loop in
4803  push(), although that is only a problem if the packet is large or
4804  outgoing buffer is full). */
4805  (void) mg_lock(conn);
4806  retval = mg_write(conn, header, headerLen);
4807  retval = mg_write(conn, data, dataLen);
4808  mg_unlock(conn);
4809 
4810  return retval;
4811 }
4812 
4813 static void handle_websocket_request(struct mg_connection *conn, const char *path, int is_script_resource)
4814 {
4815  const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
4816 #ifdef USE_LUA
4817  int lua_websock, shared_lua_websock = 0;
4818  /* TODO: A websocket script may be shared between several clients, allowing them to communicate
4819  directly instead of writing to a data base and polling the data base. */
4820 #endif
4821 
4822  if (version == NULL || strcmp(version, "13") != 0) {
4823  send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
4824  } else if (conn->ctx->callbacks.websocket_connect != NULL &&
4825  conn->ctx->callbacks.websocket_connect(conn) != 0) {
4826  /* C callback has returned non-zero, do not proceed with handshake. */
4827  /* The C callback is called before Lua and may prevent Lua from handling the websocket. */
4828  } else {
4829 #ifdef USE_LUA
4830  lua_websock = conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS] ?
4831  match_prefix(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS],
4832  (int)strlen(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
4833  path) : 0;
4834 
4835  if (lua_websock || shared_lua_websock) {
4836  conn->lua_websocket_state = lua_websocket_new(path, conn, !!shared_lua_websock);
4837  if (conn->lua_websocket_state) {
4838  send_websocket_handshake(conn);
4839  if (lua_websocket_ready(conn)) {
4840  read_websocket(conn);
4841  }
4842  }
4843  } else
4844 #endif
4845  {
4846  /* No Lua websock script specified. */
4847  send_websocket_handshake(conn);
4848  if (conn->ctx->callbacks.websocket_ready != NULL) {
4849  conn->ctx->callbacks.websocket_ready(conn);
4850  }
4851  read_websocket(conn);
4852  }
4853  }
4854 }
4855 
4856 static int is_websocket_request(const struct mg_connection *conn)
4857 {
4858  const char *host, *upgrade, *connection, *version, *key;
4859 
4860  host = mg_get_header(conn, "Host");
4861  upgrade = mg_get_header(conn, "Upgrade");
4862  connection = mg_get_header(conn, "Connection");
4863  key = mg_get_header(conn, "Sec-WebSocket-Key");
4864  version = mg_get_header(conn, "Sec-WebSocket-Version");
4865 
4866  return host != NULL && upgrade != NULL && connection != NULL &&
4867  key != NULL && version != NULL &&
4868  mg_strcasestr(upgrade, "websocket") != NULL &&
4869  mg_strcasestr(connection, "Upgrade") != NULL;
4870 }
4871 #endif /* !USE_WEBSOCKET */
4872 
4873 static int isbyte(int n)
4874 {
4875  return n >= 0 && n <= 255;
4876 }
4877 
4878 static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
4879 {
4880  int n, a, b, c, d, slash = 32, len = 0;
4881 
4882  if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
4883  sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
4884  isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
4885  slash >= 0 && slash < 33) {
4886  len = n;
4887  *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
4888  *mask = slash ? 0xffffffffU << (32 - slash) : 0;
4889  }
4890 
4891  return len;
4892 }
4893 
4894 static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
4895 {
4896  int throttle = 0;
4897  struct vec vec, val;
4898  uint32_t net, mask;
4899  char mult;
4900  double v;
4901 
4902  while ((spec = next_option(spec, &vec, &val)) != NULL) {
4903  mult = ',';
4904  if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0 ||
4905  (lowercase(&mult) != 'k' && lowercase(&mult) != 'm' && mult != ',')) {
4906  continue;
4907  }
4908  v *= lowercase(&mult) == 'k' ? 1024 : lowercase(&mult) == 'm' ? 1048576 : 1;
4909  if (vec.len == 1 && vec.ptr[0] == '*') {
4910  throttle = (int) v;
4911  } else if (parse_net(vec.ptr, &net, &mask) > 0) {
4912  if ((remote_ip & mask) == net) {
4913  throttle = (int) v;
4914  }
4915  } else if (match_prefix(vec.ptr, (int)vec.len, uri) > 0) {
4916  throttle = (int) v;
4917  }
4918  }
4919 
4920  return throttle;
4921 }
4922 
4923 static uint32_t get_remote_ip(const struct mg_connection *conn)
4924 {
4925  return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
4926 }
4927 
4928 int mg_upload(struct mg_connection *conn, const char *destination_dir)
4929 {
4930  const char *content_type_header, *boundary_start;
4931  char buf[MG_BUF_LEN], path[PATH_MAX], fname[1024], boundary[100], *s;
4932  FILE *fp;
4933  int bl, n, i, j, headers_len, boundary_len, eof,
4934  len = 0, num_uploaded_files = 0;
4935 
4936  /* Request looks like this:
4937 
4938  POST /upload HTTP/1.1
4939  Host: 127.0.0.1:8080
4940  Content-Length: 244894
4941  Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryRVr
4942 
4943  ------WebKitFormBoundaryRVr
4944  Content-Disposition: form-data; name="file"; filename="accum.png"
4945  Content-Type: image/png
4946 
4947  <89>PNG
4948  <PNG DATA>
4949  ------WebKitFormBoundaryRVr */
4950 
4951  /* Extract boundary string from the Content-Type header */
4952  if ((content_type_header = mg_get_header(conn, "Content-Type")) == NULL ||
4953  (boundary_start = mg_strcasestr(content_type_header,
4954  "boundary=")) == NULL ||
4955  (sscanf(boundary_start, "boundary=\"%99[^\"]\"", boundary) == 0 &&
4956  sscanf(boundary_start, "boundary=%99s", boundary) == 0) ||
4957  boundary[0] == '\0') {
4958  return num_uploaded_files;
4959  }
4960 
4961  boundary_len = (int)strlen(boundary);
4962  bl = boundary_len + 4; /* \r\n--<boundary> */
4963  for (;;) {
4964  /* Pull in headers */
4965  assert(len >= 0 && len <= (int) sizeof(buf));
4966  while ((n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0) {
4967  len += n;
4968  }
4969  if ((headers_len = get_request_len(buf, len)) <= 0) {
4970  break;
4971  }
4972 
4973  /* Fetch file name. */
4974  fname[0] = '\0';
4975  for (i = j = 0; i < headers_len; i++) {
4976  if (buf[i] == '\r' && buf[i + 1] == '\n') {
4977  buf[i] = buf[i + 1] = '\0';
4978  /* TODO(lsm): don't expect filename to be the 3rd field,
4979  parse the header properly instead. */
4980  IGNORE_UNUSED_RESULT(sscanf(&buf[j], "Content-Disposition: %*s %*s filename=\"%1023[^\"]",
4981  fname));
4982  j = i + 2;
4983  }
4984  }
4985 
4986  /* Give up if the headers are not what we expect */
4987  if (fname[0] == '\0') {
4988  break;
4989  }
4990 
4991  /* Move data to the beginning of the buffer */
4992  assert(len >= headers_len);
4993  memmove(buf, &buf[headers_len], len - headers_len);
4994  len -= headers_len;
4995 
4996  /* We open the file with exclusive lock held. This guarantee us
4997  there is no other thread can save into the same file
4998  simultaneously. */
4999  fp = NULL;
5000  /* Construct destination file name. Do not allow paths to have
5001  slashes. */
5002  if ((s = strrchr(fname, '/')) == NULL &&
5003  (s = strrchr(fname, '\\')) == NULL) {
5004  s = fname;
5005  }
5006 
5007  /* Open file in binary mode. TODO: set an exclusive lock. */
5008  snprintf(path, sizeof(path), "%s/%s", destination_dir, s);
5009  if ((fp = fopen(path, "wb")) == NULL) {
5010  break;
5011  }
5012 
5013  /* Read POST data, write into file until boundary is found. */
5014  eof = n = 0;
5015  do {
5016  len += n;
5017  for (i = 0; i < len - bl; i++) {
5018  if (!memcmp(&buf[i], "\r\n--", 4) &&
5019  !memcmp(&buf[i + 4], boundary, boundary_len)) {
5020  /* Found boundary, that's the end of file data. */
5021  fwrite(buf, 1, i, fp);
5022  eof = 1;
5023  memmove(buf, &buf[i + bl], len - (i + bl));
5024  len -= i + bl;
5025  break;
5026  }
5027  }
5028  if (!eof && len > bl) {
5029  fwrite(buf, 1, len - bl, fp);
5030  memmove(buf, &buf[len - bl], bl);
5031  len = bl;
5032  }
5033  } while (!eof && (n = mg_read(conn, buf + len, sizeof(buf) - len)) > 0);
5034  fclose(fp);
5035  if (eof) {
5036  num_uploaded_files++;
5037  if (conn->ctx->callbacks.upload != NULL) {
5038  conn->ctx->callbacks.upload(conn, path);
5039  }
5040  }
5041  }
5042 
5043  return num_uploaded_files;
5044 }
5045 
5046 static int is_put_or_delete_request(const struct mg_connection *conn)
5047 {
5048  const char *s = conn->request_info.request_method;
5049  return s != NULL && (!strcmp(s, "PUT") ||
5050  !strcmp(s, "DELETE") ||
5051  !strcmp(s, "MKCOL"));
5052 }
5053 
5054 static int get_first_ssl_listener_index(const struct mg_context *ctx)
5055 {
5056  int i, idx = -1;
5057  for (i = 0; idx == -1 && i < ctx->num_listening_sockets; i++) {
5058  idx = ctx->listening_sockets[i].is_ssl ? i : -1;
5059  }
5060  return idx;
5061 }
5062 
5063 static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
5064 {
5065  char host[1025];
5066  const char *host_header;
5067  size_t hostlen;
5068 
5069  host_header = mg_get_header(conn, "Host");
5070  hostlen = sizeof(host);
5071  if (host_header != NULL) {
5072  char *pos;
5073 
5074  strncpy(host, host_header, hostlen);
5075  host[hostlen - 1] = '\0';
5076  pos = strchr(host, ':');
5077  if (pos != NULL) {
5078  *pos = '\0';
5079  }
5080  } else {
5081  /* Cannot get host from the Host: header.
5082  Fallback to our IP address. */
5083  sockaddr_to_string(host, hostlen, &conn->client.lsa);
5084  }
5085 
5086  mg_printf(conn, "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s\r\n\r\n",
5087  host, (int) ntohs(conn->ctx->listening_sockets[ssl_index].
5088  lsa.sin.sin_port), conn->request_info.uri);
5089 }
5090 
5091 
5092 void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
5093 {
5094  struct mg_request_handler_info *tmp_rh, *lastref = 0;
5095  size_t urilen = strlen(uri);
5096 
5097  /* first see it the uri exists */
5098  for (tmp_rh = ctx->request_handlers;
5099  tmp_rh != NULL && strcmp(uri, tmp_rh->uri);
5100  lastref = tmp_rh, tmp_rh = tmp_rh->next) {
5101  /* first try for an exact match */
5102  if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri,uri)) {
5103  /* already there... */
5104 
5105  if (handler != NULL) {
5106  /* change this entry */
5107  tmp_rh->handler = handler;
5108  tmp_rh->cbdata = cbdata;
5109  } else {
5110  /* remove this entry */
5111  if (lastref != NULL)
5112  lastref->next = tmp_rh->next;
5113  else
5114  ctx->request_handlers = tmp_rh->next;
5115  free(tmp_rh->uri);
5116  free(tmp_rh);
5117  }
5118  return;
5119  }
5120 
5121  /* next try for a partial match, we will accept uri/something */
5122  if (tmp_rh->uri_len < urilen
5123  && uri[tmp_rh->uri_len] == '/'
5124  && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
5125  /* if there is a partical match this new entry MUST go BEFORE
5126  the current position otherwise it will never be matched. */
5127  break;
5128  }
5129 
5130  }
5131 
5132  if (handler == NULL) {
5133  /* no handler to set, this was a remove request */
5134  return;
5135  }
5136 
5137  tmp_rh = (struct mg_request_handler_info *)malloc(sizeof(struct mg_request_handler_info));
5138  if (tmp_rh == NULL) {
5139  mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
5140  return;
5141  }
5142  tmp_rh->uri = mg_strdup(uri);
5143  tmp_rh->uri_len = strlen(uri);
5144  tmp_rh->handler = handler;
5145  tmp_rh->cbdata = cbdata;
5146 
5147  if (lastref == NULL) {
5148  tmp_rh->next = ctx->request_handlers;
5149  ctx->request_handlers = tmp_rh;
5150  } else {
5151  tmp_rh->next = lastref->next;
5152  lastref->next = tmp_rh;
5153  }
5154 
5155 }
5156 
5157 static int use_request_handler(struct mg_connection *conn)
5158 {
5159  struct mg_request_info *request_info = mg_get_request_info(conn);
5160  const char *uri = request_info->uri;
5161  size_t urilen = strlen(uri);
5162  struct mg_request_handler_info *tmp_rh = conn->ctx->request_handlers;
5163 
5164  for (; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
5165 
5166  /* first try for an exact match */
5167  if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri,uri)) {
5168  return tmp_rh->handler(conn, tmp_rh->cbdata);
5169  }
5170 
5171  /* next try for a partial match */
5172  /* we will accept uri/something */
5173  if (tmp_rh->uri_len < urilen
5174  && uri[tmp_rh->uri_len] == '/'
5175  && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
5176 
5177  return tmp_rh->handler(conn, tmp_rh->cbdata);
5178  }
5179 
5180  /* try for pattern match */
5181  if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
5182  return tmp_rh->handler(conn, tmp_rh->cbdata);
5183  }
5184 
5185  }
5186 
5187  return 0; /* none found */
5188 }
5189 
5190 /* This is the heart of the Civetweb's logic.
5191  This function is called when the request is read, parsed and validated,
5192  and Civetweb must decide what action to take: serve a file, or
5193  a directory, or call embedded function, etcetera. */
5194 static void handle_request(struct mg_connection *conn)
5195 {
5196  struct mg_request_info *ri = &conn->request_info;
5197  char path[PATH_MAX];
5198  int uri_len, ssl_index, is_script_resource;
5199  struct file file = STRUCT_FILE_INITIALIZER;
5200  char date[64];
5201  time_t curtime = time(NULL);
5202 
5203  if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
5204  * ((char *) conn->request_info.query_string++) = '\0';
5205  }
5206  uri_len = (int) strlen(ri->uri);
5207  mg_url_decode(ri->uri, uri_len, (char *) ri->uri, uri_len + 1, 0);
5209  path[0] = '\0';
5210  convert_uri_to_file_name(conn, path, sizeof(path), &file, &is_script_resource);
5211  conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
5212  get_remote_ip(conn), ri->uri);
5213 
5214  DEBUG_TRACE(("%s", ri->uri));
5215  /* Perform redirect and auth checks before calling begin_request() handler.
5216  Otherwise, begin_request() would need to perform auth checks and
5217  redirects. */
5218  if (!conn->client.is_ssl && conn->client.ssl_redir &&
5219  (ssl_index = get_first_ssl_listener_index(conn->ctx)) > -1) {
5220  redirect_to_https_port(conn, ssl_index);
5221  } else if (!is_script_resource && !is_put_or_delete_request(conn) &&
5222  !check_authorization(conn, path)) {
5224  } else if (conn->ctx->callbacks.begin_request != NULL &&
5225  conn->ctx->callbacks.begin_request(conn)) {
5226  /* Do nothing, callback has served the request */
5227 #if defined(USE_WEBSOCKET)
5228  } else if (is_websocket_request(conn)) {
5229  handle_websocket_request(conn, path, is_script_resource);
5230 #endif
5231  } else if (conn->ctx->request_handlers != NULL &&
5232  use_request_handler(conn)) {
5233  /* Do nothing, callback has served the request */
5234  } else if (!is_script_resource && !strcmp(ri->request_method, "OPTIONS")) {
5235  send_options(conn);
5236  } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
5237  send_http_error(conn, 404, "Not Found", "Not Found");
5238  } else if (!is_script_resource && is_put_or_delete_request(conn) &&
5239  (is_authorized_for_put(conn) != 1)) {
5241  } else if (!is_script_resource && !strcmp(ri->request_method, "PUT")) {
5242  put_file(conn, path);
5243  } else if (!is_script_resource && !strcmp(ri->request_method, "MKCOL")) {
5244  mkcol(conn, path);
5245  } else if (!is_script_resource && !strcmp(ri->request_method, "DELETE")) {
5246  struct de de;
5247  memset(&de.file, 0, sizeof(de.file));
5248  if(!mg_stat(conn, path, &de.file)) {
5249  send_http_error(conn, 404, "Not Found", "%s", "File not found");
5250  } else {
5251  if(de.file.modification_time) {
5252  if(de.file.is_directory) {
5253  remove_directory(conn, path);
5254  send_http_error(conn, 204, "No Content", "%s", "");
5255  } else if (mg_remove(path) == 0) {
5256  send_http_error(conn, 204, "No Content", "%s", "");
5257  } else {
5258  send_http_error(conn, 423, "Locked", "remove(%s): %s", path,
5259  strerror(ERRNO));
5260  }
5261  } else {
5262  send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
5263  strerror(ERRNO));
5264  }
5265  }
5266  } else if ((file.membuf == NULL && file.modification_time == (time_t) 0) ||
5267  must_hide_file(conn, path)) {
5268  send_http_error(conn, 404, "Not Found", "%s", "File not found");
5269  } else if (file.is_directory && ri->uri[uri_len - 1] != '/') {
5270  gmt_time_string(date, sizeof(date), &curtime);
5271  mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"
5272  "Location: %s/\r\n"
5273  "Date: %s\r\n"
5274  "Content-Length: 0\r\n"
5275  "Connection: %s\r\n\r\n",
5276  ri->uri, date, suggest_connection_header(conn));
5277  } else if (!is_script_resource && !strcmp(ri->request_method, "PROPFIND")) {
5278  handle_propfind(conn, path, &file);
5279  } else if (file.is_directory &&
5280  !substitute_index_file(conn, path, sizeof(path), &file)) {
5281  if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
5282  handle_directory_request(conn, path);
5283  } else {
5284  send_http_error(conn, 403, "Directory Listing Denied",
5285  "Directory listing denied");
5286  }
5287 #ifdef USE_LUA
5288  } else if (match_prefix(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
5289  (int)strlen(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
5290  path) > 0) {
5291  /* Lua server page: an SSI like page containing mostly plain html code plus some tags with server generated contents. */
5292  handle_lsp_request(conn, path, &file, NULL);
5293  } else if (match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
5294  (int)strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
5295  path) > 0) {
5296  /* Lua in-server module script: a CGI like script used to generate the entire reply. */
5297  mg_exec_lua_script(conn, path, NULL);
5298 #endif
5299 #if !defined(NO_CGI)
5300  } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
5301  (int)strlen(conn->ctx->config[CGI_EXTENSIONS]),
5302  path) > 0) {
5303  /* TODO: check unsupported methods -> 501
5304  if (strcmp(ri->request_method, "POST") &&
5305  strcmp(ri->request_method, "HEAD") &&
5306  strcmp(ri->request_method, "GET")) {
5307  send_http_error(conn, 501, "Not Implemented",
5308  "Method %s is not implemented", ri->request_method);
5309  } else {
5310  handle_cgi_request(conn, path);
5311  } */
5312  handle_cgi_request(conn, path);
5313 #endif /* !NO_CGI */
5314  } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
5315  (int)strlen(conn->ctx->config[SSI_EXTENSIONS]),
5316  path) > 0) {
5317  handle_ssi_file_request(conn, path);
5318  } else if (is_not_modified(conn, &file)) {
5319  send_http_error(conn, 304, "Not Modified", "%s", "");
5320  } else {
5321  handle_file_request(conn, path, &file);
5322  }
5323 }
5324 
5325 static void close_all_listening_sockets(struct mg_context *ctx)
5326 {
5327  int i;
5328  for (i = 0; i < ctx->num_listening_sockets; i++) {
5329  closesocket(ctx->listening_sockets[i].sock);
5330  }
5331  free(ctx->listening_sockets);
5332 }
5333 
5334 static int is_valid_port(unsigned int port)
5335 {
5336  return port < 0xffff;
5337 }
5338 
5339 /* Valid listening port specification is: [ip_address:]port[s]
5340  Examples: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
5341  TODO(lsm): add parsing of the IPv6 address */
5342 static int parse_port_string(const struct vec *vec, struct socket *so)
5343 {
5344  unsigned int a, b, c, d, ch, len, port;
5345 #if defined(USE_IPV6)
5346  char buf[100];
5347 #endif
5348 
5349  /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
5350  Also, all-zeroes in the socket address means binding to all addresses
5351  for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
5352  memset(so, 0, sizeof(*so));
5353  so->lsa.sin.sin_family = AF_INET;
5354 
5355  if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
5356  /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
5357  so->lsa.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
5358  so->lsa.sin.sin_port = htons((uint16_t) port);
5359 #if defined(USE_IPV6)
5360 
5361  } else if (sscanf(vec->ptr, "[%49[^]]]:%d%n", buf, &port, &len) == 2 &&
5362  inet_pton(AF_INET6, buf, &so->lsa.sin6.sin6_addr)) {
5363  /* IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080 */
5364  so->lsa.sin6.sin6_family = AF_INET6;
5365  so->lsa.sin6.sin6_port = htons((uint16_t) port);
5366 #endif
5367  } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
5368  /* If only port is specified, bind to IPv4, INADDR_ANY */
5369  so->lsa.sin.sin_port = htons((uint16_t) port);
5370  } else {
5371  port = len = 0; /* Parsing failure. Make port invalid. */
5372  }
5373 
5374  ch = vec->ptr[len]; /* Next character after the port number */
5375  so->is_ssl = ch == 's';
5376  so->ssl_redir = ch == 'r';
5377 
5378  /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
5379  return is_valid_port(port) &&
5380  (ch == '\0' || ch == 's' || ch == 'r' || ch == ',');
5381 }
5382 
5383 static int set_ports_option(struct mg_context *ctx)
5384 {
5385  const char *list = ctx->config[LISTENING_PORTS];
5386  int on = 1, success = 1;
5387 #if defined(USE_IPV6)
5388  int off = 0;
5389 #endif
5390  struct vec vec;
5391  struct socket so, *ptr;
5392 
5393  in_port_t *portPtr;
5394  struct sockaddr_in sin;
5395  socklen_t len;
5396 
5397  memset(&sin, 0, sizeof(sin));
5398  len = sizeof(sin);
5399 
5400  while (success && (list = next_option(list, &vec, NULL)) != NULL) {
5401  if (!parse_port_string(&vec, &so)) {
5402  mg_cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
5403  __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|r]");
5404  success = 0;
5405  } else if (so.is_ssl && ctx->ssl_ctx == NULL) {
5406  mg_cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
5407  success = 0;
5408  } else if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) ==
5409  INVALID_SOCKET ||
5410  /* On Windows, SO_REUSEADDR is recommended only for
5411  broadcast UDP sockets */
5412  setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR,
5413  (void *) &on, sizeof(on)) != 0 ||
5414 #if defined(USE_IPV6)
5415  (so.lsa.sa.sa_family == AF_INET6 &&
5416  setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &off,
5417  sizeof(off)) != 0) ||
5418 #endif
5419  bind(so.sock, &so.lsa.sa, so.lsa.sa.sa_family == AF_INET ?
5420  sizeof(so.lsa.sin) : sizeof(so.lsa)) != 0 ||
5421  listen(so.sock, SOMAXCONN) != 0 ||
5422  getsockname(so.sock, (struct sockaddr *)&sin, &len) != 0) {
5423  mg_cry(fc(ctx), "%s: cannot bind to %.*s: %d (%s)", __func__,
5424  (int) vec.len, vec.ptr, ERRNO, strerror(errno));
5425  if (so.sock != INVALID_SOCKET) {
5426  closesocket(so.sock);
5427  }
5428  success = 0;
5429  } else if ((ptr = (struct socket *) realloc(ctx->listening_sockets,
5430  (ctx->num_listening_sockets + 1) *
5431  sizeof(ctx->listening_sockets[0]))) == NULL) {
5432  closesocket(so.sock);
5433  success = 0;
5434  } else if ((portPtr = (in_port_t*) realloc(ctx->listening_ports,
5435  (ctx->num_listening_sockets + 1) *
5436  sizeof(ctx->listening_ports[0]))) == NULL) {
5437  closesocket(so.sock);
5438  success = 0;
5439  }
5440  else {
5441  set_close_on_exec(so.sock, fc(ctx));
5442  ctx->listening_sockets = ptr;
5443  ctx->listening_sockets[ctx->num_listening_sockets] = so;
5444  ctx->listening_ports = portPtr;
5445  ctx->listening_ports[ctx->num_listening_sockets] = ntohs(sin.sin_port);
5446  ctx->num_listening_sockets++;
5447  }
5448  }
5449 
5450  if (!success) {
5452  }
5453 
5454  return success;
5455 }
5456 
5457 static void log_header(const struct mg_connection *conn, const char *header,
5458  FILE *fp)
5459 {
5460  const char *header_value;
5461 
5462  if ((header_value = mg_get_header(conn, header)) == NULL) {
5463  (void) fprintf(fp, "%s", " -");
5464  } else {
5465  (void) fprintf(fp, " \"%s\"", header_value);
5466  }
5467 }
5468 
5469 static void log_access(const struct mg_connection *conn)
5470 {
5471  const struct mg_request_info *ri;
5472  FILE *fp;
5473  char date[64], src_addr[IP_ADDR_STR_LEN];
5474  struct tm *tm;
5475 
5476  fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ? NULL :
5477  fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
5478 
5479  if (fp == NULL)
5480  return;
5481 
5482  tm = localtime(&conn->birth_time);
5483  if (tm != NULL) {
5484  strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
5485  } else {
5486  strncpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
5487  date[sizeof(date) - 1] = '\0';
5488  }
5489 
5490  ri = &conn->request_info;
5491  flockfile(fp);
5492 
5493  sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
5494  fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
5495  src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
5496  ri->request_method ? ri->request_method : "-",
5497  ri->uri ? ri->uri : "-", ri->http_version,
5498  conn->status_code, conn->num_bytes_sent);
5499  log_header(conn, "Referer", fp);
5500  log_header(conn, "User-Agent", fp);
5501  fputc('\n', fp);
5502  fflush(fp);
5503 
5504  funlockfile(fp);
5505  fclose(fp);
5506 }
5507 
5508 /* Verify given socket address against the ACL.
5509  Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed. */
5510 static int check_acl(struct mg_context *ctx, uint32_t remote_ip)
5511 {
5512  int allowed, flag;
5513  uint32_t net, mask;
5514  struct vec vec;
5515  const char *list = ctx->config[ACCESS_CONTROL_LIST];
5516 
5517  /* If any ACL is set, deny by default */
5518  allowed = list == NULL ? '+' : '-';
5519 
5520  while ((list = next_option(list, &vec, NULL)) != NULL) {
5521  flag = vec.ptr[0];
5522  if ((flag != '+' && flag != '-') ||
5523  parse_net(&vec.ptr[1], &net, &mask) == 0) {
5524  mg_cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
5525  return -1;
5526  }
5527 
5528  if (net == (remote_ip & mask)) {
5529  allowed = flag;
5530  }
5531  }
5532 
5533  return allowed == '+';
5534 }
5535 
5536 #if !defined(_WIN32)
5537 static int set_uid_option(struct mg_context *ctx)
5538 {
5539  struct passwd *pw;
5540  const char *uid = ctx->config[RUN_AS_USER];
5541  int success = 0;
5542 
5543  if (uid == NULL) {
5544  success = 1;
5545  } else {
5546  if ((pw = getpwnam(uid)) == NULL) {
5547  mg_cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
5548  } else if (setgid(pw->pw_gid) == -1) {
5549  mg_cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno));
5550  } else if (setuid(pw->pw_uid) == -1) {
5551  mg_cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno));
5552  } else {
5553  success = 1;
5554  }
5555  }
5556 
5557  return success;
5558 }
5559 #endif /* !_WIN32 */
5560 
5561 #if !defined(NO_SSL)
5562 static pthread_mutex_t *ssl_mutexes;
5563 
5564 static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *))
5565 {
5566  return (conn->ssl = SSL_new(s)) != NULL &&
5567  SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
5568  func(conn->ssl) == 1;
5569 }
5570 
5571 /* Return OpenSSL error message */
5572 static const char *ssl_error(void)
5573 {
5574  unsigned long err;
5575  err = ERR_get_error();
5576  return err == 0 ? "" : ERR_error_string(err, NULL);
5577 }
5578 
5579 static void ssl_locking_callback(int mode, int mutex_num, const char *file,
5580  int line)
5581 {
5582  (void) line;
5583  (void) file;
5584 
5585  if (mode & 1) { /* 1 is CRYPTO_LOCK */
5586  (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
5587  } else {
5588  (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
5589  }
5590 }
5591 
5592 static unsigned long ssl_id_callback(void)
5593 {
5594  return (unsigned long) pthread_self();
5595 }
5596 
5597 #if !defined(NO_SSL_DL)
5598 static void *load_dll(struct mg_context *ctx, const char *dll_name,
5599  struct ssl_func *sw)
5600 {
5601  union {
5602  void *p;
5603  void (*fp)(void);
5604  } u;
5605  void *dll_handle;
5606  struct ssl_func *fp;
5607 
5608  if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
5609  mg_cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
5610  return NULL;
5611  }
5612 
5613  for (fp = sw; fp->name != NULL; fp++) {
5614 #ifdef _WIN32
5615  /* GetProcAddress() returns pointer to function */
5616  u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
5617 #else
5618  /* dlsym() on UNIX returns void *. ISO C forbids casts of data
5619  pointers to function pointers. We need to use a union to make a
5620  cast. */
5621  u.p = dlsym(dll_handle, fp->name);
5622 #endif /* _WIN32 */
5623  if (u.fp == NULL) {
5624  mg_cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name);
5625  dlclose(dll_handle);
5626  return NULL;
5627  } else {
5628  fp->ptr = u.fp;
5629  }
5630  }
5631 
5632  return dll_handle;
5633 }
5634 #endif /* NO_SSL_DL */
5635 
5636 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
5637 static int set_ssl_option(struct mg_context *ctx)
5638 {
5639  int i, size;
5640  const char *pem;
5641 
5642  /* If PEM file is not specified and the init_ssl callback
5643  is not specified, skip SSL initialization. */
5644  if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL &&
5645  ctx->callbacks.init_ssl == NULL) {
5646  return 1;
5647  }
5648 
5649 #if !defined(NO_SSL_DL)
5650  ctx->ssllib_dll_handle = load_dll(ctx, SSL_LIB, ssl_sw);
5651  ctx->cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, crypto_sw);
5652  if (!ctx->ssllib_dll_handle || !ctx->cryptolib_dll_handle) {
5653  return 0;
5654  }
5655 #endif /* NO_SSL_DL */
5656 
5657  /* Initialize SSL library */
5658  SSL_library_init();
5660 
5661  if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
5662  mg_cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
5663  return 0;
5664  }
5665 
5666  /* If user callback returned non-NULL, that means that user callback has
5667  set up certificate itself. In this case, skip sertificate setting. */
5668  if ((ctx->callbacks.init_ssl == NULL ||
5669  !ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data)) &&
5670  (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 ||
5671  SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0)) {
5672  mg_cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
5673  return 0;
5674  }
5675 
5676  if (pem != NULL) {
5677  (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
5678  }
5679 
5680  /* Initialize locking callbacks, needed for thread safety.
5681  http://www.openssl.org/support/faq.html#PROG1 */
5682  size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
5683  if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
5684  mg_cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
5685  return 0;
5686  }
5687 
5688  for (i = 0; i < CRYPTO_num_locks(); i++) {
5689  pthread_mutex_init(&ssl_mutexes[i], NULL);
5690  }
5691 
5694 
5695  return 1;
5696 }
5697 
5698 static void uninitialize_ssl(struct mg_context *ctx)
5699 {
5700  int i;
5701  if (ctx->ssl_ctx != NULL) {
5703  for (i = 0; i < CRYPTO_num_locks(); i++) {
5704  pthread_mutex_destroy(&ssl_mutexes[i]);
5705  }
5708  }
5709 }
5710 #endif /* !NO_SSL */
5711 
5712 static int set_gpass_option(struct mg_context *ctx)
5713 {
5714  struct file file = STRUCT_FILE_INITIALIZER;
5715  const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
5716  if (path != NULL && !mg_stat(fc(ctx), path, &file)) {
5717  mg_cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
5718  return 0;
5719  }
5720  return 1;
5721 }
5722 
5723 static int set_acl_option(struct mg_context *ctx)
5724 {
5725  return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
5726 }
5727 
5728 static void reset_per_request_attributes(struct mg_connection *conn)
5729 {
5730  conn->path_info = NULL;
5731  conn->num_bytes_sent = conn->consumed_content = 0;
5732  conn->status_code = -1;
5733  conn->must_close = conn->request_len = conn->throttle = 0;
5734 }
5735 
5736 static void close_socket_gracefully(struct mg_connection *conn)
5737 {
5738 #if defined(_WIN32)
5739  char buf[MG_BUF_LEN];
5740  int n;
5741 #endif
5742  struct linger linger;
5743 
5744  /* Set linger option to avoid socket hanging out after close. This prevent
5745  ephemeral port exhaust problem under high QPS. */
5746  linger.l_onoff = 1;
5747  linger.l_linger = 1;
5748  if (setsockopt(conn->client.sock, SOL_SOCKET, SO_LINGER,
5749  (char *) &linger, sizeof(linger)) != 0) {
5750  mg_cry(conn, "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
5751  __func__, strerror(ERRNO));
5752  }
5753 
5754  /* Send FIN to the client */
5755  shutdown(conn->client.sock, SHUT_WR);
5756  set_non_blocking_mode(conn->client.sock);
5757 
5758 #if defined(_WIN32)
5759  /* Read and discard pending incoming data. If we do not do that and close
5760  the socket, the data in the send buffer may be discarded. This
5761  behaviour is seen on Windows, when client keeps sending data
5762  when server decides to close the connection; then when client
5763  does recv() it gets no data back. */
5764  do {
5765  n = pull(NULL, conn, buf, sizeof(buf));
5766  } while (n > 0);
5767 #endif
5768 
5769  /* Now we know that our FIN is ACK-ed, safe to close */
5770  closesocket(conn->client.sock);
5771 }
5772 
5773 static void close_connection(struct mg_connection *conn)
5774 {
5775 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
5776  if (conn->lua_websocket_state) {
5777  lua_websocket_close(conn);
5778  }
5779 #endif
5780 
5781  /* call the connection_close callback if assigned */
5782  if (conn->ctx->callbacks.connection_close != NULL)
5783  conn->ctx->callbacks.connection_close(conn);
5784 
5785  mg_lock(conn);
5786 
5787  conn->must_close = 1;
5788 
5789 #ifndef NO_SSL
5790  if (conn->ssl != NULL) {
5791  /* Run SSL_shutdown twice to ensure completly close SSL connection */
5792  SSL_shutdown(conn->ssl);
5793  SSL_free(conn->ssl);
5794  conn->ssl = NULL;
5795  }
5796 #endif
5797  if (conn->client.sock != INVALID_SOCKET) {
5799  conn->client.sock = INVALID_SOCKET;
5800  }
5801 
5802  mg_unlock(conn);
5803 }
5804 
5805 void mg_close_connection(struct mg_connection *conn)
5806 {
5807 #ifndef NO_SSL
5808  if (conn->client_ssl_ctx != NULL) {
5809  SSL_CTX_free((SSL_CTX *) conn->client_ssl_ctx);
5810  }
5811 #endif
5812  close_connection(conn);
5813  (void) pthread_mutex_destroy(&conn->mutex);
5814  free(conn);
5815 }
5816 
5817 struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
5818  char *ebuf, size_t ebuf_len);
5819 
5820 struct mg_connection *mg_connect(const char *host, int port, int use_ssl,
5821  char *ebuf, size_t ebuf_len)
5822 {
5823  static struct mg_context fake_ctx;
5824  struct mg_connection *conn = NULL;
5825  SOCKET sock;
5826 
5827  if ((sock = conn2(&fake_ctx, host, port, use_ssl, ebuf,
5828  ebuf_len)) == INVALID_SOCKET) {
5829  } else if ((conn = (struct mg_connection *)
5830  calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
5831  snprintf(ebuf, ebuf_len, "calloc(): %s", strerror(ERRNO));
5832  closesocket(sock);
5833 #ifndef NO_SSL
5834  } else if (use_ssl && (conn->client_ssl_ctx =
5836  snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
5837  closesocket(sock);
5838  free(conn);
5839  conn = NULL;
5840 #endif /* NO_SSL */
5841  } else {
5842  socklen_t len = sizeof(struct sockaddr);
5843  conn->buf_size = MAX_REQUEST_SIZE;
5844  conn->buf = (char *) (conn + 1);
5845  conn->ctx = &fake_ctx;
5846  conn->client.sock = sock;
5847  if (getsockname(sock, &conn->client.rsa.sa, &len) != 0) {
5848  mg_cry(conn, "%s: getsockname() failed: %s",
5849  __func__, strerror(ERRNO));
5850  }
5851  conn->client.is_ssl = use_ssl;
5852  (void) pthread_mutex_init(&conn->mutex, NULL);
5853 #ifndef NO_SSL
5854  if (use_ssl) {
5855  /* SSL_CTX_set_verify call is needed to switch off server
5856  certificate checking, which is off by default in OpenSSL and on
5857  in yaSSL. */
5858  SSL_CTX_set_verify(conn->client_ssl_ctx, 0, 0);
5859  sslize(conn, conn->client_ssl_ctx, SSL_connect);
5860  }
5861 #endif
5862  }
5863 
5864  return conn;
5865 }
5866 
5867 static int is_valid_uri(const char *uri)
5868 {
5869  /* Conform to
5870  http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
5871  URI can be an asterisk (*) or should start with slash. */
5872  return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
5873 }
5874 
5875 static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len)
5876 {
5877  const char *cl;
5878 
5879  ebuf[0] = '\0';
5881  conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
5882  &conn->data_len);
5883  assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
5884 
5885  if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
5886  snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
5887  } else if (conn->request_len <= 0) {
5888  snprintf(ebuf, ebuf_len, "%s", "Client closed connection");
5889  } else if (parse_http_message(conn->buf, conn->buf_size,
5890  &conn->request_info) <= 0) {
5891  snprintf(ebuf, ebuf_len, "Bad request: [%.*s]", conn->data_len, conn->buf);
5892  } else {
5893  /* Request is valid */
5894  if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
5895  conn->content_len = strtoll(cl, NULL, 10);
5896  } else if (!mg_strcasecmp(conn->request_info.request_method, "POST") ||
5897  !mg_strcasecmp(conn->request_info.request_method, "PUT")) {
5898  conn->content_len = -1;
5899  } else {
5900  conn->content_len = 0;
5901  }
5902  conn->birth_time = time(NULL);
5903  }
5904  return ebuf[0] == '\0';
5905 }
5906 
5907 struct mg_connection *mg_download(const char *host, int port, int use_ssl,
5908  char *ebuf, size_t ebuf_len,
5909  const char *fmt, ...)
5910 {
5911  struct mg_connection *conn;
5912  va_list ap;
5913 
5914  va_start(ap, fmt);
5915  ebuf[0] = '\0';
5916  if ((conn = mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
5917  } else if (mg_vprintf(conn, fmt, ap) <= 0) {
5918  snprintf(ebuf, ebuf_len, "%s", "Error sending request");
5919  } else {
5920  getreq(conn, ebuf, ebuf_len);
5921  }
5922  if (ebuf[0] != '\0' && conn != NULL) {
5923  mg_close_connection(conn);
5924  conn = NULL;
5925  }
5926  va_end(ap);
5927 
5928  return conn;
5929 }
5930 
5931 static void process_new_connection(struct mg_connection *conn)
5932 {
5933  struct mg_request_info *ri = &conn->request_info;
5934  int keep_alive_enabled, keep_alive, discard_len;
5935  char ebuf[100];
5936 
5937  keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
5938  keep_alive = 0;
5939 
5940  /* Important: on new connection, reset the receiving buffer. Credit goes
5941  to crule42. */
5942  conn->data_len = 0;
5943  do {
5944  if (!getreq(conn, ebuf, sizeof(ebuf))) {
5945  send_http_error(conn, 500, "Server Error", "%s", ebuf);
5946  conn->must_close = 1;
5947  } else if (!is_valid_uri(conn->request_info.uri)) {
5948  snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
5949  send_http_error(conn, 400, "Bad Request", "%s", ebuf);
5950  } else if (strcmp(ri->http_version, "1.0") &&
5951  strcmp(ri->http_version, "1.1")) {
5952  snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
5953  send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
5954  }
5955 
5956  if (ebuf[0] == '\0') {
5957  handle_request(conn);
5958  if (conn->ctx->callbacks.end_request != NULL) {
5959  conn->ctx->callbacks.end_request(conn, conn->status_code);
5960  }
5961  log_access(conn);
5962  }
5963  if (ri->remote_user != NULL) {
5964  free((void *) ri->remote_user);
5965  /* Important! When having connections with and without auth
5966  would cause double free and then crash */
5967  ri->remote_user = NULL;
5968  }
5969 
5970  /* NOTE(lsm): order is important here. should_keep_alive() call is
5971  using parsed request, which will be invalid after memmove's below.
5972  Therefore, memorize should_keep_alive() result now for later use
5973  in loop exit condition. */
5974  keep_alive = conn->ctx->stop_flag == 0 && keep_alive_enabled &&
5975  conn->content_len >= 0 && should_keep_alive(conn);
5976 
5977  /* Discard all buffered data for this request */
5978  discard_len = conn->content_len >= 0 && conn->request_len > 0 &&
5979  conn->request_len + conn->content_len < (int64_t) conn->data_len ?
5980  (int) (conn->request_len + conn->content_len) : conn->data_len;
5981  assert(discard_len >= 0);
5982  memmove(conn->buf, conn->buf + discard_len, conn->data_len - discard_len);
5983  conn->data_len -= discard_len;
5984  assert(conn->data_len >= 0);
5985  assert(conn->data_len <= conn->buf_size);
5986  } while (keep_alive);
5987 }
5988 
5989 /* Worker threads take accepted socket from the queue */
5990 static int consume_socket(struct mg_context *ctx, struct socket *sp)
5991 {
5992  (void) pthread_mutex_lock(&ctx->mutex);
5993  DEBUG_TRACE(("going idle"));
5994 
5995  /* If the queue is empty, wait. We're idle at this point. */
5996  while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
5997  pthread_cond_wait(&ctx->sq_full, &ctx->mutex);
5998  }
5999 
6000  /* If we're stopping, sq_head may be equal to sq_tail. */
6001  if (ctx->sq_head > ctx->sq_tail) {
6002  /* Copy socket from the queue and increment tail */
6003  *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)];
6004  ctx->sq_tail++;
6005  DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock));
6006 
6007  /* Wrap pointers if needed */
6008  while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) {
6009  ctx->sq_tail -= ARRAY_SIZE(ctx->queue);
6010  ctx->sq_head -= ARRAY_SIZE(ctx->queue);
6011  }
6012  }
6013 
6014  (void) pthread_cond_signal(&ctx->sq_empty);
6015  (void) pthread_mutex_unlock(&ctx->mutex);
6016 
6017  return !ctx->stop_flag;
6018 }
6019 
6020 static void *worker_thread_run(void *thread_func_param)
6021 {
6022  struct mg_context *ctx = (struct mg_context *) thread_func_param;
6023  struct mg_connection *conn;
6024  struct mg_workerTLS tls;
6025 
6026  tls.is_master = 0;
6027 #if defined(_WIN32) && !defined(__SYMBIAN32__)
6028  tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
6029 #endif
6030 
6031  conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
6032  if (conn == NULL) {
6033  mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
6034  } else {
6035  pthread_setspecific(sTlsKey, &tls);
6036  conn->buf_size = MAX_REQUEST_SIZE;
6037  conn->buf = (char *) (conn + 1);
6038  conn->ctx = ctx;
6039  conn->request_info.user_data = ctx->user_data;
6040  /* Allocate a mutex for this connection to allow communication both
6041  within the request handler and from elsewhere in the application */
6042  (void) pthread_mutex_init(&conn->mutex, NULL);
6043 
6044  /* Call consume_socket() even when ctx->stop_flag > 0, to let it
6045  signal sq_empty condvar to wake up the master waiting in
6046  produce_socket() */
6047  while (consume_socket(ctx, &conn->client)) {
6048  conn->birth_time = time(NULL);
6049 
6050  /* Fill in IP, port info early so even if SSL setup below fails,
6051  error handler would have the corresponding info.
6052  Thanks to Johannes Winkelmann for the patch.
6053  TODO(lsm): Fix IPv6 case */
6054  conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
6055  memcpy(&conn->request_info.remote_ip,
6056  &conn->client.rsa.sin.sin_addr.s_addr, 4);
6057  conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
6058  conn->request_info.is_ssl = conn->client.is_ssl;
6059 
6060  if (!conn->client.is_ssl
6061 #ifndef NO_SSL
6062  || sslize(conn, conn->ctx->ssl_ctx, SSL_accept)
6063 #endif
6064  ) {
6065  process_new_connection(conn);
6066  }
6067 
6068  close_connection(conn);
6069  }
6070  }
6071 
6072  /* Signal master that we're done with connection and exiting */
6073  (void) pthread_mutex_lock(&ctx->mutex);
6074  ctx->num_threads--;
6075  (void) pthread_cond_signal(&ctx->cond);
6076  assert(ctx->num_threads >= 0);
6077  (void) pthread_mutex_unlock(&ctx->mutex);
6078 
6079  pthread_setspecific(sTlsKey, 0);
6080 #if defined(_WIN32) && !defined(__SYMBIAN32__)
6081  CloseHandle(tls.pthread_cond_helper_mutex);
6082 #endif
6083  free(conn);
6084 
6085  DEBUG_TRACE(("exiting"));
6086  return NULL;
6087 }
6088 
6089 /* Threads have different return types on Windows and Unix. */
6090 
6091 #ifdef _WIN32
6092 static unsigned __stdcall worker_thread(void *thread_func_param)
6093 {
6094  worker_thread_run(thread_func_param);
6095  return 0;
6096 }
6097 #else
6098 static void *worker_thread(void *thread_func_param)
6099 {
6100  worker_thread_run(thread_func_param);
6101  return NULL;
6102 }
6103 #endif /* _WIN32 */
6104 
6105 /* Master thread adds accepted socket to a queue */
6106 static void produce_socket(struct mg_context *ctx, const struct socket *sp)
6107 {
6108  (void) pthread_mutex_lock(&ctx->mutex);
6109 
6110  /* If the queue is full, wait */
6111  while (ctx->stop_flag == 0 &&
6112  ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) {
6113  (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex);
6114  }
6115 
6116  if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) {
6117  /* Copy socket to the queue and increment head */
6118  ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp;
6119  ctx->sq_head++;
6120  DEBUG_TRACE(("queued socket %d", sp->sock));
6121  }
6122 
6123  (void) pthread_cond_signal(&ctx->sq_full);
6124  (void) pthread_mutex_unlock(&ctx->mutex);
6125 }
6126 
6127 static int set_sock_timeout(SOCKET sock, int milliseconds)
6128 {
6129 #ifdef _WIN32
6130  DWORD t = milliseconds;
6131 #else
6132  struct timeval t;
6133  t.tv_sec = milliseconds / 1000;
6134  t.tv_usec = (milliseconds * 1000) % 1000000;
6135 #endif
6136  return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *) &t, sizeof(t)) ||
6137  setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *) &t, sizeof(t));
6138 }
6139 
6140 static void accept_new_connection(const struct socket *listener,
6141  struct mg_context *ctx)
6142 {
6143  struct socket so;
6144  char src_addr[IP_ADDR_STR_LEN];
6145  socklen_t len = sizeof(so.rsa);
6146  int on = 1;
6147 
6148  if ((so.sock = accept(listener->sock, &so.rsa.sa, &len)) == INVALID_SOCKET) {
6149  } else if (!check_acl(ctx, ntohl(* (uint32_t *) &so.rsa.sin.sin_addr))) {
6150  sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
6151  mg_cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
6152  closesocket(so.sock);
6153  } else {
6154  /* Put so socket structure into the queue */
6155  DEBUG_TRACE(("Accepted socket %d", (int) so.sock));
6156  set_close_on_exec(so.sock, fc(ctx));
6157  so.is_ssl = listener->is_ssl;
6158  so.ssl_redir = listener->ssl_redir;
6159  if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
6160  mg_cry(fc(ctx), "%s: getsockname() failed: %s",
6161  __func__, strerror(ERRNO));
6162  }
6163  /* Set TCP keep-alive. This is needed because if HTTP-level keep-alive
6164  is enabled, and client resets the connection, server won't get
6165  TCP FIN or RST and will keep the connection open forever. With TCP
6166  keep-alive, next keep-alive handshake will figure out that the
6167  client is down and will close the server end.
6168  Thanks to Igor Klopov who suggested the patch. */
6169  if (setsockopt(so.sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &on,
6170  sizeof(on)) != 0) {
6171  mg_cry(fc(ctx),
6172  "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
6173  __func__, strerror(ERRNO));
6174  }
6175  set_sock_timeout(so.sock, atoi(ctx->config[REQUEST_TIMEOUT]));
6176  produce_socket(ctx, &so);
6177  }
6178 }
6179 
6180 static void master_thread_run(void *thread_func_param)
6181 {
6182  struct mg_context *ctx = (struct mg_context *) thread_func_param;
6183  struct mg_workerTLS tls;
6184  struct pollfd *pfd;
6185  int i;
6186  int workerthreadcount;
6187 
6188  /* Increase priority of the master thread */
6189 #if defined(_WIN32)
6190  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
6191 #elif defined(USE_MASTER_THREAD_PRIORITY)
6192  int min_prio = sched_get_priority_min(SCHED_RR);
6193  int max_prio = sched_get_priority_max(SCHED_RR);
6194  if ((min_prio >=0) && (max_prio >= 0) &&
6195  ((USE_MASTER_THREAD_PRIORITY) <= max_prio) &&
6196  ((USE_MASTER_THREAD_PRIORITY) >= min_prio)
6197  ) {
6198  struct sched_param sched_param = {0};
6199  sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
6200  pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
6201  }
6202 #endif
6203 
6204 #if defined(_WIN32) && !defined(__SYMBIAN32__)
6205  tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
6206 #endif
6207  tls.is_master = 1;
6208  pthread_setspecific(sTlsKey, &tls);
6209 
6210  pfd = (struct pollfd *) calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
6211  while (pfd != NULL && ctx->stop_flag == 0) {
6212  for (i = 0; i < ctx->num_listening_sockets; i++) {
6213  pfd[i].fd = ctx->listening_sockets[i].sock;
6214  pfd[i].events = POLLIN;
6215  }
6216 
6217  if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
6218  for (i = 0; i < ctx->num_listening_sockets; i++) {
6219  /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
6220  successful poll, and POLLIN is defined as
6221  (POLLRDNORM | POLLRDBAND)
6222  Therefore, we're checking pfd[i].revents & POLLIN, not
6223  pfd[i].revents == POLLIN. */
6224  if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
6225  accept_new_connection(&ctx->listening_sockets[i], ctx);
6226  }
6227  }
6228  }
6229  }
6230  free(pfd);
6231  DEBUG_TRACE(("stopping workers"));
6232 
6233  /* Stop signal received: somebody called mg_stop. Quit. */
6235 
6236  /* Wakeup workers that are waiting for connections to handle. */
6237  pthread_cond_broadcast(&ctx->sq_full);
6238 
6239  /* Wait until all threads finish */
6240  (void) pthread_mutex_lock(&ctx->mutex);
6241  while (ctx->num_threads > 0) {
6242  (void) pthread_cond_wait(&ctx->cond, &ctx->mutex);
6243  }
6244  (void) pthread_mutex_unlock(&ctx->mutex);
6245 
6246  /* Join all worker threads to avoid leaking threads. */
6247  workerthreadcount = ctx->workerthreadcount;
6248  for (i = 0; i < workerthreadcount; i++) {
6249  mg_join_thread(ctx->workerthreadids[i]);
6250  }
6251 
6252  /* All threads exited, no sync is needed. Destroy mutex and condvars */
6253  (void) pthread_mutex_destroy(&ctx->mutex);
6254  (void) pthread_cond_destroy(&ctx->cond);
6255  (void) pthread_cond_destroy(&ctx->sq_empty);
6256  (void) pthread_cond_destroy(&ctx->sq_full);
6257 
6258 #if !defined(NO_SSL)
6259  uninitialize_ssl(ctx);
6260 #endif
6261  DEBUG_TRACE(("exiting"));
6262 
6263 #if defined(_WIN32) && !defined(__SYMBIAN32__)
6264  CloseHandle(tls.pthread_cond_helper_mutex);
6265 #endif
6266  pthread_setspecific(sTlsKey, 0);
6267 
6268  /* Signal mg_stop() that we're done.
6269  WARNING: This must be the very last thing this
6270  thread does, as ctx becomes invalid after this line. */
6271  ctx->stop_flag = 2;
6272 }
6273 
6274 /* Threads have different return types on Windows and Unix. */
6275 
6276 #ifdef _WIN32
6277 static unsigned __stdcall master_thread(void *thread_func_param)
6278 {
6279  master_thread_run(thread_func_param);
6280  return 0;
6281 }
6282 #else
6283 static void *master_thread(void *thread_func_param)
6284 {
6285  master_thread_run(thread_func_param);
6286  return NULL;
6287 }
6288 #endif /* _WIN32 */
6289 
6290 static void free_context(struct mg_context *ctx)
6291 {
6292  int i;
6293  struct mg_request_handler_info *tmp_rh;
6294 
6295  if (ctx == NULL)
6296  return;
6297 
6298  /* Deallocate config parameters */
6299  for (i = 0; i < NUM_OPTIONS; i++) {
6300  if (ctx->config[i] != NULL)
6301 #ifdef WIN32
6302 #pragma warning(suppress: 6001)
6303 #endif
6304  free(ctx->config[i]);
6305  }
6306 
6307  /* Deallocate request handlers */
6308  while (ctx->request_handlers) {
6309  tmp_rh = ctx->request_handlers;
6310  ctx->request_handlers = tmp_rh->next;
6311  free(tmp_rh->uri);
6312  free(tmp_rh);
6313  }
6314 
6315 #ifndef NO_SSL
6316  /* Deallocate SSL context */
6317  if (ctx->ssl_ctx != NULL) {
6318  SSL_CTX_free(ctx->ssl_ctx);
6319  }
6320  if (ssl_mutexes != NULL) {
6321  free(ssl_mutexes);
6322  ssl_mutexes = NULL;
6323  }
6324 #endif /* !NO_SSL */
6325 
6326  /* Deallocate worker thread ID array */
6327  if (ctx->workerthreadids != NULL) {
6328  free(ctx->workerthreadids);
6329  }
6330 
6331  /* Deallocate the tls variable */
6332  sTlsInit--;
6333  if (sTlsInit==0) {
6334  pthread_key_delete(sTlsKey);
6335  }
6336 
6337  /* Deallocate context itself */
6338  free(ctx);
6339 }
6340 
6341 void mg_stop(struct mg_context *ctx)
6342 {
6343  ctx->stop_flag = 1;
6344 
6345  /* Wait until mg_fini() stops */
6346  while (ctx->stop_flag != 2) {
6347  (void) mg_sleep(10);
6348  }
6349  mg_join_thread(ctx->masterthreadid);
6350  free_context(ctx);
6351 
6352 #if defined(_WIN32) && !defined(__SYMBIAN32__)
6353  (void) WSACleanup();
6354 #endif /* _WIN32 && !__SYMBIAN32__ */
6355 }
6356 
6357 struct mg_context *mg_start(const struct mg_callbacks *callbacks,
6358  void *user_data,
6359  const char **options)
6360 {
6361  struct mg_context *ctx;
6362  const char *name, *value, *default_value;
6363  int i;
6364  int workerthreadcount;
6365 
6366 #if defined(_WIN32) && !defined(__SYMBIAN32__)
6367  WSADATA data;
6368  WSAStartup(MAKEWORD(2,2), &data);
6369 #pragma warning(suppress: 28125)
6370  InitializeCriticalSection(&global_log_file_lock);
6371 #endif /* _WIN32 && !__SYMBIAN32__ */
6372 
6373  /* Check if the config_options and the corresponding enum have compatible sizes. */
6374  /* Could use static_assert, once it is verified that all compilers support this. */
6375  assert(sizeof(config_options)/sizeof(config_options[0]) == NUM_OPTIONS*2+1);
6376 
6377  /* Allocate context and initialize reasonable general case defaults.
6378  TODO(lsm): do proper error handling here. */
6379  if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
6380  return NULL;
6381  }
6382 
6383  if (sTlsInit==0) {
6384  if (0 != pthread_key_create(&sTlsKey, NULL)) {
6385  mg_cry(fc(ctx), "Cannot initialize thread local storage");
6386  free(ctx);
6387  return NULL;
6388  }
6389  sTlsInit++;
6390  }
6391 
6392  ctx->callbacks = *callbacks;
6393  ctx->user_data = user_data;
6394  ctx->request_handlers = 0;
6395 
6396  while (options && (name = *options++) != NULL) {
6397  if ((i = get_option_index(name)) == -1) {
6398  mg_cry(fc(ctx), "Invalid option: %s", name);
6399  free_context(ctx);
6400  return NULL;
6401  } else if ((value = *options++) == NULL) {
6402  mg_cry(fc(ctx), "%s: option value cannot be NULL", name);
6403  free_context(ctx);
6404  return NULL;
6405  }
6406  if (ctx->config[i] != NULL) {
6407  mg_cry(fc(ctx), "warning: %s: duplicate option", name);
6408  free(ctx->config[i]);
6409  }
6410  ctx->config[i] = mg_strdup(value);
6411  DEBUG_TRACE(("[%s] -> [%s]", name, value));
6412  }
6413 
6414  /* Set default value if needed */
6415  for (i = 0; config_options[i * 2] != NULL; i++) {
6416  default_value = config_options[i * 2 + 1];
6417  if (ctx->config[i] == NULL && default_value != NULL) {
6418  ctx->config[i] = mg_strdup(default_value);
6419  }
6420  }
6421 
6422  /* NOTE(lsm): order is important here. SSL certificates must
6423  be initialized before listening ports. UID must be set last. */
6424  if (!set_gpass_option(ctx) ||
6425 #if !defined(NO_SSL)
6426  !set_ssl_option(ctx) ||
6427 #endif
6428  !set_ports_option(ctx) ||
6429 #if !defined(_WIN32)
6430  !set_uid_option(ctx) ||
6431 #endif
6432  !set_acl_option(ctx)) {
6433  free_context(ctx);
6434  return NULL;
6435  }
6436 
6437 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
6438  /* Ignore SIGPIPE signal, so if browser cancels the request, it
6439  won't kill the whole process. */
6440  (void) signal(SIGPIPE, SIG_IGN);
6441 #endif /* !_WIN32 && !__SYMBIAN32__ */
6442 
6443  (void) pthread_mutex_init(&ctx->mutex, NULL);
6444  (void) pthread_cond_init(&ctx->cond, NULL);
6445  (void) pthread_cond_init(&ctx->sq_empty, NULL);
6446  (void) pthread_cond_init(&ctx->sq_full, NULL);
6447 
6448  workerthreadcount = atoi(ctx->config[NUM_THREADS]);
6449 
6450  if (workerthreadcount > MAX_WORKER_THREADS) {
6451  mg_cry(fc(ctx), "Too many worker threads");
6452  free_context(ctx);
6453  return NULL;
6454  }
6455 
6456  if (workerthreadcount > 0) {
6457  ctx->workerthreadcount = workerthreadcount;
6458  ctx->workerthreadids = calloc(workerthreadcount, sizeof(pthread_t));
6459  if (ctx->workerthreadids == NULL) {
6460  mg_cry(fc(ctx), "Not enough memory for worker thread ID array");
6461  free_context(ctx);
6462  return NULL;
6463  }
6464  }
6465 
6466  /* Start master (listening) thread */
6467  mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
6468 
6469  /* Start worker threads */
6470  for (i = 0; i < workerthreadcount; i++) {
6471  (void) pthread_mutex_lock(&ctx->mutex);
6472  ctx->num_threads++;
6473  (void) pthread_mutex_unlock(&ctx->mutex);
6475  &ctx->workerthreadids[i]) != 0) {
6476  (void) pthread_mutex_lock(&ctx->mutex);
6477  ctx->num_threads--;
6478  (void) pthread_mutex_unlock(&ctx->mutex);
6479  mg_cry(fc(ctx), "Cannot start worker thread: %ld", (long) ERRNO);
6480  }
6481  }
6482 
6483  return ctx;
6484 }
static int is_file_in_memory(struct mg_connection *conn, const char *path, struct file *filep)
Definition: civetweb.c:678
int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence)
Definition: civetweb.c:2195
#define MAX_CGI_ENVIR_VARS
Definition: civetweb.c:291
static int set_ports_option(struct mg_context *ctx)
Definition: civetweb.c:5383
const char * remote_user
Definition: civetweb.h:47
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
Definition: civetweb.c:1044
static void mg_fclose(struct file *filep)
Definition: civetweb.c:724
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
Definition: civetweb.c:2163
static void close_all_listening_sockets(struct mg_context *ctx)
Definition: civetweb.c:5325
double read(const std::string &file_name)
reading
struct md5_state_s md5_state_t
size_t mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
Definition: civetweb.c:755
#define ERRNO
Definition: civetweb.c:279
static int match_prefix(const char *pattern, int pattern_len, const char *str)
Definition: civetweb.c:1079
int pw_uid
Definition: TWinNTSystem.h:52
int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
static int authorize(struct mg_connection *conn, struct file *filep)
Definition: civetweb.c:2807
static int is_valid_port(unsigned int port)
Definition: civetweb.c:5334
#define CRYPTO_set_id_callback
Definition: civetweb.c:427
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
Definition: civetweb.h:191
#define MAX_REQUEST_SIZE
Definition: civetweb.c:294
#define ERR_get_error
Definition: civetweb.c:429
static int num_leap_years(int year)
Definition: civetweb.c:2407
const char * uri
Definition: civetweb.h:43
static char * mg_strndup(const char *ptr, size_t len)
Definition: civetweb.c:892
static const char * ssl_error(void)
Definition: civetweb.c:5572
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
Definition: civetweb.c:2900
#define SSL_CTX_use_certificate_chain_file
Definition: civetweb.c:417
unsigned int hex
Definition: math.cpp:442
int mg_start_thread(mg_thread_func_t func, void *param)
Definition: civetweb.c:1797
static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
Definition: civetweb.c:1954
static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_env_block *blk)
Definition: civetweb.c:3704
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
Definition: civetweb.c:783
ClassImp(TSeqCollection) Int_t TSeqCollection TIter next(this)
Return index of object in collection.
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
Definition: civetweb.c:4118
const char * mime_type
Definition: civetweb.c:2469
TLine * line
#define INVALID_HANDLE_VALUE
Definition: TMapFile.cxx:84
static int check_acl(struct mg_context *ctx, uint32_t remote_ip)
Definition: civetweb.c:5510
#define PRINTF_ARGS(x, y)
Definition: civetweb.h:322
static int set_uid_option(struct mg_context *ctx)
Definition: civetweb.c:5537
RooArgList L(const RooAbsArg &v1)
#define mg_mkdir(x, y)
Definition: civetweb.c:276
static int set_acl_option(struct mg_context *ctx)
Definition: civetweb.c:5723
#define assert(cond)
Definition: unittest.h:542
#define SSL_library_init
Definition: civetweb.c:408
#define closesocket(a)
Definition: civetweb.c:275
static int isbyte(int n)
Definition: civetweb.c:4873
static int consume_socket(struct mg_context *ctx, struct socket *sp)
Definition: civetweb.c:5990
int mg_read(struct mg_connection *conn, void *buf, size_t len)
Definition: civetweb.c:1996
static void bin2str(char *to, const unsigned char *p, size_t len)
Definition: civetweb.c:2603
static void convert_uri_to_file_name(struct mg_connection *conn, char *buf, size_t buf_len, struct file *filep, int *is_script_ressource)
Definition: civetweb.c:2284
static void print_props(struct mg_connection *conn, const char *uri, struct file *filep)
Definition: civetweb.c:4298
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
Definition: civetweb.c:6106
const char * mg_version(void)
Definition: civetweb.c:846
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
Definition: civetweb.c:3820
#define SSL_set_fd
Definition: civetweb.c:404
static void handle_request(struct mg_connection *conn)
Definition: civetweb.c:5194
static SOCKET conn2(struct mg_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len)
Definition: civetweb.c:2965
static void log_header(const struct mg_connection *conn, const char *header, FILE *fp)
Definition: civetweb.c:5457
static const struct @204 builtin_mime_types[]
static void reset_per_request_attributes(struct mg_connection *conn)
Definition: civetweb.c:5728
void mg_stop(struct mg_context *ctx)
Definition: civetweb.c:6341
static void remove_double_dots_and_double_slashes(char *s)
Definition: civetweb.c:2444
#define SSL_write
Definition: civetweb.c:402
const struct mg_context * mg_get_context(const struct mg_connection *conn)
Definition: civetweb.c:696
#define ARRAY_SIZE(array)
Definition: civetweb.c:296
static int get_option_index(const char *name)
Definition: civetweb.c:731
static int is_valid_uri(const char *uri)
Definition: civetweb.c:5867
static const char * get_header(const struct mg_request_info *ri, const char *name)
Definition: civetweb.c:1021
#define MAX_WORKER_THREADS
Definition: civetweb.c:82
int mg_upload(struct mg_connection *conn, const char *destination_dir)
Definition: civetweb.c:4928
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
Definition: civetweb.c:2244
TAlienJobStatus * status
Definition: TAlienJob.cxx:51
struct mg_request_info::mg_header http_headers[64]
TArc * a
Definition: textangle.C:12
static void * master_thread(void *thread_func_param)
Definition: civetweb.c:6283
static int use_request_handler(struct mg_connection *conn)
Definition: civetweb.c:5157
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
Definition: civetweb.c:3328
#define CGI_ENVIRONMENT_SIZE
Definition: civetweb.c:290
static void set_close_on_exec(int fd, struct mg_connection *conn)
Definition: civetweb.c:1788
static pthread_mutex_t * ssl_mutexes
Definition: civetweb.c:5562
static void * load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
Definition: civetweb.c:5598
static void close_connection(struct mg_connection *conn)
Definition: civetweb.c:5773
#define CIVETWEB_VERSION
Definition: civetweb.h:26
size_t
Definition: TBuffer.cxx:28
#define CRYPTO_num_locks
Definition: civetweb.c:424
static void close_socket_gracefully(struct mg_connection *conn)
Definition: civetweb.c:5736
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
Definition: civetweb.c:1975
#define MGSQLEN
Definition: civetweb.c:376
static int check_authorization(struct mg_connection *conn, const char *path)
Definition: civetweb.c:2833
int SOCKET
Definition: civetweb.c:282
const char * mg_get_option(const struct mg_context *ctx, const char *name)
Definition: civetweb.c:743
#define SSL_CTX_free
Definition: civetweb.c:415
#define PRINTF_FORMAT_STRING(s)
Definition: civetweb.h:316
static void parse_http_headers(char **buf, struct mg_request_info *ri)
Definition: civetweb.c:3448
#define ERR_error_string
Definition: civetweb.c:430
static struct mg_connection * fc(struct mg_context *ctx)
Definition: civetweb.c:839
static int read_request(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread)
Definition: civetweb.c:3514
static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
Definition: civetweb.c:1820
static void dir_scan_callback(struct de *de, void *data)
Definition: civetweb.c:3206
unsigned char md5_byte_t
Definition: md5.inl:50
const char * request_method
Definition: civetweb.h:42
static const char * mg_strcasestr(const char *big_str, const char *small_str)
Definition: civetweb.c:908
Vc_ALWAYS_INLINE void free(T *p)
Frees memory that was allocated with Vc::malloc.
Definition: memory.h:94
#define WINCDECL
Definition: civetweb.c:283
static int mg_strcasecmp(const char *s1, const char *s2)
Definition: civetweb.c:881
static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen, const char *fmt, va_list ap)
Definition: civetweb.c:925
#define HEXTOI(x)
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
Definition: md5.inl:403
static void send_http_error(struct mg_connection *, int, const char *, PRINTF_FORMAT_STRING(const char *fmt),...)
Definition: civetweb.c:1141
static void handle_propfind(struct mg_connection *conn, const char *path, struct file *filep)
Definition: civetweb.c:4332
static int is_authorized_for_put(struct mg_connection *conn)
Definition: civetweb.c:2886
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
Definition: civetweb.c:5092
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
Definition: civetweb.c:969
static double p2(double t, double a, double b, double c)
static int is_put_or_delete_request(const struct mg_connection *conn)
Definition: civetweb.c:5046
static void send_authorization_request(struct mg_connection *conn)
Definition: civetweb.c:2865
if(pyself &&pyself!=Py_None)
static int is_not_modified(const struct mg_connection *conn, const struct file *filep)
Definition: civetweb.c:3580
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
Definition: civetweb.c:4878
#define SSL_CTX_use_PrivateKey_file
Definition: civetweb.c:409
static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
Definition: civetweb.c:2077
static void master_thread_run(void *thread_func_param)
Definition: civetweb.c:6180
static const std::string pattern("pattern")
static const char * suggest_connection_header(const struct mg_connection *conn)
Definition: civetweb.c:1136
static int get_request_len(const char *buf, int buflen)
Definition: civetweb.c:2372
#define SSL_shutdown
Definition: civetweb.c:422
static int mg_fgetc(struct file *filep, int offset)
Definition: civetweb.c:4181
void mg_send_file(struct mg_connection *conn, const char *path)
Definition: civetweb.c:3435
static int set_non_blocking_mode(SOCKET sock)
Definition: civetweb.c:1904
#define SSLv23_client_method
Definition: civetweb.c:419
struct mg_connection * mg_connect(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len)
Definition: civetweb.c:5820
double sin(double)
#define SOMAXCONN
Definition: civetweb.c:367
static void print_dav_dir_entry(struct de *de, void *data)
Definition: civetweb.c:4321
static int get_first_ssl_listener_index(const struct mg_context *ctx)
Definition: civetweb.c:5054
#define SSL_CTX_use_certificate_file
Definition: civetweb.c:411
static char * mg_fgets(char *buf, size_t size, struct file *filep, char **p)
Definition: civetweb.c:2778
char * out
Definition: TBase64.cxx:29
static int mg_join_thread(pthread_t threadid)
Definition: civetweb.c:1845
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void(*cb)(struct de *, void *))
Definition: civetweb.c:3099
int mg_printf(struct mg_connection *conn, const char *fmt,...)
Definition: civetweb.c:2151
static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(4
char * mg_md5(char buf[33],...)
Definition: civetweb.c:2615
static int set_ssl_option(struct mg_context *ctx)
Definition: civetweb.c:5637
static time_t parse_date_string(const char *datetime)
Definition: civetweb.c:2413
static int is_file_opened(const struct file *filep)
Definition: civetweb.c:691
struct ssl_st SSL
Definition: civetweb.c:389
static void mkcol(struct mg_connection *conn, const char *path)
Definition: civetweb.c:4026
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
Definition: civetweb.c:3064
static void uninitialize_ssl(struct mg_context *ctx)
Definition: civetweb.c:5698
static void * worker_thread_run(void *thread_func_param)
Definition: civetweb.c:6020
size_t ext_len
Definition: civetweb.c:2468
void mg_unlock(struct mg_connection *conn)
Definition: civetweb.c:4371
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct file *filep)
Definition: civetweb.c:3534
struct ssl_method_st SSL_METHOD
Definition: civetweb.c:390
SVector< double, 2 > v
Definition: Dict.h:5
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: civetweb.c:2636
#define INT64_FMT
Definition: civetweb.c:281
int mg_url_encode(const char *src, char *dst, size_t dst_len)
Definition: civetweb.c:2997
unsigned int r1[N_CITIES]
Definition: simanTSP.cxx:321
#define SSL_new
Definition: civetweb.c:405
static char * addenv(struct cgi_env_block *block, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
#define DEBUG_TRACE(x)
Definition: civetweb.c:350
TLine * l
Definition: textangle.C:4
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
Definition: civetweb.c:5579
static double p1(double t, double a, double b)
static int put_dir(struct mg_connection *conn, const char *path)
Definition: civetweb.c:3994
static int must_hide_file(struct mg_connection *conn, const char *path)
Definition: civetweb.c:3091
static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
Definition: civetweb.c:1772
const char * http_version
Definition: civetweb.h:44
static void put_file(struct mg_connection *conn, const char *path)
Definition: civetweb.c:4075
#define SSL_CTX_new
Definition: civetweb.c:406
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
Definition: civetweb.c:6357
static const char * config_options[]
Definition: civetweb.c:541
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
Definition: civetweb.c:2037
static int remove_directory(struct mg_connection *conn, const char *dir)
Definition: civetweb.c:3141
static void handle_ssi_file_request(struct mg_connection *conn, const char *path)
Definition: civetweb.c:4256
void mg_cry(struct mg_connection *conn, const char *fmt,...)
Definition: civetweb.c:797
static void send_ssi_file(struct mg_connection *, const char *, struct file *, int)
Definition: civetweb.c:4192
static int should_keep_alive(const struct mg_connection *conn)
Definition: civetweb.c:1122
void mg_close_connection(struct mg_connection *conn)
Definition: civetweb.c:5805
static void handle_directory_request(struct mg_connection *conn, const char *dir)
Definition: civetweb.c:3226
const char * extension
Definition: civetweb.c:2467
#define mg_remove(x)
Definition: civetweb.c:277
static int lowercase(const char *s)
Definition: civetweb.c:864
struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
Definition: civetweb.c:5907
static unsigned int total
static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
Definition: civetweb.c:2576
const char ** mg_get_valid_option_names(void)
Definition: civetweb.c:673
static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
Definition: civetweb.c:4894
const char * mg_get_header(const struct mg_connection *conn, const char *name)
Definition: civetweb.c:1033
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
Definition: md5.inl:441
#define INVALID_SOCKET
Definition: civetweb.c:280
void * mg_get_user_data(const struct mg_context *ctx)
Definition: civetweb.c:701
static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin, int fdout, const char *dir)
Definition: civetweb.c:1854
#define CRYPTO_LIB
Definition: civetweb.c:269
#define CRYPTO_set_locking_callback
Definition: civetweb.c:425
static uint32_t get_remote_ip(const struct mg_connection *conn)
Definition: civetweb.c:4923
double func(double *x, double *p)
Definition: stressTF1.cxx:213
static void fclose_on_exec(struct file *filep, struct mg_connection *conn)
Definition: civetweb.c:3340
#define SSL_load_error_strings
Definition: civetweb.c:416
static void process_new_connection(struct mg_connection *conn)
Definition: civetweb.c:5931
TCanvas * slash()
Definition: slash.C:1
#define PASSWORDS_FILE_NAME
Definition: civetweb.c:289
static void handle_file_request(struct mg_connection *conn, const char *path, struct file *filep)
Definition: civetweb.c:3354
#define IP_ADDR_STR_LEN
Definition: civetweb.c:360
static void * worker_thread(void *thread_func_param)
Definition: civetweb.c:6098
#define name(a, b)
Definition: linkTestLib0.cpp:5
R__EXTERN C unsigned int sleep(unsigned int seconds)
static void construct_etag(char *buf, size_t buf_len, const struct file *filep)
Definition: civetweb.c:3333
int pw_gid
Definition: TWinNTSystem.h:53
#define SSL_CTX_set_verify
Definition: civetweb.c:421
#define SSL_free
Definition: civetweb.c:398
while((ob=next()))
static int is_valid_http_method(const char *method)
Definition: civetweb.c:3462
typedef void((*Func_t)())
#define SSLv23_server_method
Definition: civetweb.c:407
#define STRUCT_FILE_INITIALIZER
Definition: civetweb.c:506
static void do_ssi_exec(struct mg_connection *conn, char *tag)
Definition: civetweb.c:4165
#define SSL_LIB
Definition: civetweb.c:266
#define SSL_connect
Definition: civetweb.c:400
#define IGNORE_UNUSED_RESULT(a)
Definition: civetweb.c:61
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
Definition: civetweb.c:856
static int parse_http_message(char *buf, int len, struct mg_request_info *ri)
Definition: civetweb.c:3475
int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
Definition: civetweb.c:2136
static int sslize(struct mg_connection *conn, SSL_CTX *s, int(*func)(SSL *))
Definition: civetweb.c:5564
static void send_file_data(struct mg_connection *conn, struct file *filep, int64_t offset, int64_t len)
Definition: civetweb.c:3285
static void print_dir_entry(struct de *de)
Definition: civetweb.c:3022
const char * mg_get_builtin_mime_type(const char *path)
Definition: civetweb.c:2556
static int set_sock_timeout(SOCKET sock, int milliseconds)
Definition: civetweb.c:6127
struct ssl_ctx_st SSL_CTX
Definition: civetweb.c:391
static void send_options(struct mg_connection *conn)
Definition: civetweb.c:4280
#define NULL
Definition: Rtypes.h:82
static void open_auth_file(struct mg_connection *conn, const char *path, struct file *filep)
Definition: civetweb.c:2666
ClassImp(TSlaveInfo) Int_t TSlaveInfo const TSlaveInfo * si
Used to sort slaveinfos by ordinal.
Definition: TProof.cxx:167
void *(* mg_thread_func_t)(void *)
Definition: civetweb.h:450
struct mg_request_info * mg_get_request_info(struct mg_connection *conn)
Definition: civetweb.c:851
static int mg_fopen(struct mg_connection *conn, const char *path, const char *mode, struct file *filep)
Definition: civetweb.c:707
static pthread_key_t sTlsKey
Definition: civetweb.c:652
static int set_gpass_option(struct mg_context *ctx)
Definition: civetweb.c:5712
double result[121]
static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
Definition: civetweb.c:5063
#define MG_BUF_LEN
Definition: civetweb.c:292
#define MSG_NOSIGNAL
Definition: civetweb.c:363
#define SSL_accept
Definition: civetweb.c:399
static unsigned long ssl_id_callback(void)
Definition: civetweb.c:5592
static char * mg_strdup(const char *str)
Definition: civetweb.c:903
MD5_STATIC void md5_init(md5_state_t *pms)
Definition: md5.inl:393
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
Definition: civetweb.c:6140
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
Definition: civetweb.c:766
#define PATH_MAX
Definition: civetweb.c:371
static void free_context(struct mg_context *ctx)
Definition: civetweb.c:6290
int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len)
Definition: civetweb.c:2189
float value
Definition: math.cpp:443
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
Definition: civetweb.c:2713
Vc_ALWAYS_INLINE_L T *Vc_ALWAYS_INLINE_R malloc(size_t n)
Allocates memory on the Heap with alignment and padding suitable for vectorized access.
Definition: memory.h:67
static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
Definition: civetweb.c:1917
static char * skip(char **buf, const char *delimiters)
Definition: civetweb.c:1014
const Int_t n
Definition: legend1.C:16
static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
Definition: civetweb.c:2099
static int parse_port_string(const struct vec *vec, struct socket *so)
Definition: civetweb.c:5342
static int get_month_index(const char *s)
Definition: civetweb.c:2396
unsigned int r2[N_CITIES]
Definition: simanTSP.cxx:322
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
Definition: civetweb.c:3591
static void log_access(const struct mg_connection *conn)
Definition: civetweb.c:5469
#define mg_sleep(x)
Definition: civetweb.c:278
static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len)
Definition: civetweb.c:5875
int mg_strncasecmp(const char *s1, const char *s2, size_t len)
Definition: civetweb.c:869
void mg_lock(struct mg_connection *conn)
Definition: civetweb.c:4366
#define SSL_read
Definition: civetweb.c:401
static void * realloc2(void *ptr, size_t size)
Definition: civetweb.c:3197