Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
civetweb.c
Go to the documentation of this file.
1/* Copyright (c) 2013-2018 the Civetweb developers
2 * Copyright (c) 2004-2013 Sergey Lyubka
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#if defined(__GNUC__) || defined(__MINGW32__)
24#define GCC_VERSION \
25 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
26#if GCC_VERSION >= 40500
27/* gcc diagnostic pragmas available */
28#define GCC_DIAGNOSTIC
29#endif
30#endif
31
32#if defined(GCC_DIAGNOSTIC)
33/* Disable unused macros warnings - not all defines are required
34 * for all systems and all compilers. */
35#pragma GCC diagnostic ignored "-Wunused-macros"
36/* A padding warning is just plain useless */
37#pragma GCC diagnostic ignored "-Wpadded"
38#endif
39
40#if defined(__clang__) /* GCC does not (yet) support this pragma */
41/* We must set some flags for the headers we include. These flags
42 * are reserved ids according to C99, so we need to disable a
43 * warning for that. */
44#pragma GCC diagnostic push
45#pragma GCC diagnostic ignored "-Wreserved-id-macro"
46#endif
47
48#if defined(_WIN32)
49#if !defined(_CRT_SECURE_NO_WARNINGS)
50#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
51#endif
52#if !defined(_WIN32_WINNT) /* defined for tdm-gcc so we can use getnameinfo */
53#define _WIN32_WINNT 0x0501
54#endif
55#else
56#if !defined(_GNU_SOURCE)
57#define _GNU_SOURCE /* for setgroups(), pthread_setname_np() */
58#endif
59#if defined(__linux__) && !defined(_XOPEN_SOURCE)
60#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
61#endif
62#if !defined(_LARGEFILE_SOURCE)
63#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
64#endif
65#if !defined(_FILE_OFFSET_BITS)
66#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
67#endif
68#if !defined(__STDC_FORMAT_MACROS)
69#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
70#endif
71#if !defined(__STDC_LIMIT_MACROS)
72#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
73#endif
74#if !defined(_DARWIN_UNLIMITED_SELECT)
75#define _DARWIN_UNLIMITED_SELECT
76#endif
77#if defined(__sun)
78#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
79#define __inline inline /* not recognized on older compiler versions */
80#endif
81#endif
82
83#if defined(__clang__)
84/* Enable reserved-id-macro warning again. */
85#pragma GCC diagnostic pop
86#endif
87
88
89#if defined(USE_LUA)
90#define USE_TIMERS
91#endif
92
93#if defined(_MSC_VER)
94/* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
95#pragma warning(disable : 4306)
96/* conditional expression is constant: introduced by FD_SET(..) */
97#pragma warning(disable : 4127)
98/* non-constant aggregate initializer: issued due to missing C99 support */
99#pragma warning(disable : 4204)
100/* padding added after data member */
101#pragma warning(disable : 4820)
102/* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
103#pragma warning(disable : 4668)
104/* no function prototype given: converting '()' to '(void)' */
105#pragma warning(disable : 4255)
106/* function has been selected for automatic inline expansion */
107#pragma warning(disable : 4711)
108#endif
109
110
111/* This code uses static_assert to check some conditions.
112 * Unfortunately some compilers still do not support it, so we have a
113 * replacement function here. */
114#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201100L
115#define mg_static_assert _Static_assert
116#elif defined(__cplusplus) && __cplusplus >= 201103L
117#define mg_static_assert static_assert
118#else
120#define mg_static_assert(cond, txt) \
121 extern char static_assert_replacement[(cond) ? 1 : -1]
122#endif
123
124mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
125 "int data type size check");
126mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
127 "pointer data type size check");
128mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
129
130
131/* Alternative queue is well tested and should be the new default */
132#if defined(NO_ALTERNATIVE_QUEUE)
133#if defined(ALTERNATIVE_QUEUE)
134#error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both"
135#endif
136#else
137#define ALTERNATIVE_QUEUE
138#endif
139
140
141/* DTL -- including winsock2.h works better if lean and mean */
142#if !defined(WIN32_LEAN_AND_MEAN)
143#define WIN32_LEAN_AND_MEAN
144#endif
145
146#if defined(__SYMBIAN32__)
147/* According to https://en.wikipedia.org/wiki/Symbian#History,
148 * Symbian is no longer maintained since 2014-01-01.
149 * Recent versions of CivetWeb are no longer tested for Symbian.
150 * It makes no sense, to support an abandoned operating system.
151 */
152#error "Symbian is no longer maintained. CivetWeb no longer supports Symbian."
153#define NO_SSL /* SSL is not supported */
154#define NO_CGI /* CGI is not supported */
155#define PATH_MAX FILENAME_MAX
156#endif /* __SYMBIAN32__ */
157
158
159#if !defined(CIVETWEB_HEADER_INCLUDED)
160/* Include the header file here, so the CivetWeb interface is defined for the
161 * entire implementation, including the following forward definitions. */
162#include "civetweb.h"
163#endif
164
165#if !defined(DEBUG_TRACE)
166#if defined(DEBUG)
167static void DEBUG_TRACE_FUNC(const char *func,
168 unsigned line,
169 PRINTF_FORMAT_STRING(const char *fmt),
170 ...) PRINTF_ARGS(3, 4);
171
172#define DEBUG_TRACE(fmt, ...) \
173 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
174
175#define NEED_DEBUG_TRACE_FUNC
176
177#else
178#define DEBUG_TRACE(fmt, ...) \
179 do { \
180 } while (0)
181#endif /* DEBUG */
182#endif /* DEBUG_TRACE */
183
184
185#if !defined(DEBUG_ASSERT)
186#if defined(DEBUG)
187#define DEBUG_ASSERT(cond) \
188 do { \
189 if (!(cond)) { \
190 DEBUG_TRACE("ASSERTION FAILED: %s", #cond); \
191 exit(2); /* Exit with error */ \
192 } \
193 } while (0)
194#else
195#define DEBUG_ASSERT(cond)
196#endif /* DEBUG */
197#endif
198
199
200#if defined(__GNUC__) && defined(GCC_INSTRUMENTATION)
201void __cyg_profile_func_enter(void *this_fn, void *call_site)
202 __attribute__((no_instrument_function));
203
204void __cyg_profile_func_exit(void *this_fn, void *call_site)
205 __attribute__((no_instrument_function));
206
207void
208__cyg_profile_func_enter(void *this_fn, void *call_site)
209{
210 if ((void *)this_fn != (void *)printf) {
211 printf("E %p %p\n", this_fn, call_site);
212 }
213}
214
215void
216__cyg_profile_func_exit(void *this_fn, void *call_site)
217{
218 if ((void *)this_fn != (void *)printf) {
219 printf("X %p %p\n", this_fn, call_site);
220 }
221}
222#endif
223
224
225#if !defined(IGNORE_UNUSED_RESULT)
226#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
227#endif
228
229
230#if defined(__GNUC__) || defined(__MINGW32__)
231
232/* GCC unused function attribute seems fundamentally broken.
233 * Several attempts to tell the compiler "THIS FUNCTION MAY BE USED
234 * OR UNUSED" for individual functions failed.
235 * Either the compiler creates an "unused-function" warning if a
236 * function is not marked with __attribute__((unused)).
237 * On the other hand, if the function is marked with this attribute,
238 * but is used, the compiler raises a completely idiotic
239 * "used-but-marked-unused" warning - and
240 * #pragma GCC diagnostic ignored "-Wused-but-marked-unused"
241 * raises error: unknown option after "#pragma GCC diagnostic".
242 * Disable this warning completely, until the GCC guys sober up
243 * again.
244 */
245
246#pragma GCC diagnostic ignored "-Wunused-function"
247
248#define FUNCTION_MAY_BE_UNUSED /* __attribute__((unused)) */
249
250#else
251#define FUNCTION_MAY_BE_UNUSED
252#endif
253
254
255/* Some ANSI #includes are not available on Windows CE */
256#if !defined(_WIN32_WCE)
257#include <errno.h>
258#include <fcntl.h>
259#include <signal.h>
260#include <sys/stat.h>
261#include <sys/types.h>
262#endif /* !_WIN32_WCE */
263
264
265#if defined(__clang__)
266/* When using -Weverything, clang does not accept it's own headers
267 * in a release build configuration. Disable what is too much in
268 * -Weverything. */
269#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
270#endif
271
272#if defined(__GNUC__) || defined(__MINGW32__)
273/* Who on earth came to the conclusion, using __DATE__ should rise
274 * an "expansion of date or time macro is not reproducible"
275 * warning. That's exactly what was intended by using this macro.
276 * Just disable this nonsense warning. */
277
278/* And disabling them does not work either:
279 * #pragma clang diagnostic ignored "-Wno-error=date-time"
280 * #pragma clang diagnostic ignored "-Wdate-time"
281 * So we just have to disable ALL warnings for some lines
282 * of code.
283 * This seems to be a known GCC bug, not resolved since 2012:
284 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53431
285 */
286#endif
287
288
289#if defined(__MACH__) /* Apple OSX section */
290
291#if defined(__clang__)
292#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
293/* Avoid warnings for Xcode 7. It seems it does no longer exist in Xcode 8 */
294#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
295#pragma clang diagnostic ignored "-Wno-keyword-macro"
296#endif
297#endif
298
299#define CLOCK_MONOTONIC (1)
300#define CLOCK_REALTIME (2)
301
302#include <mach/clock.h>
303#include <mach/mach.h>
304#include <mach/mach_time.h>
305#include <sys/errno.h>
306#include <sys/time.h>
307
308/* clock_gettime is not implemented on OSX prior to 10.12 */
309static int
310_civet_clock_gettime(int clk_id, struct timespec *t)
311{
312 memset(t, 0, sizeof(*t));
313 if (clk_id == CLOCK_REALTIME) {
314 struct timeval now;
315 int rv = gettimeofday(&now, NULL);
316 if (rv) {
317 return rv;
318 }
319 t->tv_sec = now.tv_sec;
320 t->tv_nsec = now.tv_usec * 1000;
321 return 0;
322
323 } else if (clk_id == CLOCK_MONOTONIC) {
324 static uint64_t clock_start_time = 0;
325 static mach_timebase_info_data_t timebase_ifo = {0, 0};
326
327 uint64_t now = mach_absolute_time();
328
329 if (clock_start_time == 0) {
330 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
331 DEBUG_ASSERT(mach_status == KERN_SUCCESS);
332
333 /* appease "unused variable" warning for release builds */
334 (void)mach_status;
335
336 clock_start_time = now;
337 }
338
339 now = (uint64_t)((double)(now - clock_start_time)
340 * (double)timebase_ifo.numer
341 / (double)timebase_ifo.denom);
342
343 t->tv_sec = now / 1000000000;
344 t->tv_nsec = now % 1000000000;
345 return 0;
346 }
347 return -1; /* EINVAL - Clock ID is unknown */
348}
349
350/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
351#if defined(__CLOCK_AVAILABILITY)
352/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be
353 * declared but it may be NULL at runtime. So we need to check before using
354 * it. */
355static int
356_civet_safe_clock_gettime(int clk_id, struct timespec *t)
357{
358 if (clock_gettime) {
359 return clock_gettime(clk_id, t);
360 }
361 return _civet_clock_gettime(clk_id, t);
362}
363#define clock_gettime _civet_safe_clock_gettime
364#else
365#define clock_gettime _civet_clock_gettime
366#endif
367
368#endif
369
370
371#include <ctype.h>
372#include <limits.h>
373#include <stdarg.h>
374#include <stddef.h>
375#include <stdint.h>
376#include <stdio.h>
377#include <stdlib.h>
378#include <string.h>
379#include <time.h>
380
381/********************************************************************/
382/* CivetWeb configuration defines */
383/********************************************************************/
384
385/* Maximum number of threads that can be configured.
386 * The number of threads actually created depends on the "num_threads"
387 * configuration parameter, but this is the upper limit. */
388#if !defined(MAX_WORKER_THREADS)
389#define MAX_WORKER_THREADS (1024 * 64) /* in threads (count) */
390#endif
391
392/* Timeout interval for select/poll calls.
393 * The timeouts depend on "*_timeout_ms" configuration values, but long
394 * timeouts are split into timouts as small as SOCKET_TIMEOUT_QUANTUM.
395 * This reduces the time required to stop the server. */
396#if !defined(SOCKET_TIMEOUT_QUANTUM)
397#define SOCKET_TIMEOUT_QUANTUM (2000) /* in ms */
398#endif
399
400/* Do not try to compress files smaller than this limit. */
401#if !defined(MG_FILE_COMPRESSION_SIZE_LIMIT)
402#define MG_FILE_COMPRESSION_SIZE_LIMIT (1024) /* in bytes */
403#endif
404
405#if !defined(PASSWORDS_FILE_NAME)
406#define PASSWORDS_FILE_NAME ".htpasswd"
407#endif
408
409/* Initial buffer size for all CGI environment variables. In case there is
410 * not enough space, another block is allocated. */
411#if !defined(CGI_ENVIRONMENT_SIZE)
412#define CGI_ENVIRONMENT_SIZE (4096) /* in bytes */
413#endif
414
415/* Maximum number of environment variables. */
416#if !defined(MAX_CGI_ENVIR_VARS)
417#define MAX_CGI_ENVIR_VARS (256) /* in variables (count) */
418#endif
419
420/* General purpose buffer size. */
421#if !defined(MG_BUF_LEN) /* in bytes */
422#define MG_BUF_LEN (1024 * 8)
423#endif
424
425/* Size of the accepted socket queue (in case the old queue implementation
426 * is used). */
427#if !defined(MGSQLEN)
428#define MGSQLEN (20) /* count */
429#endif
430
431
432/********************************************************************/
433
434/* Helper makros */
435#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
436
437/* Standard defines */
438#if !defined(INT64_MAX)
439#define INT64_MAX (9223372036854775807)
440#endif
441
442#define SHUTDOWN_RD (0)
443#define SHUTDOWN_WR (1)
444#define SHUTDOWN_BOTH (2)
445
447 "worker threads must be a positive number");
448
449mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8,
450 "size_t data type size check");
451
452#if defined(_WIN32) /* WINDOWS include block */
453#include <windows.h>
454#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
455#include <ws2tcpip.h>
456
457typedef const char *SOCK_OPT_TYPE;
458
459#if !defined(PATH_MAX)
460#define W_PATH_MAX (MAX_PATH)
461/* at most three UTF-8 chars per wchar_t */
462#define PATH_MAX (W_PATH_MAX * 3)
463#else
464#define W_PATH_MAX ((PATH_MAX + 2) / 3)
465#endif
466
467mg_static_assert(PATH_MAX >= 1, "path length must be a positive number");
468
469#if !defined(_IN_PORT_T)
470#if !defined(in_port_t)
471#define in_port_t u_short
472#endif
473#endif
474
475#if !defined(_WIN32_WCE)
476#include <direct.h>
477#include <io.h>
478#include <process.h>
479#else /* _WIN32_WCE */
480#define NO_CGI /* WinCE has no pipes */
481#define NO_POPEN /* WinCE has no popen */
482
483typedef long off_t;
484
485#define errno ((int)(GetLastError()))
486#define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
487#endif /* _WIN32_WCE */
488
489#define MAKEUQUAD(lo, hi) \
490 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
491#define RATE_DIFF (10000000) /* 100 nsecs */
492#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
493#define SYS2UNIX_TIME(lo, hi) \
494 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
495
496/* Visual Studio 6 does not know __func__ or __FUNCTION__
497 * The rest of MS compilers use __FUNCTION__, not C99 __func__
498 * Also use _strtoui64 on modern M$ compilers */
499#if defined(_MSC_VER)
500#if (_MSC_VER < 1300)
501#define STRX(x) #x
502#define STR(x) STRX(x)
503#define __func__ __FILE__ ":" STR(__LINE__)
504#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
505#define strtoll(x, y, z) (_atoi64(x))
506#else
507#define __func__ __FUNCTION__
508#define strtoull(x, y, z) (_strtoui64(x, y, z))
509#define strtoll(x, y, z) (_strtoi64(x, y, z))
510#endif
511#endif /* _MSC_VER */
512
513#define ERRNO ((int)(GetLastError()))
514#define NO_SOCKLEN_T
515
516#if defined(_WIN64) || defined(__MINGW64__)
517#if !defined(SSL_LIB)
518#define SSL_LIB "ssleay64.dll"
519#endif
520#if !defined(CRYPTO_LIB)
521#define CRYPTO_LIB "libeay64.dll"
522#endif
523#else
524#if !defined(SSL_LIB)
525#define SSL_LIB "ssleay32.dll"
526#endif
527#if !defined(CRYPTO_LIB)
528#define CRYPTO_LIB "libeay32.dll"
529#endif
530#endif
531
532#define O_NONBLOCK (0)
533#if !defined(W_OK)
534#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
535#endif
536#if !defined(EWOULDBLOCK)
537#define EWOULDBLOCK WSAEWOULDBLOCK
538#endif /* !EWOULDBLOCK */
539#define _POSIX_
540#define INT64_FMT "I64d"
541#define UINT64_FMT "I64u"
542
543#define WINCDECL __cdecl
544#define vsnprintf_impl _vsnprintf
545#define access _access
546#define mg_sleep(x) (Sleep(x))
547
548#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
549#if !defined(popen)
550#define popen(x, y) (_popen(x, y))
551#endif
552#if !defined(pclose)
553#define pclose(x) (_pclose(x))
554#endif
555#define close(x) (_close(x))
556#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
557#define RTLD_LAZY (0)
558#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
559#define fdopen(x, y) (_fdopen((x), (y)))
560#define write(x, y, z) (_write((x), (y), (unsigned)z))
561#define read(x, y, z) (_read((x), (y), (unsigned)z))
562#define flockfile(x) (EnterCriticalSection(&global_log_file_lock))
563#define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock))
564#define sleep(x) (Sleep((x)*1000))
565#define rmdir(x) (_rmdir(x))
566#if defined(_WIN64) || !defined(__MINGW32__)
567/* Only MinGW 32 bit is missing this function */
568#define timegm(x) (_mkgmtime(x))
569#else
570time_t timegm(struct tm *tm);
571#define NEED_TIMEGM
572#endif
573
574
575#if !defined(fileno)
576#define fileno(x) (_fileno(x))
577#endif /* !fileno MINGW #defines fileno */
578
579typedef HANDLE pthread_mutex_t;
580typedef DWORD pthread_key_t;
581typedef HANDLE pthread_t;
582typedef struct {
583 CRITICAL_SECTION threadIdSec;
584 struct mg_workerTLS *waiting_thread; /* The chain of threads */
586
587#if !defined(__clockid_t_defined)
588typedef DWORD clockid_t;
589#endif
590#if !defined(CLOCK_MONOTONIC)
591#define CLOCK_MONOTONIC (1)
592#endif
593#if !defined(CLOCK_REALTIME)
594#define CLOCK_REALTIME (2)
595#endif
596#if !defined(CLOCK_THREAD)
597#define CLOCK_THREAD (3)
598#endif
599#if !defined(CLOCK_PROCESS)
600#define CLOCK_PROCESS (4)
601#endif
602
603
604#if defined(_MSC_VER) && (_MSC_VER >= 1900)
605#define _TIMESPEC_DEFINED
606#endif
607#if !defined(_TIMESPEC_DEFINED)
608struct timespec {
609 time_t tv_sec; /* seconds */
610 long tv_nsec; /* nanoseconds */
611};
612#endif
613
614#if !defined(WIN_PTHREADS_TIME_H)
615#define MUST_IMPLEMENT_CLOCK_GETTIME
616#endif
617
618#if defined(MUST_IMPLEMENT_CLOCK_GETTIME)
619#define clock_gettime mg_clock_gettime
620static int
621clock_gettime(clockid_t clk_id, struct timespec *tp)
622{
623 FILETIME ft;
624 ULARGE_INTEGER li, li2;
625 BOOL ok = FALSE;
626 double d;
627 static double perfcnt_per_sec = 0.0;
628 static BOOL initialized = FALSE;
629
630 if (!initialized) {
631 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
632 perfcnt_per_sec = 1.0 / li.QuadPart;
633 initialized = TRUE;
634 }
635
636 if (tp) {
637 memset(tp, 0, sizeof(*tp));
638
639 if (clk_id == CLOCK_REALTIME) {
640
641 /* BEGIN: CLOCK_REALTIME = wall clock (date and time) */
642 GetSystemTimeAsFileTime(&ft);
643 li.LowPart = ft.dwLowDateTime;
644 li.HighPart = ft.dwHighDateTime;
645 li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
646 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
647 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
648 ok = TRUE;
649 /* END: CLOCK_REALTIME */
650
651 } else if (clk_id == CLOCK_MONOTONIC) {
652
653 /* BEGIN: CLOCK_MONOTONIC = stopwatch (time differences) */
654 QueryPerformanceCounter((LARGE_INTEGER *)&li);
655 d = li.QuadPart * perfcnt_per_sec;
656 tp->tv_sec = (time_t)d;
657 d -= (double)tp->tv_sec;
658 tp->tv_nsec = (long)(d * 1.0E9);
659 ok = TRUE;
660 /* END: CLOCK_MONOTONIC */
661
662 } else if (clk_id == CLOCK_THREAD) {
663
664 /* BEGIN: CLOCK_THREAD = CPU usage of thread */
665 FILETIME t_create, t_exit, t_kernel, t_user;
666 if (GetThreadTimes(GetCurrentThread(),
667 &t_create,
668 &t_exit,
669 &t_kernel,
670 &t_user)) {
671 li.LowPart = t_user.dwLowDateTime;
672 li.HighPart = t_user.dwHighDateTime;
673 li2.LowPart = t_kernel.dwLowDateTime;
674 li2.HighPart = t_kernel.dwHighDateTime;
675 li.QuadPart += li2.QuadPart;
676 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
677 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
678 ok = TRUE;
679 }
680 /* END: CLOCK_THREAD */
681
682 } else if (clk_id == CLOCK_PROCESS) {
683
684 /* BEGIN: CLOCK_PROCESS = CPU usage of process */
685 FILETIME t_create, t_exit, t_kernel, t_user;
686 if (GetProcessTimes(GetCurrentProcess(),
687 &t_create,
688 &t_exit,
689 &t_kernel,
690 &t_user)) {
691 li.LowPart = t_user.dwLowDateTime;
692 li.HighPart = t_user.dwHighDateTime;
693 li2.LowPart = t_kernel.dwLowDateTime;
694 li2.HighPart = t_kernel.dwHighDateTime;
695 li.QuadPart += li2.QuadPart;
696 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
697 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
698 ok = TRUE;
699 }
700 /* END: CLOCK_PROCESS */
701
702 } else {
703
704 /* BEGIN: unknown clock */
705 /* ok = FALSE; already set by init */
706 /* END: unknown clock */
707 }
708 }
709
710 return ok ? 0 : -1;
711}
712#endif
713
714
715#define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
716
717static int pthread_mutex_lock(pthread_mutex_t *);
718static int pthread_mutex_unlock(pthread_mutex_t *);
719static void path_to_unicode(const struct mg_connection *conn,
720 const char *path,
721 wchar_t *wbuf,
722 size_t wbuf_len);
723
724/* All file operations need to be rewritten to solve #246. */
725
726struct mg_file;
727
728static const char *
729mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p);
730
731
732/* POSIX dirent interface */
733struct dirent {
734 char d_name[PATH_MAX];
735};
736
737typedef struct DIR {
738 HANDLE handle;
739 WIN32_FIND_DATAW info;
740 struct dirent result;
741} DIR;
742
743#if defined(_WIN32)
744#if !defined(HAVE_POLL)
745struct pollfd {
746 SOCKET fd;
747 short events;
748 short revents;
749};
750#endif
751#endif
752
753/* Mark required libraries */
754#if defined(_MSC_VER)
755#pragma comment(lib, "Ws2_32.lib")
756#endif
757
758#else /* defined(_WIN32) - WINDOWS vs UNIX include block */
759
760#include <arpa/inet.h>
761#include <inttypes.h>
762#include <netdb.h>
763#include <netinet/in.h>
764#include <netinet/tcp.h>
765#include <stdint.h>
766#include <sys/poll.h>
767#include <sys/socket.h>
768#include <sys/time.h>
769#include <sys/utsname.h>
770#include <sys/wait.h>
771typedef const void *SOCK_OPT_TYPE;
772
773#if defined(ANDROID)
774typedef unsigned short int in_port_t;
775#endif
776
777#include <dirent.h>
778#include <grp.h>
779#include <pwd.h>
780#include <unistd.h>
781#define vsnprintf_impl vsnprintf
782
783#if !defined(NO_SSL_DL) && !defined(NO_SSL)
784#include <dlfcn.h>
785#endif
786#include <pthread.h>
787#if defined(__MACH__)
788#define SSL_LIB "libssl.dylib"
789#define CRYPTO_LIB "libcrypto.dylib"
790#else
791#if !defined(SSL_LIB)
792#define SSL_LIB "libssl.so"
793#endif
794#if !defined(CRYPTO_LIB)
795#define CRYPTO_LIB "libcrypto.so"
796#endif
797#endif
798#if !defined(O_BINARY)
799#define O_BINARY (0)
800#endif /* O_BINARY */
801#define closesocket(a) (close(a))
802#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
803#define mg_remove(conn, x) (remove(x))
804#define mg_sleep(x) (usleep((x)*1000))
805#define mg_opendir(conn, x) (opendir(x))
806#define mg_closedir(x) (closedir(x))
807#define mg_readdir(x) (readdir(x))
808#define ERRNO (errno)
809#define INVALID_SOCKET (-1)
810#define INT64_FMT PRId64
811#define UINT64_FMT PRIu64
812typedef int SOCKET;
813#define WINCDECL
814
815#if defined(__hpux)
816/* HPUX 11 does not have monotonic, fall back to realtime */
817#if !defined(CLOCK_MONOTONIC)
818#define CLOCK_MONOTONIC CLOCK_REALTIME
819#endif
820
821/* HPUX defines socklen_t incorrectly as size_t which is 64bit on
822 * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
823 * the prototypes use int* rather than socklen_t* which matches the
824 * actual library expectation. When called with the wrong size arg
825 * accept() returns a zero client inet addr and check_acl() always
826 * fails. Since socklen_t is widely used below, just force replace
827 * their typedef with int. - DTL
828 */
829#define socklen_t int
830#endif /* hpux */
831
832#endif /* defined(_WIN32) - WINDOWS vs UNIX include block */
833
834/* Maximum queue length for pending connections. This value is passed as
835 * parameter to the "listen" socket call. */
836#if !defined(SOMAXCONN)
837/* This symbol may be defined in winsock2.h so this must after that include */
838#define SOMAXCONN (100) /* in pending connections (count) */
839#endif
840
841/* In case our C library is missing "timegm", provide an implementation */
842#if defined(NEED_TIMEGM)
843static inline int
844is_leap(int y)
845{
846 return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
847}
848
849static inline int
850count_leap(int y)
851{
852 return (y - 1969) / 4 - (y - 1901) / 100 + (y - 1601) / 400;
853}
854
855time_t
856timegm(struct tm *tm)
857{
858 static const unsigned short ydays[] = {
859 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
860 int year = tm->tm_year + 1900;
861 int mon = tm->tm_mon;
862 int mday = tm->tm_mday - 1;
863 int hour = tm->tm_hour;
864 int min = tm->tm_min;
865 int sec = tm->tm_sec;
866
867 if (year < 1970 || mon < 0 || mon > 11 || mday < 0
868 || (mday >= ydays[mon + 1] - ydays[mon]
869 + (mon == 1 && is_leap(year) ? 1 : 0))
870 || hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 || sec > 60)
871 return -1;
872
873 time_t res = year - 1970;
874 res *= 365;
875 res += mday;
876 res += ydays[mon] + (mon > 1 && is_leap(year) ? 1 : 0);
877 res += count_leap(year);
878
879 res *= 24;
880 res += hour;
881 res *= 60;
882 res += min;
883 res *= 60;
884 res += sec;
885 return res;
886}
887#endif /* NEED_TIMEGM */
888
889
890/* va_copy should always be a macro, C99 and C++11 - DTL */
891#if !defined(va_copy)
892#define va_copy(x, y) ((x) = (y))
893#endif
894
895
896#if defined(_WIN32)
897/* Create substitutes for POSIX functions in Win32. */
898
899#if defined(GCC_DIAGNOSTIC)
900/* Show no warning in case system functions are not used. */
901#pragma GCC diagnostic push
902#pragma GCC diagnostic ignored "-Wunused-function"
903#endif
904
905
906static CRITICAL_SECTION global_log_file_lock;
907
909static DWORD
910pthread_self(void)
911{
912 return GetCurrentThreadId();
913}
914
915
917static int
918pthread_key_create(
919 pthread_key_t *key,
920 void (*_ignored)(void *) /* destructor not supported for Windows */
921)
922{
923 (void)_ignored;
924
925 if ((key != 0)) {
926 *key = TlsAlloc();
927 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
928 }
929 return -2;
930}
931
932
934static int
935pthread_key_delete(pthread_key_t key)
936{
937 return TlsFree(key) ? 0 : 1;
938}
939
940
942static int
943pthread_setspecific(pthread_key_t key, void *value)
944{
945 return TlsSetValue(key, value) ? 0 : 1;
946}
947
948
950static void *
951pthread_getspecific(pthread_key_t key)
952{
953 return TlsGetValue(key);
954}
955
956#if defined(GCC_DIAGNOSTIC)
957/* Enable unused function warning again */
958#pragma GCC diagnostic pop
959#endif
960
961static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL;
962#else
963static pthread_mutexattr_t pthread_mutex_attr;
964#endif /* _WIN32 */
965
966
967#if defined(_WIN32_WCE)
968/* Create substitutes for POSIX functions in Win32. */
969
970#if defined(GCC_DIAGNOSTIC)
971/* Show no warning in case system functions are not used. */
972#pragma GCC diagnostic push
973#pragma GCC diagnostic ignored "-Wunused-function"
974#endif
975
976
978static time_t
979time(time_t *ptime)
980{
981 time_t t;
982 SYSTEMTIME st;
983 FILETIME ft;
984
985 GetSystemTime(&st);
986 SystemTimeToFileTime(&st, &ft);
987 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
988
989 if (ptime != NULL) {
990 *ptime = t;
991 }
992
993 return t;
994}
995
996
998static struct tm *
999localtime_s(const time_t *ptime, struct tm *ptm)
1000{
1001 int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
1002 FILETIME ft, lft;
1003 SYSTEMTIME st;
1004 TIME_ZONE_INFORMATION tzinfo;
1005
1006 if (ptm == NULL) {
1007 return NULL;
1008 }
1009
1010 *(int64_t *)&ft = t;
1011 FileTimeToLocalFileTime(&ft, &lft);
1012 FileTimeToSystemTime(&lft, &st);
1013 ptm->tm_year = st.wYear - 1900;
1014 ptm->tm_mon = st.wMonth - 1;
1015 ptm->tm_wday = st.wDayOfWeek;
1016 ptm->tm_mday = st.wDay;
1017 ptm->tm_hour = st.wHour;
1018 ptm->tm_min = st.wMinute;
1019 ptm->tm_sec = st.wSecond;
1020 ptm->tm_yday = 0; /* hope nobody uses this */
1021 ptm->tm_isdst =
1022 (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0;
1023
1024 return ptm;
1025}
1026
1027
1029static struct tm *
1030gmtime_s(const time_t *ptime, struct tm *ptm)
1031{
1032 /* FIXME(lsm): fix this. */
1033 return localtime_s(ptime, ptm);
1034}
1035
1036
1037static int mg_atomic_inc(volatile int *addr);
1038static struct tm tm_array[MAX_WORKER_THREADS];
1039static int tm_index = 0;
1040
1041
1043static struct tm *
1044localtime(const time_t *ptime)
1045{
1046 int i = mg_atomic_inc(&tm_index) % (sizeof(tm_array) / sizeof(tm_array[0]));
1047 return localtime_s(ptime, tm_array + i);
1048}
1049
1050
1052static struct tm *
1053gmtime(const time_t *ptime)
1054{
1055 int i = mg_atomic_inc(&tm_index) % ARRAY_SIZE(tm_array);
1056 return gmtime_s(ptime, tm_array + i);
1057}
1058
1059
1061static size_t
1062strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm)
1063{
1064 /* TODO: (void)mg_snprintf(NULL, dst, dst_size, "implement strftime()
1065 * for WinCE"); */
1066 return 0;
1067}
1068
1069#define _beginthreadex(psec, stack, func, prm, flags, ptid) \
1070 (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid)
1071
1072#define remove(f) mg_remove(NULL, f)
1073
1074
1076static int
1077rename(const char *a, const char *b)
1078{
1079 wchar_t wa[W_PATH_MAX];
1080 wchar_t wb[W_PATH_MAX];
1081 path_to_unicode(NULL, a, wa, ARRAY_SIZE(wa));
1082 path_to_unicode(NULL, b, wb, ARRAY_SIZE(wb));
1083
1084 return MoveFileW(wa, wb) ? 0 : -1;
1085}
1086
1087
1088struct stat {
1089 int64_t st_size;
1090 time_t st_mtime;
1091};
1092
1093
1095static int
1096stat(const char *name, struct stat *st)
1097{
1098 wchar_t wbuf[W_PATH_MAX];
1099 WIN32_FILE_ATTRIBUTE_DATA attr;
1100 time_t creation_time, write_time;
1101
1102 path_to_unicode(NULL, name, wbuf, ARRAY_SIZE(wbuf));
1103 memset(&attr, 0, sizeof(attr));
1104
1105 GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr);
1106 st->st_size =
1107 (((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow;
1108
1109 write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime,
1110 attr.ftLastWriteTime.dwHighDateTime);
1111 creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime,
1112 attr.ftCreationTime.dwHighDateTime);
1113
1114 if (creation_time > write_time) {
1115 st->st_mtime = creation_time;
1116 } else {
1117 st->st_mtime = write_time;
1118 }
1119 return 0;
1120}
1121
1122#define access(x, a) 1 /* not required anyway */
1123
1124/* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */
1125/* Values from errno.h in Windows SDK (Visual Studio). */
1126#define EEXIST 17
1127#define EACCES 13
1128#define ENOENT 2
1129
1130#if defined(GCC_DIAGNOSTIC)
1131/* Enable unused function warning again */
1132#pragma GCC diagnostic pop
1133#endif
1134
1135#endif /* defined(_WIN32_WCE) */
1136
1137
1138#if defined(GCC_DIAGNOSTIC)
1139/* Show no warning in case system functions are not used. */
1140#pragma GCC diagnostic push
1141#pragma GCC diagnostic ignored "-Wunused-function"
1142#endif /* defined(GCC_DIAGNOSTIC) */
1143#if defined(__clang__)
1144/* Show no warning in case system functions are not used. */
1145#pragma clang diagnostic push
1146#pragma clang diagnostic ignored "-Wunused-function"
1147#endif
1148
1149static pthread_mutex_t global_lock_mutex;
1150
1151
1152#if defined(_WIN32)
1153/* Forward declaration for Windows */
1155static int pthread_mutex_lock(pthread_mutex_t *mutex);
1156
1158static int pthread_mutex_unlock(pthread_mutex_t *mutex);
1159#endif
1160
1161
1163static void
1165{
1166 (void)pthread_mutex_lock(&global_lock_mutex);
1167}
1168
1169
1171static void
1173{
1174 (void)pthread_mutex_unlock(&global_lock_mutex);
1175}
1176
1177
1179static int
1180mg_atomic_inc(volatile int *addr)
1181{
1182 int ret;
1183#if defined(_WIN32) && !defined(NO_ATOMICS)
1184 /* Depending on the SDK, this function uses either
1185 * (volatile unsigned int *) or (volatile LONG *),
1186 * so whatever you use, the other SDK is likely to raise a warning. */
1187 ret = InterlockedIncrement((volatile long *)addr);
1188#elif defined(__GNUC__) \
1189 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1190 && !defined(NO_ATOMICS)
1191 ret = __sync_add_and_fetch(addr, 1);
1192#else
1194 ret = (++(*addr));
1196#endif
1197 return ret;
1198}
1199
1200
1202static int
1203mg_atomic_dec(volatile int *addr)
1204{
1205 int ret;
1206#if defined(_WIN32) && !defined(NO_ATOMICS)
1207 /* Depending on the SDK, this function uses either
1208 * (volatile unsigned int *) or (volatile LONG *),
1209 * so whatever you use, the other SDK is likely to raise a warning. */
1210 ret = InterlockedDecrement((volatile long *)addr);
1211#elif defined(__GNUC__) \
1212 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1213 && !defined(NO_ATOMICS)
1214 ret = __sync_sub_and_fetch(addr, 1);
1215#else
1217 ret = (--(*addr));
1219#endif
1220 return ret;
1221}
1222
1223
1224#if defined(USE_SERVER_STATS)
1225static int64_t
1226mg_atomic_add(volatile int64_t *addr, int64_t value)
1227{
1228 int64_t ret;
1229#if defined(_WIN64) && !defined(NO_ATOMICS)
1230 ret = InterlockedAdd64(addr, value);
1231#elif defined(__GNUC__) \
1232 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1233 && !defined(NO_ATOMICS)
1234 ret = __sync_add_and_fetch(addr, value);
1235#else
1237 *addr += value;
1238 ret = (*addr);
1240#endif
1241 return ret;
1242}
1243#endif
1244
1245
1246#if defined(GCC_DIAGNOSTIC)
1247/* Show no warning in case system functions are not used. */
1248#pragma GCC diagnostic pop
1249#endif /* defined(GCC_DIAGNOSTIC) */
1250#if defined(__clang__)
1251/* Show no warning in case system functions are not used. */
1252#pragma clang diagnostic pop
1253#endif
1254
1255
1256#if defined(USE_SERVER_STATS)
1257
1258struct mg_memory_stat {
1259 volatile int64_t totalMemUsed;
1260 volatile int64_t maxMemUsed;
1261 volatile int blockCount;
1262};
1263
1264
1265static struct mg_memory_stat *get_memory_stat(struct mg_context *ctx);
1266
1267
1268static void *
1269mg_malloc_ex(size_t size,
1270 struct mg_context *ctx,
1271 const char *file,
1272 unsigned line)
1273{
1274 void *data = malloc(size + 2 * sizeof(uintptr_t));
1275 void *memory = 0;
1276 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1277
1278#if defined(MEMORY_DEBUGGING)
1279 char mallocStr[256];
1280#else
1281 (void)file;
1282 (void)line;
1283#endif
1284
1285 if (data) {
1286 int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size);
1287 if (mmem > mstat->maxMemUsed) {
1288 /* could use atomic compare exchange, but this
1289 * seems overkill for statistics data */
1290 mstat->maxMemUsed = mmem;
1291 }
1292
1293 mg_atomic_inc(&mstat->blockCount);
1294 ((uintptr_t *)data)[0] = size;
1295 ((uintptr_t *)data)[1] = (uintptr_t)mstat;
1296 memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
1297 }
1298
1299#if defined(MEMORY_DEBUGGING)
1300 sprintf(mallocStr,
1301 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1302 memory,
1303 (unsigned long)size,
1304 (unsigned long)mstat->totalMemUsed,
1305 (unsigned long)mstat->blockCount,
1306 file,
1307 line);
1308#if defined(_WIN32)
1309 OutputDebugStringA(mallocStr);
1310#else
1311 DEBUG_TRACE("%s", mallocStr);
1312#endif
1313#endif
1314
1315 return memory;
1316}
1317
1318
1319static void *
1320mg_calloc_ex(size_t count,
1321 size_t size,
1322 struct mg_context *ctx,
1323 const char *file,
1324 unsigned line)
1325{
1326 void *data = mg_malloc_ex(size * count, ctx, file, line);
1327
1328 if (data) {
1329 memset(data, 0, size * count);
1330 }
1331 return data;
1332}
1333
1334
1335static void
1336mg_free_ex(void *memory, const char *file, unsigned line)
1337{
1338 void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
1339
1340
1341#if defined(MEMORY_DEBUGGING)
1342 char mallocStr[256];
1343#else
1344 (void)file;
1345 (void)line;
1346#endif
1347
1348 if (memory) {
1349 uintptr_t size = ((uintptr_t *)data)[0];
1350 struct mg_memory_stat *mstat =
1351 (struct mg_memory_stat *)(((uintptr_t *)data)[1]);
1352 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size);
1353 mg_atomic_dec(&mstat->blockCount);
1354#if defined(MEMORY_DEBUGGING)
1355 sprintf(mallocStr,
1356 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1357 memory,
1358 (unsigned long)size,
1359 (unsigned long)mstat->totalMemUsed,
1360 (unsigned long)mstat->blockCount,
1361 file,
1362 line);
1363#if defined(_WIN32)
1364 OutputDebugStringA(mallocStr);
1365#else
1366 DEBUG_TRACE("%s", mallocStr);
1367#endif
1368#endif
1369 free(data);
1370 }
1371}
1372
1373
1374static void *
1375mg_realloc_ex(void *memory,
1376 size_t newsize,
1377 struct mg_context *ctx,
1378 const char *file,
1379 unsigned line)
1380{
1381 void *data;
1382 void *_realloc;
1383 uintptr_t oldsize;
1384
1385#if defined(MEMORY_DEBUGGING)
1386 char mallocStr[256];
1387#else
1388 (void)file;
1389 (void)line;
1390#endif
1391
1392 if (newsize) {
1393 if (memory) {
1394 /* Reallocate existing block */
1395 struct mg_memory_stat *mstat;
1396 data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
1397 oldsize = ((uintptr_t *)data)[0];
1398 mstat = (struct mg_memory_stat *)((uintptr_t *)data)[1];
1399 _realloc = realloc(data, newsize + 2 * sizeof(uintptr_t));
1400 if (_realloc) {
1401 data = _realloc;
1402 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize);
1403#if defined(MEMORY_DEBUGGING)
1404 sprintf(mallocStr,
1405 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1406 memory,
1407 (unsigned long)oldsize,
1408 (unsigned long)mstat->totalMemUsed,
1409 (unsigned long)mstat->blockCount,
1410 file,
1411 line);
1412#if defined(_WIN32)
1413 OutputDebugStringA(mallocStr);
1414#else
1415 DEBUG_TRACE("%s", mallocStr);
1416#endif
1417#endif
1418 mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize);
1419#if defined(MEMORY_DEBUGGING)
1420 sprintf(mallocStr,
1421 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1422 memory,
1423 (unsigned long)newsize,
1424 (unsigned long)mstat->totalMemUsed,
1425 (unsigned long)mstat->blockCount,
1426 file,
1427 line);
1428#if defined(_WIN32)
1429 OutputDebugStringA(mallocStr);
1430#else
1431 DEBUG_TRACE("%s", mallocStr);
1432#endif
1433#endif
1434 *(uintptr_t *)data = newsize;
1435 data = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
1436 } else {
1437#if defined(MEMORY_DEBUGGING)
1438#if defined(_WIN32)
1439 OutputDebugStringA("MEM: realloc failed\n");
1440#else
1441 DEBUG_TRACE("%s", "MEM: realloc failed\n");
1442#endif
1443#endif
1444 return _realloc;
1445 }
1446 } else {
1447 /* Allocate new block */
1448 data = mg_malloc_ex(newsize, ctx, file, line);
1449 }
1450 } else {
1451 /* Free existing block */
1452 data = 0;
1453 mg_free_ex(memory, file, line);
1454 }
1455
1456 return data;
1457}
1458
1459#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
1460#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
1461#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
1462#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1463
1464#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
1465#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
1466#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
1467
1468#else /* USE_SERVER_STATS */
1469
1470static __inline void *
1472{
1473 return malloc(a);
1474}
1475
1476static __inline void *
1477mg_calloc(size_t a, size_t b)
1478{
1479 return calloc(a, b);
1480}
1481
1482static __inline void *
1483mg_realloc(void *a, size_t b)
1484{
1485 return realloc(a, b);
1486}
1487
1488static __inline void
1490{
1491 free(a);
1492}
1493
1494#define mg_malloc_ctx(a, c) mg_malloc(a)
1495#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
1496#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
1497#define mg_free_ctx(a, c) mg_free(a)
1498
1499#endif /* USE_SERVER_STATS */
1500
1501
1502static void mg_vsnprintf(const struct mg_connection *conn,
1503 int *truncated,
1504 char *buf,
1505 size_t buflen,
1506 const char *fmt,
1507 va_list ap);
1508
1509static void mg_snprintf(const struct mg_connection *conn,
1510 int *truncated,
1511 char *buf,
1512 size_t buflen,
1513 PRINTF_FORMAT_STRING(const char *fmt),
1514 ...) PRINTF_ARGS(5, 6);
1515
1516/* This following lines are just meant as a reminder to use the mg-functions
1517 * for memory management */
1518#if defined(malloc)
1519#undef malloc
1520#endif
1521#if defined(calloc)
1522#undef calloc
1523#endif
1524#if defined(realloc)
1525#undef realloc
1526#endif
1527#if defined(free)
1528#undef free
1529#endif
1530#if defined(snprintf)
1531#undef snprintf
1532#endif
1533#if defined(vsnprintf)
1534#undef vsnprintf
1535#endif
1536#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1537#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1538#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1539#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1540#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
1541#if defined(_WIN32)
1542/* vsnprintf must not be used in any system,
1543 * but this define only works well for Windows. */
1544#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1545#endif
1546
1547
1548/* mg_init_library counter */
1550
1551#if !defined(NO_SSL)
1552static int mg_ssl_initialized = 0;
1553#endif
1554
1555static pthread_key_t sTlsKey; /* Thread local storage index */
1556static int thread_idx_max = 0;
1557
1558#if defined(MG_LEGACY_INTERFACE)
1559#define MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE
1560#endif
1561
1564 unsigned long thread_idx;
1565#if defined(_WIN32)
1566 HANDLE pthread_cond_helper_mutex;
1567 struct mg_workerTLS *next_waiting_thread;
1568#endif
1569#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
1570 char txtbuf[4];
1571#endif
1572};
1573
1574
1575#if defined(GCC_DIAGNOSTIC)
1576/* Show no warning in case system functions are not used. */
1577#pragma GCC diagnostic push
1578#pragma GCC diagnostic ignored "-Wunused-function"
1579#endif /* defined(GCC_DIAGNOSTIC) */
1580#if defined(__clang__)
1581/* Show no warning in case system functions are not used. */
1582#pragma clang diagnostic push
1583#pragma clang diagnostic ignored "-Wunused-function"
1584#endif
1585
1586
1587/* Get a unique thread ID as unsigned long, independent from the data type
1588 * of thread IDs defined by the operating system API.
1589 * If two calls to mg_current_thread_id return the same value, they calls
1590 * are done from the same thread. If they return different values, they are
1591 * done from different threads. (Provided this function is used in the same
1592 * process context and threads are not repeatedly created and deleted, but
1593 * CivetWeb does not do that).
1594 * This function must match the signature required for SSL id callbacks:
1595 * CRYPTO_set_id_callback
1596 */
1598static unsigned long
1600{
1601#if defined(_WIN32)
1602 return GetCurrentThreadId();
1603#else
1604
1605#if defined(__clang__)
1606#pragma clang diagnostic push
1607#pragma clang diagnostic ignored "-Wunreachable-code"
1608/* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
1609 * or not, so one of the two conditions will be unreachable by construction.
1610 * Unfortunately the C standard does not define a way to check this at
1611 * compile time, since the #if preprocessor conditions can not use the sizeof
1612 * operator as an argument. */
1613#endif
1614
1615 if (sizeof(pthread_t) > sizeof(unsigned long)) {
1616 /* This is the problematic case for CRYPTO_set_id_callback:
1617 * The OS pthread_t can not be cast to unsigned long. */
1618 struct mg_workerTLS *tls =
1619 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
1620 if (tls == NULL) {
1621 /* SSL called from an unknown thread: Create some thread index.
1622 */
1623 tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS));
1624 tls->is_master = -2; /* -2 means "3rd party thread" */
1625 tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
1626 pthread_setspecific(sTlsKey, tls);
1627 }
1628 return tls->thread_idx;
1629 } else {
1630 /* pthread_t may be any data type, so a simple cast to unsigned long
1631 * can rise a warning/error, depending on the platform.
1632 * Here memcpy is used as an anything-to-anything cast. */
1633 unsigned long ret = 0;
1634 pthread_t t = pthread_self();
1635 memcpy(&ret, &t, sizeof(pthread_t));
1636 return ret;
1637 }
1638
1639#if defined(__clang__)
1640#pragma clang diagnostic pop
1641#endif
1642
1643#endif
1644}
1645
1646
1648static uint64_t
1650{
1651 struct timespec tsnow;
1652 clock_gettime(CLOCK_REALTIME, &tsnow);
1653 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1654}
1655
1656
1657#if defined(GCC_DIAGNOSTIC)
1658/* Show no warning in case system functions are not used. */
1659#pragma GCC diagnostic pop
1660#endif /* defined(GCC_DIAGNOSTIC) */
1661#if defined(__clang__)
1662/* Show no warning in case system functions are not used. */
1663#pragma clang diagnostic pop
1664#endif
1665
1666
1667#if defined(NEED_DEBUG_TRACE_FUNC)
1668static void
1669DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
1670{
1671 va_list args;
1672 uint64_t nsnow;
1673 static uint64_t nslast;
1674 struct timespec tsnow;
1675
1676 /* Get some operating system independent thread id */
1677 unsigned long thread_id = mg_current_thread_id();
1678
1679 clock_gettime(CLOCK_REALTIME, &tsnow);
1680 nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000)
1681 + ((uint64_t)tsnow.tv_nsec);
1682
1683 if (!nslast) {
1684 nslast = nsnow;
1685 }
1686
1687 flockfile(stdout);
1688 printf("*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ",
1689 (unsigned long)tsnow.tv_sec,
1690 (unsigned long)tsnow.tv_nsec,
1691 nsnow - nslast,
1692 thread_id,
1693 func,
1694 line);
1695 va_start(args, fmt);
1696 vprintf(fmt, args);
1697 va_end(args);
1698 putchar('\n');
1699 fflush(stdout);
1700 funlockfile(stdout);
1701 nslast = nsnow;
1702}
1703#endif /* NEED_DEBUG_TRACE_FUNC */
1704
1705
1706#define MD5_STATIC static
1707#include "md5.inl"
1708
1709/* Darwin prior to 7.0 and Win32 do not have socklen_t */
1710#if defined(NO_SOCKLEN_T)
1711typedef int socklen_t;
1712#endif /* NO_SOCKLEN_T */
1713
1714#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
1715
1716#if !defined(MSG_NOSIGNAL)
1717#define MSG_NOSIGNAL (0)
1718#endif
1719
1720
1721#if defined(NO_SSL)
1722typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
1723typedef struct SSL_CTX SSL_CTX;
1724#else
1725#if defined(NO_SSL_DL)
1726#include <openssl/bn.h>
1727#include <openssl/conf.h>
1728#include <openssl/crypto.h>
1729#include <openssl/dh.h>
1730#include <openssl/engine.h>
1731#include <openssl/err.h>
1732#include <openssl/opensslv.h>
1733#include <openssl/pem.h>
1734#include <openssl/ssl.h>
1735#include <openssl/tls1.h>
1736#include <openssl/x509.h>
1737
1738#if defined(WOLFSSL_VERSION)
1739/* Additional defines for WolfSSL, see
1740 * https://github.com/civetweb/civetweb/issues/583 */
1741#include "wolfssl_extras.inl"
1742#endif
1743
1744#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
1745/* If OpenSSL headers are included, automatically select the API version */
1746#if !defined(OPENSSL_API_1_1)
1747#define OPENSSL_API_1_1
1748#endif
1749#define OPENSSL_REMOVE_THREAD_STATE()
1750#else
1751#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_thread_state(NULL)
1752#endif
1753
1754#else
1755
1756/* SSL loaded dynamically from DLL.
1757 * I put the prototypes here to be independent from OpenSSL source
1758 * installation. */
1759
1760typedef struct ssl_st SSL;
1761typedef struct ssl_method_st SSL_METHOD;
1762typedef struct ssl_ctx_st SSL_CTX;
1763typedef struct x509_store_ctx_st X509_STORE_CTX;
1764typedef struct x509_name X509_NAME;
1765typedef struct asn1_integer ASN1_INTEGER;
1766typedef struct bignum BIGNUM;
1767typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS;
1768typedef struct evp_md EVP_MD;
1769typedef struct x509 X509;
1770
1771
1772#define SSL_CTRL_OPTIONS (32)
1773#define SSL_CTRL_CLEAR_OPTIONS (77)
1774#define SSL_CTRL_SET_ECDH_AUTO (94)
1775
1776#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L
1777#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L
1778#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
1779
1780#define SSL_VERIFY_NONE (0)
1781#define SSL_VERIFY_PEER (1)
1782#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
1783#define SSL_VERIFY_CLIENT_ONCE (4)
1784#define SSL_OP_ALL ((long)(0x80000BFFUL))
1785#define SSL_OP_NO_SSLv2 (0x01000000L)
1786#define SSL_OP_NO_SSLv3 (0x02000000L)
1787#define SSL_OP_NO_TLSv1 (0x04000000L)
1788#define SSL_OP_NO_TLSv1_2 (0x08000000L)
1789#define SSL_OP_NO_TLSv1_1 (0x10000000L)
1790#define SSL_OP_SINGLE_DH_USE (0x00100000L)
1791#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L)
1792#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L)
1793#define SSL_OP_NO_COMPRESSION (0x00020000L)
1794
1795#define SSL_CB_HANDSHAKE_START (0x10)
1796#define SSL_CB_HANDSHAKE_DONE (0x20)
1797
1798#define SSL_ERROR_NONE (0)
1799#define SSL_ERROR_SSL (1)
1800#define SSL_ERROR_WANT_READ (2)
1801#define SSL_ERROR_WANT_WRITE (3)
1802#define SSL_ERROR_WANT_X509_LOOKUP (4)
1803#define SSL_ERROR_SYSCALL (5) /* see errno */
1804#define SSL_ERROR_ZERO_RETURN (6)
1805#define SSL_ERROR_WANT_CONNECT (7)
1806#define SSL_ERROR_WANT_ACCEPT (8)
1807
1808#define TLSEXT_TYPE_server_name (0)
1809#define TLSEXT_NAMETYPE_host_name (0)
1810#define SSL_TLSEXT_ERR_OK (0)
1811#define SSL_TLSEXT_ERR_ALERT_WARNING (1)
1812#define SSL_TLSEXT_ERR_ALERT_FATAL (2)
1813#define SSL_TLSEXT_ERR_NOACK (3)
1814
1815struct ssl_func {
1816 const char *name; /* SSL function name */
1817 void (*ptr)(void); /* Function pointer */
1818};
1819
1820
1821#if defined(OPENSSL_API_1_1)
1822
1823#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
1824#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
1825#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
1826#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
1827#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
1828#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
1829#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
1830#define SSL_new (*(SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
1831#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
1832#define TLS_server_method (*(SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
1833#define OPENSSL_init_ssl \
1834 (*(int (*)(uint64_t opts, \
1835 const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10] \
1836 .ptr)
1837#define SSL_CTX_use_PrivateKey_file \
1838 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
1839#define SSL_CTX_use_certificate_file \
1840 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
1841#define SSL_CTX_set_default_passwd_cb \
1842 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
1843#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
1844#define SSL_CTX_use_certificate_chain_file \
1845 (*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr)
1846#define TLS_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[16].ptr)
1847#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr)
1848#define SSL_CTX_set_verify \
1849 (*(void (*)(SSL_CTX *, \
1850 int, \
1851 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18] \
1852 .ptr)
1853#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr)
1854#define SSL_CTX_load_verify_locations \
1855 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr)
1856#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr)
1857#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr)
1858#define SSL_get_peer_certificate (*(X509 * (*)(SSL *)) ssl_sw[23].ptr)
1859#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr)
1860#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *)) ssl_sw[25].ptr)
1861#define SSL_CIPHER_get_name \
1862 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr)
1863#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr)
1864#define SSL_CTX_set_session_id_context \
1865 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr)
1866#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr)
1867#define SSL_CTX_set_cipher_list \
1868 (*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr)
1869#define SSL_CTX_set_options \
1870 (*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr)
1871#define SSL_CTX_set_info_callback \
1872 (*(void (*)(SSL_CTX * ctx, void (*callback)(const SSL *, int, int))) \
1873 ssl_sw[32] \
1874 .ptr)
1875#define SSL_get_ex_data (*(char *(*)(const SSL *, int))ssl_sw[33].ptr)
1876#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
1877#define SSL_CTX_callback_ctrl \
1878 (*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
1879#define SSL_get_servername \
1880 (*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
1881#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *)) ssl_sw[37].ptr)
1882#define SSL_ctrl (*(long (*)(SSL *, int, long, void *))ssl_sw[38].ptr)
1883
1884#define SSL_CTX_clear_options(ctx, op) \
1885 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
1886#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
1887 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
1888
1889#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
1890#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
1891#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
1892#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
1893 SSL_CTX_callback_ctrl(ctx, \
1894 SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
1895 (void (*)(void))cb)
1896#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
1897 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg)
1898#define SSL_set_tlsext_host_name(ctx, arg) \
1899 SSL_ctrl(ctx, SSL_CTRL_SET_TLSEXT_HOSTNAME, 0, (void *)arg)
1900
1901#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
1902#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
1903
1904#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
1905#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
1906
1907#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr)
1908#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr)
1909#define CONF_modules_unload (*(void (*)(int))crypto_sw[2].ptr)
1910#define X509_free (*(void (*)(X509 *))crypto_sw[3].ptr)
1911#define X509_get_subject_name (*(X509_NAME * (*)(X509 *)) crypto_sw[4].ptr)
1912#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *)) crypto_sw[5].ptr)
1913#define X509_NAME_oneline \
1914 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[6].ptr)
1915#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *)) crypto_sw[7].ptr)
1916#define EVP_get_digestbyname \
1917 (*(const EVP_MD *(*)(const char *))crypto_sw[8].ptr)
1918#define EVP_Digest \
1919 (*(int (*)( \
1920 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
1921 crypto_sw[9] \
1922 .ptr)
1923#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[10].ptr)
1924#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[11].ptr)
1925#define ASN1_INTEGER_to_BN \
1926 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn)) crypto_sw[12].ptr)
1927#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[13].ptr)
1928#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[14].ptr)
1929
1930#define OPENSSL_free(a) CRYPTO_free(a)
1931
1932#define OPENSSL_REMOVE_THREAD_STATE()
1933
1934/* init_ssl_ctx() function updates this array.
1935 * It loads SSL library dynamically and changes NULLs to the actual addresses
1936 * of respective functions. The macros above (like SSL_connect()) are really
1937 * just calling these functions indirectly via the pointer. */
1938static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
1939 {"SSL_accept", NULL},
1940 {"SSL_connect", NULL},
1941 {"SSL_read", NULL},
1942 {"SSL_write", NULL},
1943 {"SSL_get_error", NULL},
1944 {"SSL_set_fd", NULL},
1945 {"SSL_new", NULL},
1946 {"SSL_CTX_new", NULL},
1947 {"TLS_server_method", NULL},
1948 {"OPENSSL_init_ssl", NULL},
1949 {"SSL_CTX_use_PrivateKey_file", NULL},
1950 {"SSL_CTX_use_certificate_file", NULL},
1951 {"SSL_CTX_set_default_passwd_cb", NULL},
1952 {"SSL_CTX_free", NULL},
1953 {"SSL_CTX_use_certificate_chain_file", NULL},
1954 {"TLS_client_method", NULL},
1955 {"SSL_pending", NULL},
1956 {"SSL_CTX_set_verify", NULL},
1957 {"SSL_shutdown", NULL},
1958 {"SSL_CTX_load_verify_locations", NULL},
1959 {"SSL_CTX_set_default_verify_paths", NULL},
1960 {"SSL_CTX_set_verify_depth", NULL},
1961 {"SSL_get_peer_certificate", NULL},
1962 {"SSL_get_version", NULL},
1963 {"SSL_get_current_cipher", NULL},
1964 {"SSL_CIPHER_get_name", NULL},
1965 {"SSL_CTX_check_private_key", NULL},
1966 {"SSL_CTX_set_session_id_context", NULL},
1967 {"SSL_CTX_ctrl", NULL},
1968 {"SSL_CTX_set_cipher_list", NULL},
1969 {"SSL_CTX_set_options", NULL},
1970 {"SSL_CTX_set_info_callback", NULL},
1971 {"SSL_get_ex_data", NULL},
1972 {"SSL_set_ex_data", NULL},
1973 {"SSL_CTX_callback_ctrl", NULL},
1974 {"SSL_get_servername", NULL},
1975 {"SSL_set_SSL_CTX", NULL},
1976 {"SSL_ctrl", NULL},
1977 {NULL, NULL}};
1978
1979
1980/* Similar array as ssl_sw. These functions could be located in different
1981 * lib. */
1982static struct ssl_func crypto_sw[] = {{"ERR_get_error", NULL},
1983 {"ERR_error_string", NULL},
1984 {"CONF_modules_unload", NULL},
1985 {"X509_free", NULL},
1986 {"X509_get_subject_name", NULL},
1987 {"X509_get_issuer_name", NULL},
1988 {"X509_NAME_oneline", NULL},
1989 {"X509_get_serialNumber", NULL},
1990 {"EVP_get_digestbyname", NULL},
1991 {"EVP_Digest", NULL},
1992 {"i2d_X509", NULL},
1993 {"BN_bn2hex", NULL},
1994 {"ASN1_INTEGER_to_BN", NULL},
1995 {"BN_free", NULL},
1996 {"CRYPTO_free", NULL},
1997 {NULL, NULL}};
1998#else
1999
2000#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
2001#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
2002#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
2003#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
2004#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
2005#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
2006#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
2007#define SSL_new (*(SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
2008#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
2009#define SSLv23_server_method (*(SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
2010#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
2011#define SSL_CTX_use_PrivateKey_file \
2012 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
2013#define SSL_CTX_use_certificate_file \
2014 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
2015#define SSL_CTX_set_default_passwd_cb \
2016 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
2017#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
2018#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
2019#define SSL_CTX_use_certificate_chain_file \
2020 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
2021#define SSLv23_client_method (*(SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
2022#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
2023#define SSL_CTX_set_verify \
2024 (*(void (*)(SSL_CTX *, \
2025 int, \
2026 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19] \
2027 .ptr)
2028#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
2029#define SSL_CTX_load_verify_locations \
2030 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
2031#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
2032#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
2033#define SSL_get_peer_certificate (*(X509 * (*)(SSL *)) ssl_sw[24].ptr)
2034#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
2035#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *)) ssl_sw[26].ptr)
2036#define SSL_CIPHER_get_name \
2037 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
2038#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
2039#define SSL_CTX_set_session_id_context \
2040 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
2041#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
2042#define SSL_CTX_set_cipher_list \
2043 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
2044#define SSL_CTX_set_info_callback \
2045 (*(void (*)(SSL_CTX *, void (*callback)(const SSL *, int, int)))ssl_sw[32] \
2046 .ptr)
2047#define SSL_get_ex_data (*(char *(*)(const SSL *, int))ssl_sw[33].ptr)
2048#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
2049#define SSL_CTX_callback_ctrl \
2050 (*(long (*)(SSL_CTX *, int, void (*)(void)))ssl_sw[35].ptr)
2051#define SSL_get_servername \
2052 (*(const char *(*)(const SSL *, int type))ssl_sw[36].ptr)
2053#define SSL_set_SSL_CTX (*(SSL_CTX * (*)(SSL *, SSL_CTX *)) ssl_sw[37].ptr)
2054#define SSL_ctrl (*(long (*)(SSL *, int, long, void *))ssl_sw[38].ptr)
2055
2056#define SSL_CTX_set_options(ctx, op) \
2057 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
2058#define SSL_CTX_clear_options(ctx, op) \
2059 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
2060#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
2061 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
2062
2063#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53
2064#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54
2065#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
2066#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \
2067 SSL_CTX_callback_ctrl(ctx, \
2068 SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
2069 (void (*)(void))cb)
2070#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \
2071 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, (void *)arg)
2072#define SSL_set_tlsext_host_name(ctx, arg) \
2073 SSL_ctrl(ctx, SSL_CTRL_SET_TLSEXT_HOSTNAME, 0, (void *)arg)
2074
2075#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
2076#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
2077
2078#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
2079#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
2080
2081#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
2082#define CRYPTO_set_locking_callback \
2083 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
2084#define CRYPTO_set_id_callback \
2085 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
2086#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
2087#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
2088#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
2089#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
2090#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
2091#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
2092#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
2093#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
2094#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr)
2095#define X509_get_subject_name (*(X509_NAME * (*)(X509 *)) crypto_sw[12].ptr)
2096#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *)) crypto_sw[13].ptr)
2097#define X509_NAME_oneline \
2098 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
2099#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *)) crypto_sw[15].ptr)
2100#define i2c_ASN1_INTEGER \
2101 (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
2102#define EVP_get_digestbyname \
2103 (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
2104#define EVP_Digest \
2105 (*(int (*)( \
2106 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
2107 crypto_sw[18] \
2108 .ptr)
2109#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
2110#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr)
2111#define ASN1_INTEGER_to_BN \
2112 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn)) crypto_sw[21].ptr)
2113#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr)
2114#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr)
2115
2116#define OPENSSL_free(a) CRYPTO_free(a)
2117
2118/* use here ERR_remove_state,
2119 * while on some platforms function is not included into library due to
2120 * deprication */
2121#define OPENSSL_REMOVE_THREAD_STATE() ERR_remove_state(0)
2122
2123/* init_ssl_ctx() function updates this array.
2124 * It loads SSL library dynamically and changes NULLs to the actual addresses
2125 * of respective functions. The macros above (like SSL_connect()) are really
2126 * just calling these functions indirectly via the pointer. */
2127static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
2128 {"SSL_accept", NULL},
2129 {"SSL_connect", NULL},
2130 {"SSL_read", NULL},
2131 {"SSL_write", NULL},
2132 {"SSL_get_error", NULL},
2133 {"SSL_set_fd", NULL},
2134 {"SSL_new", NULL},
2135 {"SSL_CTX_new", NULL},
2136 {"SSLv23_server_method", NULL},
2137 {"SSL_library_init", NULL},
2138 {"SSL_CTX_use_PrivateKey_file", NULL},
2139 {"SSL_CTX_use_certificate_file", NULL},
2140 {"SSL_CTX_set_default_passwd_cb", NULL},
2141 {"SSL_CTX_free", NULL},
2142 {"SSL_load_error_strings", NULL},
2143 {"SSL_CTX_use_certificate_chain_file", NULL},
2144 {"SSLv23_client_method", NULL},
2145 {"SSL_pending", NULL},
2146 {"SSL_CTX_set_verify", NULL},
2147 {"SSL_shutdown", NULL},
2148 {"SSL_CTX_load_verify_locations", NULL},
2149 {"SSL_CTX_set_default_verify_paths", NULL},
2150 {"SSL_CTX_set_verify_depth", NULL},
2151 {"SSL_get_peer_certificate", NULL},
2152 {"SSL_get_version", NULL},
2153 {"SSL_get_current_cipher", NULL},
2154 {"SSL_CIPHER_get_name", NULL},
2155 {"SSL_CTX_check_private_key", NULL},
2156 {"SSL_CTX_set_session_id_context", NULL},
2157 {"SSL_CTX_ctrl", NULL},
2158 {"SSL_CTX_set_cipher_list", NULL},
2159 {"SSL_CTX_set_info_callback", NULL},
2160 {"SSL_get_ex_data", NULL},
2161 {"SSL_set_ex_data", NULL},
2162 {"SSL_CTX_callback_ctrl", NULL},
2163 {"SSL_get_servername", NULL},
2164 {"SSL_set_SSL_CTX", NULL},
2165 {"SSL_ctrl", NULL},
2166 {NULL, NULL}};
2167
2168
2169/* Similar array as ssl_sw. These functions could be located in different
2170 * lib. */
2171static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
2172 {"CRYPTO_set_locking_callback", NULL},
2173 {"CRYPTO_set_id_callback", NULL},
2174 {"ERR_get_error", NULL},
2175 {"ERR_error_string", NULL},
2176 {"ERR_remove_state", NULL},
2177 {"ERR_free_strings", NULL},
2178 {"ENGINE_cleanup", NULL},
2179 {"CONF_modules_unload", NULL},
2180 {"CRYPTO_cleanup_all_ex_data", NULL},
2181 {"EVP_cleanup", NULL},
2182 {"X509_free", NULL},
2183 {"X509_get_subject_name", NULL},
2184 {"X509_get_issuer_name", NULL},
2185 {"X509_NAME_oneline", NULL},
2186 {"X509_get_serialNumber", NULL},
2187 {"i2c_ASN1_INTEGER", NULL},
2188 {"EVP_get_digestbyname", NULL},
2189 {"EVP_Digest", NULL},
2190 {"i2d_X509", NULL},
2191 {"BN_bn2hex", NULL},
2192 {"ASN1_INTEGER_to_BN", NULL},
2193 {"BN_free", NULL},
2194 {"CRYPTO_free", NULL},
2195 {NULL, NULL}};
2196#endif /* OPENSSL_API_1_1 */
2197#endif /* NO_SSL_DL */
2198#endif /* NO_SSL */
2199
2200
2201#if !defined(NO_CACHING)
2202static const char *month_names[] = {"Jan",
2203 "Feb",
2204 "Mar",
2205 "Apr",
2206 "May",
2207 "Jun",
2208 "Jul",
2209 "Aug",
2210 "Sep",
2211 "Oct",
2212 "Nov",
2213 "Dec"};
2214#endif /* !NO_CACHING */
2215
2216/* Unified socket address. For IPv6 support, add IPv6 address structure in
2217 * the
2218 * union u. */
2219union usa {
2220 struct sockaddr sa;
2221 struct sockaddr_in sin;
2222#if defined(USE_IPV6)
2223 struct sockaddr_in6 sin6;
2224#endif
2225};
2226
2227/* Describes a string (chunk of memory). */
2228struct vec {
2229 const char *ptr;
2230 size_t len;
2231};
2232
2234 /* File properties filled by mg_stat: */
2235 uint64_t size;
2237 int is_directory; /* Set to 1 if mg_stat is called for a directory */
2238 int is_gzipped; /* Set to 1 if the content is gzipped, in which
2239 * case we need a "Content-Eencoding: gzip" header */
2240 int location; /* 0 = nowhere, 1 = on disk, 2 = in memory */
2241};
2242
2244 char *p;
2245 uint32_t pos;
2246 char mode;
2247};
2248
2250 /* File properties filled by mg_fopen: */
2251 FILE *fp;
2252#if defined(MG_USE_OPEN_FILE)
2253 /* TODO (low): Remove obsolete "file in memory" implementation.
2254 * In an "early 2017" discussion at Google groups
2255 * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI
2256 * we decided to get rid of this feature (after some fade-out
2257 * phase). */
2258 const char *membuf;
2259#endif
2260};
2261
2262struct mg_file {
2265};
2266
2267#if defined(MG_USE_OPEN_FILE)
2268
2269#define STRUCT_FILE_INITIALIZER \
2270 { \
2271 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
2272 { \
2273 (FILE *)NULL, (const char *)NULL \
2274 } \
2275 }
2276
2277#else
2278
2279#define STRUCT_FILE_INITIALIZER \
2280 { \
2281 {(uint64_t)0, (time_t)0, 0, 0, 0}, \
2282 { \
2283 (FILE *)NULL \
2284 } \
2285 }
2286
2287#endif
2288
2289
2290/* Describes listening socket, or socket which was accept()-ed by the master
2291 * thread and queued for future handling by the worker thread. */
2292struct socket {
2293 SOCKET sock; /* Listening socket */
2294 union usa lsa; /* Local socket address */
2295 union usa rsa; /* Remote socket address */
2296 unsigned char is_ssl; /* Is port SSL-ed */
2297 unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
2298 * port */
2299 unsigned char in_use; /* Is valid */
2300};
2301
2302
2303/* Enum const for all options must be in sync with
2304 * static struct mg_option config_options[]
2305 * This is tested in the unit test (test/private.c)
2306 * "Private Config Options"
2307 */
2308enum {
2309 /* Once for each server */
2313 CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the
2314 * socket option typedef TCP_NODELAY. */
2317#if defined(__linux__)
2318 ALLOW_SENDFILE_CALL,
2319#endif
2320#if defined(_WIN32)
2321 CASE_SENSITIVE_FILES,
2322#endif
2329#if defined(USE_WEBSOCKET)
2330 WEBSOCKET_TIMEOUT,
2331 ENABLE_WEBSOCKET_PING_PONG,
2332#endif
2334#if defined(USE_LUA)
2335 LUA_BACKGROUND_SCRIPT,
2336 LUA_BACKGROUND_SCRIPT_PARAMS,
2337#endif
2338#if defined(USE_TIMERS)
2339 CGI_TIMEOUT,
2340#endif
2341
2342 /* Once for each domain */
2369
2370#if defined(USE_LUA)
2371 LUA_PRELOAD_FILE,
2372 LUA_SCRIPT_EXTENSIONS,
2373 LUA_SERVER_PAGE_EXTENSIONS,
2374#if defined(MG_EXPERIMENTAL_INTERFACES)
2375 LUA_DEBUG_PARAMS,
2376#endif
2377#endif
2378#if defined(USE_DUKTAPE)
2379 DUKTAPE_SCRIPT_EXTENSIONS,
2380#endif
2381
2382#if defined(USE_WEBSOCKET)
2383 WEBSOCKET_ROOT,
2384#endif
2385#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2386 LUA_WEBSOCKET_EXTENSIONS,
2387#endif
2388
2393#if !defined(NO_CACHING)
2395#endif
2396#if !defined(NO_SSL)
2398#endif
2401
2404
2405
2406/* Config option name, config types, default value.
2407 * Must be in the same order as the enum const above.
2408 */
2409static const struct mg_option config_options[] = {
2410
2411 /* Once for each server */
2412 {"listening_ports", MG_CONFIG_TYPE_STRING_LIST, "8080"},
2413 {"num_threads", MG_CONFIG_TYPE_NUMBER, "50"},
2414 {"run_as_user", MG_CONFIG_TYPE_STRING, NULL},
2415 {"tcp_nodelay", MG_CONFIG_TYPE_NUMBER, "0"},
2416 {"max_request_size", MG_CONFIG_TYPE_NUMBER, "16384"},
2417 {"linger_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2418#if defined(__linux__)
2419 {"allow_sendfile_call", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2420#endif
2421#if defined(_WIN32)
2422 {"case_sensitive", MG_CONFIG_TYPE_BOOLEAN, "no"},
2423#endif
2424 {"throttle", MG_CONFIG_TYPE_STRING_LIST, NULL},
2425 {"access_log_file", MG_CONFIG_TYPE_FILE, NULL},
2426 {"error_log_file", MG_CONFIG_TYPE_FILE, NULL},
2427 {"enable_keep_alive", MG_CONFIG_TYPE_BOOLEAN, "no"},
2428 {"request_timeout_ms", MG_CONFIG_TYPE_NUMBER, "30000"},
2429 {"keep_alive_timeout_ms", MG_CONFIG_TYPE_NUMBER, "500"},
2430#if defined(USE_WEBSOCKET)
2431 {"websocket_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2432 {"enable_websocket_ping_pong", MG_CONFIG_TYPE_BOOLEAN, "no"},
2433#endif
2434 {"decode_url", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2435#if defined(USE_LUA)
2436 {"lua_background_script", MG_CONFIG_TYPE_FILE, NULL},
2437 {"lua_background_script_params", MG_CONFIG_TYPE_STRING_LIST, NULL},
2438#endif
2439#if defined(USE_TIMERS)
2440 {"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
2441#endif
2442
2443 /* Once for each domain */
2444 {"document_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
2445 {"cgi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
2446 {"cgi_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
2447 {"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
2448 {"cgi_interpreter", MG_CONFIG_TYPE_FILE, NULL},
2449 {"protect_uri", MG_CONFIG_TYPE_STRING_LIST, NULL},
2450 {"authentication_domain", MG_CONFIG_TYPE_STRING, "mydomain.com"},
2451 {"enable_auth_domain_check", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2452 {"ssi_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"},
2453 {"enable_directory_listing", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2454 {"global_auth_file", MG_CONFIG_TYPE_FILE, NULL},
2455 {"index_files",
2457#if defined(USE_LUA)
2458 "index.xhtml,index.html,index.htm,"
2459 "index.lp,index.lsp,index.lua,index.cgi,"
2460 "index.shtml,index.php"},
2461#else
2462 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2463#endif
2464 {"access_control_list", MG_CONFIG_TYPE_STRING_LIST, NULL},
2465 {"extra_mime_types", MG_CONFIG_TYPE_STRING_LIST, NULL},
2466 {"ssl_certificate", MG_CONFIG_TYPE_FILE, NULL},
2467 {"ssl_certificate_chain", MG_CONFIG_TYPE_FILE, NULL},
2468 {"url_rewrite_patterns", MG_CONFIG_TYPE_STRING_LIST, NULL},
2469 {"hide_files_patterns", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
2470
2471 {"ssl_verify_peer", MG_CONFIG_TYPE_YES_NO_OPTIONAL, "no"},
2472
2473 {"ssl_ca_path", MG_CONFIG_TYPE_DIRECTORY, NULL},
2474 {"ssl_ca_file", MG_CONFIG_TYPE_FILE, NULL},
2475 {"ssl_verify_depth", MG_CONFIG_TYPE_NUMBER, "9"},
2476 {"ssl_default_verify_paths", MG_CONFIG_TYPE_BOOLEAN, "yes"},
2477 {"ssl_cipher_list", MG_CONFIG_TYPE_STRING, NULL},
2478 {"ssl_protocol_version", MG_CONFIG_TYPE_NUMBER, "0"},
2479 {"ssl_short_trust", MG_CONFIG_TYPE_BOOLEAN, "no"},
2480
2481#if defined(USE_LUA)
2482 {"lua_preload_file", MG_CONFIG_TYPE_FILE, NULL},
2483 {"lua_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
2484 {"lua_server_page_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"},
2485#if defined(MG_EXPERIMENTAL_INTERFACES)
2486 {"lua_debug", MG_CONFIG_TYPE_STRING, NULL},
2487#endif
2488#endif
2489#if defined(USE_DUKTAPE)
2490 /* The support for duktape is still in alpha version state.
2491 * The name of this config option might change. */
2492 {"duktape_script_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"},
2493#endif
2494
2495#if defined(USE_WEBSOCKET)
2496 {"websocket_root", MG_CONFIG_TYPE_DIRECTORY, NULL},
2497#endif
2498#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2499 {"lua_websocket_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
2500#endif
2501 {"access_control_allow_origin", MG_CONFIG_TYPE_STRING, "*"},
2502 {"access_control_allow_methods", MG_CONFIG_TYPE_STRING, "*"},
2503 {"access_control_allow_headers", MG_CONFIG_TYPE_STRING, "*"},
2504 {"error_pages", MG_CONFIG_TYPE_DIRECTORY, NULL},
2505#if !defined(NO_CACHING)
2506 {"static_file_max_age", MG_CONFIG_TYPE_NUMBER, "3600"},
2507#endif
2508#if !defined(NO_SSL)
2509 {"strict_transport_security_max_age", MG_CONFIG_TYPE_NUMBER, NULL},
2510#endif
2511 {"additional_header", MG_CONFIG_TYPE_STRING_MULTILINE, NULL},
2512 {"allow_index_script_resource", MG_CONFIG_TYPE_BOOLEAN, "no"},
2513
2514 {NULL, MG_CONFIG_TYPE_UNKNOWN, NULL}};
2515
2516
2517/* Check if the config_options and the corresponding enum have compatible
2518 * sizes. */
2520 == (NUM_OPTIONS + 1),
2521 "config_options and enum not sync");
2522
2523
2525
2526
2528 /* Name/Pattern of the URI. */
2529 char *uri;
2530 size_t uri_len;
2531
2532 /* handler type */
2534
2535 /* Handler for http/https or authorization requests. */
2537 unsigned int refcount;
2538 pthread_mutex_t refcount_mutex; /* Protects refcount */
2540 refcount_cond; /* Signaled when handler refcount is decremented */
2541
2542 /* Handler for ws/wss (websocket) requests. */
2547
2548 /* accepted subprotocols for ws/wss requests. */
2550
2551 /* Handler for authorization requests */
2553
2554 /* User supplied argument for the handler function. */
2555 void *cbdata;
2556
2557 /* next handler in a linked list */
2559};
2560
2561
2562enum {
2568
2569
2571 SSL_CTX *ssl_ctx; /* SSL context */
2572 char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
2573 struct mg_handler_info *handlers; /* linked list of uri handlers */
2574
2575 /* Server nonce */
2576 uint64_t auth_nonce_mask; /* Mask for all nonce values */
2577 unsigned long nonce_count; /* Used nonces, used for authentication */
2578
2579#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2580 /* linked list of shared lua websockets */
2581 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2582#endif
2583
2584 /* Linked list of domains */
2586};
2587
2588
2590
2591 /* Part 1 - Physical context:
2592 * This holds threads, ports, timeouts, ...
2593 * set for the entire server, independent from the
2594 * addressed hostname.
2595 */
2596
2597 /* Connection related */
2598 int context_type; /* See CONTEXT_* above */
2599
2601 struct pollfd *listening_socket_fds;
2603
2604 struct mg_connection *worker_connections; /* The connection struct, pre-
2605 * allocated for each worker */
2606
2607#if defined(USE_SERVER_STATS)
2608 int active_connections;
2609 int max_connections;
2610 int64_t total_connections;
2611 int64_t total_requests;
2612 int64_t total_data_read;
2613 int64_t total_data_written;
2614#endif
2615
2616 /* Thread related */
2617 volatile int stop_flag; /* Should we stop event loop */
2618 pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */
2619
2620 pthread_t masterthreadid; /* The master thread ID */
2621 unsigned int
2622 cfg_worker_threads; /* The number of configured worker threads. */
2623 pthread_t *worker_threadids; /* The worker thread IDs */
2624
2625/* Connection to thread dispatching */
2626#if defined(ALTERNATIVE_QUEUE)
2629#else
2630 struct socket queue[MGSQLEN]; /* Accepted sockets */
2631 volatile int sq_head; /* Head of the socket queue */
2632 volatile int sq_tail; /* Tail of the socket queue */
2633 pthread_cond_t sq_full; /* Signaled when socket is produced */
2634 pthread_cond_t sq_empty; /* Signaled when socket is consumed */
2635#endif
2636
2637 /* Memory related */
2638 unsigned int max_request_size; /* The max request size */
2639
2640#if defined(USE_SERVER_STATS)
2641 struct mg_memory_stat ctx_memory;
2642#endif
2643
2644 /* Operating system related */
2645 char *systemName; /* What operating system is running */
2646 time_t start_time; /* Server start time, used for authentication
2647 * and for diagnstics. */
2648
2649#if defined(USE_TIMERS)
2650 struct ttimers *timers;
2651#endif
2652
2653/* Lua specific: Background operations and shared websockets */
2654#if defined(USE_LUA)
2655 void *lua_background_state;
2656#endif
2657
2658 /* Server nonce */
2659 pthread_mutex_t nonce_mutex; /* Protects nonce_count */
2660
2661 /* Server callbacks */
2662 struct mg_callbacks callbacks; /* User-defined callback function */
2663 void *user_data; /* User-defined data */
2664
2665 /* Part 2 - Logical domain:
2666 * This holds hostname, TLS certificate, document root, ...
2667 * set for a domain hosted at the server.
2668 * There may be multiple domains hosted at one physical server.
2669 * The default domain "dd" is the first element of a list of
2670 * domains.
2671 */
2672 struct mg_domain_context dd; /* default domain */
2673};
2674
2675
2676#if defined(USE_SERVER_STATS)
2677static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2678
2679static struct mg_memory_stat *
2680get_memory_stat(struct mg_context *ctx)
2681{
2682 if (ctx) {
2683 return &(ctx->ctx_memory);
2684 }
2685 return &mg_common_memory;
2686}
2687#endif
2688
2689enum {
2694
2696 int connection_type; /* see CONNECTION_TYPE_* above */
2697
2700
2703
2704#if defined(USE_SERVER_STATS)
2705 int conn_state; /* 0 = undef, numerical value may change in different
2706 * versions. For the current definition, see
2707 * mg_get_connection_info_impl */
2708#endif
2709
2710 const char *host; /* Host (HTTP/1.1 header or SNI) */
2711 SSL *ssl; /* SSL descriptor */
2712 SSL_CTX *client_ssl_ctx; /* SSL context for client connections */
2713 struct socket client; /* Connected client */
2714 time_t conn_birth_time; /* Time (wall clock) when connection was
2715 * established */
2716 struct timespec req_time; /* Time (since system start) when the request
2717 * was received */
2718 int64_t num_bytes_sent; /* Total bytes sent to client */
2719 int64_t content_len; /* Content-Length header value */
2720 int64_t consumed_content; /* How many bytes of content have been read */
2721 int is_chunked; /* Transfer-Encoding is chunked:
2722 * 0 = not chunked,
2723 * 1 = chunked, do data read yet,
2724 * 2 = chunked, some data read,
2725 * 3 = chunked, all data read
2726 */
2727 size_t chunk_remainder; /* Unread data from the last chunk */
2728 char *buf; /* Buffer for received data */
2729 char *path_info; /* PATH_INFO part of the URL */
2730
2731 int must_close; /* 1 if connection must be closed */
2732 int accept_gzip; /* 1 if gzip encoding is accepted */
2733 int in_error_handler; /* 1 if in handler for user defined error
2734 * pages */
2735#if defined(USE_WEBSOCKET)
2736 int in_websocket_handling; /* 1 if in read_websocket */
2737#endif
2738 int handled_requests; /* Number of requests handled by this connection
2739 */
2740 int buf_size; /* Buffer size */
2741 int request_len; /* Size of the request + headers in a buffer */
2742 int data_len; /* Total size of data in a buffer */
2743 int status_code; /* HTTP reply status code, e.g. 200 */
2744 int throttle; /* Throttling, bytes/sec. <= 0 means no
2745 * throttle */
2746
2747 time_t last_throttle_time; /* Last time throttled data was sent */
2748 int64_t last_throttle_bytes; /* Bytes sent this second */
2749 pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure
2750 * atomic transmissions for websockets */
2751#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2752 void *lua_websocket_state; /* Lua_State for a websocket connection */
2753#endif
2754
2755 int thread_index; /* Thread index within ctx */
2756};
2757
2758
2759/* Directory entry */
2760struct de {
2764};
2765
2766
2767#if defined(USE_WEBSOCKET)
2768static int is_websocket_protocol(const struct mg_connection *conn);
2769#else
2770#define is_websocket_protocol(conn) (0)
2771#endif
2772
2773
2774#define mg_cry_internal(conn, fmt, ...) \
2775 mg_cry_internal_wrap(conn, __func__, __LINE__, fmt, __VA_ARGS__)
2776
2777static void mg_cry_internal_wrap(const struct mg_connection *conn,
2778 const char *func,
2779 unsigned line,
2780 const char *fmt,
2781 ...) PRINTF_ARGS(4, 5);
2782
2783
2784#if !defined(NO_THREAD_NAME)
2785#if defined(_WIN32) && defined(_MSC_VER)
2786/* Set the thread name for debugging purposes in Visual Studio
2787 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
2788 */
2789#pragma pack(push, 8)
2790typedef struct tagTHREADNAME_INFO {
2791 DWORD dwType; /* Must be 0x1000. */
2792 LPCSTR szName; /* Pointer to name (in user addr space). */
2793 DWORD dwThreadID; /* Thread ID (-1=caller thread). */
2794 DWORD dwFlags; /* Reserved for future use, must be zero. */
2795} THREADNAME_INFO;
2796#pragma pack(pop)
2797
2798#elif defined(__linux__)
2799
2800#include <sys/prctl.h>
2801#include <sys/sendfile.h>
2802#if defined(ALTERNATIVE_QUEUE)
2803#include <sys/eventfd.h>
2804#endif /* ALTERNATIVE_QUEUE */
2805
2806
2807#if defined(ALTERNATIVE_QUEUE)
2808
2809static void *
2810event_create(void)
2811{
2812 int evhdl = eventfd(0, EFD_CLOEXEC);
2813 int *ret;
2814
2815 if (evhdl == -1) {
2816 /* Linux uses -1 on error, Windows NULL. */
2817 /* However, Linux does not return 0 on success either. */
2818 return 0;
2819 }
2820
2821 ret = (int *)mg_malloc(sizeof(int));
2822 if (ret) {
2823 *ret = evhdl;
2824 } else {
2825 (void)close(evhdl);
2826 }
2827
2828 return (void *)ret;
2829}
2830
2831
2832static int
2833event_wait(void *eventhdl)
2834{
2835 uint64_t u;
2836 int evhdl, s;
2837
2838 if (!eventhdl) {
2839 /* error */
2840 return 0;
2841 }
2842 evhdl = *(int *)eventhdl;
2843
2844 s = (int)read(evhdl, &u, sizeof(u));
2845 if (s != sizeof(u)) {
2846 /* error */
2847 return 0;
2848 }
2849 (void)u; /* the value is not required */
2850 return 1;
2851}
2852
2853
2854static int
2855event_signal(void *eventhdl)
2856{
2857 uint64_t u = 1;
2858 int evhdl, s;
2859
2860 if (!eventhdl) {
2861 /* error */
2862 return 0;
2863 }
2864 evhdl = *(int *)eventhdl;
2865
2866 s = (int)write(evhdl, &u, sizeof(u));
2867 if (s != sizeof(u)) {
2868 /* error */
2869 return 0;
2870 }
2871 return 1;
2872}
2873
2874
2875static void
2876event_destroy(void *eventhdl)
2877{
2878 int evhdl;
2879
2880 if (!eventhdl) {
2881 /* error */
2882 return;
2883 }
2884 evhdl = *(int *)eventhdl;
2885
2886 close(evhdl);
2887 mg_free(eventhdl);
2888}
2889
2890
2891#endif
2892
2893#endif
2894
2895
2896#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
2897
2899 pthread_mutex_t mutex;
2901};
2902
2903
2904static void *
2906{
2907 struct posix_event *ret = mg_malloc(sizeof(struct posix_event));
2908 if (ret == 0) {
2909 /* out of memory */
2910 return 0;
2911 }
2912 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
2913 /* pthread mutex not available */
2914 mg_free(ret);
2915 return 0;
2916 }
2917 if (0 != pthread_cond_init(&(ret->cond), NULL)) {
2918 /* pthread cond not available */
2919 pthread_mutex_destroy(&(ret->mutex));
2920 mg_free(ret);
2921 return 0;
2922 }
2923 return (void *)ret;
2924}
2925
2926
2927static int
2928event_wait(void *eventhdl)
2929{
2930 struct posix_event *ev = (struct posix_event *)eventhdl;
2931 pthread_mutex_lock(&(ev->mutex));
2932 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2933 pthread_mutex_unlock(&(ev->mutex));
2934 return 1;
2935}
2936
2937
2938static int
2939event_signal(void *eventhdl)
2940{
2941 struct posix_event *ev = (struct posix_event *)eventhdl;
2942 pthread_mutex_lock(&(ev->mutex));
2943 pthread_cond_signal(&(ev->cond));
2944 pthread_mutex_unlock(&(ev->mutex));
2945 return 1;
2946}
2947
2948
2949static void
2950event_destroy(void *eventhdl)
2951{
2952 struct posix_event *ev = (struct posix_event *)eventhdl;
2953 pthread_cond_destroy(&(ev->cond));
2954 pthread_mutex_destroy(&(ev->mutex));
2955 mg_free(ev);
2956}
2957#endif
2958
2959
2960static void
2962{
2963 char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
2964
2966 NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name);
2967
2968#if defined(_WIN32)
2969#if defined(_MSC_VER)
2970 /* Windows and Visual Studio Compiler */
2971 __try {
2972 THREADNAME_INFO info;
2973 info.dwType = 0x1000;
2974 info.szName = threadName;
2975 info.dwThreadID = ~0U;
2976 info.dwFlags = 0;
2977
2978 RaiseException(0x406D1388,
2979 0,
2980 sizeof(info) / sizeof(ULONG_PTR),
2981 (ULONG_PTR *)&info);
2982 } __except (EXCEPTION_EXECUTE_HANDLER) {
2983 }
2984#elif defined(__MINGW32__)
2985/* No option known to set thread name for MinGW */
2986#endif
2987#elif defined(_GNU_SOURCE) && defined(__GLIBC__) \
2988 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
2989/* pthread_setname_np first appeared in glibc in version 2.12*/
2990#if defined(__MACH__)
2991 /* OS X only current thread name can be changed */
2992 (void)pthread_setname_np(threadName);
2993#else
2994 (void)pthread_setname_np(pthread_self(), threadName);
2995#endif
2996#elif defined(__linux__)
2997 /* on linux we can use the old prctl function */
2998 (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
2999#endif
3000}
3001#else /* !defined(NO_THREAD_NAME) */
3002void
3003mg_set_thread_name(const char *threadName)
3004{
3005}
3006#endif
3007
3008
3009#if defined(MG_LEGACY_INTERFACE)
3010const char **
3011mg_get_valid_option_names(void)
3012{
3013 /* This function is deprecated. Use mg_get_valid_options instead. */
3014 static const char
3015 *data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0};
3016 int i;
3017
3018 for (i = 0; config_options[i].name != NULL; i++) {
3019 data[i * 2] = config_options[i].name;
3020 data[i * 2 + 1] = config_options[i].default_value;
3021 }
3022
3023 return data;
3024}
3025#endif
3026
3027
3028const struct mg_option *
3030{
3031 return config_options;
3032}
3033
3034
3035/* Do not open file (used in is_file_in_memory) */
3036#define MG_FOPEN_MODE_NONE (0)
3037
3038/* Open file for read only access */
3039#define MG_FOPEN_MODE_READ (1)
3040
3041/* Open file for writing, create and overwrite */
3042#define MG_FOPEN_MODE_WRITE (2)
3043
3044/* Open file for writing, create and append */
3045#define MG_FOPEN_MODE_APPEND (4)
3046
3047
3048/* If a file is in memory, set all "stat" members and the membuf pointer of
3049 * output filep and return 1, otherwise return 0 and don't modify anything.
3050 */
3051static int
3053 const char *path,
3054 struct mg_file *filep,
3055 int mode)
3056{
3057#if defined(MG_USE_OPEN_FILE)
3058
3059 size_t size = 0;
3060 const char *buf = NULL;
3061 if (!conn) {
3062 return 0;
3063 }
3064
3065 if ((mode != MG_FOPEN_MODE_NONE) && (mode != MG_FOPEN_MODE_READ)) {
3066 return 0;
3067 }
3068
3069 if (conn->phys_ctx->callbacks.open_file) {
3070 buf = conn->phys_ctx->callbacks.open_file(conn, path, &size);
3071 if (buf != NULL) {
3072 if (filep == NULL) {
3073 /* This is a file in memory, but we cannot store the
3074 * properties
3075 * now.
3076 * Called from "is_file_in_memory" function. */
3077 return 1;
3078 }
3079
3080 /* NOTE: override filep->size only on success. Otherwise, it
3081 * might
3082 * break constructs like if (!mg_stat() || !mg_fopen()) ... */
3083 filep->access.membuf = buf;
3084 filep->access.fp = NULL;
3085
3086 /* Size was set by the callback */
3087 filep->stat.size = size;
3088
3089 /* Assume the data may change during runtime by setting
3090 * last_modified = now */
3091 filep->stat.last_modified = time(NULL);
3092
3093 filep->stat.is_directory = 0;
3094 filep->stat.is_gzipped = 0;
3095 }
3096 }
3097
3098 return (buf != NULL);
3099
3100#else
3101 (void)conn;
3102 (void)path;
3103 (void)filep;
3104 (void)mode;
3105
3106 return 0;
3107
3108#endif
3109}
3110
3111
3112static int
3113is_file_in_memory(const struct mg_connection *conn, const char *path)
3114{
3115 return open_file_in_memory(conn, path, NULL, MG_FOPEN_MODE_NONE);
3116}
3117
3118
3119static int
3120is_file_opened(const struct mg_file_access *fileacc)
3121{
3122 if (!fileacc) {
3123 return 0;
3124 }
3125
3126#if defined(MG_USE_OPEN_FILE)
3127 return (fileacc->membuf != NULL) || (fileacc->fp != NULL);
3128#else
3129 return (fileacc->fp != NULL);
3130#endif
3131}
3132
3133
3134static int mg_stat(const struct mg_connection *conn,
3135 const char *path,
3136 struct mg_file_stat *filep);
3137
3138
3139/* mg_fopen will open a file either in memory or on the disk.
3140 * The input parameter path is a string in UTF-8 encoding.
3141 * The input parameter mode is MG_FOPEN_MODE_*
3142 * On success, either fp or membuf will be set in the output
3143 * struct file. All status members will also be set.
3144 * The function returns 1 on success, 0 on error. */
3145static int
3146mg_fopen(const struct mg_connection *conn,
3147 const char *path,
3148 int mode,
3149 struct mg_file *filep)
3150{
3151 int found;
3152
3153 if (!filep) {
3154 return 0;
3155 }
3156 filep->access.fp = NULL;
3157#if defined(MG_USE_OPEN_FILE)
3158 filep->access.membuf = NULL;
3159#endif
3160
3161 if (!is_file_in_memory(conn, path)) {
3162
3163 /* filep is initialized in mg_stat: all fields with memset to,
3164 * some fields like size and modification date with values */
3165 found = mg_stat(conn, path, &(filep->stat));
3166
3167 if ((mode == MG_FOPEN_MODE_READ) && (!found)) {
3168 /* file does not exist and will not be created */
3169 return 0;
3170 }
3171
3172#if defined(_WIN32)
3173 {
3174 wchar_t wbuf[W_PATH_MAX];
3175 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
3176 switch (mode) {
3177 case MG_FOPEN_MODE_READ:
3178 filep->access.fp = _wfopen(wbuf, L"rb");
3179 break;
3181 filep->access.fp = _wfopen(wbuf, L"wb");
3182 break;
3184 filep->access.fp = _wfopen(wbuf, L"ab");
3185 break;
3186 }
3187 }
3188#else
3189 /* Linux et al already use unicode. No need to convert. */
3190 switch (mode) {
3191 case MG_FOPEN_MODE_READ:
3192 filep->access.fp = fopen(path, "r");
3193 break;
3195 filep->access.fp = fopen(path, "w");
3196 break;
3198 filep->access.fp = fopen(path, "a");
3199 break;
3200 }
3201
3202#endif
3203 if (!found) {
3204 /* File did not exist before fopen was called.
3205 * Maybe it has been created now. Get stat info
3206 * like creation time now. */
3207 found = mg_stat(conn, path, &(filep->stat));
3208 (void)found;
3209 }
3210
3211 /* file is on disk */
3212 return (filep->access.fp != NULL);
3213
3214 } else {
3215#if defined(MG_USE_OPEN_FILE)
3216 /* is_file_in_memory returned true */
3217 if (open_file_in_memory(conn, path, filep, mode)) {
3218 /* file is in memory */
3219 return (filep->access.membuf != NULL);
3220 }
3221#endif
3222 }
3223
3224 /* Open failed */
3225 return 0;
3226}
3227
3228
3229/* return 0 on success, just like fclose */
3230static int
3232{
3233 int ret = -1;
3234 if (fileacc != NULL) {
3235 if (fileacc->fp != NULL) {
3236 ret = fclose(fileacc->fp);
3237#if defined(MG_USE_OPEN_FILE)
3238 } else if (fileacc->membuf != NULL) {
3239 ret = 0;
3240#endif
3241 }
3242 /* reset all members of fileacc */
3243 memset(fileacc, 0, sizeof(*fileacc));
3244 }
3245 return ret;
3246}
3247
3248
3249static void
3250mg_strlcpy(register char *dst, register const char *src, size_t n)
3251{
3252 for (; *src != '\0' && n > 1; n--) {
3253 *dst++ = *src++;
3254 }
3255 *dst = '\0';
3256}
3257
3258
3259static int
3260lowercase(const char *s)
3261{
3262 return tolower(*(const unsigned char *)s);
3263}
3264
3265
3266int
3267mg_strncasecmp(const char *s1, const char *s2, size_t len)
3268{
3269 int diff = 0;
3270
3271 if (len > 0) {
3272 do {
3273 diff = lowercase(s1++) - lowercase(s2++);
3274 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
3275 }
3276
3277 return diff;
3278}
3279
3280
3281int
3282mg_strcasecmp(const char *s1, const char *s2)
3283{
3284 int diff;
3285
3286 do {
3287 diff = lowercase(s1++) - lowercase(s2++);
3288 } while (diff == 0 && s1[-1] != '\0');
3289
3290 return diff;
3291}
3292
3293
3294static char *
3295mg_strndup_ctx(const char *ptr, size_t len, struct mg_context *ctx)
3296{
3297 char *p;
3298 (void)ctx; /* Avoid Visual Studio warning if USE_SERVER_STATS is not
3299 * defined */
3300
3301 if ((p = (char *)mg_malloc_ctx(len + 1, ctx)) != NULL) {
3302 mg_strlcpy(p, ptr, len + 1);
3303 }
3304
3305 return p;
3306}
3307
3308
3309static char *
3310mg_strdup_ctx(const char *str, struct mg_context *ctx)
3311{
3312 return mg_strndup_ctx(str, strlen(str), ctx);
3313}
3314
3315static char *
3316mg_strdup(const char *str)
3317{
3318 return mg_strndup_ctx(str, strlen(str), NULL);
3319}
3320
3321
3322static const char *
3323mg_strcasestr(const char *big_str, const char *small_str)
3324{
3325 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3326
3327 if (big_len >= small_len) {
3328 for (i = 0; i <= (big_len - small_len); i++) {
3329 if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
3330 return big_str + i;
3331 }
3332 }
3333 }
3334
3335 return NULL;
3336}
3337
3338
3339/* Return null terminated string of given maximum length.
3340 * Report errors if length is exceeded. */
3341static void
3342mg_vsnprintf(const struct mg_connection *conn,
3343 int *truncated,
3344 char *buf,
3345 size_t buflen,
3346 const char *fmt,
3347 va_list ap)
3348{
3349 int n, ok;
3350
3351 if (buflen == 0) {
3352 if (truncated) {
3353 *truncated = 1;
3354 }
3355 return;
3356 }
3357
3358#if defined(__clang__)
3359#pragma clang diagnostic push
3360#pragma clang diagnostic ignored "-Wformat-nonliteral"
3361/* Using fmt as a non-literal is intended here, since it is mostly called
3362 * indirectly by mg_snprintf */
3363#endif
3364
3365 n = (int)vsnprintf_impl(buf, buflen, fmt, ap);
3366 ok = (n >= 0) && ((size_t)n < buflen);
3367
3368#if defined(__clang__)
3369#pragma clang diagnostic pop
3370#endif
3371
3372 if (ok) {
3373 if (truncated) {
3374 *truncated = 0;
3375 }
3376 } else {
3377 if (truncated) {
3378 *truncated = 1;
3379 }
3380 mg_cry_internal(conn,
3381 "truncating vsnprintf buffer: [%.*s]",
3382 (int)((buflen > 200) ? 200 : (buflen - 1)),
3383 buf);
3384 n = (int)buflen - 1;
3385 }
3386 buf[n] = '\0';
3387}
3388
3389
3390static void
3391mg_snprintf(const struct mg_connection *conn,
3392 int *truncated,
3393 char *buf,
3394 size_t buflen,
3395 const char *fmt,
3396 ...)
3397{
3398 va_list ap;
3399
3400 va_start(ap, fmt);
3401 mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap);
3402 va_end(ap);
3403}
3404
3405
3406static int
3408{
3409 int i;
3410
3411 for (i = 0; config_options[i].name != NULL; i++) {
3412 if (strcmp(config_options[i].name, name) == 0) {
3413 return i;
3414 }
3415 }
3416 return -1;
3417}
3418
3419
3420const char *
3421mg_get_option(const struct mg_context *ctx, const char *name)
3422{
3423 int i;
3424 if ((i = get_option_index(name)) == -1) {
3425 return NULL;
3426 } else if (!ctx || ctx->dd.config[i] == NULL) {
3427 return "";
3428 } else {
3429 return ctx->dd.config[i];
3430 }
3431}
3432
3433#define mg_get_option DO_NOT_USE_THIS_FUNCTION_INTERNALLY__access_directly
3434
3435struct mg_context *
3437{
3438 return (conn == NULL) ? (struct mg_context *)NULL : (conn->phys_ctx);
3439}
3440
3441
3442void *
3444{
3445 return (ctx == NULL) ? NULL : ctx->user_data;
3446}
3447
3448
3449void
3451{
3452 if (conn != NULL) {
3453 conn->request_info.conn_data = data;
3454 }
3455}
3456
3457
3458void *
3460{
3461 if (conn != NULL) {
3462 return conn->request_info.conn_data;
3463 }
3464 return NULL;
3465}
3466
3467
3468#if defined(MG_LEGACY_INTERFACE)
3469/* Deprecated: Use mg_get_server_ports instead. */
3470size_t
3471mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
3472{
3473 size_t i;
3474 if (!ctx) {
3475 return 0;
3476 }
3477 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
3478 ssl[i] = ctx->listening_sockets[i].is_ssl;
3479 ports[i] =
3480#if defined(USE_IPV6)
3481 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3482 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3483 :
3484#endif
3485 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
3486 }
3487 return i;
3488}
3489#endif
3490
3491
3492int
3494 int size,
3495 struct mg_server_ports *ports)
3496{
3497 int i, cnt = 0;
3498
3499 if (size <= 0) {
3500 return -1;
3501 }
3502 memset(ports, 0, sizeof(*ports) * (size_t)size);
3503 if (!ctx) {
3504 return -1;
3505 }
3506 if (!ctx->listening_sockets) {
3507 return -1;
3508 }
3509
3510 for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) {
3511
3512 ports[cnt].port =
3513#if defined(USE_IPV6)
3514 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3515 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3516 :
3517#endif
3518 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
3519 ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
3520 ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
3521
3522 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
3523 /* IPv4 */
3524 ports[cnt].protocol = 1;
3525 cnt++;
3526 } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
3527 /* IPv6 */
3528 ports[cnt].protocol = 3;
3529 cnt++;
3530 }
3531 }
3532
3533 return cnt;
3534}
3535
3536
3537static void
3538sockaddr_to_string(char *buf, size_t len, const union usa *usa)
3539{
3540 buf[0] = '\0';
3541
3542 if (!usa) {
3543 return;
3544 }
3545
3546 if (usa->sa.sa_family == AF_INET) {
3547 getnameinfo(&usa->sa,
3548 sizeof(usa->sin),
3549 buf,
3550 (unsigned)len,
3551 NULL,
3552 0,
3553 NI_NUMERICHOST);
3554 }
3555#if defined(USE_IPV6)
3556 else if (usa->sa.sa_family == AF_INET6) {
3557 getnameinfo(&usa->sa,
3558 sizeof(usa->sin6),
3559 buf,
3560 (unsigned)len,
3561 NULL,
3562 0,
3563 NI_NUMERICHOST);
3564 }
3565#endif
3566}
3567
3568
3569/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
3570 * included in all responses other than 100, 101, 5xx. */
3571static void
3572gmt_time_string(char *buf, size_t buf_len, time_t *t)
3573{
3574#if !defined(REENTRANT_TIME)
3575 struct tm *tm;
3576
3577 tm = ((t != NULL) ? gmtime(t) : NULL);
3578 if (tm != NULL) {
3579#else
3580 struct tm _tm;
3581 struct tm *tm = &_tm;
3582
3583 if (t != NULL) {
3584 gmtime_r(t, tm);
3585#endif
3586 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
3587 } else {
3588 mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3589 buf[buf_len - 1] = '\0';
3590 }
3591}
3592
3593
3594/* difftime for struct timespec. Return value is in seconds. */
3595static double
3596mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
3597{
3598 return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3599 + (double)(ts_now->tv_sec - ts_before->tv_sec);
3600}
3601
3602
3603#if defined(MG_EXTERNAL_FUNCTION_mg_cry_internal_impl)
3604static void mg_cry_internal_impl(const struct mg_connection *conn,
3605 const char *func,
3606 unsigned line,
3607 const char *fmt,
3608 va_list ap);
3609#include "external_mg_cry_internal_impl.inl"
3610#else
3611
3612/* Print error message to the opened error log stream. */
3613static void
3615 const char *func,
3616 unsigned line,
3617 const char *fmt,
3618 va_list ap)
3619{
3620 char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
3621 struct mg_file fi;
3622 time_t timestamp;
3623
3624 /* Unused, in the RELEASE build */
3625 (void)func;
3626 (void)line;
3627
3628#if defined(GCC_DIAGNOSTIC)
3629#pragma GCC diagnostic push
3630#pragma GCC diagnostic ignored "-Wformat-nonliteral"
3631#endif
3632
3633 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
3634
3635#if defined(GCC_DIAGNOSTIC)
3636#pragma GCC diagnostic pop
3637#endif
3638
3639 buf[sizeof(buf) - 1] = 0;
3640
3641 DEBUG_TRACE("mg_cry called from %s:%u: %s", func, line, buf);
3642
3643 if (!conn) {
3644 puts(buf);
3645 return;
3646 }
3647
3648 /* Do not lock when getting the callback value, here and below.
3649 * I suppose this is fine, since function cannot disappear in the
3650 * same way string option can. */
3651 if ((conn->phys_ctx->callbacks.log_message == NULL)
3652 || (conn->phys_ctx->callbacks.log_message(conn, buf) == 0)) {
3653
3654 if (conn->dom_ctx->config[ERROR_LOG_FILE] != NULL) {
3655 if (mg_fopen(conn,
3658 &fi)
3659 == 0) {
3660 fi.access.fp = NULL;
3661 }
3662 } else {
3663 fi.access.fp = NULL;
3664 }
3665
3666 if (fi.access.fp != NULL) {
3667 flockfile(fi.access.fp);
3668 timestamp = time(NULL);
3669
3670 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
3671 fprintf(fi.access.fp,
3672 "[%010lu] [error] [client %s] ",
3673 (unsigned long)timestamp,
3674 src_addr);
3675
3676 if (conn->request_info.request_method != NULL) {
3677 fprintf(fi.access.fp,
3678 "%s %s: ",
3682 : "");
3683 }
3684
3685 fprintf(fi.access.fp, "%s", buf);
3686 fputc('\n', fi.access.fp);
3687 fflush(fi.access.fp);
3688 funlockfile(fi.access.fp);
3689 (void)mg_fclose(&fi.access); /* Ignore errors. We can't call
3690 * mg_cry here anyway ;-) */
3691 }
3692 }
3693}
3694
3695#endif /* Externally provided function */
3696
3697
3698static void
3700 const char *func,
3701 unsigned line,
3702 const char *fmt,
3703 ...)
3704{
3705 va_list ap;
3706 va_start(ap, fmt);
3707 mg_cry_internal_impl(conn, func, line, fmt, ap);
3708 va_end(ap);
3709}
3710
3711
3712void
3713mg_cry(const struct mg_connection *conn, const char *fmt, ...)
3714{
3715 va_list ap;
3716 va_start(ap, fmt);
3717 mg_cry_internal_impl(conn, "user", 0, fmt, ap);
3718 va_end(ap);
3719}
3720
3721
3722#define mg_cry DO_NOT_USE_THIS_FUNCTION__USE_mg_cry_internal
3723
3724
3725/* Return fake connection structure. Used for logging, if connection
3726 * is not applicable at the moment of logging. */
3727static struct mg_connection *
3728fc(struct mg_context *ctx)
3729{
3730 static struct mg_connection fake_connection;
3731 fake_connection.phys_ctx = ctx;
3732 fake_connection.dom_ctx = &(ctx->dd);
3733 return &fake_connection;
3734}
3735
3736
3737const char *
3739{
3740 return CIVETWEB_VERSION;
3741}
3742
3743
3744const struct mg_request_info *
3746{
3747 if (!conn) {
3748 return NULL;
3749 }
3750#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3752 char txt[16];
3753 struct mg_workerTLS *tls =
3754 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
3755
3756 sprintf(txt, "%03i", conn->response_info.status_code);
3757 if (strlen(txt) == 3) {
3758 memcpy(tls->txtbuf, txt, 4);
3759 } else {
3760 strcpy(tls->txtbuf, "ERR");
3761 }
3762
3763 ((struct mg_connection *)conn)->request_info.local_uri =
3764 ((struct mg_connection *)conn)->request_info.request_uri =
3765 tls->txtbuf; /* use thread safe buffer */
3766
3767 ((struct mg_connection *)conn)->request_info.num_headers =
3769 memcpy(((struct mg_connection *)conn)->request_info.http_headers,
3771 sizeof(conn->response_info.http_headers));
3772 } else
3773#endif
3775 return NULL;
3776 }
3777 return &conn->request_info;
3778}
3779
3780
3781const struct mg_response_info *
3783{
3784 if (!conn) {
3785 return NULL;
3786 }
3788 return NULL;
3789 }
3790 return &conn->response_info;
3791}
3792
3793
3794static const char *
3796{
3797#if defined(__clang__)
3798#pragma clang diagnostic push
3799#pragma clang diagnostic ignored "-Wunreachable-code"
3800/* Depending on USE_WEBSOCKET and NO_SSL, some oft the protocols might be
3801 * not supported. Clang raises an "unreachable code" warning for parts of ?:
3802 * unreachable, but splitting into four different #ifdef clauses here is more
3803 * complicated.
3804 */
3805#endif
3806
3807 const struct mg_request_info *ri = &conn->request_info;
3808
3809 const char *proto =
3810 (is_websocket_protocol(conn) ? (ri->is_ssl ? "wss" : "ws")
3811 : (ri->is_ssl ? "https" : "http"));
3812
3813 return proto;
3814
3815#if defined(__clang__)
3816#pragma clang diagnostic pop
3817#endif
3818}
3819
3820
3821int
3822mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
3823{
3824 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3825 return -1;
3826 } else {
3827
3828 int truncated = 0;
3829 const struct mg_request_info *ri = &conn->request_info;
3830
3831 const char *proto = get_proto_name(conn);
3832
3833 if (ri->local_uri == NULL) {
3834 return -1;
3835 }
3836
3837 if ((ri->request_uri != NULL)
3838 && (0 != strcmp(ri->local_uri, ri->request_uri))) {
3839 /* The request uri is different from the local uri.
3840 * This is usually if an absolute URI, including server
3841 * name has been provided. */
3842 mg_snprintf(conn,
3843 &truncated,
3844 buf,
3845 buflen,
3846 "%s://%s",
3847 proto,
3848 ri->request_uri);
3849 if (truncated) {
3850 return -1;
3851 }
3852 return 0;
3853
3854 } else {
3855
3856 /* The common case is a relative URI, so we have to
3857 * construct an absolute URI from server name and port */
3858
3859#if defined(USE_IPV6)
3860 int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6);
3861 int port = is_ipv6 ? htons(conn->client.lsa.sin6.sin6_port)
3862 : htons(conn->client.lsa.sin.sin_port);
3863#else
3864 int port = htons(conn->client.lsa.sin.sin_port);
3865#endif
3866 int def_port = ri->is_ssl ? 443 : 80;
3867 int auth_domain_check_enabled =
3869 && (!mg_strcasecmp(
3870 conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes"));
3871 const char *server_domain =
3873
3874 char portstr[16];
3875 char server_ip[48];
3876
3877 if (port != def_port) {
3878 sprintf(portstr, ":%u", (unsigned)port);
3879 } else {
3880 portstr[0] = 0;
3881 }
3882
3883 if (!auth_domain_check_enabled || !server_domain) {
3884
3885 sockaddr_to_string(server_ip,
3886 sizeof(server_ip),
3887 &conn->client.lsa);
3888
3889 server_domain = server_ip;
3890 }
3891
3892 mg_snprintf(conn,
3893 &truncated,
3894 buf,
3895 buflen,
3896 "%s://%s%s%s",
3897 proto,
3898 server_domain,
3899 portstr,
3900 ri->local_uri);
3901 if (truncated) {
3902 return -1;
3903 }
3904 return 0;
3905 }
3906 }
3907}
3908
3909/* Skip the characters until one of the delimiters characters found.
3910 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
3911 * Advance pointer to buffer to the next word. Return found 0-terminated
3912 * word.
3913 * Delimiters can be quoted with quotechar. */
3914static char *
3915skip_quoted(char **buf,
3916 const char *delimiters,
3917 const char *whitespace,
3918 char quotechar)
3919{
3920 char *p, *begin_word, *end_word, *end_whitespace;
3921
3922 begin_word = *buf;
3923 end_word = begin_word + strcspn(begin_word, delimiters);
3924
3925 /* Check for quotechar */
3926 if (end_word > begin_word) {
3927 p = end_word - 1;
3928 while (*p == quotechar) {
3929 /* While the delimiter is quoted, look for the next delimiter.
3930 */
3931 /* This happens, e.g., in calls from parse_auth_header,
3932 * if the user name contains a " character. */
3933
3934 /* If there is anything beyond end_word, copy it. */
3935 if (*end_word != '\0') {
3936 size_t end_off = strcspn(end_word + 1, delimiters);
3937 memmove(p, end_word, end_off + 1);
3938 p += end_off; /* p must correspond to end_word - 1 */
3939 end_word += end_off + 1;
3940 } else {
3941 *p = '\0';
3942 break;
3943 }
3944 }
3945 for (p++; p < end_word; p++) {
3946 *p = '\0';
3947 }
3948 }
3949
3950 if (*end_word == '\0') {
3951 *buf = end_word;
3952 } else {
3953
3954#if defined(GCC_DIAGNOSTIC)
3955/* Disable spurious conversion warning for GCC */
3956#pragma GCC diagnostic push
3957#pragma GCC diagnostic ignored "-Wsign-conversion"
3958#endif /* defined(GCC_DIAGNOSTIC) */
3959
3960 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3961
3962#if defined(GCC_DIAGNOSTIC)
3963#pragma GCC diagnostic pop
3964#endif /* defined(GCC_DIAGNOSTIC) */
3965
3966 for (p = end_word; p < end_whitespace; p++) {
3967 *p = '\0';
3968 }
3969
3970 *buf = end_whitespace;
3971 }
3972
3973 return begin_word;
3974}
3975
3976
3977/* Return HTTP header value, or NULL if not found. */
3978static const char *
3979get_header(const struct mg_header *hdr, int num_hdr, const char *name)
3980{
3981 int i;
3982 for (i = 0; i < num_hdr; i++) {
3983 if (!mg_strcasecmp(name, hdr[i].name)) {
3984 return hdr[i].value;
3985 }
3986 }
3987
3988 return NULL;
3989}
3990
3991
3992#if defined(USE_WEBSOCKET)
3993/* Retrieve requested HTTP header multiple values, and return the number of
3994 * found occurrences */
3995static int
3996get_req_headers(const struct mg_request_info *ri,
3997 const char *name,
3998 const char **output,
3999 int output_max_size)
4000{
4001 int i;
4002 int cnt = 0;
4003 if (ri) {
4004 for (i = 0; i < ri->num_headers && cnt < output_max_size; i++) {
4005 if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
4006 output[cnt++] = ri->http_headers[i].value;
4007 }
4008 }
4009 }
4010 return cnt;
4011}
4012#endif
4013
4014
4015const char *
4016mg_get_header(const struct mg_connection *conn, const char *name)
4017{
4018 if (!conn) {
4019 return NULL;
4020 }
4021
4025 name);
4026 }
4030 name);
4031 }
4032 return NULL;
4033}
4034
4035
4036static const char *
4038{
4039 if (!conn) {
4040 return NULL;
4041 }
4042
4044 return conn->request_info.http_version;
4045 }
4047 return conn->response_info.http_version;
4048 }
4049 return NULL;
4050}
4051
4052
4053/* A helper function for traversing a comma separated list of values.
4054 * It returns a list pointer shifted to the next value, or NULL if the end
4055 * of the list found.
4056 * Value is stored in val vector. If value has form "x=y", then eq_val
4057 * vector is initialized to point to the "y" part, and val vector length
4058 * is adjusted to point only to "x". */
4059static const char *
4060next_option(const char *list, struct vec *val, struct vec *eq_val)
4061{
4062 int end;
4063
4064reparse:
4065 if (val == NULL || list == NULL || *list == '\0') {
4066 /* End of the list */
4067 return NULL;
4068 }
4069
4070 /* Skip over leading LWS */
4071 while (*list == ' ' || *list == '\t')
4072 list++;
4073
4074 val->ptr = list;
4075 if ((list = strchr(val->ptr, ',')) != NULL) {
4076 /* Comma found. Store length and shift the list ptr */
4077 val->len = ((size_t)(list - val->ptr));
4078 list++;
4079 } else {
4080 /* This value is the last one */
4081 list = val->ptr + strlen(val->ptr);
4082 val->len = ((size_t)(list - val->ptr));
4083 }
4084
4085 /* Adjust length for trailing LWS */
4086 end = (int)val->len - 1;
4087 while (end >= 0 && ((val->ptr[end] == ' ') || (val->ptr[end] == '\t')))
4088 end--;
4089 val->len = (size_t)(end + 1);
4090
4091 if (val->len == 0) {
4092 /* Ignore any empty entries. */
4093 goto reparse;
4094 }
4095
4096 if (eq_val != NULL) {
4097 /* Value has form "x=y", adjust pointers and lengths
4098 * so that val points to "x", and eq_val points to "y". */
4099 eq_val->len = 0;
4100 eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len);
4101 if (eq_val->ptr != NULL) {
4102 eq_val->ptr++; /* Skip over '=' character */
4103 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
4104 val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1;
4105 }
4106 }
4107
4108 return list;
4109}
4110
4111
4112/* A helper function for checking if a comma separated list of values
4113 * contains
4114 * the given option (case insensitvely).
4115 * 'header' can be NULL, in which case false is returned. */
4116static int
4117header_has_option(const char *header, const char *option)
4118{
4119 struct vec opt_vec;
4120 struct vec eq_vec;
4121
4122 DEBUG_ASSERT(option != NULL);
4123 DEBUG_ASSERT(option[0] != '\0');
4124
4125 while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) {
4126 if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0)
4127 return 1;
4128 }
4129
4130 return 0;
4131}
4132
4133
4134/* Perform case-insensitive match of string against pattern */
4135static ptrdiff_t
4136match_prefix(const char *pattern, size_t pattern_len, const char *str)
4137{
4138 const char *or_str;
4139 ptrdiff_t i, j, len, res;
4140
4141 if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) {
4142 res = match_prefix(pattern, (size_t)(or_str - pattern), str);
4143 return (res > 0) ? res
4144 : match_prefix(or_str + 1,
4145 (size_t)((pattern + pattern_len)
4146 - (or_str + 1)),
4147 str);
4148 }
4149
4150 for (i = 0, j = 0; (i < (ptrdiff_t)pattern_len); i++, j++) {
4151 if ((pattern[i] == '?') && (str[j] != '\0')) {
4152 continue;
4153 } else if (pattern[i] == '$') {
4154 return (str[j] == '\0') ? j : -1;
4155 } else if (pattern[i] == '*') {
4156 i++;
4157 if (pattern[i] == '*') {
4158 i++;
4159 len = strlen(str + j);
4160 } else {
4161 len = strcspn(str + j, "/");
4162 }
4163 if (i == (ptrdiff_t)pattern_len) {
4164 return j + len;
4165 }
4166 do {
4167 res = match_prefix(pattern + i, pattern_len - i, str + j + len);
4168 } while (res == -1 && len-- > 0);
4169 return (res == -1) ? -1 : j + res + len;
4170 } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
4171 return -1;
4172 }
4173 }
4174 return (ptrdiff_t)j;
4175}
4176
4177
4178/* HTTP 1.1 assumes keep alive if "Connection:" header is not set
4179 * This function must tolerate situations when connection info is not
4180 * set up, for example if request parsing failed. */
4181static int
4183{
4184 const char *http_version;
4185 const char *header;
4186
4187 /* First satisfy needs of the server */
4188 if ((conn == NULL) || conn->must_close) {
4189 /* Close, if civetweb framework needs to close */
4190 return 0;
4191 }
4192
4193 if (mg_strcasecmp(conn->dom_ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0) {
4194 /* Close, if keep alive is not enabled */
4195 return 0;
4196 }
4197
4198 /* Check explicit wish of the client */
4199 header = mg_get_header(conn, "Connection");
4200 if (header) {
4201 /* If there is a connection header from the client, obey */
4202 if (header_has_option(header, "keep-alive")) {
4203 return 1;
4204 }
4205 return 0;
4206 }
4207
4208 /* Use default of the standard */
4209 http_version = get_http_version(conn);
4210 if (http_version && (0 == strcmp(http_version, "1.1"))) {
4211 /* HTTP 1.1 default is keep alive */
4212 return 1;
4213 }
4214
4215 /* HTTP 1.0 (and earlier) default is to close the connection */
4216 return 0;
4217}
4218
4219
4220static int
4222{
4223 if (!conn || !conn->dom_ctx) {
4224 return 0;
4225 }
4226
4227 return (mg_strcasecmp(conn->dom_ctx->config[DECODE_URL], "yes") == 0);
4228}
4229
4230
4231static const char *
4233{
4234 return should_keep_alive(conn) ? "keep-alive" : "close";
4235}
4236
4237
4238static int
4240{
4241 /* Send all current and obsolete cache opt-out directives. */
4242 return mg_printf(conn,
4243 "Cache-Control: no-cache, no-store, "
4244 "must-revalidate, private, max-age=0\r\n"
4245 "Pragma: no-cache\r\n"
4246 "Expires: 0\r\n");
4247}
4248
4249
4250static int
4252{
4253#if !defined(NO_CACHING)
4254 /* Read the server config to check how long a file may be cached.
4255 * The configuration is in seconds. */
4256 int max_age = atoi(conn->dom_ctx->config[STATIC_FILE_MAX_AGE]);
4257 if (max_age <= 0) {
4258 /* 0 means "do not cache". All values <0 are reserved
4259 * and may be used differently in the future. */
4260 /* If a file should not be cached, do not only send
4261 * max-age=0, but also pragmas and Expires headers. */
4262 return send_no_cache_header(conn);
4263 }
4264
4265 /* Use "Cache-Control: max-age" instead of "Expires" header.
4266 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
4267 /* See also https://www.mnot.net/cache_docs/ */
4268 /* According to RFC 2616, Section 14.21, caching times should not exceed
4269 * one year. A year with 365 days corresponds to 31536000 seconds, a
4270 * leap
4271 * year to 31622400 seconds. For the moment, we just send whatever has
4272 * been configured, still the behavior for >1 year should be considered
4273 * as undefined. */
4274 return mg_printf(conn, "Cache-Control: max-age=%u\r\n", (unsigned)max_age);
4275#else /* NO_CACHING */
4276 return send_no_cache_header(conn);
4277#endif /* !NO_CACHING */
4278}
4279
4280
4281static int
4283{
4284 int i = 0;
4285 const char *header = conn->dom_ctx->config[ADDITIONAL_HEADER];
4286
4287#if !defined(NO_SSL)
4288 if (conn->dom_ctx->config[STRICT_HTTPS_MAX_AGE]) {
4289 int max_age = atoi(conn->dom_ctx->config[STRICT_HTTPS_MAX_AGE]);
4290 if (max_age >= 0) {
4291 i += mg_printf(conn,
4292 "Strict-Transport-Security: max-age=%u\r\n",
4293 (unsigned)max_age);
4294 }
4295 }
4296#endif
4297
4298 if (header && header[0]) {
4299 i += mg_printf(conn, "%s\r\n", header);
4300 }
4301
4302 return i;
4303}
4304
4305
4306static void handle_file_based_request(struct mg_connection *conn,
4307 const char *path,
4308 struct mg_file *filep);
4309
4310
4311const char *
4312mg_get_response_code_text(const struct mg_connection *conn, int response_code)
4313{
4314 /* See IANA HTTP status code assignment:
4315 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
4316 */
4317
4318 switch (response_code) {
4319 /* RFC2616 Section 10.1 - Informational 1xx */
4320 case 100:
4321 return "Continue"; /* RFC2616 Section 10.1.1 */
4322 case 101:
4323 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
4324 case 102:
4325 return "Processing"; /* RFC2518 Section 10.1 */
4326
4327 /* RFC2616 Section 10.2 - Successful 2xx */
4328 case 200:
4329 return "OK"; /* RFC2616 Section 10.2.1 */
4330 case 201:
4331 return "Created"; /* RFC2616 Section 10.2.2 */
4332 case 202:
4333 return "Accepted"; /* RFC2616 Section 10.2.3 */
4334 case 203:
4335 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
4336 case 204:
4337 return "No Content"; /* RFC2616 Section 10.2.5 */
4338 case 205:
4339 return "Reset Content"; /* RFC2616 Section 10.2.6 */
4340 case 206:
4341 return "Partial Content"; /* RFC2616 Section 10.2.7 */
4342 case 207:
4343 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1
4344 */
4345 case 208:
4346 return "Already Reported"; /* RFC5842 Section 7.1 */
4347
4348 case 226:
4349 return "IM used"; /* RFC3229 Section 10.4.1 */
4350
4351 /* RFC2616 Section 10.3 - Redirection 3xx */
4352 case 300:
4353 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
4354 case 301:
4355 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
4356 case 302:
4357 return "Found"; /* RFC2616 Section 10.3.3 */
4358 case 303:
4359 return "See Other"; /* RFC2616 Section 10.3.4 */
4360 case 304:
4361 return "Not Modified"; /* RFC2616 Section 10.3.5 */
4362 case 305:
4363 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
4364 case 307:
4365 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
4366 case 308:
4367 return "Permanent Redirect"; /* RFC7238 Section 3 */
4368
4369 /* RFC2616 Section 10.4 - Client Error 4xx */
4370 case 400:
4371 return "Bad Request"; /* RFC2616 Section 10.4.1 */
4372 case 401:
4373 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
4374 case 402:
4375 return "Payment Required"; /* RFC2616 Section 10.4.3 */
4376 case 403:
4377 return "Forbidden"; /* RFC2616 Section 10.4.4 */
4378 case 404:
4379 return "Not Found"; /* RFC2616 Section 10.4.5 */
4380 case 405:
4381 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
4382 case 406:
4383 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
4384 case 407:
4385 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
4386 case 408:
4387 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
4388 case 409:
4389 return "Conflict"; /* RFC2616 Section 10.4.10 */
4390 case 410:
4391 return "Gone"; /* RFC2616 Section 10.4.11 */
4392 case 411:
4393 return "Length Required"; /* RFC2616 Section 10.4.12 */
4394 case 412:
4395 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
4396 case 413:
4397 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
4398 case 414:
4399 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
4400 case 415:
4401 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
4402 case 416:
4403 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17
4404 */
4405 case 417:
4406 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
4407
4408 case 421:
4409 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
4410 case 422:
4411 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
4412 * Section 11.2 */
4413 case 423:
4414 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
4415 case 424:
4416 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
4417 * Section 11.4 */
4418
4419 case 426:
4420 return "Upgrade Required"; /* RFC 2817 Section 4 */
4421
4422 case 428:
4423 return "Precondition Required"; /* RFC 6585, Section 3 */
4424 case 429:
4425 return "Too Many Requests"; /* RFC 6585, Section 4 */
4426
4427 case 431:
4428 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
4429
4430 case 451:
4431 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
4432 * Section 3 */
4433
4434 /* RFC2616 Section 10.5 - Server Error 5xx */
4435 case 500:
4436 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
4437 case 501:
4438 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
4439 case 502:
4440 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
4441 case 503:
4442 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
4443 case 504:
4444 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
4445 case 505:
4446 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
4447 case 506:
4448 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
4449 case 507:
4450 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
4451 * Section 11.5 */
4452 case 508:
4453 return "Loop Detected"; /* RFC5842 Section 7.1 */
4454
4455 case 510:
4456 return "Not Extended"; /* RFC 2774, Section 7 */
4457 case 511:
4458 return "Network Authentication Required"; /* RFC 6585, Section 6 */
4459
4460 /* Other status codes, not shown in the IANA HTTP status code
4461 * assignment.
4462 * E.g., "de facto" standards due to common use, ... */
4463 case 418:
4464 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
4465 case 419:
4466 return "Authentication Timeout"; /* common use */
4467 case 420:
4468 return "Enhance Your Calm"; /* common use */
4469 case 440:
4470 return "Login Timeout"; /* common use */
4471 case 509:
4472 return "Bandwidth Limit Exceeded"; /* common use */
4473
4474 default:
4475 /* This error code is unknown. This should not happen. */
4476 if (conn) {
4477 mg_cry_internal(conn,
4478 "Unknown HTTP response code: %u",
4479 response_code);
4480 }
4481
4482 /* Return at least a category according to RFC 2616 Section 10. */
4483 if (response_code >= 100 && response_code < 200) {
4484 /* Unknown informational status code */
4485 return "Information";
4486 }
4487 if (response_code >= 200 && response_code < 300) {
4488 /* Unknown success code */
4489 return "Success";
4490 }
4491 if (response_code >= 300 && response_code < 400) {
4492 /* Unknown redirection code */
4493 return "Redirection";
4494 }
4495 if (response_code >= 400 && response_code < 500) {
4496 /* Unknown request error code */
4497 return "Client Error";
4498 }
4499 if (response_code >= 500 && response_code < 600) {
4500 /* Unknown server error code */
4501 return "Server Error";
4502 }
4503
4504 /* Response code not even within reasonable range */
4505 return "";
4506 }
4507}
4508
4509
4510static int
4512 int status,
4513 const char *fmt,
4514 va_list args)
4515{
4516 char errmsg_buf[MG_BUF_LEN];
4517 char path_buf[PATH_MAX];
4518 va_list ap;
4519 int len, i, page_handler_found, scope, truncated, has_body;
4520 char date[64];
4521 time_t curtime = time(NULL);
4522 const char *error_handler = NULL;
4523 struct mg_file error_page_file = STRUCT_FILE_INITIALIZER;
4524 const char *error_page_file_ext, *tstr;
4525 int handled_by_callback = 0;
4526
4527 const char *status_text = mg_get_response_code_text(conn, status);
4528
4529 if ((conn == NULL) || (fmt == NULL)) {
4530 return -2;
4531 }
4532
4533 /* Set status (for log) */
4534 conn->status_code = status;
4535
4536 /* Errors 1xx, 204 and 304 MUST NOT send a body */
4537 has_body = ((status > 199) && (status != 204) && (status != 304));
4538
4539 /* Prepare message in buf, if required */
4540 if (has_body
4541 || (!conn->in_error_handler
4542 && (conn->phys_ctx->callbacks.http_error != NULL))) {
4543 /* Store error message in errmsg_buf */
4544 va_copy(ap, args);
4545 mg_vsnprintf(conn, NULL, errmsg_buf, sizeof(errmsg_buf), fmt, ap);
4546 va_end(ap);
4547 /* In a debug build, print all html errors */
4548 DEBUG_TRACE("Error %i - [%s]", status, errmsg_buf);
4549 }
4550
4551 /* If there is a http_error callback, call it.
4552 * But don't do it recursively, if callback calls mg_send_http_error again.
4553 */
4554 if (!conn->in_error_handler
4555 && (conn->phys_ctx->callbacks.http_error != NULL)) {
4556 /* Mark in_error_handler to avoid recursion and call user callback. */
4557 conn->in_error_handler = 1;
4558 handled_by_callback =
4559 (conn->phys_ctx->callbacks.http_error(conn, status, errmsg_buf)
4560 == 0);
4561 conn->in_error_handler = 0;
4562 }
4563
4564 if (!handled_by_callback) {
4565 /* Check for recursion */
4566 if (conn->in_error_handler) {
4568 "Recursion when handling error %u - fall back to default",
4569 status);
4570 } else {
4571 /* Send user defined error pages, if defined */
4572 error_handler = conn->dom_ctx->config[ERROR_PAGES];
4573 error_page_file_ext = conn->dom_ctx->config[INDEX_FILES];
4574 page_handler_found = 0;
4575
4576 if (error_handler != NULL) {
4577 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4578 switch (scope) {
4579 case 1: /* Handler for specific error, e.g. 404 error */
4580 mg_snprintf(conn,
4581 &truncated,
4582 path_buf,
4583 sizeof(path_buf) - 32,
4584 "%serror%03u.",
4585 error_handler,
4586 status);
4587 break;
4588 case 2: /* Handler for error group, e.g., 5xx error
4589 * handler
4590 * for all server errors (500-599) */
4591 mg_snprintf(conn,
4592 &truncated,
4593 path_buf,
4594 sizeof(path_buf) - 32,
4595 "%serror%01uxx.",
4596 error_handler,
4597 status / 100);
4598 break;
4599 default: /* Handler for all errors */
4600 mg_snprintf(conn,
4601 &truncated,
4602 path_buf,
4603 sizeof(path_buf) - 32,
4604 "%serror.",
4605 error_handler);
4606 break;
4607 }
4608
4609 /* String truncation in buf may only occur if
4610 * error_handler is too long. This string is
4611 * from the config, not from a client. */
4612 (void)truncated;
4613
4614 len = (int)strlen(path_buf);
4615
4616 tstr = strchr(error_page_file_ext, '.');
4617
4618 while (tstr) {
4619 for (i = 1;
4620 (i < 32) && (tstr[i] != 0) && (tstr[i] != ',');
4621 i++) {
4622 /* buffer overrun is not possible here, since
4623 * (i < 32) && (len < sizeof(path_buf) - 32)
4624 * ==> (i + len) < sizeof(path_buf) */
4625 path_buf[len + i - 1] = tstr[i];
4626 }
4627 /* buffer overrun is not possible here, since
4628 * (i <= 32) && (len < sizeof(path_buf) - 32)
4629 * ==> (i + len) <= sizeof(path_buf) */
4630 path_buf[len + i - 1] = 0;
4631
4632 if (mg_stat(conn, path_buf, &error_page_file.stat)) {
4633 DEBUG_TRACE("Check error page %s - found",
4634 path_buf);
4635 page_handler_found = 1;
4636 break;
4637 }
4638 DEBUG_TRACE("Check error page %s - not found",
4639 path_buf);
4640
4641 tstr = strchr(tstr + i, '.');
4642 }
4643 }
4644 }
4645
4646 if (page_handler_found) {
4647 conn->in_error_handler = 1;
4648 handle_file_based_request(conn, path_buf, &error_page_file);
4649 conn->in_error_handler = 0;
4650 return 0;
4651 }
4652 }
4653
4654 /* No custom error page. Send default error page. */
4655 gmt_time_string(date, sizeof(date), &curtime);
4656
4657 conn->must_close = 1;
4658 mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
4661 if (has_body) {
4662 mg_printf(conn,
4663 "%s",
4664 "Content-Type: text/plain; charset=utf-8\r\n");
4665 }
4666 mg_printf(conn,
4667 "Date: %s\r\n"
4668 "Connection: close\r\n\r\n",
4669 date);
4670
4671 /* HTTP responses 1xx, 204 and 304 MUST NOT send a body */
4672 if (has_body) {
4673 /* For other errors, send a generic error message. */
4674 mg_printf(conn, "Error %d: %s\n", status, status_text);
4675 mg_write(conn, errmsg_buf, strlen(errmsg_buf));
4676
4677 } else {
4678 /* No body allowed. Close the connection. */
4679 DEBUG_TRACE("Error %i", status);
4680 }
4681 }
4682 return 0;
4683}
4684
4685
4686int
4687mg_send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
4688{
4689 va_list ap;
4690 int ret;
4691
4692 va_start(ap, fmt);
4693 ret = mg_send_http_error_impl(conn, status, fmt, ap);
4694 va_end(ap);
4695
4696 return ret;
4697}
4698
4699
4700int
4702 const char *mime_type,
4703 long long content_length)
4704{
4705 char date[64];
4706 time_t curtime = time(NULL);
4707
4708 if ((mime_type == NULL) || (*mime_type == 0)) {
4709 /* Parameter error */
4710 return -2;
4711 }
4712
4713 gmt_time_string(date, sizeof(date), &curtime);
4714
4715 mg_printf(conn,
4716 "HTTP/1.1 200 OK\r\n"
4717 "Content-Type: %s\r\n"
4718 "Date: %s\r\n"
4719 "Connection: %s\r\n",
4720 mime_type,
4721 date,
4723
4726 if (content_length < 0) {
4727 mg_printf(conn, "Transfer-Encoding: chunked\r\n\r\n");
4728 } else {
4729 mg_printf(conn,
4730 "Content-Length: %" UINT64_FMT "\r\n\r\n",
4731 (uint64_t)content_length);
4732 }
4733
4734 return 0;
4735}
4736
4737
4738int
4740 const char *target_url,
4741 int redirect_code)
4742{
4743 /* Send a 30x redirect response.
4744 *
4745 * Redirect types (status codes):
4746 *
4747 * Status | Perm/Temp | Method | Version
4748 * 301 | permanent | POST->GET undefined | HTTP/1.0
4749 * 302 | temporary | POST->GET undefined | HTTP/1.0
4750 * 303 | temporary | always use GET | HTTP/1.1
4751 * 307 | temporary | always keep method | HTTP/1.1
4752 * 308 | permanent | always keep method | HTTP/1.1
4753 */
4754 const char *redirect_text;
4755 int ret;
4756 size_t content_len = 0;
4757 char reply[MG_BUF_LEN];
4758
4759 /* In case redirect_code=0, use 307. */
4760 if (redirect_code == 0) {
4761 redirect_code = 307;
4762 }
4763
4764 /* In case redirect_code is none of the above, return error. */
4765 if ((redirect_code != 301) && (redirect_code != 302)
4766 && (redirect_code != 303) && (redirect_code != 307)
4767 && (redirect_code != 308)) {
4768 /* Parameter error */
4769 return -2;
4770 }
4771
4772 /* Get proper text for response code */
4773 redirect_text = mg_get_response_code_text(conn, redirect_code);
4774
4775 /* If target_url is not defined, redirect to "/". */
4776 if ((target_url == NULL) || (*target_url == 0)) {
4777 target_url = "/";
4778 }
4779
4780#if defined(MG_SEND_REDIRECT_BODY)
4781 /* TODO: condition name? */
4782
4783 /* Prepare a response body with a hyperlink.
4784 *
4785 * According to RFC2616 (and RFC1945 before):
4786 * Unless the request method was HEAD, the entity of the
4787 * response SHOULD contain a short hypertext note with a hyperlink to
4788 * the new URI(s).
4789 *
4790 * However, this response body is not useful in M2M communication.
4791 * Probably the original reason in the RFC was, clients not supporting
4792 * a 30x HTTP redirect could still show the HTML page and let the user
4793 * press the link. Since current browsers support 30x HTTP, the additional
4794 * HTML body does not seem to make sense anymore.
4795 *
4796 * The new RFC7231 (Section 6.4) does no longer recommend it ("SHOULD"),
4797 * but it only notes:
4798 * The server's response payload usually contains a short
4799 * hypertext note with a hyperlink to the new URI(s).
4800 *
4801 * Deactivated by default. If you need the 30x body, set the define.
4802 */
4804 conn,
4805 NULL /* ignore truncation */,
4806 reply,
4807 sizeof(reply),
4808 "<html><head>%s</head><body><a href=\"%s\">%s</a></body></html>",
4809 redirect_text,
4810 target_url,
4811 target_url);
4812 content_len = strlen(reply);
4813#else
4814 reply[0] = 0;
4815#endif
4816
4817 /* Do not send any additional header. For all other options,
4818 * including caching, there are suitable defaults. */
4819 ret = mg_printf(conn,
4820 "HTTP/1.1 %i %s\r\n"
4821 "Location: %s\r\n"
4822 "Content-Length: %u\r\n"
4823 "Connection: %s\r\n\r\n",
4824 redirect_code,
4825 redirect_text,
4826 target_url,
4827 (unsigned int)content_len,
4829
4830 /* Send response body */
4831 if (ret > 0) {
4832 /* ... unless it is a HEAD request */
4833 if (0 != strcmp(conn->request_info.request_method, "HEAD")) {
4834 ret = mg_write(conn, reply, content_len);
4835 }
4836 }
4837
4838 return (ret > 0) ? ret : -1;
4839}
4840
4841
4842#if defined(_WIN32)
4843/* Create substitutes for POSIX functions in Win32. */
4844
4845#if defined(GCC_DIAGNOSTIC)
4846/* Show no warning in case system functions are not used. */
4847#pragma GCC diagnostic push
4848#pragma GCC diagnostic ignored "-Wunused-function"
4849#endif
4850
4851
4853static int
4854pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
4855{
4856 (void)unused;
4857 *mutex = CreateMutex(NULL, FALSE, NULL);
4858 return (*mutex == NULL) ? -1 : 0;
4859}
4860
4862static int
4863pthread_mutex_destroy(pthread_mutex_t *mutex)
4864{
4865 return (CloseHandle(*mutex) == 0) ? -1 : 0;
4866}
4867
4868
4870static int
4871pthread_mutex_lock(pthread_mutex_t *mutex)
4872{
4873 return (WaitForSingleObject(*mutex, (DWORD)INFINITE) == WAIT_OBJECT_0) ? 0
4874 : -1;
4875}
4876
4877
4878#if defined(ENABLE_UNUSED_PTHREAD_FUNCTIONS)
4880static int
4881pthread_mutex_trylock(pthread_mutex_t *mutex)
4882{
4883 switch (WaitForSingleObject(*mutex, 0)) {
4884 case WAIT_OBJECT_0:
4885 return 0;
4886 case WAIT_TIMEOUT:
4887 return -2; /* EBUSY */
4888 }
4889 return -1;
4890}
4891#endif
4892
4893
4895static int
4896pthread_mutex_unlock(pthread_mutex_t *mutex)
4897{
4898 return (ReleaseMutex(*mutex) == 0) ? -1 : 0;
4899}
4900
4901
4903static int
4904pthread_cond_init(pthread_cond_t *cv, const void *unused)
4905{
4906 (void)unused;
4907 InitializeCriticalSection(&cv->threadIdSec);
4908 cv->waiting_thread = NULL;
4909 return 0;
4910}
4911
4912
4914static int
4915pthread_cond_timedwait(pthread_cond_t *cv,
4916 pthread_mutex_t *mutex,
4917 FUNCTION_MAY_BE_UNUSED const struct timespec *abstime)
4918{
4919 struct mg_workerTLS **ptls,
4920 *tls = (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
4921 int ok;
4922 int64_t nsnow, nswaitabs, nswaitrel;
4923 DWORD mswaitrel;
4924
4925 EnterCriticalSection(&cv->threadIdSec);
4926 /* Add this thread to cv's waiting list */
4927 ptls = &cv->waiting_thread;
4928 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
4929 ;
4930 tls->next_waiting_thread = NULL;
4931 *ptls = tls;
4932 LeaveCriticalSection(&cv->threadIdSec);
4933
4934 if (abstime) {
4935 nsnow = mg_get_current_time_ns();
4936 nswaitabs =
4937 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4938 nswaitrel = nswaitabs - nsnow;
4939 if (nswaitrel < 0) {
4940 nswaitrel = 0;
4941 }
4942 mswaitrel = (DWORD)(nswaitrel / 1000000);
4943 } else {
4944 mswaitrel = (DWORD)INFINITE;
4945 }
4946
4947 pthread_mutex_unlock(mutex);
4948 ok = (WAIT_OBJECT_0
4949 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
4950 if (!ok) {
4951 ok = 1;
4952 EnterCriticalSection(&cv->threadIdSec);
4953 ptls = &cv->waiting_thread;
4954 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
4955 if (*ptls == tls) {
4956 *ptls = tls->next_waiting_thread;
4957 ok = 0;
4958 break;
4959 }
4960 }
4961 LeaveCriticalSection(&cv->threadIdSec);
4962 if (ok) {
4963 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4964 (DWORD)INFINITE);
4965 }
4966 }
4967 /* This thread has been removed from cv's waiting list */
4968 pthread_mutex_lock(mutex);
4969
4970 return ok ? 0 : -1;
4971}
4972
4973
4975static int
4976pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
4977{
4978 return pthread_cond_timedwait(cv, mutex, NULL);
4979}
4980
4981
4983static int
4984pthread_cond_signal(pthread_cond_t *cv)
4985{
4986 HANDLE wkup = NULL;
4987 BOOL ok = FALSE;
4988
4989 EnterCriticalSection(&cv->threadIdSec);
4990 if (cv->waiting_thread) {
4991 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4992 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
4993
4994 ok = SetEvent(wkup);
4995 DEBUG_ASSERT(ok);
4996 }
4997 LeaveCriticalSection(&cv->threadIdSec);
4998
4999 return ok ? 0 : 1;
5000}
5001
5002
5004static int
5005pthread_cond_broadcast(pthread_cond_t *cv)
5006{
5007 EnterCriticalSection(&cv->threadIdSec);
5008 while (cv->waiting_thread) {
5009 pthread_cond_signal(cv);
5010 }
5011 LeaveCriticalSection(&cv->threadIdSec);
5012
5013 return 0;
5014}
5015
5016
5018static int
5019pthread_cond_destroy(pthread_cond_t *cv)
5020{
5021 EnterCriticalSection(&cv->threadIdSec);
5022 DEBUG_ASSERT(cv->waiting_thread == NULL);
5023 LeaveCriticalSection(&cv->threadIdSec);
5024 DeleteCriticalSection(&cv->threadIdSec);
5025
5026 return 0;
5027}
5028
5029
5030#if defined(ALTERNATIVE_QUEUE)
5032static void *
5033event_create(void)
5034{
5035 return (void *)CreateEvent(NULL, FALSE, FALSE, NULL);
5036}
5037
5038
5040static int
5041event_wait(void *eventhdl)
5042{
5043 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
5044 return (res == WAIT_OBJECT_0);
5045}
5046
5047
5049static int
5050event_signal(void *eventhdl)
5051{
5052 return (int)SetEvent((HANDLE)eventhdl);
5053}
5054
5055
5057static void
5058event_destroy(void *eventhdl)
5059{
5060 CloseHandle((HANDLE)eventhdl);
5061}
5062#endif
5063
5064
5065#if defined(GCC_DIAGNOSTIC)
5066/* Enable unused function warning again */
5067#pragma GCC diagnostic pop
5068#endif
5069
5070
5071/* For Windows, change all slashes to backslashes in path names. */
5072static void
5073change_slashes_to_backslashes(char *path)
5074{
5075 int i;
5076
5077 for (i = 0; path[i] != '\0'; i++) {
5078 if (path[i] == '/') {
5079 path[i] = '\\';
5080 }
5081
5082 /* remove double backslash (check i > 0 to preserve UNC paths,
5083 * like \\server\file.txt) */
5084 if ((path[i] == '\\') && (i > 0)) {
5085 while ((path[i + 1] == '\\') || (path[i + 1] == '/')) {
5086 (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
5087 }
5088 }
5089 }
5090}
5091
5092
5093static int
5094mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2)
5095{
5096 int diff;
5097
5098 do {
5099 diff = tolower(*s1) - tolower(*s2);
5100 s1++;
5101 s2++;
5102 } while ((diff == 0) && (s1[-1] != '\0'));
5103
5104 return diff;
5105}
5106
5107
5108/* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
5109 * wbuf and wbuf_len is a target buffer and its length. */
5110static void
5111path_to_unicode(const struct mg_connection *conn,
5112 const char *path,
5113 wchar_t *wbuf,
5114 size_t wbuf_len)
5115{
5116 char buf[PATH_MAX], buf2[PATH_MAX];
5117 wchar_t wbuf2[W_PATH_MAX + 1];
5118 DWORD long_len, err;
5119 int (*fcompare)(const wchar_t *, const wchar_t *) = mg_wcscasecmp;
5120
5121 mg_strlcpy(buf, path, sizeof(buf));
5122 change_slashes_to_backslashes(buf);
5123
5124 /* Convert to Unicode and back. If doubly-converted string does not
5125 * match the original, something is fishy, reject. */
5126 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
5127 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
5128 WideCharToMultiByte(
5129 CP_UTF8, 0, wbuf, (int)wbuf_len, buf2, sizeof(buf2), NULL, NULL);
5130 if (strcmp(buf, buf2) != 0) {
5131 wbuf[0] = L'\0';
5132 }
5133
5134 /* Windows file systems are not case sensitive, but you can still use
5135 * uppercase and lowercase letters (on all modern file systems).
5136 * The server can check if the URI uses the same upper/lowercase
5137 * letters an the file system, effectively making Windows servers
5138 * case sensitive (like Linux servers are). It is still not possible
5139 * to use two files with the same name in different cases on Windows
5140 * (like /a and /A) - this would be possible in Linux.
5141 * As a default, Windows is not case sensitive, but the case sensitive
5142 * file name check can be activated by an additional configuration. */
5143 if (conn) {
5144 if (conn->dom_ctx->config[CASE_SENSITIVE_FILES]
5145 && !mg_strcasecmp(conn->dom_ctx->config[CASE_SENSITIVE_FILES],
5146 "yes")) {
5147 /* Use case sensitive compare function */
5148 fcompare = wcscmp;
5149 }
5150 }
5151 (void)conn; /* conn is currently unused */
5152
5153#if !defined(_WIN32_WCE)
5154 /* Only accept a full file path, not a Windows short (8.3) path. */
5155 memset(wbuf2, 0, ARRAY_SIZE(wbuf2) * sizeof(wchar_t));
5156 long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1);
5157 if (long_len == 0) {
5158 err = GetLastError();
5159 if (err == ERROR_FILE_NOT_FOUND) {
5160 /* File does not exist. This is not always a problem here. */
5161 return;
5162 }
5163 }
5164 if ((long_len >= ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
5165 /* Short name is used. */
5166 wbuf[0] = L'\0';
5167 }
5168#else
5169 (void)long_len;
5170 (void)wbuf2;
5171 (void)err;
5172
5173 if (strchr(path, '~')) {
5174 wbuf[0] = L'\0';
5175 }
5176#endif
5177}
5178
5179
5180/* Windows happily opens files with some garbage at the end of file name.
5181 * For example, fopen("a.cgi ", "r") on Windows successfully opens
5182 * "a.cgi", despite one would expect an error back.
5183 * This function returns non-0 if path ends with some garbage. */
5184static int
5185path_cannot_disclose_cgi(const char *path)
5186{
5187 static const char *allowed_last_characters = "_-";
5188 int last = path[strlen(path) - 1];
5189 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
5190}
5191
5192
5193static int
5194mg_stat(const struct mg_connection *conn,
5195 const char *path,
5196 struct mg_file_stat *filep)
5197{
5198 wchar_t wbuf[W_PATH_MAX];
5199 WIN32_FILE_ATTRIBUTE_DATA info;
5200 time_t creation_time;
5201
5202 if (!filep) {
5203 return 0;
5204 }
5205 memset(filep, 0, sizeof(*filep));
5206
5207 if (conn && is_file_in_memory(conn, path)) {
5208 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
5209 * memset */
5210
5211 /* Quick fix (for 1.9.x): */
5212 /* mg_stat must fill all fields, also for files in memory */
5213 struct mg_file tmp_file = STRUCT_FILE_INITIALIZER;
5214 open_file_in_memory(conn, path, &tmp_file, MG_FOPEN_MODE_NONE);
5215 filep->size = tmp_file.stat.size;
5216 filep->location = 2;
5217 /* TODO: for 1.10: restructure how files in memory are handled */
5218
5219 /* The "file in memory" feature is a candidate for deletion.
5220 * Please join the discussion at
5221 * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI
5222 */
5223
5224 filep->last_modified = time(NULL); /* TODO */
5225 /* last_modified = now ... assumes the file may change during
5226 * runtime,
5227 * so every mg_fopen call may return different data */
5228 /* last_modified = conn->phys_ctx.start_time;
5229 * May be used it the data does not change during runtime. This
5230 * allows
5231 * browser caching. Since we do not know, we have to assume the file
5232 * in memory may change. */
5233 return 1;
5234 }
5235
5236 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
5237 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
5238 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
5239 filep->last_modified =
5240 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
5241 info.ftLastWriteTime.dwHighDateTime);
5242
5243 /* On Windows, the file creation time can be higher than the
5244 * modification time, e.g. when a file is copied.
5245 * Since the Last-Modified timestamp is used for caching
5246 * it should be based on the most recent timestamp. */
5247 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
5248 info.ftCreationTime.dwHighDateTime);
5249 if (creation_time > filep->last_modified) {
5250 filep->last_modified = creation_time;
5251 }
5252
5253 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
5254 /* If file name is fishy, reset the file structure and return
5255 * error.
5256 * Note it is important to reset, not just return the error, cause
5257 * functions like is_file_opened() check the struct. */
5258 if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
5259 memset(filep, 0, sizeof(*filep));
5260 return 0;
5261 }
5262
5263 return 1;
5264 }
5265
5266 return 0;
5267}
5268
5269
5270static int
5271mg_remove(const struct mg_connection *conn, const char *path)
5272{
5273 wchar_t wbuf[W_PATH_MAX];
5274 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
5275 return DeleteFileW(wbuf) ? 0 : -1;
5276}
5277
5278
5279static int
5280mg_mkdir(const struct mg_connection *conn, const char *path, int mode)
5281{
5282 wchar_t wbuf[W_PATH_MAX];
5283 (void)mode;
5284 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
5285 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
5286}
5287
5288
5289/* Create substitutes for POSIX functions in Win32. */
5290
5291#if defined(GCC_DIAGNOSTIC)
5292/* Show no warning in case system functions are not used. */
5293#pragma GCC diagnostic push
5294#pragma GCC diagnostic ignored "-Wunused-function"
5295#endif
5296
5297
5298/* Implementation of POSIX opendir/closedir/readdir for Windows. */
5300static DIR *
5301mg_opendir(const struct mg_connection *conn, const char *name)
5302{
5303 DIR *dir = NULL;
5304 wchar_t wpath[W_PATH_MAX];
5305 DWORD attrs;
5306
5307 if (name == NULL) {
5308 SetLastError(ERROR_BAD_ARGUMENTS);
5309 } else if ((dir = (DIR *)mg_malloc(sizeof(*dir))) == NULL) {
5310 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5311 } else {
5312 path_to_unicode(conn, name, wpath, ARRAY_SIZE(wpath));
5313 attrs = GetFileAttributesW(wpath);
5314 if ((wcslen(wpath) + 2 < ARRAY_SIZE(wpath)) && (attrs != 0xFFFFFFFF)
5315 && ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0)) {
5316 (void)wcscat(wpath, L"\\*");
5317 dir->handle = FindFirstFileW(wpath, &dir->info);
5318 dir->result.d_name[0] = '\0';
5319 } else {
5320 mg_free(dir);
5321 dir = NULL;
5322 }
5323 }
5324
5325 return dir;
5326}
5327
5328
5330static int
5331mg_closedir(DIR *dir)
5332{
5333 int result = 0;
5334
5335 if (dir != NULL) {
5336 if (dir->handle != INVALID_HANDLE_VALUE)
5337 result = FindClose(dir->handle) ? 0 : -1;
5338
5339 mg_free(dir);
5340 } else {
5341 result = -1;
5342 SetLastError(ERROR_BAD_ARGUMENTS);
5343 }
5344
5345 return result;
5346}
5347
5348
5350static struct dirent *
5351mg_readdir(DIR *dir)
5352{
5353 struct dirent *result = 0;
5354
5355 if (dir) {
5356 if (dir->handle != INVALID_HANDLE_VALUE) {
5357 result = &dir->result;
5358 (void)WideCharToMultiByte(CP_UTF8,
5359 0,
5360 dir->info.cFileName,
5361 -1,
5362 result->d_name,
5363 sizeof(result->d_name),
5364 NULL,
5365 NULL);
5366
5367 if (!FindNextFileW(dir->handle, &dir->info)) {
5368 (void)FindClose(dir->handle);
5369 dir->handle = INVALID_HANDLE_VALUE;
5370 }
5371
5372 } else {
5373 SetLastError(ERROR_FILE_NOT_FOUND);
5374 }
5375 } else {
5376 SetLastError(ERROR_BAD_ARGUMENTS);
5377 }
5378
5379 return result;
5380}
5381
5382
5383#if !defined(HAVE_POLL)
5384#define POLLIN (1) /* Data ready - read will not block. */
5385#define POLLPRI (2) /* Priority data ready. */
5386#define POLLOUT (4) /* Send queue not full - write will not block. */
5387
5389static int
5390poll(struct pollfd *pfd, unsigned int n, int milliseconds)
5391{
5392 struct timeval tv;
5393 fd_set rset;
5394 fd_set wset;
5395 unsigned int i;
5396 int result;
5397 SOCKET maxfd = 0;
5398
5399 memset(&tv, 0, sizeof(tv));
5400 tv.tv_sec = milliseconds / 1000;
5401 tv.tv_usec = (milliseconds % 1000) * 1000;
5402 FD_ZERO(&rset);
5403 FD_ZERO(&wset);
5404
5405 for (i = 0; i < n; i++) {
5406 if (pfd[i].events & POLLIN) {
5407 FD_SET((SOCKET)pfd[i].fd, &rset);
5408 } else if (pfd[i].events & POLLOUT) {
5409 FD_SET((SOCKET)pfd[i].fd, &wset);
5410 }
5411 pfd[i].revents = 0;
5412
5413 if (pfd[i].fd > maxfd) {
5414 maxfd = pfd[i].fd;
5415 }
5416 }
5417
5418 if ((result = select((int)maxfd + 1, &rset, &wset, NULL, &tv)) > 0) {
5419 for (i = 0; i < n; i++) {
5420 if (FD_ISSET(pfd[i].fd, &rset)) {
5421 pfd[i].revents |= POLLIN;
5422 }
5423 if (FD_ISSET(pfd[i].fd, &wset)) {
5424 pfd[i].revents |= POLLOUT;
5425 }
5426 }
5427 }
5428
5429 /* We should subtract the time used in select from remaining
5430 * "milliseconds", in particular if called from mg_poll with a
5431 * timeout quantum.
5432 * Unfortunately, the remaining time is not stored in "tv" in all
5433 * implementations, so the result in "tv" must be considered undefined.
5434 * See http://man7.org/linux/man-pages/man2/select.2.html */
5435
5436 return result;
5437}
5438#endif /* HAVE_POLL */
5439
5440
5441#if defined(GCC_DIAGNOSTIC)
5442/* Enable unused function warning again */
5443#pragma GCC diagnostic pop
5444#endif
5445
5446
5447static void
5448set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
5449{
5450 (void)conn; /* Unused. */
5451#if defined(_WIN32_WCE)
5452 (void)sock;
5453#else
5454 (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
5455#endif
5456}
5457
5458
5459int
5461{
5462#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5463 /* Compile-time option to control stack size, e.g.
5464 * -DUSE_STACK_SIZE=16384
5465 */
5466 return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p)
5467 == ((uintptr_t)(-1L)))
5468 ? -1
5469 : 0);
5470#else
5471 return (
5472 (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L)))
5473 ? -1
5474 : 0);
5475#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
5476}
5477
5478
5479/* Start a thread storing the thread context. */
5480static int
5481mg_start_thread_with_id(unsigned(__stdcall *f)(void *),
5482 void *p,
5483 pthread_t *threadidptr)
5484{
5485 uintptr_t uip;
5486 HANDLE threadhandle;
5487 int result = -1;
5488
5489 uip = _beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))f, p, 0, NULL);
5490 threadhandle = (HANDLE)uip;
5491 if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
5492 *threadidptr = threadhandle;
5493 result = 0;
5494 }
5495
5496 return result;
5497}
5498
5499
5500/* Wait for a thread to finish. */
5501static int
5502mg_join_thread(pthread_t threadid)
5503{
5504 int result;
5505 DWORD dwevent;
5506
5507 result = -1;
5508 dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE);
5509 if (dwevent == WAIT_FAILED) {
5510 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO);
5511 } else {
5512 if (dwevent == WAIT_OBJECT_0) {
5513 CloseHandle(threadid);
5514 result = 0;
5515 }
5516 }
5517
5518 return result;
5519}
5520
5521#if !defined(NO_SSL_DL) && !defined(NO_SSL)
5522/* If SSL is loaded dynamically, dlopen/dlclose is required. */
5523/* Create substitutes for POSIX functions in Win32. */
5524
5525#if defined(GCC_DIAGNOSTIC)
5526/* Show no warning in case system functions are not used. */
5527#pragma GCC diagnostic push
5528#pragma GCC diagnostic ignored "-Wunused-function"
5529#endif
5530
5531
5533static HANDLE
5534dlopen(const char *dll_name, int flags)
5535{
5536 wchar_t wbuf[W_PATH_MAX];
5537 (void)flags;
5538 path_to_unicode(NULL, dll_name, wbuf, ARRAY_SIZE(wbuf));
5539 return LoadLibraryW(wbuf);
5540}
5541
5542
5544static int
5545dlclose(void *handle)
5546{
5547 int result;
5548
5549 if (FreeLibrary((HMODULE)handle) != 0) {
5550 result = 0;
5551 } else {
5552 result = -1;
5553 }
5554
5555 return result;
5556}
5557
5558
5559#if defined(GCC_DIAGNOSTIC)
5560/* Enable unused function warning again */
5561#pragma GCC diagnostic pop
5562#endif
5563
5564#endif
5565
5566
5567#if !defined(NO_CGI)
5568#define SIGKILL (0)
5569
5570
5571static int
5572kill(pid_t pid, int sig_num)
5573{
5574 (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
5575 (void)CloseHandle((HANDLE)pid);
5576 return 0;
5577}
5578
5579
5580#if !defined(WNOHANG)
5581#define WNOHANG (1)
5582#endif
5583
5584
5585static pid_t
5586waitpid(pid_t pid, int *status, int flags)
5587{
5588 DWORD timeout = INFINITE;
5589 DWORD waitres;
5590
5591 (void)status; /* Currently not used by any client here */
5592
5593 if ((flags | WNOHANG) == WNOHANG) {
5594 timeout = 0;
5595 }
5596
5597 waitres = WaitForSingleObject((HANDLE)pid, timeout);
5598 if (waitres == WAIT_OBJECT_0) {
5599 return pid;
5600 }
5601 if (waitres == WAIT_TIMEOUT) {
5602 return 0;
5603 }
5604 return (pid_t)-1;
5605}
5606
5607
5608static void
5609trim_trailing_whitespaces(char *s)
5610{
5611 char *e = s + strlen(s) - 1;
5612 while ((e > s) && isspace(*(unsigned char *)e)) {
5613 *e-- = '\0';
5614 }
5615}
5616
5617
5618static pid_t
5619spawn_process(struct mg_connection *conn,
5620 const char *prog,
5621 char *envblk,
5622 char *envp[],
5623 int fdin[2],
5624 int fdout[2],
5625 int fderr[2],
5626 const char *dir)
5627{
5628 HANDLE me;
5629 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
5630 cmdline[PATH_MAX], buf[PATH_MAX];
5631 int truncated;
5633 STARTUPINFOA si;
5634 PROCESS_INFORMATION pi = {0};
5635
5636 (void)envp;
5637
5638 memset(&si, 0, sizeof(si));
5639 si.cb = sizeof(si);
5640
5641 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5642 si.wShowWindow = SW_HIDE;
5643
5644 me = GetCurrentProcess();
5645 DuplicateHandle(me,
5646 (HANDLE)_get_osfhandle(fdin[0]),
5647 me,
5648 &si.hStdInput,
5649 0,
5650 TRUE,
5651 DUPLICATE_SAME_ACCESS);
5652 DuplicateHandle(me,
5653 (HANDLE)_get_osfhandle(fdout[1]),
5654 me,
5655 &si.hStdOutput,
5656 0,
5657 TRUE,
5658 DUPLICATE_SAME_ACCESS);
5659 DuplicateHandle(me,
5660 (HANDLE)_get_osfhandle(fderr[1]),
5661 me,
5662 &si.hStdError,
5663 0,
5664 TRUE,
5665 DUPLICATE_SAME_ACCESS);
5666
5667 /* Mark handles that should not be inherited. See
5668 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
5669 */
5670 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5671 HANDLE_FLAG_INHERIT,
5672 0);
5673 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5674 HANDLE_FLAG_INHERIT,
5675 0);
5676 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5677 HANDLE_FLAG_INHERIT,
5678 0);
5679
5680 /* If CGI file is a script, try to read the interpreter line */
5681 interp = conn->dom_ctx->config[CGI_INTERPRETER];
5682 if (interp == NULL) {
5683 buf[0] = buf[1] = '\0';
5684
5685 /* Read the first line of the script into the buffer */
5687 conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
5688
5689 if (truncated) {
5690 pi.hProcess = (pid_t)-1;
5691 goto spawn_cleanup;
5692 }
5693
5694 if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) {
5695#if defined(MG_USE_OPEN_FILE)
5696 p = (char *)file.access.membuf;
5697#else
5698 p = (char *)NULL;
5699#endif
5700 mg_fgets(buf, sizeof(buf), &file, &p);
5701 (void)mg_fclose(&file.access); /* ignore error on read only file */
5702 buf[sizeof(buf) - 1] = '\0';
5703 }
5704
5705 if ((buf[0] == '#') && (buf[1] == '!')) {
5706 trim_trailing_whitespaces(buf + 2);
5707 } else {
5708 buf[2] = '\0';
5709 }
5710 interp = buf + 2;
5711 }
5712
5713 if (interp[0] != '\0') {
5714 GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
5715 interp = full_interp;
5716 }
5717 GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
5718
5719 if (interp[0] != '\0') {
5720 mg_snprintf(conn,
5721 &truncated,
5722 cmdline,
5723 sizeof(cmdline),
5724 "\"%s\" \"%s\\%s\"",
5725 interp,
5726 full_dir,
5727 prog);
5728 } else {
5729 mg_snprintf(conn,
5730 &truncated,
5731 cmdline,
5732 sizeof(cmdline),
5733 "\"%s\\%s\"",
5734 full_dir,
5735 prog);
5736 }
5737
5738 if (truncated) {
5739 pi.hProcess = (pid_t)-1;
5740 goto spawn_cleanup;
5741 }
5742
5743 DEBUG_TRACE("Running [%s]", cmdline);
5744 if (CreateProcessA(NULL,
5745 cmdline,
5746 NULL,
5747 NULL,
5748 TRUE,
5749 CREATE_NEW_PROCESS_GROUP,
5750 envblk,
5751 NULL,
5752 &si,
5753 &pi)
5754 == 0) {
5756 conn, "%s: CreateProcess(%s): %ld", __func__, cmdline, (long)ERRNO);
5757 pi.hProcess = (pid_t)-1;
5758 /* goto spawn_cleanup; */
5759 }
5760
5761spawn_cleanup:
5762 (void)CloseHandle(si.hStdOutput);
5763 (void)CloseHandle(si.hStdError);
5764 (void)CloseHandle(si.hStdInput);
5765 if (pi.hThread != NULL) {
5766 (void)CloseHandle(pi.hThread);
5767 }
5768
5769 return (pid_t)pi.hProcess;
5770}
5771#endif /* !NO_CGI */
5772
5773
5774static int
5776{
5777 unsigned long non_blocking = 0;
5778 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
5779}
5780
5781static int
5783{
5784 unsigned long non_blocking = 1;
5785 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
5786}
5787
5788#else
5789
5790static int
5791mg_stat(const struct mg_connection *conn,
5792 const char *path,
5793 struct mg_file_stat *filep)
5794{
5795 struct stat st;
5796 if (!filep) {
5797 return 0;
5798 }
5799 memset(filep, 0, sizeof(*filep));
5800
5801 if (conn && is_file_in_memory(conn, path)) {
5802
5803 /* Quick fix (for 1.9.x): */
5804 /* mg_stat must fill all fields, also for files in memory */
5805 struct mg_file tmp_file = STRUCT_FILE_INITIALIZER;
5806 open_file_in_memory(conn, path, &tmp_file, MG_FOPEN_MODE_NONE);
5807 filep->size = tmp_file.stat.size;
5808 filep->last_modified = time(NULL);
5809 filep->location = 2;
5810 /* TODO: remove legacy "files in memory" feature */
5811
5812 return 1;
5813 }
5814
5815 if (0 == stat(path, &st)) {
5816 filep->size = (uint64_t)(st.st_size);
5817 filep->last_modified = st.st_mtime;
5818 filep->is_directory = S_ISDIR(st.st_mode);
5819 return 1;
5820 }
5821
5822 return 0;
5823}
5824
5825
5826static void
5827set_close_on_exec(SOCKET fd, struct mg_connection *conn /* may be null */)
5828{
5829 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5830 if (conn) {
5831 mg_cry_internal(conn,
5832 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5833 __func__,
5834 strerror(ERRNO));
5835 }
5836 }
5837}
5838
5839
5840int
5842{
5843 pthread_t thread_id;
5844 pthread_attr_t attr;
5845 int result;
5846
5847 (void)pthread_attr_init(&attr);
5848 (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5849
5850#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5851 /* Compile-time option to control stack size,
5852 * e.g. -DUSE_STACK_SIZE=16384 */
5853 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5854#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
5855
5856 result = pthread_create(&thread_id, &attr, func, param);
5857 pthread_attr_destroy(&attr);
5858
5859 return result;
5860}
5861
5862
5863/* Start a thread storing the thread context. */
5864static int
5866 void *param,
5867 pthread_t *threadidptr)
5868{
5869 pthread_t thread_id;
5870 pthread_attr_t attr;
5871 int result;
5872
5873 (void)pthread_attr_init(&attr);
5874
5875#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5876 /* Compile-time option to control stack size,
5877 * e.g. -DUSE_STACK_SIZE=16384 */
5878 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5879#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
5880
5881 result = pthread_create(&thread_id, &attr, func, param);
5882 pthread_attr_destroy(&attr);
5883 if ((result == 0) && (threadidptr != NULL)) {
5884 *threadidptr = thread_id;
5885 }
5886 return result;
5887}
5888
5889
5890/* Wait for a thread to finish. */
5891static int
5892mg_join_thread(pthread_t threadid)
5893{
5894 int result;
5895
5896 result = pthread_join(threadid, NULL);
5897 return result;
5898}
5899
5900
5901#if !defined(NO_CGI)
5902static pid_t
5904 const char *prog,
5905 char *envblk,
5906 char *envp[],
5907 int fdin[2],
5908 int fdout[2],
5909 int fderr[2],
5910 const char *dir)
5911{
5912 pid_t pid;
5913 const char *interp;
5914
5915 (void)envblk;
5916
5917 if (conn == NULL) {
5918 return 0;
5919 }
5920
5921 if ((pid = fork()) == -1) {
5922 /* Parent */
5923 mg_send_http_error(conn,
5924 500,
5925 "Error: Creating CGI process\nfork(): %s",
5926 strerror(ERRNO));
5927 } else if (pid == 0) {
5928 /* Child */
5929 if (chdir(dir) != 0) {
5931 conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
5932 } else if (dup2(fdin[0], 0) == -1) {
5933 mg_cry_internal(conn,
5934 "%s: dup2(%d, 0): %s",
5935 __func__,
5936 fdin[0],
5937 strerror(ERRNO));
5938 } else if (dup2(fdout[1], 1) == -1) {
5939 mg_cry_internal(conn,
5940 "%s: dup2(%d, 1): %s",
5941 __func__,
5942 fdout[1],
5943 strerror(ERRNO));
5944 } else if (dup2(fderr[1], 2) == -1) {
5945 mg_cry_internal(conn,
5946 "%s: dup2(%d, 2): %s",
5947 __func__,
5948 fderr[1],
5949 strerror(ERRNO));
5950 } else {
5951 /* Keep stderr and stdout in two different pipes.
5952 * Stdout will be sent back to the client,
5953 * stderr should go into a server error log. */
5954 (void)close(fdin[0]);
5955 (void)close(fdout[1]);
5956 (void)close(fderr[1]);
5957
5958 /* Close write end fdin and read end fdout and fderr */
5959 (void)close(fdin[1]);
5960 (void)close(fdout[0]);
5961 (void)close(fderr[0]);
5962
5963 /* After exec, all signal handlers are restored to their default
5964 * values, with one exception of SIGCHLD. According to
5965 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler
5966 * will leave unchanged after exec if it was set to be ignored.
5967 * Restore it to default action. */
5968 signal(SIGCHLD, SIG_DFL);
5969
5970 interp = conn->dom_ctx->config[CGI_INTERPRETER];
5971 if (interp == NULL) {
5972 (void)execle(prog, prog, NULL, envp);
5973 mg_cry_internal(conn,
5974 "%s: execle(%s): %s",
5975 __func__,
5976 prog,
5977 strerror(ERRNO));
5978 } else {
5979 (void)execle(interp, interp, prog, NULL, envp);
5980 mg_cry_internal(conn,
5981 "%s: execle(%s %s): %s",
5982 __func__,
5983 interp,
5984 prog,
5985 strerror(ERRNO));
5986 }
5987 }
5988 exit(EXIT_FAILURE);
5989 }
5990
5991 return pid;
5992}
5993#endif /* !NO_CGI */
5994
5995
5996static int
5998{
5999 int flags = fcntl(sock, F_GETFL, 0);
6000 if (flags < 0) {
6001 return -1;
6002 }
6003
6004 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
6005 return -1;
6006 }
6007 return 0;
6008}
6009
6010static int
6012{
6013 int flags = fcntl(sock, F_GETFL, 0);
6014 if (flags < 0) {
6015 return -1;
6016 }
6017
6018 if (fcntl(sock, F_SETFL, flags & (~(int)(O_NONBLOCK))) < 0) {
6019 return -1;
6020 }
6021 return 0;
6022}
6023#endif /* _WIN32 / else */
6024
6025/* End of initial operating system specific define block. */
6026
6027
6028/* Get a random number (independent of C rand function) */
6029static uint64_t
6031{
6032 static uint64_t lfsr = 0; /* Linear feedback shift register */
6033 static uint64_t lcg = 0; /* Linear congruential generator */
6034 uint64_t now = mg_get_current_time_ns();
6035
6036 if (lfsr == 0) {
6037 /* lfsr will be only 0 if has not been initialized,
6038 * so this code is called only once. */
6039 lfsr = mg_get_current_time_ns();
6040 lcg = mg_get_current_time_ns();
6041 } else {
6042 /* Get the next step of both random number generators. */
6043 lfsr = (lfsr >> 1)
6044 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
6045 << 63);
6046 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
6047 }
6048
6049 /* Combining two pseudo-random number generators and a high resolution
6050 * part
6051 * of the current server time will make it hard (impossible?) to guess
6052 * the
6053 * next number. */
6054 return (lfsr ^ lcg ^ now);
6055}
6056
6057
6058static int
6059mg_poll(struct pollfd *pfd,
6060 unsigned int n,
6061 int milliseconds,
6062 volatile int *stop_server)
6063{
6064 /* Call poll, but only for a maximum time of a few seconds.
6065 * This will allow to stop the server after some seconds, instead
6066 * of having to wait for a long socket timeout. */
6067 int ms_now = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
6068
6069 do {
6070 int result;
6071
6072 if (*stop_server) {
6073 /* Shut down signal */
6074 return -2;
6075 }
6076
6077 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
6078 ms_now = milliseconds;
6079 }
6080
6081 result = poll(pfd, n, ms_now);
6082 if (result != 0) {
6083 /* Poll returned either success (1) or error (-1).
6084 * Forward both to the caller. */
6085 return result;
6086 }
6087
6088 /* Poll returned timeout (0). */
6089 if (milliseconds > 0) {
6090 milliseconds -= ms_now;
6091 }
6092
6093 } while (milliseconds != 0);
6094
6095 /* timeout: return 0 */
6096 return 0;
6097}
6098
6099
6100/* Write data to the IO channel - opened file descriptor, socket or SSL
6101 * descriptor.
6102 * Return value:
6103 * >=0 .. number of bytes successfully written
6104 * -1 .. timeout
6105 * -2 .. error
6106 */
6107static int
6109 FILE *fp,
6110 SOCKET sock,
6111 SSL *ssl,
6112 const char *buf,
6113 int len,
6114 double timeout)
6115{
6116 uint64_t start = 0, now = 0, timeout_ns = 0;
6117 int n, err;
6118 unsigned ms_wait = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
6119
6120#if defined(_WIN32)
6121 typedef int len_t;
6122#else
6123 typedef size_t len_t;
6124#endif
6125
6126 if (timeout > 0) {
6127 now = mg_get_current_time_ns();
6128 start = now;
6129 timeout_ns = (uint64_t)(timeout * 1.0E9);
6130 }
6131
6132 if (ctx == NULL) {
6133 return -2;
6134 }
6135
6136#if defined(NO_SSL)
6137 if (ssl) {
6138 return -2;
6139 }
6140#endif
6141
6142 /* Try to read until it succeeds, fails, times out, or the server
6143 * shuts down. */
6144 for (;;) {
6145
6146#if !defined(NO_SSL)
6147 if (ssl != NULL) {
6148 n = SSL_write(ssl, buf, len);
6149 if (n <= 0) {
6150 err = SSL_get_error(ssl, n);
6151 if ((err == SSL_ERROR_SYSCALL) && (n == -1)) {
6152 err = ERRNO;
6153 } else if ((err == SSL_ERROR_WANT_READ)
6154 || (err == SSL_ERROR_WANT_WRITE)) {
6155 n = 0;
6156 } else {
6157 DEBUG_TRACE("SSL_write() failed, error %d", err);
6158 return -2;
6159 }
6160 } else {
6161 err = 0;
6162 }
6163 } else
6164#endif
6165 if (fp != NULL) {
6166 n = (int)fwrite(buf, 1, (size_t)len, fp);
6167 if (ferror(fp)) {
6168 n = -1;
6169 err = ERRNO;
6170 } else {
6171 err = 0;
6172 }
6173 } else {
6174 n = (int)send(sock, buf, (len_t)len, MSG_NOSIGNAL);
6175 err = (n < 0) ? ERRNO : 0;
6176#if defined(_WIN32)
6177 if (err == WSAEWOULDBLOCK) {
6178 err = 0;
6179 n = 0;
6180 }
6181#else
6182 if (err == EWOULDBLOCK) {
6183 err = 0;
6184 n = 0;
6185 }
6186#endif
6187 if (n < 0) {
6188 /* shutdown of the socket at client side */
6189 return -2;
6190 }
6191 }
6192
6193 if (ctx->stop_flag) {
6194 return -2;
6195 }
6196
6197 if ((n > 0) || ((n == 0) && (len == 0))) {
6198 /* some data has been read, or no data was requested */
6199 return n;
6200 }
6201 if (n < 0) {
6202 /* socket error - check errno */
6203 DEBUG_TRACE("send() failed, error %d", err);
6204
6205 /* TODO (mid): error handling depending on the error code.
6206 * These codes are different between Windows and Linux.
6207 * Currently there is no problem with failing send calls,
6208 * if there is a reproducible situation, it should be
6209 * investigated in detail.
6210 */
6211 return -2;
6212 }
6213
6214 /* Only in case n=0 (timeout), repeat calling the write function */
6215
6216 /* If send failed, wait before retry */
6217 if (fp != NULL) {
6218 /* For files, just wait a fixed time.
6219 * Maybe it helps, maybe not. */
6220 mg_sleep(5);
6221 } else {
6222 /* For sockets, wait for the socket using poll */
6223 struct pollfd pfd[1];
6224 int pollres;
6225
6226 pfd[0].fd = sock;
6227 pfd[0].events = POLLOUT;
6228 pollres = mg_poll(pfd, 1, (int)(ms_wait), &(ctx->stop_flag));
6229 if (ctx->stop_flag) {
6230 return -2;
6231 }
6232 if (pollres > 0) {
6233 continue;
6234 }
6235 }
6236
6237 if (timeout > 0) {
6238 now = mg_get_current_time_ns();
6239 if ((now - start) > timeout_ns) {
6240 /* Timeout */
6241 break;
6242 }
6243 }
6244 }
6245
6246 (void)err; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
6247 used */
6248
6249 return -1;
6250}
6251
6252
6253static int64_t
6255 FILE *fp,
6256 SOCKET sock,
6257 SSL *ssl,
6258 const char *buf,
6259 int64_t len)
6260{
6261 double timeout = -1.0;
6262 int64_t n, nwritten = 0;
6263
6264 if (ctx == NULL) {
6265 return -1;
6266 }
6267
6268 if (ctx->dd.config[REQUEST_TIMEOUT]) {
6269 timeout = atoi(ctx->dd.config[REQUEST_TIMEOUT]) / 1000.0;
6270 }
6271
6272 while ((len > 0) && (ctx->stop_flag == 0)) {
6273 n = push_inner(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout);
6274 if (n < 0) {
6275 if (nwritten == 0) {
6276 nwritten = n; /* Propagate the error */
6277 }
6278 break;
6279 } else if (n == 0) {
6280 break; /* No more data to write */
6281 } else {
6282 nwritten += n;
6283 len -= n;
6284 }
6285 }
6286
6287 return nwritten;
6288}
6289
6290
6291/* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
6292 * Return value:
6293 * >=0 .. number of bytes successfully read
6294 * -1 .. timeout
6295 * -2 .. error
6296 */
6297static int
6298pull_inner(FILE *fp,
6299 struct mg_connection *conn,
6300 char *buf,
6301 int len,
6302 double timeout)
6303{
6304 int nread, err = 0;
6305
6306#if defined(_WIN32)
6307 typedef int len_t;
6308#else
6309 typedef size_t len_t;
6310#endif
6311#if !defined(NO_SSL)
6312 int ssl_pending;
6313#endif
6314
6315 /* We need an additional wait loop around this, because in some cases
6316 * with TLSwe may get data from the socket but not from SSL_read.
6317 * In this case we need to repeat at least once.
6318 */
6319
6320 if (fp != NULL) {
6321#if !defined(_WIN32_WCE)
6322 /* Use read() instead of fread(), because if we're reading from the
6323 * CGI pipe, fread() may block until IO buffer is filled up. We
6324 * cannot afford to block and must pass all read bytes immediately
6325 * to the client. */
6326 nread = (int)read(fileno(fp), buf, (size_t)len);
6327#else
6328 /* WinCE does not support CGI pipes */
6329 nread = (int)fread(buf, 1, (size_t)len, fp);
6330#endif
6331 err = (nread < 0) ? ERRNO : 0;
6332 if ((nread == 0) && (len > 0)) {
6333 /* Should get data, but got EOL */
6334 return -2;
6335 }
6336
6337#if !defined(NO_SSL)
6338 } else if ((conn->ssl != NULL)
6339 && ((ssl_pending = SSL_pending(conn->ssl)) > 0)) {
6340 /* We already know there is no more data buffered in conn->buf
6341 * but there is more available in the SSL layer. So don't poll
6342 * conn->client.sock yet. */
6343 if (ssl_pending > len) {
6344 ssl_pending = len;
6345 }
6346 nread = SSL_read(conn->ssl, buf, ssl_pending);
6347 if (nread <= 0) {
6348 err = SSL_get_error(conn->ssl, nread);
6349 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
6350 err = ERRNO;
6351 } else if ((err == SSL_ERROR_WANT_READ)
6352 || (err == SSL_ERROR_WANT_WRITE)) {
6353 nread = 0;
6354 } else {
6355 DEBUG_TRACE("SSL_read() failed, error %d", err);
6356 return -1;
6357 }
6358 } else {
6359 err = 0;
6360 }
6361
6362 } else if (conn->ssl != NULL) {
6363
6364 struct pollfd pfd[1];
6365 int pollres;
6366
6367 pfd[0].fd = conn->client.sock;
6368 pfd[0].events = POLLIN;
6369 pollres = mg_poll(pfd,
6370 1,
6371 (int)(timeout * 1000.0),
6372 &(conn->phys_ctx->stop_flag));
6373 if (conn->phys_ctx->stop_flag) {
6374 return -2;
6375 }
6376 if (pollres > 0) {
6377 nread = SSL_read(conn->ssl, buf, len);
6378 if (nread <= 0) {
6379 err = SSL_get_error(conn->ssl, nread);
6380 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
6381 err = ERRNO;
6382 } else if ((err == SSL_ERROR_WANT_READ)
6383 || (err == SSL_ERROR_WANT_WRITE)) {
6384 nread = 0;
6385 } else {
6386 DEBUG_TRACE("SSL_read() failed, error %d", err);
6387 return -2;
6388 }
6389 } else {
6390 err = 0;
6391 }
6392
6393 } else if (pollres < 0) {
6394 /* Error */
6395 return -2;
6396 } else {
6397 /* pollres = 0 means timeout */
6398 nread = 0;
6399 }
6400#endif
6401
6402 } else {
6403 struct pollfd pfd[1];
6404 int pollres;
6405
6406 pfd[0].fd = conn->client.sock;
6407 pfd[0].events = POLLIN;
6408 pollres = mg_poll(pfd,
6409 1,
6410 (int)(timeout * 1000.0),
6411 &(conn->phys_ctx->stop_flag));
6412 if (conn->phys_ctx->stop_flag) {
6413 return -2;
6414 }
6415 if (pollres > 0) {
6416 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
6417 err = (nread < 0) ? ERRNO : 0;
6418 if (nread <= 0) {
6419 /* shutdown of the socket at client side */
6420 return -2;
6421 }
6422 } else if (pollres < 0) {
6423 /* error callint poll */
6424 return -2;
6425 } else {
6426 /* pollres = 0 means timeout */
6427 nread = 0;
6428 }
6429 }
6430
6431 if (conn->phys_ctx->stop_flag) {
6432 return -2;
6433 }
6434
6435 if ((nread > 0) || ((nread == 0) && (len == 0))) {
6436 /* some data has been read, or no data was requested */
6437 return nread;
6438 }
6439
6440 if (nread < 0) {
6441/* socket error - check errno */
6442#if defined(_WIN32)
6443 if (err == WSAEWOULDBLOCK) {
6444 /* TODO (low): check if this is still required */
6445 /* standard case if called from close_socket_gracefully */
6446 return -2;
6447 } else if (err == WSAETIMEDOUT) {
6448 /* TODO (low): check if this is still required */
6449 /* timeout is handled by the while loop */
6450 return 0;
6451 } else if (err == WSAECONNABORTED) {
6452 /* See https://www.chilkatsoft.com/p/p_299.asp */
6453 return -2;
6454 } else {
6455 DEBUG_TRACE("recv() failed, error %d", err);
6456 return -2;
6457 }
6458#else
6459 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
6460 * if the timeout is reached and if the socket was set to non-
6461 * blocking in close_socket_gracefully, so we can not distinguish
6462 * here. We have to wait for the timeout in both cases for now.
6463 */
6464 if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == EINTR)) {
6465 /* TODO (low): check if this is still required */
6466 /* EAGAIN/EWOULDBLOCK:
6467 * standard case if called from close_socket_gracefully
6468 * => should return -1 */
6469 /* or timeout occurred
6470 * => the code must stay in the while loop */
6471
6472 /* EINTR can be generated on a socket with a timeout set even
6473 * when SA_RESTART is effective for all relevant signals
6474 * (see signal(7)).
6475 * => stay in the while loop */
6476 } else {
6477 DEBUG_TRACE("recv() failed, error %d", err);
6478 return -2;
6479 }
6480#endif
6481 }
6482
6483 /* Timeout occurred, but no data available. */
6484 return -1;
6485}
6486
6487
6488static int
6489pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
6490{
6491 int n, nread = 0;
6492 double timeout = -1.0;
6493 uint64_t start_time = 0, now = 0, timeout_ns = 0;
6494
6495 if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
6496 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
6497 }
6498 if (timeout >= 0.0) {
6499 start_time = mg_get_current_time_ns();
6500 timeout_ns = (uint64_t)(timeout * 1.0E9);
6501 }
6502
6503 while ((len > 0) && (conn->phys_ctx->stop_flag == 0)) {
6504 n = pull_inner(fp, conn, buf + nread, len, timeout);
6505 if (n == -2) {
6506 if (nread == 0) {
6507 nread = -1; /* Propagate the error */
6508 }
6509 break;
6510 } else if (n == -1) {
6511 /* timeout */
6512 if (timeout >= 0.0) {
6513 now = mg_get_current_time_ns();
6514 if ((now - start_time) <= timeout_ns) {
6515 continue;
6516 }
6517 }
6518 break;
6519 } else if (n == 0) {
6520 break; /* No more data to read */
6521 } else {
6522 conn->consumed_content += n;
6523 nread += n;
6524 len -= n;
6525 }
6526 }
6527
6528 return nread;
6529}
6530
6531
6532static void
6534{
6535 char buf[MG_BUF_LEN];
6536 size_t to_read;
6537 int nread;
6538
6539 if (conn == NULL) {
6540 return;
6541 }
6542
6543 to_read = sizeof(buf);
6544
6545 if (conn->is_chunked) {
6546 /* Chunked encoding: 3=chunk read completely
6547 * completely */
6548 while (conn->is_chunked != 3) {
6549 nread = mg_read(conn, buf, to_read);
6550 if (nread <= 0) {
6551 break;
6552 }
6553 }
6554
6555 } else {
6556 /* Not chunked: content length is known */
6557 while (conn->consumed_content < conn->content_len) {
6558 if (to_read
6559 > (size_t)(conn->content_len - conn->consumed_content)) {
6560 to_read = (size_t)(conn->content_len - conn->consumed_content);
6561 }
6562
6563 nread = mg_read(conn, buf, to_read);
6564 if (nread <= 0) {
6565 break;
6566 }
6567 }
6568 }
6569}
6570
6571
6572static int
6573mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
6574{
6575 int64_t n, buffered_len, nread;
6576 int64_t len64 =
6577 (int64_t)((len > INT_MAX) ? INT_MAX : len); /* since the return value is
6578 * int, we may not read more
6579 * bytes */
6580 const char *body;
6581
6582 if (conn == NULL) {
6583 return 0;
6584 }
6585
6586 /* If Content-Length is not set for a request with body data
6587 * (e.g., a PUT or POST request), we do not know in advance
6588 * how much data should be read. */
6589 if (conn->consumed_content == 0) {
6590 if (conn->is_chunked == 1) {
6591 conn->content_len = len64;
6592 conn->is_chunked = 2;
6593 } else if (conn->content_len == -1) {
6594 /* The body data is completed when the connection
6595 * is closed. */
6596 conn->content_len = INT64_MAX;
6597 conn->must_close = 1;
6598 }
6599 }
6600
6601 nread = 0;
6602 if (conn->consumed_content < conn->content_len) {
6603 /* Adjust number of bytes to read. */
6604 int64_t left_to_read = conn->content_len - conn->consumed_content;
6605 if (left_to_read < len64) {
6606 /* Do not read more than the total content length of the
6607 * request.
6608 */
6609 len64 = left_to_read;
6610 }
6611
6612 /* Return buffered data */
6613 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
6614 - conn->consumed_content;
6615 if (buffered_len > 0) {
6616 if (len64 < buffered_len) {
6617 buffered_len = len64;
6618 }
6619 body = conn->buf + conn->request_len + conn->consumed_content;
6620 memcpy(buf, body, (size_t)buffered_len);
6621 len64 -= buffered_len;
6622 conn->consumed_content += buffered_len;
6623 nread += buffered_len;
6624 buf = (char *)buf + buffered_len;
6625 }
6626
6627 /* We have returned all buffered data. Read new data from the remote
6628 * socket.
6629 */
6630 if ((n = pull_all(NULL, conn, (char *)buf, (int)len64)) >= 0) {
6631 nread += n;
6632 } else {
6633 nread = ((nread > 0) ? nread : n);
6634 }
6635 }
6636 return (int)nread;
6637}
6638
6639
6640static char
6642{
6643 char c;
6644 if (conn == NULL) {
6645 return 0;
6646 }
6647 if (mg_read_inner(conn, &c, 1) <= 0) {
6648 return (char)0;
6649 }
6650 return c;
6651}
6652
6653
6654int
6655mg_read(struct mg_connection *conn, void *buf, size_t len)
6656{
6657 if (len > INT_MAX) {
6658 len = INT_MAX;
6659 }
6660
6661 if (conn == NULL) {
6662 return 0;
6663 }
6664
6665 if (conn->is_chunked) {
6666 size_t all_read = 0;
6667
6668 while (len > 0) {
6669 if (conn->is_chunked == 3) {
6670 /* No more data left to read */
6671 return 0;
6672 }
6673
6674 if (conn->chunk_remainder) {
6675 /* copy from the remainder of the last received chunk */
6676 long read_ret;
6677 size_t read_now =
6678 ((conn->chunk_remainder > len) ? (len)
6679 : (conn->chunk_remainder));
6680
6681 conn->content_len += (int)read_now;
6682 read_ret =
6683 mg_read_inner(conn, (char *)buf + all_read, read_now);
6684
6685 if (read_ret < 1) {
6686 /* read error */
6687 return -1;
6688 }
6689
6690 all_read += (size_t)read_ret;
6691 conn->chunk_remainder -= (size_t)read_ret;
6692 len -= (size_t)read_ret;
6693
6694 if (conn->chunk_remainder == 0) {
6695 /* Add data bytes in the current chunk have been read,
6696 * so we are expecting \r\n now. */
6697 char x1, x2;
6698 conn->content_len += 2;
6699 x1 = mg_getc(conn);
6700 x2 = mg_getc(conn);
6701 if ((x1 != '\r') || (x2 != '\n')) {
6702 /* Protocol violation */
6703 return -1;
6704 }
6705 }
6706
6707 } else {
6708 /* fetch a new chunk */
6709 int i = 0;
6710 char lenbuf[64];
6711 char *end = 0;
6712 unsigned long chunkSize = 0;
6713
6714 for (i = 0; i < ((int)sizeof(lenbuf) - 1); i++) {
6715 conn->content_len++;
6716 lenbuf[i] = mg_getc(conn);
6717 if ((i > 0) && (lenbuf[i] == '\r')
6718 && (lenbuf[i - 1] != '\r')) {
6719 continue;
6720 }
6721 if ((i > 1) && (lenbuf[i] == '\n')
6722 && (lenbuf[i - 1] == '\r')) {
6723 lenbuf[i + 1] = 0;
6724 chunkSize = strtoul(lenbuf, &end, 16);
6725 if (chunkSize == 0) {
6726 /* regular end of content */
6727 conn->is_chunked = 3;
6728 }
6729 break;
6730 }
6731 if (!isxdigit(lenbuf[i])) {
6732 /* illegal character for chunk length */
6733 return -1;
6734 }
6735 }
6736 if ((end == NULL) || (*end != '\r')) {
6737 /* chunksize not set correctly */
6738 return -1;
6739 }
6740 if (chunkSize == 0) {
6741 break;
6742 }
6743
6744 conn->chunk_remainder = chunkSize;
6745 }
6746 }
6747
6748 return (int)all_read;
6749 }
6750 return mg_read_inner(conn, buf, len);
6751}
6752
6753
6754int
6755mg_write(struct mg_connection *conn, const void *buf, size_t len)
6756{
6757 time_t now;
6758 int64_t n, total, allowed;
6759
6760 if (conn == NULL) {
6761 return 0;
6762 }
6763
6764 if (conn->throttle > 0) {
6765 if ((now = time(NULL)) != conn->last_throttle_time) {
6766 conn->last_throttle_time = now;
6767 conn->last_throttle_bytes = 0;
6768 }
6769 allowed = conn->throttle - conn->last_throttle_bytes;
6770 if (allowed > (int64_t)len) {
6771 allowed = (int64_t)len;
6772 }
6773 if ((total = push_all(conn->phys_ctx,
6774 NULL,
6775 conn->client.sock,
6776 conn->ssl,
6777 (const char *)buf,
6778 (int64_t)allowed))
6779 == allowed) {
6780 buf = (const char *)buf + total;
6781 conn->last_throttle_bytes += total;
6782 while ((total < (int64_t)len) && (conn->phys_ctx->stop_flag == 0)) {
6783 allowed = (conn->throttle > ((int64_t)len - total))
6784 ? (int64_t)len - total
6785 : conn->throttle;
6786 if ((n = push_all(conn->phys_ctx,
6787 NULL,
6788 conn->client.sock,
6789 conn->ssl,
6790 (const char *)buf,
6791 (int64_t)allowed))
6792 != allowed) {
6793 break;
6794 }
6795 sleep(1);
6796 conn->last_throttle_bytes = allowed;
6797 conn->last_throttle_time = time(NULL);
6798 buf = (const char *)buf + n;
6799 total += n;
6800 }
6801 }
6802 } else {
6803 total = push_all(conn->phys_ctx,
6804 NULL,
6805 conn->client.sock,
6806 conn->ssl,
6807 (const char *)buf,
6808 (int64_t)len);
6809 }
6810 if (total > 0) {
6811 conn->num_bytes_sent += total;
6812 }
6813 return (int)total;
6814}
6815
6816
6817/* Send a chunk, if "Transfer-Encoding: chunked" is used */
6818int
6820 const char *chunk,
6821 unsigned int chunk_len)
6822{
6823 char lenbuf[16];
6824 size_t lenbuf_len;
6825 int ret;
6826 int t;
6827
6828 /* First store the length information in a text buffer. */
6829 sprintf(lenbuf, "%x\r\n", chunk_len);
6830 lenbuf_len = strlen(lenbuf);
6831
6832 /* Then send length information, chunk and terminating \r\n. */
6833 ret = mg_write(conn, lenbuf, lenbuf_len);
6834 if (ret != (int)lenbuf_len) {
6835 return -1;
6836 }
6837 t = ret;
6838
6839 ret = mg_write(conn, chunk, chunk_len);
6840 if (ret != (int)chunk_len) {
6841 return -1;
6842 }
6843 t += ret;
6844
6845 ret = mg_write(conn, "\r\n", 2);
6846 if (ret != 2) {
6847 return -1;
6848 }
6849 t += ret;
6850
6851 return t;
6852}
6853
6854
6855#if defined(GCC_DIAGNOSTIC)
6856/* This block forwards format strings to printf implementations,
6857 * so we need to disable the format-nonliteral warning. */
6858#pragma GCC diagnostic push
6859#pragma GCC diagnostic ignored "-Wformat-nonliteral"
6860#endif
6861
6862
6863/* Alternative alloc_vprintf() for non-compliant C runtimes */
6864static int
6865alloc_vprintf2(char **buf, const char *fmt, va_list ap)
6866{
6867 va_list ap_copy;
6868 size_t size = MG_BUF_LEN / 4;
6869 int len = -1;
6870
6871 *buf = NULL;
6872 while (len < 0) {
6873 if (*buf) {
6874 mg_free(*buf);
6875 }
6876
6877 size *= 4;
6878 *buf = (char *)mg_malloc(size);
6879 if (!*buf) {
6880 break;
6881 }
6882
6883 va_copy(ap_copy, ap);
6884 len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy);
6885 va_end(ap_copy);
6886 (*buf)[size - 1] = 0;
6887 }
6888
6889 return len;
6890}
6891
6892
6893/* Print message to buffer. If buffer is large enough to hold the message,
6894 * return buffer. If buffer is to small, allocate large enough buffer on
6895 * heap,
6896 * and return allocated buffer. */
6897static int
6898alloc_vprintf(char **out_buf,
6899 char *prealloc_buf,
6900 size_t prealloc_size,
6901 const char *fmt,
6902 va_list ap)
6903{
6904 va_list ap_copy;
6905 int len;
6906
6907 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
6908 * buffer is too small. Also, older versions of msvcrt.dll do not have
6909 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
6910 * Therefore, we make two passes: on first pass, get required message
6911 * length.
6912 * On second pass, actually print the message. */
6913 va_copy(ap_copy, ap);
6914 len = vsnprintf_impl(NULL, 0, fmt, ap_copy);
6915 va_end(ap_copy);
6916
6917 if (len < 0) {
6918 /* C runtime is not standard compliant, vsnprintf() returned -1.
6919 * Switch to alternative code path that uses incremental
6920 * allocations.
6921 */
6922 va_copy(ap_copy, ap);
6923 len = alloc_vprintf2(out_buf, fmt, ap_copy);
6924 va_end(ap_copy);
6925
6926 } else if ((size_t)(len) >= prealloc_size) {
6927 /* The pre-allocated buffer not large enough. */
6928 /* Allocate a new buffer. */
6929 *out_buf = (char *)mg_malloc((size_t)(len) + 1);
6930 if (!*out_buf) {
6931 /* Allocation failed. Return -1 as "out of memory" error. */
6932 return -1;
6933 }
6934 /* Buffer allocation successful. Store the string there. */
6935 va_copy(ap_copy, ap);
6937 vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy));
6938 va_end(ap_copy);
6939
6940 } else {
6941 /* The pre-allocated buffer is large enough.
6942 * Use it to store the string and return the address. */
6943 va_copy(ap_copy, ap);
6945 vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy));
6946 va_end(ap_copy);
6947 *out_buf = prealloc_buf;
6948 }
6949
6950 return len;
6951}
6952
6953
6954#if defined(GCC_DIAGNOSTIC)
6955/* Enable format-nonliteral warning again. */
6956#pragma GCC diagnostic pop
6957#endif
6958
6959
6960static int
6961mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
6962{
6963 char mem[MG_BUF_LEN];
6964 char *buf = NULL;
6965 int len;
6966
6967 if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) {
6968 len = mg_write(conn, buf, (size_t)len);
6969 }
6970 if ((buf != mem) && (buf != NULL)) {
6971 mg_free(buf);
6972 }
6973
6974 return len;
6975}
6976
6977
6978int
6979mg_printf(struct mg_connection *conn, const char *fmt, ...)
6980{
6981 va_list ap;
6982 int result;
6983
6984 va_start(ap, fmt);
6985 result = mg_vprintf(conn, fmt, ap);
6986 va_end(ap);
6987
6988 return result;
6989}
6990
6991
6992int
6993mg_url_decode(const char *src,
6994 int src_len,
6995 char *dst,
6996 int dst_len,
6997 int is_form_url_encoded)
6998{
6999 int i, j, a, b;
7000#define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
7001
7002 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
7003 if ((i < src_len - 2) && (src[i] == '%')
7004 && isxdigit(*(const unsigned char *)(src + i + 1))
7005 && isxdigit(*(const unsigned char *)(src + i + 2))) {
7006 a = tolower(*(const unsigned char *)(src + i + 1));
7007 b = tolower(*(const unsigned char *)(src + i + 2));
7008 dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
7009 i += 2;
7010 } else if (is_form_url_encoded && (src[i] == '+')) {
7011 dst[j] = ' ';
7012 } else {
7013 dst[j] = src[i];
7014 }
7015 }
7016
7017 dst[j] = '\0'; /* Null-terminate the destination */
7018
7019 return (i >= src_len) ? j : -1;
7020}
7021
7022
7023int
7024mg_get_var(const char *data,
7025 size_t data_len,
7026 const char *name,
7027 char *dst,
7028 size_t dst_len)
7029{
7030 return mg_get_var2(data, data_len, name, dst, dst_len, 0);
7031}
7032
7033
7034int
7035mg_get_var2(const char *data,
7036 size_t data_len,
7037 const char *name,
7038 char *dst,
7039 size_t dst_len,
7040 size_t occurrence)
7041{
7042 const char *p, *e, *s;
7043 size_t name_len;
7044 int len;
7045
7046 if ((dst == NULL) || (dst_len == 0)) {
7047 len = -2;
7048 } else if ((data == NULL) || (name == NULL) || (data_len == 0)) {
7049 len = -1;
7050 dst[0] = '\0';
7051 } else {
7052 name_len = strlen(name);
7053 e = data + data_len;
7054 len = -1;
7055 dst[0] = '\0';
7056
7057 /* data is "var1=val1&var2=val2...". Find variable first */
7058 for (p = data; p + name_len < e; p++) {
7059 if (((p == data) || (p[-1] == '&')) && (p[name_len] == '=')
7060 && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
7061 /* Point p to variable value */
7062 p += name_len + 1;
7063
7064 /* Point s to the end of the value */
7065 s = (const char *)memchr(p, '&', (size_t)(e - p));
7066 if (s == NULL) {
7067 s = e;
7068 }
7069 DEBUG_ASSERT(s >= p);
7070 if (s < p) {
7071 return -3;
7072 }
7073
7074 /* Decode variable into destination buffer */
7075 len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
7076
7077 /* Redirect error code from -1 to -2 (destination buffer too
7078 * small). */
7079 if (len == -1) {
7080 len = -2;
7081 }
7082 break;
7083 }
7084 }
7085 }
7086
7087 return len;
7088}
7089
7090
7091/* HCP24: some changes to compare hole var_name */
7092int
7093mg_get_cookie(const char *cookie_header,
7094 const char *var_name,
7095 char *dst,
7096 size_t dst_size)
7097{
7098 const char *s, *p, *end;
7099 int name_len, len = -1;
7100
7101 if ((dst == NULL) || (dst_size == 0)) {
7102 return -2;
7103 }
7104
7105 dst[0] = '\0';
7106 if ((var_name == NULL) || ((s = cookie_header) == NULL)) {
7107 return -1;
7108 }
7109
7110 name_len = (int)strlen(var_name);
7111 end = s + strlen(s);
7112 for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
7113 if (s[name_len] == '=') {
7114 /* HCP24: now check is it a substring or a full cookie name */
7115 if ((s == cookie_header) || (s[-1] == ' ')) {
7116 s += name_len + 1;
7117 if ((p = strchr(s, ' ')) == NULL) {
7118 p = end;
7119 }
7120 if (p[-1] == ';') {
7121 p--;
7122 }
7123 if ((*s == '"') && (p[-1] == '"') && (p > s + 1)) {
7124 s++;
7125 p--;
7126 }
7127 if ((size_t)(p - s) < dst_size) {
7128 len = (int)(p - s);
7129 mg_strlcpy(dst, s, (size_t)len + 1);
7130 } else {
7131 len = -3;
7132 }
7133 break;
7134 }
7135 }
7136 }
7137 return len;
7138}
7139
7140
7141#if defined(USE_WEBSOCKET) || defined(USE_LUA)
7142static void
7143base64_encode(const unsigned char *src, int src_len, char *dst)
7144{
7145 static const char *b64 =
7146 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7147 int i, j, a, b, c;
7148
7149 for (i = j = 0; i < src_len; i += 3) {
7150 a = src[i];
7151 b = ((i + 1) >= src_len) ? 0 : src[i + 1];
7152 c = ((i + 2) >= src_len) ? 0 : src[i + 2];
7153
7154 dst[j++] = b64[a >> 2];
7155 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
7156 if (i + 1 < src_len) {
7157 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
7158 }
7159 if (i + 2 < src_len) {
7160 dst[j++] = b64[c & 63];
7161 }
7162 }
7163 while (j % 4 != 0) {
7164 dst[j++] = '=';
7165 }
7166 dst[j++] = '\0';
7167}
7168#endif
7169
7170
7171#if defined(USE_LUA)
7172static unsigned char
7173b64reverse(char letter)
7174{
7175 if ((letter >= 'A') && (letter <= 'Z')) {
7176 return letter - 'A';
7177 }
7178 if ((letter >= 'a') && (letter <= 'z')) {
7179 return letter - 'a' + 26;
7180 }
7181 if ((letter >= '0') && (letter <= '9')) {
7182 return letter - '0' + 52;
7183 }
7184 if (letter == '+') {
7185 return 62;
7186 }
7187 if (letter == '/') {
7188 return 63;
7189 }
7190 if (letter == '=') {
7191 return 255; /* normal end */
7192 }
7193 return 254; /* error */
7194}
7195
7196
7197static int
7198base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
7199{
7200 int i;
7201 unsigned char a, b, c, d;
7202
7203 *dst_len = 0;
7204
7205 for (i = 0; i < src_len; i += 4) {
7206 a = b64reverse(src[i]);
7207 if (a >= 254) {
7208 return i;
7209 }
7210
7211 b = b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]);
7212 if (b >= 254) {
7213 return i + 1;
7214 }
7215
7216 c = b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]);
7217 if (c == 254) {
7218 return i + 2;
7219 }
7220
7221 d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
7222 if (d == 254) {
7223 return i + 3;
7224 }
7225
7226 dst[(*dst_len)++] = (a << 2) + (b >> 4);
7227 if (c != 255) {
7228 dst[(*dst_len)++] = (b << 4) + (c >> 2);
7229 if (d != 255) {
7230 dst[(*dst_len)++] = (c << 6) + d;
7231 }
7232 }
7233 }
7234 return -1;
7235}
7236#endif
7237
7238
7239static int
7241{
7242 if (conn) {
7243 const char *s = conn->request_info.request_method;
7244 return (s != NULL)
7245 && (!strcmp(s, "PUT") || !strcmp(s, "DELETE")
7246 || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH"));
7247 }
7248 return 0;
7249}
7250
7251
7252#if !defined(NO_FILES)
7253static int
7255 struct mg_connection *conn, /* in: request (must be valid) */
7256 const char *filename /* in: filename (must be valid) */
7257)
7258{
7259#if !defined(NO_CGI)
7261 strlen(conn->dom_ctx->config[CGI_EXTENSIONS]),
7262 filename)
7263 > 0) {
7264 return 1;
7265 }
7266#endif
7267#if defined(USE_LUA)
7268 if (match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
7269 strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
7270 filename)
7271 > 0) {
7272 return 1;
7273 }
7274#endif
7275#if defined(USE_DUKTAPE)
7276 if (match_prefix(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
7277 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
7278 filename)
7279 > 0) {
7280 return 1;
7281 }
7282#endif
7283 /* filename and conn could be unused, if all preocessor conditions
7284 * are false (no script language supported). */
7285 (void)filename;
7286 (void)conn;
7287
7288 return 0;
7289}
7290
7291
7292/* For given directory path, substitute it to valid index file.
7293 * Return 1 if index file has been found, 0 if not found.
7294 * If the file is found, it's stats is returned in stp. */
7295static int
7297 char *path,
7298 size_t path_len,
7299 struct mg_file_stat *filestat)
7300{
7301 const char *list = conn->dom_ctx->config[INDEX_FILES];
7302 struct vec filename_vec;
7303 size_t n = strlen(path);
7304 int found = 0;
7305
7306 /* The 'path' given to us points to the directory. Remove all trailing
7307 * directory separator characters from the end of the path, and
7308 * then append single directory separator character. */
7309 while ((n > 0) && (path[n - 1] == '/')) {
7310 n--;
7311 }
7312 path[n] = '/';
7313
7314 /* Traverse index files list. For each entry, append it to the given
7315 * path and see if the file exists. If it exists, break the loop */
7316 while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
7317 /* Ignore too long entries that may overflow path buffer */
7318 if ((filename_vec.len + 1) > (path_len - (n + 1))) {
7319 continue;
7320 }
7321
7322 /* Prepare full path to the index file */
7323 mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
7324
7325 /* Does it exist? */
7326 if (mg_stat(conn, path, filestat)) {
7327 /* Yes it does, break the loop */
7328 found = 1;
7329 break;
7330 }
7331 }
7332
7333 /* If no index file exists, restore directory path */
7334 if (!found) {
7335 path[n] = '\0';
7336 }
7337
7338 return found;
7339}
7340#endif
7341
7342
7343static void
7344interpret_uri(struct mg_connection *conn, /* in/out: request (must be valid) */
7345 char *filename, /* out: filename */
7346 size_t filename_buf_len, /* in: size of filename buffer */
7347 struct mg_file_stat *filestat, /* out: file status structure */
7348 int *is_found, /* out: file found (directly) */
7349 int *is_script_resource, /* out: handled by a script? */
7350 int *is_websocket_request, /* out: websocket connetion? */
7351 int *is_put_or_delete_request /* out: put/delete a file? */
7352)
7353{
7354 char const *accept_encoding;
7355
7356#if !defined(NO_FILES)
7357 const char *uri = conn->request_info.local_uri;
7358 const char *root = conn->dom_ctx->config[DOCUMENT_ROOT];
7359 const char *rewrite;
7360 struct vec a, b;
7361 ptrdiff_t match_len;
7362 char gz_path[PATH_MAX];
7363 int truncated;
7364#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7365 char *tmp_str;
7366 size_t tmp_str_len, sep_pos;
7367 int allow_substitute_script_subresources;
7368#endif
7369#else
7370 (void)filename_buf_len; /* unused if NO_FILES is defined */
7371#endif
7372
7373 /* Step 1: Set all initially unknown outputs to zero */
7374 memset(filestat, 0, sizeof(*filestat));
7375 *filename = 0;
7376 *is_found = 0;
7377 *is_script_resource = 0;
7378
7379 /* Step 2: Check if the request attempts to modify the file system */
7380 *is_put_or_delete_request = is_put_or_delete_method(conn);
7381
7382/* Step 3: Check if it is a websocket request, and modify the document
7383 * root if required */
7384#if defined(USE_WEBSOCKET)
7385 *is_websocket_request = is_websocket_protocol(conn);
7386#if !defined(NO_FILES)
7387 if (*is_websocket_request && conn->dom_ctx->config[WEBSOCKET_ROOT]) {
7388 root = conn->dom_ctx->config[WEBSOCKET_ROOT];
7389 }
7390#endif /* !NO_FILES */
7391#else /* USE_WEBSOCKET */
7392 *is_websocket_request = 0;
7393#endif /* USE_WEBSOCKET */
7394
7395 /* Step 4: Check if gzip encoded response is allowed */
7396 conn->accept_gzip = 0;
7397 if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
7398 if (strstr(accept_encoding, "gzip") != NULL) {
7399 conn->accept_gzip = 1;
7400 }
7401 }
7402
7403#if !defined(NO_FILES)
7404 /* Step 5: If there is no root directory, don't look for files. */
7405 /* Note that root == NULL is a regular use case here. This occurs,
7406 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
7407 * config is not required. */
7408 if (root == NULL) {
7409 /* all file related outputs have already been set to 0, just return
7410 */
7411 return;
7412 }
7413
7414 /* Step 6: Determine the local file path from the root path and the
7415 * request uri. */
7416 /* Using filename_buf_len - 1 because memmove() for PATH_INFO may shift
7417 * part of the path one byte on the right. */
7419 conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
7420
7421 if (truncated) {
7422 goto interpret_cleanup;
7423 }
7424
7425 /* Step 7: URI rewriting */
7426 rewrite = conn->dom_ctx->config[URL_REWRITE_PATTERN];
7427 while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
7428 if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
7429 mg_snprintf(conn,
7430 &truncated,
7431 filename,
7432 filename_buf_len - 1,
7433 "%.*s%s",
7434 (int)b.len,
7435 b.ptr,
7436 uri + match_len);
7437 break;
7438 }
7439 }
7440
7441 if (truncated) {
7442 goto interpret_cleanup;
7443 }
7444
7445 /* Step 8: Check if the file exists at the server */
7446 /* Local file path and name, corresponding to requested URI
7447 * is now stored in "filename" variable. */
7448 if (mg_stat(conn, filename, filestat)) {
7449 int uri_len = (int)strlen(uri);
7450 int is_uri_end_slash = (uri_len > 0) && (uri[uri_len - 1] == '/');
7451
7452 /* 8.1: File exists. */
7453 *is_found = 1;
7454
7455 /* 8.2: Check if it is a script type. */
7456 if (extention_matches_script(conn, filename)) {
7457 /* The request addresses a CGI resource, Lua script or
7458 * server-side javascript.
7459 * The URI corresponds to the script itself (like
7460 * /path/script.cgi), and there is no additional resource
7461 * path (like /path/script.cgi/something).
7462 * Requests that modify (replace or delete) a resource, like
7463 * PUT and DELETE requests, should replace/delete the script
7464 * file.
7465 * Requests that read or write from/to a resource, like GET and
7466 * POST requests, should call the script and return the
7467 * generated response. */
7468 *is_script_resource = (!*is_put_or_delete_request);
7469 }
7470
7471 /* 8.3: If the request target is a directory, there could be
7472 * a substitute file (index.html, index.cgi, ...). */
7473 if (filestat->is_directory && is_uri_end_slash) {
7474 /* Use a local copy here, since substitute_index_file will
7475 * change the content of the file status */
7476 struct mg_file_stat tmp_filestat;
7477 memset(&tmp_filestat, 0, sizeof(tmp_filestat));
7478
7480 conn, filename, filename_buf_len, &tmp_filestat)) {
7481
7482 /* Substitute file found. Copy stat to the output, then
7483 * check if the file is a script file */
7484 *filestat = tmp_filestat;
7485
7486 if (extention_matches_script(conn, filename)) {
7487 /* Substitute file is a script file */
7488 *is_script_resource = 1;
7489 } else {
7490 /* Substitute file is a regular file */
7491 *is_script_resource = 0;
7492 *is_found = (mg_stat(conn, filename, filestat) ? 1 : 0);
7493 }
7494 }
7495 /* If there is no substitute file, the server could return
7496 * a directory listing in a later step */
7497 }
7498 return;
7499 }
7500
7501 /* Step 9: Check for zipped files: */
7502 /* If we can't find the actual file, look for the file
7503 * with the same name but a .gz extension. If we find it,
7504 * use that and set the gzipped flag in the file struct
7505 * to indicate that the response need to have the content-
7506 * encoding: gzip header.
7507 * We can only do this if the browser declares support. */
7508 if (conn->accept_gzip) {
7510 conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename);
7511
7512 if (truncated) {
7513 goto interpret_cleanup;
7514 }
7515
7516 if (mg_stat(conn, gz_path, filestat)) {
7517 if (filestat) {
7518 filestat->is_gzipped = 1;
7519 *is_found = 1;
7520 }
7521 /* Currently gz files can not be scripts. */
7522 return;
7523 }
7524 }
7525
7526#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
7527 /* Step 10: Script resources may handle sub-resources */
7528 /* Support PATH_INFO for CGI scripts. */
7529 tmp_str_len = strlen(filename);
7530 tmp_str = (char *)mg_malloc_ctx(tmp_str_len + PATH_MAX + 1, conn->phys_ctx);
7531 if (!tmp_str) {
7532 /* Out of memory */
7533 goto interpret_cleanup;
7534 }
7535 memcpy(tmp_str, filename, tmp_str_len + 1);
7536
7537 /* Check config, if index scripts may have sub-resources */
7538 allow_substitute_script_subresources =
7540 "yes");
7541
7542 sep_pos = tmp_str_len;
7543 while (sep_pos > 0) {
7544 sep_pos--;
7545 if (tmp_str[sep_pos] == '/') {
7546 int is_script = 0, does_exist = 0;
7547
7548 tmp_str[sep_pos] = 0;
7549 if (tmp_str[0]) {
7550 is_script = extention_matches_script(conn, tmp_str);
7551 does_exist = mg_stat(conn, tmp_str, filestat);
7552 }
7553
7554 if (does_exist && is_script) {
7555 filename[sep_pos] = 0;
7556 memmove(filename + sep_pos + 2,
7557 filename + sep_pos + 1,
7558 strlen(filename + sep_pos + 1) + 1);
7559 conn->path_info = filename + sep_pos + 1;
7560 filename[sep_pos + 1] = '/';
7561 *is_script_resource = 1;
7562 *is_found = 1;
7563 break;
7564 }
7565
7566 if (allow_substitute_script_subresources) {
7568 conn, tmp_str, tmp_str_len + PATH_MAX, filestat)) {
7569
7570 /* some intermediate directory has an index file */
7571 if (extention_matches_script(conn, tmp_str)) {
7572
7573 char *tmp_str2;
7574
7575 DEBUG_TRACE("Substitute script %s serving path %s",
7576 tmp_str,
7577 filename);
7578
7579 /* this index file is a script */
7580 tmp_str2 = mg_strdup_ctx(filename + sep_pos + 1,
7581 conn->phys_ctx);
7582 mg_snprintf(conn,
7583 &truncated,
7584 filename,
7585 filename_buf_len,
7586 "%s//%s",
7587 tmp_str,
7588 tmp_str2);
7589 mg_free(tmp_str2);
7590
7591 if (truncated) {
7592 mg_free(tmp_str);
7593 goto interpret_cleanup;
7594 }
7595 sep_pos = strlen(tmp_str);
7596 filename[sep_pos] = 0;
7597 conn->path_info = filename + sep_pos + 1;
7598 *is_script_resource = 1;
7599 *is_found = 1;
7600 break;
7601
7602 } else {
7603
7604 DEBUG_TRACE("Substitute file %s serving path %s",
7605 tmp_str,
7606 filename);
7607
7608 /* non-script files will not have sub-resources */
7609 filename[sep_pos] = 0;
7610 conn->path_info = 0;
7611 *is_script_resource = 0;
7612 *is_found = 0;
7613 break;
7614 }
7615 }
7616 }
7617
7618 tmp_str[sep_pos] = '/';
7619 }
7620 }
7621
7622 mg_free(tmp_str);
7623
7624#endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
7625#endif /* !defined(NO_FILES) */
7626 return;
7627
7628#if !defined(NO_FILES)
7629/* Reset all outputs */
7630interpret_cleanup:
7631 memset(filestat, 0, sizeof(*filestat));
7632 *filename = 0;
7633 *is_found = 0;
7634 *is_script_resource = 0;
7635 *is_websocket_request = 0;
7636 *is_put_or_delete_request = 0;
7637#endif /* !defined(NO_FILES) */
7638}
7639
7640
7641/* Check whether full request is buffered. Return:
7642 * -1 if request or response is malformed
7643 * 0 if request or response is not yet fully buffered
7644 * >0 actual request length, including last \r\n\r\n */
7645static int
7646get_http_header_len(const char *buf, int buflen)
7647{
7648 int i;
7649 for (i = 0; i < buflen; i++) {
7650 /* Do an unsigned comparison in some conditions below */
7651 const unsigned char c = ((const unsigned char *)buf)[i];
7652
7653 if ((c < 128) && ((char)c != '\r') && ((char)c != '\n')
7654 && !isprint(c)) {
7655 /* abort scan as soon as one malformed character is found */
7656 return -1;
7657 }
7658
7659 if (i < buflen - 1) {
7660 if ((buf[i] == '\n') && (buf[i + 1] == '\n')) {
7661 /* Two newline, no carriage return - not standard compliant,
7662 * but
7663 * it
7664 * should be accepted */
7665 return i + 2;
7666 }
7667 }
7668
7669 if (i < buflen - 3) {
7670 if ((buf[i] == '\r') && (buf[i + 1] == '\n') && (buf[i + 2] == '\r')
7671 && (buf[i + 3] == '\n')) {
7672 /* Two \r\n - standard compliant */
7673 return i + 4;
7674 }
7675 }
7676 }
7677
7678 return 0;
7679}
7680
7681
7682#if !defined(NO_CACHING)
7683/* Convert month to the month number. Return -1 on error, or month number */
7684static int
7685get_month_index(const char *s)
7686{
7687 size_t i;
7688
7689 for (i = 0; i < ARRAY_SIZE(month_names); i++) {
7690 if (!strcmp(s, month_names[i])) {
7691 return (int)i;
7692 }
7693 }
7694
7695 return -1;
7696}
7697
7698
7699/* Parse UTC date-time string, and return the corresponding time_t value. */
7700static time_t
7701parse_date_string(const char *datetime)
7702{
7703 char month_str[32] = {0};
7704 int second, minute, hour, day, month, year;
7705 time_t result = (time_t)0;
7706 struct tm tm;
7707
7708 if ((sscanf(datetime,
7709 "%d/%3s/%d %d:%d:%d",
7710 &day,
7711 month_str,
7712 &year,
7713 &hour,
7714 &minute,
7715 &second)
7716 == 6)
7717 || (sscanf(datetime,
7718 "%d %3s %d %d:%d:%d",
7719 &day,
7720 month_str,
7721 &year,
7722 &hour,
7723 &minute,
7724 &second)
7725 == 6)
7726 || (sscanf(datetime,
7727 "%*3s, %d %3s %d %d:%d:%d",
7728 &day,
7729 month_str,
7730 &year,
7731 &hour,
7732 &minute,
7733 &second)
7734 == 6)
7735 || (sscanf(datetime,
7736 "%d-%3s-%d %d:%d:%d",
7737 &day,
7738 month_str,
7739 &year,
7740 &hour,
7741 &minute,
7742 &second)
7743 == 6)) {
7744 month = get_month_index(month_str);
7745 if ((month >= 0) && (year >= 1970)) {
7746 memset(&tm, 0, sizeof(tm));
7747 tm.tm_year = year - 1900;
7748 tm.tm_mon = month;
7749 tm.tm_mday = day;
7750 tm.tm_hour = hour;
7751 tm.tm_min = minute;
7752 tm.tm_sec = second;
7753 result = timegm(&tm);
7754 }
7755 }
7756
7757 return result;
7758}
7759#endif /* !NO_CACHING */
7760
7761
7762/* Protect against directory disclosure attack by removing '..',
7763 * excessive '/' and '\' characters */
7764static void
7766{
7767 char *p = s;
7768
7769 while ((s[0] == '.') && (s[1] == '.')) {
7770 s++;
7771 }
7772
7773 while (*s != '\0') {
7774 *p++ = *s++;
7775 if ((s[-1] == '/') || (s[-1] == '\\')) {
7776 /* Skip all following slashes, backslashes and double-dots */
7777 while (s[0] != '\0') {
7778 if ((s[0] == '/') || (s[0] == '\\')) {
7779 s++;
7780 } else if ((s[0] == '.') && (s[1] == '.')) {
7781 s += 2;
7782 } else {
7783 break;
7784 }
7785 }
7786 }
7787 }
7788 *p = '\0';
7789}
7790
7791
7792static const struct {
7793 const char *extension;
7794 size_t ext_len;
7795 const char *mime_type;
7796} builtin_mime_types[] = {
7797 /* IANA registered MIME types
7798 * (http://www.iana.org/assignments/media-types)
7799 * application types */
7800 {".doc", 4, "application/msword"},
7801 {".eps", 4, "application/postscript"},
7802 {".exe", 4, "application/octet-stream"},
7803 {".js", 3, "application/javascript"},
7804 {".json", 5, "application/json"},
7805 {".pdf", 4, "application/pdf"},
7806 {".ps", 3, "application/postscript"},
7807 {".rtf", 4, "application/rtf"},
7808 {".xhtml", 6, "application/xhtml+xml"},
7809 {".xsl", 4, "application/xml"},
7810 {".xslt", 5, "application/xml"},
7811
7812 /* fonts */
7813 {".ttf", 4, "application/font-sfnt"},
7814 {".cff", 4, "application/font-sfnt"},
7815 {".otf", 4, "application/font-sfnt"},
7816 {".aat", 4, "application/font-sfnt"},
7817 {".sil", 4, "application/font-sfnt"},
7818 {".pfr", 4, "application/font-tdpfr"},
7819 {".woff", 5, "application/font-woff"},
7820
7821 /* audio */
7822 {".mp3", 4, "audio/mpeg"},
7823 {".oga", 4, "audio/ogg"},
7824 {".ogg", 4, "audio/ogg"},
7825
7826 /* image */
7827 {".gif", 4, "image/gif"},
7828 {".ief", 4, "image/ief"},
7829 {".jpeg", 5, "image/jpeg"},
7830 {".jpg", 4, "image/jpeg"},
7831 {".jpm", 4, "image/jpm"},
7832 {".jpx", 4, "image/jpx"},
7833 {".png", 4, "image/png"},
7834 {".svg", 4, "image/svg+xml"},
7835 {".tif", 4, "image/tiff"},
7836 {".tiff", 5, "image/tiff"},
7837
7838 /* model */
7839 {".wrl", 4, "model/vrml"},
7840
7841 /* text */
7842 {".css", 4, "text/css"},
7843 {".csv", 4, "text/csv"},
7844 {".htm", 4, "text/html"},
7845 {".html", 5, "text/html"},
7846 {".sgm", 4, "text/sgml"},
7847 {".shtm", 5, "text/html"},
7848 {".shtml", 6, "text/html"},
7849 {".txt", 4, "text/plain"},
7850 {".xml", 4, "text/xml"},
7851
7852 /* video */
7853 {".mov", 4, "video/quicktime"},
7854 {".mp4", 4, "video/mp4"},
7855 {".mpeg", 5, "video/mpeg"},
7856 {".mpg", 4, "video/mpeg"},
7857 {".ogv", 4, "video/ogg"},
7858 {".qt", 3, "video/quicktime"},
7859
7860 /* not registered types
7861 * (http://reference.sitepoint.com/html/mime-types-full,
7862 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
7863 {".arj", 4, "application/x-arj-compressed"},
7864 {".gz", 3, "application/x-gunzip"},
7865 {".rar", 4, "application/x-arj-compressed"},
7866 {".swf", 4, "application/x-shockwave-flash"},
7867 {".tar", 4, "application/x-tar"},
7868 {".tgz", 4, "application/x-tar-gz"},
7869 {".torrent", 8, "application/x-bittorrent"},
7870 {".ppt", 4, "application/x-mspowerpoint"},
7871 {".xls", 4, "application/x-msexcel"},
7872 {".zip", 4, "application/x-zip-compressed"},
7873 {".aac",
7874 4,
7875 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
7876 {".aif", 4, "audio/x-aif"},
7877 {".m3u", 4, "audio/x-mpegurl"},
7878 {".mid", 4, "audio/x-midi"},
7879 {".ra", 3, "audio/x-pn-realaudio"},
7880 {".ram", 4, "audio/x-pn-realaudio"},
7881 {".wav", 4, "audio/x-wav"},
7882 {".bmp", 4, "image/bmp"},
7883 {".ico", 4, "image/x-icon"},
7884 {".pct", 4, "image/x-pct"},
7885 {".pict", 5, "image/pict"},
7886 {".rgb", 4, "image/x-rgb"},
7887 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
7888 {".asf", 4, "video/x-ms-asf"},
7889 {".avi", 4, "video/x-msvideo"},
7890 {".m4v", 4, "video/x-m4v"},
7891 {NULL, 0, NULL}};
7892
7893
7894const char *
7896{
7897 const char *ext;
7898 size_t i, path_len;
7899
7900 path_len = strlen(path);
7901
7902 for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
7903 ext = path + (path_len - builtin_mime_types[i].ext_len);
7904 if ((path_len > builtin_mime_types[i].ext_len)
7905 && (mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0)) {
7906 return builtin_mime_types[i].mime_type;
7907 }
7908 }
7909
7910 return "text/plain";
7911}
7912
7913
7914/* Look at the "path" extension and figure what mime type it has.
7915 * Store mime type in the vector. */
7916static void
7917get_mime_type(struct mg_connection *conn, const char *path, struct vec *vec)
7918{
7919 struct vec ext_vec, mime_vec;
7920 const char *list, *ext;
7921 size_t path_len;
7922
7923 path_len = strlen(path);
7924
7925 if ((conn == NULL) || (vec == NULL)) {
7926 if (vec != NULL) {
7927 memset(vec, '\0', sizeof(struct vec));
7928 }
7929 return;
7930 }
7931
7932 /* Scan user-defined mime types first, in case user wants to
7933 * override default mime types. */
7934 list = conn->dom_ctx->config[EXTRA_MIME_TYPES];
7935 while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
7936 /* ext now points to the path suffix */
7937 ext = path + path_len - ext_vec.len;
7938 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
7939 *vec = mime_vec;
7940 return;
7941 }
7942 }
7943
7945 vec->len = strlen(vec->ptr);
7946}
7947
7948
7949/* Stringify binary data. Output buffer must be twice as big as input,
7950 * because each byte takes 2 bytes in string representation */
7951static void
7952bin2str(char *to, const unsigned char *p, size_t len)
7953{
7954 static const char *hex = "0123456789abcdef";
7955
7956 for (; len--; p++) {
7957 *to++ = hex[p[0] >> 4];
7958 *to++ = hex[p[0] & 0x0f];
7959 }
7960 *to = '\0';
7961}
7962
7963
7964/* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
7965 */
7966char *
7967mg_md5(char buf[33], ...)
7968{
7969 md5_byte_t hash[16];
7970 const char *p;
7971 va_list ap;
7972 md5_state_t ctx;
7973
7974 md5_init(&ctx);
7975
7976 va_start(ap, buf);
7977 while ((p = va_arg(ap, const char *)) != NULL) {
7978 md5_append(&ctx, (const md5_byte_t *)p, strlen(p));
7979 }
7980 va_end(ap);
7981
7982 md5_finish(&ctx, hash);
7983 bin2str(buf, hash, sizeof(hash));
7984 return buf;
7985}
7986
7987
7988/* Check the user's password, return 1 if OK */
7989static int
7990check_password(const char *method,
7991 const char *ha1,
7992 const char *uri,
7993 const char *nonce,
7994 const char *nc,
7995 const char *cnonce,
7996 const char *qop,
7997 const char *response)
7998{
7999 char ha2[32 + 1], expected_response[32 + 1];
8000
8001 /* Some of the parameters may be NULL */
8002 if ((method == NULL) || (nonce == NULL) || (nc == NULL) || (cnonce == NULL)
8003 || (qop == NULL) || (response == NULL)) {
8004 return 0;
8005 }
8006
8007 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
8008 if (strlen(response) != 32) {
8009 return 0;
8010 }
8011
8012 mg_md5(ha2, method, ":", uri, NULL);
8013 mg_md5(expected_response,
8014 ha1,
8015 ":",
8016 nonce,
8017 ":",
8018 nc,
8019 ":",
8020 cnonce,
8021 ":",
8022 qop,
8023 ":",
8024 ha2,
8025 NULL);
8026
8027 return mg_strcasecmp(response, expected_response) == 0;
8028}
8029
8030
8031/* Use the global passwords file, if specified by auth_gpass option,
8032 * or search for .htpasswd in the requested directory. */
8033static void
8035 const char *path,
8036 struct mg_file *filep)
8037{
8038 if ((conn != NULL) && (conn->dom_ctx != NULL)) {
8039 char name[PATH_MAX];
8040 const char *p, *e,
8041 *gpass = conn->dom_ctx->config[GLOBAL_PASSWORDS_FILE];
8042 int truncated;
8043
8044 if (gpass != NULL) {
8045 /* Use global passwords file */
8046 if (!mg_fopen(conn, gpass, MG_FOPEN_MODE_READ, filep)) {
8047#if defined(DEBUG)
8048 /* Use mg_cry_internal here, since gpass has been configured. */
8049 mg_cry_internal(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
8050#endif
8051 }
8052 /* Important: using local struct mg_file to test path for
8053 * is_directory flag. If filep is used, mg_stat() makes it
8054 * appear as if auth file was opened.
8055 * TODO(mid): Check if this is still required after rewriting
8056 * mg_stat */
8057 } else if (mg_stat(conn, path, &filep->stat)
8058 && filep->stat.is_directory) {
8059 mg_snprintf(conn,
8060 &truncated,
8061 name,
8062 sizeof(name),
8063 "%s/%s",
8064 path,
8066
8067 if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) {
8068#if defined(DEBUG)
8069 /* Don't use mg_cry_internal here, but only a trace, since this
8070 * is
8071 * a typical case. It will occur for every directory
8072 * without a password file. */
8073 DEBUG_TRACE("fopen(%s): %s", name, strerror(ERRNO));
8074#endif
8075 }
8076 } else {
8077 /* Try to find .htpasswd in requested directory. */
8078 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
8079 if (e[0] == '/') {
8080 break;
8081 }
8082 }
8083 mg_snprintf(conn,
8084 &truncated,
8085 name,
8086 sizeof(name),
8087 "%.*s/%s",
8088 (int)(e - p),
8089 p,
8091
8092 if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) {
8093#if defined(DEBUG)
8094 /* Don't use mg_cry_internal here, but only a trace, since this
8095 * is
8096 * a typical case. It will occur for every directory
8097 * without a password file. */
8098 DEBUG_TRACE("fopen(%s): %s", name, strerror(ERRNO));
8099#endif
8100 }
8101 }
8102 }
8103}
8104
8105
8106/* Parsed Authorization header */
8107struct ah {
8108 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
8109};
8110
8111
8112/* Return 1 on success. Always initializes the ah structure. */
8113static int
8115 char *buf,
8116 size_t buf_size,
8117 struct ah *ah)
8118{
8119 char *name, *value, *s;
8120 const char *auth_header;
8121 uint64_t nonce;
8122
8123 if (!ah || !conn) {
8124 return 0;
8125 }
8126
8127 (void)memset(ah, 0, sizeof(*ah));
8128 if (((auth_header = mg_get_header(conn, "Authorization")) == NULL)
8129 || mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
8130 return 0;
8131 }
8132
8133 /* Make modifiable copy of the auth header */
8134 (void)mg_strlcpy(buf, auth_header + 7, buf_size);
8135 s = buf;
8136
8137 /* Parse authorization header */
8138 for (;;) {
8139 /* Gobble initial spaces */
8140 while (isspace(*(unsigned char *)s)) {
8141 s++;
8142 }
8143 name = skip_quoted(&s, "=", " ", 0);
8144 /* Value is either quote-delimited, or ends at first comma or space.
8145 */
8146 if (s[0] == '\"') {
8147 s++;
8148 value = skip_quoted(&s, "\"", " ", '\\');
8149 if (s[0] == ',') {
8150 s++;
8151 }
8152 } else {
8153 value = skip_quoted(&s, ", ", " ", 0); /* IE uses commas, FF uses
8154 * spaces */
8155 }
8156 if (*name == '\0') {
8157 break;
8158 }
8159
8160 if (!strcmp(name, "username")) {
8161 ah->user = value;
8162 } else if (!strcmp(name, "cnonce")) {
8163 ah->cnonce = value;
8164 } else if (!strcmp(name, "response")) {
8165 ah->response = value;
8166 } else if (!strcmp(name, "uri")) {
8167 ah->uri = value;
8168 } else if (!strcmp(name, "qop")) {
8169 ah->qop = value;
8170 } else if (!strcmp(name, "nc")) {
8171 ah->nc = value;
8172 } else if (!strcmp(name, "nonce")) {
8173 ah->nonce = value;
8174 }
8175 }
8176
8177#if !defined(NO_NONCE_CHECK)
8178 /* Read the nonce from the response. */
8179 if (ah->nonce == NULL) {
8180 return 0;
8181 }
8182 s = NULL;
8183 nonce = strtoull(ah->nonce, &s, 10);
8184 if ((s == NULL) || (*s != 0)) {
8185 return 0;
8186 }
8187
8188 /* Convert the nonce from the client to a number. */
8189 nonce ^= conn->dom_ctx->auth_nonce_mask;
8190
8191 /* The converted number corresponds to the time the nounce has been
8192 * created. This should not be earlier than the server start. */
8193 /* Server side nonce check is valuable in all situations but one:
8194 * if the server restarts frequently, but the client should not see
8195 * that, so the server should accept nonces from previous starts. */
8196 /* However, the reasonable default is to not accept a nonce from a
8197 * previous start, so if anyone changed the access rights between
8198 * two restarts, a new login is required. */
8199 if (nonce < (uint64_t)conn->phys_ctx->start_time) {
8200 /* nonce is from a previous start of the server and no longer valid
8201 * (replay attack?) */
8202 return 0;
8203 }
8204 /* Check if the nonce is too high, so it has not (yet) been used by the
8205 * server. */
8206 if (nonce >= ((uint64_t)conn->phys_ctx->start_time
8207 + conn->dom_ctx->nonce_count)) {
8208 return 0;
8209 }
8210#else
8211 (void)nonce;
8212#endif
8213
8214 /* CGI needs it as REMOTE_USER */
8215 if (ah->user != NULL) {
8217 mg_strdup_ctx(ah->user, conn->phys_ctx);
8218 } else {
8219 return 0;
8220 }
8221
8222 return 1;
8223}
8224
8225
8226static const char *
8227mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p)
8228{
8229#if defined(MG_USE_OPEN_FILE)
8230 const char *eof;
8231 size_t len;
8232 const char *memend;
8233#else
8234 (void)p; /* parameter is unused */
8235#endif
8236
8237 if (!filep) {
8238 return NULL;
8239 }
8240
8241#if defined(MG_USE_OPEN_FILE)
8242 if ((filep->access.membuf != NULL) && (*p != NULL)) {
8243 memend = (const char *)&filep->access.membuf[filep->stat.size];
8244 /* Search for \n from p till the end of stream */
8245 eof = (char *)memchr(*p, '\n', (size_t)(memend - *p));
8246 if (eof != NULL) {
8247 eof += 1; /* Include \n */
8248 } else {
8249 eof = memend; /* Copy remaining data */
8250 }
8251 len =
8252 ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (size_t)(eof - *p);
8253 memcpy(buf, *p, len);
8254 buf[len] = '\0';
8255 *p += len;
8256 return len ? eof : NULL;
8257 } else /* filep->access.fp block below */
8258#endif
8259 if (filep->access.fp != NULL) {
8260 return fgets(buf, (int)size, filep->access.fp);
8261 } else {
8262 return NULL;
8263 }
8264}
8265
8266/* Define the initial recursion depth for procesesing htpasswd files that
8267 * include other htpasswd
8268 * (or even the same) files. It is not difficult to provide a file or files
8269 * s.t. they force civetweb
8270 * to infinitely recurse and then crash.
8271 */
8272#define INITIAL_DEPTH 9
8273#if INITIAL_DEPTH <= 0
8274#error Bad INITIAL_DEPTH for recursion, set to at least 1
8275#endif
8276
8279 struct ah ah;
8280 const char *domain;
8281 char buf[256 + 256 + 40];
8282 const char *f_user;
8283 const char *f_domain;
8284 const char *f_ha1;
8285};
8286
8287
8288static int
8290 struct read_auth_file_struct *workdata,
8291 int depth)
8292{
8293 char *p = NULL /* init if MG_USE_OPEN_FILE is not set */;
8294 int is_authorized = 0;
8295 struct mg_file fp;
8296 size_t l;
8297
8298 if (!filep || !workdata || (0 == depth)) {
8299 return 0;
8300 }
8301
8302/* Loop over passwords file */
8303#if defined(MG_USE_OPEN_FILE)
8304 p = (char *)filep->access.membuf;
8305#endif
8306 while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) {
8307 l = strlen(workdata->buf);
8308 while (l > 0) {
8309 if (isspace(workdata->buf[l - 1])
8310 || iscntrl(workdata->buf[l - 1])) {
8311 l--;
8312 workdata->buf[l] = 0;
8313 } else
8314 break;
8315 }
8316 if (l < 1) {
8317 continue;
8318 }
8319
8320 workdata->f_user = workdata->buf;
8321
8322 if (workdata->f_user[0] == ':') {
8323 /* user names may not contain a ':' and may not be empty,
8324 * so lines starting with ':' may be used for a special purpose
8325 */
8326 if (workdata->f_user[1] == '#') {
8327 /* :# is a comment */
8328 continue;
8329 } else if (!strncmp(workdata->f_user + 1, "include=", 8)) {
8330 if (mg_fopen(workdata->conn,
8331 workdata->f_user + 9,
8333 &fp)) {
8334 is_authorized = read_auth_file(&fp, workdata, depth - 1);
8335 (void)mg_fclose(
8336 &fp.access); /* ignore error on read only file */
8337
8338 /* No need to continue processing files once we have a
8339 * match, since nothing will reset it back
8340 * to 0.
8341 */
8342 if (is_authorized) {
8343 return is_authorized;
8344 }
8345 } else {
8346 mg_cry_internal(workdata->conn,
8347 "%s: cannot open authorization file: %s",
8348 __func__,
8349 workdata->buf);
8350 }
8351 continue;
8352 }
8353 /* everything is invalid for the moment (might change in the
8354 * future) */
8355 mg_cry_internal(workdata->conn,
8356 "%s: syntax error in authorization file: %s",
8357 __func__,
8358 workdata->buf);
8359 continue;
8360 }
8361
8362 workdata->f_domain = strchr(workdata->f_user, ':');
8363 if (workdata->f_domain == NULL) {
8364 mg_cry_internal(workdata->conn,
8365 "%s: syntax error in authorization file: %s",
8366 __func__,
8367 workdata->buf);
8368 continue;
8369 }
8370 *(char *)(workdata->f_domain) = 0;
8371 (workdata->f_domain)++;
8372
8373 workdata->f_ha1 = strchr(workdata->f_domain, ':');
8374 if (workdata->f_ha1 == NULL) {
8375 mg_cry_internal(workdata->conn,
8376 "%s: syntax error in authorization file: %s",
8377 __func__,
8378 workdata->buf);
8379 continue;
8380 }
8381 *(char *)(workdata->f_ha1) = 0;
8382 (workdata->f_ha1)++;
8383
8384 if (!strcmp(workdata->ah.user, workdata->f_user)
8385 && !strcmp(workdata->domain, workdata->f_domain)) {
8387 workdata->f_ha1,
8388 workdata->ah.uri,
8389 workdata->ah.nonce,
8390 workdata->ah.nc,
8391 workdata->ah.cnonce,
8392 workdata->ah.qop,
8393 workdata->ah.response);
8394 }
8395 }
8396
8397 return is_authorized;
8398}
8399
8400
8401/* Authorize against the opened passwords file. Return 1 if authorized. */
8402static int
8403authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm)
8404{
8405 struct read_auth_file_struct workdata;
8406 char buf[MG_BUF_LEN];
8407
8408 if (!conn || !conn->dom_ctx) {
8409 return 0;
8410 }
8411
8412 memset(&workdata, 0, sizeof(workdata));
8413 workdata.conn = conn;
8414
8415 if (!parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) {
8416 return 0;
8417 }
8418
8419 if (realm) {
8420 workdata.domain = realm;
8421 } else {
8423 }
8424
8425 return read_auth_file(filep, &workdata, INITIAL_DEPTH);
8426}
8427
8428
8429/* Public function to check http digest authentication header */
8430int
8432 const char *realm,
8433 const char *filename)
8434{
8436 int auth;
8437
8438 if (!conn || !filename) {
8439 return -1;
8440 }
8441 if (!mg_fopen(conn, filename, MG_FOPEN_MODE_READ, &file)) {
8442 return -2;
8443 }
8444
8445 auth = authorize(conn, &file, realm);
8446
8447 mg_fclose(&file.access);
8448
8449 return auth;
8450}
8451
8452
8453/* Return 1 if request is authorised, 0 otherwise. */
8454static int
8455check_authorization(struct mg_connection *conn, const char *path)
8456{
8457 char fname[PATH_MAX];
8458 struct vec uri_vec, filename_vec;
8459 const char *list;
8461 int authorized = 1, truncated;
8462
8463 if (!conn || !conn->dom_ctx) {
8464 return 0;
8465 }
8466
8467 list = conn->dom_ctx->config[PROTECT_URI];
8468 while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
8469 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
8470 mg_snprintf(conn,
8471 &truncated,
8472 fname,
8473 sizeof(fname),
8474 "%.*s",
8475 (int)filename_vec.len,
8476 filename_vec.ptr);
8477
8478 if (truncated
8479 || !mg_fopen(conn, fname, MG_FOPEN_MODE_READ, &file)) {
8480 mg_cry_internal(conn,
8481 "%s: cannot open %s: %s",
8482 __func__,
8483 fname,
8484 strerror(errno));
8485 }
8486 break;
8487 }
8488 }
8489
8490 if (!is_file_opened(&file.access)) {
8491 open_auth_file(conn, path, &file);
8492 }
8493
8494 if (is_file_opened(&file.access)) {
8495 authorized = authorize(conn, &file, NULL);
8496 (void)mg_fclose(&file.access); /* ignore error on read only file */
8497 }
8498
8499 return authorized;
8500}
8501
8502
8503/* Internal function. Assumes conn is valid */
8504static void
8505send_authorization_request(struct mg_connection *conn, const char *realm)
8506{
8507 char date[64];
8508 time_t curtime = time(NULL);
8509 uint64_t nonce = (uint64_t)(conn->phys_ctx->start_time);
8510
8511 if (!realm) {
8512 realm = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
8513 }
8514
8515 (void)pthread_mutex_lock(&conn->phys_ctx->nonce_mutex);
8516 nonce += conn->dom_ctx->nonce_count;
8517 ++conn->dom_ctx->nonce_count;
8518 (void)pthread_mutex_unlock(&conn->phys_ctx->nonce_mutex);
8519
8520 nonce ^= conn->dom_ctx->auth_nonce_mask;
8521 conn->status_code = 401;
8522 conn->must_close = 1;
8523
8524 gmt_time_string(date, sizeof(date), &curtime);
8525
8526 mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n");
8529 mg_printf(conn,
8530 "Date: %s\r\n"
8531 "Connection: %s\r\n"
8532 "Content-Length: 0\r\n"
8533 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
8534 "nonce=\"%" UINT64_FMT "\"\r\n\r\n",
8535 date,
8537 realm,
8538 nonce);
8539}
8540
8541
8542/* Interface function. Parameters are provided by the user, so do
8543 * at least some basic checks.
8544 */
8545int
8547 const char *realm)
8548{
8549 if (conn && conn->dom_ctx) {
8550 send_authorization_request(conn, realm);
8551 return 0;
8552 }
8553 return -1;
8554}
8555
8556
8557#if !defined(NO_FILES)
8558static int
8560{
8561 if (conn) {
8563 const char *passfile = conn->dom_ctx->config[PUT_DELETE_PASSWORDS_FILE];
8564 int ret = 0;
8565
8566 if (passfile != NULL
8567 && mg_fopen(conn, passfile, MG_FOPEN_MODE_READ, &file)) {
8568 ret = authorize(conn, &file, NULL);
8569 (void)mg_fclose(&file.access); /* ignore error on read only file */
8570 }
8571
8572 return ret;
8573 }
8574 return 0;
8575}
8576#endif
8577
8578
8579int
8581 const char *domain,
8582 const char *user,
8583 const char *pass)
8584{
8585 int found, i;
8586 char line[512], u[512] = "", d[512] = "", ha1[33], tmp[PATH_MAX + 8];
8587 FILE *fp, *fp2;
8588
8589 found = 0;
8590 fp = fp2 = NULL;
8591
8592 /* Regard empty password as no password - remove user record. */
8593 if ((pass != NULL) && (pass[0] == '\0')) {
8594 pass = NULL;
8595 }
8596
8597 /* Other arguments must not be empty */
8598 if ((fname == NULL) || (domain == NULL) || (user == NULL)) {
8599 return 0;
8600 }
8601
8602 /* Using the given file format, user name and domain must not contain
8603 * ':'
8604 */
8605 if (strchr(user, ':') != NULL) {
8606 return 0;
8607 }
8608 if (strchr(domain, ':') != NULL) {
8609 return 0;
8610 }
8611
8612 /* Do not allow control characters like newline in user name and domain.
8613 * Do not allow excessively long names either. */
8614 for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
8615 if (iscntrl(user[i])) {
8616 return 0;
8617 }
8618 }
8619 if (user[i]) {
8620 return 0;
8621 }
8622 for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
8623 if (iscntrl(domain[i])) {
8624 return 0;
8625 }
8626 }
8627 if (domain[i]) {
8628 return 0;
8629 }
8630
8631 /* The maximum length of the path to the password file is limited */
8632 if ((strlen(fname) + 4) >= PATH_MAX) {
8633 return 0;
8634 }
8635
8636 /* Create a temporary file name. Length has been checked before. */
8637 strcpy(tmp, fname);
8638 strcat(tmp, ".tmp");
8639
8640 /* Create the file if does not exist */
8641 /* Use of fopen here is OK, since fname is only ASCII */
8642 if ((fp = fopen(fname, "a+")) != NULL) {
8643 (void)fclose(fp);
8644 }
8645
8646 /* Open the given file and temporary file */
8647 if ((fp = fopen(fname, "r")) == NULL) {
8648 return 0;
8649 } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
8650 fclose(fp);
8651 return 0;
8652 }
8653
8654 /* Copy the stuff to temporary file */
8655 while (fgets(line, sizeof(line), fp) != NULL) {
8656 if (sscanf(line, "%255[^:]:%255[^:]:%*s", u, d) != 2) {
8657 continue;
8658 }
8659 u[255] = 0;
8660 d[255] = 0;
8661
8662 if (!strcmp(u, user) && !strcmp(d, domain)) {
8663 found++;
8664 if (pass != NULL) {
8665 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
8666 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
8667 }
8668 } else {
8669 fprintf(fp2, "%s", line);
8670 }
8671 }
8672
8673 /* If new user, just add it */
8674 if (!found && (pass != NULL)) {
8675 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
8676 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
8677 }
8678
8679 /* Close files */
8680 fclose(fp);
8681 fclose(fp2);
8682
8683 /* Put the temp file in place of real file */
8684 IGNORE_UNUSED_RESULT(remove(fname));
8685 IGNORE_UNUSED_RESULT(rename(tmp, fname));
8686
8687 return 1;
8688}
8689
8690
8691static int
8692is_valid_port(unsigned long port)
8693{
8694 return (port <= 0xffff);
8695}
8696
8697
8698static int
8699mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
8700{
8701 struct addrinfo hints, *res, *ressave;
8702 int func_ret = 0;
8703 int gai_ret;
8704
8705 memset(&hints, 0, sizeof(struct addrinfo));
8706 hints.ai_family = af;
8707
8708 gai_ret = getaddrinfo(src, NULL, &hints, &res);
8709 if (gai_ret != 0) {
8710 /* gai_strerror could be used to convert gai_ret to a string */
8711 /* POSIX return values: see
8712 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
8713 */
8714 /* Windows return values: see
8715 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
8716 */
8717 return 0;
8718 }
8719
8720 ressave = res;
8721
8722 while (res) {
8723 if (dstlen >= (size_t)res->ai_addrlen) {
8724 memcpy(dst, res->ai_addr, res->ai_addrlen);
8725 func_ret = 1;
8726 }
8727 res = res->ai_next;
8728 }
8729
8730 freeaddrinfo(ressave);
8731 return func_ret;
8732}
8733
8734
8735static int
8736connect_socket(struct mg_context *ctx /* may be NULL */,
8737 const char *host,
8738 int port,
8739 int use_ssl,
8740 char *ebuf,
8741 size_t ebuf_len,
8742 SOCKET *sock /* output: socket, must not be NULL */,
8743 union usa *sa /* output: socket address, must not be NULL */
8744)
8745{
8746 int ip_ver = 0;
8747 int conn_ret = -1;
8748 int ret;
8749 *sock = INVALID_SOCKET;
8750 memset(sa, 0, sizeof(*sa));
8751
8752 if (ebuf_len > 0) {
8753 *ebuf = 0;
8754 }
8755
8756 if (host == NULL) {
8757 mg_snprintf(NULL,
8758 NULL, /* No truncation check for ebuf */
8759 ebuf,
8760 ebuf_len,
8761 "%s",
8762 "NULL host");
8763 return 0;
8764 }
8765
8766 if ((port <= 0) || !is_valid_port((unsigned)port)) {
8767 mg_snprintf(NULL,
8768 NULL, /* No truncation check for ebuf */
8769 ebuf,
8770 ebuf_len,
8771 "%s",
8772 "invalid port");
8773 return 0;
8774 }
8775
8776#if !defined(NO_SSL)
8777#if !defined(NO_SSL_DL)
8778#if defined(OPENSSL_API_1_1)
8779 if (use_ssl && (TLS_client_method == NULL)) {
8780 mg_snprintf(NULL,
8781 NULL, /* No truncation check for ebuf */
8782 ebuf,
8783 ebuf_len,
8784 "%s",
8785 "SSL is not initialized");
8786 return 0;
8787 }
8788#else
8789 if (use_ssl && (SSLv23_client_method == NULL)) {
8790 mg_snprintf(NULL,
8791 NULL, /* No truncation check for ebuf */
8792 ebuf,
8793 ebuf_len,
8794 "%s",
8795 "SSL is not initialized");
8796 return 0;
8797 }
8798
8799#endif /* OPENSSL_API_1_1 */
8800#else
8801 (void)use_ssl;
8802#endif /* NO_SSL_DL */
8803#else
8804 (void)use_ssl;
8805#endif /* !defined(NO_SSL) */
8806
8807 if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) {
8808 sa->sin.sin_family = AF_INET;
8809 sa->sin.sin_port = htons((uint16_t)port);
8810 ip_ver = 4;
8811#if defined(USE_IPV6)
8812 } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) {
8813 sa->sin6.sin6_family = AF_INET6;
8814 sa->sin6.sin6_port = htons((uint16_t)port);
8815 ip_ver = 6;
8816 } else if (host[0] == '[') {
8817 /* While getaddrinfo on Windows will work with [::1],
8818 * getaddrinfo on Linux only works with ::1 (without []). */
8819 size_t l = strlen(host + 1);
8820 char *h = (l > 1) ? mg_strdup_ctx(host + 1, ctx) : NULL;
8821 if (h) {
8822 h[l - 1] = 0;
8823 if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) {
8824 sa->sin6.sin6_family = AF_INET6;
8825 sa->sin6.sin6_port = htons((uint16_t)port);
8826 ip_ver = 6;
8827 }
8828 mg_free(h);
8829 }
8830#endif
8831 }
8832
8833 if (ip_ver == 0) {
8834 mg_snprintf(NULL,
8835 NULL, /* No truncation check for ebuf */
8836 ebuf,
8837 ebuf_len,
8838 "%s",
8839 "host not found");
8840 return 0;
8841 }
8842
8843 if (ip_ver == 4) {
8844 *sock = socket(PF_INET, SOCK_STREAM, 0);
8845 }
8846#if defined(USE_IPV6)
8847 else if (ip_ver == 6) {
8848 *sock = socket(PF_INET6, SOCK_STREAM, 0);
8849 }
8850#endif
8851
8852 if (*sock == INVALID_SOCKET) {
8853 mg_snprintf(NULL,
8854 NULL, /* No truncation check for ebuf */
8855 ebuf,
8856 ebuf_len,
8857 "socket(): %s",
8858 strerror(ERRNO));
8859 return 0;
8860 }
8861
8862 if (0 != set_non_blocking_mode(*sock)) {
8863 mg_snprintf(NULL,
8864 NULL, /* No truncation check for ebuf */
8865 ebuf,
8866 ebuf_len,
8867 "Cannot set socket to non-blocking: %s",
8868 strerror(ERRNO));
8869 closesocket(*sock);
8870 *sock = INVALID_SOCKET;
8871 return 0;
8872 }
8873
8874 set_close_on_exec(*sock, fc(ctx));
8875
8876 if (ip_ver == 4) {
8877 /* connected with IPv4 */
8878 conn_ret = connect(*sock,
8879 (struct sockaddr *)((void *)&sa->sin),
8880 sizeof(sa->sin));
8881 }
8882#if defined(USE_IPV6)
8883 else if (ip_ver == 6) {
8884 /* connected with IPv6 */
8885 conn_ret = connect(*sock,
8886 (struct sockaddr *)((void *)&sa->sin6),
8887 sizeof(sa->sin6));
8888 }
8889#endif
8890
8891#if defined(_WIN32)
8892 if (conn_ret != 0) {
8893 DWORD err = WSAGetLastError(); /* could return WSAEWOULDBLOCK */
8894 conn_ret = (int)err;
8895#if !defined(EINPROGRESS)
8896#define EINPROGRESS (WSAEWOULDBLOCK) /* Winsock equivalent */
8897#endif /* if !defined(EINPROGRESS) */
8898 }
8899#endif
8900
8901 if ((conn_ret != 0) && (conn_ret != EINPROGRESS)) {
8902 /* Data for getsockopt */
8903 int sockerr = -1;
8904 void *psockerr = &sockerr;
8905
8906#if defined(_WIN32)
8907 int len = (int)sizeof(sockerr);
8908#else
8909 socklen_t len = (socklen_t)sizeof(sockerr);
8910#endif
8911
8912 /* Data for poll */
8913 struct pollfd pfd[1];
8914 int pollres;
8915 int ms_wait = 10000; /* 10 second timeout */
8916
8917 /* For a non-blocking socket, the connect sequence is:
8918 * 1) call connect (will not block)
8919 * 2) wait until the socket is ready for writing (select or poll)
8920 * 3) check connection state with getsockopt
8921 */
8922 pfd[0].fd = *sock;
8923 pfd[0].events = POLLOUT;
8924 pollres = mg_poll(pfd, 1, (int)(ms_wait), &(ctx->stop_flag));
8925
8926 if (pollres != 1) {
8927 /* Not connected */
8928 mg_snprintf(NULL,
8929 NULL, /* No truncation check for ebuf */
8930 ebuf,
8931 ebuf_len,
8932 "connect(%s:%d): timeout",
8933 host,
8934 port);
8935 closesocket(*sock);
8936 *sock = INVALID_SOCKET;
8937 return 0;
8938 }
8939
8940#if defined(_WIN32)
8941 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, (char *)psockerr, &len);
8942#else
8943 ret = getsockopt(*sock, SOL_SOCKET, SO_ERROR, psockerr, &len);
8944#endif
8945
8946 if ((ret != 0) || (sockerr != 0)) {
8947 /* Not connected */
8948 mg_snprintf(NULL,
8949 NULL, /* No truncation check for ebuf */
8950 ebuf,
8951 ebuf_len,
8952 "connect(%s:%d): error %s",
8953 host,
8954 port,
8955 strerror(sockerr));
8956 closesocket(*sock);
8957 *sock = INVALID_SOCKET;
8958 return 0;
8959 }
8960 }
8961
8962 return 1;
8963}
8964
8965
8966int
8967mg_url_encode(const char *src, char *dst, size_t dst_len)
8968{
8969 static const char *dont_escape = "._-$,;~()";
8970 static const char *hex = "0123456789abcdef";
8971 char *pos = dst;
8972 const char *end = dst + dst_len - 1;
8973
8974 for (; ((*src != '\0') && (pos < end)); src++, pos++) {
8975 if (isalnum(*(const unsigned char *)src)
8976 || (strchr(dont_escape, *(const unsigned char *)src) != NULL)) {
8977 *pos = *src;
8978 } else if (pos + 2 < end) {
8979 pos[0] = '%';
8980 pos[1] = hex[(*(const unsigned char *)src) >> 4];
8981 pos[2] = hex[(*(const unsigned char *)src) & 0xf];
8982 pos += 2;
8983 } else {
8984 break;
8985 }
8986 }
8987
8988 *pos = '\0';
8989 return (*src == '\0') ? (int)(pos - dst) : -1;
8990}
8991
8992/* Return 0 on success, non-zero if an error occurs. */
8993
8994static int
8996{
8997 size_t hrefsize;
8998 char *href;
8999 char size[64], mod[64];
9000#if defined(REENTRANT_TIME)
9001 struct tm _tm;
9002 struct tm *tm = &_tm;
9003#else
9004 struct tm *tm;
9005#endif
9006
9007 hrefsize = PATH_MAX * 3; /* worst case */
9008 href = (char *)mg_malloc(hrefsize);
9009 if (href == NULL) {
9010 return -1;
9011 }
9012 if (de->file.is_directory) {
9014 NULL, /* Buffer is big enough */
9015 size,
9016 sizeof(size),
9017 "%s",
9018 "[DIRECTORY]");
9019 } else {
9020 /* We use (signed) cast below because MSVC 6 compiler cannot
9021 * convert unsigned __int64 to double. Sigh. */
9022 if (de->file.size < 1024) {
9024 NULL, /* Buffer is big enough */
9025 size,
9026 sizeof(size),
9027 "%d",
9028 (int)de->file.size);
9029 } else if (de->file.size < 0x100000) {
9031 NULL, /* Buffer is big enough */
9032 size,
9033 sizeof(size),
9034 "%.1fk",
9035 (double)de->file.size / 1024.0);
9036 } else if (de->file.size < 0x40000000) {
9038 NULL, /* Buffer is big enough */
9039 size,
9040 sizeof(size),
9041 "%.1fM",
9042 (double)de->file.size / 1048576);
9043 } else {
9045 NULL, /* Buffer is big enough */
9046 size,
9047 sizeof(size),
9048 "%.1fG",
9049 (double)de->file.size / 1073741824);
9050 }
9051 }
9052
9053 /* Note: mg_snprintf will not cause a buffer overflow above.
9054 * So, string truncation checks are not required here. */
9055
9056#if defined(REENTRANT_TIME)
9057 localtime_r(&de->file.last_modified, tm);
9058#else
9059 tm = localtime(&de->file.last_modified);
9060#endif
9061 if (tm != NULL) {
9062 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
9063 } else {
9064 mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
9065 mod[sizeof(mod) - 1] = '\0';
9066 }
9067 mg_url_encode(de->file_name, href, hrefsize);
9068 mg_printf(de->conn,
9069 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
9070 "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
9072 href,
9073 de->file.is_directory ? "/" : "",
9074 de->file_name,
9075 de->file.is_directory ? "/" : "",
9076 mod,
9077 size);
9078 mg_free(href);
9079 return 0;
9080}
9081
9082
9083/* This function is called from send_directory() and used for
9084 * sorting directory entries by size, or name, or modification time.
9085 * On windows, __cdecl specification is needed in case if project is built
9086 * with __stdcall convention. qsort always requires __cdels callback. */
9087static int WINCDECL
9088compare_dir_entries(const void *p1, const void *p2)
9089{
9090 if (p1 && p2) {
9091 const struct de *a = (const struct de *)p1, *b = (const struct de *)p2;
9092 const char *query_string = a->conn->request_info.query_string;
9093 int cmp_result = 0;
9094
9095 if (query_string == NULL) {
9096 query_string = "na";
9097 }
9098
9099 if (a->file.is_directory && !b->file.is_directory) {
9100 return -1; /* Always put directories on top */
9101 } else if (!a->file.is_directory && b->file.is_directory) {
9102 return 1; /* Always put directories on top */
9103 } else if (*query_string == 'n') {
9104 cmp_result = strcmp(a->file_name, b->file_name);
9105 } else if (*query_string == 's') {
9106 cmp_result = (a->file.size == b->file.size)
9107 ? 0
9108 : ((a->file.size > b->file.size) ? 1 : -1);
9109 } else if (*query_string == 'd') {
9110 cmp_result =
9111 (a->file.last_modified == b->file.last_modified)
9112 ? 0
9113 : ((a->file.last_modified > b->file.last_modified) ? 1
9114 : -1);
9115 }
9116
9117 return (query_string[1] == 'd') ? -cmp_result : cmp_result;
9118 }
9119 return 0;
9120}
9121
9122
9123static int
9124must_hide_file(struct mg_connection *conn, const char *path)
9125{
9126 if (conn && conn->dom_ctx) {
9127 const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
9128 const char *pattern = conn->dom_ctx->config[HIDE_FILES];
9129 return (match_prefix(pw_pattern, strlen(pw_pattern), path) > 0)
9130 || ((pattern != NULL)
9131 && (match_prefix(pattern, strlen(pattern), path) > 0));
9132 }
9133 return 0;
9134}
9135
9136
9137static int
9139 const char *dir,
9140 void *data,
9141 int (*cb)(struct de *, void *))
9142{
9143 char path[PATH_MAX];
9144 struct dirent *dp;
9145 DIR *dirp;
9146 struct de de;
9147 int truncated;
9148
9149 if ((dirp = mg_opendir(conn, dir)) == NULL) {
9150 return 0;
9151 } else {
9152 de.conn = conn;
9153
9154 while ((dp = mg_readdir(dirp)) != NULL) {
9155 /* Do not show current dir and hidden files */
9156 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
9157 || must_hide_file(conn, dp->d_name)) {
9158 continue;
9159 }
9160
9162 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
9163
9164 /* If we don't memset stat structure to zero, mtime will have
9165 * garbage and strftime() will segfault later on in
9166 * print_dir_entry(). memset is required only if mg_stat()
9167 * fails. For more details, see
9168 * http://code.google.com/p/mongoose/issues/detail?id=79 */
9169 memset(&de.file, 0, sizeof(de.file));
9170
9171 if (truncated) {
9172 /* If the path is not complete, skip processing. */
9173 continue;
9174 }
9175
9176 if (!mg_stat(conn, path, &de.file)) {
9178 "%s: mg_stat(%s) failed: %s",
9179 __func__,
9180 path,
9181 strerror(ERRNO));
9182 }
9183 de.file_name = dp->d_name;
9184 cb(&de, data);
9185 }
9186 (void)mg_closedir(dirp);
9187 }
9188 return 1;
9189}
9190
9191
9192#if !defined(NO_FILES)
9193static int
9194remove_directory(struct mg_connection *conn, const char *dir)
9195{
9196 char path[PATH_MAX];
9197 struct dirent *dp;
9198 DIR *dirp;
9199 struct de de;
9200 int truncated;
9201 int ok = 1;
9202
9203 if ((dirp = mg_opendir(conn, dir)) == NULL) {
9204 return 0;
9205 } else {
9206 de.conn = conn;
9207
9208 while ((dp = mg_readdir(dirp)) != NULL) {
9209 /* Do not show current dir (but show hidden files as they will
9210 * also be removed) */
9211 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
9212 continue;
9213 }
9214
9216 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
9217
9218 /* If we don't memset stat structure to zero, mtime will have
9219 * garbage and strftime() will segfault later on in
9220 * print_dir_entry(). memset is required only if mg_stat()
9221 * fails. For more details, see
9222 * http://code.google.com/p/mongoose/issues/detail?id=79 */
9223 memset(&de.file, 0, sizeof(de.file));
9224
9225 if (truncated) {
9226 /* Do not delete anything shorter */
9227 ok = 0;
9228 continue;
9229 }
9230
9231 if (!mg_stat(conn, path, &de.file)) {
9233 "%s: mg_stat(%s) failed: %s",
9234 __func__,
9235 path,
9236 strerror(ERRNO));
9237 ok = 0;
9238 }
9239
9240 if (de.file.is_directory) {
9241 if (remove_directory(conn, path) == 0) {
9242 ok = 0;
9243 }
9244 } else {
9245 /* This will fail file is the file is in memory */
9246 if (mg_remove(conn, path) == 0) {
9247 ok = 0;
9248 }
9249 }
9250 }
9251 (void)mg_closedir(dirp);
9252
9253 IGNORE_UNUSED_RESULT(rmdir(dir));
9254 }
9255
9256 return ok;
9257}
9258#endif
9259
9260
9262 struct de *entries;
9263 unsigned int num_entries;
9264 unsigned int arr_size;
9265};
9266
9267
9268/* Behaves like realloc(), but frees original pointer on failure */
9269static void *
9270realloc2(void *ptr, size_t size)
9271{
9272 void *new_ptr = mg_realloc(ptr, size);
9273 if (new_ptr == NULL) {
9274 mg_free(ptr);
9275 }
9276 return new_ptr;
9277}
9278
9279
9280static int
9281dir_scan_callback(struct de *de, void *data)
9282{
9283 struct dir_scan_data *dsd = (struct dir_scan_data *)data;
9284
9285 if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
9286 dsd->arr_size *= 2;
9287 dsd->entries =
9288 (struct de *)realloc2(dsd->entries,
9289 dsd->arr_size * sizeof(dsd->entries[0]));
9290 }
9291 if (dsd->entries == NULL) {
9292 /* TODO(lsm, low): propagate an error to the caller */
9293 dsd->num_entries = 0;
9294 } else {
9296 dsd->entries[dsd->num_entries].file = de->file;
9297 dsd->entries[dsd->num_entries].conn = de->conn;
9298 dsd->num_entries++;
9299 }
9300
9301 return 0;
9302}
9303
9304
9305static void
9307{
9308 unsigned int i;
9309 int sort_direction;
9310 struct dir_scan_data data = {NULL, 0, 128};
9311 char date[64];
9312 time_t curtime = time(NULL);
9313
9314 if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
9315 mg_send_http_error(conn,
9316 500,
9317 "Error: Cannot open directory\nopendir(%s): %s",
9318 dir,
9319 strerror(ERRNO));
9320 return;
9321 }
9322
9323 gmt_time_string(date, sizeof(date), &curtime);
9324
9325 if (!conn) {
9326 return;
9327 }
9328
9329 sort_direction = ((conn->request_info.query_string != NULL)
9330 && (conn->request_info.query_string[1] == 'd'))
9331 ? 'a'
9332 : 'd';
9333
9334 conn->must_close = 1;
9335 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
9338 mg_printf(conn,
9339 "Date: %s\r\n"
9340 "Connection: close\r\n"
9341 "Content-Type: text/html; charset=utf-8\r\n\r\n",
9342 date);
9343 mg_printf(conn,
9344 "<html><head><title>Index of %s</title>"
9345 "<style>th {text-align: left;}</style></head>"
9346 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
9347 "<tr><th><a href=\"?n%c\">Name</a></th>"
9348 "<th><a href=\"?d%c\">Modified</a></th>"
9349 "<th><a href=\"?s%c\">Size</a></th></tr>"
9350 "<tr><td colspan=\"3\"><hr></td></tr>",
9351 conn->request_info.local_uri,
9352 conn->request_info.local_uri,
9353 sort_direction,
9354 sort_direction,
9355 sort_direction);
9356
9357 /* Print first entry - link to a parent directory */
9358 mg_printf(conn,
9359 "<tr><td><a href=\"%s%s\">%s</a></td>"
9360 "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
9361 conn->request_info.local_uri,
9362 "..",
9363 "Parent directory",
9364 "-",
9365 "-");
9366
9367 /* Sort and print directory entries */
9368 if (data.entries != NULL) {
9369 qsort(data.entries,
9370 (size_t)data.num_entries,
9371 sizeof(data.entries[0]),
9373 for (i = 0; i < data.num_entries; i++) {
9374 print_dir_entry(&data.entries[i]);
9375 mg_free(data.entries[i].file_name);
9376 }
9377 mg_free(data.entries);
9378 }
9379
9380 mg_printf(conn, "%s", "</table></body></html>");
9381 conn->status_code = 200;
9382}
9383
9384
9385/* Send len bytes from the opened file to the client. */
9386static void
9388 struct mg_file *filep,
9389 int64_t offset,
9390 int64_t len)
9391{
9392 char buf[MG_BUF_LEN];
9393 int to_read, num_read, num_written;
9394 int64_t size;
9395
9396 if (!filep || !conn) {
9397 return;
9398 }
9399
9400 /* Sanity check the offset */
9401 size = (filep->stat.size > INT64_MAX) ? INT64_MAX
9402 : (int64_t)(filep->stat.size);
9403 offset = (offset < 0) ? 0 : ((offset > size) ? size : offset);
9404
9405#if defined(MG_USE_OPEN_FILE)
9406 if ((len > 0) && (filep->access.membuf != NULL) && (size > 0)) {
9407 /* file stored in memory */
9408 if (len > size - offset) {
9409 len = size - offset;
9410 }
9411 mg_write(conn, filep->access.membuf + offset, (size_t)len);
9412 } else /* else block below */
9413#endif
9414 if (len > 0 && filep->access.fp != NULL) {
9415/* file stored on disk */
9416#if defined(__linux__)
9417 /* sendfile is only available for Linux */
9418 if ((conn->ssl == 0) && (conn->throttle == 0)
9419 && (!mg_strcasecmp(conn->dom_ctx->config[ALLOW_SENDFILE_CALL],
9420 "yes"))) {
9421 off_t sf_offs = (off_t)offset;
9422 ssize_t sf_sent;
9423 int sf_file = fileno(filep->access.fp);
9424 int loop_cnt = 0;
9425
9426 do {
9427 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
9428 * 64 bit Linux (2^31 minus one memory page of 4k?). */
9429 size_t sf_tosend =
9430 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
9431 sf_sent =
9432 sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
9433 if (sf_sent > 0) {
9434 len -= sf_sent;
9435 offset += sf_sent;
9436 } else if (loop_cnt == 0) {
9437 /* This file can not be sent using sendfile.
9438 * This might be the case for pseudo-files in the
9439 * /sys/ and /proc/ file system.
9440 * Use the regular user mode copy code instead. */
9441 break;
9442 } else if (sf_sent == 0) {
9443 /* No error, but 0 bytes sent. May be EOF? */
9444 return;
9445 }
9446 loop_cnt++;
9447
9448 } while ((len > 0) && (sf_sent >= 0));
9449
9450 if (sf_sent > 0) {
9451 return; /* OK */
9452 }
9453
9454 /* sf_sent<0 means error, thus fall back to the classic way */
9455 /* This is always the case, if sf_file is not a "normal" file,
9456 * e.g., for sending data from the output of a CGI process. */
9457 offset = (int64_t)sf_offs;
9458 }
9459#endif
9460 if ((offset > 0) && (fseeko(filep->access.fp, offset, SEEK_SET) != 0)) {
9461 mg_cry_internal(conn,
9462 "%s: fseeko() failed: %s",
9463 __func__,
9464 strerror(ERRNO));
9466 conn,
9467 500,
9468 "%s",
9469 "Error: Unable to access file at requested position.");
9470 } else {
9471 while (len > 0) {
9472 /* Calculate how much to read from the file in the buffer */
9473 to_read = sizeof(buf);
9474 if ((int64_t)to_read > len) {
9475 to_read = (int)len;
9476 }
9477
9478 /* Read from file, exit the loop on error */
9479 if ((num_read =
9480 (int)fread(buf, 1, (size_t)to_read, filep->access.fp))
9481 <= 0) {
9482 break;
9483 }
9484
9485 /* Send read bytes to the client, exit the loop on error */
9486 if ((num_written = mg_write(conn, buf, (size_t)num_read))
9487 != num_read) {
9488 break;
9489 }
9490
9491 /* Both read and were successful, adjust counters */
9492 len -= num_written;
9493 }
9494 }
9495 }
9496}
9497
9498
9499static int
9500parse_range_header(const char *header, int64_t *a, int64_t *b)
9501{
9502 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
9503}
9504
9505
9506static void
9507construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
9508{
9509 if ((filestat != NULL) && (buf != NULL)) {
9510 mg_snprintf(NULL,
9511 NULL, /* All calls to construct_etag use 64 byte buffer */
9512 buf,
9513 buf_len,
9514 "\"%lx.%" INT64_FMT "\"",
9515 (unsigned long)filestat->last_modified,
9516 filestat->size);
9517 }
9518}
9519
9520
9521static void
9522fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
9523{
9524 if (filep != NULL && filep->fp != NULL) {
9525#if defined(_WIN32)
9526 (void)conn; /* Unused. */
9527#else
9528 if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
9529 mg_cry_internal(conn,
9530 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
9531 __func__,
9532 strerror(ERRNO));
9533 }
9534#endif
9535 }
9536}
9537
9538
9539#if defined(USE_ZLIB)
9540#include "mod_zlib.inl"
9541#endif
9542
9543
9544static void
9546 const char *path,
9547 struct mg_file *filep,
9548 const char *mime_type,
9549 const char *additional_headers)
9550{
9551 char date[64], lm[64], etag[64];
9552 char range[128]; /* large enough, so there will be no overflow */
9553 const char *msg = "OK", *hdr;
9554 time_t curtime = time(NULL);
9555 int64_t cl, r1, r2;
9556 struct vec mime_vec;
9557 int n, truncated;
9558 char gz_path[PATH_MAX];
9559 const char *encoding = "";
9560 const char *cors1, *cors2, *cors3;
9561 int is_head_request;
9562
9563#if defined(USE_ZLIB)
9564 /* Compression is allowed, unless there is a reason not to use compression.
9565 * If the file is already compressed, too small or a "range" request was
9566 * made, on the fly compression is not possible. */
9567 int allow_on_the_fly_compression = 1;
9568#endif
9569
9570 if ((conn == NULL) || (conn->dom_ctx == NULL) || (filep == NULL)) {
9571 return;
9572 }
9573
9574 is_head_request = !strcmp(conn->request_info.request_method, "HEAD");
9575
9576 if (mime_type == NULL) {
9577 get_mime_type(conn, path, &mime_vec);
9578 } else {
9579 mime_vec.ptr = mime_type;
9580 mime_vec.len = strlen(mime_type);
9581 }
9582 if (filep->stat.size > INT64_MAX) {
9583 mg_send_http_error(conn,
9584 500,
9585 "Error: File size is too large to send\n%" INT64_FMT,
9586 filep->stat.size);
9587 return;
9588 }
9589 cl = (int64_t)filep->stat.size;
9590 conn->status_code = 200;
9591 range[0] = '\0';
9592
9593#if defined(USE_ZLIB)
9594 /* if this file is in fact a pre-gzipped file, rewrite its filename
9595 * it's important to rewrite the filename after resolving
9596 * the mime type from it, to preserve the actual file's type */
9597 if (!conn->accept_gzip) {
9598 allow_on_the_fly_compression = 0;
9599 }
9600#endif
9601
9602 if (filep->stat.is_gzipped) {
9603 mg_snprintf(conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", path);
9604
9605 if (truncated) {
9606 mg_send_http_error(conn,
9607 500,
9608 "Error: Path of zipped file too long (%s)",
9609 path);
9610 return;
9611 }
9612
9613 path = gz_path;
9614 encoding = "Content-Encoding: gzip\r\n";
9615
9616#if defined(USE_ZLIB)
9617 /* File is already compressed. No "on the fly" compression. */
9618 allow_on_the_fly_compression = 0;
9619#endif
9620 }
9621
9622 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
9623 mg_send_http_error(conn,
9624 500,
9625 "Error: Cannot open file\nfopen(%s): %s",
9626 path,
9627 strerror(ERRNO));
9628 return;
9629 }
9630
9631 fclose_on_exec(&filep->access, conn);
9632
9633 /* If "Range" request was made: parse header, send only selected part
9634 * of the file. */
9635 r1 = r2 = 0;
9636 hdr = mg_get_header(conn, "Range");
9637 if ((hdr != NULL) && ((n = parse_range_header(hdr, &r1, &r2)) > 0)
9638 && (r1 >= 0) && (r2 >= 0)) {
9639 /* actually, range requests don't play well with a pre-gzipped
9640 * file (since the range is specified in the uncompressed space) */
9641 if (filep->stat.is_gzipped) {
9643 conn,
9644 416, /* 416 = Range Not Satisfiable */
9645 "%s",
9646 "Error: Range requests in gzipped files are not supported");
9647 (void)mg_fclose(
9648 &filep->access); /* ignore error on read only file */
9649 return;
9650 }
9651 conn->status_code = 206;
9652 cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
9653 mg_snprintf(conn,
9654 NULL, /* range buffer is big enough */
9655 range,
9656 sizeof(range),
9657 "Content-Range: bytes "
9658 "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
9659 r1,
9660 r1 + cl - 1,
9661 filep->stat.size);
9662 msg = "Partial Content";
9663
9664#if defined(USE_ZLIB)
9665 /* Do not compress ranges. */
9666 allow_on_the_fly_compression = 0;
9667#endif
9668 }
9669
9670/* Do not compress small files. Small files do not benefit from file
9671 * compression, but there is still some overhead. */
9672#if defined(USE_ZLIB)
9674 /* File is below the size limit. */
9675 allow_on_the_fly_compression = 0;
9676 }
9677#endif
9678
9679 /* Standard CORS header */
9680 hdr = mg_get_header(conn, "Origin");
9681 if (hdr) {
9682 /* Cross-origin resource sharing (CORS), see
9683 * http://www.html5rocks.com/en/tutorials/cors/,
9684 * http://www.html5rocks.com/static/images/cors_server_flowchart.png
9685 * -
9686 * preflight is not supported for files. */
9687 cors1 = "Access-Control-Allow-Origin: ";
9689 cors3 = "\r\n";
9690 } else {
9691 cors1 = cors2 = cors3 = "";
9692 }
9693
9694 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC,
9695 * according to
9696 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
9697 gmt_time_string(date, sizeof(date), &curtime);
9698 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
9699 construct_etag(etag, sizeof(etag), &filep->stat);
9700
9701 /* Send header */
9702 (void)mg_printf(conn,
9703 "HTTP/1.1 %d %s\r\n"
9704 "%s%s%s" /* CORS */
9705 "Date: %s\r\n"
9706 "Last-Modified: %s\r\n"
9707 "Etag: %s\r\n"
9708 "Content-Type: %.*s\r\n"
9709 "Connection: %s\r\n",
9710 conn->status_code,
9711 msg,
9712 cors1,
9713 cors2,
9714 cors3,
9715 date,
9716 lm,
9717 etag,
9718 (int)mime_vec.len,
9719 mime_vec.ptr,
9723
9724#if defined(USE_ZLIB)
9725 /* On the fly compression allowed */
9726 if (allow_on_the_fly_compression) {
9727 /* For on the fly compression, we don't know the content size in
9728 * advance, so we have to use chunked encoding */
9729 (void)mg_printf(conn,
9730 "Content-Encoding: gzip\r\n"
9731 "Transfer-Encoding: chunked\r\n");
9732 } else
9733#endif
9734 {
9735 /* Without on-the-fly compression, we know the content-length
9736 * and we can use ranges (with on-the-fly compression we cannot).
9737 * So we send these response headers only in this case. */
9738 (void)mg_printf(conn,
9739 "Content-Length: %" INT64_FMT "\r\n"
9740 "Accept-Ranges: bytes\r\n"
9741 "%s" /* range */
9742 "%s" /* encoding */,
9743 cl,
9744 range,
9745 encoding);
9746 }
9747
9748 /* The previous code must not add any header starting with X- to make
9749 * sure no one of the additional_headers is included twice */
9750 if (additional_headers != NULL) {
9751 (void)mg_printf(conn,
9752 "%.*s\r\n\r\n",
9753 (int)strlen(additional_headers),
9754 additional_headers);
9755 } else {
9756 (void)mg_printf(conn, "\r\n");
9757 }
9758
9759 if (!is_head_request) {
9760#if defined(USE_ZLIB)
9761 if (allow_on_the_fly_compression) {
9762 /* Compress and send */
9763 send_compressed_data(conn, filep);
9764 } else
9765#endif
9766 {
9767 /* Send file directly */
9768 send_file_data(conn, filep, r1, cl);
9769 }
9770 }
9771 (void)mg_fclose(&filep->access); /* ignore error on read only file */
9772}
9773
9774
9775int
9776mg_send_file_body(struct mg_connection *conn, const char *path)
9777{
9779 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, &file)) {
9780 return -1;
9781 }
9782 fclose_on_exec(&file.access, conn);
9783 send_file_data(conn, &file, 0, INT64_MAX);
9784 (void)mg_fclose(&file.access); /* Ignore errors for readonly files */
9785 return 0; /* >= 0 for OK */
9786}
9787
9788
9789#if !defined(NO_CACHING)
9790/* Return True if we should reply 304 Not Modified. */
9791static int
9793 const struct mg_file_stat *filestat)
9794{
9795 char etag[64];
9796 const char *ims = mg_get_header(conn, "If-Modified-Since");
9797 const char *inm = mg_get_header(conn, "If-None-Match");
9798 construct_etag(etag, sizeof(etag), filestat);
9799
9800 return ((inm != NULL) && !mg_strcasecmp(etag, inm))
9801 || ((ims != NULL)
9802 && (filestat->last_modified <= parse_date_string(ims)));
9803}
9804
9805static void
9807 struct mg_file *filep)
9808{
9809 char date[64], lm[64], etag[64];
9810 time_t curtime = time(NULL);
9811
9812 if ((conn == NULL) || (filep == NULL)) {
9813 return;
9814 }
9815 conn->status_code = 304;
9816 gmt_time_string(date, sizeof(date), &curtime);
9817 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
9818 construct_etag(etag, sizeof(etag), &filep->stat);
9819
9820 (void)mg_printf(conn,
9821 "HTTP/1.1 %d %s\r\n"
9822 "Date: %s\r\n",
9823 conn->status_code,
9825 date);
9828 (void)mg_printf(conn,
9829 "Last-Modified: %s\r\n"
9830 "Etag: %s\r\n"
9831 "Connection: %s\r\n"
9832 "\r\n",
9833 lm,
9834 etag,
9836}
9837#endif
9838
9839
9840void
9841mg_send_file(struct mg_connection *conn, const char *path)
9842{
9843 mg_send_mime_file2(conn, path, NULL, NULL);
9844}
9845
9846
9847void
9849 const char *path,
9850 const char *mime_type)
9851{
9852 mg_send_mime_file2(conn, path, mime_type, NULL);
9853}
9854
9855
9856void
9858 const char *path,
9859 const char *mime_type,
9860 const char *additional_headers)
9861{
9863
9864 if (!conn) {
9865 /* No conn */
9866 return;
9867 }
9868
9869 if (mg_stat(conn, path, &file.stat)) {
9870#if !defined(NO_CACHING)
9871 if (is_not_modified(conn, &file.stat)) {
9872 /* Send 304 "Not Modified" - this must not send any body data */
9874 } else
9875#endif /* NO_CACHING */
9876 if (file.stat.is_directory) {
9878 "yes")) {
9879 handle_directory_request(conn, path);
9880 } else {
9881 mg_send_http_error(conn,
9882 403,
9883 "%s",
9884 "Error: Directory listing denied");
9885 }
9886 } else {
9888 conn, path, &file, mime_type, additional_headers);
9889 }
9890 } else {
9891 mg_send_http_error(conn, 404, "%s", "Error: File not found");
9892 }
9893}
9894
9895
9896/* For a given PUT path, create all intermediate subdirectories.
9897 * Return 0 if the path itself is a directory.
9898 * Return 1 if the path leads to a file.
9899 * Return -1 for if the path is too long.
9900 * Return -2 if path can not be created.
9901 */
9902static int
9903put_dir(struct mg_connection *conn, const char *path)
9904{
9905 char buf[PATH_MAX];
9906 const char *s, *p;
9908 size_t len;
9909 int res = 1;
9910
9911 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
9912 len = (size_t)(p - path);
9913 if (len >= sizeof(buf)) {
9914 /* path too long */
9915 res = -1;
9916 break;
9917 }
9918 memcpy(buf, path, len);
9919 buf[len] = '\0';
9920
9921 /* Try to create intermediate directory */
9922 DEBUG_TRACE("mkdir(%s)", buf);
9923 if (!mg_stat(conn, buf, &file.stat) && mg_mkdir(conn, buf, 0755) != 0) {
9924 /* path does not exixt and can not be created */
9925 res = -2;
9926 break;
9927 }
9928
9929 /* Is path itself a directory? */
9930 if (p[1] == '\0') {
9931 res = 0;
9932 }
9933 }
9934
9935 return res;
9936}
9937
9938
9939static void
9940remove_bad_file(const struct mg_connection *conn, const char *path)
9941{
9942 int r = mg_remove(conn, path);
9943 if (r != 0) {
9944 mg_cry_internal(conn,
9945 "%s: Cannot remove invalid file %s",
9946 __func__,
9947 path);
9948 }
9949}
9950
9951
9952long long
9953mg_store_body(struct mg_connection *conn, const char *path)
9954{
9955 char buf[MG_BUF_LEN];
9956 long long len = 0;
9957 int ret, n;
9958 struct mg_file fi;
9959
9960 if (conn->consumed_content != 0) {
9961 mg_cry_internal(conn, "%s: Contents already consumed", __func__);
9962 return -11;
9963 }
9964
9965 ret = put_dir(conn, path);
9966 if (ret < 0) {
9967 /* -1 for path too long,
9968 * -2 for path can not be created. */
9969 return ret;
9970 }
9971 if (ret != 1) {
9972 /* Return 0 means, path itself is a directory. */
9973 return 0;
9974 }
9975
9976 if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fi) == 0) {
9977 return -12;
9978 }
9979
9980 ret = mg_read(conn, buf, sizeof(buf));
9981 while (ret > 0) {
9982 n = (int)fwrite(buf, 1, (size_t)ret, fi.access.fp);
9983 if (n != ret) {
9984 (void)mg_fclose(
9985 &fi.access); /* File is bad and will be removed anyway. */
9986 remove_bad_file(conn, path);
9987 return -13;
9988 }
9989 len += ret;
9990 ret = mg_read(conn, buf, sizeof(buf));
9991 }
9992
9993 /* File is open for writing. If fclose fails, there was probably an
9994 * error flushing the buffer to disk, so the file on disk might be
9995 * broken. Delete it and return an error to the caller. */
9996 if (mg_fclose(&fi.access) != 0) {
9997 remove_bad_file(conn, path);
9998 return -14;
9999 }
10000
10001 return len;
10002}
10003
10004
10005/* Parse a buffer:
10006 * Forward the string pointer till the end of a word, then
10007 * terminate it and forward till the begin of the next word.
10008 */
10009static int
10011{
10012 /* Forward until a space is found - use isgraph here */
10013 /* See http://www.cplusplus.com/reference/cctype/ */
10014 while (isgraph(**ppw)) {
10015 (*ppw)++;
10016 }
10017
10018 /* Check end of word */
10019 if (eol) {
10020 /* must be a end of line */
10021 if ((**ppw != '\r') && (**ppw != '\n')) {
10022 return -1;
10023 }
10024 } else {
10025 /* must be a end of a word, but not a line */
10026 if (**ppw != ' ') {
10027 return -1;
10028 }
10029 }
10030
10031 /* Terminate and forward to the next word */
10032 do {
10033 **ppw = 0;
10034 (*ppw)++;
10035 } while ((**ppw) && isspace(**ppw));
10036
10037 /* Check after term */
10038 if (!eol) {
10039 /* if it's not the end of line, there must be a next word */
10040 if (!isgraph(**ppw)) {
10041 return -1;
10042 }
10043 }
10044
10045 /* ok */
10046 return 1;
10047}
10048
10049
10050/* Parse HTTP headers from the given buffer, advance buf pointer
10051 * to the point where parsing stopped.
10052 * All parameters must be valid pointers (not NULL).
10053 * Return <0 on error. */
10054static int
10056{
10057 int i;
10058 int num_headers = 0;
10059
10060 for (i = 0; i < (int)MG_MAX_HEADERS; i++) {
10061 char *dp = *buf;
10062 while ((*dp != ':') && (*dp >= 33) && (*dp <= 126)) {
10063 dp++;
10064 }
10065 if (dp == *buf) {
10066 /* End of headers reached. */
10067 break;
10068 }
10069 if (*dp != ':') {
10070 /* This is not a valid field. */
10071 return -1;
10072 }
10073
10074 /* End of header key (*dp == ':') */
10075 /* Truncate here and set the key name */
10076 *dp = 0;
10077 hdr[i].name = *buf;
10078 do {
10079 dp++;
10080 } while (*dp == ' ');
10081
10082 /* The rest of the line is the value */
10083 hdr[i].value = dp;
10084 *buf = dp + strcspn(dp, "\r\n");
10085 if (((*buf)[0] != '\r') || ((*buf)[1] != '\n')) {
10086 *buf = NULL;
10087 }
10088
10089 num_headers = i + 1;
10090 if (*buf) {
10091 (*buf)[0] = 0;
10092 (*buf)[1] = 0;
10093 *buf += 2;
10094 } else {
10095 *buf = dp;
10096 break;
10097 }
10098
10099 if ((*buf)[0] == '\r') {
10100 /* This is the end of the header */
10101 break;
10102 }
10103 }
10104 return num_headers;
10105}
10106
10107
10109 const char *name;
10115};
10116
10117
10118/* https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods */
10120 /* HTTP (RFC 2616) */
10121 {"GET", 0, 1, 1, 1, 1},
10122 {"POST", 1, 1, 0, 0, 0},
10123 {"PUT", 1, 0, 0, 1, 0},
10124 {"DELETE", 0, 0, 0, 1, 0},
10125 {"HEAD", 0, 0, 1, 1, 1},
10126 {"OPTIONS", 0, 0, 1, 1, 0},
10127 {"CONNECT", 1, 1, 0, 0, 0},
10128 /* TRACE method (RFC 2616) is not supported for security reasons */
10129
10130 /* PATCH method (RFC 5789) */
10131 {"PATCH", 1, 0, 0, 0, 0},
10132 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
10133
10134 /* WEBDAV (RFC 2518) */
10135 {"PROPFIND", 0, 1, 1, 1, 0},
10136 /* http://www.webdav.org/specs/rfc4918.html, 9.1:
10137 * Some PROPFIND results MAY be cached, with care,
10138 * as there is no cache validation mechanism for
10139 * most properties. This method is both safe and
10140 * idempotent (see Section 9.1 of [RFC2616]). */
10141 {"MKCOL", 0, 0, 0, 1, 0},
10142 /* http://www.webdav.org/specs/rfc4918.html, 9.1:
10143 * When MKCOL is invoked without a request body,
10144 * the newly created collection SHOULD have no
10145 * members. A MKCOL request message may contain
10146 * a message body. The precise behavior of a MKCOL
10147 * request when the body is present is undefined,
10148 * ... ==> We do not support MKCOL with body data.
10149 * This method is idempotent, but not safe (see
10150 * Section 9.1 of [RFC2616]). Responses to this
10151 * method MUST NOT be cached. */
10152
10153 /* Unsupported WEBDAV Methods: */
10154 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
10155 /* + 11 methods from RFC 3253 */
10156 /* ORDERPATCH (RFC 3648) */
10157 /* ACL (RFC 3744) */
10158 /* SEARCH (RFC 5323) */
10159 /* + MicroSoft extensions
10160 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
10161
10162 /* REPORT method (RFC 3253) */
10163 {"REPORT", 1, 1, 1, 1, 1},
10164 /* REPORT method only allowed for CGI/Lua/LSP and callbacks. */
10165 /* It was defined for WEBDAV in RFC 3253, Sec. 3.6
10166 * (https://tools.ietf.org/html/rfc3253#section-3.6), but seems
10167 * to be useful for REST in case a "GET request with body" is
10168 * required. */
10169
10170 {NULL, 0, 0, 0, 0, 0}
10171 /* end of list */
10172};
10173
10174
10175static const struct mg_http_method_info *
10176get_http_method_info(const char *method)
10177{
10178 /* Check if the method is known to the server. The list of all known
10179 * HTTP methods can be found here at
10180 * http://www.iana.org/assignments/http-methods/http-methods.xhtml
10181 */
10182 const struct mg_http_method_info *m = http_methods;
10183
10184 while (m->name) {
10185 if (!strcmp(m->name, method)) {
10186 return m;
10187 }
10188 m++;
10189 }
10190 return NULL;
10191}
10192
10193
10194static int
10195is_valid_http_method(const char *method)
10196{
10197 return (get_http_method_info(method) != NULL);
10198}
10199
10200
10201/* Parse HTTP request, fill in mg_request_info structure.
10202 * This function modifies the buffer by NUL-terminating
10203 * HTTP request components, header names and header values.
10204 * Parameters:
10205 * buf (in/out): pointer to the HTTP header to parse and split
10206 * len (in): length of HTTP header buffer
10207 * re (out): parsed header as mg_request_info
10208 * buf and ri must be valid pointers (not NULL), len>0.
10209 * Returns <0 on error. */
10210static int
10211parse_http_request(char *buf, int len, struct mg_request_info *ri)
10212{
10213 int request_length;
10214 int init_skip = 0;
10215
10216 /* Reset attributes. DO NOT TOUCH is_ssl, remote_addr,
10217 * remote_port */
10218 ri->remote_user = ri->request_method = ri->request_uri = ri->http_version =
10219 NULL;
10220 ri->num_headers = 0;
10221
10222 /* RFC says that all initial whitespaces should be ingored */
10223 /* This included all leading \r and \n (isspace) */
10224 /* See table: http://www.cplusplus.com/reference/cctype/ */
10225 while ((len > 0) && isspace(*(unsigned char *)buf)) {
10226 buf++;
10227 len--;
10228 init_skip++;
10229 }
10230
10231 if (len == 0) {
10232 /* Incomplete request */
10233 return 0;
10234 }
10235
10236 /* Control characters are not allowed, including zero */
10237 if (iscntrl(*(unsigned char *)buf)) {
10238 return -1;
10239 }
10240
10241 /* Find end of HTTP header */
10242 request_length = get_http_header_len(buf, len);
10243 if (request_length <= 0) {
10244 return request_length;
10245 }
10246 buf[request_length - 1] = '\0';
10247
10248 if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) {
10249 return -1;
10250 }
10251
10252 /* The first word has to be the HTTP method */
10253 ri->request_method = buf;
10254
10255 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
10256 return -1;
10257 }
10258
10259 /* Check for a valid http method */
10261 return -1;
10262 }
10263
10264 /* The second word is the URI */
10265 ri->request_uri = buf;
10266
10267 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
10268 return -1;
10269 }
10270
10271 /* Next would be the HTTP version */
10272 ri->http_version = buf;
10273
10274 if (skip_to_end_of_word_and_terminate(&buf, 1) <= 0) {
10275 return -1;
10276 }
10277
10278 /* Check for a valid HTTP version key */
10279 if (strncmp(ri->http_version, "HTTP/", 5) != 0) {
10280 /* Invalid request */
10281 return -1;
10282 }
10283 ri->http_version += 5;
10284
10285
10286 /* Parse all HTTP headers */
10288 if (ri->num_headers < 0) {
10289 /* Error while parsing headers */
10290 return -1;
10291 }
10292
10293 return request_length + init_skip;
10294}
10295
10296
10297static int
10298parse_http_response(char *buf, int len, struct mg_response_info *ri)
10299{
10300 int response_length;
10301 int init_skip = 0;
10302 char *tmp, *tmp2;
10303 long l;
10304
10305 /* Initialize elements. */
10306 ri->http_version = ri->status_text = NULL;
10307 ri->num_headers = ri->status_code = 0;
10308
10309 /* RFC says that all initial whitespaces should be ingored */
10310 /* This included all leading \r and \n (isspace) */
10311 /* See table: http://www.cplusplus.com/reference/cctype/ */
10312 while ((len > 0) && isspace(*(unsigned char *)buf)) {
10313 buf++;
10314 len--;
10315 init_skip++;
10316 }
10317
10318 if (len == 0) {
10319 /* Incomplete request */
10320 return 0;
10321 }
10322
10323 /* Control characters are not allowed, including zero */
10324 if (iscntrl(*(unsigned char *)buf)) {
10325 return -1;
10326 }
10327
10328 /* Find end of HTTP header */
10329 response_length = get_http_header_len(buf, len);
10330 if (response_length <= 0) {
10331 return response_length;
10332 }
10333 buf[response_length - 1] = '\0';
10334
10335 if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) {
10336 return -1;
10337 }
10338
10339 /* The first word is the HTTP version */
10340 /* Check for a valid HTTP version key */
10341 if (strncmp(buf, "HTTP/", 5) != 0) {
10342 /* Invalid request */
10343 return -1;
10344 }
10345 buf += 5;
10346 if (!isgraph(buf[0])) {
10347 /* Invalid request */
10348 return -1;
10349 }
10350 ri->http_version = buf;
10351
10352 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
10353 return -1;
10354 }
10355
10356 /* The second word is the status as a number */
10357 tmp = buf;
10358
10359 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
10360 return -1;
10361 }
10362
10363 l = strtol(tmp, &tmp2, 10);
10364 if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
10365 /* Everything else but a 3 digit code is invalid */
10366 return -1;
10367 }
10368 ri->status_code = (int)l;
10369
10370 /* The rest of the line is the status text */
10371 ri->status_text = buf;
10372
10373 /* Find end of status text */
10374 /* isgraph or isspace = isprint */
10375 while (isprint(*buf)) {
10376 buf++;
10377 }
10378 if ((*buf != '\r') && (*buf != '\n')) {
10379 return -1;
10380 }
10381 /* Terminate string and forward buf to next line */
10382 do {
10383 *buf = 0;
10384 buf++;
10385 } while ((*buf) && isspace(*buf));
10386
10387
10388 /* Parse all HTTP headers */
10390 if (ri->num_headers < 0) {
10391 /* Error while parsing headers */
10392 return -1;
10393 }
10394
10395 return response_length + init_skip;
10396}
10397
10398
10399/* Keep reading the input (either opened file descriptor fd, or socket sock,
10400 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
10401 * buffer (which marks the end of HTTP request). Buffer buf may already
10402 * have some data. The length of the data is stored in nread.
10403 * Upon every read operation, increase nread by the number of bytes read. */
10404static int
10406 struct mg_connection *conn,
10407 char *buf,
10408 int bufsiz,
10409 int *nread)
10410{
10411 int request_len, n = 0;
10412 struct timespec last_action_time;
10413 double request_timeout;
10414
10415 if (!conn) {
10416 return 0;
10417 }
10418
10419 memset(&last_action_time, 0, sizeof(last_action_time));
10420
10421 if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
10422 /* value of request_timeout is in seconds, config in milliseconds */
10423 request_timeout = atof(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
10424 } else {
10425 request_timeout = -1.0;
10426 }
10427 if (conn->handled_requests > 0) {
10428 if (conn->dom_ctx->config[KEEP_ALIVE_TIMEOUT]) {
10429 request_timeout =
10430 atof(conn->dom_ctx->config[KEEP_ALIVE_TIMEOUT]) / 1000.0;
10431 }
10432 }
10433
10434 request_len = get_http_header_len(buf, *nread);
10435
10436 /* first time reading from this connection */
10437 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
10438
10439 while (request_len == 0) {
10440 /* Full request not yet received */
10441 if (conn->phys_ctx->stop_flag != 0) {
10442 /* Server is to be stopped. */
10443 return -1;
10444 }
10445
10446 if (*nread >= bufsiz) {
10447 /* Request too long */
10448 return -2;
10449 }
10450
10451 n = pull_inner(
10452 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
10453 if (n == -2) {
10454 /* Receive error */
10455 return -1;
10456 }
10457 if (n > 0) {
10458 *nread += n;
10459 request_len = get_http_header_len(buf, *nread);
10460 } else {
10461 request_len = 0;
10462 }
10463
10464 if ((request_len == 0) && (request_timeout >= 0)) {
10465 if (mg_difftimespec(&last_action_time, &(conn->req_time))
10466 > request_timeout) {
10467 /* Timeout */
10468 return -1;
10469 }
10470 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
10471 }
10472 }
10473
10474 return request_len;
10475}
10476
10477
10478#if !defined(NO_CGI) || !defined(NO_FILES)
10479static int
10480forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
10481{
10482 const char *expect, *body;
10483 char buf[MG_BUF_LEN];
10484 int to_read, nread, success = 0;
10485 int64_t buffered_len;
10486 double timeout = -1.0;
10487
10488 if (!conn) {
10489 return 0;
10490 }
10491 if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
10492 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
10493 }
10494
10495 expect = mg_get_header(conn, "Expect");
10496 DEBUG_ASSERT(fp != NULL);
10497 if (!fp) {
10498 mg_send_http_error(conn, 500, "%s", "Error: NULL File");
10499 return 0;
10500 }
10501
10502 if ((conn->content_len == -1) && (!conn->is_chunked)) {
10503 /* Content length is not specified by the client. */
10504 mg_send_http_error(conn,
10505 411,
10506 "%s",
10507 "Error: Client did not specify content length");
10508 } else if ((expect != NULL)
10509 && (mg_strcasecmp(expect, "100-continue") != 0)) {
10510 /* Client sent an "Expect: xyz" header and xyz is not 100-continue.
10511 */
10512 mg_send_http_error(conn,
10513 417,
10514 "Error: Can not fulfill expectation %s",
10515 expect);
10516 } else {
10517 if (expect != NULL) {
10518 (void)mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
10519 conn->status_code = 100;
10520 } else {
10521 conn->status_code = 200;
10522 }
10523
10524 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
10525 - conn->consumed_content;
10526
10527 DEBUG_ASSERT(buffered_len >= 0);
10528 DEBUG_ASSERT(conn->consumed_content == 0);
10529
10530 if ((buffered_len < 0) || (conn->consumed_content != 0)) {
10531 mg_send_http_error(conn, 500, "%s", "Error: Size mismatch");
10532 return 0;
10533 }
10534
10535 if (buffered_len > 0) {
10536 if ((int64_t)buffered_len > conn->content_len) {
10537 buffered_len = (int)conn->content_len;
10538 }
10539 body = conn->buf + conn->request_len + conn->consumed_content;
10540 push_all(
10541 conn->phys_ctx, fp, sock, ssl, body, (int64_t)buffered_len);
10542 conn->consumed_content += buffered_len;
10543 }
10544
10545 nread = 0;
10546 while (conn->consumed_content < conn->content_len) {
10547 to_read = sizeof(buf);
10548 if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
10549 to_read = (int)(conn->content_len - conn->consumed_content);
10550 }
10551 nread = pull_inner(NULL, conn, buf, to_read, timeout);
10552 if (nread == -2) {
10553 /* error */
10554 break;
10555 }
10556 if (nread > 0) {
10557 if (push_all(conn->phys_ctx, fp, sock, ssl, buf, nread)
10558 != nread) {
10559 break;
10560 }
10561 }
10562 conn->consumed_content += nread;
10563 }
10564
10565 if (conn->consumed_content == conn->content_len) {
10566 success = (nread >= 0);
10567 }
10568
10569 /* Each error code path in this function must send an error */
10570 if (!success) {
10571 /* NOTE: Maybe some data has already been sent. */
10572 /* TODO (low): If some data has been sent, a correct error
10573 * reply can no longer be sent, so just close the connection */
10574 mg_send_http_error(conn, 500, "%s", "");
10575 }
10576 }
10577
10578 return success;
10579}
10580#endif
10581
10582
10583#if defined(USE_TIMERS)
10584
10585#define TIMER_API static
10586#include "timer.inl"
10587
10588#endif /* USE_TIMERS */
10589
10590
10591#if !defined(NO_CGI)
10592/* This structure helps to create an environment for the spawned CGI
10593 * program.
10594 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
10595 * last element must be NULL.
10596 * However, on Windows there is a requirement that all these
10597 * VARIABLE=VALUE\0
10598 * strings must reside in a contiguous buffer. The end of the buffer is
10599 * marked by two '\0' characters.
10600 * We satisfy both worlds: we create an envp array (which is vars), all
10601 * entries are actually pointers inside buf. */
10604 /* Data block */
10605 char *buf; /* Environment buffer */
10606 size_t buflen; /* Space available in buf */
10607 size_t bufused; /* Space taken in buf */
10608 /* Index block */
10609 char **var; /* char **envp */
10610 size_t varlen; /* Number of variables available in var */
10611 size_t varused; /* Number of variables stored in var */
10612};
10613
10614
10615static void addenv(struct cgi_environment *env,
10616 PRINTF_FORMAT_STRING(const char *fmt),
10617 ...) PRINTF_ARGS(2, 3);
10618
10619/* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
10620 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
10621static void
10622addenv(struct cgi_environment *env, const char *fmt, ...)
10623{
10624 size_t n, space;
10625 int truncated = 0;
10626 char *added;
10627 va_list ap;
10628
10629 /* Calculate how much space is left in the buffer */
10630 space = (env->buflen - env->bufused);
10631
10632 /* Calculate an estimate for the required space */
10633 n = strlen(fmt) + 2 + 128;
10634
10635 do {
10636 if (space <= n) {
10637 /* Allocate new buffer */
10638 n = env->buflen + CGI_ENVIRONMENT_SIZE;
10639 added = (char *)mg_realloc_ctx(env->buf, n, env->conn->phys_ctx);
10640 if (!added) {
10641 /* Out of memory */
10643 env->conn,
10644 "%s: Cannot allocate memory for CGI variable [%s]",
10645 __func__,
10646 fmt);
10647 return;
10648 }
10649 env->buf = added;
10650 env->buflen = n;
10651 space = (env->buflen - env->bufused);
10652 }
10653
10654 /* Make a pointer to the free space int the buffer */
10655 added = env->buf + env->bufused;
10656
10657 /* Copy VARIABLE=VALUE\0 string into the free space */
10658 va_start(ap, fmt);
10659 mg_vsnprintf(env->conn, &truncated, added, (size_t)space, fmt, ap);
10660 va_end(ap);
10661
10662 /* Do not add truncated strings to the environment */
10663 if (truncated) {
10664 /* Reallocate the buffer */
10665 space = 0;
10666 n = 1;
10667 }
10668 } while (truncated);
10669
10670 /* Calculate number of bytes added to the environment */
10671 n = strlen(added) + 1;
10672 env->bufused += n;
10673
10674 /* Now update the variable index */
10675 space = (env->varlen - env->varused);
10676 if (space < 2) {
10677 mg_cry_internal(env->conn,
10678 "%s: Cannot register CGI variable [%s]",
10679 __func__,
10680 fmt);
10681 return;
10682 }
10683
10684 /* Append a pointer to the added string into the envp array */
10685 env->var[env->varused] = added;
10686 env->varused++;
10687}
10688
10689/* Return 0 on success, non-zero if an error occurs. */
10690
10691static int
10693 const char *prog,
10694 struct cgi_environment *env)
10695{
10696 const char *s;
10697 struct vec var_vec;
10698 char *p, src_addr[IP_ADDR_STR_LEN], http_var_name[128];
10699 int i, truncated, uri_len;
10700
10701 if ((conn == NULL) || (prog == NULL) || (env == NULL)) {
10702 return -1;
10703 }
10704
10705 env->conn = conn;
10707 env->bufused = 0;
10708 env->buf = (char *)mg_malloc_ctx(env->buflen, conn->phys_ctx);
10709 if (env->buf == NULL) {
10710 mg_cry_internal(conn,
10711 "%s: Not enough memory for environmental buffer",
10712 __func__);
10713 return -1;
10714 }
10716 env->varused = 0;
10717 env->var =
10718 (char **)mg_malloc_ctx(env->buflen * sizeof(char *), conn->phys_ctx);
10719 if (env->var == NULL) {
10720 mg_cry_internal(conn,
10721 "%s: Not enough memory for environmental variables",
10722 __func__);
10723 mg_free(env->buf);
10724 return -1;
10725 }
10726
10727 addenv(env, "SERVER_NAME=%s", conn->dom_ctx->config[AUTHENTICATION_DOMAIN]);
10728 addenv(env, "SERVER_ROOT=%s", conn->dom_ctx->config[DOCUMENT_ROOT]);
10729 addenv(env, "DOCUMENT_ROOT=%s", conn->dom_ctx->config[DOCUMENT_ROOT]);
10730 addenv(env, "SERVER_SOFTWARE=CivetWeb/%s", mg_version());
10731
10732 /* Prepare the environment block */
10733 addenv(env, "%s", "GATEWAY_INTERFACE=CGI/1.1");
10734 addenv(env, "%s", "SERVER_PROTOCOL=HTTP/1.1");
10735 addenv(env, "%s", "REDIRECT_STATUS=200"); /* For PHP */
10736
10737#if defined(USE_IPV6)
10738 if (conn->client.lsa.sa.sa_family == AF_INET6) {
10739 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
10740 } else
10741#endif
10742 {
10743 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
10744 }
10745
10746 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
10747 addenv(env, "REMOTE_ADDR=%s", src_addr);
10748
10749 addenv(env, "REQUEST_METHOD=%s", conn->request_info.request_method);
10750 addenv(env, "REMOTE_PORT=%d", conn->request_info.remote_port);
10751
10752 addenv(env, "REQUEST_URI=%s", conn->request_info.request_uri);
10753 addenv(env, "LOCAL_URI=%s", conn->request_info.local_uri);
10754
10755 /* SCRIPT_NAME */
10756 uri_len = (int)strlen(conn->request_info.local_uri);
10757 if (conn->path_info == NULL) {
10758 if (conn->request_info.local_uri[uri_len - 1] != '/') {
10759 /* URI: /path_to_script/script.cgi */
10760 addenv(env, "SCRIPT_NAME=%s", conn->request_info.local_uri);
10761 } else {
10762 /* URI: /path_to_script/ ... using index.cgi */
10763 const char *index_file = strrchr(prog, '/');
10764 if (index_file) {
10765 addenv(env,
10766 "SCRIPT_NAME=%s%s",
10767 conn->request_info.local_uri,
10768 index_file + 1);
10769 }
10770 }
10771 } else {
10772 /* URI: /path_to_script/script.cgi/path_info */
10773 addenv(env,
10774 "SCRIPT_NAME=%.*s",
10775 uri_len - (int)strlen(conn->path_info),
10776 conn->request_info.local_uri);
10777 }
10778
10779 addenv(env, "SCRIPT_FILENAME=%s", prog);
10780 if (conn->path_info == NULL) {
10781 addenv(env, "PATH_TRANSLATED=%s", conn->dom_ctx->config[DOCUMENT_ROOT]);
10782 } else {
10783 addenv(env,
10784 "PATH_TRANSLATED=%s%s",
10786 conn->path_info);
10787 }
10788
10789 addenv(env, "HTTPS=%s", (conn->ssl == NULL) ? "off" : "on");
10790
10791 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
10792 addenv(env, "CONTENT_TYPE=%s", s);
10793 }
10794 if (conn->request_info.query_string != NULL) {
10795 addenv(env, "QUERY_STRING=%s", conn->request_info.query_string);
10796 }
10797 if ((s = mg_get_header(conn, "Content-Length")) != NULL) {
10798 addenv(env, "CONTENT_LENGTH=%s", s);
10799 }
10800 if ((s = getenv("PATH")) != NULL) {
10801 addenv(env, "PATH=%s", s);
10802 }
10803 if (conn->path_info != NULL) {
10804 addenv(env, "PATH_INFO=%s", conn->path_info);
10805 }
10806
10807 if (conn->status_code > 0) {
10808 /* CGI error handler should show the status code */
10809 addenv(env, "STATUS=%d", conn->status_code);
10810 }
10811
10812#if defined(_WIN32)
10813 if ((s = getenv("COMSPEC")) != NULL) {
10814 addenv(env, "COMSPEC=%s", s);
10815 }
10816 if ((s = getenv("SYSTEMROOT")) != NULL) {
10817 addenv(env, "SYSTEMROOT=%s", s);
10818 }
10819 if ((s = getenv("SystemDrive")) != NULL) {
10820 addenv(env, "SystemDrive=%s", s);
10821 }
10822 if ((s = getenv("ProgramFiles")) != NULL) {
10823 addenv(env, "ProgramFiles=%s", s);
10824 }
10825 if ((s = getenv("ProgramFiles(x86)")) != NULL) {
10826 addenv(env, "ProgramFiles(x86)=%s", s);
10827 }
10828#else
10829 if ((s = getenv("LD_LIBRARY_PATH")) != NULL) {
10830 addenv(env, "LD_LIBRARY_PATH=%s", s);
10831 }
10832#endif /* _WIN32 */
10833
10834 if ((s = getenv("PERLLIB")) != NULL) {
10835 addenv(env, "PERLLIB=%s", s);
10836 }
10837
10838 if (conn->request_info.remote_user != NULL) {
10839 addenv(env, "REMOTE_USER=%s", conn->request_info.remote_user);
10840 addenv(env, "%s", "AUTH_TYPE=Digest");
10841 }
10842
10843 /* Add all headers as HTTP_* variables */
10844 for (i = 0; i < conn->request_info.num_headers; i++) {
10845
10846 (void)mg_snprintf(conn,
10847 &truncated,
10848 http_var_name,
10849 sizeof(http_var_name),
10850 "HTTP_%s",
10851 conn->request_info.http_headers[i].name);
10852
10853 if (truncated) {
10854 mg_cry_internal(conn,
10855 "%s: HTTP header variable too long [%s]",
10856 __func__,
10857 conn->request_info.http_headers[i].name);
10858 continue;
10859 }
10860
10861 /* Convert variable name into uppercase, and change - to _ */
10862 for (p = http_var_name; *p != '\0'; p++) {
10863 if (*p == '-') {
10864 *p = '_';
10865 }
10866 *p = (char)toupper(*(unsigned char *)p);
10867 }
10868
10869 addenv(env,
10870 "%s=%s",
10871 http_var_name,
10873 }
10874
10875 /* Add user-specified variables */
10876 s = conn->dom_ctx->config[CGI_ENVIRONMENT];
10877 while ((s = next_option(s, &var_vec, NULL)) != NULL) {
10878 addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr);
10879 }
10880
10881 env->var[env->varused] = NULL;
10882 env->buf[env->bufused] = '\0';
10883
10884 return 0;
10885}
10886
10887
10888/* Data for CGI process control: PID and number of references */
10890 pid_t pid;
10892};
10893
10894static int
10895abort_process(void *data)
10896{
10897 /* Waitpid checks for child status and won't work for a pid that does not
10898 * identify a child of the current process. Thus, if the pid is reused,
10899 * we will not affect a different process. */
10900 struct process_control_data *proc = (struct process_control_data *)data;
10901 int status = 0;
10902 int refs;
10903 pid_t ret_pid;
10904
10905 ret_pid = waitpid(proc->pid, &status, WNOHANG);
10906 if ((ret_pid != (pid_t)-1) && (status == 0)) {
10907 /* Stop child process */
10908 DEBUG_TRACE("CGI timer: Stop child process %p\n", proc->pid);
10909 kill(proc->pid, SIGABRT);
10910
10911 /* Wait until process is terminated (don't leave zombies) */
10912 while (waitpid(proc->pid, &status, 0) != (pid_t)-1) /* nop */
10913 ;
10914 } else {
10915 DEBUG_TRACE("CGI timer: Child process %p already stopped\n", proc->pid);
10916 }
10917 /* Dec reference counter */
10918 refs = mg_atomic_dec(&proc->references);
10919 if (refs == 0) {
10920 /* no more references - free data */
10921 mg_free(data);
10922 }
10923
10924 return 0;
10925}
10926
10927
10928static void
10929handle_cgi_request(struct mg_connection *conn, const char *prog)
10930{
10931 char *buf;
10932 size_t buflen;
10933 int headers_len, data_len, i, truncated;
10934 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
10935 const char *status, *status_text, *connection_state;
10936 char *pbuf, dir[PATH_MAX], *p;
10937 struct mg_request_info ri;
10938 struct cgi_environment blk;
10939 FILE *in = NULL, *out = NULL, *err = NULL;
10940 struct mg_file fout = STRUCT_FILE_INITIALIZER;
10941 pid_t pid = (pid_t)-1;
10942 struct process_control_data *proc = NULL;
10943
10944#if defined(USE_TIMERS)
10945 double cgi_timeout = -1.0;
10946 if (conn->dom_ctx->config[CGI_TIMEOUT]) {
10947 /* Get timeout in seconds */
10948 cgi_timeout = atof(conn->dom_ctx->config[CGI_TIMEOUT]) * 0.001;
10949 }
10950#endif
10951
10952 if (conn == NULL) {
10953 return;
10954 }
10955
10956 buf = NULL;
10957 buflen = conn->phys_ctx->max_request_size;
10958 i = prepare_cgi_environment(conn, prog, &blk);
10959 if (i != 0) {
10960 blk.buf = NULL;
10961 blk.var = NULL;
10962 goto done;
10963 }
10964
10965 /* CGI must be executed in its own directory. 'dir' must point to the
10966 * directory containing executable program, 'p' must point to the
10967 * executable program name relative to 'dir'. */
10968 (void)mg_snprintf(conn, &truncated, dir, sizeof(dir), "%s", prog);
10969
10970 if (truncated) {
10971 mg_cry_internal(conn, "Error: CGI program \"%s\": Path too long", prog);
10972 mg_send_http_error(conn, 500, "Error: %s", "CGI path too long");
10973 goto done;
10974 }
10975
10976 if ((p = strrchr(dir, '/')) != NULL) {
10977 *p++ = '\0';
10978 } else {
10979 dir[0] = '.';
10980 dir[1] = '\0';
10981 p = (char *)prog;
10982 }
10983
10984 if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) {
10985 status = strerror(ERRNO);
10987 conn,
10988 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
10989 prog,
10990 status);
10991 mg_send_http_error(conn,
10992 500,
10993 "Error: Cannot create CGI pipe: %s",
10994 status);
10995 goto done;
10996 }
10997
10998 proc = (struct process_control_data *)
10999 mg_malloc_ctx(sizeof(struct process_control_data), conn->phys_ctx);
11000 if (proc == NULL) {
11001 mg_cry_internal(conn, "Error: CGI program \"%s\": Out or memory", prog);
11002 mg_send_http_error(conn, 500, "Error: Out of memory [%s]", prog);
11003 goto done;
11004 }
11005
11006 DEBUG_TRACE("CGI: spawn %s %s\n", dir, p);
11007 pid = spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
11008
11009 if (pid == (pid_t)-1) {
11010 status = strerror(ERRNO);
11012 conn,
11013 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
11014 prog,
11015 status);
11016 mg_send_http_error(conn,
11017 500,
11018 "Error: Cannot spawn CGI process [%s]: %s",
11019 prog,
11020 status);
11021 mg_free(proc);
11022 proc = NULL;
11023 goto done;
11024 }
11025
11026 /* Store data in shared process_control_data */
11027 proc->pid = pid;
11028 proc->references = 1;
11029
11030#if defined(USE_TIMERS)
11031 if (cgi_timeout > 0.0) {
11032 proc->references = 2;
11033
11034 // Start a timer for CGI
11035 timer_add(conn->phys_ctx,
11036 cgi_timeout /* in seconds */,
11037 0.0,
11038 1,
11040 (void *)proc);
11041 }
11042#endif
11043
11044 /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
11045 set_close_on_exec((SOCKET)fdin[0], conn); /* stdin read */
11046 set_close_on_exec((SOCKET)fdin[1], conn); /* stdin write */
11047 set_close_on_exec((SOCKET)fdout[0], conn); /* stdout read */
11048 set_close_on_exec((SOCKET)fdout[1], conn); /* stdout write */
11049 set_close_on_exec((SOCKET)fderr[0], conn); /* stderr read */
11050 set_close_on_exec((SOCKET)fderr[1], conn); /* stderr write */
11051
11052 /* Parent closes only one side of the pipes.
11053 * If we don't mark them as closed, close() attempt before
11054 * return from this function throws an exception on Windows.
11055 * Windows does not like when closed descriptor is closed again. */
11056 (void)close(fdin[0]);
11057 (void)close(fdout[1]);
11058 (void)close(fderr[1]);
11059 fdin[0] = fdout[1] = fderr[1] = -1;
11060
11061 if ((in = fdopen(fdin[1], "wb")) == NULL) {
11062 status = strerror(ERRNO);
11063 mg_cry_internal(conn,
11064 "Error: CGI program \"%s\": Can not open stdin: %s",
11065 prog,
11066 status);
11067 mg_send_http_error(conn,
11068 500,
11069 "Error: CGI can not open fdin\nfopen: %s",
11070 status);
11071 goto done;
11072 }
11073
11074 if ((out = fdopen(fdout[0], "rb")) == NULL) {
11075 status = strerror(ERRNO);
11076 mg_cry_internal(conn,
11077 "Error: CGI program \"%s\": Can not open stdout: %s",
11078 prog,
11079 status);
11080 mg_send_http_error(conn,
11081 500,
11082 "Error: CGI can not open fdout\nfopen: %s",
11083 status);
11084 goto done;
11085 }
11086
11087 if ((err = fdopen(fderr[0], "rb")) == NULL) {
11088 status = strerror(ERRNO);
11089 mg_cry_internal(conn,
11090 "Error: CGI program \"%s\": Can not open stderr: %s",
11091 prog,
11092 status);
11093 mg_send_http_error(conn,
11094 500,
11095 "Error: CGI can not open fderr\nfopen: %s",
11096 status);
11097 goto done;
11098 }
11099
11100 setbuf(in, NULL);
11101 setbuf(out, NULL);
11102 setbuf(err, NULL);
11103 fout.access.fp = out;
11104
11105 if ((conn->request_info.content_length != 0) || (conn->is_chunked)) {
11106 DEBUG_TRACE("CGI: send body data (%lli)\n",
11107 (signed long long)conn->request_info.content_length);
11108
11109 /* This is a POST/PUT request, or another request with body data. */
11110 if (!forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
11111 /* Error sending the body data */
11113 conn,
11114 "Error: CGI program \"%s\": Forward body data failed",
11115 prog);
11116 goto done;
11117 }
11118 }
11119
11120 /* Close so child gets an EOF. */
11121 fclose(in);
11122 in = NULL;
11123 fdin[1] = -1;
11124
11125 /* Now read CGI reply into a buffer. We need to set correct
11126 * status code, thus we need to see all HTTP headers first.
11127 * Do not send anything back to client, until we buffer in all
11128 * HTTP headers. */
11129 data_len = 0;
11130 buf = (char *)mg_malloc_ctx(buflen, conn->phys_ctx);
11131 if (buf == NULL) {
11132 mg_send_http_error(conn,
11133 500,
11134 "Error: Not enough memory for CGI buffer (%u bytes)",
11135 (unsigned int)buflen);
11137 conn,
11138 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
11139 "bytes)",
11140 prog,
11141 (unsigned int)buflen);
11142 goto done;
11143 }
11144
11145 DEBUG_TRACE("CGI: %s", "wait for response");
11146 headers_len = read_message(out, conn, buf, (int)buflen, &data_len);
11147 DEBUG_TRACE("CGI: response: %li", (signed long)headers_len);
11148
11149 if (headers_len <= 0) {
11150
11151 /* Could not parse the CGI response. Check if some error message on
11152 * stderr. */
11153 i = pull_all(err, conn, buf, (int)buflen);
11154 if (i > 0) {
11155 /* CGI program explicitly sent an error */
11156 /* Write the error message to the internal log */
11157 mg_cry_internal(conn,
11158 "Error: CGI program \"%s\" sent error "
11159 "message: [%.*s]",
11160 prog,
11161 i,
11162 buf);
11163 /* Don't send the error message back to the client */
11164 mg_send_http_error(conn,
11165 500,
11166 "Error: CGI program \"%s\" failed.",
11167 prog);
11168 } else {
11169 /* CGI program did not explicitly send an error, but a broken
11170 * respon header */
11171 mg_cry_internal(conn,
11172 "Error: CGI program sent malformed or too big "
11173 "(>%u bytes) HTTP headers: [%.*s]",
11174 (unsigned)buflen,
11175 data_len,
11176 buf);
11177
11178 mg_send_http_error(conn,
11179 500,
11180 "Error: CGI program sent malformed or too big "
11181 "(>%u bytes) HTTP headers: [%.*s]",
11182 (unsigned)buflen,
11183 data_len,
11184 buf);
11185 }
11186
11187 /* in both cases, abort processing CGI */
11188 goto done;
11189 }
11190
11191 pbuf = buf;
11192 buf[headers_len - 1] = '\0';
11194
11195 /* Make up and send the status line */
11196 status_text = "OK";
11197 if ((status = get_header(ri.http_headers, ri.num_headers, "Status"))
11198 != NULL) {
11199 conn->status_code = atoi(status);
11200 status_text = status;
11201 while (isdigit(*(const unsigned char *)status_text)
11202 || *status_text == ' ') {
11203 status_text++;
11204 }
11205 } else if (get_header(ri.http_headers, ri.num_headers, "Location")
11206 != NULL) {
11207 conn->status_code = 307;
11208 } else {
11209 conn->status_code = 200;
11210 }
11211 connection_state =
11212 get_header(ri.http_headers, ri.num_headers, "Connection");
11213 if (!header_has_option(connection_state, "keep-alive")) {
11214 conn->must_close = 1;
11215 }
11216
11217 DEBUG_TRACE("CGI: response %u %s", conn->status_code, status_text);
11218
11219 (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
11220
11221 /* Send headers */
11222 for (i = 0; i < ri.num_headers; i++) {
11223 mg_printf(conn,
11224 "%s: %s\r\n",
11225 ri.http_headers[i].name,
11226 ri.http_headers[i].value);
11227 }
11228 mg_write(conn, "\r\n", 2);
11229
11230 /* Send chunk of data that may have been read after the headers */
11231 mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
11232
11233 /* Read the rest of CGI output and send to the client */
11234 DEBUG_TRACE("CGI: %s", "forward all data");
11235 send_file_data(conn, &fout, 0, INT64_MAX);
11236 DEBUG_TRACE("CGI: %s", "all data sent");
11237
11238done:
11239 mg_free(blk.var);
11240 mg_free(blk.buf);
11241
11242 if (pid != (pid_t)-1) {
11243 abort_process((void *)proc);
11244 }
11245
11246 if (fdin[0] != -1) {
11247 close(fdin[0]);
11248 }
11249 if (fdout[1] != -1) {
11250 close(fdout[1]);
11251 }
11252
11253 if (in != NULL) {
11254 fclose(in);
11255 } else if (fdin[1] != -1) {
11256 close(fdin[1]);
11257 }
11258
11259 if (out != NULL) {
11260 fclose(out);
11261 } else if (fdout[0] != -1) {
11262 close(fdout[0]);
11263 }
11264
11265 if (err != NULL) {
11266 fclose(err);
11267 } else if (fderr[0] != -1) {
11268 close(fderr[0]);
11269 }
11270
11271 if (buf != NULL) {
11272 mg_free(buf);
11273 }
11274}
11275#endif /* !NO_CGI */
11276
11277
11278#if !defined(NO_FILES)
11279static void
11280mkcol(struct mg_connection *conn, const char *path)
11281{
11282 int rc, body_len;
11283 struct de de;
11284 char date[64];
11285 time_t curtime = time(NULL);
11286
11287 if (conn == NULL) {
11288 return;
11289 }
11290
11291 /* TODO (mid): Check the mg_send_http_error situations in this function
11292 */
11293
11294 memset(&de.file, 0, sizeof(de.file));
11295 if (!mg_stat(conn, path, &de.file)) {
11297 "%s: mg_stat(%s) failed: %s",
11298 __func__,
11299 path,
11300 strerror(ERRNO));
11301 }
11302
11303 if (de.file.last_modified) {
11304 /* TODO (mid): This check does not seem to make any sense ! */
11305 /* TODO (mid): Add a webdav unit test first, before changing
11306 * anything here. */
11308 conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
11309 return;
11310 }
11311
11312 body_len = conn->data_len - conn->request_len;
11313 if (body_len > 0) {
11315 conn, 415, "Error: mkcol(%s): %s", path, strerror(ERRNO));
11316 return;
11317 }
11318
11319 rc = mg_mkdir(conn, path, 0755);
11320
11321 if (rc == 0) {
11322 conn->status_code = 201;
11323 gmt_time_string(date, sizeof(date), &curtime);
11325 "HTTP/1.1 %d Created\r\n"
11326 "Date: %s\r\n",
11328 date);
11332 "Content-Length: 0\r\n"
11333 "Connection: %s\r\n\r\n",
11335 } else {
11336 if (errno == EEXIST) {
11338 conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
11339 } else if (errno == EACCES) {
11341 conn, 403, "Error: mkcol(%s): %s", path, strerror(ERRNO));
11342 } else if (errno == ENOENT) {
11344 conn, 409, "Error: mkcol(%s): %s", path, strerror(ERRNO));
11345 } else {
11347 conn, 500, "fopen(%s): %s", path, strerror(ERRNO));
11348 }
11349 }
11350}
11351
11352
11353static void
11354put_file(struct mg_connection *conn, const char *path)
11355{
11357 const char *range;
11358 int64_t r1, r2;
11359 int rc;
11360 char date[64];
11361 time_t curtime = time(NULL);
11362
11363 if (conn == NULL) {
11364 return;
11365 }
11366
11367 if (mg_stat(conn, path, &file.stat)) {
11368 /* File already exists */
11369 conn->status_code = 200;
11370
11371 if (file.stat.is_directory) {
11372 /* This is an already existing directory,
11373 * so there is nothing to do for the server. */
11374 rc = 0;
11375
11376 } else {
11377 /* File exists and is not a directory. */
11378 /* Can it be replaced? */
11379
11380#if defined(MG_USE_OPEN_FILE)
11381 if (file.access.membuf != NULL) {
11382 /* This is an "in-memory" file, that can not be replaced */
11383 mg_send_http_error(conn,
11384 405,
11385 "Error: Put not possible\nReplacing %s "
11386 "is not supported",
11387 path);
11388 return;
11389 }
11390#endif
11391
11392 /* Check if the server may write this file */
11393 if (access(path, W_OK) == 0) {
11394 /* Access granted */
11395 conn->status_code = 200;
11396 rc = 1;
11397 } else {
11399 conn,
11400 403,
11401 "Error: Put not possible\nReplacing %s is not allowed",
11402 path);
11403 return;
11404 }
11405 }
11406 } else {
11407 /* File should be created */
11408 conn->status_code = 201;
11409 rc = put_dir(conn, path);
11410 }
11411
11412 if (rc == 0) {
11413 /* put_dir returns 0 if path is a directory */
11414 gmt_time_string(date, sizeof(date), &curtime);
11415 mg_printf(conn,
11416 "HTTP/1.1 %d %s\r\n",
11417 conn->status_code,
11421 mg_printf(conn,
11422 "Date: %s\r\n"
11423 "Content-Length: 0\r\n"
11424 "Connection: %s\r\n\r\n",
11425 date,
11427
11428 /* Request to create a directory has been fulfilled successfully.
11429 * No need to put a file. */
11430 return;
11431 }
11432
11433 if (rc == -1) {
11434 /* put_dir returns -1 if the path is too long */
11435 mg_send_http_error(conn,
11436 414,
11437 "Error: Path too long\nput_dir(%s): %s",
11438 path,
11439 strerror(ERRNO));
11440 return;
11441 }
11442
11443 if (rc == -2) {
11444 /* put_dir returns -2 if the directory can not be created */
11445 mg_send_http_error(conn,
11446 500,
11447 "Error: Can not create directory\nput_dir(%s): %s",
11448 path,
11449 strerror(ERRNO));
11450 return;
11451 }
11452
11453 /* A file should be created or overwritten. */
11454 /* Currently CivetWeb does not nead read+write access. */
11455 if (!mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &file)
11456 || file.access.fp == NULL) {
11457 (void)mg_fclose(&file.access);
11458 mg_send_http_error(conn,
11459 500,
11460 "Error: Can not create file\nfopen(%s): %s",
11461 path,
11462 strerror(ERRNO));
11463 return;
11464 }
11465
11466 fclose_on_exec(&file.access, conn);
11467 range = mg_get_header(conn, "Content-Range");
11468 r1 = r2 = 0;
11469 if ((range != NULL) && parse_range_header(range, &r1, &r2) > 0) {
11470 conn->status_code = 206; /* Partial content */
11471 fseeko(file.access.fp, r1, SEEK_SET);
11472 }
11473
11474 if (!forward_body_data(conn, file.access.fp, INVALID_SOCKET, NULL)) {
11475 /* forward_body_data failed.
11476 * The error code has already been sent to the client,
11477 * and conn->status_code is already set. */
11478 (void)mg_fclose(&file.access);
11479 return;
11480 }
11481
11482 if (mg_fclose(&file.access) != 0) {
11483 /* fclose failed. This might have different reasons, but a likely
11484 * one is "no space on disk", http 507. */
11485 conn->status_code = 507;
11486 }
11487
11488 gmt_time_string(date, sizeof(date), &curtime);
11489 mg_printf(conn,
11490 "HTTP/1.1 %d %s\r\n",
11491 conn->status_code,
11495 mg_printf(conn,
11496 "Date: %s\r\n"
11497 "Content-Length: 0\r\n"
11498 "Connection: %s\r\n\r\n",
11499 date,
11501}
11502
11503
11504static void
11505delete_file(struct mg_connection *conn, const char *path)
11506{
11507 struct de de;
11508 memset(&de.file, 0, sizeof(de.file));
11509 if (!mg_stat(conn, path, &de.file)) {
11510 /* mg_stat returns 0 if the file does not exist */
11512 404,
11513 "Error: Cannot delete file\nFile %s not found",
11514 path);
11515 return;
11516 }
11517
11518#if 0 /* Ignore if a file in memory is inside a folder */
11519 if (de.access.membuf != NULL) {
11520 /* the file is cached in memory */
11522 conn,
11523 405,
11524 "Error: Delete not possible\nDeleting %s is not supported",
11525 path);
11526 return;
11527 }
11528#endif
11529
11530 if (de.file.is_directory) {
11531 if (remove_directory(conn, path)) {
11532 /* Delete is successful: Return 204 without content. */
11533 mg_send_http_error(conn, 204, "%s", "");
11534 } else {
11535 /* Delete is not successful: Return 500 (Server error). */
11536 mg_send_http_error(conn, 500, "Error: Could not delete %s", path);
11537 }
11538 return;
11539 }
11540
11541 /* This is an existing file (not a directory).
11542 * Check if write permission is granted. */
11543 if (access(path, W_OK) != 0) {
11544 /* File is read only */
11546 conn,
11547 403,
11548 "Error: Delete not possible\nDeleting %s is not allowed",
11549 path);
11550 return;
11551 }
11552
11553 /* Try to delete it. */
11554 if (mg_remove(conn, path) == 0) {
11555 /* Delete was successful: Return 204 without content. */
11556 mg_send_http_error(conn, 204, "%s", "");
11557 } else {
11558 /* Delete not successful (file locked). */
11560 423,
11561 "Error: Cannot delete file\nremove(%s): %s",
11562 path,
11563 strerror(ERRNO));
11564 }
11565}
11566#endif /* !NO_FILES */
11567
11568
11569static void
11570send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int);
11571
11572
11573static void
11575 const char *ssi,
11576 char *tag,
11577 int include_level)
11578{
11579 char file_name[MG_BUF_LEN], path[512], *p;
11581 size_t len;
11582 int truncated = 0;
11583
11584 if (conn == NULL) {
11585 return;
11586 }
11587
11588 /* sscanf() is safe here, since send_ssi_file() also uses buffer
11589 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
11590 * always < MG_BUF_LEN. */
11591 if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) {
11592 /* File name is relative to the webserver root */
11593 file_name[511] = 0;
11594 (void)mg_snprintf(conn,
11595 &truncated,
11596 path,
11597 sizeof(path),
11598 "%s/%s",
11600 file_name);
11601
11602 } else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
11603 /* File name is relative to the webserver working directory
11604 * or it is absolute system path */
11605 file_name[511] = 0;
11606 (void)
11607 mg_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name);
11608
11609 } else if ((sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1)
11610 || (sscanf(tag, " \"%511[^\"]\"", file_name) == 1)) {
11611 /* File name is relative to the currect document */
11612 file_name[511] = 0;
11613 (void)mg_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
11614
11615 if (!truncated) {
11616 if ((p = strrchr(path, '/')) != NULL) {
11617 p[1] = '\0';
11618 }
11619 len = strlen(path);
11620 (void)mg_snprintf(conn,
11621 &truncated,
11622 path + len,
11623 sizeof(path) - len,
11624 "%s",
11625 file_name);
11626 }
11627
11628 } else {
11629 mg_cry_internal(conn, "Bad SSI #include: [%s]", tag);
11630 return;
11631 }
11632
11633 if (truncated) {
11634 mg_cry_internal(conn, "SSI #include path length overflow: [%s]", tag);
11635 return;
11636 }
11637
11638 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, &file)) {
11639 mg_cry_internal(conn,
11640 "Cannot open SSI #include: [%s]: fopen(%s): %s",
11641 tag,
11642 path,
11643 strerror(ERRNO));
11644 } else {
11645 fclose_on_exec(&file.access, conn);
11647 strlen(conn->dom_ctx->config[SSI_EXTENSIONS]),
11648 path)
11649 > 0) {
11650 send_ssi_file(conn, path, &file, include_level + 1);
11651 } else {
11652 send_file_data(conn, &file, 0, INT64_MAX);
11653 }
11654 (void)mg_fclose(&file.access); /* Ignore errors for readonly files */
11655 }
11656}
11657
11658
11659#if !defined(NO_POPEN)
11660static void
11661do_ssi_exec(struct mg_connection *conn, char *tag)
11662{
11663 char cmd[1024] = "";
11665
11666 if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
11667 mg_cry_internal(conn, "Bad SSI #exec: [%s]", tag);
11668 } else {
11669 cmd[1023] = 0;
11670 if ((file.access.fp = popen(cmd, "r")) == NULL) {
11671 mg_cry_internal(conn,
11672 "Cannot SSI #exec: [%s]: %s",
11673 cmd,
11674 strerror(ERRNO));
11675 } else {
11676 send_file_data(conn, &file, 0, INT64_MAX);
11677 pclose(file.access.fp);
11678 }
11679 }
11680}
11681#endif /* !NO_POPEN */
11682
11683
11684static int
11685mg_fgetc(struct mg_file *filep, int offset)
11686{
11687 (void)offset; /* unused in case MG_USE_OPEN_FILE is set */
11688
11689 if (filep == NULL) {
11690 return EOF;
11691 }
11692#if defined(MG_USE_OPEN_FILE)
11693 if ((filep->access.membuf != NULL) && (offset >= 0)
11694 && (((unsigned int)(offset)) < filep->stat.size)) {
11695 return ((const unsigned char *)filep->access.membuf)[offset];
11696 } else /* else block below */
11697#endif
11698 if (filep->access.fp != NULL) {
11699 return fgetc(filep->access.fp);
11700 } else {
11701 return EOF;
11702 }
11703}
11704
11705
11706static void
11708 const char *path,
11709 struct mg_file *filep,
11710 int include_level)
11711{
11712 char buf[MG_BUF_LEN];
11713 int ch, offset, len, in_tag, in_ssi_tag;
11714
11715 if (include_level > 10) {
11716 mg_cry_internal(conn, "SSI #include level is too deep (%s)", path);
11717 return;
11718 }
11719
11720 in_tag = in_ssi_tag = len = offset = 0;
11721
11722 /* Read file, byte by byte, and look for SSI include tags */
11723 while ((ch = mg_fgetc(filep, offset++)) != EOF) {
11724
11725 if (in_tag) {
11726 /* We are in a tag, either SSI tag or html tag */
11727
11728 if (ch == '>') {
11729 /* Tag is closing */
11730 buf[len++] = '>';
11731
11732 if (in_ssi_tag) {
11733 /* Handle SSI tag */
11734 buf[len] = 0;
11735
11736 if ((len > 12) && !memcmp(buf + 5, "include", 7)) {
11737 do_ssi_include(conn, path, buf + 12, include_level + 1);
11738#if !defined(NO_POPEN)
11739 } else if ((len > 9) && !memcmp(buf + 5, "exec", 4)) {
11740 do_ssi_exec(conn, buf + 9);
11741#endif /* !NO_POPEN */
11742 } else {
11743 mg_cry_internal(conn,
11744 "%s: unknown SSI "
11745 "command: \"%s\"",
11746 path,
11747 buf);
11748 }
11749 len = 0;
11750 in_ssi_tag = in_tag = 0;
11751
11752 } else {
11753 /* Not an SSI tag */
11754 /* Flush buffer */
11755 (void)mg_write(conn, buf, (size_t)len);
11756 len = 0;
11757 in_tag = 0;
11758 }
11759
11760 } else {
11761 /* Tag is still open */
11762 buf[len++] = (char)(ch & 0xff);
11763
11764 if ((len == 5) && !memcmp(buf, "<!--#", 5)) {
11765 /* All SSI tags start with <!--# */
11766 in_ssi_tag = 1;
11767 }
11768
11769 if ((len + 2) > (int)sizeof(buf)) {
11770 /* Tag to long for buffer */
11771 mg_cry_internal(conn, "%s: tag is too large", path);
11772 return;
11773 }
11774 }
11775
11776 } else {
11777
11778 /* We are not in a tag yet. */
11779 if (ch == '<') {
11780 /* Tag is opening */
11781 in_tag = 1;
11782
11783 if (len > 0) {
11784 /* Flush current buffer.
11785 * Buffer is filled with "len" bytes. */
11786 (void)mg_write(conn, buf, (size_t)len);
11787 }
11788 /* Store the < */
11789 len = 1;
11790 buf[0] = '<';
11791
11792 } else {
11793 /* No Tag */
11794 /* Add data to buffer */
11795 buf[len++] = (char)(ch & 0xff);
11796 /* Flush if buffer is full */
11797 if (len == (int)sizeof(buf)) {
11798 mg_write(conn, buf, (size_t)len);
11799 len = 0;
11800 }
11801 }
11802 }
11803 }
11804
11805 /* Send the rest of buffered data */
11806 if (len > 0) {
11807 mg_write(conn, buf, (size_t)len);
11808 }
11809}
11810
11811
11812static void
11814 const char *path,
11815 struct mg_file *filep)
11816{
11817 char date[64];
11818 time_t curtime = time(NULL);
11819 const char *cors1, *cors2, *cors3;
11820
11821 if ((conn == NULL) || (path == NULL) || (filep == NULL)) {
11822 return;
11823 }
11824
11825 if (mg_get_header(conn, "Origin")) {
11826 /* Cross-origin resource sharing (CORS). */
11827 cors1 = "Access-Control-Allow-Origin: ";
11829 cors3 = "\r\n";
11830 } else {
11831 cors1 = cors2 = cors3 = "";
11832 }
11833
11834 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
11835 /* File exists (precondition for calling this function),
11836 * but can not be opened by the server. */
11837 mg_send_http_error(conn,
11838 500,
11839 "Error: Cannot read file\nfopen(%s): %s",
11840 path,
11841 strerror(ERRNO));
11842 } else {
11843 conn->must_close = 1;
11844 gmt_time_string(date, sizeof(date), &curtime);
11845 fclose_on_exec(&filep->access, conn);
11846 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
11849 mg_printf(conn,
11850 "%s%s%s"
11851 "Date: %s\r\n"
11852 "Content-Type: text/html\r\n"
11853 "Connection: %s\r\n\r\n",
11854 cors1,
11855 cors2,
11856 cors3,
11857 date,
11859 send_ssi_file(conn, path, filep, 0);
11860 (void)mg_fclose(&filep->access); /* Ignore errors for readonly files */
11861 }
11862}
11863
11864
11865#if !defined(NO_FILES)
11866static void
11868{
11869 char date[64];
11870 time_t curtime = time(NULL);
11871
11872 if (!conn) {
11873 return;
11874 }
11875
11876 conn->status_code = 200;
11877 conn->must_close = 1;
11878 gmt_time_string(date, sizeof(date), &curtime);
11879
11880 /* We do not set a "Cache-Control" header here, but leave the default.
11881 * Since browsers do not send an OPTIONS request, we can not test the
11882 * effect anyway. */
11883 mg_printf(conn,
11884 "HTTP/1.1 200 OK\r\n"
11885 "Date: %s\r\n"
11886 "Connection: %s\r\n"
11887 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
11888 "PROPFIND, MKCOL\r\n"
11889 "DAV: 1\r\n",
11890 date,
11893 mg_printf(conn, "\r\n");
11894}
11895
11896
11897/* Writes PROPFIND properties for a collection element */
11898static void
11900 const char *uri,
11901 struct mg_file_stat *filep)
11902{
11903 char mtime[64];
11904
11905 if ((conn == NULL) || (uri == NULL) || (filep == NULL)) {
11906 return;
11907 }
11908
11909 gmt_time_string(mtime, sizeof(mtime), &filep->last_modified);
11910 mg_printf(conn,
11911 "<d:response>"
11912 "<d:href>%s</d:href>"
11913 "<d:propstat>"
11914 "<d:prop>"
11915 "<d:resourcetype>%s</d:resourcetype>"
11916 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
11917 "<d:getlastmodified>%s</d:getlastmodified>"
11918 "</d:prop>"
11919 "<d:status>HTTP/1.1 200 OK</d:status>"
11920 "</d:propstat>"
11921 "</d:response>\n",
11922 uri,
11923 filep->is_directory ? "<d:collection/>" : "",
11924 filep->size,
11925 mtime);
11926}
11927
11928
11929static int
11930print_dav_dir_entry(struct de *de, void *data)
11931{
11932 char href[PATH_MAX];
11933 int truncated;
11934
11935 struct mg_connection *conn = (struct mg_connection *)data;
11936 if (!de || !conn) {
11937 return -1;
11938 }
11939 mg_snprintf(conn,
11940 &truncated,
11941 href,
11942 sizeof(href),
11943 "%s%s",
11944 conn->request_info.local_uri,
11945 de->file_name);
11946
11947 if (!truncated) {
11948 size_t href_encoded_size;
11949 char *href_encoded;
11950
11951 href_encoded_size = PATH_MAX * 3; /* worst case */
11952 href_encoded = (char *)mg_malloc(href_encoded_size);
11953 if (href_encoded == NULL) {
11954 return -1;
11955 }
11956 mg_url_encode(href, href_encoded, href_encoded_size);
11957 print_props(conn, href_encoded, &de->file);
11958 mg_free(href_encoded);
11959 }
11960
11961 return 0;
11962}
11963
11964
11965static void
11967 const char *path,
11968 struct mg_file_stat *filep)
11969{
11970 const char *depth = mg_get_header(conn, "Depth");
11971 char date[64];
11972 time_t curtime = time(NULL);
11973
11974 gmt_time_string(date, sizeof(date), &curtime);
11975
11976 if (!conn || !path || !filep || !conn->dom_ctx) {
11977 return;
11978 }
11979
11980 conn->must_close = 1;
11981 conn->status_code = 207;
11982 mg_printf(conn,
11983 "HTTP/1.1 207 Multi-Status\r\n"
11984 "Date: %s\r\n",
11985 date);
11988 mg_printf(conn,
11989 "Connection: %s\r\n"
11990 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
11992
11993 mg_printf(conn,
11994 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
11995 "<d:multistatus xmlns:d='DAV:'>\n");
11996
11997 /* Print properties for the requested resource itself */
11998 print_props(conn, conn->request_info.local_uri, filep);
11999
12000 /* If it is a directory, print directory entries too if Depth is not 0
12001 */
12002 if (filep->is_directory
12004 "yes")
12005 && ((depth == NULL) || (strcmp(depth, "0") != 0))) {
12006 scan_directory(conn, path, conn, &print_dav_dir_entry);
12007 }
12008
12009 mg_printf(conn, "%s\n", "</d:multistatus>");
12010}
12011#endif
12012
12013void
12015{
12016 if (conn) {
12017 (void)pthread_mutex_lock(&conn->mutex);
12018 }
12019}
12020
12021void
12023{
12024 if (conn) {
12025 (void)pthread_mutex_unlock(&conn->mutex);
12026 }
12027}
12028
12029void
12031{
12032 if (ctx) {
12033 (void)pthread_mutex_lock(&ctx->nonce_mutex);
12034 }
12035}
12036
12037void
12039{
12040 if (ctx) {
12041 (void)pthread_mutex_unlock(&ctx->nonce_mutex);
12042 }
12043}
12044
12045
12046#if defined(USE_LUA)
12047#include "mod_lua.inl"
12048#endif /* USE_LUA */
12049
12050#if defined(USE_DUKTAPE)
12051#include "mod_duktape.inl"
12052#endif /* USE_DUKTAPE */
12053
12054#if defined(USE_WEBSOCKET)
12055
12056#if !defined(NO_SSL_DL)
12057#if !defined(OPENSSL_API_3_0)
12058#define SHA_API static
12059#include "sha1.inl"
12060#endif
12061#endif
12062
12063static int
12064send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
12065{
12066 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
12067 char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
12068#if !defined(OPENSSL_API_3_0)
12069 SHA_CTX sha_ctx;
12070#endif
12071 int truncated;
12072
12073 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
12074 mg_snprintf(conn, &truncated, buf, sizeof(buf), "%s%s", websock_key, magic);
12075 if (truncated) {
12076 conn->must_close = 1;
12077 return 0;
12078 }
12079
12080 DEBUG_TRACE("%s", "Send websocket handshake");
12081
12082#if defined(OPENSSL_API_3_0)
12083 EVP_Digest((unsigned char *)buf, (uint32_t)strlen(buf), (unsigned char *)sha,
12084 NULL, EVP_get_digestbyname("sha1"), NULL);
12085#else
12086 SHA1_Init(&sha_ctx);
12087 SHA1_Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
12088 SHA1_Final((unsigned char *)sha, &sha_ctx);
12089#endif
12090 base64_encode((unsigned char *)sha, sizeof(sha), b64_sha);
12091 mg_printf(conn,
12092 "HTTP/1.1 101 Switching Protocols\r\n"
12093 "Upgrade: websocket\r\n"
12094 "Connection: Upgrade\r\n"
12095 "Sec-WebSocket-Accept: %s\r\n",
12096 b64_sha);
12098 mg_printf(conn,
12099 "Sec-WebSocket-Protocol: %s\r\n\r\n",
12101 } else {
12102 mg_printf(conn, "%s", "\r\n");
12103 }
12104
12105 return 1;
12106}
12107
12108
12109#if !defined(MG_MAX_UNANSWERED_PING)
12110/* Configuration of the maximum number of websocket PINGs that might
12111 * stay unanswered before the connection is considered broken.
12112 * Note: The name of this define may still change (until it is
12113 * defined as a compile parameter in a documentation).
12114 */
12115#define MG_MAX_UNANSWERED_PING (5)
12116#endif
12117
12118
12119static void
12120read_websocket(struct mg_connection *conn,
12121 mg_websocket_data_handler ws_data_handler,
12122 void *callback_data)
12123{
12124 /* Pointer to the beginning of the portion of the incoming websocket
12125 * message queue.
12126 * The original websocket upgrade request is never removed, so the queue
12127 * begins after it. */
12128 unsigned char *buf = (unsigned char *)conn->buf + conn->request_len;
12129 int n, error, exit_by_callback;
12130 int ret;
12131
12132 /* body_len is the length of the entire queue in bytes
12133 * len is the length of the current message
12134 * data_len is the length of the current message's data payload
12135 * header_len is the length of the current message's header */
12136 size_t i, len, mask_len = 0, header_len, body_len;
12137 uint64_t data_len = 0;
12138
12139 /* "The masking key is a 32-bit value chosen at random by the client."
12140 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
12141 */
12142 unsigned char mask[4];
12143
12144 /* data points to the place where the message is stored when passed to
12145 * the websocket_data callback. This is either mem on the stack, or a
12146 * dynamically allocated buffer if it is too large. */
12147 unsigned char mem[4096];
12148 unsigned char mop; /* mask flag and opcode */
12149
12150
12151 /* Variables used for connection monitoring */
12152 double timeout = -1.0;
12153 int enable_ping_pong = 0;
12154 int ping_count = 0;
12155
12156 if (conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG]) {
12157 enable_ping_pong =
12158 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG],
12159 "yes");
12160 }
12161
12162 if (conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) {
12163 timeout = atoi(conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
12164 }
12165 if ((timeout <= 0.0) && (conn->dom_ctx->config[REQUEST_TIMEOUT])) {
12166 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
12167 }
12168
12169 /* Enter data processing loop */
12170 DEBUG_TRACE("Websocket connection %s:%u start data processing loop",
12173 conn->in_websocket_handling = 1;
12174 mg_set_thread_name("wsock");
12175
12176 /* Loop continuously, reading messages from the socket, invoking the
12177 * callback, and waiting repeatedly until an error occurs. */
12178 while (!conn->phys_ctx->stop_flag && !conn->must_close) {
12179 header_len = 0;
12180 DEBUG_ASSERT(conn->data_len >= conn->request_len);
12181 if ((body_len = (size_t)(conn->data_len - conn->request_len)) >= 2) {
12182 len = buf[1] & 127;
12183 mask_len = (buf[1] & 128) ? 4 : 0;
12184 if ((len < 126) && (body_len >= mask_len)) {
12185 /* inline 7-bit length field */
12186 data_len = len;
12187 header_len = 2 + mask_len;
12188 } else if ((len == 126) && (body_len >= (4 + mask_len))) {
12189 /* 16-bit length field */
12190 header_len = 4 + mask_len;
12191 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
12192 } else if (body_len >= (10 + mask_len)) {
12193 /* 64-bit length field */
12194 uint32_t l1, l2;
12195 memcpy(&l1, &buf[2], 4); /* Use memcpy for alignment */
12196 memcpy(&l2, &buf[6], 4);
12197 header_len = 10 + mask_len;
12198 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
12199
12200 if (data_len > (uint64_t)0x7FFF0000ul) {
12201 /* no can do */
12203 conn,
12204 "%s",
12205 "websocket out of memory; closing connection");
12206 break;
12207 }
12208 }
12209 }
12210
12211 if ((header_len > 0) && (body_len >= header_len)) {
12212 /* Allocate space to hold websocket payload */
12213 unsigned char *data = mem;
12214
12215 if ((size_t)data_len > (size_t)sizeof(mem)) {
12216 data = (unsigned char *)mg_malloc_ctx((size_t)data_len,
12217 conn->phys_ctx);
12218 if (data == NULL) {
12219 /* Allocation failed, exit the loop and then close the
12220 * connection */
12222 conn,
12223 "%s",
12224 "websocket out of memory; closing connection");
12225 break;
12226 }
12227 }
12228
12229 /* Copy the mask before we shift the queue and destroy it */
12230 if (mask_len > 0) {
12231 memcpy(mask, buf + header_len - mask_len, sizeof(mask));
12232 } else {
12233 memset(mask, 0, sizeof(mask));
12234 }
12235
12236 /* Read frame payload from the first message in the queue into
12237 * data and advance the queue by moving the memory in place. */
12238 DEBUG_ASSERT(body_len >= header_len);
12239 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
12240 mop = buf[0]; /* current mask and opcode */
12241 /* Overflow case */
12242 len = body_len - header_len;
12243 memcpy(data, buf + header_len, len);
12244 error = 0;
12245 while ((uint64_t)len < data_len) {
12246 n = pull_inner(NULL,
12247 conn,
12248 (char *)(data + len),
12249 (int)(data_len - len),
12250 timeout);
12251 if (n <= -2) {
12252 error = 1;
12253 break;
12254 } else if (n > 0) {
12255 len += (size_t)n;
12256 } else {
12257 /* Timeout: should retry */
12258 /* TODO: retry condition */
12259 }
12260 }
12261 if (error) {
12263 conn,
12264 "%s",
12265 "Websocket pull failed; closing connection");
12266 if (data != mem) {
12267 mg_free(data);
12268 }
12269 break;
12270 }
12271
12272 conn->data_len = conn->request_len;
12273
12274 } else {
12275
12276 mop = buf[0]; /* current mask and opcode, overwritten by
12277 * memmove() */
12278
12279 /* Length of the message being read at the front of the
12280 * queue. Cast to 31 bit is OK, since we limited
12281 * data_len before. */
12282 len = (size_t)data_len + header_len;
12283
12284 /* Copy the data payload into the data pointer for the
12285 * callback. Cast to 31 bit is OK, since we
12286 * limited data_len */
12287 memcpy(data, buf + header_len, (size_t)data_len);
12288
12289 /* Move the queue forward len bytes */
12290 memmove(buf, buf + len, body_len - len);
12291
12292 /* Mark the queue as advanced */
12293 conn->data_len -= (int)len;
12294 }
12295
12296 /* Apply mask if necessary */
12297 if (mask_len > 0) {
12298 for (i = 0; i < (size_t)data_len; i++) {
12299 data[i] ^= mask[i & 3];
12300 }
12301 }
12302
12303 exit_by_callback = 0;
12304 if (enable_ping_pong && ((mop & 0xF) == MG_WEBSOCKET_OPCODE_PONG)) {
12305 /* filter PONG messages */
12306 DEBUG_TRACE("PONG from %s:%u",
12309 /* No unanwered PINGs left */
12310 ping_count = 0;
12311 } else if (enable_ping_pong
12312 && ((mop & 0xF) == MG_WEBSOCKET_OPCODE_PING)) {
12313 /* reply PING messages */
12314 DEBUG_TRACE("Reply PING from %s:%u",
12317 ret = mg_websocket_write(conn,
12319 (char *)data,
12320 (size_t)data_len);
12321 if (ret <= 0) {
12322 /* Error: send failed */
12323 DEBUG_TRACE("Reply PONG failed (%i)", ret);
12324 break;
12325 }
12326
12327
12328 } else {
12329 /* Exit the loop if callback signals to exit (server side),
12330 * or "connection close" opcode received (client side). */
12331 if ((ws_data_handler != NULL)
12332 && !ws_data_handler(conn,
12333 mop,
12334 (char *)data,
12335 (size_t)data_len,
12336 callback_data)) {
12337 exit_by_callback = 1;
12338 }
12339 }
12340
12341 /* It a buffer has been allocated, free it again */
12342 if (data != mem) {
12343 mg_free(data);
12344 }
12345
12346 if (exit_by_callback) {
12347 DEBUG_TRACE("Callback requests to close connection from %s:%u",
12350 break;
12351 }
12352 if ((mop & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
12353 /* Opcode == 8, connection close */
12354 DEBUG_TRACE("Message requests to close connection from %s:%u",
12357 break;
12358 }
12359
12360 /* Not breaking the loop, process next websocket frame. */
12361 } else {
12362 /* Read from the socket into the next available location in the
12363 * message queue. */
12364 n = pull_inner(NULL,
12365 conn,
12366 conn->buf + conn->data_len,
12367 conn->buf_size - conn->data_len,
12368 timeout);
12369 if (n <= -2) {
12370 /* Error, no bytes read */
12371 DEBUG_TRACE("PULL from %s:%u failed",
12374 break;
12375 }
12376 if (n > 0) {
12377 conn->data_len += n;
12378 /* Reset open PING count */
12379 ping_count = 0;
12380 } else {
12381 if (!conn->phys_ctx->stop_flag && !conn->must_close) {
12382 if (ping_count > MG_MAX_UNANSWERED_PING) {
12383 /* Stop sending PING */
12384 DEBUG_TRACE("Too many (%i) unanswered ping from %s:%u "
12385 "- closing connection",
12386 ping_count,
12389 break;
12390 }
12391 if (enable_ping_pong) {
12392 /* Send Websocket PING message */
12393 DEBUG_TRACE("PING to %s:%u",
12396 ret = mg_websocket_write(conn,
12398 NULL,
12399 0);
12400
12401 if (ret <= 0) {
12402 /* Error: send failed */
12403 DEBUG_TRACE("Send PING failed (%i)", ret);
12404 break;
12405 }
12406 ping_count++;
12407 }
12408 }
12409 /* Timeout: should retry */
12410 /* TODO: get timeout def */
12411 }
12412 }
12413 }
12414
12415 /* Leave data processing loop */
12416 mg_set_thread_name("worker");
12417 conn->in_websocket_handling = 0;
12418 DEBUG_TRACE("Websocket connection %s:%u left data processing loop",
12421}
12422
12423
12424static int
12425mg_websocket_write_exec(struct mg_connection *conn,
12426 int opcode,
12427 const char *data,
12428 size_t dataLen,
12429 uint32_t masking_key)
12430{
12431 unsigned char header[14];
12432 size_t headerLen;
12433 int retval;
12434
12435#if defined(GCC_DIAGNOSTIC)
12436/* Disable spurious conversion warning for GCC */
12437#pragma GCC diagnostic push
12438#pragma GCC diagnostic ignored "-Wconversion"
12439#endif
12440
12441 header[0] = 0x80u | (unsigned char)((unsigned)opcode & 0xf);
12442
12443#if defined(GCC_DIAGNOSTIC)
12444#pragma GCC diagnostic pop
12445#endif
12446
12447 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
12448 if (dataLen < 126) {
12449 /* inline 7-bit length field */
12450 header[1] = (unsigned char)dataLen;
12451 headerLen = 2;
12452 } else if (dataLen <= 0xFFFF) {
12453 /* 16-bit length field */
12454 uint16_t len = htons((uint16_t)dataLen);
12455 header[1] = 126;
12456 memcpy(header + 2, &len, 2);
12457 headerLen = 4;
12458 } else {
12459 /* 64-bit length field */
12460 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
12461 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
12462 header[1] = 127;
12463 memcpy(header + 2, &len1, 4);
12464 memcpy(header + 6, &len2, 4);
12465 headerLen = 10;
12466 }
12467
12468 if (masking_key) {
12469 /* add mask */
12470 header[1] |= 0x80;
12471 memcpy(header + headerLen, &masking_key, 4);
12472 headerLen += 4;
12473 }
12474
12475 /* Note that POSIX/Winsock's send() is threadsafe
12476 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
12477 * but mongoose's mg_printf/mg_write is not (because of the loop in
12478 * push(), although that is only a problem if the packet is large or
12479 * outgoing buffer is full). */
12480
12481 /* TODO: Check if this lock should be moved to user land.
12482 * Currently the server sets this lock for websockets, but
12483 * not for any other connection. It must be set for every
12484 * conn read/written by more than one thread, no matter if
12485 * it is a websocket or regular connection. */
12486 (void)mg_lock_connection(conn);
12487
12488 retval = mg_write(conn, header, headerLen);
12489 if (retval != (int)headerLen) {
12490 /* Did not send complete header */
12491 retval = -1;
12492 } else {
12493 if (dataLen > 0) {
12494 retval = mg_write(conn, data, dataLen);
12495 }
12496 /* if dataLen == 0, the header length (2) is returned */
12497 }
12498
12499 /* TODO: Remove this unlock as well, when lock is removed. */
12501
12502 return retval;
12503}
12504
12505int
12507 int opcode,
12508 const char *data,
12509 size_t dataLen)
12510{
12511 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
12512}
12513
12514
12515static void
12516mask_data(const char *in, size_t in_len, uint32_t masking_key, char *out)
12517{
12518 size_t i = 0;
12519
12520 i = 0;
12521 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
12522 /* Convert in 32 bit words, if data is 4 byte aligned */
12523 while (i < (in_len - 3)) {
12524 *(uint32_t *)(void *)(out + i) =
12525 *(uint32_t *)(void *)(in + i) ^ masking_key;
12526 i += 4;
12527 }
12528 }
12529 if (i != in_len) {
12530 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
12531 while (i < in_len) {
12532 *(uint8_t *)(void *)(out + i) =
12533 *(uint8_t *)(void *)(in + i)
12534 ^ *(((uint8_t *)&masking_key) + (i % 4));
12535 i++;
12536 }
12537 }
12538}
12539
12540
12541int
12543 int opcode,
12544 const char *data,
12545 size_t dataLen)
12546{
12547 int retval = -1;
12548 char *masked_data =
12549 (char *)mg_malloc_ctx(((dataLen + 7) / 4) * 4, conn->phys_ctx);
12550 uint32_t masking_key = 0;
12551
12552 if (masked_data == NULL) {
12553 /* Return -1 in an error case */
12554 mg_cry_internal(conn,
12555 "%s",
12556 "Cannot allocate buffer for masked websocket response: "
12557 "Out of memory");
12558 return -1;
12559 }
12560
12561 do {
12562 /* Get a masking key - but not 0 */
12563 masking_key = (uint32_t)get_random();
12564 } while (masking_key == 0);
12565
12566 mask_data(data, dataLen, masking_key, masked_data);
12567
12568 retval = mg_websocket_write_exec(
12569 conn, opcode, masked_data, dataLen, masking_key);
12570 mg_free(masked_data);
12571
12572 return retval;
12573}
12574
12575
12576static void
12577handle_websocket_request(struct mg_connection *conn,
12578 const char *path,
12579 int is_callback_resource,
12580 struct mg_websocket_subprotocols *subprotocols,
12581 mg_websocket_connect_handler ws_connect_handler,
12582 mg_websocket_ready_handler ws_ready_handler,
12583 mg_websocket_data_handler ws_data_handler,
12584 mg_websocket_close_handler ws_close_handler,
12585 void *cbData)
12586{
12587 const char *websock_key = mg_get_header(conn, "Sec-WebSocket-Key");
12588 const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
12589 ptrdiff_t lua_websock = 0;
12590
12591#if !defined(USE_LUA)
12592 (void)path;
12593#endif
12594
12595 /* Step 1: Check websocket protocol version. */
12596 /* Step 1.1: Check Sec-WebSocket-Key. */
12597 if (!websock_key) {
12598 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
12599 * requires a Sec-WebSocket-Key header.
12600 */
12601 /* It could be the hixie draft version
12602 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
12603 */
12604 const char *key1 = mg_get_header(conn, "Sec-WebSocket-Key1");
12605 const char *key2 = mg_get_header(conn, "Sec-WebSocket-Key2");
12606 char key3[8];
12607
12608 if ((key1 != NULL) && (key2 != NULL)) {
12609 /* This version uses 8 byte body data in a GET request */
12610 conn->content_len = 8;
12611 if (8 == mg_read(conn, key3, 8)) {
12612 /* This is the hixie version */
12613 mg_send_http_error(conn,
12614 426,
12615 "%s",
12616 "Protocol upgrade to RFC 6455 required");
12617 return;
12618 }
12619 }
12620 /* This is an unknown version */
12621 mg_send_http_error(conn, 400, "%s", "Malformed websocket request");
12622 return;
12623 }
12624
12625 /* Step 1.2: Check websocket protocol version. */
12626 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
12627 if ((version == NULL) || (strcmp(version, "13") != 0)) {
12628 /* Reject wrong versions */
12629 mg_send_http_error(conn, 426, "%s", "Protocol upgrade required");
12630 return;
12631 }
12632
12633 /* Step 1.3: Could check for "Host", but we do not really nead this
12634 * value for anything, so just ignore it. */
12635
12636 /* Step 2: If a callback is responsible, call it. */
12637 if (is_callback_resource) {
12638 /* Step 2.1 check and select subprotocol */
12639 const char *protocols[64]; // max 64 headers
12640 int nbSubprotocolHeader = get_req_headers(&conn->request_info,
12641 "Sec-WebSocket-Protocol",
12642 protocols,
12643 64);
12644 if ((nbSubprotocolHeader > 0) && subprotocols) {
12645 int cnt = 0;
12646 int idx;
12647 unsigned long len;
12648 const char *sep, *curSubProtocol,
12649 *acceptedWebSocketSubprotocol = NULL;
12650
12651
12652 /* look for matching subprotocol */
12653 do {
12654 const char *protocol = protocols[cnt];
12655
12656 do {
12657 sep = strchr(protocol, ',');
12658 curSubProtocol = protocol;
12659 len = sep ? (unsigned long)(sep - protocol)
12660 : (unsigned long)strlen(protocol);
12661 while (sep && isspace(*++sep))
12662 ; // ignore leading whitespaces
12663 protocol = sep;
12664
12665
12666 for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
12667 if ((strlen(subprotocols->subprotocols[idx]) == len)
12668 && (strncmp(curSubProtocol,
12669 subprotocols->subprotocols[idx],
12670 len)
12671 == 0)) {
12672 acceptedWebSocketSubprotocol =
12673 subprotocols->subprotocols[idx];
12674 break;
12675 }
12676 }
12677 } while (sep && !acceptedWebSocketSubprotocol);
12678 } while (++cnt < nbSubprotocolHeader
12679 && !acceptedWebSocketSubprotocol);
12680
12682 acceptedWebSocketSubprotocol;
12683
12684 } else if (nbSubprotocolHeader > 0) {
12685 /* keep legacy behavior */
12686 const char *protocol = protocols[0];
12687
12688 /* The protocol is a comma separated list of names. */
12689 /* The server must only return one value from this list. */
12690 /* First check if it is a list or just a single value. */
12691 const char *sep = strrchr(protocol, ',');
12692 if (sep == NULL) {
12693 /* Just a single protocol -> accept it. */
12695 } else {
12696 /* Multiple protocols -> accept the last one. */
12697 /* This is just a quick fix if the client offers multiple
12698 * protocols. The handler should have a list of accepted
12699 * protocols on his own
12700 * and use it to select one protocol among those the client
12701 * has
12702 * offered.
12703 */
12704 while (isspace(*++sep)) {
12705 ; /* ignore leading whitespaces */
12706 }
12708 }
12709 }
12710
12711 if ((ws_connect_handler != NULL)
12712 && (ws_connect_handler(conn, cbData) != 0)) {
12713 /* C callback has returned non-zero, do not proceed with
12714 * handshake.
12715 */
12716 /* Note that C callbacks are no longer called when Lua is
12717 * responsible, so C can no longer filter callbacks for Lua. */
12718 return;
12719 }
12720 }
12721
12722#if defined(USE_LUA)
12723 /* Step 3: No callback. Check if Lua is responsible. */
12724 else {
12725 /* Step 3.1: Check if Lua is responsible. */
12726 if (conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
12727 lua_websock = match_prefix(
12728 conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS],
12729 strlen(conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
12730 path);
12731 }
12732
12733 if (lua_websock) {
12734 /* Step 3.2: Lua is responsible: call it. */
12735 conn->lua_websocket_state = lua_websocket_new(path, conn);
12736 if (!conn->lua_websocket_state) {
12737 /* Lua rejected the new client */
12738 return;
12739 }
12740 }
12741 }
12742#endif
12743
12744 /* Step 4: Check if there is a responsible websocket handler. */
12745 if (!is_callback_resource && !lua_websock) {
12746 /* There is no callback, and Lua is not responsible either. */
12747 /* Reply with a 404 Not Found. We are still at a standard
12748 * HTTP request here, before the websocket handshake, so
12749 * we can still send standard HTTP error replies. */
12750 mg_send_http_error(conn, 404, "%s", "Not found");
12751 return;
12752 }
12753
12754 /* Step 5: The websocket connection has been accepted */
12755 if (!send_websocket_handshake(conn, websock_key)) {
12756 mg_send_http_error(conn, 500, "%s", "Websocket handshake failed");
12757 return;
12758 }
12759
12760 /* Step 6: Call the ready handler */
12761 if (is_callback_resource) {
12762 if (ws_ready_handler != NULL) {
12763 ws_ready_handler(conn, cbData);
12764 }
12765#if defined(USE_LUA)
12766 } else if (lua_websock) {
12767 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
12768 /* the ready handler returned false */
12769 return;
12770 }
12771#endif
12772 }
12773
12774 /* Step 7: Enter the read loop */
12775 if (is_callback_resource) {
12776 read_websocket(conn, ws_data_handler, cbData);
12777#if defined(USE_LUA)
12778 } else if (lua_websock) {
12779 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
12780#endif
12781 }
12782
12783 /* Step 8: Call the close handler */
12784 if (ws_close_handler) {
12785 ws_close_handler(conn, cbData);
12786 }
12787}
12788
12789
12790static int
12791is_websocket_protocol(const struct mg_connection *conn)
12792{
12793 const char *upgrade, *connection;
12794
12795 /* A websocket protocoll has the following HTTP headers:
12796 *
12797 * Connection: Upgrade
12798 * Upgrade: Websocket
12799 */
12800
12801 upgrade = mg_get_header(conn, "Upgrade");
12802 if (upgrade == NULL) {
12803 return 0; /* fail early, don't waste time checking other header
12804 * fields
12805 */
12806 }
12807 if (!mg_strcasestr(upgrade, "websocket")) {
12808 return 0;
12809 }
12810
12811 connection = mg_get_header(conn, "Connection");
12812 if (connection == NULL) {
12813 return 0;
12814 }
12815 if (!mg_strcasestr(connection, "upgrade")) {
12816 return 0;
12817 }
12818
12819 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
12820 * "Sec-WebSocket-Version" are also required.
12821 * Don't check them here, since even an unsupported websocket protocol
12822 * request still IS a websocket request (in contrast to a standard HTTP
12823 * request). It will fail later in handle_websocket_request.
12824 */
12825
12826 return 1;
12827}
12828#endif /* !USE_WEBSOCKET */
12829
12830
12831static int
12833{
12834 return (n >= 0) && (n <= 255);
12835}
12836
12837
12838static int
12839parse_net(const char *spec, uint32_t *net, uint32_t *mask)
12840{
12841 int n, a, b, c, d, slash = 32, len = 0;
12842
12843 if (((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5)
12844 || (sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4))
12845 && isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && (slash >= 0)
12846 && (slash < 33)) {
12847 len = n;
12848 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
12849 | (uint32_t)d;
12850 *mask = slash ? (0xffffffffU << (32 - slash)) : 0;
12851 }
12852
12853 return len;
12854}
12855
12856
12857static int
12858set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
12859{
12860 int throttle = 0;
12861 struct vec vec, val;
12862 uint32_t net, mask;
12863 char mult;
12864 double v;
12865
12866 while ((spec = next_option(spec, &vec, &val)) != NULL) {
12867 mult = ',';
12868 if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1)
12869 || (v < 0)
12870 || ((lowercase(&mult) != 'k') && (lowercase(&mult) != 'm')
12871 && (mult != ','))) {
12872 continue;
12873 }
12874 v *= (lowercase(&mult) == 'k')
12875 ? 1024
12876 : ((lowercase(&mult) == 'm') ? 1048576 : 1);
12877 if (vec.len == 1 && vec.ptr[0] == '*') {
12878 throttle = (int)v;
12879 } else if (parse_net(vec.ptr, &net, &mask) > 0) {
12880 if ((remote_ip & mask) == net) {
12881 throttle = (int)v;
12882 }
12883 } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
12884 throttle = (int)v;
12885 }
12886 }
12887
12888 return throttle;
12889}
12890
12891
12892static uint32_t
12893get_remote_ip(const struct mg_connection *conn)
12894{
12895 if (!conn) {
12896 return 0;
12897 }
12898 return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr);
12899}
12900
12901
12902/* The mg_upload function is superseeded by mg_handle_form_request. */
12903#include "handle_form.inl"
12904
12905
12906#if defined(MG_LEGACY_INTERFACE)
12907/* Implement the deprecated mg_upload function by calling the new
12908 * mg_handle_form_request function. While mg_upload could only handle
12909 * HTML forms sent as POST request in multipart/form-data format
12910 * containing only file input elements, mg_handle_form_request can
12911 * handle all form input elements and all standard request methods. */
12912struct mg_upload_user_data {
12913 struct mg_connection *conn;
12914 const char *destination_dir;
12915 int num_uploaded_files;
12916};
12917
12918
12919/* Helper function for deprecated mg_upload. */
12920static int
12921mg_upload_field_found(const char *key,
12922 const char *filename,
12923 char *path,
12924 size_t pathlen,
12925 void *user_data)
12926{
12927 int truncated = 0;
12928 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
12929 (void)key;
12930
12931 if (!filename) {
12932 mg_cry_internal(fud->conn, "%s: No filename set", __func__);
12933 return FORM_FIELD_STORAGE_ABORT;
12934 }
12935 mg_snprintf(fud->conn,
12936 &truncated,
12937 path,
12938 pathlen - 1,
12939 "%s/%s",
12940 fud->destination_dir,
12941 filename);
12942 if (truncated) {
12943 mg_cry_internal(fud->conn, "%s: File path too long", __func__);
12944 return FORM_FIELD_STORAGE_ABORT;
12945 }
12946 return FORM_FIELD_STORAGE_STORE;
12947}
12948
12949
12950/* Helper function for deprecated mg_upload. */
12951static int
12952mg_upload_field_get(const char *key,
12953 const char *value,
12954 size_t value_size,
12955 void *user_data)
12956{
12957 /* Function should never be called */
12958 (void)key;
12959 (void)value;
12960 (void)value_size;
12961 (void)user_data;
12962
12963 return 0;
12964}
12965
12966
12967/* Helper function for deprecated mg_upload. */
12968static int
12969mg_upload_field_stored(const char *path, long long file_size, void *user_data)
12970{
12971 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
12972 (void)file_size;
12973
12974 fud->num_uploaded_files++;
12975 fud->conn->phys_ctx->callbacks.upload(fud->conn, path);
12976
12977 return 0;
12978}
12979
12980
12981/* Deprecated function mg_upload - use mg_handle_form_request instead. */
12982int
12983mg_upload(struct mg_connection *conn, const char *destination_dir)
12984{
12985 struct mg_upload_user_data fud = {conn, destination_dir, 0};
12986 struct mg_form_data_handler fdh = {mg_upload_field_found,
12987 mg_upload_field_get,
12988 mg_upload_field_stored,
12989 0};
12990 int ret;
12991
12992 fdh.user_data = (void *)&fud;
12993 ret = mg_handle_form_request(conn, &fdh);
12994
12995 if (ret < 0) {
12996 mg_cry_internal(conn, "%s: Error while parsing the request", __func__);
12997 }
12998
12999 return fud.num_uploaded_files;
13000}
13001#endif
13002
13003
13004static int
13006{
13007 unsigned int i;
13008 int idx = -1;
13009 if (ctx) {
13010 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
13011 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
13012 }
13013 }
13014 return idx;
13015}
13016
13017
13018/* Return host (without port) */
13019/* Use mg_free to free the result */
13020static const char *
13022{
13023 char buf[1025];
13024 size_t buflen = sizeof(buf);
13025 const char *host_header = get_header(conn->request_info.http_headers,
13027 "Host");
13028 char *host;
13029
13030 if (host_header != NULL) {
13031 char *pos;
13032
13033 /* Create a local copy of the "Host" header, since it might be
13034 * modified here. */
13035 mg_strlcpy(buf, host_header, buflen);
13036 buf[buflen - 1] = '\0';
13037 host = buf;
13038 while (isspace(*host)) {
13039 host++;
13040 }
13041
13042 /* If the "Host" is an IPv6 address, like [::1], parse until ]
13043 * is found. */
13044 if (*host == '[') {
13045 pos = strchr(host, ']');
13046 if (!pos) {
13047 /* Malformed hostname starts with '[', but no ']' found */
13048 DEBUG_TRACE("%s", "Host name format error '[' without ']'");
13049 return NULL;
13050 }
13051 /* terminate after ']' */
13052 pos[1] = 0;
13053 } else {
13054 /* Otherwise, a ':' separates hostname and port number */
13055 pos = strchr(host, ':');
13056 if (pos != NULL) {
13057 *pos = '\0';
13058 }
13059 }
13060
13061 if (conn->ssl) {
13062 /* This is a HTTPS connection, maybe we have a hostname
13063 * from SNI (set in ssl_servername_callback). */
13064 const char *sslhost = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
13065 if (sslhost && (conn->dom_ctx != &(conn->phys_ctx->dd))) {
13066 /* We are not using the default domain */
13067 if (mg_strcasecmp(host, sslhost)) {
13068 /* Mismatch between SNI domain and HTTP domain */
13069 DEBUG_TRACE("Host mismatch: SNI: %s, HTTPS: %s",
13070 sslhost,
13071 host);
13072 return NULL;
13073 }
13074 }
13075 DEBUG_TRACE("HTTPS Host: %s", host);
13076
13077 } else {
13078 struct mg_domain_context *dom = &(conn->phys_ctx->dd);
13079 while (dom) {
13080 if (!mg_strcasecmp(host, dom->config[AUTHENTICATION_DOMAIN])) {
13081
13082 /* Found matching domain */
13083 DEBUG_TRACE("HTTP domain %s found",
13085
13086 /* TODO: Check if this is a HTTP or HTTPS domain */
13087 conn->dom_ctx = dom;
13088 break;
13089 }
13090 dom = dom->next;
13091 }
13092
13093 DEBUG_TRACE("HTTP Host: %s", host);
13094 }
13095
13096 } else {
13097 sockaddr_to_string(buf, buflen, &conn->client.lsa);
13098 host = buf;
13099
13100 DEBUG_TRACE("IP: %s", host);
13101 }
13102
13103 return mg_strdup_ctx(host, conn->phys_ctx);
13104}
13105
13106
13107static void
13108redirect_to_https_port(struct mg_connection *conn, int ssl_index)
13109{
13110 char target_url[MG_BUF_LEN];
13111 int truncated = 0;
13112
13113 conn->must_close = 1;
13114
13115 /* Send host, port, uri and (if it exists) ?query_string */
13116 if (conn->host) {
13117
13118 /* Use "308 Permanent Redirect" */
13119 int redirect_code = 308;
13120
13121 /* Create target URL */
13123 conn,
13124 &truncated,
13125 target_url,
13126 sizeof(target_url),
13127 "https://%s:%d%s%s%s",
13128
13129 conn->host,
13130#if defined(USE_IPV6)
13131 (conn->phys_ctx->listening_sockets[ssl_index].lsa.sa.sa_family
13132 == AF_INET6)
13133 ? (int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13134 .lsa.sin6.sin6_port)
13135 :
13136#endif
13137 (int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13138 .lsa.sin.sin_port),
13139 conn->request_info.local_uri,
13140 (conn->request_info.query_string == NULL) ? "" : "?",
13141 (conn->request_info.query_string == NULL)
13142 ? ""
13143 : conn->request_info.query_string);
13144
13145 /* Check overflow in location buffer (will not occur if MG_BUF_LEN
13146 * is used as buffer size) */
13147 if (truncated) {
13148 mg_send_http_error(conn, 500, "%s", "Redirect URL too long");
13149 return;
13150 }
13151
13152 /* Use redirect helper function */
13153 mg_send_http_redirect(conn, target_url, redirect_code);
13154 }
13155}
13156
13157
13158static void
13160{
13161 pthread_mutex_lock(&handler_info->refcount_mutex);
13162 handler_info->refcount++;
13163 pthread_mutex_unlock(&handler_info->refcount_mutex);
13164}
13165
13166
13167static void
13169{
13170 pthread_mutex_lock(&handler_info->refcount_mutex);
13171 handler_info->refcount--;
13172 pthread_cond_signal(&handler_info->refcount_cond);
13173 pthread_mutex_unlock(&handler_info->refcount_mutex);
13174}
13175
13176
13177static void
13179{
13180 pthread_mutex_lock(&handler_info->refcount_mutex);
13181 while (handler_info->refcount) {
13182 pthread_cond_wait(&handler_info->refcount_cond,
13183 &handler_info->refcount_mutex);
13184 }
13185 pthread_mutex_unlock(&handler_info->refcount_mutex);
13186}
13187
13188
13189static void
13191 struct mg_domain_context *dom_ctx,
13192 const char *uri,
13193 int handler_type,
13194 int is_delete_request,
13195 mg_request_handler handler,
13196 struct mg_websocket_subprotocols *subprotocols,
13197 mg_websocket_connect_handler connect_handler,
13198 mg_websocket_ready_handler ready_handler,
13199 mg_websocket_data_handler data_handler,
13200 mg_websocket_close_handler close_handler,
13201 mg_authorization_handler auth_handler,
13202 void *cbdata)
13203{
13204 struct mg_handler_info *tmp_rh, **lastref;
13205 size_t urilen = strlen(uri);
13206
13208 DEBUG_ASSERT(handler == NULL);
13209 DEBUG_ASSERT(is_delete_request || connect_handler != NULL
13210 || ready_handler != NULL || data_handler != NULL
13211 || close_handler != NULL);
13212
13213 DEBUG_ASSERT(auth_handler == NULL);
13214 if (handler != NULL) {
13215 return;
13216 }
13217 if (!is_delete_request && (connect_handler == NULL)
13218 && (ready_handler == NULL) && (data_handler == NULL)
13219 && (close_handler == NULL)) {
13220 return;
13221 }
13222 if (auth_handler != NULL) {
13223 return;
13224 }
13225 } else if (handler_type == REQUEST_HANDLER) {
13226 DEBUG_ASSERT(connect_handler == NULL && ready_handler == NULL
13227 && data_handler == NULL && close_handler == NULL);
13228 DEBUG_ASSERT(is_delete_request || (handler != NULL));
13229 DEBUG_ASSERT(auth_handler == NULL);
13230
13231 if ((connect_handler != NULL) || (ready_handler != NULL)
13232 || (data_handler != NULL) || (close_handler != NULL)) {
13233 return;
13234 }
13235 if (!is_delete_request && (handler == NULL)) {
13236 return;
13237 }
13238 if (auth_handler != NULL) {
13239 return;
13240 }
13241 } else { /* AUTH_HANDLER */
13242 DEBUG_ASSERT(handler == NULL);
13243 DEBUG_ASSERT(connect_handler == NULL && ready_handler == NULL
13244 && data_handler == NULL && close_handler == NULL);
13245 DEBUG_ASSERT(auth_handler != NULL);
13246 if (handler != NULL) {
13247 return;
13248 }
13249 if ((connect_handler != NULL) || (ready_handler != NULL)
13250 || (data_handler != NULL) || (close_handler != NULL)) {
13251 return;
13252 }
13253 if (!is_delete_request && (auth_handler == NULL)) {
13254 return;
13255 }
13256 }
13257
13258 if (!phys_ctx || !dom_ctx) {
13259 return;
13260 }
13261
13262 mg_lock_context(phys_ctx);
13263
13264 /* first try to find an existing handler */
13265 lastref = &(dom_ctx->handlers);
13266 for (tmp_rh = dom_ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
13267 if (tmp_rh->handler_type == handler_type) {
13268 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13269 if (!is_delete_request) {
13270 /* update existing handler */
13272 /* Wait for end of use before updating */
13274
13275 /* Ok, the handler is no more use -> Update it */
13276 tmp_rh->handler = handler;
13277 } else if (handler_type == WEBSOCKET_HANDLER) {
13278 tmp_rh->subprotocols = subprotocols;
13280 tmp_rh->ready_handler = ready_handler;
13281 tmp_rh->data_handler = data_handler;
13282 tmp_rh->close_handler = close_handler;
13283 } else { /* AUTH_HANDLER */
13284 tmp_rh->auth_handler = auth_handler;
13285 }
13286 tmp_rh->cbdata = cbdata;
13287 } else {
13288 /* remove existing handler */
13290 /* Wait for end of use before removing */
13292
13293 /* Ok, the handler is no more used -> Destroy resources
13294 */
13295 pthread_cond_destroy(&tmp_rh->refcount_cond);
13296 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13297 }
13298 *lastref = tmp_rh->next;
13299 mg_free(tmp_rh->uri);
13300 mg_free(tmp_rh);
13301 }
13302 mg_unlock_context(phys_ctx);
13303 return;
13304 }
13305 }
13306 lastref = &(tmp_rh->next);
13307 }
13308
13309 if (is_delete_request) {
13310 /* no handler to set, this was a remove request to a non-existing
13311 * handler */
13312 mg_unlock_context(phys_ctx);
13313 return;
13314 }
13315
13316 tmp_rh =
13317 (struct mg_handler_info *)mg_calloc_ctx(sizeof(struct mg_handler_info),
13318 1,
13319 phys_ctx);
13320 if (tmp_rh == NULL) {
13321 mg_unlock_context(phys_ctx);
13322 mg_cry_internal(fc(phys_ctx),
13323 "%s",
13324 "Cannot create new request handler struct, OOM");
13325 return;
13326 }
13327 tmp_rh->uri = mg_strdup_ctx(uri, phys_ctx);
13328 if (!tmp_rh->uri) {
13329 mg_unlock_context(phys_ctx);
13330 mg_free(tmp_rh);
13331 mg_cry_internal(fc(phys_ctx),
13332 "%s",
13333 "Cannot create new request handler struct, OOM");
13334 return;
13335 }
13336 tmp_rh->uri_len = urilen;
13338 /* Init refcount mutex and condition */
13339 if (0 != pthread_mutex_init(&tmp_rh->refcount_mutex, NULL)) {
13340 mg_unlock_context(phys_ctx);
13341 mg_free(tmp_rh);
13342 mg_cry_internal(fc(phys_ctx), "%s", "Cannot init refcount mutex");
13343 return;
13344 }
13345 if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
13346 mg_unlock_context(phys_ctx);
13347 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13348 mg_free(tmp_rh);
13349 mg_cry_internal(fc(phys_ctx), "%s", "Cannot init refcount cond");
13350 return;
13351 }
13352 tmp_rh->refcount = 0;
13353 tmp_rh->handler = handler;
13354 } else if (handler_type == WEBSOCKET_HANDLER) {
13355 tmp_rh->subprotocols = subprotocols;
13357 tmp_rh->ready_handler = ready_handler;
13358 tmp_rh->data_handler = data_handler;
13359 tmp_rh->close_handler = close_handler;
13360 } else { /* AUTH_HANDLER */
13361 tmp_rh->auth_handler = auth_handler;
13362 }
13363 tmp_rh->cbdata = cbdata;
13364 tmp_rh->handler_type = handler_type;
13365 tmp_rh->next = NULL;
13366
13367 *lastref = tmp_rh;
13368 mg_unlock_context(phys_ctx);
13369}
13370
13371
13372void
13374 const char *uri,
13376 void *cbdata)
13377{
13379 &(ctx->dd),
13380 uri,
13382 handler == NULL,
13383 handler,
13384 NULL,
13385 NULL,
13386 NULL,
13387 NULL,
13388 NULL,
13389 NULL,
13390 cbdata);
13391}
13392
13393
13394void
13396 const char *uri,
13401 void *cbdata)
13402{
13404 uri,
13405 NULL,
13410 cbdata);
13411}
13412
13413
13414void
13416 struct mg_context *ctx,
13417 const char *uri,
13423 void *cbdata)
13424{
13425 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
13426 && (data_handler == NULL)
13427 && (close_handler == NULL);
13429 &(ctx->dd),
13430 uri,
13432 is_delete_request,
13433 NULL,
13439 NULL,
13440 cbdata);
13441}
13442
13443
13444void
13446 const char *uri,
13448 void *cbdata)
13449{
13451 &(ctx->dd),
13452 uri,
13454 handler == NULL,
13455 NULL,
13456 NULL,
13457 NULL,
13458 NULL,
13459 NULL,
13460 NULL,
13461 handler,
13462 cbdata);
13463}
13464
13465
13466static int
13468 int handler_type,
13476 void **cbdata,
13477 struct mg_handler_info **handler_info)
13478{
13479 const struct mg_request_info *request_info = mg_get_request_info(conn);
13480 if (request_info) {
13481 const char *uri = request_info->local_uri;
13482 size_t urilen = strlen(uri);
13483 struct mg_handler_info *tmp_rh;
13484
13485 if (!conn || !conn->phys_ctx || !conn->dom_ctx) {
13486 return 0;
13487 }
13488
13490
13491 /* first try for an exact match */
13492 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13493 tmp_rh = tmp_rh->next) {
13494 if (tmp_rh->handler_type == handler_type) {
13495 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13497 *subprotocols = tmp_rh->subprotocols;
13499 *ready_handler = tmp_rh->ready_handler;
13500 *data_handler = tmp_rh->data_handler;
13501 *close_handler = tmp_rh->close_handler;
13502 } else if (handler_type == REQUEST_HANDLER) {
13503 *handler = tmp_rh->handler;
13504 /* Acquire handler and give it back */
13505 handler_info_acquire(tmp_rh);
13506 *handler_info = tmp_rh;
13507 } else { /* AUTH_HANDLER */
13508 *auth_handler = tmp_rh->auth_handler;
13509 }
13510 *cbdata = tmp_rh->cbdata;
13512 return 1;
13513 }
13514 }
13515 }
13516
13517 /* next try for a partial match, we will accept uri/something */
13518 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13519 tmp_rh = tmp_rh->next) {
13520 if (tmp_rh->handler_type == handler_type) {
13521 if ((tmp_rh->uri_len < urilen) && (uri[tmp_rh->uri_len] == '/')
13522 && (memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0)) {
13524 *subprotocols = tmp_rh->subprotocols;
13526 *ready_handler = tmp_rh->ready_handler;
13527 *data_handler = tmp_rh->data_handler;
13528 *close_handler = tmp_rh->close_handler;
13529 } else if (handler_type == REQUEST_HANDLER) {
13530 *handler = tmp_rh->handler;
13531 /* Acquire handler and give it back */
13532 handler_info_acquire(tmp_rh);
13533 *handler_info = tmp_rh;
13534 } else { /* AUTH_HANDLER */
13535 *auth_handler = tmp_rh->auth_handler;
13536 }
13537 *cbdata = tmp_rh->cbdata;
13539 return 1;
13540 }
13541 }
13542 }
13543
13544 /* finally try for pattern match */
13545 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13546 tmp_rh = tmp_rh->next) {
13547 if (tmp_rh->handler_type == handler_type) {
13548 if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
13550 *subprotocols = tmp_rh->subprotocols;
13552 *ready_handler = tmp_rh->ready_handler;
13553 *data_handler = tmp_rh->data_handler;
13554 *close_handler = tmp_rh->close_handler;
13555 } else if (handler_type == REQUEST_HANDLER) {
13556 *handler = tmp_rh->handler;
13557 /* Acquire handler and give it back */
13558 handler_info_acquire(tmp_rh);
13559 *handler_info = tmp_rh;
13560 } else { /* AUTH_HANDLER */
13561 *auth_handler = tmp_rh->auth_handler;
13562 }
13563 *cbdata = tmp_rh->cbdata;
13565 return 1;
13566 }
13567 }
13568 }
13569
13571 }
13572 return 0; /* none found */
13573}
13574
13575
13576/* Check if the script file is in a path, allowed for script files.
13577 * This can be used if uploading files is possible not only for the server
13578 * admin, and the upload mechanism does not check the file extension.
13579 */
13580static int
13581is_in_script_path(const struct mg_connection *conn, const char *path)
13582{
13583 /* TODO (Feature): Add config value for allowed script path.
13584 * Default: All allowed. */
13585 (void)conn;
13586 (void)path;
13587 return 1;
13588}
13589
13590
13591#if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
13592static int
13593deprecated_websocket_connect_wrapper(const struct mg_connection *conn,
13594 void *cbdata)
13595{
13596 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
13597 if (pcallbacks->websocket_connect) {
13598 return pcallbacks->websocket_connect(conn);
13599 }
13600 /* No handler set - assume "OK" */
13601 return 0;
13602}
13603
13604
13605static void
13606deprecated_websocket_ready_wrapper(struct mg_connection *conn, void *cbdata)
13607{
13608 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
13609 if (pcallbacks->websocket_ready) {
13610 pcallbacks->websocket_ready(conn);
13611 }
13612}
13613
13614
13615static int
13616deprecated_websocket_data_wrapper(struct mg_connection *conn,
13617 int bits,
13618 char *data,
13619 size_t len,
13620 void *cbdata)
13621{
13622 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
13623 if (pcallbacks->websocket_data) {
13624 return pcallbacks->websocket_data(conn, bits, data, len);
13625 }
13626 /* No handler set - assume "OK" */
13627 return 1;
13628}
13629#endif
13630
13631
13632/* This is the heart of the Civetweb's logic.
13633 * This function is called when the request is read, parsed and validated,
13634 * and Civetweb must decide what action to take: serve a file, or
13635 * a directory, or call embedded function, etcetera. */
13636static void
13638{
13639 struct mg_request_info *ri = &conn->request_info;
13640 char path[PATH_MAX];
13641 int uri_len, ssl_index;
13642 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
13643 is_put_or_delete_request = 0, is_callback_resource = 0;
13644 int i;
13646 mg_request_handler callback_handler = NULL;
13647 struct mg_handler_info *handler_info = NULL;
13649 mg_websocket_connect_handler ws_connect_handler = NULL;
13650 mg_websocket_ready_handler ws_ready_handler = NULL;
13651 mg_websocket_data_handler ws_data_handler = NULL;
13652 mg_websocket_close_handler ws_close_handler = NULL;
13653 void *callback_data = NULL;
13654 mg_authorization_handler auth_handler = NULL;
13655 void *auth_callback_data = NULL;
13656 int handler_type;
13657 time_t curtime = time(NULL);
13658 char date[64];
13659
13660 path[0] = 0;
13661
13662 /* 1. get the request url */
13663 /* 1.1. split into url and query string */
13664 if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
13665 != NULL) {
13666 *((char *)conn->request_info.query_string++) = '\0';
13667 }
13668
13669 /* 1.2. do a https redirect, if required. Do not decode URIs yet. */
13670 if (!conn->client.is_ssl && conn->client.ssl_redir) {
13671 ssl_index = get_first_ssl_listener_index(conn->phys_ctx);
13672 if (ssl_index >= 0) {
13673 redirect_to_https_port(conn, ssl_index);
13674 } else {
13675 /* A http to https forward port has been specified,
13676 * but no https port to forward to. */
13677 mg_send_http_error(conn,
13678 503,
13679 "%s",
13680 "Error: SSL forward not configured properly");
13681 mg_cry_internal(conn,
13682 "%s",
13683 "Can not redirect to SSL, no SSL port available");
13684 }
13685 return;
13686 }
13687 uri_len = (int)strlen(ri->local_uri);
13688
13689 /* 1.3. decode url (if config says so) */
13690 if (should_decode_url(conn)) {
13692 ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
13693 }
13694
13695 /* 1.4. clean URIs, so a path like allowed_dir/../forbidden_file is
13696 * not possible */
13698
13699 /* step 1. completed, the url is known now */
13700 uri_len = (int)strlen(ri->local_uri);
13701 DEBUG_TRACE("URL: %s", ri->local_uri);
13702
13703 /* 2. if this ip has limited speed, set it for this connection */
13705 get_remote_ip(conn),
13706 ri->local_uri);
13707
13708 /* 3. call a "handle everything" callback, if registered */
13709 if (conn->phys_ctx->callbacks.begin_request != NULL) {
13710 /* Note that since V1.7 the "begin_request" function is called
13711 * before an authorization check. If an authorization check is
13712 * required, use a request_handler instead. */
13713 i = conn->phys_ctx->callbacks.begin_request(conn);
13714 if (i > 0) {
13715 /* callback already processed the request. Store the
13716 return value as a status code for the access log. */
13717 conn->status_code = i;
13719 return;
13720 } else if (i == 0) {
13721 /* civetweb should process the request */
13722 } else {
13723 /* unspecified - may change with the next version */
13724 return;
13725 }
13726 }
13727
13728 /* request not yet handled by a handler or redirect, so the request
13729 * is processed here */
13730
13731 /* 4. Check for CORS preflight requests and handle them (if configured).
13732 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
13733 */
13734 if (!strcmp(ri->request_method, "OPTIONS")) {
13735 /* Send a response to CORS preflights only if
13736 * access_control_allow_methods is not NULL and not an empty string.
13737 * In this case, scripts can still handle CORS. */
13738 const char *cors_meth_cfg =
13740 const char *cors_orig_cfg =
13742 const char *cors_origin =
13743 get_header(ri->http_headers, ri->num_headers, "Origin");
13744 const char *cors_acrm = get_header(ri->http_headers,
13745 ri->num_headers,
13746 "Access-Control-Request-Method");
13747
13748 /* Todo: check if cors_origin is in cors_orig_cfg.
13749 * Or, let the client check this. */
13750
13751 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
13752 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
13753 && (cors_origin != NULL) && (cors_acrm != NULL)) {
13754 /* This is a valid CORS preflight, and the server is configured
13755 * to
13756 * handle it automatically. */
13757 const char *cors_acrh =
13759 ri->num_headers,
13760 "Access-Control-Request-Headers");
13761
13762 gmt_time_string(date, sizeof(date), &curtime);
13763 mg_printf(conn,
13764 "HTTP/1.1 200 OK\r\n"
13765 "Date: %s\r\n"
13766 "Access-Control-Allow-Origin: %s\r\n"
13767 "Access-Control-Allow-Methods: %s\r\n"
13768 "Content-Length: 0\r\n"
13769 "Connection: %s\r\n",
13770 date,
13771 cors_orig_cfg,
13772 ((cors_meth_cfg[0] == '*') ? cors_acrm : cors_meth_cfg),
13774
13775 if (cors_acrh != NULL) {
13776 /* CORS request is asking for additional headers */
13777 const char *cors_hdr_cfg =
13779
13780 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
13781 /* Allow only if access_control_allow_headers is
13782 * not NULL and not an empty string. If this
13783 * configuration is set to *, allow everything.
13784 * Otherwise this configuration must be a list
13785 * of allowed HTTP header names. */
13786 mg_printf(conn,
13787 "Access-Control-Allow-Headers: %s\r\n",
13788 ((cors_hdr_cfg[0] == '*') ? cors_acrh
13789 : cors_hdr_cfg));
13790 }
13791 }
13792 mg_printf(conn, "Access-Control-Max-Age: 60\r\n");
13793
13794 mg_printf(conn, "\r\n");
13795 return;
13796 }
13797 }
13798
13799 /* 5. interpret the url to find out how the request must be handled
13800 */
13801 /* 5.1. first test, if the request targets the regular http(s)://
13802 * protocol namespace or the websocket ws(s):// protocol namespace.
13803 */
13804 is_websocket_request = is_websocket_protocol(conn);
13805#if defined(USE_WEBSOCKET)
13806 handler_type = is_websocket_request ? WEBSOCKET_HANDLER : REQUEST_HANDLER;
13807#else
13808 handler_type = REQUEST_HANDLER;
13809#endif /* defined(USE_WEBSOCKET) */
13810 /* 5.2. check if the request will be handled by a callback */
13811 if (get_request_handler(conn,
13812 handler_type,
13813 &callback_handler,
13814 &subprotocols,
13815 &ws_connect_handler,
13816 &ws_ready_handler,
13817 &ws_data_handler,
13818 &ws_close_handler,
13819 NULL,
13820 &callback_data,
13821 &handler_info)) {
13822 /* 5.2.1. A callback will handle this request. All requests
13823 * handled
13824 * by a callback have to be considered as requests to a script
13825 * resource. */
13826 is_callback_resource = 1;
13827 is_script_resource = 1;
13828 is_put_or_delete_request = is_put_or_delete_method(conn);
13829 } else {
13830 no_callback_resource:
13831
13832 /* 5.2.2. No callback is responsible for this request. The URI
13833 * addresses a file based resource (static content or Lua/cgi
13834 * scripts in the file system). */
13835 is_callback_resource = 0;
13836 interpret_uri(conn,
13837 path,
13838 sizeof(path),
13839 &file.stat,
13840 &is_found,
13841 &is_script_resource,
13842 &is_websocket_request,
13843 &is_put_or_delete_request);
13844 }
13845
13846 /* 6. authorization check */
13847 /* 6.1. a custom authorization handler is installed */
13848 if (get_request_handler(conn,
13850 NULL,
13851 NULL,
13852 NULL,
13853 NULL,
13854 NULL,
13855 NULL,
13856 &auth_handler,
13857 &auth_callback_data,
13858 NULL)) {
13859 if (!auth_handler(conn, auth_callback_data)) {
13860 return;
13861 }
13862 } else if (is_put_or_delete_request && !is_script_resource
13863 && !is_callback_resource) {
13864/* 6.2. this request is a PUT/DELETE to a real file */
13865/* 6.2.1. thus, the server must have real files */
13866#if defined(NO_FILES)
13867 if (1) {
13868#else
13869 if (conn->dom_ctx->config[DOCUMENT_ROOT] == NULL) {
13870#endif
13871 /* This server does not have any real files, thus the
13872 * PUT/DELETE methods are not valid. */
13873 mg_send_http_error(conn,
13874 405,
13875 "%s method not allowed",
13877 return;
13878 }
13879
13880#if !defined(NO_FILES)
13881 /* 6.2.2. Check if put authorization for static files is
13882 * available.
13883 */
13884 if (!is_authorized_for_put(conn)) {
13885 send_authorization_request(conn, NULL);
13886 return;
13887 }
13888#endif
13889
13890 } else {
13891 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
13892 * or it is a PUT or DELETE request to a resource that does not
13893 * correspond to a file. Check authorization. */
13894 if (!check_authorization(conn, path)) {
13895 send_authorization_request(conn, NULL);
13896 return;
13897 }
13898 }
13899
13900 /* request is authorized or does not need authorization */
13901
13902 /* 7. check if there are request handlers for this uri */
13903 if (is_callback_resource) {
13904 if (!is_websocket_request) {
13905 i = callback_handler(conn, callback_data);
13906
13907 /* Callback handler will not be used anymore. Release it */
13908 handler_info_release(handler_info);
13909
13910 if (i > 0) {
13911 /* Do nothing, callback has served the request. Store
13912 * then return value as status code for the log and discard
13913 * all data from the client not used by the callback. */
13914 conn->status_code = i;
13916 } else {
13917 /* The handler did NOT handle the request. */
13918 /* Some proper reactions would be:
13919 * a) close the connections without sending anything
13920 * b) send a 404 not found
13921 * c) try if there is a file matching the URI
13922 * It would be possible to do a, b or c in the callback
13923 * implementation, and return 1 - we cannot do anything
13924 * here, that is not possible in the callback.
13925 *
13926 * TODO: What would be the best reaction here?
13927 * (Note: The reaction may change, if there is a better
13928 *idea.)
13929 */
13930
13931 /* For the moment, use option c: We look for a proper file,
13932 * but since a file request is not always a script resource,
13933 * the authorization check might be different. */
13934 interpret_uri(conn,
13935 path,
13936 sizeof(path),
13937 &file.stat,
13938 &is_found,
13939 &is_script_resource,
13940 &is_websocket_request,
13941 &is_put_or_delete_request);
13942 callback_handler = NULL;
13943
13944 /* Here we are at a dead end:
13945 * According to URI matching, a callback should be
13946 * responsible for handling the request,
13947 * we called it, but the callback declared itself
13948 * not responsible.
13949 * We use a goto here, to get out of this dead end,
13950 * and continue with the default handling.
13951 * A goto here is simpler and better to understand
13952 * than some curious loop. */
13953 goto no_callback_resource;
13954 }
13955 } else {
13956#if defined(USE_WEBSOCKET)
13957 handle_websocket_request(conn,
13958 path,
13959 is_callback_resource,
13961 ws_connect_handler,
13962 ws_ready_handler,
13963 ws_data_handler,
13964 ws_close_handler,
13965 callback_data);
13966#endif
13967 }
13968 return;
13969 }
13970
13971/* 8. handle websocket requests */
13972#if defined(USE_WEBSOCKET)
13973 if (is_websocket_request) {
13974 if (is_script_resource) {
13975
13976 if (is_in_script_path(conn, path)) {
13977 /* Websocket Lua script */
13978 handle_websocket_request(conn,
13979 path,
13980 0 /* Lua Script */,
13981 NULL,
13982 NULL,
13983 NULL,
13984 NULL,
13985 NULL,
13986 conn->phys_ctx->user_data);
13987 } else {
13988 /* Script was in an illegal path */
13989 mg_send_http_error(conn, 403, "%s", "Forbidden");
13990 }
13991 } else {
13992#if defined(MG_LEGACY_INTERFACE)
13993 handle_websocket_request(
13994 conn,
13995 path,
13996 !is_script_resource /* could be deprecated global callback */,
13997 NULL,
13998 deprecated_websocket_connect_wrapper,
13999 deprecated_websocket_ready_wrapper,
14000 deprecated_websocket_data_wrapper,
14001 NULL,
14002 conn->phys_ctx->user_data);
14003#else
14004 mg_send_http_error(conn, 404, "%s", "Not found");
14005#endif
14006 }
14007 return;
14008 } else
14009#endif
14010
14011#if defined(NO_FILES)
14012 /* 9a. In case the server uses only callbacks, this uri is
14013 * unknown.
14014 * Then, all request handling ends here. */
14015 mg_send_http_error(conn, 404, "%s", "Not Found");
14016
14017#else
14018 /* 9b. This request is either for a static file or resource handled
14019 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
14020 if (conn->dom_ctx->config[DOCUMENT_ROOT] == NULL) {
14021 mg_send_http_error(conn, 404, "%s", "Not Found");
14022 return;
14023 }
14024
14025 /* 10. Request is handled by a script */
14026 if (is_script_resource) {
14027 handle_file_based_request(conn, path, &file);
14028 return;
14029 }
14030
14031 /* 11. Handle put/delete/mkcol requests */
14032 if (is_put_or_delete_request) {
14033 /* 11.1. PUT method */
14034 if (!strcmp(ri->request_method, "PUT")) {
14035 put_file(conn, path);
14036 return;
14037 }
14038 /* 11.2. DELETE method */
14039 if (!strcmp(ri->request_method, "DELETE")) {
14040 delete_file(conn, path);
14041 return;
14042 }
14043 /* 11.3. MKCOL method */
14044 if (!strcmp(ri->request_method, "MKCOL")) {
14045 mkcol(conn, path);
14046 return;
14047 }
14048 /* 11.4. PATCH method
14049 * This method is not supported for static resources,
14050 * only for scripts (Lua, CGI) and callbacks. */
14051 mg_send_http_error(conn,
14052 405,
14053 "%s method not allowed",
14055 return;
14056 }
14057
14058 /* 11. File does not exist, or it was configured that it should be
14059 * hidden */
14060 if (!is_found || (must_hide_file(conn, path))) {
14061 mg_send_http_error(conn, 404, "%s", "Not found");
14062 return;
14063 }
14064
14065 /* 12. Directory uris should end with a slash */
14066 if (file.stat.is_directory && (uri_len > 0)
14067 && (ri->local_uri[uri_len - 1] != '/')) {
14068 gmt_time_string(date, sizeof(date), &curtime);
14069 mg_printf(conn,
14070 "HTTP/1.1 301 Moved Permanently\r\n"
14071 "Location: %s/\r\n"
14072 "Date: %s\r\n"
14073 /* "Cache-Control: private\r\n" (= default) */
14074 "Content-Length: 0\r\n"
14075 "Connection: %s\r\n",
14076 ri->request_uri,
14077 date,
14080 mg_printf(conn, "\r\n");
14081 return;
14082 }
14083
14084 /* 13. Handle other methods than GET/HEAD */
14085 /* 13.1. Handle PROPFIND */
14086 if (!strcmp(ri->request_method, "PROPFIND")) {
14087 handle_propfind(conn, path, &file.stat);
14088 return;
14089 }
14090 /* 13.2. Handle OPTIONS for files */
14091 if (!strcmp(ri->request_method, "OPTIONS")) {
14092 /* This standard handler is only used for real files.
14093 * Scripts should support the OPTIONS method themselves, to allow a
14094 * maximum flexibility.
14095 * Lua and CGI scripts may fully support CORS this way (including
14096 * preflights). */
14097 send_options(conn);
14098 return;
14099 }
14100 /* 13.3. everything but GET and HEAD (e.g. POST) */
14101 if ((0 != strcmp(ri->request_method, "GET"))
14102 && (0 != strcmp(ri->request_method, "HEAD"))) {
14103 mg_send_http_error(conn,
14104 405,
14105 "%s method not allowed",
14107 return;
14108 }
14109
14110 /* 14. directories */
14111 if (file.stat.is_directory) {
14112 /* Substitute files have already been handled above. */
14113 /* Here we can either generate and send a directory listing,
14114 * or send an "access denied" error. */
14116 "yes")) {
14117 handle_directory_request(conn, path);
14118 } else {
14119 mg_send_http_error(conn,
14120 403,
14121 "%s",
14122 "Error: Directory listing denied");
14123 }
14124 return;
14125 }
14126
14127 /* 15. read a normal file with GET or HEAD */
14128 handle_file_based_request(conn, path, &file);
14129#endif /* !defined(NO_FILES) */
14130}
14131
14132
14133static void
14135 const char *path,
14136 struct mg_file *file)
14137{
14138 if (!conn || !conn->dom_ctx) {
14139 return;
14140 }
14141
14142 if (0) {
14143#if defined(USE_LUA)
14144 } else if (match_prefix(
14145 conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
14146 strlen(conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
14147 path)
14148 > 0) {
14149 if (is_in_script_path(conn, path)) {
14150 /* Lua server page: an SSI like page containing mostly plain
14151 * html
14152 * code
14153 * plus some tags with server generated contents. */
14154 handle_lsp_request(conn, path, file, NULL);
14155 } else {
14156 /* Script was in an illegal path */
14157 mg_send_http_error(conn, 403, "%s", "Forbidden");
14158 }
14159
14160 } else if (match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
14161 strlen(
14162 conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
14163 path)
14164 > 0) {
14165 if (is_in_script_path(conn, path)) {
14166 /* Lua in-server module script: a CGI like script used to
14167 * generate
14168 * the
14169 * entire reply. */
14170 mg_exec_lua_script(conn, path, NULL);
14171 } else {
14172 /* Script was in an illegal path */
14173 mg_send_http_error(conn, 403, "%s", "Forbidden");
14174 }
14175#endif
14176#if defined(USE_DUKTAPE)
14177 } else if (match_prefix(
14178 conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
14179 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
14180 path)
14181 > 0) {
14182 if (is_in_script_path(conn, path)) {
14183 /* Call duktape to generate the page */
14184 mg_exec_duktape_script(conn, path);
14185 } else {
14186 /* Script was in an illegal path */
14187 mg_send_http_error(conn, 403, "%s", "Forbidden");
14188 }
14189#endif
14190#if !defined(NO_CGI)
14191 } else if (match_prefix(conn->dom_ctx->config[CGI_EXTENSIONS],
14192 strlen(conn->dom_ctx->config[CGI_EXTENSIONS]),
14193 path)
14194 > 0) {
14195 if (is_in_script_path(conn, path)) {
14196 /* CGI scripts may support all HTTP methods */
14197 handle_cgi_request(conn, path);
14198 } else {
14199 /* Script was in an illegal path */
14200 mg_send_http_error(conn, 403, "%s", "Forbidden");
14201 }
14202#endif /* !NO_CGI */
14203 } else if (match_prefix(conn->dom_ctx->config[SSI_EXTENSIONS],
14204 strlen(conn->dom_ctx->config[SSI_EXTENSIONS]),
14205 path)
14206 > 0) {
14207 if (is_in_script_path(conn, path)) {
14208 handle_ssi_file_request(conn, path, file);
14209 } else {
14210 /* Script was in an illegal path */
14211 mg_send_http_error(conn, 403, "%s", "Forbidden");
14212 }
14213#if !defined(NO_CACHING)
14214 } else if ((!conn->in_error_handler)
14215 && is_not_modified(conn, &file->stat)) {
14216 /* Send 304 "Not Modified" - this must not send any body data */
14218#endif /* !NO_CACHING */
14219 } else {
14220 handle_static_file_request(conn, path, file, NULL, NULL);
14221 }
14222}
14223
14224
14225static void
14227{
14228 unsigned int i;
14229 if (!ctx) {
14230 return;
14231 }
14232
14233 for (i = 0; i < ctx->num_listening_sockets; i++) {
14236 }
14238 ctx->listening_sockets = NULL;
14240 ctx->listening_socket_fds = NULL;
14241}
14242
14243
14244/* Valid listening port specification is: [ip_address:]port[s]
14245 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
14246 * Examples for IPv6: [::]:80, [::1]:80,
14247 * [2001:0db8:7654:3210:FEDC:BA98:7654:3210]:443s
14248 * see https://tools.ietf.org/html/rfc3513#section-2.2
14249 * In order to bind to both, IPv4 and IPv6, you can either add
14250 * both ports using 8080,[::]:8080, or the short form +8080.
14251 * Both forms differ in detail: 8080,[::]:8080 create two sockets,
14252 * one only accepting IPv4 the other only IPv6. +8080 creates
14253 * one socket accepting IPv4 and IPv6. Depending on the IPv6
14254 * environment, they might work differently, or might not work
14255 * at all - it must be tested what options work best in the
14256 * relevant network environment.
14257 */
14258static int
14259parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
14260{
14261 unsigned int a, b, c, d, port;
14262 int ch, len;
14263 const char *cb;
14264#if defined(USE_IPV6)
14265 char buf[100] = {0};
14266#endif
14267
14268 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
14269 * Also, all-zeroes in the socket address means binding to all addresses
14270 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
14271 memset(so, 0, sizeof(*so));
14272 so->lsa.sin.sin_family = AF_INET;
14273 *ip_version = 0;
14274
14275 /* Initialize port and len as invalid. */
14276 port = 0;
14277 len = 0;
14278
14279 /* Test for different ways to format this string */
14280 if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
14281 == 5) {
14282 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
14283 so->lsa.sin.sin_addr.s_addr =
14284 htonl((a << 24) | (b << 16) | (c << 8) | d);
14285 so->lsa.sin.sin_port = htons((uint16_t)port);
14286 *ip_version = 4;
14287
14288#if defined(USE_IPV6)
14289 } else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
14290 && mg_inet_pton(
14291 AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
14292 /* IPv6 address, examples: see above */
14293 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
14294 */
14295 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14296 *ip_version = 6;
14297#endif
14298
14299 } else if ((vec->ptr[0] == '+')
14300 && (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
14301
14302 /* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY */
14303 /* Add 1 to len for the + character we skipped before */
14304 len++;
14305
14306#if defined(USE_IPV6)
14307 /* Set socket family to IPv6, do not use IPV6_V6ONLY */
14308 so->lsa.sin6.sin6_family = AF_INET6;
14309 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14310 *ip_version = 4 + 6;
14311#else
14312 /* Bind to IPv4 only, since IPv6 is not built in. */
14313 so->lsa.sin.sin_port = htons((uint16_t)port);
14314 *ip_version = 4;
14315#endif
14316
14317 } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
14318 /* If only port is specified, bind to IPv4, INADDR_ANY */
14319 so->lsa.sin.sin_port = htons((uint16_t)port);
14320 *ip_version = 4;
14321
14322 } else if ((cb = strchr(vec->ptr, ':')) != NULL) {
14323 /* String could be a hostname. This check algotithm
14324 * will only work for RFC 952 compliant hostnames,
14325 * starting with a letter, containing only letters,
14326 * digits and hyphen ('-'). Newer specs may allow
14327 * more, but this is not guaranteed here, since it
14328 * may interfere with rules for port option lists. */
14329
14330 /* According to RFC 1035, hostnames are restricted to 255 characters
14331 * in total (63 between two dots). */
14332 char hostname[256];
14333 size_t hostnlen = (size_t)(cb - vec->ptr);
14334
14335 if (hostnlen >= sizeof(hostname)) {
14336 /* This would be invalid in any case */
14337 *ip_version = 0;
14338 return 0;
14339 }
14340
14341 memcpy(hostname, vec->ptr, hostnlen);
14342 hostname[hostnlen] = 0;
14343
14344 if (mg_inet_pton(
14345 AF_INET, vec->ptr, &so->lsa.sin, sizeof(so->lsa.sin))) {
14346 if (sscanf(cb + 1, "%u%n", &port, &len) == 1) {
14347 *ip_version = 4;
14348 so->lsa.sin.sin_family = AF_INET;
14349 so->lsa.sin.sin_port = htons((uint16_t)port);
14350 len += (int)(hostnlen + 1);
14351 } else {
14352 port = 0;
14353 len = 0;
14354 }
14355#if defined(USE_IPV6)
14356 } else if (mg_inet_pton(AF_INET6,
14357 vec->ptr,
14358 &so->lsa.sin6,
14359 sizeof(so->lsa.sin6))) {
14360 if (sscanf(cb + 1, "%u%n", &port, &len) == 1) {
14361 *ip_version = 6;
14362 so->lsa.sin6.sin6_family = AF_INET6;
14363 so->lsa.sin.sin_port = htons((uint16_t)port);
14364 len += (int)(hostnlen + 1);
14365 } else {
14366 port = 0;
14367 len = 0;
14368 }
14369#endif
14370 }
14371
14372
14373 } else {
14374 /* Parsing failure. */
14375 }
14376
14377 /* sscanf and the option splitting code ensure the following condition
14378 */
14379 if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
14380 *ip_version = 0;
14381 return 0;
14382 }
14383 ch = vec->ptr[len]; /* Next character after the port number */
14384 so->is_ssl = (ch == 's');
14385 so->ssl_redir = (ch == 'r');
14386
14387 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
14388 if (is_valid_port(port)
14389 && ((ch == '\0') || (ch == 's') || (ch == 'r') || (ch == ','))) {
14390 return 1;
14391 }
14392
14393 /* Reset ip_version to 0 if there is an error */
14394 *ip_version = 0;
14395 return 0;
14396}
14397
14398
14399/* Is there any SSL port in use? */
14400static int
14401is_ssl_port_used(const char *ports)
14402{
14403 if (ports) {
14404 /* There are several different allowed syntax variants:
14405 * - "80" for a single port using every network interface
14406 * - "localhost:80" for a single port using only localhost
14407 * - "80,localhost:8080" for two ports, one bound to localhost
14408 * - "80,127.0.0.1:8084,[::1]:8086" for three ports, one bound
14409 * to IPv4 localhost, one to IPv6 localhost
14410 * - "+80" use port 80 for IPv4 and IPv6
14411 * - "+80r,+443s" port 80 (HTTP) is a redirect to port 443 (HTTPS),
14412 * for both: IPv4 and IPv4
14413 * - "+443s,localhost:8080" port 443 (HTTPS) for every interface,
14414 * additionally port 8080 bound to localhost connections
14415 *
14416 * If we just look for 's' anywhere in the string, "localhost:80"
14417 * will be detected as SSL (false positive).
14418 * Looking for 's' after a digit may cause false positives in
14419 * "my24service:8080".
14420 * Looking from 's' backward if there are only ':' and numbers
14421 * before will not work for "24service:8080" (non SSL, port 8080)
14422 * or "24s" (SSL, port 24).
14423 *
14424 * Remark: Initially hostnames were not allowed to start with a
14425 * digit (according to RFC 952), this was allowed later (RFC 1123,
14426 * Section 2.1).
14427 *
14428 * To get this correct, the entire string must be parsed as a whole,
14429 * reading it as a list element for element and parsing with an
14430 * algorithm equivalent to parse_port_string.
14431 *
14432 * In fact, we use local interface names here, not arbitrary hostnames,
14433 * so in most cases the only name will be "localhost".
14434 *
14435 * So, for now, we use this simple algorithm, that may still return
14436 * a false positive in bizarre cases.
14437 */
14438 int i;
14439 int portslen = (int)strlen(ports);
14440 char prevIsNumber = 0;
14441
14442 for (i = 0; i < portslen; i++) {
14443 if (prevIsNumber && (ports[i] == 's' || ports[i] == 'r')) {
14444 return 1;
14445 }
14446 if (ports[i] >= '0' && ports[i] <= '9') {
14447 prevIsNumber = 1;
14448 } else {
14449 prevIsNumber = 0;
14450 }
14451 }
14452 }
14453 return 0;
14454}
14455
14456
14457static int
14459{
14460 const char *list;
14461 int on = 1;
14462#if defined(USE_IPV6)
14463 int off = 0;
14464#endif
14465 struct vec vec;
14466 struct socket so, *ptr;
14467
14468 struct pollfd *pfd;
14469 union usa usa;
14470 socklen_t len;
14471 int ip_version;
14472
14473 int portsTotal = 0;
14474 int portsOk = 0;
14475
14476 if (!phys_ctx) {
14477 return 0;
14478 }
14479
14480 memset(&so, 0, sizeof(so));
14481 memset(&usa, 0, sizeof(usa));
14482 len = sizeof(usa);
14483 list = phys_ctx->dd.config[LISTENING_PORTS];
14484
14485 while ((list = next_option(list, &vec, NULL)) != NULL) {
14486
14487 portsTotal++;
14488
14489 if (!parse_port_string(&vec, &so, &ip_version)) {
14491 fc(phys_ctx),
14492 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
14493 (int)vec.len,
14494 vec.ptr,
14495 portsTotal,
14496 "[IP_ADDRESS:]PORT[s|r]");
14497 continue;
14498 }
14499
14500#if !defined(NO_SSL)
14501 if (so.is_ssl && phys_ctx->dd.ssl_ctx == NULL) {
14502
14503 mg_cry_internal(fc(phys_ctx),
14504 "Cannot add SSL socket (entry %i)",
14505 portsTotal);
14506 continue;
14507 }
14508#endif
14509
14510 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
14511 == INVALID_SOCKET) {
14512
14513 mg_cry_internal(fc(phys_ctx),
14514 "cannot create socket (entry %i)",
14515 portsTotal);
14516 continue;
14517 }
14518
14519#if defined(_WIN32)
14520 /* Windows SO_REUSEADDR lets many procs binds to a
14521 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
14522 * if someone already has the socket -- DTL */
14523 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
14524 * Windows might need a few seconds before
14525 * the same port can be used again in the
14526 * same process, so a short Sleep may be
14527 * required between mg_stop and mg_start.
14528 */
14529 if (setsockopt(so.sock,
14530 SOL_SOCKET,
14531 SO_EXCLUSIVEADDRUSE,
14532 (SOCK_OPT_TYPE)&on,
14533 sizeof(on))
14534 != 0) {
14535
14536 /* Set reuse option, but don't abort on errors. */
14538 fc(phys_ctx),
14539 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
14540 portsTotal);
14541 }
14542#else
14543 if (setsockopt(so.sock,
14544 SOL_SOCKET,
14545 SO_REUSEADDR,
14546 (SOCK_OPT_TYPE)&on,
14547 sizeof(on))
14548 != 0) {
14549
14550 /* Set reuse option, but don't abort on errors. */
14551 mg_cry_internal(fc(phys_ctx),
14552 "cannot set socket option SO_REUSEADDR (entry %i)",
14553 portsTotal);
14554 }
14555#endif
14556
14557 if (ip_version > 4) {
14558/* Could be 6 for IPv6 onlyor 10 (4+6) for IPv4+IPv6 */
14559#if defined(USE_IPV6)
14560 if (ip_version > 6) {
14561 if (so.lsa.sa.sa_family == AF_INET6
14562 && setsockopt(so.sock,
14563 IPPROTO_IPV6,
14564 IPV6_V6ONLY,
14565 (void *)&off,
14566 sizeof(off))
14567 != 0) {
14568
14569 /* Set IPv6 only option, but don't abort on errors. */
14571 fc(phys_ctx),
14572 "cannot set socket option IPV6_V6ONLY=off (entry %i)",
14573 portsTotal);
14574 }
14575 } else {
14576 if (so.lsa.sa.sa_family == AF_INET6
14577 && setsockopt(so.sock,
14578 IPPROTO_IPV6,
14579 IPV6_V6ONLY,
14580 (void *)&on,
14581 sizeof(on))
14582 != 0) {
14583
14584 /* Set IPv6 only option, but don't abort on errors. */
14586 fc(phys_ctx),
14587 "cannot set socket option IPV6_V6ONLY=on (entry %i)",
14588 portsTotal);
14589 }
14590 }
14591#else
14592 mg_cry_internal(fc(phys_ctx), "%s", "IPv6 not available");
14593 closesocket(so.sock);
14594 so.sock = INVALID_SOCKET;
14595 continue;
14596#endif
14597 }
14598
14599 if (so.lsa.sa.sa_family == AF_INET) {
14600
14601 len = sizeof(so.lsa.sin);
14602 if (bind(so.sock, &so.lsa.sa, len) != 0) {
14603 mg_cry_internal(fc(phys_ctx),
14604 "cannot bind to %.*s: %d (%s)",
14605 (int)vec.len,
14606 vec.ptr,
14607 (int)ERRNO,
14608 strerror(errno));
14609 closesocket(so.sock);
14610 so.sock = INVALID_SOCKET;
14611 continue;
14612 }
14613 }
14614#if defined(USE_IPV6)
14615 else if (so.lsa.sa.sa_family == AF_INET6) {
14616
14617 len = sizeof(so.lsa.sin6);
14618 if (bind(so.sock, &so.lsa.sa, len) != 0) {
14619 mg_cry_internal(fc(phys_ctx),
14620 "cannot bind to IPv6 %.*s: %d (%s)",
14621 (int)vec.len,
14622 vec.ptr,
14623 (int)ERRNO,
14624 strerror(errno));
14625 closesocket(so.sock);
14626 so.sock = INVALID_SOCKET;
14627 continue;
14628 }
14629 }
14630#endif
14631 else {
14633 fc(phys_ctx),
14634 "cannot bind: address family not supported (entry %i)",
14635 portsTotal);
14636 closesocket(so.sock);
14637 so.sock = INVALID_SOCKET;
14638 continue;
14639 }
14640
14641 if (listen(so.sock, SOMAXCONN) != 0) {
14642
14643 mg_cry_internal(fc(phys_ctx),
14644 "cannot listen to %.*s: %d (%s)",
14645 (int)vec.len,
14646 vec.ptr,
14647 (int)ERRNO,
14648 strerror(errno));
14649 closesocket(so.sock);
14650 so.sock = INVALID_SOCKET;
14651 continue;
14652 }
14653
14654 if ((getsockname(so.sock, &(usa.sa), &len) != 0)
14655 || (usa.sa.sa_family != so.lsa.sa.sa_family)) {
14656
14657 int err = (int)ERRNO;
14658 mg_cry_internal(fc(phys_ctx),
14659 "call to getsockname failed %.*s: %d (%s)",
14660 (int)vec.len,
14661 vec.ptr,
14662 err,
14663 strerror(errno));
14664 closesocket(so.sock);
14665 so.sock = INVALID_SOCKET;
14666 continue;
14667 }
14668
14669/* Update lsa port in case of random free ports */
14670#if defined(USE_IPV6)
14671 if (so.lsa.sa.sa_family == AF_INET6) {
14672 so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
14673 } else
14674#endif
14675 {
14676 so.lsa.sin.sin_port = usa.sin.sin_port;
14677 }
14678
14679 if ((ptr = (struct socket *)
14681 (phys_ctx->num_listening_sockets + 1)
14682 * sizeof(phys_ctx->listening_sockets[0]),
14683 phys_ctx))
14684 == NULL) {
14685
14686 mg_cry_internal(fc(phys_ctx), "%s", "Out of memory");
14687 closesocket(so.sock);
14688 so.sock = INVALID_SOCKET;
14689 continue;
14690 }
14691
14692 if ((pfd = (struct pollfd *)
14694 (phys_ctx->num_listening_sockets + 1)
14695 * sizeof(phys_ctx->listening_socket_fds[0]),
14696 phys_ctx))
14697 == NULL) {
14698
14699 mg_cry_internal(fc(phys_ctx), "%s", "Out of memory");
14700 closesocket(so.sock);
14701 so.sock = INVALID_SOCKET;
14702 mg_free(ptr);
14703 continue;
14704 }
14705
14706 set_close_on_exec(so.sock, fc(phys_ctx));
14707 phys_ctx->listening_sockets = ptr;
14708 phys_ctx->listening_sockets[phys_ctx->num_listening_sockets] = so;
14709 phys_ctx->listening_socket_fds = pfd;
14710 phys_ctx->num_listening_sockets++;
14711 portsOk++;
14712 }
14713
14714 if (portsOk != portsTotal) {
14716 portsOk = 0;
14717 }
14718
14719 return portsOk;
14720}
14721
14722
14723static const char *
14724header_val(const struct mg_connection *conn, const char *header)
14725{
14726 const char *header_value;
14727
14728 if ((header_value = mg_get_header(conn, header)) == NULL) {
14729 return "-";
14730 } else {
14731 return header_value;
14732 }
14733}
14734
14735
14736#if defined(MG_EXTERNAL_FUNCTION_log_access)
14737static void log_access(const struct mg_connection *conn);
14738#include "external_log_access.inl"
14739#else
14740
14741static void
14742log_access(const struct mg_connection *conn)
14743{
14744 const struct mg_request_info *ri;
14745 struct mg_file fi;
14746 char date[64], src_addr[IP_ADDR_STR_LEN];
14747 struct tm *tm;
14748
14749 const char *referer;
14750 const char *user_agent;
14751
14752 char buf[4096];
14753
14754 if (!conn || !conn->dom_ctx) {
14755 return;
14756 }
14757
14758 if (conn->dom_ctx->config[ACCESS_LOG_FILE] != NULL) {
14759 if (mg_fopen(conn,
14762 &fi)
14763 == 0) {
14764 fi.access.fp = NULL;
14765 }
14766 } else {
14767 fi.access.fp = NULL;
14768 }
14769
14770 /* Log is written to a file and/or a callback. If both are not set,
14771 * executing the rest of the function is pointless. */
14772 if ((fi.access.fp == NULL)
14773 && (conn->phys_ctx->callbacks.log_access == NULL)) {
14774 return;
14775 }
14776
14777 tm = localtime(&conn->conn_birth_time);
14778 if (tm != NULL) {
14779 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
14780 } else {
14781 mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
14782 date[sizeof(date) - 1] = '\0';
14783 }
14784
14785 ri = &conn->request_info;
14786
14787 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
14788 referer = header_val(conn, "Referer");
14789 user_agent = header_val(conn, "User-Agent");
14790
14791 mg_snprintf(conn,
14792 NULL, /* Ignore truncation in access log */
14793 buf,
14794 sizeof(buf),
14795 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
14796 src_addr,
14797 (ri->remote_user == NULL) ? "-" : ri->remote_user,
14798 date,
14799 ri->request_method ? ri->request_method : "-",
14800 ri->request_uri ? ri->request_uri : "-",
14801 ri->query_string ? "?" : "",
14802 ri->query_string ? ri->query_string : "",
14803 ri->http_version,
14804 conn->status_code,
14805 conn->num_bytes_sent,
14806 referer,
14807 user_agent);
14808
14809 if (conn->phys_ctx->callbacks.log_access) {
14810 conn->phys_ctx->callbacks.log_access(conn, buf);
14811 }
14812
14813 if (fi.access.fp) {
14814 int ok = 1;
14815 flockfile(fi.access.fp);
14816 if (fprintf(fi.access.fp, "%s\n", buf) < 1) {
14817 ok = 0;
14818 }
14819 if (fflush(fi.access.fp) != 0) {
14820 ok = 0;
14821 }
14822 funlockfile(fi.access.fp);
14823 if (mg_fclose(&fi.access) != 0) {
14824 ok = 0;
14825 }
14826 if (!ok) {
14827 mg_cry_internal(conn,
14828 "Error writing log file %s",
14830 }
14831 }
14832}
14833
14834#endif /* Externally provided function */
14835
14836
14837/* Verify given socket address against the ACL.
14838 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
14839 */
14840static int
14841check_acl(struct mg_context *phys_ctx, uint32_t remote_ip)
14842{
14843 int allowed, flag;
14844 uint32_t net, mask;
14845 struct vec vec;
14846
14847 if (phys_ctx) {
14848 const char *list = phys_ctx->dd.config[ACCESS_CONTROL_LIST];
14849
14850 /* If any ACL is set, deny by default */
14851 allowed = (list == NULL) ? '+' : '-';
14852
14853 while ((list = next_option(list, &vec, NULL)) != NULL) {
14854 flag = vec.ptr[0];
14855 if ((flag != '+' && flag != '-')
14856 || (parse_net(&vec.ptr[1], &net, &mask) == 0)) {
14857 mg_cry_internal(fc(phys_ctx),
14858 "%s: subnet must be [+|-]x.x.x.x[/x]",
14859 __func__);
14860 return -1;
14861 }
14862
14863 if (net == (remote_ip & mask)) {
14864 allowed = flag;
14865 }
14866 }
14867
14868 return allowed == '+';
14869 }
14870 return -1;
14871}
14872
14873
14874#if !defined(_WIN32)
14875static int
14877{
14878 int success = 0;
14879
14880 if (phys_ctx) {
14881 /* We are currently running as curr_uid. */
14882 const uid_t curr_uid = getuid();
14883 /* If set, we want to run as run_as_user. */
14884 const char *run_as_user = phys_ctx->dd.config[RUN_AS_USER];
14885 const struct passwd *to_pw = NULL;
14886
14887 if (run_as_user != NULL && (to_pw = getpwnam(run_as_user)) == NULL) {
14888 /* run_as_user does not exist on the system. We can't proceed
14889 * further. */
14890 mg_cry_internal(fc(phys_ctx),
14891 "%s: unknown user [%s]",
14892 __func__,
14893 run_as_user);
14894 } else if (run_as_user == NULL || curr_uid == to_pw->pw_uid) {
14895 /* There was either no request to change user, or we're already
14896 * running as run_as_user. Nothing else to do.
14897 */
14898 success = 1;
14899 } else {
14900 /* Valid change request. */
14901 if (setgid(to_pw->pw_gid) == -1) {
14902 mg_cry_internal(fc(phys_ctx),
14903 "%s: setgid(%s): %s",
14904 __func__,
14905 run_as_user,
14906 strerror(errno));
14907 } else if (setgroups(0, NULL) == -1) {
14908 mg_cry_internal(fc(phys_ctx),
14909 "%s: setgroups(): %s",
14910 __func__,
14911 strerror(errno));
14912 } else if (setuid(to_pw->pw_uid) == -1) {
14913 mg_cry_internal(fc(phys_ctx),
14914 "%s: setuid(%s): %s",
14915 __func__,
14916 run_as_user,
14917 strerror(errno));
14918 } else {
14919 success = 1;
14920 }
14921 }
14922 }
14923
14924 return success;
14925}
14926#endif /* !_WIN32 */
14927
14928
14929static void
14930tls_dtor(void *key)
14931{
14932 struct mg_workerTLS *tls = (struct mg_workerTLS *)key;
14933 /* key == pthread_getspecific(sTlsKey); */
14934
14935 if (tls) {
14936 if (tls->is_master == 2) {
14937 tls->is_master = -3; /* Mark memory as dead */
14938 mg_free(tls);
14939 }
14940 }
14941 pthread_setspecific(sTlsKey, NULL);
14942}
14943
14944
14945#if !defined(NO_SSL)
14946
14947static int ssl_use_pem_file(struct mg_context *phys_ctx,
14948 struct mg_domain_context *dom_ctx,
14949 const char *pem,
14950 const char *chain);
14951static const char *ssl_error(void);
14952
14953
14954static int
14956{
14957 static int reload_lock = 0;
14958 static long int data_check = 0;
14959 volatile int *p_reload_lock = (volatile int *)&reload_lock;
14960
14961 struct stat cert_buf;
14962 long int t;
14963 const char *pem;
14964 const char *chain;
14965 int should_verify_peer;
14966
14967 if ((pem = conn->dom_ctx->config[SSL_CERTIFICATE]) == NULL) {
14968 /* If peem is NULL and conn->phys_ctx->callbacks.init_ssl is not,
14969 * refresh_trust still can not work. */
14970 return 0;
14971 }
14972 chain = conn->dom_ctx->config[SSL_CERTIFICATE_CHAIN];
14973 if (chain == NULL) {
14974 /* pem is not NULL here */
14975 chain = pem;
14976 }
14977 if (*chain == 0) {
14978 chain = NULL;
14979 }
14980
14981 t = data_check;
14982 if (stat(pem, &cert_buf) != -1) {
14983 t = (long int)cert_buf.st_mtime;
14984 }
14985
14986 if (data_check != t) {
14987 data_check = t;
14988
14989 should_verify_peer = 0;
14990 if (conn->dom_ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
14992 == 0) {
14993 should_verify_peer = 1;
14995 "optional")
14996 == 0) {
14997 should_verify_peer = 1;
14998 }
14999 }
15000
15001 if (should_verify_peer) {
15002 char *ca_path = conn->dom_ctx->config[SSL_CA_PATH];
15003 char *ca_file = conn->dom_ctx->config[SSL_CA_FILE];
15005 ca_file,
15006 ca_path)
15007 != 1) {
15009 fc(conn->phys_ctx),
15010 "SSL_CTX_load_verify_locations error: %s "
15011 "ssl_verify_peer requires setting "
15012 "either ssl_ca_path or ssl_ca_file. Is any of them "
15013 "present in "
15014 "the .conf file?",
15015 ssl_error());
15016 return 0;
15017 }
15018 }
15019
15020 if (1 == mg_atomic_inc(p_reload_lock)) {
15021 if (ssl_use_pem_file(conn->phys_ctx, conn->dom_ctx, pem, chain)
15022 == 0) {
15023 return 0;
15024 }
15025 *p_reload_lock = 0;
15026 }
15027 }
15028 /* lock while cert is reloading */
15029 while (*p_reload_lock) {
15030 sleep(1);
15031 }
15032
15033 return 1;
15034}
15035
15036#if defined(OPENSSL_API_1_1)
15037#else
15038static pthread_mutex_t *ssl_mutexes;
15039#endif /* OPENSSL_API_1_1 */
15040
15041static int
15043 SSL_CTX *s,
15044 int (*func)(SSL *),
15045 volatile int *stop_server,
15046 const struct mg_client_options *client_options)
15047{
15048 int ret, err;
15049 int short_trust;
15050 unsigned i;
15051
15052 if (!conn) {
15053 return 0;
15054 }
15055
15056 short_trust =
15057 (conn->dom_ctx->config[SSL_SHORT_TRUST] != NULL)
15058 && (mg_strcasecmp(conn->dom_ctx->config[SSL_SHORT_TRUST], "yes") == 0);
15059
15060 if (short_trust) {
15061 int trust_ret = refresh_trust(conn);
15062 if (!trust_ret) {
15063 return trust_ret;
15064 }
15065 }
15066
15067 conn->ssl = SSL_new(s);
15068 if (conn->ssl == NULL) {
15069 return 0;
15070 }
15071 SSL_set_app_data(conn->ssl, (char *)conn);
15072
15073 ret = SSL_set_fd(conn->ssl, conn->client.sock);
15074 if (ret != 1) {
15075 err = SSL_get_error(conn->ssl, ret);
15076 mg_cry_internal(conn, "SSL error %i, destroying SSL context", err);
15077 SSL_free(conn->ssl);
15078 conn->ssl = NULL;
15080 return 0;
15081 }
15082
15083 if (client_options) {
15084 if (client_options->host_name) {
15085 SSL_set_tlsext_host_name(conn->ssl, client_options->host_name);
15086 }
15087 }
15088
15089 /* SSL functions may fail and require to be called again:
15090 * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html
15091 * Here "func" could be SSL_connect or SSL_accept. */
15092 for (i = 16; i <= 1024; i *= 2) {
15093 ret = func(conn->ssl);
15094 if (ret != 1) {
15095 err = SSL_get_error(conn->ssl, ret);
15096 if ((err == SSL_ERROR_WANT_CONNECT)
15097 || (err == SSL_ERROR_WANT_ACCEPT)
15098 || (err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE)
15099 || (err == SSL_ERROR_WANT_X509_LOOKUP)) {
15100 /* Need to retry the function call "later".
15101 * See https://linux.die.net/man/3/ssl_get_error
15102 * This is typical for non-blocking sockets. */
15103 if (*stop_server) {
15104 /* Don't wait if the server is going to be stopped. */
15105 break;
15106 }
15107 mg_sleep(i);
15108
15109 } else if (err == SSL_ERROR_SYSCALL) {
15110 /* This is an IO error. Look at errno. */
15111 err = errno;
15112 mg_cry_internal(conn, "SSL syscall error %i", err);
15113 break;
15114
15115 } else {
15116 /* This is an SSL specific error, e.g. SSL_ERROR_SSL */
15117 mg_cry_internal(conn, "sslize error: %s", ssl_error());
15118 break;
15119 }
15120
15121 } else {
15122 /* success */
15123 break;
15124 }
15125 }
15126
15127 if (ret != 1) {
15128 SSL_free(conn->ssl);
15129 conn->ssl = NULL;
15131 return 0;
15132 }
15133
15134 return 1;
15135}
15136
15137
15138/* Return OpenSSL error message (from CRYPTO lib) */
15139static const char *
15141{
15142 unsigned long err;
15143 err = ERR_get_error();
15144 return ((err == 0) ? "" : ERR_error_string(err, NULL));
15145}
15146
15147
15148static int
15149hexdump2string(void *mem, int memlen, char *buf, int buflen)
15150{
15151 int i;
15152 const char hexdigit[] = "0123456789abcdef";
15153
15154 if ((memlen <= 0) || (buflen <= 0)) {
15155 return 0;
15156 }
15157 if (buflen < (3 * memlen)) {
15158 return 0;
15159 }
15160
15161 for (i = 0; i < memlen; i++) {
15162 if (i > 0) {
15163 buf[3 * i - 1] = ' ';
15164 }
15165 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
15166 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
15167 }
15168 buf[3 * memlen - 1] = 0;
15169
15170 return 1;
15171}
15172
15173
15174static void
15176{
15177 X509 *cert = SSL_get_peer_certificate(conn->ssl);
15178 if (cert) {
15179 char str_subject[1024];
15180 char str_issuer[1024];
15181 char str_finger[1024];
15182 unsigned char buf[256];
15183 char *str_serial = NULL;
15184 unsigned int ulen;
15185 int ilen;
15186 unsigned char *tmp_buf;
15187 unsigned char *tmp_p;
15188
15189 /* Handle to algorithm used for fingerprint */
15190 const EVP_MD *digest = EVP_get_digestbyname("sha1");
15191
15192 /* Get Subject and issuer */
15193 X509_NAME *subj = X509_get_subject_name(cert);
15194 X509_NAME *iss = X509_get_issuer_name(cert);
15195
15196 /* Get serial number */
15197 ASN1_INTEGER *serial = X509_get_serialNumber(cert);
15198
15199 /* Translate serial number to a hex string */
15200 BIGNUM *serial_bn = ASN1_INTEGER_to_BN(serial, NULL);
15201 str_serial = BN_bn2hex(serial_bn);
15202 BN_free(serial_bn);
15203
15204 /* Translate subject and issuer to a string */
15205 (void)X509_NAME_oneline(subj, str_subject, (int)sizeof(str_subject));
15206 (void)X509_NAME_oneline(iss, str_issuer, (int)sizeof(str_issuer));
15207
15208 /* Calculate SHA1 fingerprint and store as a hex string */
15209 ulen = 0;
15210
15211 /* ASN1_digest is deprecated. Do the calculation manually,
15212 * using EVP_Digest. */
15213 ilen = i2d_X509(cert, NULL);
15214 tmp_buf = (ilen > 0)
15215 ? (unsigned char *)mg_malloc_ctx((unsigned)ilen + 1,
15216 conn->phys_ctx)
15217 : NULL;
15218 if (tmp_buf) {
15219 tmp_p = tmp_buf;
15220 (void)i2d_X509(cert, &tmp_p);
15221 if (!EVP_Digest(
15222 tmp_buf, (unsigned)ilen, buf, &ulen, digest, NULL)) {
15223 ulen = 0;
15224 }
15225 mg_free(tmp_buf);
15226 }
15227
15228 if (!hexdump2string(
15229 buf, (int)ulen, str_finger, (int)sizeof(str_finger))) {
15230 *str_finger = 0;
15231 }
15232
15233 conn->request_info.client_cert = (struct mg_client_cert *)
15234 mg_malloc_ctx(sizeof(struct mg_client_cert), conn->phys_ctx);
15235 if (conn->request_info.client_cert) {
15236 conn->request_info.client_cert->peer_cert = (void *)cert;
15238 mg_strdup_ctx(str_subject, conn->phys_ctx);
15240 mg_strdup_ctx(str_issuer, conn->phys_ctx);
15242 mg_strdup_ctx(str_serial, conn->phys_ctx);
15244 mg_strdup_ctx(str_finger, conn->phys_ctx);
15245 } else {
15246 mg_cry_internal(conn,
15247 "%s",
15248 "Out of memory: Cannot allocate memory for client "
15249 "certificate");
15250 }
15251
15252 /* Strings returned from bn_bn2hex must be freed using OPENSSL_free,
15253 * see https://linux.die.net/man/3/bn_bn2hex */
15254 OPENSSL_free(str_serial);
15255 }
15256}
15257
15258
15259#if defined(OPENSSL_API_1_1)
15260#else
15261static void
15262ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
15263{
15264 (void)line;
15265 (void)file;
15266
15267 if (mode & 1) {
15268 /* 1 is CRYPTO_LOCK */
15269 (void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
15270 } else {
15271 (void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
15272 }
15273}
15274#endif /* OPENSSL_API_1_1 */
15275
15276
15277#if !defined(NO_SSL_DL)
15278static void *
15279load_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw)
15280{
15281 union {
15282 void *p;
15283 void (*fp)(void);
15284 } u;
15285 void *dll_handle;
15286 struct ssl_func *fp;
15287 int ok;
15288 int truncated = 0;
15289
15290 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
15291 mg_snprintf(NULL,
15292 NULL, /* No truncation check for ebuf */
15293 ebuf,
15294 ebuf_len,
15295 "%s: cannot load %s",
15296 __func__,
15297 dll_name);
15298 return NULL;
15299 }
15300
15301 ok = 1;
15302 for (fp = sw; fp->name != NULL; fp++) {
15303#if defined(_WIN32)
15304 /* GetProcAddress() returns pointer to function */
15305 u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
15306#else
15307 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
15308 * pointers to function pointers. We need to use a union to make a
15309 * cast. */
15310 u.p = dlsym(dll_handle, fp->name);
15311#endif /* _WIN32 */
15312 if (u.fp == NULL) {
15313 if (ok) {
15314 mg_snprintf(NULL,
15315 &truncated,
15316 ebuf,
15317 ebuf_len,
15318 "%s: %s: cannot find %s",
15319 __func__,
15320 dll_name,
15321 fp->name);
15322 ok = 0;
15323 } else {
15324 size_t cur_len = strlen(ebuf);
15325 if (!truncated) {
15326 mg_snprintf(NULL,
15327 &truncated,
15328 ebuf + cur_len,
15329 ebuf_len - cur_len - 3,
15330 ", %s",
15331 fp->name);
15332 if (truncated) {
15333 /* If truncated, add "..." */
15334 strcat(ebuf, "...");
15335 }
15336 }
15337 }
15338 /* Debug:
15339 * printf("Missing function: %s\n", fp->name); */
15340 } else {
15341 fp->ptr = u.fp;
15342 }
15343 }
15344
15345 if (!ok) {
15346 (void)dlclose(dll_handle);
15347 return NULL;
15348 }
15349
15350 return dll_handle;
15351}
15352
15353
15354static void *ssllib_dll_handle; /* Store the ssl library handle. */
15355static void *cryptolib_dll_handle; /* Store the crypto library handle. */
15356
15357#endif /* NO_SSL_DL */
15358
15359
15360#if defined(SSL_ALREADY_INITIALIZED)
15361static int cryptolib_users = 1; /* Reference counter for crypto library. */
15362#else
15363static int cryptolib_users = 0; /* Reference counter for crypto library. */
15364#endif
15365
15366
15367static int
15368initialize_ssl(char *ebuf, size_t ebuf_len)
15369{
15370#if defined(OPENSSL_API_1_1)
15371 if (ebuf_len > 0) {
15372 ebuf[0] = 0;
15373 }
15374
15375#if !defined(NO_SSL_DL)
15376 if (!cryptolib_dll_handle) {
15378 if (!cryptolib_dll_handle) {
15379 mg_snprintf(NULL,
15380 NULL, /* No truncation check for ebuf */
15381 ebuf,
15382 ebuf_len,
15383 "%s: error loading library %s",
15384 __func__,
15385 CRYPTO_LIB);
15386 DEBUG_TRACE("%s", ebuf);
15387 return 0;
15388 }
15389 }
15390#endif /* NO_SSL_DL */
15391
15392 if (mg_atomic_inc(&cryptolib_users) > 1) {
15393 return 1;
15394 }
15395
15396#else /* not OPENSSL_API_1_1 */
15397 int i, num_locks;
15398 size_t size;
15399
15400 if (ebuf_len > 0) {
15401 ebuf[0] = 0;
15402 }
15403
15404#if !defined(NO_SSL_DL)
15405 if (!cryptolib_dll_handle) {
15407 if (!cryptolib_dll_handle) {
15408 mg_snprintf(NULL,
15409 NULL, /* No truncation check for ebuf */
15410 ebuf,
15411 ebuf_len,
15412 "%s: error loading library %s",
15413 __func__,
15414 CRYPTO_LIB);
15415 DEBUG_TRACE("%s", ebuf);
15416 return 0;
15417 }
15418 }
15419#endif /* NO_SSL_DL */
15420
15421 if (mg_atomic_inc(&cryptolib_users) > 1) {
15422 return 1;
15423 }
15424
15425 /* Initialize locking callbacks, needed for thread safety.
15426 * http://www.openssl.org/support/faq.html#PROG1
15427 */
15428 num_locks = CRYPTO_num_locks();
15429 if (num_locks < 0) {
15430 num_locks = 0;
15431 }
15432 size = sizeof(pthread_mutex_t) * ((size_t)(num_locks));
15433
15434 /* allocate mutex array, if required */
15435 if (num_locks == 0) {
15436 /* No mutex array required */
15437 ssl_mutexes = NULL;
15438 } else {
15439 /* Mutex array required - allocate it */
15440 ssl_mutexes = (pthread_mutex_t *)mg_malloc(size);
15441
15442 /* Check OOM */
15443 if (ssl_mutexes == NULL) {
15444 mg_snprintf(NULL,
15445 NULL, /* No truncation check for ebuf */
15446 ebuf,
15447 ebuf_len,
15448 "%s: cannot allocate mutexes: %s",
15449 __func__,
15450 ssl_error());
15451 DEBUG_TRACE("%s", ebuf);
15452 return 0;
15453 }
15454
15455 /* initialize mutex array */
15456 for (i = 0; i < num_locks; i++) {
15457 if (0 != pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr)) {
15458 mg_snprintf(NULL,
15459 NULL, /* No truncation check for ebuf */
15460 ebuf,
15461 ebuf_len,
15462 "%s: error initializing mutex %i of %i",
15463 __func__,
15464 i,
15465 num_locks);
15466 DEBUG_TRACE("%s", ebuf);
15468 return 0;
15469 }
15470 }
15471 }
15472
15475#endif /* OPENSSL_API_1_1 */
15476
15477#if !defined(NO_SSL_DL)
15478 if (!ssllib_dll_handle) {
15479 ssllib_dll_handle = load_dll(ebuf, ebuf_len, SSL_LIB, ssl_sw);
15480 if (!ssllib_dll_handle) {
15481#if !defined(OPENSSL_API_1_1)
15483#endif
15484 DEBUG_TRACE("%s", ebuf);
15485 return 0;
15486 }
15487 }
15488#endif /* NO_SSL_DL */
15489
15490#if defined(OPENSSL_API_1_1)
15491 /* Initialize SSL library */
15492 OPENSSL_init_ssl(0, NULL);
15493 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
15495 NULL);
15496#else
15497 /* Initialize SSL library */
15500#endif
15501
15502 return 1;
15503}
15504
15505
15506static int
15508 struct mg_domain_context *dom_ctx,
15509 const char *pem,
15510 const char *chain)
15511{
15512 if (SSL_CTX_use_certificate_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
15513 mg_cry_internal(fc(phys_ctx),
15514 "%s: cannot open certificate file %s: %s",
15515 __func__,
15516 pem,
15517 ssl_error());
15518 return 0;
15519 }
15520
15521 /* could use SSL_CTX_set_default_passwd_cb_userdata */
15522 if (SSL_CTX_use_PrivateKey_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
15523 mg_cry_internal(fc(phys_ctx),
15524 "%s: cannot open private key file %s: %s",
15525 __func__,
15526 pem,
15527 ssl_error());
15528 return 0;
15529 }
15530
15531 if (SSL_CTX_check_private_key(dom_ctx->ssl_ctx) == 0) {
15532 mg_cry_internal(fc(phys_ctx),
15533 "%s: certificate and private key do not match: %s",
15534 __func__,
15535 pem);
15536 return 0;
15537 }
15538
15539 /* In contrast to OpenSSL, wolfSSL does not support certificate
15540 * chain files that contain private keys and certificates in
15541 * SSL_CTX_use_certificate_chain_file.
15542 * The CivetWeb-Server used pem-Files that contained both information.
15543 * In order to make wolfSSL work, it is split in two files.
15544 * One file that contains key and certificate used by the server and
15545 * an optional chain file for the ssl stack.
15546 */
15547 if (chain) {
15548 if (SSL_CTX_use_certificate_chain_file(dom_ctx->ssl_ctx, chain) == 0) {
15549 mg_cry_internal(fc(phys_ctx),
15550 "%s: cannot use certificate chain file %s: %s",
15551 __func__,
15552 pem,
15553 ssl_error());
15554 return 0;
15555 }
15556 }
15557 return 1;
15558}
15559
15560
15561#if defined(OPENSSL_API_1_1)
15562static unsigned long
15563ssl_get_protocol(int version_id)
15564{
15565 long unsigned ret = (long unsigned)SSL_OP_ALL;
15566 if (version_id > 0)
15567 ret |= SSL_OP_NO_SSLv2;
15568 if (version_id > 1)
15569 ret |= SSL_OP_NO_SSLv3;
15570 if (version_id > 2)
15571 ret |= SSL_OP_NO_TLSv1;
15572 if (version_id > 3)
15573 ret |= SSL_OP_NO_TLSv1_1;
15574 return ret;
15575}
15576#else
15577static long
15578ssl_get_protocol(int version_id)
15579{
15580 long ret = (long)SSL_OP_ALL;
15581 if (version_id > 0)
15582 ret |= SSL_OP_NO_SSLv2;
15583 if (version_id > 1)
15584 ret |= SSL_OP_NO_SSLv3;
15585 if (version_id > 2)
15586 ret |= SSL_OP_NO_TLSv1;
15587 if (version_id > 3)
15588 ret |= SSL_OP_NO_TLSv1_1;
15589 return ret;
15590}
15591#endif /* OPENSSL_API_1_1 */
15592
15593
15594/* SSL callback documentation:
15595 * https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_info_callback.html
15596 * https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_info_callback(3)
15597 * https://linux.die.net/man/3/ssl_set_info_callback */
15598/* Note: There is no "const" for the first argument in the documentation
15599 * examples, however some (maybe most, but not all) headers of OpenSSL versions
15600 * / OpenSSL compatibility layers have it. Having a different definition will
15601 * cause a warning in C and an error in C++. Use "const SSL *", while
15602 * automatical conversion from "SSL *" works for all compilers, but not other
15603 * way around */
15604static void
15605ssl_info_callback(const SSL *ssl, int what, int ret)
15606{
15607 (void)ret;
15608
15610 SSL_get_app_data(ssl);
15611 }
15613 /* TODO: check for openSSL 1.1 */
15614 //#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001
15615 // ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
15616 }
15617}
15618
15619
15620static int
15621ssl_servername_callback(SSL *ssl, int *ad, void *arg)
15622{
15623 struct mg_context *ctx = (struct mg_context *)arg;
15624 struct mg_domain_context *dom =
15625 (struct mg_domain_context *)ctx ? &(ctx->dd) : NULL;
15626
15627#if defined(GCC_DIAGNOSTIC)
15628#pragma GCC diagnostic push
15629#pragma GCC diagnostic ignored "-Wcast-align"
15630#endif /* defined(GCC_DIAGNOSTIC) */
15631
15632 /* We used an aligned pointer in SSL_set_app_data */
15633 struct mg_connection *conn = (struct mg_connection *)SSL_get_app_data(ssl);
15634
15635#if defined(GCC_DIAGNOSTIC)
15636#pragma GCC diagnostic pop
15637#endif /* defined(GCC_DIAGNOSTIC) */
15638
15639 const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
15640
15641 (void)ad;
15642
15643 if ((ctx == NULL) || (conn->phys_ctx == ctx)) {
15644 DEBUG_TRACE("%s", "internal error - assertion failed");
15645 return SSL_TLSEXT_ERR_NOACK;
15646 }
15647
15648 /* Old clients (Win XP) will not support SNI. Then, there
15649 * is no server name available in the request - we can
15650 * only work with the default certificate.
15651 * Multiple HTTPS hosts on one IP+port are only possible
15652 * with a certificate containing all alternative names.
15653 */
15654 if ((servername == NULL) || (*servername == 0)) {
15655 DEBUG_TRACE("%s", "SSL connection not supporting SNI");
15656 conn->dom_ctx = &(ctx->dd);
15658 return SSL_TLSEXT_ERR_NOACK;
15659 }
15660
15661 DEBUG_TRACE("TLS connection to host %s", servername);
15662
15663 while (dom) {
15664 if (!mg_strcasecmp(servername, dom->config[AUTHENTICATION_DOMAIN])) {
15665
15666 /* Found matching domain */
15667 DEBUG_TRACE("TLS domain %s found",
15670 conn->dom_ctx = dom;
15671 return SSL_TLSEXT_ERR_OK;
15672 }
15673 dom = dom->next;
15674 }
15675
15676 /* Default domain */
15677 DEBUG_TRACE("TLS default domain %s used",
15679 conn->dom_ctx = &(ctx->dd);
15681 return SSL_TLSEXT_ERR_OK;
15682}
15683
15684
15685/* Setup SSL CTX as required by CivetWeb */
15686static int
15688 struct mg_domain_context *dom_ctx,
15689 const char *pem,
15690 const char *chain)
15691{
15692 int callback_ret;
15693 int should_verify_peer;
15694 int peer_certificate_optional;
15695 const char *ca_path;
15696 const char *ca_file;
15697 int use_default_verify_paths;
15698 int verify_depth;
15699 struct timespec now_mt;
15700 md5_byte_t ssl_context_id[16];
15701 md5_state_t md5state;
15702 int protocol_ver;
15703
15704#if defined(OPENSSL_API_1_1)
15705 if ((dom_ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
15706 mg_cry_internal(fc(phys_ctx),
15707 "SSL_CTX_new (server) error: %s",
15708 ssl_error());
15709 return 0;
15710 }
15711#else
15712 if ((dom_ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
15713 mg_cry_internal(fc(phys_ctx),
15714 "SSL_CTX_new (server) error: %s",
15715 ssl_error());
15716 return 0;
15717 }
15718#endif /* OPENSSL_API_1_1 */
15719
15723 protocol_ver = atoi(dom_ctx->config[SSL_PROTOCOL_VERSION]);
15724 SSL_CTX_set_options(dom_ctx->ssl_ctx, ssl_get_protocol(protocol_ver));
15730#if !defined(NO_SSL_DL)
15731 SSL_CTX_set_ecdh_auto(dom_ctx->ssl_ctx, 1);
15732#endif /* NO_SSL_DL */
15733
15734 /* In SSL documentation examples callback defined without const specifier
15735 * 'void (*)(SSL *, int, int)' See:
15736 * https://www.openssl.org/docs/man1.0.2/ssl/ssl.html
15737 * https://www.openssl.org/docs/man1.1.0/ssl/ssl.html
15738 * But in the source code const SSL is used:
15739 * 'void (*)(const SSL *, int, int)' See:
15740 * https://github.com/openssl/openssl/blob/1d97c8435171a7af575f73c526d79e1ef0ee5960/ssl/ssl.h#L1173
15741 * Problem about wrong documentation described, but not resolved:
15742 * https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1147526
15743 * Wrong const cast ignored on C or can be suppressed by compiler flags.
15744 * But when compiled with modern C++ compiler, correct const should be
15745 * provided
15746 */
15748
15751 SSL_CTX_set_tlsext_servername_arg(dom_ctx->ssl_ctx, phys_ctx);
15752
15753 /* If a callback has been specified, call it. */
15754 callback_ret = (phys_ctx->callbacks.init_ssl == NULL)
15755 ? 0
15756 : (phys_ctx->callbacks.init_ssl(dom_ctx->ssl_ctx,
15757 phys_ctx->user_data));
15758
15759 /* If callback returns 0, civetweb sets up the SSL certificate.
15760 * If it returns 1, civetweb assumes the calback already did this.
15761 * If it returns -1, initializing ssl fails. */
15762 if (callback_ret < 0) {
15763 mg_cry_internal(fc(phys_ctx),
15764 "SSL callback returned error: %i",
15765 callback_ret);
15766 return 0;
15767 }
15768 if (callback_ret > 0) {
15769 /* Callback did everything. */
15770 return 1;
15771 }
15772
15773 /* Use some combination of start time, domain and port as a SSL
15774 * context ID. This should be unique on the current machine. */
15775 md5_init(&md5state);
15776 clock_gettime(CLOCK_MONOTONIC, &now_mt);
15777 md5_append(&md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt));
15778 md5_append(&md5state,
15779 (const md5_byte_t *)phys_ctx->dd.config[LISTENING_PORTS],
15780 strlen(phys_ctx->dd.config[LISTENING_PORTS]));
15781 md5_append(&md5state,
15782 (const md5_byte_t *)dom_ctx->config[AUTHENTICATION_DOMAIN],
15783 strlen(dom_ctx->config[AUTHENTICATION_DOMAIN]));
15784 md5_append(&md5state, (const md5_byte_t *)phys_ctx, sizeof(*phys_ctx));
15785 md5_append(&md5state, (const md5_byte_t *)dom_ctx, sizeof(*dom_ctx));
15786 md5_finish(&md5state, ssl_context_id);
15787
15789 (unsigned char *)ssl_context_id,
15790 sizeof(ssl_context_id));
15791
15792 if (pem != NULL) {
15793 if (!ssl_use_pem_file(phys_ctx, dom_ctx, pem, chain)) {
15794 return 0;
15795 }
15796 }
15797
15798 /* Should we support client certificates? */
15799 /* Default is "no". */
15800 should_verify_peer = 0;
15801 peer_certificate_optional = 0;
15802 if (dom_ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
15803 if (mg_strcasecmp(dom_ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0) {
15804 /* Yes, they are mandatory */
15805 should_verify_peer = 1;
15806 peer_certificate_optional = 0;
15807 } else if (mg_strcasecmp(dom_ctx->config[SSL_DO_VERIFY_PEER],
15808 "optional")
15809 == 0) {
15810 /* Yes, they are optional */
15811 should_verify_peer = 1;
15812 peer_certificate_optional = 1;
15813 }
15814 }
15815
15816 use_default_verify_paths =
15817 (dom_ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
15818 && (mg_strcasecmp(dom_ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes")
15819 == 0);
15820
15821 if (should_verify_peer) {
15822 ca_path = dom_ctx->config[SSL_CA_PATH];
15823 ca_file = dom_ctx->config[SSL_CA_FILE];
15824 if (SSL_CTX_load_verify_locations(dom_ctx->ssl_ctx, ca_file, ca_path)
15825 != 1) {
15826 mg_cry_internal(fc(phys_ctx),
15827 "SSL_CTX_load_verify_locations error: %s "
15828 "ssl_verify_peer requires setting "
15829 "either ssl_ca_path or ssl_ca_file. "
15830 "Is any of them present in the "
15831 ".conf file?",
15832 ssl_error());
15833 return 0;
15834 }
15835
15836 if (peer_certificate_optional) {
15838 } else {
15839 SSL_CTX_set_verify(dom_ctx->ssl_ctx,
15842 NULL);
15843 }
15844
15845 if (use_default_verify_paths
15846 && (SSL_CTX_set_default_verify_paths(dom_ctx->ssl_ctx) != 1)) {
15847 mg_cry_internal(fc(phys_ctx),
15848 "SSL_CTX_set_default_verify_paths error: %s",
15849 ssl_error());
15850 return 0;
15851 }
15852
15853 if (dom_ctx->config[SSL_VERIFY_DEPTH]) {
15854 verify_depth = atoi(dom_ctx->config[SSL_VERIFY_DEPTH]);
15855 SSL_CTX_set_verify_depth(dom_ctx->ssl_ctx, verify_depth);
15856 }
15857 }
15858
15859 if (dom_ctx->config[SSL_CIPHER_LIST] != NULL) {
15860 if (SSL_CTX_set_cipher_list(dom_ctx->ssl_ctx,
15861 dom_ctx->config[SSL_CIPHER_LIST])
15862 != 1) {
15863 mg_cry_internal(fc(phys_ctx),
15864 "SSL_CTX_set_cipher_list error: %s",
15865 ssl_error());
15866 }
15867 }
15868
15869 return 1;
15870}
15871
15872
15873/* Check if SSL is required.
15874 * If so, dynamically load SSL library
15875 * and set up ctx->ssl_ctx pointer. */
15876static int
15877init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
15878{
15879 void *ssl_ctx = 0;
15880 int callback_ret;
15881 const char *pem;
15882 const char *chain;
15883 char ebuf[128];
15884
15885 if (!phys_ctx) {
15886 return 0;
15887 }
15888
15889 if (!dom_ctx) {
15890 dom_ctx = &(phys_ctx->dd);
15891 }
15892
15893 if (!is_ssl_port_used(dom_ctx->config[LISTENING_PORTS])) {
15894 /* No SSL port is set. No need to setup SSL. */
15895 return 1;
15896 }
15897
15898 /* Check for external SSL_CTX */
15899 callback_ret =
15900 (phys_ctx->callbacks.external_ssl_ctx == NULL)
15901 ? 0
15902 : (phys_ctx->callbacks.external_ssl_ctx(&ssl_ctx,
15903 phys_ctx->user_data));
15904
15905 if (callback_ret < 0) {
15906 mg_cry_internal(fc(phys_ctx),
15907 "external_ssl_ctx callback returned error: %i",
15908 callback_ret);
15909 return 0;
15910 } else if (callback_ret > 0) {
15911 dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
15912 if (!initialize_ssl(ebuf, sizeof(ebuf))) {
15913 mg_cry_internal(fc(phys_ctx), "%s", ebuf);
15914 return 0;
15915 }
15916 return 1;
15917 }
15918 /* else: external_ssl_ctx does not exist or returns 0,
15919 * CivetWeb should continue initializing SSL */
15920
15921 /* If PEM file is not specified and the init_ssl callback
15922 * is not specified, setup will fail. */
15923 if (((pem = dom_ctx->config[SSL_CERTIFICATE]) == NULL)
15924 && (phys_ctx->callbacks.init_ssl == NULL)) {
15925 /* No certificate and no callback:
15926 * Essential data to set up TLS is missing.
15927 */
15928 mg_cry_internal(fc(phys_ctx),
15929 "Initializing SSL failed: -%s is not set",
15931 return 0;
15932 }
15933
15934 chain = dom_ctx->config[SSL_CERTIFICATE_CHAIN];
15935 if (chain == NULL) {
15936 chain = pem;
15937 }
15938 if ((chain != NULL) && (*chain == 0)) {
15939 chain = NULL;
15940 }
15941
15942 if (!initialize_ssl(ebuf, sizeof(ebuf))) {
15943 mg_cry_internal(fc(phys_ctx), "%s", ebuf);
15944 return 0;
15945 }
15946
15947 return init_ssl_ctx_impl(phys_ctx, dom_ctx, pem, chain);
15948}
15949
15950
15951static void
15953{
15954#if defined(OPENSSL_API_1_1)
15955
15956 if (mg_atomic_dec(&cryptolib_users) == 0) {
15957
15958 /* Shutdown according to
15959 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
15960 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
15961 */
15963#else
15964 int i;
15965
15966 if (mg_atomic_dec(&cryptolib_users) == 0) {
15967
15968 /* Shutdown according to
15969 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
15970 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
15971 */
15977 EVP_cleanup();
15980
15981 for (i = 0; i < CRYPTO_num_locks(); i++) {
15982 pthread_mutex_destroy(&ssl_mutexes[i]);
15983 }
15985 ssl_mutexes = NULL;
15986#endif /* OPENSSL_API_1_1 */
15987 }
15988}
15989#endif /* !NO_SSL */
15990
15991
15992static int
15993set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
15994{
15995 if (phys_ctx) {
15997 const char *path;
15998 if (!dom_ctx) {
15999 dom_ctx = &(phys_ctx->dd);
16000 }
16001 path = dom_ctx->config[GLOBAL_PASSWORDS_FILE];
16002 if ((path != NULL) && !mg_stat(fc(phys_ctx), path, &file.stat)) {
16003 mg_cry_internal(fc(phys_ctx),
16004 "Cannot open %s: %s",
16005 path,
16006 strerror(ERRNO));
16007 return 0;
16008 }
16009 return 1;
16010 }
16011 return 0;
16012}
16013
16014
16015static int
16017{
16018 return check_acl(phys_ctx, (uint32_t)0x7f000001UL) != -1;
16019}
16020
16021
16022static void
16024{
16025 if (!conn) {
16026 return;
16027 }
16028 conn->connection_type =
16029 CONNECTION_TYPE_INVALID; /* Not yet a valid request/response */
16030
16031 conn->num_bytes_sent = conn->consumed_content = 0;
16032
16033 conn->path_info = NULL;
16034 conn->status_code = -1;
16035 conn->content_len = -1;
16036 conn->is_chunked = 0;
16037 conn->must_close = 0;
16038 conn->request_len = 0;
16039 conn->throttle = 0;
16040 conn->data_len = 0;
16041 conn->chunk_remainder = 0;
16042 conn->accept_gzip = 0;
16043
16047 conn->response_info.status_text = NULL;
16048 conn->response_info.status_code = 0;
16049
16050 conn->request_info.remote_user = NULL;
16051 conn->request_info.request_method = NULL;
16052 conn->request_info.request_uri = NULL;
16053 conn->request_info.local_uri = NULL;
16054
16055#if defined(MG_LEGACY_INTERFACE)
16056 /* Legacy before split into local_uri and request_uri */
16057 conn->request_info.uri = NULL;
16058#endif
16059}
16060
16061
16062#if 0
16063/* Note: set_sock_timeout is not required for non-blocking sockets.
16064 * Leave this function here (commented out) for reference until
16065 * CivetWeb 1.9 is tested, and the tests confirme this function is
16066 * no longer required.
16067*/
16068static int
16069set_sock_timeout(SOCKET sock, int milliseconds)
16070{
16071 int r0 = 0, r1, r2;
16072
16073#if defined(_WIN32)
16074 /* Windows specific */
16075
16076 DWORD tv = (DWORD)milliseconds;
16077
16078#else
16079 /* Linux, ... (not Windows) */
16080
16081 struct timeval tv;
16082
16083/* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
16084 * max. time waiting for the acknowledged of TCP data before the connection
16085 * will be forcefully closed and ETIMEDOUT is returned to the application.
16086 * If this option is not set, the default timeout of 20-30 minutes is used.
16087*/
16088/* #define TCP_USER_TIMEOUT (18) */
16089
16090#if defined(TCP_USER_TIMEOUT)
16091 unsigned int uto = (unsigned int)milliseconds;
16092 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (const void *)&uto, sizeof(uto));
16093#endif
16094
16095 memset(&tv, 0, sizeof(tv));
16096 tv.tv_sec = milliseconds / 1000;
16097 tv.tv_usec = (milliseconds * 1000) % 1000000;
16098
16099#endif /* _WIN32 */
16100
16101 r1 = setsockopt(
16102 sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
16103 r2 = setsockopt(
16104 sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
16105
16106 return r0 || r1 || r2;
16107}
16108#endif
16109
16110
16111static int
16112set_tcp_nodelay(SOCKET sock, int nodelay_on)
16113{
16114 if (setsockopt(sock,
16115 IPPROTO_TCP,
16116 TCP_NODELAY,
16117 (SOCK_OPT_TYPE)&nodelay_on,
16118 sizeof(nodelay_on))
16119 != 0) {
16120 /* Error */
16121 return 1;
16122 }
16123 /* OK */
16124 return 0;
16125}
16126
16127
16128static void
16130{
16131#if defined(_WIN32)
16132 char buf[MG_BUF_LEN];
16133 int n;
16134#endif
16135 struct linger linger;
16136 int error_code = 0;
16137 int linger_timeout = -2;
16138 socklen_t opt_len = sizeof(error_code);
16139
16140 if (!conn) {
16141 return;
16142 }
16143
16144 /* http://msdn.microsoft.com/en-us/library/ms739165(v=vs.85).aspx:
16145 * "Note that enabling a nonzero timeout on a nonblocking socket
16146 * is not recommended.", so set it to blocking now */
16148
16149 /* Send FIN to the client */
16150 shutdown(conn->client.sock, SHUTDOWN_WR);
16151
16152
16153#if defined(_WIN32)
16154 /* Read and discard pending incoming data. If we do not do that and
16155 * close
16156 * the socket, the data in the send buffer may be discarded. This
16157 * behaviour is seen on Windows, when client keeps sending data
16158 * when server decides to close the connection; then when client
16159 * does recv() it gets no data back. */
16160 do {
16161 n = pull_inner(NULL, conn, buf, sizeof(buf), /* Timeout in s: */ 1.0);
16162 } while (n > 0);
16163#endif
16164
16165 if (conn->dom_ctx->config[LINGER_TIMEOUT]) {
16166 linger_timeout = atoi(conn->dom_ctx->config[LINGER_TIMEOUT]);
16167 }
16168
16169 /* Set linger option according to configuration */
16170 if (linger_timeout >= 0) {
16171 /* Set linger option to avoid socket hanging out after close. This
16172 * prevent ephemeral port exhaust problem under high QPS. */
16173 linger.l_onoff = 1;
16174
16175#if defined(_MSC_VER)
16176#pragma warning(push)
16177#pragma warning(disable : 4244)
16178#endif
16179#if defined(GCC_DIAGNOSTIC)
16180#pragma GCC diagnostic push
16181#pragma GCC diagnostic ignored "-Wconversion"
16182#endif
16183 /* Data type of linger structure elements may differ,
16184 * so we don't know what cast we need here.
16185 * Disable type conversion warnings. */
16186
16187 linger.l_linger = (linger_timeout + 999) / 1000;
16188
16189#if defined(GCC_DIAGNOSTIC)
16190#pragma GCC diagnostic pop
16191#endif
16192#if defined(_MSC_VER)
16193#pragma warning(pop)
16194#endif
16195
16196 } else {
16197 linger.l_onoff = 0;
16198 linger.l_linger = 0;
16199 }
16200
16201 if (linger_timeout < -1) {
16202 /* Default: don't configure any linger */
16203 } else if (getsockopt(conn->client.sock,
16204 SOL_SOCKET,
16205 SO_ERROR,
16206#if defined(_WIN32) /* WinSock uses different data type here */
16207 (char *)&error_code,
16208#else
16209 &error_code,
16210#endif
16211 &opt_len)
16212 != 0) {
16213 /* Cannot determine if socket is already closed. This should
16214 * not occur and never did in a test. Log an error message
16215 * and continue. */
16216 mg_cry_internal(conn,
16217 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
16218 __func__,
16219 strerror(ERRNO));
16220 } else if (error_code == ECONNRESET) {
16221 /* Socket already closed by client/peer, close socket without linger
16222 */
16223 } else {
16224
16225 /* Set linger timeout */
16226 if (setsockopt(conn->client.sock,
16227 SOL_SOCKET,
16228 SO_LINGER,
16229 (char *)&linger,
16230 sizeof(linger))
16231 != 0) {
16233 conn,
16234 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
16235 __func__,
16236 linger.l_onoff,
16237 linger.l_linger,
16238 strerror(ERRNO));
16239 }
16240 }
16241
16242 /* Now we know that our FIN is ACK-ed, safe to close */
16243 closesocket(conn->client.sock);
16244 conn->client.sock = INVALID_SOCKET;
16245}
16246
16247
16248static void
16250{
16251#if defined(USE_SERVER_STATS)
16252 conn->conn_state = 6; /* to close */
16253#endif
16254
16255#if defined(USE_LUA) && defined(USE_WEBSOCKET)
16256 if (conn->lua_websocket_state) {
16257 lua_websocket_close(conn, conn->lua_websocket_state);
16258 conn->lua_websocket_state = NULL;
16259 }
16260#endif
16261
16262 mg_lock_connection(conn);
16263
16264 /* Set close flag, so keep-alive loops will stop */
16265 conn->must_close = 1;
16266
16267 /* call the connection_close callback if assigned */
16268 if (conn->phys_ctx->callbacks.connection_close != NULL) {
16269 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
16270 conn->phys_ctx->callbacks.connection_close(conn);
16271 }
16272 }
16273
16274 /* Reset user data, after close callback is called.
16275 * Do not reuse it. If the user needs a destructor,
16276 * it must be done in the connection_close callback. */
16277 mg_set_user_connection_data(conn, NULL);
16278
16279
16280#if defined(USE_SERVER_STATS)
16281 conn->conn_state = 7; /* closing */
16282#endif
16283
16284#if !defined(NO_SSL)
16285 if (conn->ssl != NULL) {
16286 /* Run SSL_shutdown twice to ensure completely close SSL connection
16287 */
16288 SSL_shutdown(conn->ssl);
16289 SSL_free(conn->ssl);
16291 conn->ssl = NULL;
16292 }
16293#endif
16294 if (conn->client.sock != INVALID_SOCKET) {
16296 conn->client.sock = INVALID_SOCKET;
16297 }
16298
16299 if (conn->host) {
16300 mg_free((void *)conn->host);
16301 conn->host = NULL;
16302 }
16303
16305
16306#if defined(USE_SERVER_STATS)
16307 conn->conn_state = 8; /* closed */
16308#endif
16309}
16310
16311
16312void
16314{
16315#if defined(USE_WEBSOCKET)
16316 struct mg_context *client_ctx = NULL;
16317#endif /* defined(USE_WEBSOCKET) */
16318
16319 if ((conn == NULL) || (conn->phys_ctx == NULL)) {
16320 return;
16321 }
16322
16323#if defined(USE_WEBSOCKET)
16324 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
16325 if (conn->in_websocket_handling) {
16326 /* Set close flag, so the server thread can exit. */
16327 conn->must_close = 1;
16328 return;
16329 }
16330 }
16331 if (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT) {
16332
16333 unsigned int i;
16334
16335 /* ws/wss client */
16336 client_ctx = conn->phys_ctx;
16337
16338 /* client context: loops must end */
16339 client_ctx->stop_flag = 1;
16340 conn->must_close = 1;
16341
16342 /* We need to get the client thread out of the select/recv call
16343 * here. */
16344 /* Since we use a sleep quantum of some seconds to check for recv
16345 * timeouts, we will just wait a few seconds in mg_join_thread. */
16346
16347 /* join worker thread */
16348 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
16349 if (client_ctx->worker_threadids[i] != 0) {
16350 mg_join_thread(client_ctx->worker_threadids[i]);
16351 }
16352 }
16353 }
16354#endif /* defined(USE_WEBSOCKET) */
16355
16356 close_connection(conn);
16357
16358#if !defined(NO_SSL)
16359 if (conn->client_ssl_ctx != NULL) {
16361 }
16362#endif
16363
16364#if defined(USE_WEBSOCKET)
16365 if (client_ctx != NULL) {
16366 /* free context */
16367 mg_free(client_ctx->worker_threadids);
16368 mg_free(client_ctx);
16369 (void)pthread_mutex_destroy(&conn->mutex);
16370 mg_free(conn);
16371 } else if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) {
16372 mg_free(conn);
16373 }
16374#else
16375 if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) { /* Client */
16376 mg_free(conn);
16377 }
16378#endif /* defined(USE_WEBSOCKET) */
16379}
16380
16381
16382/* Only for memory statistics */
16384
16385
16386static struct mg_connection *
16387mg_connect_client_impl(const struct mg_client_options *client_options,
16388 int use_ssl,
16389 char *ebuf,
16390 size_t ebuf_len)
16391{
16392 struct mg_connection *conn = NULL;
16393 SOCKET sock;
16394 union usa sa;
16395 struct sockaddr *psa;
16396 socklen_t len;
16397
16398 unsigned max_req_size =
16399 (unsigned)atoi(config_options[MAX_REQUEST_SIZE].default_value);
16400
16401 /* Size of structures, aligned to 8 bytes */
16402 size_t conn_size = ((sizeof(struct mg_connection) + 7) >> 3) << 3;
16403 size_t ctx_size = ((sizeof(struct mg_context) + 7) >> 3) << 3;
16404
16405 conn = (struct mg_connection *)mg_calloc_ctx(
16406 1, conn_size + ctx_size + max_req_size, &common_client_context);
16407
16408 if (conn == NULL) {
16409 mg_snprintf(NULL,
16410 NULL, /* No truncation check for ebuf */
16411 ebuf,
16412 ebuf_len,
16413 "calloc(): %s",
16414 strerror(ERRNO));
16415 return NULL;
16416 }
16417
16418#if defined(GCC_DIAGNOSTIC)
16419#pragma GCC diagnostic push
16420#pragma GCC diagnostic ignored "-Wcast-align"
16421#endif /* defined(GCC_DIAGNOSTIC) */
16422 /* conn_size is aligned to 8 bytes */
16423
16424 conn->phys_ctx = (struct mg_context *)(((char *)conn) + conn_size);
16425
16426#if defined(GCC_DIAGNOSTIC)
16427#pragma GCC diagnostic pop
16428#endif /* defined(GCC_DIAGNOSTIC) */
16429
16430 conn->buf = (((char *)conn) + conn_size + ctx_size);
16431 conn->buf_size = (int)max_req_size;
16433 conn->dom_ctx = &(conn->phys_ctx->dd);
16434
16436 client_options->host,
16437 client_options->port,
16438 use_ssl,
16439 ebuf,
16440 ebuf_len,
16441 &sock,
16442 &sa)) {
16443 /* ebuf is set by connect_socket,
16444 * free all memory and return NULL; */
16445 mg_free(conn);
16446 return NULL;
16447 }
16448
16449#if !defined(NO_SSL)
16450#if defined(OPENSSL_API_1_1)
16451 if (use_ssl
16452 && (conn->client_ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
16453 mg_snprintf(NULL,
16454 NULL, /* No truncation check for ebuf */
16455 ebuf,
16456 ebuf_len,
16457 "SSL_CTX_new error");
16458 closesocket(sock);
16459 mg_free(conn);
16460 return NULL;
16461 }
16462#else
16463 if (use_ssl
16465 == NULL) {
16466 mg_snprintf(NULL,
16467 NULL, /* No truncation check for ebuf */
16468 ebuf,
16469 ebuf_len,
16470 "SSL_CTX_new error");
16471 closesocket(sock);
16472 mg_free(conn);
16473 return NULL;
16474 }
16475#endif /* OPENSSL_API_1_1 */
16476#endif /* NO_SSL */
16477
16478
16479#if defined(USE_IPV6)
16480 len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin)
16481 : sizeof(conn->client.rsa.sin6);
16482 psa = (sa.sa.sa_family == AF_INET)
16483 ? (struct sockaddr *)&(conn->client.rsa.sin)
16484 : (struct sockaddr *)&(conn->client.rsa.sin6);
16485#else
16486 len = sizeof(conn->client.rsa.sin);
16487 psa = (struct sockaddr *)&(conn->client.rsa.sin);
16488#endif
16489
16490 conn->client.sock = sock;
16491 conn->client.lsa = sa;
16492
16493 if (getsockname(sock, psa, &len) != 0) {
16494 mg_cry_internal(conn,
16495 "%s: getsockname() failed: %s",
16496 __func__,
16497 strerror(ERRNO));
16498 }
16499
16500 conn->client.is_ssl = use_ssl ? 1 : 0;
16501 if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
16502 mg_snprintf(NULL,
16503 NULL, /* No truncation check for ebuf */
16504 ebuf,
16505 ebuf_len,
16506 "Can not create mutex");
16507#if !defined(NO_SSL)
16509#endif
16510 closesocket(sock);
16511 mg_free(conn);
16512 return NULL;
16513 }
16514
16515
16516#if !defined(NO_SSL)
16517 if (use_ssl) {
16519
16520 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
16521 * SSL_CTX_set_verify call is needed to switch off server
16522 * certificate checking, which is off by default in OpenSSL and
16523 * on in yaSSL. */
16524 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
16525 * SSL_VERIFY_PEER, verify_ssl_server); */
16526
16527 if (client_options->client_cert) {
16530 client_options->client_cert,
16531 NULL)) {
16532 mg_snprintf(NULL,
16533 NULL, /* No truncation check for ebuf */
16534 ebuf,
16535 ebuf_len,
16536 "Can not use SSL client certificate");
16538 closesocket(sock);
16539 mg_free(conn);
16540 return NULL;
16541 }
16542 }
16543
16544 if (client_options->server_cert) {
16546 client_options->server_cert,
16547 NULL);
16549 } else {
16551 }
16552
16553 if (!sslize(conn,
16554 conn->client_ssl_ctx,
16556 &(conn->phys_ctx->stop_flag),
16557 client_options)) {
16558 mg_snprintf(NULL,
16559 NULL, /* No truncation check for ebuf */
16560 ebuf,
16561 ebuf_len,
16562 "SSL connection error");
16564 closesocket(sock);
16565 mg_free(conn);
16566 return NULL;
16567 }
16568 }
16569#endif
16570
16571 if (0 != set_non_blocking_mode(sock)) {
16572 mg_cry_internal(conn,
16573 "Cannot set non-blocking mode for client %s:%i",
16574 client_options->host,
16575 client_options->port);
16576 }
16577
16578 return conn;
16579}
16580
16581
16583mg_connect_client_secure(const struct mg_client_options *client_options,
16584 char *error_buffer,
16585 size_t error_buffer_size)
16586{
16587 return mg_connect_client_impl(client_options,
16588 1,
16589 error_buffer,
16590 error_buffer_size);
16591}
16592
16593
16594struct mg_connection *
16596 int port,
16597 int use_ssl,
16598 char *error_buffer,
16599 size_t error_buffer_size)
16600{
16601 struct mg_client_options opts;
16602 memset(&opts, 0, sizeof(opts));
16603 opts.host = host;
16604 opts.port = port;
16605 return mg_connect_client_impl(&opts,
16606 use_ssl,
16607 error_buffer,
16608 error_buffer_size);
16609}
16610
16611
16612static const struct {
16613 const char *proto;
16616} abs_uri_protocols[] = {{"http://", 7, 80},
16617 {"https://", 8, 443},
16618 {"ws://", 5, 80},
16619 {"wss://", 6, 443},
16620 {NULL, 0, 0}};
16621
16622
16623/* Check if the uri is valid.
16624 * return 0 for invalid uri,
16625 * return 1 for *,
16626 * return 2 for relative uri,
16627 * return 3 for absolute uri without port,
16628 * return 4 for absolute uri with port */
16629static int
16630get_uri_type(const char *uri)
16631{
16632 int i;
16633 const char *hostend, *portbegin;
16634 char *portend;
16635 unsigned long port;
16636
16637 /* According to the HTTP standard
16638 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
16639 * URI can be an asterisk (*) or should start with slash (relative uri),
16640 * or it should start with the protocol (absolute uri). */
16641 if ((uri[0] == '*') && (uri[1] == '\0')) {
16642 /* asterisk */
16643 return 1;
16644 }
16645
16646 /* Valid URIs according to RFC 3986
16647 * (https://www.ietf.org/rfc/rfc3986.txt)
16648 * must only contain reserved characters :/?#[]@!$&'()*+,;=
16649 * and unreserved characters A-Z a-z 0-9 and -._~
16650 * and % encoded symbols.
16651 */
16652 for (i = 0; uri[i] != 0; i++) {
16653 if (uri[i] < 33) {
16654 /* control characters and spaces are invalid */
16655 return 0;
16656 }
16657 if (uri[i] > 126) {
16658 /* non-ascii characters must be % encoded */
16659 return 0;
16660 } else {
16661 switch (uri[i]) {
16662 case '"': /* 34 */
16663 case '<': /* 60 */
16664 case '>': /* 62 */
16665 case '\\': /* 92 */
16666 case '^': /* 94 */
16667 case '`': /* 96 */
16668 case '{': /* 123 */
16669 case '|': /* 124 */
16670 case '}': /* 125 */
16671 return 0;
16672 default:
16673 /* character is ok */
16674 break;
16675 }
16676 }
16677 }
16678
16679 /* A relative uri starts with a / character */
16680 if (uri[0] == '/') {
16681 /* relative uri */
16682 return 2;
16683 }
16684
16685 /* It could be an absolute uri: */
16686 /* This function only checks if the uri is valid, not if it is
16687 * addressing the current server. So civetweb can also be used
16688 * as a proxy server. */
16689 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
16690 if (mg_strncasecmp(uri,
16693 == 0) {
16694
16695 hostend = strchr(uri + abs_uri_protocols[i].proto_len, '/');
16696 if (!hostend) {
16697 return 0;
16698 }
16699 portbegin = strchr(uri + abs_uri_protocols[i].proto_len, ':');
16700 if (!portbegin) {
16701 return 3;
16702 }
16703
16704 port = strtoul(portbegin + 1, &portend, 10);
16705 if ((portend != hostend) || (port <= 0) || !is_valid_port(port)) {
16706 return 0;
16707 }
16708
16709 return 4;
16710 }
16711 }
16712
16713 return 0;
16714}
16715
16716
16717/* Return NULL or the relative uri at the current server */
16718static const char *
16719get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
16720{
16721 const char *server_domain;
16722 size_t server_domain_len;
16723 size_t request_domain_len = 0;
16724 unsigned long port = 0;
16725 int i, auth_domain_check_enabled;
16726 const char *hostbegin = NULL;
16727 const char *hostend = NULL;
16728 const char *portbegin;
16729 char *portend;
16730
16731 auth_domain_check_enabled =
16733
16734 /* DNS is case insensitive, so use case insensitive string compare here
16735 */
16736 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
16737 if (mg_strncasecmp(uri,
16740 == 0) {
16741
16742 hostbegin = uri + abs_uri_protocols[i].proto_len;
16743 hostend = strchr(hostbegin, '/');
16744 if (!hostend) {
16745 return 0;
16746 }
16747 portbegin = strchr(hostbegin, ':');
16748 if ((!portbegin) || (portbegin > hostend)) {
16749 port = abs_uri_protocols[i].default_port;
16750 request_domain_len = (size_t)(hostend - hostbegin);
16751 } else {
16752 port = strtoul(portbegin + 1, &portend, 10);
16753 if ((portend != hostend) || (port <= 0)
16754 || !is_valid_port(port)) {
16755 return 0;
16756 }
16757 request_domain_len = (size_t)(portbegin - hostbegin);
16758 }
16759 /* protocol found, port set */
16760 break;
16761 }
16762 }
16763
16764 if (!port) {
16765 /* port remains 0 if the protocol is not found */
16766 return 0;
16767 }
16768
16769/* Check if the request is directed to a different server. */
16770/* First check if the port is the same (IPv4 and IPv6). */
16771#if defined(USE_IPV6)
16772 if (conn->client.lsa.sa.sa_family == AF_INET6) {
16773 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
16774 /* Request is directed to a different port */
16775 return 0;
16776 }
16777 } else
16778#endif
16779 {
16780 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
16781 /* Request is directed to a different port */
16782 return 0;
16783 }
16784 }
16785
16786 /* Finally check if the server corresponds to the authentication
16787 * domain of the server (the server domain).
16788 * Allow full matches (like http://mydomain.com/path/file.ext), and
16789 * allow subdomain matches (like http://www.mydomain.com/path/file.ext),
16790 * but do not allow substrings (like
16791 * http://notmydomain.com/path/file.ext
16792 * or http://mydomain.com.fake/path/file.ext).
16793 */
16794 if (auth_domain_check_enabled) {
16795 server_domain = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
16796 server_domain_len = strlen(server_domain);
16797 if ((server_domain_len == 0) || (hostbegin == NULL)) {
16798 return 0;
16799 }
16800 if ((request_domain_len == server_domain_len)
16801 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
16802 /* Request is directed to this server - full name match. */
16803 } else {
16804 if (request_domain_len < (server_domain_len + 2)) {
16805 /* Request is directed to another server: The server name
16806 * is longer than the request name.
16807 * Drop this case here to avoid overflows in the
16808 * following checks. */
16809 return 0;
16810 }
16811 if (hostbegin[request_domain_len - server_domain_len - 1] != '.') {
16812 /* Request is directed to another server: It could be a
16813 * substring
16814 * like notmyserver.com */
16815 return 0;
16816 }
16817 if (0
16818 != memcmp(server_domain,
16819 hostbegin + request_domain_len - server_domain_len,
16820 server_domain_len)) {
16821 /* Request is directed to another server:
16822 * The server name is different. */
16823 return 0;
16824 }
16825 }
16826 }
16827
16828 return hostend;
16829}
16830
16831
16832static int
16833get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
16834{
16835 if (ebuf_len > 0) {
16836 ebuf[0] = '\0';
16837 }
16838 *err = 0;
16839
16841
16842 if (!conn) {
16843 mg_snprintf(conn,
16844 NULL, /* No truncation check for ebuf */
16845 ebuf,
16846 ebuf_len,
16847 "%s",
16848 "Internal error");
16849 *err = 500;
16850 return 0;
16851 }
16852 /* Set the time the request was received. This value should be used for
16853 * timeouts. */
16854 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
16855
16856 conn->request_len =
16857 read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
16858 DEBUG_ASSERT(conn->request_len < 0 || conn->data_len >= conn->request_len);
16859 if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) {
16860 mg_snprintf(conn,
16861 NULL, /* No truncation check for ebuf */
16862 ebuf,
16863 ebuf_len,
16864 "%s",
16865 "Invalid message size");
16866 *err = 500;
16867 return 0;
16868 }
16869
16870 if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) {
16871 mg_snprintf(conn,
16872 NULL, /* No truncation check for ebuf */
16873 ebuf,
16874 ebuf_len,
16875 "%s",
16876 "Message too large");
16877 *err = 413;
16878 return 0;
16879 }
16880
16881 if (conn->request_len <= 0) {
16882 if (conn->data_len > 0) {
16883 mg_snprintf(conn,
16884 NULL, /* No truncation check for ebuf */
16885 ebuf,
16886 ebuf_len,
16887 "%s",
16888 "Malformed message");
16889 *err = 400;
16890 } else {
16891 /* Server did not recv anything -> just close the connection */
16892 conn->must_close = 1;
16893 mg_snprintf(conn,
16894 NULL, /* No truncation check for ebuf */
16895 ebuf,
16896 ebuf_len,
16897 "%s",
16898 "No data received");
16899 *err = 0;
16900 }
16901 return 0;
16902 }
16903 return 1;
16904}
16905
16906
16907static int
16908get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
16909{
16910 const char *cl;
16911 if (!get_message(conn, ebuf, ebuf_len, err)) {
16912 return 0;
16913 }
16914
16915 if (parse_http_request(conn->buf, conn->buf_size, &conn->request_info)
16916 <= 0) {
16917 mg_snprintf(conn,
16918 NULL, /* No truncation check for ebuf */
16919 ebuf,
16920 ebuf_len,
16921 "%s",
16922 "Bad request");
16923 *err = 400;
16924 return 0;
16925 }
16926
16927 /* Message is a valid request */
16928
16929 /* Is there a "host" ? */
16930 conn->host = alloc_get_host(conn);
16931 if (!conn->host) {
16932 mg_snprintf(conn,
16933 NULL, /* No truncation check for ebuf */
16934 ebuf,
16935 ebuf_len,
16936 "%s",
16937 "Bad request: Host mismatch");
16938 *err = 400;
16939 return 0;
16940 }
16941
16942 /* Do we know the content length? */
16943 if ((cl = get_header(conn->request_info.http_headers,
16945 "Content-Length"))
16946 != NULL) {
16947 /* Request/response has content length set */
16948 char *endptr = NULL;
16949 conn->content_len = strtoll(cl, &endptr, 10);
16950 if (endptr == cl) {
16951 mg_snprintf(conn,
16952 NULL, /* No truncation check for ebuf */
16953 ebuf,
16954 ebuf_len,
16955 "%s",
16956 "Bad request");
16957 *err = 411;
16958 return 0;
16959 }
16960 /* Publish the content length back to the request info. */
16962 } else if ((cl = get_header(conn->request_info.http_headers,
16964 "Transfer-Encoding"))
16965 != NULL
16966 && !mg_strcasecmp(cl, "chunked")) {
16967 conn->is_chunked = 1;
16968 conn->content_len = -1; /* unknown content length */
16969 } else {
16970 const struct mg_http_method_info *meth =
16972 if (!meth) {
16973 /* No valid HTTP method */
16974 mg_snprintf(conn,
16975 NULL, /* No truncation check for ebuf */
16976 ebuf,
16977 ebuf_len,
16978 "%s",
16979 "Bad request");
16980 *err = 411;
16981 return 0;
16982 }
16983 if (meth->request_has_body) {
16984 /* POST or PUT request without content length set */
16985 conn->content_len = -1; /* unknown content length */
16986 } else {
16987 /* Other request */
16988 conn->content_len = 0; /* No content */
16989 }
16990 }
16991
16992 conn->connection_type = CONNECTION_TYPE_REQUEST; /* Valid request */
16993 return 1;
16994}
16995
16996
16997/* conn is assumed to be valid in this internal function */
16998static int
16999get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
17000{
17001 const char *cl;
17002 if (!get_message(conn, ebuf, ebuf_len, err)) {
17003 return 0;
17004 }
17005
17006 if (parse_http_response(conn->buf, conn->buf_size, &conn->response_info)
17007 <= 0) {
17008 mg_snprintf(conn,
17009 NULL, /* No truncation check for ebuf */
17010 ebuf,
17011 ebuf_len,
17012 "%s",
17013 "Bad response");
17014 *err = 400;
17015 return 0;
17016 }
17017
17018 /* Message is a valid response */
17019
17020 /* Do we know the content length? */
17021 if ((cl = get_header(conn->response_info.http_headers,
17023 "Content-Length"))
17024 != NULL) {
17025 /* Request/response has content length set */
17026 char *endptr = NULL;
17027 conn->content_len = strtoll(cl, &endptr, 10);
17028 if (endptr == cl) {
17029 mg_snprintf(conn,
17030 NULL, /* No truncation check for ebuf */
17031 ebuf,
17032 ebuf_len,
17033 "%s",
17034 "Bad request");
17035 *err = 411;
17036 return 0;
17037 }
17038 /* Publish the content length back to the response info. */
17040
17041 /* TODO: check if it is still used in response_info */
17043
17044 } else if ((cl = get_header(conn->response_info.http_headers,
17046 "Transfer-Encoding"))
17047 != NULL
17048 && !mg_strcasecmp(cl, "chunked")) {
17049 conn->is_chunked = 1;
17050 conn->content_len = -1; /* unknown content length */
17051 } else {
17052 conn->content_len = -1; /* unknown content length */
17053 }
17054
17055 conn->connection_type = CONNECTION_TYPE_RESPONSE; /* Valid response */
17056 return 1;
17057}
17058
17059
17060int
17062 char *ebuf,
17063 size_t ebuf_len,
17064 int timeout)
17065{
17066 int err, ret;
17067 char txt[32]; /* will not overflow */
17068 char *save_timeout;
17069 char *new_timeout;
17070
17071 if (ebuf_len > 0) {
17072 ebuf[0] = '\0';
17073 }
17074
17075 if (!conn) {
17076 mg_snprintf(conn,
17077 NULL, /* No truncation check for ebuf */
17078 ebuf,
17079 ebuf_len,
17080 "%s",
17081 "Parameter error");
17082 return -1;
17083 }
17084
17085 /* Implementation of API function for HTTP clients */
17086 save_timeout = conn->dom_ctx->config[REQUEST_TIMEOUT];
17087
17088 if (timeout >= 0) {
17089 mg_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout);
17090 new_timeout = txt;
17091 /* Not required for non-blocking sockets.
17092 set_sock_timeout(conn->client.sock, timeout);
17093 */
17094 } else {
17095 new_timeout = NULL;
17096 }
17097
17098 conn->dom_ctx->config[REQUEST_TIMEOUT] = new_timeout;
17099 ret = get_response(conn, ebuf, ebuf_len, &err);
17100 conn->dom_ctx->config[REQUEST_TIMEOUT] = save_timeout;
17101
17102#if defined(MG_LEGACY_INTERFACE)
17103 /* TODO: 1) uri is deprecated;
17104 * 2) here, ri.uri is the http response code */
17105 conn->request_info.uri = conn->request_info.request_uri;
17106#endif
17108
17109 /* TODO (mid): Define proper return values - maybe return length?
17110 * For the first test use <0 for error and >0 for OK */
17111 return (ret == 0) ? -1 : +1;
17112}
17113
17114
17115struct mg_connection *
17116mg_download(const char *host,
17117 int port,
17118 int use_ssl,
17119 char *ebuf,
17120 size_t ebuf_len,
17121 const char *fmt,
17122 ...)
17123{
17124 struct mg_connection *conn;
17125 va_list ap;
17126 int i;
17127 int reqerr;
17128
17129 if (ebuf_len > 0) {
17130 ebuf[0] = '\0';
17131 }
17132
17133 va_start(ap, fmt);
17134
17135 /* open a connection */
17136 conn = mg_connect_client(host, port, use_ssl, ebuf, ebuf_len);
17137
17138 if (conn != NULL) {
17139 i = mg_vprintf(conn, fmt, ap);
17140 if (i <= 0) {
17141 mg_snprintf(conn,
17142 NULL, /* No truncation check for ebuf */
17143 ebuf,
17144 ebuf_len,
17145 "%s",
17146 "Error sending request");
17147 } else {
17148 get_response(conn, ebuf, ebuf_len, &reqerr);
17149
17150#if defined(MG_LEGACY_INTERFACE)
17151 /* TODO: 1) uri is deprecated;
17152 * 2) here, ri.uri is the http response code */
17153 conn->request_info.uri = conn->request_info.request_uri;
17154#endif
17156 }
17157 }
17158
17159 /* if an error occurred, close the connection */
17160 if ((ebuf[0] != '\0') && (conn != NULL)) {
17161 mg_close_connection(conn);
17162 conn = NULL;
17163 }
17164
17165 va_end(ap);
17166 return conn;
17167}
17168
17169
17175};
17176
17177
17178#if defined(USE_WEBSOCKET)
17179#if defined(_WIN32)
17180static unsigned __stdcall websocket_client_thread(void *data)
17181#else
17182static void *
17183websocket_client_thread(void *data)
17184#endif
17185{
17186 struct websocket_client_thread_data *cdata =
17187 (struct websocket_client_thread_data *)data;
17188
17189#if !defined(_WIN32)
17190 struct sigaction sa;
17191
17192 /* Ignore SIGPIPE */
17193 memset(&sa, 0, sizeof(sa));
17194 sa.sa_handler = SIG_IGN;
17195 sigaction(SIGPIPE, &sa, NULL);
17196#endif
17197
17198 mg_set_thread_name("ws-clnt");
17199
17200 if (cdata->conn->phys_ctx) {
17201 if (cdata->conn->phys_ctx->callbacks.init_thread) {
17202 /* 3 indicates a websocket client thread */
17203 /* TODO: check if conn->phys_ctx can be set */
17205 3);
17206 }
17207 }
17208
17209 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
17210
17211 DEBUG_TRACE("%s", "Websocket client thread exited\n");
17212
17213 if (cdata->close_handler != NULL) {
17214 cdata->close_handler(cdata->conn, cdata->callback_data);
17215 }
17216
17217 /* The websocket_client context has only this thread. If it runs out,
17218 set the stop_flag to 2 (= "stopped"). */
17219 cdata->conn->phys_ctx->stop_flag = 2;
17220
17221 mg_free((void *)cdata);
17222
17223#if defined(_WIN32)
17224 return 0;
17225#else
17226 return NULL;
17227#endif
17228}
17229#endif
17230
17231
17232struct mg_connection *
17234 int port,
17235 int use_ssl,
17236 char *error_buffer,
17237 size_t error_buffer_size,
17238 const char *path,
17239 const char *origin,
17240 mg_websocket_data_handler data_func,
17241 mg_websocket_close_handler close_func,
17242 void *user_data)
17243{
17244 struct mg_connection *conn = NULL;
17245
17246#if defined(USE_WEBSOCKET)
17247 struct mg_context *newctx = NULL;
17248 struct websocket_client_thread_data *thread_data;
17249 static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
17250 static const char *handshake_req;
17251
17252 if (origin != NULL) {
17253 handshake_req = "GET %s HTTP/1.1\r\n"
17254 "Host: %s\r\n"
17255 "Upgrade: websocket\r\n"
17256 "Connection: Upgrade\r\n"
17257 "Sec-WebSocket-Key: %s\r\n"
17258 "Sec-WebSocket-Version: 13\r\n"
17259 "Origin: %s\r\n"
17260 "\r\n";
17261 } else {
17262 handshake_req = "GET %s HTTP/1.1\r\n"
17263 "Host: %s\r\n"
17264 "Upgrade: websocket\r\n"
17265 "Connection: Upgrade\r\n"
17266 "Sec-WebSocket-Key: %s\r\n"
17267 "Sec-WebSocket-Version: 13\r\n"
17268 "\r\n";
17269 }
17270
17271#if defined(__clang__)
17272#pragma clang diagnostic push
17273#pragma clang diagnostic ignored "-Wformat-nonliteral"
17274#endif
17275
17276 /* Establish the client connection and request upgrade */
17277 conn = mg_download(host,
17278 port,
17279 use_ssl,
17280 error_buffer,
17281 error_buffer_size,
17282 handshake_req,
17283 path,
17284 host,
17285 magic,
17286 origin);
17287
17288#if defined(__clang__)
17289#pragma clang diagnostic pop
17290#endif
17291
17292 /* Connection object will be null if something goes wrong */
17293 if (conn == NULL) {
17294 if (!*error_buffer) {
17295 /* There should be already an error message */
17297 NULL, /* No truncation check for ebuf */
17298 error_buffer,
17299 error_buffer_size,
17300 "Unexpected error");
17301 }
17302 return NULL;
17303 }
17304
17305 if (conn->response_info.status_code != 101) {
17306 /* We sent an "upgrade" request. For a correct websocket
17307 * protocol handshake, we expect a "101 Continue" response.
17308 * Otherwise it is a protocol violation. Maybe the HTTP
17309 * Server does not know websockets. */
17310 if (!*error_buffer) {
17311 /* set an error, if not yet set */
17313 NULL, /* No truncation check for ebuf */
17314 error_buffer,
17315 error_buffer_size,
17316 "Unexpected server reply");
17317 }
17318
17319 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
17320 mg_free(conn);
17321 return NULL;
17322 }
17323
17324 /* For client connections, mg_context is fake. Since we need to set a
17325 * callback function, we need to create a copy and modify it. */
17326 newctx = (struct mg_context *)mg_malloc(sizeof(struct mg_context));
17327 if (!newctx) {
17328 DEBUG_TRACE("%s\r\n", "Out of memory");
17329 mg_free(conn);
17330 return NULL;
17331 }
17332
17333 memcpy(newctx, conn->phys_ctx, sizeof(struct mg_context));
17334 newctx->user_data = user_data;
17335 newctx->context_type = CONTEXT_WS_CLIENT; /* ws/wss client context */
17336 newctx->cfg_worker_threads = 1; /* one worker thread will be created */
17337 newctx->worker_threadids =
17338 (pthread_t *)mg_calloc_ctx(newctx->cfg_worker_threads,
17339 sizeof(pthread_t),
17340 newctx);
17341
17342 conn->phys_ctx = newctx;
17343 conn->dom_ctx = &(newctx->dd);
17344
17345 thread_data = (struct websocket_client_thread_data *)
17346 mg_calloc_ctx(sizeof(struct websocket_client_thread_data), 1, newctx);
17347 if (!thread_data) {
17348 DEBUG_TRACE("%s\r\n", "Out of memory");
17349 mg_free(newctx);
17350 mg_free(conn);
17351 return NULL;
17352 }
17353
17354 thread_data->conn = conn;
17355 thread_data->data_handler = data_func;
17356 thread_data->close_handler = close_func;
17357 thread_data->callback_data = user_data;
17358
17359 /* Start a thread to read the websocket client connection
17360 * This thread will automatically stop when mg_disconnect is
17361 * called on the client connection */
17362 if (mg_start_thread_with_id(websocket_client_thread,
17363 (void *)thread_data,
17364 newctx->worker_threadids)
17365 != 0) {
17366 mg_free((void *)thread_data);
17367 mg_free((void *)newctx->worker_threadids);
17368 mg_free((void *)newctx);
17369 mg_free((void *)conn);
17370 conn = NULL;
17371 DEBUG_TRACE("%s",
17372 "Websocket client connect thread could not be started\r\n");
17373 }
17374
17375#else
17376 /* Appease "unused parameter" warnings */
17377 (void)host;
17378 (void)port;
17379 (void)use_ssl;
17380 (void)error_buffer;
17381 (void)error_buffer_size;
17382 (void)path;
17383 (void)origin;
17384 (void)user_data;
17385 (void)data_func;
17386 (void)close_func;
17387#endif
17388
17389 return conn;
17390}
17391
17392
17393/* Prepare connection data structure */
17394static void
17396{
17397 /* Is keep alive allowed by the server */
17398 int keep_alive_enabled =
17400
17401 if (!keep_alive_enabled) {
17402 conn->must_close = 1;
17403 }
17404
17405 /* Important: on new connection, reset the receiving buffer. Credit
17406 * goes to crule42. */
17407 conn->data_len = 0;
17410
17411#if defined(USE_SERVER_STATS)
17412 conn->conn_state = 2; /* init */
17413#endif
17414
17415 /* call the init_connection callback if assigned */
17416 if (conn->phys_ctx->callbacks.init_connection != NULL) {
17418 void *conn_data = NULL;
17421 }
17422 }
17423}
17424
17425
17426/* Process a connection - may handle multiple requests
17427 * using the same connection.
17428 * Must be called with a valid connection (conn and
17429 * conn->phys_ctx must be valid).
17430 */
17431static void
17433{
17434 struct mg_request_info *ri = &conn->request_info;
17435 int keep_alive, discard_len;
17436 char ebuf[100];
17437 const char *hostend;
17438 int reqerr, uri_type;
17439
17440#if defined(USE_SERVER_STATS)
17441 int mcon = mg_atomic_inc(&(conn->phys_ctx->active_connections));
17442 mg_atomic_add(&(conn->phys_ctx->total_connections), 1);
17443 if (mcon > (conn->phys_ctx->max_connections)) {
17444 /* could use atomic compare exchange, but this
17445 * seems overkill for statistics data */
17446 conn->phys_ctx->max_connections = mcon;
17447 }
17448#endif
17449
17450 init_connection(conn);
17451
17452 DEBUG_TRACE("Start processing connection from %s",
17454
17455 /* Loop over multiple requests sent using the same connection
17456 * (while "keep alive"). */
17457 do {
17458
17459 DEBUG_TRACE("calling get_request (%i times for this connection)",
17460 conn->handled_requests + 1);
17461
17462#if defined(USE_SERVER_STATS)
17463 conn->conn_state = 3; /* ready */
17464#endif
17465
17466 if (!get_request(conn, ebuf, sizeof(ebuf), &reqerr)) {
17467 /* The request sent by the client could not be understood by
17468 * the server, or it was incomplete or a timeout. Send an
17469 * error message and close the connection. */
17470 if (reqerr > 0) {
17471 DEBUG_ASSERT(ebuf[0] != '\0');
17472 mg_send_http_error(conn, reqerr, "%s", ebuf);
17473 }
17474 } else if (strcmp(ri->http_version, "1.0")
17475 && strcmp(ri->http_version, "1.1")) {
17476 mg_snprintf(conn,
17477 NULL, /* No truncation check for ebuf */
17478 ebuf,
17479 sizeof(ebuf),
17480 "Bad HTTP version: [%s]",
17481 ri->http_version);
17482 mg_send_http_error(conn, 505, "%s", ebuf);
17483 }
17484
17485 if (ebuf[0] == '\0') {
17486 uri_type = get_uri_type(conn->request_info.request_uri);
17487 switch (uri_type) {
17488 case 1:
17489 /* Asterisk */
17490 conn->request_info.local_uri = NULL;
17491 break;
17492 case 2:
17493 /* relative uri */
17495 break;
17496 case 3:
17497 case 4:
17498 /* absolute uri (with/without port) */
17500 conn->request_info.request_uri, conn);
17501 if (hostend) {
17502 conn->request_info.local_uri = hostend;
17503 } else {
17504 conn->request_info.local_uri = NULL;
17505 }
17506 break;
17507 default:
17508 mg_snprintf(conn,
17509 NULL, /* No truncation check for ebuf */
17510 ebuf,
17511 sizeof(ebuf),
17512 "Invalid URI");
17513 mg_send_http_error(conn, 400, "%s", ebuf);
17514 conn->request_info.local_uri = NULL;
17515 break;
17516 }
17517
17518#if defined(MG_LEGACY_INTERFACE)
17519 /* Legacy before split into local_uri and request_uri */
17520 conn->request_info.uri = conn->request_info.local_uri;
17521#endif
17522 }
17523
17524 DEBUG_TRACE("http: %s, error: %s",
17525 (ri->http_version ? ri->http_version : "none"),
17526 (ebuf[0] ? ebuf : "none"));
17527
17528 if (ebuf[0] == '\0') {
17529 if (conn->request_info.local_uri) {
17530
17531/* handle request to local server */
17532#if defined(USE_SERVER_STATS)
17533 conn->conn_state = 4; /* processing */
17534#endif
17535 handle_request(conn);
17536
17537#if defined(USE_SERVER_STATS)
17538 conn->conn_state = 5; /* processed */
17539
17540 mg_atomic_add(&(conn->phys_ctx->total_data_read),
17541 conn->consumed_content);
17542 mg_atomic_add(&(conn->phys_ctx->total_data_written),
17543 conn->num_bytes_sent);
17544#endif
17545
17546 DEBUG_TRACE("%s", "handle_request done");
17547
17548 if (conn->phys_ctx->callbacks.end_request != NULL) {
17549 conn->phys_ctx->callbacks.end_request(conn,
17550 conn->status_code);
17551 DEBUG_TRACE("%s", "end_request callback done");
17552 }
17553 log_access(conn);
17554 } else {
17555 /* TODO: handle non-local request (PROXY) */
17556 conn->must_close = 1;
17557 }
17558 } else {
17559 conn->must_close = 1;
17560 }
17561
17562 if (ri->remote_user != NULL) {
17563 mg_free((void *)ri->remote_user);
17564 /* Important! When having connections with and without auth
17565 * would cause double free and then crash */
17566 ri->remote_user = NULL;
17567 }
17568
17569 /* NOTE(lsm): order is important here. should_keep_alive() call
17570 * is using parsed request, which will be invalid after
17571 * memmove's below.
17572 * Therefore, memorize should_keep_alive() result now for later
17573 * use in loop exit condition. */
17574 keep_alive = (conn->phys_ctx->stop_flag == 0) && should_keep_alive(conn)
17575 && (conn->content_len >= 0);
17576
17577
17578 /* Discard all buffered data for this request */
17579 discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
17580 && ((conn->request_len + conn->content_len)
17581 < (int64_t)conn->data_len))
17582 ? (int)(conn->request_len + conn->content_len)
17583 : conn->data_len;
17584 DEBUG_ASSERT(discard_len >= 0);
17585 if (discard_len < 0) {
17586 DEBUG_TRACE("internal error: discard_len = %li",
17587 (long int)discard_len);
17588 break;
17589 }
17590 conn->data_len -= discard_len;
17591 if (conn->data_len > 0) {
17592 DEBUG_TRACE("discard_len = %lu", (long unsigned)discard_len);
17593 memmove(conn->buf, conn->buf + discard_len, (size_t)conn->data_len);
17594 }
17595
17596 DEBUG_ASSERT(conn->data_len >= 0);
17597 DEBUG_ASSERT(conn->data_len <= conn->buf_size);
17598
17599 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
17600 DEBUG_TRACE("internal error: data_len = %li, buf_size = %li",
17601 (long int)conn->data_len,
17602 (long int)conn->buf_size);
17603 break;
17604 }
17605
17606 conn->handled_requests++;
17607
17608 } while (keep_alive);
17609
17610 DEBUG_TRACE("Done processing connection from %s (%f sec)",
17612 difftime(time(NULL), conn->conn_birth_time));
17613
17614 close_connection(conn);
17615
17616#if defined(USE_SERVER_STATS)
17617 mg_atomic_add(&(conn->phys_ctx->total_requests), conn->handled_requests);
17618 mg_atomic_dec(&(conn->phys_ctx->active_connections));
17619#endif
17620}
17621
17622
17623#if defined(ALTERNATIVE_QUEUE)
17624
17625static void
17626produce_socket(struct mg_context *ctx, const struct socket *sp)
17627{
17628 unsigned int i;
17629
17630 while (!ctx->stop_flag) {
17631 for (i = 0; i < ctx->cfg_worker_threads; i++) {
17632 /* find a free worker slot and signal it */
17633 if (ctx->client_socks[i].in_use == 0) {
17634 ctx->client_socks[i] = *sp;
17635 ctx->client_socks[i].in_use = 1;
17637 return;
17638 }
17639 }
17640 /* queue is full */
17641 mg_sleep(1);
17642 }
17643}
17644
17645
17646static int
17647consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
17648{
17649 DEBUG_TRACE("%s", "going idle");
17650 ctx->client_socks[thread_index].in_use = 0;
17651 event_wait(ctx->client_wait_events[thread_index]);
17652 *sp = ctx->client_socks[thread_index];
17653 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
17654
17655 return !ctx->stop_flag;
17656}
17657
17658#else /* ALTERNATIVE_QUEUE */
17659
17660/* Worker threads take accepted socket from the queue */
17661static int
17662consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
17663{
17664#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17665
17666 (void)thread_index;
17667
17668 (void)pthread_mutex_lock(&ctx->thread_mutex);
17669 DEBUG_TRACE("%s", "going idle");
17670
17671 /* If the queue is empty, wait. We're idle at this point. */
17672 while ((ctx->sq_head == ctx->sq_tail) && (ctx->stop_flag == 0)) {
17673 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
17674 }
17675
17676 /* If we're stopping, sq_head may be equal to sq_tail. */
17677 if (ctx->sq_head > ctx->sq_tail) {
17678 /* Copy socket from the queue and increment tail */
17679 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
17680 ctx->sq_tail++;
17681
17682 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
17683
17684 /* Wrap pointers if needed */
17685 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
17686 ctx->sq_tail -= QUEUE_SIZE(ctx);
17687 ctx->sq_head -= QUEUE_SIZE(ctx);
17688 }
17689 }
17690
17691 (void)pthread_cond_signal(&ctx->sq_empty);
17692 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17693
17694 return !ctx->stop_flag;
17695#undef QUEUE_SIZE
17696}
17697
17698
17699/* Master thread adds accepted socket to a queue */
17700static void
17701produce_socket(struct mg_context *ctx, const struct socket *sp)
17702{
17703#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17704 if (!ctx) {
17705 return;
17706 }
17707 (void)pthread_mutex_lock(&ctx->thread_mutex);
17708
17709 /* If the queue is full, wait */
17710 while ((ctx->stop_flag == 0)
17711 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
17712 (void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
17713 }
17714
17715 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
17716 /* Copy socket to the queue and increment head */
17717 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
17718 ctx->sq_head++;
17719 DEBUG_TRACE("queued socket %d", sp ? sp->sock : -1);
17720 }
17721
17722 (void)pthread_cond_signal(&ctx->sq_full);
17723 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17724#undef QUEUE_SIZE
17725}
17726#endif /* ALTERNATIVE_QUEUE */
17727
17728
17732};
17733
17734
17735static void *
17737{
17738 struct mg_context *ctx = thread_args->ctx;
17739 struct mg_connection *conn;
17740 struct mg_workerTLS tls;
17741#if defined(MG_LEGACY_INTERFACE)
17742 uint32_t addr;
17743#endif
17744
17745 mg_set_thread_name("worker");
17746
17747 tls.is_master = 0;
17748 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
17749#if defined(_WIN32)
17750 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
17751#endif
17752
17753 /* Initialize thread local storage before calling any callback */
17754 pthread_setspecific(sTlsKey, &tls);
17755
17756 if (ctx->callbacks.init_thread) {
17757 /* call init_thread for a worker thread (type 1) */
17758 ctx->callbacks.init_thread(ctx, 1);
17759 }
17760
17761 /* Connection structure has been pre-allocated */
17762 if (((int)thread_args->index < 0)
17763 || ((unsigned)thread_args->index
17764 >= (unsigned)ctx->cfg_worker_threads)) {
17765 mg_cry_internal(fc(ctx),
17766 "Internal error: Invalid worker index %i",
17767 (int)thread_args->index);
17768 return NULL;
17769 }
17770 conn = ctx->worker_connections + thread_args->index;
17771
17772 /* Request buffers are not pre-allocated. They are private to the
17773 * request and do not contain any state information that might be
17774 * of interest to anyone observing a server status. */
17775 conn->buf = (char *)mg_malloc_ctx(ctx->max_request_size, conn->phys_ctx);
17776 if (conn->buf == NULL) {
17777 mg_cry_internal(fc(ctx),
17778 "Out of memory: Cannot allocate buffer for worker %i",
17779 (int)thread_args->index);
17780 return NULL;
17781 }
17782 conn->buf_size = (int)ctx->max_request_size;
17783
17784 conn->phys_ctx = ctx;
17785 conn->dom_ctx = &(ctx->dd); /* Use default domain and default host */
17786 conn->host = NULL; /* until we have more information. */
17787
17788 conn->thread_index = thread_args->index;
17789 conn->request_info.user_data = ctx->user_data;
17790 /* Allocate a mutex for this connection to allow communication both
17791 * within the request handler and from elsewhere in the application
17792 */
17793 if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
17794 mg_free(conn->buf);
17795 mg_cry_internal(fc(ctx), "%s", "Cannot create mutex");
17796 return NULL;
17797 }
17798
17799#if defined(USE_SERVER_STATS)
17800 conn->conn_state = 1; /* not consumed */
17801#endif
17802
17803#if defined(ALTERNATIVE_QUEUE)
17804 while ((ctx->stop_flag == 0)
17805 && consume_socket(ctx, &conn->client, conn->thread_index)) {
17806#else
17807 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
17808 * signal sq_empty condvar to wake up the master waiting in
17809 * produce_socket() */
17810 while (consume_socket(ctx, &conn->client, conn->thread_index)) {
17811#endif
17812
17813 conn->conn_birth_time = time(NULL);
17814
17815/* Fill in IP, port info early so even if SSL setup below fails,
17816 * error handler would have the corresponding info.
17817 * Thanks to Johannes Winkelmann for the patch.
17818 */
17819#if defined(USE_IPV6)
17820 if (conn->client.rsa.sa.sa_family == AF_INET6) {
17822 ntohs(conn->client.rsa.sin6.sin6_port);
17823 } else
17824#endif
17825 {
17827 ntohs(conn->client.rsa.sin.sin_port);
17828 }
17829
17831 sizeof(conn->request_info.remote_addr),
17832 &conn->client.rsa);
17833
17834 DEBUG_TRACE("Start processing connection from %s",
17836
17837 conn->request_info.is_ssl = conn->client.is_ssl;
17838
17839 if (conn->client.is_ssl) {
17840#if !defined(NO_SSL)
17841 /* HTTPS connection */
17842 if (sslize(conn,
17843 conn->dom_ctx->ssl_ctx,
17844 SSL_accept,
17845 &(conn->phys_ctx->stop_flag),
17846 NULL)) {
17847 /* conn->dom_ctx is set in get_request */
17848
17849 /* Get SSL client certificate information (if set) */
17851
17852 /* process HTTPS connection */
17854
17855 /* Free client certificate info */
17856 if (conn->request_info.client_cert) {
17857 mg_free((void *)(conn->request_info.client_cert->subject));
17858 mg_free((void *)(conn->request_info.client_cert->issuer));
17859 mg_free((void *)(conn->request_info.client_cert->serial));
17860 mg_free((void *)(conn->request_info.client_cert->finger));
17861 /* Free certificate memory */
17862 X509_free(
17865 conn->request_info.client_cert->subject = 0;
17866 conn->request_info.client_cert->issuer = 0;
17867 conn->request_info.client_cert->serial = 0;
17868 conn->request_info.client_cert->finger = 0;
17870 conn->request_info.client_cert = 0;
17871 }
17872 } else {
17873 /* make sure the connection is cleaned up on SSL failure */
17874 close_connection(conn);
17875 }
17876#endif
17877 } else {
17878 /* process HTTP connection */
17880 }
17881
17882 DEBUG_TRACE("%s", "Connection closed");
17883 }
17884
17885
17886 pthread_setspecific(sTlsKey, NULL);
17887#if defined(_WIN32)
17888 CloseHandle(tls.pthread_cond_helper_mutex);
17889#endif
17890 pthread_mutex_destroy(&conn->mutex);
17891
17892 /* Free the request buffer. */
17893 conn->buf_size = 0;
17894 mg_free(conn->buf);
17895 conn->buf = NULL;
17896
17897#if defined(USE_SERVER_STATS)
17898 conn->conn_state = 9; /* done */
17899#endif
17900
17901 DEBUG_TRACE("%s", "exiting");
17902 return NULL;
17903}
17904
17905
17906/* Threads have different return types on Windows and Unix. */
17907#if defined(_WIN32)
17908static unsigned __stdcall worker_thread(void *thread_func_param)
17909{
17910 struct worker_thread_args *pwta =
17911 (struct worker_thread_args *)thread_func_param;
17912 worker_thread_run(pwta);
17913 mg_free(thread_func_param);
17914 return 0;
17915}
17916#else
17917static void *
17918worker_thread(void *thread_func_param)
17919{
17920 struct worker_thread_args *pwta =
17921 (struct worker_thread_args *)thread_func_param;
17922 struct sigaction sa;
17923
17924 /* Ignore SIGPIPE */
17925 memset(&sa, 0, sizeof(sa));
17926 sa.sa_handler = SIG_IGN;
17927 sigaction(SIGPIPE, &sa, NULL);
17928
17929 worker_thread_run(pwta);
17930 mg_free(thread_func_param);
17931 return NULL;
17932}
17933#endif /* _WIN32 */
17934
17935
17936/* This is an internal function, thus all arguments are expected to be
17937 * valid - a NULL check is not required. */
17938static void
17939accept_new_connection(const struct socket *listener, struct mg_context *ctx)
17940{
17941 struct socket so;
17942 char src_addr[IP_ADDR_STR_LEN];
17943 socklen_t len = sizeof(so.rsa);
17944 int on = 1;
17945
17946 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
17947 == INVALID_SOCKET) {
17948 } else if (!check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
17949 sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
17950 mg_cry_internal(fc(ctx),
17951 "%s: %s is not allowed to connect",
17952 __func__,
17953 src_addr);
17954 closesocket(so.sock);
17955 } else {
17956 /* Put so socket structure into the queue */
17957 DEBUG_TRACE("Accepted socket %d", (int)so.sock);
17958 set_close_on_exec(so.sock, fc(ctx));
17959 so.is_ssl = listener->is_ssl;
17960 so.ssl_redir = listener->ssl_redir;
17961 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
17962 mg_cry_internal(fc(ctx),
17963 "%s: getsockname() failed: %s",
17964 __func__,
17965 strerror(ERRNO));
17966 }
17967
17968 /* Set TCP keep-alive. This is needed because if HTTP-level
17969 * keep-alive
17970 * is enabled, and client resets the connection, server won't get
17971 * TCP FIN or RST and will keep the connection open forever. With
17972 * TCP keep-alive, next keep-alive handshake will figure out that
17973 * the client is down and will close the server end.
17974 * Thanks to Igor Klopov who suggested the patch. */
17975 if (setsockopt(so.sock,
17976 SOL_SOCKET,
17977 SO_KEEPALIVE,
17978 (SOCK_OPT_TYPE)&on,
17979 sizeof(on))
17980 != 0) {
17982 fc(ctx),
17983 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
17984 __func__,
17985 strerror(ERRNO));
17986 }
17987
17988 /* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
17989 * to effectively fill up the underlying IP packet payload and
17990 * reduce the overhead of sending lots of small buffers. However
17991 * this hurts the server's throughput (ie. operations per second)
17992 * when HTTP 1.1 persistent connections are used and the responses
17993 * are relatively small (eg. less than 1400 bytes).
17994 */
17995 if ((ctx->dd.config[CONFIG_TCP_NODELAY] != NULL)
17996 && (!strcmp(ctx->dd.config[CONFIG_TCP_NODELAY], "1"))) {
17997 if (set_tcp_nodelay(so.sock, 1) != 0) {
17999 fc(ctx),
18000 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
18001 __func__,
18002 strerror(ERRNO));
18003 }
18004 }
18005
18006 /* We are using non-blocking sockets. Thus, the
18007 * set_sock_timeout(so.sock, timeout);
18008 * call is no longer required. */
18009
18010 /* The "non blocking" property should already be
18011 * inherited from the parent socket. Set it for
18012 * non-compliant socket implementations. */
18014
18015 so.in_use = 0;
18016 produce_socket(ctx, &so);
18017 }
18018}
18019
18020
18021static void
18022master_thread_run(void *thread_func_param)
18023{
18024 struct mg_context *ctx = (struct mg_context *)thread_func_param;
18025 struct mg_workerTLS tls;
18026 struct pollfd *pfd;
18027 unsigned int i;
18028 unsigned int workerthreadcount;
18029
18030 if (!ctx) {
18031 return;
18032 }
18033
18034 mg_set_thread_name("master");
18035
18036/* Increase priority of the master thread */
18037#if defined(_WIN32)
18038 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
18039#elif defined(USE_MASTER_THREAD_PRIORITY)
18040 int min_prio = sched_get_priority_min(SCHED_RR);
18041 int max_prio = sched_get_priority_max(SCHED_RR);
18042 if ((min_prio >= 0) && (max_prio >= 0)
18043 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
18044 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
18045 struct sched_param sched_param = {0};
18046 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
18047 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
18048 }
18049#endif
18050
18051/* Initialize thread local storage */
18052#if defined(_WIN32)
18053 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
18054#endif
18055 tls.is_master = 1;
18056 pthread_setspecific(sTlsKey, &tls);
18057
18058 if (ctx->callbacks.init_thread) {
18059 /* Callback for the master thread (type 0) */
18060 ctx->callbacks.init_thread(ctx, 0);
18061 }
18062
18063 /* Server starts *now* */
18064 ctx->start_time = time(NULL);
18065
18066 /* Start the server */
18067 pfd = ctx->listening_socket_fds;
18068 while (ctx->stop_flag == 0) {
18069 for (i = 0; i < ctx->num_listening_sockets; i++) {
18070 pfd[i].fd = ctx->listening_sockets[i].sock;
18071 pfd[i].events = POLLIN;
18072 }
18073
18074 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
18075 for (i = 0; i < ctx->num_listening_sockets; i++) {
18076 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
18077 * successful poll, and POLLIN is defined as
18078 * (POLLRDNORM | POLLRDBAND)
18079 * Therefore, we're checking pfd[i].revents & POLLIN, not
18080 * pfd[i].revents == POLLIN. */
18081 if ((ctx->stop_flag == 0) && (pfd[i].revents & POLLIN)) {
18083 }
18084 }
18085 }
18086 }
18087
18088 /* Here stop_flag is 1 - Initiate shutdown. */
18089 DEBUG_TRACE("%s", "stopping workers");
18090
18091 /* Stop signal received: somebody called mg_stop. Quit. */
18093
18094 /* Wakeup workers that are waiting for connections to handle. */
18095 (void)pthread_mutex_lock(&ctx->thread_mutex);
18096#if defined(ALTERNATIVE_QUEUE)
18097 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18099
18100 /* Since we know all sockets, we can shutdown the connections. */
18101 if (ctx->client_socks[i].in_use) {
18102 shutdown(ctx->client_socks[i].sock, SHUTDOWN_BOTH);
18103 }
18104 }
18105#else
18106 pthread_cond_broadcast(&ctx->sq_full);
18107#endif
18108 (void)pthread_mutex_unlock(&ctx->thread_mutex);
18109
18110 /* Join all worker threads to avoid leaking threads. */
18111 workerthreadcount = ctx->cfg_worker_threads;
18112 for (i = 0; i < workerthreadcount; i++) {
18113 if (ctx->worker_threadids[i] != 0) {
18115 }
18116 }
18117
18118#if defined(USE_LUA)
18119 /* Free Lua state of lua background task */
18120 if (ctx->lua_background_state) {
18121 lua_State *lstate = (lua_State *)ctx->lua_background_state;
18122 lua_getglobal(lstate, LUABACKGROUNDPARAMS);
18123 if (lua_istable(lstate, -1)) {
18124 reg_boolean(lstate, "shutdown", 1);
18125 lua_pop(lstate, 1);
18126 mg_sleep(2);
18127 }
18128 lua_close(lstate);
18129 ctx->lua_background_state = 0;
18130 }
18131#endif
18132
18133 DEBUG_TRACE("%s", "exiting");
18134
18135#if defined(_WIN32)
18136 CloseHandle(tls.pthread_cond_helper_mutex);
18137#endif
18138 pthread_setspecific(sTlsKey, NULL);
18139
18140 /* Signal mg_stop() that we're done.
18141 * WARNING: This must be the very last thing this
18142 * thread does, as ctx becomes invalid after this line. */
18143 ctx->stop_flag = 2;
18144}
18145
18146
18147/* Threads have different return types on Windows and Unix. */
18148#if defined(_WIN32)
18149static unsigned __stdcall master_thread(void *thread_func_param)
18150{
18151 master_thread_run(thread_func_param);
18152 return 0;
18153}
18154#else
18155static void *
18156master_thread(void *thread_func_param)
18157{
18158 struct sigaction sa;
18159
18160 /* Ignore SIGPIPE */
18161 memset(&sa, 0, sizeof(sa));
18162 sa.sa_handler = SIG_IGN;
18163 sigaction(SIGPIPE, &sa, NULL);
18164
18165 master_thread_run(thread_func_param);
18166 return NULL;
18167}
18168#endif /* _WIN32 */
18169
18170
18171static void
18173{
18174 int i;
18175 struct mg_handler_info *tmp_rh;
18176
18177 if (ctx == NULL) {
18178 return;
18179 }
18180
18181 if (ctx->callbacks.exit_context) {
18182 ctx->callbacks.exit_context(ctx);
18183 }
18184
18185 /* All threads exited, no sync is needed. Destroy thread mutex and
18186 * condvars
18187 */
18188 (void)pthread_mutex_destroy(&ctx->thread_mutex);
18189#if defined(ALTERNATIVE_QUEUE)
18190 mg_free(ctx->client_socks);
18191 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18193 }
18195#else
18196 (void)pthread_cond_destroy(&ctx->sq_empty);
18197 (void)pthread_cond_destroy(&ctx->sq_full);
18198#endif
18199
18200 /* Destroy other context global data structures mutex */
18201 (void)pthread_mutex_destroy(&ctx->nonce_mutex);
18202
18203#if defined(USE_TIMERS)
18204 timers_exit(ctx);
18205#endif
18206
18207 /* Deallocate config parameters */
18208 for (i = 0; i < NUM_OPTIONS; i++) {
18209 if (ctx->dd.config[i] != NULL) {
18210#if defined(_MSC_VER)
18211#pragma warning(suppress : 6001)
18212#endif
18213 mg_free(ctx->dd.config[i]);
18214 }
18215 }
18216
18217 /* Deallocate request handlers */
18218 while (ctx->dd.handlers) {
18219 tmp_rh = ctx->dd.handlers;
18220 ctx->dd.handlers = tmp_rh->next;
18221 if (tmp_rh->handler_type == REQUEST_HANDLER) {
18222 pthread_cond_destroy(&tmp_rh->refcount_cond);
18223 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
18224 }
18225 mg_free(tmp_rh->uri);
18226 mg_free(tmp_rh);
18227 }
18228
18229#if !defined(NO_SSL)
18230 /* Deallocate SSL context */
18231 if (ctx->dd.ssl_ctx != NULL) {
18232 void *ssl_ctx = (void *)ctx->dd.ssl_ctx;
18233 int callback_ret =
18234 (ctx->callbacks.external_ssl_ctx == NULL)
18235 ? 0
18236 : (ctx->callbacks.external_ssl_ctx(&ssl_ctx, ctx->user_data));
18237
18238 if (callback_ret == 0) {
18239 SSL_CTX_free(ctx->dd.ssl_ctx);
18240 }
18241 /* else: ignore error and ommit SSL_CTX_free in case
18242 * callback_ret is 1 */
18243 }
18244#endif /* !NO_SSL */
18245
18246 /* Deallocate worker thread ID array */
18247 if (ctx->worker_threadids != NULL) {
18249 }
18250
18251 /* Deallocate worker thread ID array */
18252 if (ctx->worker_connections != NULL) {
18254 }
18255
18256 /* deallocate system name string */
18257 mg_free(ctx->systemName);
18258
18259 /* Deallocate context itself */
18260 mg_free(ctx);
18261}
18262
18263
18264void
18266{
18267 pthread_t mt;
18268 if (!ctx) {
18269 return;
18270 }
18271
18272 /* We don't use a lock here. Calling mg_stop with the same ctx from
18273 * two threads is not allowed. */
18274 mt = ctx->masterthreadid;
18275 if (mt == 0) {
18276 return;
18277 }
18278
18279 ctx->masterthreadid = 0;
18280
18281 /* Set stop flag, so all threads know they have to exit. */
18282 ctx->stop_flag = 1;
18283
18284 /* Wait until everything has stopped. */
18285 while (ctx->stop_flag != 2) {
18286 (void)mg_sleep(10);
18287 }
18288
18289 mg_join_thread(mt);
18290 free_context(ctx);
18291
18292#if defined(_WIN32)
18293 (void)WSACleanup();
18294#endif /* _WIN32 */
18295}
18296
18297
18298static void
18299get_system_name(char **sysName)
18300{
18301#if defined(_WIN32)
18302#if !defined(__SYMBIAN32__)
18303#if defined(_WIN32_WCE)
18304 *sysName = mg_strdup("WinCE");
18305#else
18306 char name[128];
18307 DWORD dwVersion = 0;
18308 DWORD dwMajorVersion = 0;
18309 DWORD dwMinorVersion = 0;
18310 DWORD dwBuild = 0;
18311 BOOL wowRet, isWoW = FALSE;
18312
18313#if defined(_MSC_VER)
18314#pragma warning(push)
18315/* GetVersion was declared deprecated */
18316#pragma warning(disable : 4996)
18317#endif
18318 dwVersion = GetVersion();
18319#if defined(_MSC_VER)
18320#pragma warning(pop)
18321#endif
18322
18323 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18324 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18325 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
18326 (void)dwBuild;
18327
18328 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
18329
18330 sprintf(name,
18331 "Windows %u.%u%s",
18332 (unsigned)dwMajorVersion,
18333 (unsigned)dwMinorVersion,
18334 (wowRet ? (isWoW ? " (WoW64)" : "") : " (?)"));
18335
18336 *sysName = mg_strdup(name);
18337#endif
18338#else
18339 *sysName = mg_strdup("Symbian");
18340#endif
18341#else
18342 struct utsname name;
18343 memset(&name, 0, sizeof(name));
18344 uname(&name);
18345 *sysName = mg_strdup(name.sysname);
18346#endif
18347}
18348
18349
18350struct mg_context *
18352 void *user_data,
18353 const char **options)
18354{
18355 struct mg_context *ctx;
18356 const char *name, *value, *default_value;
18357 int idx, ok, workerthreadcount;
18358 unsigned int i;
18359 int itmp;
18360 void (*exit_callback)(const struct mg_context *ctx) = 0;
18361
18362 struct mg_workerTLS tls;
18363
18364#if defined(_WIN32)
18365 WSADATA data;
18366 WSAStartup(MAKEWORD(2, 2), &data);
18367#endif /* _WIN32 */
18368
18369 /* Allocate context and initialize reasonable general case defaults. */
18370 if ((ctx = (struct mg_context *)mg_calloc(1, sizeof(*ctx))) == NULL) {
18371 return NULL;
18372 }
18373
18374 /* Random number generator will initialize at the first call */
18375 ctx->dd.auth_nonce_mask =
18376 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
18377
18378 if (mg_init_library_called == 0) {
18379 /* Legacy INIT, if mg_start is called without mg_init_library.
18380 * Note: This may cause a memory leak */
18381 const char *ports_option =
18383
18384 if (options) {
18385 const char **run_options = options;
18386 const char *optname = config_options[LISTENING_PORTS].name;
18387
18388 /* Try to find the "listening_ports" option */
18389 while (*run_options) {
18390 if (!strcmp(*run_options, optname)) {
18391 ports_option = run_options[1];
18392 }
18393 run_options += 2;
18394 }
18395 }
18396
18397 if (is_ssl_port_used(ports_option)) {
18398 /* Initialize with SSL support */
18400 } else {
18401 /* Initialize without SSL support */
18403 }
18404 }
18405
18406 tls.is_master = -1;
18407 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
18408#if defined(_WIN32)
18409 tls.pthread_cond_helper_mutex = NULL;
18410#endif
18411 pthread_setspecific(sTlsKey, &tls);
18412
18413 ok = (0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr));
18414#if !defined(ALTERNATIVE_QUEUE)
18415 ok &= (0 == pthread_cond_init(&ctx->sq_empty, NULL));
18416 ok &= (0 == pthread_cond_init(&ctx->sq_full, NULL));
18417#endif
18418 ok &= (0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr));
18419 if (!ok) {
18420 /* Fatal error - abort start. However, this situation should never
18421 * occur in practice. */
18422 mg_cry_internal(fc(ctx),
18423 "%s",
18424 "Cannot initialize thread synchronization objects");
18425 mg_free(ctx);
18426 pthread_setspecific(sTlsKey, NULL);
18427 return NULL;
18428 }
18429
18430 if (callbacks) {
18431 ctx->callbacks = *callbacks;
18432 exit_callback = callbacks->exit_context;
18433 ctx->callbacks.exit_context = 0;
18434 }
18435 ctx->user_data = user_data;
18436 ctx->dd.handlers = NULL;
18437 ctx->dd.next = NULL;
18438
18439#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18440 ctx->dd.shared_lua_websockets = NULL;
18441#endif
18442
18443 /* Store options */
18444 while (options && (name = *options++) != NULL) {
18445 if ((idx = get_option_index(name)) == -1) {
18446 mg_cry_internal(fc(ctx), "Invalid option: %s", name);
18447 free_context(ctx);
18448 pthread_setspecific(sTlsKey, NULL);
18449 return NULL;
18450 } else if ((value = *options++) == NULL) {
18451 mg_cry_internal(fc(ctx), "%s: option value cannot be NULL", name);
18452 free_context(ctx);
18453 pthread_setspecific(sTlsKey, NULL);
18454 return NULL;
18455 }
18456 if (ctx->dd.config[idx] != NULL) {
18457 mg_cry_internal(fc(ctx), "warning: %s: duplicate option", name);
18458 mg_free(ctx->dd.config[idx]);
18459 }
18460 ctx->dd.config[idx] = mg_strdup_ctx(value, ctx);
18461 DEBUG_TRACE("[%s] -> [%s]", name, value);
18462 }
18463
18464 /* Set default value if needed */
18465 for (i = 0; config_options[i].name != NULL; i++) {
18466 default_value = config_options[i].default_value;
18467 if ((ctx->dd.config[i] == NULL) && (default_value != NULL)) {
18468 ctx->dd.config[i] = mg_strdup_ctx(default_value, ctx);
18469 }
18470 }
18471
18472 /* Request size option */
18473 itmp = atoi(ctx->dd.config[MAX_REQUEST_SIZE]);
18474 if (itmp < 1024) {
18475 mg_cry_internal(fc(ctx), "%s", "max_request_size too small");
18476 free_context(ctx);
18477 pthread_setspecific(sTlsKey, NULL);
18478 return NULL;
18479 }
18480 ctx->max_request_size = (unsigned)itmp;
18481
18482 /* Worker thread count option */
18483 workerthreadcount = atoi(ctx->dd.config[NUM_THREADS]);
18484
18485 if (workerthreadcount > MAX_WORKER_THREADS) {
18486 mg_cry_internal(fc(ctx), "%s", "Too many worker threads");
18487 free_context(ctx);
18488 pthread_setspecific(sTlsKey, NULL);
18489 return NULL;
18490 }
18491
18492 if (workerthreadcount <= 0) {
18493 mg_cry_internal(fc(ctx), "%s", "Invalid number of worker threads");
18494 free_context(ctx);
18495 pthread_setspecific(sTlsKey, NULL);
18496 return NULL;
18497 }
18498
18499/* Document root */
18500#if defined(NO_FILES)
18501 if (ctx->dd.config[DOCUMENT_ROOT] != NULL) {
18502 mg_cry_internal(fc(ctx), "%s", "Document root must not be set");
18503 free_context(ctx);
18504 pthread_setspecific(sTlsKey, NULL);
18505 return NULL;
18506 }
18507#endif
18508
18510
18511#if defined(USE_LUA)
18512 /* If a Lua background script has been configured, start it. */
18513 if (ctx->dd.config[LUA_BACKGROUND_SCRIPT] != NULL) {
18514 char ebuf[256];
18515 struct vec opt_vec;
18516 struct vec eq_vec;
18517 const char *sparams;
18518 lua_State *state = mg_prepare_lua_context_script(
18519 ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
18520 if (!state) {
18521 mg_cry_internal(fc(ctx), "lua_background_script error: %s", ebuf);
18522 free_context(ctx);
18523 pthread_setspecific(sTlsKey, NULL);
18524 return NULL;
18525 }
18526 ctx->lua_background_state = (void *)state;
18527
18528 lua_newtable(state);
18529 reg_boolean(state, "shutdown", 0);
18530
18531 sparams = ctx->dd.config[LUA_BACKGROUND_SCRIPT_PARAMS];
18532
18533 while ((sparams = next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
18534 reg_llstring(
18535 state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
18536 if (mg_strncasecmp(sparams, opt_vec.ptr, opt_vec.len) == 0)
18537 break;
18538 }
18539 lua_setglobal(state, LUABACKGROUNDPARAMS);
18540
18541 } else {
18542 ctx->lua_background_state = 0;
18543 }
18544#endif
18545
18546 /* NOTE(lsm): order is important here. SSL certificates must
18547 * be initialized before listening ports. UID must be set last. */
18548 if (!set_gpass_option(ctx, NULL) ||
18549#if !defined(NO_SSL)
18550 !init_ssl_ctx(ctx, NULL) ||
18551#endif
18552 !set_ports_option(ctx) ||
18553#if !defined(_WIN32)
18554 !set_uid_option(ctx) ||
18555#endif
18556 !set_acl_option(ctx)) {
18557 free_context(ctx);
18558 pthread_setspecific(sTlsKey, NULL);
18559 return NULL;
18560 }
18561
18562 ctx->cfg_worker_threads = ((unsigned int)(workerthreadcount));
18563 ctx->worker_threadids = (pthread_t *)mg_calloc_ctx(ctx->cfg_worker_threads,
18564 sizeof(pthread_t),
18565 ctx);
18566
18567 if (ctx->worker_threadids == NULL) {
18568 mg_cry_internal(fc(ctx),
18569 "%s",
18570 "Not enough memory for worker thread ID array");
18571 free_context(ctx);
18572 pthread_setspecific(sTlsKey, NULL);
18573 return NULL;
18574 }
18575 ctx->worker_connections =
18577 sizeof(struct mg_connection),
18578 ctx);
18579 if (ctx->worker_connections == NULL) {
18580 mg_cry_internal(fc(ctx),
18581 "%s",
18582 "Not enough memory for worker thread connection array");
18583 free_context(ctx);
18584 pthread_setspecific(sTlsKey, NULL);
18585 return NULL;
18586 }
18587
18588
18589#if defined(ALTERNATIVE_QUEUE)
18590 ctx->client_wait_events =
18591 (void **)mg_calloc_ctx(sizeof(ctx->client_wait_events[0]),
18592 ctx->cfg_worker_threads,
18593 ctx);
18594 if (ctx->client_wait_events == NULL) {
18595 mg_cry_internal(fc(ctx),
18596 "%s",
18597 "Not enough memory for worker event array");
18599 free_context(ctx);
18600 pthread_setspecific(sTlsKey, NULL);
18601 return NULL;
18602 }
18603
18604 ctx->client_socks =
18605 (struct socket *)mg_calloc_ctx(sizeof(ctx->client_socks[0]),
18606 ctx->cfg_worker_threads,
18607 ctx);
18608 if (ctx->client_socks == NULL) {
18609 mg_cry_internal(fc(ctx),
18610 "%s",
18611 "Not enough memory for worker socket array");
18614 free_context(ctx);
18615 pthread_setspecific(sTlsKey, NULL);
18616 return NULL;
18617 }
18618
18619 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18620 ctx->client_wait_events[i] = event_create();
18621 if (ctx->client_wait_events[i] == 0) {
18622 mg_cry_internal(fc(ctx), "Error creating worker event %i", i);
18623 while (i > 0) {
18624 i--;
18626 }
18627 mg_free(ctx->client_socks);
18630 free_context(ctx);
18631 pthread_setspecific(sTlsKey, NULL);
18632 return NULL;
18633 }
18634 }
18635#endif
18636
18637
18638#if defined(USE_TIMERS)
18639 if (timers_init(ctx) != 0) {
18640 mg_cry_internal(fc(ctx), "%s", "Error creating timers");
18641 free_context(ctx);
18642 pthread_setspecific(sTlsKey, NULL);
18643 return NULL;
18644 }
18645#endif
18646
18647 /* Context has been created - init user libraries */
18648 if (ctx->callbacks.init_context) {
18649 ctx->callbacks.init_context(ctx);
18650 }
18651 ctx->callbacks.exit_context = exit_callback;
18652 ctx->context_type = CONTEXT_SERVER; /* server context */
18653
18654 /* Start master (listening) thread */
18656
18657 /* Start worker threads */
18658 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18659 struct worker_thread_args *wta = (struct worker_thread_args *)
18660 mg_malloc_ctx(sizeof(struct worker_thread_args), ctx);
18661 if (wta) {
18662 wta->ctx = ctx;
18663 wta->index = (int)i;
18664 }
18665
18666 if ((wta == NULL)
18668 wta,
18669 &ctx->worker_threadids[i])
18670 != 0)) {
18671
18672 /* thread was not created */
18673 if (wta != NULL) {
18674 mg_free(wta);
18675 }
18676
18677 if (i > 0) {
18679 "Cannot start worker thread %i: error %ld",
18680 i + 1,
18681 (long)ERRNO);
18682 } else {
18684 "Cannot create threads: error %ld",
18685 (long)ERRNO);
18687 pthread_setspecific(sTlsKey, NULL);
18688 return NULL;
18689 }
18690 break;
18691 }
18692 }
18693
18694 pthread_setspecific(sTlsKey, NULL);
18695 return ctx;
18696}
18697
18698
18699#if defined(MG_EXPERIMENTAL_INTERFACES)
18700/* Add an additional domain to an already running web server. */
18701int
18702mg_start_domain(struct mg_context *ctx, const char **options)
18703{
18704 const char *name;
18705 const char *value;
18706 const char *default_value;
18707 struct mg_domain_context *new_dom;
18708 struct mg_domain_context *dom;
18709 int idx, i;
18710
18711 if ((ctx == NULL) || (ctx->stop_flag != 0) || (options == NULL)) {
18712 return -1;
18713 }
18714
18715 new_dom = (struct mg_domain_context *)
18716 mg_calloc_ctx(1, sizeof(struct mg_domain_context), ctx);
18717
18718 if (!new_dom) {
18719 /* Out of memory */
18720 return -6;
18721 }
18722
18723 /* Store options - TODO: unite duplicate code */
18724 while (options && (name = *options++) != NULL) {
18725 if ((idx = get_option_index(name)) == -1) {
18726 mg_cry_internal(fc(ctx), "Invalid option: %s", name);
18727 mg_free(new_dom);
18728 return -2;
18729 } else if ((value = *options++) == NULL) {
18730 mg_cry_internal(fc(ctx), "%s: option value cannot be NULL", name);
18731 mg_free(new_dom);
18732 return -2;
18733 }
18734 if (new_dom->config[idx] != NULL) {
18735 mg_cry_internal(fc(ctx), "warning: %s: duplicate option", name);
18736 mg_free(new_dom->config[idx]);
18737 }
18738 new_dom->config[idx] = mg_strdup_ctx(value, ctx);
18739 DEBUG_TRACE("[%s] -> [%s]", name, value);
18740 }
18741
18742 /* Authentication domain is mandatory */
18743 /* TODO: Maybe use a new option hostname? */
18744 if (!new_dom->config[AUTHENTICATION_DOMAIN]) {
18745 mg_cry_internal(fc(ctx), "%s", "authentication domain required");
18746 mg_free(new_dom);
18747 return -4;
18748 }
18749
18750 /* Set default value if needed. Take the config value from
18751 * ctx as a default value. */
18752 for (i = 0; config_options[i].name != NULL; i++) {
18753 default_value = ctx->dd.config[i];
18754 if ((new_dom->config[i] == NULL) && (default_value != NULL)) {
18755 new_dom->config[i] = mg_strdup_ctx(default_value, ctx);
18756 }
18757 }
18758
18759 new_dom->handlers = NULL;
18760 new_dom->next = NULL;
18761 new_dom->nonce_count = 0;
18762 new_dom->auth_nonce_mask =
18763 (uint64_t)get_random() ^ ((uint64_t)get_random() << 31);
18764
18765#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18766 new_dom->shared_lua_websockets = NULL;
18767#endif
18768
18769 if (!init_ssl_ctx(ctx, new_dom)) {
18770 /* Init SSL failed */
18771 mg_free(new_dom);
18772 return -3;
18773 }
18774
18775 /* Add element to linked list. */
18776 mg_lock_context(ctx);
18777
18778 idx = 0;
18779 dom = &(ctx->dd);
18780 for (;;) {
18781 if (!strcasecmp(new_dom->config[AUTHENTICATION_DOMAIN],
18783 /* Domain collision */
18784 mg_cry_internal(fc(ctx),
18785 "domain %s already in use",
18786 new_dom->config[AUTHENTICATION_DOMAIN]);
18787 mg_free(new_dom);
18788 return -5;
18789 }
18790
18791 /* Count number of domains */
18792 idx++;
18793
18794 if (dom->next == NULL) {
18795 dom->next = new_dom;
18796 break;
18797 }
18798 dom = dom->next;
18799 }
18800
18801 mg_unlock_context(ctx);
18802
18803 /* Return domain number */
18804 return idx;
18805}
18806#endif
18807
18808
18809/* Feature check API function */
18810unsigned
18811mg_check_feature(unsigned feature)
18812{
18813 static const unsigned feature_set = 0
18814/* Set bits for available features according to API documentation.
18815 * This bit mask is created at compile time, according to the active
18816 * preprocessor defines. It is a single const value at runtime. */
18817#if !defined(NO_FILES)
18819#endif
18820#if !defined(NO_SSL)
18822#endif
18823#if !defined(NO_CGI)
18825#endif
18826#if defined(USE_IPV6)
18828#endif
18829#if defined(USE_WEBSOCKET)
18831#endif
18832#if defined(USE_LUA)
18834#endif
18835#if defined(USE_DUKTAPE)
18837#endif
18838#if !defined(NO_CACHING)
18840#endif
18841#if defined(USE_SERVER_STATS)
18843#endif
18844#if defined(USE_ZLIB)
18846#endif
18847
18848/* Set some extra bits not defined in the API documentation.
18849 * These bits may change without further notice. */
18850#if defined(MG_LEGACY_INTERFACE)
18851 | 0x00008000u
18852#endif
18853#if defined(MG_EXPERIMENTAL_INTERFACES)
18854 | 0x00004000u
18855#endif
18856#if defined(MEMORY_DEBUGGING)
18857 | 0x00001000u
18858#endif
18859#if defined(USE_TIMERS)
18860 | 0x00020000u
18861#endif
18862#if !defined(NO_NONCE_CHECK)
18863 | 0x00040000u
18864#endif
18865#if !defined(NO_POPEN)
18866 | 0x00080000u
18867#endif
18868 ;
18869 return (feature & feature_set);
18870}
18871
18872
18873/* strcat with additional NULL check to avoid clang scan-build warning. */
18874#define strcat0(a, b) \
18875 { \
18876 if ((a != NULL) && (b != NULL)) { \
18877 strcat(a, b); \
18878 } \
18879 }
18880
18881
18882/* Get system information. It can be printed or stored by the caller.
18883 * Return the size of available information. */
18884static int
18885mg_get_system_info_impl(char *buffer, int buflen)
18886{
18887 char block[256];
18888 int system_info_length = 0;
18889
18890#if defined(_WIN32)
18891 const char *eol = "\r\n";
18892#else
18893 const char *eol = "\n";
18894#endif
18895
18896 const char *eoobj = "}";
18897 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
18898
18899 if ((buffer == NULL) || (buflen < 1)) {
18900 buflen = 0;
18901 } else {
18902 *buffer = 0;
18903 }
18904
18905 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
18906 system_info_length += (int)strlen(block);
18907 if (system_info_length < buflen) {
18908 strcat0(buffer, block);
18909 }
18910
18911 /* Server version */
18912 {
18913 const char *version = mg_version();
18914 mg_snprintf(NULL,
18915 NULL,
18916 block,
18917 sizeof(block),
18918 "\"version\" : \"%s\",%s",
18919 version,
18920 eol);
18921 system_info_length += (int)strlen(block);
18922 if (system_info_length < buflen) {
18923 strcat0(buffer, block);
18924 }
18925 }
18926
18927 /* System info */
18928 {
18929#if defined(_WIN32)
18930 DWORD dwVersion = 0;
18931 DWORD dwMajorVersion = 0;
18932 DWORD dwMinorVersion = 0;
18933 SYSTEM_INFO si;
18934
18935 GetSystemInfo(&si);
18936
18937#if defined(_MSC_VER)
18938#pragma warning(push)
18939/* GetVersion was declared deprecated */
18940#pragma warning(disable : 4996)
18941#endif
18942 dwVersion = GetVersion();
18943#if defined(_MSC_VER)
18944#pragma warning(pop)
18945#endif
18946
18947 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18948 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18949
18950 mg_snprintf(NULL,
18951 NULL,
18952 block,
18953 sizeof(block),
18954 "\"os\" : \"Windows %u.%u\",%s",
18955 (unsigned)dwMajorVersion,
18956 (unsigned)dwMinorVersion,
18957 eol);
18958 system_info_length += (int)strlen(block);
18959 if (system_info_length < buflen) {
18960 strcat0(buffer, block);
18961 }
18962
18963 mg_snprintf(NULL,
18964 NULL,
18965 block,
18966 sizeof(block),
18967 "\"cpu\" : \"type %u, cores %u, mask %x\",%s",
18968 (unsigned)si.wProcessorArchitecture,
18969 (unsigned)si.dwNumberOfProcessors,
18970 (unsigned)si.dwActiveProcessorMask,
18971 eol);
18972 system_info_length += (int)strlen(block);
18973 if (system_info_length < buflen) {
18974 strcat0(buffer, block);
18975 }
18976#else
18977 struct utsname name;
18978 memset(&name, 0, sizeof(name));
18979 uname(&name);
18980
18981 mg_snprintf(NULL,
18982 NULL,
18983 block,
18984 sizeof(block),
18985 "\"os\" : \"%s %s (%s) - %s\",%s",
18986 name.sysname,
18987 name.version,
18988 name.release,
18989 name.machine,
18990 eol);
18991 system_info_length += (int)strlen(block);
18992 if (system_info_length < buflen) {
18993 strcat0(buffer, block);
18994 }
18995#endif
18996 }
18997
18998 /* Features */
18999 {
19000 mg_snprintf(NULL,
19001 NULL,
19002 block,
19003 sizeof(block),
19004 "\"features\" : %lu,%s"
19005 "\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\",%s",
19006 (unsigned long)mg_check_feature(0xFFFFFFFFu),
19007 eol,
19008 mg_check_feature(MG_FEATURES_FILES) ? " Files" : "",
19009 mg_check_feature(MG_FEATURES_SSL) ? " HTTPS" : "",
19010 mg_check_feature(MG_FEATURES_CGI) ? " CGI" : "",
19011 mg_check_feature(MG_FEATURES_IPV6) ? " IPv6" : "",
19013 : "",
19014 mg_check_feature(MG_FEATURES_LUA) ? " Lua" : "",
19015 mg_check_feature(MG_FEATURES_SSJS) ? " JavaScript" : "",
19016 mg_check_feature(MG_FEATURES_CACHE) ? " Cache" : "",
19017 mg_check_feature(MG_FEATURES_STATS) ? " Stats" : "",
19018 eol);
19019 system_info_length += (int)strlen(block);
19020 if (system_info_length < buflen) {
19021 strcat0(buffer, block);
19022 }
19023
19024#if defined(USE_LUA)
19025 mg_snprintf(NULL,
19026 NULL,
19027 block,
19028 sizeof(block),
19029 "\"lua_version\" : \"%u (%s)\",%s",
19030 (unsigned)LUA_VERSION_NUM,
19031 LUA_RELEASE,
19032 eol);
19033 system_info_length += (int)strlen(block);
19034 if (system_info_length < buflen) {
19035 strcat0(buffer, block);
19036 }
19037#endif
19038#if defined(USE_DUKTAPE)
19039 mg_snprintf(NULL,
19040 NULL,
19041 block,
19042 sizeof(block),
19043 "\"javascript\" : \"Duktape %u.%u.%u\",%s",
19044 (unsigned)DUK_VERSION / 10000,
19045 ((unsigned)DUK_VERSION / 100) % 100,
19046 (unsigned)DUK_VERSION % 100,
19047 eol);
19048 system_info_length += (int)strlen(block);
19049 if (system_info_length < buflen) {
19050 strcat0(buffer, block);
19051 }
19052#endif
19053 }
19054
19055 /* Build date */
19056 {
19057#if defined(GCC_DIAGNOSTIC)
19058#if GCC_VERSION >= 50000
19059#pragma GCC diagnostic push
19060/* Disable bogus compiler warning -Wdate-time */
19061#pragma GCC diagnostic ignored "-Wdate-time"
19062#endif
19063#endif
19064 mg_snprintf(NULL,
19065 NULL,
19066 block,
19067 sizeof(block),
19068 "\"build\" : \"%s\",%s",
19069 __DATE__,
19070 eol);
19071
19072#if defined(GCC_DIAGNOSTIC)
19073#if GCC_VERSION >= 50000
19074#pragma GCC diagnostic pop
19075#endif
19076#endif
19077
19078 system_info_length += (int)strlen(block);
19079 if (system_info_length < buflen) {
19080 strcat0(buffer, block);
19081 }
19082 }
19083
19084
19085 /* Compiler information */
19086 /* http://sourceforge.net/p/predef/wiki/Compilers/ */
19087 {
19088#if defined(_MSC_VER)
19089 mg_snprintf(NULL,
19090 NULL,
19091 block,
19092 sizeof(block),
19093 "\"compiler\" : \"MSC: %u (%u)\",%s",
19094 (unsigned)_MSC_VER,
19095 (unsigned)_MSC_FULL_VER,
19096 eol);
19097 system_info_length += (int)strlen(block);
19098 if (system_info_length < buflen) {
19099 strcat0(buffer, block);
19100 }
19101#elif defined(__MINGW64__)
19102 mg_snprintf(NULL,
19103 NULL,
19104 block,
19105 sizeof(block),
19106 "\"compiler\" : \"MinGW64: %u.%u\",%s",
19107 (unsigned)__MINGW64_VERSION_MAJOR,
19108 (unsigned)__MINGW64_VERSION_MINOR,
19109 eol);
19110 system_info_length += (int)strlen(block);
19111 if (system_info_length < buflen) {
19112 strcat0(buffer, block);
19113 }
19114 mg_snprintf(NULL,
19115 NULL,
19116 block,
19117 sizeof(block),
19118 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19119 (unsigned)__MINGW32_MAJOR_VERSION,
19120 (unsigned)__MINGW32_MINOR_VERSION,
19121 eol);
19122 system_info_length += (int)strlen(block);
19123 if (system_info_length < buflen) {
19124 strcat0(buffer, block);
19125 }
19126#elif defined(__MINGW32__)
19127 mg_snprintf(NULL,
19128 NULL,
19129 block,
19130 sizeof(block),
19131 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19132 (unsigned)__MINGW32_MAJOR_VERSION,
19133 (unsigned)__MINGW32_MINOR_VERSION,
19134 eol);
19135 system_info_length += (int)strlen(block);
19136 if (system_info_length < buflen) {
19137 strcat0(buffer, block);
19138 }
19139#elif defined(__clang__)
19140 mg_snprintf(NULL,
19141 NULL,
19142 block,
19143 sizeof(block),
19144 "\"compiler\" : \"clang: %u.%u.%u (%s)\",%s",
19145 __clang_major__,
19146 __clang_minor__,
19147 __clang_patchlevel__,
19148 __clang_version__,
19149 eol);
19150 system_info_length += (int)strlen(block);
19151 if (system_info_length < buflen) {
19152 strcat0(buffer, block);
19153 }
19154#elif defined(__GNUC__)
19155 mg_snprintf(NULL,
19156 NULL,
19157 block,
19158 sizeof(block),
19159 "\"compiler\" : \"gcc: %u.%u.%u\",%s",
19160 (unsigned)__GNUC__,
19161 (unsigned)__GNUC_MINOR__,
19162 (unsigned)__GNUC_PATCHLEVEL__,
19163 eol);
19164 system_info_length += (int)strlen(block);
19165 if (system_info_length < buflen) {
19166 strcat0(buffer, block);
19167 }
19168#elif defined(__INTEL_COMPILER)
19169 mg_snprintf(NULL,
19170 NULL,
19171 block,
19172 sizeof(block),
19173 "\"compiler\" : \"Intel C/C++: %u\",%s",
19174 (unsigned)__INTEL_COMPILER,
19175 eol);
19176 system_info_length += (int)strlen(block);
19177 if (system_info_length < buflen) {
19178 strcat0(buffer, block);
19179 }
19180#elif defined(__BORLANDC__)
19181 mg_snprintf(NULL,
19182 NULL,
19183 block,
19184 sizeof(block),
19185 "\"compiler\" : \"Borland C: 0x%x\",%s",
19186 (unsigned)__BORLANDC__,
19187 eol);
19188 system_info_length += (int)strlen(block);
19189 if (system_info_length < buflen) {
19190 strcat0(buffer, block);
19191 }
19192#elif defined(__SUNPRO_C)
19193 mg_snprintf(NULL,
19194 NULL,
19195 block,
19196 sizeof(block),
19197 "\"compiler\" : \"Solaris: 0x%x\",%s",
19198 (unsigned)__SUNPRO_C,
19199 eol);
19200 system_info_length += (int)strlen(block);
19201 if (system_info_length < buflen) {
19202 strcat0(buffer, block);
19203 }
19204#else
19205 mg_snprintf(NULL,
19206 NULL,
19207 block,
19208 sizeof(block),
19209 "\"compiler\" : \"other\",%s",
19210 eol);
19211 system_info_length += (int)strlen(block);
19212 if (system_info_length < buflen) {
19213 strcat0(buffer, block);
19214 }
19215#endif
19216 }
19217
19218 /* Determine 32/64 bit data mode.
19219 * see https://en.wikipedia.org/wiki/64-bit_computing */
19220 {
19221 mg_snprintf(NULL,
19222 NULL,
19223 block,
19224 sizeof(block),
19225 "\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, "
19226 "char:%u/%u, "
19227 "ptr:%u, size:%u, time:%u\"%s",
19228 (unsigned)sizeof(short),
19229 (unsigned)sizeof(int),
19230 (unsigned)sizeof(long),
19231 (unsigned)sizeof(long long),
19232 (unsigned)sizeof(float),
19233 (unsigned)sizeof(double),
19234 (unsigned)sizeof(long double),
19235 (unsigned)sizeof(char),
19236 (unsigned)sizeof(wchar_t),
19237 (unsigned)sizeof(void *),
19238 (unsigned)sizeof(size_t),
19239 (unsigned)sizeof(time_t),
19240 eol);
19241 system_info_length += (int)strlen(block);
19242 if (system_info_length < buflen) {
19243 strcat0(buffer, block);
19244 }
19245 }
19246
19247 /* Terminate string */
19248 if ((buflen > 0) && buffer && buffer[0]) {
19249 if (system_info_length < buflen) {
19250 strcat0(buffer, eoobj);
19251 strcat0(buffer, eol);
19252 }
19253 }
19254 system_info_length += reserved_len;
19255
19256 return system_info_length;
19257}
19258
19259
19260#if defined(USE_SERVER_STATS)
19261/* Get context information. It can be printed or stored by the caller.
19262 * Return the size of available information. */
19263static int
19264mg_get_context_info_impl(const struct mg_context *ctx, char *buffer, int buflen)
19265
19266{
19267 char block[256];
19268 int context_info_length = 0;
19269
19270#if defined(_WIN32)
19271 const char *eol = "\r\n";
19272#else
19273 const char *eol = "\n";
19274#endif
19275 struct mg_memory_stat *ms = get_memory_stat((struct mg_context *)ctx);
19276
19277 const char *eoobj = "}";
19278 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
19279
19280 if ((buffer == NULL) || (buflen < 1)) {
19281 buflen = 0;
19282 } else {
19283 *buffer = 0;
19284 }
19285
19286 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
19287 context_info_length += (int)strlen(block);
19288 if (context_info_length < buflen) {
19289 strcat0(buffer, block);
19290 }
19291
19292 if (ms) { /* <-- should be always true */
19293 /* Memory information */
19294 mg_snprintf(NULL,
19295 NULL,
19296 block,
19297 sizeof(block),
19298 "\"memory\" : {%s"
19299 "\"blocks\" : %i,%s"
19300 "\"used\" : %" INT64_FMT ",%s"
19301 "\"maxUsed\" : %" INT64_FMT "%s"
19302 "}%s%s",
19303 eol,
19304 ms->blockCount,
19305 eol,
19306 ms->totalMemUsed,
19307 eol,
19308 ms->maxMemUsed,
19309 eol,
19310 (ctx ? "," : ""),
19311 eol);
19312
19313 context_info_length += (int)strlen(block);
19314 if (context_info_length + reserved_len < buflen) {
19315 strcat0(buffer, block);
19316 }
19317 }
19318
19319 if (ctx) {
19320 /* Declare all variables at begin of the block, to comply
19321 * with old C standards. */
19322 char start_time_str[64] = {0};
19323 char now_str[64] = {0};
19324 time_t start_time = ctx->start_time;
19325 time_t now = time(NULL);
19326
19327 /* Connections information */
19328 mg_snprintf(NULL,
19329 NULL,
19330 block,
19331 sizeof(block),
19332 "\"connections\" : {%s"
19333 "\"active\" : %i,%s"
19334 "\"maxActive\" : %i,%s"
19335 "\"total\" : %" INT64_FMT "%s"
19336 "},%s",
19337 eol,
19338 ctx->active_connections,
19339 eol,
19340 ctx->max_connections,
19341 eol,
19342 ctx->total_connections,
19343 eol,
19344 eol);
19345
19346 context_info_length += (int)strlen(block);
19347 if (context_info_length + reserved_len < buflen) {
19348 strcat0(buffer, block);
19349 }
19350
19351 /* Requests information */
19352 mg_snprintf(NULL,
19353 NULL,
19354 block,
19355 sizeof(block),
19356 "\"requests\" : {%s"
19357 "\"total\" : %" INT64_FMT "%s"
19358 "},%s",
19359 eol,
19360 ctx->total_requests,
19361 eol,
19362 eol);
19363
19364 context_info_length += (int)strlen(block);
19365 if (context_info_length + reserved_len < buflen) {
19366 strcat0(buffer, block);
19367 }
19368
19369 /* Data information */
19370 mg_snprintf(NULL,
19371 NULL,
19372 block,
19373 sizeof(block),
19374 "\"data\" : {%s"
19375 "\"read\" : %" INT64_FMT "%s,"
19376 "\"written\" : %" INT64_FMT "%s"
19377 "},%s",
19378 eol,
19379 ctx->total_data_read,
19380 eol,
19381 ctx->total_data_written,
19382 eol,
19383 eol);
19384
19385 context_info_length += (int)strlen(block);
19386 if (context_info_length + reserved_len < buflen) {
19387 strcat0(buffer, block);
19388 }
19389
19390 /* Execution time information */
19391 gmt_time_string(start_time_str,
19392 sizeof(start_time_str) - 1,
19393 &start_time);
19394 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
19395
19396 mg_snprintf(NULL,
19397 NULL,
19398 block,
19399 sizeof(block),
19400 "\"time\" : {%s"
19401 "\"uptime\" : %.0f,%s"
19402 "\"start\" : \"%s\",%s"
19403 "\"now\" : \"%s\"%s"
19404 "}%s",
19405 eol,
19406 difftime(now, start_time),
19407 eol,
19408 start_time_str,
19409 eol,
19410 now_str,
19411 eol,
19412 eol);
19413
19414 context_info_length += (int)strlen(block);
19415 if (context_info_length + reserved_len < buflen) {
19416 strcat0(buffer, block);
19417 }
19418 }
19419
19420 /* Terminate string */
19421 if ((buflen > 0) && buffer && buffer[0]) {
19422 if (context_info_length < buflen) {
19423 strcat0(buffer, eoobj);
19424 strcat0(buffer, eol);
19425 }
19426 }
19427 context_info_length += reserved_len;
19428
19429 return context_info_length;
19430}
19431#endif
19432
19433
19434#if defined(MG_EXPERIMENTAL_INTERFACES)
19435/* Get connection information. It can be printed or stored by the caller.
19436 * Return the size of available information. */
19437static int
19438mg_get_connection_info_impl(const struct mg_context *ctx,
19439 int idx,
19440 char *buffer,
19441 int buflen)
19442{
19443 const struct mg_connection *conn;
19444 const struct mg_request_info *ri;
19445 char block[256];
19446 int connection_info_length = 0;
19447 int state = 0;
19448 const char *state_str = "unknown";
19449
19450#if defined(_WIN32)
19451 const char *eol = "\r\n";
19452#else
19453 const char *eol = "\n";
19454#endif
19455
19456 const char *eoobj = "}";
19457 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
19458
19459 if ((buffer == NULL) || (buflen < 1)) {
19460 buflen = 0;
19461 } else {
19462 *buffer = 0;
19463 }
19464
19465 if ((ctx == NULL) || (idx < 0)) {
19466 /* Parameter error */
19467 return 0;
19468 }
19469
19470 if ((unsigned)idx >= ctx->cfg_worker_threads) {
19471 /* Out of range */
19472 return 0;
19473 }
19474
19475 /* Take connection [idx]. This connection is not locked in
19476 * any way, so some other thread might use it. */
19477 conn = (ctx->worker_connections) + idx;
19478
19479 /* Initialize output string */
19480 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
19481 connection_info_length += (int)strlen(block);
19482 if (connection_info_length < buflen) {
19483 strcat0(buffer, block);
19484 }
19485
19486 /* Init variables */
19487 ri = &(conn->request_info);
19488
19489#if defined(USE_SERVER_STATS)
19490 state = conn->conn_state;
19491
19492 /* State as string */
19493 switch (state) {
19494 case 0:
19495 state_str = "undefined";
19496 break;
19497 case 1:
19498 state_str = "not used";
19499 break;
19500 case 2:
19501 state_str = "init";
19502 break;
19503 case 3:
19504 state_str = "ready";
19505 break;
19506 case 4:
19507 state_str = "processing";
19508 break;
19509 case 5:
19510 state_str = "processed";
19511 break;
19512 case 6:
19513 state_str = "to close";
19514 break;
19515 case 7:
19516 state_str = "closing";
19517 break;
19518 case 8:
19519 state_str = "closed";
19520 break;
19521 case 9:
19522 state_str = "done";
19523 break;
19524 }
19525#endif
19526
19527 /* Connection info */
19528 if ((state >= 3) && (state < 9)) {
19529 mg_snprintf(NULL,
19530 NULL,
19531 block,
19532 sizeof(block),
19533 "\"connection\" : {%s"
19534 "\"remote\" : {%s"
19535 "\"protocol\" : \"%s\",%s"
19536 "\"addr\" : \"%s\",%s"
19537 "\"port\" : %u%s"
19538 "},%s"
19539 "\"handled_requests\" : %u%s"
19540 "},%s",
19541 eol,
19542 eol,
19543 get_proto_name(conn),
19544 eol,
19545 ri->remote_addr,
19546 eol,
19547 ri->remote_port,
19548 eol,
19549 eol,
19550 conn->handled_requests,
19551 eol,
19552 eol);
19553
19554 connection_info_length += (int)strlen(block);
19555 if (connection_info_length + reserved_len < buflen) {
19556 strcat0(buffer, block);
19557 }
19558 }
19559
19560 /* Request info */
19561 if ((state >= 4) && (state < 6)) {
19562 mg_snprintf(NULL,
19563 NULL,
19564 block,
19565 sizeof(block),
19566 "\"request_info\" : {%s"
19567 "\"method\" : \"%s\",%s"
19568 "\"uri\" : \"%s\",%s"
19569 "\"query\" : %s%s%s%s"
19570 "},%s",
19571 eol,
19572 ri->request_method,
19573 eol,
19574 ri->request_uri,
19575 eol,
19576 ri->query_string ? "\"" : "",
19577 ri->query_string ? ri->query_string : "null",
19578 ri->query_string ? "\"" : "",
19579 eol,
19580 eol);
19581
19582 connection_info_length += (int)strlen(block);
19583 if (connection_info_length + reserved_len < buflen) {
19584 strcat0(buffer, block);
19585 }
19586 }
19587
19588 /* Execution time information */
19589 if ((state >= 2) && (state < 9)) {
19590 char start_time_str[64] = {0};
19591 char now_str[64] = {0};
19592 time_t start_time = conn->conn_birth_time;
19593 time_t now = time(NULL);
19594
19595 gmt_time_string(start_time_str,
19596 sizeof(start_time_str) - 1,
19597 &start_time);
19598 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
19599
19600 mg_snprintf(NULL,
19601 NULL,
19602 block,
19603 sizeof(block),
19604 "\"time\" : {%s"
19605 "\"uptime\" : %.0f,%s"
19606 "\"start\" : \"%s\",%s"
19607 "\"now\" : \"%s\"%s"
19608 "},%s",
19609 eol,
19610 difftime(now, start_time),
19611 eol,
19612 start_time_str,
19613 eol,
19614 now_str,
19615 eol,
19616 eol);
19617
19618 connection_info_length += (int)strlen(block);
19619 if (connection_info_length + reserved_len < buflen) {
19620 strcat0(buffer, block);
19621 }
19622 }
19623
19624 /* Remote user name */
19625 if ((ri->remote_user) && (state < 9)) {
19626 mg_snprintf(NULL,
19627 NULL,
19628 block,
19629 sizeof(block),
19630 "\"user\" : {%s"
19631 "\"name\" : \"%s\",%s"
19632 "},%s",
19633 eol,
19634 ri->remote_user,
19635 eol,
19636 eol);
19637
19638 connection_info_length += (int)strlen(block);
19639 if (connection_info_length + reserved_len < buflen) {
19640 strcat0(buffer, block);
19641 }
19642 }
19643
19644 /* Data block */
19645 if (state >= 3) {
19646 mg_snprintf(NULL,
19647 NULL,
19648 block,
19649 sizeof(block),
19650 "\"data\" : {%s"
19651 "\"read\" : %" INT64_FMT ",%s"
19652 "\"written\" : %" INT64_FMT "%s"
19653 "},%s",
19654 eol,
19655 conn->consumed_content,
19656 eol,
19657 conn->num_bytes_sent,
19658 eol,
19659 eol);
19660
19661 connection_info_length += (int)strlen(block);
19662 if (connection_info_length + reserved_len < buflen) {
19663 strcat0(buffer, block);
19664 }
19665 }
19666
19667 /* State */
19668 mg_snprintf(NULL,
19669 NULL,
19670 block,
19671 sizeof(block),
19672 "\"state\" : \"%s\"%s",
19673 state_str,
19674 eol);
19675
19676 connection_info_length += (int)strlen(block);
19677 if (connection_info_length + reserved_len < buflen) {
19678 strcat0(buffer, block);
19679 }
19680
19681 /* Terminate string */
19682 if ((buflen > 0) && buffer && buffer[0]) {
19683 if (connection_info_length < buflen) {
19684 strcat0(buffer, eoobj);
19685 strcat0(buffer, eol);
19686 }
19687 }
19688 connection_info_length += reserved_len;
19689
19690 return connection_info_length;
19691}
19692#endif
19693
19694
19695/* Get system information. It can be printed or stored by the caller.
19696 * Return the size of available information. */
19697int
19698mg_get_system_info(char *buffer, int buflen)
19699{
19700 if ((buffer == NULL) || (buflen < 1)) {
19701 return mg_get_system_info_impl(NULL, 0);
19702 } else {
19703 /* Reset buffer, so we can always use strcat. */
19704 buffer[0] = 0;
19705 return mg_get_system_info_impl(buffer, buflen);
19706 }
19707}
19708
19709
19710/* Get context information. It can be printed or stored by the caller.
19711 * Return the size of available information. */
19712int
19713mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
19714{
19715#if defined(USE_SERVER_STATS)
19716 if ((buffer == NULL) || (buflen < 1)) {
19717 return mg_get_context_info_impl(ctx, NULL, 0);
19718 } else {
19719 /* Reset buffer, so we can always use strcat. */
19720 buffer[0] = 0;
19721 return mg_get_context_info_impl(ctx, buffer, buflen);
19722 }
19723#else
19724 (void)ctx;
19725 if ((buffer != NULL) && (buflen > 0)) {
19726 buffer[0] = 0;
19727 }
19728 return 0;
19729#endif
19730}
19731
19732
19733#if defined(MG_EXPERIMENTAL_INTERFACES)
19734int
19735mg_get_connection_info(const struct mg_context *ctx,
19736 int idx,
19737 char *buffer,
19738 int buflen)
19739{
19740 if ((buffer == NULL) || (buflen < 1)) {
19741 return mg_get_connection_info_impl(ctx, idx, NULL, 0);
19742 } else {
19743 /* Reset buffer, so we can always use strcat. */
19744 buffer[0] = 0;
19745 return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
19746 }
19747}
19748#endif
19749
19750
19751/* Initialize this library. This function does not need to be thread safe.
19752 */
19753unsigned
19754mg_init_library(unsigned features)
19755{
19756#if !defined(NO_SSL)
19757 char ebuf[128];
19758#endif
19759
19760 unsigned features_to_init = mg_check_feature(features & 0xFFu);
19761 unsigned features_inited = features_to_init;
19762
19763 if (mg_init_library_called <= 0) {
19764 /* Not initialized yet */
19765 if (0 != pthread_mutex_init(&global_lock_mutex, NULL)) {
19766 return 0;
19767 }
19768 }
19769
19771
19772 if (mg_init_library_called <= 0) {
19773 if (0 != pthread_key_create(&sTlsKey, tls_dtor)) {
19774 /* Fatal error - abort start. However, this situation should
19775 * never occur in practice. */
19777 return 0;
19778 }
19779
19780#if defined(_WIN32)
19781 InitializeCriticalSection(&global_log_file_lock);
19782#endif
19783#if !defined(_WIN32)
19784 pthread_mutexattr_init(&pthread_mutex_attr);
19785 pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
19786#endif
19787
19788#if defined(USE_LUA)
19789 lua_init_optional_libraries();
19790#endif
19791 }
19792
19794
19795#if !defined(NO_SSL)
19796 if (features_to_init & MG_FEATURES_SSL) {
19797 if (!mg_ssl_initialized) {
19798 if (initialize_ssl(ebuf, sizeof(ebuf))) {
19800 } else {
19801 (void)ebuf;
19802 DEBUG_TRACE("Initializing SSL failed: %s", ebuf);
19803 features_inited &= ~((unsigned)(MG_FEATURES_SSL));
19804 }
19805 } else {
19806 /* ssl already initialized */
19807 }
19808 }
19809#endif
19810
19811 /* Start WinSock for Windows */
19813 if (mg_init_library_called <= 0) {
19814#if defined(_WIN32)
19815 WSADATA data;
19816 WSAStartup(MAKEWORD(2, 2), &data);
19817#endif /* _WIN32 */
19819 } else {
19821 }
19823
19824 return features_inited;
19825}
19826
19827
19828/* Un-initialize this library. */
19829unsigned
19831{
19832 if (mg_init_library_called <= 0) {
19833 return 0;
19834 }
19835
19837
19839 if (mg_init_library_called == 0) {
19840#if defined(_WIN32)
19841 (void)WSACleanup();
19842#endif /* _WIN32 */
19843#if !defined(NO_SSL)
19844 if (mg_ssl_initialized) {
19847 }
19848#endif
19849
19850#if defined(_WIN32)
19851 (void)DeleteCriticalSection(&global_log_file_lock);
19852#endif /* _WIN32 */
19853#if !defined(_WIN32)
19854 (void)pthread_mutexattr_destroy(&pthread_mutex_attr);
19855#endif
19856
19857 (void)pthread_key_delete(sTlsKey);
19858
19859#if defined(USE_LUA)
19860 lua_exit_optional_libraries();
19861#endif
19862
19864 (void)pthread_mutex_destroy(&global_lock_mutex);
19865 return 1;
19866 }
19867
19869 return 1;
19870}
19871
19872
19873/* End of civetweb.c */
double
long
uint8_t
typedef void(GLAPIENTRYP _GLUfuncptr)(void)
ROOT::R::TRInterface & r
Definition Object.C:4
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define s1(x)
Definition RSha256.hxx:91
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
static const double x2[5]
static const double x1[5]
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
static unsigned int total
char name[80]
Definition TGX11.cxx:110
#define INVALID_HANDLE_VALUE
Definition TMapFile.cxx:84
R__EXTERN C unsigned int sleep(unsigned int seconds)
static void process_new_connection(struct mg_connection *conn)
Definition civetweb.c:17432
static int set_tcp_nodelay(SOCKET sock, int nodelay_on)
Definition civetweb.c:16112
#define SSL_CTX_use_certificate_file
Definition civetweb.c:2013
#define OPENSSL_free(a)
Definition civetweb.c:2116
static int is_authorized_for_put(struct mg_connection *conn)
Definition civetweb.c:8559
static int consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
Definition civetweb.c:17647
static int parse_http_request(char *buf, int len, struct mg_request_info *ri)
Definition civetweb.c:10211
#define SSL_new
Definition civetweb.c:2007
void mg_send_mime_file2(struct mg_connection *conn, const char *path, const char *mime_type, const char *additional_headers)
Definition civetweb.c:9857
#define mg_readdir(x)
Definition civetweb.c:807
static pthread_key_t sTlsKey
Definition civetweb.c:1555
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
Definition civetweb.c:3538
#define SOMAXCONN
Definition civetweb.c:838
static void open_auth_file(struct mg_connection *conn, const char *path, struct mg_file *filep)
Definition civetweb.c:8034
char static_assert_replacement[1]
Definition civetweb.c:119
int mg_strncasecmp(const char *s1, const char *s2, size_t len)
Definition civetweb.c:3267
#define IP_ADDR_STR_LEN
Definition civetweb.c:1714
#define SSL_VERIFY_NONE
Definition civetweb.c:1780
#define SSL_CTX_check_private_key
Definition civetweb.c:2038
#define ENGINE_cleanup
Definition civetweb.c:2090
static int check_authorization(struct mg_connection *conn, const char *path)
Definition civetweb.c:8455
#define vsnprintf_impl
Definition civetweb.c:781
#define HEXTOI(x)
#define mg_malloc_ctx(a, c)
Definition civetweb.c:1494
@ CONTEXT_WS_CLIENT
Definition civetweb.c:2566
@ CONTEXT_INVALID
Definition civetweb.c:2563
@ CONTEXT_SERVER
Definition civetweb.c:2564
@ CONTEXT_HTTP_CLIENT
Definition civetweb.c:2565
static int mg_fgetc(struct mg_file *filep, int offset)
Definition civetweb.c:11685
struct asn1_integer ASN1_INTEGER
Definition civetweb.c:1765
#define X509_NAME_oneline
Definition civetweb.c:2097
static char mg_getc(struct mg_connection *conn)
Definition civetweb.c:6641
static int mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
Definition civetweb.c:8699
void mg_unlock_connection(struct mg_connection *conn)
Definition civetweb.c:12022
static void mkcol(struct mg_connection *conn, const char *path)
Definition civetweb.c:11280
static void remove_bad_file(const struct mg_connection *conn, const char *path)
Definition civetweb.c:9940
static const struct @145 abs_uri_protocols[]
const struct mg_option * mg_get_valid_options(void)
Definition civetweb.c:3029
#define SSL_set_tlsext_host_name(ctx, arg)
Definition civetweb.c:2072
int mg_get_server_ports(const struct mg_context *ctx, int size, struct mg_server_ports *ports)
Definition civetweb.c:3493
const char * mime_type
Definition civetweb.c:7795
static int set_non_blocking_mode(SOCKET sock)
Definition civetweb.c:5997
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
Definition civetweb.c:15262
const char * proto
Definition civetweb.c:16613
int mg_send_http_error(struct mg_connection *conn, int status, const char *fmt,...)
Definition civetweb.c:4687
static const char * get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
Definition civetweb.c:16719
static void mg_cry_internal_impl(const struct mg_connection *conn, const char *func, unsigned line, const char *fmt, va_list ap)
Definition civetweb.c:3614
void mg_lock_context(struct mg_context *ctx)
Definition civetweb.c:12030
#define SSL_OP_CIPHER_SERVER_PREFERENCE
Definition civetweb.c:1791
#define SSL_shutdown
Definition civetweb.c:2028
#define MAX_WORKER_THREADS
Definition civetweb.c:389
static int send_additional_header(struct mg_connection *conn)
Definition civetweb.c:4282
@ AUTH_HANDLER
Definition civetweb.c:2524
@ REQUEST_HANDLER
Definition civetweb.c:2524
@ WEBSOCKET_HANDLER
Definition civetweb.c:2524
#define SSL_load_error_strings
Definition civetweb.c:2018
static void put_file(struct mg_connection *conn, const char *path)
Definition civetweb.c:11354
#define SSL_OP_NO_SSLv2
Definition civetweb.c:1785
struct ssl_ctx_st SSL_CTX
Definition civetweb.c:1762
static void do_ssi_exec(struct mg_connection *conn, char *tag)
Definition civetweb.c:11661
static void tls_dtor(void *key)
Definition civetweb.c:14930
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
Definition civetweb.c:3250
#define realloc
Definition civetweb.c:1538
const void * SOCK_OPT_TYPE
Definition civetweb.c:771
static int header_has_option(const char *header, const char *option)
Definition civetweb.c:4117
int mg_send_http_redirect(struct mg_connection *conn, const char *target_url, int redirect_code)
Definition civetweb.c:4739
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
Definition civetweb.c:7093
#define SSL_set_app_data(s, arg)
Definition civetweb.c:2078
#define SSL_get_peer_certificate
Definition civetweb.c:2033
#define mg_opendir(conn, x)
Definition civetweb.c:805
static FUNCTION_MAY_BE_UNUSED uint64_t mg_get_current_time_ns(void)
Definition civetweb.c:1649
static char * mg_strndup_ctx(const char *ptr, size_t len, struct mg_context *ctx)
Definition civetweb.c:3295
#define is_websocket_protocol(conn)
Definition civetweb.c:2770
static int put_dir(struct mg_connection *conn, const char *path)
Definition civetweb.c:9903
#define UINT64_FMT
Definition civetweb.c:811
static void * realloc2(void *ptr, size_t size)
Definition civetweb.c:9270
#define INVALID_SOCKET
Definition civetweb.c:809
size_t ext_len
Definition civetweb.c:7794
#define SSL_OP_SINGLE_DH_USE
Definition civetweb.c:1790
static int print_dav_dir_entry(struct de *de, void *data)
Definition civetweb.c:11930
static void delete_file(struct mg_connection *conn, const char *path)
Definition civetweb.c:11505
static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
Definition civetweb.c:12858
#define mg_calloc_ctx(a, b, c)
Definition civetweb.c:1495
#define mg_closedir(x)
Definition civetweb.c:806
static FUNCTION_MAY_BE_UNUSED int mg_atomic_inc(volatile int *addr)
Definition civetweb.c:1180
#define free
Definition civetweb.c:1539
int mg_printf(struct mg_connection *conn, const char *fmt,...)
Definition civetweb.c:6979
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
Definition civetweb.c:9088
static int should_keep_alive(const struct mg_connection *conn)
Definition civetweb.c:4182
static __inline void * mg_malloc(size_t a)
Definition civetweb.c:1471
#define SSL_get_app_data(s)
Definition civetweb.c:2079
static int mg_fopen(const struct mg_connection *conn, const char *path, int mode, struct mg_file *filep)
Definition civetweb.c:3146
#define OPENSSL_REMOVE_THREAD_STATE()
Definition civetweb.c:2121
static int send_no_cache_header(struct mg_connection *conn)
Definition civetweb.c:4239
static void handle_static_file_request(struct mg_connection *conn, const char *path, struct mg_file *filep, const char *mime_type, const char *additional_headers)
Definition civetweb.c:9545
static int ssl_use_pem_file(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *pem, const char *chain)
Definition civetweb.c:15507
static void mg_cry_internal_wrap(const struct mg_connection *conn, const char *func, unsigned line, const char *fmt,...) PRINTF_ARGS(4
Definition civetweb.c:3699
static const char * ssl_error(void)
Definition civetweb.c:15140
static int must_hide_file(struct mg_connection *conn, const char *path)
Definition civetweb.c:9124
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT
Definition civetweb.c:1782
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
Definition civetweb.c:12839
const char * extension
Definition civetweb.c:7793
#define ERRNO
Definition civetweb.c:808
#define SSL_library_init
Definition civetweb.c:2010
#define CONF_modules_unload
Definition civetweb.c:2091
#define mg_remove(conn, x)
Definition civetweb.c:803
int mg_send_http_ok(struct mg_connection *conn, const char *mime_type, long long content_length)
Definition civetweb.c:4701
static void close_all_listening_sockets(struct mg_context *ctx)
Definition civetweb.c:14226
#define closesocket(a)
Definition civetweb.c:801
void mg_send_file(struct mg_connection *conn, const char *path)
Definition civetweb.c:9841
#define SSL_TLSEXT_ERR_OK
Definition civetweb.c:1810
static void send_authorization_request(struct mg_connection *conn, const char *realm)
Definition civetweb.c:8505
#define EVP_Digest
Definition civetweb.c:2104
static int check_password(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response)
Definition civetweb.c:7990
#define X509_get_subject_name
Definition civetweb.c:2095
#define SSL_TLSEXT_ERR_NOACK
Definition civetweb.c:1813
static const struct mg_option config_options[]
Definition civetweb.c:2409
#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS
Definition civetweb.c:1778
static FUNCTION_MAY_BE_UNUSED unsigned long mg_current_thread_id(void)
Definition civetweb.c:1599
static const struct mg_http_method_info * get_http_method_info(const char *method)
Definition civetweb.c:10176
static const char * mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p)
Definition civetweb.c:8227
unsigned default_port
Definition civetweb.c:16615
const char * mg_get_response_code_text(const struct mg_connection *conn, int response_code)
Definition civetweb.c:4312
static int get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
Definition civetweb.c:16999
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS])
Definition civetweb.c:10055
static int set_uid_option(struct mg_context *phys_ctx)
Definition civetweb.c:14876
static void remove_double_dots_and_double_slashes(char *s)
Definition civetweb.c:7765
static void reset_per_request_attributes(struct mg_connection *conn)
Definition civetweb.c:16023
static void handle_file_based_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
Definition civetweb.c:14134
static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin[2], int fdout[2], int fderr[2], const char *dir)
Definition civetweb.c:5903
#define ERR_get_error
Definition civetweb.c:2086
#define SSL_CTX_set_ecdh_auto(ctx, onoff)
Definition civetweb.c:2060
#define FUNCTION_MAY_BE_UNUSED
Definition civetweb.c:251
static pthread_mutex_t * ssl_mutexes
Definition civetweb.c:15038
void mg_set_user_connection_data(struct mg_connection *conn, void *data)
Definition civetweb.c:3450
#define SSLv23_client_method
Definition civetweb.c:2021
static int get_option_index(const char *name)
Definition civetweb.c:3407
static int abort_process(void *data)
Definition civetweb.c:10895
static char * mg_strdup(const char *str)
Definition civetweb.c:3316
static void addenv(struct cgi_environment *env, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
struct x509 X509
Definition civetweb.c:1769
const struct mg_response_info * mg_get_response_info(const struct mg_connection *conn)
Definition civetweb.c:3782
static int initialize_ssl(char *ebuf, size_t ebuf_len)
Definition civetweb.c:15368
static __inline void * mg_realloc(void *a, size_t b)
Definition civetweb.c:1483
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
Definition civetweb.c:17939
static int get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
Definition civetweb.c:16833
#define CRYPTO_LIB
Definition civetweb.c:795
static pthread_mutex_t global_lock_mutex
Definition civetweb.c:1149
#define CGI_ENVIRONMENT_SIZE
Definition civetweb.c:412
#define mg_get_option
Definition civetweb.c:3433
static long ssl_get_protocol(int version_id)
Definition civetweb.c:15578
static int mg_init_library_called
Definition civetweb.c:1549
long long mg_store_body(struct mg_connection *conn, const char *path)
Definition civetweb.c:9953
#define EVP_cleanup
Definition civetweb.c:2093
struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
Definition civetweb.c:17116
#define DEBUG_ASSERT(cond)
Definition civetweb.c:195
static int pull_inner(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
Definition civetweb.c:6298
#define INT64_FMT
Definition civetweb.c:810
static int mg_poll(struct pollfd *pfd, unsigned int n, int milliseconds, volatile int *stop_server)
Definition civetweb.c:6059
int mg_get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int timeout)
Definition civetweb.c:17061
#define MG_FILE_COMPRESSION_SIZE_LIMIT
Definition civetweb.c:402
static struct mg_connection * mg_connect_client_impl(const struct mg_client_options *client_options, int use_ssl, char *ebuf, size_t ebuf_len)
Definition civetweb.c:16387
unsigned mg_check_feature(unsigned feature)
Definition civetweb.c:18811
static int mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
Definition civetweb.c:6573
static int mg_send_http_error_impl(struct mg_connection *conn, int status, const char *fmt, va_list args)
Definition civetweb.c:4511
struct mg_context * mg_start(const struct mg_callbacks *callbacks, void *user_data, const char **options)
Definition civetweb.c:18351
#define SSL_CTX_clear_options(ctx, op)
Definition civetweb.c:2058
#define MG_FOPEN_MODE_READ
Definition civetweb.c:3039
static int open_file_in_memory(const struct mg_connection *conn, const char *path, struct mg_file *filep, int mode)
Definition civetweb.c:3052
#define SSL_OP_NO_COMPRESSION
Definition civetweb.c:1793
static int extention_matches_script(struct mg_connection *conn, const char *filename)
Definition civetweb.c:7254
void mg_set_websocket_handler(struct mg_context *ctx, const char *uri, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
Definition civetweb.c:13395
static const char * alloc_get_host(struct mg_connection *conn)
Definition civetweb.c:13021
static pthread_mutexattr_t pthread_mutex_attr
Definition civetweb.c:963
#define SSL_ERROR_SYSCALL
Definition civetweb.c:1803
#define SSL_CTX_load_verify_locations
Definition civetweb.c:2029
void mg_unlock_context(struct mg_context *ctx)
Definition civetweb.c:12038
#define SSL_ERROR_WANT_READ
Definition civetweb.c:1800
static int ssl_servername_callback(SSL *ssl, int *ad, void *arg)
Definition civetweb.c:15621
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
Definition civetweb.c:8580
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
Definition civetweb.c:3915
static void fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
Definition civetweb.c:9522
int mg_start_thread(mg_thread_func_t func, void *param)
Definition civetweb.c:5841
static void * load_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw)
Definition civetweb.c:15279
static const char * get_header(const struct mg_header *hdr, int num_hdr, const char *name)
Definition civetweb.c:3979
static struct mg_http_method_info http_methods[]
Definition civetweb.c:10119
static int event_signal(void *eventhdl)
Definition civetweb.c:2939
static int init_ssl_ctx_impl(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *pem, const char *chain)
Definition civetweb.c:15687
static int connect_socket(struct mg_context *ctx, const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, SOCKET *sock, union usa *sa)
Definition civetweb.c:8736
unsigned mg_init_library(unsigned features)
Definition civetweb.c:19754
struct mg_connection * mg_connect_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size)
Definition civetweb.c:16595
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
Definition civetweb.c:10480
static void master_thread_run(void *thread_func_param)
Definition civetweb.c:18022
static int set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
Definition civetweb.c:15993
static int skip_to_end_of_word_and_terminate(char **ppw, int eol)
Definition civetweb.c:10010
#define SSL_CTX_new
Definition civetweb.c:2008
#define BN_bn2hex
Definition civetweb.c:2110
static int get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
Definition civetweb.c:16908
int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len)
Definition civetweb.c:7024
#define SSL_free
Definition civetweb.c:2000
#define ARRAY_SIZE(array)
Definition civetweb.c:435
#define ERR_free_strings
Definition civetweb.c:2089
#define SSL_VERIFY_PEER
Definition civetweb.c:1781
struct ssl_st SSL
Definition civetweb.c:1760
static int parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
Definition civetweb.c:14259
static int get_first_ssl_listener_index(const struct mg_context *ctx)
Definition civetweb.c:13005
#define SSL_CTX_use_PrivateKey_file
Definition civetweb.c:2011
struct ssl_method_st SSL_METHOD
Definition civetweb.c:1761
void mg_send_mime_file(struct mg_connection *conn, const char *path, const char *mime_type)
Definition civetweb.c:9848
const char * mg_get_header(const struct mg_connection *conn, const char *name)
Definition civetweb.c:4016
#define mg_mkdir(conn, path, mode)
Definition civetweb.c:802
#define SSL_OP_NO_TLSv1
Definition civetweb.c:1787
static int isbyte(int n)
Definition civetweb.c:12832
static uint32_t get_remote_ip(const struct mg_connection *conn)
Definition civetweb.c:12893
static int hexdump2string(void *mem, int memlen, char *buf, int buflen)
Definition civetweb.c:15149
static void handle_directory_request(struct mg_connection *conn, const char *dir)
Definition civetweb.c:9306
static int set_ports_option(struct mg_context *phys_ctx)
Definition civetweb.c:14458
#define SSL_write
Definition civetweb.c:2004
static int read_auth_file(struct mg_file *filep, struct read_auth_file_struct *workdata, int depth)
Definition civetweb.c:8289
static int mg_start_thread_with_id(mg_thread_func_t func, void *param, pthread_t *threadidptr)
Definition civetweb.c:5865
unsigned mg_exit_library(void)
Definition civetweb.c:19830
#define SSL_CTX_set_tlsext_servername_callback(ctx, cb)
Definition civetweb.c:2066
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
Definition civetweb.c:3572
int mg_send_digest_access_authentication_request(struct mg_connection *conn, const char *realm)
Definition civetweb.c:8546
static void print_props(struct mg_connection *conn, const char *uri, struct mg_file_stat *filep)
Definition civetweb.c:11899
static const char * mg_strcasestr(const char *big_str, const char *small_str)
Definition civetweb.c:3323
struct mg_connection * mg_connect_websocket_client(const char *host, int port, int use_ssl, char *error_buffer, size_t error_buffer_size, const char *path, const char *origin, mg_websocket_data_handler data_func, mg_websocket_close_handler close_func, void *user_data)
Definition civetweb.c:17233
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
Definition civetweb.c:6489
static void handle_ssi_file_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
Definition civetweb.c:11813
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
Definition civetweb.c:6755
static void mg_snprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(5
static void ssl_info_callback(const SSL *ssl, int what, int ret)
Definition civetweb.c:15605
#define ASN1_INTEGER_to_BN
Definition civetweb.c:2111
#define calloc
Definition civetweb.c:1537
#define SSL_ERROR_WANT_ACCEPT
Definition civetweb.c:1806
@ CONNECTION_TYPE_RESPONSE
Definition civetweb.c:2692
@ CONNECTION_TYPE_INVALID
Definition civetweb.c:2690
@ CONNECTION_TYPE_REQUEST
Definition civetweb.c:2691
static void bin2str(char *to, const unsigned char *p, size_t len)
Definition civetweb.c:7952
const struct mg_request_info * mg_get_request_info(const struct mg_connection *conn)
Definition civetweb.c:3745
#define SSL_ERROR_WANT_X509_LOOKUP
Definition civetweb.c:1802
#define MG_FOPEN_MODE_APPEND
Definition civetweb.c:3045
char * mg_md5(char buf[33],...)
Definition civetweb.c:7967
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
Definition civetweb.c:4060
#define X509_free
Definition civetweb.c:2094
#define SSL_CB_HANDSHAKE_START
Definition civetweb.c:1795
static const char * suggest_connection_header(const struct mg_connection *conn)
Definition civetweb.c:4232
static int alloc_vprintf(char **out_buf, char *prealloc_buf, size_t prealloc_size, const char *fmt, va_list ap)
Definition civetweb.c:6898
static time_t parse_date_string(const char *datetime)
Definition civetweb.c:7701
int SOCKET
Definition civetweb.c:812
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
Definition civetweb.c:11574
int mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
Definition civetweb.c:3822
static int prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_environment *env)
Definition civetweb.c:10692
static void interpret_uri(struct mg_connection *conn, char *filename, size_t filename_buf_len, struct mg_file_stat *filestat, int *is_found, int *is_script_resource, int *is_websocket_request, int *is_put_or_delete_request)
Definition civetweb.c:7344
#define SSL_CTX_free
Definition civetweb.c:2017
#define SSL_ERROR_WANT_CONNECT
Definition civetweb.c:1805
#define SSL_set_fd
Definition civetweb.c:2006
static void send_options(struct mg_connection *conn)
Definition civetweb.c:11867
static int lowercase(const char *s)
Definition civetweb.c:3260
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
Definition civetweb.c:9500
static void event_destroy(void *eventhdl)
Definition civetweb.c:2950
static int mg_stat(const struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
Definition civetweb.c:5791
static int get_uri_type(const char *uri)
Definition civetweb.c:16630
#define X509_get_serialNumber
Definition civetweb.c:2099
#define SSL_LIB
Definition civetweb.c:792
#define DEBUG_TRACE(fmt,...)
Definition civetweb.c:178
static void get_system_name(char **sysName)
Definition civetweb.c:18299
int mg_url_encode(const char *src, char *dst, size_t dst_len)
Definition civetweb.c:8967
static void handler_info_wait_unused(struct mg_handler_info *handler_info)
Definition civetweb.c:13178
static const char * header_val(const struct mg_connection *conn, const char *header)
Definition civetweb.c:14724
#define CRYPTO_set_locking_callback
Definition civetweb.c:2082
struct ossl_init_settings_st OPENSSL_INIT_SETTINGS
Definition civetweb.c:1767
#define mg_cry_internal(conn, fmt,...)
Definition civetweb.c:2774
static int set_acl_option(struct mg_context *phys_ctx)
Definition civetweb.c:16016
static void mg_set_thread_name(const char *name)
Definition civetweb.c:2961
static void get_mime_type(struct mg_connection *conn, const char *path, struct vec *vec)
Definition civetweb.c:7917
static int set_blocking_mode(SOCKET sock)
Definition civetweb.c:6011
#define MSG_NOSIGNAL
Definition civetweb.c:1717
#define CRYPTO_cleanup_all_ex_data
Definition civetweb.c:2092
CIVETWEB_API struct mg_connection * mg_connect_client_secure(const struct mg_client_options *client_options, char *error_buffer, size_t error_buffer_size)
Definition civetweb.c:16583
static void send_file_data(struct mg_connection *conn, struct mg_file *filep, int64_t offset, int64_t len)
Definition civetweb.c:9387
#define MAX_CGI_ENVIR_VARS
Definition civetweb.c:417
#define SSL_OP_NO_SSLv3
Definition civetweb.c:1786
#define SSL_set_SSL_CTX
Definition civetweb.c:2053
static int sslize(struct mg_connection *conn, SSL_CTX *s, int(*func)(SSL *), volatile int *stop_server, const struct mg_client_options *client_options)
Definition civetweb.c:15042
static char * mg_strdup_ctx(const char *str, struct mg_context *ctx)
Definition civetweb.c:3310
static void set_close_on_exec(SOCKET fd, struct mg_connection *conn)
Definition civetweb.c:5827
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
Definition civetweb.c:6993
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
Definition civetweb.c:8114
struct evp_md EVP_MD
Definition civetweb.c:1768
#define SSL_CTX_set_cipher_list
Definition civetweb.c:2042
int mg_get_var2(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len, size_t occurrence)
Definition civetweb.c:7035
static int is_not_modified(const struct mg_connection *conn, const struct mg_file_stat *filestat)
Definition civetweb.c:9792
static const char * get_proto_name(const struct mg_connection *conn)
Definition civetweb.c:3795
static void * master_thread(void *thread_func_param)
Definition civetweb.c:18156
#define SSL_CTX_set_verify_depth
Definition civetweb.c:2032
static void mg_set_handler_type(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx, const char *uri, int handler_type, int is_delete_request, mg_request_handler handler, struct mg_websocket_subprotocols *subprotocols, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, mg_authorization_handler auth_handler, void *cbdata)
Definition civetweb.c:13190
static int is_file_opened(const struct mg_file_access *fileacc)
Definition civetweb.c:3120
static int get_http_header_len(const char *buf, int buflen)
Definition civetweb.c:7646
#define SSL_CTX_set_info_callback
Definition civetweb.c:2044
#define SSL_read
Definition civetweb.c:2003
static void handler_info_release(struct mg_handler_info *handler_info)
Definition civetweb.c:13168
void mg_close_connection(struct mg_connection *conn)
Definition civetweb.c:16313
static int is_valid_port(unsigned long port)
Definition civetweb.c:8692
static void handle_propfind(struct mg_connection *conn, const char *path, struct mg_file_stat *filep)
Definition civetweb.c:11966
static int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
Definition civetweb.c:6961
#define SSL_get_servername
Definition civetweb.c:2051
#define mg_realloc_ctx(a, b, c)
Definition civetweb.c:1496
#define SSL_CTX_use_certificate_chain_file
Definition civetweb.c:2019
struct x509_name X509_NAME
Definition civetweb.c:1764
#define CRYPTO_num_locks
Definition civetweb.c:2081
static int is_put_or_delete_method(const struct mg_connection *conn)
Definition civetweb.c:7240
static int read_message(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread)
Definition civetweb.c:10405
#define SSL_CTX_set_default_verify_paths
Definition civetweb.c:2031
static int print_dir_entry(struct de *de)
Definition civetweb.c:8995
#define MG_FOPEN_MODE_WRITE
Definition civetweb.c:3042
void * mg_get_user_connection_data(const struct mg_connection *conn)
Definition civetweb.c:3459
static int authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm)
Definition civetweb.c:8403
static void send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int)
Definition civetweb.c:11707
#define ERR_error_string
Definition civetweb.c:2087
#define mg_static_assert(cond, txt)
Definition civetweb.c:120
#define SOCKET_TIMEOUT_QUANTUM
Definition civetweb.c:397
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
Definition civetweb.c:17626
static ptrdiff_t match_prefix(const char *pattern, size_t pattern_len, const char *str)
Definition civetweb.c:4136
int mg_send_chunk(struct mg_connection *conn, const char *chunk, unsigned int chunk_len)
Definition civetweb.c:6819
#define EVP_get_digestbyname
Definition civetweb.c:2102
#define SHUTDOWN_BOTH
Definition civetweb.c:444
static int get_request_handler(struct mg_connection *conn, int handler_type, mg_request_handler *handler, struct mg_websocket_subprotocols **subprotocols, mg_websocket_connect_handler *connect_handler, mg_websocket_ready_handler *ready_handler, mg_websocket_data_handler *data_handler, mg_websocket_close_handler *close_handler, mg_authorization_handler *auth_handler, void **cbdata, struct mg_handler_info **handler_info)
Definition civetweb.c:13467
static void ssl_get_client_cert_info(struct mg_connection *conn)
Definition civetweb.c:15175
#define MG_BUF_LEN
Definition civetweb.c:422
static int alloc_vprintf2(char **buf, const char *fmt, va_list ap)
Definition civetweb.c:6865
#define BN_free
Definition civetweb.c:2113
static int is_in_script_path(const struct mg_connection *conn, const char *path)
Definition civetweb.c:13581
static double mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
Definition civetweb.c:3596
static void free_context(struct mg_context *ctx)
Definition civetweb.c:18172
#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
Definition civetweb.c:1792
static void construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
Definition civetweb.c:9507
int mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
Definition civetweb.c:19713
static int thread_idx_max
Definition civetweb.c:1556
static int cryptolib_users
Definition civetweb.c:15363
static int64_t push_all(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
Definition civetweb.c:6254
static const char * month_names[]
Definition civetweb.c:2202
static int refresh_trust(struct mg_connection *conn)
Definition civetweb.c:14955
#define SHUTDOWN_WR
Definition civetweb.c:443
static struct ssl_func ssl_sw[]
Definition civetweb.c:2127
static void mg_vsnprintf(const struct mg_connection *conn, int *truncated, char *buf, size_t buflen, const char *fmt, va_list ap)
Definition civetweb.c:3342
static int event_wait(void *eventhdl)
Definition civetweb.c:2928
static int should_decode_url(const struct mg_connection *conn)
Definition civetweb.c:4221
static void uninitialize_ssl(void)
Definition civetweb.c:15952
#define TLSEXT_NAMETYPE_host_name
Definition civetweb.c:1809
#define SSL_CTX_set_options(ctx, op)
Definition civetweb.c:2056
static void handle_request(struct mg_connection *conn)
Definition civetweb.c:13637
#define malloc
Definition civetweb.c:1536
static int mg_get_system_info_impl(char *buffer, int buflen)
Definition civetweb.c:18885
#define INT64_MAX
Definition civetweb.c:439
static void * worker_thread_run(struct worker_thread_args *thread_args)
Definition civetweb.c:17736
#define SSL_CTX_set_verify
Definition civetweb.c:2023
static int remove_directory(struct mg_connection *conn, const char *dir)
Definition civetweb.c:9194
static const char * get_http_version(const struct mg_connection *conn)
Definition civetweb.c:4037
static __inline void * mg_calloc(size_t a, size_t b)
Definition civetweb.c:1477
#define WINCDECL
Definition civetweb.c:813
#define va_copy(x, y)
Definition civetweb.c:892
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
Definition civetweb.c:10929
static void handler_info_acquire(struct mg_handler_info *handler_info)
Definition civetweb.c:13159
#define i2d_X509
Definition civetweb.c:2109
#define SSL_accept
Definition civetweb.c:2001
static int parse_http_response(char *buf, int len, struct mg_response_info *ri)
Definition civetweb.c:10298
static void * cryptolib_dll_handle
Definition civetweb.c:15355
#define MG_FOPEN_MODE_NONE
Definition civetweb.c:3036
#define CRYPTO_set_id_callback
Definition civetweb.c:2084
const char * mg_get_builtin_mime_type(const char *path)
Definition civetweb.c:7895
int mg_read(struct mg_connection *conn, void *buf, size_t len)
Definition civetweb.c:6655
#define IGNORE_UNUSED_RESULT(a)
Definition civetweb.c:226
static FUNCTION_MAY_BE_UNUSED int mg_atomic_dec(volatile int *addr)
Definition civetweb.c:1203
#define X509_get_issuer_name
Definition civetweb.c:2096
static void discard_unread_request_data(struct mg_connection *conn)
Definition civetweb.c:6533
int mg_strcasecmp(const char *s1, const char *s2)
Definition civetweb.c:3282
static int mg_fclose(struct mg_file_access *fileacc)
Definition civetweb.c:3231
static struct mg_connection * fc(struct mg_context *ctx)
Definition civetweb.c:3728
void mg_set_request_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
Definition civetweb.c:13373
static int send_static_cache_header(struct mg_connection *conn)
Definition civetweb.c:4251
#define SSL_CTX_set_session_id_context
Definition civetweb.c:2039
static struct mg_context common_client_context
Definition civetweb.c:16383
static void * worker_thread(void *thread_func_param)
Definition civetweb.c:17918
#define SSL_CB_HANDSHAKE_DONE
Definition civetweb.c:1796
static __inline void mg_free(void *a)
Definition civetweb.c:1489
int mg_check_digest_access_authentication(struct mg_connection *conn, const char *realm, const char *filename)
Definition civetweb.c:8431
static int mg_join_thread(pthread_t threadid)
Definition civetweb.c:5892
#define SSL_OP_ALL
Definition civetweb.c:1784
int mg_get_system_info(char *buffer, int buflen)
Definition civetweb.c:19698
static void handle_not_modified_static_file_request(struct mg_connection *conn, struct mg_file *filep)
Definition civetweb.c:9806
static int init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
Definition civetweb.c:15877
static void close_socket_gracefully(struct mg_connection *conn)
Definition civetweb.c:16129
struct mg_context * mg_get_context(const struct mg_connection *conn)
Definition civetweb.c:3436
static int is_ssl_port_used(const char *ports)
Definition civetweb.c:14401
static void init_connection(struct mg_connection *conn)
Definition civetweb.c:17395
#define INITIAL_DEPTH
Definition civetweb.c:8272
struct x509_store_ctx_st X509_STORE_CTX
Definition civetweb.c:1763
static struct ssl_func crypto_sw[]
Definition civetweb.c:2171
#define MGSQLEN
Definition civetweb.c:428
static int dir_scan_callback(struct de *de, void *data)
Definition civetweb.c:9281
size_t proto_len
Definition civetweb.c:16614
static int get_month_index(const char *s)
Definition civetweb.c:7685
void mg_set_websocket_handler_with_subprotocols(struct mg_context *ctx, const char *uri, struct mg_websocket_subprotocols *subprotocols, mg_websocket_connect_handler connect_handler, mg_websocket_ready_handler ready_handler, mg_websocket_data_handler data_handler, mg_websocket_close_handler close_handler, void *cbdata)
Definition civetweb.c:13415
static int mg_ssl_initialized
Definition civetweb.c:1552
static void * ssllib_dll_handle
Definition civetweb.c:15354
#define OPENSSL_INIT_LOAD_SSL_STRINGS
Definition civetweb.c:1777
static const struct @144 builtin_mime_types[]
#define mg_sleep(x)
Definition civetweb.c:804
@ ENABLE_DIRECTORY_LISTING
Definition civetweb.c:2352
@ SSL_SHORT_TRUST
Definition civetweb.c:2368
@ GLOBAL_PASSWORDS_FILE
Definition civetweb.c:2353
@ ADDITIONAL_HEADER
Definition civetweb.c:2399
@ SSL_VERIFY_DEPTH
Definition civetweb.c:2364
@ ACCESS_CONTROL_ALLOW_ORIGIN
Definition civetweb.c:2389
@ SSL_PROTOCOL_VERSION
Definition civetweb.c:2367
@ SSL_DO_VERIFY_PEER
Definition civetweb.c:2361
@ SSL_CERTIFICATE
Definition civetweb.c:2357
@ RUN_AS_USER
Definition civetweb.c:2312
@ ALLOW_INDEX_SCRIPT_SUB_RES
Definition civetweb.c:2400
@ ENABLE_KEEP_ALIVE
Definition civetweb.c:2326
@ ACCESS_CONTROL_LIST
Definition civetweb.c:2355
@ SSL_CA_PATH
Definition civetweb.c:2362
@ AUTHENTICATION_DOMAIN
Definition civetweb.c:2349
@ ACCESS_CONTROL_ALLOW_HEADERS
Definition civetweb.c:2391
@ SSL_DEFAULT_VERIFY_PATHS
Definition civetweb.c:2365
@ ACCESS_CONTROL_ALLOW_METHODS
Definition civetweb.c:2390
@ STRICT_HTTPS_MAX_AGE
Definition civetweb.c:2397
@ HIDE_FILES
Definition civetweb.c:2360
@ ERROR_LOG_FILE
Definition civetweb.c:2325
@ STATIC_FILE_MAX_AGE
Definition civetweb.c:2394
@ LINGER_TIMEOUT
Definition civetweb.c:2316
@ URL_REWRITE_PATTERN
Definition civetweb.c:2359
@ THROTTLE
Definition civetweb.c:2323
@ SSL_CIPHER_LIST
Definition civetweb.c:2366
@ KEEP_ALIVE_TIMEOUT
Definition civetweb.c:2328
@ CGI_EXTENSIONS
Definition civetweb.c:2344
@ ERROR_PAGES
Definition civetweb.c:2392
@ CGI_ENVIRONMENT
Definition civetweb.c:2345
@ PUT_DELETE_PASSWORDS_FILE
Definition civetweb.c:2346
@ ENABLE_AUTH_DOMAIN_CHECK
Definition civetweb.c:2350
@ NUM_OPTIONS
Definition civetweb.c:2402
@ MAX_REQUEST_SIZE
Definition civetweb.c:2315
@ DECODE_URL
Definition civetweb.c:2333
@ NUM_THREADS
Definition civetweb.c:2311
@ DOCUMENT_ROOT
Definition civetweb.c:2343
@ SSL_CERTIFICATE_CHAIN
Definition civetweb.c:2358
@ PROTECT_URI
Definition civetweb.c:2348
@ ACCESS_LOG_FILE
Definition civetweb.c:2324
@ REQUEST_TIMEOUT
Definition civetweb.c:2327
@ SSI_EXTENSIONS
Definition civetweb.c:2351
@ CONFIG_TCP_NODELAY
Definition civetweb.c:2313
@ SSL_CA_FILE
Definition civetweb.c:2363
@ CGI_INTERPRETER
Definition civetweb.c:2347
@ LISTENING_PORTS
Definition civetweb.c:2310
@ INDEX_FILES
Definition civetweb.c:2354
@ EXTRA_MIME_TYPES
Definition civetweb.c:2356
#define PASSWORDS_FILE_NAME
Definition civetweb.c:406
static void log_access(const struct mg_connection *conn)
Definition civetweb.c:14742
#define SSLv23_server_method
Definition civetweb.c:2009
static void close_connection(struct mg_connection *conn)
Definition civetweb.c:16249
#define SSL_OP_NO_TLSv1_1
Definition civetweb.c:1789
struct bignum BIGNUM
Definition civetweb.c:1766
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct mg_file_stat *filestat)
Definition civetweb.c:7296
static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
Definition civetweb.c:13108
void mg_stop(struct mg_context *ctx)
Definition civetweb.c:18265
#define STRUCT_FILE_INITIALIZER
Definition civetweb.c:2279
#define SSL_CTX_set_tlsext_servername_arg(ctx, arg)
Definition civetweb.c:2070
static FUNCTION_MAY_BE_UNUSED void mg_global_unlock(void)
Definition civetweb.c:1172
void * mg_get_user_data(const struct mg_context *ctx)
Definition civetweb.c:3443
static FUNCTION_MAY_BE_UNUSED void mg_global_lock(void)
Definition civetweb.c:1164
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, int(*cb)(struct de *, void *))
Definition civetweb.c:9138
static int push_inner(struct mg_context *ctx, FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int len, double timeout)
Definition civetweb.c:6108
#define SSL_get_error
Definition civetweb.c:2005
static int check_acl(struct mg_context *phys_ctx, uint32_t remote_ip)
Definition civetweb.c:14841
const char * mg_version(void)
Definition civetweb.c:3738
void mg_set_auth_handler(struct mg_context *ctx, const char *uri, mg_request_handler handler, void *cbdata)
Definition civetweb.c:13445
static uint64_t get_random(void)
Definition civetweb.c:6030
#define SSL_pending
Definition civetweb.c:2022
void mg_lock_connection(struct mg_connection *conn)
Definition civetweb.c:12014
int mg_send_file_body(struct mg_connection *conn, const char *path)
Definition civetweb.c:9776
static void * event_create(void)
Definition civetweb.c:2905
#define strcat0(a, b)
Definition civetweb.c:18874
#define SSL_connect
Definition civetweb.c:2002
#define mg_cry
Definition civetweb.c:3722
static int is_valid_http_method(const char *method)
Definition civetweb.c:10195
#define SSL_ERROR_WANT_WRITE
Definition civetweb.c:1801
static int is_file_in_memory(const struct mg_connection *conn, const char *path)
Definition civetweb.c:3113
#define MG_MAX_HEADERS
Definition civetweb.h:136
CIVETWEB_API int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
void *(* mg_thread_func_t)(void *)
Definition civetweb.h:1273
#define CIVETWEB_VERSION
Definition civetweb.h:26
#define PRINTF_FORMAT_STRING(s)
Definition civetweb.h:855
int(* mg_authorization_handler)(struct mg_connection *conn, void *cbdata)
Definition civetweb.h:569
CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
@ MG_FEATURES_STATS
Definition civetweb.h:95
@ MG_FEATURES_CACHE
Definition civetweb.h:91
@ MG_FEATURES_FILES
Definition civetweb.h:61
@ MG_FEATURES_CGI
Definition civetweb.h:71
@ MG_FEATURES_IPV6
Definition civetweb.h:75
@ MG_FEATURES_DEFAULT
Definition civetweb.h:57
@ MG_FEATURES_TLS
Definition civetweb.h:66
@ MG_FEATURES_SSL
Definition civetweb.h:67
@ MG_FEATURES_LUA
Definition civetweb.h:83
@ MG_FEATURES_WEBSOCKET
Definition civetweb.h:79
@ MG_FEATURES_SSJS
Definition civetweb.h:87
@ MG_FEATURES_COMPRESSION
Definition civetweb.h:99
void(* mg_websocket_ready_handler)(struct mg_connection *, void *)
Definition civetweb.h:512
#define CIVETWEB_API
Definition civetweb.h:43
CIVETWEB_API int mg_handle_form_request(struct mg_connection *conn, struct mg_form_data_handler *fdh)
#define PRINTF_ARGS(x, y)
Definition civetweb.h:861
@ MG_CONFIG_TYPE_UNKNOWN
Definition civetweb.h:666
@ MG_CONFIG_TYPE_FILE
Definition civetweb.h:669
@ MG_CONFIG_TYPE_STRING
Definition civetweb.h:668
@ MG_CONFIG_TYPE_DIRECTORY
Definition civetweb.h:670
@ MG_CONFIG_TYPE_EXT_PATTERN
Definition civetweb.h:672
@ MG_CONFIG_TYPE_STRING_MULTILINE
Definition civetweb.h:674
@ MG_CONFIG_TYPE_STRING_LIST
Definition civetweb.h:673
@ MG_CONFIG_TYPE_YES_NO_OPTIONAL
Definition civetweb.h:675
@ MG_CONFIG_TYPE_NUMBER
Definition civetweb.h:667
@ MG_CONFIG_TYPE_BOOLEAN
Definition civetweb.h:671
@ MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE
Definition civetweb.h:840
@ MG_WEBSOCKET_OPCODE_PONG
Definition civetweb.h:842
@ MG_WEBSOCKET_OPCODE_PING
Definition civetweb.h:841
int(* mg_websocket_data_handler)(struct mg_connection *, int, char *, size_t, void *)
Definition civetweb.h:513
int(* mg_request_handler)(struct mg_connection *conn, void *cbdata)
Definition civetweb.h:456
void(* mg_websocket_close_handler)(const struct mg_connection *, void *)
Definition civetweb.h:518
int(* mg_websocket_connect_handler)(const struct mg_connection *, void *)
Definition civetweb.h:510
TLine * line
Double_t y[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
unsigned char md5_byte_t
Definition md5.inl:50
MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16])
Definition md5.inl:449
MD5_STATIC void md5_init(md5_state_t *pms)
Definition md5.inl:401
MD5_STATIC void md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
Definition md5.inl:411
#define TRUE
Definition mesh.c:42
#define FALSE
Definition mesh.c:45
RooArgList L(Args_t &&... args)
Definition RooArgList.h:156
Definition file.py:1
const char * cnt
Definition TXMLSetup.cxx:75
SHA_API void SHA1_Init(SHA_CTX *context)
Definition sha1.inl:258
SHA_API void SHA1_Update(SHA_CTX *context, const uint8_t *data, const uint32_t len)
Definition sha1.inl:271
SHA_API void SHA1_Final(unsigned char *digest, SHA_CTX *context)
Definition sha1.inl:298
#define blk(block, i)
Definition sha1.inl:124
TCanvas * slash()
Definition slash.C:1
static const char * what
Definition stlLoader.cc:6
char * nc
Definition civetweb.c:8108
char * nonce
Definition civetweb.c:8108
char * cnonce
Definition civetweb.c:8108
char * uri
Definition civetweb.c:8108
char * user
Definition civetweb.c:8108
char * qop
Definition civetweb.c:8108
char * response
Definition civetweb.c:8108
struct mg_connection * conn
Definition civetweb.c:10603
char * file_name
Definition civetweb.c:2762
struct mg_connection * conn
Definition civetweb.c:2761
struct mg_file_stat file
Definition civetweb.c:2763
unsigned int arr_size
Definition civetweb.c:9264
struct de * entries
Definition civetweb.c:9262
unsigned int num_entries
Definition civetweb.c:9263
int(* init_ssl)(void *ssl_context, void *user_data)
Definition civetweb.h:255
int(* log_message)(const struct mg_connection *, const char *message)
Definition civetweb.h:242
void(* end_request)(const struct mg_connection *, int reply_status_code)
Definition civetweb.h:238
int(* init_connection)(const struct mg_connection *conn, void **conn_data)
Definition civetweb.h:379
void(* connection_close)(const struct mg_connection *)
Definition civetweb.h:314
int(* http_error)(struct mg_connection *conn, int status, const char *errmsg)
Definition civetweb.h:341
void(* exit_context)(const struct mg_context *ctx)
Definition civetweb.h:364
void(* init_thread)(const struct mg_context *ctx, int thread_type)
Definition civetweb.h:359
int(* external_ssl_ctx)(void **ssl_ctx, void *user_data)
Definition civetweb.h:269
int(* begin_request)(struct mg_connection *)
Definition civetweb.h:235
int(* log_access)(const struct mg_connection *, const char *message)
Definition civetweb.h:246
void(* init_context)(const struct mg_context *ctx)
Definition civetweb.h:349
const char * issuer
Definition civetweb.h:201
const char * finger
Definition civetweb.h:203
void * peer_cert
Definition civetweb.h:199
const char * subject
Definition civetweb.h:200
const char * serial
Definition civetweb.h:202
const char * host_name
Definition civetweb.h:1391
const char * client_cert
Definition civetweb.h:1389
const char * server_cert
Definition civetweb.h:1390
const char * host
Definition civetweb.h:1387
time_t last_throttle_time
Definition civetweb.c:2747
int64_t content_len
Definition civetweb.c:2719
struct timespec req_time
Definition civetweb.c:2716
size_t chunk_remainder
Definition civetweb.c:2727
int64_t consumed_content
Definition civetweb.c:2720
SSL_CTX * client_ssl_ctx
Definition civetweb.c:2712
char * path_info
Definition civetweb.c:2729
int64_t num_bytes_sent
Definition civetweb.c:2718
int connection_type
Definition civetweb.c:2696
pthread_mutex_t mutex
Definition civetweb.c:2749
const char * host
Definition civetweb.c:2710
struct socket client
Definition civetweb.c:2713
struct mg_response_info response_info
Definition civetweb.c:2699
struct mg_request_info request_info
Definition civetweb.c:2698
struct mg_context * phys_ctx
Definition civetweb.c:2701
struct mg_domain_context * dom_ctx
Definition civetweb.c:2702
int64_t last_throttle_bytes
Definition civetweb.c:2748
int in_error_handler
Definition civetweb.c:2733
time_t conn_birth_time
Definition civetweb.c:2714
int handled_requests
Definition civetweb.c:2738
time_t start_time
Definition civetweb.c:2646
volatile int stop_flag
Definition civetweb.c:2617
pthread_t * worker_threadids
Definition civetweb.c:2623
struct socket * client_socks
Definition civetweb.c:2627
void * user_data
Definition civetweb.c:2663
struct mg_connection * worker_connections
Definition civetweb.c:2604
struct socket * listening_sockets
Definition civetweb.c:2600
char * systemName
Definition civetweb.c:2645
pthread_t masterthreadid
Definition civetweb.c:2620
int context_type
Definition civetweb.c:2598
pthread_mutex_t thread_mutex
Definition civetweb.c:2618
struct mg_callbacks callbacks
Definition civetweb.c:2662
struct mg_domain_context dd
Definition civetweb.c:2672
struct pollfd * listening_socket_fds
Definition civetweb.c:2601
void ** client_wait_events
Definition civetweb.c:2628
unsigned int num_listening_sockets
Definition civetweb.c:2602
unsigned int max_request_size
Definition civetweb.c:2638
unsigned int cfg_worker_threads
Definition civetweb.c:2622
pthread_mutex_t nonce_mutex
Definition civetweb.c:2659
char * config[NUM_OPTIONS]
Definition civetweb.c:2572
unsigned long nonce_count
Definition civetweb.c:2577
uint64_t auth_nonce_mask
Definition civetweb.c:2576
struct mg_domain_context * next
Definition civetweb.c:2585
SSL_CTX * ssl_ctx
Definition civetweb.c:2571
struct mg_handler_info * handlers
Definition civetweb.c:2573
uint64_t size
Definition civetweb.c:2235
time_t last_modified
Definition civetweb.c:2236
struct mg_file_stat stat
Definition civetweb.c:2263
struct mg_file_access access
Definition civetweb.c:2264
mg_request_handler handler
Definition civetweb.c:2536
mg_authorization_handler auth_handler
Definition civetweb.c:2552
mg_websocket_close_handler close_handler
Definition civetweb.c:2546
pthread_mutex_t refcount_mutex
Definition civetweb.c:2538
struct mg_handler_info * next
Definition civetweb.c:2558
pthread_cond_t refcount_cond
Definition civetweb.c:2540
unsigned int refcount
Definition civetweb.c:2537
mg_websocket_connect_handler connect_handler
Definition civetweb.c:2543
struct mg_websocket_subprotocols * subprotocols
Definition civetweb.c:2549
mg_websocket_data_handler data_handler
Definition civetweb.c:2545
mg_websocket_ready_handler ready_handler
Definition civetweb.c:2544
const char * value
Definition civetweb.h:140
const char * name
Definition civetweb.h:139
const char * name
Definition civetweb.c:10109
const char * default_value
Definition civetweb.h:646
const char * name
Definition civetweb.h:644
struct mg_header http_headers[MG_MAX_HEADERS]
Definition civetweb.h:170
const char * local_uri
Definition civetweb.h:149
void * user_data
Definition civetweb.h:166
const char * request_method
Definition civetweb.h:146
struct mg_client_cert * client_cert
Definition civetweb.h:173
const char * query_string
Definition civetweb.h:156
long long content_length
Definition civetweb.h:162
void * conn_data
Definition civetweb.h:167
char remote_addr[48]
Definition civetweb.h:160
const char * http_version
Definition civetweb.h:155
const char * request_uri
Definition civetweb.h:147
const char * acceptedWebSocketSubprotocol
Definition civetweb.h:175
const char * remote_user
Definition civetweb.h:158
long long content_length
Definition civetweb.h:187
const char * http_version
Definition civetweb.h:185
const char * status_text
Definition civetweb.h:184
struct mg_header http_headers[MG_MAX_HEADERS]
Definition civetweb.h:191
unsigned long thread_idx
Definition civetweb.c:1564
int pw_gid
int pw_uid
pthread_mutex_t mutex
Definition civetweb.c:2899
pthread_cond_t cond
Definition civetweb.c:2900
const char * f_ha1
Definition civetweb.c:8284
const char * f_domain
Definition civetweb.c:8283
const char * f_user
Definition civetweb.c:8282
const char * domain
Definition civetweb.c:8280
char buf[256+256+40]
Definition civetweb.c:8281
struct mg_connection * conn
Definition civetweb.c:8278
unsigned char is_ssl
Definition civetweb.c:2296
union usa lsa
Definition civetweb.c:2294
unsigned char ssl_redir
Definition civetweb.c:2297
SOCKET sock
Definition civetweb.c:2293
unsigned char in_use
Definition civetweb.c:2299
union usa rsa
Definition civetweb.c:2295
void(* ptr)(void)
Definition civetweb.c:1817
const char * name
Definition civetweb.c:1816
size_t len
Definition civetweb.c:2230
const char * ptr
Definition civetweb.c:2229
mg_websocket_close_handler close_handler
Definition civetweb.c:17173
mg_websocket_data_handler data_handler
Definition civetweb.c:17172
struct mg_connection * conn
Definition civetweb.c:17171
struct mg_context * ctx
Definition civetweb.c:17730
auto * m
Definition textangle.C:8
auto * l
Definition textangle.C:4
struct sockaddr sa
Definition civetweb.c:2220
struct sockaddr_in sin
Definition civetweb.c:2221
static void output(int code)
Definition gifencode.c:226