1 /* Copyright (c) 2013-2016 the Civetweb developers
2 * Copyright (c) 2004-2013 Sergey Lyubka
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
25 #if !defined(_CRT_SECURE_NO_WARNINGS)
26 #define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
28 #ifndef _WIN32_WINNT /* defined for tdm-gcc so we can use getnameinfo */
29 #define _WIN32_WINNT 0x0501
32 #if defined(__GNUC__) && !defined(_GNU_SOURCE)
33 #define _GNU_SOURCE /* for setgroups() */
35 #if defined(__linux__) && !defined(_XOPEN_SOURCE)
36 #define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
38 #ifndef _LARGEFILE_SOURCE
39 #define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
41 #ifndef _FILE_OFFSET_BITS
42 #define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
44 #ifndef __STDC_FORMAT_MACROS
45 #define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
47 #ifndef __STDC_LIMIT_MACROS
48 #define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
51 #define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
52 #define __inline inline /* not recognized on older compiler versions */
56 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
61 /* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
62 #pragma warning(disable : 4306)
63 /* conditional expression is constant: introduced by FD_SET(..) */
64 #pragma warning(disable : 4127)
65 /* non-constant aggregate initializer: issued due to missing C99 support */
66 #pragma warning(disable : 4204)
67 /* padding added after data member */
68 #pragma warning(disable : 4820)
69 /* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
70 #pragma warning(disable : 4668)
71 /* no function prototype given: converting '()' to '(void)' */
72 #pragma warning(disable : 4255)
73 /* function has been selected for automatic inline expansion */
74 #pragma warning(disable : 4711)
78 /* This code uses static_assert to check some conditions.
79 * Unfortunately some compilers still do not support it, so we have a
80 * replacement function here. */
81 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
82 #define mg_static_assert static_assert
83 #elif defined(__cplusplus) && (__cplusplus >= 201103L)
84 #define mg_static_assert static_assert
85 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
86 #define mg_static_assert _Static_assert
88 char static_assert_replacement
[1];
89 #define mg_static_assert(cond, txt) \
90 extern char static_assert_replacement[(cond) ? 1 : -1]
93 mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
94 "int data type size check");
95 mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
96 "pointer data type size check");
97 mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
98 /* mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t data
99 * type size check"); */
101 /* DTL -- including winsock2.h works better if lean and mean */
102 #ifndef WIN32_LEAN_AND_MEAN
103 #define WIN32_LEAN_AND_MEAN
106 #if defined(__SYMBIAN32__)
107 #define NO_SSL /* SSL is not supported */
108 #define NO_CGI /* CGI is not supported */
109 #define PATH_MAX FILENAME_MAX
110 #endif /* __SYMBIAN32__ */
113 /* Include the header file here, so the CivetWeb interface is defined for the
114 * entire implementation, including the following forward definitions. */
115 #include "civetweb.h"
118 #ifndef IGNORE_UNUSED_RESULT
119 #define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
122 #ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
123 #include <sys/types.h>
124 #include <sys/stat.h>
128 #endif /* !_WIN32_WCE */
132 #define CLOCK_MONOTONIC (1)
133 #define CLOCK_REALTIME (2)
135 #include <sys/time.h>
136 #include <mach/clock.h>
137 #include <mach/mach.h>
138 #include <mach/mach_time.h>
142 /* clock_gettime is not implemented on OSX */
143 int clock_gettime(int clk_id
, struct timespec
*t
);
146 clock_gettime(int clk_id
, struct timespec
*t
)
148 memset(t
, 0, sizeof(*t
));
149 if (clk_id
== CLOCK_REALTIME
) {
151 int rv
= gettimeofday(&now
, NULL
);
155 t
->tv_sec
= now
.tv_sec
;
156 t
->tv_nsec
= now
.tv_usec
* 1000;
159 } else if (clk_id
== CLOCK_MONOTONIC
) {
160 static uint64_t clock_start_time
= 0;
161 static mach_timebase_info_data_t timebase_ifo
= {0, 0};
163 uint64_t now
= mach_absolute_time();
165 if (clock_start_time
== 0) {
166 kern_return_t mach_status
= mach_timebase_info(&timebase_ifo
);
168 assert(mach_status
== KERN_SUCCESS
);
170 /* appease "unused variable" warning for release builds */
173 clock_start_time
= now
;
176 now
= (uint64_t)((double)(now
- clock_start_time
)
177 * (double)timebase_ifo
.numer
178 / (double)timebase_ifo
.denom
);
180 t
->tv_sec
= now
/ 1000000000;
181 t
->tv_nsec
= now
% 1000000000;
184 return -1; /* EINVAL - Clock ID is unknown */
200 #ifndef MAX_WORKER_THREADS
201 #define MAX_WORKER_THREADS (1024 * 64)
203 #ifndef SOCKET_TIMEOUT_QUANTUM
204 #define SOCKET_TIMEOUT_QUANTUM (10000)
207 mg_static_assert(MAX_WORKER_THREADS
>= 1,
208 "worker threads must be a positive number");
210 #if defined(_WIN32) \
211 && !defined(__SYMBIAN32__) /* WINDOWS / UNIX include block */
213 #include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
214 #include <ws2tcpip.h>
216 typedef const char *SOCK_OPT_TYPE
;
218 #if !defined(PATH_MAX)
219 #define PATH_MAX (MAX_PATH)
222 #if !defined(PATH_MAX)
223 #define PATH_MAX (4096)
226 mg_static_assert(PATH_MAX
>= 1, "path length must be a positive number");
230 #define in_port_t u_short
238 #else /* _WIN32_WCE */
239 #define NO_CGI /* WinCE has no pipes */
243 #define errno ((int)(GetLastError()))
244 #define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
245 #endif /* _WIN32_WCE */
247 #define MAKEUQUAD(lo, hi) \
248 ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
249 #define RATE_DIFF (10000000) /* 100 nsecs */
250 #define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
251 #define SYS2UNIX_TIME(lo, hi) \
252 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
254 /* Visual Studio 6 does not know __func__ or __FUNCTION__
255 * The rest of MS compilers use __FUNCTION__, not C99 __func__
256 * Also use _strtoui64 on modern M$ compilers */
257 #if defined(_MSC_VER)
258 #if (_MSC_VER < 1300)
260 #define STR(x) STRX(x)
261 #define __func__ __FILE__ ":" STR(__LINE__)
262 #define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
263 #define strtoll(x, y, z) (_atoi64(x))
265 #define __func__ __FUNCTION__
266 #define strtoull(x, y, z) (_strtoui64(x, y, z))
267 #define strtoll(x, y, z) (_strtoi64(x, y, z))
269 #endif /* _MSC_VER */
271 #define ERRNO ((int)(GetLastError()))
274 #if defined(_WIN64) || defined(__MINGW64__)
275 #define SSL_LIB "ssleay64.dll"
276 #define CRYPTO_LIB "libeay64.dll"
278 #define SSL_LIB "ssleay32.dll"
279 #define CRYPTO_LIB "libeay32.dll"
282 #define O_NONBLOCK (0)
284 #define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
286 #if !defined(EWOULDBLOCK)
287 #define EWOULDBLOCK WSAEWOULDBLOCK
288 #endif /* !EWOULDBLOCK */
290 #define INT64_FMT "I64d"
291 #define UINT64_FMT "I64u"
293 #define WINCDECL __cdecl
296 #define SHUT_BOTH (2)
297 #define vsnprintf_impl _vsnprintf
298 #define access _access
299 #define mg_sleep(x) (Sleep(x))
301 #define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
303 #define popen(x, y) (_popen(x, y))
306 #define pclose(x) (_pclose(x))
308 #define close(x) (_close(x))
309 #define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
310 #define RTLD_LAZY (0)
311 #define fseeko(x, y, z) (_lseeki64(_fileno(x), (y), (z)) == -1 ? -1 : 0)
312 #define fdopen(x, y) (_fdopen((x), (y)))
313 #define write(x, y, z) (_write((x), (y), (unsigned)z))
314 #define read(x, y, z) (_read((x), (y), (unsigned)z))
315 #define flockfile(x) (EnterCriticalSection(&global_log_file_lock))
316 #define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock))
317 #define sleep(x) (Sleep((x)*1000))
318 #define rmdir(x) (_rmdir(x))
319 #define timegm(x) (_mkgmtime(x))
322 #define fileno(x) (_fileno(x))
323 #endif /* !fileno MINGW #defines fileno */
325 typedef HANDLE pthread_mutex_t
;
326 typedef DWORD pthread_key_t
;
327 typedef HANDLE pthread_t
;
329 CRITICAL_SECTION threadIdSec
;
330 int waitingthreadcount
; /* The number of threads queued. */
331 pthread_t
*waitingthreadhdls
; /* The thread handles. */
334 #ifndef __clockid_t_defined
335 typedef DWORD clockid_t
;
337 #ifndef CLOCK_MONOTONIC
338 #define CLOCK_MONOTONIC (1)
340 #ifndef CLOCK_REALTIME
341 #define CLOCK_REALTIME (2)
344 #if defined(_MSC_VER) && (_MSC_VER >= 1900)
345 #define _TIMESPEC_DEFINED
347 #ifndef _TIMESPEC_DEFINED
349 time_t tv_sec
; /* seconds */
350 long tv_nsec
; /* nanoseconds */
354 #define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
356 static int pthread_mutex_lock(pthread_mutex_t
*);
357 static int pthread_mutex_unlock(pthread_mutex_t
*);
358 static void path_to_unicode(const struct mg_connection
*conn
,
364 mg_fgets(char *buf
, size_t size
, struct file
*filep
, char **p
);
367 #if defined(HAVE_STDINT)
370 typedef unsigned char uint8_t;
371 typedef unsigned short uint16_t;
372 typedef unsigned int uint32_t;
373 typedef unsigned __int64
uint64_t;
374 typedef __int64
int64_t;
375 #define INT64_MAX (9223372036854775807)
376 #endif /* HAVE_STDINT */
378 /* POSIX dirent interface */
380 char d_name
[PATH_MAX
];
385 WIN32_FIND_DATAW info
;
386 struct dirent result
;
389 #if defined(_WIN32) && !defined(POLLIN)
396 #define POLLIN (0x0300)
400 /* Mark required libraries */
401 #if defined(_MSC_VER)
402 #pragma comment(lib, "Ws2_32.lib")
405 #else /* defined(_WIN32) && !defined(__SYMBIAN32__) - WINDOWS / UNIX include \
408 #include <sys/wait.h>
409 #include <sys/socket.h>
410 #include <sys/poll.h>
411 #include <netinet/in.h>
412 #include <arpa/inet.h>
413 #include <sys/time.h>
414 #include <sys/utsname.h>
416 #include <inttypes.h>
418 #include <netinet/tcp.h>
419 typedef const void *SOCK_OPT_TYPE
;
422 typedef unsigned short int in_port_t
;
429 #define vsnprintf_impl vsnprintf
431 #if !defined(NO_SSL_DL) && !defined(NO_SSL)
435 #if defined(__MACH__)
436 #define SSL_LIB "libssl.dylib"
437 #define CRYPTO_LIB "libcrypto.dylib"
439 #if !defined(SSL_LIB)
440 #define SSL_LIB "libssl.so"
442 #if !defined(CRYPTO_LIB)
443 #define CRYPTO_LIB "libcrypto.so"
448 #endif /* O_BINARY */
449 #define closesocket(a) (close(a))
450 #define mg_mkdir(conn, path, mode) (mkdir(path, mode))
451 #define mg_remove(conn, x) (remove(x))
452 #define mg_sleep(x) (usleep((x)*1000))
453 #define mg_opendir(conn, x) (opendir(x))
454 #define mg_closedir(x) (closedir(x))
455 #define mg_readdir(x) (readdir(x))
456 #define ERRNO (errno)
457 #define INVALID_SOCKET (-1)
458 #define INT64_FMT PRId64
459 #define UINT64_FMT PRIu64
464 /* HPUX 11 does not have monotonic, fall back to realtime */
465 #ifndef CLOCK_MONOTONIC
466 #define CLOCK_MONOTONIC CLOCK_REALTIME
469 /* HPUX defines socklen_t incorrectly as size_t which is 64bit on
470 * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
471 * the prototypes use int* rather than socklen_t* which matches the
472 * actual library expectation. When called with the wrong size arg
473 * accept() returns a zero client inet addr and check_acl() always
474 * fails. Since socklen_t is widely used below, just force replace
475 * their typedef with int. - DTL
477 #define socklen_t int
480 #endif /* defined(_WIN32) && !defined(__SYMBIAN32__) - WINDOWS / UNIX include \
483 /* va_copy should always be a macro, C99 and C++11 - DTL */
485 #define va_copy(x, y) ((x) = (y))
489 /* Create substitutes for POSIX functions in Win32. */
491 #if defined(__MINGW32__)
492 /* Show no warning in case system functions are not used. */
493 #pragma GCC diagnostic push
494 #pragma GCC diagnostic ignored "-Wunused-function"
498 static CRITICAL_SECTION global_log_file_lock
;
502 return GetCurrentThreadId();
509 void (*_ignored
)(void *) /* destructor not supported for Windows */
516 return (*key
!= TLS_OUT_OF_INDEXES
) ? 0 : -1;
523 pthread_key_delete(pthread_key_t key
)
525 return TlsFree(key
) ? 0 : 1;
530 pthread_setspecific(pthread_key_t key
, void *value
)
532 return TlsSetValue(key
, value
) ? 0 : 1;
537 pthread_getspecific(pthread_key_t key
)
539 return TlsGetValue(key
);
542 #if defined(__MINGW32__)
543 /* Enable unused function warning again */
544 #pragma GCC diagnostic pop
547 static struct pthread_mutex_undefined_struct
*pthread_mutex_attr
= NULL
;
549 static pthread_mutexattr_t pthread_mutex_attr
;
553 #define PASSWORDS_FILE_NAME ".htpasswd"
554 #define CGI_ENVIRONMENT_SIZE (4096)
555 #define MAX_CGI_ENVIR_VARS (256)
556 #define MG_BUF_LEN (8192)
558 #ifndef MAX_REQUEST_SIZE
559 #define MAX_REQUEST_SIZE (16384)
562 mg_static_assert(MAX_REQUEST_SIZE
>= 256,
563 "request size length must be a positive number");
565 #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
567 #if !defined(DEBUG_TRACE)
571 static void DEBUG_TRACE_FUNC(const char *func
,
573 PRINTF_FORMAT_STRING(const char *fmt
),
574 ...) PRINTF_ARGS(3, 4);
577 DEBUG_TRACE_FUNC(const char *func
, unsigned line
, const char *fmt
, ...)
581 printf("*** %lu.%p.%s.%u: ",
582 (unsigned long)time(NULL
),
583 (void *)pthread_self(),
594 #define DEBUG_TRACE(fmt, ...) \
595 DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
598 #define DEBUG_TRACE(fmt, ...) \
602 #endif /* DEBUG_TRACE */
604 #if defined(MEMORY_DEBUGGING)
605 unsigned long mg_memory_debug_blockCount
= 0;
606 unsigned long mg_memory_debug_totalMemUsed
= 0;
610 mg_malloc_ex(size_t size
, const char *file
, unsigned line
)
612 void *data
= malloc(size
+ sizeof(size_t));
617 *(size_t *)data
= size
;
618 mg_memory_debug_totalMemUsed
+= size
;
619 mg_memory_debug_blockCount
++;
620 memory
= (void *)(((char *)data
) + sizeof(size_t));
624 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
627 mg_memory_debug_totalMemUsed
,
628 mg_memory_debug_blockCount
,
632 OutputDebugStringA(mallocStr
);
634 DEBUG_TRACE("%s", mallocStr
);
642 mg_calloc_ex(size_t count
, size_t size
, const char *file
, unsigned line
)
644 void *data
= mg_malloc_ex(size
* count
, file
, line
);
646 memset(data
, 0, size
);
653 mg_free_ex(void *memory
, const char *file
, unsigned line
)
656 void *data
= (void *)(((char *)memory
) - sizeof(size_t));
660 size
= *(size_t *)data
;
661 mg_memory_debug_totalMemUsed
-= size
;
662 mg_memory_debug_blockCount
--;
664 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
667 mg_memory_debug_totalMemUsed
,
668 mg_memory_debug_blockCount
,
672 OutputDebugStringA(mallocStr
);
674 DEBUG_TRACE("%s", mallocStr
);
683 mg_realloc_ex(void *memory
, size_t newsize
, const char *file
, unsigned line
)
692 data
= (void *)(((char *)memory
) - sizeof(size_t));
693 oldsize
= *(size_t *)data
;
694 _realloc
= realloc(data
, newsize
+ sizeof(size_t));
697 mg_memory_debug_totalMemUsed
-= oldsize
;
699 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
701 (unsigned long)oldsize
,
702 mg_memory_debug_totalMemUsed
,
703 mg_memory_debug_blockCount
,
707 OutputDebugStringA(mallocStr
);
709 DEBUG_TRACE("%s", mallocStr
);
711 mg_memory_debug_totalMemUsed
+= newsize
;
713 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
715 (unsigned long)newsize
,
716 mg_memory_debug_totalMemUsed
,
717 mg_memory_debug_blockCount
,
721 OutputDebugStringA(mallocStr
);
723 DEBUG_TRACE("%s", mallocStr
);
725 *(size_t *)data
= newsize
;
726 data
= (void *)(((char *)data
) + sizeof(size_t));
729 OutputDebugStringA("MEM: realloc failed\n");
731 DEBUG_TRACE("%s", "MEM: realloc failed\n");
736 data
= mg_malloc_ex(newsize
, file
, line
);
740 mg_free_ex(memory
, file
, line
);
746 #define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__)
747 #define mg_calloc(a, b) mg_calloc_ex(a, b, __FILE__, __LINE__)
748 #define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__)
749 #define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
753 static __inline
void *
759 static __inline
void *
760 mg_calloc(size_t a
, size_t b
)
765 static __inline
void *
766 mg_realloc(void *a
, size_t b
)
768 return realloc(a
, b
);
780 static void mg_vsnprintf(const struct mg_connection
*conn
,
787 static void mg_snprintf(const struct mg_connection
*conn
,
791 PRINTF_FORMAT_STRING(const char *fmt
),
792 ...) PRINTF_ARGS(5, 6);
794 /* This following lines are just meant as a reminder to use the mg-functions
795 * for memory management */
814 #define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
815 #define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
816 #define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
817 #define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
818 #define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
819 #ifdef _WIN32 /* vsnprintf must not be used in any system, * \
820 * but this define only works well for Windows. */
821 #define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
824 #define MD5_STATIC static
827 /* Darwin prior to 7.0 and Win32 do not have socklen_t */
829 typedef int socklen_t
;
830 #endif /* NO_SOCKLEN_T */
831 #define _DARWIN_UNLIMITED_SELECT
833 #define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
835 #if !defined(MSG_NOSIGNAL)
836 #define MSG_NOSIGNAL (0)
839 #if !defined(SOMAXCONN)
840 #define SOMAXCONN (100)
843 /* Size of the accepted socket queue */
844 #if !defined(MGSQLEN)
848 #if defined(NO_SSL_DL)
849 #include <openssl/ssl.h>
850 #include <openssl/err.h>
851 #include <openssl/crypto.h>
852 #include <openssl/x509.h>
853 #include <openssl/pem.h>
855 /* SSL loaded dynamically from DLL.
856 * I put the prototypes here to be independent from OpenSSL source
859 typedef struct ssl_st SSL
;
860 typedef struct ssl_method_st SSL_METHOD
;
861 typedef struct ssl_ctx_st SSL_CTX
;
862 typedef struct x509_store_ctx_st X509_STORE_CTX
;
864 #define SSL_CTRL_OPTIONS (32)
865 #define SSL_CTRL_CLEAR_OPTIONS (77)
866 #define SSL_CTRL_SET_ECDH_AUTO (94)
868 #define SSL_VERIFY_NONE (0)
869 #define SSL_VERIFY_PEER (1)
870 #define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
871 #define SSL_VERIFY_CLIENT_ONCE (4)
872 #define SSL_OP_ALL ((long)(0x80000BFFUL))
873 #define SSL_OP_NO_SSLv2 (0x01000000L)
874 #define SSL_OP_NO_SSLv3 (0x02000000L)
875 #define SSL_OP_NO_TLSv1 (0x04000000L)
876 #define SSL_OP_NO_TLSv1_2 (0x08000000L)
877 #define SSL_OP_NO_TLSv1_1 (0x10000000L)
878 #define SSL_OP_SINGLE_DH_USE (0x00100000L)
881 const char *name
; /* SSL function name */
882 void (*ptr
)(void); /* Function pointer */
885 #define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
886 #define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
887 #define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
888 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
889 #define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
890 #define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
891 #define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
892 #define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr)
893 #define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr)
894 #define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr)
895 #define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
896 #define SSL_CTX_use_PrivateKey_file \
897 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
898 #define SSL_CTX_use_certificate_file \
899 (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
900 #define SSL_CTX_set_default_passwd_cb \
901 (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
902 #define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
903 #define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
904 #define SSL_CTX_use_certificate_chain_file \
905 (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
906 #define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr)
907 #define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
908 #define SSL_CTX_set_verify \
909 (*(void (*)(SSL_CTX *, \
911 int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr)
912 #define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
913 #define SSL_CTX_load_verify_locations \
914 (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
915 #define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
916 #define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
917 #define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr)
918 #define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
919 #define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr)
920 #define SSL_CIPHER_get_name \
921 (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
922 #define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
923 #define SSL_CTX_set_session_id_context \
924 (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
925 #define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
926 #define SSL_CTX_set_cipher_list \
927 (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
928 #define SSL_CTX_set_options(ctx, op) \
929 SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
930 #define SSL_CTX_clear_options(ctx, op) \
931 SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
932 #define SSL_CTX_set_ecdh_auto(ctx, onoff) \
933 SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
935 #define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
936 #define CRYPTO_set_locking_callback \
937 (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
938 #define CRYPTO_set_id_callback \
939 (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
940 #define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
941 #define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
942 #define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
943 #define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
944 #define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
945 #define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
946 #define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
947 #define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
950 /* set_ssl_option() function updates this array.
951 * It loads SSL library dynamically and changes NULLs to the actual addresses
952 * of respective functions. The macros above (like SSL_connect()) are really
953 * just calling these functions indirectly via the pointer. */
954 static struct ssl_func ssl_sw
[] = {{"SSL_free", NULL
},
955 {"SSL_accept", NULL
},
956 {"SSL_connect", NULL
},
959 {"SSL_get_error", NULL
},
960 {"SSL_set_fd", NULL
},
962 {"SSL_CTX_new", NULL
},
963 {"SSLv23_server_method", NULL
},
964 {"SSL_library_init", NULL
},
965 {"SSL_CTX_use_PrivateKey_file", NULL
},
966 {"SSL_CTX_use_certificate_file", NULL
},
967 {"SSL_CTX_set_default_passwd_cb", NULL
},
968 {"SSL_CTX_free", NULL
},
969 {"SSL_load_error_strings", NULL
},
970 {"SSL_CTX_use_certificate_chain_file", NULL
},
971 {"SSLv23_client_method", NULL
},
972 {"SSL_pending", NULL
},
973 {"SSL_CTX_set_verify", NULL
},
974 {"SSL_shutdown", NULL
},
975 {"SSL_CTX_load_verify_locations", NULL
},
976 {"SSL_CTX_set_default_verify_paths", NULL
},
977 {"SSL_CTX_set_verify_depth", NULL
},
978 {"SSL_get_peer_certificate", NULL
},
979 {"SSL_get_version", NULL
},
980 {"SSL_get_current_cipher", NULL
},
981 {"SSL_CIPHER_get_name", NULL
},
982 {"SSL_CTX_check_private_key", NULL
},
983 {"SSL_CTX_set_session_id_context", NULL
},
984 {"SSL_CTX_ctrl", NULL
},
985 {"SSL_CTX_set_cipher_list", NULL
},
989 /* Similar array as ssl_sw. These functions could be located in different
992 static struct ssl_func crypto_sw
[] = {{"CRYPTO_num_locks", NULL
},
993 {"CRYPTO_set_locking_callback", NULL
},
994 {"CRYPTO_set_id_callback", NULL
},
995 {"ERR_get_error", NULL
},
996 {"ERR_error_string", NULL
},
997 {"ERR_remove_state", NULL
},
998 {"ERR_free_strings", NULL
},
999 {"ENGINE_cleanup", NULL
},
1000 {"CONF_modules_unload", NULL
},
1001 {"CRYPTO_cleanup_all_ex_data", NULL
},
1002 {"EVP_cleanup", NULL
},
1005 #endif /* NO_SSL_DL */
1008 #if !defined(NO_CACHING)
1009 static const char *month_names
[] = {"Jan",
1021 #endif /* !NO_CACHING */
1023 /* Unified socket address. For IPv6 support, add IPv6 address structure in the
1027 struct sockaddr_in sin
;
1028 #if defined(USE_IPV6)
1029 struct sockaddr_in6 sin6
;
1033 /* Describes a string (chunk of memory). */
1041 time_t last_modified
;
1043 const char *membuf
; /* Non-NULL if file data is in memory */
1045 int gzipped
; /* set to 1 if the content is gzipped
1046 * in which case we need a content-encoding: gzip header */
1049 #define STRUCT_FILE_INITIALIZER \
1051 (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 \
1054 /* Describes listening socket, or socket which was accept()-ed by the master
1055 * thread and queued for future handling by the worker thread. */
1057 SOCKET sock
; /* Listening socket */
1058 union usa lsa
; /* Local socket address */
1059 union usa rsa
; /* Remote socket address */
1060 unsigned char is_ssl
; /* Is port SSL-ed */
1061 unsigned char ssl_redir
; /* Is port supposed to redirect everything to SSL
1065 /* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
1069 PUT_DELETE_PASSWORDS_FILE
,
1072 AUTHENTICATION_DOMAIN
,
1073 ENABLE_AUTH_DOMAIN_CHECK
,
1077 ENABLE_DIRECTORY_LISTING
,
1079 GLOBAL_PASSWORDS_FILE
,
1082 ACCESS_CONTROL_LIST
,
1096 SSL_DEFAULT_VERIFY_PATHS
,
1098 SSL_PROTOCOL_VERSION
,
1100 #if defined(USE_WEBSOCKET)
1105 #if defined(USE_LUA)
1107 LUA_SCRIPT_EXTENSIONS
,
1108 LUA_SERVER_PAGE_EXTENSIONS
,
1110 #if defined(USE_DUKTAPE)
1111 DUKTAPE_SCRIPT_EXTENSIONS
,
1114 #if defined(USE_WEBSOCKET)
1117 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1118 LUA_WEBSOCKET_EXTENSIONS
,
1120 ACCESS_CONTROL_ALLOW_ORIGIN
,
1122 CONFIG_TCP_NODELAY
, /* Prepended CONFIG_ to avoid conflict with the
1123 * socket option typedef TCP_NODELAY. */
1124 #if !defined(NO_CACHING)
1125 STATIC_FILE_MAX_AGE
,
1127 VALIDATE_HTTP_METHOD
,
1128 CANONICALIZE_URL_PATH
,
1134 /* Config option name, config types, default value */
1135 static struct mg_option config_options
[] = {
1136 {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.cgi$|**.pl$|**.php$"},
1137 {"cgi_environment", CONFIG_TYPE_STRING
, NULL
},
1138 {"put_delete_auth_file", CONFIG_TYPE_FILE
, NULL
},
1139 {"cgi_interpreter", CONFIG_TYPE_FILE
, NULL
},
1140 {"protect_uri", CONFIG_TYPE_STRING
, NULL
},
1141 {"authentication_domain", CONFIG_TYPE_STRING
, "mydomain.com"},
1142 {"enable_auth_domain_check", CONFIG_TYPE_BOOLEAN
, "yes"},
1143 {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.shtml$|**.shtm$"},
1144 {"throttle", CONFIG_TYPE_STRING
, NULL
},
1145 {"access_log_file", CONFIG_TYPE_FILE
, NULL
},
1146 {"enable_directory_listing", CONFIG_TYPE_BOOLEAN
, "yes"},
1147 {"error_log_file", CONFIG_TYPE_FILE
, NULL
},
1148 {"global_auth_file", CONFIG_TYPE_FILE
, NULL
},
1152 "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,"
1153 "index.shtml,index.php"},
1155 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
1157 {"enable_keep_alive", CONFIG_TYPE_BOOLEAN
, "no"},
1158 {"access_control_list", CONFIG_TYPE_STRING
, NULL
},
1159 {"extra_mime_types", CONFIG_TYPE_STRING
, NULL
},
1160 {"listening_ports", CONFIG_TYPE_STRING
, "8080"},
1161 {"document_root", CONFIG_TYPE_DIRECTORY
, NULL
},
1162 {"ssl_certificate", CONFIG_TYPE_FILE
, NULL
},
1163 {"num_threads", CONFIG_TYPE_NUMBER
, "50"},
1164 {"run_as_user", CONFIG_TYPE_STRING
, NULL
},
1165 {"url_rewrite_patterns", CONFIG_TYPE_STRING
, NULL
},
1166 {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN
, NULL
},
1167 {"request_timeout_ms", CONFIG_TYPE_NUMBER
, "30000"},
1168 {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN
, "no"},
1169 {"ssl_ca_path", CONFIG_TYPE_DIRECTORY
, NULL
},
1170 {"ssl_ca_file", CONFIG_TYPE_FILE
, NULL
},
1171 {"ssl_verify_depth", CONFIG_TYPE_NUMBER
, "9"},
1172 {"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN
, "yes"},
1173 {"ssl_cipher_list", CONFIG_TYPE_STRING
, NULL
},
1174 {"ssl_protocol_version", CONFIG_TYPE_NUMBER
, "0"},
1175 {"ssl_short_trust", CONFIG_TYPE_BOOLEAN
, "no"},
1176 #if defined(USE_WEBSOCKET)
1177 {"websocket_timeout_ms", CONFIG_TYPE_NUMBER
, "30000"},
1179 {"decode_url", CONFIG_TYPE_BOOLEAN
, "yes"},
1181 #if defined(USE_LUA)
1182 {"lua_preload_file", CONFIG_TYPE_FILE
, NULL
},
1183 {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lua$"},
1184 {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lp$|**.lsp$"},
1186 #if defined(USE_DUKTAPE)
1187 /* The support for duktape is still in alpha version state.
1188 * The name of this config option might change. */
1189 {"duktape_script_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.ssjs$"},
1192 #if defined(USE_WEBSOCKET)
1193 {"websocket_root", CONFIG_TYPE_DIRECTORY
, NULL
},
1195 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1196 {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lua$"},
1198 {"access_control_allow_origin", CONFIG_TYPE_STRING
, "*"},
1199 {"error_pages", CONFIG_TYPE_DIRECTORY
, NULL
},
1200 {"tcp_nodelay", CONFIG_TYPE_NUMBER
, "0"},
1201 #if !defined(NO_CACHING)
1202 {"static_file_max_age", CONFIG_TYPE_NUMBER
, "3600"},
1204 {"validate_http_method", CONFIG_TYPE_BOOLEAN
, "yes"},
1205 {"canonicalize_url_path", CONFIG_TYPE_BOOLEAN
, "yes"},
1207 {NULL
, CONFIG_TYPE_UNKNOWN
, NULL
}};
1209 /* Check if the config_options and the corresponding enum have compatible
1211 mg_static_assert((sizeof(config_options
) / sizeof(config_options
[0]))
1212 == (NUM_OPTIONS
+ 1),
1213 "config_options and enum not sync");
1215 enum { REQUEST_HANDLER
, WEBSOCKET_HANDLER
, AUTH_HANDLER
};
1217 struct mg_handler_info
{
1218 /* Name/Pattern of the URI. */
1225 /* Handler for http/https or authorization requests. */
1226 mg_request_handler handler
;
1228 /* Handler for ws/wss (websocket) requests. */
1229 mg_websocket_connect_handler connect_handler
;
1230 mg_websocket_ready_handler ready_handler
;
1231 mg_websocket_data_handler data_handler
;
1232 mg_websocket_close_handler close_handler
;
1234 /* Handler for authorization requests */
1235 mg_authorization_handler auth_handler
;
1237 /* User supplied argument for the handler function. */
1240 /* next handler in a linked list */
1241 struct mg_handler_info
*next
;
1245 volatile int stop_flag
; /* Should we stop event loop */
1246 SSL_CTX
*ssl_ctx
; /* SSL context */
1247 char *config
[NUM_OPTIONS
]; /* Civetweb configuration parameters */
1248 struct mg_callbacks callbacks
; /* User-defined callback function */
1249 void *user_data
; /* User-defined data */
1250 int context_type
; /* 1 = server context, 2 = client context */
1252 struct socket
*listening_sockets
;
1253 in_port_t
*listening_ports
;
1254 unsigned int num_listening_sockets
;
1257 running_worker_threads
; /* Number of currently running worker threads */
1258 pthread_mutex_t thread_mutex
; /* Protects (max|num)_threads */
1259 pthread_cond_t thread_cond
; /* Condvar for tracking workers terminations */
1261 struct socket queue
[MGSQLEN
]; /* Accepted sockets */
1262 volatile int sq_head
; /* Head of the socket queue */
1263 volatile int sq_tail
; /* Tail of the socket queue */
1264 pthread_cond_t sq_full
; /* Signaled when socket is produced */
1265 pthread_cond_t sq_empty
; /* Signaled when socket is consumed */
1266 pthread_t masterthreadid
; /* The master thread ID */
1268 cfg_worker_threads
; /* The number of configured worker threads. */
1269 pthread_t
*workerthreadids
; /* The worker thread IDs */
1271 time_t start_time
; /* Server start time, used for authentication */
1272 uint64_t auth_nonce_mask
; /* Mask for all nonce values */
1273 pthread_mutex_t nonce_mutex
; /* Protects nonce_count */
1274 unsigned long nonce_count
; /* Used nonces, used for authentication */
1276 char *systemName
; /* What operating system is running */
1278 /* linked list of uri handlers */
1279 struct mg_handler_info
*handlers
;
1281 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1282 /* linked list of shared lua websockets */
1283 struct mg_shared_lua_websocket_list
*shared_lua_websockets
;
1287 struct ttimers
*timers
;
1292 struct mg_connection
{
1293 struct mg_request_info request_info
;
1294 struct mg_context
*ctx
;
1295 SSL
*ssl
; /* SSL descriptor */
1296 SSL_CTX
*client_ssl_ctx
; /* SSL context for client connections */
1297 struct socket client
; /* Connected client */
1298 time_t conn_birth_time
; /* Time (wall clock) when connection was
1300 struct timespec req_time
; /* Time (since system start) when the request
1302 int64_t num_bytes_sent
; /* Total bytes sent to client */
1303 int64_t content_len
; /* Content-Length header value */
1304 int64_t consumed_content
; /* How many bytes of content have been read */
1305 int is_chunked
; /* Transfer-Encoding is chunked: 0=no, 1=yes:
1306 * data available, 2: all data read */
1307 size_t chunk_remainder
; /* Unread data from the last chunk */
1308 char *buf
; /* Buffer for received data */
1309 char *path_info
; /* PATH_INFO part of the URL */
1311 int must_close
; /* 1 if connection must be closed */
1312 int in_error_handler
; /* 1 if in handler for user defined error
1314 int internal_error
; /* 1 if an error occured while processing the
1317 int buf_size
; /* Buffer size */
1318 int request_len
; /* Size of the request + headers in a buffer */
1319 int data_len
; /* Total size of data in a buffer */
1320 int status_code
; /* HTTP reply status code, e.g. 200 */
1321 int throttle
; /* Throttling, bytes/sec. <= 0 means no
1323 time_t last_throttle_time
; /* Last time throttled data was sent */
1324 int64_t last_throttle_bytes
; /* Bytes sent this second */
1325 pthread_mutex_t mutex
; /* Used by mg_(un)lock_connection to ensure
1326 * atomic transmissions for websockets */
1327 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1328 void *lua_websocket_state
; /* Lua_State for a websocket connection */
1333 static pthread_key_t sTlsKey
; /* Thread local storage index */
1334 static int sTlsInit
= 0;
1335 static int thread_idx_max
= 0;
1338 struct mg_workerTLS
{
1340 unsigned long thread_idx
;
1341 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1342 HANDLE pthread_cond_helper_mutex
;
1346 /* Directory entry */
1348 struct mg_connection
*conn
;
1354 #if defined(USE_WEBSOCKET)
1355 static int is_websocket_protocol(const struct mg_connection
*conn
);
1357 #define is_websocket_protocol(conn) (0)
1362 mg_atomic_inc(volatile int *addr
)
1365 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1366 /* Depending on the SDK, this function uses either
1367 * (volatile unsigned int *) or (volatile LONG *),
1368 * so whatever you use, the other SDK is likely to raise a warning. */
1369 ret
= InterlockedIncrement((volatile long *)addr
);
1370 #elif defined(__GNUC__) \
1371 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1372 ret
= __sync_add_and_fetch(addr
, 1);
1381 mg_atomic_dec(volatile int *addr
)
1384 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1385 /* Depending on the SDK, this function uses either
1386 * (volatile unsigned int *) or (volatile LONG *),
1387 * so whatever you use, the other SDK is likely to raise a warning. */
1388 ret
= InterlockedDecrement((volatile long *)addr
);
1389 #elif defined(__GNUC__) \
1390 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1391 ret
= __sync_sub_and_fetch(addr
, 1);
1398 #if !defined(NO_THREAD_NAME)
1399 #if defined(_WIN32) && defined(_MSC_VER)
1400 /* Set the thread name for debugging purposes in Visual Studio
1401 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
1403 #pragma pack(push, 8)
1404 typedef struct tagTHREADNAME_INFO
{
1405 DWORD dwType
; /* Must be 0x1000. */
1406 LPCSTR szName
; /* Pointer to name (in user addr space). */
1407 DWORD dwThreadID
; /* Thread ID (-1=caller thread). */
1408 DWORD dwFlags
; /* Reserved for future use, must be zero. */
1411 #elif defined(__linux__)
1412 #include <sys/prctl.h>
1413 #include <sys/sendfile.h>
1418 mg_set_thread_name(const char *name
)
1420 char threadName
[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
1423 NULL
, NULL
, threadName
, sizeof(threadName
), "civetweb-%s", name
);
1426 #if defined(_MSC_VER)
1427 /* Windows and Visual Studio Compiler */
1430 THREADNAME_INFO info
;
1431 info
.dwType
= 0x1000;
1432 info
.szName
= threadName
;
1433 info
.dwThreadID
= ~0U;
1436 RaiseException(0x406D1388,
1438 sizeof(info
) / sizeof(ULONG_PTR
),
1439 (ULONG_PTR
*)&info
);
1441 __except(EXCEPTION_EXECUTE_HANDLER
)
1444 #elif defined(__MINGW32__)
1445 /* No option known to set thread name for MinGW */
1447 #elif defined(__GLIBC__) \
1448 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
1449 /* pthread_setname_np first appeared in glibc in version 2.12*/
1450 (void)pthread_setname_np(pthread_self(), threadName
);
1451 #elif defined(__linux__)
1452 /* on linux we can use the old prctl function */
1453 (void)prctl(PR_SET_NAME
, threadName
, 0, 0, 0);
1456 #else /* !defined(NO_THREAD_NAME) */
1458 mg_set_thread_name(const char *threadName
)
1464 #if defined(MG_LEGACY_INTERFACE)
1466 mg_get_valid_option_names(void)
1468 /* This function is deprecated. Use mg_get_valid_options instead. */
1470 data
[2 * sizeof(config_options
) / sizeof(config_options
[0])] = {0};
1473 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
1474 data
[i
* 2] = config_options
[i
].name
;
1475 data
[i
* 2 + 1] = config_options
[i
].default_value
;
1483 const struct mg_option
*
1484 mg_get_valid_options(void)
1486 return config_options
;
1491 is_file_in_memory(const struct mg_connection
*conn
,
1496 if (!conn
|| !filep
) {
1500 if (conn
->ctx
->callbacks
.open_file
) {
1501 filep
->membuf
= conn
->ctx
->callbacks
.open_file(conn
, path
, &size
);
1502 if (filep
->membuf
!= NULL
) {
1503 /* NOTE: override filep->size only on success. Otherwise, it might
1504 * break constructs like if (!mg_stat() || !mg_fopen()) ... */
1509 return filep
->membuf
!= NULL
;
1514 is_file_opened(const struct file
*filep
)
1520 return filep
->membuf
!= NULL
|| filep
->fp
!= NULL
;
1524 /* mg_fopen will open a file either in memory or on the disk.
1525 * The input parameter path is a string in UTF-8 encoding.
1526 * The input parameter mode is the same as for fopen.
1527 * Either fp or membuf will be set in the output struct filep.
1528 * The function returns 1 on success, 0 on error. */
1530 mg_fopen(const struct mg_connection
*conn
,
1541 /* TODO (high): mg_fopen should only open a file, while mg_stat should
1542 * only get the file status. They should not work on different members of
1543 * the same structure (bad cohesion). */
1544 memset(filep
, 0, sizeof(*filep
));
1546 if (stat(path
, &st
) == 0) {
1547 filep
->size
= (uint64_t)(st
.st_size
);
1550 if (!is_file_in_memory(conn
, path
, filep
)) {
1552 wchar_t wbuf
[PATH_MAX
], wmode
[20];
1553 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
1554 MultiByteToWideChar(CP_UTF8
, 0, mode
, -1, wmode
, ARRAY_SIZE(wmode
));
1555 filep
->fp
= _wfopen(wbuf
, wmode
);
1557 /* Linux et al already use unicode. No need to convert. */
1558 filep
->fp
= fopen(path
, mode
);
1562 return is_file_opened(filep
);
1567 mg_fclose(struct file
*filep
)
1569 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
1576 mg_strlcpy(register char *dst
, register const char *src
, size_t n
)
1578 for (; *src
!= '\0' && n
> 1; n
--) {
1586 lowercase(const char *s
)
1588 return tolower(*(const unsigned char *)s
);
1593 mg_strncasecmp(const char *s1
, const char *s2
, size_t len
)
1599 diff
= lowercase(s1
++) - lowercase(s2
++);
1600 } while (diff
== 0 && s1
[-1] != '\0' && --len
> 0);
1608 mg_strcasecmp(const char *s1
, const char *s2
)
1613 diff
= lowercase(s1
++) - lowercase(s2
++);
1614 } while (diff
== 0 && s1
[-1] != '\0');
1621 mg_strndup(const char *ptr
, size_t len
)
1625 if ((p
= (char *)mg_malloc(len
+ 1)) != NULL
) {
1626 mg_strlcpy(p
, ptr
, len
+ 1);
1634 mg_strdup(const char *str
)
1636 return mg_strndup(str
, strlen(str
));
1641 mg_strcasestr(const char *big_str
, const char *small_str
)
1643 size_t i
, big_len
= strlen(big_str
), small_len
= strlen(small_str
);
1645 if (big_len
>= small_len
) {
1646 for (i
= 0; i
<= (big_len
- small_len
); i
++) {
1647 if (mg_strncasecmp(big_str
+ i
, small_str
, small_len
) == 0) {
1657 /* Return null terminated string of given maximum length.
1658 * Report errors if length is exceeded. */
1660 mg_vsnprintf(const struct mg_connection
*conn
,
1674 #pragma clang diagnostic push
1675 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1676 /* Using fmt as a non-literal is intended here, since it is mostly called
1677 * indirectly by mg_snprintf */
1680 n
= (int)vsnprintf_impl(buf
, buflen
, fmt
, ap
);
1681 ok
= (n
>= 0) && ((size_t)n
< buflen
);
1684 #pragma clang diagnostic pop
1696 "truncating vsnprintf buffer: [%.*s]",
1697 (int)((buflen
> 200) ? 200 : (buflen
- 1)),
1699 n
= (int)buflen
- 1;
1706 mg_snprintf(const struct mg_connection
*conn
,
1716 mg_vsnprintf(conn
, truncated
, buf
, buflen
, fmt
, ap
);
1722 get_option_index(const char *name
)
1726 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
1727 if (strcmp(config_options
[i
].name
, name
) == 0) {
1736 mg_get_option(const struct mg_context
*ctx
, const char *name
)
1739 if ((i
= get_option_index(name
)) == -1) {
1741 } else if (!ctx
|| ctx
->config
[i
] == NULL
) {
1744 return ctx
->config
[i
];
1750 mg_get_context(const struct mg_connection
*conn
)
1752 return (conn
== NULL
) ? (struct mg_context
*)NULL
: (conn
->ctx
);
1757 mg_get_user_data(const struct mg_context
*ctx
)
1759 return (ctx
== NULL
) ? NULL
: ctx
->user_data
;
1764 mg_set_user_connection_data(struct mg_connection
*conn
, void *data
)
1767 conn
->request_info
.conn_data
= data
;
1773 mg_get_user_connection_data(const struct mg_connection
*conn
)
1776 return conn
->request_info
.conn_data
;
1783 mg_get_ports(const struct mg_context
*ctx
, size_t size
, int *ports
, int *ssl
)
1789 for (i
= 0; i
< size
&& i
< ctx
->num_listening_sockets
; i
++) {
1790 ssl
[i
] = ctx
->listening_sockets
[i
].is_ssl
;
1791 ports
[i
] = ctx
->listening_ports
[i
];
1798 mg_get_server_ports(const struct mg_context
*ctx
,
1800 struct mg_server_ports
*ports
)
1807 memset(ports
, 0, sizeof(*ports
) * (size_t)size
);
1811 if (!ctx
->listening_sockets
|| !ctx
->listening_ports
) {
1815 for (i
= 0; (i
< size
) && (i
< (int)ctx
->num_listening_sockets
); i
++) {
1817 ports
[cnt
].port
= ctx
->listening_ports
[i
];
1818 ports
[cnt
].is_ssl
= ctx
->listening_sockets
[i
].is_ssl
;
1819 ports
[cnt
].is_redirect
= ctx
->listening_sockets
[i
].ssl_redir
;
1821 if (ctx
->listening_sockets
[i
].lsa
.sa
.sa_family
== AF_INET
) {
1823 ports
[cnt
].protocol
= 1;
1825 } else if (ctx
->listening_sockets
[i
].lsa
.sa
.sa_family
== AF_INET6
) {
1827 ports
[cnt
].protocol
= 3;
1837 sockaddr_to_string(char *buf
, size_t len
, const union usa
*usa
)
1845 if (usa
->sa
.sa_family
== AF_INET
) {
1846 getnameinfo(&usa
->sa
,
1854 #if defined(USE_IPV6)
1855 else if (usa
->sa
.sa_family
== AF_INET6
) {
1856 getnameinfo(&usa
->sa
,
1868 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
1869 * included in all responses other than 100, 101, 5xx. */
1871 gmt_time_string(char *buf
, size_t buf_len
, time_t *t
)
1875 tm
= ((t
!= NULL
) ? gmtime(t
) : NULL
);
1877 strftime(buf
, buf_len
, "%a, %d %b %Y %H:%M:%S GMT", tm
);
1879 mg_strlcpy(buf
, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len
);
1880 buf
[buf_len
- 1] = '\0';
1885 /* difftime for struct timespec. Return value is in seconds. */
1887 mg_difftimespec(const struct timespec
*ts_now
, const struct timespec
*ts_before
)
1889 return (double)(ts_now
->tv_nsec
- ts_before
->tv_nsec
) * 1.0E-9
1890 + (double)(ts_now
->tv_sec
- ts_before
->tv_sec
);
1894 /* Print error message to the opened error log stream. */
1896 mg_cry(const struct mg_connection
*conn
, const char *fmt
, ...)
1898 char buf
[MG_BUF_LEN
], src_addr
[IP_ADDR_STR_LEN
];
1904 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf
, sizeof(buf
), fmt
, ap
));
1906 buf
[sizeof(buf
) - 1] = 0;
1913 /* Do not lock when getting the callback value, here and below.
1914 * I suppose this is fine, since function cannot disappear in the
1915 * same way string option can. */
1916 if ((conn
->ctx
->callbacks
.log_message
== NULL
)
1917 || (conn
->ctx
->callbacks
.log_message(conn
, buf
) == 0)) {
1919 if (conn
->ctx
->config
[ERROR_LOG_FILE
] != NULL
) {
1920 if (mg_fopen(conn
, conn
->ctx
->config
[ERROR_LOG_FILE
], "a+", &fi
)
1928 if (fi
.fp
!= NULL
) {
1930 timestamp
= time(NULL
);
1932 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
1934 "[%010lu] [error] [client %s] ",
1935 (unsigned long)timestamp
,
1938 if (conn
->request_info
.request_method
!= NULL
) {
1941 conn
->request_info
.request_method
,
1942 conn
->request_info
.request_uri
);
1945 fprintf(fi
.fp
, "%s", buf
);
1955 mg_set_http_status(struct mg_connection
*conn
, int status
)
1957 conn
->status_code
= status
;
1960 /* Return fake connection structure. Used for logging, if connection
1961 * is not applicable at the moment of logging. */
1962 static struct mg_connection
*
1963 fc(struct mg_context
*ctx
)
1965 static struct mg_connection fake_connection
;
1966 fake_connection
.ctx
= ctx
;
1967 return &fake_connection
;
1974 return CIVETWEB_VERSION
;
1978 const struct mg_request_info
*
1979 mg_get_request_info(const struct mg_connection
*conn
)
1984 return &conn
->request_info
;
1989 mg_get_local_addr(struct mg_connection
*conn
)
1991 return &conn
->client
.lsa
.sa
;
1995 /* Skip the characters until one of the delimiters characters found.
1996 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
1997 * Advance pointer to buffer to the next word. Return found 0-terminated word.
1998 * Delimiters can be quoted with quotechar. */
2000 skip_quoted(char **buf
,
2001 const char *delimiters
,
2002 const char *whitespace
,
2005 char *p
, *begin_word
, *end_word
, *end_whitespace
;
2008 end_word
= begin_word
+ strcspn(begin_word
, delimiters
);
2010 /* Check for quotechar */
2011 if (end_word
> begin_word
) {
2013 while (*p
== quotechar
) {
2014 /* While the delimiter is quoted, look for the next delimiter. */
2015 /* This happens, e.g., in calls from parse_auth_header,
2016 * if the user name contains a " character. */
2018 /* If there is anything beyond end_word, copy it. */
2019 if (*end_word
!= '\0') {
2020 size_t end_off
= strcspn(end_word
+ 1, delimiters
);
2021 memmove(p
, end_word
, end_off
+ 1);
2022 p
+= end_off
; /* p must correspond to end_word - 1 */
2023 end_word
+= end_off
+ 1;
2029 for (p
++; p
< end_word
; p
++) {
2034 if (*end_word
== '\0') {
2037 end_whitespace
= end_word
+ 1 + strspn(end_word
+ 1, whitespace
);
2039 for (p
= end_word
; p
< end_whitespace
; p
++) {
2043 *buf
= end_whitespace
;
2050 /* Simplified version of skip_quoted without quote char
2051 * and whitespace == delimiters */
2053 skip(char **buf
, const char *delimiters
)
2055 return skip_quoted(buf
, delimiters
, delimiters
, 0);
2059 /* Return HTTP header value, or NULL if not found. */
2061 get_header(const struct mg_request_info
*ri
, const char *name
)
2065 for (i
= 0; i
< ri
->num_headers
; i
++) {
2066 if (!mg_strcasecmp(name
, ri
->http_headers
[i
].name
)) {
2067 return ri
->http_headers
[i
].value
;
2077 mg_get_header(const struct mg_connection
*conn
, const char *name
)
2083 return get_header(&conn
->request_info
, name
);
2087 /* A helper function for traversing a comma separated list of values.
2088 * It returns a list pointer shifted to the next value, or NULL if the end
2089 * of the list found.
2090 * Value is stored in val vector. If value has form "x=y", then eq_val
2091 * vector is initialized to point to the "y" part, and val vector length
2092 * is adjusted to point only to "x". */
2094 next_option(const char *list
, struct vec
*val
, struct vec
*eq_val
)
2099 if (val
== NULL
|| list
== NULL
|| *list
== '\0') {
2100 /* End of the list */
2103 /* Skip over leading LWS */
2104 while (*list
== ' ' || *list
== '\t')
2108 if ((list
= strchr(val
->ptr
, ',')) != NULL
) {
2109 /* Comma found. Store length and shift the list ptr */
2110 val
->len
= ((size_t)(list
- val
->ptr
));
2113 /* This value is the last one */
2114 list
= val
->ptr
+ strlen(val
->ptr
);
2115 val
->len
= ((size_t)(list
- val
->ptr
));
2118 /* Adjust length for trailing LWS */
2119 end
= (int)val
->len
- 1;
2120 while (end
>= 0 && (val
->ptr
[end
] == ' ' || val
->ptr
[end
] == '\t'))
2122 val
->len
= (size_t)(end
+ 1);
2124 if (val
->len
== 0) {
2125 /* Ignore any empty entries. */
2129 if (eq_val
!= NULL
) {
2130 /* Value has form "x=y", adjust pointers and lengths
2131 * so that val points to "x", and eq_val points to "y". */
2133 eq_val
->ptr
= (const char *)memchr(val
->ptr
, '=', val
->len
);
2134 if (eq_val
->ptr
!= NULL
) {
2135 eq_val
->ptr
++; /* Skip over '=' character */
2136 eq_val
->len
= ((size_t)(val
->ptr
- eq_val
->ptr
)) + val
->len
;
2137 val
->len
= ((size_t)(eq_val
->ptr
- val
->ptr
)) - 1;
2145 /* A helper function for checking if a comma separated list of values contains
2146 * the given option (case insensitvely).
2147 * 'header' can be NULL, in which case false is returned. */
2149 header_has_option(const char *header
, const char *option
)
2154 assert(option
!= NULL
);
2155 assert(option
[0] != '\0');
2157 while ((header
= next_option(header
, &opt_vec
, &eq_vec
)) != NULL
) {
2158 if (mg_strncasecmp(option
, opt_vec
.ptr
, opt_vec
.len
) == 0)
2165 /* Perform case-insensitive match of string against pattern */
2167 match_prefix(const char *pattern
, size_t pattern_len
, const char *str
)
2173 if ((or_str
= (const char *)memchr(pattern
, '|', pattern_len
)) != NULL
) {
2174 res
= match_prefix(pattern
, (size_t)(or_str
- pattern
), str
);
2175 return res
> 0 ? res
: match_prefix(or_str
+ 1,
2176 (size_t)((pattern
+ pattern_len
)
2181 for (i
= 0, j
= 0; i
< pattern_len
; i
++, j
++) {
2182 if (pattern
[i
] == '?' && str
[j
] != '\0') {
2184 } else if (pattern
[i
] == '$') {
2185 return str
[j
] == '\0' ? j
: -1;
2186 } else if (pattern
[i
] == '*') {
2188 if (pattern
[i
] == '*') {
2190 len
= (int)strlen(str
+ j
);
2192 len
= (int)strcspn(str
+ j
, "/");
2194 if (i
== pattern_len
) {
2198 res
= match_prefix(pattern
+ i
, pattern_len
- i
, str
+ j
+ len
);
2199 } while (res
== -1 && len
-- > 0);
2200 return res
== -1 ? -1 : j
+ res
+ len
;
2201 } else if (lowercase(&pattern
[i
]) != lowercase(&str
[j
])) {
2209 /* HTTP 1.1 assumes keep alive if "Connection:" header is not set
2210 * This function must tolerate situations when connection info is not
2211 * set up, for example if request parsing failed. */
2213 should_keep_alive(const struct mg_connection
*conn
)
2216 const char *http_version
= conn
->request_info
.http_version
;
2217 const char *header
= mg_get_header(conn
, "Connection");
2218 if (conn
->must_close
|| conn
->internal_error
|| conn
->status_code
== 401
2219 || mg_strcasecmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes") != 0
2220 || (header
!= NULL
&& !header_has_option(header
, "keep-alive"))
2221 || (header
== NULL
&& http_version
2222 && 0 != strcmp(http_version
, "1.1"))) {
2232 should_decode_url(const struct mg_connection
*conn
)
2234 if (!conn
|| !conn
->ctx
) {
2238 return (mg_strcasecmp(conn
->ctx
->config
[DECODE_URL
], "yes") == 0);
2242 should_validate_http_method(const struct mg_connection
*conn
)
2244 if (!conn
|| !conn
->ctx
|| !conn
->ctx
->config
[VALIDATE_HTTP_METHOD
]) {
2248 return (mg_strcasecmp(conn
->ctx
->config
[VALIDATE_HTTP_METHOD
], "yes") == 0);
2253 suggest_connection_header(const struct mg_connection
*conn
)
2255 return should_keep_alive(conn
) ? "keep-alive" : "close";
2260 send_no_cache_header(struct mg_connection
*conn
)
2262 /* Send all current and obsolete cache opt-out directives. */
2263 return mg_printf(conn
,
2264 "Cache-Control: no-cache, no-store, "
2265 "must-revalidate, private, max-age=0\r\n"
2266 "Pragma: no-cache\r\n"
2272 send_static_cache_header(struct mg_connection
*conn
)
2274 #if !defined(NO_CACHING)
2275 /* Read the server config to check how long a file may be cached.
2276 * The configuration is in seconds. */
2277 int max_age
= atoi(conn
->ctx
->config
[STATIC_FILE_MAX_AGE
]);
2279 /* 0 means "do not cache". All values <0 are reserved
2280 * and may be used differently in the future. */
2281 /* If a file should not be cached, do not only send
2282 * max-age=0, but also pragmas and Expires headers. */
2283 return send_no_cache_header(conn
);
2286 /* Use "Cache-Control: max-age" instead of "Expires" header.
2287 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
2288 /* See also https://www.mnot.net/cache_docs/ */
2289 /* According to RFC 2616, Section 14.21, caching times should not exceed
2290 * one year. A year with 365 days corresponds to 31536000 seconds, a leap
2291 * year to 31622400 seconds. For the moment, we just send whatever has
2292 * been configured, still the behavior for >1 year should be considered
2294 return mg_printf(conn
, "Cache-Control: max-age=%u\r\n", (unsigned)max_age
);
2295 #else /* NO_CACHING */
2296 return send_no_cache_header(conn
);
2297 #endif /* !NO_CACHING */
2301 static void handle_file_based_request(struct mg_connection
*conn
,
2303 struct file
*filep
);
2306 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
);
2310 mg_get_response_code_text(struct mg_connection
*conn
, int response_code
)
2312 /* See IANA HTTP status code assignment:
2313 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
2316 switch (response_code
) {
2317 /* RFC2616 Section 10.1 - Informational 1xx */
2319 return "Continue"; /* RFC2616 Section 10.1.1 */
2321 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
2323 return "Processing"; /* RFC2518 Section 10.1 */
2325 /* RFC2616 Section 10.2 - Successful 2xx */
2327 return "OK"; /* RFC2616 Section 10.2.1 */
2329 return "Created"; /* RFC2616 Section 10.2.2 */
2331 return "Accepted"; /* RFC2616 Section 10.2.3 */
2333 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
2335 return "No Content"; /* RFC2616 Section 10.2.5 */
2337 return "Reset Content"; /* RFC2616 Section 10.2.6 */
2339 return "Partial Content"; /* RFC2616 Section 10.2.7 */
2341 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */
2343 return "Already Reported"; /* RFC5842 Section 7.1 */
2346 return "IM used"; /* RFC3229 Section 10.4.1 */
2348 /* RFC2616 Section 10.3 - Redirection 3xx */
2350 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
2352 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
2354 return "Found"; /* RFC2616 Section 10.3.3 */
2356 return "See Other"; /* RFC2616 Section 10.3.4 */
2358 return "Not Modified"; /* RFC2616 Section 10.3.5 */
2360 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
2362 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
2364 return "Permanent Redirect"; /* RFC7238 Section 3 */
2366 /* RFC2616 Section 10.4 - Client Error 4xx */
2368 return "Bad Request"; /* RFC2616 Section 10.4.1 */
2370 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
2372 return "Payment Required"; /* RFC2616 Section 10.4.3 */
2374 return "Forbidden"; /* RFC2616 Section 10.4.4 */
2376 return "Not Found"; /* RFC2616 Section 10.4.5 */
2378 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
2380 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
2382 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
2384 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
2386 return "Conflict"; /* RFC2616 Section 10.4.10 */
2388 return "Gone"; /* RFC2616 Section 10.4.11 */
2390 return "Length Required"; /* RFC2616 Section 10.4.12 */
2392 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
2394 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
2396 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
2398 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
2400 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */
2402 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
2405 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
2407 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
2410 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
2412 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
2416 return "Upgrade Required"; /* RFC 2817 Section 4 */
2419 return "Precondition Required"; /* RFC 6585, Section 3 */
2421 return "Too Many Requests"; /* RFC 6585, Section 4 */
2424 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
2427 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
2430 /* RFC2616 Section 10.5 - Server Error 5xx */
2432 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
2434 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
2436 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
2438 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
2440 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
2442 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
2444 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
2446 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
2449 return "Loop Detected"; /* RFC5842 Section 7.1 */
2452 return "Not Extended"; /* RFC 2774, Section 7 */
2454 return "Network Authentication Required"; /* RFC 6585, Section 6 */
2456 /* Other status codes, not shown in the IANA HTTP status code assignment.
2457 * E.g., "de facto" standards due to common use, ... */
2459 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
2461 return "Authentication Timeout"; /* common use */
2463 return "Enhance Your Calm"; /* common use */
2465 return "Login Timeout"; /* common use */
2467 return "Bandwidth Limit Exceeded"; /* common use */
2470 /* This error code is unknown. This should not happen. */
2472 mg_cry(conn
, "Unknown HTTP response code: %u", response_code
);
2475 /* Return at least a category according to RFC 2616 Section 10. */
2476 if (response_code
>= 100 && response_code
< 200) {
2477 /* Unknown informational status code */
2478 return "Information";
2480 if (response_code
>= 200 && response_code
< 300) {
2481 /* Unknown success code */
2484 if (response_code
>= 300 && response_code
< 400) {
2485 /* Unknown redirection code */
2486 return "Redirection";
2488 if (response_code
>= 400 && response_code
< 500) {
2489 /* Unknown request error code */
2490 return "Client Error";
2492 if (response_code
>= 500 && response_code
< 600) {
2493 /* Unknown server error code */
2494 return "Server Error";
2497 /* Response code not even within reasonable range */
2503 static void send_http_error(struct mg_connection
*,
2505 PRINTF_FORMAT_STRING(const char *fmt
),
2506 ...) PRINTF_ARGS(3, 4);
2509 send_http_error(struct mg_connection
*conn
, int status
, const char *fmt
, ...)
2511 char buf
[MG_BUF_LEN
];
2513 int len
, i
, page_handler_found
, scope
, truncated
;
2515 time_t curtime
= time(NULL
);
2516 const char *error_handler
= NULL
;
2517 struct file error_page_file
= STRUCT_FILE_INITIALIZER
;
2518 const char *error_page_file_ext
, *tstr
;
2520 const char *status_text
= mg_get_response_code_text(conn
, status
);
2526 conn
->status_code
= status
;
2527 if (conn
->in_error_handler
|| conn
->ctx
->callbacks
.http_error
== NULL
2528 || conn
->ctx
->callbacks
.http_error(conn
, status
)) {
2529 if (!conn
->in_error_handler
) {
2530 /* Send user defined error pages, if defined */
2531 error_handler
= conn
->ctx
->config
[ERROR_PAGES
];
2532 error_page_file_ext
= conn
->ctx
->config
[INDEX_FILES
];
2533 page_handler_found
= 0;
2534 if (error_handler
!= NULL
) {
2535 for (scope
= 1; (scope
<= 3) && !page_handler_found
; scope
++) {
2537 case 1: /* Handler for specific error, e.g. 404 error */
2546 case 2: /* Handler for error group, e.g., 5xx error handler
2547 * for all server errors (500-599) */
2556 default: /* Handler for all errors */
2566 /* String truncation in buf may only occur if error_handler
2567 * is too long. This string is from the config, not from a
2571 len
= (int)strlen(buf
);
2573 tstr
= strchr(error_page_file_ext
, '.');
2576 for (i
= 1; i
< 32 && tstr
[i
] != 0 && tstr
[i
] != ',';
2578 buf
[len
+ i
- 1] = tstr
[i
];
2579 buf
[len
+ i
- 1] = 0;
2580 if (mg_stat(conn
, buf
, &error_page_file
)) {
2581 page_handler_found
= 1;
2584 tstr
= strchr(tstr
+ i
, '.');
2589 if (page_handler_found
) {
2590 conn
->in_error_handler
= 1;
2591 handle_file_based_request(conn
, buf
, &error_page_file
);
2592 conn
->in_error_handler
= 0;
2597 /* No custom error page. Send default error page. */
2598 gmt_time_string(date
, sizeof(date
), &curtime
);
2600 conn
->must_close
= 1;
2601 mg_printf(conn
, "HTTP/1.1 %d %s\r\n", status
, status_text
);
2602 send_no_cache_header(conn
);
2605 "Connection: close\r\n\r\n",
2608 /* Errors 1xx, 204 and 304 MUST NOT send a body */
2609 if (status
> 199 && status
!= 204 && status
!= 304) {
2611 mg_printf(conn
, "Error %d: %s\n", status
, status_text
);
2615 mg_vsnprintf(conn
, NULL
, buf
, sizeof(buf
), fmt
, ap
);
2617 mg_write(conn
, buf
, strlen(buf
));
2618 DEBUG_TRACE("Error %i - [%s]", status
, buf
);
2622 /* No body allowed. Close the connection. */
2623 DEBUG_TRACE("Error %i", status
);
2628 #if defined(_WIN32) && !defined(__SYMBIAN32__)
2629 /* Create substitutes for POSIX functions in Win32. */
2631 #if defined(__MINGW32__)
2632 /* Show no warning in case system functions are not used. */
2633 #pragma GCC diagnostic push
2634 #pragma GCC diagnostic ignored "-Wunused-function"
2639 pthread_mutex_init(pthread_mutex_t
*mutex
, void *unused
)
2642 *mutex
= CreateMutex(NULL
, FALSE
, NULL
);
2643 return *mutex
== NULL
? -1 : 0;
2648 pthread_mutex_destroy(pthread_mutex_t
*mutex
)
2650 return CloseHandle(*mutex
) == 0 ? -1 : 0;
2655 pthread_mutex_lock(pthread_mutex_t
*mutex
)
2657 return WaitForSingleObject(*mutex
, INFINITE
) == WAIT_OBJECT_0
? 0 : -1;
2661 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
2663 pthread_mutex_trylock(pthread_mutex_t
*mutex
)
2665 switch (WaitForSingleObject(*mutex
, 0)) {
2669 return -2; /* EBUSY */
2677 pthread_mutex_unlock(pthread_mutex_t
*mutex
)
2679 return ReleaseMutex(*mutex
) == 0 ? -1 : 0;
2683 #ifndef WIN_PTHREADS_TIME_H
2685 clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
2691 static double perfcnt_per_sec
= 0.0;
2694 memset(tp
, 0, sizeof(*tp
));
2695 if (clk_id
== CLOCK_REALTIME
) {
2696 GetSystemTimeAsFileTime(&ft
);
2697 li
.LowPart
= ft
.dwLowDateTime
;
2698 li
.HighPart
= ft
.dwHighDateTime
;
2699 li
.QuadPart
-= 116444736000000000; /* 1.1.1970 in filedate */
2700 tp
->tv_sec
= (time_t)(li
.QuadPart
/ 10000000);
2701 tp
->tv_nsec
= (long)(li
.QuadPart
% 10000000) * 100;
2703 } else if (clk_id
== CLOCK_MONOTONIC
) {
2704 if (perfcnt_per_sec
== 0.0) {
2705 QueryPerformanceFrequency((LARGE_INTEGER
*)&li
);
2706 perfcnt_per_sec
= 1.0 / li
.QuadPart
;
2708 if (perfcnt_per_sec
!= 0.0) {
2709 QueryPerformanceCounter((LARGE_INTEGER
*)&li
);
2710 d
= li
.QuadPart
* perfcnt_per_sec
;
2711 tp
->tv_sec
= (time_t)d
;
2713 tp
->tv_nsec
= (long)(d
* 1.0E9
);
2725 pthread_cond_init(pthread_cond_t
*cv
, const void *unused
)
2728 InitializeCriticalSection(&cv
->threadIdSec
);
2729 cv
->waitingthreadcount
= 0;
2730 cv
->waitingthreadhdls
=
2731 (pthread_t
*)mg_calloc(MAX_WORKER_THREADS
, sizeof(pthread_t
));
2732 return (cv
->waitingthreadhdls
!= NULL
) ? 0 : -1;
2737 pthread_cond_timedwait(pthread_cond_t
*cv
,
2738 pthread_mutex_t
*mutex
,
2739 const struct timespec
*abstime
)
2741 struct mg_workerTLS
*tls
=
2742 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
2744 struct timespec tsnow
;
2745 int64_t nsnow
, nswaitabs
, nswaitrel
;
2748 EnterCriticalSection(&cv
->threadIdSec
);
2749 assert(cv
->waitingthreadcount
< MAX_WORKER_THREADS
);
2750 cv
->waitingthreadhdls
[cv
->waitingthreadcount
] =
2751 tls
->pthread_cond_helper_mutex
;
2752 cv
->waitingthreadcount
++;
2753 LeaveCriticalSection(&cv
->threadIdSec
);
2756 clock_gettime(CLOCK_REALTIME
, &tsnow
);
2757 nsnow
= (((int64_t)tsnow
.tv_sec
) * 1000000000) + tsnow
.tv_nsec
;
2759 (((int64_t)abstime
->tv_sec
) * 1000000000) + abstime
->tv_nsec
;
2760 nswaitrel
= nswaitabs
- nsnow
;
2761 if (nswaitrel
< 0) {
2764 mswaitrel
= (DWORD
)(nswaitrel
/ 1000000);
2766 mswaitrel
= INFINITE
;
2769 pthread_mutex_unlock(mutex
);
2771 == WaitForSingleObject(tls
->pthread_cond_helper_mutex
, mswaitrel
));
2772 pthread_mutex_lock(mutex
);
2779 pthread_cond_wait(pthread_cond_t
*cv
, pthread_mutex_t
*mutex
)
2781 return pthread_cond_timedwait(cv
, mutex
, NULL
);
2786 pthread_cond_signal(pthread_cond_t
*cv
)
2792 EnterCriticalSection(&cv
->threadIdSec
);
2793 if (cv
->waitingthreadcount
) {
2794 wkup
= cv
->waitingthreadhdls
[0];
2795 ok
= SetEvent(wkup
);
2797 for (i
= 1; i
< cv
->waitingthreadcount
; i
++) {
2798 cv
->waitingthreadhdls
[i
- 1] = cv
->waitingthreadhdls
[i
];
2800 cv
->waitingthreadcount
--;
2804 LeaveCriticalSection(&cv
->threadIdSec
);
2811 pthread_cond_broadcast(pthread_cond_t
*cv
)
2813 EnterCriticalSection(&cv
->threadIdSec
);
2814 while (cv
->waitingthreadcount
) {
2815 pthread_cond_signal(cv
);
2817 LeaveCriticalSection(&cv
->threadIdSec
);
2824 pthread_cond_destroy(pthread_cond_t
*cv
)
2826 EnterCriticalSection(&cv
->threadIdSec
);
2827 assert(cv
->waitingthreadcount
== 0);
2828 mg_free(cv
->waitingthreadhdls
);
2829 cv
->waitingthreadhdls
= 0;
2830 LeaveCriticalSection(&cv
->threadIdSec
);
2831 DeleteCriticalSection(&cv
->threadIdSec
);
2837 #if defined(__MINGW32__)
2838 /* Enable unused function warning again */
2839 #pragma GCC diagnostic pop
2843 /* For Windows, change all slashes to backslashes in path names. */
2845 change_slashes_to_backslashes(char *path
)
2849 for (i
= 0; path
[i
] != '\0'; i
++) {
2850 if (path
[i
] == '/') {
2854 /* remove double backslash (check i > 0 to preserve UNC paths,
2855 * like \\server\file.txt) */
2856 if ((path
[i
] == '\\') && (i
> 0)) {
2857 while (path
[i
+ 1] == '\\' || path
[i
+ 1] == '/') {
2858 (void)memmove(path
+ i
+ 1, path
+ i
+ 2, strlen(path
+ i
+ 1));
2866 mg_wcscasecmp(const wchar_t *s1
, const wchar_t *s2
)
2871 diff
= tolower(*s1
) - tolower(*s2
);
2874 } while (diff
== 0 && s1
[-1] != '\0');
2880 /* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
2881 * wbuf and wbuf_len is a target buffer and its length. */
2883 path_to_unicode(const struct mg_connection
*conn
,
2888 char buf
[PATH_MAX
], buf2
[PATH_MAX
];
2889 wchar_t wbuf2
[MAX_PATH
+ 1];
2890 DWORD long_len
, err
;
2891 int (*fcompare
)(const wchar_t *, const wchar_t *) = mg_wcscasecmp
;
2893 mg_strlcpy(buf
, path
, sizeof(buf
));
2894 change_slashes_to_backslashes(buf
);
2896 /* Convert to Unicode and back. If doubly-converted string does not
2897 * match the original, something is fishy, reject. */
2898 memset(wbuf
, 0, wbuf_len
* sizeof(wchar_t));
2899 MultiByteToWideChar(CP_UTF8
, 0, buf
, -1, wbuf
, (int)wbuf_len
);
2900 WideCharToMultiByte(
2901 CP_UTF8
, 0, wbuf
, (int)wbuf_len
, buf2
, sizeof(buf2
), NULL
, NULL
);
2902 if (strcmp(buf
, buf2
) != 0) {
2906 /* TODO: Add a configuration to switch between case sensitive and
2907 * case insensitive URIs for Windows server. */
2910 if (conn->ctx->config[WINDOWS_CASE_SENSITIVE]) {
2915 (void)conn
; /* conn is currently unused */
2917 /* Only accept a full file path, not a Windows short (8.3) path. */
2918 memset(wbuf2
, 0, ARRAY_SIZE(wbuf2
) * sizeof(wchar_t));
2919 long_len
= GetLongPathNameW(wbuf
, wbuf2
, ARRAY_SIZE(wbuf2
) - 1);
2920 if (long_len
== 0) {
2921 err
= GetLastError();
2922 if (err
== ERROR_FILE_NOT_FOUND
) {
2923 /* File does not exist. This is not always a problem here. */
2927 if ((long_len
>= ARRAY_SIZE(wbuf2
)) || (fcompare(wbuf
, wbuf2
) != 0)) {
2928 /* Short name is used. */
2934 #if defined(_WIN32_WCE)
2935 /* Create substitutes for POSIX functions in Win32. */
2937 #if defined(__MINGW32__)
2938 /* Show no warning in case system functions are not used. */
2939 #pragma GCC diagnostic push
2940 #pragma GCC diagnostic ignored "-Wunused-function"
2952 SystemTimeToFileTime(&st
, &ft
);
2953 t
= SYS2UNIX_TIME(ft
.dwLowDateTime
, ft
.dwHighDateTime
);
2955 if (ptime
!= NULL
) {
2964 localtime(const time_t *ptime
, struct tm
*ptm
)
2966 int64_t t
= ((int64_t)*ptime
) * RATE_DIFF
+ EPOCH_DIFF
;
2969 TIME_ZONE_INFORMATION tzinfo
;
2975 *(int64_t *)&ft
= t
;
2976 FileTimeToLocalFileTime(&ft
, &lft
);
2977 FileTimeToSystemTime(&lft
, &st
);
2978 ptm
->tm_year
= st
.wYear
- 1900;
2979 ptm
->tm_mon
= st
.wMonth
- 1;
2980 ptm
->tm_wday
= st
.wDayOfWeek
;
2981 ptm
->tm_mday
= st
.wDay
;
2982 ptm
->tm_hour
= st
.wHour
;
2983 ptm
->tm_min
= st
.wMinute
;
2984 ptm
->tm_sec
= st
.wSecond
;
2985 ptm
->tm_yday
= 0; /* hope nobody uses this */
2987 GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_DAYLIGHT
? 1 : 0;
2994 gmtime(const time_t *ptime
, struct tm
*ptm
)
2996 /* FIXME(lsm): fix this. */
2997 return localtime(ptime
, ptm
);
3002 strftime(char *dst
, size_t dst_size
, const char *fmt
, const struct tm
*tm
)
3004 (void)mg_snprintf(NULL
, dst
, dst_size
, "implement strftime() for WinCE");
3009 #if defined(__MINGW32__)
3010 /* Enable unused function warning again */
3011 #pragma GCC diagnostic pop
3017 /* Windows happily opens files with some garbage at the end of file name.
3018 * For example, fopen("a.cgi ", "r") on Windows successfully opens
3019 * "a.cgi", despite one would expect an error back.
3020 * This function returns non-0 if path ends with some garbage. */
3022 path_cannot_disclose_cgi(const char *path
)
3024 static const char *allowed_last_characters
= "_-";
3025 int last
= path
[strlen(path
) - 1];
3026 return isalnum(last
) || strchr(allowed_last_characters
, last
) != NULL
;
3031 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3033 wchar_t wbuf
[PATH_MAX
];
3034 WIN32_FILE_ATTRIBUTE_DATA info
;
3035 time_t creation_time
;
3040 memset(filep
, 0, sizeof(*filep
));
3042 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3043 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
3045 filep
->last_modified
= time(NULL
);
3046 /* last_modified = now ... assumes the file may change during runtime,
3047 * so every mg_fopen call may return different data */
3048 /* last_modified = conn->ctx.start_time;
3049 * May be used it the data does not change during runtime. This allows
3050 * browser caching. Since we do not know, we have to assume the file
3051 * in memory may change. */
3055 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3056 if (GetFileAttributesExW(wbuf
, GetFileExInfoStandard
, &info
) != 0) {
3057 filep
->size
= MAKEUQUAD(info
.nFileSizeLow
, info
.nFileSizeHigh
);
3058 filep
->last_modified
=
3059 SYS2UNIX_TIME(info
.ftLastWriteTime
.dwLowDateTime
,
3060 info
.ftLastWriteTime
.dwHighDateTime
);
3062 /* On Windows, the file creation time can be higher than the
3063 * modification time, e.g. when a file is copied.
3064 * Since the Last-Modified timestamp is used for caching
3065 * it should be based on the most recent timestamp. */
3066 creation_time
= SYS2UNIX_TIME(info
.ftCreationTime
.dwLowDateTime
,
3067 info
.ftCreationTime
.dwHighDateTime
);
3068 if (creation_time
> filep
->last_modified
) {
3069 filep
->last_modified
= creation_time
;
3072 filep
->is_directory
= info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
;
3073 /* If file name is fishy, reset the file structure and return
3075 * Note it is important to reset, not just return the error, cause
3076 * functions like is_file_opened() check the struct. */
3077 if (!filep
->is_directory
&& !path_cannot_disclose_cgi(path
)) {
3078 memset(filep
, 0, sizeof(*filep
));
3090 mg_remove(const struct mg_connection
*conn
, const char *path
)
3092 wchar_t wbuf
[PATH_MAX
];
3093 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3094 return DeleteFileW(wbuf
) ? 0 : -1;
3099 mg_mkdir(const struct mg_connection
*conn
, const char *path
, int mode
)
3101 wchar_t wbuf
[PATH_MAX
];
3103 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3104 return CreateDirectoryW(wbuf
, NULL
) ? 0 : -1;
3108 /* Create substitutes for POSIX functions in Win32. */
3110 #if defined(__MINGW32__)
3111 /* Show no warning in case system functions are not used. */
3112 #pragma GCC diagnostic push
3113 #pragma GCC diagnostic ignored "-Wunused-function"
3117 /* Implementation of POSIX opendir/closedir/readdir for Windows. */
3119 mg_opendir(const struct mg_connection
*conn
, const char *name
)
3122 wchar_t wpath
[PATH_MAX
];
3126 SetLastError(ERROR_BAD_ARGUMENTS
);
3127 } else if ((dir
= (DIR *)mg_malloc(sizeof(*dir
))) == NULL
) {
3128 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3130 path_to_unicode(conn
, name
, wpath
, ARRAY_SIZE(wpath
));
3131 attrs
= GetFileAttributesW(wpath
);
3132 if (attrs
!= 0xFFFFFFFF && ((attrs
& FILE_ATTRIBUTE_DIRECTORY
)
3133 == FILE_ATTRIBUTE_DIRECTORY
)) {
3134 (void)wcscat(wpath
, L
"\\*");
3135 dir
->handle
= FindFirstFileW(wpath
, &dir
->info
);
3136 dir
->result
.d_name
[0] = '\0';
3148 mg_closedir(DIR *dir
)
3153 if (dir
->handle
!= INVALID_HANDLE_VALUE
)
3154 result
= FindClose(dir
->handle
) ? 0 : -1;
3159 SetLastError(ERROR_BAD_ARGUMENTS
);
3166 static struct dirent
*
3167 mg_readdir(DIR *dir
)
3169 struct dirent
*result
= 0;
3172 if (dir
->handle
!= INVALID_HANDLE_VALUE
) {
3173 result
= &dir
->result
;
3174 (void)WideCharToMultiByte(CP_UTF8
,
3176 dir
->info
.cFileName
,
3179 sizeof(result
->d_name
),
3183 if (!FindNextFileW(dir
->handle
, &dir
->info
)) {
3184 (void)FindClose(dir
->handle
);
3185 dir
->handle
= INVALID_HANDLE_VALUE
;
3189 SetLastError(ERROR_FILE_NOT_FOUND
);
3192 SetLastError(ERROR_BAD_ARGUMENTS
);
3201 poll(struct pollfd
*pfd
, unsigned int n
, int milliseconds
)
3209 memset(&tv
, 0, sizeof(tv
));
3210 tv
.tv_sec
= milliseconds
/ 1000;
3211 tv
.tv_usec
= (milliseconds
% 1000) * 1000;
3214 for (i
= 0; i
< n
; i
++) {
3215 FD_SET((SOCKET
)pfd
[i
].fd
, &set
);
3218 if (pfd
[i
].fd
> maxfd
) {
3223 if ((result
= select((int)maxfd
+ 1, &set
, NULL
, NULL
, &tv
)) > 0) {
3224 for (i
= 0; i
< n
; i
++) {
3225 if (FD_ISSET(pfd
[i
].fd
, &set
)) {
3226 pfd
[i
].revents
= POLLIN
;
3233 #endif /* HAVE_POLL */
3235 #if defined(__MINGW32__)
3236 /* Enable unused function warning again */
3237 #pragma GCC diagnostic pop
3242 set_close_on_exec(SOCKET sock
, struct mg_connection
*conn
/* may be null */)
3244 (void)conn
; /* Unused. */
3245 (void)SetHandleInformation((HANDLE
)(intptr_t)sock
, HANDLE_FLAG_INHERIT
, 0);
3250 mg_start_thread(mg_thread_func_t f
, void *p
)
3252 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3253 /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
3255 return ((_beginthread((void(__cdecl
*)(void *))f
, USE_STACK_SIZE
, p
)
3256 == ((uintptr_t)(-1L)))
3261 (_beginthread((void(__cdecl
*)(void *))f
, 0, p
) == ((uintptr_t)(-1L)))
3264 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3268 /* Start a thread storing the thread context. */
3270 mg_start_thread_with_id(unsigned(__stdcall
*f
)(void *),
3272 pthread_t
*threadidptr
)
3275 HANDLE threadhandle
;
3278 uip
= _beginthreadex(NULL
, 0, (unsigned(__stdcall
*)(void *))f
, p
, 0, NULL
);
3279 threadhandle
= (HANDLE
)uip
;
3280 if ((uip
!= (uintptr_t)(-1L)) && (threadidptr
!= NULL
)) {
3281 *threadidptr
= threadhandle
;
3289 /* Wait for a thread to finish. */
3291 mg_join_thread(pthread_t threadid
)
3297 dwevent
= WaitForSingleObject(threadid
, INFINITE
);
3298 if (dwevent
== WAIT_FAILED
) {
3299 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO
);
3301 if (dwevent
== WAIT_OBJECT_0
) {
3302 CloseHandle(threadid
);
3310 #if !defined(NO_SSL_DL)
3311 /* Create substitutes for POSIX functions in Win32. */
3313 #if defined(__MINGW32__)
3314 /* Show no warning in case system functions are not used. */
3315 #pragma GCC diagnostic push
3316 #pragma GCC diagnostic ignored "-Wunused-function"
3321 dlopen(const char *dll_name
, int flags
)
3323 wchar_t wbuf
[PATH_MAX
];
3325 path_to_unicode(NULL
, dll_name
, wbuf
, ARRAY_SIZE(wbuf
));
3326 return LoadLibraryW(wbuf
);
3331 dlclose(void *handle
)
3335 if (FreeLibrary((HMODULE
)handle
) != 0) {
3345 #if defined(__MINGW32__)
3346 /* Enable unused function warning again */
3347 #pragma GCC diagnostic pop
3353 #if !defined(NO_CGI)
3357 kill(pid_t pid
, int sig_num
)
3359 (void)TerminateProcess((HANDLE
)pid
, (UINT
)sig_num
);
3360 (void)CloseHandle((HANDLE
)pid
);
3366 trim_trailing_whitespaces(char *s
)
3368 char *e
= s
+ strlen(s
) - 1;
3369 while (e
> s
&& isspace(*(unsigned char *)e
)) {
3376 spawn_process(struct mg_connection
*conn
,
3386 char *p
, *interp
, full_interp
[PATH_MAX
], full_dir
[PATH_MAX
],
3387 cmdline
[PATH_MAX
], buf
[PATH_MAX
];
3389 struct file file
= STRUCT_FILE_INITIALIZER
;
3391 PROCESS_INFORMATION pi
= {0};
3395 memset(&si
, 0, sizeof(si
));
3398 si
.dwFlags
= STARTF_USESTDHANDLES
| STARTF_USESHOWWINDOW
;
3399 si
.wShowWindow
= SW_HIDE
;
3401 me
= GetCurrentProcess();
3403 (HANDLE
)_get_osfhandle(fdin
[0]),
3408 DUPLICATE_SAME_ACCESS
);
3410 (HANDLE
)_get_osfhandle(fdout
[1]),
3415 DUPLICATE_SAME_ACCESS
);
3417 (HANDLE
)_get_osfhandle(fderr
[1]),
3422 DUPLICATE_SAME_ACCESS
);
3424 /* Mark handles that should not be inherited. See
3425 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
3427 SetHandleInformation((HANDLE
)_get_osfhandle(fdin
[1]),
3428 HANDLE_FLAG_INHERIT
,
3430 SetHandleInformation((HANDLE
)_get_osfhandle(fdout
[0]),
3431 HANDLE_FLAG_INHERIT
,
3433 SetHandleInformation((HANDLE
)_get_osfhandle(fderr
[0]),
3434 HANDLE_FLAG_INHERIT
,
3437 /* If CGI file is a script, try to read the interpreter line */
3438 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3439 if (interp
== NULL
) {
3440 buf
[0] = buf
[1] = '\0';
3442 /* Read the first line of the script into the buffer */
3444 conn
, &truncated
, cmdline
, sizeof(cmdline
), "%s/%s", dir
, prog
);
3447 pi
.hProcess
= (pid_t
)-1;
3451 if (mg_fopen(conn
, cmdline
, "r", &file
)) {
3452 p
= (char *)file
.membuf
;
3453 mg_fgets(buf
, sizeof(buf
), &file
, &p
);
3455 buf
[sizeof(buf
) - 1] = '\0';
3458 if (buf
[0] == '#' && buf
[1] == '!') {
3459 trim_trailing_whitespaces(buf
+ 2);
3466 if (interp
[0] != '\0') {
3467 GetFullPathNameA(interp
, sizeof(full_interp
), full_interp
, NULL
);
3468 interp
= full_interp
;
3470 GetFullPathNameA(dir
, sizeof(full_dir
), full_dir
, NULL
);
3472 if (interp
[0] != '\0') {
3477 "\"%s\" \"%s\\%s\"",
3492 pi
.hProcess
= (pid_t
)-1;
3496 DEBUG_TRACE("Running [%s]", cmdline
);
3497 if (CreateProcessA(NULL
,
3502 CREATE_NEW_PROCESS_GROUP
,
3508 conn
, "%s: CreateProcess(%s): %ld", __func__
, cmdline
, (long)ERRNO
);
3509 pi
.hProcess
= (pid_t
)-1;
3510 /* goto spawn_cleanup; */
3514 (void)CloseHandle(si
.hStdOutput
);
3515 (void)CloseHandle(si
.hStdError
);
3516 (void)CloseHandle(si
.hStdInput
);
3517 if (pi
.hThread
!= NULL
) {
3518 (void)CloseHandle(pi
.hThread
);
3521 return (pid_t
)pi
.hProcess
;
3523 #endif /* !NO_CGI */
3527 set_non_blocking_mode(SOCKET sock
)
3529 unsigned long on
= 1;
3530 return ioctlsocket(sock
, (long)FIONBIO
, &on
);
3536 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3542 memset(filep
, 0, sizeof(*filep
));
3544 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3548 if (0 == stat(path
, &st
)) {
3549 filep
->size
= (uint64_t)(st
.st_size
);
3550 filep
->last_modified
= st
.st_mtime
;
3551 filep
->is_directory
= S_ISDIR(st
.st_mode
);
3560 set_close_on_exec(SOCKET fd
, struct mg_connection
*conn
/* may be null */)
3562 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) != 0) {
3565 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
3574 mg_start_thread(mg_thread_func_t func
, void *param
)
3576 pthread_t thread_id
;
3577 pthread_attr_t attr
;
3580 (void)pthread_attr_init(&attr
);
3581 (void)pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3583 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3584 /* Compile-time option to control stack size,
3585 * e.g. -DUSE_STACK_SIZE=16384 */
3586 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3587 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3589 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3590 pthread_attr_destroy(&attr
);
3596 /* Start a thread storing the thread context. */
3598 mg_start_thread_with_id(mg_thread_func_t func
,
3600 pthread_t
*threadidptr
)
3602 pthread_t thread_id
;
3603 pthread_attr_t attr
;
3606 (void)pthread_attr_init(&attr
);
3608 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3609 /* Compile-time option to control stack size,
3610 * e.g. -DUSE_STACK_SIZE=16384 */
3611 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3612 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
3614 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3615 pthread_attr_destroy(&attr
);
3616 if ((result
== 0) && (threadidptr
!= NULL
)) {
3617 *threadidptr
= thread_id
;
3623 /* Wait for a thread to finish. */
3625 mg_join_thread(pthread_t threadid
)
3629 result
= pthread_join(threadid
, NULL
);
3636 spawn_process(struct mg_connection
*conn
,
3654 if ((pid
= fork()) == -1) {
3656 send_http_error(conn
,
3658 "Error: Creating CGI process\nfork(): %s",
3660 } else if (pid
== 0) {
3662 if (chdir(dir
) != 0) {
3663 mg_cry(conn
, "%s: chdir(%s): %s", __func__
, dir
, strerror(ERRNO
));
3664 } else if (dup2(fdin
[0], 0) == -1) {
3666 "%s: dup2(%d, 0): %s",
3670 } else if (dup2(fdout
[1], 1) == -1) {
3672 "%s: dup2(%d, 1): %s",
3676 } else if (dup2(fderr
[1], 2) == -1) {
3678 "%s: dup2(%d, 2): %s",
3683 /* Keep stderr and stdout in two different pipes.
3684 * Stdout will be sent back to the client,
3685 * stderr should go into a server error log. */
3686 (void)close(fdin
[0]);
3687 (void)close(fdout
[1]);
3688 (void)close(fderr
[1]);
3690 /* Close write end fdin and read end fdout and fderr */
3691 (void)close(fdin
[1]);
3692 (void)close(fdout
[0]);
3693 (void)close(fderr
[0]);
3695 /* After exec, all signal handlers are restored to their default
3696 * values, with one exception of SIGCHLD. According to
3697 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
3698 * leave unchanged after exec if it was set to be ignored. Restore
3699 * it to default action. */
3700 signal(SIGCHLD
, SIG_DFL
);
3702 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3703 if (interp
== NULL
) {
3704 (void)execle(prog
, prog
, NULL
, envp
);
3706 "%s: execle(%s): %s",
3711 (void)execle(interp
, interp
, prog
, NULL
, envp
);
3713 "%s: execle(%s %s): %s",
3725 #endif /* !NO_CGI */
3729 set_non_blocking_mode(SOCKET sock
)
3733 flags
= fcntl(sock
, F_GETFL
, 0);
3734 (void)fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
3739 /* End of initial operating system specific define block. */
3742 /* Get a random number (independent of C rand function) */
3746 static uint64_t lfsr
= 0; /* Linear feedback shift register */
3747 static uint64_t lcg
= 0; /* Linear congruential generator */
3748 struct timespec now
;
3750 memset(&now
, 0, sizeof(now
));
3751 clock_gettime(CLOCK_MONOTONIC
, &now
);
3754 /* lfsr will be only 0 if has not been initialized,
3755 * so this code is called only once. */
3756 lfsr
= (((uint64_t)now
.tv_sec
) << 21) ^ ((uint64_t)now
.tv_nsec
)
3757 ^ ((uint64_t)(ptrdiff_t)&now
) ^ (((uint64_t)time(NULL
)) << 33);
3758 lcg
= (((uint64_t)now
.tv_sec
) << 25) + (uint64_t)now
.tv_nsec
3759 + (uint64_t)(ptrdiff_t)&now
;
3761 /* Get the next step of both random number generators. */
3763 | ((((lfsr
>> 0) ^ (lfsr
>> 1) ^ (lfsr
>> 3) ^ (lfsr
>> 4)) & 1)
3765 lcg
= lcg
* 6364136223846793005 + 1442695040888963407;
3768 /* Combining two pseudo-random number generators and a high resolution part
3769 * of the current server time will make it hard (impossible?) to guess the
3771 return (lfsr
^ lcg
^ (uint64_t)now
.tv_nsec
);
3775 /* Write data to the IO channel - opened file descriptor, socket or SSL
3776 * descriptor. Return number of bytes written. */
3778 push(struct mg_context
*ctx
,
3786 struct timespec start
, now
;
3792 typedef size_t len_t
;
3796 memset(&start
, 0, sizeof(start
));
3797 memset(&now
, 0, sizeof(now
));
3798 clock_gettime(CLOCK_MONOTONIC
, &start
);
3815 n
= SSL_write(ssl
, buf
, len
);
3817 err
= SSL_get_error(ssl
, n
);
3818 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (n
== -1)) {
3821 DEBUG_TRACE("SSL_write() failed, error %d", err
);
3830 n
= (int)fwrite(buf
, 1, (size_t)len
, fp
);
3838 n
= (int)send(sock
, buf
, (len_t
)len
, MSG_NOSIGNAL
);
3839 err
= (n
< 0) ? ERRNO
: 0;
3842 if (ctx
->stop_flag
) {
3846 if ((n
> 0) || (n
== 0 && len
== 0)) {
3847 /* some data has been read, or no data was requested */
3851 /* shutdown of the socket at client side */
3855 /* socket error - check errno */
3856 DEBUG_TRACE("send() failed, error %d", err
);
3858 /* TODO: error handling depending on the error code.
3859 * These codes are different between Windows and Linux.
3864 /* This code is not reached in the moment.
3865 * ==> Fix the TODOs above first. */
3868 clock_gettime(CLOCK_MONOTONIC
, &now
);
3871 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
3873 (void)err
; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
3881 push_all(struct mg_context
*ctx
,
3888 double timeout
= -1.0;
3889 int64_t n
, nwritten
= 0;
3895 if (ctx
->config
[REQUEST_TIMEOUT
]) {
3896 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
3899 while (len
> 0 && ctx
->stop_flag
== 0) {
3900 n
= push(ctx
, fp
, sock
, ssl
, buf
+ nwritten
, (int)len
, timeout
);
3902 if (nwritten
== 0) {
3903 nwritten
= n
; /* Propagate the error */
3906 } else if (n
== 0) {
3907 break; /* No more data to write */
3918 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
3919 * Return negative value on error, or number of bytes read on success. */
3921 pull(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
, double timeout
)
3924 struct timespec start
, now
;
3929 typedef size_t len_t
;
3933 memset(&start
, 0, sizeof(start
));
3934 memset(&now
, 0, sizeof(now
));
3935 clock_gettime(CLOCK_MONOTONIC
, &start
);
3940 /* Use read() instead of fread(), because if we're reading from the
3941 * CGI pipe, fread() may block until IO buffer is filled up. We
3942 * cannot afford to block and must pass all read bytes immediately
3944 nread
= (int)read(fileno(fp
), buf
, (size_t)len
);
3945 err
= (nread
< 0) ? ERRNO
: 0;
3948 } else if (conn
->ssl
!= NULL
) {
3949 nread
= SSL_read(conn
->ssl
, buf
, len
);
3951 err
= SSL_get_error(conn
->ssl
, nread
);
3952 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (nread
== -1)) {
3955 DEBUG_TRACE("SSL_read() failed, error %d", err
);
3964 nread
= (int)recv(conn
->client
.sock
, buf
, (len_t
)len
, 0);
3965 err
= (nread
< 0) ? ERRNO
: 0;
3968 if (conn
->ctx
->stop_flag
) {
3972 if ((nread
> 0) || (nread
== 0 && len
== 0)) {
3973 /* some data has been read, or no data was requested */
3977 /* shutdown of the socket at client side */
3981 /* socket error - check errno */
3983 if (err
== WSAEWOULDBLOCK
) {
3984 /* standard case if called from close_socket_gracefully */
3986 } else if (err
== WSAETIMEDOUT
) {
3987 /* timeout is handled by the while loop */
3989 DEBUG_TRACE("recv() failed, error %d", err
);
3993 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
3994 * if the timeout is reached and if the socket was set to non-
3995 * blocking in close_socket_gracefully, so we can not distinguish
3996 * here. We have to wait for the timeout in both cases for now.
3998 if (err
== EAGAIN
|| err
== EWOULDBLOCK
|| err
== EINTR
) {
3999 /* EAGAIN/EWOULDBLOCK:
4000 * standard case if called from close_socket_gracefully
4001 * => should return -1 */
4002 /* or timeout occured
4003 * => the code must stay in the while loop */
4005 /* EINTR can be generated on a socket with a timeout set even
4006 * when SA_RESTART is effective for all relevant signals
4008 * => stay in the while loop */
4010 DEBUG_TRACE("recv() failed, error %d", err
);
4016 clock_gettime(CLOCK_MONOTONIC
, &now
);
4018 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
4020 /* Timeout occured, but no data available. */
4026 pull_all(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
)
4029 double timeout
= -1.0;
4031 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
4032 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
4035 while (len
> 0 && conn
->ctx
->stop_flag
== 0) {
4036 n
= pull(fp
, conn
, buf
+ nread
, len
, timeout
);
4039 nread
= n
; /* Propagate the error */
4042 } else if (n
== 0) {
4043 break; /* No more data to read */
4045 conn
->consumed_content
+= n
;
4056 discard_unread_request_data(struct mg_connection
*conn
)
4058 char buf
[MG_BUF_LEN
];
4066 to_read
= sizeof(buf
);
4068 if (conn
->is_chunked
) {
4069 /* Chunked encoding: 1=chunk not read completely, 2=chunk read
4071 while (conn
->is_chunked
== 1) {
4072 nread
= mg_read(conn
, buf
, to_read
);
4079 /* Not chunked: content length is known */
4080 while (conn
->consumed_content
< conn
->content_len
) {
4082 > (size_t)(conn
->content_len
- conn
->consumed_content
)) {
4083 to_read
= (size_t)(conn
->content_len
- conn
->consumed_content
);
4086 nread
= mg_read(conn
, buf
, to_read
);
4096 mg_read_inner(struct mg_connection
*conn
, void *buf
, size_t len
)
4098 int64_t n
, buffered_len
, nread
;
4100 (int64_t)(len
> INT_MAX
? INT_MAX
: len
); /* since the return value is
4101 * int, we may not read more
4109 /* If Content-Length is not set for a PUT or POST request, read until
4110 * socket is closed */
4111 if (conn
->consumed_content
== 0 && conn
->content_len
== -1) {
4112 conn
->content_len
= INT64_MAX
;
4113 conn
->must_close
= 1;
4117 if (conn
->consumed_content
< conn
->content_len
) {
4118 /* Adjust number of bytes to read. */
4119 int64_t left_to_read
= conn
->content_len
- conn
->consumed_content
;
4120 if (left_to_read
< len64
) {
4121 /* Do not read more than the total content length of the request.
4123 len64
= left_to_read
;
4126 /* Return buffered data */
4127 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
4128 - conn
->consumed_content
;
4129 if (buffered_len
> 0) {
4130 if (len64
< buffered_len
) {
4131 buffered_len
= len64
;
4133 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
4134 memcpy(buf
, body
, (size_t)buffered_len
);
4135 len64
-= buffered_len
;
4136 conn
->consumed_content
+= buffered_len
;
4137 nread
+= buffered_len
;
4138 buf
= (char *)buf
+ buffered_len
;
4141 /* We have returned all buffered data. Read new data from the remote
4144 if ((n
= pull_all(NULL
, conn
, (char *)buf
, (int)len64
)) >= 0) {
4147 nread
= (nread
> 0 ? nread
: n
);
4155 mg_getc(struct mg_connection
*conn
)
4161 conn
->content_len
++;
4162 if (mg_read_inner(conn
, &c
, 1) <= 0) {
4170 mg_read(struct mg_connection
*conn
, void *buf
, size_t len
)
4172 if (len
> INT_MAX
) {
4180 if (conn
->is_chunked
) {
4181 size_t all_read
= 0;
4185 if (conn
->is_chunked
== 2) {
4186 /* No more data left to read */
4190 if (conn
->chunk_remainder
) {
4191 /* copy from the remainder of the last received chunk */
4194 ((conn
->chunk_remainder
> len
) ? (len
)
4195 : (conn
->chunk_remainder
));
4197 conn
->content_len
+= (int)read_now
;
4199 mg_read_inner(conn
, (char *)buf
+ all_read
, read_now
);
4200 all_read
+= (size_t)read_ret
;
4202 conn
->chunk_remainder
-= read_now
;
4205 if (conn
->chunk_remainder
== 0) {
4206 /* the rest of the data in the current chunk has been read
4208 if ((mg_getc(conn
) != '\r') || (mg_getc(conn
) != '\n')) {
4209 /* Protocol violation */
4215 /* fetch a new chunk */
4219 unsigned long chunkSize
= 0;
4221 for (i
= 0; i
< ((int)sizeof(lenbuf
) - 1); i
++) {
4222 lenbuf
[i
] = mg_getc(conn
);
4223 if (i
> 0 && lenbuf
[i
] == '\r' && lenbuf
[i
- 1] != '\r') {
4226 if (i
> 1 && lenbuf
[i
] == '\n' && lenbuf
[i
- 1] == '\r') {
4228 chunkSize
= strtoul(lenbuf
, &end
, 16);
4229 if (chunkSize
== 0) {
4230 /* regular end of content */
4231 conn
->is_chunked
= 2;
4235 if (!isalnum(lenbuf
[i
])) {
4236 /* illegal character for chunk length */
4240 if ((end
== NULL
) || (*end
!= '\r')) {
4241 /* chunksize not set correctly */
4244 if (chunkSize
== 0) {
4248 conn
->chunk_remainder
= chunkSize
;
4252 return (int)all_read
;
4254 return mg_read_inner(conn
, buf
, len
);
4259 mg_write(struct mg_connection
*conn
, const void *buf
, size_t len
)
4262 int64_t n
, total
, allowed
;
4268 if (conn
->throttle
> 0) {
4269 if ((now
= time(NULL
)) != conn
->last_throttle_time
) {
4270 conn
->last_throttle_time
= now
;
4271 conn
->last_throttle_bytes
= 0;
4273 allowed
= conn
->throttle
- conn
->last_throttle_bytes
;
4274 if (allowed
> (int64_t)len
) {
4275 allowed
= (int64_t)len
;
4277 if ((total
= push_all(conn
->ctx
,
4282 (int64_t)allowed
)) == allowed
) {
4283 buf
= (const char *)buf
+ total
;
4284 conn
->last_throttle_bytes
+= total
;
4285 while (total
< (int64_t)len
&& conn
->ctx
->stop_flag
== 0) {
4286 allowed
= conn
->throttle
> (int64_t)len
- total
4287 ? (int64_t)len
- total
4289 if ((n
= push_all(conn
->ctx
,
4294 (int64_t)allowed
)) != allowed
) {
4298 conn
->last_throttle_bytes
= allowed
;
4299 conn
->last_throttle_time
= time(NULL
);
4300 buf
= (const char *)buf
+ n
;
4305 total
= push_all(conn
->ctx
,
4316 /* Alternative alloc_vprintf() for non-compliant C runtimes */
4318 alloc_vprintf2(char **buf
, const char *fmt
, va_list ap
)
4321 size_t size
= MG_BUF_LEN
/ 4;
4331 *buf
= (char *)mg_malloc(size
);
4336 va_copy(ap_copy
, ap
);
4337 len
= vsnprintf_impl(*buf
, size
- 1, fmt
, ap_copy
);
4339 (*buf
)[size
- 1] = 0;
4346 /* Print message to buffer. If buffer is large enough to hold the message,
4347 * return buffer. If buffer is to small, allocate large enough buffer on heap,
4348 * and return allocated buffer. */
4350 alloc_vprintf(char **out_buf
,
4352 size_t prealloc_size
,
4359 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
4360 * buffer is too small. Also, older versions of msvcrt.dll do not have
4361 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
4362 * Therefore, we make two passes: on first pass, get required message
4364 * On second pass, actually print the message. */
4365 va_copy(ap_copy
, ap
);
4366 len
= vsnprintf_impl(NULL
, 0, fmt
, ap_copy
);
4370 /* C runtime is not standard compliant, vsnprintf() returned -1.
4371 * Switch to alternative code path that uses incremental allocations.
4373 va_copy(ap_copy
, ap
);
4374 len
= alloc_vprintf2(out_buf
, fmt
, ap
);
4377 } else if ((size_t)(len
) >= prealloc_size
) {
4378 /* The pre-allocated buffer not large enough. */
4379 /* Allocate a new buffer. */
4380 *out_buf
= (char *)mg_malloc((size_t)(len
) + 1);
4382 /* Allocation failed. Return -1 as "out of memory" error. */
4385 /* Buffer allocation successful. Store the string there. */
4386 va_copy(ap_copy
, ap
);
4387 IGNORE_UNUSED_RESULT(
4388 vsnprintf_impl(*out_buf
, (size_t)(len
) + 1, fmt
, ap_copy
));
4392 /* The pre-allocated buffer is large enough.
4393 * Use it to store the string and return the address. */
4394 va_copy(ap_copy
, ap
);
4395 IGNORE_UNUSED_RESULT(
4396 vsnprintf_impl(prealloc_buf
, prealloc_size
, fmt
, ap_copy
));
4398 *out_buf
= prealloc_buf
;
4406 mg_vprintf(struct mg_connection
*conn
, const char *fmt
, va_list ap
)
4408 char mem
[MG_BUF_LEN
];
4412 if ((len
= alloc_vprintf(&buf
, mem
, sizeof(mem
), fmt
, ap
)) > 0) {
4413 len
= mg_write(conn
, buf
, (size_t)len
);
4415 if (buf
!= mem
&& buf
!= NULL
) {
4424 mg_printf(struct mg_connection
*conn
, const char *fmt
, ...)
4430 result
= mg_vprintf(conn
, fmt
, ap
);
4438 mg_url_decode(const char *src
,
4442 int is_form_url_encoded
)
4445 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
4447 for (i
= j
= 0; i
< src_len
&& j
< dst_len
- 1; i
++, j
++) {
4448 if (i
< src_len
- 2 && src
[i
] == '%'
4449 && isxdigit(*(const unsigned char *)(src
+ i
+ 1))
4450 && isxdigit(*(const unsigned char *)(src
+ i
+ 2))) {
4451 a
= tolower(*(const unsigned char *)(src
+ i
+ 1));
4452 b
= tolower(*(const unsigned char *)(src
+ i
+ 2));
4453 dst
[j
] = (char)((HEXTOI(a
) << 4) | HEXTOI(b
));
4455 } else if (is_form_url_encoded
&& src
[i
] == '+') {
4462 dst
[j
] = '\0'; /* Null-terminate the destination */
4464 return i
>= src_len
? j
: -1;
4469 mg_get_var(const char *data
,
4475 return mg_get_var2(data
, data_len
, name
, dst
, dst_len
, 0);
4480 mg_get_var2(const char *data
,
4487 const char *p
, *e
, *s
;
4491 if (dst
== NULL
|| dst_len
== 0) {
4493 } else if (data
== NULL
|| name
== NULL
|| data_len
== 0) {
4497 name_len
= strlen(name
);
4498 e
= data
+ data_len
;
4502 /* data is "var1=val1&var2=val2...". Find variable first */
4503 for (p
= data
; p
+ name_len
< e
; p
++) {
4504 if ((p
== data
|| p
[-1] == '&') && p
[name_len
] == '='
4505 && !mg_strncasecmp(name
, p
, name_len
) && 0 == occurrence
--) {
4506 /* Point p to variable value */
4509 /* Point s to the end of the value */
4510 s
= (const char *)memchr(p
, '&', (size_t)(e
- p
));
4514 /* assert(s >= p); */
4519 /* Decode variable into destination buffer */
4520 len
= mg_url_decode(p
, (int)(s
- p
), dst
, (int)dst_len
, 1);
4522 /* Redirect error code from -1 to -2 (destination buffer too
4537 mg_get_cookie(const char *cookie_header
,
4538 const char *var_name
,
4542 const char *s
, *p
, *end
;
4543 int name_len
, len
= -1;
4545 if (dst
== NULL
|| dst_size
== 0) {
4547 } else if (var_name
== NULL
|| (s
= cookie_header
) == NULL
) {
4551 name_len
= (int)strlen(var_name
);
4552 end
= s
+ strlen(s
);
4555 for (; (s
= mg_strcasestr(s
, var_name
)) != NULL
; s
+= name_len
) {
4556 if (s
[name_len
] == '=') {
4558 if ((p
= strchr(s
, ' ')) == NULL
) {
4564 if (*s
== '"' && p
[-1] == '"' && p
> s
+ 1) {
4568 if ((size_t)(p
- s
) < dst_size
) {
4570 mg_strlcpy(dst
, s
, (size_t)len
+ 1);
4582 #if defined(USE_WEBSOCKET) || defined(USE_LUA)
4584 base64_encode(const unsigned char *src
, int src_len
, char *dst
)
4586 static const char *b64
=
4587 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4590 for (i
= j
= 0; i
< src_len
; i
+= 3) {
4592 b
= i
+ 1 >= src_len
? 0 : src
[i
+ 1];
4593 c
= i
+ 2 >= src_len
? 0 : src
[i
+ 2];
4595 dst
[j
++] = b64
[a
>> 2];
4596 dst
[j
++] = b64
[((a
& 3) << 4) | (b
>> 4)];
4597 if (i
+ 1 < src_len
) {
4598 dst
[j
++] = b64
[(b
& 15) << 2 | (c
>> 6)];
4600 if (i
+ 2 < src_len
) {
4601 dst
[j
++] = b64
[c
& 63];
4604 while (j
% 4 != 0) {
4612 #if defined(USE_LUA)
4613 static unsigned char
4614 b64reverse(char letter
)
4616 if (letter
>= 'A' && letter
<= 'Z') {
4617 return letter
- 'A';
4619 if (letter
>= 'a' && letter
<= 'z') {
4620 return letter
- 'a' + 26;
4622 if (letter
>= '0' && letter
<= '9') {
4623 return letter
- '0' + 52;
4625 if (letter
== '+') {
4628 if (letter
== '/') {
4631 if (letter
== '=') {
4632 return 255; /* normal end */
4634 return 254; /* error */
4639 base64_decode(const unsigned char *src
, int src_len
, char *dst
, size_t *dst_len
)
4642 unsigned char a
, b
, c
, d
;
4646 for (i
= 0; i
< src_len
; i
+= 4) {
4647 a
= b64reverse(src
[i
]);
4652 b
= b64reverse(i
+ 1 >= src_len
? 0 : src
[i
+ 1]);
4657 c
= b64reverse(i
+ 2 >= src_len
? 0 : src
[i
+ 2]);
4662 d
= b64reverse(i
+ 3 >= src_len
? 0 : src
[i
+ 3]);
4667 dst
[(*dst_len
)++] = (a
<< 2) + (b
>> 4);
4669 dst
[(*dst_len
)++] = (b
<< 4) + (c
>> 2);
4671 dst
[(*dst_len
)++] = (c
<< 6) + d
;
4681 is_put_or_delete_method(const struct mg_connection
*conn
)
4684 const char *s
= conn
->request_info
.request_method
;
4685 return s
!= NULL
&& (!strcmp(s
, "PUT") || !strcmp(s
, "DELETE")
4686 || !strcmp(s
, "MKCOL") || !strcmp(s
, "PATCH"));
4693 interpret_uri(struct mg_connection
*conn
, /* in: request (must be valid) */
4694 char *filename
, /* out: filename */
4695 size_t filename_buf_len
, /* in: size of filename buffer */
4696 struct file
*filep
, /* out: file structure */
4697 int *is_found
, /* out: file is found (directly) */
4698 int *is_script_resource
, /* out: handled by a script? */
4699 int *is_websocket_request
, /* out: websocket connetion? */
4700 int *is_put_or_delete_request
/* out: put/delete a file? */
4703 /* TODO (high): Restructure this function */
4705 #if !defined(NO_FILES)
4706 const char *uri
= conn
->request_info
.local_uri
;
4707 const char *root
= conn
->ctx
->config
[DOCUMENT_ROOT
];
4708 const char *rewrite
;
4711 char gz_path
[PATH_MAX
];
4712 char const *accept_encoding
;
4714 #if !defined(NO_CGI) || defined(USE_LUA)
4718 (void)filename_buf_len
; /* unused if NO_FILES is defined */
4721 memset(filep
, 0, sizeof(*filep
));
4724 *is_script_resource
= 0;
4725 *is_put_or_delete_request
= is_put_or_delete_method(conn
);
4727 #if defined(USE_WEBSOCKET)
4728 *is_websocket_request
= is_websocket_protocol(conn
);
4729 #if !defined(NO_FILES)
4730 if (*is_websocket_request
&& conn
->ctx
->config
[WEBSOCKET_ROOT
]) {
4731 root
= conn
->ctx
->config
[WEBSOCKET_ROOT
];
4733 #endif /* !NO_FILES */
4734 #else /* USE_WEBSOCKET */
4735 *is_websocket_request
= 0;
4736 #endif /* USE_WEBSOCKET */
4738 #if !defined(NO_FILES)
4739 /* Note that root == NULL is a regular use case here. This occurs,
4740 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
4741 * config is not required. */
4743 /* all file related outputs have already been set to 0, just return
4748 /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
4749 * of the path one byte on the right.
4750 * If document_root is NULL, leave the file empty. */
4752 conn
, &truncated
, filename
, filename_buf_len
- 1, "%s%s", root
, uri
);
4755 goto interpret_cleanup
;
4758 rewrite
= conn
->ctx
->config
[REWRITE
];
4759 while ((rewrite
= next_option(rewrite
, &a
, &b
)) != NULL
) {
4760 if ((match_len
= match_prefix(a
.ptr
, a
.len
, uri
)) > 0) {
4764 filename_buf_len
- 1,
4774 goto interpret_cleanup
;
4777 /* Local file path and name, corresponding to requested URI
4778 * is now stored in "filename" variable. */
4779 if (mg_stat(conn
, filename
, filep
)) {
4780 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4781 /* File exists. Check if it is a script type. */
4783 #if !defined(NO_CGI)
4784 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4785 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4788 #if defined(USE_LUA)
4789 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4790 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4793 #if defined(USE_DUKTAPE)
4794 || match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4796 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4800 /* The request addresses a CGI script or a Lua script. The URI
4801 * corresponds to the script itself (like /path/script.cgi),
4802 * and there is no additional resource path
4803 * (like /path/script.cgi/something).
4804 * Requests that modify (replace or delete) a resource, like
4805 * PUT and DELETE requests, should replace/delete the script
4807 * Requests that read or write from/to a resource, like GET and
4808 * POST requests, should call the script and return the
4809 * generated response. */
4810 *is_script_resource
= !*is_put_or_delete_request
;
4812 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4817 /* If we can't find the actual file, look for the file
4818 * with the same name but a .gz extension. If we find it,
4819 * use that and set the gzipped flag in the file struct
4820 * to indicate that the response need to have the content-
4821 * encoding: gzip header.
4822 * We can only do this if the browser declares support. */
4823 if ((accept_encoding
= mg_get_header(conn
, "Accept-Encoding")) != NULL
) {
4824 if (strstr(accept_encoding
, "gzip") != NULL
) {
4826 conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", filename
);
4829 goto interpret_cleanup
;
4832 if (mg_stat(conn
, gz_path
, filep
)) {
4837 /* Currently gz files can not be scripts. */
4843 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4844 /* Support PATH_INFO for CGI scripts. */
4845 for (p
= filename
+ strlen(filename
); p
> filename
+ 1; p
--) {
4849 #if !defined(NO_CGI)
4850 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4851 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4854 #if defined(USE_LUA)
4855 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4857 conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4860 #if defined(USE_DUKTAPE)
4862 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4863 strlen(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4866 ) && mg_stat(conn
, filename
, filep
)) {
4867 /* Shift PATH_INFO block one character right, e.g.
4868 * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
4869 * conn->path_info is pointing to the local variable "path"
4870 * declared in handle_request(), so PATH_INFO is not valid
4871 * after handle_request returns. */
4872 conn
->path_info
= p
+ 1;
4873 memmove(p
+ 2, p
+ 1, strlen(p
+ 1) + 1); /* +1 is for
4876 *is_script_resource
= 1;
4883 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4884 #endif /* !defined(NO_FILES) */
4887 #if !defined(NO_FILES)
4888 /* Reset all outputs */
4890 memset(filep
, 0, sizeof(*filep
));
4893 *is_script_resource
= 0;
4894 *is_websocket_request
= 0;
4895 *is_put_or_delete_request
= 0;
4896 #endif /* !defined(NO_FILES) */
4900 /* Check whether full request is buffered. Return:
4901 * -1 if request is malformed
4902 * 0 if request is not yet fully buffered
4903 * >0 actual request length, including last \r\n\r\n */
4905 get_request_len(const char *buf
, int buflen
)
4911 for (s
= buf
, e
= s
+ buflen
- 1; len
<= 0 && s
< e
; s
++) {
4912 /* Control characters are not allowed but >=128 is. */
4913 if (!in_content
&& !isprint(*(const unsigned char *)s
) && *s
!= '\r'
4915 && *(const unsigned char *)s
< 128) {
4917 break; /* [i_a] abort scan as soon as one malformed character is
4919 /* don't let subsequent \r\n\r\n win us over anyhow */
4920 } else if (s
[0] == '\n' && s
[1] == '\n') {
4921 len
= (int)(s
- buf
) + 2;
4922 } else if (s
[0] == '\n' && &s
[1] < e
&& s
[1] == '\r' && s
[2] == '\n') {
4923 len
= (int)(s
- buf
) + 3;
4927 if (!in_content
&& *s
== ':') {
4936 #if !defined(NO_CACHING)
4937 /* Convert month to the month number. Return -1 on error, or month number */
4939 get_month_index(const char *s
)
4943 for (i
= 0; i
< ARRAY_SIZE(month_names
); i
++) {
4944 if (!strcmp(s
, month_names
[i
])) {
4953 /* Parse UTC date-time string, and return the corresponding time_t value. */
4955 parse_date_string(const char *datetime
)
4957 char month_str
[32] = {0};
4958 int second
, minute
, hour
, day
, month
, year
;
4959 time_t result
= (time_t)0;
4962 if ((sscanf(datetime
,
4963 "%d/%3s/%d %d:%d:%d",
4969 &second
) == 6) || (sscanf(datetime
,
4970 "%d %3s %d %d:%d:%d",
4977 || (sscanf(datetime
,
4978 "%*3s, %d %3s %d %d:%d:%d",
4984 &second
) == 6) || (sscanf(datetime
,
4985 "%d-%3s-%d %d:%d:%d",
4992 month
= get_month_index(month_str
);
4993 if ((month
>= 0) && (year
>= 1970)) {
4994 memset(&tm
, 0, sizeof(tm
));
4995 tm
.tm_year
= year
- 1900;
5001 result
= timegm(&tm
);
5007 #endif /* !NO_CACHING */
5010 /* Protect against directory disclosure attack by removing '..',
5011 * excessive '/' and '\' characters */
5013 remove_double_dots_and_double_slashes(char *s
)
5017 while (*s
!= '\0') {
5019 if (s
[-1] == '/' || s
[-1] == '\\') {
5020 /* Skip all following slashes, backslashes and double-dots */
5021 while (s
[0] != '\0') {
5022 if (s
[0] == '/' || s
[0] == '\\') {
5024 } else if (s
[0] == '.' && s
[1] == '.') {
5036 static const struct {
5037 const char *extension
;
5039 const char *mime_type
;
5040 } builtin_mime_types
[] = {
5041 /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
5042 * application types */
5043 {".doc", 4, "application/msword"},
5044 {".eps", 4, "application/postscript"},
5045 {".exe", 4, "application/octet-stream"},
5046 {".js", 3, "application/javascript"},
5047 {".json", 5, "application/json"},
5048 {".pdf", 4, "application/pdf"},
5049 {".ps", 3, "application/postscript"},
5050 {".rtf", 4, "application/rtf"},
5051 {".xhtml", 6, "application/xhtml+xml"},
5052 {".xsl", 4, "application/xml"},
5053 {".xslt", 5, "application/xml"},
5056 {".ttf", 4, "application/font-sfnt"},
5057 {".cff", 4, "application/font-sfnt"},
5058 {".otf", 4, "application/font-sfnt"},
5059 {".aat", 4, "application/font-sfnt"},
5060 {".sil", 4, "application/font-sfnt"},
5061 {".pfr", 4, "application/font-tdpfr"},
5062 {".woff", 5, "application/font-woff"},
5065 {".mp3", 4, "audio/mpeg"},
5066 {".oga", 4, "audio/ogg"},
5067 {".ogg", 4, "audio/ogg"},
5070 {".gif", 4, "image/gif"},
5071 {".ief", 4, "image/ief"},
5072 {".jpeg", 5, "image/jpeg"},
5073 {".jpg", 4, "image/jpeg"},
5074 {".jpm", 4, "image/jpm"},
5075 {".jpx", 4, "image/jpx"},
5076 {".png", 4, "image/png"},
5077 {".svg", 4, "image/svg+xml"},
5078 {".tif", 4, "image/tiff"},
5079 {".tiff", 5, "image/tiff"},
5082 {".wrl", 4, "model/vrml"},
5085 {".css", 4, "text/css"},
5086 {".csv", 4, "text/csv"},
5087 {".htm", 4, "text/html"},
5088 {".html", 5, "text/html"},
5089 {".sgm", 4, "text/sgml"},
5090 {".shtm", 5, "text/html"},
5091 {".shtml", 6, "text/html"},
5092 {".txt", 4, "text/plain"},
5093 {".xml", 4, "text/xml"},
5096 {".mov", 4, "video/quicktime"},
5097 {".mp4", 4, "video/mp4"},
5098 {".mpeg", 5, "video/mpeg"},
5099 {".mpg", 4, "video/mpeg"},
5100 {".ogv", 4, "video/ogg"},
5101 {".qt", 3, "video/quicktime"},
5103 /* not registered types
5104 * (http://reference.sitepoint.com/html/mime-types-full,
5105 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
5106 {".arj", 4, "application/x-arj-compressed"},
5107 {".gz", 3, "application/x-gunzip"},
5108 {".rar", 4, "application/x-arj-compressed"},
5109 {".swf", 4, "application/x-shockwave-flash"},
5110 {".tar", 4, "application/x-tar"},
5111 {".tgz", 4, "application/x-tar-gz"},
5112 {".torrent", 8, "application/x-bittorrent"},
5113 {".ppt", 4, "application/x-mspowerpoint"},
5114 {".xls", 4, "application/x-msexcel"},
5115 {".zip", 4, "application/x-zip-compressed"},
5118 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
5119 {".aif", 4, "audio/x-aif"},
5120 {".m3u", 4, "audio/x-mpegurl"},
5121 {".mid", 4, "audio/x-midi"},
5122 {".ra", 3, "audio/x-pn-realaudio"},
5123 {".ram", 4, "audio/x-pn-realaudio"},
5124 {".wav", 4, "audio/x-wav"},
5125 {".bmp", 4, "image/bmp"},
5126 {".ico", 4, "image/x-icon"},
5127 {".pct", 4, "image/x-pct"},
5128 {".pict", 5, "image/pict"},
5129 {".rgb", 4, "image/x-rgb"},
5130 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
5131 {".asf", 4, "video/x-ms-asf"},
5132 {".avi", 4, "video/x-msvideo"},
5133 {".m4v", 4, "video/x-m4v"},
5138 mg_get_builtin_mime_type(const char *path
)
5143 path_len
= strlen(path
);
5145 for (i
= 0; builtin_mime_types
[i
].extension
!= NULL
; i
++) {
5146 ext
= path
+ (path_len
- builtin_mime_types
[i
].ext_len
);
5147 if (path_len
> builtin_mime_types
[i
].ext_len
5148 && mg_strcasecmp(ext
, builtin_mime_types
[i
].extension
) == 0) {
5149 return builtin_mime_types
[i
].mime_type
;
5153 return "text/plain";
5157 /* Look at the "path" extension and figure what mime type it has.
5158 * Store mime type in the vector. */
5160 get_mime_type(struct mg_context
*ctx
, const char *path
, struct vec
*vec
)
5162 struct vec ext_vec
, mime_vec
;
5163 const char *list
, *ext
;
5166 path_len
= strlen(path
);
5168 if (ctx
== NULL
|| vec
== NULL
) {
5172 /* Scan user-defined mime types first, in case user wants to
5173 * override default mime types. */
5174 list
= ctx
->config
[EXTRA_MIME_TYPES
];
5175 while ((list
= next_option(list
, &ext_vec
, &mime_vec
)) != NULL
) {
5176 /* ext now points to the path suffix */
5177 ext
= path
+ path_len
- ext_vec
.len
;
5178 if (mg_strncasecmp(ext
, ext_vec
.ptr
, ext_vec
.len
) == 0) {
5184 vec
->ptr
= mg_get_builtin_mime_type(path
);
5185 vec
->len
= strlen(vec
->ptr
);
5189 /* Stringify binary data. Output buffer must be twice as big as input,
5190 * because each byte takes 2 bytes in string representation */
5192 bin2str(char *to
, const unsigned char *p
, size_t len
)
5194 static const char *hex
= "0123456789abcdef";
5196 for (; len
--; p
++) {
5197 *to
++ = hex
[p
[0] >> 4];
5198 *to
++ = hex
[p
[0] & 0x0f];
5204 /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
5206 mg_md5(char buf
[33], ...)
5208 md5_byte_t hash
[16];
5216 while ((p
= va_arg(ap
, const char *)) != NULL
) {
5217 md5_append(&ctx
, (const md5_byte_t
*)p
, strlen(p
));
5221 md5_finish(&ctx
, hash
);
5222 bin2str(buf
, hash
, sizeof(hash
));
5227 /* Check the user's password, return 1 if OK */
5229 check_password(const char *method
,
5236 const char *response
)
5238 char ha2
[32 + 1], expected_response
[32 + 1];
5240 /* Some of the parameters may be NULL */
5241 if (method
== NULL
|| nonce
== NULL
|| nc
== NULL
|| cnonce
== NULL
5243 || response
== NULL
) {
5247 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
5248 if (strlen(response
) != 32) {
5252 mg_md5(ha2
, method
, ":", uri
, NULL
);
5253 mg_md5(expected_response
,
5267 return mg_strcasecmp(response
, expected_response
) == 0;
5271 /* Use the global passwords file, if specified by auth_gpass option,
5272 * or search for .htpasswd in the requested directory. */
5274 open_auth_file(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
5276 if (conn
!= NULL
&& conn
->ctx
!= NULL
) {
5277 char name
[PATH_MAX
];
5278 const char *p
, *e
, *gpass
= conn
->ctx
->config
[GLOBAL_PASSWORDS_FILE
];
5279 struct file file
= STRUCT_FILE_INITIALIZER
;
5282 if (gpass
!= NULL
) {
5283 /* Use global passwords file */
5284 if (!mg_fopen(conn
, gpass
, "r", filep
)) {
5286 mg_cry(conn
, "fopen(%s): %s", gpass
, strerror(ERRNO
));
5289 /* Important: using local struct file to test path for is_directory
5290 * flag. If filep is used, mg_stat() makes it appear as if auth file
5292 } else if (mg_stat(conn
, path
, &file
) && file
.is_directory
) {
5299 PASSWORDS_FILE_NAME
);
5301 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5303 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5307 /* Try to find .htpasswd in requested directory. */
5308 for (p
= path
, e
= p
+ strlen(p
) - 1; e
> p
; e
--) {
5320 PASSWORDS_FILE_NAME
);
5322 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5324 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5332 /* Parsed Authorization header */
5334 char *user
, *uri
, *cnonce
, *response
, *qop
, *nc
, *nonce
;
5338 /* Return 1 on success. Always initializes the ah structure. */
5340 parse_auth_header(struct mg_connection
*conn
,
5345 char *name
, *value
, *s
;
5346 const char *auth_header
;
5353 (void)memset(ah
, 0, sizeof(*ah
));
5354 if ((auth_header
= mg_get_header(conn
, "Authorization")) == NULL
5355 || mg_strncasecmp(auth_header
, "Digest ", 7) != 0) {
5359 /* Make modifiable copy of the auth header */
5360 (void)mg_strlcpy(buf
, auth_header
+ 7, buf_size
);
5363 /* Parse authorization header */
5365 /* Gobble initial spaces */
5366 while (isspace(*(unsigned char *)s
)) {
5369 name
= skip_quoted(&s
, "=", " ", 0);
5370 /* Value is either quote-delimited, or ends at first comma or space. */
5373 value
= skip_quoted(&s
, "\"", " ", '\\');
5378 value
= skip_quoted(&s
, ", ", " ", 0); /* IE uses commas, FF uses
5381 if (*name
== '\0') {
5385 if (!strcmp(name
, "username")) {
5387 } else if (!strcmp(name
, "cnonce")) {
5389 } else if (!strcmp(name
, "response")) {
5390 ah
->response
= value
;
5391 } else if (!strcmp(name
, "uri")) {
5393 } else if (!strcmp(name
, "qop")) {
5395 } else if (!strcmp(name
, "nc")) {
5397 } else if (!strcmp(name
, "nonce")) {
5402 #ifndef NO_NONCE_CHECK
5403 /* Read the nonce from the response. */
5404 if (ah
->nonce
== NULL
) {
5408 nonce
= strtoull(ah
->nonce
, &s
, 10);
5409 if ((s
== NULL
) || (*s
!= 0)) {
5413 /* Convert the nonce from the client to a number. */
5414 nonce
^= conn
->ctx
->auth_nonce_mask
;
5416 /* The converted number corresponds to the time the nounce has been
5417 * created. This should not be earlier than the server start. */
5418 /* Server side nonce check is valuable in all situations but one:
5419 * if the server restarts frequently, but the client should not see
5420 * that, so the server should accept nonces from previous starts. */
5421 /* However, the reasonable default is to not accept a nonce from a
5422 * previous start, so if anyone changed the access rights between
5423 * two restarts, a new login is required. */
5424 if (nonce
< (uint64_t)conn
->ctx
->start_time
) {
5425 /* nonce is from a previous start of the server and no longer valid
5426 * (replay attack?) */
5429 /* Check if the nonce is too high, so it has not (yet) been used by the
5431 if (nonce
>= ((uint64_t)conn
->ctx
->start_time
+ conn
->ctx
->nonce_count
)) {
5436 /* CGI needs it as REMOTE_USER */
5437 if (ah
->user
!= NULL
) {
5438 conn
->request_info
.remote_user
= mg_strdup(ah
->user
);
5448 mg_fgets(char *buf
, size_t size
, struct file
*filep
, char **p
)
5458 if (filep
->membuf
!= NULL
&& *p
!= NULL
) {
5459 memend
= (const char *)&filep
->membuf
[filep
->size
];
5460 /* Search for \n from p till the end of stream */
5461 eof
= (char *)memchr(*p
, '\n', (size_t)(memend
- *p
));
5463 eof
+= 1; /* Include \n */
5465 eof
= memend
; /* Copy remaining data */
5467 len
= (size_t)(eof
- *p
) > size
- 1 ? size
- 1 : (size_t)(eof
- *p
);
5468 memcpy(buf
, *p
, len
);
5471 return len
? eof
: NULL
;
5472 } else if (filep
->fp
!= NULL
) {
5473 return fgets(buf
, (int)size
, filep
->fp
);
5479 struct read_auth_file_struct
{
5480 struct mg_connection
*conn
;
5483 char buf
[256 + 256 + 40];
5491 read_auth_file(struct file
*filep
, struct read_auth_file_struct
*workdata
)
5494 int is_authorized
= 0;
5498 if (!filep
|| !workdata
) {
5502 /* Loop over passwords file */
5503 p
= (char *)filep
->membuf
;
5504 while (mg_fgets(workdata
->buf
, sizeof(workdata
->buf
), filep
, &p
) != NULL
) {
5505 l
= strlen(workdata
->buf
);
5507 if (isspace(workdata
->buf
[l
- 1])
5508 || iscntrl(workdata
->buf
[l
- 1])) {
5510 workdata
->buf
[l
] = 0;
5518 workdata
->f_user
= workdata
->buf
;
5520 if (workdata
->f_user
[0] == ':') {
5521 /* user names may not contain a ':' and may not be empty,
5522 * so lines starting with ':' may be used for a special purpose */
5523 if (workdata
->f_user
[1] == '#') {
5524 /* :# is a comment */
5526 } else if (!strncmp(workdata
->f_user
+ 1, "include=", 8)) {
5527 if (mg_fopen(workdata
->conn
, workdata
->f_user
+ 9, "r", &fp
)) {
5528 is_authorized
= read_auth_file(&fp
, workdata
);
5531 mg_cry(workdata
->conn
,
5532 "%s: cannot open authorization file: %s",
5538 /* everything is invalid for the moment (might change in the
5540 mg_cry(workdata
->conn
,
5541 "%s: syntax error in authorization file: %s",
5547 workdata
->f_domain
= strchr(workdata
->f_user
, ':');
5548 if (workdata
->f_domain
== NULL
) {
5549 mg_cry(workdata
->conn
,
5550 "%s: syntax error in authorization file: %s",
5555 *(workdata
->f_domain
) = 0;
5556 (workdata
->f_domain
)++;
5558 workdata
->f_ha1
= strchr(workdata
->f_domain
, ':');
5559 if (workdata
->f_ha1
== NULL
) {
5560 mg_cry(workdata
->conn
,
5561 "%s: syntax error in authorization file: %s",
5566 *(workdata
->f_ha1
) = 0;
5567 (workdata
->f_ha1
)++;
5569 if (!strcmp(workdata
->ah
.user
, workdata
->f_user
)
5570 && !strcmp(workdata
->domain
, workdata
->f_domain
)) {
5571 return check_password(workdata
->conn
->request_info
.request_method
,
5576 workdata
->ah
.cnonce
,
5578 workdata
->ah
.response
);
5582 return is_authorized
;
5586 /* Authorize against the opened passwords file. Return 1 if authorized. */
5588 authorize(struct mg_connection
*conn
, struct file
*filep
)
5590 struct read_auth_file_struct workdata
;
5591 char buf
[MG_BUF_LEN
];
5593 if (!conn
|| !conn
->ctx
) {
5597 memset(&workdata
, 0, sizeof(workdata
));
5598 workdata
.conn
= conn
;
5600 if (!parse_auth_header(conn
, buf
, sizeof(buf
), &workdata
.ah
)) {
5603 workdata
.domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
5605 return read_auth_file(filep
, &workdata
);
5609 /* Return 1 if request is authorised, 0 otherwise. */
5611 check_authorization(struct mg_connection
*conn
, const char *path
)
5613 char fname
[PATH_MAX
];
5614 struct vec uri_vec
, filename_vec
;
5616 struct file file
= STRUCT_FILE_INITIALIZER
;
5617 int authorized
= 1, truncated
;
5619 if (!conn
|| !conn
->ctx
) {
5623 list
= conn
->ctx
->config
[PROTECT_URI
];
5624 while ((list
= next_option(list
, &uri_vec
, &filename_vec
)) != NULL
) {
5625 if (!memcmp(conn
->request_info
.local_uri
, uri_vec
.ptr
, uri_vec
.len
)) {
5631 (int)filename_vec
.len
,
5634 if (truncated
|| !mg_fopen(conn
, fname
, "r", &file
)) {
5636 "%s: cannot open %s: %s",
5645 if (!is_file_opened(&file
)) {
5646 open_auth_file(conn
, path
, &file
);
5649 if (is_file_opened(&file
)) {
5650 authorized
= authorize(conn
, &file
);
5659 send_authorization_request(struct mg_connection
*conn
)
5662 time_t curtime
= time(NULL
);
5664 if (conn
&& conn
->ctx
) {
5665 uint64_t nonce
= (uint64_t)(conn
->ctx
->start_time
);
5667 (void)pthread_mutex_lock(&conn
->ctx
->nonce_mutex
);
5668 nonce
+= conn
->ctx
->nonce_count
;
5669 ++conn
->ctx
->nonce_count
;
5670 (void)pthread_mutex_unlock(&conn
->ctx
->nonce_mutex
);
5672 nonce
^= conn
->ctx
->auth_nonce_mask
;
5673 conn
->status_code
= 401;
5674 conn
->must_close
= 1;
5676 gmt_time_string(date
, sizeof(date
), &curtime
);
5678 mg_printf(conn
, "HTTP/1.1 401 Unauthorized\r\n");
5679 send_no_cache_header(conn
);
5682 "Connection: %s\r\n"
5683 "Content-Length: 0\r\n"
5684 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
5685 "nonce=\"%" UINT64_FMT
"\"\r\n\r\n",
5687 suggest_connection_header(conn
),
5688 conn
->ctx
->config
[AUTHENTICATION_DOMAIN
],
5694 #if !defined(NO_FILES)
5696 is_authorized_for_put(struct mg_connection
*conn
)
5699 struct file file
= STRUCT_FILE_INITIALIZER
;
5700 const char *passfile
= conn
->ctx
->config
[PUT_DELETE_PASSWORDS_FILE
];
5703 if (passfile
!= NULL
&& mg_fopen(conn
, passfile
, "r", &file
)) {
5704 ret
= authorize(conn
, &file
);
5716 mg_modify_passwords_file(const char *fname
,
5722 char line
[512], u
[512] = "", d
[512] = "", ha1
[33], tmp
[PATH_MAX
+ 8];
5728 /* Regard empty password as no password - remove user record. */
5729 if (pass
!= NULL
&& pass
[0] == '\0') {
5733 /* Other arguments must not be empty */
5734 if (fname
== NULL
|| domain
== NULL
|| user
== NULL
) {
5738 /* Using the given file format, user name and domain must not contain ':'
5740 if (strchr(user
, ':') != NULL
) {
5743 if (strchr(domain
, ':') != NULL
) {
5747 /* Do not allow control characters like newline in user name and domain.
5748 * Do not allow excessively long names either. */
5749 for (i
= 0; i
< 255 && user
[i
] != 0; i
++) {
5750 if (iscntrl(user
[i
])) {
5757 for (i
= 0; i
< 255 && domain
[i
] != 0; i
++) {
5758 if (iscntrl(domain
[i
])) {
5766 /* The maximum length of the path to the password file is limited */
5767 if ((strlen(fname
) + 4) >= PATH_MAX
) {
5771 /* Create a temporary file name. Length has been checked before. */
5773 strcat(tmp
, ".tmp");
5775 /* Create the file if does not exist */
5776 /* Use of fopen here is OK, since fname is only ASCII */
5777 if ((fp
= fopen(fname
, "a+")) != NULL
) {
5781 /* Open the given file and temporary file */
5782 if ((fp
= fopen(fname
, "r")) == NULL
) {
5784 } else if ((fp2
= fopen(tmp
, "w+")) == NULL
) {
5789 /* Copy the stuff to temporary file */
5790 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
5791 if (sscanf(line
, "%255[^:]:%255[^:]:%*s", u
, d
) != 2) {
5797 if (!strcmp(u
, user
) && !strcmp(d
, domain
)) {
5800 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5801 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5804 fprintf(fp2
, "%s", line
);
5808 /* If new user, just add it */
5809 if (!found
&& pass
!= NULL
) {
5810 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5811 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5818 /* Put the temp file in place of real file */
5819 IGNORE_UNUSED_RESULT(remove(fname
));
5820 IGNORE_UNUSED_RESULT(rename(tmp
, fname
));
5827 is_valid_port(unsigned long port
)
5829 return port
< 0xffff;
5834 mg_inet_pton(int af
, const char *src
, void *dst
, size_t dstlen
)
5836 struct addrinfo hints
, *res
, *ressave
;
5840 memset(&hints
, 0, sizeof(struct addrinfo
));
5841 hints
.ai_family
= af
;
5843 gai_ret
= getaddrinfo(src
, NULL
, &hints
, &res
);
5845 /* gai_strerror could be used to convert gai_ret to a string */
5846 /* POSIX return values: see
5847 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
5849 /* Windows return values: see
5850 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
5858 if (dstlen
>= res
->ai_addrlen
) {
5859 memcpy(dst
, res
->ai_addr
, res
->ai_addrlen
);
5865 freeaddrinfo(ressave
);
5871 connect_socket(struct mg_context
*ctx
/* may be NULL */,
5877 SOCKET
*sock
/* output: socket, must not be NULL */,
5878 union usa
*sa
/* output: socket address, must not be NULL */
5882 *sock
= INVALID_SOCKET
;
5883 memset(sa
, 0, sizeof(*sa
));
5891 NULL
, /* No truncation check for ebuf */
5899 if (port
< 0 || !is_valid_port((unsigned)port
)) {
5901 NULL
, /* No truncation check for ebuf */
5910 if (use_ssl
&& (SSLv23_client_method
== NULL
)) {
5912 NULL
, /* No truncation check for ebuf */
5916 "SSL is not initialized");
5921 if (mg_inet_pton(AF_INET
, host
, &sa
->sin
, sizeof(sa
->sin
))) {
5922 sa
->sin
.sin_port
= htons((uint16_t)port
);
5925 } else if (mg_inet_pton(AF_INET6
, host
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5926 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5928 } else if (host
[0] == '[') {
5929 /* While getaddrinfo on Windows will work with [::1],
5930 * getaddrinfo on Linux only works with ::1 (without []). */
5931 size_t l
= strlen(host
+ 1);
5932 char *h
= l
> 1 ? mg_strdup(host
+ 1) : NULL
;
5935 if (mg_inet_pton(AF_INET6
, h
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5936 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5946 NULL
, /* No truncation check for ebuf */
5955 *sock
= socket(PF_INET
, SOCK_STREAM
, 0);
5958 else if (ip_ver
== 6) {
5959 *sock
= socket(PF_INET6
, SOCK_STREAM
, 0);
5963 if (*sock
== INVALID_SOCKET
) {
5965 NULL
, /* No truncation check for ebuf */
5973 set_close_on_exec(*sock
, fc(ctx
));
5976 && (connect(*sock
, (struct sockaddr
*)&sa
->sin
, sizeof(sa
->sin
))
5978 /* connected with IPv4 */
5984 && (connect(*sock
, (struct sockaddr
*)&sa
->sin6
, sizeof(sa
->sin6
))
5986 /* connected with IPv6 */
5993 NULL
, /* No truncation check for ebuf */
5996 "connect(%s:%d): %s",
6001 *sock
= INVALID_SOCKET
;
6007 mg_url_encode(const char *src
, char *dst
, size_t dst_len
)
6009 static const char *dont_escape
= "._-$,;~()";
6010 static const char *hex
= "0123456789abcdef";
6012 const char *end
= dst
+ dst_len
- 1;
6014 for (; *src
!= '\0' && pos
< end
; src
++, pos
++) {
6015 if (isalnum(*(const unsigned char *)src
)
6016 || strchr(dont_escape
, *(const unsigned char *)src
) != NULL
) {
6018 } else if (pos
+ 2 < end
) {
6020 pos
[1] = hex
[(*(const unsigned char *)src
) >> 4];
6021 pos
[2] = hex
[(*(const unsigned char *)src
) & 0xf];
6029 return (*src
== '\0') ? (int)(pos
- dst
) : -1;
6034 print_dir_entry(struct de
*de
)
6036 char size
[64], mod
[64], href
[PATH_MAX
];
6039 if (de
->file
.is_directory
) {
6040 mg_snprintf(de
->conn
,
6041 NULL
, /* Buffer is big enough */
6047 /* We use (signed) cast below because MSVC 6 compiler cannot
6048 * convert unsigned __int64 to double. Sigh. */
6049 if (de
->file
.size
< 1024) {
6050 mg_snprintf(de
->conn
,
6051 NULL
, /* Buffer is big enough */
6055 (int)de
->file
.size
);
6056 } else if (de
->file
.size
< 0x100000) {
6057 mg_snprintf(de
->conn
,
6058 NULL
, /* Buffer is big enough */
6062 (double)de
->file
.size
/ 1024.0);
6063 } else if (de
->file
.size
< 0x40000000) {
6064 mg_snprintf(de
->conn
,
6065 NULL
, /* Buffer is big enough */
6069 (double)de
->file
.size
/ 1048576);
6071 mg_snprintf(de
->conn
,
6072 NULL
, /* Buffer is big enough */
6076 (double)de
->file
.size
/ 1073741824);
6080 /* Note: mg_snprintf will not cause a buffer overflow above.
6081 * So, string truncation checks are not required here. */
6083 tm
= localtime(&de
->file
.last_modified
);
6085 strftime(mod
, sizeof(mod
), "%d-%b-%Y %H:%M", tm
);
6087 mg_strlcpy(mod
, "01-Jan-1970 00:00", sizeof(mod
));
6088 mod
[sizeof(mod
) - 1] = '\0';
6090 mg_url_encode(de
->file_name
, href
, sizeof(href
));
6091 de
->conn
->num_bytes_sent
+=
6093 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
6094 "<td> %s</td><td> %s</td></tr>\n",
6095 de
->conn
->request_info
.local_uri
,
6097 de
->file
.is_directory
? "/" : "",
6099 de
->file
.is_directory
? "/" : "",
6105 /* This function is called from send_directory() and used for
6106 * sorting directory entries by size, or name, or modification time.
6107 * On windows, __cdecl specification is needed in case if project is built
6108 * with __stdcall convention. qsort always requires __cdels callback. */
6110 compare_dir_entries(const void *p1
, const void *p2
)
6113 const struct de
*a
= (const struct de
*)p1
, *b
= (const struct de
*)p2
;
6114 const char *query_string
= a
->conn
->request_info
.query_string
;
6117 if (query_string
== NULL
) {
6118 query_string
= "na";
6121 if (a
->file
.is_directory
&& !b
->file
.is_directory
) {
6122 return -1; /* Always put directories on top */
6123 } else if (!a
->file
.is_directory
&& b
->file
.is_directory
) {
6124 return 1; /* Always put directories on top */
6125 } else if (*query_string
== 'n') {
6126 cmp_result
= strcmp(a
->file_name
, b
->file_name
);
6127 } else if (*query_string
== 's') {
6128 cmp_result
= a
->file
.size
== b
->file
.size
6130 : a
->file
.size
> b
->file
.size
? 1 : -1;
6131 } else if (*query_string
== 'd') {
6133 (a
->file
.last_modified
== b
->file
.last_modified
)
6135 : ((a
->file
.last_modified
> b
->file
.last_modified
) ? 1
6139 return query_string
[1] == 'd' ? -cmp_result
: cmp_result
;
6146 must_hide_file(struct mg_connection
*conn
, const char *path
)
6148 if (conn
&& conn
->ctx
) {
6149 const char *pw_pattern
= "**" PASSWORDS_FILE_NAME
"$";
6150 const char *pattern
= conn
->ctx
->config
[HIDE_FILES
];
6151 return match_prefix(pw_pattern
, strlen(pw_pattern
), path
) > 0
6153 && match_prefix(pattern
, strlen(pattern
), path
) > 0);
6160 scan_directory(struct mg_connection
*conn
,
6163 void (*cb
)(struct de
*, void *))
6165 char path
[PATH_MAX
];
6171 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6176 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6177 /* Do not show current dir and hidden files */
6178 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")
6179 || must_hide_file(conn
, dp
->d_name
)) {
6184 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6186 /* If we don't memset stat structure to zero, mtime will have
6187 * garbage and strftime() will segfault later on in
6188 * print_dir_entry(). memset is required only if mg_stat()
6189 * fails. For more details, see
6190 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6191 memset(&de
.file
, 0, sizeof(de
.file
));
6194 /* If the path is not complete, skip processing. */
6198 if (!mg_stat(conn
, path
, &de
.file
)) {
6200 "%s: mg_stat(%s) failed: %s",
6205 de
.file_name
= dp
->d_name
;
6208 (void)mg_closedir(dirp
);
6214 #if !defined(NO_FILES)
6216 remove_directory(struct mg_connection
*conn
, const char *dir
)
6218 char path
[PATH_MAX
];
6225 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6230 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6231 /* Do not show current dir (but show hidden files as they will
6232 * also be removed) */
6233 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")) {
6238 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6240 /* If we don't memset stat structure to zero, mtime will have
6241 * garbage and strftime() will segfault later on in
6242 * print_dir_entry(). memset is required only if mg_stat()
6243 * fails. For more details, see
6244 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6245 memset(&de
.file
, 0, sizeof(de
.file
));
6248 /* Do not delete anything shorter */
6253 if (!mg_stat(conn
, path
, &de
.file
)) {
6255 "%s: mg_stat(%s) failed: %s",
6261 if (de
.file
.membuf
== NULL
) {
6262 /* file is not in memory */
6263 if (de
.file
.is_directory
) {
6264 if (remove_directory(conn
, path
) == 0) {
6268 if (mg_remove(conn
, path
) == 0) {
6273 /* file is in memory. It can not be deleted. */
6277 (void)mg_closedir(dirp
);
6279 IGNORE_UNUSED_RESULT(rmdir(dir
));
6287 struct dir_scan_data
{
6289 unsigned int num_entries
;
6290 unsigned int arr_size
;
6294 /* Behaves like realloc(), but frees original pointer on failure */
6296 realloc2(void *ptr
, size_t size
)
6298 void *new_ptr
= mg_realloc(ptr
, size
);
6299 if (new_ptr
== NULL
) {
6307 dir_scan_callback(struct de
*de
, void *data
)
6309 struct dir_scan_data
*dsd
= (struct dir_scan_data
*)data
;
6311 if (dsd
->entries
== NULL
|| dsd
->num_entries
>= dsd
->arr_size
) {
6314 (struct de
*)realloc2(dsd
->entries
,
6315 dsd
->arr_size
* sizeof(dsd
->entries
[0]));
6317 if (dsd
->entries
== NULL
) {
6318 /* TODO(lsm, low): propagate an error to the caller */
6319 dsd
->num_entries
= 0;
6321 dsd
->entries
[dsd
->num_entries
].file_name
= mg_strdup(de
->file_name
);
6322 dsd
->entries
[dsd
->num_entries
].file
= de
->file
;
6323 dsd
->entries
[dsd
->num_entries
].conn
= de
->conn
;
6330 handle_directory_request(struct mg_connection
*conn
, const char *dir
)
6334 struct dir_scan_data data
= {NULL
, 0, 128};
6336 time_t curtime
= time(NULL
);
6338 if (!scan_directory(conn
, dir
, &data
, dir_scan_callback
)) {
6339 send_http_error(conn
,
6341 "Error: Cannot open directory\nopendir(%s): %s",
6347 gmt_time_string(date
, sizeof(date
), &curtime
);
6353 sort_direction
= conn
->request_info
.query_string
!= NULL
6354 && conn
->request_info
.query_string
[1] == 'd'
6358 conn
->must_close
= 1;
6359 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
6360 send_static_cache_header(conn
);
6363 "Connection: close\r\n"
6364 "Content-Type: text/html; charset=utf-8\r\n\r\n",
6367 conn
->num_bytes_sent
+=
6369 "<html><head><title>Index of %s</title>"
6370 "<style>th {text-align: left;}</style></head>"
6371 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
6372 "<tr><th><a href=\"?n%c\">Name</a></th>"
6373 "<th><a href=\"?d%c\">Modified</a></th>"
6374 "<th><a href=\"?s%c\">Size</a></th></tr>"
6375 "<tr><td colspan=\"3\"><hr></td></tr>",
6376 conn
->request_info
.local_uri
,
6377 conn
->request_info
.local_uri
,
6382 /* Print first entry - link to a parent directory */
6383 conn
->num_bytes_sent
+=
6385 "<tr><td><a href=\"%s%s\">%s</a></td>"
6386 "<td> %s</td><td> %s</td></tr>\n",
6387 conn
->request_info
.local_uri
,
6393 /* Sort and print directory entries */
6394 if (data
.entries
!= NULL
) {
6396 (size_t)data
.num_entries
,
6397 sizeof(data
.entries
[0]),
6398 compare_dir_entries
);
6399 for (i
= 0; i
< data
.num_entries
; i
++) {
6400 print_dir_entry(&data
.entries
[i
]);
6401 mg_free(data
.entries
[i
].file_name
);
6403 mg_free(data
.entries
);
6406 conn
->num_bytes_sent
+= mg_printf(conn
, "%s", "</table></body></html>");
6407 conn
->status_code
= 200;
6411 /* Send len bytes from the opened file to the client. */
6413 send_file_data(struct mg_connection
*conn
,
6418 char buf
[MG_BUF_LEN
];
6419 int to_read
, num_read
, num_written
;
6422 if (!filep
|| !conn
) {
6426 /* Sanity check the offset */
6427 size
= filep
->size
> INT64_MAX
? INT64_MAX
: (int64_t)(filep
->size
);
6428 offset
= offset
< 0 ? 0 : offset
> size
? size
: offset
;
6430 if (len
> 0 && filep
->membuf
!= NULL
&& size
> 0) {
6431 /* file stored in memory */
6432 if (len
> size
- offset
) {
6433 len
= size
- offset
;
6435 mg_write(conn
, filep
->membuf
+ offset
, (size_t)len
);
6436 } else if (len
> 0 && filep
->fp
!= NULL
) {
6437 /* file stored on disk */
6438 #if defined(__linux__)
6439 /* sendfile is only available for Linux */
6440 if (conn
->throttle
== 0 && conn
->ssl
== 0) {
6441 off_t sf_offs
= (off_t
)offset
;
6443 int sf_file
= fileno(filep
->fp
);
6447 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
6448 * 64 bit Linux (2^31 minus one memory page of 4k?). */
6450 (size_t)((len
< 0x7FFFF000) ? len
: 0x7FFFF000);
6452 sendfile(conn
->client
.sock
, sf_file
, &sf_offs
, sf_tosend
);
6454 conn
->num_bytes_sent
+= sf_sent
;
6457 } else if (loop_cnt
== 0) {
6458 /* This file can not be sent using sendfile.
6459 * This might be the case for pseudo-files in the
6460 * /sys/ and /proc/ file system.
6461 * Use the regular user mode copy code instead. */
6463 } else if (sf_sent
== 0) {
6464 /* No error, but 0 bytes sent. May be EOF? */
6469 } while ((len
> 0) && (sf_sent
>= 0));
6475 /* sf_sent<0 means error, thus fall back to the classic way */
6476 /* This is always the case, if sf_file is not a "normal" file,
6477 * e.g., for sending data from the output of a CGI process. */
6478 offset
= (int64_t)sf_offs
;
6481 if ((offset
> 0) && (fseeko(filep
->fp
, offset
, SEEK_SET
) != 0)) {
6482 mg_cry(conn
, "%s: fseeko() failed: %s", __func__
, strerror(ERRNO
));
6487 "Error: Unable to access file at requested position.");
6490 /* Calculate how much to read from the file in the buffer */
6491 to_read
= sizeof(buf
);
6492 if ((int64_t)to_read
> len
) {
6496 /* Read from file, exit the loop on error */
6497 if ((num_read
= (int)fread(buf
, 1, (size_t)to_read
, filep
->fp
))
6502 /* Send read bytes to the client, exit the loop on error */
6503 if ((num_written
= mg_write(conn
, buf
, (size_t)num_read
))
6508 /* Both read and were successful, adjust counters */
6509 conn
->num_bytes_sent
+= num_written
;
6518 parse_range_header(const char *header
, int64_t *a
, int64_t *b
)
6520 return sscanf(header
, "bytes=%" INT64_FMT
"-%" INT64_FMT
, a
, b
);
6525 construct_etag(char *buf
, size_t buf_len
, const struct file
*filep
)
6527 if (filep
!= NULL
&& buf
!= NULL
) {
6529 NULL
, /* All calls to construct_etag use 64 byte buffer */
6532 "\"%lx.%" INT64_FMT
"\"",
6533 (unsigned long)filep
->last_modified
,
6540 fclose_on_exec(struct file
*filep
, struct mg_connection
*conn
)
6542 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
6544 (void)conn
; /* Unused. */
6546 if (fcntl(fileno(filep
->fp
), F_SETFD
, FD_CLOEXEC
) != 0) {
6548 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
6558 handle_static_file_request(struct mg_connection
*conn
,
6561 const char *mime_type
)
6563 char date
[64], lm
[64], etag
[64];
6564 char range
[128]; /* large enough, so there will be no overflow */
6565 const char *msg
= "OK", *hdr
;
6566 time_t curtime
= time(NULL
);
6568 struct vec mime_vec
;
6570 char gz_path
[PATH_MAX
];
6571 const char *encoding
= "";
6572 const char *cors1
, *cors2
, *cors3
;
6574 if (conn
== NULL
|| conn
->ctx
== NULL
|| filep
== NULL
) {
6578 if (mime_type
== NULL
) {
6579 get_mime_type(conn
->ctx
, path
, &mime_vec
);
6581 mime_vec
.ptr
= mime_type
;
6582 mime_vec
.len
= strlen(mime_type
);
6584 if (filep
->size
> INT64_MAX
) {
6585 send_http_error(conn
,
6587 "Error: File size is too large to send\n%" INT64_FMT
,
6590 cl
= (int64_t)filep
->size
;
6591 conn
->status_code
= 200;
6594 /* if this file is in fact a pre-gzipped file, rewrite its filename
6595 * it's important to rewrite the filename after resolving
6596 * the mime type from it, to preserve the actual file's type */
6597 if (filep
->gzipped
) {
6598 mg_snprintf(conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", path
);
6601 send_http_error(conn
,
6603 "Error: Path of zipped file too long (%s)",
6609 encoding
= "Content-Encoding: gzip\r\n";
6612 if (!mg_fopen(conn
, path
, "rb", filep
)) {
6613 send_http_error(conn
,
6615 "Error: Cannot open file\nfopen(%s): %s",
6621 fclose_on_exec(filep
, conn
);
6623 /* If Range: header specified, act accordingly */
6625 hdr
= mg_get_header(conn
, "Range");
6626 if (hdr
!= NULL
&& (n
= parse_range_header(hdr
, &r1
, &r2
)) > 0 && r1
>= 0
6628 /* actually, range requests don't play well with a pre-gzipped
6629 * file (since the range is specified in the uncompressed space) */
6630 if (filep
->gzipped
) {
6635 "Error: Range requests in gzipped files are not supported");
6639 conn
->status_code
= 206;
6640 cl
= n
== 2 ? (r2
> cl
? cl
: r2
) - r1
+ 1 : cl
- r1
;
6642 NULL
, /* range buffer is big enough */
6645 "Content-Range: bytes "
6646 "%" INT64_FMT
"-%" INT64_FMT
"/%" INT64_FMT
"\r\n",
6650 msg
= "Partial Content";
6653 hdr
= mg_get_header(conn
, "Origin");
6655 /* Cross-origin resource sharing (CORS), see
6656 * http://www.html5rocks.com/en/tutorials/cors/,
6657 * http://www.html5rocks.com/static/images/cors_server_flowchart.png -
6658 * preflight is not supported for files. */
6659 cors1
= "Access-Control-Allow-Origin: ";
6660 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
6663 cors1
= cors2
= cors3
= "";
6666 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
6667 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
6668 gmt_time_string(date
, sizeof(date
), &curtime
);
6669 gmt_time_string(lm
, sizeof(lm
), &filep
->last_modified
);
6670 construct_etag(etag
, sizeof(etag
), filep
);
6672 (void)mg_printf(conn
,
6673 "HTTP/1.1 %d %s\r\n"
6682 send_static_cache_header(conn
);
6683 (void)mg_printf(conn
,
6684 "Last-Modified: %s\r\n"
6686 "Content-Type: %.*s\r\n"
6687 "Content-Length: %" INT64_FMT
"\r\n"
6688 "Connection: %s\r\n"
6689 "Accept-Ranges: bytes\r\n"
6696 suggest_connection_header(conn
),
6700 if (strcmp(conn
->request_info
.request_method
, "HEAD") != 0) {
6701 send_file_data(conn
, filep
, r1
, cl
);
6708 mg_send_file(struct mg_connection
*conn
, const char *path
)
6710 mg_send_mime_file(conn
, path
, NULL
);
6715 mg_send_mime_file(struct mg_connection
*conn
,
6717 const char *mime_type
)
6719 struct file file
= STRUCT_FILE_INITIALIZER
;
6720 if (mg_stat(conn
, path
, &file
)) {
6721 if (file
.is_directory
) {
6725 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
6727 handle_directory_request(conn
, path
);
6729 send_http_error(conn
,
6732 "Error: Directory listing denied");
6735 handle_static_file_request(conn
, path
, &file
, mime_type
);
6738 send_http_error(conn
, 404, "%s", "Error: File not found");
6743 /* For a given PUT path, create all intermediate subdirectories.
6744 * Return 0 if the path itself is a directory.
6745 * Return 1 if the path leads to a file.
6746 * Return -1 for if the path is too long.
6747 * Return -2 if path can not be created.
6750 put_dir(struct mg_connection
*conn
, const char *path
)
6754 struct file file
= STRUCT_FILE_INITIALIZER
;
6758 for (s
= p
= path
+ 2; (p
= strchr(s
, '/')) != NULL
; s
= ++p
) {
6759 len
= (size_t)(p
- path
);
6760 if (len
>= sizeof(buf
)) {
6765 memcpy(buf
, path
, len
);
6768 /* Try to create intermediate directory */
6769 DEBUG_TRACE("mkdir(%s)", buf
);
6770 if (!mg_stat(conn
, buf
, &file
) && mg_mkdir(conn
, buf
, 0755) != 0) {
6771 /* path does not exixt and can not be created */
6776 /* Is path itself a directory? */
6787 remove_bad_file(const struct mg_connection
*conn
, const char *path
)
6789 int r
= mg_remove(conn
, path
);
6791 mg_cry(conn
, "%s: Cannot remove invalid file %s", __func__
, path
);
6797 mg_store_body(struct mg_connection
*conn
, const char *path
)
6799 char buf
[MG_BUF_LEN
];
6804 if (conn
->consumed_content
!= 0) {
6805 mg_cry(conn
, "%s: Contents already consumed", __func__
);
6809 ret
= put_dir(conn
, path
);
6811 /* -1 for path too long,
6812 * -2 for path can not be created. */
6816 /* Return 0 means, path itself is a directory. */
6820 if (mg_fopen(conn
, path
, "w", &fi
) == 0) {
6824 ret
= mg_read(conn
, buf
, sizeof(buf
));
6826 n
= (int)fwrite(buf
, 1, (size_t)ret
, fi
.fp
);
6829 remove_bad_file(conn
, path
);
6832 ret
= mg_read(conn
, buf
, sizeof(buf
));
6835 /* TODO: mg_fclose should return an error,
6836 * and every caller should check and handle it. */
6837 if (fclose(fi
.fp
) != 0) {
6838 remove_bad_file(conn
, path
);
6846 /* Parse HTTP headers from the given buffer, advance buffer to the point
6847 * where parsing stopped. */
6849 parse_http_headers(char **buf
, struct mg_request_info
*ri
)
6857 ri
->num_headers
= 0;
6859 for (i
= 0; i
< (int)ARRAY_SIZE(ri
->http_headers
); i
++) {
6861 while ((*dp
!= ':') && (*dp
!= '\r') && (*dp
!= 0)) {
6865 /* neither : nor \r\n. This is not a valid field. */
6869 if (dp
[1] == '\n') {
6871 ri
->http_headers
[i
].name
= *buf
;
6872 ri
->http_headers
[i
].value
= 0;
6875 /* stray \r. This is not valid. */
6881 ri
->http_headers
[i
].name
= *buf
;
6884 } while (*dp
== ' ');
6886 ri
->http_headers
[i
].value
= dp
;
6887 *buf
= strstr(dp
, "\r\n");
6890 ri
->num_headers
= i
+ 1;
6900 if (*buf
[0] == '\r') {
6901 /* This is the end of the header */
6909 is_valid_http_method(const char *method
)
6911 return !strcmp(method
, "GET") /* HTTP (RFC 2616) */
6912 || !strcmp(method
, "POST") /* HTTP (RFC 2616) */
6913 || !strcmp(method
, "HEAD") /* HTTP (RFC 2616) */
6914 || !strcmp(method
, "PUT") /* HTTP (RFC 2616) */
6915 || !strcmp(method
, "DELETE") /* HTTP (RFC 2616) */
6916 || !strcmp(method
, "OPTIONS") /* HTTP (RFC 2616) */
6917 /* TRACE method (RFC 2616) is not supported for security reasons */
6918 || !strcmp(method
, "CONNECT") /* HTTP (RFC 2616) */
6920 || !strcmp(method
, "PROPFIND") /* WEBDAV (RFC 2518) */
6921 || !strcmp(method
, "MKCOL") /* WEBDAV (RFC 2518) */
6923 /* Unsupported WEBDAV Methods: */
6924 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
6925 /* + 11 methods from RFC 3253 */
6926 /* ORDERPATCH (RFC 3648) */
6927 /* ACL (RFC 3744) */
6928 /* SEARCH (RFC 5323) */
6929 /* + MicroSoft extensions
6930 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
6932 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
6933 || !strcmp(method
, "PATCH"); /* PATCH method (RFC 5789) */
6937 /* Parse HTTP request, fill in mg_request_info structure.
6938 * This function modifies the buffer by NUL-terminating
6939 * HTTP request components, header names and header values. */
6941 parse_http_message(int check_method
,
6944 struct mg_request_info
*ri
)
6946 int is_request
, request_length
;
6952 request_length
= get_request_len(buf
, len
);
6954 if (request_length
> 0) {
6955 /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
6957 ri
->remote_user
= ri
->request_method
= ri
->request_uri
=
6958 ri
->http_version
= NULL
;
6959 ri
->num_headers
= 0;
6961 buf
[request_length
- 1] = '\0';
6963 /* RFC says that all initial whitespaces should be ingored */
6964 while (*buf
!= '\0' && isspace(*(unsigned char *)buf
)) {
6967 ri
->request_method
= skip(&buf
, " ");
6968 ri
->request_uri
= skip(&buf
, " ");
6969 ri
->http_version
= skip(&buf
, "\r\n");
6971 /* HTTP message could be either HTTP request or HTTP response, e.g.
6972 * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
6974 check_method
? is_valid_http_method(ri
->request_method
) : 1;
6975 if ((is_request
&& memcmp(ri
->http_version
, "HTTP/", 5) != 0)
6976 || (!is_request
&& memcmp(ri
->request_method
, "HTTP/", 5) != 0)) {
6977 request_length
= -1;
6980 ri
->http_version
+= 5;
6982 parse_http_headers(&buf
, ri
);
6985 return request_length
;
6989 /* Keep reading the input (either opened file descriptor fd, or socket sock,
6990 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
6991 * buffer (which marks the end of HTTP request). Buffer buf may already
6992 * have some data. The length of the data is stored in nread.
6993 * Upon every read operation, increase nread by the number of bytes read. */
6995 read_request(FILE *fp
,
6996 struct mg_connection
*conn
,
7001 int request_len
, n
= 0;
7002 struct timespec last_action_time
;
7003 double request_timeout
;
7009 memset(&last_action_time
, 0, sizeof(last_action_time
));
7011 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
7012 /* value of request_timeout is in seconds, config in milliseconds */
7013 request_timeout
= atof(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
7015 request_timeout
= -1.0;
7018 request_len
= get_request_len(buf
, *nread
);
7020 /* first time reading from this connection */
7021 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
7024 (conn
->ctx
->stop_flag
== 0) && (*nread
< bufsiz
) && (request_len
== 0)
7025 && ((mg_difftimespec(&last_action_time
, &(conn
->req_time
))
7026 <= request_timeout
) || (request_timeout
< 0))
7027 && ((n
= pull(fp
, conn
, buf
+ *nread
, bufsiz
- *nread
, request_timeout
))
7030 /* assert(*nread <= bufsiz); */
7031 if (*nread
> bufsiz
) {
7034 request_len
= get_request_len(buf
, *nread
);
7035 if (request_timeout
> 0.0) {
7036 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
7040 return (request_len
<= 0 && n
<= 0) ? -1 : request_len
;
7043 #if !defined(NO_FILES)
7044 /* For given directory path, substitute it to valid index file.
7045 * Return 1 if index file has been found, 0 if not found.
7046 * If the file is found, it's stats is returned in stp. */
7048 substitute_index_file(struct mg_connection
*conn
,
7053 if (conn
&& conn
->ctx
) {
7054 const char *list
= conn
->ctx
->config
[INDEX_FILES
];
7055 struct file file
= STRUCT_FILE_INITIALIZER
;
7056 struct vec filename_vec
;
7057 size_t n
= strlen(path
);
7060 /* The 'path' given to us points to the directory. Remove all trailing
7061 * directory separator characters from the end of the path, and
7062 * then append single directory separator character. */
7063 while (n
> 0 && path
[n
- 1] == '/') {
7068 /* Traverse index files list. For each entry, append it to the given
7069 * path and see if the file exists. If it exists, break the loop */
7070 while ((list
= next_option(list
, &filename_vec
, NULL
)) != NULL
) {
7071 /* Ignore too long entries that may overflow path buffer */
7072 if (filename_vec
.len
> path_len
- (n
+ 2)) {
7076 /* Prepare full path to the index file */
7077 mg_strlcpy(path
+ n
+ 1, filename_vec
.ptr
, filename_vec
.len
+ 1);
7079 /* Does it exist? */
7080 if (mg_stat(conn
, path
, &file
)) {
7081 /* Yes it does, break the loop */
7088 /* If no index file exists, restore directory path */
7100 #if !defined(NO_CACHING)
7101 /* Return True if we should reply 304 Not Modified. */
7103 is_not_modified(const struct mg_connection
*conn
, const struct file
*filep
)
7106 const char *ims
= mg_get_header(conn
, "If-Modified-Since");
7107 const char *inm
= mg_get_header(conn
, "If-None-Match");
7108 construct_etag(etag
, sizeof(etag
), filep
);
7112 return (inm
!= NULL
&& !mg_strcasecmp(etag
, inm
))
7113 || (ims
!= NULL
&& (filep
->last_modified
<= parse_date_string(ims
)));
7115 #endif /* !NO_CACHING */
7118 #if !defined(NO_CGI) || !defined(NO_FILES)
7120 forward_body_data(struct mg_connection
*conn
, FILE *fp
, SOCKET sock
, SSL
*ssl
)
7122 const char *expect
, *body
;
7123 char buf
[MG_BUF_LEN
];
7124 int to_read
, nread
, success
= 0;
7125 int64_t buffered_len
;
7126 double timeout
= -1.0;
7131 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
7132 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
7135 expect
= mg_get_header(conn
, "Expect");
7136 /* assert(fp != NULL); */
7138 send_http_error(conn
, 500, "%s", "Error: NULL File");
7142 if (conn
->content_len
== -1 && !conn
->is_chunked
) {
7143 /* Content length is not specified by the client. */
7144 send_http_error(conn
,
7147 "Error: Client did not specify content length");
7148 } else if ((expect
!= NULL
)
7149 && (mg_strcasecmp(expect
, "100-continue") != 0)) {
7150 /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
7151 send_http_error(conn
,
7153 "Error: Can not fulfill expectation %s",
7156 if (expect
!= NULL
) {
7157 (void)mg_printf(conn
, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
7158 conn
->status_code
= 100;
7160 conn
->status_code
= 200;
7163 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
7164 - conn
->consumed_content
;
7166 /* assert(buffered_len >= 0); */
7167 /* assert(conn->consumed_content == 0); */
7169 if ((buffered_len
< 0) || (conn
->consumed_content
!= 0)) {
7170 send_http_error(conn
, 500, "%s", "Error: Size mismatch");
7174 if (buffered_len
> 0) {
7175 if ((int64_t)buffered_len
> conn
->content_len
) {
7176 buffered_len
= (int)conn
->content_len
;
7178 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
7179 push_all(conn
->ctx
, fp
, sock
, ssl
, body
, (int64_t)buffered_len
);
7180 conn
->consumed_content
+= buffered_len
;
7184 while (conn
->consumed_content
< conn
->content_len
) {
7185 to_read
= sizeof(buf
);
7186 if ((int64_t)to_read
> conn
->content_len
- conn
->consumed_content
) {
7187 to_read
= (int)(conn
->content_len
- conn
->consumed_content
);
7189 nread
= pull(NULL
, conn
, buf
, to_read
, timeout
);
7191 || push_all(conn
->ctx
, fp
, sock
, ssl
, buf
, nread
) != nread
) {
7194 conn
->consumed_content
+= nread
;
7197 if (conn
->consumed_content
== conn
->content_len
) {
7198 success
= (nread
>= 0);
7201 /* Each error code path in this function must send an error */
7203 /* NOTE: Maybe some data has already been sent. */
7204 /* TODO (low): If some data has been sent, a correct error
7205 * reply can no longer be sent, so just close the connection */
7206 send_http_error(conn
, 500, "%s", "");
7214 #if !defined(NO_CGI)
7215 /* This structure helps to create an environment for the spawned CGI program.
7216 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
7217 * last element must be NULL.
7218 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
7219 * strings must reside in a contiguous buffer. The end of the buffer is
7220 * marked by two '\0' characters.
7221 * We satisfy both worlds: we create an envp array (which is vars), all
7222 * entries are actually pointers inside buf. */
7223 struct cgi_environment
{
7224 struct mg_connection
*conn
;
7226 char *buf
; /* Environment buffer */
7227 size_t buflen
; /* Space available in buf */
7228 size_t bufused
; /* Space taken in buf */
7230 char **var
; /* char **envp */
7231 size_t varlen
; /* Number of variables available in var */
7232 size_t varused
; /* Number of variables stored in var */
7236 static void addenv(struct cgi_environment
*env
,
7237 PRINTF_FORMAT_STRING(const char *fmt
),
7238 ...) PRINTF_ARGS(2, 3);
7240 /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
7241 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
7243 addenv(struct cgi_environment
*env
, const char *fmt
, ...)
7250 /* Calculate how much space is left in the buffer */
7251 space
= (env
->buflen
- env
->bufused
);
7253 /* Calculate an estimate for the required space */
7254 n
= strlen(fmt
) + 2 + 128;
7258 /* Allocate new buffer */
7259 n
= env
->buflen
+ CGI_ENVIRONMENT_SIZE
;
7260 added
= (char *)mg_realloc(env
->buf
, n
);
7264 "%s: Cannot allocate memory for CGI variable [%s]",
7271 space
= (env
->buflen
- env
->bufused
);
7274 /* Make a pointer to the free space int the buffer */
7275 added
= env
->buf
+ env
->bufused
;
7277 /* Copy VARIABLE=VALUE\0 string into the free space */
7279 mg_vsnprintf(env
->conn
, &truncated
, added
, (size_t)space
, fmt
, ap
);
7282 /* Do not add truncated strings to the environment */
7284 /* Reallocate the buffer */
7288 } while (truncated
);
7290 /* Calculate number of bytes added to the environment */
7291 n
= strlen(added
) + 1;
7294 /* Now update the variable index */
7295 space
= (env
->varlen
- env
->varused
);
7298 "%s: Cannot register CGI variable [%s]",
7304 /* Append a pointer to the added string into the envp array */
7305 env
->var
[env
->varused
] = added
;
7311 prepare_cgi_environment(struct mg_connection
*conn
,
7313 struct cgi_environment
*env
)
7317 char *p
, src_addr
[IP_ADDR_STR_LEN
], http_var_name
[128];
7320 if (conn
== NULL
|| prog
== NULL
|| env
== NULL
) {
7325 env
->buflen
= CGI_ENVIRONMENT_SIZE
;
7327 env
->buf
= (char *)mg_malloc(env
->buflen
);
7328 env
->varlen
= MAX_CGI_ENVIR_VARS
;
7330 env
->var
= (char **)mg_malloc(env
->buflen
* sizeof(char *));
7332 addenv(env
, "SERVER_NAME=%s", conn
->ctx
->config
[AUTHENTICATION_DOMAIN
]);
7333 addenv(env
, "SERVER_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7334 addenv(env
, "DOCUMENT_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7335 addenv(env
, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
7337 /* Prepare the environment block */
7338 addenv(env
, "%s", "GATEWAY_INTERFACE=CGI/1.1");
7339 addenv(env
, "%s", "SERVER_PROTOCOL=HTTP/1.1");
7340 addenv(env
, "%s", "REDIRECT_STATUS=200"); /* For PHP */
7342 #if defined(USE_IPV6)
7343 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
7344 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin6
.sin6_port
));
7348 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin
.sin_port
));
7351 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
7352 addenv(env
, "REMOTE_ADDR=%s", src_addr
);
7354 addenv(env
, "REQUEST_METHOD=%s", conn
->request_info
.request_method
);
7355 addenv(env
, "REMOTE_PORT=%d", conn
->request_info
.remote_port
);
7357 addenv(env
, "REQUEST_URI=%s", conn
->request_info
.request_uri
);
7358 addenv(env
, "LOCAL_URI=%s", conn
->request_info
.local_uri
);
7363 (int)strlen(conn
->request_info
.local_uri
)
7364 - ((conn
->path_info
== NULL
) ? 0 : (int)strlen(conn
->path_info
)),
7365 conn
->request_info
.local_uri
);
7367 addenv(env
, "SCRIPT_FILENAME=%s", prog
);
7368 if (conn
->path_info
== NULL
) {
7369 addenv(env
, "PATH_TRANSLATED=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7372 "PATH_TRANSLATED=%s%s",
7373 conn
->ctx
->config
[DOCUMENT_ROOT
],
7377 addenv(env
, "HTTPS=%s", conn
->ssl
== NULL
? "off" : "on");
7379 if ((s
= mg_get_header(conn
, "Content-Type")) != NULL
) {
7380 addenv(env
, "CONTENT_TYPE=%s", s
);
7382 if (conn
->request_info
.query_string
!= NULL
) {
7383 addenv(env
, "QUERY_STRING=%s", conn
->request_info
.query_string
);
7385 if ((s
= mg_get_header(conn
, "Content-Length")) != NULL
) {
7386 addenv(env
, "CONTENT_LENGTH=%s", s
);
7388 if ((s
= getenv("PATH")) != NULL
) {
7389 addenv(env
, "PATH=%s", s
);
7391 if (conn
->path_info
!= NULL
) {
7392 addenv(env
, "PATH_INFO=%s", conn
->path_info
);
7395 if (conn
->status_code
> 0) {
7396 /* CGI error handler should show the status code */
7397 addenv(env
, "STATUS=%d", conn
->status_code
);
7401 if ((s
= getenv("COMSPEC")) != NULL
) {
7402 addenv(env
, "COMSPEC=%s", s
);
7404 if ((s
= getenv("SYSTEMROOT")) != NULL
) {
7405 addenv(env
, "SYSTEMROOT=%s", s
);
7407 if ((s
= getenv("SystemDrive")) != NULL
) {
7408 addenv(env
, "SystemDrive=%s", s
);
7410 if ((s
= getenv("ProgramFiles")) != NULL
) {
7411 addenv(env
, "ProgramFiles=%s", s
);
7413 if ((s
= getenv("ProgramFiles(x86)")) != NULL
) {
7414 addenv(env
, "ProgramFiles(x86)=%s", s
);
7417 if ((s
= getenv("LD_LIBRARY_PATH")) != NULL
) {
7418 addenv(env
, "LD_LIBRARY_PATH=%s", s
);
7422 if ((s
= getenv("PERLLIB")) != NULL
) {
7423 addenv(env
, "PERLLIB=%s", s
);
7426 if (conn
->request_info
.remote_user
!= NULL
) {
7427 addenv(env
, "REMOTE_USER=%s", conn
->request_info
.remote_user
);
7428 addenv(env
, "%s", "AUTH_TYPE=Digest");
7431 /* Add all headers as HTTP_* variables */
7432 for (i
= 0; i
< conn
->request_info
.num_headers
; i
++) {
7434 (void)mg_snprintf(conn
,
7437 sizeof(http_var_name
),
7439 conn
->request_info
.http_headers
[i
].name
);
7443 "%s: HTTP header variable too long [%s]",
7445 conn
->request_info
.http_headers
[i
].name
);
7449 /* Convert variable name into uppercase, and change - to _ */
7450 for (p
= http_var_name
; *p
!= '\0'; p
++) {
7454 *p
= (char)toupper(*(unsigned char *)p
);
7460 conn
->request_info
.http_headers
[i
].value
);
7463 /* Add user-specified variables */
7464 s
= conn
->ctx
->config
[CGI_ENVIRONMENT
];
7465 while ((s
= next_option(s
, &var_vec
, NULL
)) != NULL
) {
7466 addenv(env
, "%.*s", (int)var_vec
.len
, var_vec
.ptr
);
7469 env
->var
[env
->varused
] = NULL
;
7470 env
->buf
[env
->bufused
] = '\0';
7475 handle_cgi_request(struct mg_connection
*conn
, const char *prog
)
7479 int headers_len
, data_len
, i
, truncated
;
7480 int fdin
[2] = {-1, -1}, fdout
[2] = {-1, -1}, fderr
[2] = {-1, -1};
7481 const char *status
, *status_text
, *connection_state
;
7482 char *pbuf
, dir
[PATH_MAX
], *p
;
7483 struct mg_request_info ri
;
7484 struct cgi_environment blk
;
7485 FILE *in
= NULL
, *out
= NULL
, *err
= NULL
;
7486 struct file fout
= STRUCT_FILE_INITIALIZER
;
7487 pid_t pid
= (pid_t
)-1;
7495 prepare_cgi_environment(conn
, prog
, &blk
);
7497 /* CGI must be executed in its own directory. 'dir' must point to the
7498 * directory containing executable program, 'p' must point to the
7499 * executable program name relative to 'dir'. */
7500 (void)mg_snprintf(conn
, &truncated
, dir
, sizeof(dir
), "%s", prog
);
7503 mg_cry(conn
, "Error: CGI program \"%s\": Path too long", prog
);
7504 send_http_error(conn
, 500, "Error: %s", "CGI path too long");
7508 if ((p
= strrchr(dir
, '/')) != NULL
) {
7511 dir
[0] = '.', dir
[1] = '\0';
7515 if (pipe(fdin
) != 0 || pipe(fdout
) != 0 || pipe(fderr
) != 0) {
7516 status
= strerror(ERRNO
);
7518 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
7521 send_http_error(conn
, 500, "Error: Cannot create CGI pipe: %s", status
);
7525 pid
= spawn_process(conn
, p
, blk
.buf
, blk
.var
, fdin
, fdout
, fderr
, dir
);
7527 if (pid
== (pid_t
)-1) {
7528 status
= strerror(ERRNO
);
7530 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
7533 send_http_error(conn
,
7535 "Error: Cannot spawn CGI process [%s]: %s",
7541 /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
7542 set_close_on_exec((SOCKET
)fdin
[0], conn
); /* stdin read */
7543 set_close_on_exec((SOCKET
)fdout
[1], conn
); /* stdout write */
7544 set_close_on_exec((SOCKET
)fderr
[1], conn
); /* stderr write */
7545 set_close_on_exec((SOCKET
)fdin
[1], conn
); /* stdin write */
7546 set_close_on_exec((SOCKET
)fdout
[0], conn
); /* stdout read */
7547 set_close_on_exec((SOCKET
)fderr
[0], conn
); /* stderr read */
7549 /* Parent closes only one side of the pipes.
7550 * If we don't mark them as closed, close() attempt before
7551 * return from this function throws an exception on Windows.
7552 * Windows does not like when closed descriptor is closed again. */
7553 (void)close(fdin
[0]);
7554 (void)close(fdout
[1]);
7555 (void)close(fderr
[1]);
7556 fdin
[0] = fdout
[1] = fderr
[1] = -1;
7558 if ((in
= fdopen(fdin
[1], "wb")) == NULL
) {
7559 status
= strerror(ERRNO
);
7561 "Error: CGI program \"%s\": Can not open stdin: %s",
7564 send_http_error(conn
,
7566 "Error: CGI can not open fdin\nfopen: %s",
7571 if ((out
= fdopen(fdout
[0], "rb")) == NULL
) {
7572 status
= strerror(ERRNO
);
7574 "Error: CGI program \"%s\": Can not open stdout: %s",
7577 send_http_error(conn
,
7579 "Error: CGI can not open fdout\nfopen: %s",
7584 if ((err
= fdopen(fderr
[0], "rb")) == NULL
) {
7585 status
= strerror(ERRNO
);
7587 "Error: CGI program \"%s\": Can not open stderr: %s",
7590 send_http_error(conn
,
7592 "Error: CGI can not open fdout\nfopen: %s",
7602 if ((conn
->request_info
.content_length
> 0) || conn
->is_chunked
) {
7603 /* This is a POST/PUT request, or another request with body data. */
7604 if (!forward_body_data(conn
, in
, INVALID_SOCKET
, NULL
)) {
7605 /* Error sending the body data */
7607 "Error: CGI program \"%s\": Forward body data failed",
7613 /* Close so child gets an EOF. */
7618 /* Now read CGI reply into a buffer. We need to set correct
7619 * status code, thus we need to see all HTTP headers first.
7620 * Do not send anything back to client, until we buffer in all
7623 buf
= (char *)mg_malloc(buflen
);
7625 send_http_error(conn
,
7627 "Error: Not enough memory for CGI buffer (%u bytes)",
7628 (unsigned int)buflen
);
7630 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
7633 (unsigned int)buflen
);
7636 headers_len
= read_request(out
, conn
, buf
, (int)buflen
, &data_len
);
7637 if (headers_len
<= 0) {
7639 /* Could not parse the CGI response. Check if some error message on
7641 i
= pull_all(err
, conn
, buf
, (int)buflen
);
7644 "Error: CGI program \"%s\" sent error "
7649 send_http_error(conn
,
7651 "Error: CGI program \"%s\" sent error "
7658 "Error: CGI program sent malformed or too big "
7659 "(>%u bytes) HTTP headers: [%.*s]",
7664 send_http_error(conn
,
7666 "Error: CGI program sent malformed or too big "
7667 "(>%u bytes) HTTP headers: [%.*s]",
7676 buf
[headers_len
- 1] = '\0';
7677 parse_http_headers(&pbuf
, &ri
);
7679 /* Make up and send the status line */
7681 if ((status
= get_header(&ri
, "Status")) != NULL
) {
7682 conn
->status_code
= atoi(status
);
7683 status_text
= status
;
7684 while (isdigit(*(const unsigned char *)status_text
)
7685 || *status_text
== ' ') {
7688 } else if (get_header(&ri
, "Location") != NULL
) {
7689 conn
->status_code
= 302;
7691 conn
->status_code
= 200;
7693 connection_state
= get_header(&ri
, "Connection");
7694 if (!header_has_option(connection_state
, "keep-alive")) {
7695 conn
->must_close
= 1;
7697 (void)mg_printf(conn
, "HTTP/1.1 %d %s\r\n", conn
->status_code
, status_text
);
7700 for (i
= 0; i
< ri
.num_headers
; i
++) {
7703 ri
.http_headers
[i
].name
,
7704 ri
.http_headers
[i
].value
);
7706 mg_write(conn
, "\r\n", 2);
7708 /* Send chunk of data that may have been read after the headers */
7709 conn
->num_bytes_sent
+=
7710 mg_write(conn
, buf
+ headers_len
, (size_t)(data_len
- headers_len
));
7712 /* Read the rest of CGI output and send to the client */
7713 send_file_data(conn
, &fout
, 0, INT64_MAX
);
7719 if (pid
!= (pid_t
)-1) {
7721 #if !defined(_WIN32)
7724 while (waitpid(pid
, &st
, 0) != -1)
7725 ; /* clean zombies */
7729 if (fdin
[0] != -1) {
7732 if (fdout
[1] != -1) {
7738 } else if (fdin
[1] != -1) {
7744 } else if (fdout
[0] != -1) {
7750 } else if (fderr
[0] != -1) {
7758 #endif /* !NO_CGI */
7761 #if !defined(NO_FILES)
7763 mkcol(struct mg_connection
*conn
, const char *path
)
7768 time_t curtime
= time(NULL
);
7774 /* TODO (mid): Check the send_http_error situations in this function */
7776 memset(&de
.file
, 0, sizeof(de
.file
));
7777 if (!mg_stat(conn
, path
, &de
.file
)) {
7779 "%s: mg_stat(%s) failed: %s",
7785 if (de
.file
.last_modified
) {
7786 /* TODO (high): This check does not seem to make any sense ! */
7788 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7792 body_len
= conn
->data_len
- conn
->request_len
;
7795 conn
, 415, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7799 rc
= mg_mkdir(conn
, path
, 0755);
7802 conn
->status_code
= 201;
7803 gmt_time_string(date
, sizeof(date
), &curtime
);
7805 "HTTP/1.1 %d Created\r\n"
7809 send_static_cache_header(conn
);
7811 "Content-Length: 0\r\n"
7812 "Connection: %s\r\n\r\n",
7813 suggest_connection_header(conn
));
7814 } else if (rc
== -1) {
7815 if (errno
== EEXIST
) {
7817 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7818 } else if (errno
== EACCES
) {
7820 conn
, 403, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7821 } else if (errno
== ENOENT
) {
7823 conn
, 409, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7825 send_http_error(conn
, 500, "fopen(%s): %s", path
, strerror(ERRNO
));
7832 put_file(struct mg_connection
*conn
, const char *path
)
7834 struct file file
= STRUCT_FILE_INITIALIZER
;
7839 time_t curtime
= time(NULL
);
7845 if (mg_stat(conn
, path
, &file
)) {
7846 /* File already exists */
7847 conn
->status_code
= 200;
7849 if (file
.is_directory
) {
7850 /* This is an already existing directory,
7851 * so there is nothing to do for the server. */
7855 /* File exists and is not a directory. */
7856 /* Can it be replaced? */
7858 if (file
.membuf
!= NULL
) {
7859 /* This is an "in-memory" file, that can not be replaced */
7863 "Error: Put not possible\nReplacing %s is not supported",
7868 /* Check if the server may write this file */
7869 if (access(path
, W_OK
) == 0) {
7870 /* Access granted */
7871 conn
->status_code
= 200;
7877 "Error: Put not possible\nReplacing %s is not allowed",
7883 /* File should be created */
7884 conn
->status_code
= 201;
7885 rc
= put_dir(conn
, path
);
7889 /* put_dir returns 0 if path is a directory */
7890 gmt_time_string(date
, sizeof(date
), &curtime
);
7892 "HTTP/1.1 %d %s\r\n",
7894 mg_get_response_code_text(NULL
, conn
->status_code
));
7895 send_no_cache_header(conn
);
7898 "Content-Length: 0\r\n"
7899 "Connection: %s\r\n\r\n",
7901 suggest_connection_header(conn
));
7903 /* Request to create a directory has been fulfilled successfully.
7904 * No need to put a file. */
7909 /* put_dir returns -1 if the path is too long */
7910 send_http_error(conn
,
7912 "Error: Path too long\nput_dir(%s): %s",
7919 /* put_dir returns -2 if the directory can not be created */
7920 send_http_error(conn
,
7922 "Error: Can not create directory\nput_dir(%s): %s",
7928 /* A file should be created or overwritten. */
7929 if (!mg_fopen(conn
, path
, "wb+", &file
) || file
.fp
== NULL
) {
7931 send_http_error(conn
,
7933 "Error: Can not create file\nfopen(%s): %s",
7939 fclose_on_exec(&file
, conn
);
7940 range
= mg_get_header(conn
, "Content-Range");
7942 if (range
!= NULL
&& parse_range_header(range
, &r1
, &r2
) > 0) {
7943 conn
->status_code
= 206; /* Partial content */
7944 fseeko(file
.fp
, r1
, SEEK_SET
);
7947 if (!forward_body_data(conn
, file
.fp
, INVALID_SOCKET
, NULL
)) {
7948 /* forward_body_data failed.
7949 * The error code has already been sent to the client,
7950 * and conn->status_code is already set. */
7955 gmt_time_string(date
, sizeof(date
), &curtime
);
7957 "HTTP/1.1 %d %s\r\n",
7959 mg_get_response_code_text(NULL
, conn
->status_code
));
7960 send_no_cache_header(conn
);
7963 "Content-Length: 0\r\n"
7964 "Connection: %s\r\n\r\n",
7966 suggest_connection_header(conn
));
7973 delete_file(struct mg_connection
*conn
, const char *path
)
7976 memset(&de
.file
, 0, sizeof(de
.file
));
7977 if (!mg_stat(conn
, path
, &de
.file
)) {
7978 /* mg_stat returns 0 if the file does not exist */
7979 send_http_error(conn
,
7981 "Error: Cannot delete file\nFile %s not found",
7986 if (de
.file
.membuf
!= NULL
) {
7987 /* the file is cached in memory */
7991 "Error: Delete not possible\nDeleting %s is not supported",
7996 if (de
.file
.is_directory
) {
7997 if (remove_directory(conn
, path
)) {
7998 /* Delete is successful: Return 204 without content. */
7999 send_http_error(conn
, 204, "%s", "");
8001 /* Delete is not successful: Return 500 (Server error). */
8002 send_http_error(conn
, 500, "Error: Could not delete %s", path
);
8007 /* This is an existing file (not a directory).
8008 * Check if write permission is granted. */
8009 if (access(path
, W_OK
) != 0) {
8010 /* File is read only */
8014 "Error: Delete not possible\nDeleting %s is not allowed",
8019 /* Try to delete it. */
8020 if (mg_remove(conn
, path
) == 0) {
8021 /* Delete was successful: Return 204 without content. */
8022 send_http_error(conn
, 204, "%s", "");
8024 /* Delete not successful (file locked). */
8025 send_http_error(conn
,
8027 "Error: Cannot delete file\nremove(%s): %s",
8032 #endif /* !NO_FILES */
8036 send_ssi_file(struct mg_connection
*, const char *, struct file
*, int);
8040 do_ssi_include(struct mg_connection
*conn
,
8045 char file_name
[MG_BUF_LEN
], path
[512], *p
;
8046 struct file file
= STRUCT_FILE_INITIALIZER
;
8054 /* sscanf() is safe here, since send_ssi_file() also uses buffer
8055 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
8056 * always < MG_BUF_LEN. */
8057 if (sscanf(tag
, " virtual=\"%511[^\"]\"", file_name
) == 1) {
8058 /* File name is relative to the webserver root */
8060 (void)mg_snprintf(conn
,
8065 conn
->ctx
->config
[DOCUMENT_ROOT
],
8068 } else if (sscanf(tag
, " abspath=\"%511[^\"]\"", file_name
) == 1) {
8069 /* File name is relative to the webserver working directory
8070 * or it is absolute system path */
8073 mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", file_name
);
8075 } else if (sscanf(tag
, " file=\"%511[^\"]\"", file_name
) == 1
8076 || sscanf(tag
, " \"%511[^\"]\"", file_name
) == 1) {
8077 /* File name is relative to the currect document */
8079 (void)mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", ssi
);
8082 if ((p
= strrchr(path
, '/')) != NULL
) {
8086 (void)mg_snprintf(conn
,
8095 mg_cry(conn
, "Bad SSI #include: [%s]", tag
);
8100 mg_cry(conn
, "SSI #include path length overflow: [%s]", tag
);
8104 if (!mg_fopen(conn
, path
, "rb", &file
)) {
8106 "Cannot open SSI #include: [%s]: fopen(%s): %s",
8111 fclose_on_exec(&file
, conn
);
8112 if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
8113 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
8115 send_ssi_file(conn
, path
, &file
, include_level
+ 1);
8117 send_file_data(conn
, &file
, 0, INT64_MAX
);
8124 #if !defined(NO_POPEN)
8126 do_ssi_exec(struct mg_connection
*conn
, char *tag
)
8128 char cmd
[1024] = "";
8129 struct file file
= STRUCT_FILE_INITIALIZER
;
8131 if (sscanf(tag
, " \"%1023[^\"]\"", cmd
) != 1) {
8132 mg_cry(conn
, "Bad SSI #exec: [%s]", tag
);
8135 if ((file
.fp
= popen(cmd
, "r")) == NULL
) {
8136 mg_cry(conn
, "Cannot SSI #exec: [%s]: %s", cmd
, strerror(ERRNO
));
8138 send_file_data(conn
, &file
, 0, INT64_MAX
);
8143 #endif /* !NO_POPEN */
8147 mg_fgetc(struct file
*filep
, int offset
)
8149 if (filep
== NULL
) {
8152 if (filep
->membuf
!= NULL
&& offset
>= 0
8153 && ((unsigned int)(offset
)) < filep
->size
) {
8154 return ((const unsigned char *)filep
->membuf
)[offset
];
8155 } else if (filep
->fp
!= NULL
) {
8156 return fgetc(filep
->fp
);
8164 send_ssi_file(struct mg_connection
*conn
,
8169 char buf
[MG_BUF_LEN
];
8170 int ch
, offset
, len
, in_ssi_tag
;
8172 if (include_level
> 10) {
8173 mg_cry(conn
, "SSI #include level is too deep (%s)", path
);
8177 in_ssi_tag
= len
= offset
= 0;
8178 while ((ch
= mg_fgetc(filep
, offset
)) != EOF
) {
8179 if (in_ssi_tag
&& ch
== '>') {
8181 buf
[len
++] = (char)ch
;
8183 /* assert(len <= (int) sizeof(buf)); */
8184 if (len
> (int)sizeof(buf
)) {
8187 if (len
< 6 || memcmp(buf
, "<!--#", 5) != 0) {
8188 /* Not an SSI tag, pass it */
8189 (void)mg_write(conn
, buf
, (size_t)len
);
8191 if (!memcmp(buf
+ 5, "include", 7)) {
8192 do_ssi_include(conn
, path
, buf
+ 12, include_level
);
8193 #if !defined(NO_POPEN)
8194 } else if (!memcmp(buf
+ 5, "exec", 4)) {
8195 do_ssi_exec(conn
, buf
+ 9);
8196 #endif /* !NO_POPEN */
8206 } else if (in_ssi_tag
) {
8207 if (len
== 5 && memcmp(buf
, "<!--#", 5) != 0) {
8208 /* Not an SSI tag */
8210 } else if (len
== (int)sizeof(buf
) - 2) {
8211 mg_cry(conn
, "%s: SSI tag is too large", path
);
8214 buf
[len
++] = (char)(ch
& 0xff);
8215 } else if (ch
== '<') {
8218 mg_write(conn
, buf
, (size_t)len
);
8221 buf
[len
++] = (char)(ch
& 0xff);
8223 buf
[len
++] = (char)(ch
& 0xff);
8224 if (len
== (int)sizeof(buf
)) {
8225 mg_write(conn
, buf
, (size_t)len
);
8231 /* Send the rest of buffered data */
8233 mg_write(conn
, buf
, (size_t)len
);
8239 handle_ssi_file_request(struct mg_connection
*conn
,
8244 time_t curtime
= time(NULL
);
8245 const char *cors1
, *cors2
, *cors3
;
8247 if (conn
== NULL
|| path
== NULL
|| filep
== NULL
) {
8251 if (mg_get_header(conn
, "Origin")) {
8252 /* Cross-origin resource sharing (CORS). */
8253 cors1
= "Access-Control-Allow-Origin: ";
8254 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
8257 cors1
= cors2
= cors3
= "";
8260 if (!mg_fopen(conn
, path
, "rb", filep
)) {
8261 /* File exists (precondition for calling this function),
8262 * but can not be opened by the server. */
8263 send_http_error(conn
,
8265 "Error: Cannot read file\nfopen(%s): %s",
8269 conn
->must_close
= 1;
8270 gmt_time_string(date
, sizeof(date
), &curtime
);
8271 fclose_on_exec(filep
, conn
);
8272 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
8273 send_no_cache_header(conn
);
8277 "Content-Type: text/html\r\n"
8278 "Connection: %s\r\n\r\n",
8283 suggest_connection_header(conn
));
8284 send_ssi_file(conn
, path
, filep
, 0);
8290 #if !defined(NO_FILES)
8292 send_options(struct mg_connection
*conn
)
8295 time_t curtime
= time(NULL
);
8301 conn
->status_code
= 200;
8302 conn
->must_close
= 1;
8303 gmt_time_string(date
, sizeof(date
), &curtime
);
8306 "HTTP/1.1 200 OK\r\n"
8308 /* TODO: "Cache-Control" (?) */
8309 "Connection: %s\r\n"
8310 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
8311 "PROPFIND, MKCOL\r\n"
8314 suggest_connection_header(conn
));
8318 /* Writes PROPFIND properties for a collection element */
8320 print_props(struct mg_connection
*conn
, const char *uri
, struct file
*filep
)
8324 if (conn
== NULL
|| uri
== NULL
|| filep
== NULL
) {
8328 gmt_time_string(mtime
, sizeof(mtime
), &filep
->last_modified
);
8329 conn
->num_bytes_sent
+=
8332 "<d:href>%s</d:href>"
8335 "<d:resourcetype>%s</d:resourcetype>"
8336 "<d:getcontentlength>%" INT64_FMT
"</d:getcontentlength>"
8337 "<d:getlastmodified>%s</d:getlastmodified>"
8339 "<d:status>HTTP/1.1 200 OK</d:status>"
8343 filep
->is_directory
? "<d:collection/>" : "",
8350 print_dav_dir_entry(struct de
*de
, void *data
)
8352 char href
[PATH_MAX
];
8353 char href_encoded
[PATH_MAX
];
8356 struct mg_connection
*conn
= (struct mg_connection
*)data
;
8365 conn
->request_info
.local_uri
,
8369 mg_url_encode(href
, href_encoded
, PATH_MAX
- 1);
8370 print_props(conn
, href_encoded
, &de
->file
);
8376 handle_propfind(struct mg_connection
*conn
,
8380 const char *depth
= mg_get_header(conn
, "Depth");
8382 time_t curtime
= time(NULL
);
8384 gmt_time_string(date
, sizeof(date
), &curtime
);
8386 if (!conn
|| !path
|| !filep
|| !conn
->ctx
) {
8390 conn
->must_close
= 1;
8391 conn
->status_code
= 207;
8393 "HTTP/1.1 207 Multi-Status\r\n"
8396 send_static_cache_header(conn
);
8398 "Connection: %s\r\n"
8399 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
8400 suggest_connection_header(conn
));
8402 conn
->num_bytes_sent
+=
8404 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
8405 "<d:multistatus xmlns:d='DAV:'>\n");
8407 /* Print properties for the requested resource itself */
8408 print_props(conn
, conn
->request_info
.local_uri
, filep
);
8410 /* If it is a directory, print directory entries too if Depth is not 0 */
8411 if (filep
&& filep
->is_directory
8412 && !mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
], "yes")
8413 && (depth
== NULL
|| strcmp(depth
, "0") != 0)) {
8414 scan_directory(conn
, path
, conn
, &print_dav_dir_entry
);
8417 conn
->num_bytes_sent
+= mg_printf(conn
, "%s\n", "</d:multistatus>");
8422 mg_lock_connection(struct mg_connection
*conn
)
8425 (void)pthread_mutex_lock(&conn
->mutex
);
8430 mg_unlock_connection(struct mg_connection
*conn
)
8433 (void)pthread_mutex_unlock(&conn
->mutex
);
8438 mg_lock_context(struct mg_context
*ctx
)
8441 (void)pthread_mutex_lock(&ctx
->nonce_mutex
);
8446 mg_unlock_context(struct mg_context
*ctx
)
8449 (void)pthread_mutex_unlock(&ctx
->nonce_mutex
);
8453 #if defined(USE_TIMERS)
8454 #include "timer.inl"
8455 #endif /* USE_TIMERS */
8458 #include "mod_lua.inl"
8459 #endif /* USE_LUA */
8462 #include "mod_duktape.inl"
8463 #endif /* USE_DUKTAPE */
8465 #if defined(USE_WEBSOCKET)
8467 /* START OF SHA-1 code
8468 * Copyright(c) By Steve Reid <steve@edmweb.com> */
8469 #define SHA1HANDSOFF
8471 /* According to current tests (May 2015), the <solarisfixes.h> is not required.
8473 * #if defined(__sun)
8474 * #include "solarisfixes.h"
8482 static const int n
= 1;
8483 return ((char *)&n
)[0] == 0;
8487 union char64long16
{
8488 unsigned char c
[64];
8492 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
8496 blk0(union char64long16
*block
, int i
)
8498 /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
8499 if (!is_big_endian()) {
8500 block
->l
[i
] = (rol(block
->l
[i
], 24) & 0xFF00FF00)
8501 | (rol(block
->l
[i
], 8) & 0x00FF00FF);
8507 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
8508 ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
8510 #define R0(v, w, x, y, z, i) \
8511 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
8513 #define R1(v, w, x, y, z, i) \
8514 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
8516 #define R2(v, w, x, y, z, i) \
8517 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
8519 #define R3(v, w, x, y, z, i) \
8520 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
8522 #define R4(v, w, x, y, z, i) \
8523 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
8530 unsigned char buffer
[64];
8535 SHA1Transform(uint32_t state
[5], const unsigned char buffer
[64])
8537 uint32_t a
, b
, c
, d
, e
;
8538 union char64long16 block
[1];
8540 memcpy(block
, buffer
, 64);
8546 R0(a
, b
, c
, d
, e
, 0);
8547 R0(e
, a
, b
, c
, d
, 1);
8548 R0(d
, e
, a
, b
, c
, 2);
8549 R0(c
, d
, e
, a
, b
, 3);
8550 R0(b
, c
, d
, e
, a
, 4);
8551 R0(a
, b
, c
, d
, e
, 5);
8552 R0(e
, a
, b
, c
, d
, 6);
8553 R0(d
, e
, a
, b
, c
, 7);
8554 R0(c
, d
, e
, a
, b
, 8);
8555 R0(b
, c
, d
, e
, a
, 9);
8556 R0(a
, b
, c
, d
, e
, 10);
8557 R0(e
, a
, b
, c
, d
, 11);
8558 R0(d
, e
, a
, b
, c
, 12);
8559 R0(c
, d
, e
, a
, b
, 13);
8560 R0(b
, c
, d
, e
, a
, 14);
8561 R0(a
, b
, c
, d
, e
, 15);
8562 R1(e
, a
, b
, c
, d
, 16);
8563 R1(d
, e
, a
, b
, c
, 17);
8564 R1(c
, d
, e
, a
, b
, 18);
8565 R1(b
, c
, d
, e
, a
, 19);
8566 R2(a
, b
, c
, d
, e
, 20);
8567 R2(e
, a
, b
, c
, d
, 21);
8568 R2(d
, e
, a
, b
, c
, 22);
8569 R2(c
, d
, e
, a
, b
, 23);
8570 R2(b
, c
, d
, e
, a
, 24);
8571 R2(a
, b
, c
, d
, e
, 25);
8572 R2(e
, a
, b
, c
, d
, 26);
8573 R2(d
, e
, a
, b
, c
, 27);
8574 R2(c
, d
, e
, a
, b
, 28);
8575 R2(b
, c
, d
, e
, a
, 29);
8576 R2(a
, b
, c
, d
, e
, 30);
8577 R2(e
, a
, b
, c
, d
, 31);
8578 R2(d
, e
, a
, b
, c
, 32);
8579 R2(c
, d
, e
, a
, b
, 33);
8580 R2(b
, c
, d
, e
, a
, 34);
8581 R2(a
, b
, c
, d
, e
, 35);
8582 R2(e
, a
, b
, c
, d
, 36);
8583 R2(d
, e
, a
, b
, c
, 37);
8584 R2(c
, d
, e
, a
, b
, 38);
8585 R2(b
, c
, d
, e
, a
, 39);
8586 R3(a
, b
, c
, d
, e
, 40);
8587 R3(e
, a
, b
, c
, d
, 41);
8588 R3(d
, e
, a
, b
, c
, 42);
8589 R3(c
, d
, e
, a
, b
, 43);
8590 R3(b
, c
, d
, e
, a
, 44);
8591 R3(a
, b
, c
, d
, e
, 45);
8592 R3(e
, a
, b
, c
, d
, 46);
8593 R3(d
, e
, a
, b
, c
, 47);
8594 R3(c
, d
, e
, a
, b
, 48);
8595 R3(b
, c
, d
, e
, a
, 49);
8596 R3(a
, b
, c
, d
, e
, 50);
8597 R3(e
, a
, b
, c
, d
, 51);
8598 R3(d
, e
, a
, b
, c
, 52);
8599 R3(c
, d
, e
, a
, b
, 53);
8600 R3(b
, c
, d
, e
, a
, 54);
8601 R3(a
, b
, c
, d
, e
, 55);
8602 R3(e
, a
, b
, c
, d
, 56);
8603 R3(d
, e
, a
, b
, c
, 57);
8604 R3(c
, d
, e
, a
, b
, 58);
8605 R3(b
, c
, d
, e
, a
, 59);
8606 R4(a
, b
, c
, d
, e
, 60);
8607 R4(e
, a
, b
, c
, d
, 61);
8608 R4(d
, e
, a
, b
, c
, 62);
8609 R4(c
, d
, e
, a
, b
, 63);
8610 R4(b
, c
, d
, e
, a
, 64);
8611 R4(a
, b
, c
, d
, e
, 65);
8612 R4(e
, a
, b
, c
, d
, 66);
8613 R4(d
, e
, a
, b
, c
, 67);
8614 R4(c
, d
, e
, a
, b
, 68);
8615 R4(b
, c
, d
, e
, a
, 69);
8616 R4(a
, b
, c
, d
, e
, 70);
8617 R4(e
, a
, b
, c
, d
, 71);
8618 R4(d
, e
, a
, b
, c
, 72);
8619 R4(c
, d
, e
, a
, b
, 73);
8620 R4(b
, c
, d
, e
, a
, 74);
8621 R4(a
, b
, c
, d
, e
, 75);
8622 R4(e
, a
, b
, c
, d
, 76);
8623 R4(d
, e
, a
, b
, c
, 77);
8624 R4(c
, d
, e
, a
, b
, 78);
8625 R4(b
, c
, d
, e
, a
, 79);
8631 a
= b
= c
= d
= e
= 0;
8632 memset(block
, '\0', sizeof(block
));
8637 SHA1Init(SHA1_CTX
*context
)
8639 context
->state
[0] = 0x67452301;
8640 context
->state
[1] = 0xEFCDAB89;
8641 context
->state
[2] = 0x98BADCFE;
8642 context
->state
[3] = 0x10325476;
8643 context
->state
[4] = 0xC3D2E1F0;
8644 context
->count
[0] = context
->count
[1] = 0;
8649 SHA1Update(SHA1_CTX
*context
, const unsigned char *data
, uint32_t len
)
8653 j
= context
->count
[0];
8654 if ((context
->count
[0] += len
<< 3) < j
) {
8655 context
->count
[1]++;
8657 context
->count
[1] += (len
>> 29);
8659 if ((j
+ len
) > 63) {
8660 memcpy(&context
->buffer
[j
], data
, (i
= 64 - j
));
8661 SHA1Transform(context
->state
, context
->buffer
);
8662 for (; i
+ 63 < len
; i
+= 64) {
8663 SHA1Transform(context
->state
, &data
[i
]);
8668 memcpy(&context
->buffer
[j
], &data
[i
], len
- i
);
8673 SHA1Final(unsigned char digest
[20], SHA1_CTX
*context
)
8676 unsigned char finalcount
[8], c
;
8678 for (i
= 0; i
< 8; i
++) {
8679 finalcount
[i
] = (unsigned char)((context
->count
[(i
>= 4 ? 0 : 1)]
8680 >> ((3 - (i
& 3)) * 8)) & 255);
8683 SHA1Update(context
, &c
, 1);
8684 while ((context
->count
[0] & 504) != 448) {
8686 SHA1Update(context
, &c
, 1);
8688 SHA1Update(context
, finalcount
, 8);
8689 for (i
= 0; i
< 20; i
++) {
8690 digest
[i
] = (unsigned char)((context
->state
[i
>> 2]
8691 >> ((3 - (i
& 3)) * 8)) & 255);
8693 memset(context
, '\0', sizeof(*context
));
8694 memset(&finalcount
, '\0', sizeof(finalcount
));
8696 /* END OF SHA1 CODE */
8700 send_websocket_handshake(struct mg_connection
*conn
, const char *websock_key
)
8702 static const char *magic
= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8703 const char *protocol
= NULL
;
8704 char buf
[100], sha
[20], b64_sha
[sizeof(sha
) * 2];
8708 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
8709 mg_snprintf(conn
, &truncated
, buf
, sizeof(buf
), "%s%s", websock_key
, magic
);
8711 conn
->must_close
= 1;
8716 SHA1Update(&sha_ctx
, (unsigned char *)buf
, (uint32_t)strlen(buf
));
8717 SHA1Final((unsigned char *)sha
, &sha_ctx
);
8718 base64_encode((unsigned char *)sha
, sizeof(sha
), b64_sha
);
8720 "HTTP/1.1 101 Switching Protocols\r\n"
8721 "Upgrade: websocket\r\n"
8722 "Connection: Upgrade\r\n"
8723 "Sec-WebSocket-Accept: %s\r\n",
8725 protocol
= mg_get_header(conn
, "Sec-WebSocket-Protocol");
8727 /* The protocol is a comma seperated list of names. */
8728 /* The server must only return one value from this list. */
8729 /* First check if it is a list or just a single value. */
8730 const char *sep
= strchr(protocol
, ',');
8732 /* Just a single protocol -> accept it. */
8733 mg_printf(conn
, "Sec-WebSocket-Protocol: %s\r\n\r\n", protocol
);
8735 /* Multiple protocols -> accept the first one. */
8736 /* This is just a quick fix if the client offers multiple
8737 * protocols. In order to get the behavior intended by
8738 * RFC 6455 (https://tools.ietf.org/rfc/rfc6455.txt), it is
8739 * required to have a list of websocket subprotocols accepted
8740 * by the server. Then the server must either select a subprotocol
8741 * supported by client and server, or the server has to abort the
8742 * handshake by not returning a Sec-Websocket-Protocol header if
8743 * no subprotocol is acceptable.
8746 "Sec-WebSocket-Protocol: %.*s\r\n\r\n",
8747 (int)(sep
- protocol
),
8750 /* TODO: Real subprotocol negotiation instead of just taking the first
8751 * websocket subprotocol suggested by the client. */
8753 mg_printf(conn
, "%s", "\r\n");
8761 read_websocket(struct mg_connection
*conn
,
8762 mg_websocket_data_handler ws_data_handler
,
8763 void *callback_data
)
8765 /* Pointer to the beginning of the portion of the incoming websocket
8767 * The original websocket upgrade request is never removed, so the queue
8768 * begins after it. */
8769 unsigned char *buf
= (unsigned char *)conn
->buf
+ conn
->request_len
;
8770 int n
, error
, exit_by_callback
;
8772 /* body_len is the length of the entire queue in bytes
8773 * len is the length of the current message
8774 * data_len is the length of the current message's data payload
8775 * header_len is the length of the current message's header */
8776 size_t i
, len
, mask_len
= 0, data_len
= 0, header_len
, body_len
;
8778 /* "The masking key is a 32-bit value chosen at random by the client."
8779 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
8781 unsigned char mask
[4];
8783 /* data points to the place where the message is stored when passed to
8785 * websocket_data callback. This is either mem on the stack, or a
8786 * dynamically allocated buffer if it is too large. */
8789 unsigned char mop
; /* mask flag and opcode */
8790 double timeout
= -1.0;
8792 if (conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) {
8793 timeout
= atoi(conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) / 1000.0;
8795 if ((timeout
<= 0.0) && (conn
->ctx
->config
[REQUEST_TIMEOUT
])) {
8796 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
8799 mg_set_thread_name("wsock");
8801 /* Loop continuously, reading messages from the socket, invoking the
8802 * callback, and waiting repeatedly until an error occurs. */
8803 while (!conn
->ctx
->stop_flag
) {
8805 assert(conn
->data_len
>= conn
->request_len
);
8806 if ((body_len
= (size_t)(conn
->data_len
- conn
->request_len
)) >= 2) {
8808 mask_len
= buf
[1] & 128 ? 4 : 0;
8809 if (len
< 126 && body_len
>= mask_len
) {
8811 header_len
= 2 + mask_len
;
8812 } else if (len
== 126 && body_len
>= 4 + mask_len
) {
8813 header_len
= 4 + mask_len
;
8814 data_len
= ((((size_t)buf
[2]) << 8) + buf
[3]);
8815 } else if (body_len
>= 10 + mask_len
) {
8816 header_len
= 10 + mask_len
;
8817 data_len
= (((uint64_t)ntohl(*(uint32_t *)(void *)&buf
[2]))
8818 << 32) + ntohl(*(uint32_t *)(void *)&buf
[6]);
8822 if (header_len
> 0 && body_len
>= header_len
) {
8823 /* Allocate space to hold websocket payload */
8825 if (data_len
> sizeof(mem
)) {
8826 data
= (char *)mg_malloc(data_len
);
8828 /* Allocation failed, exit the loop and then close the
8830 mg_cry(conn
, "websocket out of memory; closing connection");
8835 /* Copy the mask before we shift the queue and destroy it */
8837 memcpy(mask
, buf
+ header_len
- mask_len
, sizeof(mask
));
8839 memset(mask
, 0, sizeof(mask
));
8842 /* Read frame payload from the first message in the queue into
8843 * data and advance the queue by moving the memory in place. */
8844 assert(body_len
>= header_len
);
8845 if (data_len
+ header_len
> body_len
) {
8846 mop
= buf
[0]; /* current mask and opcode */
8848 len
= body_len
- header_len
;
8849 memcpy(data
, buf
+ header_len
, len
);
8851 while (len
< data_len
) {
8853 NULL
, conn
, data
+ len
, (int)(data_len
- len
), timeout
);
8861 mg_cry(conn
, "Websocket pull failed; closing connection");
8864 conn
->data_len
= conn
->request_len
;
8866 mop
= buf
[0]; /* current mask and opcode, overwritten by
8868 /* Length of the message being read at the front of the
8870 len
= data_len
+ header_len
;
8872 /* Copy the data payload into the data pointer for the
8874 memcpy(data
, buf
+ header_len
, data_len
);
8876 /* Move the queue forward len bytes */
8877 memmove(buf
, buf
+ len
, body_len
- len
);
8879 /* Mark the queue as advanced */
8880 conn
->data_len
-= (int)len
;
8883 /* Apply mask if necessary */
8885 for (i
= 0; i
< data_len
; ++i
) {
8886 data
[i
] ^= mask
[i
& 3];
8890 /* Exit the loop if callback signals to exit (server side),
8891 * or "connection close" opcode received (client side). */
8892 exit_by_callback
= 0;
8893 if ((ws_data_handler
!= NULL
)
8894 && !ws_data_handler(conn
, mop
, data
, data_len
, callback_data
)) {
8895 exit_by_callback
= 1;
8902 if (exit_by_callback
8903 || ((mop
& 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE
)) {
8904 /* Opcode == 8, connection close */
8908 /* Not breaking the loop, process next websocket frame. */
8910 /* Read from the socket into the next available location in the
8914 conn
->buf
+ conn
->data_len
,
8915 conn
->buf_size
- conn
->data_len
,
8917 /* Error, no bytes read */
8920 conn
->data_len
+= n
;
8924 mg_set_thread_name("worker");
8929 mg_websocket_write_exec(struct mg_connection
*conn
,
8933 uint32_t masking_key
)
8935 unsigned char header
[14];
8936 size_t headerLen
= 1;
8940 header
[0] = 0x80 + (opcode
& 0xF);
8942 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
8943 if (dataLen
< 126) {
8944 /* inline 7-bit length field */
8945 header
[1] = (unsigned char)dataLen
;
8947 } else if (dataLen
<= 0xFFFF) {
8948 /* 16-bit length field */
8950 *(uint16_t *)(void *)(header
+ 2) = htons((uint16_t)dataLen
);
8953 /* 64-bit length field */
8955 *(uint32_t *)(void *)(header
+ 2) = htonl((uint64_t)dataLen
>> 32);
8956 *(uint32_t *)(void *)(header
+ 6) = htonl(dataLen
& 0xFFFFFFFF);
8963 *(uint32_t *)(void *)(header
+ headerLen
) = masking_key
;
8968 /* Note that POSIX/Winsock's send() is threadsafe
8969 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
8970 * but mongoose's mg_printf/mg_write is not (because of the loop in
8971 * push(), although that is only a problem if the packet is large or
8972 * outgoing buffer is full). */
8973 (void)mg_lock_connection(conn
);
8974 retval
= mg_write(conn
, header
, headerLen
);
8976 retval
= mg_write(conn
, data
, dataLen
);
8978 mg_unlock_connection(conn
);
8984 mg_websocket_write(struct mg_connection
*conn
,
8989 return mg_websocket_write_exec(conn
, opcode
, data
, dataLen
, 0);
8994 mask_data(const char *in
, size_t in_len
, uint32_t masking_key
, char *out
)
8999 if ((in_len
> 3) && ((ptrdiff_t)in
% 4) == 0) {
9000 /* Convert in 32 bit words, if data is 4 byte aligned */
9001 while (i
< (in_len
- 3)) {
9002 *(uint32_t *)(void *)(out
+ i
) =
9003 *(uint32_t *)(void *)(in
+ i
) ^ masking_key
;
9008 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
9009 while (i
< in_len
) {
9010 *(uint8_t *)(void *)(out
+ i
) =
9011 *(uint8_t *)(void *)(in
+ i
)
9012 ^ *(((uint8_t *)&masking_key
) + (i
% 4));
9020 mg_websocket_client_write(struct mg_connection
*conn
,
9026 char *masked_data
= (char *)mg_malloc(((dataLen
+ 7) / 4) * 4);
9027 uint32_t masking_key
= (uint32_t)get_random();
9029 if (masked_data
== NULL
) {
9030 /* Return -1 in an error case */
9032 "Cannot allocate buffer for masked websocket response: "
9037 mask_data(data
, dataLen
, masking_key
, masked_data
);
9039 retval
= mg_websocket_write_exec(
9040 conn
, opcode
, masked_data
, dataLen
, masking_key
);
9041 mg_free(masked_data
);
9048 handle_websocket_request(struct mg_connection
*conn
,
9050 int is_callback_resource
,
9051 mg_websocket_connect_handler ws_connect_handler
,
9052 mg_websocket_ready_handler ws_ready_handler
,
9053 mg_websocket_data_handler ws_data_handler
,
9054 mg_websocket_close_handler ws_close_handler
,
9057 const char *websock_key
= mg_get_header(conn
, "Sec-WebSocket-Key");
9058 const char *version
= mg_get_header(conn
, "Sec-WebSocket-Version");
9059 int lua_websock
= 0;
9061 #if !defined(USE_LUA)
9065 /* Step 1: Check websocket protocol version. */
9066 /* Step 1.1: Check Sec-WebSocket-Key. */
9068 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
9069 * requires a Sec-WebSocket-Key header.
9071 /* It could be the hixie draft version
9072 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
9074 const char *key1
= mg_get_header(conn
, "Sec-WebSocket-Key1");
9075 const char *key2
= mg_get_header(conn
, "Sec-WebSocket-Key2");
9078 if ((key1
!= NULL
) && (key2
!= NULL
)) {
9079 /* This version uses 8 byte body data in a GET request */
9080 conn
->content_len
= 8;
9081 if (8 == mg_read(conn
, key3
, 8)) {
9082 /* This is the hixie version */
9083 send_http_error(conn
,
9086 "Protocol upgrade to RFC 6455 required");
9090 /* This is an unknown version */
9091 send_http_error(conn
, 400, "%s", "Malformed websocket request");
9095 /* Step 1.2: Check websocket protocol version. */
9096 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
9097 if (version
== NULL
|| strcmp(version
, "13") != 0) {
9098 /* Reject wrong versions */
9099 send_http_error(conn
, 426, "%s", "Protocol upgrade required");
9103 /* Step 1.3: Could check for "Host", but we do not really nead this
9104 * value for anything, so just ignore it. */
9106 /* Step 2: If a callback is responsible, call it. */
9107 if (is_callback_resource
) {
9108 if (ws_connect_handler
!= NULL
9109 && ws_connect_handler(conn
, cbData
) != 0) {
9110 /* C callback has returned non-zero, do not proceed with
9113 /* Note that C callbacks are no longer called when Lua is
9114 * responsible, so C can no longer filter callbacks for Lua. */
9118 #if defined(USE_LUA)
9119 /* Step 3: No callback. Check if Lua is responsible. */
9121 /* Step 3.1: Check if Lua is responsible. */
9122 if (conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]) {
9124 match_prefix(conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
],
9126 conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]),
9131 /* Step 3.2: Lua is responsible: call it. */
9132 conn
->lua_websocket_state
= lua_websocket_new(path
, conn
);
9133 if (!conn
->lua_websocket_state
) {
9134 /* Lua rejected the new client */
9141 /* Step 4: Check if there is a responsible websocket handler. */
9142 if (!is_callback_resource
&& !lua_websock
) {
9143 /* There is no callback, an Lua is not responsible either. */
9144 /* Reply with a 404 Not Found or with nothing at all?
9145 * TODO (mid): check the websocket standards, how to reply to
9146 * requests to invalid websocket addresses. */
9147 send_http_error(conn
, 404, "%s", "Not found");
9151 /* Step 5: The websocket connection has been accepted */
9152 if (!send_websocket_handshake(conn
, websock_key
)) {
9153 send_http_error(conn
, 500, "%s", "Websocket handshake failed");
9157 /* Step 6: Call the ready handler */
9158 if (is_callback_resource
) {
9159 if (ws_ready_handler
!= NULL
) {
9160 ws_ready_handler(conn
, cbData
);
9162 #if defined(USE_LUA)
9163 } else if (lua_websock
) {
9164 if (!lua_websocket_ready(conn
, conn
->lua_websocket_state
)) {
9165 /* the ready handler returned false */
9171 /* Step 7: Enter the read loop */
9172 if (is_callback_resource
) {
9173 read_websocket(conn
, ws_data_handler
, cbData
);
9174 #if defined(USE_LUA)
9175 } else if (lua_websock
) {
9176 read_websocket(conn
, lua_websocket_data
, conn
->lua_websocket_state
);
9180 /* Step 8: Call the close handler */
9181 if (ws_close_handler
) {
9182 ws_close_handler(conn
, cbData
);
9188 is_websocket_protocol(const struct mg_connection
*conn
)
9190 const char *upgrade
, *connection
;
9192 /* A websocket protocoll has the following HTTP headers:
9194 * Connection: Upgrade
9195 * Upgrade: Websocket
9198 upgrade
= mg_get_header(conn
, "Upgrade");
9199 if (upgrade
== NULL
) {
9200 return 0; /* fail early, don't waste time checking other header
9204 if (!mg_strcasestr(upgrade
, "websocket")) {
9208 connection
= mg_get_header(conn
, "Connection");
9209 if (connection
== NULL
) {
9212 if (!mg_strcasestr(connection
, "upgrade")) {
9216 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
9217 * "Sec-WebSocket-Version" are also required.
9218 * Don't check them here, since even an unsupported websocket protocol
9219 * request still IS a websocket request (in contrast to a standard HTTP
9220 * request). It will fail later in handle_websocket_request.
9225 #endif /* !USE_WEBSOCKET */
9231 return n
>= 0 && n
<= 255;
9236 parse_net(const char *spec
, uint32_t *net
, uint32_t *mask
)
9238 int n
, a
, b
, c
, d
, slash
= 32, len
= 0;
9240 if ((sscanf(spec
, "%d.%d.%d.%d/%d%n", &a
, &b
, &c
, &d
, &slash
, &n
) == 5
9241 || sscanf(spec
, "%d.%d.%d.%d%n", &a
, &b
, &c
, &d
, &n
) == 4) && isbyte(a
)
9242 && isbyte(b
) && isbyte(c
) && isbyte(d
) && slash
>= 0
9245 *net
= ((uint32_t)a
<< 24) | ((uint32_t)b
<< 16) | ((uint32_t)c
<< 8)
9247 *mask
= slash
? 0xffffffffU
<< (32 - slash
) : 0;
9255 set_throttle(const char *spec
, uint32_t remote_ip
, const char *uri
)
9258 struct vec vec
, val
;
9263 while ((spec
= next_option(spec
, &vec
, &val
)) != NULL
) {
9265 if (sscanf(val
.ptr
, "%lf%c", &v
, &mult
) < 1 || v
< 0
9266 || (lowercase(&mult
) != 'k' && lowercase(&mult
) != 'm'
9270 v
*= lowercase(&mult
) == 'k' ? 1024 : lowercase(&mult
) == 'm' ? 1048576
9272 if (vec
.len
== 1 && vec
.ptr
[0] == '*') {
9274 } else if (parse_net(vec
.ptr
, &net
, &mask
) > 0) {
9275 if ((remote_ip
& mask
) == net
) {
9278 } else if (match_prefix(vec
.ptr
, vec
.len
, uri
) > 0) {
9288 get_remote_ip(const struct mg_connection
*conn
)
9293 return ntohl(*(const uint32_t *)&conn
->client
.rsa
.sin
.sin_addr
);
9297 /* The mg_upload function is superseeded by mg_handle_form_request. */
9298 #include "handle_form.inl"
9301 #if defined(MG_LEGACY_INTERFACE)
9302 /* Implement the deprecated mg_upload function by calling the new
9303 * mg_handle_form_request function. While mg_upload could only handle
9304 * HTML forms sent as POST request in multipart/form-data format
9305 * containing only file input elements, mg_handle_form_request can
9306 * handle all form input elements and all standard request methods. */
9307 struct mg_upload_user_data
{
9308 struct mg_connection
*conn
;
9309 const char *destination_dir
;
9310 int num_uploaded_files
;
9314 /* Helper function for deprecated mg_upload. */
9316 mg_upload_field_found(const char *key
,
9317 const char *filename
,
9323 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9327 mg_cry(fud
->conn
, "%s: No filename set", __func__
);
9328 return FORM_FIELD_STORAGE_ABORT
;
9330 mg_snprintf(fud
->conn
,
9335 fud
->destination_dir
,
9338 mg_cry(fud
->conn
, "%s: File path too long", __func__
);
9339 return FORM_FIELD_STORAGE_ABORT
;
9341 return FORM_FIELD_STORAGE_STORE
;
9345 /* Helper function for deprecated mg_upload. */
9347 mg_upload_field_get(const char *key
,
9352 /* Function should never be called */
9362 /* Helper function for deprecated mg_upload. */
9364 mg_upload_field_stored(const char *path
, long long file_size
, void *user_data
)
9366 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9369 fud
->num_uploaded_files
++;
9370 fud
->conn
->ctx
->callbacks
.upload(fud
->conn
, path
);
9376 /* Deprecated function mg_upload - use mg_handle_form_request instead. */
9378 mg_upload(struct mg_connection
*conn
, const char *destination_dir
)
9380 struct mg_upload_user_data fud
= {conn
, destination_dir
, 0};
9381 struct mg_form_data_handler fdh
= {mg_upload_field_found
,
9382 mg_upload_field_get
,
9383 mg_upload_field_stored
,
9387 fdh
.user_data
= (void *)&fud
;
9388 ret
= mg_handle_form_request(conn
, &fdh
);
9391 mg_cry(conn
, "%s: Error while parsing the request", __func__
);
9394 return fud
.num_uploaded_files
;
9400 get_first_ssl_listener_index(const struct mg_context
*ctx
)
9405 for (i
= 0; idx
== -1 && i
< ctx
->num_listening_sockets
; i
++) {
9406 idx
= ctx
->listening_sockets
[i
].is_ssl
? ((int)(i
)) : -1;
9414 redirect_to_https_port(struct mg_connection
*conn
, int ssl_index
)
9417 const char *host_header
;
9420 host_header
= mg_get_header(conn
, "Host");
9421 hostlen
= sizeof(host
);
9422 if (host_header
!= NULL
) {
9425 mg_strlcpy(host
, host_header
, hostlen
);
9426 host
[hostlen
- 1] = '\0';
9427 pos
= strchr(host
, ':');
9432 /* Cannot get host from the Host: header.
9433 * Fallback to our IP address. */
9435 sockaddr_to_string(host
, hostlen
, &conn
->client
.lsa
);
9439 /* Send host, port, uri and (if it exists) ?query_string */
9442 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
9445 conn
->ctx
->listening_sockets
[ssl_index
].lsa
.sin
.sin_port
),
9446 conn
->request_info
.local_uri
,
9447 (conn
->request_info
.query_string
== NULL
) ? "" : "?",
9448 (conn
->request_info
.query_string
== NULL
)
9450 : conn
->request_info
.query_string
);
9456 mg_set_handler_type(struct mg_context
*ctx
,
9459 int is_delete_request
,
9460 mg_request_handler handler
,
9461 mg_websocket_connect_handler connect_handler
,
9462 mg_websocket_ready_handler ready_handler
,
9463 mg_websocket_data_handler data_handler
,
9464 mg_websocket_close_handler close_handler
,
9465 mg_authorization_handler auth_handler
,
9468 struct mg_handler_info
*tmp_rh
, **lastref
;
9469 size_t urilen
= strlen(uri
);
9471 if (handler_type
== WEBSOCKET_HANDLER
) {
9472 /* assert(handler == NULL); */
9473 /* assert(is_delete_request || connect_handler!=NULL ||
9474 * ready_handler!=NULL || data_handler!=NULL ||
9475 * close_handler!=NULL);
9477 /* assert(auth_handler == NULL); */
9478 if (handler
!= NULL
) {
9481 if (!is_delete_request
&& connect_handler
== NULL
9482 && ready_handler
== NULL
9483 && data_handler
== NULL
9484 && close_handler
== NULL
) {
9487 if (auth_handler
!= NULL
) {
9490 } else if (handler_type
== REQUEST_HANDLER
) {
9491 /* assert(connect_handler==NULL && ready_handler==NULL &&
9492 * data_handler==NULL && close_handler==NULL); */
9493 /* assert(is_delete_request || (handler!=NULL));
9495 /* assert(auth_handler == NULL); */
9496 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9497 || data_handler
!= NULL
9498 || close_handler
!= NULL
) {
9501 if (!is_delete_request
&& (handler
== NULL
)) {
9504 if (auth_handler
!= NULL
) {
9507 } else { /* AUTH_HANDLER */
9508 /* assert(handler == NULL); */
9509 /* assert(connect_handler==NULL && ready_handler==NULL &&
9510 * data_handler==NULL && close_handler==NULL); */
9511 /* assert(auth_handler != NULL); */
9512 if (handler
!= NULL
) {
9515 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9516 || data_handler
!= NULL
9517 || close_handler
!= NULL
) {
9520 if (!is_delete_request
&& (auth_handler
== NULL
)) {
9529 mg_lock_context(ctx
);
9531 /* first try to find an existing handler */
9532 lastref
= &(ctx
->handlers
);
9533 for (tmp_rh
= ctx
->handlers
; tmp_rh
!= NULL
; tmp_rh
= tmp_rh
->next
) {
9534 if (tmp_rh
->handler_type
== handler_type
) {
9535 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9536 if (!is_delete_request
) {
9537 /* update existing handler */
9538 if (handler_type
== REQUEST_HANDLER
) {
9539 tmp_rh
->handler
= handler
;
9540 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9541 tmp_rh
->connect_handler
= connect_handler
;
9542 tmp_rh
->ready_handler
= ready_handler
;
9543 tmp_rh
->data_handler
= data_handler
;
9544 tmp_rh
->close_handler
= close_handler
;
9545 } else { /* AUTH_HANDLER */
9546 tmp_rh
->auth_handler
= auth_handler
;
9548 tmp_rh
->cbdata
= cbdata
;
9550 /* remove existing handler */
9551 *lastref
= tmp_rh
->next
;
9552 mg_free(tmp_rh
->uri
);
9555 mg_unlock_context(ctx
);
9559 lastref
= &(tmp_rh
->next
);
9562 if (is_delete_request
) {
9563 /* no handler to set, this was a remove request to a non-existing
9565 mg_unlock_context(ctx
);
9570 (struct mg_handler_info
*)mg_calloc(sizeof(struct mg_handler_info
), 1);
9571 if (tmp_rh
== NULL
) {
9572 mg_unlock_context(ctx
);
9573 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9576 tmp_rh
->uri
= mg_strdup(uri
);
9578 mg_unlock_context(ctx
);
9580 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9583 tmp_rh
->uri_len
= urilen
;
9584 if (handler_type
== REQUEST_HANDLER
) {
9585 tmp_rh
->handler
= handler
;
9586 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9587 tmp_rh
->connect_handler
= connect_handler
;
9588 tmp_rh
->ready_handler
= ready_handler
;
9589 tmp_rh
->data_handler
= data_handler
;
9590 tmp_rh
->close_handler
= close_handler
;
9591 } else { /* AUTH_HANDLER */
9592 tmp_rh
->auth_handler
= auth_handler
;
9594 tmp_rh
->cbdata
= cbdata
;
9595 tmp_rh
->handler_type
= handler_type
;
9596 tmp_rh
->next
= NULL
;
9599 mg_unlock_context(ctx
);
9604 mg_set_request_handler(struct mg_context
*ctx
,
9606 mg_request_handler handler
,
9609 mg_set_handler_type(ctx
,
9624 mg_set_websocket_handler(struct mg_context
*ctx
,
9626 mg_websocket_connect_handler connect_handler
,
9627 mg_websocket_ready_handler ready_handler
,
9628 mg_websocket_data_handler data_handler
,
9629 mg_websocket_close_handler close_handler
,
9632 int is_delete_request
= (connect_handler
== NULL
) && (ready_handler
== NULL
)
9633 && (data_handler
== NULL
)
9634 && (close_handler
== NULL
);
9635 mg_set_handler_type(ctx
,
9650 mg_set_auth_handler(struct mg_context
*ctx
,
9652 mg_request_handler handler
,
9655 mg_set_handler_type(ctx
,
9670 get_request_handler(struct mg_connection
*conn
,
9672 mg_request_handler
*handler
,
9673 mg_websocket_connect_handler
*connect_handler
,
9674 mg_websocket_ready_handler
*ready_handler
,
9675 mg_websocket_data_handler
*data_handler
,
9676 mg_websocket_close_handler
*close_handler
,
9677 mg_authorization_handler
*auth_handler
,
9680 const struct mg_request_info
*request_info
= mg_get_request_info(conn
);
9682 const char *uri
= request_info
->local_uri
;
9683 size_t urilen
= strlen(uri
);
9684 struct mg_handler_info
*tmp_rh
;
9686 if (!conn
|| !conn
->ctx
) {
9690 mg_lock_context(conn
->ctx
);
9692 /* first try for an exact match */
9693 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9694 tmp_rh
= tmp_rh
->next
) {
9695 if (tmp_rh
->handler_type
== handler_type
) {
9696 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9697 if (handler_type
== WEBSOCKET_HANDLER
) {
9698 *connect_handler
= tmp_rh
->connect_handler
;
9699 *ready_handler
= tmp_rh
->ready_handler
;
9700 *data_handler
= tmp_rh
->data_handler
;
9701 *close_handler
= tmp_rh
->close_handler
;
9702 } else if (handler_type
== REQUEST_HANDLER
) {
9703 *handler
= tmp_rh
->handler
;
9704 } else { /* AUTH_HANDLER */
9705 *auth_handler
= tmp_rh
->auth_handler
;
9707 *cbdata
= tmp_rh
->cbdata
;
9708 mg_unlock_context(conn
->ctx
);
9714 /* next try for a partial match, we will accept uri/something */
9715 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9716 tmp_rh
= tmp_rh
->next
) {
9717 if (tmp_rh
->handler_type
== handler_type
) {
9718 if (tmp_rh
->uri_len
< urilen
&& uri
[tmp_rh
->uri_len
] == '/'
9719 && memcmp(tmp_rh
->uri
, uri
, tmp_rh
->uri_len
) == 0) {
9720 if (handler_type
== WEBSOCKET_HANDLER
) {
9721 *connect_handler
= tmp_rh
->connect_handler
;
9722 *ready_handler
= tmp_rh
->ready_handler
;
9723 *data_handler
= tmp_rh
->data_handler
;
9724 *close_handler
= tmp_rh
->close_handler
;
9725 } else if (handler_type
== REQUEST_HANDLER
) {
9726 *handler
= tmp_rh
->handler
;
9727 } else { /* AUTH_HANDLER */
9728 *auth_handler
= tmp_rh
->auth_handler
;
9730 *cbdata
= tmp_rh
->cbdata
;
9731 mg_unlock_context(conn
->ctx
);
9737 /* finally try for pattern match */
9738 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9739 tmp_rh
= tmp_rh
->next
) {
9740 if (tmp_rh
->handler_type
== handler_type
) {
9741 if (match_prefix(tmp_rh
->uri
, tmp_rh
->uri_len
, uri
) > 0) {
9742 if (handler_type
== WEBSOCKET_HANDLER
) {
9743 *connect_handler
= tmp_rh
->connect_handler
;
9744 *ready_handler
= tmp_rh
->ready_handler
;
9745 *data_handler
= tmp_rh
->data_handler
;
9746 *close_handler
= tmp_rh
->close_handler
;
9747 } else if (handler_type
== REQUEST_HANDLER
) {
9748 *handler
= tmp_rh
->handler
;
9749 } else { /* AUTH_HANDLER */
9750 *auth_handler
= tmp_rh
->auth_handler
;
9752 *cbdata
= tmp_rh
->cbdata
;
9753 mg_unlock_context(conn
->ctx
);
9759 mg_unlock_context(conn
->ctx
);
9761 return 0; /* none found */
9765 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
9767 deprecated_websocket_connect_wrapper(const struct mg_connection
*conn
,
9770 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9771 if (pcallbacks
->websocket_connect
) {
9772 return pcallbacks
->websocket_connect(conn
);
9774 /* No handler set - assume "OK" */
9780 deprecated_websocket_ready_wrapper(struct mg_connection
*conn
, void *cbdata
)
9782 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9783 if (pcallbacks
->websocket_ready
) {
9784 pcallbacks
->websocket_ready(conn
);
9790 deprecated_websocket_data_wrapper(struct mg_connection
*conn
,
9796 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9797 if (pcallbacks
->websocket_data
) {
9798 return pcallbacks
->websocket_data(conn
, bits
, data
, len
);
9800 /* No handler set - assume "OK" */
9806 /* This is the heart of the Civetweb's logic.
9807 * This function is called when the request is read, parsed and validated,
9808 * and Civetweb must decide what action to take: serve a file, or
9809 * a directory, or call embedded function, etcetera. */
9811 handle_request(struct mg_connection
*conn
)
9814 struct mg_request_info
*ri
= &conn
->request_info
;
9815 char path
[PATH_MAX
];
9816 int uri_len
, ssl_index
;
9817 int is_found
= 0, is_script_resource
= 0, is_websocket_request
= 0,
9818 is_put_or_delete_request
= 0, is_callback_resource
= 0;
9820 struct file file
= STRUCT_FILE_INITIALIZER
;
9821 mg_request_handler callback_handler
= NULL
;
9822 mg_websocket_connect_handler ws_connect_handler
= NULL
;
9823 mg_websocket_ready_handler ws_ready_handler
= NULL
;
9824 mg_websocket_data_handler ws_data_handler
= NULL
;
9825 mg_websocket_close_handler ws_close_handler
= NULL
;
9826 void *callback_data
= NULL
;
9827 mg_authorization_handler auth_handler
= NULL
;
9828 void *auth_callback_data
= NULL
;
9829 #if !defined(NO_FILES)
9830 time_t curtime
= time(NULL
);
9840 /* 1. get the request url */
9841 /* 1.1. split into url and query string */
9842 if ((conn
->request_info
.query_string
= strchr(ri
->request_uri
, '?'))
9844 *((char *)conn
->request_info
.query_string
++) = '\0';
9846 uri_len
= (int)strlen(ri
->local_uri
);
9848 /* 1.2. decode url (if config says so) */
9849 if (should_decode_url(conn
)) {
9851 ri
->local_uri
, uri_len
, (char *)ri
->local_uri
, uri_len
+ 1, 0);
9854 /* 1.3. clean URIs, so a path like allowed_dir/../forbidden_file is
9855 * not possible (if config says so) */
9856 if (!mg_strcasecmp(conn
->ctx
->config
[CANONICALIZE_URL_PATH
], "yes")) {
9857 remove_double_dots_and_double_slashes((char *)ri
->local_uri
);
9860 /* step 1. completed, the url is known now */
9861 DEBUG_TRACE("URL: %s", ri
->local_uri
);
9863 /* 2. do a https redirect, if required */
9864 if (!conn
->client
.is_ssl
&& conn
->client
.ssl_redir
) {
9865 ssl_index
= get_first_ssl_listener_index(conn
->ctx
);
9866 if (ssl_index
>= 0) {
9867 redirect_to_https_port(conn
, ssl_index
);
9869 /* A http to https forward port has been specified,
9870 * but no https port to forward to. */
9871 send_http_error(conn
,
9874 "Error: SSL forward not configured properly");
9875 mg_cry(conn
, "Can not redirect to SSL, no SSL port available");
9880 /* 3. if this ip has limited speed, set it for this connection */
9881 conn
->throttle
= set_throttle(conn
->ctx
->config
[THROTTLE
],
9882 get_remote_ip(conn
),
9885 /* 4. call a "handle everything" callback, if registered */
9886 if (conn
->ctx
->callbacks
.begin_request
!= NULL
) {
9887 /* Note that since V1.7 the "begin_request" function is called
9888 * before an authorization check. If an authorization check is
9889 * required, use a request_handler instead. */
9890 i
= conn
->ctx
->callbacks
.begin_request(conn
);
9892 /* callback already processed the request. Store the
9893 return value as a status code for the access log. */
9894 conn
->status_code
= i
;
9895 discard_unread_request_data(conn
);
9897 } else if (i
== 0) {
9898 /* civetweb should process the request */
9900 /* unspecified - may change with the next version */
9905 /* request not yet handled by a handler or redirect, so the request
9906 * is processed here */
9908 /* 5. interpret the url to find out how the request must be handled
9910 /* 5.1. first test, if the request targets the regular http(s)://
9911 * protocol namespace or the websocket ws(s):// protocol namespace.
9913 is_websocket_request
= is_websocket_protocol(conn
);
9915 /* 5.2. check if the request will be handled by a callback */
9916 if (get_request_handler(conn
,
9917 is_websocket_request
? WEBSOCKET_HANDLER
9920 &ws_connect_handler
,
9926 /* 5.2.1. A callback will handle this request. All requests
9928 * by a callback have to be considered as requests to a script
9930 is_callback_resource
= 1;
9931 is_script_resource
= 1;
9932 is_put_or_delete_request
= is_put_or_delete_method(conn
);
9934 no_callback_resource
:
9935 /* 5.2.2. No callback is responsible for this request. The URI
9936 * addresses a file based resource (static content or Lua/cgi
9937 * scripts in the file system). */
9938 is_callback_resource
= 0;
9944 &is_script_resource
,
9945 &is_websocket_request
,
9946 &is_put_or_delete_request
);
9949 /* 6. authorization check */
9950 /* 6.1. a custom authorization handler is installed */
9951 if (get_request_handler(conn
,
9959 &auth_callback_data
)) {
9960 if (!auth_handler(conn
, auth_callback_data
)) {
9963 } else if (is_put_or_delete_request
&& !is_script_resource
9964 && !is_callback_resource
) {
9965 /* 6.2. this request is a PUT/DELETE to a real file */
9966 /* 6.2.1. thus, the server must have real files */
9967 #if defined(NO_FILES)
9970 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
9972 /* This server does not have any real files, thus the
9973 * PUT/DELETE methods are not valid. */
9974 send_http_error(conn
,
9976 "%s method not allowed",
9977 conn
->request_info
.request_method
);
9981 #if !defined(NO_FILES)
9982 /* 6.2.2. Check if put authorization for static files is
9985 if (!is_authorized_for_put(conn
)) {
9986 send_authorization_request(conn
);
9992 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
9993 * or it is a PUT or DELETE request to a resource that does not
9994 * correspond to a file. Check authorization. */
9995 if (!check_authorization(conn
, path
)) {
9996 send_authorization_request(conn
);
10001 /* request is authorized or does not need authorization */
10003 /* 7. check if there are request handlers for this uri */
10004 if (is_callback_resource
) {
10005 if (!is_websocket_request
) {
10006 i
= callback_handler(conn
, callback_data
);
10008 /* Do nothing, callback has served the request. Store
10010 * return value as status code for the log and discard
10012 * data from the client not used by the callback. */
10013 conn
->status_code
= i
;
10014 discard_unread_request_data(conn
);
10016 /* TODO (high): what if the handler did NOT handle the
10018 /* The last version did handle this as a file request,
10020 * since a file request is not always a script resource,
10021 * the authorization check might be different */
10022 interpret_uri(conn
,
10027 &is_script_resource
,
10028 &is_websocket_request
,
10029 &is_put_or_delete_request
);
10030 callback_handler
= NULL
;
10032 /* TODO (very low): goto is deprecated but for the
10034 * a goto is simpler than some curious loop. */
10035 /* The situation "callback does not handle the request"
10036 * needs to be reconsidered anyway. */
10037 goto no_callback_resource
;
10040 #if defined(USE_WEBSOCKET)
10041 handle_websocket_request(conn
,
10043 is_callback_resource
,
10044 ws_connect_handler
,
10054 /* 8. handle websocket requests */
10055 #if defined(USE_WEBSOCKET)
10056 if (is_websocket_request
) {
10057 if (is_script_resource
) {
10058 /* Websocket Lua script */
10059 handle_websocket_request(conn
,
10061 0 /* Lua Script */,
10066 &conn
->ctx
->callbacks
);
10068 #if defined(MG_LEGACY_INTERFACE)
10069 handle_websocket_request(
10072 !is_script_resource
/* could be deprecated global callback */,
10073 deprecated_websocket_connect_wrapper
,
10074 deprecated_websocket_ready_wrapper
,
10075 deprecated_websocket_data_wrapper
,
10077 &conn
->ctx
->callbacks
);
10079 send_http_error(conn
, 404, "%s", "Not found");
10086 #if defined(NO_FILES)
10087 /* 9a. In case the server uses only callbacks, this uri is
10089 * Then, all request handling ends here. */
10090 send_http_error(conn
, 404, "%s", "Not Found");
10093 /* 9b. This request is either for a static file or resource handled
10094 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
10095 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
10096 send_http_error(conn
, 404, "%s", "Not Found");
10100 /* 10. File is handled by a script. */
10101 if (is_script_resource
) {
10102 handle_file_based_request(conn
, path
, &file
);
10106 /* 11. Handle put/delete/mkcol requests */
10107 if (is_put_or_delete_request
) {
10108 /* 11.1. PUT method */
10109 if (!strcmp(ri
->request_method
, "PUT")) {
10110 put_file(conn
, path
);
10113 /* 11.2. DELETE method */
10114 if (!strcmp(ri
->request_method
, "DELETE")) {
10115 delete_file(conn
, path
);
10118 /* 11.3. MKCOL method */
10119 if (!strcmp(ri
->request_method
, "MKCOL")) {
10123 /* 11.4. PATCH method
10124 * This method is not supported for static resources,
10125 * only for scripts (Lua, CGI) and callbacks. */
10126 send_http_error(conn
,
10128 "%s method not allowed",
10129 conn
->request_info
.request_method
);
10133 /* 11. File does not exist, or it was configured that it should be
10135 if (!is_found
|| (must_hide_file(conn
, path
))) {
10136 send_http_error(conn
, 404, "%s", "Not found");
10140 /* 12. Directory uris should end with a slash */
10141 if (file
.is_directory
&& ri
->local_uri
[uri_len
- 1] != '/') {
10142 gmt_time_string(date
, sizeof(date
), &curtime
);
10144 "HTTP/1.1 301 Moved Permanently\r\n"
10145 "Location: %s/\r\n"
10147 /* "Cache-Control: private\r\n" (= default) */
10148 "Content-Length: 0\r\n"
10149 "Connection: %s\r\n\r\n",
10152 suggest_connection_header(conn
));
10156 /* 13. Handle other methods than GET/HEAD */
10157 /* 13.1. Handle PROPFIND */
10158 if (!strcmp(ri
->request_method
, "PROPFIND")) {
10159 handle_propfind(conn
, path
, &file
);
10162 /* 13.2. Handle OPTIONS for files */
10163 if (!strcmp(ri
->request_method
, "OPTIONS")) {
10164 /* This standard handler is only used for real files.
10165 * Scripts should support the OPTIONS method themselves, to allow a
10166 * maximum flexibility.
10167 * Lua and CGI scripts may fully support CORS this way (including
10169 send_options(conn
);
10172 /* 13.3. everything but GET and HEAD (e.g. POST) */
10173 if (0 != strcmp(ri
->request_method
, "GET")
10174 && 0 != strcmp(ri
->request_method
, "HEAD")) {
10175 send_http_error(conn
,
10177 "%s method not allowed",
10178 conn
->request_info
.request_method
);
10182 /* 14. directories */
10183 if (file
.is_directory
) {
10184 if (substitute_index_file(conn
, path
, sizeof(path
), &file
)) {
10185 /* 14.1. use a substitute file */
10186 /* TODO (high): substitute index may be a script resource.
10187 * define what should be possible in this case. */
10189 /* 14.2. no substitute file */
10190 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
10192 handle_directory_request(conn
, path
);
10194 send_http_error(conn
,
10197 "Error: Directory listing denied");
10203 handle_file_based_request(conn
, path
, &file
);
10204 #endif /* !defined(NO_FILES) */
10207 /* Perform redirect and auth checks before calling begin_request()
10209 * Otherwise, begin_request() would need to perform auth checks and
10218 handle_file_based_request(struct mg_connection
*conn
,
10222 if (!conn
|| !conn
->ctx
) {
10228 } else if (match_prefix(conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
],
10230 conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
]),
10232 /* Lua server page: an SSI like page containing mostly plain html
10234 * plus some tags with server generated contents. */
10235 handle_lsp_request(conn
, path
, file
, NULL
);
10236 } else if (match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
10237 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
10239 /* Lua in-server module script: a CGI like script used to generate
10242 mg_exec_lua_script(conn
, path
, NULL
);
10244 #if defined(USE_DUKTAPE)
10245 } else if (match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
10247 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
10249 /* Call duktape to generate the page */
10250 mg_exec_duktape_script(conn
, path
);
10252 #if !defined(NO_CGI)
10253 } else if (match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
10254 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
10256 /* CGI scripts may support all HTTP methods */
10257 handle_cgi_request(conn
, path
);
10258 #endif /* !NO_CGI */
10259 } else if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
10260 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
10262 handle_ssi_file_request(conn
, path
, file
);
10263 #if !defined(NO_CACHING)
10264 } else if ((!conn
->in_error_handler
) && is_not_modified(conn
, file
)) {
10265 /* Send 304 "Not Modified" - this must not send any body data */
10266 send_http_error(conn
, 304, "%s", "");
10267 #endif /* !NO_CACHING */
10269 handle_static_file_request(conn
, path
, file
, NULL
);
10275 close_all_listening_sockets(struct mg_context
*ctx
)
10282 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
10283 closesocket(ctx
->listening_sockets
[i
].sock
);
10284 ctx
->listening_sockets
[i
].sock
= INVALID_SOCKET
;
10286 mg_free(ctx
->listening_sockets
);
10287 ctx
->listening_sockets
= NULL
;
10288 mg_free(ctx
->listening_ports
);
10289 ctx
->listening_ports
= NULL
;
10293 /* Valid listening port specification is: [ip_address:]port[s]
10294 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
10295 * Examples for IPv6: [::]:80, [::1]:80,
10296 * [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443s
10297 * see https://tools.ietf.org/html/rfc3513#section-2.2 */
10299 parse_port_string(const struct vec
*vec
, struct socket
*so
)
10301 unsigned int a
, b
, c
, d
, port
;
10303 #if defined(USE_IPV6)
10304 char buf
[100] = {0};
10307 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
10308 * Also, all-zeroes in the socket address means binding to all addresses
10309 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
10310 memset(so
, 0, sizeof(*so
));
10311 so
->lsa
.sin
.sin_family
= AF_INET
;
10313 if (sscanf(vec
->ptr
, "%u.%u.%u.%u:%u%n", &a
, &b
, &c
, &d
, &port
, &len
)
10315 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
10316 so
->lsa
.sin
.sin_addr
.s_addr
=
10317 htonl((a
<< 24) | (b
<< 16) | (c
<< 8) | d
);
10318 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10319 #if defined(USE_IPV6)
10320 } else if (sscanf(vec
->ptr
, "[%49[^]]]:%u%n", buf
, &port
, &len
) == 2
10322 AF_INET6
, buf
, &so
->lsa
.sin6
, sizeof(so
->lsa
.sin6
))) {
10323 /* IPv6 address, examples: see above */
10324 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
10326 so
->lsa
.sin6
.sin6_port
= htons((uint16_t)port
);
10328 } else if (sscanf(vec
->ptr
, "%u%n", &port
, &len
) == 1) {
10329 /* If only port is specified, bind to IPv4, INADDR_ANY */
10330 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10332 /* Parsing failure. Make port invalid. */
10337 /* sscanf and the option splitting code ensure the following condition
10339 if ((len
< 0) && ((unsigned)len
> (unsigned)vec
->len
)) {
10342 ch
= vec
->ptr
[len
]; /* Next character after the port number */
10343 so
->is_ssl
= (ch
== 's');
10344 so
->ssl_redir
= (ch
== 'r');
10346 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
10347 return is_valid_port(port
)
10348 && (ch
== '\0' || ch
== 's' || ch
== 'r' || ch
== ',');
10353 set_ports_option(struct mg_context
*ctx
)
10357 #if defined(USE_IPV6)
10361 struct socket so
, *ptr
;
10363 in_port_t
*portPtr
;
10367 int portsTotal
= 0;
10374 memset(&so
, 0, sizeof(so
));
10375 memset(&usa
, 0, sizeof(usa
));
10377 list
= ctx
->config
[LISTENING_PORTS
];
10378 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10382 if (!parse_port_string(&vec
, &so
)) {
10384 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
10388 "[IP_ADDRESS:]PORT[s|r]");
10392 if (so
.is_ssl
&& ctx
->ssl_ctx
== NULL
) {
10395 "Cannot add SSL socket (entry %i). Is -ssl_certificate "
10401 if ((so
.sock
= socket(so
.lsa
.sa
.sa_family
, SOCK_STREAM
, 6))
10402 == INVALID_SOCKET
) {
10404 mg_cry(fc(ctx
), "cannot create socket (entry %i)", portsTotal
);
10409 /* Windows SO_REUSEADDR lets many procs binds to a
10410 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
10411 * if someone already has the socket -- DTL */
10412 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
10413 * Windows might need a few seconds before
10414 * the same port can be used again in the
10415 * same process, so a short Sleep may be
10416 * required between mg_stop and mg_start.
10418 if (setsockopt(so
.sock
,
10420 SO_EXCLUSIVEADDRUSE
,
10421 (SOCK_OPT_TYPE
)&on
,
10422 sizeof(on
)) != 0) {
10425 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
10429 if (setsockopt(so
.sock
,
10432 (SOCK_OPT_TYPE
)&on
,
10433 sizeof(on
)) != 0) {
10436 "cannot set socket option SO_REUSEADDR (entry %i)",
10441 #if defined(USE_IPV6)
10442 if (so
.lsa
.sa
.sa_family
== AF_INET6
10443 && setsockopt(so
.sock
,
10447 sizeof(off
)) != 0) {
10450 "cannot set socket option IPV6_V6ONLY (entry %i)",
10455 if (so
.lsa
.sa
.sa_family
== AF_INET
) {
10457 len
= sizeof(so
.lsa
.sin
);
10458 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10460 "cannot bind to %.*s: %d (%s)",
10465 closesocket(so
.sock
);
10466 so
.sock
= INVALID_SOCKET
;
10470 #if defined(USE_IPV6)
10471 else if (so
.lsa
.sa
.sa_family
== AF_INET6
) {
10473 len
= sizeof(so
.lsa
.sin6
);
10474 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10476 "cannot bind to IPv6 %.*s: %d (%s)",
10481 closesocket(so
.sock
);
10482 so
.sock
= INVALID_SOCKET
;
10489 "cannot bind: address family not supported (entry %i)",
10494 if (listen(so
.sock
, SOMAXCONN
) != 0) {
10497 "cannot listen to %.*s: %d (%s)",
10502 closesocket(so
.sock
);
10503 so
.sock
= INVALID_SOCKET
;
10507 if (getsockname(so
.sock
, &(usa
.sa
), &len
) != 0) {
10509 int err
= (int)ERRNO
;
10511 "call to getsockname failed %.*s: %d (%s)",
10516 closesocket(so
.sock
);
10517 so
.sock
= INVALID_SOCKET
;
10521 if ((ptr
= (struct socket
*)
10522 mg_realloc(ctx
->listening_sockets
,
10523 (ctx
->num_listening_sockets
+ 1)
10524 * sizeof(ctx
->listening_sockets
[0]))) == NULL
) {
10526 mg_cry(fc(ctx
), "%s", "Out of memory");
10527 closesocket(so
.sock
);
10528 so
.sock
= INVALID_SOCKET
;
10533 (in_port_t
*)mg_realloc(ctx
->listening_ports
,
10534 (ctx
->num_listening_sockets
+ 1)
10535 * sizeof(ctx
->listening_ports
[0])))
10538 mg_cry(fc(ctx
), "%s", "Out of memory");
10539 closesocket(so
.sock
);
10540 so
.sock
= INVALID_SOCKET
;
10545 set_close_on_exec(so
.sock
, fc(ctx
));
10546 ctx
->listening_sockets
= ptr
;
10547 ctx
->listening_sockets
[ctx
->num_listening_sockets
] = so
;
10548 ctx
->listening_ports
= portPtr
;
10549 ctx
->listening_ports
[ctx
->num_listening_sockets
] =
10550 ntohs(usa
.sin
.sin_port
);
10551 ctx
->num_listening_sockets
++;
10555 if (portsOk
!= portsTotal
) {
10556 close_all_listening_sockets(ctx
);
10564 static const char *
10565 header_val(const struct mg_connection
*conn
, const char *header
)
10567 const char *header_value
;
10569 if ((header_value
= mg_get_header(conn
, header
)) == NULL
) {
10572 return header_value
;
10578 log_access(const struct mg_connection
*conn
)
10580 const struct mg_request_info
*ri
;
10582 char date
[64], src_addr
[IP_ADDR_STR_LEN
];
10585 const char *referer
;
10586 const char *user_agent
;
10590 if (!conn
|| !conn
->ctx
) {
10594 if (conn
->ctx
->config
[ACCESS_LOG_FILE
] != NULL
) {
10595 if (mg_fopen(conn
, conn
->ctx
->config
[ACCESS_LOG_FILE
], "a+", &fi
)
10603 if (fi
.fp
== NULL
&& conn
->ctx
->callbacks
.log_message
== NULL
) {
10607 tm
= localtime(&conn
->conn_birth_time
);
10609 strftime(date
, sizeof(date
), "%d/%b/%Y:%H:%M:%S %z", tm
);
10611 mg_strlcpy(date
, "01/Jan/1970:00:00:00 +0000", sizeof(date
));
10612 date
[sizeof(date
) - 1] = '\0';
10615 ri
= &conn
->request_info
;
10617 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
10618 referer
= header_val(conn
, "Referer");
10619 user_agent
= header_val(conn
, "User-Agent");
10622 NULL
, /* Ignore truncation in access log */
10625 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT
" %s %s",
10627 ri
->remote_user
== NULL
? "-" : ri
->remote_user
,
10629 ri
->request_method
? ri
->request_method
: "-",
10630 ri
->request_uri
? ri
->request_uri
: "-",
10631 ri
->query_string
? "?" : "",
10632 ri
->query_string
? ri
->query_string
: "",
10635 conn
->num_bytes_sent
,
10639 if (conn
->ctx
->callbacks
.log_access
) {
10640 conn
->ctx
->callbacks
.log_access(conn
, buf
);
10645 fprintf(fi
.fp
, "%s\n", buf
);
10647 funlockfile(fi
.fp
);
10653 /* Verify given socket address against the ACL.
10654 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
10657 check_acl(struct mg_context
*ctx
, uint32_t remote_ip
)
10660 uint32_t net
, mask
;
10664 const char *list
= ctx
->config
[ACCESS_CONTROL_LIST
];
10666 /* If any ACL is set, deny by default */
10667 allowed
= list
== NULL
? '+' : '-';
10669 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10671 if ((flag
!= '+' && flag
!= '-')
10672 || parse_net(&vec
.ptr
[1], &net
, &mask
) == 0) {
10674 "%s: subnet must be [+|-]x.x.x.x[/x]",
10679 if (net
== (remote_ip
& mask
)) {
10684 return allowed
== '+';
10690 #if !defined(_WIN32)
10692 set_uid_option(struct mg_context
*ctx
)
10696 const char *uid
= ctx
->config
[RUN_AS_USER
];
10702 if ((pw
= getpwnam(uid
)) == NULL
) {
10703 mg_cry(fc(ctx
), "%s: unknown user [%s]", __func__
, uid
);
10704 } else if (setgid(pw
->pw_gid
) == -1) {
10706 "%s: setgid(%s): %s",
10710 } else if (setgroups(0, NULL
)) {
10712 "%s: setgroups(): %s",
10715 } else if (setuid(pw
->pw_uid
) == -1) {
10717 "%s: setuid(%s): %s",
10730 #endif /* !_WIN32 */
10734 tls_dtor(void *key
)
10736 struct mg_workerTLS
*tls
= (struct mg_workerTLS
*)key
;
10737 /* key == pthread_getspecific(sTlsKey); */
10740 if (tls
->is_master
== 2) {
10741 tls
->is_master
= -3; /* Mark memory as dead */
10745 pthread_setspecific(sTlsKey
, NULL
);
10749 #if !defined(NO_SSL)
10751 /* Must be set if sizeof(pthread_t) > sizeof(unsigned long) */
10752 static unsigned long
10753 ssl_id_callback(void)
10756 return GetCurrentThreadId();
10760 #pragma clang diagnostic push
10761 #pragma clang diagnostic ignored "-Wunreachable-code"
10762 /* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
10763 * or not, so one of the two conditions will be unreachable by construction.
10764 * Unfortunately the C standard does not define a way to check this at
10765 * compile time, since the #if preprocessor conditions can not use the sizeof
10766 * operator as an argument. */
10769 if (sizeof(pthread_t
) > sizeof(unsigned long)) {
10770 /* This is the problematic case for CRYPTO_set_id_callback:
10771 * The OS pthread_t can not be cast to unsigned long. */
10772 struct mg_workerTLS
*tls
=
10773 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
10775 /* SSL called from an unknown thread: Create some thread index.
10777 tls
= (struct mg_workerTLS
*)mg_malloc(sizeof(struct mg_workerTLS
));
10778 tls
->is_master
= -2; /* -2 means "3rd party thread" */
10779 tls
->thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
10780 pthread_setspecific(sTlsKey
, tls
);
10782 return tls
->thread_idx
;
10784 /* pthread_t may be any data type, so a simple cast to unsigned long
10785 * can rise a warning/error, depending on the platform.
10786 * Here memcpy is used as an anything-to-anything cast. */
10787 unsigned long ret
= 0;
10788 pthread_t t
= pthread_self();
10789 memcpy(&ret
, &t
, sizeof(pthread_t
));
10794 #pragma clang diagnostic pop
10801 static int ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
);
10802 static const char *ssl_error(void);
10806 refresh_trust(struct mg_connection
*conn
)
10808 static int reload_lock
= 0;
10809 static long int data_check
= 0;
10811 struct stat cert_buf
;
10814 int should_verify_peer
;
10816 if ((pem
= conn
->ctx
->config
[SSL_CERTIFICATE
]) == NULL
10817 && conn
->ctx
->callbacks
.init_ssl
== NULL
) {
10822 if (stat(pem
, &cert_buf
) != -1) {
10823 t
= (long int)cert_buf
.st_mtime
;
10826 if (data_check
!= t
) {
10829 should_verify_peer
=
10830 (conn
->ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
10831 && (mg_strcasecmp(conn
->ctx
->config
[SSL_DO_VERIFY_PEER
], "yes")
10834 if (should_verify_peer
) {
10835 char *ca_path
= conn
->ctx
->config
[SSL_CA_PATH
];
10836 char *ca_file
= conn
->ctx
->config
[SSL_CA_FILE
];
10837 if (SSL_CTX_load_verify_locations(conn
->ctx
->ssl_ctx
,
10840 mg_cry(fc(conn
->ctx
),
10841 "SSL_CTX_load_verify_locations error: %s "
10842 "ssl_verify_peer requires setting "
10843 "either ssl_ca_path or ssl_ca_file. Is any of them "
10851 if (!reload_lock
) {
10853 if (ssl_use_pem_file(conn
->ctx
, pem
) == 0) {
10859 /* lock while cert is reloading */
10860 while (reload_lock
) {
10868 static pthread_mutex_t
*ssl_mutexes
;
10872 sslize(struct mg_connection
*conn
, SSL_CTX
*s
, int (*func
)(SSL
*))
10882 (conn
->ctx
->config
[SSL_SHORT_TRUST
] != NULL
)
10883 && (mg_strcasecmp(conn
->ctx
->config
[SSL_SHORT_TRUST
], "yes") == 0);
10886 int trust_ret
= refresh_trust(conn
);
10892 conn
->ssl
= SSL_new(s
);
10893 if (conn
->ssl
== NULL
) {
10897 ret
= SSL_set_fd(conn
->ssl
, conn
->client
.sock
);
10899 err
= SSL_get_error(conn
->ssl
, ret
);
10900 (void)err
; /* TODO: set some error message */
10901 SSL_free(conn
->ssl
);
10903 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10905 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10906 ERR_remove_state(0);
10910 ret
= func(conn
->ssl
);
10912 err
= SSL_get_error(conn
->ssl
, ret
);
10913 (void)err
; /* TODO: set some error message */
10914 SSL_free(conn
->ssl
);
10916 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10918 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10919 ERR_remove_state(0);
10927 /* Return OpenSSL error message (from CRYPTO lib) */
10928 static const char *
10932 err
= ERR_get_error();
10933 return err
== 0 ? "" : ERR_error_string(err
, NULL
);
10938 ssl_locking_callback(int mode
, int mutex_num
, const char *file
, int line
)
10944 /* 1 is CRYPTO_LOCK */
10945 (void)pthread_mutex_lock(&ssl_mutexes
[mutex_num
]);
10947 (void)pthread_mutex_unlock(&ssl_mutexes
[mutex_num
]);
10952 #if !defined(NO_SSL_DL)
10954 load_dll(struct mg_context
*ctx
, const char *dll_name
, struct ssl_func
*sw
)
10961 struct ssl_func
*fp
;
10963 if ((dll_handle
= dlopen(dll_name
, RTLD_LAZY
)) == NULL
) {
10964 mg_cry(fc(ctx
), "%s: cannot load %s", __func__
, dll_name
);
10968 for (fp
= sw
; fp
->name
!= NULL
; fp
++) {
10970 /* GetProcAddress() returns pointer to function */
10971 u
.fp
= (void (*)(void))dlsym(dll_handle
, fp
->name
);
10973 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
10974 * pointers to function pointers. We need to use a union to make a
10976 u
.p
= dlsym(dll_handle
, fp
->name
);
10977 #endif /* _WIN32 */
10978 if (u
.fp
== NULL
) {
10980 "%s: %s: cannot find %s",
10984 dlclose(dll_handle
);
10995 static void *ssllib_dll_handle
; /* Store the ssl library handle. */
10996 static void *cryptolib_dll_handle
; /* Store the crypto library handle. */
10998 #endif /* NO_SSL_DL */
11001 #if defined(SSL_ALREADY_INITIALIZED)
11002 static int cryptolib_users
= 1; /* Reference counter for crypto library. */
11004 static int cryptolib_users
= 0; /* Reference counter for crypto library. */
11009 initialize_ssl(struct mg_context
*ctx
)
11014 #if !defined(NO_SSL_DL)
11015 if (!cryptolib_dll_handle
) {
11016 cryptolib_dll_handle
= load_dll(ctx
, CRYPTO_LIB
, crypto_sw
);
11017 if (!cryptolib_dll_handle
) {
11021 #endif /* NO_SSL_DL */
11023 if (mg_atomic_inc(&cryptolib_users
) > 1) {
11027 /* Initialize locking callbacks, needed for thread safety.
11028 * http://www.openssl.org/support/faq.html#PROG1
11030 i
= CRYPTO_num_locks();
11034 size
= sizeof(pthread_mutex_t
) * ((size_t)(i
));
11035 if ((ssl_mutexes
= (pthread_mutex_t
*)mg_malloc(size
)) == NULL
) {
11037 "%s: cannot allocate mutexes: %s",
11043 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11044 pthread_mutex_init(&ssl_mutexes
[i
], &pthread_mutex_attr
);
11047 CRYPTO_set_locking_callback(&ssl_locking_callback
);
11048 CRYPTO_set_id_callback(&ssl_id_callback
);
11055 ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
)
11057 if (SSL_CTX_use_certificate_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11059 "%s: cannot open certificate file %s: %s",
11066 /* could use SSL_CTX_set_default_passwd_cb_userdata */
11067 if (SSL_CTX_use_PrivateKey_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11069 "%s: cannot open private key file %s: %s",
11076 if (SSL_CTX_check_private_key(ctx
->ssl_ctx
) == 0) {
11078 "%s: certificate and private key do not match: %s",
11084 if (SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
) == 0) {
11086 "%s: cannot use certificate chain file %s: %s",
11097 ssl_get_protocol(int version_id
)
11099 long ret
= SSL_OP_ALL
;
11100 if (version_id
> 0)
11101 ret
|= SSL_OP_NO_SSLv2
;
11102 if (version_id
> 1)
11103 ret
|= SSL_OP_NO_SSLv3
;
11104 if (version_id
> 2)
11105 ret
|= SSL_OP_NO_TLSv1
;
11106 if (version_id
> 3)
11107 ret
|= SSL_OP_NO_TLSv1_1
;
11112 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
11114 set_ssl_option(struct mg_context
*ctx
)
11118 int should_verify_peer
;
11119 const char *ca_path
;
11120 const char *ca_file
;
11121 int use_default_verify_paths
;
11123 time_t now_rt
= time(NULL
);
11124 struct timespec now_mt
;
11125 md5_byte_t ssl_context_id
[16];
11126 md5_state_t md5state
;
11129 /* If PEM file is not specified and the init_ssl callback
11130 * is not specified, skip SSL initialization. */
11134 if ((pem
= ctx
->config
[SSL_CERTIFICATE
]) == NULL
11135 && ctx
->callbacks
.init_ssl
== NULL
) {
11139 if (!initialize_ssl(ctx
)) {
11143 #if !defined(NO_SSL_DL)
11144 if (!ssllib_dll_handle
) {
11145 ssllib_dll_handle
= load_dll(ctx
, SSL_LIB
, ssl_sw
);
11146 if (!ssllib_dll_handle
) {
11150 #endif /* NO_SSL_DL */
11152 /* Initialize SSL library */
11153 SSL_library_init();
11154 SSL_load_error_strings();
11156 if ((ctx
->ssl_ctx
= SSL_CTX_new(SSLv23_server_method())) == NULL
) {
11157 mg_cry(fc(ctx
), "SSL_CTX_new (server) error: %s", ssl_error());
11161 SSL_CTX_clear_options(ctx
->ssl_ctx
,
11162 SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
| SSL_OP_NO_TLSv1
11163 | SSL_OP_NO_TLSv1_1
);
11164 protocol_ver
= atoi(ctx
->config
[SSL_PROTOCOL_VERSION
]);
11165 SSL_CTX_set_options(ctx
->ssl_ctx
, ssl_get_protocol(protocol_ver
));
11166 SSL_CTX_set_options(ctx
->ssl_ctx
, SSL_OP_SINGLE_DH_USE
);
11167 SSL_CTX_set_ecdh_auto(ctx
->ssl_ctx
, 1);
11169 /* If a callback has been specified, call it. */
11171 (ctx
->callbacks
.init_ssl
== NULL
)
11173 : (ctx
->callbacks
.init_ssl(ctx
->ssl_ctx
, ctx
->user_data
));
11175 /* If callback returns 0, civetweb sets up the SSL certificate.
11176 * If it returns 1, civetweb assumes the calback already did this.
11177 * If it returns -1, initializing ssl fails. */
11178 if (callback_ret
< 0) {
11179 mg_cry(fc(ctx
), "SSL callback returned error: %i", callback_ret
);
11182 if (callback_ret
> 0) {
11184 (void)SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
);
11189 /* Use some UID as session context ID. */
11190 md5_init(&md5state
);
11191 md5_append(&md5state
, (const md5_byte_t
*)&now_rt
, sizeof(now_rt
));
11192 clock_gettime(CLOCK_MONOTONIC
, &now_mt
);
11193 md5_append(&md5state
, (const md5_byte_t
*)&now_mt
, sizeof(now_mt
));
11194 md5_append(&md5state
,
11195 (const md5_byte_t
*)ctx
->config
[LISTENING_PORTS
],
11196 strlen(ctx
->config
[LISTENING_PORTS
]));
11197 md5_append(&md5state
, (const md5_byte_t
*)ctx
, sizeof(*ctx
));
11198 md5_finish(&md5state
, ssl_context_id
);
11200 SSL_CTX_set_session_id_context(ctx
->ssl_ctx
,
11201 (const unsigned char *)&ssl_context_id
,
11202 sizeof(ssl_context_id
));
11205 if (!ssl_use_pem_file(ctx
, pem
)) {
11210 should_verify_peer
=
11211 (ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
11212 && (mg_strcasecmp(ctx
->config
[SSL_DO_VERIFY_PEER
], "yes") == 0);
11214 use_default_verify_paths
=
11215 (ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
] != NULL
)
11216 && (mg_strcasecmp(ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
], "yes") == 0);
11218 if (should_verify_peer
) {
11219 ca_path
= ctx
->config
[SSL_CA_PATH
];
11220 ca_file
= ctx
->config
[SSL_CA_FILE
];
11221 if (SSL_CTX_load_verify_locations(ctx
->ssl_ctx
, ca_file
, ca_path
)
11224 "SSL_CTX_load_verify_locations error: %s "
11225 "ssl_verify_peer requires setting "
11226 "either ssl_ca_path or ssl_ca_file. Is any of them "
11233 SSL_CTX_set_verify(ctx
->ssl_ctx
,
11234 SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
,
11237 if (use_default_verify_paths
11238 && SSL_CTX_set_default_verify_paths(ctx
->ssl_ctx
) != 1) {
11240 "SSL_CTX_set_default_verify_paths error: %s",
11245 if (ctx
->config
[SSL_VERIFY_DEPTH
]) {
11246 verify_depth
= atoi(ctx
->config
[SSL_VERIFY_DEPTH
]);
11247 SSL_CTX_set_verify_depth(ctx
->ssl_ctx
, verify_depth
);
11251 if (ctx
->config
[SSL_CIPHER_LIST
] != NULL
) {
11252 if (SSL_CTX_set_cipher_list(ctx
->ssl_ctx
, ctx
->config
[SSL_CIPHER_LIST
])
11254 mg_cry(fc(ctx
), "SSL_CTX_set_cipher_list error: %s", ssl_error());
11263 uninitialize_ssl(struct mg_context
*ctx
)
11268 if (mg_atomic_dec(&cryptolib_users
) == 0) {
11270 /* Shutdown according to
11271 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
11272 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
11274 CRYPTO_set_locking_callback(NULL
);
11275 CRYPTO_set_id_callback(NULL
);
11277 CONF_modules_unload(1);
11278 ERR_free_strings();
11280 CRYPTO_cleanup_all_ex_data();
11281 ERR_remove_state(0);
11283 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11284 pthread_mutex_destroy(&ssl_mutexes
[i
]);
11286 mg_free(ssl_mutexes
);
11287 ssl_mutexes
= NULL
;
11290 #endif /* !NO_SSL */
11294 set_gpass_option(struct mg_context
*ctx
)
11297 struct file file
= STRUCT_FILE_INITIALIZER
;
11298 const char *path
= ctx
->config
[GLOBAL_PASSWORDS_FILE
];
11299 if (path
!= NULL
&& !mg_stat(fc(ctx
), path
, &file
)) {
11300 mg_cry(fc(ctx
), "Cannot open %s: %s", path
, strerror(ERRNO
));
11310 set_acl_option(struct mg_context
*ctx
)
11312 return check_acl(ctx
, (uint32_t)0x7f000001UL
) != -1;
11317 reset_per_request_attributes(struct mg_connection
*conn
)
11322 conn
->path_info
= NULL
;
11323 conn
->num_bytes_sent
= conn
->consumed_content
= 0;
11324 conn
->status_code
= -1;
11325 conn
->is_chunked
= 0;
11326 conn
->must_close
= conn
->request_len
= conn
->throttle
= 0;
11327 conn
->request_info
.content_length
= -1;
11328 conn
->request_info
.remote_user
= NULL
;
11329 conn
->request_info
.request_method
= NULL
;
11330 conn
->request_info
.request_uri
= NULL
;
11331 conn
->request_info
.local_uri
= NULL
;
11332 conn
->request_info
.uri
= NULL
; /* TODO: cleanup uri,
11333 * local_uri and request_uri */
11334 conn
->request_info
.http_version
= NULL
;
11335 conn
->request_info
.num_headers
= 0;
11336 conn
->data_len
= 0;
11337 conn
->chunk_remainder
= 0;
11338 conn
->internal_error
= 0;
11343 set_sock_timeout(SOCKET sock
, int milliseconds
)
11345 int r0
= 0, r1
, r2
;
11348 /* Windows specific */
11350 DWORD tv
= (DWORD
)milliseconds
;
11353 /* Linux, ... (not Windows) */
11357 /* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
11358 * max. time waiting for the acknowledged of TCP data before the connection
11359 * will be forcefully closed and ETIMEDOUT is returned to the application.
11360 * If this option is not set, the default timeout of 20-30 minutes is used.
11362 /* #define TCP_USER_TIMEOUT (18) */
11364 #if defined(TCP_USER_TIMEOUT)
11365 unsigned int uto
= (unsigned int)milliseconds
;
11366 r0
= setsockopt(sock
, 6, TCP_USER_TIMEOUT
, (const void *)&uto
, sizeof(uto
));
11369 memset(&tv
, 0, sizeof(tv
));
11370 tv
.tv_sec
= milliseconds
/ 1000;
11371 tv
.tv_usec
= (milliseconds
* 1000) % 1000000;
11373 #endif /* _WIN32 */
11376 sock
, SOL_SOCKET
, SO_RCVTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11378 sock
, SOL_SOCKET
, SO_SNDTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11380 return r0
|| r1
|| r2
;
11385 set_tcp_nodelay(SOCKET sock
, int nodelay_on
)
11387 if (setsockopt(sock
,
11390 (SOCK_OPT_TYPE
)&nodelay_on
,
11391 sizeof(nodelay_on
)) != 0) {
11401 close_socket_gracefully(struct mg_connection
*conn
)
11403 #if defined(_WIN32)
11404 char buf
[MG_BUF_LEN
];
11407 struct linger linger
;
11413 /* Set linger option to avoid socket hanging out after close. This
11415 * ephemeral port exhaust problem under high QPS. */
11416 linger
.l_onoff
= 1;
11417 linger
.l_linger
= 1;
11419 if (setsockopt(conn
->client
.sock
,
11423 sizeof(linger
)) != 0) {
11425 "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
11430 /* Send FIN to the client */
11431 shutdown(conn
->client
.sock
, SHUT_WR
);
11432 set_non_blocking_mode(conn
->client
.sock
);
11434 #if defined(_WIN32)
11435 /* Read and discard pending incoming data. If we do not do that and
11437 * the socket, the data in the send buffer may be discarded. This
11438 * behaviour is seen on Windows, when client keeps sending data
11439 * when server decides to close the connection; then when client
11440 * does recv() it gets no data back. */
11443 NULL
, conn
, buf
, sizeof(buf
), 1E-10 /* TODO: allow 0 as timeout */);
11447 /* Now we know that our FIN is ACK-ed, safe to close */
11448 closesocket(conn
->client
.sock
);
11449 conn
->client
.sock
= INVALID_SOCKET
;
11454 close_connection(struct mg_connection
*conn
)
11456 if (!conn
|| !conn
->ctx
) {
11460 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
11461 if (conn
->lua_websocket_state
) {
11462 lua_websocket_close(conn
, conn
->lua_websocket_state
);
11463 conn
->lua_websocket_state
= NULL
;
11467 /* call the connection_close callback if assigned */
11468 if ((conn
->ctx
->callbacks
.connection_close
!= NULL
)
11469 && (conn
->ctx
->context_type
== 1)) {
11470 conn
->ctx
->callbacks
.connection_close(conn
);
11473 mg_lock_connection(conn
);
11475 conn
->must_close
= 1;
11478 if (conn
->ssl
!= NULL
) {
11479 /* Run SSL_shutdown twice to ensure completly close SSL connection
11481 SSL_shutdown(conn
->ssl
);
11482 SSL_free(conn
->ssl
);
11483 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
11485 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
11486 ERR_remove_state(0);
11490 if (conn
->client
.sock
!= INVALID_SOCKET
) {
11491 close_socket_gracefully(conn
);
11492 conn
->client
.sock
= INVALID_SOCKET
;
11495 mg_unlock_connection(conn
);
11499 mg_close_connection(struct mg_connection
*conn
)
11501 struct mg_context
*client_ctx
= NULL
;
11504 if (conn
== NULL
) {
11508 if (conn
->ctx
->context_type
== 2) {
11509 client_ctx
= conn
->ctx
;
11510 /* client context: loops must end */
11511 conn
->ctx
->stop_flag
= 1;
11515 if (conn
->client_ssl_ctx
!= NULL
) {
11516 SSL_CTX_free((SSL_CTX
*)conn
->client_ssl_ctx
);
11519 close_connection(conn
);
11520 if (client_ctx
!= NULL
) {
11521 /* join worker thread and free context */
11522 for (i
= 0; i
< client_ctx
->cfg_worker_threads
; i
++) {
11523 if (client_ctx
->workerthreadids
[i
] != 0) {
11524 mg_join_thread(client_ctx
->workerthreadids
[i
]);
11527 mg_free(client_ctx
->workerthreadids
);
11528 mg_free(client_ctx
);
11529 (void)pthread_mutex_destroy(&conn
->mutex
);
11535 static struct mg_connection
*
11536 mg_connect_client_impl(const struct mg_client_options
*client_options
,
11541 static struct mg_context fake_ctx
;
11542 struct mg_connection
*conn
= NULL
;
11546 if (!connect_socket(&fake_ctx
,
11547 client_options
->host
,
11548 client_options
->port
,
11555 } else if ((conn
= (struct mg_connection
*)
11556 mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
)) == NULL
) {
11558 NULL
, /* No truncation check for ebuf */
11566 && (conn
->client_ssl_ctx
= SSL_CTX_new(SSLv23_client_method()))
11569 NULL
, /* No truncation check for ebuf */
11572 "SSL_CTX_new error");
11576 #endif /* NO_SSL */
11581 socklen_t len
= (sa
.sa
.sa_family
== AF_INET
)
11582 ? sizeof(conn
->client
.rsa
.sin
)
11583 : sizeof(conn
->client
.rsa
.sin6
);
11584 struct sockaddr
*psa
=
11585 (sa
.sa
.sa_family
== AF_INET
)
11586 ? (struct sockaddr
*)&(conn
->client
.rsa
.sin
)
11587 : (struct sockaddr
*)&(conn
->client
.rsa
.sin6
);
11589 socklen_t len
= sizeof(conn
->client
.rsa
.sin
);
11590 struct sockaddr
*psa
= (struct sockaddr
*)&(conn
->client
.rsa
.sin
);
11593 conn
->buf_size
= MAX_REQUEST_SIZE
;
11594 conn
->buf
= (char *)(conn
+ 1);
11595 conn
->ctx
= &fake_ctx
;
11596 conn
->client
.sock
= sock
;
11597 conn
->client
.lsa
= sa
;
11599 if (getsockname(sock
, psa
, &len
) != 0) {
11601 "%s: getsockname() failed: %s",
11606 conn
->client
.is_ssl
= use_ssl
? 1 : 0;
11607 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
11611 fake_ctx
.ssl_ctx
= conn
->client_ssl_ctx
;
11613 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
11614 * SSL_CTX_set_verify call is needed to switch off server
11615 * certificate checking, which is off by default in OpenSSL and
11617 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
11618 * SSL_VERIFY_PEER, verify_ssl_server); */
11620 if (client_options
->client_cert
) {
11621 if (!ssl_use_pem_file(&fake_ctx
, client_options
->client_cert
)) {
11623 NULL
, /* No truncation check for ebuf */
11626 "Can not use SSL client certificate");
11627 SSL_CTX_free(conn
->client_ssl_ctx
);
11634 if (client_options
->server_cert
) {
11635 SSL_CTX_load_verify_locations(conn
->client_ssl_ctx
,
11636 client_options
->server_cert
,
11638 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_PEER
, NULL
);
11640 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
11643 if (!sslize(conn
, conn
->client_ssl_ctx
, SSL_connect
)) {
11645 NULL
, /* No truncation check for ebuf */
11648 "SSL connection error");
11649 SSL_CTX_free(conn
->client_ssl_ctx
);
11662 CIVETWEB_API
struct mg_connection
*
11663 mg_connect_client_secure(const struct mg_client_options
*client_options
,
11664 char *error_buffer
,
11665 size_t error_buffer_size
)
11667 return mg_connect_client_impl(client_options
,
11670 error_buffer_size
);
11674 struct mg_connection
*
11675 mg_connect_client(const char *host
,
11678 char *error_buffer
,
11679 size_t error_buffer_size
)
11681 struct mg_client_options opts
;
11682 memset(&opts
, 0, sizeof(opts
));
11685 return mg_connect_client_impl(&opts
,
11688 error_buffer_size
);
11692 static const struct {
11695 unsigned default_port
;
11696 } abs_uri_protocols
[] = {{"http://", 7, 80},
11697 {"https://", 8, 443},
11699 {"wss://", 6, 443},
11703 /* Check if the uri is valid.
11704 * return 0 for invalid uri,
11706 * return 2 for relative uri,
11707 * return 3 for absolute uri without port,
11708 * return 4 for absolute uri with port */
11710 get_uri_type(const char *uri
)
11713 char *hostend
, *portbegin
, *portend
;
11714 unsigned long port
;
11716 /* According to the HTTP standard
11717 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
11718 * URI can be an asterisk (*) or should start with slash (relative uri),
11719 * or it should start with the protocol (absolute uri). */
11720 if (uri
[0] == '*' && uri
[1] == '\0') {
11724 if (uri
[0] == '/') {
11729 /* It could be an absolute uri: */
11730 /* This function only checks if the uri is valid, not if it is
11731 * addressing the current server. So civetweb can also be used
11732 * as a proxy server. */
11733 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11734 if (mg_strncasecmp(uri
,
11735 abs_uri_protocols
[i
].proto
,
11736 abs_uri_protocols
[i
].proto_len
) == 0) {
11738 hostend
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, '/');
11742 portbegin
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, ':');
11747 port
= strtoul(portbegin
+ 1, &portend
, 10);
11748 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11760 /* Return NULL or the relative uri at the current server */
11761 static const char *
11762 get_rel_url_at_current_server(const char *uri
, const struct mg_connection
*conn
)
11764 const char *server_domain
;
11765 size_t server_domain_len
;
11766 size_t request_domain_len
= 0;
11767 unsigned long port
= 0;
11768 int i
, auth_domain_check_enabled
;
11769 const char *hostbegin
= NULL
;
11770 const char *hostend
= NULL
;
11771 const char *portbegin
;
11774 auth_domain_check_enabled
=
11775 !strcmp(conn
->ctx
->config
[ENABLE_AUTH_DOMAIN_CHECK
],"yes");
11776 /* DNS is case insensitive, so use case insensitive string compare here
11778 server_domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
11779 if (!server_domain
&& auth_domain_check_enabled
) {
11782 server_domain_len
= strlen(server_domain
);
11783 if (!server_domain_len
) {
11787 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11788 if (mg_strncasecmp(uri
,
11789 abs_uri_protocols
[i
].proto
,
11790 abs_uri_protocols
[i
].proto_len
) == 0) {
11792 hostbegin
= uri
+ abs_uri_protocols
[i
].proto_len
;
11793 hostend
= strchr(hostbegin
, '/');
11797 portbegin
= strchr(hostbegin
, ':');
11798 if ((!portbegin
) || (portbegin
> hostend
)) {
11799 port
= abs_uri_protocols
[i
].default_port
;
11800 request_domain_len
= (size_t)(hostend
- hostbegin
);
11802 port
= strtoul(portbegin
+ 1, &portend
, 10);
11803 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11806 request_domain_len
= (size_t)(portbegin
- hostbegin
);
11808 /* protocol found, port set */
11814 /* port remains 0 if the protocol is not found */
11818 /* Check if the request is directed to a different server. */
11819 /* First check if the port is the same (IPv4 and IPv6). */
11820 #if defined(USE_IPV6)
11821 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
11822 if (ntohs(conn
->client
.lsa
.sin6
.sin6_port
) != port
) {
11823 /* Request is directed to a different port */
11829 if (ntohs(conn
->client
.lsa
.sin
.sin_port
) != port
) {
11830 /* Request is directed to a different port */
11835 /* Finally check if the server corresponds to the authentication
11836 * domain of the server (the server domain).
11837 * Allow full matches (like http://mydomain.com/path/file.ext), and
11838 * allow subdomain matches (like http://www.mydomain.com/path/file.ext),
11839 * but do not allow substrings (like http://notmydomain.com/path/file.ext
11840 * or http://mydomain.com.fake/path/file.ext).
11842 if (auth_domain_check_enabled
) {
11843 if ((request_domain_len
== server_domain_len
)
11844 && (!memcmp(server_domain
, hostbegin
, server_domain_len
))) {
11845 /* Request is directed to this server - full name match. */
11847 if (request_domain_len
< (server_domain_len
+ 2)) {
11848 /* Request is directed to another server: The server name is longer
11850 * the request name. Drop this case here to avoid overflows in the
11851 * following checks. */
11854 if (hostbegin
[request_domain_len
- server_domain_len
- 1] != '.') {
11855 /* Request is directed to another server: It could be a substring
11856 * like notmyserver.com */
11859 if (0 != memcmp(server_domain
,
11860 hostbegin
+ request_domain_len
- server_domain_len
,
11861 server_domain_len
)) {
11862 /* Request is directed to another server:
11863 * The server name is different. */
11874 getreq(struct mg_connection
*conn
, char *ebuf
, size_t ebuf_len
, int *err
)
11877 int check_method
= should_validate_http_method(conn
);
11879 if (ebuf_len
> 0) {
11884 reset_per_request_attributes(conn
);
11888 NULL
, /* No truncation check for ebuf */
11896 /* Set the time the request was received. This value should be used for
11898 clock_gettime(CLOCK_MONOTONIC
, &(conn
->req_time
));
11900 conn
->request_len
=
11901 read_request(NULL
, conn
, conn
->buf
, conn
->buf_size
, &conn
->data_len
);
11902 /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
11904 if (conn
->request_len
>= 0 && conn
->data_len
< conn
->request_len
) {
11906 NULL
, /* No truncation check for ebuf */
11910 "Invalid request size");
11915 if (conn
->request_len
== 0 && conn
->data_len
== conn
->buf_size
) {
11917 NULL
, /* No truncation check for ebuf */
11921 "Request Too Large");
11924 } else if (conn
->request_len
<= 0) {
11925 if (conn
->data_len
> 0) {
11927 NULL
, /* No truncation check for ebuf */
11931 "Client sent malformed request");
11934 /* Server did not send anything -> just close the connection */
11935 conn
->must_close
= 1;
11937 NULL
, /* No truncation check for ebuf */
11941 "Client did not send a request");
11945 } else if (parse_http_message(
11946 check_method
, conn
->buf
, conn
->buf_size
, &conn
->request_info
)
11949 NULL
, /* No truncation check for ebuf */
11957 /* Message is a valid request or response */
11958 if ((cl
= get_header(&conn
->request_info
, "Transfer-Encoding"))
11960 && !mg_strcasecmp(cl
, "chunked")) {
11961 conn
->is_chunked
= 1;
11962 conn
->content_len
= 0;
11963 } else if ((cl
= get_header(&conn
->request_info
, "Content-Length")) != NULL
) {
11964 /* Request/response has content length set */
11965 char *endptr
= NULL
;
11966 conn
->content_len
= strtoll(cl
, &endptr
, 10);
11967 if (endptr
== cl
) {
11969 NULL
, /* No truncation check for ebuf */
11977 /* Publish the content length back to the request info. */
11978 conn
->request_info
.content_length
= conn
->content_len
;
11979 } else if (!mg_strcasecmp(conn
->request_info
.request_method
, "POST")
11980 || !mg_strcasecmp(conn
->request_info
.request_method
,
11982 /* POST or PUT request without content length set */
11983 conn
->content_len
= -1;
11984 } else if (!mg_strncasecmp(conn
->request_info
.request_method
,
11987 /* Response without content length set */
11988 conn
->content_len
= -1;
11990 /* Other request */
11991 conn
->content_len
= 0;
11999 mg_get_response(struct mg_connection
*conn
,
12005 /* Implementation of API function for HTTP clients */
12007 struct mg_context
*octx
= conn
->ctx
;
12008 struct mg_context rctx
= *(conn
->ctx
);
12009 char txt
[32]; /* will not overflow */
12011 if (timeout
>= 0) {
12012 mg_snprintf(conn
, NULL
, txt
, sizeof(txt
), "%i", timeout
);
12013 rctx
.config
[REQUEST_TIMEOUT
] = txt
;
12014 set_sock_timeout(conn
->client
.sock
, timeout
);
12016 rctx
.config
[REQUEST_TIMEOUT
] = NULL
;
12020 ret
= getreq(conn
, ebuf
, ebuf_len
, &err
);
12023 /* TODO: 1) uri is deprecated;
12024 * 2) here, ri.uri is the http response code */
12025 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
12027 /* TODO (mid): Define proper return values - maybe return length?
12028 * For the first test use <0 for error and >0 for OK */
12029 return (ret
== 0) ? -1 : +1;
12035 struct mg_connection
*
12036 mg_download(const char *host
,
12044 struct mg_connection
*conn
;
12052 /* open a connection */
12053 conn
= mg_connect_client(host
, port
, use_ssl
, ebuf
, ebuf_len
);
12055 if (conn
!= NULL
) {
12056 i
= mg_vprintf(conn
, fmt
, ap
);
12059 NULL
, /* No truncation check for ebuf */
12063 "Error sending request");
12065 getreq(conn
, ebuf
, ebuf_len
, &reqerr
);
12067 /* TODO: 1) uri is deprecated;
12068 * 2) here, ri.uri is the http response code */
12069 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
12073 /* if an error occured, close the connection */
12074 if (ebuf
[0] != '\0' && conn
!= NULL
) {
12075 mg_close_connection(conn
);
12084 struct websocket_client_thread_data
{
12085 struct mg_connection
*conn
;
12086 mg_websocket_data_handler data_handler
;
12087 mg_websocket_close_handler close_handler
;
12088 void *callback_data
;
12092 #if defined(USE_WEBSOCKET)
12094 static unsigned __stdcall
websocket_client_thread(void *data
)
12097 websocket_client_thread(void *data
)
12100 struct websocket_client_thread_data
*cdata
=
12101 (struct websocket_client_thread_data
*)data
;
12103 mg_set_thread_name("ws-client");
12105 if (cdata
->conn
->ctx
) {
12106 if (cdata
->conn
->ctx
->callbacks
.init_thread
) {
12107 /* 3 indicates a websocket client thread */
12108 /* TODO: check if conn->ctx can be set */
12109 cdata
->conn
->ctx
->callbacks
.init_thread(cdata
->conn
->ctx
, 3);
12113 read_websocket(cdata
->conn
, cdata
->data_handler
, cdata
->callback_data
);
12115 DEBUG_TRACE("%s", "Websocket client thread exited\n");
12117 if (cdata
->close_handler
!= NULL
) {
12118 cdata
->close_handler(cdata
->conn
, cdata
->callback_data
);
12121 mg_free((void *)cdata
);
12132 struct mg_connection
*
12133 mg_connect_websocket_client(const char *host
,
12136 char *error_buffer
,
12137 size_t error_buffer_size
,
12139 const char *origin
,
12140 mg_websocket_data_handler data_func
,
12141 mg_websocket_close_handler close_func
,
12144 struct mg_connection
*conn
= NULL
;
12146 #if defined(USE_WEBSOCKET)
12147 struct mg_context
*newctx
= NULL
;
12148 struct websocket_client_thread_data
*thread_data
;
12149 static const char *magic
= "x3JJHMbDL1EzLkh9GBhXDw==";
12150 static const char *handshake_req
;
12152 if (origin
!= NULL
) {
12153 handshake_req
= "GET %s HTTP/1.1\r\n"
12155 "Upgrade: websocket\r\n"
12156 "Connection: Upgrade\r\n"
12157 "Sec-WebSocket-Key: %s\r\n"
12158 "Sec-WebSocket-Version: 13\r\n"
12162 handshake_req
= "GET %s HTTP/1.1\r\n"
12164 "Upgrade: websocket\r\n"
12165 "Connection: Upgrade\r\n"
12166 "Sec-WebSocket-Key: %s\r\n"
12167 "Sec-WebSocket-Version: 13\r\n"
12171 /* Establish the client connection and request upgrade */
12172 conn
= mg_download(host
,
12183 /* Connection object will be null if something goes wrong */
12184 if (conn
== NULL
|| (strcmp(conn
->request_info
.request_uri
, "101") != 0)) {
12185 if (!*error_buffer
) {
12186 /* if there is a connection, but it did not return 101,
12187 * error_buffer is not yet set */
12189 NULL
, /* No truncation check for ebuf */
12192 "Unexpected server reply");
12194 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer
);
12195 if (conn
!= NULL
) {
12202 /* For client connections, mg_context is fake. Since we need to set a
12203 * callback function, we need to create a copy and modify it. */
12204 newctx
= (struct mg_context
*)mg_malloc(sizeof(struct mg_context
));
12205 memcpy(newctx
, conn
->ctx
, sizeof(struct mg_context
));
12206 newctx
->user_data
= user_data
;
12207 newctx
->context_type
= 2; /* client context type */
12208 newctx
->cfg_worker_threads
= 1; /* one worker thread will be created */
12209 newctx
->workerthreadids
=
12210 (pthread_t
*)mg_calloc(newctx
->cfg_worker_threads
, sizeof(pthread_t
));
12211 conn
->ctx
= newctx
;
12212 thread_data
= (struct websocket_client_thread_data
*)
12213 mg_calloc(sizeof(struct websocket_client_thread_data
), 1);
12214 thread_data
->conn
= conn
;
12215 thread_data
->data_handler
= data_func
;
12216 thread_data
->close_handler
= close_func
;
12217 thread_data
->callback_data
= NULL
;
12219 /* Start a thread to read the websocket client connection
12220 * This thread will automatically stop when mg_disconnect is
12221 * called on the client connection */
12222 if (mg_start_thread_with_id(websocket_client_thread
,
12223 (void *)thread_data
,
12224 newctx
->workerthreadids
) != 0) {
12225 mg_free((void *)thread_data
);
12226 mg_free((void *)newctx
->workerthreadids
);
12227 mg_free((void *)newctx
);
12228 mg_free((void *)conn
);
12231 "Websocket client connect thread could not be started\r\n");
12234 /* Appease "unused parameter" warnings */
12238 (void)error_buffer
;
12239 (void)error_buffer_size
;
12252 process_new_connection(struct mg_connection
*conn
)
12254 if (conn
&& conn
->ctx
) {
12255 struct mg_request_info
*ri
= &conn
->request_info
;
12256 int keep_alive_enabled
, keep_alive
, discard_len
;
12258 const char *hostend
;
12259 int reqerr
, uri_type
;
12261 keep_alive_enabled
=
12262 !strcmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes");
12264 /* Important: on new connection, reset the receiving buffer. Credit
12265 * goes to crule42. */
12266 conn
->data_len
= 0;
12268 if (!getreq(conn
, ebuf
, sizeof(ebuf
), &reqerr
)) {
12269 /* The request sent by the client could not be understood by
12270 * the server, or it was incomplete or a timeout. Send an
12271 * error message and close the connection. */
12273 /*assert(ebuf[0] != '\0');*/
12274 send_http_error(conn
, reqerr
, "%s", ebuf
);
12276 } else if (strcmp(ri
->http_version
, "1.0")
12277 && strcmp(ri
->http_version
, "1.1")) {
12279 NULL
, /* No truncation check for ebuf */
12282 "Bad HTTP version: [%s]",
12284 send_http_error(conn
, 505, "%s", ebuf
);
12287 if (ebuf
[0] == '\0') {
12288 uri_type
= get_uri_type(conn
->request_info
.request_uri
);
12289 switch (uri_type
) {
12292 conn
->request_info
.local_uri
= NULL
;
12296 conn
->request_info
.local_uri
=
12297 conn
->request_info
.request_uri
;
12301 /* absolute uri (with/without port) */
12302 hostend
= get_rel_url_at_current_server(
12303 conn
->request_info
.request_uri
, conn
);
12305 conn
->request_info
.local_uri
= hostend
;
12307 conn
->request_info
.local_uri
= NULL
;
12312 NULL
, /* No truncation check for ebuf */
12315 "Invalid URI: [%s]",
12317 send_http_error(conn
, 400, "%s", ebuf
);
12321 /* TODO: cleanup uri, local_uri and request_uri */
12322 conn
->request_info
.uri
= conn
->request_info
.local_uri
;
12325 if (ebuf
[0] == '\0') {
12326 if (conn
->request_info
.local_uri
) {
12327 /* handle request to local server */
12328 handle_request(conn
);
12329 if (conn
->ctx
->callbacks
.end_request
!= NULL
) {
12330 conn
->ctx
->callbacks
.end_request(conn
,
12331 conn
->status_code
);
12335 /* TODO: handle non-local request (PROXY) */
12336 conn
->must_close
= 1;
12339 conn
->must_close
= 1;
12342 if (ri
->remote_user
!= NULL
) {
12343 mg_free((void *)ri
->remote_user
);
12344 /* Important! When having connections with and without auth
12345 * would cause double free and then crash */
12346 ri
->remote_user
= NULL
;
12349 /* NOTE(lsm): order is important here. should_keep_alive() call
12351 * using parsed request, which will be invalid after memmove's
12353 * Therefore, memorize should_keep_alive() result now for later
12355 * in loop exit condition. */
12356 keep_alive
= conn
->ctx
->stop_flag
== 0 && keep_alive_enabled
12357 && conn
->content_len
>= 0 && should_keep_alive(conn
);
12359 /* Discard all buffered data for this request */
12360 discard_len
= conn
->content_len
>= 0 && conn
->request_len
> 0
12361 && conn
->request_len
+ conn
->content_len
12362 < (int64_t)conn
->data_len
12363 ? (int)(conn
->request_len
+ conn
->content_len
)
12365 /*assert(discard_len >= 0);*/
12366 if (discard_len
< 0)
12368 conn
->data_len
-= discard_len
;
12369 if (conn
->data_len
> 0) {
12371 conn
->buf
+ discard_len
,
12372 (size_t)conn
->data_len
);
12375 /* assert(conn->data_len >= 0); */
12376 /* assert(conn->data_len <= conn->buf_size); */
12378 if ((conn
->data_len
< 0) || (conn
->data_len
> conn
->buf_size
)) {
12382 } while (keep_alive
);
12387 /* Worker threads take accepted socket from the queue */
12389 consume_socket(struct mg_context
*ctx
, struct socket
*sp
)
12391 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12396 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12397 DEBUG_TRACE("%s", "going idle");
12399 /* If the queue is empty, wait. We're idle at this point. */
12400 while (ctx
->sq_head
== ctx
->sq_tail
&& ctx
->stop_flag
== 0) {
12401 pthread_cond_wait(&ctx
->sq_full
, &ctx
->thread_mutex
);
12404 /* If we're stopping, sq_head may be equal to sq_tail. */
12405 if (ctx
->sq_head
> ctx
->sq_tail
) {
12406 /* Copy socket from the queue and increment tail */
12407 *sp
= ctx
->queue
[ctx
->sq_tail
% QUEUE_SIZE(ctx
)];
12410 DEBUG_TRACE("grabbed socket %d, going busy", sp
? sp
->sock
: -1);
12412 /* Wrap pointers if needed */
12413 while (ctx
->sq_tail
> QUEUE_SIZE(ctx
)) {
12414 ctx
->sq_tail
-= QUEUE_SIZE(ctx
);
12415 ctx
->sq_head
-= QUEUE_SIZE(ctx
);
12419 (void)pthread_cond_signal(&ctx
->sq_empty
);
12420 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12422 return !ctx
->stop_flag
;
12428 worker_thread_run(void *thread_func_param
)
12430 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12431 struct mg_connection
*conn
;
12432 struct mg_workerTLS tls
;
12433 #if defined(MG_LEGACY_INTERFACE)
12437 mg_set_thread_name("worker");
12440 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12441 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12442 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12445 if (ctx
->callbacks
.init_thread
) {
12446 /* call init_thread for a worker thread (type 1) */
12447 ctx
->callbacks
.init_thread(ctx
, 1);
12451 (struct mg_connection
*)mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
);
12452 if (conn
== NULL
) {
12453 mg_cry(fc(ctx
), "%s", "Cannot create new connection struct, OOM");
12455 pthread_setspecific(sTlsKey
, &tls
);
12456 conn
->buf_size
= MAX_REQUEST_SIZE
;
12457 conn
->buf
= (char *)(conn
+ 1);
12459 conn
->request_info
.user_data
= ctx
->user_data
;
12460 /* Allocate a mutex for this connection to allow communication both
12461 * within the request handler and from elsewhere in the application
12463 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
12465 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
12466 * signal sq_empty condvar to wake up the master waiting in
12467 * produce_socket() */
12468 while (consume_socket(ctx
, &conn
->client
)) {
12469 conn
->conn_birth_time
= time(NULL
);
12471 /* Fill in IP, port info early so even if SSL setup below fails,
12472 * error handler would have the corresponding info.
12473 * Thanks to Johannes Winkelmann for the patch.
12475 #if defined(USE_IPV6)
12476 if (conn
->client
.rsa
.sa
.sa_family
== AF_INET6
) {
12477 conn
->request_info
.remote_port
=
12478 ntohs(conn
->client
.rsa
.sin6
.sin6_port
);
12482 conn
->request_info
.remote_port
=
12483 ntohs(conn
->client
.rsa
.sin
.sin_port
);
12486 sockaddr_to_string(conn
->request_info
.remote_addr
,
12487 sizeof(conn
->request_info
.remote_addr
),
12488 &conn
->client
.rsa
);
12490 #if defined(MG_LEGACY_INTERFACE)
12491 /* This legacy interface only works for the IPv4 case */
12492 addr
= ntohl(conn
->client
.rsa
.sin
.sin_addr
.s_addr
);
12493 memcpy(&conn
->request_info
.remote_ip
, &addr
, 4);
12496 conn
->request_info
.is_ssl
= conn
->client
.is_ssl
;
12498 if (!conn
->client
.is_ssl
12500 || sslize(conn
, conn
->ctx
->ssl_ctx
, SSL_accept
)
12505 process_new_connection(conn
);
12508 close_connection(conn
);
12512 /* Signal master that we're done with connection and exiting */
12513 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12514 ctx
->running_worker_threads
--;
12515 (void)pthread_cond_signal(&ctx
->thread_cond
);
12516 /* assert(ctx->running_worker_threads >= 0); */
12517 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12519 pthread_setspecific(sTlsKey
, NULL
);
12520 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12521 CloseHandle(tls
.pthread_cond_helper_mutex
);
12523 pthread_mutex_destroy(&conn
->mutex
);
12526 DEBUG_TRACE("%s", "exiting");
12531 /* Threads have different return types on Windows and Unix. */
12533 static unsigned __stdcall
worker_thread(void *thread_func_param
)
12535 worker_thread_run(thread_func_param
);
12540 worker_thread(void *thread_func_param
)
12542 worker_thread_run(thread_func_param
);
12545 #endif /* _WIN32 */
12548 /* Master thread adds accepted socket to a queue */
12550 produce_socket(struct mg_context
*ctx
, const struct socket
*sp
)
12552 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12556 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12558 /* If the queue is full, wait */
12559 while (ctx
->stop_flag
== 0
12560 && ctx
->sq_head
- ctx
->sq_tail
>= QUEUE_SIZE(ctx
)) {
12561 (void)pthread_cond_wait(&ctx
->sq_empty
, &ctx
->thread_mutex
);
12564 if (ctx
->sq_head
- ctx
->sq_tail
< QUEUE_SIZE(ctx
)) {
12565 /* Copy socket to the queue and increment head */
12566 ctx
->queue
[ctx
->sq_head
% QUEUE_SIZE(ctx
)] = *sp
;
12568 DEBUG_TRACE("queued socket %d", sp
? sp
->sock
: -1);
12571 (void)pthread_cond_signal(&ctx
->sq_full
);
12572 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12578 accept_new_connection(const struct socket
*listener
, struct mg_context
*ctx
)
12581 char src_addr
[IP_ADDR_STR_LEN
];
12582 socklen_t len
= sizeof(so
.rsa
);
12590 if ((so
.sock
= accept(listener
->sock
, &so
.rsa
.sa
, &len
))
12591 == INVALID_SOCKET
) {
12592 } else if (!check_acl(ctx
, ntohl(*(uint32_t *)&so
.rsa
.sin
.sin_addr
))) {
12593 sockaddr_to_string(src_addr
, sizeof(src_addr
), &so
.rsa
);
12594 mg_cry(fc(ctx
), "%s: %s is not allowed to connect", __func__
, src_addr
);
12595 closesocket(so
.sock
);
12596 so
.sock
= INVALID_SOCKET
;
12598 /* Put so socket structure into the queue */
12599 DEBUG_TRACE("Accepted socket %d", (int)so
.sock
);
12600 set_close_on_exec(so
.sock
, fc(ctx
));
12601 so
.is_ssl
= listener
->is_ssl
;
12602 so
.ssl_redir
= listener
->ssl_redir
;
12603 if (getsockname(so
.sock
, &so
.lsa
.sa
, &len
) != 0) {
12605 "%s: getsockname() failed: %s",
12610 /* Set TCP keep-alive. This is needed because if HTTP-level
12612 * is enabled, and client resets the connection, server won't get
12613 * TCP FIN or RST and will keep the connection open forever. With
12614 * TCP keep-alive, next keep-alive handshake will figure out that
12615 * the client is down and will close the server end.
12616 * Thanks to Igor Klopov who suggested the patch. */
12617 if (setsockopt(so
.sock
,
12620 (SOCK_OPT_TYPE
)&on
,
12621 sizeof(on
)) != 0) {
12623 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
12629 /* Disable TCP Nagle's algorithm. Normally TCP packets are
12631 * to effectively fill up the underlying IP packet payload and
12633 * the overhead of sending lots of small buffers. However this hurts
12634 * the server's throughput (ie. operations per second) when HTTP 1.1
12635 * persistent connections are used and the responses are relatively
12636 * small (eg. less than 1400 bytes).
12638 if ((ctx
!= NULL
) && (ctx
->config
[CONFIG_TCP_NODELAY
] != NULL
)
12639 && (!strcmp(ctx
->config
[CONFIG_TCP_NODELAY
], "1"))) {
12640 if (set_tcp_nodelay(so
.sock
, 1) != 0) {
12642 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
12648 if (ctx
&& ctx
->config
[REQUEST_TIMEOUT
]) {
12649 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]);
12654 /* Set socket timeout to the given value, but not more than a
12655 * a certain limit (SOCKET_TIMEOUT_QUANTUM, default 10 seconds),
12656 * so the server can exit after that time if requested. */
12657 if ((timeout
> 0) && (timeout
< SOCKET_TIMEOUT_QUANTUM
)) {
12658 set_sock_timeout(so
.sock
, timeout
);
12660 set_sock_timeout(so
.sock
, SOCKET_TIMEOUT_QUANTUM
);
12663 produce_socket(ctx
, &so
);
12669 master_thread_run(void *thread_func_param
)
12671 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12672 struct mg_workerTLS tls
;
12673 struct pollfd
*pfd
;
12675 unsigned int workerthreadcount
;
12681 mg_set_thread_name("master");
12683 /* Increase priority of the master thread */
12684 #if defined(_WIN32)
12685 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
12686 #elif defined(USE_MASTER_THREAD_PRIORITY)
12687 int min_prio
= sched_get_priority_min(SCHED_RR
);
12688 int max_prio
= sched_get_priority_max(SCHED_RR
);
12689 if ((min_prio
>= 0) && (max_prio
>= 0)
12690 && ((USE_MASTER_THREAD_PRIORITY
) <= max_prio
)
12691 && ((USE_MASTER_THREAD_PRIORITY
) >= min_prio
)) {
12692 struct sched_param sched_param
= {0};
12693 sched_param
.sched_priority
= (USE_MASTER_THREAD_PRIORITY
);
12694 pthread_setschedparam(pthread_self(), SCHED_RR
, &sched_param
);
12698 /* Initialize thread local storage */
12699 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12700 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12703 pthread_setspecific(sTlsKey
, &tls
);
12705 if (ctx
->callbacks
.init_thread
) {
12706 /* Callback for the master thread (type 0) */
12707 ctx
->callbacks
.init_thread(ctx
, 0);
12710 /* Server starts *now* */
12711 ctx
->start_time
= time(NULL
);
12713 /* Allocate memory for the listening sockets, and start the server */
12715 (struct pollfd
*)mg_calloc(ctx
->num_listening_sockets
, sizeof(pfd
[0]));
12716 while (pfd
!= NULL
&& ctx
->stop_flag
== 0) {
12717 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12718 pfd
[i
].fd
= ctx
->listening_sockets
[i
].sock
;
12719 pfd
[i
].events
= POLLIN
;
12722 if (poll(pfd
, ctx
->num_listening_sockets
, 200) > 0) {
12723 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12724 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
12725 * successful poll, and POLLIN is defined as
12726 * (POLLRDNORM | POLLRDBAND)
12727 * Therefore, we're checking pfd[i].revents & POLLIN, not
12728 * pfd[i].revents == POLLIN. */
12729 if (ctx
->stop_flag
== 0 && (pfd
[i
].revents
& POLLIN
)) {
12730 accept_new_connection(&ctx
->listening_sockets
[i
], ctx
);
12736 DEBUG_TRACE("%s", "stopping workers");
12738 /* Stop signal received: somebody called mg_stop. Quit. */
12739 close_all_listening_sockets(ctx
);
12741 /* Wakeup workers that are waiting for connections to handle. */
12742 pthread_cond_broadcast(&ctx
->sq_full
);
12744 /* Wait until all threads finish */
12745 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12746 while (ctx
->running_worker_threads
> 0) {
12747 (void)pthread_cond_wait(&ctx
->thread_cond
, &ctx
->thread_mutex
);
12749 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12751 /* Join all worker threads to avoid leaking threads. */
12752 workerthreadcount
= ctx
->cfg_worker_threads
;
12753 for (i
= 0; i
< workerthreadcount
; i
++) {
12754 if (ctx
->workerthreadids
[i
] != 0) {
12755 mg_join_thread(ctx
->workerthreadids
[i
]);
12759 #if !defined(NO_SSL)
12760 if (ctx
->ssl_ctx
!= NULL
) {
12761 uninitialize_ssl(ctx
);
12764 DEBUG_TRACE("%s", "exiting");
12766 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12767 CloseHandle(tls
.pthread_cond_helper_mutex
);
12769 pthread_setspecific(sTlsKey
, NULL
);
12771 /* Signal mg_stop() that we're done.
12772 * WARNING: This must be the very last thing this
12773 * thread does, as ctx becomes invalid after this line. */
12774 ctx
->stop_flag
= 2;
12778 /* Threads have different return types on Windows and Unix. */
12780 static unsigned __stdcall
master_thread(void *thread_func_param
)
12782 master_thread_run(thread_func_param
);
12787 master_thread(void *thread_func_param
)
12789 master_thread_run(thread_func_param
);
12792 #endif /* _WIN32 */
12796 free_context(struct mg_context
*ctx
)
12799 struct mg_handler_info
*tmp_rh
;
12805 if (ctx
->callbacks
.exit_context
) {
12806 ctx
->callbacks
.exit_context(ctx
);
12809 /* All threads exited, no sync is needed. Destroy thread mutex and
12812 (void)pthread_mutex_destroy(&ctx
->thread_mutex
);
12813 (void)pthread_cond_destroy(&ctx
->thread_cond
);
12814 (void)pthread_cond_destroy(&ctx
->sq_empty
);
12815 (void)pthread_cond_destroy(&ctx
->sq_full
);
12817 /* Destroy other context global data structures mutex */
12818 (void)pthread_mutex_destroy(&ctx
->nonce_mutex
);
12820 #if defined(USE_TIMERS)
12824 /* Deallocate config parameters */
12825 for (i
= 0; i
< NUM_OPTIONS
; i
++) {
12826 if (ctx
->config
[i
] != NULL
) {
12827 #if defined(_MSC_VER)
12828 #pragma warning(suppress : 6001)
12830 mg_free(ctx
->config
[i
]);
12834 /* Deallocate request handlers */
12835 while (ctx
->handlers
) {
12836 tmp_rh
= ctx
->handlers
;
12837 ctx
->handlers
= tmp_rh
->next
;
12838 mg_free(tmp_rh
->uri
);
12843 /* Deallocate SSL context */
12844 if (ctx
->ssl_ctx
!= NULL
) {
12845 SSL_CTX_free(ctx
->ssl_ctx
);
12847 #endif /* !NO_SSL */
12849 /* Deallocate worker thread ID array */
12850 if (ctx
->workerthreadids
!= NULL
) {
12851 mg_free(ctx
->workerthreadids
);
12854 /* Deallocate the tls variable */
12855 if (mg_atomic_dec(&sTlsInit
) == 0) {
12856 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12857 DeleteCriticalSection(&global_log_file_lock
);
12858 #endif /* _WIN32 && !__SYMBIAN32__ */
12859 #if !defined(_WIN32)
12860 pthread_mutexattr_destroy(&pthread_mutex_attr
);
12863 pthread_key_delete(sTlsKey
);
12866 /* deallocate system name string */
12867 mg_free(ctx
->systemName
);
12869 /* Deallocate context itself */
12875 mg_stop(struct mg_context
*ctx
)
12882 /* We don't use a lock here. Calling mg_stop with the same ctx from
12883 * two threads is not allowed. */
12884 mt
= ctx
->masterthreadid
;
12889 ctx
->masterthreadid
= 0;
12890 ctx
->stop_flag
= 1;
12892 /* Wait until mg_fini() stops */
12893 while (ctx
->stop_flag
!= 2) {
12894 (void)mg_sleep(10);
12897 mg_join_thread(mt
);
12900 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12901 (void)WSACleanup();
12902 #endif /* _WIN32 && !__SYMBIAN32__ */
12907 get_system_name(char **sysName
)
12909 #if defined(_WIN32)
12910 #if !defined(__SYMBIAN32__)
12912 DWORD dwVersion
= 0;
12913 DWORD dwMajorVersion
= 0;
12914 DWORD dwMinorVersion
= 0;
12918 #pragma warning(push)
12919 // GetVersion was declared deprecated
12920 #pragma warning(disable : 4996)
12922 dwVersion
= GetVersion();
12924 #pragma warning(pop)
12927 dwMajorVersion
= (DWORD
)(LOBYTE(LOWORD(dwVersion
)));
12928 dwMinorVersion
= (DWORD
)(HIBYTE(LOWORD(dwVersion
)));
12929 dwBuild
= ((dwVersion
< 0x80000000) ? (DWORD
)(HIWORD(dwVersion
)) : 0);
12934 (unsigned)dwMajorVersion
,
12935 (unsigned)dwMinorVersion
);
12936 *sysName
= mg_strdup(name
);
12938 *sysName
= mg_strdup("Symbian");
12941 struct utsname name
;
12942 memset(&name
, 0, sizeof(name
));
12944 *sysName
= mg_strdup(name
.sysname
);
12949 struct mg_context
*
12950 mg_start(const struct mg_callbacks
*callbacks
,
12952 const char **options
)
12954 struct mg_context
*ctx
;
12955 const char *name
, *value
, *default_value
;
12956 int idx
, ok
, workerthreadcount
;
12958 void (*exit_callback
)(const struct mg_context
*ctx
) = 0;
12960 struct mg_workerTLS tls
;
12962 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12964 WSAStartup(MAKEWORD(2, 2), &data
);
12965 #endif /* _WIN32 && !__SYMBIAN32__ */
12967 /* Allocate context and initialize reasonable general case defaults. */
12968 if ((ctx
= (struct mg_context
*)mg_calloc(1, sizeof(*ctx
))) == NULL
) {
12972 /* Random number generator will initialize at the first call */
12973 ctx
->auth_nonce_mask
=
12974 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options
);
12976 if (mg_atomic_inc(&sTlsInit
) == 1) {
12978 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12979 InitializeCriticalSection(&global_log_file_lock
);
12980 #endif /* _WIN32 && !__SYMBIAN32__ */
12981 #if !defined(_WIN32)
12982 pthread_mutexattr_init(&pthread_mutex_attr
);
12983 pthread_mutexattr_settype(&pthread_mutex_attr
, PTHREAD_MUTEX_RECURSIVE
);
12986 if (0 != pthread_key_create(&sTlsKey
, tls_dtor
)) {
12987 /* Fatal error - abort start. However, this situation should
12989 * occur in practice. */
12990 mg_atomic_dec(&sTlsInit
);
12991 mg_cry(fc(ctx
), "Cannot initialize thread local storage");
12996 /* TODO (low): istead of sleeping, check if sTlsKey is already
13001 tls
.is_master
= -1;
13002 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
13003 #if defined(_WIN32) && !defined(__SYMBIAN32__)
13004 tls
.pthread_cond_helper_mutex
= NULL
;
13006 pthread_setspecific(sTlsKey
, &tls
);
13008 #if defined(USE_LUA)
13009 lua_init_optional_libraries();
13012 ok
= 0 == pthread_mutex_init(&ctx
->thread_mutex
, &pthread_mutex_attr
);
13013 ok
&= 0 == pthread_cond_init(&ctx
->thread_cond
, NULL
);
13014 ok
&= 0 == pthread_cond_init(&ctx
->sq_empty
, NULL
);
13015 ok
&= 0 == pthread_cond_init(&ctx
->sq_full
, NULL
);
13016 ok
&= 0 == pthread_mutex_init(&ctx
->nonce_mutex
, &pthread_mutex_attr
);
13018 /* Fatal error - abort start. However, this situation should never
13019 * occur in practice. */
13020 mg_cry(fc(ctx
), "Cannot initialize thread synchronization objects");
13022 pthread_setspecific(sTlsKey
, NULL
);
13027 ctx
->callbacks
= *callbacks
;
13028 exit_callback
= callbacks
->exit_context
;
13029 ctx
->callbacks
.exit_context
= 0;
13031 ctx
->user_data
= user_data
;
13032 ctx
->handlers
= NULL
;
13034 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
13035 ctx
->shared_lua_websockets
= 0;
13038 while (options
&& (name
= *options
++) != NULL
) {
13039 if ((idx
= get_option_index(name
)) == -1) {
13040 mg_cry(fc(ctx
), "Invalid option: %s", name
);
13042 pthread_setspecific(sTlsKey
, NULL
);
13044 } else if ((value
= *options
++) == NULL
) {
13045 mg_cry(fc(ctx
), "%s: option value cannot be NULL", name
);
13047 pthread_setspecific(sTlsKey
, NULL
);
13050 if (ctx
->config
[idx
] != NULL
) {
13051 mg_cry(fc(ctx
), "warning: %s: duplicate option", name
);
13052 mg_free(ctx
->config
[idx
]);
13054 ctx
->config
[idx
] = mg_strdup(value
);
13055 DEBUG_TRACE("[%s] -> [%s]", name
, value
);
13058 /* Set default value if needed */
13059 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
13060 default_value
= config_options
[i
].default_value
;
13061 if (ctx
->config
[i
] == NULL
&& default_value
!= NULL
) {
13062 ctx
->config
[i
] = mg_strdup(default_value
);
13066 #if defined(NO_FILES)
13067 if (ctx
->config
[DOCUMENT_ROOT
] != NULL
) {
13068 mg_cry(fc(ctx
), "%s", "Document root must not be set");
13070 pthread_setspecific(sTlsKey
, NULL
);
13075 get_system_name(&ctx
->systemName
);
13077 /* NOTE(lsm): order is important here. SSL certificates must
13078 * be initialized before listening ports. UID must be set last. */
13079 if (!set_gpass_option(ctx
) ||
13080 #if !defined(NO_SSL)
13081 !set_ssl_option(ctx
) ||
13083 !set_ports_option(ctx
) ||
13084 #if !defined(_WIN32)
13085 !set_uid_option(ctx
) ||
13087 !set_acl_option(ctx
)) {
13089 pthread_setspecific(sTlsKey
, NULL
);
13093 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
13094 /* Ignore SIGPIPE signal, so if browser cancels the request, it
13095 * won't kill the whole process. */
13096 (void)signal(SIGPIPE
, SIG_IGN
);
13097 #endif /* !_WIN32 && !__SYMBIAN32__ */
13099 workerthreadcount
= atoi(ctx
->config
[NUM_THREADS
]);
13101 if (workerthreadcount
> MAX_WORKER_THREADS
) {
13102 mg_cry(fc(ctx
), "Too many worker threads");
13104 pthread_setspecific(sTlsKey
, NULL
);
13108 if (workerthreadcount
> 0) {
13109 ctx
->cfg_worker_threads
= ((unsigned int)(workerthreadcount
));
13110 ctx
->workerthreadids
=
13111 (pthread_t
*)mg_calloc(ctx
->cfg_worker_threads
, sizeof(pthread_t
));
13112 if (ctx
->workerthreadids
== NULL
) {
13113 mg_cry(fc(ctx
), "Not enough memory for worker thread ID array");
13115 pthread_setspecific(sTlsKey
, NULL
);
13120 #if defined(USE_TIMERS)
13121 if (timers_init(ctx
) != 0) {
13122 mg_cry(fc(ctx
), "Error creating timers");
13124 pthread_setspecific(sTlsKey
, NULL
);
13129 /* Context has been created - init user libraries */
13130 if (ctx
->callbacks
.init_context
) {
13131 ctx
->callbacks
.init_context(ctx
);
13133 ctx
->callbacks
.exit_context
= exit_callback
;
13134 ctx
->context_type
= 1; /* server context */
13136 /* Start master (listening) thread */
13137 mg_start_thread_with_id(master_thread
, ctx
, &ctx
->masterthreadid
);
13139 /* Start worker threads */
13140 for (i
= 0; i
< ctx
->cfg_worker_threads
; i
++) {
13141 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13142 ctx
->running_worker_threads
++;
13143 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13144 if (mg_start_thread_with_id(worker_thread
,
13146 &ctx
->workerthreadids
[i
]) != 0) {
13147 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13148 ctx
->running_worker_threads
--;
13149 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13152 "Cannot start worker thread %i: error %ld",
13157 "Cannot create threads: error %ld",
13160 pthread_setspecific(sTlsKey
, NULL
);
13167 pthread_setspecific(sTlsKey
, NULL
);
13172 /* Feature check API function */
13174 mg_check_feature(unsigned feature
)
13176 static const unsigned feature_set
= 0
13177 /* Set bits for available features according to API documentation.
13178 * This bit mask is created at compile time, according to the active
13179 * preprocessor defines. It is a single const value at runtime. */
13180 #if !defined(NO_FILES)
13183 #if !defined(NO_SSL)
13186 #if !defined(NO_CGI)
13189 #if defined(USE_IPV6)
13192 #if defined(USE_WEBSOCKET)
13195 #if defined(USE_LUA)
13198 #if defined(USE_DUKTAPE)
13201 #if !defined(NO_CACHING)
13205 /* Set some extra bits not defined in the API documentation.
13206 * These bits may change without further notice. */
13207 #if defined(MG_LEGACY_INTERFACE)
13210 #if defined(MEMORY_DEBUGGING)
13213 #if defined(USE_TIMERS)
13216 #if !defined(NO_NONCE_CHECK)
13219 #if !defined(NO_POPEN)
13223 return (feature
& feature_set
);