1 /* Copyright (c) 2013-2016 the Civetweb developers
2 * Copyright (c) 2004-2013 Sergey Lyubka
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 #if defined(_WIN32)
24 #if !defined(_CRT_SECURE_NO_WARNINGS)
25 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
26 #endif
27 #ifndef _WIN32_WINNT /* defined for tdm-gcc so we can use getnameinfo */
28 #define _WIN32_WINNT 0x0501
29 #endif
30 #else
31 #if defined(__GNUC__) && !defined(_GNU_SOURCE)
32 #define _GNU_SOURCE /* for setgroups() */
33 #endif
34 #if defined(__linux__) && !defined(_XOPEN_SOURCE)
35 #define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
36 #endif
37 #ifndef _LARGEFILE_SOURCE
38 #define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
39 #endif
40 #ifndef _FILE_OFFSET_BITS
41 #define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
42 #endif
43 #ifndef __STDC_FORMAT_MACROS
44 #define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
45 #endif
46 #ifndef __STDC_LIMIT_MACROS
47 #define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
48 #endif
49 #ifdef __sun
50 #define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
51 #define __inline inline /* not recognized on older compiler versions */
52 #endif
53 #endif
54
55 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
56 #define USE_TIMERS
57 #endif
58
59 #if defined(_MSC_VER)
60 /* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
61 #pragma warning(disable : 4306)
62 /* conditional expression is constant: introduced by FD_SET(..) */
63 #pragma warning(disable : 4127)
64 /* non-constant aggregate initializer: issued due to missing C99 support */
65 #pragma warning(disable : 4204)
66 /* padding added after data member */
67 #pragma warning(disable : 4820)
68 /* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
69 #pragma warning(disable : 4668)
70 /* no function prototype given: converting '()' to '(void)' */
71 #pragma warning(disable : 4255)
72 /* function has been selected for automatic inline expansion */
73 #pragma warning(disable : 4711)
74 #endif
75
76
77 /* This code uses static_assert to check some conditions.
78 * Unfortunately some compilers still do not support it, so we have a
79 * replacement function here. */
80 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
81 #define mg_static_assert static_assert
82 #elif defined(__cplusplus) && (__cplusplus >= 201103L)
83 #define mg_static_assert static_assert
84 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
85 #define mg_static_assert _Static_assert
86 #else
87 char static_assert_replacement[1];
88 #define mg_static_assert(cond, txt) \
89 extern char static_assert_replacement[(cond) ? 1 : -1]
90 #endif
91
92 mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
93 "int data type size check");
94 mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
95 "pointer data type size check");
96 mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
97
98
99 /* DTL -- including winsock2.h works better if lean and mean */
100 #ifndef WIN32_LEAN_AND_MEAN
101 #define WIN32_LEAN_AND_MEAN
102 #endif
103
104 #if defined(__SYMBIAN32__)
105 #define NO_SSL /* SSL is not supported */
106 #define NO_CGI /* CGI is not supported */
107 #define PATH_MAX FILENAME_MAX
108 #endif /* __SYMBIAN32__ */
109
110
111 /* Include the header file here, so the CivetWeb interface is defined for the
112 * entire implementation, including the following forward definitions. */
113 #include "civetweb.h"
114
115
116 #ifndef IGNORE_UNUSED_RESULT
117 #define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
118 #endif
119
120 #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
121 #include <sys/types.h>
122 #include <sys/stat.h>
123 #include <errno.h>
124 #include <signal.h>
125 #include <fcntl.h>
126 #endif /* !_WIN32_WCE */
127
128
129 #ifdef __clang__
130 /* When using -Weverything, clang does not accept it's own headers
131 * in a release build configuration. Disable what is too much in
132 * -Weverything. */
133 #pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
134 #endif
135
136
137 #ifdef __MACH__ /* Apple OSX section */
138
139 #ifdef __clang__
140 /* Avoid warnings for Xopen 7.00 and higher */
141 /* CYRUSH NOTE: Conduit Mod from: https://github.com/civetweb/civetweb/issues/503 */
142 #if (__clang_major__ < 3) || ((__clang_major__ < 4) && (__clang_minor__ < 9))
143 #pragma clang diagnostic ignored "-Wno-reserved-id-macro"
144 #pragma clang diagnostic ignored "-Wno-keyword-macro"
145 #endif
146 #endif
147
148 #define CLOCK_MONOTONIC (1)
149 #define CLOCK_REALTIME (2)
150
151 #include <sys/errno.h>
152 #include <sys/time.h>
153 #include <mach/clock.h>
154 #include <mach/mach.h>
155 #include <mach/mach_time.h>
156 #include <assert.h>
157
158 /* clock_gettime is not implemented on OSX prior to 10.12 */
159 static int
_civet_clock_gettime(int clk_id,struct timespec * t)160 _civet_clock_gettime(int clk_id, struct timespec *t)
161 {
162 memset(t, 0, sizeof(*t));
163 if (clk_id == CLOCK_REALTIME) {
164 struct timeval now;
165 int rv = gettimeofday(&now, NULL);
166 if (rv) {
167 return rv;
168 }
169 t->tv_sec = now.tv_sec;
170 t->tv_nsec = now.tv_usec * 1000;
171 return 0;
172
173 } else if (clk_id == CLOCK_MONOTONIC) {
174 static uint64_t clock_start_time = 0;
175 static mach_timebase_info_data_t timebase_ifo = {0, 0};
176
177 uint64_t now = mach_absolute_time();
178
179 if (clock_start_time == 0) {
180 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
181 #if defined(DEBUG)
182 assert(mach_status == KERN_SUCCESS);
183 #else
184 /* appease "unused variable" warning for release builds */
185 (void)mach_status;
186 #endif
187 clock_start_time = now;
188 }
189
190 now = (uint64_t)((double)(now - clock_start_time)
191 * (double)timebase_ifo.numer
192 / (double)timebase_ifo.denom);
193
194 t->tv_sec = now / 1000000000;
195 t->tv_nsec = now % 1000000000;
196 return 0;
197 }
198 return -1; /* EINVAL - Clock ID is unknown */
199 }
200
201 /* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
202 #ifdef __CLOCK_AVAILABILITY
203 /* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be
204 * declared but it may be NULL at runtime. So we need to check before using
205 * it. */
206 static int
_civet_safe_clock_gettime(int clk_id,struct timespec * t)207 _civet_safe_clock_gettime(int clk_id, struct timespec *t)
208 {
209 if (clock_gettime) {
210 return clock_gettime(clk_id, t);
211 }
212 return _civet_clock_gettime(clk_id, t);
213 }
214 #define clock_gettime _civet_safe_clock_gettime
215 #else
216 #define clock_gettime _civet_clock_gettime
217 #endif
218
219 #endif
220
221
222 #include <time.h>
223 #include <stdlib.h>
224 #include <stdarg.h>
225 #include <assert.h>
226 #include <string.h>
227 #include <ctype.h>
228 #include <limits.h>
229 #include <stddef.h>
230 #include <stdio.h>
231 #include <stdint.h>
232
233 #ifndef INT64_MAX
234 #define INT64_MAX (9223372036854775807)
235 #endif
236
237
238 #ifndef MAX_WORKER_THREADS
239 #define MAX_WORKER_THREADS (1024 * 64)
240 #endif
241
242 #ifndef SOCKET_TIMEOUT_QUANTUM /* in ms */
243 #define SOCKET_TIMEOUT_QUANTUM (2000)
244 #endif
245
246 #define SHUTDOWN_RD (0)
247 #define SHUTDOWN_WR (1)
248 #define SHUTDOWN_BOTH (2)
249
250 mg_static_assert(MAX_WORKER_THREADS >= 1,
251 "worker threads must be a positive number");
252
253 mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8,
254 "size_t data type size check");
255
256 #if defined(_WIN32) \
257 && !defined(__SYMBIAN32__) /* WINDOWS / UNIX include block */
258 #include <windows.h>
259 #include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
260 #include <ws2tcpip.h>
261
262 typedef const char *SOCK_OPT_TYPE;
263
264 #if !defined(PATH_MAX)
265 #define PATH_MAX (MAX_PATH)
266 #endif
267
268 #if !defined(PATH_MAX)
269 #define PATH_MAX (4096)
270 #endif
271
272 mg_static_assert(PATH_MAX >= 1, "path length must be a positive number");
273
274 #ifndef _IN_PORT_T
275 #ifndef in_port_t
276 #define in_port_t u_short
277 #endif
278 #endif
279
280 #ifndef _WIN32_WCE
281 #include <process.h>
282 #include <direct.h>
283 #include <io.h>
284 #else /* _WIN32_WCE */
285 #define NO_CGI /* WinCE has no pipes */
286 #define NO_POPEN /* WinCE has no popen */
287
288 typedef long off_t;
289
290 #define errno ((int)(GetLastError()))
291 #define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
292 #endif /* _WIN32_WCE */
293
294 #define MAKEUQUAD(lo, hi) \
295 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
296 #define RATE_DIFF (10000000) /* 100 nsecs */
297 #define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
298 #define SYS2UNIX_TIME(lo, hi) \
299 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
300
301 /* Visual Studio 6 does not know __func__ or __FUNCTION__
302 * The rest of MS compilers use __FUNCTION__, not C99 __func__
303 * Also use _strtoui64 on modern M$ compilers */
304 #if defined(_MSC_VER)
305 #if (_MSC_VER < 1300)
306 #define STRX(x) #x
307 #define STR(x) STRX(x)
308 #define __func__ __FILE__ ":" STR(__LINE__)
309 #define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
310 #define strtoll(x, y, z) (_atoi64(x))
311 #else
312 #define __func__ __FUNCTION__
313 #define strtoull(x, y, z) (_strtoui64(x, y, z))
314 #define strtoll(x, y, z) (_strtoi64(x, y, z))
315 #endif
316 #endif /* _MSC_VER */
317
318 #define ERRNO ((int)(GetLastError()))
319 #define NO_SOCKLEN_T
320
321 #if defined(_WIN64) || defined(__MINGW64__)
322 #define SSL_LIB "ssleay64.dll"
323 #define CRYPTO_LIB "libeay64.dll"
324 #else
325 #define SSL_LIB "ssleay32.dll"
326 #define CRYPTO_LIB "libeay32.dll"
327 #endif
328
329 #define O_NONBLOCK (0)
330 #ifndef W_OK
331 #define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
332 #endif
333 #if !defined(EWOULDBLOCK)
334 #define EWOULDBLOCK WSAEWOULDBLOCK
335 #endif /* !EWOULDBLOCK */
336 #define _POSIX_
337 #define INT64_FMT "I64d"
338 #define UINT64_FMT "I64u"
339
340 #define WINCDECL __cdecl
341 #define vsnprintf_impl _vsnprintf
342 #define access _access
343 #define mg_sleep(x) (Sleep(x))
344
345 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
346 #ifndef popen
347 #define popen(x, y) (_popen(x, y))
348 #endif
349 #ifndef pclose
350 #define pclose(x) (_pclose(x))
351 #endif
352 #define close(x) (_close(x))
353 #define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
354 #define RTLD_LAZY (0)
355 #define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
356 #define fdopen(x, y) (_fdopen((x), (y)))
357 #define write(x, y, z) (_write((x), (y), (unsigned)z))
358 #define read(x, y, z) (_read((x), (y), (unsigned)z))
359 #define flockfile(x) (EnterCriticalSection(&global_log_file_lock))
360 #define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock))
361 #define sleep(x) (Sleep((x)*1000))
362 #define rmdir(x) (_rmdir(x))
363 #define timegm(x) (_mkgmtime(x))
364
365 #if !defined(fileno)
366 #define fileno(x) (_fileno(x))
367 #endif /* !fileno MINGW #defines fileno */
368
369 typedef HANDLE pthread_mutex_t;
370 typedef DWORD pthread_key_t;
371 typedef HANDLE pthread_t;
372 typedef struct {
373 CRITICAL_SECTION threadIdSec;
374 struct mg_workerTLS *waiting_thread; /* The chain of threads */
375 } pthread_cond_t;
376
377 #ifndef __clockid_t_defined
378 typedef DWORD clockid_t;
379 #endif
380 #ifndef CLOCK_MONOTONIC
381 #define CLOCK_MONOTONIC (1)
382 #endif
383 #ifndef CLOCK_REALTIME
384 #define CLOCK_REALTIME (2)
385 #endif
386
387 #if defined(_MSC_VER) && (_MSC_VER >= 1900)
388 #define _TIMESPEC_DEFINED
389 #endif
390 #ifndef _TIMESPEC_DEFINED
391 struct timespec {
392 time_t tv_sec; /* seconds */
393 long tv_nsec; /* nanoseconds */
394 };
395 #endif
396
397 #if !defined(WIN_PTHREADS_TIME_H)
398 #define MUST_IMPLEMENT_CLOCK_GETTIME
399 #endif
400
401 #ifdef MUST_IMPLEMENT_CLOCK_GETTIME
402 #define clock_gettime mg_clock_gettime
403 static int
clock_gettime(clockid_t clk_id,struct timespec * tp)404 clock_gettime(clockid_t clk_id, struct timespec *tp)
405 {
406 FILETIME ft;
407 ULARGE_INTEGER li;
408 BOOL ok = FALSE;
409 double d;
410 static double perfcnt_per_sec = 0.0;
411
412 if (tp) {
413 memset(tp, 0, sizeof(*tp));
414 if (clk_id == CLOCK_REALTIME) {
415 GetSystemTimeAsFileTime(&ft);
416 li.LowPart = ft.dwLowDateTime;
417 li.HighPart = ft.dwHighDateTime;
418 li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
419 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
420 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
421 ok = TRUE;
422 } else if (clk_id == CLOCK_MONOTONIC) {
423 if (perfcnt_per_sec == 0.0) {
424 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
425 perfcnt_per_sec = 1.0 / li.QuadPart;
426 }
427 if (perfcnt_per_sec != 0.0) {
428 QueryPerformanceCounter((LARGE_INTEGER *)&li);
429 d = li.QuadPart * perfcnt_per_sec;
430 tp->tv_sec = (time_t)d;
431 d -= tp->tv_sec;
432 tp->tv_nsec = (long)(d * 1.0E9);
433 ok = TRUE;
434 }
435 }
436 }
437
438 return ok ? 0 : -1;
439 }
440 #endif
441
442
443 #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
444
445 static int pthread_mutex_lock(pthread_mutex_t *);
446 static int pthread_mutex_unlock(pthread_mutex_t *);
447 static void path_to_unicode(const struct mg_connection *conn,
448 const char *path,
449 wchar_t *wbuf,
450 size_t wbuf_len);
451
452 /* All file operations need to be rewritten to solve #246. */
453
454 #include "file_ops.inl"
455
456 struct mg_file;
457
458 static const char *
459 mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p);
460
461
462 /* POSIX dirent interface */
463 struct dirent {
464 char d_name[PATH_MAX];
465 };
466
467 typedef struct DIR {
468 HANDLE handle;
469 WIN32_FIND_DATAW info;
470 struct dirent result;
471 } DIR;
472
473 #if defined(_WIN32) && !defined(POLLIN)
474 #ifndef HAVE_POLL
475 struct pollfd {
476 SOCKET fd;
477 short events;
478 short revents;
479 };
480 #define POLLIN (0x0300)
481 #endif
482 #endif
483
484 /* Mark required libraries */
485 #if defined(_MSC_VER)
486 #pragma comment(lib, "Ws2_32.lib")
487 #endif
488
489 #else /* defined(_WIN32) && !defined(__SYMBIAN32__) - \
490 WINDOWS / UNIX include block */
491
492 #include <sys/wait.h>
493 #include <sys/socket.h>
494 #include <sys/poll.h>
495 #include <netinet/in.h>
496 #include <arpa/inet.h>
497 #include <sys/time.h>
498 #include <sys/utsname.h>
499 #include <stdint.h>
500 #include <inttypes.h>
501 #include <netdb.h>
502 #include <netinet/tcp.h>
503 typedef const void *SOCK_OPT_TYPE;
504
505 #if defined(ANDROID)
506 typedef unsigned short int in_port_t;
507 #endif
508
509 #include <pwd.h>
510 #include <unistd.h>
511 #include <grp.h>
512 #include <dirent.h>
513 #define vsnprintf_impl vsnprintf
514
515 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
516 #include <dlfcn.h>
517 #endif
518 #include <pthread.h>
519 #if defined(__MACH__)
520 #define SSL_LIB "libssl.dylib"
521 #define CRYPTO_LIB "libcrypto.dylib"
522 #else
523 #if !defined(SSL_LIB)
524 #define SSL_LIB "libssl.so"
525 #endif
526 #if !defined(CRYPTO_LIB)
527 #define CRYPTO_LIB "libcrypto.so"
528 #endif
529 #endif
530 #ifndef O_BINARY
531 #define O_BINARY (0)
532 #endif /* O_BINARY */
533 #define closesocket(a) (close(a))
534 #define mg_mkdir(conn, path, mode) (mkdir(path, mode))
535 #define mg_remove(conn, x) (remove(x))
536 #define mg_sleep(x) (usleep((x)*1000))
537 #define mg_opendir(conn, x) (opendir(x))
538 #define mg_closedir(x) (closedir(x))
539 #define mg_readdir(x) (readdir(x))
540 #define ERRNO (errno)
541 #define INVALID_SOCKET (-1)
542 #define INT64_FMT PRId64
543 #define UINT64_FMT PRIu64
544 typedef int SOCKET;
545 #define WINCDECL
546
547 #if defined(__hpux)
548 /* HPUX 11 does not have monotonic, fall back to realtime */
549 #ifndef CLOCK_MONOTONIC
550 #define CLOCK_MONOTONIC CLOCK_REALTIME
551 #endif
552
553 /* HPUX defines socklen_t incorrectly as size_t which is 64bit on
554 * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
555 * the prototypes use int* rather than socklen_t* which matches the
556 * actual library expectation. When called with the wrong size arg
557 * accept() returns a zero client inet addr and check_acl() always
558 * fails. Since socklen_t is widely used below, just force replace
559 * their typedef with int. - DTL
560 */
561 #define socklen_t int
562 #endif /* hpux */
563
564 #endif /* defined(_WIN32) && !defined(__SYMBIAN32__) - \
565 WINDOWS / UNIX include block */
566
567 /* va_copy should always be a macro, C99 and C++11 - DTL */
568 #ifndef va_copy
569 #define va_copy(x, y) ((x) = (y))
570 #endif
571
572 #ifdef _WIN32
573 /* Create substitutes for POSIX functions in Win32. */
574
575 #if defined(__MINGW32__)
576 /* Show no warning in case system functions are not used. */
577 #pragma GCC diagnostic push
578 #pragma GCC diagnostic ignored "-Wunused-function"
579 #endif
580
581
582 static CRITICAL_SECTION global_log_file_lock;
583 static DWORD
pthread_self(void)584 pthread_self(void)
585 {
586 return GetCurrentThreadId();
587 }
588
589
590 static int
pthread_key_create(pthread_key_t * key,void (* _ignored)(void *))591 pthread_key_create(
592 pthread_key_t *key,
593 void (*_ignored)(void *) /* destructor not supported for Windows */
594 )
595 {
596 (void)_ignored;
597
598 if ((key != 0)) {
599 *key = TlsAlloc();
600 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
601 }
602 return -2;
603 }
604
605
606 static int
pthread_key_delete(pthread_key_t key)607 pthread_key_delete(pthread_key_t key)
608 {
609 return TlsFree(key) ? 0 : 1;
610 }
611
612
613 static int
pthread_setspecific(pthread_key_t key,void * value)614 pthread_setspecific(pthread_key_t key, void *value)
615 {
616 return TlsSetValue(key, value) ? 0 : 1;
617 }
618
619
620 static void *
pthread_getspecific(pthread_key_t key)621 pthread_getspecific(pthread_key_t key)
622 {
623 return TlsGetValue(key);
624 }
625
626 #if defined(__MINGW32__)
627 /* Enable unused function warning again */
628 #pragma GCC diagnostic pop
629 #endif
630
631 static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL;
632 #else
633 static pthread_mutexattr_t pthread_mutex_attr;
634 #endif /* _WIN32 */
635
636
637 #define PASSWORDS_FILE_NAME ".htpasswd"
638 #define CGI_ENVIRONMENT_SIZE (4096)
639 #define MAX_CGI_ENVIR_VARS (256)
640 #define MG_BUF_LEN (8192)
641
642 #ifndef MAX_REQUEST_SIZE
643 #define MAX_REQUEST_SIZE (16384)
644 #endif
645
646 mg_static_assert(MAX_REQUEST_SIZE >= 256,
647 "request size length must be a positive number");
648
649 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
650
651
652 #if defined(_WIN32_WCE)
653 /* Create substitutes for POSIX functions in Win32. */
654
655 #if defined(__MINGW32__)
656 /* Show no warning in case system functions are not used. */
657 #pragma GCC diagnostic push
658 #pragma GCC diagnostic ignored "-Wunused-function"
659 #endif
660
661
662 static time_t
time(time_t * ptime)663 time(time_t *ptime)
664 {
665 time_t t;
666 SYSTEMTIME st;
667 FILETIME ft;
668
669 GetSystemTime(&st);
670 SystemTimeToFileTime(&st, &ft);
671 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
672
673 if (ptime != NULL) {
674 *ptime = t;
675 }
676
677 return t;
678 }
679
680
681 static struct tm *
localtime_s(const time_t * ptime,struct tm * ptm)682 localtime_s(const time_t *ptime, struct tm *ptm)
683 {
684 int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
685 FILETIME ft, lft;
686 SYSTEMTIME st;
687 TIME_ZONE_INFORMATION tzinfo;
688
689 if (ptm == NULL) {
690 return NULL;
691 }
692
693 *(int64_t *)&ft = t;
694 FileTimeToLocalFileTime(&ft, &lft);
695 FileTimeToSystemTime(&lft, &st);
696 ptm->tm_year = st.wYear - 1900;
697 ptm->tm_mon = st.wMonth - 1;
698 ptm->tm_wday = st.wDayOfWeek;
699 ptm->tm_mday = st.wDay;
700 ptm->tm_hour = st.wHour;
701 ptm->tm_min = st.wMinute;
702 ptm->tm_sec = st.wSecond;
703 ptm->tm_yday = 0; /* hope nobody uses this */
704 ptm->tm_isdst =
705 (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0;
706
707 return ptm;
708 }
709
710
711 static struct tm *
gmtime_s(const time_t * ptime,struct tm * ptm)712 gmtime_s(const time_t *ptime, struct tm *ptm)
713 {
714 /* FIXME(lsm): fix this. */
715 return localtime_s(ptime, ptm);
716 }
717
718 static int mg_atomic_inc(volatile int *addr);
719 static struct tm tm_array[MAX_WORKER_THREADS];
720 static int tm_index = 0;
721
722 static struct tm *
localtime(const time_t * ptime)723 localtime(const time_t *ptime)
724 {
725 int i = mg_atomic_inc(&tm_index) % (sizeof(tm_array) / sizeof(tm_array[0]));
726 return localtime_s(ptime, tm_array + i);
727 }
728
729
730 static struct tm *
gmtime(const time_t * ptime)731 gmtime(const time_t *ptime)
732 {
733 int i = mg_atomic_inc(&tm_index) % ARRAY_SIZE(tm_array);
734 return gmtime_s(ptime, tm_array + i);
735 }
736
737
738 static size_t
strftime(char * dst,size_t dst_size,const char * fmt,const struct tm * tm)739 strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm)
740 {
741 /* TODO */ //(void)mg_snprintf(NULL, dst, dst_size, "implement strftime()
742 // for WinCE");
743 return 0;
744 }
745
746 #define _beginthreadex(psec, stack, func, prm, flags, ptid) \
747 (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid)
748
749 #define remove(f) mg_remove(NULL, f)
750
751 static int
rename(const char * a,const char * b)752 rename(const char *a, const char *b)
753 {
754 wchar_t wa[PATH_MAX];
755 wchar_t wb[PATH_MAX];
756 path_to_unicode(NULL, a, wa, ARRAY_SIZE(wa));
757 path_to_unicode(NULL, b, wb, ARRAY_SIZE(wb));
758
759 return MoveFileW(wa, wb) ? 0 : -1;
760 }
761
762 struct stat {
763 int64_t st_size;
764 time_t st_mtime;
765 };
766
767 static int
stat(const char * name,struct stat * st)768 stat(const char *name, struct stat *st)
769 {
770 wchar_t wbuf[PATH_MAX];
771 WIN32_FILE_ATTRIBUTE_DATA attr;
772 time_t creation_time, write_time;
773
774 path_to_unicode(NULL, name, wbuf, ARRAY_SIZE(wbuf));
775 memset(&attr, 0, sizeof(attr));
776
777 GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr);
778 st->st_size =
779 (((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow;
780
781 write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime,
782 attr.ftLastWriteTime.dwHighDateTime);
783 creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime,
784 attr.ftCreationTime.dwHighDateTime);
785
786 if (creation_time > write_time) {
787 st->st_mtime = creation_time;
788 } else {
789 st->st_mtime = write_time;
790 }
791 return 0;
792 }
793
794 #define access(x, a) 1 /* not required anyway */
795
796 /* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */
797 #define EEXIST 1 /* TODO: See Windows error codes */
798 #define EACCES 2 /* TODO: See Windows error codes */
799 #define ENOENT 3 /* TODO: See Windows Error codes */
800
801 #if defined(__MINGW32__)
802 /* Enable unused function warning again */
803 #pragma GCC diagnostic pop
804 #endif
805
806 #endif /* defined(_WIN32_WCE) */
807
808
809 #if !defined(DEBUG_TRACE)
810 #if defined(DEBUG)
811 static void DEBUG_TRACE_FUNC(const char *func,
812 unsigned line,
813 PRINTF_FORMAT_STRING(const char *fmt),
814 ...) PRINTF_ARGS(3, 4);
815
816 static void
DEBUG_TRACE_FUNC(const char * func,unsigned line,const char * fmt,...)817 DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
818 {
819 va_list args;
820 struct timespec tsnow;
821 uint64_t nsnow;
822 static uint64_t nslast;
823
824 clock_gettime(CLOCK_REALTIME, &tsnow);
825 nsnow = (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
826
827 flockfile(stdout);
828 printf("*** %lu.%09lu %12" INT64_FMT " %p %s:%u: ",
829 (unsigned long)tsnow.tv_sec,
830 (unsigned long)tsnow.tv_nsec,
831 nsnow - nslast,
832 (void *)pthread_self(),
833 func,
834 line);
835 va_start(args, fmt);
836 vprintf(fmt, args);
837 va_end(args);
838 putchar('\n');
839 fflush(stdout);
840 funlockfile(stdout);
841 nslast = nsnow;
842 }
843
844 #define DEBUG_TRACE(fmt, ...) \
845 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
846
847 #else
848 #define DEBUG_TRACE(fmt, ...) \
849 do { \
850 } while (0)
851 #endif /* DEBUG */
852 #endif /* DEBUG_TRACE */
853
854
855 #if defined(MEMORY_DEBUGGING)
856 static unsigned long mg_memory_debug_blockCount = 0;
857 static unsigned long mg_memory_debug_totalMemUsed = 0;
858
859
860 static void *
mg_malloc_ex(size_t size,const char * file,unsigned line)861 mg_malloc_ex(size_t size, const char *file, unsigned line)
862 {
863 void *data = malloc(size + sizeof(size_t));
864 void *memory = 0;
865 char mallocStr[256];
866
867 if (data) {
868 *(size_t *)data = size;
869 mg_memory_debug_totalMemUsed += size;
870 mg_memory_debug_blockCount++;
871 memory = (void *)(((char *)data) + sizeof(size_t));
872 }
873
874 sprintf(mallocStr,
875 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
876 memory,
877 (unsigned long)size,
878 mg_memory_debug_totalMemUsed,
879 mg_memory_debug_blockCount,
880 file,
881 line);
882 #if defined(_WIN32)
883 OutputDebugStringA(mallocStr);
884 #else
885 DEBUG_TRACE("%s", mallocStr);
886 #endif
887
888 return memory;
889 }
890
891
892 static void *
mg_calloc_ex(size_t count,size_t size,const char * file,unsigned line)893 mg_calloc_ex(size_t count, size_t size, const char *file, unsigned line)
894 {
895 void *data = mg_malloc_ex(size * count, file, line);
896 if (data) {
897 memset(data, 0, size * count);
898 }
899 return data;
900 }
901
902
903 static void
mg_free_ex(void * memory,const char * file,unsigned line)904 mg_free_ex(void *memory, const char *file, unsigned line)
905 {
906 char mallocStr[256];
907 void *data = (void *)(((char *)memory) - sizeof(size_t));
908 size_t size;
909
910 if (memory) {
911 size = *(size_t *)data;
912 mg_memory_debug_totalMemUsed -= size;
913 mg_memory_debug_blockCount--;
914 sprintf(mallocStr,
915 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
916 memory,
917 (unsigned long)size,
918 mg_memory_debug_totalMemUsed,
919 mg_memory_debug_blockCount,
920 file,
921 line);
922 #if defined(_WIN32)
923 OutputDebugStringA(mallocStr);
924 #else
925 DEBUG_TRACE("%s", mallocStr);
926 #endif
927
928 free(data);
929 }
930 }
931
932
933 static void *
mg_realloc_ex(void * memory,size_t newsize,const char * file,unsigned line)934 mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line)
935 {
936 char mallocStr[256];
937 void *data;
938 void *_realloc;
939 size_t oldsize;
940
941 if (newsize) {
942 if (memory) {
943 data = (void *)(((char *)memory) - sizeof(size_t));
944 oldsize = *(size_t *)data;
945 _realloc = realloc(data, newsize + sizeof(size_t));
946 if (_realloc) {
947 data = _realloc;
948 mg_memory_debug_totalMemUsed -= oldsize;
949 sprintf(mallocStr,
950 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
951 memory,
952 (unsigned long)oldsize,
953 mg_memory_debug_totalMemUsed,
954 mg_memory_debug_blockCount,
955 file,
956 line);
957 #if defined(_WIN32)
958 OutputDebugStringA(mallocStr);
959 #else
960 DEBUG_TRACE("%s", mallocStr);
961 #endif
962 mg_memory_debug_totalMemUsed += newsize;
963 sprintf(mallocStr,
964 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
965 memory,
966 (unsigned long)newsize,
967 mg_memory_debug_totalMemUsed,
968 mg_memory_debug_blockCount,
969 file,
970 line);
971 #if defined(_WIN32)
972 OutputDebugStringA(mallocStr);
973 #else
974 DEBUG_TRACE("%s", mallocStr);
975 #endif
976 *(size_t *)data = newsize;
977 data = (void *)(((char *)data) + sizeof(size_t));
978 } else {
979 #if defined(_WIN32)
980 OutputDebugStringA("MEM: realloc failed\n");
981 #else
982 DEBUG_TRACE("%s", "MEM: realloc failed\n");
983 #endif
984 return _realloc;
985 }
986 } else {
987 data = mg_malloc_ex(newsize, file, line);
988 }
989 } else {
990 data = 0;
991 mg_free_ex(memory, file, line);
992 }
993
994 return data;
995 }
996
997 #define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__)
998 #define mg_calloc(a, b) mg_calloc_ex(a, b, __FILE__, __LINE__)
999 #define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__)
1000 #define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1001
1002 #else
1003
1004 static __inline void *
mg_malloc(size_t a)1005 mg_malloc(size_t a)
1006 {
1007 return malloc(a);
1008 }
1009
1010 static __inline void *
mg_calloc(size_t a,size_t b)1011 mg_calloc(size_t a, size_t b)
1012 {
1013 return calloc(a, b);
1014 }
1015
1016 static __inline void *
mg_realloc(void * a,size_t b)1017 mg_realloc(void *a, size_t b)
1018 {
1019 return realloc(a, b);
1020 }
1021
1022 static __inline void
mg_free(void * a)1023 mg_free(void *a)
1024 {
1025 free(a);
1026 }
1027
1028 #endif
1029
1030
1031 static void mg_vsnprintf(const struct mg_connection *conn,
1032 int *truncated,
1033 char *buf,
1034 size_t buflen,
1035 const char *fmt,
1036 va_list ap);
1037
1038 static void mg_snprintf(const struct mg_connection *conn,
1039 int *truncated,
1040 char *buf,
1041 size_t buflen,
1042 PRINTF_FORMAT_STRING(const char *fmt),
1043 ...) PRINTF_ARGS(5, 6);
1044
1045 /* This following lines are just meant as a reminder to use the mg-functions
1046 * for memory management */
1047 #ifdef malloc
1048 #undef malloc
1049 #endif
1050 #ifdef calloc
1051 #undef calloc
1052 #endif
1053 #ifdef realloc
1054 #undef realloc
1055 #endif
1056 #ifdef free
1057 #undef free
1058 #endif
1059 #ifdef snprintf
1060 #undef snprintf
1061 #endif
1062 #ifdef vsnprintf
1063 #undef vsnprintf
1064 #endif
1065 #define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1066 #define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1067 #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1068 #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1069 #define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
1070 #ifdef _WIN32 /* vsnprintf must not be used in any system, * \ \ \ \
1071 * but this define only works well for Windows. */
1072 #define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1073 #endif
1074
1075 #define MD5_STATIC static
1076 #include "md5.inl"
1077
1078 /* Darwin prior to 7.0 and Win32 do not have socklen_t */
1079 #ifdef NO_SOCKLEN_T
1080 typedef int socklen_t;
1081 #endif /* NO_SOCKLEN_T */
1082 #define _DARWIN_UNLIMITED_SELECT
1083
1084 #define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
1085
1086 #if !defined(MSG_NOSIGNAL)
1087 #define MSG_NOSIGNAL (0)
1088 #endif
1089
1090 #if !defined(SOMAXCONN)
1091 #define SOMAXCONN (100)
1092 #endif
1093
1094 /* Size of the accepted socket queue */
1095 #if !defined(MGSQLEN)
1096 #define MGSQLEN (20)
1097 #endif
1098
1099
1100 #if defined(NO_SSL)
1101 typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
1102 typedef struct SSL_CTX SSL_CTX;
1103 #else
1104 #if defined(NO_SSL_DL)
1105 #include <openssl/ssl.h>
1106 #include <openssl/err.h>
1107 #include <openssl/crypto.h>
1108 #include <openssl/x509.h>
1109 #include <openssl/pem.h>
1110 #include <openssl/engine.h>
1111 #include <openssl/conf.h>
1112 #include <openssl/dh.h>
1113 #else
1114 /* SSL loaded dynamically from DLL.
1115 * I put the prototypes here to be independent from OpenSSL source
1116 * installation. */
1117
1118 typedef struct ssl_st SSL;
1119 typedef struct ssl_method_st SSL_METHOD;
1120 typedef struct ssl_ctx_st SSL_CTX;
1121 typedef struct x509_store_ctx_st X509_STORE_CTX;
1122 typedef struct x509_name X509_NAME;
1123 typedef struct asn1_integer ASN1_INTEGER;
1124 typedef struct evp_md EVP_MD;
1125 typedef struct x509 X509;
1126
1127
1128 #define SSL_CTRL_OPTIONS (32)
1129 #define SSL_CTRL_CLEAR_OPTIONS (77)
1130 #define SSL_CTRL_SET_ECDH_AUTO (94)
1131
1132 #define SSL_VERIFY_NONE (0)
1133 #define SSL_VERIFY_PEER (1)
1134 #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
1135 #define SSL_VERIFY_CLIENT_ONCE (4)
1136 #define SSL_OP_ALL ((long)(0x80000BFFUL))
1137 #define SSL_OP_NO_SSLv2 (0x01000000L)
1138 #define SSL_OP_NO_SSLv3 (0x02000000L)
1139 #define SSL_OP_NO_TLSv1 (0x04000000L)
1140 #define SSL_OP_NO_TLSv1_2 (0x08000000L)
1141 #define SSL_OP_NO_TLSv1_1 (0x10000000L)
1142 #define SSL_OP_SINGLE_DH_USE (0x00100000L)
1143 #define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L)
1144 #define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L)
1145
1146 #define SSL_ERROR_NONE (0)
1147 #define SSL_ERROR_SSL (1)
1148 #define SSL_ERROR_WANT_READ (2)
1149 #define SSL_ERROR_WANT_WRITE (3)
1150 #define SSL_ERROR_WANT_X509_LOOKUP (4)
1151 #define SSL_ERROR_SYSCALL (5) /* see errno */
1152 #define SSL_ERROR_ZERO_RETURN (6)
1153 #define SSL_ERROR_WANT_CONNECT (7)
1154 #define SSL_ERROR_WANT_ACCEPT (8)
1155
1156
1157 struct ssl_func {
1158 const char *name; /* SSL function name */
1159 void (*ptr)(void); /* Function pointer */
1160 };
1161
1162 #define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
1163 #define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
1164 #define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
1165 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
1166 #define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
1167 #define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
1168 #define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
1169 #define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr)
1170 #define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr)
1171 #define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr)
1172 #define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
1173 #define SSL_CTX_use_PrivateKey_file \
1174 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
1175 #define SSL_CTX_use_certificate_file \
1176 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
1177 #define SSL_CTX_set_default_passwd_cb \
1178 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
1179 #define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
1180 #define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
1181 #define SSL_CTX_use_certificate_chain_file \
1182 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
1183 #define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr)
1184 #define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
1185 #define SSL_CTX_set_verify \
1186 (*(void (*)(SSL_CTX *, \
1187 int, \
1188 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr)
1189 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
1190 #define SSL_CTX_load_verify_locations \
1191 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
1192 #define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
1193 #define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
1194 #define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr)
1195 #define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
1196 #define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr)
1197 #define SSL_CIPHER_get_name \
1198 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
1199 #define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
1200 #define SSL_CTX_set_session_id_context \
1201 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
1202 #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
1203
1204
1205 #define SSL_CTX_set_cipher_list \
1206 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
1207 #define SSL_CTX_set_options(ctx, op) \
1208 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
1209 #define SSL_CTX_clear_options(ctx, op) \
1210 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
1211 #define SSL_CTX_set_ecdh_auto(ctx, onoff) \
1212 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
1213
1214 #define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
1215 #define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
1216
1217
1218 #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
1219 #define CRYPTO_set_locking_callback \
1220 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
1221 #define CRYPTO_set_id_callback \
1222 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
1223 #define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
1224 #define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
1225 #define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
1226 #define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
1227 #define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
1228 #define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
1229 #define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
1230 #define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
1231 #define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr)
1232 #define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[12].ptr)
1233 #define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[13].ptr)
1234 #define X509_NAME_oneline \
1235 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
1236 #define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr)
1237 #define i2c_ASN1_INTEGER \
1238 (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
1239 #define EVP_get_digestbyname \
1240 (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
1241 #define ASN1_digest \
1242 (*(int (*)(int (*)(), \
1243 const EVP_MD *, \
1244 char *, \
1245 unsigned char *, \
1246 unsigned int *))crypto_sw[18].ptr)
1247 #define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
1248
1249
1250 /* set_ssl_option() function updates this array.
1251 * It loads SSL library dynamically and changes NULLs to the actual addresses
1252 * of respective functions. The macros above (like SSL_connect()) are really
1253 * just calling these functions indirectly via the pointer. */
1254 static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
1255 {"SSL_accept", NULL},
1256 {"SSL_connect", NULL},
1257 {"SSL_read", NULL},
1258 {"SSL_write", NULL},
1259 {"SSL_get_error", NULL},
1260 {"SSL_set_fd", NULL},
1261 {"SSL_new", NULL},
1262 {"SSL_CTX_new", NULL},
1263 {"SSLv23_server_method", NULL},
1264 {"SSL_library_init", NULL},
1265 {"SSL_CTX_use_PrivateKey_file", NULL},
1266 {"SSL_CTX_use_certificate_file", NULL},
1267 {"SSL_CTX_set_default_passwd_cb", NULL},
1268 {"SSL_CTX_free", NULL},
1269 {"SSL_load_error_strings", NULL},
1270 {"SSL_CTX_use_certificate_chain_file", NULL},
1271 {"SSLv23_client_method", NULL},
1272 {"SSL_pending", NULL},
1273 {"SSL_CTX_set_verify", NULL},
1274 {"SSL_shutdown", NULL},
1275 {"SSL_CTX_load_verify_locations", NULL},
1276 {"SSL_CTX_set_default_verify_paths", NULL},
1277 {"SSL_CTX_set_verify_depth", NULL},
1278 {"SSL_get_peer_certificate", NULL},
1279 {"SSL_get_version", NULL},
1280 {"SSL_get_current_cipher", NULL},
1281 {"SSL_CIPHER_get_name", NULL},
1282 {"SSL_CTX_check_private_key", NULL},
1283 {"SSL_CTX_set_session_id_context", NULL},
1284 {"SSL_CTX_ctrl", NULL},
1285 {"SSL_CTX_set_cipher_list", NULL},
1286 {NULL, NULL}};
1287
1288
1289 /* Similar array as ssl_sw. These functions could be located in different
1290 * lib. */
1291 static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
1292 {"CRYPTO_set_locking_callback", NULL},
1293 {"CRYPTO_set_id_callback", NULL},
1294 {"ERR_get_error", NULL},
1295 {"ERR_error_string", NULL},
1296 {"ERR_remove_state", NULL},
1297 {"ERR_free_strings", NULL},
1298 {"ENGINE_cleanup", NULL},
1299 {"CONF_modules_unload", NULL},
1300 {"CRYPTO_cleanup_all_ex_data", NULL},
1301 {"EVP_cleanup", NULL},
1302 {"X509_free", NULL},
1303 {"X509_get_subject_name", NULL},
1304 {"X509_get_issuer_name", NULL},
1305 {"X509_NAME_oneline", NULL},
1306 {"X509_get_serialNumber", NULL},
1307 {"i2c_ASN1_INTEGER", NULL},
1308 {"EVP_get_digestbyname", NULL},
1309 {"ASN1_digest", NULL},
1310 {"i2d_X509", NULL},
1311 {NULL, NULL}};
1312 #endif /* NO_SSL_DL */
1313 #endif /* NO_SSL */
1314
1315
1316 #if !defined(NO_CACHING)
1317 static const char *month_names[] = {"Jan",
1318 "Feb",
1319 "Mar",
1320 "Apr",
1321 "May",
1322 "Jun",
1323 "Jul",
1324 "Aug",
1325 "Sep",
1326 "Oct",
1327 "Nov",
1328 "Dec"};
1329 #endif /* !NO_CACHING */
1330
1331 /* Unified socket address. For IPv6 support, add IPv6 address structure in the
1332 * union u. */
1333 union usa {
1334 struct sockaddr sa;
1335 struct sockaddr_in sin;
1336 #if defined(USE_IPV6)
1337 struct sockaddr_in6 sin6;
1338 #endif
1339 };
1340
1341 /* Describes a string (chunk of memory). */
1342 struct vec {
1343 const char *ptr;
1344 size_t len;
1345 };
1346
1347 struct mg_file_stat {
1348 /* File properties filled by mg_stat: */
1349 uint64_t size;
1350 time_t last_modified;
1351 int is_directory; /* Set to 1 if mg_stat is called for a directory */
1352 int is_gzipped; /* Set to 1 if the content is gzipped, in which
1353 * case we need a "Content-Eencoding: gzip" header */
1354 int location; /* 0 = nowhere, 1 = on disk, 2 = in memory */
1355 };
1356
1357 struct mg_file_in_memory {
1358 char *p;
1359 uint32_t pos;
1360 char mode;
1361 };
1362
1363 struct mg_file_access {
1364 /* File properties filled by mg_fopen: */
1365 FILE *fp;
1366 /* TODO: struct mg_file_in_memory *mf; */
1367 const char *membuf; /* TODO: remove */
1368 };
1369
1370 struct mg_file {
1371 struct mg_file_stat stat;
1372 struct mg_file_access access;
1373 };
1374
1375 #define STRUCT_FILE_INITIALIZER \
1376 { \
1377 { \
1378 (uint64_t)0, (time_t)0, 0, 0, 0 \
1379 } \
1380 , \
1381 { \
1382 (FILE *) NULL, (const char *)NULL \
1383 } \
1384 }
1385
1386 /* Describes listening socket, or socket which was accept()-ed by the master
1387 * thread and queued for future handling by the worker thread. */
1388 struct socket {
1389 SOCKET sock; /* Listening socket */
1390 union usa lsa; /* Local socket address */
1391 union usa rsa; /* Remote socket address */
1392 unsigned char is_ssl; /* Is port SSL-ed */
1393 unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
1394 * port */
1395 unsigned char in_use; /* Is valid */
1396 };
1397
1398 /* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
1399 enum {
1400 CGI_EXTENSIONS,
1401 CGI_ENVIRONMENT,
1402 PUT_DELETE_PASSWORDS_FILE,
1403 CGI_INTERPRETER,
1404 PROTECT_URI,
1405 AUTHENTICATION_DOMAIN,
1406 SSI_EXTENSIONS,
1407 THROTTLE,
1408 ACCESS_LOG_FILE,
1409 ENABLE_DIRECTORY_LISTING,
1410 ERROR_LOG_FILE,
1411 GLOBAL_PASSWORDS_FILE,
1412 INDEX_FILES,
1413 ENABLE_KEEP_ALIVE,
1414 ACCESS_CONTROL_LIST,
1415 EXTRA_MIME_TYPES,
1416 LISTENING_PORTS,
1417 DOCUMENT_ROOT,
1418 SSL_CERTIFICATE,
1419 NUM_THREADS,
1420 RUN_AS_USER,
1421 REWRITE,
1422 HIDE_FILES,
1423 REQUEST_TIMEOUT,
1424 KEEP_ALIVE_TIMEOUT,
1425 SSL_DO_VERIFY_PEER,
1426 SSL_CA_PATH,
1427 SSL_CA_FILE,
1428 SSL_VERIFY_DEPTH,
1429 SSL_DEFAULT_VERIFY_PATHS,
1430 SSL_CIPHER_LIST,
1431 SSL_PROTOCOL_VERSION,
1432 SSL_SHORT_TRUST,
1433
1434 #if defined(USE_WEBSOCKET)
1435 WEBSOCKET_TIMEOUT,
1436 #endif
1437
1438 DECODE_URL,
1439
1440 #if defined(USE_LUA)
1441 LUA_PRELOAD_FILE,
1442 LUA_SCRIPT_EXTENSIONS,
1443 LUA_SERVER_PAGE_EXTENSIONS,
1444 #endif
1445 #if defined(USE_DUKTAPE)
1446 DUKTAPE_SCRIPT_EXTENSIONS,
1447 #endif
1448
1449 #if defined(USE_WEBSOCKET)
1450 WEBSOCKET_ROOT,
1451 #endif
1452 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1453 LUA_WEBSOCKET_EXTENSIONS,
1454 #endif
1455
1456 ACCESS_CONTROL_ALLOW_ORIGIN,
1457 ERROR_PAGES,
1458 CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the
1459 * socket option typedef TCP_NODELAY. */
1460 #if !defined(NO_CACHING)
1461 STATIC_FILE_MAX_AGE,
1462 #endif
1463 #if defined(__linux__)
1464 ALLOW_SENDFILE_CALL,
1465 #endif
1466 #if defined(_WIN32)
1467 CASE_SENSITIVE_FILES,
1468 #endif
1469
1470 NUM_OPTIONS
1471 };
1472
1473
1474 /* Config option name, config types, default value */
1475 static struct mg_option config_options[] = {
1476 {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
1477 {"cgi_environment", CONFIG_TYPE_STRING, NULL},
1478 {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL},
1479 {"cgi_interpreter", CONFIG_TYPE_FILE, NULL},
1480 {"protect_uri", CONFIG_TYPE_STRING, NULL},
1481 {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"},
1482 {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"},
1483 {"throttle", CONFIG_TYPE_STRING, NULL},
1484 {"access_log_file", CONFIG_TYPE_FILE, NULL},
1485 {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"},
1486 {"error_log_file", CONFIG_TYPE_FILE, NULL},
1487 {"global_auth_file", CONFIG_TYPE_FILE, NULL},
1488 {"index_files",
1489 CONFIG_TYPE_STRING,
1490 #ifdef USE_LUA
1491 "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,"
1492 "index.shtml,index.php"},
1493 #else
1494 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
1495 #endif
1496 {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"},
1497 {"access_control_list", CONFIG_TYPE_STRING, NULL},
1498 {"extra_mime_types", CONFIG_TYPE_STRING, NULL},
1499 {"listening_ports", CONFIG_TYPE_STRING, "8080"},
1500 {"document_root", CONFIG_TYPE_DIRECTORY, NULL},
1501 {"ssl_certificate", CONFIG_TYPE_FILE, NULL},
1502 {"num_threads", CONFIG_TYPE_NUMBER, "50"},
1503 {"run_as_user", CONFIG_TYPE_STRING, NULL},
1504 {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL},
1505 {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL},
1506 {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
1507 {"keep_alive_timeout_ms", CONFIG_TYPE_NUMBER, "500"},
1508 {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN, "no"},
1509 {"ssl_ca_path", CONFIG_TYPE_DIRECTORY, NULL},
1510 {"ssl_ca_file", CONFIG_TYPE_FILE, NULL},
1511 {"ssl_verify_depth", CONFIG_TYPE_NUMBER, "9"},
1512 {"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN, "yes"},
1513 {"ssl_cipher_list", CONFIG_TYPE_STRING, NULL},
1514 {"ssl_protocol_version", CONFIG_TYPE_NUMBER, "0"},
1515 {"ssl_short_trust", CONFIG_TYPE_BOOLEAN, "no"},
1516 #if defined(USE_WEBSOCKET)
1517 {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
1518 #endif
1519 {"decode_url", CONFIG_TYPE_BOOLEAN, "yes"},
1520
1521 #if defined(USE_LUA)
1522 {"lua_preload_file", CONFIG_TYPE_FILE, NULL},
1523 {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
1524 {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"},
1525 #endif
1526 #if defined(USE_DUKTAPE)
1527 /* The support for duktape is still in alpha version state.
1528 * The name of this config option might change. */
1529 {"duktape_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"},
1530 #endif
1531
1532 #if defined(USE_WEBSOCKET)
1533 {"websocket_root", CONFIG_TYPE_DIRECTORY, NULL},
1534 #endif
1535 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1536 {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
1537 #endif
1538 {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"},
1539 {"error_pages", CONFIG_TYPE_DIRECTORY, NULL},
1540 {"tcp_nodelay", CONFIG_TYPE_NUMBER, "0"},
1541 #if !defined(NO_CACHING)
1542 {"static_file_max_age", CONFIG_TYPE_NUMBER, "3600"},
1543 #endif
1544 #if defined(__linux__)
1545 {"allow_sendfile_call", CONFIG_TYPE_BOOLEAN, "yes"},
1546 #endif
1547 #if defined(_WIN32)
1548 {"case_sensitive", CONFIG_TYPE_BOOLEAN, "no"},
1549 #endif
1550
1551 {NULL, CONFIG_TYPE_UNKNOWN, NULL}};
1552
1553 /* Check if the config_options and the corresponding enum have compatible
1554 * sizes. */
1555 mg_static_assert((sizeof(config_options) / sizeof(config_options[0]))
1556 == (NUM_OPTIONS + 1),
1557 "config_options and enum not sync");
1558
1559 enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER };
1560
1561 struct mg_handler_info {
1562 /* Name/Pattern of the URI. */
1563 char *uri;
1564 size_t uri_len;
1565
1566 /* handler type */
1567 int handler_type;
1568
1569 /* Handler for http/https or authorization requests. */
1570 mg_request_handler handler;
1571
1572 /* Handler for ws/wss (websocket) requests. */
1573 mg_websocket_connect_handler connect_handler;
1574 mg_websocket_ready_handler ready_handler;
1575 mg_websocket_data_handler data_handler;
1576 mg_websocket_close_handler close_handler;
1577
1578 /* accepted subprotocols for ws/wss requests. */
1579 struct mg_websocket_subprotocols *subprotocols;
1580
1581 /* Handler for authorization requests */
1582 mg_authorization_handler auth_handler;
1583
1584 /* User supplied argument for the handler function. */
1585 void *cbdata;
1586
1587 /* next handler in a linked list */
1588 struct mg_handler_info *next;
1589 };
1590
1591 struct mg_context {
1592 volatile int stop_flag; /* Should we stop event loop */
1593 SSL_CTX *ssl_ctx; /* SSL context */
1594 char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
1595 struct mg_callbacks callbacks; /* User-defined callback function */
1596 void *user_data; /* User-defined data */
1597 int context_type; /* 1 = server context,
1598 * 2 = ws/wss client context,
1599 */
1600
1601 struct socket *listening_sockets;
1602 struct pollfd *listening_socket_fds;
1603 unsigned int num_listening_sockets;
1604
1605 pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */
1606
1607 #ifdef ALTERNATIVE_QUEUE
1608 struct socket *client_socks;
1609 void **client_wait_events;
1610 #else
1611 struct socket queue[MGSQLEN]; /* Accepted sockets */
1612 volatile int sq_head; /* Head of the socket queue */
1613 volatile int sq_tail; /* Tail of the socket queue */
1614 pthread_cond_t sq_full; /* Signaled when socket is produced */
1615 pthread_cond_t sq_empty; /* Signaled when socket is consumed */
1616 #endif
1617
1618 pthread_t masterthreadid; /* The master thread ID */
1619 unsigned int
1620 cfg_worker_threads; /* The number of configured worker threads. */
1621 pthread_t *workerthreadids; /* The worker thread IDs */
1622
1623 time_t start_time; /* Server start time, used for authentication */
1624 uint64_t auth_nonce_mask; /* Mask for all nonce values */
1625 pthread_mutex_t nonce_mutex; /* Protects nonce_count */
1626 unsigned long nonce_count; /* Used nonces, used for authentication */
1627
1628 char *systemName; /* What operating system is running */
1629
1630 /* linked list of uri handlers */
1631 struct mg_handler_info *handlers;
1632
1633 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1634 /* linked list of shared lua websockets */
1635 struct mg_shared_lua_websocket_list *shared_lua_websockets;
1636 #endif
1637
1638 #ifdef USE_TIMERS
1639 struct ttimers *timers;
1640 #endif
1641 };
1642
1643
1644 struct mg_connection {
1645 struct mg_request_info request_info;
1646 struct mg_context *ctx;
1647 SSL *ssl; /* SSL descriptor */
1648 SSL_CTX *client_ssl_ctx; /* SSL context for client connections */
1649 struct socket client; /* Connected client */
1650 time_t conn_birth_time; /* Time (wall clock) when connection was
1651 * established */
1652 struct timespec req_time; /* Time (since system start) when the request
1653 * was received */
1654 int64_t num_bytes_sent; /* Total bytes sent to client */
1655 int64_t content_len; /* Content-Length header value */
1656 int64_t consumed_content; /* How many bytes of content have been read */
1657 int is_chunked; /* Transfer-Encoding is chunked: 0=no, 1=yes:
1658 * data available, 2: all data read */
1659 size_t chunk_remainder; /* Unread data from the last chunk */
1660 char *buf; /* Buffer for received data */
1661 char *path_info; /* PATH_INFO part of the URL */
1662
1663 int must_close; /* 1 if connection must be closed */
1664 int in_error_handler; /* 1 if in handler for user defined error
1665 * pages */
1666 int handled_requests; /* Number of requests handled by this connection */
1667 int buf_size; /* Buffer size */
1668 int request_len; /* Size of the request + headers in a buffer */
1669 int data_len; /* Total size of data in a buffer */
1670 int status_code; /* HTTP reply status code, e.g. 200 */
1671 int throttle; /* Throttling, bytes/sec. <= 0 means no
1672 * throttle */
1673 time_t last_throttle_time; /* Last time throttled data was sent */
1674 int64_t last_throttle_bytes; /* Bytes sent this second */
1675 pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure
1676 * atomic transmissions for websockets */
1677 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1678 void *lua_websocket_state; /* Lua_State for a websocket connection */
1679 #endif
1680
1681 int thread_index; /* Thread index within ctx */
1682 };
1683
1684
1685 static pthread_key_t sTlsKey; /* Thread local storage index */
1686 static int sTlsInit = 0;
1687 static int thread_idx_max = 0;
1688
1689
1690 struct mg_workerTLS {
1691 int is_master;
1692 unsigned long thread_idx;
1693 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1694 HANDLE pthread_cond_helper_mutex;
1695 struct mg_workerTLS *next_waiting_thread;
1696 #endif
1697 };
1698
1699 /* Directory entry */
1700 struct de {
1701 struct mg_connection *conn;
1702 char *file_name;
1703 struct mg_file_stat file;
1704 };
1705
1706
1707 #if defined(USE_WEBSOCKET)
1708 static int is_websocket_protocol(const struct mg_connection *conn);
1709 #else
1710 #define is_websocket_protocol(conn) (0)
1711 #endif
1712
1713
1714 static int
mg_atomic_inc(volatile int * addr)1715 mg_atomic_inc(volatile int *addr)
1716 {
1717 int ret;
1718 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1719 /* Depending on the SDK, this function uses either
1720 * (volatile unsigned int *) or (volatile LONG *),
1721 * so whatever you use, the other SDK is likely to raise a warning. */
1722 ret = InterlockedIncrement((volatile long *)addr);
1723 #elif defined(__GNUC__) \
1724 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1725 ret = __sync_add_and_fetch(addr, 1);
1726 #else
1727 ret = (++(*addr));
1728 #endif
1729 return ret;
1730 }
1731
1732
1733 static int
mg_atomic_dec(volatile int * addr)1734 mg_atomic_dec(volatile int *addr)
1735 {
1736 int ret;
1737 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1738 /* Depending on the SDK, this function uses either
1739 * (volatile unsigned int *) or (volatile LONG *),
1740 * so whatever you use, the other SDK is likely to raise a warning. */
1741 ret = InterlockedDecrement((volatile long *)addr);
1742 #elif defined(__GNUC__) \
1743 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1744 ret = __sync_sub_and_fetch(addr, 1);
1745 #else
1746 ret = (--(*addr));
1747 #endif
1748 return ret;
1749 }
1750
1751 #if !defined(NO_THREAD_NAME)
1752 #if defined(_WIN32) && defined(_MSC_VER)
1753 /* Set the thread name for debugging purposes in Visual Studio
1754 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
1755 */
1756 #pragma pack(push, 8)
1757 typedef struct tagTHREADNAME_INFO {
1758 DWORD dwType; /* Must be 0x1000. */
1759 LPCSTR szName; /* Pointer to name (in user addr space). */
1760 DWORD dwThreadID; /* Thread ID (-1=caller thread). */
1761 DWORD dwFlags; /* Reserved for future use, must be zero. */
1762 } THREADNAME_INFO;
1763 #pragma pack(pop)
1764
1765 #elif defined(__linux__)
1766
1767 #include <sys/prctl.h>
1768 #include <sys/sendfile.h>
1769 #include <sys/eventfd.h>
1770
1771
1772 #if defined(ALTERNATIVE_QUEUE)
1773
1774 static void *
event_create(void)1775 event_create(void)
1776 {
1777 int ret = eventfd(0, EFD_CLOEXEC);
1778 if (ret == -1) {
1779 /* Linux uses -1 on error, Windows NULL. */
1780 /* However, Linux does not return 0 on success either. */
1781 return 0;
1782 }
1783 return (void *)ret;
1784 }
1785
1786
1787 static int
event_wait(void * eventhdl)1788 event_wait(void *eventhdl)
1789 {
1790 uint64_t u;
1791 int s = (int)read((int)eventhdl, &u, sizeof(u));
1792 if (s != sizeof(uint64_t)) {
1793 /* error */
1794 return 0;
1795 }
1796 (void)u; /* the value is not required */
1797 return 1;
1798 }
1799
1800
1801 static int
event_signal(void * eventhdl)1802 event_signal(void *eventhdl)
1803 {
1804 uint64_t u = 1;
1805 int s = (int)write((int)eventhdl, &u, sizeof(u));
1806 if (s != sizeof(uint64_t)) {
1807 /* error */
1808 return 0;
1809 }
1810 return 1;
1811 }
1812
1813
1814 static void
event_destroy(void * eventhdl)1815 event_destroy(void *eventhdl)
1816 {
1817 close((int)eventhdl);
1818 }
1819 #endif
1820
1821 #endif
1822
1823
1824 #if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
1825
1826 struct posix_event {
1827 pthread_mutex_t mutex;
1828 pthread_cond_t cond;
1829 };
1830
1831
1832 static void *
event_create(void)1833 event_create(void)
1834 {
1835 struct posix_event *ret = mg_malloc(sizeof(struct posix_event));
1836 if (ret == 0) {
1837 /* out of memory */
1838 return 0;
1839 }
1840 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
1841 /* pthread mutex not available */
1842 mg_free(ret);
1843 return 0;
1844 }
1845 if (0 != pthread_cond_init(&(ret->cond), NULL)) {
1846 /* pthread cond not available */
1847 pthread_mutex_destroy(&(ret->mutex));
1848 mg_free(ret);
1849 return 0;
1850 }
1851 return (void *)ret;
1852 }
1853
1854
1855 static int
event_wait(void * eventhdl)1856 event_wait(void *eventhdl)
1857 {
1858 struct posix_event *ev = (struct posix_event *)eventhdl;
1859 pthread_mutex_lock(&(ev->mutex));
1860 pthread_cond_wait(&(ev->cond), &(ev->mutex));
1861 pthread_mutex_unlock(&(ev->mutex));
1862 return 1;
1863 }
1864
1865
1866 static int
event_signal(void * eventhdl)1867 event_signal(void *eventhdl)
1868 {
1869 struct posix_event *ev = (struct posix_event *)eventhdl;
1870 pthread_mutex_lock(&(ev->mutex));
1871 pthread_cond_signal(&(ev->cond));
1872 pthread_mutex_unlock(&(ev->mutex));
1873 return 1;
1874 }
1875
1876
1877 static void
event_destroy(void * eventhdl)1878 event_destroy(void *eventhdl)
1879 {
1880 struct posix_event *ev = (struct posix_event *)eventhdl;
1881 pthread_cond_destroy(&(ev->cond));
1882 pthread_mutex_destroy(&(ev->mutex));
1883 mg_free(ev);
1884 }
1885 #endif
1886
1887
1888 static void
mg_set_thread_name(const char * name)1889 mg_set_thread_name(const char *name)
1890 {
1891 char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
1892
1893 mg_snprintf(
1894 NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name);
1895
1896 #if defined(_WIN32)
1897 #if defined(_MSC_VER)
1898 /* Windows and Visual Studio Compiler */
1899 __try
1900 {
1901 THREADNAME_INFO info;
1902 info.dwType = 0x1000;
1903 info.szName = threadName;
1904 info.dwThreadID = ~0U;
1905 info.dwFlags = 0;
1906
1907 RaiseException(0x406D1388,
1908 0,
1909 sizeof(info) / sizeof(ULONG_PTR),
1910 (ULONG_PTR *)&info);
1911 }
1912 __except(EXCEPTION_EXECUTE_HANDLER)
1913 {
1914 }
1915 #elif defined(__MINGW32__)
1916 /* No option known to set thread name for MinGW */
1917 #endif
1918 #elif defined(__GLIBC__) \
1919 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
1920 /* pthread_setname_np first appeared in glibc in version 2.12*/
1921 (void)pthread_setname_np(pthread_self(), threadName);
1922 #elif defined(__linux__)
1923 /* on linux we can use the old prctl function */
1924 (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
1925 #endif
1926 }
1927 #else /* !defined(NO_THREAD_NAME) */
1928 void
mg_set_thread_name(const char * threadName)1929 mg_set_thread_name(const char *threadName)
1930 {
1931 }
1932 #endif
1933
1934
1935 #if defined(MG_LEGACY_INTERFACE)
1936 const char **
mg_get_valid_option_names(void)1937 mg_get_valid_option_names(void)
1938 {
1939 /* This function is deprecated. Use mg_get_valid_options instead. */
1940 static const char *
1941 data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0};
1942 int i;
1943
1944 for (i = 0; config_options[i].name != NULL; i++) {
1945 data[i * 2] = config_options[i].name;
1946 data[i * 2 + 1] = config_options[i].default_value;
1947 }
1948
1949 return data;
1950 }
1951 #endif
1952
1953
1954 const struct mg_option *
mg_get_valid_options(void)1955 mg_get_valid_options(void)
1956 {
1957 return config_options;
1958 }
1959
1960
1961 /* Do not open file (used in is_file_in_memory) */
1962 #define MG_FOPEN_MODE_NONE (0)
1963
1964 /* Open file for read only access */
1965 #define MG_FOPEN_MODE_READ (1)
1966
1967 /* Open file for writing, create and overwrite */
1968 #define MG_FOPEN_MODE_WRITE (2)
1969
1970 /* Open file for writing, create and append */
1971 #define MG_FOPEN_MODE_APPEND (4)
1972
1973
1974 /* If a file is in memory, set all "stat" members and the membuf pointer of
1975 * output filep and return 1, otherwise return 0 and don't modify anything. */
1976 static int
open_file_in_memory(const struct mg_connection * conn,const char * path,struct mg_file * filep,int mode)1977 open_file_in_memory(const struct mg_connection *conn,
1978 const char *path,
1979 struct mg_file *filep,
1980 int mode)
1981 {
1982 size_t size = 0;
1983 const char *buf = NULL;
1984 if (!conn) {
1985 return 0;
1986 }
1987
1988 if ((mode != MG_FOPEN_MODE_NONE) && (mode != MG_FOPEN_MODE_READ)) {
1989 return 0;
1990 }
1991
1992 if (conn->ctx->callbacks.open_file) {
1993 buf = conn->ctx->callbacks.open_file(conn, path, &size);
1994 if (buf != NULL) {
1995 if (filep == NULL) {
1996 /* This is a file in memory, but we cannot store the properties
1997 * now.
1998 * Called from "is_file_in_memory" function. */
1999 return 1;
2000 }
2001
2002 /* NOTE: override filep->size only on success. Otherwise, it might
2003 * break constructs like if (!mg_stat() || !mg_fopen()) ... */
2004 filep->access.membuf = buf;
2005 filep->access.fp = NULL;
2006
2007 /* Size was set by the callback */
2008 filep->stat.size = size;
2009
2010 /* Assume the data may change during runtime by setting
2011 * last_modified = now */
2012 filep->stat.last_modified = time(NULL);
2013
2014 filep->stat.is_directory = 0;
2015 filep->stat.is_gzipped = 0;
2016 }
2017 }
2018
2019 return (buf != NULL);
2020 }
2021
2022
2023 static int
is_file_in_memory(const struct mg_connection * conn,const char * path)2024 is_file_in_memory(const struct mg_connection *conn, const char *path)
2025 {
2026 return open_file_in_memory(conn, path, NULL, MG_FOPEN_MODE_NONE);
2027 }
2028
2029
2030 static int
is_file_opened(const struct mg_file_access * fileacc)2031 is_file_opened(const struct mg_file_access *fileacc)
2032 {
2033 if (!fileacc) {
2034 return 0;
2035 }
2036 return (fileacc->membuf != NULL) || (fileacc->fp != NULL);
2037 }
2038
2039
2040 static int mg_stat(const struct mg_connection *conn,
2041 const char *path,
2042 struct mg_file_stat *filep);
2043
2044
2045 /* mg_fopen will open a file either in memory or on the disk.
2046 * The input parameter path is a string in UTF-8 encoding.
2047 * The input parameter mode is MG_FOPEN_MODE_*
2048 * On success, either fp or membuf will be set in the output
2049 * struct file. All status members will also be set.
2050 * The function returns 1 on success, 0 on error. */
2051 static int
mg_fopen(const struct mg_connection * conn,const char * path,int mode,struct mg_file * filep)2052 mg_fopen(const struct mg_connection *conn,
2053 const char *path,
2054 int mode,
2055 struct mg_file *filep)
2056 {
2057 int found;
2058
2059 if (!filep) {
2060 return 0;
2061 }
2062 filep->access.fp = NULL;
2063 filep->access.membuf = NULL;
2064
2065 if (!is_file_in_memory(conn, path)) {
2066
2067 /* filep is initialized in mg_stat: all fields with memset to,
2068 * some fields like size and modification date with values */
2069 found = mg_stat(conn, path, &(filep->stat));
2070
2071 if ((mode == MG_FOPEN_MODE_READ) && (!found)) {
2072 /* file does not exist and will not be created */
2073 return 0;
2074 }
2075
2076 #ifdef _WIN32
2077 {
2078 wchar_t wbuf[PATH_MAX];
2079 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
2080 switch (mode) {
2081 case MG_FOPEN_MODE_READ:
2082 filep->access.fp = _wfopen(wbuf, L"rb");
2083 break;
2084 case MG_FOPEN_MODE_WRITE:
2085 filep->access.fp = _wfopen(wbuf, L"wb");
2086 break;
2087 case MG_FOPEN_MODE_APPEND:
2088 filep->access.fp = _wfopen(wbuf, L"ab");
2089 break;
2090 }
2091 }
2092 #else
2093 /* Linux et al already use unicode. No need to convert. */
2094 switch (mode) {
2095 case MG_FOPEN_MODE_READ:
2096 filep->access.fp = fopen(path, "r");
2097 break;
2098 case MG_FOPEN_MODE_WRITE:
2099 filep->access.fp = fopen(path, "w");
2100 break;
2101 case MG_FOPEN_MODE_APPEND:
2102 filep->access.fp = fopen(path, "a");
2103 break;
2104 }
2105
2106 #endif
2107 if (!found) {
2108 /* File did not exist before fopen was called.
2109 * Maybe it has been created now. Get stat info
2110 * like creation time now. */
2111 found = mg_stat(conn, path, &(filep->stat));
2112 (void)found;
2113 }
2114
2115 /* file is on disk */
2116 return (filep->access.fp != NULL);
2117
2118 } else {
2119 /* is_file_in_memory returned true */
2120 if (open_file_in_memory(conn, path, filep, mode)) {
2121 /* file is in memory */
2122 return (filep->access.membuf != NULL);
2123 }
2124 }
2125
2126 /* Open failed */
2127 return 0;
2128 }
2129
2130
2131 /* return 0 on success, just like fclose */
2132 static int
mg_fclose(struct mg_file_access * fileacc)2133 mg_fclose(struct mg_file_access *fileacc)
2134 {
2135 int ret = -1;
2136 if (fileacc != NULL) {
2137 if (fileacc->fp != NULL) {
2138 ret = fclose(fileacc->fp);
2139 } else if (fileacc->membuf != NULL) {
2140 ret = 0;
2141 }
2142 /* reset all members of fileacc */
2143 memset(fileacc, 0, sizeof(*fileacc));
2144 }
2145 return ret;
2146 }
2147
2148
2149 static void
mg_strlcpy(register char * dst,register const char * src,size_t n)2150 mg_strlcpy(register char *dst, register const char *src, size_t n)
2151 {
2152 for (; *src != '\0' && n > 1; n--) {
2153 *dst++ = *src++;
2154 }
2155 *dst = '\0';
2156 }
2157
2158
2159 static int
lowercase(const char * s)2160 lowercase(const char *s)
2161 {
2162 return tolower(*(const unsigned char *)s);
2163 }
2164
2165
2166 int
mg_strncasecmp(const char * s1,const char * s2,size_t len)2167 mg_strncasecmp(const char *s1, const char *s2, size_t len)
2168 {
2169 int diff = 0;
2170
2171 if (len > 0) {
2172 do {
2173 diff = lowercase(s1++) - lowercase(s2++);
2174 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2175 }
2176
2177 return diff;
2178 }
2179
2180
2181 int
mg_strcasecmp(const char * s1,const char * s2)2182 mg_strcasecmp(const char *s1, const char *s2)
2183 {
2184 int diff;
2185
2186 do {
2187 diff = lowercase(s1++) - lowercase(s2++);
2188 } while (diff == 0 && s1[-1] != '\0');
2189
2190 return diff;
2191 }
2192
2193
2194 static char *
mg_strndup(const char * ptr,size_t len)2195 mg_strndup(const char *ptr, size_t len)
2196 {
2197 char *p;
2198
2199 if ((p = (char *)mg_malloc(len + 1)) != NULL) {
2200 mg_strlcpy(p, ptr, len + 1);
2201 }
2202
2203 return p;
2204 }
2205
2206
2207 static char *
mg_strdup(const char * str)2208 mg_strdup(const char *str)
2209 {
2210 return mg_strndup(str, strlen(str));
2211 }
2212
2213
2214 static const char *
mg_strcasestr(const char * big_str,const char * small_str)2215 mg_strcasestr(const char *big_str, const char *small_str)
2216 {
2217 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
2218
2219 if (big_len >= small_len) {
2220 for (i = 0; i <= (big_len - small_len); i++) {
2221 if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
2222 return big_str + i;
2223 }
2224 }
2225 }
2226
2227 return NULL;
2228 }
2229
2230
2231 /* Return null terminated string of given maximum length.
2232 * Report errors if length is exceeded. */
2233 static void
mg_vsnprintf(const struct mg_connection * conn,int * truncated,char * buf,size_t buflen,const char * fmt,va_list ap)2234 mg_vsnprintf(const struct mg_connection *conn,
2235 int *truncated,
2236 char *buf,
2237 size_t buflen,
2238 const char *fmt,
2239 va_list ap)
2240 {
2241 int n, ok;
2242
2243 if (buflen == 0) {
2244 return;
2245 }
2246
2247 #ifdef __clang__
2248 #pragma clang diagnostic push
2249 #pragma clang diagnostic ignored "-Wformat-nonliteral"
2250 /* Using fmt as a non-literal is intended here, since it is mostly called
2251 * indirectly by mg_snprintf */
2252 #endif
2253
2254 n = (int)vsnprintf_impl(buf, buflen, fmt, ap);
2255 ok = (n >= 0) && ((size_t)n < buflen);
2256
2257 #ifdef __clang__
2258 #pragma clang diagnostic pop
2259 #endif
2260
2261 if (ok) {
2262 if (truncated) {
2263 *truncated = 0;
2264 }
2265 } else {
2266 if (truncated) {
2267 *truncated = 1;
2268 }
2269 mg_cry(conn,
2270 "truncating vsnprintf buffer: [%.*s]",
2271 (int)((buflen > 200) ? 200 : (buflen - 1)),
2272 buf);
2273 n = (int)buflen - 1;
2274 }
2275 buf[n] = '\0';
2276 }
2277
2278
2279 static void
mg_snprintf(const struct mg_connection * conn,int * truncated,char * buf,size_t buflen,const char * fmt,...)2280 mg_snprintf(const struct mg_connection *conn,
2281 int *truncated,
2282 char *buf,
2283 size_t buflen,
2284 const char *fmt,
2285 ...)
2286 {
2287 va_list ap;
2288
2289 va_start(ap, fmt);
2290 mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap);
2291 va_end(ap);
2292 }
2293
2294
2295 static int
get_option_index(const char * name)2296 get_option_index(const char *name)
2297 {
2298 int i;
2299
2300 for (i = 0; config_options[i].name != NULL; i++) {
2301 if (strcmp(config_options[i].name, name) == 0) {
2302 return i;
2303 }
2304 }
2305 return -1;
2306 }
2307
2308
2309 const char *
mg_get_option(const struct mg_context * ctx,const char * name)2310 mg_get_option(const struct mg_context *ctx, const char *name)
2311 {
2312 int i;
2313 if ((i = get_option_index(name)) == -1) {
2314 return NULL;
2315 } else if (!ctx || ctx->config[i] == NULL) {
2316 return "";
2317 } else {
2318 return ctx->config[i];
2319 }
2320 }
2321
2322
2323 struct mg_context *
mg_get_context(const struct mg_connection * conn)2324 mg_get_context(const struct mg_connection *conn)
2325 {
2326 return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
2327 }
2328
2329
2330 void *
mg_get_user_data(const struct mg_context * ctx)2331 mg_get_user_data(const struct mg_context *ctx)
2332 {
2333 return (ctx == NULL) ? NULL : ctx->user_data;
2334 }
2335
2336
2337 void
mg_set_user_connection_data(struct mg_connection * conn,void * data)2338 mg_set_user_connection_data(struct mg_connection *conn, void *data)
2339 {
2340 if (conn != NULL) {
2341 conn->request_info.conn_data = data;
2342 }
2343 }
2344
2345
2346 void *
mg_get_user_connection_data(const struct mg_connection * conn)2347 mg_get_user_connection_data(const struct mg_connection *conn)
2348 {
2349 if (conn != NULL) {
2350 return conn->request_info.conn_data;
2351 }
2352 return NULL;
2353 }
2354
2355
2356 size_t
mg_get_ports(const struct mg_context * ctx,size_t size,int * ports,int * ssl)2357 mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
2358 {
2359 size_t i;
2360 if (!ctx) {
2361 return 0;
2362 }
2363 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
2364 ssl[i] = ctx->listening_sockets[i].is_ssl;
2365 ports[i] =
2366 #if defined(USE_IPV6)
2367 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
2368 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
2369 :
2370 #endif
2371 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
2372 }
2373 return i;
2374 }
2375
2376
2377 int
mg_get_server_ports(const struct mg_context * ctx,int size,struct mg_server_ports * ports)2378 mg_get_server_ports(const struct mg_context *ctx,
2379 int size,
2380 struct mg_server_ports *ports)
2381 {
2382 int i, cnt = 0;
2383
2384 if (size <= 0) {
2385 return -1;
2386 }
2387 memset(ports, 0, sizeof(*ports) * (size_t)size);
2388 if (!ctx) {
2389 return -1;
2390 }
2391 if (!ctx->listening_sockets) {
2392 return -1;
2393 }
2394
2395 for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) {
2396
2397 ports[cnt].port =
2398 #if defined(USE_IPV6)
2399 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
2400 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
2401 :
2402 #endif
2403 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
2404 ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
2405 ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
2406
2407 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
2408 /* IPv4 */
2409 ports[cnt].protocol = 1;
2410 cnt++;
2411 } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
2412 /* IPv6 */
2413 ports[cnt].protocol = 3;
2414 cnt++;
2415 }
2416 }
2417
2418 return cnt;
2419 }
2420
2421
2422 static void
sockaddr_to_string(char * buf,size_t len,const union usa * usa)2423 sockaddr_to_string(char *buf, size_t len, const union usa *usa)
2424 {
2425 buf[0] = '\0';
2426
2427 if (!usa) {
2428 return;
2429 }
2430
2431 if (usa->sa.sa_family == AF_INET) {
2432 getnameinfo(&usa->sa,
2433 sizeof(usa->sin),
2434 buf,
2435 (unsigned)len,
2436 NULL,
2437 0,
2438 NI_NUMERICHOST);
2439 }
2440 #if defined(USE_IPV6)
2441 else if (usa->sa.sa_family == AF_INET6) {
2442 getnameinfo(&usa->sa,
2443 sizeof(usa->sin6),
2444 buf,
2445 (unsigned)len,
2446 NULL,
2447 0,
2448 NI_NUMERICHOST);
2449 }
2450 #endif
2451 }
2452
2453
2454 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
2455 * included in all responses other than 100, 101, 5xx. */
2456 static void
gmt_time_string(char * buf,size_t buf_len,time_t * t)2457 gmt_time_string(char *buf, size_t buf_len, time_t *t)
2458 {
2459 struct tm *tm;
2460
2461 tm = ((t != NULL) ? gmtime(t) : NULL);
2462 if (tm != NULL) {
2463 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
2464 } else {
2465 mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
2466 buf[buf_len - 1] = '\0';
2467 }
2468 }
2469
2470
2471 /* difftime for struct timespec. Return value is in seconds. */
2472 static double
mg_difftimespec(const struct timespec * ts_now,const struct timespec * ts_before)2473 mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
2474 {
2475 return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
2476 + (double)(ts_now->tv_sec - ts_before->tv_sec);
2477 }
2478
2479
2480 /* Print error message to the opened error log stream. */
2481 void
mg_cry(const struct mg_connection * conn,const char * fmt,...)2482 mg_cry(const struct mg_connection *conn, const char *fmt, ...)
2483 {
2484 char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
2485 va_list ap;
2486 struct mg_file fi;
2487 time_t timestamp;
2488
2489 va_start(ap, fmt);
2490 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
2491 va_end(ap);
2492 buf[sizeof(buf) - 1] = 0;
2493
2494 if (!conn) {
2495 puts(buf);
2496 return;
2497 }
2498
2499 /* Do not lock when getting the callback value, here and below.
2500 * I suppose this is fine, since function cannot disappear in the
2501 * same way string option can. */
2502 if ((conn->ctx->callbacks.log_message == NULL)
2503 || (conn->ctx->callbacks.log_message(conn, buf) == 0)) {
2504
2505 if (conn->ctx->config[ERROR_LOG_FILE] != NULL) {
2506 if (mg_fopen(conn,
2507 conn->ctx->config[ERROR_LOG_FILE],
2508 MG_FOPEN_MODE_APPEND,
2509 &fi) == 0) {
2510 fi.access.fp = NULL;
2511 }
2512 } else {
2513 fi.access.fp = NULL;
2514 }
2515
2516 if (fi.access.fp != NULL) {
2517 flockfile(fi.access.fp);
2518 timestamp = time(NULL);
2519
2520 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
2521 fprintf(fi.access.fp,
2522 "[%010lu] [error] [client %s] ",
2523 (unsigned long)timestamp,
2524 src_addr);
2525
2526 if (conn->request_info.request_method != NULL) {
2527 fprintf(fi.access.fp,
2528 "%s %s: ",
2529 conn->request_info.request_method,
2530 conn->request_info.request_uri);
2531 }
2532
2533 fprintf(fi.access.fp, "%s", buf);
2534 fputc('\n', fi.access.fp);
2535 fflush(fi.access.fp);
2536 funlockfile(fi.access.fp);
2537 (void)mg_fclose(&fi.access); /* Ignore errors. We can't call
2538 * mg_cry here anyway ;-) */
2539 }
2540 }
2541 }
2542
2543
2544 /* Return fake connection structure. Used for logging, if connection
2545 * is not applicable at the moment of logging. */
2546 static struct mg_connection *
fc(struct mg_context * ctx)2547 fc(struct mg_context *ctx)
2548 {
2549 static struct mg_connection fake_connection;
2550 fake_connection.ctx = ctx;
2551 return &fake_connection;
2552 }
2553
2554
2555 const char *
mg_version(void)2556 mg_version(void)
2557 {
2558 return CIVETWEB_VERSION;
2559 }
2560
2561
2562 const struct mg_request_info *
mg_get_request_info(const struct mg_connection * conn)2563 mg_get_request_info(const struct mg_connection *conn)
2564 {
2565 if (!conn) {
2566 return NULL;
2567 }
2568 return &conn->request_info;
2569 }
2570
2571
2572 /* Skip the characters until one of the delimiters characters found.
2573 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
2574 * Advance pointer to buffer to the next word. Return found 0-terminated word.
2575 * Delimiters can be quoted with quotechar. */
2576 static char *
skip_quoted(char ** buf,const char * delimiters,const char * whitespace,char quotechar)2577 skip_quoted(char **buf,
2578 const char *delimiters,
2579 const char *whitespace,
2580 char quotechar)
2581 {
2582 char *p, *begin_word, *end_word, *end_whitespace;
2583
2584 begin_word = *buf;
2585 end_word = begin_word + strcspn(begin_word, delimiters);
2586
2587 /* Check for quotechar */
2588 if (end_word > begin_word) {
2589 p = end_word - 1;
2590 while (*p == quotechar) {
2591 /* While the delimiter is quoted, look for the next delimiter. */
2592 /* This happens, e.g., in calls from parse_auth_header,
2593 * if the user name contains a " character. */
2594
2595 /* If there is anything beyond end_word, copy it. */
2596 if (*end_word != '\0') {
2597 size_t end_off = strcspn(end_word + 1, delimiters);
2598 memmove(p, end_word, end_off + 1);
2599 p += end_off; /* p must correspond to end_word - 1 */
2600 end_word += end_off + 1;
2601 } else {
2602 *p = '\0';
2603 break;
2604 }
2605 }
2606 for (p++; p < end_word; p++) {
2607 *p = '\0';
2608 }
2609 }
2610
2611 if (*end_word == '\0') {
2612 *buf = end_word;
2613 } else {
2614
2615 #if defined(__MINGW32__) || defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
2616 /* Disable spurious conversion warning for GCC */
2617 #pragma GCC diagnostic push
2618 #pragma GCC diagnostic ignored "-Wsign-conversion"
2619 #endif
2620
2621 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
2622
2623 #if defined(__MINGW32__) || defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
2624 #pragma GCC diagnostic pop
2625 #endif
2626
2627 for (p = end_word; p < end_whitespace; p++) {
2628 *p = '\0';
2629 }
2630
2631 *buf = end_whitespace;
2632 }
2633
2634 return begin_word;
2635 }
2636
2637
2638 /* Simplified version of skip_quoted without quote char
2639 * and whitespace == delimiters */
2640 static char *
skip(char ** buf,const char * delimiters)2641 skip(char **buf, const char *delimiters)
2642 {
2643 return skip_quoted(buf, delimiters, delimiters, 0);
2644 }
2645
2646
2647 /* Return HTTP header value, or NULL if not found. */
2648 static const char *
get_header(const struct mg_request_info * ri,const char * name)2649 get_header(const struct mg_request_info *ri, const char *name)
2650 {
2651 int i;
2652 if (ri) {
2653 for (i = 0; i < ri->num_headers; i++) {
2654 if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
2655 return ri->http_headers[i].value;
2656 }
2657 }
2658 }
2659
2660 return NULL;
2661 }
2662
2663
2664 const char *
mg_get_header(const struct mg_connection * conn,const char * name)2665 mg_get_header(const struct mg_connection *conn, const char *name)
2666 {
2667 if (!conn) {
2668 return NULL;
2669 }
2670
2671 return get_header(&conn->request_info, name);
2672 }
2673
2674
2675 /* A helper function for traversing a comma separated list of values.
2676 * It returns a list pointer shifted to the next value, or NULL if the end
2677 * of the list found.
2678 * Value is stored in val vector. If value has form "x=y", then eq_val
2679 * vector is initialized to point to the "y" part, and val vector length
2680 * is adjusted to point only to "x". */
2681 static const char *
next_option(const char * list,struct vec * val,struct vec * eq_val)2682 next_option(const char *list, struct vec *val, struct vec *eq_val)
2683 {
2684 int end;
2685
2686 reparse:
2687 if (val == NULL || list == NULL || *list == '\0') {
2688 /* End of the list */
2689 list = NULL;
2690 } else {
2691 /* Skip over leading LWS */
2692 while (*list == ' ' || *list == '\t')
2693 list++;
2694
2695 val->ptr = list;
2696 if ((list = strchr(val->ptr, ',')) != NULL) {
2697 /* Comma found. Store length and shift the list ptr */
2698 val->len = ((size_t)(list - val->ptr));
2699 list++;
2700 } else {
2701 /* This value is the last one */
2702 list = val->ptr + strlen(val->ptr);
2703 val->len = ((size_t)(list - val->ptr));
2704 }
2705
2706 /* Adjust length for trailing LWS */
2707 end = (int)val->len - 1;
2708 while (end >= 0 && (val->ptr[end] == ' ' || val->ptr[end] == '\t'))
2709 end--;
2710 val->len = (size_t)(end + 1);
2711
2712 if (val->len == 0) {
2713 /* Ignore any empty entries. */
2714 goto reparse;
2715 }
2716
2717 if (eq_val != NULL) {
2718 /* Value has form "x=y", adjust pointers and lengths
2719 * so that val points to "x", and eq_val points to "y". */
2720 eq_val->len = 0;
2721 eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len);
2722 if (eq_val->ptr != NULL) {
2723 eq_val->ptr++; /* Skip over '=' character */
2724 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
2725 val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1;
2726 }
2727 }
2728 }
2729
2730 return list;
2731 }
2732
2733 /* A helper function for checking if a comma separated list of values contains
2734 * the given option (case insensitvely).
2735 * 'header' can be NULL, in which case false is returned. */
2736 static int
header_has_option(const char * header,const char * option)2737 header_has_option(const char *header, const char *option)
2738 {
2739 struct vec opt_vec;
2740 struct vec eq_vec;
2741
2742 assert(option != NULL);
2743 assert(option[0] != '\0');
2744
2745 while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) {
2746 if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0)
2747 return 1;
2748 }
2749
2750 return 0;
2751 }
2752
2753 /* Perform case-insensitive match of string against pattern */
2754 static int
match_prefix(const char * pattern,size_t pattern_len,const char * str)2755 match_prefix(const char *pattern, size_t pattern_len, const char *str)
2756 {
2757 const char *or_str;
2758 size_t i;
2759 int j, len, res;
2760
2761 if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) {
2762 res = match_prefix(pattern, (size_t)(or_str - pattern), str);
2763 return (res > 0) ? res : match_prefix(or_str + 1,
2764 (size_t)((pattern + pattern_len)
2765 - (or_str + 1)),
2766 str);
2767 }
2768
2769 for (i = 0, j = 0; i < pattern_len; i++, j++) {
2770 if (pattern[i] == '?' && str[j] != '\0') {
2771 continue;
2772 } else if (pattern[i] == '$') {
2773 return (str[j] == '\0') ? j : -1;
2774 } else if (pattern[i] == '*') {
2775 i++;
2776 if (pattern[i] == '*') {
2777 i++;
2778 len = (int)strlen(str + j);
2779 } else {
2780 len = (int)strcspn(str + j, "/");
2781 }
2782 if (i == pattern_len) {
2783 return j + len;
2784 }
2785 do {
2786 res = match_prefix(pattern + i, pattern_len - i, str + j + len);
2787 } while (res == -1 && len-- > 0);
2788 return (res == -1) ? -1 : j + res + len;
2789 } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
2790 return -1;
2791 }
2792 }
2793 return j;
2794 }
2795
2796
2797 /* HTTP 1.1 assumes keep alive if "Connection:" header is not set
2798 * This function must tolerate situations when connection info is not
2799 * set up, for example if request parsing failed. */
2800 static int
should_keep_alive(const struct mg_connection * conn)2801 should_keep_alive(const struct mg_connection *conn)
2802 {
2803 if (conn != NULL) {
2804 const char *http_version = conn->request_info.http_version;
2805 const char *header = mg_get_header(conn, "Connection");
2806 if (conn->must_close || conn->status_code == 401
2807 || mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0
2808 || (header != NULL && !header_has_option(header, "keep-alive"))
2809 || (header == NULL && http_version
2810 && 0 != strcmp(http_version, "1.1"))) {
2811 return 0;
2812 }
2813 return 1;
2814 }
2815 return 0;
2816 }
2817
2818
2819 static int
should_decode_url(const struct mg_connection * conn)2820 should_decode_url(const struct mg_connection *conn)
2821 {
2822 if (!conn || !conn->ctx) {
2823 return 0;
2824 }
2825
2826 return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0);
2827 }
2828
2829
2830 static const char *
suggest_connection_header(const struct mg_connection * conn)2831 suggest_connection_header(const struct mg_connection *conn)
2832 {
2833 return should_keep_alive(conn) ? "keep-alive" : "close";
2834 }
2835
2836
2837 static int
send_no_cache_header(struct mg_connection * conn)2838 send_no_cache_header(struct mg_connection *conn)
2839 {
2840 /* Send all current and obsolete cache opt-out directives. */
2841 return mg_printf(conn,
2842 "Cache-Control: no-cache, no-store, "
2843 "must-revalidate, private, max-age=0\r\n"
2844 "Pragma: no-cache\r\n"
2845 "Expires: 0\r\n");
2846 }
2847
2848
2849 static int
send_static_cache_header(struct mg_connection * conn)2850 send_static_cache_header(struct mg_connection *conn)
2851 {
2852 #if !defined(NO_CACHING)
2853 /* Read the server config to check how long a file may be cached.
2854 * The configuration is in seconds. */
2855 int max_age = atoi(conn->ctx->config[STATIC_FILE_MAX_AGE]);
2856 if (max_age <= 0) {
2857 /* 0 means "do not cache". All values <0 are reserved
2858 * and may be used differently in the future. */
2859 /* If a file should not be cached, do not only send
2860 * max-age=0, but also pragmas and Expires headers. */
2861 return send_no_cache_header(conn);
2862 }
2863
2864 /* Use "Cache-Control: max-age" instead of "Expires" header.
2865 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
2866 /* See also https://www.mnot.net/cache_docs/ */
2867 /* According to RFC 2616, Section 14.21, caching times should not exceed
2868 * one year. A year with 365 days corresponds to 31536000 seconds, a leap
2869 * year to 31622400 seconds. For the moment, we just send whatever has
2870 * been configured, still the behavior for >1 year should be considered
2871 * as undefined. */
2872 return mg_printf(conn, "Cache-Control: max-age=%u\r\n", (unsigned)max_age);
2873 #else /* NO_CACHING */
2874 return send_no_cache_header(conn);
2875 #endif /* !NO_CACHING */
2876 }
2877
2878
2879 static void handle_file_based_request(struct mg_connection *conn,
2880 const char *path,
2881 struct mg_file *filep);
2882
2883
2884 const char *
mg_get_response_code_text(struct mg_connection * conn,int response_code)2885 mg_get_response_code_text(struct mg_connection *conn, int response_code)
2886 {
2887 /* See IANA HTTP status code assignment:
2888 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
2889 */
2890
2891 switch (response_code) {
2892 /* RFC2616 Section 10.1 - Informational 1xx */
2893 case 100:
2894 return "Continue"; /* RFC2616 Section 10.1.1 */
2895 case 101:
2896 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
2897 case 102:
2898 return "Processing"; /* RFC2518 Section 10.1 */
2899
2900 /* RFC2616 Section 10.2 - Successful 2xx */
2901 case 200:
2902 return "OK"; /* RFC2616 Section 10.2.1 */
2903 case 201:
2904 return "Created"; /* RFC2616 Section 10.2.2 */
2905 case 202:
2906 return "Accepted"; /* RFC2616 Section 10.2.3 */
2907 case 203:
2908 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
2909 case 204:
2910 return "No Content"; /* RFC2616 Section 10.2.5 */
2911 case 205:
2912 return "Reset Content"; /* RFC2616 Section 10.2.6 */
2913 case 206:
2914 return "Partial Content"; /* RFC2616 Section 10.2.7 */
2915 case 207:
2916 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */
2917 case 208:
2918 return "Already Reported"; /* RFC5842 Section 7.1 */
2919
2920 case 226:
2921 return "IM used"; /* RFC3229 Section 10.4.1 */
2922
2923 /* RFC2616 Section 10.3 - Redirection 3xx */
2924 case 300:
2925 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
2926 case 301:
2927 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
2928 case 302:
2929 return "Found"; /* RFC2616 Section 10.3.3 */
2930 case 303:
2931 return "See Other"; /* RFC2616 Section 10.3.4 */
2932 case 304:
2933 return "Not Modified"; /* RFC2616 Section 10.3.5 */
2934 case 305:
2935 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
2936 case 307:
2937 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
2938 case 308:
2939 return "Permanent Redirect"; /* RFC7238 Section 3 */
2940
2941 /* RFC2616 Section 10.4 - Client Error 4xx */
2942 case 400:
2943 return "Bad Request"; /* RFC2616 Section 10.4.1 */
2944 case 401:
2945 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
2946 case 402:
2947 return "Payment Required"; /* RFC2616 Section 10.4.3 */
2948 case 403:
2949 return "Forbidden"; /* RFC2616 Section 10.4.4 */
2950 case 404:
2951 return "Not Found"; /* RFC2616 Section 10.4.5 */
2952 case 405:
2953 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
2954 case 406:
2955 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
2956 case 407:
2957 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
2958 case 408:
2959 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
2960 case 409:
2961 return "Conflict"; /* RFC2616 Section 10.4.10 */
2962 case 410:
2963 return "Gone"; /* RFC2616 Section 10.4.11 */
2964 case 411:
2965 return "Length Required"; /* RFC2616 Section 10.4.12 */
2966 case 412:
2967 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
2968 case 413:
2969 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
2970 case 414:
2971 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
2972 case 415:
2973 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
2974 case 416:
2975 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */
2976 case 417:
2977 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
2978
2979 case 421:
2980 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
2981 case 422:
2982 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
2983 * Section 11.2 */
2984 case 423:
2985 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
2986 case 424:
2987 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
2988 * Section 11.4 */
2989
2990 case 426:
2991 return "Upgrade Required"; /* RFC 2817 Section 4 */
2992
2993 case 428:
2994 return "Precondition Required"; /* RFC 6585, Section 3 */
2995 case 429:
2996 return "Too Many Requests"; /* RFC 6585, Section 4 */
2997
2998 case 431:
2999 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
3000
3001 case 451:
3002 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
3003 * Section 3 */
3004
3005 /* RFC2616 Section 10.5 - Server Error 5xx */
3006 case 500:
3007 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
3008 case 501:
3009 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
3010 case 502:
3011 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
3012 case 503:
3013 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
3014 case 504:
3015 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
3016 case 505:
3017 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
3018 case 506:
3019 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
3020 case 507:
3021 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
3022 * Section 11.5 */
3023 case 508:
3024 return "Loop Detected"; /* RFC5842 Section 7.1 */
3025
3026 case 510:
3027 return "Not Extended"; /* RFC 2774, Section 7 */
3028 case 511:
3029 return "Network Authentication Required"; /* RFC 6585, Section 6 */
3030
3031 /* Other status codes, not shown in the IANA HTTP status code assignment.
3032 * E.g., "de facto" standards due to common use, ... */
3033 case 418:
3034 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
3035 case 419:
3036 return "Authentication Timeout"; /* common use */
3037 case 420:
3038 return "Enhance Your Calm"; /* common use */
3039 case 440:
3040 return "Login Timeout"; /* common use */
3041 case 509:
3042 return "Bandwidth Limit Exceeded"; /* common use */
3043
3044 default:
3045 /* This error code is unknown. This should not happen. */
3046 if (conn) {
3047 mg_cry(conn, "Unknown HTTP response code: %u", response_code);
3048 }
3049
3050 /* Return at least a category according to RFC 2616 Section 10. */
3051 if (response_code >= 100 && response_code < 200) {
3052 /* Unknown informational status code */
3053 return "Information";
3054 }
3055 if (response_code >= 200 && response_code < 300) {
3056 /* Unknown success code */
3057 return "Success";
3058 }
3059 if (response_code >= 300 && response_code < 400) {
3060 /* Unknown redirection code */
3061 return "Redirection";
3062 }
3063 if (response_code >= 400 && response_code < 500) {
3064 /* Unknown request error code */
3065 return "Client Error";
3066 }
3067 if (response_code >= 500 && response_code < 600) {
3068 /* Unknown server error code */
3069 return "Server Error";
3070 }
3071
3072 /* Response code not even within reasonable range */
3073 return "";
3074 }
3075 }
3076
3077
3078 static void send_http_error(struct mg_connection *,
3079 int,
3080 PRINTF_FORMAT_STRING(const char *fmt),
3081 ...) PRINTF_ARGS(3, 4);
3082
3083 static void
send_http_error(struct mg_connection * conn,int status,const char * fmt,...)3084 send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
3085 {
3086 char buf[MG_BUF_LEN];
3087 va_list ap;
3088 int len, i, page_handler_found, scope, truncated, has_body;
3089 char date[64];
3090 time_t curtime = time(NULL);
3091 const char *error_handler = NULL;
3092 struct mg_file error_page_file = STRUCT_FILE_INITIALIZER;
3093 const char *error_page_file_ext, *tstr;
3094
3095 const char *status_text = mg_get_response_code_text(conn, status);
3096
3097 if (conn == NULL) {
3098 return;
3099 }
3100
3101 conn->status_code = status;
3102 if (conn->in_error_handler || conn->ctx->callbacks.http_error == NULL
3103 || conn->ctx->callbacks.http_error(conn, status)) {
3104 if (!conn->in_error_handler) {
3105 /* Send user defined error pages, if defined */
3106 error_handler = conn->ctx->config[ERROR_PAGES];
3107 error_page_file_ext = conn->ctx->config[INDEX_FILES];
3108 page_handler_found = 0;
3109 if (error_handler != NULL) {
3110 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
3111 switch (scope) {
3112 case 1: /* Handler for specific error, e.g. 404 error */
3113 mg_snprintf(conn,
3114 &truncated,
3115 buf,
3116 sizeof(buf) - 32,
3117 "%serror%03u.",
3118 error_handler,
3119 status);
3120 break;
3121 case 2: /* Handler for error group, e.g., 5xx error handler
3122 * for all server errors (500-599) */
3123 mg_snprintf(conn,
3124 &truncated,
3125 buf,
3126 sizeof(buf) - 32,
3127 "%serror%01uxx.",
3128 error_handler,
3129 status / 100);
3130 break;
3131 default: /* Handler for all errors */
3132 mg_snprintf(conn,
3133 &truncated,
3134 buf,
3135 sizeof(buf) - 32,
3136 "%serror.",
3137 error_handler);
3138 break;
3139 }
3140
3141 /* String truncation in buf may only occur if error_handler
3142 * is too long. This string is from the config, not from a
3143 * client. */
3144 (void)truncated;
3145
3146 len = (int)strlen(buf);
3147
3148 tstr = strchr(error_page_file_ext, '.');
3149
3150 while (tstr) {
3151 for (i = 1; i < 32 && tstr[i] != 0 && tstr[i] != ',';
3152 i++)
3153 buf[len + i - 1] = tstr[i];
3154 buf[len + i - 1] = 0;
3155 if (mg_stat(conn, buf, &error_page_file.stat)) {
3156 page_handler_found = 1;
3157 break;
3158 }
3159 tstr = strchr(tstr + i, '.');
3160 }
3161 }
3162 }
3163
3164 if (page_handler_found) {
3165 conn->in_error_handler = 1;
3166 handle_file_based_request(conn, buf, &error_page_file);
3167 conn->in_error_handler = 0;
3168 return;
3169 }
3170 }
3171
3172 /* No custom error page. Send default error page. */
3173 gmt_time_string(date, sizeof(date), &curtime);
3174
3175 /* Errors 1xx, 204 and 304 MUST NOT send a body */
3176 has_body = (status > 199 && status != 204 && status != 304);
3177
3178 conn->must_close = 1;
3179 mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
3180 send_no_cache_header(conn);
3181 if (has_body) {
3182 mg_printf(conn,
3183 "%s",
3184 "Content-Type: text/plain; charset=utf-8\r\n");
3185 }
3186 mg_printf(conn,
3187 "Date: %s\r\n"
3188 "Connection: close\r\n\r\n",
3189 date);
3190
3191 /* Errors 1xx, 204 and 304 MUST NOT send a body */
3192 if (has_body) {
3193 mg_printf(conn, "Error %d: %s\n", status, status_text);
3194
3195 if (fmt != NULL) {
3196 va_start(ap, fmt);
3197 mg_vsnprintf(conn, NULL, buf, sizeof(buf), fmt, ap);
3198 va_end(ap);
3199 mg_write(conn, buf, strlen(buf));
3200 DEBUG_TRACE("Error %i - [%s]", status, buf);
3201 }
3202
3203 } else {
3204 /* No body allowed. Close the connection. */
3205 DEBUG_TRACE("Error %i", status);
3206 }
3207 }
3208 }
3209
3210 #if defined(_WIN32) && !defined(__SYMBIAN32__)
3211 /* Create substitutes for POSIX functions in Win32. */
3212
3213 #if defined(__MINGW32__)
3214 /* Show no warning in case system functions are not used. */
3215 #pragma GCC diagnostic push
3216 #pragma GCC diagnostic ignored "-Wunused-function"
3217 #endif
3218
3219
3220 static int
pthread_mutex_init(pthread_mutex_t * mutex,void * unused)3221 pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
3222 {
3223 (void)unused;
3224 *mutex = CreateMutex(NULL, FALSE, NULL);
3225 return (*mutex == NULL) ? -1 : 0;
3226 }
3227
3228
3229 static int
pthread_mutex_destroy(pthread_mutex_t * mutex)3230 pthread_mutex_destroy(pthread_mutex_t *mutex)
3231 {
3232 return (CloseHandle(*mutex) == 0) ? -1 : 0;
3233 }
3234
3235
3236 static int
pthread_mutex_lock(pthread_mutex_t * mutex)3237 pthread_mutex_lock(pthread_mutex_t *mutex)
3238 {
3239 return (WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0) ? 0 : -1;
3240 }
3241
3242
3243 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
3244 static int
pthread_mutex_trylock(pthread_mutex_t * mutex)3245 pthread_mutex_trylock(pthread_mutex_t *mutex)
3246 {
3247 switch (WaitForSingleObject(*mutex, 0)) {
3248 case WAIT_OBJECT_0:
3249 return 0;
3250 case WAIT_TIMEOUT:
3251 return -2; /* EBUSY */
3252 }
3253 return -1;
3254 }
3255 #endif
3256
3257
3258 static int
pthread_mutex_unlock(pthread_mutex_t * mutex)3259 pthread_mutex_unlock(pthread_mutex_t *mutex)
3260 {
3261 return (ReleaseMutex(*mutex) == 0) ? -1 : 0;
3262 }
3263
3264
3265 static int
pthread_cond_init(pthread_cond_t * cv,const void * unused)3266 pthread_cond_init(pthread_cond_t *cv, const void *unused)
3267 {
3268 (void)unused;
3269 InitializeCriticalSection(&cv->threadIdSec);
3270 cv->waiting_thread = NULL;
3271 return 0;
3272 }
3273
3274
3275 static int
pthread_cond_timedwait(pthread_cond_t * cv,pthread_mutex_t * mutex,const struct timespec * abstime)3276 pthread_cond_timedwait(pthread_cond_t *cv,
3277 pthread_mutex_t *mutex,
3278 const struct timespec *abstime)
3279 {
3280 struct mg_workerTLS **ptls,
3281 *tls = (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
3282 int ok;
3283 struct timespec tsnow;
3284 int64_t nsnow, nswaitabs, nswaitrel;
3285 DWORD mswaitrel;
3286
3287 EnterCriticalSection(&cv->threadIdSec);
3288 /* Add this thread to cv's waiting list */
3289 ptls = &cv->waiting_thread;
3290 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
3291 ;
3292 tls->next_waiting_thread = NULL;
3293 *ptls = tls;
3294 LeaveCriticalSection(&cv->threadIdSec);
3295
3296 if (abstime) {
3297 clock_gettime(CLOCK_REALTIME, &tsnow);
3298 nsnow = (((int64_t)tsnow.tv_sec) * 1000000000) + tsnow.tv_nsec;
3299 nswaitabs =
3300 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
3301 nswaitrel = nswaitabs - nsnow;
3302 if (nswaitrel < 0) {
3303 nswaitrel = 0;
3304 }
3305 mswaitrel = (DWORD)(nswaitrel / 1000000);
3306 } else {
3307 mswaitrel = INFINITE;
3308 }
3309
3310 pthread_mutex_unlock(mutex);
3311 ok = (WAIT_OBJECT_0
3312 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
3313 if (!ok) {
3314 ok = 1;
3315 EnterCriticalSection(&cv->threadIdSec);
3316 ptls = &cv->waiting_thread;
3317 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
3318 if (*ptls == tls) {
3319 *ptls = tls->next_waiting_thread;
3320 ok = 0;
3321 break;
3322 }
3323 }
3324 LeaveCriticalSection(&cv->threadIdSec);
3325 if (ok) {
3326 WaitForSingleObject(tls->pthread_cond_helper_mutex, INFINITE);
3327 }
3328 }
3329 /* This thread has been removed from cv's waiting list */
3330 pthread_mutex_lock(mutex);
3331
3332 return ok ? 0 : -1;
3333 }
3334
3335
3336 static int
pthread_cond_wait(pthread_cond_t * cv,pthread_mutex_t * mutex)3337 pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
3338 {
3339 return pthread_cond_timedwait(cv, mutex, NULL);
3340 }
3341
3342
3343 static int
pthread_cond_signal(pthread_cond_t * cv)3344 pthread_cond_signal(pthread_cond_t *cv)
3345 {
3346 HANDLE wkup = NULL;
3347 BOOL ok = FALSE;
3348
3349 EnterCriticalSection(&cv->threadIdSec);
3350 if (cv->waiting_thread) {
3351 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
3352 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
3353
3354 ok = SetEvent(wkup);
3355 assert(ok);
3356 }
3357 LeaveCriticalSection(&cv->threadIdSec);
3358
3359 return ok ? 0 : 1;
3360 }
3361
3362
3363 static int
pthread_cond_broadcast(pthread_cond_t * cv)3364 pthread_cond_broadcast(pthread_cond_t *cv)
3365 {
3366 EnterCriticalSection(&cv->threadIdSec);
3367 while (cv->waiting_thread) {
3368 pthread_cond_signal(cv);
3369 }
3370 LeaveCriticalSection(&cv->threadIdSec);
3371
3372 return 0;
3373 }
3374
3375
3376 static int
pthread_cond_destroy(pthread_cond_t * cv)3377 pthread_cond_destroy(pthread_cond_t *cv)
3378 {
3379 EnterCriticalSection(&cv->threadIdSec);
3380 assert(cv->waiting_thread == NULL);
3381 LeaveCriticalSection(&cv->threadIdSec);
3382 DeleteCriticalSection(&cv->threadIdSec);
3383
3384 return 0;
3385 }
3386
3387
3388 #ifdef ALTERNATIVE_QUEUE
3389 static void *
event_create(void)3390 event_create(void)
3391 {
3392 return (void *)CreateEvent(NULL, FALSE, FALSE, NULL);
3393 }
3394
3395
3396 static int
event_wait(void * eventhdl)3397 event_wait(void *eventhdl)
3398 {
3399 int res = WaitForSingleObject((HANDLE)eventhdl, INFINITE);
3400 return (res == WAIT_OBJECT_0);
3401 }
3402
3403
3404 static int
event_signal(void * eventhdl)3405 event_signal(void *eventhdl)
3406 {
3407 return (int)SetEvent((HANDLE)eventhdl);
3408 }
3409
3410
3411 static void
event_destroy(void * eventhdl)3412 event_destroy(void *eventhdl)
3413 {
3414 CloseHandle((HANDLE)eventhdl);
3415 }
3416 #endif
3417
3418
3419 #if defined(__MINGW32__)
3420 /* Enable unused function warning again */
3421 #pragma GCC diagnostic pop
3422 #endif
3423
3424
3425 /* For Windows, change all slashes to backslashes in path names. */
3426 static void
change_slashes_to_backslashes(char * path)3427 change_slashes_to_backslashes(char *path)
3428 {
3429 int i;
3430
3431 for (i = 0; path[i] != '\0'; i++) {
3432 if (path[i] == '/') {
3433 path[i] = '\\';
3434 }
3435
3436 /* remove double backslash (check i > 0 to preserve UNC paths,
3437 * like \\server\file.txt) */
3438 if ((path[i] == '\\') && (i > 0)) {
3439 while (path[i + 1] == '\\' || path[i + 1] == '/') {
3440 (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
3441 }
3442 }
3443 }
3444 }
3445
3446
3447 static int
mg_wcscasecmp(const wchar_t * s1,const wchar_t * s2)3448 mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2)
3449 {
3450 int diff;
3451
3452 do {
3453 diff = tolower(*s1) - tolower(*s2);
3454 s1++;
3455 s2++;
3456 } while (diff == 0 && s1[-1] != '\0');
3457
3458 return diff;
3459 }
3460
3461
3462 /* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
3463 * wbuf and wbuf_len is a target buffer and its length. */
3464 static void
path_to_unicode(const struct mg_connection * conn,const char * path,wchar_t * wbuf,size_t wbuf_len)3465 path_to_unicode(const struct mg_connection *conn,
3466 const char *path,
3467 wchar_t *wbuf,
3468 size_t wbuf_len)
3469 {
3470 char buf[PATH_MAX], buf2[PATH_MAX];
3471 wchar_t wbuf2[MAX_PATH + 1];
3472 DWORD long_len, err;
3473 int (*fcompare)(const wchar_t *, const wchar_t *) = mg_wcscasecmp;
3474
3475 mg_strlcpy(buf, path, sizeof(buf));
3476 change_slashes_to_backslashes(buf);
3477
3478 /* Convert to Unicode and back. If doubly-converted string does not
3479 * match the original, something is fishy, reject. */
3480 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
3481 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
3482 WideCharToMultiByte(
3483 CP_UTF8, 0, wbuf, (int)wbuf_len, buf2, sizeof(buf2), NULL, NULL);
3484 if (strcmp(buf, buf2) != 0) {
3485 wbuf[0] = L'\0';
3486 }
3487
3488 /* Windows file systems are not case sensitive, but you can still use
3489 * uppercase and lowercase letters (on all modern file systems).
3490 * The server can check if the URI uses the same upper/lowercase
3491 * letters an the file system, effectively making Windows servers
3492 * case sensitive (like Linux servers are). It is still not possible
3493 * to use two files with the same name in different cases on Windows
3494 * (like /a and /A) - this would be possible in Linux.
3495 * As a default, Windows is not case sensitive, but the case sensitive
3496 * file name check can be activated by an additional configuration. */
3497 if (conn) {
3498 if (conn->ctx->config[CASE_SENSITIVE_FILES]
3499 && !mg_strcasecmp(conn->ctx->config[CASE_SENSITIVE_FILES], "yes")) {
3500 /* Use case sensitive compare function */
3501 fcompare = wcscmp;
3502 }
3503 }
3504 (void)conn; /* conn is currently unused */
3505
3506 #if !defined(_WIN32_WCE)
3507 /* Only accept a full file path, not a Windows short (8.3) path. */
3508 memset(wbuf2, 0, ARRAY_SIZE(wbuf2) * sizeof(wchar_t));
3509 long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1);
3510 if (long_len == 0) {
3511 err = GetLastError();
3512 if (err == ERROR_FILE_NOT_FOUND) {
3513 /* File does not exist. This is not always a problem here. */
3514 return;
3515 }
3516 }
3517 if ((long_len >= ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
3518 /* Short name is used. */
3519 wbuf[0] = L'\0';
3520 }
3521 #else
3522 (void)long_len;
3523 (void)wbuf2;
3524 (void)err;
3525
3526 if (strchr(path, '~')) {
3527 wbuf[0] = L'\0';
3528 }
3529 #endif
3530 }
3531
3532
3533 /* Windows happily opens files with some garbage at the end of file name.
3534 * For example, fopen("a.cgi ", "r") on Windows successfully opens
3535 * "a.cgi", despite one would expect an error back.
3536 * This function returns non-0 if path ends with some garbage. */
3537 static int
path_cannot_disclose_cgi(const char * path)3538 path_cannot_disclose_cgi(const char *path)
3539 {
3540 static const char *allowed_last_characters = "_-";
3541 int last = path[strlen(path) - 1];
3542 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
3543 }
3544
3545
3546 static int
mg_stat(const struct mg_connection * conn,const char * path,struct mg_file_stat * filep)3547 mg_stat(const struct mg_connection *conn,
3548 const char *path,
3549 struct mg_file_stat *filep)
3550 {
3551 wchar_t wbuf[PATH_MAX];
3552 WIN32_FILE_ATTRIBUTE_DATA info;
3553 time_t creation_time;
3554
3555 if (!filep) {
3556 return 0;
3557 }
3558 memset(filep, 0, sizeof(*filep));
3559
3560 if (conn && is_file_in_memory(conn, path)) {
3561 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
3562 * memset */
3563 filep->last_modified = time(NULL); /* xxxxxxxx */
3564 /* last_modified = now ... assumes the file may change during runtime,
3565 * so every mg_fopen call may return different data */
3566 /* last_modified = conn->ctx.start_time;
3567 * May be used it the data does not change during runtime. This allows
3568 * browser caching. Since we do not know, we have to assume the file
3569 * in memory may change. */
3570 return 1;
3571 }
3572
3573 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
3574 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
3575 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
3576 filep->last_modified =
3577 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
3578 info.ftLastWriteTime.dwHighDateTime);
3579
3580 /* On Windows, the file creation time can be higher than the
3581 * modification time, e.g. when a file is copied.
3582 * Since the Last-Modified timestamp is used for caching
3583 * it should be based on the most recent timestamp. */
3584 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
3585 info.ftCreationTime.dwHighDateTime);
3586 if (creation_time > filep->last_modified) {
3587 filep->last_modified = creation_time;
3588 }
3589
3590 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
3591 /* If file name is fishy, reset the file structure and return
3592 * error.
3593 * Note it is important to reset, not just return the error, cause
3594 * functions like is_file_opened() check the struct. */
3595 if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
3596 memset(filep, 0, sizeof(*filep));
3597 return 0;
3598 }
3599
3600 return 1;
3601 }
3602
3603 return 0;
3604 }
3605
3606
3607 static int
mg_remove(const struct mg_connection * conn,const char * path)3608 mg_remove(const struct mg_connection *conn, const char *path)
3609 {
3610 wchar_t wbuf[PATH_MAX];
3611 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
3612 return DeleteFileW(wbuf) ? 0 : -1;
3613 }
3614
3615
3616 static int
mg_mkdir(const struct mg_connection * conn,const char * path,int mode)3617 mg_mkdir(const struct mg_connection *conn, const char *path, int mode)
3618 {
3619 wchar_t wbuf[PATH_MAX];
3620 (void)mode;
3621 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
3622 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
3623 }
3624
3625
3626 /* Create substitutes for POSIX functions in Win32. */
3627
3628 #if defined(__MINGW32__)
3629 /* Show no warning in case system functions are not used. */
3630 #pragma GCC diagnostic push
3631 #pragma GCC diagnostic ignored "-Wunused-function"
3632 #endif
3633
3634
3635 /* Implementation of POSIX opendir/closedir/readdir for Windows. */
3636 static DIR *
mg_opendir(const struct mg_connection * conn,const char * name)3637 mg_opendir(const struct mg_connection *conn, const char *name)
3638 {
3639 DIR *dir = NULL;
3640 wchar_t wpath[PATH_MAX];
3641 DWORD attrs;
3642
3643 if (name == NULL) {
3644 SetLastError(ERROR_BAD_ARGUMENTS);
3645 } else if ((dir = (DIR *)mg_malloc(sizeof(*dir))) == NULL) {
3646 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3647 } else {
3648 path_to_unicode(conn, name, wpath, ARRAY_SIZE(wpath));
3649 attrs = GetFileAttributesW(wpath);
3650 if (attrs != 0xFFFFFFFF && ((attrs & FILE_ATTRIBUTE_DIRECTORY)
3651 == FILE_ATTRIBUTE_DIRECTORY)) {
3652 (void)wcscat(wpath, L"\\*");
3653 dir->handle = FindFirstFileW(wpath, &dir->info);
3654 dir->result.d_name[0] = '\0';
3655 } else {
3656 mg_free(dir);
3657 dir = NULL;
3658 }
3659 }
3660
3661 return dir;
3662 }
3663
3664
3665 static int
mg_closedir(DIR * dir)3666 mg_closedir(DIR *dir)
3667 {
3668 int result = 0;
3669
3670 if (dir != NULL) {
3671 if (dir->handle != INVALID_HANDLE_VALUE)
3672 result = FindClose(dir->handle) ? 0 : -1;
3673
3674 mg_free(dir);
3675 } else {
3676 result = -1;
3677 SetLastError(ERROR_BAD_ARGUMENTS);
3678 }
3679
3680 return result;
3681 }
3682
3683
3684 static struct dirent *
mg_readdir(DIR * dir)3685 mg_readdir(DIR *dir)
3686 {
3687 struct dirent *result = 0;
3688
3689 if (dir) {
3690 if (dir->handle != INVALID_HANDLE_VALUE) {
3691 result = &dir->result;
3692 (void)WideCharToMultiByte(CP_UTF8,
3693 0,
3694 dir->info.cFileName,
3695 -1,
3696 result->d_name,
3697 sizeof(result->d_name),
3698 NULL,
3699 NULL);
3700
3701 if (!FindNextFileW(dir->handle, &dir->info)) {
3702 (void)FindClose(dir->handle);
3703 dir->handle = INVALID_HANDLE_VALUE;
3704 }
3705
3706 } else {
3707 SetLastError(ERROR_FILE_NOT_FOUND);
3708 }
3709 } else {
3710 SetLastError(ERROR_BAD_ARGUMENTS);
3711 }
3712
3713 return result;
3714 }
3715
3716
3717 #ifndef HAVE_POLL
3718 static int
poll(struct pollfd * pfd,unsigned int n,int milliseconds)3719 poll(struct pollfd *pfd, unsigned int n, int milliseconds)
3720 {
3721 struct timeval tv;
3722 fd_set set;
3723 unsigned int i;
3724 int result;
3725 SOCKET maxfd = 0;
3726
3727 memset(&tv, 0, sizeof(tv));
3728 tv.tv_sec = milliseconds / 1000;
3729 tv.tv_usec = (milliseconds % 1000) * 1000;
3730 FD_ZERO(&set);
3731
3732 for (i = 0; i < n; i++) {
3733 FD_SET((SOCKET)pfd[i].fd, &set);
3734 pfd[i].revents = 0;
3735
3736 if (pfd[i].fd > maxfd) {
3737 maxfd = pfd[i].fd;
3738 }
3739 }
3740
3741 if ((result = select((int)maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
3742 for (i = 0; i < n; i++) {
3743 if (FD_ISSET(pfd[i].fd, &set)) {
3744 pfd[i].revents = POLLIN;
3745 }
3746 }
3747 }
3748
3749 /* We should subtract the time used in select from remaining
3750 * "milliseconds", in particular if called from mg_poll with a
3751 * timeout quantum.
3752 * Unfortunately, the remaining time is not stored in "tv" in all
3753 * implementations, so the result in "tv" must be considered undefined.
3754 * See http://man7.org/linux/man-pages/man2/select.2.html */
3755
3756 return result;
3757 }
3758 #endif /* HAVE_POLL */
3759
3760
3761 #if defined(__MINGW32__)
3762 /* Enable unused function warning again */
3763 #pragma GCC diagnostic pop
3764 #endif
3765
3766
3767 static void
set_close_on_exec(SOCKET sock,struct mg_connection * conn)3768 set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
3769 {
3770 (void)conn; /* Unused. */
3771 #if defined(_WIN32_WCE)
3772 (void)sock;
3773 #else
3774 (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
3775 #endif
3776 }
3777
3778
3779 int
mg_start_thread(mg_thread_func_t f,void * p)3780 mg_start_thread(mg_thread_func_t f, void *p)
3781 {
3782 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3783 /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
3784 */
3785 return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p)
3786 == ((uintptr_t)(-1L)))
3787 ? -1
3788 : 0);
3789 #else
3790 return (
3791 (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L)))
3792 ? -1
3793 : 0);
3794 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3795 }
3796
3797
3798 /* Start a thread storing the thread context. */
3799 static int
mg_start_thread_with_id(unsigned (__stdcall * f)(void *),void * p,pthread_t * threadidptr)3800 mg_start_thread_with_id(unsigned(__stdcall *f)(void *),
3801 void *p,
3802 pthread_t *threadidptr)
3803 {
3804 uintptr_t uip;
3805 HANDLE threadhandle;
3806 int result = -1;
3807
3808 uip = _beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))f, p, 0, NULL);
3809 threadhandle = (HANDLE)uip;
3810 if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
3811 *threadidptr = threadhandle;
3812 result = 0;
3813 }
3814
3815 return result;
3816 }
3817
3818
3819 /* Wait for a thread to finish. */
3820 static int
mg_join_thread(pthread_t threadid)3821 mg_join_thread(pthread_t threadid)
3822 {
3823 int result;
3824 DWORD dwevent;
3825
3826 result = -1;
3827 dwevent = WaitForSingleObject(threadid, INFINITE);
3828 if (dwevent == WAIT_FAILED) {
3829 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO);
3830 } else {
3831 if (dwevent == WAIT_OBJECT_0) {
3832 CloseHandle(threadid);
3833 result = 0;
3834 }
3835 }
3836
3837 return result;
3838 }
3839
3840 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
3841 /* If SSL is loaded dynamically, dlopen/dlclose is required. */
3842 /* Create substitutes for POSIX functions in Win32. */
3843
3844 #if defined(__MINGW32__)
3845 /* Show no warning in case system functions are not used. */
3846 #pragma GCC diagnostic push
3847 #pragma GCC diagnostic ignored "-Wunused-function"
3848 #endif
3849
3850
3851 static HANDLE
dlopen(const char * dll_name,int flags)3852 dlopen(const char *dll_name, int flags)
3853 {
3854 wchar_t wbuf[PATH_MAX];
3855 (void)flags;
3856 path_to_unicode(NULL, dll_name, wbuf, ARRAY_SIZE(wbuf));
3857 return LoadLibraryW(wbuf);
3858 }
3859
3860
3861 static int
dlclose(void * handle)3862 dlclose(void *handle)
3863 {
3864 int result;
3865
3866 if (FreeLibrary((HMODULE)handle) != 0) {
3867 result = 0;
3868 } else {
3869 result = -1;
3870 }
3871
3872 return result;
3873 }
3874
3875
3876 #if defined(__MINGW32__)
3877 /* Enable unused function warning again */
3878 #pragma GCC diagnostic pop
3879 #endif
3880
3881 #endif
3882
3883
3884 #if !defined(NO_CGI)
3885 #define SIGKILL (0)
3886
3887 static int
kill(pid_t pid,int sig_num)3888 kill(pid_t pid, int sig_num)
3889 {
3890 (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
3891 (void)CloseHandle((HANDLE)pid);
3892 return 0;
3893 }
3894
3895
3896 static void
trim_trailing_whitespaces(char * s)3897 trim_trailing_whitespaces(char *s)
3898 {
3899 char *e = s + strlen(s) - 1;
3900 while (e > s && isspace(*(unsigned char *)e)) {
3901 *e-- = '\0';
3902 }
3903 }
3904
3905
3906 static pid_t
spawn_process(struct mg_connection * conn,const char * prog,char * envblk,char * envp[],int fdin[2],int fdout[2],int fderr[2],const char * dir)3907 spawn_process(struct mg_connection *conn,
3908 const char *prog,
3909 char *envblk,
3910 char *envp[],
3911 int fdin[2],
3912 int fdout[2],
3913 int fderr[2],
3914 const char *dir)
3915 {
3916 HANDLE me;
3917 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
3918 cmdline[PATH_MAX], buf[PATH_MAX];
3919 int truncated;
3920 struct mg_file file = STRUCT_FILE_INITIALIZER;
3921 STARTUPINFOA si;
3922 PROCESS_INFORMATION pi = {0};
3923
3924 (void)envp;
3925
3926 memset(&si, 0, sizeof(si));
3927 si.cb = sizeof(si);
3928
3929 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
3930 si.wShowWindow = SW_HIDE;
3931
3932 me = GetCurrentProcess();
3933 DuplicateHandle(me,
3934 (HANDLE)_get_osfhandle(fdin[0]),
3935 me,
3936 &si.hStdInput,
3937 0,
3938 TRUE,
3939 DUPLICATE_SAME_ACCESS);
3940 DuplicateHandle(me,
3941 (HANDLE)_get_osfhandle(fdout[1]),
3942 me,
3943 &si.hStdOutput,
3944 0,
3945 TRUE,
3946 DUPLICATE_SAME_ACCESS);
3947 DuplicateHandle(me,
3948 (HANDLE)_get_osfhandle(fderr[1]),
3949 me,
3950 &si.hStdError,
3951 0,
3952 TRUE,
3953 DUPLICATE_SAME_ACCESS);
3954
3955 /* Mark handles that should not be inherited. See
3956 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
3957 */
3958 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
3959 HANDLE_FLAG_INHERIT,
3960 0);
3961 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
3962 HANDLE_FLAG_INHERIT,
3963 0);
3964 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
3965 HANDLE_FLAG_INHERIT,
3966 0);
3967
3968 /* If CGI file is a script, try to read the interpreter line */
3969 interp = conn->ctx->config[CGI_INTERPRETER];
3970 if (interp == NULL) {
3971 buf[0] = buf[1] = '\0';
3972
3973 /* Read the first line of the script into the buffer */
3974 mg_snprintf(
3975 conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
3976
3977 if (truncated) {
3978 pi.hProcess = (pid_t)-1;
3979 goto spawn_cleanup;
3980 }
3981
3982 if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) {
3983 p = (char *)file.access.membuf;
3984 mg_fgets(buf, sizeof(buf), &file, &p);
3985 (void)mg_fclose(&file.access); /* ignore error on read only file */
3986 buf[sizeof(buf) - 1] = '\0';
3987 }
3988
3989 if (buf[0] == '#' && buf[1] == '!') {
3990 trim_trailing_whitespaces(buf + 2);
3991 } else {
3992 buf[2] = '\0';
3993 }
3994 interp = buf + 2;
3995 }
3996
3997 if (interp[0] != '\0') {
3998 GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
3999 interp = full_interp;
4000 }
4001 GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
4002
4003 if (interp[0] != '\0') {
4004 mg_snprintf(conn,
4005 &truncated,
4006 cmdline,
4007 sizeof(cmdline),
4008 "\"%s\" \"%s\\%s\"",
4009 interp,
4010 full_dir,
4011 prog);
4012 } else {
4013 mg_snprintf(conn,
4014 &truncated,
4015 cmdline,
4016 sizeof(cmdline),
4017 "\"%s\\%s\"",
4018 full_dir,
4019 prog);
4020 }
4021
4022 if (truncated) {
4023 pi.hProcess = (pid_t)-1;
4024 goto spawn_cleanup;
4025 }
4026
4027 DEBUG_TRACE("Running [%s]", cmdline);
4028 if (CreateProcessA(NULL,
4029 cmdline,
4030 NULL,
4031 NULL,
4032 TRUE,
4033 CREATE_NEW_PROCESS_GROUP,
4034 envblk,
4035 NULL,
4036 &si,
4037 &pi) == 0) {
4038 mg_cry(
4039 conn, "%s: CreateProcess(%s): %ld", __func__, cmdline, (long)ERRNO);
4040 pi.hProcess = (pid_t)-1;
4041 /* goto spawn_cleanup; */
4042 }
4043
4044 spawn_cleanup:
4045 (void)CloseHandle(si.hStdOutput);
4046 (void)CloseHandle(si.hStdError);
4047 (void)CloseHandle(si.hStdInput);
4048 if (pi.hThread != NULL) {
4049 (void)CloseHandle(pi.hThread);
4050 }
4051
4052 return (pid_t)pi.hProcess;
4053 }
4054 #endif /* !NO_CGI */
4055
4056
4057 static int
set_blocking_mode(SOCKET sock,int blocking)4058 set_blocking_mode(SOCKET sock, int blocking)
4059 {
4060 unsigned long non_blocking = !blocking;
4061 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
4062 }
4063
4064 #else
4065
4066 static int
mg_stat(const struct mg_connection * conn,const char * path,struct mg_file_stat * filep)4067 mg_stat(const struct mg_connection *conn,
4068 const char *path,
4069 struct mg_file_stat *filep)
4070 {
4071 struct stat st;
4072 if (!filep) {
4073 return 0;
4074 }
4075 memset(filep, 0, sizeof(*filep));
4076
4077 if (conn && is_file_in_memory(conn, path)) {
4078 return 1;
4079 }
4080
4081 if (0 == stat(path, &st)) {
4082 filep->size = (uint64_t)(st.st_size);
4083 filep->last_modified = st.st_mtime;
4084 filep->is_directory = S_ISDIR(st.st_mode);
4085 return 1;
4086 }
4087
4088 return 0;
4089 }
4090
4091
4092 static void
set_close_on_exec(SOCKET fd,struct mg_connection * conn)4093 set_close_on_exec(SOCKET fd, struct mg_connection *conn /* may be null */)
4094 {
4095 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
4096 if (conn) {
4097 mg_cry(conn,
4098 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
4099 __func__,
4100 strerror(ERRNO));
4101 }
4102 }
4103 }
4104
4105
4106 int
mg_start_thread(mg_thread_func_t func,void * param)4107 mg_start_thread(mg_thread_func_t func, void *param)
4108 {
4109 pthread_t thread_id;
4110 pthread_attr_t attr;
4111 int result;
4112
4113 (void)pthread_attr_init(&attr);
4114 (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4115
4116 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
4117 /* Compile-time option to control stack size,
4118 * e.g. -DUSE_STACK_SIZE=16384 */
4119 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
4120 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
4121
4122 result = pthread_create(&thread_id, &attr, func, param);
4123 pthread_attr_destroy(&attr);
4124
4125 return result;
4126 }
4127
4128
4129 /* Start a thread storing the thread context. */
4130 static int
mg_start_thread_with_id(mg_thread_func_t func,void * param,pthread_t * threadidptr)4131 mg_start_thread_with_id(mg_thread_func_t func,
4132 void *param,
4133 pthread_t *threadidptr)
4134 {
4135 pthread_t thread_id;
4136 pthread_attr_t attr;
4137 int result;
4138
4139 (void)pthread_attr_init(&attr);
4140
4141 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
4142 /* Compile-time option to control stack size,
4143 * e.g. -DUSE_STACK_SIZE=16384 */
4144 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
4145 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
4146
4147 result = pthread_create(&thread_id, &attr, func, param);
4148 pthread_attr_destroy(&attr);
4149 if ((result == 0) && (threadidptr != NULL)) {
4150 *threadidptr = thread_id;
4151 }
4152 return result;
4153 }
4154
4155
4156 /* Wait for a thread to finish. */
4157 static int
mg_join_thread(pthread_t threadid)4158 mg_join_thread(pthread_t threadid)
4159 {
4160 int result;
4161
4162 result = pthread_join(threadid, NULL);
4163 return result;
4164 }
4165
4166
4167 #ifndef NO_CGI
4168 static pid_t
spawn_process(struct mg_connection * conn,const char * prog,char * envblk,char * envp[],int fdin[2],int fdout[2],int fderr[2],const char * dir)4169 spawn_process(struct mg_connection *conn,
4170 const char *prog,
4171 char *envblk,
4172 char *envp[],
4173 int fdin[2],
4174 int fdout[2],
4175 int fderr[2],
4176 const char *dir)
4177 {
4178 pid_t pid;
4179 const char *interp;
4180
4181 (void)envblk;
4182
4183 if (conn == NULL) {
4184 return 0;
4185 }
4186
4187 if ((pid = fork()) == -1) {
4188 /* Parent */
4189 send_http_error(conn,
4190 500,
4191 "Error: Creating CGI process\nfork(): %s",
4192 strerror(ERRNO));
4193 } else if (pid == 0) {
4194 /* Child */
4195 if (chdir(dir) != 0) {
4196 mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
4197 } else if (dup2(fdin[0], 0) == -1) {
4198 mg_cry(conn,
4199 "%s: dup2(%d, 0): %s",
4200 __func__,
4201 fdin[0],
4202 strerror(ERRNO));
4203 } else if (dup2(fdout[1], 1) == -1) {
4204 mg_cry(conn,
4205 "%s: dup2(%d, 1): %s",
4206 __func__,
4207 fdout[1],
4208 strerror(ERRNO));
4209 } else if (dup2(fderr[1], 2) == -1) {
4210 mg_cry(conn,
4211 "%s: dup2(%d, 2): %s",
4212 __func__,
4213 fderr[1],
4214 strerror(ERRNO));
4215 } else {
4216 /* Keep stderr and stdout in two different pipes.
4217 * Stdout will be sent back to the client,
4218 * stderr should go into a server error log. */
4219 (void)close(fdin[0]);
4220 (void)close(fdout[1]);
4221 (void)close(fderr[1]);
4222
4223 /* Close write end fdin and read end fdout and fderr */
4224 (void)close(fdin[1]);
4225 (void)close(fdout[0]);
4226 (void)close(fderr[0]);
4227
4228 /* After exec, all signal handlers are restored to their default
4229 * values, with one exception of SIGCHLD. According to
4230 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
4231 * leave unchanged after exec if it was set to be ignored. Restore
4232 * it to default action. */
4233 signal(SIGCHLD, SIG_DFL);
4234
4235 interp = conn->ctx->config[CGI_INTERPRETER];
4236 if (interp == NULL) {
4237 (void)execle(prog, prog, NULL, envp);
4238 mg_cry(conn,
4239 "%s: execle(%s): %s",
4240 __func__,
4241 prog,
4242 strerror(ERRNO));
4243 } else {
4244 (void)execle(interp, interp, prog, NULL, envp);
4245 mg_cry(conn,
4246 "%s: execle(%s %s): %s",
4247 __func__,
4248 interp,
4249 prog,
4250 strerror(ERRNO));
4251 }
4252 }
4253 exit(EXIT_FAILURE);
4254 }
4255
4256 return pid;
4257 }
4258 #endif /* !NO_CGI */
4259
4260
4261 static int
set_blocking_mode(SOCKET sock,int blocking)4262 set_blocking_mode(SOCKET sock, int blocking)
4263 {
4264 int flags;
4265
4266 flags = fcntl(sock, F_GETFL, 0);
4267 if (blocking) {
4268 (void)fcntl(sock, F_SETFL, flags | O_NONBLOCK);
4269 } else {
4270 (void)fcntl(sock, F_SETFL, flags & (~(int)(O_NONBLOCK)));
4271 }
4272
4273 return 0;
4274 }
4275 #endif /* _WIN32 */
4276 /* End of initial operating system specific define block. */
4277
4278
4279 /* Get a random number (independent of C rand function) */
4280 static uint64_t
get_random(void)4281 get_random(void)
4282 {
4283 static uint64_t lfsr = 0; /* Linear feedback shift register */
4284 static uint64_t lcg = 0; /* Linear congruential generator */
4285 struct timespec now;
4286
4287 memset(&now, 0, sizeof(now));
4288 clock_gettime(CLOCK_MONOTONIC, &now);
4289
4290 if (lfsr == 0) {
4291 /* lfsr will be only 0 if has not been initialized,
4292 * so this code is called only once. */
4293 lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
4294 ^ ((uint64_t)(ptrdiff_t)&now) ^ (((uint64_t)time(NULL)) << 33);
4295 lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
4296 + (uint64_t)(ptrdiff_t)&now;
4297 } else {
4298 /* Get the next step of both random number generators. */
4299 lfsr = (lfsr >> 1)
4300 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
4301 << 63);
4302 lcg = lcg * 6364136223846793005 + 1442695040888963407;
4303 }
4304
4305 /* Combining two pseudo-random number generators and a high resolution part
4306 * of the current server time will make it hard (impossible?) to guess the
4307 * next number. */
4308 return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec);
4309 }
4310
4311
4312 static int
mg_poll(struct pollfd * pfd,unsigned int n,int milliseconds,volatile int * stop_server)4313 mg_poll(struct pollfd *pfd,
4314 unsigned int n,
4315 int milliseconds,
4316 volatile int *stop_server)
4317 {
4318 int ms_now, result;
4319
4320 /* Call poll, but only for a maximum time of a few seconds.
4321 * This will allow to stop the server after some seconds, instead
4322 * of having to wait for a long socket timeout. */
4323 ms_now = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
4324
4325 do {
4326 if (*stop_server) {
4327 /* Shut down signal */
4328 return -2;
4329 }
4330
4331 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
4332 ms_now = milliseconds;
4333 }
4334
4335 result = poll(pfd, n, ms_now);
4336 if (result != 0) {
4337 /* Poll returned either success (1) or error (-1).
4338 * Forward both to the caller. */
4339 return result;
4340 }
4341
4342 /* Poll returned timeout (0). */
4343 if (milliseconds > 0) {
4344 milliseconds -= ms_now;
4345 }
4346
4347 } while (milliseconds != 0);
4348
4349 return result;
4350 }
4351
4352
4353 /* Write data to the IO channel - opened file descriptor, socket or SSL
4354 * descriptor. Return number of bytes written. */
4355 static int
push(struct mg_context * ctx,FILE * fp,SOCKET sock,SSL * ssl,const char * buf,int len,double timeout)4356 push(struct mg_context *ctx,
4357 FILE *fp,
4358 SOCKET sock,
4359 SSL *ssl,
4360 const char *buf,
4361 int len,
4362 double timeout)
4363 {
4364 struct timespec start, now;
4365 int n, err;
4366
4367 #ifdef _WIN32
4368 typedef int len_t;
4369 #else
4370 typedef size_t len_t;
4371 #endif
4372
4373 if (timeout > 0) {
4374 memset(&start, 0, sizeof(start));
4375 memset(&now, 0, sizeof(now));
4376 clock_gettime(CLOCK_MONOTONIC, &start);
4377 }
4378
4379 if (ctx == NULL) {
4380 return -1;
4381 }
4382
4383 #ifdef NO_SSL
4384 if (ssl) {
4385 return -1;
4386 }
4387 #endif
4388
4389 do {
4390
4391 #ifndef NO_SSL
4392 if (ssl != NULL) {
4393 n = SSL_write(ssl, buf, len);
4394 if (n <= 0) {
4395 err = SSL_get_error(ssl, n);
4396 if ((err == SSL_ERROR_SYSCALL) && (n == -1)) {
4397 err = ERRNO;
4398 } else if ((err == SSL_ERROR_WANT_READ)
4399 || (err == SSL_ERROR_WANT_WRITE)) {
4400 n = 0;
4401 } else {
4402 DEBUG_TRACE("SSL_write() failed, error %d", err);
4403 return -1;
4404 }
4405 } else {
4406 err = 0;
4407 }
4408 } else
4409 #endif
4410 if (fp != NULL) {
4411 n = (int)fwrite(buf, 1, (size_t)len, fp);
4412 if (ferror(fp)) {
4413 n = -1;
4414 err = ERRNO;
4415 } else {
4416 err = 0;
4417 }
4418 } else {
4419 n = (int)send(sock, buf, (len_t)len, MSG_NOSIGNAL);
4420 err = (n < 0) ? ERRNO : 0;
4421 if (n <= 0) {
4422 /* shutdown of the socket at client side */
4423 return -1;
4424 }
4425 #if defined(TEMPORARY_INSTRUMENTATION)
4426 {
4427 FILE *f = fopen("r:\\all.txt", "ab");
4428 fprintf(f, "\r\n%010u SEND:\r\n", GetTickCount());
4429 fwrite(buf, 1, n, f);
4430 fclose(f);
4431 }
4432 #endif
4433 }
4434
4435 if (ctx->stop_flag) {
4436 return -1;
4437 }
4438
4439 if ((n > 0) || (n == 0 && len == 0)) {
4440 /* some data has been read, or no data was requested */
4441 return n;
4442 }
4443 if (n < 0) {
4444 /* socket error - check errno */
4445 DEBUG_TRACE("send() failed, error %d", err);
4446
4447 /* TODO: error handling depending on the error code.
4448 * These codes are different between Windows and Linux.
4449 */
4450 return -1;
4451 }
4452
4453 /* Only in case n=0 (timeout), repeat calling the write function */
4454
4455 if (timeout > 0) {
4456 clock_gettime(CLOCK_MONOTONIC, &now);
4457 }
4458
4459 } while ((timeout <= 0) || (mg_difftimespec(&now, &start) <= timeout));
4460
4461 (void)err; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
4462 used */
4463
4464 return -1;
4465 }
4466
4467
4468 static int64_t
push_all(struct mg_context * ctx,FILE * fp,SOCKET sock,SSL * ssl,const char * buf,int64_t len)4469 push_all(struct mg_context *ctx,
4470 FILE *fp,
4471 SOCKET sock,
4472 SSL *ssl,
4473 const char *buf,
4474 int64_t len)
4475 {
4476 double timeout = -1.0;
4477 int64_t n, nwritten = 0;
4478
4479 if (ctx == NULL) {
4480 return -1;
4481 }
4482
4483 if (ctx->config[REQUEST_TIMEOUT]) {
4484 timeout = atoi(ctx->config[REQUEST_TIMEOUT]) / 1000.0;
4485 }
4486
4487 while (len > 0 && ctx->stop_flag == 0) {
4488 n = push(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout);
4489 if (n < 0) {
4490 if (nwritten == 0) {
4491 nwritten = n; /* Propagate the error */
4492 }
4493 break;
4494 } else if (n == 0) {
4495 break; /* No more data to write */
4496 } else {
4497 nwritten += n;
4498 len -= n;
4499 }
4500 }
4501
4502 return nwritten;
4503 }
4504
4505
4506 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
4507 * Return negative value on error, or number of bytes read on success. */
4508 static int
pull(FILE * fp,struct mg_connection * conn,char * buf,int len,double timeout)4509 pull(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
4510 {
4511 int nread, err = 0;
4512
4513 #ifdef _WIN32
4514 typedef int len_t;
4515 #else
4516 typedef size_t len_t;
4517 #endif
4518
4519 if (fp != NULL) {
4520 #if !defined(_WIN32_WCE)
4521 /* Use read() instead of fread(), because if we're reading from the
4522 * CGI pipe, fread() may block until IO buffer is filled up. We
4523 * cannot afford to block and must pass all read bytes immediately
4524 * to the client. */
4525 nread = (int)read(fileno(fp), buf, (size_t)len);
4526 #else
4527 /* WinCE does not support CGI pipes */
4528 nread = (int)fread(buf, 1, (size_t)len, fp);
4529 #endif
4530 err = (nread < 0) ? ERRNO : 0;
4531
4532 #ifndef NO_SSL
4533 } else if (conn->ssl != NULL) {
4534
4535 struct pollfd pfd[1];
4536 int pollres;
4537
4538 pfd[0].fd = conn->client.sock;
4539 pfd[0].events = POLLIN;
4540 pollres =
4541 mg_poll(pfd, 1, (int)(timeout * 1000.0), &(conn->ctx->stop_flag));
4542 if (conn->ctx->stop_flag) {
4543 return -1;
4544 }
4545 if (pollres > 0) {
4546 nread = SSL_read(conn->ssl, buf, len);
4547 if (nread <= 0) {
4548 err = SSL_get_error(conn->ssl, nread);
4549 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
4550 err = ERRNO;
4551 } else if ((err == SSL_ERROR_WANT_READ)
4552 || (err == SSL_ERROR_WANT_WRITE)) {
4553 nread = 0;
4554 } else {
4555 DEBUG_TRACE("SSL_read() failed, error %d", err);
4556 return -1;
4557 }
4558 } else {
4559 err = 0;
4560 }
4561
4562 } else if (pollres < 0) {
4563 /* Error */
4564 return -1;
4565 } else {
4566 /* pollres = 0 means timeout */
4567 nread = 0;
4568 }
4569
4570 #endif
4571
4572 } else {
4573 struct pollfd pfd[1];
4574 int pollres;
4575
4576 pfd[0].fd = conn->client.sock;
4577 pfd[0].events = POLLIN;
4578 pollres =
4579 mg_poll(pfd, 1, (int)(timeout * 1000.0), &(conn->ctx->stop_flag));
4580 if (conn->ctx->stop_flag) {
4581 return -1;
4582 }
4583 if (pollres > 0) {
4584 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
4585 err = (nread < 0) ? ERRNO : 0;
4586 if (nread <= 0) {
4587 /* shutdown of the socket at client side */
4588 return -1;
4589 }
4590 #if defined(TEMPORARY_INSTRUMENTATION)
4591 {
4592 FILE *f = fopen("r:\\all.txt", "ab");
4593 fprintf(f, "\r\n%010u RECV:\r\n", GetTickCount());
4594 fwrite(buf, 1, nread, f);
4595 fclose(f);
4596 }
4597 #endif
4598 } else if (pollres < 0) {
4599 /* error callint poll */
4600 return -1;
4601 } else {
4602 /* pollres = 0 means timeout */
4603 nread = 0;
4604 }
4605 }
4606
4607 if (conn->ctx->stop_flag) {
4608 return -1;
4609 }
4610
4611 if ((nread > 0) || (nread == 0 && len == 0)) {
4612 /* some data has been read, or no data was requested */
4613 return nread;
4614 }
4615
4616 if (nread < 0) {
4617 /* socket error - check errno */
4618 #ifdef _WIN32
4619 if (err == WSAEWOULDBLOCK) {
4620 /* TODO: check if this is still required */
4621 /* standard case if called from close_socket_gracefully */
4622 return -1;
4623 } else if (err == WSAETIMEDOUT) {
4624 /* TODO: check if this is still required */
4625 /* timeout is handled by the while loop */
4626 return 0;
4627 } else if (err == WSAECONNABORTED) {
4628 /* See https://www.chilkatsoft.com/p/p_299.asp */
4629 return -1;
4630 } else {
4631 DEBUG_TRACE("recv() failed, error %d", err);
4632 return -1;
4633 }
4634 #else
4635 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
4636 * if the timeout is reached and if the socket was set to non-
4637 * blocking in close_socket_gracefully, so we can not distinguish
4638 * here. We have to wait for the timeout in both cases for now.
4639 */
4640 if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) {
4641 /* TODO: check if this is still required */
4642 /* EAGAIN/EWOULDBLOCK:
4643 * standard case if called from close_socket_gracefully
4644 * => should return -1 */
4645 /* or timeout occured
4646 * => the code must stay in the while loop */
4647
4648 /* EINTR can be generated on a socket with a timeout set even
4649 * when SA_RESTART is effective for all relevant signals
4650 * (see signal(7)).
4651 * => stay in the while loop */
4652 } else {
4653 DEBUG_TRACE("recv() failed, error %d", err);
4654 return -1;
4655 }
4656 #endif
4657 }
4658
4659 /* Timeout occured, but no data available. */
4660 return -1;
4661 }
4662
4663
4664 static int
pull_all(FILE * fp,struct mg_connection * conn,char * buf,int len)4665 pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
4666 {
4667 int n, nread = 0;
4668 double timeout = -1.0;
4669
4670 if (conn->ctx->config[REQUEST_TIMEOUT]) {
4671 timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
4672 }
4673
4674 while (len > 0 && conn->ctx->stop_flag == 0) {
4675 n = pull(fp, conn, buf + nread, len, timeout);
4676 if (n < 0) {
4677 if (nread == 0) {
4678 nread = n; /* Propagate the error */
4679 }
4680 break;
4681 } else if (n == 0) {
4682 break; /* No more data to read */
4683 } else {
4684 conn->consumed_content += n;
4685 nread += n;
4686 len -= n;
4687 }
4688 }
4689
4690 return nread;
4691 }
4692
4693
4694 static void
discard_unread_request_data(struct mg_connection * conn)4695 discard_unread_request_data(struct mg_connection *conn)
4696 {
4697 char buf[MG_BUF_LEN];
4698 size_t to_read;
4699 int nread;
4700
4701 if (conn == NULL) {
4702 return;
4703 }
4704
4705 to_read = sizeof(buf);
4706
4707 if (conn->is_chunked) {
4708 /* Chunked encoding: 1=chunk not read completely, 2=chunk read
4709 * completely */
4710 while (conn->is_chunked == 1) {
4711 nread = mg_read(conn, buf, to_read);
4712 if (nread <= 0) {
4713 break;
4714 }
4715 }
4716
4717 } else {
4718 /* Not chunked: content length is known */
4719 while (conn->consumed_content < conn->content_len) {
4720 if (to_read
4721 > (size_t)(conn->content_len - conn->consumed_content)) {
4722 to_read = (size_t)(conn->content_len - conn->consumed_content);
4723 }
4724
4725 nread = mg_read(conn, buf, to_read);
4726 if (nread <= 0) {
4727 break;
4728 }
4729 }
4730 }
4731 }
4732
4733
4734 static int
mg_read_inner(struct mg_connection * conn,void * buf,size_t len)4735 mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
4736 {
4737 int64_t n, buffered_len, nread;
4738 int64_t len64 =
4739 (int64_t)((len > INT_MAX) ? INT_MAX : len); /* since the return value is
4740 * int, we may not read more
4741 * bytes */
4742 const char *body;
4743
4744 if (conn == NULL) {
4745 return 0;
4746 }
4747
4748 /* If Content-Length is not set for a PUT or POST request, read until
4749 * socket is closed */
4750 if (conn->consumed_content == 0 && conn->content_len == -1) {
4751 conn->content_len = INT64_MAX;
4752 conn->must_close = 1;
4753 }
4754
4755 nread = 0;
4756 if (conn->consumed_content < conn->content_len) {
4757 /* Adjust number of bytes to read. */
4758 int64_t left_to_read = conn->content_len - conn->consumed_content;
4759 if (left_to_read < len64) {
4760 /* Do not read more than the total content length of the request.
4761 */
4762 len64 = left_to_read;
4763 }
4764
4765 /* Return buffered data */
4766 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
4767 - conn->consumed_content;
4768 if (buffered_len > 0) {
4769 if (len64 < buffered_len) {
4770 buffered_len = len64;
4771 }
4772 body = conn->buf + conn->request_len + conn->consumed_content;
4773 memcpy(buf, body, (size_t)buffered_len);
4774 len64 -= buffered_len;
4775 conn->consumed_content += buffered_len;
4776 nread += buffered_len;
4777 buf = (char *)buf + buffered_len;
4778 }
4779
4780 /* We have returned all buffered data. Read new data from the remote
4781 * socket.
4782 */
4783 if ((n = pull_all(NULL, conn, (char *)buf, (int)len64)) >= 0) {
4784 nread += n;
4785 } else {
4786 nread = ((nread > 0) ? nread : n);
4787 }
4788 }
4789 return (int)nread;
4790 }
4791
4792
4793 static char
mg_getc(struct mg_connection * conn)4794 mg_getc(struct mg_connection *conn)
4795 {
4796 char c;
4797 if (conn == NULL) {
4798 return 0;
4799 }
4800 conn->content_len++;
4801 if (mg_read_inner(conn, &c, 1) <= 0) {
4802 return (char)0;
4803 }
4804 return c;
4805 }
4806
4807
4808 int
mg_read(struct mg_connection * conn,void * buf,size_t len)4809 mg_read(struct mg_connection *conn, void *buf, size_t len)
4810 {
4811 if (len > INT_MAX) {
4812 len = INT_MAX;
4813 }
4814
4815 if (conn == NULL) {
4816 return 0;
4817 }
4818
4819 if (conn->is_chunked) {
4820 size_t all_read = 0;
4821
4822 while (len > 0) {
4823
4824 if (conn->is_chunked == 2) {
4825 /* No more data left to read */
4826 return 0;
4827 }
4828
4829 if (conn->chunk_remainder) {
4830 /* copy from the remainder of the last received chunk */
4831 long read_ret;
4832 size_t read_now =
4833 ((conn->chunk_remainder > len) ? (len)
4834 : (conn->chunk_remainder));
4835
4836 conn->content_len += (int)read_now;
4837 read_ret =
4838 mg_read_inner(conn, (char *)buf + all_read, read_now);
4839
4840 if (read_ret < 1) {
4841 /* read error */
4842 return -1;
4843 }
4844
4845 all_read += (size_t)read_ret;
4846 conn->chunk_remainder -= (size_t)read_ret;
4847 len -= (size_t)read_ret;
4848
4849 if (conn->chunk_remainder == 0) {
4850 /* Add data bytes in the current chunk have been read,
4851 * so we are expecting \r\n now. */
4852 char x1 = mg_getc(conn);
4853 char x2 = mg_getc(conn);
4854 if ((x1 != '\r') || (x2 != '\n')) {
4855 /* Protocol violation */
4856 return -1;
4857 }
4858 }
4859
4860 } else {
4861 /* fetch a new chunk */
4862 int i = 0;
4863 char lenbuf[64];
4864 char *end = 0;
4865 unsigned long chunkSize = 0;
4866
4867 for (i = 0; i < ((int)sizeof(lenbuf) - 1); i++) {
4868 lenbuf[i] = mg_getc(conn);
4869 if (i > 0 && lenbuf[i] == '\r' && lenbuf[i - 1] != '\r') {
4870 continue;
4871 }
4872 if (i > 1 && lenbuf[i] == '\n' && lenbuf[i - 1] == '\r') {
4873 lenbuf[i + 1] = 0;
4874 chunkSize = strtoul(lenbuf, &end, 16);
4875 if (chunkSize == 0) {
4876 /* regular end of content */
4877 conn->is_chunked = 2;
4878 }
4879 break;
4880 }
4881 if (!isxdigit(lenbuf[i])) {
4882 /* illegal character for chunk length */
4883 return -1;
4884 }
4885 }
4886 if ((end == NULL) || (*end != '\r')) {
4887 /* chunksize not set correctly */
4888 return -1;
4889 }
4890 if (chunkSize == 0) {
4891 break;
4892 }
4893
4894 conn->chunk_remainder = chunkSize;
4895 }
4896 }
4897
4898 return (int)all_read;
4899 }
4900 return mg_read_inner(conn, buf, len);
4901 }
4902
4903
4904 int
mg_write(struct mg_connection * conn,const void * buf,size_t len)4905 mg_write(struct mg_connection *conn, const void *buf, size_t len)
4906 {
4907 time_t now;
4908 int64_t n, total, allowed;
4909
4910 if (conn == NULL) {
4911 return 0;
4912 }
4913
4914 if (conn->throttle > 0) {
4915 if ((now = time(NULL)) != conn->last_throttle_time) {
4916 conn->last_throttle_time = now;
4917 conn->last_throttle_bytes = 0;
4918 }
4919 allowed = conn->throttle - conn->last_throttle_bytes;
4920 if (allowed > (int64_t)len) {
4921 allowed = (int64_t)len;
4922 }
4923 if ((total = push_all(conn->ctx,
4924 NULL,
4925 conn->client.sock,
4926 conn->ssl,
4927 (const char *)buf,
4928 (int64_t)allowed)) == allowed) {
4929 buf = (const char *)buf + total;
4930 conn->last_throttle_bytes += total;
4931 while (total < (int64_t)len && conn->ctx->stop_flag == 0) {
4932 allowed = (conn->throttle > ((int64_t)len - total))
4933 ? (int64_t)len - total
4934 : conn->throttle;
4935 if ((n = push_all(conn->ctx,
4936 NULL,
4937 conn->client.sock,
4938 conn->ssl,
4939 (const char *)buf,
4940 (int64_t)allowed)) != allowed) {
4941 break;
4942 }
4943 sleep(1);
4944 conn->last_throttle_bytes = allowed;
4945 conn->last_throttle_time = time(NULL);
4946 buf = (const char *)buf + n;
4947 total += n;
4948 }
4949 }
4950 } else {
4951 total = push_all(conn->ctx,
4952 NULL,
4953 conn->client.sock,
4954 conn->ssl,
4955 (const char *)buf,
4956 (int64_t)len);
4957 }
4958 return (int)total;
4959 }
4960
4961
4962 /* Alternative alloc_vprintf() for non-compliant C runtimes */
4963 static int
alloc_vprintf2(char ** buf,const char * fmt,va_list ap)4964 alloc_vprintf2(char **buf, const char *fmt, va_list ap)
4965 {
4966 va_list ap_copy;
4967 size_t size = MG_BUF_LEN / 4;
4968 int len = -1;
4969
4970 *buf = NULL;
4971 while (len < 0) {
4972 if (*buf) {
4973 mg_free(*buf);
4974 }
4975
4976 size *= 4;
4977 *buf = (char *)mg_malloc(size);
4978 if (!*buf) {
4979 break;
4980 }
4981
4982 va_copy(ap_copy, ap);
4983 len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy);
4984 va_end(ap_copy);
4985 (*buf)[size - 1] = 0;
4986 }
4987
4988 return len;
4989 }
4990
4991
4992 /* Print message to buffer. If buffer is large enough to hold the message,
4993 * return buffer. If buffer is to small, allocate large enough buffer on heap,
4994 * and return allocated buffer. */
4995 static int
alloc_vprintf(char ** out_buf,char * prealloc_buf,size_t prealloc_size,const char * fmt,va_list ap)4996 alloc_vprintf(char **out_buf,
4997 char *prealloc_buf,
4998 size_t prealloc_size,
4999 const char *fmt,
5000 va_list ap)
5001 {
5002 va_list ap_copy;
5003 int len;
5004
5005 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
5006 * buffer is too small. Also, older versions of msvcrt.dll do not have
5007 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
5008 * Therefore, we make two passes: on first pass, get required message
5009 * length.
5010 * On second pass, actually print the message. */
5011 va_copy(ap_copy, ap);
5012 len = vsnprintf_impl(NULL, 0, fmt, ap_copy);
5013 va_end(ap_copy);
5014
5015 if (len < 0) {
5016 /* C runtime is not standard compliant, vsnprintf() returned -1.
5017 * Switch to alternative code path that uses incremental allocations.
5018 */
5019 va_copy(ap_copy, ap);
5020 len = alloc_vprintf2(out_buf, fmt, ap);
5021 va_end(ap_copy);
5022
5023 } else if ((size_t)(len) >= prealloc_size) {
5024 /* The pre-allocated buffer not large enough. */
5025 /* Allocate a new buffer. */
5026 *out_buf = (char *)mg_malloc((size_t)(len) + 1);
5027 if (!*out_buf) {
5028 /* Allocation failed. Return -1 as "out of memory" error. */
5029 return -1;
5030 }
5031 /* Buffer allocation successful. Store the string there. */
5032 va_copy(ap_copy, ap);
5033 IGNORE_UNUSED_RESULT(
5034 vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy));
5035 va_end(ap_copy);
5036
5037 } else {
5038 /* The pre-allocated buffer is large enough.
5039 * Use it to store the string and return the address. */
5040 va_copy(ap_copy, ap);
5041 IGNORE_UNUSED_RESULT(
5042 vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy));
5043 va_end(ap_copy);
5044 *out_buf = prealloc_buf;
5045 }
5046
5047 return len;
5048 }
5049
5050
5051 static int
mg_vprintf(struct mg_connection * conn,const char * fmt,va_list ap)5052 mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
5053 {
5054 char mem[MG_BUF_LEN];
5055 char *buf = NULL;
5056 int len;
5057
5058 if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) {
5059 len = mg_write(conn, buf, (size_t)len);
5060 }
5061 if (buf != mem && buf != NULL) {
5062 mg_free(buf);
5063 }
5064
5065 return len;
5066 }
5067
5068
5069 int
mg_printf(struct mg_connection * conn,const char * fmt,...)5070 mg_printf(struct mg_connection *conn, const char *fmt, ...)
5071 {
5072 va_list ap;
5073 int result;
5074
5075 va_start(ap, fmt);
5076 result = mg_vprintf(conn, fmt, ap);
5077 va_end(ap);
5078
5079 return result;
5080 }
5081
5082
5083 int
mg_url_decode(const char * src,int src_len,char * dst,int dst_len,int is_form_url_encoded)5084 mg_url_decode(const char *src,
5085 int src_len,
5086 char *dst,
5087 int dst_len,
5088 int is_form_url_encoded)
5089 {
5090 int i, j, a, b;
5091 #define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
5092
5093 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
5094 if (i < src_len - 2 && src[i] == '%'
5095 && isxdigit(*(const unsigned char *)(src + i + 1))
5096 && isxdigit(*(const unsigned char *)(src + i + 2))) {
5097 a = tolower(*(const unsigned char *)(src + i + 1));
5098 b = tolower(*(const unsigned char *)(src + i + 2));
5099 dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
5100 i += 2;
5101 } else if (is_form_url_encoded && src[i] == '+') {
5102 dst[j] = ' ';
5103 } else {
5104 dst[j] = src[i];
5105 }
5106 }
5107
5108 dst[j] = '\0'; /* Null-terminate the destination */
5109
5110 return (i >= src_len) ? j : -1;
5111 }
5112
5113
5114 int
mg_get_var(const char * data,size_t data_len,const char * name,char * dst,size_t dst_len)5115 mg_get_var(const char *data,
5116 size_t data_len,
5117 const char *name,
5118 char *dst,
5119 size_t dst_len)
5120 {
5121 return mg_get_var2(data, data_len, name, dst, dst_len, 0);
5122 }
5123
5124
5125 int
mg_get_var2(const char * data,size_t data_len,const char * name,char * dst,size_t dst_len,size_t occurrence)5126 mg_get_var2(const char *data,
5127 size_t data_len,
5128 const char *name,
5129 char *dst,
5130 size_t dst_len,
5131 size_t occurrence)
5132 {
5133 const char *p, *e, *s;
5134 size_t name_len;
5135 int len;
5136
5137 if (dst == NULL || dst_len == 0) {
5138 len = -2;
5139 } else if (data == NULL || name == NULL || data_len == 0) {
5140 len = -1;
5141 dst[0] = '\0';
5142 } else {
5143 name_len = strlen(name);
5144 e = data + data_len;
5145 len = -1;
5146 dst[0] = '\0';
5147
5148 /* data is "var1=val1&var2=val2...". Find variable first */
5149 for (p = data; p + name_len < e; p++) {
5150 if ((p == data || p[-1] == '&') && p[name_len] == '='
5151 && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
5152 /* Point p to variable value */
5153 p += name_len + 1;
5154
5155 /* Point s to the end of the value */
5156 s = (const char *)memchr(p, '&', (size_t)(e - p));
5157 if (s == NULL) {
5158 s = e;
5159 }
5160 /* assert(s >= p); */
5161 if (s < p) {
5162 return -3;
5163 }
5164
5165 /* Decode variable into destination buffer */
5166 len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
5167
5168 /* Redirect error code from -1 to -2 (destination buffer too
5169 * small). */
5170 if (len == -1) {
5171 len = -2;
5172 }
5173 break;
5174 }
5175 }
5176 }
5177
5178 return len;
5179 }
5180
5181
5182 /* HCP24: some changes to compare hole var_name */
5183 int
mg_get_cookie(const char * cookie_header,const char * var_name,char * dst,size_t dst_size)5184 mg_get_cookie(const char *cookie_header,
5185 const char *var_name,
5186 char *dst,
5187 size_t dst_size)
5188 {
5189 const char *s, *p, *end;
5190 int name_len, len = -1;
5191
5192 if (dst == NULL || dst_size == 0) {
5193 return -2;
5194 }
5195
5196 dst[0] = '\0';
5197 if (var_name == NULL || (s = cookie_header) == NULL) {
5198 return -1;
5199 }
5200
5201 name_len = (int)strlen(var_name);
5202 end = s + strlen(s);
5203 for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
5204 if (s[name_len] == '=') {
5205 /* HCP24: now check is it a substring or a full cookie name */
5206 if ((s == cookie_header) || (s[-1] == ' ')) {
5207 s += name_len + 1;
5208 if ((p = strchr(s, ' ')) == NULL) {
5209 p = end;
5210 }
5211 if (p[-1] == ';') {
5212 p--;
5213 }
5214 if (*s == '"' && p[-1] == '"' && p > s + 1) {
5215 s++;
5216 p--;
5217 }
5218 if ((size_t)(p - s) < dst_size) {
5219 len = (int)(p - s);
5220 mg_strlcpy(dst, s, (size_t)len + 1);
5221 } else {
5222 len = -3;
5223 }
5224 break;
5225 }
5226 }
5227 }
5228 return len;
5229 }
5230
5231
5232 #if defined(USE_WEBSOCKET) || defined(USE_LUA)
5233 static void
base64_encode(const unsigned char * src,int src_len,char * dst)5234 base64_encode(const unsigned char *src, int src_len, char *dst)
5235 {
5236 static const char *b64 =
5237 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5238 int i, j, a, b, c;
5239
5240 for (i = j = 0; i < src_len; i += 3) {
5241 a = src[i];
5242 b = ((i + 1) >= src_len) ? 0 : src[i + 1];
5243 c = ((i + 2) >= src_len) ? 0 : src[i + 2];
5244
5245 dst[j++] = b64[a >> 2];
5246 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
5247 if (i + 1 < src_len) {
5248 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
5249 }
5250 if (i + 2 < src_len) {
5251 dst[j++] = b64[c & 63];
5252 }
5253 }
5254 while (j % 4 != 0) {
5255 dst[j++] = '=';
5256 }
5257 dst[j++] = '\0';
5258 }
5259 #endif
5260
5261
5262 #if defined(USE_LUA)
5263 static unsigned char
b64reverse(char letter)5264 b64reverse(char letter)
5265 {
5266 if (letter >= 'A' && letter <= 'Z') {
5267 return letter - 'A';
5268 }
5269 if (letter >= 'a' && letter <= 'z') {
5270 return letter - 'a' + 26;
5271 }
5272 if (letter >= '0' && letter <= '9') {
5273 return letter - '0' + 52;
5274 }
5275 if (letter == '+') {
5276 return 62;
5277 }
5278 if (letter == '/') {
5279 return 63;
5280 }
5281 if (letter == '=') {
5282 return 255; /* normal end */
5283 }
5284 return 254; /* error */
5285 }
5286
5287
5288 static int
base64_decode(const unsigned char * src,int src_len,char * dst,size_t * dst_len)5289 base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
5290 {
5291 int i;
5292 unsigned char a, b, c, d;
5293
5294 *dst_len = 0;
5295
5296 for (i = 0; i < src_len; i += 4) {
5297 a = b64reverse(src[i]);
5298 if (a >= 254) {
5299 return i;
5300 }
5301
5302 b = b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]);
5303 if (b >= 254) {
5304 return i + 1;
5305 }
5306
5307 c = b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]);
5308 if (c == 254) {
5309 return i + 2;
5310 }
5311
5312 d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
5313 if (d == 254) {
5314 return i + 3;
5315 }
5316
5317 dst[(*dst_len)++] = (a << 2) + (b >> 4);
5318 if (c != 255) {
5319 dst[(*dst_len)++] = (b << 4) + (c >> 2);
5320 if (d != 255) {
5321 dst[(*dst_len)++] = (c << 6) + d;
5322 }
5323 }
5324 }
5325 return -1;
5326 }
5327 #endif
5328
5329
5330 static int
is_put_or_delete_method(const struct mg_connection * conn)5331 is_put_or_delete_method(const struct mg_connection *conn)
5332 {
5333 if (conn) {
5334 const char *s = conn->request_info.request_method;
5335 return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE")
5336 || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH"));
5337 }
5338 return 0;
5339 }
5340
5341
5342 static void
interpret_uri(struct mg_connection * conn,char * filename,size_t filename_buf_len,struct mg_file_stat * filestat,int * is_found,int * is_script_resource,int * is_websocket_request,int * is_put_or_delete_request)5343 interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */
5344 char *filename, /* out: filename */
5345 size_t filename_buf_len, /* in: size of filename buffer */
5346 struct mg_file_stat *filestat, /* out: file structure */
5347 int *is_found, /* out: file found (directly) */
5348 int *is_script_resource, /* out: handled by a script? */
5349 int *is_websocket_request, /* out: websocket connetion? */
5350 int *is_put_or_delete_request /* out: put/delete a file? */
5351 )
5352 {
5353 /* TODO (high): Restructure this function */
5354
5355 #if !defined(NO_FILES)
5356 const char *uri = conn->request_info.local_uri;
5357 const char *root = conn->ctx->config[DOCUMENT_ROOT];
5358 const char *rewrite;
5359 struct vec a, b;
5360 int match_len;
5361 char gz_path[PATH_MAX];
5362 char const *accept_encoding;
5363 int truncated;
5364 #if !defined(NO_CGI) || defined(USE_LUA)
5365 char *p;
5366 #endif
5367 #else
5368 (void)filename_buf_len; /* unused if NO_FILES is defined */
5369 #endif
5370
5371 memset(filestat, 0, sizeof(*filestat));
5372 *filename = 0;
5373 *is_found = 0;
5374 *is_script_resource = 0;
5375 *is_put_or_delete_request = is_put_or_delete_method(conn);
5376
5377 #if defined(USE_WEBSOCKET)
5378 *is_websocket_request = is_websocket_protocol(conn);
5379 #if !defined(NO_FILES)
5380 if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
5381 root = conn->ctx->config[WEBSOCKET_ROOT];
5382 }
5383 #endif /* !NO_FILES */
5384 #else /* USE_WEBSOCKET */
5385 *is_websocket_request = 0;
5386 #endif /* USE_WEBSOCKET */
5387
5388 #if !defined(NO_FILES)
5389 /* Note that root == NULL is a regular use case here. This occurs,
5390 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
5391 * config is not required. */
5392 if (root == NULL) {
5393 /* all file related outputs have already been set to 0, just return
5394 */
5395 return;
5396 }
5397
5398 /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
5399 * of the path one byte on the right.
5400 * If document_root is NULL, leave the file empty. */
5401 mg_snprintf(
5402 conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
5403
5404 if (truncated) {
5405 goto interpret_cleanup;
5406 }
5407
5408 rewrite = conn->ctx->config[REWRITE];
5409 while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
5410 if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
5411 mg_snprintf(conn,
5412 &truncated,
5413 filename,
5414 filename_buf_len - 1,
5415 "%.*s%s",
5416 (int)b.len,
5417 b.ptr,
5418 uri + match_len);
5419 break;
5420 }
5421 }
5422
5423 if (truncated) {
5424 goto interpret_cleanup;
5425 }
5426
5427 /* Local file path and name, corresponding to requested URI
5428 * is now stored in "filename" variable. */
5429 if (mg_stat(conn, filename, filestat)) {
5430 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
5431 /* File exists. Check if it is a script type. */
5432 if (0
5433 #if !defined(NO_CGI)
5434 || match_prefix(conn->ctx->config[CGI_EXTENSIONS],
5435 strlen(conn->ctx->config[CGI_EXTENSIONS]),
5436 filename) > 0
5437 #endif
5438 #if defined(USE_LUA)
5439 || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
5440 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
5441 filename) > 0
5442 #endif
5443 #if defined(USE_DUKTAPE)
5444 || match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
5445 strlen(
5446 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
5447 filename) > 0
5448 #endif
5449 ) {
5450 /* The request addresses a CGI script or a Lua script. The URI
5451 * corresponds to the script itself (like /path/script.cgi),
5452 * and there is no additional resource path
5453 * (like /path/script.cgi/something).
5454 * Requests that modify (replace or delete) a resource, like
5455 * PUT and DELETE requests, should replace/delete the script
5456 * file.
5457 * Requests that read or write from/to a resource, like GET and
5458 * POST requests, should call the script and return the
5459 * generated response. */
5460 *is_script_resource = !*is_put_or_delete_request;
5461 }
5462 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
5463 *is_found = 1;
5464 return;
5465 }
5466
5467 /* If we can't find the actual file, look for the file
5468 * with the same name but a .gz extension. If we find it,
5469 * use that and set the gzipped flag in the file struct
5470 * to indicate that the response need to have the content-
5471 * encoding: gzip header.
5472 * We can only do this if the browser declares support. */
5473 if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
5474 if (strstr(accept_encoding, "gzip") != NULL) {
5475 mg_snprintf(
5476 conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename);
5477
5478 if (truncated) {
5479 goto interpret_cleanup;
5480 }
5481
5482 if (mg_stat(conn, gz_path, filestat)) {
5483 if (filestat) {
5484 filestat->is_gzipped = 1;
5485 *is_found = 1;
5486 }
5487 /* Currently gz files can not be scripts. */
5488 return;
5489 }
5490 }
5491 }
5492
5493 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
5494 /* Support PATH_INFO for CGI scripts. */
5495 for (p = filename + strlen(filename); p > filename + 1; p--) {
5496 if (*p == '/') {
5497 *p = '\0';
5498 if ((0
5499 #if !defined(NO_CGI)
5500 || match_prefix(conn->ctx->config[CGI_EXTENSIONS],
5501 strlen(conn->ctx->config[CGI_EXTENSIONS]),
5502 filename) > 0
5503 #endif
5504 #if defined(USE_LUA)
5505 || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
5506 strlen(
5507 conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
5508 filename) > 0
5509 #endif
5510 #if defined(USE_DUKTAPE)
5511 || match_prefix(
5512 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
5513 strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
5514 filename) > 0
5515 #endif
5516 ) && mg_stat(conn, filename, filestat)) {
5517 /* Shift PATH_INFO block one character right, e.g.
5518 * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
5519 * conn->path_info is pointing to the local variable "path"
5520 * declared in handle_request(), so PATH_INFO is not valid
5521 * after handle_request returns. */
5522 conn->path_info = p + 1;
5523 memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for
5524 * trailing \0 */
5525 p[1] = '/';
5526 *is_script_resource = 1;
5527 break;
5528 } else {
5529 *p = '/';
5530 }
5531 }
5532 }
5533 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
5534 #endif /* !defined(NO_FILES) */
5535 return;
5536
5537 #if !defined(NO_FILES)
5538 /* Reset all outputs */
5539 interpret_cleanup:
5540 memset(filestat, 0, sizeof(*filestat));
5541 *filename = 0;
5542 *is_found = 0;
5543 *is_script_resource = 0;
5544 *is_websocket_request = 0;
5545 *is_put_or_delete_request = 0;
5546 #endif /* !defined(NO_FILES) */
5547 }
5548
5549
5550 /* Check whether full request is buffered. Return:
5551 * -1 if request is malformed
5552 * 0 if request is not yet fully buffered
5553 * >0 actual request length, including last \r\n\r\n */
5554 static int
get_request_len(const char * buf,int buflen)5555 get_request_len(const char *buf, int buflen)
5556 {
5557 const char *s, *e;
5558 int len = 0;
5559
5560 for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
5561 /* Control characters are not allowed but >=128 is. */
5562 if (!isprint(*(const unsigned char *)s) && *s != '\r' && *s != '\n'
5563 && *(const unsigned char *)s < 128) {
5564 len = -1;
5565 break; /* [i_a] abort scan as soon as one malformed character is
5566 * found; */
5567 /* don't let subsequent \r\n\r\n win us over anyhow */
5568 } else if (s[0] == '\n' && s[1] == '\n') {
5569 len = (int)(s - buf) + 2;
5570 } else if (s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') {
5571 len = (int)(s - buf) + 3;
5572 }
5573
5574 return len;
5575 }
5576
5577
5578 #if !defined(NO_CACHING)
5579 /* Convert month to the month number. Return -1 on error, or month number */
5580 static int
get_month_index(const char * s)5581 get_month_index(const char *s)
5582 {
5583 size_t i;
5584
5585 for (i = 0; i < ARRAY_SIZE(month_names); i++) {
5586 if (!strcmp(s, month_names[i])) {
5587 return (int)i;
5588 }
5589 }
5590
5591 return -1;
5592 }
5593
5594
5595 /* Parse UTC date-time string, and return the corresponding time_t value. */
5596 static time_t
parse_date_string(const char * datetime)5597 parse_date_string(const char *datetime)
5598 {
5599 char month_str[32] = {0};
5600 int second, minute, hour, day, month, year;
5601 time_t result = (time_t)0;
5602 struct tm tm;
5603
5604 if ((sscanf(datetime,
5605 "%d/%3s/%d %d:%d:%d",
5606 &day,
5607 month_str,
5608 &year,
5609 &hour,
5610 &minute,
5611 &second) == 6) || (sscanf(datetime,
5612 "%d %3s %d %d:%d:%d",
5613 &day,
5614 month_str,
5615 &year,
5616 &hour,
5617 &minute,
5618 &second) == 6)
5619 || (sscanf(datetime,
5620 "%*3s, %d %3s %d %d:%d:%d",
5621 &day,
5622 month_str,
5623 &year,
5624 &hour,
5625 &minute,
5626 &second) == 6) || (sscanf(datetime,
5627 "%d-%3s-%d %d:%d:%d",
5628 &day,
5629 month_str,
5630 &year,
5631 &hour,
5632 &minute,
5633 &second) == 6)) {
5634 month = get_month_index(month_str);
5635 if ((month >= 0) && (year >= 1970)) {
5636 memset(&tm, 0, sizeof(tm));
5637 tm.tm_year = year - 1900;
5638 tm.tm_mon = month;
5639 tm.tm_mday = day;
5640 tm.tm_hour = hour;
5641 tm.tm_min = minute;
5642 tm.tm_sec = second;
5643 result = timegm(&tm);
5644 }
5645 }
5646
5647 return result;
5648 }
5649 #endif /* !NO_CACHING */
5650
5651
5652 /* Protect against directory disclosure attack by removing '..',
5653 * excessive '/' and '\' characters */
5654 static void
remove_double_dots_and_double_slashes(char * s)5655 remove_double_dots_and_double_slashes(char *s)
5656 {
5657 char *p = s;
5658
5659 while ((s[0] == '.') && (s[1] == '.')) {
5660 s++;
5661 }
5662
5663 while (*s != '\0') {
5664 *p++ = *s++;
5665 if (s[-1] == '/' || s[-1] == '\\') {
5666 /* Skip all following slashes, backslashes and double-dots */
5667 while (s[0] != '\0') {
5668 if (s[0] == '/' || s[0] == '\\') {
5669 s++;
5670 } else if (s[0] == '.' && s[1] == '.') {
5671 s += 2;
5672 } else {
5673 break;
5674 }
5675 }
5676 }
5677 }
5678 *p = '\0';
5679 }
5680
5681
5682 static const struct {
5683 const char *extension;
5684 size_t ext_len;
5685 const char *mime_type;
5686 } builtin_mime_types[] = {
5687 /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
5688 * application types */
5689 {".doc", 4, "application/msword"},
5690 {".eps", 4, "application/postscript"},
5691 {".exe", 4, "application/octet-stream"},
5692 {".js", 3, "application/javascript"},
5693 {".json", 5, "application/json"},
5694 {".pdf", 4, "application/pdf"},
5695 {".ps", 3, "application/postscript"},
5696 {".rtf", 4, "application/rtf"},
5697 {".xhtml", 6, "application/xhtml+xml"},
5698 {".xsl", 4, "application/xml"},
5699 {".xslt", 5, "application/xml"},
5700
5701 /* fonts */
5702 {".ttf", 4, "application/font-sfnt"},
5703 {".cff", 4, "application/font-sfnt"},
5704 {".otf", 4, "application/font-sfnt"},
5705 {".aat", 4, "application/font-sfnt"},
5706 {".sil", 4, "application/font-sfnt"},
5707 {".pfr", 4, "application/font-tdpfr"},
5708 {".woff", 5, "application/font-woff"},
5709
5710 /* audio */
5711 {".mp3", 4, "audio/mpeg"},
5712 {".oga", 4, "audio/ogg"},
5713 {".ogg", 4, "audio/ogg"},
5714
5715 /* image */
5716 {".gif", 4, "image/gif"},
5717 {".ief", 4, "image/ief"},
5718 {".jpeg", 5, "image/jpeg"},
5719 {".jpg", 4, "image/jpeg"},
5720 {".jpm", 4, "image/jpm"},
5721 {".jpx", 4, "image/jpx"},
5722 {".png", 4, "image/png"},
5723 {".svg", 4, "image/svg+xml"},
5724 {".tif", 4, "image/tiff"},
5725 {".tiff", 5, "image/tiff"},
5726
5727 /* model */
5728 {".wrl", 4, "model/vrml"},
5729
5730 /* text */
5731 {".css", 4, "text/css"},
5732 {".csv", 4, "text/csv"},
5733 {".htm", 4, "text/html"},
5734 {".html", 5, "text/html"},
5735 {".sgm", 4, "text/sgml"},
5736 {".shtm", 5, "text/html"},
5737 {".shtml", 6, "text/html"},
5738 {".txt", 4, "text/plain"},
5739 {".xml", 4, "text/xml"},
5740
5741 /* video */
5742 {".mov", 4, "video/quicktime"},
5743 {".mp4", 4, "video/mp4"},
5744 {".mpeg", 5, "video/mpeg"},
5745 {".mpg", 4, "video/mpeg"},
5746 {".ogv", 4, "video/ogg"},
5747 {".qt", 3, "video/quicktime"},
5748
5749 /* not registered types
5750 * (http://reference.sitepoint.com/html/mime-types-full,
5751 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
5752 {".arj", 4, "application/x-arj-compressed"},
5753 {".gz", 3, "application/x-gunzip"},
5754 {".rar", 4, "application/x-arj-compressed"},
5755 {".swf", 4, "application/x-shockwave-flash"},
5756 {".tar", 4, "application/x-tar"},
5757 {".tgz", 4, "application/x-tar-gz"},
5758 {".torrent", 8, "application/x-bittorrent"},
5759 {".ppt", 4, "application/x-mspowerpoint"},
5760 {".xls", 4, "application/x-msexcel"},
5761 {".zip", 4, "application/x-zip-compressed"},
5762 {".aac",
5763 4,
5764 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
5765 {".aif", 4, "audio/x-aif"},
5766 {".m3u", 4, "audio/x-mpegurl"},
5767 {".mid", 4, "audio/x-midi"},
5768 {".ra", 3, "audio/x-pn-realaudio"},
5769 {".ram", 4, "audio/x-pn-realaudio"},
5770 {".wav", 4, "audio/x-wav"},
5771 {".bmp", 4, "image/bmp"},
5772 {".ico", 4, "image/x-icon"},
5773 {".pct", 4, "image/x-pct"},
5774 {".pict", 5, "image/pict"},
5775 {".rgb", 4, "image/x-rgb"},
5776 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
5777 {".asf", 4, "video/x-ms-asf"},
5778 {".avi", 4, "video/x-msvideo"},
5779 {".m4v", 4, "video/x-m4v"},
5780 {NULL, 0, NULL}};
5781
5782
5783 const char *
mg_get_builtin_mime_type(const char * path)5784 mg_get_builtin_mime_type(const char *path)
5785 {
5786 const char *ext;
5787 size_t i, path_len;
5788
5789 path_len = strlen(path);
5790
5791 for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
5792 ext = path + (path_len - builtin_mime_types[i].ext_len);
5793 if (path_len > builtin_mime_types[i].ext_len
5794 && mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
5795 return builtin_mime_types[i].mime_type;
5796 }
5797 }
5798
5799 return "text/plain";
5800 }
5801
5802
5803 /* Look at the "path" extension and figure what mime type it has.
5804 * Store mime type in the vector. */
5805 static void
get_mime_type(struct mg_context * ctx,const char * path,struct vec * vec)5806 get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
5807 {
5808 struct vec ext_vec, mime_vec;
5809 const char *list, *ext;
5810 size_t path_len;
5811
5812 path_len = strlen(path);
5813
5814 if (ctx == NULL || vec == NULL) {
5815 return;
5816 }
5817
5818 /* Scan user-defined mime types first, in case user wants to
5819 * override default mime types. */
5820 list = ctx->config[EXTRA_MIME_TYPES];
5821 while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
5822 /* ext now points to the path suffix */
5823 ext = path + path_len - ext_vec.len;
5824 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
5825 *vec = mime_vec;
5826 return;
5827 }
5828 }
5829
5830 vec->ptr = mg_get_builtin_mime_type(path);
5831 vec->len = strlen(vec->ptr);
5832 }
5833
5834
5835 /* Stringify binary data. Output buffer must be twice as big as input,
5836 * because each byte takes 2 bytes in string representation */
5837 static void
bin2str(char * to,const unsigned char * p,size_t len)5838 bin2str(char *to, const unsigned char *p, size_t len)
5839 {
5840 static const char *hex = "0123456789abcdef";
5841
5842 for (; len--; p++) {
5843 *to++ = hex[p[0] >> 4];
5844 *to++ = hex[p[0] & 0x0f];
5845 }
5846 *to = '\0';
5847 }
5848
5849
5850 /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
5851 char *
mg_md5(char buf[33],...)5852 mg_md5(char buf[33], ...)
5853 {
5854 md5_byte_t hash[16];
5855 const char *p;
5856 va_list ap;
5857 md5_state_t ctx;
5858
5859 md5_init(&ctx);
5860
5861 va_start(ap, buf);
5862 while ((p = va_arg(ap, const char *)) != NULL) {
5863 md5_append(&ctx, (const md5_byte_t *)p, strlen(p));
5864 }
5865 va_end(ap);
5866
5867 md5_finish(&ctx, hash);
5868 bin2str(buf, hash, sizeof(hash));
5869 return buf;
5870 }
5871
5872
5873 /* Check the user's password, return 1 if OK */
5874 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)5875 check_password(const char *method,
5876 const char *ha1,
5877 const char *uri,
5878 const char *nonce,
5879 const char *nc,
5880 const char *cnonce,
5881 const char *qop,
5882 const char *response)
5883 {
5884 char ha2[32 + 1], expected_response[32 + 1];
5885
5886 /* Some of the parameters may be NULL */
5887 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL
5888 || qop == NULL
5889 || response == NULL) {
5890 return 0;
5891 }
5892
5893 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
5894 if (strlen(response) != 32) {
5895 return 0;
5896 }
5897
5898 mg_md5(ha2, method, ":", uri, NULL);
5899 mg_md5(expected_response,
5900 ha1,
5901 ":",
5902 nonce,
5903 ":",
5904 nc,
5905 ":",
5906 cnonce,
5907 ":",
5908 qop,
5909 ":",
5910 ha2,
5911 NULL);
5912
5913 return mg_strcasecmp(response, expected_response) == 0;
5914 }
5915
5916
5917 /* Use the global passwords file, if specified by auth_gpass option,
5918 * or search for .htpasswd in the requested directory. */
5919 static void
open_auth_file(struct mg_connection * conn,const char * path,struct mg_file * filep)5920 open_auth_file(struct mg_connection *conn,
5921 const char *path,
5922 struct mg_file *filep)
5923 {
5924 if (conn != NULL && conn->ctx != NULL) {
5925 char name[PATH_MAX];
5926 const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
5927 int truncated;
5928
5929 if (gpass != NULL) {
5930 /* Use global passwords file */
5931 if (!mg_fopen(conn, gpass, MG_FOPEN_MODE_READ, filep)) {
5932 #ifdef DEBUG
5933 mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
5934 #endif
5935 }
5936 /* Important: using local struct mg_file to test path for
5937 * is_directory
5938 * flag. If filep is used, mg_stat() makes it appear as if auth file
5939 * was opened. TODO: mg_stat must not make anything appear to be
5940 * opened */
5941 } else if (mg_stat(conn, path, &filep->stat)
5942 && filep->stat.is_directory) {
5943 mg_snprintf(conn,
5944 &truncated,
5945 name,
5946 sizeof(name),
5947 "%s/%s",
5948 path,
5949 PASSWORDS_FILE_NAME);
5950
5951 if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) {
5952 #ifdef DEBUG
5953 mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
5954 #endif
5955 }
5956 } else {
5957 /* Try to find .htpasswd in requested directory. */
5958 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
5959 if (e[0] == '/') {
5960 break;
5961 }
5962 }
5963 mg_snprintf(conn,
5964 &truncated,
5965 name,
5966 sizeof(name),
5967 "%.*s/%s",
5968 (int)(e - p),
5969 p,
5970 PASSWORDS_FILE_NAME);
5971
5972 if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) {
5973 #ifdef DEBUG
5974 mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
5975 #endif
5976 }
5977 }
5978 }
5979 }
5980
5981
5982 /* Parsed Authorization header */
5983 struct ah {
5984 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
5985 };
5986
5987
5988 /* Return 1 on success. Always initializes the ah structure. */
5989 static int
parse_auth_header(struct mg_connection * conn,char * buf,size_t buf_size,struct ah * ah)5990 parse_auth_header(struct mg_connection *conn,
5991 char *buf,
5992 size_t buf_size,
5993 struct ah *ah)
5994 {
5995 char *name, *value, *s;
5996 const char *auth_header;
5997 uint64_t nonce;
5998
5999 if (!ah || !conn) {
6000 return 0;
6001 }
6002
6003 (void)memset(ah, 0, sizeof(*ah));
6004 if ((auth_header = mg_get_header(conn, "Authorization")) == NULL
6005 || mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
6006 return 0;
6007 }
6008
6009 /* Make modifiable copy of the auth header */
6010 (void)mg_strlcpy(buf, auth_header + 7, buf_size);
6011 s = buf;
6012
6013 /* Parse authorization header */
6014 for (;;) {
6015 /* Gobble initial spaces */
6016 while (isspace(*(unsigned char *)s)) {
6017 s++;
6018 }
6019 name = skip_quoted(&s, "=", " ", 0);
6020 /* Value is either quote-delimited, or ends at first comma or space. */
6021 if (s[0] == '\"') {
6022 s++;
6023 value = skip_quoted(&s, "\"", " ", '\\');
6024 if (s[0] == ',') {
6025 s++;
6026 }
6027 } else {
6028 value = skip_quoted(&s, ", ", " ", 0); /* IE uses commas, FF uses
6029 * spaces */
6030 }
6031 if (*name == '\0') {
6032 break;
6033 }
6034
6035 if (!strcmp(name, "username")) {
6036 ah->user = value;
6037 } else if (!strcmp(name, "cnonce")) {
6038 ah->cnonce = value;
6039 } else if (!strcmp(name, "response")) {
6040 ah->response = value;
6041 } else if (!strcmp(name, "uri")) {
6042 ah->uri = value;
6043 } else if (!strcmp(name, "qop")) {
6044 ah->qop = value;
6045 } else if (!strcmp(name, "nc")) {
6046 ah->nc = value;
6047 } else if (!strcmp(name, "nonce")) {
6048 ah->nonce = value;
6049 }
6050 }
6051
6052 #ifndef NO_NONCE_CHECK
6053 /* Read the nonce from the response. */
6054 if (ah->nonce == NULL) {
6055 return 0;
6056 }
6057 s = NULL;
6058 nonce = strtoull(ah->nonce, &s, 10);
6059 if ((s == NULL) || (*s != 0)) {
6060 return 0;
6061 }
6062
6063 /* Convert the nonce from the client to a number. */
6064 nonce ^= conn->ctx->auth_nonce_mask;
6065
6066 /* The converted number corresponds to the time the nounce has been
6067 * created. This should not be earlier than the server start. */
6068 /* Server side nonce check is valuable in all situations but one:
6069 * if the server restarts frequently, but the client should not see
6070 * that, so the server should accept nonces from previous starts. */
6071 /* However, the reasonable default is to not accept a nonce from a
6072 * previous start, so if anyone changed the access rights between
6073 * two restarts, a new login is required. */
6074 if (nonce < (uint64_t)conn->ctx->start_time) {
6075 /* nonce is from a previous start of the server and no longer valid
6076 * (replay attack?) */
6077 return 0;
6078 }
6079 /* Check if the nonce is too high, so it has not (yet) been used by the
6080 * server. */
6081 if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
6082 return 0;
6083 }
6084 #else
6085 (void)nonce;
6086 #endif
6087
6088 /* CGI needs it as REMOTE_USER */
6089 if (ah->user != NULL) {
6090 conn->request_info.remote_user = mg_strdup(ah->user);
6091 } else {
6092 return 0;
6093 }
6094
6095 return 1;
6096 }
6097
6098
6099 static const char *
mg_fgets(char * buf,size_t size,struct mg_file * filep,char ** p)6100 mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p)
6101 {
6102 const char *eof;
6103 size_t len;
6104 const char *memend;
6105
6106 if (!filep) {
6107 return NULL;
6108 }
6109
6110 if (filep->access.membuf != NULL && *p != NULL) {
6111 memend = (const char *)&filep->access.membuf[filep->stat.size];
6112 /* Search for \n from p till the end of stream */
6113 eof = (char *)memchr(*p, '\n', (size_t)(memend - *p));
6114 if (eof != NULL) {
6115 eof += 1; /* Include \n */
6116 } else {
6117 eof = memend; /* Copy remaining data */
6118 }
6119 len =
6120 ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (size_t)(eof - *p);
6121 memcpy(buf, *p, len);
6122 buf[len] = '\0';
6123 *p += len;
6124 return len ? eof : NULL;
6125 } else if (filep->access.fp != NULL) {
6126 return fgets(buf, (int)size, filep->access.fp);
6127 } else {
6128 return NULL;
6129 }
6130 }
6131
6132 /* Define the initial recursion depth for procesesing htpasswd files that include other htpasswd
6133 * (or even the same) files. It is not difficult to provide a file or files s.t. they force civetweb
6134 * to infinitely recurse and then crash.
6135 */
6136 #define INITIAL_DEPTH 9
6137 #if INITIAL_DEPTH <= 0
6138 #error Bad INITIAL_DEPTH for recursion, set to at least 1
6139 #endif
6140
6141 struct read_auth_file_struct {
6142 struct mg_connection *conn;
6143 struct ah ah;
6144 char *domain;
6145 char buf[256 + 256 + 40];
6146 char *f_user;
6147 char *f_domain;
6148 char *f_ha1;
6149 };
6150
6151
6152 static int
read_auth_file(struct mg_file * filep,struct read_auth_file_struct * workdata,int depth)6153 read_auth_file(struct mg_file *filep, struct read_auth_file_struct *workdata, int depth)
6154 {
6155 char *p;
6156 int is_authorized = 0;
6157 struct mg_file fp;
6158 size_t l;
6159
6160 if (!filep || !workdata || 0 == depth) {
6161 return 0;
6162 }
6163
6164 /* Loop over passwords file */
6165 p = (char *)filep->access.membuf;
6166 while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) {
6167 l = strlen(workdata->buf);
6168 while (l > 0) {
6169 if (isspace(workdata->buf[l - 1])
6170 || iscntrl(workdata->buf[l - 1])) {
6171 l--;
6172 workdata->buf[l] = 0;
6173 } else
6174 break;
6175 }
6176 if (l < 1) {
6177 continue;
6178 }
6179
6180 workdata->f_user = workdata->buf;
6181
6182 if (workdata->f_user[0] == ':') {
6183 /* user names may not contain a ':' and may not be empty,
6184 * so lines starting with ':' may be used for a special purpose */
6185 if (workdata->f_user[1] == '#') {
6186 /* :# is a comment */
6187 continue;
6188 } else if (!strncmp(workdata->f_user + 1, "include=", 8)) {
6189 if (mg_fopen(workdata->conn,
6190 workdata->f_user + 9,
6191 MG_FOPEN_MODE_READ,
6192 &fp)) {
6193 is_authorized = read_auth_file(&fp, workdata, depth - 1);
6194 (void)mg_fclose(
6195 &fp.access); /* ignore error on read only file */
6196
6197 /* No need to continue processing files once we have a match, since nothing will reset it back
6198 * to 0.
6199 */
6200 if (is_authorized) {
6201 return is_authorized;
6202 }
6203 } else {
6204 mg_cry(workdata->conn,
6205 "%s: cannot open authorization file: %s",
6206 __func__,
6207 workdata->buf);
6208 }
6209 continue;
6210 }
6211 /* everything is invalid for the moment (might change in the
6212 * future) */
6213 mg_cry(workdata->conn,
6214 "%s: syntax error in authorization file: %s",
6215 __func__,
6216 workdata->buf);
6217 continue;
6218 }
6219
6220 workdata->f_domain = strchr(workdata->f_user, ':');
6221 if (workdata->f_domain == NULL) {
6222 mg_cry(workdata->conn,
6223 "%s: syntax error in authorization file: %s",
6224 __func__,
6225 workdata->buf);
6226 continue;
6227 }
6228 *(workdata->f_domain) = 0;
6229 (workdata->f_domain)++;
6230
6231 workdata->f_ha1 = strchr(workdata->f_domain, ':');
6232 if (workdata->f_ha1 == NULL) {
6233 mg_cry(workdata->conn,
6234 "%s: syntax error in authorization file: %s",
6235 __func__,
6236 workdata->buf);
6237 continue;
6238 }
6239 *(workdata->f_ha1) = 0;
6240 (workdata->f_ha1)++;
6241
6242 if (!strcmp(workdata->ah.user, workdata->f_user)
6243 && !strcmp(workdata->domain, workdata->f_domain)) {
6244 return check_password(workdata->conn->request_info.request_method,
6245 workdata->f_ha1,
6246 workdata->ah.uri,
6247 workdata->ah.nonce,
6248 workdata->ah.nc,
6249 workdata->ah.cnonce,
6250 workdata->ah.qop,
6251 workdata->ah.response);
6252 }
6253 }
6254
6255 return is_authorized;
6256 }
6257
6258
6259 /* Authorize against the opened passwords file. Return 1 if authorized. */
6260 static int
authorize(struct mg_connection * conn,struct mg_file * filep)6261 authorize(struct mg_connection *conn, struct mg_file *filep)
6262 {
6263 struct read_auth_file_struct workdata;
6264 char buf[MG_BUF_LEN];
6265
6266 if (!conn || !conn->ctx) {
6267 return 0;
6268 }
6269
6270 memset(&workdata, 0, sizeof(workdata));
6271 workdata.conn = conn;
6272
6273 if (!parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) {
6274 return 0;
6275 }
6276 workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN];
6277
6278 return read_auth_file(filep, &workdata, INITIAL_DEPTH);
6279 }
6280
6281
6282 /* Return 1 if request is authorised, 0 otherwise. */
6283 static int
check_authorization(struct mg_connection * conn,const char * path)6284 check_authorization(struct mg_connection *conn, const char *path)
6285 {
6286 char fname[PATH_MAX];
6287 struct vec uri_vec, filename_vec;
6288 const char *list;
6289 struct mg_file file = STRUCT_FILE_INITIALIZER;
6290 int authorized = 1, truncated;
6291
6292 if (!conn || !conn->ctx) {
6293 return 0;
6294 }
6295
6296 list = conn->ctx->config[PROTECT_URI];
6297 while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
6298 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
6299 mg_snprintf(conn,
6300 &truncated,
6301 fname,
6302 sizeof(fname),
6303 "%.*s",
6304 (int)filename_vec.len,
6305 filename_vec.ptr);
6306
6307 if (truncated
6308 || !mg_fopen(conn, fname, MG_FOPEN_MODE_READ, &file)) {
6309 mg_cry(conn,
6310 "%s: cannot open %s: %s",
6311 __func__,
6312 fname,
6313 strerror(errno));
6314 }
6315 break;
6316 }
6317 }
6318
6319 if (!is_file_opened(&file.access)) {
6320 open_auth_file(conn, path, &file);
6321 }
6322
6323 if (is_file_opened(&file.access)) {
6324 authorized = authorize(conn, &file);
6325 (void)mg_fclose(&file.access); /* ignore error on read only file */
6326 }
6327
6328 return authorized;
6329 }
6330
6331
6332 static void
send_authorization_request(struct mg_connection * conn)6333 send_authorization_request(struct mg_connection *conn)
6334 {
6335 char date[64];
6336 time_t curtime = time(NULL);
6337
6338 if (conn && conn->ctx) {
6339 uint64_t nonce = (uint64_t)(conn->ctx->start_time);
6340
6341 (void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
6342 nonce += conn->ctx->nonce_count;
6343 ++conn->ctx->nonce_count;
6344 (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
6345
6346 nonce ^= conn->ctx->auth_nonce_mask;
6347 conn->status_code = 401;
6348 conn->must_close = 1;
6349
6350 gmt_time_string(date, sizeof(date), &curtime);
6351
6352 mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n");
6353 send_no_cache_header(conn);
6354 mg_printf(conn,
6355 "Date: %s\r\n"
6356 "Connection: %s\r\n"
6357 "Content-Length: 0\r\n"
6358 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
6359 "nonce=\"%" UINT64_FMT "\"\r\n\r\n",
6360 date,
6361 suggest_connection_header(conn),
6362 conn->ctx->config[AUTHENTICATION_DOMAIN],
6363 nonce);
6364 }
6365 }
6366
6367
6368 #if !defined(NO_FILES)
6369 static int
is_authorized_for_put(struct mg_connection * conn)6370 is_authorized_for_put(struct mg_connection *conn)
6371 {
6372 if (conn) {
6373 struct mg_file file = STRUCT_FILE_INITIALIZER;
6374 const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
6375 int ret = 0;
6376
6377 if (passfile != NULL
6378 && mg_fopen(conn, passfile, MG_FOPEN_MODE_READ, &file)) {
6379 ret = authorize(conn, &file);
6380 (void)mg_fclose(&file.access); /* ignore error on read only file */
6381 }
6382
6383 return ret;
6384 }
6385 return 0;
6386 }
6387 #endif
6388
6389
6390 int
mg_modify_passwords_file(const char * fname,const char * domain,const char * user,const char * pass)6391 mg_modify_passwords_file(const char *fname,
6392 const char *domain,
6393 const char *user,
6394 const char *pass)
6395 {
6396 int found, i;
6397 char line[512], u[512] = "", d[512] = "", ha1[33], tmp[PATH_MAX + 8];
6398 FILE *fp, *fp2;
6399
6400 found = 0;
6401 fp = fp2 = NULL;
6402
6403 /* Regard empty password as no password - remove user record. */
6404 if (pass != NULL && pass[0] == '\0') {
6405 pass = NULL;
6406 }
6407
6408 /* Other arguments must not be empty */
6409 if (fname == NULL || domain == NULL || user == NULL) {
6410 return 0;
6411 }
6412
6413 /* Using the given file format, user name and domain must not contain ':'
6414 */
6415 if (strchr(user, ':') != NULL) {
6416 return 0;
6417 }
6418 if (strchr(domain, ':') != NULL) {
6419 return 0;
6420 }
6421
6422 /* Do not allow control characters like newline in user name and domain.
6423 * Do not allow excessively long names either. */
6424 for (i = 0; i < 255 && user[i] != 0; i++) {
6425 if (iscntrl(user[i])) {
6426 return 0;
6427 }
6428 }
6429 if (user[i]) {
6430 return 0;
6431 }
6432 for (i = 0; i < 255 && domain[i] != 0; i++) {
6433 if (iscntrl(domain[i])) {
6434 return 0;
6435 }
6436 }
6437 if (domain[i]) {
6438 return 0;
6439 }
6440
6441 /* The maximum length of the path to the password file is limited */
6442 if ((strlen(fname) + 4) >= PATH_MAX) {
6443 return 0;
6444 }
6445
6446 /* Create a temporary file name. Length has been checked before. */
6447 strcpy(tmp, fname);
6448 strcat(tmp, ".tmp");
6449
6450 /* Create the file if does not exist */
6451 /* Use of fopen here is OK, since fname is only ASCII */
6452 if ((fp = fopen(fname, "a+")) != NULL) {
6453 (void)fclose(fp);
6454 }
6455
6456 /* Open the given file and temporary file */
6457 if ((fp = fopen(fname, "r")) == NULL) {
6458 return 0;
6459 } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
6460 fclose(fp);
6461 return 0;
6462 }
6463
6464 /* Copy the stuff to temporary file */
6465 while (fgets(line, sizeof(line), fp) != NULL) {
6466 if (sscanf(line, "%255[^:]:%255[^:]:%*s", u, d) != 2) {
6467 continue;
6468 }
6469 u[255] = 0;
6470 d[255] = 0;
6471
6472 if (!strcmp(u, user) && !strcmp(d, domain)) {
6473 found++;
6474 if (pass != NULL) {
6475 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
6476 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
6477 }
6478 } else {
6479 fprintf(fp2, "%s", line);
6480 }
6481 }
6482
6483 /* If new user, just add it */
6484 if (!found && pass != NULL) {
6485 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
6486 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
6487 }
6488
6489 /* Close files */
6490 fclose(fp);
6491 fclose(fp2);
6492
6493 /* Put the temp file in place of real file */
6494 IGNORE_UNUSED_RESULT(remove(fname));
6495 IGNORE_UNUSED_RESULT(rename(tmp, fname));
6496
6497 return 1;
6498 }
6499
6500
6501 static int
is_valid_port(unsigned long port)6502 is_valid_port(unsigned long port)
6503 {
6504 return port < 0xffff;
6505 }
6506
6507
6508 static int
mg_inet_pton(int af,const char * src,void * dst,size_t dstlen)6509 mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
6510 {
6511 struct addrinfo hints, *res, *ressave;
6512 int func_ret = 0;
6513 int gai_ret;
6514
6515 memset(&hints, 0, sizeof(struct addrinfo));
6516 hints.ai_family = af;
6517
6518 gai_ret = getaddrinfo(src, NULL, &hints, &res);
6519 if (gai_ret != 0) {
6520 /* gai_strerror could be used to convert gai_ret to a string */
6521 /* POSIX return values: see
6522 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
6523 */
6524 /* Windows return values: see
6525 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
6526 */
6527 return 0;
6528 }
6529
6530 ressave = res;
6531
6532 while (res) {
6533 if (dstlen >= res->ai_addrlen) {
6534 memcpy(dst, res->ai_addr, res->ai_addrlen);
6535 func_ret = 1;
6536 }
6537 res = res->ai_next;
6538 }
6539
6540 freeaddrinfo(ressave);
6541 return func_ret;
6542 }
6543
6544
6545 static int
connect_socket(struct mg_context * ctx,const char * host,int port,int use_ssl,char * ebuf,size_t ebuf_len,SOCKET * sock,union usa * sa)6546 connect_socket(struct mg_context *ctx /* may be NULL */,
6547 const char *host,
6548 int port,
6549 int use_ssl,
6550 char *ebuf,
6551 size_t ebuf_len,
6552 SOCKET *sock /* output: socket, must not be NULL */,
6553 union usa *sa /* output: socket address, must not be NULL */
6554 )
6555 {
6556 int ip_ver = 0;
6557 *sock = INVALID_SOCKET;
6558 memset(sa, 0, sizeof(*sa));
6559
6560 if (ebuf_len > 0) {
6561 *ebuf = 0;
6562 }
6563
6564 if (host == NULL) {
6565 mg_snprintf(NULL,
6566 NULL, /* No truncation check for ebuf */
6567 ebuf,
6568 ebuf_len,
6569 "%s",
6570 "NULL host");
6571 return 0;
6572 }
6573
6574 if (port < 0 || !is_valid_port((unsigned)port)) {
6575 mg_snprintf(NULL,
6576 NULL, /* No truncation check for ebuf */
6577 ebuf,
6578 ebuf_len,
6579 "%s",
6580 "invalid port");
6581 return 0;
6582 }
6583
6584 #if !defined(NO_SSL)
6585 if (use_ssl && (SSLv23_client_method == NULL)) {
6586 mg_snprintf(NULL,
6587 NULL, /* No truncation check for ebuf */
6588 ebuf,
6589 ebuf_len,
6590 "%s",
6591 "SSL is not initialized");
6592 return 0;
6593 }
6594 #else
6595 (void)use_ssl;
6596 #endif
6597
6598 if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) {
6599 sa->sin.sin_port = htons((uint16_t)port);
6600 ip_ver = 4;
6601 #ifdef USE_IPV6
6602 } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) {
6603 sa->sin6.sin6_port = htons((uint16_t)port);
6604 ip_ver = 6;
6605 } else if (host[0] == '[') {
6606 /* While getaddrinfo on Windows will work with [::1],
6607 * getaddrinfo on Linux only works with ::1 (without []). */
6608 size_t l = strlen(host + 1);
6609 char *h = (l > 1) ? mg_strdup(host + 1) : NULL;
6610 if (h) {
6611 h[l - 1] = 0;
6612 if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) {
6613 sa->sin6.sin6_port = htons((uint16_t)port);
6614 ip_ver = 6;
6615 }
6616 mg_free(h);
6617 }
6618 #endif
6619 }
6620
6621 if (ip_ver == 0) {
6622 mg_snprintf(NULL,
6623 NULL, /* No truncation check for ebuf */
6624 ebuf,
6625 ebuf_len,
6626 "%s",
6627 "host not found");
6628 return 0;
6629 }
6630
6631 if (ip_ver == 4) {
6632 *sock = socket(PF_INET, SOCK_STREAM, 0);
6633 }
6634 #ifdef USE_IPV6
6635 else if (ip_ver == 6) {
6636 *sock = socket(PF_INET6, SOCK_STREAM, 0);
6637 }
6638 #endif
6639
6640 if (*sock == INVALID_SOCKET) {
6641 mg_snprintf(NULL,
6642 NULL, /* No truncation check for ebuf */
6643 ebuf,
6644 ebuf_len,
6645 "socket(): %s",
6646 strerror(ERRNO));
6647 return 0;
6648 }
6649
6650 set_close_on_exec(*sock, fc(ctx));
6651
6652 if ((ip_ver == 4)
6653 && (connect(*sock, (struct sockaddr *)&sa->sin, sizeof(sa->sin))
6654 == 0)) {
6655 /* connected with IPv4 */
6656 set_blocking_mode(*sock, 0);
6657 return 1;
6658 }
6659
6660 #ifdef USE_IPV6
6661 if ((ip_ver == 6)
6662 && (connect(*sock, (struct sockaddr *)&sa->sin6, sizeof(sa->sin6))
6663 == 0)) {
6664 /* connected with IPv6 */
6665 set_blocking_mode(*sock, 0);
6666 return 1;
6667 }
6668 #endif
6669
6670 /* Not connected */
6671 mg_snprintf(NULL,
6672 NULL, /* No truncation check for ebuf */
6673 ebuf,
6674 ebuf_len,
6675 "connect(%s:%d): %s",
6676 host,
6677 port,
6678 strerror(ERRNO));
6679 closesocket(*sock);
6680 *sock = INVALID_SOCKET;
6681
6682 return 0;
6683 }
6684
6685
6686 int
mg_url_encode(const char * src,char * dst,size_t dst_len)6687 mg_url_encode(const char *src, char *dst, size_t dst_len)
6688 {
6689 static const char *dont_escape = "._-$,;~()";
6690 static const char *hex = "0123456789abcdef";
6691 char *pos = dst;
6692 const char *end = dst + dst_len - 1;
6693
6694 for (; *src != '\0' && pos < end; src++, pos++) {
6695 if (isalnum(*(const unsigned char *)src)
6696 || strchr(dont_escape, *(const unsigned char *)src) != NULL) {
6697 *pos = *src;
6698 } else if (pos + 2 < end) {
6699 pos[0] = '%';
6700 pos[1] = hex[(*(const unsigned char *)src) >> 4];
6701 pos[2] = hex[(*(const unsigned char *)src) & 0xf];
6702 pos += 2;
6703 } else {
6704 break;
6705 }
6706 }
6707
6708 *pos = '\0';
6709 return (*src == '\0') ? (int)(pos - dst) : -1;
6710 }
6711
6712
6713 static void
print_dir_entry(struct de * de)6714 print_dir_entry(struct de *de)
6715 {
6716 char size[64], mod[64], href[PATH_MAX * 3 /* worst case */];
6717 struct tm *tm;
6718
6719 if (de->file.is_directory) {
6720 mg_snprintf(de->conn,
6721 NULL, /* Buffer is big enough */
6722 size,
6723 sizeof(size),
6724 "%s",
6725 "[DIRECTORY]");
6726 } else {
6727 /* We use (signed) cast below because MSVC 6 compiler cannot
6728 * convert unsigned __int64 to double. Sigh. */
6729 if (de->file.size < 1024) {
6730 mg_snprintf(de->conn,
6731 NULL, /* Buffer is big enough */
6732 size,
6733 sizeof(size),
6734 "%d",
6735 (int)de->file.size);
6736 } else if (de->file.size < 0x100000) {
6737 mg_snprintf(de->conn,
6738 NULL, /* Buffer is big enough */
6739 size,
6740 sizeof(size),
6741 "%.1fk",
6742 (double)de->file.size / 1024.0);
6743 } else if (de->file.size < 0x40000000) {
6744 mg_snprintf(de->conn,
6745 NULL, /* Buffer is big enough */
6746 size,
6747 sizeof(size),
6748 "%.1fM",
6749 (double)de->file.size / 1048576);
6750 } else {
6751 mg_snprintf(de->conn,
6752 NULL, /* Buffer is big enough */
6753 size,
6754 sizeof(size),
6755 "%.1fG",
6756 (double)de->file.size / 1073741824);
6757 }
6758 }
6759
6760 /* Note: mg_snprintf will not cause a buffer overflow above.
6761 * So, string truncation checks are not required here. */
6762
6763 tm = localtime(&de->file.last_modified);
6764 if (tm != NULL) {
6765 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
6766 } else {
6767 mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
6768 mod[sizeof(mod) - 1] = '\0';
6769 }
6770 mg_url_encode(de->file_name, href, sizeof(href));
6771 de->conn->num_bytes_sent +=
6772 mg_printf(de->conn,
6773 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
6774 "<td> %s</td><td> %s</td></tr>\n",
6775 de->conn->request_info.local_uri,
6776 href,
6777 de->file.is_directory ? "/" : "",
6778 de->file_name,
6779 de->file.is_directory ? "/" : "",
6780 mod,
6781 size);
6782 }
6783
6784
6785 /* This function is called from send_directory() and used for
6786 * sorting directory entries by size, or name, or modification time.
6787 * On windows, __cdecl specification is needed in case if project is built
6788 * with __stdcall convention. qsort always requires __cdels callback. */
6789 static int WINCDECL
compare_dir_entries(const void * p1,const void * p2)6790 compare_dir_entries(const void *p1, const void *p2)
6791 {
6792 if (p1 && p2) {
6793 const struct de *a = (const struct de *)p1, *b = (const struct de *)p2;
6794 const char *query_string = a->conn->request_info.query_string;
6795 int cmp_result = 0;
6796
6797 if (query_string == NULL) {
6798 query_string = "na";
6799 }
6800
6801 if (a->file.is_directory && !b->file.is_directory) {
6802 return -1; /* Always put directories on top */
6803 } else if (!a->file.is_directory && b->file.is_directory) {
6804 return 1; /* Always put directories on top */
6805 } else if (*query_string == 'n') {
6806 cmp_result = strcmp(a->file_name, b->file_name);
6807 } else if (*query_string == 's') {
6808 cmp_result = (a->file.size == b->file.size)
6809 ? 0
6810 : ((a->file.size > b->file.size) ? 1 : -1);
6811 } else if (*query_string == 'd') {
6812 cmp_result =
6813 (a->file.last_modified == b->file.last_modified)
6814 ? 0
6815 : ((a->file.last_modified > b->file.last_modified) ? 1
6816 : -1);
6817 }
6818
6819 return (query_string[1] == 'd') ? -cmp_result : cmp_result;
6820 }
6821 return 0;
6822 }
6823
6824
6825 static int
must_hide_file(struct mg_connection * conn,const char * path)6826 must_hide_file(struct mg_connection *conn, const char *path)
6827 {
6828 if (conn && conn->ctx) {
6829 const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
6830 const char *pattern = conn->ctx->config[HIDE_FILES];
6831 return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0
6832 || (pattern != NULL
6833 && match_prefix(pattern, strlen(pattern), path) > 0);
6834 }
6835 return 0;
6836 }
6837
6838
6839 static int
scan_directory(struct mg_connection * conn,const char * dir,void * data,void (* cb)(struct de *,void *))6840 scan_directory(struct mg_connection *conn,
6841 const char *dir,
6842 void *data,
6843 void (*cb)(struct de *, void *))
6844 {
6845 char path[PATH_MAX];
6846 struct dirent *dp;
6847 DIR *dirp;
6848 struct de de;
6849 int truncated;
6850
6851 if ((dirp = mg_opendir(conn, dir)) == NULL) {
6852 return 0;
6853 } else {
6854 de.conn = conn;
6855
6856 while ((dp = mg_readdir(dirp)) != NULL) {
6857 /* Do not show current dir and hidden files */
6858 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
6859 || must_hide_file(conn, dp->d_name)) {
6860 continue;
6861 }
6862
6863 mg_snprintf(
6864 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
6865
6866 /* If we don't memset stat structure to zero, mtime will have
6867 * garbage and strftime() will segfault later on in
6868 * print_dir_entry(). memset is required only if mg_stat()
6869 * fails. For more details, see
6870 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6871 memset(&de.file, 0, sizeof(de.file));
6872
6873 if (truncated) {
6874 /* If the path is not complete, skip processing. */
6875 continue;
6876 }
6877
6878 if (!mg_stat(conn, path, &de.file)) {
6879 mg_cry(conn,
6880 "%s: mg_stat(%s) failed: %s",
6881 __func__,
6882 path,
6883 strerror(ERRNO));
6884 }
6885 de.file_name = dp->d_name;
6886 cb(&de, data);
6887 }
6888 (void)mg_closedir(dirp);
6889 }
6890 return 1;
6891 }
6892
6893
6894 #if !defined(NO_FILES)
6895 static int
remove_directory(struct mg_connection * conn,const char * dir)6896 remove_directory(struct mg_connection *conn, const char *dir)
6897 {
6898 char path[PATH_MAX];
6899 struct dirent *dp;
6900 DIR *dirp;
6901 struct de de;
6902 int truncated;
6903 int ok = 1;
6904
6905 if ((dirp = mg_opendir(conn, dir)) == NULL) {
6906 return 0;
6907 } else {
6908 de.conn = conn;
6909
6910 while ((dp = mg_readdir(dirp)) != NULL) {
6911 /* Do not show current dir (but show hidden files as they will
6912 * also be removed) */
6913 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
6914 continue;
6915 }
6916
6917 mg_snprintf(
6918 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
6919
6920 /* If we don't memset stat structure to zero, mtime will have
6921 * garbage and strftime() will segfault later on in
6922 * print_dir_entry(). memset is required only if mg_stat()
6923 * fails. For more details, see
6924 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6925 memset(&de.file, 0, sizeof(de.file));
6926
6927 if (truncated) {
6928 /* Do not delete anything shorter */
6929 ok = 0;
6930 continue;
6931 }
6932
6933 if (!mg_stat(conn, path, &de.file)) {
6934 mg_cry(conn,
6935 "%s: mg_stat(%s) failed: %s",
6936 __func__,
6937 path,
6938 strerror(ERRNO));
6939 ok = 0;
6940 }
6941
6942 if (de.file.is_directory) {
6943 if (remove_directory(conn, path) == 0) {
6944 ok = 0;
6945 }
6946 } else {
6947 /* This will fail file is the file is in memory */
6948 if (mg_remove(conn, path) == 0) {
6949 ok = 0;
6950 }
6951 }
6952 }
6953 (void)mg_closedir(dirp);
6954
6955 IGNORE_UNUSED_RESULT(rmdir(dir));
6956 }
6957
6958 return ok;
6959 }
6960 #endif
6961
6962
6963 struct dir_scan_data {
6964 struct de *entries;
6965 unsigned int num_entries;
6966 unsigned int arr_size;
6967 };
6968
6969
6970 /* Behaves like realloc(), but frees original pointer on failure */
6971 static void *
realloc2(void * ptr,size_t size)6972 realloc2(void *ptr, size_t size)
6973 {
6974 void *new_ptr = mg_realloc(ptr, size);
6975 if (new_ptr == NULL) {
6976 mg_free(ptr);
6977 }
6978 return new_ptr;
6979 }
6980
6981
6982 static void
dir_scan_callback(struct de * de,void * data)6983 dir_scan_callback(struct de *de, void *data)
6984 {
6985 struct dir_scan_data *dsd = (struct dir_scan_data *)data;
6986
6987 if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
6988 dsd->arr_size *= 2;
6989 dsd->entries =
6990 (struct de *)realloc2(dsd->entries,
6991 dsd->arr_size * sizeof(dsd->entries[0]));
6992 }
6993 if (dsd->entries == NULL) {
6994 /* TODO(lsm, low): propagate an error to the caller */
6995 dsd->num_entries = 0;
6996 } else {
6997 dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
6998 dsd->entries[dsd->num_entries].file = de->file;
6999 dsd->entries[dsd->num_entries].conn = de->conn;
7000 dsd->num_entries++;
7001 }
7002 }
7003
7004
7005 static void
handle_directory_request(struct mg_connection * conn,const char * dir)7006 handle_directory_request(struct mg_connection *conn, const char *dir)
7007 {
7008 unsigned int i;
7009 int sort_direction;
7010 struct dir_scan_data data = {NULL, 0, 128};
7011 char date[64];
7012 time_t curtime = time(NULL);
7013
7014 if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
7015 send_http_error(conn,
7016 500,
7017 "Error: Cannot open directory\nopendir(%s): %s",
7018 dir,
7019 strerror(ERRNO));
7020 return;
7021 }
7022
7023 gmt_time_string(date, sizeof(date), &curtime);
7024
7025 if (!conn) {
7026 return;
7027 }
7028
7029 sort_direction = ((conn->request_info.query_string != NULL)
7030 && (conn->request_info.query_string[1] == 'd'))
7031 ? 'a'
7032 : 'd';
7033
7034 conn->must_close = 1;
7035 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
7036 send_static_cache_header(conn);
7037 mg_printf(conn,
7038 "Date: %s\r\n"
7039 "Connection: close\r\n"
7040 "Content-Type: text/html; charset=utf-8\r\n\r\n",
7041 date);
7042
7043 conn->num_bytes_sent +=
7044 mg_printf(conn,
7045 "<html><head><title>Index of %s</title>"
7046 "<style>th {text-align: left;}</style></head>"
7047 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
7048 "<tr><th><a href=\"?n%c\">Name</a></th>"
7049 "<th><a href=\"?d%c\">Modified</a></th>"
7050 "<th><a href=\"?s%c\">Size</a></th></tr>"
7051 "<tr><td colspan=\"3\"><hr></td></tr>",
7052 conn->request_info.local_uri,
7053 conn->request_info.local_uri,
7054 sort_direction,
7055 sort_direction,
7056 sort_direction);
7057
7058 /* Print first entry - link to a parent directory */
7059 conn->num_bytes_sent +=
7060 mg_printf(conn,
7061 "<tr><td><a href=\"%s%s\">%s</a></td>"
7062 "<td> %s</td><td> %s</td></tr>\n",
7063 conn->request_info.local_uri,
7064 "..",
7065 "Parent directory",
7066 "-",
7067 "-");
7068
7069 /* Sort and print directory entries */
7070 if (data.entries != NULL) {
7071 qsort(data.entries,
7072 (size_t)data.num_entries,
7073 sizeof(data.entries[0]),
7074 compare_dir_entries);
7075 for (i = 0; i < data.num_entries; i++) {
7076 print_dir_entry(&data.entries[i]);
7077 mg_free(data.entries[i].file_name);
7078 }
7079 mg_free(data.entries);
7080 }
7081
7082 conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
7083 conn->status_code = 200;
7084 }
7085
7086
7087 /* Send len bytes from the opened file to the client. */
7088 static void
send_file_data(struct mg_connection * conn,struct mg_file * filep,int64_t offset,int64_t len)7089 send_file_data(struct mg_connection *conn,
7090 struct mg_file *filep,
7091 int64_t offset,
7092 int64_t len)
7093 {
7094 char buf[MG_BUF_LEN];
7095 int to_read, num_read, num_written;
7096 int64_t size;
7097
7098 if (!filep || !conn) {
7099 return;
7100 }
7101
7102 /* Sanity check the offset */
7103 size = (filep->stat.size > INT64_MAX) ? INT64_MAX
7104 : (int64_t)(filep->stat.size);
7105 offset = (offset < 0) ? 0 : ((offset > size) ? size : offset);
7106
7107 if ((len > 0) && (filep->access.membuf != NULL) && (size > 0)) {
7108 /* file stored in memory */
7109 if (len > size - offset) {
7110 len = size - offset;
7111 }
7112 mg_write(conn, filep->access.membuf + offset, (size_t)len);
7113 } else if (len > 0 && filep->access.fp != NULL) {
7114 /* file stored on disk */
7115 #if defined(__linux__)
7116 /* sendfile is only available for Linux */
7117 if ((conn->ssl == 0) && (conn->throttle == 0)
7118 && (!mg_strcasecmp(conn->ctx->config[ALLOW_SENDFILE_CALL],
7119 "yes"))) {
7120 off_t sf_offs = (off_t)offset;
7121 ssize_t sf_sent;
7122 int sf_file = fileno(filep->access.fp);
7123 int loop_cnt = 0;
7124
7125 do {
7126 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
7127 * 64 bit Linux (2^31 minus one memory page of 4k?). */
7128 size_t sf_tosend =
7129 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
7130 sf_sent =
7131 sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
7132 if (sf_sent > 0) {
7133 conn->num_bytes_sent += sf_sent;
7134 len -= sf_sent;
7135 offset += sf_sent;
7136 } else if (loop_cnt == 0) {
7137 /* This file can not be sent using sendfile.
7138 * This might be the case for pseudo-files in the
7139 * /sys/ and /proc/ file system.
7140 * Use the regular user mode copy code instead. */
7141 break;
7142 } else if (sf_sent == 0) {
7143 /* No error, but 0 bytes sent. May be EOF? */
7144 return;
7145 }
7146 loop_cnt++;
7147
7148 } while ((len > 0) && (sf_sent >= 0));
7149
7150 if (sf_sent > 0) {
7151 return; /* OK */
7152 }
7153
7154 /* sf_sent<0 means error, thus fall back to the classic way */
7155 /* This is always the case, if sf_file is not a "normal" file,
7156 * e.g., for sending data from the output of a CGI process. */
7157 offset = (int64_t)sf_offs;
7158 }
7159 #endif
7160 if ((offset > 0) && (fseeko(filep->access.fp, offset, SEEK_SET) != 0)) {
7161 mg_cry(conn, "%s: fseeko() failed: %s", __func__, strerror(ERRNO));
7162 send_http_error(
7163 conn,
7164 500,
7165 "%s",
7166 "Error: Unable to access file at requested position.");
7167 } else {
7168 while (len > 0) {
7169 /* Calculate how much to read from the file in the buffer */
7170 to_read = sizeof(buf);
7171 if ((int64_t)to_read > len) {
7172 to_read = (int)len;
7173 }
7174
7175 /* Read from file, exit the loop on error */
7176 if ((num_read =
7177 (int)fread(buf, 1, (size_t)to_read, filep->access.fp))
7178 <= 0) {
7179 break;
7180 }
7181
7182 /* Send read bytes to the client, exit the loop on error */
7183 if ((num_written = mg_write(conn, buf, (size_t)num_read))
7184 != num_read) {
7185 break;
7186 }
7187
7188 /* Both read and were successful, adjust counters */
7189 conn->num_bytes_sent += num_written;
7190 len -= num_written;
7191 }
7192 }
7193 }
7194 }
7195
7196
7197 static int
parse_range_header(const char * header,int64_t * a,int64_t * b)7198 parse_range_header(const char *header, int64_t *a, int64_t *b)
7199 {
7200 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
7201 }
7202
7203
7204 static void
construct_etag(char * buf,size_t buf_len,const struct mg_file_stat * filestat)7205 construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
7206 {
7207 if (filestat != NULL && buf != NULL) {
7208 mg_snprintf(NULL,
7209 NULL, /* All calls to construct_etag use 64 byte buffer */
7210 buf,
7211 buf_len,
7212 "\"%lx.%" INT64_FMT "\"",
7213 (unsigned long)filestat->last_modified,
7214 filestat->size);
7215 }
7216 }
7217
7218
7219 static void
fclose_on_exec(struct mg_file_access * filep,struct mg_connection * conn)7220 fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
7221 {
7222 if (filep != NULL && filep->fp != NULL) {
7223 #ifdef _WIN32
7224 (void)conn; /* Unused. */
7225 #else
7226 if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
7227 mg_cry(conn,
7228 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
7229 __func__,
7230 strerror(ERRNO));
7231 }
7232 #endif
7233 }
7234 }
7235
7236
7237 static void
handle_static_file_request(struct mg_connection * conn,const char * path,struct mg_file * filep,const char * mime_type,const char * additional_headers)7238 handle_static_file_request(struct mg_connection *conn,
7239 const char *path,
7240 struct mg_file *filep,
7241 const char *mime_type,
7242 const char *additional_headers)
7243 {
7244 char date[64], lm[64], etag[64];
7245 char range[128]; /* large enough, so there will be no overflow */
7246 const char *msg = "OK", *hdr;
7247 time_t curtime = time(NULL);
7248 int64_t cl, r1, r2;
7249 struct vec mime_vec;
7250 int n, truncated;
7251 char gz_path[PATH_MAX];
7252 const char *encoding = "";
7253 const char *cors1, *cors2, *cors3;
7254
7255 if (conn == NULL || conn->ctx == NULL || filep == NULL) {
7256 return;
7257 }
7258
7259 if (mime_type == NULL) {
7260 get_mime_type(conn->ctx, path, &mime_vec);
7261 } else {
7262 mime_vec.ptr = mime_type;
7263 mime_vec.len = strlen(mime_type);
7264 }
7265 if (filep->stat.size > INT64_MAX) {
7266 send_http_error(conn,
7267 500,
7268 "Error: File size is too large to send\n%" INT64_FMT,
7269 filep->stat.size);
7270 }
7271 cl = (int64_t)filep->stat.size;
7272 conn->status_code = 200;
7273 range[0] = '\0';
7274
7275 /* if this file is in fact a pre-gzipped file, rewrite its filename
7276 * it's important to rewrite the filename after resolving
7277 * the mime type from it, to preserve the actual file's type */
7278 if (filep->stat.is_gzipped) {
7279 mg_snprintf(conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", path);
7280
7281 if (truncated) {
7282 send_http_error(conn,
7283 500,
7284 "Error: Path of zipped file too long (%s)",
7285 path);
7286 return;
7287 }
7288
7289 path = gz_path;
7290 encoding = "Content-Encoding: gzip\r\n";
7291 }
7292
7293 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
7294 send_http_error(conn,
7295 500,
7296 "Error: Cannot open file\nfopen(%s): %s",
7297 path,
7298 strerror(ERRNO));
7299 return;
7300 }
7301
7302 fclose_on_exec(&filep->access, conn);
7303
7304 /* If Range: header specified, act accordingly */
7305 r1 = r2 = 0;
7306 hdr = mg_get_header(conn, "Range");
7307 if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0
7308 && r2 >= 0) {
7309 /* actually, range requests don't play well with a pre-gzipped
7310 * file (since the range is specified in the uncompressed space) */
7311 if (filep->stat.is_gzipped) {
7312 send_http_error(
7313 conn,
7314 501,
7315 "%s",
7316 "Error: Range requests in gzipped files are not supported");
7317 (void)mg_fclose(
7318 &filep->access); /* ignore error on read only file */
7319 return;
7320 }
7321 conn->status_code = 206;
7322 cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
7323 mg_snprintf(conn,
7324 NULL, /* range buffer is big enough */
7325 range,
7326 sizeof(range),
7327 "Content-Range: bytes "
7328 "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
7329 r1,
7330 r1 + cl - 1,
7331 filep->stat.size);
7332 msg = "Partial Content";
7333 }
7334
7335 hdr = mg_get_header(conn, "Origin");
7336 if (hdr) {
7337 /* Cross-origin resource sharing (CORS), see
7338 * http://www.html5rocks.com/en/tutorials/cors/,
7339 * http://www.html5rocks.com/static/images/cors_server_flowchart.png -
7340 * preflight is not supported for files. */
7341 cors1 = "Access-Control-Allow-Origin: ";
7342 cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
7343 cors3 = "\r\n";
7344 } else {
7345 cors1 = cors2 = cors3 = "";
7346 }
7347
7348 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
7349 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
7350 gmt_time_string(date, sizeof(date), &curtime);
7351 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
7352 construct_etag(etag, sizeof(etag), &filep->stat);
7353
7354 (void)mg_printf(conn,
7355 "HTTP/1.1 %d %s\r\n"
7356 "%s%s%s"
7357 "Date: %s\r\n",
7358 conn->status_code,
7359 msg,
7360 cors1,
7361 cors2,
7362 cors3,
7363 date);
7364 send_static_cache_header(conn);
7365 (void)mg_printf(conn,
7366 "Last-Modified: %s\r\n"
7367 "Etag: %s\r\n"
7368 "Content-Type: %.*s\r\n"
7369 "Content-Length: %" INT64_FMT "\r\n"
7370 "Connection: %s\r\n"
7371 "Accept-Ranges: bytes\r\n"
7372 "%s%s",
7373 lm,
7374 etag,
7375 (int)mime_vec.len,
7376 mime_vec.ptr,
7377 cl,
7378 suggest_connection_header(conn),
7379 range,
7380 encoding);
7381
7382 /* The previous code must not add any header starting with X- to make
7383 * sure no one of the additional_headers is included twice */
7384
7385 if (additional_headers != NULL) {
7386 (void)mg_printf(conn,
7387 "%.*s\r\n\r\n",
7388 (int)strlen(additional_headers),
7389 additional_headers);
7390 } else {
7391 (void)mg_printf(conn, "\r\n");
7392 }
7393
7394 if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
7395 send_file_data(conn, filep, r1, cl);
7396 }
7397 (void)mg_fclose(&filep->access); /* ignore error on read only file */
7398 }
7399
7400
7401 #if !defined(NO_CACHING)
7402 static void
handle_not_modified_static_file_request(struct mg_connection * conn,struct mg_file * filep)7403 handle_not_modified_static_file_request(struct mg_connection *conn,
7404 struct mg_file *filep)
7405 {
7406 char date[64], lm[64], etag[64];
7407 time_t curtime = time(NULL);
7408
7409 if (conn == NULL || filep == NULL) {
7410 return;
7411 }
7412 conn->status_code = 304;
7413 gmt_time_string(date, sizeof(date), &curtime);
7414 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
7415 construct_etag(etag, sizeof(etag), &filep->stat);
7416
7417 (void)mg_printf(conn,
7418 "HTTP/1.1 %d %s\r\n"
7419 "Date: %s\r\n",
7420 conn->status_code,
7421 mg_get_response_code_text(conn, conn->status_code),
7422 date);
7423 send_static_cache_header(conn);
7424 (void)mg_printf(conn,
7425 "Last-Modified: %s\r\n"
7426 "Etag: %s\r\n"
7427 "Connection: %s\r\n"
7428 "\r\n",
7429 lm,
7430 etag,
7431 suggest_connection_header(conn));
7432 }
7433 #endif
7434
7435
7436 void
mg_send_file(struct mg_connection * conn,const char * path)7437 mg_send_file(struct mg_connection *conn, const char *path)
7438 {
7439 mg_send_mime_file(conn, path, NULL);
7440 }
7441
7442
7443 void
mg_send_mime_file(struct mg_connection * conn,const char * path,const char * mime_type)7444 mg_send_mime_file(struct mg_connection *conn,
7445 const char *path,
7446 const char *mime_type)
7447 {
7448 mg_send_mime_file2(conn, path, mime_type, NULL);
7449 }
7450
7451
7452 void
mg_send_mime_file2(struct mg_connection * conn,const char * path,const char * mime_type,const char * additional_headers)7453 mg_send_mime_file2(struct mg_connection *conn,
7454 const char *path,
7455 const char *mime_type,
7456 const char *additional_headers)
7457 {
7458 struct mg_file file = STRUCT_FILE_INITIALIZER;
7459 if (mg_stat(conn, path, &file.stat)) {
7460 if (file.stat.is_directory) {
7461 if (!conn) {
7462 return;
7463 }
7464 if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
7465 "yes")) {
7466 handle_directory_request(conn, path);
7467 } else {
7468 send_http_error(conn,
7469 403,
7470 "%s",
7471 "Error: Directory listing denied");
7472 }
7473 } else {
7474 handle_static_file_request(
7475 conn, path, &file, mime_type, additional_headers);
7476 }
7477 } else {
7478 send_http_error(conn, 404, "%s", "Error: File not found");
7479 }
7480 }
7481
7482
7483 /* For a given PUT path, create all intermediate subdirectories.
7484 * Return 0 if the path itself is a directory.
7485 * Return 1 if the path leads to a file.
7486 * Return -1 for if the path is too long.
7487 * Return -2 if path can not be created.
7488 */
7489 static int
put_dir(struct mg_connection * conn,const char * path)7490 put_dir(struct mg_connection *conn, const char *path)
7491 {
7492 char buf[PATH_MAX];
7493 const char *s, *p;
7494 struct mg_file file = STRUCT_FILE_INITIALIZER;
7495 size_t len;
7496 int res = 1;
7497
7498 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
7499 len = (size_t)(p - path);
7500 if (len >= sizeof(buf)) {
7501 /* path too long */
7502 res = -1;
7503 break;
7504 }
7505 memcpy(buf, path, len);
7506 buf[len] = '\0';
7507
7508 /* Try to create intermediate directory */
7509 DEBUG_TRACE("mkdir(%s)", buf);
7510 if (!mg_stat(conn, buf, &file.stat) && mg_mkdir(conn, buf, 0755) != 0) {
7511 /* path does not exixt and can not be created */
7512 res = -2;
7513 break;
7514 }
7515
7516 /* Is path itself a directory? */
7517 if (p[1] == '\0') {
7518 res = 0;
7519 }
7520 }
7521
7522 return res;
7523 }
7524
7525
7526 static void
remove_bad_file(const struct mg_connection * conn,const char * path)7527 remove_bad_file(const struct mg_connection *conn, const char *path)
7528 {
7529 int r = mg_remove(conn, path);
7530 if (r != 0) {
7531 mg_cry(conn, "%s: Cannot remove invalid file %s", __func__, path);
7532 }
7533 }
7534
7535
7536 long long
mg_store_body(struct mg_connection * conn,const char * path)7537 mg_store_body(struct mg_connection *conn, const char *path)
7538 {
7539 char buf[MG_BUF_LEN];
7540 long long len = 0;
7541 int ret, n;
7542 struct mg_file fi;
7543
7544 if (conn->consumed_content != 0) {
7545 mg_cry(conn, "%s: Contents already consumed", __func__);
7546 return -11;
7547 }
7548
7549 ret = put_dir(conn, path);
7550 if (ret < 0) {
7551 /* -1 for path too long,
7552 * -2 for path can not be created. */
7553 return ret;
7554 }
7555 if (ret != 1) {
7556 /* Return 0 means, path itself is a directory. */
7557 return 0;
7558 }
7559
7560 if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fi) == 0) {
7561 return -12;
7562 }
7563
7564 ret = mg_read(conn, buf, sizeof(buf));
7565 while (ret > 0) {
7566 n = (int)fwrite(buf, 1, (size_t)ret, fi.access.fp);
7567 if (n != ret) {
7568 (void)mg_fclose(
7569 &fi.access); /* File is bad and will be removed anyway. */
7570 remove_bad_file(conn, path);
7571 return -13;
7572 }
7573 ret = mg_read(conn, buf, sizeof(buf));
7574 }
7575
7576 /* File is open for writing. If fclose fails, there was probably an
7577 * error flushing the buffer to disk, so the file on disk might be
7578 * broken. Delete it and return an error to the caller. */
7579 if (mg_fclose(&fi.access) != 0) {
7580 remove_bad_file(conn, path);
7581 return -14;
7582 }
7583
7584 return len;
7585 }
7586
7587
7588 /* Parse HTTP headers from the given buffer, advance buf pointer
7589 * to the point where parsing stopped.
7590 * All parameters must be valid pointers (not NULL).
7591 * Return <0 on error. */
7592 static int
parse_http_headers(char ** buf,struct mg_request_info * ri)7593 parse_http_headers(char **buf, struct mg_request_info *ri)
7594 {
7595 int i;
7596
7597 ri->num_headers = 0;
7598
7599 for (i = 0; i < (int)ARRAY_SIZE(ri->http_headers); i++) {
7600 char *dp = *buf;
7601 while ((*dp != ':') && (*dp >= 33) && (*dp <= 126)) {
7602 dp++;
7603 }
7604 if (dp == *buf) {
7605 /* End of headers reached. */
7606 break;
7607 }
7608 if (*dp != ':') {
7609 /* This is not a valid field. */
7610 return -1;
7611 }
7612
7613 /* End of header key (*dp == ':') */
7614 /* Truncate here and set the key name */
7615 *dp = 0;
7616 ri->http_headers[i].name = *buf;
7617 do {
7618 dp++;
7619 } while (*dp == ' ');
7620
7621 /* The rest of the line is the value */
7622 ri->http_headers[i].value = dp;
7623 *buf = dp + strcspn(dp, "\r\n");
7624 if (((*buf)[0] != '\r') || ((*buf)[1] != '\n')) {
7625 *buf = NULL;
7626 }
7627
7628
7629 ri->num_headers = i + 1;
7630 if (*buf) {
7631 (*buf)[0] = 0;
7632 (*buf)[1] = 0;
7633 *buf += 2;
7634 } else {
7635 *buf = dp;
7636 break;
7637 }
7638
7639 if ((*buf)[0] == '\r') {
7640 /* This is the end of the header */
7641 break;
7642 }
7643 }
7644 return ri->num_headers;
7645 }
7646
7647
7648 static int
is_valid_http_method(const char * method)7649 is_valid_http_method(const char *method)
7650 {
7651 return !strcmp(method, "GET") /* HTTP (RFC 2616) */
7652 || !strcmp(method, "POST") /* HTTP (RFC 2616) */
7653 || !strcmp(method, "HEAD") /* HTTP (RFC 2616) */
7654 || !strcmp(method, "PUT") /* HTTP (RFC 2616) */
7655 || !strcmp(method, "DELETE") /* HTTP (RFC 2616) */
7656 || !strcmp(method, "OPTIONS") /* HTTP (RFC 2616) */
7657 /* TRACE method (RFC 2616) is not supported for security reasons */
7658 || !strcmp(method, "CONNECT") /* HTTP (RFC 2616) */
7659
7660 || !strcmp(method, "PROPFIND") /* WEBDAV (RFC 2518) */
7661 || !strcmp(method, "MKCOL") /* WEBDAV (RFC 2518) */
7662
7663 /* Unsupported WEBDAV Methods: */
7664 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
7665 /* + 11 methods from RFC 3253 */
7666 /* ORDERPATCH (RFC 3648) */
7667 /* ACL (RFC 3744) */
7668 /* SEARCH (RFC 5323) */
7669 /* + MicroSoft extensions
7670 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
7671
7672 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
7673 || !strcmp(method, "PATCH"); /* PATCH method (RFC 5789) */
7674 }
7675
7676
7677 /* Parse HTTP request, fill in mg_request_info structure.
7678 * This function modifies the buffer by NUL-terminating
7679 * HTTP request components, header names and header values.
7680 * Parameters:
7681 * buf (in/out): pointer to the HTTP header to parse and split
7682 * len (in): length of HTTP header buffer
7683 * re (out): parsed header as mg_request_info
7684 * buf and ri must be valid pointers (not NULL), len>0.
7685 * Returns <0 on error. */
7686 static int
parse_http_message(char * buf,int len,struct mg_request_info * ri)7687 parse_http_message(char *buf, int len, struct mg_request_info *ri)
7688 {
7689 int is_request, request_length;
7690 char *start_line;
7691
7692 request_length = get_request_len(buf, len);
7693
7694 if (request_length > 0) {
7695 /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
7696 * remote_port */
7697 ri->remote_user = ri->request_method = ri->request_uri =
7698 ri->http_version = NULL;
7699 ri->num_headers = 0;
7700
7701 buf[request_length - 1] = '\0';
7702
7703 /* RFC says that all initial whitespaces should be ingored */
7704 while (*buf != '\0' && isspace(*(unsigned char *)buf)) {
7705 buf++;
7706 }
7707 start_line = skip(&buf, "\r\n");
7708 ri->request_method = skip(&start_line, " ");
7709 ri->request_uri = skip(&start_line, " ");
7710 ri->http_version = start_line;
7711
7712 /* HTTP message could be either HTTP request:
7713 * "GET / HTTP/1.0 ..."
7714 * or a HTTP response:
7715 * "HTTP/1.0 200 OK ..."
7716 * otherwise it is invalid.
7717 */
7718 is_request = is_valid_http_method(ri->request_method);
7719 if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0)
7720 || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
7721 /* Not a valid request or response: invalid */
7722 return -1;
7723 }
7724 if (is_request) {
7725 ri->http_version += 5;
7726 }
7727 if (parse_http_headers(&buf, ri) < 0) {
7728 /* Error while parsing headers */
7729 return -1;
7730 }
7731 }
7732 return request_length;
7733 }
7734
7735
7736 /* Keep reading the input (either opened file descriptor fd, or socket sock,
7737 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
7738 * buffer (which marks the end of HTTP request). Buffer buf may already
7739 * have some data. The length of the data is stored in nread.
7740 * Upon every read operation, increase nread by the number of bytes read. */
7741 static int
read_request(FILE * fp,struct mg_connection * conn,char * buf,int bufsiz,int * nread)7742 read_request(FILE *fp,
7743 struct mg_connection *conn,
7744 char *buf,
7745 int bufsiz,
7746 int *nread)
7747 {
7748 int request_len, n = 0;
7749 struct timespec last_action_time;
7750 double request_timeout;
7751
7752 if (!conn) {
7753 return 0;
7754 }
7755
7756 memset(&last_action_time, 0, sizeof(last_action_time));
7757
7758 if (conn->ctx->config[REQUEST_TIMEOUT]) {
7759 /* value of request_timeout is in seconds, config in milliseconds */
7760 request_timeout = atof(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
7761 } else {
7762 request_timeout = -1.0;
7763 }
7764 if (conn->handled_requests > 0) {
7765 if (conn->ctx->config[KEEP_ALIVE_TIMEOUT]) {
7766 request_timeout =
7767 atof(conn->ctx->config[KEEP_ALIVE_TIMEOUT]) / 1000.0;
7768 }
7769 }
7770
7771 request_len = get_request_len(buf, *nread);
7772
7773 /* first time reading from this connection */
7774 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
7775
7776 while (request_len == 0) {
7777 /* Full request not yet received */
7778 if (conn->ctx->stop_flag != 0) {
7779 /* Server is to be stopped. */
7780 return -1;
7781 }
7782
7783 if (*nread >= bufsiz) {
7784 /* Request too long */
7785 return -2;
7786 }
7787
7788 n = pull(fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
7789 if (n < 0) {
7790 /* Receive error */
7791 return -1;
7792 }
7793 *nread += n;
7794 request_len = get_request_len(buf, *nread);
7795
7796 if ((request_len == 0) && (request_timeout >= 0)) {
7797 if (mg_difftimespec(&last_action_time, &(conn->req_time))
7798 > request_timeout) {
7799 /* Timeout */
7800 return -1;
7801 }
7802 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
7803 }
7804 }
7805
7806 return request_len;
7807 }
7808
7809 #if !defined(NO_FILES)
7810 /* For given directory path, substitute it to valid index file.
7811 * Return 1 if index file has been found, 0 if not found.
7812 * If the file is found, it's stats is returned in stp. */
7813 static int
substitute_index_file(struct mg_connection * conn,char * path,size_t path_len,struct mg_file * filep)7814 substitute_index_file(struct mg_connection *conn,
7815 char *path,
7816 size_t path_len,
7817 struct mg_file *filep)
7818 {
7819 if (conn && conn->ctx) {
7820 const char *list = conn->ctx->config[INDEX_FILES];
7821 struct mg_file file = STRUCT_FILE_INITIALIZER;
7822 struct vec filename_vec;
7823 size_t n = strlen(path);
7824 int found = 0;
7825
7826 /* The 'path' given to us points to the directory. Remove all trailing
7827 * directory separator characters from the end of the path, and
7828 * then append single directory separator character. */
7829 while (n > 0 && path[n - 1] == '/') {
7830 n--;
7831 }
7832 path[n] = '/';
7833
7834 /* Traverse index files list. For each entry, append it to the given
7835 * path and see if the file exists. If it exists, break the loop */
7836 while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
7837 /* Ignore too long entries that may overflow path buffer */
7838 if (filename_vec.len > path_len - (n + 2)) {
7839 continue;
7840 }
7841
7842 /* Prepare full path to the index file */
7843 mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
7844
7845 /* Does it exist? */
7846 if (mg_stat(conn, path, &file.stat)) {
7847 /* Yes it does, break the loop */
7848 *filep = file;
7849 found = 1;
7850 break;
7851 }
7852 }
7853
7854 /* If no index file exists, restore directory path */
7855 if (!found) {
7856 path[n] = '\0';
7857 }
7858
7859 return found;
7860 }
7861 return 0;
7862 }
7863 #endif
7864
7865
7866 #if !defined(NO_CACHING)
7867 /* Return True if we should reply 304 Not Modified. */
7868 static int
is_not_modified(const struct mg_connection * conn,const struct mg_file_stat * filestat)7869 is_not_modified(const struct mg_connection *conn,
7870 const struct mg_file_stat *filestat)
7871 {
7872 char etag[64];
7873 const char *ims = mg_get_header(conn, "If-Modified-Since");
7874 const char *inm = mg_get_header(conn, "If-None-Match");
7875 construct_etag(etag, sizeof(etag), filestat);
7876
7877 return (inm != NULL && !mg_strcasecmp(etag, inm))
7878 || ((ims != NULL)
7879 && (filestat->last_modified <= parse_date_string(ims)));
7880 }
7881 #endif /* !NO_CACHING */
7882
7883
7884 #if !defined(NO_CGI) || !defined(NO_FILES)
7885 static int
forward_body_data(struct mg_connection * conn,FILE * fp,SOCKET sock,SSL * ssl)7886 forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
7887 {
7888 const char *expect, *body;
7889 char buf[MG_BUF_LEN];
7890 int to_read, nread, success = 0;
7891 int64_t buffered_len;
7892 double timeout = -1.0;
7893
7894 if (!conn) {
7895 return 0;
7896 }
7897 if (conn->ctx->config[REQUEST_TIMEOUT]) {
7898 timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
7899 }
7900
7901 expect = mg_get_header(conn, "Expect");
7902 /* assert(fp != NULL); */
7903 if (!fp) {
7904 send_http_error(conn, 500, "%s", "Error: NULL File");
7905 return 0;
7906 }
7907
7908 if (conn->content_len == -1 && !conn->is_chunked) {
7909 /* Content length is not specified by the client. */
7910 send_http_error(conn,
7911 411,
7912 "%s",
7913 "Error: Client did not specify content length");
7914 } else if ((expect != NULL)
7915 && (mg_strcasecmp(expect, "100-continue") != 0)) {
7916 /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
7917 send_http_error(conn,
7918 417,
7919 "Error: Can not fulfill expectation %s",
7920 expect);
7921 } else {
7922 if (expect != NULL) {
7923 (void)mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
7924 conn->status_code = 100;
7925 } else {
7926 conn->status_code = 200;
7927 }
7928
7929 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
7930 - conn->consumed_content;
7931
7932 /* assert(buffered_len >= 0); */
7933 /* assert(conn->consumed_content == 0); */
7934
7935 if ((buffered_len < 0) || (conn->consumed_content != 0)) {
7936 send_http_error(conn, 500, "%s", "Error: Size mismatch");
7937 return 0;
7938 }
7939
7940 if (buffered_len > 0) {
7941 if ((int64_t)buffered_len > conn->content_len) {
7942 buffered_len = (int)conn->content_len;
7943 }
7944 body = conn->buf + conn->request_len + conn->consumed_content;
7945 push_all(conn->ctx, fp, sock, ssl, body, (int64_t)buffered_len);
7946 conn->consumed_content += buffered_len;
7947 }
7948
7949 nread = 0;
7950 while (conn->consumed_content < conn->content_len) {
7951 to_read = sizeof(buf);
7952 if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
7953 to_read = (int)(conn->content_len - conn->consumed_content);
7954 }
7955 nread = pull(NULL, conn, buf, to_read, timeout);
7956 if (nread <= 0
7957 || push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) {
7958 break;
7959 }
7960 conn->consumed_content += nread;
7961 }
7962
7963 if (conn->consumed_content == conn->content_len) {
7964 success = (nread >= 0);
7965 }
7966
7967 /* Each error code path in this function must send an error */
7968 if (!success) {
7969 /* NOTE: Maybe some data has already been sent. */
7970 /* TODO (low): If some data has been sent, a correct error
7971 * reply can no longer be sent, so just close the connection */
7972 send_http_error(conn, 500, "%s", "");
7973 }
7974 }
7975
7976 return success;
7977 }
7978 #endif
7979
7980 #if !defined(NO_CGI)
7981 /* This structure helps to create an environment for the spawned CGI program.
7982 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
7983 * last element must be NULL.
7984 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
7985 * strings must reside in a contiguous buffer. The end of the buffer is
7986 * marked by two '\0' characters.
7987 * We satisfy both worlds: we create an envp array (which is vars), all
7988 * entries are actually pointers inside buf. */
7989 struct cgi_environment {
7990 struct mg_connection *conn;
7991 /* Data block */
7992 char *buf; /* Environment buffer */
7993 size_t buflen; /* Space available in buf */
7994 size_t bufused; /* Space taken in buf */
7995 /* Index block */
7996 char **var; /* char **envp */
7997 size_t varlen; /* Number of variables available in var */
7998 size_t varused; /* Number of variables stored in var */
7999 };
8000
8001
8002 static void addenv(struct cgi_environment *env,
8003 PRINTF_FORMAT_STRING(const char *fmt),
8004 ...) PRINTF_ARGS(2, 3);
8005
8006 /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
8007 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
8008 static void
addenv(struct cgi_environment * env,const char * fmt,...)8009 addenv(struct cgi_environment *env, const char *fmt, ...)
8010 {
8011 size_t n, space;
8012 int truncated = 0;
8013 char *added;
8014 va_list ap;
8015
8016 /* Calculate how much space is left in the buffer */
8017 space = (env->buflen - env->bufused);
8018
8019 /* Calculate an estimate for the required space */
8020 n = strlen(fmt) + 2 + 128;
8021
8022 do {
8023 if (space <= n) {
8024 /* Allocate new buffer */
8025 n = env->buflen + CGI_ENVIRONMENT_SIZE;
8026 added = (char *)mg_realloc(env->buf, n);
8027 if (!added) {
8028 /* Out of memory */
8029 mg_cry(env->conn,
8030 "%s: Cannot allocate memory for CGI variable [%s]",
8031 __func__,
8032 fmt);
8033 return;
8034 }
8035 env->buf = added;
8036 env->buflen = n;
8037 space = (env->buflen - env->bufused);
8038 }
8039
8040 /* Make a pointer to the free space int the buffer */
8041 added = env->buf + env->bufused;
8042
8043 /* Copy VARIABLE=VALUE\0 string into the free space */
8044 va_start(ap, fmt);
8045 mg_vsnprintf(env->conn, &truncated, added, (size_t)space, fmt, ap);
8046 va_end(ap);
8047
8048 /* Do not add truncated strings to the environment */
8049 if (truncated) {
8050 /* Reallocate the buffer */
8051 space = 0;
8052 n = 1;
8053 }
8054 } while (truncated);
8055
8056 /* Calculate number of bytes added to the environment */
8057 n = strlen(added) + 1;
8058 env->bufused += n;
8059
8060 /* Now update the variable index */
8061 space = (env->varlen - env->varused);
8062 if (space < 2) {
8063 mg_cry(env->conn,
8064 "%s: Cannot register CGI variable [%s]",
8065 __func__,
8066 fmt);
8067 return;
8068 }
8069
8070 /* Append a pointer to the added string into the envp array */
8071 env->var[env->varused] = added;
8072 env->varused++;
8073 }
8074
8075
8076 static void
prepare_cgi_environment(struct mg_connection * conn,const char * prog,struct cgi_environment * env)8077 prepare_cgi_environment(struct mg_connection *conn,
8078 const char *prog,
8079 struct cgi_environment *env)
8080 {
8081 const char *s;
8082 struct vec var_vec;
8083 char *p, src_addr[IP_ADDR_STR_LEN], http_var_name[128];
8084 int i, truncated, uri_len;
8085
8086 if (conn == NULL || prog == NULL || env == NULL) {
8087 return;
8088 }
8089
8090 env->conn = conn;
8091 env->buflen = CGI_ENVIRONMENT_SIZE;
8092 env->bufused = 0;
8093 env->buf = (char *)mg_malloc(env->buflen);
8094 env->varlen = MAX_CGI_ENVIR_VARS;
8095 env->varused = 0;
8096 env->var = (char **)mg_malloc(env->buflen * sizeof(char *));
8097
8098 addenv(env, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
8099 addenv(env, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
8100 addenv(env, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
8101 addenv(env, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
8102
8103 /* Prepare the environment block */
8104 addenv(env, "%s", "GATEWAY_INTERFACE=CGI/1.1");
8105 addenv(env, "%s", "SERVER_PROTOCOL=HTTP/1.1");
8106 addenv(env, "%s", "REDIRECT_STATUS=200"); /* For PHP */
8107
8108 #if defined(USE_IPV6)
8109 if (conn->client.lsa.sa.sa_family == AF_INET6) {
8110 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
8111 } else
8112 #endif
8113 {
8114 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
8115 }
8116
8117 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
8118 addenv(env, "REMOTE_ADDR=%s", src_addr);
8119
8120 addenv(env, "REQUEST_METHOD=%s", conn->request_info.request_method);
8121 addenv(env, "REMOTE_PORT=%d", conn->request_info.remote_port);
8122
8123 addenv(env, "REQUEST_URI=%s", conn->request_info.request_uri);
8124 addenv(env, "LOCAL_URI=%s", conn->request_info.local_uri);
8125
8126 /* SCRIPT_NAME */
8127 uri_len = (int)strlen(conn->request_info.local_uri);
8128 if (conn->path_info == NULL) {
8129 if (conn->request_info.local_uri[uri_len - 1] != '/') {
8130 /* URI: /path_to_script/script.cgi */
8131 addenv(env, "SCRIPT_NAME=%s", conn->request_info.local_uri);
8132 } else {
8133 /* URI: /path_to_script/ ... using index.cgi */
8134 char *index_file = strrchr(prog, '/');
8135 if (index_file) {
8136 addenv(env,
8137 "SCRIPT_NAME=%s%s",
8138 conn->request_info.local_uri,
8139 index_file + 1);
8140 }
8141 }
8142 } else {
8143 /* URI: /path_to_script/script.cgi/path_info */
8144 addenv(env,
8145 "SCRIPT_NAME=%.*s",
8146 uri_len - (int)strlen(conn->path_info),
8147 conn->request_info.local_uri);
8148 }
8149
8150 addenv(env, "SCRIPT_FILENAME=%s", prog);
8151 if (conn->path_info == NULL) {
8152 addenv(env, "PATH_TRANSLATED=%s", conn->ctx->config[DOCUMENT_ROOT]);
8153 } else {
8154 addenv(env,
8155 "PATH_TRANSLATED=%s%s",
8156 conn->ctx->config[DOCUMENT_ROOT],
8157 conn->path_info);
8158 }
8159
8160 addenv(env, "HTTPS=%s", (conn->ssl == NULL) ? "off" : "on");
8161
8162 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
8163 addenv(env, "CONTENT_TYPE=%s", s);
8164 }
8165 if (conn->request_info.query_string != NULL) {
8166 addenv(env, "QUERY_STRING=%s", conn->request_info.query_string);
8167 }
8168 if ((s = mg_get_header(conn, "Content-Length")) != NULL) {
8169 addenv(env, "CONTENT_LENGTH=%s", s);
8170 }
8171 if ((s = getenv("PATH")) != NULL) {
8172 addenv(env, "PATH=%s", s);
8173 }
8174 if (conn->path_info != NULL) {
8175 addenv(env, "PATH_INFO=%s", conn->path_info);
8176 }
8177
8178 if (conn->status_code > 0) {
8179 /* CGI error handler should show the status code */
8180 addenv(env, "STATUS=%d", conn->status_code);
8181 }
8182
8183 #if defined(_WIN32)
8184 if ((s = getenv("COMSPEC")) != NULL) {
8185 addenv(env, "COMSPEC=%s", s);
8186 }
8187 if ((s = getenv("SYSTEMROOT")) != NULL) {
8188 addenv(env, "SYSTEMROOT=%s", s);
8189 }
8190 if ((s = getenv("SystemDrive")) != NULL) {
8191 addenv(env, "SystemDrive=%s", s);
8192 }
8193 if ((s = getenv("ProgramFiles")) != NULL) {
8194 addenv(env, "ProgramFiles=%s", s);
8195 }
8196 if ((s = getenv("ProgramFiles(x86)")) != NULL) {
8197 addenv(env, "ProgramFiles(x86)=%s", s);
8198 }
8199 #else
8200 if ((s = getenv("LD_LIBRARY_PATH")) != NULL) {
8201 addenv(env, "LD_LIBRARY_PATH=%s", s);
8202 }
8203 #endif /* _WIN32 */
8204
8205 if ((s = getenv("PERLLIB")) != NULL) {
8206 addenv(env, "PERLLIB=%s", s);
8207 }
8208
8209 if (conn->request_info.remote_user != NULL) {
8210 addenv(env, "REMOTE_USER=%s", conn->request_info.remote_user);
8211 addenv(env, "%s", "AUTH_TYPE=Digest");
8212 }
8213
8214 /* Add all headers as HTTP_* variables */
8215 for (i = 0; i < conn->request_info.num_headers; i++) {
8216
8217 (void)mg_snprintf(conn,
8218 &truncated,
8219 http_var_name,
8220 sizeof(http_var_name),
8221 "HTTP_%s",
8222 conn->request_info.http_headers[i].name);
8223
8224 if (truncated) {
8225 mg_cry(conn,
8226 "%s: HTTP header variable too long [%s]",
8227 __func__,
8228 conn->request_info.http_headers[i].name);
8229 continue;
8230 }
8231
8232 /* Convert variable name into uppercase, and change - to _ */
8233 for (p = http_var_name; *p != '\0'; p++) {
8234 if (*p == '-') {
8235 *p = '_';
8236 }
8237 *p = (char)toupper(*(unsigned char *)p);
8238 }
8239
8240 addenv(env,
8241 "%s=%s",
8242 http_var_name,
8243 conn->request_info.http_headers[i].value);
8244 }
8245
8246 /* Add user-specified variables */
8247 s = conn->ctx->config[CGI_ENVIRONMENT];
8248 while ((s = next_option(s, &var_vec, NULL)) != NULL) {
8249 addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr);
8250 }
8251
8252 env->var[env->varused] = NULL;
8253 env->buf[env->bufused] = '\0';
8254 }
8255
8256
8257 static void
handle_cgi_request(struct mg_connection * conn,const char * prog)8258 handle_cgi_request(struct mg_connection *conn, const char *prog)
8259 {
8260 char *buf;
8261 size_t buflen;
8262 int headers_len, data_len, i, truncated;
8263 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
8264 const char *status, *status_text, *connection_state;
8265 char *pbuf, dir[PATH_MAX], *p;
8266 struct mg_request_info ri;
8267 struct cgi_environment blk;
8268 FILE *in = NULL, *out = NULL, *err = NULL;
8269 struct mg_file fout = STRUCT_FILE_INITIALIZER;
8270 pid_t pid = (pid_t)-1;
8271
8272 if (conn == NULL) {
8273 return;
8274 }
8275
8276 buf = NULL;
8277 buflen = 16384;
8278 prepare_cgi_environment(conn, prog, &blk);
8279
8280 /* CGI must be executed in its own directory. 'dir' must point to the
8281 * directory containing executable program, 'p' must point to the
8282 * executable program name relative to 'dir'. */
8283 (void)mg_snprintf(conn, &truncated, dir, sizeof(dir), "%s", prog);
8284
8285 if (truncated) {
8286 mg_cry(conn, "Error: CGI program \"%s\": Path too long", prog);
8287 send_http_error(conn, 500, "Error: %s", "CGI path too long");
8288 goto done;
8289 }
8290
8291 if ((p = strrchr(dir, '/')) != NULL) {
8292 *p++ = '\0';
8293 } else {
8294 dir[0] = '.', dir[1] = '\0';
8295 p = (char *)prog;
8296 }
8297
8298 if (pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0) {
8299 status = strerror(ERRNO);
8300 mg_cry(conn,
8301 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
8302 prog,
8303 status);
8304 send_http_error(conn, 500, "Error: Cannot create CGI pipe: %s", status);
8305 goto done;
8306 }
8307
8308 pid = spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
8309
8310 if (pid == (pid_t)-1) {
8311 status = strerror(ERRNO);
8312 mg_cry(conn,
8313 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
8314 prog,
8315 status);
8316 send_http_error(conn,
8317 500,
8318 "Error: Cannot spawn CGI process [%s]: %s",
8319 prog,
8320 status);
8321 goto done;
8322 }
8323
8324 /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
8325 set_close_on_exec((SOCKET)fdin[0], conn); /* stdin read */
8326 set_close_on_exec((SOCKET)fdout[1], conn); /* stdout write */
8327 set_close_on_exec((SOCKET)fderr[1], conn); /* stderr write */
8328 set_close_on_exec((SOCKET)fdin[1], conn); /* stdin write */
8329 set_close_on_exec((SOCKET)fdout[0], conn); /* stdout read */
8330 set_close_on_exec((SOCKET)fderr[0], conn); /* stderr read */
8331
8332 /* Parent closes only one side of the pipes.
8333 * If we don't mark them as closed, close() attempt before
8334 * return from this function throws an exception on Windows.
8335 * Windows does not like when closed descriptor is closed again. */
8336 (void)close(fdin[0]);
8337 (void)close(fdout[1]);
8338 (void)close(fderr[1]);
8339 fdin[0] = fdout[1] = fderr[1] = -1;
8340
8341 if ((in = fdopen(fdin[1], "wb")) == NULL) {
8342 status = strerror(ERRNO);
8343 mg_cry(conn,
8344 "Error: CGI program \"%s\": Can not open stdin: %s",
8345 prog,
8346 status);
8347 send_http_error(conn,
8348 500,
8349 "Error: CGI can not open fdin\nfopen: %s",
8350 status);
8351 goto done;
8352 }
8353
8354 if ((out = fdopen(fdout[0], "rb")) == NULL) {
8355 status = strerror(ERRNO);
8356 mg_cry(conn,
8357 "Error: CGI program \"%s\": Can not open stdout: %s",
8358 prog,
8359 status);
8360 send_http_error(conn,
8361 500,
8362 "Error: CGI can not open fdout\nfopen: %s",
8363 status);
8364 goto done;
8365 }
8366
8367 if ((err = fdopen(fderr[0], "rb")) == NULL) {
8368 status = strerror(ERRNO);
8369 mg_cry(conn,
8370 "Error: CGI program \"%s\": Can not open stderr: %s",
8371 prog,
8372 status);
8373 send_http_error(conn,
8374 500,
8375 "Error: CGI can not open fdout\nfopen: %s",
8376 status);
8377 goto done;
8378 }
8379
8380 setbuf(in, NULL);
8381 setbuf(out, NULL);
8382 setbuf(err, NULL);
8383 fout.access.fp = out;
8384
8385 if ((conn->request_info.content_length > 0) || conn->is_chunked) {
8386 /* This is a POST/PUT request, or another request with body data. */
8387 if (!forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
8388 /* Error sending the body data */
8389 mg_cry(conn,
8390 "Error: CGI program \"%s\": Forward body data failed",
8391 prog);
8392 goto done;
8393 }
8394 }
8395
8396 /* Close so child gets an EOF. */
8397 fclose(in);
8398 in = NULL;
8399 fdin[1] = -1;
8400
8401 /* Now read CGI reply into a buffer. We need to set correct
8402 * status code, thus we need to see all HTTP headers first.
8403 * Do not send anything back to client, until we buffer in all
8404 * HTTP headers. */
8405 data_len = 0;
8406 buf = (char *)mg_malloc(buflen);
8407 if (buf == NULL) {
8408 send_http_error(conn,
8409 500,
8410 "Error: Not enough memory for CGI buffer (%u bytes)",
8411 (unsigned int)buflen);
8412 mg_cry(conn,
8413 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
8414 "bytes)",
8415 prog,
8416 (unsigned int)buflen);
8417 goto done;
8418 }
8419 headers_len = read_request(out, conn, buf, (int)buflen, &data_len);
8420 if (headers_len <= 0) {
8421
8422 /* Could not parse the CGI response. Check if some error message on
8423 * stderr. */
8424 i = pull_all(err, conn, buf, (int)buflen);
8425 if (i > 0) {
8426 mg_cry(conn,
8427 "Error: CGI program \"%s\" sent error "
8428 "message: [%.*s]",
8429 prog,
8430 i,
8431 buf);
8432 send_http_error(conn,
8433 500,
8434 "Error: CGI program \"%s\" sent error "
8435 "message: [%.*s]",
8436 prog,
8437 i,
8438 buf);
8439 } else {
8440 mg_cry(conn,
8441 "Error: CGI program sent malformed or too big "
8442 "(>%u bytes) HTTP headers: [%.*s]",
8443 (unsigned)buflen,
8444 data_len,
8445 buf);
8446
8447 send_http_error(conn,
8448 500,
8449 "Error: CGI program sent malformed or too big "
8450 "(>%u bytes) HTTP headers: [%.*s]",
8451 (unsigned)buflen,
8452 data_len,
8453 buf);
8454 }
8455
8456 goto done;
8457 }
8458 pbuf = buf;
8459 buf[headers_len - 1] = '\0';
8460 parse_http_headers(&pbuf, &ri);
8461
8462 /* Make up and send the status line */
8463 status_text = "OK";
8464 if ((status = get_header(&ri, "Status")) != NULL) {
8465 conn->status_code = atoi(status);
8466 status_text = status;
8467 while (isdigit(*(const unsigned char *)status_text)
8468 || *status_text == ' ') {
8469 status_text++;
8470 }
8471 } else if (get_header(&ri, "Location") != NULL) {
8472 conn->status_code = 302;
8473 } else {
8474 conn->status_code = 200;
8475 }
8476 connection_state = get_header(&ri, "Connection");
8477 if (!header_has_option(connection_state, "keep-alive")) {
8478 conn->must_close = 1;
8479 }
8480 (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
8481
8482 /* Send headers */
8483 for (i = 0; i < ri.num_headers; i++) {
8484 mg_printf(conn,
8485 "%s: %s\r\n",
8486 ri.http_headers[i].name,
8487 ri.http_headers[i].value);
8488 }
8489 mg_write(conn, "\r\n", 2);
8490
8491 /* Send chunk of data that may have been read after the headers */
8492 conn->num_bytes_sent +=
8493 mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
8494
8495 /* Read the rest of CGI output and send to the client */
8496 send_file_data(conn, &fout, 0, INT64_MAX);
8497
8498 done:
8499 mg_free(blk.var);
8500 mg_free(blk.buf);
8501
8502 if (pid != (pid_t)-1) {
8503 kill(pid, SIGKILL);
8504 #if !defined(_WIN32)
8505 {
8506 int st;
8507 while (waitpid(pid, &st, 0) != -1)
8508 ; /* clean zombies */
8509 }
8510 #endif
8511 }
8512 if (fdin[0] != -1) {
8513 close(fdin[0]);
8514 }
8515 if (fdout[1] != -1) {
8516 close(fdout[1]);
8517 }
8518
8519 if (in != NULL) {
8520 fclose(in);
8521 } else if (fdin[1] != -1) {
8522 close(fdin[1]);
8523 }
8524
8525 if (out != NULL) {
8526 fclose(out);
8527 } else if (fdout[0] != -1) {
8528 close(fdout[0]);
8529 }
8530
8531 if (err != NULL) {
8532 fclose(err);
8533 } else if (fderr[0] != -1) {
8534 close(fderr[0]);
8535 }
8536
8537 if (buf != NULL) {
8538 mg_free(buf);
8539 }
8540 }
8541 #endif /* !NO_CGI */
8542
8543
8544 #if !defined(NO_FILES)
8545 static void
mkcol(struct mg_connection * conn,const char * path)8546 mkcol(struct mg_connection *conn, const char *path)
8547 {
8548 int rc, body_len;
8549 struct de de;
8550 char date[64];
8551 time_t curtime = time(NULL);
8552
8553 if (conn == NULL) {
8554 return;
8555 }
8556
8557 /* TODO (mid): Check the send_http_error situations in this function */
8558
8559 memset(&de.file, 0, sizeof(de.file));
8560 if (!mg_stat(conn, path, &de.file)) {
8561 mg_cry(conn,
8562 "%s: mg_stat(%s) failed: %s",
8563 __func__,
8564 path,
8565 strerror(ERRNO));
8566 }
8567
8568 if (de.file.last_modified) {
8569 /* TODO (high): This check does not seem to make any sense ! */
8570 send_http_error(
8571 conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
8572 return;
8573 }
8574
8575 body_len = conn->data_len - conn->request_len;
8576 if (body_len > 0) {
8577 send_http_error(
8578 conn, 415, "Error: mkcol(%s): %s", path, strerror(ERRNO));
8579 return;
8580 }
8581
8582 rc = mg_mkdir(conn, path, 0755);
8583
8584 if (rc == 0) {
8585 conn->status_code = 201;
8586 gmt_time_string(date, sizeof(date), &curtime);
8587 mg_printf(conn,
8588 "HTTP/1.1 %d Created\r\n"
8589 "Date: %s\r\n",
8590 conn->status_code,
8591 date);
8592 send_static_cache_header(conn);
8593 mg_printf(conn,
8594 "Content-Length: 0\r\n"
8595 "Connection: %s\r\n\r\n",
8596 suggest_connection_header(conn));
8597 } else if (rc == -1) {
8598 if (errno == EEXIST) {
8599 send_http_error(
8600 conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
8601 } else if (errno == EACCES) {
8602 send_http_error(
8603 conn, 403, "Error: mkcol(%s): %s", path, strerror(ERRNO));
8604 } else if (errno == ENOENT) {
8605 send_http_error(
8606 conn, 409, "Error: mkcol(%s): %s", path, strerror(ERRNO));
8607 } else {
8608 send_http_error(conn, 500, "fopen(%s): %s", path, strerror(ERRNO));
8609 }
8610 }
8611 }
8612
8613
8614 static void
put_file(struct mg_connection * conn,const char * path)8615 put_file(struct mg_connection *conn, const char *path)
8616 {
8617 struct mg_file file = STRUCT_FILE_INITIALIZER;
8618 const char *range;
8619 int64_t r1, r2;
8620 int rc;
8621 char date[64];
8622 time_t curtime = time(NULL);
8623
8624 if (conn == NULL) {
8625 return;
8626 }
8627
8628 if (mg_stat(conn, path, &file.stat)) {
8629 /* File already exists */
8630 conn->status_code = 200;
8631
8632 if (file.stat.is_directory) {
8633 /* This is an already existing directory,
8634 * so there is nothing to do for the server. */
8635 rc = 0;
8636
8637 } else {
8638 /* File exists and is not a directory. */
8639 /* Can it be replaced? */
8640
8641 if (file.access.membuf != NULL) {
8642 /* This is an "in-memory" file, that can not be replaced */
8643 send_http_error(
8644 conn,
8645 405,
8646 "Error: Put not possible\nReplacing %s is not supported",
8647 path);
8648 return;
8649 }
8650
8651 /* Check if the server may write this file */
8652 if (access(path, W_OK) == 0) {
8653 /* Access granted */
8654 conn->status_code = 200;
8655 rc = 1;
8656 } else {
8657 send_http_error(
8658 conn,
8659 403,
8660 "Error: Put not possible\nReplacing %s is not allowed",
8661 path);
8662 return;
8663 }
8664 }
8665 } else {
8666 /* File should be created */
8667 conn->status_code = 201;
8668 rc = put_dir(conn, path);
8669 }
8670
8671 if (rc == 0) {
8672 /* put_dir returns 0 if path is a directory */
8673 gmt_time_string(date, sizeof(date), &curtime);
8674 mg_printf(conn,
8675 "HTTP/1.1 %d %s\r\n",
8676 conn->status_code,
8677 mg_get_response_code_text(NULL, conn->status_code));
8678 send_no_cache_header(conn);
8679 mg_printf(conn,
8680 "Date: %s\r\n"
8681 "Content-Length: 0\r\n"
8682 "Connection: %s\r\n\r\n",
8683 date,
8684 suggest_connection_header(conn));
8685
8686 /* Request to create a directory has been fulfilled successfully.
8687 * No need to put a file. */
8688 return;
8689 }
8690
8691 if (rc == -1) {
8692 /* put_dir returns -1 if the path is too long */
8693 send_http_error(conn,
8694 414,
8695 "Error: Path too long\nput_dir(%s): %s",
8696 path,
8697 strerror(ERRNO));
8698 return;
8699 }
8700
8701 if (rc == -2) {
8702 /* put_dir returns -2 if the directory can not be created */
8703 send_http_error(conn,
8704 500,
8705 "Error: Can not create directory\nput_dir(%s): %s",
8706 path,
8707 strerror(ERRNO));
8708 return;
8709 }
8710
8711 /* A file should be created or overwritten. */
8712 /* TODO: Test if write or write+read is required. */
8713 if (!mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &file)
8714 || file.access.fp == NULL) {
8715 (void)mg_fclose(&file.access);
8716 send_http_error(conn,
8717 500,
8718 "Error: Can not create file\nfopen(%s): %s",
8719 path,
8720 strerror(ERRNO));
8721 return;
8722 }
8723
8724 fclose_on_exec(&file.access, conn);
8725 range = mg_get_header(conn, "Content-Range");
8726 r1 = r2 = 0;
8727 if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
8728 conn->status_code = 206; /* Partial content */
8729 fseeko(file.access.fp, r1, SEEK_SET);
8730 }
8731
8732 if (!forward_body_data(conn, file.access.fp, INVALID_SOCKET, NULL)) {
8733 /* forward_body_data failed.
8734 * The error code has already been sent to the client,
8735 * and conn->status_code is already set. */
8736 (void)mg_fclose(&file.access);
8737 return;
8738 }
8739
8740 if (mg_fclose(&file.access) != 0) {
8741 /* fclose failed. This might have different reasons, but a likely
8742 * one is "no space on disk", http 507. */
8743 conn->status_code = 507;
8744 }
8745
8746 gmt_time_string(date, sizeof(date), &curtime);
8747 mg_printf(conn,
8748 "HTTP/1.1 %d %s\r\n",
8749 conn->status_code,
8750 mg_get_response_code_text(NULL, conn->status_code));
8751 send_no_cache_header(conn);
8752 mg_printf(conn,
8753 "Date: %s\r\n"
8754 "Content-Length: 0\r\n"
8755 "Connection: %s\r\n\r\n",
8756 date,
8757 suggest_connection_header(conn));
8758 }
8759
8760
8761 static void
delete_file(struct mg_connection * conn,const char * path)8762 delete_file(struct mg_connection *conn, const char *path)
8763 {
8764 struct de de;
8765 memset(&de.file, 0, sizeof(de.file));
8766 if (!mg_stat(conn, path, &de.file)) {
8767 /* mg_stat returns 0 if the file does not exist */
8768 send_http_error(conn,
8769 404,
8770 "Error: Cannot delete file\nFile %s not found",
8771 path);
8772 return;
8773 }
8774
8775 #if 0 /* Ignore if a file in memory is inside a folder */
8776 if (de.access.membuf != NULL) {
8777 /* the file is cached in memory */
8778 send_http_error(
8779 conn,
8780 405,
8781 "Error: Delete not possible\nDeleting %s is not supported",
8782 path);
8783 return;
8784 }
8785 #endif
8786
8787 if (de.file.is_directory) {
8788 if (remove_directory(conn, path)) {
8789 /* Delete is successful: Return 204 without content. */
8790 send_http_error(conn, 204, "%s", "");
8791 } else {
8792 /* Delete is not successful: Return 500 (Server error). */
8793 send_http_error(conn, 500, "Error: Could not delete %s", path);
8794 }
8795 return;
8796 }
8797
8798 /* This is an existing file (not a directory).
8799 * Check if write permission is granted. */
8800 if (access(path, W_OK) != 0) {
8801 /* File is read only */
8802 send_http_error(
8803 conn,
8804 403,
8805 "Error: Delete not possible\nDeleting %s is not allowed",
8806 path);
8807 return;
8808 }
8809
8810 /* Try to delete it. */
8811 if (mg_remove(conn, path) == 0) {
8812 /* Delete was successful: Return 204 without content. */
8813 send_http_error(conn, 204, "%s", "");
8814 } else {
8815 /* Delete not successful (file locked). */
8816 send_http_error(conn,
8817 423,
8818 "Error: Cannot delete file\nremove(%s): %s",
8819 path,
8820 strerror(ERRNO));
8821 }
8822 }
8823 #endif /* !NO_FILES */
8824
8825
8826 static void
8827 send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int);
8828
8829
8830 static void
do_ssi_include(struct mg_connection * conn,const char * ssi,char * tag,int include_level)8831 do_ssi_include(struct mg_connection *conn,
8832 const char *ssi,
8833 char *tag,
8834 int include_level)
8835 {
8836 char file_name[MG_BUF_LEN], path[512], *p;
8837 struct mg_file file = STRUCT_FILE_INITIALIZER;
8838 size_t len;
8839 int truncated = 0;
8840
8841 if (conn == NULL) {
8842 return;
8843 }
8844
8845 /* sscanf() is safe here, since send_ssi_file() also uses buffer
8846 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
8847 * always < MG_BUF_LEN. */
8848 if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) {
8849 /* File name is relative to the webserver root */
8850 file_name[511] = 0;
8851 (void)mg_snprintf(conn,
8852 &truncated,
8853 path,
8854 sizeof(path),
8855 "%s/%s",
8856 conn->ctx->config[DOCUMENT_ROOT],
8857 file_name);
8858
8859 } else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
8860 /* File name is relative to the webserver working directory
8861 * or it is absolute system path */
8862 file_name[511] = 0;
8863 (void)
8864 mg_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name);
8865
8866 } else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1
8867 || sscanf(tag, " \"%511[^\"]\"", file_name) == 1) {
8868 /* File name is relative to the currect document */
8869 file_name[511] = 0;
8870 (void)mg_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
8871
8872 if (!truncated) {
8873 if ((p = strrchr(path, '/')) != NULL) {
8874 p[1] = '\0';
8875 }
8876 len = strlen(path);
8877 (void)mg_snprintf(conn,
8878 &truncated,
8879 path + len,
8880 sizeof(path) - len,
8881 "%s",
8882 file_name);
8883 }
8884
8885 } else {
8886 mg_cry(conn, "Bad SSI #include: [%s]", tag);
8887 return;
8888 }
8889
8890 if (truncated) {
8891 mg_cry(conn, "SSI #include path length overflow: [%s]", tag);
8892 return;
8893 }
8894
8895 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, &file)) {
8896 mg_cry(conn,
8897 "Cannot open SSI #include: [%s]: fopen(%s): %s",
8898 tag,
8899 path,
8900 strerror(ERRNO));
8901 } else {
8902 fclose_on_exec(&file.access, conn);
8903 if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
8904 strlen(conn->ctx->config[SSI_EXTENSIONS]),
8905 path) > 0) {
8906 send_ssi_file(conn, path, &file, include_level + 1);
8907 } else {
8908 send_file_data(conn, &file, 0, INT64_MAX);
8909 }
8910 (void)mg_fclose(&file.access); /* Ignore errors for readonly files */
8911 }
8912 }
8913
8914
8915 #if !defined(NO_POPEN)
8916 static void
do_ssi_exec(struct mg_connection * conn,char * tag)8917 do_ssi_exec(struct mg_connection *conn, char *tag)
8918 {
8919 char cmd[1024] = "";
8920 struct mg_file file = STRUCT_FILE_INITIALIZER;
8921
8922 if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
8923 mg_cry(conn, "Bad SSI #exec: [%s]", tag);
8924 } else {
8925 cmd[1023] = 0;
8926 if ((file.access.fp = popen(cmd, "r")) == NULL) {
8927 mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
8928 } else {
8929 send_file_data(conn, &file, 0, INT64_MAX);
8930 pclose(file.access.fp);
8931 }
8932 }
8933 }
8934 #endif /* !NO_POPEN */
8935
8936
8937 static int
mg_fgetc(struct mg_file * filep,int offset)8938 mg_fgetc(struct mg_file *filep, int offset)
8939 {
8940 if (filep == NULL) {
8941 return EOF;
8942 }
8943 if (filep->access.membuf != NULL && offset >= 0
8944 && ((unsigned int)(offset)) < filep->stat.size) {
8945 return ((const unsigned char *)filep->access.membuf)[offset];
8946 } else if (filep->access.fp != NULL) {
8947 return fgetc(filep->access.fp);
8948 } else {
8949 return EOF;
8950 }
8951 }
8952
8953
8954 static void
send_ssi_file(struct mg_connection * conn,const char * path,struct mg_file * filep,int include_level)8955 send_ssi_file(struct mg_connection *conn,
8956 const char *path,
8957 struct mg_file *filep,
8958 int include_level)
8959 {
8960 char buf[MG_BUF_LEN];
8961 int ch, offset, len, in_ssi_tag;
8962
8963 if (include_level > 10) {
8964 mg_cry(conn, "SSI #include level is too deep (%s)", path);
8965 return;
8966 }
8967
8968 in_ssi_tag = len = offset = 0;
8969 while ((ch = mg_fgetc(filep, offset)) != EOF) {
8970 if (in_ssi_tag && ch == '>') {
8971 in_ssi_tag = 0;
8972 buf[len++] = (char)ch;
8973 buf[len] = '\0';
8974 /* assert(len <= (int) sizeof(buf)); */
8975 if (len > (int)sizeof(buf)) {
8976 break;
8977 }
8978 if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
8979 /* Not an SSI tag, pass it */
8980 (void)mg_write(conn, buf, (size_t)len);
8981 } else {
8982 if (!memcmp(buf + 5, "include", 7)) {
8983 do_ssi_include(conn, path, buf + 12, include_level);
8984 #if !defined(NO_POPEN)
8985 } else if (!memcmp(buf + 5, "exec", 4)) {
8986 do_ssi_exec(conn, buf + 9);
8987 #endif /* !NO_POPEN */
8988 } else {
8989 mg_cry(conn,
8990 "%s: unknown SSI "
8991 "command: \"%s\"",
8992 path,
8993 buf);
8994 }
8995 }
8996 len = 0;
8997 } else if (in_ssi_tag) {
8998 if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
8999 /* Not an SSI tag */
9000 in_ssi_tag = 0;
9001 } else if (len == (int)sizeof(buf) - 2) {
9002 mg_cry(conn, "%s: SSI tag is too large", path);
9003 len = 0;
9004 }
9005 buf[len++] = (char)(ch & 0xff);
9006 } else if (ch == '<') {
9007 in_ssi_tag = 1;
9008 if (len > 0) {
9009 mg_write(conn, buf, (size_t)len);
9010 }
9011 len = 0;
9012 buf[len++] = (char)(ch & 0xff);
9013 } else {
9014 buf[len++] = (char)(ch & 0xff);
9015 if (len == (int)sizeof(buf)) {
9016 mg_write(conn, buf, (size_t)len);
9017 len = 0;
9018 }
9019 }
9020 }
9021
9022 /* Send the rest of buffered data */
9023 if (len > 0) {
9024 mg_write(conn, buf, (size_t)len);
9025 }
9026 }
9027
9028
9029 static void
handle_ssi_file_request(struct mg_connection * conn,const char * path,struct mg_file * filep)9030 handle_ssi_file_request(struct mg_connection *conn,
9031 const char *path,
9032 struct mg_file *filep)
9033 {
9034 char date[64];
9035 time_t curtime = time(NULL);
9036 const char *cors1, *cors2, *cors3;
9037
9038 if (conn == NULL || path == NULL || filep == NULL) {
9039 return;
9040 }
9041
9042 if (mg_get_header(conn, "Origin")) {
9043 /* Cross-origin resource sharing (CORS). */
9044 cors1 = "Access-Control-Allow-Origin: ";
9045 cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
9046 cors3 = "\r\n";
9047 } else {
9048 cors1 = cors2 = cors3 = "";
9049 }
9050
9051 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
9052 /* File exists (precondition for calling this function),
9053 * but can not be opened by the server. */
9054 send_http_error(conn,
9055 500,
9056 "Error: Cannot read file\nfopen(%s): %s",
9057 path,
9058 strerror(ERRNO));
9059 } else {
9060 conn->must_close = 1;
9061 gmt_time_string(date, sizeof(date), &curtime);
9062 fclose_on_exec(&filep->access, conn);
9063 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
9064 send_no_cache_header(conn);
9065 mg_printf(conn,
9066 "%s%s%s"
9067 "Date: %s\r\n"
9068 "Content-Type: text/html\r\n"
9069 "Connection: %s\r\n\r\n",
9070 cors1,
9071 cors2,
9072 cors3,
9073 date,
9074 suggest_connection_header(conn));
9075 send_ssi_file(conn, path, filep, 0);
9076 (void)mg_fclose(&filep->access); /* Ignore errors for readonly files */
9077 }
9078 }
9079
9080
9081 #if !defined(NO_FILES)
9082 static void
send_options(struct mg_connection * conn)9083 send_options(struct mg_connection *conn)
9084 {
9085 char date[64];
9086 time_t curtime = time(NULL);
9087
9088 if (!conn) {
9089 return;
9090 }
9091
9092 conn->status_code = 200;
9093 conn->must_close = 1;
9094 gmt_time_string(date, sizeof(date), &curtime);
9095
9096 mg_printf(conn,
9097 "HTTP/1.1 200 OK\r\n"
9098 "Date: %s\r\n"
9099 /* TODO: "Cache-Control" (?) */
9100 "Connection: %s\r\n"
9101 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
9102 "PROPFIND, MKCOL\r\n"
9103 "DAV: 1\r\n\r\n",
9104 date,
9105 suggest_connection_header(conn));
9106 }
9107
9108
9109 /* Writes PROPFIND properties for a collection element */
9110 static void
print_props(struct mg_connection * conn,const char * uri,struct mg_file_stat * filep)9111 print_props(struct mg_connection *conn,
9112 const char *uri,
9113 struct mg_file_stat *filep)
9114 {
9115 char mtime[64];
9116
9117 if (conn == NULL || uri == NULL || filep == NULL) {
9118 return;
9119 }
9120
9121 gmt_time_string(mtime, sizeof(mtime), &filep->last_modified);
9122 conn->num_bytes_sent +=
9123 mg_printf(conn,
9124 "<d:response>"
9125 "<d:href>%s</d:href>"
9126 "<d:propstat>"
9127 "<d:prop>"
9128 "<d:resourcetype>%s</d:resourcetype>"
9129 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
9130 "<d:getlastmodified>%s</d:getlastmodified>"
9131 "</d:prop>"
9132 "<d:status>HTTP/1.1 200 OK</d:status>"
9133 "</d:propstat>"
9134 "</d:response>\n",
9135 uri,
9136 filep->is_directory ? "<d:collection/>" : "",
9137 filep->size,
9138 mtime);
9139 }
9140
9141
9142 static void
print_dav_dir_entry(struct de * de,void * data)9143 print_dav_dir_entry(struct de *de, void *data)
9144 {
9145 char href[PATH_MAX];
9146 char href_encoded[PATH_MAX * 3 /* worst case */];
9147 int truncated;
9148
9149 struct mg_connection *conn = (struct mg_connection *)data;
9150 if (!de || !conn) {
9151 return;
9152 }
9153 mg_snprintf(conn,
9154 &truncated,
9155 href,
9156 sizeof(href),
9157 "%s%s",
9158 conn->request_info.local_uri,
9159 de->file_name);
9160
9161 if (!truncated) {
9162 mg_url_encode(href, href_encoded, PATH_MAX * 3);
9163 print_props(conn, href_encoded, &de->file);
9164 }
9165 }
9166
9167
9168 static void
handle_propfind(struct mg_connection * conn,const char * path,struct mg_file_stat * filep)9169 handle_propfind(struct mg_connection *conn,
9170 const char *path,
9171 struct mg_file_stat *filep)
9172 {
9173 const char *depth = mg_get_header(conn, "Depth");
9174 char date[64];
9175 time_t curtime = time(NULL);
9176
9177 gmt_time_string(date, sizeof(date), &curtime);
9178
9179 if (!conn || !path || !filep || !conn->ctx) {
9180 return;
9181 }
9182
9183 conn->must_close = 1;
9184 conn->status_code = 207;
9185 mg_printf(conn,
9186 "HTTP/1.1 207 Multi-Status\r\n"
9187 "Date: %s\r\n",
9188 date);
9189 send_static_cache_header(conn);
9190 mg_printf(conn,
9191 "Connection: %s\r\n"
9192 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
9193 suggest_connection_header(conn));
9194
9195 conn->num_bytes_sent +=
9196 mg_printf(conn,
9197 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
9198 "<d:multistatus xmlns:d='DAV:'>\n");
9199
9200 /* Print properties for the requested resource itself */
9201 print_props(conn, conn->request_info.local_uri, filep);
9202
9203 /* If it is a directory, print directory entries too if Depth is not 0 */
9204 if (filep && filep->is_directory
9205 && !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")
9206 && (depth == NULL || strcmp(depth, "0") != 0)) {
9207 scan_directory(conn, path, conn, &print_dav_dir_entry);
9208 }
9209
9210 conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
9211 }
9212 #endif
9213
9214 void
mg_lock_connection(struct mg_connection * conn)9215 mg_lock_connection(struct mg_connection *conn)
9216 {
9217 if (conn) {
9218 (void)pthread_mutex_lock(&conn->mutex);
9219 }
9220 }
9221
9222 void
mg_unlock_connection(struct mg_connection * conn)9223 mg_unlock_connection(struct mg_connection *conn)
9224 {
9225 if (conn) {
9226 (void)pthread_mutex_unlock(&conn->mutex);
9227 }
9228 }
9229
9230 void
mg_lock_context(struct mg_context * ctx)9231 mg_lock_context(struct mg_context *ctx)
9232 {
9233 if (ctx) {
9234 (void)pthread_mutex_lock(&ctx->nonce_mutex);
9235 }
9236 }
9237
9238 void
mg_unlock_context(struct mg_context * ctx)9239 mg_unlock_context(struct mg_context *ctx)
9240 {
9241 if (ctx) {
9242 (void)pthread_mutex_unlock(&ctx->nonce_mutex);
9243 }
9244 }
9245
9246 #if defined(USE_TIMERS)
9247 #include "timer.inl"
9248 #endif /* USE_TIMERS */
9249
9250 #ifdef USE_LUA
9251 #include "mod_lua.inl"
9252 #endif /* USE_LUA */
9253
9254 #ifdef USE_DUKTAPE
9255 #include "mod_duktape.inl"
9256 #endif /* USE_DUKTAPE */
9257
9258 #if defined(USE_WEBSOCKET)
9259
9260 #define SHA_API static
9261 #include "sha1.inl"
9262
9263 static int
send_websocket_handshake(struct mg_connection * conn,const char * websock_key)9264 send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
9265 {
9266 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
9267 char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
9268 SHA1_CTX sha_ctx;
9269 int truncated;
9270
9271 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
9272 mg_snprintf(conn, &truncated, buf, sizeof(buf), "%s%s", websock_key, magic);
9273 if (truncated) {
9274 conn->must_close = 1;
9275 return 0;
9276 }
9277
9278 SHA1_Init(&sha_ctx);
9279 SHA1_Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
9280 SHA1_Final(&sha_ctx, (unsigned char *)sha);
9281 base64_encode((unsigned char *)sha, sizeof(sha), b64_sha);
9282 mg_printf(conn,
9283 "HTTP/1.1 101 Switching Protocols\r\n"
9284 "Upgrade: websocket\r\n"
9285 "Connection: Upgrade\r\n"
9286 "Sec-WebSocket-Accept: %s\r\n",
9287 b64_sha);
9288 if (conn->request_info.acceptedWebSocketSubprotocol) {
9289 mg_printf(conn,
9290 "Sec-WebSocket-Protocol: %s\r\n\r\n",
9291 conn->request_info.acceptedWebSocketSubprotocol);
9292 } else {
9293 mg_printf(conn, "%s", "\r\n");
9294 }
9295
9296 return 1;
9297 }
9298
9299
9300 static void
read_websocket(struct mg_connection * conn,mg_websocket_data_handler ws_data_handler,void * callback_data)9301 read_websocket(struct mg_connection *conn,
9302 mg_websocket_data_handler ws_data_handler,
9303 void *callback_data)
9304 {
9305 /* Pointer to the beginning of the portion of the incoming websocket
9306 * message queue.
9307 * The original websocket upgrade request is never removed, so the queue
9308 * begins after it. */
9309 unsigned char *buf = (unsigned char *)conn->buf + conn->request_len;
9310 int n, error, exit_by_callback;
9311
9312 /* body_len is the length of the entire queue in bytes
9313 * len is the length of the current message
9314 * data_len is the length of the current message's data payload
9315 * header_len is the length of the current message's header */
9316 size_t i, len, mask_len = 0, data_len = 0, header_len, body_len;
9317
9318 /* "The masking key is a 32-bit value chosen at random by the client."
9319 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
9320 */
9321 unsigned char mask[4];
9322
9323 /* data points to the place where the message is stored when passed to
9324 * the
9325 * websocket_data callback. This is either mem on the stack, or a
9326 * dynamically allocated buffer if it is too large. */
9327 unsigned char mem[4096];
9328 unsigned char *data = mem;
9329 unsigned char mop; /* mask flag and opcode */
9330 double timeout = -1.0;
9331
9332 if (conn->ctx->config[WEBSOCKET_TIMEOUT]) {
9333 timeout = atoi(conn->ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
9334 }
9335 if ((timeout <= 0.0) && (conn->ctx->config[REQUEST_TIMEOUT])) {
9336 timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
9337 }
9338
9339 mg_set_thread_name("wsock");
9340
9341 /* Loop continuously, reading messages from the socket, invoking the
9342 * callback, and waiting repeatedly until an error occurs. */
9343 while (!conn->ctx->stop_flag) {
9344 header_len = 0;
9345 assert(conn->data_len >= conn->request_len);
9346 if ((body_len = (size_t)(conn->data_len - conn->request_len)) >= 2) {
9347 len = buf[1] & 127;
9348 mask_len = (buf[1] & 128) ? 4 : 0;
9349 if ((len < 126) && (body_len >= mask_len)) {
9350 data_len = len;
9351 header_len = 2 + mask_len;
9352 } else if ((len == 126) && (body_len >= (4 + mask_len))) {
9353 header_len = 4 + mask_len;
9354 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
9355 } else if (body_len >= (10 + mask_len)) {
9356 header_len = 10 + mask_len;
9357 data_len = (((uint64_t)ntohl(*(uint32_t *)(void *)&buf[2]))
9358 << 32) + ntohl(*(uint32_t *)(void *)&buf[6]);
9359 }
9360 }
9361
9362 if (header_len > 0 && body_len >= header_len) {
9363 /* Allocate space to hold websocket payload */
9364 data = mem;
9365 if (data_len > sizeof(mem)) {
9366 data = (unsigned char *)mg_malloc(data_len);
9367 if (data == NULL) {
9368 /* Allocation failed, exit the loop and then close the
9369 * connection */
9370 mg_cry(conn, "websocket out of memory; closing connection");
9371 break;
9372 }
9373 }
9374
9375 /* Copy the mask before we shift the queue and destroy it */
9376 if (mask_len > 0) {
9377 memcpy(mask, buf + header_len - mask_len, sizeof(mask));
9378 } else {
9379 memset(mask, 0, sizeof(mask));
9380 }
9381
9382 /* Read frame payload from the first message in the queue into
9383 * data and advance the queue by moving the memory in place. */
9384 assert(body_len >= header_len);
9385 if (data_len + header_len > body_len) {
9386 mop = buf[0]; /* current mask and opcode */
9387 /* Overflow case */
9388 len = body_len - header_len;
9389 memcpy(data, buf + header_len, len);
9390 error = 0;
9391 while (len < data_len) {
9392 n = pull(NULL,
9393 conn,
9394 (char *)(data + len),
9395 (int)(data_len - len),
9396 timeout);
9397 if (n <= 0) {
9398 error = 1;
9399 break;
9400 }
9401 len += (size_t)n;
9402 }
9403 if (error) {
9404 mg_cry(conn, "Websocket pull failed; closing connection");
9405 break;
9406 }
9407 conn->data_len = conn->request_len;
9408 } else {
9409 mop = buf[0]; /* current mask and opcode, overwritten by
9410 * memmove() */
9411 /* Length of the message being read at the front of the
9412 * queue */
9413 len = data_len + header_len;
9414
9415 /* Copy the data payload into the data pointer for the
9416 * callback */
9417 memcpy(data, buf + header_len, data_len);
9418
9419 /* Move the queue forward len bytes */
9420 memmove(buf, buf + len, body_len - len);
9421
9422 /* Mark the queue as advanced */
9423 conn->data_len -= (int)len;
9424 }
9425
9426 /* Apply mask if necessary */
9427 if (mask_len > 0) {
9428 for (i = 0; i < data_len; ++i) {
9429 data[i] ^= mask[i & 3];
9430 }
9431 }
9432
9433 /* Exit the loop if callback signals to exit (server side),
9434 * or "connection close" opcode received (client side). */
9435 exit_by_callback = 0;
9436 if ((ws_data_handler != NULL)
9437 && !ws_data_handler(
9438 conn, mop, (char *)data, data_len, callback_data)) {
9439 exit_by_callback = 1;
9440 }
9441
9442 if (data != mem) {
9443 mg_free(data);
9444 }
9445
9446 if (exit_by_callback
9447 || ((mop & 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE)) {
9448 /* Opcode == 8, connection close */
9449 break;
9450 }
9451
9452 /* Not breaking the loop, process next websocket frame. */
9453 } else {
9454 /* Read from the socket into the next available location in the
9455 * message queue. */
9456 if ((n = pull(NULL,
9457 conn,
9458 conn->buf + conn->data_len,
9459 conn->buf_size - conn->data_len,
9460 timeout)) <= 0) {
9461 /* Error, no bytes read */
9462 break;
9463 }
9464 conn->data_len += n;
9465 }
9466 }
9467
9468 mg_set_thread_name("worker");
9469 }
9470
9471
9472 static int
mg_websocket_write_exec(struct mg_connection * conn,int opcode,const char * data,size_t dataLen,uint32_t masking_key)9473 mg_websocket_write_exec(struct mg_connection *conn,
9474 int opcode,
9475 const char *data,
9476 size_t dataLen,
9477 uint32_t masking_key)
9478 {
9479 unsigned char header[14];
9480 size_t headerLen = 1;
9481
9482 int retval = -1;
9483
9484 #if defined(__MINGW32__) || defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
9485 /* Disable spurious conversion warning for GCC */
9486 #pragma GCC diagnostic push
9487 #pragma GCC diagnostic ignored "-Wconversion"
9488 #endif
9489
9490 header[0] = 0x80u | (unsigned char)((unsigned)opcode & 0xf);
9491
9492 #if defined(__MINGW32__) || defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))
9493 #pragma GCC diagnostic pop
9494 #endif
9495
9496 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
9497 if (dataLen < 126) {
9498 /* inline 7-bit length field */
9499 header[1] = (unsigned char)dataLen;
9500 headerLen = 2;
9501 } else if (dataLen <= 0xFFFF) {
9502 /* 16-bit length field */
9503 uint16_t len = htons((uint16_t)dataLen);
9504 header[1] = 126;
9505 memcpy(header + 2, &len, 2);
9506 headerLen = 4;
9507 } else {
9508 /* 64-bit length field */
9509 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
9510 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
9511 header[1] = 127;
9512 memcpy(header + 2, &len1, 4);
9513 memcpy(header + 6, &len2, 4);
9514 headerLen = 10;
9515 }
9516
9517 if (masking_key) {
9518 /* add mask */
9519 header[1] |= 0x80;
9520 memcpy(header + headerLen, &masking_key, 4);
9521 headerLen += 4;
9522 }
9523
9524
9525 /* Note that POSIX/Winsock's send() is threadsafe
9526 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
9527 * but mongoose's mg_printf/mg_write is not (because of the loop in
9528 * push(), although that is only a problem if the packet is large or
9529 * outgoing buffer is full). */
9530 (void)mg_lock_connection(conn);
9531 retval = mg_write(conn, header, headerLen);
9532 if (dataLen > 0) {
9533 retval = mg_write(conn, data, dataLen);
9534 }
9535 mg_unlock_connection(conn);
9536
9537 return retval;
9538 }
9539
9540 int
mg_websocket_write(struct mg_connection * conn,int opcode,const char * data,size_t dataLen)9541 mg_websocket_write(struct mg_connection *conn,
9542 int opcode,
9543 const char *data,
9544 size_t dataLen)
9545 {
9546 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
9547 }
9548
9549
9550 static void
mask_data(const char * in,size_t in_len,uint32_t masking_key,char * out)9551 mask_data(const char *in, size_t in_len, uint32_t masking_key, char *out)
9552 {
9553 size_t i = 0;
9554
9555 i = 0;
9556 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
9557 /* Convert in 32 bit words, if data is 4 byte aligned */
9558 while (i < (in_len - 3)) {
9559 *(uint32_t *)(void *)(out + i) =
9560 *(uint32_t *)(void *)(in + i) ^ masking_key;
9561 i += 4;
9562 }
9563 }
9564 if (i != in_len) {
9565 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
9566 while (i < in_len) {
9567 *(uint8_t *)(void *)(out + i) =
9568 *(uint8_t *)(void *)(in + i)
9569 ^ *(((uint8_t *)&masking_key) + (i % 4));
9570 i++;
9571 }
9572 }
9573 }
9574
9575
9576 int
mg_websocket_client_write(struct mg_connection * conn,int opcode,const char * data,size_t dataLen)9577 mg_websocket_client_write(struct mg_connection *conn,
9578 int opcode,
9579 const char *data,
9580 size_t dataLen)
9581 {
9582 int retval = -1;
9583 char *masked_data = (char *)mg_malloc(((dataLen + 7) / 4) * 4);
9584 uint32_t masking_key = (uint32_t)get_random();
9585
9586 if (masked_data == NULL) {
9587 /* Return -1 in an error case */
9588 mg_cry(conn,
9589 "Cannot allocate buffer for masked websocket response: "
9590 "Out of memory");
9591 return -1;
9592 }
9593
9594 mask_data(data, dataLen, masking_key, masked_data);
9595
9596 retval = mg_websocket_write_exec(
9597 conn, opcode, masked_data, dataLen, masking_key);
9598 mg_free(masked_data);
9599
9600 return retval;
9601 }
9602
9603
9604 static void
handle_websocket_request(struct mg_connection * conn,const char * path,int is_callback_resource,struct mg_websocket_subprotocols * subprotocols,mg_websocket_connect_handler ws_connect_handler,mg_websocket_ready_handler ws_ready_handler,mg_websocket_data_handler ws_data_handler,mg_websocket_close_handler ws_close_handler,void * cbData)9605 handle_websocket_request(struct mg_connection *conn,
9606 const char *path,
9607 int is_callback_resource,
9608 struct mg_websocket_subprotocols *subprotocols,
9609 mg_websocket_connect_handler ws_connect_handler,
9610 mg_websocket_ready_handler ws_ready_handler,
9611 mg_websocket_data_handler ws_data_handler,
9612 mg_websocket_close_handler ws_close_handler,
9613 void *cbData)
9614 {
9615 const char *websock_key = mg_get_header(conn, "Sec-WebSocket-Key");
9616 const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
9617 int lua_websock = 0;
9618
9619 #if !defined(USE_LUA)
9620 (void)path;
9621 #endif
9622
9623 /* Step 1: Check websocket protocol version. */
9624 /* Step 1.1: Check Sec-WebSocket-Key. */
9625 if (!websock_key) {
9626 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
9627 * requires a Sec-WebSocket-Key header.
9628 */
9629 /* It could be the hixie draft version
9630 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
9631 */
9632 const char *key1 = mg_get_header(conn, "Sec-WebSocket-Key1");
9633 const char *key2 = mg_get_header(conn, "Sec-WebSocket-Key2");
9634 char key3[8];
9635
9636 if ((key1 != NULL) && (key2 != NULL)) {
9637 /* This version uses 8 byte body data in a GET request */
9638 conn->content_len = 8;
9639 if (8 == mg_read(conn, key3, 8)) {
9640 /* This is the hixie version */
9641 send_http_error(conn,
9642 426,
9643 "%s",
9644 "Protocol upgrade to RFC 6455 required");
9645 return;
9646 }
9647 }
9648 /* This is an unknown version */
9649 send_http_error(conn, 400, "%s", "Malformed websocket request");
9650 return;
9651 }
9652
9653 /* Step 1.2: Check websocket protocol version. */
9654 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
9655 if (version == NULL || strcmp(version, "13") != 0) {
9656 /* Reject wrong versions */
9657 send_http_error(conn, 426, "%s", "Protocol upgrade required");
9658 return;
9659 }
9660
9661 /* Step 1.3: Could check for "Host", but we do not really nead this
9662 * value for anything, so just ignore it. */
9663
9664 /* Step 2: If a callback is responsible, call it. */
9665 if (is_callback_resource) {
9666 /* Step 2.1 check and select subprotocol */
9667 const char *protocol = mg_get_header(conn, "Sec-WebSocket-Protocol");
9668 if (protocol && subprotocols) {
9669 int idx;
9670 unsigned long len;
9671 const char *sep, *curSubProtocol,
9672 *acceptedWebSocketSubprotocol = NULL;
9673
9674
9675 /* look for matching subprotocol */
9676 do {
9677 sep = strchr(protocol, ',');
9678 curSubProtocol = protocol;
9679 // CONDUIT CHANGE: supress warnings ident on windows
9680 len = (unsigned long) (sep ? (unsigned long)(sep - protocol) : strlen(protocol));
9681 while (sep && isspace(*++sep))
9682 ; // ignore leading whitespaces
9683 protocol = sep;
9684
9685
9686 for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
9687 if ((strlen(subprotocols->subprotocols[idx]) == len)
9688 && (strncmp(curSubProtocol,
9689 subprotocols->subprotocols[idx],
9690 len) == 0)) {
9691 acceptedWebSocketSubprotocol =
9692 subprotocols->subprotocols[idx];
9693 break;
9694 }
9695 }
9696 } while (sep && !acceptedWebSocketSubprotocol);
9697
9698 conn->request_info.acceptedWebSocketSubprotocol =
9699 acceptedWebSocketSubprotocol;
9700 } else if (protocol) {
9701 /* keep legacy behavior */
9702
9703 /* The protocol is a comma seperated list of names. */
9704 /* The server must only return one value from this list. */
9705 /* First check if it is a list or just a single value. */
9706 const char *sep = strrchr(protocol, ',');
9707 if (sep == NULL) {
9708 /* Just a single protocol -> accept it. */
9709 conn->request_info.acceptedWebSocketSubprotocol = protocol;
9710 } else {
9711 /* Multiple protocols -> accept the last one. */
9712 /* This is just a quick fix if the client offers multiple
9713 * protocols. The handler should have a list of accepted
9714 * protocols on his own
9715 * and use it to select one protocol among those the client has
9716 * offered.
9717 */
9718 while (isspace(*++sep))
9719 ; // ignore leading whitespaces
9720 conn->request_info.acceptedWebSocketSubprotocol = sep;
9721 }
9722 }
9723
9724 if (ws_connect_handler != NULL
9725 && ws_connect_handler(conn, cbData) != 0) {
9726 /* C callback has returned non-zero, do not proceed with
9727 * handshake.
9728 */
9729 /* Note that C callbacks are no longer called when Lua is
9730 * responsible, so C can no longer filter callbacks for Lua. */
9731 return;
9732 }
9733 }
9734 #if defined(USE_LUA)
9735 /* Step 3: No callback. Check if Lua is responsible. */
9736 else {
9737 /* Step 3.1: Check if Lua is responsible. */
9738 if (conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
9739 lua_websock =
9740 match_prefix(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS],
9741 strlen(
9742 conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
9743 path);
9744 }
9745
9746 if (lua_websock) {
9747 /* Step 3.2: Lua is responsible: call it. */
9748 conn->lua_websocket_state = lua_websocket_new(path, conn);
9749 if (!conn->lua_websocket_state) {
9750 /* Lua rejected the new client */
9751 return;
9752 }
9753 }
9754 }
9755 #endif
9756
9757 /* Step 4: Check if there is a responsible websocket handler. */
9758 if (!is_callback_resource && !lua_websock) {
9759 /* There is no callback, and Lua is not responsible either. */
9760 /* Reply with a 404 Not Found or with nothing at all?
9761 * TODO (mid): check the websocket standards, how to reply to
9762 * requests to invalid websocket addresses. */
9763 send_http_error(conn, 404, "%s", "Not found");
9764 return;
9765 }
9766
9767 /* Step 5: The websocket connection has been accepted */
9768 if (!send_websocket_handshake(conn, websock_key)) {
9769 send_http_error(conn, 500, "%s", "Websocket handshake failed");
9770 return;
9771 }
9772
9773 /* Step 6: Call the ready handler */
9774 if (is_callback_resource) {
9775 if (ws_ready_handler != NULL) {
9776 ws_ready_handler(conn, cbData);
9777 }
9778 #if defined(USE_LUA)
9779 } else if (lua_websock) {
9780 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
9781 /* the ready handler returned false */
9782 return;
9783 }
9784 #endif
9785 }
9786
9787 /* Step 7: Enter the read loop */
9788 if (is_callback_resource) {
9789 read_websocket(conn, ws_data_handler, cbData);
9790 #if defined(USE_LUA)
9791 } else if (lua_websock) {
9792 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
9793 #endif
9794 }
9795
9796 /* Step 8: Call the close handler */
9797 if (ws_close_handler) {
9798 ws_close_handler(conn, cbData);
9799 }
9800 }
9801
9802
9803 static int
is_websocket_protocol(const struct mg_connection * conn)9804 is_websocket_protocol(const struct mg_connection *conn)
9805 {
9806 const char *upgrade, *connection;
9807
9808 /* A websocket protocoll has the following HTTP headers:
9809 *
9810 * Connection: Upgrade
9811 * Upgrade: Websocket
9812 */
9813
9814 upgrade = mg_get_header(conn, "Upgrade");
9815 if (upgrade == NULL) {
9816 return 0; /* fail early, don't waste time checking other header
9817 * fields
9818 */
9819 }
9820 if (!mg_strcasestr(upgrade, "websocket")) {
9821 return 0;
9822 }
9823
9824 connection = mg_get_header(conn, "Connection");
9825 if (connection == NULL) {
9826 return 0;
9827 }
9828 if (!mg_strcasestr(connection, "upgrade")) {
9829 return 0;
9830 }
9831
9832 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
9833 * "Sec-WebSocket-Version" are also required.
9834 * Don't check them here, since even an unsupported websocket protocol
9835 * request still IS a websocket request (in contrast to a standard HTTP
9836 * request). It will fail later in handle_websocket_request.
9837 */
9838
9839 return 1;
9840 }
9841 #endif /* !USE_WEBSOCKET */
9842
9843
9844 static int
isbyte(int n)9845 isbyte(int n)
9846 {
9847 return n >= 0 && n <= 255;
9848 }
9849
9850
9851 static int
parse_net(const char * spec,uint32_t * net,uint32_t * mask)9852 parse_net(const char *spec, uint32_t *net, uint32_t *mask)
9853 {
9854 int n, a, b, c, d, slash = 32, len = 0;
9855
9856 if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5
9857 || sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) && isbyte(a)
9858 && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0
9859 && slash < 33) {
9860 len = n;
9861 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
9862 | (uint32_t)d;
9863 *mask = slash ? (0xffffffffU << (32 - slash)) : 0;
9864 }
9865
9866 return len;
9867 }
9868
9869
9870 static int
set_throttle(const char * spec,uint32_t remote_ip,const char * uri)9871 set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
9872 {
9873 int throttle = 0;
9874 struct vec vec, val;
9875 uint32_t net, mask;
9876 char mult;
9877 double v;
9878
9879 while ((spec = next_option(spec, &vec, &val)) != NULL) {
9880 mult = ',';
9881 if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1)
9882 || (v < 0) || ((lowercase(&mult) != 'k')
9883 && (lowercase(&mult) != 'm') && (mult != ','))) {
9884 continue;
9885 }
9886 v *= (lowercase(&mult) == 'k')
9887 ? 1024
9888 : ((lowercase(&mult) == 'm') ? 1048576 : 1);
9889 if (vec.len == 1 && vec.ptr[0] == '*') {
9890 throttle = (int)v;
9891 } else if (parse_net(vec.ptr, &net, &mask) > 0) {
9892 if ((remote_ip & mask) == net) {
9893 throttle = (int)v;
9894 }
9895 } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
9896 throttle = (int)v;
9897 }
9898 }
9899
9900 return throttle;
9901 }
9902
9903
9904 static uint32_t
get_remote_ip(const struct mg_connection * conn)9905 get_remote_ip(const struct mg_connection *conn)
9906 {
9907 if (!conn) {
9908 return 0;
9909 }
9910 return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr);
9911 }
9912
9913
9914 /* The mg_upload function is superseeded by mg_handle_form_request. */
9915 #include "handle_form.inl"
9916
9917
9918 #if defined(MG_LEGACY_INTERFACE)
9919 /* Implement the deprecated mg_upload function by calling the new
9920 * mg_handle_form_request function. While mg_upload could only handle
9921 * HTML forms sent as POST request in multipart/form-data format
9922 * containing only file input elements, mg_handle_form_request can
9923 * handle all form input elements and all standard request methods. */
9924 struct mg_upload_user_data {
9925 struct mg_connection *conn;
9926 const char *destination_dir;
9927 int num_uploaded_files;
9928 };
9929
9930
9931 /* Helper function for deprecated mg_upload. */
9932 static int
mg_upload_field_found(const char * key,const char * filename,char * path,size_t pathlen,void * user_data)9933 mg_upload_field_found(const char *key,
9934 const char *filename,
9935 char *path,
9936 size_t pathlen,
9937 void *user_data)
9938 {
9939 int truncated = 0;
9940 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
9941 (void)key;
9942
9943 if (!filename) {
9944 mg_cry(fud->conn, "%s: No filename set", __func__);
9945 return FORM_FIELD_STORAGE_ABORT;
9946 }
9947 mg_snprintf(fud->conn,
9948 &truncated,
9949 path,
9950 pathlen - 1,
9951 "%s/%s",
9952 fud->destination_dir,
9953 filename);
9954 if (!truncated) {
9955 mg_cry(fud->conn, "%s: File path too long", __func__);
9956 return FORM_FIELD_STORAGE_ABORT;
9957 }
9958 return FORM_FIELD_STORAGE_STORE;
9959 }
9960
9961
9962 /* Helper function for deprecated mg_upload. */
9963 static int
mg_upload_field_get(const char * key,const char * value,size_t value_size,void * user_data)9964 mg_upload_field_get(const char *key,
9965 const char *value,
9966 size_t value_size,
9967 void *user_data)
9968 {
9969 /* Function should never be called */
9970 (void)key;
9971 (void)value;
9972 (void)value_size;
9973 (void)user_data;
9974
9975 return 0;
9976 }
9977
9978
9979 /* Helper function for deprecated mg_upload. */
9980 static int
mg_upload_field_stored(const char * path,long long file_size,void * user_data)9981 mg_upload_field_stored(const char *path, long long file_size, void *user_data)
9982 {
9983 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
9984 (void)file_size;
9985
9986 fud->num_uploaded_files++;
9987 fud->conn->ctx->callbacks.upload(fud->conn, path);
9988
9989 return 0;
9990 }
9991
9992
9993 /* Deprecated function mg_upload - use mg_handle_form_request instead. */
9994 int
mg_upload(struct mg_connection * conn,const char * destination_dir)9995 mg_upload(struct mg_connection *conn, const char *destination_dir)
9996 {
9997 struct mg_upload_user_data fud = {conn, destination_dir, 0};
9998 struct mg_form_data_handler fdh = {mg_upload_field_found,
9999 mg_upload_field_get,
10000 mg_upload_field_stored,
10001 0};
10002 int ret;
10003
10004 fdh.user_data = (void *)&fud;
10005 ret = mg_handle_form_request(conn, &fdh);
10006
10007 if (ret < 0) {
10008 mg_cry(conn, "%s: Error while parsing the request", __func__);
10009 }
10010
10011 return fud.num_uploaded_files;
10012 }
10013 #endif
10014
10015
10016 static int
get_first_ssl_listener_index(const struct mg_context * ctx)10017 get_first_ssl_listener_index(const struct mg_context *ctx)
10018 {
10019 unsigned int i;
10020 int idx = -1;
10021 if (ctx) {
10022 for (i = 0; idx == -1 && i < ctx->num_listening_sockets; i++) {
10023 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
10024 }
10025 }
10026 return idx;
10027 }
10028
10029
10030 static void
redirect_to_https_port(struct mg_connection * conn,int ssl_index)10031 redirect_to_https_port(struct mg_connection *conn, int ssl_index)
10032 {
10033 char host[1025];
10034 const char *host_header;
10035 size_t hostlen;
10036
10037 host_header = mg_get_header(conn, "Host");
10038 hostlen = sizeof(host);
10039 if (host_header != NULL) {
10040 char *pos;
10041
10042 mg_strlcpy(host, host_header, hostlen);
10043 host[hostlen - 1] = '\0';
10044 pos = strchr(host, ':');
10045 if (pos != NULL) {
10046 *pos = '\0';
10047 }
10048 } else {
10049 /* Cannot get host from the Host: header.
10050 * Fallback to our IP address. */
10051 if (conn) {
10052 sockaddr_to_string(host, hostlen, &conn->client.lsa);
10053 }
10054 }
10055
10056 /* Send host, port, uri and (if it exists) ?query_string */
10057 if (conn) {
10058 mg_printf(conn,
10059 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
10060 host,
10061 #if defined(USE_IPV6)
10062 (conn->ctx->listening_sockets[ssl_index].lsa.sa.sa_family
10063 == AF_INET6)
10064 ? (int)ntohs(conn->ctx->listening_sockets[ssl_index]
10065 .lsa.sin6.sin6_port)
10066 :
10067 #endif
10068 (int)ntohs(conn->ctx->listening_sockets[ssl_index]
10069 .lsa.sin.sin_port),
10070 conn->request_info.local_uri,
10071 (conn->request_info.query_string == NULL) ? "" : "?",
10072 (conn->request_info.query_string == NULL)
10073 ? ""
10074 : conn->request_info.query_string);
10075 }
10076 }
10077
10078
10079 static void
mg_set_handler_type(struct mg_context * ctx,const char * uri,int handler_type,int is_delete_request,mg_request_handler handler,struct mg_websocket_subprotocols * subprotocols,mg_websocket_connect_handler connect_handler,mg_websocket_ready_handler ready_handler,mg_websocket_data_handler data_handler,mg_websocket_close_handler close_handler,mg_authorization_handler auth_handler,void * cbdata)10080 mg_set_handler_type(struct mg_context *ctx,
10081 const char *uri,
10082 int handler_type,
10083 int is_delete_request,
10084 mg_request_handler handler,
10085 struct mg_websocket_subprotocols *subprotocols,
10086 mg_websocket_connect_handler connect_handler,
10087 mg_websocket_ready_handler ready_handler,
10088 mg_websocket_data_handler data_handler,
10089 mg_websocket_close_handler close_handler,
10090 mg_authorization_handler auth_handler,
10091 void *cbdata)
10092 {
10093 struct mg_handler_info *tmp_rh, **lastref;
10094 size_t urilen = strlen(uri);
10095
10096 if (handler_type == WEBSOCKET_HANDLER) {
10097 /* assert(handler == NULL); */
10098 /* assert(is_delete_request || connect_handler!=NULL ||
10099 * ready_handler!=NULL || data_handler!=NULL ||
10100 * close_handler!=NULL);
10101 */
10102 /* assert(auth_handler == NULL); */
10103 if (handler != NULL) {
10104 return;
10105 }
10106 if (!is_delete_request && connect_handler == NULL
10107 && ready_handler == NULL
10108 && data_handler == NULL
10109 && close_handler == NULL) {
10110 return;
10111 }
10112 if (auth_handler != NULL) {
10113 return;
10114 }
10115 } else if (handler_type == REQUEST_HANDLER) {
10116 /* assert(connect_handler==NULL && ready_handler==NULL &&
10117 * data_handler==NULL && close_handler==NULL); */
10118 /* assert(is_delete_request || (handler!=NULL));
10119 */
10120 /* assert(auth_handler == NULL); */
10121 if (connect_handler != NULL || ready_handler != NULL
10122 || data_handler != NULL
10123 || close_handler != NULL) {
10124 return;
10125 }
10126 if (!is_delete_request && (handler == NULL)) {
10127 return;
10128 }
10129 if (auth_handler != NULL) {
10130 return;
10131 }
10132 } else { /* AUTH_HANDLER */
10133 /* assert(handler == NULL); */
10134 /* assert(connect_handler==NULL && ready_handler==NULL &&
10135 * data_handler==NULL && close_handler==NULL); */
10136 /* assert(auth_handler != NULL); */
10137 if (handler != NULL) {
10138 return;
10139 }
10140 if (connect_handler != NULL || ready_handler != NULL
10141 || data_handler != NULL
10142 || close_handler != NULL) {
10143 return;
10144 }
10145 if (!is_delete_request && (auth_handler == NULL)) {
10146 return;
10147 }
10148 }
10149
10150 if (!ctx) {
10151 return;
10152 }
10153
10154 mg_lock_context(ctx);
10155
10156 /* first try to find an existing handler */
10157 lastref = &(ctx->handlers);
10158 for (tmp_rh = ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
10159 if (tmp_rh->handler_type == handler_type) {
10160 if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) {
10161 if (!is_delete_request) {
10162 /* update existing handler */
10163 if (handler_type == REQUEST_HANDLER) {
10164 tmp_rh->handler = handler;
10165 } else if (handler_type == WEBSOCKET_HANDLER) {
10166 tmp_rh->subprotocols = subprotocols;
10167 tmp_rh->connect_handler = connect_handler;
10168 tmp_rh->ready_handler = ready_handler;
10169 tmp_rh->data_handler = data_handler;
10170 tmp_rh->close_handler = close_handler;
10171 } else { /* AUTH_HANDLER */
10172 tmp_rh->auth_handler = auth_handler;
10173 }
10174 tmp_rh->cbdata = cbdata;
10175 } else {
10176 /* remove existing handler */
10177 *lastref = tmp_rh->next;
10178 mg_free(tmp_rh->uri);
10179 mg_free(tmp_rh);
10180 }
10181 mg_unlock_context(ctx);
10182 return;
10183 }
10184 }
10185 lastref = &(tmp_rh->next);
10186 }
10187
10188 if (is_delete_request) {
10189 /* no handler to set, this was a remove request to a non-existing
10190 * handler */
10191 mg_unlock_context(ctx);
10192 return;
10193 }
10194
10195 tmp_rh =
10196 (struct mg_handler_info *)mg_calloc(sizeof(struct mg_handler_info), 1);
10197 if (tmp_rh == NULL) {
10198 mg_unlock_context(ctx);
10199 mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
10200 return;
10201 }
10202 tmp_rh->uri = mg_strdup(uri);
10203 if (!tmp_rh->uri) {
10204 mg_unlock_context(ctx);
10205 mg_free(tmp_rh);
10206 mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
10207 return;
10208 }
10209 tmp_rh->uri_len = urilen;
10210 if (handler_type == REQUEST_HANDLER) {
10211 tmp_rh->handler = handler;
10212 } else if (handler_type == WEBSOCKET_HANDLER) {
10213 tmp_rh->subprotocols = subprotocols;
10214 tmp_rh->connect_handler = connect_handler;
10215 tmp_rh->ready_handler = ready_handler;
10216 tmp_rh->data_handler = data_handler;
10217 tmp_rh->close_handler = close_handler;
10218 } else { /* AUTH_HANDLER */
10219 tmp_rh->auth_handler = auth_handler;
10220 }
10221 tmp_rh->cbdata = cbdata;
10222 tmp_rh->handler_type = handler_type;
10223 tmp_rh->next = NULL;
10224
10225 *lastref = tmp_rh;
10226 mg_unlock_context(ctx);
10227 }
10228
10229
10230 void
mg_set_request_handler(struct mg_context * ctx,const char * uri,mg_request_handler handler,void * cbdata)10231 mg_set_request_handler(struct mg_context *ctx,
10232 const char *uri,
10233 mg_request_handler handler,
10234 void *cbdata)
10235 {
10236 mg_set_handler_type(ctx,
10237 uri,
10238 REQUEST_HANDLER,
10239 handler == NULL,
10240 handler,
10241 NULL,
10242 NULL,
10243 NULL,
10244 NULL,
10245 NULL,
10246 NULL,
10247 cbdata);
10248 }
10249
10250
10251 void
mg_set_websocket_handler(struct mg_context * ctx,const char * uri,mg_websocket_connect_handler connect_handler,mg_websocket_ready_handler ready_handler,mg_websocket_data_handler data_handler,mg_websocket_close_handler close_handler,void * cbdata)10252 mg_set_websocket_handler(struct mg_context *ctx,
10253 const char *uri,
10254 mg_websocket_connect_handler connect_handler,
10255 mg_websocket_ready_handler ready_handler,
10256 mg_websocket_data_handler data_handler,
10257 mg_websocket_close_handler close_handler,
10258 void *cbdata)
10259 {
10260 mg_set_websocket_handler_with_subprotocols(ctx,
10261 uri,
10262 NULL,
10263 connect_handler,
10264 ready_handler,
10265 data_handler,
10266 close_handler,
10267 cbdata);
10268 }
10269
10270
10271 void
mg_set_websocket_handler_with_subprotocols(struct mg_context * ctx,const char * uri,struct mg_websocket_subprotocols * subprotocols,mg_websocket_connect_handler connect_handler,mg_websocket_ready_handler ready_handler,mg_websocket_data_handler data_handler,mg_websocket_close_handler close_handler,void * cbdata)10272 mg_set_websocket_handler_with_subprotocols(
10273 struct mg_context *ctx,
10274 const char *uri,
10275 struct mg_websocket_subprotocols *subprotocols,
10276 mg_websocket_connect_handler connect_handler,
10277 mg_websocket_ready_handler ready_handler,
10278 mg_websocket_data_handler data_handler,
10279 mg_websocket_close_handler close_handler,
10280 void *cbdata)
10281 {
10282 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
10283 && (data_handler == NULL)
10284 && (close_handler == NULL);
10285 mg_set_handler_type(ctx,
10286 uri,
10287 WEBSOCKET_HANDLER,
10288 is_delete_request,
10289 NULL,
10290 subprotocols,
10291 connect_handler,
10292 ready_handler,
10293 data_handler,
10294 close_handler,
10295 NULL,
10296 cbdata);
10297 }
10298
10299
10300 void
mg_set_auth_handler(struct mg_context * ctx,const char * uri,mg_request_handler handler,void * cbdata)10301 mg_set_auth_handler(struct mg_context *ctx,
10302 const char *uri,
10303 mg_request_handler handler,
10304 void *cbdata)
10305 {
10306 mg_set_handler_type(ctx,
10307 uri,
10308 AUTH_HANDLER,
10309 handler == NULL,
10310 NULL,
10311 NULL,
10312 NULL,
10313 NULL,
10314 NULL,
10315 NULL,
10316 handler,
10317 cbdata);
10318 }
10319
10320
10321 static int
get_request_handler(struct mg_connection * conn,int handler_type,mg_request_handler * handler,struct mg_websocket_subprotocols ** subprotocols,mg_websocket_connect_handler * connect_handler,mg_websocket_ready_handler * ready_handler,mg_websocket_data_handler * data_handler,mg_websocket_close_handler * close_handler,mg_authorization_handler * auth_handler,void ** cbdata)10322 get_request_handler(struct mg_connection *conn,
10323 int handler_type,
10324 mg_request_handler *handler,
10325 struct mg_websocket_subprotocols **subprotocols,
10326 mg_websocket_connect_handler *connect_handler,
10327 mg_websocket_ready_handler *ready_handler,
10328 mg_websocket_data_handler *data_handler,
10329 mg_websocket_close_handler *close_handler,
10330 mg_authorization_handler *auth_handler,
10331 void **cbdata)
10332 {
10333 const struct mg_request_info *request_info = mg_get_request_info(conn);
10334 if (request_info) {
10335 const char *uri = request_info->local_uri;
10336 size_t urilen = strlen(uri);
10337 struct mg_handler_info *tmp_rh;
10338
10339 if (!conn || !conn->ctx) {
10340 return 0;
10341 }
10342
10343 mg_lock_context(conn->ctx);
10344
10345 /* first try for an exact match */
10346 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
10347 tmp_rh = tmp_rh->next) {
10348 if (tmp_rh->handler_type == handler_type) {
10349 if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) {
10350 if (handler_type == WEBSOCKET_HANDLER) {
10351 *subprotocols = tmp_rh->subprotocols;
10352 *connect_handler = tmp_rh->connect_handler;
10353 *ready_handler = tmp_rh->ready_handler;
10354 *data_handler = tmp_rh->data_handler;
10355 *close_handler = tmp_rh->close_handler;
10356 } else if (handler_type == REQUEST_HANDLER) {
10357 *handler = tmp_rh->handler;
10358 } else { /* AUTH_HANDLER */
10359 *auth_handler = tmp_rh->auth_handler;
10360 }
10361 *cbdata = tmp_rh->cbdata;
10362 mg_unlock_context(conn->ctx);
10363 return 1;
10364 }
10365 }
10366 }
10367
10368 /* next try for a partial match, we will accept uri/something */
10369 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
10370 tmp_rh = tmp_rh->next) {
10371 if (tmp_rh->handler_type == handler_type) {
10372 if (tmp_rh->uri_len < urilen && uri[tmp_rh->uri_len] == '/'
10373 && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
10374 if (handler_type == WEBSOCKET_HANDLER) {
10375 *subprotocols = tmp_rh->subprotocols;
10376 *connect_handler = tmp_rh->connect_handler;
10377 *ready_handler = tmp_rh->ready_handler;
10378 *data_handler = tmp_rh->data_handler;
10379 *close_handler = tmp_rh->close_handler;
10380 } else if (handler_type == REQUEST_HANDLER) {
10381 *handler = tmp_rh->handler;
10382 } else { /* AUTH_HANDLER */
10383 *auth_handler = tmp_rh->auth_handler;
10384 }
10385 *cbdata = tmp_rh->cbdata;
10386 mg_unlock_context(conn->ctx);
10387 return 1;
10388 }
10389 }
10390 }
10391
10392 /* finally try for pattern match */
10393 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
10394 tmp_rh = tmp_rh->next) {
10395 if (tmp_rh->handler_type == handler_type) {
10396 if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
10397 if (handler_type == WEBSOCKET_HANDLER) {
10398 *subprotocols = tmp_rh->subprotocols;
10399 *connect_handler = tmp_rh->connect_handler;
10400 *ready_handler = tmp_rh->ready_handler;
10401 *data_handler = tmp_rh->data_handler;
10402 *close_handler = tmp_rh->close_handler;
10403 } else if (handler_type == REQUEST_HANDLER) {
10404 *handler = tmp_rh->handler;
10405 } else { /* AUTH_HANDLER */
10406 *auth_handler = tmp_rh->auth_handler;
10407 }
10408 *cbdata = tmp_rh->cbdata;
10409 mg_unlock_context(conn->ctx);
10410 return 1;
10411 }
10412 }
10413 }
10414
10415 mg_unlock_context(conn->ctx);
10416 }
10417 return 0; /* none found */
10418 }
10419
10420
10421 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
10422 static int
deprecated_websocket_connect_wrapper(const struct mg_connection * conn,void * cbdata)10423 deprecated_websocket_connect_wrapper(const struct mg_connection *conn,
10424 void *cbdata)
10425 {
10426 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
10427 if (pcallbacks->websocket_connect) {
10428 return pcallbacks->websocket_connect(conn);
10429 }
10430 /* No handler set - assume "OK" */
10431 return 0;
10432 }
10433
10434
10435 static void
deprecated_websocket_ready_wrapper(struct mg_connection * conn,void * cbdata)10436 deprecated_websocket_ready_wrapper(struct mg_connection *conn, void *cbdata)
10437 {
10438 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
10439 if (pcallbacks->websocket_ready) {
10440 pcallbacks->websocket_ready(conn);
10441 }
10442 }
10443
10444
10445 static int
deprecated_websocket_data_wrapper(struct mg_connection * conn,int bits,char * data,size_t len,void * cbdata)10446 deprecated_websocket_data_wrapper(struct mg_connection *conn,
10447 int bits,
10448 char *data,
10449 size_t len,
10450 void *cbdata)
10451 {
10452 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
10453 if (pcallbacks->websocket_data) {
10454 return pcallbacks->websocket_data(conn, bits, data, len);
10455 }
10456 /* No handler set - assume "OK" */
10457 return 1;
10458 }
10459 #endif
10460
10461
10462 /* This is the heart of the Civetweb's logic.
10463 * This function is called when the request is read, parsed and validated,
10464 * and Civetweb must decide what action to take: serve a file, or
10465 * a directory, or call embedded function, etcetera. */
10466 static void
handle_request(struct mg_connection * conn)10467 handle_request(struct mg_connection *conn)
10468 {
10469 if (conn) {
10470 struct mg_request_info *ri = &conn->request_info;
10471 char path[PATH_MAX];
10472 int uri_len, ssl_index;
10473 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
10474 is_put_or_delete_request = 0, is_callback_resource = 0;
10475 int i;
10476 struct mg_file file = STRUCT_FILE_INITIALIZER;
10477 mg_request_handler callback_handler = NULL;
10478 struct mg_websocket_subprotocols *subprotocols;
10479 mg_websocket_connect_handler ws_connect_handler = NULL;
10480 mg_websocket_ready_handler ws_ready_handler = NULL;
10481 mg_websocket_data_handler ws_data_handler = NULL;
10482 mg_websocket_close_handler ws_close_handler = NULL;
10483 void *callback_data = NULL;
10484 mg_authorization_handler auth_handler = NULL;
10485 void *auth_callback_data = NULL;
10486 #if !defined(NO_FILES)
10487 time_t curtime = time(NULL);
10488 char date[64];
10489 #endif
10490
10491 path[0] = 0;
10492
10493 if (!ri) {
10494 return;
10495 }
10496
10497 /* 1. get the request url */
10498 /* 1.1. split into url and query string */
10499 if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
10500 != NULL) {
10501 *((char *)conn->request_info.query_string++) = '\0';
10502 }
10503
10504 /* 1.2. do a https redirect, if required. Do not decode URIs yet. */
10505 if (!conn->client.is_ssl && conn->client.ssl_redir) {
10506 ssl_index = get_first_ssl_listener_index(conn->ctx);
10507 if (ssl_index >= 0) {
10508 redirect_to_https_port(conn, ssl_index);
10509 } else {
10510 /* A http to https forward port has been specified,
10511 * but no https port to forward to. */
10512 send_http_error(conn,
10513 503,
10514 "%s",
10515 "Error: SSL forward not configured properly");
10516 mg_cry(conn, "Can not redirect to SSL, no SSL port available");
10517 }
10518 return;
10519 }
10520 uri_len = (int)strlen(ri->local_uri);
10521
10522 /* 1.3. decode url (if config says so) */
10523 if (should_decode_url(conn)) {
10524 mg_url_decode(
10525 ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
10526 }
10527
10528 /* 1.4. clean URIs, so a path like allowed_dir/../forbidden_file is
10529 * not possible */
10530 remove_double_dots_and_double_slashes((char *)ri->local_uri);
10531
10532 /* step 1. completed, the url is known now */
10533 uri_len = (int)strlen(ri->local_uri);
10534 DEBUG_TRACE("URL: %s", ri->local_uri);
10535
10536 /* 3. if this ip has limited speed, set it for this connection */
10537 conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
10538 get_remote_ip(conn),
10539 ri->local_uri);
10540
10541 /* 4. call a "handle everything" callback, if registered */
10542 if (conn->ctx->callbacks.begin_request != NULL) {
10543 /* Note that since V1.7 the "begin_request" function is called
10544 * before an authorization check. If an authorization check is
10545 * required, use a request_handler instead. */
10546 i = conn->ctx->callbacks.begin_request(conn);
10547 if (i > 0) {
10548 /* callback already processed the request. Store the
10549 return value as a status code for the access log. */
10550 conn->status_code = i;
10551 discard_unread_request_data(conn);
10552 return;
10553 } else if (i == 0) {
10554 /* civetweb should process the request */
10555 } else {
10556 /* unspecified - may change with the next version */
10557 return;
10558 }
10559 }
10560
10561 /* request not yet handled by a handler or redirect, so the request
10562 * is processed here */
10563
10564 /* 5. interpret the url to find out how the request must be handled
10565 */
10566 /* 5.1. first test, if the request targets the regular http(s)://
10567 * protocol namespace or the websocket ws(s):// protocol namespace.
10568 */
10569 is_websocket_request = is_websocket_protocol(conn);
10570
10571 /* 5.2. check if the request will be handled by a callback */
10572 if (get_request_handler(conn,
10573 is_websocket_request ? WEBSOCKET_HANDLER
10574 : REQUEST_HANDLER,
10575 &callback_handler,
10576 &subprotocols,
10577 &ws_connect_handler,
10578 &ws_ready_handler,
10579 &ws_data_handler,
10580 &ws_close_handler,
10581 NULL,
10582 &callback_data)) {
10583 /* 5.2.1. A callback will handle this request. All requests
10584 * handled
10585 * by a callback have to be considered as requests to a script
10586 * resource. */
10587 is_callback_resource = 1;
10588 is_script_resource = 1;
10589 is_put_or_delete_request = is_put_or_delete_method(conn);
10590 } else {
10591 no_callback_resource:
10592 /* 5.2.2. No callback is responsible for this request. The URI
10593 * addresses a file based resource (static content or Lua/cgi
10594 * scripts in the file system). */
10595 is_callback_resource = 0;
10596 interpret_uri(conn,
10597 path,
10598 sizeof(path),
10599 &file.stat,
10600 &is_found,
10601 &is_script_resource,
10602 &is_websocket_request,
10603 &is_put_or_delete_request);
10604 }
10605
10606 /* 6. authorization check */
10607 /* 6.1. a custom authorization handler is installed */
10608 if (get_request_handler(conn,
10609 AUTH_HANDLER,
10610 NULL,
10611 NULL,
10612 NULL,
10613 NULL,
10614 NULL,
10615 NULL,
10616 &auth_handler,
10617 &auth_callback_data)) {
10618 if (!auth_handler(conn, auth_callback_data)) {
10619 return;
10620 }
10621 } else if (is_put_or_delete_request && !is_script_resource
10622 && !is_callback_resource) {
10623 /* 6.2. this request is a PUT/DELETE to a real file */
10624 /* 6.2.1. thus, the server must have real files */
10625 #if defined(NO_FILES)
10626 if (1) {
10627 #else
10628 if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
10629 #endif
10630 /* This server does not have any real files, thus the
10631 * PUT/DELETE methods are not valid. */
10632 send_http_error(conn,
10633 405,
10634 "%s method not allowed",
10635 conn->request_info.request_method);
10636 return;
10637 }
10638
10639 #if !defined(NO_FILES)
10640 /* 6.2.2. Check if put authorization for static files is
10641 * available.
10642 */
10643 if (!is_authorized_for_put(conn)) {
10644 send_authorization_request(conn);
10645 return;
10646 }
10647 #endif
10648
10649 } else {
10650 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
10651 * or it is a PUT or DELETE request to a resource that does not
10652 * correspond to a file. Check authorization. */
10653 if (!check_authorization(conn, path)) {
10654 send_authorization_request(conn);
10655 return;
10656 }
10657 }
10658
10659 /* request is authorized or does not need authorization */
10660
10661 /* 7. check if there are request handlers for this uri */
10662 if (is_callback_resource) {
10663 if (!is_websocket_request) {
10664 i = callback_handler(conn, callback_data);
10665 if (i > 0) {
10666 /* Do nothing, callback has served the request. Store
10667 * the
10668 * return value as status code for the log and discard
10669 * all
10670 * data from the client not used by the callback. */
10671 conn->status_code = i;
10672 discard_unread_request_data(conn);
10673 } else {
10674 /* TODO (high): what if the handler did NOT handle the
10675 * request */
10676 /* The last version did handle this as a file request,
10677 * but
10678 * since a file request is not always a script resource,
10679 * the authorization check might be different */
10680 interpret_uri(conn,
10681 path,
10682 sizeof(path),
10683 &file.stat,
10684 &is_found,
10685 &is_script_resource,
10686 &is_websocket_request,
10687 &is_put_or_delete_request);
10688 callback_handler = NULL;
10689
10690 /* TODO (very low): goto is deprecated but for the
10691 * moment,
10692 * a goto is simpler than some curious loop. */
10693 /* The situation "callback does not handle the request"
10694 * needs to be reconsidered anyway. */
10695 goto no_callback_resource;
10696 }
10697 } else {
10698 #if defined(USE_WEBSOCKET)
10699 handle_websocket_request(conn,
10700 path,
10701 is_callback_resource,
10702 subprotocols,
10703 ws_connect_handler,
10704 ws_ready_handler,
10705 ws_data_handler,
10706 ws_close_handler,
10707 callback_data);
10708 #endif
10709 }
10710 return;
10711 }
10712
10713 /* 8. handle websocket requests */
10714 #if defined(USE_WEBSOCKET)
10715 if (is_websocket_request) {
10716 if (is_script_resource) {
10717 /* Websocket Lua script */
10718 handle_websocket_request(conn,
10719 path,
10720 0 /* Lua Script */,
10721 NULL,
10722 NULL,
10723 NULL,
10724 NULL,
10725 NULL,
10726 &conn->ctx->callbacks);
10727 } else {
10728 #if defined(MG_LEGACY_INTERFACE)
10729 handle_websocket_request(
10730 conn,
10731 path,
10732 !is_script_resource /* could be deprecated global callback */,
10733 NULL,
10734 deprecated_websocket_connect_wrapper,
10735 deprecated_websocket_ready_wrapper,
10736 deprecated_websocket_data_wrapper,
10737 NULL,
10738 &conn->ctx->callbacks);
10739 #else
10740 send_http_error(conn, 404, "%s", "Not found");
10741 #endif
10742 }
10743 return;
10744 } else
10745 #endif
10746
10747 #if defined(NO_FILES)
10748 /* 9a. In case the server uses only callbacks, this uri is
10749 * unknown.
10750 * Then, all request handling ends here. */
10751 send_http_error(conn, 404, "%s", "Not Found");
10752
10753 #else
10754 /* 9b. This request is either for a static file or resource handled
10755 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
10756 if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
10757 send_http_error(conn, 404, "%s", "Not Found");
10758 return;
10759 }
10760
10761 /* 10. File is handled by a script. */
10762 if (is_script_resource) {
10763 handle_file_based_request(conn, path, &file);
10764 return;
10765 }
10766
10767 /* 11. Handle put/delete/mkcol requests */
10768 if (is_put_or_delete_request) {
10769 /* 11.1. PUT method */
10770 if (!strcmp(ri->request_method, "PUT")) {
10771 put_file(conn, path);
10772 return;
10773 }
10774 /* 11.2. DELETE method */
10775 if (!strcmp(ri->request_method, "DELETE")) {
10776 delete_file(conn, path);
10777 return;
10778 }
10779 /* 11.3. MKCOL method */
10780 if (!strcmp(ri->request_method, "MKCOL")) {
10781 mkcol(conn, path);
10782 return;
10783 }
10784 /* 11.4. PATCH method
10785 * This method is not supported for static resources,
10786 * only for scripts (Lua, CGI) and callbacks. */
10787 send_http_error(conn,
10788 405,
10789 "%s method not allowed",
10790 conn->request_info.request_method);
10791 return;
10792 }
10793
10794 /* 11. File does not exist, or it was configured that it should be
10795 * hidden */
10796 if (!is_found || (must_hide_file(conn, path))) {
10797 send_http_error(conn, 404, "%s", "Not found");
10798 return;
10799 }
10800
10801 /* 12. Directory uris should end with a slash */
10802 if (file.stat.is_directory && (uri_len > 0)
10803 && (ri->local_uri[uri_len - 1] != '/')) {
10804 gmt_time_string(date, sizeof(date), &curtime);
10805 mg_printf(conn,
10806 "HTTP/1.1 301 Moved Permanently\r\n"
10807 "Location: %s/\r\n"
10808 "Date: %s\r\n"
10809 /* "Cache-Control: private\r\n" (= default) */
10810 "Content-Length: 0\r\n"
10811 "Connection: %s\r\n\r\n",
10812 ri->request_uri,
10813 date,
10814 suggest_connection_header(conn));
10815 return;
10816 }
10817
10818 /* 13. Handle other methods than GET/HEAD */
10819 /* 13.1. Handle PROPFIND */
10820 if (!strcmp(ri->request_method, "PROPFIND")) {
10821 handle_propfind(conn, path, &file.stat);
10822 return;
10823 }
10824 /* 13.2. Handle OPTIONS for files */
10825 if (!strcmp(ri->request_method, "OPTIONS")) {
10826 /* This standard handler is only used for real files.
10827 * Scripts should support the OPTIONS method themselves, to allow a
10828 * maximum flexibility.
10829 * Lua and CGI scripts may fully support CORS this way (including
10830 * preflights). */
10831 send_options(conn);
10832 return;
10833 }
10834 /* 13.3. everything but GET and HEAD (e.g. POST) */
10835 if (0 != strcmp(ri->request_method, "GET")
10836 && 0 != strcmp(ri->request_method, "HEAD")) {
10837 send_http_error(conn,
10838 405,
10839 "%s method not allowed",
10840 conn->request_info.request_method);
10841 return;
10842 }
10843
10844 /* 14. directories */
10845 if (file.stat.is_directory) {
10846 if (substitute_index_file(conn, path, sizeof(path), &file)) {
10847 /* 14.1. use a substitute file */
10848 /* TODO (high): substitute index may be a script resource.
10849 * define what should be possible in this case. */
10850 } else {
10851 /* 14.2. no substitute file */
10852 if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
10853 "yes")) {
10854 handle_directory_request(conn, path);
10855 } else {
10856 send_http_error(conn,
10857 403,
10858 "%s",
10859 "Error: Directory listing denied");
10860 }
10861 return;
10862 }
10863 }
10864
10865 handle_file_based_request(conn, path, &file);
10866 #endif /* !defined(NO_FILES) */
10867
10868 #if 0
10869 /* Perform redirect and auth checks before calling begin_request()
10870 * handler.
10871 * Otherwise, begin_request() would need to perform auth checks and
10872 * redirects. */
10873 #endif
10874 }
10875 return;
10876 }
10877
10878
10879 static void
10880 handle_file_based_request(struct mg_connection *conn,
10881 const char *path,
10882 struct mg_file *file)
10883 {
10884 if (!conn || !conn->ctx) {
10885 return;
10886 }
10887
10888 if (0) {
10889 #ifdef USE_LUA
10890 } else if (match_prefix(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
10891 strlen(
10892 conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
10893 path) > 0) {
10894 /* Lua server page: an SSI like page containing mostly plain html
10895 * code
10896 * plus some tags with server generated contents. */
10897 handle_lsp_request(conn, path, file, NULL);
10898 } else if (match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
10899 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
10900 path) > 0) {
10901 /* Lua in-server module script: a CGI like script used to generate
10902 * the
10903 * entire reply. */
10904 mg_exec_lua_script(conn, path, NULL);
10905 #endif
10906 #if defined(USE_DUKTAPE)
10907 } else if (match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
10908 strlen(
10909 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
10910 path) > 0) {
10911 /* Call duktape to generate the page */
10912 mg_exec_duktape_script(conn, path);
10913 #endif
10914 #if !defined(NO_CGI)
10915 } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
10916 strlen(conn->ctx->config[CGI_EXTENSIONS]),
10917 path) > 0) {
10918 /* CGI scripts may support all HTTP methods */
10919 handle_cgi_request(conn, path);
10920 #endif /* !NO_CGI */
10921 } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
10922 strlen(conn->ctx->config[SSI_EXTENSIONS]),
10923 path) > 0) {
10924 handle_ssi_file_request(conn, path, file);
10925 #if !defined(NO_CACHING)
10926 } else if ((!conn->in_error_handler)
10927 && is_not_modified(conn, &file->stat)) {
10928 /* Send 304 "Not Modified" - this must not send any body data */
10929 handle_not_modified_static_file_request(conn, file);
10930 #endif /* !NO_CACHING */
10931 } else {
10932 handle_static_file_request(conn, path, file, NULL, NULL);
10933 }
10934 }
10935
10936
10937 static void
10938 close_all_listening_sockets(struct mg_context *ctx)
10939 {
10940 unsigned int i;
10941 if (!ctx) {
10942 return;
10943 }
10944
10945 for (i = 0; i < ctx->num_listening_sockets; i++) {
10946 closesocket(ctx->listening_sockets[i].sock);
10947 ctx->listening_sockets[i].sock = INVALID_SOCKET;
10948 }
10949 mg_free(ctx->listening_sockets);
10950 ctx->listening_sockets = NULL;
10951 mg_free(ctx->listening_socket_fds);
10952 ctx->listening_socket_fds = NULL;
10953 }
10954
10955
10956 /* Valid listening port specification is: [ip_address:]port[s]
10957 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
10958 * Examples for IPv6: [::]:80, [::1]:80,
10959 * [2001:0db8:7654:3210:FEDC:BA98:7654:3210]:443s
10960 * see https://tools.ietf.org/html/rfc3513#section-2.2
10961 * In order to bind to both, IPv4 and IPv6, you can either add
10962 * both ports using 8080,[::]:8080, or the short form +8080.
10963 * Both forms differ in detail: 8080,[::]:8080 create two sockets,
10964 * one only accepting IPv4 the other only IPv6. +8080 creates
10965 * one socket accepting IPv4 and IPv6. Depending on the IPv6
10966 * environment, they might work differently, or might not work
10967 * at all - it must be tested what options work best in the
10968 * relevant network environment.
10969 */
10970 static int
10971 parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
10972 {
10973 unsigned int a, b, c, d, port;
10974 int ch, len;
10975 #if defined(USE_IPV6)
10976 char buf[100] = {0};
10977 #endif
10978
10979 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
10980 * Also, all-zeroes in the socket address means binding to all addresses
10981 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
10982 memset(so, 0, sizeof(*so));
10983 so->lsa.sin.sin_family = AF_INET;
10984 *ip_version = 0;
10985
10986 if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
10987 == 5) {
10988 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
10989 so->lsa.sin.sin_addr.s_addr =
10990 htonl((a << 24) | (b << 16) | (c << 8) | d);
10991 so->lsa.sin.sin_port = htons((uint16_t)port);
10992 *ip_version = 4;
10993
10994 #if defined(USE_IPV6)
10995 } else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
10996 && mg_inet_pton(
10997 AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
10998 /* IPv6 address, examples: see above */
10999 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
11000 */
11001 so->lsa.sin6.sin6_port = htons((uint16_t)port);
11002 *ip_version = 6;
11003 #endif
11004
11005 } else if ((vec->ptr[0] == '+')
11006 && (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
11007
11008 /* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY */
11009 /* Add 1 to len for the + character we skipped before */
11010 len++;
11011
11012 #if defined(USE_IPV6)
11013 /* Set socket family to IPv6, do not use IPV6_V6ONLY */
11014 so->lsa.sin6.sin6_family = AF_INET6;
11015 so->lsa.sin6.sin6_port = htons((uint16_t)port);
11016 *ip_version = 4 + 6;
11017 #else
11018 /* Bind to IPv4 only, since IPv6 is not built in. */
11019 so->lsa.sin.sin_port = htons((uint16_t)port);
11020 *ip_version = 4;
11021 #endif
11022
11023 } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
11024 /* If only port is specified, bind to IPv4, INADDR_ANY */
11025 so->lsa.sin.sin_port = htons((uint16_t)port);
11026 *ip_version = 4;
11027
11028 } else {
11029 /* Parsing failure. Make port invalid. */
11030 port = 0;
11031 len = 0;
11032 }
11033
11034 /* sscanf and the option splitting code ensure the following condition
11035 */
11036 if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
11037 *ip_version = 0;
11038 return 0;
11039 }
11040 ch = vec->ptr[len]; /* Next character after the port number */
11041 so->is_ssl = (ch == 's');
11042 so->ssl_redir = (ch == 'r');
11043
11044 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
11045 if (is_valid_port(port)
11046 && (ch == '\0' || ch == 's' || ch == 'r' || ch == ',')) {
11047 return 1;
11048 }
11049
11050 /* Reset ip_version to 0 of there is an error */
11051 *ip_version = 0;
11052 return 0;
11053 }
11054
11055
11056 static int
11057 set_ports_option(struct mg_context *ctx)
11058 {
11059 const char *list;
11060 int on = 1;
11061 #if defined(USE_IPV6)
11062 int off = 0;
11063 #endif
11064 struct vec vec;
11065 struct socket so, *ptr;
11066
11067 struct pollfd *pfd;
11068 union usa usa;
11069 socklen_t len;
11070 int ip_version;
11071
11072 int portsTotal = 0;
11073 int portsOk = 0;
11074
11075 if (!ctx) {
11076 return 0;
11077 }
11078
11079 memset(&so, 0, sizeof(so));
11080 memset(&usa, 0, sizeof(usa));
11081 len = sizeof(usa);
11082 list = ctx->config[LISTENING_PORTS];
11083
11084 while ((list = next_option(list, &vec, NULL)) != NULL) {
11085
11086 portsTotal++;
11087
11088 if (!parse_port_string(&vec, &so, &ip_version)) {
11089 mg_cry(fc(ctx),
11090 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
11091 (int)vec.len,
11092 vec.ptr,
11093 portsTotal,
11094 "[IP_ADDRESS:]PORT[s|r]");
11095 continue;
11096 }
11097
11098 #if !defined(NO_SSL)
11099 if (so.is_ssl && ctx->ssl_ctx == NULL) {
11100
11101 mg_cry(fc(ctx),
11102 "Cannot add SSL socket (entry %i). Is -ssl_certificate "
11103 "option set?",
11104 portsTotal);
11105 continue;
11106 }
11107 #endif
11108
11109 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
11110 == INVALID_SOCKET) {
11111
11112 mg_cry(fc(ctx), "cannot create socket (entry %i)", portsTotal);
11113 continue;
11114 }
11115
11116 #ifdef _WIN32
11117 /* Windows SO_REUSEADDR lets many procs binds to a
11118 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
11119 * if someone already has the socket -- DTL */
11120 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
11121 * Windows might need a few seconds before
11122 * the same port can be used again in the
11123 * same process, so a short Sleep may be
11124 * required between mg_stop and mg_start.
11125 */
11126 if (setsockopt(so.sock,
11127 SOL_SOCKET,
11128 SO_EXCLUSIVEADDRUSE,
11129 (SOCK_OPT_TYPE)&on,
11130 sizeof(on)) != 0) {
11131
11132 /* Set reuse option, but don't abort on errors. */
11133 mg_cry(fc(ctx),
11134 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
11135 portsTotal);
11136 }
11137 #else
11138 if (setsockopt(so.sock,
11139 SOL_SOCKET,
11140 SO_REUSEADDR,
11141 (SOCK_OPT_TYPE)&on,
11142 sizeof(on)) != 0) {
11143
11144 /* Set reuse option, but don't abort on errors. */
11145 mg_cry(fc(ctx),
11146 "cannot set socket option SO_REUSEADDR (entry %i)",
11147 portsTotal);
11148 }
11149 #endif
11150
11151 if (ip_version > 4) {
11152 #if defined(USE_IPV6)
11153 if (ip_version == 6) {
11154 if (so.lsa.sa.sa_family == AF_INET6
11155 && setsockopt(so.sock,
11156 IPPROTO_IPV6,
11157 IPV6_V6ONLY,
11158 (void *)&off,
11159 sizeof(off)) != 0) {
11160
11161 /* Set IPv6 only option, but don't abort on errors. */
11162 mg_cry(fc(ctx),
11163 "cannot set socket option IPV6_V6ONLY (entry %i)",
11164 portsTotal);
11165 }
11166 }
11167 #else
11168 mg_cry(fc(ctx), "IPv6 not available");
11169 closesocket(so.sock);
11170 so.sock = INVALID_SOCKET;
11171 continue;
11172 #endif
11173 }
11174
11175 if (so.lsa.sa.sa_family == AF_INET) {
11176
11177 len = sizeof(so.lsa.sin);
11178 if (bind(so.sock, &so.lsa.sa, len) != 0) {
11179 mg_cry(fc(ctx),
11180 "cannot bind to %.*s: %d (%s)",
11181 (int)vec.len,
11182 vec.ptr,
11183 (int)ERRNO,
11184 strerror(errno));
11185 closesocket(so.sock);
11186 so.sock = INVALID_SOCKET;
11187 continue;
11188 }
11189 }
11190 #if defined(USE_IPV6)
11191 else if (so.lsa.sa.sa_family == AF_INET6) {
11192
11193 len = sizeof(so.lsa.sin6);
11194 if (bind(so.sock, &so.lsa.sa, len) != 0) {
11195 mg_cry(fc(ctx),
11196 "cannot bind to IPv6 %.*s: %d (%s)",
11197 (int)vec.len,
11198 vec.ptr,
11199 (int)ERRNO,
11200 strerror(errno));
11201 closesocket(so.sock);
11202 so.sock = INVALID_SOCKET;
11203 continue;
11204 }
11205 }
11206 #endif
11207 else {
11208 mg_cry(fc(ctx),
11209 "cannot bind: address family not supported (entry %i)",
11210 portsTotal);
11211 continue;
11212 }
11213
11214 if (listen(so.sock, SOMAXCONN) != 0) {
11215
11216 mg_cry(fc(ctx),
11217 "cannot listen to %.*s: %d (%s)",
11218 (int)vec.len,
11219 vec.ptr,
11220 (int)ERRNO,
11221 strerror(errno));
11222 closesocket(so.sock);
11223 so.sock = INVALID_SOCKET;
11224 continue;
11225 }
11226
11227 if (getsockname(so.sock, &(usa.sa), &len) != 0
11228 || usa.sa.sa_family != so.lsa.sa.sa_family) {
11229
11230 int err = (int)ERRNO;
11231 mg_cry(fc(ctx),
11232 "call to getsockname failed %.*s: %d (%s)",
11233 (int)vec.len,
11234 vec.ptr,
11235 err,
11236 strerror(errno));
11237 closesocket(so.sock);
11238 so.sock = INVALID_SOCKET;
11239 continue;
11240 }
11241
11242 /* Update lsa port in case of random free ports */
11243 #if defined(USE_IPV6)
11244 if (so.lsa.sa.sa_family == AF_INET6) {
11245 so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
11246 } else
11247 #endif
11248 {
11249 so.lsa.sin.sin_port = usa.sin.sin_port;
11250 }
11251
11252 if ((ptr = (struct socket *)
11253 mg_realloc(ctx->listening_sockets,
11254 (ctx->num_listening_sockets + 1)
11255 * sizeof(ctx->listening_sockets[0]))) == NULL) {
11256
11257 mg_cry(fc(ctx), "%s", "Out of memory");
11258 closesocket(so.sock);
11259 so.sock = INVALID_SOCKET;
11260 continue;
11261 }
11262
11263 if ((pfd = (struct pollfd *)mg_realloc(
11264 ctx->listening_socket_fds,
11265 (ctx->num_listening_sockets + 1)
11266 * sizeof(ctx->listening_socket_fds[0]))) == NULL) {
11267
11268 mg_cry(fc(ctx), "%s", "Out of memory");
11269 closesocket(so.sock);
11270 so.sock = INVALID_SOCKET;
11271 mg_free(ptr);
11272 continue;
11273 }
11274
11275 set_close_on_exec(so.sock, fc(ctx));
11276 ctx->listening_sockets = ptr;
11277 ctx->listening_sockets[ctx->num_listening_sockets] = so;
11278 ctx->listening_socket_fds = pfd;
11279 ctx->num_listening_sockets++;
11280 portsOk++;
11281 }
11282
11283 if (portsOk != portsTotal) {
11284 close_all_listening_sockets(ctx);
11285 portsOk = 0;
11286 }
11287
11288 return portsOk;
11289 }
11290
11291
11292 static const char *
11293 header_val(const struct mg_connection *conn, const char *header)
11294 {
11295 const char *header_value;
11296
11297 if ((header_value = mg_get_header(conn, header)) == NULL) {
11298 return "-";
11299 } else {
11300 return header_value;
11301 }
11302 }
11303
11304
11305 static void
11306 log_access(const struct mg_connection *conn)
11307 {
11308 const struct mg_request_info *ri;
11309 struct mg_file fi;
11310 char date[64], src_addr[IP_ADDR_STR_LEN];
11311 struct tm *tm;
11312
11313 const char *referer;
11314 const char *user_agent;
11315
11316 char buf[4096];
11317
11318 if (!conn || !conn->ctx) {
11319 return;
11320 }
11321
11322 if (conn->ctx->config[ACCESS_LOG_FILE] != NULL) {
11323 if (mg_fopen(conn,
11324 conn->ctx->config[ACCESS_LOG_FILE],
11325 MG_FOPEN_MODE_APPEND,
11326 &fi) == 0) {
11327 fi.access.fp = NULL;
11328 }
11329 } else {
11330 fi.access.fp = NULL;
11331 }
11332
11333 /* Log is written to a file and/or a callback. If both are not set,
11334 * executing the rest of the function is pointless. */
11335 if ((fi.access.fp == NULL) && (conn->ctx->callbacks.log_access == NULL)) {
11336 return;
11337 }
11338
11339 tm = localtime(&conn->conn_birth_time);
11340 if (tm != NULL) {
11341 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
11342 } else {
11343 mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
11344 date[sizeof(date) - 1] = '\0';
11345 }
11346
11347 ri = &conn->request_info;
11348
11349 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
11350 referer = header_val(conn, "Referer");
11351 user_agent = header_val(conn, "User-Agent");
11352
11353 mg_snprintf(conn,
11354 NULL, /* Ignore truncation in access log */
11355 buf,
11356 sizeof(buf),
11357 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
11358 src_addr,
11359 (ri->remote_user == NULL) ? "-" : ri->remote_user,
11360 date,
11361 ri->request_method ? ri->request_method : "-",
11362 ri->request_uri ? ri->request_uri : "-",
11363 ri->query_string ? "?" : "",
11364 ri->query_string ? ri->query_string : "",
11365 ri->http_version,
11366 conn->status_code,
11367 conn->num_bytes_sent,
11368 referer,
11369 user_agent);
11370
11371 if (conn->ctx->callbacks.log_access) {
11372 conn->ctx->callbacks.log_access(conn, buf);
11373 }
11374
11375 if (fi.access.fp) {
11376 int ok = 1;
11377 flockfile(fi.access.fp);
11378 if (fprintf(fi.access.fp, "%s\n", buf) < 1) {
11379 ok = 0;
11380 }
11381 if (fflush(fi.access.fp) != 0) {
11382 ok = 0;
11383 }
11384 funlockfile(fi.access.fp);
11385 if (mg_fclose(&fi.access) != 0) {
11386 ok = 0;
11387 }
11388 if (!ok) {
11389 mg_cry(conn,
11390 "Error writing log file %s",
11391 conn->ctx->config[ACCESS_LOG_FILE]);
11392 }
11393 }
11394 }
11395
11396
11397 /* Verify given socket address against the ACL.
11398 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
11399 */
11400 static int
11401 check_acl(struct mg_context *ctx, uint32_t remote_ip)
11402 {
11403 int allowed, flag;
11404 uint32_t net, mask;
11405 struct vec vec;
11406
11407 if (ctx) {
11408 const char *list = ctx->config[ACCESS_CONTROL_LIST];
11409
11410 /* If any ACL is set, deny by default */
11411 allowed = (list == NULL) ? '+' : '-';
11412
11413 while ((list = next_option(list, &vec, NULL)) != NULL) {
11414 flag = vec.ptr[0];
11415 if ((flag != '+' && flag != '-')
11416 || parse_net(&vec.ptr[1], &net, &mask) == 0) {
11417 mg_cry(fc(ctx),
11418 "%s: subnet must be [+|-]x.x.x.x[/x]",
11419 __func__);
11420 return -1;
11421 }
11422
11423 if (net == (remote_ip & mask)) {
11424 allowed = flag;
11425 }
11426 }
11427
11428 return allowed == '+';
11429 }
11430 return -1;
11431 }
11432
11433
11434 #if !defined(_WIN32)
11435 static int
11436 set_uid_option(struct mg_context *ctx)
11437 {
11438 struct passwd *pw;
11439 if (ctx) {
11440 const char *uid = ctx->config[RUN_AS_USER];
11441 int success = 0;
11442
11443 if (uid == NULL) {
11444 success = 1;
11445 } else {
11446 if ((pw = getpwnam(uid)) == NULL) {
11447 mg_cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
11448 } else if (setgid(pw->pw_gid) == -1) {
11449 mg_cry(fc(ctx),
11450 "%s: setgid(%s): %s",
11451 __func__,
11452 uid,
11453 strerror(errno));
11454 } else if (setgroups(0, NULL)) {
11455 mg_cry(fc(ctx),
11456 "%s: setgroups(): %s",
11457 __func__,
11458 strerror(errno));
11459 } else if (setuid(pw->pw_uid) == -1) {
11460 mg_cry(fc(ctx),
11461 "%s: setuid(%s): %s",
11462 __func__,
11463 uid,
11464 strerror(errno));
11465 } else {
11466 success = 1;
11467 }
11468 }
11469
11470 return success;
11471 }
11472 return 0;
11473 }
11474 #endif /* !_WIN32 */
11475
11476
11477 static void
11478 tls_dtor(void *key)
11479 {
11480 struct mg_workerTLS *tls = (struct mg_workerTLS *)key;
11481 /* key == pthread_getspecific(sTlsKey); */
11482
11483 if (tls) {
11484 if (tls->is_master == 2) {
11485 tls->is_master = -3; /* Mark memory as dead */
11486 mg_free(tls);
11487 }
11488 }
11489 pthread_setspecific(sTlsKey, NULL);
11490 }
11491
11492
11493 #if !defined(NO_SSL)
11494
11495 /* Must be set if sizeof(pthread_t) > sizeof(unsigned long) */
11496 static unsigned long
11497 ssl_id_callback(void)
11498 {
11499 #ifdef _WIN32
11500 return GetCurrentThreadId();
11501 #else
11502
11503 #ifdef __clang__
11504 #pragma clang diagnostic push
11505 #pragma clang diagnostic ignored "-Wunreachable-code"
11506 /* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
11507 * or not, so one of the two conditions will be unreachable by construction.
11508 * Unfortunately the C standard does not define a way to check this at
11509 * compile time, since the #if preprocessor conditions can not use the sizeof
11510 * operator as an argument. */
11511 #endif
11512
11513 if (sizeof(pthread_t) > sizeof(unsigned long)) {
11514 /* This is the problematic case for CRYPTO_set_id_callback:
11515 * The OS pthread_t can not be cast to unsigned long. */
11516 struct mg_workerTLS *tls =
11517 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
11518 if (tls == NULL) {
11519 /* SSL called from an unknown thread: Create some thread index.
11520 */
11521 tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS));
11522 tls->is_master = -2; /* -2 means "3rd party thread" */
11523 tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
11524 pthread_setspecific(sTlsKey, tls);
11525 }
11526 return tls->thread_idx;
11527 } else {
11528 /* pthread_t may be any data type, so a simple cast to unsigned long
11529 * can rise a warning/error, depending on the platform.
11530 * Here memcpy is used as an anything-to-anything cast. */
11531 unsigned long ret = 0;
11532 pthread_t t = pthread_self();
11533 memcpy(&ret, &t, sizeof(pthread_t));
11534 return ret;
11535 }
11536
11537 #ifdef __clang__
11538 #pragma clang diagnostic pop
11539 #endif
11540
11541 #endif
11542 }
11543
11544
11545 static int ssl_use_pem_file(struct mg_context *ctx, const char *pem);
11546 static const char *ssl_error(void);
11547
11548
11549 static int
11550 refresh_trust(struct mg_connection *conn)
11551 {
11552 static int reload_lock = 0;
11553 static long int data_check = 0;
11554 volatile int *p_reload_lock = (volatile int *)&reload_lock;
11555
11556 struct stat cert_buf;
11557 long int t;
11558 char *pem;
11559 int should_verify_peer;
11560
11561 if ((pem = conn->ctx->config[SSL_CERTIFICATE]) == NULL) {
11562 /* If peem is NULL and conn->ctx->callbacks.init_ssl is not,
11563 * refresh_trust still can not work. */
11564 return 0;
11565 }
11566
11567 t = data_check;
11568 if (stat(pem, &cert_buf) != -1) {
11569 t = (long int)cert_buf.st_mtime;
11570 }
11571
11572 if (data_check != t) {
11573 data_check = t;
11574
11575 should_verify_peer =
11576 (conn->ctx->config[SSL_DO_VERIFY_PEER] != NULL)
11577 && (mg_strcasecmp(conn->ctx->config[SSL_DO_VERIFY_PEER], "yes")
11578 == 0);
11579
11580 if (should_verify_peer) {
11581 char *ca_path = conn->ctx->config[SSL_CA_PATH];
11582 char *ca_file = conn->ctx->config[SSL_CA_FILE];
11583 if (SSL_CTX_load_verify_locations(conn->ctx->ssl_ctx,
11584 ca_file,
11585 ca_path) != 1) {
11586 mg_cry(fc(conn->ctx),
11587 "SSL_CTX_load_verify_locations error: %s "
11588 "ssl_verify_peer requires setting "
11589 "either ssl_ca_path or ssl_ca_file. Is any of them "
11590 "present in "
11591 "the .conf file?",
11592 ssl_error());
11593 return 0;
11594 }
11595 }
11596
11597 if (1 == mg_atomic_inc(p_reload_lock)) {
11598 if (ssl_use_pem_file(conn->ctx, pem) == 0) {
11599 return 0;
11600 }
11601 *p_reload_lock = 0;
11602 }
11603 }
11604 /* lock while cert is reloading */
11605 while (*p_reload_lock) {
11606 sleep(1);
11607 }
11608
11609 return 1;
11610 }
11611
11612
11613 static pthread_mutex_t *ssl_mutexes;
11614
11615
11616 static int
11617 sslize(struct mg_connection *conn,
11618 SSL_CTX *s,
11619 int (*func)(SSL *),
11620 volatile int *stop_server)
11621 {
11622 int ret, err;
11623 int short_trust;
11624 unsigned i;
11625
11626 if (!conn) {
11627 return 0;
11628 }
11629
11630 short_trust =
11631 (conn->ctx->config[SSL_SHORT_TRUST] != NULL)
11632 && (mg_strcasecmp(conn->ctx->config[SSL_SHORT_TRUST], "yes") == 0);
11633
11634 if (short_trust) {
11635 int trust_ret = refresh_trust(conn);
11636 if (!trust_ret) {
11637 return trust_ret;
11638 }
11639 }
11640
11641 conn->ssl = SSL_new(s);
11642 if (conn->ssl == NULL) {
11643 return 0;
11644 }
11645
11646 ret = SSL_set_fd(conn->ssl, conn->client.sock);
11647 if (ret != 1) {
11648 err = SSL_get_error(conn->ssl, ret);
11649 (void)err; /* TODO: set some error message */
11650 SSL_free(conn->ssl);
11651 conn->ssl = NULL;
11652 /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion:
11653 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
11654 ERR_remove_state(0);
11655 return 0;
11656 }
11657
11658 /* SSL functions may fail and require to be called again:
11659 * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html
11660 * Here "func" could be SSL_connect or SSL_accept. */
11661 for (i = 16; i <= 1024; i *= 2) {
11662 ret = func(conn->ssl);
11663 if (ret != 1) {
11664 err = SSL_get_error(conn->ssl, ret);
11665 if ((err == SSL_ERROR_WANT_CONNECT)
11666 || (err == SSL_ERROR_WANT_ACCEPT)
11667 || (err == SSL_ERROR_WANT_READ)
11668 || (err == SSL_ERROR_WANT_WRITE)) {
11669 /* Need to retry the function call "later".
11670 * See https://linux.die.net/man/3/ssl_get_error
11671 * This is typical for non-blocking sockets. */
11672 if (*stop_server) {
11673 /* Don't wait if the server is going to be stopped. */
11674 break;
11675 }
11676 mg_sleep(i);
11677
11678 } else if (err == SSL_ERROR_SYSCALL) {
11679 /* This is an IO error. Look at errno. */
11680 err = errno;
11681 /* TODO: set some error message */
11682 break;
11683 } else {
11684 /* This is an SSL specific error */
11685 /* TODO: set some error message */
11686 break;
11687 }
11688
11689 } else {
11690 /* success */
11691 break;
11692 }
11693 }
11694
11695 if (ret != 1) {
11696 SSL_free(conn->ssl);
11697 conn->ssl = NULL;
11698 /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion:
11699 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
11700 ERR_remove_state(0);
11701 return 0;
11702 }
11703
11704 return 1;
11705 }
11706
11707
11708 /* Return OpenSSL error message (from CRYPTO lib) */
11709 static const char *
11710 ssl_error(void)
11711 {
11712 unsigned long err;
11713 err = ERR_get_error();
11714 return ((err == 0) ? "" : ERR_error_string(err, NULL));
11715 }
11716
11717
11718 static int
11719 hexdump2string(void *mem, int memlen, char *buf, int buflen)
11720 {
11721 int i;
11722 const char hexdigit[] = "0123456789abcdef";
11723
11724 if (memlen <= 0 || buflen <= 0) {
11725 return 0;
11726 }
11727 if (buflen < (3 * memlen)) {
11728 return 0;
11729 }
11730
11731 for (i = 0; i < memlen; i++) {
11732 if (i > 0) {
11733 buf[3 * i - 1] = ' ';
11734 }
11735 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
11736 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
11737 }
11738 buf[3 * memlen - 1] = 0;
11739
11740 return 1;
11741 }
11742
11743
11744 static void
11745 ssl_get_client_cert_info(struct mg_connection *conn)
11746 {
11747 X509 *cert = SSL_get_peer_certificate(conn->ssl);
11748 if (cert) {
11749 char str_subject[1024];
11750 char str_issuer[1024];
11751 char str_serial[1024];
11752 char str_finger[1024];
11753 unsigned char buf[256];
11754 int len;
11755 unsigned int ulen;
11756
11757 /* Handle to algorithm used for fingerprint */
11758 const EVP_MD *digest = EVP_get_digestbyname("sha1");
11759
11760 /* Get Subject and issuer */
11761 X509_NAME *subj = X509_get_subject_name(cert);
11762 X509_NAME *iss = X509_get_issuer_name(cert);
11763
11764 /* Get serial number */
11765 ASN1_INTEGER *serial = X509_get_serialNumber(cert);
11766
11767 /* Translate subject and issuer to a string */
11768 (void)X509_NAME_oneline(subj, str_subject, (int)sizeof(str_subject));
11769 (void)X509_NAME_oneline(iss, str_issuer, (int)sizeof(str_issuer));
11770
11771 /* Translate serial number to a hex string */
11772 len = i2c_ASN1_INTEGER(serial, NULL);
11773 if ((len > 0) && ((unsigned)len < (unsigned)sizeof(buf))) {
11774 unsigned char *pbuf = buf;
11775 int len2 = i2c_ASN1_INTEGER(serial, &pbuf);
11776 if (!hexdump2string(
11777 buf, len2, str_serial, (int)sizeof(str_serial))) {
11778 *str_serial = 0;
11779 }
11780 } else {
11781 *str_serial = 0;
11782 }
11783
11784 /* Calculate SHA1 fingerprint and store as a hex string */
11785 ulen = 0;
11786 ASN1_digest((int (*)())i2d_X509, digest, (char *)cert, buf, &ulen);
11787 if (!hexdump2string(
11788 buf, (int)ulen, str_finger, (int)sizeof(str_finger))) {
11789 *str_finger = 0;
11790 }
11791
11792 conn->request_info.client_cert =
11793 (struct client_cert *)mg_malloc(sizeof(struct client_cert));
11794 if (conn->request_info.client_cert) {
11795 conn->request_info.client_cert->subject = mg_strdup(str_subject);
11796 conn->request_info.client_cert->issuer = mg_strdup(str_issuer);
11797 conn->request_info.client_cert->serial = mg_strdup(str_serial);
11798 conn->request_info.client_cert->finger = mg_strdup(str_finger);
11799 } else {
11800 /* TODO: write some OOM message */
11801 }
11802
11803 X509_free(cert);
11804 }
11805 }
11806
11807
11808 static void
11809 ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
11810 {
11811 (void)line;
11812 (void)file;
11813
11814 if (mode & 1) {
11815 /* 1 is CRYPTO_LOCK */
11816 (void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
11817 } else {
11818 (void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
11819 }
11820 }
11821
11822
11823 #if !defined(NO_SSL_DL)
11824 static void *
11825 load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
11826 {
11827 union {
11828 void *p;
11829 void (*fp)(void);
11830 } u;
11831 void *dll_handle;
11832 struct ssl_func *fp;
11833
11834 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
11835 mg_cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
11836 return NULL;
11837 }
11838
11839 for (fp = sw; fp->name != NULL; fp++) {
11840 #ifdef _WIN32
11841 /* GetProcAddress() returns pointer to function */
11842 u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
11843 #else
11844 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
11845 * pointers to function pointers. We need to use a union to make a
11846 * cast. */
11847 u.p = dlsym(dll_handle, fp->name);
11848 #endif /* _WIN32 */
11849 if (u.fp == NULL) {
11850 mg_cry(fc(ctx),
11851 "%s: %s: cannot find %s",
11852 __func__,
11853 dll_name,
11854 fp->name);
11855 dlclose(dll_handle);
11856 return NULL;
11857 } else {
11858 fp->ptr = u.fp;
11859 }
11860 }
11861
11862 return dll_handle;
11863 }
11864
11865
11866 static void *ssllib_dll_handle; /* Store the ssl library handle. */
11867 static void *cryptolib_dll_handle; /* Store the crypto library handle. */
11868
11869 #endif /* NO_SSL_DL */
11870
11871
11872 #if defined(SSL_ALREADY_INITIALIZED)
11873 static int cryptolib_users = 1; /* Reference counter for crypto library. */
11874 #else
11875 static int cryptolib_users = 0; /* Reference counter for crypto library. */
11876 #endif
11877
11878
11879 static int
11880 initialize_ssl(struct mg_context *ctx)
11881 {
11882 int i;
11883 size_t size;
11884
11885 #if !defined(NO_SSL_DL)
11886 if (!cryptolib_dll_handle) {
11887 cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, crypto_sw);
11888 if (!cryptolib_dll_handle) {
11889 return 0;
11890 }
11891 }
11892 #endif /* NO_SSL_DL */
11893
11894 if (mg_atomic_inc(&cryptolib_users) > 1) {
11895 return 1;
11896 }
11897
11898 /* Initialize locking callbacks, needed for thread safety.
11899 * http://www.openssl.org/support/faq.html#PROG1
11900 */
11901 i = CRYPTO_num_locks();
11902 if (i < 0) {
11903 i = 0;
11904 }
11905 size = sizeof(pthread_mutex_t) * ((size_t)(i));
11906 if ((ssl_mutexes = (pthread_mutex_t *)mg_malloc(size)) == NULL) {
11907 mg_cry(fc(ctx),
11908 "%s: cannot allocate mutexes: %s",
11909 __func__,
11910 ssl_error());
11911 return 0;
11912 }
11913
11914 for (i = 0; i < CRYPTO_num_locks(); i++) {
11915 pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr);
11916 }
11917
11918 CRYPTO_set_locking_callback(&ssl_locking_callback);
11919 CRYPTO_set_id_callback(&ssl_id_callback);
11920
11921 return 1;
11922 }
11923
11924
11925 static int
11926 ssl_use_pem_file(struct mg_context *ctx, const char *pem)
11927 {
11928 if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0) {
11929 mg_cry(fc(ctx),
11930 "%s: cannot open certificate file %s: %s",
11931 __func__,
11932 pem,
11933 ssl_error());
11934 return 0;
11935 }
11936
11937 /* could use SSL_CTX_set_default_passwd_cb_userdata */
11938 if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0) {
11939 mg_cry(fc(ctx),
11940 "%s: cannot open private key file %s: %s",
11941 __func__,
11942 pem,
11943 ssl_error());
11944 return 0;
11945 }
11946
11947 if (SSL_CTX_check_private_key(ctx->ssl_ctx) == 0) {
11948 mg_cry(fc(ctx),
11949 "%s: certificate and private key do not match: %s",
11950 __func__,
11951 pem);
11952 return 0;
11953 }
11954
11955 if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem) == 0) {
11956 mg_cry(fc(ctx),
11957 "%s: cannot use certificate chain file %s: %s",
11958 __func__,
11959 pem,
11960 ssl_error());
11961 return 0;
11962 }
11963 return 1;
11964 }
11965
11966
11967 static long
11968 ssl_get_protocol(int version_id)
11969 {
11970 long ret = SSL_OP_ALL;
11971 if (version_id > 0)
11972 ret |= SSL_OP_NO_SSLv2;
11973 if (version_id > 1)
11974 ret |= SSL_OP_NO_SSLv3;
11975 if (version_id > 2)
11976 ret |= SSL_OP_NO_TLSv1;
11977 if (version_id > 3)
11978 ret |= SSL_OP_NO_TLSv1_1;
11979 return ret;
11980 }
11981
11982
11983 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
11984 static int
11985 set_ssl_option(struct mg_context *ctx)
11986 {
11987 const char *pem;
11988 int callback_ret;
11989 int should_verify_peer;
11990 const char *ca_path;
11991 const char *ca_file;
11992 int use_default_verify_paths;
11993 int verify_depth;
11994 time_t now_rt = time(NULL);
11995 struct timespec now_mt;
11996 md5_byte_t ssl_context_id[16];
11997 md5_state_t md5state;
11998 int protocol_ver;
11999
12000 /* If PEM file is not specified and the init_ssl callback
12001 * is not specified, skip SSL initialization. */
12002 if (!ctx) {
12003 return 0;
12004 }
12005 if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL
12006 && ctx->callbacks.init_ssl == NULL) {
12007 return 1;
12008 }
12009
12010 if (!initialize_ssl(ctx)) {
12011 return 0;
12012 }
12013
12014 #if !defined(NO_SSL_DL)
12015 if (!ssllib_dll_handle) {
12016 ssllib_dll_handle = load_dll(ctx, SSL_LIB, ssl_sw);
12017 if (!ssllib_dll_handle) {
12018 return 0;
12019 }
12020 }
12021 #endif /* NO_SSL_DL */
12022
12023 /* Initialize SSL library */
12024 SSL_library_init();
12025 SSL_load_error_strings();
12026
12027 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
12028 mg_cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
12029 return 0;
12030 }
12031
12032 SSL_CTX_clear_options(ctx->ssl_ctx,
12033 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1
12034 | SSL_OP_NO_TLSv1_1);
12035 protocol_ver = atoi(ctx->config[SSL_PROTOCOL_VERSION]);
12036 SSL_CTX_set_options(ctx->ssl_ctx, ssl_get_protocol(protocol_ver));
12037 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE);
12038 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
12039 SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1);
12040
12041 /* If a callback has been specified, call it. */
12042 callback_ret =
12043 (ctx->callbacks.init_ssl == NULL)
12044 ? 0
12045 : (ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data));
12046
12047 /* If callback returns 0, civetweb sets up the SSL certificate.
12048 * If it returns 1, civetweb assumes the calback already did this.
12049 * If it returns -1, initializing ssl fails. */
12050 if (callback_ret < 0) {
12051 mg_cry(fc(ctx), "SSL callback returned error: %i", callback_ret);
12052 return 0;
12053 }
12054 if (callback_ret > 0) {
12055 if (pem != NULL) {
12056 (void)SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
12057 }
12058 return 1;
12059 }
12060
12061 /* Use some UID as session context ID. */
12062 md5_init(&md5state);
12063 md5_append(&md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt));
12064 clock_gettime(CLOCK_MONOTONIC, &now_mt);
12065 md5_append(&md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt));
12066 md5_append(&md5state,
12067 (const md5_byte_t *)ctx->config[LISTENING_PORTS],
12068 strlen(ctx->config[LISTENING_PORTS]));
12069 md5_append(&md5state, (const md5_byte_t *)ctx, sizeof(*ctx));
12070 md5_finish(&md5state, ssl_context_id);
12071
12072 SSL_CTX_set_session_id_context(ctx->ssl_ctx,
12073 (const unsigned char *)&ssl_context_id,
12074 sizeof(ssl_context_id));
12075
12076 if (pem != NULL) {
12077 if (!ssl_use_pem_file(ctx, pem)) {
12078 return 0;
12079 }
12080 }
12081
12082 should_verify_peer =
12083 (ctx->config[SSL_DO_VERIFY_PEER] != NULL)
12084 && (mg_strcasecmp(ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0);
12085
12086 use_default_verify_paths =
12087 (ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
12088 && (mg_strcasecmp(ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes") == 0);
12089
12090 if (should_verify_peer) {
12091 ca_path = ctx->config[SSL_CA_PATH];
12092 ca_file = ctx->config[SSL_CA_FILE];
12093 if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, ca_file, ca_path)
12094 != 1) {
12095 mg_cry(fc(ctx),
12096 "SSL_CTX_load_verify_locations error: %s "
12097 "ssl_verify_peer requires setting "
12098 "either ssl_ca_path or ssl_ca_file. Is any of them "
12099 "present in "
12100 "the .conf file?",
12101 ssl_error());
12102 return 0;
12103 }
12104
12105 SSL_CTX_set_verify(ctx->ssl_ctx,
12106 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
12107 NULL);
12108
12109 if (use_default_verify_paths
12110 && SSL_CTX_set_default_verify_paths(ctx->ssl_ctx) != 1) {
12111 mg_cry(fc(ctx),
12112 "SSL_CTX_set_default_verify_paths error: %s",
12113 ssl_error());
12114 return 0;
12115 }
12116
12117 if (ctx->config[SSL_VERIFY_DEPTH]) {
12118 verify_depth = atoi(ctx->config[SSL_VERIFY_DEPTH]);
12119 SSL_CTX_set_verify_depth(ctx->ssl_ctx, verify_depth);
12120 }
12121 }
12122
12123 if (ctx->config[SSL_CIPHER_LIST] != NULL) {
12124 if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config[SSL_CIPHER_LIST])
12125 != 1) {
12126 mg_cry(fc(ctx), "SSL_CTX_set_cipher_list error: %s", ssl_error());
12127 }
12128 }
12129
12130 return 1;
12131 }
12132
12133
12134 static void
12135 uninitialize_ssl(struct mg_context *ctx)
12136 {
12137 int i;
12138 (void)ctx;
12139
12140 if (mg_atomic_dec(&cryptolib_users) == 0) {
12141
12142 /* Shutdown according to
12143 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
12144 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
12145 */
12146 CRYPTO_set_locking_callback(NULL);
12147 CRYPTO_set_id_callback(NULL);
12148 ENGINE_cleanup();
12149 CONF_modules_unload(1);
12150 ERR_free_strings();
12151 EVP_cleanup();
12152 CRYPTO_cleanup_all_ex_data();
12153 ERR_remove_state(0);
12154
12155 for (i = 0; i < CRYPTO_num_locks(); i++) {
12156 pthread_mutex_destroy(&ssl_mutexes[i]);
12157 }
12158 mg_free(ssl_mutexes);
12159 ssl_mutexes = NULL;
12160 }
12161 }
12162 #endif /* !NO_SSL */
12163
12164
12165 static int
12166 set_gpass_option(struct mg_context *ctx)
12167 {
12168 if (ctx) {
12169 struct mg_file file = STRUCT_FILE_INITIALIZER;
12170 const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
12171 if (path != NULL && !mg_stat(fc(ctx), path, &file.stat)) {
12172 mg_cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
12173 return 0;
12174 }
12175 return 1;
12176 }
12177 return 0;
12178 }
12179
12180
12181 static int
12182 set_acl_option(struct mg_context *ctx)
12183 {
12184 return check_acl(ctx, (uint32_t)0x7f000001UL) != -1;
12185 }
12186
12187
12188 static void
12189 reset_per_request_attributes(struct mg_connection *conn)
12190 {
12191 if (!conn) {
12192 return;
12193 }
12194 conn->path_info = NULL;
12195 conn->num_bytes_sent = conn->consumed_content = 0;
12196 conn->status_code = -1;
12197 conn->is_chunked = 0;
12198 conn->must_close = conn->request_len = conn->throttle = 0;
12199 conn->request_info.content_length = -1;
12200 conn->request_info.remote_user = NULL;
12201 conn->request_info.request_method = NULL;
12202 conn->request_info.request_uri = NULL;
12203 conn->request_info.local_uri = NULL;
12204 conn->request_info.uri = NULL; /* TODO: cleanup uri,
12205 * local_uri and request_uri */
12206 conn->request_info.http_version = NULL;
12207 conn->request_info.num_headers = 0;
12208 conn->data_len = 0;
12209 conn->chunk_remainder = 0;
12210 }
12211
12212
12213 #if 0
12214 /* Note: set_sock_timeout is not required for non-blocking sockets.
12215 * Leave this function here (commented out) for reference until
12216 * CivetWeb 1.9 is tested, and the tests confirme this function is
12217 * no longer required.
12218 */
12219 static int
12220 set_sock_timeout(SOCKET sock, int milliseconds)
12221 {
12222 int r0 = 0, r1, r2;
12223
12224 #ifdef _WIN32
12225 /* Windows specific */
12226
12227 DWORD tv = (DWORD)milliseconds;
12228
12229 #else
12230 /* Linux, ... (not Windows) */
12231
12232 struct timeval tv;
12233
12234 /* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
12235 * max. time waiting for the acknowledged of TCP data before the connection
12236 * will be forcefully closed and ETIMEDOUT is returned to the application.
12237 * If this option is not set, the default timeout of 20-30 minutes is used.
12238 */
12239 /* #define TCP_USER_TIMEOUT (18) */
12240
12241 #if defined(TCP_USER_TIMEOUT)
12242 unsigned int uto = (unsigned int)milliseconds;
12243 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (const void *)&uto, sizeof(uto));
12244 #endif
12245
12246 memset(&tv, 0, sizeof(tv));
12247 tv.tv_sec = milliseconds / 1000;
12248 tv.tv_usec = (milliseconds * 1000) % 1000000;
12249
12250 #endif /* _WIN32 */
12251
12252 r1 = setsockopt(
12253 sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
12254 r2 = setsockopt(
12255 sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
12256
12257 return r0 || r1 || r2;
12258 }
12259 #endif
12260
12261
12262 static int
12263 set_tcp_nodelay(SOCKET sock, int nodelay_on)
12264 {
12265 if (setsockopt(sock,
12266 IPPROTO_TCP,
12267 TCP_NODELAY,
12268 (SOCK_OPT_TYPE)&nodelay_on,
12269 sizeof(nodelay_on)) != 0) {
12270 /* Error */
12271 return 1;
12272 }
12273 /* OK */
12274 return 0;
12275 }
12276
12277
12278 static void
12279 close_socket_gracefully(struct mg_connection *conn)
12280 {
12281 #if defined(_WIN32)
12282 char buf[MG_BUF_LEN];
12283 int n;
12284 #endif
12285 struct linger linger;
12286 int error_code = 0;
12287 socklen_t opt_len = sizeof(error_code);
12288
12289 if (!conn) {
12290 return;
12291 }
12292
12293 /* http://msdn.microsoft.com/en-us/library/ms739165(v=vs.85).aspx:
12294 * "Note that enabling a nonzero timeout on a nonblocking socket
12295 * is not recommended.", so set it to blocking now */
12296 set_blocking_mode(conn->client.sock, 1);
12297
12298 /* Send FIN to the client */
12299 shutdown(conn->client.sock, SHUTDOWN_WR);
12300
12301
12302 #if defined(_WIN32)
12303 /* Read and discard pending incoming data. If we do not do that and
12304 * close
12305 * the socket, the data in the send buffer may be discarded. This
12306 * behaviour is seen on Windows, when client keeps sending data
12307 * when server decides to close the connection; then when client
12308 * does recv() it gets no data back. */
12309 do {
12310 n = pull(NULL, conn, buf, sizeof(buf), /* Timeout in s: */ 1.0);
12311 } while (n > 0);
12312 #endif
12313
12314 /* Set linger option to avoid socket hanging out after close. This
12315 * prevent ephemeral port exhaust problem under high QPS. */
12316 linger.l_onoff = 1;
12317 linger.l_linger = 1;
12318
12319 if (getsockopt(conn->client.sock,
12320 SOL_SOCKET,
12321 SO_ERROR,
12322 (char *)&error_code,
12323 &opt_len) != 0) {
12324 /* Cannot determine if socket is already closed. This should
12325 * not occur and never did in a test. Log an error message
12326 * and continue. */
12327 mg_cry(conn,
12328 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
12329 __func__,
12330 strerror(ERRNO));
12331 } else if (error_code == ECONNRESET) {
12332 /* Socket already closed by client/peer, close socket without linger */
12333 } else {
12334
12335
12336 /* Set linger timeout */
12337 if (setsockopt(conn->client.sock,
12338 SOL_SOCKET,
12339 SO_LINGER,
12340 (char *)&linger,
12341 sizeof(linger)) != 0) {
12342 mg_cry(conn,
12343 "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
12344 __func__,
12345 strerror(ERRNO));
12346 }
12347 }
12348
12349 /* Now we know that our FIN is ACK-ed, safe to close */
12350 closesocket(conn->client.sock);
12351 conn->client.sock = INVALID_SOCKET;
12352 }
12353
12354
12355 static void
12356 close_connection(struct mg_connection *conn)
12357 {
12358 if (!conn || !conn->ctx) {
12359 return;
12360 }
12361
12362 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
12363 if (conn->lua_websocket_state) {
12364 lua_websocket_close(conn, conn->lua_websocket_state);
12365 conn->lua_websocket_state = NULL;
12366 }
12367 #endif
12368
12369 /* call the connection_close callback if assigned */
12370 if ((conn->ctx->callbacks.connection_close != NULL)
12371 && (conn->ctx->context_type == 1)) {
12372 conn->ctx->callbacks.connection_close(conn);
12373 }
12374
12375 mg_lock_connection(conn);
12376
12377 conn->must_close = 1;
12378
12379 #ifndef NO_SSL
12380 if (conn->ssl != NULL) {
12381 /* Run SSL_shutdown twice to ensure completly close SSL connection
12382 */
12383 SSL_shutdown(conn->ssl);
12384 SSL_free(conn->ssl);
12385 /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion:
12386 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
12387 ERR_remove_state(0);
12388 conn->ssl = NULL;
12389 }
12390 #endif
12391 if (conn->client.sock != INVALID_SOCKET) {
12392 close_socket_gracefully(conn);
12393 conn->client.sock = INVALID_SOCKET;
12394 }
12395
12396 mg_unlock_connection(conn);
12397 }
12398
12399
12400 void
12401 mg_close_connection(struct mg_connection *conn)
12402 {
12403 struct mg_context *client_ctx = NULL;
12404
12405 if (conn == NULL) {
12406 return;
12407 }
12408
12409 #if defined(USE_WEBSOCKET)
12410 if (conn->ctx->context_type == 2) {
12411 unsigned int i;
12412
12413 /* ws/wss client */
12414 client_ctx = conn->ctx;
12415
12416 /* client context: loops must end */
12417 conn->ctx->stop_flag = 1;
12418
12419 /* We need to get the client thread out of the select/recv call here. */
12420 /* Since we use a sleep quantum of some seconds to check for recv
12421 * timeouts, we will just wait a few seconds in mg_join_thread. */
12422
12423 /* join worker thread */
12424 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
12425 if (client_ctx->workerthreadids[i] != 0) {
12426 mg_join_thread(client_ctx->workerthreadids[i]);
12427 }
12428 }
12429 }
12430 #else
12431 (void)client_ctx;
12432 #endif
12433
12434 close_connection(conn);
12435
12436 #ifndef NO_SSL
12437 if (conn->client_ssl_ctx != NULL) {
12438 SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx);
12439 }
12440 #endif
12441
12442 if (client_ctx != NULL) {
12443 /* free context */
12444 mg_free(client_ctx->workerthreadids);
12445 mg_free(client_ctx);
12446 (void)pthread_mutex_destroy(&conn->mutex);
12447 mg_free(conn);
12448 }
12449 }
12450
12451
12452 static struct mg_connection *
12453 mg_connect_client_impl(const struct mg_client_options *client_options,
12454 int use_ssl,
12455 char *ebuf,
12456 size_t ebuf_len)
12457 {
12458 static struct mg_context fake_ctx;
12459 struct mg_connection *conn = NULL;
12460 SOCKET sock;
12461 union usa sa;
12462
12463 if (!connect_socket(&fake_ctx,
12464 client_options->host,
12465 client_options->port,
12466 use_ssl,
12467 ebuf,
12468 ebuf_len,
12469 &sock,
12470 &sa)) {
12471 ;
12472 } else if ((conn = (struct mg_connection *)
12473 mg_calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
12474 mg_snprintf(NULL,
12475 NULL, /* No truncation check for ebuf */
12476 ebuf,
12477 ebuf_len,
12478 "calloc(): %s",
12479 strerror(ERRNO));
12480 closesocket(sock);
12481 #ifndef NO_SSL
12482 } else if (use_ssl
12483 && (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
12484 == NULL) {
12485 mg_snprintf(NULL,
12486 NULL, /* No truncation check for ebuf */
12487 ebuf,
12488 ebuf_len,
12489 "SSL_CTX_new error");
12490 closesocket(sock);
12491 mg_free(conn);
12492 conn = NULL;
12493 #endif /* NO_SSL */
12494
12495 } else {
12496
12497 #ifdef USE_IPV6
12498 socklen_t len = (sa.sa.sa_family == AF_INET)
12499 ? sizeof(conn->client.rsa.sin)
12500 : sizeof(conn->client.rsa.sin6);
12501 struct sockaddr *psa =
12502 (sa.sa.sa_family == AF_INET)
12503 ? (struct sockaddr *)&(conn->client.rsa.sin)
12504 : (struct sockaddr *)&(conn->client.rsa.sin6);
12505 #else
12506 socklen_t len = sizeof(conn->client.rsa.sin);
12507 struct sockaddr *psa = (struct sockaddr *)&(conn->client.rsa.sin);
12508 #endif
12509
12510 conn->buf_size = MAX_REQUEST_SIZE;
12511 conn->buf = (char *)(conn + 1);
12512 conn->ctx = &fake_ctx;
12513 conn->client.sock = sock;
12514 conn->client.lsa = sa;
12515
12516 if (getsockname(sock, psa, &len) != 0) {
12517 mg_cry(conn,
12518 "%s: getsockname() failed: %s",
12519 __func__,
12520 strerror(ERRNO));
12521 }
12522
12523 conn->client.is_ssl = use_ssl ? 1 : 0;
12524 (void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
12525
12526 #ifndef NO_SSL
12527 if (use_ssl) {
12528 fake_ctx.ssl_ctx = conn->client_ssl_ctx;
12529
12530 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
12531 * SSL_CTX_set_verify call is needed to switch off server
12532 * certificate checking, which is off by default in OpenSSL and
12533 * on in yaSSL. */
12534 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
12535 * SSL_VERIFY_PEER, verify_ssl_server); */
12536
12537 if (client_options->client_cert) {
12538 if (!ssl_use_pem_file(&fake_ctx, client_options->client_cert)) {
12539 mg_snprintf(NULL,
12540 NULL, /* No truncation check for ebuf */
12541 ebuf,
12542 ebuf_len,
12543 "Can not use SSL client certificate");
12544 SSL_CTX_free(conn->client_ssl_ctx);
12545 closesocket(sock);
12546 mg_free(conn);
12547 conn = NULL;
12548 }
12549 }
12550
12551 if (client_options->server_cert) {
12552 SSL_CTX_load_verify_locations(conn->client_ssl_ctx,
12553 client_options->server_cert,
12554 NULL);
12555 SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_PEER, NULL);
12556 } else {
12557 SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_NONE, NULL);
12558 }
12559
12560 if (!sslize(conn,
12561 conn->client_ssl_ctx,
12562 SSL_connect,
12563 &(conn->ctx->stop_flag))) {
12564 mg_snprintf(NULL,
12565 NULL, /* No truncation check for ebuf */
12566 ebuf,
12567 ebuf_len,
12568 "SSL connection error");
12569 SSL_CTX_free(conn->client_ssl_ctx);
12570 closesocket(sock);
12571 mg_free(conn);
12572 conn = NULL;
12573 }
12574 }
12575 #endif
12576 }
12577
12578 if (conn) {
12579 set_blocking_mode(sock, 0);
12580 }
12581
12582 return conn;
12583 }
12584
12585
12586 CIVETWEB_API struct mg_connection *
12587 mg_connect_client_secure(const struct mg_client_options *client_options,
12588 char *error_buffer,
12589 size_t error_buffer_size)
12590 {
12591 return mg_connect_client_impl(client_options,
12592 1,
12593 error_buffer,
12594 error_buffer_size);
12595 }
12596
12597
12598 struct mg_connection *
12599 mg_connect_client(const char *host,
12600 int port,
12601 int use_ssl,
12602 char *error_buffer,
12603 size_t error_buffer_size)
12604 {
12605 struct mg_client_options opts;
12606 memset(&opts, 0, sizeof(opts));
12607 opts.host = host;
12608 opts.port = port;
12609 return mg_connect_client_impl(&opts,
12610 use_ssl,
12611 error_buffer,
12612 error_buffer_size);
12613 }
12614
12615
12616 static const struct {
12617 const char *proto;
12618 size_t proto_len;
12619 unsigned default_port;
12620 } abs_uri_protocols[] = {{"http://", 7, 80},
12621 {"https://", 8, 443},
12622 {"ws://", 5, 80},
12623 {"wss://", 6, 443},
12624 {NULL, 0, 0}};
12625
12626
12627 /* Check if the uri is valid.
12628 * return 0 for invalid uri,
12629 * return 1 for *,
12630 * return 2 for relative uri,
12631 * return 3 for absolute uri without port,
12632 * return 4 for absolute uri with port */
12633 static int
12634 get_uri_type(const char *uri)
12635 {
12636 int i;
12637 char *hostend, *portbegin, *portend;
12638 unsigned long port;
12639
12640 /* According to the HTTP standard
12641 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
12642 * URI can be an asterisk (*) or should start with slash (relative uri),
12643 * or it should start with the protocol (absolute uri). */
12644 if (uri[0] == '*' && uri[1] == '\0') {
12645 /* asterisk */
12646 return 1;
12647 }
12648
12649 /* Valid URIs according to RFC 3986
12650 * (https://www.ietf.org/rfc/rfc3986.txt)
12651 * must only contain reserved characters :/?#[]@!$&'()*+,;=
12652 * and unreserved characters A-Z a-z 0-9 and -._~
12653 * and % encoded symbols.
12654 */
12655 for (i = 0; uri[i] != 0; i++) {
12656 if (uri[i] < 33) {
12657 /* control characters and spaces are invalid */
12658 return 0;
12659 }
12660 if (uri[i] > 126) {
12661 /* non-ascii characters must be % encoded */
12662 return 0;
12663 } else {
12664 switch (uri[i]) {
12665 case '"': /* 34 */
12666 case '<': /* 60 */
12667 case '>': /* 62 */
12668 case '\\': /* 92 */
12669 case '^': /* 94 */
12670 case '`': /* 96 */
12671 case '{': /* 123 */
12672 case '|': /* 124 */
12673 case '}': /* 125 */
12674 return 0;
12675 default:
12676 /* character is ok */
12677 break;
12678 }
12679 }
12680 }
12681
12682 /* A relative uri starts with a / character */
12683 if (uri[0] == '/') {
12684 /* relative uri */
12685 return 2;
12686 }
12687
12688 /* It could be an absolute uri: */
12689 /* This function only checks if the uri is valid, not if it is
12690 * addressing the current server. So civetweb can also be used
12691 * as a proxy server. */
12692 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
12693 if (mg_strncasecmp(uri,
12694 abs_uri_protocols[i].proto,
12695 abs_uri_protocols[i].proto_len) == 0) {
12696
12697 hostend = strchr(uri + abs_uri_protocols[i].proto_len, '/');
12698 if (!hostend) {
12699 return 0;
12700 }
12701 portbegin = strchr(uri + abs_uri_protocols[i].proto_len, ':');
12702 if (!portbegin) {
12703 return 3;
12704 }
12705
12706 port = strtoul(portbegin + 1, &portend, 10);
12707 if ((portend != hostend) || !port || !is_valid_port(port)) {
12708 return 0;
12709 }
12710
12711 return 4;
12712 }
12713 }
12714
12715 return 0;
12716 }
12717
12718
12719 /* Return NULL or the relative uri at the current server */
12720 static const char *
12721 get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
12722 {
12723 const char *server_domain;
12724 size_t server_domain_len;
12725 size_t request_domain_len = 0;
12726 unsigned long port = 0;
12727 int i;
12728 const char *hostbegin = NULL;
12729 const char *hostend = NULL;
12730 const char *portbegin;
12731 char *portend;
12732
12733 /* DNS is case insensitive, so use case insensitive string compare here
12734 */
12735 server_domain = conn->ctx->config[AUTHENTICATION_DOMAIN];
12736 if (!server_domain) {
12737 return 0;
12738 }
12739 server_domain_len = strlen(server_domain);
12740 if (!server_domain_len) {
12741 return 0;
12742 }
12743
12744 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
12745 if (mg_strncasecmp(uri,
12746 abs_uri_protocols[i].proto,
12747 abs_uri_protocols[i].proto_len) == 0) {
12748
12749 hostbegin = uri + abs_uri_protocols[i].proto_len;
12750 hostend = strchr(hostbegin, '/');
12751 if (!hostend) {
12752 return 0;
12753 }
12754 portbegin = strchr(hostbegin, ':');
12755 if ((!portbegin) || (portbegin > hostend)) {
12756 port = abs_uri_protocols[i].default_port;
12757 request_domain_len = (size_t)(hostend - hostbegin);
12758 } else {
12759 port = strtoul(portbegin + 1, &portend, 10);
12760 if ((portend != hostend) || !port || !is_valid_port(port)) {
12761 return 0;
12762 }
12763 request_domain_len = (size_t)(portbegin - hostbegin);
12764 }
12765 /* protocol found, port set */
12766 break;
12767 }
12768 }
12769
12770 if (!port) {
12771 /* port remains 0 if the protocol is not found */
12772 return 0;
12773 }
12774
12775 /* Check if the request is directed to a different server. */
12776 /* First check if the port is the same (IPv4 and IPv6). */
12777 #if defined(USE_IPV6)
12778 if (conn->client.lsa.sa.sa_family == AF_INET6) {
12779 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
12780 /* Request is directed to a different port */
12781 return 0;
12782 }
12783 } else
12784 #endif
12785 {
12786 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
12787 /* Request is directed to a different port */
12788 return 0;
12789 }
12790 }
12791
12792 /* Finally check if the server corresponds to the authentication
12793 * domain of the server (the server domain).
12794 * Allow full matches (like http://mydomain.com/path/file.ext), and
12795 * allow subdomain matches (like http://www.mydomain.com/path/file.ext),
12796 * but do not allow substrings (like http://notmydomain.com/path/file.ext
12797 * or http://mydomain.com.fake/path/file.ext).
12798 */
12799 if ((request_domain_len == server_domain_len)
12800 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
12801 /* Request is directed to this server - full name match. */
12802 } else {
12803 if (request_domain_len < (server_domain_len + 2)) {
12804 /* Request is directed to another server: The server name is longer
12805 * than
12806 * the request name. Drop this case here to avoid overflows in the
12807 * following checks. */
12808 return 0;
12809 }
12810 if (hostbegin[request_domain_len - server_domain_len - 1] != '.') {
12811 /* Request is directed to another server: It could be a substring
12812 * like notmyserver.com */
12813 return 0;
12814 }
12815 if (0 != memcmp(server_domain,
12816 hostbegin + request_domain_len - server_domain_len,
12817 server_domain_len)) {
12818 /* Request is directed to another server:
12819 * The server name is different. */
12820 return 0;
12821 }
12822 }
12823
12824 return hostend;
12825 }
12826
12827
12828 static int
12829 getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
12830 {
12831 const char *cl;
12832
12833 if (ebuf_len > 0) {
12834 ebuf[0] = '\0';
12835 }
12836 *err = 0;
12837
12838 reset_per_request_attributes(conn);
12839
12840 if (!conn) {
12841 mg_snprintf(conn,
12842 NULL, /* No truncation check for ebuf */
12843 ebuf,
12844 ebuf_len,
12845 "%s",
12846 "Internal error");
12847 *err = 500;
12848 return 0;
12849 }
12850 /* Set the time the request was received. This value should be used for
12851 * timeouts. */
12852 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
12853
12854 conn->request_len =
12855 read_request(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
12856 /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
12857 */
12858 if (conn->request_len >= 0 && conn->data_len < conn->request_len) {
12859 mg_snprintf(conn,
12860 NULL, /* No truncation check for ebuf */
12861 ebuf,
12862 ebuf_len,
12863 "%s",
12864 "Invalid request size");
12865 *err = 500;
12866 return 0;
12867 }
12868
12869 if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
12870 mg_snprintf(conn,
12871 NULL, /* No truncation check for ebuf */
12872 ebuf,
12873 ebuf_len,
12874 "%s",
12875 "Request Too Large");
12876 *err = 413;
12877 return 0;
12878 } else if (conn->request_len <= 0) {
12879 if (conn->data_len > 0) {
12880 mg_snprintf(conn,
12881 NULL, /* No truncation check for ebuf */
12882 ebuf,
12883 ebuf_len,
12884 "%s",
12885 "Client sent malformed request");
12886 *err = 400;
12887 } else {
12888 /* Server did not recv anything -> just close the connection */
12889 conn->must_close = 1;
12890 mg_snprintf(conn,
12891 NULL, /* No truncation check for ebuf */
12892 ebuf,
12893 ebuf_len,
12894 "%s",
12895 "Client did not send a request");
12896 *err = 0;
12897 }
12898 return 0;
12899 } else if (parse_http_message(conn->buf,
12900 conn->buf_size,
12901 &conn->request_info) <= 0) {
12902 mg_snprintf(conn,
12903 NULL, /* No truncation check for ebuf */
12904 ebuf,
12905 ebuf_len,
12906 "%s",
12907 "Bad Request");
12908 *err = 400;
12909 return 0;
12910 } else {
12911 /* Message is a valid request or response */
12912 if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
12913 /* Request/response has content length set */
12914 char *endptr = NULL;
12915 conn->content_len = strtoll(cl, &endptr, 10);
12916 if (endptr == cl) {
12917 mg_snprintf(conn,
12918 NULL, /* No truncation check for ebuf */
12919 ebuf,
12920 ebuf_len,
12921 "%s",
12922 "Bad Request");
12923 *err = 411;
12924 return 0;
12925 }
12926 /* Publish the content length back to the request info. */
12927 conn->request_info.content_length = conn->content_len;
12928 } else if ((cl = get_header(&conn->request_info, "Transfer-Encoding"))
12929 != NULL
12930 && !mg_strcasecmp(cl, "chunked")) {
12931 conn->is_chunked = 1;
12932 } else if (!mg_strcasecmp(conn->request_info.request_method, "POST")
12933 || !mg_strcasecmp(conn->request_info.request_method,
12934 "PUT")) {
12935 /* POST or PUT request without content length set */
12936 conn->content_len = -1;
12937 } else if (!mg_strncasecmp(conn->request_info.request_method,
12938 "HTTP/",
12939 5)) {
12940 /* Response without content length set */
12941 conn->content_len = -1;
12942 } else {
12943 /* Other request */
12944 conn->content_len = 0;
12945 }
12946 }
12947 return 1;
12948 }
12949
12950
12951 int
12952 mg_get_response(struct mg_connection *conn,
12953 char *ebuf,
12954 size_t ebuf_len,
12955 int timeout)
12956 {
12957 if (conn) {
12958 /* Implementation of API function for HTTP clients */
12959 int err, ret;
12960 struct mg_context *octx = conn->ctx;
12961 struct mg_context rctx = *(conn->ctx);
12962 char txt[32]; /* will not overflow */
12963
12964 if (timeout >= 0) {
12965 mg_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout);
12966 rctx.config[REQUEST_TIMEOUT] = txt;
12967 /* Not required for non-blocking sockets.
12968 set_sock_timeout(conn->client.sock, timeout);
12969 */
12970 } else {
12971 rctx.config[REQUEST_TIMEOUT] = NULL;
12972 }
12973
12974 conn->ctx = &rctx;
12975 ret = getreq(conn, ebuf, ebuf_len, &err);
12976 conn->ctx = octx;
12977
12978 /* TODO: 1) uri is deprecated;
12979 * 2) here, ri.uri is the http response code */
12980 conn->request_info.uri = conn->request_info.request_uri;
12981
12982 /* TODO (mid): Define proper return values - maybe return length?
12983 * For the first test use <0 for error and >0 for OK */
12984 return (ret == 0) ? -1 : +1;
12985 }
12986 return -1;
12987 }
12988
12989
12990 struct mg_connection *
12991 mg_download(const char *host,
12992 int port,
12993 int use_ssl,
12994 char *ebuf,
12995 size_t ebuf_len,
12996 const char *fmt,
12997 ...)
12998 {
12999 struct mg_connection *conn;
13000 va_list ap;
13001 int i;
13002 int reqerr;
13003
13004 va_start(ap, fmt);
13005 ebuf[0] = '\0';
13006
13007 /* open a connection */
13008 conn = mg_connect_client(host, port, use_ssl, ebuf, ebuf_len);
13009
13010 if (conn != NULL) {
13011 i = mg_vprintf(conn, fmt, ap);
13012 if (i <= 0) {
13013 mg_snprintf(conn,
13014 NULL, /* No truncation check for ebuf */
13015 ebuf,
13016 ebuf_len,
13017 "%s",
13018 "Error sending request");
13019 } else {
13020 getreq(conn, ebuf, ebuf_len, &reqerr);
13021
13022 /* TODO: 1) uri is deprecated;
13023 * 2) here, ri.uri is the http response code */
13024 conn->request_info.uri = conn->request_info.request_uri;
13025 }
13026 }
13027
13028 /* if an error occured, close the connection */
13029 if (ebuf[0] != '\0' && conn != NULL) {
13030 mg_close_connection(conn);
13031 conn = NULL;
13032 }
13033
13034 va_end(ap);
13035 return conn;
13036 }
13037
13038
13039 struct websocket_client_thread_data {
13040 struct mg_connection *conn;
13041 mg_websocket_data_handler data_handler;
13042 mg_websocket_close_handler close_handler;
13043 void *callback_data;
13044 };
13045
13046
13047 #if defined(USE_WEBSOCKET)
13048 #ifdef _WIN32
13049 static unsigned __stdcall websocket_client_thread(void *data)
13050 #else
13051 static void *
13052 websocket_client_thread(void *data)
13053 #endif
13054 {
13055 struct websocket_client_thread_data *cdata =
13056 (struct websocket_client_thread_data *)data;
13057
13058 mg_set_thread_name("ws-clnt");
13059
13060 if (cdata->conn->ctx) {
13061 if (cdata->conn->ctx->callbacks.init_thread) {
13062 /* 3 indicates a websocket client thread */
13063 /* TODO: check if conn->ctx can be set */
13064 cdata->conn->ctx->callbacks.init_thread(cdata->conn->ctx, 3);
13065 }
13066 }
13067
13068 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
13069
13070 DEBUG_TRACE("%s", "Websocket client thread exited\n");
13071
13072 if (cdata->close_handler != NULL) {
13073 cdata->close_handler(cdata->conn, cdata->callback_data);
13074 }
13075
13076 /* The websocket_client context has only this thread. If it runs out,
13077 set the stop_flag to 2 (= "stopped"). */
13078 cdata->conn->ctx->stop_flag = 2;
13079
13080 mg_free((void *)cdata);
13081
13082 #ifdef _WIN32
13083 return 0;
13084 #else
13085 return NULL;
13086 #endif
13087 }
13088 #endif
13089
13090
13091 struct mg_connection *
13092 mg_connect_websocket_client(const char *host,
13093 int port,
13094 int use_ssl,
13095 char *error_buffer,
13096 size_t error_buffer_size,
13097 const char *path,
13098 const char *origin,
13099 mg_websocket_data_handler data_func,
13100 mg_websocket_close_handler close_func,
13101 void *user_data)
13102 {
13103 struct mg_connection *conn = NULL;
13104
13105 #if defined(USE_WEBSOCKET)
13106 struct mg_context *newctx = NULL;
13107 struct websocket_client_thread_data *thread_data;
13108 static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
13109 static const char *handshake_req;
13110
13111 if (origin != NULL) {
13112 handshake_req = "GET %s HTTP/1.1\r\n"
13113 "Host: %s\r\n"
13114 "Upgrade: websocket\r\n"
13115 "Connection: Upgrade\r\n"
13116 "Sec-WebSocket-Key: %s\r\n"
13117 "Sec-WebSocket-Version: 13\r\n"
13118 "Origin: %s\r\n"
13119 "\r\n";
13120 } else {
13121 handshake_req = "GET %s HTTP/1.1\r\n"
13122 "Host: %s\r\n"
13123 "Upgrade: websocket\r\n"
13124 "Connection: Upgrade\r\n"
13125 "Sec-WebSocket-Key: %s\r\n"
13126 "Sec-WebSocket-Version: 13\r\n"
13127 "\r\n";
13128 }
13129
13130 /* Establish the client connection and request upgrade */
13131 conn = mg_download(host,
13132 port,
13133 use_ssl,
13134 error_buffer,
13135 error_buffer_size,
13136 handshake_req,
13137 path,
13138 host,
13139 magic,
13140 origin);
13141
13142 /* Connection object will be null if something goes wrong */
13143 if (conn == NULL || (strcmp(conn->request_info.request_uri, "101") != 0)) {
13144 if (!*error_buffer) {
13145 /* if there is a connection, but it did not return 101,
13146 * error_buffer is not yet set */
13147 mg_snprintf(conn,
13148 NULL, /* No truncation check for ebuf */
13149 error_buffer,
13150 error_buffer_size,
13151 "Unexpected server reply");
13152 }
13153 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
13154 if (conn != NULL) {
13155 mg_free(conn);
13156 conn = NULL;
13157 }
13158 return conn;
13159 }
13160
13161 /* For client connections, mg_context is fake. Since we need to set a
13162 * callback function, we need to create a copy and modify it. */
13163 newctx = (struct mg_context *)mg_malloc(sizeof(struct mg_context));
13164 memcpy(newctx, conn->ctx, sizeof(struct mg_context));
13165 newctx->user_data = user_data;
13166 newctx->context_type = 2; /* ws/wss client context type */
13167 newctx->cfg_worker_threads = 1; /* one worker thread will be created */
13168 newctx->workerthreadids =
13169 (pthread_t *)mg_calloc(newctx->cfg_worker_threads, sizeof(pthread_t));
13170 conn->ctx = newctx;
13171 thread_data = (struct websocket_client_thread_data *)
13172 mg_calloc(sizeof(struct websocket_client_thread_data), 1);
13173 thread_data->conn = conn;
13174 thread_data->data_handler = data_func;
13175 thread_data->close_handler = close_func;
13176 thread_data->callback_data = NULL;
13177
13178 /* Start a thread to read the websocket client connection
13179 * This thread will automatically stop when mg_disconnect is
13180 * called on the client connection */
13181 if (mg_start_thread_with_id(websocket_client_thread,
13182 (void *)thread_data,
13183 newctx->workerthreadids) != 0) {
13184 mg_free((void *)thread_data);
13185 mg_free((void *)newctx->workerthreadids);
13186 mg_free((void *)newctx);
13187 mg_free((void *)conn);
13188 conn = NULL;
13189 DEBUG_TRACE("%s",
13190 "Websocket client connect thread could not be started\r\n");
13191 }
13192
13193 #else
13194 /* Appease "unused parameter" warnings */
13195 (void)host;
13196 (void)port;
13197 (void)use_ssl;
13198 (void)error_buffer;
13199 (void)error_buffer_size;
13200 (void)path;
13201 (void)origin;
13202 (void)user_data;
13203 (void)data_func;
13204 (void)close_func;
13205 #endif
13206
13207 return conn;
13208 }
13209
13210
13211 static void
13212 process_new_connection(struct mg_connection *conn)
13213 {
13214 if (conn && conn->ctx) {
13215 struct mg_request_info *ri = &conn->request_info;
13216 int keep_alive_enabled, keep_alive, discard_len;
13217 char ebuf[100];
13218 const char *hostend;
13219 int reqerr, uri_type;
13220
13221 keep_alive_enabled =
13222 !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
13223
13224 /* Important: on new connection, reset the receiving buffer. Credit
13225 * goes to crule42. */
13226 conn->data_len = 0;
13227 conn->handled_requests = 0;
13228 do {
13229
13230 DEBUG_TRACE("calling getreq (%i times for this connection)",
13231 conn->handled_requests + 1);
13232
13233 if (!getreq(conn, ebuf, sizeof(ebuf), &reqerr)) {
13234 /* The request sent by the client could not be understood by
13235 * the server, or it was incomplete or a timeout. Send an
13236 * error message and close the connection. */
13237 if (reqerr > 0) {
13238 /*assert(ebuf[0] != '\0');*/
13239 send_http_error(conn, reqerr, "%s", ebuf);
13240 }
13241 } else if (strcmp(ri->http_version, "1.0")
13242 && strcmp(ri->http_version, "1.1")) {
13243 mg_snprintf(conn,
13244 NULL, /* No truncation check for ebuf */
13245 ebuf,
13246 sizeof(ebuf),
13247 "Bad HTTP version: [%s]",
13248 ri->http_version);
13249 send_http_error(conn, 505, "%s", ebuf);
13250 }
13251
13252 if (ebuf[0] == '\0') {
13253 uri_type = get_uri_type(conn->request_info.request_uri);
13254 switch (uri_type) {
13255 case 1:
13256 /* Asterisk */
13257 conn->request_info.local_uri = NULL;
13258 break;
13259 case 2:
13260 /* relative uri */
13261 conn->request_info.local_uri =
13262 conn->request_info.request_uri;
13263 break;
13264 case 3:
13265 case 4:
13266 /* absolute uri (with/without port) */
13267 hostend = get_rel_url_at_current_server(
13268 conn->request_info.request_uri, conn);
13269 if (hostend) {
13270 conn->request_info.local_uri = hostend;
13271 } else {
13272 conn->request_info.local_uri = NULL;
13273 }
13274 break;
13275 default:
13276 mg_snprintf(conn,
13277 NULL, /* No truncation check for ebuf */
13278 ebuf,
13279 sizeof(ebuf),
13280 "Invalid URI");
13281 send_http_error(conn, 400, "%s", ebuf);
13282 conn->request_info.local_uri = NULL;
13283 break;
13284 }
13285
13286 /* TODO: cleanup uri, local_uri and request_uri */
13287 conn->request_info.uri = conn->request_info.local_uri;
13288 }
13289
13290 DEBUG_TRACE("http: %s, error: %s",
13291 (ri->http_version ? ri->http_version : "none"),
13292 (ebuf[0] ? ebuf : "none"));
13293
13294 if (ebuf[0] == '\0') {
13295 if (conn->request_info.local_uri) {
13296 /* handle request to local server */
13297 handle_request(conn);
13298 DEBUG_TRACE("%s", "handle_request done");
13299 if (conn->ctx->callbacks.end_request != NULL) {
13300 conn->ctx->callbacks.end_request(conn,
13301 conn->status_code);
13302 DEBUG_TRACE("%s", "end_request callback done");
13303 }
13304 log_access(conn);
13305 } else {
13306 /* TODO: handle non-local request (PROXY) */
13307 conn->must_close = 1;
13308 }
13309 } else {
13310 conn->must_close = 1;
13311 }
13312
13313 if (ri->remote_user != NULL) {
13314 mg_free((void *)ri->remote_user);
13315 /* Important! When having connections with and without auth
13316 * would cause double free and then crash */
13317 ri->remote_user = NULL;
13318 }
13319
13320 /* NOTE(lsm): order is important here. should_keep_alive() call
13321 * is
13322 * using parsed request, which will be invalid after memmove's
13323 * below.
13324 * Therefore, memorize should_keep_alive() result now for later
13325 * use
13326 * in loop exit condition. */
13327 keep_alive = (conn->ctx->stop_flag == 0) && keep_alive_enabled
13328 && (conn->content_len >= 0) && should_keep_alive(conn);
13329
13330
13331 /* Discard all buffered data for this request */
13332 discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
13333 && ((conn->request_len + conn->content_len)
13334 < (int64_t)conn->data_len))
13335 ? (int)(conn->request_len + conn->content_len)
13336 : conn->data_len;
13337 /*assert(discard_len >= 0);*/
13338 if (discard_len < 0) {
13339 DEBUG_TRACE("internal error: discard_len = %li",
13340 (long int)discard_len);
13341 break;
13342 }
13343 conn->data_len -= discard_len;
13344 if (conn->data_len > 0) {
13345 DEBUG_TRACE("discard_len = %lu", (long unsigned)discard_len);
13346 memmove(conn->buf,
13347 conn->buf + discard_len,
13348 (size_t)conn->data_len);
13349 }
13350
13351 /* assert(conn->data_len >= 0); */
13352 /* assert(conn->data_len <= conn->buf_size); */
13353
13354 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
13355 DEBUG_TRACE("internal error: data_len = %li, buf_size = %li",
13356 (long int)conn->data_len,
13357 (long int)conn->buf_size);
13358 break;
13359 }
13360
13361 conn->handled_requests++;
13362
13363 } while (keep_alive);
13364 }
13365 }
13366
13367
13368 #if defined(ALTERNATIVE_QUEUE)
13369
13370 static void
13371 produce_socket(struct mg_context *ctx, const struct socket *sp)
13372 {
13373 unsigned int i;
13374
13375 for (;;) {
13376 for (i = 0; i < ctx->cfg_worker_threads; i++) {
13377 /* find a free worker slot and signal it */
13378 if (ctx->client_socks[i].in_use == 0) {
13379 ctx->client_socks[i] = *sp;
13380 ctx->client_socks[i].in_use = 1;
13381 event_signal(ctx->client_wait_events[i]);
13382 return;
13383 }
13384 }
13385 /* queue is full */
13386 mg_sleep(1);
13387 }
13388 }
13389
13390
13391 static int
13392 consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
13393 {
13394 DEBUG_TRACE("%s", "going idle");
13395 ctx->client_socks[thread_index].in_use = 0;
13396 event_wait(ctx->client_wait_events[thread_index]);
13397 *sp = ctx->client_socks[thread_index];
13398 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
13399
13400 return !ctx->stop_flag;
13401 }
13402
13403 #else /* ALTERNATIVE_QUEUE */
13404
13405 /* Worker threads take accepted socket from the queue */
13406 static int
13407 consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
13408 {
13409 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
13410
13411 (void)thread_index;
13412
13413 (void)pthread_mutex_lock(&ctx->thread_mutex);
13414 DEBUG_TRACE("%s", "going idle");
13415
13416 /* If the queue is empty, wait. We're idle at this point. */
13417 while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
13418 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
13419 }
13420
13421 /* If we're stopping, sq_head may be equal to sq_tail. */
13422 if (ctx->sq_head > ctx->sq_tail) {
13423 /* Copy socket from the queue and increment tail */
13424 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
13425 ctx->sq_tail++;
13426
13427 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
13428
13429 /* Wrap pointers if needed */
13430 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
13431 ctx->sq_tail -= QUEUE_SIZE(ctx);
13432 ctx->sq_head -= QUEUE_SIZE(ctx);
13433 }
13434 }
13435
13436 (void)pthread_cond_signal(&ctx->sq_empty);
13437 (void)pthread_mutex_unlock(&ctx->thread_mutex);
13438
13439 return !ctx->stop_flag;
13440 #undef QUEUE_SIZE
13441 }
13442
13443
13444 /* Master thread adds accepted socket to a queue */
13445 static void
13446 produce_socket(struct mg_context *ctx, const struct socket *sp)
13447 {
13448 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
13449 if (!ctx) {
13450 return;
13451 }
13452 (void)pthread_mutex_lock(&ctx->thread_mutex);
13453
13454 /* If the queue is full, wait */
13455 while (ctx->stop_flag == 0
13456 && ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx)) {
13457 (void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
13458 }
13459
13460 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
13461 /* Copy socket to the queue and increment head */
13462 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
13463 ctx->sq_head++;
13464 DEBUG_TRACE("queued socket %d", sp ? sp->sock : -1);
13465 }
13466
13467 (void)pthread_cond_signal(&ctx->sq_full);
13468 (void)pthread_mutex_unlock(&ctx->thread_mutex);
13469 #undef QUEUE_SIZE
13470 }
13471 #endif /* ALTERNATIVE_QUEUE */
13472
13473
13474 struct worker_thread_args {
13475 struct mg_context *ctx;
13476 int index;
13477 };
13478
13479
13480 static void *
13481 worker_thread_run(struct worker_thread_args *thread_args)
13482 {
13483 struct mg_context *ctx = thread_args->ctx;
13484 struct mg_connection *conn;
13485 struct mg_workerTLS tls;
13486 #if defined(MG_LEGACY_INTERFACE)
13487 uint32_t addr;
13488 #endif
13489
13490 mg_set_thread_name("worker");
13491
13492 tls.is_master = 0;
13493 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
13494 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13495 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
13496 #endif
13497
13498 if (ctx->callbacks.init_thread) {
13499 /* call init_thread for a worker thread (type 1) */
13500 ctx->callbacks.init_thread(ctx, 1);
13501 }
13502
13503 conn =
13504 (struct mg_connection *)mg_calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
13505 if (conn == NULL) {
13506 mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
13507 } else {
13508 pthread_setspecific(sTlsKey, &tls);
13509 conn->buf_size = MAX_REQUEST_SIZE;
13510 conn->buf = (char *)(conn + 1);
13511 conn->ctx = ctx;
13512 conn->thread_index = thread_args->index;
13513 conn->request_info.user_data = ctx->user_data;
13514 /* Allocate a mutex for this connection to allow communication both
13515 * within the request handler and from elsewhere in the application
13516 */
13517 (void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
13518
13519 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
13520 * signal sq_empty condvar to wake up the master waiting in
13521 * produce_socket() */
13522 while (consume_socket(ctx, &conn->client, conn->thread_index)) {
13523 conn->conn_birth_time = time(NULL);
13524
13525 /* Fill in IP, port info early so even if SSL setup below fails,
13526 * error handler would have the corresponding info.
13527 * Thanks to Johannes Winkelmann for the patch.
13528 */
13529 #if defined(USE_IPV6)
13530 if (conn->client.rsa.sa.sa_family == AF_INET6) {
13531 conn->request_info.remote_port =
13532 ntohs(conn->client.rsa.sin6.sin6_port);
13533 } else
13534 #endif
13535 {
13536 conn->request_info.remote_port =
13537 ntohs(conn->client.rsa.sin.sin_port);
13538 }
13539
13540 sockaddr_to_string(conn->request_info.remote_addr,
13541 sizeof(conn->request_info.remote_addr),
13542 &conn->client.rsa);
13543
13544 DEBUG_TRACE("Start processing connection from %s",
13545 conn->request_info.remote_addr);
13546
13547 #if defined(MG_LEGACY_INTERFACE)
13548 /* This legacy interface only works for the IPv4 case */
13549 addr = ntohl(conn->client.rsa.sin.sin_addr.s_addr);
13550 memcpy(&conn->request_info.remote_ip, &addr, 4);
13551 #endif
13552
13553 conn->request_info.is_ssl = conn->client.is_ssl;
13554
13555 if (conn->client.is_ssl) {
13556 #ifndef NO_SSL
13557 /* HTTPS connection */
13558 if (sslize(conn,
13559 conn->ctx->ssl_ctx,
13560 SSL_accept,
13561 &(conn->ctx->stop_flag))) {
13562 /* Get SSL client certificate information (if set) */
13563 ssl_get_client_cert_info(conn);
13564
13565 /* process HTTPS connection */
13566 process_new_connection(conn);
13567
13568 /* Free client certificate info */
13569 if (conn->request_info.client_cert) {
13570 mg_free(
13571 (void *)(conn->request_info.client_cert->subject));
13572 mg_free(
13573 (void *)(conn->request_info.client_cert->issuer));
13574 mg_free(
13575 (void *)(conn->request_info.client_cert->serial));
13576 mg_free(
13577 (void *)(conn->request_info.client_cert->finger));
13578 conn->request_info.client_cert->subject = 0;
13579 conn->request_info.client_cert->issuer = 0;
13580 conn->request_info.client_cert->serial = 0;
13581 conn->request_info.client_cert->finger = 0;
13582 mg_free(conn->request_info.client_cert);
13583 conn->request_info.client_cert = 0;
13584 }
13585 }
13586 #endif
13587 } else {
13588 /* process HTTP connection */
13589 process_new_connection(conn);
13590 }
13591
13592 DEBUG_TRACE("Done processing connection from %s (%f sec)",
13593 conn->request_info.remote_addr,
13594 difftime(time(NULL), conn->conn_birth_time));
13595
13596 close_connection(conn);
13597
13598 DEBUG_TRACE("%s", "Connection closed");
13599 }
13600 }
13601
13602 pthread_setspecific(sTlsKey, NULL);
13603 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13604 CloseHandle(tls.pthread_cond_helper_mutex);
13605 #endif
13606 pthread_mutex_destroy(&conn->mutex);
13607 mg_free(conn);
13608
13609 DEBUG_TRACE("%s", "exiting");
13610 return NULL;
13611 }
13612
13613
13614 /* Threads have different return types on Windows and Unix. */
13615 #ifdef _WIN32
13616 static unsigned __stdcall worker_thread(void *thread_func_param)
13617 {
13618 struct worker_thread_args *pwta =
13619 (struct worker_thread_args *)thread_func_param;
13620 worker_thread_run(pwta);
13621 mg_free(thread_func_param);
13622 return 0;
13623 }
13624 #else
13625 static void *
13626 worker_thread(void *thread_func_param)
13627 {
13628 struct worker_thread_args *pwta =
13629 (struct worker_thread_args *)thread_func_param;
13630 worker_thread_run(pwta);
13631 mg_free(thread_func_param);
13632 return NULL;
13633 }
13634 #endif /* _WIN32 */
13635
13636
13637 static void
13638 accept_new_connection(const struct socket *listener, struct mg_context *ctx)
13639 {
13640 struct socket so;
13641 char src_addr[IP_ADDR_STR_LEN];
13642 socklen_t len = sizeof(so.rsa);
13643 int on = 1;
13644 int timeout;
13645
13646 if (!listener) {
13647 return;
13648 }
13649
13650 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
13651 == INVALID_SOCKET) {
13652 } else if (!check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
13653 sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
13654 mg_cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
13655 closesocket(so.sock);
13656 so.sock = INVALID_SOCKET;
13657 } else {
13658 /* Put so socket structure into the queue */
13659 DEBUG_TRACE("Accepted socket %d", (int)so.sock);
13660 set_close_on_exec(so.sock, fc(ctx));
13661 so.is_ssl = listener->is_ssl;
13662 so.ssl_redir = listener->ssl_redir;
13663 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
13664 mg_cry(fc(ctx),
13665 "%s: getsockname() failed: %s",
13666 __func__,
13667 strerror(ERRNO));
13668 }
13669
13670 /* Set TCP keep-alive. This is needed because if HTTP-level
13671 * keep-alive
13672 * is enabled, and client resets the connection, server won't get
13673 * TCP FIN or RST and will keep the connection open forever. With
13674 * TCP keep-alive, next keep-alive handshake will figure out that
13675 * the client is down and will close the server end.
13676 * Thanks to Igor Klopov who suggested the patch. */
13677 if (setsockopt(so.sock,
13678 SOL_SOCKET,
13679 SO_KEEPALIVE,
13680 (SOCK_OPT_TYPE)&on,
13681 sizeof(on)) != 0) {
13682 mg_cry(fc(ctx),
13683 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
13684 __func__,
13685 strerror(ERRNO));
13686 }
13687
13688 /* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
13689 * to effectively fill up the underlying IP packet payload and
13690 * reduce the overhead of sending lots of small buffers. However
13691 * this hurts the server's throughput (ie. operations per second)
13692 * when HTTP 1.1 persistent connections are used and the responses
13693 * are relatively small (eg. less than 1400 bytes).
13694 */
13695 if ((ctx != NULL) && (ctx->config[CONFIG_TCP_NODELAY] != NULL)
13696 && (!strcmp(ctx->config[CONFIG_TCP_NODELAY], "1"))) {
13697 if (set_tcp_nodelay(so.sock, 1) != 0) {
13698 mg_cry(fc(ctx),
13699 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
13700 __func__,
13701 strerror(ERRNO));
13702 }
13703 }
13704
13705 if (ctx && ctx->config[REQUEST_TIMEOUT]) {
13706 timeout = atoi(ctx->config[REQUEST_TIMEOUT]);
13707 } else {
13708 timeout = -1;
13709 }
13710
13711
13712 /* TODO: if non blocking sockets are used, timeouts are implemented
13713 * differently */
13714 // if (timeout > 0) {
13715 // set_sock_timeout(so.sock, timeout);
13716 //}
13717 (void)timeout;
13718 set_blocking_mode(so.sock, 0);
13719
13720 produce_socket(ctx, &so);
13721 }
13722 }
13723
13724
13725 static void
13726 master_thread_run(void *thread_func_param)
13727 {
13728 struct mg_context *ctx = (struct mg_context *)thread_func_param;
13729 struct mg_workerTLS tls;
13730 struct pollfd *pfd;
13731 unsigned int i;
13732 unsigned int workerthreadcount;
13733
13734 if (!ctx) {
13735 return;
13736 }
13737
13738 mg_set_thread_name("master");
13739
13740 /* Increase priority of the master thread */
13741 #if defined(_WIN32)
13742 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
13743 #elif defined(USE_MASTER_THREAD_PRIORITY)
13744 int min_prio = sched_get_priority_min(SCHED_RR);
13745 int max_prio = sched_get_priority_max(SCHED_RR);
13746 if ((min_prio >= 0) && (max_prio >= 0)
13747 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
13748 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
13749 struct sched_param sched_param = {0};
13750 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
13751 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
13752 }
13753 #endif
13754
13755 /* Initialize thread local storage */
13756 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13757 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
13758 #endif
13759 tls.is_master = 1;
13760 pthread_setspecific(sTlsKey, &tls);
13761
13762 if (ctx->callbacks.init_thread) {
13763 /* Callback for the master thread (type 0) */
13764 ctx->callbacks.init_thread(ctx, 0);
13765 }
13766
13767 /* Server starts *now* */
13768 ctx->start_time = time(NULL);
13769
13770 /* Start the server */
13771 pfd = ctx->listening_socket_fds;
13772 while (ctx->stop_flag == 0) {
13773 for (i = 0; i < ctx->num_listening_sockets; i++) {
13774 pfd[i].fd = ctx->listening_sockets[i].sock;
13775 pfd[i].events = POLLIN;
13776 }
13777
13778 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
13779 for (i = 0; i < ctx->num_listening_sockets; i++) {
13780 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
13781 * successful poll, and POLLIN is defined as
13782 * (POLLRDNORM | POLLRDBAND)
13783 * Therefore, we're checking pfd[i].revents & POLLIN, not
13784 * pfd[i].revents == POLLIN. */
13785 if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
13786 accept_new_connection(&ctx->listening_sockets[i], ctx);
13787 }
13788 }
13789 }
13790 }
13791
13792 /* Here stop_flag is 1 - Initiate shutdown. */
13793 DEBUG_TRACE("%s", "stopping workers");
13794
13795 /* Stop signal received: somebody called mg_stop. Quit. */
13796 close_all_listening_sockets(ctx);
13797
13798 /* Wakeup workers that are waiting for connections to handle. */
13799 (void)pthread_mutex_lock(&ctx->thread_mutex);
13800 #if defined(ALTERNATIVE_QUEUE)
13801 for (i = 0; i < ctx->cfg_worker_threads; i++) {
13802 event_signal(ctx->client_wait_events[i]);
13803
13804 /* Since we know all sockets, we can shutdown the connections. */
13805 if (ctx->client_socks[i].in_use) {
13806 shutdown(ctx->client_socks[i].sock, SHUTDOWN_BOTH);
13807 }
13808 }
13809 #else
13810 pthread_cond_broadcast(&ctx->sq_full);
13811 #endif
13812 (void)pthread_mutex_unlock(&ctx->thread_mutex);
13813
13814 /* Join all worker threads to avoid leaking threads. */
13815 workerthreadcount = ctx->cfg_worker_threads;
13816 for (i = 0; i < workerthreadcount; i++) {
13817 if (ctx->workerthreadids[i] != 0) {
13818 mg_join_thread(ctx->workerthreadids[i]);
13819 }
13820 }
13821
13822 #if !defined(NO_SSL)
13823 if (ctx->ssl_ctx != NULL) {
13824 uninitialize_ssl(ctx);
13825 }
13826 #endif
13827 DEBUG_TRACE("%s", "exiting");
13828
13829 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13830 CloseHandle(tls.pthread_cond_helper_mutex);
13831 #endif
13832 pthread_setspecific(sTlsKey, NULL);
13833
13834 /* Signal mg_stop() that we're done.
13835 * WARNING: This must be the very last thing this
13836 * thread does, as ctx becomes invalid after this line. */
13837 ctx->stop_flag = 2;
13838 }
13839
13840
13841 /* Threads have different return types on Windows and Unix. */
13842 #ifdef _WIN32
13843 static unsigned __stdcall master_thread(void *thread_func_param)
13844 {
13845 master_thread_run(thread_func_param);
13846 return 0;
13847 }
13848 #else
13849 static void *
13850 master_thread(void *thread_func_param)
13851 {
13852 master_thread_run(thread_func_param);
13853 return NULL;
13854 }
13855 #endif /* _WIN32 */
13856
13857
13858 static void
13859 free_context(struct mg_context *ctx)
13860 {
13861 int i;
13862 struct mg_handler_info *tmp_rh;
13863
13864 if (ctx == NULL) {
13865 return;
13866 }
13867
13868 if (ctx->callbacks.exit_context) {
13869 ctx->callbacks.exit_context(ctx);
13870 }
13871
13872 /* All threads exited, no sync is needed. Destroy thread mutex and
13873 * condvars
13874 */
13875 (void)pthread_mutex_destroy(&ctx->thread_mutex);
13876 #if defined(ALTERNATIVE_QUEUE)
13877 mg_free(ctx->client_socks);
13878 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
13879 event_destroy(ctx->client_wait_events[i]);
13880 }
13881 mg_free(ctx->client_wait_events);
13882 #else
13883 (void)pthread_cond_destroy(&ctx->sq_empty);
13884 (void)pthread_cond_destroy(&ctx->sq_full);
13885 #endif
13886
13887 /* Destroy other context global data structures mutex */
13888 (void)pthread_mutex_destroy(&ctx->nonce_mutex);
13889
13890 #if defined(USE_TIMERS)
13891 timers_exit(ctx);
13892 #endif
13893
13894 /* Deallocate config parameters */
13895 for (i = 0; i < NUM_OPTIONS; i++) {
13896 if (ctx->config[i] != NULL) {
13897 #if defined(_MSC_VER)
13898 #pragma warning(suppress : 6001)
13899 #endif
13900 mg_free(ctx->config[i]);
13901 }
13902 }
13903
13904 /* Deallocate request handlers */
13905 while (ctx->handlers) {
13906 tmp_rh = ctx->handlers;
13907 ctx->handlers = tmp_rh->next;
13908 mg_free(tmp_rh->uri);
13909 mg_free(tmp_rh);
13910 }
13911
13912 #ifndef NO_SSL
13913 /* Deallocate SSL context */
13914 if (ctx->ssl_ctx != NULL) {
13915 SSL_CTX_free(ctx->ssl_ctx);
13916 }
13917 #endif /* !NO_SSL */
13918
13919 /* Deallocate worker thread ID array */
13920 if (ctx->workerthreadids != NULL) {
13921 mg_free(ctx->workerthreadids);
13922 }
13923
13924 /* Deallocate the tls variable */
13925 if (mg_atomic_dec(&sTlsInit) == 0) {
13926 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13927 DeleteCriticalSection(&global_log_file_lock);
13928 #endif /* _WIN32 && !__SYMBIAN32__ */
13929 #if !defined(_WIN32)
13930 pthread_mutexattr_destroy(&pthread_mutex_attr);
13931 #endif
13932
13933 pthread_key_delete(sTlsKey);
13934
13935 #if defined(USE_LUA)
13936 lua_exit_optional_libraries();
13937 #endif
13938 }
13939
13940 /* deallocate system name string */
13941 mg_free(ctx->systemName);
13942
13943 /* Deallocate context itself */
13944 mg_free(ctx);
13945 }
13946
13947
13948 void
13949 mg_stop(struct mg_context *ctx)
13950 {
13951 pthread_t mt;
13952 if (!ctx) {
13953 return;
13954 }
13955
13956 /* We don't use a lock here. Calling mg_stop with the same ctx from
13957 * two threads is not allowed. */
13958 mt = ctx->masterthreadid;
13959 if (mt == 0) {
13960 return;
13961 }
13962
13963 ctx->masterthreadid = 0;
13964
13965 /* Set stop flag, so all threads know they have to exit. */
13966 ctx->stop_flag = 1;
13967
13968 /* Wait until everything has stopped. */
13969 while (ctx->stop_flag != 2) {
13970 (void)mg_sleep(10);
13971 }
13972
13973 mg_join_thread(mt);
13974 free_context(ctx);
13975
13976 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13977 (void)WSACleanup();
13978 #endif /* _WIN32 && !__SYMBIAN32__ */
13979 }
13980
13981
13982 static void
13983 get_system_name(char **sysName)
13984 {
13985 #if defined(_WIN32)
13986 #if !defined(__SYMBIAN32__)
13987 #if defined(_WIN32_WCE)
13988 *sysName = mg_strdup("WinCE");
13989 #else
13990 char name[128];
13991 DWORD dwVersion = 0;
13992 DWORD dwMajorVersion = 0;
13993 DWORD dwMinorVersion = 0;
13994 DWORD dwBuild = 0;
13995
13996 #ifdef _MSC_VER
13997 #pragma warning(push)
13998 /* GetVersion was declared deprecated */
13999 #pragma warning(disable : 4996)
14000 #endif
14001 dwVersion = GetVersion();
14002 #ifdef _MSC_VER
14003 #pragma warning(pop)
14004 #endif
14005
14006 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
14007 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
14008 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
14009 (void)dwBuild;
14010
14011 sprintf(name,
14012 "Windows %u.%u",
14013 (unsigned)dwMajorVersion,
14014 (unsigned)dwMinorVersion);
14015 *sysName = mg_strdup(name);
14016 #endif
14017 #else
14018 *sysName = mg_strdup("Symbian");
14019 #endif
14020 #else
14021 struct utsname name;
14022 memset(&name, 0, sizeof(name));
14023 uname(&name);
14024 *sysName = mg_strdup(name.sysname);
14025 #endif
14026 }
14027
14028
14029 struct mg_context *
14030 mg_start(const struct mg_callbacks *callbacks,
14031 void *user_data,
14032 const char **options)
14033 {
14034 struct mg_context *ctx;
14035 const char *name, *value, *default_value;
14036 int idx, ok, workerthreadcount;
14037 unsigned int i;
14038 void (*exit_callback)(const struct mg_context *ctx) = 0;
14039
14040 struct mg_workerTLS tls;
14041
14042 #if defined(_WIN32) && !defined(__SYMBIAN32__)
14043 WSADATA data;
14044 WSAStartup(MAKEWORD(2, 2), &data);
14045 #endif /* _WIN32 && !__SYMBIAN32__ */
14046
14047 /* Allocate context and initialize reasonable general case defaults. */
14048 if ((ctx = (struct mg_context *)mg_calloc(1, sizeof(*ctx))) == NULL) {
14049 return NULL;
14050 }
14051
14052 /* Random number generator will initialize at the first call */
14053 ctx->auth_nonce_mask =
14054 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
14055
14056 if (mg_atomic_inc(&sTlsInit) == 1) {
14057
14058 #if defined(_WIN32) && !defined(__SYMBIAN32__)
14059 InitializeCriticalSection(&global_log_file_lock);
14060 #endif /* _WIN32 && !__SYMBIAN32__ */
14061 #if !defined(_WIN32)
14062 pthread_mutexattr_init(&pthread_mutex_attr);
14063 pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
14064 #endif
14065
14066 if (0 != pthread_key_create(&sTlsKey, tls_dtor)) {
14067 /* Fatal error - abort start. However, this situation should
14068 * never
14069 * occur in practice. */
14070 mg_atomic_dec(&sTlsInit);
14071 mg_cry(fc(ctx), "Cannot initialize thread local storage");
14072 mg_free(ctx);
14073 return NULL;
14074 }
14075
14076 #if defined(USE_LUA)
14077 lua_init_optional_libraries();
14078 #endif
14079
14080 } else {
14081 /* TODO (low): istead of sleeping, check if sTlsKey is already
14082 * initialized. */
14083 mg_sleep(1);
14084 }
14085
14086 tls.is_master = -1;
14087 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
14088 #if defined(_WIN32) && !defined(__SYMBIAN32__)
14089 tls.pthread_cond_helper_mutex = NULL;
14090 #endif
14091 pthread_setspecific(sTlsKey, &tls);
14092
14093 ok = 0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr);
14094 #if !defined(ALTERNATIVE_QUEUE)
14095 ok &= 0 == pthread_cond_init(&ctx->sq_empty, NULL);
14096 ok &= 0 == pthread_cond_init(&ctx->sq_full, NULL);
14097 #endif
14098 ok &= 0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr);
14099 if (!ok) {
14100 /* Fatal error - abort start. However, this situation should never
14101 * occur in practice. */
14102 mg_cry(fc(ctx), "Cannot initialize thread synchronization objects");
14103 mg_free(ctx);
14104 pthread_setspecific(sTlsKey, NULL);
14105 return NULL;
14106 }
14107
14108 if (callbacks) {
14109 ctx->callbacks = *callbacks;
14110 exit_callback = callbacks->exit_context;
14111 ctx->callbacks.exit_context = 0;
14112 }
14113 ctx->user_data = user_data;
14114 ctx->handlers = NULL;
14115
14116 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
14117 ctx->shared_lua_websockets = 0;
14118 #endif
14119
14120 while (options && (name = *options++) != NULL) {
14121 if ((idx = get_option_index(name)) == -1) {
14122 mg_cry(fc(ctx), "Invalid option: %s", name);
14123 free_context(ctx);
14124 pthread_setspecific(sTlsKey, NULL);
14125 return NULL;
14126 } else if ((value = *options++) == NULL) {
14127 mg_cry(fc(ctx), "%s: option value cannot be NULL", name);
14128 free_context(ctx);
14129 pthread_setspecific(sTlsKey, NULL);
14130 return NULL;
14131 }
14132 if (ctx->config[idx] != NULL) {
14133 mg_cry(fc(ctx), "warning: %s: duplicate option", name);
14134 mg_free(ctx->config[idx]);
14135 }
14136 ctx->config[idx] = mg_strdup(value);
14137 DEBUG_TRACE("[%s] -> [%s]", name, value);
14138 }
14139
14140 /* Set default value if needed */
14141 for (i = 0; config_options[i].name != NULL; i++) {
14142 default_value = config_options[i].default_value;
14143 if (ctx->config[i] == NULL && default_value != NULL) {
14144 ctx->config[i] = mg_strdup(default_value);
14145 }
14146 }
14147
14148 #if defined(NO_FILES)
14149 if (ctx->config[DOCUMENT_ROOT] != NULL) {
14150 mg_cry(fc(ctx), "%s", "Document root must not be set");
14151 free_context(ctx);
14152 pthread_setspecific(sTlsKey, NULL);
14153 return NULL;
14154 }
14155 #endif
14156
14157 get_system_name(&ctx->systemName);
14158
14159 /* NOTE(lsm): order is important here. SSL certificates must
14160 * be initialized before listening ports. UID must be set last. */
14161 if (!set_gpass_option(ctx) ||
14162 #if !defined(NO_SSL)
14163 !set_ssl_option(ctx) ||
14164 #endif
14165 !set_ports_option(ctx) ||
14166 #if !defined(_WIN32)
14167 !set_uid_option(ctx) ||
14168 #endif
14169 !set_acl_option(ctx)) {
14170 free_context(ctx);
14171 pthread_setspecific(sTlsKey, NULL);
14172 return NULL;
14173 }
14174
14175 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
14176 /* Ignore SIGPIPE signal, so if browser cancels the request, it
14177 * won't kill the whole process. */
14178 (void)signal(SIGPIPE, SIG_IGN);
14179 #endif /* !_WIN32 && !__SYMBIAN32__ */
14180
14181 workerthreadcount = atoi(ctx->config[NUM_THREADS]);
14182
14183 if (workerthreadcount > MAX_WORKER_THREADS) {
14184 mg_cry(fc(ctx), "Too many worker threads");
14185 free_context(ctx);
14186 pthread_setspecific(sTlsKey, NULL);
14187 return NULL;
14188 }
14189
14190 if (workerthreadcount > 0) {
14191 ctx->cfg_worker_threads = ((unsigned int)(workerthreadcount));
14192 ctx->workerthreadids =
14193 (pthread_t *)mg_calloc(ctx->cfg_worker_threads, sizeof(pthread_t));
14194 if (ctx->workerthreadids == NULL) {
14195 mg_cry(fc(ctx), "Not enough memory for worker thread ID array");
14196 free_context(ctx);
14197 pthread_setspecific(sTlsKey, NULL);
14198 return NULL;
14199 }
14200
14201 #if defined(ALTERNATIVE_QUEUE)
14202 ctx->client_wait_events = mg_calloc(sizeof(ctx->client_wait_events[0]),
14203 ctx->cfg_worker_threads);
14204 if (ctx->client_wait_events == NULL) {
14205 mg_cry(fc(ctx), "Not enough memory for worker event array");
14206 mg_free(ctx->workerthreadids);
14207 free_context(ctx);
14208 pthread_setspecific(sTlsKey, NULL);
14209 return NULL;
14210 }
14211
14212 ctx->client_socks =
14213 mg_calloc(sizeof(ctx->client_socks[0]), ctx->cfg_worker_threads);
14214 if (ctx->client_wait_events == NULL) {
14215 mg_cry(fc(ctx), "Not enough memory for worker socket array");
14216 mg_free(ctx->client_socks);
14217 mg_free(ctx->workerthreadids);
14218 free_context(ctx);
14219 pthread_setspecific(sTlsKey, NULL);
14220 return NULL;
14221 }
14222
14223 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
14224 ctx->client_wait_events[i] = event_create();
14225 if (ctx->client_wait_events[i] == 0) {
14226 mg_cry(fc(ctx), "Error creating worker event %i", i);
14227 /* TODO: clean all and exit */
14228 }
14229 }
14230 #endif
14231 }
14232
14233 #if defined(USE_TIMERS)
14234 if (timers_init(ctx) != 0) {
14235 mg_cry(fc(ctx), "Error creating timers");
14236 free_context(ctx);
14237 pthread_setspecific(sTlsKey, NULL);
14238 return NULL;
14239 }
14240 #endif
14241
14242 /* Context has been created - init user libraries */
14243 if (ctx->callbacks.init_context) {
14244 ctx->callbacks.init_context(ctx);
14245 }
14246 ctx->callbacks.exit_context = exit_callback;
14247 ctx->context_type = 1; /* server context */
14248
14249 /* Start master (listening) thread */
14250 mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
14251
14252 /* Start worker threads */
14253 for (i = 0; i < ctx->cfg_worker_threads; i++) {
14254 struct worker_thread_args *wta =
14255 mg_malloc(sizeof(struct worker_thread_args));
14256 if (wta) {
14257 wta->ctx = ctx;
14258 wta->index = (int)i;
14259 }
14260
14261 if ((wta == NULL)
14262 || (mg_start_thread_with_id(worker_thread,
14263 wta,
14264 &ctx->workerthreadids[i]) != 0)) {
14265
14266 /* thread was not created */
14267 if (wta != NULL) {
14268 mg_free(wta);
14269 }
14270
14271 if (i > 0) {
14272 mg_cry(fc(ctx),
14273 "Cannot start worker thread %i: error %ld",
14274 i + 1,
14275 (long)ERRNO);
14276 } else {
14277 mg_cry(fc(ctx),
14278 "Cannot create threads: error %ld",
14279 (long)ERRNO);
14280 free_context(ctx);
14281 pthread_setspecific(sTlsKey, NULL);
14282 return NULL;
14283 }
14284 break;
14285 }
14286 }
14287
14288 pthread_setspecific(sTlsKey, NULL);
14289 return ctx;
14290 }
14291
14292
14293 /* Feature check API function */
14294 unsigned
14295 mg_check_feature(unsigned feature)
14296 {
14297 static const unsigned feature_set = 0
14298 /* Set bits for available features according to API documentation.
14299 * This bit mask is created at compile time, according to the active
14300 * preprocessor defines. It is a single const value at runtime. */
14301 #if !defined(NO_FILES)
14302 | 0x0001u
14303 #endif
14304 #if !defined(NO_SSL)
14305 | 0x0002u
14306 #endif
14307 #if !defined(NO_CGI)
14308 | 0x0004u
14309 #endif
14310 #if defined(USE_IPV6)
14311 | 0x0008u
14312 #endif
14313 #if defined(USE_WEBSOCKET)
14314 | 0x0010u
14315 #endif
14316 #if defined(USE_LUA)
14317 | 0x0020u
14318 #endif
14319 #if defined(USE_DUKTAPE)
14320 | 0x0040u
14321 #endif
14322 #if !defined(NO_CACHING)
14323 | 0x0080u
14324 #endif
14325
14326 /* Set some extra bits not defined in the API documentation.
14327 * These bits may change without further notice. */
14328 #if defined(MG_LEGACY_INTERFACE)
14329 | 0x8000u
14330 #endif
14331 #if defined(MEMORY_DEBUGGING)
14332 | 0x0100u
14333 #endif
14334 #if defined(USE_TIMERS)
14335 | 0x0200u
14336 #endif
14337 #if !defined(NO_NONCE_CHECK)
14338 | 0x0400u
14339 #endif
14340 #if !defined(NO_POPEN)
14341 | 0x0800u
14342 #endif
14343 ;
14344 return (feature & feature_set);
14345 }
14346