Coverage Report

Created: 2023-12-08 06:16

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