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
1562struct mg_workerTLS {
1563 int is_master;
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
2233struct mg_file_stat {
2234 /* File properties filled by mg_stat: */
2235 uint64_t size;
2236 time_t last_modified;
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
2243struct mg_file_in_memory {
2244 char *p;
2245 uint32_t pos;
2246 char mode;
2247};
2248
2249struct mg_file_access {
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 {
2263 struct mg_file_stat stat;
2264 struct mg_file_access access;
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
2527struct mg_handler_info {
2528 /* Name/Pattern of the URI. */
2529 char *uri;
2530 size_t uri_len;
2531
2532 /* handler type */
2533 int handler_type;
2534
2535 /* Handler for http/https or authorization requests. */
2536 mg_request_handler handler;
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. */
2543 mg_websocket_connect_handler connect_handler;
2544 mg_websocket_ready_handler ready_handler;
2545 mg_websocket_data_handler data_handler;
2546 mg_websocket_close_handler close_handler;
2547
2548 /* accepted subprotocols for ws/wss requests. */
2549 struct mg_websocket_subprotocols *subprotocols;
2550
2551 /* Handler for authorization requests */
2552 mg_authorization_handler auth_handler;
2553
2554 /* User supplied argument for the handler function. */
2555 void *cbdata;
2556
2557 /* next handler in a linked list */
2558 struct mg_handler_info *next;
2559};
2560
2561
2562enum {
2568
2569
2570struct mg_domain_context {
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 */
2585 struct mg_domain_context *next;
2586};
2587
2588
2589struct mg_context {
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
2600 struct socket *listening_sockets;
2601 struct pollfd *listening_socket_fds;
2602 unsigned int num_listening_sockets;
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)
2627 struct socket *client_socks;
2628 void **client_wait_events;
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
2695struct mg_connection {
2696 int connection_type; /* see CONNECTION_TYPE_* above */
2697
2698 struct mg_request_info request_info;
2699 struct mg_response_info response_info;
2700
2701 struct mg_context *phys_ctx;
2702 struct mg_domain_context *dom_ctx;
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 {
2761 struct mg_connection *conn;
2762 char *file_name;
2763 struct mg_file_stat file;
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
2898struct posix_event {
2899 pthread_mutex_t mutex;
2900 pthread_cond_t cond;
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
3052open_file_in_memory(const struct mg_connection *conn,
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
3231mg_fclose(struct mg_file_access *fileacc)
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 *
3436mg_get_context(const struct mg_connection *conn)
3437{
3438 return (conn == NULL) ? (struct mg_context *)NULL : (conn->phys_ctx);
3439}
3440
3441
3442void *
3443mg_get_user_data(const struct mg_context *ctx)
3444{
3445 return (ctx == NULL) ? NULL : ctx->user_data;
3446}
3447
3448
3449void
3450mg_set_user_connection_data(struct mg_connection *conn, void *data)
3451{
3452 if (conn != NULL) {
3453 conn->request_info.conn_data = data;
3454 }
3455}
3456
3457
3458void *
3459mg_get_user_connection_data(const struct mg_connection *conn)
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
3493mg_get_server_ports(const struct mg_context *ctx,
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
3614mg_cry_internal_impl(const struct mg_connection *conn,
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,
3656 conn->dom_ctx->config[ERROR_LOG_FILE],
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: ",
3679 conn->request_info.request_method,
3680 conn->request_info.request_uri
3681 ? conn->request_info.request_uri
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
3699mg_cry_internal_wrap(const struct mg_connection *conn,
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 *
3745mg_get_request_info(const struct mg_connection *conn)
3746{
3747 if (!conn) {
3748 return NULL;
3749 }
3750#if defined(MG_ALLOW_USING_GET_REQUEST_INFO_FOR_RESPONSE)
3751 if (conn->connection_type == CONNECTION_TYPE_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 =
3768 conn->response_info.num_headers;
3769 memcpy(((struct mg_connection *)conn)->request_info.http_headers,
3770 conn->response_info.http_headers,
3771 sizeof(conn->response_info.http_headers));
3772 } else
3773#endif
3774 if (conn->connection_type != CONNECTION_TYPE_REQUEST) {
3775 return NULL;
3776 }
3777 return &conn->request_info;
3778}
3779
3780
3781const struct mg_response_info *
3782mg_get_response_info(const struct mg_connection *conn)
3783{
3784 if (!conn) {
3785 return NULL;
3786 }
3787 if (conn->connection_type != CONNECTION_TYPE_RESPONSE) {
3788 return NULL;
3789 }
3790 return &conn->response_info;
3791}
3792
3793
3794static const char *
3795get_proto_name(const struct mg_connection *conn)
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 =
3868 conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK]
3869 && (!mg_strcasecmp(
3870 conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes"));
3871 const char *server_domain =
3872 conn->dom_ctx->config[AUTHENTICATION_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
4022 if (conn->connection_type == CONNECTION_TYPE_REQUEST) {
4023 return get_header(conn->request_info.http_headers,
4024 conn->request_info.num_headers,
4025 name);
4026 }
4027 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
4028 return get_header(conn->response_info.http_headers,
4029 conn->response_info.num_headers,
4030 name);
4031 }
4032 return NULL;
4033}
4034
4035
4036static const char *
4037get_http_version(const struct mg_connection *conn)
4038{
4039 if (!conn) {
4040 return NULL;
4041 }
4042
4043 if (conn->connection_type == CONNECTION_TYPE_REQUEST) {
4044 return conn->request_info.http_version;
4045 }
4046 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
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
4182should_keep_alive(const struct mg_connection *conn)
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
4221should_decode_url(const struct mg_connection *conn)
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 *
4232suggest_connection_header(const struct mg_connection *conn)
4233{
4234 return should_keep_alive(conn) ? "keep-alive" : "close";
4235}
4236
4237
4238static int
4239send_no_cache_header(struct mg_connection *conn)
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
4251send_static_cache_header(struct mg_connection *conn)
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
4282send_additional_header(struct mg_connection *conn)
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
4511mg_send_http_error_impl(struct mg_connection *conn,
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
4701mg_send_http_ok(struct mg_connection *conn,
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
4739mg_send_http_redirect(struct mg_connection *conn,
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;
5632 struct mg_file file = STRUCT_FILE_INITIALIZER;
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
5903spawn_process(struct mg_connection *conn,
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
6108push_inner(struct mg_context *ctx,
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
6254push_all(struct mg_context *ctx,
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
6533discard_unread_request_data(struct mg_connection *conn)
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
6641mg_getc(struct mg_connection *conn)
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
6819mg_send_chunk(struct mg_connection *conn,
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
7240is_put_or_delete_method(const struct mg_connection *conn)
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)
7260 if (match_prefix(conn->dom_ctx->config[CGI_EXTENSIONS],
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
7296substitute_index_file(struct mg_connection *conn,
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 =
7539 !mg_strcasecmp(conn->dom_ctx->config[ALLOW_INDEX_SCRIPT_SUB_RES],
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
7944 vec->ptr = mg_get_builtin_mime_type(path);
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
8034open_auth_file(struct mg_connection *conn,
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
8114parse_auth_header(struct mg_connection *conn,
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) {
8216 conn->request_info.remote_user =
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
8277struct read_auth_file_struct {
8278 struct mg_connection *conn;
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
8289read_auth_file(struct mg_file *filep,
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)) {
8386 return check_password(workdata->conn->request_info.request_method,
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 {
8422 workdata.domain = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
8423 }
8424
8425 return read_auth_file(filep, &workdata, INITIAL_DEPTH);
8426}
8427
8428
8429/* Public function to check http digest authentication header */
8430int
8431mg_check_digest_access_authentication(struct mg_connection *conn,
8432 const char *realm,
8433 const char *filename)
8434{
8435 struct mg_file file = STRUCT_FILE_INITIALIZER;
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;
8460 struct mg_file file = STRUCT_FILE_INITIALIZER;
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
8559is_authorized_for_put(struct mg_connection *conn)
8560{
8561 if (conn) {
8562 struct mg_file file = STRUCT_FILE_INITIALIZER;
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
8995print_dir_entry(struct de *de)
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) {
9013 mg_snprintf(de->conn,
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) {
9023 mg_snprintf(de->conn,
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) {
9030 mg_snprintf(de->conn,
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) {
9037 mg_snprintf(de->conn,
9038 NULL, /* Buffer is big enough */
9039 size,
9040 sizeof(size),
9041 "%.1fM",
9042 (double)de->file.size / 1048576);
9043 } else {
9044 mg_snprintf(de->conn,
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",
9071 de->conn->request_info.local_uri,
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
9138scan_directory(struct mg_connection *conn,
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)) {
9177 mg_cry_internal(conn,
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)) {
9232 mg_cry_internal(conn,
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
9261struct dir_scan_data {
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 {
9295 dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
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
9306handle_directory_request(struct mg_connection *conn, const char *dir)
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
9387send_file_data(struct mg_connection *conn,
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
9545handle_static_file_request(struct mg_connection *conn,
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)
9673 if (filep->stat.size < MG_FILE_COMPRESSION_SIZE_LIMIT) {
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: ";
9688 cors2 = conn->dom_ctx->config[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{
9778 struct mg_file file = STRUCT_FILE_INITIALIZER;
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
9792is_not_modified(const struct mg_connection *conn,
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,
9824 mg_get_response_code_text(conn, 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
9848mg_send_mime_file(struct mg_connection *conn,
9849 const char *path,
9850 const char *mime_type)
9851{
9852 mg_send_mime_file2(conn, path, mime_type, NULL);
9853}
9854
9855
9856void
9857mg_send_mime_file2(struct mg_connection *conn,
9858 const char *path,
9859 const char *mime_type,
9860 const char *additional_headers)
9861{
9862 struct mg_file file = STRUCT_FILE_INITIALIZER;
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) {
9877 if (!mg_strcasecmp(conn->dom_ctx->config[ENABLE_DIRECTORY_LISTING],
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;
9907 struct mg_file file = STRUCT_FILE_INITIALIZER;
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
10108struct mg_http_method_info {
10109 const char *name;
10110 int request_has_body;
10111 int response_has_body;
10112 int is_safe;
10113 int is_idempotent;
10114 int is_cacheable;
10115};
10116
10117
10118/* https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods */
10119static struct mg_http_method_info 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. */
10602struct cgi_environment {
10603 struct mg_connection *conn;
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
10692prepare_cgi_environment(struct mg_connection *conn,
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;
10706 env->buflen = CGI_ENVIRONMENT_SIZE;
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 }
10715 env->varlen = MAX_CGI_ENVIR_VARS;
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",
10785 conn->dom_ctx->config[DOCUMENT_ROOT],
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,
10872 conn->request_info.http_headers[i].value);
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 */
10889struct process_control_data {
10890 pid_t pid;
10891 int references;
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)) {
11296 mg_cry_internal(conn,
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);
11324 mg_printf(conn,
11325 "HTTP/1.1 %d Created\r\n"
11326 "Date: %s\r\n",
11327 conn->status_code,
11328 date);
11331 mg_printf(conn,
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{
11356 struct mg_file file = STRUCT_FILE_INITIALIZER;
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,
11418 mg_get_response_code_text(NULL, 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,
11492 mg_get_response_code_text(NULL, 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 */
11511 mg_send_http_error(conn,
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). */
11559 mg_send_http_error(conn,
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
11574do_ssi_include(struct mg_connection *conn,
11575 const char *ssi,
11576 char *tag,
11577 int include_level)
11578{
11579 char file_name[MG_BUF_LEN], path[512], *p;
11580 struct mg_file file = STRUCT_FILE_INITIALIZER;
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",
11599 conn->dom_ctx->config[DOCUMENT_ROOT],
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);
11646 if (match_prefix(conn->dom_ctx->config[SSI_EXTENSIONS],
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] = "";
11664 struct mg_file file = STRUCT_FILE_INITIALIZER;
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
11707send_ssi_file(struct mg_connection *conn,
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
11813handle_ssi_file_request(struct mg_connection *conn,
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: ";
11828 cors2 = conn->dom_ctx->config[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
11867send_options(struct mg_connection *conn)
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
11899print_props(struct mg_connection *conn,
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
11966handle_propfind(struct mg_connection *conn,
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
12003 && !mg_strcasecmp(conn->dom_ctx->config[ENABLE_DIRECTORY_LISTING],
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
12014mg_lock_connection(struct mg_connection *conn)
12015{
12016 if (conn) {
12017 (void)pthread_mutex_lock(&conn->mutex);
12018 }
12019}
12020
12021void
12022mg_unlock_connection(struct mg_connection *conn)
12023{
12024 if (conn) {
12025 (void)pthread_mutex_unlock(&conn->mutex);
12026 }
12027}
12028
12029void
12030mg_lock_context(struct mg_context *ctx)
12031{
12032 if (ctx) {
12033 (void)pthread_mutex_lock(&ctx->nonce_mutex);
12034 }
12035}
12036
12037void
12038mg_unlock_context(struct mg_context *ctx)
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#define SHA_API static
12058#include "sha1.inl"
12059#endif
12060
12061static int
12062send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
12063{
12064 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
12065 char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
12066 SHA_CTX sha_ctx;
12067 int truncated;
12068
12069 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
12070 mg_snprintf(conn, &truncated, buf, sizeof(buf), "%s%s", websock_key, magic);
12071 if (truncated) {
12072 conn->must_close = 1;
12073 return 0;
12074 }
12075
12076 DEBUG_TRACE("%s", "Send websocket handshake");
12077
12078 SHA1_Init(&sha_ctx);
12079 SHA1_Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
12080 SHA1_Final((unsigned char *)sha, &sha_ctx);
12081 base64_encode((unsigned char *)sha, sizeof(sha), b64_sha);
12082 mg_printf(conn,
12083 "HTTP/1.1 101 Switching Protocols\r\n"
12084 "Upgrade: websocket\r\n"
12085 "Connection: Upgrade\r\n"
12086 "Sec-WebSocket-Accept: %s\r\n",
12087 b64_sha);
12088 if (conn->request_info.acceptedWebSocketSubprotocol) {
12089 mg_printf(conn,
12090 "Sec-WebSocket-Protocol: %s\r\n\r\n",
12091 conn->request_info.acceptedWebSocketSubprotocol);
12092 } else {
12093 mg_printf(conn, "%s", "\r\n");
12094 }
12095
12096 return 1;
12097}
12098
12099
12100#if !defined(MG_MAX_UNANSWERED_PING)
12101/* Configuration of the maximum number of websocket PINGs that might
12102 * stay unanswered before the connection is considered broken.
12103 * Note: The name of this define may still change (until it is
12104 * defined as a compile parameter in a documentation).
12105 */
12106#define MG_MAX_UNANSWERED_PING (5)
12107#endif
12108
12109
12110static void
12111read_websocket(struct mg_connection *conn,
12112 mg_websocket_data_handler ws_data_handler,
12113 void *callback_data)
12114{
12115 /* Pointer to the beginning of the portion of the incoming websocket
12116 * message queue.
12117 * The original websocket upgrade request is never removed, so the queue
12118 * begins after it. */
12119 unsigned char *buf = (unsigned char *)conn->buf + conn->request_len;
12120 int n, error, exit_by_callback;
12121 int ret;
12122
12123 /* body_len is the length of the entire queue in bytes
12124 * len is the length of the current message
12125 * data_len is the length of the current message's data payload
12126 * header_len is the length of the current message's header */
12127 size_t i, len, mask_len = 0, header_len, body_len;
12128 uint64_t data_len = 0;
12129
12130 /* "The masking key is a 32-bit value chosen at random by the client."
12131 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
12132 */
12133 unsigned char mask[4];
12134
12135 /* data points to the place where the message is stored when passed to
12136 * the websocket_data callback. This is either mem on the stack, or a
12137 * dynamically allocated buffer if it is too large. */
12138 unsigned char mem[4096];
12139 unsigned char mop; /* mask flag and opcode */
12140
12141
12142 /* Variables used for connection monitoring */
12143 double timeout = -1.0;
12144 int enable_ping_pong = 0;
12145 int ping_count = 0;
12146
12147 if (conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG]) {
12148 enable_ping_pong =
12149 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG],
12150 "yes");
12151 }
12152
12153 if (conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) {
12154 timeout = atoi(conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
12155 }
12156 if ((timeout <= 0.0) && (conn->dom_ctx->config[REQUEST_TIMEOUT])) {
12157 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
12158 }
12159
12160 /* Enter data processing loop */
12161 DEBUG_TRACE("Websocket connection %s:%u start data processing loop",
12162 conn->request_info.remote_addr,
12163 conn->request_info.remote_port);
12164 conn->in_websocket_handling = 1;
12165 mg_set_thread_name("wsock");
12166
12167 /* Loop continuously, reading messages from the socket, invoking the
12168 * callback, and waiting repeatedly until an error occurs. */
12169 while (!conn->phys_ctx->stop_flag && !conn->must_close) {
12170 header_len = 0;
12171 DEBUG_ASSERT(conn->data_len >= conn->request_len);
12172 if ((body_len = (size_t)(conn->data_len - conn->request_len)) >= 2) {
12173 len = buf[1] & 127;
12174 mask_len = (buf[1] & 128) ? 4 : 0;
12175 if ((len < 126) && (body_len >= mask_len)) {
12176 /* inline 7-bit length field */
12177 data_len = len;
12178 header_len = 2 + mask_len;
12179 } else if ((len == 126) && (body_len >= (4 + mask_len))) {
12180 /* 16-bit length field */
12181 header_len = 4 + mask_len;
12182 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
12183 } else if (body_len >= (10 + mask_len)) {
12184 /* 64-bit length field */
12185 uint32_t l1, l2;
12186 memcpy(&l1, &buf[2], 4); /* Use memcpy for alignment */
12187 memcpy(&l2, &buf[6], 4);
12188 header_len = 10 + mask_len;
12189 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
12190
12191 if (data_len > (uint64_t)0x7FFF0000ul) {
12192 /* no can do */
12194 conn,
12195 "%s",
12196 "websocket out of memory; closing connection");
12197 break;
12198 }
12199 }
12200 }
12201
12202 if ((header_len > 0) && (body_len >= header_len)) {
12203 /* Allocate space to hold websocket payload */
12204 unsigned char *data = mem;
12205
12206 if ((size_t)data_len > (size_t)sizeof(mem)) {
12207 data = (unsigned char *)mg_malloc_ctx((size_t)data_len,
12208 conn->phys_ctx);
12209 if (data == NULL) {
12210 /* Allocation failed, exit the loop and then close the
12211 * connection */
12213 conn,
12214 "%s",
12215 "websocket out of memory; closing connection");
12216 break;
12217 }
12218 }
12219
12220 /* Copy the mask before we shift the queue and destroy it */
12221 if (mask_len > 0) {
12222 memcpy(mask, buf + header_len - mask_len, sizeof(mask));
12223 } else {
12224 memset(mask, 0, sizeof(mask));
12225 }
12226
12227 /* Read frame payload from the first message in the queue into
12228 * data and advance the queue by moving the memory in place. */
12229 DEBUG_ASSERT(body_len >= header_len);
12230 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
12231 mop = buf[0]; /* current mask and opcode */
12232 /* Overflow case */
12233 len = body_len - header_len;
12234 memcpy(data, buf + header_len, len);
12235 error = 0;
12236 while ((uint64_t)len < data_len) {
12237 n = pull_inner(NULL,
12238 conn,
12239 (char *)(data + len),
12240 (int)(data_len - len),
12241 timeout);
12242 if (n <= -2) {
12243 error = 1;
12244 break;
12245 } else if (n > 0) {
12246 len += (size_t)n;
12247 } else {
12248 /* Timeout: should retry */
12249 /* TODO: retry condition */
12250 }
12251 }
12252 if (error) {
12254 conn,
12255 "%s",
12256 "Websocket pull failed; closing connection");
12257 if (data != mem) {
12258 mg_free(data);
12259 }
12260 break;
12261 }
12262
12263 conn->data_len = conn->request_len;
12264
12265 } else {
12266
12267 mop = buf[0]; /* current mask and opcode, overwritten by
12268 * memmove() */
12269
12270 /* Length of the message being read at the front of the
12271 * queue. Cast to 31 bit is OK, since we limited
12272 * data_len before. */
12273 len = (size_t)data_len + header_len;
12274
12275 /* Copy the data payload into the data pointer for the
12276 * callback. Cast to 31 bit is OK, since we
12277 * limited data_len */
12278 memcpy(data, buf + header_len, (size_t)data_len);
12279
12280 /* Move the queue forward len bytes */
12281 memmove(buf, buf + len, body_len - len);
12282
12283 /* Mark the queue as advanced */
12284 conn->data_len -= (int)len;
12285 }
12286
12287 /* Apply mask if necessary */
12288 if (mask_len > 0) {
12289 for (i = 0; i < (size_t)data_len; i++) {
12290 data[i] ^= mask[i & 3];
12291 }
12292 }
12293
12294 exit_by_callback = 0;
12295 if (enable_ping_pong && ((mop & 0xF) == MG_WEBSOCKET_OPCODE_PONG)) {
12296 /* filter PONG messages */
12297 DEBUG_TRACE("PONG from %s:%u",
12298 conn->request_info.remote_addr,
12299 conn->request_info.remote_port);
12300 /* No unanwered PINGs left */
12301 ping_count = 0;
12302 } else if (enable_ping_pong
12303 && ((mop & 0xF) == MG_WEBSOCKET_OPCODE_PING)) {
12304 /* reply PING messages */
12305 DEBUG_TRACE("Reply PING from %s:%u",
12306 conn->request_info.remote_addr,
12307 conn->request_info.remote_port);
12308 ret = mg_websocket_write(conn,
12310 (char *)data,
12311 (size_t)data_len);
12312 if (ret <= 0) {
12313 /* Error: send failed */
12314 DEBUG_TRACE("Reply PONG failed (%i)", ret);
12315 break;
12316 }
12317
12318
12319 } else {
12320 /* Exit the loop if callback signals to exit (server side),
12321 * or "connection close" opcode received (client side). */
12322 if ((ws_data_handler != NULL)
12323 && !ws_data_handler(conn,
12324 mop,
12325 (char *)data,
12326 (size_t)data_len,
12327 callback_data)) {
12328 exit_by_callback = 1;
12329 }
12330 }
12331
12332 /* It a buffer has been allocated, free it again */
12333 if (data != mem) {
12334 mg_free(data);
12335 }
12336
12337 if (exit_by_callback) {
12338 DEBUG_TRACE("Callback requests to close connection from %s:%u",
12339 conn->request_info.remote_addr,
12340 conn->request_info.remote_port);
12341 break;
12342 }
12343 if ((mop & 0xf) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) {
12344 /* Opcode == 8, connection close */
12345 DEBUG_TRACE("Message requests to close connection from %s:%u",
12346 conn->request_info.remote_addr,
12347 conn->request_info.remote_port);
12348 break;
12349 }
12350
12351 /* Not breaking the loop, process next websocket frame. */
12352 } else {
12353 /* Read from the socket into the next available location in the
12354 * message queue. */
12355 n = pull_inner(NULL,
12356 conn,
12357 conn->buf + conn->data_len,
12358 conn->buf_size - conn->data_len,
12359 timeout);
12360 if (n <= -2) {
12361 /* Error, no bytes read */
12362 DEBUG_TRACE("PULL from %s:%u failed",
12363 conn->request_info.remote_addr,
12364 conn->request_info.remote_port);
12365 break;
12366 }
12367 if (n > 0) {
12368 conn->data_len += n;
12369 /* Reset open PING count */
12370 ping_count = 0;
12371 } else {
12372 if (!conn->phys_ctx->stop_flag && !conn->must_close) {
12373 if (ping_count > MG_MAX_UNANSWERED_PING) {
12374 /* Stop sending PING */
12375 DEBUG_TRACE("Too many (%i) unanswered ping from %s:%u "
12376 "- closing connection",
12377 ping_count,
12378 conn->request_info.remote_addr,
12379 conn->request_info.remote_port);
12380 break;
12381 }
12382 if (enable_ping_pong) {
12383 /* Send Websocket PING message */
12384 DEBUG_TRACE("PING to %s:%u",
12385 conn->request_info.remote_addr,
12386 conn->request_info.remote_port);
12387 ret = mg_websocket_write(conn,
12389 NULL,
12390 0);
12391
12392 if (ret <= 0) {
12393 /* Error: send failed */
12394 DEBUG_TRACE("Send PING failed (%i)", ret);
12395 break;
12396 }
12397 ping_count++;
12398 }
12399 }
12400 /* Timeout: should retry */
12401 /* TODO: get timeout def */
12402 }
12403 }
12404 }
12405
12406 /* Leave data processing loop */
12407 mg_set_thread_name("worker");
12408 conn->in_websocket_handling = 0;
12409 DEBUG_TRACE("Websocket connection %s:%u left data processing loop",
12410 conn->request_info.remote_addr,
12411 conn->request_info.remote_port);
12412}
12413
12414
12415static int
12416mg_websocket_write_exec(struct mg_connection *conn,
12417 int opcode,
12418 const char *data,
12419 size_t dataLen,
12420 uint32_t masking_key)
12421{
12422 unsigned char header[14];
12423 size_t headerLen;
12424 int retval;
12425
12426#if defined(GCC_DIAGNOSTIC)
12427/* Disable spurious conversion warning for GCC */
12428#pragma GCC diagnostic push
12429#pragma GCC diagnostic ignored "-Wconversion"
12430#endif
12431
12432 header[0] = 0x80u | (unsigned char)((unsigned)opcode & 0xf);
12433
12434#if defined(GCC_DIAGNOSTIC)
12435#pragma GCC diagnostic pop
12436#endif
12437
12438 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
12439 if (dataLen < 126) {
12440 /* inline 7-bit length field */
12441 header[1] = (unsigned char)dataLen;
12442 headerLen = 2;
12443 } else if (dataLen <= 0xFFFF) {
12444 /* 16-bit length field */
12445 uint16_t len = htons((uint16_t)dataLen);
12446 header[1] = 126;
12447 memcpy(header + 2, &len, 2);
12448 headerLen = 4;
12449 } else {
12450 /* 64-bit length field */
12451 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
12452 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
12453 header[1] = 127;
12454 memcpy(header + 2, &len1, 4);
12455 memcpy(header + 6, &len2, 4);
12456 headerLen = 10;
12457 }
12458
12459 if (masking_key) {
12460 /* add mask */
12461 header[1] |= 0x80;
12462 memcpy(header + headerLen, &masking_key, 4);
12463 headerLen += 4;
12464 }
12465
12466 /* Note that POSIX/Winsock's send() is threadsafe
12467 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
12468 * but mongoose's mg_printf/mg_write is not (because of the loop in
12469 * push(), although that is only a problem if the packet is large or
12470 * outgoing buffer is full). */
12471
12472 /* TODO: Check if this lock should be moved to user land.
12473 * Currently the server sets this lock for websockets, but
12474 * not for any other connection. It must be set for every
12475 * conn read/written by more than one thread, no matter if
12476 * it is a websocket or regular connection. */
12477 (void)mg_lock_connection(conn);
12478
12479 retval = mg_write(conn, header, headerLen);
12480 if (retval != (int)headerLen) {
12481 /* Did not send complete header */
12482 retval = -1;
12483 } else {
12484 if (dataLen > 0) {
12485 retval = mg_write(conn, data, dataLen);
12486 }
12487 /* if dataLen == 0, the header length (2) is returned */
12488 }
12489
12490 /* TODO: Remove this unlock as well, when lock is removed. */
12492
12493 return retval;
12494}
12495
12496int
12497mg_websocket_write(struct mg_connection *conn,
12498 int opcode,
12499 const char *data,
12500 size_t dataLen)
12501{
12502 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
12503}
12504
12505
12506static void
12507mask_data(const char *in, size_t in_len, uint32_t masking_key, char *out)
12508{
12509 size_t i = 0;
12510
12511 i = 0;
12512 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
12513 /* Convert in 32 bit words, if data is 4 byte aligned */
12514 while (i < (in_len - 3)) {
12515 *(uint32_t *)(void *)(out + i) =
12516 *(uint32_t *)(void *)(in + i) ^ masking_key;
12517 i += 4;
12518 }
12519 }
12520 if (i != in_len) {
12521 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
12522 while (i < in_len) {
12523 *(uint8_t *)(void *)(out + i) =
12524 *(uint8_t *)(void *)(in + i)
12525 ^ *(((uint8_t *)&masking_key) + (i % 4));
12526 i++;
12527 }
12528 }
12529}
12530
12531
12532int
12533mg_websocket_client_write(struct mg_connection *conn,
12534 int opcode,
12535 const char *data,
12536 size_t dataLen)
12537{
12538 int retval = -1;
12539 char *masked_data =
12540 (char *)mg_malloc_ctx(((dataLen + 7) / 4) * 4, conn->phys_ctx);
12541 uint32_t masking_key = 0;
12542
12543 if (masked_data == NULL) {
12544 /* Return -1 in an error case */
12545 mg_cry_internal(conn,
12546 "%s",
12547 "Cannot allocate buffer for masked websocket response: "
12548 "Out of memory");
12549 return -1;
12550 }
12551
12552 do {
12553 /* Get a masking key - but not 0 */
12554 masking_key = (uint32_t)get_random();
12555 } while (masking_key == 0);
12556
12557 mask_data(data, dataLen, masking_key, masked_data);
12558
12559 retval = mg_websocket_write_exec(
12560 conn, opcode, masked_data, dataLen, masking_key);
12561 mg_free(masked_data);
12562
12563 return retval;
12564}
12565
12566
12567static void
12568handle_websocket_request(struct mg_connection *conn,
12569 const char *path,
12570 int is_callback_resource,
12571 struct mg_websocket_subprotocols *subprotocols,
12572 mg_websocket_connect_handler ws_connect_handler,
12573 mg_websocket_ready_handler ws_ready_handler,
12574 mg_websocket_data_handler ws_data_handler,
12575 mg_websocket_close_handler ws_close_handler,
12576 void *cbData)
12577{
12578 const char *websock_key = mg_get_header(conn, "Sec-WebSocket-Key");
12579 const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
12580 ptrdiff_t lua_websock = 0;
12581
12582#if !defined(USE_LUA)
12583 (void)path;
12584#endif
12585
12586 /* Step 1: Check websocket protocol version. */
12587 /* Step 1.1: Check Sec-WebSocket-Key. */
12588 if (!websock_key) {
12589 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
12590 * requires a Sec-WebSocket-Key header.
12591 */
12592 /* It could be the hixie draft version
12593 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
12594 */
12595 const char *key1 = mg_get_header(conn, "Sec-WebSocket-Key1");
12596 const char *key2 = mg_get_header(conn, "Sec-WebSocket-Key2");
12597 char key3[8];
12598
12599 if ((key1 != NULL) && (key2 != NULL)) {
12600 /* This version uses 8 byte body data in a GET request */
12601 conn->content_len = 8;
12602 if (8 == mg_read(conn, key3, 8)) {
12603 /* This is the hixie version */
12604 mg_send_http_error(conn,
12605 426,
12606 "%s",
12607 "Protocol upgrade to RFC 6455 required");
12608 return;
12609 }
12610 }
12611 /* This is an unknown version */
12612 mg_send_http_error(conn, 400, "%s", "Malformed websocket request");
12613 return;
12614 }
12615
12616 /* Step 1.2: Check websocket protocol version. */
12617 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
12618 if ((version == NULL) || (strcmp(version, "13") != 0)) {
12619 /* Reject wrong versions */
12620 mg_send_http_error(conn, 426, "%s", "Protocol upgrade required");
12621 return;
12622 }
12623
12624 /* Step 1.3: Could check for "Host", but we do not really nead this
12625 * value for anything, so just ignore it. */
12626
12627 /* Step 2: If a callback is responsible, call it. */
12628 if (is_callback_resource) {
12629 /* Step 2.1 check and select subprotocol */
12630 const char *protocols[64]; // max 64 headers
12631 int nbSubprotocolHeader = get_req_headers(&conn->request_info,
12632 "Sec-WebSocket-Protocol",
12633 protocols,
12634 64);
12635 if ((nbSubprotocolHeader > 0) && subprotocols) {
12636 int cnt = 0;
12637 int idx;
12638 unsigned long len;
12639 const char *sep, *curSubProtocol,
12640 *acceptedWebSocketSubprotocol = NULL;
12641
12642
12643 /* look for matching subprotocol */
12644 do {
12645 const char *protocol = protocols[cnt];
12646
12647 do {
12648 sep = strchr(protocol, ',');
12649 curSubProtocol = protocol;
12650 len = sep ? (unsigned long)(sep - protocol)
12651 : (unsigned long)strlen(protocol);
12652 while (sep && isspace(*++sep))
12653 ; // ignore leading whitespaces
12654 protocol = sep;
12655
12656
12657 for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
12658 if ((strlen(subprotocols->subprotocols[idx]) == len)
12659 && (strncmp(curSubProtocol,
12660 subprotocols->subprotocols[idx],
12661 len)
12662 == 0)) {
12663 acceptedWebSocketSubprotocol =
12664 subprotocols->subprotocols[idx];
12665 break;
12666 }
12667 }
12668 } while (sep && !acceptedWebSocketSubprotocol);
12669 } while (++cnt < nbSubprotocolHeader
12670 && !acceptedWebSocketSubprotocol);
12671
12672 conn->request_info.acceptedWebSocketSubprotocol =
12673 acceptedWebSocketSubprotocol;
12674
12675 } else if (nbSubprotocolHeader > 0) {
12676 /* keep legacy behavior */
12677 const char *protocol = protocols[0];
12678
12679 /* The protocol is a comma separated list of names. */
12680 /* The server must only return one value from this list. */
12681 /* First check if it is a list or just a single value. */
12682 const char *sep = strrchr(protocol, ',');
12683 if (sep == NULL) {
12684 /* Just a single protocol -> accept it. */
12685 conn->request_info.acceptedWebSocketSubprotocol = protocol;
12686 } else {
12687 /* Multiple protocols -> accept the last one. */
12688 /* This is just a quick fix if the client offers multiple
12689 * protocols. The handler should have a list of accepted
12690 * protocols on his own
12691 * and use it to select one protocol among those the client
12692 * has
12693 * offered.
12694 */
12695 while (isspace(*++sep)) {
12696 ; /* ignore leading whitespaces */
12697 }
12698 conn->request_info.acceptedWebSocketSubprotocol = sep;
12699 }
12700 }
12701
12702 if ((ws_connect_handler != NULL)
12703 && (ws_connect_handler(conn, cbData) != 0)) {
12704 /* C callback has returned non-zero, do not proceed with
12705 * handshake.
12706 */
12707 /* Note that C callbacks are no longer called when Lua is
12708 * responsible, so C can no longer filter callbacks for Lua. */
12709 return;
12710 }
12711 }
12712
12713#if defined(USE_LUA)
12714 /* Step 3: No callback. Check if Lua is responsible. */
12715 else {
12716 /* Step 3.1: Check if Lua is responsible. */
12717 if (conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
12718 lua_websock = match_prefix(
12719 conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS],
12720 strlen(conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
12721 path);
12722 }
12723
12724 if (lua_websock) {
12725 /* Step 3.2: Lua is responsible: call it. */
12726 conn->lua_websocket_state = lua_websocket_new(path, conn);
12727 if (!conn->lua_websocket_state) {
12728 /* Lua rejected the new client */
12729 return;
12730 }
12731 }
12732 }
12733#endif
12734
12735 /* Step 4: Check if there is a responsible websocket handler. */
12736 if (!is_callback_resource && !lua_websock) {
12737 /* There is no callback, and Lua is not responsible either. */
12738 /* Reply with a 404 Not Found. We are still at a standard
12739 * HTTP request here, before the websocket handshake, so
12740 * we can still send standard HTTP error replies. */
12741 mg_send_http_error(conn, 404, "%s", "Not found");
12742 return;
12743 }
12744
12745 /* Step 5: The websocket connection has been accepted */
12746 if (!send_websocket_handshake(conn, websock_key)) {
12747 mg_send_http_error(conn, 500, "%s", "Websocket handshake failed");
12748 return;
12749 }
12750
12751 /* Step 6: Call the ready handler */
12752 if (is_callback_resource) {
12753 if (ws_ready_handler != NULL) {
12754 ws_ready_handler(conn, cbData);
12755 }
12756#if defined(USE_LUA)
12757 } else if (lua_websock) {
12758 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
12759 /* the ready handler returned false */
12760 return;
12761 }
12762#endif
12763 }
12764
12765 /* Step 7: Enter the read loop */
12766 if (is_callback_resource) {
12767 read_websocket(conn, ws_data_handler, cbData);
12768#if defined(USE_LUA)
12769 } else if (lua_websock) {
12770 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
12771#endif
12772 }
12773
12774 /* Step 8: Call the close handler */
12775 if (ws_close_handler) {
12776 ws_close_handler(conn, cbData);
12777 }
12778}
12779
12780
12781static int
12782is_websocket_protocol(const struct mg_connection *conn)
12783{
12784 const char *upgrade, *connection;
12785
12786 /* A websocket protocoll has the following HTTP headers:
12787 *
12788 * Connection: Upgrade
12789 * Upgrade: Websocket
12790 */
12791
12792 upgrade = mg_get_header(conn, "Upgrade");
12793 if (upgrade == NULL) {
12794 return 0; /* fail early, don't waste time checking other header
12795 * fields
12796 */
12797 }
12798 if (!mg_strcasestr(upgrade, "websocket")) {
12799 return 0;
12800 }
12801
12802 connection = mg_get_header(conn, "Connection");
12803 if (connection == NULL) {
12804 return 0;
12805 }
12806 if (!mg_strcasestr(connection, "upgrade")) {
12807 return 0;
12808 }
12809
12810 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
12811 * "Sec-WebSocket-Version" are also required.
12812 * Don't check them here, since even an unsupported websocket protocol
12813 * request still IS a websocket request (in contrast to a standard HTTP
12814 * request). It will fail later in handle_websocket_request.
12815 */
12816
12817 return 1;
12818}
12819#endif /* !USE_WEBSOCKET */
12820
12821
12822static int
12824{
12825 return (n >= 0) && (n <= 255);
12826}
12827
12828
12829static int
12830parse_net(const char *spec, uint32_t *net, uint32_t *mask)
12831{
12832 int n, a, b, c, d, slash = 32, len = 0;
12833
12834 if (((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5)
12835 || (sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4))
12836 && isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && (slash >= 0)
12837 && (slash < 33)) {
12838 len = n;
12839 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
12840 | (uint32_t)d;
12841 *mask = slash ? (0xffffffffU << (32 - slash)) : 0;
12842 }
12843
12844 return len;
12845}
12846
12847
12848static int
12849set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
12850{
12851 int throttle = 0;
12852 struct vec vec, val;
12853 uint32_t net, mask;
12854 char mult;
12855 double v;
12856
12857 while ((spec = next_option(spec, &vec, &val)) != NULL) {
12858 mult = ',';
12859 if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1)
12860 || (v < 0)
12861 || ((lowercase(&mult) != 'k') && (lowercase(&mult) != 'm')
12862 && (mult != ','))) {
12863 continue;
12864 }
12865 v *= (lowercase(&mult) == 'k')
12866 ? 1024
12867 : ((lowercase(&mult) == 'm') ? 1048576 : 1);
12868 if (vec.len == 1 && vec.ptr[0] == '*') {
12869 throttle = (int)v;
12870 } else if (parse_net(vec.ptr, &net, &mask) > 0) {
12871 if ((remote_ip & mask) == net) {
12872 throttle = (int)v;
12873 }
12874 } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
12875 throttle = (int)v;
12876 }
12877 }
12878
12879 return throttle;
12880}
12881
12882
12883static uint32_t
12884get_remote_ip(const struct mg_connection *conn)
12885{
12886 if (!conn) {
12887 return 0;
12888 }
12889 return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr);
12890}
12891
12892
12893/* The mg_upload function is superseeded by mg_handle_form_request. */
12894#include "handle_form.inl"
12895
12896
12897#if defined(MG_LEGACY_INTERFACE)
12898/* Implement the deprecated mg_upload function by calling the new
12899 * mg_handle_form_request function. While mg_upload could only handle
12900 * HTML forms sent as POST request in multipart/form-data format
12901 * containing only file input elements, mg_handle_form_request can
12902 * handle all form input elements and all standard request methods. */
12903struct mg_upload_user_data {
12904 struct mg_connection *conn;
12905 const char *destination_dir;
12906 int num_uploaded_files;
12907};
12908
12909
12910/* Helper function for deprecated mg_upload. */
12911static int
12912mg_upload_field_found(const char *key,
12913 const char *filename,
12914 char *path,
12915 size_t pathlen,
12916 void *user_data)
12917{
12918 int truncated = 0;
12919 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
12920 (void)key;
12921
12922 if (!filename) {
12923 mg_cry_internal(fud->conn, "%s: No filename set", __func__);
12924 return FORM_FIELD_STORAGE_ABORT;
12925 }
12926 mg_snprintf(fud->conn,
12927 &truncated,
12928 path,
12929 pathlen - 1,
12930 "%s/%s",
12931 fud->destination_dir,
12932 filename);
12933 if (truncated) {
12934 mg_cry_internal(fud->conn, "%s: File path too long", __func__);
12935 return FORM_FIELD_STORAGE_ABORT;
12936 }
12937 return FORM_FIELD_STORAGE_STORE;
12938}
12939
12940
12941/* Helper function for deprecated mg_upload. */
12942static int
12943mg_upload_field_get(const char *key,
12944 const char *value,
12945 size_t value_size,
12946 void *user_data)
12947{
12948 /* Function should never be called */
12949 (void)key;
12950 (void)value;
12951 (void)value_size;
12952 (void)user_data;
12953
12954 return 0;
12955}
12956
12957
12958/* Helper function for deprecated mg_upload. */
12959static int
12960mg_upload_field_stored(const char *path, long long file_size, void *user_data)
12961{
12962 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
12963 (void)file_size;
12964
12965 fud->num_uploaded_files++;
12966 fud->conn->phys_ctx->callbacks.upload(fud->conn, path);
12967
12968 return 0;
12969}
12970
12971
12972/* Deprecated function mg_upload - use mg_handle_form_request instead. */
12973int
12974mg_upload(struct mg_connection *conn, const char *destination_dir)
12975{
12976 struct mg_upload_user_data fud = {conn, destination_dir, 0};
12977 struct mg_form_data_handler fdh = {mg_upload_field_found,
12978 mg_upload_field_get,
12979 mg_upload_field_stored,
12980 0};
12981 int ret;
12982
12983 fdh.user_data = (void *)&fud;
12984 ret = mg_handle_form_request(conn, &fdh);
12985
12986 if (ret < 0) {
12987 mg_cry_internal(conn, "%s: Error while parsing the request", __func__);
12988 }
12989
12990 return fud.num_uploaded_files;
12991}
12992#endif
12993
12994
12995static int
12996get_first_ssl_listener_index(const struct mg_context *ctx)
12997{
12998 unsigned int i;
12999 int idx = -1;
13000 if (ctx) {
13001 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
13002 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
13003 }
13004 }
13005 return idx;
13006}
13007
13008
13009/* Return host (without port) */
13010/* Use mg_free to free the result */
13011static const char *
13012alloc_get_host(struct mg_connection *conn)
13013{
13014 char buf[1025];
13015 size_t buflen = sizeof(buf);
13016 const char *host_header = get_header(conn->request_info.http_headers,
13017 conn->request_info.num_headers,
13018 "Host");
13019 char *host;
13020
13021 if (host_header != NULL) {
13022 char *pos;
13023
13024 /* Create a local copy of the "Host" header, since it might be
13025 * modified here. */
13026 mg_strlcpy(buf, host_header, buflen);
13027 buf[buflen - 1] = '\0';
13028 host = buf;
13029 while (isspace(*host)) {
13030 host++;
13031 }
13032
13033 /* If the "Host" is an IPv6 address, like [::1], parse until ]
13034 * is found. */
13035 if (*host == '[') {
13036 pos = strchr(host, ']');
13037 if (!pos) {
13038 /* Malformed hostname starts with '[', but no ']' found */
13039 DEBUG_TRACE("%s", "Host name format error '[' without ']'");
13040 return NULL;
13041 }
13042 /* terminate after ']' */
13043 pos[1] = 0;
13044 } else {
13045 /* Otherwise, a ':' separates hostname and port number */
13046 pos = strchr(host, ':');
13047 if (pos != NULL) {
13048 *pos = '\0';
13049 }
13050 }
13051
13052 if (conn->ssl) {
13053 /* This is a HTTPS connection, maybe we have a hostname
13054 * from SNI (set in ssl_servername_callback). */
13055 const char *sslhost = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
13056 if (sslhost && (conn->dom_ctx != &(conn->phys_ctx->dd))) {
13057 /* We are not using the default domain */
13058 if (mg_strcasecmp(host, sslhost)) {
13059 /* Mismatch between SNI domain and HTTP domain */
13060 DEBUG_TRACE("Host mismatch: SNI: %s, HTTPS: %s",
13061 sslhost,
13062 host);
13063 return NULL;
13064 }
13065 }
13066 DEBUG_TRACE("HTTPS Host: %s", host);
13067
13068 } else {
13069 struct mg_domain_context *dom = &(conn->phys_ctx->dd);
13070 while (dom) {
13071 if (!mg_strcasecmp(host, dom->config[AUTHENTICATION_DOMAIN])) {
13072
13073 /* Found matching domain */
13074 DEBUG_TRACE("HTTP domain %s found",
13075 dom->config[AUTHENTICATION_DOMAIN]);
13076
13077 /* TODO: Check if this is a HTTP or HTTPS domain */
13078 conn->dom_ctx = dom;
13079 break;
13080 }
13081 dom = dom->next;
13082 }
13083
13084 DEBUG_TRACE("HTTP Host: %s", host);
13085 }
13086
13087 } else {
13088 sockaddr_to_string(buf, buflen, &conn->client.lsa);
13089 host = buf;
13090
13091 DEBUG_TRACE("IP: %s", host);
13092 }
13093
13094 return mg_strdup_ctx(host, conn->phys_ctx);
13095}
13096
13097
13098static void
13099redirect_to_https_port(struct mg_connection *conn, int ssl_index)
13100{
13101 char target_url[MG_BUF_LEN];
13102 int truncated = 0;
13103
13104 conn->must_close = 1;
13105
13106 /* Send host, port, uri and (if it exists) ?query_string */
13107 if (conn->host) {
13108
13109 /* Use "308 Permanent Redirect" */
13110 int redirect_code = 308;
13111
13112 /* Create target URL */
13114 conn,
13115 &truncated,
13116 target_url,
13117 sizeof(target_url),
13118 "https://%s:%d%s%s%s",
13119
13120 conn->host,
13121#if defined(USE_IPV6)
13122 (conn->phys_ctx->listening_sockets[ssl_index].lsa.sa.sa_family
13123 == AF_INET6)
13124 ? (int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13125 .lsa.sin6.sin6_port)
13126 :
13127#endif
13128 (int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13129 .lsa.sin.sin_port),
13130 conn->request_info.local_uri,
13131 (conn->request_info.query_string == NULL) ? "" : "?",
13132 (conn->request_info.query_string == NULL)
13133 ? ""
13134 : conn->request_info.query_string);
13135
13136 /* Check overflow in location buffer (will not occur if MG_BUF_LEN
13137 * is used as buffer size) */
13138 if (truncated) {
13139 mg_send_http_error(conn, 500, "%s", "Redirect URL too long");
13140 return;
13141 }
13142
13143 /* Use redirect helper function */
13144 mg_send_http_redirect(conn, target_url, redirect_code);
13145 }
13146}
13147
13148
13149static void
13150handler_info_acquire(struct mg_handler_info *handler_info)
13151{
13152 pthread_mutex_lock(&handler_info->refcount_mutex);
13153 handler_info->refcount++;
13154 pthread_mutex_unlock(&handler_info->refcount_mutex);
13155}
13156
13157
13158static void
13159handler_info_release(struct mg_handler_info *handler_info)
13160{
13161 pthread_mutex_lock(&handler_info->refcount_mutex);
13162 handler_info->refcount--;
13163 pthread_cond_signal(&handler_info->refcount_cond);
13164 pthread_mutex_unlock(&handler_info->refcount_mutex);
13165}
13166
13167
13168static void
13169handler_info_wait_unused(struct mg_handler_info *handler_info)
13170{
13171 pthread_mutex_lock(&handler_info->refcount_mutex);
13172 while (handler_info->refcount) {
13173 pthread_cond_wait(&handler_info->refcount_cond,
13174 &handler_info->refcount_mutex);
13175 }
13176 pthread_mutex_unlock(&handler_info->refcount_mutex);
13177}
13178
13179
13180static void
13181mg_set_handler_type(struct mg_context *phys_ctx,
13182 struct mg_domain_context *dom_ctx,
13183 const char *uri,
13184 int handler_type,
13185 int is_delete_request,
13186 mg_request_handler handler,
13187 struct mg_websocket_subprotocols *subprotocols,
13188 mg_websocket_connect_handler connect_handler,
13189 mg_websocket_ready_handler ready_handler,
13190 mg_websocket_data_handler data_handler,
13191 mg_websocket_close_handler close_handler,
13192 mg_authorization_handler auth_handler,
13193 void *cbdata)
13194{
13195 struct mg_handler_info *tmp_rh, **lastref;
13196 size_t urilen = strlen(uri);
13197
13198 if (handler_type == WEBSOCKET_HANDLER) {
13199 DEBUG_ASSERT(handler == NULL);
13200 DEBUG_ASSERT(is_delete_request || connect_handler != NULL
13201 || ready_handler != NULL || data_handler != NULL
13202 || close_handler != NULL);
13203
13204 DEBUG_ASSERT(auth_handler == NULL);
13205 if (handler != NULL) {
13206 return;
13207 }
13208 if (!is_delete_request && (connect_handler == NULL)
13209 && (ready_handler == NULL) && (data_handler == NULL)
13210 && (close_handler == NULL)) {
13211 return;
13212 }
13213 if (auth_handler != NULL) {
13214 return;
13215 }
13216 } else if (handler_type == REQUEST_HANDLER) {
13217 DEBUG_ASSERT(connect_handler == NULL && ready_handler == NULL
13218 && data_handler == NULL && close_handler == NULL);
13219 DEBUG_ASSERT(is_delete_request || (handler != NULL));
13220 DEBUG_ASSERT(auth_handler == NULL);
13221
13222 if ((connect_handler != NULL) || (ready_handler != NULL)
13223 || (data_handler != NULL) || (close_handler != NULL)) {
13224 return;
13225 }
13226 if (!is_delete_request && (handler == NULL)) {
13227 return;
13228 }
13229 if (auth_handler != NULL) {
13230 return;
13231 }
13232 } else { /* AUTH_HANDLER */
13233 DEBUG_ASSERT(handler == NULL);
13234 DEBUG_ASSERT(connect_handler == NULL && ready_handler == NULL
13235 && data_handler == NULL && close_handler == NULL);
13236 DEBUG_ASSERT(auth_handler != NULL);
13237 if (handler != NULL) {
13238 return;
13239 }
13240 if ((connect_handler != NULL) || (ready_handler != NULL)
13241 || (data_handler != NULL) || (close_handler != NULL)) {
13242 return;
13243 }
13244 if (!is_delete_request && (auth_handler == NULL)) {
13245 return;
13246 }
13247 }
13248
13249 if (!phys_ctx || !dom_ctx) {
13250 return;
13251 }
13252
13253 mg_lock_context(phys_ctx);
13254
13255 /* first try to find an existing handler */
13256 lastref = &(dom_ctx->handlers);
13257 for (tmp_rh = dom_ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
13258 if (tmp_rh->handler_type == handler_type) {
13259 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13260 if (!is_delete_request) {
13261 /* update existing handler */
13262 if (handler_type == REQUEST_HANDLER) {
13263 /* Wait for end of use before updating */
13265
13266 /* Ok, the handler is no more use -> Update it */
13267 tmp_rh->handler = handler;
13268 } else if (handler_type == WEBSOCKET_HANDLER) {
13269 tmp_rh->subprotocols = subprotocols;
13270 tmp_rh->connect_handler = connect_handler;
13271 tmp_rh->ready_handler = ready_handler;
13272 tmp_rh->data_handler = data_handler;
13273 tmp_rh->close_handler = close_handler;
13274 } else { /* AUTH_HANDLER */
13275 tmp_rh->auth_handler = auth_handler;
13276 }
13277 tmp_rh->cbdata = cbdata;
13278 } else {
13279 /* remove existing handler */
13280 if (handler_type == REQUEST_HANDLER) {
13281 /* Wait for end of use before removing */
13283
13284 /* Ok, the handler is no more used -> Destroy resources
13285 */
13286 pthread_cond_destroy(&tmp_rh->refcount_cond);
13287 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13288 }
13289 *lastref = tmp_rh->next;
13290 mg_free(tmp_rh->uri);
13291 mg_free(tmp_rh);
13292 }
13293 mg_unlock_context(phys_ctx);
13294 return;
13295 }
13296 }
13297 lastref = &(tmp_rh->next);
13298 }
13299
13300 if (is_delete_request) {
13301 /* no handler to set, this was a remove request to a non-existing
13302 * handler */
13303 mg_unlock_context(phys_ctx);
13304 return;
13305 }
13306
13307 tmp_rh =
13308 (struct mg_handler_info *)mg_calloc_ctx(sizeof(struct mg_handler_info),
13309 1,
13310 phys_ctx);
13311 if (tmp_rh == NULL) {
13312 mg_unlock_context(phys_ctx);
13313 mg_cry_internal(fc(phys_ctx),
13314 "%s",
13315 "Cannot create new request handler struct, OOM");
13316 return;
13317 }
13318 tmp_rh->uri = mg_strdup_ctx(uri, phys_ctx);
13319 if (!tmp_rh->uri) {
13320 mg_unlock_context(phys_ctx);
13321 mg_free(tmp_rh);
13322 mg_cry_internal(fc(phys_ctx),
13323 "%s",
13324 "Cannot create new request handler struct, OOM");
13325 return;
13326 }
13327 tmp_rh->uri_len = urilen;
13328 if (handler_type == REQUEST_HANDLER) {
13329 /* Init refcount mutex and condition */
13330 if (0 != pthread_mutex_init(&tmp_rh->refcount_mutex, NULL)) {
13331 mg_unlock_context(phys_ctx);
13332 mg_free(tmp_rh);
13333 mg_cry_internal(fc(phys_ctx), "%s", "Cannot init refcount mutex");
13334 return;
13335 }
13336 if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
13337 mg_unlock_context(phys_ctx);
13338 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13339 mg_free(tmp_rh);
13340 mg_cry_internal(fc(phys_ctx), "%s", "Cannot init refcount cond");
13341 return;
13342 }
13343 tmp_rh->refcount = 0;
13344 tmp_rh->handler = handler;
13345 } else if (handler_type == WEBSOCKET_HANDLER) {
13346 tmp_rh->subprotocols = subprotocols;
13347 tmp_rh->connect_handler = connect_handler;
13348 tmp_rh->ready_handler = ready_handler;
13349 tmp_rh->data_handler = data_handler;
13350 tmp_rh->close_handler = close_handler;
13351 } else { /* AUTH_HANDLER */
13352 tmp_rh->auth_handler = auth_handler;
13353 }
13354 tmp_rh->cbdata = cbdata;
13355 tmp_rh->handler_type = handler_type;
13356 tmp_rh->next = NULL;
13357
13358 *lastref = tmp_rh;
13359 mg_unlock_context(phys_ctx);
13360}
13361
13362
13363void
13364mg_set_request_handler(struct mg_context *ctx,
13365 const char *uri,
13366 mg_request_handler handler,
13367 void *cbdata)
13368{
13370 &(ctx->dd),
13371 uri,
13373 handler == NULL,
13374 handler,
13375 NULL,
13376 NULL,
13377 NULL,
13378 NULL,
13379 NULL,
13380 NULL,
13381 cbdata);
13382}
13383
13384
13385void
13386mg_set_websocket_handler(struct mg_context *ctx,
13387 const char *uri,
13388 mg_websocket_connect_handler connect_handler,
13389 mg_websocket_ready_handler ready_handler,
13390 mg_websocket_data_handler data_handler,
13391 mg_websocket_close_handler close_handler,
13392 void *cbdata)
13393{
13395 uri,
13396 NULL,
13397 connect_handler,
13398 ready_handler,
13399 data_handler,
13400 close_handler,
13401 cbdata);
13402}
13403
13404
13405void
13407 struct mg_context *ctx,
13408 const char *uri,
13409 struct mg_websocket_subprotocols *subprotocols,
13410 mg_websocket_connect_handler connect_handler,
13411 mg_websocket_ready_handler ready_handler,
13412 mg_websocket_data_handler data_handler,
13413 mg_websocket_close_handler close_handler,
13414 void *cbdata)
13415{
13416 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
13417 && (data_handler == NULL)
13418 && (close_handler == NULL);
13420 &(ctx->dd),
13421 uri,
13423 is_delete_request,
13424 NULL,
13425 subprotocols,
13426 connect_handler,
13427 ready_handler,
13428 data_handler,
13429 close_handler,
13430 NULL,
13431 cbdata);
13432}
13433
13434
13435void
13436mg_set_auth_handler(struct mg_context *ctx,
13437 const char *uri,
13438 mg_request_handler handler,
13439 void *cbdata)
13440{
13442 &(ctx->dd),
13443 uri,
13445 handler == NULL,
13446 NULL,
13447 NULL,
13448 NULL,
13449 NULL,
13450 NULL,
13451 NULL,
13452 handler,
13453 cbdata);
13454}
13455
13456
13457static int
13458get_request_handler(struct mg_connection *conn,
13459 int handler_type,
13460 mg_request_handler *handler,
13461 struct mg_websocket_subprotocols **subprotocols,
13462 mg_websocket_connect_handler *connect_handler,
13463 mg_websocket_ready_handler *ready_handler,
13464 mg_websocket_data_handler *data_handler,
13465 mg_websocket_close_handler *close_handler,
13466 mg_authorization_handler *auth_handler,
13467 void **cbdata,
13468 struct mg_handler_info **handler_info)
13469{
13470 const struct mg_request_info *request_info = mg_get_request_info(conn);
13471 if (request_info) {
13472 const char *uri = request_info->local_uri;
13473 size_t urilen = strlen(uri);
13474 struct mg_handler_info *tmp_rh;
13475
13476 if (!conn || !conn->phys_ctx || !conn->dom_ctx) {
13477 return 0;
13478 }
13479
13480 mg_lock_context(conn->phys_ctx);
13481
13482 /* first try for an exact match */
13483 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13484 tmp_rh = tmp_rh->next) {
13485 if (tmp_rh->handler_type == handler_type) {
13486 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13487 if (handler_type == WEBSOCKET_HANDLER) {
13488 *subprotocols = tmp_rh->subprotocols;
13489 *connect_handler = tmp_rh->connect_handler;
13490 *ready_handler = tmp_rh->ready_handler;
13491 *data_handler = tmp_rh->data_handler;
13492 *close_handler = tmp_rh->close_handler;
13493 } else if (handler_type == REQUEST_HANDLER) {
13494 *handler = tmp_rh->handler;
13495 /* Acquire handler and give it back */
13496 handler_info_acquire(tmp_rh);
13497 *handler_info = tmp_rh;
13498 } else { /* AUTH_HANDLER */
13499 *auth_handler = tmp_rh->auth_handler;
13500 }
13501 *cbdata = tmp_rh->cbdata;
13502 mg_unlock_context(conn->phys_ctx);
13503 return 1;
13504 }
13505 }
13506 }
13507
13508 /* next try for a partial match, we will accept uri/something */
13509 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13510 tmp_rh = tmp_rh->next) {
13511 if (tmp_rh->handler_type == handler_type) {
13512 if ((tmp_rh->uri_len < urilen) && (uri[tmp_rh->uri_len] == '/')
13513 && (memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0)) {
13514 if (handler_type == WEBSOCKET_HANDLER) {
13515 *subprotocols = tmp_rh->subprotocols;
13516 *connect_handler = tmp_rh->connect_handler;
13517 *ready_handler = tmp_rh->ready_handler;
13518 *data_handler = tmp_rh->data_handler;
13519 *close_handler = tmp_rh->close_handler;
13520 } else if (handler_type == REQUEST_HANDLER) {
13521 *handler = tmp_rh->handler;
13522 /* Acquire handler and give it back */
13523 handler_info_acquire(tmp_rh);
13524 *handler_info = tmp_rh;
13525 } else { /* AUTH_HANDLER */
13526 *auth_handler = tmp_rh->auth_handler;
13527 }
13528 *cbdata = tmp_rh->cbdata;
13529 mg_unlock_context(conn->phys_ctx);
13530 return 1;
13531 }
13532 }
13533 }
13534
13535 /* finally try for pattern match */
13536 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13537 tmp_rh = tmp_rh->next) {
13538 if (tmp_rh->handler_type == handler_type) {
13539 if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
13540 if (handler_type == WEBSOCKET_HANDLER) {
13541 *subprotocols = tmp_rh->subprotocols;
13542 *connect_handler = tmp_rh->connect_handler;
13543 *ready_handler = tmp_rh->ready_handler;
13544 *data_handler = tmp_rh->data_handler;
13545 *close_handler = tmp_rh->close_handler;
13546 } else if (handler_type == REQUEST_HANDLER) {
13547 *handler = tmp_rh->handler;
13548 /* Acquire handler and give it back */
13549 handler_info_acquire(tmp_rh);
13550 *handler_info = tmp_rh;
13551 } else { /* AUTH_HANDLER */
13552 *auth_handler = tmp_rh->auth_handler;
13553 }
13554 *cbdata = tmp_rh->cbdata;
13555 mg_unlock_context(conn->phys_ctx);
13556 return 1;
13557 }
13558 }
13559 }
13560
13561 mg_unlock_context(conn->phys_ctx);
13562 }
13563 return 0; /* none found */
13564}
13565
13566
13567/* Check if the script file is in a path, allowed for script files.
13568 * This can be used if uploading files is possible not only for the server
13569 * admin, and the upload mechanism does not check the file extension.
13570 */
13571static int
13572is_in_script_path(const struct mg_connection *conn, const char *path)
13573{
13574 /* TODO (Feature): Add config value for allowed script path.
13575 * Default: All allowed. */
13576 (void)conn;
13577 (void)path;
13578 return 1;
13579}
13580
13581
13582#if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
13583static int
13584deprecated_websocket_connect_wrapper(const struct mg_connection *conn,
13585 void *cbdata)
13586{
13587 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
13588 if (pcallbacks->websocket_connect) {
13589 return pcallbacks->websocket_connect(conn);
13590 }
13591 /* No handler set - assume "OK" */
13592 return 0;
13593}
13594
13595
13596static void
13597deprecated_websocket_ready_wrapper(struct mg_connection *conn, void *cbdata)
13598{
13599 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
13600 if (pcallbacks->websocket_ready) {
13601 pcallbacks->websocket_ready(conn);
13602 }
13603}
13604
13605
13606static int
13607deprecated_websocket_data_wrapper(struct mg_connection *conn,
13608 int bits,
13609 char *data,
13610 size_t len,
13611 void *cbdata)
13612{
13613 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
13614 if (pcallbacks->websocket_data) {
13615 return pcallbacks->websocket_data(conn, bits, data, len);
13616 }
13617 /* No handler set - assume "OK" */
13618 return 1;
13619}
13620#endif
13621
13622
13623/* This is the heart of the Civetweb's logic.
13624 * This function is called when the request is read, parsed and validated,
13625 * and Civetweb must decide what action to take: serve a file, or
13626 * a directory, or call embedded function, etcetera. */
13627static void
13628handle_request(struct mg_connection *conn)
13629{
13630 struct mg_request_info *ri = &conn->request_info;
13631 char path[PATH_MAX];
13632 int uri_len, ssl_index;
13633 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
13634 is_put_or_delete_request = 0, is_callback_resource = 0;
13635 int i;
13636 struct mg_file file = STRUCT_FILE_INITIALIZER;
13637 mg_request_handler callback_handler = NULL;
13638 struct mg_handler_info *handler_info = NULL;
13640 mg_websocket_connect_handler ws_connect_handler = NULL;
13641 mg_websocket_ready_handler ws_ready_handler = NULL;
13642 mg_websocket_data_handler ws_data_handler = NULL;
13643 mg_websocket_close_handler ws_close_handler = NULL;
13644 void *callback_data = NULL;
13645 mg_authorization_handler auth_handler = NULL;
13646 void *auth_callback_data = NULL;
13647 int handler_type;
13648 time_t curtime = time(NULL);
13649 char date[64];
13650
13651 path[0] = 0;
13652
13653 /* 1. get the request url */
13654 /* 1.1. split into url and query string */
13655 if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
13656 != NULL) {
13657 *((char *)conn->request_info.query_string++) = '\0';
13658 }
13659
13660 /* 1.2. do a https redirect, if required. Do not decode URIs yet. */
13661 if (!conn->client.is_ssl && conn->client.ssl_redir) {
13662 ssl_index = get_first_ssl_listener_index(conn->phys_ctx);
13663 if (ssl_index >= 0) {
13664 redirect_to_https_port(conn, ssl_index);
13665 } else {
13666 /* A http to https forward port has been specified,
13667 * but no https port to forward to. */
13668 mg_send_http_error(conn,
13669 503,
13670 "%s",
13671 "Error: SSL forward not configured properly");
13672 mg_cry_internal(conn,
13673 "%s",
13674 "Can not redirect to SSL, no SSL port available");
13675 }
13676 return;
13677 }
13678 uri_len = (int)strlen(ri->local_uri);
13679
13680 /* 1.3. decode url (if config says so) */
13681 if (should_decode_url(conn)) {
13683 ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
13684 }
13685
13686 /* 1.4. clean URIs, so a path like allowed_dir/../forbidden_file is
13687 * not possible */
13689
13690 /* step 1. completed, the url is known now */
13691 uri_len = (int)strlen(ri->local_uri);
13692 DEBUG_TRACE("URL: %s", ri->local_uri);
13693
13694 /* 2. if this ip has limited speed, set it for this connection */
13695 conn->throttle = set_throttle(conn->dom_ctx->config[THROTTLE],
13696 get_remote_ip(conn),
13697 ri->local_uri);
13698
13699 /* 3. call a "handle everything" callback, if registered */
13700 if (conn->phys_ctx->callbacks.begin_request != NULL) {
13701 /* Note that since V1.7 the "begin_request" function is called
13702 * before an authorization check. If an authorization check is
13703 * required, use a request_handler instead. */
13704 i = conn->phys_ctx->callbacks.begin_request(conn);
13705 if (i > 0) {
13706 /* callback already processed the request. Store the
13707 return value as a status code for the access log. */
13708 conn->status_code = i;
13710 return;
13711 } else if (i == 0) {
13712 /* civetweb should process the request */
13713 } else {
13714 /* unspecified - may change with the next version */
13715 return;
13716 }
13717 }
13718
13719 /* request not yet handled by a handler or redirect, so the request
13720 * is processed here */
13721
13722 /* 4. Check for CORS preflight requests and handle them (if configured).
13723 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
13724 */
13725 if (!strcmp(ri->request_method, "OPTIONS")) {
13726 /* Send a response to CORS preflights only if
13727 * access_control_allow_methods is not NULL and not an empty string.
13728 * In this case, scripts can still handle CORS. */
13729 const char *cors_meth_cfg =
13730 conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_METHODS];
13731 const char *cors_orig_cfg =
13732 conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
13733 const char *cors_origin =
13734 get_header(ri->http_headers, ri->num_headers, "Origin");
13735 const char *cors_acrm = get_header(ri->http_headers,
13736 ri->num_headers,
13737 "Access-Control-Request-Method");
13738
13739 /* Todo: check if cors_origin is in cors_orig_cfg.
13740 * Or, let the client check this. */
13741
13742 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
13743 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
13744 && (cors_origin != NULL) && (cors_acrm != NULL)) {
13745 /* This is a valid CORS preflight, and the server is configured
13746 * to
13747 * handle it automatically. */
13748 const char *cors_acrh =
13750 ri->num_headers,
13751 "Access-Control-Request-Headers");
13752
13753 gmt_time_string(date, sizeof(date), &curtime);
13754 mg_printf(conn,
13755 "HTTP/1.1 200 OK\r\n"
13756 "Date: %s\r\n"
13757 "Access-Control-Allow-Origin: %s\r\n"
13758 "Access-Control-Allow-Methods: %s\r\n"
13759 "Content-Length: 0\r\n"
13760 "Connection: %s\r\n",
13761 date,
13762 cors_orig_cfg,
13763 ((cors_meth_cfg[0] == '*') ? cors_acrm : cors_meth_cfg),
13765
13766 if (cors_acrh != NULL) {
13767 /* CORS request is asking for additional headers */
13768 const char *cors_hdr_cfg =
13769 conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_HEADERS];
13770
13771 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
13772 /* Allow only if access_control_allow_headers is
13773 * not NULL and not an empty string. If this
13774 * configuration is set to *, allow everything.
13775 * Otherwise this configuration must be a list
13776 * of allowed HTTP header names. */
13777 mg_printf(conn,
13778 "Access-Control-Allow-Headers: %s\r\n",
13779 ((cors_hdr_cfg[0] == '*') ? cors_acrh
13780 : cors_hdr_cfg));
13781 }
13782 }
13783 mg_printf(conn, "Access-Control-Max-Age: 60\r\n");
13784
13785 mg_printf(conn, "\r\n");
13786 return;
13787 }
13788 }
13789
13790 /* 5. interpret the url to find out how the request must be handled
13791 */
13792 /* 5.1. first test, if the request targets the regular http(s)://
13793 * protocol namespace or the websocket ws(s):// protocol namespace.
13794 */
13795 is_websocket_request = is_websocket_protocol(conn);
13796#if defined(USE_WEBSOCKET)
13797 handler_type = is_websocket_request ? WEBSOCKET_HANDLER : REQUEST_HANDLER;
13798#else
13799 handler_type = REQUEST_HANDLER;
13800#endif /* defined(USE_WEBSOCKET) */
13801 /* 5.2. check if the request will be handled by a callback */
13802 if (get_request_handler(conn,
13803 handler_type,
13804 &callback_handler,
13805 &subprotocols,
13806 &ws_connect_handler,
13807 &ws_ready_handler,
13808 &ws_data_handler,
13809 &ws_close_handler,
13810 NULL,
13811 &callback_data,
13812 &handler_info)) {
13813 /* 5.2.1. A callback will handle this request. All requests
13814 * handled
13815 * by a callback have to be considered as requests to a script
13816 * resource. */
13817 is_callback_resource = 1;
13818 is_script_resource = 1;
13819 is_put_or_delete_request = is_put_or_delete_method(conn);
13820 } else {
13821 no_callback_resource:
13822
13823 /* 5.2.2. No callback is responsible for this request. The URI
13824 * addresses a file based resource (static content or Lua/cgi
13825 * scripts in the file system). */
13826 is_callback_resource = 0;
13827 interpret_uri(conn,
13828 path,
13829 sizeof(path),
13830 &file.stat,
13831 &is_found,
13832 &is_script_resource,
13833 &is_websocket_request,
13834 &is_put_or_delete_request);
13835 }
13836
13837 /* 6. authorization check */
13838 /* 6.1. a custom authorization handler is installed */
13839 if (get_request_handler(conn,
13841 NULL,
13842 NULL,
13843 NULL,
13844 NULL,
13845 NULL,
13846 NULL,
13847 &auth_handler,
13848 &auth_callback_data,
13849 NULL)) {
13850 if (!auth_handler(conn, auth_callback_data)) {
13851 return;
13852 }
13853 } else if (is_put_or_delete_request && !is_script_resource
13854 && !is_callback_resource) {
13855/* 6.2. this request is a PUT/DELETE to a real file */
13856/* 6.2.1. thus, the server must have real files */
13857#if defined(NO_FILES)
13858 if (1) {
13859#else
13860 if (conn->dom_ctx->config[DOCUMENT_ROOT] == NULL) {
13861#endif
13862 /* This server does not have any real files, thus the
13863 * PUT/DELETE methods are not valid. */
13864 mg_send_http_error(conn,
13865 405,
13866 "%s method not allowed",
13867 conn->request_info.request_method);
13868 return;
13869 }
13870
13871#if !defined(NO_FILES)
13872 /* 6.2.2. Check if put authorization for static files is
13873 * available.
13874 */
13875 if (!is_authorized_for_put(conn)) {
13876 send_authorization_request(conn, NULL);
13877 return;
13878 }
13879#endif
13880
13881 } else {
13882 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
13883 * or it is a PUT or DELETE request to a resource that does not
13884 * correspond to a file. Check authorization. */
13885 if (!check_authorization(conn, path)) {
13886 send_authorization_request(conn, NULL);
13887 return;
13888 }
13889 }
13890
13891 /* request is authorized or does not need authorization */
13892
13893 /* 7. check if there are request handlers for this uri */
13894 if (is_callback_resource) {
13895 if (!is_websocket_request) {
13896 i = callback_handler(conn, callback_data);
13897
13898 /* Callback handler will not be used anymore. Release it */
13899 handler_info_release(handler_info);
13900
13901 if (i > 0) {
13902 /* Do nothing, callback has served the request. Store
13903 * then return value as status code for the log and discard
13904 * all data from the client not used by the callback. */
13905 conn->status_code = i;
13907 } else {
13908 /* The handler did NOT handle the request. */
13909 /* Some proper reactions would be:
13910 * a) close the connections without sending anything
13911 * b) send a 404 not found
13912 * c) try if there is a file matching the URI
13913 * It would be possible to do a, b or c in the callback
13914 * implementation, and return 1 - we cannot do anything
13915 * here, that is not possible in the callback.
13916 *
13917 * TODO: What would be the best reaction here?
13918 * (Note: The reaction may change, if there is a better
13919 *idea.)
13920 */
13921
13922 /* For the moment, use option c: We look for a proper file,
13923 * but since a file request is not always a script resource,
13924 * the authorization check might be different. */
13925 interpret_uri(conn,
13926 path,
13927 sizeof(path),
13928 &file.stat,
13929 &is_found,
13930 &is_script_resource,
13931 &is_websocket_request,
13932 &is_put_or_delete_request);
13933 callback_handler = NULL;
13934
13935 /* Here we are at a dead end:
13936 * According to URI matching, a callback should be
13937 * responsible for handling the request,
13938 * we called it, but the callback declared itself
13939 * not responsible.
13940 * We use a goto here, to get out of this dead end,
13941 * and continue with the default handling.
13942 * A goto here is simpler and better to understand
13943 * than some curious loop. */
13944 goto no_callback_resource;
13945 }
13946 } else {
13947#if defined(USE_WEBSOCKET)
13948 handle_websocket_request(conn,
13949 path,
13950 is_callback_resource,
13952 ws_connect_handler,
13953 ws_ready_handler,
13954 ws_data_handler,
13955 ws_close_handler,
13956 callback_data);
13957#endif
13958 }
13959 return;
13960 }
13961
13962/* 8. handle websocket requests */
13963#if defined(USE_WEBSOCKET)
13964 if (is_websocket_request) {
13965 if (is_script_resource) {
13966
13967 if (is_in_script_path(conn, path)) {
13968 /* Websocket Lua script */
13969 handle_websocket_request(conn,
13970 path,
13971 0 /* Lua Script */,
13972 NULL,
13973 NULL,
13974 NULL,
13975 NULL,
13976 NULL,
13977 conn->phys_ctx->user_data);
13978 } else {
13979 /* Script was in an illegal path */
13980 mg_send_http_error(conn, 403, "%s", "Forbidden");
13981 }
13982 } else {
13983#if defined(MG_LEGACY_INTERFACE)
13984 handle_websocket_request(
13985 conn,
13986 path,
13987 !is_script_resource /* could be deprecated global callback */,
13988 NULL,
13989 deprecated_websocket_connect_wrapper,
13990 deprecated_websocket_ready_wrapper,
13991 deprecated_websocket_data_wrapper,
13992 NULL,
13993 conn->phys_ctx->user_data);
13994#else
13995 mg_send_http_error(conn, 404, "%s", "Not found");
13996#endif
13997 }
13998 return;
13999 } else
14000#endif
14001
14002#if defined(NO_FILES)
14003 /* 9a. In case the server uses only callbacks, this uri is
14004 * unknown.
14005 * Then, all request handling ends here. */
14006 mg_send_http_error(conn, 404, "%s", "Not Found");
14007
14008#else
14009 /* 9b. This request is either for a static file or resource handled
14010 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
14011 if (conn->dom_ctx->config[DOCUMENT_ROOT] == NULL) {
14012 mg_send_http_error(conn, 404, "%s", "Not Found");
14013 return;
14014 }
14015
14016 /* 10. Request is handled by a script */
14017 if (is_script_resource) {
14018 handle_file_based_request(conn, path, &file);
14019 return;
14020 }
14021
14022 /* 11. Handle put/delete/mkcol requests */
14023 if (is_put_or_delete_request) {
14024 /* 11.1. PUT method */
14025 if (!strcmp(ri->request_method, "PUT")) {
14026 put_file(conn, path);
14027 return;
14028 }
14029 /* 11.2. DELETE method */
14030 if (!strcmp(ri->request_method, "DELETE")) {
14031 delete_file(conn, path);
14032 return;
14033 }
14034 /* 11.3. MKCOL method */
14035 if (!strcmp(ri->request_method, "MKCOL")) {
14036 mkcol(conn, path);
14037 return;
14038 }
14039 /* 11.4. PATCH method
14040 * This method is not supported for static resources,
14041 * only for scripts (Lua, CGI) and callbacks. */
14042 mg_send_http_error(conn,
14043 405,
14044 "%s method not allowed",
14045 conn->request_info.request_method);
14046 return;
14047 }
14048
14049 /* 11. File does not exist, or it was configured that it should be
14050 * hidden */
14051 if (!is_found || (must_hide_file(conn, path))) {
14052 mg_send_http_error(conn, 404, "%s", "Not found");
14053 return;
14054 }
14055
14056 /* 12. Directory uris should end with a slash */
14057 if (file.stat.is_directory && (uri_len > 0)
14058 && (ri->local_uri[uri_len - 1] != '/')) {
14059 gmt_time_string(date, sizeof(date), &curtime);
14060 mg_printf(conn,
14061 "HTTP/1.1 301 Moved Permanently\r\n"
14062 "Location: %s/\r\n"
14063 "Date: %s\r\n"
14064 /* "Cache-Control: private\r\n" (= default) */
14065 "Content-Length: 0\r\n"
14066 "Connection: %s\r\n",
14067 ri->request_uri,
14068 date,
14071 mg_printf(conn, "\r\n");
14072 return;
14073 }
14074
14075 /* 13. Handle other methods than GET/HEAD */
14076 /* 13.1. Handle PROPFIND */
14077 if (!strcmp(ri->request_method, "PROPFIND")) {
14078 handle_propfind(conn, path, &file.stat);
14079 return;
14080 }
14081 /* 13.2. Handle OPTIONS for files */
14082 if (!strcmp(ri->request_method, "OPTIONS")) {
14083 /* This standard handler is only used for real files.
14084 * Scripts should support the OPTIONS method themselves, to allow a
14085 * maximum flexibility.
14086 * Lua and CGI scripts may fully support CORS this way (including
14087 * preflights). */
14088 send_options(conn);
14089 return;
14090 }
14091 /* 13.3. everything but GET and HEAD (e.g. POST) */
14092 if ((0 != strcmp(ri->request_method, "GET"))
14093 && (0 != strcmp(ri->request_method, "HEAD"))) {
14094 mg_send_http_error(conn,
14095 405,
14096 "%s method not allowed",
14097 conn->request_info.request_method);
14098 return;
14099 }
14100
14101 /* 14. directories */
14102 if (file.stat.is_directory) {
14103 /* Substitute files have already been handled above. */
14104 /* Here we can either generate and send a directory listing,
14105 * or send an "access denied" error. */
14106 if (!mg_strcasecmp(conn->dom_ctx->config[ENABLE_DIRECTORY_LISTING],
14107 "yes")) {
14108 handle_directory_request(conn, path);
14109 } else {
14110 mg_send_http_error(conn,
14111 403,
14112 "%s",
14113 "Error: Directory listing denied");
14114 }
14115 return;
14116 }
14117
14118 /* 15. read a normal file with GET or HEAD */
14119 handle_file_based_request(conn, path, &file);
14120#endif /* !defined(NO_FILES) */
14121}
14122
14123
14124static void
14125handle_file_based_request(struct mg_connection *conn,
14126 const char *path,
14127 struct mg_file *file)
14128{
14129 if (!conn || !conn->dom_ctx) {
14130 return;
14131 }
14132
14133 if (0) {
14134#if defined(USE_LUA)
14135 } else if (match_prefix(
14136 conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
14137 strlen(conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
14138 path)
14139 > 0) {
14140 if (is_in_script_path(conn, path)) {
14141 /* Lua server page: an SSI like page containing mostly plain
14142 * html
14143 * code
14144 * plus some tags with server generated contents. */
14145 handle_lsp_request(conn, path, file, NULL);
14146 } else {
14147 /* Script was in an illegal path */
14148 mg_send_http_error(conn, 403, "%s", "Forbidden");
14149 }
14150
14151 } else if (match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
14152 strlen(
14153 conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
14154 path)
14155 > 0) {
14156 if (is_in_script_path(conn, path)) {
14157 /* Lua in-server module script: a CGI like script used to
14158 * generate
14159 * the
14160 * entire reply. */
14161 mg_exec_lua_script(conn, path, NULL);
14162 } else {
14163 /* Script was in an illegal path */
14164 mg_send_http_error(conn, 403, "%s", "Forbidden");
14165 }
14166#endif
14167#if defined(USE_DUKTAPE)
14168 } else if (match_prefix(
14169 conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
14170 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
14171 path)
14172 > 0) {
14173 if (is_in_script_path(conn, path)) {
14174 /* Call duktape to generate the page */
14175 mg_exec_duktape_script(conn, path);
14176 } else {
14177 /* Script was in an illegal path */
14178 mg_send_http_error(conn, 403, "%s", "Forbidden");
14179 }
14180#endif
14181#if !defined(NO_CGI)
14182 } else if (match_prefix(conn->dom_ctx->config[CGI_EXTENSIONS],
14183 strlen(conn->dom_ctx->config[CGI_EXTENSIONS]),
14184 path)
14185 > 0) {
14186 if (is_in_script_path(conn, path)) {
14187 /* CGI scripts may support all HTTP methods */
14188 handle_cgi_request(conn, path);
14189 } else {
14190 /* Script was in an illegal path */
14191 mg_send_http_error(conn, 403, "%s", "Forbidden");
14192 }
14193#endif /* !NO_CGI */
14194 } else if (match_prefix(conn->dom_ctx->config[SSI_EXTENSIONS],
14195 strlen(conn->dom_ctx->config[SSI_EXTENSIONS]),
14196 path)
14197 > 0) {
14198 if (is_in_script_path(conn, path)) {
14199 handle_ssi_file_request(conn, path, file);
14200 } else {
14201 /* Script was in an illegal path */
14202 mg_send_http_error(conn, 403, "%s", "Forbidden");
14203 }
14204#if !defined(NO_CACHING)
14205 } else if ((!conn->in_error_handler)
14206 && is_not_modified(conn, &file->stat)) {
14207 /* Send 304 "Not Modified" - this must not send any body data */
14209#endif /* !NO_CACHING */
14210 } else {
14211 handle_static_file_request(conn, path, file, NULL, NULL);
14212 }
14213}
14214
14215
14216static void
14217close_all_listening_sockets(struct mg_context *ctx)
14218{
14219 unsigned int i;
14220 if (!ctx) {
14221 return;
14222 }
14223
14224 for (i = 0; i < ctx->num_listening_sockets; i++) {
14225 closesocket(ctx->listening_sockets[i].sock);
14226 ctx->listening_sockets[i].sock = INVALID_SOCKET;
14227 }
14228 mg_free(ctx->listening_sockets);
14229 ctx->listening_sockets = NULL;
14230 mg_free(ctx->listening_socket_fds);
14231 ctx->listening_socket_fds = NULL;
14232}
14233
14234
14235/* Valid listening port specification is: [ip_address:]port[s]
14236 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
14237 * Examples for IPv6: [::]:80, [::1]:80,
14238 * [2001:0db8:7654:3210:FEDC:BA98:7654:3210]:443s
14239 * see https://tools.ietf.org/html/rfc3513#section-2.2
14240 * In order to bind to both, IPv4 and IPv6, you can either add
14241 * both ports using 8080,[::]:8080, or the short form +8080.
14242 * Both forms differ in detail: 8080,[::]:8080 create two sockets,
14243 * one only accepting IPv4 the other only IPv6. +8080 creates
14244 * one socket accepting IPv4 and IPv6. Depending on the IPv6
14245 * environment, they might work differently, or might not work
14246 * at all - it must be tested what options work best in the
14247 * relevant network environment.
14248 */
14249static int
14250parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
14251{
14252 unsigned int a, b, c, d, port;
14253 int ch, len;
14254 const char *cb;
14255#if defined(USE_IPV6)
14256 char buf[100] = {0};
14257#endif
14258
14259 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
14260 * Also, all-zeroes in the socket address means binding to all addresses
14261 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
14262 memset(so, 0, sizeof(*so));
14263 so->lsa.sin.sin_family = AF_INET;
14264 *ip_version = 0;
14265
14266 /* Initialize port and len as invalid. */
14267 port = 0;
14268 len = 0;
14269
14270 /* Test for different ways to format this string */
14271 if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
14272 == 5) {
14273 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
14274 so->lsa.sin.sin_addr.s_addr =
14275 htonl((a << 24) | (b << 16) | (c << 8) | d);
14276 so->lsa.sin.sin_port = htons((uint16_t)port);
14277 *ip_version = 4;
14278
14279#if defined(USE_IPV6)
14280 } else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
14281 && mg_inet_pton(
14282 AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
14283 /* IPv6 address, examples: see above */
14284 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
14285 */
14286 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14287 *ip_version = 6;
14288#endif
14289
14290 } else if ((vec->ptr[0] == '+')
14291 && (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
14292
14293 /* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY */
14294 /* Add 1 to len for the + character we skipped before */
14295 len++;
14296
14297#if defined(USE_IPV6)
14298 /* Set socket family to IPv6, do not use IPV6_V6ONLY */
14299 so->lsa.sin6.sin6_family = AF_INET6;
14300 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14301 *ip_version = 4 + 6;
14302#else
14303 /* Bind to IPv4 only, since IPv6 is not built in. */
14304 so->lsa.sin.sin_port = htons((uint16_t)port);
14305 *ip_version = 4;
14306#endif
14307
14308 } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
14309 /* If only port is specified, bind to IPv4, INADDR_ANY */
14310 so->lsa.sin.sin_port = htons((uint16_t)port);
14311 *ip_version = 4;
14312
14313 } else if ((cb = strchr(vec->ptr, ':')) != NULL) {
14314 /* String could be a hostname. This check algotithm
14315 * will only work for RFC 952 compliant hostnames,
14316 * starting with a letter, containing only letters,
14317 * digits and hyphen ('-'). Newer specs may allow
14318 * more, but this is not guaranteed here, since it
14319 * may interfere with rules for port option lists. */
14320
14321 /* According to RFC 1035, hostnames are restricted to 255 characters
14322 * in total (63 between two dots). */
14323 char hostname[256];
14324 size_t hostnlen = (size_t)(cb - vec->ptr);
14325
14326 if (hostnlen >= sizeof(hostname)) {
14327 /* This would be invalid in any case */
14328 *ip_version = 0;
14329 return 0;
14330 }
14331
14332 memcpy(hostname, vec->ptr, hostnlen);
14333 hostname[hostnlen] = 0;
14334
14335 if (mg_inet_pton(
14336 AF_INET, vec->ptr, &so->lsa.sin, sizeof(so->lsa.sin))) {
14337 if (sscanf(cb + 1, "%u%n", &port, &len) == 1) {
14338 *ip_version = 4;
14339 so->lsa.sin.sin_family = AF_INET;
14340 so->lsa.sin.sin_port = htons((uint16_t)port);
14341 len += (int)(hostnlen + 1);
14342 } else {
14343 port = 0;
14344 len = 0;
14345 }
14346#if defined(USE_IPV6)
14347 } else if (mg_inet_pton(AF_INET6,
14348 vec->ptr,
14349 &so->lsa.sin6,
14350 sizeof(so->lsa.sin6))) {
14351 if (sscanf(cb + 1, "%u%n", &port, &len) == 1) {
14352 *ip_version = 6;
14353 so->lsa.sin6.sin6_family = AF_INET6;
14354 so->lsa.sin.sin_port = htons((uint16_t)port);
14355 len += (int)(hostnlen + 1);
14356 } else {
14357 port = 0;
14358 len = 0;
14359 }
14360#endif
14361 }
14362
14363
14364 } else {
14365 /* Parsing failure. */
14366 }
14367
14368 /* sscanf and the option splitting code ensure the following condition
14369 */
14370 if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
14371 *ip_version = 0;
14372 return 0;
14373 }
14374 ch = vec->ptr[len]; /* Next character after the port number */
14375 so->is_ssl = (ch == 's');
14376 so->ssl_redir = (ch == 'r');
14377
14378 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
14379 if (is_valid_port(port)
14380 && ((ch == '\0') || (ch == 's') || (ch == 'r') || (ch == ','))) {
14381 return 1;
14382 }
14383
14384 /* Reset ip_version to 0 if there is an error */
14385 *ip_version = 0;
14386 return 0;
14387}
14388
14389
14390/* Is there any SSL port in use? */
14391static int
14392is_ssl_port_used(const char *ports)
14393{
14394 if (ports) {
14395 /* There are several different allowed syntax variants:
14396 * - "80" for a single port using every network interface
14397 * - "localhost:80" for a single port using only localhost
14398 * - "80,localhost:8080" for two ports, one bound to localhost
14399 * - "80,127.0.0.1:8084,[::1]:8086" for three ports, one bound
14400 * to IPv4 localhost, one to IPv6 localhost
14401 * - "+80" use port 80 for IPv4 and IPv6
14402 * - "+80r,+443s" port 80 (HTTP) is a redirect to port 443 (HTTPS),
14403 * for both: IPv4 and IPv4
14404 * - "+443s,localhost:8080" port 443 (HTTPS) for every interface,
14405 * additionally port 8080 bound to localhost connections
14406 *
14407 * If we just look for 's' anywhere in the string, "localhost:80"
14408 * will be detected as SSL (false positive).
14409 * Looking for 's' after a digit may cause false positives in
14410 * "my24service:8080".
14411 * Looking from 's' backward if there are only ':' and numbers
14412 * before will not work for "24service:8080" (non SSL, port 8080)
14413 * or "24s" (SSL, port 24).
14414 *
14415 * Remark: Initially hostnames were not allowed to start with a
14416 * digit (according to RFC 952), this was allowed later (RFC 1123,
14417 * Section 2.1).
14418 *
14419 * To get this correct, the entire string must be parsed as a whole,
14420 * reading it as a list element for element and parsing with an
14421 * algorithm equivalent to parse_port_string.
14422 *
14423 * In fact, we use local interface names here, not arbitrary hostnames,
14424 * so in most cases the only name will be "localhost".
14425 *
14426 * So, for now, we use this simple algorithm, that may still return
14427 * a false positive in bizarre cases.
14428 */
14429 int i;
14430 int portslen = (int)strlen(ports);
14431 char prevIsNumber = 0;
14432
14433 for (i = 0; i < portslen; i++) {
14434 if (prevIsNumber && (ports[i] == 's' || ports[i] == 'r')) {
14435 return 1;
14436 }
14437 if (ports[i] >= '0' && ports[i] <= '9') {
14438 prevIsNumber = 1;
14439 } else {
14440 prevIsNumber = 0;
14441 }
14442 }
14443 }
14444 return 0;
14445}
14446
14447
14448static int
14449set_ports_option(struct mg_context *phys_ctx)
14450{
14451 const char *list;
14452 int on = 1;
14453#if defined(USE_IPV6)
14454 int off = 0;
14455#endif
14456 struct vec vec;
14457 struct socket so, *ptr;
14458
14459 struct pollfd *pfd;
14460 union usa usa;
14461 socklen_t len;
14462 int ip_version;
14463
14464 int portsTotal = 0;
14465 int portsOk = 0;
14466
14467 if (!phys_ctx) {
14468 return 0;
14469 }
14470
14471 memset(&so, 0, sizeof(so));
14472 memset(&usa, 0, sizeof(usa));
14473 len = sizeof(usa);
14474 list = phys_ctx->dd.config[LISTENING_PORTS];
14475
14476 while ((list = next_option(list, &vec, NULL)) != NULL) {
14477
14478 portsTotal++;
14479
14480 if (!parse_port_string(&vec, &so, &ip_version)) {
14482 fc(phys_ctx),
14483 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
14484 (int)vec.len,
14485 vec.ptr,
14486 portsTotal,
14487 "[IP_ADDRESS:]PORT[s|r]");
14488 continue;
14489 }
14490
14491#if !defined(NO_SSL)
14492 if (so.is_ssl && phys_ctx->dd.ssl_ctx == NULL) {
14493
14494 mg_cry_internal(fc(phys_ctx),
14495 "Cannot add SSL socket (entry %i)",
14496 portsTotal);
14497 continue;
14498 }
14499#endif
14500
14501 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
14502 == INVALID_SOCKET) {
14503
14504 mg_cry_internal(fc(phys_ctx),
14505 "cannot create socket (entry %i)",
14506 portsTotal);
14507 continue;
14508 }
14509
14510#if defined(_WIN32)
14511 /* Windows SO_REUSEADDR lets many procs binds to a
14512 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
14513 * if someone already has the socket -- DTL */
14514 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
14515 * Windows might need a few seconds before
14516 * the same port can be used again in the
14517 * same process, so a short Sleep may be
14518 * required between mg_stop and mg_start.
14519 */
14520 if (setsockopt(so.sock,
14521 SOL_SOCKET,
14522 SO_EXCLUSIVEADDRUSE,
14523 (SOCK_OPT_TYPE)&on,
14524 sizeof(on))
14525 != 0) {
14526
14527 /* Set reuse option, but don't abort on errors. */
14529 fc(phys_ctx),
14530 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
14531 portsTotal);
14532 }
14533#else
14534 if (setsockopt(so.sock,
14535 SOL_SOCKET,
14536 SO_REUSEADDR,
14537 (SOCK_OPT_TYPE)&on,
14538 sizeof(on))
14539 != 0) {
14540
14541 /* Set reuse option, but don't abort on errors. */
14542 mg_cry_internal(fc(phys_ctx),
14543 "cannot set socket option SO_REUSEADDR (entry %i)",
14544 portsTotal);
14545 }
14546#endif
14547
14548 if (ip_version > 4) {
14549/* Could be 6 for IPv6 onlyor 10 (4+6) for IPv4+IPv6 */
14550#if defined(USE_IPV6)
14551 if (ip_version > 6) {
14552 if (so.lsa.sa.sa_family == AF_INET6
14553 && setsockopt(so.sock,
14554 IPPROTO_IPV6,
14555 IPV6_V6ONLY,
14556 (void *)&off,
14557 sizeof(off))
14558 != 0) {
14559
14560 /* Set IPv6 only option, but don't abort on errors. */
14562 fc(phys_ctx),
14563 "cannot set socket option IPV6_V6ONLY=off (entry %i)",
14564 portsTotal);
14565 }
14566 } else {
14567 if (so.lsa.sa.sa_family == AF_INET6
14568 && setsockopt(so.sock,
14569 IPPROTO_IPV6,
14570 IPV6_V6ONLY,
14571 (void *)&on,
14572 sizeof(on))
14573 != 0) {
14574
14575 /* Set IPv6 only option, but don't abort on errors. */
14577 fc(phys_ctx),
14578 "cannot set socket option IPV6_V6ONLY=on (entry %i)",
14579 portsTotal);
14580 }
14581 }
14582#else
14583 mg_cry_internal(fc(phys_ctx), "%s", "IPv6 not available");
14584 closesocket(so.sock);
14585 so.sock = INVALID_SOCKET;
14586 continue;
14587#endif
14588 }
14589
14590 if (so.lsa.sa.sa_family == AF_INET) {
14591
14592 len = sizeof(so.lsa.sin);
14593 if (bind(so.sock, &so.lsa.sa, len) != 0) {
14594 mg_cry_internal(fc(phys_ctx),
14595 "cannot bind to %.*s: %d (%s)",
14596 (int)vec.len,
14597 vec.ptr,
14598 (int)ERRNO,
14599 strerror(errno));
14600 closesocket(so.sock);
14601 so.sock = INVALID_SOCKET;
14602 continue;
14603 }
14604 }
14605#if defined(USE_IPV6)
14606 else if (so.lsa.sa.sa_family == AF_INET6) {
14607
14608 len = sizeof(so.lsa.sin6);
14609 if (bind(so.sock, &so.lsa.sa, len) != 0) {
14610 mg_cry_internal(fc(phys_ctx),
14611 "cannot bind to IPv6 %.*s: %d (%s)",
14612 (int)vec.len,
14613 vec.ptr,
14614 (int)ERRNO,
14615 strerror(errno));
14616 closesocket(so.sock);
14617 so.sock = INVALID_SOCKET;
14618 continue;
14619 }
14620 }
14621#endif
14622 else {
14624 fc(phys_ctx),
14625 "cannot bind: address family not supported (entry %i)",
14626 portsTotal);
14627 closesocket(so.sock);
14628 so.sock = INVALID_SOCKET;
14629 continue;
14630 }
14631
14632 if (listen(so.sock, SOMAXCONN) != 0) {
14633
14634 mg_cry_internal(fc(phys_ctx),
14635 "cannot listen to %.*s: %d (%s)",
14636 (int)vec.len,
14637 vec.ptr,
14638 (int)ERRNO,
14639 strerror(errno));
14640 closesocket(so.sock);
14641 so.sock = INVALID_SOCKET;
14642 continue;
14643 }
14644
14645 if ((getsockname(so.sock, &(usa.sa), &len) != 0)
14646 || (usa.sa.sa_family != so.lsa.sa.sa_family)) {
14647
14648 int err = (int)ERRNO;
14649 mg_cry_internal(fc(phys_ctx),
14650 "call to getsockname failed %.*s: %d (%s)",
14651 (int)vec.len,
14652 vec.ptr,
14653 err,
14654 strerror(errno));
14655 closesocket(so.sock);
14656 so.sock = INVALID_SOCKET;
14657 continue;
14658 }
14659
14660/* Update lsa port in case of random free ports */
14661#if defined(USE_IPV6)
14662 if (so.lsa.sa.sa_family == AF_INET6) {
14663 so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
14664 } else
14665#endif
14666 {
14667 so.lsa.sin.sin_port = usa.sin.sin_port;
14668 }
14669
14670 if ((ptr = (struct socket *)
14671 mg_realloc_ctx(phys_ctx->listening_sockets,
14672 (phys_ctx->num_listening_sockets + 1)
14673 * sizeof(phys_ctx->listening_sockets[0]),
14674 phys_ctx))
14675 == NULL) {
14676
14677 mg_cry_internal(fc(phys_ctx), "%s", "Out of memory");
14678 closesocket(so.sock);
14679 so.sock = INVALID_SOCKET;
14680 continue;
14681 }
14682
14683 if ((pfd = (struct pollfd *)
14684 mg_realloc_ctx(phys_ctx->listening_socket_fds,
14685 (phys_ctx->num_listening_sockets + 1)
14686 * sizeof(phys_ctx->listening_socket_fds[0]),
14687 phys_ctx))
14688 == NULL) {
14689
14690 mg_cry_internal(fc(phys_ctx), "%s", "Out of memory");
14691 closesocket(so.sock);
14692 so.sock = INVALID_SOCKET;
14693 mg_free(ptr);
14694 continue;
14695 }
14696
14697 set_close_on_exec(so.sock, fc(phys_ctx));
14698 phys_ctx->listening_sockets = ptr;
14699 phys_ctx->listening_sockets[phys_ctx->num_listening_sockets] = so;
14700 phys_ctx->listening_socket_fds = pfd;
14701 phys_ctx->num_listening_sockets++;
14702 portsOk++;
14703 }
14704
14705 if (portsOk != portsTotal) {
14707 portsOk = 0;
14708 }
14709
14710 return portsOk;
14711}
14712
14713
14714static const char *
14715header_val(const struct mg_connection *conn, const char *header)
14716{
14717 const char *header_value;
14718
14719 if ((header_value = mg_get_header(conn, header)) == NULL) {
14720 return "-";
14721 } else {
14722 return header_value;
14723 }
14724}
14725
14726
14727#if defined(MG_EXTERNAL_FUNCTION_log_access)
14728static void log_access(const struct mg_connection *conn);
14729#include "external_log_access.inl"
14730#else
14731
14732static void
14733log_access(const struct mg_connection *conn)
14734{
14735 const struct mg_request_info *ri;
14736 struct mg_file fi;
14737 char date[64], src_addr[IP_ADDR_STR_LEN];
14738 struct tm *tm;
14739
14740 const char *referer;
14741 const char *user_agent;
14742
14743 char buf[4096];
14744
14745 if (!conn || !conn->dom_ctx) {
14746 return;
14747 }
14748
14749 if (conn->dom_ctx->config[ACCESS_LOG_FILE] != NULL) {
14750 if (mg_fopen(conn,
14751 conn->dom_ctx->config[ACCESS_LOG_FILE],
14753 &fi)
14754 == 0) {
14755 fi.access.fp = NULL;
14756 }
14757 } else {
14758 fi.access.fp = NULL;
14759 }
14760
14761 /* Log is written to a file and/or a callback. If both are not set,
14762 * executing the rest of the function is pointless. */
14763 if ((fi.access.fp == NULL)
14764 && (conn->phys_ctx->callbacks.log_access == NULL)) {
14765 return;
14766 }
14767
14768 tm = localtime(&conn->conn_birth_time);
14769 if (tm != NULL) {
14770 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
14771 } else {
14772 mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
14773 date[sizeof(date) - 1] = '\0';
14774 }
14775
14776 ri = &conn->request_info;
14777
14778 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
14779 referer = header_val(conn, "Referer");
14780 user_agent = header_val(conn, "User-Agent");
14781
14782 mg_snprintf(conn,
14783 NULL, /* Ignore truncation in access log */
14784 buf,
14785 sizeof(buf),
14786 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
14787 src_addr,
14788 (ri->remote_user == NULL) ? "-" : ri->remote_user,
14789 date,
14790 ri->request_method ? ri->request_method : "-",
14791 ri->request_uri ? ri->request_uri : "-",
14792 ri->query_string ? "?" : "",
14793 ri->query_string ? ri->query_string : "",
14794 ri->http_version,
14795 conn->status_code,
14796 conn->num_bytes_sent,
14797 referer,
14798 user_agent);
14799
14800 if (conn->phys_ctx->callbacks.log_access) {
14801 conn->phys_ctx->callbacks.log_access(conn, buf);
14802 }
14803
14804 if (fi.access.fp) {
14805 int ok = 1;
14806 flockfile(fi.access.fp);
14807 if (fprintf(fi.access.fp, "%s\n", buf) < 1) {
14808 ok = 0;
14809 }
14810 if (fflush(fi.access.fp) != 0) {
14811 ok = 0;
14812 }
14813 funlockfile(fi.access.fp);
14814 if (mg_fclose(&fi.access) != 0) {
14815 ok = 0;
14816 }
14817 if (!ok) {
14818 mg_cry_internal(conn,
14819 "Error writing log file %s",
14820 conn->dom_ctx->config[ACCESS_LOG_FILE]);
14821 }
14822 }
14823}
14824
14825#endif /* Externally provided function */
14826
14827
14828/* Verify given socket address against the ACL.
14829 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
14830 */
14831static int
14832check_acl(struct mg_context *phys_ctx, uint32_t remote_ip)
14833{
14834 int allowed, flag;
14835 uint32_t net, mask;
14836 struct vec vec;
14837
14838 if (phys_ctx) {
14839 const char *list = phys_ctx->dd.config[ACCESS_CONTROL_LIST];
14840
14841 /* If any ACL is set, deny by default */
14842 allowed = (list == NULL) ? '+' : '-';
14843
14844 while ((list = next_option(list, &vec, NULL)) != NULL) {
14845 flag = vec.ptr[0];
14846 if ((flag != '+' && flag != '-')
14847 || (parse_net(&vec.ptr[1], &net, &mask) == 0)) {
14848 mg_cry_internal(fc(phys_ctx),
14849 "%s: subnet must be [+|-]x.x.x.x[/x]",
14850 __func__);
14851 return -1;
14852 }
14853
14854 if (net == (remote_ip & mask)) {
14855 allowed = flag;
14856 }
14857 }
14858
14859 return allowed == '+';
14860 }
14861 return -1;
14862}
14863
14864
14865#if !defined(_WIN32)
14866static int
14867set_uid_option(struct mg_context *phys_ctx)
14868{
14869 int success = 0;
14870
14871 if (phys_ctx) {
14872 /* We are currently running as curr_uid. */
14873 const uid_t curr_uid = getuid();
14874 /* If set, we want to run as run_as_user. */
14875 const char *run_as_user = phys_ctx->dd.config[RUN_AS_USER];
14876 const struct passwd *to_pw = NULL;
14877
14878 if (run_as_user != NULL && (to_pw = getpwnam(run_as_user)) == NULL) {
14879 /* run_as_user does not exist on the system. We can't proceed
14880 * further. */
14881 mg_cry_internal(fc(phys_ctx),
14882 "%s: unknown user [%s]",
14883 __func__,
14884 run_as_user);
14885 } else if (run_as_user == NULL || curr_uid == to_pw->pw_uid) {
14886 /* There was either no request to change user, or we're already
14887 * running as run_as_user. Nothing else to do.
14888 */
14889 success = 1;
14890 } else {
14891 /* Valid change request. */
14892 if (setgid(to_pw->pw_gid) == -1) {
14893 mg_cry_internal(fc(phys_ctx),
14894 "%s: setgid(%s): %s",
14895 __func__,
14896 run_as_user,
14897 strerror(errno));
14898 } else if (setgroups(0, NULL) == -1) {
14899 mg_cry_internal(fc(phys_ctx),
14900 "%s: setgroups(): %s",
14901 __func__,
14902 strerror(errno));
14903 } else if (setuid(to_pw->pw_uid) == -1) {
14904 mg_cry_internal(fc(phys_ctx),
14905 "%s: setuid(%s): %s",
14906 __func__,
14907 run_as_user,
14908 strerror(errno));
14909 } else {
14910 success = 1;
14911 }
14912 }
14913 }
14914
14915 return success;
14916}
14917#endif /* !_WIN32 */
14918
14919
14920static void
14921tls_dtor(void *key)
14922{
14923 struct mg_workerTLS *tls = (struct mg_workerTLS *)key;
14924 /* key == pthread_getspecific(sTlsKey); */
14925
14926 if (tls) {
14927 if (tls->is_master == 2) {
14928 tls->is_master = -3; /* Mark memory as dead */
14929 mg_free(tls);
14930 }
14931 }
14932 pthread_setspecific(sTlsKey, NULL);
14933}
14934
14935
14936#if !defined(NO_SSL)
14937
14938static int ssl_use_pem_file(struct mg_context *phys_ctx,
14939 struct mg_domain_context *dom_ctx,
14940 const char *pem,
14941 const char *chain);
14942static const char *ssl_error(void);
14943
14944
14945static int
14946refresh_trust(struct mg_connection *conn)
14947{
14948 static int reload_lock = 0;
14949 static long int data_check = 0;
14950 volatile int *p_reload_lock = (volatile int *)&reload_lock;
14951
14952 struct stat cert_buf;
14953 long int t;
14954 const char *pem;
14955 const char *chain;
14956 int should_verify_peer;
14957
14958 if ((pem = conn->dom_ctx->config[SSL_CERTIFICATE]) == NULL) {
14959 /* If peem is NULL and conn->phys_ctx->callbacks.init_ssl is not,
14960 * refresh_trust still can not work. */
14961 return 0;
14962 }
14963 chain = conn->dom_ctx->config[SSL_CERTIFICATE_CHAIN];
14964 if (chain == NULL) {
14965 /* pem is not NULL here */
14966 chain = pem;
14967 }
14968 if (*chain == 0) {
14969 chain = NULL;
14970 }
14971
14972 t = data_check;
14973 if (stat(pem, &cert_buf) != -1) {
14974 t = (long int)cert_buf.st_mtime;
14975 }
14976
14977 if (data_check != t) {
14978 data_check = t;
14979
14980 should_verify_peer = 0;
14981 if (conn->dom_ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
14982 if (mg_strcasecmp(conn->dom_ctx->config[SSL_DO_VERIFY_PEER], "yes")
14983 == 0) {
14984 should_verify_peer = 1;
14985 } else if (mg_strcasecmp(conn->dom_ctx->config[SSL_DO_VERIFY_PEER],
14986 "optional")
14987 == 0) {
14988 should_verify_peer = 1;
14989 }
14990 }
14991
14992 if (should_verify_peer) {
14993 char *ca_path = conn->dom_ctx->config[SSL_CA_PATH];
14994 char *ca_file = conn->dom_ctx->config[SSL_CA_FILE];
14995 if (SSL_CTX_load_verify_locations(conn->dom_ctx->ssl_ctx,
14996 ca_file,
14997 ca_path)
14998 != 1) {
15000 fc(conn->phys_ctx),
15001 "SSL_CTX_load_verify_locations error: %s "
15002 "ssl_verify_peer requires setting "
15003 "either ssl_ca_path or ssl_ca_file. Is any of them "
15004 "present in "
15005 "the .conf file?",
15006 ssl_error());
15007 return 0;
15008 }
15009 }
15010
15011 if (1 == mg_atomic_inc(p_reload_lock)) {
15012 if (ssl_use_pem_file(conn->phys_ctx, conn->dom_ctx, pem, chain)
15013 == 0) {
15014 return 0;
15015 }
15016 *p_reload_lock = 0;
15017 }
15018 }
15019 /* lock while cert is reloading */
15020 while (*p_reload_lock) {
15021 sleep(1);
15022 }
15023
15024 return 1;
15025}
15026
15027#if defined(OPENSSL_API_1_1)
15028#else
15029static pthread_mutex_t *ssl_mutexes;
15030#endif /* OPENSSL_API_1_1 */
15031
15032static int
15033sslize(struct mg_connection *conn,
15034 SSL_CTX *s,
15035 int (*func)(SSL *),
15036 volatile int *stop_server,
15037 const struct mg_client_options *client_options)
15038{
15039 int ret, err;
15040 int short_trust;
15041 unsigned i;
15042
15043 if (!conn) {
15044 return 0;
15045 }
15046
15047 short_trust =
15048 (conn->dom_ctx->config[SSL_SHORT_TRUST] != NULL)
15049 && (mg_strcasecmp(conn->dom_ctx->config[SSL_SHORT_TRUST], "yes") == 0);
15050
15051 if (short_trust) {
15052 int trust_ret = refresh_trust(conn);
15053 if (!trust_ret) {
15054 return trust_ret;
15055 }
15056 }
15057
15058 conn->ssl = SSL_new(s);
15059 if (conn->ssl == NULL) {
15060 return 0;
15061 }
15062 SSL_set_app_data(conn->ssl, (char *)conn);
15063
15064 ret = SSL_set_fd(conn->ssl, conn->client.sock);
15065 if (ret != 1) {
15066 err = SSL_get_error(conn->ssl, ret);
15067 mg_cry_internal(conn, "SSL error %i, destroying SSL context", err);
15068 SSL_free(conn->ssl);
15069 conn->ssl = NULL;
15071 return 0;
15072 }
15073
15074 if (client_options) {
15075 if (client_options->host_name) {
15076 SSL_set_tlsext_host_name(conn->ssl, client_options->host_name);
15077 }
15078 }
15079
15080 /* SSL functions may fail and require to be called again:
15081 * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html
15082 * Here "func" could be SSL_connect or SSL_accept. */
15083 for (i = 16; i <= 1024; i *= 2) {
15084 ret = func(conn->ssl);
15085 if (ret != 1) {
15086 err = SSL_get_error(conn->ssl, ret);
15087 if ((err == SSL_ERROR_WANT_CONNECT)
15088 || (err == SSL_ERROR_WANT_ACCEPT)
15089 || (err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE)
15090 || (err == SSL_ERROR_WANT_X509_LOOKUP)) {
15091 /* Need to retry the function call "later".
15092 * See https://linux.die.net/man/3/ssl_get_error
15093 * This is typical for non-blocking sockets. */
15094 if (*stop_server) {
15095 /* Don't wait if the server is going to be stopped. */
15096 break;
15097 }
15098 mg_sleep(i);
15099
15100 } else if (err == SSL_ERROR_SYSCALL) {
15101 /* This is an IO error. Look at errno. */
15102 err = errno;
15103 mg_cry_internal(conn, "SSL syscall error %i", err);
15104 break;
15105
15106 } else {
15107 /* This is an SSL specific error, e.g. SSL_ERROR_SSL */
15108 mg_cry_internal(conn, "sslize error: %s", ssl_error());
15109 break;
15110 }
15111
15112 } else {
15113 /* success */
15114 break;
15115 }
15116 }
15117
15118 if (ret != 1) {
15119 SSL_free(conn->ssl);
15120 conn->ssl = NULL;
15122 return 0;
15123 }
15124
15125 return 1;
15126}
15127
15128
15129/* Return OpenSSL error message (from CRYPTO lib) */
15130static const char *
15132{
15133 unsigned long err;
15134 err = ERR_get_error();
15135 return ((err == 0) ? "" : ERR_error_string(err, NULL));
15136}
15137
15138
15139static int
15140hexdump2string(void *mem, int memlen, char *buf, int buflen)
15141{
15142 int i;
15143 const char hexdigit[] = "0123456789abcdef";
15144
15145 if ((memlen <= 0) || (buflen <= 0)) {
15146 return 0;
15147 }
15148 if (buflen < (3 * memlen)) {
15149 return 0;
15150 }
15151
15152 for (i = 0; i < memlen; i++) {
15153 if (i > 0) {
15154 buf[3 * i - 1] = ' ';
15155 }
15156 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
15157 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
15158 }
15159 buf[3 * memlen - 1] = 0;
15160
15161 return 1;
15162}
15163
15164
15165static void
15166ssl_get_client_cert_info(struct mg_connection *conn)
15167{
15168 X509 *cert = SSL_get_peer_certificate(conn->ssl);
15169 if (cert) {
15170 char str_subject[1024];
15171 char str_issuer[1024];
15172 char str_finger[1024];
15173 unsigned char buf[256];
15174 char *str_serial = NULL;
15175 unsigned int ulen;
15176 int ilen;
15177 unsigned char *tmp_buf;
15178 unsigned char *tmp_p;
15179
15180 /* Handle to algorithm used for fingerprint */
15181 const EVP_MD *digest = EVP_get_digestbyname("sha1");
15182
15183 /* Get Subject and issuer */
15184 X509_NAME *subj = X509_get_subject_name(cert);
15185 X509_NAME *iss = X509_get_issuer_name(cert);
15186
15187 /* Get serial number */
15188 ASN1_INTEGER *serial = X509_get_serialNumber(cert);
15189
15190 /* Translate serial number to a hex string */
15191 BIGNUM *serial_bn = ASN1_INTEGER_to_BN(serial, NULL);
15192 str_serial = BN_bn2hex(serial_bn);
15193 BN_free(serial_bn);
15194
15195 /* Translate subject and issuer to a string */
15196 (void)X509_NAME_oneline(subj, str_subject, (int)sizeof(str_subject));
15197 (void)X509_NAME_oneline(iss, str_issuer, (int)sizeof(str_issuer));
15198
15199 /* Calculate SHA1 fingerprint and store as a hex string */
15200 ulen = 0;
15201
15202 /* ASN1_digest is deprecated. Do the calculation manually,
15203 * using EVP_Digest. */
15204 ilen = i2d_X509(cert, NULL);
15205 tmp_buf = (ilen > 0)
15206 ? (unsigned char *)mg_malloc_ctx((unsigned)ilen + 1,
15207 conn->phys_ctx)
15208 : NULL;
15209 if (tmp_buf) {
15210 tmp_p = tmp_buf;
15211 (void)i2d_X509(cert, &tmp_p);
15212 if (!EVP_Digest(
15213 tmp_buf, (unsigned)ilen, buf, &ulen, digest, NULL)) {
15214 ulen = 0;
15215 }
15216 mg_free(tmp_buf);
15217 }
15218
15219 if (!hexdump2string(
15220 buf, (int)ulen, str_finger, (int)sizeof(str_finger))) {
15221 *str_finger = 0;
15222 }
15223
15224 conn->request_info.client_cert = (struct mg_client_cert *)
15225 mg_malloc_ctx(sizeof(struct mg_client_cert), conn->phys_ctx);
15226 if (conn->request_info.client_cert) {
15227 conn->request_info.client_cert->peer_cert = (void *)cert;
15228 conn->request_info.client_cert->subject =
15229 mg_strdup_ctx(str_subject, conn->phys_ctx);
15230 conn->request_info.client_cert->issuer =
15231 mg_strdup_ctx(str_issuer, conn->phys_ctx);
15232 conn->request_info.client_cert->serial =
15233 mg_strdup_ctx(str_serial, conn->phys_ctx);
15234 conn->request_info.client_cert->finger =
15235 mg_strdup_ctx(str_finger, conn->phys_ctx);
15236 } else {
15237 mg_cry_internal(conn,
15238 "%s",
15239 "Out of memory: Cannot allocate memory for client "
15240 "certificate");
15241 }
15242
15243 /* Strings returned from bn_bn2hex must be freed using OPENSSL_free,
15244 * see https://linux.die.net/man/3/bn_bn2hex */
15245 OPENSSL_free(str_serial);
15246 }
15247}
15248
15249
15250#if defined(OPENSSL_API_1_1)
15251#else
15252static void
15253ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
15254{
15255 (void)line;
15256 (void)file;
15257
15258 if (mode & 1) {
15259 /* 1 is CRYPTO_LOCK */
15260 (void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
15261 } else {
15262 (void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
15263 }
15264}
15265#endif /* OPENSSL_API_1_1 */
15266
15267
15268#if !defined(NO_SSL_DL)
15269static void *
15270load_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw)
15271{
15272 union {
15273 void *p;
15274 void (*fp)(void);
15275 } u;
15276 void *dll_handle;
15277 struct ssl_func *fp;
15278 int ok;
15279 int truncated = 0;
15280
15281 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
15282 mg_snprintf(NULL,
15283 NULL, /* No truncation check for ebuf */
15284 ebuf,
15285 ebuf_len,
15286 "%s: cannot load %s",
15287 __func__,
15288 dll_name);
15289 return NULL;
15290 }
15291
15292 ok = 1;
15293 for (fp = sw; fp->name != NULL; fp++) {
15294#if defined(_WIN32)
15295 /* GetProcAddress() returns pointer to function */
15296 u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
15297#else
15298 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
15299 * pointers to function pointers. We need to use a union to make a
15300 * cast. */
15301 u.p = dlsym(dll_handle, fp->name);
15302#endif /* _WIN32 */
15303 if (u.fp == NULL) {
15304 if (ok) {
15305 mg_snprintf(NULL,
15306 &truncated,
15307 ebuf,
15308 ebuf_len,
15309 "%s: %s: cannot find %s",
15310 __func__,
15311 dll_name,
15312 fp->name);
15313 ok = 0;
15314 } else {
15315 size_t cur_len = strlen(ebuf);
15316 if (!truncated) {
15317 mg_snprintf(NULL,
15318 &truncated,
15319 ebuf + cur_len,
15320 ebuf_len - cur_len - 3,
15321 ", %s",
15322 fp->name);
15323 if (truncated) {
15324 /* If truncated, add "..." */
15325 strcat(ebuf, "...");
15326 }
15327 }
15328 }
15329 /* Debug:
15330 * printf("Missing function: %s\n", fp->name); */
15331 } else {
15332 fp->ptr = u.fp;
15333 }
15334 }
15335
15336 if (!ok) {
15337 (void)dlclose(dll_handle);
15338 return NULL;
15339 }
15340
15341 return dll_handle;
15342}
15343
15344
15345static void *ssllib_dll_handle; /* Store the ssl library handle. */
15346static void *cryptolib_dll_handle; /* Store the crypto library handle. */
15347
15348#endif /* NO_SSL_DL */
15349
15350
15351#if defined(SSL_ALREADY_INITIALIZED)
15352static int cryptolib_users = 1; /* Reference counter for crypto library. */
15353#else
15354static int cryptolib_users = 0; /* Reference counter for crypto library. */
15355#endif
15356
15357
15358static int
15359initialize_ssl(char *ebuf, size_t ebuf_len)
15360{
15361#if defined(OPENSSL_API_1_1)
15362 if (ebuf_len > 0) {
15363 ebuf[0] = 0;
15364 }
15365
15366#if !defined(NO_SSL_DL)
15367 if (!cryptolib_dll_handle) {
15369 if (!cryptolib_dll_handle) {
15370 mg_snprintf(NULL,
15371 NULL, /* No truncation check for ebuf */
15372 ebuf,
15373 ebuf_len,
15374 "%s: error loading library %s",
15375 __func__,
15376 CRYPTO_LIB);
15377 DEBUG_TRACE("%s", ebuf);
15378 return 0;
15379 }
15380 }
15381#endif /* NO_SSL_DL */
15382
15383 if (mg_atomic_inc(&cryptolib_users) > 1) {
15384 return 1;
15385 }
15386
15387#else /* not OPENSSL_API_1_1 */
15388 int i, num_locks;
15389 size_t size;
15390
15391 if (ebuf_len > 0) {
15392 ebuf[0] = 0;
15393 }
15394
15395#if !defined(NO_SSL_DL)
15396 if (!cryptolib_dll_handle) {
15398 if (!cryptolib_dll_handle) {
15399 mg_snprintf(NULL,
15400 NULL, /* No truncation check for ebuf */
15401 ebuf,
15402 ebuf_len,
15403 "%s: error loading library %s",
15404 __func__,
15405 CRYPTO_LIB);
15406 DEBUG_TRACE("%s", ebuf);
15407 return 0;
15408 }
15409 }
15410#endif /* NO_SSL_DL */
15411
15412 if (mg_atomic_inc(&cryptolib_users) > 1) {
15413 return 1;
15414 }
15415
15416 /* Initialize locking callbacks, needed for thread safety.
15417 * http://www.openssl.org/support/faq.html#PROG1
15418 */
15419 num_locks = CRYPTO_num_locks();
15420 if (num_locks < 0) {
15421 num_locks = 0;
15422 }
15423 size = sizeof(pthread_mutex_t) * ((size_t)(num_locks));
15424
15425 /* allocate mutex array, if required */
15426 if (num_locks == 0) {
15427 /* No mutex array required */
15428 ssl_mutexes = NULL;
15429 } else {
15430 /* Mutex array required - allocate it */
15431 ssl_mutexes = (pthread_mutex_t *)mg_malloc(size);
15432
15433 /* Check OOM */
15434 if (ssl_mutexes == NULL) {
15435 mg_snprintf(NULL,
15436 NULL, /* No truncation check for ebuf */
15437 ebuf,
15438 ebuf_len,
15439 "%s: cannot allocate mutexes: %s",
15440 __func__,
15441 ssl_error());
15442 DEBUG_TRACE("%s", ebuf);
15443 return 0;
15444 }
15445
15446 /* initialize mutex array */
15447 for (i = 0; i < num_locks; i++) {
15448 if (0 != pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr)) {
15449 mg_snprintf(NULL,
15450 NULL, /* No truncation check for ebuf */
15451 ebuf,
15452 ebuf_len,
15453 "%s: error initializing mutex %i of %i",
15454 __func__,
15455 i,
15456 num_locks);
15457 DEBUG_TRACE("%s", ebuf);
15459 return 0;
15460 }
15461 }
15462 }
15463
15466#endif /* OPENSSL_API_1_1 */
15467
15468#if !defined(NO_SSL_DL)
15469 if (!ssllib_dll_handle) {
15470 ssllib_dll_handle = load_dll(ebuf, ebuf_len, SSL_LIB, ssl_sw);
15471 if (!ssllib_dll_handle) {
15472#if !defined(OPENSSL_API_1_1)
15474#endif
15475 DEBUG_TRACE("%s", ebuf);
15476 return 0;
15477 }
15478 }
15479#endif /* NO_SSL_DL */
15480
15481#if defined(OPENSSL_API_1_1)
15482 /* Initialize SSL library */
15483 OPENSSL_init_ssl(0, NULL);
15484 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
15486 NULL);
15487#else
15488 /* Initialize SSL library */
15491#endif
15492
15493 return 1;
15494}
15495
15496
15497static int
15498ssl_use_pem_file(struct mg_context *phys_ctx,
15499 struct mg_domain_context *dom_ctx,
15500 const char *pem,
15501 const char *chain)
15502{
15503 if (SSL_CTX_use_certificate_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
15504 mg_cry_internal(fc(phys_ctx),
15505 "%s: cannot open certificate file %s: %s",
15506 __func__,
15507 pem,
15508 ssl_error());
15509 return 0;
15510 }
15511
15512 /* could use SSL_CTX_set_default_passwd_cb_userdata */
15513 if (SSL_CTX_use_PrivateKey_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
15514 mg_cry_internal(fc(phys_ctx),
15515 "%s: cannot open private key file %s: %s",
15516 __func__,
15517 pem,
15518 ssl_error());
15519 return 0;
15520 }
15521
15522 if (SSL_CTX_check_private_key(dom_ctx->ssl_ctx) == 0) {
15523 mg_cry_internal(fc(phys_ctx),
15524 "%s: certificate and private key do not match: %s",
15525 __func__,
15526 pem);
15527 return 0;
15528 }
15529
15530 /* In contrast to OpenSSL, wolfSSL does not support certificate
15531 * chain files that contain private keys and certificates in
15532 * SSL_CTX_use_certificate_chain_file.
15533 * The CivetWeb-Server used pem-Files that contained both information.
15534 * In order to make wolfSSL work, it is split in two files.
15535 * One file that contains key and certificate used by the server and
15536 * an optional chain file for the ssl stack.
15537 */
15538 if (chain) {
15539 if (SSL_CTX_use_certificate_chain_file(dom_ctx->ssl_ctx, chain) == 0) {
15540 mg_cry_internal(fc(phys_ctx),
15541 "%s: cannot use certificate chain file %s: %s",
15542 __func__,
15543 pem,
15544 ssl_error());
15545 return 0;
15546 }
15547 }
15548 return 1;
15549}
15550
15551
15552#if defined(OPENSSL_API_1_1)
15553static unsigned long
15554ssl_get_protocol(int version_id)
15555{
15556 long unsigned ret = (long unsigned)SSL_OP_ALL;
15557 if (version_id > 0)
15558 ret |= SSL_OP_NO_SSLv2;
15559 if (version_id > 1)
15560 ret |= SSL_OP_NO_SSLv3;
15561 if (version_id > 2)
15562 ret |= SSL_OP_NO_TLSv1;
15563 if (version_id > 3)
15564 ret |= SSL_OP_NO_TLSv1_1;
15565 return ret;
15566}
15567#else
15568static long
15569ssl_get_protocol(int version_id)
15570{
15571 long ret = (long)SSL_OP_ALL;
15572 if (version_id > 0)
15573 ret |= SSL_OP_NO_SSLv2;
15574 if (version_id > 1)
15575 ret |= SSL_OP_NO_SSLv3;
15576 if (version_id > 2)
15577 ret |= SSL_OP_NO_TLSv1;
15578 if (version_id > 3)
15579 ret |= SSL_OP_NO_TLSv1_1;
15580 return ret;
15581}
15582#endif /* OPENSSL_API_1_1 */
15583
15584
15585/* SSL callback documentation:
15586 * https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_info_callback.html
15587 * https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_info_callback(3)
15588 * https://linux.die.net/man/3/ssl_set_info_callback */
15589/* Note: There is no "const" for the first argument in the documentation
15590 * examples, however some (maybe most, but not all) headers of OpenSSL versions
15591 * / OpenSSL compatibility layers have it. Having a different definition will
15592 * cause a warning in C and an error in C++. Use "const SSL *", while
15593 * automatical conversion from "SSL *" works for all compilers, but not other
15594 * way around */
15595static void
15596ssl_info_callback(const SSL *ssl, int what, int ret)
15597{
15598 (void)ret;
15599
15601 SSL_get_app_data(ssl);
15602 }
15604 /* TODO: check for openSSL 1.1 */
15605 //#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001
15606 // ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
15607 }
15608}
15609
15610
15611static int
15612ssl_servername_callback(SSL *ssl, int *ad, void *arg)
15613{
15614 struct mg_context *ctx = (struct mg_context *)arg;
15615 struct mg_domain_context *dom =
15616 (struct mg_domain_context *)ctx ? &(ctx->dd) : NULL;
15617
15618#if defined(GCC_DIAGNOSTIC)
15619#pragma GCC diagnostic push
15620#pragma GCC diagnostic ignored "-Wcast-align"
15621#endif /* defined(GCC_DIAGNOSTIC) */
15622
15623 /* We used an aligned pointer in SSL_set_app_data */
15624 struct mg_connection *conn = (struct mg_connection *)SSL_get_app_data(ssl);
15625
15626#if defined(GCC_DIAGNOSTIC)
15627#pragma GCC diagnostic pop
15628#endif /* defined(GCC_DIAGNOSTIC) */
15629
15630 const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
15631
15632 (void)ad;
15633
15634 if ((ctx == NULL) || (conn->phys_ctx == ctx)) {
15635 DEBUG_TRACE("%s", "internal error - assertion failed");
15636 return SSL_TLSEXT_ERR_NOACK;
15637 }
15638
15639 /* Old clients (Win XP) will not support SNI. Then, there
15640 * is no server name available in the request - we can
15641 * only work with the default certificate.
15642 * Multiple HTTPS hosts on one IP+port are only possible
15643 * with a certificate containing all alternative names.
15644 */
15645 if ((servername == NULL) || (*servername == 0)) {
15646 DEBUG_TRACE("%s", "SSL connection not supporting SNI");
15647 conn->dom_ctx = &(ctx->dd);
15648 SSL_set_SSL_CTX(ssl, conn->dom_ctx->ssl_ctx);
15649 return SSL_TLSEXT_ERR_NOACK;
15650 }
15651
15652 DEBUG_TRACE("TLS connection to host %s", servername);
15653
15654 while (dom) {
15655 if (!mg_strcasecmp(servername, dom->config[AUTHENTICATION_DOMAIN])) {
15656
15657 /* Found matching domain */
15658 DEBUG_TRACE("TLS domain %s found",
15659 dom->config[AUTHENTICATION_DOMAIN]);
15660 SSL_set_SSL_CTX(ssl, dom->ssl_ctx);
15661 conn->dom_ctx = dom;
15662 return SSL_TLSEXT_ERR_OK;
15663 }
15664 dom = dom->next;
15665 }
15666
15667 /* Default domain */
15668 DEBUG_TRACE("TLS default domain %s used",
15669 ctx->dd.config[AUTHENTICATION_DOMAIN]);
15670 conn->dom_ctx = &(ctx->dd);
15671 SSL_set_SSL_CTX(ssl, conn->dom_ctx->ssl_ctx);
15672 return SSL_TLSEXT_ERR_OK;
15673}
15674
15675
15676/* Setup SSL CTX as required by CivetWeb */
15677static int
15678init_ssl_ctx_impl(struct mg_context *phys_ctx,
15679 struct mg_domain_context *dom_ctx,
15680 const char *pem,
15681 const char *chain)
15682{
15683 int callback_ret;
15684 int should_verify_peer;
15685 int peer_certificate_optional;
15686 const char *ca_path;
15687 const char *ca_file;
15688 int use_default_verify_paths;
15689 int verify_depth;
15690 struct timespec now_mt;
15691 md5_byte_t ssl_context_id[16];
15692 md5_state_t md5state;
15693 int protocol_ver;
15694
15695#if defined(OPENSSL_API_1_1)
15696 if ((dom_ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
15697 mg_cry_internal(fc(phys_ctx),
15698 "SSL_CTX_new (server) error: %s",
15699 ssl_error());
15700 return 0;
15701 }
15702#else
15703 if ((dom_ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
15704 mg_cry_internal(fc(phys_ctx),
15705 "SSL_CTX_new (server) error: %s",
15706 ssl_error());
15707 return 0;
15708 }
15709#endif /* OPENSSL_API_1_1 */
15710
15711 SSL_CTX_clear_options(dom_ctx->ssl_ctx,
15714 protocol_ver = atoi(dom_ctx->config[SSL_PROTOCOL_VERSION]);
15715 SSL_CTX_set_options(dom_ctx->ssl_ctx, ssl_get_protocol(protocol_ver));
15716 SSL_CTX_set_options(dom_ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE);
15718 SSL_CTX_set_options(dom_ctx->ssl_ctx,
15720 SSL_CTX_set_options(dom_ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
15721#if !defined(NO_SSL_DL)
15722 SSL_CTX_set_ecdh_auto(dom_ctx->ssl_ctx, 1);
15723#endif /* NO_SSL_DL */
15724
15725 /* In SSL documentation examples callback defined without const specifier
15726 * 'void (*)(SSL *, int, int)' See:
15727 * https://www.openssl.org/docs/man1.0.2/ssl/ssl.html
15728 * https://www.openssl.org/docs/man1.1.0/ssl/ssl.html
15729 * But in the source code const SSL is used:
15730 * 'void (*)(const SSL *, int, int)' See:
15731 * https://github.com/openssl/openssl/blob/1d97c8435171a7af575f73c526d79e1ef0ee5960/ssl/ssl.h#L1173
15732 * Problem about wrong documentation described, but not resolved:
15733 * https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1147526
15734 * Wrong const cast ignored on C or can be suppressed by compiler flags.
15735 * But when compiled with modern C++ compiler, correct const should be
15736 * provided
15737 */
15739
15742 SSL_CTX_set_tlsext_servername_arg(dom_ctx->ssl_ctx, phys_ctx);
15743
15744 /* If a callback has been specified, call it. */
15745 callback_ret = (phys_ctx->callbacks.init_ssl == NULL)
15746 ? 0
15747 : (phys_ctx->callbacks.init_ssl(dom_ctx->ssl_ctx,
15748 phys_ctx->user_data));
15749
15750 /* If callback returns 0, civetweb sets up the SSL certificate.
15751 * If it returns 1, civetweb assumes the calback already did this.
15752 * If it returns -1, initializing ssl fails. */
15753 if (callback_ret < 0) {
15754 mg_cry_internal(fc(phys_ctx),
15755 "SSL callback returned error: %i",
15756 callback_ret);
15757 return 0;
15758 }
15759 if (callback_ret > 0) {
15760 /* Callback did everything. */
15761 return 1;
15762 }
15763
15764 /* Use some combination of start time, domain and port as a SSL
15765 * context ID. This should be unique on the current machine. */
15766 md5_init(&md5state);
15767 clock_gettime(CLOCK_MONOTONIC, &now_mt);
15768 md5_append(&md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt));
15769 md5_append(&md5state,
15770 (const md5_byte_t *)phys_ctx->dd.config[LISTENING_PORTS],
15771 strlen(phys_ctx->dd.config[LISTENING_PORTS]));
15772 md5_append(&md5state,
15773 (const md5_byte_t *)dom_ctx->config[AUTHENTICATION_DOMAIN],
15774 strlen(dom_ctx->config[AUTHENTICATION_DOMAIN]));
15775 md5_append(&md5state, (const md5_byte_t *)phys_ctx, sizeof(*phys_ctx));
15776 md5_append(&md5state, (const md5_byte_t *)dom_ctx, sizeof(*dom_ctx));
15777 md5_finish(&md5state, ssl_context_id);
15778
15779 SSL_CTX_set_session_id_context(dom_ctx->ssl_ctx,
15780 (unsigned char *)ssl_context_id,
15781 sizeof(ssl_context_id));
15782
15783 if (pem != NULL) {
15784 if (!ssl_use_pem_file(phys_ctx, dom_ctx, pem, chain)) {
15785 return 0;
15786 }
15787 }
15788
15789 /* Should we support client certificates? */
15790 /* Default is "no". */
15791 should_verify_peer = 0;
15792 peer_certificate_optional = 0;
15793 if (dom_ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
15794 if (mg_strcasecmp(dom_ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0) {
15795 /* Yes, they are mandatory */
15796 should_verify_peer = 1;
15797 peer_certificate_optional = 0;
15798 } else if (mg_strcasecmp(dom_ctx->config[SSL_DO_VERIFY_PEER],
15799 "optional")
15800 == 0) {
15801 /* Yes, they are optional */
15802 should_verify_peer = 1;
15803 peer_certificate_optional = 1;
15804 }
15805 }
15806
15807 use_default_verify_paths =
15808 (dom_ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
15809 && (mg_strcasecmp(dom_ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes")
15810 == 0);
15811
15812 if (should_verify_peer) {
15813 ca_path = dom_ctx->config[SSL_CA_PATH];
15814 ca_file = dom_ctx->config[SSL_CA_FILE];
15815 if (SSL_CTX_load_verify_locations(dom_ctx->ssl_ctx, ca_file, ca_path)
15816 != 1) {
15817 mg_cry_internal(fc(phys_ctx),
15818 "SSL_CTX_load_verify_locations error: %s "
15819 "ssl_verify_peer requires setting "
15820 "either ssl_ca_path or ssl_ca_file. "
15821 "Is any of them present in the "
15822 ".conf file?",
15823 ssl_error());
15824 return 0;
15825 }
15826
15827 if (peer_certificate_optional) {
15828 SSL_CTX_set_verify(dom_ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
15829 } else {
15830 SSL_CTX_set_verify(dom_ctx->ssl_ctx,
15833 NULL);
15834 }
15835
15836 if (use_default_verify_paths
15837 && (SSL_CTX_set_default_verify_paths(dom_ctx->ssl_ctx) != 1)) {
15838 mg_cry_internal(fc(phys_ctx),
15839 "SSL_CTX_set_default_verify_paths error: %s",
15840 ssl_error());
15841 return 0;
15842 }
15843
15844 if (dom_ctx->config[SSL_VERIFY_DEPTH]) {
15845 verify_depth = atoi(dom_ctx->config[SSL_VERIFY_DEPTH]);
15846 SSL_CTX_set_verify_depth(dom_ctx->ssl_ctx, verify_depth);
15847 }
15848 }
15849
15850 if (dom_ctx->config[SSL_CIPHER_LIST] != NULL) {
15851 if (SSL_CTX_set_cipher_list(dom_ctx->ssl_ctx,
15852 dom_ctx->config[SSL_CIPHER_LIST])
15853 != 1) {
15854 mg_cry_internal(fc(phys_ctx),
15855 "SSL_CTX_set_cipher_list error: %s",
15856 ssl_error());
15857 }
15858 }
15859
15860 return 1;
15861}
15862
15863
15864/* Check if SSL is required.
15865 * If so, dynamically load SSL library
15866 * and set up ctx->ssl_ctx pointer. */
15867static int
15868init_ssl_ctx(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
15869{
15870 void *ssl_ctx = 0;
15871 int callback_ret;
15872 const char *pem;
15873 const char *chain;
15874 char ebuf[128];
15875
15876 if (!phys_ctx) {
15877 return 0;
15878 }
15879
15880 if (!dom_ctx) {
15881 dom_ctx = &(phys_ctx->dd);
15882 }
15883
15884 if (!is_ssl_port_used(dom_ctx->config[LISTENING_PORTS])) {
15885 /* No SSL port is set. No need to setup SSL. */
15886 return 1;
15887 }
15888
15889 /* Check for external SSL_CTX */
15890 callback_ret =
15891 (phys_ctx->callbacks.external_ssl_ctx == NULL)
15892 ? 0
15893 : (phys_ctx->callbacks.external_ssl_ctx(&ssl_ctx,
15894 phys_ctx->user_data));
15895
15896 if (callback_ret < 0) {
15897 mg_cry_internal(fc(phys_ctx),
15898 "external_ssl_ctx callback returned error: %i",
15899 callback_ret);
15900 return 0;
15901 } else if (callback_ret > 0) {
15902 dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
15903 if (!initialize_ssl(ebuf, sizeof(ebuf))) {
15904 mg_cry_internal(fc(phys_ctx), "%s", ebuf);
15905 return 0;
15906 }
15907 return 1;
15908 }
15909 /* else: external_ssl_ctx does not exist or returns 0,
15910 * CivetWeb should continue initializing SSL */
15911
15912 /* If PEM file is not specified and the init_ssl callback
15913 * is not specified, setup will fail. */
15914 if (((pem = dom_ctx->config[SSL_CERTIFICATE]) == NULL)
15915 && (phys_ctx->callbacks.init_ssl == NULL)) {
15916 /* No certificate and no callback:
15917 * Essential data to set up TLS is missing.
15918 */
15919 mg_cry_internal(fc(phys_ctx),
15920 "Initializing SSL failed: -%s is not set",
15922 return 0;
15923 }
15924
15925 chain = dom_ctx->config[SSL_CERTIFICATE_CHAIN];
15926 if (chain == NULL) {
15927 chain = pem;
15928 }
15929 if ((chain != NULL) && (*chain == 0)) {
15930 chain = NULL;
15931 }
15932
15933 if (!initialize_ssl(ebuf, sizeof(ebuf))) {
15934 mg_cry_internal(fc(phys_ctx), "%s", ebuf);
15935 return 0;
15936 }
15937
15938 return init_ssl_ctx_impl(phys_ctx, dom_ctx, pem, chain);
15939}
15940
15941
15942static void
15944{
15945#if defined(OPENSSL_API_1_1)
15946
15947 if (mg_atomic_dec(&cryptolib_users) == 0) {
15948
15949 /* Shutdown according to
15950 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
15951 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
15952 */
15954#else
15955 int i;
15956
15957 if (mg_atomic_dec(&cryptolib_users) == 0) {
15958
15959 /* Shutdown according to
15960 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
15961 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
15962 */
15968 EVP_cleanup();
15971
15972 for (i = 0; i < CRYPTO_num_locks(); i++) {
15973 pthread_mutex_destroy(&ssl_mutexes[i]);
15974 }
15976 ssl_mutexes = NULL;
15977#endif /* OPENSSL_API_1_1 */
15978 }
15979}
15980#endif /* !NO_SSL */
15981
15982
15983static int
15984set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
15985{
15986 if (phys_ctx) {
15987 struct mg_file file = STRUCT_FILE_INITIALIZER;
15988 const char *path;
15989 if (!dom_ctx) {
15990 dom_ctx = &(phys_ctx->dd);
15991 }
15992 path = dom_ctx->config[GLOBAL_PASSWORDS_FILE];
15993 if ((path != NULL) && !mg_stat(fc(phys_ctx), path, &file.stat)) {
15994 mg_cry_internal(fc(phys_ctx),
15995 "Cannot open %s: %s",
15996 path,
15997 strerror(ERRNO));
15998 return 0;
15999 }
16000 return 1;
16001 }
16002 return 0;
16003}
16004
16005
16006static int
16007set_acl_option(struct mg_context *phys_ctx)
16008{
16009 return check_acl(phys_ctx, (uint32_t)0x7f000001UL) != -1;
16010}
16011
16012
16013static void
16014reset_per_request_attributes(struct mg_connection *conn)
16015{
16016 if (!conn) {
16017 return;
16018 }
16019 conn->connection_type =
16020 CONNECTION_TYPE_INVALID; /* Not yet a valid request/response */
16021
16022 conn->num_bytes_sent = conn->consumed_content = 0;
16023
16024 conn->path_info = NULL;
16025 conn->status_code = -1;
16026 conn->content_len = -1;
16027 conn->is_chunked = 0;
16028 conn->must_close = 0;
16029 conn->request_len = 0;
16030 conn->throttle = 0;
16031 conn->data_len = 0;
16032 conn->chunk_remainder = 0;
16033 conn->accept_gzip = 0;
16034
16035 conn->response_info.content_length = conn->request_info.content_length = -1;
16036 conn->response_info.http_version = conn->request_info.http_version = NULL;
16037 conn->response_info.num_headers = conn->request_info.num_headers = 0;
16038 conn->response_info.status_text = NULL;
16039 conn->response_info.status_code = 0;
16040
16041 conn->request_info.remote_user = NULL;
16042 conn->request_info.request_method = NULL;
16043 conn->request_info.request_uri = NULL;
16044 conn->request_info.local_uri = NULL;
16045
16046#if defined(MG_LEGACY_INTERFACE)
16047 /* Legacy before split into local_uri and request_uri */
16048 conn->request_info.uri = NULL;
16049#endif
16050}
16051
16052
16053#if 0
16054/* Note: set_sock_timeout is not required for non-blocking sockets.
16055 * Leave this function here (commented out) for reference until
16056 * CivetWeb 1.9 is tested, and the tests confirme this function is
16057 * no longer required.
16058*/
16059static int
16060set_sock_timeout(SOCKET sock, int milliseconds)
16061{
16062 int r0 = 0, r1, r2;
16063
16064#if defined(_WIN32)
16065 /* Windows specific */
16066
16067 DWORD tv = (DWORD)milliseconds;
16068
16069#else
16070 /* Linux, ... (not Windows) */
16071
16072 struct timeval tv;
16073
16074/* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
16075 * max. time waiting for the acknowledged of TCP data before the connection
16076 * will be forcefully closed and ETIMEDOUT is returned to the application.
16077 * If this option is not set, the default timeout of 20-30 minutes is used.
16078*/
16079/* #define TCP_USER_TIMEOUT (18) */
16080
16081#if defined(TCP_USER_TIMEOUT)
16082 unsigned int uto = (unsigned int)milliseconds;
16083 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (const void *)&uto, sizeof(uto));
16084#endif
16085
16086 memset(&tv, 0, sizeof(tv));
16087 tv.tv_sec = milliseconds / 1000;
16088 tv.tv_usec = (milliseconds * 1000) % 1000000;
16089
16090#endif /* _WIN32 */
16091
16092 r1 = setsockopt(
16093 sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
16094 r2 = setsockopt(
16095 sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
16096
16097 return r0 || r1 || r2;
16098}
16099#endif
16100
16101
16102static int
16103set_tcp_nodelay(SOCKET sock, int nodelay_on)
16104{
16105 if (setsockopt(sock,
16106 IPPROTO_TCP,
16107 TCP_NODELAY,
16108 (SOCK_OPT_TYPE)&nodelay_on,
16109 sizeof(nodelay_on))
16110 != 0) {
16111 /* Error */
16112 return 1;
16113 }
16114 /* OK */
16115 return 0;
16116}
16117
16118
16119static void
16120close_socket_gracefully(struct mg_connection *conn)
16121{
16122#if defined(_WIN32)
16123 char buf[MG_BUF_LEN];
16124 int n;
16125#endif
16126 struct linger linger;
16127 int error_code = 0;
16128 int linger_timeout = -2;
16129 socklen_t opt_len = sizeof(error_code);
16130
16131 if (!conn) {
16132 return;
16133 }
16134
16135 /* http://msdn.microsoft.com/en-us/library/ms739165(v=vs.85).aspx:
16136 * "Note that enabling a nonzero timeout on a nonblocking socket
16137 * is not recommended.", so set it to blocking now */
16138 set_blocking_mode(conn->client.sock);
16139
16140 /* Send FIN to the client */
16141 shutdown(conn->client.sock, SHUTDOWN_WR);
16142
16143
16144#if defined(_WIN32)
16145 /* Read and discard pending incoming data. If we do not do that and
16146 * close
16147 * the socket, the data in the send buffer may be discarded. This
16148 * behaviour is seen on Windows, when client keeps sending data
16149 * when server decides to close the connection; then when client
16150 * does recv() it gets no data back. */
16151 do {
16152 n = pull_inner(NULL, conn, buf, sizeof(buf), /* Timeout in s: */ 1.0);
16153 } while (n > 0);
16154#endif
16155
16156 if (conn->dom_ctx->config[LINGER_TIMEOUT]) {
16157 linger_timeout = atoi(conn->dom_ctx->config[LINGER_TIMEOUT]);
16158 }
16159
16160 /* Set linger option according to configuration */
16161 if (linger_timeout >= 0) {
16162 /* Set linger option to avoid socket hanging out after close. This
16163 * prevent ephemeral port exhaust problem under high QPS. */
16164 linger.l_onoff = 1;
16165
16166#if defined(_MSC_VER)
16167#pragma warning(push)
16168#pragma warning(disable : 4244)
16169#endif
16170#if defined(GCC_DIAGNOSTIC)
16171#pragma GCC diagnostic push
16172#pragma GCC diagnostic ignored "-Wconversion"
16173#endif
16174 /* Data type of linger structure elements may differ,
16175 * so we don't know what cast we need here.
16176 * Disable type conversion warnings. */
16177
16178 linger.l_linger = (linger_timeout + 999) / 1000;
16179
16180#if defined(GCC_DIAGNOSTIC)
16181#pragma GCC diagnostic pop
16182#endif
16183#if defined(_MSC_VER)
16184#pragma warning(pop)
16185#endif
16186
16187 } else {
16188 linger.l_onoff = 0;
16189 linger.l_linger = 0;
16190 }
16191
16192 if (linger_timeout < -1) {
16193 /* Default: don't configure any linger */
16194 } else if (getsockopt(conn->client.sock,
16195 SOL_SOCKET,
16196 SO_ERROR,
16197#if defined(_WIN32) /* WinSock uses different data type here */
16198 (char *)&error_code,
16199#else
16200 &error_code,
16201#endif
16202 &opt_len)
16203 != 0) {
16204 /* Cannot determine if socket is already closed. This should
16205 * not occur and never did in a test. Log an error message
16206 * and continue. */
16207 mg_cry_internal(conn,
16208 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
16209 __func__,
16210 strerror(ERRNO));
16211 } else if (error_code == ECONNRESET) {
16212 /* Socket already closed by client/peer, close socket without linger
16213 */
16214 } else {
16215
16216 /* Set linger timeout */
16217 if (setsockopt(conn->client.sock,
16218 SOL_SOCKET,
16219 SO_LINGER,
16220 (char *)&linger,
16221 sizeof(linger))
16222 != 0) {
16224 conn,
16225 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
16226 __func__,
16227 linger.l_onoff,
16228 linger.l_linger,
16229 strerror(ERRNO));
16230 }
16231 }
16232
16233 /* Now we know that our FIN is ACK-ed, safe to close */
16234 closesocket(conn->client.sock);
16235 conn->client.sock = INVALID_SOCKET;
16236}
16237
16238
16239static void
16240close_connection(struct mg_connection *conn)
16241{
16242#if defined(USE_SERVER_STATS)
16243 conn->conn_state = 6; /* to close */
16244#endif
16245
16246#if defined(USE_LUA) && defined(USE_WEBSOCKET)
16247 if (conn->lua_websocket_state) {
16248 lua_websocket_close(conn, conn->lua_websocket_state);
16249 conn->lua_websocket_state = NULL;
16250 }
16251#endif
16252
16253 mg_lock_connection(conn);
16254
16255 /* Set close flag, so keep-alive loops will stop */
16256 conn->must_close = 1;
16257
16258 /* call the connection_close callback if assigned */
16259 if (conn->phys_ctx->callbacks.connection_close != NULL) {
16260 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
16261 conn->phys_ctx->callbacks.connection_close(conn);
16262 }
16263 }
16264
16265 /* Reset user data, after close callback is called.
16266 * Do not reuse it. If the user needs a destructor,
16267 * it must be done in the connection_close callback. */
16268 mg_set_user_connection_data(conn, NULL);
16269
16270
16271#if defined(USE_SERVER_STATS)
16272 conn->conn_state = 7; /* closing */
16273#endif
16274
16275#if !defined(NO_SSL)
16276 if (conn->ssl != NULL) {
16277 /* Run SSL_shutdown twice to ensure completely close SSL connection
16278 */
16279 SSL_shutdown(conn->ssl);
16280 SSL_free(conn->ssl);
16282 conn->ssl = NULL;
16283 }
16284#endif
16285 if (conn->client.sock != INVALID_SOCKET) {
16287 conn->client.sock = INVALID_SOCKET;
16288 }
16289
16290 if (conn->host) {
16291 mg_free((void *)conn->host);
16292 conn->host = NULL;
16293 }
16294
16296
16297#if defined(USE_SERVER_STATS)
16298 conn->conn_state = 8; /* closed */
16299#endif
16300}
16301
16302
16303void
16304mg_close_connection(struct mg_connection *conn)
16305{
16306#if defined(USE_WEBSOCKET)
16307 struct mg_context *client_ctx = NULL;
16308#endif /* defined(USE_WEBSOCKET) */
16309
16310 if ((conn == NULL) || (conn->phys_ctx == NULL)) {
16311 return;
16312 }
16313
16314#if defined(USE_WEBSOCKET)
16315 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
16316 if (conn->in_websocket_handling) {
16317 /* Set close flag, so the server thread can exit. */
16318 conn->must_close = 1;
16319 return;
16320 }
16321 }
16322 if (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT) {
16323
16324 unsigned int i;
16325
16326 /* ws/wss client */
16327 client_ctx = conn->phys_ctx;
16328
16329 /* client context: loops must end */
16330 client_ctx->stop_flag = 1;
16331 conn->must_close = 1;
16332
16333 /* We need to get the client thread out of the select/recv call
16334 * here. */
16335 /* Since we use a sleep quantum of some seconds to check for recv
16336 * timeouts, we will just wait a few seconds in mg_join_thread. */
16337
16338 /* join worker thread */
16339 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
16340 if (client_ctx->worker_threadids[i] != 0) {
16341 mg_join_thread(client_ctx->worker_threadids[i]);
16342 }
16343 }
16344 }
16345#endif /* defined(USE_WEBSOCKET) */
16346
16347 close_connection(conn);
16348
16349#if !defined(NO_SSL)
16350 if (conn->client_ssl_ctx != NULL) {
16351 SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx);
16352 }
16353#endif
16354
16355#if defined(USE_WEBSOCKET)
16356 if (client_ctx != NULL) {
16357 /* free context */
16358 mg_free(client_ctx->worker_threadids);
16359 mg_free(client_ctx);
16360 (void)pthread_mutex_destroy(&conn->mutex);
16361 mg_free(conn);
16362 } else if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) {
16363 mg_free(conn);
16364 }
16365#else
16366 if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) { /* Client */
16367 mg_free(conn);
16368 }
16369#endif /* defined(USE_WEBSOCKET) */
16370}
16371
16372
16373/* Only for memory statistics */
16374static struct mg_context common_client_context;
16375
16376
16377static struct mg_connection *
16378mg_connect_client_impl(const struct mg_client_options *client_options,
16379 int use_ssl,
16380 char *ebuf,
16381 size_t ebuf_len)
16382{
16383 struct mg_connection *conn = NULL;
16384 SOCKET sock;
16385 union usa sa;
16386 struct sockaddr *psa;
16387 socklen_t len;
16388
16389 unsigned max_req_size =
16390 (unsigned)atoi(config_options[MAX_REQUEST_SIZE].default_value);
16391
16392 /* Size of structures, aligned to 8 bytes */
16393 size_t conn_size = ((sizeof(struct mg_connection) + 7) >> 3) << 3;
16394 size_t ctx_size = ((sizeof(struct mg_context) + 7) >> 3) << 3;
16395
16396 conn = (struct mg_connection *)mg_calloc_ctx(
16397 1, conn_size + ctx_size + max_req_size, &common_client_context);
16398
16399 if (conn == NULL) {
16400 mg_snprintf(NULL,
16401 NULL, /* No truncation check for ebuf */
16402 ebuf,
16403 ebuf_len,
16404 "calloc(): %s",
16405 strerror(ERRNO));
16406 return NULL;
16407 }
16408
16409#if defined(GCC_DIAGNOSTIC)
16410#pragma GCC diagnostic push
16411#pragma GCC diagnostic ignored "-Wcast-align"
16412#endif /* defined(GCC_DIAGNOSTIC) */
16413 /* conn_size is aligned to 8 bytes */
16414
16415 conn->phys_ctx = (struct mg_context *)(((char *)conn) + conn_size);
16416
16417#if defined(GCC_DIAGNOSTIC)
16418#pragma GCC diagnostic pop
16419#endif /* defined(GCC_DIAGNOSTIC) */
16420
16421 conn->buf = (((char *)conn) + conn_size + ctx_size);
16422 conn->buf_size = (int)max_req_size;
16423 conn->phys_ctx->context_type = CONTEXT_HTTP_CLIENT;
16424 conn->dom_ctx = &(conn->phys_ctx->dd);
16425
16427 client_options->host,
16428 client_options->port,
16429 use_ssl,
16430 ebuf,
16431 ebuf_len,
16432 &sock,
16433 &sa)) {
16434 /* ebuf is set by connect_socket,
16435 * free all memory and return NULL; */
16436 mg_free(conn);
16437 return NULL;
16438 }
16439
16440#if !defined(NO_SSL)
16441#if defined(OPENSSL_API_1_1)
16442 if (use_ssl
16443 && (conn->client_ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
16444 mg_snprintf(NULL,
16445 NULL, /* No truncation check for ebuf */
16446 ebuf,
16447 ebuf_len,
16448 "SSL_CTX_new error");
16449 closesocket(sock);
16450 mg_free(conn);
16451 return NULL;
16452 }
16453#else
16454 if (use_ssl
16455 && (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
16456 == NULL) {
16457 mg_snprintf(NULL,
16458 NULL, /* No truncation check for ebuf */
16459 ebuf,
16460 ebuf_len,
16461 "SSL_CTX_new error");
16462 closesocket(sock);
16463 mg_free(conn);
16464 return NULL;
16465 }
16466#endif /* OPENSSL_API_1_1 */
16467#endif /* NO_SSL */
16468
16469
16470#if defined(USE_IPV6)
16471 len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin)
16472 : sizeof(conn->client.rsa.sin6);
16473 psa = (sa.sa.sa_family == AF_INET)
16474 ? (struct sockaddr *)&(conn->client.rsa.sin)
16475 : (struct sockaddr *)&(conn->client.rsa.sin6);
16476#else
16477 len = sizeof(conn->client.rsa.sin);
16478 psa = (struct sockaddr *)&(conn->client.rsa.sin);
16479#endif
16480
16481 conn->client.sock = sock;
16482 conn->client.lsa = sa;
16483
16484 if (getsockname(sock, psa, &len) != 0) {
16485 mg_cry_internal(conn,
16486 "%s: getsockname() failed: %s",
16487 __func__,
16488 strerror(ERRNO));
16489 }
16490
16491 conn->client.is_ssl = use_ssl ? 1 : 0;
16492 if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
16493 mg_snprintf(NULL,
16494 NULL, /* No truncation check for ebuf */
16495 ebuf,
16496 ebuf_len,
16497 "Can not create mutex");
16498#if !defined(NO_SSL)
16499 SSL_CTX_free(conn->client_ssl_ctx);
16500#endif
16501 closesocket(sock);
16502 mg_free(conn);
16503 return NULL;
16504 }
16505
16506
16507#if !defined(NO_SSL)
16508 if (use_ssl) {
16509 common_client_context.dd.ssl_ctx = conn->client_ssl_ctx;
16510
16511 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
16512 * SSL_CTX_set_verify call is needed to switch off server
16513 * certificate checking, which is off by default in OpenSSL and
16514 * on in yaSSL. */
16515 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
16516 * SSL_VERIFY_PEER, verify_ssl_server); */
16517
16518 if (client_options->client_cert) {
16521 client_options->client_cert,
16522 NULL)) {
16523 mg_snprintf(NULL,
16524 NULL, /* No truncation check for ebuf */
16525 ebuf,
16526 ebuf_len,
16527 "Can not use SSL client certificate");
16528 SSL_CTX_free(conn->client_ssl_ctx);
16529 closesocket(sock);
16530 mg_free(conn);
16531 return NULL;
16532 }
16533 }
16534
16535 if (client_options->server_cert) {
16536 SSL_CTX_load_verify_locations(conn->client_ssl_ctx,
16537 client_options->server_cert,
16538 NULL);
16539 SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_PEER, NULL);
16540 } else {
16541 SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_NONE, NULL);
16542 }
16543
16544 if (!sslize(conn,
16545 conn->client_ssl_ctx,
16547 &(conn->phys_ctx->stop_flag),
16548 client_options)) {
16549 mg_snprintf(NULL,
16550 NULL, /* No truncation check for ebuf */
16551 ebuf,
16552 ebuf_len,
16553 "SSL connection error");
16554 SSL_CTX_free(conn->client_ssl_ctx);
16555 closesocket(sock);
16556 mg_free(conn);
16557 return NULL;
16558 }
16559 }
16560#endif
16561
16562 if (0 != set_non_blocking_mode(sock)) {
16563 mg_cry_internal(conn,
16564 "Cannot set non-blocking mode for client %s:%i",
16565 client_options->host,
16566 client_options->port);
16567 }
16568
16569 return conn;
16570}
16571
16572
16573CIVETWEB_API struct mg_connection *
16574mg_connect_client_secure(const struct mg_client_options *client_options,
16575 char *error_buffer,
16576 size_t error_buffer_size)
16577{
16578 return mg_connect_client_impl(client_options,
16579 1,
16580 error_buffer,
16581 error_buffer_size);
16582}
16583
16584
16585struct mg_connection *
16586mg_connect_client(const char *host,
16587 int port,
16588 int use_ssl,
16589 char *error_buffer,
16590 size_t error_buffer_size)
16591{
16592 struct mg_client_options opts;
16593 memset(&opts, 0, sizeof(opts));
16594 opts.host = host;
16595 opts.port = port;
16596 return mg_connect_client_impl(&opts,
16597 use_ssl,
16598 error_buffer,
16599 error_buffer_size);
16600}
16601
16602
16603static const struct {
16604 const char *proto;
16607} abs_uri_protocols[] = {{"http://", 7, 80},
16608 {"https://", 8, 443},
16609 {"ws://", 5, 80},
16610 {"wss://", 6, 443},
16611 {NULL, 0, 0}};
16612
16613
16614/* Check if the uri is valid.
16615 * return 0 for invalid uri,
16616 * return 1 for *,
16617 * return 2 for relative uri,
16618 * return 3 for absolute uri without port,
16619 * return 4 for absolute uri with port */
16620static int
16621get_uri_type(const char *uri)
16622{
16623 int i;
16624 const char *hostend, *portbegin;
16625 char *portend;
16626 unsigned long port;
16627
16628 /* According to the HTTP standard
16629 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
16630 * URI can be an asterisk (*) or should start with slash (relative uri),
16631 * or it should start with the protocol (absolute uri). */
16632 if ((uri[0] == '*') && (uri[1] == '\0')) {
16633 /* asterisk */
16634 return 1;
16635 }
16636
16637 /* Valid URIs according to RFC 3986
16638 * (https://www.ietf.org/rfc/rfc3986.txt)
16639 * must only contain reserved characters :/?#[]@!$&'()*+,;=
16640 * and unreserved characters A-Z a-z 0-9 and -._~
16641 * and % encoded symbols.
16642 */
16643 for (i = 0; uri[i] != 0; i++) {
16644 if (uri[i] < 33) {
16645 /* control characters and spaces are invalid */
16646 return 0;
16647 }
16648 if (uri[i] > 126) {
16649 /* non-ascii characters must be % encoded */
16650 return 0;
16651 } else {
16652 switch (uri[i]) {
16653 case '"': /* 34 */
16654 case '<': /* 60 */
16655 case '>': /* 62 */
16656 case '\\': /* 92 */
16657 case '^': /* 94 */
16658 case '`': /* 96 */
16659 case '{': /* 123 */
16660 case '|': /* 124 */
16661 case '}': /* 125 */
16662 return 0;
16663 default:
16664 /* character is ok */
16665 break;
16666 }
16667 }
16668 }
16669
16670 /* A relative uri starts with a / character */
16671 if (uri[0] == '/') {
16672 /* relative uri */
16673 return 2;
16674 }
16675
16676 /* It could be an absolute uri: */
16677 /* This function only checks if the uri is valid, not if it is
16678 * addressing the current server. So civetweb can also be used
16679 * as a proxy server. */
16680 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
16681 if (mg_strncasecmp(uri,
16684 == 0) {
16685
16686 hostend = strchr(uri + abs_uri_protocols[i].proto_len, '/');
16687 if (!hostend) {
16688 return 0;
16689 }
16690 portbegin = strchr(uri + abs_uri_protocols[i].proto_len, ':');
16691 if (!portbegin) {
16692 return 3;
16693 }
16694
16695 port = strtoul(portbegin + 1, &portend, 10);
16696 if ((portend != hostend) || (port <= 0) || !is_valid_port(port)) {
16697 return 0;
16698 }
16699
16700 return 4;
16701 }
16702 }
16703
16704 return 0;
16705}
16706
16707
16708/* Return NULL or the relative uri at the current server */
16709static const char *
16710get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
16711{
16712 const char *server_domain;
16713 size_t server_domain_len;
16714 size_t request_domain_len = 0;
16715 unsigned long port = 0;
16716 int i, auth_domain_check_enabled;
16717 const char *hostbegin = NULL;
16718 const char *hostend = NULL;
16719 const char *portbegin;
16720 char *portend;
16721
16722 auth_domain_check_enabled =
16723 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes");
16724
16725 /* DNS is case insensitive, so use case insensitive string compare here
16726 */
16727 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
16728 if (mg_strncasecmp(uri,
16731 == 0) {
16732
16733 hostbegin = uri + abs_uri_protocols[i].proto_len;
16734 hostend = strchr(hostbegin, '/');
16735 if (!hostend) {
16736 return 0;
16737 }
16738 portbegin = strchr(hostbegin, ':');
16739 if ((!portbegin) || (portbegin > hostend)) {
16740 port = abs_uri_protocols[i].default_port;
16741 request_domain_len = (size_t)(hostend - hostbegin);
16742 } else {
16743 port = strtoul(portbegin + 1, &portend, 10);
16744 if ((portend != hostend) || (port <= 0)
16745 || !is_valid_port(port)) {
16746 return 0;
16747 }
16748 request_domain_len = (size_t)(portbegin - hostbegin);
16749 }
16750 /* protocol found, port set */
16751 break;
16752 }
16753 }
16754
16755 if (!port) {
16756 /* port remains 0 if the protocol is not found */
16757 return 0;
16758 }
16759
16760/* Check if the request is directed to a different server. */
16761/* First check if the port is the same (IPv4 and IPv6). */
16762#if defined(USE_IPV6)
16763 if (conn->client.lsa.sa.sa_family == AF_INET6) {
16764 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
16765 /* Request is directed to a different port */
16766 return 0;
16767 }
16768 } else
16769#endif
16770 {
16771 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
16772 /* Request is directed to a different port */
16773 return 0;
16774 }
16775 }
16776
16777 /* Finally check if the server corresponds to the authentication
16778 * domain of the server (the server domain).
16779 * Allow full matches (like http://mydomain.com/path/file.ext), and
16780 * allow subdomain matches (like http://www.mydomain.com/path/file.ext),
16781 * but do not allow substrings (like
16782 * http://notmydomain.com/path/file.ext
16783 * or http://mydomain.com.fake/path/file.ext).
16784 */
16785 if (auth_domain_check_enabled) {
16786 server_domain = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
16787 server_domain_len = strlen(server_domain);
16788 if ((server_domain_len == 0) || (hostbegin == NULL)) {
16789 return 0;
16790 }
16791 if ((request_domain_len == server_domain_len)
16792 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
16793 /* Request is directed to this server - full name match. */
16794 } else {
16795 if (request_domain_len < (server_domain_len + 2)) {
16796 /* Request is directed to another server: The server name
16797 * is longer than the request name.
16798 * Drop this case here to avoid overflows in the
16799 * following checks. */
16800 return 0;
16801 }
16802 if (hostbegin[request_domain_len - server_domain_len - 1] != '.') {
16803 /* Request is directed to another server: It could be a
16804 * substring
16805 * like notmyserver.com */
16806 return 0;
16807 }
16808 if (0
16809 != memcmp(server_domain,
16810 hostbegin + request_domain_len - server_domain_len,
16811 server_domain_len)) {
16812 /* Request is directed to another server:
16813 * The server name is different. */
16814 return 0;
16815 }
16816 }
16817 }
16818
16819 return hostend;
16820}
16821
16822
16823static int
16824get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
16825{
16826 if (ebuf_len > 0) {
16827 ebuf[0] = '\0';
16828 }
16829 *err = 0;
16830
16832
16833 if (!conn) {
16834 mg_snprintf(conn,
16835 NULL, /* No truncation check for ebuf */
16836 ebuf,
16837 ebuf_len,
16838 "%s",
16839 "Internal error");
16840 *err = 500;
16841 return 0;
16842 }
16843 /* Set the time the request was received. This value should be used for
16844 * timeouts. */
16845 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
16846
16847 conn->request_len =
16848 read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
16849 DEBUG_ASSERT(conn->request_len < 0 || conn->data_len >= conn->request_len);
16850 if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) {
16851 mg_snprintf(conn,
16852 NULL, /* No truncation check for ebuf */
16853 ebuf,
16854 ebuf_len,
16855 "%s",
16856 "Invalid message size");
16857 *err = 500;
16858 return 0;
16859 }
16860
16861 if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) {
16862 mg_snprintf(conn,
16863 NULL, /* No truncation check for ebuf */
16864 ebuf,
16865 ebuf_len,
16866 "%s",
16867 "Message too large");
16868 *err = 413;
16869 return 0;
16870 }
16871
16872 if (conn->request_len <= 0) {
16873 if (conn->data_len > 0) {
16874 mg_snprintf(conn,
16875 NULL, /* No truncation check for ebuf */
16876 ebuf,
16877 ebuf_len,
16878 "%s",
16879 "Malformed message");
16880 *err = 400;
16881 } else {
16882 /* Server did not recv anything -> just close the connection */
16883 conn->must_close = 1;
16884 mg_snprintf(conn,
16885 NULL, /* No truncation check for ebuf */
16886 ebuf,
16887 ebuf_len,
16888 "%s",
16889 "No data received");
16890 *err = 0;
16891 }
16892 return 0;
16893 }
16894 return 1;
16895}
16896
16897
16898static int
16899get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
16900{
16901 const char *cl;
16902 if (!get_message(conn, ebuf, ebuf_len, err)) {
16903 return 0;
16904 }
16905
16906 if (parse_http_request(conn->buf, conn->buf_size, &conn->request_info)
16907 <= 0) {
16908 mg_snprintf(conn,
16909 NULL, /* No truncation check for ebuf */
16910 ebuf,
16911 ebuf_len,
16912 "%s",
16913 "Bad request");
16914 *err = 400;
16915 return 0;
16916 }
16917
16918 /* Message is a valid request */
16919
16920 /* Is there a "host" ? */
16921 conn->host = alloc_get_host(conn);
16922 if (!conn->host) {
16923 mg_snprintf(conn,
16924 NULL, /* No truncation check for ebuf */
16925 ebuf,
16926 ebuf_len,
16927 "%s",
16928 "Bad request: Host mismatch");
16929 *err = 400;
16930 return 0;
16931 }
16932
16933 /* Do we know the content length? */
16934 if ((cl = get_header(conn->request_info.http_headers,
16935 conn->request_info.num_headers,
16936 "Content-Length"))
16937 != NULL) {
16938 /* Request/response has content length set */
16939 char *endptr = NULL;
16940 conn->content_len = strtoll(cl, &endptr, 10);
16941 if (endptr == cl) {
16942 mg_snprintf(conn,
16943 NULL, /* No truncation check for ebuf */
16944 ebuf,
16945 ebuf_len,
16946 "%s",
16947 "Bad request");
16948 *err = 411;
16949 return 0;
16950 }
16951 /* Publish the content length back to the request info. */
16952 conn->request_info.content_length = conn->content_len;
16953 } else if ((cl = get_header(conn->request_info.http_headers,
16954 conn->request_info.num_headers,
16955 "Transfer-Encoding"))
16956 != NULL
16957 && !mg_strcasecmp(cl, "chunked")) {
16958 conn->is_chunked = 1;
16959 conn->content_len = -1; /* unknown content length */
16960 } else {
16961 const struct mg_http_method_info *meth =
16962 get_http_method_info(conn->request_info.request_method);
16963 if (!meth) {
16964 /* No valid HTTP method */
16965 mg_snprintf(conn,
16966 NULL, /* No truncation check for ebuf */
16967 ebuf,
16968 ebuf_len,
16969 "%s",
16970 "Bad request");
16971 *err = 411;
16972 return 0;
16973 }
16974 if (meth->request_has_body) {
16975 /* POST or PUT request without content length set */
16976 conn->content_len = -1; /* unknown content length */
16977 } else {
16978 /* Other request */
16979 conn->content_len = 0; /* No content */
16980 }
16981 }
16982
16983 conn->connection_type = CONNECTION_TYPE_REQUEST; /* Valid request */
16984 return 1;
16985}
16986
16987
16988/* conn is assumed to be valid in this internal function */
16989static int
16990get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
16991{
16992 const char *cl;
16993 if (!get_message(conn, ebuf, ebuf_len, err)) {
16994 return 0;
16995 }
16996
16997 if (parse_http_response(conn->buf, conn->buf_size, &conn->response_info)
16998 <= 0) {
16999 mg_snprintf(conn,
17000 NULL, /* No truncation check for ebuf */
17001 ebuf,
17002 ebuf_len,
17003 "%s",
17004 "Bad response");
17005 *err = 400;
17006 return 0;
17007 }
17008
17009 /* Message is a valid response */
17010
17011 /* Do we know the content length? */
17012 if ((cl = get_header(conn->response_info.http_headers,
17013 conn->response_info.num_headers,
17014 "Content-Length"))
17015 != NULL) {
17016 /* Request/response has content length set */
17017 char *endptr = NULL;
17018 conn->content_len = strtoll(cl, &endptr, 10);
17019 if (endptr == cl) {
17020 mg_snprintf(conn,
17021 NULL, /* No truncation check for ebuf */
17022 ebuf,
17023 ebuf_len,
17024 "%s",
17025 "Bad request");
17026 *err = 411;
17027 return 0;
17028 }
17029 /* Publish the content length back to the response info. */
17030 conn->response_info.content_length = conn->content_len;
17031
17032 /* TODO: check if it is still used in response_info */
17033 conn->request_info.content_length = conn->content_len;
17034
17035 } else if ((cl = get_header(conn->response_info.http_headers,
17036 conn->response_info.num_headers,
17037 "Transfer-Encoding"))
17038 != NULL
17039 && !mg_strcasecmp(cl, "chunked")) {
17040 conn->is_chunked = 1;
17041 conn->content_len = -1; /* unknown content length */
17042 } else {
17043 conn->content_len = -1; /* unknown content length */
17044 }
17045
17046 conn->connection_type = CONNECTION_TYPE_RESPONSE; /* Valid response */
17047 return 1;
17048}
17049
17050
17051int
17052mg_get_response(struct mg_connection *conn,
17053 char *ebuf,
17054 size_t ebuf_len,
17055 int timeout)
17056{
17057 int err, ret;
17058 char txt[32]; /* will not overflow */
17059 char *save_timeout;
17060 char *new_timeout;
17061
17062 if (ebuf_len > 0) {
17063 ebuf[0] = '\0';
17064 }
17065
17066 if (!conn) {
17067 mg_snprintf(conn,
17068 NULL, /* No truncation check for ebuf */
17069 ebuf,
17070 ebuf_len,
17071 "%s",
17072 "Parameter error");
17073 return -1;
17074 }
17075
17076 /* Implementation of API function for HTTP clients */
17077 save_timeout = conn->dom_ctx->config[REQUEST_TIMEOUT];
17078
17079 if (timeout >= 0) {
17080 mg_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout);
17081 new_timeout = txt;
17082 /* Not required for non-blocking sockets.
17083 set_sock_timeout(conn->client.sock, timeout);
17084 */
17085 } else {
17086 new_timeout = NULL;
17087 }
17088
17089 conn->dom_ctx->config[REQUEST_TIMEOUT] = new_timeout;
17090 ret = get_response(conn, ebuf, ebuf_len, &err);
17091 conn->dom_ctx->config[REQUEST_TIMEOUT] = save_timeout;
17092
17093#if defined(MG_LEGACY_INTERFACE)
17094 /* TODO: 1) uri is deprecated;
17095 * 2) here, ri.uri is the http response code */
17096 conn->request_info.uri = conn->request_info.request_uri;
17097#endif
17098 conn->request_info.local_uri = conn->request_info.request_uri;
17099
17100 /* TODO (mid): Define proper return values - maybe return length?
17101 * For the first test use <0 for error and >0 for OK */
17102 return (ret == 0) ? -1 : +1;
17103}
17104
17105
17106struct mg_connection *
17107mg_download(const char *host,
17108 int port,
17109 int use_ssl,
17110 char *ebuf,
17111 size_t ebuf_len,
17112 const char *fmt,
17113 ...)
17114{
17115 struct mg_connection *conn;
17116 va_list ap;
17117 int i;
17118 int reqerr;
17119
17120 if (ebuf_len > 0) {
17121 ebuf[0] = '\0';
17122 }
17123
17124 va_start(ap, fmt);
17125
17126 /* open a connection */
17127 conn = mg_connect_client(host, port, use_ssl, ebuf, ebuf_len);
17128
17129 if (conn != NULL) {
17130 i = mg_vprintf(conn, fmt, ap);
17131 if (i <= 0) {
17132 mg_snprintf(conn,
17133 NULL, /* No truncation check for ebuf */
17134 ebuf,
17135 ebuf_len,
17136 "%s",
17137 "Error sending request");
17138 } else {
17139 get_response(conn, ebuf, ebuf_len, &reqerr);
17140
17141#if defined(MG_LEGACY_INTERFACE)
17142 /* TODO: 1) uri is deprecated;
17143 * 2) here, ri.uri is the http response code */
17144 conn->request_info.uri = conn->request_info.request_uri;
17145#endif
17146 conn->request_info.local_uri = conn->request_info.request_uri;
17147 }
17148 }
17149
17150 /* if an error occurred, close the connection */
17151 if ((ebuf[0] != '\0') && (conn != NULL)) {
17152 mg_close_connection(conn);
17153 conn = NULL;
17154 }
17155
17156 va_end(ap);
17157 return conn;
17158}
17159
17160
17161struct websocket_client_thread_data {
17162 struct mg_connection *conn;
17163 mg_websocket_data_handler data_handler;
17164 mg_websocket_close_handler close_handler;
17165 void *callback_data;
17166};
17167
17168
17169#if defined(USE_WEBSOCKET)
17170#if defined(_WIN32)
17171static unsigned __stdcall websocket_client_thread(void *data)
17172#else
17173static void *
17174websocket_client_thread(void *data)
17175#endif
17176{
17177 struct websocket_client_thread_data *cdata =
17178 (struct websocket_client_thread_data *)data;
17179
17180#if !defined(_WIN32)
17181 struct sigaction sa;
17182
17183 /* Ignore SIGPIPE */
17184 memset(&sa, 0, sizeof(sa));
17185 sa.sa_handler = SIG_IGN;
17186 sigaction(SIGPIPE, &sa, NULL);
17187#endif
17188
17189 mg_set_thread_name("ws-clnt");
17190
17191 if (cdata->conn->phys_ctx) {
17192 if (cdata->conn->phys_ctx->callbacks.init_thread) {
17193 /* 3 indicates a websocket client thread */
17194 /* TODO: check if conn->phys_ctx can be set */
17195 cdata->conn->phys_ctx->callbacks.init_thread(cdata->conn->phys_ctx,
17196 3);
17197 }
17198 }
17199
17200 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
17201
17202 DEBUG_TRACE("%s", "Websocket client thread exited\n");
17203
17204 if (cdata->close_handler != NULL) {
17205 cdata->close_handler(cdata->conn, cdata->callback_data);
17206 }
17207
17208 /* The websocket_client context has only this thread. If it runs out,
17209 set the stop_flag to 2 (= "stopped"). */
17210 cdata->conn->phys_ctx->stop_flag = 2;
17211
17212 mg_free((void *)cdata);
17213
17214#if defined(_WIN32)
17215 return 0;
17216#else
17217 return NULL;
17218#endif
17219}
17220#endif
17221
17222
17223struct mg_connection *
17225 int port,
17226 int use_ssl,
17227 char *error_buffer,
17228 size_t error_buffer_size,
17229 const char *path,
17230 const char *origin,
17231 mg_websocket_data_handler data_func,
17232 mg_websocket_close_handler close_func,
17233 void *user_data)
17234{
17235 struct mg_connection *conn = NULL;
17236
17237#if defined(USE_WEBSOCKET)
17238 struct mg_context *newctx = NULL;
17239 struct websocket_client_thread_data *thread_data;
17240 static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
17241 static const char *handshake_req;
17242
17243 if (origin != NULL) {
17244 handshake_req = "GET %s HTTP/1.1\r\n"
17245 "Host: %s\r\n"
17246 "Upgrade: websocket\r\n"
17247 "Connection: Upgrade\r\n"
17248 "Sec-WebSocket-Key: %s\r\n"
17249 "Sec-WebSocket-Version: 13\r\n"
17250 "Origin: %s\r\n"
17251 "\r\n";
17252 } else {
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 "\r\n";
17260 }
17261
17262#if defined(__clang__)
17263#pragma clang diagnostic push
17264#pragma clang diagnostic ignored "-Wformat-nonliteral"
17265#endif
17266
17267 /* Establish the client connection and request upgrade */
17268 conn = mg_download(host,
17269 port,
17270 use_ssl,
17271 error_buffer,
17272 error_buffer_size,
17273 handshake_req,
17274 path,
17275 host,
17276 magic,
17277 origin);
17278
17279#if defined(__clang__)
17280#pragma clang diagnostic pop
17281#endif
17282
17283 /* Connection object will be null if something goes wrong */
17284 if (conn == NULL) {
17285 if (!*error_buffer) {
17286 /* There should be already an error message */
17287 mg_snprintf(conn,
17288 NULL, /* No truncation check for ebuf */
17289 error_buffer,
17290 error_buffer_size,
17291 "Unexpected error");
17292 }
17293 return NULL;
17294 }
17295
17296 if (conn->response_info.status_code != 101) {
17297 /* We sent an "upgrade" request. For a correct websocket
17298 * protocol handshake, we expect a "101 Continue" response.
17299 * Otherwise it is a protocol violation. Maybe the HTTP
17300 * Server does not know websockets. */
17301 if (!*error_buffer) {
17302 /* set an error, if not yet set */
17303 mg_snprintf(conn,
17304 NULL, /* No truncation check for ebuf */
17305 error_buffer,
17306 error_buffer_size,
17307 "Unexpected server reply");
17308 }
17309
17310 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
17311 mg_free(conn);
17312 return NULL;
17313 }
17314
17315 /* For client connections, mg_context is fake. Since we need to set a
17316 * callback function, we need to create a copy and modify it. */
17317 newctx = (struct mg_context *)mg_malloc(sizeof(struct mg_context));
17318 if (!newctx) {
17319 DEBUG_TRACE("%s\r\n", "Out of memory");
17320 mg_free(conn);
17321 return NULL;
17322 }
17323
17324 memcpy(newctx, conn->phys_ctx, sizeof(struct mg_context));
17325 newctx->user_data = user_data;
17326 newctx->context_type = CONTEXT_WS_CLIENT; /* ws/wss client context */
17327 newctx->cfg_worker_threads = 1; /* one worker thread will be created */
17328 newctx->worker_threadids =
17329 (pthread_t *)mg_calloc_ctx(newctx->cfg_worker_threads,
17330 sizeof(pthread_t),
17331 newctx);
17332
17333 conn->phys_ctx = newctx;
17334 conn->dom_ctx = &(newctx->dd);
17335
17336 thread_data = (struct websocket_client_thread_data *)
17337 mg_calloc_ctx(sizeof(struct websocket_client_thread_data), 1, newctx);
17338 if (!thread_data) {
17339 DEBUG_TRACE("%s\r\n", "Out of memory");
17340 mg_free(newctx);
17341 mg_free(conn);
17342 return NULL;
17343 }
17344
17345 thread_data->conn = conn;
17346 thread_data->data_handler = data_func;
17347 thread_data->close_handler = close_func;
17348 thread_data->callback_data = user_data;
17349
17350 /* Start a thread to read the websocket client connection
17351 * This thread will automatically stop when mg_disconnect is
17352 * called on the client connection */
17353 if (mg_start_thread_with_id(websocket_client_thread,
17354 (void *)thread_data,
17355 newctx->worker_threadids)
17356 != 0) {
17357 mg_free((void *)thread_data);
17358 mg_free((void *)newctx->worker_threadids);
17359 mg_free((void *)newctx);
17360 mg_free((void *)conn);
17361 conn = NULL;
17362 DEBUG_TRACE("%s",
17363 "Websocket client connect thread could not be started\r\n");
17364 }
17365
17366#else
17367 /* Appease "unused parameter" warnings */
17368 (void)host;
17369 (void)port;
17370 (void)use_ssl;
17371 (void)error_buffer;
17372 (void)error_buffer_size;
17373 (void)path;
17374 (void)origin;
17375 (void)user_data;
17376 (void)data_func;
17377 (void)close_func;
17378#endif
17379
17380 return conn;
17381}
17382
17383
17384/* Prepare connection data structure */
17385static void
17386init_connection(struct mg_connection *conn)
17387{
17388 /* Is keep alive allowed by the server */
17389 int keep_alive_enabled =
17390 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_KEEP_ALIVE], "yes");
17391
17392 if (!keep_alive_enabled) {
17393 conn->must_close = 1;
17394 }
17395
17396 /* Important: on new connection, reset the receiving buffer. Credit
17397 * goes to crule42. */
17398 conn->data_len = 0;
17399 conn->handled_requests = 0;
17400 mg_set_user_connection_data(conn, NULL);
17401
17402#if defined(USE_SERVER_STATS)
17403 conn->conn_state = 2; /* init */
17404#endif
17405
17406 /* call the init_connection callback if assigned */
17407 if (conn->phys_ctx->callbacks.init_connection != NULL) {
17408 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
17409 void *conn_data = NULL;
17410 conn->phys_ctx->callbacks.init_connection(conn, &conn_data);
17411 mg_set_user_connection_data(conn, conn_data);
17412 }
17413 }
17414}
17415
17416
17417/* Process a connection - may handle multiple requests
17418 * using the same connection.
17419 * Must be called with a valid connection (conn and
17420 * conn->phys_ctx must be valid).
17421 */
17422static void
17423process_new_connection(struct mg_connection *conn)
17424{
17425 struct mg_request_info *ri = &conn->request_info;
17426 int keep_alive, discard_len;
17427 char ebuf[100];
17428 const char *hostend;
17429 int reqerr, uri_type;
17430
17431#if defined(USE_SERVER_STATS)
17432 int mcon = mg_atomic_inc(&(conn->phys_ctx->active_connections));
17433 mg_atomic_add(&(conn->phys_ctx->total_connections), 1);
17434 if (mcon > (conn->phys_ctx->max_connections)) {
17435 /* could use atomic compare exchange, but this
17436 * seems overkill for statistics data */
17437 conn->phys_ctx->max_connections = mcon;
17438 }
17439#endif
17440
17441 init_connection(conn);
17442
17443 DEBUG_TRACE("Start processing connection from %s",
17444 conn->request_info.remote_addr);
17445
17446 /* Loop over multiple requests sent using the same connection
17447 * (while "keep alive"). */
17448 do {
17449
17450 DEBUG_TRACE("calling get_request (%i times for this connection)",
17451 conn->handled_requests + 1);
17452
17453#if defined(USE_SERVER_STATS)
17454 conn->conn_state = 3; /* ready */
17455#endif
17456
17457 if (!get_request(conn, ebuf, sizeof(ebuf), &reqerr)) {
17458 /* The request sent by the client could not be understood by
17459 * the server, or it was incomplete or a timeout. Send an
17460 * error message and close the connection. */
17461 if (reqerr > 0) {
17462 DEBUG_ASSERT(ebuf[0] != '\0');
17463 mg_send_http_error(conn, reqerr, "%s", ebuf);
17464 }
17465 } else if (strcmp(ri->http_version, "1.0")
17466 && strcmp(ri->http_version, "1.1")) {
17467 mg_snprintf(conn,
17468 NULL, /* No truncation check for ebuf */
17469 ebuf,
17470 sizeof(ebuf),
17471 "Bad HTTP version: [%s]",
17472 ri->http_version);
17473 mg_send_http_error(conn, 505, "%s", ebuf);
17474 }
17475
17476 if (ebuf[0] == '\0') {
17477 uri_type = get_uri_type(conn->request_info.request_uri);
17478 switch (uri_type) {
17479 case 1:
17480 /* Asterisk */
17481 conn->request_info.local_uri = NULL;
17482 break;
17483 case 2:
17484 /* relative uri */
17485 conn->request_info.local_uri = conn->request_info.request_uri;
17486 break;
17487 case 3:
17488 case 4:
17489 /* absolute uri (with/without port) */
17491 conn->request_info.request_uri, conn);
17492 if (hostend) {
17493 conn->request_info.local_uri = hostend;
17494 } else {
17495 conn->request_info.local_uri = NULL;
17496 }
17497 break;
17498 default:
17499 mg_snprintf(conn,
17500 NULL, /* No truncation check for ebuf */
17501 ebuf,
17502 sizeof(ebuf),
17503 "Invalid URI");
17504 mg_send_http_error(conn, 400, "%s", ebuf);
17505 conn->request_info.local_uri = NULL;
17506 break;
17507 }
17508
17509#if defined(MG_LEGACY_INTERFACE)
17510 /* Legacy before split into local_uri and request_uri */
17511 conn->request_info.uri = conn->request_info.local_uri;
17512#endif
17513 }
17514
17515 DEBUG_TRACE("http: %s, error: %s",
17516 (ri->http_version ? ri->http_version : "none"),
17517 (ebuf[0] ? ebuf : "none"));
17518
17519 if (ebuf[0] == '\0') {
17520 if (conn->request_info.local_uri) {
17521
17522/* handle request to local server */
17523#if defined(USE_SERVER_STATS)
17524 conn->conn_state = 4; /* processing */
17525#endif
17526 handle_request(conn);
17527
17528#if defined(USE_SERVER_STATS)
17529 conn->conn_state = 5; /* processed */
17530
17531 mg_atomic_add(&(conn->phys_ctx->total_data_read),
17532 conn->consumed_content);
17533 mg_atomic_add(&(conn->phys_ctx->total_data_written),
17534 conn->num_bytes_sent);
17535#endif
17536
17537 DEBUG_TRACE("%s", "handle_request done");
17538
17539 if (conn->phys_ctx->callbacks.end_request != NULL) {
17540 conn->phys_ctx->callbacks.end_request(conn,
17541 conn->status_code);
17542 DEBUG_TRACE("%s", "end_request callback done");
17543 }
17544 log_access(conn);
17545 } else {
17546 /* TODO: handle non-local request (PROXY) */
17547 conn->must_close = 1;
17548 }
17549 } else {
17550 conn->must_close = 1;
17551 }
17552
17553 if (ri->remote_user != NULL) {
17554 mg_free((void *)ri->remote_user);
17555 /* Important! When having connections with and without auth
17556 * would cause double free and then crash */
17557 ri->remote_user = NULL;
17558 }
17559
17560 /* NOTE(lsm): order is important here. should_keep_alive() call
17561 * is using parsed request, which will be invalid after
17562 * memmove's below.
17563 * Therefore, memorize should_keep_alive() result now for later
17564 * use in loop exit condition. */
17565 keep_alive = (conn->phys_ctx->stop_flag == 0) && should_keep_alive(conn)
17566 && (conn->content_len >= 0);
17567
17568
17569 /* Discard all buffered data for this request */
17570 discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
17571 && ((conn->request_len + conn->content_len)
17572 < (int64_t)conn->data_len))
17573 ? (int)(conn->request_len + conn->content_len)
17574 : conn->data_len;
17575 DEBUG_ASSERT(discard_len >= 0);
17576 if (discard_len < 0) {
17577 DEBUG_TRACE("internal error: discard_len = %li",
17578 (long int)discard_len);
17579 break;
17580 }
17581 conn->data_len -= discard_len;
17582 if (conn->data_len > 0) {
17583 DEBUG_TRACE("discard_len = %lu", (long unsigned)discard_len);
17584 memmove(conn->buf, conn->buf + discard_len, (size_t)conn->data_len);
17585 }
17586
17587 DEBUG_ASSERT(conn->data_len >= 0);
17588 DEBUG_ASSERT(conn->data_len <= conn->buf_size);
17589
17590 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
17591 DEBUG_TRACE("internal error: data_len = %li, buf_size = %li",
17592 (long int)conn->data_len,
17593 (long int)conn->buf_size);
17594 break;
17595 }
17596
17597 conn->handled_requests++;
17598
17599 } while (keep_alive);
17600
17601 DEBUG_TRACE("Done processing connection from %s (%f sec)",
17602 conn->request_info.remote_addr,
17603 difftime(time(NULL), conn->conn_birth_time));
17604
17605 close_connection(conn);
17606
17607#if defined(USE_SERVER_STATS)
17608 mg_atomic_add(&(conn->phys_ctx->total_requests), conn->handled_requests);
17609 mg_atomic_dec(&(conn->phys_ctx->active_connections));
17610#endif
17611}
17612
17613
17614#if defined(ALTERNATIVE_QUEUE)
17615
17616static void
17617produce_socket(struct mg_context *ctx, const struct socket *sp)
17618{
17619 unsigned int i;
17620
17621 while (!ctx->stop_flag) {
17622 for (i = 0; i < ctx->cfg_worker_threads; i++) {
17623 /* find a free worker slot and signal it */
17624 if (ctx->client_socks[i].in_use == 0) {
17625 ctx->client_socks[i] = *sp;
17626 ctx->client_socks[i].in_use = 1;
17627 event_signal(ctx->client_wait_events[i]);
17628 return;
17629 }
17630 }
17631 /* queue is full */
17632 mg_sleep(1);
17633 }
17634}
17635
17636
17637static int
17638consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
17639{
17640 DEBUG_TRACE("%s", "going idle");
17641 ctx->client_socks[thread_index].in_use = 0;
17642 event_wait(ctx->client_wait_events[thread_index]);
17643 *sp = ctx->client_socks[thread_index];
17644 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
17645
17646 return !ctx->stop_flag;
17647}
17648
17649#else /* ALTERNATIVE_QUEUE */
17650
17651/* Worker threads take accepted socket from the queue */
17652static int
17653consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
17654{
17655#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17656
17657 (void)thread_index;
17658
17659 (void)pthread_mutex_lock(&ctx->thread_mutex);
17660 DEBUG_TRACE("%s", "going idle");
17661
17662 /* If the queue is empty, wait. We're idle at this point. */
17663 while ((ctx->sq_head == ctx->sq_tail) && (ctx->stop_flag == 0)) {
17664 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
17665 }
17666
17667 /* If we're stopping, sq_head may be equal to sq_tail. */
17668 if (ctx->sq_head > ctx->sq_tail) {
17669 /* Copy socket from the queue and increment tail */
17670 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
17671 ctx->sq_tail++;
17672
17673 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
17674
17675 /* Wrap pointers if needed */
17676 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
17677 ctx->sq_tail -= QUEUE_SIZE(ctx);
17678 ctx->sq_head -= QUEUE_SIZE(ctx);
17679 }
17680 }
17681
17682 (void)pthread_cond_signal(&ctx->sq_empty);
17683 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17684
17685 return !ctx->stop_flag;
17686#undef QUEUE_SIZE
17687}
17688
17689
17690/* Master thread adds accepted socket to a queue */
17691static void
17692produce_socket(struct mg_context *ctx, const struct socket *sp)
17693{
17694#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17695 if (!ctx) {
17696 return;
17697 }
17698 (void)pthread_mutex_lock(&ctx->thread_mutex);
17699
17700 /* If the queue is full, wait */
17701 while ((ctx->stop_flag == 0)
17702 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
17703 (void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
17704 }
17705
17706 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
17707 /* Copy socket to the queue and increment head */
17708 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
17709 ctx->sq_head++;
17710 DEBUG_TRACE("queued socket %d", sp ? sp->sock : -1);
17711 }
17712
17713 (void)pthread_cond_signal(&ctx->sq_full);
17714 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17715#undef QUEUE_SIZE
17716}
17717#endif /* ALTERNATIVE_QUEUE */
17718
17719
17720struct worker_thread_args {
17721 struct mg_context *ctx;
17722 int index;
17723};
17724
17725
17726static void *
17727worker_thread_run(struct worker_thread_args *thread_args)
17728{
17729 struct mg_context *ctx = thread_args->ctx;
17730 struct mg_connection *conn;
17731 struct mg_workerTLS tls;
17732#if defined(MG_LEGACY_INTERFACE)
17733 uint32_t addr;
17734#endif
17735
17736 mg_set_thread_name("worker");
17737
17738 tls.is_master = 0;
17739 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
17740#if defined(_WIN32)
17741 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
17742#endif
17743
17744 /* Initialize thread local storage before calling any callback */
17745 pthread_setspecific(sTlsKey, &tls);
17746
17747 if (ctx->callbacks.init_thread) {
17748 /* call init_thread for a worker thread (type 1) */
17749 ctx->callbacks.init_thread(ctx, 1);
17750 }
17751
17752 /* Connection structure has been pre-allocated */
17753 if (((int)thread_args->index < 0)
17754 || ((unsigned)thread_args->index
17755 >= (unsigned)ctx->cfg_worker_threads)) {
17756 mg_cry_internal(fc(ctx),
17757 "Internal error: Invalid worker index %i",
17758 (int)thread_args->index);
17759 return NULL;
17760 }
17761 conn = ctx->worker_connections + thread_args->index;
17762
17763 /* Request buffers are not pre-allocated. They are private to the
17764 * request and do not contain any state information that might be
17765 * of interest to anyone observing a server status. */
17766 conn->buf = (char *)mg_malloc_ctx(ctx->max_request_size, conn->phys_ctx);
17767 if (conn->buf == NULL) {
17768 mg_cry_internal(fc(ctx),
17769 "Out of memory: Cannot allocate buffer for worker %i",
17770 (int)thread_args->index);
17771 return NULL;
17772 }
17773 conn->buf_size = (int)ctx->max_request_size;
17774
17775 conn->phys_ctx = ctx;
17776 conn->dom_ctx = &(ctx->dd); /* Use default domain and default host */
17777 conn->host = NULL; /* until we have more information. */
17778
17779 conn->thread_index = thread_args->index;
17780 conn->request_info.user_data = ctx->user_data;
17781 /* Allocate a mutex for this connection to allow communication both
17782 * within the request handler and from elsewhere in the application
17783 */
17784 if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
17785 mg_free(conn->buf);
17786 mg_cry_internal(fc(ctx), "%s", "Cannot create mutex");
17787 return NULL;
17788 }
17789
17790#if defined(USE_SERVER_STATS)
17791 conn->conn_state = 1; /* not consumed */
17792#endif
17793
17794#if defined(ALTERNATIVE_QUEUE)
17795 while ((ctx->stop_flag == 0)
17796 && consume_socket(ctx, &conn->client, conn->thread_index)) {
17797#else
17798 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
17799 * signal sq_empty condvar to wake up the master waiting in
17800 * produce_socket() */
17801 while (consume_socket(ctx, &conn->client, conn->thread_index)) {
17802#endif
17803
17804 conn->conn_birth_time = time(NULL);
17805
17806/* Fill in IP, port info early so even if SSL setup below fails,
17807 * error handler would have the corresponding info.
17808 * Thanks to Johannes Winkelmann for the patch.
17809 */
17810#if defined(USE_IPV6)
17811 if (conn->client.rsa.sa.sa_family == AF_INET6) {
17812 conn->request_info.remote_port =
17813 ntohs(conn->client.rsa.sin6.sin6_port);
17814 } else
17815#endif
17816 {
17817 conn->request_info.remote_port =
17818 ntohs(conn->client.rsa.sin.sin_port);
17819 }
17820
17821 sockaddr_to_string(conn->request_info.remote_addr,
17822 sizeof(conn->request_info.remote_addr),
17823 &conn->client.rsa);
17824
17825 DEBUG_TRACE("Start processing connection from %s",
17826 conn->request_info.remote_addr);
17827
17828 conn->request_info.is_ssl = conn->client.is_ssl;
17829
17830 if (conn->client.is_ssl) {
17831#if !defined(NO_SSL)
17832 /* HTTPS connection */
17833 if (sslize(conn,
17834 conn->dom_ctx->ssl_ctx,
17835 SSL_accept,
17836 &(conn->phys_ctx->stop_flag),
17837 NULL)) {
17838 /* conn->dom_ctx is set in get_request */
17839
17840 /* Get SSL client certificate information (if set) */
17842
17843 /* process HTTPS connection */
17845
17846 /* Free client certificate info */
17847 if (conn->request_info.client_cert) {
17848 mg_free((void *)(conn->request_info.client_cert->subject));
17849 mg_free((void *)(conn->request_info.client_cert->issuer));
17850 mg_free((void *)(conn->request_info.client_cert->serial));
17851 mg_free((void *)(conn->request_info.client_cert->finger));
17852 /* Free certificate memory */
17853 X509_free(
17854 (X509 *)conn->request_info.client_cert->peer_cert);
17855 conn->request_info.client_cert->peer_cert = 0;
17856 conn->request_info.client_cert->subject = 0;
17857 conn->request_info.client_cert->issuer = 0;
17858 conn->request_info.client_cert->serial = 0;
17859 conn->request_info.client_cert->finger = 0;
17860 mg_free(conn->request_info.client_cert);
17861 conn->request_info.client_cert = 0;
17862 }
17863 } else {
17864 /* make sure the connection is cleaned up on SSL failure */
17865 close_connection(conn);
17866 }
17867#endif
17868 } else {
17869 /* process HTTP connection */
17871 }
17872
17873 DEBUG_TRACE("%s", "Connection closed");
17874 }
17875
17876
17877 pthread_setspecific(sTlsKey, NULL);
17878#if defined(_WIN32)
17879 CloseHandle(tls.pthread_cond_helper_mutex);
17880#endif
17881 pthread_mutex_destroy(&conn->mutex);
17882
17883 /* Free the request buffer. */
17884 conn->buf_size = 0;
17885 mg_free(conn->buf);
17886 conn->buf = NULL;
17887
17888#if defined(USE_SERVER_STATS)
17889 conn->conn_state = 9; /* done */
17890#endif
17891
17892 DEBUG_TRACE("%s", "exiting");
17893 return NULL;
17894}
17895
17896
17897/* Threads have different return types on Windows and Unix. */
17898#if defined(_WIN32)
17899static unsigned __stdcall worker_thread(void *thread_func_param)
17900{
17901 struct worker_thread_args *pwta =
17902 (struct worker_thread_args *)thread_func_param;
17903 worker_thread_run(pwta);
17904 mg_free(thread_func_param);
17905 return 0;
17906}
17907#else
17908static void *
17909worker_thread(void *thread_func_param)
17910{
17911 struct worker_thread_args *pwta =
17912 (struct worker_thread_args *)thread_func_param;
17913 struct sigaction sa;
17914
17915 /* Ignore SIGPIPE */
17916 memset(&sa, 0, sizeof(sa));
17917 sa.sa_handler = SIG_IGN;
17918 sigaction(SIGPIPE, &sa, NULL);
17919
17920 worker_thread_run(pwta);
17921 mg_free(thread_func_param);
17922 return NULL;
17923}
17924#endif /* _WIN32 */
17925
17926
17927/* This is an internal function, thus all arguments are expected to be
17928 * valid - a NULL check is not required. */
17929static void
17930accept_new_connection(const struct socket *listener, struct mg_context *ctx)
17931{
17932 struct socket so;
17933 char src_addr[IP_ADDR_STR_LEN];
17934 socklen_t len = sizeof(so.rsa);
17935 int on = 1;
17936
17937 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
17938 == INVALID_SOCKET) {
17939 } else if (!check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
17940 sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
17941 mg_cry_internal(fc(ctx),
17942 "%s: %s is not allowed to connect",
17943 __func__,
17944 src_addr);
17945 closesocket(so.sock);
17946 } else {
17947 /* Put so socket structure into the queue */
17948 DEBUG_TRACE("Accepted socket %d", (int)so.sock);
17949 set_close_on_exec(so.sock, fc(ctx));
17950 so.is_ssl = listener->is_ssl;
17951 so.ssl_redir = listener->ssl_redir;
17952 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
17953 mg_cry_internal(fc(ctx),
17954 "%s: getsockname() failed: %s",
17955 __func__,
17956 strerror(ERRNO));
17957 }
17958
17959 /* Set TCP keep-alive. This is needed because if HTTP-level
17960 * keep-alive
17961 * is enabled, and client resets the connection, server won't get
17962 * TCP FIN or RST and will keep the connection open forever. With
17963 * TCP keep-alive, next keep-alive handshake will figure out that
17964 * the client is down and will close the server end.
17965 * Thanks to Igor Klopov who suggested the patch. */
17966 if (setsockopt(so.sock,
17967 SOL_SOCKET,
17968 SO_KEEPALIVE,
17969 (SOCK_OPT_TYPE)&on,
17970 sizeof(on))
17971 != 0) {
17973 fc(ctx),
17974 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
17975 __func__,
17976 strerror(ERRNO));
17977 }
17978
17979 /* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
17980 * to effectively fill up the underlying IP packet payload and
17981 * reduce the overhead of sending lots of small buffers. However
17982 * this hurts the server's throughput (ie. operations per second)
17983 * when HTTP 1.1 persistent connections are used and the responses
17984 * are relatively small (eg. less than 1400 bytes).
17985 */
17986 if ((ctx->dd.config[CONFIG_TCP_NODELAY] != NULL)
17987 && (!strcmp(ctx->dd.config[CONFIG_TCP_NODELAY], "1"))) {
17988 if (set_tcp_nodelay(so.sock, 1) != 0) {
17990 fc(ctx),
17991 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
17992 __func__,
17993 strerror(ERRNO));
17994 }
17995 }
17996
17997 /* We are using non-blocking sockets. Thus, the
17998 * set_sock_timeout(so.sock, timeout);
17999 * call is no longer required. */
18000
18001 /* The "non blocking" property should already be
18002 * inherited from the parent socket. Set it for
18003 * non-compliant socket implementations. */
18004 set_non_blocking_mode(so.sock);
18005
18006 so.in_use = 0;
18007 produce_socket(ctx, &so);
18008 }
18009}
18010
18011
18012static void
18013master_thread_run(void *thread_func_param)
18014{
18015 struct mg_context *ctx = (struct mg_context *)thread_func_param;
18016 struct mg_workerTLS tls;
18017 struct pollfd *pfd;
18018 unsigned int i;
18019 unsigned int workerthreadcount;
18020
18021 if (!ctx) {
18022 return;
18023 }
18024
18025 mg_set_thread_name("master");
18026
18027/* Increase priority of the master thread */
18028#if defined(_WIN32)
18029 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
18030#elif defined(USE_MASTER_THREAD_PRIORITY)
18031 int min_prio = sched_get_priority_min(SCHED_RR);
18032 int max_prio = sched_get_priority_max(SCHED_RR);
18033 if ((min_prio >= 0) && (max_prio >= 0)
18034 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
18035 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
18036 struct sched_param sched_param = {0};
18037 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
18038 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
18039 }
18040#endif
18041
18042/* Initialize thread local storage */
18043#if defined(_WIN32)
18044 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
18045#endif
18046 tls.is_master = 1;
18047 pthread_setspecific(sTlsKey, &tls);
18048
18049 if (ctx->callbacks.init_thread) {
18050 /* Callback for the master thread (type 0) */
18051 ctx->callbacks.init_thread(ctx, 0);
18052 }
18053
18054 /* Server starts *now* */
18055 ctx->start_time = time(NULL);
18056
18057 /* Start the server */
18058 pfd = ctx->listening_socket_fds;
18059 while (ctx->stop_flag == 0) {
18060 for (i = 0; i < ctx->num_listening_sockets; i++) {
18061 pfd[i].fd = ctx->listening_sockets[i].sock;
18062 pfd[i].events = POLLIN;
18063 }
18064
18065 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
18066 for (i = 0; i < ctx->num_listening_sockets; i++) {
18067 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
18068 * successful poll, and POLLIN is defined as
18069 * (POLLRDNORM | POLLRDBAND)
18070 * Therefore, we're checking pfd[i].revents & POLLIN, not
18071 * pfd[i].revents == POLLIN. */
18072 if ((ctx->stop_flag == 0) && (pfd[i].revents & POLLIN)) {
18073 accept_new_connection(&ctx->listening_sockets[i], ctx);
18074 }
18075 }
18076 }
18077 }
18078
18079 /* Here stop_flag is 1 - Initiate shutdown. */
18080 DEBUG_TRACE("%s", "stopping workers");
18081
18082 /* Stop signal received: somebody called mg_stop. Quit. */
18084
18085 /* Wakeup workers that are waiting for connections to handle. */
18086 (void)pthread_mutex_lock(&ctx->thread_mutex);
18087#if defined(ALTERNATIVE_QUEUE)
18088 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18089 event_signal(ctx->client_wait_events[i]);
18090
18091 /* Since we know all sockets, we can shutdown the connections. */
18092 if (ctx->client_socks[i].in_use) {
18093 shutdown(ctx->client_socks[i].sock, SHUTDOWN_BOTH);
18094 }
18095 }
18096#else
18097 pthread_cond_broadcast(&ctx->sq_full);
18098#endif
18099 (void)pthread_mutex_unlock(&ctx->thread_mutex);
18100
18101 /* Join all worker threads to avoid leaking threads. */
18102 workerthreadcount = ctx->cfg_worker_threads;
18103 for (i = 0; i < workerthreadcount; i++) {
18104 if (ctx->worker_threadids[i] != 0) {
18105 mg_join_thread(ctx->worker_threadids[i]);
18106 }
18107 }
18108
18109#if defined(USE_LUA)
18110 /* Free Lua state of lua background task */
18111 if (ctx->lua_background_state) {
18112 lua_State *lstate = (lua_State *)ctx->lua_background_state;
18113 lua_getglobal(lstate, LUABACKGROUNDPARAMS);
18114 if (lua_istable(lstate, -1)) {
18115 reg_boolean(lstate, "shutdown", 1);
18116 lua_pop(lstate, 1);
18117 mg_sleep(2);
18118 }
18119 lua_close(lstate);
18120 ctx->lua_background_state = 0;
18121 }
18122#endif
18123
18124 DEBUG_TRACE("%s", "exiting");
18125
18126#if defined(_WIN32)
18127 CloseHandle(tls.pthread_cond_helper_mutex);
18128#endif
18129 pthread_setspecific(sTlsKey, NULL);
18130
18131 /* Signal mg_stop() that we're done.
18132 * WARNING: This must be the very last thing this
18133 * thread does, as ctx becomes invalid after this line. */
18134 ctx->stop_flag = 2;
18135}
18136
18137
18138/* Threads have different return types on Windows and Unix. */
18139#if defined(_WIN32)
18140static unsigned __stdcall master_thread(void *thread_func_param)
18141{
18142 master_thread_run(thread_func_param);
18143 return 0;
18144}
18145#else
18146static void *
18147master_thread(void *thread_func_param)
18148{
18149 struct sigaction sa;
18150
18151 /* Ignore SIGPIPE */
18152 memset(&sa, 0, sizeof(sa));
18153 sa.sa_handler = SIG_IGN;
18154 sigaction(SIGPIPE, &sa, NULL);
18155
18156 master_thread_run(thread_func_param);
18157 return NULL;
18158}
18159#endif /* _WIN32 */
18160
18161
18162static void
18163free_context(struct mg_context *ctx)
18164{
18165 int i;
18166 struct mg_handler_info *tmp_rh;
18167
18168 if (ctx == NULL) {
18169 return;
18170 }
18171
18172 if (ctx->callbacks.exit_context) {
18173 ctx->callbacks.exit_context(ctx);
18174 }
18175
18176 /* All threads exited, no sync is needed. Destroy thread mutex and
18177 * condvars
18178 */
18179 (void)pthread_mutex_destroy(&ctx->thread_mutex);
18180#if defined(ALTERNATIVE_QUEUE)
18181 mg_free(ctx->client_socks);
18182 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18183 event_destroy(ctx->client_wait_events[i]);
18184 }
18185 mg_free(ctx->client_wait_events);
18186#else
18187 (void)pthread_cond_destroy(&ctx->sq_empty);
18188 (void)pthread_cond_destroy(&ctx->sq_full);
18189#endif
18190
18191 /* Destroy other context global data structures mutex */
18192 (void)pthread_mutex_destroy(&ctx->nonce_mutex);
18193
18194#if defined(USE_TIMERS)
18195 timers_exit(ctx);
18196#endif
18197
18198 /* Deallocate config parameters */
18199 for (i = 0; i < NUM_OPTIONS; i++) {
18200 if (ctx->dd.config[i] != NULL) {
18201#if defined(_MSC_VER)
18202#pragma warning(suppress : 6001)
18203#endif
18204 mg_free(ctx->dd.config[i]);
18205 }
18206 }
18207
18208 /* Deallocate request handlers */
18209 while (ctx->dd.handlers) {
18210 tmp_rh = ctx->dd.handlers;
18211 ctx->dd.handlers = tmp_rh->next;
18212 if (tmp_rh->handler_type == REQUEST_HANDLER) {
18213 pthread_cond_destroy(&tmp_rh->refcount_cond);
18214 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
18215 }
18216 mg_free(tmp_rh->uri);
18217 mg_free(tmp_rh);
18218 }
18219
18220#if !defined(NO_SSL)
18221 /* Deallocate SSL context */
18222 if (ctx->dd.ssl_ctx != NULL) {
18223 void *ssl_ctx = (void *)ctx->dd.ssl_ctx;
18224 int callback_ret =
18225 (ctx->callbacks.external_ssl_ctx == NULL)
18226 ? 0
18227 : (ctx->callbacks.external_ssl_ctx(&ssl_ctx, ctx->user_data));
18228
18229 if (callback_ret == 0) {
18230 SSL_CTX_free(ctx->dd.ssl_ctx);
18231 }
18232 /* else: ignore error and ommit SSL_CTX_free in case
18233 * callback_ret is 1 */
18234 }
18235#endif /* !NO_SSL */
18236
18237 /* Deallocate worker thread ID array */
18238 if (ctx->worker_threadids != NULL) {
18239 mg_free(ctx->worker_threadids);
18240 }
18241
18242 /* Deallocate worker thread ID array */
18243 if (ctx->worker_connections != NULL) {
18244 mg_free(ctx->worker_connections);
18245 }
18246
18247 /* deallocate system name string */
18248 mg_free(ctx->systemName);
18249
18250 /* Deallocate context itself */
18251 mg_free(ctx);
18252}
18253
18254
18255void
18256mg_stop(struct mg_context *ctx)
18257{
18258 pthread_t mt;
18259 if (!ctx) {
18260 return;
18261 }
18262
18263 /* We don't use a lock here. Calling mg_stop with the same ctx from
18264 * two threads is not allowed. */
18265 mt = ctx->masterthreadid;
18266 if (mt == 0) {
18267 return;
18268 }
18269
18270 ctx->masterthreadid = 0;
18271
18272 /* Set stop flag, so all threads know they have to exit. */
18273 ctx->stop_flag = 1;
18274
18275 /* Wait until everything has stopped. */
18276 while (ctx->stop_flag != 2) {
18277 (void)mg_sleep(10);
18278 }
18279
18280 mg_join_thread(mt);
18281 free_context(ctx);
18282
18283#if defined(_WIN32)
18284 (void)WSACleanup();
18285#endif /* _WIN32 */
18286}
18287
18288
18289static void
18290get_system_name(char **sysName)
18291{
18292#if defined(_WIN32)
18293#if !defined(__SYMBIAN32__)
18294#if defined(_WIN32_WCE)
18295 *sysName = mg_strdup("WinCE");
18296#else
18297 char name[128];
18298 DWORD dwVersion = 0;
18299 DWORD dwMajorVersion = 0;
18300 DWORD dwMinorVersion = 0;
18301 DWORD dwBuild = 0;
18302 BOOL wowRet, isWoW = FALSE;
18303
18304#if defined(_MSC_VER)
18305#pragma warning(push)
18306/* GetVersion was declared deprecated */
18307#pragma warning(disable : 4996)
18308#endif
18309 dwVersion = GetVersion();
18310#if defined(_MSC_VER)
18311#pragma warning(pop)
18312#endif
18313
18314 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18315 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18316 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
18317 (void)dwBuild;
18318
18319 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
18320
18321 sprintf(name,
18322 "Windows %u.%u%s",
18323 (unsigned)dwMajorVersion,
18324 (unsigned)dwMinorVersion,
18325 (wowRet ? (isWoW ? " (WoW64)" : "") : " (?)"));
18326
18327 *sysName = mg_strdup(name);
18328#endif
18329#else
18330 *sysName = mg_strdup("Symbian");
18331#endif
18332#else
18333 struct utsname name;
18334 memset(&name, 0, sizeof(name));
18335 uname(&name);
18336 *sysName = mg_strdup(name.sysname);
18337#endif
18338}
18339
18340
18341struct mg_context *
18342mg_start(const struct mg_callbacks *callbacks,
18343 void *user_data,
18344 const char **options)
18345{
18346 struct mg_context *ctx;
18347 const char *name, *value, *default_value;
18348 int idx, ok, workerthreadcount;
18349 unsigned int i;
18350 int itmp;
18351 void (*exit_callback)(const struct mg_context *ctx) = 0;
18352
18353 struct mg_workerTLS tls;
18354
18355#if defined(_WIN32)
18356 WSADATA data;
18357 WSAStartup(MAKEWORD(2, 2), &data);
18358#endif /* _WIN32 */
18359
18360 /* Allocate context and initialize reasonable general case defaults. */
18361 if ((ctx = (struct mg_context *)mg_calloc(1, sizeof(*ctx))) == NULL) {
18362 return NULL;
18363 }
18364
18365 /* Random number generator will initialize at the first call */
18366 ctx->dd.auth_nonce_mask =
18367 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
18368
18369 if (mg_init_library_called == 0) {
18370 /* Legacy INIT, if mg_start is called without mg_init_library.
18371 * Note: This may cause a memory leak */
18372 const char *ports_option =
18374
18375 if (options) {
18376 const char **run_options = options;
18377 const char *optname = config_options[LISTENING_PORTS].name;
18378
18379 /* Try to find the "listening_ports" option */
18380 while (*run_options) {
18381 if (!strcmp(*run_options, optname)) {
18382 ports_option = run_options[1];
18383 }
18384 run_options += 2;
18385 }
18386 }
18387
18388 if (is_ssl_port_used(ports_option)) {
18389 /* Initialize with SSL support */
18391 } else {
18392 /* Initialize without SSL support */
18394 }
18395 }
18396
18397 tls.is_master = -1;
18398 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
18399#if defined(_WIN32)
18400 tls.pthread_cond_helper_mutex = NULL;
18401#endif
18402 pthread_setspecific(sTlsKey, &tls);
18403
18404 ok = (0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr));
18405#if !defined(ALTERNATIVE_QUEUE)
18406 ok &= (0 == pthread_cond_init(&ctx->sq_empty, NULL));
18407 ok &= (0 == pthread_cond_init(&ctx->sq_full, NULL));
18408#endif
18409 ok &= (0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr));
18410 if (!ok) {
18411 /* Fatal error - abort start. However, this situation should never
18412 * occur in practice. */
18413 mg_cry_internal(fc(ctx),
18414 "%s",
18415 "Cannot initialize thread synchronization objects");
18416 mg_free(ctx);
18417 pthread_setspecific(sTlsKey, NULL);
18418 return NULL;
18419 }
18420
18421 if (callbacks) {
18422 ctx->callbacks = *callbacks;
18423 exit_callback = callbacks->exit_context;
18424 ctx->callbacks.exit_context = 0;
18425 }
18426 ctx->user_data = user_data;
18427 ctx->dd.handlers = NULL;
18428 ctx->dd.next = NULL;
18429
18430#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18431 ctx->dd.shared_lua_websockets = NULL;
18432#endif
18433
18434 /* Store options */
18435 while (options && (name = *options++) != NULL) {
18436 if ((idx = get_option_index(name)) == -1) {
18437 mg_cry_internal(fc(ctx), "Invalid option: %s", name);
18438 free_context(ctx);
18439 pthread_setspecific(sTlsKey, NULL);
18440 return NULL;
18441 } else if ((value = *options++) == NULL) {
18442 mg_cry_internal(fc(ctx), "%s: option value cannot be NULL", name);
18443 free_context(ctx);
18444 pthread_setspecific(sTlsKey, NULL);
18445 return NULL;
18446 }
18447 if (ctx->dd.config[idx] != NULL) {
18448 mg_cry_internal(fc(ctx), "warning: %s: duplicate option", name);
18449 mg_free(ctx->dd.config[idx]);
18450 }
18451 ctx->dd.config[idx] = mg_strdup_ctx(value, ctx);
18452 DEBUG_TRACE("[%s] -> [%s]", name, value);
18453 }
18454
18455 /* Set default value if needed */
18456 for (i = 0; config_options[i].name != NULL; i++) {
18457 default_value = config_options[i].default_value;
18458 if ((ctx->dd.config[i] == NULL) && (default_value != NULL)) {
18459 ctx->dd.config[i] = mg_strdup_ctx(default_value, ctx);
18460 }
18461 }
18462
18463 /* Request size option */
18464 itmp = atoi(ctx->dd.config[MAX_REQUEST_SIZE]);
18465 if (itmp < 1024) {
18466 mg_cry_internal(fc(ctx), "%s", "max_request_size too small");
18467 free_context(ctx);
18468 pthread_setspecific(sTlsKey, NULL);
18469 return NULL;
18470 }
18471 ctx->max_request_size = (unsigned)itmp;
18472
18473 /* Worker thread count option */
18474 workerthreadcount = atoi(ctx->dd.config[NUM_THREADS]);
18475
18476 if (workerthreadcount > MAX_WORKER_THREADS) {
18477 mg_cry_internal(fc(ctx), "%s", "Too many worker threads");
18478 free_context(ctx);
18479 pthread_setspecific(sTlsKey, NULL);
18480 return NULL;
18481 }
18482
18483 if (workerthreadcount <= 0) {
18484 mg_cry_internal(fc(ctx), "%s", "Invalid number of worker threads");
18485 free_context(ctx);
18486 pthread_setspecific(sTlsKey, NULL);
18487 return NULL;
18488 }
18489
18490/* Document root */
18491#if defined(NO_FILES)
18492 if (ctx->dd.config[DOCUMENT_ROOT] != NULL) {
18493 mg_cry_internal(fc(ctx), "%s", "Document root must not be set");
18494 free_context(ctx);
18495 pthread_setspecific(sTlsKey, NULL);
18496 return NULL;
18497 }
18498#endif
18499
18500 get_system_name(&ctx->systemName);
18501
18502#if defined(USE_LUA)
18503 /* If a Lua background script has been configured, start it. */
18504 if (ctx->dd.config[LUA_BACKGROUND_SCRIPT] != NULL) {
18505 char ebuf[256];
18506 struct vec opt_vec;
18507 struct vec eq_vec;
18508 const char *sparams;
18509 lua_State *state = mg_prepare_lua_context_script(
18510 ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
18511 if (!state) {
18512 mg_cry_internal(fc(ctx), "lua_background_script error: %s", ebuf);
18513 free_context(ctx);
18514 pthread_setspecific(sTlsKey, NULL);
18515 return NULL;
18516 }
18517 ctx->lua_background_state = (void *)state;
18518
18519 lua_newtable(state);
18520 reg_boolean(state, "shutdown", 0);
18521
18522 sparams = ctx->dd.config[LUA_BACKGROUND_SCRIPT_PARAMS];
18523
18524 while ((sparams = next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
18525 reg_llstring(
18526 state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
18527 if (mg_strncasecmp(sparams, opt_vec.ptr, opt_vec.len) == 0)
18528 break;
18529 }
18530 lua_setglobal(state, LUABACKGROUNDPARAMS);
18531
18532 } else {
18533 ctx->lua_background_state = 0;
18534 }
18535#endif
18536
18537 /* NOTE(lsm): order is important here. SSL certificates must
18538 * be initialized before listening ports. UID must be set last. */
18539 if (!set_gpass_option(ctx, NULL) ||
18540#if !defined(NO_SSL)
18541 !init_ssl_ctx(ctx, NULL) ||
18542#endif
18543 !set_ports_option(ctx) ||
18544#if !defined(_WIN32)
18545 !set_uid_option(ctx) ||
18546#endif
18547 !set_acl_option(ctx)) {
18548 free_context(ctx);
18549 pthread_setspecific(sTlsKey, NULL);
18550 return NULL;
18551 }
18552
18553 ctx->cfg_worker_threads = ((unsigned int)(workerthreadcount));
18554 ctx->worker_threadids = (pthread_t *)mg_calloc_ctx(ctx->cfg_worker_threads,
18555 sizeof(pthread_t),
18556 ctx);
18557
18558 if (ctx->worker_threadids == NULL) {
18559 mg_cry_internal(fc(ctx),
18560 "%s",
18561 "Not enough memory for worker thread ID array");
18562 free_context(ctx);
18563 pthread_setspecific(sTlsKey, NULL);
18564 return NULL;
18565 }
18566 ctx->worker_connections =
18567 (struct mg_connection *)mg_calloc_ctx(ctx->cfg_worker_threads,
18568 sizeof(struct mg_connection),
18569 ctx);
18570 if (ctx->worker_connections == NULL) {
18571 mg_cry_internal(fc(ctx),
18572 "%s",
18573 "Not enough memory for worker thread connection array");
18574 free_context(ctx);
18575 pthread_setspecific(sTlsKey, NULL);
18576 return NULL;
18577 }
18578
18579
18580#if defined(ALTERNATIVE_QUEUE)
18581 ctx->client_wait_events =
18582 (void **)mg_calloc_ctx(sizeof(ctx->client_wait_events[0]),
18583 ctx->cfg_worker_threads,
18584 ctx);
18585 if (ctx->client_wait_events == NULL) {
18586 mg_cry_internal(fc(ctx),
18587 "%s",
18588 "Not enough memory for worker event array");
18589 mg_free(ctx->worker_threadids);
18590 free_context(ctx);
18591 pthread_setspecific(sTlsKey, NULL);
18592 return NULL;
18593 }
18594
18595 ctx->client_socks =
18596 (struct socket *)mg_calloc_ctx(sizeof(ctx->client_socks[0]),
18597 ctx->cfg_worker_threads,
18598 ctx);
18599 if (ctx->client_socks == NULL) {
18600 mg_cry_internal(fc(ctx),
18601 "%s",
18602 "Not enough memory for worker socket array");
18603 mg_free(ctx->client_wait_events);
18604 mg_free(ctx->worker_threadids);
18605 free_context(ctx);
18606 pthread_setspecific(sTlsKey, NULL);
18607 return NULL;
18608 }
18609
18610 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18611 ctx->client_wait_events[i] = event_create();
18612 if (ctx->client_wait_events[i] == 0) {
18613 mg_cry_internal(fc(ctx), "Error creating worker event %i", i);
18614 while (i > 0) {
18615 i--;
18616 event_destroy(ctx->client_wait_events[i]);
18617 }
18618 mg_free(ctx->client_socks);
18619 mg_free(ctx->client_wait_events);
18620 mg_free(ctx->worker_threadids);
18621 free_context(ctx);
18622 pthread_setspecific(sTlsKey, NULL);
18623 return NULL;
18624 }
18625 }
18626#endif
18627
18628
18629#if defined(USE_TIMERS)
18630 if (timers_init(ctx) != 0) {
18631 mg_cry_internal(fc(ctx), "%s", "Error creating timers");
18632 free_context(ctx);
18633 pthread_setspecific(sTlsKey, NULL);
18634 return NULL;
18635 }
18636#endif
18637
18638 /* Context has been created - init user libraries */
18639 if (ctx->callbacks.init_context) {
18640 ctx->callbacks.init_context(ctx);
18641 }
18642 ctx->callbacks.exit_context = exit_callback;
18643 ctx->context_type = CONTEXT_SERVER; /* server context */
18644
18645 /* Start master (listening) thread */
18646 mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
18647
18648 /* Start worker threads */
18649 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18650 struct worker_thread_args *wta = (struct worker_thread_args *)
18651 mg_malloc_ctx(sizeof(struct worker_thread_args), ctx);
18652 if (wta) {
18653 wta->ctx = ctx;
18654 wta->index = (int)i;
18655 }
18656
18657 if ((wta == NULL)
18659 wta,
18660 &ctx->worker_threadids[i])
18661 != 0)) {
18662
18663 /* thread was not created */
18664 if (wta != NULL) {
18665 mg_free(wta);
18666 }
18667
18668 if (i > 0) {
18669 mg_cry_internal(fc(ctx),
18670 "Cannot start worker thread %i: error %ld",
18671 i + 1,
18672 (long)ERRNO);
18673 } else {
18674 mg_cry_internal(fc(ctx),
18675 "Cannot create threads: error %ld",
18676 (long)ERRNO);
18677 free_context(ctx);
18678 pthread_setspecific(sTlsKey, NULL);
18679 return NULL;
18680 }
18681 break;
18682 }
18683 }
18684
18685 pthread_setspecific(sTlsKey, NULL);
18686 return ctx;
18687}
18688
18689
18690#if defined(MG_EXPERIMENTAL_INTERFACES)
18691/* Add an additional domain to an already running web server. */
18692int
18693mg_start_domain(struct mg_context *ctx, const char **options)
18694{
18695 const char *name;
18696 const char *value;
18697 const char *default_value;
18698 struct mg_domain_context *new_dom;
18699 struct mg_domain_context *dom;
18700 int idx, i;
18701
18702 if ((ctx == NULL) || (ctx->stop_flag != 0) || (options == NULL)) {
18703 return -1;
18704 }
18705
18706 new_dom = (struct mg_domain_context *)
18707 mg_calloc_ctx(1, sizeof(struct mg_domain_context), ctx);
18708
18709 if (!new_dom) {
18710 /* Out of memory */
18711 return -6;
18712 }
18713
18714 /* Store options - TODO: unite duplicate code */
18715 while (options && (name = *options++) != NULL) {
18716 if ((idx = get_option_index(name)) == -1) {
18717 mg_cry_internal(fc(ctx), "Invalid option: %s", name);
18718 mg_free(new_dom);
18719 return -2;
18720 } else if ((value = *options++) == NULL) {
18721 mg_cry_internal(fc(ctx), "%s: option value cannot be NULL", name);
18722 mg_free(new_dom);
18723 return -2;
18724 }
18725 if (new_dom->config[idx] != NULL) {
18726 mg_cry_internal(fc(ctx), "warning: %s: duplicate option", name);
18727 mg_free(new_dom->config[idx]);
18728 }
18729 new_dom->config[idx] = mg_strdup_ctx(value, ctx);
18730 DEBUG_TRACE("[%s] -> [%s]", name, value);
18731 }
18732
18733 /* Authentication domain is mandatory */
18734 /* TODO: Maybe use a new option hostname? */
18735 if (!new_dom->config[AUTHENTICATION_DOMAIN]) {
18736 mg_cry_internal(fc(ctx), "%s", "authentication domain required");
18737 mg_free(new_dom);
18738 return -4;
18739 }
18740
18741 /* Set default value if needed. Take the config value from
18742 * ctx as a default value. */
18743 for (i = 0; config_options[i].name != NULL; i++) {
18744 default_value = ctx->dd.config[i];
18745 if ((new_dom->config[i] == NULL) && (default_value != NULL)) {
18746 new_dom->config[i] = mg_strdup_ctx(default_value, ctx);
18747 }
18748 }
18749
18750 new_dom->handlers = NULL;
18751 new_dom->next = NULL;
18752 new_dom->nonce_count = 0;
18753 new_dom->auth_nonce_mask =
18754 (uint64_t)get_random() ^ ((uint64_t)get_random() << 31);
18755
18756#if defined(USE_LUA) && defined(USE_WEBSOCKET)
18757 new_dom->shared_lua_websockets = NULL;
18758#endif
18759
18760 if (!init_ssl_ctx(ctx, new_dom)) {
18761 /* Init SSL failed */
18762 mg_free(new_dom);
18763 return -3;
18764 }
18765
18766 /* Add element to linked list. */
18767 mg_lock_context(ctx);
18768
18769 idx = 0;
18770 dom = &(ctx->dd);
18771 for (;;) {
18772 if (!strcasecmp(new_dom->config[AUTHENTICATION_DOMAIN],
18773 dom->config[AUTHENTICATION_DOMAIN])) {
18774 /* Domain collision */
18775 mg_cry_internal(fc(ctx),
18776 "domain %s already in use",
18777 new_dom->config[AUTHENTICATION_DOMAIN]);
18778 mg_free(new_dom);
18779 return -5;
18780 }
18781
18782 /* Count number of domains */
18783 idx++;
18784
18785 if (dom->next == NULL) {
18786 dom->next = new_dom;
18787 break;
18788 }
18789 dom = dom->next;
18790 }
18791
18792 mg_unlock_context(ctx);
18793
18794 /* Return domain number */
18795 return idx;
18796}
18797#endif
18798
18799
18800/* Feature check API function */
18801unsigned
18802mg_check_feature(unsigned feature)
18803{
18804 static const unsigned feature_set = 0
18805/* Set bits for available features according to API documentation.
18806 * This bit mask is created at compile time, according to the active
18807 * preprocessor defines. It is a single const value at runtime. */
18808#if !defined(NO_FILES)
18810#endif
18811#if !defined(NO_SSL)
18813#endif
18814#if !defined(NO_CGI)
18816#endif
18817#if defined(USE_IPV6)
18819#endif
18820#if defined(USE_WEBSOCKET)
18822#endif
18823#if defined(USE_LUA)
18825#endif
18826#if defined(USE_DUKTAPE)
18828#endif
18829#if !defined(NO_CACHING)
18831#endif
18832#if defined(USE_SERVER_STATS)
18834#endif
18835#if defined(USE_ZLIB)
18837#endif
18838
18839/* Set some extra bits not defined in the API documentation.
18840 * These bits may change without further notice. */
18841#if defined(MG_LEGACY_INTERFACE)
18842 | 0x00008000u
18843#endif
18844#if defined(MG_EXPERIMENTAL_INTERFACES)
18845 | 0x00004000u
18846#endif
18847#if defined(MEMORY_DEBUGGING)
18848 | 0x00001000u
18849#endif
18850#if defined(USE_TIMERS)
18851 | 0x00020000u
18852#endif
18853#if !defined(NO_NONCE_CHECK)
18854 | 0x00040000u
18855#endif
18856#if !defined(NO_POPEN)
18857 | 0x00080000u
18858#endif
18859 ;
18860 return (feature & feature_set);
18861}
18862
18863
18864/* strcat with additional NULL check to avoid clang scan-build warning. */
18865#define strcat0(a, b) \
18866 { \
18867 if ((a != NULL) && (b != NULL)) { \
18868 strcat(a, b); \
18869 } \
18870 }
18871
18872
18873/* Get system information. It can be printed or stored by the caller.
18874 * Return the size of available information. */
18875static int
18876mg_get_system_info_impl(char *buffer, int buflen)
18877{
18878 char block[256];
18879 int system_info_length = 0;
18880
18881#if defined(_WIN32)
18882 const char *eol = "\r\n";
18883#else
18884 const char *eol = "\n";
18885#endif
18886
18887 const char *eoobj = "}";
18888 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
18889
18890 if ((buffer == NULL) || (buflen < 1)) {
18891 buflen = 0;
18892 } else {
18893 *buffer = 0;
18894 }
18895
18896 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
18897 system_info_length += (int)strlen(block);
18898 if (system_info_length < buflen) {
18899 strcat0(buffer, block);
18900 }
18901
18902 /* Server version */
18903 {
18904 const char *version = mg_version();
18905 mg_snprintf(NULL,
18906 NULL,
18907 block,
18908 sizeof(block),
18909 "\"version\" : \"%s\",%s",
18910 version,
18911 eol);
18912 system_info_length += (int)strlen(block);
18913 if (system_info_length < buflen) {
18914 strcat0(buffer, block);
18915 }
18916 }
18917
18918 /* System info */
18919 {
18920#if defined(_WIN32)
18921 DWORD dwVersion = 0;
18922 DWORD dwMajorVersion = 0;
18923 DWORD dwMinorVersion = 0;
18924 SYSTEM_INFO si;
18925
18926 GetSystemInfo(&si);
18927
18928#if defined(_MSC_VER)
18929#pragma warning(push)
18930/* GetVersion was declared deprecated */
18931#pragma warning(disable : 4996)
18932#endif
18933 dwVersion = GetVersion();
18934#if defined(_MSC_VER)
18935#pragma warning(pop)
18936#endif
18937
18938 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
18939 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
18940
18941 mg_snprintf(NULL,
18942 NULL,
18943 block,
18944 sizeof(block),
18945 "\"os\" : \"Windows %u.%u\",%s",
18946 (unsigned)dwMajorVersion,
18947 (unsigned)dwMinorVersion,
18948 eol);
18949 system_info_length += (int)strlen(block);
18950 if (system_info_length < buflen) {
18951 strcat0(buffer, block);
18952 }
18953
18954 mg_snprintf(NULL,
18955 NULL,
18956 block,
18957 sizeof(block),
18958 "\"cpu\" : \"type %u, cores %u, mask %x\",%s",
18959 (unsigned)si.wProcessorArchitecture,
18960 (unsigned)si.dwNumberOfProcessors,
18961 (unsigned)si.dwActiveProcessorMask,
18962 eol);
18963 system_info_length += (int)strlen(block);
18964 if (system_info_length < buflen) {
18965 strcat0(buffer, block);
18966 }
18967#else
18968 struct utsname name;
18969 memset(&name, 0, sizeof(name));
18970 uname(&name);
18971
18972 mg_snprintf(NULL,
18973 NULL,
18974 block,
18975 sizeof(block),
18976 "\"os\" : \"%s %s (%s) - %s\",%s",
18977 name.sysname,
18978 name.version,
18979 name.release,
18980 name.machine,
18981 eol);
18982 system_info_length += (int)strlen(block);
18983 if (system_info_length < buflen) {
18984 strcat0(buffer, block);
18985 }
18986#endif
18987 }
18988
18989 /* Features */
18990 {
18991 mg_snprintf(NULL,
18992 NULL,
18993 block,
18994 sizeof(block),
18995 "\"features\" : %lu,%s"
18996 "\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\",%s",
18997 (unsigned long)mg_check_feature(0xFFFFFFFFu),
18998 eol,
18999 mg_check_feature(MG_FEATURES_FILES) ? " Files" : "",
19000 mg_check_feature(MG_FEATURES_SSL) ? " HTTPS" : "",
19001 mg_check_feature(MG_FEATURES_CGI) ? " CGI" : "",
19002 mg_check_feature(MG_FEATURES_IPV6) ? " IPv6" : "",
19004 : "",
19005 mg_check_feature(MG_FEATURES_LUA) ? " Lua" : "",
19006 mg_check_feature(MG_FEATURES_SSJS) ? " JavaScript" : "",
19007 mg_check_feature(MG_FEATURES_CACHE) ? " Cache" : "",
19008 mg_check_feature(MG_FEATURES_STATS) ? " Stats" : "",
19009 eol);
19010 system_info_length += (int)strlen(block);
19011 if (system_info_length < buflen) {
19012 strcat0(buffer, block);
19013 }
19014
19015#if defined(USE_LUA)
19016 mg_snprintf(NULL,
19017 NULL,
19018 block,
19019 sizeof(block),
19020 "\"lua_version\" : \"%u (%s)\",%s",
19021 (unsigned)LUA_VERSION_NUM,
19022 LUA_RELEASE,
19023 eol);
19024 system_info_length += (int)strlen(block);
19025 if (system_info_length < buflen) {
19026 strcat0(buffer, block);
19027 }
19028#endif
19029#if defined(USE_DUKTAPE)
19030 mg_snprintf(NULL,
19031 NULL,
19032 block,
19033 sizeof(block),
19034 "\"javascript\" : \"Duktape %u.%u.%u\",%s",
19035 (unsigned)DUK_VERSION / 10000,
19036 ((unsigned)DUK_VERSION / 100) % 100,
19037 (unsigned)DUK_VERSION % 100,
19038 eol);
19039 system_info_length += (int)strlen(block);
19040 if (system_info_length < buflen) {
19041 strcat0(buffer, block);
19042 }
19043#endif
19044 }
19045
19046 /* Build date */
19047 {
19048#if defined(GCC_DIAGNOSTIC)
19049#if GCC_VERSION >= 50000
19050#pragma GCC diagnostic push
19051/* Disable bogus compiler warning -Wdate-time */
19052#pragma GCC diagnostic ignored "-Wdate-time"
19053#endif
19054#endif
19055 mg_snprintf(NULL,
19056 NULL,
19057 block,
19058 sizeof(block),
19059 "\"build\" : \"%s\",%s",
19060 __DATE__,
19061 eol);
19062
19063#if defined(GCC_DIAGNOSTIC)
19064#if GCC_VERSION >= 50000
19065#pragma GCC diagnostic pop
19066#endif
19067#endif
19068
19069 system_info_length += (int)strlen(block);
19070 if (system_info_length < buflen) {
19071 strcat0(buffer, block);
19072 }
19073 }
19074
19075
19076 /* Compiler information */
19077 /* http://sourceforge.net/p/predef/wiki/Compilers/ */
19078 {
19079#if defined(_MSC_VER)
19080 mg_snprintf(NULL,
19081 NULL,
19082 block,
19083 sizeof(block),
19084 "\"compiler\" : \"MSC: %u (%u)\",%s",
19085 (unsigned)_MSC_VER,
19086 (unsigned)_MSC_FULL_VER,
19087 eol);
19088 system_info_length += (int)strlen(block);
19089 if (system_info_length < buflen) {
19090 strcat0(buffer, block);
19091 }
19092#elif defined(__MINGW64__)
19093 mg_snprintf(NULL,
19094 NULL,
19095 block,
19096 sizeof(block),
19097 "\"compiler\" : \"MinGW64: %u.%u\",%s",
19098 (unsigned)__MINGW64_VERSION_MAJOR,
19099 (unsigned)__MINGW64_VERSION_MINOR,
19100 eol);
19101 system_info_length += (int)strlen(block);
19102 if (system_info_length < buflen) {
19103 strcat0(buffer, block);
19104 }
19105 mg_snprintf(NULL,
19106 NULL,
19107 block,
19108 sizeof(block),
19109 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19110 (unsigned)__MINGW32_MAJOR_VERSION,
19111 (unsigned)__MINGW32_MINOR_VERSION,
19112 eol);
19113 system_info_length += (int)strlen(block);
19114 if (system_info_length < buflen) {
19115 strcat0(buffer, block);
19116 }
19117#elif defined(__MINGW32__)
19118 mg_snprintf(NULL,
19119 NULL,
19120 block,
19121 sizeof(block),
19122 "\"compiler\" : \"MinGW32: %u.%u\",%s",
19123 (unsigned)__MINGW32_MAJOR_VERSION,
19124 (unsigned)__MINGW32_MINOR_VERSION,
19125 eol);
19126 system_info_length += (int)strlen(block);
19127 if (system_info_length < buflen) {
19128 strcat0(buffer, block);
19129 }
19130#elif defined(__clang__)
19131 mg_snprintf(NULL,
19132 NULL,
19133 block,
19134 sizeof(block),
19135 "\"compiler\" : \"clang: %u.%u.%u (%s)\",%s",
19136 __clang_major__,
19137 __clang_minor__,
19138 __clang_patchlevel__,
19139 __clang_version__,
19140 eol);
19141 system_info_length += (int)strlen(block);
19142 if (system_info_length < buflen) {
19143 strcat0(buffer, block);
19144 }
19145#elif defined(__GNUC__)
19146 mg_snprintf(NULL,
19147 NULL,
19148 block,
19149 sizeof(block),
19150 "\"compiler\" : \"gcc: %u.%u.%u\",%s",
19151 (unsigned)__GNUC__,
19152 (unsigned)__GNUC_MINOR__,
19153 (unsigned)__GNUC_PATCHLEVEL__,
19154 eol);
19155 system_info_length += (int)strlen(block);
19156 if (system_info_length < buflen) {
19157 strcat0(buffer, block);
19158 }
19159#elif defined(__INTEL_COMPILER)
19160 mg_snprintf(NULL,
19161 NULL,
19162 block,
19163 sizeof(block),
19164 "\"compiler\" : \"Intel C/C++: %u\",%s",
19165 (unsigned)__INTEL_COMPILER,
19166 eol);
19167 system_info_length += (int)strlen(block);
19168 if (system_info_length < buflen) {
19169 strcat0(buffer, block);
19170 }
19171#elif defined(__BORLANDC__)
19172 mg_snprintf(NULL,
19173 NULL,
19174 block,
19175 sizeof(block),
19176 "\"compiler\" : \"Borland C: 0x%x\",%s",
19177 (unsigned)__BORLANDC__,
19178 eol);
19179 system_info_length += (int)strlen(block);
19180 if (system_info_length < buflen) {
19181 strcat0(buffer, block);
19182 }
19183#elif defined(__SUNPRO_C)
19184 mg_snprintf(NULL,
19185 NULL,
19186 block,
19187 sizeof(block),
19188 "\"compiler\" : \"Solaris: 0x%x\",%s",
19189 (unsigned)__SUNPRO_C,
19190 eol);
19191 system_info_length += (int)strlen(block);
19192 if (system_info_length < buflen) {
19193 strcat0(buffer, block);
19194 }
19195#else
19196 mg_snprintf(NULL,
19197 NULL,
19198 block,
19199 sizeof(block),
19200 "\"compiler\" : \"other\",%s",
19201 eol);
19202 system_info_length += (int)strlen(block);
19203 if (system_info_length < buflen) {
19204 strcat0(buffer, block);
19205 }
19206#endif
19207 }
19208
19209 /* Determine 32/64 bit data mode.
19210 * see https://en.wikipedia.org/wiki/64-bit_computing */
19211 {
19212 mg_snprintf(NULL,
19213 NULL,
19214 block,
19215 sizeof(block),
19216 "\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, "
19217 "char:%u/%u, "
19218 "ptr:%u, size:%u, time:%u\"%s",
19219 (unsigned)sizeof(short),
19220 (unsigned)sizeof(int),
19221 (unsigned)sizeof(long),
19222 (unsigned)sizeof(long long),
19223 (unsigned)sizeof(float),
19224 (unsigned)sizeof(double),
19225 (unsigned)sizeof(long double),
19226 (unsigned)sizeof(char),
19227 (unsigned)sizeof(wchar_t),
19228 (unsigned)sizeof(void *),
19229 (unsigned)sizeof(size_t),
19230 (unsigned)sizeof(time_t),
19231 eol);
19232 system_info_length += (int)strlen(block);
19233 if (system_info_length < buflen) {
19234 strcat0(buffer, block);
19235 }
19236 }
19237
19238 /* Terminate string */
19239 if ((buflen > 0) && buffer && buffer[0]) {
19240 if (system_info_length < buflen) {
19241 strcat0(buffer, eoobj);
19242 strcat0(buffer, eol);
19243 }
19244 }
19245 system_info_length += reserved_len;
19246
19247 return system_info_length;
19248}
19249
19250
19251#if defined(USE_SERVER_STATS)
19252/* Get context information. It can be printed or stored by the caller.
19253 * Return the size of available information. */
19254static int
19255mg_get_context_info_impl(const struct mg_context *ctx, char *buffer, int buflen)
19256
19257{
19258 char block[256];
19259 int context_info_length = 0;
19260
19261#if defined(_WIN32)
19262 const char *eol = "\r\n";
19263#else
19264 const char *eol = "\n";
19265#endif
19266 struct mg_memory_stat *ms = get_memory_stat((struct mg_context *)ctx);
19267
19268 const char *eoobj = "}";
19269 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
19270
19271 if ((buffer == NULL) || (buflen < 1)) {
19272 buflen = 0;
19273 } else {
19274 *buffer = 0;
19275 }
19276
19277 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
19278 context_info_length += (int)strlen(block);
19279 if (context_info_length < buflen) {
19280 strcat0(buffer, block);
19281 }
19282
19283 if (ms) { /* <-- should be always true */
19284 /* Memory information */
19285 mg_snprintf(NULL,
19286 NULL,
19287 block,
19288 sizeof(block),
19289 "\"memory\" : {%s"
19290 "\"blocks\" : %i,%s"
19291 "\"used\" : %" INT64_FMT ",%s"
19292 "\"maxUsed\" : %" INT64_FMT "%s"
19293 "}%s%s",
19294 eol,
19295 ms->blockCount,
19296 eol,
19297 ms->totalMemUsed,
19298 eol,
19299 ms->maxMemUsed,
19300 eol,
19301 (ctx ? "," : ""),
19302 eol);
19303
19304 context_info_length += (int)strlen(block);
19305 if (context_info_length + reserved_len < buflen) {
19306 strcat0(buffer, block);
19307 }
19308 }
19309
19310 if (ctx) {
19311 /* Declare all variables at begin of the block, to comply
19312 * with old C standards. */
19313 char start_time_str[64] = {0};
19314 char now_str[64] = {0};
19315 time_t start_time = ctx->start_time;
19316 time_t now = time(NULL);
19317
19318 /* Connections information */
19319 mg_snprintf(NULL,
19320 NULL,
19321 block,
19322 sizeof(block),
19323 "\"connections\" : {%s"
19324 "\"active\" : %i,%s"
19325 "\"maxActive\" : %i,%s"
19326 "\"total\" : %" INT64_FMT "%s"
19327 "},%s",
19328 eol,
19329 ctx->active_connections,
19330 eol,
19331 ctx->max_connections,
19332 eol,
19333 ctx->total_connections,
19334 eol,
19335 eol);
19336
19337 context_info_length += (int)strlen(block);
19338 if (context_info_length + reserved_len < buflen) {
19339 strcat0(buffer, block);
19340 }
19341
19342 /* Requests information */
19343 mg_snprintf(NULL,
19344 NULL,
19345 block,
19346 sizeof(block),
19347 "\"requests\" : {%s"
19348 "\"total\" : %" INT64_FMT "%s"
19349 "},%s",
19350 eol,
19351 ctx->total_requests,
19352 eol,
19353 eol);
19354
19355 context_info_length += (int)strlen(block);
19356 if (context_info_length + reserved_len < buflen) {
19357 strcat0(buffer, block);
19358 }
19359
19360 /* Data information */
19361 mg_snprintf(NULL,
19362 NULL,
19363 block,
19364 sizeof(block),
19365 "\"data\" : {%s"
19366 "\"read\" : %" INT64_FMT "%s,"
19367 "\"written\" : %" INT64_FMT "%s"
19368 "},%s",
19369 eol,
19370 ctx->total_data_read,
19371 eol,
19372 ctx->total_data_written,
19373 eol,
19374 eol);
19375
19376 context_info_length += (int)strlen(block);
19377 if (context_info_length + reserved_len < buflen) {
19378 strcat0(buffer, block);
19379 }
19380
19381 /* Execution time information */
19382 gmt_time_string(start_time_str,
19383 sizeof(start_time_str) - 1,
19384 &start_time);
19385 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
19386
19387 mg_snprintf(NULL,
19388 NULL,
19389 block,
19390 sizeof(block),
19391 "\"time\" : {%s"
19392 "\"uptime\" : %.0f,%s"
19393 "\"start\" : \"%s\",%s"
19394 "\"now\" : \"%s\"%s"
19395 "}%s",
19396 eol,
19397 difftime(now, start_time),
19398 eol,
19399 start_time_str,
19400 eol,
19401 now_str,
19402 eol,
19403 eol);
19404
19405 context_info_length += (int)strlen(block);
19406 if (context_info_length + reserved_len < buflen) {
19407 strcat0(buffer, block);
19408 }
19409 }
19410
19411 /* Terminate string */
19412 if ((buflen > 0) && buffer && buffer[0]) {
19413 if (context_info_length < buflen) {
19414 strcat0(buffer, eoobj);
19415 strcat0(buffer, eol);
19416 }
19417 }
19418 context_info_length += reserved_len;
19419
19420 return context_info_length;
19421}
19422#endif
19423
19424
19425#if defined(MG_EXPERIMENTAL_INTERFACES)
19426/* Get connection information. It can be printed or stored by the caller.
19427 * Return the size of available information. */
19428static int
19429mg_get_connection_info_impl(const struct mg_context *ctx,
19430 int idx,
19431 char *buffer,
19432 int buflen)
19433{
19434 const struct mg_connection *conn;
19435 const struct mg_request_info *ri;
19436 char block[256];
19437 int connection_info_length = 0;
19438 int state = 0;
19439 const char *state_str = "unknown";
19440
19441#if defined(_WIN32)
19442 const char *eol = "\r\n";
19443#else
19444 const char *eol = "\n";
19445#endif
19446
19447 const char *eoobj = "}";
19448 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
19449
19450 if ((buffer == NULL) || (buflen < 1)) {
19451 buflen = 0;
19452 } else {
19453 *buffer = 0;
19454 }
19455
19456 if ((ctx == NULL) || (idx < 0)) {
19457 /* Parameter error */
19458 return 0;
19459 }
19460
19461 if ((unsigned)idx >= ctx->cfg_worker_threads) {
19462 /* Out of range */
19463 return 0;
19464 }
19465
19466 /* Take connection [idx]. This connection is not locked in
19467 * any way, so some other thread might use it. */
19468 conn = (ctx->worker_connections) + idx;
19469
19470 /* Initialize output string */
19471 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
19472 connection_info_length += (int)strlen(block);
19473 if (connection_info_length < buflen) {
19474 strcat0(buffer, block);
19475 }
19476
19477 /* Init variables */
19478 ri = &(conn->request_info);
19479
19480#if defined(USE_SERVER_STATS)
19481 state = conn->conn_state;
19482
19483 /* State as string */
19484 switch (state) {
19485 case 0:
19486 state_str = "undefined";
19487 break;
19488 case 1:
19489 state_str = "not used";
19490 break;
19491 case 2:
19492 state_str = "init";
19493 break;
19494 case 3:
19495 state_str = "ready";
19496 break;
19497 case 4:
19498 state_str = "processing";
19499 break;
19500 case 5:
19501 state_str = "processed";
19502 break;
19503 case 6:
19504 state_str = "to close";
19505 break;
19506 case 7:
19507 state_str = "closing";
19508 break;
19509 case 8:
19510 state_str = "closed";
19511 break;
19512 case 9:
19513 state_str = "done";
19514 break;
19515 }
19516#endif
19517
19518 /* Connection info */
19519 if ((state >= 3) && (state < 9)) {
19520 mg_snprintf(NULL,
19521 NULL,
19522 block,
19523 sizeof(block),
19524 "\"connection\" : {%s"
19525 "\"remote\" : {%s"
19526 "\"protocol\" : \"%s\",%s"
19527 "\"addr\" : \"%s\",%s"
19528 "\"port\" : %u%s"
19529 "},%s"
19530 "\"handled_requests\" : %u%s"
19531 "},%s",
19532 eol,
19533 eol,
19534 get_proto_name(conn),
19535 eol,
19536 ri->remote_addr,
19537 eol,
19538 ri->remote_port,
19539 eol,
19540 eol,
19541 conn->handled_requests,
19542 eol,
19543 eol);
19544
19545 connection_info_length += (int)strlen(block);
19546 if (connection_info_length + reserved_len < buflen) {
19547 strcat0(buffer, block);
19548 }
19549 }
19550
19551 /* Request info */
19552 if ((state >= 4) && (state < 6)) {
19553 mg_snprintf(NULL,
19554 NULL,
19555 block,
19556 sizeof(block),
19557 "\"request_info\" : {%s"
19558 "\"method\" : \"%s\",%s"
19559 "\"uri\" : \"%s\",%s"
19560 "\"query\" : %s%s%s%s"
19561 "},%s",
19562 eol,
19563 ri->request_method,
19564 eol,
19565 ri->request_uri,
19566 eol,
19567 ri->query_string ? "\"" : "",
19568 ri->query_string ? ri->query_string : "null",
19569 ri->query_string ? "\"" : "",
19570 eol,
19571 eol);
19572
19573 connection_info_length += (int)strlen(block);
19574 if (connection_info_length + reserved_len < buflen) {
19575 strcat0(buffer, block);
19576 }
19577 }
19578
19579 /* Execution time information */
19580 if ((state >= 2) && (state < 9)) {
19581 char start_time_str[64] = {0};
19582 char now_str[64] = {0};
19583 time_t start_time = conn->conn_birth_time;
19584 time_t now = time(NULL);
19585
19586 gmt_time_string(start_time_str,
19587 sizeof(start_time_str) - 1,
19588 &start_time);
19589 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
19590
19591 mg_snprintf(NULL,
19592 NULL,
19593 block,
19594 sizeof(block),
19595 "\"time\" : {%s"
19596 "\"uptime\" : %.0f,%s"
19597 "\"start\" : \"%s\",%s"
19598 "\"now\" : \"%s\"%s"
19599 "},%s",
19600 eol,
19601 difftime(now, start_time),
19602 eol,
19603 start_time_str,
19604 eol,
19605 now_str,
19606 eol,
19607 eol);
19608
19609 connection_info_length += (int)strlen(block);
19610 if (connection_info_length + reserved_len < buflen) {
19611 strcat0(buffer, block);
19612 }
19613 }
19614
19615 /* Remote user name */
19616 if ((ri->remote_user) && (state < 9)) {
19617 mg_snprintf(NULL,
19618 NULL,
19619 block,
19620 sizeof(block),
19621 "\"user\" : {%s"
19622 "\"name\" : \"%s\",%s"
19623 "},%s",
19624 eol,
19625 ri->remote_user,
19626 eol,
19627 eol);
19628
19629 connection_info_length += (int)strlen(block);
19630 if (connection_info_length + reserved_len < buflen) {
19631 strcat0(buffer, block);
19632 }
19633 }
19634
19635 /* Data block */
19636 if (state >= 3) {
19637 mg_snprintf(NULL,
19638 NULL,
19639 block,
19640 sizeof(block),
19641 "\"data\" : {%s"
19642 "\"read\" : %" INT64_FMT ",%s"
19643 "\"written\" : %" INT64_FMT "%s"
19644 "},%s",
19645 eol,
19646 conn->consumed_content,
19647 eol,
19648 conn->num_bytes_sent,
19649 eol,
19650 eol);
19651
19652 connection_info_length += (int)strlen(block);
19653 if (connection_info_length + reserved_len < buflen) {
19654 strcat0(buffer, block);
19655 }
19656 }
19657
19658 /* State */
19659 mg_snprintf(NULL,
19660 NULL,
19661 block,
19662 sizeof(block),
19663 "\"state\" : \"%s\"%s",
19664 state_str,
19665 eol);
19666
19667 connection_info_length += (int)strlen(block);
19668 if (connection_info_length + reserved_len < buflen) {
19669 strcat0(buffer, block);
19670 }
19671
19672 /* Terminate string */
19673 if ((buflen > 0) && buffer && buffer[0]) {
19674 if (connection_info_length < buflen) {
19675 strcat0(buffer, eoobj);
19676 strcat0(buffer, eol);
19677 }
19678 }
19679 connection_info_length += reserved_len;
19680
19681 return connection_info_length;
19682}
19683#endif
19684
19685
19686/* Get system information. It can be printed or stored by the caller.
19687 * Return the size of available information. */
19688int
19689mg_get_system_info(char *buffer, int buflen)
19690{
19691 if ((buffer == NULL) || (buflen < 1)) {
19692 return mg_get_system_info_impl(NULL, 0);
19693 } else {
19694 /* Reset buffer, so we can always use strcat. */
19695 buffer[0] = 0;
19696 return mg_get_system_info_impl(buffer, buflen);
19697 }
19698}
19699
19700
19701/* Get context information. It can be printed or stored by the caller.
19702 * Return the size of available information. */
19703int
19704mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
19705{
19706#if defined(USE_SERVER_STATS)
19707 if ((buffer == NULL) || (buflen < 1)) {
19708 return mg_get_context_info_impl(ctx, NULL, 0);
19709 } else {
19710 /* Reset buffer, so we can always use strcat. */
19711 buffer[0] = 0;
19712 return mg_get_context_info_impl(ctx, buffer, buflen);
19713 }
19714#else
19715 (void)ctx;
19716 if ((buffer != NULL) && (buflen > 0)) {
19717 buffer[0] = 0;
19718 }
19719 return 0;
19720#endif
19721}
19722
19723
19724#if defined(MG_EXPERIMENTAL_INTERFACES)
19725int
19726mg_get_connection_info(const struct mg_context *ctx,
19727 int idx,
19728 char *buffer,
19729 int buflen)
19730{
19731 if ((buffer == NULL) || (buflen < 1)) {
19732 return mg_get_connection_info_impl(ctx, idx, NULL, 0);
19733 } else {
19734 /* Reset buffer, so we can always use strcat. */
19735 buffer[0] = 0;
19736 return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
19737 }
19738}
19739#endif
19740
19741
19742/* Initialize this library. This function does not need to be thread safe.
19743 */
19744unsigned
19745mg_init_library(unsigned features)
19746{
19747#if !defined(NO_SSL)
19748 char ebuf[128];
19749#endif
19750
19751 unsigned features_to_init = mg_check_feature(features & 0xFFu);
19752 unsigned features_inited = features_to_init;
19753
19754 if (mg_init_library_called <= 0) {
19755 /* Not initialized yet */
19756 if (0 != pthread_mutex_init(&global_lock_mutex, NULL)) {
19757 return 0;
19758 }
19759 }
19760
19762
19763 if (mg_init_library_called <= 0) {
19764 if (0 != pthread_key_create(&sTlsKey, tls_dtor)) {
19765 /* Fatal error - abort start. However, this situation should
19766 * never occur in practice. */
19768 return 0;
19769 }
19770
19771#if defined(_WIN32)
19772 InitializeCriticalSection(&global_log_file_lock);
19773#endif
19774#if !defined(_WIN32)
19775 pthread_mutexattr_init(&pthread_mutex_attr);
19776 pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
19777#endif
19778
19779#if defined(USE_LUA)
19780 lua_init_optional_libraries();
19781#endif
19782 }
19783
19785
19786#if !defined(NO_SSL)
19787 if (features_to_init & MG_FEATURES_SSL) {
19788 if (!mg_ssl_initialized) {
19789 if (initialize_ssl(ebuf, sizeof(ebuf))) {
19791 } else {
19792 (void)ebuf;
19793 DEBUG_TRACE("Initializing SSL failed: %s", ebuf);
19794 features_inited &= ~((unsigned)(MG_FEATURES_SSL));
19795 }
19796 } else {
19797 /* ssl already initialized */
19798 }
19799 }
19800#endif
19801
19802 /* Start WinSock for Windows */
19804 if (mg_init_library_called <= 0) {
19805#if defined(_WIN32)
19806 WSADATA data;
19807 WSAStartup(MAKEWORD(2, 2), &data);
19808#endif /* _WIN32 */
19810 } else {
19812 }
19814
19815 return features_inited;
19816}
19817
19818
19819/* Un-initialize this library. */
19820unsigned
19822{
19823 if (mg_init_library_called <= 0) {
19824 return 0;
19825 }
19826
19828
19830 if (mg_init_library_called == 0) {
19831#if defined(_WIN32)
19832 (void)WSACleanup();
19833#endif /* _WIN32 */
19834#if !defined(NO_SSL)
19835 if (mg_ssl_initialized) {
19838 }
19839#endif
19840
19841#if defined(_WIN32)
19842 (void)DeleteCriticalSection(&global_log_file_lock);
19843#endif /* _WIN32 */
19844#if !defined(_WIN32)
19845 (void)pthread_mutexattr_destroy(&pthread_mutex_attr);
19846#endif
19847
19848 (void)pthread_key_delete(sTlsKey);
19849
19850#if defined(USE_LUA)
19851 lua_exit_optional_libraries();
19852#endif
19853
19855 (void)pthread_mutex_destroy(&global_lock_mutex);
19856 return 1;
19857 }
19858
19860 return 1;
19861}
19862
19863
19864/* End of civetweb.c */
double
long
uint8_t
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]
static unsigned int total
char name[80]
Definition TGX11.cxx:110
#define INVALID_HANDLE_VALUE
Definition TMapFile.cxx:84
double sin(double)
R__EXTERN C unsigned int sleep(unsigned int seconds)
typedef void((*Func_t)())
static void process_new_connection(struct mg_connection *conn)
Definition civetweb.c:17423
static int set_tcp_nodelay(SOCKET sock, int nodelay_on)
Definition civetweb.c:16103
#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:17638
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 const struct @139 abs_uri_protocols[]
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
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
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:15253
const char * proto
Definition civetweb.c:16604
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:16710
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
#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:14921
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
@ AUTH_HANDLER
Definition civetweb.c:2524
@ REQUEST_HANDLER
Definition civetweb.c:2524
@ WEBSOCKET_HANDLER
Definition civetweb.c:2524
#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:12849
#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:15498
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:15131
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:12830
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:14217
#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:16606
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:16990
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:14867
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:16014
static void handle_file_based_request(struct mg_connection *conn, const char *path, struct mg_file *filep)
Definition civetweb.c:14125
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:15029
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
@ 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
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:15359
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:17930
static int get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
Definition civetweb.c:16824
#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:15569
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:17107
#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:17052
#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:16378
unsigned mg_check_feature(unsigned feature)
Definition civetweb.c:18802
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:18342
#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:13386
static const char * alloc_get_host(struct mg_connection *conn)
Definition civetweb.c:13012
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:15612
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:15270
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:15678
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:19745
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:16586
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:18013
static int set_gpass_option(struct mg_context *phys_ctx, struct mg_domain_context *dom_ctx)
Definition civetweb.c:15984
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:16899
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:14250
static int get_first_ssl_listener_index(const struct mg_context *ctx)
Definition civetweb.c:12996
#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:12823
static uint32_t get_remote_ip(const struct mg_connection *conn)
Definition civetweb.c:12884
static int hexdump2string(void *mem, int memlen, char *buf, int buflen)
Definition civetweb.c:15140
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:14449
#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:19821
#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:17224
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:15596
#define ASN1_INTEGER_to_BN
Definition civetweb.c:2111
#define calloc
Definition civetweb.c:1537
#define SSL_ERROR_WANT_ACCEPT
Definition civetweb.c:1806
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 struct @138 builtin_mime_types[]
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:16621
#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:18290
@ 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
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:13169
static const char * header_val(const struct mg_connection *conn, const char *header)
Definition civetweb.c:14715
#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:16007
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:16574
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:15033
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:18147
#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:13181
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:13159
void mg_close_connection(struct mg_connection *conn)
Definition civetweb.c:16304
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:17617
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:13458
static void ssl_get_client_cert_info(struct mg_connection *conn)
Definition civetweb.c:15166
#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:13572
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:18163
#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:19704
static int thread_idx_max
Definition civetweb.c:1556
static int cryptolib_users
Definition civetweb.c:15354
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:14946
#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:15943
#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:13628
#define malloc
Definition civetweb.c:1536
static int mg_get_system_info_impl(char *buffer, int buflen)
Definition civetweb.c:18876
#define INT64_MAX
Definition civetweb.c:439
static void * worker_thread_run(struct worker_thread_args *thread_args)
Definition civetweb.c:17727
#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:13150
#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:15346
#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:13364
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:16374
static void * worker_thread(void *thread_func_param)
Definition civetweb.c:17909
#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:19689
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:15868
static void close_socket_gracefully(struct mg_connection *conn)
Definition civetweb.c:16120
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:14392
static void init_connection(struct mg_connection *conn)
Definition civetweb.c:17386
#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:16605
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:13406
static int mg_ssl_initialized
Definition civetweb.c:1552
static void * ssllib_dll_handle
Definition civetweb.c:15345
#define OPENSSL_INIT_LOAD_SSL_STRINGS
Definition civetweb.c:1777
#define mg_sleep(x)
Definition civetweb.c:804
#define PASSWORDS_FILE_NAME
Definition civetweb.c:406
static void log_access(const struct mg_connection *conn)
Definition civetweb.c:14733
#define SSLv23_server_method
Definition civetweb.c:2009
static void close_connection(struct mg_connection *conn)
Definition civetweb.c:16240
@ CONNECTION_TYPE_RESPONSE
Definition civetweb.c:2692
@ CONNECTION_TYPE_INVALID
Definition civetweb.c:2690
@ CONNECTION_TYPE_REQUEST
Definition civetweb.c:2691
#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:13099
void mg_stop(struct mg_context *ctx)
Definition civetweb.c:18256
#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:14832
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:13436
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:18865
#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
@ 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
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
@ 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
#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)
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
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
@ 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
TLine * line
Double_t y[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
struct md5_state_s md5_state_t
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(const RooAbsArg &v1)
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
void(* exit_context)(const struct mg_context *ctx)
Definition civetweb.h:364
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
const char * value
Definition civetweb.h:140
const char * name
Definition civetweb.h:139
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
const char * request_method
Definition civetweb.h:146
const char * query_string
Definition civetweb.h:156
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 * remote_user
Definition civetweb.h:158
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
int pw_gid
int pw_uid
auto * m
Definition textangle.C:8
auto * l
Definition textangle.C:4
static void output(int code)
Definition gifencode.c:226