]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/civetweb.c
buildsys: switch source download to quincy
[ceph.git] / ceph / src / civetweb / src / civetweb.c
CommitLineData
11fdf7f2 1/* Copyright (c) 2013-2017 the Civetweb developers
7c673cae
FG
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
7c673cae
FG
23#if defined(_WIN32)
24#if !defined(_CRT_SECURE_NO_WARNINGS)
25#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
26#endif
27#ifndef _WIN32_WINNT /* defined for tdm-gcc so we can use getnameinfo */
28#define _WIN32_WINNT 0x0501
29#endif
30#else
31#if defined(__GNUC__) && !defined(_GNU_SOURCE)
32#define _GNU_SOURCE /* for setgroups() */
33#endif
34#if defined(__linux__) && !defined(_XOPEN_SOURCE)
35#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
36#endif
37#ifndef _LARGEFILE_SOURCE
38#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
39#endif
40#ifndef _FILE_OFFSET_BITS
41#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
42#endif
43#ifndef __STDC_FORMAT_MACROS
44#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
45#endif
46#ifndef __STDC_LIMIT_MACROS
47#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
48#endif
49#ifdef __sun
50#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
51#define __inline inline /* not recognized on older compiler versions */
52#endif
53#endif
54
11fdf7f2 55#if defined(USE_LUA)
7c673cae
FG
56#define USE_TIMERS
57#endif
58
59#if defined(_MSC_VER)
60/* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
61#pragma warning(disable : 4306)
62/* conditional expression is constant: introduced by FD_SET(..) */
63#pragma warning(disable : 4127)
64/* non-constant aggregate initializer: issued due to missing C99 support */
65#pragma warning(disable : 4204)
66/* padding added after data member */
67#pragma warning(disable : 4820)
68/* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
69#pragma warning(disable : 4668)
70/* no function prototype given: converting '()' to '(void)' */
71#pragma warning(disable : 4255)
72/* function has been selected for automatic inline expansion */
73#pragma warning(disable : 4711)
74#endif
75
76
77/* This code uses static_assert to check some conditions.
78 * Unfortunately some compilers still do not support it, so we have a
79 * replacement function here. */
80#if defined(_MSC_VER) && (_MSC_VER >= 1600)
81#define mg_static_assert static_assert
82#elif defined(__cplusplus) && (__cplusplus >= 201103L)
83#define mg_static_assert static_assert
84#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
85#define mg_static_assert _Static_assert
86#else
87char static_assert_replacement[1];
88#define mg_static_assert(cond, txt) \
89 extern char static_assert_replacement[(cond) ? 1 : -1]
90#endif
91
92mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
93 "int data type size check");
94mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
95 "pointer data type size check");
96mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
11fdf7f2
TL
97
98
99/* Alternative queue is well tested and should be the new default */
100#ifdef NO_ALTERNATIVE_QUEUE
101#ifdef ALTERNATIVE_QUEUE
102#error "Define ALTERNATIVE_QUEUE or NO_ALTERNATIVE_QUEUE or none, but not both"
103#endif
104#else
105#define ALTERNATIVE_QUEUE
106#endif
107
7c673cae
FG
108
109/* DTL -- including winsock2.h works better if lean and mean */
110#ifndef WIN32_LEAN_AND_MEAN
111#define WIN32_LEAN_AND_MEAN
112#endif
113
114#if defined(__SYMBIAN32__)
11fdf7f2
TL
115/* According to https://en.wikipedia.org/wiki/Symbian#History,
116 * Symbian is no longer maintained since 2014-01-01.
117 * Recent versions of CivetWeb are no longer tested for Symbian.
118 * It makes no sense, to support an abandoned operating system.
119 * All remaining "#ifdef __SYMBIAN__" cases will be droped from
120 * the code sooner or later.
121 */
122#pragma message \
123 "Symbian is no longer maintained. CivetWeb will drop Symbian support."
7c673cae
FG
124#define NO_SSL /* SSL is not supported */
125#define NO_CGI /* CGI is not supported */
126#define PATH_MAX FILENAME_MAX
127#endif /* __SYMBIAN32__ */
128
129
11fdf7f2 130#ifndef CIVETWEB_HEADER_INCLUDED
7c673cae
FG
131/* Include the header file here, so the CivetWeb interface is defined for the
132 * entire implementation, including the following forward definitions. */
133#include "civetweb.h"
11fdf7f2 134#endif
7c673cae
FG
135
136
137#ifndef IGNORE_UNUSED_RESULT
138#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
139#endif
140
11fdf7f2
TL
141
142#if defined(__GNUC__) || defined(__MINGW32__)
143
144/* GCC unused function attribute seems fundamentally broken.
145 * Several attempts to tell the compiler "THIS FUNCTION MAY BE USED
146 * OR UNUSED" for individual functions failed.
147 * Either the compiler creates an "unused-function" warning if a
148 * function is not marked with __attribute__((unused)).
149 * On the other hand, if the function is marked with this attribute,
150 * but is used, the compiler raises a completely idiotic
151 * "used-but-marked-unused" warning - and
152 * #pragma GCC diagnostic ignored "-Wused-but-marked-unused"
153 * raises error: unknown option after ‘#pragma GCC diagnostic’.
154 * Disable this warning completely, until the GCC guys sober up
155 * again.
156 */
157
158#pragma GCC diagnostic ignored "-Wunused-function"
159
160#define FUNCTION_MAY_BE_UNUSED /* __attribute__((unused)) */
161
162#else
163#define FUNCTION_MAY_BE_UNUSED
164#endif
165
166
7c673cae
FG
167#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
168#include <sys/types.h>
169#include <sys/stat.h>
170#include <errno.h>
171#include <signal.h>
172#include <fcntl.h>
173#endif /* !_WIN32_WCE */
174
11fdf7f2
TL
175
176#ifdef __clang__
177/* When using -Weverything, clang does not accept it's own headers
178 * in a release build configuration. Disable what is too much in
179 * -Weverything. */
180#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
181#endif
182
183#if defined(__GNUC__) || defined(__MINGW32__)
184/* Who on earth came to the conclusion, using __DATE__ should rise
185 * an "expansion of date or time macro is not reproducible"
186 * warning. That's exactly what was intended by using this macro.
187 * Just disable this nonsense warning. */
188
189/* And disabling them does not work either:
190 * #pragma clang diagnostic ignored "-Wno-error=date-time"
191 * #pragma clang diagnostic ignored "-Wdate-time"
192 * So we just have to disable ALL warnings for some lines
193 * of code.
194 */
195#endif
196
197
198#ifdef __MACH__ /* Apple OSX section */
199
200#ifdef __clang__
201#if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
202/* Avoid warnings for Xcode 7. It seems it does no longer exist in Xcode 8 */
203#pragma clang diagnostic ignored "-Wno-reserved-id-macro"
204#pragma clang diagnostic ignored "-Wno-keyword-macro"
205#endif
206#endif
7c673cae
FG
207
208#define CLOCK_MONOTONIC (1)
209#define CLOCK_REALTIME (2)
210
11fdf7f2 211#include <sys/errno.h>
7c673cae
FG
212#include <sys/time.h>
213#include <mach/clock.h>
214#include <mach/mach.h>
215#include <mach/mach_time.h>
216#include <assert.h>
217
11fdf7f2
TL
218/* clock_gettime is not implemented on OSX prior to 10.12 */
219static int
220_civet_clock_gettime(int clk_id, struct timespec *t)
7c673cae
FG
221{
222 memset(t, 0, sizeof(*t));
223 if (clk_id == CLOCK_REALTIME) {
224 struct timeval now;
225 int rv = gettimeofday(&now, NULL);
226 if (rv) {
227 return rv;
228 }
229 t->tv_sec = now.tv_sec;
230 t->tv_nsec = now.tv_usec * 1000;
231 return 0;
232
233 } else if (clk_id == CLOCK_MONOTONIC) {
234 static uint64_t clock_start_time = 0;
235 static mach_timebase_info_data_t timebase_ifo = {0, 0};
236
237 uint64_t now = mach_absolute_time();
238
239 if (clock_start_time == 0) {
240 kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
241#if defined(DEBUG)
242 assert(mach_status == KERN_SUCCESS);
243#else
244 /* appease "unused variable" warning for release builds */
245 (void)mach_status;
246#endif
247 clock_start_time = now;
248 }
249
250 now = (uint64_t)((double)(now - clock_start_time)
251 * (double)timebase_ifo.numer
252 / (double)timebase_ifo.denom);
253
254 t->tv_sec = now / 1000000000;
255 t->tv_nsec = now % 1000000000;
256 return 0;
257 }
258 return -1; /* EINVAL - Clock ID is unknown */
259}
11fdf7f2
TL
260
261/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
262#ifdef __CLOCK_AVAILABILITY
263/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be
264 * declared but it may be NULL at runtime. So we need to check before using
265 * it. */
266static int
267_civet_safe_clock_gettime(int clk_id, struct timespec *t)
268{
269 if (clock_gettime) {
270 return clock_gettime(clk_id, t);
271 }
272 return _civet_clock_gettime(clk_id, t);
273}
274#define clock_gettime _civet_safe_clock_gettime
275#else
276#define clock_gettime _civet_clock_gettime
277#endif
278
7c673cae
FG
279#endif
280
281
282#include <time.h>
283#include <stdlib.h>
284#include <stdarg.h>
285#include <assert.h>
286#include <string.h>
287#include <ctype.h>
288#include <limits.h>
289#include <stddef.h>
290#include <stdio.h>
11fdf7f2
TL
291#include <stdint.h>
292
293#ifndef INT64_MAX
294#define INT64_MAX (9223372036854775807)
295#endif
7c673cae
FG
296
297
298#ifndef MAX_WORKER_THREADS
299#define MAX_WORKER_THREADS (1024 * 64)
300#endif
11fdf7f2
TL
301
302#ifndef SOCKET_TIMEOUT_QUANTUM /* in ms */
303#define SOCKET_TIMEOUT_QUANTUM (2000)
7c673cae
FG
304#endif
305
11fdf7f2
TL
306#define SHUTDOWN_RD (0)
307#define SHUTDOWN_WR (1)
308#define SHUTDOWN_BOTH (2)
309
7c673cae
FG
310mg_static_assert(MAX_WORKER_THREADS >= 1,
311 "worker threads must be a positive number");
312
11fdf7f2
TL
313mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8,
314 "size_t data type size check");
315
7c673cae
FG
316#if defined(_WIN32) \
317 && !defined(__SYMBIAN32__) /* WINDOWS / UNIX include block */
318#include <windows.h>
319#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
320#include <ws2tcpip.h>
321
322typedef const char *SOCK_OPT_TYPE;
323
324#if !defined(PATH_MAX)
325#define PATH_MAX (MAX_PATH)
326#endif
327
328#if !defined(PATH_MAX)
329#define PATH_MAX (4096)
330#endif
331
332mg_static_assert(PATH_MAX >= 1, "path length must be a positive number");
333
334#ifndef _IN_PORT_T
335#ifndef in_port_t
336#define in_port_t u_short
337#endif
338#endif
339
340#ifndef _WIN32_WCE
341#include <process.h>
342#include <direct.h>
343#include <io.h>
11fdf7f2
TL
344#else /* _WIN32_WCE */
345#define NO_CGI /* WinCE has no pipes */
346#define NO_POPEN /* WinCE has no popen */
7c673cae
FG
347
348typedef long off_t;
349
350#define errno ((int)(GetLastError()))
351#define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
352#endif /* _WIN32_WCE */
353
354#define MAKEUQUAD(lo, hi) \
355 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
356#define RATE_DIFF (10000000) /* 100 nsecs */
357#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
358#define SYS2UNIX_TIME(lo, hi) \
359 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
360
361/* Visual Studio 6 does not know __func__ or __FUNCTION__
362 * The rest of MS compilers use __FUNCTION__, not C99 __func__
363 * Also use _strtoui64 on modern M$ compilers */
364#if defined(_MSC_VER)
365#if (_MSC_VER < 1300)
366#define STRX(x) #x
367#define STR(x) STRX(x)
368#define __func__ __FILE__ ":" STR(__LINE__)
369#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
370#define strtoll(x, y, z) (_atoi64(x))
371#else
372#define __func__ __FUNCTION__
373#define strtoull(x, y, z) (_strtoui64(x, y, z))
374#define strtoll(x, y, z) (_strtoi64(x, y, z))
375#endif
376#endif /* _MSC_VER */
377
378#define ERRNO ((int)(GetLastError()))
379#define NO_SOCKLEN_T
380
381#if defined(_WIN64) || defined(__MINGW64__)
382#define SSL_LIB "ssleay64.dll"
383#define CRYPTO_LIB "libeay64.dll"
384#else
385#define SSL_LIB "ssleay32.dll"
386#define CRYPTO_LIB "libeay32.dll"
387#endif
388
389#define O_NONBLOCK (0)
390#ifndef W_OK
391#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
392#endif
393#if !defined(EWOULDBLOCK)
394#define EWOULDBLOCK WSAEWOULDBLOCK
395#endif /* !EWOULDBLOCK */
396#define _POSIX_
397#define INT64_FMT "I64d"
398#define UINT64_FMT "I64u"
399
400#define WINCDECL __cdecl
7c673cae
FG
401#define vsnprintf_impl _vsnprintf
402#define access _access
403#define mg_sleep(x) (Sleep(x))
404
405#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
406#ifndef popen
407#define popen(x, y) (_popen(x, y))
408#endif
409#ifndef pclose
410#define pclose(x) (_pclose(x))
411#endif
412#define close(x) (_close(x))
413#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
414#define RTLD_LAZY (0)
11fdf7f2 415#define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
7c673cae
FG
416#define fdopen(x, y) (_fdopen((x), (y)))
417#define write(x, y, z) (_write((x), (y), (unsigned)z))
418#define read(x, y, z) (_read((x), (y), (unsigned)z))
419#define flockfile(x) (EnterCriticalSection(&global_log_file_lock))
420#define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock))
421#define sleep(x) (Sleep((x)*1000))
422#define rmdir(x) (_rmdir(x))
423#define timegm(x) (_mkgmtime(x))
424
425#if !defined(fileno)
426#define fileno(x) (_fileno(x))
427#endif /* !fileno MINGW #defines fileno */
428
429typedef HANDLE pthread_mutex_t;
430typedef DWORD pthread_key_t;
431typedef HANDLE pthread_t;
432typedef struct {
433 CRITICAL_SECTION threadIdSec;
11fdf7f2 434 struct mg_workerTLS *waiting_thread; /* The chain of threads */
7c673cae
FG
435} pthread_cond_t;
436
437#ifndef __clockid_t_defined
438typedef DWORD clockid_t;
439#endif
440#ifndef CLOCK_MONOTONIC
441#define CLOCK_MONOTONIC (1)
442#endif
443#ifndef CLOCK_REALTIME
444#define CLOCK_REALTIME (2)
445#endif
11fdf7f2
TL
446#ifndef CLOCK_THREAD
447#define CLOCK_THREAD (3)
448#endif
449#ifndef CLOCK_PROCESS
450#define CLOCK_PROCESS (4)
451#endif
452
7c673cae
FG
453
454#if defined(_MSC_VER) && (_MSC_VER >= 1900)
455#define _TIMESPEC_DEFINED
456#endif
457#ifndef _TIMESPEC_DEFINED
458struct timespec {
459 time_t tv_sec; /* seconds */
460 long tv_nsec; /* nanoseconds */
461};
462#endif
463
11fdf7f2
TL
464#if !defined(WIN_PTHREADS_TIME_H)
465#define MUST_IMPLEMENT_CLOCK_GETTIME
466#endif
467
468#ifdef MUST_IMPLEMENT_CLOCK_GETTIME
469#define clock_gettime mg_clock_gettime
470static int
471clock_gettime(clockid_t clk_id, struct timespec *tp)
472{
473 FILETIME ft;
474 ULARGE_INTEGER li, li2;
475 BOOL ok = FALSE;
476 double d;
477 static double perfcnt_per_sec = 0.0;
478
479 if (tp) {
480 memset(tp, 0, sizeof(*tp));
481
482 if (clk_id == CLOCK_REALTIME) {
483
484 /* BEGIN: CLOCK_REALTIME = wall clock (date and time) */
485 GetSystemTimeAsFileTime(&ft);
486 li.LowPart = ft.dwLowDateTime;
487 li.HighPart = ft.dwHighDateTime;
488 li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
489 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
490 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
491 ok = TRUE;
492 /* END: CLOCK_REALTIME */
493
494 } else if (clk_id == CLOCK_MONOTONIC) {
495
496 /* BEGIN: CLOCK_MONOTONIC = stopwatch (time differences) */
497 if (perfcnt_per_sec == 0.0) {
498 QueryPerformanceFrequency((LARGE_INTEGER *)&li);
499 perfcnt_per_sec = 1.0 / li.QuadPart;
500 }
501 if (perfcnt_per_sec != 0.0) {
502 QueryPerformanceCounter((LARGE_INTEGER *)&li);
503 d = li.QuadPart * perfcnt_per_sec;
504 tp->tv_sec = (time_t)d;
505 d -= tp->tv_sec;
506 tp->tv_nsec = (long)(d * 1.0E9);
507 ok = TRUE;
508 }
509 /* END: CLOCK_MONOTONIC */
510
511 } else if (clk_id == CLOCK_THREAD) {
512
513 /* BEGIN: CLOCK_THREAD = CPU usage of thread */
514 FILETIME t_create, t_exit, t_kernel, t_user;
515 if (GetThreadTimes(GetCurrentThread(),
516 &t_create,
517 &t_exit,
518 &t_kernel,
519 &t_user)) {
520 li.LowPart = t_user.dwLowDateTime;
521 li.HighPart = t_user.dwHighDateTime;
522 li2.LowPart = t_kernel.dwLowDateTime;
523 li2.HighPart = t_kernel.dwHighDateTime;
524 li.QuadPart += li2.QuadPart;
525 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
526 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
527 ok = TRUE;
528 }
529 /* END: CLOCK_THREAD */
530
531 } else if (clk_id == CLOCK_PROCESS) {
532
533 /* BEGIN: CLOCK_PROCESS = CPU usage of process */
534 FILETIME t_create, t_exit, t_kernel, t_user;
535 if (GetProcessTimes(GetCurrentProcess(),
536 &t_create,
537 &t_exit,
538 &t_kernel,
539 &t_user)) {
540 li.LowPart = t_user.dwLowDateTime;
541 li.HighPart = t_user.dwHighDateTime;
542 li2.LowPart = t_kernel.dwLowDateTime;
543 li2.HighPart = t_kernel.dwHighDateTime;
544 li.QuadPart += li2.QuadPart;
545 tp->tv_sec = (time_t)(li.QuadPart / 10000000);
546 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
547 ok = TRUE;
548 }
549 /* END: CLOCK_PROCESS */
550
551 } else {
552
553 /* BEGIN: unknown clock */
554 /* ok = FALSE; already set by init */
555 /* END: unknown clock */
556 }
557 }
558
559 return ok ? 0 : -1;
560}
561#endif
562
563
7c673cae
FG
564#define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
565
566static int pthread_mutex_lock(pthread_mutex_t *);
567static int pthread_mutex_unlock(pthread_mutex_t *);
568static void path_to_unicode(const struct mg_connection *conn,
569 const char *path,
570 wchar_t *wbuf,
571 size_t wbuf_len);
7c673cae 572
11fdf7f2
TL
573/* All file operations need to be rewritten to solve #246. */
574
575#include "file_ops.inl"
576
577struct mg_file;
578
579static const char *
580mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p);
7c673cae 581
7c673cae
FG
582
583/* POSIX dirent interface */
584struct dirent {
585 char d_name[PATH_MAX];
586};
587
588typedef struct DIR {
589 HANDLE handle;
590 WIN32_FIND_DATAW info;
591 struct dirent result;
592} DIR;
593
594#if defined(_WIN32) && !defined(POLLIN)
595#ifndef HAVE_POLL
596struct pollfd {
597 SOCKET fd;
598 short events;
599 short revents;
600};
601#define POLLIN (0x0300)
602#endif
603#endif
604
605/* Mark required libraries */
606#if defined(_MSC_VER)
607#pragma comment(lib, "Ws2_32.lib")
608#endif
609
11fdf7f2
TL
610#else /* defined(_WIN32) && !defined(__SYMBIAN32__) - \
611 WINDOWS / UNIX include block */
7c673cae
FG
612
613#include <sys/wait.h>
614#include <sys/socket.h>
615#include <sys/poll.h>
616#include <netinet/in.h>
617#include <arpa/inet.h>
618#include <sys/time.h>
619#include <sys/utsname.h>
620#include <stdint.h>
621#include <inttypes.h>
622#include <netdb.h>
623#include <netinet/tcp.h>
624typedef const void *SOCK_OPT_TYPE;
625
626#if defined(ANDROID)
627typedef unsigned short int in_port_t;
628#endif
629
630#include <pwd.h>
631#include <unistd.h>
632#include <grp.h>
633#include <dirent.h>
634#define vsnprintf_impl vsnprintf
635
636#if !defined(NO_SSL_DL) && !defined(NO_SSL)
637#include <dlfcn.h>
638#endif
639#include <pthread.h>
640#if defined(__MACH__)
641#define SSL_LIB "libssl.dylib"
642#define CRYPTO_LIB "libcrypto.dylib"
643#else
644#if !defined(SSL_LIB)
645#define SSL_LIB "libssl.so"
646#endif
647#if !defined(CRYPTO_LIB)
648#define CRYPTO_LIB "libcrypto.so"
649#endif
650#endif
651#ifndef O_BINARY
652#define O_BINARY (0)
653#endif /* O_BINARY */
654#define closesocket(a) (close(a))
655#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
656#define mg_remove(conn, x) (remove(x))
657#define mg_sleep(x) (usleep((x)*1000))
658#define mg_opendir(conn, x) (opendir(x))
659#define mg_closedir(x) (closedir(x))
660#define mg_readdir(x) (readdir(x))
661#define ERRNO (errno)
662#define INVALID_SOCKET (-1)
663#define INT64_FMT PRId64
664#define UINT64_FMT PRIu64
665typedef int SOCKET;
666#define WINCDECL
667
668#if defined(__hpux)
669/* HPUX 11 does not have monotonic, fall back to realtime */
670#ifndef CLOCK_MONOTONIC
671#define CLOCK_MONOTONIC CLOCK_REALTIME
672#endif
673
674/* HPUX defines socklen_t incorrectly as size_t which is 64bit on
675 * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
676 * the prototypes use int* rather than socklen_t* which matches the
677 * actual library expectation. When called with the wrong size arg
678 * accept() returns a zero client inet addr and check_acl() always
679 * fails. Since socklen_t is widely used below, just force replace
680 * their typedef with int. - DTL
681 */
682#define socklen_t int
683#endif /* hpux */
684
11fdf7f2
TL
685#endif /* defined(_WIN32) && !defined(__SYMBIAN32__) - \
686 WINDOWS / UNIX include block */
7c673cae
FG
687
688/* va_copy should always be a macro, C99 and C++11 - DTL */
689#ifndef va_copy
690#define va_copy(x, y) ((x) = (y))
691#endif
692
693#ifdef _WIN32
694/* Create substitutes for POSIX functions in Win32. */
695
696#if defined(__MINGW32__)
697/* Show no warning in case system functions are not used. */
698#pragma GCC diagnostic push
699#pragma GCC diagnostic ignored "-Wunused-function"
700#endif
701
702
703static CRITICAL_SECTION global_log_file_lock;
11fdf7f2
TL
704
705FUNCTION_MAY_BE_UNUSED
7c673cae
FG
706static DWORD
707pthread_self(void)
708{
709 return GetCurrentThreadId();
710}
711
712
11fdf7f2 713FUNCTION_MAY_BE_UNUSED
7c673cae
FG
714static int
715pthread_key_create(
716 pthread_key_t *key,
717 void (*_ignored)(void *) /* destructor not supported for Windows */
718 )
719{
720 (void)_ignored;
721
722 if ((key != 0)) {
723 *key = TlsAlloc();
724 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
725 }
726 return -2;
727}
728
729
11fdf7f2 730FUNCTION_MAY_BE_UNUSED
7c673cae
FG
731static int
732pthread_key_delete(pthread_key_t key)
733{
734 return TlsFree(key) ? 0 : 1;
735}
736
737
11fdf7f2 738FUNCTION_MAY_BE_UNUSED
7c673cae
FG
739static int
740pthread_setspecific(pthread_key_t key, void *value)
741{
742 return TlsSetValue(key, value) ? 0 : 1;
743}
744
745
11fdf7f2 746FUNCTION_MAY_BE_UNUSED
7c673cae
FG
747static void *
748pthread_getspecific(pthread_key_t key)
749{
750 return TlsGetValue(key);
751}
752
753#if defined(__MINGW32__)
754/* Enable unused function warning again */
755#pragma GCC diagnostic pop
756#endif
757
758static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL;
759#else
760static pthread_mutexattr_t pthread_mutex_attr;
761#endif /* _WIN32 */
762
763
764#define PASSWORDS_FILE_NAME ".htpasswd"
765#define CGI_ENVIRONMENT_SIZE (4096)
766#define MAX_CGI_ENVIR_VARS (256)
767#define MG_BUF_LEN (8192)
768
11fdf7f2
TL
769#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
770
771
772#if defined(_WIN32_WCE)
773/* Create substitutes for POSIX functions in Win32. */
774
775#if defined(__MINGW32__)
776/* Show no warning in case system functions are not used. */
777#pragma GCC diagnostic push
778#pragma GCC diagnostic ignored "-Wunused-function"
7c673cae
FG
779#endif
780
7c673cae 781
11fdf7f2
TL
782FUNCTION_MAY_BE_UNUSED
783static time_t
784time(time_t *ptime)
785{
786 time_t t;
787 SYSTEMTIME st;
788 FILETIME ft;
7c673cae 789
11fdf7f2
TL
790 GetSystemTime(&st);
791 SystemTimeToFileTime(&st, &ft);
792 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
7c673cae 793
11fdf7f2
TL
794 if (ptime != NULL) {
795 *ptime = t;
796 }
7c673cae 797
11fdf7f2
TL
798 return t;
799}
7c673cae 800
11fdf7f2
TL
801
802FUNCTION_MAY_BE_UNUSED
803static struct tm *
804localtime_s(const time_t *ptime, struct tm *ptm)
7c673cae 805{
11fdf7f2
TL
806 int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
807 FILETIME ft, lft;
808 SYSTEMTIME st;
809 TIME_ZONE_INFORMATION tzinfo;
7c673cae 810
11fdf7f2
TL
811 if (ptm == NULL) {
812 return NULL;
813 }
7c673cae 814
11fdf7f2
TL
815 *(int64_t *)&ft = t;
816 FileTimeToLocalFileTime(&ft, &lft);
817 FileTimeToSystemTime(&lft, &st);
818 ptm->tm_year = st.wYear - 1900;
819 ptm->tm_mon = st.wMonth - 1;
820 ptm->tm_wday = st.wDayOfWeek;
821 ptm->tm_mday = st.wDay;
822 ptm->tm_hour = st.wHour;
823 ptm->tm_min = st.wMinute;
824 ptm->tm_sec = st.wSecond;
825 ptm->tm_yday = 0; /* hope nobody uses this */
826 ptm->tm_isdst =
827 (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT) ? 1 : 0;
7c673cae 828
11fdf7f2
TL
829 return ptm;
830}
7c673cae
FG
831
832
11fdf7f2
TL
833FUNCTION_MAY_BE_UNUSED
834static struct tm *
835gmtime_s(const time_t *ptime, struct tm *ptm)
7c673cae 836{
11fdf7f2
TL
837 /* FIXME(lsm): fix this. */
838 return localtime_s(ptime, ptm);
839}
7c673cae 840
7c673cae 841
11fdf7f2
TL
842static int mg_atomic_inc(volatile int *addr);
843static struct tm tm_array[MAX_WORKER_THREADS];
844static int tm_index = 0;
7c673cae 845
11fdf7f2
TL
846
847FUNCTION_MAY_BE_UNUSED
848static struct tm *
849localtime(const time_t *ptime)
850{
851 int i = mg_atomic_inc(&tm_index) % (sizeof(tm_array) / sizeof(tm_array[0]));
852 return localtime_s(ptime, tm_array + i);
7c673cae
FG
853}
854
855
11fdf7f2
TL
856FUNCTION_MAY_BE_UNUSED
857static struct tm *
858gmtime(const time_t *ptime)
7c673cae 859{
11fdf7f2
TL
860 int i = mg_atomic_inc(&tm_index) % ARRAY_SIZE(tm_array);
861 return gmtime_s(ptime, tm_array + i);
7c673cae
FG
862}
863
864
11fdf7f2
TL
865FUNCTION_MAY_BE_UNUSED
866static size_t
867strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm)
7c673cae 868{
11fdf7f2
TL
869 /* TODO: (void)mg_snprintf(NULL, dst, dst_size, "implement strftime()
870 * for WinCE"); */
871 return 0;
872}
7c673cae 873
11fdf7f2
TL
874#define _beginthreadex(psec, stack, func, prm, flags, ptid) \
875 (uintptr_t) CreateThread(psec, stack, func, prm, flags, ptid)
7c673cae 876
11fdf7f2
TL
877#define remove(f) mg_remove(NULL, f)
878
879
880FUNCTION_MAY_BE_UNUSED
881static int
882rename(const char *a, const char *b)
883{
884 wchar_t wa[PATH_MAX];
885 wchar_t wb[PATH_MAX];
886 path_to_unicode(NULL, a, wa, ARRAY_SIZE(wa));
887 path_to_unicode(NULL, b, wb, ARRAY_SIZE(wb));
888
889 return MoveFileW(wa, wb) ? 0 : -1;
7c673cae
FG
890}
891
892
11fdf7f2
TL
893struct stat {
894 int64_t st_size;
895 time_t st_mtime;
896};
897
898
899FUNCTION_MAY_BE_UNUSED
900static int
901stat(const char *name, struct stat *st)
7c673cae 902{
11fdf7f2
TL
903 wchar_t wbuf[PATH_MAX];
904 WIN32_FILE_ATTRIBUTE_DATA attr;
905 time_t creation_time, write_time;
906
907 path_to_unicode(NULL, name, wbuf, ARRAY_SIZE(wbuf));
908 memset(&attr, 0, sizeof(attr));
909
910 GetFileAttributesExW(wbuf, GetFileExInfoStandard, &attr);
911 st->st_size =
912 (((int64_t)attr.nFileSizeHigh) << 32) + (int64_t)attr.nFileSizeLow;
913
914 write_time = SYS2UNIX_TIME(attr.ftLastWriteTime.dwLowDateTime,
915 attr.ftLastWriteTime.dwHighDateTime);
916 creation_time = SYS2UNIX_TIME(attr.ftCreationTime.dwLowDateTime,
917 attr.ftCreationTime.dwHighDateTime);
918
919 if (creation_time > write_time) {
920 st->st_mtime = creation_time;
921 } else {
922 st->st_mtime = write_time;
923 }
924 return 0;
925}
926
927#define access(x, a) 1 /* not required anyway */
928
929/* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */
930/* Values from errno.h in Windows SDK (Visual Studio). */
931#define EEXIST 17
932#define EACCES 13
933#define ENOENT 2
934
935#if defined(__MINGW32__)
936/* Enable unused function warning again */
937#pragma GCC diagnostic pop
938#endif
939
940#endif /* defined(_WIN32_WCE) */
941
942
943#if defined(__GNUC__) || defined(__MINGW32__)
944/* Show no warning in case system functions are not used. */
945#define GCC_VERSION \
946 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
947#if GCC_VERSION >= 40500
948#pragma GCC diagnostic push
949#pragma GCC diagnostic ignored "-Wunused-function"
950#endif /* GCC_VERSION >= 40500 */
951#endif /* defined(__GNUC__) || defined(__MINGW32__) */
952#if defined(__clang__)
953/* Show no warning in case system functions are not used. */
954#pragma clang diagnostic push
955#pragma clang diagnostic ignored "-Wunused-function"
956#endif
957
958static pthread_mutex_t global_lock_mutex;
959
960
961#if defined(_WIN32) && !defined(__SYMBIAN32__)
962/* Forward declaration for Windows */
963FUNCTION_MAY_BE_UNUSED
964static int pthread_mutex_lock(pthread_mutex_t *mutex);
965
966FUNCTION_MAY_BE_UNUSED
967static int pthread_mutex_unlock(pthread_mutex_t *mutex);
968#endif
969
970
971FUNCTION_MAY_BE_UNUSED
972static void
973mg_global_lock(void)
974{
975 (void)pthread_mutex_lock(&global_lock_mutex);
976}
977
978
979FUNCTION_MAY_BE_UNUSED
980static void
981mg_global_unlock(void)
982{
983 (void)pthread_mutex_unlock(&global_lock_mutex);
984}
985
986
987FUNCTION_MAY_BE_UNUSED
988static int
989mg_atomic_inc(volatile int *addr)
990{
991 int ret;
992#if defined(_WIN32) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS)
993 /* Depending on the SDK, this function uses either
994 * (volatile unsigned int *) or (volatile LONG *),
995 * so whatever you use, the other SDK is likely to raise a warning. */
996 ret = InterlockedIncrement((volatile long *)addr);
997#elif defined(__GNUC__) \
998 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
999 && !defined(NO_ATOMICS)
1000 ret = __sync_add_and_fetch(addr, 1);
1001#else
1002 mg_global_lock();
1003 ret = (++(*addr));
1004 mg_global_unlock();
1005#endif
1006 return ret;
1007}
1008
1009
1010FUNCTION_MAY_BE_UNUSED
1011static int
1012mg_atomic_dec(volatile int *addr)
1013{
1014 int ret;
1015#if defined(_WIN32) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS)
1016 /* Depending on the SDK, this function uses either
1017 * (volatile unsigned int *) or (volatile LONG *),
1018 * so whatever you use, the other SDK is likely to raise a warning. */
1019 ret = InterlockedDecrement((volatile long *)addr);
1020#elif defined(__GNUC__) \
1021 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1022 && !defined(NO_ATOMICS)
1023 ret = __sync_sub_and_fetch(addr, 1);
1024#else
1025 mg_global_lock();
1026 ret = (--(*addr));
1027 mg_global_unlock();
1028#endif
1029 return ret;
1030}
1031
1032
1033#if defined(USE_SERVER_STATS)
1034static int64_t
1035mg_atomic_add(volatile int64_t *addr, int64_t value)
1036{
1037 int64_t ret;
1038#if defined(_WIN64) && !defined(__SYMBIAN32__) && !defined(NO_ATOMICS)
1039 ret = InterlockedAdd64(addr, value);
1040#elif defined(__GNUC__) \
1041 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0))) \
1042 && !defined(NO_ATOMICS)
1043 ret = __sync_add_and_fetch(addr, value);
1044#else
1045 mg_global_lock();
1046 *addr += value;
1047 ret = (*addr);
1048 mg_global_unlock();
1049#endif
1050 return ret;
1051}
1052#endif
1053
1054
1055#if defined(__GNUC__)
1056/* Show no warning in case system functions are not used. */
1057#if GCC_VERSION >= 40500
1058#pragma GCC diagnostic pop
1059#endif /* GCC_VERSION >= 40500 */
1060#endif /* defined(__GNUC__) */
1061#if defined(__clang__)
1062/* Show no warning in case system functions are not used. */
1063#pragma clang diagnostic pop
1064#endif
1065
1066
1067#if defined(USE_SERVER_STATS)
1068
1069struct mg_memory_stat {
1070 volatile int64_t totalMemUsed;
1071 volatile int64_t maxMemUsed;
1072 volatile int blockCount;
1073};
1074
1075
1076static struct mg_memory_stat *get_memory_stat(struct mg_context *ctx);
1077
1078
1079static void *
1080mg_malloc_ex(size_t size,
1081 struct mg_context *ctx,
1082 const char *file,
1083 unsigned line)
1084{
1085 void *data = malloc(size + 2 * sizeof(uintptr_t));
1086 void *memory = 0;
1087 struct mg_memory_stat *mstat = get_memory_stat(ctx);
1088
1089#if defined(MEMORY_DEBUGGING)
1090 char mallocStr[256];
1091#else
1092 (void)file;
1093 (void)line;
1094#endif
1095
1096 if (data) {
1097 int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size);
1098 if (mmem > mstat->maxMemUsed) {
1099 /* could use atomic compare exchange, but this
1100 * seems overkill for statistics data */
1101 mstat->maxMemUsed = mmem;
1102 }
1103
1104 mg_atomic_inc(&mstat->blockCount);
1105 ((uintptr_t *)data)[0] = size;
1106 ((uintptr_t *)data)[1] = (uintptr_t)mstat;
1107 memory = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
1108 }
1109
1110#if defined(MEMORY_DEBUGGING)
1111 sprintf(mallocStr,
1112 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
1113 memory,
1114 (unsigned long)size,
1115 (unsigned long)mstat->totalMemUsed,
1116 (unsigned long)mstat->blockCount,
1117 file,
1118 line);
1119#if defined(_WIN32)
1120 OutputDebugStringA(mallocStr);
1121#else
1122 DEBUG_TRACE("%s", mallocStr);
1123#endif
1124#endif
1125
1126 return memory;
1127}
1128
1129
1130static void *
1131mg_calloc_ex(size_t count,
1132 size_t size,
1133 struct mg_context *ctx,
1134 const char *file,
1135 unsigned line)
1136{
1137 void *data = mg_malloc_ex(size * count, ctx, file, line);
1138
1139 if (data) {
1140 memset(data, 0, size * count);
1141 }
1142 return data;
1143}
1144
1145
1146static void
1147mg_free_ex(void *memory, const char *file, unsigned line)
1148{
1149 void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
1150
1151
1152#if defined(MEMORY_DEBUGGING)
1153 char mallocStr[256];
1154#else
1155 (void)file;
1156 (void)line;
1157#endif
1158
1159 if (memory) {
1160 uintptr_t size = ((uintptr_t *)data)[0];
1161 struct mg_memory_stat *mstat =
1162 (struct mg_memory_stat *)(((uintptr_t *)data)[1]);
1163 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size);
1164 mg_atomic_dec(&mstat->blockCount);
1165#if defined(MEMORY_DEBUGGING)
1166 sprintf(mallocStr,
1167 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
1168 memory,
1169 (unsigned long)size,
1170 (unsigned long)mstat->totalMemUsed,
1171 (unsigned long)mstat->blockCount,
1172 file,
1173 line);
1174#if defined(_WIN32)
1175 OutputDebugStringA(mallocStr);
1176#else
1177 DEBUG_TRACE("%s", mallocStr);
1178#endif
1179#endif
1180 free(data);
1181 }
1182}
1183
1184
1185static void *
1186mg_realloc_ex(void *memory,
1187 size_t newsize,
1188 struct mg_context *ctx,
1189 const char *file,
1190 unsigned line)
1191{
1192 void *data;
1193 void *_realloc;
1194 uintptr_t oldsize;
1195
1196#if defined(MEMORY_DEBUGGING)
1197 char mallocStr[256];
1198#else
1199 (void)file;
1200 (void)line;
1201#endif
7c673cae
FG
1202
1203 if (newsize) {
1204 if (memory) {
11fdf7f2
TL
1205 /* Reallocate existing block */
1206 struct mg_memory_stat *mstat;
1207 data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t));
1208 oldsize = ((uintptr_t *)data)[0];
1209 mstat = (struct mg_memory_stat *)((uintptr_t *)data)[1];
1210 _realloc = realloc(data, newsize + 2 * sizeof(uintptr_t));
7c673cae
FG
1211 if (_realloc) {
1212 data = _realloc;
11fdf7f2
TL
1213 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize);
1214#if defined(MEMORY_DEBUGGING)
7c673cae
FG
1215 sprintf(mallocStr,
1216 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
1217 memory,
1218 (unsigned long)oldsize,
11fdf7f2
TL
1219 (unsigned long)mstat->totalMemUsed,
1220 (unsigned long)mstat->blockCount,
7c673cae
FG
1221 file,
1222 line);
1223#if defined(_WIN32)
1224 OutputDebugStringA(mallocStr);
1225#else
1226 DEBUG_TRACE("%s", mallocStr);
1227#endif
11fdf7f2
TL
1228#endif
1229 mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize);
1230#if defined(MEMORY_DEBUGGING)
7c673cae
FG
1231 sprintf(mallocStr,
1232 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
1233 memory,
1234 (unsigned long)newsize,
11fdf7f2
TL
1235 (unsigned long)mstat->totalMemUsed,
1236 (unsigned long)mstat->blockCount,
7c673cae
FG
1237 file,
1238 line);
1239#if defined(_WIN32)
1240 OutputDebugStringA(mallocStr);
1241#else
1242 DEBUG_TRACE("%s", mallocStr);
1243#endif
11fdf7f2
TL
1244#endif
1245 *(uintptr_t *)data = newsize;
1246 data = (void *)(((char *)data) + 2 * sizeof(uintptr_t));
7c673cae 1247 } else {
11fdf7f2 1248#if defined(MEMORY_DEBUGGING)
7c673cae
FG
1249#if defined(_WIN32)
1250 OutputDebugStringA("MEM: realloc failed\n");
1251#else
1252 DEBUG_TRACE("%s", "MEM: realloc failed\n");
11fdf7f2 1253#endif
7c673cae
FG
1254#endif
1255 return _realloc;
1256 }
1257 } else {
11fdf7f2
TL
1258 /* Allocate new block */
1259 data = mg_malloc_ex(newsize, ctx, file, line);
7c673cae
FG
1260 }
1261 } else {
11fdf7f2 1262 /* Free existing block */
7c673cae
FG
1263 data = 0;
1264 mg_free_ex(memory, file, line);
1265 }
1266
1267 return data;
1268}
1269
11fdf7f2
TL
1270#define mg_malloc(a) mg_malloc_ex(a, NULL, __FILE__, __LINE__)
1271#define mg_calloc(a, b) mg_calloc_ex(a, b, NULL, __FILE__, __LINE__)
1272#define mg_realloc(a, b) mg_realloc_ex(a, b, NULL, __FILE__, __LINE__)
7c673cae
FG
1273#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
1274
11fdf7f2
TL
1275#define mg_malloc_ctx(a, c) mg_malloc_ex(a, c, __FILE__, __LINE__)
1276#define mg_calloc_ctx(a, b, c) mg_calloc_ex(a, b, c, __FILE__, __LINE__)
1277#define mg_realloc_ctx(a, b, c) mg_realloc_ex(a, b, c, __FILE__, __LINE__)
1278
1279#else /* USE_SERVER_STATS */
7c673cae
FG
1280
1281static __inline void *
1282mg_malloc(size_t a)
1283{
1284 return malloc(a);
1285}
1286
1287static __inline void *
1288mg_calloc(size_t a, size_t b)
1289{
1290 return calloc(a, b);
1291}
1292
1293static __inline void *
1294mg_realloc(void *a, size_t b)
1295{
1296 return realloc(a, b);
1297}
1298
1299static __inline void
1300mg_free(void *a)
1301{
1302 free(a);
1303}
1304
11fdf7f2
TL
1305#define mg_malloc_ctx(a, c) mg_malloc(a)
1306#define mg_calloc_ctx(a, b, c) mg_calloc(a, b)
1307#define mg_realloc_ctx(a, b, c) mg_realloc(a, b)
1308#define mg_free_ctx(a, c) mg_free(a)
1309
1310#endif /* USE_SERVER_STATS */
7c673cae
FG
1311
1312
1313static void mg_vsnprintf(const struct mg_connection *conn,
1314 int *truncated,
1315 char *buf,
1316 size_t buflen,
1317 const char *fmt,
1318 va_list ap);
1319
1320static void mg_snprintf(const struct mg_connection *conn,
1321 int *truncated,
1322 char *buf,
1323 size_t buflen,
1324 PRINTF_FORMAT_STRING(const char *fmt),
1325 ...) PRINTF_ARGS(5, 6);
1326
1327/* This following lines are just meant as a reminder to use the mg-functions
1328 * for memory management */
1329#ifdef malloc
1330#undef malloc
1331#endif
1332#ifdef calloc
1333#undef calloc
1334#endif
1335#ifdef realloc
1336#undef realloc
1337#endif
1338#ifdef free
1339#undef free
1340#endif
1341#ifdef snprintf
1342#undef snprintf
1343#endif
1344#ifdef vsnprintf
1345#undef vsnprintf
1346#endif
1347#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
1348#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
1349#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
1350#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
1351#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
11fdf7f2 1352#ifdef _WIN32 /* vsnprintf must not be used in any system, * \ \ \ \
7c673cae
FG
1353 * but this define only works well for Windows. */
1354#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
1355#endif
1356
7c673cae 1357
11fdf7f2
TL
1358/* mg_init_library counter */
1359static int mg_init_library_called = 0;
7c673cae 1360
11fdf7f2
TL
1361#if !defined(NO_SSL)
1362static int mg_ssl_initialized = 0;
7c673cae
FG
1363#endif
1364
11fdf7f2
TL
1365static pthread_key_t sTlsKey; /* Thread local storage index */
1366static int thread_idx_max = 0;
1367
1368
1369struct mg_workerTLS {
1370 int is_master;
1371 unsigned long thread_idx;
1372#if defined(_WIN32) && !defined(__SYMBIAN32__)
1373 HANDLE pthread_cond_helper_mutex;
1374 struct mg_workerTLS *next_waiting_thread;
7c673cae 1375#endif
11fdf7f2 1376};
7c673cae 1377
11fdf7f2
TL
1378
1379#if defined(__GNUC__) || defined(__MINGW32__)
1380/* Show no warning in case system functions are not used. */
1381#if GCC_VERSION >= 40500
1382#pragma GCC diagnostic push
1383#pragma GCC diagnostic ignored "-Wunused-function"
1384#endif /* GCC_VERSION >= 40500 */
1385#endif /* defined(__GNUC__) || defined(__MINGW32__) */
1386#if defined(__clang__)
1387/* Show no warning in case system functions are not used. */
1388#pragma clang diagnostic push
1389#pragma clang diagnostic ignored "-Wunused-function"
7c673cae
FG
1390#endif
1391
11fdf7f2
TL
1392
1393/* Get a unique thread ID as unsigned long, independent from the data type
1394 * of thread IDs defined by the operating system API.
1395 * If two calls to mg_current_thread_id return the same value, they calls
1396 * are done from the same thread. If they return different values, they are
1397 * done from different threads. (Provided this function is used in the same
1398 * process context and threads are not repeatedly created and deleted, but
1399 * CivetWeb does not do that).
1400 * This function must match the signature required for SSL id callbacks:
1401 * CRYPTO_set_id_callback
1402 */
1403FUNCTION_MAY_BE_UNUSED
1404static unsigned long
1405mg_current_thread_id(void)
1406{
1407#ifdef _WIN32
1408 return GetCurrentThreadId();
7c673cae 1409#else
7c673cae 1410
11fdf7f2
TL
1411#ifdef __clang__
1412#pragma clang diagnostic push
1413#pragma clang diagnostic ignored "-Wunreachable-code"
1414/* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
1415 * or not, so one of the two conditions will be unreachable by construction.
1416 * Unfortunately the C standard does not define a way to check this at
1417 * compile time, since the #if preprocessor conditions can not use the sizeof
1418 * operator as an argument. */
1419#endif
7c673cae 1420
11fdf7f2
TL
1421 if (sizeof(pthread_t) > sizeof(unsigned long)) {
1422 /* This is the problematic case for CRYPTO_set_id_callback:
1423 * The OS pthread_t can not be cast to unsigned long. */
1424 struct mg_workerTLS *tls =
1425 (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
1426 if (tls == NULL) {
1427 /* SSL called from an unknown thread: Create some thread index.
1428 */
1429 tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS));
1430 tls->is_master = -2; /* -2 means "3rd party thread" */
1431 tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
1432 pthread_setspecific(sTlsKey, tls);
1433 }
1434 return tls->thread_idx;
1435 } else {
1436 /* pthread_t may be any data type, so a simple cast to unsigned long
1437 * can rise a warning/error, depending on the platform.
1438 * Here memcpy is used as an anything-to-anything cast. */
1439 unsigned long ret = 0;
1440 pthread_t t = pthread_self();
1441 memcpy(&ret, &t, sizeof(pthread_t));
1442 return ret;
1443 }
1444
1445#ifdef __clang__
1446#pragma clang diagnostic pop
1447#endif
1448
1449#endif
1450}
1451
1452
1453FUNCTION_MAY_BE_UNUSED
1454static uint64_t
1455mg_get_current_time_ns(void)
1456{
1457 struct timespec tsnow;
1458 clock_gettime(CLOCK_REALTIME, &tsnow);
1459 return (((uint64_t)tsnow.tv_sec) * 1000000000) + (uint64_t)tsnow.tv_nsec;
1460}
1461
1462
1463#if defined(__GNUC__)
1464/* Show no warning in case system functions are not used. */
1465#if GCC_VERSION >= 40500
1466#pragma GCC diagnostic pop
1467#endif /* GCC_VERSION >= 40500 */
1468#endif /* defined(__GNUC__) */
1469#if defined(__clang__)
1470/* Show no warning in case system functions are not used. */
1471#pragma clang diagnostic pop
1472#endif
1473
1474
1475#if !defined(DEBUG_TRACE)
1476#if defined(DEBUG)
1477static void DEBUG_TRACE_FUNC(const char *func,
1478 unsigned line,
1479 PRINTF_FORMAT_STRING(const char *fmt),
1480 ...) PRINTF_ARGS(3, 4);
1481
1482static void
1483DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
1484{
1485 va_list args;
1486 uint64_t nsnow;
1487 static uint64_t nslast;
1488 struct timespec tsnow;
1489
1490 /* Get some operating system independent thread id */
1491 unsigned long thread_id = mg_current_thread_id();
1492
1493 clock_gettime(CLOCK_REALTIME, &tsnow);
1494 nsnow = ((uint64_t)tsnow.tv_sec) * ((uint64_t)1000000000)
1495 + ((uint64_t)tsnow.tv_nsec);
1496
1497 if (!nslast) {
1498 nslast = nsnow;
1499 }
1500
1501 flockfile(stdout);
1502 printf("*** %lu.%09lu %12" INT64_FMT " %lu %s:%u: ",
1503 (unsigned long)tsnow.tv_sec,
1504 (unsigned long)tsnow.tv_nsec,
1505 nsnow - nslast,
1506 thread_id,
1507 func,
1508 line);
1509 va_start(args, fmt);
1510 vprintf(fmt, args);
1511 va_end(args);
1512 putchar('\n');
1513 fflush(stdout);
1514 funlockfile(stdout);
1515 nslast = nsnow;
1516}
1517
1518#define DEBUG_TRACE(fmt, ...) \
1519 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
1520
1521#else
1522#define DEBUG_TRACE(fmt, ...) \
1523 do { \
1524 } while (0)
1525#endif /* DEBUG */
1526#endif /* DEBUG_TRACE */
1527
1528
1529#define MD5_STATIC static
1530#include "md5.inl"
1531
1532/* Darwin prior to 7.0 and Win32 do not have socklen_t */
1533#ifdef NO_SOCKLEN_T
1534typedef int socklen_t;
1535#endif /* NO_SOCKLEN_T */
1536#define _DARWIN_UNLIMITED_SELECT
1537
1538#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
1539
1540#if !defined(MSG_NOSIGNAL)
1541#define MSG_NOSIGNAL (0)
1542#endif
1543
1544#if !defined(SOMAXCONN)
1545#define SOMAXCONN (100)
1546#endif
1547
1548/* Size of the accepted socket queue */
1549#if !defined(MGSQLEN)
1550#define MGSQLEN (20)
1551#endif
1552
1553
1554#if defined(NO_SSL)
1555typedef struct SSL SSL; /* dummy for SSL argument to push/pull */
1556typedef struct SSL_CTX SSL_CTX;
1557#else
1558#if defined(NO_SSL_DL)
1559#include <openssl/ssl.h>
1560#include <openssl/err.h>
1561#include <openssl/crypto.h>
1562#include <openssl/x509.h>
1563#include <openssl/pem.h>
1564#include <openssl/engine.h>
1565#include <openssl/conf.h>
1566#include <openssl/dh.h>
1567#include <openssl/bn.h>
1568#include <openssl/opensslv.h>
1569#else
1570
1571/* SSL loaded dynamically from DLL.
1572 * I put the prototypes here to be independent from OpenSSL source
1573 * installation. */
1574
1575typedef struct ssl_st SSL;
1576typedef struct ssl_method_st SSL_METHOD;
1577typedef struct ssl_ctx_st SSL_CTX;
1578typedef struct x509_store_ctx_st X509_STORE_CTX;
1579typedef struct x509_name X509_NAME;
1580typedef struct asn1_integer ASN1_INTEGER;
1581typedef struct bignum BIGNUM;
1582typedef struct ossl_init_settings_st OPENSSL_INIT_SETTINGS;
1583typedef struct evp_md EVP_MD;
1584typedef struct x509 X509;
1585
1586
1587#define SSL_CTRL_OPTIONS (32)
7c673cae
FG
1588#define SSL_CTRL_CLEAR_OPTIONS (77)
1589#define SSL_CTRL_SET_ECDH_AUTO (94)
1590
11fdf7f2
TL
1591#define OPENSSL_INIT_NO_LOAD_SSL_STRINGS 0x00100000L
1592#define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L
1593#define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L
1594
7c673cae
FG
1595#define SSL_VERIFY_NONE (0)
1596#define SSL_VERIFY_PEER (1)
1597#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
1598#define SSL_VERIFY_CLIENT_ONCE (4)
1599#define SSL_OP_ALL ((long)(0x80000BFFUL))
1600#define SSL_OP_NO_SSLv2 (0x01000000L)
1601#define SSL_OP_NO_SSLv3 (0x02000000L)
1602#define SSL_OP_NO_TLSv1 (0x04000000L)
1603#define SSL_OP_NO_TLSv1_2 (0x08000000L)
1604#define SSL_OP_NO_TLSv1_1 (0x10000000L)
1605#define SSL_OP_SINGLE_DH_USE (0x00100000L)
11fdf7f2
TL
1606#define SSL_OP_CIPHER_SERVER_PREFERENCE (0x00400000L)
1607#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (0x00010000L)
1608#define SSL_OP_NO_COMPRESSION (0x00020000L)
1609
1610#define SSL_CB_HANDSHAKE_START (0x10)
1611#define SSL_CB_HANDSHAKE_DONE (0x20)
1612
1613#define SSL_ERROR_NONE (0)
1614#define SSL_ERROR_SSL (1)
1615#define SSL_ERROR_WANT_READ (2)
1616#define SSL_ERROR_WANT_WRITE (3)
1617#define SSL_ERROR_WANT_X509_LOOKUP (4)
1618#define SSL_ERROR_SYSCALL (5) /* see errno */
1619#define SSL_ERROR_ZERO_RETURN (6)
1620#define SSL_ERROR_WANT_CONNECT (7)
1621#define SSL_ERROR_WANT_ACCEPT (8)
1622
7c673cae
FG
1623
1624struct ssl_func {
1625 const char *name; /* SSL function name */
1626 void (*ptr)(void); /* Function pointer */
1627};
1628
11fdf7f2
TL
1629
1630#ifdef OPENSSL_API_1_1
1631
1632#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
1633#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
1634#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
1635#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
1636#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
1637#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
1638#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
1639#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr)
1640#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr)
1641#define TLS_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr)
1642#define OPENSSL_init_ssl \
1643 (*(int (*)(uint64_t opts, \
1644 const OPENSSL_INIT_SETTINGS *settings))ssl_sw[10].ptr)
1645#define SSL_CTX_use_PrivateKey_file \
1646 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
1647#define SSL_CTX_use_certificate_file \
1648 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
1649#define SSL_CTX_set_default_passwd_cb \
1650 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
1651#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
1652#define SSL_CTX_use_certificate_chain_file \
1653 (*(int (*)(SSL_CTX *, const char *))ssl_sw[15].ptr)
1654#define TLS_client_method (*(SSL_METHOD * (*)(void))ssl_sw[16].ptr)
1655#define SSL_pending (*(int (*)(SSL *))ssl_sw[17].ptr)
1656#define SSL_CTX_set_verify \
1657 (*(void (*)(SSL_CTX *, \
1658 int, \
1659 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[18].ptr)
1660#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[19].ptr)
1661#define SSL_CTX_load_verify_locations \
1662 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[20].ptr)
1663#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[21].ptr)
1664#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[22].ptr)
1665#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[23].ptr)
1666#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[24].ptr)
1667#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[25].ptr)
1668#define SSL_CIPHER_get_name \
1669 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[26].ptr)
1670#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[27].ptr)
1671#define SSL_CTX_set_session_id_context \
1672 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[28].ptr)
1673#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[29].ptr)
1674#define SSL_CTX_set_cipher_list \
1675 (*(int (*)(SSL_CTX *, const char *))ssl_sw[30].ptr)
1676#define SSL_CTX_set_options \
1677 (*(unsigned long (*)(SSL_CTX *, unsigned long))ssl_sw[31].ptr)
1678#define SSL_CTX_set_info_callback \
1679 (*(void (*)(SSL_CTX * ctx, \
1680 void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr)
1681#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr)
1682#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
1683
1684#define SSL_CTX_clear_options(ctx, op) \
1685 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
1686#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
1687 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
1688
1689#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
1690#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
1691
1692#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
1693#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
1694
1695#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[0].ptr)
1696#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[1].ptr)
1697#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[2].ptr)
1698#define CONF_modules_unload (*(void (*)(int))crypto_sw[3].ptr)
1699#define X509_free (*(void (*)(X509 *))crypto_sw[4].ptr)
1700#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[5].ptr)
1701#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[6].ptr)
1702#define X509_NAME_oneline \
1703 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[7].ptr)
1704#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[8].ptr)
1705#define EVP_get_digestbyname \
1706 (*(const EVP_MD *(*)(const char *))crypto_sw[9].ptr)
1707#define EVP_Digest \
1708 (*(int (*)( \
1709 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
1710 crypto_sw[10].ptr)
1711#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[11].ptr)
1712#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[12].ptr)
1713#define ASN1_INTEGER_to_BN \
1714 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[13].ptr)
1715#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[14].ptr)
1716#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[15].ptr)
1717
1718#define OPENSSL_free(a) CRYPTO_free(a)
1719
1720
1721/* set_ssl_option() function updates this array.
1722 * It loads SSL library dynamically and changes NULLs to the actual addresses
1723 * of respective functions. The macros above (like SSL_connect()) are really
1724 * just calling these functions indirectly via the pointer. */
1725static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
1726 {"SSL_accept", NULL},
1727 {"SSL_connect", NULL},
1728 {"SSL_read", NULL},
1729 {"SSL_write", NULL},
1730 {"SSL_get_error", NULL},
1731 {"SSL_set_fd", NULL},
1732 {"SSL_new", NULL},
1733 {"SSL_CTX_new", NULL},
1734 {"TLS_server_method", NULL},
1735 {"OPENSSL_init_ssl", NULL},
1736 {"SSL_CTX_use_PrivateKey_file", NULL},
1737 {"SSL_CTX_use_certificate_file", NULL},
1738 {"SSL_CTX_set_default_passwd_cb", NULL},
1739 {"SSL_CTX_free", NULL},
1740 {"SSL_CTX_use_certificate_chain_file", NULL},
1741 {"TLS_client_method", NULL},
1742 {"SSL_pending", NULL},
1743 {"SSL_CTX_set_verify", NULL},
1744 {"SSL_shutdown", NULL},
1745 {"SSL_CTX_load_verify_locations", NULL},
1746 {"SSL_CTX_set_default_verify_paths", NULL},
1747 {"SSL_CTX_set_verify_depth", NULL},
1748 {"SSL_get_peer_certificate", NULL},
1749 {"SSL_get_version", NULL},
1750 {"SSL_get_current_cipher", NULL},
1751 {"SSL_CIPHER_get_name", NULL},
1752 {"SSL_CTX_check_private_key", NULL},
1753 {"SSL_CTX_set_session_id_context", NULL},
1754 {"SSL_CTX_ctrl", NULL},
1755 {"SSL_CTX_set_cipher_list", NULL},
1756 {"SSL_CTX_set_options", NULL},
1757 {"SSL_CTX_set_info_callback", NULL},
1758 {"SSL_get_ex_data", NULL},
1759 {"SSL_set_ex_data", NULL},
1760 {NULL, NULL}};
1761
1762
1763/* Similar array as ssl_sw. These functions could be located in different
1764 * lib. */
1765static struct ssl_func crypto_sw[] = {{"ERR_get_error", NULL},
1766 {"ERR_error_string", NULL},
1767 {"ERR_remove_state", NULL},
1768 {"CONF_modules_unload", NULL},
1769 {"X509_free", NULL},
1770 {"X509_get_subject_name", NULL},
1771 {"X509_get_issuer_name", NULL},
1772 {"X509_NAME_oneline", NULL},
1773 {"X509_get_serialNumber", NULL},
1774 {"EVP_get_digestbyname", NULL},
1775 {"EVP_Digest", NULL},
1776 {"i2d_X509", NULL},
1777 {"BN_bn2hex", NULL},
1778 {"ASN1_INTEGER_to_BN", NULL},
1779 {"BN_free", NULL},
1780 {"CRYPTO_free", NULL},
1781 {NULL, NULL}};
1782#else
1783
7c673cae
FG
1784#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
1785#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
1786#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
1787#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
1788#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
1789#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
1790#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
1791#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr)
1792#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr)
1793#define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr)
1794#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
1795#define SSL_CTX_use_PrivateKey_file \
1796 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
1797#define SSL_CTX_use_certificate_file \
1798 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
1799#define SSL_CTX_set_default_passwd_cb \
1800 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
1801#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
1802#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
1803#define SSL_CTX_use_certificate_chain_file \
1804 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
1805#define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr)
1806#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
1807#define SSL_CTX_set_verify \
1808 (*(void (*)(SSL_CTX *, \
1809 int, \
1810 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr)
1811#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
1812#define SSL_CTX_load_verify_locations \
1813 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
1814#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
1815#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
1816#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr)
1817#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
1818#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr)
1819#define SSL_CIPHER_get_name \
1820 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
1821#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
1822#define SSL_CTX_set_session_id_context \
1823 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
1824#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
1825#define SSL_CTX_set_cipher_list \
1826 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
11fdf7f2
TL
1827#define SSL_CTX_set_info_callback \
1828 (*(void (*)(SSL_CTX * ctx, \
1829 void (*callback)(SSL * s, int, int)))ssl_sw[32].ptr)
1830#define SSL_get_ex_data (*(char *(*)(SSL *, int))ssl_sw[33].ptr)
1831#define SSL_set_ex_data (*(void (*)(SSL *, int, char *))ssl_sw[34].ptr)
1832
7c673cae
FG
1833#define SSL_CTX_set_options(ctx, op) \
1834 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
1835#define SSL_CTX_clear_options(ctx, op) \
1836 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
1837#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
1838 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
1839
11fdf7f2
TL
1840
1841#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
1842#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
1843
1844#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg))
1845#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0))
1846
7c673cae
FG
1847#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
1848#define CRYPTO_set_locking_callback \
1849 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
1850#define CRYPTO_set_id_callback \
1851 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
1852#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
1853#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
1854#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
1855#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
1856#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
1857#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
1858#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
1859#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
11fdf7f2
TL
1860#define X509_free (*(void (*)(X509 *))crypto_sw[11].ptr)
1861#define X509_get_subject_name (*(X509_NAME * (*)(X509 *))crypto_sw[12].ptr)
1862#define X509_get_issuer_name (*(X509_NAME * (*)(X509 *))crypto_sw[13].ptr)
1863#define X509_NAME_oneline \
1864 (*(char *(*)(X509_NAME *, char *, int))crypto_sw[14].ptr)
1865#define X509_get_serialNumber (*(ASN1_INTEGER * (*)(X509 *))crypto_sw[15].ptr)
1866#define i2c_ASN1_INTEGER \
1867 (*(int (*)(ASN1_INTEGER *, unsigned char **))crypto_sw[16].ptr)
1868#define EVP_get_digestbyname \
1869 (*(const EVP_MD *(*)(const char *))crypto_sw[17].ptr)
1870#define EVP_Digest \
1871 (*(int (*)( \
1872 const void *, size_t, void *, unsigned int *, const EVP_MD *, void *)) \
1873 crypto_sw[18].ptr)
1874#define i2d_X509 (*(int (*)(X509 *, unsigned char **))crypto_sw[19].ptr)
1875#define BN_bn2hex (*(char *(*)(const BIGNUM *a))crypto_sw[20].ptr)
1876#define ASN1_INTEGER_to_BN \
1877 (*(BIGNUM * (*)(const ASN1_INTEGER *ai, BIGNUM *bn))crypto_sw[21].ptr)
1878#define BN_free (*(void (*)(const BIGNUM *a))crypto_sw[22].ptr)
1879#define CRYPTO_free (*(void (*)(void *addr))crypto_sw[23].ptr)
1880
1881#define OPENSSL_free(a) CRYPTO_free(a)
7c673cae
FG
1882
1883/* set_ssl_option() function updates this array.
1884 * It loads SSL library dynamically and changes NULLs to the actual addresses
1885 * of respective functions. The macros above (like SSL_connect()) are really
1886 * just calling these functions indirectly via the pointer. */
1887static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
1888 {"SSL_accept", NULL},
1889 {"SSL_connect", NULL},
1890 {"SSL_read", NULL},
1891 {"SSL_write", NULL},
1892 {"SSL_get_error", NULL},
1893 {"SSL_set_fd", NULL},
1894 {"SSL_new", NULL},
1895 {"SSL_CTX_new", NULL},
1896 {"SSLv23_server_method", NULL},
1897 {"SSL_library_init", NULL},
1898 {"SSL_CTX_use_PrivateKey_file", NULL},
1899 {"SSL_CTX_use_certificate_file", NULL},
1900 {"SSL_CTX_set_default_passwd_cb", NULL},
1901 {"SSL_CTX_free", NULL},
1902 {"SSL_load_error_strings", NULL},
1903 {"SSL_CTX_use_certificate_chain_file", NULL},
1904 {"SSLv23_client_method", NULL},
1905 {"SSL_pending", NULL},
1906 {"SSL_CTX_set_verify", NULL},
1907 {"SSL_shutdown", NULL},
1908 {"SSL_CTX_load_verify_locations", NULL},
1909 {"SSL_CTX_set_default_verify_paths", NULL},
1910 {"SSL_CTX_set_verify_depth", NULL},
1911 {"SSL_get_peer_certificate", NULL},
1912 {"SSL_get_version", NULL},
1913 {"SSL_get_current_cipher", NULL},
1914 {"SSL_CIPHER_get_name", NULL},
1915 {"SSL_CTX_check_private_key", NULL},
1916 {"SSL_CTX_set_session_id_context", NULL},
1917 {"SSL_CTX_ctrl", NULL},
1918 {"SSL_CTX_set_cipher_list", NULL},
11fdf7f2
TL
1919 {"SSL_CTX_set_info_callback", NULL},
1920 {"SSL_get_ex_data", NULL},
1921 {"SSL_set_ex_data", NULL},
7c673cae
FG
1922 {NULL, NULL}};
1923
1924
1925/* Similar array as ssl_sw. These functions could be located in different
1926 * lib. */
7c673cae
FG
1927static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
1928 {"CRYPTO_set_locking_callback", NULL},
1929 {"CRYPTO_set_id_callback", NULL},
1930 {"ERR_get_error", NULL},
1931 {"ERR_error_string", NULL},
1932 {"ERR_remove_state", NULL},
1933 {"ERR_free_strings", NULL},
1934 {"ENGINE_cleanup", NULL},
1935 {"CONF_modules_unload", NULL},
1936 {"CRYPTO_cleanup_all_ex_data", NULL},
1937 {"EVP_cleanup", NULL},
11fdf7f2
TL
1938 {"X509_free", NULL},
1939 {"X509_get_subject_name", NULL},
1940 {"X509_get_issuer_name", NULL},
1941 {"X509_NAME_oneline", NULL},
1942 {"X509_get_serialNumber", NULL},
1943 {"i2c_ASN1_INTEGER", NULL},
1944 {"EVP_get_digestbyname", NULL},
1945 {"EVP_Digest", NULL},
1946 {"i2d_X509", NULL},
1947 {"BN_bn2hex", NULL},
1948 {"ASN1_INTEGER_to_BN", NULL},
1949 {"BN_free", NULL},
1950 {"CRYPTO_free", NULL},
7c673cae 1951 {NULL, NULL}};
11fdf7f2 1952#endif /* OPENSSL_API_1_1 */
7c673cae 1953#endif /* NO_SSL_DL */
11fdf7f2 1954#endif /* NO_SSL */
7c673cae
FG
1955
1956
1957#if !defined(NO_CACHING)
1958static const char *month_names[] = {"Jan",
1959 "Feb",
1960 "Mar",
1961 "Apr",
1962 "May",
1963 "Jun",
1964 "Jul",
1965 "Aug",
1966 "Sep",
1967 "Oct",
1968 "Nov",
1969 "Dec"};
1970#endif /* !NO_CACHING */
1971
11fdf7f2
TL
1972/* Unified socket address. For IPv6 support, add IPv6 address structure in
1973 * the
7c673cae
FG
1974 * union u. */
1975union usa {
1976 struct sockaddr sa;
1977 struct sockaddr_in sin;
1978#if defined(USE_IPV6)
1979 struct sockaddr_in6 sin6;
1980#endif
1981};
1982
1983/* Describes a string (chunk of memory). */
1984struct vec {
1985 const char *ptr;
1986 size_t len;
1987};
1988
11fdf7f2
TL
1989struct mg_file_stat {
1990 /* File properties filled by mg_stat: */
7c673cae
FG
1991 uint64_t size;
1992 time_t last_modified;
11fdf7f2
TL
1993 int is_directory; /* Set to 1 if mg_stat is called for a directory */
1994 int is_gzipped; /* Set to 1 if the content is gzipped, in which
1995 * case we need a "Content-Eencoding: gzip" header */
1996 int location; /* 0 = nowhere, 1 = on disk, 2 = in memory */
1997};
1998
1999struct mg_file_in_memory {
2000 char *p;
2001 uint32_t pos;
2002 char mode;
2003};
2004
2005struct mg_file_access {
2006 /* File properties filled by mg_fopen: */
7c673cae 2007 FILE *fp;
11fdf7f2
TL
2008 /* TODO (low): Replace "membuf" implementation by a "file in memory"
2009 * support library. Use some struct mg_file_in_memory *mf; instead of
2010 * membuf char pointer. */
2011 const char *membuf;
2012};
2013
2014struct mg_file {
2015 struct mg_file_stat stat;
2016 struct mg_file_access access;
7c673cae
FG
2017};
2018
2019#define STRUCT_FILE_INITIALIZER \
2020 { \
11fdf7f2
TL
2021 { \
2022 (uint64_t)0, (time_t)0, 0, 0, 0 \
2023 } \
2024 , \
2025 { \
2026 (FILE *) NULL, (const char *)NULL \
2027 } \
7c673cae
FG
2028 }
2029
2030/* Describes listening socket, or socket which was accept()-ed by the master
2031 * thread and queued for future handling by the worker thread. */
2032struct socket {
2033 SOCKET sock; /* Listening socket */
2034 union usa lsa; /* Local socket address */
2035 union usa rsa; /* Remote socket address */
2036 unsigned char is_ssl; /* Is port SSL-ed */
2037 unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
2038 * port */
11fdf7f2 2039 unsigned char in_use; /* Is valid */
7c673cae
FG
2040};
2041
2042/* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
2043enum {
2044 CGI_EXTENSIONS,
2045 CGI_ENVIRONMENT,
2046 PUT_DELETE_PASSWORDS_FILE,
2047 CGI_INTERPRETER,
2048 PROTECT_URI,
2049 AUTHENTICATION_DOMAIN,
31f18b77 2050 ENABLE_AUTH_DOMAIN_CHECK,
7c673cae
FG
2051 SSI_EXTENSIONS,
2052 THROTTLE,
2053 ACCESS_LOG_FILE,
2054 ENABLE_DIRECTORY_LISTING,
2055 ERROR_LOG_FILE,
2056 GLOBAL_PASSWORDS_FILE,
2057 INDEX_FILES,
2058 ENABLE_KEEP_ALIVE,
2059 ACCESS_CONTROL_LIST,
2060 EXTRA_MIME_TYPES,
2061 LISTENING_PORTS,
2062 DOCUMENT_ROOT,
2063 SSL_CERTIFICATE,
11fdf7f2 2064 SSL_CERTIFICATE_CHAIN,
7c673cae
FG
2065 NUM_THREADS,
2066 RUN_AS_USER,
11fdf7f2 2067 URL_REWRITE_PATTERN,
7c673cae
FG
2068 HIDE_FILES,
2069 REQUEST_TIMEOUT,
11fdf7f2
TL
2070 KEEP_ALIVE_TIMEOUT,
2071 LINGER_TIMEOUT,
7c673cae
FG
2072 SSL_DO_VERIFY_PEER,
2073 SSL_CA_PATH,
2074 SSL_CA_FILE,
2075 SSL_VERIFY_DEPTH,
2076 SSL_DEFAULT_VERIFY_PATHS,
2077 SSL_CIPHER_LIST,
2078 SSL_PROTOCOL_VERSION,
2079 SSL_SHORT_TRUST,
11fdf7f2 2080
7c673cae
FG
2081#if defined(USE_WEBSOCKET)
2082 WEBSOCKET_TIMEOUT,
2083#endif
11fdf7f2 2084
7c673cae
FG
2085 DECODE_URL,
2086
2087#if defined(USE_LUA)
2088 LUA_PRELOAD_FILE,
2089 LUA_SCRIPT_EXTENSIONS,
2090 LUA_SERVER_PAGE_EXTENSIONS,
2091#endif
2092#if defined(USE_DUKTAPE)
2093 DUKTAPE_SCRIPT_EXTENSIONS,
2094#endif
2095
2096#if defined(USE_WEBSOCKET)
2097 WEBSOCKET_ROOT,
2098#endif
2099#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2100 LUA_WEBSOCKET_EXTENSIONS,
2101#endif
11fdf7f2 2102
7c673cae 2103 ACCESS_CONTROL_ALLOW_ORIGIN,
11fdf7f2
TL
2104 ACCESS_CONTROL_ALLOW_METHODS,
2105 ACCESS_CONTROL_ALLOW_HEADERS,
7c673cae
FG
2106 ERROR_PAGES,
2107 CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the
11fdf7f2 2108 * socket option typedef TCP_NODELAY. */
7c673cae
FG
2109#if !defined(NO_CACHING)
2110 STATIC_FILE_MAX_AGE,
2111#endif
11fdf7f2
TL
2112#if !defined(NO_SSL)
2113 STRICT_HTTPS_MAX_AGE,
2114#endif
2115#if defined(__linux__)
2116 ALLOW_SENDFILE_CALL,
2117#endif
2118#if defined(_WIN32)
2119 CASE_SENSITIVE_FILES,
2120#endif
2121#if defined(USE_LUA)
2122 LUA_BACKGROUND_SCRIPT,
2123 LUA_BACKGROUND_SCRIPT_PARAMS,
2124#endif
2125 ADDITIONAL_HEADER,
2126 MAX_REQUEST_SIZE,
2127 ALLOW_INDEX_SCRIPT_SUB_RES,
7c673cae 2128
11fdf7f2
TL
2129 VALIDATE_HTTP_METHOD,
2130 CANONICALIZE_URL_PATH,
2131 ALLOW_UNICODE_IN_URLS,
7c673cae
FG
2132 NUM_OPTIONS
2133};
2134
2135
2136/* Config option name, config types, default value */
2137static struct mg_option config_options[] = {
2138 {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
11fdf7f2 2139 {"cgi_environment", CONFIG_TYPE_STRING_LIST, NULL},
7c673cae
FG
2140 {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL},
2141 {"cgi_interpreter", CONFIG_TYPE_FILE, NULL},
11fdf7f2 2142 {"protect_uri", CONFIG_TYPE_STRING_LIST, NULL},
7c673cae 2143 {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"},
31f18b77 2144 {"enable_auth_domain_check", CONFIG_TYPE_BOOLEAN, "yes"},
7c673cae 2145 {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"},
11fdf7f2 2146 {"throttle", CONFIG_TYPE_STRING_LIST, NULL},
7c673cae
FG
2147 {"access_log_file", CONFIG_TYPE_FILE, NULL},
2148 {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"},
2149 {"error_log_file", CONFIG_TYPE_FILE, NULL},
2150 {"global_auth_file", CONFIG_TYPE_FILE, NULL},
2151 {"index_files",
11fdf7f2 2152 CONFIG_TYPE_STRING_LIST,
7c673cae 2153#ifdef USE_LUA
11fdf7f2
TL
2154 "index.xhtml,index.html,index.htm,"
2155 "index.lp,index.lsp,index.lua,index.cgi,"
7c673cae
FG
2156 "index.shtml,index.php"},
2157#else
2158 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
2159#endif
2160 {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"},
11fdf7f2
TL
2161 {"access_control_list", CONFIG_TYPE_STRING_LIST, NULL},
2162 {"extra_mime_types", CONFIG_TYPE_STRING_LIST, NULL},
2163 {"listening_ports", CONFIG_TYPE_STRING_LIST, "8080"},
7c673cae
FG
2164 {"document_root", CONFIG_TYPE_DIRECTORY, NULL},
2165 {"ssl_certificate", CONFIG_TYPE_FILE, NULL},
11fdf7f2 2166 {"ssl_certificate_chain", CONFIG_TYPE_FILE, NULL},
7c673cae
FG
2167 {"num_threads", CONFIG_TYPE_NUMBER, "50"},
2168 {"run_as_user", CONFIG_TYPE_STRING, NULL},
11fdf7f2 2169 {"url_rewrite_patterns", CONFIG_TYPE_STRING_LIST, NULL},
7c673cae
FG
2170 {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL},
2171 {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
11fdf7f2
TL
2172 {"keep_alive_timeout_ms", CONFIG_TYPE_NUMBER, "500"},
2173 {"linger_timeout_ms", CONFIG_TYPE_NUMBER, NULL},
2174
2175 /* TODO(Feature): this is no longer a boolean, but yes/no/optional */
7c673cae 2176 {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN, "no"},
11fdf7f2 2177
7c673cae
FG
2178 {"ssl_ca_path", CONFIG_TYPE_DIRECTORY, NULL},
2179 {"ssl_ca_file", CONFIG_TYPE_FILE, NULL},
2180 {"ssl_verify_depth", CONFIG_TYPE_NUMBER, "9"},
2181 {"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN, "yes"},
2182 {"ssl_cipher_list", CONFIG_TYPE_STRING, NULL},
2183 {"ssl_protocol_version", CONFIG_TYPE_NUMBER, "0"},
2184 {"ssl_short_trust", CONFIG_TYPE_BOOLEAN, "no"},
2185#if defined(USE_WEBSOCKET)
2186 {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
2187#endif
2188 {"decode_url", CONFIG_TYPE_BOOLEAN, "yes"},
2189
2190#if defined(USE_LUA)
2191 {"lua_preload_file", CONFIG_TYPE_FILE, NULL},
2192 {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
2193 {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"},
2194#endif
2195#if defined(USE_DUKTAPE)
2196 /* The support for duktape is still in alpha version state.
2197 * The name of this config option might change. */
2198 {"duktape_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"},
2199#endif
2200
2201#if defined(USE_WEBSOCKET)
2202 {"websocket_root", CONFIG_TYPE_DIRECTORY, NULL},
2203#endif
2204#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2205 {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
2206#endif
2207 {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"},
11fdf7f2
TL
2208 {"access_control_allow_methods", CONFIG_TYPE_STRING, "*"},
2209 {"access_control_allow_headers", CONFIG_TYPE_STRING, "*"},
7c673cae
FG
2210 {"error_pages", CONFIG_TYPE_DIRECTORY, NULL},
2211 {"tcp_nodelay", CONFIG_TYPE_NUMBER, "0"},
2212#if !defined(NO_CACHING)
2213 {"static_file_max_age", CONFIG_TYPE_NUMBER, "3600"},
2214#endif
11fdf7f2
TL
2215#if !defined(NO_SSL)
2216 {"strict_transport_security_max_age", CONFIG_TYPE_NUMBER, NULL},
2217#endif
2218#if defined(__linux__)
2219 {"allow_sendfile_call", CONFIG_TYPE_BOOLEAN, "yes"},
2220#endif
2221#if defined(_WIN32)
2222 {"case_sensitive", CONFIG_TYPE_BOOLEAN, "no"},
2223#endif
2224#if defined(USE_LUA)
2225 {"lua_background_script", CONFIG_TYPE_FILE, NULL},
2226 {"lua_background_script_params", CONFIG_TYPE_STRING_LIST, NULL},
2227#endif
2228 {"additional_header", CONFIG_TYPE_STRING_MULTILINE, NULL},
2229 {"max_request_size", CONFIG_TYPE_NUMBER, "16384"},
2230 {"allow_index_script_resource", CONFIG_TYPE_BOOLEAN, "no"},
7c673cae
FG
2231 {"validate_http_method", CONFIG_TYPE_BOOLEAN, "yes"},
2232 {"canonicalize_url_path", CONFIG_TYPE_BOOLEAN, "yes"},
11fdf7f2 2233 {"allow_unicode_in_urls", CONFIG_TYPE_BOOLEAN, "no"},
7c673cae
FG
2234 {NULL, CONFIG_TYPE_UNKNOWN, NULL}};
2235
11fdf7f2 2236
7c673cae
FG
2237/* Check if the config_options and the corresponding enum have compatible
2238 * sizes. */
2239mg_static_assert((sizeof(config_options) / sizeof(config_options[0]))
2240 == (NUM_OPTIONS + 1),
2241 "config_options and enum not sync");
2242
11fdf7f2 2243
7c673cae
FG
2244enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER };
2245
11fdf7f2 2246
7c673cae
FG
2247struct mg_handler_info {
2248 /* Name/Pattern of the URI. */
2249 char *uri;
2250 size_t uri_len;
2251
2252 /* handler type */
2253 int handler_type;
2254
2255 /* Handler for http/https or authorization requests. */
2256 mg_request_handler handler;
2257
2258 /* Handler for ws/wss (websocket) requests. */
2259 mg_websocket_connect_handler connect_handler;
2260 mg_websocket_ready_handler ready_handler;
2261 mg_websocket_data_handler data_handler;
2262 mg_websocket_close_handler close_handler;
2263
11fdf7f2
TL
2264 /* accepted subprotocols for ws/wss requests. */
2265 struct mg_websocket_subprotocols *subprotocols;
2266
7c673cae
FG
2267 /* Handler for authorization requests */
2268 mg_authorization_handler auth_handler;
2269
2270 /* User supplied argument for the handler function. */
2271 void *cbdata;
2272
2273 /* next handler in a linked list */
2274 struct mg_handler_info *next;
2275};
2276
11fdf7f2
TL
2277
2278enum {
2279 CONTEXT_INVALID,
2280 CONTEXT_SERVER,
2281 CONTEXT_HTTP_CLIENT,
2282 CONTEXT_WS_CLIENT
2283};
2284
2285
7c673cae
FG
2286struct mg_context {
2287 volatile int stop_flag; /* Should we stop event loop */
2288 SSL_CTX *ssl_ctx; /* SSL context */
2289 char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
2290 struct mg_callbacks callbacks; /* User-defined callback function */
2291 void *user_data; /* User-defined data */
11fdf7f2 2292 int context_type; /* See CONTEXT_* above */
7c673cae
FG
2293
2294 struct socket *listening_sockets;
11fdf7f2 2295 struct pollfd *listening_socket_fds;
7c673cae
FG
2296 unsigned int num_listening_sockets;
2297
7c673cae 2298 pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */
7c673cae 2299
11fdf7f2
TL
2300#ifdef ALTERNATIVE_QUEUE
2301 struct socket *client_socks;
2302 void **client_wait_events;
2303#else
7c673cae
FG
2304 struct socket queue[MGSQLEN]; /* Accepted sockets */
2305 volatile int sq_head; /* Head of the socket queue */
2306 volatile int sq_tail; /* Tail of the socket queue */
2307 pthread_cond_t sq_full; /* Signaled when socket is produced */
2308 pthread_cond_t sq_empty; /* Signaled when socket is consumed */
11fdf7f2
TL
2309#endif
2310
2311 unsigned int max_request_size; /* The max request size */
2312
2313 pthread_t masterthreadid; /* The master thread ID */
7c673cae 2314 unsigned int
11fdf7f2
TL
2315 cfg_worker_threads; /* The number of configured worker threads. */
2316 pthread_t *worker_threadids; /* The worker thread IDs */
2317 struct mg_connection *worker_connections; /* The connection struct, pre-
2318 * allocated for each worker */
7c673cae 2319
11fdf7f2
TL
2320 time_t start_time; /* Server start time, used for authentication
2321 * and for diagnstics. */
2322
2323 uint64_t auth_nonce_mask; /* Mask for all nonce values */
7c673cae
FG
2324 pthread_mutex_t nonce_mutex; /* Protects nonce_count */
2325 unsigned long nonce_count; /* Used nonces, used for authentication */
2326
2327 char *systemName; /* What operating system is running */
2328
2329 /* linked list of uri handlers */
2330 struct mg_handler_info *handlers;
2331
2332#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2333 /* linked list of shared lua websockets */
2334 struct mg_shared_lua_websocket_list *shared_lua_websockets;
2335#endif
2336
11fdf7f2 2337#if defined(USE_TIMERS)
7c673cae
FG
2338 struct ttimers *timers;
2339#endif
11fdf7f2
TL
2340
2341#if defined(USE_LUA)
2342 void *lua_background_state;
2343#endif
2344
2345#if defined(USE_SERVER_STATS)
2346 int active_connections;
2347 int max_connections;
2348 int64_t total_connections;
2349 int64_t total_requests;
2350 struct mg_memory_stat ctx_memory;
2351 int64_t total_data_read;
2352 int64_t total_data_written;
2353#endif
7c673cae
FG
2354};
2355
2356
11fdf7f2
TL
2357#if defined(USE_SERVER_STATS)
2358static struct mg_memory_stat mg_common_memory = {0, 0, 0};
2359
2360static struct mg_memory_stat *
2361get_memory_stat(struct mg_context *ctx)
2362{
2363 if (ctx) {
2364 return &(ctx->ctx_memory);
2365 }
2366 return &mg_common_memory;
2367}
2368#endif
2369
2370enum {
2371 CONNECTION_TYPE_INVALID,
2372 CONNECTION_TYPE_REQUEST,
2373 CONNECTION_TYPE_RESPONSE
2374};
2375
7c673cae 2376struct mg_connection {
11fdf7f2
TL
2377 int connection_type; /* see CONNECTION_TYPE_* above */
2378
7c673cae 2379 struct mg_request_info request_info;
11fdf7f2
TL
2380 struct mg_response_info response_info;
2381
7c673cae 2382 struct mg_context *ctx;
11fdf7f2
TL
2383
2384#if defined(USE_SERVER_STATS)
2385 int conn_state; /* 0 = undef, numerical value may change in different
2386 * versions. For the current definition, see
2387 * mg_get_connection_info_impl */
2388#endif
2389
7c673cae
FG
2390 SSL *ssl; /* SSL descriptor */
2391 SSL_CTX *client_ssl_ctx; /* SSL context for client connections */
2392 struct socket client; /* Connected client */
2393 time_t conn_birth_time; /* Time (wall clock) when connection was
2394 * established */
2395 struct timespec req_time; /* Time (since system start) when the request
2396 * was received */
2397 int64_t num_bytes_sent; /* Total bytes sent to client */
2398 int64_t content_len; /* Content-Length header value */
2399 int64_t consumed_content; /* How many bytes of content have been read */
11fdf7f2
TL
2400 int is_chunked; /* Transfer-Encoding is chunked:
2401 * 0 = not chunked,
2402 * 1 = chunked, do data read yet,
2403 * 2 = chunked, some data read,
2404 * 3 = chunked, all data read
2405 */
7c673cae
FG
2406 size_t chunk_remainder; /* Unread data from the last chunk */
2407 char *buf; /* Buffer for received data */
2408 char *path_info; /* PATH_INFO part of the URL */
2409
2410 int must_close; /* 1 if connection must be closed */
11fdf7f2 2411 int accept_gzip; /* 1 if gzip encoding is accepted */
7c673cae
FG
2412 int in_error_handler; /* 1 if in handler for user defined error
2413 * pages */
11fdf7f2
TL
2414#if defined(USE_WEBSOCKET)
2415 int in_websocket_handling; /* 1 if in read_websocket */
2416#endif
2417 int handled_requests; /* Number of requests handled by this connection
2418 */
2419 int buf_size; /* Buffer size */
2420 int request_len; /* Size of the request + headers in a buffer */
2421 int data_len; /* Total size of data in a buffer */
2422 int status_code; /* HTTP reply status code, e.g. 200 */
2423 int throttle; /* Throttling, bytes/sec. <= 0 means no
2424 * throttle */
2425
7c673cae
FG
2426 time_t last_throttle_time; /* Last time throttled data was sent */
2427 int64_t last_throttle_bytes; /* Bytes sent this second */
2428 pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure
2429 * atomic transmissions for websockets */
2430#if defined(USE_LUA) && defined(USE_WEBSOCKET)
2431 void *lua_websocket_state; /* Lua_State for a websocket connection */
2432#endif
7c673cae 2433
11fdf7f2 2434 int thread_index; /* Thread index within ctx */
7c673cae
FG
2435};
2436
11fdf7f2 2437
7c673cae
FG
2438/* Directory entry */
2439struct de {
2440 struct mg_connection *conn;
2441 char *file_name;
11fdf7f2 2442 struct mg_file_stat file;
7c673cae
FG
2443};
2444
2445
2446#if defined(USE_WEBSOCKET)
2447static int is_websocket_protocol(const struct mg_connection *conn);
2448#else
2449#define is_websocket_protocol(conn) (0)
2450#endif
2451
2452
7c673cae
FG
2453#if !defined(NO_THREAD_NAME)
2454#if defined(_WIN32) && defined(_MSC_VER)
2455/* Set the thread name for debugging purposes in Visual Studio
2456 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
2457 */
2458#pragma pack(push, 8)
2459typedef struct tagTHREADNAME_INFO {
2460 DWORD dwType; /* Must be 0x1000. */
2461 LPCSTR szName; /* Pointer to name (in user addr space). */
2462 DWORD dwThreadID; /* Thread ID (-1=caller thread). */
2463 DWORD dwFlags; /* Reserved for future use, must be zero. */
2464} THREADNAME_INFO;
2465#pragma pack(pop)
11fdf7f2 2466
7c673cae 2467#elif defined(__linux__)
11fdf7f2 2468
7c673cae
FG
2469#include <sys/prctl.h>
2470#include <sys/sendfile.h>
11fdf7f2
TL
2471#ifdef ALTERNATIVE_QUEUE
2472#include <sys/eventfd.h>
2473#endif /* ALTERNATIVE_QUEUE */
2474
2475
2476#if defined(ALTERNATIVE_QUEUE)
2477
2478
2479#ifdef __clang__
2480#pragma clang diagnostic push
2481#pragma clang diagnostic ignored "-Wunreachable-code"
2482/* For every system, "(sizeof(int) == sizeof(void *))" is either always
2483 * true or always false. One of the two branches is unreachable in any case.
2484 * Unfortunately the C standard does not define a way to check this at
2485 * compile time, since the #if preprocessor conditions can not use the sizeof
2486 * operator as an argument. */
2487#endif
2488
2489#if defined(__GNUC__) || defined(__MINGW32__)
2490/* GCC does not realize one branch is unreachable, so it raises some
2491 * pointer cast warning within the unreachable branch.
2492 */
2493#pragma GCC diagnostic push
2494#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
2495#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
2496#endif
2497
2498
2499static void *
2500event_create(void)
2501{
2502 int evhdl = eventfd(0, EFD_CLOEXEC);
2503 int *ret;
2504
2505 if (evhdl == -1) {
2506 /* Linux uses -1 on error, Windows NULL. */
2507 /* However, Linux does not return 0 on success either. */
2508 return 0;
2509 }
2510 if (sizeof(int) == sizeof(void *)) {
2511 ret = (void *)evhdl;
2512 } else {
2513 ret = (int *)mg_malloc(sizeof(int));
2514 if (ret) {
2515 *ret = evhdl;
2516 } else {
2517 (void)close(evhdl);
2518 }
2519 }
2520
2521 return (void *)ret;
2522}
2523
2524
2525static int
2526event_wait(void *eventhdl)
2527{
2528 uint64_t u;
2529 int evhdl, s;
2530
2531 if (sizeof(int) == sizeof(void *)) {
2532 evhdl = (int)eventhdl;
2533 } else {
2534 if (!eventhdl) {
2535 /* error */
2536 return 0;
2537 }
2538 evhdl = *(int *)eventhdl;
2539 }
2540
2541 s = (int)read(evhdl, &u, sizeof(u));
2542 if (s != sizeof(uint64_t)) {
2543 /* error */
2544 return 0;
2545 }
2546 (void)u; /* the value is not required */
2547 return 1;
2548}
2549
2550
2551static int
2552event_signal(void *eventhdl)
2553{
2554 uint64_t u = 1;
2555 int evhdl, s;
2556
2557 if (sizeof(int) == sizeof(void *)) {
2558 evhdl = (int)eventhdl;
2559 } else {
2560 if (!eventhdl) {
2561 /* error */
2562 return 0;
2563 }
2564 evhdl = *(int *)eventhdl;
2565 }
2566
2567 s = (int)write(evhdl, &u, sizeof(u));
2568 if (s != sizeof(uint64_t)) {
2569 /* error */
2570 return 0;
2571 }
2572 return 1;
2573}
2574
2575
2576static void
2577event_destroy(void *eventhdl)
2578{
2579 int evhdl;
2580
2581 if (sizeof(int) == sizeof(void *)) {
2582 evhdl = (int)eventhdl;
2583 close(evhdl);
2584 } else {
2585 if (!eventhdl) {
2586 /* error */
2587 return;
2588 }
2589 evhdl = *(int *)eventhdl;
2590 close(evhdl);
2591 mg_free(eventhdl);
2592 }
2593}
2594
2595
2596#if defined(__GNUC__) || defined(__MINGW32__)
2597#pragma GCC diagnostic pop
2598#endif
2599
2600#ifdef __clang__
2601#pragma clang diagnostic pop
2602#endif
2603
2604#endif
2605
2606#endif
2607
2608
2609#if !defined(__linux__) && !defined(_WIN32) && defined(ALTERNATIVE_QUEUE)
2610
2611struct posix_event {
2612 pthread_mutex_t mutex;
2613 pthread_cond_t cond;
2614};
2615
2616
2617static void *
2618event_create(void)
2619{
2620 struct posix_event *ret = mg_malloc(sizeof(struct posix_event));
2621 if (ret == 0) {
2622 /* out of memory */
2623 return 0;
2624 }
2625 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) {
2626 /* pthread mutex not available */
2627 mg_free(ret);
2628 return 0;
2629 }
2630 if (0 != pthread_cond_init(&(ret->cond), NULL)) {
2631 /* pthread cond not available */
2632 pthread_mutex_destroy(&(ret->mutex));
2633 mg_free(ret);
2634 return 0;
2635 }
2636 return (void *)ret;
2637}
2638
2639
2640static int
2641event_wait(void *eventhdl)
2642{
2643 struct posix_event *ev = (struct posix_event *)eventhdl;
2644 pthread_mutex_lock(&(ev->mutex));
2645 pthread_cond_wait(&(ev->cond), &(ev->mutex));
2646 pthread_mutex_unlock(&(ev->mutex));
2647 return 1;
2648}
2649
2650
2651static int
2652event_signal(void *eventhdl)
2653{
2654 struct posix_event *ev = (struct posix_event *)eventhdl;
2655 pthread_mutex_lock(&(ev->mutex));
2656 pthread_cond_signal(&(ev->cond));
2657 pthread_mutex_unlock(&(ev->mutex));
2658 return 1;
2659}
2660
2661
2662static void
2663event_destroy(void *eventhdl)
2664{
2665 struct posix_event *ev = (struct posix_event *)eventhdl;
2666 pthread_cond_destroy(&(ev->cond));
2667 pthread_mutex_destroy(&(ev->mutex));
2668 mg_free(ev);
2669}
7c673cae
FG
2670#endif
2671
2672
2673static void
2674mg_set_thread_name(const char *name)
2675{
2676 char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
2677
2678 mg_snprintf(
2679 NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name);
2680
2681#if defined(_WIN32)
2682#if defined(_MSC_VER)
2683 /* Windows and Visual Studio Compiler */
2684 __try
2685 {
2686 THREADNAME_INFO info;
2687 info.dwType = 0x1000;
2688 info.szName = threadName;
2689 info.dwThreadID = ~0U;
2690 info.dwFlags = 0;
2691
2692 RaiseException(0x406D1388,
2693 0,
2694 sizeof(info) / sizeof(ULONG_PTR),
2695 (ULONG_PTR *)&info);
2696 }
2697 __except(EXCEPTION_EXECUTE_HANDLER)
2698 {
2699 }
2700#elif defined(__MINGW32__)
2701/* No option known to set thread name for MinGW */
2702#endif
2703#elif defined(__GLIBC__) \
2704 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
2705 /* pthread_setname_np first appeared in glibc in version 2.12*/
2706 (void)pthread_setname_np(pthread_self(), threadName);
2707#elif defined(__linux__)
2708 /* on linux we can use the old prctl function */
2709 (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
2710#endif
2711}
2712#else /* !defined(NO_THREAD_NAME) */
2713void
2714mg_set_thread_name(const char *threadName)
2715{
2716}
2717#endif
2718
2719
2720#if defined(MG_LEGACY_INTERFACE)
2721const char **
2722mg_get_valid_option_names(void)
2723{
2724 /* This function is deprecated. Use mg_get_valid_options instead. */
2725 static const char *
2726 data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0};
2727 int i;
2728
2729 for (i = 0; config_options[i].name != NULL; i++) {
2730 data[i * 2] = config_options[i].name;
2731 data[i * 2 + 1] = config_options[i].default_value;
2732 }
2733
2734 return data;
2735}
2736#endif
2737
2738
2739const struct mg_option *
2740mg_get_valid_options(void)
2741{
2742 return config_options;
2743}
2744
2745
11fdf7f2
TL
2746/* Do not open file (used in is_file_in_memory) */
2747#define MG_FOPEN_MODE_NONE (0)
2748
2749/* Open file for read only access */
2750#define MG_FOPEN_MODE_READ (1)
2751
2752/* Open file for writing, create and overwrite */
2753#define MG_FOPEN_MODE_WRITE (2)
2754
2755/* Open file for writing, create and append */
2756#define MG_FOPEN_MODE_APPEND (4)
2757
2758
2759/* If a file is in memory, set all "stat" members and the membuf pointer of
2760 * output filep and return 1, otherwise return 0 and don't modify anything.
2761 */
7c673cae 2762static int
11fdf7f2
TL
2763open_file_in_memory(const struct mg_connection *conn,
2764 const char *path,
2765 struct mg_file *filep,
2766 int mode)
7c673cae 2767{
11fdf7f2
TL
2768#if defined(MG_USE_OPEN_FILE)
2769
7c673cae 2770 size_t size = 0;
11fdf7f2
TL
2771 const char *buf = NULL;
2772 if (!conn) {
2773 return 0;
2774 }
2775
2776 if ((mode != MG_FOPEN_MODE_NONE) && (mode != MG_FOPEN_MODE_READ)) {
7c673cae
FG
2777 return 0;
2778 }
2779
2780 if (conn->ctx->callbacks.open_file) {
11fdf7f2
TL
2781 buf = conn->ctx->callbacks.open_file(conn, path, &size);
2782 if (buf != NULL) {
2783 if (filep == NULL) {
2784 /* This is a file in memory, but we cannot store the
2785 * properties
2786 * now.
2787 * Called from "is_file_in_memory" function. */
2788 return 1;
2789 }
2790
2791 /* NOTE: override filep->size only on success. Otherwise, it
2792 * might
7c673cae 2793 * break constructs like if (!mg_stat() || !mg_fopen()) ... */
11fdf7f2
TL
2794 filep->access.membuf = buf;
2795 filep->access.fp = NULL;
2796
2797 /* Size was set by the callback */
2798 filep->stat.size = size;
2799
2800 /* Assume the data may change during runtime by setting
2801 * last_modified = now */
2802 filep->stat.last_modified = time(NULL);
2803
2804 filep->stat.is_directory = 0;
2805 filep->stat.is_gzipped = 0;
7c673cae
FG
2806 }
2807 }
2808
11fdf7f2
TL
2809 return (buf != NULL);
2810
2811#else
2812 (void)conn;
2813 (void)path;
2814 (void)filep;
2815 (void)mode;
2816
2817 return 0;
2818
2819#endif
7c673cae
FG
2820}
2821
2822
2823static int
11fdf7f2 2824is_file_in_memory(const struct mg_connection *conn, const char *path)
7c673cae 2825{
11fdf7f2
TL
2826 return open_file_in_memory(conn, path, NULL, MG_FOPEN_MODE_NONE);
2827}
2828
2829
2830static int
2831is_file_opened(const struct mg_file_access *fileacc)
2832{
2833 if (!fileacc) {
7c673cae
FG
2834 return 0;
2835 }
11fdf7f2 2836 return (fileacc->membuf != NULL) || (fileacc->fp != NULL);
7c673cae
FG
2837}
2838
2839
11fdf7f2
TL
2840static int mg_stat(const struct mg_connection *conn,
2841 const char *path,
2842 struct mg_file_stat *filep);
2843
2844
7c673cae
FG
2845/* mg_fopen will open a file either in memory or on the disk.
2846 * The input parameter path is a string in UTF-8 encoding.
11fdf7f2
TL
2847 * The input parameter mode is MG_FOPEN_MODE_*
2848 * On success, either fp or membuf will be set in the output
2849 * struct file. All status members will also be set.
7c673cae
FG
2850 * The function returns 1 on success, 0 on error. */
2851static int
2852mg_fopen(const struct mg_connection *conn,
2853 const char *path,
11fdf7f2
TL
2854 int mode,
2855 struct mg_file *filep)
7c673cae 2856{
11fdf7f2 2857 int found;
7c673cae
FG
2858
2859 if (!filep) {
2860 return 0;
2861 }
11fdf7f2
TL
2862 filep->access.fp = NULL;
2863 filep->access.membuf = NULL;
7c673cae 2864
11fdf7f2 2865 if (!is_file_in_memory(conn, path)) {
7c673cae 2866
11fdf7f2
TL
2867 /* filep is initialized in mg_stat: all fields with memset to,
2868 * some fields like size and modification date with values */
2869 found = mg_stat(conn, path, &(filep->stat));
2870
2871 if ((mode == MG_FOPEN_MODE_READ) && (!found)) {
2872 /* file does not exist and will not be created */
2873 return 0;
2874 }
7c673cae 2875
7c673cae 2876#ifdef _WIN32
11fdf7f2
TL
2877 {
2878 wchar_t wbuf[PATH_MAX];
2879 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
2880 switch (mode) {
2881 case MG_FOPEN_MODE_READ:
2882 filep->access.fp = _wfopen(wbuf, L"rb");
2883 break;
2884 case MG_FOPEN_MODE_WRITE:
2885 filep->access.fp = _wfopen(wbuf, L"wb");
2886 break;
2887 case MG_FOPEN_MODE_APPEND:
2888 filep->access.fp = _wfopen(wbuf, L"ab");
2889 break;
2890 }
2891 }
7c673cae
FG
2892#else
2893 /* Linux et al already use unicode. No need to convert. */
11fdf7f2
TL
2894 switch (mode) {
2895 case MG_FOPEN_MODE_READ:
2896 filep->access.fp = fopen(path, "r");
2897 break;
2898 case MG_FOPEN_MODE_WRITE:
2899 filep->access.fp = fopen(path, "w");
2900 break;
2901 case MG_FOPEN_MODE_APPEND:
2902 filep->access.fp = fopen(path, "a");
2903 break;
2904 }
2905
7c673cae 2906#endif
11fdf7f2
TL
2907 if (!found) {
2908 /* File did not exist before fopen was called.
2909 * Maybe it has been created now. Get stat info
2910 * like creation time now. */
2911 found = mg_stat(conn, path, &(filep->stat));
2912 (void)found;
2913 }
2914
2915 /* file is on disk */
2916 return (filep->access.fp != NULL);
2917
2918 } else {
2919 /* is_file_in_memory returned true */
2920 if (open_file_in_memory(conn, path, filep, mode)) {
2921 /* file is in memory */
2922 return (filep->access.membuf != NULL);
2923 }
7c673cae
FG
2924 }
2925
11fdf7f2
TL
2926 /* Open failed */
2927 return 0;
7c673cae
FG
2928}
2929
2930
11fdf7f2
TL
2931/* return 0 on success, just like fclose */
2932static int
2933mg_fclose(struct mg_file_access *fileacc)
7c673cae 2934{
11fdf7f2
TL
2935 int ret = -1;
2936 if (fileacc != NULL) {
2937 if (fileacc->fp != NULL) {
2938 ret = fclose(fileacc->fp);
2939 } else if (fileacc->membuf != NULL) {
2940 ret = 0;
2941 }
2942 /* reset all members of fileacc */
2943 memset(fileacc, 0, sizeof(*fileacc));
7c673cae 2944 }
11fdf7f2 2945 return ret;
7c673cae
FG
2946}
2947
2948
2949static void
2950mg_strlcpy(register char *dst, register const char *src, size_t n)
2951{
2952 for (; *src != '\0' && n > 1; n--) {
2953 *dst++ = *src++;
2954 }
2955 *dst = '\0';
2956}
2957
2958
2959static int
2960lowercase(const char *s)
2961{
2962 return tolower(*(const unsigned char *)s);
2963}
2964
2965
2966int
2967mg_strncasecmp(const char *s1, const char *s2, size_t len)
2968{
2969 int diff = 0;
2970
2971 if (len > 0) {
2972 do {
2973 diff = lowercase(s1++) - lowercase(s2++);
2974 } while (diff == 0 && s1[-1] != '\0' && --len > 0);
2975 }
2976
2977 return diff;
2978}
2979
2980
2981int
2982mg_strcasecmp(const char *s1, const char *s2)
2983{
2984 int diff;
2985
2986 do {
2987 diff = lowercase(s1++) - lowercase(s2++);
2988 } while (diff == 0 && s1[-1] != '\0');
2989
2990 return diff;
2991}
2992
2993
2994static char *
2995mg_strndup(const char *ptr, size_t len)
2996{
2997 char *p;
2998
2999 if ((p = (char *)mg_malloc(len + 1)) != NULL) {
3000 mg_strlcpy(p, ptr, len + 1);
3001 }
3002
3003 return p;
3004}
3005
3006
3007static char *
3008mg_strdup(const char *str)
3009{
3010 return mg_strndup(str, strlen(str));
3011}
3012
3013
3014static const char *
3015mg_strcasestr(const char *big_str, const char *small_str)
3016{
3017 size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
3018
3019 if (big_len >= small_len) {
3020 for (i = 0; i <= (big_len - small_len); i++) {
3021 if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
3022 return big_str + i;
3023 }
3024 }
3025 }
3026
3027 return NULL;
3028}
3029
3030
3031/* Return null terminated string of given maximum length.
3032 * Report errors if length is exceeded. */
3033static void
3034mg_vsnprintf(const struct mg_connection *conn,
3035 int *truncated,
3036 char *buf,
3037 size_t buflen,
3038 const char *fmt,
3039 va_list ap)
3040{
3041 int n, ok;
3042
3043 if (buflen == 0) {
11fdf7f2
TL
3044 if (truncated) {
3045 *truncated = 1;
3046 }
7c673cae
FG
3047 return;
3048 }
3049
3050#ifdef __clang__
3051#pragma clang diagnostic push
3052#pragma clang diagnostic ignored "-Wformat-nonliteral"
3053/* Using fmt as a non-literal is intended here, since it is mostly called
3054 * indirectly by mg_snprintf */
3055#endif
3056
3057 n = (int)vsnprintf_impl(buf, buflen, fmt, ap);
3058 ok = (n >= 0) && ((size_t)n < buflen);
3059
3060#ifdef __clang__
3061#pragma clang diagnostic pop
3062#endif
3063
3064 if (ok) {
3065 if (truncated) {
3066 *truncated = 0;
3067 }
3068 } else {
3069 if (truncated) {
3070 *truncated = 1;
3071 }
3072 mg_cry(conn,
3073 "truncating vsnprintf buffer: [%.*s]",
3074 (int)((buflen > 200) ? 200 : (buflen - 1)),
3075 buf);
3076 n = (int)buflen - 1;
3077 }
3078 buf[n] = '\0';
3079}
3080
3081
3082static void
3083mg_snprintf(const struct mg_connection *conn,
3084 int *truncated,
3085 char *buf,
3086 size_t buflen,
3087 const char *fmt,
3088 ...)
3089{
3090 va_list ap;
3091
3092 va_start(ap, fmt);
3093 mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap);
3094 va_end(ap);
3095}
3096
3097
3098static int
3099get_option_index(const char *name)
3100{
3101 int i;
3102
3103 for (i = 0; config_options[i].name != NULL; i++) {
3104 if (strcmp(config_options[i].name, name) == 0) {
3105 return i;
3106 }
3107 }
3108 return -1;
3109}
3110
3111
3112const char *
3113mg_get_option(const struct mg_context *ctx, const char *name)
3114{
3115 int i;
3116 if ((i = get_option_index(name)) == -1) {
3117 return NULL;
3118 } else if (!ctx || ctx->config[i] == NULL) {
3119 return "";
3120 } else {
3121 return ctx->config[i];
3122 }
3123}
3124
3125
3126struct mg_context *
3127mg_get_context(const struct mg_connection *conn)
3128{
3129 return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
3130}
3131
3132
3133void *
3134mg_get_user_data(const struct mg_context *ctx)
3135{
3136 return (ctx == NULL) ? NULL : ctx->user_data;
3137}
3138
3139
3140void
3141mg_set_user_connection_data(struct mg_connection *conn, void *data)
3142{
3143 if (conn != NULL) {
3144 conn->request_info.conn_data = data;
3145 }
3146}
3147
3148
3149void *
3150mg_get_user_connection_data(const struct mg_connection *conn)
3151{
3152 if (conn != NULL) {
3153 return conn->request_info.conn_data;
3154 }
3155 return NULL;
3156}
3157
3158
11fdf7f2
TL
3159#if defined(MG_LEGACY_INTERFACE)
3160/* Deprecated: Use mg_get_server_ports instead. */
7c673cae
FG
3161size_t
3162mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
3163{
3164 size_t i;
3165 if (!ctx) {
3166 return 0;
3167 }
3168 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
3169 ssl[i] = ctx->listening_sockets[i].is_ssl;
11fdf7f2
TL
3170 ports[i] =
3171#if defined(USE_IPV6)
3172 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3173 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3174 :
3175#endif
3176 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
7c673cae
FG
3177 }
3178 return i;
3179}
11fdf7f2 3180#endif
7c673cae
FG
3181
3182
3183int
3184mg_get_server_ports(const struct mg_context *ctx,
3185 int size,
3186 struct mg_server_ports *ports)
3187{
3188 int i, cnt = 0;
3189
3190 if (size <= 0) {
3191 return -1;
3192 }
3193 memset(ports, 0, sizeof(*ports) * (size_t)size);
3194 if (!ctx) {
3195 return -1;
3196 }
11fdf7f2 3197 if (!ctx->listening_sockets) {
7c673cae
FG
3198 return -1;
3199 }
3200
3201 for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) {
3202
11fdf7f2
TL
3203 ports[cnt].port =
3204#if defined(USE_IPV6)
3205 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6)
3206 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port)
3207 :
3208#endif
3209 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port);
7c673cae
FG
3210 ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
3211 ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
3212
3213 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
3214 /* IPv4 */
3215 ports[cnt].protocol = 1;
3216 cnt++;
3217 } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
3218 /* IPv6 */
3219 ports[cnt].protocol = 3;
3220 cnt++;
3221 }
3222 }
3223
3224 return cnt;
3225}
3226
3227
3228static void
3229sockaddr_to_string(char *buf, size_t len, const union usa *usa)
3230{
3231 buf[0] = '\0';
3232
3233 if (!usa) {
3234 return;
3235 }
3236
3237 if (usa->sa.sa_family == AF_INET) {
3238 getnameinfo(&usa->sa,
3239 sizeof(usa->sin),
3240 buf,
3241 (unsigned)len,
3242 NULL,
3243 0,
3244 NI_NUMERICHOST);
3245 }
3246#if defined(USE_IPV6)
3247 else if (usa->sa.sa_family == AF_INET6) {
3248 getnameinfo(&usa->sa,
3249 sizeof(usa->sin6),
3250 buf,
3251 (unsigned)len,
3252 NULL,
3253 0,
3254 NI_NUMERICHOST);
3255 }
3256#endif
3257}
3258
3259
3260/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
3261 * included in all responses other than 100, 101, 5xx. */
3262static void
3263gmt_time_string(char *buf, size_t buf_len, time_t *t)
3264{
3265 struct tm *tm;
3266
3267 tm = ((t != NULL) ? gmtime(t) : NULL);
3268 if (tm != NULL) {
3269 strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
3270 } else {
3271 mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
3272 buf[buf_len - 1] = '\0';
3273 }
3274}
3275
3276
3277/* difftime for struct timespec. Return value is in seconds. */
3278static double
3279mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
3280{
3281 return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3282 + (double)(ts_now->tv_sec - ts_before->tv_sec);
3283}
3284
3285
3286/* Print error message to the opened error log stream. */
3287void
3288mg_cry(const struct mg_connection *conn, const char *fmt, ...)
3289{
3290 char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
3291 va_list ap;
11fdf7f2 3292 struct mg_file fi;
7c673cae
FG
3293 time_t timestamp;
3294
3295 va_start(ap, fmt);
3296 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
3297 va_end(ap);
3298 buf[sizeof(buf) - 1] = 0;
3299
11fdf7f2
TL
3300 DEBUG_TRACE("mg_cry: %s", buf);
3301
7c673cae
FG
3302 if (!conn) {
3303 puts(buf);
3304 return;
3305 }
3306
3307 /* Do not lock when getting the callback value, here and below.
3308 * I suppose this is fine, since function cannot disappear in the
3309 * same way string option can. */
3310 if ((conn->ctx->callbacks.log_message == NULL)
3311 || (conn->ctx->callbacks.log_message(conn, buf) == 0)) {
3312
3313 if (conn->ctx->config[ERROR_LOG_FILE] != NULL) {
11fdf7f2
TL
3314 if (mg_fopen(conn,
3315 conn->ctx->config[ERROR_LOG_FILE],
3316 MG_FOPEN_MODE_APPEND,
3317 &fi) == 0) {
3318 fi.access.fp = NULL;
7c673cae
FG
3319 }
3320 } else {
11fdf7f2 3321 fi.access.fp = NULL;
7c673cae
FG
3322 }
3323
11fdf7f2
TL
3324 if (fi.access.fp != NULL) {
3325 flockfile(fi.access.fp);
7c673cae
FG
3326 timestamp = time(NULL);
3327
3328 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
11fdf7f2 3329 fprintf(fi.access.fp,
7c673cae
FG
3330 "[%010lu] [error] [client %s] ",
3331 (unsigned long)timestamp,
3332 src_addr);
3333
3334 if (conn->request_info.request_method != NULL) {
11fdf7f2 3335 fprintf(fi.access.fp,
7c673cae
FG
3336 "%s %s: ",
3337 conn->request_info.request_method,
11fdf7f2
TL
3338 conn->request_info.request_uri
3339 ? conn->request_info.request_uri
3340 : "");
7c673cae
FG
3341 }
3342
11fdf7f2
TL
3343 fprintf(fi.access.fp, "%s", buf);
3344 fputc('\n', fi.access.fp);
3345 fflush(fi.access.fp);
3346 funlockfile(fi.access.fp);
3347 (void)mg_fclose(&fi.access); /* Ignore errors. We can't call
3348 * mg_cry here anyway ;-) */
7c673cae
FG
3349 }
3350 }
3351}
3352
3353void
3354mg_set_http_status(struct mg_connection *conn, int status)
3355{
11fdf7f2 3356 conn->status_code = status;
7c673cae
FG
3357}
3358
3359/* Return fake connection structure. Used for logging, if connection
3360 * is not applicable at the moment of logging. */
3361static struct mg_connection *
3362fc(struct mg_context *ctx)
3363{
3364 static struct mg_connection fake_connection;
3365 fake_connection.ctx = ctx;
3366 return &fake_connection;
3367}
3368
3369
3370const char *
3371mg_version(void)
3372{
3373 return CIVETWEB_VERSION;
3374}
3375
3376
3377const struct mg_request_info *
3378mg_get_request_info(const struct mg_connection *conn)
3379{
3380 if (!conn) {
3381 return NULL;
3382 }
11fdf7f2
TL
3383#if 1 /* TODO: deal with legacy */
3384 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
3385 static char txt[16];
3386 sprintf(txt, "%03i", conn->response_info.status_code);
3387
3388 ((struct mg_connection *)conn)->request_info.local_uri =
3389 ((struct mg_connection *)conn)->request_info.request_uri =
3390 txt; /* TODO: not thread safe */
3391
3392 ((struct mg_connection *)conn)->request_info.num_headers =
3393 conn->response_info.num_headers;
3394 memcpy(((struct mg_connection *)conn)->request_info.http_headers,
3395 conn->response_info.http_headers,
3396 sizeof(conn->response_info.http_headers));
3397 } else
3398#endif
3399 if (conn->connection_type != CONNECTION_TYPE_REQUEST) {
3400 return NULL;
3401 }
7c673cae
FG
3402 return &conn->request_info;
3403}
3404
3405
11fdf7f2
TL
3406const struct mg_response_info *
3407mg_get_response_info(const struct mg_connection *conn)
3408{
3409 if (!conn) {
3410 return NULL;
3411 }
3412 if (conn->connection_type != CONNECTION_TYPE_RESPONSE) {
3413 return NULL;
3414 }
3415 return &conn->response_info;
3416}
3417
3418
3419static const char *
3420get_proto_name(const struct mg_connection *conn)
3421{
3422#ifdef __clang__
3423#pragma clang diagnostic push
3424#pragma clang diagnostic ignored "-Wunreachable-code"
3425/* Depending on USE_WEBSOCKET and NO_SSL, some oft the protocols might be
3426 * not supported. Clang raises an "unreachable code" warning for parts of ?:
3427 * unreachable, but splitting into four different #ifdef clauses here is more
3428 * complicated.
3429 */
3430#endif
3431
3432 const struct mg_request_info *ri = &conn->request_info;
3433
3434 const char *proto =
3435 (is_websocket_protocol(conn) ? (ri->is_ssl ? "wss" : "ws")
3436 : (ri->is_ssl ? "https" : "http"));
3437
3438 return proto;
3439
3440#ifdef __clang__
3441#pragma clang diagnostic pop
3442#endif
3443}
3444
3445
3446int
3447mg_get_request_link(const struct mg_connection *conn, char *buf, size_t buflen)
3448{
3449 if ((buflen < 1) || (buf == 0) || (conn == 0)) {
3450 return -1;
3451 } else {
3452
3453 int truncated = 0;
3454 const struct mg_request_info *ri = &conn->request_info;
3455
3456 const char *proto = get_proto_name(conn);
3457
3458 if (ri->local_uri == NULL) {
3459 return -1;
3460 }
3461
3462 if ((ri->request_uri != NULL)
3463 && strcmp(ri->local_uri, ri->request_uri)) {
3464 mg_snprintf(conn,
3465 &truncated,
3466 buf,
3467 buflen,
3468 "%s://%s",
3469 proto,
3470 ri->request_uri);
3471 if (truncated) {
3472 return -1;
3473 }
3474 return 0;
3475 } else {
3476
3477#if defined(USE_IPV6)
3478 int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6);
3479 int port = is_ipv6 ? htons(conn->client.lsa.sin6.sin6_port)
3480 : htons(conn->client.lsa.sin.sin_port);
3481#else
3482 int port = htons(conn->client.lsa.sin.sin_port);
3483#endif
3484 int def_port = ri->is_ssl ? 443 : 80;
3485 int auth_domain_check_enabled =
3486 conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK]
3487 && (!mg_strcasecmp(conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK],
3488 "yes"));
3489 const char *server_domain =
3490 conn->ctx->config[AUTHENTICATION_DOMAIN];
3491
3492 char portstr[16];
3493 char server_ip[48];
3494
3495 if (port != def_port) {
3496 sprintf(portstr, ":%u", (unsigned)port);
3497 } else {
3498 portstr[0] = 0;
3499 }
3500
3501 if (!auth_domain_check_enabled || !server_domain) {
3502
3503 sockaddr_to_string(server_ip,
3504 sizeof(server_ip),
3505 &conn->client.lsa);
3506
3507 server_domain = server_ip;
3508 }
3509
3510 mg_snprintf(conn,
3511 &truncated,
3512 buf,
3513 buflen,
3514 "%s://%s%s%s",
3515 proto,
3516 server_domain,
3517 portstr,
3518 ri->local_uri);
3519 if (truncated) {
3520 return -1;
3521 }
3522 return 0;
3523 }
3524 }
3525}
3526
7c673cae
FG
3527struct sockaddr *
3528mg_get_local_addr(struct mg_connection *conn)
3529{
3530 return &conn->client.lsa.sa;
3531}
3532
3533
3534/* Skip the characters until one of the delimiters characters found.
3535 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
11fdf7f2
TL
3536 * Advance pointer to buffer to the next word. Return found 0-terminated
3537 * word.
7c673cae
FG
3538 * Delimiters can be quoted with quotechar. */
3539static char *
3540skip_quoted(char **buf,
3541 const char *delimiters,
3542 const char *whitespace,
3543 char quotechar)
3544{
3545 char *p, *begin_word, *end_word, *end_whitespace;
3546
3547 begin_word = *buf;
3548 end_word = begin_word + strcspn(begin_word, delimiters);
3549
3550 /* Check for quotechar */
3551 if (end_word > begin_word) {
3552 p = end_word - 1;
3553 while (*p == quotechar) {
11fdf7f2
TL
3554 /* While the delimiter is quoted, look for the next delimiter.
3555 */
7c673cae
FG
3556 /* This happens, e.g., in calls from parse_auth_header,
3557 * if the user name contains a " character. */
3558
3559 /* If there is anything beyond end_word, copy it. */
3560 if (*end_word != '\0') {
3561 size_t end_off = strcspn(end_word + 1, delimiters);
3562 memmove(p, end_word, end_off + 1);
3563 p += end_off; /* p must correspond to end_word - 1 */
3564 end_word += end_off + 1;
3565 } else {
3566 *p = '\0';
3567 break;
3568 }
3569 }
3570 for (p++; p < end_word; p++) {
3571 *p = '\0';
3572 }
3573 }
3574
3575 if (*end_word == '\0') {
3576 *buf = end_word;
3577 } else {
11fdf7f2
TL
3578
3579#if defined(__GNUC__) || defined(__MINGW32__)
3580/* Disable spurious conversion warning for GCC */
3581#if GCC_VERSION >= 40500
3582#pragma GCC diagnostic push
3583#pragma GCC diagnostic ignored "-Wsign-conversion"
3584#endif /* GCC_VERSION >= 40500 */
3585#endif /* defined(__GNUC__) || defined(__MINGW32__) */
3586
3587 end_whitespace = end_word + strspn(&end_word[1], whitespace) + 1;
3588
3589#if defined(__GNUC__) || defined(__MINGW32__)
3590#if GCC_VERSION >= 40500
3591#pragma GCC diagnostic pop
3592#endif /* GCC_VERSION >= 40500 */
3593#endif /* defined(__GNUC__) || defined(__MINGW32__) */
7c673cae
FG
3594
3595 for (p = end_word; p < end_whitespace; p++) {
3596 *p = '\0';
3597 }
3598
3599 *buf = end_whitespace;
3600 }
3601
3602 return begin_word;
3603}
3604
3605
11fdf7f2
TL
3606/* Return HTTP header value, or NULL if not found. */
3607static const char *
3608get_header(const struct mg_header *hdr, int num_hdr, const char *name)
7c673cae 3609{
11fdf7f2
TL
3610 int i;
3611 for (i = 0; i < num_hdr; i++) {
3612 if (!mg_strcasecmp(name, hdr[i].name)) {
3613 return hdr[i].value;
3614 }
3615 }
3616
3617 return NULL;
7c673cae
FG
3618}
3619
3620
11fdf7f2
TL
3621#if defined(USE_WEBSOCKET)
3622/* Retrieve requested HTTP header multiple values, and return the number of
3623 * found occurences */
3624static int
3625get_req_headers(const struct mg_request_info *ri,
3626 const char *name,
3627 const char **output,
3628 int output_max_size)
7c673cae
FG
3629{
3630 int i;
11fdf7f2 3631 int cnt = 0;
7c673cae 3632 if (ri) {
11fdf7f2 3633 for (i = 0; i < ri->num_headers && cnt < output_max_size; i++) {
7c673cae 3634 if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
11fdf7f2 3635 output[cnt++] = ri->http_headers[i].value;
7c673cae
FG
3636 }
3637 }
3638 }
11fdf7f2 3639 return cnt;
7c673cae 3640}
11fdf7f2 3641#endif
7c673cae
FG
3642
3643
3644const char *
3645mg_get_header(const struct mg_connection *conn, const char *name)
3646{
3647 if (!conn) {
3648 return NULL;
3649 }
3650
11fdf7f2
TL
3651 if (conn->connection_type == CONNECTION_TYPE_REQUEST) {
3652 return get_header(conn->request_info.http_headers,
3653 conn->request_info.num_headers,
3654 name);
3655 }
3656 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
3657 return get_header(conn->response_info.http_headers,
3658 conn->request_info.num_headers,
3659 name);
3660 }
3661 return NULL;
3662}
3663
3664
3665static const char *
3666get_http_version(const struct mg_connection *conn)
3667{
3668 if (!conn) {
3669 return NULL;
3670 }
3671
3672 if (conn->connection_type == CONNECTION_TYPE_REQUEST) {
3673 return conn->request_info.http_version;
3674 }
3675 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
3676 return conn->response_info.http_version;
3677 }
3678 return NULL;
7c673cae
FG
3679}
3680
3681
3682/* A helper function for traversing a comma separated list of values.
3683 * It returns a list pointer shifted to the next value, or NULL if the end
3684 * of the list found.
3685 * Value is stored in val vector. If value has form "x=y", then eq_val
3686 * vector is initialized to point to the "y" part, and val vector length
3687 * is adjusted to point only to "x". */
3688static const char *
3689next_option(const char *list, struct vec *val, struct vec *eq_val)
3690{
3691 int end;
3692
3693reparse:
3694 if (val == NULL || list == NULL || *list == '\0') {
3695 /* End of the list */
11fdf7f2
TL
3696 return NULL;
3697 }
3698
3699 /* Skip over leading LWS */
3700 while (*list == ' ' || *list == '\t')
3701 list++;
3702
3703 val->ptr = list;
3704 if ((list = strchr(val->ptr, ',')) != NULL) {
3705 /* Comma found. Store length and shift the list ptr */
3706 val->len = ((size_t)(list - val->ptr));
3707 list++;
7c673cae 3708 } else {
11fdf7f2
TL
3709 /* This value is the last one */
3710 list = val->ptr + strlen(val->ptr);
3711 val->len = ((size_t)(list - val->ptr));
3712 }
7c673cae 3713
11fdf7f2
TL
3714 /* Adjust length for trailing LWS */
3715 end = (int)val->len - 1;
3716 while (end >= 0 && ((val->ptr[end] == ' ') || (val->ptr[end] == '\t')))
3717 end--;
3718 val->len = (size_t)(end + 1);
7c673cae 3719
11fdf7f2
TL
3720 if (val->len == 0) {
3721 /* Ignore any empty entries. */
3722 goto reparse;
3723 }
7c673cae 3724
11fdf7f2
TL
3725 if (eq_val != NULL) {
3726 /* Value has form "x=y", adjust pointers and lengths
3727 * so that val points to "x", and eq_val points to "y". */
3728 eq_val->len = 0;
3729 eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len);
3730 if (eq_val->ptr != NULL) {
3731 eq_val->ptr++; /* Skip over '=' character */
3732 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
3733 val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1;
7c673cae
FG
3734 }
3735 }
3736
3737 return list;
3738}
3739
11fdf7f2
TL
3740
3741/* A helper function for checking if a comma separated list of values
3742 * contains
7c673cae
FG
3743 * the given option (case insensitvely).
3744 * 'header' can be NULL, in which case false is returned. */
3745static int
3746header_has_option(const char *header, const char *option)
3747{
3748 struct vec opt_vec;
3749 struct vec eq_vec;
3750
11fdf7f2 3751 /*
7c673cae
FG
3752 assert(option != NULL);
3753 assert(option[0] != '\0');
11fdf7f2 3754 */
7c673cae
FG
3755
3756 while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) {
3757 if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0)
3758 return 1;
3759 }
3760
3761 return 0;
3762}
3763
11fdf7f2 3764
7c673cae
FG
3765/* Perform case-insensitive match of string against pattern */
3766static int
3767match_prefix(const char *pattern, size_t pattern_len, const char *str)
3768{
3769 const char *or_str;
3770 size_t i;
3771 int j, len, res;
3772
3773 if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) {
3774 res = match_prefix(pattern, (size_t)(or_str - pattern), str);
11fdf7f2
TL
3775 return (res > 0) ? res : match_prefix(or_str + 1,
3776 (size_t)((pattern + pattern_len)
3777 - (or_str + 1)),
3778 str);
7c673cae
FG
3779 }
3780
11fdf7f2
TL
3781 for (i = 0, j = 0; (i < pattern_len); i++, j++) {
3782 if ((pattern[i] == '?') && (str[j] != '\0')) {
7c673cae
FG
3783 continue;
3784 } else if (pattern[i] == '$') {
11fdf7f2 3785 return (str[j] == '\0') ? j : -1;
7c673cae
FG
3786 } else if (pattern[i] == '*') {
3787 i++;
3788 if (pattern[i] == '*') {
3789 i++;
3790 len = (int)strlen(str + j);
3791 } else {
3792 len = (int)strcspn(str + j, "/");
3793 }
3794 if (i == pattern_len) {
3795 return j + len;
3796 }
3797 do {
3798 res = match_prefix(pattern + i, pattern_len - i, str + j + len);
3799 } while (res == -1 && len-- > 0);
11fdf7f2 3800 return (res == -1) ? -1 : j + res + len;
7c673cae
FG
3801 } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
3802 return -1;
3803 }
3804 }
3805 return j;
3806}
3807
3808
3809/* HTTP 1.1 assumes keep alive if "Connection:" header is not set
3810 * This function must tolerate situations when connection info is not
3811 * set up, for example if request parsing failed. */
3812static int
3813should_keep_alive(const struct mg_connection *conn)
3814{
11fdf7f2
TL
3815 const char *http_version;
3816 const char *header;
3817
3818 /* First satisfy needs of the server */
3819 if ((conn == NULL) || conn->must_close) {
3820 /* Close, if civetweb framework needs to close */
3821 return 0;
3822 }
3823
3824 if (mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0) {
3825 /* Close, if keep alive is not enabled */
3826 return 0;
3827 }
3828
3829 /* Check explicit wish of the client */
3830 header = mg_get_header(conn, "Connection");
3831 if (header) {
3832 /* If there is a connection header from the client, obey */
3833 if (header_has_option(header, "keep-alive")) {
3834 return 1;
7c673cae 3835 }
11fdf7f2
TL
3836 return 0;
3837 }
3838
3839 /* Use default of the standard */
3840 http_version = get_http_version(conn);
3841 if (http_version && (0 == strcmp(http_version, "1.1"))) {
3842 /* HTTP 1.1 default is keep alive */
7c673cae
FG
3843 return 1;
3844 }
11fdf7f2
TL
3845
3846 /* HTTP 1.0 (and earlier) default is to close the connection */
7c673cae
FG
3847 return 0;
3848}
3849
3850
3851static int
3852should_decode_url(const struct mg_connection *conn)
3853{
3854 if (!conn || !conn->ctx) {
3855 return 0;
3856 }
3857
3858 return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0);
3859}
3860
7c673cae
FG
3861
3862static const char *
3863suggest_connection_header(const struct mg_connection *conn)
3864{
3865 return should_keep_alive(conn) ? "keep-alive" : "close";
3866}
3867
3868
3869static int
3870send_no_cache_header(struct mg_connection *conn)
3871{
3872 /* Send all current and obsolete cache opt-out directives. */
3873 return mg_printf(conn,
3874 "Cache-Control: no-cache, no-store, "
3875 "must-revalidate, private, max-age=0\r\n"
3876 "Pragma: no-cache\r\n"
3877 "Expires: 0\r\n");
3878}
3879
3880
3881static int
3882send_static_cache_header(struct mg_connection *conn)
3883{
3884#if !defined(NO_CACHING)
3885 /* Read the server config to check how long a file may be cached.
3886 * The configuration is in seconds. */
3887 int max_age = atoi(conn->ctx->config[STATIC_FILE_MAX_AGE]);
3888 if (max_age <= 0) {
3889 /* 0 means "do not cache". All values <0 are reserved
3890 * and may be used differently in the future. */
3891 /* If a file should not be cached, do not only send
3892 * max-age=0, but also pragmas and Expires headers. */
3893 return send_no_cache_header(conn);
3894 }
3895
3896 /* Use "Cache-Control: max-age" instead of "Expires" header.
3897 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
3898 /* See also https://www.mnot.net/cache_docs/ */
3899 /* According to RFC 2616, Section 14.21, caching times should not exceed
11fdf7f2
TL
3900 * one year. A year with 365 days corresponds to 31536000 seconds, a
3901 * leap
7c673cae
FG
3902 * year to 31622400 seconds. For the moment, we just send whatever has
3903 * been configured, still the behavior for >1 year should be considered
3904 * as undefined. */
3905 return mg_printf(conn, "Cache-Control: max-age=%u\r\n", (unsigned)max_age);
3906#else /* NO_CACHING */
3907 return send_no_cache_header(conn);
3908#endif /* !NO_CACHING */
3909}
3910
3911
11fdf7f2
TL
3912static int
3913send_additional_header(struct mg_connection *conn)
3914{
3915 int i = 0;
3916 const char *header = conn->ctx->config[ADDITIONAL_HEADER];
3917
3918#if !defined(NO_SSL)
3919 if (conn->ctx->config[STRICT_HTTPS_MAX_AGE]) {
3920 int max_age = atoi(conn->ctx->config[STRICT_HTTPS_MAX_AGE]);
3921 if (max_age >= 0) {
3922 i += mg_printf(conn,
3923 "Strict-Transport-Security: max-age=%u\r\n",
3924 (unsigned)max_age);
3925 }
3926 }
3927#endif
3928
3929 if (header && header[0]) {
3930 i += mg_printf(conn, "%s\r\n", header);
3931 }
3932
3933 return i;
3934}
3935
3936
7c673cae
FG
3937static void handle_file_based_request(struct mg_connection *conn,
3938 const char *path,
11fdf7f2 3939 struct mg_file *filep);
7c673cae
FG
3940
3941
3942const char *
11fdf7f2 3943mg_get_response_code_text(const struct mg_connection *conn, int response_code)
7c673cae
FG
3944{
3945 /* See IANA HTTP status code assignment:
3946 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
3947 */
3948
3949 switch (response_code) {
3950 /* RFC2616 Section 10.1 - Informational 1xx */
3951 case 100:
3952 return "Continue"; /* RFC2616 Section 10.1.1 */
3953 case 101:
3954 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
3955 case 102:
3956 return "Processing"; /* RFC2518 Section 10.1 */
3957
3958 /* RFC2616 Section 10.2 - Successful 2xx */
3959 case 200:
3960 return "OK"; /* RFC2616 Section 10.2.1 */
3961 case 201:
3962 return "Created"; /* RFC2616 Section 10.2.2 */
3963 case 202:
3964 return "Accepted"; /* RFC2616 Section 10.2.3 */
3965 case 203:
3966 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
3967 case 204:
3968 return "No Content"; /* RFC2616 Section 10.2.5 */
3969 case 205:
3970 return "Reset Content"; /* RFC2616 Section 10.2.6 */
3971 case 206:
3972 return "Partial Content"; /* RFC2616 Section 10.2.7 */
3973 case 207:
11fdf7f2
TL
3974 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1
3975 */
7c673cae
FG
3976 case 208:
3977 return "Already Reported"; /* RFC5842 Section 7.1 */
3978
3979 case 226:
3980 return "IM used"; /* RFC3229 Section 10.4.1 */
3981
3982 /* RFC2616 Section 10.3 - Redirection 3xx */
3983 case 300:
3984 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
3985 case 301:
3986 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
3987 case 302:
3988 return "Found"; /* RFC2616 Section 10.3.3 */
3989 case 303:
3990 return "See Other"; /* RFC2616 Section 10.3.4 */
3991 case 304:
3992 return "Not Modified"; /* RFC2616 Section 10.3.5 */
3993 case 305:
3994 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
3995 case 307:
3996 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
3997 case 308:
3998 return "Permanent Redirect"; /* RFC7238 Section 3 */
3999
4000 /* RFC2616 Section 10.4 - Client Error 4xx */
4001 case 400:
4002 return "Bad Request"; /* RFC2616 Section 10.4.1 */
4003 case 401:
4004 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
4005 case 402:
4006 return "Payment Required"; /* RFC2616 Section 10.4.3 */
4007 case 403:
4008 return "Forbidden"; /* RFC2616 Section 10.4.4 */
4009 case 404:
4010 return "Not Found"; /* RFC2616 Section 10.4.5 */
4011 case 405:
4012 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
4013 case 406:
4014 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
4015 case 407:
4016 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
4017 case 408:
4018 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
4019 case 409:
4020 return "Conflict"; /* RFC2616 Section 10.4.10 */
4021 case 410:
4022 return "Gone"; /* RFC2616 Section 10.4.11 */
4023 case 411:
4024 return "Length Required"; /* RFC2616 Section 10.4.12 */
4025 case 412:
4026 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
4027 case 413:
4028 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
4029 case 414:
4030 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
4031 case 415:
4032 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
4033 case 416:
11fdf7f2
TL
4034 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17
4035 */
7c673cae
FG
4036 case 417:
4037 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
4038
4039 case 421:
4040 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
4041 case 422:
4042 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
4043 * Section 11.2 */
4044 case 423:
4045 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
4046 case 424:
4047 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
4048 * Section 11.4 */
4049
4050 case 426:
4051 return "Upgrade Required"; /* RFC 2817 Section 4 */
4052
4053 case 428:
4054 return "Precondition Required"; /* RFC 6585, Section 3 */
4055 case 429:
4056 return "Too Many Requests"; /* RFC 6585, Section 4 */
4057
4058 case 431:
4059 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
4060
4061 case 451:
4062 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
4063 * Section 3 */
4064
4065 /* RFC2616 Section 10.5 - Server Error 5xx */
4066 case 500:
4067 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
4068 case 501:
4069 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
4070 case 502:
4071 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
4072 case 503:
4073 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
4074 case 504:
4075 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
4076 case 505:
4077 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
4078 case 506:
4079 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
4080 case 507:
4081 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
4082 * Section 11.5 */
4083 case 508:
4084 return "Loop Detected"; /* RFC5842 Section 7.1 */
4085
4086 case 510:
4087 return "Not Extended"; /* RFC 2774, Section 7 */
4088 case 511:
4089 return "Network Authentication Required"; /* RFC 6585, Section 6 */
4090
11fdf7f2
TL
4091 /* Other status codes, not shown in the IANA HTTP status code
4092 * assignment.
7c673cae
FG
4093 * E.g., "de facto" standards due to common use, ... */
4094 case 418:
4095 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
4096 case 419:
4097 return "Authentication Timeout"; /* common use */
4098 case 420:
4099 return "Enhance Your Calm"; /* common use */
4100 case 440:
4101 return "Login Timeout"; /* common use */
4102 case 509:
4103 return "Bandwidth Limit Exceeded"; /* common use */
4104
4105 default:
4106 /* This error code is unknown. This should not happen. */
4107 if (conn) {
4108 mg_cry(conn, "Unknown HTTP response code: %u", response_code);
4109 }
4110
4111 /* Return at least a category according to RFC 2616 Section 10. */
4112 if (response_code >= 100 && response_code < 200) {
4113 /* Unknown informational status code */
4114 return "Information";
4115 }
4116 if (response_code >= 200 && response_code < 300) {
4117 /* Unknown success code */
4118 return "Success";
4119 }
4120 if (response_code >= 300 && response_code < 400) {
4121 /* Unknown redirection code */
4122 return "Redirection";
4123 }
4124 if (response_code >= 400 && response_code < 500) {
4125 /* Unknown request error code */
4126 return "Client Error";
4127 }
4128 if (response_code >= 500 && response_code < 600) {
4129 /* Unknown server error code */
4130 return "Server Error";
4131 }
4132
4133 /* Response code not even within reasonable range */
4134 return "";
4135 }
4136}
4137
4138
11fdf7f2
TL
4139void
4140mg_send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
7c673cae
FG
4141{
4142 char buf[MG_BUF_LEN];
4143 va_list ap;
11fdf7f2 4144 int len, i, page_handler_found, scope, truncated, has_body;
7c673cae
FG
4145 char date[64];
4146 time_t curtime = time(NULL);
4147 const char *error_handler = NULL;
11fdf7f2 4148 struct mg_file error_page_file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
4149 const char *error_page_file_ext, *tstr;
4150
4151 const char *status_text = mg_get_response_code_text(conn, status);
4152
4153 if (conn == NULL) {
4154 return;
4155 }
4156
4157 conn->status_code = status;
11fdf7f2 4158 if (conn->in_error_handler || (conn->ctx->callbacks.http_error == NULL)
7c673cae 4159 || conn->ctx->callbacks.http_error(conn, status)) {
11fdf7f2
TL
4160
4161 /* Check for recursion */
4162 if (conn->in_error_handler) {
4163 DEBUG_TRACE(
4164 "Recursion when handling error %u - fall back to default",
4165 status);
4166 } else {
7c673cae
FG
4167 /* Send user defined error pages, if defined */
4168 error_handler = conn->ctx->config[ERROR_PAGES];
4169 error_page_file_ext = conn->ctx->config[INDEX_FILES];
4170 page_handler_found = 0;
11fdf7f2 4171
7c673cae
FG
4172 if (error_handler != NULL) {
4173 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4174 switch (scope) {
4175 case 1: /* Handler for specific error, e.g. 404 error */
4176 mg_snprintf(conn,
4177 &truncated,
4178 buf,
4179 sizeof(buf) - 32,
4180 "%serror%03u.",
4181 error_handler,
4182 status);
4183 break;
11fdf7f2
TL
4184 case 2: /* Handler for error group, e.g., 5xx error
4185 * handler
7c673cae
FG
4186 * for all server errors (500-599) */
4187 mg_snprintf(conn,
4188 &truncated,
4189 buf,
4190 sizeof(buf) - 32,
4191 "%serror%01uxx.",
4192 error_handler,
4193 status / 100);
4194 break;
4195 default: /* Handler for all errors */
4196 mg_snprintf(conn,
4197 &truncated,
4198 buf,
4199 sizeof(buf) - 32,
4200 "%serror.",
4201 error_handler);
4202 break;
4203 }
4204
11fdf7f2
TL
4205 /* String truncation in buf may only occur if
4206 * error_handler is too long. This string is
4207 * from the config, not from a client. */
7c673cae
FG
4208 (void)truncated;
4209
4210 len = (int)strlen(buf);
4211
4212 tstr = strchr(error_page_file_ext, '.');
4213
4214 while (tstr) {
11fdf7f2
TL
4215 for (i = 1;
4216 (i < 32) && (tstr[i] != 0) && (tstr[i] != ',');
7c673cae
FG
4217 i++)
4218 buf[len + i - 1] = tstr[i];
4219 buf[len + i - 1] = 0;
11fdf7f2
TL
4220
4221 if (mg_stat(conn, buf, &error_page_file.stat)) {
4222 DEBUG_TRACE("Check error page %s - found", buf);
7c673cae
FG
4223 page_handler_found = 1;
4224 break;
4225 }
11fdf7f2
TL
4226 DEBUG_TRACE("Check error page %s - not found", buf);
4227
7c673cae
FG
4228 tstr = strchr(tstr + i, '.');
4229 }
4230 }
4231 }
4232
4233 if (page_handler_found) {
4234 conn->in_error_handler = 1;
4235 handle_file_based_request(conn, buf, &error_page_file);
4236 conn->in_error_handler = 0;
4237 return;
4238 }
4239 }
4240
4241 /* No custom error page. Send default error page. */
4242 gmt_time_string(date, sizeof(date), &curtime);
4243
11fdf7f2
TL
4244 /* Errors 1xx, 204 and 304 MUST NOT send a body */
4245 has_body = ((status > 199) && (status != 204) && (status != 304));
4246
7c673cae
FG
4247 conn->must_close = 1;
4248 mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
4249 send_no_cache_header(conn);
11fdf7f2
TL
4250 send_additional_header(conn);
4251 if (has_body) {
4252 mg_printf(conn,
4253 "%s",
4254 "Content-Type: text/plain; charset=utf-8\r\n");
4255 }
7c673cae
FG
4256 mg_printf(conn,
4257 "Date: %s\r\n"
4258 "Connection: close\r\n\r\n",
4259 date);
4260
4261 /* Errors 1xx, 204 and 304 MUST NOT send a body */
11fdf7f2 4262 if (has_body) {
7c673cae
FG
4263 mg_printf(conn, "Error %d: %s\n", status, status_text);
4264
4265 if (fmt != NULL) {
4266 va_start(ap, fmt);
4267 mg_vsnprintf(conn, NULL, buf, sizeof(buf), fmt, ap);
4268 va_end(ap);
4269 mg_write(conn, buf, strlen(buf));
4270 DEBUG_TRACE("Error %i - [%s]", status, buf);
4271 }
4272
4273 } else {
4274 /* No body allowed. Close the connection. */
4275 DEBUG_TRACE("Error %i", status);
4276 }
4277 }
4278}
4279
4280#if defined(_WIN32) && !defined(__SYMBIAN32__)
4281/* Create substitutes for POSIX functions in Win32. */
4282
4283#if defined(__MINGW32__)
4284/* Show no warning in case system functions are not used. */
4285#pragma GCC diagnostic push
4286#pragma GCC diagnostic ignored "-Wunused-function"
4287#endif
4288
4289
11fdf7f2 4290FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4291static int
4292pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
4293{
4294 (void)unused;
4295 *mutex = CreateMutex(NULL, FALSE, NULL);
11fdf7f2 4296 return (*mutex == NULL) ? -1 : 0;
7c673cae
FG
4297}
4298
11fdf7f2 4299FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4300static int
4301pthread_mutex_destroy(pthread_mutex_t *mutex)
4302{
11fdf7f2 4303 return (CloseHandle(*mutex) == 0) ? -1 : 0;
7c673cae
FG
4304}
4305
4306
11fdf7f2 4307FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4308static int
4309pthread_mutex_lock(pthread_mutex_t *mutex)
4310{
11fdf7f2
TL
4311 return (WaitForSingleObject(*mutex, (DWORD)INFINITE) == WAIT_OBJECT_0) ? 0
4312 : -1;
7c673cae
FG
4313}
4314
4315
4316#ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
11fdf7f2 4317FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4318static int
4319pthread_mutex_trylock(pthread_mutex_t *mutex)
4320{
4321 switch (WaitForSingleObject(*mutex, 0)) {
4322 case WAIT_OBJECT_0:
4323 return 0;
4324 case WAIT_TIMEOUT:
4325 return -2; /* EBUSY */
4326 }
4327 return -1;
4328}
4329#endif
4330
4331
11fdf7f2 4332FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4333static int
4334pthread_mutex_unlock(pthread_mutex_t *mutex)
4335{
11fdf7f2 4336 return (ReleaseMutex(*mutex) == 0) ? -1 : 0;
7c673cae 4337}
7c673cae
FG
4338
4339
11fdf7f2 4340FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4341static int
4342pthread_cond_init(pthread_cond_t *cv, const void *unused)
4343{
4344 (void)unused;
4345 InitializeCriticalSection(&cv->threadIdSec);
11fdf7f2
TL
4346 cv->waiting_thread = NULL;
4347 return 0;
7c673cae
FG
4348}
4349
4350
11fdf7f2 4351FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4352static int
4353pthread_cond_timedwait(pthread_cond_t *cv,
4354 pthread_mutex_t *mutex,
4355 const struct timespec *abstime)
4356{
11fdf7f2
TL
4357 struct mg_workerTLS **ptls,
4358 *tls = (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
7c673cae 4359 int ok;
7c673cae
FG
4360 int64_t nsnow, nswaitabs, nswaitrel;
4361 DWORD mswaitrel;
4362
4363 EnterCriticalSection(&cv->threadIdSec);
11fdf7f2
TL
4364 /* Add this thread to cv's waiting list */
4365 ptls = &cv->waiting_thread;
4366 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
4367 ;
4368 tls->next_waiting_thread = NULL;
4369 *ptls = tls;
7c673cae
FG
4370 LeaveCriticalSection(&cv->threadIdSec);
4371
4372 if (abstime) {
11fdf7f2 4373 nsnow = mg_get_current_time_ns();
7c673cae
FG
4374 nswaitabs =
4375 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
4376 nswaitrel = nswaitabs - nsnow;
4377 if (nswaitrel < 0) {
4378 nswaitrel = 0;
4379 }
4380 mswaitrel = (DWORD)(nswaitrel / 1000000);
4381 } else {
11fdf7f2 4382 mswaitrel = (DWORD)INFINITE;
7c673cae
FG
4383 }
4384
4385 pthread_mutex_unlock(mutex);
4386 ok = (WAIT_OBJECT_0
4387 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
11fdf7f2
TL
4388 if (!ok) {
4389 ok = 1;
4390 EnterCriticalSection(&cv->threadIdSec);
4391 ptls = &cv->waiting_thread;
4392 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
4393 if (*ptls == tls) {
4394 *ptls = tls->next_waiting_thread;
4395 ok = 0;
4396 break;
4397 }
4398 }
4399 LeaveCriticalSection(&cv->threadIdSec);
4400 if (ok) {
4401 WaitForSingleObject(tls->pthread_cond_helper_mutex,
4402 (DWORD)INFINITE);
4403 }
4404 }
4405 /* This thread has been removed from cv's waiting list */
7c673cae
FG
4406 pthread_mutex_lock(mutex);
4407
4408 return ok ? 0 : -1;
4409}
4410
4411
11fdf7f2 4412FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4413static int
4414pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
4415{
4416 return pthread_cond_timedwait(cv, mutex, NULL);
4417}
4418
4419
11fdf7f2 4420FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4421static int
4422pthread_cond_signal(pthread_cond_t *cv)
4423{
7c673cae
FG
4424 HANDLE wkup = NULL;
4425 BOOL ok = FALSE;
4426
4427 EnterCriticalSection(&cv->threadIdSec);
11fdf7f2
TL
4428 if (cv->waiting_thread) {
4429 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
4430 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
7c673cae 4431
11fdf7f2 4432 ok = SetEvent(wkup);
7c673cae
FG
4433 assert(ok);
4434 }
4435 LeaveCriticalSection(&cv->threadIdSec);
4436
4437 return ok ? 0 : 1;
4438}
4439
4440
11fdf7f2 4441FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4442static int
4443pthread_cond_broadcast(pthread_cond_t *cv)
4444{
4445 EnterCriticalSection(&cv->threadIdSec);
11fdf7f2 4446 while (cv->waiting_thread) {
7c673cae
FG
4447 pthread_cond_signal(cv);
4448 }
4449 LeaveCriticalSection(&cv->threadIdSec);
4450
4451 return 0;
4452}
4453
4454
11fdf7f2 4455FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4456static int
4457pthread_cond_destroy(pthread_cond_t *cv)
4458{
4459 EnterCriticalSection(&cv->threadIdSec);
11fdf7f2 4460 assert(cv->waiting_thread == NULL);
7c673cae
FG
4461 LeaveCriticalSection(&cv->threadIdSec);
4462 DeleteCriticalSection(&cv->threadIdSec);
4463
4464 return 0;
4465}
4466
4467
11fdf7f2
TL
4468#ifdef ALTERNATIVE_QUEUE
4469FUNCTION_MAY_BE_UNUSED
4470static void *
4471event_create(void)
4472{
4473 return (void *)CreateEvent(NULL, FALSE, FALSE, NULL);
4474}
4475
4476
4477FUNCTION_MAY_BE_UNUSED
4478static int
4479event_wait(void *eventhdl)
4480{
4481 int res = WaitForSingleObject((HANDLE)eventhdl, (DWORD)INFINITE);
4482 return (res == WAIT_OBJECT_0);
4483}
4484
4485
4486FUNCTION_MAY_BE_UNUSED
4487static int
4488event_signal(void *eventhdl)
4489{
4490 return (int)SetEvent((HANDLE)eventhdl);
4491}
4492
4493
4494FUNCTION_MAY_BE_UNUSED
4495static void
4496event_destroy(void *eventhdl)
4497{
4498 CloseHandle((HANDLE)eventhdl);
4499}
4500#endif
4501
4502
7c673cae
FG
4503#if defined(__MINGW32__)
4504/* Enable unused function warning again */
4505#pragma GCC diagnostic pop
4506#endif
4507
4508
4509/* For Windows, change all slashes to backslashes in path names. */
4510static void
4511change_slashes_to_backslashes(char *path)
4512{
4513 int i;
4514
4515 for (i = 0; path[i] != '\0'; i++) {
4516 if (path[i] == '/') {
4517 path[i] = '\\';
4518 }
4519
4520 /* remove double backslash (check i > 0 to preserve UNC paths,
4521 * like \\server\file.txt) */
4522 if ((path[i] == '\\') && (i > 0)) {
11fdf7f2 4523 while ((path[i + 1] == '\\') || (path[i + 1] == '/')) {
7c673cae
FG
4524 (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
4525 }
4526 }
4527 }
4528}
4529
4530
4531static int
4532mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2)
4533{
4534 int diff;
4535
4536 do {
4537 diff = tolower(*s1) - tolower(*s2);
4538 s1++;
4539 s2++;
11fdf7f2 4540 } while ((diff == 0) && (s1[-1] != '\0'));
7c673cae
FG
4541
4542 return diff;
4543}
4544
4545
4546/* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
4547 * wbuf and wbuf_len is a target buffer and its length. */
4548static void
4549path_to_unicode(const struct mg_connection *conn,
4550 const char *path,
4551 wchar_t *wbuf,
4552 size_t wbuf_len)
4553{
4554 char buf[PATH_MAX], buf2[PATH_MAX];
4555 wchar_t wbuf2[MAX_PATH + 1];
4556 DWORD long_len, err;
4557 int (*fcompare)(const wchar_t *, const wchar_t *) = mg_wcscasecmp;
4558
4559 mg_strlcpy(buf, path, sizeof(buf));
4560 change_slashes_to_backslashes(buf);
4561
4562 /* Convert to Unicode and back. If doubly-converted string does not
4563 * match the original, something is fishy, reject. */
4564 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
4565 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
4566 WideCharToMultiByte(
4567 CP_UTF8, 0, wbuf, (int)wbuf_len, buf2, sizeof(buf2), NULL, NULL);
4568 if (strcmp(buf, buf2) != 0) {
4569 wbuf[0] = L'\0';
4570 }
4571
11fdf7f2
TL
4572 /* Windows file systems are not case sensitive, but you can still use
4573 * uppercase and lowercase letters (on all modern file systems).
4574 * The server can check if the URI uses the same upper/lowercase
4575 * letters an the file system, effectively making Windows servers
4576 * case sensitive (like Linux servers are). It is still not possible
4577 * to use two files with the same name in different cases on Windows
4578 * (like /a and /A) - this would be possible in Linux.
4579 * As a default, Windows is not case sensitive, but the case sensitive
4580 * file name check can be activated by an additional configuration. */
7c673cae 4581 if (conn) {
11fdf7f2
TL
4582 if (conn->ctx->config[CASE_SENSITIVE_FILES]
4583 && !mg_strcasecmp(conn->ctx->config[CASE_SENSITIVE_FILES], "yes")) {
4584 /* Use case sensitive compare function */
4585 fcompare = wcscmp;
4586 }
7c673cae 4587 }
7c673cae
FG
4588 (void)conn; /* conn is currently unused */
4589
11fdf7f2 4590#if !defined(_WIN32_WCE)
7c673cae
FG
4591 /* Only accept a full file path, not a Windows short (8.3) path. */
4592 memset(wbuf2, 0, ARRAY_SIZE(wbuf2) * sizeof(wchar_t));
4593 long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1);
4594 if (long_len == 0) {
4595 err = GetLastError();
4596 if (err == ERROR_FILE_NOT_FOUND) {
4597 /* File does not exist. This is not always a problem here. */
4598 return;
4599 }
4600 }
4601 if ((long_len >= ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
4602 /* Short name is used. */
4603 wbuf[0] = L'\0';
4604 }
11fdf7f2
TL
4605#else
4606 (void)long_len;
4607 (void)wbuf2;
4608 (void)err;
7c673cae 4609
11fdf7f2
TL
4610 if (strchr(path, '~')) {
4611 wbuf[0] = L'\0';
7c673cae 4612 }
7c673cae 4613#endif
11fdf7f2 4614}
7c673cae
FG
4615
4616
4617/* Windows happily opens files with some garbage at the end of file name.
4618 * For example, fopen("a.cgi ", "r") on Windows successfully opens
4619 * "a.cgi", despite one would expect an error back.
4620 * This function returns non-0 if path ends with some garbage. */
4621static int
4622path_cannot_disclose_cgi(const char *path)
4623{
4624 static const char *allowed_last_characters = "_-";
4625 int last = path[strlen(path) - 1];
4626 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
4627}
4628
4629
4630static int
11fdf7f2
TL
4631mg_stat(const struct mg_connection *conn,
4632 const char *path,
4633 struct mg_file_stat *filep)
7c673cae
FG
4634{
4635 wchar_t wbuf[PATH_MAX];
4636 WIN32_FILE_ATTRIBUTE_DATA info;
4637 time_t creation_time;
4638
4639 if (!filep) {
4640 return 0;
4641 }
4642 memset(filep, 0, sizeof(*filep));
4643
11fdf7f2 4644 if (conn && is_file_in_memory(conn, path)) {
7c673cae
FG
4645 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
4646 * memset */
11fdf7f2
TL
4647
4648 /* Quick fix (for 1.9.x): */
4649 /* mg_stat must fill all fields, also for files in memory */
4650 struct mg_file tmp_file = STRUCT_FILE_INITIALIZER;
4651 open_file_in_memory(conn, path, &tmp_file, MG_FOPEN_MODE_NONE);
4652 filep->size = tmp_file.stat.size;
4653 filep->location = 2;
4654 /* TODO: for 1.10: restructure how files in memory are handled */
4655
4656 /* The "file in memory" feature is a candidate for deletion.
4657 * Please join the discussion at
4658 * https://groups.google.com/forum/#!topic/civetweb/h9HT4CmeYqI
4659 */
4660
4661 filep->last_modified = time(NULL); /* TODO */
4662 /* last_modified = now ... assumes the file may change during
4663 * runtime,
7c673cae
FG
4664 * so every mg_fopen call may return different data */
4665 /* last_modified = conn->ctx.start_time;
11fdf7f2
TL
4666 * May be used it the data does not change during runtime. This
4667 * allows
7c673cae
FG
4668 * browser caching. Since we do not know, we have to assume the file
4669 * in memory may change. */
4670 return 1;
4671 }
4672
4673 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
4674 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
4675 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
4676 filep->last_modified =
4677 SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
4678 info.ftLastWriteTime.dwHighDateTime);
4679
4680 /* On Windows, the file creation time can be higher than the
4681 * modification time, e.g. when a file is copied.
4682 * Since the Last-Modified timestamp is used for caching
4683 * it should be based on the most recent timestamp. */
4684 creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
4685 info.ftCreationTime.dwHighDateTime);
4686 if (creation_time > filep->last_modified) {
4687 filep->last_modified = creation_time;
4688 }
4689
4690 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
4691 /* If file name is fishy, reset the file structure and return
4692 * error.
4693 * Note it is important to reset, not just return the error, cause
4694 * functions like is_file_opened() check the struct. */
4695 if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
4696 memset(filep, 0, sizeof(*filep));
4697 return 0;
4698 }
4699
4700 return 1;
4701 }
4702
4703 return 0;
4704}
4705
4706
4707static int
4708mg_remove(const struct mg_connection *conn, const char *path)
4709{
4710 wchar_t wbuf[PATH_MAX];
4711 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
4712 return DeleteFileW(wbuf) ? 0 : -1;
4713}
4714
4715
4716static int
4717mg_mkdir(const struct mg_connection *conn, const char *path, int mode)
4718{
4719 wchar_t wbuf[PATH_MAX];
4720 (void)mode;
4721 path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
4722 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
4723}
4724
4725
4726/* Create substitutes for POSIX functions in Win32. */
4727
4728#if defined(__MINGW32__)
4729/* Show no warning in case system functions are not used. */
4730#pragma GCC diagnostic push
4731#pragma GCC diagnostic ignored "-Wunused-function"
4732#endif
4733
4734
4735/* Implementation of POSIX opendir/closedir/readdir for Windows. */
11fdf7f2 4736FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4737static DIR *
4738mg_opendir(const struct mg_connection *conn, const char *name)
4739{
4740 DIR *dir = NULL;
4741 wchar_t wpath[PATH_MAX];
4742 DWORD attrs;
4743
4744 if (name == NULL) {
4745 SetLastError(ERROR_BAD_ARGUMENTS);
4746 } else if ((dir = (DIR *)mg_malloc(sizeof(*dir))) == NULL) {
4747 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
4748 } else {
4749 path_to_unicode(conn, name, wpath, ARRAY_SIZE(wpath));
4750 attrs = GetFileAttributesW(wpath);
4751 if (attrs != 0xFFFFFFFF && ((attrs & FILE_ATTRIBUTE_DIRECTORY)
4752 == FILE_ATTRIBUTE_DIRECTORY)) {
4753 (void)wcscat(wpath, L"\\*");
4754 dir->handle = FindFirstFileW(wpath, &dir->info);
4755 dir->result.d_name[0] = '\0';
4756 } else {
4757 mg_free(dir);
4758 dir = NULL;
4759 }
4760 }
4761
4762 return dir;
4763}
4764
4765
11fdf7f2 4766FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4767static int
4768mg_closedir(DIR *dir)
4769{
4770 int result = 0;
4771
4772 if (dir != NULL) {
4773 if (dir->handle != INVALID_HANDLE_VALUE)
4774 result = FindClose(dir->handle) ? 0 : -1;
4775
4776 mg_free(dir);
4777 } else {
4778 result = -1;
4779 SetLastError(ERROR_BAD_ARGUMENTS);
4780 }
4781
4782 return result;
4783}
4784
4785
11fdf7f2 4786FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4787static struct dirent *
4788mg_readdir(DIR *dir)
4789{
4790 struct dirent *result = 0;
4791
4792 if (dir) {
4793 if (dir->handle != INVALID_HANDLE_VALUE) {
4794 result = &dir->result;
4795 (void)WideCharToMultiByte(CP_UTF8,
4796 0,
4797 dir->info.cFileName,
4798 -1,
4799 result->d_name,
4800 sizeof(result->d_name),
4801 NULL,
4802 NULL);
4803
4804 if (!FindNextFileW(dir->handle, &dir->info)) {
4805 (void)FindClose(dir->handle);
4806 dir->handle = INVALID_HANDLE_VALUE;
4807 }
4808
4809 } else {
4810 SetLastError(ERROR_FILE_NOT_FOUND);
4811 }
4812 } else {
4813 SetLastError(ERROR_BAD_ARGUMENTS);
4814 }
4815
4816 return result;
4817}
4818
4819
4820#ifndef HAVE_POLL
11fdf7f2 4821FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4822static int
4823poll(struct pollfd *pfd, unsigned int n, int milliseconds)
4824{
4825 struct timeval tv;
4826 fd_set set;
4827 unsigned int i;
4828 int result;
4829 SOCKET maxfd = 0;
4830
4831 memset(&tv, 0, sizeof(tv));
4832 tv.tv_sec = milliseconds / 1000;
4833 tv.tv_usec = (milliseconds % 1000) * 1000;
4834 FD_ZERO(&set);
4835
4836 for (i = 0; i < n; i++) {
4837 FD_SET((SOCKET)pfd[i].fd, &set);
4838 pfd[i].revents = 0;
4839
4840 if (pfd[i].fd > maxfd) {
4841 maxfd = pfd[i].fd;
4842 }
4843 }
4844
4845 if ((result = select((int)maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
4846 for (i = 0; i < n; i++) {
4847 if (FD_ISSET(pfd[i].fd, &set)) {
4848 pfd[i].revents = POLLIN;
4849 }
4850 }
4851 }
4852
11fdf7f2
TL
4853 /* We should subtract the time used in select from remaining
4854 * "milliseconds", in particular if called from mg_poll with a
4855 * timeout quantum.
4856 * Unfortunately, the remaining time is not stored in "tv" in all
4857 * implementations, so the result in "tv" must be considered undefined.
4858 * See http://man7.org/linux/man-pages/man2/select.2.html */
4859
7c673cae
FG
4860 return result;
4861}
4862#endif /* HAVE_POLL */
4863
11fdf7f2 4864
7c673cae
FG
4865#if defined(__MINGW32__)
4866/* Enable unused function warning again */
4867#pragma GCC diagnostic pop
4868#endif
4869
4870
4871static void
4872set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
4873{
4874 (void)conn; /* Unused. */
11fdf7f2
TL
4875#if defined(_WIN32_WCE)
4876 (void)sock;
4877#else
7c673cae 4878 (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
11fdf7f2 4879#endif
7c673cae
FG
4880}
4881
4882
4883int
4884mg_start_thread(mg_thread_func_t f, void *p)
4885{
4886#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
11fdf7f2
TL
4887 /* Compile-time option to control stack size, e.g.
4888 * -DUSE_STACK_SIZE=16384
7c673cae
FG
4889 */
4890 return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p)
4891 == ((uintptr_t)(-1L)))
4892 ? -1
4893 : 0);
4894#else
4895 return (
4896 (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L)))
4897 ? -1
4898 : 0);
4899#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
4900}
4901
4902
4903/* Start a thread storing the thread context. */
4904static int
4905mg_start_thread_with_id(unsigned(__stdcall *f)(void *),
4906 void *p,
4907 pthread_t *threadidptr)
4908{
4909 uintptr_t uip;
4910 HANDLE threadhandle;
4911 int result = -1;
4912
4913 uip = _beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))f, p, 0, NULL);
4914 threadhandle = (HANDLE)uip;
4915 if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
4916 *threadidptr = threadhandle;
4917 result = 0;
4918 }
4919
4920 return result;
4921}
4922
4923
4924/* Wait for a thread to finish. */
4925static int
4926mg_join_thread(pthread_t threadid)
4927{
4928 int result;
4929 DWORD dwevent;
4930
4931 result = -1;
11fdf7f2 4932 dwevent = WaitForSingleObject(threadid, (DWORD)INFINITE);
7c673cae
FG
4933 if (dwevent == WAIT_FAILED) {
4934 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO);
4935 } else {
4936 if (dwevent == WAIT_OBJECT_0) {
4937 CloseHandle(threadid);
4938 result = 0;
4939 }
4940 }
4941
4942 return result;
4943}
4944
11fdf7f2
TL
4945#if !defined(NO_SSL_DL) && !defined(NO_SSL)
4946/* If SSL is loaded dynamically, dlopen/dlclose is required. */
7c673cae
FG
4947/* Create substitutes for POSIX functions in Win32. */
4948
4949#if defined(__MINGW32__)
4950/* Show no warning in case system functions are not used. */
4951#pragma GCC diagnostic push
4952#pragma GCC diagnostic ignored "-Wunused-function"
4953#endif
4954
4955
11fdf7f2 4956FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4957static HANDLE
4958dlopen(const char *dll_name, int flags)
4959{
4960 wchar_t wbuf[PATH_MAX];
4961 (void)flags;
4962 path_to_unicode(NULL, dll_name, wbuf, ARRAY_SIZE(wbuf));
4963 return LoadLibraryW(wbuf);
4964}
4965
4966
11fdf7f2 4967FUNCTION_MAY_BE_UNUSED
7c673cae
FG
4968static int
4969dlclose(void *handle)
4970{
4971 int result;
4972
4973 if (FreeLibrary((HMODULE)handle) != 0) {
4974 result = 0;
4975 } else {
4976 result = -1;
4977 }
4978
4979 return result;
4980}
4981
4982
4983#if defined(__MINGW32__)
4984/* Enable unused function warning again */
4985#pragma GCC diagnostic pop
4986#endif
4987
4988#endif
4989
4990
4991#if !defined(NO_CGI)
4992#define SIGKILL (0)
4993
4994static int
4995kill(pid_t pid, int sig_num)
4996{
4997 (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
4998 (void)CloseHandle((HANDLE)pid);
4999 return 0;
5000}
5001
5002
5003static void
5004trim_trailing_whitespaces(char *s)
5005{
5006 char *e = s + strlen(s) - 1;
11fdf7f2 5007 while ((e > s) && isspace(*(unsigned char *)e)) {
7c673cae
FG
5008 *e-- = '\0';
5009 }
5010}
5011
5012
5013static pid_t
5014spawn_process(struct mg_connection *conn,
5015 const char *prog,
5016 char *envblk,
5017 char *envp[],
5018 int fdin[2],
5019 int fdout[2],
5020 int fderr[2],
5021 const char *dir)
5022{
5023 HANDLE me;
5024 char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
5025 cmdline[PATH_MAX], buf[PATH_MAX];
5026 int truncated;
11fdf7f2 5027 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
5028 STARTUPINFOA si;
5029 PROCESS_INFORMATION pi = {0};
5030
5031 (void)envp;
5032
5033 memset(&si, 0, sizeof(si));
5034 si.cb = sizeof(si);
5035
5036 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
5037 si.wShowWindow = SW_HIDE;
5038
5039 me = GetCurrentProcess();
5040 DuplicateHandle(me,
5041 (HANDLE)_get_osfhandle(fdin[0]),
5042 me,
5043 &si.hStdInput,
5044 0,
5045 TRUE,
5046 DUPLICATE_SAME_ACCESS);
5047 DuplicateHandle(me,
5048 (HANDLE)_get_osfhandle(fdout[1]),
5049 me,
5050 &si.hStdOutput,
5051 0,
5052 TRUE,
5053 DUPLICATE_SAME_ACCESS);
5054 DuplicateHandle(me,
5055 (HANDLE)_get_osfhandle(fderr[1]),
5056 me,
5057 &si.hStdError,
5058 0,
5059 TRUE,
5060 DUPLICATE_SAME_ACCESS);
5061
5062 /* Mark handles that should not be inherited. See
5063 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
5064 */
5065 SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
5066 HANDLE_FLAG_INHERIT,
5067 0);
5068 SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
5069 HANDLE_FLAG_INHERIT,
5070 0);
5071 SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
5072 HANDLE_FLAG_INHERIT,
5073 0);
5074
5075 /* If CGI file is a script, try to read the interpreter line */
5076 interp = conn->ctx->config[CGI_INTERPRETER];
5077 if (interp == NULL) {
5078 buf[0] = buf[1] = '\0';
5079
5080 /* Read the first line of the script into the buffer */
5081 mg_snprintf(
5082 conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
5083
5084 if (truncated) {
5085 pi.hProcess = (pid_t)-1;
5086 goto spawn_cleanup;
5087 }
5088
11fdf7f2
TL
5089 if (mg_fopen(conn, cmdline, MG_FOPEN_MODE_READ, &file)) {
5090 p = (char *)file.access.membuf;
7c673cae 5091 mg_fgets(buf, sizeof(buf), &file, &p);
11fdf7f2 5092 (void)mg_fclose(&file.access); /* ignore error on read only file */
7c673cae
FG
5093 buf[sizeof(buf) - 1] = '\0';
5094 }
5095
11fdf7f2 5096 if ((buf[0] == '#') && (buf[1] == '!')) {
7c673cae
FG
5097 trim_trailing_whitespaces(buf + 2);
5098 } else {
5099 buf[2] = '\0';
5100 }
5101 interp = buf + 2;
5102 }
5103
5104 if (interp[0] != '\0') {
5105 GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
5106 interp = full_interp;
5107 }
5108 GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
5109
5110 if (interp[0] != '\0') {
5111 mg_snprintf(conn,
5112 &truncated,
5113 cmdline,
5114 sizeof(cmdline),
5115 "\"%s\" \"%s\\%s\"",
5116 interp,
5117 full_dir,
5118 prog);
5119 } else {
5120 mg_snprintf(conn,
5121 &truncated,
5122 cmdline,
5123 sizeof(cmdline),
5124 "\"%s\\%s\"",
5125 full_dir,
5126 prog);
5127 }
5128
5129 if (truncated) {
5130 pi.hProcess = (pid_t)-1;
5131 goto spawn_cleanup;
5132 }
5133
5134 DEBUG_TRACE("Running [%s]", cmdline);
5135 if (CreateProcessA(NULL,
5136 cmdline,
5137 NULL,
5138 NULL,
5139 TRUE,
5140 CREATE_NEW_PROCESS_GROUP,
5141 envblk,
5142 NULL,
5143 &si,
5144 &pi) == 0) {
5145 mg_cry(
5146 conn, "%s: CreateProcess(%s): %ld", __func__, cmdline, (long)ERRNO);
5147 pi.hProcess = (pid_t)-1;
5148 /* goto spawn_cleanup; */
5149 }
5150
5151spawn_cleanup:
5152 (void)CloseHandle(si.hStdOutput);
5153 (void)CloseHandle(si.hStdError);
5154 (void)CloseHandle(si.hStdInput);
5155 if (pi.hThread != NULL) {
5156 (void)CloseHandle(pi.hThread);
5157 }
5158
5159 return (pid_t)pi.hProcess;
5160}
5161#endif /* !NO_CGI */
5162
5163
5164static int
11fdf7f2 5165set_blocking_mode(SOCKET sock)
7c673cae 5166{
11fdf7f2
TL
5167 unsigned long non_blocking = 0;
5168 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
7c673cae
FG
5169}
5170
11fdf7f2
TL
5171static int
5172set_non_blocking_mode(SOCKET sock)
5173{
5174 unsigned long non_blocking = 1;
5175 return ioctlsocket(sock, (long)FIONBIO, &non_blocking);
5176}
7c673cae
FG
5177#else
5178
5179static int
11fdf7f2
TL
5180mg_stat(const struct mg_connection *conn,
5181 const char *path,
5182 struct mg_file_stat *filep)
7c673cae
FG
5183{
5184 struct stat st;
5185 if (!filep) {
5186 return 0;
5187 }
5188 memset(filep, 0, sizeof(*filep));
5189
11fdf7f2
TL
5190 if (conn && is_file_in_memory(conn, path)) {
5191
5192 /* Quick fix (for 1.9.x): */
5193 /* mg_stat must fill all fields, also for files in memory */
5194 struct mg_file tmp_file = STRUCT_FILE_INITIALIZER;
5195 open_file_in_memory(conn, path, &tmp_file, MG_FOPEN_MODE_NONE);
5196 filep->size = tmp_file.stat.size;
5197 filep->last_modified = time(NULL);
5198 filep->location = 2;
5199 /* TODO: for 1.10: restructure how files in memory are handled */
5200
7c673cae
FG
5201 return 1;
5202 }
5203
5204 if (0 == stat(path, &st)) {
5205 filep->size = (uint64_t)(st.st_size);
5206 filep->last_modified = st.st_mtime;
5207 filep->is_directory = S_ISDIR(st.st_mode);
5208 return 1;
5209 }
5210
5211 return 0;
5212}
5213
5214
5215static void
5216set_close_on_exec(SOCKET fd, struct mg_connection *conn /* may be null */)
5217{
5218 if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
5219 if (conn) {
5220 mg_cry(conn,
5221 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
5222 __func__,
5223 strerror(ERRNO));
5224 }
5225 }
5226}
5227
5228
5229int
5230mg_start_thread(mg_thread_func_t func, void *param)
5231{
5232 pthread_t thread_id;
5233 pthread_attr_t attr;
5234 int result;
5235
5236 (void)pthread_attr_init(&attr);
5237 (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
5238
5239#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5240 /* Compile-time option to control stack size,
5241 * e.g. -DUSE_STACK_SIZE=16384 */
5242 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5243#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
5244
5245 result = pthread_create(&thread_id, &attr, func, param);
5246 pthread_attr_destroy(&attr);
5247
5248 return result;
5249}
5250
5251
5252/* Start a thread storing the thread context. */
5253static int
5254mg_start_thread_with_id(mg_thread_func_t func,
5255 void *param,
5256 pthread_t *threadidptr)
5257{
5258 pthread_t thread_id;
5259 pthread_attr_t attr;
5260 int result;
5261
5262 (void)pthread_attr_init(&attr);
5263
5264#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
5265 /* Compile-time option to control stack size,
5266 * e.g. -DUSE_STACK_SIZE=16384 */
5267 (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
5268#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
5269
5270 result = pthread_create(&thread_id, &attr, func, param);
5271 pthread_attr_destroy(&attr);
5272 if ((result == 0) && (threadidptr != NULL)) {
5273 *threadidptr = thread_id;
5274 }
5275 return result;
5276}
5277
5278
5279/* Wait for a thread to finish. */
5280static int
5281mg_join_thread(pthread_t threadid)
5282{
5283 int result;
5284
5285 result = pthread_join(threadid, NULL);
5286 return result;
5287}
5288
5289
5290#ifndef NO_CGI
5291static pid_t
5292spawn_process(struct mg_connection *conn,
5293 const char *prog,
5294 char *envblk,
5295 char *envp[],
5296 int fdin[2],
5297 int fdout[2],
5298 int fderr[2],
5299 const char *dir)
5300{
5301 pid_t pid;
5302 const char *interp;
5303
5304 (void)envblk;
5305
5306 if (conn == NULL) {
5307 return 0;
5308 }
5309
5310 if ((pid = fork()) == -1) {
5311 /* Parent */
11fdf7f2
TL
5312 mg_send_http_error(conn,
5313 500,
5314 "Error: Creating CGI process\nfork(): %s",
5315 strerror(ERRNO));
7c673cae
FG
5316 } else if (pid == 0) {
5317 /* Child */
5318 if (chdir(dir) != 0) {
5319 mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
5320 } else if (dup2(fdin[0], 0) == -1) {
5321 mg_cry(conn,
5322 "%s: dup2(%d, 0): %s",
5323 __func__,
5324 fdin[0],
5325 strerror(ERRNO));
5326 } else if (dup2(fdout[1], 1) == -1) {
5327 mg_cry(conn,
5328 "%s: dup2(%d, 1): %s",
5329 __func__,
5330 fdout[1],
5331 strerror(ERRNO));
5332 } else if (dup2(fderr[1], 2) == -1) {
5333 mg_cry(conn,
5334 "%s: dup2(%d, 2): %s",
5335 __func__,
5336 fderr[1],
5337 strerror(ERRNO));
5338 } else {
5339 /* Keep stderr and stdout in two different pipes.
5340 * Stdout will be sent back to the client,
5341 * stderr should go into a server error log. */
5342 (void)close(fdin[0]);
5343 (void)close(fdout[1]);
5344 (void)close(fderr[1]);
5345
5346 /* Close write end fdin and read end fdout and fderr */
5347 (void)close(fdin[1]);
5348 (void)close(fdout[0]);
5349 (void)close(fderr[0]);
5350
5351 /* After exec, all signal handlers are restored to their default
5352 * values, with one exception of SIGCHLD. According to
5353 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
5354 * leave unchanged after exec if it was set to be ignored. Restore
5355 * it to default action. */
5356 signal(SIGCHLD, SIG_DFL);
5357
5358 interp = conn->ctx->config[CGI_INTERPRETER];
5359 if (interp == NULL) {
5360 (void)execle(prog, prog, NULL, envp);
5361 mg_cry(conn,
5362 "%s: execle(%s): %s",
5363 __func__,
5364 prog,
5365 strerror(ERRNO));
5366 } else {
5367 (void)execle(interp, interp, prog, NULL, envp);
5368 mg_cry(conn,
5369 "%s: execle(%s %s): %s",
5370 __func__,
5371 interp,
5372 prog,
5373 strerror(ERRNO));
5374 }
5375 }
5376 exit(EXIT_FAILURE);
5377 }
5378
5379 return pid;
5380}
5381#endif /* !NO_CGI */
5382
5383
5384static int
5385set_non_blocking_mode(SOCKET sock)
5386{
11fdf7f2
TL
5387 int flags = fcntl(sock, F_GETFL, 0);
5388 if (flags < 0) {
5389 return -1;
5390 }
7c673cae 5391
11fdf7f2
TL
5392 if (fcntl(sock, F_SETFL, (flags | O_NONBLOCK)) < 0) {
5393 return -1;
5394 }
5395 return 0;
5396}
5397
5398static int
5399set_blocking_mode(SOCKET sock)
5400{
5401 int flags = fcntl(sock, F_GETFL, 0);
5402 if (flags < 0) {
5403 return -1;
5404 }
7c673cae 5405
11fdf7f2
TL
5406 if (fcntl(sock, F_SETFL, flags & (~(int)(O_NONBLOCK))) < 0) {
5407 return -1;
5408 }
7c673cae
FG
5409 return 0;
5410}
11fdf7f2
TL
5411#endif /* _WIN32 / else */
5412
7c673cae
FG
5413/* End of initial operating system specific define block. */
5414
5415
5416/* Get a random number (independent of C rand function) */
5417static uint64_t
5418get_random(void)
5419{
5420 static uint64_t lfsr = 0; /* Linear feedback shift register */
5421 static uint64_t lcg = 0; /* Linear congruential generator */
11fdf7f2 5422 uint64_t now = mg_get_current_time_ns();
7c673cae
FG
5423
5424 if (lfsr == 0) {
5425 /* lfsr will be only 0 if has not been initialized,
5426 * so this code is called only once. */
11fdf7f2
TL
5427 lfsr = mg_get_current_time_ns();
5428 lcg = mg_get_current_time_ns();
7c673cae
FG
5429 } else {
5430 /* Get the next step of both random number generators. */
5431 lfsr = (lfsr >> 1)
5432 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
5433 << 63);
11fdf7f2 5434 lcg = lcg * 6364136223846793005LL + 1442695040888963407LL;
7c673cae
FG
5435 }
5436
11fdf7f2
TL
5437 /* Combining two pseudo-random number generators and a high resolution
5438 * part
5439 * of the current server time will make it hard (impossible?) to guess
5440 * the
7c673cae 5441 * next number. */
11fdf7f2 5442 return (lfsr ^ lcg ^ now);
7c673cae
FG
5443}
5444
5445
7c673cae 5446static int
11fdf7f2
TL
5447mg_poll(struct pollfd *pfd,
5448 unsigned int n,
5449 int milliseconds,
5450 volatile int *stop_server)
7c673cae 5451{
11fdf7f2
TL
5452 /* Call poll, but only for a maximum time of a few seconds.
5453 * This will allow to stop the server after some seconds, instead
5454 * of having to wait for a long socket timeout. */
5455 int ms_now = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
5456
5457 do {
5458 int result;
5459
5460 if (*stop_server) {
5461 /* Shut down signal */
5462 return -2;
5463 }
5464
5465 if ((milliseconds >= 0) && (milliseconds < ms_now)) {
5466 ms_now = milliseconds;
5467 }
5468
5469 result = poll(pfd, n, ms_now);
5470 if (result != 0) {
5471 /* Poll returned either success (1) or error (-1).
5472 * Forward both to the caller. */
5473 return result;
5474 }
5475
5476 /* Poll returned timeout (0). */
5477 if (milliseconds > 0) {
5478 milliseconds -= ms_now;
5479 }
5480
5481 } while (milliseconds != 0);
5482
5483 /* timeout: return 0 */
5484 return 0;
5485}
5486
5487
5488/* Write data to the IO channel - opened file descriptor, socket or SSL
5489 * descriptor.
5490 * Return value:
5491 * >=0 .. number of bytes successfully written
5492 * -1 .. timeout
5493 * -2 .. error
5494 */
5495static int
5496push_inner(struct mg_context *ctx,
5497 FILE *fp,
5498 SOCKET sock,
5499 SSL *ssl,
5500 const char *buf,
5501 int len,
5502 double timeout)
5503{
5504 uint64_t start = 0, now = 0, timeout_ns = 0;
7c673cae 5505 int n, err;
11fdf7f2 5506 unsigned ms_wait = SOCKET_TIMEOUT_QUANTUM; /* Sleep quantum in ms */
7c673cae
FG
5507
5508#ifdef _WIN32
5509 typedef int len_t;
5510#else
5511 typedef size_t len_t;
5512#endif
5513
5514 if (timeout > 0) {
11fdf7f2
TL
5515 now = mg_get_current_time_ns();
5516 start = now;
5517 timeout_ns = (uint64_t)(timeout * 1.0E9);
7c673cae
FG
5518 }
5519
5520 if (ctx == NULL) {
11fdf7f2 5521 return -2;
7c673cae
FG
5522 }
5523
5524#ifdef NO_SSL
5525 if (ssl) {
11fdf7f2 5526 return -2;
7c673cae
FG
5527 }
5528#endif
5529
11fdf7f2
TL
5530 /* Try to read until it succeeds, fails, times out, or the server
5531 * shuts down. */
5532 for (;;) {
7c673cae
FG
5533
5534#ifndef NO_SSL
5535 if (ssl != NULL) {
5536 n = SSL_write(ssl, buf, len);
5537 if (n <= 0) {
5538 err = SSL_get_error(ssl, n);
11fdf7f2 5539 if ((err == SSL_ERROR_SYSCALL) && (n == -1)) {
7c673cae 5540 err = ERRNO;
11fdf7f2
TL
5541 } else if ((err == SSL_ERROR_WANT_READ)
5542 || (err == SSL_ERROR_WANT_WRITE)) {
5543 n = 0;
7c673cae
FG
5544 } else {
5545 DEBUG_TRACE("SSL_write() failed, error %d", err);
11fdf7f2 5546 return -2;
7c673cae
FG
5547 }
5548 } else {
5549 err = 0;
5550 }
5551 } else
5552#endif
5553 if (fp != NULL) {
5554 n = (int)fwrite(buf, 1, (size_t)len, fp);
5555 if (ferror(fp)) {
5556 n = -1;
5557 err = ERRNO;
5558 } else {
5559 err = 0;
5560 }
5561 } else {
5562 n = (int)send(sock, buf, (len_t)len, MSG_NOSIGNAL);
5563 err = (n < 0) ? ERRNO : 0;
11fdf7f2
TL
5564#ifdef _WIN32
5565 if (err == WSAEWOULDBLOCK) {
5566 err = 0;
5567 n = 0;
5568 }
5569#else
5570 if (err == EWOULDBLOCK) {
5571 err = 0;
5572 n = 0;
5573 }
5574#endif
5575 if (n < 0) {
5576 /* shutdown of the socket at client side */
5577 return -2;
5578 }
7c673cae
FG
5579 }
5580
5581 if (ctx->stop_flag) {
11fdf7f2 5582 return -2;
7c673cae
FG
5583 }
5584
11fdf7f2 5585 if ((n > 0) || ((n == 0) && (len == 0))) {
7c673cae
FG
5586 /* some data has been read, or no data was requested */
5587 return n;
5588 }
7c673cae
FG
5589 if (n < 0) {
5590 /* socket error - check errno */
5591 DEBUG_TRACE("send() failed, error %d", err);
5592
11fdf7f2 5593 /* TODO (mid): error handling depending on the error code.
7c673cae 5594 * These codes are different between Windows and Linux.
11fdf7f2
TL
5595 * Currently there is no problem with failing send calls,
5596 * if there is a reproducible situation, it should be
5597 * investigated in detail.
7c673cae 5598 */
11fdf7f2 5599 return -2;
7c673cae
FG
5600 }
5601
11fdf7f2 5602 /* Only in case n=0 (timeout), repeat calling the write function */
7c673cae 5603
11fdf7f2
TL
5604 /* If send failed, wait before retry */
5605 if (fp != NULL) {
5606 /* For files, just wait a fixed time,
5607 * maybe an average disk seek time. */
5608 mg_sleep(ms_wait > 10 ? 10 : ms_wait);
5609 } else {
5610 /* For sockets, wait for the socket using poll */
5611 struct pollfd pfd[1];
5612 int pollres;
5613
5614 pfd[0].fd = sock;
5615 pfd[0].events = POLLOUT;
5616 pollres = mg_poll(pfd, 1, (int)(ms_wait), &(ctx->stop_flag));
5617 if (ctx->stop_flag) {
5618 return -2;
5619 }
5620 if (pollres > 0) {
5621 continue;
5622 }
7c673cae
FG
5623 }
5624
11fdf7f2
TL
5625 if (timeout > 0) {
5626 now = mg_get_current_time_ns();
5627 if ((now - start) > timeout_ns) {
5628 /* Timeout */
5629 break;
5630 }
5631 }
5632 }
7c673cae
FG
5633
5634 (void)err; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
5635 used */
5636
5637 return -1;
5638}
5639
5640
5641static int64_t
5642push_all(struct mg_context *ctx,
5643 FILE *fp,
5644 SOCKET sock,
5645 SSL *ssl,
5646 const char *buf,
5647 int64_t len)
5648{
5649 double timeout = -1.0;
5650 int64_t n, nwritten = 0;
5651
5652 if (ctx == NULL) {
5653 return -1;
5654 }
5655
5656 if (ctx->config[REQUEST_TIMEOUT]) {
5657 timeout = atoi(ctx->config[REQUEST_TIMEOUT]) / 1000.0;
5658 }
5659
11fdf7f2
TL
5660 while ((len > 0) && (ctx->stop_flag == 0)) {
5661 n = push_inner(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout);
7c673cae
FG
5662 if (n < 0) {
5663 if (nwritten == 0) {
5664 nwritten = n; /* Propagate the error */
5665 }
5666 break;
5667 } else if (n == 0) {
5668 break; /* No more data to write */
5669 } else {
5670 nwritten += n;
5671 len -= n;
5672 }
5673 }
5674
5675 return nwritten;
5676}
5677
5678
5679/* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
11fdf7f2
TL
5680 * Return value:
5681 * >=0 .. number of bytes successfully read
5682 * -1 .. timeout
5683 * -2 .. error
5684 */
7c673cae 5685static int
11fdf7f2
TL
5686pull_inner(FILE *fp,
5687 struct mg_connection *conn,
5688 char *buf,
5689 int len,
5690 double timeout)
7c673cae 5691{
11fdf7f2 5692 int nread, err = 0;
7c673cae
FG
5693
5694#ifdef _WIN32
5695 typedef int len_t;
5696#else
5697 typedef size_t len_t;
5698#endif
11fdf7f2
TL
5699#ifndef NO_SSL
5700 int ssl_pending;
5701#endif
7c673cae 5702
11fdf7f2
TL
5703 /* We need an additional wait loop around this, because in some cases
5704 * with TLSwe may get data from the socket but not from SSL_read.
5705 * In this case we need to repeat at least once.
5706 */
7c673cae 5707
11fdf7f2
TL
5708 if (fp != NULL) {
5709#if !defined(_WIN32_WCE)
5710 /* Use read() instead of fread(), because if we're reading from the
5711 * CGI pipe, fread() may block until IO buffer is filled up. We
5712 * cannot afford to block and must pass all read bytes immediately
5713 * to the client. */
5714 nread = (int)read(fileno(fp), buf, (size_t)len);
5715#else
5716 /* WinCE does not support CGI pipes */
5717 nread = (int)fread(buf, 1, (size_t)len, fp);
5718#endif
5719 err = (nread < 0) ? ERRNO : 0;
5720 if ((nread == 0) && (len > 0)) {
5721 /* Should get data, but got EOL */
5722 return -2;
5723 }
7c673cae
FG
5724
5725#ifndef NO_SSL
11fdf7f2
TL
5726 } else if ((conn->ssl != NULL)
5727 && ((ssl_pending = SSL_pending(conn->ssl)) > 0)) {
5728 /* We already know there is no more data buffered in conn->buf
5729 * but there is more available in the SSL layer. So don't poll
5730 * conn->client.sock yet. */
5731 if (ssl_pending > len) {
5732 ssl_pending = len;
5733 }
5734 nread = SSL_read(conn->ssl, buf, ssl_pending);
5735 if (nread <= 0) {
5736 err = SSL_get_error(conn->ssl, nread);
5737 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
5738 err = ERRNO;
5739 } else if ((err == SSL_ERROR_WANT_READ)
5740 || (err == SSL_ERROR_WANT_WRITE)) {
5741 nread = 0;
5742 } else {
5743 DEBUG_TRACE("SSL_read() failed, error %d", err);
5744 return -1;
5745 }
5746 } else {
5747 err = 0;
5748 }
5749
5750 } else if (conn->ssl != NULL) {
5751
5752 struct pollfd pfd[1];
5753 int pollres;
5754
5755 pfd[0].fd = conn->client.sock;
5756 pfd[0].events = POLLIN;
5757 pollres =
5758 mg_poll(pfd, 1, (int)(timeout * 1000.0), &(conn->ctx->stop_flag));
5759 if (conn->ctx->stop_flag) {
5760 return -2;
5761 }
5762 if (pollres > 0) {
7c673cae
FG
5763 nread = SSL_read(conn->ssl, buf, len);
5764 if (nread <= 0) {
5765 err = SSL_get_error(conn->ssl, nread);
11fdf7f2 5766 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
7c673cae 5767 err = ERRNO;
11fdf7f2
TL
5768 } else if ((err == SSL_ERROR_WANT_READ)
5769 || (err == SSL_ERROR_WANT_WRITE)) {
5770 nread = 0;
7c673cae
FG
5771 } else {
5772 DEBUG_TRACE("SSL_read() failed, error %d", err);
11fdf7f2 5773 return -2;
7c673cae
FG
5774 }
5775 } else {
5776 err = 0;
5777 }
7c673cae 5778
11fdf7f2
TL
5779 } else if (pollres < 0) {
5780 /* Error */
5781 return -2;
7c673cae 5782 } else {
11fdf7f2
TL
5783 /* pollres = 0 means timeout */
5784 nread = 0;
7c673cae 5785 }
11fdf7f2 5786#endif
7c673cae 5787
11fdf7f2
TL
5788 } else {
5789 struct pollfd pfd[1];
5790 int pollres;
7c673cae 5791
11fdf7f2
TL
5792 pfd[0].fd = conn->client.sock;
5793 pfd[0].events = POLLIN;
5794 pollres =
5795 mg_poll(pfd, 1, (int)(timeout * 1000.0), &(conn->ctx->stop_flag));
5796 if (conn->ctx->stop_flag) {
5797 return -2;
7c673cae 5798 }
11fdf7f2
TL
5799 if (pollres > 0) {
5800 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
5801 err = (nread < 0) ? ERRNO : 0;
5802 if (nread <= 0) {
5803 /* shutdown of the socket at client side */
5804 return -2;
5805 }
5806 } else if (pollres < 0) {
5807 /* error callint poll */
5808 return -2;
5809 } else {
5810 /* pollres = 0 means timeout */
5811 nread = 0;
7c673cae 5812 }
11fdf7f2
TL
5813 }
5814
5815 if (conn->ctx->stop_flag) {
5816 return -2;
5817 }
5818
5819 if ((nread > 0) || ((nread == 0) && (len == 0))) {
5820 /* some data has been read, or no data was requested */
5821 return nread;
5822 }
5823
5824 if (nread < 0) {
7c673cae
FG
5825/* socket error - check errno */
5826#ifdef _WIN32
11fdf7f2
TL
5827 if (err == WSAEWOULDBLOCK) {
5828 /* TODO (low): check if this is still required */
5829 /* standard case if called from close_socket_gracefully */
5830 return -2;
5831 } else if (err == WSAETIMEDOUT) {
5832 /* TODO (low): check if this is still required */
5833 /* timeout is handled by the while loop */
5834 return 0;
5835 } else if (err == WSAECONNABORTED) {
5836 /* See https://www.chilkatsoft.com/p/p_299.asp */
5837 return -2;
5838 } else {
5839 DEBUG_TRACE("recv() failed, error %d", err);
5840 return -2;
7c673cae 5841 }
11fdf7f2
TL
5842#else
5843 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
5844 * if the timeout is reached and if the socket was set to non-
5845 * blocking in close_socket_gracefully, so we can not distinguish
5846 * here. We have to wait for the timeout in both cases for now.
5847 */
5848 if ((err == EAGAIN) || (err == EWOULDBLOCK) || (err == EINTR)) {
5849 /* TODO (low): check if this is still required */
5850 /* EAGAIN/EWOULDBLOCK:
5851 * standard case if called from close_socket_gracefully
5852 * => should return -1 */
5853 /* or timeout occured
5854 * => the code must stay in the while loop */
5855
5856 /* EINTR can be generated on a socket with a timeout set even
5857 * when SA_RESTART is effective for all relevant signals
5858 * (see signal(7)).
5859 * => stay in the while loop */
5860 } else {
5861 DEBUG_TRACE("recv() failed, error %d", err);
5862 return -2;
7c673cae 5863 }
11fdf7f2
TL
5864#endif
5865 }
7c673cae
FG
5866
5867 /* Timeout occured, but no data available. */
5868 return -1;
5869}
5870
5871
5872static int
5873pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
5874{
5875 int n, nread = 0;
5876 double timeout = -1.0;
11fdf7f2 5877 uint64_t start_time = 0, now = 0, timeout_ns = 0;
7c673cae
FG
5878
5879 if (conn->ctx->config[REQUEST_TIMEOUT]) {
5880 timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
5881 }
11fdf7f2
TL
5882 if (timeout >= 0.0) {
5883 start_time = mg_get_current_time_ns();
5884 timeout_ns = (uint64_t)(timeout * 1.0E9);
5885 }
7c673cae 5886
11fdf7f2
TL
5887 while ((len > 0) && (conn->ctx->stop_flag == 0)) {
5888 n = pull_inner(fp, conn, buf + nread, len, timeout);
5889 if (n == -2) {
7c673cae 5890 if (nread == 0) {
11fdf7f2
TL
5891 nread = -1; /* Propagate the error */
5892 }
5893 break;
5894 } else if (n == -1) {
5895 /* timeout */
5896 if (timeout >= 0.0) {
5897 now = mg_get_current_time_ns();
5898 if ((now - start_time) <= timeout_ns) {
5899 continue;
5900 }
7c673cae
FG
5901 }
5902 break;
5903 } else if (n == 0) {
5904 break; /* No more data to read */
5905 } else {
5906 conn->consumed_content += n;
5907 nread += n;
5908 len -= n;
5909 }
5910 }
5911
5912 return nread;
5913}
5914
5915
5916static void
5917discard_unread_request_data(struct mg_connection *conn)
5918{
5919 char buf[MG_BUF_LEN];
5920 size_t to_read;
5921 int nread;
5922
5923 if (conn == NULL) {
5924 return;
5925 }
5926
5927 to_read = sizeof(buf);
5928
5929 if (conn->is_chunked) {
11fdf7f2 5930 /* Chunked encoding: 3=chunk read completely
7c673cae 5931 * completely */
11fdf7f2 5932 while (conn->is_chunked != 3) {
7c673cae
FG
5933 nread = mg_read(conn, buf, to_read);
5934 if (nread <= 0) {
5935 break;
5936 }
5937 }
5938
5939 } else {
5940 /* Not chunked: content length is known */
5941 while (conn->consumed_content < conn->content_len) {
5942 if (to_read
5943 > (size_t)(conn->content_len - conn->consumed_content)) {
5944 to_read = (size_t)(conn->content_len - conn->consumed_content);
5945 }
5946
5947 nread = mg_read(conn, buf, to_read);
5948 if (nread <= 0) {
5949 break;
5950 }
5951 }
5952 }
5953}
5954
5955
5956static int
5957mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
5958{
5959 int64_t n, buffered_len, nread;
5960 int64_t len64 =
11fdf7f2 5961 (int64_t)((len > INT_MAX) ? INT_MAX : len); /* since the return value is
7c673cae
FG
5962 * int, we may not read more
5963 * bytes */
5964 const char *body;
5965
5966 if (conn == NULL) {
5967 return 0;
5968 }
5969
11fdf7f2
TL
5970 /* If Content-Length is not set for a request with body data
5971 * (e.g., a PUT or POST request), we do not know in advance
5972 * how much data should be read. */
5973 if (conn->consumed_content == 0) {
5974 if (conn->is_chunked == 1) {
5975 conn->content_len = len64;
5976 conn->is_chunked = 2;
5977 } else if (conn->content_len == -1) {
5978 /* The body data is completed when the connection
5979 * is closed. */
5980 conn->content_len = INT64_MAX;
5981 conn->must_close = 1;
5982 }
7c673cae
FG
5983 }
5984
5985 nread = 0;
5986 if (conn->consumed_content < conn->content_len) {
5987 /* Adjust number of bytes to read. */
5988 int64_t left_to_read = conn->content_len - conn->consumed_content;
5989 if (left_to_read < len64) {
11fdf7f2
TL
5990 /* Do not read more than the total content length of the
5991 * request.
7c673cae
FG
5992 */
5993 len64 = left_to_read;
5994 }
5995
5996 /* Return buffered data */
5997 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
5998 - conn->consumed_content;
5999 if (buffered_len > 0) {
6000 if (len64 < buffered_len) {
6001 buffered_len = len64;
6002 }
6003 body = conn->buf + conn->request_len + conn->consumed_content;
6004 memcpy(buf, body, (size_t)buffered_len);
6005 len64 -= buffered_len;
6006 conn->consumed_content += buffered_len;
6007 nread += buffered_len;
6008 buf = (char *)buf + buffered_len;
6009 }
6010
6011 /* We have returned all buffered data. Read new data from the remote
6012 * socket.
6013 */
6014 if ((n = pull_all(NULL, conn, (char *)buf, (int)len64)) >= 0) {
6015 nread += n;
6016 } else {
11fdf7f2 6017 nread = ((nread > 0) ? nread : n);
7c673cae
FG
6018 }
6019 }
6020 return (int)nread;
6021}
6022
6023
6024static char
6025mg_getc(struct mg_connection *conn)
6026{
6027 char c;
6028 if (conn == NULL) {
6029 return 0;
6030 }
7c673cae
FG
6031 if (mg_read_inner(conn, &c, 1) <= 0) {
6032 return (char)0;
6033 }
6034 return c;
6035}
6036
6037
6038int
6039mg_read(struct mg_connection *conn, void *buf, size_t len)
6040{
6041 if (len > INT_MAX) {
6042 len = INT_MAX;
6043 }
6044
6045 if (conn == NULL) {
6046 return 0;
6047 }
6048
6049 if (conn->is_chunked) {
6050 size_t all_read = 0;
6051
6052 while (len > 0) {
11fdf7f2 6053 if (conn->is_chunked == 3) {
7c673cae
FG
6054 /* No more data left to read */
6055 return 0;
6056 }
6057
6058 if (conn->chunk_remainder) {
6059 /* copy from the remainder of the last received chunk */
6060 long read_ret;
6061 size_t read_now =
6062 ((conn->chunk_remainder > len) ? (len)
6063 : (conn->chunk_remainder));
6064
6065 conn->content_len += (int)read_now;
6066 read_ret =
6067 mg_read_inner(conn, (char *)buf + all_read, read_now);
11fdf7f2
TL
6068
6069 if (read_ret < 1) {
6070 /* read error */
6071 return -1;
6072 }
6073
6074 all_read += (size_t)read_ret;
6075 conn->chunk_remainder -= (size_t)read_ret;
6076 len -= (size_t)read_ret;
7c673cae
FG
6077
6078 if (conn->chunk_remainder == 0) {
11fdf7f2
TL
6079 /* Add data bytes in the current chunk have been read,
6080 * so we are expecting \r\n now. */
6081 char x1, x2;
6082 conn->content_len += 2;
6083 x1 = mg_getc(conn);
6084 x2 = mg_getc(conn);
6085 if ((x1 != '\r') || (x2 != '\n')) {
7c673cae
FG
6086 /* Protocol violation */
6087 return -1;
6088 }
6089 }
6090
6091 } else {
6092 /* fetch a new chunk */
6093 int i = 0;
6094 char lenbuf[64];
6095 char *end = 0;
6096 unsigned long chunkSize = 0;
6097
6098 for (i = 0; i < ((int)sizeof(lenbuf) - 1); i++) {
11fdf7f2 6099 conn->content_len++;
7c673cae 6100 lenbuf[i] = mg_getc(conn);
11fdf7f2
TL
6101 if ((i > 0) && (lenbuf[i] == '\r')
6102 && (lenbuf[i - 1] != '\r')) {
7c673cae
FG
6103 continue;
6104 }
11fdf7f2
TL
6105 if ((i > 1) && (lenbuf[i] == '\n')
6106 && (lenbuf[i - 1] == '\r')) {
7c673cae
FG
6107 lenbuf[i + 1] = 0;
6108 chunkSize = strtoul(lenbuf, &end, 16);
6109 if (chunkSize == 0) {
6110 /* regular end of content */
11fdf7f2 6111 conn->is_chunked = 3;
7c673cae
FG
6112 }
6113 break;
6114 }
11fdf7f2 6115 if (!isxdigit(lenbuf[i])) {
7c673cae
FG
6116 /* illegal character for chunk length */
6117 return -1;
6118 }
6119 }
6120 if ((end == NULL) || (*end != '\r')) {
6121 /* chunksize not set correctly */
6122 return -1;
6123 }
6124 if (chunkSize == 0) {
6125 break;
6126 }
6127
6128 conn->chunk_remainder = chunkSize;
6129 }
6130 }
6131
6132 return (int)all_read;
6133 }
6134 return mg_read_inner(conn, buf, len);
6135}
6136
6137
6138int
6139mg_write(struct mg_connection *conn, const void *buf, size_t len)
6140{
6141 time_t now;
6142 int64_t n, total, allowed;
6143
6144 if (conn == NULL) {
6145 return 0;
6146 }
6147
6148 if (conn->throttle > 0) {
6149 if ((now = time(NULL)) != conn->last_throttle_time) {
6150 conn->last_throttle_time = now;
6151 conn->last_throttle_bytes = 0;
6152 }
6153 allowed = conn->throttle - conn->last_throttle_bytes;
6154 if (allowed > (int64_t)len) {
6155 allowed = (int64_t)len;
6156 }
6157 if ((total = push_all(conn->ctx,
6158 NULL,
6159 conn->client.sock,
6160 conn->ssl,
6161 (const char *)buf,
6162 (int64_t)allowed)) == allowed) {
6163 buf = (const char *)buf + total;
6164 conn->last_throttle_bytes += total;
11fdf7f2
TL
6165 while ((total < (int64_t)len) && (conn->ctx->stop_flag == 0)) {
6166 allowed = (conn->throttle > ((int64_t)len - total))
7c673cae
FG
6167 ? (int64_t)len - total
6168 : conn->throttle;
6169 if ((n = push_all(conn->ctx,
6170 NULL,
6171 conn->client.sock,
6172 conn->ssl,
6173 (const char *)buf,
6174 (int64_t)allowed)) != allowed) {
6175 break;
6176 }
6177 sleep(1);
6178 conn->last_throttle_bytes = allowed;
6179 conn->last_throttle_time = time(NULL);
6180 buf = (const char *)buf + n;
6181 total += n;
6182 }
6183 }
6184 } else {
6185 total = push_all(conn->ctx,
6186 NULL,
6187 conn->client.sock,
6188 conn->ssl,
6189 (const char *)buf,
6190 (int64_t)len);
6191 }
11fdf7f2
TL
6192 if (total > 0) {
6193 conn->num_bytes_sent += total;
6194 }
7c673cae
FG
6195 return (int)total;
6196}
6197
6198
11fdf7f2
TL
6199/* Send a chunk, if "Transfer-Encoding: chunked" is used */
6200int
6201mg_send_chunk(struct mg_connection *conn,
6202 const char *chunk,
6203 unsigned int chunk_len)
6204{
6205 char lenbuf[16];
6206 size_t lenbuf_len;
6207 int ret;
6208 int t;
6209
6210 /* First store the length information in a text buffer. */
6211 sprintf(lenbuf, "%x\r\n", chunk_len);
6212 lenbuf_len = strlen(lenbuf);
6213
6214 /* Then send length information, chunk and terminating \r\n. */
6215 ret = mg_write(conn, lenbuf, lenbuf_len);
6216 if (ret != (int)lenbuf_len) {
6217 return -1;
6218 }
6219 t = ret;
6220
6221 ret = mg_write(conn, chunk, chunk_len);
6222 if (ret != (int)chunk_len) {
6223 return -1;
6224 }
6225 t += ret;
6226
6227 ret = mg_write(conn, "\r\n", 2);
6228 if (ret != 2) {
6229 return -1;
6230 }
6231 t += ret;
6232
6233 return t;
6234}
6235
6236
7c673cae
FG
6237/* Alternative alloc_vprintf() for non-compliant C runtimes */
6238static int
6239alloc_vprintf2(char **buf, const char *fmt, va_list ap)
6240{
6241 va_list ap_copy;
6242 size_t size = MG_BUF_LEN / 4;
6243 int len = -1;
6244
6245 *buf = NULL;
6246 while (len < 0) {
6247 if (*buf) {
6248 mg_free(*buf);
6249 }
6250
6251 size *= 4;
6252 *buf = (char *)mg_malloc(size);
6253 if (!*buf) {
6254 break;
6255 }
6256
6257 va_copy(ap_copy, ap);
6258 len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy);
6259 va_end(ap_copy);
6260 (*buf)[size - 1] = 0;
6261 }
6262
6263 return len;
6264}
6265
6266
6267/* Print message to buffer. If buffer is large enough to hold the message,
11fdf7f2
TL
6268 * return buffer. If buffer is to small, allocate large enough buffer on
6269 * heap,
7c673cae
FG
6270 * and return allocated buffer. */
6271static int
6272alloc_vprintf(char **out_buf,
6273 char *prealloc_buf,
6274 size_t prealloc_size,
6275 const char *fmt,
6276 va_list ap)
6277{
6278 va_list ap_copy;
6279 int len;
6280
6281 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
6282 * buffer is too small. Also, older versions of msvcrt.dll do not have
6283 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
6284 * Therefore, we make two passes: on first pass, get required message
6285 * length.
6286 * On second pass, actually print the message. */
6287 va_copy(ap_copy, ap);
6288 len = vsnprintf_impl(NULL, 0, fmt, ap_copy);
6289 va_end(ap_copy);
6290
6291 if (len < 0) {
6292 /* C runtime is not standard compliant, vsnprintf() returned -1.
11fdf7f2
TL
6293 * Switch to alternative code path that uses incremental
6294 * allocations.
7c673cae
FG
6295 */
6296 va_copy(ap_copy, ap);
11fdf7f2 6297 len = alloc_vprintf2(out_buf, fmt, ap_copy);
7c673cae
FG
6298 va_end(ap_copy);
6299
6300 } else if ((size_t)(len) >= prealloc_size) {
6301 /* The pre-allocated buffer not large enough. */
6302 /* Allocate a new buffer. */
6303 *out_buf = (char *)mg_malloc((size_t)(len) + 1);
6304 if (!*out_buf) {
6305 /* Allocation failed. Return -1 as "out of memory" error. */
6306 return -1;
6307 }
6308 /* Buffer allocation successful. Store the string there. */
6309 va_copy(ap_copy, ap);
6310 IGNORE_UNUSED_RESULT(
6311 vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy));
6312 va_end(ap_copy);
6313
6314 } else {
6315 /* The pre-allocated buffer is large enough.
6316 * Use it to store the string and return the address. */
6317 va_copy(ap_copy, ap);
6318 IGNORE_UNUSED_RESULT(
6319 vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy));
6320 va_end(ap_copy);
6321 *out_buf = prealloc_buf;
6322 }
6323
6324 return len;
6325}
6326
6327
6328static int
6329mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
6330{
6331 char mem[MG_BUF_LEN];
6332 char *buf = NULL;
6333 int len;
6334
6335 if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) {
6336 len = mg_write(conn, buf, (size_t)len);
6337 }
11fdf7f2 6338 if ((buf != mem) && (buf != NULL)) {
7c673cae
FG
6339 mg_free(buf);
6340 }
6341
6342 return len;
6343}
6344
6345
6346int
6347mg_printf(struct mg_connection *conn, const char *fmt, ...)
6348{
6349 va_list ap;
6350 int result;
6351
6352 va_start(ap, fmt);
6353 result = mg_vprintf(conn, fmt, ap);
6354 va_end(ap);
6355
6356 return result;
6357}
6358
6359
6360int
6361mg_url_decode(const char *src,
6362 int src_len,
6363 char *dst,
6364 int dst_len,
6365 int is_form_url_encoded)
6366{
6367 int i, j, a, b;
11fdf7f2 6368#define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
7c673cae 6369
11fdf7f2
TL
6370 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
6371 if ((i < src_len - 2) && (src[i] == '%')
7c673cae
FG
6372 && isxdigit(*(const unsigned char *)(src + i + 1))
6373 && isxdigit(*(const unsigned char *)(src + i + 2))) {
6374 a = tolower(*(const unsigned char *)(src + i + 1));
6375 b = tolower(*(const unsigned char *)(src + i + 2));
6376 dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
6377 i += 2;
11fdf7f2 6378 } else if (is_form_url_encoded && (src[i] == '+')) {
7c673cae
FG
6379 dst[j] = ' ';
6380 } else {
6381 dst[j] = src[i];
6382 }
6383 }
6384
6385 dst[j] = '\0'; /* Null-terminate the destination */
6386
11fdf7f2 6387 return (i >= src_len) ? j : -1;
7c673cae
FG
6388}
6389
6390
6391int
6392mg_get_var(const char *data,
6393 size_t data_len,
6394 const char *name,
6395 char *dst,
6396 size_t dst_len)
6397{
6398 return mg_get_var2(data, data_len, name, dst, dst_len, 0);
6399}
6400
6401
6402int
6403mg_get_var2(const char *data,
6404 size_t data_len,
6405 const char *name,
6406 char *dst,
6407 size_t dst_len,
6408 size_t occurrence)
6409{
6410 const char *p, *e, *s;
6411 size_t name_len;
6412 int len;
6413
11fdf7f2 6414 if ((dst == NULL) || (dst_len == 0)) {
7c673cae 6415 len = -2;
11fdf7f2 6416 } else if ((data == NULL) || (name == NULL) || (data_len == 0)) {
7c673cae
FG
6417 len = -1;
6418 dst[0] = '\0';
6419 } else {
6420 name_len = strlen(name);
6421 e = data + data_len;
6422 len = -1;
6423 dst[0] = '\0';
6424
6425 /* data is "var1=val1&var2=val2...". Find variable first */
6426 for (p = data; p + name_len < e; p++) {
11fdf7f2 6427 if (((p == data) || (p[-1] == '&')) && (p[name_len] == '=')
7c673cae
FG
6428 && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
6429 /* Point p to variable value */
6430 p += name_len + 1;
6431
6432 /* Point s to the end of the value */
6433 s = (const char *)memchr(p, '&', (size_t)(e - p));
6434 if (s == NULL) {
6435 s = e;
6436 }
6437 /* assert(s >= p); */
6438 if (s < p) {
6439 return -3;
6440 }
6441
6442 /* Decode variable into destination buffer */
6443 len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
6444
6445 /* Redirect error code from -1 to -2 (destination buffer too
6446 * small). */
6447 if (len == -1) {
6448 len = -2;
6449 }
6450 break;
6451 }
6452 }
6453 }
6454
6455 return len;
6456}
6457
6458
11fdf7f2 6459/* HCP24: some changes to compare hole var_name */
7c673cae
FG
6460int
6461mg_get_cookie(const char *cookie_header,
6462 const char *var_name,
6463 char *dst,
6464 size_t dst_size)
6465{
6466 const char *s, *p, *end;
6467 int name_len, len = -1;
6468
11fdf7f2
TL
6469 if ((dst == NULL) || (dst_size == 0)) {
6470 return -2;
6471 }
6472
6473 dst[0] = '\0';
6474 if ((var_name == NULL) || ((s = cookie_header) == NULL)) {
6475 return -1;
6476 }
7c673cae 6477
11fdf7f2
TL
6478 name_len = (int)strlen(var_name);
6479 end = s + strlen(s);
6480 for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
6481 if (s[name_len] == '=') {
6482 /* HCP24: now check is it a substring or a full cookie name */
6483 if ((s == cookie_header) || (s[-1] == ' ')) {
7c673cae
FG
6484 s += name_len + 1;
6485 if ((p = strchr(s, ' ')) == NULL) {
6486 p = end;
6487 }
6488 if (p[-1] == ';') {
6489 p--;
6490 }
11fdf7f2 6491 if ((*s == '"') && (p[-1] == '"') && (p > s + 1)) {
7c673cae
FG
6492 s++;
6493 p--;
6494 }
6495 if ((size_t)(p - s) < dst_size) {
6496 len = (int)(p - s);
6497 mg_strlcpy(dst, s, (size_t)len + 1);
6498 } else {
6499 len = -3;
6500 }
6501 break;
6502 }
6503 }
6504 }
6505 return len;
6506}
6507
6508
6509#if defined(USE_WEBSOCKET) || defined(USE_LUA)
6510static void
6511base64_encode(const unsigned char *src, int src_len, char *dst)
6512{
6513 static const char *b64 =
6514 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6515 int i, j, a, b, c;
6516
6517 for (i = j = 0; i < src_len; i += 3) {
6518 a = src[i];
11fdf7f2
TL
6519 b = ((i + 1) >= src_len) ? 0 : src[i + 1];
6520 c = ((i + 2) >= src_len) ? 0 : src[i + 2];
7c673cae
FG
6521
6522 dst[j++] = b64[a >> 2];
6523 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
6524 if (i + 1 < src_len) {
6525 dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
6526 }
6527 if (i + 2 < src_len) {
6528 dst[j++] = b64[c & 63];
6529 }
6530 }
6531 while (j % 4 != 0) {
6532 dst[j++] = '=';
6533 }
6534 dst[j++] = '\0';
6535}
6536#endif
6537
6538
6539#if defined(USE_LUA)
6540static unsigned char
6541b64reverse(char letter)
6542{
11fdf7f2 6543 if ((letter >= 'A') && (letter <= 'Z')) {
7c673cae
FG
6544 return letter - 'A';
6545 }
11fdf7f2 6546 if ((letter >= 'a') && (letter <= 'z')) {
7c673cae
FG
6547 return letter - 'a' + 26;
6548 }
11fdf7f2 6549 if ((letter >= '0') && (letter <= '9')) {
7c673cae
FG
6550 return letter - '0' + 52;
6551 }
6552 if (letter == '+') {
6553 return 62;
6554 }
6555 if (letter == '/') {
6556 return 63;
6557 }
6558 if (letter == '=') {
6559 return 255; /* normal end */
6560 }
6561 return 254; /* error */
6562}
6563
6564
6565static int
6566base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
6567{
6568 int i;
6569 unsigned char a, b, c, d;
6570
6571 *dst_len = 0;
6572
6573 for (i = 0; i < src_len; i += 4) {
6574 a = b64reverse(src[i]);
6575 if (a >= 254) {
6576 return i;
6577 }
6578
11fdf7f2 6579 b = b64reverse(((i + 1) >= src_len) ? 0 : src[i + 1]);
7c673cae
FG
6580 if (b >= 254) {
6581 return i + 1;
6582 }
6583
11fdf7f2 6584 c = b64reverse(((i + 2) >= src_len) ? 0 : src[i + 2]);
7c673cae
FG
6585 if (c == 254) {
6586 return i + 2;
6587 }
6588
11fdf7f2 6589 d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
7c673cae
FG
6590 if (d == 254) {
6591 return i + 3;
6592 }
6593
6594 dst[(*dst_len)++] = (a << 2) + (b >> 4);
6595 if (c != 255) {
6596 dst[(*dst_len)++] = (b << 4) + (c >> 2);
6597 if (d != 255) {
6598 dst[(*dst_len)++] = (c << 6) + d;
6599 }
6600 }
6601 }
6602 return -1;
6603}
6604#endif
6605
6606
6607static int
6608is_put_or_delete_method(const struct mg_connection *conn)
6609{
6610 if (conn) {
6611 const char *s = conn->request_info.request_method;
11fdf7f2
TL
6612 return (s != NULL) && (!strcmp(s, "PUT") || !strcmp(s, "DELETE")
6613 || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH"));
6614 }
6615 return 0;
6616}
6617
6618
6619#if !defined(NO_FILES)
6620static int
6621extention_matches_script(
6622 struct mg_connection *conn, /* in: request (must be valid) */
6623 const char *filename /* in: filename (must be valid) */
6624 )
6625{
6626#if !defined(NO_CGI)
6627 if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
6628 strlen(conn->ctx->config[CGI_EXTENSIONS]),
6629 filename) > 0) {
6630 return 1;
6631 }
6632#endif
6633#if defined(USE_LUA)
6634 if (match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
6635 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
6636 filename) > 0) {
6637 return 1;
6638 }
6639#endif
6640#if defined(USE_DUKTAPE)
6641 if (match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
6642 strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
6643 filename) > 0) {
6644 return 1;
7c673cae 6645 }
11fdf7f2
TL
6646#endif
6647 /* filename and conn could be unused, if all preocessor conditions
6648 * are false (no script language supported). */
6649 (void)filename;
6650 (void)conn;
6651
7c673cae
FG
6652 return 0;
6653}
6654
6655
11fdf7f2
TL
6656/* For given directory path, substitute it to valid index file.
6657 * Return 1 if index file has been found, 0 if not found.
6658 * If the file is found, it's stats is returned in stp. */
6659static int
6660substitute_index_file(struct mg_connection *conn,
6661 char *path,
6662 size_t path_len,
6663 struct mg_file_stat *filestat)
6664{
6665 const char *list = conn->ctx->config[INDEX_FILES];
6666 struct vec filename_vec;
6667 size_t n = strlen(path);
6668 int found = 0;
6669
6670 /* The 'path' given to us points to the directory. Remove all trailing
6671 * directory separator characters from the end of the path, and
6672 * then append single directory separator character. */
6673 while ((n > 0) && (path[n - 1] == '/')) {
6674 n--;
6675 }
6676 path[n] = '/';
6677
6678 /* Traverse index files list. For each entry, append it to the given
6679 * path and see if the file exists. If it exists, break the loop */
6680 while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
6681 /* Ignore too long entries that may overflow path buffer */
6682 if (filename_vec.len > (path_len - (n + 2))) {
6683 continue;
6684 }
6685
6686 /* Prepare full path to the index file */
6687 mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
6688
6689 /* Does it exist? */
6690 if (mg_stat(conn, path, filestat)) {
6691 /* Yes it does, break the loop */
6692 found = 1;
6693 break;
6694 }
6695 }
6696
6697 /* If no index file exists, restore directory path */
6698 if (!found) {
6699 path[n] = '\0';
6700 }
6701
6702 return found;
6703}
6704#endif
6705
6706
7c673cae 6707static void
11fdf7f2
TL
6708interpret_uri(struct mg_connection *conn, /* in/out: request (must be valid) */
6709 char *filename, /* out: filename */
6710 size_t filename_buf_len, /* in: size of filename buffer */
6711 struct mg_file_stat *filestat, /* out: file status structure */
6712 int *is_found, /* out: file found (directly) */
6713 int *is_script_resource, /* out: handled by a script? */
6714 int *is_websocket_request, /* out: websocket connetion? */
6715 int *is_put_or_delete_request /* out: put/delete a file? */
7c673cae
FG
6716 )
6717{
11fdf7f2 6718 char const *accept_encoding;
7c673cae
FG
6719
6720#if !defined(NO_FILES)
6721 const char *uri = conn->request_info.local_uri;
6722 const char *root = conn->ctx->config[DOCUMENT_ROOT];
6723 const char *rewrite;
6724 struct vec a, b;
6725 int match_len;
6726 char gz_path[PATH_MAX];
7c673cae 6727 int truncated;
11fdf7f2
TL
6728#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
6729 char *tmp_str;
6730 size_t tmp_str_len, sep_pos;
6731 int allow_substitute_script_subresources;
7c673cae
FG
6732#endif
6733#else
6734 (void)filename_buf_len; /* unused if NO_FILES is defined */
6735#endif
6736
11fdf7f2
TL
6737 /* Step 1: Set all initially unknown outputs to zero */
6738 memset(filestat, 0, sizeof(*filestat));
7c673cae
FG
6739 *filename = 0;
6740 *is_found = 0;
6741 *is_script_resource = 0;
11fdf7f2
TL
6742
6743 /* Step 2: Check if the request attempts to modify the file system */
7c673cae
FG
6744 *is_put_or_delete_request = is_put_or_delete_method(conn);
6745
11fdf7f2
TL
6746/* Step 3: Check if it is a websocket request, and modify the document
6747 * root if required */
7c673cae
FG
6748#if defined(USE_WEBSOCKET)
6749 *is_websocket_request = is_websocket_protocol(conn);
6750#if !defined(NO_FILES)
6751 if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
6752 root = conn->ctx->config[WEBSOCKET_ROOT];
6753 }
6754#endif /* !NO_FILES */
6755#else /* USE_WEBSOCKET */
6756 *is_websocket_request = 0;
6757#endif /* USE_WEBSOCKET */
6758
11fdf7f2
TL
6759 /* Step 4: Check if gzip encoded response is allowed */
6760 conn->accept_gzip = 0;
6761 if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
6762 if (strstr(accept_encoding, "gzip") != NULL) {
6763 conn->accept_gzip = 1;
6764 }
6765 }
6766
7c673cae 6767#if !defined(NO_FILES)
11fdf7f2 6768 /* Step 5: If there is no root directory, don't look for files. */
7c673cae
FG
6769 /* Note that root == NULL is a regular use case here. This occurs,
6770 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
6771 * config is not required. */
6772 if (root == NULL) {
6773 /* all file related outputs have already been set to 0, just return
6774 */
6775 return;
6776 }
6777
11fdf7f2
TL
6778 /* Step 6: Determine the local file path from the root path and the
6779 * request uri. */
6780 /* Using filename_buf_len - 1 because memmove() for PATH_INFO may shift
6781 * part of the path one byte on the right. */
7c673cae
FG
6782 mg_snprintf(
6783 conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
6784
6785 if (truncated) {
6786 goto interpret_cleanup;
6787 }
6788
11fdf7f2
TL
6789 /* Step 7: URI rewriting */
6790 rewrite = conn->ctx->config[URL_REWRITE_PATTERN];
7c673cae
FG
6791 while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
6792 if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
6793 mg_snprintf(conn,
6794 &truncated,
6795 filename,
6796 filename_buf_len - 1,
6797 "%.*s%s",
6798 (int)b.len,
6799 b.ptr,
6800 uri + match_len);
6801 break;
6802 }
6803 }
6804
6805 if (truncated) {
6806 goto interpret_cleanup;
6807 }
6808
11fdf7f2 6809 /* Step 8: Check if the file exists at the server */
7c673cae
FG
6810 /* Local file path and name, corresponding to requested URI
6811 * is now stored in "filename" variable. */
11fdf7f2
TL
6812 if (mg_stat(conn, filename, filestat)) {
6813 /* 8.1: File exists. */
6814 *is_found = 1;
6815
6816 /* 8.2: Check if it is a script type. */
6817 if (extention_matches_script(conn, filename)) {
6818 /* The request addresses a CGI resource, Lua script or
6819 * server-side javascript.
6820 * The URI corresponds to the script itself (like
6821 * /path/script.cgi), and there is no additional resource
6822 * path (like /path/script.cgi/something).
7c673cae
FG
6823 * Requests that modify (replace or delete) a resource, like
6824 * PUT and DELETE requests, should replace/delete the script
6825 * file.
6826 * Requests that read or write from/to a resource, like GET and
6827 * POST requests, should call the script and return the
6828 * generated response. */
11fdf7f2
TL
6829 *is_script_resource = (!*is_put_or_delete_request);
6830 }
6831
6832 /* 8.3: If the request target is a directory, there could be
6833 * a substitute file (index.html, index.cgi, ...). */
6834 if (filestat->is_directory) {
6835 /* Use a local copy here, since substitute_index_file will
6836 * change the content of the file status */
6837 struct mg_file_stat tmp_filestat;
6838 memset(&tmp_filestat, 0, sizeof(tmp_filestat));
6839
6840 if (substitute_index_file(
6841 conn, filename, filename_buf_len, &tmp_filestat)) {
6842
6843 /* Substitute file found. Copy stat to the output, then
6844 * check if the file is a script file */
6845 *filestat = tmp_filestat;
6846
6847 if (extention_matches_script(conn, filename)) {
6848 /* Substitute file is a script file */
6849 *is_script_resource = 1;
6850 } else {
6851 /* Substitute file is a regular file */
6852 *is_script_resource = 0;
6853 *is_found = (mg_stat(conn, filename, filestat) ? 1 : 0);
6854 }
6855 }
6856 /* If there is no substitute file, the server could return
6857 * a directory listing in a later step */
7c673cae 6858 }
7c673cae
FG
6859 return;
6860 }
6861
11fdf7f2 6862 /* Step 9: Check for zipped files: */
7c673cae
FG
6863 /* If we can't find the actual file, look for the file
6864 * with the same name but a .gz extension. If we find it,
6865 * use that and set the gzipped flag in the file struct
6866 * to indicate that the response need to have the content-
6867 * encoding: gzip header.
6868 * We can only do this if the browser declares support. */
11fdf7f2
TL
6869 if (conn->accept_gzip) {
6870 mg_snprintf(
6871 conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename);
7c673cae 6872
11fdf7f2
TL
6873 if (truncated) {
6874 goto interpret_cleanup;
6875 }
7c673cae 6876
11fdf7f2
TL
6877 if (mg_stat(conn, gz_path, filestat)) {
6878 if (filestat) {
6879 filestat->is_gzipped = 1;
6880 *is_found = 1;
7c673cae 6881 }
11fdf7f2
TL
6882 /* Currently gz files can not be scripts. */
6883 return;
7c673cae
FG
6884 }
6885 }
6886
6887#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
11fdf7f2 6888 /* Step 10: Script resources may handle sub-resources */
7c673cae 6889 /* Support PATH_INFO for CGI scripts. */
11fdf7f2
TL
6890 tmp_str_len = strlen(filename);
6891 tmp_str = (char *)mg_malloc_ctx(tmp_str_len + PATH_MAX + 1, conn->ctx);
6892 if (!tmp_str) {
6893 /* Out of memory */
6894 goto interpret_cleanup;
6895 }
6896 memcpy(tmp_str, filename, tmp_str_len + 1);
6897
6898 /* Check config, if index scripts may have sub-resources */
6899 allow_substitute_script_subresources =
6900 !mg_strcasecmp(conn->ctx->config[ALLOW_INDEX_SCRIPT_SUB_RES], "yes");
6901
6902 sep_pos = tmp_str_len;
6903 while (sep_pos > 0) {
6904 sep_pos--;
6905 if (tmp_str[sep_pos] == '/') {
6906 int is_script = 0, does_exist = 0;
6907
6908 tmp_str[sep_pos] = 0;
6909 if (tmp_str[0]) {
6910 is_script = extention_matches_script(conn, tmp_str);
6911 does_exist = mg_stat(conn, tmp_str, filestat);
6912 }
6913
6914 if (does_exist && is_script) {
6915 filename[sep_pos] = 0;
6916 memmove(filename + sep_pos + 2,
6917 filename + sep_pos + 1,
6918 strlen(filename + sep_pos + 1) + 1);
6919 conn->path_info = filename + sep_pos + 1;
6920 filename[sep_pos + 1] = '/';
7c673cae 6921 *is_script_resource = 1;
11fdf7f2 6922 *is_found = 1;
7c673cae 6923 break;
7c673cae 6924 }
11fdf7f2
TL
6925
6926 if (allow_substitute_script_subresources) {
6927 if (substitute_index_file(
6928 conn, tmp_str, tmp_str_len + PATH_MAX, filestat)) {
6929
6930 /* some intermediate directory has an index file */
6931 if (extention_matches_script(conn, tmp_str)) {
6932
6933 char *tmp_str2;
6934
6935 DEBUG_TRACE("Substitute script %s serving path %s",
6936 tmp_str,
6937 filename);
6938
6939 /* this index file is a script */
6940 tmp_str2 = mg_strdup(filename + sep_pos + 1);
6941 mg_snprintf(conn,
6942 &truncated,
6943 filename,
6944 filename_buf_len,
6945 "%s//%s",
6946 tmp_str,
6947 tmp_str2);
6948 mg_free(tmp_str2);
6949
6950 if (truncated) {
6951 mg_free(tmp_str);
6952 goto interpret_cleanup;
6953 }
6954 sep_pos = strlen(tmp_str);
6955 filename[sep_pos] = 0;
6956 conn->path_info = filename + sep_pos + 1;
6957 *is_script_resource = 1;
6958 *is_found = 1;
6959 break;
6960
6961 } else {
6962
6963 DEBUG_TRACE("Substitute file %s serving path %s",
6964 tmp_str,
6965 filename);
6966
6967 /* non-script files will not have sub-resources */
6968 filename[sep_pos] = 0;
6969 conn->path_info = 0;
6970 *is_script_resource = 0;
6971 *is_found = 0;
6972 break;
6973 }
6974 }
6975 }
6976
6977 tmp_str[sep_pos] = '/';
7c673cae
FG
6978 }
6979 }
11fdf7f2
TL
6980
6981 mg_free(tmp_str);
6982
7c673cae
FG
6983#endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
6984#endif /* !defined(NO_FILES) */
6985 return;
6986
6987#if !defined(NO_FILES)
6988/* Reset all outputs */
6989interpret_cleanup:
11fdf7f2 6990 memset(filestat, 0, sizeof(*filestat));
7c673cae
FG
6991 *filename = 0;
6992 *is_found = 0;
6993 *is_script_resource = 0;
6994 *is_websocket_request = 0;
6995 *is_put_or_delete_request = 0;
6996#endif /* !defined(NO_FILES) */
6997}
6998
6999
7000/* Check whether full request is buffered. Return:
11fdf7f2
TL
7001 * -1 if request or response is malformed
7002 * 0 if request or response is not yet fully buffered
7c673cae
FG
7003 * >0 actual request length, including last \r\n\r\n */
7004static int
11fdf7f2 7005get_http_header_len(const char *buf, int buflen)
7c673cae 7006{
11fdf7f2
TL
7007 int i;
7008 for (i = 0; i < buflen; i++) {
7009 /* Do an unsigned comparison in some conditions below */
7010 const unsigned char c = ((const unsigned char *)buf)[i];
7c673cae 7011
11fdf7f2
TL
7012 if ((c < 128) && ((char)c != '\r') && ((char)c != '\n')
7013 && !isprint(c)) {
7014 /* abort scan as soon as one malformed character is found */
7015 return -1;
7016 }
7017
7018 if (i < buflen - 1) {
7019 if ((buf[i] == '\n') && (buf[i + 1] == '\n')) {
7020 /* Two newline, no carriage return - not standard compliant,
7021 * but
7022 * it
7023 * should be accepted */
7024 return i + 2;
7025 }
7c673cae
FG
7026 }
7027
11fdf7f2
TL
7028 if (i < buflen - 3) {
7029 if ((buf[i] == '\r') && (buf[i + 1] == '\n') && (buf[i + 2] == '\r')
7030 && (buf[i + 3] == '\n')) {
7031 /* Two \r\n - standard compliant */
7032 return i + 4;
7033 }
7c673cae
FG
7034 }
7035 }
7036
11fdf7f2 7037 return 0;
7c673cae
FG
7038}
7039
7040
7041#if !defined(NO_CACHING)
7042/* Convert month to the month number. Return -1 on error, or month number */
7043static int
7044get_month_index(const char *s)
7045{
7046 size_t i;
7047
7048 for (i = 0; i < ARRAY_SIZE(month_names); i++) {
7049 if (!strcmp(s, month_names[i])) {
7050 return (int)i;
7051 }
7052 }
7053
7054 return -1;
7055}
7056
7057
7058/* Parse UTC date-time string, and return the corresponding time_t value. */
7059static time_t
7060parse_date_string(const char *datetime)
7061{
7062 char month_str[32] = {0};
7063 int second, minute, hour, day, month, year;
7064 time_t result = (time_t)0;
7065 struct tm tm;
7066
7067 if ((sscanf(datetime,
7068 "%d/%3s/%d %d:%d:%d",
7069 &day,
7070 month_str,
7071 &year,
7072 &hour,
7073 &minute,
7074 &second) == 6) || (sscanf(datetime,
7075 "%d %3s %d %d:%d:%d",
7076 &day,
7077 month_str,
7078 &year,
7079 &hour,
7080 &minute,
7081 &second) == 6)
7082 || (sscanf(datetime,
7083 "%*3s, %d %3s %d %d:%d:%d",
7084 &day,
7085 month_str,
7086 &year,
7087 &hour,
7088 &minute,
7089 &second) == 6) || (sscanf(datetime,
7090 "%d-%3s-%d %d:%d:%d",
7091 &day,
7092 month_str,
7093 &year,
7094 &hour,
7095 &minute,
7096 &second) == 6)) {
7097 month = get_month_index(month_str);
7098 if ((month >= 0) && (year >= 1970)) {
7099 memset(&tm, 0, sizeof(tm));
7100 tm.tm_year = year - 1900;
7101 tm.tm_mon = month;
7102 tm.tm_mday = day;
7103 tm.tm_hour = hour;
7104 tm.tm_min = minute;
7105 tm.tm_sec = second;
7106 result = timegm(&tm);
7107 }
7108 }
7109
7110 return result;
7111}
7112#endif /* !NO_CACHING */
7113
7114
7115/* Protect against directory disclosure attack by removing '..',
7116 * excessive '/' and '\' characters */
7117static void
7118remove_double_dots_and_double_slashes(char *s)
7119{
7120 char *p = s;
7121
11fdf7f2
TL
7122 while ((s[0] == '.') && (s[1] == '.')) {
7123 s++;
7124 }
7125
7c673cae
FG
7126 while (*s != '\0') {
7127 *p++ = *s++;
11fdf7f2 7128 if ((s[-1] == '/') || (s[-1] == '\\')) {
7c673cae
FG
7129 /* Skip all following slashes, backslashes and double-dots */
7130 while (s[0] != '\0') {
11fdf7f2 7131 if ((s[0] == '/') || (s[0] == '\\')) {
7c673cae 7132 s++;
11fdf7f2 7133 } else if ((s[0] == '.') && (s[1] == '.')) {
7c673cae
FG
7134 s += 2;
7135 } else {
7136 break;
7137 }
7138 }
7139 }
7140 }
7141 *p = '\0';
7142}
7143
7144
7145static const struct {
7146 const char *extension;
7147 size_t ext_len;
7148 const char *mime_type;
7149} builtin_mime_types[] = {
11fdf7f2
TL
7150 /* IANA registered MIME types
7151 * (http://www.iana.org/assignments/media-types)
7c673cae
FG
7152 * application types */
7153 {".doc", 4, "application/msword"},
7154 {".eps", 4, "application/postscript"},
7155 {".exe", 4, "application/octet-stream"},
7156 {".js", 3, "application/javascript"},
7157 {".json", 5, "application/json"},
7158 {".pdf", 4, "application/pdf"},
7159 {".ps", 3, "application/postscript"},
7160 {".rtf", 4, "application/rtf"},
7161 {".xhtml", 6, "application/xhtml+xml"},
7162 {".xsl", 4, "application/xml"},
7163 {".xslt", 5, "application/xml"},
7164
7165 /* fonts */
7166 {".ttf", 4, "application/font-sfnt"},
7167 {".cff", 4, "application/font-sfnt"},
7168 {".otf", 4, "application/font-sfnt"},
7169 {".aat", 4, "application/font-sfnt"},
7170 {".sil", 4, "application/font-sfnt"},
7171 {".pfr", 4, "application/font-tdpfr"},
7172 {".woff", 5, "application/font-woff"},
7173
7174 /* audio */
7175 {".mp3", 4, "audio/mpeg"},
7176 {".oga", 4, "audio/ogg"},
7177 {".ogg", 4, "audio/ogg"},
7178
7179 /* image */
7180 {".gif", 4, "image/gif"},
7181 {".ief", 4, "image/ief"},
7182 {".jpeg", 5, "image/jpeg"},
7183 {".jpg", 4, "image/jpeg"},
7184 {".jpm", 4, "image/jpm"},
7185 {".jpx", 4, "image/jpx"},
7186 {".png", 4, "image/png"},
7187 {".svg", 4, "image/svg+xml"},
7188 {".tif", 4, "image/tiff"},
7189 {".tiff", 5, "image/tiff"},
7190
7191 /* model */
7192 {".wrl", 4, "model/vrml"},
7193
7194 /* text */
7195 {".css", 4, "text/css"},
7196 {".csv", 4, "text/csv"},
7197 {".htm", 4, "text/html"},
7198 {".html", 5, "text/html"},
7199 {".sgm", 4, "text/sgml"},
7200 {".shtm", 5, "text/html"},
7201 {".shtml", 6, "text/html"},
7202 {".txt", 4, "text/plain"},
7203 {".xml", 4, "text/xml"},
7204
7205 /* video */
7206 {".mov", 4, "video/quicktime"},
7207 {".mp4", 4, "video/mp4"},
7208 {".mpeg", 5, "video/mpeg"},
7209 {".mpg", 4, "video/mpeg"},
7210 {".ogv", 4, "video/ogg"},
7211 {".qt", 3, "video/quicktime"},
7212
7213 /* not registered types
7214 * (http://reference.sitepoint.com/html/mime-types-full,
7215 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
7216 {".arj", 4, "application/x-arj-compressed"},
7217 {".gz", 3, "application/x-gunzip"},
7218 {".rar", 4, "application/x-arj-compressed"},
7219 {".swf", 4, "application/x-shockwave-flash"},
7220 {".tar", 4, "application/x-tar"},
7221 {".tgz", 4, "application/x-tar-gz"},
7222 {".torrent", 8, "application/x-bittorrent"},
7223 {".ppt", 4, "application/x-mspowerpoint"},
7224 {".xls", 4, "application/x-msexcel"},
7225 {".zip", 4, "application/x-zip-compressed"},
7226 {".aac",
7227 4,
7228 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
7229 {".aif", 4, "audio/x-aif"},
7230 {".m3u", 4, "audio/x-mpegurl"},
7231 {".mid", 4, "audio/x-midi"},
7232 {".ra", 3, "audio/x-pn-realaudio"},
7233 {".ram", 4, "audio/x-pn-realaudio"},
7234 {".wav", 4, "audio/x-wav"},
7235 {".bmp", 4, "image/bmp"},
7236 {".ico", 4, "image/x-icon"},
7237 {".pct", 4, "image/x-pct"},
7238 {".pict", 5, "image/pict"},
7239 {".rgb", 4, "image/x-rgb"},
7240 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
7241 {".asf", 4, "video/x-ms-asf"},
7242 {".avi", 4, "video/x-msvideo"},
7243 {".m4v", 4, "video/x-m4v"},
7244 {NULL, 0, NULL}};
7245
7246
7247const char *
7248mg_get_builtin_mime_type(const char *path)
7249{
7250 const char *ext;
7251 size_t i, path_len;
7252
7253 path_len = strlen(path);
7254
7255 for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
7256 ext = path + (path_len - builtin_mime_types[i].ext_len);
11fdf7f2
TL
7257 if ((path_len > builtin_mime_types[i].ext_len)
7258 && (mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0)) {
7c673cae
FG
7259 return builtin_mime_types[i].mime_type;
7260 }
7261 }
7262
7263 return "text/plain";
7264}
7265
7266
7267/* Look at the "path" extension and figure what mime type it has.
7268 * Store mime type in the vector. */
7269static void
7270get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
7271{
7272 struct vec ext_vec, mime_vec;
7273 const char *list, *ext;
7274 size_t path_len;
7275
7276 path_len = strlen(path);
7277
11fdf7f2
TL
7278 if ((ctx == NULL) || (vec == NULL)) {
7279 if (vec != NULL) {
7280 memset(vec, '\0', sizeof(struct vec));
7281 }
7c673cae
FG
7282 return;
7283 }
7284
7285 /* Scan user-defined mime types first, in case user wants to
7286 * override default mime types. */
7287 list = ctx->config[EXTRA_MIME_TYPES];
7288 while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
7289 /* ext now points to the path suffix */
7290 ext = path + path_len - ext_vec.len;
7291 if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
7292 *vec = mime_vec;
7293 return;
7294 }
7295 }
7296
7297 vec->ptr = mg_get_builtin_mime_type(path);
7298 vec->len = strlen(vec->ptr);
7299}
7300
7301
7302/* Stringify binary data. Output buffer must be twice as big as input,
7303 * because each byte takes 2 bytes in string representation */
7304static void
7305bin2str(char *to, const unsigned char *p, size_t len)
7306{
7307 static const char *hex = "0123456789abcdef";
7308
7309 for (; len--; p++) {
7310 *to++ = hex[p[0] >> 4];
7311 *to++ = hex[p[0] & 0x0f];
7312 }
7313 *to = '\0';
7314}
7315
7316
11fdf7f2
TL
7317/* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
7318 */
7c673cae
FG
7319char *
7320mg_md5(char buf[33], ...)
7321{
7322 md5_byte_t hash[16];
7323 const char *p;
7324 va_list ap;
7325 md5_state_t ctx;
7326
7327 md5_init(&ctx);
7328
7329 va_start(ap, buf);
7330 while ((p = va_arg(ap, const char *)) != NULL) {
7331 md5_append(&ctx, (const md5_byte_t *)p, strlen(p));
7332 }
7333 va_end(ap);
7334
7335 md5_finish(&ctx, hash);
7336 bin2str(buf, hash, sizeof(hash));
7337 return buf;
7338}
7339
7340
7341/* Check the user's password, return 1 if OK */
7342static int
7343check_password(const char *method,
7344 const char *ha1,
7345 const char *uri,
7346 const char *nonce,
7347 const char *nc,
7348 const char *cnonce,
7349 const char *qop,
7350 const char *response)
7351{
7352 char ha2[32 + 1], expected_response[32 + 1];
7353
7354 /* Some of the parameters may be NULL */
11fdf7f2
TL
7355 if ((method == NULL) || (nonce == NULL) || (nc == NULL) || (cnonce == NULL)
7356 || (qop == NULL) || (response == NULL)) {
7c673cae
FG
7357 return 0;
7358 }
7359
7360 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
7361 if (strlen(response) != 32) {
7362 return 0;
7363 }
7364
7365 mg_md5(ha2, method, ":", uri, NULL);
7366 mg_md5(expected_response,
7367 ha1,
7368 ":",
7369 nonce,
7370 ":",
7371 nc,
7372 ":",
7373 cnonce,
7374 ":",
7375 qop,
7376 ":",
7377 ha2,
7378 NULL);
7379
7380 return mg_strcasecmp(response, expected_response) == 0;
7381}
7382
7383
7384/* Use the global passwords file, if specified by auth_gpass option,
7385 * or search for .htpasswd in the requested directory. */
7386static void
11fdf7f2
TL
7387open_auth_file(struct mg_connection *conn,
7388 const char *path,
7389 struct mg_file *filep)
7c673cae 7390{
11fdf7f2 7391 if ((conn != NULL) && (conn->ctx != NULL)) {
7c673cae
FG
7392 char name[PATH_MAX];
7393 const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
7c673cae
FG
7394 int truncated;
7395
7396 if (gpass != NULL) {
7397 /* Use global passwords file */
11fdf7f2 7398 if (!mg_fopen(conn, gpass, MG_FOPEN_MODE_READ, filep)) {
7c673cae 7399#ifdef DEBUG
11fdf7f2 7400 /* Use mg_cry here, since gpass has been configured. */
7c673cae
FG
7401 mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
7402#endif
7403 }
11fdf7f2
TL
7404 /* Important: using local struct mg_file to test path for
7405 * is_directory flag. If filep is used, mg_stat() makes it
7406 * appear as if auth file was opened.
7407 * TODO(mid): Check if this is still required after rewriting
7408 * mg_stat */
7409 } else if (mg_stat(conn, path, &filep->stat)
7410 && filep->stat.is_directory) {
7c673cae
FG
7411 mg_snprintf(conn,
7412 &truncated,
7413 name,
7414 sizeof(name),
7415 "%s/%s",
7416 path,
7417 PASSWORDS_FILE_NAME);
7418
11fdf7f2 7419 if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) {
7c673cae 7420#ifdef DEBUG
11fdf7f2
TL
7421 /* Don't use mg_cry here, but only a trace, since this is
7422 * a typical case. It will occur for every directory
7423 * without a password file. */
7424 DEBUG_TRACE("fopen(%s): %s", name, strerror(ERRNO));
7c673cae
FG
7425#endif
7426 }
7427 } else {
7428 /* Try to find .htpasswd in requested directory. */
7429 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
7430 if (e[0] == '/') {
7431 break;
7432 }
7433 }
7434 mg_snprintf(conn,
7435 &truncated,
7436 name,
7437 sizeof(name),
7438 "%.*s/%s",
7439 (int)(e - p),
7440 p,
7441 PASSWORDS_FILE_NAME);
7442
11fdf7f2 7443 if (truncated || !mg_fopen(conn, name, MG_FOPEN_MODE_READ, filep)) {
7c673cae 7444#ifdef DEBUG
11fdf7f2
TL
7445 /* Don't use mg_cry here, but only a trace, since this is
7446 * a typical case. It will occur for every directory
7447 * without a password file. */
7448 DEBUG_TRACE("fopen(%s): %s", name, strerror(ERRNO));
7c673cae
FG
7449#endif
7450 }
7451 }
7452 }
7453}
7454
7455
7456/* Parsed Authorization header */
7457struct ah {
7458 char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
7459};
7460
7461
7462/* Return 1 on success. Always initializes the ah structure. */
7463static int
7464parse_auth_header(struct mg_connection *conn,
7465 char *buf,
7466 size_t buf_size,
7467 struct ah *ah)
7468{
7469 char *name, *value, *s;
7470 const char *auth_header;
7471 uint64_t nonce;
7472
7473 if (!ah || !conn) {
7474 return 0;
7475 }
7476
7477 (void)memset(ah, 0, sizeof(*ah));
11fdf7f2 7478 if (((auth_header = mg_get_header(conn, "Authorization")) == NULL)
7c673cae
FG
7479 || mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
7480 return 0;
7481 }
7482
7483 /* Make modifiable copy of the auth header */
7484 (void)mg_strlcpy(buf, auth_header + 7, buf_size);
7485 s = buf;
7486
7487 /* Parse authorization header */
7488 for (;;) {
7489 /* Gobble initial spaces */
7490 while (isspace(*(unsigned char *)s)) {
7491 s++;
7492 }
7493 name = skip_quoted(&s, "=", " ", 0);
11fdf7f2
TL
7494 /* Value is either quote-delimited, or ends at first comma or space.
7495 */
7c673cae
FG
7496 if (s[0] == '\"') {
7497 s++;
7498 value = skip_quoted(&s, "\"", " ", '\\');
7499 if (s[0] == ',') {
7500 s++;
7501 }
7502 } else {
7503 value = skip_quoted(&s, ", ", " ", 0); /* IE uses commas, FF uses
7504 * spaces */
7505 }
7506 if (*name == '\0') {
7507 break;
7508 }
7509
7510 if (!strcmp(name, "username")) {
7511 ah->user = value;
7512 } else if (!strcmp(name, "cnonce")) {
7513 ah->cnonce = value;
7514 } else if (!strcmp(name, "response")) {
7515 ah->response = value;
7516 } else if (!strcmp(name, "uri")) {
7517 ah->uri = value;
7518 } else if (!strcmp(name, "qop")) {
7519 ah->qop = value;
7520 } else if (!strcmp(name, "nc")) {
7521 ah->nc = value;
7522 } else if (!strcmp(name, "nonce")) {
7523 ah->nonce = value;
7524 }
7525 }
7526
7527#ifndef NO_NONCE_CHECK
7528 /* Read the nonce from the response. */
7529 if (ah->nonce == NULL) {
7530 return 0;
7531 }
7532 s = NULL;
7533 nonce = strtoull(ah->nonce, &s, 10);
7534 if ((s == NULL) || (*s != 0)) {
7535 return 0;
7536 }
7537
7538 /* Convert the nonce from the client to a number. */
7539 nonce ^= conn->ctx->auth_nonce_mask;
7540
7541 /* The converted number corresponds to the time the nounce has been
7542 * created. This should not be earlier than the server start. */
7543 /* Server side nonce check is valuable in all situations but one:
7544 * if the server restarts frequently, but the client should not see
7545 * that, so the server should accept nonces from previous starts. */
7546 /* However, the reasonable default is to not accept a nonce from a
7547 * previous start, so if anyone changed the access rights between
7548 * two restarts, a new login is required. */
7549 if (nonce < (uint64_t)conn->ctx->start_time) {
7550 /* nonce is from a previous start of the server and no longer valid
7551 * (replay attack?) */
7552 return 0;
7553 }
7554 /* Check if the nonce is too high, so it has not (yet) been used by the
7555 * server. */
7556 if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
7557 return 0;
7558 }
11fdf7f2
TL
7559#else
7560 (void)nonce;
7c673cae
FG
7561#endif
7562
7563 /* CGI needs it as REMOTE_USER */
7564 if (ah->user != NULL) {
7565 conn->request_info.remote_user = mg_strdup(ah->user);
7566 } else {
7567 return 0;
7568 }
7569
7570 return 1;
7571}
7572
7573
7574static const char *
11fdf7f2 7575mg_fgets(char *buf, size_t size, struct mg_file *filep, char **p)
7c673cae
FG
7576{
7577 const char *eof;
7578 size_t len;
7579 const char *memend;
7580
7581 if (!filep) {
7582 return NULL;
7583 }
7584
11fdf7f2
TL
7585 if ((filep->access.membuf != NULL) && (*p != NULL)) {
7586 memend = (const char *)&filep->access.membuf[filep->stat.size];
7c673cae
FG
7587 /* Search for \n from p till the end of stream */
7588 eof = (char *)memchr(*p, '\n', (size_t)(memend - *p));
7589 if (eof != NULL) {
7590 eof += 1; /* Include \n */
7591 } else {
7592 eof = memend; /* Copy remaining data */
7593 }
11fdf7f2
TL
7594 len =
7595 ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (size_t)(eof - *p);
7c673cae
FG
7596 memcpy(buf, *p, len);
7597 buf[len] = '\0';
7598 *p += len;
7599 return len ? eof : NULL;
11fdf7f2
TL
7600 } else if (filep->access.fp != NULL) {
7601 return fgets(buf, (int)size, filep->access.fp);
7c673cae
FG
7602 } else {
7603 return NULL;
7604 }
7605}
7606
11fdf7f2
TL
7607/* Define the initial recursion depth for procesesing htpasswd files that
7608 * include other htpasswd
7609 * (or even the same) files. It is not difficult to provide a file or files
7610 * s.t. they force civetweb
7611 * to infinitely recurse and then crash.
7612 */
7613#define INITIAL_DEPTH 9
7614#if INITIAL_DEPTH <= 0
7615#error Bad INITIAL_DEPTH for recursion, set to at least 1
7616#endif
7617
7c673cae
FG
7618struct read_auth_file_struct {
7619 struct mg_connection *conn;
7620 struct ah ah;
11fdf7f2 7621 const char *domain;
7c673cae 7622 char buf[256 + 256 + 40];
11fdf7f2
TL
7623 const char *f_user;
7624 const char *f_domain;
7625 const char *f_ha1;
7c673cae
FG
7626};
7627
7628
7629static int
11fdf7f2
TL
7630read_auth_file(struct mg_file *filep,
7631 struct read_auth_file_struct *workdata,
7632 int depth)
7c673cae
FG
7633{
7634 char *p;
7635 int is_authorized = 0;
11fdf7f2 7636 struct mg_file fp;
7c673cae
FG
7637 size_t l;
7638
11fdf7f2 7639 if (!filep || !workdata || (0 == depth)) {
7c673cae
FG
7640 return 0;
7641 }
7642
7643 /* Loop over passwords file */
11fdf7f2 7644 p = (char *)filep->access.membuf;
7c673cae
FG
7645 while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) {
7646 l = strlen(workdata->buf);
7647 while (l > 0) {
7648 if (isspace(workdata->buf[l - 1])
7649 || iscntrl(workdata->buf[l - 1])) {
7650 l--;
7651 workdata->buf[l] = 0;
7652 } else
7653 break;
7654 }
7655 if (l < 1) {
7656 continue;
7657 }
7658
7659 workdata->f_user = workdata->buf;
7660
7661 if (workdata->f_user[0] == ':') {
7662 /* user names may not contain a ':' and may not be empty,
11fdf7f2
TL
7663 * so lines starting with ':' may be used for a special purpose
7664 */
7c673cae
FG
7665 if (workdata->f_user[1] == '#') {
7666 /* :# is a comment */
7667 continue;
7668 } else if (!strncmp(workdata->f_user + 1, "include=", 8)) {
11fdf7f2
TL
7669 if (mg_fopen(workdata->conn,
7670 workdata->f_user + 9,
7671 MG_FOPEN_MODE_READ,
7672 &fp)) {
7673 is_authorized = read_auth_file(&fp, workdata, depth - 1);
7674 (void)mg_fclose(
7675 &fp.access); /* ignore error on read only file */
7676
7677 /* No need to continue processing files once we have a
7678 * match, since nothing will reset it back
7679 * to 0.
7680 */
7681 if (is_authorized) {
7682 return is_authorized;
7683 }
7c673cae
FG
7684 } else {
7685 mg_cry(workdata->conn,
7686 "%s: cannot open authorization file: %s",
7687 __func__,
7688 workdata->buf);
7689 }
7690 continue;
7691 }
7692 /* everything is invalid for the moment (might change in the
7693 * future) */
7694 mg_cry(workdata->conn,
7695 "%s: syntax error in authorization file: %s",
7696 __func__,
7697 workdata->buf);
7698 continue;
7699 }
7700
7701 workdata->f_domain = strchr(workdata->f_user, ':');
7702 if (workdata->f_domain == NULL) {
7703 mg_cry(workdata->conn,
7704 "%s: syntax error in authorization file: %s",
7705 __func__,
7706 workdata->buf);
7707 continue;
7708 }
11fdf7f2 7709 *(char *)(workdata->f_domain) = 0;
7c673cae
FG
7710 (workdata->f_domain)++;
7711
7712 workdata->f_ha1 = strchr(workdata->f_domain, ':');
7713 if (workdata->f_ha1 == NULL) {
7714 mg_cry(workdata->conn,
7715 "%s: syntax error in authorization file: %s",
7716 __func__,
7717 workdata->buf);
7718 continue;
7719 }
11fdf7f2 7720 *(char *)(workdata->f_ha1) = 0;
7c673cae
FG
7721 (workdata->f_ha1)++;
7722
7723 if (!strcmp(workdata->ah.user, workdata->f_user)
7724 && !strcmp(workdata->domain, workdata->f_domain)) {
7725 return check_password(workdata->conn->request_info.request_method,
7726 workdata->f_ha1,
7727 workdata->ah.uri,
7728 workdata->ah.nonce,
7729 workdata->ah.nc,
7730 workdata->ah.cnonce,
7731 workdata->ah.qop,
7732 workdata->ah.response);
7733 }
7734 }
7735
7736 return is_authorized;
7737}
7738
7739
7740/* Authorize against the opened passwords file. Return 1 if authorized. */
7741static int
11fdf7f2 7742authorize(struct mg_connection *conn, struct mg_file *filep, const char *realm)
7c673cae
FG
7743{
7744 struct read_auth_file_struct workdata;
7745 char buf[MG_BUF_LEN];
7746
7747 if (!conn || !conn->ctx) {
7748 return 0;
7749 }
7750
7751 memset(&workdata, 0, sizeof(workdata));
7752 workdata.conn = conn;
7753
7754 if (!parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) {
7755 return 0;
7756 }
7c673cae 7757
11fdf7f2
TL
7758 if (realm) {
7759 workdata.domain = realm;
7760 } else {
7761 workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN];
7762 }
7763
7764 return read_auth_file(filep, &workdata, INITIAL_DEPTH);
7765}
7766
7767
7768/* Public function to check http digest authentication header */
7769int
7770mg_check_digest_access_authentication(struct mg_connection *conn,
7771 const char *realm,
7772 const char *filename)
7773{
7774 struct mg_file file = STRUCT_FILE_INITIALIZER;
7775 int auth;
7776
7777 if (!conn || !filename) {
7778 return -1;
7779 }
7780 if (!mg_fopen(conn, filename, MG_FOPEN_MODE_READ, &file)) {
7781 return -2;
7782 }
7783
7784 auth = authorize(conn, &file, realm);
7785
7786 mg_fclose(&file.access);
7787
7788 return auth;
7c673cae
FG
7789}
7790
7791
7792/* Return 1 if request is authorised, 0 otherwise. */
7793static int
7794check_authorization(struct mg_connection *conn, const char *path)
7795{
7796 char fname[PATH_MAX];
7797 struct vec uri_vec, filename_vec;
7798 const char *list;
11fdf7f2 7799 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
7800 int authorized = 1, truncated;
7801
7802 if (!conn || !conn->ctx) {
7803 return 0;
7804 }
7805
7806 list = conn->ctx->config[PROTECT_URI];
7807 while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
7808 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
7809 mg_snprintf(conn,
7810 &truncated,
7811 fname,
7812 sizeof(fname),
7813 "%.*s",
7814 (int)filename_vec.len,
7815 filename_vec.ptr);
7816
11fdf7f2
TL
7817 if (truncated
7818 || !mg_fopen(conn, fname, MG_FOPEN_MODE_READ, &file)) {
7c673cae
FG
7819 mg_cry(conn,
7820 "%s: cannot open %s: %s",
7821 __func__,
7822 fname,
7823 strerror(errno));
7824 }
7825 break;
7826 }
7827 }
7828
11fdf7f2 7829 if (!is_file_opened(&file.access)) {
7c673cae
FG
7830 open_auth_file(conn, path, &file);
7831 }
7832
11fdf7f2
TL
7833 if (is_file_opened(&file.access)) {
7834 authorized = authorize(conn, &file, NULL);
7835 (void)mg_fclose(&file.access); /* ignore error on read only file */
7c673cae
FG
7836 }
7837
7838 return authorized;
7839}
7840
7841
11fdf7f2 7842/* Internal function. Assumes conn is valid */
7c673cae 7843static void
11fdf7f2 7844send_authorization_request(struct mg_connection *conn, const char *realm)
7c673cae
FG
7845{
7846 char date[64];
7847 time_t curtime = time(NULL);
11fdf7f2 7848 uint64_t nonce = (uint64_t)(conn->ctx->start_time);
7c673cae 7849
11fdf7f2
TL
7850 if (!realm) {
7851 realm = conn->ctx->config[AUTHENTICATION_DOMAIN];
7852 }
7c673cae 7853
11fdf7f2
TL
7854 (void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
7855 nonce += conn->ctx->nonce_count;
7856 ++conn->ctx->nonce_count;
7857 (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
7c673cae 7858
11fdf7f2
TL
7859 nonce ^= conn->ctx->auth_nonce_mask;
7860 conn->status_code = 401;
7861 conn->must_close = 1;
7c673cae 7862
11fdf7f2 7863 gmt_time_string(date, sizeof(date), &curtime);
7c673cae 7864
11fdf7f2
TL
7865 mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n");
7866 send_no_cache_header(conn);
7867 send_additional_header(conn);
7868 mg_printf(conn,
7869 "Date: %s\r\n"
7870 "Connection: %s\r\n"
7871 "Content-Length: 0\r\n"
7872 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
7873 "nonce=\"%" UINT64_FMT "\"\r\n\r\n",
7874 date,
7875 suggest_connection_header(conn),
7876 realm,
7877 nonce);
7878}
7879
7880
7881/* Interface function. Parameters are provided by the user, so do
7882 * at least some basic checks.
7883 */
7884int
7885mg_send_digest_access_authentication_request(struct mg_connection *conn,
7886 const char *realm)
7887{
7888 if (conn && conn->ctx) {
7889 send_authorization_request(conn, realm);
7890 return 0;
7c673cae 7891 }
11fdf7f2 7892 return -1;
7c673cae
FG
7893}
7894
7895
7896#if !defined(NO_FILES)
7897static int
7898is_authorized_for_put(struct mg_connection *conn)
7899{
7900 if (conn) {
11fdf7f2 7901 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
7902 const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
7903 int ret = 0;
7904
11fdf7f2
TL
7905 if (passfile != NULL
7906 && mg_fopen(conn, passfile, MG_FOPEN_MODE_READ, &file)) {
7907 ret = authorize(conn, &file, NULL);
7908 (void)mg_fclose(&file.access); /* ignore error on read only file */
7c673cae
FG
7909 }
7910
7911 return ret;
7912 }
7913 return 0;
7914}
7915#endif
7916
7917
7918int
7919mg_modify_passwords_file(const char *fname,
7920 const char *domain,
7921 const char *user,
7922 const char *pass)
7923{
7924 int found, i;
7925 char line[512], u[512] = "", d[512] = "", ha1[33], tmp[PATH_MAX + 8];
7926 FILE *fp, *fp2;
7927
7928 found = 0;
7929 fp = fp2 = NULL;
7930
7931 /* Regard empty password as no password - remove user record. */
11fdf7f2 7932 if ((pass != NULL) && (pass[0] == '\0')) {
7c673cae
FG
7933 pass = NULL;
7934 }
7935
7936 /* Other arguments must not be empty */
11fdf7f2 7937 if ((fname == NULL) || (domain == NULL) || (user == NULL)) {
7c673cae
FG
7938 return 0;
7939 }
7940
11fdf7f2
TL
7941 /* Using the given file format, user name and domain must not contain
7942 * ':'
7c673cae
FG
7943 */
7944 if (strchr(user, ':') != NULL) {
7945 return 0;
7946 }
7947 if (strchr(domain, ':') != NULL) {
7948 return 0;
7949 }
7950
7951 /* Do not allow control characters like newline in user name and domain.
7952 * Do not allow excessively long names either. */
11fdf7f2 7953 for (i = 0; ((i < 255) && (user[i] != 0)); i++) {
7c673cae
FG
7954 if (iscntrl(user[i])) {
7955 return 0;
7956 }
7957 }
7958 if (user[i]) {
7959 return 0;
7960 }
11fdf7f2 7961 for (i = 0; ((i < 255) && (domain[i] != 0)); i++) {
7c673cae
FG
7962 if (iscntrl(domain[i])) {
7963 return 0;
7964 }
7965 }
7966 if (domain[i]) {
7967 return 0;
7968 }
7969
7970 /* The maximum length of the path to the password file is limited */
7971 if ((strlen(fname) + 4) >= PATH_MAX) {
7972 return 0;
7973 }
7974
7975 /* Create a temporary file name. Length has been checked before. */
7976 strcpy(tmp, fname);
7977 strcat(tmp, ".tmp");
7978
7979 /* Create the file if does not exist */
7980 /* Use of fopen here is OK, since fname is only ASCII */
7981 if ((fp = fopen(fname, "a+")) != NULL) {
7982 (void)fclose(fp);
7983 }
7984
7985 /* Open the given file and temporary file */
7986 if ((fp = fopen(fname, "r")) == NULL) {
7987 return 0;
7988 } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
7989 fclose(fp);
7990 return 0;
7991 }
7992
7993 /* Copy the stuff to temporary file */
7994 while (fgets(line, sizeof(line), fp) != NULL) {
7995 if (sscanf(line, "%255[^:]:%255[^:]:%*s", u, d) != 2) {
7996 continue;
7997 }
7998 u[255] = 0;
7999 d[255] = 0;
8000
8001 if (!strcmp(u, user) && !strcmp(d, domain)) {
8002 found++;
8003 if (pass != NULL) {
8004 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
8005 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
8006 }
8007 } else {
8008 fprintf(fp2, "%s", line);
8009 }
8010 }
8011
8012 /* If new user, just add it */
11fdf7f2 8013 if (!found && (pass != NULL)) {
7c673cae
FG
8014 mg_md5(ha1, user, ":", domain, ":", pass, NULL);
8015 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
8016 }
8017
8018 /* Close files */
8019 fclose(fp);
8020 fclose(fp2);
8021
8022 /* Put the temp file in place of real file */
8023 IGNORE_UNUSED_RESULT(remove(fname));
8024 IGNORE_UNUSED_RESULT(rename(tmp, fname));
8025
8026 return 1;
8027}
8028
8029
8030static int
8031is_valid_port(unsigned long port)
8032{
11fdf7f2 8033 return (port <= 0xffff);
7c673cae
FG
8034}
8035
8036
8037static int
8038mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
8039{
8040 struct addrinfo hints, *res, *ressave;
8041 int func_ret = 0;
8042 int gai_ret;
8043
8044 memset(&hints, 0, sizeof(struct addrinfo));
8045 hints.ai_family = af;
8046
8047 gai_ret = getaddrinfo(src, NULL, &hints, &res);
8048 if (gai_ret != 0) {
8049 /* gai_strerror could be used to convert gai_ret to a string */
8050 /* POSIX return values: see
8051 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
8052 */
8053 /* Windows return values: see
8054 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
8055 */
8056 return 0;
8057 }
8058
8059 ressave = res;
8060
8061 while (res) {
11fdf7f2 8062 if (dstlen >= (size_t)res->ai_addrlen) {
7c673cae
FG
8063 memcpy(dst, res->ai_addr, res->ai_addrlen);
8064 func_ret = 1;
8065 }
8066 res = res->ai_next;
8067 }
8068
8069 freeaddrinfo(ressave);
8070 return func_ret;
8071}
8072
8073
8074static int
8075connect_socket(struct mg_context *ctx /* may be NULL */,
8076 const char *host,
8077 int port,
8078 int use_ssl,
8079 char *ebuf,
8080 size_t ebuf_len,
8081 SOCKET *sock /* output: socket, must not be NULL */,
8082 union usa *sa /* output: socket address, must not be NULL */
8083 )
8084{
8085 int ip_ver = 0;
8086 *sock = INVALID_SOCKET;
8087 memset(sa, 0, sizeof(*sa));
8088
8089 if (ebuf_len > 0) {
8090 *ebuf = 0;
8091 }
8092
8093 if (host == NULL) {
8094 mg_snprintf(NULL,
8095 NULL, /* No truncation check for ebuf */
8096 ebuf,
8097 ebuf_len,
8098 "%s",
8099 "NULL host");
8100 return 0;
8101 }
8102
11fdf7f2 8103 if ((port <= 0) || !is_valid_port((unsigned)port)) {
7c673cae
FG
8104 mg_snprintf(NULL,
8105 NULL, /* No truncation check for ebuf */
8106 ebuf,
8107 ebuf_len,
8108 "%s",
8109 "invalid port");
8110 return 0;
8111 }
8112
11fdf7f2
TL
8113#if !defined(NO_SSL)
8114#if !defined(NO_SSL_DL)
8115#ifdef OPENSSL_API_1_1
8116 if (use_ssl && (TLS_client_method == NULL)) {
8117 mg_snprintf(NULL,
8118 NULL, /* No truncation check for ebuf */
8119 ebuf,
8120 ebuf_len,
8121 "%s",
8122 "SSL is not initialized");
8123 return 0;
8124 }
8125#else
7c673cae
FG
8126 if (use_ssl && (SSLv23_client_method == NULL)) {
8127 mg_snprintf(NULL,
8128 NULL, /* No truncation check for ebuf */
8129 ebuf,
8130 ebuf_len,
8131 "%s",
8132 "SSL is not initialized");
8133 return 0;
8134 }
11fdf7f2
TL
8135
8136#endif /* OPENSSL_API_1_1 */
8137#else
8138 (void)use_ssl;
8139#endif /* NO_SSL_DL */
8140#else
8141 (void)use_ssl;
8142#endif /* !defined(NO_SSL) */
7c673cae
FG
8143
8144 if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) {
11fdf7f2 8145 sa->sin.sin_family = AF_INET;
7c673cae
FG
8146 sa->sin.sin_port = htons((uint16_t)port);
8147 ip_ver = 4;
8148#ifdef USE_IPV6
8149 } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) {
11fdf7f2 8150 sa->sin6.sin6_family = AF_INET6;
7c673cae
FG
8151 sa->sin6.sin6_port = htons((uint16_t)port);
8152 ip_ver = 6;
8153 } else if (host[0] == '[') {
8154 /* While getaddrinfo on Windows will work with [::1],
8155 * getaddrinfo on Linux only works with ::1 (without []). */
8156 size_t l = strlen(host + 1);
11fdf7f2 8157 char *h = (l > 1) ? mg_strdup(host + 1) : NULL;
7c673cae
FG
8158 if (h) {
8159 h[l - 1] = 0;
8160 if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) {
11fdf7f2 8161 sa->sin6.sin6_family = AF_INET6;
7c673cae
FG
8162 sa->sin6.sin6_port = htons((uint16_t)port);
8163 ip_ver = 6;
8164 }
8165 mg_free(h);
8166 }
8167#endif
8168 }
8169
8170 if (ip_ver == 0) {
8171 mg_snprintf(NULL,
8172 NULL, /* No truncation check for ebuf */
8173 ebuf,
8174 ebuf_len,
8175 "%s",
8176 "host not found");
8177 return 0;
8178 }
8179
8180 if (ip_ver == 4) {
8181 *sock = socket(PF_INET, SOCK_STREAM, 0);
8182 }
8183#ifdef USE_IPV6
8184 else if (ip_ver == 6) {
8185 *sock = socket(PF_INET6, SOCK_STREAM, 0);
8186 }
8187#endif
8188
8189 if (*sock == INVALID_SOCKET) {
8190 mg_snprintf(NULL,
8191 NULL, /* No truncation check for ebuf */
8192 ebuf,
8193 ebuf_len,
8194 "socket(): %s",
8195 strerror(ERRNO));
8196 return 0;
8197 }
8198
8199 set_close_on_exec(*sock, fc(ctx));
8200
8201 if ((ip_ver == 4)
8202 && (connect(*sock, (struct sockaddr *)&sa->sin, sizeof(sa->sin))
8203 == 0)) {
8204 /* connected with IPv4 */
11fdf7f2
TL
8205 if (0 == set_non_blocking_mode(*sock)) {
8206 /* Ok */
8207 return 1;
8208 }
8209 /* failed */
8210 /* TODO: specific error message */
7c673cae
FG
8211 }
8212
8213#ifdef USE_IPV6
8214 if ((ip_ver == 6)
8215 && (connect(*sock, (struct sockaddr *)&sa->sin6, sizeof(sa->sin6))
8216 == 0)) {
8217 /* connected with IPv6 */
11fdf7f2
TL
8218 if (0 == set_non_blocking_mode(*sock)) {
8219 /* Ok */
8220 return 1;
8221 }
8222 /* failed */
8223 /* TODO: specific error message */
7c673cae
FG
8224 }
8225#endif
8226
8227 /* Not connected */
8228 mg_snprintf(NULL,
8229 NULL, /* No truncation check for ebuf */
8230 ebuf,
8231 ebuf_len,
8232 "connect(%s:%d): %s",
8233 host,
8234 port,
8235 strerror(ERRNO));
8236 closesocket(*sock);
8237 *sock = INVALID_SOCKET;
11fdf7f2 8238
7c673cae
FG
8239 return 0;
8240}
8241
8242
8243int
8244mg_url_encode(const char *src, char *dst, size_t dst_len)
8245{
8246 static const char *dont_escape = "._-$,;~()";
8247 static const char *hex = "0123456789abcdef";
8248 char *pos = dst;
8249 const char *end = dst + dst_len - 1;
8250
11fdf7f2 8251 for (; ((*src != '\0') && (pos < end)); src++, pos++) {
7c673cae 8252 if (isalnum(*(const unsigned char *)src)
11fdf7f2 8253 || (strchr(dont_escape, *(const unsigned char *)src) != NULL)) {
7c673cae
FG
8254 *pos = *src;
8255 } else if (pos + 2 < end) {
8256 pos[0] = '%';
8257 pos[1] = hex[(*(const unsigned char *)src) >> 4];
8258 pos[2] = hex[(*(const unsigned char *)src) & 0xf];
8259 pos += 2;
8260 } else {
8261 break;
8262 }
8263 }
8264
8265 *pos = '\0';
8266 return (*src == '\0') ? (int)(pos - dst) : -1;
8267}
8268
11fdf7f2 8269/* Return 0 on success, non-zero if an error occurs. */
7c673cae 8270
11fdf7f2 8271static int
7c673cae
FG
8272print_dir_entry(struct de *de)
8273{
11fdf7f2
TL
8274 size_t hrefsize;
8275 char *href;
8276 char size[64], mod[64];
7c673cae
FG
8277 struct tm *tm;
8278
11fdf7f2
TL
8279 hrefsize = PATH_MAX * 3; /* worst case */
8280 href = (char *)mg_malloc(hrefsize);
8281 if (href == NULL) {
8282 return -1;
8283 }
7c673cae
FG
8284 if (de->file.is_directory) {
8285 mg_snprintf(de->conn,
8286 NULL, /* Buffer is big enough */
8287 size,
8288 sizeof(size),
8289 "%s",
8290 "[DIRECTORY]");
8291 } else {
8292 /* We use (signed) cast below because MSVC 6 compiler cannot
8293 * convert unsigned __int64 to double. Sigh. */
8294 if (de->file.size < 1024) {
8295 mg_snprintf(de->conn,
8296 NULL, /* Buffer is big enough */
8297 size,
8298 sizeof(size),
8299 "%d",
8300 (int)de->file.size);
8301 } else if (de->file.size < 0x100000) {
8302 mg_snprintf(de->conn,
8303 NULL, /* Buffer is big enough */
8304 size,
8305 sizeof(size),
8306 "%.1fk",
8307 (double)de->file.size / 1024.0);
8308 } else if (de->file.size < 0x40000000) {
8309 mg_snprintf(de->conn,
8310 NULL, /* Buffer is big enough */
8311 size,
8312 sizeof(size),
8313 "%.1fM",
8314 (double)de->file.size / 1048576);
8315 } else {
8316 mg_snprintf(de->conn,
8317 NULL, /* Buffer is big enough */
8318 size,
8319 sizeof(size),
8320 "%.1fG",
8321 (double)de->file.size / 1073741824);
8322 }
8323 }
8324
8325 /* Note: mg_snprintf will not cause a buffer overflow above.
8326 * So, string truncation checks are not required here. */
8327
8328 tm = localtime(&de->file.last_modified);
8329 if (tm != NULL) {
8330 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
8331 } else {
8332 mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
8333 mod[sizeof(mod) - 1] = '\0';
8334 }
11fdf7f2
TL
8335 mg_url_encode(de->file_name, href, hrefsize);
8336 mg_printf(de->conn,
8337 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
8338 "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
8339 de->conn->request_info.local_uri,
8340 href,
8341 de->file.is_directory ? "/" : "",
8342 de->file_name,
8343 de->file.is_directory ? "/" : "",
8344 mod,
8345 size);
8346 mg_free(href);
8347 return 0;
7c673cae
FG
8348}
8349
8350
8351/* This function is called from send_directory() and used for
8352 * sorting directory entries by size, or name, or modification time.
8353 * On windows, __cdecl specification is needed in case if project is built
8354 * with __stdcall convention. qsort always requires __cdels callback. */
8355static int WINCDECL
8356compare_dir_entries(const void *p1, const void *p2)
8357{
8358 if (p1 && p2) {
8359 const struct de *a = (const struct de *)p1, *b = (const struct de *)p2;
8360 const char *query_string = a->conn->request_info.query_string;
8361 int cmp_result = 0;
8362
8363 if (query_string == NULL) {
8364 query_string = "na";
8365 }
8366
8367 if (a->file.is_directory && !b->file.is_directory) {
8368 return -1; /* Always put directories on top */
8369 } else if (!a->file.is_directory && b->file.is_directory) {
8370 return 1; /* Always put directories on top */
8371 } else if (*query_string == 'n') {
8372 cmp_result = strcmp(a->file_name, b->file_name);
8373 } else if (*query_string == 's') {
11fdf7f2 8374 cmp_result = (a->file.size == b->file.size)
7c673cae 8375 ? 0
11fdf7f2 8376 : ((a->file.size > b->file.size) ? 1 : -1);
7c673cae
FG
8377 } else if (*query_string == 'd') {
8378 cmp_result =
8379 (a->file.last_modified == b->file.last_modified)
8380 ? 0
8381 : ((a->file.last_modified > b->file.last_modified) ? 1
8382 : -1);
8383 }
8384
11fdf7f2 8385 return (query_string[1] == 'd') ? -cmp_result : cmp_result;
7c673cae
FG
8386 }
8387 return 0;
8388}
8389
8390
8391static int
8392must_hide_file(struct mg_connection *conn, const char *path)
8393{
8394 if (conn && conn->ctx) {
8395 const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
8396 const char *pattern = conn->ctx->config[HIDE_FILES];
11fdf7f2
TL
8397 return (match_prefix(pw_pattern, strlen(pw_pattern), path) > 0)
8398 || ((pattern != NULL)
8399 && (match_prefix(pattern, strlen(pattern), path) > 0));
7c673cae
FG
8400 }
8401 return 0;
8402}
8403
8404
8405static int
8406scan_directory(struct mg_connection *conn,
8407 const char *dir,
8408 void *data,
11fdf7f2 8409 int (*cb)(struct de *, void *))
7c673cae
FG
8410{
8411 char path[PATH_MAX];
8412 struct dirent *dp;
8413 DIR *dirp;
8414 struct de de;
8415 int truncated;
8416
8417 if ((dirp = mg_opendir(conn, dir)) == NULL) {
8418 return 0;
8419 } else {
8420 de.conn = conn;
8421
8422 while ((dp = mg_readdir(dirp)) != NULL) {
8423 /* Do not show current dir and hidden files */
8424 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
8425 || must_hide_file(conn, dp->d_name)) {
8426 continue;
8427 }
8428
8429 mg_snprintf(
8430 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
8431
8432 /* If we don't memset stat structure to zero, mtime will have
8433 * garbage and strftime() will segfault later on in
8434 * print_dir_entry(). memset is required only if mg_stat()
8435 * fails. For more details, see
8436 * http://code.google.com/p/mongoose/issues/detail?id=79 */
8437 memset(&de.file, 0, sizeof(de.file));
8438
8439 if (truncated) {
8440 /* If the path is not complete, skip processing. */
8441 continue;
8442 }
8443
8444 if (!mg_stat(conn, path, &de.file)) {
8445 mg_cry(conn,
8446 "%s: mg_stat(%s) failed: %s",
8447 __func__,
8448 path,
8449 strerror(ERRNO));
8450 }
8451 de.file_name = dp->d_name;
8452 cb(&de, data);
8453 }
8454 (void)mg_closedir(dirp);
8455 }
8456 return 1;
8457}
8458
8459
8460#if !defined(NO_FILES)
8461static int
8462remove_directory(struct mg_connection *conn, const char *dir)
8463{
8464 char path[PATH_MAX];
8465 struct dirent *dp;
8466 DIR *dirp;
8467 struct de de;
8468 int truncated;
8469 int ok = 1;
8470
8471 if ((dirp = mg_opendir(conn, dir)) == NULL) {
8472 return 0;
8473 } else {
8474 de.conn = conn;
8475
8476 while ((dp = mg_readdir(dirp)) != NULL) {
8477 /* Do not show current dir (but show hidden files as they will
8478 * also be removed) */
8479 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
8480 continue;
8481 }
8482
8483 mg_snprintf(
8484 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
8485
8486 /* If we don't memset stat structure to zero, mtime will have
8487 * garbage and strftime() will segfault later on in
8488 * print_dir_entry(). memset is required only if mg_stat()
8489 * fails. For more details, see
8490 * http://code.google.com/p/mongoose/issues/detail?id=79 */
8491 memset(&de.file, 0, sizeof(de.file));
8492
8493 if (truncated) {
8494 /* Do not delete anything shorter */
8495 ok = 0;
8496 continue;
8497 }
8498
8499 if (!mg_stat(conn, path, &de.file)) {
8500 mg_cry(conn,
8501 "%s: mg_stat(%s) failed: %s",
8502 __func__,
8503 path,
8504 strerror(ERRNO));
8505 ok = 0;
8506 }
11fdf7f2
TL
8507
8508 if (de.file.is_directory) {
8509 if (remove_directory(conn, path) == 0) {
8510 ok = 0;
7c673cae
FG
8511 }
8512 } else {
11fdf7f2
TL
8513 /* This will fail file is the file is in memory */
8514 if (mg_remove(conn, path) == 0) {
8515 ok = 0;
8516 }
7c673cae
FG
8517 }
8518 }
8519 (void)mg_closedir(dirp);
8520
8521 IGNORE_UNUSED_RESULT(rmdir(dir));
8522 }
8523
8524 return ok;
8525}
8526#endif
8527
8528
8529struct dir_scan_data {
8530 struct de *entries;
8531 unsigned int num_entries;
8532 unsigned int arr_size;
8533};
8534
8535
8536/* Behaves like realloc(), but frees original pointer on failure */
8537static void *
8538realloc2(void *ptr, size_t size)
8539{
8540 void *new_ptr = mg_realloc(ptr, size);
8541 if (new_ptr == NULL) {
8542 mg_free(ptr);
8543 }
8544 return new_ptr;
8545}
8546
8547
11fdf7f2 8548static int
7c673cae
FG
8549dir_scan_callback(struct de *de, void *data)
8550{
8551 struct dir_scan_data *dsd = (struct dir_scan_data *)data;
8552
11fdf7f2 8553 if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
7c673cae
FG
8554 dsd->arr_size *= 2;
8555 dsd->entries =
8556 (struct de *)realloc2(dsd->entries,
8557 dsd->arr_size * sizeof(dsd->entries[0]));
8558 }
8559 if (dsd->entries == NULL) {
8560 /* TODO(lsm, low): propagate an error to the caller */
8561 dsd->num_entries = 0;
8562 } else {
8563 dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
8564 dsd->entries[dsd->num_entries].file = de->file;
8565 dsd->entries[dsd->num_entries].conn = de->conn;
8566 dsd->num_entries++;
8567 }
11fdf7f2
TL
8568
8569 return 0;
7c673cae
FG
8570}
8571
8572
8573static void
8574handle_directory_request(struct mg_connection *conn, const char *dir)
8575{
8576 unsigned int i;
8577 int sort_direction;
8578 struct dir_scan_data data = {NULL, 0, 128};
8579 char date[64];
8580 time_t curtime = time(NULL);
8581
8582 if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
11fdf7f2
TL
8583 mg_send_http_error(conn,
8584 500,
8585 "Error: Cannot open directory\nopendir(%s): %s",
8586 dir,
8587 strerror(ERRNO));
7c673cae
FG
8588 return;
8589 }
8590
8591 gmt_time_string(date, sizeof(date), &curtime);
8592
8593 if (!conn) {
8594 return;
8595 }
8596
11fdf7f2
TL
8597 sort_direction = ((conn->request_info.query_string != NULL)
8598 && (conn->request_info.query_string[1] == 'd'))
7c673cae
FG
8599 ? 'a'
8600 : 'd';
8601
8602 conn->must_close = 1;
8603 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
8604 send_static_cache_header(conn);
11fdf7f2 8605 send_additional_header(conn);
7c673cae
FG
8606 mg_printf(conn,
8607 "Date: %s\r\n"
8608 "Connection: close\r\n"
8609 "Content-Type: text/html; charset=utf-8\r\n\r\n",
8610 date);
11fdf7f2
TL
8611 mg_printf(conn,
8612 "<html><head><title>Index of %s</title>"
8613 "<style>th {text-align: left;}</style></head>"
8614 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
8615 "<tr><th><a href=\"?n%c\">Name</a></th>"
8616 "<th><a href=\"?d%c\">Modified</a></th>"
8617 "<th><a href=\"?s%c\">Size</a></th></tr>"
8618 "<tr><td colspan=\"3\"><hr></td></tr>",
8619 conn->request_info.local_uri,
8620 conn->request_info.local_uri,
8621 sort_direction,
8622 sort_direction,
8623 sort_direction);
7c673cae
FG
8624
8625 /* Print first entry - link to a parent directory */
11fdf7f2
TL
8626 mg_printf(conn,
8627 "<tr><td><a href=\"%s%s\">%s</a></td>"
8628 "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
8629 conn->request_info.local_uri,
8630 "..",
8631 "Parent directory",
8632 "-",
8633 "-");
7c673cae
FG
8634
8635 /* Sort and print directory entries */
8636 if (data.entries != NULL) {
8637 qsort(data.entries,
8638 (size_t)data.num_entries,
8639 sizeof(data.entries[0]),
8640 compare_dir_entries);
8641 for (i = 0; i < data.num_entries; i++) {
8642 print_dir_entry(&data.entries[i]);
8643 mg_free(data.entries[i].file_name);
8644 }
8645 mg_free(data.entries);
8646 }
8647
11fdf7f2 8648 mg_printf(conn, "%s", "</table></body></html>");
7c673cae
FG
8649 conn->status_code = 200;
8650}
8651
8652
8653/* Send len bytes from the opened file to the client. */
8654static void
8655send_file_data(struct mg_connection *conn,
11fdf7f2 8656 struct mg_file *filep,
7c673cae
FG
8657 int64_t offset,
8658 int64_t len)
8659{
8660 char buf[MG_BUF_LEN];
8661 int to_read, num_read, num_written;
8662 int64_t size;
8663
8664 if (!filep || !conn) {
8665 return;
8666 }
8667
8668 /* Sanity check the offset */
11fdf7f2
TL
8669 size = (filep->stat.size > INT64_MAX) ? INT64_MAX
8670 : (int64_t)(filep->stat.size);
8671 offset = (offset < 0) ? 0 : ((offset > size) ? size : offset);
7c673cae 8672
11fdf7f2 8673 if ((len > 0) && (filep->access.membuf != NULL) && (size > 0)) {
7c673cae
FG
8674 /* file stored in memory */
8675 if (len > size - offset) {
8676 len = size - offset;
8677 }
11fdf7f2
TL
8678 mg_write(conn, filep->access.membuf + offset, (size_t)len);
8679 } else if (len > 0 && filep->access.fp != NULL) {
7c673cae
FG
8680/* file stored on disk */
8681#if defined(__linux__)
8682 /* sendfile is only available for Linux */
11fdf7f2
TL
8683 if ((conn->ssl == 0) && (conn->throttle == 0)
8684 && (!mg_strcasecmp(conn->ctx->config[ALLOW_SENDFILE_CALL],
8685 "yes"))) {
7c673cae
FG
8686 off_t sf_offs = (off_t)offset;
8687 ssize_t sf_sent;
11fdf7f2 8688 int sf_file = fileno(filep->access.fp);
7c673cae
FG
8689 int loop_cnt = 0;
8690
8691 do {
8692 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
8693 * 64 bit Linux (2^31 minus one memory page of 4k?). */
8694 size_t sf_tosend =
8695 (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
8696 sf_sent =
8697 sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
8698 if (sf_sent > 0) {
7c673cae
FG
8699 len -= sf_sent;
8700 offset += sf_sent;
8701 } else if (loop_cnt == 0) {
8702 /* This file can not be sent using sendfile.
8703 * This might be the case for pseudo-files in the
8704 * /sys/ and /proc/ file system.
8705 * Use the regular user mode copy code instead. */
8706 break;
8707 } else if (sf_sent == 0) {
8708 /* No error, but 0 bytes sent. May be EOF? */
8709 return;
8710 }
8711 loop_cnt++;
8712
8713 } while ((len > 0) && (sf_sent >= 0));
8714
8715 if (sf_sent > 0) {
8716 return; /* OK */
8717 }
8718
8719 /* sf_sent<0 means error, thus fall back to the classic way */
8720 /* This is always the case, if sf_file is not a "normal" file,
8721 * e.g., for sending data from the output of a CGI process. */
8722 offset = (int64_t)sf_offs;
8723 }
8724#endif
11fdf7f2 8725 if ((offset > 0) && (fseeko(filep->access.fp, offset, SEEK_SET) != 0)) {
7c673cae 8726 mg_cry(conn, "%s: fseeko() failed: %s", __func__, strerror(ERRNO));
11fdf7f2 8727 mg_send_http_error(
7c673cae
FG
8728 conn,
8729 500,
8730 "%s",
8731 "Error: Unable to access file at requested position.");
8732 } else {
8733 while (len > 0) {
8734 /* Calculate how much to read from the file in the buffer */
8735 to_read = sizeof(buf);
8736 if ((int64_t)to_read > len) {
8737 to_read = (int)len;
8738 }
8739
8740 /* Read from file, exit the loop on error */
11fdf7f2
TL
8741 if ((num_read =
8742 (int)fread(buf, 1, (size_t)to_read, filep->access.fp))
7c673cae
FG
8743 <= 0) {
8744 break;
8745 }
8746
8747 /* Send read bytes to the client, exit the loop on error */
8748 if ((num_written = mg_write(conn, buf, (size_t)num_read))
8749 != num_read) {
8750 break;
8751 }
8752
8753 /* Both read and were successful, adjust counters */
7c673cae
FG
8754 len -= num_written;
8755 }
8756 }
8757 }
8758}
8759
8760
8761static int
8762parse_range_header(const char *header, int64_t *a, int64_t *b)
8763{
8764 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
8765}
8766
8767
8768static void
11fdf7f2 8769construct_etag(char *buf, size_t buf_len, const struct mg_file_stat *filestat)
7c673cae 8770{
11fdf7f2 8771 if ((filestat != NULL) && (buf != NULL)) {
7c673cae
FG
8772 mg_snprintf(NULL,
8773 NULL, /* All calls to construct_etag use 64 byte buffer */
8774 buf,
8775 buf_len,
8776 "\"%lx.%" INT64_FMT "\"",
11fdf7f2
TL
8777 (unsigned long)filestat->last_modified,
8778 filestat->size);
7c673cae
FG
8779 }
8780}
8781
8782
8783static void
11fdf7f2 8784fclose_on_exec(struct mg_file_access *filep, struct mg_connection *conn)
7c673cae
FG
8785{
8786 if (filep != NULL && filep->fp != NULL) {
8787#ifdef _WIN32
8788 (void)conn; /* Unused. */
8789#else
8790 if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
8791 mg_cry(conn,
8792 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
8793 __func__,
8794 strerror(ERRNO));
8795 }
8796#endif
8797 }
8798}
8799
8800
8801static void
8802handle_static_file_request(struct mg_connection *conn,
8803 const char *path,
11fdf7f2
TL
8804 struct mg_file *filep,
8805 const char *mime_type,
8806 const char *additional_headers)
7c673cae
FG
8807{
8808 char date[64], lm[64], etag[64];
8809 char range[128]; /* large enough, so there will be no overflow */
8810 const char *msg = "OK", *hdr;
8811 time_t curtime = time(NULL);
8812 int64_t cl, r1, r2;
8813 struct vec mime_vec;
8814 int n, truncated;
8815 char gz_path[PATH_MAX];
8816 const char *encoding = "";
8817 const char *cors1, *cors2, *cors3;
11fdf7f2 8818 int allow_on_the_fly_compression;
7c673cae 8819
11fdf7f2 8820 if ((conn == NULL) || (conn->ctx == NULL) || (filep == NULL)) {
7c673cae
FG
8821 return;
8822 }
8823
8824 if (mime_type == NULL) {
8825 get_mime_type(conn->ctx, path, &mime_vec);
8826 } else {
8827 mime_vec.ptr = mime_type;
8828 mime_vec.len = strlen(mime_type);
8829 }
11fdf7f2
TL
8830 if (filep->stat.size > INT64_MAX) {
8831 mg_send_http_error(conn,
8832 500,
8833 "Error: File size is too large to send\n%" INT64_FMT,
8834 filep->stat.size);
8835 return;
7c673cae 8836 }
11fdf7f2 8837 cl = (int64_t)filep->stat.size;
7c673cae
FG
8838 conn->status_code = 200;
8839 range[0] = '\0';
8840
8841 /* if this file is in fact a pre-gzipped file, rewrite its filename
8842 * it's important to rewrite the filename after resolving
8843 * the mime type from it, to preserve the actual file's type */
11fdf7f2
TL
8844 allow_on_the_fly_compression = conn->accept_gzip;
8845
8846 if (filep->stat.is_gzipped) {
7c673cae
FG
8847 mg_snprintf(conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", path);
8848
8849 if (truncated) {
11fdf7f2
TL
8850 mg_send_http_error(conn,
8851 500,
8852 "Error: Path of zipped file too long (%s)",
8853 path);
7c673cae
FG
8854 return;
8855 }
8856
8857 path = gz_path;
8858 encoding = "Content-Encoding: gzip\r\n";
11fdf7f2
TL
8859
8860 /* File is already compressed. No "on the fly" compression. */
8861 allow_on_the_fly_compression = 0;
7c673cae
FG
8862 }
8863
11fdf7f2
TL
8864 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
8865 mg_send_http_error(conn,
8866 500,
8867 "Error: Cannot open file\nfopen(%s): %s",
8868 path,
8869 strerror(ERRNO));
7c673cae
FG
8870 return;
8871 }
8872
11fdf7f2 8873 fclose_on_exec(&filep->access, conn);
7c673cae
FG
8874
8875 /* If Range: header specified, act accordingly */
8876 r1 = r2 = 0;
8877 hdr = mg_get_header(conn, "Range");
11fdf7f2
TL
8878 if ((hdr != NULL) && ((n = parse_range_header(hdr, &r1, &r2)) > 0)
8879 && (r1 >= 0) && (r2 >= 0)) {
7c673cae
FG
8880 /* actually, range requests don't play well with a pre-gzipped
8881 * file (since the range is specified in the uncompressed space) */
11fdf7f2
TL
8882 if (filep->stat.is_gzipped) {
8883 mg_send_http_error(
7c673cae 8884 conn,
11fdf7f2 8885 416, /* 416 = Range Not Satisfiable */
7c673cae
FG
8886 "%s",
8887 "Error: Range requests in gzipped files are not supported");
11fdf7f2
TL
8888 (void)mg_fclose(
8889 &filep->access); /* ignore error on read only file */
7c673cae
FG
8890 return;
8891 }
8892 conn->status_code = 206;
11fdf7f2 8893 cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
7c673cae
FG
8894 mg_snprintf(conn,
8895 NULL, /* range buffer is big enough */
8896 range,
8897 sizeof(range),
8898 "Content-Range: bytes "
8899 "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
8900 r1,
8901 r1 + cl - 1,
11fdf7f2 8902 filep->stat.size);
7c673cae 8903 msg = "Partial Content";
11fdf7f2
TL
8904
8905 /* Do not compress ranges. */
8906 allow_on_the_fly_compression = 0;
7c673cae
FG
8907 }
8908
8909 hdr = mg_get_header(conn, "Origin");
8910 if (hdr) {
8911 /* Cross-origin resource sharing (CORS), see
8912 * http://www.html5rocks.com/en/tutorials/cors/,
11fdf7f2
TL
8913 * http://www.html5rocks.com/static/images/cors_server_flowchart.png
8914 * -
7c673cae
FG
8915 * preflight is not supported for files. */
8916 cors1 = "Access-Control-Allow-Origin: ";
8917 cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
8918 cors3 = "\r\n";
8919 } else {
8920 cors1 = cors2 = cors3 = "";
8921 }
8922
11fdf7f2
TL
8923 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC,
8924 * according to
7c673cae
FG
8925 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
8926 gmt_time_string(date, sizeof(date), &curtime);
11fdf7f2
TL
8927 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
8928 construct_etag(etag, sizeof(etag), &filep->stat);
7c673cae 8929
11fdf7f2
TL
8930 /* On the fly compression allowed */
8931 if (allow_on_the_fly_compression) {
8932 ;
8933 /* TODO: add interface to compression module */
8934 /* e.g., def from https://zlib.net/zlib_how.html */
8935 /* Check license (zlib has a permissive license, but */
8936 /* is still not MIT) and use dynamic binding like */
8937 /* done with OpenSSL */
8938 /* See #199 (https://github.com/civetweb/civetweb/issues/199) */
8939 }
8940
8941 /* Send header */
7c673cae
FG
8942 (void)mg_printf(conn,
8943 "HTTP/1.1 %d %s\r\n"
8944 "%s%s%s"
8945 "Date: %s\r\n",
8946 conn->status_code,
8947 msg,
8948 cors1,
8949 cors2,
8950 cors3,
8951 date);
8952 send_static_cache_header(conn);
11fdf7f2
TL
8953 send_additional_header(conn);
8954
7c673cae
FG
8955 (void)mg_printf(conn,
8956 "Last-Modified: %s\r\n"
8957 "Etag: %s\r\n"
8958 "Content-Type: %.*s\r\n"
8959 "Content-Length: %" INT64_FMT "\r\n"
8960 "Connection: %s\r\n"
8961 "Accept-Ranges: bytes\r\n"
11fdf7f2 8962 "%s%s",
7c673cae
FG
8963 lm,
8964 etag,
8965 (int)mime_vec.len,
8966 mime_vec.ptr,
8967 cl,
8968 suggest_connection_header(conn),
8969 range,
8970 encoding);
8971
11fdf7f2
TL
8972 /* The previous code must not add any header starting with X- to make
8973 * sure no one of the additional_headers is included twice */
8974
8975 if (additional_headers != NULL) {
8976 (void)mg_printf(conn,
8977 "%.*s\r\n\r\n",
8978 (int)strlen(additional_headers),
8979 additional_headers);
8980 } else {
8981 (void)mg_printf(conn, "\r\n");
8982 }
8983
7c673cae
FG
8984 if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
8985 send_file_data(conn, filep, r1, cl);
8986 }
11fdf7f2
TL
8987 (void)mg_fclose(&filep->access); /* ignore error on read only file */
8988}
8989
8990
8991#if !defined(NO_CACHING)
8992static void
8993handle_not_modified_static_file_request(struct mg_connection *conn,
8994 struct mg_file *filep)
8995{
8996 char date[64], lm[64], etag[64];
8997 time_t curtime = time(NULL);
8998
8999 if ((conn == NULL) || (filep == NULL)) {
9000 return;
9001 }
9002 conn->status_code = 304;
9003 gmt_time_string(date, sizeof(date), &curtime);
9004 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
9005 construct_etag(etag, sizeof(etag), &filep->stat);
9006
9007 (void)mg_printf(conn,
9008 "HTTP/1.1 %d %s\r\n"
9009 "Date: %s\r\n",
9010 conn->status_code,
9011 mg_get_response_code_text(conn, conn->status_code),
9012 date);
9013 send_static_cache_header(conn);
9014 send_additional_header(conn);
9015 (void)mg_printf(conn,
9016 "Last-Modified: %s\r\n"
9017 "Etag: %s\r\n"
9018 "Connection: %s\r\n"
9019 "\r\n",
9020 lm,
9021 etag,
9022 suggest_connection_header(conn));
7c673cae 9023}
11fdf7f2 9024#endif
7c673cae
FG
9025
9026
9027void
9028mg_send_file(struct mg_connection *conn, const char *path)
9029{
9030 mg_send_mime_file(conn, path, NULL);
9031}
9032
9033
9034void
9035mg_send_mime_file(struct mg_connection *conn,
9036 const char *path,
9037 const char *mime_type)
9038{
11fdf7f2
TL
9039 mg_send_mime_file2(conn, path, mime_type, NULL);
9040}
9041
9042
9043void
9044mg_send_mime_file2(struct mg_connection *conn,
9045 const char *path,
9046 const char *mime_type,
9047 const char *additional_headers)
9048{
9049 struct mg_file file = STRUCT_FILE_INITIALIZER;
9050
9051 if (!conn) {
9052 /* No conn */
9053 return;
9054 }
9055
9056 if (mg_stat(conn, path, &file.stat)) {
9057 if (file.stat.is_directory) {
7c673cae
FG
9058 if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
9059 "yes")) {
9060 handle_directory_request(conn, path);
9061 } else {
11fdf7f2
TL
9062 mg_send_http_error(conn,
9063 403,
9064 "%s",
9065 "Error: Directory listing denied");
7c673cae
FG
9066 }
9067 } else {
11fdf7f2
TL
9068 handle_static_file_request(
9069 conn, path, &file, mime_type, additional_headers);
7c673cae
FG
9070 }
9071 } else {
11fdf7f2 9072 mg_send_http_error(conn, 404, "%s", "Error: File not found");
7c673cae
FG
9073 }
9074}
9075
9076
9077/* For a given PUT path, create all intermediate subdirectories.
9078 * Return 0 if the path itself is a directory.
9079 * Return 1 if the path leads to a file.
9080 * Return -1 for if the path is too long.
9081 * Return -2 if path can not be created.
9082*/
9083static int
9084put_dir(struct mg_connection *conn, const char *path)
9085{
9086 char buf[PATH_MAX];
9087 const char *s, *p;
11fdf7f2 9088 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
9089 size_t len;
9090 int res = 1;
9091
9092 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
9093 len = (size_t)(p - path);
9094 if (len >= sizeof(buf)) {
9095 /* path too long */
9096 res = -1;
9097 break;
9098 }
9099 memcpy(buf, path, len);
9100 buf[len] = '\0';
9101
9102 /* Try to create intermediate directory */
9103 DEBUG_TRACE("mkdir(%s)", buf);
11fdf7f2 9104 if (!mg_stat(conn, buf, &file.stat) && mg_mkdir(conn, buf, 0755) != 0) {
7c673cae
FG
9105 /* path does not exixt and can not be created */
9106 res = -2;
9107 break;
9108 }
9109
9110 /* Is path itself a directory? */
9111 if (p[1] == '\0') {
9112 res = 0;
9113 }
9114 }
9115
9116 return res;
9117}
9118
9119
9120static void
9121remove_bad_file(const struct mg_connection *conn, const char *path)
9122{
9123 int r = mg_remove(conn, path);
9124 if (r != 0) {
9125 mg_cry(conn, "%s: Cannot remove invalid file %s", __func__, path);
9126 }
9127}
9128
9129
9130long long
9131mg_store_body(struct mg_connection *conn, const char *path)
9132{
9133 char buf[MG_BUF_LEN];
9134 long long len = 0;
9135 int ret, n;
11fdf7f2 9136 struct mg_file fi;
7c673cae
FG
9137
9138 if (conn->consumed_content != 0) {
9139 mg_cry(conn, "%s: Contents already consumed", __func__);
9140 return -11;
9141 }
9142
9143 ret = put_dir(conn, path);
9144 if (ret < 0) {
9145 /* -1 for path too long,
9146 * -2 for path can not be created. */
9147 return ret;
9148 }
9149 if (ret != 1) {
9150 /* Return 0 means, path itself is a directory. */
9151 return 0;
9152 }
9153
11fdf7f2 9154 if (mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &fi) == 0) {
7c673cae
FG
9155 return -12;
9156 }
9157
9158 ret = mg_read(conn, buf, sizeof(buf));
9159 while (ret > 0) {
11fdf7f2 9160 n = (int)fwrite(buf, 1, (size_t)ret, fi.access.fp);
7c673cae 9161 if (n != ret) {
11fdf7f2
TL
9162 (void)mg_fclose(
9163 &fi.access); /* File is bad and will be removed anyway. */
7c673cae
FG
9164 remove_bad_file(conn, path);
9165 return -13;
9166 }
11fdf7f2 9167 len += ret;
7c673cae
FG
9168 ret = mg_read(conn, buf, sizeof(buf));
9169 }
9170
11fdf7f2
TL
9171 /* File is open for writing. If fclose fails, there was probably an
9172 * error flushing the buffer to disk, so the file on disk might be
9173 * broken. Delete it and return an error to the caller. */
9174 if (mg_fclose(&fi.access) != 0) {
7c673cae
FG
9175 remove_bad_file(conn, path);
9176 return -14;
9177 }
9178
9179 return len;
9180}
9181
9182
11fdf7f2
TL
9183/* Parse a buffer:
9184 * Forward the string pointer till the end of a word, then
9185 * terminate it and forward till the begin of the next word.
9186 */
9187static int
9188skip_to_end_of_word_and_terminate(char **ppw, int eol)
7c673cae 9189{
11fdf7f2
TL
9190 /* Forward until a space is found - use isgraph here */
9191 /* See http://www.cplusplus.com/reference/cctype/ */
9192 while (isgraph(**ppw)) {
9193 (*ppw)++;
9194 }
7c673cae 9195
11fdf7f2
TL
9196 /* Check end of word */
9197 if (eol) {
9198 /* must be a end of line */
9199 if ((**ppw != '\r') && (**ppw != '\n')) {
9200 return -1;
9201 }
9202 } else {
9203 /* must be a end of a word, but not a line */
9204 if (**ppw != ' ') {
9205 return -1;
9206 }
7c673cae
FG
9207 }
9208
11fdf7f2
TL
9209 /* Terminate and forward to the next word */
9210 do {
9211 **ppw = 0;
9212 (*ppw)++;
9213 } while ((**ppw) && isspace(**ppw));
9214
9215 /* Check after term */
9216 if (!eol) {
9217 /* if it's not the end of line, there must be a next word */
9218 if (!isgraph(**ppw)) {
9219 return -1;
9220 }
9221 }
9222
9223 /* ok */
9224 return 1;
9225}
9226
9227
9228/* Parse HTTP headers from the given buffer, advance buf pointer
9229 * to the point where parsing stopped.
9230 * All parameters must be valid pointers (not NULL).
9231 * Return <0 on error. */
9232static int
9233parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS])
9234{
9235 int i;
9236 int num_headers = 0;
7c673cae 9237
11fdf7f2 9238 for (i = 0; i < (int)MG_MAX_HEADERS; i++) {
7c673cae 9239 char *dp = *buf;
11fdf7f2 9240 while ((*dp != ':') && (*dp >= 33) && (*dp <= 126)) {
7c673cae
FG
9241 dp++;
9242 }
11fdf7f2
TL
9243 if (dp == *buf) {
9244 /* End of headers reached. */
7c673cae
FG
9245 break;
9246 }
11fdf7f2
TL
9247 if (*dp != ':') {
9248 /* This is not a valid field. */
9249 return -1;
9250 }
9251
9252 /* End of header key (*dp == ':') */
9253 /* Truncate here and set the key name */
9254 *dp = 0;
9255 hdr[i].name = *buf;
9256 do {
9257 dp++;
9258 } while (*dp == ' ');
7c673cae 9259
11fdf7f2
TL
9260 /* The rest of the line is the value */
9261 hdr[i].value = dp;
9262 *buf = dp + strcspn(dp, "\r\n");
9263 if (((*buf)[0] != '\r') || ((*buf)[1] != '\n')) {
9264 *buf = NULL;
7c673cae
FG
9265 }
9266
11fdf7f2 9267 num_headers = i + 1;
7c673cae
FG
9268 if (*buf) {
9269 (*buf)[0] = 0;
9270 (*buf)[1] = 0;
9271 *buf += 2;
9272 } else {
9273 *buf = dp;
9274 break;
9275 }
9276
11fdf7f2 9277 if ((*buf)[0] == '\r') {
7c673cae
FG
9278 /* This is the end of the header */
9279 break;
9280 }
9281 }
11fdf7f2 9282 return num_headers;
7c673cae
FG
9283}
9284
9285
11fdf7f2
TL
9286struct mg_http_method_info {
9287 const char *name;
9288 int request_has_body;
9289 int response_has_body;
9290 int is_safe;
9291 int is_idempotent;
9292 int is_cacheable;
9293};
9294
9295
9296/* https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods */
9297static struct mg_http_method_info http_methods[] = {
9298 /* HTTP (RFC 2616) */
9299 {"GET", 0, 1, 1, 1, 1},
9300 {"POST", 1, 1, 0, 0, 0},
9301 {"PUT", 1, 0, 0, 1, 0},
9302 {"DELETE", 0, 0, 0, 1, 0},
9303 {"HEAD", 0, 0, 1, 1, 1},
9304 {"OPTIONS", 0, 0, 1, 1, 0},
9305 {"CONNECT", 1, 1, 0, 0, 0},
9306 /* TRACE method (RFC 2616) is not supported for security reasons */
9307
9308 /* PATCH method (RFC 5789) */
9309 {"PATCH", 1, 0, 0, 0, 0},
9310 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
9311
9312 /* WEBDAV (RFC 2518) */
9313 {"PROPFIND", 0, 1, 1, 1, 0},
9314 /* http://www.webdav.org/specs/rfc4918.html, 9.1:
9315 * Some PROPFIND results MAY be cached, with care,
9316 * as there is no cache validation mechanism for
9317 * most properties. This method is both safe and
9318 * idempotent (see Section 9.1 of [RFC2616]). */
9319 {"MKCOL", 0, 0, 0, 1, 0},
9320 /* http://www.webdav.org/specs/rfc4918.html, 9.1:
9321 * When MKCOL is invoked without a request body,
9322 * the newly created collection SHOULD have no
9323 * members. A MKCOL request message may contain
9324 * a message body. The precise behavior of a MKCOL
9325 * request when the body is present is undefined,
9326 * ... ==> We do not support MKCOL with body data.
9327 * This method is idempotent, but not safe (see
9328 * Section 9.1 of [RFC2616]). Responses to this
9329 * method MUST NOT be cached. */
9330
9331 /* Unsupported WEBDAV Methods: */
9332 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
9333 /* + 11 methods from RFC 3253 */
9334 /* ORDERPATCH (RFC 3648) */
9335 /* ACL (RFC 3744) */
9336 /* SEARCH (RFC 5323) */
9337 /* + MicroSoft extensions
9338 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
9339
9340 /* REPORT method (RFC 3253) */
9341 {"REPORT", 1, 1, 1, 1, 1},
9342 /* REPORT method only allowed for CGI/Lua/LSP and callbacks. */
9343 /* It was defined for WEBDAV in RFC 3253, Sec. 3.6
9344 * (https://tools.ietf.org/html/rfc3253#section-3.6), but seems
9345 * to be useful for REST in case a "GET request with body" is
9346 * required. */
9347
9348 {NULL, 0, 0, 0, 0, 0}
9349 /* end of list */
9350};
9351
9352
9353static const struct mg_http_method_info *
9354get_http_method_info(const char *method)
7c673cae 9355{
11fdf7f2
TL
9356 /* Check if the method is known to the server. The list of all known
9357 * HTTP methods can be found here at
9358 * http://www.iana.org/assignments/http-methods/http-methods.xhtml
9359 */
9360 const struct mg_http_method_info *m = http_methods;
7c673cae 9361
11fdf7f2
TL
9362 while (m->name) {
9363 if (!strcmp(m->name, method)) {
9364 return m;
9365 }
9366 m++;
9367 }
9368 return m;
9369}
7c673cae 9370
7c673cae 9371
11fdf7f2
TL
9372static int
9373is_valid_http_method(const char *method)
9374{
9375 return (get_http_method_info(method) != NULL);
7c673cae
FG
9376}
9377
9378
9379/* Parse HTTP request, fill in mg_request_info structure.
9380 * This function modifies the buffer by NUL-terminating
11fdf7f2
TL
9381 * HTTP request components, header names and header values.
9382 * Parameters:
9383 * buf (in/out): pointer to the HTTP header to parse and split
9384 * len (in): length of HTTP header buffer
9385 * re (out): parsed header as mg_request_info
9386 * buf and ri must be valid pointers (not NULL), len>0.
9387 * Returns <0 on error. */
7c673cae 9388static int
11fdf7f2 9389parse_http_request(int check_method, char *buf, int len, struct mg_request_info *ri)
7c673cae 9390{
11fdf7f2
TL
9391 int request_length;
9392 int init_skip = 0;
9393
9394 /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
9395 * remote_port */
9396 ri->remote_user = ri->request_method = ri->request_uri = ri->http_version =
9397 NULL;
9398 ri->num_headers = 0;
9399
9400 /* RFC says that all initial whitespaces should be ingored */
9401 /* This included all leading \r and \n (isspace) */
9402 /* See table: http://www.cplusplus.com/reference/cctype/ */
9403 while ((len > 0) && isspace(*(unsigned char *)buf)) {
9404 buf++;
9405 len--;
9406 init_skip++;
9407 }
7c673cae 9408
11fdf7f2
TL
9409 if (len == 0) {
9410 /* Incomplete request */
7c673cae
FG
9411 return 0;
9412 }
9413
11fdf7f2
TL
9414 /* Control characters are not allowed, including zero */
9415 if (iscntrl(*(unsigned char *)buf)) {
9416 return -1;
9417 }
7c673cae 9418
11fdf7f2
TL
9419 /* Find end of HTTP header */
9420 request_length = get_http_header_len(buf, len);
9421 if (request_length <= 0) {
9422 return request_length;
9423 }
9424 buf[request_length - 1] = '\0';
7c673cae 9425
11fdf7f2
TL
9426 if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) {
9427 return -1;
9428 }
7c673cae 9429
11fdf7f2
TL
9430 /* The first word has to be the HTTP method */
9431 ri->request_method = buf;
7c673cae 9432
11fdf7f2
TL
9433 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
9434 return -1;
9435 }
9436
9437 /* Check for a valid http method */
9438 if (check_method && !is_valid_http_method(ri->request_method)) {
9439 return -1;
9440 }
9441
9442 /* The second word is the URI */
9443 ri->request_uri = skip_quoted(&buf, " ", " ", 0);
9444
9445 /* Next would be the HTTP version */
9446 ri->http_version = buf;
9447
9448 if (skip_to_end_of_word_and_terminate(&buf, 1) <= 0) {
9449 return -1;
9450 }
9451
9452 /* Check for a valid HTTP version key */
9453 if (strncmp(ri->http_version, "HTTP/", 5) != 0) {
9454 /* Invalid request */
9455 return -1;
9456 }
9457 ri->http_version += 5;
9458
9459
9460 /* Parse all HTTP headers */
9461 ri->num_headers = parse_http_headers(&buf, ri->http_headers);
9462 if (ri->num_headers < 0) {
9463 /* Error while parsing headers */
9464 return -1;
7c673cae 9465 }
11fdf7f2
TL
9466
9467 return request_length + init_skip;
9468}
9469
9470
9471static int
9472parse_http_response(char *buf, int len, struct mg_response_info *ri)
9473{
9474 int response_length;
9475 int init_skip = 0;
9476 char *tmp, *tmp2;
9477 long l;
9478
9479 /* Initialize elements. */
9480 ri->http_version = ri->status_text = NULL;
9481 ri->num_headers = ri->status_code = 0;
9482
9483 /* RFC says that all initial whitespaces should be ingored */
9484 /* This included all leading \r and \n (isspace) */
9485 /* See table: http://www.cplusplus.com/reference/cctype/ */
9486 while ((len > 0) && isspace(*(unsigned char *)buf)) {
9487 buf++;
9488 len--;
9489 init_skip++;
9490 }
9491
9492 if (len == 0) {
9493 /* Incomplete request */
9494 return 0;
9495 }
9496
9497 /* Control characters are not allowed, including zero */
9498 if (iscntrl(*(unsigned char *)buf)) {
9499 return -1;
9500 }
9501
9502 /* Find end of HTTP header */
9503 response_length = get_http_header_len(buf, len);
9504 if (response_length <= 0) {
9505 return response_length;
9506 }
9507 buf[response_length - 1] = '\0';
9508
9509
9510 /* TODO: Define mg_response_info and implement parsing */
9511 (void)buf;
9512 (void)len;
9513 (void)ri;
9514
9515 /* RFC says that all initial whitespaces should be ingored */
9516 while ((*buf != '\0') && isspace(*(unsigned char *)buf)) {
9517 buf++;
9518 }
9519 if ((*buf == 0) || (*buf == '\r') || (*buf == '\n')) {
9520 return -1;
9521 }
9522
9523 /* The first word is the HTTP version */
9524 /* Check for a valid HTTP version key */
9525 if (strncmp(buf, "HTTP/", 5) != 0) {
9526 /* Invalid request */
9527 return -1;
9528 }
9529 buf += 5;
9530 if (!isgraph(buf[0])) {
9531 /* Invalid request */
9532 return -1;
9533 }
9534 ri->http_version = buf;
9535
9536 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
9537 return -1;
9538 }
9539
9540 /* The second word is the status as a number */
9541 tmp = buf;
9542
9543 if (skip_to_end_of_word_and_terminate(&buf, 0) <= 0) {
9544 return -1;
9545 }
9546
9547 l = strtol(tmp, &tmp2, 10);
9548 if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
9549 /* Everything else but a 3 digit code is invalid */
9550 return -1;
9551 }
9552 ri->status_code = (int)l;
9553
9554 /* The rest of the line is the status text */
9555 ri->status_text = buf;
9556
9557 /* Find end of status text */
9558 /* isgraph or isspace = isprint */
9559 while (isprint(*buf)) {
9560 buf++;
9561 }
9562 if ((*buf != '\r') && (*buf != '\n')) {
9563 return -1;
9564 }
9565 /* Terminate string and forward buf to next line */
9566 do {
9567 *buf = 0;
9568 buf++;
9569 } while ((*buf) && isspace(*buf));
9570
9571
9572 /* Parse all HTTP headers */
9573 ri->num_headers = parse_http_headers(&buf, ri->http_headers);
9574 if (ri->num_headers < 0) {
9575 /* Error while parsing headers */
9576 return -1;
9577 }
9578
9579 return response_length + init_skip;
7c673cae
FG
9580}
9581
9582
9583/* Keep reading the input (either opened file descriptor fd, or socket sock,
9584 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
9585 * buffer (which marks the end of HTTP request). Buffer buf may already
9586 * have some data. The length of the data is stored in nread.
9587 * Upon every read operation, increase nread by the number of bytes read. */
9588static int
11fdf7f2 9589read_message(FILE *fp,
7c673cae
FG
9590 struct mg_connection *conn,
9591 char *buf,
9592 int bufsiz,
9593 int *nread)
9594{
9595 int request_len, n = 0;
9596 struct timespec last_action_time;
9597 double request_timeout;
9598
9599 if (!conn) {
9600 return 0;
9601 }
9602
9603 memset(&last_action_time, 0, sizeof(last_action_time));
9604
9605 if (conn->ctx->config[REQUEST_TIMEOUT]) {
9606 /* value of request_timeout is in seconds, config in milliseconds */
9607 request_timeout = atof(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
9608 } else {
9609 request_timeout = -1.0;
9610 }
11fdf7f2
TL
9611 if (conn->handled_requests > 0) {
9612 if (conn->ctx->config[KEEP_ALIVE_TIMEOUT]) {
9613 request_timeout =
9614 atof(conn->ctx->config[KEEP_ALIVE_TIMEOUT]) / 1000.0;
9615 }
9616 }
7c673cae 9617
11fdf7f2 9618 request_len = get_http_header_len(buf, *nread);
7c673cae
FG
9619
9620 /* first time reading from this connection */
9621 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
9622
11fdf7f2
TL
9623 while (request_len == 0) {
9624 /* Full request not yet received */
9625 if (conn->ctx->stop_flag != 0) {
9626 /* Server is to be stopped. */
9627 return -1;
7c673cae 9628 }
7c673cae 9629
11fdf7f2
TL
9630 if (*nread >= bufsiz) {
9631 /* Request too long */
9632 return -2;
7c673cae
FG
9633 }
9634
11fdf7f2
TL
9635 n = pull_inner(
9636 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
9637 if (n == -2) {
9638 /* Receive error */
9639 return -1;
9640 }
9641 if (n > 0) {
9642 *nread += n;
9643 request_len = get_http_header_len(buf, *nread);
9644 } else {
9645 request_len = 0;
7c673cae
FG
9646 }
9647
11fdf7f2
TL
9648 if ((request_len == 0) && (request_timeout >= 0)) {
9649 if (mg_difftimespec(&last_action_time, &(conn->req_time))
9650 > request_timeout) {
9651 /* Timeout */
9652 return -1;
9653 }
9654 clock_gettime(CLOCK_MONOTONIC, &last_action_time);
9655 }
7c673cae 9656 }
11fdf7f2
TL
9657
9658 return request_len;
7c673cae 9659}
7c673cae
FG
9660
9661
9662#if !defined(NO_CACHING)
9663/* Return True if we should reply 304 Not Modified. */
9664static int
11fdf7f2
TL
9665is_not_modified(const struct mg_connection *conn,
9666 const struct mg_file_stat *filestat)
7c673cae
FG
9667{
9668 char etag[64];
9669 const char *ims = mg_get_header(conn, "If-Modified-Since");
9670 const char *inm = mg_get_header(conn, "If-None-Match");
11fdf7f2
TL
9671 construct_etag(etag, sizeof(etag), filestat);
9672
9673 return ((inm != NULL) && !mg_strcasecmp(etag, inm))
9674 || ((ims != NULL)
9675 && (filestat->last_modified <= parse_date_string(ims)));
7c673cae
FG
9676}
9677#endif /* !NO_CACHING */
9678
9679
9680#if !defined(NO_CGI) || !defined(NO_FILES)
9681static int
9682forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
9683{
9684 const char *expect, *body;
9685 char buf[MG_BUF_LEN];
9686 int to_read, nread, success = 0;
9687 int64_t buffered_len;
9688 double timeout = -1.0;
9689
9690 if (!conn) {
9691 return 0;
9692 }
9693 if (conn->ctx->config[REQUEST_TIMEOUT]) {
9694 timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
9695 }
9696
9697 expect = mg_get_header(conn, "Expect");
9698 /* assert(fp != NULL); */
9699 if (!fp) {
11fdf7f2 9700 mg_send_http_error(conn, 500, "%s", "Error: NULL File");
7c673cae
FG
9701 return 0;
9702 }
9703
11fdf7f2 9704 if ((conn->content_len == -1) && (!conn->is_chunked)) {
7c673cae 9705 /* Content length is not specified by the client. */
11fdf7f2
TL
9706 mg_send_http_error(conn,
9707 411,
9708 "%s",
9709 "Error: Client did not specify content length");
7c673cae
FG
9710 } else if ((expect != NULL)
9711 && (mg_strcasecmp(expect, "100-continue") != 0)) {
11fdf7f2
TL
9712 /* Client sent an "Expect: xyz" header and xyz is not 100-continue.
9713 */
9714 mg_send_http_error(conn,
9715 417,
9716 "Error: Can not fulfill expectation %s",
9717 expect);
7c673cae
FG
9718 } else {
9719 if (expect != NULL) {
9720 (void)mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
9721 conn->status_code = 100;
9722 } else {
9723 conn->status_code = 200;
9724 }
9725
9726 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
9727 - conn->consumed_content;
9728
9729 /* assert(buffered_len >= 0); */
9730 /* assert(conn->consumed_content == 0); */
9731
9732 if ((buffered_len < 0) || (conn->consumed_content != 0)) {
11fdf7f2 9733 mg_send_http_error(conn, 500, "%s", "Error: Size mismatch");
7c673cae
FG
9734 return 0;
9735 }
9736
9737 if (buffered_len > 0) {
9738 if ((int64_t)buffered_len > conn->content_len) {
9739 buffered_len = (int)conn->content_len;
9740 }
9741 body = conn->buf + conn->request_len + conn->consumed_content;
9742 push_all(conn->ctx, fp, sock, ssl, body, (int64_t)buffered_len);
9743 conn->consumed_content += buffered_len;
9744 }
9745
9746 nread = 0;
9747 while (conn->consumed_content < conn->content_len) {
9748 to_read = sizeof(buf);
9749 if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
9750 to_read = (int)(conn->content_len - conn->consumed_content);
9751 }
11fdf7f2
TL
9752 nread = pull_inner(NULL, conn, buf, to_read, timeout);
9753 if (nread == -2) {
9754 /* error */
7c673cae
FG
9755 break;
9756 }
11fdf7f2
TL
9757 if (nread > 0) {
9758 if (push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) {
9759 break;
9760 }
9761 }
7c673cae
FG
9762 conn->consumed_content += nread;
9763 }
9764
9765 if (conn->consumed_content == conn->content_len) {
9766 success = (nread >= 0);
9767 }
9768
9769 /* Each error code path in this function must send an error */
9770 if (!success) {
9771 /* NOTE: Maybe some data has already been sent. */
9772 /* TODO (low): If some data has been sent, a correct error
9773 * reply can no longer be sent, so just close the connection */
11fdf7f2 9774 mg_send_http_error(conn, 500, "%s", "");
7c673cae
FG
9775 }
9776 }
9777
9778 return success;
9779}
9780#endif
9781
9782#if !defined(NO_CGI)
11fdf7f2
TL
9783/* This structure helps to create an environment for the spawned CGI
9784 * program.
7c673cae
FG
9785 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
9786 * last element must be NULL.
11fdf7f2
TL
9787 * However, on Windows there is a requirement that all these
9788 * VARIABLE=VALUE\0
7c673cae
FG
9789 * strings must reside in a contiguous buffer. The end of the buffer is
9790 * marked by two '\0' characters.
9791 * We satisfy both worlds: we create an envp array (which is vars), all
9792 * entries are actually pointers inside buf. */
9793struct cgi_environment {
9794 struct mg_connection *conn;
9795 /* Data block */
9796 char *buf; /* Environment buffer */
9797 size_t buflen; /* Space available in buf */
9798 size_t bufused; /* Space taken in buf */
9799 /* Index block */
9800 char **var; /* char **envp */
9801 size_t varlen; /* Number of variables available in var */
9802 size_t varused; /* Number of variables stored in var */
9803};
9804
9805
9806static void addenv(struct cgi_environment *env,
9807 PRINTF_FORMAT_STRING(const char *fmt),
9808 ...) PRINTF_ARGS(2, 3);
9809
9810/* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
9811 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
9812static void
9813addenv(struct cgi_environment *env, const char *fmt, ...)
9814{
9815 size_t n, space;
11fdf7f2 9816 int truncated = 0;
7c673cae
FG
9817 char *added;
9818 va_list ap;
9819
9820 /* Calculate how much space is left in the buffer */
9821 space = (env->buflen - env->bufused);
9822
9823 /* Calculate an estimate for the required space */
9824 n = strlen(fmt) + 2 + 128;
9825
9826 do {
9827 if (space <= n) {
9828 /* Allocate new buffer */
9829 n = env->buflen + CGI_ENVIRONMENT_SIZE;
11fdf7f2 9830 added = (char *)mg_realloc_ctx(env->buf, n, env->conn->ctx);
7c673cae
FG
9831 if (!added) {
9832 /* Out of memory */
9833 mg_cry(env->conn,
9834 "%s: Cannot allocate memory for CGI variable [%s]",
9835 __func__,
9836 fmt);
9837 return;
9838 }
9839 env->buf = added;
9840 env->buflen = n;
9841 space = (env->buflen - env->bufused);
9842 }
9843
9844 /* Make a pointer to the free space int the buffer */
9845 added = env->buf + env->bufused;
9846
9847 /* Copy VARIABLE=VALUE\0 string into the free space */
9848 va_start(ap, fmt);
9849 mg_vsnprintf(env->conn, &truncated, added, (size_t)space, fmt, ap);
9850 va_end(ap);
9851
9852 /* Do not add truncated strings to the environment */
9853 if (truncated) {
9854 /* Reallocate the buffer */
9855 space = 0;
9856 n = 1;
9857 }
9858 } while (truncated);
9859
9860 /* Calculate number of bytes added to the environment */
9861 n = strlen(added) + 1;
9862 env->bufused += n;
9863
9864 /* Now update the variable index */
9865 space = (env->varlen - env->varused);
9866 if (space < 2) {
9867 mg_cry(env->conn,
9868 "%s: Cannot register CGI variable [%s]",
9869 __func__,
9870 fmt);
9871 return;
9872 }
9873
9874 /* Append a pointer to the added string into the envp array */
9875 env->var[env->varused] = added;
9876 env->varused++;
9877}
9878
11fdf7f2 9879/* Return 0 on success, non-zero if an error occurs. */
7c673cae 9880
11fdf7f2 9881static int
7c673cae
FG
9882prepare_cgi_environment(struct mg_connection *conn,
9883 const char *prog,
9884 struct cgi_environment *env)
9885{
9886 const char *s;
9887 struct vec var_vec;
9888 char *p, src_addr[IP_ADDR_STR_LEN], http_var_name[128];
11fdf7f2 9889 int i, truncated, uri_len;
7c673cae 9890
11fdf7f2
TL
9891 if ((conn == NULL) || (prog == NULL) || (env == NULL)) {
9892 return -1;
7c673cae
FG
9893 }
9894
9895 env->conn = conn;
9896 env->buflen = CGI_ENVIRONMENT_SIZE;
9897 env->bufused = 0;
11fdf7f2
TL
9898 env->buf = (char *)mg_malloc_ctx(env->buflen, conn->ctx);
9899 if (env->buf == NULL) {
9900 mg_cry(conn,
9901 "%s: Not enough memory for environmental buffer",
9902 __func__);
9903 return -1;
9904 }
7c673cae
FG
9905 env->varlen = MAX_CGI_ENVIR_VARS;
9906 env->varused = 0;
11fdf7f2
TL
9907 env->var = (char **)mg_malloc_ctx(env->buflen * sizeof(char *), conn->ctx);
9908 if (env->var == NULL) {
9909 mg_cry(conn,
9910 "%s: Not enough memory for environmental variables",
9911 __func__);
9912 mg_free(env->buf);
9913 return -1;
9914 }
7c673cae
FG
9915
9916 addenv(env, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
9917 addenv(env, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
9918 addenv(env, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
9919 addenv(env, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
9920
9921 /* Prepare the environment block */
9922 addenv(env, "%s", "GATEWAY_INTERFACE=CGI/1.1");
9923 addenv(env, "%s", "SERVER_PROTOCOL=HTTP/1.1");
9924 addenv(env, "%s", "REDIRECT_STATUS=200"); /* For PHP */
9925
9926#if defined(USE_IPV6)
9927 if (conn->client.lsa.sa.sa_family == AF_INET6) {
9928 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
9929 } else
9930#endif
9931 {
9932 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
9933 }
9934
9935 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
9936 addenv(env, "REMOTE_ADDR=%s", src_addr);
9937
9938 addenv(env, "REQUEST_METHOD=%s", conn->request_info.request_method);
9939 addenv(env, "REMOTE_PORT=%d", conn->request_info.remote_port);
9940
9941 addenv(env, "REQUEST_URI=%s", conn->request_info.request_uri);
9942 addenv(env, "LOCAL_URI=%s", conn->request_info.local_uri);
9943
9944 /* SCRIPT_NAME */
11fdf7f2
TL
9945 uri_len = (int)strlen(conn->request_info.local_uri);
9946 if (conn->path_info == NULL) {
9947 if (conn->request_info.local_uri[uri_len - 1] != '/') {
9948 /* URI: /path_to_script/script.cgi */
9949 addenv(env, "SCRIPT_NAME=%s", conn->request_info.local_uri);
9950 } else {
9951 /* URI: /path_to_script/ ... using index.cgi */
9952 const char *index_file = strrchr(prog, '/');
9953 if (index_file) {
9954 addenv(env,
9955 "SCRIPT_NAME=%s%s",
9956 conn->request_info.local_uri,
9957 index_file + 1);
9958 }
9959 }
9960 } else {
9961 /* URI: /path_to_script/script.cgi/path_info */
9962 addenv(env,
9963 "SCRIPT_NAME=%.*s",
9964 uri_len - (int)strlen(conn->path_info),
9965 conn->request_info.local_uri);
9966 }
7c673cae
FG
9967
9968 addenv(env, "SCRIPT_FILENAME=%s", prog);
9969 if (conn->path_info == NULL) {
9970 addenv(env, "PATH_TRANSLATED=%s", conn->ctx->config[DOCUMENT_ROOT]);
9971 } else {
9972 addenv(env,
9973 "PATH_TRANSLATED=%s%s",
9974 conn->ctx->config[DOCUMENT_ROOT],
9975 conn->path_info);
9976 }
9977
11fdf7f2 9978 addenv(env, "HTTPS=%s", (conn->ssl == NULL) ? "off" : "on");
7c673cae
FG
9979
9980 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
9981 addenv(env, "CONTENT_TYPE=%s", s);
9982 }
9983 if (conn->request_info.query_string != NULL) {
9984 addenv(env, "QUERY_STRING=%s", conn->request_info.query_string);
9985 }
9986 if ((s = mg_get_header(conn, "Content-Length")) != NULL) {
9987 addenv(env, "CONTENT_LENGTH=%s", s);
9988 }
9989 if ((s = getenv("PATH")) != NULL) {
9990 addenv(env, "PATH=%s", s);
9991 }
9992 if (conn->path_info != NULL) {
9993 addenv(env, "PATH_INFO=%s", conn->path_info);
9994 }
9995
9996 if (conn->status_code > 0) {
9997 /* CGI error handler should show the status code */
9998 addenv(env, "STATUS=%d", conn->status_code);
9999 }
10000
10001#if defined(_WIN32)
10002 if ((s = getenv("COMSPEC")) != NULL) {
10003 addenv(env, "COMSPEC=%s", s);
10004 }
10005 if ((s = getenv("SYSTEMROOT")) != NULL) {
10006 addenv(env, "SYSTEMROOT=%s", s);
10007 }
10008 if ((s = getenv("SystemDrive")) != NULL) {
10009 addenv(env, "SystemDrive=%s", s);
10010 }
10011 if ((s = getenv("ProgramFiles")) != NULL) {
10012 addenv(env, "ProgramFiles=%s", s);
10013 }
10014 if ((s = getenv("ProgramFiles(x86)")) != NULL) {
10015 addenv(env, "ProgramFiles(x86)=%s", s);
10016 }
10017#else
10018 if ((s = getenv("LD_LIBRARY_PATH")) != NULL) {
10019 addenv(env, "LD_LIBRARY_PATH=%s", s);
10020 }
10021#endif /* _WIN32 */
10022
10023 if ((s = getenv("PERLLIB")) != NULL) {
10024 addenv(env, "PERLLIB=%s", s);
10025 }
10026
10027 if (conn->request_info.remote_user != NULL) {
10028 addenv(env, "REMOTE_USER=%s", conn->request_info.remote_user);
10029 addenv(env, "%s", "AUTH_TYPE=Digest");
10030 }
10031
10032 /* Add all headers as HTTP_* variables */
10033 for (i = 0; i < conn->request_info.num_headers; i++) {
10034
10035 (void)mg_snprintf(conn,
10036 &truncated,
10037 http_var_name,
10038 sizeof(http_var_name),
10039 "HTTP_%s",
10040 conn->request_info.http_headers[i].name);
10041
10042 if (truncated) {
10043 mg_cry(conn,
10044 "%s: HTTP header variable too long [%s]",
10045 __func__,
10046 conn->request_info.http_headers[i].name);
10047 continue;
10048 }
10049
10050 /* Convert variable name into uppercase, and change - to _ */
10051 for (p = http_var_name; *p != '\0'; p++) {
10052 if (*p == '-') {
10053 *p = '_';
10054 }
10055 *p = (char)toupper(*(unsigned char *)p);
10056 }
10057
10058 addenv(env,
10059 "%s=%s",
10060 http_var_name,
10061 conn->request_info.http_headers[i].value);
10062 }
10063
10064 /* Add user-specified variables */
10065 s = conn->ctx->config[CGI_ENVIRONMENT];
10066 while ((s = next_option(s, &var_vec, NULL)) != NULL) {
10067 addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr);
10068 }
10069
10070 env->var[env->varused] = NULL;
10071 env->buf[env->bufused] = '\0';
11fdf7f2
TL
10072
10073 return 0;
7c673cae
FG
10074}
10075
10076
10077static void
10078handle_cgi_request(struct mg_connection *conn, const char *prog)
10079{
10080 char *buf;
10081 size_t buflen;
10082 int headers_len, data_len, i, truncated;
10083 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
10084 const char *status, *status_text, *connection_state;
10085 char *pbuf, dir[PATH_MAX], *p;
10086 struct mg_request_info ri;
10087 struct cgi_environment blk;
10088 FILE *in = NULL, *out = NULL, *err = NULL;
11fdf7f2 10089 struct mg_file fout = STRUCT_FILE_INITIALIZER;
7c673cae
FG
10090 pid_t pid = (pid_t)-1;
10091
10092 if (conn == NULL) {
10093 return;
10094 }
10095
10096 buf = NULL;
10097 buflen = 16384;
11fdf7f2
TL
10098 i = prepare_cgi_environment(conn, prog, &blk);
10099 if (i != 0) {
10100 blk.buf = NULL;
10101 blk.var = NULL;
10102 goto done;
10103 }
7c673cae
FG
10104
10105 /* CGI must be executed in its own directory. 'dir' must point to the
10106 * directory containing executable program, 'p' must point to the
10107 * executable program name relative to 'dir'. */
10108 (void)mg_snprintf(conn, &truncated, dir, sizeof(dir), "%s", prog);
10109
10110 if (truncated) {
10111 mg_cry(conn, "Error: CGI program \"%s\": Path too long", prog);
11fdf7f2 10112 mg_send_http_error(conn, 500, "Error: %s", "CGI path too long");
7c673cae
FG
10113 goto done;
10114 }
10115
10116 if ((p = strrchr(dir, '/')) != NULL) {
10117 *p++ = '\0';
10118 } else {
11fdf7f2
TL
10119 dir[0] = '.';
10120 dir[1] = '\0';
7c673cae
FG
10121 p = (char *)prog;
10122 }
10123
11fdf7f2 10124 if ((pipe(fdin) != 0) || (pipe(fdout) != 0) || (pipe(fderr) != 0)) {
7c673cae
FG
10125 status = strerror(ERRNO);
10126 mg_cry(conn,
10127 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
10128 prog,
10129 status);
11fdf7f2
TL
10130 mg_send_http_error(conn,
10131 500,
10132 "Error: Cannot create CGI pipe: %s",
10133 status);
7c673cae
FG
10134 goto done;
10135 }
10136
11fdf7f2 10137 DEBUG_TRACE("CGI: spawn %s %s\n", dir, p);
7c673cae
FG
10138 pid = spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
10139
10140 if (pid == (pid_t)-1) {
10141 status = strerror(ERRNO);
10142 mg_cry(conn,
10143 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
10144 prog,
10145 status);
11fdf7f2
TL
10146 mg_send_http_error(conn,
10147 500,
10148 "Error: Cannot spawn CGI process [%s]: %s",
10149 prog,
10150 status);
7c673cae
FG
10151 goto done;
10152 }
10153
11fdf7f2
TL
10154 /* Make sure child closes all pipe descriptors. It must dup them to 0,1
10155 */
7c673cae
FG
10156 set_close_on_exec((SOCKET)fdin[0], conn); /* stdin read */
10157 set_close_on_exec((SOCKET)fdout[1], conn); /* stdout write */
10158 set_close_on_exec((SOCKET)fderr[1], conn); /* stderr write */
10159 set_close_on_exec((SOCKET)fdin[1], conn); /* stdin write */
10160 set_close_on_exec((SOCKET)fdout[0], conn); /* stdout read */
10161 set_close_on_exec((SOCKET)fderr[0], conn); /* stderr read */
10162
10163 /* Parent closes only one side of the pipes.
10164 * If we don't mark them as closed, close() attempt before
10165 * return from this function throws an exception on Windows.
10166 * Windows does not like when closed descriptor is closed again. */
10167 (void)close(fdin[0]);
10168 (void)close(fdout[1]);
10169 (void)close(fderr[1]);
10170 fdin[0] = fdout[1] = fderr[1] = -1;
10171
10172 if ((in = fdopen(fdin[1], "wb")) == NULL) {
10173 status = strerror(ERRNO);
10174 mg_cry(conn,
10175 "Error: CGI program \"%s\": Can not open stdin: %s",
10176 prog,
10177 status);
11fdf7f2
TL
10178 mg_send_http_error(conn,
10179 500,
10180 "Error: CGI can not open fdin\nfopen: %s",
10181 status);
7c673cae
FG
10182 goto done;
10183 }
10184
10185 if ((out = fdopen(fdout[0], "rb")) == NULL) {
10186 status = strerror(ERRNO);
10187 mg_cry(conn,
10188 "Error: CGI program \"%s\": Can not open stdout: %s",
10189 prog,
10190 status);
11fdf7f2
TL
10191 mg_send_http_error(conn,
10192 500,
10193 "Error: CGI can not open fdout\nfopen: %s",
10194 status);
7c673cae
FG
10195 goto done;
10196 }
10197
10198 if ((err = fdopen(fderr[0], "rb")) == NULL) {
10199 status = strerror(ERRNO);
10200 mg_cry(conn,
10201 "Error: CGI program \"%s\": Can not open stderr: %s",
10202 prog,
10203 status);
11fdf7f2
TL
10204 mg_send_http_error(conn,
10205 500,
10206 "Error: CGI can not open fdout\nfopen: %s",
10207 status);
7c673cae
FG
10208 goto done;
10209 }
10210
10211 setbuf(in, NULL);
10212 setbuf(out, NULL);
10213 setbuf(err, NULL);
11fdf7f2
TL
10214 fout.access.fp = out;
10215
10216 if ((conn->request_info.content_length != 0) || (conn->is_chunked)) {
10217 DEBUG_TRACE("CGI: send body data (%lli)\n",
10218 (signed long long)conn->request_info.content_length);
7c673cae 10219
7c673cae
FG
10220 /* This is a POST/PUT request, or another request with body data. */
10221 if (!forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
10222 /* Error sending the body data */
10223 mg_cry(conn,
10224 "Error: CGI program \"%s\": Forward body data failed",
10225 prog);
10226 goto done;
10227 }
10228 }
10229
10230 /* Close so child gets an EOF. */
10231 fclose(in);
10232 in = NULL;
10233 fdin[1] = -1;
10234
10235 /* Now read CGI reply into a buffer. We need to set correct
10236 * status code, thus we need to see all HTTP headers first.
10237 * Do not send anything back to client, until we buffer in all
10238 * HTTP headers. */
10239 data_len = 0;
11fdf7f2 10240 buf = (char *)mg_malloc_ctx(buflen, conn->ctx);
7c673cae 10241 if (buf == NULL) {
11fdf7f2
TL
10242 mg_send_http_error(conn,
10243 500,
10244 "Error: Not enough memory for CGI buffer (%u bytes)",
10245 (unsigned int)buflen);
7c673cae
FG
10246 mg_cry(conn,
10247 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
10248 "bytes)",
10249 prog,
10250 (unsigned int)buflen);
10251 goto done;
10252 }
11fdf7f2
TL
10253
10254 DEBUG_TRACE("CGI: %s", "wait for response");
10255 headers_len = read_message(out, conn, buf, (int)buflen, &data_len);
10256 DEBUG_TRACE("CGI: response: %li", (signed long)headers_len);
10257
7c673cae
FG
10258 if (headers_len <= 0) {
10259
10260 /* Could not parse the CGI response. Check if some error message on
10261 * stderr. */
10262 i = pull_all(err, conn, buf, (int)buflen);
10263 if (i > 0) {
10264 mg_cry(conn,
10265 "Error: CGI program \"%s\" sent error "
10266 "message: [%.*s]",
10267 prog,
10268 i,
10269 buf);
11fdf7f2
TL
10270 mg_send_http_error(conn,
10271 500,
10272 "Error: CGI program \"%s\" sent error "
10273 "message: [%.*s]",
10274 prog,
10275 i,
10276 buf);
7c673cae
FG
10277 } else {
10278 mg_cry(conn,
10279 "Error: CGI program sent malformed or too big "
10280 "(>%u bytes) HTTP headers: [%.*s]",
10281 (unsigned)buflen,
10282 data_len,
10283 buf);
10284
11fdf7f2
TL
10285 mg_send_http_error(conn,
10286 500,
10287 "Error: CGI program sent malformed or too big "
10288 "(>%u bytes) HTTP headers: [%.*s]",
10289 (unsigned)buflen,
10290 data_len,
10291 buf);
7c673cae
FG
10292 }
10293
10294 goto done;
10295 }
11fdf7f2 10296
7c673cae
FG
10297 pbuf = buf;
10298 buf[headers_len - 1] = '\0';
11fdf7f2 10299 ri.num_headers = parse_http_headers(&pbuf, ri.http_headers);
7c673cae
FG
10300
10301 /* Make up and send the status line */
10302 status_text = "OK";
11fdf7f2
TL
10303 if ((status = get_header(ri.http_headers, ri.num_headers, "Status"))
10304 != NULL) {
7c673cae
FG
10305 conn->status_code = atoi(status);
10306 status_text = status;
10307 while (isdigit(*(const unsigned char *)status_text)
10308 || *status_text == ' ') {
10309 status_text++;
10310 }
11fdf7f2
TL
10311 } else if (get_header(ri.http_headers, ri.num_headers, "Location")
10312 != NULL) {
7c673cae
FG
10313 conn->status_code = 302;
10314 } else {
10315 conn->status_code = 200;
10316 }
11fdf7f2
TL
10317 connection_state =
10318 get_header(ri.http_headers, ri.num_headers, "Connection");
7c673cae
FG
10319 if (!header_has_option(connection_state, "keep-alive")) {
10320 conn->must_close = 1;
10321 }
11fdf7f2
TL
10322
10323 DEBUG_TRACE("CGI: response %u %s", conn->status_code, status_text);
10324
7c673cae
FG
10325 (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
10326
10327 /* Send headers */
10328 for (i = 0; i < ri.num_headers; i++) {
10329 mg_printf(conn,
10330 "%s: %s\r\n",
10331 ri.http_headers[i].name,
10332 ri.http_headers[i].value);
10333 }
10334 mg_write(conn, "\r\n", 2);
10335
10336 /* Send chunk of data that may have been read after the headers */
11fdf7f2 10337 mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
7c673cae
FG
10338
10339 /* Read the rest of CGI output and send to the client */
10340 send_file_data(conn, &fout, 0, INT64_MAX);
10341
11fdf7f2
TL
10342 DEBUG_TRACE("CGI: %s", "all data sent");
10343
7c673cae
FG
10344done:
10345 mg_free(blk.var);
10346 mg_free(blk.buf);
10347
10348 if (pid != (pid_t)-1) {
10349 kill(pid, SIGKILL);
10350#if !defined(_WIN32)
10351 {
10352 int st;
10353 while (waitpid(pid, &st, 0) != -1)
10354 ; /* clean zombies */
10355 }
10356#endif
10357 }
10358 if (fdin[0] != -1) {
10359 close(fdin[0]);
10360 }
10361 if (fdout[1] != -1) {
10362 close(fdout[1]);
10363 }
10364
10365 if (in != NULL) {
10366 fclose(in);
10367 } else if (fdin[1] != -1) {
10368 close(fdin[1]);
10369 }
10370
10371 if (out != NULL) {
10372 fclose(out);
10373 } else if (fdout[0] != -1) {
10374 close(fdout[0]);
10375 }
10376
10377 if (err != NULL) {
10378 fclose(err);
10379 } else if (fderr[0] != -1) {
10380 close(fderr[0]);
10381 }
10382
10383 if (buf != NULL) {
10384 mg_free(buf);
10385 }
10386}
10387#endif /* !NO_CGI */
10388
10389
10390#if !defined(NO_FILES)
10391static void
10392mkcol(struct mg_connection *conn, const char *path)
10393{
10394 int rc, body_len;
10395 struct de de;
10396 char date[64];
10397 time_t curtime = time(NULL);
10398
10399 if (conn == NULL) {
10400 return;
10401 }
10402
11fdf7f2
TL
10403 /* TODO (mid): Check the mg_send_http_error situations in this function
10404 */
7c673cae
FG
10405
10406 memset(&de.file, 0, sizeof(de.file));
10407 if (!mg_stat(conn, path, &de.file)) {
10408 mg_cry(conn,
10409 "%s: mg_stat(%s) failed: %s",
10410 __func__,
10411 path,
10412 strerror(ERRNO));
10413 }
10414
10415 if (de.file.last_modified) {
11fdf7f2
TL
10416 /* TODO (mid): This check does not seem to make any sense ! */
10417 /* TODO (mid): Add a webdav unit test first, before changing
10418 * anything here. */
10419 mg_send_http_error(
7c673cae
FG
10420 conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
10421 return;
10422 }
10423
10424 body_len = conn->data_len - conn->request_len;
10425 if (body_len > 0) {
11fdf7f2 10426 mg_send_http_error(
7c673cae
FG
10427 conn, 415, "Error: mkcol(%s): %s", path, strerror(ERRNO));
10428 return;
10429 }
10430
10431 rc = mg_mkdir(conn, path, 0755);
10432
10433 if (rc == 0) {
10434 conn->status_code = 201;
10435 gmt_time_string(date, sizeof(date), &curtime);
10436 mg_printf(conn,
10437 "HTTP/1.1 %d Created\r\n"
10438 "Date: %s\r\n",
10439 conn->status_code,
10440 date);
10441 send_static_cache_header(conn);
11fdf7f2 10442 send_additional_header(conn);
7c673cae
FG
10443 mg_printf(conn,
10444 "Content-Length: 0\r\n"
10445 "Connection: %s\r\n\r\n",
10446 suggest_connection_header(conn));
10447 } else if (rc == -1) {
10448 if (errno == EEXIST) {
11fdf7f2 10449 mg_send_http_error(
7c673cae
FG
10450 conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
10451 } else if (errno == EACCES) {
11fdf7f2 10452 mg_send_http_error(
7c673cae
FG
10453 conn, 403, "Error: mkcol(%s): %s", path, strerror(ERRNO));
10454 } else if (errno == ENOENT) {
11fdf7f2 10455 mg_send_http_error(
7c673cae
FG
10456 conn, 409, "Error: mkcol(%s): %s", path, strerror(ERRNO));
10457 } else {
11fdf7f2
TL
10458 mg_send_http_error(
10459 conn, 500, "fopen(%s): %s", path, strerror(ERRNO));
7c673cae
FG
10460 }
10461 }
10462}
10463
10464
10465static void
10466put_file(struct mg_connection *conn, const char *path)
10467{
11fdf7f2 10468 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
10469 const char *range;
10470 int64_t r1, r2;
10471 int rc;
10472 char date[64];
10473 time_t curtime = time(NULL);
10474
10475 if (conn == NULL) {
10476 return;
10477 }
10478
11fdf7f2 10479 if (mg_stat(conn, path, &file.stat)) {
7c673cae
FG
10480 /* File already exists */
10481 conn->status_code = 200;
10482
11fdf7f2 10483 if (file.stat.is_directory) {
7c673cae
FG
10484 /* This is an already existing directory,
10485 * so there is nothing to do for the server. */
10486 rc = 0;
10487
10488 } else {
10489 /* File exists and is not a directory. */
10490 /* Can it be replaced? */
10491
11fdf7f2 10492 if (file.access.membuf != NULL) {
7c673cae 10493 /* This is an "in-memory" file, that can not be replaced */
11fdf7f2
TL
10494 mg_send_http_error(conn,
10495 405,
10496 "Error: Put not possible\nReplacing %s "
10497 "is not supported",
10498 path);
7c673cae
FG
10499 return;
10500 }
10501
10502 /* Check if the server may write this file */
10503 if (access(path, W_OK) == 0) {
10504 /* Access granted */
10505 conn->status_code = 200;
10506 rc = 1;
10507 } else {
11fdf7f2 10508 mg_send_http_error(
7c673cae
FG
10509 conn,
10510 403,
10511 "Error: Put not possible\nReplacing %s is not allowed",
10512 path);
10513 return;
10514 }
10515 }
10516 } else {
10517 /* File should be created */
10518 conn->status_code = 201;
10519 rc = put_dir(conn, path);
10520 }
10521
10522 if (rc == 0) {
10523 /* put_dir returns 0 if path is a directory */
10524 gmt_time_string(date, sizeof(date), &curtime);
10525 mg_printf(conn,
10526 "HTTP/1.1 %d %s\r\n",
10527 conn->status_code,
10528 mg_get_response_code_text(NULL, conn->status_code));
10529 send_no_cache_header(conn);
11fdf7f2 10530 send_additional_header(conn);
7c673cae
FG
10531 mg_printf(conn,
10532 "Date: %s\r\n"
10533 "Content-Length: 0\r\n"
10534 "Connection: %s\r\n\r\n",
10535 date,
10536 suggest_connection_header(conn));
10537
10538 /* Request to create a directory has been fulfilled successfully.
10539 * No need to put a file. */
10540 return;
10541 }
10542
10543 if (rc == -1) {
10544 /* put_dir returns -1 if the path is too long */
11fdf7f2
TL
10545 mg_send_http_error(conn,
10546 414,
10547 "Error: Path too long\nput_dir(%s): %s",
10548 path,
10549 strerror(ERRNO));
7c673cae
FG
10550 return;
10551 }
10552
10553 if (rc == -2) {
10554 /* put_dir returns -2 if the directory can not be created */
11fdf7f2
TL
10555 mg_send_http_error(conn,
10556 500,
10557 "Error: Can not create directory\nput_dir(%s): %s",
10558 path,
10559 strerror(ERRNO));
7c673cae
FG
10560 return;
10561 }
10562
10563 /* A file should be created or overwritten. */
11fdf7f2
TL
10564 /* Currently CivetWeb does not nead read+write access. */
10565 if (!mg_fopen(conn, path, MG_FOPEN_MODE_WRITE, &file)
10566 || file.access.fp == NULL) {
10567 (void)mg_fclose(&file.access);
10568 mg_send_http_error(conn,
10569 500,
10570 "Error: Can not create file\nfopen(%s): %s",
10571 path,
10572 strerror(ERRNO));
7c673cae
FG
10573 return;
10574 }
10575
11fdf7f2 10576 fclose_on_exec(&file.access, conn);
7c673cae
FG
10577 range = mg_get_header(conn, "Content-Range");
10578 r1 = r2 = 0;
11fdf7f2 10579 if ((range != NULL) && parse_range_header(range, &r1, &r2) > 0) {
7c673cae 10580 conn->status_code = 206; /* Partial content */
11fdf7f2 10581 fseeko(file.access.fp, r1, SEEK_SET);
7c673cae
FG
10582 }
10583
11fdf7f2 10584 if (!forward_body_data(conn, file.access.fp, INVALID_SOCKET, NULL)) {
7c673cae
FG
10585 /* forward_body_data failed.
10586 * The error code has already been sent to the client,
10587 * and conn->status_code is already set. */
11fdf7f2 10588 (void)mg_fclose(&file.access);
7c673cae
FG
10589 return;
10590 }
10591
11fdf7f2
TL
10592 if (mg_fclose(&file.access) != 0) {
10593 /* fclose failed. This might have different reasons, but a likely
10594 * one is "no space on disk", http 507. */
10595 conn->status_code = 507;
10596 }
10597
7c673cae
FG
10598 gmt_time_string(date, sizeof(date), &curtime);
10599 mg_printf(conn,
10600 "HTTP/1.1 %d %s\r\n",
10601 conn->status_code,
10602 mg_get_response_code_text(NULL, conn->status_code));
10603 send_no_cache_header(conn);
11fdf7f2 10604 send_additional_header(conn);
7c673cae
FG
10605 mg_printf(conn,
10606 "Date: %s\r\n"
10607 "Content-Length: 0\r\n"
10608 "Connection: %s\r\n\r\n",
10609 date,
10610 suggest_connection_header(conn));
7c673cae
FG
10611}
10612
10613
10614static void
10615delete_file(struct mg_connection *conn, const char *path)
10616{
10617 struct de de;
10618 memset(&de.file, 0, sizeof(de.file));
10619 if (!mg_stat(conn, path, &de.file)) {
10620 /* mg_stat returns 0 if the file does not exist */
11fdf7f2
TL
10621 mg_send_http_error(conn,
10622 404,
10623 "Error: Cannot delete file\nFile %s not found",
10624 path);
7c673cae
FG
10625 return;
10626 }
10627
11fdf7f2
TL
10628#if 0 /* Ignore if a file in memory is inside a folder */
10629 if (de.access.membuf != NULL) {
10630 /* the file is cached in memory */
10631 mg_send_http_error(
10632 conn,
10633 405,
10634 "Error: Delete not possible\nDeleting %s is not supported",
10635 path);
10636 return;
10637 }
10638#endif
7c673cae
FG
10639
10640 if (de.file.is_directory) {
10641 if (remove_directory(conn, path)) {
10642 /* Delete is successful: Return 204 without content. */
11fdf7f2 10643 mg_send_http_error(conn, 204, "%s", "");
7c673cae
FG
10644 } else {
10645 /* Delete is not successful: Return 500 (Server error). */
11fdf7f2 10646 mg_send_http_error(conn, 500, "Error: Could not delete %s", path);
7c673cae
FG
10647 }
10648 return;
10649 }
10650
10651 /* This is an existing file (not a directory).
10652 * Check if write permission is granted. */
10653 if (access(path, W_OK) != 0) {
10654 /* File is read only */
11fdf7f2 10655 mg_send_http_error(
7c673cae
FG
10656 conn,
10657 403,
10658 "Error: Delete not possible\nDeleting %s is not allowed",
10659 path);
10660 return;
10661 }
10662
10663 /* Try to delete it. */
10664 if (mg_remove(conn, path) == 0) {
10665 /* Delete was successful: Return 204 without content. */
11fdf7f2 10666 mg_send_http_error(conn, 204, "%s", "");
7c673cae
FG
10667 } else {
10668 /* Delete not successful (file locked). */
11fdf7f2
TL
10669 mg_send_http_error(conn,
10670 423,
10671 "Error: Cannot delete file\nremove(%s): %s",
10672 path,
10673 strerror(ERRNO));
7c673cae
FG
10674 }
10675}
10676#endif /* !NO_FILES */
10677
10678
10679static void
11fdf7f2 10680send_ssi_file(struct mg_connection *, const char *, struct mg_file *, int);
7c673cae
FG
10681
10682
10683static void
10684do_ssi_include(struct mg_connection *conn,
10685 const char *ssi,
10686 char *tag,
10687 int include_level)
10688{
10689 char file_name[MG_BUF_LEN], path[512], *p;
11fdf7f2 10690 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
10691 size_t len;
10692 int truncated = 0;
10693
10694 if (conn == NULL) {
10695 return;
10696 }
10697
10698 /* sscanf() is safe here, since send_ssi_file() also uses buffer
10699 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
10700 * always < MG_BUF_LEN. */
10701 if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) {
10702 /* File name is relative to the webserver root */
10703 file_name[511] = 0;
10704 (void)mg_snprintf(conn,
10705 &truncated,
10706 path,
10707 sizeof(path),
10708 "%s/%s",
10709 conn->ctx->config[DOCUMENT_ROOT],
10710 file_name);
10711
10712 } else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
10713 /* File name is relative to the webserver working directory
10714 * or it is absolute system path */
10715 file_name[511] = 0;
10716 (void)
10717 mg_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name);
10718
11fdf7f2
TL
10719 } else if ((sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1)
10720 || (sscanf(tag, " \"%511[^\"]\"", file_name) == 1)) {
7c673cae
FG
10721 /* File name is relative to the currect document */
10722 file_name[511] = 0;
10723 (void)mg_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
10724
10725 if (!truncated) {
10726 if ((p = strrchr(path, '/')) != NULL) {
10727 p[1] = '\0';
10728 }
10729 len = strlen(path);
10730 (void)mg_snprintf(conn,
10731 &truncated,
10732 path + len,
10733 sizeof(path) - len,
10734 "%s",
10735 file_name);
10736 }
10737
10738 } else {
10739 mg_cry(conn, "Bad SSI #include: [%s]", tag);
10740 return;
10741 }
10742
10743 if (truncated) {
10744 mg_cry(conn, "SSI #include path length overflow: [%s]", tag);
10745 return;
10746 }
10747
11fdf7f2 10748 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, &file)) {
7c673cae
FG
10749 mg_cry(conn,
10750 "Cannot open SSI #include: [%s]: fopen(%s): %s",
10751 tag,
10752 path,
10753 strerror(ERRNO));
10754 } else {
11fdf7f2 10755 fclose_on_exec(&file.access, conn);
7c673cae
FG
10756 if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
10757 strlen(conn->ctx->config[SSI_EXTENSIONS]),
10758 path) > 0) {
10759 send_ssi_file(conn, path, &file, include_level + 1);
10760 } else {
10761 send_file_data(conn, &file, 0, INT64_MAX);
10762 }
11fdf7f2 10763 (void)mg_fclose(&file.access); /* Ignore errors for readonly files */
7c673cae
FG
10764 }
10765}
10766
10767
10768#if !defined(NO_POPEN)
10769static void
10770do_ssi_exec(struct mg_connection *conn, char *tag)
10771{
10772 char cmd[1024] = "";
11fdf7f2 10773 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae
FG
10774
10775 if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
10776 mg_cry(conn, "Bad SSI #exec: [%s]", tag);
10777 } else {
10778 cmd[1023] = 0;
11fdf7f2 10779 if ((file.access.fp = popen(cmd, "r")) == NULL) {
7c673cae
FG
10780 mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
10781 } else {
10782 send_file_data(conn, &file, 0, INT64_MAX);
11fdf7f2 10783 pclose(file.access.fp);
7c673cae
FG
10784 }
10785 }
10786}
10787#endif /* !NO_POPEN */
10788
10789
10790static int
11fdf7f2 10791mg_fgetc(struct mg_file *filep, int offset)
7c673cae
FG
10792{
10793 if (filep == NULL) {
10794 return EOF;
10795 }
11fdf7f2
TL
10796 if ((filep->access.membuf != NULL) && (offset >= 0)
10797 && (((unsigned int)(offset)) < filep->stat.size)) {
10798 return ((const unsigned char *)filep->access.membuf)[offset];
10799 } else if (filep->access.fp != NULL) {
10800 return fgetc(filep->access.fp);
7c673cae
FG
10801 } else {
10802 return EOF;
10803 }
10804}
10805
10806
10807static void
10808send_ssi_file(struct mg_connection *conn,
10809 const char *path,
11fdf7f2 10810 struct mg_file *filep,
7c673cae
FG
10811 int include_level)
10812{
10813 char buf[MG_BUF_LEN];
11fdf7f2 10814 int ch, offset, len, in_tag, in_ssi_tag;
7c673cae
FG
10815
10816 if (include_level > 10) {
10817 mg_cry(conn, "SSI #include level is too deep (%s)", path);
10818 return;
10819 }
10820
11fdf7f2
TL
10821 in_tag = in_ssi_tag = len = offset = 0;
10822
10823 /* Read file, byte by byte, and look for SSI include tags */
10824 while ((ch = mg_fgetc(filep, offset++)) != EOF) {
10825
10826 if (in_tag) {
10827 /* We are in a tag, either SSI tag or html tag */
10828
10829 if (ch == '>') {
10830 /* Tag is closing */
10831 buf[len++] = '>';
10832
10833 if (in_ssi_tag) {
10834 /* Handle SSI tag */
10835 buf[len] = 0;
10836
10837 if (!memcmp(buf + 5, "include", 7)) {
10838 do_ssi_include(conn, path, buf + 12, include_level + 1);
7c673cae 10839#if !defined(NO_POPEN)
11fdf7f2
TL
10840 } else if (!memcmp(buf + 5, "exec", 4)) {
10841 do_ssi_exec(conn, buf + 9);
7c673cae 10842#endif /* !NO_POPEN */
11fdf7f2
TL
10843 } else {
10844 mg_cry(conn,
10845 "%s: unknown SSI "
10846 "command: \"%s\"",
10847 path,
10848 buf);
10849 }
10850 len = 0;
10851 in_ssi_tag = in_tag = 0;
10852
7c673cae 10853 } else {
11fdf7f2
TL
10854 /* Not an SSI tag */
10855 /* Flush buffer */
10856 (void)mg_write(conn, buf, (size_t)len);
10857 len = 0;
10858 in_tag = 0;
10859 }
10860
10861 } else {
10862 /* Tag is still open */
10863 buf[len++] = (char)(ch & 0xff);
10864
10865 if ((len == 5) && !memcmp(buf, "<!--#", 5)) {
10866 /* All SSI tags start with <!--# */
10867 in_ssi_tag = 1;
10868 }
10869
10870 if ((len + 2) > (int)sizeof(buf)) {
10871 /* Tag to long for buffer */
10872 mg_cry(conn, "%s: tag is too large", path);
10873 return;
7c673cae
FG
10874 }
10875 }
11fdf7f2 10876
7c673cae 10877 } else {
11fdf7f2
TL
10878 /* We are not in a tag yet. */
10879
10880 if (ch == '<') {
10881 /* Tag is opening */
10882 in_tag = 1;
10883 /* Flush current buffer */
10884 (void)mg_write(conn, buf, (size_t)len);
10885 /* Store the < */
10886 len = 1;
10887 buf[0] = '<';
10888
10889 } else {
10890 /* No Tag */
10891 /* Add data to buffer */
10892 buf[len++] = (char)(ch & 0xff);
10893 /* Flush if buffer is full */
10894 if (len == (int)sizeof(buf)) {
10895 mg_write(conn, buf, (size_t)len);
10896 len = 0;
10897 }
7c673cae
FG
10898 }
10899 }
10900 }
10901
10902 /* Send the rest of buffered data */
10903 if (len > 0) {
10904 mg_write(conn, buf, (size_t)len);
10905 }
10906}
10907
10908
10909static void
10910handle_ssi_file_request(struct mg_connection *conn,
10911 const char *path,
11fdf7f2 10912 struct mg_file *filep)
7c673cae
FG
10913{
10914 char date[64];
10915 time_t curtime = time(NULL);
10916 const char *cors1, *cors2, *cors3;
10917
11fdf7f2 10918 if ((conn == NULL) || (path == NULL) || (filep == NULL)) {
7c673cae
FG
10919 return;
10920 }
10921
10922 if (mg_get_header(conn, "Origin")) {
10923 /* Cross-origin resource sharing (CORS). */
10924 cors1 = "Access-Control-Allow-Origin: ";
10925 cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
10926 cors3 = "\r\n";
10927 } else {
10928 cors1 = cors2 = cors3 = "";
10929 }
10930
11fdf7f2 10931 if (!mg_fopen(conn, path, MG_FOPEN_MODE_READ, filep)) {
7c673cae
FG
10932 /* File exists (precondition for calling this function),
10933 * but can not be opened by the server. */
11fdf7f2
TL
10934 mg_send_http_error(conn,
10935 500,
10936 "Error: Cannot read file\nfopen(%s): %s",
10937 path,
10938 strerror(ERRNO));
7c673cae
FG
10939 } else {
10940 conn->must_close = 1;
10941 gmt_time_string(date, sizeof(date), &curtime);
11fdf7f2 10942 fclose_on_exec(&filep->access, conn);
7c673cae
FG
10943 mg_printf(conn, "HTTP/1.1 200 OK\r\n");
10944 send_no_cache_header(conn);
11fdf7f2 10945 send_additional_header(conn);
7c673cae
FG
10946 mg_printf(conn,
10947 "%s%s%s"
10948 "Date: %s\r\n"
10949 "Content-Type: text/html\r\n"
10950 "Connection: %s\r\n\r\n",
10951 cors1,
10952 cors2,
10953 cors3,
10954 date,
10955 suggest_connection_header(conn));
10956 send_ssi_file(conn, path, filep, 0);
11fdf7f2 10957 (void)mg_fclose(&filep->access); /* Ignore errors for readonly files */
7c673cae
FG
10958 }
10959}
10960
10961
10962#if !defined(NO_FILES)
10963static void
10964send_options(struct mg_connection *conn)
10965{
10966 char date[64];
10967 time_t curtime = time(NULL);
10968
10969 if (!conn) {
10970 return;
10971 }
10972
10973 conn->status_code = 200;
10974 conn->must_close = 1;
10975 gmt_time_string(date, sizeof(date), &curtime);
10976
11fdf7f2
TL
10977 /* We do not set a "Cache-Control" header here, but leave the default.
10978 * Since browsers do not send an OPTIONS request, we can not test the
10979 * effect anyway. */
7c673cae
FG
10980 mg_printf(conn,
10981 "HTTP/1.1 200 OK\r\n"
10982 "Date: %s\r\n"
7c673cae
FG
10983 "Connection: %s\r\n"
10984 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
10985 "PROPFIND, MKCOL\r\n"
11fdf7f2 10986 "DAV: 1\r\n",
7c673cae
FG
10987 date,
10988 suggest_connection_header(conn));
11fdf7f2
TL
10989 send_additional_header(conn);
10990 mg_printf(conn, "\r\n");
7c673cae
FG
10991}
10992
10993
10994/* Writes PROPFIND properties for a collection element */
10995static void
11fdf7f2
TL
10996print_props(struct mg_connection *conn,
10997 const char *uri,
10998 struct mg_file_stat *filep)
7c673cae
FG
10999{
11000 char mtime[64];
11001
11fdf7f2 11002 if ((conn == NULL) || (uri == NULL) || (filep == NULL)) {
7c673cae
FG
11003 return;
11004 }
11005
11006 gmt_time_string(mtime, sizeof(mtime), &filep->last_modified);
11fdf7f2
TL
11007 mg_printf(conn,
11008 "<d:response>"
11009 "<d:href>%s</d:href>"
11010 "<d:propstat>"
11011 "<d:prop>"
11012 "<d:resourcetype>%s</d:resourcetype>"
11013 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
11014 "<d:getlastmodified>%s</d:getlastmodified>"
11015 "</d:prop>"
11016 "<d:status>HTTP/1.1 200 OK</d:status>"
11017 "</d:propstat>"
11018 "</d:response>\n",
11019 uri,
11020 filep->is_directory ? "<d:collection/>" : "",
11021 filep->size,
11022 mtime);
7c673cae
FG
11023}
11024
11025
11fdf7f2 11026static int
7c673cae
FG
11027print_dav_dir_entry(struct de *de, void *data)
11028{
11029 char href[PATH_MAX];
7c673cae
FG
11030 int truncated;
11031
11032 struct mg_connection *conn = (struct mg_connection *)data;
11033 if (!de || !conn) {
11fdf7f2 11034 return -1;
7c673cae
FG
11035 }
11036 mg_snprintf(conn,
11037 &truncated,
11038 href,
11039 sizeof(href),
11040 "%s%s",
11041 conn->request_info.local_uri,
11042 de->file_name);
11043
11044 if (!truncated) {
11fdf7f2
TL
11045 size_t href_encoded_size;
11046 char *href_encoded;
11047
11048 href_encoded_size = PATH_MAX * 3; /* worst case */
11049 href_encoded = (char *)mg_malloc(href_encoded_size);
11050 if (href_encoded == NULL) {
11051 return -1;
11052 }
11053 mg_url_encode(href, href_encoded, href_encoded_size);
7c673cae 11054 print_props(conn, href_encoded, &de->file);
11fdf7f2 11055 mg_free(href_encoded);
7c673cae 11056 }
11fdf7f2
TL
11057
11058 return 0;
7c673cae
FG
11059}
11060
11061
11062static void
11063handle_propfind(struct mg_connection *conn,
11064 const char *path,
11fdf7f2 11065 struct mg_file_stat *filep)
7c673cae
FG
11066{
11067 const char *depth = mg_get_header(conn, "Depth");
11068 char date[64];
11069 time_t curtime = time(NULL);
11070
11071 gmt_time_string(date, sizeof(date), &curtime);
11072
11073 if (!conn || !path || !filep || !conn->ctx) {
11074 return;
11075 }
11076
11077 conn->must_close = 1;
11078 conn->status_code = 207;
11079 mg_printf(conn,
11080 "HTTP/1.1 207 Multi-Status\r\n"
11081 "Date: %s\r\n",
11082 date);
11083 send_static_cache_header(conn);
11fdf7f2 11084 send_additional_header(conn);
7c673cae
FG
11085 mg_printf(conn,
11086 "Connection: %s\r\n"
11087 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
11088 suggest_connection_header(conn));
11089
11fdf7f2
TL
11090 mg_printf(conn,
11091 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
11092 "<d:multistatus xmlns:d='DAV:'>\n");
7c673cae
FG
11093
11094 /* Print properties for the requested resource itself */
11095 print_props(conn, conn->request_info.local_uri, filep);
11096
11fdf7f2
TL
11097 /* If it is a directory, print directory entries too if Depth is not 0
11098 */
7c673cae
FG
11099 if (filep && filep->is_directory
11100 && !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")
11fdf7f2 11101 && ((depth == NULL) || (strcmp(depth, "0") != 0))) {
7c673cae
FG
11102 scan_directory(conn, path, conn, &print_dav_dir_entry);
11103 }
11104
11fdf7f2 11105 mg_printf(conn, "%s\n", "</d:multistatus>");
7c673cae
FG
11106}
11107#endif
11108
11109void
11110mg_lock_connection(struct mg_connection *conn)
11111{
11112 if (conn) {
11113 (void)pthread_mutex_lock(&conn->mutex);
11114 }
11115}
11116
11117void
11118mg_unlock_connection(struct mg_connection *conn)
11119{
11120 if (conn) {
11121 (void)pthread_mutex_unlock(&conn->mutex);
11122 }
11123}
11124
11125void
11126mg_lock_context(struct mg_context *ctx)
11127{
11128 if (ctx) {
11129 (void)pthread_mutex_lock(&ctx->nonce_mutex);
11130 }
11131}
11132
11133void
11134mg_unlock_context(struct mg_context *ctx)
11135{
11136 if (ctx) {
11137 (void)pthread_mutex_unlock(&ctx->nonce_mutex);
11138 }
11139}
11140
11141#if defined(USE_TIMERS)
11fdf7f2 11142#define TIMER_API static
7c673cae
FG
11143#include "timer.inl"
11144#endif /* USE_TIMERS */
11145
11146#ifdef USE_LUA
11147#include "mod_lua.inl"
11148#endif /* USE_LUA */
11149
11150#ifdef USE_DUKTAPE
11151#include "mod_duktape.inl"
11152#endif /* USE_DUKTAPE */
11153
11154#if defined(USE_WEBSOCKET)
11155
11fdf7f2
TL
11156#if !defined(NO_SSL_DL)
11157#define SHA_API static
11158#include "sha1.inl"
11159#endif
7c673cae
FG
11160
11161static int
11162send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
11163{
11164 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
7c673cae 11165 char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
11fdf7f2 11166 SHA_CTX sha_ctx;
7c673cae
FG
11167 int truncated;
11168
11169 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
11170 mg_snprintf(conn, &truncated, buf, sizeof(buf), "%s%s", websock_key, magic);
11171 if (truncated) {
11172 conn->must_close = 1;
11173 return 0;
11174 }
11175
11fdf7f2
TL
11176 SHA1_Init(&sha_ctx);
11177 SHA1_Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
11178 SHA1_Final((unsigned char *)sha, &sha_ctx);
7c673cae
FG
11179 base64_encode((unsigned char *)sha, sizeof(sha), b64_sha);
11180 mg_printf(conn,
11181 "HTTP/1.1 101 Switching Protocols\r\n"
11182 "Upgrade: websocket\r\n"
11183 "Connection: Upgrade\r\n"
11184 "Sec-WebSocket-Accept: %s\r\n",
11185 b64_sha);
11fdf7f2
TL
11186 if (conn->request_info.acceptedWebSocketSubprotocol) {
11187 mg_printf(conn,
11188 "Sec-WebSocket-Protocol: %s\r\n\r\n",
11189 conn->request_info.acceptedWebSocketSubprotocol);
7c673cae
FG
11190 } else {
11191 mg_printf(conn, "%s", "\r\n");
11192 }
11193
11194 return 1;
11195}
11196
11197
11198static void
11199read_websocket(struct mg_connection *conn,
11200 mg_websocket_data_handler ws_data_handler,
11201 void *callback_data)
11202{
11203 /* Pointer to the beginning of the portion of the incoming websocket
11204 * message queue.
11205 * The original websocket upgrade request is never removed, so the queue
11206 * begins after it. */
11207 unsigned char *buf = (unsigned char *)conn->buf + conn->request_len;
11208 int n, error, exit_by_callback;
11209
11210 /* body_len is the length of the entire queue in bytes
11211 * len is the length of the current message
11212 * data_len is the length of the current message's data payload
11213 * header_len is the length of the current message's header */
11fdf7f2
TL
11214 size_t i, len, mask_len = 0, header_len, body_len;
11215 uint64_t data_len = 0;
7c673cae
FG
11216
11217 /* "The masking key is a 32-bit value chosen at random by the client."
11218 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
11219 */
11220 unsigned char mask[4];
11221
11222 /* data points to the place where the message is stored when passed to
11223 * the
11224 * websocket_data callback. This is either mem on the stack, or a
11225 * dynamically allocated buffer if it is too large. */
11fdf7f2 11226 unsigned char mem[4096];
7c673cae
FG
11227 unsigned char mop; /* mask flag and opcode */
11228 double timeout = -1.0;
11229
11230 if (conn->ctx->config[WEBSOCKET_TIMEOUT]) {
11231 timeout = atoi(conn->ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
11232 }
11233 if ((timeout <= 0.0) && (conn->ctx->config[REQUEST_TIMEOUT])) {
11234 timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
11235 }
11236
11fdf7f2 11237 conn->in_websocket_handling = 1;
7c673cae
FG
11238 mg_set_thread_name("wsock");
11239
11240 /* Loop continuously, reading messages from the socket, invoking the
11241 * callback, and waiting repeatedly until an error occurs. */
11fdf7f2 11242 while (!conn->ctx->stop_flag && !conn->must_close) {
7c673cae
FG
11243 header_len = 0;
11244 assert(conn->data_len >= conn->request_len);
11245 if ((body_len = (size_t)(conn->data_len - conn->request_len)) >= 2) {
11246 len = buf[1] & 127;
11fdf7f2
TL
11247 mask_len = (buf[1] & 128) ? 4 : 0;
11248 if ((len < 126) && (body_len >= mask_len)) {
11249 /* inline 7-bit length field */
7c673cae
FG
11250 data_len = len;
11251 header_len = 2 + mask_len;
11fdf7f2
TL
11252 } else if ((len == 126) && (body_len >= (4 + mask_len))) {
11253 /* 16-bit length field */
7c673cae
FG
11254 header_len = 4 + mask_len;
11255 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
11fdf7f2
TL
11256 } else if (body_len >= (10 + mask_len)) {
11257 /* 64-bit length field */
11258 uint32_t l1, l2;
11259 memcpy(&l1, &buf[2], 4); /* Use memcpy for alignment */
11260 memcpy(&l2, &buf[6], 4);
7c673cae 11261 header_len = 10 + mask_len;
11fdf7f2
TL
11262 data_len = (((uint64_t)ntohl(l1)) << 32) + ntohl(l2);
11263
11264 if (data_len > (uint64_t)0x7FFF0000ul) {
11265 /* no can do */
11266 mg_cry(conn, "websocket out of memory; closing connection");
11267 break;
11268 }
7c673cae
FG
11269 }
11270 }
11271
11fdf7f2 11272 if ((header_len > 0) && (body_len >= header_len)) {
7c673cae 11273 /* Allocate space to hold websocket payload */
11fdf7f2
TL
11274 unsigned char *data = mem;
11275
11276 if ((size_t)data_len > (size_t)sizeof(mem)) {
11277 data =
11278 (unsigned char *)mg_malloc_ctx((size_t)data_len, conn->ctx);
7c673cae
FG
11279 if (data == NULL) {
11280 /* Allocation failed, exit the loop and then close the
11281 * connection */
11282 mg_cry(conn, "websocket out of memory; closing connection");
11283 break;
11284 }
11285 }
11286
11287 /* Copy the mask before we shift the queue and destroy it */
11288 if (mask_len > 0) {
11289 memcpy(mask, buf + header_len - mask_len, sizeof(mask));
11290 } else {
11291 memset(mask, 0, sizeof(mask));
11292 }
11293
11294 /* Read frame payload from the first message in the queue into
11295 * data and advance the queue by moving the memory in place. */
11296 assert(body_len >= header_len);
11fdf7f2 11297 if (data_len + (uint64_t)header_len > (uint64_t)body_len) {
7c673cae
FG
11298 mop = buf[0]; /* current mask and opcode */
11299 /* Overflow case */
11300 len = body_len - header_len;
11301 memcpy(data, buf + header_len, len);
11302 error = 0;
11fdf7f2
TL
11303 while ((uint64_t)len < data_len) {
11304 n = pull_inner(NULL,
11305 conn,
11306 (char *)(data + len),
11307 (int)(data_len - len),
11308 timeout);
11309 if (n <= -2) {
7c673cae
FG
11310 error = 1;
11311 break;
11fdf7f2
TL
11312 } else if (n > 0) {
11313 len += (size_t)n;
11314 } else {
11315 /* Timeout: should retry */
11316 /* TODO: retry condition */
7c673cae 11317 }
7c673cae
FG
11318 }
11319 if (error) {
11320 mg_cry(conn, "Websocket pull failed; closing connection");
11fdf7f2
TL
11321 if (data != mem) {
11322 mg_free(data);
11323 }
7c673cae
FG
11324 break;
11325 }
11fdf7f2 11326
7c673cae 11327 conn->data_len = conn->request_len;
11fdf7f2 11328
7c673cae 11329 } else {
11fdf7f2 11330
7c673cae
FG
11331 mop = buf[0]; /* current mask and opcode, overwritten by
11332 * memmove() */
11fdf7f2 11333
7c673cae 11334 /* Length of the message being read at the front of the
11fdf7f2
TL
11335 * queue. Cast to 31 bit is OK, since we limited
11336 * data_len before. */
11337 len = (size_t)data_len + header_len;
7c673cae
FG
11338
11339 /* Copy the data payload into the data pointer for the
11fdf7f2
TL
11340 * callback. Cast to 31 bit is OK, since we
11341 * limited data_len */
11342 memcpy(data, buf + header_len, (size_t)data_len);
7c673cae
FG
11343
11344 /* Move the queue forward len bytes */
11345 memmove(buf, buf + len, body_len - len);
11346
11347 /* Mark the queue as advanced */
11348 conn->data_len -= (int)len;
11349 }
11350
11351 /* Apply mask if necessary */
11352 if (mask_len > 0) {
11fdf7f2 11353 for (i = 0; i < (size_t)data_len; i++) {
7c673cae
FG
11354 data[i] ^= mask[i & 3];
11355 }
11356 }
11357
11358 /* Exit the loop if callback signals to exit (server side),
11359 * or "connection close" opcode received (client side). */
11360 exit_by_callback = 0;
11361 if ((ws_data_handler != NULL)
11fdf7f2
TL
11362 && !ws_data_handler(conn,
11363 mop,
11364 (char *)data,
11365 (size_t)data_len,
11366 callback_data)) {
7c673cae
FG
11367 exit_by_callback = 1;
11368 }
11369
11370 if (data != mem) {
11371 mg_free(data);
11372 }
11373
11374 if (exit_by_callback
11375 || ((mop & 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE)) {
11376 /* Opcode == 8, connection close */
11377 break;
11378 }
11379
11380 /* Not breaking the loop, process next websocket frame. */
11381 } else {
11382 /* Read from the socket into the next available location in the
11383 * message queue. */
11fdf7f2
TL
11384 n = pull_inner(NULL,
11385 conn,
11386 conn->buf + conn->data_len,
11387 conn->buf_size - conn->data_len,
11388 timeout);
11389 if (n <= -2) {
7c673cae
FG
11390 /* Error, no bytes read */
11391 break;
11392 }
11fdf7f2
TL
11393 if (n > 0) {
11394 conn->data_len += n;
11395 } else {
11396 /* Timeout: should retry */
11397 /* TODO: get timeout def */
11398 }
7c673cae
FG
11399 }
11400 }
11401
11402 mg_set_thread_name("worker");
11fdf7f2 11403 conn->in_websocket_handling = 0;
7c673cae
FG
11404}
11405
11406
11407static int
11408mg_websocket_write_exec(struct mg_connection *conn,
11409 int opcode,
11410 const char *data,
11411 size_t dataLen,
11412 uint32_t masking_key)
11413{
11414 unsigned char header[14];
11415 size_t headerLen = 1;
11416
11417 int retval = -1;
11418
11fdf7f2
TL
11419#if defined(__GNUC__) || defined(__MINGW32__)
11420/* Disable spurious conversion warning for GCC */
11421#pragma GCC diagnostic push
11422#pragma GCC diagnostic ignored "-Wconversion"
11423#endif
11424
11425 header[0] = 0x80u | (unsigned char)((unsigned)opcode & 0xf);
11426
11427#if defined(__GNUC__) || defined(__MINGW32__)
11428#pragma GCC diagnostic pop
11429#endif
7c673cae
FG
11430
11431 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
11432 if (dataLen < 126) {
11433 /* inline 7-bit length field */
11434 header[1] = (unsigned char)dataLen;
11435 headerLen = 2;
11436 } else if (dataLen <= 0xFFFF) {
11437 /* 16-bit length field */
11fdf7f2 11438 uint16_t len = htons((uint16_t)dataLen);
7c673cae 11439 header[1] = 126;
11fdf7f2 11440 memcpy(header + 2, &len, 2);
7c673cae
FG
11441 headerLen = 4;
11442 } else {
11443 /* 64-bit length field */
11fdf7f2
TL
11444 uint32_t len1 = htonl((uint32_t)((uint64_t)dataLen >> 32));
11445 uint32_t len2 = htonl((uint32_t)(dataLen & 0xFFFFFFFFu));
7c673cae 11446 header[1] = 127;
11fdf7f2
TL
11447 memcpy(header + 2, &len1, 4);
11448 memcpy(header + 6, &len2, 4);
7c673cae
FG
11449 headerLen = 10;
11450 }
11451
11452 if (masking_key) {
11453 /* add mask */
11454 header[1] |= 0x80;
11fdf7f2 11455 memcpy(header + headerLen, &masking_key, 4);
7c673cae
FG
11456 headerLen += 4;
11457 }
11458
11459
11460 /* Note that POSIX/Winsock's send() is threadsafe
11461 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
11462 * but mongoose's mg_printf/mg_write is not (because of the loop in
11463 * push(), although that is only a problem if the packet is large or
11464 * outgoing buffer is full). */
11fdf7f2
TL
11465
11466 /* TODO: Check if this lock should be moved to user land.
11467 * Currently the server sets this lock for websockets, but
11468 * not for any other connection. It must be set for every
11469 * conn read/written by more than one thread, no matter if
11470 * it is a websocket or regular connection. */
7c673cae 11471 (void)mg_lock_connection(conn);
11fdf7f2 11472
7c673cae
FG
11473 retval = mg_write(conn, header, headerLen);
11474 if (dataLen > 0) {
11475 retval = mg_write(conn, data, dataLen);
11476 }
11fdf7f2
TL
11477
11478 /* TODO: Remove this unlock as well, when lock is moved. */
7c673cae
FG
11479 mg_unlock_connection(conn);
11480
11481 return retval;
11482}
11483
11484int
11485mg_websocket_write(struct mg_connection *conn,
11486 int opcode,
11487 const char *data,
11488 size_t dataLen)
11489{
11490 return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
11491}
11492
11493
11494static void
11495mask_data(const char *in, size_t in_len, uint32_t masking_key, char *out)
11496{
11497 size_t i = 0;
11498
11499 i = 0;
11500 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
11501 /* Convert in 32 bit words, if data is 4 byte aligned */
11502 while (i < (in_len - 3)) {
11503 *(uint32_t *)(void *)(out + i) =
11504 *(uint32_t *)(void *)(in + i) ^ masking_key;
11505 i += 4;
11506 }
11507 }
11508 if (i != in_len) {
11509 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
11510 while (i < in_len) {
11511 *(uint8_t *)(void *)(out + i) =
11512 *(uint8_t *)(void *)(in + i)
11513 ^ *(((uint8_t *)&masking_key) + (i % 4));
11514 i++;
11515 }
11516 }
11517}
11518
11519
11520int
11521mg_websocket_client_write(struct mg_connection *conn,
11522 int opcode,
11523 const char *data,
11524 size_t dataLen)
11525{
11526 int retval = -1;
11fdf7f2
TL
11527 char *masked_data =
11528 (char *)mg_malloc_ctx(((dataLen + 7) / 4) * 4, conn->ctx);
7c673cae
FG
11529 uint32_t masking_key = (uint32_t)get_random();
11530
11531 if (masked_data == NULL) {
11532 /* Return -1 in an error case */
11533 mg_cry(conn,
11534 "Cannot allocate buffer for masked websocket response: "
11535 "Out of memory");
11536 return -1;
11537 }
11538
11539 mask_data(data, dataLen, masking_key, masked_data);
11540
11541 retval = mg_websocket_write_exec(
11542 conn, opcode, masked_data, dataLen, masking_key);
11543 mg_free(masked_data);
11544
11545 return retval;
11546}
11547
11548
11549static void
11550handle_websocket_request(struct mg_connection *conn,
11551 const char *path,
11552 int is_callback_resource,
11fdf7f2 11553 struct mg_websocket_subprotocols *subprotocols,
7c673cae
FG
11554 mg_websocket_connect_handler ws_connect_handler,
11555 mg_websocket_ready_handler ws_ready_handler,
11556 mg_websocket_data_handler ws_data_handler,
11557 mg_websocket_close_handler ws_close_handler,
11558 void *cbData)
11559{
11560 const char *websock_key = mg_get_header(conn, "Sec-WebSocket-Key");
11561 const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
11562 int lua_websock = 0;
11563
11564#if !defined(USE_LUA)
11565 (void)path;
11566#endif
11567
11568 /* Step 1: Check websocket protocol version. */
11569 /* Step 1.1: Check Sec-WebSocket-Key. */
11570 if (!websock_key) {
11571 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
11572 * requires a Sec-WebSocket-Key header.
11573 */
11574 /* It could be the hixie draft version
11575 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
11576 */
11577 const char *key1 = mg_get_header(conn, "Sec-WebSocket-Key1");
11578 const char *key2 = mg_get_header(conn, "Sec-WebSocket-Key2");
11579 char key3[8];
11580
11581 if ((key1 != NULL) && (key2 != NULL)) {
11582 /* This version uses 8 byte body data in a GET request */
11583 conn->content_len = 8;
11584 if (8 == mg_read(conn, key3, 8)) {
11585 /* This is the hixie version */
11fdf7f2
TL
11586 mg_send_http_error(conn,
11587 426,
11588 "%s",
11589 "Protocol upgrade to RFC 6455 required");
7c673cae
FG
11590 return;
11591 }
11592 }
11593 /* This is an unknown version */
11fdf7f2 11594 mg_send_http_error(conn, 400, "%s", "Malformed websocket request");
7c673cae
FG
11595 return;
11596 }
11597
11598 /* Step 1.2: Check websocket protocol version. */
11599 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
11fdf7f2 11600 if ((version == NULL) || (strcmp(version, "13") != 0)) {
7c673cae 11601 /* Reject wrong versions */
11fdf7f2 11602 mg_send_http_error(conn, 426, "%s", "Protocol upgrade required");
7c673cae
FG
11603 return;
11604 }
11605
11606 /* Step 1.3: Could check for "Host", but we do not really nead this
11607 * value for anything, so just ignore it. */
11608
11609 /* Step 2: If a callback is responsible, call it. */
11610 if (is_callback_resource) {
11fdf7f2
TL
11611 /* Step 2.1 check and select subprotocol */
11612 const char *protocols[64]; // max 64 headers
11613 int nbSubprotocolHeader = get_req_headers(&conn->request_info,
11614 "Sec-WebSocket-Protocol",
11615 protocols,
11616 64);
11617 if ((nbSubprotocolHeader > 0) && subprotocols) {
11618 int cnt = 0;
11619 int idx;
11620 unsigned long len;
11621 const char *sep, *curSubProtocol,
11622 *acceptedWebSocketSubprotocol = NULL;
11623
11624
11625 /* look for matching subprotocol */
11626 do {
11627 const char *protocol = protocols[cnt];
11628
11629 do {
11630 sep = strchr(protocol, ',');
11631 curSubProtocol = protocol;
11632 len = sep ? (unsigned long)(sep - protocol)
11633 : (unsigned long)strlen(protocol);
11634 while (sep && isspace(*++sep))
11635 ; // ignore leading whitespaces
11636 protocol = sep;
11637
11638
11639 for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
11640 if ((strlen(subprotocols->subprotocols[idx]) == len)
11641 && (strncmp(curSubProtocol,
11642 subprotocols->subprotocols[idx],
11643 len) == 0)) {
11644 acceptedWebSocketSubprotocol =
11645 subprotocols->subprotocols[idx];
11646 break;
11647 }
11648 }
11649 } while (sep && !acceptedWebSocketSubprotocol);
11650 } while (++cnt < nbSubprotocolHeader
11651 && !acceptedWebSocketSubprotocol);
11652
11653 conn->request_info.acceptedWebSocketSubprotocol =
11654 acceptedWebSocketSubprotocol;
11655 } else if (nbSubprotocolHeader > 0) {
11656 /* keep legacy behavior */
11657 const char *protocol = protocols[0];
11658
11659 /* The protocol is a comma separated list of names. */
11660 /* The server must only return one value from this list. */
11661 /* First check if it is a list or just a single value. */
11662 const char *sep = strrchr(protocol, ',');
11663 if (sep == NULL) {
11664 /* Just a single protocol -> accept it. */
11665 conn->request_info.acceptedWebSocketSubprotocol = protocol;
11666 } else {
11667 /* Multiple protocols -> accept the last one. */
11668 /* This is just a quick fix if the client offers multiple
11669 * protocols. The handler should have a list of accepted
11670 * protocols on his own
11671 * and use it to select one protocol among those the client
11672 * has
11673 * offered.
11674 */
11675 while (isspace(*++sep)) {
11676 ; /* ignore leading whitespaces */
11677 }
11678 conn->request_info.acceptedWebSocketSubprotocol = sep;
11679 }
11680 }
11681
11682 if ((ws_connect_handler != NULL)
11683 && (ws_connect_handler(conn, cbData) != 0)) {
7c673cae
FG
11684 /* C callback has returned non-zero, do not proceed with
11685 * handshake.
11686 */
11687 /* Note that C callbacks are no longer called when Lua is
11688 * responsible, so C can no longer filter callbacks for Lua. */
11689 return;
11690 }
11691 }
11692#if defined(USE_LUA)
11693 /* Step 3: No callback. Check if Lua is responsible. */
11694 else {
11695 /* Step 3.1: Check if Lua is responsible. */
11696 if (conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
11697 lua_websock =
11698 match_prefix(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS],
11699 strlen(
11700 conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
11701 path);
11702 }
11703
11704 if (lua_websock) {
11705 /* Step 3.2: Lua is responsible: call it. */
11706 conn->lua_websocket_state = lua_websocket_new(path, conn);
11707 if (!conn->lua_websocket_state) {
11708 /* Lua rejected the new client */
11709 return;
11710 }
11711 }
11712 }
11713#endif
11714
11715 /* Step 4: Check if there is a responsible websocket handler. */
11716 if (!is_callback_resource && !lua_websock) {
11fdf7f2
TL
11717 /* There is no callback, and Lua is not responsible either. */
11718 /* Reply with a 404 Not Found. We are still at a standard
11719 * HTTP request here, before the websocket handshake, so
11720 * we can still send standard HTTP error replies. */
11721 mg_send_http_error(conn, 404, "%s", "Not found");
7c673cae
FG
11722 return;
11723 }
11724
11725 /* Step 5: The websocket connection has been accepted */
11726 if (!send_websocket_handshake(conn, websock_key)) {
11fdf7f2 11727 mg_send_http_error(conn, 500, "%s", "Websocket handshake failed");
7c673cae
FG
11728 return;
11729 }
11730
11731 /* Step 6: Call the ready handler */
11732 if (is_callback_resource) {
11733 if (ws_ready_handler != NULL) {
11734 ws_ready_handler(conn, cbData);
11735 }
11736#if defined(USE_LUA)
11737 } else if (lua_websock) {
11738 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
11739 /* the ready handler returned false */
11740 return;
11741 }
11742#endif
11743 }
11744
11745 /* Step 7: Enter the read loop */
11746 if (is_callback_resource) {
11747 read_websocket(conn, ws_data_handler, cbData);
11748#if defined(USE_LUA)
11749 } else if (lua_websock) {
11750 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
11751#endif
11752 }
11753
11754 /* Step 8: Call the close handler */
11755 if (ws_close_handler) {
11756 ws_close_handler(conn, cbData);
11757 }
11758}
11759
11760
11761static int
11762is_websocket_protocol(const struct mg_connection *conn)
11763{
11764 const char *upgrade, *connection;
11765
11766 /* A websocket protocoll has the following HTTP headers:
11767 *
11768 * Connection: Upgrade
11769 * Upgrade: Websocket
11770 */
11771
11772 upgrade = mg_get_header(conn, "Upgrade");
11773 if (upgrade == NULL) {
11774 return 0; /* fail early, don't waste time checking other header
11775 * fields
11776 */
11777 }
11778 if (!mg_strcasestr(upgrade, "websocket")) {
11779 return 0;
11780 }
11781
11782 connection = mg_get_header(conn, "Connection");
11783 if (connection == NULL) {
11784 return 0;
11785 }
11786 if (!mg_strcasestr(connection, "upgrade")) {
11787 return 0;
11788 }
11789
11790 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
11791 * "Sec-WebSocket-Version" are also required.
11792 * Don't check them here, since even an unsupported websocket protocol
11793 * request still IS a websocket request (in contrast to a standard HTTP
11794 * request). It will fail later in handle_websocket_request.
11795 */
11796
11797 return 1;
11798}
11799#endif /* !USE_WEBSOCKET */
11800
11801
11802static int
11803isbyte(int n)
11804{
11fdf7f2 11805 return (n >= 0) && (n <= 255);
7c673cae
FG
11806}
11807
11808
11809static int
11810parse_net(const char *spec, uint32_t *net, uint32_t *mask)
11811{
11812 int n, a, b, c, d, slash = 32, len = 0;
11813
11fdf7f2
TL
11814 if (((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5)
11815 || (sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4))
11816 && isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) && (slash >= 0)
11817 && (slash < 33)) {
7c673cae
FG
11818 len = n;
11819 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
11820 | (uint32_t)d;
11fdf7f2 11821 *mask = slash ? (0xffffffffU << (32 - slash)) : 0;
7c673cae
FG
11822 }
11823
11824 return len;
11825}
11826
11827
11828static int
11829set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
11830{
11831 int throttle = 0;
11832 struct vec vec, val;
11833 uint32_t net, mask;
11834 char mult;
11835 double v;
11836
11837 while ((spec = next_option(spec, &vec, &val)) != NULL) {
11838 mult = ',';
11fdf7f2
TL
11839 if ((val.ptr == NULL) || (sscanf(val.ptr, "%lf%c", &v, &mult) < 1)
11840 || (v < 0) || ((lowercase(&mult) != 'k')
11841 && (lowercase(&mult) != 'm') && (mult != ','))) {
7c673cae
FG
11842 continue;
11843 }
11fdf7f2
TL
11844 v *= (lowercase(&mult) == 'k')
11845 ? 1024
11846 : ((lowercase(&mult) == 'm') ? 1048576 : 1);
7c673cae
FG
11847 if (vec.len == 1 && vec.ptr[0] == '*') {
11848 throttle = (int)v;
11849 } else if (parse_net(vec.ptr, &net, &mask) > 0) {
11850 if ((remote_ip & mask) == net) {
11851 throttle = (int)v;
11852 }
11853 } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
11854 throttle = (int)v;
11855 }
11856 }
11857
11858 return throttle;
11859}
11860
11861
11862static uint32_t
11863get_remote_ip(const struct mg_connection *conn)
11864{
11865 if (!conn) {
11866 return 0;
11867 }
11868 return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr);
11869}
11870
11871
11872/* The mg_upload function is superseeded by mg_handle_form_request. */
11873#include "handle_form.inl"
11874
11875
11876#if defined(MG_LEGACY_INTERFACE)
11877/* Implement the deprecated mg_upload function by calling the new
11878 * mg_handle_form_request function. While mg_upload could only handle
11879 * HTML forms sent as POST request in multipart/form-data format
11880 * containing only file input elements, mg_handle_form_request can
11881 * handle all form input elements and all standard request methods. */
11882struct mg_upload_user_data {
11883 struct mg_connection *conn;
11884 const char *destination_dir;
11885 int num_uploaded_files;
11886};
11887
11888
11889/* Helper function for deprecated mg_upload. */
11890static int
11891mg_upload_field_found(const char *key,
11892 const char *filename,
11893 char *path,
11894 size_t pathlen,
11895 void *user_data)
11896{
11897 int truncated = 0;
11898 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
11899 (void)key;
11900
11901 if (!filename) {
11902 mg_cry(fud->conn, "%s: No filename set", __func__);
11903 return FORM_FIELD_STORAGE_ABORT;
11904 }
11905 mg_snprintf(fud->conn,
11906 &truncated,
11907 path,
11908 pathlen - 1,
11909 "%s/%s",
11910 fud->destination_dir,
11911 filename);
11912 if (!truncated) {
11913 mg_cry(fud->conn, "%s: File path too long", __func__);
11914 return FORM_FIELD_STORAGE_ABORT;
11915 }
11916 return FORM_FIELD_STORAGE_STORE;
11917}
11918
11919
11920/* Helper function for deprecated mg_upload. */
11921static int
11922mg_upload_field_get(const char *key,
11923 const char *value,
11924 size_t value_size,
11925 void *user_data)
11926{
11927 /* Function should never be called */
11928 (void)key;
11929 (void)value;
11930 (void)value_size;
11931 (void)user_data;
11932
11933 return 0;
11934}
11935
11936
11937/* Helper function for deprecated mg_upload. */
11938static int
11939mg_upload_field_stored(const char *path, long long file_size, void *user_data)
11940{
11941 struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
11942 (void)file_size;
11943
11944 fud->num_uploaded_files++;
11945 fud->conn->ctx->callbacks.upload(fud->conn, path);
11946
11947 return 0;
11948}
11949
11950
11951/* Deprecated function mg_upload - use mg_handle_form_request instead. */
11952int
11953mg_upload(struct mg_connection *conn, const char *destination_dir)
11954{
11955 struct mg_upload_user_data fud = {conn, destination_dir, 0};
11956 struct mg_form_data_handler fdh = {mg_upload_field_found,
11957 mg_upload_field_get,
11958 mg_upload_field_stored,
11959 0};
11960 int ret;
11961
11962 fdh.user_data = (void *)&fud;
11963 ret = mg_handle_form_request(conn, &fdh);
11964
11965 if (ret < 0) {
11966 mg_cry(conn, "%s: Error while parsing the request", __func__);
11967 }
11968
11969 return fud.num_uploaded_files;
11970}
11971#endif
11972
11973
11974static int
11975get_first_ssl_listener_index(const struct mg_context *ctx)
11976{
11977 unsigned int i;
11978 int idx = -1;
11979 if (ctx) {
11fdf7f2 11980 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
7c673cae
FG
11981 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
11982 }
11983 }
11984 return idx;
11985}
11986
11987
11988static void
11989redirect_to_https_port(struct mg_connection *conn, int ssl_index)
11990{
11991 char host[1025];
11992 const char *host_header;
11993 size_t hostlen;
11994
11995 host_header = mg_get_header(conn, "Host");
11996 hostlen = sizeof(host);
11997 if (host_header != NULL) {
11998 char *pos;
11999
12000 mg_strlcpy(host, host_header, hostlen);
12001 host[hostlen - 1] = '\0';
12002 pos = strchr(host, ':');
12003 if (pos != NULL) {
12004 *pos = '\0';
12005 }
12006 } else {
12007 /* Cannot get host from the Host: header.
12008 * Fallback to our IP address. */
12009 if (conn) {
12010 sockaddr_to_string(host, hostlen, &conn->client.lsa);
12011 }
12012 }
12013
12014 /* Send host, port, uri and (if it exists) ?query_string */
12015 if (conn) {
12016 mg_printf(conn,
12017 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
12018 host,
11fdf7f2
TL
12019#if defined(USE_IPV6)
12020 (conn->ctx->listening_sockets[ssl_index].lsa.sa.sa_family
12021 == AF_INET6)
12022 ? (int)ntohs(conn->ctx->listening_sockets[ssl_index]
12023 .lsa.sin6.sin6_port)
12024 :
12025#endif
12026 (int)ntohs(conn->ctx->listening_sockets[ssl_index]
12027 .lsa.sin.sin_port),
7c673cae
FG
12028 conn->request_info.local_uri,
12029 (conn->request_info.query_string == NULL) ? "" : "?",
12030 (conn->request_info.query_string == NULL)
12031 ? ""
12032 : conn->request_info.query_string);
12033 }
12034}
12035
12036
12037static void
12038mg_set_handler_type(struct mg_context *ctx,
12039 const char *uri,
12040 int handler_type,
12041 int is_delete_request,
12042 mg_request_handler handler,
11fdf7f2 12043 struct mg_websocket_subprotocols *subprotocols,
7c673cae
FG
12044 mg_websocket_connect_handler connect_handler,
12045 mg_websocket_ready_handler ready_handler,
12046 mg_websocket_data_handler data_handler,
12047 mg_websocket_close_handler close_handler,
12048 mg_authorization_handler auth_handler,
12049 void *cbdata)
12050{
12051 struct mg_handler_info *tmp_rh, **lastref;
12052 size_t urilen = strlen(uri);
12053
12054 if (handler_type == WEBSOCKET_HANDLER) {
12055 /* assert(handler == NULL); */
12056 /* assert(is_delete_request || connect_handler!=NULL ||
12057 * ready_handler!=NULL || data_handler!=NULL ||
12058 * close_handler!=NULL);
12059 */
12060 /* assert(auth_handler == NULL); */
12061 if (handler != NULL) {
12062 return;
12063 }
11fdf7f2
TL
12064 if (!is_delete_request && (connect_handler == NULL)
12065 && (ready_handler == NULL) && (data_handler == NULL)
12066 && (close_handler == NULL)) {
7c673cae
FG
12067 return;
12068 }
12069 if (auth_handler != NULL) {
12070 return;
12071 }
12072 } else if (handler_type == REQUEST_HANDLER) {
12073 /* assert(connect_handler==NULL && ready_handler==NULL &&
12074 * data_handler==NULL && close_handler==NULL); */
12075 /* assert(is_delete_request || (handler!=NULL));
12076 */
12077 /* assert(auth_handler == NULL); */
11fdf7f2
TL
12078 if ((connect_handler != NULL) || (ready_handler != NULL)
12079 || (data_handler != NULL) || (close_handler != NULL)) {
7c673cae
FG
12080 return;
12081 }
12082 if (!is_delete_request && (handler == NULL)) {
12083 return;
12084 }
12085 if (auth_handler != NULL) {
12086 return;
12087 }
12088 } else { /* AUTH_HANDLER */
12089 /* assert(handler == NULL); */
12090 /* assert(connect_handler==NULL && ready_handler==NULL &&
12091 * data_handler==NULL && close_handler==NULL); */
12092 /* assert(auth_handler != NULL); */
12093 if (handler != NULL) {
12094 return;
12095 }
11fdf7f2
TL
12096 if ((connect_handler != NULL) || (ready_handler != NULL)
12097 || (data_handler != NULL) || (close_handler != NULL)) {
7c673cae
FG
12098 return;
12099 }
12100 if (!is_delete_request && (auth_handler == NULL)) {
12101 return;
12102 }
12103 }
12104
12105 if (!ctx) {
12106 return;
12107 }
12108
12109 mg_lock_context(ctx);
12110
12111 /* first try to find an existing handler */
12112 lastref = &(ctx->handlers);
12113 for (tmp_rh = ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
12114 if (tmp_rh->handler_type == handler_type) {
11fdf7f2 12115 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
7c673cae
FG
12116 if (!is_delete_request) {
12117 /* update existing handler */
12118 if (handler_type == REQUEST_HANDLER) {
12119 tmp_rh->handler = handler;
12120 } else if (handler_type == WEBSOCKET_HANDLER) {
11fdf7f2 12121 tmp_rh->subprotocols = subprotocols;
7c673cae
FG
12122 tmp_rh->connect_handler = connect_handler;
12123 tmp_rh->ready_handler = ready_handler;
12124 tmp_rh->data_handler = data_handler;
12125 tmp_rh->close_handler = close_handler;
12126 } else { /* AUTH_HANDLER */
12127 tmp_rh->auth_handler = auth_handler;
12128 }
12129 tmp_rh->cbdata = cbdata;
12130 } else {
12131 /* remove existing handler */
12132 *lastref = tmp_rh->next;
12133 mg_free(tmp_rh->uri);
12134 mg_free(tmp_rh);
12135 }
12136 mg_unlock_context(ctx);
12137 return;
12138 }
12139 }
12140 lastref = &(tmp_rh->next);
12141 }
12142
12143 if (is_delete_request) {
12144 /* no handler to set, this was a remove request to a non-existing
12145 * handler */
12146 mg_unlock_context(ctx);
12147 return;
12148 }
12149
12150 tmp_rh =
11fdf7f2
TL
12151 (struct mg_handler_info *)mg_calloc_ctx(sizeof(struct mg_handler_info),
12152 1,
12153 ctx);
7c673cae
FG
12154 if (tmp_rh == NULL) {
12155 mg_unlock_context(ctx);
12156 mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
12157 return;
12158 }
12159 tmp_rh->uri = mg_strdup(uri);
12160 if (!tmp_rh->uri) {
12161 mg_unlock_context(ctx);
12162 mg_free(tmp_rh);
12163 mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
12164 return;
12165 }
12166 tmp_rh->uri_len = urilen;
12167 if (handler_type == REQUEST_HANDLER) {
12168 tmp_rh->handler = handler;
12169 } else if (handler_type == WEBSOCKET_HANDLER) {
11fdf7f2 12170 tmp_rh->subprotocols = subprotocols;
7c673cae
FG
12171 tmp_rh->connect_handler = connect_handler;
12172 tmp_rh->ready_handler = ready_handler;
12173 tmp_rh->data_handler = data_handler;
12174 tmp_rh->close_handler = close_handler;
12175 } else { /* AUTH_HANDLER */
12176 tmp_rh->auth_handler = auth_handler;
12177 }
12178 tmp_rh->cbdata = cbdata;
12179 tmp_rh->handler_type = handler_type;
12180 tmp_rh->next = NULL;
12181
12182 *lastref = tmp_rh;
12183 mg_unlock_context(ctx);
12184}
12185
12186
12187void
12188mg_set_request_handler(struct mg_context *ctx,
12189 const char *uri,
12190 mg_request_handler handler,
12191 void *cbdata)
12192{
12193 mg_set_handler_type(ctx,
12194 uri,
12195 REQUEST_HANDLER,
12196 handler == NULL,
12197 handler,
12198 NULL,
12199 NULL,
12200 NULL,
12201 NULL,
12202 NULL,
11fdf7f2 12203 NULL,
7c673cae
FG
12204 cbdata);
12205}
12206
12207
12208void
12209mg_set_websocket_handler(struct mg_context *ctx,
12210 const char *uri,
12211 mg_websocket_connect_handler connect_handler,
12212 mg_websocket_ready_handler ready_handler,
12213 mg_websocket_data_handler data_handler,
12214 mg_websocket_close_handler close_handler,
12215 void *cbdata)
11fdf7f2
TL
12216{
12217 mg_set_websocket_handler_with_subprotocols(ctx,
12218 uri,
12219 NULL,
12220 connect_handler,
12221 ready_handler,
12222 data_handler,
12223 close_handler,
12224 cbdata);
12225}
12226
12227
12228void
12229mg_set_websocket_handler_with_subprotocols(
12230 struct mg_context *ctx,
12231 const char *uri,
12232 struct mg_websocket_subprotocols *subprotocols,
12233 mg_websocket_connect_handler connect_handler,
12234 mg_websocket_ready_handler ready_handler,
12235 mg_websocket_data_handler data_handler,
12236 mg_websocket_close_handler close_handler,
12237 void *cbdata)
7c673cae
FG
12238{
12239 int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
12240 && (data_handler == NULL)
12241 && (close_handler == NULL);
12242 mg_set_handler_type(ctx,
12243 uri,
12244 WEBSOCKET_HANDLER,
12245 is_delete_request,
12246 NULL,
11fdf7f2 12247 subprotocols,
7c673cae
FG
12248 connect_handler,
12249 ready_handler,
12250 data_handler,
12251 close_handler,
12252 NULL,
12253 cbdata);
12254}
12255
12256
12257void
12258mg_set_auth_handler(struct mg_context *ctx,
12259 const char *uri,
12260 mg_request_handler handler,
12261 void *cbdata)
12262{
12263 mg_set_handler_type(ctx,
12264 uri,
12265 AUTH_HANDLER,
12266 handler == NULL,
12267 NULL,
12268 NULL,
12269 NULL,
12270 NULL,
12271 NULL,
11fdf7f2 12272 NULL,
7c673cae
FG
12273 handler,
12274 cbdata);
12275}
12276
12277
12278static int
12279get_request_handler(struct mg_connection *conn,
12280 int handler_type,
12281 mg_request_handler *handler,
11fdf7f2 12282 struct mg_websocket_subprotocols **subprotocols,
7c673cae
FG
12283 mg_websocket_connect_handler *connect_handler,
12284 mg_websocket_ready_handler *ready_handler,
12285 mg_websocket_data_handler *data_handler,
12286 mg_websocket_close_handler *close_handler,
12287 mg_authorization_handler *auth_handler,
12288 void **cbdata)
12289{
12290 const struct mg_request_info *request_info = mg_get_request_info(conn);
12291 if (request_info) {
12292 const char *uri = request_info->local_uri;
12293 size_t urilen = strlen(uri);
12294 struct mg_handler_info *tmp_rh;
12295
12296 if (!conn || !conn->ctx) {
12297 return 0;
12298 }
12299
12300 mg_lock_context(conn->ctx);
12301
12302 /* first try for an exact match */
12303 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
12304 tmp_rh = tmp_rh->next) {
12305 if (tmp_rh->handler_type == handler_type) {
11fdf7f2 12306 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
7c673cae 12307 if (handler_type == WEBSOCKET_HANDLER) {
11fdf7f2 12308 *subprotocols = tmp_rh->subprotocols;
7c673cae
FG
12309 *connect_handler = tmp_rh->connect_handler;
12310 *ready_handler = tmp_rh->ready_handler;
12311 *data_handler = tmp_rh->data_handler;
12312 *close_handler = tmp_rh->close_handler;
12313 } else if (handler_type == REQUEST_HANDLER) {
12314 *handler = tmp_rh->handler;
12315 } else { /* AUTH_HANDLER */
12316 *auth_handler = tmp_rh->auth_handler;
12317 }
12318 *cbdata = tmp_rh->cbdata;
12319 mg_unlock_context(conn->ctx);
12320 return 1;
12321 }
12322 }
12323 }
12324
12325 /* next try for a partial match, we will accept uri/something */
12326 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
12327 tmp_rh = tmp_rh->next) {
12328 if (tmp_rh->handler_type == handler_type) {
11fdf7f2
TL
12329 if ((tmp_rh->uri_len < urilen) && (uri[tmp_rh->uri_len] == '/')
12330 && (memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0)) {
7c673cae 12331 if (handler_type == WEBSOCKET_HANDLER) {
11fdf7f2 12332 *subprotocols = tmp_rh->subprotocols;
7c673cae
FG
12333 *connect_handler = tmp_rh->connect_handler;
12334 *ready_handler = tmp_rh->ready_handler;
12335 *data_handler = tmp_rh->data_handler;
12336 *close_handler = tmp_rh->close_handler;
12337 } else if (handler_type == REQUEST_HANDLER) {
12338 *handler = tmp_rh->handler;
12339 } else { /* AUTH_HANDLER */
12340 *auth_handler = tmp_rh->auth_handler;
12341 }
12342 *cbdata = tmp_rh->cbdata;
12343 mg_unlock_context(conn->ctx);
12344 return 1;
12345 }
12346 }
12347 }
12348
12349 /* finally try for pattern match */
12350 for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
12351 tmp_rh = tmp_rh->next) {
12352 if (tmp_rh->handler_type == handler_type) {
12353 if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
12354 if (handler_type == WEBSOCKET_HANDLER) {
11fdf7f2 12355 *subprotocols = tmp_rh->subprotocols;
7c673cae
FG
12356 *connect_handler = tmp_rh->connect_handler;
12357 *ready_handler = tmp_rh->ready_handler;
12358 *data_handler = tmp_rh->data_handler;
12359 *close_handler = tmp_rh->close_handler;
12360 } else if (handler_type == REQUEST_HANDLER) {
12361 *handler = tmp_rh->handler;
12362 } else { /* AUTH_HANDLER */
12363 *auth_handler = tmp_rh->auth_handler;
12364 }
12365 *cbdata = tmp_rh->cbdata;
12366 mg_unlock_context(conn->ctx);
12367 return 1;
12368 }
12369 }
12370 }
12371
12372 mg_unlock_context(conn->ctx);
12373 }
12374 return 0; /* none found */
12375}
12376
12377
11fdf7f2
TL
12378/* Check if the script file is in a path, allowed for script files.
12379 * This can be used if uploading files is possible not only for the server
12380 * admin, and the upload mechanism does not check the file extension.
12381 */
12382static int
12383is_in_script_path(const struct mg_connection *conn, const char *path)
12384{
12385 /* TODO (Feature): Add config value for allowed script path.
12386 * Default: All allowed. */
12387 (void)conn;
12388 (void)path;
12389 return 1;
12390}
12391
12392
7c673cae
FG
12393#if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
12394static int
12395deprecated_websocket_connect_wrapper(const struct mg_connection *conn,
12396 void *cbdata)
12397{
12398 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
12399 if (pcallbacks->websocket_connect) {
12400 return pcallbacks->websocket_connect(conn);
12401 }
12402 /* No handler set - assume "OK" */
12403 return 0;
12404}
12405
12406
12407static void
12408deprecated_websocket_ready_wrapper(struct mg_connection *conn, void *cbdata)
12409{
12410 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
12411 if (pcallbacks->websocket_ready) {
12412 pcallbacks->websocket_ready(conn);
12413 }
12414}
12415
12416
12417static int
12418deprecated_websocket_data_wrapper(struct mg_connection *conn,
12419 int bits,
12420 char *data,
12421 size_t len,
12422 void *cbdata)
12423{
12424 struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
12425 if (pcallbacks->websocket_data) {
12426 return pcallbacks->websocket_data(conn, bits, data, len);
12427 }
12428 /* No handler set - assume "OK" */
12429 return 1;
12430}
12431#endif
12432
12433
12434/* This is the heart of the Civetweb's logic.
12435 * This function is called when the request is read, parsed and validated,
12436 * and Civetweb must decide what action to take: serve a file, or
12437 * a directory, or call embedded function, etcetera. */
12438static void
12439handle_request(struct mg_connection *conn)
12440{
11fdf7f2
TL
12441 struct mg_request_info *ri = &conn->request_info;
12442 char path[PATH_MAX];
12443 int uri_len, ssl_index;
12444 int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
12445 is_put_or_delete_request = 0, is_callback_resource = 0;
12446 int i;
12447 struct mg_file file = STRUCT_FILE_INITIALIZER;
12448 mg_request_handler callback_handler = NULL;
12449 struct mg_websocket_subprotocols *subprotocols;
12450 mg_websocket_connect_handler ws_connect_handler = NULL;
12451 mg_websocket_ready_handler ws_ready_handler = NULL;
12452 mg_websocket_data_handler ws_data_handler = NULL;
12453 mg_websocket_close_handler ws_close_handler = NULL;
12454 void *callback_data = NULL;
12455 mg_authorization_handler auth_handler = NULL;
12456 void *auth_callback_data = NULL;
12457 int handler_type;
12458 time_t curtime = time(NULL);
12459 char date[64];
7c673cae 12460
11fdf7f2 12461 path[0] = 0;
7c673cae 12462
11fdf7f2
TL
12463 /* 1. get the request url */
12464 /* 1.1. split into url and query string */
12465 if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
12466 != NULL) {
12467 *((char *)conn->request_info.query_string++) = '\0';
12468 }
7c673cae 12469
11fdf7f2
TL
12470 /* 1.2. do a https redirect, if required. Do not decode URIs yet. */
12471 if (!conn->client.is_ssl && conn->client.ssl_redir) {
12472 ssl_index = get_first_ssl_listener_index(conn->ctx);
12473 if (ssl_index >= 0) {
12474 redirect_to_https_port(conn, ssl_index);
12475 } else {
12476 /* A http to https forward port has been specified,
12477 * but no https port to forward to. */
12478 mg_send_http_error(conn,
12479 503,
12480 "%s",
12481 "Error: SSL forward not configured properly");
12482 mg_cry(conn, "Can not redirect to SSL, no SSL port available");
7c673cae 12483 }
11fdf7f2
TL
12484 return;
12485 }
12486 uri_len = (int)strlen(ri->local_uri);
7c673cae 12487
11fdf7f2
TL
12488 /* 1.3. decode url (if config says so) */
12489 if (should_decode_url(conn)) {
12490 mg_url_decode(
12491 ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
12492 }
7c673cae 12493
11fdf7f2
TL
12494 /* 1.4. clean URIs, so a path like allowed_dir/../forbidden_file is
12495 * not possible */
12496 if (!mg_strcasecmp(conn->ctx->config[CANONICALIZE_URL_PATH], "yes")) {
12497 remove_double_dots_and_double_slashes((char *)ri->local_uri);
12498 }
7c673cae 12499
11fdf7f2
TL
12500 /* step 1. completed, the url is known now */
12501 uri_len = (int)strlen(ri->local_uri);
12502 DEBUG_TRACE("URL: %s", ri->local_uri);
7c673cae 12503
11fdf7f2
TL
12504 /* 2. if this ip has limited speed, set it for this connection */
12505 conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
12506 get_remote_ip(conn),
12507 ri->local_uri);
12508
12509 /* 3. call a "handle everything" callback, if registered */
12510 if (conn->ctx->callbacks.begin_request != NULL) {
12511 /* Note that since V1.7 the "begin_request" function is called
12512 * before an authorization check. If an authorization check is
12513 * required, use a request_handler instead. */
12514 i = conn->ctx->callbacks.begin_request(conn);
12515 if (i > 0) {
12516 /* callback already processed the request. Store the
12517 return value as a status code for the access log. */
12518 conn->status_code = i;
12519 discard_unread_request_data(conn);
12520 return;
12521 } else if (i == 0) {
12522 /* civetweb should process the request */
12523 } else {
12524 /* unspecified - may change with the next version */
7c673cae
FG
12525 return;
12526 }
11fdf7f2 12527 }
7c673cae 12528
11fdf7f2
TL
12529 /* request not yet handled by a handler or redirect, so the request
12530 * is processed here */
7c673cae 12531
11fdf7f2
TL
12532 /* 4. Check for CORS preflight requests and handle them (if configured).
12533 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
12534 */
12535 if (!strcmp(ri->request_method, "OPTIONS")) {
12536 /* Send a response to CORS preflights only if
12537 * access_control_allow_methods is not NULL and not an empty string.
12538 * In this case, scripts can still handle CORS. */
12539 const char *cors_meth_cfg =
12540 conn->ctx->config[ACCESS_CONTROL_ALLOW_METHODS];
12541 const char *cors_orig_cfg =
12542 conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
12543 const char *cors_origin =
12544 get_header(ri->http_headers, ri->num_headers, "Origin");
12545 const char *cors_acrm = get_header(ri->http_headers,
12546 ri->num_headers,
12547 "Access-Control-Request-Method");
12548
12549 /* Todo: check if cors_origin is in cors_orig_cfg.
12550 * Or, let the client check this. */
12551
12552 if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
12553 && (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
12554 && (cors_origin != NULL) && (cors_acrm != NULL)) {
12555 /* This is a valid CORS preflight, and the server is configured
12556 * to
12557 * handle it automatically. */
12558 const char *cors_acrh =
12559 get_header(ri->http_headers,
12560 ri->num_headers,
12561 "Access-Control-Request-Headers");
7c673cae 12562
11fdf7f2
TL
12563 gmt_time_string(date, sizeof(date), &curtime);
12564 mg_printf(conn,
12565 "HTTP/1.1 200 OK\r\n"
12566 "Date: %s\r\n"
12567 "Access-Control-Allow-Origin: %s\r\n"
12568 "Access-Control-Allow-Methods: %s\r\n"
12569 "Content-Length: 0\r\n"
12570 "Connection: %s\r\n",
12571 date,
12572 cors_orig_cfg,
12573 ((cors_meth_cfg[0] == '*') ? cors_acrm : cors_meth_cfg),
12574 suggest_connection_header(conn));
7c673cae 12575
11fdf7f2
TL
12576 if (cors_acrh != NULL) {
12577 /* CORS request is asking for additional headers */
12578 const char *cors_hdr_cfg =
12579 conn->ctx->config[ACCESS_CONTROL_ALLOW_HEADERS];
12580
12581 if ((cors_hdr_cfg != NULL) && (*cors_hdr_cfg != 0)) {
12582 /* Allow only if access_control_allow_headers is
12583 * not NULL and not an empty string. If this
12584 * configuration is set to *, allow everything.
12585 * Otherwise this configuration must be a list
12586 * of allowed HTTP header names. */
12587 mg_printf(conn,
12588 "Access-Control-Allow-Headers: %s\r\n",
12589 ((cors_hdr_cfg[0] == '*') ? cors_acrh
12590 : cors_hdr_cfg));
12591 }
7c673cae 12592 }
11fdf7f2
TL
12593 mg_printf(conn, "Access-Control-Max-Age: 60\r\n");
12594
12595 mg_printf(conn, "\r\n");
12596 return;
12597 }
12598 }
12599
12600 /* 5. interpret the url to find out how the request must be handled
12601 */
12602 /* 5.1. first test, if the request targets the regular http(s)://
12603 * protocol namespace or the websocket ws(s):// protocol namespace.
12604 */
12605 is_websocket_request = is_websocket_protocol(conn);
12606#if defined(USE_WEBSOCKET)
12607 handler_type = is_websocket_request ? WEBSOCKET_HANDLER : REQUEST_HANDLER;
12608#else
12609 handler_type = REQUEST_HANDLER;
12610#endif /* defined(USE_WEBSOCKET) */
12611 /* 5.2. check if the request will be handled by a callback */
12612 if (get_request_handler(conn,
12613 handler_type,
12614 &callback_handler,
12615 &subprotocols,
12616 &ws_connect_handler,
12617 &ws_ready_handler,
12618 &ws_data_handler,
12619 &ws_close_handler,
12620 NULL,
12621 &callback_data)) {
12622 /* 5.2.1. A callback will handle this request. All requests
12623 * handled
12624 * by a callback have to be considered as requests to a script
12625 * resource. */
12626 is_callback_resource = 1;
12627 is_script_resource = 1;
12628 is_put_or_delete_request = is_put_or_delete_method(conn);
12629 } else {
12630 no_callback_resource:
12631 /* 5.2.2. No callback is responsible for this request. The URI
12632 * addresses a file based resource (static content or Lua/cgi
12633 * scripts in the file system). */
12634 is_callback_resource = 0;
12635 interpret_uri(conn,
12636 path,
12637 sizeof(path),
12638 &file.stat,
12639 &is_found,
12640 &is_script_resource,
12641 &is_websocket_request,
12642 &is_put_or_delete_request);
12643 }
12644
12645 /* 6. authorization check */
12646 /* 6.1. a custom authorization handler is installed */
12647 if (get_request_handler(conn,
12648 AUTH_HANDLER,
12649 NULL,
12650 NULL,
12651 NULL,
12652 NULL,
12653 NULL,
12654 NULL,
12655 &auth_handler,
12656 &auth_callback_data)) {
12657 if (!auth_handler(conn, auth_callback_data)) {
12658 return;
12659 }
12660 } else if (is_put_or_delete_request && !is_script_resource
12661 && !is_callback_resource) {
7c673cae
FG
12662/* 6.2. this request is a PUT/DELETE to a real file */
12663/* 6.2.1. thus, the server must have real files */
12664#if defined(NO_FILES)
11fdf7f2 12665 if (1) {
7c673cae 12666#else
11fdf7f2
TL
12667 if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
12668#endif
12669 /* This server does not have any real files, thus the
12670 * PUT/DELETE methods are not valid. */
12671 mg_send_http_error(conn,
12672 405,
12673 "%s method not allowed",
12674 conn->request_info.request_method);
12675 return;
12676 }
7c673cae
FG
12677
12678#if !defined(NO_FILES)
11fdf7f2
TL
12679 /* 6.2.2. Check if put authorization for static files is
12680 * available.
12681 */
12682 if (!is_authorized_for_put(conn)) {
12683 send_authorization_request(conn, NULL);
12684 return;
12685 }
7c673cae
FG
12686#endif
12687
11fdf7f2
TL
12688 } else {
12689 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
12690 * or it is a PUT or DELETE request to a resource that does not
12691 * correspond to a file. Check authorization. */
12692 if (!check_authorization(conn, path)) {
12693 send_authorization_request(conn, NULL);
12694 return;
7c673cae 12695 }
11fdf7f2 12696 }
7c673cae 12697
11fdf7f2 12698 /* request is authorized or does not need authorization */
7c673cae 12699
11fdf7f2
TL
12700 /* 7. check if there are request handlers for this uri */
12701 if (is_callback_resource) {
12702 if (!is_websocket_request) {
12703 i = callback_handler(conn, callback_data);
12704 if (i > 0) {
12705 /* Do nothing, callback has served the request. Store
12706 * then return value as status code for the log and discard
12707 * all data from the client not used by the callback. */
12708 conn->status_code = i;
12709 discard_unread_request_data(conn);
7c673cae 12710 } else {
11fdf7f2
TL
12711 /* The handler did NOT handle the request. */
12712 /* Some proper reactions would be:
12713 * a) close the connections without sending anything
12714 * b) send a 404 not found
12715 * c) try if there is a file matching the URI
12716 * It would be possible to do a, b or c in the callback
12717 * implementation, and return 1 - we cannot do anything
12718 * here, that is not possible in the callback.
12719 *
12720 * TODO: What would be the best reaction here?
12721 * (Note: The reaction may change, if there is a better
12722 *idea.)
12723 */
12724
12725 /* For the moment, use option c: We look for a proper file,
12726 * but since a file request is not always a script resource,
12727 * the authorization check might be different. */
12728 interpret_uri(conn,
12729 path,
12730 sizeof(path),
12731 &file.stat,
12732 &is_found,
12733 &is_script_resource,
12734 &is_websocket_request,
12735 &is_put_or_delete_request);
12736 callback_handler = NULL;
12737
12738 /* Here we are at a dead end:
12739 * According to URI matching, a callback should be
12740 * responsible for handling the request,
12741 * we called it, but the callback declared itself
12742 * not responsible.
12743 * We use a goto here, to get out of this dead end,
12744 * and continue with the default handling.
12745 * A goto here is simpler and better to understand
12746 * than some curious loop. */
12747 goto no_callback_resource;
12748 }
12749 } else {
7c673cae 12750#if defined(USE_WEBSOCKET)
11fdf7f2
TL
12751 handle_websocket_request(conn,
12752 path,
12753 is_callback_resource,
12754 subprotocols,
12755 ws_connect_handler,
12756 ws_ready_handler,
12757 ws_data_handler,
12758 ws_close_handler,
12759 callback_data);
7c673cae 12760#endif
7c673cae 12761 }
11fdf7f2
TL
12762 return;
12763 }
7c673cae
FG
12764
12765/* 8. handle websocket requests */
12766#if defined(USE_WEBSOCKET)
11fdf7f2
TL
12767 if (is_websocket_request) {
12768 if (is_script_resource) {
12769
12770 if (is_in_script_path(conn, path)) {
7c673cae
FG
12771 /* Websocket Lua script */
12772 handle_websocket_request(conn,
12773 path,
12774 0 /* Lua Script */,
12775 NULL,
12776 NULL,
12777 NULL,
12778 NULL,
11fdf7f2 12779 NULL,
7c673cae
FG
12780 &conn->ctx->callbacks);
12781 } else {
11fdf7f2
TL
12782 /* Script was in an illegal path */
12783 mg_send_http_error(conn, 403, "%s", "Forbidden");
12784 }
12785 } else {
7c673cae 12786#if defined(MG_LEGACY_INTERFACE)
11fdf7f2
TL
12787 handle_websocket_request(
12788 conn,
12789 path,
12790 !is_script_resource /* could be deprecated global callback */,
12791 NULL,
12792 deprecated_websocket_connect_wrapper,
12793 deprecated_websocket_ready_wrapper,
12794 deprecated_websocket_data_wrapper,
12795 NULL,
12796 &conn->ctx->callbacks);
7c673cae 12797#else
11fdf7f2 12798 mg_send_http_error(conn, 404, "%s", "Not found");
7c673cae 12799#endif
11fdf7f2
TL
12800 }
12801 return;
12802 } else
7c673cae
FG
12803#endif
12804
12805#if defined(NO_FILES)
11fdf7f2
TL
12806 /* 9a. In case the server uses only callbacks, this uri is
12807 * unknown.
12808 * Then, all request handling ends here. */
12809 mg_send_http_error(conn, 404, "%s", "Not Found");
7c673cae
FG
12810
12811#else
11fdf7f2
TL
12812 /* 9b. This request is either for a static file or resource handled
12813 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
12814 if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
12815 mg_send_http_error(conn, 404, "%s", "Not Found");
12816 return;
12817 }
7c673cae 12818
11fdf7f2
TL
12819 /* 10. Request is handled by a script */
12820 if (is_script_resource) {
12821 handle_file_based_request(conn, path, &file);
12822 return;
12823 }
7c673cae 12824
11fdf7f2
TL
12825 /* 11. Handle put/delete/mkcol requests */
12826 if (is_put_or_delete_request) {
12827 /* 11.1. PUT method */
12828 if (!strcmp(ri->request_method, "PUT")) {
12829 put_file(conn, path);
7c673cae
FG
12830 return;
12831 }
11fdf7f2
TL
12832 /* 11.2. DELETE method */
12833 if (!strcmp(ri->request_method, "DELETE")) {
12834 delete_file(conn, path);
7c673cae
FG
12835 return;
12836 }
11fdf7f2
TL
12837 /* 11.3. MKCOL method */
12838 if (!strcmp(ri->request_method, "MKCOL")) {
12839 mkcol(conn, path);
7c673cae
FG
12840 return;
12841 }
11fdf7f2
TL
12842 /* 11.4. PATCH method
12843 * This method is not supported for static resources,
12844 * only for scripts (Lua, CGI) and callbacks. */
12845 mg_send_http_error(conn,
12846 405,
12847 "%s method not allowed",
12848 conn->request_info.request_method);
12849 return;
12850 }
7c673cae 12851
11fdf7f2
TL
12852 /* 11. File does not exist, or it was configured that it should be
12853 * hidden */
12854 if (!is_found || (must_hide_file(conn, path))) {
12855 mg_send_http_error(conn, 404, "%s", "Not found");
12856 return;
12857 }
7c673cae 12858
11fdf7f2
TL
12859 /* 12. Directory uris should end with a slash */
12860 if (file.stat.is_directory && (uri_len > 0)
12861 && (ri->local_uri[uri_len - 1] != '/')) {
12862 gmt_time_string(date, sizeof(date), &curtime);
12863 mg_printf(conn,
12864 "HTTP/1.1 301 Moved Permanently\r\n"
12865 "Location: %s/\r\n"
12866 "Date: %s\r\n"
12867 /* "Cache-Control: private\r\n" (= default) */
12868 "Content-Length: 0\r\n"
12869 "Connection: %s\r\n",
12870 ri->request_uri,
12871 date,
12872 suggest_connection_header(conn));
12873 send_additional_header(conn);
12874 mg_printf(conn, "\r\n");
12875 return;
12876 }
12877
12878 /* 13. Handle other methods than GET/HEAD */
12879 /* 13.1. Handle PROPFIND */
12880 if (!strcmp(ri->request_method, "PROPFIND")) {
12881 handle_propfind(conn, path, &file.stat);
12882 return;
12883 }
12884 /* 13.2. Handle OPTIONS for files */
12885 if (!strcmp(ri->request_method, "OPTIONS")) {
12886 /* This standard handler is only used for real files.
12887 * Scripts should support the OPTIONS method themselves, to allow a
12888 * maximum flexibility.
12889 * Lua and CGI scripts may fully support CORS this way (including
12890 * preflights). */
12891 send_options(conn);
12892 return;
12893 }
12894 /* 13.3. everything but GET and HEAD (e.g. POST) */
12895 if ((0 != strcmp(ri->request_method, "GET"))
12896 && (0 != strcmp(ri->request_method, "HEAD"))) {
12897 mg_send_http_error(conn,
12898 405,
12899 "%s method not allowed",
12900 conn->request_info.request_method);
12901 return;
12902 }
12903
12904 /* 14. directories */
12905 if (file.stat.is_directory) {
12906 /* Substitute files have already been handled above. */
12907 /* Here we can either generate and send a directory listing,
12908 * or send an "access denied" error. */
12909 if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
12910 "yes")) {
12911 handle_directory_request(conn, path);
12912 } else {
12913 mg_send_http_error(conn,
12914 403,
12915 "%s",
12916 "Error: Directory listing denied");
7c673cae 12917 }
11fdf7f2
TL
12918 return;
12919 }
7c673cae 12920
11fdf7f2 12921 handle_file_based_request(conn, path, &file);
7c673cae
FG
12922#endif /* !defined(NO_FILES) */
12923
12924#if 0
12925 /* Perform redirect and auth checks before calling begin_request()
12926 * handler.
12927 * Otherwise, begin_request() would need to perform auth checks and
12928 * redirects. */
12929#endif
7c673cae
FG
12930}
12931
12932
12933static void
12934handle_file_based_request(struct mg_connection *conn,
12935 const char *path,
11fdf7f2 12936 struct mg_file *file)
7c673cae
FG
12937{
12938 if (!conn || !conn->ctx) {
12939 return;
12940 }
12941
12942 if (0) {
12943#ifdef USE_LUA
12944 } else if (match_prefix(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
12945 strlen(
12946 conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
12947 path) > 0) {
11fdf7f2
TL
12948 if (is_in_script_path(conn, path)) {
12949 /* Lua server page: an SSI like page containing mostly plain
12950 * html
12951 * code
12952 * plus some tags with server generated contents. */
12953 handle_lsp_request(conn, path, file, NULL);
12954 } else {
12955 /* Script was in an illegal path */
12956 mg_send_http_error(conn, 403, "%s", "Forbidden");
12957 }
12958
7c673cae
FG
12959 } else if (match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
12960 strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
12961 path) > 0) {
11fdf7f2
TL
12962 if (is_in_script_path(conn, path)) {
12963 /* Lua in-server module script: a CGI like script used to
12964 * generate
12965 * the
12966 * entire reply. */
12967 mg_exec_lua_script(conn, path, NULL);
12968 } else {
12969 /* Script was in an illegal path */
12970 mg_send_http_error(conn, 403, "%s", "Forbidden");
12971 }
7c673cae
FG
12972#endif
12973#if defined(USE_DUKTAPE)
12974 } else if (match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
12975 strlen(
12976 conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
12977 path) > 0) {
11fdf7f2
TL
12978 if (is_in_script_path(conn, path)) {
12979 /* Call duktape to generate the page */
12980 mg_exec_duktape_script(conn, path);
12981 } else {
12982 /* Script was in an illegal path */
12983 mg_send_http_error(conn, 403, "%s", "Forbidden");
12984 }
7c673cae
FG
12985#endif
12986#if !defined(NO_CGI)
12987 } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
12988 strlen(conn->ctx->config[CGI_EXTENSIONS]),
12989 path) > 0) {
11fdf7f2
TL
12990 if (is_in_script_path(conn, path)) {
12991 /* CGI scripts may support all HTTP methods */
12992 handle_cgi_request(conn, path);
12993 } else {
12994 /* Script was in an illegal path */
12995 mg_send_http_error(conn, 403, "%s", "Forbidden");
12996 }
7c673cae
FG
12997#endif /* !NO_CGI */
12998 } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
12999 strlen(conn->ctx->config[SSI_EXTENSIONS]),
13000 path) > 0) {
11fdf7f2
TL
13001 if (is_in_script_path(conn, path)) {
13002 handle_ssi_file_request(conn, path, file);
13003 } else {
13004 /* Script was in an illegal path */
13005 mg_send_http_error(conn, 403, "%s", "Forbidden");
13006 }
7c673cae 13007#if !defined(NO_CACHING)
11fdf7f2
TL
13008 } else if ((!conn->in_error_handler)
13009 && is_not_modified(conn, &file->stat)) {
7c673cae 13010 /* Send 304 "Not Modified" - this must not send any body data */
11fdf7f2 13011 handle_not_modified_static_file_request(conn, file);
7c673cae
FG
13012#endif /* !NO_CACHING */
13013 } else {
11fdf7f2 13014 handle_static_file_request(conn, path, file, NULL, NULL);
7c673cae
FG
13015 }
13016}
13017
13018
13019static void
13020close_all_listening_sockets(struct mg_context *ctx)
13021{
13022 unsigned int i;
13023 if (!ctx) {
13024 return;
13025 }
13026
13027 for (i = 0; i < ctx->num_listening_sockets; i++) {
13028 closesocket(ctx->listening_sockets[i].sock);
13029 ctx->listening_sockets[i].sock = INVALID_SOCKET;
13030 }
13031 mg_free(ctx->listening_sockets);
13032 ctx->listening_sockets = NULL;
11fdf7f2
TL
13033 mg_free(ctx->listening_socket_fds);
13034 ctx->listening_socket_fds = NULL;
7c673cae
FG
13035}
13036
13037
13038/* Valid listening port specification is: [ip_address:]port[s]
11fdf7f2 13039 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 192.0.2.3:8080s
7c673cae 13040 * Examples for IPv6: [::]:80, [::1]:80,
11fdf7f2
TL
13041 * [2001:0db8:7654:3210:FEDC:BA98:7654:3210]:443s
13042 * see https://tools.ietf.org/html/rfc3513#section-2.2
13043 * In order to bind to both, IPv4 and IPv6, you can either add
13044 * both ports using 8080,[::]:8080, or the short form +8080.
13045 * Both forms differ in detail: 8080,[::]:8080 create two sockets,
13046 * one only accepting IPv4 the other only IPv6. +8080 creates
13047 * one socket accepting IPv4 and IPv6. Depending on the IPv6
13048 * environment, they might work differently, or might not work
13049 * at all - it must be tested what options work best in the
13050 * relevant network environment.
13051 */
7c673cae 13052static int
11fdf7f2 13053parse_port_string(const struct vec *vec, struct socket *so, int *ip_version)
7c673cae
FG
13054{
13055 unsigned int a, b, c, d, port;
13056 int ch, len;
11fdf7f2 13057 const char *cb;
7c673cae
FG
13058#if defined(USE_IPV6)
13059 char buf[100] = {0};
13060#endif
13061
13062 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
13063 * Also, all-zeroes in the socket address means binding to all addresses
13064 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
13065 memset(so, 0, sizeof(*so));
13066 so->lsa.sin.sin_family = AF_INET;
11fdf7f2
TL
13067 *ip_version = 0;
13068
13069 /* Initialize port and len as invalid. */
13070 port = 0;
13071 len = 0;
7c673cae 13072
11fdf7f2 13073 /* Test for different ways to format this string */
7c673cae
FG
13074 if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
13075 == 5) {
13076 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
13077 so->lsa.sin.sin_addr.s_addr =
13078 htonl((a << 24) | (b << 16) | (c << 8) | d);
13079 so->lsa.sin.sin_port = htons((uint16_t)port);
11fdf7f2
TL
13080 *ip_version = 4;
13081
7c673cae
FG
13082#if defined(USE_IPV6)
13083 } else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
13084 && mg_inet_pton(
13085 AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
13086 /* IPv6 address, examples: see above */
13087 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
13088 */
13089 so->lsa.sin6.sin6_port = htons((uint16_t)port);
11fdf7f2
TL
13090 *ip_version = 6;
13091#endif
13092
13093 } else if ((vec->ptr[0] == '+')
13094 && (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
13095
13096 /* Port is specified with a +, bind to IPv6 and IPv4, INADDR_ANY */
13097 /* Add 1 to len for the + character we skipped before */
13098 len++;
13099
13100#if defined(USE_IPV6)
13101 /* Set socket family to IPv6, do not use IPV6_V6ONLY */
13102 so->lsa.sin6.sin6_family = AF_INET6;
13103 so->lsa.sin6.sin6_port = htons((uint16_t)port);
13104 *ip_version = 4 + 6;
13105#else
13106 /* Bind to IPv4 only, since IPv6 is not built in. */
13107 so->lsa.sin.sin_port = htons((uint16_t)port);
13108 *ip_version = 4;
7c673cae 13109#endif
11fdf7f2 13110
7c673cae
FG
13111 } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
13112 /* If only port is specified, bind to IPv4, INADDR_ANY */
13113 so->lsa.sin.sin_port = htons((uint16_t)port);
11fdf7f2
TL
13114 *ip_version = 4;
13115
13116 } else if ((cb = strchr(vec->ptr, ':')) != NULL) {
13117 /* Could be a hostname */
13118 /* Will only work for RFC 952 compliant hostnames,
13119 * starting with a letter, containing only letters,
13120 * digits and hyphen ('-'). Newer specs may allow
13121 * more, but this is not guaranteed here, since it
13122 * may interfere with rules for port option lists. */
13123
13124 *(char *)cb = 0; /* Use a const cast here and modify the string.
13125 * We are going to restore the string later. */
13126
13127 if (mg_inet_pton(
13128 AF_INET, vec->ptr, &so->lsa.sin, sizeof(so->lsa.sin))) {
13129 if (sscanf(cb + 1, "%u%n", &port, &len) == 1) {
13130 *ip_version = 4;
13131 so->lsa.sin.sin_family = AF_INET;
13132 so->lsa.sin.sin_port = htons((uint16_t)port);
13133 len += (int)(cb - vec->ptr) + 1;
13134 } else {
13135 port = 0;
13136 len = 0;
13137 }
13138#if defined(USE_IPV6)
13139 } else if (mg_inet_pton(AF_INET6,
13140 vec->ptr,
13141 &so->lsa.sin6,
13142 sizeof(so->lsa.sin6))) {
13143 if (sscanf(cb + 1, "%u%n", &port, &len) == 1) {
13144 *ip_version = 6;
13145 so->lsa.sin6.sin6_family = AF_INET6;
13146 so->lsa.sin.sin_port = htons((uint16_t)port);
13147 len += (int)(cb - vec->ptr) + 1;
13148 } else {
13149 port = 0;
13150 len = 0;
13151 }
13152#endif
13153 }
13154
13155 *(char *)cb = ':'; /* restore the string */
13156
7c673cae 13157 } else {
11fdf7f2 13158 /* Parsing failure. */
7c673cae
FG
13159 }
13160
13161 /* sscanf and the option splitting code ensure the following condition
13162 */
13163 if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
11fdf7f2 13164 *ip_version = 0;
7c673cae
FG
13165 return 0;
13166 }
13167 ch = vec->ptr[len]; /* Next character after the port number */
13168 so->is_ssl = (ch == 's');
13169 so->ssl_redir = (ch == 'r');
13170
13171 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
11fdf7f2
TL
13172 if (is_valid_port(port)
13173 && ((ch == '\0') || (ch == 's') || (ch == 'r') || (ch == ','))) {
13174 return 1;
13175 }
13176
13177 /* Reset ip_version to 0 of there is an error */
13178 *ip_version = 0;
13179 return 0;
7c673cae
FG
13180}
13181
13182
13183static int
13184set_ports_option(struct mg_context *ctx)
13185{
13186 const char *list;
13187 int on = 1;
13188#if defined(USE_IPV6)
13189 int off = 0;
13190#endif
13191 struct vec vec;
13192 struct socket so, *ptr;
13193
11fdf7f2 13194 struct pollfd *pfd;
7c673cae
FG
13195 union usa usa;
13196 socklen_t len;
11fdf7f2 13197 int ip_version;
7c673cae
FG
13198
13199 int portsTotal = 0;
13200 int portsOk = 0;
13201
13202 if (!ctx) {
13203 return 0;
13204 }
13205
13206 memset(&so, 0, sizeof(so));
13207 memset(&usa, 0, sizeof(usa));
13208 len = sizeof(usa);
13209 list = ctx->config[LISTENING_PORTS];
11fdf7f2 13210
7c673cae
FG
13211 while ((list = next_option(list, &vec, NULL)) != NULL) {
13212
13213 portsTotal++;
13214
11fdf7f2 13215 if (!parse_port_string(&vec, &so, &ip_version)) {
7c673cae
FG
13216 mg_cry(fc(ctx),
13217 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
13218 (int)vec.len,
13219 vec.ptr,
13220 portsTotal,
13221 "[IP_ADDRESS:]PORT[s|r]");
13222 continue;
13223 }
13224
11fdf7f2 13225#if !defined(NO_SSL)
7c673cae
FG
13226 if (so.is_ssl && ctx->ssl_ctx == NULL) {
13227
13228 mg_cry(fc(ctx),
13229 "Cannot add SSL socket (entry %i). Is -ssl_certificate "
13230 "option set?",
13231 portsTotal);
13232 continue;
13233 }
11fdf7f2 13234#endif
7c673cae
FG
13235
13236 if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
13237 == INVALID_SOCKET) {
13238
13239 mg_cry(fc(ctx), "cannot create socket (entry %i)", portsTotal);
13240 continue;
13241 }
13242
13243#ifdef _WIN32
13244 /* Windows SO_REUSEADDR lets many procs binds to a
13245 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
13246 * if someone already has the socket -- DTL */
13247 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
13248 * Windows might need a few seconds before
13249 * the same port can be used again in the
13250 * same process, so a short Sleep may be
13251 * required between mg_stop and mg_start.
13252 */
13253 if (setsockopt(so.sock,
13254 SOL_SOCKET,
13255 SO_EXCLUSIVEADDRUSE,
13256 (SOCK_OPT_TYPE)&on,
13257 sizeof(on)) != 0) {
13258
11fdf7f2 13259 /* Set reuse option, but don't abort on errors. */
7c673cae
FG
13260 mg_cry(fc(ctx),
13261 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
13262 portsTotal);
13263 }
13264#else
13265 if (setsockopt(so.sock,
13266 SOL_SOCKET,
13267 SO_REUSEADDR,
13268 (SOCK_OPT_TYPE)&on,
13269 sizeof(on)) != 0) {
13270
11fdf7f2 13271 /* Set reuse option, but don't abort on errors. */
7c673cae
FG
13272 mg_cry(fc(ctx),
13273 "cannot set socket option SO_REUSEADDR (entry %i)",
13274 portsTotal);
13275 }
13276#endif
13277
11fdf7f2 13278 if (ip_version > 4) {
7c673cae 13279#if defined(USE_IPV6)
11fdf7f2
TL
13280 if (ip_version == 6) {
13281 if (so.lsa.sa.sa_family == AF_INET6
13282 && setsockopt(so.sock,
13283 IPPROTO_IPV6,
13284 IPV6_V6ONLY,
13285 (void *)&off,
13286 sizeof(off)) != 0) {
13287
13288 /* Set IPv6 only option, but don't abort on errors. */
13289 mg_cry(fc(ctx),
13290 "cannot set socket option IPV6_V6ONLY (entry %i)",
13291 portsTotal);
13292 }
13293 }
13294#else
13295 mg_cry(fc(ctx), "IPv6 not available");
13296 closesocket(so.sock);
13297 so.sock = INVALID_SOCKET;
13298 continue;
7c673cae 13299#endif
11fdf7f2 13300 }
7c673cae
FG
13301
13302 if (so.lsa.sa.sa_family == AF_INET) {
13303
13304 len = sizeof(so.lsa.sin);
13305 if (bind(so.sock, &so.lsa.sa, len) != 0) {
13306 mg_cry(fc(ctx),
13307 "cannot bind to %.*s: %d (%s)",
13308 (int)vec.len,
13309 vec.ptr,
13310 (int)ERRNO,
13311 strerror(errno));
13312 closesocket(so.sock);
13313 so.sock = INVALID_SOCKET;
13314 continue;
13315 }
13316 }
13317#if defined(USE_IPV6)
13318 else if (so.lsa.sa.sa_family == AF_INET6) {
13319
13320 len = sizeof(so.lsa.sin6);
13321 if (bind(so.sock, &so.lsa.sa, len) != 0) {
13322 mg_cry(fc(ctx),
13323 "cannot bind to IPv6 %.*s: %d (%s)",
13324 (int)vec.len,
13325 vec.ptr,
13326 (int)ERRNO,
13327 strerror(errno));
13328 closesocket(so.sock);
13329 so.sock = INVALID_SOCKET;
13330 continue;
13331 }
13332 }
13333#endif
13334 else {
13335 mg_cry(fc(ctx),
13336 "cannot bind: address family not supported (entry %i)",
13337 portsTotal);
11fdf7f2
TL
13338 closesocket(so.sock);
13339 so.sock = INVALID_SOCKET;
7c673cae
FG
13340 continue;
13341 }
13342
13343 if (listen(so.sock, SOMAXCONN) != 0) {
13344
13345 mg_cry(fc(ctx),
13346 "cannot listen to %.*s: %d (%s)",
13347 (int)vec.len,
13348 vec.ptr,
13349 (int)ERRNO,
13350 strerror(errno));
13351 closesocket(so.sock);
13352 so.sock = INVALID_SOCKET;
13353 continue;
13354 }
13355
11fdf7f2
TL
13356 if ((getsockname(so.sock, &(usa.sa), &len) != 0)
13357 || (usa.sa.sa_family != so.lsa.sa.sa_family)) {
7c673cae
FG
13358
13359 int err = (int)ERRNO;
13360 mg_cry(fc(ctx),
13361 "call to getsockname failed %.*s: %d (%s)",
13362 (int)vec.len,
13363 vec.ptr,
13364 err,
13365 strerror(errno));
13366 closesocket(so.sock);
13367 so.sock = INVALID_SOCKET;
13368 continue;
13369 }
13370
11fdf7f2
TL
13371/* Update lsa port in case of random free ports */
13372#if defined(USE_IPV6)
13373 if (so.lsa.sa.sa_family == AF_INET6) {
13374 so.lsa.sin6.sin6_port = usa.sin6.sin6_port;
13375 } else
13376#endif
13377 {
13378 so.lsa.sin.sin_port = usa.sin.sin_port;
13379 }
13380
7c673cae 13381 if ((ptr = (struct socket *)
11fdf7f2
TL
13382 mg_realloc_ctx(ctx->listening_sockets,
13383 (ctx->num_listening_sockets + 1)
13384 * sizeof(ctx->listening_sockets[0]),
13385 ctx)) == NULL) {
7c673cae
FG
13386
13387 mg_cry(fc(ctx), "%s", "Out of memory");
13388 closesocket(so.sock);
13389 so.sock = INVALID_SOCKET;
13390 continue;
13391 }
13392
11fdf7f2
TL
13393 if ((pfd = (struct pollfd *)
13394 mg_realloc_ctx(ctx->listening_socket_fds,
13395 (ctx->num_listening_sockets + 1)
13396 * sizeof(ctx->listening_socket_fds[0]),
13397 ctx)) == NULL) {
7c673cae
FG
13398
13399 mg_cry(fc(ctx), "%s", "Out of memory");
13400 closesocket(so.sock);
13401 so.sock = INVALID_SOCKET;
13402 mg_free(ptr);
13403 continue;
13404 }
13405
13406 set_close_on_exec(so.sock, fc(ctx));
13407 ctx->listening_sockets = ptr;
13408 ctx->listening_sockets[ctx->num_listening_sockets] = so;
11fdf7f2 13409 ctx->listening_socket_fds = pfd;
7c673cae
FG
13410 ctx->num_listening_sockets++;
13411 portsOk++;
13412 }
13413
13414 if (portsOk != portsTotal) {
13415 close_all_listening_sockets(ctx);
13416 portsOk = 0;
13417 }
13418
13419 return portsOk;
13420}
13421
13422
13423static const char *
13424header_val(const struct mg_connection *conn, const char *header)
13425{
13426 const char *header_value;
13427
13428 if ((header_value = mg_get_header(conn, header)) == NULL) {
13429 return "-";
13430 } else {
13431 return header_value;
13432 }
13433}
13434
13435
13436static void
13437log_access(const struct mg_connection *conn)
13438{
13439 const struct mg_request_info *ri;
11fdf7f2 13440 struct mg_file fi;
7c673cae
FG
13441 char date[64], src_addr[IP_ADDR_STR_LEN];
13442 struct tm *tm;
13443
13444 const char *referer;
13445 const char *user_agent;
13446
13447 char buf[4096];
13448
13449 if (!conn || !conn->ctx) {
13450 return;
13451 }
13452
13453 if (conn->ctx->config[ACCESS_LOG_FILE] != NULL) {
11fdf7f2
TL
13454 if (mg_fopen(conn,
13455 conn->ctx->config[ACCESS_LOG_FILE],
13456 MG_FOPEN_MODE_APPEND,
13457 &fi) == 0) {
13458 fi.access.fp = NULL;
7c673cae
FG
13459 }
13460 } else {
11fdf7f2 13461 fi.access.fp = NULL;
7c673cae
FG
13462 }
13463
11fdf7f2
TL
13464 /* Log is written to a file and/or a callback. If both are not set,
13465 * executing the rest of the function is pointless. */
13466 if ((fi.access.fp == NULL) && (conn->ctx->callbacks.log_access == NULL)) {
7c673cae
FG
13467 return;
13468 }
13469
13470 tm = localtime(&conn->conn_birth_time);
13471 if (tm != NULL) {
13472 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
13473 } else {
13474 mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
13475 date[sizeof(date) - 1] = '\0';
13476 }
13477
13478 ri = &conn->request_info;
13479
13480 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
13481 referer = header_val(conn, "Referer");
13482 user_agent = header_val(conn, "User-Agent");
13483
13484 mg_snprintf(conn,
13485 NULL, /* Ignore truncation in access log */
13486 buf,
13487 sizeof(buf),
13488 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
13489 src_addr,
11fdf7f2 13490 (ri->remote_user == NULL) ? "-" : ri->remote_user,
7c673cae
FG
13491 date,
13492 ri->request_method ? ri->request_method : "-",
13493 ri->request_uri ? ri->request_uri : "-",
13494 ri->query_string ? "?" : "",
13495 ri->query_string ? ri->query_string : "",
13496 ri->http_version,
13497 conn->status_code,
13498 conn->num_bytes_sent,
13499 referer,
13500 user_agent);
13501
13502 if (conn->ctx->callbacks.log_access) {
13503 conn->ctx->callbacks.log_access(conn, buf);
13504 }
13505
11fdf7f2
TL
13506 if (fi.access.fp) {
13507 int ok = 1;
13508 flockfile(fi.access.fp);
13509 if (fprintf(fi.access.fp, "%s\n", buf) < 1) {
13510 ok = 0;
13511 }
13512 if (fflush(fi.access.fp) != 0) {
13513 ok = 0;
13514 }
13515 funlockfile(fi.access.fp);
13516 if (mg_fclose(&fi.access) != 0) {
13517 ok = 0;
13518 }
13519 if (!ok) {
13520 mg_cry(conn,
13521 "Error writing log file %s",
13522 conn->ctx->config[ACCESS_LOG_FILE]);
13523 }
7c673cae
FG
13524 }
13525}
13526
13527
13528/* Verify given socket address against the ACL.
13529 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
13530 */
13531static int
13532check_acl(struct mg_context *ctx, uint32_t remote_ip)
13533{
13534 int allowed, flag;
13535 uint32_t net, mask;
13536 struct vec vec;
13537
13538 if (ctx) {
13539 const char *list = ctx->config[ACCESS_CONTROL_LIST];
13540
13541 /* If any ACL is set, deny by default */
11fdf7f2 13542 allowed = (list == NULL) ? '+' : '-';
7c673cae
FG
13543
13544 while ((list = next_option(list, &vec, NULL)) != NULL) {
13545 flag = vec.ptr[0];
13546 if ((flag != '+' && flag != '-')
11fdf7f2 13547 || (parse_net(&vec.ptr[1], &net, &mask) == 0)) {
7c673cae
FG
13548 mg_cry(fc(ctx),
13549 "%s: subnet must be [+|-]x.x.x.x[/x]",
13550 __func__);
13551 return -1;
13552 }
13553
13554 if (net == (remote_ip & mask)) {
13555 allowed = flag;
13556 }
13557 }
13558
13559 return allowed == '+';
13560 }
13561 return -1;
13562}
13563
13564
13565#if !defined(_WIN32)
13566static int
13567set_uid_option(struct mg_context *ctx)
13568{
13569 struct passwd *pw;
13570 if (ctx) {
13571 const char *uid = ctx->config[RUN_AS_USER];
13572 int success = 0;
13573
13574 if (uid == NULL) {
13575 success = 1;
13576 } else {
13577 if ((pw = getpwnam(uid)) == NULL) {
13578 mg_cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
13579 } else if (setgid(pw->pw_gid) == -1) {
13580 mg_cry(fc(ctx),
13581 "%s: setgid(%s): %s",
13582 __func__,
13583 uid,
13584 strerror(errno));
13585 } else if (setgroups(0, NULL)) {
13586 mg_cry(fc(ctx),
13587 "%s: setgroups(): %s",
13588 __func__,
13589 strerror(errno));
13590 } else if (setuid(pw->pw_uid) == -1) {
13591 mg_cry(fc(ctx),
13592 "%s: setuid(%s): %s",
13593 __func__,
13594 uid,
13595 strerror(errno));
13596 } else {
13597 success = 1;
13598 }
13599 }
13600
13601 return success;
13602 }
13603 return 0;
13604}
13605#endif /* !_WIN32 */
13606
13607
13608static void
13609tls_dtor(void *key)
13610{
13611 struct mg_workerTLS *tls = (struct mg_workerTLS *)key;
13612 /* key == pthread_getspecific(sTlsKey); */
13613
13614 if (tls) {
13615 if (tls->is_master == 2) {
13616 tls->is_master = -3; /* Mark memory as dead */
13617 mg_free(tls);
13618 }
13619 }
13620 pthread_setspecific(sTlsKey, NULL);
13621}
13622
13623
13624#if !defined(NO_SSL)
13625
11fdf7f2
TL
13626static int
13627ssl_use_pem_file(struct mg_context *ctx, const char *pem, const char *chain);
7c673cae
FG
13628static const char *ssl_error(void);
13629
13630
13631static int
13632refresh_trust(struct mg_connection *conn)
13633{
13634 static int reload_lock = 0;
13635 static long int data_check = 0;
11fdf7f2 13636 volatile int *p_reload_lock = (volatile int *)&reload_lock;
7c673cae
FG
13637
13638 struct stat cert_buf;
13639 long int t;
11fdf7f2
TL
13640 const char *pem;
13641 const char *chain;
7c673cae
FG
13642 int should_verify_peer;
13643
11fdf7f2
TL
13644 if ((pem = conn->ctx->config[SSL_CERTIFICATE]) == NULL) {
13645 /* If peem is NULL and conn->ctx->callbacks.init_ssl is not,
13646 * refresh_trust still can not work. */
7c673cae
FG
13647 return 0;
13648 }
11fdf7f2
TL
13649 chain = conn->ctx->config[SSL_CERTIFICATE_CHAIN];
13650 if (chain == NULL) {
13651 /* pem is not NULL here */
13652 chain = pem;
13653 }
13654 if (*chain == 0) {
13655 chain = NULL;
13656 }
7c673cae
FG
13657
13658 t = data_check;
13659 if (stat(pem, &cert_buf) != -1) {
13660 t = (long int)cert_buf.st_mtime;
13661 }
13662
13663 if (data_check != t) {
13664 data_check = t;
13665
11fdf7f2
TL
13666 should_verify_peer = 0;
13667 if (conn->ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
13668 if (mg_strcasecmp(conn->ctx->config[SSL_DO_VERIFY_PEER], "yes")
13669 == 0) {
13670 should_verify_peer = 1;
13671 } else if (mg_strcasecmp(conn->ctx->config[SSL_DO_VERIFY_PEER],
13672 "optional") == 0) {
13673 should_verify_peer = 1;
13674 }
13675 }
7c673cae
FG
13676
13677 if (should_verify_peer) {
13678 char *ca_path = conn->ctx->config[SSL_CA_PATH];
13679 char *ca_file = conn->ctx->config[SSL_CA_FILE];
13680 if (SSL_CTX_load_verify_locations(conn->ctx->ssl_ctx,
13681 ca_file,
13682 ca_path) != 1) {
13683 mg_cry(fc(conn->ctx),
13684 "SSL_CTX_load_verify_locations error: %s "
13685 "ssl_verify_peer requires setting "
13686 "either ssl_ca_path or ssl_ca_file. Is any of them "
13687 "present in "
13688 "the .conf file?",
13689 ssl_error());
13690 return 0;
13691 }
13692 }
13693
11fdf7f2
TL
13694 if (1 == mg_atomic_inc(p_reload_lock)) {
13695 if (ssl_use_pem_file(conn->ctx, pem, chain) == 0) {
7c673cae
FG
13696 return 0;
13697 }
11fdf7f2 13698 *p_reload_lock = 0;
7c673cae
FG
13699 }
13700 }
13701 /* lock while cert is reloading */
11fdf7f2 13702 while (*p_reload_lock) {
7c673cae
FG
13703 sleep(1);
13704 }
13705
13706 return 1;
13707}
13708
11fdf7f2
TL
13709#ifdef OPENSSL_API_1_1
13710#else
7c673cae 13711static pthread_mutex_t *ssl_mutexes;
11fdf7f2 13712#endif /* OPENSSL_API_1_1 */
7c673cae
FG
13713
13714static int
11fdf7f2
TL
13715sslize(struct mg_connection *conn,
13716 SSL_CTX *s,
13717 int (*func)(SSL *),
13718 volatile int *stop_server)
7c673cae
FG
13719{
13720 int ret, err;
13721 int short_trust;
11fdf7f2 13722 unsigned i;
7c673cae
FG
13723
13724 if (!conn) {
13725 return 0;
13726 }
13727
13728 short_trust =
13729 (conn->ctx->config[SSL_SHORT_TRUST] != NULL)
13730 && (mg_strcasecmp(conn->ctx->config[SSL_SHORT_TRUST], "yes") == 0);
13731
13732 if (short_trust) {
13733 int trust_ret = refresh_trust(conn);
13734 if (!trust_ret) {
13735 return trust_ret;
13736 }
13737 }
13738
13739 conn->ssl = SSL_new(s);
13740 if (conn->ssl == NULL) {
13741 return 0;
13742 }
11fdf7f2 13743 SSL_set_app_data(conn->ssl, (char *)conn);
7c673cae
FG
13744
13745 ret = SSL_set_fd(conn->ssl, conn->client.sock);
13746 if (ret != 1) {
13747 err = SSL_get_error(conn->ssl, ret);
13748 (void)err; /* TODO: set some error message */
13749 SSL_free(conn->ssl);
13750 conn->ssl = NULL;
11fdf7f2
TL
13751/* Avoid CRYPTO_cleanup_all_ex_data(); See discussion:
13752 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
13753#ifndef OPENSSL_API_1_1
7c673cae 13754 ERR_remove_state(0);
11fdf7f2 13755#endif
7c673cae
FG
13756 return 0;
13757 }
13758
11fdf7f2
TL
13759 /* SSL functions may fail and require to be called again:
13760 * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html
13761 * Here "func" could be SSL_connect or SSL_accept. */
13762 for (i = 16; i <= 1024; i *= 2) {
13763 ret = func(conn->ssl);
13764 if (ret != 1) {
13765 err = SSL_get_error(conn->ssl, ret);
13766 if ((err == SSL_ERROR_WANT_CONNECT)
13767 || (err == SSL_ERROR_WANT_ACCEPT)
13768 || (err == SSL_ERROR_WANT_READ)
13769 || (err == SSL_ERROR_WANT_WRITE)) {
13770 /* Need to retry the function call "later".
13771 * See https://linux.die.net/man/3/ssl_get_error
13772 * This is typical for non-blocking sockets. */
13773 if (*stop_server) {
13774 /* Don't wait if the server is going to be stopped. */
13775 break;
13776 }
13777 mg_sleep(i);
13778
13779 } else if (err == SSL_ERROR_SYSCALL) {
13780 /* This is an IO error. Look at errno. */
13781 err = errno;
13782 /* TODO: set some error message */
13783 (void)err;
13784 break;
13785 } else {
13786 /* This is an SSL specific error */
13787 /* TODO: set some error message */
13788 break;
13789 }
13790
13791 } else {
13792 /* success */
13793 break;
13794 }
13795 }
13796
7c673cae 13797 if (ret != 1) {
7c673cae
FG
13798 SSL_free(conn->ssl);
13799 conn->ssl = NULL;
11fdf7f2
TL
13800/* Avoid CRYPTO_cleanup_all_ex_data(); See discussion:
13801 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
13802#ifndef OPENSSL_API_1_1
7c673cae 13803 ERR_remove_state(0);
11fdf7f2 13804#endif
7c673cae
FG
13805 return 0;
13806 }
13807
13808 return 1;
13809}
13810
13811
13812/* Return OpenSSL error message (from CRYPTO lib) */
13813static const char *
13814ssl_error(void)
13815{
13816 unsigned long err;
13817 err = ERR_get_error();
11fdf7f2
TL
13818 return ((err == 0) ? "" : ERR_error_string(err, NULL));
13819}
13820
13821
13822static int
13823hexdump2string(void *mem, int memlen, char *buf, int buflen)
13824{
13825 int i;
13826 const char hexdigit[] = "0123456789abcdef";
13827
13828 if ((memlen <= 0) || (buflen <= 0)) {
13829 return 0;
13830 }
13831 if (buflen < (3 * memlen)) {
13832 return 0;
13833 }
13834
13835 for (i = 0; i < memlen; i++) {
13836 if (i > 0) {
13837 buf[3 * i - 1] = ' ';
13838 }
13839 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
13840 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
13841 }
13842 buf[3 * memlen - 1] = 0;
13843
13844 return 1;
13845}
13846
13847
13848static void
13849ssl_get_client_cert_info(struct mg_connection *conn)
13850{
13851 X509 *cert = SSL_get_peer_certificate(conn->ssl);
13852 if (cert) {
13853 char str_subject[1024];
13854 char str_issuer[1024];
13855 char str_finger[1024];
13856 unsigned char buf[256];
13857 char *str_serial = NULL;
13858 unsigned int ulen;
13859 int ilen;
13860 unsigned char *tmp_buf;
13861 unsigned char *tmp_p;
13862
13863 /* Handle to algorithm used for fingerprint */
13864 const EVP_MD *digest = EVP_get_digestbyname("sha1");
13865
13866 /* Get Subject and issuer */
13867 X509_NAME *subj = X509_get_subject_name(cert);
13868 X509_NAME *iss = X509_get_issuer_name(cert);
13869
13870 /* Get serial number */
13871 ASN1_INTEGER *serial = X509_get_serialNumber(cert);
13872
13873 /* Translate serial number to a hex string */
13874 BIGNUM *serial_bn = ASN1_INTEGER_to_BN(serial, NULL);
13875 str_serial = BN_bn2hex(serial_bn);
13876 BN_free(serial_bn);
13877
13878 /* Translate subject and issuer to a string */
13879 (void)X509_NAME_oneline(subj, str_subject, (int)sizeof(str_subject));
13880 (void)X509_NAME_oneline(iss, str_issuer, (int)sizeof(str_issuer));
13881
13882 /* Calculate SHA1 fingerprint and store as a hex string */
13883 ulen = 0;
13884
13885 /* ASN1_digest is deprecated. Do the calculation manually,
13886 * using EVP_Digest. */
13887 ilen = i2d_X509(cert, NULL);
13888 tmp_buf =
13889 (ilen > 0)
13890 ? (unsigned char *)mg_malloc_ctx((unsigned)ilen + 1, conn->ctx)
13891 : NULL;
13892 if (tmp_buf) {
13893 tmp_p = tmp_buf;
13894 (void)i2d_X509(cert, &tmp_p);
13895 if (!EVP_Digest(
13896 tmp_buf, (unsigned)ilen, buf, &ulen, digest, NULL)) {
13897 ulen = 0;
13898 }
13899 mg_free(tmp_buf);
13900 }
13901
13902 if (!hexdump2string(
13903 buf, (int)ulen, str_finger, (int)sizeof(str_finger))) {
13904 *str_finger = 0;
13905 }
13906
13907 conn->request_info.client_cert = (struct mg_client_cert *)
13908 mg_malloc_ctx(sizeof(struct mg_client_cert), conn->ctx);
13909 if (conn->request_info.client_cert) {
13910 conn->request_info.client_cert->subject = mg_strdup(str_subject);
13911 conn->request_info.client_cert->issuer = mg_strdup(str_issuer);
13912 conn->request_info.client_cert->serial = mg_strdup(str_serial);
13913 conn->request_info.client_cert->finger = mg_strdup(str_finger);
13914 } else {
13915 mg_cry(conn,
13916 "Out of memory: Cannot allocate memory for client "
13917 "certificate");
13918 }
13919
13920 /* Strings returned from bn_bn2hex must be freed using OPENSSL_free,
13921 * see https://linux.die.net/man/3/bn_bn2hex */
13922 OPENSSL_free(str_serial);
13923
13924 /* Free certificate memory */
13925 X509_free(cert);
13926 }
7c673cae
FG
13927}
13928
13929
11fdf7f2
TL
13930#ifdef OPENSSL_API_1_1
13931#else
7c673cae
FG
13932static void
13933ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
13934{
13935 (void)line;
13936 (void)file;
13937
13938 if (mode & 1) {
13939 /* 1 is CRYPTO_LOCK */
13940 (void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
13941 } else {
13942 (void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
13943 }
13944}
11fdf7f2 13945#endif /* OPENSSL_API_1_1 */
7c673cae
FG
13946
13947
13948#if !defined(NO_SSL_DL)
13949static void *
11fdf7f2 13950load_dll(char *ebuf, size_t ebuf_len, const char *dll_name, struct ssl_func *sw)
7c673cae
FG
13951{
13952 union {
13953 void *p;
13954 void (*fp)(void);
13955 } u;
13956 void *dll_handle;
13957 struct ssl_func *fp;
11fdf7f2
TL
13958 int ok;
13959 int truncated = 0;
7c673cae
FG
13960
13961 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
11fdf7f2
TL
13962 mg_snprintf(NULL,
13963 NULL, /* No truncation check for ebuf */
13964 ebuf,
13965 ebuf_len,
13966 "%s: cannot load %s",
13967 __func__,
13968 dll_name);
7c673cae
FG
13969 return NULL;
13970 }
13971
11fdf7f2 13972 ok = 1;
7c673cae
FG
13973 for (fp = sw; fp->name != NULL; fp++) {
13974#ifdef _WIN32
13975 /* GetProcAddress() returns pointer to function */
13976 u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
13977#else
13978 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
13979 * pointers to function pointers. We need to use a union to make a
13980 * cast. */
13981 u.p = dlsym(dll_handle, fp->name);
13982#endif /* _WIN32 */
13983 if (u.fp == NULL) {
11fdf7f2
TL
13984 if (ok) {
13985 mg_snprintf(NULL,
13986 &truncated,
13987 ebuf,
13988 ebuf_len,
13989 "%s: %s: cannot find %s",
13990 __func__,
13991 dll_name,
13992 fp->name);
13993 ok = 0;
13994 } else {
13995 size_t cur_len = strlen(ebuf);
13996 if (!truncated) {
13997 mg_snprintf(NULL,
13998 &truncated,
13999 ebuf + cur_len,
14000 ebuf_len - cur_len - 3,
14001 ", %s",
14002 fp->name);
14003 if (truncated) {
14004 /* If truncated, add "..." */
14005 strcat(ebuf, "...");
14006 }
14007 }
14008 }
14009 /* Debug:
14010 * printf("Missing function: %s\n", fp->name); */
7c673cae
FG
14011 } else {
14012 fp->ptr = u.fp;
14013 }
14014 }
14015
11fdf7f2
TL
14016 if (!ok) {
14017 (void)dlclose(dll_handle);
14018 return NULL;
14019 }
14020
7c673cae
FG
14021 return dll_handle;
14022}
14023
14024
14025static void *ssllib_dll_handle; /* Store the ssl library handle. */
14026static void *cryptolib_dll_handle; /* Store the crypto library handle. */
14027
14028#endif /* NO_SSL_DL */
14029
14030
14031#if defined(SSL_ALREADY_INITIALIZED)
14032static int cryptolib_users = 1; /* Reference counter for crypto library. */
14033#else
14034static int cryptolib_users = 0; /* Reference counter for crypto library. */
14035#endif
14036
14037
14038static int
11fdf7f2 14039initialize_ssl(char *ebuf, size_t ebuf_len)
7c673cae 14040{
11fdf7f2
TL
14041#ifdef OPENSSL_API_1_1
14042 if (ebuf_len > 0) {
14043 ebuf[0] = 0;
14044 }
14045
14046#if !defined(NO_SSL_DL)
14047 if (!cryptolib_dll_handle) {
14048 cryptolib_dll_handle = load_dll(ebuf, ebuf_len, CRYPTO_LIB, crypto_sw);
14049 if (!cryptolib_dll_handle) {
14050 return 0;
14051 }
14052 }
14053#endif /* NO_SSL_DL */
14054
14055 if (mg_atomic_inc(&cryptolib_users) > 1) {
14056 return 1;
14057 }
14058
14059#else /* not OPENSSL_API_1_1 */
7c673cae
FG
14060 int i;
14061 size_t size;
14062
11fdf7f2
TL
14063 if (ebuf_len > 0) {
14064 ebuf[0] = 0;
14065 }
14066
7c673cae
FG
14067#if !defined(NO_SSL_DL)
14068 if (!cryptolib_dll_handle) {
11fdf7f2 14069 cryptolib_dll_handle = load_dll(ebuf, ebuf_len, CRYPTO_LIB, crypto_sw);
7c673cae
FG
14070 if (!cryptolib_dll_handle) {
14071 return 0;
14072 }
14073 }
14074#endif /* NO_SSL_DL */
14075
14076 if (mg_atomic_inc(&cryptolib_users) > 1) {
14077 return 1;
14078 }
14079
14080 /* Initialize locking callbacks, needed for thread safety.
14081 * http://www.openssl.org/support/faq.html#PROG1
14082 */
14083 i = CRYPTO_num_locks();
14084 if (i < 0) {
14085 i = 0;
14086 }
14087 size = sizeof(pthread_mutex_t) * ((size_t)(i));
11fdf7f2
TL
14088
14089 if (size == 0) {
14090 ssl_mutexes = NULL;
14091 } else if ((ssl_mutexes = (pthread_mutex_t *)mg_malloc(size)) == NULL) {
14092 mg_snprintf(NULL,
14093 NULL, /* No truncation check for ebuf */
14094 ebuf,
14095 ebuf_len,
14096 "%s: cannot allocate mutexes: %s",
14097 __func__,
14098 ssl_error());
14099
7c673cae
FG
14100 return 0;
14101 }
14102
14103 for (i = 0; i < CRYPTO_num_locks(); i++) {
14104 pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr);
14105 }
14106
14107 CRYPTO_set_locking_callback(&ssl_locking_callback);
11fdf7f2
TL
14108 CRYPTO_set_id_callback(&mg_current_thread_id);
14109#endif /* OPENSSL_API_1_1 */
7c673cae
FG
14110
14111 return 1;
14112}
14113
14114
14115static int
11fdf7f2 14116ssl_use_pem_file(struct mg_context *ctx, const char *pem, const char *chain)
7c673cae
FG
14117{
14118 if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0) {
14119 mg_cry(fc(ctx),
14120 "%s: cannot open certificate file %s: %s",
14121 __func__,
14122 pem,
14123 ssl_error());
14124 return 0;
14125 }
14126
14127 /* could use SSL_CTX_set_default_passwd_cb_userdata */
14128 if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0) {
14129 mg_cry(fc(ctx),
14130 "%s: cannot open private key file %s: %s",
14131 __func__,
14132 pem,
14133 ssl_error());
14134 return 0;
14135 }
14136
14137 if (SSL_CTX_check_private_key(ctx->ssl_ctx) == 0) {
14138 mg_cry(fc(ctx),
14139 "%s: certificate and private key do not match: %s",
14140 __func__,
14141 pem);
14142 return 0;
14143 }
14144
11fdf7f2
TL
14145 /* In contrast to OpenSSL, wolfSSL does not support certificate
14146 * chain files that contain private keys and certificates in
14147 * SSL_CTX_use_certificate_chain_file.
14148 * The CivetWeb-Server used pem-Files that contained both information.
14149 * In order to make wolfSSL work, it is split in two files.
14150 * One file that contains key and certificate used by the server and
14151 * an optional chain file for the ssl stack.
14152 */
14153 if (chain) {
14154 if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, chain) == 0) {
14155 mg_cry(fc(ctx),
14156 "%s: cannot use certificate chain file %s: %s",
14157 __func__,
14158 pem,
14159 ssl_error());
14160 return 0;
14161 }
7c673cae
FG
14162 }
14163 return 1;
14164}
14165
14166
11fdf7f2
TL
14167#ifdef OPENSSL_API_1_1
14168static unsigned long
14169ssl_get_protocol(int version_id)
14170{
14171 long unsigned ret = SSL_OP_ALL;
14172 if (version_id > 0)
14173 ret |= SSL_OP_NO_SSLv2;
14174 if (version_id > 1)
14175 ret |= SSL_OP_NO_SSLv3;
14176 if (version_id > 2)
14177 ret |= SSL_OP_NO_TLSv1;
14178 if (version_id > 3)
14179 ret |= SSL_OP_NO_TLSv1_1;
14180 return ret;
14181}
14182#else
7c673cae
FG
14183static long
14184ssl_get_protocol(int version_id)
14185{
14186 long ret = SSL_OP_ALL;
14187 if (version_id > 0)
14188 ret |= SSL_OP_NO_SSLv2;
14189 if (version_id > 1)
14190 ret |= SSL_OP_NO_SSLv3;
14191 if (version_id > 2)
14192 ret |= SSL_OP_NO_TLSv1;
14193 if (version_id > 3)
14194 ret |= SSL_OP_NO_TLSv1_1;
14195 return ret;
14196}
11fdf7f2
TL
14197#endif /* OPENSSL_API_1_1 */
14198
14199
14200/* SSL callback documentation:
14201 * https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_info_callback.html
14202 * https://linux.die.net/man/3/ssl_set_info_callback */
14203static void
14204ssl_info_callback(SSL *ssl, int what, int ret)
14205{
14206 (void)ret;
14207
14208 if (what & SSL_CB_HANDSHAKE_START) {
14209 SSL_get_app_data(ssl);
14210 }
14211 if (what & SSL_CB_HANDSHAKE_DONE) {
14212 /* TODO: check for openSSL 1.1 */
14213 //#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001
14214 // ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
14215 }
14216}
7c673cae
FG
14217
14218
14219/* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
14220static int
14221set_ssl_option(struct mg_context *ctx)
14222{
14223 const char *pem;
11fdf7f2 14224 const char *chain;
7c673cae
FG
14225 int callback_ret;
14226 int should_verify_peer;
11fdf7f2 14227 int peer_certificate_optional;
7c673cae
FG
14228 const char *ca_path;
14229 const char *ca_file;
14230 int use_default_verify_paths;
14231 int verify_depth;
14232 time_t now_rt = time(NULL);
14233 struct timespec now_mt;
14234 md5_byte_t ssl_context_id[16];
14235 md5_state_t md5state;
14236 int protocol_ver;
11fdf7f2 14237 char ebuf[128];
7c673cae
FG
14238
14239 /* If PEM file is not specified and the init_ssl callback
14240 * is not specified, skip SSL initialization. */
14241 if (!ctx) {
14242 return 0;
14243 }
14244 if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL
14245 && ctx->callbacks.init_ssl == NULL) {
14246 return 1;
14247 }
11fdf7f2
TL
14248 chain = ctx->config[SSL_CERTIFICATE_CHAIN];
14249 if (chain == NULL) {
14250 chain = pem;
14251 }
14252 if ((chain != NULL) && (*chain == 0)) {
14253 chain = NULL;
14254 }
7c673cae 14255
11fdf7f2
TL
14256 if (!initialize_ssl(ebuf, sizeof(ebuf))) {
14257 mg_cry(fc(ctx), "%s", ebuf);
7c673cae
FG
14258 return 0;
14259 }
14260
14261#if !defined(NO_SSL_DL)
14262 if (!ssllib_dll_handle) {
11fdf7f2 14263 ssllib_dll_handle = load_dll(ebuf, sizeof(ebuf), SSL_LIB, ssl_sw);
7c673cae 14264 if (!ssllib_dll_handle) {
11fdf7f2 14265 mg_cry(fc(ctx), "%s", ebuf);
7c673cae
FG
14266 return 0;
14267 }
14268 }
14269#endif /* NO_SSL_DL */
14270
11fdf7f2
TL
14271#ifdef OPENSSL_API_1_1
14272 /* Initialize SSL library */
14273 OPENSSL_init_ssl(0, NULL);
14274 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
14275 | OPENSSL_INIT_LOAD_CRYPTO_STRINGS,
14276 NULL);
14277
14278 if ((ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
14279 mg_cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
14280 return 0;
14281 }
14282#else
7c673cae
FG
14283 /* Initialize SSL library */
14284 SSL_library_init();
14285 SSL_load_error_strings();
14286
14287 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
14288 mg_cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
14289 return 0;
14290 }
11fdf7f2 14291#endif /* OPENSSL_API_1_1 */
7c673cae
FG
14292
14293 SSL_CTX_clear_options(ctx->ssl_ctx,
14294 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1
14295 | SSL_OP_NO_TLSv1_1);
14296 protocol_ver = atoi(ctx->config[SSL_PROTOCOL_VERSION]);
14297 SSL_CTX_set_options(ctx->ssl_ctx, ssl_get_protocol(protocol_ver));
14298 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE);
11fdf7f2
TL
14299 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
14300 SSL_CTX_set_options(ctx->ssl_ctx,
14301 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
14302 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
14303#if !defined(NO_SSL_DL)
7c673cae 14304 SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1);
11fdf7f2
TL
14305#endif /* NO_SSL_DL */
14306
14307#ifdef __clang__
14308#pragma clang diagnostic push
14309#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
14310#endif
14311 /* Depending on the OpenSSL version, the callback may be
14312 * 'void (*)(SSL *, int, int)' or 'void (*)(const SSL *, int, int)'
14313 * yielding in an "incompatible-pointer-type" warning for the other
14314 * version. It seems to be "unclear" what is correct:
14315 * https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1147526
14316 * https://www.openssl.org/docs/man1.0.2/ssl/ssl.html
14317 * https://www.openssl.org/docs/man1.1.0/ssl/ssl.html
14318 * https://github.com/openssl/openssl/blob/1d97c8435171a7af575f73c526d79e1ef0ee5960/ssl/ssl.h#L1173
14319 * Disable this warning here.
14320 * Alternative would be a version dependent ssl_info_callback and
14321 * a const-cast to call 'char *SSL_get_app_data(SSL *ssl)' there.
14322 */
14323 SSL_CTX_set_info_callback(ctx->ssl_ctx, ssl_info_callback);
14324
14325#ifdef __clang__
14326#pragma clang diagnostic pop
14327#endif
7c673cae
FG
14328
14329 /* If a callback has been specified, call it. */
14330 callback_ret =
14331 (ctx->callbacks.init_ssl == NULL)
14332 ? 0
14333 : (ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data));
14334
14335 /* If callback returns 0, civetweb sets up the SSL certificate.
14336 * If it returns 1, civetweb assumes the calback already did this.
14337 * If it returns -1, initializing ssl fails. */
14338 if (callback_ret < 0) {
14339 mg_cry(fc(ctx), "SSL callback returned error: %i", callback_ret);
14340 return 0;
14341 }
14342 if (callback_ret > 0) {
14343 if (pem != NULL) {
14344 (void)SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
14345 }
14346 return 1;
14347 }
14348
14349 /* Use some UID as session context ID. */
14350 md5_init(&md5state);
14351 md5_append(&md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt));
14352 clock_gettime(CLOCK_MONOTONIC, &now_mt);
14353 md5_append(&md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt));
14354 md5_append(&md5state,
14355 (const md5_byte_t *)ctx->config[LISTENING_PORTS],
14356 strlen(ctx->config[LISTENING_PORTS]));
14357 md5_append(&md5state, (const md5_byte_t *)ctx, sizeof(*ctx));
14358 md5_finish(&md5state, ssl_context_id);
14359
14360 SSL_CTX_set_session_id_context(ctx->ssl_ctx,
14361 (const unsigned char *)&ssl_context_id,
14362 sizeof(ssl_context_id));
14363
14364 if (pem != NULL) {
11fdf7f2 14365 if (!ssl_use_pem_file(ctx, pem, chain)) {
7c673cae
FG
14366 return 0;
14367 }
14368 }
14369
11fdf7f2
TL
14370 /* Should we support client certificates? */
14371 /* Default is "no". */
14372 should_verify_peer = 0;
14373 peer_certificate_optional = 0;
14374 if (ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
14375 if (mg_strcasecmp(ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0) {
14376 /* Yes, they are mandatory */
14377 should_verify_peer = 1;
14378 peer_certificate_optional = 0;
14379 } else if (mg_strcasecmp(ctx->config[SSL_DO_VERIFY_PEER], "optional")
14380 == 0) {
14381 /* Yes, they are optional */
14382 should_verify_peer = 1;
14383 peer_certificate_optional = 1;
14384 }
14385 }
7c673cae
FG
14386
14387 use_default_verify_paths =
14388 (ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
14389 && (mg_strcasecmp(ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes") == 0);
14390
14391 if (should_verify_peer) {
14392 ca_path = ctx->config[SSL_CA_PATH];
14393 ca_file = ctx->config[SSL_CA_FILE];
14394 if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, ca_file, ca_path)
14395 != 1) {
14396 mg_cry(fc(ctx),
14397 "SSL_CTX_load_verify_locations error: %s "
14398 "ssl_verify_peer requires setting "
14399 "either ssl_ca_path or ssl_ca_file. Is any of them "
14400 "present in "
14401 "the .conf file?",
14402 ssl_error());
14403 return 0;
14404 }
14405
11fdf7f2
TL
14406 if (peer_certificate_optional) {
14407 SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
14408 } else {
14409 SSL_CTX_set_verify(ctx->ssl_ctx,
14410 SSL_VERIFY_PEER
14411 | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
14412 NULL);
14413 }
7c673cae
FG
14414
14415 if (use_default_verify_paths
11fdf7f2 14416 && (SSL_CTX_set_default_verify_paths(ctx->ssl_ctx) != 1)) {
7c673cae
FG
14417 mg_cry(fc(ctx),
14418 "SSL_CTX_set_default_verify_paths error: %s",
14419 ssl_error());
14420 return 0;
14421 }
14422
14423 if (ctx->config[SSL_VERIFY_DEPTH]) {
14424 verify_depth = atoi(ctx->config[SSL_VERIFY_DEPTH]);
14425 SSL_CTX_set_verify_depth(ctx->ssl_ctx, verify_depth);
14426 }
14427 }
14428
14429 if (ctx->config[SSL_CIPHER_LIST] != NULL) {
14430 if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config[SSL_CIPHER_LIST])
14431 != 1) {
14432 mg_cry(fc(ctx), "SSL_CTX_set_cipher_list error: %s", ssl_error());
14433 }
14434 }
14435
14436 return 1;
14437}
14438
14439
14440static void
11fdf7f2 14441uninitialize_ssl(void)
7c673cae 14442{
11fdf7f2
TL
14443#ifdef OPENSSL_API_1_1
14444
14445 if (mg_atomic_dec(&cryptolib_users) == 0) {
14446
14447 /* Shutdown according to
14448 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
14449 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
14450 */
14451 CONF_modules_unload(1);
14452#else
7c673cae 14453 int i;
7c673cae
FG
14454
14455 if (mg_atomic_dec(&cryptolib_users) == 0) {
14456
14457 /* Shutdown according to
14458 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
14459 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
14460 */
14461 CRYPTO_set_locking_callback(NULL);
14462 CRYPTO_set_id_callback(NULL);
14463 ENGINE_cleanup();
14464 CONF_modules_unload(1);
14465 ERR_free_strings();
14466 EVP_cleanup();
14467 CRYPTO_cleanup_all_ex_data();
14468 ERR_remove_state(0);
14469
14470 for (i = 0; i < CRYPTO_num_locks(); i++) {
14471 pthread_mutex_destroy(&ssl_mutexes[i]);
14472 }
14473 mg_free(ssl_mutexes);
14474 ssl_mutexes = NULL;
11fdf7f2 14475#endif /* OPENSSL_API_1_1 */
7c673cae
FG
14476 }
14477}
14478#endif /* !NO_SSL */
14479
14480
14481static int
14482set_gpass_option(struct mg_context *ctx)
14483{
14484 if (ctx) {
11fdf7f2 14485 struct mg_file file = STRUCT_FILE_INITIALIZER;
7c673cae 14486 const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
11fdf7f2 14487 if ((path != NULL) && !mg_stat(fc(ctx), path, &file.stat)) {
7c673cae
FG
14488 mg_cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
14489 return 0;
14490 }
14491 return 1;
14492 }
14493 return 0;
14494}
14495
14496
14497static int
14498set_acl_option(struct mg_context *ctx)
14499{
14500 return check_acl(ctx, (uint32_t)0x7f000001UL) != -1;
14501}
14502
14503
14504static void
14505reset_per_request_attributes(struct mg_connection *conn)
14506{
14507 if (!conn) {
14508 return;
14509 }
11fdf7f2
TL
14510 conn->connection_type =
14511 CONNECTION_TYPE_INVALID; /* Not yet a valid request/response */
14512
7c673cae 14513 conn->num_bytes_sent = conn->consumed_content = 0;
11fdf7f2
TL
14514
14515 conn->path_info = NULL;
7c673cae 14516 conn->status_code = -1;
11fdf7f2 14517 conn->content_len = -1;
7c673cae 14518 conn->is_chunked = 0;
11fdf7f2
TL
14519 conn->must_close = 0;
14520 conn->request_len = 0;
14521 conn->throttle = 0;
14522 conn->data_len = 0;
14523 conn->chunk_remainder = 0;
14524 conn->accept_gzip = 0;
14525
14526 conn->response_info.content_length = conn->request_info.content_length = -1;
14527 conn->response_info.http_version = conn->request_info.http_version = NULL;
14528 conn->response_info.num_headers = conn->request_info.num_headers = 0;
14529 conn->response_info.status_text = NULL;
14530 conn->response_info.status_code = 0;
14531
7c673cae
FG
14532 conn->request_info.remote_user = NULL;
14533 conn->request_info.request_method = NULL;
14534 conn->request_info.request_uri = NULL;
14535 conn->request_info.local_uri = NULL;
11fdf7f2
TL
14536
14537#if defined(MG_LEGACY_INTERFACE)
14538 /* Legacy before split into local_uri and request_uri */
14539 conn->request_info.uri = NULL;
14540#endif
7c673cae
FG
14541}
14542
14543
11fdf7f2
TL
14544#if 0
14545/* Note: set_sock_timeout is not required for non-blocking sockets.
14546 * Leave this function here (commented out) for reference until
14547 * CivetWeb 1.9 is tested, and the tests confirme this function is
14548 * no longer required.
14549*/
7c673cae
FG
14550static int
14551set_sock_timeout(SOCKET sock, int milliseconds)
14552{
11fdf7f2 14553 int r0 = 0, r1, r2;
7c673cae
FG
14554
14555#ifdef _WIN32
11fdf7f2 14556 /* Windows specific */
7c673cae 14557
11fdf7f2 14558 DWORD tv = (DWORD)milliseconds;
7c673cae
FG
14559
14560#else
11fdf7f2 14561 /* Linux, ... (not Windows) */
7c673cae 14562
11fdf7f2 14563 struct timeval tv;
7c673cae
FG
14564
14565/* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
14566 * max. time waiting for the acknowledged of TCP data before the connection
14567 * will be forcefully closed and ETIMEDOUT is returned to the application.
14568 * If this option is not set, the default timeout of 20-30 minutes is used.
14569*/
14570/* #define TCP_USER_TIMEOUT (18) */
14571
14572#if defined(TCP_USER_TIMEOUT)
11fdf7f2
TL
14573 unsigned int uto = (unsigned int)milliseconds;
14574 r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (const void *)&uto, sizeof(uto));
7c673cae
FG
14575#endif
14576
11fdf7f2
TL
14577 memset(&tv, 0, sizeof(tv));
14578 tv.tv_sec = milliseconds / 1000;
14579 tv.tv_usec = (milliseconds * 1000) % 1000000;
7c673cae
FG
14580
14581#endif /* _WIN32 */
14582
11fdf7f2
TL
14583 r1 = setsockopt(
14584 sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
14585 r2 = setsockopt(
14586 sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
7c673cae 14587
11fdf7f2 14588 return r0 || r1 || r2;
7c673cae 14589}
11fdf7f2 14590#endif
7c673cae
FG
14591
14592
14593static int
14594set_tcp_nodelay(SOCKET sock, int nodelay_on)
14595{
14596 if (setsockopt(sock,
14597 IPPROTO_TCP,
14598 TCP_NODELAY,
14599 (SOCK_OPT_TYPE)&nodelay_on,
14600 sizeof(nodelay_on)) != 0) {
14601 /* Error */
14602 return 1;
14603 }
14604 /* OK */
14605 return 0;
14606}
14607
14608
14609static void
14610close_socket_gracefully(struct mg_connection *conn)
14611{
14612#if defined(_WIN32)
14613 char buf[MG_BUF_LEN];
14614 int n;
14615#endif
14616 struct linger linger;
11fdf7f2
TL
14617 int error_code = 0;
14618 int linger_timeout = -2;
14619 socklen_t opt_len = sizeof(error_code);
7c673cae
FG
14620
14621 if (!conn) {
14622 return;
14623 }
14624
11fdf7f2
TL
14625 /* http://msdn.microsoft.com/en-us/library/ms739165(v=vs.85).aspx:
14626 * "Note that enabling a nonzero timeout on a nonblocking socket
14627 * is not recommended.", so set it to blocking now */
14628 set_blocking_mode(conn->client.sock);
7c673cae
FG
14629
14630 /* Send FIN to the client */
11fdf7f2
TL
14631 shutdown(conn->client.sock, SHUTDOWN_WR);
14632
7c673cae
FG
14633
14634#if defined(_WIN32)
14635 /* Read and discard pending incoming data. If we do not do that and
14636 * close
14637 * the socket, the data in the send buffer may be discarded. This
14638 * behaviour is seen on Windows, when client keeps sending data
14639 * when server decides to close the connection; then when client
14640 * does recv() it gets no data back. */
14641 do {
11fdf7f2 14642 n = pull_inner(NULL, conn, buf, sizeof(buf), /* Timeout in s: */ 1.0);
7c673cae
FG
14643 } while (n > 0);
14644#endif
14645
11fdf7f2
TL
14646 if (conn->ctx->config[LINGER_TIMEOUT]) {
14647 linger_timeout = atoi(conn->ctx->config[LINGER_TIMEOUT]);
14648 }
14649
14650 /* Set linger option according to configuration */
14651 if (linger_timeout >= 0) {
14652 /* Set linger option to avoid socket hanging out after close. This
14653 * prevent ephemeral port exhaust problem under high QPS. */
14654 linger.l_onoff = 1;
14655
14656#if defined(_MSC_VER)
14657#pragma warning(push)
14658#pragma warning(disable : 4244)
14659#endif
14660#if defined(__GNUC__) || defined(__MINGW32__)
14661#pragma GCC diagnostic push
14662#pragma GCC diagnostic ignored "-Wconversion"
14663#endif
14664 /* Data type of linger structure elements may differ,
14665 * so we don't know what cast we need here.
14666 * Disable type conversion warnings. */
14667
14668 linger.l_linger = (linger_timeout + 999) / 1000;
14669
14670#if defined(__GNUC__) || defined(__MINGW32__)
14671#pragma GCC diagnostic pop
14672#endif
14673#if defined(_MSC_VER)
14674#pragma warning(pop)
14675#endif
14676
14677 } else {
14678 linger.l_onoff = 0;
14679 linger.l_linger = 0;
14680 }
14681
14682 if (linger_timeout < -1) {
14683 /* Default: don't configure any linger */
14684 } else if (getsockopt(conn->client.sock,
14685 SOL_SOCKET,
14686 SO_ERROR,
14687 (char *)&error_code,
14688 &opt_len) != 0) {
14689 /* Cannot determine if socket is already closed. This should
14690 * not occur and never did in a test. Log an error message
14691 * and continue. */
14692 mg_cry(conn,
14693 "%s: getsockopt(SOL_SOCKET SO_ERROR) failed: %s",
14694 __func__,
14695 strerror(ERRNO));
14696 } else if (error_code == ECONNRESET) {
14697 /* Socket already closed by client/peer, close socket without linger
14698 */
14699 } else {
14700
14701 /* Set linger timeout */
14702 if (setsockopt(conn->client.sock,
14703 SOL_SOCKET,
14704 SO_LINGER,
14705 (char *)&linger,
14706 sizeof(linger)) != 0) {
14707 mg_cry(conn,
14708 "%s: setsockopt(SOL_SOCKET SO_LINGER(%i,%i)) failed: %s",
14709 __func__,
14710 linger.l_onoff,
14711 linger.l_linger,
14712 strerror(ERRNO));
14713 }
14714 }
14715
7c673cae
FG
14716 /* Now we know that our FIN is ACK-ed, safe to close */
14717 closesocket(conn->client.sock);
14718 conn->client.sock = INVALID_SOCKET;
14719}
14720
14721
14722static void
14723close_connection(struct mg_connection *conn)
14724{
11fdf7f2
TL
14725#if defined(USE_SERVER_STATS)
14726 conn->conn_state = 6; /* to close */
14727#endif
7c673cae
FG
14728
14729#if defined(USE_LUA) && defined(USE_WEBSOCKET)
14730 if (conn->lua_websocket_state) {
14731 lua_websocket_close(conn, conn->lua_websocket_state);
14732 conn->lua_websocket_state = NULL;
14733 }
14734#endif
14735
11fdf7f2
TL
14736 mg_lock_connection(conn);
14737
14738 /* Set close flag, so keep-alive loops will stop */
14739 conn->must_close = 1;
14740
7c673cae 14741 /* call the connection_close callback if assigned */
11fdf7f2
TL
14742 if (conn->ctx->callbacks.connection_close != NULL) {
14743 if (conn->ctx->context_type == CONTEXT_SERVER) {
14744 conn->ctx->callbacks.connection_close(conn);
14745 }
7c673cae
FG
14746 }
14747
11fdf7f2
TL
14748 /* Reset user data, after close callback is called.
14749 * Do not reuse it. If the user needs a destructor,
14750 * it must be done in the connection_close callback. */
14751 mg_set_user_connection_data(conn, NULL);
7c673cae 14752
11fdf7f2
TL
14753
14754#if defined(USE_SERVER_STATS)
14755 conn->conn_state = 7; /* closing */
14756#endif
7c673cae
FG
14757
14758#ifndef NO_SSL
14759 if (conn->ssl != NULL) {
14760 /* Run SSL_shutdown twice to ensure completly close SSL connection
14761 */
14762 SSL_shutdown(conn->ssl);
14763 SSL_free(conn->ssl);
11fdf7f2
TL
14764/* Avoid CRYPTO_cleanup_all_ex_data(); See discussion:
14765 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
14766#ifndef OPENSSL_API_1_1
7c673cae 14767 ERR_remove_state(0);
11fdf7f2 14768#endif
7c673cae
FG
14769 conn->ssl = NULL;
14770 }
14771#endif
14772 if (conn->client.sock != INVALID_SOCKET) {
14773 close_socket_gracefully(conn);
14774 conn->client.sock = INVALID_SOCKET;
14775 }
14776
14777 mg_unlock_connection(conn);
11fdf7f2
TL
14778
14779#if defined(USE_SERVER_STATS)
14780 conn->conn_state = 8; /* closed */
14781#endif
7c673cae
FG
14782}
14783
11fdf7f2 14784
7c673cae
FG
14785void
14786mg_close_connection(struct mg_connection *conn)
14787{
11fdf7f2 14788#if defined(USE_WEBSOCKET)
7c673cae 14789 struct mg_context *client_ctx = NULL;
11fdf7f2 14790#endif /* defined(USE_WEBSOCKET) */
7c673cae 14791
11fdf7f2 14792 if ((conn == NULL) || (conn->ctx == NULL)) {
7c673cae
FG
14793 return;
14794 }
14795
11fdf7f2
TL
14796#if defined(USE_WEBSOCKET)
14797 if (conn->ctx->context_type == CONTEXT_SERVER) {
14798 if (conn->in_websocket_handling) {
14799 /* Set close flag, so the server thread can exit. */
14800 conn->must_close = 1;
14801 return;
14802 }
14803 }
14804 if (conn->ctx->context_type == CONTEXT_WS_CLIENT) {
14805
14806 unsigned int i;
14807
14808 /* ws/wss client */
7c673cae 14809 client_ctx = conn->ctx;
11fdf7f2 14810
7c673cae
FG
14811 /* client context: loops must end */
14812 conn->ctx->stop_flag = 1;
11fdf7f2
TL
14813 conn->must_close = 1;
14814
14815 /* We need to get the client thread out of the select/recv call
14816 * here. */
14817 /* Since we use a sleep quantum of some seconds to check for recv
14818 * timeouts, we will just wait a few seconds in mg_join_thread. */
14819
14820 /* join worker thread */
14821 for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
14822 if (client_ctx->worker_threadids[i] != 0) {
14823 mg_join_thread(client_ctx->worker_threadids[i]);
14824 }
14825 }
7c673cae 14826 }
11fdf7f2
TL
14827#endif /* defined(USE_WEBSOCKET) */
14828
14829 close_connection(conn);
7c673cae
FG
14830
14831#ifndef NO_SSL
14832 if (conn->client_ssl_ctx != NULL) {
14833 SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx);
14834 }
14835#endif
11fdf7f2
TL
14836
14837#if defined(USE_WEBSOCKET)
7c673cae 14838 if (client_ctx != NULL) {
11fdf7f2
TL
14839 /* free context */
14840 mg_free(client_ctx->worker_threadids);
7c673cae
FG
14841 mg_free(client_ctx);
14842 (void)pthread_mutex_destroy(&conn->mutex);
14843 mg_free(conn);
11fdf7f2
TL
14844 } else if (conn->ctx->context_type == CONTEXT_HTTP_CLIENT) {
14845 mg_free(conn);
7c673cae 14846 }
11fdf7f2
TL
14847#else
14848 if (conn->ctx->context_type == CONTEXT_HTTP_CLIENT) { /* Client */
14849 mg_free(conn);
14850 }
14851#endif /* defined(USE_WEBSOCKET) */
7c673cae
FG
14852}
14853
14854
11fdf7f2
TL
14855/* Only for memory statistics */
14856static struct mg_context common_client_context;
14857
14858
7c673cae
FG
14859static struct mg_connection *
14860mg_connect_client_impl(const struct mg_client_options *client_options,
14861 int use_ssl,
14862 char *ebuf,
14863 size_t ebuf_len)
14864{
7c673cae
FG
14865 struct mg_connection *conn = NULL;
14866 SOCKET sock;
14867 union usa sa;
11fdf7f2
TL
14868 struct sockaddr *psa;
14869 socklen_t len;
14870
14871 unsigned max_req_size =
14872 (unsigned)atoi(config_options[MAX_REQUEST_SIZE].default_value);
14873
14874 /* Size of structures, aligned to 8 bytes */
14875 size_t conn_size = ((sizeof(struct mg_connection) + 7) >> 3) << 3;
14876 size_t ctx_size = ((sizeof(struct mg_context) + 7) >> 3) << 3;
14877
14878 conn = (struct mg_connection *)mg_calloc_ctx(1,
14879 conn_size + ctx_size
14880 + max_req_size,
14881 &common_client_context);
14882
14883 if (conn == NULL) {
14884 mg_snprintf(NULL,
14885 NULL, /* No truncation check for ebuf */
14886 ebuf,
14887 ebuf_len,
14888 "calloc(): %s",
14889 strerror(ERRNO));
14890 return NULL;
14891 }
14892
14893 conn->ctx = (struct mg_context *)(((char *)conn) + conn_size);
14894 conn->buf = (((char *)conn) + conn_size + ctx_size);
14895 conn->buf_size = (int)max_req_size;
14896 conn->ctx->context_type = CONTEXT_HTTP_CLIENT;
7c673cae 14897
11fdf7f2 14898 if (!connect_socket(&common_client_context,
7c673cae
FG
14899 client_options->host,
14900 client_options->port,
14901 use_ssl,
14902 ebuf,
14903 ebuf_len,
14904 &sock,
14905 &sa)) {
11fdf7f2
TL
14906 /* ebuf is set by connect_socket,
14907 * free all memory and return NULL; */
14908 mg_free(conn);
14909 return NULL;
14910 }
14911
14912#ifndef NO_SSL
14913#ifdef OPENSSL_API_1_1
14914 if (use_ssl
14915 && (conn->client_ssl_ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
7c673cae
FG
14916 mg_snprintf(NULL,
14917 NULL, /* No truncation check for ebuf */
14918 ebuf,
14919 ebuf_len,
11fdf7f2 14920 "SSL_CTX_new error");
7c673cae 14921 closesocket(sock);
11fdf7f2
TL
14922 mg_free(conn);
14923 return NULL;
14924 }
14925#else
14926 if (use_ssl
14927 && (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
14928 == NULL) {
7c673cae
FG
14929 mg_snprintf(NULL,
14930 NULL, /* No truncation check for ebuf */
14931 ebuf,
14932 ebuf_len,
14933 "SSL_CTX_new error");
14934 closesocket(sock);
14935 mg_free(conn);
11fdf7f2
TL
14936 return NULL;
14937 }
14938#endif /* OPENSSL_API_1_1 */
7c673cae
FG
14939#endif /* NO_SSL */
14940
7c673cae
FG
14941
14942#ifdef USE_IPV6
11fdf7f2
TL
14943 len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin)
14944 : sizeof(conn->client.rsa.sin6);
14945 psa = (sa.sa.sa_family == AF_INET)
14946 ? (struct sockaddr *)&(conn->client.rsa.sin)
14947 : (struct sockaddr *)&(conn->client.rsa.sin6);
7c673cae 14948#else
11fdf7f2
TL
14949 len = sizeof(conn->client.rsa.sin);
14950 psa = (struct sockaddr *)&(conn->client.rsa.sin);
7c673cae
FG
14951#endif
14952
11fdf7f2
TL
14953 conn->client.sock = sock;
14954 conn->client.lsa = sa;
7c673cae 14955
11fdf7f2
TL
14956 if (getsockname(sock, psa, &len) != 0) {
14957 mg_cry(conn, "%s: getsockname() failed: %s", __func__, strerror(ERRNO));
14958 }
7c673cae 14959
11fdf7f2
TL
14960 conn->client.is_ssl = use_ssl ? 1 : 0;
14961 (void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
7c673cae
FG
14962
14963#ifndef NO_SSL
11fdf7f2
TL
14964 if (use_ssl) {
14965 common_client_context.ssl_ctx = conn->client_ssl_ctx;
14966
14967 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
14968 * SSL_CTX_set_verify call is needed to switch off server
14969 * certificate checking, which is off by default in OpenSSL and
14970 * on in yaSSL. */
14971 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
14972 * SSL_VERIFY_PEER, verify_ssl_server); */
14973
14974 if (client_options->client_cert) {
14975 if (!ssl_use_pem_file(&common_client_context,
14976 client_options->client_cert,
14977 NULL)) {
7c673cae
FG
14978 mg_snprintf(NULL,
14979 NULL, /* No truncation check for ebuf */
14980 ebuf,
14981 ebuf_len,
11fdf7f2 14982 "Can not use SSL client certificate");
7c673cae
FG
14983 SSL_CTX_free(conn->client_ssl_ctx);
14984 closesocket(sock);
14985 mg_free(conn);
11fdf7f2 14986 return NULL;
7c673cae
FG
14987 }
14988 }
7c673cae 14989
11fdf7f2
TL
14990 if (client_options->server_cert) {
14991 SSL_CTX_load_verify_locations(conn->client_ssl_ctx,
14992 client_options->server_cert,
14993 NULL);
14994 SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_PEER, NULL);
14995 } else {
14996 SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_NONE, NULL);
14997 }
7c673cae 14998
11fdf7f2
TL
14999 if (!sslize(conn,
15000 conn->client_ssl_ctx,
15001 SSL_connect,
15002 &(conn->ctx->stop_flag))) {
15003 mg_snprintf(NULL,
15004 NULL, /* No truncation check for ebuf */
15005 ebuf,
15006 ebuf_len,
15007 "SSL connection error");
15008 SSL_CTX_free(conn->client_ssl_ctx);
15009 closesocket(sock);
15010 mg_free(conn);
15011 return NULL;
15012 }
15013 }
15014#endif
15015
15016 if (0 != set_non_blocking_mode(sock)) {
15017 /* TODO: handle error */
15018 ;
15019 }
15020
15021 return conn;
15022}
15023
15024
15025CIVETWEB_API struct mg_connection *
15026mg_connect_client_secure(const struct mg_client_options *client_options,
15027 char *error_buffer,
15028 size_t error_buffer_size)
15029{
7c673cae
FG
15030 return mg_connect_client_impl(client_options,
15031 1,
15032 error_buffer,
15033 error_buffer_size);
15034}
15035
15036
15037struct mg_connection *
15038mg_connect_client(const char *host,
15039 int port,
15040 int use_ssl,
15041 char *error_buffer,
15042 size_t error_buffer_size)
15043{
15044 struct mg_client_options opts;
15045 memset(&opts, 0, sizeof(opts));
15046 opts.host = host;
15047 opts.port = port;
15048 return mg_connect_client_impl(&opts,
15049 use_ssl,
15050 error_buffer,
15051 error_buffer_size);
15052}
15053
15054
15055static const struct {
15056 const char *proto;
15057 size_t proto_len;
15058 unsigned default_port;
15059} abs_uri_protocols[] = {{"http://", 7, 80},
15060 {"https://", 8, 443},
15061 {"ws://", 5, 80},
15062 {"wss://", 6, 443},
15063 {NULL, 0, 0}};
15064
15065
15066/* Check if the uri is valid.
15067 * return 0 for invalid uri,
15068 * return 1 for *,
15069 * return 2 for relative uri,
15070 * return 3 for absolute uri without port,
15071 * return 4 for absolute uri with port */
15072static int
11fdf7f2 15073get_uri_type(const char *uri, int allow_unicode)
7c673cae
FG
15074{
15075 int i;
11fdf7f2
TL
15076 const char *hostend, *portbegin;
15077 char *portend;
7c673cae
FG
15078 unsigned long port;
15079
15080 /* According to the HTTP standard
15081 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
15082 * URI can be an asterisk (*) or should start with slash (relative uri),
15083 * or it should start with the protocol (absolute uri). */
11fdf7f2 15084 if ((uri[0] == '*') && (uri[1] == '\0')) {
7c673cae
FG
15085 /* asterisk */
15086 return 1;
15087 }
11fdf7f2
TL
15088
15089 /* Valid URIs according to RFC 3986
15090 * (https://www.ietf.org/rfc/rfc3986.txt)
15091 * must only contain reserved characters :/?#[]@!$&'()*+,;=
15092 * and unreserved characters A-Z a-z 0-9 and -._~
15093 * and % encoded symbols.
15094 */
15095 /* (downstream): don't validate urls at all, RGW parses them and can return
15096 *the relevant error codes if invalid
15097 */
15098 if (!allow_unicode) {
15099 for (i = 0; uri[i] != 0; i++) {
15100 if (uri[i] < 33) {
15101 /* control characters and spaces are invalid */
15102 return 0;
15103 }
15104 if (uri[i] > 126) {
15105 /* non-ascii characters must be % encoded */
15106 return 0;
15107 } else {
15108 switch (uri[i]) {
15109 case '"': /* 34 */
15110 case '<': /* 60 */
15111 case '>': /* 62 */
15112 case '\\': /* 92 */
15113 case '^': /* 94 */
15114 case '`': /* 96 */
15115 case '{': /* 123 */
15116 case '|': /* 124 */
15117 case '}': /* 125 */
15118 return 0;
15119 default:
15120 /* character is ok */
15121 break;
15122 }
15123 }
15124 }
15125 }
15126
15127 /* A relative uri starts with a / character */
7c673cae
FG
15128 if (uri[0] == '/') {
15129 /* relative uri */
15130 return 2;
15131 }
15132
15133 /* It could be an absolute uri: */
15134 /* This function only checks if the uri is valid, not if it is
15135 * addressing the current server. So civetweb can also be used
15136 * as a proxy server. */
15137 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
15138 if (mg_strncasecmp(uri,
15139 abs_uri_protocols[i].proto,
15140 abs_uri_protocols[i].proto_len) == 0) {
15141
15142 hostend = strchr(uri + abs_uri_protocols[i].proto_len, '/');
15143 if (!hostend) {
15144 return 0;
15145 }
15146 portbegin = strchr(uri + abs_uri_protocols[i].proto_len, ':');
15147 if (!portbegin) {
15148 return 3;
15149 }
15150
15151 port = strtoul(portbegin + 1, &portend, 10);
11fdf7f2 15152 if ((portend != hostend) || (port <= 0) || !is_valid_port(port)) {
7c673cae
FG
15153 return 0;
15154 }
15155
15156 return 4;
15157 }
15158 }
15159
15160 return 0;
15161}
15162
15163
15164/* Return NULL or the relative uri at the current server */
15165static const char *
15166get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
15167{
15168 const char *server_domain;
15169 size_t server_domain_len;
15170 size_t request_domain_len = 0;
15171 unsigned long port = 0;
31f18b77 15172 int i, auth_domain_check_enabled;
7c673cae
FG
15173 const char *hostbegin = NULL;
15174 const char *hostend = NULL;
15175 const char *portbegin;
15176 char *portend;
15177
31f18b77 15178 auth_domain_check_enabled =
11fdf7f2
TL
15179 !mg_strcasecmp(conn->ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes");
15180
7c673cae
FG
15181 /* DNS is case insensitive, so use case insensitive string compare here
15182 */
7c673cae
FG
15183 for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
15184 if (mg_strncasecmp(uri,
15185 abs_uri_protocols[i].proto,
15186 abs_uri_protocols[i].proto_len) == 0) {
15187
15188 hostbegin = uri + abs_uri_protocols[i].proto_len;
15189 hostend = strchr(hostbegin, '/');
15190 if (!hostend) {
15191 return 0;
15192 }
15193 portbegin = strchr(hostbegin, ':');
15194 if ((!portbegin) || (portbegin > hostend)) {
15195 port = abs_uri_protocols[i].default_port;
15196 request_domain_len = (size_t)(hostend - hostbegin);
15197 } else {
15198 port = strtoul(portbegin + 1, &portend, 10);
11fdf7f2
TL
15199 if ((portend != hostend) || (port <= 0)
15200 || !is_valid_port(port)) {
7c673cae
FG
15201 return 0;
15202 }
15203 request_domain_len = (size_t)(portbegin - hostbegin);
15204 }
15205 /* protocol found, port set */
15206 break;
15207 }
15208 }
15209
15210 if (!port) {
15211 /* port remains 0 if the protocol is not found */
15212 return 0;
15213 }
15214
31f18b77
FG
15215/* Check if the request is directed to a different server. */
15216/* First check if the port is the same (IPv4 and IPv6). */
7c673cae
FG
15217#if defined(USE_IPV6)
15218 if (conn->client.lsa.sa.sa_family == AF_INET6) {
15219 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
15220 /* Request is directed to a different port */
15221 return 0;
15222 }
15223 } else
15224#endif
15225 {
15226 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
15227 /* Request is directed to a different port */
15228 return 0;
15229 }
15230 }
15231
31f18b77
FG
15232 /* Finally check if the server corresponds to the authentication
15233 * domain of the server (the server domain).
15234 * Allow full matches (like http://mydomain.com/path/file.ext), and
15235 * allow subdomain matches (like http://www.mydomain.com/path/file.ext),
11fdf7f2
TL
15236 * but do not allow substrings (like
15237 * http://notmydomain.com/path/file.ext
31f18b77
FG
15238 * or http://mydomain.com.fake/path/file.ext).
15239 */
15240 if (auth_domain_check_enabled) {
11fdf7f2
TL
15241 server_domain = conn->ctx->config[AUTHENTICATION_DOMAIN];
15242 server_domain_len = strlen(server_domain);
15243 if (!server_domain_len) {
15244 return 0;
15245 }
31f18b77 15246 if ((request_domain_len == server_domain_len)
11fdf7f2 15247 && (!memcmp(server_domain, hostbegin, server_domain_len))) {
31f18b77
FG
15248 /* Request is directed to this server - full name match. */
15249 } else {
15250 if (request_domain_len < (server_domain_len + 2)) {
11fdf7f2
TL
15251 /* Request is directed to another server: The server name is
15252 * longer
31f18b77 15253 * than
11fdf7f2
TL
15254 * the request name. Drop this case here to avoid overflows
15255 * in
15256 * the
31f18b77
FG
15257 * following checks. */
15258 return 0;
15259 }
15260 if (hostbegin[request_domain_len - server_domain_len - 1] != '.') {
11fdf7f2
TL
15261 /* Request is directed to another server: It could be a
15262 * substring
31f18b77
FG
15263 * like notmyserver.com */
15264 return 0;
15265 }
15266 if (0 != memcmp(server_domain,
11fdf7f2
TL
15267 hostbegin + request_domain_len - server_domain_len,
15268 server_domain_len)) {
31f18b77
FG
15269 /* Request is directed to another server:
15270 * The server name is different. */
15271 return 0;
15272 }
15273 }
7c673cae
FG
15274 }
15275
15276 return hostend;
15277}
15278
15279
15280static int
11fdf7f2 15281get_message(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
7c673cae 15282{
7c673cae
FG
15283 if (ebuf_len > 0) {
15284 ebuf[0] = '\0';
15285 }
15286 *err = 0;
15287
15288 reset_per_request_attributes(conn);
15289
15290 if (!conn) {
15291 mg_snprintf(conn,
15292 NULL, /* No truncation check for ebuf */
15293 ebuf,
15294 ebuf_len,
15295 "%s",
15296 "Internal error");
15297 *err = 500;
15298 return 0;
15299 }
15300 /* Set the time the request was received. This value should be used for
15301 * timeouts. */
15302 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
15303
15304 conn->request_len =
11fdf7f2 15305 read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
7c673cae
FG
15306 /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
15307 */
11fdf7f2 15308 if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) {
7c673cae
FG
15309 mg_snprintf(conn,
15310 NULL, /* No truncation check for ebuf */
15311 ebuf,
15312 ebuf_len,
15313 "%s",
11fdf7f2 15314 "Invalid message size");
7c673cae
FG
15315 *err = 500;
15316 return 0;
15317 }
15318
11fdf7f2 15319 if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) {
7c673cae
FG
15320 mg_snprintf(conn,
15321 NULL, /* No truncation check for ebuf */
15322 ebuf,
15323 ebuf_len,
15324 "%s",
11fdf7f2 15325 "Message too large");
7c673cae
FG
15326 *err = 413;
15327 return 0;
11fdf7f2
TL
15328 }
15329
15330 if (conn->request_len <= 0) {
7c673cae
FG
15331 if (conn->data_len > 0) {
15332 mg_snprintf(conn,
15333 NULL, /* No truncation check for ebuf */
15334 ebuf,
15335 ebuf_len,
15336 "%s",
11fdf7f2 15337 "Malformed message");
7c673cae
FG
15338 *err = 400;
15339 } else {
11fdf7f2 15340 /* Server did not recv anything -> just close the connection */
7c673cae
FG
15341 conn->must_close = 1;
15342 mg_snprintf(conn,
15343 NULL, /* No truncation check for ebuf */
15344 ebuf,
15345 ebuf_len,
15346 "%s",
11fdf7f2 15347 "No data received");
7c673cae
FG
15348 *err = 0;
15349 }
15350 return 0;
11fdf7f2
TL
15351 }
15352 return 1;
15353}
15354
15355static int should_validate_http_method(const struct mg_connection *conn)
15356{
15357 if (!conn || !conn->ctx || !conn->ctx->config[VALIDATE_HTTP_METHOD]) {
15358 return 1;
15359 }
15360
15361 return (mg_strcasecmp(conn->ctx->config[VALIDATE_HTTP_METHOD], "yes") == 0);
15362}
15363
15364static int
15365get_request(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
15366{
15367 const char *cl;
15368 if (!get_message(conn, ebuf, ebuf_len, err)) {
15369 return 0;
15370 }
15371
15372 int check_method = should_validate_http_method(conn);
15373 if (parse_http_request(check_method, conn->buf, conn->buf_size, &conn->request_info)
15374 <= 0) {
7c673cae
FG
15375 mg_snprintf(conn,
15376 NULL, /* No truncation check for ebuf */
15377 ebuf,
15378 ebuf_len,
15379 "%s",
11fdf7f2 15380 "Bad request");
7c673cae
FG
15381 *err = 400;
15382 return 0;
11fdf7f2
TL
15383 }
15384
15385 /* Message is a valid request */
15386 if ((cl = get_header(conn->request_info.http_headers,
15387 conn->request_info.num_headers,
15388 "Content-Length")) != NULL) {
15389 /* Request/response has content length set */
15390 char *endptr = NULL;
15391 conn->content_len = strtoll(cl, &endptr, 10);
15392 if (endptr == cl) {
15393 mg_snprintf(conn,
15394 NULL, /* No truncation check for ebuf */
15395 ebuf,
15396 ebuf_len,
15397 "%s",
15398 "Bad request");
15399 *err = 400;
15400 return 0;
15401 }
15402 /* Publish the content length back to the request info. */
15403 conn->request_info.content_length = conn->content_len;
15404 } else if ((cl = get_header(conn->request_info.http_headers,
15405 conn->request_info.num_headers,
15406 "Transfer-Encoding")) != NULL
15407 && !mg_strcasecmp(cl, "chunked")) {
15408 conn->is_chunked = 1;
15409 conn->content_len = -1; /* unknown content length */
15410 } else if (get_http_method_info(conn->request_info.request_method)
15411 ->request_has_body) {
15412 /* POST or PUT request without content length set */
15413 conn->content_len = -1; /* unknown content length */
7c673cae 15414 } else {
11fdf7f2
TL
15415 /* Other request */
15416 conn->content_len = 0; /* No content */
15417 }
15418
15419 conn->connection_type = CONNECTION_TYPE_REQUEST; /* Valid request */
15420 return 1;
15421}
15422
15423
15424/* conn is assumed to be valid in this internal function */
15425static int
15426get_response(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
15427{
15428 const char *cl;
15429 if (!get_message(conn, ebuf, ebuf_len, err)) {
15430 return 0;
15431 }
15432
15433 if (parse_http_response(conn->buf, conn->buf_size, &conn->response_info)
15434 <= 0) {
15435 mg_snprintf(conn,
15436 NULL, /* No truncation check for ebuf */
15437 ebuf,
15438 ebuf_len,
15439 "%s",
15440 "Bad response");
15441 *err = 400;
15442 return 0;
15443 }
15444
15445 /* Message is a valid response */
15446 if ((cl = get_header(conn->response_info.http_headers,
15447 conn->response_info.num_headers,
15448 "Content-Length")) != NULL) {
15449 /* Request/response has content length set */
15450 char *endptr = NULL;
15451 conn->content_len = strtoll(cl, &endptr, 10);
15452 if (endptr == cl) {
15453 mg_snprintf(conn,
15454 NULL, /* No truncation check for ebuf */
15455 ebuf,
15456 ebuf_len,
15457 "%s",
15458 "Bad request");
15459 *err = 400;
15460 return 0;
7c673cae 15461 }
11fdf7f2
TL
15462 /* Publish the content length back to the response info. */
15463 conn->response_info.content_length = conn->content_len;
15464
15465 /* TODO: check if it is still used in response_info */
15466 conn->request_info.content_length = conn->content_len;
15467
15468 } else if ((cl = get_header(conn->response_info.http_headers,
15469 conn->response_info.num_headers,
15470 "Transfer-Encoding")) != NULL
15471 && !mg_strcasecmp(cl, "chunked")) {
15472 conn->is_chunked = 1;
15473 conn->content_len = -1; /* unknown content length */
15474 } else {
15475 conn->content_len = -1; /* unknown content length */
7c673cae 15476 }
11fdf7f2
TL
15477
15478 conn->connection_type = CONNECTION_TYPE_RESPONSE; /* Valid response */
7c673cae
FG
15479 return 1;
15480}
15481
15482
15483int
15484mg_get_response(struct mg_connection *conn,
15485 char *ebuf,
15486 size_t ebuf_len,
15487 int timeout)
15488{
11fdf7f2
TL
15489 int err, ret;
15490 char txt[32]; /* will not overflow */
15491 struct mg_context *octx;
15492 struct mg_context rctx;
7c673cae 15493
11fdf7f2
TL
15494 if (ebuf_len > 0) {
15495 ebuf[0] = '\0';
15496 }
15497
15498 if (!conn) {
15499 mg_snprintf(conn,
15500 NULL, /* No truncation check for ebuf */
15501 ebuf,
15502 ebuf_len,
15503 "%s",
15504 "Parameter error");
15505 return -1;
15506 }
7c673cae 15507
11fdf7f2
TL
15508 /* Implementation of API function for HTTP clients */
15509 octx = conn->ctx;
15510 rctx = *(conn->ctx);
7c673cae 15511
11fdf7f2
TL
15512 if (timeout >= 0) {
15513 mg_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout);
15514 rctx.config[REQUEST_TIMEOUT] = txt;
15515 /* Not required for non-blocking sockets.
15516 set_sock_timeout(conn->client.sock, timeout);
15517 */
15518 } else {
15519 rctx.config[REQUEST_TIMEOUT] = NULL;
7c673cae 15520 }
11fdf7f2
TL
15521
15522 conn->ctx = &rctx;
15523 ret = get_response(conn, ebuf, ebuf_len, &err);
15524 conn->ctx = octx;
15525
15526#if defined(MG_LEGACY_INTERFACE)
15527 /* TODO: 1) uri is deprecated;
15528 * 2) here, ri.uri is the http response code */
15529 conn->request_info.uri = conn->request_info.request_uri;
15530#endif
15531 conn->request_info.local_uri = conn->request_info.request_uri;
15532
15533 /* TODO (mid): Define proper return values - maybe return length?
15534 * For the first test use <0 for error and >0 for OK */
15535 return (ret == 0) ? -1 : +1;
7c673cae
FG
15536}
15537
15538
15539struct mg_connection *
15540mg_download(const char *host,
15541 int port,
15542 int use_ssl,
15543 char *ebuf,
15544 size_t ebuf_len,
15545 const char *fmt,
15546 ...)
15547{
15548 struct mg_connection *conn;
15549 va_list ap;
15550 int i;
15551 int reqerr;
15552
11fdf7f2
TL
15553 if (ebuf_len > 0) {
15554 ebuf[0] = '\0';
15555 }
15556
7c673cae 15557 va_start(ap, fmt);
7c673cae
FG
15558
15559 /* open a connection */
15560 conn = mg_connect_client(host, port, use_ssl, ebuf, ebuf_len);
15561
15562 if (conn != NULL) {
15563 i = mg_vprintf(conn, fmt, ap);
15564 if (i <= 0) {
15565 mg_snprintf(conn,
15566 NULL, /* No truncation check for ebuf */
15567 ebuf,
15568 ebuf_len,
15569 "%s",
15570 "Error sending request");
15571 } else {
11fdf7f2 15572 get_response(conn, ebuf, ebuf_len, &reqerr);
7c673cae 15573
11fdf7f2 15574#if defined(MG_LEGACY_INTERFACE)
7c673cae
FG
15575 /* TODO: 1) uri is deprecated;
15576 * 2) here, ri.uri is the http response code */
15577 conn->request_info.uri = conn->request_info.request_uri;
11fdf7f2
TL
15578#endif
15579 conn->request_info.local_uri = conn->request_info.request_uri;
7c673cae
FG
15580 }
15581 }
15582
15583 /* if an error occured, close the connection */
11fdf7f2 15584 if ((ebuf[0] != '\0') && (conn != NULL)) {
7c673cae
FG
15585 mg_close_connection(conn);
15586 conn = NULL;
15587 }
15588
15589 va_end(ap);
15590 return conn;
15591}
15592
15593
15594struct websocket_client_thread_data {
15595 struct mg_connection *conn;
15596 mg_websocket_data_handler data_handler;
15597 mg_websocket_close_handler close_handler;
15598 void *callback_data;
15599};
15600
15601
15602#if defined(USE_WEBSOCKET)
15603#ifdef _WIN32
15604static unsigned __stdcall websocket_client_thread(void *data)
15605#else
15606static void *
15607websocket_client_thread(void *data)
15608#endif
15609{
15610 struct websocket_client_thread_data *cdata =
15611 (struct websocket_client_thread_data *)data;
15612
11fdf7f2 15613 mg_set_thread_name("ws-clnt");
7c673cae
FG
15614
15615 if (cdata->conn->ctx) {
15616 if (cdata->conn->ctx->callbacks.init_thread) {
15617 /* 3 indicates a websocket client thread */
15618 /* TODO: check if conn->ctx can be set */
15619 cdata->conn->ctx->callbacks.init_thread(cdata->conn->ctx, 3);
15620 }
15621 }
15622
15623 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
15624
15625 DEBUG_TRACE("%s", "Websocket client thread exited\n");
15626
15627 if (cdata->close_handler != NULL) {
15628 cdata->close_handler(cdata->conn, cdata->callback_data);
15629 }
15630
11fdf7f2
TL
15631 /* The websocket_client context has only this thread. If it runs out,
15632 set the stop_flag to 2 (= "stopped"). */
15633 cdata->conn->ctx->stop_flag = 2;
15634
7c673cae
FG
15635 mg_free((void *)cdata);
15636
15637#ifdef _WIN32
15638 return 0;
15639#else
15640 return NULL;
15641#endif
15642}
15643#endif
15644
15645
15646struct mg_connection *
15647mg_connect_websocket_client(const char *host,
15648 int port,
15649 int use_ssl,
15650 char *error_buffer,
15651 size_t error_buffer_size,
15652 const char *path,
15653 const char *origin,
15654 mg_websocket_data_handler data_func,
15655 mg_websocket_close_handler close_func,
15656 void *user_data)
15657{
15658 struct mg_connection *conn = NULL;
15659
15660#if defined(USE_WEBSOCKET)
15661 struct mg_context *newctx = NULL;
15662 struct websocket_client_thread_data *thread_data;
15663 static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
15664 static const char *handshake_req;
15665
15666 if (origin != NULL) {
15667 handshake_req = "GET %s HTTP/1.1\r\n"
15668 "Host: %s\r\n"
15669 "Upgrade: websocket\r\n"
15670 "Connection: Upgrade\r\n"
15671 "Sec-WebSocket-Key: %s\r\n"
15672 "Sec-WebSocket-Version: 13\r\n"
15673 "Origin: %s\r\n"
15674 "\r\n";
15675 } else {
15676 handshake_req = "GET %s HTTP/1.1\r\n"
15677 "Host: %s\r\n"
15678 "Upgrade: websocket\r\n"
15679 "Connection: Upgrade\r\n"
15680 "Sec-WebSocket-Key: %s\r\n"
15681 "Sec-WebSocket-Version: 13\r\n"
15682 "\r\n";
15683 }
15684
15685 /* Establish the client connection and request upgrade */
15686 conn = mg_download(host,
15687 port,
15688 use_ssl,
15689 error_buffer,
15690 error_buffer_size,
15691 handshake_req,
15692 path,
15693 host,
15694 magic,
15695 origin);
15696
15697 /* Connection object will be null if something goes wrong */
11fdf7f2
TL
15698 if (conn == NULL) {
15699 if (!*error_buffer) {
15700 /* There should be already an error message */
15701 mg_snprintf(conn,
15702 NULL, /* No truncation check for ebuf */
15703 error_buffer,
15704 error_buffer_size,
15705 "Unexpected error");
15706 }
15707 return NULL;
15708 }
15709
15710 if (conn->response_info.status_code != 101) {
15711 /* We sent an "upgrade" request. For a correct websocket
15712 * protocol handshake, we expect a "101 Continue" response.
15713 * Otherwise it is a protocol violation. Maybe the HTTP
15714 * Server does not know websockets. */
7c673cae 15715 if (!*error_buffer) {
11fdf7f2 15716 /* set an error, if not yet set */
7c673cae
FG
15717 mg_snprintf(conn,
15718 NULL, /* No truncation check for ebuf */
15719 error_buffer,
15720 error_buffer_size,
15721 "Unexpected server reply");
15722 }
11fdf7f2 15723
7c673cae 15724 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
11fdf7f2
TL
15725 mg_free(conn);
15726 return NULL;
7c673cae
FG
15727 }
15728
15729 /* For client connections, mg_context is fake. Since we need to set a
15730 * callback function, we need to create a copy and modify it. */
15731 newctx = (struct mg_context *)mg_malloc(sizeof(struct mg_context));
15732 memcpy(newctx, conn->ctx, sizeof(struct mg_context));
15733 newctx->user_data = user_data;
11fdf7f2 15734 newctx->context_type = CONTEXT_WS_CLIENT; /* ws/wss client context */
7c673cae 15735 newctx->cfg_worker_threads = 1; /* one worker thread will be created */
11fdf7f2
TL
15736 newctx->worker_threadids =
15737 (pthread_t *)mg_calloc_ctx(newctx->cfg_worker_threads,
15738 sizeof(pthread_t),
15739 newctx);
7c673cae
FG
15740 conn->ctx = newctx;
15741 thread_data = (struct websocket_client_thread_data *)
11fdf7f2 15742 mg_calloc_ctx(sizeof(struct websocket_client_thread_data), 1, newctx);
7c673cae
FG
15743 thread_data->conn = conn;
15744 thread_data->data_handler = data_func;
15745 thread_data->close_handler = close_func;
11fdf7f2 15746 thread_data->callback_data = user_data;
7c673cae
FG
15747
15748 /* Start a thread to read the websocket client connection
15749 * This thread will automatically stop when mg_disconnect is
15750 * called on the client connection */
15751 if (mg_start_thread_with_id(websocket_client_thread,
15752 (void *)thread_data,
11fdf7f2 15753 newctx->worker_threadids) != 0) {
7c673cae 15754 mg_free((void *)thread_data);
11fdf7f2 15755 mg_free((void *)newctx->worker_threadids);
7c673cae
FG
15756 mg_free((void *)newctx);
15757 mg_free((void *)conn);
15758 conn = NULL;
15759 DEBUG_TRACE("%s",
15760 "Websocket client connect thread could not be started\r\n");
15761 }
11fdf7f2 15762
7c673cae
FG
15763#else
15764 /* Appease "unused parameter" warnings */
15765 (void)host;
15766 (void)port;
15767 (void)use_ssl;
15768 (void)error_buffer;
15769 (void)error_buffer_size;
15770 (void)path;
15771 (void)origin;
15772 (void)user_data;
15773 (void)data_func;
15774 (void)close_func;
15775#endif
15776
15777 return conn;
15778}
15779
15780
11fdf7f2
TL
15781/* Prepare connection data structure */
15782static void
15783init_connection(struct mg_connection *conn)
15784{
15785 /* Is keep alive allowed by the server */
15786 int keep_alive_enabled =
15787 !mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
15788
15789 if (!keep_alive_enabled) {
15790 conn->must_close = 1;
15791 }
15792
15793 /* Important: on new connection, reset the receiving buffer. Credit
15794 * goes to crule42. */
15795 conn->data_len = 0;
15796 conn->handled_requests = 0;
15797 mg_set_user_connection_data(conn, NULL);
15798
15799#if defined(USE_SERVER_STATS)
15800 conn->conn_state = 2; /* init */
15801#endif
15802
15803 /* call the init_connection callback if assigned */
15804 if (conn->ctx->callbacks.init_connection != NULL) {
15805 if (conn->ctx->context_type == CONTEXT_SERVER) {
15806 void *conn_data = NULL;
15807 conn->ctx->callbacks.init_connection(conn, &conn_data);
15808 mg_set_user_connection_data(conn, conn_data);
15809 }
15810 }
15811}
15812
15813
15814/* Process a connection - may handle multiple requests
15815 * using the same connection.
15816 * Must be called with a valid connection (conn and
15817 * conn->ctx must be valid).
15818 */
7c673cae
FG
15819static void
15820process_new_connection(struct mg_connection *conn)
15821{
11fdf7f2
TL
15822 struct mg_request_info *ri = &conn->request_info;
15823 int keep_alive, discard_len;
15824 char ebuf[100];
15825 const char *hostend;
15826 int reqerr, uri_type;
15827
15828#if defined(USE_SERVER_STATS)
15829 int mcon = mg_atomic_inc(&(conn->ctx->active_connections));
15830 mg_atomic_add(&(conn->ctx->total_connections), 1);
15831 if (mcon > (conn->ctx->max_connections)) {
15832 /* could use atomic compare exchange, but this
15833 * seems overkill for statistics data */
15834 conn->ctx->max_connections = mcon;
15835 }
15836#endif
15837
15838 init_connection(conn);
15839
15840 DEBUG_TRACE("Start processing connection from %s",
15841 conn->request_info.remote_addr);
15842
15843 /* Loop over multiple requests sent using the same connection
15844 * (while "keep alive"). */
15845 do {
15846
15847 DEBUG_TRACE("calling get_request (%i times for this connection)",
15848 conn->handled_requests + 1);
15849
15850#if defined(USE_SERVER_STATS)
15851 conn->conn_state = 3; /* ready */
15852#endif
15853
15854 if (!get_request(conn, ebuf, sizeof(ebuf), &reqerr)) {
15855 /* The request sent by the client could not be understood by
15856 * the server, or it was incomplete or a timeout. Send an
15857 * error message and close the connection. */
15858 if (reqerr > 0) {
15859 /*assert(ebuf[0] != '\0');*/
15860 mg_send_http_error(conn, reqerr, "%s", ebuf);
15861 }
15862 } else if (strcmp(ri->http_version, "1.0")
15863 && strcmp(ri->http_version, "1.1")) {
15864 mg_snprintf(conn,
15865 NULL, /* No truncation check for ebuf */
15866 ebuf,
15867 sizeof(ebuf),
15868 "Bad HTTP version: [%s]",
15869 ri->http_version);
15870 mg_send_http_error(conn, 505, "%s", ebuf);
15871 }
15872
15873 if (ebuf[0] == '\0') {
15874 uri_type = get_uri_type(conn->request_info.request_uri,
15875 !mg_strcasecmp(conn->ctx->config[ALLOW_UNICODE_IN_URLS],"yes"));
15876 switch (uri_type) {
15877 case 1:
15878 /* Asterisk */
15879 conn->request_info.local_uri = NULL;
15880 break;
15881 case 2:
15882 /* relative uri */
15883 conn->request_info.local_uri = conn->request_info.request_uri;
15884 break;
15885 case 3:
15886 case 4:
15887 /* absolute uri (with/without port) */
15888 hostend = get_rel_url_at_current_server(
15889 conn->request_info.request_uri, conn);
15890 if (hostend) {
15891 conn->request_info.local_uri = hostend;
15892 } else {
15893 conn->request_info.local_uri = NULL;
7c673cae 15894 }
11fdf7f2
TL
15895 break;
15896 default:
7c673cae
FG
15897 mg_snprintf(conn,
15898 NULL, /* No truncation check for ebuf */
15899 ebuf,
15900 sizeof(ebuf),
11fdf7f2
TL
15901 "Invalid URI");
15902 mg_send_http_error(conn, 400, "%s", ebuf);
15903 conn->request_info.local_uri = NULL;
15904 break;
7c673cae
FG
15905 }
15906
11fdf7f2
TL
15907#if defined(MG_LEGACY_INTERFACE)
15908 /* Legacy before split into local_uri and request_uri */
15909 conn->request_info.uri = conn->request_info.local_uri;
15910#endif
15911 }
7c673cae 15912
11fdf7f2
TL
15913 DEBUG_TRACE("http: %s, error: %s",
15914 (ri->http_version ? ri->http_version : "none"),
15915 (ebuf[0] ? ebuf : "none"));
7c673cae 15916
11fdf7f2
TL
15917 if (ebuf[0] == '\0') {
15918 if (conn->request_info.local_uri) {
15919
15920/* handle request to local server */
15921#if defined(USE_SERVER_STATS)
15922 conn->conn_state = 4; /* processing */
15923#endif
15924 handle_request(conn);
15925
15926#if defined(USE_SERVER_STATS)
15927 conn->conn_state = 5; /* processed */
15928
15929 mg_atomic_add(&(conn->ctx->total_data_read),
15930 conn->consumed_content);
15931 mg_atomic_add(&(conn->ctx->total_data_written),
15932 conn->num_bytes_sent);
15933#endif
15934
15935 DEBUG_TRACE("%s", "handle_request done");
15936
15937 if (conn->ctx->callbacks.end_request != NULL) {
15938 conn->ctx->callbacks.end_request(conn, conn->status_code);
15939 DEBUG_TRACE("%s", "end_request callback done");
7c673cae 15940 }
11fdf7f2 15941 log_access(conn);
7c673cae 15942 } else {
11fdf7f2 15943 /* TODO: handle non-local request (PROXY) */
7c673cae
FG
15944 conn->must_close = 1;
15945 }
11fdf7f2
TL
15946 } else {
15947 conn->must_close = 1;
15948 }
7c673cae 15949
11fdf7f2
TL
15950 if (ri->remote_user != NULL) {
15951 mg_free((void *)ri->remote_user);
15952 /* Important! When having connections with and without auth
15953 * would cause double free and then crash */
15954 ri->remote_user = NULL;
15955 }
15956
15957 /* NOTE(lsm): order is important here. should_keep_alive() call
15958 * is using parsed request, which will be invalid after
15959 * memmove's below.
15960 * Therefore, memorize should_keep_alive() result now for later
15961 * use in loop exit condition. */
15962 keep_alive = (conn->ctx->stop_flag == 0) && should_keep_alive(conn)
15963 && (conn->content_len >= 0);
15964
15965
15966 /* Discard all buffered data for this request */
15967 discard_len = ((conn->content_len >= 0) && (conn->request_len > 0)
15968 && ((conn->request_len + conn->content_len)
15969 < (int64_t)conn->data_len))
15970 ? (int)(conn->request_len + conn->content_len)
15971 : conn->data_len;
15972 /*assert(discard_len >= 0);*/
15973 if (discard_len < 0) {
15974 DEBUG_TRACE("internal error: discard_len = %li",
15975 (long int)discard_len);
15976 break;
15977 }
15978 conn->data_len -= discard_len;
15979 if (conn->data_len > 0) {
15980 DEBUG_TRACE("discard_len = %lu", (long unsigned)discard_len);
15981 memmove(conn->buf, conn->buf + discard_len, (size_t)conn->data_len);
15982 }
7c673cae 15983
11fdf7f2
TL
15984 /* assert(conn->data_len >= 0); */
15985 /* assert(conn->data_len <= conn->buf_size); */
7c673cae 15986
11fdf7f2
TL
15987 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
15988 DEBUG_TRACE("internal error: data_len = %li, buf_size = %li",
15989 (long int)conn->data_len,
15990 (long int)conn->buf_size);
15991 break;
15992 }
15993
15994 conn->handled_requests++;
15995
15996 } while (keep_alive);
15997
15998 DEBUG_TRACE("Done processing connection from %s (%f sec)",
15999 conn->request_info.remote_addr,
16000 difftime(time(NULL), conn->conn_birth_time));
16001
16002 close_connection(conn);
16003
16004#if defined(USE_SERVER_STATS)
16005 mg_atomic_add(&(conn->ctx->total_requests), conn->handled_requests);
16006 mg_atomic_dec(&(conn->ctx->active_connections));
16007#endif
16008}
16009
16010
16011#if defined(ALTERNATIVE_QUEUE)
16012
16013static void
16014produce_socket(struct mg_context *ctx, const struct socket *sp)
16015{
16016 unsigned int i;
7c673cae 16017
11fdf7f2
TL
16018 for (;;) {
16019 for (i = 0; i < ctx->cfg_worker_threads; i++) {
16020 /* find a free worker slot and signal it */
16021 if (ctx->client_socks[i].in_use == 0) {
16022 ctx->client_socks[i] = *sp;
16023 ctx->client_socks[i].in_use = 1;
16024 event_signal(ctx->client_wait_events[i]);
16025 return;
16026 }
16027 }
16028 /* queue is full */
16029 mg_sleep(1);
7c673cae
FG
16030 }
16031}
16032
16033
11fdf7f2
TL
16034static int
16035consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
16036{
16037 DEBUG_TRACE("%s", "going idle");
16038 ctx->client_socks[thread_index].in_use = 0;
16039 event_wait(ctx->client_wait_events[thread_index]);
16040 *sp = ctx->client_socks[thread_index];
16041 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
16042
16043 return !ctx->stop_flag;
16044}
16045
16046#else /* ALTERNATIVE_QUEUE */
16047
7c673cae
FG
16048/* Worker threads take accepted socket from the queue */
16049static int
11fdf7f2 16050consume_socket(struct mg_context *ctx, struct socket *sp, int thread_index)
7c673cae
FG
16051{
16052#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
11fdf7f2
TL
16053
16054 (void)thread_index;
7c673cae
FG
16055
16056 (void)pthread_mutex_lock(&ctx->thread_mutex);
16057 DEBUG_TRACE("%s", "going idle");
16058
16059 /* If the queue is empty, wait. We're idle at this point. */
11fdf7f2 16060 while ((ctx->sq_head == ctx->sq_tail) && (ctx->stop_flag == 0)) {
7c673cae
FG
16061 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
16062 }
16063
16064 /* If we're stopping, sq_head may be equal to sq_tail. */
16065 if (ctx->sq_head > ctx->sq_tail) {
16066 /* Copy socket from the queue and increment tail */
16067 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
16068 ctx->sq_tail++;
16069
16070 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
16071
16072 /* Wrap pointers if needed */
16073 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
16074 ctx->sq_tail -= QUEUE_SIZE(ctx);
16075 ctx->sq_head -= QUEUE_SIZE(ctx);
16076 }
16077 }
16078
16079 (void)pthread_cond_signal(&ctx->sq_empty);
16080 (void)pthread_mutex_unlock(&ctx->thread_mutex);
16081
16082 return !ctx->stop_flag;
16083#undef QUEUE_SIZE
16084}
16085
16086
11fdf7f2
TL
16087/* Master thread adds accepted socket to a queue */
16088static void
16089produce_socket(struct mg_context *ctx, const struct socket *sp)
7c673cae 16090{
11fdf7f2
TL
16091#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
16092 if (!ctx) {
16093 return;
16094 }
16095 (void)pthread_mutex_lock(&ctx->thread_mutex);
16096
16097 /* If the queue is full, wait */
16098 while ((ctx->stop_flag == 0)
16099 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
16100 (void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
16101 }
16102
16103 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
16104 /* Copy socket to the queue and increment head */
16105 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
16106 ctx->sq_head++;
16107 DEBUG_TRACE("queued socket %d", sp ? sp->sock : -1);
16108 }
16109
16110 (void)pthread_cond_signal(&ctx->sq_full);
16111 (void)pthread_mutex_unlock(&ctx->thread_mutex);
16112#undef QUEUE_SIZE
16113}
16114#endif /* ALTERNATIVE_QUEUE */
16115
16116
16117struct worker_thread_args {
16118 struct mg_context *ctx;
16119 int index;
16120};
16121
16122
16123static void *
16124worker_thread_run(struct worker_thread_args *thread_args)
16125{
16126 struct mg_context *ctx = thread_args->ctx;
7c673cae
FG
16127 struct mg_connection *conn;
16128 struct mg_workerTLS tls;
16129#if defined(MG_LEGACY_INTERFACE)
16130 uint32_t addr;
16131#endif
16132
16133 mg_set_thread_name("worker");
16134
16135 tls.is_master = 0;
16136 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
16137#if defined(_WIN32) && !defined(__SYMBIAN32__)
16138 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
16139#endif
16140
11fdf7f2
TL
16141 /* Initialize thread local storage before calling any callback */
16142 pthread_setspecific(sTlsKey, &tls);
16143
7c673cae
FG
16144 if (ctx->callbacks.init_thread) {
16145 /* call init_thread for a worker thread (type 1) */
16146 ctx->callbacks.init_thread(ctx, 1);
16147 }
16148
11fdf7f2
TL
16149 /* Connection structure has been pre-allocated */
16150 if (((int)thread_args->index < 0)
16151 || ((unsigned)thread_args->index
16152 >= (unsigned)ctx->cfg_worker_threads)) {
16153 mg_cry(fc(ctx),
16154 "Internal error: Invalid worker index %i",
16155 (int)thread_args->index);
16156 return NULL;
16157 }
16158 conn = ctx->worker_connections + thread_args->index;
16159
16160 /* Request buffers are not pre-allocated. They are private to the
16161 * request and do not contain any state information that might be
16162 * of interest to anyone observing a server status. */
16163 conn->buf = (char *)mg_malloc_ctx(ctx->max_request_size, conn->ctx);
16164 if (conn->buf == NULL) {
16165 mg_cry(fc(ctx),
16166 "Out of memory: Cannot allocate buffer for worker %i",
16167 (int)thread_args->index);
16168 return NULL;
16169 }
16170 conn->buf_size = (int)ctx->max_request_size;
16171
16172 conn->ctx = ctx;
16173 conn->thread_index = thread_args->index;
16174 conn->request_info.user_data = ctx->user_data;
16175 /* Allocate a mutex for this connection to allow communication both
16176 * within the request handler and from elsewhere in the application
16177 */
16178 (void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
7c673cae 16179
11fdf7f2
TL
16180#if defined(USE_SERVER_STATS)
16181 conn->conn_state = 1; /* not consumed */
16182#endif
16183
16184 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
16185 * signal sq_empty condvar to wake up the master waiting in
16186 * produce_socket() */
16187 while (consume_socket(ctx, &conn->client, conn->thread_index)) {
16188 conn->conn_birth_time = time(NULL);
7c673cae
FG
16189
16190/* Fill in IP, port info early so even if SSL setup below fails,
16191 * error handler would have the corresponding info.
16192 * Thanks to Johannes Winkelmann for the patch.
16193 */
16194#if defined(USE_IPV6)
11fdf7f2
TL
16195 if (conn->client.rsa.sa.sa_family == AF_INET6) {
16196 conn->request_info.remote_port =
16197 ntohs(conn->client.rsa.sin6.sin6_port);
16198 } else
7c673cae 16199#endif
11fdf7f2
TL
16200 {
16201 conn->request_info.remote_port =
16202 ntohs(conn->client.rsa.sin.sin_port);
16203 }
16204
16205 sockaddr_to_string(conn->request_info.remote_addr,
16206 sizeof(conn->request_info.remote_addr),
16207 &conn->client.rsa);
7c673cae 16208
11fdf7f2
TL
16209 DEBUG_TRACE("Start processing connection from %s",
16210 conn->request_info.remote_addr);
7c673cae
FG
16211
16212#if defined(MG_LEGACY_INTERFACE)
11fdf7f2
TL
16213 /* This legacy interface only works for the IPv4 case */
16214 addr = ntohl(conn->client.rsa.sin.sin_addr.s_addr);
16215 memcpy(&conn->request_info.remote_ip, &addr, 4);
7c673cae
FG
16216#endif
16217
11fdf7f2 16218 conn->request_info.is_ssl = conn->client.is_ssl;
7c673cae 16219
11fdf7f2 16220 if (conn->client.is_ssl) {
7c673cae 16221#ifndef NO_SSL
11fdf7f2
TL
16222 /* HTTPS connection */
16223 if (sslize(conn,
16224 conn->ctx->ssl_ctx,
16225 SSL_accept,
16226 &(conn->ctx->stop_flag))) {
16227 /* Get SSL client certificate information (if set) */
16228 ssl_get_client_cert_info(conn);
16229
16230 /* process HTTPS connection */
7c673cae 16231 process_new_connection(conn);
7c673cae 16232
11fdf7f2
TL
16233 /* Free client certificate info */
16234 if (conn->request_info.client_cert) {
16235 mg_free((void *)(conn->request_info.client_cert->subject));
16236 mg_free((void *)(conn->request_info.client_cert->issuer));
16237 mg_free((void *)(conn->request_info.client_cert->serial));
16238 mg_free((void *)(conn->request_info.client_cert->finger));
16239 conn->request_info.client_cert->subject = 0;
16240 conn->request_info.client_cert->issuer = 0;
16241 conn->request_info.client_cert->serial = 0;
16242 conn->request_info.client_cert->finger = 0;
16243 mg_free(conn->request_info.client_cert);
16244 conn->request_info.client_cert = 0;
16245 }
16246 }
16247 else {
16248 close_connection(conn);
16249 }
16250#endif
16251 } else {
16252 /* process HTTP connection */
16253 process_new_connection(conn);
7c673cae 16254 }
11fdf7f2
TL
16255
16256 DEBUG_TRACE("%s", "Connection closed");
7c673cae
FG
16257 }
16258
7c673cae
FG
16259
16260 pthread_setspecific(sTlsKey, NULL);
16261#if defined(_WIN32) && !defined(__SYMBIAN32__)
16262 CloseHandle(tls.pthread_cond_helper_mutex);
16263#endif
16264 pthread_mutex_destroy(&conn->mutex);
11fdf7f2
TL
16265
16266 /* Free the request buffer. */
16267 conn->buf_size = 0;
16268 mg_free(conn->buf);
16269 conn->buf = NULL;
16270
16271#if defined(USE_SERVER_STATS)
16272 conn->conn_state = 9; /* done */
16273#endif
7c673cae
FG
16274
16275 DEBUG_TRACE("%s", "exiting");
16276 return NULL;
16277}
16278
16279
16280/* Threads have different return types on Windows and Unix. */
16281#ifdef _WIN32
16282static unsigned __stdcall worker_thread(void *thread_func_param)
16283{
11fdf7f2
TL
16284 struct worker_thread_args *pwta =
16285 (struct worker_thread_args *)thread_func_param;
16286 worker_thread_run(pwta);
16287 mg_free(thread_func_param);
7c673cae
FG
16288 return 0;
16289}
16290#else
16291static void *
16292worker_thread(void *thread_func_param)
16293{
11fdf7f2
TL
16294 struct worker_thread_args *pwta =
16295 (struct worker_thread_args *)thread_func_param;
16296 worker_thread_run(pwta);
16297 mg_free(thread_func_param);
7c673cae
FG
16298 return NULL;
16299}
16300#endif /* _WIN32 */
16301
16302
7c673cae
FG
16303static void
16304accept_new_connection(const struct socket *listener, struct mg_context *ctx)
16305{
16306 struct socket so;
16307 char src_addr[IP_ADDR_STR_LEN];
16308 socklen_t len = sizeof(so.rsa);
16309 int on = 1;
7c673cae
FG
16310
16311 if (!listener) {
16312 return;
16313 }
16314
16315 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
16316 == INVALID_SOCKET) {
16317 } else if (!check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
16318 sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
16319 mg_cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
16320 closesocket(so.sock);
7c673cae
FG
16321 } else {
16322 /* Put so socket structure into the queue */
16323 DEBUG_TRACE("Accepted socket %d", (int)so.sock);
16324 set_close_on_exec(so.sock, fc(ctx));
16325 so.is_ssl = listener->is_ssl;
16326 so.ssl_redir = listener->ssl_redir;
16327 if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
16328 mg_cry(fc(ctx),
16329 "%s: getsockname() failed: %s",
16330 __func__,
16331 strerror(ERRNO));
16332 }
16333
16334 /* Set TCP keep-alive. This is needed because if HTTP-level
16335 * keep-alive
16336 * is enabled, and client resets the connection, server won't get
16337 * TCP FIN or RST and will keep the connection open forever. With
16338 * TCP keep-alive, next keep-alive handshake will figure out that
16339 * the client is down and will close the server end.
16340 * Thanks to Igor Klopov who suggested the patch. */
16341 if (setsockopt(so.sock,
16342 SOL_SOCKET,
16343 SO_KEEPALIVE,
16344 (SOCK_OPT_TYPE)&on,
16345 sizeof(on)) != 0) {
16346 mg_cry(fc(ctx),
16347 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
16348 __func__,
16349 strerror(ERRNO));
16350 }
16351
11fdf7f2 16352 /* Disable TCP Nagle's algorithm. Normally TCP packets are coalesced
7c673cae 16353 * to effectively fill up the underlying IP packet payload and
11fdf7f2
TL
16354 * reduce the overhead of sending lots of small buffers. However
16355 * this hurts the server's throughput (ie. operations per second)
16356 * when HTTP 1.1 persistent connections are used and the responses
16357 * are relatively small (eg. less than 1400 bytes).
7c673cae
FG
16358 */
16359 if ((ctx != NULL) && (ctx->config[CONFIG_TCP_NODELAY] != NULL)
16360 && (!strcmp(ctx->config[CONFIG_TCP_NODELAY], "1"))) {
16361 if (set_tcp_nodelay(so.sock, 1) != 0) {
16362 mg_cry(fc(ctx),
16363 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
16364 __func__,
16365 strerror(ERRNO));
16366 }
16367 }
16368
11fdf7f2
TL
16369 /* We are using non-blocking sockets. Thus, the
16370 * set_sock_timeout(so.sock, timeout);
16371 * call is no longer required. */
7c673cae 16372
11fdf7f2
TL
16373 /* The "non blocking" property should already be
16374 * inherited from the parent socket. Set it for
16375 * non-compliant socket implementations. */
16376 set_non_blocking_mode(so.sock);
7c673cae 16377
11fdf7f2 16378 so.in_use = 0;
7c673cae
FG
16379 produce_socket(ctx, &so);
16380 }
16381}
16382
16383
16384static void
16385master_thread_run(void *thread_func_param)
16386{
16387 struct mg_context *ctx = (struct mg_context *)thread_func_param;
16388 struct mg_workerTLS tls;
16389 struct pollfd *pfd;
16390 unsigned int i;
16391 unsigned int workerthreadcount;
16392
16393 if (!ctx) {
16394 return;
16395 }
16396
16397 mg_set_thread_name("master");
16398
16399/* Increase priority of the master thread */
16400#if defined(_WIN32)
16401 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
16402#elif defined(USE_MASTER_THREAD_PRIORITY)
16403 int min_prio = sched_get_priority_min(SCHED_RR);
16404 int max_prio = sched_get_priority_max(SCHED_RR);
16405 if ((min_prio >= 0) && (max_prio >= 0)
16406 && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
16407 && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
16408 struct sched_param sched_param = {0};
16409 sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
16410 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
16411 }
16412#endif
16413
16414/* Initialize thread local storage */
16415#if defined(_WIN32) && !defined(__SYMBIAN32__)
16416 tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
16417#endif
16418 tls.is_master = 1;
16419 pthread_setspecific(sTlsKey, &tls);
16420
16421 if (ctx->callbacks.init_thread) {
16422 /* Callback for the master thread (type 0) */
16423 ctx->callbacks.init_thread(ctx, 0);
16424 }
16425
16426 /* Server starts *now* */
16427 ctx->start_time = time(NULL);
16428
11fdf7f2
TL
16429 /* Start the server */
16430 pfd = ctx->listening_socket_fds;
16431 while (ctx->stop_flag == 0) {
7c673cae
FG
16432 for (i = 0; i < ctx->num_listening_sockets; i++) {
16433 pfd[i].fd = ctx->listening_sockets[i].sock;
16434 pfd[i].events = POLLIN;
16435 }
16436
16437 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
16438 for (i = 0; i < ctx->num_listening_sockets; i++) {
16439 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
16440 * successful poll, and POLLIN is defined as
16441 * (POLLRDNORM | POLLRDBAND)
16442 * Therefore, we're checking pfd[i].revents & POLLIN, not
16443 * pfd[i].revents == POLLIN. */
11fdf7f2 16444 if ((ctx->stop_flag == 0) && (pfd[i].revents & POLLIN)) {
7c673cae
FG
16445 accept_new_connection(&ctx->listening_sockets[i], ctx);
16446 }
16447 }
16448 }
16449 }
11fdf7f2
TL
16450
16451 /* Here stop_flag is 1 - Initiate shutdown. */
7c673cae
FG
16452 DEBUG_TRACE("%s", "stopping workers");
16453
16454 /* Stop signal received: somebody called mg_stop. Quit. */
16455 close_all_listening_sockets(ctx);
16456
16457 /* Wakeup workers that are waiting for connections to handle. */
7c673cae 16458 (void)pthread_mutex_lock(&ctx->thread_mutex);
11fdf7f2
TL
16459#if defined(ALTERNATIVE_QUEUE)
16460 for (i = 0; i < ctx->cfg_worker_threads; i++) {
16461 event_signal(ctx->client_wait_events[i]);
16462
16463 /* Since we know all sockets, we can shutdown the connections. */
16464 if (ctx->client_socks[i].in_use) {
16465 shutdown(ctx->client_socks[i].sock, SHUTDOWN_BOTH);
16466 }
7c673cae 16467 }
11fdf7f2
TL
16468#else
16469 pthread_cond_broadcast(&ctx->sq_full);
16470#endif
7c673cae
FG
16471 (void)pthread_mutex_unlock(&ctx->thread_mutex);
16472
16473 /* Join all worker threads to avoid leaking threads. */
16474 workerthreadcount = ctx->cfg_worker_threads;
16475 for (i = 0; i < workerthreadcount; i++) {
11fdf7f2
TL
16476 if (ctx->worker_threadids[i] != 0) {
16477 mg_join_thread(ctx->worker_threadids[i]);
7c673cae
FG
16478 }
16479 }
16480
11fdf7f2
TL
16481#if defined(USE_LUA)
16482 /* Free Lua state of lua background task */
16483 if (ctx->lua_background_state) {
16484 lua_State *lstate = (lua_State *)ctx->lua_background_state;
16485 lua_getglobal(lstate, LUABACKGROUNDPARAMS);
16486 if (lua_istable(lstate, -1)) {
16487 reg_boolean(lstate, "shutdown", 1);
16488 lua_pop(lstate, 1);
16489 mg_sleep(2);
16490 }
16491 lua_close(lstate);
16492 ctx->lua_background_state = 0;
7c673cae
FG
16493 }
16494#endif
11fdf7f2 16495
7c673cae
FG
16496 DEBUG_TRACE("%s", "exiting");
16497
16498#if defined(_WIN32) && !defined(__SYMBIAN32__)
16499 CloseHandle(tls.pthread_cond_helper_mutex);
16500#endif
16501 pthread_setspecific(sTlsKey, NULL);
16502
16503 /* Signal mg_stop() that we're done.
16504 * WARNING: This must be the very last thing this
16505 * thread does, as ctx becomes invalid after this line. */
16506 ctx->stop_flag = 2;
16507}
16508
16509
16510/* Threads have different return types on Windows and Unix. */
16511#ifdef _WIN32
16512static unsigned __stdcall master_thread(void *thread_func_param)
16513{
16514 master_thread_run(thread_func_param);
16515 return 0;
16516}
16517#else
16518static void *
16519master_thread(void *thread_func_param)
16520{
16521 master_thread_run(thread_func_param);
16522 return NULL;
16523}
16524#endif /* _WIN32 */
16525
16526
16527static void
16528free_context(struct mg_context *ctx)
16529{
16530 int i;
16531 struct mg_handler_info *tmp_rh;
16532
16533 if (ctx == NULL) {
16534 return;
16535 }
16536
16537 if (ctx->callbacks.exit_context) {
16538 ctx->callbacks.exit_context(ctx);
16539 }
16540
16541 /* All threads exited, no sync is needed. Destroy thread mutex and
16542 * condvars
16543 */
16544 (void)pthread_mutex_destroy(&ctx->thread_mutex);
11fdf7f2
TL
16545#if defined(ALTERNATIVE_QUEUE)
16546 mg_free(ctx->client_socks);
16547 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
16548 event_destroy(ctx->client_wait_events[i]);
16549 }
16550 mg_free(ctx->client_wait_events);
16551#else
7c673cae
FG
16552 (void)pthread_cond_destroy(&ctx->sq_empty);
16553 (void)pthread_cond_destroy(&ctx->sq_full);
11fdf7f2 16554#endif
7c673cae
FG
16555
16556 /* Destroy other context global data structures mutex */
16557 (void)pthread_mutex_destroy(&ctx->nonce_mutex);
16558
16559#if defined(USE_TIMERS)
16560 timers_exit(ctx);
16561#endif
16562
16563 /* Deallocate config parameters */
16564 for (i = 0; i < NUM_OPTIONS; i++) {
16565 if (ctx->config[i] != NULL) {
16566#if defined(_MSC_VER)
16567#pragma warning(suppress : 6001)
16568#endif
16569 mg_free(ctx->config[i]);
16570 }
16571 }
16572
16573 /* Deallocate request handlers */
16574 while (ctx->handlers) {
16575 tmp_rh = ctx->handlers;
16576 ctx->handlers = tmp_rh->next;
16577 mg_free(tmp_rh->uri);
16578 mg_free(tmp_rh);
16579 }
16580
16581#ifndef NO_SSL
16582 /* Deallocate SSL context */
16583 if (ctx->ssl_ctx != NULL) {
16584 SSL_CTX_free(ctx->ssl_ctx);
16585 }
16586#endif /* !NO_SSL */
16587
16588 /* Deallocate worker thread ID array */
11fdf7f2
TL
16589 if (ctx->worker_threadids != NULL) {
16590 mg_free(ctx->worker_threadids);
7c673cae
FG
16591 }
16592
11fdf7f2
TL
16593 /* Deallocate worker thread ID array */
16594 if (ctx->worker_connections != NULL) {
16595 mg_free(ctx->worker_connections);
7c673cae
FG
16596 }
16597
16598 /* deallocate system name string */
16599 mg_free(ctx->systemName);
16600
16601 /* Deallocate context itself */
16602 mg_free(ctx);
16603}
16604
16605
16606void
16607mg_stop(struct mg_context *ctx)
16608{
16609 pthread_t mt;
16610 if (!ctx) {
16611 return;
16612 }
16613
16614 /* We don't use a lock here. Calling mg_stop with the same ctx from
16615 * two threads is not allowed. */
16616 mt = ctx->masterthreadid;
16617 if (mt == 0) {
16618 return;
16619 }
16620
16621 ctx->masterthreadid = 0;
11fdf7f2
TL
16622
16623 /* Set stop flag, so all threads know they have to exit. */
7c673cae
FG
16624 ctx->stop_flag = 1;
16625
11fdf7f2 16626 /* Wait until everything has stopped. */
7c673cae
FG
16627 while (ctx->stop_flag != 2) {
16628 (void)mg_sleep(10);
16629 }
16630
16631 mg_join_thread(mt);
16632 free_context(ctx);
16633
16634#if defined(_WIN32) && !defined(__SYMBIAN32__)
16635 (void)WSACleanup();
16636#endif /* _WIN32 && !__SYMBIAN32__ */
16637}
16638
16639
16640static void
16641get_system_name(char **sysName)
16642{
16643#if defined(_WIN32)
16644#if !defined(__SYMBIAN32__)
11fdf7f2
TL
16645#if defined(_WIN32_WCE)
16646 *sysName = mg_strdup("WinCE");
16647#else
7c673cae
FG
16648 char name[128];
16649 DWORD dwVersion = 0;
16650 DWORD dwMajorVersion = 0;
16651 DWORD dwMinorVersion = 0;
16652 DWORD dwBuild = 0;
11fdf7f2 16653 BOOL wowRet, isWoW = FALSE;
7c673cae
FG
16654
16655#ifdef _MSC_VER
16656#pragma warning(push)
11fdf7f2 16657/* GetVersion was declared deprecated */
7c673cae
FG
16658#pragma warning(disable : 4996)
16659#endif
16660 dwVersion = GetVersion();
16661#ifdef _MSC_VER
16662#pragma warning(pop)
16663#endif
16664
16665 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
16666 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
16667 dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
16668 (void)dwBuild;
16669
11fdf7f2
TL
16670 wowRet = IsWow64Process(GetCurrentProcess(), &isWoW);
16671
7c673cae 16672 sprintf(name,
11fdf7f2 16673 "Windows %u.%u%s",
7c673cae 16674 (unsigned)dwMajorVersion,
11fdf7f2
TL
16675 (unsigned)dwMinorVersion,
16676 (wowRet ? (isWoW ? " (WoW64)" : "") : " (?)"));
16677
7c673cae 16678 *sysName = mg_strdup(name);
11fdf7f2 16679#endif
7c673cae
FG
16680#else
16681 *sysName = mg_strdup("Symbian");
16682#endif
16683#else
16684 struct utsname name;
16685 memset(&name, 0, sizeof(name));
16686 uname(&name);
16687 *sysName = mg_strdup(name.sysname);
16688#endif
16689}
16690
16691
16692struct mg_context *
16693mg_start(const struct mg_callbacks *callbacks,
16694 void *user_data,
16695 const char **options)
16696{
16697 struct mg_context *ctx;
16698 const char *name, *value, *default_value;
16699 int idx, ok, workerthreadcount;
16700 unsigned int i;
11fdf7f2 16701 int itmp;
7c673cae
FG
16702 void (*exit_callback)(const struct mg_context *ctx) = 0;
16703
16704 struct mg_workerTLS tls;
16705
16706#if defined(_WIN32) && !defined(__SYMBIAN32__)
16707 WSADATA data;
16708 WSAStartup(MAKEWORD(2, 2), &data);
16709#endif /* _WIN32 && !__SYMBIAN32__ */
16710
16711 /* Allocate context and initialize reasonable general case defaults. */
16712 if ((ctx = (struct mg_context *)mg_calloc(1, sizeof(*ctx))) == NULL) {
16713 return NULL;
16714 }
16715
16716 /* Random number generator will initialize at the first call */
16717 ctx->auth_nonce_mask =
16718 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
16719
11fdf7f2
TL
16720 if (mg_init_library_called == 0) {
16721 /* Legacy INIT, if mg_start is called without mg_init_library.
16722 * Note: This may cause a memory leak */
16723 mg_init_library(0);
7c673cae
FG
16724 }
16725
16726 tls.is_master = -1;
16727 tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
16728#if defined(_WIN32) && !defined(__SYMBIAN32__)
16729 tls.pthread_cond_helper_mutex = NULL;
16730#endif
16731 pthread_setspecific(sTlsKey, &tls);
16732
7c673cae 16733 ok = 0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr);
11fdf7f2 16734#if !defined(ALTERNATIVE_QUEUE)
7c673cae
FG
16735 ok &= 0 == pthread_cond_init(&ctx->sq_empty, NULL);
16736 ok &= 0 == pthread_cond_init(&ctx->sq_full, NULL);
11fdf7f2 16737#endif
7c673cae
FG
16738 ok &= 0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr);
16739 if (!ok) {
16740 /* Fatal error - abort start. However, this situation should never
16741 * occur in practice. */
16742 mg_cry(fc(ctx), "Cannot initialize thread synchronization objects");
16743 mg_free(ctx);
16744 pthread_setspecific(sTlsKey, NULL);
16745 return NULL;
16746 }
16747
16748 if (callbacks) {
16749 ctx->callbacks = *callbacks;
16750 exit_callback = callbacks->exit_context;
16751 ctx->callbacks.exit_context = 0;
16752 }
16753 ctx->user_data = user_data;
16754 ctx->handlers = NULL;
16755
16756#if defined(USE_LUA) && defined(USE_WEBSOCKET)
16757 ctx->shared_lua_websockets = 0;
16758#endif
16759
16760 while (options && (name = *options++) != NULL) {
16761 if ((idx = get_option_index(name)) == -1) {
16762 mg_cry(fc(ctx), "Invalid option: %s", name);
16763 free_context(ctx);
16764 pthread_setspecific(sTlsKey, NULL);
16765 return NULL;
16766 } else if ((value = *options++) == NULL) {
16767 mg_cry(fc(ctx), "%s: option value cannot be NULL", name);
16768 free_context(ctx);
16769 pthread_setspecific(sTlsKey, NULL);
16770 return NULL;
16771 }
16772 if (ctx->config[idx] != NULL) {
16773 mg_cry(fc(ctx), "warning: %s: duplicate option", name);
16774 mg_free(ctx->config[idx]);
16775 }
16776 ctx->config[idx] = mg_strdup(value);
16777 DEBUG_TRACE("[%s] -> [%s]", name, value);
16778 }
16779
16780 /* Set default value if needed */
16781 for (i = 0; config_options[i].name != NULL; i++) {
16782 default_value = config_options[i].default_value;
11fdf7f2 16783 if ((ctx->config[i] == NULL) && (default_value != NULL)) {
7c673cae
FG
16784 ctx->config[i] = mg_strdup(default_value);
16785 }
16786 }
16787
11fdf7f2
TL
16788 itmp = atoi(ctx->config[MAX_REQUEST_SIZE]);
16789
16790 if (itmp < 1024) {
16791 mg_cry(fc(ctx), "max_request_size too small");
16792 free_context(ctx);
16793 pthread_setspecific(sTlsKey, NULL);
16794 return NULL;
16795 }
16796 ctx->max_request_size = (unsigned)itmp;
16797
16798 workerthreadcount = atoi(ctx->config[NUM_THREADS]);
16799
16800 if (workerthreadcount > MAX_WORKER_THREADS) {
16801 mg_cry(fc(ctx), "Too many worker threads");
16802 free_context(ctx);
16803 pthread_setspecific(sTlsKey, NULL);
16804 return NULL;
16805 }
16806
16807 if (workerthreadcount <= 0) {
16808 mg_cry(fc(ctx), "Invalid number of worker threads");
16809 free_context(ctx);
16810 pthread_setspecific(sTlsKey, NULL);
16811 return NULL;
16812 }
16813
7c673cae
FG
16814#if defined(NO_FILES)
16815 if (ctx->config[DOCUMENT_ROOT] != NULL) {
16816 mg_cry(fc(ctx), "%s", "Document root must not be set");
16817 free_context(ctx);
16818 pthread_setspecific(sTlsKey, NULL);
16819 return NULL;
16820 }
16821#endif
16822
16823 get_system_name(&ctx->systemName);
16824
11fdf7f2
TL
16825#if defined(USE_LUA)
16826 /* If a Lua background script has been configured, start it. */
16827 if (ctx->config[LUA_BACKGROUND_SCRIPT] != NULL) {
16828 char ebuf[256];
16829 lua_State *state = (void *)mg_prepare_lua_context_script(
16830 ctx->config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
16831 if (!state) {
16832 mg_cry(fc(ctx), "lua_background_script error: %s", ebuf);
16833 free_context(ctx);
16834 pthread_setspecific(sTlsKey, NULL);
16835 return NULL;
16836 }
16837 ctx->lua_background_state = (void *)state;
16838
16839 lua_newtable(state);
16840 reg_boolean(state, "shutdown", 0);
16841
16842 struct vec opt_vec;
16843 struct vec eq_vec;
16844 const char *sparams = ctx->config[LUA_BACKGROUND_SCRIPT_PARAMS];
16845
16846 while ((sparams = next_option(sparams, &opt_vec, &eq_vec)) != NULL) {
16847 reg_llstring(
16848 state, opt_vec.ptr, opt_vec.len, eq_vec.ptr, eq_vec.len);
16849 if (mg_strncasecmp(sparams, opt_vec.ptr, opt_vec.len) == 0)
16850 break;
16851 }
16852 lua_setglobal(state, LUABACKGROUNDPARAMS);
16853
16854 } else {
16855 ctx->lua_background_state = 0;
16856 }
16857#endif
16858
7c673cae
FG
16859 /* NOTE(lsm): order is important here. SSL certificates must
16860 * be initialized before listening ports. UID must be set last. */
16861 if (!set_gpass_option(ctx) ||
16862#if !defined(NO_SSL)
16863 !set_ssl_option(ctx) ||
16864#endif
16865 !set_ports_option(ctx) ||
16866#if !defined(_WIN32)
16867 !set_uid_option(ctx) ||
16868#endif
16869 !set_acl_option(ctx)) {
16870 free_context(ctx);
16871 pthread_setspecific(sTlsKey, NULL);
16872 return NULL;
16873 }
16874
16875#if !defined(_WIN32) && !defined(__SYMBIAN32__)
16876 /* Ignore SIGPIPE signal, so if browser cancels the request, it
16877 * won't kill the whole process. */
16878 (void)signal(SIGPIPE, SIG_IGN);
16879#endif /* !_WIN32 && !__SYMBIAN32__ */
16880
11fdf7f2
TL
16881 ctx->cfg_worker_threads = ((unsigned int)(workerthreadcount));
16882 ctx->worker_threadids = (pthread_t *)mg_calloc_ctx(ctx->cfg_worker_threads,
16883 sizeof(pthread_t),
16884 ctx);
16885 if (ctx->worker_threadids == NULL) {
16886 mg_cry(fc(ctx), "Not enough memory for worker thread ID array");
16887 free_context(ctx);
16888 pthread_setspecific(sTlsKey, NULL);
16889 return NULL;
16890 }
16891 ctx->worker_connections =
16892 (struct mg_connection *)mg_calloc_ctx(ctx->cfg_worker_threads,
16893 sizeof(struct mg_connection),
16894 ctx);
16895 if (ctx->worker_connections == NULL) {
16896 mg_cry(fc(ctx), "Not enough memory for worker thread connection array");
16897 free_context(ctx);
16898 pthread_setspecific(sTlsKey, NULL);
16899 return NULL;
16900 }
7c673cae 16901
11fdf7f2
TL
16902
16903#if defined(ALTERNATIVE_QUEUE)
16904 ctx->client_wait_events =
16905 (void **)mg_calloc_ctx(sizeof(ctx->client_wait_events[0]),
16906 ctx->cfg_worker_threads,
16907 ctx);
16908 if (ctx->client_wait_events == NULL) {
16909 mg_cry(fc(ctx), "Not enough memory for worker event array");
16910 mg_free(ctx->worker_threadids);
16911 free_context(ctx);
16912 pthread_setspecific(sTlsKey, NULL);
16913 return NULL;
16914 }
16915
16916 ctx->client_socks =
16917 (struct socket *)mg_calloc_ctx(sizeof(ctx->client_socks[0]),
16918 ctx->cfg_worker_threads,
16919 ctx);
16920 if (ctx->client_wait_events == NULL) {
16921 mg_cry(fc(ctx), "Not enough memory for worker socket array");
16922 mg_free(ctx->client_socks);
16923 mg_free(ctx->worker_threadids);
7c673cae
FG
16924 free_context(ctx);
16925 pthread_setspecific(sTlsKey, NULL);
16926 return NULL;
16927 }
16928
11fdf7f2
TL
16929 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
16930 ctx->client_wait_events[i] = event_create();
16931 if (ctx->client_wait_events[i] == 0) {
16932 mg_cry(fc(ctx), "Error creating worker event %i", i);
16933 while (i > 0) {
16934 i--;
16935 event_destroy(ctx->client_wait_events[i]);
16936 }
16937 mg_free(ctx->client_socks);
16938 mg_free(ctx->worker_threadids);
7c673cae
FG
16939 free_context(ctx);
16940 pthread_setspecific(sTlsKey, NULL);
16941 return NULL;
16942 }
16943 }
11fdf7f2
TL
16944#endif
16945
7c673cae
FG
16946
16947#if defined(USE_TIMERS)
16948 if (timers_init(ctx) != 0) {
16949 mg_cry(fc(ctx), "Error creating timers");
16950 free_context(ctx);
16951 pthread_setspecific(sTlsKey, NULL);
16952 return NULL;
16953 }
16954#endif
16955
16956 /* Context has been created - init user libraries */
16957 if (ctx->callbacks.init_context) {
16958 ctx->callbacks.init_context(ctx);
16959 }
16960 ctx->callbacks.exit_context = exit_callback;
11fdf7f2 16961 ctx->context_type = CONTEXT_SERVER; /* server context */
7c673cae
FG
16962
16963 /* Start master (listening) thread */
16964 mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
16965
16966 /* Start worker threads */
16967 for (i = 0; i < ctx->cfg_worker_threads; i++) {
11fdf7f2
TL
16968 struct worker_thread_args *wta = (struct worker_thread_args *)
16969 mg_malloc_ctx(sizeof(struct worker_thread_args), ctx);
16970 if (wta) {
16971 wta->ctx = ctx;
16972 wta->index = (int)i;
16973 }
16974
16975 if ((wta == NULL)
16976 || (mg_start_thread_with_id(worker_thread,
16977 wta,
16978 &ctx->worker_threadids[i]) != 0)) {
16979
16980 /* thread was not created */
16981 if (wta != NULL) {
16982 mg_free(wta);
16983 }
16984
7c673cae
FG
16985 if (i > 0) {
16986 mg_cry(fc(ctx),
16987 "Cannot start worker thread %i: error %ld",
16988 i + 1,
16989 (long)ERRNO);
16990 } else {
16991 mg_cry(fc(ctx),
16992 "Cannot create threads: error %ld",
16993 (long)ERRNO);
16994 free_context(ctx);
16995 pthread_setspecific(sTlsKey, NULL);
16996 return NULL;
16997 }
16998 break;
16999 }
17000 }
17001
17002 pthread_setspecific(sTlsKey, NULL);
17003 return ctx;
17004}
17005
17006
17007/* Feature check API function */
17008unsigned
17009mg_check_feature(unsigned feature)
17010{
17011 static const unsigned feature_set = 0
17012/* Set bits for available features according to API documentation.
17013 * This bit mask is created at compile time, according to the active
17014 * preprocessor defines. It is a single const value at runtime. */
17015#if !defined(NO_FILES)
17016 | 0x0001u
17017#endif
17018#if !defined(NO_SSL)
17019 | 0x0002u
17020#endif
17021#if !defined(NO_CGI)
17022 | 0x0004u
17023#endif
17024#if defined(USE_IPV6)
17025 | 0x0008u
17026#endif
17027#if defined(USE_WEBSOCKET)
17028 | 0x0010u
17029#endif
17030#if defined(USE_LUA)
17031 | 0x0020u
17032#endif
17033#if defined(USE_DUKTAPE)
17034 | 0x0040u
17035#endif
17036#if !defined(NO_CACHING)
17037 | 0x0080u
17038#endif
11fdf7f2
TL
17039#if defined(USE_SERVER_STATS)
17040 | 0x0100u
17041#endif
7c673cae
FG
17042
17043/* Set some extra bits not defined in the API documentation.
17044 * These bits may change without further notice. */
17045#if defined(MG_LEGACY_INTERFACE)
17046 | 0x8000u
17047#endif
17048#if defined(MEMORY_DEBUGGING)
17049 | 0x0100u
17050#endif
17051#if defined(USE_TIMERS)
17052 | 0x0200u
17053#endif
17054#if !defined(NO_NONCE_CHECK)
17055 | 0x0400u
17056#endif
17057#if !defined(NO_POPEN)
17058 | 0x0800u
17059#endif
17060 ;
17061 return (feature & feature_set);
17062}
11fdf7f2
TL
17063
17064
17065/* strcat with additional NULL check to avoid clang scan-build warning. */
17066#define strcat0(a, b) \
17067 { \
17068 if ((a != NULL) && (b != NULL)) { \
17069 strcat(a, b); \
17070 } \
17071 }
17072
17073
17074/* Get system information. It can be printed or stored by the caller.
17075 * Return the size of available information. */
17076static int
17077mg_get_system_info_impl(char *buffer, int buflen)
17078{
17079 char block[256];
17080 int system_info_length = 0;
17081
17082#if defined(_WIN32)
17083 const char *eol = "\r\n";
17084#else
17085 const char *eol = "\n";
17086#endif
17087
17088 const char *eoobj = "}";
17089 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
17090
17091 if ((buffer == NULL) || (buflen < 1)) {
17092 buflen = 0;
17093 } else {
17094 *buffer = 0;
17095 }
17096
17097 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
17098 system_info_length += (int)strlen(block);
17099 if (system_info_length < buflen) {
17100 strcat0(buffer, block);
17101 }
17102
17103 /* Server version */
17104 {
17105 const char *version = mg_version();
17106 mg_snprintf(NULL,
17107 NULL,
17108 block,
17109 sizeof(block),
17110 "\"version\" : \"%s\",%s",
17111 version,
17112 eol);
17113 system_info_length += (int)strlen(block);
17114 if (system_info_length < buflen) {
17115 strcat0(buffer, block);
17116 }
17117 }
17118
17119 /* System info */
17120 {
17121#if defined(_WIN32)
17122#if !defined(__SYMBIAN32__)
17123 DWORD dwVersion = 0;
17124 DWORD dwMajorVersion = 0;
17125 DWORD dwMinorVersion = 0;
17126 SYSTEM_INFO si;
17127
17128 GetSystemInfo(&si);
17129
17130#ifdef _MSC_VER
17131#pragma warning(push)
17132/* GetVersion was declared deprecated */
17133#pragma warning(disable : 4996)
17134#endif
17135 dwVersion = GetVersion();
17136#ifdef _MSC_VER
17137#pragma warning(pop)
17138#endif
17139
17140 dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
17141 dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
17142
17143 mg_snprintf(NULL,
17144 NULL,
17145 block,
17146 sizeof(block),
17147 "\"os\" : \"Windows %u.%u\",%s",
17148 (unsigned)dwMajorVersion,
17149 (unsigned)dwMinorVersion,
17150 eol);
17151 system_info_length += (int)strlen(block);
17152 if (system_info_length < buflen) {
17153 strcat0(buffer, block);
17154 }
17155
17156 mg_snprintf(NULL,
17157 NULL,
17158 block,
17159 sizeof(block),
17160 "\"cpu\" : \"type %u, cores %u, mask %x\",%s",
17161 (unsigned)si.wProcessorArchitecture,
17162 (unsigned)si.dwNumberOfProcessors,
17163 (unsigned)si.dwActiveProcessorMask,
17164 eol);
17165 system_info_length += (int)strlen(block);
17166 if (system_info_length < buflen) {
17167 strcat0(buffer, block);
17168 }
17169
17170#else
17171 mg_snprintf(NULL, NULL, block, sizeof(block), "%s - Symbian%s", eol);
17172 system_info_length += (int)strlen(block);
17173 if (system_info_length < buflen) {
17174 strcat0(buffer, block);
17175 }
17176#endif
17177#else
17178 struct utsname name;
17179 memset(&name, 0, sizeof(name));
17180 uname(&name);
17181
17182 mg_snprintf(NULL,
17183 NULL,
17184 block,
17185 sizeof(block),
17186 "\"os\" : \"%s %s (%s) - %s\",%s",
17187 name.sysname,
17188 name.version,
17189 name.release,
17190 name.machine,
17191 eol);
17192 system_info_length += (int)strlen(block);
17193 if (system_info_length < buflen) {
17194 strcat0(buffer, block);
17195 }
17196#endif
17197 }
17198
17199 /* Features */
17200 {
17201 mg_snprintf(NULL,
17202 NULL,
17203 block,
17204 sizeof(block),
17205 "\"features\" : %lu,%s"
17206 "\"feature_list\" : \"Server:%s%s%s%s%s%s%s%s%s\",%s",
17207 (unsigned long)mg_check_feature(0xFFFFFFFFu),
17208 eol,
17209 mg_check_feature(1) ? " Files" : "",
17210 mg_check_feature(2) ? " HTTPS" : "",
17211 mg_check_feature(4) ? " CGI" : "",
17212 mg_check_feature(8) ? " IPv6" : "",
17213 mg_check_feature(16) ? " WebSockets" : "",
17214 mg_check_feature(32) ? " Lua" : "",
17215 mg_check_feature(64) ? " JavaScript" : "",
17216 mg_check_feature(128) ? " Cache" : "",
17217 mg_check_feature(256) ? " Stats" : "",
17218 eol);
17219 system_info_length += (int)strlen(block);
17220 if (system_info_length < buflen) {
17221 strcat0(buffer, block);
17222 }
17223
17224#ifdef USE_LUA
17225 mg_snprintf(NULL,
17226 NULL,
17227 block,
17228 sizeof(block),
17229 "\"lua_version\" : \"%u (%s)\",%s",
17230 (unsigned)LUA_VERSION_NUM,
17231 LUA_RELEASE,
17232 eol);
17233 system_info_length += (int)strlen(block);
17234 if (system_info_length < buflen) {
17235 strcat0(buffer, block);
17236 }
17237#endif
17238#if defined(USE_DUKTAPE)
17239 mg_snprintf(NULL,
17240 NULL,
17241 block,
17242 sizeof(block),
17243 "\"javascript\" : \"Duktape %u.%u.%u\",%s",
17244 (unsigned)DUK_VERSION / 10000,
17245 ((unsigned)DUK_VERSION / 100) % 100,
17246 (unsigned)DUK_VERSION % 100,
17247 eol);
17248 system_info_length += (int)strlen(block);
17249 if (system_info_length < buflen) {
17250 strcat0(buffer, block);
17251 }
17252#endif
17253 }
17254
17255 /* Build date */
17256 {
17257#if defined(__GNUC__)
17258#pragma GCC diagnostic push
17259/* Disable bogus compiler warning -Wdate-time */
17260#pragma GCC diagnostic ignored "-Wall"
17261#pragma GCC diagnostic ignored "-Werror"
17262#endif
17263 mg_snprintf(NULL,
17264 NULL,
17265 block,
17266 sizeof(block),
17267 "\"build\" : \"%s\",%s",
17268 __DATE__,
17269 eol);
17270
17271#if defined(__GNUC__)
17272#pragma GCC diagnostic pop
17273#endif
17274
17275 system_info_length += (int)strlen(block);
17276 if (system_info_length < buflen) {
17277 strcat0(buffer, block);
17278 }
17279 }
17280
17281
17282 /* Compiler information */
17283 /* http://sourceforge.net/p/predef/wiki/Compilers/ */
17284 {
17285#if defined(_MSC_VER)
17286 mg_snprintf(NULL,
17287 NULL,
17288 block,
17289 sizeof(block),
17290 "\"compiler\" : \"MSC: %u (%u)\",%s",
17291 (unsigned)_MSC_VER,
17292 (unsigned)_MSC_FULL_VER,
17293 eol);
17294 system_info_length += (int)strlen(block);
17295 if (system_info_length < buflen) {
17296 strcat0(buffer, block);
17297 }
17298#elif defined(__MINGW64__)
17299 mg_snprintf(NULL,
17300 NULL,
17301 block,
17302 sizeof(block),
17303 "\"compiler\" : \"MinGW64: %u.%u\",%s",
17304 (unsigned)__MINGW64_VERSION_MAJOR,
17305 (unsigned)__MINGW64_VERSION_MINOR,
17306 eol);
17307 system_info_length += (int)strlen(block);
17308 if (system_info_length < buflen) {
17309 strcat0(buffer, block);
17310 }
17311 mg_snprintf(NULL,
17312 NULL,
17313 block,
17314 sizeof(block),
17315 "\"compiler\" : \"MinGW32: %u.%u\",%s",
17316 (unsigned)__MINGW32_MAJOR_VERSION,
17317 (unsigned)__MINGW32_MINOR_VERSION,
17318 eol);
17319 system_info_length += (int)strlen(block);
17320 if (system_info_length < buflen) {
17321 strcat0(buffer, block);
17322 }
17323#elif defined(__MINGW32__)
17324 mg_snprintf(NULL,
17325 NULL,
17326 block,
17327 sizeof(block),
17328 "\"compiler\" : \"MinGW32: %u.%u\",%s",
17329 (unsigned)__MINGW32_MAJOR_VERSION,
17330 (unsigned)__MINGW32_MINOR_VERSION,
17331 eol);
17332 system_info_length += (int)strlen(block);
17333 if (system_info_length < buflen) {
17334 strcat0(buffer, block);
17335 }
17336#elif defined(__clang__)
17337 mg_snprintf(NULL,
17338 NULL,
17339 block,
17340 sizeof(block),
17341 "\"compiler\" : \"clang: %u.%u.%u (%s)\",%s",
17342 __clang_major__,
17343 __clang_minor__,
17344 __clang_patchlevel__,
17345 __clang_version__,
17346 eol);
17347 system_info_length += (int)strlen(block);
17348 if (system_info_length < buflen) {
17349 strcat0(buffer, block);
17350 }
17351#elif defined(__GNUC__)
17352 mg_snprintf(NULL,
17353 NULL,
17354 block,
17355 sizeof(block),
17356 "\"compiler\" : \"gcc: %u.%u.%u\",%s",
17357 (unsigned)__GNUC__,
17358 (unsigned)__GNUC_MINOR__,
17359 (unsigned)__GNUC_PATCHLEVEL__,
17360 eol);
17361 system_info_length += (int)strlen(block);
17362 if (system_info_length < buflen) {
17363 strcat0(buffer, block);
17364 }
17365#elif defined(__INTEL_COMPILER)
17366 mg_snprintf(NULL,
17367 NULL,
17368 block,
17369 sizeof(block),
17370 "\"compiler\" : \"Intel C/C++: %u\",%s",
17371 (unsigned)__INTEL_COMPILER,
17372 eol);
17373 system_info_length += (int)strlen(block);
17374 if (system_info_length < buflen) {
17375 strcat0(buffer, block);
17376 }
17377#elif defined(__BORLANDC__)
17378 mg_snprintf(NULL,
17379 NULL,
17380 block,
17381 sizeof(block),
17382 "\"compiler\" : \"Borland C: 0x%x\",%s",
17383 (unsigned)__BORLANDC__,
17384 eol);
17385 system_info_length += (int)strlen(block);
17386 if (system_info_length < buflen) {
17387 strcat0(buffer, block);
17388 }
17389#elif defined(__SUNPRO_C)
17390 mg_snprintf(NULL,
17391 NULL,
17392 block,
17393 sizeof(block),
17394 "\"compiler\" : \"Solaris: 0x%x\",%s",
17395 (unsigned)__SUNPRO_C,
17396 eol);
17397 system_info_length += (int)strlen(block);
17398 if (system_info_length < buflen) {
17399 strcat0(buffer, block);
17400 }
17401#else
17402 mg_snprintf(NULL,
17403 NULL,
17404 block,
17405 sizeof(block),
17406 "\"compiler\" : \"other\",%s",
17407 eol);
17408 system_info_length += (int)strlen(block);
17409 if (system_info_length < buflen) {
17410 strcat0(buffer, block);
17411 }
17412#endif
17413 }
17414
17415 /* Determine 32/64 bit data mode.
17416 * see https://en.wikipedia.org/wiki/64-bit_computing */
17417 {
17418 mg_snprintf(
17419 NULL,
17420 NULL,
17421 block,
17422 sizeof(block),
17423 "\"data_model\" : \"int:%u/%u/%u/%u, float:%u/%u/%u, char:%u/%u, "
17424 "ptr:%u, size:%u, time:%u\"%s",
17425 (unsigned)sizeof(short),
17426 (unsigned)sizeof(int),
17427 (unsigned)sizeof(long),
17428 (unsigned)sizeof(long long),
17429 (unsigned)sizeof(float),
17430 (unsigned)sizeof(double),
17431 (unsigned)sizeof(long double),
17432 (unsigned)sizeof(char),
17433 (unsigned)sizeof(wchar_t),
17434 (unsigned)sizeof(void *),
17435 (unsigned)sizeof(size_t),
17436 (unsigned)sizeof(time_t),
17437 eol);
17438 system_info_length += (int)strlen(block);
17439 if (system_info_length < buflen) {
17440 strcat0(buffer, block);
17441 }
17442 }
17443
17444 /* Terminate string */
17445 if ((buflen > 0) && buffer && buffer[0]) {
17446 if (system_info_length < buflen) {
17447 strcat0(buffer, eoobj);
17448 strcat0(buffer, eol);
17449 }
17450 }
17451 system_info_length += reserved_len;
17452
17453 return system_info_length;
17454}
17455
17456
17457#if defined(USE_SERVER_STATS)
17458/* Get context information. It can be printed or stored by the caller.
17459 * Return the size of available information. */
17460static int
17461mg_get_context_info_impl(const struct mg_context *ctx, char *buffer, int buflen)
17462
17463{
17464 char block[256];
17465 int context_info_length = 0;
17466
17467#if defined(_WIN32)
17468 const char *eol = "\r\n";
17469#else
17470 const char *eol = "\n";
17471#endif
17472 struct mg_memory_stat *ms = get_memory_stat((struct mg_context *)ctx);
17473
17474 const char *eoobj = "}";
17475 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
17476
17477 if ((buffer == NULL) || (buflen < 1)) {
17478 buflen = 0;
17479 } else {
17480 *buffer = 0;
17481 }
17482
17483 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
17484 context_info_length += (int)strlen(block);
17485 if (context_info_length < buflen) {
17486 strcat0(buffer, block);
17487 }
17488
17489 /* Memory information */
17490 if (ms) {
17491 mg_snprintf(NULL,
17492 NULL,
17493 block,
17494 sizeof(block),
17495 "\"memory\" : {%s"
17496 "\"blocks\" : %i,%s"
17497 "\"used\" : %" INT64_FMT ",%s"
17498 "\"maxUsed\" : %" INT64_FMT "%s"
17499 "}%s%s",
17500 eol,
17501 ms->blockCount,
17502 eol,
17503 ms->totalMemUsed,
17504 eol,
17505 ms->maxMemUsed,
17506 eol,
17507 (ctx ? "," : ""),
17508 eol);
17509
17510 context_info_length += (int)strlen(block);
17511 if (context_info_length + reserved_len < buflen) {
17512 strcat0(buffer, block);
17513 }
17514 }
17515
17516
17517 /* Connections information */
17518 if (ctx) {
17519 mg_snprintf(NULL,
17520 NULL,
17521 block,
17522 sizeof(block),
17523 "\"connections\" : {%s"
17524 "\"active\" : %i,%s"
17525 "\"maxActive\" : %i,%s"
17526 "\"total\" : %" INT64_FMT "%s"
17527 "},%s",
17528 eol,
17529 ctx->active_connections,
17530 eol,
17531 ctx->max_connections,
17532 eol,
17533 ctx->total_connections,
17534 eol,
17535 eol);
17536
17537 context_info_length += (int)strlen(block);
17538 if (context_info_length + reserved_len < buflen) {
17539 strcat0(buffer, block);
17540 }
17541 }
17542
17543 /* Requests information */
17544 if (ctx) {
17545 mg_snprintf(NULL,
17546 NULL,
17547 block,
17548 sizeof(block),
17549 "\"requests\" : {%s"
17550 "\"total\" : %" INT64_FMT "%s"
17551 "},%s",
17552 eol,
17553 ctx->total_requests,
17554 eol,
17555 eol);
17556
17557 context_info_length += (int)strlen(block);
17558 if (context_info_length + reserved_len < buflen) {
17559 strcat0(buffer, block);
17560 }
17561 }
17562
17563 /* Data information */
17564 if (ctx) {
17565 mg_snprintf(NULL,
17566 NULL,
17567 block,
17568 sizeof(block),
17569 "\"data\" : {%s"
17570 "\"read\" : %" INT64_FMT "%s,"
17571 "\"written\" : %" INT64_FMT "%s"
17572 "},%s",
17573 eol,
17574 ctx->total_data_read,
17575 eol,
17576 ctx->total_data_written,
17577 eol,
17578 eol);
17579
17580 context_info_length += (int)strlen(block);
17581 if (context_info_length + reserved_len < buflen) {
17582 strcat0(buffer, block);
17583 }
17584 }
17585
17586 /* Execution time information */
17587 if (ctx) {
17588 char start_time_str[64] = {0};
17589 char now_str[64] = {0};
17590 time_t start_time = ctx->start_time;
17591 time_t now = time(NULL);
17592
17593 gmt_time_string(start_time_str,
17594 sizeof(start_time_str) - 1,
17595 &start_time);
17596 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
17597
17598 mg_snprintf(NULL,
17599 NULL,
17600 block,
17601 sizeof(block),
17602 "\"time\" : {%s"
17603 "\"uptime\" : %.0f,%s"
17604 "\"start\" : \"%s\",%s"
17605 "\"now\" : \"%s\"%s"
17606 "}%s",
17607 eol,
17608 difftime(now, start_time),
17609 eol,
17610 start_time_str,
17611 eol,
17612 now_str,
17613 eol,
17614 eol);
17615
17616 context_info_length += (int)strlen(block);
17617 if (context_info_length + reserved_len < buflen) {
17618 strcat0(buffer, block);
17619 }
17620 }
17621
17622 /* Terminate string */
17623 if ((buflen > 0) && buffer && buffer[0]) {
17624 if (context_info_length < buflen) {
17625 strcat0(buffer, eoobj);
17626 strcat0(buffer, eol);
17627 }
17628 }
17629 context_info_length += reserved_len;
17630
17631 return context_info_length;
17632}
17633#endif
17634
17635
17636#ifdef MG_EXPERIMENTAL_INTERFACES
17637/* Get connection information. It can be printed or stored by the caller.
17638 * Return the size of available information. */
17639static int
17640mg_get_connection_info_impl(const struct mg_context *ctx,
17641 int idx,
17642 char *buffer,
17643 int buflen)
17644{
17645 const struct mg_connection *conn;
17646 const struct mg_request_info *ri;
17647 char block[256];
17648 int connection_info_length = 0;
17649 int state = 0;
17650 const char *state_str = "unknown";
17651
17652#if defined(_WIN32)
17653 const char *eol = "\r\n";
17654#else
17655 const char *eol = "\n";
17656#endif
17657
17658 const char *eoobj = "}";
17659 int reserved_len = (int)strlen(eoobj) + (int)strlen(eol);
17660
17661 if ((buffer == NULL) || (buflen < 1)) {
17662 buflen = 0;
17663 } else {
17664 *buffer = 0;
17665 }
17666
17667 if ((ctx == NULL) || (idx < 0)) {
17668 /* Parameter error */
17669 return 0;
17670 }
17671
17672 if ((unsigned)idx >= ctx->cfg_worker_threads) {
17673 /* Out of range */
17674 return 0;
17675 }
17676
17677 /* Take connection [idx]. This connection is not locked in
17678 * any way, so some other thread might use it. */
17679 conn = (ctx->worker_connections) + idx;
17680
17681 /* Initialize output string */
17682 mg_snprintf(NULL, NULL, block, sizeof(block), "{%s", eol);
17683 connection_info_length += (int)strlen(block);
17684 if (connection_info_length < buflen) {
17685 strcat0(buffer, block);
17686 }
17687
17688 /* Init variables */
17689 ri = &(conn->request_info);
17690
17691#if defined(USE_SERVER_STATS)
17692 state = conn->conn_state;
17693
17694 /* State as string */
17695 switch (state) {
17696 case 0:
17697 state_str = "undefined";
17698 break;
17699 case 1:
17700 state_str = "not used";
17701 break;
17702 case 2:
17703 state_str = "init";
17704 break;
17705 case 3:
17706 state_str = "ready";
17707 break;
17708 case 4:
17709 state_str = "processing";
17710 break;
17711 case 5:
17712 state_str = "processed";
17713 break;
17714 case 6:
17715 state_str = "to close";
17716 break;
17717 case 7:
17718 state_str = "closing";
17719 break;
17720 case 8:
17721 state_str = "closed";
17722 break;
17723 case 9:
17724 state_str = "done";
17725 break;
17726 }
17727#endif
17728
17729 /* Connection info */
17730 if ((state >= 3) && (state < 9)) {
17731 mg_snprintf(NULL,
17732 NULL,
17733 block,
17734 sizeof(block),
17735 "\"connection\" : {%s"
17736 "\"remote\" : {%s"
17737 "\"protocol\" : \"%s\",%s"
17738 "\"addr\" : \"%s\",%s"
17739 "\"port\" : %u%s"
17740 "},%s"
17741 "\"handled_requests\" : %u%s"
17742 "},%s",
17743 eol,
17744 eol,
17745 get_proto_name(conn),
17746 eol,
17747 ri->remote_addr,
17748 eol,
17749 ri->remote_port,
17750 eol,
17751 eol,
17752 conn->handled_requests,
17753 eol,
17754 eol);
17755
17756 connection_info_length += (int)strlen(block);
17757 if (connection_info_length + reserved_len < buflen) {
17758 strcat0(buffer, block);
17759 }
17760 }
17761
17762 /* Request info */
17763 if ((state >= 4) && (state < 6)) {
17764 mg_snprintf(NULL,
17765 NULL,
17766 block,
17767 sizeof(block),
17768 "\"request_info\" : {%s"
17769 "\"method\" : \"%s\",%s"
17770 "\"uri\" : \"%s\",%s"
17771 "\"query\" : %s%s%s%s"
17772 "},%s",
17773 eol,
17774 ri->request_method,
17775 eol,
17776 ri->request_uri,
17777 eol,
17778 ri->query_string ? "\"" : "",
17779 ri->query_string ? ri->query_string : "null",
17780 ri->query_string ? "\"" : "",
17781 eol,
17782 eol);
17783
17784 connection_info_length += (int)strlen(block);
17785 if (connection_info_length + reserved_len < buflen) {
17786 strcat0(buffer, block);
17787 }
17788 }
17789
17790 /* Execution time information */
17791 if ((state >= 2) && (state < 9)) {
17792 char start_time_str[64] = {0};
17793 char now_str[64] = {0};
17794 time_t start_time = conn->conn_birth_time;
17795 time_t now = time(NULL);
17796
17797 gmt_time_string(start_time_str,
17798 sizeof(start_time_str) - 1,
17799 &start_time);
17800 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
17801
17802 mg_snprintf(NULL,
17803 NULL,
17804 block,
17805 sizeof(block),
17806 "\"time\" : {%s"
17807 "\"uptime\" : %.0f,%s"
17808 "\"start\" : \"%s\",%s"
17809 "\"now\" : \"%s\"%s"
17810 "},%s",
17811 eol,
17812 difftime(now, start_time),
17813 eol,
17814 start_time_str,
17815 eol,
17816 now_str,
17817 eol,
17818 eol);
17819
17820 connection_info_length += (int)strlen(block);
17821 if (connection_info_length + reserved_len < buflen) {
17822 strcat0(buffer, block);
17823 }
17824 }
17825
17826 /* Remote user name */
17827 if ((ri->remote_user) && (state < 9)) {
17828 mg_snprintf(NULL,
17829 NULL,
17830 block,
17831 sizeof(block),
17832 "\"user\" : {%s"
17833 "\"name\" : \"%s\",%s"
17834 "},%s",
17835 eol,
17836 ri->remote_user,
17837 eol,
17838 eol);
17839
17840 connection_info_length += (int)strlen(block);
17841 if (connection_info_length + reserved_len < buflen) {
17842 strcat0(buffer, block);
17843 }
17844 }
17845
17846 /* Data block */
17847 if (state >= 3) {
17848 mg_snprintf(NULL,
17849 NULL,
17850 block,
17851 sizeof(block),
17852 "\"data\" : {%s"
17853 "\"read\" : %" INT64_FMT ",%s"
17854 "\"written\" : %" INT64_FMT "%s"
17855 "},%s",
17856 eol,
17857 conn->consumed_content,
17858 eol,
17859 conn->num_bytes_sent,
17860 eol,
17861 eol);
17862
17863 connection_info_length += (int)strlen(block);
17864 if (connection_info_length + reserved_len < buflen) {
17865 strcat0(buffer, block);
17866 }
17867 }
17868
17869 /* State */
17870 mg_snprintf(NULL,
17871 NULL,
17872 block,
17873 sizeof(block),
17874 "\"state\" : \"%s\"%s",
17875 state_str,
17876 eol);
17877
17878 connection_info_length += (int)strlen(block);
17879 if (connection_info_length + reserved_len < buflen) {
17880 strcat0(buffer, block);
17881 }
17882
17883 /* Terminate string */
17884 if ((buflen > 0) && buffer && buffer[0]) {
17885 if (connection_info_length < buflen) {
17886 strcat0(buffer, eoobj);
17887 strcat0(buffer, eol);
17888 }
17889 }
17890 connection_info_length += reserved_len;
17891
17892 return connection_info_length;
17893}
17894#endif
17895
17896
17897/* Get system information. It can be printed or stored by the caller.
17898 * Return the size of available information. */
17899int
17900mg_get_system_info(char *buffer, int buflen)
17901{
17902 if ((buffer == NULL) || (buflen < 1)) {
17903 return mg_get_system_info_impl(NULL, 0);
17904 } else {
17905 /* Reset buffer, so we can always use strcat. */
17906 buffer[0] = 0;
17907 return mg_get_system_info_impl(buffer, buflen);
17908 }
17909}
17910
17911
17912/* Get context information. It can be printed or stored by the caller.
17913 * Return the size of available information. */
17914int
17915mg_get_context_info(const struct mg_context *ctx, char *buffer, int buflen)
17916{
17917#if defined(USE_SERVER_STATS)
17918 if ((buffer == NULL) || (buflen < 1)) {
17919 return mg_get_context_info_impl(ctx, NULL, 0);
17920 } else {
17921 /* Reset buffer, so we can always use strcat. */
17922 buffer[0] = 0;
17923 return mg_get_context_info_impl(ctx, buffer, buflen);
17924 }
17925#else
17926 (void)ctx;
17927 if ((buffer != NULL) && (buflen > 0)) {
17928 buffer[0] = 0;
17929 }
17930 return 0;
17931#endif
17932}
17933
17934
17935#ifdef MG_EXPERIMENTAL_INTERFACES
17936int
17937mg_get_connection_info(const struct mg_context *ctx,
17938 int idx,
17939 char *buffer,
17940 int buflen)
17941{
17942 if ((buffer == NULL) || (buflen < 1)) {
17943 return mg_get_connection_info_impl(ctx, idx, NULL, 0);
17944 } else {
17945 /* Reset buffer, so we can always use strcat. */
17946 buffer[0] = 0;
17947 return mg_get_connection_info_impl(ctx, idx, buffer, buflen);
17948 }
17949}
17950#endif
17951
17952
17953/* Initialize this library. This function does not need to be thread safe.
17954 */
17955unsigned
17956mg_init_library(unsigned features)
17957{
17958#if !defined(NO_SSL)
17959 char ebuf[128];
17960#endif
17961
17962 unsigned features_to_init = mg_check_feature(features & 0xFFu);
17963 unsigned features_inited = features_to_init;
17964
17965 if (mg_init_library_called <= 0) {
17966 /* Not initialized yet */
17967 if (0 != pthread_mutex_init(&global_lock_mutex, NULL)) {
17968 return 0;
17969 }
17970 }
17971
17972 mg_global_lock();
17973
17974 if (mg_init_library_called <= 0) {
17975 if (0 != pthread_key_create(&sTlsKey, tls_dtor)) {
17976 /* Fatal error - abort start. However, this situation should
17977 * never occur in practice. */
17978 return 0;
17979 }
17980
17981#if defined(_WIN32) && !defined(__SYMBIAN32__)
17982 InitializeCriticalSection(&global_log_file_lock);
17983#endif /* _WIN32 && !__SYMBIAN32__ */
17984#if !defined(_WIN32)
17985 pthread_mutexattr_init(&pthread_mutex_attr);
17986 pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
17987#endif
17988
17989#if defined(USE_LUA)
17990 lua_init_optional_libraries();
17991#endif
17992 }
17993
17994
17995#if !defined(NO_SSL)
17996 if (features_to_init & 2) {
17997 if (!mg_ssl_initialized) {
17998 if (initialize_ssl(ebuf, sizeof(ebuf))) {
17999 mg_ssl_initialized = 1;
18000 } else {
18001 (void)ebuf;
18002 /* TODO: print error */
18003 features_inited &= ~(2u);
18004 }
18005 } else {
18006 /* ssl already initialized */
18007 }
18008 }
18009#endif
18010
18011 /* Start WinSock for Windows */
18012 if (mg_init_library_called <= 0) {
18013#if defined(_WIN32) && !defined(__SYMBIAN32__)
18014 WSADATA data;
18015 WSAStartup(MAKEWORD(2, 2), &data);
18016#endif /* _WIN32 && !__SYMBIAN32__ */
18017 mg_init_library_called = 1;
18018 } else {
18019 mg_init_library_called++;
18020 }
18021
18022 mg_global_unlock();
18023
18024 return features_inited;
18025}
18026
18027
18028/* Un-initialize this library. */
18029unsigned
18030mg_exit_library(void)
18031{
18032 if (mg_init_library_called <= 0) {
18033 return 0;
18034 }
18035
18036 mg_global_lock();
18037
18038 mg_init_library_called--;
18039 if (mg_init_library_called == 0) {
18040#if defined(_WIN32) && !defined(__SYMBIAN32__)
18041 (void)WSACleanup();
18042#endif /* _WIN32 && !__SYMBIAN32__ */
18043#if !defined(NO_SSL)
18044 if (mg_ssl_initialized) {
18045 uninitialize_ssl();
18046 mg_ssl_initialized = 0;
18047 }
18048#endif
18049
18050#if defined(_WIN32) && !defined(__SYMBIAN32__)
18051 (void)DeleteCriticalSection(&global_log_file_lock);
18052#endif /* _WIN32 && !__SYMBIAN32__ */
18053#if !defined(_WIN32)
18054 (void)pthread_mutexattr_destroy(&pthread_mutex_attr);
18055#endif
18056
18057 (void)pthread_key_delete(sTlsKey);
18058
18059#if defined(USE_LUA)
18060 lua_exit_optional_libraries();
18061#endif
18062
18063 mg_global_unlock();
18064 (void)pthread_mutex_destroy(&global_lock_mutex);
18065 return 1;
18066 }
18067
18068 mg_global_unlock();
18069 return 1;
18070}
18071
18072
18073/* End of civetweb.c */