Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
civetweb.c
Go to the documentation of this file.
1/* Copyright (c) 2013-2021 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(__GNUC__) || defined(__MINGW32__)
24#define GCC_VERSION \
25 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
26#if GCC_VERSION >= 40500
27/* gcc diagnostic pragmas available */
28#define GCC_DIAGNOSTIC
29#endif
30#endif
31
32#if defined(GCC_DIAGNOSTIC)
33/* Disable unused macros warnings - not all defines are required
34 * for all systems and all compilers. */
35#pragma GCC diagnostic ignored "-Wunused-macros"
36/* A padding warning is just plain useless */
37#pragma GCC diagnostic ignored "-Wpadded"
38#endif
39
40#if defined(__clang__) /* GCC does not (yet) support this pragma */
41/* We must set some flags for the headers we include. These flags
42 * are reserved ids according to C99, so we need to disable a
43 * warning for that. */
44#pragma GCC diagnostic push
45#pragma GCC diagnostic ignored "-Wreserved-id-macro"
46#endif
47
48#if defined(_WIN32)
49#if !defined(_CRT_SECURE_NO_WARNINGS)
50#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
51#endif
52#if !defined(_WIN32_WINNT) /* defined for tdm-gcc so we can use getnameinfo */
53#define _WIN32_WINNT 0x0502
54#endif
55#else
56#if !defined(_GNU_SOURCE)
57#define _GNU_SOURCE /* for setgroups(), pthread_setname_np() */
58#endif
59#if defined(__linux__) && !defined(_XOPEN_SOURCE)
60#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
61#endif
62#if defined(__LSB_VERSION__) || defined(__sun)
63#define NEED_TIMEGM
64#define NO_THREAD_NAME
65#endif
66#if !defined(_LARGEFILE_SOURCE)
67#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
68#endif
69#if !defined(_FILE_OFFSET_BITS)
70#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
71#endif
72#if !defined(__STDC_FORMAT_MACROS)
73#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
74#endif
75#if !defined(__STDC_LIMIT_MACROS)
76#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
77#endif
78#if !defined(_DARWIN_UNLIMITED_SELECT)
79#define _DARWIN_UNLIMITED_SELECT
80#endif
81#if defined(__sun)
82#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
83#define __inline inline /* not recognized on older compiler versions */
84#endif
85#endif
86
87#if defined(__clang__)
88/* Enable reserved-id-macro warning again. */
89#pragma GCC diagnostic pop
90#endif
91
92
93#if defined(USE_LUA)
94#define USE_TIMERS
95#endif
96
97#if defined(_MSC_VER)
98/* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
99#pragma warning(disable : 4306)
100/* conditional expression is constant: introduced by FD_SET(..) */
101#pragma warning(disable : 4127)
102/* non-constant aggregate initializer: issued due to missing C99 support */
103#pragma warning(disable : 4204)
104/* padding added after data member */
105#pragma warning(disable : 4820)
106/* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
107#pragma warning(disable : 4668)
108/* no function prototype given: converting '()' to '(void)' */
109#pragma warning(disable : 4255)
110/* function has been selected for automatic inline expansion */
111#pragma warning(disable : 4711)
112#endif
113
114
115/* This code uses static_assert to check some conditions.
116 * Unfortunately some compilers still do not support it, so we have a
117 * replacement function here. */
118#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201100L
119#define mg_static_assert _Static_assert
120#elif defined(__cplusplus) && __cplusplus >= 201103L
121#define mg_static_assert static_assert
122#else
124#define mg_static_assert(cond, txt) \
125 extern char static_assert_replacement[(cond) ? 1 : -1]
126#endif
127
128mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
129 "int data type size check");
130mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
131 "pointer data type size check");
132mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
133
134
135/* Select queue implementation. Diagnosis features originally only implemented
136 * for the "ALTERNATIVE_QUEUE" have been ported to the previous queue
137 * implementation (NO_ALTERNATIVE_QUEUE) as well. The new configuration value
138 * "CONNECTION_QUEUE_SIZE" is only available for the previous queue
139 * implementation, since the queue length is independent from the number of
140 * worker threads there, while the new queue is one element per worker thread.
141 *
142 */
143#if defined(NO_ALTERNATIVE_QUEUE) && defined(ALTERNATIVE_QUEUE)
144/* The queues are exclusive or - only one can be used. */
145#error \
146 "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE (or none of them), but not both"
147#endif
148#if !defined(NO_ALTERNATIVE_QUEUE) && !defined(ALTERNATIVE_QUEUE)
149/* Use a default implementation */
150#define NO_ALTERNATIVE_QUEUE
151#endif
152
153#if defined(NO_FILESYSTEMS) && !defined(NO_FILES)
154/* File system access:
155 * NO_FILES = do not serve any files from the file system automatically.
156 * However, with NO_FILES CivetWeb may still write log files, read access
157 * control files, default error page files or use API functions like
158 * mg_send_file in callbacks to send files from the server local
159 * file system.
160 * NO_FILES only disables the automatic mapping between URLs and local
161 * file names.
162 * NO_FILESYSTEM = do not access any file at all. Useful for embedded
163 * devices without file system. Logging to files in not available
164 * (use callbacks instead) and API functions like mg_send_file are not
165 * available.
166 * If NO_FILESYSTEM is set, NO_FILES must be set as well.
167 */
168#error "Inconsistent build flags, NO_FILESYSTEMS requires NO_FILES"
169#endif
170
171/* DTL -- including winsock2.h works better if lean and mean */
172#if !defined(WIN32_LEAN_AND_MEAN)
173#define WIN32_LEAN_AND_MEAN
174#endif
175
176#if defined(__SYMBIAN32__)
177/* According to https://en.wikipedia.org/wiki/Symbian#History,
178 * Symbian is no longer maintained since 2014-01-01.
179 * Support for Symbian has been removed from CivetWeb
180 */
181#error "Symbian is no longer maintained. CivetWeb no longer supports Symbian."
182#endif /* __SYMBIAN32__ */
183
184#if defined(__ZEPHYR__)
185#include <time.h>
186
187#include <ctype.h>
188#include <net/socket.h>
189#include <posix/pthread.h>
190#include <posix/time.h>
191#include <stdio.h>
192#include <stdlib.h>
193#include <string.h>
194#include <zephyr.h>
195
196#include <fcntl.h>
197
198#include <libc_extensions.h>
199
200/* Max worker threads is the max of pthreads minus the main application thread
201 * and minus the main civetweb thread, thus -2
202 */
203#define MAX_WORKER_THREADS (CONFIG_MAX_PTHREAD_COUNT - 2)
204
205#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
206#define ZEPHYR_STACK_SIZE USE_STACK_SIZE
207#else
208#define ZEPHYR_STACK_SIZE (1024 * 16)
209#endif
210
211K_THREAD_STACK_DEFINE(civetweb_main_stack, ZEPHYR_STACK_SIZE);
212K_THREAD_STACK_ARRAY_DEFINE(civetweb_worker_stacks,
214 ZEPHYR_STACK_SIZE);
215
216static int zephyr_worker_stack_index;
217
218#endif
219
220#if !defined(CIVETWEB_HEADER_INCLUDED)
221/* Include the header file here, so the CivetWeb interface is defined for the
222 * entire implementation, including the following forward definitions. */
223#include "civetweb.h"
224#endif
225
226#if !defined(DEBUG_TRACE)
227#if defined(DEBUG)
228static void DEBUG_TRACE_FUNC(const char *func,
229 unsigned line,
230 PRINTF_FORMAT_STRING(const char *fmt),
231 ...) PRINTF_ARGS(3, 4);
232
233#define DEBUG_TRACE(fmt, ...) \
234 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
235
236#define NEED_DEBUG_TRACE_FUNC
237#if !defined(DEBUG_TRACE_STREAM)
238#define DEBUG_TRACE_STREAM stdout
239#endif
240
241#else
242#define DEBUG_TRACE(fmt, ...) \
243 do { \
244 } while (0)
245#endif /* DEBUG */
246#endif /* DEBUG_TRACE */
247
248
249#if !defined(DEBUG_ASSERT)
250#if defined(DEBUG)
251#include <stdlib.h>
252#define DEBUG_ASSERT(cond) \
253 do { \
254 if (!(cond)) { \
255 DEBUG_TRACE("ASSERTION FAILED: %s", #cond); \
256 exit(2); /* Exit with error */ \
257 } \
258 } while (0)
259#else
260#define DEBUG_ASSERT(cond)
261#endif /* DEBUG */
262#endif
263
264
265#if defined(__GNUC__) && defined(GCC_INSTRUMENTATION)
266void __cyg_profile_func_enter(void *this_fn, void *call_site)
267 __attribute__((no_instrument_function));
268
269void __cyg_profile_func_exit(void *this_fn, void *call_site)
270 __attribute__((no_instrument_function));
271
272void
273__cyg_profile_func_enter(void *this_fn, void *call_site)
274{
275 if ((void *)this_fn != (void *)printf) {
276 printf("E %p %p\n", this_fn, call_site);
277 }
278}
279
280void
281__cyg_profile_func_exit(void *this_fn, void *call_site)
282{
283 if ((void *)this_fn != (void *)printf) {
284 printf("X %p %p\n", this_fn, call_site);
285 }
286}
287#endif
288
289
290#if !defined(IGNORE_UNUSED_RESULT)
291#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
292#endif
293
294
295#if defined(__GNUC__) || defined(__MINGW32__)
296
297/* GCC unused function attribute seems fundamentally broken.
298 * Several attempts to tell the compiler "THIS FUNCTION MAY BE USED
299 * OR UNUSED" for individual functions failed.
300 * Either the compiler creates an "unused-function" warning if a
301 * function is not marked with __attribute__((unused)).
302 * On the other hand, if the function is marked with this attribute,
303 * but is used, the compiler raises a completely idiotic
304 * "used-but-marked-unused" warning - and
305 * #pragma GCC diagnostic ignored "-Wused-but-marked-unused"
306 * raises error: unknown option after "#pragma GCC diagnostic".
307 * Disable this warning completely, until the GCC guys sober up
308 * again.
309 */
310
311#pragma GCC diagnostic ignored "-Wunused-function"
312
313#define FUNCTION_MAY_BE_UNUSED /* __attribute__((unused)) */
314
315#else
316#define FUNCTION_MAY_BE_UNUSED
317#endif
318
319
320/* Some ANSI #includes are not available on Windows CE and Zephyr */
321#if !defined(_WIN32_WCE) && !defined(__ZEPHYR__)
322#include <errno.h>
323#include <fcntl.h>
324#include <signal.h>
325#include <stdlib.h>
326#include <sys/stat.h>
327#include <sys/types.h>
328#endif /* !_WIN32_WCE */
329
330
331#if defined(__clang__)
332/* When using -Weverything, clang does not accept it's own headers
333 * in a release build configuration. Disable what is too much in
334 * -Weverything. */
335#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
336#endif
337
338#if defined(__GNUC__) || defined(__MINGW32__)
339/* Who on earth came to the conclusion, using __DATE__ should rise
340 * an "expansion of date or time macro is not reproducible"
341 * warning. That's exactly what was intended by using this macro.
342 * Just disable this nonsense warning. */
343
344/* And disabling them does not work either:
345 * #pragma clang diagnostic ignored "-Wno-error=date-time"
346 * #pragma clang diagnostic ignored "-Wdate-time"
347 * So we just have to disable ALL warnings for some lines
348 * of code.
349 * This seems to be a known GCC bug, not resolved since 2012:
350 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
351 */
352#endif
353
354
355#if defined(__MACH__) /* Apple OSX section */
356
357#if defined(__clang__)
358#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
359/* Avoid warnings for Xcode 7. It seems it does no longer exist in Xcode 8 */
360#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
361#pragma clang diagnostic ignored "-Wno-keyword-macro"
362#endif
363#endif
364
365#ifndef CLOCK_MONOTONIC
366#define CLOCK_MONOTONIC (1)
367#endif
368#ifndef CLOCK_REALTIME
369#define CLOCK_REALTIME (2)
370#endif
371
372#include <mach/clock.h>
373#include <mach/mach.h>
374#include <mach/mach_time.h>
375#include <sys/errno.h>
376#include <sys/time.h>
377
378/* clock_gettime is not implemented on OSX prior to 10.12 */
379static int
380_civet_clock_gettime(int clk_id, struct timespec *t)
381{
382 memset(t, 0, sizeof(*t));
383 if (clk_id == CLOCK_REALTIME) {
384 struct timeval now;
385 int rv = gettimeofday(&now, NULL);
386 if (rv) {
387 return rv;
388 }
389 t->tv_sec = now.tv_sec;
390 t->tv_nsec = now.tv_usec * 1000;
391 return 0;
392
393 } else if (clk_id == CLOCK_MONOTONIC) {
394 static uint64_t clock_start_time = 0;
395 static mach_timebase_info_data_t timebase_ifo = {0, 0};
396
397 uint64_t now = mach_absolute_time();
398
399 if (clock_start_time == 0) {
400 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
401 DEBUG_ASSERT(mach_status == KERN_SUCCESS);
402
403 /* appease "unused variable" warning for release builds */
404 (void)mach_status;
405
406 clock_start_time = now;
407 }
408
409 now = (uint64_t)((double)(now - clock_start_time)
410 * (double)timebase_ifo.numer
411 / (double)timebase_ifo.denom);
412
413 t->tv_sec = now / 1000000000;
414 t->tv_nsec = now % 1000000000;
415 return 0;
416 }
417 return -1; /* EINVAL - Clock ID is unknown */
418}
419
420/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
421#if defined(__CLOCK_AVAILABILITY)
422/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be
423 * declared but it may be NULL at runtime. So we need to check before using
424 * it. */
425static int
426_civet_safe_clock_gettime(int clk_id, struct timespec *t)
427{
428 if (clock_gettime) {
429 return clock_gettime(clk_id, t);
430 }
431 return _civet_clock_gettime(clk_id, t);
432}
433#define clock_gettime _civet_safe_clock_gettime
434#else
435#define clock_gettime _civet_clock_gettime
436#endif
437
438#endif
439
440
441#if !defined(_WIN32)
442/* Unix might return different error codes indicating to try again.
443 * For Linux EAGAIN==EWOULDBLOCK, maybe EAGAIN!=EWOULDBLOCK is history from
444 * decades ago, but better check both and let the compile optimize it. */
445#define ERROR_TRY_AGAIN(err) \
446 (((err) == EAGAIN) || ((err) == EWOULDBLOCK) || ((err) == EINTR))
447#endif
448
449#if defined(USE_ZLIB)
450#include "zconf.h"
451#include "zlib.h"
452#endif
453
454
455/********************************************************************/
456/* CivetWeb configuration defines */
457/********************************************************************/
458
459/* Maximum number of threads that can be configured.
460 * The number of threads actually created depends on the "num_threads"
461 * configuration parameter, but this is the upper limit. */
462#if !defined(MAX_WORKER_THREADS)
463#define MAX_WORKER_THREADS (1024 * 64) /* in threads (count) */
464#endif
465
466/* Timeout interval for select/poll calls.
467 * The timeouts depend on "*_timeout_ms" configuration values, but long
468 * timeouts are split into timouts as small as SOCKET_TIMEOUT_QUANTUM.
469 * This reduces the time required to stop the server. */
470#if !defined(SOCKET_TIMEOUT_QUANTUM)
471#define SOCKET_TIMEOUT_QUANTUM (2000) /* in ms */
472#endif
473
474/* Do not try to compress files smaller than this limit. */
475#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT)
476#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024) /* in bytes */
477#endif
478
479#if !defined(PASSWORDS_FILE_NAME)
480#define PASSWORDS_FILE_NAME ".htpasswd"
481#endif
482
483/* Initial buffer size for all CGI environment variables. In case there is
484 * not enough space, another block is allocated. */
485#if !defined(CGI_ENVIRONMENT_SIZE)
486#define CGI_ENVIRONMENT_SIZE (4096) /* in bytes */
487#endif
488
489/* Maximum number of environment variables. */
490#if !defined(MAX_CGI_ENVIR_VARS)
491#define MAX_CGI_ENVIR_VARS (256) /* in variables (count) */
492#endif
493
494/* General purpose buffer size. */
495#if !defined(MG_BUF_LEN) /* in bytes */
496#define MG_BUF_LEN (1024 * 8)
497#endif
498
499
500/********************************************************************/
501
502/* Helper makros */
503#if !defined(ARRAY_SIZE)
504#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
505#endif
506
507#include <stdint.h>
508
509/* Standard defines */
510#if !defined(INT64_MAX)
511#define INT64_MAX (9223372036854775807)
512#endif
513
514#define SHUTDOWN_RD (0)
515#define SHUTDOWN_WR (1)
516#define SHUTDOWN_BOTH (2)
517
519 "worker threads must be a positive number");
520
521mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8,
522 "size_t data type size check");
523
524
525#if defined(_WIN32) /* WINDOWS include block */
526#include <malloc.h> /* *alloc( */
527#include <stdlib.h> /* *alloc( */
528#include <time.h> /* struct timespec */
529#include <windows.h>
530#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
531#include <ws2tcpip.h>
532
533typedef const char *SOCK_OPT_TYPE;
534
535/* For a detailed description of these *_PATH_MAX defines, see
536 * https://github.com/civetweb/civetweb/issues/937. */
537
538/* UTF8_PATH_MAX is a char buffer size for 259 BMP characters in UTF-8 plus
539 * null termination, rounded up to the next 4 bytes boundary */
540#define UTF8_PATH_MAX (3 * 260)
541/* UTF16_PATH_MAX is the 16-bit wchar_t buffer size required for 259 BMP
542 * characters plus termination. (Note: wchar_t is 16 bit on Windows) */
543#define UTF16_PATH_MAX (260)
544
545#if !defined(_IN_PORT_T)
546#if !defined(in_port_t)
547#define in_port_t u_short
548#endif
549#endif
550
551#if defined(_WIN32_WCE)
552#error "WinCE support has ended"
553#endif
554
555#include <direct.h>
556#include <io.h>
557#include <process.h>
558
559
560#define MAKEUQUAD(lo, hi) \
561 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
562#define RATE_DIFF (10000000) /* 100 nsecs */
563#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
564#define SYS2UNIX_TIME(lo, hi) \
565 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
566
567/* Visual Studio 6 does not know __func__ or __FUNCTION__
568 * The rest of MS compilers use __FUNCTION__, not C99 __func__
569 * Also use _strtoui64 on modern M$ compilers */
570#if defined(_MSC_VER)
571#if (_MSC_VER < 1300)
572#define STRX(x) #x
573#define STR(x) STRX(x)
574#define __func__ __FILE__ ":" STR(__LINE__)
575#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
576#define strtoll(x, y, z) (_atoi64(x))
577#else
578#define __func__ __FUNCTION__
579#define strtoull(x, y, z) (_strtoui64(x, y, z))
580#define strtoll(x, y, z) (_strtoi64(x, y, z))
581#endif
582#endif /* _MSC_VER */
583
584#define ERRNO ((int)(GetLastError()))
585#define NO_SOCKLEN_T
586
587
588#if defined(_WIN64) || defined(__MINGW64__)
589#if !defined(SSL_LIB)
590
591#if defined(OPENSSL_API_3_0)
592#define SSL_LIB "libssl-3-x64.dll"
593#define CRYPTO_LIB "libcrypto-3-x64.dll"
594#endif
595
596#if defined(OPENSSL_API_1_1)
597#define SSL_LIB "libssl-1_1-x64.dll"
598#define CRYPTO_LIB "libcrypto-1_1-x64.dll"
599#endif /* OPENSSL_API_1_1 */
600
601#if defined(OPENSSL_API_1_0)
602#define SSL_LIB "ssleay64.dll"
603#define CRYPTO_LIB "libeay64.dll"
604#endif /* OPENSSL_API_1_0 */
605
606#endif
607#else /* defined(_WIN64) || defined(__MINGW64__) */
608#if !defined(SSL_LIB)
609
610#if defined(OPENSSL_API_3_0)
611#define SSL_LIB "libssl-3.dll"
612#define CRYPTO_LIB "libcrypto-3.dll"
613#endif
614
615#if defined(OPENSSL_API_1_1)
616#define SSL_LIB "libssl-1_1.dll"
617#define CRYPTO_LIB "libcrypto-1_1.dll"
618#endif /* OPENSSL_API_1_1 */
619
620#if defined(OPENSSL_API_1_0)
621#define SSL_LIB "ssleay32.dll"
622#define CRYPTO_LIB "libeay32.dll"
623#endif /* OPENSSL_API_1_0 */
624
625#endif /* SSL_LIB */
626#endif /* defined(_WIN64) || defined(__MINGW64__) */
627
628
629#define O_NONBLOCK (0)
630#if !defined(W_OK)
631#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
632#endif
633#define _POSIX_
634#define INT64_FMT "I64d"
635#define UINT64_FMT "I64u"
636
637#define WINCDECL __cdecl
638#define vsnprintf_impl _vsnprintf
639#define access _access
640#define mg_sleep(x) (Sleep(x))
641
642#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
643#if !defined(popen)
644#define popen(x, y) (_popen(x, y))
645#endif
646#if !defined(pclose)
647#define pclose(x) (_pclose(x))
648#endif
649#define close(x) (_close(x))
650#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
651#define RTLD_LAZY (0)
652#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
653#define fdopen(x, y) (_fdopen((x), (y)))
654#define write(x, y, z) (_write((x), (y), (unsigned)z))
655#define read(x, y, z) (_read((x), (y), (unsigned)z))
656#define flockfile(x) ((void)pthread_mutex_lock(&global_log_file_lock))
657#define funlockfile(x) ((void)pthread_mutex_unlock(&global_log_file_lock))
658#define sleep(x) (Sleep((x)*1000))
659#define rmdir(x) (_rmdir(x))
660#if defined(_WIN64) || !defined(__MINGW32__)
661/* Only MinGW 32 bit is missing this function */
662#define timegm(x) (_mkgmtime(x))
663#else
664time_t timegm(struct tm *tm);
665#define NEED_TIMEGM
666#endif
667
668
669#if !defined(fileno)
670#define fileno(x) (_fileno(x))
671#endif /* !fileno MINGW #defines fileno */
672
673typedef struct {
674 CRITICAL_SECTION sec; /* Immovable */
675} pthread_mutex_t;
676typedef DWORD pthread_key_t;
677typedef HANDLE pthread_t;
678typedef struct {
679 pthread_mutex_t threadIdSec;
680 struct mg_workerTLS *waiting_thread; /* The chain of threads */
682
683#if !defined(__clockid_t_defined)
684typedef DWORD clockid_t;
685#endif
686#if !defined(CLOCK_MONOTONIC)
687#define CLOCK_MONOTONIC (1)
688#endif
689#if !defined(CLOCK_REALTIME)
690#define CLOCK_REALTIME (2)
691#endif
692#if !defined(CLOCK_THREAD)
693#define CLOCK_THREAD (3)
694#endif
695#if !defined(CLOCK_PROCESS)
696#define CLOCK_PROCESS (4)
697#endif
698
699
700#if defined(_MSC_VER) && (_MSC_VER >= 1900)
701#define _TIMESPEC_DEFINED
702#endif
703#if !defined(_TIMESPEC_DEFINED)
704struct timespec {
705 time_t tv_sec; /* seconds */
706 long tv_nsec; /* nanoseconds */
707};
708#endif
709
710#if !defined(WIN_PTHREADS_TIME_H)
711#define MUST_IMPLEMENT_CLOCK_GETTIME
712#endif
713
714#if defined(MUST_IMPLEMENT_CLOCK_GETTIME)
715#define clock_gettime mg_clock_gettime
716static int
717clock_gettime(clockid_t clk_id, struct timespec *tp)
718{
719 FILETIME ft;
720 ULARGE_INTEGER li, li2;
721 BOOL ok = FALSE;
722 double d;
723 static double perfcnt_per_sec = 0.0;
724 static BOOL initialized = FALSE;
725
726 if (!initialized) {
727 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
728 perfcnt_per_sec = 1.0 / li.QuadPart;
729 initialized = TRUE;
730 }
731
732 if (tp) {
733 memset(tp, 0, sizeof(*tp));
734
735 if (clk_id == CLOCK_REALTIME) {
736
737 /* BEGIN: CLOCK_REALTIME = wall clock (date and time) */
738 GetSystemTimeAsFileTime(&ft);
739 li.LowPart = ft.dwLowDateTime;
740 li.HighPart = ft.dwHighDateTime;
741 li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
742 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
743 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
744 ok = TRUE;
745 /* END: CLOCK_REALTIME */
746
747 } else if (clk_id == CLOCK_MONOTONIC) {
748
749 /* BEGIN: CLOCK_MONOTONIC = stopwatch (time differences) */
750 QueryPerformanceCounter((LARGE_INTEGER *)&li);
751 d = li.QuadPart * perfcnt_per_sec;
752 tp->tv_sec = (time_t)d;
753 d -= (double)tp->tv_sec;
754 tp->tv_nsec = (long)(d * 1.0E9);
755 ok = TRUE;
756 /* END: CLOCK_MONOTONIC */
757
758 } else if (clk_id == CLOCK_THREAD) {
759
760 /* BEGIN: CLOCK_THREAD = CPU usage of thread */
761 FILETIME t_create, t_exit, t_kernel, t_user;
762 if (GetThreadTimes(GetCurrentThread(),
763 &t_create,
764 &t_exit,
765 &t_kernel,
766 &t_user)) {
767 li.LowPart = t_user.dwLowDateTime;
768 li.HighPart = t_user.dwHighDateTime;
769 li2.LowPart = t_kernel.dwLowDateTime;
770 li2.HighPart = t_kernel.dwHighDateTime;
771 li.QuadPart += li2.QuadPart;
772 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
773 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
774 ok = TRUE;
775 }
776 /* END: CLOCK_THREAD */
777
778 } else if (clk_id == CLOCK_PROCESS) {
779
780 /* BEGIN: CLOCK_PROCESS = CPU usage of process */
781 FILETIME t_create, t_exit, t_kernel, t_user;
782 if (GetProcessTimes(GetCurrentProcess(),
783 &t_create,
784 &t_exit,
785 &t_kernel,
786 &t_user)) {
787 li.LowPart = t_user.dwLowDateTime;
788 li.HighPart = t_user.dwHighDateTime;
789 li2.LowPart = t_kernel.dwLowDateTime;
790 li2.HighPart = t_kernel.dwHighDateTime;
791 li.QuadPart += li2.QuadPart;
792 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
793 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
794 ok = TRUE;
795 }
796 /* END: CLOCK_PROCESS */
797
798 } else {
799
800 /* BEGIN: unknown clock */
801 /* ok = FALSE; already set by init */
802 /* END: unknown clock */
803 }
804 }
805
806 return ok ? 0 : -1;
807}
808#endif
809
810
811#define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
812
813static int pthread_mutex_lock(pthread_mutex_t *);
814static int pthread_mutex_unlock(pthread_mutex_t *);
815static void path_to_unicode(const struct mg_connection *conn,
816 const char *path,
817 wchar_t *wbuf,
818 size_t wbuf_len);
819
820/* All file operations need to be rewritten to solve #246. */
821
822struct mg_file;
823
824static const char *mg_fgets(char *buf, size_t size, struct mg_file *filep);
825
826
827/* POSIX dirent interface */
828struct dirent {
829 char d_name[UTF8_PATH_MAX];
830};
831
832typedef struct DIR {
833 HANDLE handle;
834 WIN32_FIND_DATAW info;
835 struct dirent result;
836} DIR;
837
838#if defined(HAVE_POLL)
839#define mg_pollfd pollfd
840#else
841struct mg_pollfd {
842 SOCKET fd;
843 short events;
844 short revents;
845};
846#endif
847
848/* Mark required libraries */
849#if defined(_MSC_VER)
850#pragma comment(lib, "Ws2_32.lib")
851#endif
852
853#else /* defined(_WIN32) - WINDOWS vs UNIX include block */
854
855#include <inttypes.h>
856
857/* Linux & co. internally use UTF8 */
858#define UTF8_PATH_MAX (PATH_MAX)
859
860typedef const void *SOCK_OPT_TYPE;
861
862#if defined(ANDROID)
863typedef unsigned short int in_port_t;
864#endif
865
866#if !defined(__ZEPHYR__)
867#include <arpa/inet.h>
868#include <ctype.h>
869#include <dirent.h>
870#include <grp.h>
871#include <limits.h>
872#include <netdb.h>
873#include <netinet/in.h>
874#include <netinet/tcp.h>
875#include <pthread.h>
876#include <pwd.h>
877#include <stdarg.h>
878#include <stddef.h>
879#include <stdio.h>
880#include <stdlib.h>
881#include <string.h>
882#include <sys/poll.h>
883#include <sys/socket.h>
884#include <sys/time.h>
885#include <sys/utsname.h>
886#include <sys/wait.h>
887#include <time.h>
888#include <unistd.h>
889#if defined(USE_X_DOM_SOCKET)
890#include <sys/un.h>
891#endif
892#endif
893
894#define vsnprintf_impl vsnprintf
895
896#if !defined(NO_SSL_DL) && !defined(NO_SSL)
897#include <dlfcn.h>
898#endif
899
900#if defined(__MACH__)
901#define SSL_LIB "libssl.dylib"
902#define CRYPTO_LIB "libcrypto.dylib"
903#else
904#if !defined(SSL_LIB)
905#define SSL_LIB "libssl.so"
906#endif
907#if !defined(CRYPTO_LIB)
908#define CRYPTO_LIB "libcrypto.so"
909#endif
910#endif
911#if !defined(O_BINARY)
912#define O_BINARY (0)
913#endif /* O_BINARY */
914#define closesocket(a) (close(a))
915#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
916#define mg_remove(conn, x) (remove(x))
917#define mg_sleep(x) (usleep((x)*1000))
918#define mg_opendir(conn, x) (opendir(x))
919#define mg_closedir(x) (closedir(x))
920#define mg_readdir(x) (readdir(x))
921#define ERRNO (errno)
922#define INVALID_SOCKET (-1)
923#define INT64_FMT PRId64
924#define UINT64_FMT PRIu64
925typedef int SOCKET;
926#define WINCDECL
927
928#if defined(__hpux)
929/* HPUX 11 does not have monotonic, fall back to realtime */
930#if !defined(CLOCK_MONOTONIC)
931#define CLOCK_MONOTONIC CLOCK_REALTIME
932#endif
933
934/* HPUX defines socklen_t incorrectly as size_t which is 64bit on
935 * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
936 * the prototypes use int* rather than socklen_t* which matches the
937 * actual library expectation. When called with the wrong size arg
938 * accept() returns a zero client inet addr and check_acl() always
939 * fails. Since socklen_t is widely used below, just force replace
940 * their typedef with int. - DTL
941 */
942#define socklen_t int
943#endif /* hpux */
944
945#define mg_pollfd pollfd
946
947#endif /* defined(_WIN32) - WINDOWS vs UNIX include block */
948
949/* In case our C library is missing "timegm", provide an implementation */
950#if defined(NEED_TIMEGM)
951static inline int
952is_leap(int y)
953{
954 return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
955}
956
957static inline int
958count_leap(int y)
959{
960 return (y - 1969) / 4 - (y - 1901) / 100 + (y - 1601) / 400;
961}
962
963time_t
964timegm(struct tm *tm)
965{
966 static const unsigned short ydays[] = {
967 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
968 int year = tm->tm_year + 1900;
969 int mon = tm->tm_mon;
970 int mday = tm->tm_mday - 1;
971 int hour = tm->tm_hour;
972 int min = tm->tm_min;
973 int sec = tm->tm_sec;
974
975 if (year < 1970 || mon < 0 || mon > 11 || mday < 0
976 || (mday >= ydays[mon + 1] - ydays[mon]
977 + (mon == 1 && is_leap(year) ? 1 : 0))
978 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60)
979 return -1;
980
981 time_t res = year - 1970;
982 res *= 365;
983 res += mday;
984 res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0);
985 res += count_leap(year);
986
987 res *= 24;
988 res += hour;
989 res *= 60;
990 res += min;
991 res *= 60;
992 res += sec;
993 return res;
994}
995#endif /* NEED_TIMEGM */
996
997
998/* va_copy should always be a macro, C99 and C++11 - DTL */
999#if !defined(va_copy)
1000#define va_copy(x, y) ((x) = (y))
1001#endif
1002
1003
1004#if defined(_WIN32)
1005/* Create substitutes for POSIX functions in Win32. */
1006
1007#if defined(GCC_DIAGNOSTIC)
1008/* Show no warning in case system functions are not used. */
1009#pragma GCC diagnostic push
1010#pragma GCC diagnostic ignored "-Wunused-function"
1011#endif
1012
1013
1014static pthread_mutex_t global_log_file_lock;
1015
1017static DWORD
1018pthread_self(void)
1019{
1020 return GetCurrentThreadId();
1021}
1022
1023
1025static int
1026pthread_key_create(
1027 pthread_key_t *key,
1028 void (*_ignored)(void *) /* destructor not supported for Windows */
1029)
1030{
1031 (void)_ignored;
1032
1033 if ((key != 0)) {
1034 *key = TlsAlloc();
1035 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
1036 }
1037 return -2;
1038}
1039
1040
1042static int
1043pthread_key_delete(pthread_key_t key)
1044{
1045 return TlsFree(key) ? 0 : 1;
1046}
1047
1048
1050static int
1051pthread_setspecific(pthread_key_t key, void *value)
1052{
1053 return TlsSetValue(key, value) ? 0 : 1;
1054}
1055
1056
1058static void *
1059pthread_getspecific(pthread_key_t key)
1060{
1061 return TlsGetValue(key);
1062}
1063
1064#if defined(GCC_DIAGNOSTIC)
1065/* Enable unused function warning again */
1066#pragma GCC diagnostic pop
1067#endif
1068
1069static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL;
1070#else
1071static pthread_mutexattr_t pthread_mutex_attr;
1072#endif /* _WIN32 */
1073
1074
1075#if defined(GCC_DIAGNOSTIC)
1076/* Show no warning in case system functions are not used. */
1077#pragma GCC diagnostic push
1078#pragma GCC diagnostic ignored "-Wunused-function"
1079#endif /* defined(GCC_DIAGNOSTIC) */
1080#if defined(__clang__)
1081/* Show no warning in case system functions are not used. */
1082#pragma clang diagnostic push
1083#pragma clang diagnostic ignored "-Wunused-function"
1084#endif
1085
1086static pthread_mutex_t global_lock_mutex;
1087
1088
1090static void
1092{
1093 (void)pthread_mutex_lock(&global_lock_mutex);
1094}
1095
1096
1098static void
1100{
1101 (void)pthread_mutex_unlock(&global_lock_mutex);
1102}
1103
1104
1105#if defined(_WIN64)
1106mg_static_assert(SIZE_MAX == 0xFFFFFFFFFFFFFFFFu, "Mismatch for atomic types");
1107#elif defined(_WIN32)
1108mg_static_assert(SIZE_MAX == 0xFFFFFFFFu, "Mismatch for atomic types");
1109#endif
1110
1111
1112/* Atomic functions working on ptrdiff_t ("signed size_t").
1113 * Operations: Increment, Decrement, Add, Maximum.
1114 * Up to size_t, they do not an atomic "load" operation.
1115 */
1117static ptrdiff_t
1118mg_atomic_inc(volatile ptrdiff_t *addr)
1119{
1120 ptrdiff_t ret;
1121
1122#if defined(_WIN64) && !defined(NO_ATOMICS)
1123 ret = InterlockedIncrement64(addr);
1124#elif defined(_WIN32) && !defined(NO_ATOMICS)
1125 ret = InterlockedIncrement(addr);
1126#elif defined(__GNUC__) \
1127 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1128 && !defined(NO_ATOMICS)
1129 ret = __sync_add_and_fetch(addr, 1);
1130#else
1132 ret = (++(*addr));
1134#endif
1135 return ret;
1136}
1137
1138
1140static ptrdiff_t
1141mg_atomic_dec(volatile ptrdiff_t *addr)
1142{
1143 ptrdiff_t ret;
1144
1145#if defined(_WIN64) && !defined(NO_ATOMICS)
1146 ret = InterlockedDecrement64(addr);
1147#elif defined(_WIN32) && !defined(NO_ATOMICS)
1148 ret = InterlockedDecrement(addr);
1149#elif defined(__GNUC__) \
1150 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1151 && !defined(NO_ATOMICS)
1152 ret = __sync_sub_and_fetch(addr, 1);
1153#else
1155 ret = (--(*addr));
1157#endif
1158 return ret;
1159}
1160
1161
1162#if defined(USE_SERVER_STATS) || defined(STOP_FLAG_NEEDS_LOCK)
1163static ptrdiff_t
1164mg_atomic_add(volatile ptrdiff_t *addr, ptrdiff_t value)
1165{
1166 ptrdiff_t ret;
1167
1168#if defined(_WIN64) && !defined(NO_ATOMICS)
1169 ret = InterlockedAdd64(addr, value);
1170#elif defined(_WIN32) && !defined(NO_ATOMICS)
1171 ret = InterlockedExchangeAdd(addr, value) + value;
1172#elif defined(__GNUC__) \
1173 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1174 && !defined(NO_ATOMICS)
1175 ret = __sync_add_and_fetch(addr, value);
1176#else
1178 *addr += value;
1179 ret = (*addr);
1181#endif
1182 return ret;
1183}
1184
1185
1187static ptrdiff_t
1188mg_atomic_compare_and_swap(volatile ptrdiff_t *addr,
1189 ptrdiff_t oldval,
1190 ptrdiff_t newval)
1191{
1192 ptrdiff_t ret;
1193
1194#if defined(_WIN64) && !defined(NO_ATOMICS)
1195 ret = InterlockedCompareExchange64(addr, newval, oldval);
1196#elif defined(_WIN32) && !defined(NO_ATOMICS)
1197 ret = InterlockedCompareExchange(addr, newval, oldval);
1198#elif defined(__GNUC__) \
1199 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1200 && !defined(NO_ATOMICS)
1201 ret = __sync_val_compare_and_swap(addr, oldval, newval);
1202#else
1204 ret = *addr;
1205 if ((ret != newval) && (ret == oldval)) {
1206 *addr = newval;
1207 }
1209#endif
1210 return ret;
1211}
1212
1213
1214static void
1215mg_atomic_max(volatile ptrdiff_t *addr, ptrdiff_t value)
1216{
1217 register ptrdiff_t tmp = *addr;
1218
1219#if defined(_WIN64) && !defined(NO_ATOMICS)
1220 while (tmp < value) {
1221 tmp = InterlockedCompareExchange64(addr, value, tmp);
1222 }
1223#elif defined(_WIN32) && !defined(NO_ATOMICS)
1224 while (tmp < value) {
1225 tmp = InterlockedCompareExchange(addr, value, tmp);
1226 }
1227#elif defined(__GNUC__) \
1228 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1229 && !defined(NO_ATOMICS)
1230 while (tmp < value) {
1231 tmp = __sync_val_compare_and_swap(addr, tmp, value);
1232 }
1233#else
1235 if (*addr < value) {
1236 *addr = value;
1237 }
1239#endif
1240}
1241
1242
1243static int64_t
1244mg_atomic_add64(volatile int64_t *addr, int64_t value)
1245{
1246 int64_t ret;
1247
1248#if defined(_WIN64) && !defined(NO_ATOMICS)
1249 ret = InterlockedAdd64(addr, value);
1250#elif defined(_WIN32) && !defined(NO_ATOMICS)
1251 ret = InterlockedExchangeAdd64(addr, value) + value;
1252#elif defined(__GNUC__) \
1253 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1254 && !defined(NO_ATOMICS)
1255 ret = __sync_add_and_fetch(addr, value);
1256#else
1258 *addr += value;
1259 ret = (*addr);
1261#endif
1262 return ret;
1263}
1264#endif
1265
1266
1267#if defined(GCC_DIAGNOSTIC)
1268/* Show no warning in case system functions are not used. */
1269#pragma GCC diagnostic pop
1270#endif /* defined(GCC_DIAGNOSTIC) */
1271#if defined(__clang__)
1272/* Show no warning in case system functions are not used. */
1273#pragma clang diagnostic pop
1274#endif
1275
1276
1277#if defined(USE_SERVER_STATS)
1278
1279struct mg_memory_stat {
1280 volatile ptrdiff_t totalMemUsed;
1281 volatile ptrdiff_t maxMemUsed;
1282 volatile ptrdiff_t blockCount;
1283};
1284
1285
1286static struct mg_memory_stat *get_memory_stat(struct mg_context *ctx);
1287
1288
1289static void *
1290mg_malloc_ex(size_t size,
1291 struct mg_context *ctx,
1292 const char *file,
1293 unsigned line)
1294{
1295 void *data = malloc(size + 2 * sizeof(uintptr_t));
1296 void *memory = 0;
1297 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1298
1299#if defined(MEMORY_DEBUGGING)
1300 char mallocStr[256];
1301#else
1302 (void)file;
1303 (void)line;
1304#endif
1305
1306 if (data) {
1307 ptrdiff_t mmem = mg_atomic_add(&mstat->totalMemUsed, (ptrdiff_t)size);
1308 mg_atomic_max(&mstat->maxMemUsed, mmem);
1309
1310 mg_atomic_inc(&mstat->blockCount);
1311 ((uintptr_t *)data)[0] = size;
1312 ((uintptr_t *)data)[1] = (uintptr_t)mstat;
1313 memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
1314 }
1315
1316#if defined(MEMORY_DEBUGGING)
1317 sprintf(mallocStr,
1318 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1319 memory,
1320 (unsigned long)size,
1321 (unsigned long)mstat->totalMemUsed,
1322 (unsigned long)mstat->blockCount,
1323 file,
1324 line);
1325 DEBUG_TRACE("%s", mallocStr);
1326#endif
1327
1328 return memory;
1329}
1330
1331
1332static void *
1333mg_calloc_ex(size_t count,
1334 size_t size,
1335 struct mg_context *ctx,
1336 const char *file,
1337 unsigned line)
1338{
1339 void *data = mg_malloc_ex(size * count, ctx, file, line);
1340
1341 if (data) {
1342 memset(data, 0, size * count);
1343 }
1344 return data;
1345}
1346
1347
1348static void
1349mg_free_ex(void *memory, const char *file, unsigned line)
1350{
1351#if defined(MEMORY_DEBUGGING)
1352 char mallocStr[256];
1353#else
1354 (void)file;
1355 (void)line;
1356#endif
1357
1358 if (memory) {
1359 void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
1360 uintptr_t size = ((uintptr_t *)data)[0];
1361 struct mg_memory_stat *mstat =
1362 (struct mg_memory_stat *)(((uintptr_t *)data)[1]);
1363 mg_atomic_add(&mstat->totalMemUsed, -(ptrdiff_t)size);
1364 mg_atomic_dec(&mstat->blockCount);
1365
1366#if defined(MEMORY_DEBUGGING)
1367 sprintf(mallocStr,
1368 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1369 memory,
1370 (unsigned long)size,
1371 (unsigned long)mstat->totalMemUsed,
1372 (unsigned long)mstat->blockCount,
1373 file,
1374 line);
1375 DEBUG_TRACE("%s", mallocStr);
1376#endif
1377 free(data);
1378 }
1379}
1380
1381
1382static void *
1383mg_realloc_ex(void *memory,
1384 size_t newsize,
1385 struct mg_context *ctx,
1386 const char *file,
1387 unsigned line)
1388{
1389 void *data;
1390 void *_realloc;
1391 uintptr_t oldsize;
1392
1393#if defined(MEMORY_DEBUGGING)
1394 char mallocStr[256];
1395#else
1396 (void)file;
1397 (void)line;
1398#endif
1399
1400 if (newsize) {
1401 if (memory) {
1402 /* Reallocate existing block */
1403 struct mg_memory_stat *mstat;
1404 data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
1405 oldsize = ((uintptr_t *)data)[0];
1406 mstat = (struct mg_memory_stat *)((uintptr_t *)data)[1];
1407 _realloc = realloc(data, newsize + 2 * sizeof(uintptr_t));
1408 if (_realloc) {
1409 data = _realloc;
1410 mg_atomic_add(&mstat->totalMemUsed, -(ptrdiff_t)oldsize);
1411#if defined(MEMORY_DEBUGGING)
1412 sprintf(mallocStr,
1413 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1414 memory,
1415 (unsigned long)oldsize,
1416 (unsigned long)mstat->totalMemUsed,
1417 (unsigned long)mstat->blockCount,
1418 file,
1419 line);
1420 DEBUG_TRACE("%s", mallocStr);
1421#endif
1422 mg_atomic_add(&mstat->totalMemUsed, (ptrdiff_t)newsize);
1423
1424#if defined(MEMORY_DEBUGGING)
1425 sprintf(mallocStr,
1426 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1427 memory,
1428 (unsigned long)newsize,
1429 (unsigned long)mstat->totalMemUsed,
1430 (unsigned long)mstat->blockCount,
1431 file,
1432 line);
1433 DEBUG_TRACE("%s", mallocStr);
1434#endif
1435 *(uintptr_t *)data = newsize;
1436 data = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
1437 } else {
1438#if defined(MEMORY_DEBUGGING)
1439 DEBUG_TRACE("%s", "MEM: realloc failed\n");
1440#endif
1441 return _realloc;
1442 }
1443 } else {
1444 /* Allocate new block */
1445 data = mg_malloc_ex(newsize, ctx, file, line);
1446 }
1447 } else {
1448 /* Free existing block */
1449 data = 0;
1450 mg_free_ex(memory, file, line);
1451 }
1452
1453 return data;
1454}
1455
1456
1457#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
1458#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
1459#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
1460#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1461
1462#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
1463#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
1464#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
1465
1466
1467#else /* USE_SERVER_STATS */
1468
1469
1470static __inline void *
1472{
1473 return malloc(a);
1474}
1475
1476static __inline void *
1477mg_calloc(size_t a, size_t b)
1478{
1479 return calloc(a, b);
1480}
1481
1482static __inline void *
1483mg_realloc(void *a, size_t b)
1484{
1485 return realloc(a, b);
1486}
1487
1488static __inline void
1490{
1491 free(a);
1492}
1493
1494#define mg_malloc_ctx(a, c) mg_malloc(a)
1495#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
1496#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
1497#define mg_free_ctx(a, c) mg_free(a)
1498
1499#endif /* USE_SERVER_STATS */
1500
1501
1502static void mg_vsnprintf(const struct mg_connection *conn,
1503 int *truncated,
1504 char *buf,
1505 size_t buflen,
1506 const char *fmt,
1507 va_list ap);
1508
1509static void mg_snprintf(const struct mg_connection *conn,
1510 int *truncated,
1511 char *buf,
1512 size_t buflen,
1513 PRINTF_FORMAT_STRING(const char *fmt),
1514 ...) PRINTF_ARGS(5, 6);
1515
1516/* This following lines are just meant as a reminder to use the mg-functions
1517 * for memory management */
1518#if defined(malloc)
1519#undef malloc
1520#endif
1521#if defined(calloc)
1522#undef calloc
1523#endif
1524#if defined(realloc)
1525#undef realloc
1526#endif
1527#if defined(free)
1528#undef free
1529#endif
1530#if defined(snprintf)
1531#undef snprintf
1532#endif
1533#if defined(vsnprintf)
1534#undef vsnprintf
1535#endif
1536#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1537#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1538#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1539#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1540#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
1541#if defined(_WIN32)
1542/* vsnprintf must not be used in any system,
1543 * but this define only works well for Windows. */
1544#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1545#endif
1546
1547
1548/* mg_init_library counter */
1550
1551#if !defined(NO_SSL)
1552#if defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
1553 || defined(OPENSSL_API_3_0)
1554static int mg_openssl_initialized = 0;
1555#endif
1556#if !defined(OPENSSL_API_1_0) && !defined(OPENSSL_API_1_1) \
1557 && !defined(OPENSSL_API_3_0) && !defined(USE_MBEDTLS)
1558#error "Please define OPENSSL_API_1_0 or OPENSSL_API_1_1"
1559#endif
1560#if defined(OPENSSL_API_1_0) && defined(OPENSSL_API_1_1) \
1561 && defined(OPENSSL_API_3_0)
1562#error "Multiple OPENSSL_API versions defined"
1563#endif
1564#if (defined(OPENSSL_API_1_0) || defined(OPENSSL_API_1_1) \
1565 || defined(OPENSSL_API_3_0)) \
1566 && defined(USE_MBEDTLS)
1567#error "Multiple SSL libraries defined"
1568#endif
1569#endif
1570
1571
1572static pthread_key_t sTlsKey; /* Thread local storage index */
1573static volatile ptrdiff_t thread_idx_max = 0;
1574
1575#if defined(MG_LEGACY_INTERFACE)
1576#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
1577#endif
1578
1581 unsigned long thread_idx;
1583#if defined(_WIN32)
1584 HANDLE pthread_cond_helper_mutex;
1585 struct mg_workerTLS *next_waiting_thread;
1586#endif
1587 const char *alpn_proto;
1588#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
1589 char txtbuf[4];
1590#endif
1591};
1592
1593
1594#if defined(GCC_DIAGNOSTIC)
1595/* Show no warning in case system functions are not used. */
1596#pragma GCC diagnostic push
1597#pragma GCC diagnostic ignored "-Wunused-function"
1598#endif /* defined(GCC_DIAGNOSTIC) */
1599#if defined(__clang__)
1600/* Show no warning in case system functions are not used. */
1601#pragma clang diagnostic push
1602#pragma clang diagnostic ignored "-Wunused-function"
1603#endif
1604
1605
1606/* Get a unique thread ID as unsigned long, independent from the data type
1607 * of thread IDs defined by the operating system API.
1608 * If two calls to mg_current_thread_id return the same value, they calls
1609 * are done from the same thread. If they return different values, they are
1610 * done from different threads. (Provided this function is used in the same
1611 * process context and threads are not repeatedly created and deleted, but
1612 * CivetWeb does not do that).
1613 * This function must match the signature required for SSL id callbacks:
1614 * CRYPTO_set_id_callback
1615 */
1617static unsigned long
1619{
1620#if defined(_WIN32)
1621 return GetCurrentThreadId();
1622#else
1623
1624#if defined(__clang__)
1625#pragma clang diagnostic push
1626#pragma clang diagnostic ignored "-Wunreachable-code"
1627 /* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
1628 * or not, so one of the two conditions will be unreachable by construction.
1629 * Unfortunately the C standard does not define a way to check this at
1630 * compile time, since the #if preprocessor conditions can not use the
1631 * sizeof operator as an argument. */
1632#endif
1633
1634 if (sizeof(pthread_t) > sizeof(unsigned long)) {
1635 /* This is the problematic case for CRYPTO_set_id_callback:
1636 * The OS pthread_t can not be cast to unsigned long. */
1637 struct mg_workerTLS *tls =
1638 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
1639 if (tls == NULL) {
1640 /* SSL called from an unknown thread: Create some thread index.
1641 */
1642 tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS));
1643 tls->is_master = -2; /* -2 means "3rd party thread" */
1644 tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
1645 pthread_setspecific(sTlsKey, tls);
1646 }
1647 return tls->thread_idx;
1648 } else {
1649 /* pthread_t may be any data type, so a simple cast to unsigned long
1650 * can rise a warning/error, depending on the platform.
1651 * Here memcpy is used as an anything-to-anything cast. */
1652 unsigned long ret = 0;
1653 pthread_t t = pthread_self();
1654 memcpy(&ret, &t, sizeof(pthread_t));
1655 return ret;
1656 }
1657
1658#if defined(__clang__)
1659#pragma clang diagnostic pop
1660#endif
1661
1662#endif
1663}
1664
1665
1667static uint64_t
1669{
1670 struct timespec tsnow;
1671 clock_gettime(CLOCK_REALTIME, &tsnow);
1672 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1673}
1674
1675
1676#if defined(GCC_DIAGNOSTIC)
1677/* Show no warning in case system functions are not used. */
1678#pragma GCC diagnostic pop
1679#endif /* defined(GCC_DIAGNOSTIC) */
1680#if defined(__clang__)
1681/* Show no warning in case system functions are not used. */
1682#pragma clang diagnostic pop
1683#endif
1684
1685
1686#if defined(NEED_DEBUG_TRACE_FUNC)
1687static void
1688DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
1689{
1690 va_list args;
1691 struct timespec tsnow;
1692
1693 /* Get some operating system independent thread id */
1694 unsigned long thread_id = mg_current_thread_id();
1695
1696 clock_gettime(CLOCK_REALTIME, &tsnow);
1697
1698 flockfile(DEBUG_TRACE_STREAM);
1699 fprintf(DEBUG_TRACE_STREAM,
1700 "*** %lu.%09lu %lu %s:%u: ",
1701 (unsigned long)tsnow.tv_sec,
1702 (unsigned long)tsnow.tv_nsec,
1703 thread_id,
1704 func,
1705 line);
1706 va_start(args, fmt);
1707 vfprintf(DEBUG_TRACE_STREAM, fmt, args);
1708 va_end(args);
1709 putc('\n', DEBUG_TRACE_STREAM);
1710 fflush(DEBUG_TRACE_STREAM);
1711 funlockfile(DEBUG_TRACE_STREAM);
1712}
1713#endif /* NEED_DEBUG_TRACE_FUNC */
1714
1715
1716#define MD5_STATIC static
1717#include "md5.inl"
1718
1719/* Darwin prior to 7.0 and Win32 do not have socklen_t */
1720#if defined(NO_SOCKLEN_T)
1721typedef int socklen_t;
1722#endif /* NO_SOCKLEN_T */
1723
1724#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
1725
1726#if !defined(MSG_NOSIGNAL)
1727#define MSG_NOSIGNAL (0)
1728#endif
1729
1730
1731/* SSL: mbedTLS vs. no-ssl vs. OpenSSL */
1732#if defined(USE_MBEDTLS)
1733/* mbedTLS */
1734#include "mod_mbedtls.inl"
1735
1736#elif defined(NO_SSL)
1737/* no SSL */
1738typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
1739typedef struct SSL_CTX SSL_CTX;
1740
1741#elif defined(NO_SSL_DL)
1742/* OpenSSL without dynamic loading */
1743#include <openssl/bn.h>
1744#include <openssl/conf.h>
1745#include <openssl/crypto.h>
1746#include <openssl/dh.h>
1747#include <openssl/engine.h>
1748#include <openssl/err.h>
1749#include <openssl/opensslv.h>
1750#include <openssl/pem.h>
1751#include <openssl/ssl.h>
1752#include <openssl/tls1.h>
1753#include <openssl/x509.h>
1754
1755#if defined(WOLFSSL_VERSION)
1756/* Additional defines for WolfSSL, see
1757 * https://github.com/civetweb/civetweb/issues/583 */
1758#include "wolfssl_extras.inl"
1759#endif
1760
1761#if defined(OPENSSL_IS_BORINGSSL)
1762/* From boringssl/src/include/openssl/mem.h:
1763 *
1764 * OpenSSL has, historically, had a complex set of malloc debugging options.
1765 * However, that was written in a time before Valgrind and ASAN. Since we now
1766 * have those tools, the OpenSSL allocation functions are simply macros around
1767 * the standard memory functions.
1768 *
1769 * #define OPENSSL_free free */
1770#define free free
1771// disable for boringssl
1772#define CONF_modules_unload(a) ((void)0)
1773#define ENGINE_cleanup() ((void)0)
1774#endif
1775
1776/* If OpenSSL headers are included, automatically select the API version */
1777#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1778#if !defined(OPENSSL_API_3_0)
1779#define OPENSSL_API_3_0
1780#endif
1781#define OPENSSL_REMOVE_THREAD_STATE()
1782#else
1783#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1784#if !defined(OPENSSL_API_1_1)
1785#define OPENSSL_API_1_1
1786#endif
1787#define OPENSSL_REMOVE_THREAD_STATE()
1788#else
1789#if !defined(OPENSSL_API_1_0)
1790#define OPENSSL_API_1_0
1791#endif
1792#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_thread_state(NULL)
1793#endif
1794#endif
1795
1796
1797#else
1798/* SSL loaded dynamically from DLL / shared object */
1799/* Add all prototypes here, to be independent from OpenSSL source
1800 * installation. */
1801#include "openssl_dl.inl"
1802
1803#endif /* Various SSL bindings */
1804
1805
1806#if !defined(NO_CACHING)
1807static const char month_names[][4] = {"Jan",
1808 "Feb",
1809 "Mar",
1810 "Apr",
1811 "May",
1812 "Jun",
1813 "Jul",
1814 "Aug",
1815 "Sep",
1816 "Oct",
1817 "Nov",
1818 "Dec"};
1819#endif /* !NO_CACHING */
1820
1821
1822/* Unified socket address. For IPv6 support, add IPv6 address structure in
1823 * the union u. */
1824union usa {
1825 struct sockaddr sa;
1826 struct sockaddr_in sin;
1827#if defined(USE_IPV6)
1828 struct sockaddr_in6 sin6;
1829#endif
1830#if defined(USE_X_DOM_SOCKET)
1831 struct sockaddr_un sun;
1832#endif
1833};
1834
1835#if defined(USE_X_DOM_SOCKET)
1836static unsigned short
1837USA_IN_PORT_UNSAFE(union usa *s)
1838{
1839 if (s->sa.sa_family == AF_INET)
1840 return s->sin.sin_port;
1841#if defined(USE_IPV6)
1842 if (s->sa.sa_family == AF_INET6)
1843 return s->sin6.sin6_port;
1844#endif
1845 return 0;
1846}
1847#endif
1848#if defined(USE_IPV6)
1849#define USA_IN_PORT_UNSAFE(s) \
1850 (((s)->sa.sa_family == AF_INET6) ? (s)->sin6.sin6_port : (s)->sin.sin_port)
1851#else
1852#define USA_IN_PORT_UNSAFE(s) ((s)->sin.sin_port)
1853#endif
1854
1855/* Describes a string (chunk of memory). */
1856struct vec {
1857 const char *ptr;
1858 size_t len;
1859};
1860
1862 /* File properties filled by mg_stat: */
1863 uint64_t size;
1865 int is_directory; /* Set to 1 if mg_stat is called for a directory */
1866 int is_gzipped; /* Set to 1 if the content is gzipped, in which
1867 * case we need a "Content-Eencoding: gzip" header */
1868 int location; /* 0 = nowhere, 1 = on disk, 2 = in memory */
1869};
1870
1871
1873 /* File properties filled by mg_fopen: */
1874 FILE *fp;
1875};
1876
1877struct mg_file {
1880};
1881
1882
1883#define STRUCT_FILE_INITIALIZER \
1884 { \
1885 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
1886 { \
1887 (FILE *)NULL \
1888 } \
1889 }
1890
1891
1892/* Describes listening socket, or socket which was accept()-ed by the master
1893 * thread and queued for future handling by the worker thread. */
1894struct socket {
1895 SOCKET sock; /* Listening socket */
1896 union usa lsa; /* Local socket address */
1897 union usa rsa; /* Remote socket address */
1898 unsigned char is_ssl; /* Is port SSL-ed */
1899 unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
1900 * port */
1901 unsigned char in_use; /* 0: invalid, 1: valid, 2: free */
1902};
1903
1904
1905/* Enum const for all options must be in sync with
1906 * static struct mg_option config_options[]
1907 * This is tested in the unit test (test/private.c)
1908 * "Private Config Options"
1909 */
1910enum {
1911 /* Once for each server */
1915 CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the
1916 * socket option typedef TCP_NODELAY. */
1921#if defined(__linux__)
1922 ALLOW_SENDFILE_CALL,
1923#endif
1924#if defined(_WIN32)
1925 CASE_SENSITIVE_FILES,
1926#endif
1931#if defined(USE_WEBSOCKET)
1932 WEBSOCKET_TIMEOUT,
1933 ENABLE_WEBSOCKET_PING_PONG,
1934#endif
1937#if defined(USE_LUA)
1938 LUA_BACKGROUND_SCRIPT,
1939 LUA_BACKGROUND_SCRIPT_PARAMS,
1940#endif
1941#if defined(USE_HTTP2)
1942 ENABLE_HTTP2,
1943#endif
1944
1945 /* Once for each domain */
1947
1950
1955#if defined(USE_TIMERS)
1956 CGI_TIMEOUT,
1957#endif
1958
1963#if defined(USE_TIMERS)
1964 CGI2_TIMEOUT,
1965#endif
1966
1967#if defined(USE_4_CGI)
1968 CGI3_EXTENSIONS,
1969 CGI3_ENVIRONMENT,
1970 CGI3_INTERPRETER,
1971 CGI3_INTERPRETER_ARGS,
1972#if defined(USE_TIMERS)
1973 CGI3_TIMEOUT,
1974#endif
1975
1976 CGI4_EXTENSIONS,
1977 CGI4_ENVIRONMENT,
1978 CGI4_INTERPRETER,
1979 CGI4_INTERPRETER_ARGS,
1980#if defined(USE_TIMERS)
1981 CGI4_TIMEOUT,
1982#endif
1983#endif
1984
1985 PUT_DELETE_PASSWORDS_FILE, /* must follow CGI_* */
2008
2009#if defined(USE_LUA)
2010 LUA_PRELOAD_FILE,
2011 LUA_SCRIPT_EXTENSIONS,
2012 LUA_SERVER_PAGE_EXTENSIONS,
2013#if defined(MG_EXPERIMENTAL_INTERFACES)
2014 LUA_DEBUG_PARAMS,
2015#endif
2016#endif
2017#if defined(USE_DUKTAPE)
2018 DUKTAPE_SCRIPT_EXTENSIONS,
2019#endif
2020
2021#if defined(USE_WEBSOCKET)
2022 WEBSOCKET_ROOT,
2023#endif
2024#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2025 LUA_WEBSOCKET_EXTENSIONS,
2026#endif
2027
2033#if !defined(NO_CACHING)
2036#endif
2037#if !defined(NO_SSL)
2039#endif
2042
2045
2046
2047/* Config option name, config types, default value.
2048 * Must be in the same order as the enum const above.
2049 */
2050static const struct mg_option config_options[] = {
2051
2052 /* Once for each server */
2053 {"listening_ports", MG_CONFIG_TYPE_STRING_LIST, "8080"},
2054 {"num_threads", MG_CONFIG_TYPE_NUMBER, "50"},
2055 {"run_as_user", MG_CONFIG_TYPE_STRING, NULL},
2056 {"tcp_nodelay", MG_CONFIG_TYPE_NUMBER, "0"},
2057 {"max_request_size", MG_CONFIG_TYPE_NUMBER, "16384"},
2058 {"linger_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2059 {"connection_queue", MG_CONFIG_TYPE_NUMBER, "20"},
2060 {"listen_backlog", MG_CONFIG_TYPE_NUMBER, "200"},
2061#if defined(__linux__)
2062 {"allow_sendfile_call", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2063#endif
2064#if defined(_WIN32)
2065 {"case_sensitive", MG_CONFIG_TYPE_BOOLEAN, "no"},
2066#endif
2067 {"throttle", MG_CONFIG_TYPE_STRING_LIST, NULL},
2068 {"enable_keep_alive", MG_CONFIG_TYPE_BOOLEAN, "no"},
2069 {"request_timeout_ms", MG_CONFIG_TYPE_NUMBER, "30000"},
2070 {"keep_alive_timeout_ms", MG_CONFIG_TYPE_NUMBER, "500"},
2071#if defined(USE_WEBSOCKET)
2072 {"websocket_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2073 {"enable_websocket_ping_pong", MG_CONFIG_TYPE_BOOLEAN, "no"},
2074#endif
2075 {"decode_url", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2076 {"decode_query_string", MG_CONFIG_TYPE_BOOLEAN, "no"},
2077#if defined(USE_LUA)
2078 {"lua_background_script", MG_CONFIG_TYPE_FILE, NULL},
2079 {"lua_background_script_params", MG_CONFIG_TYPE_STRING_LIST, NULL},
2080#endif
2081#if defined(USE_HTTP2)
2082 {"enable_http2", MG_CONFIG_TYPE_BOOLEAN, "no"},
2083#endif
2084
2085 /* Once for each domain */
2086 {"document_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
2087
2088 {"access_log_file", MG_CONFIG_TYPE_FILE, NULL},
2089 {"error_log_file", MG_CONFIG_TYPE_FILE, NULL},
2090
2091 {"cgi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
2092 {"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
2093 {"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
2094 {"cgi_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
2095#if defined(USE_TIMERS)
2096 {"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2097#endif
2098
2099 {"cgi2_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
2100 {"cgi2_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
2101 {"cgi2_interpreter", MG_CONFIG_TYPE_FILE, NULL},
2102 {"cgi2_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
2103#if defined(USE_TIMERS)
2104 {"cgi2_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2105#endif
2106
2107#if defined(USE_4_CGI)
2108 {"cgi3_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
2109 {"cgi3_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
2110 {"cgi3_interpreter", MG_CONFIG_TYPE_FILE, NULL},
2111 {"cgi3_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
2112#if defined(USE_TIMERS)
2113 {"cgi3_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2114#endif
2115
2116 {"cgi2_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
2117 {"cgi4_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
2118 {"cgi4_interpreter", MG_CONFIG_TYPE_FILE, NULL},
2119 {"cgi4_interpreter_args", MG_CONFIG_TYPE_STRING, NULL},
2120#if defined(USE_TIMERS)
2121 {"cgi4_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2122#endif
2123#endif
2124
2125 {"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
2126 {"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
2127 {"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
2128 {"enable_auth_domain_check", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2129 {"ssi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"},
2130 {"enable_directory_listing", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2131 {"global_auth_file", MG_CONFIG_TYPE_FILE, NULL},
2132 {"index_files",
2134#if defined(USE_LUA)
2135 "index.xhtml,index.html,index.htm,"
2136 "index.lp,index.lsp,index.lua,index.cgi,"
2137 "index.shtml,index.php"},
2138#else
2139 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2140#endif
2141 {"access_control_list", MG_CONFIG_TYPE_STRING_LIST, NULL},
2142 {"extra_mime_types", MG_CONFIG_TYPE_STRING_LIST, NULL},
2143 {"ssl_certificate", MG_CONFIG_TYPE_FILE, NULL},
2144 {"ssl_certificate_chain", MG_CONFIG_TYPE_FILE, NULL},
2145 {"url_rewrite_patterns", MG_CONFIG_TYPE_STRING_LIST, NULL},
2146 {"hide_files_patterns", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
2147
2148 {"ssl_verify_peer", MG_CONFIG_TYPE_YES_NO_OPTIONAL, "no"},
2149 {"ssl_cache_timeout", MG_CONFIG_TYPE_NUMBER, "-1"},
2150
2151 {"ssl_ca_path", MG_CONFIG_TYPE_DIRECTORY, NULL},
2152 {"ssl_ca_file", MG_CONFIG_TYPE_FILE, NULL},
2153 {"ssl_verify_depth", MG_CONFIG_TYPE_NUMBER, "9"},
2154 {"ssl_default_verify_paths", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2155 {"ssl_cipher_list", MG_CONFIG_TYPE_STRING, NULL},
2156
2157 /* HTTP2 requires ALPN, and anyway TLS1.2 should be considered
2158 * as a minimum in 2020 */
2159 {"ssl_protocol_version", MG_CONFIG_TYPE_NUMBER, "4"},
2160
2161 {"ssl_short_trust", MG_CONFIG_TYPE_BOOLEAN, "no"},
2162
2163#if defined(USE_LUA)
2164 {"lua_preload_file", MG_CONFIG_TYPE_FILE, NULL},
2165 {"lua_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
2166 {"lua_server_page_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"},
2167#if defined(MG_EXPERIMENTAL_INTERFACES)
2168 {"lua_debug", MG_CONFIG_TYPE_STRING, NULL},
2169#endif
2170#endif
2171#if defined(USE_DUKTAPE)
2172 /* The support for duktape is still in alpha version state.
2173 * The name of this config option might change. */
2174 {"duktape_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"},
2175#endif
2176
2177#if defined(USE_WEBSOCKET)
2178 {"websocket_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
2179#endif
2180#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2181 {"lua_websocket_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
2182#endif
2183 {"access_control_allow_origin", MG_CONFIG_TYPE_STRING, "*"},
2184 {"access_control_allow_methods", MG_CONFIG_TYPE_STRING, "*"},
2185 {"access_control_allow_headers", MG_CONFIG_TYPE_STRING, "*"},
2186 {"access_control_allow_credentials", MG_CONFIG_TYPE_STRING, ""},
2187 {"error_pages", MG_CONFIG_TYPE_DIRECTORY, NULL},
2188#if !defined(NO_CACHING)
2189 {"static_file_max_age", MG_CONFIG_TYPE_NUMBER, "3600"},
2190 {"static_file_cache_control", MG_CONFIG_TYPE_STRING, NULL},
2191#endif
2192#if !defined(NO_SSL)
2193 {"strict_transport_security_max_age", MG_CONFIG_TYPE_NUMBER, NULL},
2194#endif
2195 {"additional_header", MG_CONFIG_TYPE_STRING_MULTILINE, NULL},
2196 {"allow_index_script_resource", MG_CONFIG_TYPE_BOOLEAN, "no"},
2197
2198 {NULL, MG_CONFIG_TYPE_UNKNOWN, NULL}};
2199
2200
2201/* Check if the config_options and the corresponding enum have compatible
2202 * sizes. */
2203mg_static_assert((sizeof(config_options) / sizeof(config_options[0]))
2204 == (NUM_OPTIONS + 1),
2205 "config_options and enum not sync");
2206
2207
2209
2210
2212 /* Name/Pattern of the URI. */
2213 char *uri;
2214 size_t uri_len;
2215
2216 /* handler type */
2218
2219 /* Handler for http/https or authorization requests. */
2221 unsigned int refcount;
2223
2224 /* Handler for ws/wss (websocket) requests. */
2229
2230 /* accepted subprotocols for ws/wss requests. */
2232
2233 /* Handler for authorization requests */
2235
2236 /* User supplied argument for the handler function. */
2237 void *cbdata;
2238
2239 /* next handler in a linked list */
2241};
2242
2243
2244enum {
2250
2251
2253 SSL_CTX *ssl_ctx; /* SSL context */
2254 char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
2255 struct mg_handler_info *handlers; /* linked list of uri handlers */
2257
2258 /* Server nonce */
2259 uint64_t auth_nonce_mask; /* Mask for all nonce values */
2260 unsigned long nonce_count; /* Used nonces, used for authentication */
2261
2262#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2263 /* linked list of shared lua websockets */
2264 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2265#endif
2266
2267 /* Linked list of domains */
2269};
2270
2271
2272/* Stop flag can be "volatile" or require a lock.
2273 * MSDN uses volatile for "Interlocked" operations, but also explicitly
2274 * states a read operation for int is always atomic. */
2275#if defined(STOP_FLAG_NEEDS_LOCK)
2276
2277typedef ptrdiff_t volatile stop_flag_t;
2278
2279static int
2281{
2282 stop_flag_t sf = mg_atomic_add(f, 0);
2283 return (sf == 0);
2284}
2285
2286static int
2288{
2289 stop_flag_t sf = mg_atomic_add(f, 0);
2290 return (sf == 2);
2291}
2292
2293static void
2295{
2296 stop_flag_t sf;
2297 do {
2298 sf = mg_atomic_compare_and_swap(f, *f, v);
2299 } while (sf != v);
2300}
2301
2302#else /* STOP_FLAG_NEEDS_LOCK */
2303
2304typedef int volatile stop_flag_t;
2305#define STOP_FLAG_IS_ZERO(f) ((*(f)) == 0)
2306#define STOP_FLAG_IS_TWO(f) ((*(f)) == 2)
2307#define STOP_FLAG_ASSIGN(f, v) ((*(f)) = (v))
2308
2309#endif /* STOP_FLAG_NEEDS_LOCK */
2310
2311
2313
2314 /* Part 1 - Physical context:
2315 * This holds threads, ports, timeouts, ...
2316 * set for the entire server, independent from the
2317 * addressed hostname.
2318 */
2319
2320 /* Connection related */
2321 int context_type; /* See CONTEXT_* above */
2322
2326
2327 struct mg_connection *worker_connections; /* The connection struct, pre-
2328 * allocated for each worker */
2329
2330#if defined(USE_SERVER_STATS)
2331 volatile ptrdiff_t active_connections;
2332 volatile ptrdiff_t max_active_connections;
2333 volatile ptrdiff_t total_connections;
2334 volatile ptrdiff_t total_requests;
2335 volatile int64_t total_data_read;
2336 volatile int64_t total_data_written;
2337#endif
2338
2339 /* Thread related */
2340 stop_flag_t stop_flag; /* Should we stop event loop */
2341 pthread_mutex_t thread_mutex; /* Protects client_socks or queue */
2342
2343 pthread_t masterthreadid; /* The master thread ID */
2344 unsigned int
2345 cfg_worker_threads; /* The number of configured worker threads. */
2346 pthread_t *worker_threadids; /* The worker thread IDs */
2347 unsigned long starter_thread_idx; /* thread index which called mg_start */
2348
2349 /* Connection to thread dispatching */
2350#if defined(ALTERNATIVE_QUEUE)
2351 struct socket *client_socks;
2352 void **client_wait_events;
2353#else
2354 struct socket *squeue; /* Socket queue (sq) : accepted sockets waiting for a
2355 worker thread */
2356 volatile int sq_head; /* Head of the socket queue */
2357 volatile int sq_tail; /* Tail of the socket queue */
2358 pthread_cond_t sq_full; /* Signaled when socket is produced */
2359 pthread_cond_t sq_empty; /* Signaled when socket is consumed */
2360 volatile int sq_blocked; /* Status information: sq is full */
2361 int sq_size; /* No of elements in socket queue */
2362#if defined(USE_SERVER_STATS)
2363 int sq_max_fill;
2364#endif /* USE_SERVER_STATS */
2365#endif /* ALTERNATIVE_QUEUE */
2366
2367 /* Memory related */
2368 unsigned int max_request_size; /* The max request size */
2369
2370#if defined(USE_SERVER_STATS)
2371 struct mg_memory_stat ctx_memory;
2372#endif
2373
2374 /* Operating system related */
2375 char *systemName; /* What operating system is running */
2376 time_t start_time; /* Server start time, used for authentication
2377 * and for diagnstics. */
2378
2379#if defined(USE_TIMERS)
2380 struct ttimers *timers;
2381#endif
2382
2383 /* Lua specific: Background operations and shared websockets */
2384#if defined(USE_LUA)
2385 void *lua_background_state; /* lua_State (here as void *) */
2386 pthread_mutex_t lua_bg_mutex; /* Protect background state */
2387 int lua_bg_log_available; /* Use Lua background state for access log */
2388#endif
2389
2390 /* Server nonce */
2391 pthread_mutex_t nonce_mutex; /* Protects ssl_ctx, handlers,
2392 * ssl_cert_last_mtime, nonce_count, and
2393 * next (linked list) */
2394
2395 /* Server callbacks */
2396 struct mg_callbacks callbacks; /* User-defined callback function */
2397 void *user_data; /* User-defined data */
2398
2399 /* Part 2 - Logical domain:
2400 * This holds hostname, TLS certificate, document root, ...
2401 * set for a domain hosted at the server.
2402 * There may be multiple domains hosted at one physical server.
2403 * The default domain "dd" is the first element of a list of
2404 * domains.
2405 */
2406 struct mg_domain_context dd; /* default domain */
2407};
2408
2409
2410#if defined(USE_SERVER_STATS)
2411static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2412
2413static struct mg_memory_stat *
2414get_memory_stat(struct mg_context *ctx)
2415{
2416 if (ctx) {
2417 return &(ctx->ctx_memory);
2418 }
2419 return &mg_common_memory;
2420}
2421#endif
2422
2423enum {
2428
2429enum {
2434
2435
2436#if defined(USE_HTTP2)
2437#if !defined(HTTP2_DYN_TABLE_SIZE)
2438#define HTTP2_DYN_TABLE_SIZE (256)
2439#endif
2440
2441struct mg_http2_connection {
2442 uint32_t stream_id;
2443 uint32_t dyn_table_size;
2444 struct mg_header dyn_table[HTTP2_DYN_TABLE_SIZE];
2445};
2446#endif
2447
2448
2450 int connection_type; /* see CONNECTION_TYPE_* above */
2451 int protocol_type; /* see PROTOCOL_TYPE_*: 0=http/1.x, 1=ws, 2=http/2 */
2452 int request_state; /* 0: nothing sent, 1: header partially sent, 2: header
2453 fully sent */
2454#if defined(USE_HTTP2)
2455 struct mg_http2_connection http2;
2456#endif
2457
2460
2463
2464#if defined(USE_SERVER_STATS)
2465 int conn_state; /* 0 = undef, numerical value may change in different
2466 * versions. For the current definition, see
2467 * mg_get_connection_info_impl */
2468#endif
2469
2470 SSL *ssl; /* SSL descriptor */
2471 struct socket client; /* Connected client */
2472 time_t conn_birth_time; /* Time (wall clock) when connection was
2473 * established */
2474#if defined(USE_SERVER_STATS)
2475 time_t conn_close_time; /* Time (wall clock) when connection was
2476 * closed (or 0 if still open) */
2477 double processing_time; /* Procesing time for one request. */
2478#endif
2479 struct timespec req_time; /* Time (since system start) when the request
2480 * was received */
2481 int64_t num_bytes_sent; /* Total bytes sent to client */
2482 int64_t content_len; /* How many bytes of content can be read
2483 * !is_chunked: Content-Length header value
2484 * or -1 (until connection closed,
2485 * not allowed for a request)
2486 * is_chunked: >= 0, appended gradually
2487 */
2488 int64_t consumed_content; /* How many bytes of content have been read */
2489 int is_chunked; /* Transfer-Encoding is chunked:
2490 * 0 = not chunked,
2491 * 1 = chunked, not yet, or some data read,
2492 * 2 = chunked, has error,
2493 * 3 = chunked, all data read except trailer,
2494 * 4 = chunked, all data read
2495 */
2496 char *buf; /* Buffer for received data */
2497 char *path_info; /* PATH_INFO part of the URL */
2498
2499 int must_close; /* 1 if connection must be closed */
2500 int accept_gzip; /* 1 if gzip encoding is accepted */
2501 int in_error_handler; /* 1 if in handler for user defined error
2502 * pages */
2503#if defined(USE_WEBSOCKET)
2504 int in_websocket_handling; /* 1 if in read_websocket */
2505#endif
2506#if defined(USE_ZLIB) && defined(USE_WEBSOCKET) \
2507 && defined(MG_EXPERIMENTAL_INTERFACES)
2508 /* Parameters for websocket data compression according to rfc7692 */
2509 int websocket_deflate_server_max_windows_bits;
2510 int websocket_deflate_client_max_windows_bits;
2511 int websocket_deflate_server_no_context_takeover;
2512 int websocket_deflate_client_no_context_takeover;
2513 int websocket_deflate_initialized;
2514 int websocket_deflate_flush;
2515 z_stream websocket_deflate_state;
2516 z_stream websocket_inflate_state;
2517#endif
2518 int handled_requests; /* Number of requests handled by this connection
2519 */
2520 int buf_size; /* Buffer size */
2521 int request_len; /* Size of the request + headers in a buffer */
2522 int data_len; /* Total size of data in a buffer */
2523 int status_code; /* HTTP reply status code, e.g. 200 */
2524 int throttle; /* Throttling, bytes/sec. <= 0 means no
2525 * throttle */
2526
2527 time_t last_throttle_time; /* Last time throttled data was sent */
2528 int last_throttle_bytes; /* Bytes sent this second */
2529 pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure
2530 * atomic transmissions for websockets */
2531#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2532 void *lua_websocket_state; /* Lua_State for a websocket connection */
2533#endif
2534
2535 void *tls_user_ptr; /* User defined pointer in thread local storage,
2536 * for quick access */
2537};
2538
2539
2540/* Directory entry */
2541struct de {
2545};
2546
2547
2548#define mg_cry_internal(conn, fmt, ...) \
2549 mg_cry_internal_wrap(conn, NULL, __func__, __LINE__, fmt, __VA_ARGS__)
2550
2551#define mg_cry_ctx_internal(ctx, fmt, ...) \
2552 mg_cry_internal_wrap(NULL, ctx, __func__, __LINE__, fmt, __VA_ARGS__)
2553
2554static void mg_cry_internal_wrap(const struct mg_connection *conn,
2555 struct mg_context *ctx,
2556 const char *func,
2557 unsigned line,
2558 const char *fmt,
2559 ...) PRINTF_ARGS(5, 6);
2560
2561
2562#if !defined(NO_THREAD_NAME)
2563#if defined(_WIN32) && defined(_MSC_VER)
2564/* Set the thread name for debugging purposes in Visual Studio
2565 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
2566 */
2567#pragma pack(push, 8)
2568typedef struct tagTHREADNAME_INFO {
2569 DWORD dwType; /* Must be 0x1000. */
2570 LPCSTR szName; /* Pointer to name (in user addr space). */
2571 DWORD dwThreadID; /* Thread ID (-1=caller thread). */
2572 DWORD dwFlags; /* Reserved for future use, must be zero. */
2573} THREADNAME_INFO;
2574#pragma pack(pop)
2575
2576#elif defined(__linux__)
2577
2578#include <sys/prctl.h>
2579#include <sys/sendfile.h>
2580#if defined(ALTERNATIVE_QUEUE)
2581#include <sys/eventfd.h>
2582#endif /* ALTERNATIVE_QUEUE */
2583
2584
2585#if defined(ALTERNATIVE_QUEUE)
2586
2587static void *
2588event_create(void)
2589{
2590 int evhdl = eventfd(0, EFD_CLOEXEC);
2591 int *ret;
2592
2593 if (evhdl == -1) {
2594 /* Linux uses -1 on error, Windows NULL. */
2595 /* However, Linux does not return 0 on success either. */
2596 return 0;
2597 }
2598
2599 ret = (int *)mg_malloc(sizeof(int));
2600 if (ret) {
2601 *ret = evhdl;
2602 } else {
2603 (void)close(evhdl);
2604 }
2605
2606 return (void *)ret;
2607}
2608
2609
2610static int
2611event_wait(void *eventhdl)
2612{
2613 uint64_t u;
2614 int evhdl, s;
2615
2616 if (!eventhdl) {
2617 /* error */
2618 return 0;
2619 }
2620 evhdl = *(int *)eventhdl;
2621
2622 s = (int)read(evhdl, &u, sizeof(u));
2623 if (s != sizeof(u)) {
2624 /* error */
2625 return 0;
2626 }
2627 (void)u; /* the value is not required */
2628 return 1;
2629}
2630
2631
2632static int
2633event_signal(void *eventhdl)
2634{
2635 uint64_t u = 1;
2636 int evhdl, s;
2637
2638 if (!eventhdl) {
2639 /* error */
2640 return 0;
2641 }
2642 evhdl = *(int *)eventhdl;
2643
2644 s = (int)write(evhdl, &u, sizeof(u));
2645 if (s != sizeof(u)) {
2646 /* error */
2647 return 0;
2648 }
2649 return 1;
2650}
2651
2652
2653static void
2654event_destroy(void *eventhdl)
2655{
2656 int evhdl;
2657
2658 if (!eventhdl) {
2659 /* error */
2660 return;
2661 }
2662 evhdl = *(int *)eventhdl;
2663
2664 close(evhdl);
2665 mg_free(eventhdl);
2666}
2667
2668
2669#endif
2670
2671#endif
2672
2673
2674#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
2675
2676struct posix_event {
2677 pthread_mutex_t mutex;
2678 pthread_cond_t cond;
2679 int signaled;
2680};
2681
2682
2683static void *
2684event_create(void)
2685{
2686 struct posix_event *ret = mg_malloc(sizeof(struct posix_event));
2687 if (ret == 0) {
2688 /* out of memory */
2689 return 0;
2690 }
2691 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
2692 /* pthread mutex not available */
2693 mg_free(ret);
2694 return 0;
2695 }
2696 if (0 != pthread_cond_init(&(ret->cond), NULL)) {
2697 /* pthread cond not available */
2698 pthread_mutex_destroy(&(ret->mutex));
2699 mg_free(ret);
2700 return 0;
2701 }
2702 ret->signaled = 0;
2703 return (void *)ret;
2704}
2705
2706
2707static int
2708event_wait(void *eventhdl)
2709{
2710 struct posix_event *ev = (struct posix_event *)eventhdl;
2711 pthread_mutex_lock(&(ev->mutex));
2712 while (!ev->signaled) {
2713 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2714 }
2715 ev->signaled = 0;
2716 pthread_mutex_unlock(&(ev->mutex));
2717 return 1;
2718}
2719
2720
2721static int
2722event_signal(void *eventhdl)
2723{
2724 struct posix_event *ev = (struct posix_event *)eventhdl;
2725 pthread_mutex_lock(&(ev->mutex));
2726 pthread_cond_signal(&(ev->cond));
2727 ev->signaled = 1;
2728 pthread_mutex_unlock(&(ev->mutex));
2729 return 1;
2730}
2731
2732
2733static void
2734event_destroy(void *eventhdl)
2735{
2736 struct posix_event *ev = (struct posix_event *)eventhdl;
2737 pthread_cond_destroy(&(ev->cond));
2738 pthread_mutex_destroy(&(ev->mutex));
2739 mg_free(ev);
2740}
2741#endif
2742
2743
2744static void
2746{
2747 char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
2748
2750 NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name);
2751
2752#if defined(_WIN32)
2753#if defined(_MSC_VER)
2754 /* Windows and Visual Studio Compiler */
2755 __try {
2756 THREADNAME_INFO info;
2757 info.dwType = 0x1000;
2758 info.szName = threadName;
2759 info.dwThreadID = ~0U;
2760 info.dwFlags = 0;
2761
2762 RaiseException(0x406D1388,
2763 0,
2764 sizeof(info) / sizeof(ULONG_PTR),
2765 (ULONG_PTR *)&info);
2766 } __except (EXCEPTION_EXECUTE_HANDLER) {
2767 }
2768#elif defined(__MINGW32__)
2769 /* No option known to set thread name for MinGW known */
2770#endif
2771#elif defined(_GNU_SOURCE) && defined(__GLIBC__) \
2772 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
2773 /* pthread_setname_np first appeared in glibc in version 2.12 */
2774#if defined(__MACH__)
2775 /* OS X only current thread name can be changed */
2776 (void)pthread_setname_np(threadName);
2777#else
2778 (void)pthread_setname_np(pthread_self(), threadName);
2779#endif
2780#elif defined(__linux__)
2781 /* On Linux we can use the prctl function.
2782 * When building for Linux Standard Base (LSB) use
2783 * NO_THREAD_NAME. However, thread names are a big
2784 * help for debugging, so the stadard is to set them.
2785 */
2786 (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
2787#endif
2788}
2789#else /* !defined(NO_THREAD_NAME) */
2790void
2791mg_set_thread_name(const char *threadName)
2792{
2793}
2794#endif
2795
2796
2797const struct mg_option *
2799{
2800 return config_options;
2801}
2802
2803
2804/* Do not open file (unused) */
2805#define MG_FOPEN_MODE_NONE (0)
2806
2807/* Open file for read only access */
2808#define MG_FOPEN_MODE_READ (1)
2809
2810/* Open file for writing, create and overwrite */
2811#define MG_FOPEN_MODE_WRITE (2)
2812
2813/* Open file for writing, create and append */
2814#define MG_FOPEN_MODE_APPEND (4)
2815
2816
2817static int
2818is_file_opened(const struct mg_file_access *fileacc)
2819{
2820 if (!fileacc) {
2821 return 0;
2822 }
2823
2824 return (fileacc->fp != NULL);
2825}
2826
2827
2828#if !defined(NO_FILESYSTEMS)
2829static int mg_stat(const struct mg_connection *conn,
2830 const char *path,
2831 struct mg_file_stat *filep);
2832
2833
2834/* Reject files with special characters (for Windows) */
2835static int
2836mg_path_suspicious(const struct mg_connection *conn, const char *path)
2837{
2838 const uint8_t *c = (const uint8_t *)path;
2839 (void)conn; /* not used */
2840
2841 if ((c == NULL) || (c[0] == 0)) {
2842 /* Null pointer or empty path --> suspicious */
2843 return 1;
2844 }
2845
2846#if defined(_WIN32)
2847 while (*c) {
2848 if (*c < 32) {
2849 /* Control character */
2850 return 1;
2851 }
2852 if ((*c == '>') || (*c == '<') || (*c == '|')) {
2853 /* stdin/stdout redirection character */
2854 return 1;
2855 }
2856 if ((*c == '*') || (*c == '?')) {
2857 /* Wildcard character */
2858 return 1;
2859 }
2860 if (*c == '"') {
2861 /* Windows quotation */
2862 return 1;
2863 }
2864 c++;
2865 }
2866#endif
2867
2868 /* Nothing suspicious found */
2869 return 0;
2870}
2871
2872
2873/* mg_fopen will open a file either in memory or on the disk.
2874 * The input parameter path is a string in UTF-8 encoding.
2875 * The input parameter mode is MG_FOPEN_MODE_*
2876 * On success, fp will be set in the output struct mg_file.
2877 * All status members will also be set.
2878 * The function returns 1 on success, 0 on error. */
2879static int
2880mg_fopen(const struct mg_connection *conn,
2881 const char *path,
2882 int mode,
2883 struct mg_file *filep)
2884{
2885 int found;
2886
2887 if (!filep) {
2888 return 0;
2889 }
2890 filep->access.fp = NULL;
2891
2892 if (mg_path_suspicious(conn, path)) {
2893 return 0;
2894 }
2895
2896 /* filep is initialized in mg_stat: all fields with memset to,
2897 * some fields like size and modification date with values */
2898 found = mg_stat(conn, path, &(filep->stat));
2899
2900 if ((mode == MG_FOPEN_MODE_READ) && (!found)) {
2901 /* file does not exist and will not be created */
2902 return 0;
2903 }
2904
2905#if defined(_WIN32)
2906 {
2907 wchar_t wbuf[UTF16_PATH_MAX];
2908 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
2909 switch (mode) {
2910 case MG_FOPEN_MODE_READ:
2911 filep->access.fp = _wfopen(wbuf, L"rb");
2912 break;
2914 filep->access.fp = _wfopen(wbuf, L"wb");
2915 break;
2917 filep->access.fp = _wfopen(wbuf, L"ab");
2918 break;
2919 }
2920 }
2921#else
2922 /* Linux et al already use unicode. No need to convert. */
2923 switch (mode) {
2924 case MG_FOPEN_MODE_READ:
2925 filep->access.fp = fopen(path, "r");
2926 break;
2928 filep->access.fp = fopen(path, "w");
2929 break;
2931 filep->access.fp = fopen(path, "a");
2932 break;
2933 }
2934
2935#endif
2936 if (!found) {
2937 /* File did not exist before fopen was called.
2938 * Maybe it has been created now. Get stat info
2939 * like creation time now. */
2940 found = mg_stat(conn, path, &(filep->stat));
2941 (void)found;
2942 }
2943
2944 /* return OK if file is opened */
2945 return (filep->access.fp != NULL);
2946}
2947
2948
2949/* return 0 on success, just like fclose */
2950static int
2952{
2953 int ret = -1;
2954 if (fileacc != NULL) {
2955 if (fileacc->fp != NULL) {
2956 ret = fclose(fileacc->fp);
2957 }
2958 /* reset all members of fileacc */
2959 memset(fileacc, 0, sizeof(*fileacc));
2960 }
2961 return ret;
2962}
2963#endif /* NO_FILESYSTEMS */
2964
2965
2966static void
2967mg_strlcpy(char *dst, const char *src, size_t n)
2968{
2969 for (; *src != '\0' && n > 1; n--) {
2970 *dst++ = *src++;
2971 }
2972 *dst = '\0';
2973}
2974
2975
2976static int
2977lowercase(const char *s)
2978{
2979 return tolower((unsigned char)*s);
2980}
2981
2982
2983int
2984mg_strncasecmp(const char *s1, const char *s2, size_t len)
2985{
2986 int diff = 0;
2987
2988 if (len > 0) {
2989 do {
2990 diff = lowercase(s1++) - lowercase(s2++);
2991 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2992 }
2993
2994 return diff;
2995}
2996
2997
2998int
2999mg_strcasecmp(const char *s1, const char *s2)
3000{
3001 int diff;
3002
3003 do {
3004 diff = lowercase(s1++) - lowercase(s2++);
3005 } while (diff == 0 && s1[-1] != '\0');
3006
3007 return diff;
3008}
3009
3010
3011static char *
3012mg_strndup_ctx(const char *ptr, size_t len, struct mg_context *ctx)
3013{
3014 char *p;
3015 (void)ctx; /* Avoid Visual Studio warning if USE_SERVER_STATS is not
3016 * defined */
3017
3018 if ((p = (char *)mg_malloc_ctx(len + 1, ctx)) != NULL) {
3019 mg_strlcpy(p, ptr, len + 1);
3020 }
3021
3022 return p;
3023}
3024
3025
3026static char *
3027mg_strdup_ctx(const char *str, struct mg_context *ctx)
3028{
3029 return mg_strndup_ctx(str, strlen(str), ctx);
3030}
3031
3032static char *
3033mg_strdup(const char *str)
3034{
3035 return mg_strndup_ctx(str, strlen(str), NULL);
3036}
3037
3038
3039static const char *
3040mg_strcasestr(const char *big_str, const char *small_str)
3041{
3042 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3043
3044 if (big_len >= small_len) {
3045 for (i = 0; i <= (big_len - small_len); i++) {
3046 if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
3047 return big_str + i;
3048 }
3049 }
3050 }
3051
3052 return NULL;
3053}
3054
3055
3056/* Return null terminated string of given maximum length.
3057 * Report errors if length is exceeded. */
3058static void
3059mg_vsnprintf(const struct mg_connection *conn,
3060 int *truncated,
3061 char *buf,
3062 size_t buflen,
3063 const char *fmt,
3064 va_list ap)
3065{
3066 int n, ok;
3067
3068 if (buflen == 0) {
3069 if (truncated) {
3070 *truncated = 1;
3071 }
3072 return;
3073 }
3074
3075#if defined(__clang__)
3076#pragma clang diagnostic push
3077#pragma clang diagnostic ignored "-Wformat-nonliteral"
3078 /* Using fmt as a non-literal is intended here, since it is mostly called
3079 * indirectly by mg_snprintf */
3080#endif
3081
3082 n = (int)vsnprintf_impl(buf, buflen, fmt, ap);
3083 ok = (n >= 0) && ((size_t)n < buflen);
3084
3085#if defined(__clang__)
3086#pragma clang diagnostic pop
3087#endif
3088
3089 if (ok) {
3090 if (truncated) {
3091 *truncated = 0;
3092 }
3093 } else {
3094 if (truncated) {
3095 *truncated = 1;
3096 }
3097 mg_cry_internal(conn,
3098 "truncating vsnprintf buffer: [%.*s]",
3099 (int)((buflen > 200) ? 200 : (buflen - 1)),
3100 buf);
3101 n = (int)buflen - 1;
3102 }
3103 buf[n] = '\0';
3104}
3105
3106
3107static void
3108mg_snprintf(const struct mg_connection *conn,
3109 int *truncated,
3110 char *buf,
3111 size_t buflen,
3112 const char *fmt,
3113 ...)
3114{
3115 va_list ap;
3116
3117 va_start(ap, fmt);
3118 mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap);
3119 va_end(ap);
3120}
3121
3122
3123static int
3125{
3126 int i;
3127
3128 for (i = 0; config_options[i].name != NULL; i++) {
3129 if (strcmp(config_options[i].name, name) == 0) {
3130 return i;
3131 }
3132 }
3133 return -1;
3134}
3135
3136
3137const char *
3138mg_get_option(const struct mg_context *ctx, const char *name)
3139{
3140 int i;
3141 if ((i = get_option_index(name)) == -1) {
3142 return NULL;
3143 } else if (!ctx || ctx->dd.config[i] == NULL) {
3144 return "";
3145 } else {
3146 return ctx->dd.config[i];
3147 }
3148}
3149
3150#define mg_get_option DO_NOT_USE_THIS_FUNCTION_INTERNALLY__access_directly
3151
3152struct mg_context *
3154{
3155 return (conn == NULL) ? (struct mg_context *)NULL : (conn->phys_ctx);
3156}
3157
3158
3159void *
3161{
3162 return (ctx == NULL) ? NULL : ctx->user_data;
3163}
3164
3165
3166void *
3168{
3169 return mg_get_user_data(mg_get_context(conn));
3170}
3171
3172
3173void *
3175{
3176 /* both methods should return the same pointer */
3177 if (conn) {
3178 /* quick access, in case conn is known */
3179 return conn->tls_user_ptr;
3180 } else {
3181 /* otherwise get pointer from thread local storage (TLS) */
3182 struct mg_workerTLS *tls =
3183 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
3184 return tls->user_ptr;
3185 }
3186}
3187
3188
3189void
3190mg_set_user_connection_data(const struct mg_connection *const_conn, void *data)
3191{
3192 if (const_conn != NULL) {
3193 /* Const cast, since "const struct mg_connection *" does not mean
3194 * the connection object is not modified. Here "const" is used,
3195 * to indicate mg_read/mg_write/mg_send/.. must not be called. */
3196 struct mg_connection *conn = (struct mg_connection *)const_conn;
3197 conn->request_info.conn_data = data;
3198 }
3199}
3200
3201
3202void *
3204{
3205 if (conn != NULL) {
3206 return conn->request_info.conn_data;
3207 }
3208 return NULL;
3209}
3210
3211
3212int
3214 int size,
3215 struct mg_server_port *ports)
3216{
3217 int i, cnt = 0;
3218
3219 if (size <= 0) {
3220 return -1;
3221 }
3222 memset(ports, 0, sizeof(*ports) * (size_t)size);
3223 if (!ctx) {
3224 return -1;
3225 }
3226 if (!ctx->listening_sockets) {
3227 return -1;
3228 }
3229
3230 for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) {
3231
3232 ports[cnt].port =
3233 ntohs(USA_IN_PORT_UNSAFE(&(ctx->listening_sockets[i].lsa)));
3234 ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
3235 ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
3236
3237 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
3238 /* IPv4 */
3239 ports[cnt].protocol = 1;
3240 cnt++;
3241 } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
3242 /* IPv6 */
3243 ports[cnt].protocol = 3;
3244 cnt++;
3245 }
3246 }
3247
3248 return cnt;
3249}
3250
3251
3252#if defined(USE_X_DOM_SOCKET) && !defined(UNIX_DOMAIN_SOCKET_SERVER_NAME)
3253#define UNIX_DOMAIN_SOCKET_SERVER_NAME "*"
3254#endif
3255
3256static void
3257sockaddr_to_string(char *buf, size_t len, const union usa *usa)
3258{
3259 buf[0] = '\0';
3260
3261 if (!usa) {
3262 return;
3263 }
3264
3265 if (usa->sa.sa_family == AF_INET) {
3266 getnameinfo(&usa->sa,
3267 sizeof(usa->sin),
3268 buf,
3269 (unsigned)len,
3270 NULL,
3271 0,
3272 NI_NUMERICHOST);
3273 }
3274#if defined(USE_IPV6)
3275 else if (usa->sa.sa_family == AF_INET6) {
3276 getnameinfo(&usa->sa,
3277 sizeof(usa->sin6),
3278 buf,
3279 (unsigned)len,
3280 NULL,
3281 0,
3282 NI_NUMERICHOST);
3283 }
3284#endif
3285#if defined(USE_X_DOM_SOCKET)
3286 else if (usa->sa.sa_family == AF_UNIX) {
3287 /* TODO: Define a remote address for unix domain sockets.
3288 * This code will always return "localhost", identical to http+tcp:
3289 getnameinfo(&usa->sa,
3290 sizeof(usa->sun),
3291 buf,
3292 (unsigned)len,
3293 NULL,
3294 0,
3295 NI_NUMERICHOST);
3296 */
3297 strncpy(buf, UNIX_DOMAIN_SOCKET_SERVER_NAME, len);
3298 buf[len-1] = 0;
3299 }
3300#endif
3301}
3302
3303
3304/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
3305 * included in all responses other than 100, 101, 5xx. */
3306static void
3307gmt_time_string(char *buf, size_t buf_len, time_t *t)
3308{
3309#if !defined(REENTRANT_TIME)
3310 struct tm *tm;
3311
3312 tm = ((t != NULL) ? gmtime(t) : NULL);
3313 if (tm != NULL) {
3314#else
3315 struct tm _tm;
3316 struct tm *tm = &_tm;
3317
3318 if (t != NULL) {
3319 gmtime_r(t, tm);
3320#endif
3321 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
3322 } else {
3323 mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3324 buf[buf_len - 1] = '\0';
3325 }
3326}
3327
3328
3329/* difftime for struct timespec. Return value is in seconds. */
3330static double
3331mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
3332{
3333 return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3334 + (double)(ts_now->tv_sec - ts_before->tv_sec);
3335}
3336
3337
3338#if defined(MG_EXTERNAL_FUNCTION_mg_cry_internal_impl)
3339static void mg_cry_internal_impl(const struct mg_connection *conn,
3340 const char *func,
3341 unsigned line,
3342 const char *fmt,
3343 va_list ap);
3344#include "external_mg_cry_internal_impl.inl"
3345#elif !defined(NO_FILESYSTEMS)
3346
3347/* Print error message to the opened error log stream. */
3348static void
3350 const char *func,
3351 unsigned line,
3352 const char *fmt,
3353 va_list ap)
3354{
3355 char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
3356 struct mg_file fi;
3357 time_t timestamp;
3358
3359 /* Unused, in the RELEASE build */
3360 (void)func;
3361 (void)line;
3362
3363#if defined(GCC_DIAGNOSTIC)
3364#pragma GCC diagnostic push
3365#pragma GCC diagnostic ignored "-Wformat-nonliteral"
3366#endif
3367
3368 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
3369
3370#if defined(GCC_DIAGNOSTIC)
3371#pragma GCC diagnostic pop
3372#endif
3373
3374 buf[sizeof(buf) - 1] = 0;
3375
3376 DEBUG_TRACE("mg_cry called from %s:%u: %s", func, line, buf);
3377
3378 if (!conn) {
3379 puts(buf);
3380 return;
3381 }
3382
3383 /* Do not lock when getting the callback value, here and below.
3384 * I suppose this is fine, since function cannot disappear in the
3385 * same way string option can. */
3386 if ((conn->phys_ctx->callbacks.log_message == NULL)
3387 || (conn->phys_ctx->callbacks.log_message(conn, buf) == 0)) {
3388
3389 if (conn->dom_ctx->config[ERROR_LOG_FILE] != NULL) {
3390 if (mg_fopen(conn,
3393 &fi)
3394 == 0) {
3395 fi.access.fp = NULL;
3396 }
3397 } else {
3398 fi.access.fp = NULL;
3399 }
3400
3401 if (fi.access.fp != NULL) {
3402 flockfile(fi.access.fp);
3403 timestamp = time(NULL);
3404
3405 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
3406 fprintf(fi.access.fp,
3407 "[%010lu] [error] [client %s] ",
3408 (unsigned long)timestamp,
3409 src_addr);
3410
3411 if (conn->request_info.request_method != NULL) {
3412 fprintf(fi.access.fp,
3413 "%s %s: ",
3417 : "");
3418 }
3419
3420 fprintf(fi.access.fp, "%s", buf);
3421 fputc('\n', fi.access.fp);
3422 fflush(fi.access.fp);
3423 funlockfile(fi.access.fp);
3424 (void)mg_fclose(&fi.access); /* Ignore errors. We can't call
3425 * mg_cry here anyway ;-) */
3426 }
3427 }
3428}
3429#else
3430#error Must either enable filesystems or provide a custom mg_cry_internal_impl implementation
3431#endif /* Externally provided function */
3432
3433
3434/* Construct fake connection structure. Used for logging, if connection
3435 * is not applicable at the moment of logging. */
3436static struct mg_connection *
3438{
3439 static const struct mg_connection conn_zero = {0};
3440 *fc = conn_zero;
3441 fc->phys_ctx = ctx;
3442 fc->dom_ctx = &(ctx->dd);
3443 return fc;
3444}
3445
3446
3447static void
3449 struct mg_context *ctx,
3450 const char *func,
3451 unsigned line,
3452 const char *fmt,
3453 ...)
3454{
3455 va_list ap;
3456 va_start(ap, fmt);
3457 if (!conn && ctx) {
3458 struct mg_connection fc;
3459 mg_cry_internal_impl(fake_connection(&fc, ctx), func, line, fmt, ap);
3460 } else {
3461 mg_cry_internal_impl(conn, func, line, fmt, ap);
3462 }
3463 va_end(ap);
3464}
3465
3466
3467void
3468mg_cry(const struct mg_connection *conn, const char *fmt, ...)
3469{
3470 va_list ap;
3471 va_start(ap, fmt);
3472 mg_cry_internal_impl(conn, "user", 0, fmt, ap);
3473 va_end(ap);
3474}
3475
3476
3477#define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
3478
3479
3480const char *
3482{
3483 return CIVETWEB_VERSION;
3484}
3485
3486
3487const struct mg_request_info *
3489{
3490 if (!conn) {
3491 return NULL;
3492 }
3493#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3495 char txt[16];
3496 struct mg_workerTLS *tls =
3497 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
3498
3499 sprintf(txt, "%03i", conn->response_info.status_code);
3500 if (strlen(txt) == 3) {
3501 memcpy(tls->txtbuf, txt, 4);
3502 } else {
3503 strcpy(tls->txtbuf, "ERR");
3504 }
3505
3506 ((struct mg_connection *)conn)->request_info.local_uri =
3507 tls->txtbuf; /* use thread safe buffer */
3508 ((struct mg_connection *)conn)->request_info.local_uri_raw =
3509 tls->txtbuf; /* use the same thread safe buffer */
3510 ((struct mg_connection *)conn)->request_info.request_uri =
3511 tls->txtbuf; /* use the same thread safe buffer */
3512
3513 ((struct mg_connection *)conn)->request_info.num_headers =
3515 memcpy(((struct mg_connection *)conn)->request_info.http_headers,
3517 sizeof(conn->response_info.http_headers));
3518 } else
3519#endif
3521 return NULL;
3522 }
3523 return &conn->request_info;
3524}
3525
3526
3527const struct mg_response_info *
3529{
3530 if (!conn) {
3531 return NULL;
3532 }
3534 return NULL;
3535 }
3536 return &conn->response_info;
3537}
3538
3539
3540static const char *
3542{
3543#if defined(__clang__)
3544#pragma clang diagnostic push
3545#pragma clang diagnostic ignored "-Wunreachable-code"
3546 /* Depending on USE_WEBSOCKET and NO_SSL, some oft the protocols might be
3547 * not supported. Clang raises an "unreachable code" warning for parts of ?:
3548 * unreachable, but splitting into four different #ifdef clauses here is
3549 * more complicated.
3550 */
3551#endif
3552
3553 const struct mg_request_info *ri = &conn->request_info;
3554
3555 const char *proto = ((conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)
3556 ? (ri->is_ssl ? "wss" : "ws")
3557 : (ri->is_ssl ? "https" : "http"));
3558
3559 return proto;
3560
3561#if defined(__clang__)
3562#pragma clang diagnostic pop
3563#endif
3564}
3565
3566
3567static int
3569 char *buf,
3570 size_t buflen,
3571 const char *define_proto,
3572 int define_port,
3573 const char *define_uri)
3574{
3575 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3576 return -1;
3577 } else {
3578 int truncated = 0;
3579 const struct mg_request_info *ri = &conn->request_info;
3580
3581 const char *proto =
3582 (define_proto != NULL) ? define_proto : get_proto_name(conn);
3583 const char *uri =
3584 (define_uri != NULL)
3585 ? define_uri
3586 : ((ri->request_uri != NULL) ? ri->request_uri : ri->local_uri);
3587 int port = (define_port > 0) ? define_port : ri->server_port;
3588 int default_port = 80;
3589
3590 if (uri == NULL) {
3591 return -1;
3592 }
3593
3594#if defined(USE_X_DOM_SOCKET)
3595 if (conn->client.lsa.sa.sa_family == AF_UNIX) {
3596 /* TODO: Define and document a link for UNIX domain sockets. */
3597 /* There seems to be no official standard for this.
3598 * Common uses seem to be "httpunix://", "http.unix://" or
3599 * "http+unix://" as a protocol definition string, followed by
3600 * "localhost" or "127.0.0.1" or "/tmp/unix/path" or
3601 * "%2Ftmp%2Funix%2Fpath" (url % encoded) or
3602 * "localhost:%2Ftmp%2Funix%2Fpath" (domain socket path as port) or
3603 * "" (completely skipping the server name part). In any case, the
3604 * last part is the server local path. */
3605 const char *server_name = UNIX_DOMAIN_SOCKET_SERVER_NAME;
3606 mg_snprintf(conn,
3607 &truncated,
3608 buf,
3609 buflen,
3610 "%s.unix://%s%s",
3611 proto,
3612 server_name,
3613 ri->local_uri);
3614 default_port = 0;
3615 return 0;
3616 }
3617#endif
3618
3619 if (define_proto) {
3620 /* If we got a protocol name, use the default port accordingly. */
3621 if ((0 == strcmp(define_proto, "https"))
3622 || (0 == strcmp(define_proto, "wss"))) {
3623 default_port = 443;
3624 }
3625 } else if (ri->is_ssl) {
3626 /* If we did not get a protocol name, use TLS as default if it is
3627 * already used. */
3628 default_port = 443;
3629 }
3630
3631 {
3632#if defined(USE_IPV6)
3633 int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6);
3634#endif
3635 int auth_domain_check_enabled =
3637 && (!mg_strcasecmp(
3638 conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes"));
3639
3640 const char *server_domain =
3642
3643 char portstr[16];
3644 char server_ip[48];
3645
3646 if (port != default_port) {
3647 sprintf(portstr, ":%u", (unsigned)port);
3648 } else {
3649 portstr[0] = 0;
3650 }
3651
3652 if (!auth_domain_check_enabled || !server_domain) {
3653
3654 sockaddr_to_string(server_ip,
3655 sizeof(server_ip),
3656 &conn->client.lsa);
3657
3658 server_domain = server_ip;
3659 }
3660
3661 mg_snprintf(conn,
3662 &truncated,
3663 buf,
3664 buflen,
3665#if defined(USE_IPV6)
3666 "%s://%s%s%s%s%s",
3667 proto,
3668 (is_ipv6 && (server_domain == server_ip)) ? "[" : "",
3669 server_domain,
3670 (is_ipv6 && (server_domain == server_ip)) ? "]" : "",
3671#else
3672 "%s://%s%s%s",
3673 proto,
3674 server_domain,
3675#endif
3676 portstr,
3677 ri->local_uri);
3678
3679 if (truncated) {
3680 return -1;
3681 }
3682 return 0;
3683 }
3684 }
3685}
3686
3687
3688int
3689mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
3690{
3691 return mg_construct_local_link(conn, buf, buflen, NULL, -1, NULL);
3692}
3693
3694
3695/* Skip the characters until one of the delimiters characters found.
3696 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
3697 * Advance pointer to buffer to the next word. Return found 0-terminated
3698 * word.
3699 * Delimiters can be quoted with quotechar. */
3700static char *
3701skip_quoted(char **buf,
3702 const char *delimiters,
3703 const char *whitespace,
3704 char quotechar)
3705{
3706 char *p, *begin_word, *end_word, *end_whitespace;
3707
3708 begin_word = *buf;
3709 end_word = begin_word + strcspn(begin_word, delimiters);
3710
3711 /* Check for quotechar */
3712 if (end_word > begin_word) {
3713 p = end_word - 1;
3714 while (*p == quotechar) {
3715 /* While the delimiter is quoted, look for the next delimiter.
3716 */
3717 /* This happens, e.g., in calls from parse_auth_header,
3718 * if the user name contains a " character. */
3719
3720 /* If there is anything beyond end_word, copy it. */
3721 if (*end_word != '\0') {
3722 size_t end_off = strcspn(end_word + 1, delimiters);
3723 memmove(p, end_word, end_off + 1);
3724 p += end_off; /* p must correspond to end_word - 1 */
3725 end_word += end_off + 1;
3726 } else {
3727 *p = '\0';
3728 break;
3729 }
3730 }
3731 for (p++; p < end_word; p++) {
3732 *p = '\0';
3733 }
3734 }
3735
3736 if (*end_word == '\0') {
3737 *buf = end_word;
3738 } else {
3739
3740#if defined(GCC_DIAGNOSTIC)
3741 /* Disable spurious conversion warning for GCC */
3742#pragma GCC diagnostic push
3743#pragma GCC diagnostic ignored "-Wsign-conversion"
3744#endif /* defined(GCC_DIAGNOSTIC) */
3745
3746 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3747
3748#if defined(GCC_DIAGNOSTIC)
3749#pragma GCC diagnostic pop
3750#endif /* defined(GCC_DIAGNOSTIC) */
3751
3752 for (p = end_word; p < end_whitespace; p++) {
3753 *p = '\0';
3754 }
3755
3756 *buf = end_whitespace;
3757 }
3758
3759 return begin_word;
3760}
3761
3762
3763/* Return HTTP header value, or NULL if not found. */
3764static const char *
3765get_header(const struct mg_header *hdr, int num_hdr, const char *name)
3766{
3767 int i;
3768 for (i = 0; i < num_hdr; i++) {
3769 if (!mg_strcasecmp(name, hdr[i].name)) {
3770 return hdr[i].value;
3771 }
3772 }
3773
3774 return NULL;
3775}
3776
3777
3778#if defined(USE_WEBSOCKET)
3779/* Retrieve requested HTTP header multiple values, and return the number of
3780 * found occurrences */
3781static int
3782get_req_headers(const struct mg_request_info *ri,
3783 const char *name,
3784 const char **output,
3785 int output_max_size)
3786{
3787 int i;
3788 int cnt = 0;
3789 if (ri) {
3790 for (i = 0; i < ri->num_headers && cnt < output_max_size; i++) {
3791 if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
3792 output[cnt++] = ri->http_headers[i].value;
3793 }
3794 }
3795 }
3796 return cnt;
3797}
3798#endif
3799
3800
3801const char *
3802mg_get_header(const struct mg_connection *conn, const char *name)
3803{
3804 if (!conn) {
3805 return NULL;
3806 }
3807
3811 name);
3812 }
3816 name);
3817 }
3818 return NULL;
3819}
3820
3821
3822static const char *
3824{
3825 if (!conn) {
3826 return NULL;
3827 }
3828
3830 return conn->request_info.http_version;
3831 }
3833 return conn->response_info.http_version;
3834 }
3835 return NULL;
3836}
3837
3838
3839/* A helper function for traversing a comma separated list of values.
3840 * It returns a list pointer shifted to the next value, or NULL if the end
3841 * of the list found.
3842 * Value is stored in val vector. If value has form "x=y", then eq_val
3843 * vector is initialized to point to the "y" part, and val vector length
3844 * is adjusted to point only to "x". */
3845static const char *
3846next_option(const char *list, struct vec *val, struct vec *eq_val)
3847{
3848 int end;
3849
3850reparse:
3851 if (val == NULL || list == NULL || *list == '\0') {
3852 /* End of the list */
3853 return NULL;
3854 }
3855
3856 /* Skip over leading LWS */
3857 while (*list == ' ' || *list == '\t')
3858 list++;
3859
3860 val->ptr = list;
3861 if ((list = strchr(val->ptr, ',')) != NULL) {
3862 /* Comma found. Store length and shift the list ptr */
3863 val->len = ((size_t)(list - val->ptr));
3864 list++;
3865 } else {
3866 /* This value is the last one */
3867 list = val->ptr + strlen(val->ptr);
3868 val->len = ((size_t)(list - val->ptr));
3869 }
3870
3871 /* Adjust length for trailing LWS */
3872 end = (int)val->len - 1;
3873 while (end >= 0 && ((val->ptr[end] == ' ') || (val->ptr[end] == '\t')))
3874 end--;
3875 val->len = (size_t)(end) + (size_t)(1);
3876
3877 if (val->len == 0) {
3878 /* Ignore any empty entries. */
3879 goto reparse;
3880 }
3881
3882 if (eq_val != NULL) {
3883 /* Value has form "x=y", adjust pointers and lengths
3884 * so that val points to "x", and eq_val points to "y". */
3885 eq_val->len = 0;
3886 eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len);
3887 if (eq_val->ptr != NULL) {
3888 eq_val->ptr++; /* Skip over '=' character */
3889 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
3890 val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1;
3891 }
3892 }
3893
3894 return list;
3895}
3896
3897
3898/* A helper function for checking if a comma separated list of values
3899 * contains
3900 * the given option (case insensitvely).
3901 * 'header' can be NULL, in which case false is returned. */
3902static int
3903header_has_option(const char *header, const char *option)
3904{
3905 struct vec opt_vec;
3906 struct vec eq_vec;
3907
3908 DEBUG_ASSERT(option != NULL);
3909 DEBUG_ASSERT(option[0] != '\0');
3910
3911 while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) {
3912 if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0)
3913 return 1;
3914 }
3915
3916 return 0;
3917}
3918
3919
3920/* Perform case-insensitive match of string against pattern */
3921static ptrdiff_t
3922match_prefix(const char *pattern, size_t pattern_len, const char *str)
3923{
3924 const char *or_str;
3925 ptrdiff_t i, j, len, res;
3926
3927 if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) {
3928 res = match_prefix(pattern, (size_t)(or_str - pattern), str);
3929 return (res > 0) ? res
3930 : match_prefix(or_str + 1,
3931 (size_t)((pattern + pattern_len)
3932 - (or_str + 1)),
3933 str);
3934 }
3935
3936 for (i = 0, j = 0; (i < (ptrdiff_t)pattern_len); i++, j++) {
3937 if ((pattern[i] == '?') && (str[j] != '\0')) {
3938 continue;
3939 } else if (pattern[i] == '$') {
3940 return (str[j] == '\0') ? j : -1;
3941 } else if (pattern[i] == '*') {
3942 i++;
3943 if (pattern[i] == '*') {
3944 i++;
3945 len = (ptrdiff_t)strlen(str + j);
3946 } else {
3947 len = (ptrdiff_t)strcspn(str + j, "/");
3948 }
3949 if (i == (ptrdiff_t)pattern_len) {
3950 return j + len;
3951 }
3952 do {
3953 res = match_prefix(pattern + i,
3954 (pattern_len - (size_t)i),
3955 str + j + len);
3956 } while (res == -1 && len-- > 0);
3957 return (res == -1) ? -1 : j + res + len;
3958 } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
3959 return -1;
3960 }
3961 }
3962 return (ptrdiff_t)j;
3963}
3964
3965
3966static ptrdiff_t
3967match_prefix_strlen(const char *pattern, const char *str)
3968{
3969 if (pattern == NULL) {
3970 return -1;
3971 }
3972 return match_prefix(pattern, strlen(pattern), str);
3973}
3974
3975
3976/* HTTP 1.1 assumes keep alive if "Connection:" header is not set
3977 * This function must tolerate situations when connection info is not
3978 * set up, for example if request parsing failed. */
3979static int
3981{
3982 const char *http_version;
3983 const char *header;
3984
3985 /* First satisfy needs of the server */
3986 if ((conn == NULL) || conn->must_close) {
3987 /* Close, if civetweb framework needs to close */
3988 return 0;
3989 }
3990
3991 if (mg_strcasecmp(conn->dom_ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0) {
3992 /* Close, if keep alive is not enabled */
3993 return 0;
3994 }
3995
3996 /* Check explicit wish of the client */
3997 header = mg_get_header(conn, "Connection");
3998 if (header) {
3999 /* If there is a connection header from the client, obey */
4000 if (header_has_option(header, "keep-alive")) {
4001 return 1;
4002 }
4003 return 0;
4004 }
4005
4006 /* Use default of the standard */
4007 http_version = get_http_version(conn);
4008 if (http_version && (0 == strcmp(http_version, "1.1"))) {
4009 /* HTTP 1.1 default is keep alive */
4010 return 1;
4011 }
4012
4013 /* HTTP 1.0 (and earlier) default is to close the connection */
4014 return 0;
4015}
4016
4017
4018static int
4020{
4021 if (!conn || !conn->dom_ctx) {
4022 return 0;
4023 }
4024
4025 return (mg_strcasecmp(conn->dom_ctx->config[DECODE_URL], "yes") == 0);
4026}
4027
4028
4029static int
4031{
4032 if (!conn || !conn->dom_ctx) {
4033 return 0;
4034 }
4035
4036 return (mg_strcasecmp(conn->dom_ctx->config[DECODE_QUERY_STRING], "yes")
4037 == 0);
4038}
4039
4040
4041static const char *
4043{
4044 return should_keep_alive(conn) ? "keep-alive" : "close";
4045}
4046
4047
4048#include "response.inl"
4049
4050
4051static void
4053{
4054 /* Send all current and obsolete cache opt-out directives. */
4056 "Cache-Control",
4057 "no-cache, no-store, "
4058 "must-revalidate, private, max-age=0",
4059 -1);
4060 mg_response_header_add(conn, "Expires", "0", -1);
4061
4062 if (conn->protocol_type == PROTOCOL_TYPE_HTTP1) {
4063 /* Obsolete, but still send it for HTTP/1.0 */
4064 mg_response_header_add(conn, "Pragma", "no-cache", -1);
4065 }
4066}
4067
4068
4069static void
4071{
4072#if !defined(NO_CACHING)
4073 int max_age;
4074 char val[64];
4075
4076 const char *cache_control =
4078
4079 /* If there is a full cache-control option configured,0 use it */
4080 if (cache_control != NULL) {
4081 mg_response_header_add(conn, "Cache-Control", cache_control, -1);
4082 return;
4083 }
4084
4085 /* Read the server config to check how long a file may be cached.
4086 * The configuration is in seconds. */
4087 max_age = atoi(conn->dom_ctx->config[STATIC_FILE_MAX_AGE]);
4088 if (max_age <= 0) {
4089 /* 0 means "do not cache". All values <0 are reserved
4090 * and may be used differently in the future. */
4091 /* If a file should not be cached, do not only send
4092 * max-age=0, but also pragmas and Expires headers. */
4094 return;
4095 }
4096
4097 /* Use "Cache-Control: max-age" instead of "Expires" header.
4098 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
4099 /* See also https://www.mnot.net/cache_docs/ */
4100 /* According to RFC 2616, Section 14.21, caching times should not exceed
4101 * one year. A year with 365 days corresponds to 31536000 seconds, a
4102 * leap
4103 * year to 31622400 seconds. For the moment, we just send whatever has
4104 * been configured, still the behavior for >1 year should be considered
4105 * as undefined. */
4107 conn, NULL, val, sizeof(val), "max-age=%lu", (unsigned long)max_age);
4108 mg_response_header_add(conn, "Cache-Control", val, -1);
4109
4110#else /* NO_CACHING */
4111
4113#endif /* !NO_CACHING */
4114}
4115
4116
4117static void
4119{
4120 const char *header = conn->dom_ctx->config[ADDITIONAL_HEADER];
4121
4122#if !defined(NO_SSL)
4123 if (conn->dom_ctx->config[STRICT_HTTPS_MAX_AGE]) {
4124 long max_age = atol(conn->dom_ctx->config[STRICT_HTTPS_MAX_AGE]);
4125 if (max_age >= 0) {
4126 char val[64];
4127 mg_snprintf(conn,
4128 NULL,
4129 val,
4130 sizeof(val),
4131 "max-age=%lu",
4132 (unsigned long)max_age);
4133 mg_response_header_add(conn, "Strict-Transport-Security", val, -1);
4134 }
4135 }
4136#endif
4137
4138 if (header && header[0]) {
4139 mg_response_header_add_lines(conn, header);
4140 }
4141}
4142
4143
4144#if !defined(NO_FILESYSTEMS)
4145static void handle_file_based_request(struct mg_connection *conn,
4146 const char *path,
4147 struct mg_file *filep);
4148#endif /* NO_FILESYSTEMS */
4149
4150
4151const char *
4152mg_get_response_code_text(const struct mg_connection *conn, int response_code)
4153{
4154 /* See IANA HTTP status code assignment:
4155 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
4156 */
4157
4158 switch (response_code) {
4159 /* RFC2616 Section 10.1 - Informational 1xx */
4160 case 100:
4161 return "Continue"; /* RFC2616 Section 10.1.1 */
4162 case 101:
4163 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
4164 case 102:
4165 return "Processing"; /* RFC2518 Section 10.1 */
4166
4167 /* RFC2616 Section 10.2 - Successful 2xx */
4168 case 200:
4169 return "OK"; /* RFC2616 Section 10.2.1 */
4170 case 201:
4171 return "Created"; /* RFC2616 Section 10.2.2 */
4172 case 202:
4173 return "Accepted"; /* RFC2616 Section 10.2.3 */
4174 case 203:
4175 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
4176 case 204:
4177 return "No Content"; /* RFC2616 Section 10.2.5 */
4178 case 205:
4179 return "Reset Content"; /* RFC2616 Section 10.2.6 */
4180 case 206:
4181 return "Partial Content"; /* RFC2616 Section 10.2.7 */
4182 case 207:
4183 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1
4184 */
4185 case 208:
4186 return "Already Reported"; /* RFC5842 Section 7.1 */
4187
4188 case 226:
4189 return "IM used"; /* RFC3229 Section 10.4.1 */
4190
4191 /* RFC2616 Section 10.3 - Redirection 3xx */
4192 case 300:
4193 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
4194 case 301:
4195 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
4196 case 302:
4197 return "Found"; /* RFC2616 Section 10.3.3 */
4198 case 303:
4199 return "See Other"; /* RFC2616 Section 10.3.4 */
4200 case 304:
4201 return "Not Modified"; /* RFC2616 Section 10.3.5 */
4202 case 305:
4203 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
4204 case 307:
4205 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
4206 case 308:
4207 return "Permanent Redirect"; /* RFC7238 Section 3 */
4208
4209 /* RFC2616 Section 10.4 - Client Error 4xx */
4210 case 400:
4211 return "Bad Request"; /* RFC2616 Section 10.4.1 */
4212 case 401:
4213 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
4214 case 402:
4215 return "Payment Required"; /* RFC2616 Section 10.4.3 */
4216 case 403:
4217 return "Forbidden"; /* RFC2616 Section 10.4.4 */
4218 case 404:
4219 return "Not Found"; /* RFC2616 Section 10.4.5 */
4220 case 405:
4221 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
4222 case 406:
4223 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
4224 case 407:
4225 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
4226 case 408:
4227 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
4228 case 409:
4229 return "Conflict"; /* RFC2616 Section 10.4.10 */
4230 case 410:
4231 return "Gone"; /* RFC2616 Section 10.4.11 */
4232 case 411:
4233 return "Length Required"; /* RFC2616 Section 10.4.12 */
4234 case 412:
4235 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
4236 case 413:
4237 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
4238 case 414:
4239 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
4240 case 415:
4241 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
4242 case 416:
4243 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17
4244 */
4245 case 417:
4246 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
4247
4248 case 421:
4249 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
4250 case 422:
4251 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
4252 * Section 11.2 */
4253 case 423:
4254 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
4255 case 424:
4256 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
4257 * Section 11.4 */
4258
4259 case 426:
4260 return "Upgrade Required"; /* RFC 2817 Section 4 */
4261
4262 case 428:
4263 return "Precondition Required"; /* RFC 6585, Section 3 */
4264 case 429:
4265 return "Too Many Requests"; /* RFC 6585, Section 4 */
4266
4267 case 431:
4268 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
4269
4270 case 451:
4271 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
4272 * Section 3 */
4273
4274 /* RFC2616 Section 10.5 - Server Error 5xx */
4275 case 500:
4276 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
4277 case 501:
4278 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
4279 case 502:
4280 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
4281 case 503:
4282 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
4283 case 504:
4284 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
4285 case 505:
4286 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
4287 case 506:
4288 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
4289 case 507:
4290 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
4291 * Section 11.5 */
4292 case 508:
4293 return "Loop Detected"; /* RFC5842 Section 7.1 */
4294
4295 case 510:
4296 return "Not Extended"; /* RFC 2774, Section 7 */
4297 case 511:
4298 return "Network Authentication Required"; /* RFC 6585, Section 6 */
4299
4300 /* Other status codes, not shown in the IANA HTTP status code
4301 * assignment.
4302 * E.g., "de facto" standards due to common use, ... */
4303 case 418:
4304 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
4305 case 419:
4306 return "Authentication Timeout"; /* common use */
4307 case 420:
4308 return "Enhance Your Calm"; /* common use */
4309 case 440:
4310 return "Login Timeout"; /* common use */
4311 case 509:
4312 return "Bandwidth Limit Exceeded"; /* common use */
4313
4314 default:
4315 /* This error code is unknown. This should not happen. */
4316 if (conn) {
4317 mg_cry_internal(conn,
4318 "Unknown HTTP response code: %u",
4319 response_code);
4320 }
4321
4322 /* Return at least a category according to RFC 2616 Section 10. */
4323 if (response_code >= 100 && response_code < 200) {
4324 /* Unknown informational status code */
4325 return "Information";
4326 }
4327 if (response_code >= 200 && response_code < 300) {
4328 /* Unknown success code */
4329 return "Success";
4330 }
4331 if (response_code >= 300 && response_code < 400) {
4332 /* Unknown redirection code */
4333 return "Redirection";
4334 }
4335 if (response_code >= 400 && response_code < 500) {
4336 /* Unknown request error code */
4337 return "Client Error";
4338 }
4339 if (response_code >= 500 && response_code < 600) {
4340 /* Unknown server error code */
4341 return "Server Error";
4342 }
4343
4344 /* Response code not even within reasonable range */
4345 return "";
4346 }
4347}
4348
4349
4350static int
4352 int status,
4353 const char *fmt,
4354 va_list args)
4355{
4356 char errmsg_buf[MG_BUF_LEN];
4357 va_list ap;
4358 int has_body;
4359
4360#if !defined(NO_FILESYSTEMS)
4361 char path_buf[UTF8_PATH_MAX];
4362 int len, i, page_handler_found, scope, truncated;
4363 const char *error_handler = NULL;
4364 struct mg_file error_page_file = STRUCT_FILE_INITIALIZER;
4365 const char *error_page_file_ext, *tstr;
4366#endif /* NO_FILESYSTEMS */
4367 int handled_by_callback = 0;
4368
4369 if ((conn == NULL) || (fmt == NULL)) {
4370 return -2;
4371 }
4372
4373 /* Set status (for log) */
4374 conn->status_code = status;
4375
4376 /* Errors 1xx, 204 and 304 MUST NOT send a body */
4377 has_body = ((status > 199) && (status != 204) && (status != 304));
4378
4379 /* Prepare message in buf, if required */
4380 if (has_body
4381 || (!conn->in_error_handler
4382 && (conn->phys_ctx->callbacks.http_error != NULL))) {
4383 /* Store error message in errmsg_buf */
4384 va_copy(ap, args);
4385 mg_vsnprintf(conn, NULL, errmsg_buf, sizeof(errmsg_buf), fmt, ap);
4386 va_end(ap);
4387 /* In a debug build, print all html errors */
4388 DEBUG_TRACE("Error %i - [%s]", status, errmsg_buf);
4389 }
4390
4391 /* If there is a http_error callback, call it.
4392 * But don't do it recursively, if callback calls mg_send_http_error again.
4393 */
4394 if (!conn->in_error_handler
4395 && (conn->phys_ctx->callbacks.http_error != NULL)) {
4396 /* Mark in_error_handler to avoid recursion and call user callback. */
4397 conn->in_error_handler = 1;
4398 handled_by_callback =
4399 (conn->phys_ctx->callbacks.http_error(conn, status, errmsg_buf)
4400 == 0);
4401 conn->in_error_handler = 0;
4402 }
4403
4404 if (!handled_by_callback) {
4405 /* Check for recursion */
4406 if (conn->in_error_handler) {
4408 "Recursion when handling error %u - fall back to default",
4409 status);
4410#if !defined(NO_FILESYSTEMS)
4411 } else {
4412 /* Send user defined error pages, if defined */
4413 error_handler = conn->dom_ctx->config[ERROR_PAGES];
4414 error_page_file_ext = conn->dom_ctx->config[INDEX_FILES];
4415 page_handler_found = 0;
4416
4417 if (error_handler != NULL) {
4418 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4419 switch (scope) {
4420 case 1: /* Handler for specific error, e.g. 404 error */
4421 mg_snprintf(conn,
4422 &truncated,
4423 path_buf,
4424 sizeof(path_buf) - 32,
4425 "%serror%03u.",
4426 error_handler,
4427 status);
4428 break;
4429 case 2: /* Handler for error group, e.g., 5xx error
4430 * handler
4431 * for all server errors (500-599) */
4432 mg_snprintf(conn,
4433 &truncated,
4434 path_buf,
4435 sizeof(path_buf) - 32,
4436 "%serror%01uxx.",
4437 error_handler,
4438 status / 100);
4439 break;
4440 default: /* Handler for all errors */
4441 mg_snprintf(conn,
4442 &truncated,
4443 path_buf,
4444 sizeof(path_buf) - 32,
4445 "%serror.",
4446 error_handler);
4447 break;
4448 }
4449
4450 /* String truncation in buf may only occur if
4451 * error_handler is too long. This string is
4452 * from the config, not from a client. */
4453 (void)truncated;
4454
4455 /* The following code is redundant, but it should avoid
4456 * false positives in static source code analyzers and
4457 * vulnerability scanners.
4458 */
4459 path_buf[sizeof(path_buf) - 32] = 0;
4460 len = (int)strlen(path_buf);
4461 if (len > (int)sizeof(path_buf) - 32) {
4462 len = (int)sizeof(path_buf) - 32;
4463 }
4464
4465 /* Start with the file extenstion from the configuration. */
4466 tstr = strchr(error_page_file_ext, '.');
4467
4468 while (tstr) {
4469 for (i = 1;
4470 (i < 32) && (tstr[i] != 0) && (tstr[i] != ',');
4471 i++) {
4472 /* buffer overrun is not possible here, since
4473 * (i < 32) && (len < sizeof(path_buf) - 32)
4474 * ==> (i + len) < sizeof(path_buf) */
4475 path_buf[len + i - 1] = tstr[i];
4476 }
4477 /* buffer overrun is not possible here, since
4478 * (i <= 32) && (len < sizeof(path_buf) - 32)
4479 * ==> (i + len) <= sizeof(path_buf) */
4480 path_buf[len + i - 1] = 0;
4481
4482 if (mg_stat(conn, path_buf, &error_page_file.stat)) {
4483 DEBUG_TRACE("Check error page %s - found",
4484 path_buf);
4485 page_handler_found = 1;
4486 break;
4487 }
4488 DEBUG_TRACE("Check error page %s - not found",
4489 path_buf);
4490
4491 /* Continue with the next file extenstion from the
4492 * configuration (if there is a next one). */
4493 tstr = strchr(tstr + i, '.');
4494 }
4495 }
4496 }
4497
4498 if (page_handler_found) {
4499 conn->in_error_handler = 1;
4500 handle_file_based_request(conn, path_buf, &error_page_file);
4501 conn->in_error_handler = 0;
4502 return 0;
4503 }
4504#endif /* NO_FILESYSTEMS */
4505 }
4506
4507 /* No custom error page. Send default error page. */
4508 conn->must_close = 1;
4509 mg_response_header_start(conn, status);
4512 if (has_body) {
4514 "Content-Type",
4515 "text/plain; charset=utf-8",
4516 -1);
4517 }
4519
4520 /* HTTP responses 1xx, 204 and 304 MUST NOT send a body */
4521 if (has_body) {
4522 /* For other errors, send a generic error message. */
4523 const char *status_text = mg_get_response_code_text(conn, status);
4524 mg_printf(conn, "Error %d: %s\n", status, status_text);
4525 mg_write(conn, errmsg_buf, strlen(errmsg_buf));
4526
4527 } else {
4528 /* No body allowed. Close the connection. */
4529 DEBUG_TRACE("Error %i", status);
4530 }
4531 }
4532 return 0;
4533}
4534
4535
4536int
4537mg_send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
4538{
4539 va_list ap;
4540 int ret;
4541
4542 va_start(ap, fmt);
4543 ret = mg_send_http_error_impl(conn, status, fmt, ap);
4544 va_end(ap);
4545
4546 return ret;
4547}
4548
4549
4550int
4552 const char *mime_type,
4553 long long content_length)
4554{
4555 if ((mime_type == NULL) || (*mime_type == 0)) {
4556 /* No content type defined: default to text/html */
4557 mime_type = "text/html";
4558 }
4559
4560 mg_response_header_start(conn, 200);
4563 mg_response_header_add(conn, "Content-Type", mime_type, -1);
4564 if (content_length < 0) {
4565 /* Size not known. Use chunked encoding (HTTP/1.x) */
4566 if (conn->protocol_type == PROTOCOL_TYPE_HTTP1) {
4567 /* Only HTTP/1.x defines "chunked" encoding, HTTP/2 does not*/
4568 mg_response_header_add(conn, "Transfer-Encoding", "chunked", -1);
4569 }
4570 } else {
4571 char len[32];
4572 int trunc = 0;
4573 mg_snprintf(conn,
4574 &trunc,
4575 len,
4576 sizeof(len),
4577 "%" UINT64_FMT,
4578 (uint64_t)content_length);
4579 if (!trunc) {
4580 /* Since 32 bytes is enough to hold any 64 bit decimal number,
4581 * !trunc is always true */
4582 mg_response_header_add(conn, "Content-Length", len, -1);
4583 }
4584 }
4586
4587 return 0;
4588}
4589
4590
4591int
4593 const char *target_url,
4594 int redirect_code)
4595{
4596 /* Send a 30x redirect response.
4597 *
4598 * Redirect types (status codes):
4599 *
4600 * Status | Perm/Temp | Method | Version
4601 * 301 | permanent | POST->GET undefined | HTTP/1.0
4602 * 302 | temporary | POST->GET undefined | HTTP/1.0
4603 * 303 | temporary | always use GET | HTTP/1.1
4604 * 307 | temporary | always keep method | HTTP/1.1
4605 * 308 | permanent | always keep method | HTTP/1.1
4606 */
4607 const char *redirect_text;
4608 int ret;
4609 size_t content_len = 0;
4610#if defined(MG_SEND_REDIRECT_BODY)
4611 char reply[MG_BUF_LEN];
4612#endif
4613
4614 /* In case redirect_code=0, use 307. */
4615 if (redirect_code == 0) {
4616 redirect_code = 307;
4617 }
4618
4619 /* In case redirect_code is none of the above, return error. */
4620 if ((redirect_code != 301) && (redirect_code != 302)
4621 && (redirect_code != 303) && (redirect_code != 307)
4622 && (redirect_code != 308)) {
4623 /* Parameter error */
4624 return -2;
4625 }
4626
4627 /* Get proper text for response code */
4628 redirect_text = mg_get_response_code_text(conn, redirect_code);
4629
4630 /* If target_url is not defined, redirect to "/". */
4631 if ((target_url == NULL) || (*target_url == 0)) {
4632 target_url = "/";
4633 }
4634
4635#if defined(MG_SEND_REDIRECT_BODY)
4636 /* TODO: condition name? */
4637
4638 /* Prepare a response body with a hyperlink.
4639 *
4640 * According to RFC2616 (and RFC1945 before):
4641 * Unless the request method was HEAD, the entity of the
4642 * response SHOULD contain a short hypertext note with a hyperlink to
4643 * the new URI(s).
4644 *
4645 * However, this response body is not useful in M2M communication.
4646 * Probably the original reason in the RFC was, clients not supporting
4647 * a 30x HTTP redirect could still show the HTML page and let the user
4648 * press the link. Since current browsers support 30x HTTP, the additional
4649 * HTML body does not seem to make sense anymore.
4650 *
4651 * The new RFC7231 (Section 6.4) does no longer recommend it ("SHOULD"),
4652 * but it only notes:
4653 * The server's response payload usually contains a short
4654 * hypertext note with a hyperlink to the new URI(s).
4655 *
4656 * Deactivated by default. If you need the 30x body, set the define.
4657 */
4659 conn,
4660 NULL /* ignore truncation */,
4661 reply,
4662 sizeof(reply),
4663 "<html><head>%s</head><body><a href=\"%s\">%s</a></body></html>",
4664 redirect_text,
4665 target_url,
4666 target_url);
4667 content_len = strlen(reply);
4668#endif
4669
4670 /* Do not send any additional header. For all other options,
4671 * including caching, there are suitable defaults. */
4672 ret = mg_printf(conn,
4673 "HTTP/1.1 %i %s\r\n"
4674 "Location: %s\r\n"
4675 "Content-Length: %u\r\n"
4676 "Connection: %s\r\n\r\n",
4677 redirect_code,
4678 redirect_text,
4679 target_url,
4680 (unsigned int)content_len,
4682
4683#if defined(MG_SEND_REDIRECT_BODY)
4684 /* Send response body */
4685 if (ret > 0) {
4686 /* ... unless it is a HEAD request */
4687 if (0 != strcmp(conn->request_info.request_method, "HEAD")) {
4688 ret = mg_write(conn, reply, content_len);
4689 }
4690 }
4691#endif
4692
4693 return (ret > 0) ? ret : -1;
4694}
4695
4696
4697#if defined(_WIN32)
4698/* Create substitutes for POSIX functions in Win32. */
4699
4700#if defined(GCC_DIAGNOSTIC)
4701/* Show no warning in case system functions are not used. */
4702#pragma GCC diagnostic push
4703#pragma GCC diagnostic ignored "-Wunused-function"
4704#endif
4705
4706
4707static int
4708pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
4709{
4710 (void)unused;
4711 /* Always initialize as PTHREAD_MUTEX_RECURSIVE */
4712 InitializeCriticalSection(&mutex->sec);
4713 return 0;
4714}
4715
4716
4717static int
4718pthread_mutex_destroy(pthread_mutex_t *mutex)
4719{
4720 DeleteCriticalSection(&mutex->sec);
4721 return 0;
4722}
4723
4724
4725static int
4726pthread_mutex_lock(pthread_mutex_t *mutex)
4727{
4728 EnterCriticalSection(&mutex->sec);
4729 return 0;
4730}
4731
4732
4733static int
4734pthread_mutex_unlock(pthread_mutex_t *mutex)
4735{
4736 LeaveCriticalSection(&mutex->sec);
4737 return 0;
4738}
4739
4740
4742static int
4743pthread_cond_init(pthread_cond_t *cv, const void *unused)
4744{
4745 (void)unused;
4746 (void)pthread_mutex_init(&cv->threadIdSec, &pthread_mutex_attr);
4747 cv->waiting_thread = NULL;
4748 return 0;
4749}
4750
4751
4753static int
4754pthread_cond_timedwait(pthread_cond_t *cv,
4755 pthread_mutex_t *mutex,
4756 FUNCTION_MAY_BE_UNUSED const struct timespec *abstime)
4757{
4758 struct mg_workerTLS **ptls,
4759 *tls = (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
4760 int ok;
4761 uint64_t nsnow, nswaitabs;
4762 int64_t nswaitrel;
4763 DWORD mswaitrel;
4764
4765 pthread_mutex_lock(&cv->threadIdSec);
4766 /* Add this thread to cv's waiting list */
4767 ptls = &cv->waiting_thread;
4768 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
4769 ;
4770 tls->next_waiting_thread = NULL;
4771 *ptls = tls;
4772 pthread_mutex_unlock(&cv->threadIdSec);
4773
4774 if (abstime) {
4775 nsnow = mg_get_current_time_ns();
4776 nswaitabs =
4777 (((uint64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4778 nswaitrel = nswaitabs - nsnow;
4779 if (nswaitrel < 0) {
4780 nswaitrel = 0;
4781 }
4782 mswaitrel = (DWORD)(nswaitrel / 1000000);
4783 } else {
4784 mswaitrel = (DWORD)INFINITE;
4785 }
4786
4787 pthread_mutex_unlock(mutex);
4788 ok = (WAIT_OBJECT_0
4789 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
4790 if (!ok) {
4791 ok = 1;
4792 pthread_mutex_lock(&cv->threadIdSec);
4793 ptls = &cv->waiting_thread;
4794 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
4795 if (*ptls == tls) {
4796 *ptls = tls->next_waiting_thread;
4797 ok = 0;
4798 break;
4799 }
4800 }
4801 pthread_mutex_unlock(&cv->threadIdSec);
4802 if (ok) {
4803 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4804 (DWORD)INFINITE);
4805 }
4806 }
4807 /* This thread has been removed from cv's waiting list */
4808 pthread_mutex_lock(mutex);
4809
4810 return ok ? 0 : -1;
4811}
4812
4813
4815static int
4816pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
4817{
4818 return pthread_cond_timedwait(cv, mutex, NULL);
4819}
4820
4821
4823static int
4824pthread_cond_signal(pthread_cond_t *cv)
4825{
4826 HANDLE wkup = NULL;
4827 BOOL ok = FALSE;
4828
4829 pthread_mutex_lock(&cv->threadIdSec);
4830 if (cv->waiting_thread) {
4831 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4832 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
4833
4834 ok = SetEvent(wkup);
4835 DEBUG_ASSERT(ok);
4836 }
4837 pthread_mutex_unlock(&cv->threadIdSec);
4838
4839 return ok ? 0 : 1;
4840}
4841
4842
4844static int
4845pthread_cond_broadcast(pthread_cond_t *cv)
4846{
4847 pthread_mutex_lock(&cv->threadIdSec);
4848 while (cv->waiting_thread) {
4849 pthread_cond_signal(cv);
4850 }
4851 pthread_mutex_unlock(&cv->threadIdSec);
4852
4853 return 0;
4854}
4855
4856
4858static int
4859pthread_cond_destroy(pthread_cond_t *cv)
4860{
4861 pthread_mutex_lock(&cv->threadIdSec);
4862 DEBUG_ASSERT(cv->waiting_thread == NULL);
4863 pthread_mutex_unlock(&cv->threadIdSec);
4864 pthread_mutex_destroy(&cv->threadIdSec);
4865
4866 return 0;
4867}
4868
4869
4870#if defined(ALTERNATIVE_QUEUE)
4872static void *
4873event_create(void)
4874{
4875 return (void *)CreateEvent(NULL, FALSE, FALSE, NULL);
4876}
4877
4878
4880static int
4881event_wait(void *eventhdl)
4882{
4883 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
4884 return (res == WAIT_OBJECT_0);
4885}
4886
4887
4889static int
4890event_signal(void *eventhdl)
4891{
4892 return (int)SetEvent((HANDLE)eventhdl);
4893}
4894
4895
4897static void
4898event_destroy(void *eventhdl)
4899{
4900 CloseHandle((HANDLE)eventhdl);
4901}
4902#endif
4903
4904
4905#if defined(GCC_DIAGNOSTIC)
4906/* Enable unused function warning again */
4907#pragma GCC diagnostic pop
4908#endif
4909
4910
4911/* For Windows, change all slashes to backslashes in path names. */
4912static void
4913change_slashes_to_backslashes(char *path)
4914{
4915 int i;
4916
4917 for (i = 0; path[i] != '\0'; i++) {
4918 if (path[i] == '/') {
4919 path[i] = '\\';
4920 }
4921
4922 /* remove double backslash (check i > 0 to preserve UNC paths,
4923 * like \\server\file.txt) */
4924 if ((i > 0) && (path[i] == '\\')) {
4925 while ((path[i + 1] == '\\') || (path[i + 1] == '/')) {
4926 (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
4927 }
4928 }
4929 }
4930}
4931
4932
4933static int
4934mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2)
4935{
4936 int diff;
4937
4938 do {
4939 diff = ((*s1 >= L'A') && (*s1 <= L'Z') ? (*s1 - L'A' + L'a') : *s1)
4940 - ((*s2 >= L'A') && (*s2 <= L'Z') ? (*s2 - L'A' + L'a') : *s2);
4941 s1++;
4942 s2++;
4943 } while ((diff == 0) && (s1[-1] != L'\0'));
4944
4945 return diff;
4946}
4947
4948
4949/* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
4950 * wbuf and wbuf_len is a target buffer and its length. */
4951static void
4952path_to_unicode(const struct mg_connection *conn,
4953 const char *path,
4954 wchar_t *wbuf,
4955 size_t wbuf_len)
4956{
4957 char buf[UTF8_PATH_MAX], buf2[UTF8_PATH_MAX];
4958 wchar_t wbuf2[UTF16_PATH_MAX + 1];
4959 DWORD long_len, err;
4960 int (*fcompare)(const wchar_t *, const wchar_t *) = mg_wcscasecmp;
4961
4962 mg_strlcpy(buf, path, sizeof(buf));
4963 change_slashes_to_backslashes(buf);
4964
4965 /* Convert to Unicode and back. If doubly-converted string does not
4966 * match the original, something is fishy, reject. */
4967 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
4968 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
4969 WideCharToMultiByte(
4970 CP_UTF8, 0, wbuf, (int)wbuf_len, buf2, sizeof(buf2), NULL, NULL);
4971 if (strcmp(buf, buf2) != 0) {
4972 wbuf[0] = L'\0';
4973 }
4974
4975 /* Windows file systems are not case sensitive, but you can still use
4976 * uppercase and lowercase letters (on all modern file systems).
4977 * The server can check if the URI uses the same upper/lowercase
4978 * letters an the file system, effectively making Windows servers
4979 * case sensitive (like Linux servers are). It is still not possible
4980 * to use two files with the same name in different cases on Windows
4981 * (like /a and /A) - this would be possible in Linux.
4982 * As a default, Windows is not case sensitive, but the case sensitive
4983 * file name check can be activated by an additional configuration. */
4984 if (conn) {
4985 if (conn->dom_ctx->config[CASE_SENSITIVE_FILES]
4986 && !mg_strcasecmp(conn->dom_ctx->config[CASE_SENSITIVE_FILES],
4987 "yes")) {
4988 /* Use case sensitive compare function */
4989 fcompare = wcscmp;
4990 }
4991 }
4992 (void)conn; /* conn is currently unused */
4993
4994 /* Only accept a full file path, not a Windows short (8.3) path. */
4995 memset(wbuf2, 0, ARRAY_SIZE(wbuf2) * sizeof(wchar_t));
4996 long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1);
4997 if (long_len == 0) {
4998 err = GetLastError();
4999 if (err == ERROR_FILE_NOT_FOUND) {
5000 /* File does not exist. This is not always a problem here. */
5001 return;
5002 }
5003 }
5004 if ((long_len >= ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
5005 /* Short name is used. */
5006 wbuf[0] = L'\0';
5007 }
5008}
5009
5010
5011#if !defined(NO_FILESYSTEMS)
5012/* Get file information, return 1 if file exists, 0 if not */
5013static int
5014mg_stat(const struct mg_connection *conn,
5015 const char *path,
5016 struct mg_file_stat *filep)
5017{
5018 wchar_t wbuf[UTF16_PATH_MAX];
5019 WIN32_FILE_ATTRIBUTE_DATA info;
5020 time_t creation_time;
5021 size_t len;
5022
5023 if (!filep) {
5024 return 0;
5025 }
5026 memset(filep, 0, sizeof(*filep));
5027
5028 if (mg_path_suspicious(conn, path)) {
5029 return 0;
5030 }
5031
5032 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
5033 /* Windows happily opens files with some garbage at the end of file name.
5034 * For example, fopen("a.cgi ", "r") on Windows successfully opens
5035 * "a.cgi", despite one would expect an error back. */
5036 len = strlen(path);
5037 if ((len > 0) && (path[len - 1] != ' ') && (path[len - 1] != '.')
5038 && (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0)) {
5039 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
5040 filep->last_modified =
5041 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
5042 info.ftLastWriteTime.dwHighDateTime);
5043
5044 /* On Windows, the file creation time can be higher than the
5045 * modification time, e.g. when a file is copied.
5046 * Since the Last-Modified timestamp is used for caching
5047 * it should be based on the most recent timestamp. */
5048 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
5049 info.ftCreationTime.dwHighDateTime);
5050 if (creation_time > filep->last_modified) {
5051 filep->last_modified = creation_time;
5052 }
5053
5054 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
5055 return 1;
5056 }
5057
5058 return 0;
5059}
5060#endif
5061
5062
5063static int
5064mg_remove(const struct mg_connection *conn, const char *path)
5065{
5066 wchar_t wbuf[UTF16_PATH_MAX];
5067 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
5068 return DeleteFileW(wbuf) ? 0 : -1;
5069}
5070
5071
5072static int
5073mg_mkdir(const struct mg_connection *conn, const char *path, int mode)
5074{
5075 wchar_t wbuf[UTF16_PATH_MAX];
5076 (void)mode;
5077 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
5078 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
5079}
5080
5081
5082/* Create substitutes for POSIX functions in Win32. */
5083
5084#if defined(GCC_DIAGNOSTIC)
5085/* Show no warning in case system functions are not used. */
5086#pragma GCC diagnostic push
5087#pragma GCC diagnostic ignored "-Wunused-function"
5088#endif
5089
5090
5091/* Implementation of POSIX opendir/closedir/readdir for Windows. */
5093static DIR *
5094mg_opendir(const struct mg_connection *conn, const char *name)
5095{
5096 DIR *dir = NULL;
5097 wchar_t wpath[UTF16_PATH_MAX];
5098 DWORD attrs;
5099
5100 if (name == NULL) {
5101 SetLastError(ERROR_BAD_ARGUMENTS);
5102 } else if ((dir = (DIR *)mg_malloc(sizeof(*dir))) == NULL) {
5103 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5104 } else {
5105 path_to_unicode(conn, name, wpath, ARRAY_SIZE(wpath));
5106 attrs = GetFileAttributesW(wpath);
5107 if ((wcslen(wpath) + 2 < ARRAY_SIZE(wpath)) && (attrs != 0xFFFFFFFF)
5108 && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
5109 (void)wcscat(wpath, L"\\*");
5110 dir->handle = FindFirstFileW(wpath, &dir->info);
5111 dir->result.d_name[0] = '\0';
5112 } else {
5113 mg_free(dir);
5114 dir = NULL;
5115 }
5116 }
5117
5118 return dir;
5119}
5120
5121
5123static int
5124mg_closedir(DIR *dir)
5125{
5126 int result = 0;
5127
5128 if (dir != NULL) {
5129 if (dir->handle != INVALID_HANDLE_VALUE)
5130 result = FindClose(dir->handle) ? 0 : -1;
5131
5132 mg_free(dir);
5133 } else {
5134 result = -1;
5135 SetLastError(ERROR_BAD_ARGUMENTS);
5136 }
5137
5138 return result;
5139}
5140
5141
5143static struct dirent *
5144mg_readdir(DIR *dir)
5145{
5146 struct dirent *result = 0;
5147
5148 if (dir) {
5149 if (dir->handle != INVALID_HANDLE_VALUE) {
5150 result = &dir->result;
5151 (void)WideCharToMultiByte(CP_UTF8,
5152 0,
5153 dir->info.cFileName,
5154 -1,
5155 result->d_name,
5156 sizeof(result->d_name),
5157 NULL,
5158 NULL);
5159
5160 if (!FindNextFileW(dir->handle, &dir->info)) {
5161 (void)FindClose(dir->handle);
5162 dir->handle = INVALID_HANDLE_VALUE;
5163 }
5164
5165 } else {
5166 SetLastError(ERROR_FILE_NOT_FOUND);
5167 }
5168 } else {
5169 SetLastError(ERROR_BAD_ARGUMENTS);
5170 }
5171
5172 return result;
5173}
5174
5175
5176#if !defined(HAVE_POLL)
5177#undef POLLIN
5178#undef POLLPRI
5179#undef POLLOUT
5180#undef POLLERR
5181#define POLLIN (1) /* Data ready - read will not block. */
5182#define POLLPRI (2) /* Priority data ready. */
5183#define POLLOUT (4) /* Send queue not full - write will not block. */
5184#define POLLERR (8) /* Error event */
5185
5187static int
5188poll(struct mg_pollfd *pfd, unsigned int n, int milliseconds)
5189{
5190 struct timeval tv;
5191 fd_set rset;
5192 fd_set wset;
5193 fd_set eset;
5194 unsigned int i;
5195 int result;
5196 SOCKET maxfd = 0;
5197
5198 memset(&tv, 0, sizeof(tv));
5199 tv.tv_sec = milliseconds / 1000;
5200 tv.tv_usec = (milliseconds % 1000) * 1000;
5201 FD_ZERO(&rset);
5202 FD_ZERO(&wset);
5203 FD_ZERO(&eset);
5204
5205 for (i = 0; i < n; i++) {
5206 if (pfd[i].events & (POLLIN | POLLOUT | POLLERR)) {
5207 if (pfd[i].events & POLLIN) {
5208 FD_SET(pfd[i].fd, &rset);
5209 }
5210 if (pfd[i].events & POLLOUT) {
5211 FD_SET(pfd[i].fd, &wset);
5212 }
5213 /* Check for errors for any FD in the set */
5214 FD_SET(pfd[i].fd, &eset);
5215 }
5216 pfd[i].revents = 0;
5217
5218 if (pfd[i].fd > maxfd) {
5219 maxfd = pfd[i].fd;
5220 }
5221 }
5222
5223 if ((result = select((int)maxfd + 1, &rset, &wset, &eset, &tv)) > 0) {
5224 for (i = 0; i < n; i++) {
5225 if (FD_ISSET(pfd[i].fd, &rset)) {
5226 pfd[i].revents |= POLLIN;
5227 }
5228 if (FD_ISSET(pfd[i].fd, &wset)) {
5229 pfd[i].revents |= POLLOUT;
5230 }
5231 if (FD_ISSET(pfd[i].fd, &eset)) {
5232 pfd[i].revents |= POLLERR;
5233 }
5234 }
5235 }
5236
5237 /* We should subtract the time used in select from remaining
5238 * "milliseconds", in particular if called from mg_poll with a
5239 * timeout quantum.
5240 * Unfortunately, the remaining time is not stored in "tv" in all
5241 * implementations, so the result in "tv" must be considered undefined.
5242 * See http://man7.org/linux/man-pages/man2/select.2.html */
5243
5244 return result;
5245}
5246#endif /* HAVE_POLL */
5247
5248
5249#if defined(GCC_DIAGNOSTIC)
5250/* Enable unused function warning again */
5251#pragma GCC diagnostic pop
5252#endif
5253
5254
5255static void
5257 const struct mg_connection *conn /* may be null */,
5258 struct mg_context *ctx /* may be null */)
5259{
5260 (void)conn; /* Unused. */
5261 (void)ctx;
5262
5263 (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
5264}
5265
5266
5267int
5269{
5270#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5271 /* Compile-time option to control stack size, e.g.
5272 * -DUSE_STACK_SIZE=16384
5273 */
5274 return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p)
5275 == ((uintptr_t)(-1L)))
5276 ? -1
5277 : 0);
5278#else
5279 return (
5280 (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L)))
5281 ? -1
5282 : 0);
5283#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
5284}
5285
5286
5287/* Start a thread storing the thread context. */
5288static int
5289mg_start_thread_with_id(unsigned(__stdcall *f)(void *),
5290 void *p,
5291 pthread_t *threadidptr)
5292{
5293 uintptr_t uip;
5294 HANDLE threadhandle;
5295 int result = -1;
5296
5297 uip = _beginthreadex(NULL, 0, f, p, 0, NULL);
5298 threadhandle = (HANDLE)uip;
5299 if ((uip != 0) && (threadidptr != NULL)) {
5300 *threadidptr = threadhandle;
5301 result = 0;
5302 }
5303
5304 return result;
5305}
5306
5307
5308/* Wait for a thread to finish. */
5309static int
5310mg_join_thread(pthread_t threadid)
5311{
5312 int result;
5313 DWORD dwevent;
5314
5315 result = -1;
5316 dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE);
5317 if (dwevent == WAIT_FAILED) {
5318 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO);
5319 } else {
5320 if (dwevent == WAIT_OBJECT_0) {
5321 CloseHandle(threadid);
5322 result = 0;
5323 }
5324 }
5325
5326 return result;
5327}
5328
5329#if !defined(NO_SSL_DL) && !defined(NO_SSL)
5330/* If SSL is loaded dynamically, dlopen/dlclose is required. */
5331/* Create substitutes for POSIX functions in Win32. */
5332
5333#if defined(GCC_DIAGNOSTIC)
5334/* Show no warning in case system functions are not used. */
5335#pragma GCC diagnostic push
5336#pragma GCC diagnostic ignored "-Wunused-function"
5337#endif
5338
5339
5341static HANDLE
5342dlopen(const char *dll_name, int flags)
5343{
5344 wchar_t wbuf[UTF16_PATH_MAX];
5345 (void)flags;
5346 path_to_unicode(NULL, dll_name, wbuf, ARRAY_SIZE(wbuf));
5347 return LoadLibraryW(wbuf);
5348}
5349
5350
5352static int
5353dlclose(void *handle)
5354{
5355 int result;
5356
5357 if (FreeLibrary((HMODULE)handle) != 0) {
5358 result = 0;
5359 } else {
5360 result = -1;
5361 }
5362
5363 return result;
5364}
5365
5366
5367#if defined(GCC_DIAGNOSTIC)
5368/* Enable unused function warning again */
5369#pragma GCC diagnostic pop
5370#endif
5371
5372#endif
5373
5374
5375#if !defined(NO_CGI)
5376#define SIGKILL (0)
5377
5378
5379static int
5380kill(pid_t pid, int sig_num)
5381{
5382 (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
5383 (void)CloseHandle((HANDLE)pid);
5384 return 0;
5385}
5386
5387
5388#if !defined(WNOHANG)
5389#define WNOHANG (1)
5390#endif
5391
5392
5393static pid_t
5394waitpid(pid_t pid, int *status, int flags)
5395{
5396 DWORD timeout = INFINITE;
5397 DWORD waitres;
5398
5399 (void)status; /* Currently not used by any client here */
5400
5401 if ((flags | WNOHANG) == WNOHANG) {
5402 timeout = 0;
5403 }
5404
5405 waitres = WaitForSingleObject((HANDLE)pid, timeout);
5406 if (waitres == WAIT_OBJECT_0) {
5407 return pid;
5408 }
5409 if (waitres == WAIT_TIMEOUT) {
5410 return 0;
5411 }
5412 return (pid_t)-1;
5413}
5414
5415
5416static void
5417trim_trailing_whitespaces(char *s)
5418{
5419 char *e = s + strlen(s);
5420 while ((e > s) && isspace((unsigned char)e[-1])) {
5421 *(--e) = '\0';
5422 }
5423}
5424
5425
5426static pid_t
5427spawn_process(struct mg_connection *conn,
5428 const char *prog,
5429 char *envblk,
5430 char *envp[],
5431 int fdin[2],
5432 int fdout[2],
5433 int fderr[2],
5434 const char *dir,
5435 unsigned char cgi_config_idx)
5436{
5437 HANDLE me;
5438 char *interp;
5439 char *interp_arg = 0;
5440 char full_dir[UTF8_PATH_MAX], cmdline[UTF8_PATH_MAX], buf[UTF8_PATH_MAX];
5441 int truncated;
5442 struct mg_file file = STRUCT_FILE_INITIALIZER;
5443 STARTUPINFOA si;
5444 PROCESS_INFORMATION pi = {0};
5445
5446 (void)envp;
5447
5448 memset(&si, 0, sizeof(si));
5449 si.cb = sizeof(si);
5450
5451 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5452 si.wShowWindow = SW_HIDE;
5453
5454 me = GetCurrentProcess();
5455 DuplicateHandle(me,
5456 (HANDLE)_get_osfhandle(fdin[0]),
5457 me,
5458 &si.hStdInput,
5459 0,
5460 TRUE,
5461 DUPLICATE_SAME_ACCESS);
5462 DuplicateHandle(me,
5463 (HANDLE)_get_osfhandle(fdout[1]),
5464 me,
5465 &si.hStdOutput,
5466 0,
5467 TRUE,
5468 DUPLICATE_SAME_ACCESS);
5469 DuplicateHandle(me,
5470 (HANDLE)_get_osfhandle(fderr[1]),
5471 me,
5472 &si.hStdError,
5473 0,
5474 TRUE,
5475 DUPLICATE_SAME_ACCESS);
5476
5477 /* Mark handles that should not be inherited. See
5478 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
5479 */
5480 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5481 HANDLE_FLAG_INHERIT,
5482 0);
5483 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5484 HANDLE_FLAG_INHERIT,
5485 0);
5486 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5487 HANDLE_FLAG_INHERIT,
5488 0);
5489
5490 /* First check, if there is a CGI interpreter configured for all CGI
5491 * scripts. */
5492 interp = conn->dom_ctx->config[CGI_INTERPRETER + cgi_config_idx];
5493 if (interp != NULL) {
5494 /* If there is a configured interpreter, check for additional arguments
5495 */
5496 interp_arg =
5497 conn->dom_ctx->config[CGI_INTERPRETER_ARGS + cgi_config_idx];
5498 } else {
5499 /* Otherwise, the interpreter must be stated in the first line of the
5500 * CGI script file, after a #! (shebang) mark. */
5501 buf[0] = buf[1] = '\0';
5502
5503 /* Get the full script path */
5505 conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
5506
5507 if (truncated) {
5508 pi.hProcess = (pid_t)-1;
5509 goto spawn_cleanup;
5510 }
5511
5512 /* Open the script file, to read the first line */
5513 if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) {
5514
5515 /* Read the first line of the script into the buffer */
5516 mg_fgets(buf, sizeof(buf), &file);
5517 (void)mg_fclose(&file.access); /* ignore error on read only file */
5518 buf[sizeof(buf) - 1] = '\0';
5519 }
5520
5521 if ((buf[0] == '#') && (buf[1] == '!')) {
5522 trim_trailing_whitespaces(buf + 2);
5523 } else {
5524 buf[2] = '\0';
5525 }
5526 interp = buf + 2;
5527 }
5528
5529 GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
5530
5531 if (interp[0] != '\0') {
5532 /* This is an interpreted script file. We must call the interpreter. */
5533 if ((interp_arg != 0) && (interp_arg[0] != 0)) {
5534 mg_snprintf(conn,
5535 &truncated,
5536 cmdline,
5537 sizeof(cmdline),
5538 "\"%s\" %s \"%s\\%s\"",
5539 interp,
5540 interp_arg,
5541 full_dir,
5542 prog);
5543 } else {
5544 mg_snprintf(conn,
5545 &truncated,
5546 cmdline,
5547 sizeof(cmdline),
5548 "\"%s\" \"%s\\%s\"",
5549 interp,
5550 full_dir,
5551 prog);
5552 }
5553 } else {
5554 /* This is (probably) a compiled program. We call it directly. */
5555 mg_snprintf(conn,
5556 &truncated,
5557 cmdline,
5558 sizeof(cmdline),
5559 "\"%s\\%s\"",
5560 full_dir,
5561 prog);
5562 }
5563
5564 if (truncated) {
5565 pi.hProcess = (pid_t)-1;
5566 goto spawn_cleanup;
5567 }
5568
5569 DEBUG_TRACE("Running [%s]", cmdline);
5570 if (CreateProcessA(NULL,
5571 cmdline,
5572 NULL,
5573 NULL,
5574 TRUE,
5575 CREATE_NEW_PROCESS_GROUP,
5576 envblk,
5577 NULL,
5578 &si,
5579 &pi)
5580 == 0) {
5582 conn, "%s: CreateProcess(%s): %ld", __func__, cmdline, (long)ERRNO);
5583 pi.hProcess = (pid_t)-1;
5584 /* goto spawn_cleanup; */
5585 }
5586
5587spawn_cleanup:
5588 (void)CloseHandle(si.hStdOutput);
5589 (void)CloseHandle(si.hStdError);
5590 (void)CloseHandle(si.hStdInput);
5591 if (pi.hThread != NULL) {
5592 (void)CloseHandle(pi.hThread);
5593 }
5594
5595 return (pid_t)pi.hProcess;
5596}
5597#endif /* !NO_CGI */
5598
5599
5600static int
5602{
5603 unsigned long non_blocking = 0;
5604 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
5605}
5606
5607
5608static int
5610{
5611 unsigned long non_blocking = 1;
5612 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
5613}
5614
5615
5616#else
5617
5618
5619#if !defined(NO_FILESYSTEMS)
5620static int
5621mg_stat(const struct mg_connection *conn,
5622 const char *path,
5623 struct mg_file_stat *filep)
5624{
5625 struct stat st;
5626 if (!filep) {
5627 return 0;
5628 }
5629 memset(filep, 0, sizeof(*filep));
5630
5631 if (mg_path_suspicious(conn, path)) {
5632 return 0;
5633 }
5634
5635 if (0 == stat(path, &st)) {
5636 filep->size = (uint64_t)(st.st_size);
5637 filep->last_modified = st.st_mtime;
5638 filep->is_directory = S_ISDIR(st.st_mode);
5639 return 1;
5640 }
5641
5642 return 0;
5643}
5644#endif /* NO_FILESYSTEMS */
5645
5646
5647static void
5649 const struct mg_connection *conn /* may be null */,
5650 struct mg_context *ctx /* may be null */)
5651{
5652#if defined(__ZEPHYR__)
5653 (void)fd;
5654 (void)conn;
5655 (void)ctx;
5656#else
5657 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5658 if (conn || ctx) {
5659 struct mg_connection fc;
5660 mg_cry_internal((conn ? conn : fake_connection(&fc, ctx)),
5661 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5662 __func__,
5663 strerror(ERRNO));
5664 }
5665 }
5666#endif
5667}
5668
5669
5670int
5672{
5673 pthread_t thread_id;
5674 pthread_attr_t attr;
5675 int result;
5676
5677 (void)pthread_attr_init(&attr);
5678 (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5679
5680#if defined(__ZEPHYR__)
5681 pthread_attr_setstack(&attr, &civetweb_main_stack, ZEPHYR_STACK_SIZE);
5682#elif defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5683 /* Compile-time option to control stack size,
5684 * e.g. -DUSE_STACK_SIZE=16384 */
5685 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5686#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
5687
5688 result = pthread_create(&thread_id, &attr, func, param);
5689 pthread_attr_destroy(&attr);
5690
5691 return result;
5692}
5693
5694
5695/* Start a thread storing the thread context. */
5696static int
5698 void *param,
5699 pthread_t *threadidptr)
5700{
5701 pthread_t thread_id;
5702 pthread_attr_t attr;
5703 int result;
5704
5705 (void)pthread_attr_init(&attr);
5706
5707#if defined(__ZEPHYR__)
5708 pthread_attr_setstack(&attr,
5709 &civetweb_worker_stacks[zephyr_worker_stack_index++],
5710 ZEPHYR_STACK_SIZE);
5711#elif defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5712 /* Compile-time option to control stack size,
5713 * e.g. -DUSE_STACK_SIZE=16384 */
5714 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5715#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
5716
5717 result = pthread_create(&thread_id, &attr, func, param);
5718 pthread_attr_destroy(&attr);
5719 if ((result == 0) && (threadidptr != NULL)) {
5720 *threadidptr = thread_id;
5721 }
5722 return result;
5723}
5724
5725
5726/* Wait for a thread to finish. */
5727static int
5728mg_join_thread(pthread_t threadid)
5729{
5730 int result;
5731
5732 result = pthread_join(threadid, NULL);
5733 return result;
5734}
5735
5736
5737#if !defined(NO_CGI)
5738static pid_t
5740 const char *prog,
5741 char *envblk,
5742 char *envp[],
5743 int fdin[2],
5744 int fdout[2],
5745 int fderr[2],
5746 const char *dir,
5747 unsigned char cgi_config_idx)
5748{
5749 pid_t pid;
5750 const char *interp;
5751
5752 (void)envblk;
5753
5754 if ((pid = fork()) == -1) {
5755 /* Parent */
5756 mg_cry_internal(conn, "%s: fork(): %s", __func__, strerror(ERRNO));
5757 } else if (pid != 0) {
5758 /* Make sure children close parent-side descriptors.
5759 * The caller will close the child-side immediately. */
5760 set_close_on_exec(fdin[1], conn, NULL); /* stdin write */
5761 set_close_on_exec(fdout[0], conn, NULL); /* stdout read */
5762 set_close_on_exec(fderr[0], conn, NULL); /* stderr read */
5763 } else {
5764 /* Child */
5765 if (chdir(dir) != 0) {
5767 conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
5768 } else if (dup2(fdin[0], 0) == -1) {
5769 mg_cry_internal(conn,
5770 "%s: dup2(%d, 0): %s",
5771 __func__,
5772 fdin[0],
5773 strerror(ERRNO));
5774 } else if (dup2(fdout[1], 1) == -1) {
5775 mg_cry_internal(conn,
5776 "%s: dup2(%d, 1): %s",
5777 __func__,
5778 fdout[1],
5779 strerror(ERRNO));
5780 } else if (dup2(fderr[1], 2) == -1) {
5781 mg_cry_internal(conn,
5782 "%s: dup2(%d, 2): %s",
5783 __func__,
5784 fderr[1],
5785 strerror(ERRNO));
5786 } else {
5787 struct sigaction sa;
5788
5789 /* Keep stderr and stdout in two different pipes.
5790 * Stdout will be sent back to the client,
5791 * stderr should go into a server error log. */
5792 (void)close(fdin[0]);
5793 (void)close(fdout[1]);
5794 (void)close(fderr[1]);
5795
5796 /* Close write end fdin and read end fdout and fderr */
5797 (void)close(fdin[1]);
5798 (void)close(fdout[0]);
5799 (void)close(fderr[0]);
5800
5801 /* After exec, all signal handlers are restored to their default
5802 * values, with one exception of SIGCHLD. According to
5803 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler
5804 * will leave unchanged after exec if it was set to be ignored.
5805 * Restore it to default action. */
5806 memset(&sa, 0, sizeof(sa));
5807 sa.sa_handler = SIG_DFL;
5808 sigaction(SIGCHLD, &sa, NULL);
5809
5810 interp = conn->dom_ctx->config[CGI_INTERPRETER + cgi_config_idx];
5811 if (interp == NULL) {
5812 /* no interpreter configured, call the programm directly */
5813 (void)execle(prog, prog, NULL, envp);
5814 mg_cry_internal(conn,
5815 "%s: execle(%s): %s",
5816 __func__,
5817 prog,
5818 strerror(ERRNO));
5819 } else {
5820 /* call the configured interpreter */
5821 const char *interp_args =
5822 conn->dom_ctx
5823 ->config[CGI_INTERPRETER_ARGS + cgi_config_idx];
5824
5825 if ((interp_args != NULL) && (interp_args[0] != 0)) {
5826 (void)execle(interp, interp, interp_args, prog, NULL, envp);
5827 } else {
5828 (void)execle(interp, interp, prog, NULL, envp);
5829 }
5830 mg_cry_internal(conn,
5831 "%s: execle(%s %s): %s",
5832 __func__,
5833 interp,
5834 prog,
5835 strerror(ERRNO));
5836 }
5837 }
5838 exit(EXIT_FAILURE);
5839 }
5840
5841 return pid;
5842}
5843#endif /* !NO_CGI */
5844
5845
5846static int
5848{
5849 int flags = fcntl(sock, F_GETFL, 0);
5850 if (flags < 0) {
5851 return -1;
5852 }
5853
5854 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
5855 return -1;
5856 }
5857 return 0;
5858}
5859
5860static int
5862{
5863 int flags = fcntl(sock, F_GETFL, 0);
5864 if (flags < 0) {
5865 return -1;
5866 }
5867
5868 if (fcntl(sock, F_SETFL, flags & (~(int)(O_NONBLOCK))) < 0) {
5869 return -1;
5870 }
5871 return 0;
5872}
5873#endif /* _WIN32 / else */
5874
5875/* End of initial operating system specific define block. */
5876
5877
5878/* Get a random number (independent of C rand function) */
5879static uint64_t
5881{
5882 static uint64_t lfsr = 0; /* Linear feedback shift register */
5883 static uint64_t lcg = 0; /* Linear congruential generator */
5884 uint64_t now = mg_get_current_time_ns();
5885
5886 if (lfsr == 0) {
5887 /* lfsr will be only 0 if has not been initialized,
5888 * so this code is called only once. */
5889 lfsr = mg_get_current_time_ns();
5890 lcg = mg_get_current_time_ns();
5891 } else {
5892 /* Get the next step of both random number generators. */
5893 lfsr = (lfsr >> 1)
5894 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
5895 << 63);
5896 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
5897 }
5898
5899 /* Combining two pseudo-random number generators and a high resolution
5900 * part
5901 * of the current server time will make it hard (impossible?) to guess
5902 * the
5903 * next number. */
5904 return (lfsr ^ lcg ^ now);
5905}
5906
5907
5908static int
5909mg_poll(struct mg_pollfd *pfd,
5910 unsigned int n,
5911 int milliseconds,
5912 const stop_flag_t *stop_flag)
5913{
5914 /* Call poll, but only for a maximum time of a few seconds.
5915 * This will allow to stop the server after some seconds, instead
5916 * of having to wait for a long socket timeout. */
5917 int ms_now = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
5918
5919 int check_pollerr = 0;
5920 if ((n == 1) && ((pfd[0].events & POLLERR) == 0)) {
5921 /* If we wait for only one file descriptor, wait on error as well */
5922 pfd[0].events |= POLLERR;
5923 check_pollerr = 1;
5924 }
5925
5926 do {
5927 int result;
5928
5929 if (!STOP_FLAG_IS_ZERO(&*stop_flag)) {
5930 /* Shut down signal */
5931 return -2;
5932 }
5933
5934 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
5935 ms_now = milliseconds;
5936 }
5937
5938 result = poll(pfd, n, ms_now);
5939 if (result != 0) {
5940 /* Poll returned either success (1) or error (-1).
5941 * Forward both to the caller. */
5942 if ((check_pollerr)
5943 && ((pfd[0].revents & (POLLIN | POLLOUT | POLLERR))
5944 == POLLERR)) {
5945 /* One and only file descriptor returned error */
5946 return -1;
5947 }
5948 return result;
5949 }
5950
5951 /* Poll returned timeout (0). */
5952 if (milliseconds > 0) {
5953 milliseconds -= ms_now;
5954 }
5955
5956 } while (milliseconds > 0);
5957
5958 /* timeout: return 0 */
5959 return 0;
5960}
5961
5962
5963/* Write data to the IO channel - opened file descriptor, socket or SSL
5964 * descriptor.
5965 * Return value:
5966 * >=0 .. number of bytes successfully written
5967 * -1 .. timeout
5968 * -2 .. error
5969 */
5970static int
5972 FILE *fp,
5973 SOCKET sock,
5974 SSL *ssl,
5975 const char *buf,
5976 int len,
5977 double timeout)
5978{
5979 uint64_t start = 0, now = 0, timeout_ns = 0;
5980 int n, err;
5981 unsigned ms_wait = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
5982
5983#if defined(_WIN32)
5984 typedef int len_t;
5985#else
5986 typedef size_t len_t;
5987#endif
5988
5989 if (timeout > 0) {
5990 now = mg_get_current_time_ns();
5991 start = now;
5992 timeout_ns = (uint64_t)(timeout * 1.0E9);
5993 }
5994
5995 if (ctx == NULL) {
5996 return -2;
5997 }
5998
5999#if defined(NO_SSL) && !defined(USE_MBEDTLS)
6000 if (ssl) {
6001 return -2;
6002 }
6003#endif
6004
6005 /* Try to read until it succeeds, fails, times out, or the server
6006 * shuts down. */
6007 for (;;) {
6008
6009#if defined(USE_MBEDTLS)
6010 if (ssl != NULL) {
6011 n = mbed_ssl_write(ssl, (const unsigned char *)buf, len);
6012