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
,
1076 ENABLE_DIRECTORY_LISTING
,
1078 GLOBAL_PASSWORDS_FILE
,
1081 ACCESS_CONTROL_LIST
,
1095 SSL_DEFAULT_VERIFY_PATHS
,
1097 SSL_PROTOCOL_VERSION
,
1099 #if defined(USE_WEBSOCKET)
1104 #if defined(USE_LUA)
1106 LUA_SCRIPT_EXTENSIONS
,
1107 LUA_SERVER_PAGE_EXTENSIONS
,
1109 #if defined(USE_DUKTAPE)
1110 DUKTAPE_SCRIPT_EXTENSIONS
,
1113 #if defined(USE_WEBSOCKET)
1116 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1117 LUA_WEBSOCKET_EXTENSIONS
,
1119 ACCESS_CONTROL_ALLOW_ORIGIN
,
1121 CONFIG_TCP_NODELAY
, /* Prepended CONFIG_ to avoid conflict with the
1122 * socket option typedef TCP_NODELAY. */
1123 #if !defined(NO_CACHING)
1124 STATIC_FILE_MAX_AGE
,
1131 /* Config option name, config types, default value */
1132 static struct mg_option config_options
[] = {
1133 {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.cgi$|**.pl$|**.php$"},
1134 {"cgi_environment", CONFIG_TYPE_STRING
, NULL
},
1135 {"put_delete_auth_file", CONFIG_TYPE_FILE
, NULL
},
1136 {"cgi_interpreter", CONFIG_TYPE_FILE
, NULL
},
1137 {"protect_uri", CONFIG_TYPE_STRING
, NULL
},
1138 {"authentication_domain", CONFIG_TYPE_STRING
, "mydomain.com"},
1139 {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.shtml$|**.shtm$"},
1140 {"throttle", CONFIG_TYPE_STRING
, NULL
},
1141 {"access_log_file", CONFIG_TYPE_FILE
, NULL
},
1142 {"enable_directory_listing", CONFIG_TYPE_BOOLEAN
, "yes"},
1143 {"error_log_file", CONFIG_TYPE_FILE
, NULL
},
1144 {"global_auth_file", CONFIG_TYPE_FILE
, NULL
},
1148 "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,"
1149 "index.shtml,index.php"},
1151 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
1153 {"enable_keep_alive", CONFIG_TYPE_BOOLEAN
, "no"},
1154 {"access_control_list", CONFIG_TYPE_STRING
, NULL
},
1155 {"extra_mime_types", CONFIG_TYPE_STRING
, NULL
},
1156 {"listening_ports", CONFIG_TYPE_STRING
, "8080"},
1157 {"document_root", CONFIG_TYPE_DIRECTORY
, NULL
},
1158 {"ssl_certificate", CONFIG_TYPE_FILE
, NULL
},
1159 {"num_threads", CONFIG_TYPE_NUMBER
, "50"},
1160 {"run_as_user", CONFIG_TYPE_STRING
, NULL
},
1161 {"url_rewrite_patterns", CONFIG_TYPE_STRING
, NULL
},
1162 {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN
, NULL
},
1163 {"request_timeout_ms", CONFIG_TYPE_NUMBER
, "30000"},
1164 {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN
, "no"},
1165 {"ssl_ca_path", CONFIG_TYPE_DIRECTORY
, NULL
},
1166 {"ssl_ca_file", CONFIG_TYPE_FILE
, NULL
},
1167 {"ssl_verify_depth", CONFIG_TYPE_NUMBER
, "9"},
1168 {"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN
, "yes"},
1169 {"ssl_cipher_list", CONFIG_TYPE_STRING
, NULL
},
1170 {"ssl_protocol_version", CONFIG_TYPE_NUMBER
, "0"},
1171 {"ssl_short_trust", CONFIG_TYPE_BOOLEAN
, "no"},
1172 #if defined(USE_WEBSOCKET)
1173 {"websocket_timeout_ms", CONFIG_TYPE_NUMBER
, "30000"},
1175 {"decode_url", CONFIG_TYPE_BOOLEAN
, "yes"},
1177 #if defined(USE_LUA)
1178 {"lua_preload_file", CONFIG_TYPE_FILE
, NULL
},
1179 {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lua$"},
1180 {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lp$|**.lsp$"},
1182 #if defined(USE_DUKTAPE)
1183 /* The support for duktape is still in alpha version state.
1184 * The name of this config option might change. */
1185 {"duktape_script_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.ssjs$"},
1188 #if defined(USE_WEBSOCKET)
1189 {"websocket_root", CONFIG_TYPE_DIRECTORY
, NULL
},
1191 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1192 {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lua$"},
1194 {"access_control_allow_origin", CONFIG_TYPE_STRING
, "*"},
1195 {"error_pages", CONFIG_TYPE_DIRECTORY
, NULL
},
1196 {"tcp_nodelay", CONFIG_TYPE_NUMBER
, "0"},
1197 #if !defined(NO_CACHING)
1198 {"static_file_max_age", CONFIG_TYPE_NUMBER
, "3600"},
1201 {NULL
, CONFIG_TYPE_UNKNOWN
, NULL
}};
1203 /* Check if the config_options and the corresponding enum have compatible
1205 mg_static_assert((sizeof(config_options
) / sizeof(config_options
[0]))
1206 == (NUM_OPTIONS
+ 1),
1207 "config_options and enum not sync");
1209 enum { REQUEST_HANDLER
, WEBSOCKET_HANDLER
, AUTH_HANDLER
};
1211 struct mg_handler_info
{
1212 /* Name/Pattern of the URI. */
1219 /* Handler for http/https or authorization requests. */
1220 mg_request_handler handler
;
1222 /* Handler for ws/wss (websocket) requests. */
1223 mg_websocket_connect_handler connect_handler
;
1224 mg_websocket_ready_handler ready_handler
;
1225 mg_websocket_data_handler data_handler
;
1226 mg_websocket_close_handler close_handler
;
1228 /* Handler for authorization requests */
1229 mg_authorization_handler auth_handler
;
1231 /* User supplied argument for the handler function. */
1234 /* next handler in a linked list */
1235 struct mg_handler_info
*next
;
1239 volatile int stop_flag
; /* Should we stop event loop */
1240 SSL_CTX
*ssl_ctx
; /* SSL context */
1241 char *config
[NUM_OPTIONS
]; /* Civetweb configuration parameters */
1242 struct mg_callbacks callbacks
; /* User-defined callback function */
1243 void *user_data
; /* User-defined data */
1244 int context_type
; /* 1 = server context, 2 = client context */
1246 struct socket
*listening_sockets
;
1247 in_port_t
*listening_ports
;
1248 unsigned int num_listening_sockets
;
1251 running_worker_threads
; /* Number of currently running worker threads */
1252 pthread_mutex_t thread_mutex
; /* Protects (max|num)_threads */
1253 pthread_cond_t thread_cond
; /* Condvar for tracking workers terminations */
1255 struct socket queue
[MGSQLEN
]; /* Accepted sockets */
1256 volatile int sq_head
; /* Head of the socket queue */
1257 volatile int sq_tail
; /* Tail of the socket queue */
1258 pthread_cond_t sq_full
; /* Signaled when socket is produced */
1259 pthread_cond_t sq_empty
; /* Signaled when socket is consumed */
1260 pthread_t masterthreadid
; /* The master thread ID */
1262 cfg_worker_threads
; /* The number of configured worker threads. */
1263 pthread_t
*workerthreadids
; /* The worker thread IDs */
1265 time_t start_time
; /* Server start time, used for authentication */
1266 uint64_t auth_nonce_mask
; /* Mask for all nonce values */
1267 pthread_mutex_t nonce_mutex
; /* Protects nonce_count */
1268 unsigned long nonce_count
; /* Used nonces, used for authentication */
1270 char *systemName
; /* What operating system is running */
1272 /* linked list of uri handlers */
1273 struct mg_handler_info
*handlers
;
1275 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1276 /* linked list of shared lua websockets */
1277 struct mg_shared_lua_websocket_list
*shared_lua_websockets
;
1281 struct ttimers
*timers
;
1286 struct mg_connection
{
1287 struct mg_request_info request_info
;
1288 struct mg_context
*ctx
;
1289 SSL
*ssl
; /* SSL descriptor */
1290 SSL_CTX
*client_ssl_ctx
; /* SSL context for client connections */
1291 struct socket client
; /* Connected client */
1292 time_t conn_birth_time
; /* Time (wall clock) when connection was
1294 struct timespec req_time
; /* Time (since system start) when the request
1296 int64_t num_bytes_sent
; /* Total bytes sent to client */
1297 int64_t content_len
; /* Content-Length header value */
1298 int64_t consumed_content
; /* How many bytes of content have been read */
1299 int is_chunked
; /* Transfer-Encoding is chunked: 0=no, 1=yes:
1300 * data available, 2: all data read */
1301 size_t chunk_remainder
; /* Unread data from the last chunk */
1302 char *buf
; /* Buffer for received data */
1303 char *path_info
; /* PATH_INFO part of the URL */
1305 int must_close
; /* 1 if connection must be closed */
1306 int in_error_handler
; /* 1 if in handler for user defined error
1308 int internal_error
; /* 1 if an error occured while processing the
1311 int buf_size
; /* Buffer size */
1312 int request_len
; /* Size of the request + headers in a buffer */
1313 int data_len
; /* Total size of data in a buffer */
1314 int status_code
; /* HTTP reply status code, e.g. 200 */
1315 int throttle
; /* Throttling, bytes/sec. <= 0 means no
1317 time_t last_throttle_time
; /* Last time throttled data was sent */
1318 int64_t last_throttle_bytes
; /* Bytes sent this second */
1319 pthread_mutex_t mutex
; /* Used by mg_(un)lock_connection to ensure
1320 * atomic transmissions for websockets */
1321 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1322 void *lua_websocket_state
; /* Lua_State for a websocket connection */
1327 static pthread_key_t sTlsKey
; /* Thread local storage index */
1328 static int sTlsInit
= 0;
1329 static int thread_idx_max
= 0;
1332 struct mg_workerTLS
{
1334 unsigned long thread_idx
;
1335 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1336 HANDLE pthread_cond_helper_mutex
;
1340 /* Directory entry */
1342 struct mg_connection
*conn
;
1348 #if defined(USE_WEBSOCKET)
1349 static int is_websocket_protocol(const struct mg_connection
*conn
);
1351 #define is_websocket_protocol(conn) (0)
1356 mg_atomic_inc(volatile int *addr
)
1359 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1360 /* Depending on the SDK, this function uses either
1361 * (volatile unsigned int *) or (volatile LONG *),
1362 * so whatever you use, the other SDK is likely to raise a warning. */
1363 ret
= InterlockedIncrement((volatile long *)addr
);
1364 #elif defined(__GNUC__) \
1365 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1366 ret
= __sync_add_and_fetch(addr
, 1);
1375 mg_atomic_dec(volatile int *addr
)
1378 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1379 /* Depending on the SDK, this function uses either
1380 * (volatile unsigned int *) or (volatile LONG *),
1381 * so whatever you use, the other SDK is likely to raise a warning. */
1382 ret
= InterlockedDecrement((volatile long *)addr
);
1383 #elif defined(__GNUC__) \
1384 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1385 ret
= __sync_sub_and_fetch(addr
, 1);
1392 #if !defined(NO_THREAD_NAME)
1393 #if defined(_WIN32) && defined(_MSC_VER)
1394 /* Set the thread name for debugging purposes in Visual Studio
1395 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
1397 #pragma pack(push, 8)
1398 typedef struct tagTHREADNAME_INFO
{
1399 DWORD dwType
; /* Must be 0x1000. */
1400 LPCSTR szName
; /* Pointer to name (in user addr space). */
1401 DWORD dwThreadID
; /* Thread ID (-1=caller thread). */
1402 DWORD dwFlags
; /* Reserved for future use, must be zero. */
1405 #elif defined(__linux__)
1406 #include <sys/prctl.h>
1407 #include <sys/sendfile.h>
1412 mg_set_thread_name(const char *name
)
1414 char threadName
[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
1417 NULL
, NULL
, threadName
, sizeof(threadName
), "civetweb-%s", name
);
1420 #if defined(_MSC_VER)
1421 /* Windows and Visual Studio Compiler */
1424 THREADNAME_INFO info
;
1425 info
.dwType
= 0x1000;
1426 info
.szName
= threadName
;
1427 info
.dwThreadID
= ~0U;
1430 RaiseException(0x406D1388,
1432 sizeof(info
) / sizeof(ULONG_PTR
),
1433 (ULONG_PTR
*)&info
);
1435 __except(EXCEPTION_EXECUTE_HANDLER
)
1438 #elif defined(__MINGW32__)
1439 /* No option known to set thread name for MinGW */
1441 #elif defined(__GLIBC__) \
1442 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
1443 /* pthread_setname_np first appeared in glibc in version 2.12*/
1444 (void)pthread_setname_np(pthread_self(), threadName
);
1445 #elif defined(__linux__)
1446 /* on linux we can use the old prctl function */
1447 (void)prctl(PR_SET_NAME
, threadName
, 0, 0, 0);
1450 #else /* !defined(NO_THREAD_NAME) */
1452 mg_set_thread_name(const char *threadName
)
1458 #if defined(MG_LEGACY_INTERFACE)
1460 mg_get_valid_option_names(void)
1462 /* This function is deprecated. Use mg_get_valid_options instead. */
1464 data
[2 * sizeof(config_options
) / sizeof(config_options
[0])] = {0};
1467 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
1468 data
[i
* 2] = config_options
[i
].name
;
1469 data
[i
* 2 + 1] = config_options
[i
].default_value
;
1477 const struct mg_option
*
1478 mg_get_valid_options(void)
1480 return config_options
;
1485 is_file_in_memory(const struct mg_connection
*conn
,
1490 if (!conn
|| !filep
) {
1494 if (conn
->ctx
->callbacks
.open_file
) {
1495 filep
->membuf
= conn
->ctx
->callbacks
.open_file(conn
, path
, &size
);
1496 if (filep
->membuf
!= NULL
) {
1497 /* NOTE: override filep->size only on success. Otherwise, it might
1498 * break constructs like if (!mg_stat() || !mg_fopen()) ... */
1503 return filep
->membuf
!= NULL
;
1508 is_file_opened(const struct file
*filep
)
1514 return filep
->membuf
!= NULL
|| filep
->fp
!= NULL
;
1518 /* mg_fopen will open a file either in memory or on the disk.
1519 * The input parameter path is a string in UTF-8 encoding.
1520 * The input parameter mode is the same as for fopen.
1521 * Either fp or membuf will be set in the output struct filep.
1522 * The function returns 1 on success, 0 on error. */
1524 mg_fopen(const struct mg_connection
*conn
,
1535 /* TODO (high): mg_fopen should only open a file, while mg_stat should
1536 * only get the file status. They should not work on different members of
1537 * the same structure (bad cohesion). */
1538 memset(filep
, 0, sizeof(*filep
));
1540 if (stat(path
, &st
) == 0) {
1541 filep
->size
= (uint64_t)(st
.st_size
);
1544 if (!is_file_in_memory(conn
, path
, filep
)) {
1546 wchar_t wbuf
[PATH_MAX
], wmode
[20];
1547 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
1548 MultiByteToWideChar(CP_UTF8
, 0, mode
, -1, wmode
, ARRAY_SIZE(wmode
));
1549 filep
->fp
= _wfopen(wbuf
, wmode
);
1551 /* Linux et al already use unicode. No need to convert. */
1552 filep
->fp
= fopen(path
, mode
);
1556 return is_file_opened(filep
);
1561 mg_fclose(struct file
*filep
)
1563 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
1570 mg_strlcpy(register char *dst
, register const char *src
, size_t n
)
1572 for (; *src
!= '\0' && n
> 1; n
--) {
1580 lowercase(const char *s
)
1582 return tolower(*(const unsigned char *)s
);
1587 mg_strncasecmp(const char *s1
, const char *s2
, size_t len
)
1593 diff
= lowercase(s1
++) - lowercase(s2
++);
1594 } while (diff
== 0 && s1
[-1] != '\0' && --len
> 0);
1602 mg_strcasecmp(const char *s1
, const char *s2
)
1607 diff
= lowercase(s1
++) - lowercase(s2
++);
1608 } while (diff
== 0 && s1
[-1] != '\0');
1615 mg_strndup(const char *ptr
, size_t len
)
1619 if ((p
= (char *)mg_malloc(len
+ 1)) != NULL
) {
1620 mg_strlcpy(p
, ptr
, len
+ 1);
1628 mg_strdup(const char *str
)
1630 return mg_strndup(str
, strlen(str
));
1635 mg_strcasestr(const char *big_str
, const char *small_str
)
1637 size_t i
, big_len
= strlen(big_str
), small_len
= strlen(small_str
);
1639 if (big_len
>= small_len
) {
1640 for (i
= 0; i
<= (big_len
- small_len
); i
++) {
1641 if (mg_strncasecmp(big_str
+ i
, small_str
, small_len
) == 0) {
1651 /* Return null terminated string of given maximum length.
1652 * Report errors if length is exceeded. */
1654 mg_vsnprintf(const struct mg_connection
*conn
,
1668 #pragma clang diagnostic push
1669 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1670 /* Using fmt as a non-literal is intended here, since it is mostly called
1671 * indirectly by mg_snprintf */
1674 n
= (int)vsnprintf_impl(buf
, buflen
, fmt
, ap
);
1675 ok
= (n
>= 0) && ((size_t)n
< buflen
);
1678 #pragma clang diagnostic pop
1690 "truncating vsnprintf buffer: [%.*s]",
1691 (int)((buflen
> 200) ? 200 : (buflen
- 1)),
1693 n
= (int)buflen
- 1;
1700 mg_snprintf(const struct mg_connection
*conn
,
1710 mg_vsnprintf(conn
, truncated
, buf
, buflen
, fmt
, ap
);
1716 get_option_index(const char *name
)
1720 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
1721 if (strcmp(config_options
[i
].name
, name
) == 0) {
1730 mg_get_option(const struct mg_context
*ctx
, const char *name
)
1733 if ((i
= get_option_index(name
)) == -1) {
1735 } else if (!ctx
|| ctx
->config
[i
] == NULL
) {
1738 return ctx
->config
[i
];
1744 mg_get_context(const struct mg_connection
*conn
)
1746 return (conn
== NULL
) ? (struct mg_context
*)NULL
: (conn
->ctx
);
1751 mg_get_user_data(const struct mg_context
*ctx
)
1753 return (ctx
== NULL
) ? NULL
: ctx
->user_data
;
1758 mg_set_user_connection_data(struct mg_connection
*conn
, void *data
)
1761 conn
->request_info
.conn_data
= data
;
1767 mg_get_user_connection_data(const struct mg_connection
*conn
)
1770 return conn
->request_info
.conn_data
;
1777 mg_get_ports(const struct mg_context
*ctx
, size_t size
, int *ports
, int *ssl
)
1783 for (i
= 0; i
< size
&& i
< ctx
->num_listening_sockets
; i
++) {
1784 ssl
[i
] = ctx
->listening_sockets
[i
].is_ssl
;
1785 ports
[i
] = ctx
->listening_ports
[i
];
1792 mg_get_server_ports(const struct mg_context
*ctx
,
1794 struct mg_server_ports
*ports
)
1801 memset(ports
, 0, sizeof(*ports
) * (size_t)size
);
1805 if (!ctx
->listening_sockets
|| !ctx
->listening_ports
) {
1809 for (i
= 0; (i
< size
) && (i
< (int)ctx
->num_listening_sockets
); i
++) {
1811 ports
[cnt
].port
= ctx
->listening_ports
[i
];
1812 ports
[cnt
].is_ssl
= ctx
->listening_sockets
[i
].is_ssl
;
1813 ports
[cnt
].is_redirect
= ctx
->listening_sockets
[i
].ssl_redir
;
1815 if (ctx
->listening_sockets
[i
].lsa
.sa
.sa_family
== AF_INET
) {
1817 ports
[cnt
].protocol
= 1;
1819 } else if (ctx
->listening_sockets
[i
].lsa
.sa
.sa_family
== AF_INET6
) {
1821 ports
[cnt
].protocol
= 3;
1831 sockaddr_to_string(char *buf
, size_t len
, const union usa
*usa
)
1839 if (usa
->sa
.sa_family
== AF_INET
) {
1840 getnameinfo(&usa
->sa
,
1848 #if defined(USE_IPV6)
1849 else if (usa
->sa
.sa_family
== AF_INET6
) {
1850 getnameinfo(&usa
->sa
,
1862 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
1863 * included in all responses other than 100, 101, 5xx. */
1865 gmt_time_string(char *buf
, size_t buf_len
, time_t *t
)
1869 tm
= ((t
!= NULL
) ? gmtime(t
) : NULL
);
1871 strftime(buf
, buf_len
, "%a, %d %b %Y %H:%M:%S GMT", tm
);
1873 mg_strlcpy(buf
, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len
);
1874 buf
[buf_len
- 1] = '\0';
1879 /* difftime for struct timespec. Return value is in seconds. */
1881 mg_difftimespec(const struct timespec
*ts_now
, const struct timespec
*ts_before
)
1883 return (double)(ts_now
->tv_nsec
- ts_before
->tv_nsec
) * 1.0E-9
1884 + (double)(ts_now
->tv_sec
- ts_before
->tv_sec
);
1888 /* Print error message to the opened error log stream. */
1890 mg_cry(const struct mg_connection
*conn
, const char *fmt
, ...)
1892 char buf
[MG_BUF_LEN
], src_addr
[IP_ADDR_STR_LEN
];
1898 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf
, sizeof(buf
), fmt
, ap
));
1900 buf
[sizeof(buf
) - 1] = 0;
1907 /* Do not lock when getting the callback value, here and below.
1908 * I suppose this is fine, since function cannot disappear in the
1909 * same way string option can. */
1910 if ((conn
->ctx
->callbacks
.log_message
== NULL
)
1911 || (conn
->ctx
->callbacks
.log_message(conn
, buf
) == 0)) {
1913 if (conn
->ctx
->config
[ERROR_LOG_FILE
] != NULL
) {
1914 if (mg_fopen(conn
, conn
->ctx
->config
[ERROR_LOG_FILE
], "a+", &fi
)
1922 if (fi
.fp
!= NULL
) {
1924 timestamp
= time(NULL
);
1926 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
1928 "[%010lu] [error] [client %s] ",
1929 (unsigned long)timestamp
,
1932 if (conn
->request_info
.request_method
!= NULL
) {
1935 conn
->request_info
.request_method
,
1936 conn
->request_info
.request_uri
);
1939 fprintf(fi
.fp
, "%s", buf
);
1949 /* Return fake connection structure. Used for logging, if connection
1950 * is not applicable at the moment of logging. */
1951 static struct mg_connection
*
1952 fc(struct mg_context
*ctx
)
1954 static struct mg_connection fake_connection
;
1955 fake_connection
.ctx
= ctx
;
1956 return &fake_connection
;
1963 return CIVETWEB_VERSION
;
1967 const struct mg_request_info
*
1968 mg_get_request_info(const struct mg_connection
*conn
)
1973 return &conn
->request_info
;
1977 /* Skip the characters until one of the delimiters characters found.
1978 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
1979 * Advance pointer to buffer to the next word. Return found 0-terminated word.
1980 * Delimiters can be quoted with quotechar. */
1982 skip_quoted(char **buf
,
1983 const char *delimiters
,
1984 const char *whitespace
,
1987 char *p
, *begin_word
, *end_word
, *end_whitespace
;
1990 end_word
= begin_word
+ strcspn(begin_word
, delimiters
);
1992 /* Check for quotechar */
1993 if (end_word
> begin_word
) {
1995 while (*p
== quotechar
) {
1996 /* While the delimiter is quoted, look for the next delimiter. */
1997 /* This happens, e.g., in calls from parse_auth_header,
1998 * if the user name contains a " character. */
2000 /* If there is anything beyond end_word, copy it. */
2001 if (*end_word
!= '\0') {
2002 size_t end_off
= strcspn(end_word
+ 1, delimiters
);
2003 memmove(p
, end_word
, end_off
+ 1);
2004 p
+= end_off
; /* p must correspond to end_word - 1 */
2005 end_word
+= end_off
+ 1;
2011 for (p
++; p
< end_word
; p
++) {
2016 if (*end_word
== '\0') {
2019 end_whitespace
= end_word
+ 1 + strspn(end_word
+ 1, whitespace
);
2021 for (p
= end_word
; p
< end_whitespace
; p
++) {
2025 *buf
= end_whitespace
;
2032 /* Simplified version of skip_quoted without quote char
2033 * and whitespace == delimiters */
2035 skip(char **buf
, const char *delimiters
)
2037 return skip_quoted(buf
, delimiters
, delimiters
, 0);
2041 /* Return HTTP header value, or NULL if not found. */
2043 get_header(const struct mg_request_info
*ri
, const char *name
)
2047 for (i
= 0; i
< ri
->num_headers
; i
++) {
2048 if (!mg_strcasecmp(name
, ri
->http_headers
[i
].name
)) {
2049 return ri
->http_headers
[i
].value
;
2059 mg_get_header(const struct mg_connection
*conn
, const char *name
)
2065 return get_header(&conn
->request_info
, name
);
2069 /* A helper function for traversing a comma separated list of values.
2070 * It returns a list pointer shifted to the next value, or NULL if the end
2071 * of the list found.
2072 * Value is stored in val vector. If value has form "x=y", then eq_val
2073 * vector is initialized to point to the "y" part, and val vector length
2074 * is adjusted to point only to "x". */
2076 next_option(const char *list
, struct vec
*val
, struct vec
*eq_val
)
2081 if (val
== NULL
|| list
== NULL
|| *list
== '\0') {
2082 /* End of the list */
2085 /* Skip over leading LWS */
2086 while (*list
== ' ' || *list
== '\t')
2090 if ((list
= strchr(val
->ptr
, ',')) != NULL
) {
2091 /* Comma found. Store length and shift the list ptr */
2092 val
->len
= ((size_t)(list
- val
->ptr
));
2095 /* This value is the last one */
2096 list
= val
->ptr
+ strlen(val
->ptr
);
2097 val
->len
= ((size_t)(list
- val
->ptr
));
2100 /* Adjust length for trailing LWS */
2101 end
= (int)val
->len
- 1;
2102 while (end
>= 0 && (val
->ptr
[end
] == ' ' || val
->ptr
[end
] == '\t'))
2104 val
->len
= (size_t)(end
+ 1);
2106 if (val
->len
== 0) {
2107 /* Ignore any empty entries. */
2111 if (eq_val
!= NULL
) {
2112 /* Value has form "x=y", adjust pointers and lengths
2113 * so that val points to "x", and eq_val points to "y". */
2115 eq_val
->ptr
= (const char *)memchr(val
->ptr
, '=', val
->len
);
2116 if (eq_val
->ptr
!= NULL
) {
2117 eq_val
->ptr
++; /* Skip over '=' character */
2118 eq_val
->len
= ((size_t)(val
->ptr
- eq_val
->ptr
)) + val
->len
;
2119 val
->len
= ((size_t)(eq_val
->ptr
- val
->ptr
)) - 1;
2127 /* A helper function for checking if a comma separated list of values contains
2128 * the given option (case insensitvely).
2129 * 'header' can be NULL, in which case false is returned. */
2131 header_has_option(const char *header
, const char *option
)
2136 assert(option
!= NULL
);
2137 assert(option
[0] != '\0');
2139 while ((header
= next_option(header
, &opt_vec
, &eq_vec
)) != NULL
) {
2140 if (mg_strncasecmp(option
, opt_vec
.ptr
, opt_vec
.len
) == 0)
2147 /* Perform case-insensitive match of string against pattern */
2149 match_prefix(const char *pattern
, size_t pattern_len
, const char *str
)
2155 if ((or_str
= (const char *)memchr(pattern
, '|', pattern_len
)) != NULL
) {
2156 res
= match_prefix(pattern
, (size_t)(or_str
- pattern
), str
);
2157 return res
> 0 ? res
: match_prefix(or_str
+ 1,
2158 (size_t)((pattern
+ pattern_len
)
2163 for (i
= 0, j
= 0; i
< pattern_len
; i
++, j
++) {
2164 if (pattern
[i
] == '?' && str
[j
] != '\0') {
2166 } else if (pattern
[i
] == '$') {
2167 return str
[j
] == '\0' ? j
: -1;
2168 } else if (pattern
[i
] == '*') {
2170 if (pattern
[i
] == '*') {
2172 len
= (int)strlen(str
+ j
);
2174 len
= (int)strcspn(str
+ j
, "/");
2176 if (i
== pattern_len
) {
2180 res
= match_prefix(pattern
+ i
, pattern_len
- i
, str
+ j
+ len
);
2181 } while (res
== -1 && len
-- > 0);
2182 return res
== -1 ? -1 : j
+ res
+ len
;
2183 } else if (lowercase(&pattern
[i
]) != lowercase(&str
[j
])) {
2191 /* HTTP 1.1 assumes keep alive if "Connection:" header is not set
2192 * This function must tolerate situations when connection info is not
2193 * set up, for example if request parsing failed. */
2195 should_keep_alive(const struct mg_connection
*conn
)
2198 const char *http_version
= conn
->request_info
.http_version
;
2199 const char *header
= mg_get_header(conn
, "Connection");
2200 if (conn
->must_close
|| conn
->internal_error
|| conn
->status_code
== 401
2201 || mg_strcasecmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes") != 0
2202 || (header
!= NULL
&& !header_has_option(header
, "keep-alive"))
2203 || (header
== NULL
&& http_version
2204 && 0 != strcmp(http_version
, "1.1"))) {
2214 should_decode_url(const struct mg_connection
*conn
)
2216 if (!conn
|| !conn
->ctx
) {
2220 return (mg_strcasecmp(conn
->ctx
->config
[DECODE_URL
], "yes") == 0);
2225 suggest_connection_header(const struct mg_connection
*conn
)
2227 return should_keep_alive(conn
) ? "keep-alive" : "close";
2232 send_no_cache_header(struct mg_connection
*conn
)
2234 /* Send all current and obsolete cache opt-out directives. */
2235 return mg_printf(conn
,
2236 "Cache-Control: no-cache, no-store, "
2237 "must-revalidate, private, max-age=0\r\n"
2238 "Pragma: no-cache\r\n"
2244 send_static_cache_header(struct mg_connection
*conn
)
2246 #if !defined(NO_CACHING)
2247 /* Read the server config to check how long a file may be cached.
2248 * The configuration is in seconds. */
2249 int max_age
= atoi(conn
->ctx
->config
[STATIC_FILE_MAX_AGE
]);
2251 /* 0 means "do not cache". All values <0 are reserved
2252 * and may be used differently in the future. */
2253 /* If a file should not be cached, do not only send
2254 * max-age=0, but also pragmas and Expires headers. */
2255 return send_no_cache_header(conn
);
2258 /* Use "Cache-Control: max-age" instead of "Expires" header.
2259 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
2260 /* See also https://www.mnot.net/cache_docs/ */
2261 /* According to RFC 2616, Section 14.21, caching times should not exceed
2262 * one year. A year with 365 days corresponds to 31536000 seconds, a leap
2263 * year to 31622400 seconds. For the moment, we just send whatever has
2264 * been configured, still the behavior for >1 year should be considered
2266 return mg_printf(conn
, "Cache-Control: max-age=%u\r\n", (unsigned)max_age
);
2267 #else /* NO_CACHING */
2268 return send_no_cache_header(conn
);
2269 #endif /* !NO_CACHING */
2273 static void handle_file_based_request(struct mg_connection
*conn
,
2275 struct file
*filep
);
2278 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
);
2282 mg_get_response_code_text(struct mg_connection
*conn
, int response_code
)
2284 /* See IANA HTTP status code assignment:
2285 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
2288 switch (response_code
) {
2289 /* RFC2616 Section 10.1 - Informational 1xx */
2291 return "Continue"; /* RFC2616 Section 10.1.1 */
2293 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
2295 return "Processing"; /* RFC2518 Section 10.1 */
2297 /* RFC2616 Section 10.2 - Successful 2xx */
2299 return "OK"; /* RFC2616 Section 10.2.1 */
2301 return "Created"; /* RFC2616 Section 10.2.2 */
2303 return "Accepted"; /* RFC2616 Section 10.2.3 */
2305 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
2307 return "No Content"; /* RFC2616 Section 10.2.5 */
2309 return "Reset Content"; /* RFC2616 Section 10.2.6 */
2311 return "Partial Content"; /* RFC2616 Section 10.2.7 */
2313 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */
2315 return "Already Reported"; /* RFC5842 Section 7.1 */
2318 return "IM used"; /* RFC3229 Section 10.4.1 */
2320 /* RFC2616 Section 10.3 - Redirection 3xx */
2322 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
2324 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
2326 return "Found"; /* RFC2616 Section 10.3.3 */
2328 return "See Other"; /* RFC2616 Section 10.3.4 */
2330 return "Not Modified"; /* RFC2616 Section 10.3.5 */
2332 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
2334 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
2336 return "Permanent Redirect"; /* RFC7238 Section 3 */
2338 /* RFC2616 Section 10.4 - Client Error 4xx */
2340 return "Bad Request"; /* RFC2616 Section 10.4.1 */
2342 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
2344 return "Payment Required"; /* RFC2616 Section 10.4.3 */
2346 return "Forbidden"; /* RFC2616 Section 10.4.4 */
2348 return "Not Found"; /* RFC2616 Section 10.4.5 */
2350 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
2352 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
2354 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
2356 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
2358 return "Conflict"; /* RFC2616 Section 10.4.10 */
2360 return "Gone"; /* RFC2616 Section 10.4.11 */
2362 return "Length Required"; /* RFC2616 Section 10.4.12 */
2364 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
2366 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
2368 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
2370 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
2372 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */
2374 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
2377 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
2379 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
2382 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
2384 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
2388 return "Upgrade Required"; /* RFC 2817 Section 4 */
2391 return "Precondition Required"; /* RFC 6585, Section 3 */
2393 return "Too Many Requests"; /* RFC 6585, Section 4 */
2396 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
2399 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
2402 /* RFC2616 Section 10.5 - Server Error 5xx */
2404 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
2406 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
2408 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
2410 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
2412 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
2414 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
2416 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
2418 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
2421 return "Loop Detected"; /* RFC5842 Section 7.1 */
2424 return "Not Extended"; /* RFC 2774, Section 7 */
2426 return "Network Authentication Required"; /* RFC 6585, Section 6 */
2428 /* Other status codes, not shown in the IANA HTTP status code assignment.
2429 * E.g., "de facto" standards due to common use, ... */
2431 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
2433 return "Authentication Timeout"; /* common use */
2435 return "Enhance Your Calm"; /* common use */
2437 return "Login Timeout"; /* common use */
2439 return "Bandwidth Limit Exceeded"; /* common use */
2442 /* This error code is unknown. This should not happen. */
2444 mg_cry(conn
, "Unknown HTTP response code: %u", response_code
);
2447 /* Return at least a category according to RFC 2616 Section 10. */
2448 if (response_code
>= 100 && response_code
< 200) {
2449 /* Unknown informational status code */
2450 return "Information";
2452 if (response_code
>= 200 && response_code
< 300) {
2453 /* Unknown success code */
2456 if (response_code
>= 300 && response_code
< 400) {
2457 /* Unknown redirection code */
2458 return "Redirection";
2460 if (response_code
>= 400 && response_code
< 500) {
2461 /* Unknown request error code */
2462 return "Client Error";
2464 if (response_code
>= 500 && response_code
< 600) {
2465 /* Unknown server error code */
2466 return "Server Error";
2469 /* Response code not even within reasonable range */
2475 static void send_http_error(struct mg_connection
*,
2477 PRINTF_FORMAT_STRING(const char *fmt
),
2478 ...) PRINTF_ARGS(3, 4);
2481 send_http_error(struct mg_connection
*conn
, int status
, const char *fmt
, ...)
2483 char buf
[MG_BUF_LEN
];
2485 int len
, i
, page_handler_found
, scope
, truncated
;
2487 time_t curtime
= time(NULL
);
2488 const char *error_handler
= NULL
;
2489 struct file error_page_file
= STRUCT_FILE_INITIALIZER
;
2490 const char *error_page_file_ext
, *tstr
;
2492 const char *status_text
= mg_get_response_code_text(conn
, status
);
2498 conn
->status_code
= status
;
2499 if (conn
->in_error_handler
|| conn
->ctx
->callbacks
.http_error
== NULL
2500 || conn
->ctx
->callbacks
.http_error(conn
, status
)) {
2501 if (!conn
->in_error_handler
) {
2502 /* Send user defined error pages, if defined */
2503 error_handler
= conn
->ctx
->config
[ERROR_PAGES
];
2504 error_page_file_ext
= conn
->ctx
->config
[INDEX_FILES
];
2505 page_handler_found
= 0;
2506 if (error_handler
!= NULL
) {
2507 for (scope
= 1; (scope
<= 3) && !page_handler_found
; scope
++) {
2509 case 1: /* Handler for specific error, e.g. 404 error */
2518 case 2: /* Handler for error group, e.g., 5xx error handler
2519 * for all server errors (500-599) */
2528 default: /* Handler for all errors */
2538 /* String truncation in buf may only occur if error_handler
2539 * is too long. This string is from the config, not from a
2543 len
= (int)strlen(buf
);
2545 tstr
= strchr(error_page_file_ext
, '.');
2548 for (i
= 1; i
< 32 && tstr
[i
] != 0 && tstr
[i
] != ',';
2550 buf
[len
+ i
- 1] = tstr
[i
];
2551 buf
[len
+ i
- 1] = 0;
2552 if (mg_stat(conn
, buf
, &error_page_file
)) {
2553 page_handler_found
= 1;
2556 tstr
= strchr(tstr
+ i
, '.');
2561 if (page_handler_found
) {
2562 conn
->in_error_handler
= 1;
2563 handle_file_based_request(conn
, buf
, &error_page_file
);
2564 conn
->in_error_handler
= 0;
2569 /* No custom error page. Send default error page. */
2570 gmt_time_string(date
, sizeof(date
), &curtime
);
2572 conn
->must_close
= 1;
2573 mg_printf(conn
, "HTTP/1.1 %d %s\r\n", status
, status_text
);
2574 send_no_cache_header(conn
);
2577 "Connection: close\r\n\r\n",
2580 /* Errors 1xx, 204 and 304 MUST NOT send a body */
2581 if (status
> 199 && status
!= 204 && status
!= 304) {
2583 mg_printf(conn
, "Error %d: %s\n", status
, status_text
);
2587 mg_vsnprintf(conn
, NULL
, buf
, sizeof(buf
), fmt
, ap
);
2589 mg_write(conn
, buf
, strlen(buf
));
2590 DEBUG_TRACE("Error %i - [%s]", status
, buf
);
2594 /* No body allowed. Close the connection. */
2595 DEBUG_TRACE("Error %i", status
);
2600 #if defined(_WIN32) && !defined(__SYMBIAN32__)
2601 /* Create substitutes for POSIX functions in Win32. */
2603 #if defined(__MINGW32__)
2604 /* Show no warning in case system functions are not used. */
2605 #pragma GCC diagnostic push
2606 #pragma GCC diagnostic ignored "-Wunused-function"
2611 pthread_mutex_init(pthread_mutex_t
*mutex
, void *unused
)
2614 *mutex
= CreateMutex(NULL
, FALSE
, NULL
);
2615 return *mutex
== NULL
? -1 : 0;
2620 pthread_mutex_destroy(pthread_mutex_t
*mutex
)
2622 return CloseHandle(*mutex
) == 0 ? -1 : 0;
2627 pthread_mutex_lock(pthread_mutex_t
*mutex
)
2629 return WaitForSingleObject(*mutex
, INFINITE
) == WAIT_OBJECT_0
? 0 : -1;
2633 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
2635 pthread_mutex_trylock(pthread_mutex_t
*mutex
)
2637 switch (WaitForSingleObject(*mutex
, 0)) {
2641 return -2; /* EBUSY */
2649 pthread_mutex_unlock(pthread_mutex_t
*mutex
)
2651 return ReleaseMutex(*mutex
) == 0 ? -1 : 0;
2655 #ifndef WIN_PTHREADS_TIME_H
2657 clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
2663 static double perfcnt_per_sec
= 0.0;
2666 memset(tp
, 0, sizeof(*tp
));
2667 if (clk_id
== CLOCK_REALTIME
) {
2668 GetSystemTimeAsFileTime(&ft
);
2669 li
.LowPart
= ft
.dwLowDateTime
;
2670 li
.HighPart
= ft
.dwHighDateTime
;
2671 li
.QuadPart
-= 116444736000000000; /* 1.1.1970 in filedate */
2672 tp
->tv_sec
= (time_t)(li
.QuadPart
/ 10000000);
2673 tp
->tv_nsec
= (long)(li
.QuadPart
% 10000000) * 100;
2675 } else if (clk_id
== CLOCK_MONOTONIC
) {
2676 if (perfcnt_per_sec
== 0.0) {
2677 QueryPerformanceFrequency((LARGE_INTEGER
*)&li
);
2678 perfcnt_per_sec
= 1.0 / li
.QuadPart
;
2680 if (perfcnt_per_sec
!= 0.0) {
2681 QueryPerformanceCounter((LARGE_INTEGER
*)&li
);
2682 d
= li
.QuadPart
* perfcnt_per_sec
;
2683 tp
->tv_sec
= (time_t)d
;
2685 tp
->tv_nsec
= (long)(d
* 1.0E9
);
2697 pthread_cond_init(pthread_cond_t
*cv
, const void *unused
)
2700 InitializeCriticalSection(&cv
->threadIdSec
);
2701 cv
->waitingthreadcount
= 0;
2702 cv
->waitingthreadhdls
=
2703 (pthread_t
*)mg_calloc(MAX_WORKER_THREADS
, sizeof(pthread_t
));
2704 return (cv
->waitingthreadhdls
!= NULL
) ? 0 : -1;
2709 pthread_cond_timedwait(pthread_cond_t
*cv
,
2710 pthread_mutex_t
*mutex
,
2711 const struct timespec
*abstime
)
2713 struct mg_workerTLS
*tls
=
2714 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
2716 struct timespec tsnow
;
2717 int64_t nsnow
, nswaitabs
, nswaitrel
;
2720 EnterCriticalSection(&cv
->threadIdSec
);
2721 assert(cv
->waitingthreadcount
< MAX_WORKER_THREADS
);
2722 cv
->waitingthreadhdls
[cv
->waitingthreadcount
] =
2723 tls
->pthread_cond_helper_mutex
;
2724 cv
->waitingthreadcount
++;
2725 LeaveCriticalSection(&cv
->threadIdSec
);
2728 clock_gettime(CLOCK_REALTIME
, &tsnow
);
2729 nsnow
= (((int64_t)tsnow
.tv_sec
) * 1000000000) + tsnow
.tv_nsec
;
2731 (((int64_t)abstime
->tv_sec
) * 1000000000) + abstime
->tv_nsec
;
2732 nswaitrel
= nswaitabs
- nsnow
;
2733 if (nswaitrel
< 0) {
2736 mswaitrel
= (DWORD
)(nswaitrel
/ 1000000);
2738 mswaitrel
= INFINITE
;
2741 pthread_mutex_unlock(mutex
);
2743 == WaitForSingleObject(tls
->pthread_cond_helper_mutex
, mswaitrel
));
2744 pthread_mutex_lock(mutex
);
2751 pthread_cond_wait(pthread_cond_t
*cv
, pthread_mutex_t
*mutex
)
2753 return pthread_cond_timedwait(cv
, mutex
, NULL
);
2758 pthread_cond_signal(pthread_cond_t
*cv
)
2764 EnterCriticalSection(&cv
->threadIdSec
);
2765 if (cv
->waitingthreadcount
) {
2766 wkup
= cv
->waitingthreadhdls
[0];
2767 ok
= SetEvent(wkup
);
2769 for (i
= 1; i
< cv
->waitingthreadcount
; i
++) {
2770 cv
->waitingthreadhdls
[i
- 1] = cv
->waitingthreadhdls
[i
];
2772 cv
->waitingthreadcount
--;
2776 LeaveCriticalSection(&cv
->threadIdSec
);
2783 pthread_cond_broadcast(pthread_cond_t
*cv
)
2785 EnterCriticalSection(&cv
->threadIdSec
);
2786 while (cv
->waitingthreadcount
) {
2787 pthread_cond_signal(cv
);
2789 LeaveCriticalSection(&cv
->threadIdSec
);
2796 pthread_cond_destroy(pthread_cond_t
*cv
)
2798 EnterCriticalSection(&cv
->threadIdSec
);
2799 assert(cv
->waitingthreadcount
== 0);
2800 mg_free(cv
->waitingthreadhdls
);
2801 cv
->waitingthreadhdls
= 0;
2802 LeaveCriticalSection(&cv
->threadIdSec
);
2803 DeleteCriticalSection(&cv
->threadIdSec
);
2809 #if defined(__MINGW32__)
2810 /* Enable unused function warning again */
2811 #pragma GCC diagnostic pop
2815 /* For Windows, change all slashes to backslashes in path names. */
2817 change_slashes_to_backslashes(char *path
)
2821 for (i
= 0; path
[i
] != '\0'; i
++) {
2822 if (path
[i
] == '/') {
2826 /* remove double backslash (check i > 0 to preserve UNC paths,
2827 * like \\server\file.txt) */
2828 if ((path
[i
] == '\\') && (i
> 0)) {
2829 while (path
[i
+ 1] == '\\' || path
[i
+ 1] == '/') {
2830 (void)memmove(path
+ i
+ 1, path
+ i
+ 2, strlen(path
+ i
+ 1));
2838 mg_wcscasecmp(const wchar_t *s1
, const wchar_t *s2
)
2843 diff
= tolower(*s1
) - tolower(*s2
);
2846 } while (diff
== 0 && s1
[-1] != '\0');
2852 /* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
2853 * wbuf and wbuf_len is a target buffer and its length. */
2855 path_to_unicode(const struct mg_connection
*conn
,
2860 char buf
[PATH_MAX
], buf2
[PATH_MAX
];
2861 wchar_t wbuf2
[MAX_PATH
+ 1];
2862 DWORD long_len
, err
;
2863 int (*fcompare
)(const wchar_t *, const wchar_t *) = mg_wcscasecmp
;
2865 mg_strlcpy(buf
, path
, sizeof(buf
));
2866 change_slashes_to_backslashes(buf
);
2868 /* Convert to Unicode and back. If doubly-converted string does not
2869 * match the original, something is fishy, reject. */
2870 memset(wbuf
, 0, wbuf_len
* sizeof(wchar_t));
2871 MultiByteToWideChar(CP_UTF8
, 0, buf
, -1, wbuf
, (int)wbuf_len
);
2872 WideCharToMultiByte(
2873 CP_UTF8
, 0, wbuf
, (int)wbuf_len
, buf2
, sizeof(buf2
), NULL
, NULL
);
2874 if (strcmp(buf
, buf2
) != 0) {
2878 /* TODO: Add a configuration to switch between case sensitive and
2879 * case insensitive URIs for Windows server. */
2882 if (conn->ctx->config[WINDOWS_CASE_SENSITIVE]) {
2887 (void)conn
; /* conn is currently unused */
2889 /* Only accept a full file path, not a Windows short (8.3) path. */
2890 memset(wbuf2
, 0, ARRAY_SIZE(wbuf2
) * sizeof(wchar_t));
2891 long_len
= GetLongPathNameW(wbuf
, wbuf2
, ARRAY_SIZE(wbuf2
) - 1);
2892 if (long_len
== 0) {
2893 err
= GetLastError();
2894 if (err
== ERROR_FILE_NOT_FOUND
) {
2895 /* File does not exist. This is not always a problem here. */
2899 if ((long_len
>= ARRAY_SIZE(wbuf2
)) || (fcompare(wbuf
, wbuf2
) != 0)) {
2900 /* Short name is used. */
2906 #if defined(_WIN32_WCE)
2907 /* Create substitutes for POSIX functions in Win32. */
2909 #if defined(__MINGW32__)
2910 /* Show no warning in case system functions are not used. */
2911 #pragma GCC diagnostic push
2912 #pragma GCC diagnostic ignored "-Wunused-function"
2924 SystemTimeToFileTime(&st
, &ft
);
2925 t
= SYS2UNIX_TIME(ft
.dwLowDateTime
, ft
.dwHighDateTime
);
2927 if (ptime
!= NULL
) {
2936 localtime(const time_t *ptime
, struct tm
*ptm
)
2938 int64_t t
= ((int64_t)*ptime
) * RATE_DIFF
+ EPOCH_DIFF
;
2941 TIME_ZONE_INFORMATION tzinfo
;
2947 *(int64_t *)&ft
= t
;
2948 FileTimeToLocalFileTime(&ft
, &lft
);
2949 FileTimeToSystemTime(&lft
, &st
);
2950 ptm
->tm_year
= st
.wYear
- 1900;
2951 ptm
->tm_mon
= st
.wMonth
- 1;
2952 ptm
->tm_wday
= st
.wDayOfWeek
;
2953 ptm
->tm_mday
= st
.wDay
;
2954 ptm
->tm_hour
= st
.wHour
;
2955 ptm
->tm_min
= st
.wMinute
;
2956 ptm
->tm_sec
= st
.wSecond
;
2957 ptm
->tm_yday
= 0; /* hope nobody uses this */
2959 GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_DAYLIGHT
? 1 : 0;
2966 gmtime(const time_t *ptime
, struct tm
*ptm
)
2968 /* FIXME(lsm): fix this. */
2969 return localtime(ptime
, ptm
);
2974 strftime(char *dst
, size_t dst_size
, const char *fmt
, const struct tm
*tm
)
2976 (void)mg_snprintf(NULL
, dst
, dst_size
, "implement strftime() for WinCE");
2981 #if defined(__MINGW32__)
2982 /* Enable unused function warning again */
2983 #pragma GCC diagnostic pop
2989 /* Windows happily opens files with some garbage at the end of file name.
2990 * For example, fopen("a.cgi ", "r") on Windows successfully opens
2991 * "a.cgi", despite one would expect an error back.
2992 * This function returns non-0 if path ends with some garbage. */
2994 path_cannot_disclose_cgi(const char *path
)
2996 static const char *allowed_last_characters
= "_-";
2997 int last
= path
[strlen(path
) - 1];
2998 return isalnum(last
) || strchr(allowed_last_characters
, last
) != NULL
;
3003 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3005 wchar_t wbuf
[PATH_MAX
];
3006 WIN32_FILE_ATTRIBUTE_DATA info
;
3007 time_t creation_time
;
3012 memset(filep
, 0, sizeof(*filep
));
3014 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3015 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
3017 filep
->last_modified
= time(NULL
);
3018 /* last_modified = now ... assumes the file may change during runtime,
3019 * so every mg_fopen call may return different data */
3020 /* last_modified = conn->ctx.start_time;
3021 * May be used it the data does not change during runtime. This allows
3022 * browser caching. Since we do not know, we have to assume the file
3023 * in memory may change. */
3027 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3028 if (GetFileAttributesExW(wbuf
, GetFileExInfoStandard
, &info
) != 0) {
3029 filep
->size
= MAKEUQUAD(info
.nFileSizeLow
, info
.nFileSizeHigh
);
3030 filep
->last_modified
=
3031 SYS2UNIX_TIME(info
.ftLastWriteTime
.dwLowDateTime
,
3032 info
.ftLastWriteTime
.dwHighDateTime
);
3034 /* On Windows, the file creation time can be higher than the
3035 * modification time, e.g. when a file is copied.
3036 * Since the Last-Modified timestamp is used for caching
3037 * it should be based on the most recent timestamp. */
3038 creation_time
= SYS2UNIX_TIME(info
.ftCreationTime
.dwLowDateTime
,
3039 info
.ftCreationTime
.dwHighDateTime
);
3040 if (creation_time
> filep
->last_modified
) {
3041 filep
->last_modified
= creation_time
;
3044 filep
->is_directory
= info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
;
3045 /* If file name is fishy, reset the file structure and return
3047 * Note it is important to reset, not just return the error, cause
3048 * functions like is_file_opened() check the struct. */
3049 if (!filep
->is_directory
&& !path_cannot_disclose_cgi(path
)) {
3050 memset(filep
, 0, sizeof(*filep
));
3062 mg_remove(const struct mg_connection
*conn
, const char *path
)
3064 wchar_t wbuf
[PATH_MAX
];
3065 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3066 return DeleteFileW(wbuf
) ? 0 : -1;
3071 mg_mkdir(const struct mg_connection
*conn
, const char *path
, int mode
)
3073 wchar_t wbuf
[PATH_MAX
];
3075 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3076 return CreateDirectoryW(wbuf
, NULL
) ? 0 : -1;
3080 /* Create substitutes for POSIX functions in Win32. */
3082 #if defined(__MINGW32__)
3083 /* Show no warning in case system functions are not used. */
3084 #pragma GCC diagnostic push
3085 #pragma GCC diagnostic ignored "-Wunused-function"
3089 /* Implementation of POSIX opendir/closedir/readdir for Windows. */
3091 mg_opendir(const struct mg_connection
*conn
, const char *name
)
3094 wchar_t wpath
[PATH_MAX
];
3098 SetLastError(ERROR_BAD_ARGUMENTS
);
3099 } else if ((dir
= (DIR *)mg_malloc(sizeof(*dir
))) == NULL
) {
3100 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3102 path_to_unicode(conn
, name
, wpath
, ARRAY_SIZE(wpath
));
3103 attrs
= GetFileAttributesW(wpath
);
3104 if (attrs
!= 0xFFFFFFFF && ((attrs
& FILE_ATTRIBUTE_DIRECTORY
)
3105 == FILE_ATTRIBUTE_DIRECTORY
)) {
3106 (void)wcscat(wpath
, L
"\\*");
3107 dir
->handle
= FindFirstFileW(wpath
, &dir
->info
);
3108 dir
->result
.d_name
[0] = '\0';
3120 mg_closedir(DIR *dir
)
3125 if (dir
->handle
!= INVALID_HANDLE_VALUE
)
3126 result
= FindClose(dir
->handle
) ? 0 : -1;
3131 SetLastError(ERROR_BAD_ARGUMENTS
);
3138 static struct dirent
*
3139 mg_readdir(DIR *dir
)
3141 struct dirent
*result
= 0;
3144 if (dir
->handle
!= INVALID_HANDLE_VALUE
) {
3145 result
= &dir
->result
;
3146 (void)WideCharToMultiByte(CP_UTF8
,
3148 dir
->info
.cFileName
,
3151 sizeof(result
->d_name
),
3155 if (!FindNextFileW(dir
->handle
, &dir
->info
)) {
3156 (void)FindClose(dir
->handle
);
3157 dir
->handle
= INVALID_HANDLE_VALUE
;
3161 SetLastError(ERROR_FILE_NOT_FOUND
);
3164 SetLastError(ERROR_BAD_ARGUMENTS
);
3173 poll(struct pollfd
*pfd
, unsigned int n
, int milliseconds
)
3181 memset(&tv
, 0, sizeof(tv
));
3182 tv
.tv_sec
= milliseconds
/ 1000;
3183 tv
.tv_usec
= (milliseconds
% 1000) * 1000;
3186 for (i
= 0; i
< n
; i
++) {
3187 FD_SET((SOCKET
)pfd
[i
].fd
, &set
);
3190 if (pfd
[i
].fd
> maxfd
) {
3195 if ((result
= select((int)maxfd
+ 1, &set
, NULL
, NULL
, &tv
)) > 0) {
3196 for (i
= 0; i
< n
; i
++) {
3197 if (FD_ISSET(pfd
[i
].fd
, &set
)) {
3198 pfd
[i
].revents
= POLLIN
;
3205 #endif /* HAVE_POLL */
3207 #if defined(__MINGW32__)
3208 /* Enable unused function warning again */
3209 #pragma GCC diagnostic pop
3214 set_close_on_exec(SOCKET sock
, struct mg_connection
*conn
/* may be null */)
3216 (void)conn
; /* Unused. */
3217 (void)SetHandleInformation((HANDLE
)(intptr_t)sock
, HANDLE_FLAG_INHERIT
, 0);
3222 mg_start_thread(mg_thread_func_t f
, void *p
)
3224 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3225 /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
3227 return ((_beginthread((void(__cdecl
*)(void *))f
, USE_STACK_SIZE
, p
)
3228 == ((uintptr_t)(-1L)))
3233 (_beginthread((void(__cdecl
*)(void *))f
, 0, p
) == ((uintptr_t)(-1L)))
3236 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3240 /* Start a thread storing the thread context. */
3242 mg_start_thread_with_id(unsigned(__stdcall
*f
)(void *),
3244 pthread_t
*threadidptr
)
3247 HANDLE threadhandle
;
3250 uip
= _beginthreadex(NULL
, 0, (unsigned(__stdcall
*)(void *))f
, p
, 0, NULL
);
3251 threadhandle
= (HANDLE
)uip
;
3252 if ((uip
!= (uintptr_t)(-1L)) && (threadidptr
!= NULL
)) {
3253 *threadidptr
= threadhandle
;
3261 /* Wait for a thread to finish. */
3263 mg_join_thread(pthread_t threadid
)
3269 dwevent
= WaitForSingleObject(threadid
, INFINITE
);
3270 if (dwevent
== WAIT_FAILED
) {
3271 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO
);
3273 if (dwevent
== WAIT_OBJECT_0
) {
3274 CloseHandle(threadid
);
3282 #if !defined(NO_SSL_DL)
3283 /* Create substitutes for POSIX functions in Win32. */
3285 #if defined(__MINGW32__)
3286 /* Show no warning in case system functions are not used. */
3287 #pragma GCC diagnostic push
3288 #pragma GCC diagnostic ignored "-Wunused-function"
3293 dlopen(const char *dll_name
, int flags
)
3295 wchar_t wbuf
[PATH_MAX
];
3297 path_to_unicode(NULL
, dll_name
, wbuf
, ARRAY_SIZE(wbuf
));
3298 return LoadLibraryW(wbuf
);
3303 dlclose(void *handle
)
3307 if (FreeLibrary((HMODULE
)handle
) != 0) {
3317 #if defined(__MINGW32__)
3318 /* Enable unused function warning again */
3319 #pragma GCC diagnostic pop
3325 #if !defined(NO_CGI)
3329 kill(pid_t pid
, int sig_num
)
3331 (void)TerminateProcess((HANDLE
)pid
, (UINT
)sig_num
);
3332 (void)CloseHandle((HANDLE
)pid
);
3338 trim_trailing_whitespaces(char *s
)
3340 char *e
= s
+ strlen(s
) - 1;
3341 while (e
> s
&& isspace(*(unsigned char *)e
)) {
3348 spawn_process(struct mg_connection
*conn
,
3358 char *p
, *interp
, full_interp
[PATH_MAX
], full_dir
[PATH_MAX
],
3359 cmdline
[PATH_MAX
], buf
[PATH_MAX
];
3361 struct file file
= STRUCT_FILE_INITIALIZER
;
3363 PROCESS_INFORMATION pi
= {0};
3367 memset(&si
, 0, sizeof(si
));
3370 si
.dwFlags
= STARTF_USESTDHANDLES
| STARTF_USESHOWWINDOW
;
3371 si
.wShowWindow
= SW_HIDE
;
3373 me
= GetCurrentProcess();
3375 (HANDLE
)_get_osfhandle(fdin
[0]),
3380 DUPLICATE_SAME_ACCESS
);
3382 (HANDLE
)_get_osfhandle(fdout
[1]),
3387 DUPLICATE_SAME_ACCESS
);
3389 (HANDLE
)_get_osfhandle(fderr
[1]),
3394 DUPLICATE_SAME_ACCESS
);
3396 /* Mark handles that should not be inherited. See
3397 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
3399 SetHandleInformation((HANDLE
)_get_osfhandle(fdin
[1]),
3400 HANDLE_FLAG_INHERIT
,
3402 SetHandleInformation((HANDLE
)_get_osfhandle(fdout
[0]),
3403 HANDLE_FLAG_INHERIT
,
3405 SetHandleInformation((HANDLE
)_get_osfhandle(fderr
[0]),
3406 HANDLE_FLAG_INHERIT
,
3409 /* If CGI file is a script, try to read the interpreter line */
3410 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3411 if (interp
== NULL
) {
3412 buf
[0] = buf
[1] = '\0';
3414 /* Read the first line of the script into the buffer */
3416 conn
, &truncated
, cmdline
, sizeof(cmdline
), "%s/%s", dir
, prog
);
3419 pi
.hProcess
= (pid_t
)-1;
3423 if (mg_fopen(conn
, cmdline
, "r", &file
)) {
3424 p
= (char *)file
.membuf
;
3425 mg_fgets(buf
, sizeof(buf
), &file
, &p
);
3427 buf
[sizeof(buf
) - 1] = '\0';
3430 if (buf
[0] == '#' && buf
[1] == '!') {
3431 trim_trailing_whitespaces(buf
+ 2);
3438 if (interp
[0] != '\0') {
3439 GetFullPathNameA(interp
, sizeof(full_interp
), full_interp
, NULL
);
3440 interp
= full_interp
;
3442 GetFullPathNameA(dir
, sizeof(full_dir
), full_dir
, NULL
);
3444 if (interp
[0] != '\0') {
3449 "\"%s\" \"%s\\%s\"",
3464 pi
.hProcess
= (pid_t
)-1;
3468 DEBUG_TRACE("Running [%s]", cmdline
);
3469 if (CreateProcessA(NULL
,
3474 CREATE_NEW_PROCESS_GROUP
,
3480 conn
, "%s: CreateProcess(%s): %ld", __func__
, cmdline
, (long)ERRNO
);
3481 pi
.hProcess
= (pid_t
)-1;
3482 /* goto spawn_cleanup; */
3486 (void)CloseHandle(si
.hStdOutput
);
3487 (void)CloseHandle(si
.hStdError
);
3488 (void)CloseHandle(si
.hStdInput
);
3489 if (pi
.hThread
!= NULL
) {
3490 (void)CloseHandle(pi
.hThread
);
3493 return (pid_t
)pi
.hProcess
;
3495 #endif /* !NO_CGI */
3499 set_non_blocking_mode(SOCKET sock
)
3501 unsigned long on
= 1;
3502 return ioctlsocket(sock
, (long)FIONBIO
, &on
);
3508 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3514 memset(filep
, 0, sizeof(*filep
));
3516 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3520 if (0 == stat(path
, &st
)) {
3521 filep
->size
= (uint64_t)(st
.st_size
);
3522 filep
->last_modified
= st
.st_mtime
;
3523 filep
->is_directory
= S_ISDIR(st
.st_mode
);
3532 set_close_on_exec(SOCKET fd
, struct mg_connection
*conn
/* may be null */)
3534 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) != 0) {
3537 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
3546 mg_start_thread(mg_thread_func_t func
, void *param
)
3548 pthread_t thread_id
;
3549 pthread_attr_t attr
;
3552 (void)pthread_attr_init(&attr
);
3553 (void)pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3555 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3556 /* Compile-time option to control stack size,
3557 * e.g. -DUSE_STACK_SIZE=16384 */
3558 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3559 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3561 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3562 pthread_attr_destroy(&attr
);
3568 /* Start a thread storing the thread context. */
3570 mg_start_thread_with_id(mg_thread_func_t func
,
3572 pthread_t
*threadidptr
)
3574 pthread_t thread_id
;
3575 pthread_attr_t attr
;
3578 (void)pthread_attr_init(&attr
);
3580 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3581 /* Compile-time option to control stack size,
3582 * e.g. -DUSE_STACK_SIZE=16384 */
3583 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3584 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
3586 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3587 pthread_attr_destroy(&attr
);
3588 if ((result
== 0) && (threadidptr
!= NULL
)) {
3589 *threadidptr
= thread_id
;
3595 /* Wait for a thread to finish. */
3597 mg_join_thread(pthread_t threadid
)
3601 result
= pthread_join(threadid
, NULL
);
3608 spawn_process(struct mg_connection
*conn
,
3626 if ((pid
= fork()) == -1) {
3628 send_http_error(conn
,
3630 "Error: Creating CGI process\nfork(): %s",
3632 } else if (pid
== 0) {
3634 if (chdir(dir
) != 0) {
3635 mg_cry(conn
, "%s: chdir(%s): %s", __func__
, dir
, strerror(ERRNO
));
3636 } else if (dup2(fdin
[0], 0) == -1) {
3638 "%s: dup2(%d, 0): %s",
3642 } else if (dup2(fdout
[1], 1) == -1) {
3644 "%s: dup2(%d, 1): %s",
3648 } else if (dup2(fderr
[1], 2) == -1) {
3650 "%s: dup2(%d, 2): %s",
3655 /* Keep stderr and stdout in two different pipes.
3656 * Stdout will be sent back to the client,
3657 * stderr should go into a server error log. */
3658 (void)close(fdin
[0]);
3659 (void)close(fdout
[1]);
3660 (void)close(fderr
[1]);
3662 /* Close write end fdin and read end fdout and fderr */
3663 (void)close(fdin
[1]);
3664 (void)close(fdout
[0]);
3665 (void)close(fderr
[0]);
3667 /* After exec, all signal handlers are restored to their default
3668 * values, with one exception of SIGCHLD. According to
3669 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
3670 * leave unchanged after exec if it was set to be ignored. Restore
3671 * it to default action. */
3672 signal(SIGCHLD
, SIG_DFL
);
3674 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3675 if (interp
== NULL
) {
3676 (void)execle(prog
, prog
, NULL
, envp
);
3678 "%s: execle(%s): %s",
3683 (void)execle(interp
, interp
, prog
, NULL
, envp
);
3685 "%s: execle(%s %s): %s",
3697 #endif /* !NO_CGI */
3701 set_non_blocking_mode(SOCKET sock
)
3705 flags
= fcntl(sock
, F_GETFL
, 0);
3706 (void)fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
3711 /* End of initial operating system specific define block. */
3714 /* Get a random number (independent of C rand function) */
3718 static uint64_t lfsr
= 0; /* Linear feedback shift register */
3719 static uint64_t lcg
= 0; /* Linear congruential generator */
3720 struct timespec now
;
3722 memset(&now
, 0, sizeof(now
));
3723 clock_gettime(CLOCK_MONOTONIC
, &now
);
3726 /* lfsr will be only 0 if has not been initialized,
3727 * so this code is called only once. */
3728 lfsr
= (((uint64_t)now
.tv_sec
) << 21) ^ ((uint64_t)now
.tv_nsec
)
3729 ^ ((uint64_t)(ptrdiff_t)&now
) ^ (((uint64_t)time(NULL
)) << 33);
3730 lcg
= (((uint64_t)now
.tv_sec
) << 25) + (uint64_t)now
.tv_nsec
3731 + (uint64_t)(ptrdiff_t)&now
;
3733 /* Get the next step of both random number generators. */
3735 | ((((lfsr
>> 0) ^ (lfsr
>> 1) ^ (lfsr
>> 3) ^ (lfsr
>> 4)) & 1)
3737 lcg
= lcg
* 6364136223846793005 + 1442695040888963407;
3740 /* Combining two pseudo-random number generators and a high resolution part
3741 * of the current server time will make it hard (impossible?) to guess the
3743 return (lfsr
^ lcg
^ (uint64_t)now
.tv_nsec
);
3747 /* Write data to the IO channel - opened file descriptor, socket or SSL
3748 * descriptor. Return number of bytes written. */
3750 push(struct mg_context
*ctx
,
3758 struct timespec start
, now
;
3764 typedef size_t len_t
;
3768 memset(&start
, 0, sizeof(start
));
3769 memset(&now
, 0, sizeof(now
));
3770 clock_gettime(CLOCK_MONOTONIC
, &start
);
3787 n
= SSL_write(ssl
, buf
, len
);
3789 err
= SSL_get_error(ssl
, n
);
3790 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (n
== -1)) {
3793 DEBUG_TRACE("SSL_write() failed, error %d", err
);
3802 n
= (int)fwrite(buf
, 1, (size_t)len
, fp
);
3810 n
= (int)send(sock
, buf
, (len_t
)len
, MSG_NOSIGNAL
);
3811 err
= (n
< 0) ? ERRNO
: 0;
3814 if (ctx
->stop_flag
) {
3818 if ((n
> 0) || (n
== 0 && len
== 0)) {
3819 /* some data has been read, or no data was requested */
3823 /* shutdown of the socket at client side */
3827 /* socket error - check errno */
3828 DEBUG_TRACE("send() failed, error %d", err
);
3830 /* TODO: error handling depending on the error code.
3831 * These codes are different between Windows and Linux.
3836 /* This code is not reached in the moment.
3837 * ==> Fix the TODOs above first. */
3840 clock_gettime(CLOCK_MONOTONIC
, &now
);
3843 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
3845 (void)err
; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
3853 push_all(struct mg_context
*ctx
,
3860 double timeout
= -1.0;
3861 int64_t n
, nwritten
= 0;
3867 if (ctx
->config
[REQUEST_TIMEOUT
]) {
3868 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
3871 while (len
> 0 && ctx
->stop_flag
== 0) {
3872 n
= push(ctx
, fp
, sock
, ssl
, buf
+ nwritten
, (int)len
, timeout
);
3874 if (nwritten
== 0) {
3875 nwritten
= n
; /* Propagate the error */
3878 } else if (n
== 0) {
3879 break; /* No more data to write */
3890 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
3891 * Return negative value on error, or number of bytes read on success. */
3893 pull(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
, double timeout
)
3896 struct timespec start
, now
;
3901 typedef size_t len_t
;
3905 memset(&start
, 0, sizeof(start
));
3906 memset(&now
, 0, sizeof(now
));
3907 clock_gettime(CLOCK_MONOTONIC
, &start
);
3912 /* Use read() instead of fread(), because if we're reading from the
3913 * CGI pipe, fread() may block until IO buffer is filled up. We
3914 * cannot afford to block and must pass all read bytes immediately
3916 nread
= (int)read(fileno(fp
), buf
, (size_t)len
);
3917 err
= (nread
< 0) ? ERRNO
: 0;
3920 } else if (conn
->ssl
!= NULL
) {
3921 nread
= SSL_read(conn
->ssl
, buf
, len
);
3923 err
= SSL_get_error(conn
->ssl
, nread
);
3924 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (nread
== -1)) {
3927 DEBUG_TRACE("SSL_read() failed, error %d", err
);
3936 nread
= (int)recv(conn
->client
.sock
, buf
, (len_t
)len
, 0);
3937 err
= (nread
< 0) ? ERRNO
: 0;
3940 if (conn
->ctx
->stop_flag
) {
3944 if ((nread
> 0) || (nread
== 0 && len
== 0)) {
3945 /* some data has been read, or no data was requested */
3949 /* shutdown of the socket at client side */
3953 /* socket error - check errno */
3955 if (err
== WSAEWOULDBLOCK
) {
3956 /* standard case if called from close_socket_gracefully */
3958 } else if (err
== WSAETIMEDOUT
) {
3959 /* timeout is handled by the while loop */
3961 DEBUG_TRACE("recv() failed, error %d", err
);
3965 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
3966 * if the timeout is reached and if the socket was set to non-
3967 * blocking in close_socket_gracefully, so we can not distinguish
3968 * here. We have to wait for the timeout in both cases for now.
3970 if (err
== EAGAIN
|| err
== EWOULDBLOCK
|| err
== EINTR
) {
3971 /* EAGAIN/EWOULDBLOCK:
3972 * standard case if called from close_socket_gracefully
3973 * => should return -1 */
3974 /* or timeout occured
3975 * => the code must stay in the while loop */
3977 /* EINTR can be generated on a socket with a timeout set even
3978 * when SA_RESTART is effective for all relevant signals
3980 * => stay in the while loop */
3982 DEBUG_TRACE("recv() failed, error %d", err
);
3988 clock_gettime(CLOCK_MONOTONIC
, &now
);
3990 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
3992 /* Timeout occured, but no data available. */
3998 pull_all(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
)
4001 double timeout
= -1.0;
4003 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
4004 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
4007 while (len
> 0 && conn
->ctx
->stop_flag
== 0) {
4008 n
= pull(fp
, conn
, buf
+ nread
, len
, timeout
);
4011 nread
= n
; /* Propagate the error */
4014 } else if (n
== 0) {
4015 break; /* No more data to read */
4017 conn
->consumed_content
+= n
;
4028 discard_unread_request_data(struct mg_connection
*conn
)
4030 char buf
[MG_BUF_LEN
];
4038 to_read
= sizeof(buf
);
4040 if (conn
->is_chunked
) {
4041 /* Chunked encoding: 1=chunk not read completely, 2=chunk read
4043 while (conn
->is_chunked
== 1) {
4044 nread
= mg_read(conn
, buf
, to_read
);
4051 /* Not chunked: content length is known */
4052 while (conn
->consumed_content
< conn
->content_len
) {
4054 > (size_t)(conn
->content_len
- conn
->consumed_content
)) {
4055 to_read
= (size_t)(conn
->content_len
- conn
->consumed_content
);
4058 nread
= mg_read(conn
, buf
, to_read
);
4068 mg_read_inner(struct mg_connection
*conn
, void *buf
, size_t len
)
4070 int64_t n
, buffered_len
, nread
;
4072 (int64_t)(len
> INT_MAX
? INT_MAX
: len
); /* since the return value is
4073 * int, we may not read more
4081 /* If Content-Length is not set for a PUT or POST request, read until
4082 * socket is closed */
4083 if (conn
->consumed_content
== 0 && conn
->content_len
== -1) {
4084 conn
->content_len
= INT64_MAX
;
4085 conn
->must_close
= 1;
4089 if (conn
->consumed_content
< conn
->content_len
) {
4090 /* Adjust number of bytes to read. */
4091 int64_t left_to_read
= conn
->content_len
- conn
->consumed_content
;
4092 if (left_to_read
< len64
) {
4093 /* Do not read more than the total content length of the request.
4095 len64
= left_to_read
;
4098 /* Return buffered data */
4099 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
4100 - conn
->consumed_content
;
4101 if (buffered_len
> 0) {
4102 if (len64
< buffered_len
) {
4103 buffered_len
= len64
;
4105 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
4106 memcpy(buf
, body
, (size_t)buffered_len
);
4107 len64
-= buffered_len
;
4108 conn
->consumed_content
+= buffered_len
;
4109 nread
+= buffered_len
;
4110 buf
= (char *)buf
+ buffered_len
;
4113 /* We have returned all buffered data. Read new data from the remote
4116 if ((n
= pull_all(NULL
, conn
, (char *)buf
, (int)len64
)) >= 0) {
4119 nread
= (nread
> 0 ? nread
: n
);
4127 mg_getc(struct mg_connection
*conn
)
4133 conn
->content_len
++;
4134 if (mg_read_inner(conn
, &c
, 1) <= 0) {
4142 mg_read(struct mg_connection
*conn
, void *buf
, size_t len
)
4144 if (len
> INT_MAX
) {
4152 if (conn
->is_chunked
) {
4153 size_t all_read
= 0;
4157 if (conn
->is_chunked
== 2) {
4158 /* No more data left to read */
4162 if (conn
->chunk_remainder
) {
4163 /* copy from the remainder of the last received chunk */
4166 ((conn
->chunk_remainder
> len
) ? (len
)
4167 : (conn
->chunk_remainder
));
4169 conn
->content_len
+= (int)read_now
;
4171 mg_read_inner(conn
, (char *)buf
+ all_read
, read_now
);
4172 all_read
+= (size_t)read_ret
;
4174 conn
->chunk_remainder
-= read_now
;
4177 if (conn
->chunk_remainder
== 0) {
4178 /* the rest of the data in the current chunk has been read
4180 if ((mg_getc(conn
) != '\r') || (mg_getc(conn
) != '\n')) {
4181 /* Protocol violation */
4187 /* fetch a new chunk */
4191 unsigned long chunkSize
= 0;
4193 for (i
= 0; i
< ((int)sizeof(lenbuf
) - 1); i
++) {
4194 lenbuf
[i
] = mg_getc(conn
);
4195 if (i
> 0 && lenbuf
[i
] == '\r' && lenbuf
[i
- 1] != '\r') {
4198 if (i
> 1 && lenbuf
[i
] == '\n' && lenbuf
[i
- 1] == '\r') {
4200 chunkSize
= strtoul(lenbuf
, &end
, 16);
4201 if (chunkSize
== 0) {
4202 /* regular end of content */
4203 conn
->is_chunked
= 2;
4207 if (!isalnum(lenbuf
[i
])) {
4208 /* illegal character for chunk length */
4212 if ((end
== NULL
) || (*end
!= '\r')) {
4213 /* chunksize not set correctly */
4216 if (chunkSize
== 0) {
4220 conn
->chunk_remainder
= chunkSize
;
4224 return (int)all_read
;
4226 return mg_read_inner(conn
, buf
, len
);
4231 mg_write(struct mg_connection
*conn
, const void *buf
, size_t len
)
4234 int64_t n
, total
, allowed
;
4240 if (conn
->throttle
> 0) {
4241 if ((now
= time(NULL
)) != conn
->last_throttle_time
) {
4242 conn
->last_throttle_time
= now
;
4243 conn
->last_throttle_bytes
= 0;
4245 allowed
= conn
->throttle
- conn
->last_throttle_bytes
;
4246 if (allowed
> (int64_t)len
) {
4247 allowed
= (int64_t)len
;
4249 if ((total
= push_all(conn
->ctx
,
4254 (int64_t)allowed
)) == allowed
) {
4255 buf
= (const char *)buf
+ total
;
4256 conn
->last_throttle_bytes
+= total
;
4257 while (total
< (int64_t)len
&& conn
->ctx
->stop_flag
== 0) {
4258 allowed
= conn
->throttle
> (int64_t)len
- total
4259 ? (int64_t)len
- total
4261 if ((n
= push_all(conn
->ctx
,
4266 (int64_t)allowed
)) != allowed
) {
4270 conn
->last_throttle_bytes
= allowed
;
4271 conn
->last_throttle_time
= time(NULL
);
4272 buf
= (const char *)buf
+ n
;
4277 total
= push_all(conn
->ctx
,
4288 /* Alternative alloc_vprintf() for non-compliant C runtimes */
4290 alloc_vprintf2(char **buf
, const char *fmt
, va_list ap
)
4293 size_t size
= MG_BUF_LEN
/ 4;
4303 *buf
= (char *)mg_malloc(size
);
4308 va_copy(ap_copy
, ap
);
4309 len
= vsnprintf_impl(*buf
, size
- 1, fmt
, ap_copy
);
4311 (*buf
)[size
- 1] = 0;
4318 /* Print message to buffer. If buffer is large enough to hold the message,
4319 * return buffer. If buffer is to small, allocate large enough buffer on heap,
4320 * and return allocated buffer. */
4322 alloc_vprintf(char **out_buf
,
4324 size_t prealloc_size
,
4331 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
4332 * buffer is too small. Also, older versions of msvcrt.dll do not have
4333 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
4334 * Therefore, we make two passes: on first pass, get required message
4336 * On second pass, actually print the message. */
4337 va_copy(ap_copy
, ap
);
4338 len
= vsnprintf_impl(NULL
, 0, fmt
, ap_copy
);
4342 /* C runtime is not standard compliant, vsnprintf() returned -1.
4343 * Switch to alternative code path that uses incremental allocations.
4345 va_copy(ap_copy
, ap
);
4346 len
= alloc_vprintf2(out_buf
, fmt
, ap
);
4349 } else if ((size_t)(len
) >= prealloc_size
) {
4350 /* The pre-allocated buffer not large enough. */
4351 /* Allocate a new buffer. */
4352 *out_buf
= (char *)mg_malloc((size_t)(len
) + 1);
4354 /* Allocation failed. Return -1 as "out of memory" error. */
4357 /* Buffer allocation successful. Store the string there. */
4358 va_copy(ap_copy
, ap
);
4359 IGNORE_UNUSED_RESULT(
4360 vsnprintf_impl(*out_buf
, (size_t)(len
) + 1, fmt
, ap_copy
));
4364 /* The pre-allocated buffer is large enough.
4365 * Use it to store the string and return the address. */
4366 va_copy(ap_copy
, ap
);
4367 IGNORE_UNUSED_RESULT(
4368 vsnprintf_impl(prealloc_buf
, prealloc_size
, fmt
, ap_copy
));
4370 *out_buf
= prealloc_buf
;
4378 mg_vprintf(struct mg_connection
*conn
, const char *fmt
, va_list ap
)
4380 char mem
[MG_BUF_LEN
];
4384 if ((len
= alloc_vprintf(&buf
, mem
, sizeof(mem
), fmt
, ap
)) > 0) {
4385 len
= mg_write(conn
, buf
, (size_t)len
);
4387 if (buf
!= mem
&& buf
!= NULL
) {
4396 mg_printf(struct mg_connection
*conn
, const char *fmt
, ...)
4402 result
= mg_vprintf(conn
, fmt
, ap
);
4410 mg_url_decode(const char *src
,
4414 int is_form_url_encoded
)
4417 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
4419 for (i
= j
= 0; i
< src_len
&& j
< dst_len
- 1; i
++, j
++) {
4420 if (i
< src_len
- 2 && src
[i
] == '%'
4421 && isxdigit(*(const unsigned char *)(src
+ i
+ 1))
4422 && isxdigit(*(const unsigned char *)(src
+ i
+ 2))) {
4423 a
= tolower(*(const unsigned char *)(src
+ i
+ 1));
4424 b
= tolower(*(const unsigned char *)(src
+ i
+ 2));
4425 dst
[j
] = (char)((HEXTOI(a
) << 4) | HEXTOI(b
));
4427 } else if (is_form_url_encoded
&& src
[i
] == '+') {
4434 dst
[j
] = '\0'; /* Null-terminate the destination */
4436 return i
>= src_len
? j
: -1;
4441 mg_get_var(const char *data
,
4447 return mg_get_var2(data
, data_len
, name
, dst
, dst_len
, 0);
4452 mg_get_var2(const char *data
,
4459 const char *p
, *e
, *s
;
4463 if (dst
== NULL
|| dst_len
== 0) {
4465 } else if (data
== NULL
|| name
== NULL
|| data_len
== 0) {
4469 name_len
= strlen(name
);
4470 e
= data
+ data_len
;
4474 /* data is "var1=val1&var2=val2...". Find variable first */
4475 for (p
= data
; p
+ name_len
< e
; p
++) {
4476 if ((p
== data
|| p
[-1] == '&') && p
[name_len
] == '='
4477 && !mg_strncasecmp(name
, p
, name_len
) && 0 == occurrence
--) {
4478 /* Point p to variable value */
4481 /* Point s to the end of the value */
4482 s
= (const char *)memchr(p
, '&', (size_t)(e
- p
));
4486 /* assert(s >= p); */
4491 /* Decode variable into destination buffer */
4492 len
= mg_url_decode(p
, (int)(s
- p
), dst
, (int)dst_len
, 1);
4494 /* Redirect error code from -1 to -2 (destination buffer too
4509 mg_get_cookie(const char *cookie_header
,
4510 const char *var_name
,
4514 const char *s
, *p
, *end
;
4515 int name_len
, len
= -1;
4517 if (dst
== NULL
|| dst_size
== 0) {
4519 } else if (var_name
== NULL
|| (s
= cookie_header
) == NULL
) {
4523 name_len
= (int)strlen(var_name
);
4524 end
= s
+ strlen(s
);
4527 for (; (s
= mg_strcasestr(s
, var_name
)) != NULL
; s
+= name_len
) {
4528 if (s
[name_len
] == '=') {
4530 if ((p
= strchr(s
, ' ')) == NULL
) {
4536 if (*s
== '"' && p
[-1] == '"' && p
> s
+ 1) {
4540 if ((size_t)(p
- s
) < dst_size
) {
4542 mg_strlcpy(dst
, s
, (size_t)len
+ 1);
4554 #if defined(USE_WEBSOCKET) || defined(USE_LUA)
4556 base64_encode(const unsigned char *src
, int src_len
, char *dst
)
4558 static const char *b64
=
4559 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4562 for (i
= j
= 0; i
< src_len
; i
+= 3) {
4564 b
= i
+ 1 >= src_len
? 0 : src
[i
+ 1];
4565 c
= i
+ 2 >= src_len
? 0 : src
[i
+ 2];
4567 dst
[j
++] = b64
[a
>> 2];
4568 dst
[j
++] = b64
[((a
& 3) << 4) | (b
>> 4)];
4569 if (i
+ 1 < src_len
) {
4570 dst
[j
++] = b64
[(b
& 15) << 2 | (c
>> 6)];
4572 if (i
+ 2 < src_len
) {
4573 dst
[j
++] = b64
[c
& 63];
4576 while (j
% 4 != 0) {
4584 #if defined(USE_LUA)
4585 static unsigned char
4586 b64reverse(char letter
)
4588 if (letter
>= 'A' && letter
<= 'Z') {
4589 return letter
- 'A';
4591 if (letter
>= 'a' && letter
<= 'z') {
4592 return letter
- 'a' + 26;
4594 if (letter
>= '0' && letter
<= '9') {
4595 return letter
- '0' + 52;
4597 if (letter
== '+') {
4600 if (letter
== '/') {
4603 if (letter
== '=') {
4604 return 255; /* normal end */
4606 return 254; /* error */
4611 base64_decode(const unsigned char *src
, int src_len
, char *dst
, size_t *dst_len
)
4614 unsigned char a
, b
, c
, d
;
4618 for (i
= 0; i
< src_len
; i
+= 4) {
4619 a
= b64reverse(src
[i
]);
4624 b
= b64reverse(i
+ 1 >= src_len
? 0 : src
[i
+ 1]);
4629 c
= b64reverse(i
+ 2 >= src_len
? 0 : src
[i
+ 2]);
4634 d
= b64reverse(i
+ 3 >= src_len
? 0 : src
[i
+ 3]);
4639 dst
[(*dst_len
)++] = (a
<< 2) + (b
>> 4);
4641 dst
[(*dst_len
)++] = (b
<< 4) + (c
>> 2);
4643 dst
[(*dst_len
)++] = (c
<< 6) + d
;
4653 is_put_or_delete_method(const struct mg_connection
*conn
)
4656 const char *s
= conn
->request_info
.request_method
;
4657 return s
!= NULL
&& (!strcmp(s
, "PUT") || !strcmp(s
, "DELETE")
4658 || !strcmp(s
, "MKCOL") || !strcmp(s
, "PATCH"));
4665 interpret_uri(struct mg_connection
*conn
, /* in: request (must be valid) */
4666 char *filename
, /* out: filename */
4667 size_t filename_buf_len
, /* in: size of filename buffer */
4668 struct file
*filep
, /* out: file structure */
4669 int *is_found
, /* out: file is found (directly) */
4670 int *is_script_resource
, /* out: handled by a script? */
4671 int *is_websocket_request
, /* out: websocket connetion? */
4672 int *is_put_or_delete_request
/* out: put/delete a file? */
4675 /* TODO (high): Restructure this function */
4677 #if !defined(NO_FILES)
4678 const char *uri
= conn
->request_info
.local_uri
;
4679 const char *root
= conn
->ctx
->config
[DOCUMENT_ROOT
];
4680 const char *rewrite
;
4683 char gz_path
[PATH_MAX
];
4684 char const *accept_encoding
;
4686 #if !defined(NO_CGI) || defined(USE_LUA)
4690 (void)filename_buf_len
; /* unused if NO_FILES is defined */
4693 memset(filep
, 0, sizeof(*filep
));
4696 *is_script_resource
= 0;
4697 *is_put_or_delete_request
= is_put_or_delete_method(conn
);
4699 #if defined(USE_WEBSOCKET)
4700 *is_websocket_request
= is_websocket_protocol(conn
);
4701 #if !defined(NO_FILES)
4702 if (*is_websocket_request
&& conn
->ctx
->config
[WEBSOCKET_ROOT
]) {
4703 root
= conn
->ctx
->config
[WEBSOCKET_ROOT
];
4705 #endif /* !NO_FILES */
4706 #else /* USE_WEBSOCKET */
4707 *is_websocket_request
= 0;
4708 #endif /* USE_WEBSOCKET */
4710 #if !defined(NO_FILES)
4711 /* Note that root == NULL is a regular use case here. This occurs,
4712 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
4713 * config is not required. */
4715 /* all file related outputs have already been set to 0, just return
4720 /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
4721 * of the path one byte on the right.
4722 * If document_root is NULL, leave the file empty. */
4724 conn
, &truncated
, filename
, filename_buf_len
- 1, "%s%s", root
, uri
);
4727 goto interpret_cleanup
;
4730 rewrite
= conn
->ctx
->config
[REWRITE
];
4731 while ((rewrite
= next_option(rewrite
, &a
, &b
)) != NULL
) {
4732 if ((match_len
= match_prefix(a
.ptr
, a
.len
, uri
)) > 0) {
4736 filename_buf_len
- 1,
4746 goto interpret_cleanup
;
4749 /* Local file path and name, corresponding to requested URI
4750 * is now stored in "filename" variable. */
4751 if (mg_stat(conn
, filename
, filep
)) {
4752 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4753 /* File exists. Check if it is a script type. */
4755 #if !defined(NO_CGI)
4756 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4757 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4760 #if defined(USE_LUA)
4761 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4762 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4765 #if defined(USE_DUKTAPE)
4766 || match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4768 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4772 /* The request addresses a CGI script or a Lua script. The URI
4773 * corresponds to the script itself (like /path/script.cgi),
4774 * and there is no additional resource path
4775 * (like /path/script.cgi/something).
4776 * Requests that modify (replace or delete) a resource, like
4777 * PUT and DELETE requests, should replace/delete the script
4779 * Requests that read or write from/to a resource, like GET and
4780 * POST requests, should call the script and return the
4781 * generated response. */
4782 *is_script_resource
= !*is_put_or_delete_request
;
4784 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4789 /* If we can't find the actual file, look for the file
4790 * with the same name but a .gz extension. If we find it,
4791 * use that and set the gzipped flag in the file struct
4792 * to indicate that the response need to have the content-
4793 * encoding: gzip header.
4794 * We can only do this if the browser declares support. */
4795 if ((accept_encoding
= mg_get_header(conn
, "Accept-Encoding")) != NULL
) {
4796 if (strstr(accept_encoding
, "gzip") != NULL
) {
4798 conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", filename
);
4801 goto interpret_cleanup
;
4804 if (mg_stat(conn
, gz_path
, filep
)) {
4809 /* Currently gz files can not be scripts. */
4815 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4816 /* Support PATH_INFO for CGI scripts. */
4817 for (p
= filename
+ strlen(filename
); p
> filename
+ 1; p
--) {
4821 #if !defined(NO_CGI)
4822 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4823 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4826 #if defined(USE_LUA)
4827 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4829 conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4832 #if defined(USE_DUKTAPE)
4834 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4835 strlen(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4838 ) && mg_stat(conn
, filename
, filep
)) {
4839 /* Shift PATH_INFO block one character right, e.g.
4840 * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
4841 * conn->path_info is pointing to the local variable "path"
4842 * declared in handle_request(), so PATH_INFO is not valid
4843 * after handle_request returns. */
4844 conn
->path_info
= p
+ 1;
4845 memmove(p
+ 2, p
+ 1, strlen(p
+ 1) + 1); /* +1 is for
4848 *is_script_resource
= 1;
4855 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4856 #endif /* !defined(NO_FILES) */
4859 #if !defined(NO_FILES)
4860 /* Reset all outputs */
4862 memset(filep
, 0, sizeof(*filep
));
4865 *is_script_resource
= 0;
4866 *is_websocket_request
= 0;
4867 *is_put_or_delete_request
= 0;
4868 #endif /* !defined(NO_FILES) */
4872 /* Check whether full request is buffered. Return:
4873 * -1 if request is malformed
4874 * 0 if request is not yet fully buffered
4875 * >0 actual request length, including last \r\n\r\n */
4877 get_request_len(const char *buf
, int buflen
)
4882 for (s
= buf
, e
= s
+ buflen
- 1; len
<= 0 && s
< e
; s
++)
4883 /* Control characters are not allowed but >=128 is. */
4884 if (!isprint(*(const unsigned char *)s
) && *s
!= '\r' && *s
!= '\n'
4885 && *(const unsigned char *)s
< 128) {
4887 break; /* [i_a] abort scan as soon as one malformed character is
4889 /* don't let subsequent \r\n\r\n win us over anyhow */
4890 } else if (s
[0] == '\n' && s
[1] == '\n') {
4891 len
= (int)(s
- buf
) + 2;
4892 } else if (s
[0] == '\n' && &s
[1] < e
&& s
[1] == '\r' && s
[2] == '\n') {
4893 len
= (int)(s
- buf
) + 3;
4900 #if !defined(NO_CACHING)
4901 /* Convert month to the month number. Return -1 on error, or month number */
4903 get_month_index(const char *s
)
4907 for (i
= 0; i
< ARRAY_SIZE(month_names
); i
++) {
4908 if (!strcmp(s
, month_names
[i
])) {
4917 /* Parse UTC date-time string, and return the corresponding time_t value. */
4919 parse_date_string(const char *datetime
)
4921 char month_str
[32] = {0};
4922 int second
, minute
, hour
, day
, month
, year
;
4923 time_t result
= (time_t)0;
4926 if ((sscanf(datetime
,
4927 "%d/%3s/%d %d:%d:%d",
4933 &second
) == 6) || (sscanf(datetime
,
4934 "%d %3s %d %d:%d:%d",
4941 || (sscanf(datetime
,
4942 "%*3s, %d %3s %d %d:%d:%d",
4948 &second
) == 6) || (sscanf(datetime
,
4949 "%d-%3s-%d %d:%d:%d",
4956 month
= get_month_index(month_str
);
4957 if ((month
>= 0) && (year
>= 1970)) {
4958 memset(&tm
, 0, sizeof(tm
));
4959 tm
.tm_year
= year
- 1900;
4965 result
= timegm(&tm
);
4971 #endif /* !NO_CACHING */
4974 /* Protect against directory disclosure attack by removing '..',
4975 * excessive '/' and '\' characters */
4977 remove_double_dots_and_double_slashes(char *s
)
4981 while (*s
!= '\0') {
4983 if (s
[-1] == '/' || s
[-1] == '\\') {
4984 /* Skip all following slashes, backslashes and double-dots */
4985 while (s
[0] != '\0') {
4986 if (s
[0] == '/' || s
[0] == '\\') {
4988 } else if (s
[0] == '.' && s
[1] == '.') {
5000 static const struct {
5001 const char *extension
;
5003 const char *mime_type
;
5004 } builtin_mime_types
[] = {
5005 /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
5006 * application types */
5007 {".doc", 4, "application/msword"},
5008 {".eps", 4, "application/postscript"},
5009 {".exe", 4, "application/octet-stream"},
5010 {".js", 3, "application/javascript"},
5011 {".json", 5, "application/json"},
5012 {".pdf", 4, "application/pdf"},
5013 {".ps", 3, "application/postscript"},
5014 {".rtf", 4, "application/rtf"},
5015 {".xhtml", 6, "application/xhtml+xml"},
5016 {".xsl", 4, "application/xml"},
5017 {".xslt", 5, "application/xml"},
5020 {".ttf", 4, "application/font-sfnt"},
5021 {".cff", 4, "application/font-sfnt"},
5022 {".otf", 4, "application/font-sfnt"},
5023 {".aat", 4, "application/font-sfnt"},
5024 {".sil", 4, "application/font-sfnt"},
5025 {".pfr", 4, "application/font-tdpfr"},
5026 {".woff", 5, "application/font-woff"},
5029 {".mp3", 4, "audio/mpeg"},
5030 {".oga", 4, "audio/ogg"},
5031 {".ogg", 4, "audio/ogg"},
5034 {".gif", 4, "image/gif"},
5035 {".ief", 4, "image/ief"},
5036 {".jpeg", 5, "image/jpeg"},
5037 {".jpg", 4, "image/jpeg"},
5038 {".jpm", 4, "image/jpm"},
5039 {".jpx", 4, "image/jpx"},
5040 {".png", 4, "image/png"},
5041 {".svg", 4, "image/svg+xml"},
5042 {".tif", 4, "image/tiff"},
5043 {".tiff", 5, "image/tiff"},
5046 {".wrl", 4, "model/vrml"},
5049 {".css", 4, "text/css"},
5050 {".csv", 4, "text/csv"},
5051 {".htm", 4, "text/html"},
5052 {".html", 5, "text/html"},
5053 {".sgm", 4, "text/sgml"},
5054 {".shtm", 5, "text/html"},
5055 {".shtml", 6, "text/html"},
5056 {".txt", 4, "text/plain"},
5057 {".xml", 4, "text/xml"},
5060 {".mov", 4, "video/quicktime"},
5061 {".mp4", 4, "video/mp4"},
5062 {".mpeg", 5, "video/mpeg"},
5063 {".mpg", 4, "video/mpeg"},
5064 {".ogv", 4, "video/ogg"},
5065 {".qt", 3, "video/quicktime"},
5067 /* not registered types
5068 * (http://reference.sitepoint.com/html/mime-types-full,
5069 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
5070 {".arj", 4, "application/x-arj-compressed"},
5071 {".gz", 3, "application/x-gunzip"},
5072 {".rar", 4, "application/x-arj-compressed"},
5073 {".swf", 4, "application/x-shockwave-flash"},
5074 {".tar", 4, "application/x-tar"},
5075 {".tgz", 4, "application/x-tar-gz"},
5076 {".torrent", 8, "application/x-bittorrent"},
5077 {".ppt", 4, "application/x-mspowerpoint"},
5078 {".xls", 4, "application/x-msexcel"},
5079 {".zip", 4, "application/x-zip-compressed"},
5082 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
5083 {".aif", 4, "audio/x-aif"},
5084 {".m3u", 4, "audio/x-mpegurl"},
5085 {".mid", 4, "audio/x-midi"},
5086 {".ra", 3, "audio/x-pn-realaudio"},
5087 {".ram", 4, "audio/x-pn-realaudio"},
5088 {".wav", 4, "audio/x-wav"},
5089 {".bmp", 4, "image/bmp"},
5090 {".ico", 4, "image/x-icon"},
5091 {".pct", 4, "image/x-pct"},
5092 {".pict", 5, "image/pict"},
5093 {".rgb", 4, "image/x-rgb"},
5094 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
5095 {".asf", 4, "video/x-ms-asf"},
5096 {".avi", 4, "video/x-msvideo"},
5097 {".m4v", 4, "video/x-m4v"},
5102 mg_get_builtin_mime_type(const char *path
)
5107 path_len
= strlen(path
);
5109 for (i
= 0; builtin_mime_types
[i
].extension
!= NULL
; i
++) {
5110 ext
= path
+ (path_len
- builtin_mime_types
[i
].ext_len
);
5111 if (path_len
> builtin_mime_types
[i
].ext_len
5112 && mg_strcasecmp(ext
, builtin_mime_types
[i
].extension
) == 0) {
5113 return builtin_mime_types
[i
].mime_type
;
5117 return "text/plain";
5121 /* Look at the "path" extension and figure what mime type it has.
5122 * Store mime type in the vector. */
5124 get_mime_type(struct mg_context
*ctx
, const char *path
, struct vec
*vec
)
5126 struct vec ext_vec
, mime_vec
;
5127 const char *list
, *ext
;
5130 path_len
= strlen(path
);
5132 if (ctx
== NULL
|| vec
== NULL
) {
5136 /* Scan user-defined mime types first, in case user wants to
5137 * override default mime types. */
5138 list
= ctx
->config
[EXTRA_MIME_TYPES
];
5139 while ((list
= next_option(list
, &ext_vec
, &mime_vec
)) != NULL
) {
5140 /* ext now points to the path suffix */
5141 ext
= path
+ path_len
- ext_vec
.len
;
5142 if (mg_strncasecmp(ext
, ext_vec
.ptr
, ext_vec
.len
) == 0) {
5148 vec
->ptr
= mg_get_builtin_mime_type(path
);
5149 vec
->len
= strlen(vec
->ptr
);
5153 /* Stringify binary data. Output buffer must be twice as big as input,
5154 * because each byte takes 2 bytes in string representation */
5156 bin2str(char *to
, const unsigned char *p
, size_t len
)
5158 static const char *hex
= "0123456789abcdef";
5160 for (; len
--; p
++) {
5161 *to
++ = hex
[p
[0] >> 4];
5162 *to
++ = hex
[p
[0] & 0x0f];
5168 /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
5170 mg_md5(char buf
[33], ...)
5172 md5_byte_t hash
[16];
5180 while ((p
= va_arg(ap
, const char *)) != NULL
) {
5181 md5_append(&ctx
, (const md5_byte_t
*)p
, strlen(p
));
5185 md5_finish(&ctx
, hash
);
5186 bin2str(buf
, hash
, sizeof(hash
));
5191 /* Check the user's password, return 1 if OK */
5193 check_password(const char *method
,
5200 const char *response
)
5202 char ha2
[32 + 1], expected_response
[32 + 1];
5204 /* Some of the parameters may be NULL */
5205 if (method
== NULL
|| nonce
== NULL
|| nc
== NULL
|| cnonce
== NULL
5207 || response
== NULL
) {
5211 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
5212 if (strlen(response
) != 32) {
5216 mg_md5(ha2
, method
, ":", uri
, NULL
);
5217 mg_md5(expected_response
,
5231 return mg_strcasecmp(response
, expected_response
) == 0;
5235 /* Use the global passwords file, if specified by auth_gpass option,
5236 * or search for .htpasswd in the requested directory. */
5238 open_auth_file(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
5240 if (conn
!= NULL
&& conn
->ctx
!= NULL
) {
5241 char name
[PATH_MAX
];
5242 const char *p
, *e
, *gpass
= conn
->ctx
->config
[GLOBAL_PASSWORDS_FILE
];
5243 struct file file
= STRUCT_FILE_INITIALIZER
;
5246 if (gpass
!= NULL
) {
5247 /* Use global passwords file */
5248 if (!mg_fopen(conn
, gpass
, "r", filep
)) {
5250 mg_cry(conn
, "fopen(%s): %s", gpass
, strerror(ERRNO
));
5253 /* Important: using local struct file to test path for is_directory
5254 * flag. If filep is used, mg_stat() makes it appear as if auth file
5256 } else if (mg_stat(conn
, path
, &file
) && file
.is_directory
) {
5263 PASSWORDS_FILE_NAME
);
5265 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5267 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5271 /* Try to find .htpasswd in requested directory. */
5272 for (p
= path
, e
= p
+ strlen(p
) - 1; e
> p
; e
--) {
5284 PASSWORDS_FILE_NAME
);
5286 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5288 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5296 /* Parsed Authorization header */
5298 char *user
, *uri
, *cnonce
, *response
, *qop
, *nc
, *nonce
;
5302 /* Return 1 on success. Always initializes the ah structure. */
5304 parse_auth_header(struct mg_connection
*conn
,
5309 char *name
, *value
, *s
;
5310 const char *auth_header
;
5317 (void)memset(ah
, 0, sizeof(*ah
));
5318 if ((auth_header
= mg_get_header(conn
, "Authorization")) == NULL
5319 || mg_strncasecmp(auth_header
, "Digest ", 7) != 0) {
5323 /* Make modifiable copy of the auth header */
5324 (void)mg_strlcpy(buf
, auth_header
+ 7, buf_size
);
5327 /* Parse authorization header */
5329 /* Gobble initial spaces */
5330 while (isspace(*(unsigned char *)s
)) {
5333 name
= skip_quoted(&s
, "=", " ", 0);
5334 /* Value is either quote-delimited, or ends at first comma or space. */
5337 value
= skip_quoted(&s
, "\"", " ", '\\');
5342 value
= skip_quoted(&s
, ", ", " ", 0); /* IE uses commas, FF uses
5345 if (*name
== '\0') {
5349 if (!strcmp(name
, "username")) {
5351 } else if (!strcmp(name
, "cnonce")) {
5353 } else if (!strcmp(name
, "response")) {
5354 ah
->response
= value
;
5355 } else if (!strcmp(name
, "uri")) {
5357 } else if (!strcmp(name
, "qop")) {
5359 } else if (!strcmp(name
, "nc")) {
5361 } else if (!strcmp(name
, "nonce")) {
5366 #ifndef NO_NONCE_CHECK
5367 /* Read the nonce from the response. */
5368 if (ah
->nonce
== NULL
) {
5372 nonce
= strtoull(ah
->nonce
, &s
, 10);
5373 if ((s
== NULL
) || (*s
!= 0)) {
5377 /* Convert the nonce from the client to a number. */
5378 nonce
^= conn
->ctx
->auth_nonce_mask
;
5380 /* The converted number corresponds to the time the nounce has been
5381 * created. This should not be earlier than the server start. */
5382 /* Server side nonce check is valuable in all situations but one:
5383 * if the server restarts frequently, but the client should not see
5384 * that, so the server should accept nonces from previous starts. */
5385 /* However, the reasonable default is to not accept a nonce from a
5386 * previous start, so if anyone changed the access rights between
5387 * two restarts, a new login is required. */
5388 if (nonce
< (uint64_t)conn
->ctx
->start_time
) {
5389 /* nonce is from a previous start of the server and no longer valid
5390 * (replay attack?) */
5393 /* Check if the nonce is too high, so it has not (yet) been used by the
5395 if (nonce
>= ((uint64_t)conn
->ctx
->start_time
+ conn
->ctx
->nonce_count
)) {
5400 /* CGI needs it as REMOTE_USER */
5401 if (ah
->user
!= NULL
) {
5402 conn
->request_info
.remote_user
= mg_strdup(ah
->user
);
5412 mg_fgets(char *buf
, size_t size
, struct file
*filep
, char **p
)
5422 if (filep
->membuf
!= NULL
&& *p
!= NULL
) {
5423 memend
= (const char *)&filep
->membuf
[filep
->size
];
5424 /* Search for \n from p till the end of stream */
5425 eof
= (char *)memchr(*p
, '\n', (size_t)(memend
- *p
));
5427 eof
+= 1; /* Include \n */
5429 eof
= memend
; /* Copy remaining data */
5431 len
= (size_t)(eof
- *p
) > size
- 1 ? size
- 1 : (size_t)(eof
- *p
);
5432 memcpy(buf
, *p
, len
);
5435 return len
? eof
: NULL
;
5436 } else if (filep
->fp
!= NULL
) {
5437 return fgets(buf
, (int)size
, filep
->fp
);
5443 struct read_auth_file_struct
{
5444 struct mg_connection
*conn
;
5447 char buf
[256 + 256 + 40];
5455 read_auth_file(struct file
*filep
, struct read_auth_file_struct
*workdata
)
5458 int is_authorized
= 0;
5462 if (!filep
|| !workdata
) {
5466 /* Loop over passwords file */
5467 p
= (char *)filep
->membuf
;
5468 while (mg_fgets(workdata
->buf
, sizeof(workdata
->buf
), filep
, &p
) != NULL
) {
5469 l
= strlen(workdata
->buf
);
5471 if (isspace(workdata
->buf
[l
- 1])
5472 || iscntrl(workdata
->buf
[l
- 1])) {
5474 workdata
->buf
[l
] = 0;
5482 workdata
->f_user
= workdata
->buf
;
5484 if (workdata
->f_user
[0] == ':') {
5485 /* user names may not contain a ':' and may not be empty,
5486 * so lines starting with ':' may be used for a special purpose */
5487 if (workdata
->f_user
[1] == '#') {
5488 /* :# is a comment */
5490 } else if (!strncmp(workdata
->f_user
+ 1, "include=", 8)) {
5491 if (mg_fopen(workdata
->conn
, workdata
->f_user
+ 9, "r", &fp
)) {
5492 is_authorized
= read_auth_file(&fp
, workdata
);
5495 mg_cry(workdata
->conn
,
5496 "%s: cannot open authorization file: %s",
5502 /* everything is invalid for the moment (might change in the
5504 mg_cry(workdata
->conn
,
5505 "%s: syntax error in authorization file: %s",
5511 workdata
->f_domain
= strchr(workdata
->f_user
, ':');
5512 if (workdata
->f_domain
== NULL
) {
5513 mg_cry(workdata
->conn
,
5514 "%s: syntax error in authorization file: %s",
5519 *(workdata
->f_domain
) = 0;
5520 (workdata
->f_domain
)++;
5522 workdata
->f_ha1
= strchr(workdata
->f_domain
, ':');
5523 if (workdata
->f_ha1
== NULL
) {
5524 mg_cry(workdata
->conn
,
5525 "%s: syntax error in authorization file: %s",
5530 *(workdata
->f_ha1
) = 0;
5531 (workdata
->f_ha1
)++;
5533 if (!strcmp(workdata
->ah
.user
, workdata
->f_user
)
5534 && !strcmp(workdata
->domain
, workdata
->f_domain
)) {
5535 return check_password(workdata
->conn
->request_info
.request_method
,
5540 workdata
->ah
.cnonce
,
5542 workdata
->ah
.response
);
5546 return is_authorized
;
5550 /* Authorize against the opened passwords file. Return 1 if authorized. */
5552 authorize(struct mg_connection
*conn
, struct file
*filep
)
5554 struct read_auth_file_struct workdata
;
5555 char buf
[MG_BUF_LEN
];
5557 if (!conn
|| !conn
->ctx
) {
5561 memset(&workdata
, 0, sizeof(workdata
));
5562 workdata
.conn
= conn
;
5564 if (!parse_auth_header(conn
, buf
, sizeof(buf
), &workdata
.ah
)) {
5567 workdata
.domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
5569 return read_auth_file(filep
, &workdata
);
5573 /* Return 1 if request is authorised, 0 otherwise. */
5575 check_authorization(struct mg_connection
*conn
, const char *path
)
5577 char fname
[PATH_MAX
];
5578 struct vec uri_vec
, filename_vec
;
5580 struct file file
= STRUCT_FILE_INITIALIZER
;
5581 int authorized
= 1, truncated
;
5583 if (!conn
|| !conn
->ctx
) {
5587 list
= conn
->ctx
->config
[PROTECT_URI
];
5588 while ((list
= next_option(list
, &uri_vec
, &filename_vec
)) != NULL
) {
5589 if (!memcmp(conn
->request_info
.local_uri
, uri_vec
.ptr
, uri_vec
.len
)) {
5595 (int)filename_vec
.len
,
5598 if (truncated
|| !mg_fopen(conn
, fname
, "r", &file
)) {
5600 "%s: cannot open %s: %s",
5609 if (!is_file_opened(&file
)) {
5610 open_auth_file(conn
, path
, &file
);
5613 if (is_file_opened(&file
)) {
5614 authorized
= authorize(conn
, &file
);
5623 send_authorization_request(struct mg_connection
*conn
)
5626 time_t curtime
= time(NULL
);
5628 if (conn
&& conn
->ctx
) {
5629 uint64_t nonce
= (uint64_t)(conn
->ctx
->start_time
);
5631 (void)pthread_mutex_lock(&conn
->ctx
->nonce_mutex
);
5632 nonce
+= conn
->ctx
->nonce_count
;
5633 ++conn
->ctx
->nonce_count
;
5634 (void)pthread_mutex_unlock(&conn
->ctx
->nonce_mutex
);
5636 nonce
^= conn
->ctx
->auth_nonce_mask
;
5637 conn
->status_code
= 401;
5638 conn
->must_close
= 1;
5640 gmt_time_string(date
, sizeof(date
), &curtime
);
5642 mg_printf(conn
, "HTTP/1.1 401 Unauthorized\r\n");
5643 send_no_cache_header(conn
);
5646 "Connection: %s\r\n"
5647 "Content-Length: 0\r\n"
5648 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
5649 "nonce=\"%" UINT64_FMT
"\"\r\n\r\n",
5651 suggest_connection_header(conn
),
5652 conn
->ctx
->config
[AUTHENTICATION_DOMAIN
],
5658 #if !defined(NO_FILES)
5660 is_authorized_for_put(struct mg_connection
*conn
)
5663 struct file file
= STRUCT_FILE_INITIALIZER
;
5664 const char *passfile
= conn
->ctx
->config
[PUT_DELETE_PASSWORDS_FILE
];
5667 if (passfile
!= NULL
&& mg_fopen(conn
, passfile
, "r", &file
)) {
5668 ret
= authorize(conn
, &file
);
5680 mg_modify_passwords_file(const char *fname
,
5686 char line
[512], u
[512] = "", d
[512] = "", ha1
[33], tmp
[PATH_MAX
+ 8];
5692 /* Regard empty password as no password - remove user record. */
5693 if (pass
!= NULL
&& pass
[0] == '\0') {
5697 /* Other arguments must not be empty */
5698 if (fname
== NULL
|| domain
== NULL
|| user
== NULL
) {
5702 /* Using the given file format, user name and domain must not contain ':'
5704 if (strchr(user
, ':') != NULL
) {
5707 if (strchr(domain
, ':') != NULL
) {
5711 /* Do not allow control characters like newline in user name and domain.
5712 * Do not allow excessively long names either. */
5713 for (i
= 0; i
< 255 && user
[i
] != 0; i
++) {
5714 if (iscntrl(user
[i
])) {
5721 for (i
= 0; i
< 255 && domain
[i
] != 0; i
++) {
5722 if (iscntrl(domain
[i
])) {
5730 /* The maximum length of the path to the password file is limited */
5731 if ((strlen(fname
) + 4) >= PATH_MAX
) {
5735 /* Create a temporary file name. Length has been checked before. */
5737 strcat(tmp
, ".tmp");
5739 /* Create the file if does not exist */
5740 /* Use of fopen here is OK, since fname is only ASCII */
5741 if ((fp
= fopen(fname
, "a+")) != NULL
) {
5745 /* Open the given file and temporary file */
5746 if ((fp
= fopen(fname
, "r")) == NULL
) {
5748 } else if ((fp2
= fopen(tmp
, "w+")) == NULL
) {
5753 /* Copy the stuff to temporary file */
5754 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
5755 if (sscanf(line
, "%255[^:]:%255[^:]:%*s", u
, d
) != 2) {
5761 if (!strcmp(u
, user
) && !strcmp(d
, domain
)) {
5764 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5765 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5768 fprintf(fp2
, "%s", line
);
5772 /* If new user, just add it */
5773 if (!found
&& pass
!= NULL
) {
5774 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5775 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5782 /* Put the temp file in place of real file */
5783 IGNORE_UNUSED_RESULT(remove(fname
));
5784 IGNORE_UNUSED_RESULT(rename(tmp
, fname
));
5791 is_valid_port(unsigned long port
)
5793 return port
< 0xffff;
5798 mg_inet_pton(int af
, const char *src
, void *dst
, size_t dstlen
)
5800 struct addrinfo hints
, *res
, *ressave
;
5804 memset(&hints
, 0, sizeof(struct addrinfo
));
5805 hints
.ai_family
= af
;
5807 gai_ret
= getaddrinfo(src
, NULL
, &hints
, &res
);
5809 /* gai_strerror could be used to convert gai_ret to a string */
5810 /* POSIX return values: see
5811 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
5813 /* Windows return values: see
5814 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
5822 if (dstlen
>= res
->ai_addrlen
) {
5823 memcpy(dst
, res
->ai_addr
, res
->ai_addrlen
);
5829 freeaddrinfo(ressave
);
5835 connect_socket(struct mg_context
*ctx
/* may be NULL */,
5841 SOCKET
*sock
/* output: socket, must not be NULL */,
5842 union usa
*sa
/* output: socket address, must not be NULL */
5846 *sock
= INVALID_SOCKET
;
5847 memset(sa
, 0, sizeof(*sa
));
5855 NULL
, /* No truncation check for ebuf */
5863 if (port
< 0 || !is_valid_port((unsigned)port
)) {
5865 NULL
, /* No truncation check for ebuf */
5873 if (use_ssl
&& (SSLv23_client_method
== NULL
)) {
5875 NULL
, /* No truncation check for ebuf */
5879 "SSL is not initialized");
5883 if (mg_inet_pton(AF_INET
, host
, &sa
->sin
, sizeof(sa
->sin
))) {
5884 sa
->sin
.sin_port
= htons((uint16_t)port
);
5887 } else if (mg_inet_pton(AF_INET6
, host
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5888 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5890 } else if (host
[0] == '[') {
5891 /* While getaddrinfo on Windows will work with [::1],
5892 * getaddrinfo on Linux only works with ::1 (without []). */
5893 size_t l
= strlen(host
+ 1);
5894 char *h
= l
> 1 ? mg_strdup(host
+ 1) : NULL
;
5897 if (mg_inet_pton(AF_INET6
, h
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5898 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5908 NULL
, /* No truncation check for ebuf */
5917 *sock
= socket(PF_INET
, SOCK_STREAM
, 0);
5920 else if (ip_ver
== 6) {
5921 *sock
= socket(PF_INET6
, SOCK_STREAM
, 0);
5925 if (*sock
== INVALID_SOCKET
) {
5927 NULL
, /* No truncation check for ebuf */
5935 set_close_on_exec(*sock
, fc(ctx
));
5938 && (connect(*sock
, (struct sockaddr
*)&sa
->sin
, sizeof(sa
->sin
))
5940 /* connected with IPv4 */
5946 && (connect(*sock
, (struct sockaddr
*)&sa
->sin6
, sizeof(sa
->sin6
))
5948 /* connected with IPv6 */
5955 NULL
, /* No truncation check for ebuf */
5958 "connect(%s:%d): %s",
5963 *sock
= INVALID_SOCKET
;
5969 mg_url_encode(const char *src
, char *dst
, size_t dst_len
)
5971 static const char *dont_escape
= "._-$,;~()";
5972 static const char *hex
= "0123456789abcdef";
5974 const char *end
= dst
+ dst_len
- 1;
5976 for (; *src
!= '\0' && pos
< end
; src
++, pos
++) {
5977 if (isalnum(*(const unsigned char *)src
)
5978 || strchr(dont_escape
, *(const unsigned char *)src
) != NULL
) {
5980 } else if (pos
+ 2 < end
) {
5982 pos
[1] = hex
[(*(const unsigned char *)src
) >> 4];
5983 pos
[2] = hex
[(*(const unsigned char *)src
) & 0xf];
5991 return (*src
== '\0') ? (int)(pos
- dst
) : -1;
5996 print_dir_entry(struct de
*de
)
5998 char size
[64], mod
[64], href
[PATH_MAX
];
6001 if (de
->file
.is_directory
) {
6002 mg_snprintf(de
->conn
,
6003 NULL
, /* Buffer is big enough */
6009 /* We use (signed) cast below because MSVC 6 compiler cannot
6010 * convert unsigned __int64 to double. Sigh. */
6011 if (de
->file
.size
< 1024) {
6012 mg_snprintf(de
->conn
,
6013 NULL
, /* Buffer is big enough */
6017 (int)de
->file
.size
);
6018 } else if (de
->file
.size
< 0x100000) {
6019 mg_snprintf(de
->conn
,
6020 NULL
, /* Buffer is big enough */
6024 (double)de
->file
.size
/ 1024.0);
6025 } else if (de
->file
.size
< 0x40000000) {
6026 mg_snprintf(de
->conn
,
6027 NULL
, /* Buffer is big enough */
6031 (double)de
->file
.size
/ 1048576);
6033 mg_snprintf(de
->conn
,
6034 NULL
, /* Buffer is big enough */
6038 (double)de
->file
.size
/ 1073741824);
6042 /* Note: mg_snprintf will not cause a buffer overflow above.
6043 * So, string truncation checks are not required here. */
6045 tm
= localtime(&de
->file
.last_modified
);
6047 strftime(mod
, sizeof(mod
), "%d-%b-%Y %H:%M", tm
);
6049 mg_strlcpy(mod
, "01-Jan-1970 00:00", sizeof(mod
));
6050 mod
[sizeof(mod
) - 1] = '\0';
6052 mg_url_encode(de
->file_name
, href
, sizeof(href
));
6053 de
->conn
->num_bytes_sent
+=
6055 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
6056 "<td> %s</td><td> %s</td></tr>\n",
6057 de
->conn
->request_info
.local_uri
,
6059 de
->file
.is_directory
? "/" : "",
6061 de
->file
.is_directory
? "/" : "",
6067 /* This function is called from send_directory() and used for
6068 * sorting directory entries by size, or name, or modification time.
6069 * On windows, __cdecl specification is needed in case if project is built
6070 * with __stdcall convention. qsort always requires __cdels callback. */
6072 compare_dir_entries(const void *p1
, const void *p2
)
6075 const struct de
*a
= (const struct de
*)p1
, *b
= (const struct de
*)p2
;
6076 const char *query_string
= a
->conn
->request_info
.query_string
;
6079 if (query_string
== NULL
) {
6080 query_string
= "na";
6083 if (a
->file
.is_directory
&& !b
->file
.is_directory
) {
6084 return -1; /* Always put directories on top */
6085 } else if (!a
->file
.is_directory
&& b
->file
.is_directory
) {
6086 return 1; /* Always put directories on top */
6087 } else if (*query_string
== 'n') {
6088 cmp_result
= strcmp(a
->file_name
, b
->file_name
);
6089 } else if (*query_string
== 's') {
6090 cmp_result
= a
->file
.size
== b
->file
.size
6092 : a
->file
.size
> b
->file
.size
? 1 : -1;
6093 } else if (*query_string
== 'd') {
6095 (a
->file
.last_modified
== b
->file
.last_modified
)
6097 : ((a
->file
.last_modified
> b
->file
.last_modified
) ? 1
6101 return query_string
[1] == 'd' ? -cmp_result
: cmp_result
;
6108 must_hide_file(struct mg_connection
*conn
, const char *path
)
6110 if (conn
&& conn
->ctx
) {
6111 const char *pw_pattern
= "**" PASSWORDS_FILE_NAME
"$";
6112 const char *pattern
= conn
->ctx
->config
[HIDE_FILES
];
6113 return match_prefix(pw_pattern
, strlen(pw_pattern
), path
) > 0
6115 && match_prefix(pattern
, strlen(pattern
), path
) > 0);
6122 scan_directory(struct mg_connection
*conn
,
6125 void (*cb
)(struct de
*, void *))
6127 char path
[PATH_MAX
];
6133 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6138 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6139 /* Do not show current dir and hidden files */
6140 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")
6141 || must_hide_file(conn
, dp
->d_name
)) {
6146 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6148 /* If we don't memset stat structure to zero, mtime will have
6149 * garbage and strftime() will segfault later on in
6150 * print_dir_entry(). memset is required only if mg_stat()
6151 * fails. For more details, see
6152 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6153 memset(&de
.file
, 0, sizeof(de
.file
));
6156 /* If the path is not complete, skip processing. */
6160 if (!mg_stat(conn
, path
, &de
.file
)) {
6162 "%s: mg_stat(%s) failed: %s",
6167 de
.file_name
= dp
->d_name
;
6170 (void)mg_closedir(dirp
);
6176 #if !defined(NO_FILES)
6178 remove_directory(struct mg_connection
*conn
, const char *dir
)
6180 char path
[PATH_MAX
];
6187 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6192 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6193 /* Do not show current dir (but show hidden files as they will
6194 * also be removed) */
6195 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")) {
6200 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6202 /* If we don't memset stat structure to zero, mtime will have
6203 * garbage and strftime() will segfault later on in
6204 * print_dir_entry(). memset is required only if mg_stat()
6205 * fails. For more details, see
6206 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6207 memset(&de
.file
, 0, sizeof(de
.file
));
6210 /* Do not delete anything shorter */
6215 if (!mg_stat(conn
, path
, &de
.file
)) {
6217 "%s: mg_stat(%s) failed: %s",
6223 if (de
.file
.membuf
== NULL
) {
6224 /* file is not in memory */
6225 if (de
.file
.is_directory
) {
6226 if (remove_directory(conn
, path
) == 0) {
6230 if (mg_remove(conn
, path
) == 0) {
6235 /* file is in memory. It can not be deleted. */
6239 (void)mg_closedir(dirp
);
6241 IGNORE_UNUSED_RESULT(rmdir(dir
));
6249 struct dir_scan_data
{
6251 unsigned int num_entries
;
6252 unsigned int arr_size
;
6256 /* Behaves like realloc(), but frees original pointer on failure */
6258 realloc2(void *ptr
, size_t size
)
6260 void *new_ptr
= mg_realloc(ptr
, size
);
6261 if (new_ptr
== NULL
) {
6269 dir_scan_callback(struct de
*de
, void *data
)
6271 struct dir_scan_data
*dsd
= (struct dir_scan_data
*)data
;
6273 if (dsd
->entries
== NULL
|| dsd
->num_entries
>= dsd
->arr_size
) {
6276 (struct de
*)realloc2(dsd
->entries
,
6277 dsd
->arr_size
* sizeof(dsd
->entries
[0]));
6279 if (dsd
->entries
== NULL
) {
6280 /* TODO(lsm, low): propagate an error to the caller */
6281 dsd
->num_entries
= 0;
6283 dsd
->entries
[dsd
->num_entries
].file_name
= mg_strdup(de
->file_name
);
6284 dsd
->entries
[dsd
->num_entries
].file
= de
->file
;
6285 dsd
->entries
[dsd
->num_entries
].conn
= de
->conn
;
6292 handle_directory_request(struct mg_connection
*conn
, const char *dir
)
6296 struct dir_scan_data data
= {NULL
, 0, 128};
6298 time_t curtime
= time(NULL
);
6300 if (!scan_directory(conn
, dir
, &data
, dir_scan_callback
)) {
6301 send_http_error(conn
,
6303 "Error: Cannot open directory\nopendir(%s): %s",
6309 gmt_time_string(date
, sizeof(date
), &curtime
);
6315 sort_direction
= conn
->request_info
.query_string
!= NULL
6316 && conn
->request_info
.query_string
[1] == 'd'
6320 conn
->must_close
= 1;
6321 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
6322 send_static_cache_header(conn
);
6325 "Connection: close\r\n"
6326 "Content-Type: text/html; charset=utf-8\r\n\r\n",
6329 conn
->num_bytes_sent
+=
6331 "<html><head><title>Index of %s</title>"
6332 "<style>th {text-align: left;}</style></head>"
6333 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
6334 "<tr><th><a href=\"?n%c\">Name</a></th>"
6335 "<th><a href=\"?d%c\">Modified</a></th>"
6336 "<th><a href=\"?s%c\">Size</a></th></tr>"
6337 "<tr><td colspan=\"3\"><hr></td></tr>",
6338 conn
->request_info
.local_uri
,
6339 conn
->request_info
.local_uri
,
6344 /* Print first entry - link to a parent directory */
6345 conn
->num_bytes_sent
+=
6347 "<tr><td><a href=\"%s%s\">%s</a></td>"
6348 "<td> %s</td><td> %s</td></tr>\n",
6349 conn
->request_info
.local_uri
,
6355 /* Sort and print directory entries */
6356 if (data
.entries
!= NULL
) {
6358 (size_t)data
.num_entries
,
6359 sizeof(data
.entries
[0]),
6360 compare_dir_entries
);
6361 for (i
= 0; i
< data
.num_entries
; i
++) {
6362 print_dir_entry(&data
.entries
[i
]);
6363 mg_free(data
.entries
[i
].file_name
);
6365 mg_free(data
.entries
);
6368 conn
->num_bytes_sent
+= mg_printf(conn
, "%s", "</table></body></html>");
6369 conn
->status_code
= 200;
6373 /* Send len bytes from the opened file to the client. */
6375 send_file_data(struct mg_connection
*conn
,
6380 char buf
[MG_BUF_LEN
];
6381 int to_read
, num_read
, num_written
;
6384 if (!filep
|| !conn
) {
6388 /* Sanity check the offset */
6389 size
= filep
->size
> INT64_MAX
? INT64_MAX
: (int64_t)(filep
->size
);
6390 offset
= offset
< 0 ? 0 : offset
> size
? size
: offset
;
6392 if (len
> 0 && filep
->membuf
!= NULL
&& size
> 0) {
6393 /* file stored in memory */
6394 if (len
> size
- offset
) {
6395 len
= size
- offset
;
6397 mg_write(conn
, filep
->membuf
+ offset
, (size_t)len
);
6398 } else if (len
> 0 && filep
->fp
!= NULL
) {
6399 /* file stored on disk */
6400 #if defined(__linux__)
6401 /* sendfile is only available for Linux */
6402 if (conn
->throttle
== 0 && conn
->ssl
== 0) {
6403 off_t sf_offs
= (off_t
)offset
;
6405 int sf_file
= fileno(filep
->fp
);
6409 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
6410 * 64 bit Linux (2^31 minus one memory page of 4k?). */
6412 (size_t)((len
< 0x7FFFF000) ? len
: 0x7FFFF000);
6414 sendfile(conn
->client
.sock
, sf_file
, &sf_offs
, sf_tosend
);
6416 conn
->num_bytes_sent
+= sf_sent
;
6419 } else if (loop_cnt
== 0) {
6420 /* This file can not be sent using sendfile.
6421 * This might be the case for pseudo-files in the
6422 * /sys/ and /proc/ file system.
6423 * Use the regular user mode copy code instead. */
6425 } else if (sf_sent
== 0) {
6426 /* No error, but 0 bytes sent. May be EOF? */
6431 } while ((len
> 0) && (sf_sent
>= 0));
6437 /* sf_sent<0 means error, thus fall back to the classic way */
6438 /* This is always the case, if sf_file is not a "normal" file,
6439 * e.g., for sending data from the output of a CGI process. */
6440 offset
= (int64_t)sf_offs
;
6443 if ((offset
> 0) && (fseeko(filep
->fp
, offset
, SEEK_SET
) != 0)) {
6444 mg_cry(conn
, "%s: fseeko() failed: %s", __func__
, strerror(ERRNO
));
6449 "Error: Unable to access file at requested position.");
6452 /* Calculate how much to read from the file in the buffer */
6453 to_read
= sizeof(buf
);
6454 if ((int64_t)to_read
> len
) {
6458 /* Read from file, exit the loop on error */
6459 if ((num_read
= (int)fread(buf
, 1, (size_t)to_read
, filep
->fp
))
6464 /* Send read bytes to the client, exit the loop on error */
6465 if ((num_written
= mg_write(conn
, buf
, (size_t)num_read
))
6470 /* Both read and were successful, adjust counters */
6471 conn
->num_bytes_sent
+= num_written
;
6480 parse_range_header(const char *header
, int64_t *a
, int64_t *b
)
6482 return sscanf(header
, "bytes=%" INT64_FMT
"-%" INT64_FMT
, a
, b
);
6487 construct_etag(char *buf
, size_t buf_len
, const struct file
*filep
)
6489 if (filep
!= NULL
&& buf
!= NULL
) {
6491 NULL
, /* All calls to construct_etag use 64 byte buffer */
6494 "\"%lx.%" INT64_FMT
"\"",
6495 (unsigned long)filep
->last_modified
,
6502 fclose_on_exec(struct file
*filep
, struct mg_connection
*conn
)
6504 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
6506 (void)conn
; /* Unused. */
6508 if (fcntl(fileno(filep
->fp
), F_SETFD
, FD_CLOEXEC
) != 0) {
6510 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
6520 handle_static_file_request(struct mg_connection
*conn
,
6523 const char *mime_type
)
6525 char date
[64], lm
[64], etag
[64];
6526 char range
[128]; /* large enough, so there will be no overflow */
6527 const char *msg
= "OK", *hdr
;
6528 time_t curtime
= time(NULL
);
6530 struct vec mime_vec
;
6532 char gz_path
[PATH_MAX
];
6533 const char *encoding
= "";
6534 const char *cors1
, *cors2
, *cors3
;
6536 if (conn
== NULL
|| conn
->ctx
== NULL
|| filep
== NULL
) {
6540 if (mime_type
== NULL
) {
6541 get_mime_type(conn
->ctx
, path
, &mime_vec
);
6543 mime_vec
.ptr
= mime_type
;
6544 mime_vec
.len
= strlen(mime_type
);
6546 if (filep
->size
> INT64_MAX
) {
6547 send_http_error(conn
,
6549 "Error: File size is too large to send\n%" INT64_FMT
,
6552 cl
= (int64_t)filep
->size
;
6553 conn
->status_code
= 200;
6556 /* if this file is in fact a pre-gzipped file, rewrite its filename
6557 * it's important to rewrite the filename after resolving
6558 * the mime type from it, to preserve the actual file's type */
6559 if (filep
->gzipped
) {
6560 mg_snprintf(conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", path
);
6563 send_http_error(conn
,
6565 "Error: Path of zipped file too long (%s)",
6571 encoding
= "Content-Encoding: gzip\r\n";
6574 if (!mg_fopen(conn
, path
, "rb", filep
)) {
6575 send_http_error(conn
,
6577 "Error: Cannot open file\nfopen(%s): %s",
6583 fclose_on_exec(filep
, conn
);
6585 /* If Range: header specified, act accordingly */
6587 hdr
= mg_get_header(conn
, "Range");
6588 if (hdr
!= NULL
&& (n
= parse_range_header(hdr
, &r1
, &r2
)) > 0 && r1
>= 0
6590 /* actually, range requests don't play well with a pre-gzipped
6591 * file (since the range is specified in the uncompressed space) */
6592 if (filep
->gzipped
) {
6597 "Error: Range requests in gzipped files are not supported");
6601 conn
->status_code
= 206;
6602 cl
= n
== 2 ? (r2
> cl
? cl
: r2
) - r1
+ 1 : cl
- r1
;
6604 NULL
, /* range buffer is big enough */
6607 "Content-Range: bytes "
6608 "%" INT64_FMT
"-%" INT64_FMT
"/%" INT64_FMT
"\r\n",
6612 msg
= "Partial Content";
6615 hdr
= mg_get_header(conn
, "Origin");
6617 /* Cross-origin resource sharing (CORS), see
6618 * http://www.html5rocks.com/en/tutorials/cors/,
6619 * http://www.html5rocks.com/static/images/cors_server_flowchart.png -
6620 * preflight is not supported for files. */
6621 cors1
= "Access-Control-Allow-Origin: ";
6622 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
6625 cors1
= cors2
= cors3
= "";
6628 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
6629 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
6630 gmt_time_string(date
, sizeof(date
), &curtime
);
6631 gmt_time_string(lm
, sizeof(lm
), &filep
->last_modified
);
6632 construct_etag(etag
, sizeof(etag
), filep
);
6634 (void)mg_printf(conn
,
6635 "HTTP/1.1 %d %s\r\n"
6644 send_static_cache_header(conn
);
6645 (void)mg_printf(conn
,
6646 "Last-Modified: %s\r\n"
6648 "Content-Type: %.*s\r\n"
6649 "Content-Length: %" INT64_FMT
"\r\n"
6650 "Connection: %s\r\n"
6651 "Accept-Ranges: bytes\r\n"
6658 suggest_connection_header(conn
),
6662 if (strcmp(conn
->request_info
.request_method
, "HEAD") != 0) {
6663 send_file_data(conn
, filep
, r1
, cl
);
6670 mg_send_file(struct mg_connection
*conn
, const char *path
)
6672 mg_send_mime_file(conn
, path
, NULL
);
6677 mg_send_mime_file(struct mg_connection
*conn
,
6679 const char *mime_type
)
6681 struct file file
= STRUCT_FILE_INITIALIZER
;
6682 if (mg_stat(conn
, path
, &file
)) {
6683 if (file
.is_directory
) {
6687 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
6689 handle_directory_request(conn
, path
);
6691 send_http_error(conn
,
6694 "Error: Directory listing denied");
6697 handle_static_file_request(conn
, path
, &file
, mime_type
);
6700 send_http_error(conn
, 404, "%s", "Error: File not found");
6705 /* For a given PUT path, create all intermediate subdirectories.
6706 * Return 0 if the path itself is a directory.
6707 * Return 1 if the path leads to a file.
6708 * Return -1 for if the path is too long.
6709 * Return -2 if path can not be created.
6712 put_dir(struct mg_connection
*conn
, const char *path
)
6716 struct file file
= STRUCT_FILE_INITIALIZER
;
6720 for (s
= p
= path
+ 2; (p
= strchr(s
, '/')) != NULL
; s
= ++p
) {
6721 len
= (size_t)(p
- path
);
6722 if (len
>= sizeof(buf
)) {
6727 memcpy(buf
, path
, len
);
6730 /* Try to create intermediate directory */
6731 DEBUG_TRACE("mkdir(%s)", buf
);
6732 if (!mg_stat(conn
, buf
, &file
) && mg_mkdir(conn
, buf
, 0755) != 0) {
6733 /* path does not exixt and can not be created */
6738 /* Is path itself a directory? */
6749 remove_bad_file(const struct mg_connection
*conn
, const char *path
)
6751 int r
= mg_remove(conn
, path
);
6753 mg_cry(conn
, "%s: Cannot remove invalid file %s", __func__
, path
);
6759 mg_store_body(struct mg_connection
*conn
, const char *path
)
6761 char buf
[MG_BUF_LEN
];
6766 if (conn
->consumed_content
!= 0) {
6767 mg_cry(conn
, "%s: Contents already consumed", __func__
);
6771 ret
= put_dir(conn
, path
);
6773 /* -1 for path too long,
6774 * -2 for path can not be created. */
6778 /* Return 0 means, path itself is a directory. */
6782 if (mg_fopen(conn
, path
, "w", &fi
) == 0) {
6786 ret
= mg_read(conn
, buf
, sizeof(buf
));
6788 n
= (int)fwrite(buf
, 1, (size_t)ret
, fi
.fp
);
6791 remove_bad_file(conn
, path
);
6794 ret
= mg_read(conn
, buf
, sizeof(buf
));
6797 /* TODO: mg_fclose should return an error,
6798 * and every caller should check and handle it. */
6799 if (fclose(fi
.fp
) != 0) {
6800 remove_bad_file(conn
, path
);
6808 /* Parse HTTP headers from the given buffer, advance buffer to the point
6809 * where parsing stopped. */
6811 parse_http_headers(char **buf
, struct mg_request_info
*ri
)
6819 ri
->num_headers
= 0;
6821 for (i
= 0; i
< (int)ARRAY_SIZE(ri
->http_headers
); i
++) {
6823 while ((*dp
!= ':') && (*dp
!= '\r') && (*dp
!= 0)) {
6827 /* neither : nor \r\n. This is not a valid field. */
6831 if (dp
[1] == '\n') {
6833 ri
->http_headers
[i
].name
= *buf
;
6834 ri
->http_headers
[i
].value
= 0;
6837 /* stray \r. This is not valid. */
6843 ri
->http_headers
[i
].name
= *buf
;
6846 } while (*dp
== ' ');
6848 ri
->http_headers
[i
].value
= dp
;
6849 *buf
= strstr(dp
, "\r\n");
6852 ri
->num_headers
= i
+ 1;
6862 if (*buf
[0] == '\r') {
6863 /* This is the end of the header */
6871 is_valid_http_method(const char *method
)
6873 return !strcmp(method
, "GET") /* HTTP (RFC 2616) */
6874 || !strcmp(method
, "POST") /* HTTP (RFC 2616) */
6875 || !strcmp(method
, "HEAD") /* HTTP (RFC 2616) */
6876 || !strcmp(method
, "PUT") /* HTTP (RFC 2616) */
6877 || !strcmp(method
, "DELETE") /* HTTP (RFC 2616) */
6878 || !strcmp(method
, "OPTIONS") /* HTTP (RFC 2616) */
6879 /* TRACE method (RFC 2616) is not supported for security reasons */
6880 || !strcmp(method
, "CONNECT") /* HTTP (RFC 2616) */
6882 || !strcmp(method
, "PROPFIND") /* WEBDAV (RFC 2518) */
6883 || !strcmp(method
, "MKCOL") /* WEBDAV (RFC 2518) */
6885 /* Unsupported WEBDAV Methods: */
6886 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
6887 /* + 11 methods from RFC 3253 */
6888 /* ORDERPATCH (RFC 3648) */
6889 /* ACL (RFC 3744) */
6890 /* SEARCH (RFC 5323) */
6891 /* + MicroSoft extensions
6892 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
6894 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
6895 || !strcmp(method
, "PATCH"); /* PATCH method (RFC 5789) */
6899 /* Parse HTTP request, fill in mg_request_info structure.
6900 * This function modifies the buffer by NUL-terminating
6901 * HTTP request components, header names and header values. */
6903 parse_http_message(char *buf
, int len
, struct mg_request_info
*ri
)
6905 int is_request
, request_length
;
6911 request_length
= get_request_len(buf
, len
);
6913 if (request_length
> 0) {
6914 /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
6916 ri
->remote_user
= ri
->request_method
= ri
->request_uri
=
6917 ri
->http_version
= NULL
;
6918 ri
->num_headers
= 0;
6920 buf
[request_length
- 1] = '\0';
6922 /* RFC says that all initial whitespaces should be ingored */
6923 while (*buf
!= '\0' && isspace(*(unsigned char *)buf
)) {
6926 ri
->request_method
= skip(&buf
, " ");
6927 ri
->request_uri
= skip(&buf
, " ");
6928 ri
->http_version
= skip(&buf
, "\r\n");
6930 /* HTTP message could be either HTTP request or HTTP response, e.g.
6931 * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
6932 is_request
= is_valid_http_method(ri
->request_method
);
6933 if ((is_request
&& memcmp(ri
->http_version
, "HTTP/", 5) != 0)
6934 || (!is_request
&& memcmp(ri
->request_method
, "HTTP/", 5) != 0)) {
6935 request_length
= -1;
6938 ri
->http_version
+= 5;
6940 parse_http_headers(&buf
, ri
);
6943 return request_length
;
6947 /* Keep reading the input (either opened file descriptor fd, or socket sock,
6948 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
6949 * buffer (which marks the end of HTTP request). Buffer buf may already
6950 * have some data. The length of the data is stored in nread.
6951 * Upon every read operation, increase nread by the number of bytes read. */
6953 read_request(FILE *fp
,
6954 struct mg_connection
*conn
,
6959 int request_len
, n
= 0;
6960 struct timespec last_action_time
;
6961 double request_timeout
;
6967 memset(&last_action_time
, 0, sizeof(last_action_time
));
6969 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
6970 /* value of request_timeout is in seconds, config in milliseconds */
6971 request_timeout
= atof(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
6973 request_timeout
= -1.0;
6976 request_len
= get_request_len(buf
, *nread
);
6978 /* first time reading from this connection */
6979 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
6982 (conn
->ctx
->stop_flag
== 0) && (*nread
< bufsiz
) && (request_len
== 0)
6983 && ((mg_difftimespec(&last_action_time
, &(conn
->req_time
))
6984 <= request_timeout
) || (request_timeout
< 0))
6985 && ((n
= pull(fp
, conn
, buf
+ *nread
, bufsiz
- *nread
, request_timeout
))
6988 /* assert(*nread <= bufsiz); */
6989 if (*nread
> bufsiz
) {
6992 request_len
= get_request_len(buf
, *nread
);
6993 if (request_timeout
> 0.0) {
6994 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
6998 return (request_len
<= 0 && n
<= 0) ? -1 : request_len
;
7001 #if !defined(NO_FILES)
7002 /* For given directory path, substitute it to valid index file.
7003 * Return 1 if index file has been found, 0 if not found.
7004 * If the file is found, it's stats is returned in stp. */
7006 substitute_index_file(struct mg_connection
*conn
,
7011 if (conn
&& conn
->ctx
) {
7012 const char *list
= conn
->ctx
->config
[INDEX_FILES
];
7013 struct file file
= STRUCT_FILE_INITIALIZER
;
7014 struct vec filename_vec
;
7015 size_t n
= strlen(path
);
7018 /* The 'path' given to us points to the directory. Remove all trailing
7019 * directory separator characters from the end of the path, and
7020 * then append single directory separator character. */
7021 while (n
> 0 && path
[n
- 1] == '/') {
7026 /* Traverse index files list. For each entry, append it to the given
7027 * path and see if the file exists. If it exists, break the loop */
7028 while ((list
= next_option(list
, &filename_vec
, NULL
)) != NULL
) {
7029 /* Ignore too long entries that may overflow path buffer */
7030 if (filename_vec
.len
> path_len
- (n
+ 2)) {
7034 /* Prepare full path to the index file */
7035 mg_strlcpy(path
+ n
+ 1, filename_vec
.ptr
, filename_vec
.len
+ 1);
7037 /* Does it exist? */
7038 if (mg_stat(conn
, path
, &file
)) {
7039 /* Yes it does, break the loop */
7046 /* If no index file exists, restore directory path */
7058 #if !defined(NO_CACHING)
7059 /* Return True if we should reply 304 Not Modified. */
7061 is_not_modified(const struct mg_connection
*conn
, const struct file
*filep
)
7064 const char *ims
= mg_get_header(conn
, "If-Modified-Since");
7065 const char *inm
= mg_get_header(conn
, "If-None-Match");
7066 construct_etag(etag
, sizeof(etag
), filep
);
7070 return (inm
!= NULL
&& !mg_strcasecmp(etag
, inm
))
7071 || (ims
!= NULL
&& (filep
->last_modified
<= parse_date_string(ims
)));
7073 #endif /* !NO_CACHING */
7076 #if !defined(NO_CGI) || !defined(NO_FILES)
7078 forward_body_data(struct mg_connection
*conn
, FILE *fp
, SOCKET sock
, SSL
*ssl
)
7080 const char *expect
, *body
;
7081 char buf
[MG_BUF_LEN
];
7082 int to_read
, nread
, success
= 0;
7083 int64_t buffered_len
;
7084 double timeout
= -1.0;
7089 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
7090 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
7093 expect
= mg_get_header(conn
, "Expect");
7094 /* assert(fp != NULL); */
7096 send_http_error(conn
, 500, "%s", "Error: NULL File");
7100 if (conn
->content_len
== -1 && !conn
->is_chunked
) {
7101 /* Content length is not specified by the client. */
7102 send_http_error(conn
,
7105 "Error: Client did not specify content length");
7106 } else if ((expect
!= NULL
)
7107 && (mg_strcasecmp(expect
, "100-continue") != 0)) {
7108 /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
7109 send_http_error(conn
,
7111 "Error: Can not fulfill expectation %s",
7114 if (expect
!= NULL
) {
7115 (void)mg_printf(conn
, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
7116 conn
->status_code
= 100;
7118 conn
->status_code
= 200;
7121 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
7122 - conn
->consumed_content
;
7124 /* assert(buffered_len >= 0); */
7125 /* assert(conn->consumed_content == 0); */
7127 if ((buffered_len
< 0) || (conn
->consumed_content
!= 0)) {
7128 send_http_error(conn
, 500, "%s", "Error: Size mismatch");
7132 if (buffered_len
> 0) {
7133 if ((int64_t)buffered_len
> conn
->content_len
) {
7134 buffered_len
= (int)conn
->content_len
;
7136 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
7137 push_all(conn
->ctx
, fp
, sock
, ssl
, body
, (int64_t)buffered_len
);
7138 conn
->consumed_content
+= buffered_len
;
7142 while (conn
->consumed_content
< conn
->content_len
) {
7143 to_read
= sizeof(buf
);
7144 if ((int64_t)to_read
> conn
->content_len
- conn
->consumed_content
) {
7145 to_read
= (int)(conn
->content_len
- conn
->consumed_content
);
7147 nread
= pull(NULL
, conn
, buf
, to_read
, timeout
);
7149 || push_all(conn
->ctx
, fp
, sock
, ssl
, buf
, nread
) != nread
) {
7152 conn
->consumed_content
+= nread
;
7155 if (conn
->consumed_content
== conn
->content_len
) {
7156 success
= (nread
>= 0);
7159 /* Each error code path in this function must send an error */
7161 /* NOTE: Maybe some data has already been sent. */
7162 /* TODO (low): If some data has been sent, a correct error
7163 * reply can no longer be sent, so just close the connection */
7164 send_http_error(conn
, 500, "%s", "");
7172 #if !defined(NO_CGI)
7173 /* This structure helps to create an environment for the spawned CGI program.
7174 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
7175 * last element must be NULL.
7176 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
7177 * strings must reside in a contiguous buffer. The end of the buffer is
7178 * marked by two '\0' characters.
7179 * We satisfy both worlds: we create an envp array (which is vars), all
7180 * entries are actually pointers inside buf. */
7181 struct cgi_environment
{
7182 struct mg_connection
*conn
;
7184 char *buf
; /* Environment buffer */
7185 size_t buflen
; /* Space available in buf */
7186 size_t bufused
; /* Space taken in buf */
7188 char **var
; /* char **envp */
7189 size_t varlen
; /* Number of variables available in var */
7190 size_t varused
; /* Number of variables stored in var */
7194 static void addenv(struct cgi_environment
*env
,
7195 PRINTF_FORMAT_STRING(const char *fmt
),
7196 ...) PRINTF_ARGS(2, 3);
7198 /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
7199 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
7201 addenv(struct cgi_environment
*env
, const char *fmt
, ...)
7208 /* Calculate how much space is left in the buffer */
7209 space
= (env
->buflen
- env
->bufused
);
7211 /* Calculate an estimate for the required space */
7212 n
= strlen(fmt
) + 2 + 128;
7216 /* Allocate new buffer */
7217 n
= env
->buflen
+ CGI_ENVIRONMENT_SIZE
;
7218 added
= (char *)mg_realloc(env
->buf
, n
);
7222 "%s: Cannot allocate memory for CGI variable [%s]",
7229 space
= (env
->buflen
- env
->bufused
);
7232 /* Make a pointer to the free space int the buffer */
7233 added
= env
->buf
+ env
->bufused
;
7235 /* Copy VARIABLE=VALUE\0 string into the free space */
7237 mg_vsnprintf(env
->conn
, &truncated
, added
, (size_t)space
, fmt
, ap
);
7240 /* Do not add truncated strings to the environment */
7242 /* Reallocate the buffer */
7246 } while (truncated
);
7248 /* Calculate number of bytes added to the environment */
7249 n
= strlen(added
) + 1;
7252 /* Now update the variable index */
7253 space
= (env
->varlen
- env
->varused
);
7256 "%s: Cannot register CGI variable [%s]",
7262 /* Append a pointer to the added string into the envp array */
7263 env
->var
[env
->varused
] = added
;
7269 prepare_cgi_environment(struct mg_connection
*conn
,
7271 struct cgi_environment
*env
)
7275 char *p
, src_addr
[IP_ADDR_STR_LEN
], http_var_name
[128];
7278 if (conn
== NULL
|| prog
== NULL
|| env
== NULL
) {
7283 env
->buflen
= CGI_ENVIRONMENT_SIZE
;
7285 env
->buf
= (char *)mg_malloc(env
->buflen
);
7286 env
->varlen
= MAX_CGI_ENVIR_VARS
;
7288 env
->var
= (char **)mg_malloc(env
->buflen
* sizeof(char *));
7290 addenv(env
, "SERVER_NAME=%s", conn
->ctx
->config
[AUTHENTICATION_DOMAIN
]);
7291 addenv(env
, "SERVER_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7292 addenv(env
, "DOCUMENT_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7293 addenv(env
, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
7295 /* Prepare the environment block */
7296 addenv(env
, "%s", "GATEWAY_INTERFACE=CGI/1.1");
7297 addenv(env
, "%s", "SERVER_PROTOCOL=HTTP/1.1");
7298 addenv(env
, "%s", "REDIRECT_STATUS=200"); /* For PHP */
7300 #if defined(USE_IPV6)
7301 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
7302 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin6
.sin6_port
));
7306 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin
.sin_port
));
7309 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
7310 addenv(env
, "REMOTE_ADDR=%s", src_addr
);
7312 addenv(env
, "REQUEST_METHOD=%s", conn
->request_info
.request_method
);
7313 addenv(env
, "REMOTE_PORT=%d", conn
->request_info
.remote_port
);
7315 addenv(env
, "REQUEST_URI=%s", conn
->request_info
.request_uri
);
7316 addenv(env
, "LOCAL_URI=%s", conn
->request_info
.local_uri
);
7321 (int)strlen(conn
->request_info
.local_uri
)
7322 - ((conn
->path_info
== NULL
) ? 0 : (int)strlen(conn
->path_info
)),
7323 conn
->request_info
.local_uri
);
7325 addenv(env
, "SCRIPT_FILENAME=%s", prog
);
7326 if (conn
->path_info
== NULL
) {
7327 addenv(env
, "PATH_TRANSLATED=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7330 "PATH_TRANSLATED=%s%s",
7331 conn
->ctx
->config
[DOCUMENT_ROOT
],
7335 addenv(env
, "HTTPS=%s", conn
->ssl
== NULL
? "off" : "on");
7337 if ((s
= mg_get_header(conn
, "Content-Type")) != NULL
) {
7338 addenv(env
, "CONTENT_TYPE=%s", s
);
7340 if (conn
->request_info
.query_string
!= NULL
) {
7341 addenv(env
, "QUERY_STRING=%s", conn
->request_info
.query_string
);
7343 if ((s
= mg_get_header(conn
, "Content-Length")) != NULL
) {
7344 addenv(env
, "CONTENT_LENGTH=%s", s
);
7346 if ((s
= getenv("PATH")) != NULL
) {
7347 addenv(env
, "PATH=%s", s
);
7349 if (conn
->path_info
!= NULL
) {
7350 addenv(env
, "PATH_INFO=%s", conn
->path_info
);
7353 if (conn
->status_code
> 0) {
7354 /* CGI error handler should show the status code */
7355 addenv(env
, "STATUS=%d", conn
->status_code
);
7359 if ((s
= getenv("COMSPEC")) != NULL
) {
7360 addenv(env
, "COMSPEC=%s", s
);
7362 if ((s
= getenv("SYSTEMROOT")) != NULL
) {
7363 addenv(env
, "SYSTEMROOT=%s", s
);
7365 if ((s
= getenv("SystemDrive")) != NULL
) {
7366 addenv(env
, "SystemDrive=%s", s
);
7368 if ((s
= getenv("ProgramFiles")) != NULL
) {
7369 addenv(env
, "ProgramFiles=%s", s
);
7371 if ((s
= getenv("ProgramFiles(x86)")) != NULL
) {
7372 addenv(env
, "ProgramFiles(x86)=%s", s
);
7375 if ((s
= getenv("LD_LIBRARY_PATH")) != NULL
) {
7376 addenv(env
, "LD_LIBRARY_PATH=%s", s
);
7380 if ((s
= getenv("PERLLIB")) != NULL
) {
7381 addenv(env
, "PERLLIB=%s", s
);
7384 if (conn
->request_info
.remote_user
!= NULL
) {
7385 addenv(env
, "REMOTE_USER=%s", conn
->request_info
.remote_user
);
7386 addenv(env
, "%s", "AUTH_TYPE=Digest");
7389 /* Add all headers as HTTP_* variables */
7390 for (i
= 0; i
< conn
->request_info
.num_headers
; i
++) {
7392 (void)mg_snprintf(conn
,
7395 sizeof(http_var_name
),
7397 conn
->request_info
.http_headers
[i
].name
);
7401 "%s: HTTP header variable too long [%s]",
7403 conn
->request_info
.http_headers
[i
].name
);
7407 /* Convert variable name into uppercase, and change - to _ */
7408 for (p
= http_var_name
; *p
!= '\0'; p
++) {
7412 *p
= (char)toupper(*(unsigned char *)p
);
7418 conn
->request_info
.http_headers
[i
].value
);
7421 /* Add user-specified variables */
7422 s
= conn
->ctx
->config
[CGI_ENVIRONMENT
];
7423 while ((s
= next_option(s
, &var_vec
, NULL
)) != NULL
) {
7424 addenv(env
, "%.*s", (int)var_vec
.len
, var_vec
.ptr
);
7427 env
->var
[env
->varused
] = NULL
;
7428 env
->buf
[env
->bufused
] = '\0';
7433 handle_cgi_request(struct mg_connection
*conn
, const char *prog
)
7437 int headers_len
, data_len
, i
, truncated
;
7438 int fdin
[2] = {-1, -1}, fdout
[2] = {-1, -1}, fderr
[2] = {-1, -1};
7439 const char *status
, *status_text
, *connection_state
;
7440 char *pbuf
, dir
[PATH_MAX
], *p
;
7441 struct mg_request_info ri
;
7442 struct cgi_environment blk
;
7443 FILE *in
= NULL
, *out
= NULL
, *err
= NULL
;
7444 struct file fout
= STRUCT_FILE_INITIALIZER
;
7445 pid_t pid
= (pid_t
)-1;
7453 prepare_cgi_environment(conn
, prog
, &blk
);
7455 /* CGI must be executed in its own directory. 'dir' must point to the
7456 * directory containing executable program, 'p' must point to the
7457 * executable program name relative to 'dir'. */
7458 (void)mg_snprintf(conn
, &truncated
, dir
, sizeof(dir
), "%s", prog
);
7461 mg_cry(conn
, "Error: CGI program \"%s\": Path too long", prog
);
7462 send_http_error(conn
, 500, "Error: %s", "CGI path too long");
7466 if ((p
= strrchr(dir
, '/')) != NULL
) {
7469 dir
[0] = '.', dir
[1] = '\0';
7473 if (pipe(fdin
) != 0 || pipe(fdout
) != 0 || pipe(fderr
) != 0) {
7474 status
= strerror(ERRNO
);
7476 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
7479 send_http_error(conn
, 500, "Error: Cannot create CGI pipe: %s", status
);
7483 pid
= spawn_process(conn
, p
, blk
.buf
, blk
.var
, fdin
, fdout
, fderr
, dir
);
7485 if (pid
== (pid_t
)-1) {
7486 status
= strerror(ERRNO
);
7488 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
7491 send_http_error(conn
,
7493 "Error: Cannot spawn CGI process [%s]: %s",
7499 /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
7500 set_close_on_exec((SOCKET
)fdin
[0], conn
); /* stdin read */
7501 set_close_on_exec((SOCKET
)fdout
[1], conn
); /* stdout write */
7502 set_close_on_exec((SOCKET
)fderr
[1], conn
); /* stderr write */
7503 set_close_on_exec((SOCKET
)fdin
[1], conn
); /* stdin write */
7504 set_close_on_exec((SOCKET
)fdout
[0], conn
); /* stdout read */
7505 set_close_on_exec((SOCKET
)fderr
[0], conn
); /* stderr read */
7507 /* Parent closes only one side of the pipes.
7508 * If we don't mark them as closed, close() attempt before
7509 * return from this function throws an exception on Windows.
7510 * Windows does not like when closed descriptor is closed again. */
7511 (void)close(fdin
[0]);
7512 (void)close(fdout
[1]);
7513 (void)close(fderr
[1]);
7514 fdin
[0] = fdout
[1] = fderr
[1] = -1;
7516 if ((in
= fdopen(fdin
[1], "wb")) == NULL
) {
7517 status
= strerror(ERRNO
);
7519 "Error: CGI program \"%s\": Can not open stdin: %s",
7522 send_http_error(conn
,
7524 "Error: CGI can not open fdin\nfopen: %s",
7529 if ((out
= fdopen(fdout
[0], "rb")) == NULL
) {
7530 status
= strerror(ERRNO
);
7532 "Error: CGI program \"%s\": Can not open stdout: %s",
7535 send_http_error(conn
,
7537 "Error: CGI can not open fdout\nfopen: %s",
7542 if ((err
= fdopen(fderr
[0], "rb")) == NULL
) {
7543 status
= strerror(ERRNO
);
7545 "Error: CGI program \"%s\": Can not open stderr: %s",
7548 send_http_error(conn
,
7550 "Error: CGI can not open fdout\nfopen: %s",
7560 if ((conn
->request_info
.content_length
> 0) || conn
->is_chunked
) {
7561 /* This is a POST/PUT request, or another request with body data. */
7562 if (!forward_body_data(conn
, in
, INVALID_SOCKET
, NULL
)) {
7563 /* Error sending the body data */
7565 "Error: CGI program \"%s\": Forward body data failed",
7571 /* Close so child gets an EOF. */
7576 /* Now read CGI reply into a buffer. We need to set correct
7577 * status code, thus we need to see all HTTP headers first.
7578 * Do not send anything back to client, until we buffer in all
7581 buf
= (char *)mg_malloc(buflen
);
7583 send_http_error(conn
,
7585 "Error: Not enough memory for CGI buffer (%u bytes)",
7586 (unsigned int)buflen
);
7588 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
7591 (unsigned int)buflen
);
7594 headers_len
= read_request(out
, conn
, buf
, (int)buflen
, &data_len
);
7595 if (headers_len
<= 0) {
7597 /* Could not parse the CGI response. Check if some error message on
7599 i
= pull_all(err
, conn
, buf
, (int)buflen
);
7602 "Error: CGI program \"%s\" sent error "
7607 send_http_error(conn
,
7609 "Error: CGI program \"%s\" sent error "
7616 "Error: CGI program sent malformed or too big "
7617 "(>%u bytes) HTTP headers: [%.*s]",
7622 send_http_error(conn
,
7624 "Error: CGI program sent malformed or too big "
7625 "(>%u bytes) HTTP headers: [%.*s]",
7634 buf
[headers_len
- 1] = '\0';
7635 parse_http_headers(&pbuf
, &ri
);
7637 /* Make up and send the status line */
7639 if ((status
= get_header(&ri
, "Status")) != NULL
) {
7640 conn
->status_code
= atoi(status
);
7641 status_text
= status
;
7642 while (isdigit(*(const unsigned char *)status_text
)
7643 || *status_text
== ' ') {
7646 } else if (get_header(&ri
, "Location") != NULL
) {
7647 conn
->status_code
= 302;
7649 conn
->status_code
= 200;
7651 connection_state
= get_header(&ri
, "Connection");
7652 if (!header_has_option(connection_state
, "keep-alive")) {
7653 conn
->must_close
= 1;
7655 (void)mg_printf(conn
, "HTTP/1.1 %d %s\r\n", conn
->status_code
, status_text
);
7658 for (i
= 0; i
< ri
.num_headers
; i
++) {
7661 ri
.http_headers
[i
].name
,
7662 ri
.http_headers
[i
].value
);
7664 mg_write(conn
, "\r\n", 2);
7666 /* Send chunk of data that may have been read after the headers */
7667 conn
->num_bytes_sent
+=
7668 mg_write(conn
, buf
+ headers_len
, (size_t)(data_len
- headers_len
));
7670 /* Read the rest of CGI output and send to the client */
7671 send_file_data(conn
, &fout
, 0, INT64_MAX
);
7677 if (pid
!= (pid_t
)-1) {
7679 #if !defined(_WIN32)
7682 while (waitpid(pid
, &st
, 0) != -1)
7683 ; /* clean zombies */
7687 if (fdin
[0] != -1) {
7690 if (fdout
[1] != -1) {
7696 } else if (fdin
[1] != -1) {
7702 } else if (fdout
[0] != -1) {
7708 } else if (fderr
[0] != -1) {
7716 #endif /* !NO_CGI */
7719 #if !defined(NO_FILES)
7721 mkcol(struct mg_connection
*conn
, const char *path
)
7726 time_t curtime
= time(NULL
);
7732 /* TODO (mid): Check the send_http_error situations in this function */
7734 memset(&de
.file
, 0, sizeof(de
.file
));
7735 if (!mg_stat(conn
, path
, &de
.file
)) {
7737 "%s: mg_stat(%s) failed: %s",
7743 if (de
.file
.last_modified
) {
7744 /* TODO (high): This check does not seem to make any sense ! */
7746 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7750 body_len
= conn
->data_len
- conn
->request_len
;
7753 conn
, 415, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7757 rc
= mg_mkdir(conn
, path
, 0755);
7760 conn
->status_code
= 201;
7761 gmt_time_string(date
, sizeof(date
), &curtime
);
7763 "HTTP/1.1 %d Created\r\n"
7767 send_static_cache_header(conn
);
7769 "Content-Length: 0\r\n"
7770 "Connection: %s\r\n\r\n",
7771 suggest_connection_header(conn
));
7772 } else if (rc
== -1) {
7773 if (errno
== EEXIST
) {
7775 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7776 } else if (errno
== EACCES
) {
7778 conn
, 403, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7779 } else if (errno
== ENOENT
) {
7781 conn
, 409, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7783 send_http_error(conn
, 500, "fopen(%s): %s", path
, strerror(ERRNO
));
7790 put_file(struct mg_connection
*conn
, const char *path
)
7792 struct file file
= STRUCT_FILE_INITIALIZER
;
7797 time_t curtime
= time(NULL
);
7803 if (mg_stat(conn
, path
, &file
)) {
7804 /* File already exists */
7805 conn
->status_code
= 200;
7807 if (file
.is_directory
) {
7808 /* This is an already existing directory,
7809 * so there is nothing to do for the server. */
7813 /* File exists and is not a directory. */
7814 /* Can it be replaced? */
7816 if (file
.membuf
!= NULL
) {
7817 /* This is an "in-memory" file, that can not be replaced */
7821 "Error: Put not possible\nReplacing %s is not supported",
7826 /* Check if the server may write this file */
7827 if (access(path
, W_OK
) == 0) {
7828 /* Access granted */
7829 conn
->status_code
= 200;
7835 "Error: Put not possible\nReplacing %s is not allowed",
7841 /* File should be created */
7842 conn
->status_code
= 201;
7843 rc
= put_dir(conn
, path
);
7847 /* put_dir returns 0 if path is a directory */
7848 gmt_time_string(date
, sizeof(date
), &curtime
);
7850 "HTTP/1.1 %d %s\r\n",
7852 mg_get_response_code_text(NULL
, conn
->status_code
));
7853 send_no_cache_header(conn
);
7856 "Content-Length: 0\r\n"
7857 "Connection: %s\r\n\r\n",
7859 suggest_connection_header(conn
));
7861 /* Request to create a directory has been fulfilled successfully.
7862 * No need to put a file. */
7867 /* put_dir returns -1 if the path is too long */
7868 send_http_error(conn
,
7870 "Error: Path too long\nput_dir(%s): %s",
7877 /* put_dir returns -2 if the directory can not be created */
7878 send_http_error(conn
,
7880 "Error: Can not create directory\nput_dir(%s): %s",
7886 /* A file should be created or overwritten. */
7887 if (!mg_fopen(conn
, path
, "wb+", &file
) || file
.fp
== NULL
) {
7889 send_http_error(conn
,
7891 "Error: Can not create file\nfopen(%s): %s",
7897 fclose_on_exec(&file
, conn
);
7898 range
= mg_get_header(conn
, "Content-Range");
7900 if (range
!= NULL
&& parse_range_header(range
, &r1
, &r2
) > 0) {
7901 conn
->status_code
= 206; /* Partial content */
7902 fseeko(file
.fp
, r1
, SEEK_SET
);
7905 if (!forward_body_data(conn
, file
.fp
, INVALID_SOCKET
, NULL
)) {
7906 /* forward_body_data failed.
7907 * The error code has already been sent to the client,
7908 * and conn->status_code is already set. */
7913 gmt_time_string(date
, sizeof(date
), &curtime
);
7915 "HTTP/1.1 %d %s\r\n",
7917 mg_get_response_code_text(NULL
, conn
->status_code
));
7918 send_no_cache_header(conn
);
7921 "Content-Length: 0\r\n"
7922 "Connection: %s\r\n\r\n",
7924 suggest_connection_header(conn
));
7931 delete_file(struct mg_connection
*conn
, const char *path
)
7934 memset(&de
.file
, 0, sizeof(de
.file
));
7935 if (!mg_stat(conn
, path
, &de
.file
)) {
7936 /* mg_stat returns 0 if the file does not exist */
7937 send_http_error(conn
,
7939 "Error: Cannot delete file\nFile %s not found",
7944 if (de
.file
.membuf
!= NULL
) {
7945 /* the file is cached in memory */
7949 "Error: Delete not possible\nDeleting %s is not supported",
7954 if (de
.file
.is_directory
) {
7955 if (remove_directory(conn
, path
)) {
7956 /* Delete is successful: Return 204 without content. */
7957 send_http_error(conn
, 204, "%s", "");
7959 /* Delete is not successful: Return 500 (Server error). */
7960 send_http_error(conn
, 500, "Error: Could not delete %s", path
);
7965 /* This is an existing file (not a directory).
7966 * Check if write permission is granted. */
7967 if (access(path
, W_OK
) != 0) {
7968 /* File is read only */
7972 "Error: Delete not possible\nDeleting %s is not allowed",
7977 /* Try to delete it. */
7978 if (mg_remove(conn
, path
) == 0) {
7979 /* Delete was successful: Return 204 without content. */
7980 send_http_error(conn
, 204, "%s", "");
7982 /* Delete not successful (file locked). */
7983 send_http_error(conn
,
7985 "Error: Cannot delete file\nremove(%s): %s",
7990 #endif /* !NO_FILES */
7994 send_ssi_file(struct mg_connection
*, const char *, struct file
*, int);
7998 do_ssi_include(struct mg_connection
*conn
,
8003 char file_name
[MG_BUF_LEN
], path
[512], *p
;
8004 struct file file
= STRUCT_FILE_INITIALIZER
;
8012 /* sscanf() is safe here, since send_ssi_file() also uses buffer
8013 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
8014 * always < MG_BUF_LEN. */
8015 if (sscanf(tag
, " virtual=\"%511[^\"]\"", file_name
) == 1) {
8016 /* File name is relative to the webserver root */
8018 (void)mg_snprintf(conn
,
8023 conn
->ctx
->config
[DOCUMENT_ROOT
],
8026 } else if (sscanf(tag
, " abspath=\"%511[^\"]\"", file_name
) == 1) {
8027 /* File name is relative to the webserver working directory
8028 * or it is absolute system path */
8031 mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", file_name
);
8033 } else if (sscanf(tag
, " file=\"%511[^\"]\"", file_name
) == 1
8034 || sscanf(tag
, " \"%511[^\"]\"", file_name
) == 1) {
8035 /* File name is relative to the currect document */
8037 (void)mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", ssi
);
8040 if ((p
= strrchr(path
, '/')) != NULL
) {
8044 (void)mg_snprintf(conn
,
8053 mg_cry(conn
, "Bad SSI #include: [%s]", tag
);
8058 mg_cry(conn
, "SSI #include path length overflow: [%s]", tag
);
8062 if (!mg_fopen(conn
, path
, "rb", &file
)) {
8064 "Cannot open SSI #include: [%s]: fopen(%s): %s",
8069 fclose_on_exec(&file
, conn
);
8070 if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
8071 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
8073 send_ssi_file(conn
, path
, &file
, include_level
+ 1);
8075 send_file_data(conn
, &file
, 0, INT64_MAX
);
8082 #if !defined(NO_POPEN)
8084 do_ssi_exec(struct mg_connection
*conn
, char *tag
)
8086 char cmd
[1024] = "";
8087 struct file file
= STRUCT_FILE_INITIALIZER
;
8089 if (sscanf(tag
, " \"%1023[^\"]\"", cmd
) != 1) {
8090 mg_cry(conn
, "Bad SSI #exec: [%s]", tag
);
8093 if ((file
.fp
= popen(cmd
, "r")) == NULL
) {
8094 mg_cry(conn
, "Cannot SSI #exec: [%s]: %s", cmd
, strerror(ERRNO
));
8096 send_file_data(conn
, &file
, 0, INT64_MAX
);
8101 #endif /* !NO_POPEN */
8105 mg_fgetc(struct file
*filep
, int offset
)
8107 if (filep
== NULL
) {
8110 if (filep
->membuf
!= NULL
&& offset
>= 0
8111 && ((unsigned int)(offset
)) < filep
->size
) {
8112 return ((const unsigned char *)filep
->membuf
)[offset
];
8113 } else if (filep
->fp
!= NULL
) {
8114 return fgetc(filep
->fp
);
8122 send_ssi_file(struct mg_connection
*conn
,
8127 char buf
[MG_BUF_LEN
];
8128 int ch
, offset
, len
, in_ssi_tag
;
8130 if (include_level
> 10) {
8131 mg_cry(conn
, "SSI #include level is too deep (%s)", path
);
8135 in_ssi_tag
= len
= offset
= 0;
8136 while ((ch
= mg_fgetc(filep
, offset
)) != EOF
) {
8137 if (in_ssi_tag
&& ch
== '>') {
8139 buf
[len
++] = (char)ch
;
8141 /* assert(len <= (int) sizeof(buf)); */
8142 if (len
> (int)sizeof(buf
)) {
8145 if (len
< 6 || memcmp(buf
, "<!--#", 5) != 0) {
8146 /* Not an SSI tag, pass it */
8147 (void)mg_write(conn
, buf
, (size_t)len
);
8149 if (!memcmp(buf
+ 5, "include", 7)) {
8150 do_ssi_include(conn
, path
, buf
+ 12, include_level
);
8151 #if !defined(NO_POPEN)
8152 } else if (!memcmp(buf
+ 5, "exec", 4)) {
8153 do_ssi_exec(conn
, buf
+ 9);
8154 #endif /* !NO_POPEN */
8164 } else if (in_ssi_tag
) {
8165 if (len
== 5 && memcmp(buf
, "<!--#", 5) != 0) {
8166 /* Not an SSI tag */
8168 } else if (len
== (int)sizeof(buf
) - 2) {
8169 mg_cry(conn
, "%s: SSI tag is too large", path
);
8172 buf
[len
++] = (char)(ch
& 0xff);
8173 } else if (ch
== '<') {
8176 mg_write(conn
, buf
, (size_t)len
);
8179 buf
[len
++] = (char)(ch
& 0xff);
8181 buf
[len
++] = (char)(ch
& 0xff);
8182 if (len
== (int)sizeof(buf
)) {
8183 mg_write(conn
, buf
, (size_t)len
);
8189 /* Send the rest of buffered data */
8191 mg_write(conn
, buf
, (size_t)len
);
8197 handle_ssi_file_request(struct mg_connection
*conn
,
8202 time_t curtime
= time(NULL
);
8203 const char *cors1
, *cors2
, *cors3
;
8205 if (conn
== NULL
|| path
== NULL
|| filep
== NULL
) {
8209 if (mg_get_header(conn
, "Origin")) {
8210 /* Cross-origin resource sharing (CORS). */
8211 cors1
= "Access-Control-Allow-Origin: ";
8212 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
8215 cors1
= cors2
= cors3
= "";
8218 if (!mg_fopen(conn
, path
, "rb", filep
)) {
8219 /* File exists (precondition for calling this function),
8220 * but can not be opened by the server. */
8221 send_http_error(conn
,
8223 "Error: Cannot read file\nfopen(%s): %s",
8227 conn
->must_close
= 1;
8228 gmt_time_string(date
, sizeof(date
), &curtime
);
8229 fclose_on_exec(filep
, conn
);
8230 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
8231 send_no_cache_header(conn
);
8235 "Content-Type: text/html\r\n"
8236 "Connection: %s\r\n\r\n",
8241 suggest_connection_header(conn
));
8242 send_ssi_file(conn
, path
, filep
, 0);
8248 #if !defined(NO_FILES)
8250 send_options(struct mg_connection
*conn
)
8253 time_t curtime
= time(NULL
);
8259 conn
->status_code
= 200;
8260 conn
->must_close
= 1;
8261 gmt_time_string(date
, sizeof(date
), &curtime
);
8264 "HTTP/1.1 200 OK\r\n"
8266 /* TODO: "Cache-Control" (?) */
8267 "Connection: %s\r\n"
8268 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
8269 "PROPFIND, MKCOL\r\n"
8272 suggest_connection_header(conn
));
8276 /* Writes PROPFIND properties for a collection element */
8278 print_props(struct mg_connection
*conn
, const char *uri
, struct file
*filep
)
8282 if (conn
== NULL
|| uri
== NULL
|| filep
== NULL
) {
8286 gmt_time_string(mtime
, sizeof(mtime
), &filep
->last_modified
);
8287 conn
->num_bytes_sent
+=
8290 "<d:href>%s</d:href>"
8293 "<d:resourcetype>%s</d:resourcetype>"
8294 "<d:getcontentlength>%" INT64_FMT
"</d:getcontentlength>"
8295 "<d:getlastmodified>%s</d:getlastmodified>"
8297 "<d:status>HTTP/1.1 200 OK</d:status>"
8301 filep
->is_directory
? "<d:collection/>" : "",
8308 print_dav_dir_entry(struct de
*de
, void *data
)
8310 char href
[PATH_MAX
];
8311 char href_encoded
[PATH_MAX
];
8314 struct mg_connection
*conn
= (struct mg_connection
*)data
;
8323 conn
->request_info
.local_uri
,
8327 mg_url_encode(href
, href_encoded
, PATH_MAX
- 1);
8328 print_props(conn
, href_encoded
, &de
->file
);
8334 handle_propfind(struct mg_connection
*conn
,
8338 const char *depth
= mg_get_header(conn
, "Depth");
8340 time_t curtime
= time(NULL
);
8342 gmt_time_string(date
, sizeof(date
), &curtime
);
8344 if (!conn
|| !path
|| !filep
|| !conn
->ctx
) {
8348 conn
->must_close
= 1;
8349 conn
->status_code
= 207;
8351 "HTTP/1.1 207 Multi-Status\r\n"
8354 send_static_cache_header(conn
);
8356 "Connection: %s\r\n"
8357 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
8358 suggest_connection_header(conn
));
8360 conn
->num_bytes_sent
+=
8362 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
8363 "<d:multistatus xmlns:d='DAV:'>\n");
8365 /* Print properties for the requested resource itself */
8366 print_props(conn
, conn
->request_info
.local_uri
, filep
);
8368 /* If it is a directory, print directory entries too if Depth is not 0 */
8369 if (filep
&& filep
->is_directory
8370 && !mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
], "yes")
8371 && (depth
== NULL
|| strcmp(depth
, "0") != 0)) {
8372 scan_directory(conn
, path
, conn
, &print_dav_dir_entry
);
8375 conn
->num_bytes_sent
+= mg_printf(conn
, "%s\n", "</d:multistatus>");
8380 mg_lock_connection(struct mg_connection
*conn
)
8383 (void)pthread_mutex_lock(&conn
->mutex
);
8388 mg_unlock_connection(struct mg_connection
*conn
)
8391 (void)pthread_mutex_unlock(&conn
->mutex
);
8396 mg_lock_context(struct mg_context
*ctx
)
8399 (void)pthread_mutex_lock(&ctx
->nonce_mutex
);
8404 mg_unlock_context(struct mg_context
*ctx
)
8407 (void)pthread_mutex_unlock(&ctx
->nonce_mutex
);
8411 #if defined(USE_TIMERS)
8412 #include "timer.inl"
8413 #endif /* USE_TIMERS */
8416 #include "mod_lua.inl"
8417 #endif /* USE_LUA */
8420 #include "mod_duktape.inl"
8421 #endif /* USE_DUKTAPE */
8423 #if defined(USE_WEBSOCKET)
8425 /* START OF SHA-1 code
8426 * Copyright(c) By Steve Reid <steve@edmweb.com> */
8427 #define SHA1HANDSOFF
8429 /* According to current tests (May 2015), the <solarisfixes.h> is not required.
8431 * #if defined(__sun)
8432 * #include "solarisfixes.h"
8440 static const int n
= 1;
8441 return ((char *)&n
)[0] == 0;
8445 union char64long16
{
8446 unsigned char c
[64];
8450 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
8454 blk0(union char64long16
*block
, int i
)
8456 /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
8457 if (!is_big_endian()) {
8458 block
->l
[i
] = (rol(block
->l
[i
], 24) & 0xFF00FF00)
8459 | (rol(block
->l
[i
], 8) & 0x00FF00FF);
8465 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
8466 ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
8468 #define R0(v, w, x, y, z, i) \
8469 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
8471 #define R1(v, w, x, y, z, i) \
8472 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
8474 #define R2(v, w, x, y, z, i) \
8475 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
8477 #define R3(v, w, x, y, z, i) \
8478 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
8480 #define R4(v, w, x, y, z, i) \
8481 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
8488 unsigned char buffer
[64];
8493 SHA1Transform(uint32_t state
[5], const unsigned char buffer
[64])
8495 uint32_t a
, b
, c
, d
, e
;
8496 union char64long16 block
[1];
8498 memcpy(block
, buffer
, 64);
8504 R0(a
, b
, c
, d
, e
, 0);
8505 R0(e
, a
, b
, c
, d
, 1);
8506 R0(d
, e
, a
, b
, c
, 2);
8507 R0(c
, d
, e
, a
, b
, 3);
8508 R0(b
, c
, d
, e
, a
, 4);
8509 R0(a
, b
, c
, d
, e
, 5);
8510 R0(e
, a
, b
, c
, d
, 6);
8511 R0(d
, e
, a
, b
, c
, 7);
8512 R0(c
, d
, e
, a
, b
, 8);
8513 R0(b
, c
, d
, e
, a
, 9);
8514 R0(a
, b
, c
, d
, e
, 10);
8515 R0(e
, a
, b
, c
, d
, 11);
8516 R0(d
, e
, a
, b
, c
, 12);
8517 R0(c
, d
, e
, a
, b
, 13);
8518 R0(b
, c
, d
, e
, a
, 14);
8519 R0(a
, b
, c
, d
, e
, 15);
8520 R1(e
, a
, b
, c
, d
, 16);
8521 R1(d
, e
, a
, b
, c
, 17);
8522 R1(c
, d
, e
, a
, b
, 18);
8523 R1(b
, c
, d
, e
, a
, 19);
8524 R2(a
, b
, c
, d
, e
, 20);
8525 R2(e
, a
, b
, c
, d
, 21);
8526 R2(d
, e
, a
, b
, c
, 22);
8527 R2(c
, d
, e
, a
, b
, 23);
8528 R2(b
, c
, d
, e
, a
, 24);
8529 R2(a
, b
, c
, d
, e
, 25);
8530 R2(e
, a
, b
, c
, d
, 26);
8531 R2(d
, e
, a
, b
, c
, 27);
8532 R2(c
, d
, e
, a
, b
, 28);
8533 R2(b
, c
, d
, e
, a
, 29);
8534 R2(a
, b
, c
, d
, e
, 30);
8535 R2(e
, a
, b
, c
, d
, 31);
8536 R2(d
, e
, a
, b
, c
, 32);
8537 R2(c
, d
, e
, a
, b
, 33);
8538 R2(b
, c
, d
, e
, a
, 34);
8539 R2(a
, b
, c
, d
, e
, 35);
8540 R2(e
, a
, b
, c
, d
, 36);
8541 R2(d
, e
, a
, b
, c
, 37);
8542 R2(c
, d
, e
, a
, b
, 38);
8543 R2(b
, c
, d
, e
, a
, 39);
8544 R3(a
, b
, c
, d
, e
, 40);
8545 R3(e
, a
, b
, c
, d
, 41);
8546 R3(d
, e
, a
, b
, c
, 42);
8547 R3(c
, d
, e
, a
, b
, 43);
8548 R3(b
, c
, d
, e
, a
, 44);
8549 R3(a
, b
, c
, d
, e
, 45);
8550 R3(e
, a
, b
, c
, d
, 46);
8551 R3(d
, e
, a
, b
, c
, 47);
8552 R3(c
, d
, e
, a
, b
, 48);
8553 R3(b
, c
, d
, e
, a
, 49);
8554 R3(a
, b
, c
, d
, e
, 50);
8555 R3(e
, a
, b
, c
, d
, 51);
8556 R3(d
, e
, a
, b
, c
, 52);
8557 R3(c
, d
, e
, a
, b
, 53);
8558 R3(b
, c
, d
, e
, a
, 54);
8559 R3(a
, b
, c
, d
, e
, 55);
8560 R3(e
, a
, b
, c
, d
, 56);
8561 R3(d
, e
, a
, b
, c
, 57);
8562 R3(c
, d
, e
, a
, b
, 58);
8563 R3(b
, c
, d
, e
, a
, 59);
8564 R4(a
, b
, c
, d
, e
, 60);
8565 R4(e
, a
, b
, c
, d
, 61);
8566 R4(d
, e
, a
, b
, c
, 62);
8567 R4(c
, d
, e
, a
, b
, 63);
8568 R4(b
, c
, d
, e
, a
, 64);
8569 R4(a
, b
, c
, d
, e
, 65);
8570 R4(e
, a
, b
, c
, d
, 66);
8571 R4(d
, e
, a
, b
, c
, 67);
8572 R4(c
, d
, e
, a
, b
, 68);
8573 R4(b
, c
, d
, e
, a
, 69);
8574 R4(a
, b
, c
, d
, e
, 70);
8575 R4(e
, a
, b
, c
, d
, 71);
8576 R4(d
, e
, a
, b
, c
, 72);
8577 R4(c
, d
, e
, a
, b
, 73);
8578 R4(b
, c
, d
, e
, a
, 74);
8579 R4(a
, b
, c
, d
, e
, 75);
8580 R4(e
, a
, b
, c
, d
, 76);
8581 R4(d
, e
, a
, b
, c
, 77);
8582 R4(c
, d
, e
, a
, b
, 78);
8583 R4(b
, c
, d
, e
, a
, 79);
8589 a
= b
= c
= d
= e
= 0;
8590 memset(block
, '\0', sizeof(block
));
8595 SHA1Init(SHA1_CTX
*context
)
8597 context
->state
[0] = 0x67452301;
8598 context
->state
[1] = 0xEFCDAB89;
8599 context
->state
[2] = 0x98BADCFE;
8600 context
->state
[3] = 0x10325476;
8601 context
->state
[4] = 0xC3D2E1F0;
8602 context
->count
[0] = context
->count
[1] = 0;
8607 SHA1Update(SHA1_CTX
*context
, const unsigned char *data
, uint32_t len
)
8611 j
= context
->count
[0];
8612 if ((context
->count
[0] += len
<< 3) < j
) {
8613 context
->count
[1]++;
8615 context
->count
[1] += (len
>> 29);
8617 if ((j
+ len
) > 63) {
8618 memcpy(&context
->buffer
[j
], data
, (i
= 64 - j
));
8619 SHA1Transform(context
->state
, context
->buffer
);
8620 for (; i
+ 63 < len
; i
+= 64) {
8621 SHA1Transform(context
->state
, &data
[i
]);
8626 memcpy(&context
->buffer
[j
], &data
[i
], len
- i
);
8631 SHA1Final(unsigned char digest
[20], SHA1_CTX
*context
)
8634 unsigned char finalcount
[8], c
;
8636 for (i
= 0; i
< 8; i
++) {
8637 finalcount
[i
] = (unsigned char)((context
->count
[(i
>= 4 ? 0 : 1)]
8638 >> ((3 - (i
& 3)) * 8)) & 255);
8641 SHA1Update(context
, &c
, 1);
8642 while ((context
->count
[0] & 504) != 448) {
8644 SHA1Update(context
, &c
, 1);
8646 SHA1Update(context
, finalcount
, 8);
8647 for (i
= 0; i
< 20; i
++) {
8648 digest
[i
] = (unsigned char)((context
->state
[i
>> 2]
8649 >> ((3 - (i
& 3)) * 8)) & 255);
8651 memset(context
, '\0', sizeof(*context
));
8652 memset(&finalcount
, '\0', sizeof(finalcount
));
8654 /* END OF SHA1 CODE */
8658 send_websocket_handshake(struct mg_connection
*conn
, const char *websock_key
)
8660 static const char *magic
= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8661 const char *protocol
= NULL
;
8662 char buf
[100], sha
[20], b64_sha
[sizeof(sha
) * 2];
8666 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
8667 mg_snprintf(conn
, &truncated
, buf
, sizeof(buf
), "%s%s", websock_key
, magic
);
8669 conn
->must_close
= 1;
8674 SHA1Update(&sha_ctx
, (unsigned char *)buf
, (uint32_t)strlen(buf
));
8675 SHA1Final((unsigned char *)sha
, &sha_ctx
);
8676 base64_encode((unsigned char *)sha
, sizeof(sha
), b64_sha
);
8678 "HTTP/1.1 101 Switching Protocols\r\n"
8679 "Upgrade: websocket\r\n"
8680 "Connection: Upgrade\r\n"
8681 "Sec-WebSocket-Accept: %s\r\n",
8683 protocol
= mg_get_header(conn
, "Sec-WebSocket-Protocol");
8685 /* The protocol is a comma seperated list of names. */
8686 /* The server must only return one value from this list. */
8687 /* First check if it is a list or just a single value. */
8688 const char *sep
= strchr(protocol
, ',');
8690 /* Just a single protocol -> accept it. */
8691 mg_printf(conn
, "Sec-WebSocket-Protocol: %s\r\n\r\n", protocol
);
8693 /* Multiple protocols -> accept the first one. */
8694 /* This is just a quick fix if the client offers multiple
8695 * protocols. In order to get the behavior intended by
8696 * RFC 6455 (https://tools.ietf.org/rfc/rfc6455.txt), it is
8697 * required to have a list of websocket subprotocols accepted
8698 * by the server. Then the server must either select a subprotocol
8699 * supported by client and server, or the server has to abort the
8700 * handshake by not returning a Sec-Websocket-Protocol header if
8701 * no subprotocol is acceptable.
8704 "Sec-WebSocket-Protocol: %.*s\r\n\r\n",
8705 (int)(sep
- protocol
),
8708 /* TODO: Real subprotocol negotiation instead of just taking the first
8709 * websocket subprotocol suggested by the client. */
8711 mg_printf(conn
, "%s", "\r\n");
8719 read_websocket(struct mg_connection
*conn
,
8720 mg_websocket_data_handler ws_data_handler
,
8721 void *callback_data
)
8723 /* Pointer to the beginning of the portion of the incoming websocket
8725 * The original websocket upgrade request is never removed, so the queue
8726 * begins after it. */
8727 unsigned char *buf
= (unsigned char *)conn
->buf
+ conn
->request_len
;
8728 int n
, error
, exit_by_callback
;
8730 /* body_len is the length of the entire queue in bytes
8731 * len is the length of the current message
8732 * data_len is the length of the current message's data payload
8733 * header_len is the length of the current message's header */
8734 size_t i
, len
, mask_len
= 0, data_len
= 0, header_len
, body_len
;
8736 /* "The masking key is a 32-bit value chosen at random by the client."
8737 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
8739 unsigned char mask
[4];
8741 /* data points to the place where the message is stored when passed to
8743 * websocket_data callback. This is either mem on the stack, or a
8744 * dynamically allocated buffer if it is too large. */
8747 unsigned char mop
; /* mask flag and opcode */
8748 double timeout
= -1.0;
8750 if (conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) {
8751 timeout
= atoi(conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) / 1000.0;
8753 if ((timeout
<= 0.0) && (conn
->ctx
->config
[REQUEST_TIMEOUT
])) {
8754 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
8757 mg_set_thread_name("wsock");
8759 /* Loop continuously, reading messages from the socket, invoking the
8760 * callback, and waiting repeatedly until an error occurs. */
8761 while (!conn
->ctx
->stop_flag
) {
8763 assert(conn
->data_len
>= conn
->request_len
);
8764 if ((body_len
= (size_t)(conn
->data_len
- conn
->request_len
)) >= 2) {
8766 mask_len
= buf
[1] & 128 ? 4 : 0;
8767 if (len
< 126 && body_len
>= mask_len
) {
8769 header_len
= 2 + mask_len
;
8770 } else if (len
== 126 && body_len
>= 4 + mask_len
) {
8771 header_len
= 4 + mask_len
;
8772 data_len
= ((((size_t)buf
[2]) << 8) + buf
[3]);
8773 } else if (body_len
>= 10 + mask_len
) {
8774 header_len
= 10 + mask_len
;
8775 data_len
= (((uint64_t)ntohl(*(uint32_t *)(void *)&buf
[2]))
8776 << 32) + ntohl(*(uint32_t *)(void *)&buf
[6]);
8780 if (header_len
> 0 && body_len
>= header_len
) {
8781 /* Allocate space to hold websocket payload */
8783 if (data_len
> sizeof(mem
)) {
8784 data
= (char *)mg_malloc(data_len
);
8786 /* Allocation failed, exit the loop and then close the
8788 mg_cry(conn
, "websocket out of memory; closing connection");
8793 /* Copy the mask before we shift the queue and destroy it */
8795 memcpy(mask
, buf
+ header_len
- mask_len
, sizeof(mask
));
8797 memset(mask
, 0, sizeof(mask
));
8800 /* Read frame payload from the first message in the queue into
8801 * data and advance the queue by moving the memory in place. */
8802 assert(body_len
>= header_len
);
8803 if (data_len
+ header_len
> body_len
) {
8804 mop
= buf
[0]; /* current mask and opcode */
8806 len
= body_len
- header_len
;
8807 memcpy(data
, buf
+ header_len
, len
);
8809 while (len
< data_len
) {
8811 NULL
, conn
, data
+ len
, (int)(data_len
- len
), timeout
);
8819 mg_cry(conn
, "Websocket pull failed; closing connection");
8822 conn
->data_len
= conn
->request_len
;
8824 mop
= buf
[0]; /* current mask and opcode, overwritten by
8826 /* Length of the message being read at the front of the
8828 len
= data_len
+ header_len
;
8830 /* Copy the data payload into the data pointer for the
8832 memcpy(data
, buf
+ header_len
, data_len
);
8834 /* Move the queue forward len bytes */
8835 memmove(buf
, buf
+ len
, body_len
- len
);
8837 /* Mark the queue as advanced */
8838 conn
->data_len
-= (int)len
;
8841 /* Apply mask if necessary */
8843 for (i
= 0; i
< data_len
; ++i
) {
8844 data
[i
] ^= mask
[i
& 3];
8848 /* Exit the loop if callback signals to exit (server side),
8849 * or "connection close" opcode received (client side). */
8850 exit_by_callback
= 0;
8851 if ((ws_data_handler
!= NULL
)
8852 && !ws_data_handler(conn
, mop
, data
, data_len
, callback_data
)) {
8853 exit_by_callback
= 1;
8860 if (exit_by_callback
8861 || ((mop
& 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE
)) {
8862 /* Opcode == 8, connection close */
8866 /* Not breaking the loop, process next websocket frame. */
8868 /* Read from the socket into the next available location in the
8872 conn
->buf
+ conn
->data_len
,
8873 conn
->buf_size
- conn
->data_len
,
8875 /* Error, no bytes read */
8878 conn
->data_len
+= n
;
8882 mg_set_thread_name("worker");
8887 mg_websocket_write_exec(struct mg_connection
*conn
,
8891 uint32_t masking_key
)
8893 unsigned char header
[14];
8894 size_t headerLen
= 1;
8898 header
[0] = 0x80 + (opcode
& 0xF);
8900 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
8901 if (dataLen
< 126) {
8902 /* inline 7-bit length field */
8903 header
[1] = (unsigned char)dataLen
;
8905 } else if (dataLen
<= 0xFFFF) {
8906 /* 16-bit length field */
8908 *(uint16_t *)(void *)(header
+ 2) = htons((uint16_t)dataLen
);
8911 /* 64-bit length field */
8913 *(uint32_t *)(void *)(header
+ 2) = htonl((uint64_t)dataLen
>> 32);
8914 *(uint32_t *)(void *)(header
+ 6) = htonl(dataLen
& 0xFFFFFFFF);
8921 *(uint32_t *)(void *)(header
+ headerLen
) = masking_key
;
8926 /* Note that POSIX/Winsock's send() is threadsafe
8927 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
8928 * but mongoose's mg_printf/mg_write is not (because of the loop in
8929 * push(), although that is only a problem if the packet is large or
8930 * outgoing buffer is full). */
8931 (void)mg_lock_connection(conn
);
8932 retval
= mg_write(conn
, header
, headerLen
);
8934 retval
= mg_write(conn
, data
, dataLen
);
8936 mg_unlock_connection(conn
);
8942 mg_websocket_write(struct mg_connection
*conn
,
8947 return mg_websocket_write_exec(conn
, opcode
, data
, dataLen
, 0);
8952 mask_data(const char *in
, size_t in_len
, uint32_t masking_key
, char *out
)
8957 if ((in_len
> 3) && ((ptrdiff_t)in
% 4) == 0) {
8958 /* Convert in 32 bit words, if data is 4 byte aligned */
8959 while (i
< (in_len
- 3)) {
8960 *(uint32_t *)(void *)(out
+ i
) =
8961 *(uint32_t *)(void *)(in
+ i
) ^ masking_key
;
8966 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
8967 while (i
< in_len
) {
8968 *(uint8_t *)(void *)(out
+ i
) =
8969 *(uint8_t *)(void *)(in
+ i
)
8970 ^ *(((uint8_t *)&masking_key
) + (i
% 4));
8978 mg_websocket_client_write(struct mg_connection
*conn
,
8984 char *masked_data
= (char *)mg_malloc(((dataLen
+ 7) / 4) * 4);
8985 uint32_t masking_key
= (uint32_t)get_random();
8987 if (masked_data
== NULL
) {
8988 /* Return -1 in an error case */
8990 "Cannot allocate buffer for masked websocket response: "
8995 mask_data(data
, dataLen
, masking_key
, masked_data
);
8997 retval
= mg_websocket_write_exec(
8998 conn
, opcode
, masked_data
, dataLen
, masking_key
);
8999 mg_free(masked_data
);
9006 handle_websocket_request(struct mg_connection
*conn
,
9008 int is_callback_resource
,
9009 mg_websocket_connect_handler ws_connect_handler
,
9010 mg_websocket_ready_handler ws_ready_handler
,
9011 mg_websocket_data_handler ws_data_handler
,
9012 mg_websocket_close_handler ws_close_handler
,
9015 const char *websock_key
= mg_get_header(conn
, "Sec-WebSocket-Key");
9016 const char *version
= mg_get_header(conn
, "Sec-WebSocket-Version");
9017 int lua_websock
= 0;
9019 #if !defined(USE_LUA)
9023 /* Step 1: Check websocket protocol version. */
9024 /* Step 1.1: Check Sec-WebSocket-Key. */
9026 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
9027 * requires a Sec-WebSocket-Key header.
9029 /* It could be the hixie draft version
9030 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
9032 const char *key1
= mg_get_header(conn
, "Sec-WebSocket-Key1");
9033 const char *key2
= mg_get_header(conn
, "Sec-WebSocket-Key2");
9036 if ((key1
!= NULL
) && (key2
!= NULL
)) {
9037 /* This version uses 8 byte body data in a GET request */
9038 conn
->content_len
= 8;
9039 if (8 == mg_read(conn
, key3
, 8)) {
9040 /* This is the hixie version */
9041 send_http_error(conn
,
9044 "Protocol upgrade to RFC 6455 required");
9048 /* This is an unknown version */
9049 send_http_error(conn
, 400, "%s", "Malformed websocket request");
9053 /* Step 1.2: Check websocket protocol version. */
9054 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
9055 if (version
== NULL
|| strcmp(version
, "13") != 0) {
9056 /* Reject wrong versions */
9057 send_http_error(conn
, 426, "%s", "Protocol upgrade required");
9061 /* Step 1.3: Could check for "Host", but we do not really nead this
9062 * value for anything, so just ignore it. */
9064 /* Step 2: If a callback is responsible, call it. */
9065 if (is_callback_resource
) {
9066 if (ws_connect_handler
!= NULL
9067 && ws_connect_handler(conn
, cbData
) != 0) {
9068 /* C callback has returned non-zero, do not proceed with
9071 /* Note that C callbacks are no longer called when Lua is
9072 * responsible, so C can no longer filter callbacks for Lua. */
9076 #if defined(USE_LUA)
9077 /* Step 3: No callback. Check if Lua is responsible. */
9079 /* Step 3.1: Check if Lua is responsible. */
9080 if (conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]) {
9082 match_prefix(conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
],
9084 conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]),
9089 /* Step 3.2: Lua is responsible: call it. */
9090 conn
->lua_websocket_state
= lua_websocket_new(path
, conn
);
9091 if (!conn
->lua_websocket_state
) {
9092 /* Lua rejected the new client */
9099 /* Step 4: Check if there is a responsible websocket handler. */
9100 if (!is_callback_resource
&& !lua_websock
) {
9101 /* There is no callback, an Lua is not responsible either. */
9102 /* Reply with a 404 Not Found or with nothing at all?
9103 * TODO (mid): check the websocket standards, how to reply to
9104 * requests to invalid websocket addresses. */
9105 send_http_error(conn
, 404, "%s", "Not found");
9109 /* Step 5: The websocket connection has been accepted */
9110 if (!send_websocket_handshake(conn
, websock_key
)) {
9111 send_http_error(conn
, 500, "%s", "Websocket handshake failed");
9115 /* Step 6: Call the ready handler */
9116 if (is_callback_resource
) {
9117 if (ws_ready_handler
!= NULL
) {
9118 ws_ready_handler(conn
, cbData
);
9120 #if defined(USE_LUA)
9121 } else if (lua_websock
) {
9122 if (!lua_websocket_ready(conn
, conn
->lua_websocket_state
)) {
9123 /* the ready handler returned false */
9129 /* Step 7: Enter the read loop */
9130 if (is_callback_resource
) {
9131 read_websocket(conn
, ws_data_handler
, cbData
);
9132 #if defined(USE_LUA)
9133 } else if (lua_websock
) {
9134 read_websocket(conn
, lua_websocket_data
, conn
->lua_websocket_state
);
9138 /* Step 8: Call the close handler */
9139 if (ws_close_handler
) {
9140 ws_close_handler(conn
, cbData
);
9146 is_websocket_protocol(const struct mg_connection
*conn
)
9148 const char *upgrade
, *connection
;
9150 /* A websocket protocoll has the following HTTP headers:
9152 * Connection: Upgrade
9153 * Upgrade: Websocket
9156 upgrade
= mg_get_header(conn
, "Upgrade");
9157 if (upgrade
== NULL
) {
9158 return 0; /* fail early, don't waste time checking other header
9162 if (!mg_strcasestr(upgrade
, "websocket")) {
9166 connection
= mg_get_header(conn
, "Connection");
9167 if (connection
== NULL
) {
9170 if (!mg_strcasestr(connection
, "upgrade")) {
9174 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
9175 * "Sec-WebSocket-Version" are also required.
9176 * Don't check them here, since even an unsupported websocket protocol
9177 * request still IS a websocket request (in contrast to a standard HTTP
9178 * request). It will fail later in handle_websocket_request.
9183 #endif /* !USE_WEBSOCKET */
9189 return n
>= 0 && n
<= 255;
9194 parse_net(const char *spec
, uint32_t *net
, uint32_t *mask
)
9196 int n
, a
, b
, c
, d
, slash
= 32, len
= 0;
9198 if ((sscanf(spec
, "%d.%d.%d.%d/%d%n", &a
, &b
, &c
, &d
, &slash
, &n
) == 5
9199 || sscanf(spec
, "%d.%d.%d.%d%n", &a
, &b
, &c
, &d
, &n
) == 4) && isbyte(a
)
9200 && isbyte(b
) && isbyte(c
) && isbyte(d
) && slash
>= 0
9203 *net
= ((uint32_t)a
<< 24) | ((uint32_t)b
<< 16) | ((uint32_t)c
<< 8)
9205 *mask
= slash
? 0xffffffffU
<< (32 - slash
) : 0;
9213 set_throttle(const char *spec
, uint32_t remote_ip
, const char *uri
)
9216 struct vec vec
, val
;
9221 while ((spec
= next_option(spec
, &vec
, &val
)) != NULL
) {
9223 if (sscanf(val
.ptr
, "%lf%c", &v
, &mult
) < 1 || v
< 0
9224 || (lowercase(&mult
) != 'k' && lowercase(&mult
) != 'm'
9228 v
*= lowercase(&mult
) == 'k' ? 1024 : lowercase(&mult
) == 'm' ? 1048576
9230 if (vec
.len
== 1 && vec
.ptr
[0] == '*') {
9232 } else if (parse_net(vec
.ptr
, &net
, &mask
) > 0) {
9233 if ((remote_ip
& mask
) == net
) {
9236 } else if (match_prefix(vec
.ptr
, vec
.len
, uri
) > 0) {
9246 get_remote_ip(const struct mg_connection
*conn
)
9251 return ntohl(*(const uint32_t *)&conn
->client
.rsa
.sin
.sin_addr
);
9255 /* The mg_upload function is superseeded by mg_handle_form_request. */
9256 #include "handle_form.inl"
9259 #if defined(MG_LEGACY_INTERFACE)
9260 /* Implement the deprecated mg_upload function by calling the new
9261 * mg_handle_form_request function. While mg_upload could only handle
9262 * HTML forms sent as POST request in multipart/form-data format
9263 * containing only file input elements, mg_handle_form_request can
9264 * handle all form input elements and all standard request methods. */
9265 struct mg_upload_user_data
{
9266 struct mg_connection
*conn
;
9267 const char *destination_dir
;
9268 int num_uploaded_files
;
9272 /* Helper function for deprecated mg_upload. */
9274 mg_upload_field_found(const char *key
,
9275 const char *filename
,
9281 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9285 mg_cry(fud
->conn
, "%s: No filename set", __func__
);
9286 return FORM_FIELD_STORAGE_ABORT
;
9288 mg_snprintf(fud
->conn
,
9293 fud
->destination_dir
,
9296 mg_cry(fud
->conn
, "%s: File path too long", __func__
);
9297 return FORM_FIELD_STORAGE_ABORT
;
9299 return FORM_FIELD_STORAGE_STORE
;
9303 /* Helper function for deprecated mg_upload. */
9305 mg_upload_field_get(const char *key
,
9310 /* Function should never be called */
9320 /* Helper function for deprecated mg_upload. */
9322 mg_upload_field_stored(const char *path
, long long file_size
, void *user_data
)
9324 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9327 fud
->num_uploaded_files
++;
9328 fud
->conn
->ctx
->callbacks
.upload(fud
->conn
, path
);
9334 /* Deprecated function mg_upload - use mg_handle_form_request instead. */
9336 mg_upload(struct mg_connection
*conn
, const char *destination_dir
)
9338 struct mg_upload_user_data fud
= {conn
, destination_dir
, 0};
9339 struct mg_form_data_handler fdh
= {mg_upload_field_found
,
9340 mg_upload_field_get
,
9341 mg_upload_field_stored
,
9345 fdh
.user_data
= (void *)&fud
;
9346 ret
= mg_handle_form_request(conn
, &fdh
);
9349 mg_cry(conn
, "%s: Error while parsing the request", __func__
);
9352 return fud
.num_uploaded_files
;
9358 get_first_ssl_listener_index(const struct mg_context
*ctx
)
9363 for (i
= 0; idx
== -1 && i
< ctx
->num_listening_sockets
; i
++) {
9364 idx
= ctx
->listening_sockets
[i
].is_ssl
? ((int)(i
)) : -1;
9372 redirect_to_https_port(struct mg_connection
*conn
, int ssl_index
)
9375 const char *host_header
;
9378 host_header
= mg_get_header(conn
, "Host");
9379 hostlen
= sizeof(host
);
9380 if (host_header
!= NULL
) {
9383 mg_strlcpy(host
, host_header
, hostlen
);
9384 host
[hostlen
- 1] = '\0';
9385 pos
= strchr(host
, ':');
9390 /* Cannot get host from the Host: header.
9391 * Fallback to our IP address. */
9393 sockaddr_to_string(host
, hostlen
, &conn
->client
.lsa
);
9397 /* Send host, port, uri and (if it exists) ?query_string */
9400 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
9403 conn
->ctx
->listening_sockets
[ssl_index
].lsa
.sin
.sin_port
),
9404 conn
->request_info
.local_uri
,
9405 (conn
->request_info
.query_string
== NULL
) ? "" : "?",
9406 (conn
->request_info
.query_string
== NULL
)
9408 : conn
->request_info
.query_string
);
9414 mg_set_handler_type(struct mg_context
*ctx
,
9417 int is_delete_request
,
9418 mg_request_handler handler
,
9419 mg_websocket_connect_handler connect_handler
,
9420 mg_websocket_ready_handler ready_handler
,
9421 mg_websocket_data_handler data_handler
,
9422 mg_websocket_close_handler close_handler
,
9423 mg_authorization_handler auth_handler
,
9426 struct mg_handler_info
*tmp_rh
, **lastref
;
9427 size_t urilen
= strlen(uri
);
9429 if (handler_type
== WEBSOCKET_HANDLER
) {
9430 /* assert(handler == NULL); */
9431 /* assert(is_delete_request || connect_handler!=NULL ||
9432 * ready_handler!=NULL || data_handler!=NULL ||
9433 * close_handler!=NULL);
9435 /* assert(auth_handler == NULL); */
9436 if (handler
!= NULL
) {
9439 if (!is_delete_request
&& connect_handler
== NULL
9440 && ready_handler
== NULL
9441 && data_handler
== NULL
9442 && close_handler
== NULL
) {
9445 if (auth_handler
!= NULL
) {
9448 } else if (handler_type
== REQUEST_HANDLER
) {
9449 /* assert(connect_handler==NULL && ready_handler==NULL &&
9450 * data_handler==NULL && close_handler==NULL); */
9451 /* assert(is_delete_request || (handler!=NULL));
9453 /* assert(auth_handler == NULL); */
9454 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9455 || data_handler
!= NULL
9456 || close_handler
!= NULL
) {
9459 if (!is_delete_request
&& (handler
== NULL
)) {
9462 if (auth_handler
!= NULL
) {
9465 } else { /* AUTH_HANDLER */
9466 /* assert(handler == NULL); */
9467 /* assert(connect_handler==NULL && ready_handler==NULL &&
9468 * data_handler==NULL && close_handler==NULL); */
9469 /* assert(auth_handler != NULL); */
9470 if (handler
!= NULL
) {
9473 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9474 || data_handler
!= NULL
9475 || close_handler
!= NULL
) {
9478 if (!is_delete_request
&& (auth_handler
== NULL
)) {
9487 mg_lock_context(ctx
);
9489 /* first try to find an existing handler */
9490 lastref
= &(ctx
->handlers
);
9491 for (tmp_rh
= ctx
->handlers
; tmp_rh
!= NULL
; tmp_rh
= tmp_rh
->next
) {
9492 if (tmp_rh
->handler_type
== handler_type
) {
9493 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9494 if (!is_delete_request
) {
9495 /* update existing handler */
9496 if (handler_type
== REQUEST_HANDLER
) {
9497 tmp_rh
->handler
= handler
;
9498 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9499 tmp_rh
->connect_handler
= connect_handler
;
9500 tmp_rh
->ready_handler
= ready_handler
;
9501 tmp_rh
->data_handler
= data_handler
;
9502 tmp_rh
->close_handler
= close_handler
;
9503 } else { /* AUTH_HANDLER */
9504 tmp_rh
->auth_handler
= auth_handler
;
9506 tmp_rh
->cbdata
= cbdata
;
9508 /* remove existing handler */
9509 *lastref
= tmp_rh
->next
;
9510 mg_free(tmp_rh
->uri
);
9513 mg_unlock_context(ctx
);
9517 lastref
= &(tmp_rh
->next
);
9520 if (is_delete_request
) {
9521 /* no handler to set, this was a remove request to a non-existing
9523 mg_unlock_context(ctx
);
9528 (struct mg_handler_info
*)mg_calloc(sizeof(struct mg_handler_info
), 1);
9529 if (tmp_rh
== NULL
) {
9530 mg_unlock_context(ctx
);
9531 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9534 tmp_rh
->uri
= mg_strdup(uri
);
9536 mg_unlock_context(ctx
);
9538 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9541 tmp_rh
->uri_len
= urilen
;
9542 if (handler_type
== REQUEST_HANDLER
) {
9543 tmp_rh
->handler
= handler
;
9544 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9545 tmp_rh
->connect_handler
= connect_handler
;
9546 tmp_rh
->ready_handler
= ready_handler
;
9547 tmp_rh
->data_handler
= data_handler
;
9548 tmp_rh
->close_handler
= close_handler
;
9549 } else { /* AUTH_HANDLER */
9550 tmp_rh
->auth_handler
= auth_handler
;
9552 tmp_rh
->cbdata
= cbdata
;
9553 tmp_rh
->handler_type
= handler_type
;
9554 tmp_rh
->next
= NULL
;
9557 mg_unlock_context(ctx
);
9562 mg_set_request_handler(struct mg_context
*ctx
,
9564 mg_request_handler handler
,
9567 mg_set_handler_type(ctx
,
9582 mg_set_websocket_handler(struct mg_context
*ctx
,
9584 mg_websocket_connect_handler connect_handler
,
9585 mg_websocket_ready_handler ready_handler
,
9586 mg_websocket_data_handler data_handler
,
9587 mg_websocket_close_handler close_handler
,
9590 int is_delete_request
= (connect_handler
== NULL
) && (ready_handler
== NULL
)
9591 && (data_handler
== NULL
)
9592 && (close_handler
== NULL
);
9593 mg_set_handler_type(ctx
,
9608 mg_set_auth_handler(struct mg_context
*ctx
,
9610 mg_request_handler handler
,
9613 mg_set_handler_type(ctx
,
9628 get_request_handler(struct mg_connection
*conn
,
9630 mg_request_handler
*handler
,
9631 mg_websocket_connect_handler
*connect_handler
,
9632 mg_websocket_ready_handler
*ready_handler
,
9633 mg_websocket_data_handler
*data_handler
,
9634 mg_websocket_close_handler
*close_handler
,
9635 mg_authorization_handler
*auth_handler
,
9638 const struct mg_request_info
*request_info
= mg_get_request_info(conn
);
9640 const char *uri
= request_info
->local_uri
;
9641 size_t urilen
= strlen(uri
);
9642 struct mg_handler_info
*tmp_rh
;
9644 if (!conn
|| !conn
->ctx
) {
9648 mg_lock_context(conn
->ctx
);
9650 /* first try for an exact match */
9651 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9652 tmp_rh
= tmp_rh
->next
) {
9653 if (tmp_rh
->handler_type
== handler_type
) {
9654 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9655 if (handler_type
== WEBSOCKET_HANDLER
) {
9656 *connect_handler
= tmp_rh
->connect_handler
;
9657 *ready_handler
= tmp_rh
->ready_handler
;
9658 *data_handler
= tmp_rh
->data_handler
;
9659 *close_handler
= tmp_rh
->close_handler
;
9660 } else if (handler_type
== REQUEST_HANDLER
) {
9661 *handler
= tmp_rh
->handler
;
9662 } else { /* AUTH_HANDLER */
9663 *auth_handler
= tmp_rh
->auth_handler
;
9665 *cbdata
= tmp_rh
->cbdata
;
9666 mg_unlock_context(conn
->ctx
);
9672 /* next try for a partial match, we will accept uri/something */
9673 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9674 tmp_rh
= tmp_rh
->next
) {
9675 if (tmp_rh
->handler_type
== handler_type
) {
9676 if (tmp_rh
->uri_len
< urilen
&& uri
[tmp_rh
->uri_len
] == '/'
9677 && memcmp(tmp_rh
->uri
, uri
, tmp_rh
->uri_len
) == 0) {
9678 if (handler_type
== WEBSOCKET_HANDLER
) {
9679 *connect_handler
= tmp_rh
->connect_handler
;
9680 *ready_handler
= tmp_rh
->ready_handler
;
9681 *data_handler
= tmp_rh
->data_handler
;
9682 *close_handler
= tmp_rh
->close_handler
;
9683 } else if (handler_type
== REQUEST_HANDLER
) {
9684 *handler
= tmp_rh
->handler
;
9685 } else { /* AUTH_HANDLER */
9686 *auth_handler
= tmp_rh
->auth_handler
;
9688 *cbdata
= tmp_rh
->cbdata
;
9689 mg_unlock_context(conn
->ctx
);
9695 /* finally try for pattern match */
9696 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9697 tmp_rh
= tmp_rh
->next
) {
9698 if (tmp_rh
->handler_type
== handler_type
) {
9699 if (match_prefix(tmp_rh
->uri
, tmp_rh
->uri_len
, uri
) > 0) {
9700 if (handler_type
== WEBSOCKET_HANDLER
) {
9701 *connect_handler
= tmp_rh
->connect_handler
;
9702 *ready_handler
= tmp_rh
->ready_handler
;
9703 *data_handler
= tmp_rh
->data_handler
;
9704 *close_handler
= tmp_rh
->close_handler
;
9705 } else if (handler_type
== REQUEST_HANDLER
) {
9706 *handler
= tmp_rh
->handler
;
9707 } else { /* AUTH_HANDLER */
9708 *auth_handler
= tmp_rh
->auth_handler
;
9710 *cbdata
= tmp_rh
->cbdata
;
9711 mg_unlock_context(conn
->ctx
);
9717 mg_unlock_context(conn
->ctx
);
9719 return 0; /* none found */
9723 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
9725 deprecated_websocket_connect_wrapper(const struct mg_connection
*conn
,
9728 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9729 if (pcallbacks
->websocket_connect
) {
9730 return pcallbacks
->websocket_connect(conn
);
9732 /* No handler set - assume "OK" */
9738 deprecated_websocket_ready_wrapper(struct mg_connection
*conn
, void *cbdata
)
9740 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9741 if (pcallbacks
->websocket_ready
) {
9742 pcallbacks
->websocket_ready(conn
);
9748 deprecated_websocket_data_wrapper(struct mg_connection
*conn
,
9754 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9755 if (pcallbacks
->websocket_data
) {
9756 return pcallbacks
->websocket_data(conn
, bits
, data
, len
);
9758 /* No handler set - assume "OK" */
9764 /* This is the heart of the Civetweb's logic.
9765 * This function is called when the request is read, parsed and validated,
9766 * and Civetweb must decide what action to take: serve a file, or
9767 * a directory, or call embedded function, etcetera. */
9769 handle_request(struct mg_connection
*conn
)
9772 struct mg_request_info
*ri
= &conn
->request_info
;
9773 char path
[PATH_MAX
];
9774 int uri_len
, ssl_index
;
9775 int is_found
= 0, is_script_resource
= 0, is_websocket_request
= 0,
9776 is_put_or_delete_request
= 0, is_callback_resource
= 0;
9778 struct file file
= STRUCT_FILE_INITIALIZER
;
9779 mg_request_handler callback_handler
= NULL
;
9780 mg_websocket_connect_handler ws_connect_handler
= NULL
;
9781 mg_websocket_ready_handler ws_ready_handler
= NULL
;
9782 mg_websocket_data_handler ws_data_handler
= NULL
;
9783 mg_websocket_close_handler ws_close_handler
= NULL
;
9784 void *callback_data
= NULL
;
9785 mg_authorization_handler auth_handler
= NULL
;
9786 void *auth_callback_data
= NULL
;
9787 #if !defined(NO_FILES)
9788 time_t curtime
= time(NULL
);
9798 /* 1. get the request url */
9799 /* 1.1. split into url and query string */
9800 if ((conn
->request_info
.query_string
= strchr(ri
->request_uri
, '?'))
9802 *((char *)conn
->request_info
.query_string
++) = '\0';
9804 uri_len
= (int)strlen(ri
->local_uri
);
9806 /* 1.2. decode url (if config says so) */
9807 if (should_decode_url(conn
)) {
9809 ri
->local_uri
, uri_len
, (char *)ri
->local_uri
, uri_len
+ 1, 0);
9812 /* 1.3. clean URIs, so a path like allowed_dir/../forbidden_file is
9814 remove_double_dots_and_double_slashes((char *)ri
->local_uri
);
9816 /* step 1. completed, the url is known now */
9817 DEBUG_TRACE("URL: %s", ri
->local_uri
);
9819 /* 2. do a https redirect, if required */
9820 if (!conn
->client
.is_ssl
&& conn
->client
.ssl_redir
) {
9821 ssl_index
= get_first_ssl_listener_index(conn
->ctx
);
9822 if (ssl_index
>= 0) {
9823 redirect_to_https_port(conn
, ssl_index
);
9825 /* A http to https forward port has been specified,
9826 * but no https port to forward to. */
9827 send_http_error(conn
,
9830 "Error: SSL forward not configured properly");
9831 mg_cry(conn
, "Can not redirect to SSL, no SSL port available");
9836 /* 3. if this ip has limited speed, set it for this connection */
9837 conn
->throttle
= set_throttle(conn
->ctx
->config
[THROTTLE
],
9838 get_remote_ip(conn
),
9841 /* 4. call a "handle everything" callback, if registered */
9842 if (conn
->ctx
->callbacks
.begin_request
!= NULL
) {
9843 /* Note that since V1.7 the "begin_request" function is called
9844 * before an authorization check. If an authorization check is
9845 * required, use a request_handler instead. */
9846 i
= conn
->ctx
->callbacks
.begin_request(conn
);
9848 /* callback already processed the request. Store the
9849 return value as a status code for the access log. */
9850 conn
->status_code
= i
;
9852 } else if (i
== 0) {
9853 /* civetweb should process the request */
9855 /* unspecified - may change with the next version */
9860 /* request not yet handled by a handler or redirect, so the request
9861 * is processed here */
9863 /* 5. interpret the url to find out how the request must be handled
9865 /* 5.1. first test, if the request targets the regular http(s)://
9866 * protocol namespace or the websocket ws(s):// protocol namespace.
9868 is_websocket_request
= is_websocket_protocol(conn
);
9870 /* 5.2. check if the request will be handled by a callback */
9871 if (get_request_handler(conn
,
9872 is_websocket_request
? WEBSOCKET_HANDLER
9875 &ws_connect_handler
,
9881 /* 5.2.1. A callback will handle this request. All requests
9883 * by a callback have to be considered as requests to a script
9885 is_callback_resource
= 1;
9886 is_script_resource
= 1;
9887 is_put_or_delete_request
= is_put_or_delete_method(conn
);
9889 no_callback_resource
:
9890 /* 5.2.2. No callback is responsible for this request. The URI
9891 * addresses a file based resource (static content or Lua/cgi
9892 * scripts in the file system). */
9893 is_callback_resource
= 0;
9899 &is_script_resource
,
9900 &is_websocket_request
,
9901 &is_put_or_delete_request
);
9904 /* 6. authorization check */
9905 /* 6.1. a custom authorization handler is installed */
9906 if (get_request_handler(conn
,
9914 &auth_callback_data
)) {
9915 if (!auth_handler(conn
, auth_callback_data
)) {
9918 } else if (is_put_or_delete_request
&& !is_script_resource
9919 && !is_callback_resource
) {
9920 /* 6.2. this request is a PUT/DELETE to a real file */
9921 /* 6.2.1. thus, the server must have real files */
9922 #if defined(NO_FILES)
9925 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
9927 /* This server does not have any real files, thus the
9928 * PUT/DELETE methods are not valid. */
9929 send_http_error(conn
,
9931 "%s method not allowed",
9932 conn
->request_info
.request_method
);
9936 #if !defined(NO_FILES)
9937 /* 6.2.2. Check if put authorization for static files is
9940 if (!is_authorized_for_put(conn
)) {
9941 send_authorization_request(conn
);
9947 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
9948 * or it is a PUT or DELETE request to a resource that does not
9949 * correspond to a file. Check authorization. */
9950 if (!check_authorization(conn
, path
)) {
9951 send_authorization_request(conn
);
9956 /* request is authorized or does not need authorization */
9958 /* 7. check if there are request handlers for this uri */
9959 if (is_callback_resource
) {
9960 if (!is_websocket_request
) {
9961 i
= callback_handler(conn
, callback_data
);
9963 /* Do nothing, callback has served the request. Store
9965 * return value as status code for the log and discard
9967 * data from the client not used by the callback. */
9968 conn
->status_code
= i
;
9969 discard_unread_request_data(conn
);
9971 /* TODO (high): what if the handler did NOT handle the
9973 /* The last version did handle this as a file request,
9975 * since a file request is not always a script resource,
9976 * the authorization check might be different */
9982 &is_script_resource
,
9983 &is_websocket_request
,
9984 &is_put_or_delete_request
);
9985 callback_handler
= NULL
;
9987 /* TODO (very low): goto is deprecated but for the
9989 * a goto is simpler than some curious loop. */
9990 /* The situation "callback does not handle the request"
9991 * needs to be reconsidered anyway. */
9992 goto no_callback_resource
;
9995 #if defined(USE_WEBSOCKET)
9996 handle_websocket_request(conn
,
9998 is_callback_resource
,
10009 /* 8. handle websocket requests */
10010 #if defined(USE_WEBSOCKET)
10011 if (is_websocket_request
) {
10012 if (is_script_resource
) {
10013 /* Websocket Lua script */
10014 handle_websocket_request(conn
,
10016 0 /* Lua Script */,
10021 &conn
->ctx
->callbacks
);
10023 #if defined(MG_LEGACY_INTERFACE)
10024 handle_websocket_request(
10027 !is_script_resource
/* could be deprecated global callback */,
10028 deprecated_websocket_connect_wrapper
,
10029 deprecated_websocket_ready_wrapper
,
10030 deprecated_websocket_data_wrapper
,
10032 &conn
->ctx
->callbacks
);
10034 send_http_error(conn
, 404, "%s", "Not found");
10041 #if defined(NO_FILES)
10042 /* 9a. In case the server uses only callbacks, this uri is
10044 * Then, all request handling ends here. */
10045 send_http_error(conn
, 404, "%s", "Not Found");
10048 /* 9b. This request is either for a static file or resource handled
10049 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
10050 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
10051 send_http_error(conn
, 404, "%s", "Not Found");
10055 /* 10. File is handled by a script. */
10056 if (is_script_resource
) {
10057 handle_file_based_request(conn
, path
, &file
);
10061 /* 11. Handle put/delete/mkcol requests */
10062 if (is_put_or_delete_request
) {
10063 /* 11.1. PUT method */
10064 if (!strcmp(ri
->request_method
, "PUT")) {
10065 put_file(conn
, path
);
10068 /* 11.2. DELETE method */
10069 if (!strcmp(ri
->request_method
, "DELETE")) {
10070 delete_file(conn
, path
);
10073 /* 11.3. MKCOL method */
10074 if (!strcmp(ri
->request_method
, "MKCOL")) {
10078 /* 11.4. PATCH method
10079 * This method is not supported for static resources,
10080 * only for scripts (Lua, CGI) and callbacks. */
10081 send_http_error(conn
,
10083 "%s method not allowed",
10084 conn
->request_info
.request_method
);
10088 /* 11. File does not exist, or it was configured that it should be
10090 if (!is_found
|| (must_hide_file(conn
, path
))) {
10091 send_http_error(conn
, 404, "%s", "Not found");
10095 /* 12. Directory uris should end with a slash */
10096 if (file
.is_directory
&& ri
->local_uri
[uri_len
- 1] != '/') {
10097 gmt_time_string(date
, sizeof(date
), &curtime
);
10099 "HTTP/1.1 301 Moved Permanently\r\n"
10100 "Location: %s/\r\n"
10102 /* "Cache-Control: private\r\n" (= default) */
10103 "Content-Length: 0\r\n"
10104 "Connection: %s\r\n\r\n",
10107 suggest_connection_header(conn
));
10111 /* 13. Handle other methods than GET/HEAD */
10112 /* 13.1. Handle PROPFIND */
10113 if (!strcmp(ri
->request_method
, "PROPFIND")) {
10114 handle_propfind(conn
, path
, &file
);
10117 /* 13.2. Handle OPTIONS for files */
10118 if (!strcmp(ri
->request_method
, "OPTIONS")) {
10119 /* This standard handler is only used for real files.
10120 * Scripts should support the OPTIONS method themselves, to allow a
10121 * maximum flexibility.
10122 * Lua and CGI scripts may fully support CORS this way (including
10124 send_options(conn
);
10127 /* 13.3. everything but GET and HEAD (e.g. POST) */
10128 if (0 != strcmp(ri
->request_method
, "GET")
10129 && 0 != strcmp(ri
->request_method
, "HEAD")) {
10130 send_http_error(conn
,
10132 "%s method not allowed",
10133 conn
->request_info
.request_method
);
10137 /* 14. directories */
10138 if (file
.is_directory
) {
10139 if (substitute_index_file(conn
, path
, sizeof(path
), &file
)) {
10140 /* 14.1. use a substitute file */
10141 /* TODO (high): substitute index may be a script resource.
10142 * define what should be possible in this case. */
10144 /* 14.2. no substitute file */
10145 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
10147 handle_directory_request(conn
, path
);
10149 send_http_error(conn
,
10152 "Error: Directory listing denied");
10158 handle_file_based_request(conn
, path
, &file
);
10159 #endif /* !defined(NO_FILES) */
10162 /* Perform redirect and auth checks before calling begin_request()
10164 * Otherwise, begin_request() would need to perform auth checks and
10173 handle_file_based_request(struct mg_connection
*conn
,
10177 if (!conn
|| !conn
->ctx
) {
10183 } else if (match_prefix(conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
],
10185 conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
]),
10187 /* Lua server page: an SSI like page containing mostly plain html
10189 * plus some tags with server generated contents. */
10190 handle_lsp_request(conn
, path
, file
, NULL
);
10191 } else if (match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
10192 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
10194 /* Lua in-server module script: a CGI like script used to generate
10197 mg_exec_lua_script(conn
, path
, NULL
);
10199 #if defined(USE_DUKTAPE)
10200 } else if (match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
10202 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
10204 /* Call duktape to generate the page */
10205 mg_exec_duktape_script(conn
, path
);
10207 #if !defined(NO_CGI)
10208 } else if (match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
10209 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
10211 /* CGI scripts may support all HTTP methods */
10212 handle_cgi_request(conn
, path
);
10213 #endif /* !NO_CGI */
10214 } else if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
10215 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
10217 handle_ssi_file_request(conn
, path
, file
);
10218 #if !defined(NO_CACHING)
10219 } else if ((!conn
->in_error_handler
) && is_not_modified(conn
, file
)) {
10220 /* Send 304 "Not Modified" - this must not send any body data */
10221 send_http_error(conn
, 304, "%s", "");
10222 #endif /* !NO_CACHING */
10224 handle_static_file_request(conn
, path
, file
, NULL
);
10230 close_all_listening_sockets(struct mg_context
*ctx
)
10237 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
10238 closesocket(ctx
->listening_sockets
[i
].sock
);
10239 ctx
->listening_sockets
[i
].sock
= INVALID_SOCKET
;
10241 mg_free(ctx
->listening_sockets
);
10242 ctx
->listening_sockets
= NULL
;
10243 mg_free(ctx
->listening_ports
);
10244 ctx
->listening_ports
= NULL
;
10248 /* Valid listening port specification is: [ip_address:]port[s]
10249 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
10250 * Examples for IPv6: [::]:80, [::1]:80,
10251 * [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443s
10252 * see https://tools.ietf.org/html/rfc3513#section-2.2 */
10254 parse_port_string(const struct vec
*vec
, struct socket
*so
)
10256 unsigned int a
, b
, c
, d
, port
;
10258 #if defined(USE_IPV6)
10259 char buf
[100] = {0};
10262 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
10263 * Also, all-zeroes in the socket address means binding to all addresses
10264 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
10265 memset(so
, 0, sizeof(*so
));
10266 so
->lsa
.sin
.sin_family
= AF_INET
;
10268 if (sscanf(vec
->ptr
, "%u.%u.%u.%u:%u%n", &a
, &b
, &c
, &d
, &port
, &len
)
10270 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
10271 so
->lsa
.sin
.sin_addr
.s_addr
=
10272 htonl((a
<< 24) | (b
<< 16) | (c
<< 8) | d
);
10273 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10274 #if defined(USE_IPV6)
10275 } else if (sscanf(vec
->ptr
, "[%49[^]]]:%u%n", buf
, &port
, &len
) == 2
10277 AF_INET6
, buf
, &so
->lsa
.sin6
, sizeof(so
->lsa
.sin6
))) {
10278 /* IPv6 address, examples: see above */
10279 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
10281 so
->lsa
.sin6
.sin6_port
= htons((uint16_t)port
);
10283 } else if (sscanf(vec
->ptr
, "%u%n", &port
, &len
) == 1) {
10284 /* If only port is specified, bind to IPv4, INADDR_ANY */
10285 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10287 /* Parsing failure. Make port invalid. */
10292 /* sscanf and the option splitting code ensure the following condition
10294 if ((len
< 0) && ((unsigned)len
> (unsigned)vec
->len
)) {
10297 ch
= vec
->ptr
[len
]; /* Next character after the port number */
10298 so
->is_ssl
= (ch
== 's');
10299 so
->ssl_redir
= (ch
== 'r');
10301 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
10302 return is_valid_port(port
)
10303 && (ch
== '\0' || ch
== 's' || ch
== 'r' || ch
== ',');
10308 set_ports_option(struct mg_context
*ctx
)
10312 #if defined(USE_IPV6)
10316 struct socket so
, *ptr
;
10318 in_port_t
*portPtr
;
10322 int portsTotal
= 0;
10329 memset(&so
, 0, sizeof(so
));
10330 memset(&usa
, 0, sizeof(usa
));
10332 list
= ctx
->config
[LISTENING_PORTS
];
10333 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10337 if (!parse_port_string(&vec
, &so
)) {
10339 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
10343 "[IP_ADDRESS:]PORT[s|r]");
10347 if (so
.is_ssl
&& ctx
->ssl_ctx
== NULL
) {
10350 "Cannot add SSL socket (entry %i). Is -ssl_certificate "
10356 if ((so
.sock
= socket(so
.lsa
.sa
.sa_family
, SOCK_STREAM
, 6))
10357 == INVALID_SOCKET
) {
10359 mg_cry(fc(ctx
), "cannot create socket (entry %i)", portsTotal
);
10364 /* Windows SO_REUSEADDR lets many procs binds to a
10365 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
10366 * if someone already has the socket -- DTL */
10367 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
10368 * Windows might need a few seconds before
10369 * the same port can be used again in the
10370 * same process, so a short Sleep may be
10371 * required between mg_stop and mg_start.
10373 if (setsockopt(so
.sock
,
10375 SO_EXCLUSIVEADDRUSE
,
10376 (SOCK_OPT_TYPE
)&on
,
10377 sizeof(on
)) != 0) {
10380 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
10384 if (setsockopt(so
.sock
,
10387 (SOCK_OPT_TYPE
)&on
,
10388 sizeof(on
)) != 0) {
10391 "cannot set socket option SO_REUSEADDR (entry %i)",
10396 #if defined(USE_IPV6)
10397 if (so
.lsa
.sa
.sa_family
== AF_INET6
10398 && setsockopt(so
.sock
,
10402 sizeof(off
)) != 0) {
10405 "cannot set socket option IPV6_V6ONLY (entry %i)",
10410 if (so
.lsa
.sa
.sa_family
== AF_INET
) {
10412 len
= sizeof(so
.lsa
.sin
);
10413 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10415 "cannot bind to %.*s: %d (%s)",
10420 closesocket(so
.sock
);
10421 so
.sock
= INVALID_SOCKET
;
10425 #if defined(USE_IPV6)
10426 else if (so
.lsa
.sa
.sa_family
== AF_INET6
) {
10428 len
= sizeof(so
.lsa
.sin6
);
10429 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10431 "cannot bind to IPv6 %.*s: %d (%s)",
10436 closesocket(so
.sock
);
10437 so
.sock
= INVALID_SOCKET
;
10444 "cannot bind: address family not supported (entry %i)",
10449 if (listen(so
.sock
, SOMAXCONN
) != 0) {
10452 "cannot listen to %.*s: %d (%s)",
10457 closesocket(so
.sock
);
10458 so
.sock
= INVALID_SOCKET
;
10462 if (getsockname(so
.sock
, &(usa
.sa
), &len
) != 0) {
10464 int err
= (int)ERRNO
;
10466 "call to getsockname failed %.*s: %d (%s)",
10471 closesocket(so
.sock
);
10472 so
.sock
= INVALID_SOCKET
;
10476 if ((ptr
= (struct socket
*)
10477 mg_realloc(ctx
->listening_sockets
,
10478 (ctx
->num_listening_sockets
+ 1)
10479 * sizeof(ctx
->listening_sockets
[0]))) == NULL
) {
10481 mg_cry(fc(ctx
), "%s", "Out of memory");
10482 closesocket(so
.sock
);
10483 so
.sock
= INVALID_SOCKET
;
10488 (in_port_t
*)mg_realloc(ctx
->listening_ports
,
10489 (ctx
->num_listening_sockets
+ 1)
10490 * sizeof(ctx
->listening_ports
[0])))
10493 mg_cry(fc(ctx
), "%s", "Out of memory");
10494 closesocket(so
.sock
);
10495 so
.sock
= INVALID_SOCKET
;
10500 set_close_on_exec(so
.sock
, fc(ctx
));
10501 ctx
->listening_sockets
= ptr
;
10502 ctx
->listening_sockets
[ctx
->num_listening_sockets
] = so
;
10503 ctx
->listening_ports
= portPtr
;
10504 ctx
->listening_ports
[ctx
->num_listening_sockets
] =
10505 ntohs(usa
.sin
.sin_port
);
10506 ctx
->num_listening_sockets
++;
10510 if (portsOk
!= portsTotal
) {
10511 close_all_listening_sockets(ctx
);
10519 static const char *
10520 header_val(const struct mg_connection
*conn
, const char *header
)
10522 const char *header_value
;
10524 if ((header_value
= mg_get_header(conn
, header
)) == NULL
) {
10527 return header_value
;
10533 log_access(const struct mg_connection
*conn
)
10535 const struct mg_request_info
*ri
;
10537 char date
[64], src_addr
[IP_ADDR_STR_LEN
];
10540 const char *referer
;
10541 const char *user_agent
;
10545 if (!conn
|| !conn
->ctx
) {
10549 if (conn
->ctx
->config
[ACCESS_LOG_FILE
] != NULL
) {
10550 if (mg_fopen(conn
, conn
->ctx
->config
[ACCESS_LOG_FILE
], "a+", &fi
)
10558 if (fi
.fp
== NULL
&& conn
->ctx
->callbacks
.log_message
== NULL
) {
10562 tm
= localtime(&conn
->conn_birth_time
);
10564 strftime(date
, sizeof(date
), "%d/%b/%Y:%H:%M:%S %z", tm
);
10566 mg_strlcpy(date
, "01/Jan/1970:00:00:00 +0000", sizeof(date
));
10567 date
[sizeof(date
) - 1] = '\0';
10570 ri
= &conn
->request_info
;
10572 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
10573 referer
= header_val(conn
, "Referer");
10574 user_agent
= header_val(conn
, "User-Agent");
10577 NULL
, /* Ignore truncation in access log */
10580 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT
" %s %s",
10582 ri
->remote_user
== NULL
? "-" : ri
->remote_user
,
10584 ri
->request_method
? ri
->request_method
: "-",
10585 ri
->request_uri
? ri
->request_uri
: "-",
10586 ri
->query_string
? "?" : "",
10587 ri
->query_string
? ri
->query_string
: "",
10590 conn
->num_bytes_sent
,
10594 if (conn
->ctx
->callbacks
.log_access
) {
10595 conn
->ctx
->callbacks
.log_access(conn
, buf
);
10600 fprintf(fi
.fp
, "%s\n", buf
);
10602 funlockfile(fi
.fp
);
10608 /* Verify given socket address against the ACL.
10609 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
10612 check_acl(struct mg_context
*ctx
, uint32_t remote_ip
)
10615 uint32_t net
, mask
;
10619 const char *list
= ctx
->config
[ACCESS_CONTROL_LIST
];
10621 /* If any ACL is set, deny by default */
10622 allowed
= list
== NULL
? '+' : '-';
10624 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10626 if ((flag
!= '+' && flag
!= '-')
10627 || parse_net(&vec
.ptr
[1], &net
, &mask
) == 0) {
10629 "%s: subnet must be [+|-]x.x.x.x[/x]",
10634 if (net
== (remote_ip
& mask
)) {
10639 return allowed
== '+';
10645 #if !defined(_WIN32)
10647 set_uid_option(struct mg_context
*ctx
)
10651 const char *uid
= ctx
->config
[RUN_AS_USER
];
10657 if ((pw
= getpwnam(uid
)) == NULL
) {
10658 mg_cry(fc(ctx
), "%s: unknown user [%s]", __func__
, uid
);
10659 } else if (setgid(pw
->pw_gid
) == -1) {
10661 "%s: setgid(%s): %s",
10665 } else if (setgroups(0, NULL
)) {
10667 "%s: setgroups(): %s",
10670 } else if (setuid(pw
->pw_uid
) == -1) {
10672 "%s: setuid(%s): %s",
10685 #endif /* !_WIN32 */
10689 tls_dtor(void *key
)
10691 struct mg_workerTLS
*tls
= (struct mg_workerTLS
*)key
;
10692 /* key == pthread_getspecific(sTlsKey); */
10695 if (tls
->is_master
== 2) {
10696 tls
->is_master
= -3; /* Mark memory as dead */
10700 pthread_setspecific(sTlsKey
, NULL
);
10704 #if !defined(NO_SSL)
10706 /* Must be set if sizeof(pthread_t) > sizeof(unsigned long) */
10707 static unsigned long
10708 ssl_id_callback(void)
10711 return GetCurrentThreadId();
10715 #pragma clang diagnostic push
10716 #pragma clang diagnostic ignored "-Wunreachable-code"
10717 /* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
10718 * or not, so one of the two conditions will be unreachable by construction.
10719 * Unfortunately the C standard does not define a way to check this at
10720 * compile time, since the #if preprocessor conditions can not use the sizeof
10721 * operator as an argument. */
10724 if (sizeof(pthread_t
) > sizeof(unsigned long)) {
10725 /* This is the problematic case for CRYPTO_set_id_callback:
10726 * The OS pthread_t can not be cast to unsigned long. */
10727 struct mg_workerTLS
*tls
=
10728 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
10730 /* SSL called from an unknown thread: Create some thread index.
10732 tls
= (struct mg_workerTLS
*)mg_malloc(sizeof(struct mg_workerTLS
));
10733 tls
->is_master
= -2; /* -2 means "3rd party thread" */
10734 tls
->thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
10735 pthread_setspecific(sTlsKey
, tls
);
10737 return tls
->thread_idx
;
10739 /* pthread_t may be any data type, so a simple cast to unsigned long
10740 * can rise a warning/error, depending on the platform.
10741 * Here memcpy is used as an anything-to-anything cast. */
10742 unsigned long ret
= 0;
10743 pthread_t t
= pthread_self();
10744 memcpy(&ret
, &t
, sizeof(pthread_t
));
10749 #pragma clang diagnostic pop
10756 static int ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
);
10757 static const char *ssl_error(void);
10761 refresh_trust(struct mg_connection
*conn
)
10763 static int reload_lock
= 0;
10764 static long int data_check
= 0;
10766 struct stat cert_buf
;
10769 int should_verify_peer
;
10771 if ((pem
= conn
->ctx
->config
[SSL_CERTIFICATE
]) == NULL
10772 && conn
->ctx
->callbacks
.init_ssl
== NULL
) {
10777 if (stat(pem
, &cert_buf
) != -1) {
10778 t
= (long int)cert_buf
.st_mtime
;
10781 if (data_check
!= t
) {
10784 should_verify_peer
=
10785 (conn
->ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
10786 && (mg_strcasecmp(conn
->ctx
->config
[SSL_DO_VERIFY_PEER
], "yes")
10789 if (should_verify_peer
) {
10790 char *ca_path
= conn
->ctx
->config
[SSL_CA_PATH
];
10791 char *ca_file
= conn
->ctx
->config
[SSL_CA_FILE
];
10792 if (SSL_CTX_load_verify_locations(conn
->ctx
->ssl_ctx
,
10795 mg_cry(fc(conn
->ctx
),
10796 "SSL_CTX_load_verify_locations error: %s "
10797 "ssl_verify_peer requires setting "
10798 "either ssl_ca_path or ssl_ca_file. Is any of them "
10806 if (!reload_lock
) {
10808 if (ssl_use_pem_file(conn
->ctx
, pem
) == 0) {
10814 /* lock while cert is reloading */
10815 while (reload_lock
) {
10823 static pthread_mutex_t
*ssl_mutexes
;
10827 sslize(struct mg_connection
*conn
, SSL_CTX
*s
, int (*func
)(SSL
*))
10837 (conn
->ctx
->config
[SSL_SHORT_TRUST
] != NULL
)
10838 && (mg_strcasecmp(conn
->ctx
->config
[SSL_SHORT_TRUST
], "yes") == 0);
10841 int trust_ret
= refresh_trust(conn
);
10847 conn
->ssl
= SSL_new(s
);
10848 if (conn
->ssl
== NULL
) {
10852 ret
= SSL_set_fd(conn
->ssl
, conn
->client
.sock
);
10854 err
= SSL_get_error(conn
->ssl
, ret
);
10855 (void)err
; /* TODO: set some error message */
10856 SSL_free(conn
->ssl
);
10858 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10860 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10861 ERR_remove_state(0);
10865 ret
= func(conn
->ssl
);
10867 err
= SSL_get_error(conn
->ssl
, ret
);
10868 (void)err
; /* TODO: set some error message */
10869 SSL_free(conn
->ssl
);
10871 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10873 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10874 ERR_remove_state(0);
10882 /* Return OpenSSL error message (from CRYPTO lib) */
10883 static const char *
10887 err
= ERR_get_error();
10888 return err
== 0 ? "" : ERR_error_string(err
, NULL
);
10893 ssl_locking_callback(int mode
, int mutex_num
, const char *file
, int line
)
10899 /* 1 is CRYPTO_LOCK */
10900 (void)pthread_mutex_lock(&ssl_mutexes
[mutex_num
]);
10902 (void)pthread_mutex_unlock(&ssl_mutexes
[mutex_num
]);
10907 #if !defined(NO_SSL_DL)
10909 load_dll(struct mg_context
*ctx
, const char *dll_name
, struct ssl_func
*sw
)
10916 struct ssl_func
*fp
;
10918 if ((dll_handle
= dlopen(dll_name
, RTLD_LAZY
)) == NULL
) {
10919 mg_cry(fc(ctx
), "%s: cannot load %s", __func__
, dll_name
);
10923 for (fp
= sw
; fp
->name
!= NULL
; fp
++) {
10925 /* GetProcAddress() returns pointer to function */
10926 u
.fp
= (void (*)(void))dlsym(dll_handle
, fp
->name
);
10928 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
10929 * pointers to function pointers. We need to use a union to make a
10931 u
.p
= dlsym(dll_handle
, fp
->name
);
10932 #endif /* _WIN32 */
10933 if (u
.fp
== NULL
) {
10935 "%s: %s: cannot find %s",
10939 dlclose(dll_handle
);
10950 static void *ssllib_dll_handle
; /* Store the ssl library handle. */
10951 static void *cryptolib_dll_handle
; /* Store the crypto library handle. */
10953 #endif /* NO_SSL_DL */
10956 #if defined(SSL_ALREADY_INITIALIZED)
10957 static int cryptolib_users
= 1; /* Reference counter for crypto library. */
10959 static int cryptolib_users
= 0; /* Reference counter for crypto library. */
10964 initialize_ssl(struct mg_context
*ctx
)
10969 #if !defined(NO_SSL_DL)
10970 if (!cryptolib_dll_handle
) {
10971 cryptolib_dll_handle
= load_dll(ctx
, CRYPTO_LIB
, crypto_sw
);
10972 if (!cryptolib_dll_handle
) {
10976 #endif /* NO_SSL_DL */
10978 if (mg_atomic_inc(&cryptolib_users
) > 1) {
10982 /* Initialize locking callbacks, needed for thread safety.
10983 * http://www.openssl.org/support/faq.html#PROG1
10985 i
= CRYPTO_num_locks();
10989 size
= sizeof(pthread_mutex_t
) * ((size_t)(i
));
10990 if ((ssl_mutexes
= (pthread_mutex_t
*)mg_malloc(size
)) == NULL
) {
10992 "%s: cannot allocate mutexes: %s",
10998 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
10999 pthread_mutex_init(&ssl_mutexes
[i
], &pthread_mutex_attr
);
11002 CRYPTO_set_locking_callback(&ssl_locking_callback
);
11003 CRYPTO_set_id_callback(&ssl_id_callback
);
11010 ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
)
11012 if (SSL_CTX_use_certificate_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11014 "%s: cannot open certificate file %s: %s",
11021 /* could use SSL_CTX_set_default_passwd_cb_userdata */
11022 if (SSL_CTX_use_PrivateKey_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11024 "%s: cannot open private key file %s: %s",
11031 if (SSL_CTX_check_private_key(ctx
->ssl_ctx
) == 0) {
11033 "%s: certificate and private key do not match: %s",
11039 if (SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
) == 0) {
11041 "%s: cannot use certificate chain file %s: %s",
11052 ssl_get_protocol(int version_id
)
11054 long ret
= SSL_OP_ALL
;
11055 if (version_id
> 0)
11056 ret
|= SSL_OP_NO_SSLv2
;
11057 if (version_id
> 1)
11058 ret
|= SSL_OP_NO_SSLv3
;
11059 if (version_id
> 2)
11060 ret
|= SSL_OP_NO_TLSv1
;
11061 if (version_id
> 3)
11062 ret
|= SSL_OP_NO_TLSv1_1
;
11067 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
11069 set_ssl_option(struct mg_context
*ctx
)
11073 int should_verify_peer
;
11074 const char *ca_path
;
11075 const char *ca_file
;
11076 int use_default_verify_paths
;
11078 time_t now_rt
= time(NULL
);
11079 struct timespec now_mt
;
11080 md5_byte_t ssl_context_id
[16];
11081 md5_state_t md5state
;
11084 /* If PEM file is not specified and the init_ssl callback
11085 * is not specified, skip SSL initialization. */
11089 if ((pem
= ctx
->config
[SSL_CERTIFICATE
]) == NULL
11090 && ctx
->callbacks
.init_ssl
== NULL
) {
11094 if (!initialize_ssl(ctx
)) {
11098 #if !defined(NO_SSL_DL)
11099 if (!ssllib_dll_handle
) {
11100 ssllib_dll_handle
= load_dll(ctx
, SSL_LIB
, ssl_sw
);
11101 if (!ssllib_dll_handle
) {
11105 #endif /* NO_SSL_DL */
11107 /* Initialize SSL library */
11108 SSL_library_init();
11109 SSL_load_error_strings();
11111 if ((ctx
->ssl_ctx
= SSL_CTX_new(SSLv23_server_method())) == NULL
) {
11112 mg_cry(fc(ctx
), "SSL_CTX_new (server) error: %s", ssl_error());
11116 SSL_CTX_clear_options(ctx
->ssl_ctx
,
11117 SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
| SSL_OP_NO_TLSv1
11118 | SSL_OP_NO_TLSv1_1
);
11119 protocol_ver
= atoi(ctx
->config
[SSL_PROTOCOL_VERSION
]);
11120 SSL_CTX_set_options(ctx
->ssl_ctx
, ssl_get_protocol(protocol_ver
));
11121 SSL_CTX_set_options(ctx
->ssl_ctx
, SSL_OP_SINGLE_DH_USE
);
11122 SSL_CTX_set_ecdh_auto(ctx
->ssl_ctx
, 1);
11124 /* If a callback has been specified, call it. */
11126 (ctx
->callbacks
.init_ssl
== NULL
)
11128 : (ctx
->callbacks
.init_ssl(ctx
->ssl_ctx
, ctx
->user_data
));
11130 /* If callback returns 0, civetweb sets up the SSL certificate.
11131 * If it returns 1, civetweb assumes the calback already did this.
11132 * If it returns -1, initializing ssl fails. */
11133 if (callback_ret
< 0) {
11134 mg_cry(fc(ctx
), "SSL callback returned error: %i", callback_ret
);
11137 if (callback_ret
> 0) {
11139 (void)SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
);
11144 /* Use some UID as session context ID. */
11145 md5_init(&md5state
);
11146 md5_append(&md5state
, (const md5_byte_t
*)&now_rt
, sizeof(now_rt
));
11147 clock_gettime(CLOCK_MONOTONIC
, &now_mt
);
11148 md5_append(&md5state
, (const md5_byte_t
*)&now_mt
, sizeof(now_mt
));
11149 md5_append(&md5state
,
11150 (const md5_byte_t
*)ctx
->config
[LISTENING_PORTS
],
11151 strlen(ctx
->config
[LISTENING_PORTS
]));
11152 md5_append(&md5state
, (const md5_byte_t
*)ctx
, sizeof(*ctx
));
11153 md5_finish(&md5state
, ssl_context_id
);
11155 SSL_CTX_set_session_id_context(ctx
->ssl_ctx
,
11156 (const unsigned char *)&ssl_context_id
,
11157 sizeof(ssl_context_id
));
11160 if (!ssl_use_pem_file(ctx
, pem
)) {
11165 should_verify_peer
=
11166 (ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
11167 && (mg_strcasecmp(ctx
->config
[SSL_DO_VERIFY_PEER
], "yes") == 0);
11169 use_default_verify_paths
=
11170 (ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
] != NULL
)
11171 && (mg_strcasecmp(ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
], "yes") == 0);
11173 if (should_verify_peer
) {
11174 ca_path
= ctx
->config
[SSL_CA_PATH
];
11175 ca_file
= ctx
->config
[SSL_CA_FILE
];
11176 if (SSL_CTX_load_verify_locations(ctx
->ssl_ctx
, ca_file
, ca_path
)
11179 "SSL_CTX_load_verify_locations error: %s "
11180 "ssl_verify_peer requires setting "
11181 "either ssl_ca_path or ssl_ca_file. Is any of them "
11188 SSL_CTX_set_verify(ctx
->ssl_ctx
,
11189 SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
,
11192 if (use_default_verify_paths
11193 && SSL_CTX_set_default_verify_paths(ctx
->ssl_ctx
) != 1) {
11195 "SSL_CTX_set_default_verify_paths error: %s",
11200 if (ctx
->config
[SSL_VERIFY_DEPTH
]) {
11201 verify_depth
= atoi(ctx
->config
[SSL_VERIFY_DEPTH
]);
11202 SSL_CTX_set_verify_depth(ctx
->ssl_ctx
, verify_depth
);
11206 if (ctx
->config
[SSL_CIPHER_LIST
] != NULL
) {
11207 if (SSL_CTX_set_cipher_list(ctx
->ssl_ctx
, ctx
->config
[SSL_CIPHER_LIST
])
11209 mg_cry(fc(ctx
), "SSL_CTX_set_cipher_list error: %s", ssl_error());
11218 uninitialize_ssl(struct mg_context
*ctx
)
11223 if (mg_atomic_dec(&cryptolib_users
) == 0) {
11225 /* Shutdown according to
11226 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
11227 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
11229 CRYPTO_set_locking_callback(NULL
);
11230 CRYPTO_set_id_callback(NULL
);
11232 CONF_modules_unload(1);
11233 ERR_free_strings();
11235 CRYPTO_cleanup_all_ex_data();
11236 ERR_remove_state(0);
11238 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11239 pthread_mutex_destroy(&ssl_mutexes
[i
]);
11241 mg_free(ssl_mutexes
);
11242 ssl_mutexes
= NULL
;
11245 #endif /* !NO_SSL */
11249 set_gpass_option(struct mg_context
*ctx
)
11252 struct file file
= STRUCT_FILE_INITIALIZER
;
11253 const char *path
= ctx
->config
[GLOBAL_PASSWORDS_FILE
];
11254 if (path
!= NULL
&& !mg_stat(fc(ctx
), path
, &file
)) {
11255 mg_cry(fc(ctx
), "Cannot open %s: %s", path
, strerror(ERRNO
));
11265 set_acl_option(struct mg_context
*ctx
)
11267 return check_acl(ctx
, (uint32_t)0x7f000001UL
) != -1;
11272 reset_per_request_attributes(struct mg_connection
*conn
)
11277 conn
->path_info
= NULL
;
11278 conn
->num_bytes_sent
= conn
->consumed_content
= 0;
11279 conn
->status_code
= -1;
11280 conn
->is_chunked
= 0;
11281 conn
->must_close
= conn
->request_len
= conn
->throttle
= 0;
11282 conn
->request_info
.content_length
= -1;
11283 conn
->request_info
.remote_user
= NULL
;
11284 conn
->request_info
.request_method
= NULL
;
11285 conn
->request_info
.request_uri
= NULL
;
11286 conn
->request_info
.local_uri
= NULL
;
11287 conn
->request_info
.uri
= NULL
; /* TODO: cleanup uri,
11288 * local_uri and request_uri */
11289 conn
->request_info
.http_version
= NULL
;
11290 conn
->request_info
.num_headers
= 0;
11291 conn
->data_len
= 0;
11292 conn
->chunk_remainder
= 0;
11293 conn
->internal_error
= 0;
11298 set_sock_timeout(SOCKET sock
, int milliseconds
)
11300 int r0
= 0, r1
, r2
;
11303 /* Windows specific */
11305 DWORD tv
= (DWORD
)milliseconds
;
11308 /* Linux, ... (not Windows) */
11312 /* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
11313 * max. time waiting for the acknowledged of TCP data before the connection
11314 * will be forcefully closed and ETIMEDOUT is returned to the application.
11315 * If this option is not set, the default timeout of 20-30 minutes is used.
11317 /* #define TCP_USER_TIMEOUT (18) */
11319 #if defined(TCP_USER_TIMEOUT)
11320 unsigned int uto
= (unsigned int)milliseconds
;
11321 r0
= setsockopt(sock
, 6, TCP_USER_TIMEOUT
, (const void *)&uto
, sizeof(uto
));
11324 memset(&tv
, 0, sizeof(tv
));
11325 tv
.tv_sec
= milliseconds
/ 1000;
11326 tv
.tv_usec
= (milliseconds
* 1000) % 1000000;
11328 #endif /* _WIN32 */
11331 sock
, SOL_SOCKET
, SO_RCVTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11333 sock
, SOL_SOCKET
, SO_SNDTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11335 return r0
|| r1
|| r2
;
11340 set_tcp_nodelay(SOCKET sock
, int nodelay_on
)
11342 if (setsockopt(sock
,
11345 (SOCK_OPT_TYPE
)&nodelay_on
,
11346 sizeof(nodelay_on
)) != 0) {
11356 close_socket_gracefully(struct mg_connection
*conn
)
11358 #if defined(_WIN32)
11359 char buf
[MG_BUF_LEN
];
11362 struct linger linger
;
11368 /* Set linger option to avoid socket hanging out after close. This
11370 * ephemeral port exhaust problem under high QPS. */
11371 linger
.l_onoff
= 1;
11372 linger
.l_linger
= 1;
11374 if (setsockopt(conn
->client
.sock
,
11378 sizeof(linger
)) != 0) {
11380 "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
11385 /* Send FIN to the client */
11386 shutdown(conn
->client
.sock
, SHUT_WR
);
11387 set_non_blocking_mode(conn
->client
.sock
);
11389 #if defined(_WIN32)
11390 /* Read and discard pending incoming data. If we do not do that and
11392 * the socket, the data in the send buffer may be discarded. This
11393 * behaviour is seen on Windows, when client keeps sending data
11394 * when server decides to close the connection; then when client
11395 * does recv() it gets no data back. */
11398 NULL
, conn
, buf
, sizeof(buf
), 1E-10 /* TODO: allow 0 as timeout */);
11402 /* Now we know that our FIN is ACK-ed, safe to close */
11403 closesocket(conn
->client
.sock
);
11404 conn
->client
.sock
= INVALID_SOCKET
;
11409 close_connection(struct mg_connection
*conn
)
11411 if (!conn
|| !conn
->ctx
) {
11415 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
11416 if (conn
->lua_websocket_state
) {
11417 lua_websocket_close(conn
, conn
->lua_websocket_state
);
11418 conn
->lua_websocket_state
= NULL
;
11422 /* call the connection_close callback if assigned */
11423 if ((conn
->ctx
->callbacks
.connection_close
!= NULL
)
11424 && (conn
->ctx
->context_type
== 1)) {
11425 conn
->ctx
->callbacks
.connection_close(conn
);
11428 mg_lock_connection(conn
);
11430 conn
->must_close
= 1;
11433 if (conn
->ssl
!= NULL
) {
11434 /* Run SSL_shutdown twice to ensure completly close SSL connection
11436 SSL_shutdown(conn
->ssl
);
11437 SSL_free(conn
->ssl
);
11438 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
11440 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
11441 ERR_remove_state(0);
11445 if (conn
->client
.sock
!= INVALID_SOCKET
) {
11446 close_socket_gracefully(conn
);
11447 conn
->client
.sock
= INVALID_SOCKET
;
11450 mg_unlock_connection(conn
);
11454 mg_close_connection(struct mg_connection
*conn
)
11456 struct mg_context
*client_ctx
= NULL
;
11459 if (conn
== NULL
) {
11463 if (conn
->ctx
->context_type
== 2) {
11464 client_ctx
= conn
->ctx
;
11465 /* client context: loops must end */
11466 conn
->ctx
->stop_flag
= 1;
11470 if (conn
->client_ssl_ctx
!= NULL
) {
11471 SSL_CTX_free((SSL_CTX
*)conn
->client_ssl_ctx
);
11474 close_connection(conn
);
11475 if (client_ctx
!= NULL
) {
11476 /* join worker thread and free context */
11477 for (i
= 0; i
< client_ctx
->cfg_worker_threads
; i
++) {
11478 if (client_ctx
->workerthreadids
[i
] != 0) {
11479 mg_join_thread(client_ctx
->workerthreadids
[i
]);
11482 mg_free(client_ctx
->workerthreadids
);
11483 mg_free(client_ctx
);
11484 (void)pthread_mutex_destroy(&conn
->mutex
);
11490 static struct mg_connection
*
11491 mg_connect_client_impl(const struct mg_client_options
*client_options
,
11496 static struct mg_context fake_ctx
;
11497 struct mg_connection
*conn
= NULL
;
11501 if (!connect_socket(&fake_ctx
,
11502 client_options
->host
,
11503 client_options
->port
,
11510 } else if ((conn
= (struct mg_connection
*)
11511 mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
)) == NULL
) {
11513 NULL
, /* No truncation check for ebuf */
11521 && (conn
->client_ssl_ctx
= SSL_CTX_new(SSLv23_client_method()))
11524 NULL
, /* No truncation check for ebuf */
11527 "SSL_CTX_new error");
11531 #endif /* NO_SSL */
11536 socklen_t len
= (sa
.sa
.sa_family
== AF_INET
)
11537 ? sizeof(conn
->client
.rsa
.sin
)
11538 : sizeof(conn
->client
.rsa
.sin6
);
11539 struct sockaddr
*psa
=
11540 (sa
.sa
.sa_family
== AF_INET
)
11541 ? (struct sockaddr
*)&(conn
->client
.rsa
.sin
)
11542 : (struct sockaddr
*)&(conn
->client
.rsa
.sin6
);
11544 socklen_t len
= sizeof(conn
->client
.rsa
.sin
);
11545 struct sockaddr
*psa
= (struct sockaddr
*)&(conn
->client
.rsa
.sin
);
11548 conn
->buf_size
= MAX_REQUEST_SIZE
;
11549 conn
->buf
= (char *)(conn
+ 1);
11550 conn
->ctx
= &fake_ctx
;
11551 conn
->client
.sock
= sock
;
11552 conn
->client
.lsa
= sa
;
11554 if (getsockname(sock
, psa
, &len
) != 0) {
11556 "%s: getsockname() failed: %s",
11561 conn
->client
.is_ssl
= use_ssl
? 1 : 0;
11562 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
11566 fake_ctx
.ssl_ctx
= conn
->client_ssl_ctx
;
11568 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
11569 * SSL_CTX_set_verify call is needed to switch off server
11570 * certificate checking, which is off by default in OpenSSL and
11572 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
11573 * SSL_VERIFY_PEER, verify_ssl_server); */
11575 if (client_options
->client_cert
) {
11576 if (!ssl_use_pem_file(&fake_ctx
, client_options
->client_cert
)) {
11578 NULL
, /* No truncation check for ebuf */
11581 "Can not use SSL client certificate");
11582 SSL_CTX_free(conn
->client_ssl_ctx
);
11589 if (client_options
->server_cert
) {
11590 SSL_CTX_load_verify_locations(conn
->client_ssl_ctx
,
11591 client_options
->server_cert
,
11593 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_PEER
, NULL
);
11595 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
11598 if (!sslize(conn
, conn
->client_ssl_ctx
, SSL_connect
)) {
11600 NULL
, /* No truncation check for ebuf */
11603 "SSL connection error");
11604 SSL_CTX_free(conn
->client_ssl_ctx
);
11617 CIVETWEB_API
struct mg_connection
*
11618 mg_connect_client_secure(const struct mg_client_options
*client_options
,
11619 char *error_buffer
,
11620 size_t error_buffer_size
)
11622 return mg_connect_client_impl(client_options
,
11625 error_buffer_size
);
11629 struct mg_connection
*
11630 mg_connect_client(const char *host
,
11633 char *error_buffer
,
11634 size_t error_buffer_size
)
11636 struct mg_client_options opts
;
11637 memset(&opts
, 0, sizeof(opts
));
11640 return mg_connect_client_impl(&opts
,
11643 error_buffer_size
);
11647 static const struct {
11650 unsigned default_port
;
11651 } abs_uri_protocols
[] = {{"http://", 7, 80},
11652 {"https://", 8, 443},
11654 {"wss://", 6, 443},
11658 /* Check if the uri is valid.
11659 * return 0 for invalid uri,
11661 * return 2 for relative uri,
11662 * return 3 for absolute uri without port,
11663 * return 4 for absolute uri with port */
11665 get_uri_type(const char *uri
)
11668 char *hostend
, *portbegin
, *portend
;
11669 unsigned long port
;
11671 /* According to the HTTP standard
11672 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
11673 * URI can be an asterisk (*) or should start with slash (relative uri),
11674 * or it should start with the protocol (absolute uri). */
11675 if (uri
[0] == '*' && uri
[1] == '\0') {
11679 if (uri
[0] == '/') {
11684 /* It could be an absolute uri: */
11685 /* This function only checks if the uri is valid, not if it is
11686 * addressing the current server. So civetweb can also be used
11687 * as a proxy server. */
11688 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11689 if (mg_strncasecmp(uri
,
11690 abs_uri_protocols
[i
].proto
,
11691 abs_uri_protocols
[i
].proto_len
) == 0) {
11693 hostend
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, '/');
11697 portbegin
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, ':');
11702 port
= strtoul(portbegin
+ 1, &portend
, 10);
11703 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11715 /* Return NULL or the relative uri at the current server */
11716 static const char *
11717 get_rel_url_at_current_server(const char *uri
, const struct mg_connection
*conn
)
11719 const char *server_domain
;
11720 size_t server_domain_len
;
11721 size_t request_domain_len
= 0;
11722 unsigned long port
= 0;
11724 const char *hostbegin
= NULL
;
11725 const char *hostend
= NULL
;
11726 const char *portbegin
;
11729 /* DNS is case insensitive, so use case insensitive string compare here
11731 server_domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
11732 if (!server_domain
) {
11735 server_domain_len
= strlen(server_domain
);
11736 if (!server_domain_len
) {
11740 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11741 if (mg_strncasecmp(uri
,
11742 abs_uri_protocols
[i
].proto
,
11743 abs_uri_protocols
[i
].proto_len
) == 0) {
11745 hostbegin
= uri
+ abs_uri_protocols
[i
].proto_len
;
11746 hostend
= strchr(hostbegin
, '/');
11750 portbegin
= strchr(hostbegin
, ':');
11751 if ((!portbegin
) || (portbegin
> hostend
)) {
11752 port
= abs_uri_protocols
[i
].default_port
;
11753 request_domain_len
= (size_t)(hostend
- hostbegin
);
11755 port
= strtoul(portbegin
+ 1, &portend
, 10);
11756 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11759 request_domain_len
= (size_t)(portbegin
- hostbegin
);
11761 /* protocol found, port set */
11767 /* port remains 0 if the protocol is not found */
11771 #if defined(USE_IPV6)
11772 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
11773 if (ntohs(conn
->client
.lsa
.sin6
.sin6_port
) != port
) {
11774 /* Request is directed to a different port */
11780 if (ntohs(conn
->client
.lsa
.sin
.sin_port
) != port
) {
11781 /* Request is directed to a different port */
11786 if ((request_domain_len
!= server_domain_len
)
11787 || (0 != memcmp(server_domain
, hostbegin
, server_domain_len
))) {
11788 /* Request is directed to another server */
11797 getreq(struct mg_connection
*conn
, char *ebuf
, size_t ebuf_len
, int *err
)
11801 if (ebuf_len
> 0) {
11806 reset_per_request_attributes(conn
);
11810 NULL
, /* No truncation check for ebuf */
11818 /* Set the time the request was received. This value should be used for
11820 clock_gettime(CLOCK_MONOTONIC
, &(conn
->req_time
));
11822 conn
->request_len
=
11823 read_request(NULL
, conn
, conn
->buf
, conn
->buf_size
, &conn
->data_len
);
11824 /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
11826 if (conn
->request_len
>= 0 && conn
->data_len
< conn
->request_len
) {
11828 NULL
, /* No truncation check for ebuf */
11832 "Invalid request size");
11837 if (conn
->request_len
== 0 && conn
->data_len
== conn
->buf_size
) {
11839 NULL
, /* No truncation check for ebuf */
11843 "Request Too Large");
11846 } else if (conn
->request_len
<= 0) {
11847 if (conn
->data_len
> 0) {
11849 NULL
, /* No truncation check for ebuf */
11853 "Client sent malformed request");
11856 /* Server did not send anything -> just close the connection */
11857 conn
->must_close
= 1;
11859 NULL
, /* No truncation check for ebuf */
11863 "Client did not send a request");
11867 } else if (parse_http_message(conn
->buf
,
11869 &conn
->request_info
) <= 0) {
11871 NULL
, /* No truncation check for ebuf */
11879 /* Message is a valid request or response */
11880 if ((cl
= get_header(&conn
->request_info
, "Content-Length")) != NULL
) {
11881 /* Request/response has content length set */
11882 char *endptr
= NULL
;
11883 conn
->content_len
= strtoll(cl
, &endptr
, 10);
11884 if (endptr
== cl
) {
11886 NULL
, /* No truncation check for ebuf */
11894 /* Publish the content length back to the request info. */
11895 conn
->request_info
.content_length
= conn
->content_len
;
11896 } else if ((cl
= get_header(&conn
->request_info
, "Transfer-Encoding"))
11898 && !mg_strcasecmp(cl
, "chunked")) {
11899 conn
->is_chunked
= 1;
11900 } else if (!mg_strcasecmp(conn
->request_info
.request_method
, "POST")
11901 || !mg_strcasecmp(conn
->request_info
.request_method
,
11903 /* POST or PUT request without content length set */
11904 conn
->content_len
= -1;
11905 } else if (!mg_strncasecmp(conn
->request_info
.request_method
,
11908 /* Response without content length set */
11909 conn
->content_len
= -1;
11911 /* Other request */
11912 conn
->content_len
= 0;
11920 mg_get_response(struct mg_connection
*conn
,
11926 /* Implementation of API function for HTTP clients */
11928 struct mg_context
*octx
= conn
->ctx
;
11929 struct mg_context rctx
= *(conn
->ctx
);
11930 char txt
[32]; /* will not overflow */
11932 if (timeout
>= 0) {
11933 mg_snprintf(conn
, NULL
, txt
, sizeof(txt
), "%i", timeout
);
11934 rctx
.config
[REQUEST_TIMEOUT
] = txt
;
11935 set_sock_timeout(conn
->client
.sock
, timeout
);
11937 rctx
.config
[REQUEST_TIMEOUT
] = NULL
;
11941 ret
= getreq(conn
, ebuf
, ebuf_len
, &err
);
11944 /* TODO: 1) uri is deprecated;
11945 * 2) here, ri.uri is the http response code */
11946 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
11948 /* TODO (mid): Define proper return values - maybe return length?
11949 * For the first test use <0 for error and >0 for OK */
11950 return (ret
== 0) ? -1 : +1;
11956 struct mg_connection
*
11957 mg_download(const char *host
,
11965 struct mg_connection
*conn
;
11973 /* open a connection */
11974 conn
= mg_connect_client(host
, port
, use_ssl
, ebuf
, ebuf_len
);
11976 if (conn
!= NULL
) {
11977 i
= mg_vprintf(conn
, fmt
, ap
);
11980 NULL
, /* No truncation check for ebuf */
11984 "Error sending request");
11986 getreq(conn
, ebuf
, ebuf_len
, &reqerr
);
11988 /* TODO: 1) uri is deprecated;
11989 * 2) here, ri.uri is the http response code */
11990 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
11994 /* if an error occured, close the connection */
11995 if (ebuf
[0] != '\0' && conn
!= NULL
) {
11996 mg_close_connection(conn
);
12005 struct websocket_client_thread_data
{
12006 struct mg_connection
*conn
;
12007 mg_websocket_data_handler data_handler
;
12008 mg_websocket_close_handler close_handler
;
12009 void *callback_data
;
12013 #if defined(USE_WEBSOCKET)
12015 static unsigned __stdcall
websocket_client_thread(void *data
)
12018 websocket_client_thread(void *data
)
12021 struct websocket_client_thread_data
*cdata
=
12022 (struct websocket_client_thread_data
*)data
;
12024 mg_set_thread_name("ws-client");
12026 if (cdata
->conn
->ctx
) {
12027 if (cdata
->conn
->ctx
->callbacks
.init_thread
) {
12028 /* 3 indicates a websocket client thread */
12029 /* TODO: check if conn->ctx can be set */
12030 cdata
->conn
->ctx
->callbacks
.init_thread(cdata
->conn
->ctx
, 3);
12034 read_websocket(cdata
->conn
, cdata
->data_handler
, cdata
->callback_data
);
12036 DEBUG_TRACE("%s", "Websocket client thread exited\n");
12038 if (cdata
->close_handler
!= NULL
) {
12039 cdata
->close_handler(cdata
->conn
, cdata
->callback_data
);
12042 mg_free((void *)cdata
);
12053 struct mg_connection
*
12054 mg_connect_websocket_client(const char *host
,
12057 char *error_buffer
,
12058 size_t error_buffer_size
,
12060 const char *origin
,
12061 mg_websocket_data_handler data_func
,
12062 mg_websocket_close_handler close_func
,
12065 struct mg_connection
*conn
= NULL
;
12067 #if defined(USE_WEBSOCKET)
12068 struct mg_context
*newctx
= NULL
;
12069 struct websocket_client_thread_data
*thread_data
;
12070 static const char *magic
= "x3JJHMbDL1EzLkh9GBhXDw==";
12071 static const char *handshake_req
;
12073 if (origin
!= NULL
) {
12074 handshake_req
= "GET %s HTTP/1.1\r\n"
12076 "Upgrade: websocket\r\n"
12077 "Connection: Upgrade\r\n"
12078 "Sec-WebSocket-Key: %s\r\n"
12079 "Sec-WebSocket-Version: 13\r\n"
12083 handshake_req
= "GET %s HTTP/1.1\r\n"
12085 "Upgrade: websocket\r\n"
12086 "Connection: Upgrade\r\n"
12087 "Sec-WebSocket-Key: %s\r\n"
12088 "Sec-WebSocket-Version: 13\r\n"
12092 /* Establish the client connection and request upgrade */
12093 conn
= mg_download(host
,
12104 /* Connection object will be null if something goes wrong */
12105 if (conn
== NULL
|| (strcmp(conn
->request_info
.request_uri
, "101") != 0)) {
12106 if (!*error_buffer
) {
12107 /* if there is a connection, but it did not return 101,
12108 * error_buffer is not yet set */
12110 NULL
, /* No truncation check for ebuf */
12113 "Unexpected server reply");
12115 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer
);
12116 if (conn
!= NULL
) {
12123 /* For client connections, mg_context is fake. Since we need to set a
12124 * callback function, we need to create a copy and modify it. */
12125 newctx
= (struct mg_context
*)mg_malloc(sizeof(struct mg_context
));
12126 memcpy(newctx
, conn
->ctx
, sizeof(struct mg_context
));
12127 newctx
->user_data
= user_data
;
12128 newctx
->context_type
= 2; /* client context type */
12129 newctx
->cfg_worker_threads
= 1; /* one worker thread will be created */
12130 newctx
->workerthreadids
=
12131 (pthread_t
*)mg_calloc(newctx
->cfg_worker_threads
, sizeof(pthread_t
));
12132 conn
->ctx
= newctx
;
12133 thread_data
= (struct websocket_client_thread_data
*)
12134 mg_calloc(sizeof(struct websocket_client_thread_data
), 1);
12135 thread_data
->conn
= conn
;
12136 thread_data
->data_handler
= data_func
;
12137 thread_data
->close_handler
= close_func
;
12138 thread_data
->callback_data
= NULL
;
12140 /* Start a thread to read the websocket client connection
12141 * This thread will automatically stop when mg_disconnect is
12142 * called on the client connection */
12143 if (mg_start_thread_with_id(websocket_client_thread
,
12144 (void *)thread_data
,
12145 newctx
->workerthreadids
) != 0) {
12146 mg_free((void *)thread_data
);
12147 mg_free((void *)newctx
->workerthreadids
);
12148 mg_free((void *)newctx
);
12149 mg_free((void *)conn
);
12152 "Websocket client connect thread could not be started\r\n");
12155 /* Appease "unused parameter" warnings */
12159 (void)error_buffer
;
12160 (void)error_buffer_size
;
12173 process_new_connection(struct mg_connection
*conn
)
12175 if (conn
&& conn
->ctx
) {
12176 struct mg_request_info
*ri
= &conn
->request_info
;
12177 int keep_alive_enabled
, keep_alive
, discard_len
;
12179 const char *hostend
;
12180 int reqerr
, uri_type
;
12182 keep_alive_enabled
=
12183 !strcmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes");
12185 /* Important: on new connection, reset the receiving buffer. Credit
12186 * goes to crule42. */
12187 conn
->data_len
= 0;
12189 if (!getreq(conn
, ebuf
, sizeof(ebuf
), &reqerr
)) {
12190 /* The request sent by the client could not be understood by
12191 * the server, or it was incomplete or a timeout. Send an
12192 * error message and close the connection. */
12194 /*assert(ebuf[0] != '\0');*/
12195 send_http_error(conn
, reqerr
, "%s", ebuf
);
12197 } else if (strcmp(ri
->http_version
, "1.0")
12198 && strcmp(ri
->http_version
, "1.1")) {
12200 NULL
, /* No truncation check for ebuf */
12203 "Bad HTTP version: [%s]",
12205 send_http_error(conn
, 505, "%s", ebuf
);
12208 if (ebuf
[0] == '\0') {
12209 uri_type
= get_uri_type(conn
->request_info
.request_uri
);
12210 switch (uri_type
) {
12213 conn
->request_info
.local_uri
= NULL
;
12217 conn
->request_info
.local_uri
=
12218 conn
->request_info
.request_uri
;
12222 /* absolute uri (with/without port) */
12223 hostend
= get_rel_url_at_current_server(
12224 conn
->request_info
.request_uri
, conn
);
12226 conn
->request_info
.local_uri
= hostend
;
12228 conn
->request_info
.local_uri
= NULL
;
12233 NULL
, /* No truncation check for ebuf */
12236 "Invalid URI: [%s]",
12238 send_http_error(conn
, 400, "%s", ebuf
);
12242 /* TODO: cleanup uri, local_uri and request_uri */
12243 conn
->request_info
.uri
= conn
->request_info
.local_uri
;
12246 if (ebuf
[0] == '\0') {
12247 if (conn
->request_info
.local_uri
) {
12248 /* handle request to local server */
12249 handle_request(conn
);
12250 if (conn
->ctx
->callbacks
.end_request
!= NULL
) {
12251 conn
->ctx
->callbacks
.end_request(conn
,
12252 conn
->status_code
);
12256 /* TODO: handle non-local request (PROXY) */
12257 conn
->must_close
= 1;
12260 conn
->must_close
= 1;
12263 if (ri
->remote_user
!= NULL
) {
12264 mg_free((void *)ri
->remote_user
);
12265 /* Important! When having connections with and without auth
12266 * would cause double free and then crash */
12267 ri
->remote_user
= NULL
;
12270 /* NOTE(lsm): order is important here. should_keep_alive() call
12272 * using parsed request, which will be invalid after memmove's
12274 * Therefore, memorize should_keep_alive() result now for later
12276 * in loop exit condition. */
12277 keep_alive
= conn
->ctx
->stop_flag
== 0 && keep_alive_enabled
12278 && conn
->content_len
>= 0 && should_keep_alive(conn
);
12280 /* Discard all buffered data for this request */
12281 discard_len
= conn
->content_len
>= 0 && conn
->request_len
> 0
12282 && conn
->request_len
+ conn
->content_len
12283 < (int64_t)conn
->data_len
12284 ? (int)(conn
->request_len
+ conn
->content_len
)
12286 /*assert(discard_len >= 0);*/
12287 if (discard_len
< 0)
12289 conn
->data_len
-= discard_len
;
12290 if (conn
->data_len
> 0) {
12292 conn
->buf
+ discard_len
,
12293 (size_t)conn
->data_len
);
12296 /* assert(conn->data_len >= 0); */
12297 /* assert(conn->data_len <= conn->buf_size); */
12299 if ((conn
->data_len
< 0) || (conn
->data_len
> conn
->buf_size
)) {
12303 } while (keep_alive
);
12308 /* Worker threads take accepted socket from the queue */
12310 consume_socket(struct mg_context
*ctx
, struct socket
*sp
)
12312 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12317 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12318 DEBUG_TRACE("%s", "going idle");
12320 /* If the queue is empty, wait. We're idle at this point. */
12321 while (ctx
->sq_head
== ctx
->sq_tail
&& ctx
->stop_flag
== 0) {
12322 pthread_cond_wait(&ctx
->sq_full
, &ctx
->thread_mutex
);
12325 /* If we're stopping, sq_head may be equal to sq_tail. */
12326 if (ctx
->sq_head
> ctx
->sq_tail
) {
12327 /* Copy socket from the queue and increment tail */
12328 *sp
= ctx
->queue
[ctx
->sq_tail
% QUEUE_SIZE(ctx
)];
12331 DEBUG_TRACE("grabbed socket %d, going busy", sp
? sp
->sock
: -1);
12333 /* Wrap pointers if needed */
12334 while (ctx
->sq_tail
> QUEUE_SIZE(ctx
)) {
12335 ctx
->sq_tail
-= QUEUE_SIZE(ctx
);
12336 ctx
->sq_head
-= QUEUE_SIZE(ctx
);
12340 (void)pthread_cond_signal(&ctx
->sq_empty
);
12341 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12343 return !ctx
->stop_flag
;
12349 worker_thread_run(void *thread_func_param
)
12351 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12352 struct mg_connection
*conn
;
12353 struct mg_workerTLS tls
;
12354 #if defined(MG_LEGACY_INTERFACE)
12358 mg_set_thread_name("worker");
12361 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12362 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12363 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12366 if (ctx
->callbacks
.init_thread
) {
12367 /* call init_thread for a worker thread (type 1) */
12368 ctx
->callbacks
.init_thread(ctx
, 1);
12372 (struct mg_connection
*)mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
);
12373 if (conn
== NULL
) {
12374 mg_cry(fc(ctx
), "%s", "Cannot create new connection struct, OOM");
12376 pthread_setspecific(sTlsKey
, &tls
);
12377 conn
->buf_size
= MAX_REQUEST_SIZE
;
12378 conn
->buf
= (char *)(conn
+ 1);
12380 conn
->request_info
.user_data
= ctx
->user_data
;
12381 /* Allocate a mutex for this connection to allow communication both
12382 * within the request handler and from elsewhere in the application
12384 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
12386 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
12387 * signal sq_empty condvar to wake up the master waiting in
12388 * produce_socket() */
12389 while (consume_socket(ctx
, &conn
->client
)) {
12390 conn
->conn_birth_time
= time(NULL
);
12392 /* Fill in IP, port info early so even if SSL setup below fails,
12393 * error handler would have the corresponding info.
12394 * Thanks to Johannes Winkelmann for the patch.
12396 #if defined(USE_IPV6)
12397 if (conn
->client
.rsa
.sa
.sa_family
== AF_INET6
) {
12398 conn
->request_info
.remote_port
=
12399 ntohs(conn
->client
.rsa
.sin6
.sin6_port
);
12403 conn
->request_info
.remote_port
=
12404 ntohs(conn
->client
.rsa
.sin
.sin_port
);
12407 sockaddr_to_string(conn
->request_info
.remote_addr
,
12408 sizeof(conn
->request_info
.remote_addr
),
12409 &conn
->client
.rsa
);
12411 #if defined(MG_LEGACY_INTERFACE)
12412 /* This legacy interface only works for the IPv4 case */
12413 addr
= ntohl(conn
->client
.rsa
.sin
.sin_addr
.s_addr
);
12414 memcpy(&conn
->request_info
.remote_ip
, &addr
, 4);
12417 conn
->request_info
.is_ssl
= conn
->client
.is_ssl
;
12419 if (!conn
->client
.is_ssl
12421 || sslize(conn
, conn
->ctx
->ssl_ctx
, SSL_accept
)
12426 process_new_connection(conn
);
12429 close_connection(conn
);
12433 /* Signal master that we're done with connection and exiting */
12434 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12435 ctx
->running_worker_threads
--;
12436 (void)pthread_cond_signal(&ctx
->thread_cond
);
12437 /* assert(ctx->running_worker_threads >= 0); */
12438 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12440 pthread_setspecific(sTlsKey
, NULL
);
12441 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12442 CloseHandle(tls
.pthread_cond_helper_mutex
);
12444 pthread_mutex_destroy(&conn
->mutex
);
12447 DEBUG_TRACE("%s", "exiting");
12452 /* Threads have different return types on Windows and Unix. */
12454 static unsigned __stdcall
worker_thread(void *thread_func_param
)
12456 worker_thread_run(thread_func_param
);
12461 worker_thread(void *thread_func_param
)
12463 worker_thread_run(thread_func_param
);
12466 #endif /* _WIN32 */
12469 /* Master thread adds accepted socket to a queue */
12471 produce_socket(struct mg_context
*ctx
, const struct socket
*sp
)
12473 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12477 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12479 /* If the queue is full, wait */
12480 while (ctx
->stop_flag
== 0
12481 && ctx
->sq_head
- ctx
->sq_tail
>= QUEUE_SIZE(ctx
)) {
12482 (void)pthread_cond_wait(&ctx
->sq_empty
, &ctx
->thread_mutex
);
12485 if (ctx
->sq_head
- ctx
->sq_tail
< QUEUE_SIZE(ctx
)) {
12486 /* Copy socket to the queue and increment head */
12487 ctx
->queue
[ctx
->sq_head
% QUEUE_SIZE(ctx
)] = *sp
;
12489 DEBUG_TRACE("queued socket %d", sp
? sp
->sock
: -1);
12492 (void)pthread_cond_signal(&ctx
->sq_full
);
12493 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12499 accept_new_connection(const struct socket
*listener
, struct mg_context
*ctx
)
12502 char src_addr
[IP_ADDR_STR_LEN
];
12503 socklen_t len
= sizeof(so
.rsa
);
12511 if ((so
.sock
= accept(listener
->sock
, &so
.rsa
.sa
, &len
))
12512 == INVALID_SOCKET
) {
12513 } else if (!check_acl(ctx
, ntohl(*(uint32_t *)&so
.rsa
.sin
.sin_addr
))) {
12514 sockaddr_to_string(src_addr
, sizeof(src_addr
), &so
.rsa
);
12515 mg_cry(fc(ctx
), "%s: %s is not allowed to connect", __func__
, src_addr
);
12516 closesocket(so
.sock
);
12517 so
.sock
= INVALID_SOCKET
;
12519 /* Put so socket structure into the queue */
12520 DEBUG_TRACE("Accepted socket %d", (int)so
.sock
);
12521 set_close_on_exec(so
.sock
, fc(ctx
));
12522 so
.is_ssl
= listener
->is_ssl
;
12523 so
.ssl_redir
= listener
->ssl_redir
;
12524 if (getsockname(so
.sock
, &so
.lsa
.sa
, &len
) != 0) {
12526 "%s: getsockname() failed: %s",
12531 /* Set TCP keep-alive. This is needed because if HTTP-level
12533 * is enabled, and client resets the connection, server won't get
12534 * TCP FIN or RST and will keep the connection open forever. With
12535 * TCP keep-alive, next keep-alive handshake will figure out that
12536 * the client is down and will close the server end.
12537 * Thanks to Igor Klopov who suggested the patch. */
12538 if (setsockopt(so
.sock
,
12541 (SOCK_OPT_TYPE
)&on
,
12542 sizeof(on
)) != 0) {
12544 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
12550 /* Disable TCP Nagle's algorithm. Normally TCP packets are
12552 * to effectively fill up the underlying IP packet payload and
12554 * the overhead of sending lots of small buffers. However this hurts
12555 * the server's throughput (ie. operations per second) when HTTP 1.1
12556 * persistent connections are used and the responses are relatively
12557 * small (eg. less than 1400 bytes).
12559 if ((ctx
!= NULL
) && (ctx
->config
[CONFIG_TCP_NODELAY
] != NULL
)
12560 && (!strcmp(ctx
->config
[CONFIG_TCP_NODELAY
], "1"))) {
12561 if (set_tcp_nodelay(so
.sock
, 1) != 0) {
12563 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
12569 if (ctx
&& ctx
->config
[REQUEST_TIMEOUT
]) {
12570 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]);
12575 /* Set socket timeout to the given value, but not more than a
12576 * a certain limit (SOCKET_TIMEOUT_QUANTUM, default 10 seconds),
12577 * so the server can exit after that time if requested. */
12578 if ((timeout
> 0) && (timeout
< SOCKET_TIMEOUT_QUANTUM
)) {
12579 set_sock_timeout(so
.sock
, timeout
);
12581 set_sock_timeout(so
.sock
, SOCKET_TIMEOUT_QUANTUM
);
12584 produce_socket(ctx
, &so
);
12590 master_thread_run(void *thread_func_param
)
12592 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12593 struct mg_workerTLS tls
;
12594 struct pollfd
*pfd
;
12596 unsigned int workerthreadcount
;
12602 mg_set_thread_name("master");
12604 /* Increase priority of the master thread */
12605 #if defined(_WIN32)
12606 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
12607 #elif defined(USE_MASTER_THREAD_PRIORITY)
12608 int min_prio
= sched_get_priority_min(SCHED_RR
);
12609 int max_prio
= sched_get_priority_max(SCHED_RR
);
12610 if ((min_prio
>= 0) && (max_prio
>= 0)
12611 && ((USE_MASTER_THREAD_PRIORITY
) <= max_prio
)
12612 && ((USE_MASTER_THREAD_PRIORITY
) >= min_prio
)) {
12613 struct sched_param sched_param
= {0};
12614 sched_param
.sched_priority
= (USE_MASTER_THREAD_PRIORITY
);
12615 pthread_setschedparam(pthread_self(), SCHED_RR
, &sched_param
);
12619 /* Initialize thread local storage */
12620 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12621 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12624 pthread_setspecific(sTlsKey
, &tls
);
12626 if (ctx
->callbacks
.init_thread
) {
12627 /* Callback for the master thread (type 0) */
12628 ctx
->callbacks
.init_thread(ctx
, 0);
12631 /* Server starts *now* */
12632 ctx
->start_time
= time(NULL
);
12634 /* Allocate memory for the listening sockets, and start the server */
12636 (struct pollfd
*)mg_calloc(ctx
->num_listening_sockets
, sizeof(pfd
[0]));
12637 while (pfd
!= NULL
&& ctx
->stop_flag
== 0) {
12638 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12639 pfd
[i
].fd
= ctx
->listening_sockets
[i
].sock
;
12640 pfd
[i
].events
= POLLIN
;
12643 if (poll(pfd
, ctx
->num_listening_sockets
, 200) > 0) {
12644 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12645 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
12646 * successful poll, and POLLIN is defined as
12647 * (POLLRDNORM | POLLRDBAND)
12648 * Therefore, we're checking pfd[i].revents & POLLIN, not
12649 * pfd[i].revents == POLLIN. */
12650 if (ctx
->stop_flag
== 0 && (pfd
[i
].revents
& POLLIN
)) {
12651 accept_new_connection(&ctx
->listening_sockets
[i
], ctx
);
12657 DEBUG_TRACE("%s", "stopping workers");
12659 /* Stop signal received: somebody called mg_stop. Quit. */
12660 close_all_listening_sockets(ctx
);
12662 /* Wakeup workers that are waiting for connections to handle. */
12663 pthread_cond_broadcast(&ctx
->sq_full
);
12665 /* Wait until all threads finish */
12666 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12667 while (ctx
->running_worker_threads
> 0) {
12668 (void)pthread_cond_wait(&ctx
->thread_cond
, &ctx
->thread_mutex
);
12670 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12672 /* Join all worker threads to avoid leaking threads. */
12673 workerthreadcount
= ctx
->cfg_worker_threads
;
12674 for (i
= 0; i
< workerthreadcount
; i
++) {
12675 if (ctx
->workerthreadids
[i
] != 0) {
12676 mg_join_thread(ctx
->workerthreadids
[i
]);
12680 #if !defined(NO_SSL)
12681 if (ctx
->ssl_ctx
!= NULL
) {
12682 uninitialize_ssl(ctx
);
12685 DEBUG_TRACE("%s", "exiting");
12687 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12688 CloseHandle(tls
.pthread_cond_helper_mutex
);
12690 pthread_setspecific(sTlsKey
, NULL
);
12692 /* Signal mg_stop() that we're done.
12693 * WARNING: This must be the very last thing this
12694 * thread does, as ctx becomes invalid after this line. */
12695 ctx
->stop_flag
= 2;
12699 /* Threads have different return types on Windows and Unix. */
12701 static unsigned __stdcall
master_thread(void *thread_func_param
)
12703 master_thread_run(thread_func_param
);
12708 master_thread(void *thread_func_param
)
12710 master_thread_run(thread_func_param
);
12713 #endif /* _WIN32 */
12717 free_context(struct mg_context
*ctx
)
12720 struct mg_handler_info
*tmp_rh
;
12726 if (ctx
->callbacks
.exit_context
) {
12727 ctx
->callbacks
.exit_context(ctx
);
12730 /* All threads exited, no sync is needed. Destroy thread mutex and
12733 (void)pthread_mutex_destroy(&ctx
->thread_mutex
);
12734 (void)pthread_cond_destroy(&ctx
->thread_cond
);
12735 (void)pthread_cond_destroy(&ctx
->sq_empty
);
12736 (void)pthread_cond_destroy(&ctx
->sq_full
);
12738 /* Destroy other context global data structures mutex */
12739 (void)pthread_mutex_destroy(&ctx
->nonce_mutex
);
12741 #if defined(USE_TIMERS)
12745 /* Deallocate config parameters */
12746 for (i
= 0; i
< NUM_OPTIONS
; i
++) {
12747 if (ctx
->config
[i
] != NULL
) {
12748 #if defined(_MSC_VER)
12749 #pragma warning(suppress : 6001)
12751 mg_free(ctx
->config
[i
]);
12755 /* Deallocate request handlers */
12756 while (ctx
->handlers
) {
12757 tmp_rh
= ctx
->handlers
;
12758 ctx
->handlers
= tmp_rh
->next
;
12759 mg_free(tmp_rh
->uri
);
12764 /* Deallocate SSL context */
12765 if (ctx
->ssl_ctx
!= NULL
) {
12766 SSL_CTX_free(ctx
->ssl_ctx
);
12768 #endif /* !NO_SSL */
12770 /* Deallocate worker thread ID array */
12771 if (ctx
->workerthreadids
!= NULL
) {
12772 mg_free(ctx
->workerthreadids
);
12775 /* Deallocate the tls variable */
12776 if (mg_atomic_dec(&sTlsInit
) == 0) {
12777 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12778 DeleteCriticalSection(&global_log_file_lock
);
12779 #endif /* _WIN32 && !__SYMBIAN32__ */
12780 #if !defined(_WIN32)
12781 pthread_mutexattr_destroy(&pthread_mutex_attr
);
12784 pthread_key_delete(sTlsKey
);
12787 /* deallocate system name string */
12788 mg_free(ctx
->systemName
);
12790 /* Deallocate context itself */
12796 mg_stop(struct mg_context
*ctx
)
12803 /* We don't use a lock here. Calling mg_stop with the same ctx from
12804 * two threads is not allowed. */
12805 mt
= ctx
->masterthreadid
;
12810 ctx
->masterthreadid
= 0;
12811 ctx
->stop_flag
= 1;
12813 /* Wait until mg_fini() stops */
12814 while (ctx
->stop_flag
!= 2) {
12815 (void)mg_sleep(10);
12818 mg_join_thread(mt
);
12821 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12822 (void)WSACleanup();
12823 #endif /* _WIN32 && !__SYMBIAN32__ */
12828 get_system_name(char **sysName
)
12830 #if defined(_WIN32)
12831 #if !defined(__SYMBIAN32__)
12833 DWORD dwVersion
= 0;
12834 DWORD dwMajorVersion
= 0;
12835 DWORD dwMinorVersion
= 0;
12839 #pragma warning(push)
12840 // GetVersion was declared deprecated
12841 #pragma warning(disable : 4996)
12843 dwVersion
= GetVersion();
12845 #pragma warning(pop)
12848 dwMajorVersion
= (DWORD
)(LOBYTE(LOWORD(dwVersion
)));
12849 dwMinorVersion
= (DWORD
)(HIBYTE(LOWORD(dwVersion
)));
12850 dwBuild
= ((dwVersion
< 0x80000000) ? (DWORD
)(HIWORD(dwVersion
)) : 0);
12855 (unsigned)dwMajorVersion
,
12856 (unsigned)dwMinorVersion
);
12857 *sysName
= mg_strdup(name
);
12859 *sysName
= mg_strdup("Symbian");
12862 struct utsname name
;
12863 memset(&name
, 0, sizeof(name
));
12865 *sysName
= mg_strdup(name
.sysname
);
12870 struct mg_context
*
12871 mg_start(const struct mg_callbacks
*callbacks
,
12873 const char **options
)
12875 struct mg_context
*ctx
;
12876 const char *name
, *value
, *default_value
;
12877 int idx
, ok
, workerthreadcount
;
12879 void (*exit_callback
)(const struct mg_context
*ctx
) = 0;
12881 struct mg_workerTLS tls
;
12883 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12885 WSAStartup(MAKEWORD(2, 2), &data
);
12886 #endif /* _WIN32 && !__SYMBIAN32__ */
12888 /* Allocate context and initialize reasonable general case defaults. */
12889 if ((ctx
= (struct mg_context
*)mg_calloc(1, sizeof(*ctx
))) == NULL
) {
12893 /* Random number generator will initialize at the first call */
12894 ctx
->auth_nonce_mask
=
12895 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options
);
12897 if (mg_atomic_inc(&sTlsInit
) == 1) {
12899 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12900 InitializeCriticalSection(&global_log_file_lock
);
12901 #endif /* _WIN32 && !__SYMBIAN32__ */
12902 #if !defined(_WIN32)
12903 pthread_mutexattr_init(&pthread_mutex_attr
);
12904 pthread_mutexattr_settype(&pthread_mutex_attr
, PTHREAD_MUTEX_RECURSIVE
);
12907 if (0 != pthread_key_create(&sTlsKey
, tls_dtor
)) {
12908 /* Fatal error - abort start. However, this situation should
12910 * occur in practice. */
12911 mg_atomic_dec(&sTlsInit
);
12912 mg_cry(fc(ctx
), "Cannot initialize thread local storage");
12917 /* TODO (low): istead of sleeping, check if sTlsKey is already
12922 tls
.is_master
= -1;
12923 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12924 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12925 tls
.pthread_cond_helper_mutex
= NULL
;
12927 pthread_setspecific(sTlsKey
, &tls
);
12929 #if defined(USE_LUA)
12930 lua_init_optional_libraries();
12933 ok
= 0 == pthread_mutex_init(&ctx
->thread_mutex
, &pthread_mutex_attr
);
12934 ok
&= 0 == pthread_cond_init(&ctx
->thread_cond
, NULL
);
12935 ok
&= 0 == pthread_cond_init(&ctx
->sq_empty
, NULL
);
12936 ok
&= 0 == pthread_cond_init(&ctx
->sq_full
, NULL
);
12937 ok
&= 0 == pthread_mutex_init(&ctx
->nonce_mutex
, &pthread_mutex_attr
);
12939 /* Fatal error - abort start. However, this situation should never
12940 * occur in practice. */
12941 mg_cry(fc(ctx
), "Cannot initialize thread synchronization objects");
12943 pthread_setspecific(sTlsKey
, NULL
);
12948 ctx
->callbacks
= *callbacks
;
12949 exit_callback
= callbacks
->exit_context
;
12950 ctx
->callbacks
.exit_context
= 0;
12952 ctx
->user_data
= user_data
;
12953 ctx
->handlers
= NULL
;
12955 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
12956 ctx
->shared_lua_websockets
= 0;
12959 while (options
&& (name
= *options
++) != NULL
) {
12960 if ((idx
= get_option_index(name
)) == -1) {
12961 mg_cry(fc(ctx
), "Invalid option: %s", name
);
12963 pthread_setspecific(sTlsKey
, NULL
);
12965 } else if ((value
= *options
++) == NULL
) {
12966 mg_cry(fc(ctx
), "%s: option value cannot be NULL", name
);
12968 pthread_setspecific(sTlsKey
, NULL
);
12971 if (ctx
->config
[idx
] != NULL
) {
12972 mg_cry(fc(ctx
), "warning: %s: duplicate option", name
);
12973 mg_free(ctx
->config
[idx
]);
12975 ctx
->config
[idx
] = mg_strdup(value
);
12976 DEBUG_TRACE("[%s] -> [%s]", name
, value
);
12979 /* Set default value if needed */
12980 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
12981 default_value
= config_options
[i
].default_value
;
12982 if (ctx
->config
[i
] == NULL
&& default_value
!= NULL
) {
12983 ctx
->config
[i
] = mg_strdup(default_value
);
12987 #if defined(NO_FILES)
12988 if (ctx
->config
[DOCUMENT_ROOT
] != NULL
) {
12989 mg_cry(fc(ctx
), "%s", "Document root must not be set");
12991 pthread_setspecific(sTlsKey
, NULL
);
12996 get_system_name(&ctx
->systemName
);
12998 /* NOTE(lsm): order is important here. SSL certificates must
12999 * be initialized before listening ports. UID must be set last. */
13000 if (!set_gpass_option(ctx
) ||
13001 #if !defined(NO_SSL)
13002 !set_ssl_option(ctx
) ||
13004 !set_ports_option(ctx
) ||
13005 #if !defined(_WIN32)
13006 !set_uid_option(ctx
) ||
13008 !set_acl_option(ctx
)) {
13010 pthread_setspecific(sTlsKey
, NULL
);
13014 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
13015 /* Ignore SIGPIPE signal, so if browser cancels the request, it
13016 * won't kill the whole process. */
13017 (void)signal(SIGPIPE
, SIG_IGN
);
13018 #endif /* !_WIN32 && !__SYMBIAN32__ */
13020 workerthreadcount
= atoi(ctx
->config
[NUM_THREADS
]);
13022 if (workerthreadcount
> MAX_WORKER_THREADS
) {
13023 mg_cry(fc(ctx
), "Too many worker threads");
13025 pthread_setspecific(sTlsKey
, NULL
);
13029 if (workerthreadcount
> 0) {
13030 ctx
->cfg_worker_threads
= ((unsigned int)(workerthreadcount
));
13031 ctx
->workerthreadids
=
13032 (pthread_t
*)mg_calloc(ctx
->cfg_worker_threads
, sizeof(pthread_t
));
13033 if (ctx
->workerthreadids
== NULL
) {
13034 mg_cry(fc(ctx
), "Not enough memory for worker thread ID array");
13036 pthread_setspecific(sTlsKey
, NULL
);
13041 #if defined(USE_TIMERS)
13042 if (timers_init(ctx
) != 0) {
13043 mg_cry(fc(ctx
), "Error creating timers");
13045 pthread_setspecific(sTlsKey
, NULL
);
13050 /* Context has been created - init user libraries */
13051 if (ctx
->callbacks
.init_context
) {
13052 ctx
->callbacks
.init_context(ctx
);
13054 ctx
->callbacks
.exit_context
= exit_callback
;
13055 ctx
->context_type
= 1; /* server context */
13057 /* Start master (listening) thread */
13058 mg_start_thread_with_id(master_thread
, ctx
, &ctx
->masterthreadid
);
13060 /* Start worker threads */
13061 for (i
= 0; i
< ctx
->cfg_worker_threads
; i
++) {
13062 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13063 ctx
->running_worker_threads
++;
13064 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13065 if (mg_start_thread_with_id(worker_thread
,
13067 &ctx
->workerthreadids
[i
]) != 0) {
13068 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13069 ctx
->running_worker_threads
--;
13070 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13073 "Cannot start worker thread %i: error %ld",
13078 "Cannot create threads: error %ld",
13081 pthread_setspecific(sTlsKey
, NULL
);
13088 pthread_setspecific(sTlsKey
, NULL
);
13093 /* Feature check API function */
13095 mg_check_feature(unsigned feature
)
13097 static const unsigned feature_set
= 0
13098 /* Set bits for available features according to API documentation.
13099 * This bit mask is created at compile time, according to the active
13100 * preprocessor defines. It is a single const value at runtime. */
13101 #if !defined(NO_FILES)
13104 #if !defined(NO_SSL)
13107 #if !defined(NO_CGI)
13110 #if defined(USE_IPV6)
13113 #if defined(USE_WEBSOCKET)
13116 #if defined(USE_LUA)
13119 #if defined(USE_DUKTAPE)
13122 #if !defined(NO_CACHING)
13126 /* Set some extra bits not defined in the API documentation.
13127 * These bits may change without further notice. */
13128 #if defined(MG_LEGACY_INTERFACE)
13131 #if defined(MEMORY_DEBUGGING)
13134 #if defined(USE_TIMERS)
13137 #if !defined(NO_NONCE_CHECK)
13140 #if !defined(NO_POPEN)
13144 return (feature
& feature_set
);