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 if (path
&& path
[4] == 0 && memcmp(path
, "www/", 4) == 0)
3030 filep
->is_directory
= 1;
3034 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3035 if (GetFileAttributesExW(wbuf
, GetFileExInfoStandard
, &info
) != 0) {
3036 filep
->size
= MAKEUQUAD(info
.nFileSizeLow
, info
.nFileSizeHigh
);
3037 filep
->last_modified
=
3038 SYS2UNIX_TIME(info
.ftLastWriteTime
.dwLowDateTime
,
3039 info
.ftLastWriteTime
.dwHighDateTime
);
3041 /* On Windows, the file creation time can be higher than the
3042 * modification time, e.g. when a file is copied.
3043 * Since the Last-Modified timestamp is used for caching
3044 * it should be based on the most recent timestamp. */
3045 creation_time
= SYS2UNIX_TIME(info
.ftCreationTime
.dwLowDateTime
,
3046 info
.ftCreationTime
.dwHighDateTime
);
3047 if (creation_time
> filep
->last_modified
) {
3048 filep
->last_modified
= creation_time
;
3051 filep
->is_directory
= info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
;
3052 /* If file name is fishy, reset the file structure and return
3054 * Note it is important to reset, not just return the error, cause
3055 * functions like is_file_opened() check the struct. */
3056 if (!filep
->is_directory
&& !path_cannot_disclose_cgi(path
)) {
3057 memset(filep
, 0, sizeof(*filep
));
3069 mg_remove(const struct mg_connection
*conn
, const char *path
)
3071 wchar_t wbuf
[PATH_MAX
];
3072 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3073 return DeleteFileW(wbuf
) ? 0 : -1;
3078 mg_mkdir(const struct mg_connection
*conn
, const char *path
, int mode
)
3080 wchar_t wbuf
[PATH_MAX
];
3082 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3083 return CreateDirectoryW(wbuf
, NULL
) ? 0 : -1;
3087 /* Create substitutes for POSIX functions in Win32. */
3089 #if defined(__MINGW32__)
3090 /* Show no warning in case system functions are not used. */
3091 #pragma GCC diagnostic push
3092 #pragma GCC diagnostic ignored "-Wunused-function"
3096 /* Implementation of POSIX opendir/closedir/readdir for Windows. */
3098 mg_opendir(const struct mg_connection
*conn
, const char *name
)
3101 wchar_t wpath
[PATH_MAX
];
3105 SetLastError(ERROR_BAD_ARGUMENTS
);
3106 } else if ((dir
= (DIR *)mg_malloc(sizeof(*dir
))) == NULL
) {
3107 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3109 path_to_unicode(conn
, name
, wpath
, ARRAY_SIZE(wpath
));
3110 attrs
= GetFileAttributesW(wpath
);
3111 if (attrs
!= 0xFFFFFFFF && ((attrs
& FILE_ATTRIBUTE_DIRECTORY
)
3112 == FILE_ATTRIBUTE_DIRECTORY
)) {
3113 (void)wcscat(wpath
, L
"\\*");
3114 dir
->handle
= FindFirstFileW(wpath
, &dir
->info
);
3115 dir
->result
.d_name
[0] = '\0';
3127 mg_closedir(DIR *dir
)
3132 if (dir
->handle
!= INVALID_HANDLE_VALUE
)
3133 result
= FindClose(dir
->handle
) ? 0 : -1;
3138 SetLastError(ERROR_BAD_ARGUMENTS
);
3145 static struct dirent
*
3146 mg_readdir(DIR *dir
)
3148 struct dirent
*result
= 0;
3151 if (dir
->handle
!= INVALID_HANDLE_VALUE
) {
3152 result
= &dir
->result
;
3153 (void)WideCharToMultiByte(CP_UTF8
,
3155 dir
->info
.cFileName
,
3158 sizeof(result
->d_name
),
3162 if (!FindNextFileW(dir
->handle
, &dir
->info
)) {
3163 (void)FindClose(dir
->handle
);
3164 dir
->handle
= INVALID_HANDLE_VALUE
;
3168 SetLastError(ERROR_FILE_NOT_FOUND
);
3171 SetLastError(ERROR_BAD_ARGUMENTS
);
3180 poll(struct pollfd
*pfd
, unsigned int n
, int milliseconds
)
3188 memset(&tv
, 0, sizeof(tv
));
3189 tv
.tv_sec
= milliseconds
/ 1000;
3190 tv
.tv_usec
= (milliseconds
% 1000) * 1000;
3193 for (i
= 0; i
< n
; i
++) {
3194 FD_SET((SOCKET
)pfd
[i
].fd
, &set
);
3197 if (pfd
[i
].fd
> maxfd
) {
3202 if ((result
= select((int)maxfd
+ 1, &set
, NULL
, NULL
, &tv
)) > 0) {
3203 for (i
= 0; i
< n
; i
++) {
3204 if (FD_ISSET(pfd
[i
].fd
, &set
)) {
3205 pfd
[i
].revents
= POLLIN
;
3212 #endif /* HAVE_POLL */
3214 #if defined(__MINGW32__)
3215 /* Enable unused function warning again */
3216 #pragma GCC diagnostic pop
3221 set_close_on_exec(SOCKET sock
, struct mg_connection
*conn
/* may be null */)
3223 (void)conn
; /* Unused. */
3224 (void)SetHandleInformation((HANDLE
)(intptr_t)sock
, HANDLE_FLAG_INHERIT
, 0);
3229 mg_start_thread(mg_thread_func_t f
, void *p
)
3231 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3232 /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
3234 return ((_beginthread((void(__cdecl
*)(void *))f
, USE_STACK_SIZE
, p
)
3235 == ((uintptr_t)(-1L)))
3240 (_beginthread((void(__cdecl
*)(void *))f
, 0, p
) == ((uintptr_t)(-1L)))
3243 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3247 /* Start a thread storing the thread context. */
3249 mg_start_thread_with_id(unsigned(__stdcall
*f
)(void *),
3251 pthread_t
*threadidptr
)
3254 HANDLE threadhandle
;
3257 uip
= _beginthreadex(NULL
, 0, (unsigned(__stdcall
*)(void *))f
, p
, 0, NULL
);
3258 threadhandle
= (HANDLE
)uip
;
3259 if ((uip
!= (uintptr_t)(-1L)) && (threadidptr
!= NULL
)) {
3260 *threadidptr
= threadhandle
;
3268 /* Wait for a thread to finish. */
3270 mg_join_thread(pthread_t threadid
)
3276 dwevent
= WaitForSingleObject(threadid
, INFINITE
);
3277 if (dwevent
== WAIT_FAILED
) {
3278 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO
);
3280 if (dwevent
== WAIT_OBJECT_0
) {
3281 CloseHandle(threadid
);
3289 #if !defined(NO_SSL_DL)
3290 /* Create substitutes for POSIX functions in Win32. */
3292 #if defined(__MINGW32__)
3293 /* Show no warning in case system functions are not used. */
3294 #pragma GCC diagnostic push
3295 #pragma GCC diagnostic ignored "-Wunused-function"
3300 dlopen(const char *dll_name
, int flags
)
3302 wchar_t wbuf
[PATH_MAX
];
3304 path_to_unicode(NULL
, dll_name
, wbuf
, ARRAY_SIZE(wbuf
));
3305 return LoadLibraryW(wbuf
);
3310 dlclose(void *handle
)
3314 if (FreeLibrary((HMODULE
)handle
) != 0) {
3324 #if defined(__MINGW32__)
3325 /* Enable unused function warning again */
3326 #pragma GCC diagnostic pop
3332 #if !defined(NO_CGI)
3336 kill(pid_t pid
, int sig_num
)
3338 (void)TerminateProcess((HANDLE
)pid
, (UINT
)sig_num
);
3339 (void)CloseHandle((HANDLE
)pid
);
3345 trim_trailing_whitespaces(char *s
)
3347 char *e
= s
+ strlen(s
) - 1;
3348 while (e
> s
&& isspace(*(unsigned char *)e
)) {
3355 spawn_process(struct mg_connection
*conn
,
3365 char *p
, *interp
, full_interp
[PATH_MAX
], full_dir
[PATH_MAX
],
3366 cmdline
[PATH_MAX
], buf
[PATH_MAX
];
3368 struct file file
= STRUCT_FILE_INITIALIZER
;
3370 PROCESS_INFORMATION pi
= {0};
3374 memset(&si
, 0, sizeof(si
));
3377 si
.dwFlags
= STARTF_USESTDHANDLES
| STARTF_USESHOWWINDOW
;
3378 si
.wShowWindow
= SW_HIDE
;
3380 me
= GetCurrentProcess();
3382 (HANDLE
)_get_osfhandle(fdin
[0]),
3387 DUPLICATE_SAME_ACCESS
);
3389 (HANDLE
)_get_osfhandle(fdout
[1]),
3394 DUPLICATE_SAME_ACCESS
);
3396 (HANDLE
)_get_osfhandle(fderr
[1]),
3401 DUPLICATE_SAME_ACCESS
);
3403 /* Mark handles that should not be inherited. See
3404 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
3406 SetHandleInformation((HANDLE
)_get_osfhandle(fdin
[1]),
3407 HANDLE_FLAG_INHERIT
,
3409 SetHandleInformation((HANDLE
)_get_osfhandle(fdout
[0]),
3410 HANDLE_FLAG_INHERIT
,
3412 SetHandleInformation((HANDLE
)_get_osfhandle(fderr
[0]),
3413 HANDLE_FLAG_INHERIT
,
3416 /* If CGI file is a script, try to read the interpreter line */
3417 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3418 if (interp
== NULL
) {
3419 buf
[0] = buf
[1] = '\0';
3421 /* Read the first line of the script into the buffer */
3423 conn
, &truncated
, cmdline
, sizeof(cmdline
), "%s/%s", dir
, prog
);
3426 pi
.hProcess
= (pid_t
)-1;
3430 if (mg_fopen(conn
, cmdline
, "r", &file
)) {
3431 p
= (char *)file
.membuf
;
3432 mg_fgets(buf
, sizeof(buf
), &file
, &p
);
3434 buf
[sizeof(buf
) - 1] = '\0';
3437 if (buf
[0] == '#' && buf
[1] == '!') {
3438 trim_trailing_whitespaces(buf
+ 2);
3445 if (interp
[0] != '\0') {
3446 GetFullPathNameA(interp
, sizeof(full_interp
), full_interp
, NULL
);
3447 interp
= full_interp
;
3449 GetFullPathNameA(dir
, sizeof(full_dir
), full_dir
, NULL
);
3451 if (interp
[0] != '\0') {
3456 "\"%s\" \"%s\\%s\"",
3471 pi
.hProcess
= (pid_t
)-1;
3475 DEBUG_TRACE("Running [%s]", cmdline
);
3476 if (CreateProcessA(NULL
,
3481 CREATE_NEW_PROCESS_GROUP
,
3487 conn
, "%s: CreateProcess(%s): %ld", __func__
, cmdline
, (long)ERRNO
);
3488 pi
.hProcess
= (pid_t
)-1;
3489 /* goto spawn_cleanup; */
3493 (void)CloseHandle(si
.hStdOutput
);
3494 (void)CloseHandle(si
.hStdError
);
3495 (void)CloseHandle(si
.hStdInput
);
3496 if (pi
.hThread
!= NULL
) {
3497 (void)CloseHandle(pi
.hThread
);
3500 return (pid_t
)pi
.hProcess
;
3502 #endif /* !NO_CGI */
3506 set_non_blocking_mode(SOCKET sock
)
3508 unsigned long on
= 1;
3509 return ioctlsocket(sock
, (long)FIONBIO
, &on
);
3515 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3521 memset(filep
, 0, sizeof(*filep
));
3523 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3527 if (path
&& path
[4] == 0 && memcmp(path
, "www/", 4) == 0)
3530 filep
->is_directory
= 1;
3534 if (0 == stat(path
, &st
)) {
3535 filep
->size
= (uint64_t)(st
.st_size
);
3536 filep
->last_modified
= st
.st_mtime
;
3537 filep
->is_directory
= S_ISDIR(st
.st_mode
);
3546 set_close_on_exec(SOCKET fd
, struct mg_connection
*conn
/* may be null */)
3548 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) != 0) {
3551 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
3560 mg_start_thread(mg_thread_func_t func
, void *param
)
3562 pthread_t thread_id
;
3563 pthread_attr_t attr
;
3566 (void)pthread_attr_init(&attr
);
3567 (void)pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3569 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3570 /* Compile-time option to control stack size,
3571 * e.g. -DUSE_STACK_SIZE=16384 */
3572 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3573 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3575 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3576 pthread_attr_destroy(&attr
);
3582 /* Start a thread storing the thread context. */
3584 mg_start_thread_with_id(mg_thread_func_t func
,
3586 pthread_t
*threadidptr
)
3588 pthread_t thread_id
;
3589 pthread_attr_t attr
;
3592 (void)pthread_attr_init(&attr
);
3594 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3595 /* Compile-time option to control stack size,
3596 * e.g. -DUSE_STACK_SIZE=16384 */
3597 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3598 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
3600 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3601 pthread_attr_destroy(&attr
);
3602 if ((result
== 0) && (threadidptr
!= NULL
)) {
3603 *threadidptr
= thread_id
;
3609 /* Wait for a thread to finish. */
3611 mg_join_thread(pthread_t threadid
)
3615 result
= pthread_join(threadid
, NULL
);
3622 spawn_process(struct mg_connection
*conn
,
3640 if ((pid
= fork()) == -1) {
3642 send_http_error(conn
,
3644 "Error: Creating CGI process\nfork(): %s",
3646 } else if (pid
== 0) {
3648 if (chdir(dir
) != 0) {
3649 mg_cry(conn
, "%s: chdir(%s): %s", __func__
, dir
, strerror(ERRNO
));
3650 } else if (dup2(fdin
[0], 0) == -1) {
3652 "%s: dup2(%d, 0): %s",
3656 } else if (dup2(fdout
[1], 1) == -1) {
3658 "%s: dup2(%d, 1): %s",
3662 } else if (dup2(fderr
[1], 2) == -1) {
3664 "%s: dup2(%d, 2): %s",
3669 /* Keep stderr and stdout in two different pipes.
3670 * Stdout will be sent back to the client,
3671 * stderr should go into a server error log. */
3672 (void)close(fdin
[0]);
3673 (void)close(fdout
[1]);
3674 (void)close(fderr
[1]);
3676 /* Close write end fdin and read end fdout and fderr */
3677 (void)close(fdin
[1]);
3678 (void)close(fdout
[0]);
3679 (void)close(fderr
[0]);
3681 /* After exec, all signal handlers are restored to their default
3682 * values, with one exception of SIGCHLD. According to
3683 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
3684 * leave unchanged after exec if it was set to be ignored. Restore
3685 * it to default action. */
3686 signal(SIGCHLD
, SIG_DFL
);
3688 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3689 if (interp
== NULL
) {
3690 (void)execle(prog
, prog
, NULL
, envp
);
3692 "%s: execle(%s): %s",
3697 (void)execle(interp
, interp
, prog
, NULL
, envp
);
3699 "%s: execle(%s %s): %s",
3711 #endif /* !NO_CGI */
3715 set_non_blocking_mode(SOCKET sock
)
3719 flags
= fcntl(sock
, F_GETFL
, 0);
3720 (void)fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
3725 /* End of initial operating system specific define block. */
3728 /* Get a random number (independent of C rand function) */
3732 static uint64_t lfsr
= 0; /* Linear feedback shift register */
3733 static uint64_t lcg
= 0; /* Linear congruential generator */
3734 struct timespec now
;
3736 memset(&now
, 0, sizeof(now
));
3737 clock_gettime(CLOCK_MONOTONIC
, &now
);
3740 /* lfsr will be only 0 if has not been initialized,
3741 * so this code is called only once. */
3742 lfsr
= (((uint64_t)now
.tv_sec
) << 21) ^ ((uint64_t)now
.tv_nsec
)
3743 ^ ((uint64_t)(ptrdiff_t)&now
) ^ (((uint64_t)time(NULL
)) << 33);
3744 lcg
= (((uint64_t)now
.tv_sec
) << 25) + (uint64_t)now
.tv_nsec
3745 + (uint64_t)(ptrdiff_t)&now
;
3747 /* Get the next step of both random number generators. */
3749 | ((((lfsr
>> 0) ^ (lfsr
>> 1) ^ (lfsr
>> 3) ^ (lfsr
>> 4)) & 1)
3751 lcg
= lcg
* 6364136223846793005 + 1442695040888963407;
3754 /* Combining two pseudo-random number generators and a high resolution part
3755 * of the current server time will make it hard (impossible?) to guess the
3757 return (lfsr
^ lcg
^ (uint64_t)now
.tv_nsec
);
3761 /* Write data to the IO channel - opened file descriptor, socket or SSL
3762 * descriptor. Return number of bytes written. */
3764 push(struct mg_context
*ctx
,
3772 struct timespec start
, now
;
3778 typedef size_t len_t
;
3782 memset(&start
, 0, sizeof(start
));
3783 memset(&now
, 0, sizeof(now
));
3784 clock_gettime(CLOCK_MONOTONIC
, &start
);
3801 n
= SSL_write(ssl
, buf
, len
);
3803 err
= SSL_get_error(ssl
, n
);
3804 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (n
== -1)) {
3807 DEBUG_TRACE("SSL_write() failed, error %d", err
);
3816 n
= (int)fwrite(buf
, 1, (size_t)len
, fp
);
3824 n
= (int)send(sock
, buf
, (len_t
)len
, MSG_NOSIGNAL
);
3825 err
= (n
< 0) ? ERRNO
: 0;
3828 if (ctx
->stop_flag
) {
3832 if ((n
> 0) || (n
== 0 && len
== 0)) {
3833 /* some data has been read, or no data was requested */
3837 /* shutdown of the socket at client side */
3841 /* socket error - check errno */
3842 DEBUG_TRACE("send() failed, error %d", err
);
3844 /* TODO: error handling depending on the error code.
3845 * These codes are different between Windows and Linux.
3850 /* This code is not reached in the moment.
3851 * ==> Fix the TODOs above first. */
3854 clock_gettime(CLOCK_MONOTONIC
, &now
);
3857 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
3859 (void)err
; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
3867 push_all(struct mg_context
*ctx
,
3874 double timeout
= -1.0;
3875 int64_t n
, nwritten
= 0;
3881 if (ctx
->config
[REQUEST_TIMEOUT
]) {
3882 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
3885 while (len
> 0 && ctx
->stop_flag
== 0) {
3886 n
= push(ctx
, fp
, sock
, ssl
, buf
+ nwritten
, (int)len
, timeout
);
3888 if (nwritten
== 0) {
3889 nwritten
= n
; /* Propagate the error */
3892 } else if (n
== 0) {
3893 break; /* No more data to write */
3904 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
3905 * Return negative value on error, or number of bytes read on success. */
3907 pull(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
, double timeout
)
3910 struct timespec start
, now
;
3915 typedef size_t len_t
;
3919 memset(&start
, 0, sizeof(start
));
3920 memset(&now
, 0, sizeof(now
));
3921 clock_gettime(CLOCK_MONOTONIC
, &start
);
3926 /* Use read() instead of fread(), because if we're reading from the
3927 * CGI pipe, fread() may block until IO buffer is filled up. We
3928 * cannot afford to block and must pass all read bytes immediately
3930 nread
= (int)read(fileno(fp
), buf
, (size_t)len
);
3931 err
= (nread
< 0) ? ERRNO
: 0;
3934 } else if (conn
->ssl
!= NULL
) {
3935 nread
= SSL_read(conn
->ssl
, buf
, len
);
3937 err
= SSL_get_error(conn
->ssl
, nread
);
3938 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (nread
== -1)) {
3941 DEBUG_TRACE("SSL_read() failed, error %d", err
);
3950 nread
= (int)recv(conn
->client
.sock
, buf
, (len_t
)len
, 0);
3951 err
= (nread
< 0) ? ERRNO
: 0;
3954 if (conn
->ctx
->stop_flag
) {
3958 if ((nread
> 0) || (nread
== 0 && len
== 0)) {
3959 /* some data has been read, or no data was requested */
3963 /* shutdown of the socket at client side */
3967 /* socket error - check errno */
3969 if (err
== WSAEWOULDBLOCK
) {
3970 /* standard case if called from close_socket_gracefully */
3972 } else if (err
== WSAETIMEDOUT
) {
3973 /* timeout is handled by the while loop */
3975 DEBUG_TRACE("recv() failed, error %d", err
);
3979 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
3980 * if the timeout is reached and if the socket was set to non-
3981 * blocking in close_socket_gracefully, so we can not distinguish
3982 * here. We have to wait for the timeout in both cases for now.
3984 if (err
== EAGAIN
|| err
== EWOULDBLOCK
|| err
== EINTR
) {
3985 /* EAGAIN/EWOULDBLOCK:
3986 * standard case if called from close_socket_gracefully
3987 * => should return -1 */
3988 /* or timeout occured
3989 * => the code must stay in the while loop */
3991 /* EINTR can be generated on a socket with a timeout set even
3992 * when SA_RESTART is effective for all relevant signals
3994 * => stay in the while loop */
3996 DEBUG_TRACE("recv() failed, error %d", err
);
4002 clock_gettime(CLOCK_MONOTONIC
, &now
);
4004 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
4006 /* Timeout occured, but no data available. */
4012 pull_all(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
)
4015 double timeout
= -1.0;
4017 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
4018 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
4021 while (len
> 0 && conn
->ctx
->stop_flag
== 0) {
4022 n
= pull(fp
, conn
, buf
+ nread
, len
, timeout
);
4025 nread
= n
; /* Propagate the error */
4028 } else if (n
== 0) {
4029 break; /* No more data to read */
4031 conn
->consumed_content
+= n
;
4042 discard_unread_request_data(struct mg_connection
*conn
)
4044 char buf
[MG_BUF_LEN
];
4052 to_read
= sizeof(buf
);
4054 if (conn
->is_chunked
) {
4055 /* Chunked encoding: 1=chunk not read completely, 2=chunk read
4057 while (conn
->is_chunked
== 1) {
4058 nread
= mg_read(conn
, buf
, to_read
);
4065 /* Not chunked: content length is known */
4066 while (conn
->consumed_content
< conn
->content_len
) {
4068 > (size_t)(conn
->content_len
- conn
->consumed_content
)) {
4069 to_read
= (size_t)(conn
->content_len
- conn
->consumed_content
);
4072 nread
= mg_read(conn
, buf
, to_read
);
4082 mg_read_inner(struct mg_connection
*conn
, void *buf
, size_t len
)
4084 int64_t n
, buffered_len
, nread
;
4086 (int64_t)(len
> INT_MAX
? INT_MAX
: len
); /* since the return value is
4087 * int, we may not read more
4095 /* If Content-Length is not set for a PUT or POST request, read until
4096 * socket is closed */
4097 if (conn
->consumed_content
== 0 && conn
->content_len
== -1) {
4098 conn
->content_len
= INT64_MAX
;
4099 conn
->must_close
= 1;
4103 if (conn
->consumed_content
< conn
->content_len
) {
4104 /* Adjust number of bytes to read. */
4105 int64_t left_to_read
= conn
->content_len
- conn
->consumed_content
;
4106 if (left_to_read
< len64
) {
4107 /* Do not read more than the total content length of the request.
4109 len64
= left_to_read
;
4112 /* Return buffered data */
4113 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
4114 - conn
->consumed_content
;
4115 if (buffered_len
> 0) {
4116 if (len64
< buffered_len
) {
4117 buffered_len
= len64
;
4119 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
4120 memcpy(buf
, body
, (size_t)buffered_len
);
4121 len64
-= buffered_len
;
4122 conn
->consumed_content
+= buffered_len
;
4123 nread
+= buffered_len
;
4124 buf
= (char *)buf
+ buffered_len
;
4127 /* We have returned all buffered data. Read new data from the remote
4130 if ((n
= pull_all(NULL
, conn
, (char *)buf
, (int)len64
)) >= 0) {
4133 nread
= (nread
> 0 ? nread
: n
);
4141 mg_getc(struct mg_connection
*conn
)
4147 conn
->content_len
++;
4148 if (mg_read_inner(conn
, &c
, 1) <= 0) {
4156 mg_read(struct mg_connection
*conn
, void *buf
, size_t len
)
4158 if (len
> INT_MAX
) {
4166 if (conn
->is_chunked
) {
4167 size_t all_read
= 0;
4171 if (conn
->is_chunked
== 2) {
4172 /* No more data left to read */
4176 if (conn
->chunk_remainder
) {
4177 /* copy from the remainder of the last received chunk */
4180 ((conn
->chunk_remainder
> len
) ? (len
)
4181 : (conn
->chunk_remainder
));
4183 conn
->content_len
+= (int)read_now
;
4185 mg_read_inner(conn
, (char *)buf
+ all_read
, read_now
);
4186 all_read
+= (size_t)read_ret
;
4188 conn
->chunk_remainder
-= read_now
;
4191 if (conn
->chunk_remainder
== 0) {
4192 /* the rest of the data in the current chunk has been read
4194 if ((mg_getc(conn
) != '\r') || (mg_getc(conn
) != '\n')) {
4195 /* Protocol violation */
4201 /* fetch a new chunk */
4205 unsigned long chunkSize
= 0;
4207 for (i
= 0; i
< ((int)sizeof(lenbuf
) - 1); i
++) {
4208 lenbuf
[i
] = mg_getc(conn
);
4209 if (i
> 0 && lenbuf
[i
] == '\r' && lenbuf
[i
- 1] != '\r') {
4212 if (i
> 1 && lenbuf
[i
] == '\n' && lenbuf
[i
- 1] == '\r') {
4214 chunkSize
= strtoul(lenbuf
, &end
, 16);
4215 if (chunkSize
== 0) {
4216 /* regular end of content */
4217 conn
->is_chunked
= 2;
4221 if (!isalnum(lenbuf
[i
])) {
4222 /* illegal character for chunk length */
4226 if ((end
== NULL
) || (*end
!= '\r')) {
4227 /* chunksize not set correctly */
4230 if (chunkSize
== 0) {
4234 conn
->chunk_remainder
= chunkSize
;
4238 return (int)all_read
;
4240 return mg_read_inner(conn
, buf
, len
);
4245 mg_write(struct mg_connection
*conn
, const void *buf
, size_t len
)
4248 int64_t n
, total
, allowed
;
4254 if (conn
->throttle
> 0) {
4255 if ((now
= time(NULL
)) != conn
->last_throttle_time
) {
4256 conn
->last_throttle_time
= now
;
4257 conn
->last_throttle_bytes
= 0;
4259 allowed
= conn
->throttle
- conn
->last_throttle_bytes
;
4260 if (allowed
> (int64_t)len
) {
4261 allowed
= (int64_t)len
;
4263 if ((total
= push_all(conn
->ctx
,
4268 (int64_t)allowed
)) == allowed
) {
4269 buf
= (const char *)buf
+ total
;
4270 conn
->last_throttle_bytes
+= total
;
4271 while (total
< (int64_t)len
&& conn
->ctx
->stop_flag
== 0) {
4272 allowed
= conn
->throttle
> (int64_t)len
- total
4273 ? (int64_t)len
- total
4275 if ((n
= push_all(conn
->ctx
,
4280 (int64_t)allowed
)) != allowed
) {
4284 conn
->last_throttle_bytes
= allowed
;
4285 conn
->last_throttle_time
= time(NULL
);
4286 buf
= (const char *)buf
+ n
;
4291 total
= push_all(conn
->ctx
,
4302 /* Alternative alloc_vprintf() for non-compliant C runtimes */
4304 alloc_vprintf2(char **buf
, const char *fmt
, va_list ap
)
4307 size_t size
= MG_BUF_LEN
/ 4;
4317 *buf
= (char *)mg_malloc(size
);
4322 va_copy(ap_copy
, ap
);
4323 len
= vsnprintf_impl(*buf
, size
- 1, fmt
, ap_copy
);
4325 (*buf
)[size
- 1] = 0;
4332 /* Print message to buffer. If buffer is large enough to hold the message,
4333 * return buffer. If buffer is to small, allocate large enough buffer on heap,
4334 * and return allocated buffer. */
4336 alloc_vprintf(char **out_buf
,
4338 size_t prealloc_size
,
4345 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
4346 * buffer is too small. Also, older versions of msvcrt.dll do not have
4347 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
4348 * Therefore, we make two passes: on first pass, get required message
4350 * On second pass, actually print the message. */
4351 va_copy(ap_copy
, ap
);
4352 len
= vsnprintf_impl(NULL
, 0, fmt
, ap_copy
);
4356 /* C runtime is not standard compliant, vsnprintf() returned -1.
4357 * Switch to alternative code path that uses incremental allocations.
4359 va_copy(ap_copy
, ap
);
4360 len
= alloc_vprintf2(out_buf
, fmt
, ap
);
4363 } else if ((size_t)(len
) >= prealloc_size
) {
4364 /* The pre-allocated buffer not large enough. */
4365 /* Allocate a new buffer. */
4366 *out_buf
= (char *)mg_malloc((size_t)(len
) + 1);
4368 /* Allocation failed. Return -1 as "out of memory" error. */
4371 /* Buffer allocation successful. Store the string there. */
4372 va_copy(ap_copy
, ap
);
4373 IGNORE_UNUSED_RESULT(
4374 vsnprintf_impl(*out_buf
, (size_t)(len
) + 1, fmt
, ap_copy
));
4378 /* The pre-allocated buffer is large enough.
4379 * Use it to store the string and return the address. */
4380 va_copy(ap_copy
, ap
);
4381 IGNORE_UNUSED_RESULT(
4382 vsnprintf_impl(prealloc_buf
, prealloc_size
, fmt
, ap_copy
));
4384 *out_buf
= prealloc_buf
;
4392 mg_vprintf(struct mg_connection
*conn
, const char *fmt
, va_list ap
)
4394 char mem
[MG_BUF_LEN
];
4398 if ((len
= alloc_vprintf(&buf
, mem
, sizeof(mem
), fmt
, ap
)) > 0) {
4399 len
= mg_write(conn
, buf
, (size_t)len
);
4401 if (buf
!= mem
&& buf
!= NULL
) {
4410 mg_printf(struct mg_connection
*conn
, const char *fmt
, ...)
4416 result
= mg_vprintf(conn
, fmt
, ap
);
4424 mg_url_decode(const char *src
,
4428 int is_form_url_encoded
)
4431 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
4433 for (i
= j
= 0; i
< src_len
&& j
< dst_len
- 1; i
++, j
++) {
4434 if (i
< src_len
- 2 && src
[i
] == '%'
4435 && isxdigit(*(const unsigned char *)(src
+ i
+ 1))
4436 && isxdigit(*(const unsigned char *)(src
+ i
+ 2))) {
4437 a
= tolower(*(const unsigned char *)(src
+ i
+ 1));
4438 b
= tolower(*(const unsigned char *)(src
+ i
+ 2));
4439 dst
[j
] = (char)((HEXTOI(a
) << 4) | HEXTOI(b
));
4441 } else if (is_form_url_encoded
&& src
[i
] == '+') {
4448 dst
[j
] = '\0'; /* Null-terminate the destination */
4450 return i
>= src_len
? j
: -1;
4455 mg_get_var(const char *data
,
4461 return mg_get_var2(data
, data_len
, name
, dst
, dst_len
, 0);
4466 mg_get_var2(const char *data
,
4473 const char *p
, *e
, *s
;
4477 if (dst
== NULL
|| dst_len
== 0) {
4479 } else if (data
== NULL
|| name
== NULL
|| data_len
== 0) {
4483 name_len
= strlen(name
);
4484 e
= data
+ data_len
;
4488 /* data is "var1=val1&var2=val2...". Find variable first */
4489 for (p
= data
; p
+ name_len
< e
; p
++) {
4490 if ((p
== data
|| p
[-1] == '&') && p
[name_len
] == '='
4491 && !mg_strncasecmp(name
, p
, name_len
) && 0 == occurrence
--) {
4492 /* Point p to variable value */
4495 /* Point s to the end of the value */
4496 s
= (const char *)memchr(p
, '&', (size_t)(e
- p
));
4500 /* assert(s >= p); */
4505 /* Decode variable into destination buffer */
4506 len
= mg_url_decode(p
, (int)(s
- p
), dst
, (int)dst_len
, 1);
4508 /* Redirect error code from -1 to -2 (destination buffer too
4523 mg_get_cookie(const char *cookie_header
,
4524 const char *var_name
,
4528 const char *s
, *p
, *end
;
4529 int name_len
, len
= -1;
4531 if (dst
== NULL
|| dst_size
== 0) {
4533 } else if (var_name
== NULL
|| (s
= cookie_header
) == NULL
) {
4537 name_len
= (int)strlen(var_name
);
4538 end
= s
+ strlen(s
);
4541 for (; (s
= mg_strcasestr(s
, var_name
)) != NULL
; s
+= name_len
) {
4542 if (s
[name_len
] == '=') {
4544 if ((p
= strchr(s
, ' ')) == NULL
) {
4550 if (*s
== '"' && p
[-1] == '"' && p
> s
+ 1) {
4554 if ((size_t)(p
- s
) < dst_size
) {
4556 mg_strlcpy(dst
, s
, (size_t)len
+ 1);
4568 #if defined(USE_WEBSOCKET) || defined(USE_LUA)
4570 base64_encode(const unsigned char *src
, int src_len
, char *dst
)
4572 static const char *b64
=
4573 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4576 for (i
= j
= 0; i
< src_len
; i
+= 3) {
4578 b
= i
+ 1 >= src_len
? 0 : src
[i
+ 1];
4579 c
= i
+ 2 >= src_len
? 0 : src
[i
+ 2];
4581 dst
[j
++] = b64
[a
>> 2];
4582 dst
[j
++] = b64
[((a
& 3) << 4) | (b
>> 4)];
4583 if (i
+ 1 < src_len
) {
4584 dst
[j
++] = b64
[(b
& 15) << 2 | (c
>> 6)];
4586 if (i
+ 2 < src_len
) {
4587 dst
[j
++] = b64
[c
& 63];
4590 while (j
% 4 != 0) {
4598 #if defined(USE_LUA)
4599 static unsigned char
4600 b64reverse(char letter
)
4602 if (letter
>= 'A' && letter
<= 'Z') {
4603 return letter
- 'A';
4605 if (letter
>= 'a' && letter
<= 'z') {
4606 return letter
- 'a' + 26;
4608 if (letter
>= '0' && letter
<= '9') {
4609 return letter
- '0' + 52;
4611 if (letter
== '+') {
4614 if (letter
== '/') {
4617 if (letter
== '=') {
4618 return 255; /* normal end */
4620 return 254; /* error */
4625 base64_decode(const unsigned char *src
, int src_len
, char *dst
, size_t *dst_len
)
4628 unsigned char a
, b
, c
, d
;
4632 for (i
= 0; i
< src_len
; i
+= 4) {
4633 a
= b64reverse(src
[i
]);
4638 b
= b64reverse(i
+ 1 >= src_len
? 0 : src
[i
+ 1]);
4643 c
= b64reverse(i
+ 2 >= src_len
? 0 : src
[i
+ 2]);
4648 d
= b64reverse(i
+ 3 >= src_len
? 0 : src
[i
+ 3]);
4653 dst
[(*dst_len
)++] = (a
<< 2) + (b
>> 4);
4655 dst
[(*dst_len
)++] = (b
<< 4) + (c
>> 2);
4657 dst
[(*dst_len
)++] = (c
<< 6) + d
;
4667 is_put_or_delete_method(const struct mg_connection
*conn
)
4670 const char *s
= conn
->request_info
.request_method
;
4671 return s
!= NULL
&& (!strcmp(s
, "PUT") || !strcmp(s
, "DELETE")
4672 || !strcmp(s
, "MKCOL") || !strcmp(s
, "PATCH"));
4679 interpret_uri(struct mg_connection
*conn
, /* in: request (must be valid) */
4680 char *filename
, /* out: filename */
4681 size_t filename_buf_len
, /* in: size of filename buffer */
4682 struct file
*filep
, /* out: file structure */
4683 int *is_found
, /* out: file is found (directly) */
4684 int *is_script_resource
, /* out: handled by a script? */
4685 int *is_websocket_request
, /* out: websocket connetion? */
4686 int *is_put_or_delete_request
/* out: put/delete a file? */
4689 /* TODO (high): Restructure this function */
4691 #if !defined(NO_FILES)
4692 const char *uri
= conn
->request_info
.local_uri
;
4693 const char *root
= conn
->ctx
->config
[DOCUMENT_ROOT
];
4694 const char *rewrite
;
4697 char gz_path
[PATH_MAX
];
4698 char const *accept_encoding
;
4700 #if !defined(NO_CGI) || defined(USE_LUA)
4704 (void)filename_buf_len
; /* unused if NO_FILES is defined */
4707 memset(filep
, 0, sizeof(*filep
));
4710 *is_script_resource
= 0;
4711 *is_put_or_delete_request
= is_put_or_delete_method(conn
);
4713 #if defined(USE_WEBSOCKET)
4714 *is_websocket_request
= is_websocket_protocol(conn
);
4715 #if !defined(NO_FILES)
4716 if (*is_websocket_request
&& conn
->ctx
->config
[WEBSOCKET_ROOT
]) {
4717 root
= conn
->ctx
->config
[WEBSOCKET_ROOT
];
4719 #endif /* !NO_FILES */
4720 #else /* USE_WEBSOCKET */
4721 *is_websocket_request
= 0;
4722 #endif /* USE_WEBSOCKET */
4724 #if !defined(NO_FILES)
4725 /* Note that root == NULL is a regular use case here. This occurs,
4726 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
4727 * config is not required. */
4729 /* all file related outputs have already been set to 0, just return
4734 /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
4735 * of the path one byte on the right.
4736 * If document_root is NULL, leave the file empty. */
4738 conn
, &truncated
, filename
, filename_buf_len
- 1, "%s%s", root
, uri
);
4741 goto interpret_cleanup
;
4744 rewrite
= conn
->ctx
->config
[REWRITE
];
4745 while ((rewrite
= next_option(rewrite
, &a
, &b
)) != NULL
) {
4746 if ((match_len
= match_prefix(a
.ptr
, a
.len
, uri
)) > 0) {
4750 filename_buf_len
- 1,
4760 goto interpret_cleanup
;
4763 /* Local file path and name, corresponding to requested URI
4764 * is now stored in "filename" variable. */
4765 if (mg_stat(conn
, filename
, filep
)) {
4766 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4767 /* File exists. Check if it is a script type. */
4769 #if !defined(NO_CGI)
4770 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4771 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4774 #if defined(USE_LUA)
4775 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4776 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4779 #if defined(USE_DUKTAPE)
4780 || match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4782 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4786 /* The request addresses a CGI script or a Lua script. The URI
4787 * corresponds to the script itself (like /path/script.cgi),
4788 * and there is no additional resource path
4789 * (like /path/script.cgi/something).
4790 * Requests that modify (replace or delete) a resource, like
4791 * PUT and DELETE requests, should replace/delete the script
4793 * Requests that read or write from/to a resource, like GET and
4794 * POST requests, should call the script and return the
4795 * generated response. */
4796 *is_script_resource
= !*is_put_or_delete_request
;
4798 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4803 /* If we can't find the actual file, look for the file
4804 * with the same name but a .gz extension. If we find it,
4805 * use that and set the gzipped flag in the file struct
4806 * to indicate that the response need to have the content-
4807 * encoding: gzip header.
4808 * We can only do this if the browser declares support. */
4809 if ((accept_encoding
= mg_get_header(conn
, "Accept-Encoding")) != NULL
) {
4810 if (strstr(accept_encoding
, "gzip") != NULL
) {
4812 conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", filename
);
4815 goto interpret_cleanup
;
4818 if (mg_stat(conn
, gz_path
, filep
)) {
4823 /* Currently gz files can not be scripts. */
4829 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4830 /* Support PATH_INFO for CGI scripts. */
4831 for (p
= filename
+ strlen(filename
); p
> filename
+ 1; p
--) {
4835 #if !defined(NO_CGI)
4836 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4837 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4840 #if defined(USE_LUA)
4841 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4843 conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4846 #if defined(USE_DUKTAPE)
4848 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4849 strlen(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4852 ) && mg_stat(conn
, filename
, filep
)) {
4853 /* Shift PATH_INFO block one character right, e.g.
4854 * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
4855 * conn->path_info is pointing to the local variable "path"
4856 * declared in handle_request(), so PATH_INFO is not valid
4857 * after handle_request returns. */
4858 conn
->path_info
= p
+ 1;
4859 memmove(p
+ 2, p
+ 1, strlen(p
+ 1) + 1); /* +1 is for
4862 *is_script_resource
= 1;
4869 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4870 #endif /* !defined(NO_FILES) */
4873 #if !defined(NO_FILES)
4874 /* Reset all outputs */
4876 memset(filep
, 0, sizeof(*filep
));
4879 *is_script_resource
= 0;
4880 *is_websocket_request
= 0;
4881 *is_put_or_delete_request
= 0;
4882 #endif /* !defined(NO_FILES) */
4886 /* Check whether full request is buffered. Return:
4887 * -1 if request is malformed
4888 * 0 if request is not yet fully buffered
4889 * >0 actual request length, including last \r\n\r\n */
4891 get_request_len(const char *buf
, int buflen
)
4896 for (s
= buf
, e
= s
+ buflen
- 1; len
<= 0 && s
< e
; s
++)
4897 /* Control characters are not allowed but >=128 is. */
4898 if (!isprint(*(const unsigned char *)s
) && *s
!= '\r' && *s
!= '\n'
4899 && *(const unsigned char *)s
< 128) {
4901 break; /* [i_a] abort scan as soon as one malformed character is
4903 /* don't let subsequent \r\n\r\n win us over anyhow */
4904 } else if (s
[0] == '\n' && s
[1] == '\n') {
4905 len
= (int)(s
- buf
) + 2;
4906 } else if (s
[0] == '\n' && &s
[1] < e
&& s
[1] == '\r' && s
[2] == '\n') {
4907 len
= (int)(s
- buf
) + 3;
4914 #if !defined(NO_CACHING)
4915 /* Convert month to the month number. Return -1 on error, or month number */
4917 get_month_index(const char *s
)
4921 for (i
= 0; i
< ARRAY_SIZE(month_names
); i
++) {
4922 if (!strcmp(s
, month_names
[i
])) {
4931 /* Parse UTC date-time string, and return the corresponding time_t value. */
4933 parse_date_string(const char *datetime
)
4935 char month_str
[32] = {0};
4936 int second
, minute
, hour
, day
, month
, year
;
4937 time_t result
= (time_t)0;
4940 if ((sscanf(datetime
,
4941 "%d/%3s/%d %d:%d:%d",
4947 &second
) == 6) || (sscanf(datetime
,
4948 "%d %3s %d %d:%d:%d",
4955 || (sscanf(datetime
,
4956 "%*3s, %d %3s %d %d:%d:%d",
4962 &second
) == 6) || (sscanf(datetime
,
4963 "%d-%3s-%d %d:%d:%d",
4970 month
= get_month_index(month_str
);
4971 if ((month
>= 0) && (year
>= 1970)) {
4972 memset(&tm
, 0, sizeof(tm
));
4973 tm
.tm_year
= year
- 1900;
4979 result
= timegm(&tm
);
4985 #endif /* !NO_CACHING */
4988 /* Protect against directory disclosure attack by removing '..',
4989 * excessive '/' and '\' characters */
4991 remove_double_dots_and_double_slashes(char *s
)
4995 while (*s
!= '\0') {
4997 if (s
[-1] == '/' || s
[-1] == '\\') {
4998 /* Skip all following slashes, backslashes and double-dots */
4999 while (s
[0] != '\0') {
5000 if (s
[0] == '/' || s
[0] == '\\') {
5002 } else if (s
[0] == '.' && s
[1] == '.') {
5014 static const struct {
5015 const char *extension
;
5017 const char *mime_type
;
5018 } builtin_mime_types
[] = {
5019 /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
5020 * application types */
5021 {".doc", 4, "application/msword"},
5022 {".eps", 4, "application/postscript"},
5023 {".exe", 4, "application/octet-stream"},
5024 {".js", 3, "application/javascript"},
5025 {".json", 5, "application/json"},
5026 {".pdf", 4, "application/pdf"},
5027 {".ps", 3, "application/postscript"},
5028 {".rtf", 4, "application/rtf"},
5029 {".xhtml", 6, "application/xhtml+xml"},
5030 {".xsl", 4, "application/xml"},
5031 {".xslt", 5, "application/xml"},
5034 {".ttf", 4, "application/font-sfnt"},
5035 {".cff", 4, "application/font-sfnt"},
5036 {".otf", 4, "application/font-sfnt"},
5037 {".aat", 4, "application/font-sfnt"},
5038 {".sil", 4, "application/font-sfnt"},
5039 {".pfr", 4, "application/font-tdpfr"},
5040 {".woff", 5, "application/font-woff"},
5043 {".mp3", 4, "audio/mpeg"},
5044 {".oga", 4, "audio/ogg"},
5045 {".ogg", 4, "audio/ogg"},
5048 {".gif", 4, "image/gif"},
5049 {".ief", 4, "image/ief"},
5050 {".jpeg", 5, "image/jpeg"},
5051 {".jpg", 4, "image/jpeg"},
5052 {".jpm", 4, "image/jpm"},
5053 {".jpx", 4, "image/jpx"},
5054 {".png", 4, "image/png"},
5055 {".svg", 4, "image/svg+xml"},
5056 {".tif", 4, "image/tiff"},
5057 {".tiff", 5, "image/tiff"},
5060 {".wrl", 4, "model/vrml"},
5063 {".css", 4, "text/css"},
5064 {".csv", 4, "text/csv"},
5065 {".htm", 4, "text/html"},
5066 {".html", 5, "text/html"},
5067 {".sgm", 4, "text/sgml"},
5068 {".shtm", 5, "text/html"},
5069 {".shtml", 6, "text/html"},
5070 {".txt", 4, "text/plain"},
5071 {".xml", 4, "text/xml"},
5074 {".mov", 4, "video/quicktime"},
5075 {".mp4", 4, "video/mp4"},
5076 {".mpeg", 5, "video/mpeg"},
5077 {".mpg", 4, "video/mpeg"},
5078 {".ogv", 4, "video/ogg"},
5079 {".qt", 3, "video/quicktime"},
5081 /* not registered types
5082 * (http://reference.sitepoint.com/html/mime-types-full,
5083 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
5084 {".arj", 4, "application/x-arj-compressed"},
5085 {".gz", 3, "application/x-gunzip"},
5086 {".rar", 4, "application/x-arj-compressed"},
5087 {".swf", 4, "application/x-shockwave-flash"},
5088 {".tar", 4, "application/x-tar"},
5089 {".tgz", 4, "application/x-tar-gz"},
5090 {".torrent", 8, "application/x-bittorrent"},
5091 {".ppt", 4, "application/x-mspowerpoint"},
5092 {".xls", 4, "application/x-msexcel"},
5093 {".zip", 4, "application/x-zip-compressed"},
5096 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
5097 {".aif", 4, "audio/x-aif"},
5098 {".m3u", 4, "audio/x-mpegurl"},
5099 {".mid", 4, "audio/x-midi"},
5100 {".ra", 3, "audio/x-pn-realaudio"},
5101 {".ram", 4, "audio/x-pn-realaudio"},
5102 {".wav", 4, "audio/x-wav"},
5103 {".bmp", 4, "image/bmp"},
5104 {".ico", 4, "image/x-icon"},
5105 {".pct", 4, "image/x-pct"},
5106 {".pict", 5, "image/pict"},
5107 {".rgb", 4, "image/x-rgb"},
5108 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
5109 {".asf", 4, "video/x-ms-asf"},
5110 {".avi", 4, "video/x-msvideo"},
5111 {".m4v", 4, "video/x-m4v"},
5116 mg_get_builtin_mime_type(const char *path
)
5121 path_len
= strlen(path
);
5123 for (i
= 0; builtin_mime_types
[i
].extension
!= NULL
; i
++) {
5124 ext
= path
+ (path_len
- builtin_mime_types
[i
].ext_len
);
5125 if (path_len
> builtin_mime_types
[i
].ext_len
5126 && mg_strcasecmp(ext
, builtin_mime_types
[i
].extension
) == 0) {
5127 return builtin_mime_types
[i
].mime_type
;
5131 return "text/plain";
5135 /* Look at the "path" extension and figure what mime type it has.
5136 * Store mime type in the vector. */
5138 get_mime_type(struct mg_context
*ctx
, const char *path
, struct vec
*vec
)
5140 struct vec ext_vec
, mime_vec
;
5141 const char *list
, *ext
;
5144 path_len
= strlen(path
);
5146 if (ctx
== NULL
|| vec
== NULL
) {
5150 /* Scan user-defined mime types first, in case user wants to
5151 * override default mime types. */
5152 list
= ctx
->config
[EXTRA_MIME_TYPES
];
5153 while ((list
= next_option(list
, &ext_vec
, &mime_vec
)) != NULL
) {
5154 /* ext now points to the path suffix */
5155 ext
= path
+ path_len
- ext_vec
.len
;
5156 if (mg_strncasecmp(ext
, ext_vec
.ptr
, ext_vec
.len
) == 0) {
5162 vec
->ptr
= mg_get_builtin_mime_type(path
);
5163 vec
->len
= strlen(vec
->ptr
);
5167 /* Stringify binary data. Output buffer must be twice as big as input,
5168 * because each byte takes 2 bytes in string representation */
5170 bin2str(char *to
, const unsigned char *p
, size_t len
)
5172 static const char *hex
= "0123456789abcdef";
5174 for (; len
--; p
++) {
5175 *to
++ = hex
[p
[0] >> 4];
5176 *to
++ = hex
[p
[0] & 0x0f];
5182 /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
5184 mg_md5(char buf
[33], ...)
5186 md5_byte_t hash
[16];
5194 while ((p
= va_arg(ap
, const char *)) != NULL
) {
5195 md5_append(&ctx
, (const md5_byte_t
*)p
, strlen(p
));
5199 md5_finish(&ctx
, hash
);
5200 bin2str(buf
, hash
, sizeof(hash
));
5205 /* Check the user's password, return 1 if OK */
5207 check_password(const char *method
,
5214 const char *response
)
5216 char ha2
[32 + 1], expected_response
[32 + 1];
5218 /* Some of the parameters may be NULL */
5219 if (method
== NULL
|| nonce
== NULL
|| nc
== NULL
|| cnonce
== NULL
5221 || response
== NULL
) {
5225 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
5226 if (strlen(response
) != 32) {
5230 mg_md5(ha2
, method
, ":", uri
, NULL
);
5231 mg_md5(expected_response
,
5245 return mg_strcasecmp(response
, expected_response
) == 0;
5249 /* Use the global passwords file, if specified by auth_gpass option,
5250 * or search for .htpasswd in the requested directory. */
5252 open_auth_file(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
5254 if (conn
!= NULL
&& conn
->ctx
!= NULL
) {
5255 char name
[PATH_MAX
];
5256 const char *p
, *e
, *gpass
= conn
->ctx
->config
[GLOBAL_PASSWORDS_FILE
];
5257 struct file file
= STRUCT_FILE_INITIALIZER
;
5260 if (gpass
!= NULL
) {
5261 /* Use global passwords file */
5262 if (!mg_fopen(conn
, gpass
, "r", filep
)) {
5264 mg_cry(conn
, "fopen(%s): %s", gpass
, strerror(ERRNO
));
5267 /* Important: using local struct file to test path for is_directory
5268 * flag. If filep is used, mg_stat() makes it appear as if auth file
5270 } else if (mg_stat(conn
, path
, &file
) && file
.is_directory
) {
5277 PASSWORDS_FILE_NAME
);
5279 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5281 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5285 /* Try to find .htpasswd in requested directory. */
5286 for (p
= path
, e
= p
+ strlen(p
) - 1; e
> p
; e
--) {
5298 PASSWORDS_FILE_NAME
);
5300 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5302 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5310 /* Parsed Authorization header */
5312 char *user
, *uri
, *cnonce
, *response
, *qop
, *nc
, *nonce
;
5316 /* Return 1 on success. Always initializes the ah structure. */
5318 parse_auth_header(struct mg_connection
*conn
,
5323 char *name
, *value
, *s
;
5324 const char *auth_header
;
5331 (void)memset(ah
, 0, sizeof(*ah
));
5332 if ((auth_header
= mg_get_header(conn
, "Authorization")) == NULL
5333 || mg_strncasecmp(auth_header
, "Digest ", 7) != 0) {
5337 /* Make modifiable copy of the auth header */
5338 (void)mg_strlcpy(buf
, auth_header
+ 7, buf_size
);
5341 /* Parse authorization header */
5343 /* Gobble initial spaces */
5344 while (isspace(*(unsigned char *)s
)) {
5347 name
= skip_quoted(&s
, "=", " ", 0);
5348 /* Value is either quote-delimited, or ends at first comma or space. */
5351 value
= skip_quoted(&s
, "\"", " ", '\\');
5356 value
= skip_quoted(&s
, ", ", " ", 0); /* IE uses commas, FF uses
5359 if (*name
== '\0') {
5363 if (!strcmp(name
, "username")) {
5365 } else if (!strcmp(name
, "cnonce")) {
5367 } else if (!strcmp(name
, "response")) {
5368 ah
->response
= value
;
5369 } else if (!strcmp(name
, "uri")) {
5371 } else if (!strcmp(name
, "qop")) {
5373 } else if (!strcmp(name
, "nc")) {
5375 } else if (!strcmp(name
, "nonce")) {
5380 #ifndef NO_NONCE_CHECK
5381 /* Read the nonce from the response. */
5382 if (ah
->nonce
== NULL
) {
5386 nonce
= strtoull(ah
->nonce
, &s
, 10);
5387 if ((s
== NULL
) || (*s
!= 0)) {
5391 /* Convert the nonce from the client to a number. */
5392 nonce
^= conn
->ctx
->auth_nonce_mask
;
5394 /* The converted number corresponds to the time the nounce has been
5395 * created. This should not be earlier than the server start. */
5396 /* Server side nonce check is valuable in all situations but one:
5397 * if the server restarts frequently, but the client should not see
5398 * that, so the server should accept nonces from previous starts. */
5399 /* However, the reasonable default is to not accept a nonce from a
5400 * previous start, so if anyone changed the access rights between
5401 * two restarts, a new login is required. */
5402 if (nonce
< (uint64_t)conn
->ctx
->start_time
) {
5403 /* nonce is from a previous start of the server and no longer valid
5404 * (replay attack?) */
5407 /* Check if the nonce is too high, so it has not (yet) been used by the
5409 if (nonce
>= ((uint64_t)conn
->ctx
->start_time
+ conn
->ctx
->nonce_count
)) {
5414 /* CGI needs it as REMOTE_USER */
5415 if (ah
->user
!= NULL
) {
5416 conn
->request_info
.remote_user
= mg_strdup(ah
->user
);
5426 mg_fgets(char *buf
, size_t size
, struct file
*filep
, char **p
)
5436 if (filep
->membuf
!= NULL
&& *p
!= NULL
) {
5437 memend
= (const char *)&filep
->membuf
[filep
->size
];
5438 /* Search for \n from p till the end of stream */
5439 eof
= (char *)memchr(*p
, '\n', (size_t)(memend
- *p
));
5441 eof
+= 1; /* Include \n */
5443 eof
= memend
; /* Copy remaining data */
5445 len
= (size_t)(eof
- *p
) > size
- 1 ? size
- 1 : (size_t)(eof
- *p
);
5446 memcpy(buf
, *p
, len
);
5449 return len
? eof
: NULL
;
5450 } else if (filep
->fp
!= NULL
) {
5451 return fgets(buf
, (int)size
, filep
->fp
);
5457 struct read_auth_file_struct
{
5458 struct mg_connection
*conn
;
5461 char buf
[256 + 256 + 40];
5469 read_auth_file(struct file
*filep
, struct read_auth_file_struct
*workdata
)
5472 int is_authorized
= 0;
5476 if (!filep
|| !workdata
) {
5480 /* Loop over passwords file */
5481 p
= (char *)filep
->membuf
;
5482 while (mg_fgets(workdata
->buf
, sizeof(workdata
->buf
), filep
, &p
) != NULL
) {
5483 l
= strlen(workdata
->buf
);
5485 if (isspace(workdata
->buf
[l
- 1])
5486 || iscntrl(workdata
->buf
[l
- 1])) {
5488 workdata
->buf
[l
] = 0;
5496 workdata
->f_user
= workdata
->buf
;
5498 if (workdata
->f_user
[0] == ':') {
5499 /* user names may not contain a ':' and may not be empty,
5500 * so lines starting with ':' may be used for a special purpose */
5501 if (workdata
->f_user
[1] == '#') {
5502 /* :# is a comment */
5504 } else if (!strncmp(workdata
->f_user
+ 1, "include=", 8)) {
5505 if (mg_fopen(workdata
->conn
, workdata
->f_user
+ 9, "r", &fp
)) {
5506 is_authorized
= read_auth_file(&fp
, workdata
);
5509 mg_cry(workdata
->conn
,
5510 "%s: cannot open authorization file: %s",
5516 /* everything is invalid for the moment (might change in the
5518 mg_cry(workdata
->conn
,
5519 "%s: syntax error in authorization file: %s",
5525 workdata
->f_domain
= strchr(workdata
->f_user
, ':');
5526 if (workdata
->f_domain
== NULL
) {
5527 mg_cry(workdata
->conn
,
5528 "%s: syntax error in authorization file: %s",
5533 *(workdata
->f_domain
) = 0;
5534 (workdata
->f_domain
)++;
5536 workdata
->f_ha1
= strchr(workdata
->f_domain
, ':');
5537 if (workdata
->f_ha1
== NULL
) {
5538 mg_cry(workdata
->conn
,
5539 "%s: syntax error in authorization file: %s",
5544 *(workdata
->f_ha1
) = 0;
5545 (workdata
->f_ha1
)++;
5547 if (!strcmp(workdata
->ah
.user
, workdata
->f_user
)
5548 && !strcmp(workdata
->domain
, workdata
->f_domain
)) {
5549 return check_password(workdata
->conn
->request_info
.request_method
,
5554 workdata
->ah
.cnonce
,
5556 workdata
->ah
.response
);
5560 return is_authorized
;
5564 /* Authorize against the opened passwords file. Return 1 if authorized. */
5566 authorize(struct mg_connection
*conn
, struct file
*filep
)
5568 struct read_auth_file_struct workdata
;
5569 char buf
[MG_BUF_LEN
];
5571 if (!conn
|| !conn
->ctx
) {
5575 memset(&workdata
, 0, sizeof(workdata
));
5576 workdata
.conn
= conn
;
5578 if (!parse_auth_header(conn
, buf
, sizeof(buf
), &workdata
.ah
)) {
5581 workdata
.domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
5583 return read_auth_file(filep
, &workdata
);
5587 /* Return 1 if request is authorised, 0 otherwise. */
5589 check_authorization(struct mg_connection
*conn
, const char *path
)
5591 char fname
[PATH_MAX
];
5592 struct vec uri_vec
, filename_vec
;
5594 struct file file
= STRUCT_FILE_INITIALIZER
;
5595 int authorized
= 1, truncated
;
5597 if (!conn
|| !conn
->ctx
) {
5601 list
= conn
->ctx
->config
[PROTECT_URI
];
5602 while ((list
= next_option(list
, &uri_vec
, &filename_vec
)) != NULL
) {
5603 if (!memcmp(conn
->request_info
.local_uri
, uri_vec
.ptr
, uri_vec
.len
)) {
5609 (int)filename_vec
.len
,
5612 if (truncated
|| !mg_fopen(conn
, fname
, "r", &file
)) {
5614 "%s: cannot open %s: %s",
5623 if (!is_file_opened(&file
)) {
5624 open_auth_file(conn
, path
, &file
);
5627 if (is_file_opened(&file
)) {
5628 authorized
= authorize(conn
, &file
);
5637 send_authorization_request(struct mg_connection
*conn
)
5640 time_t curtime
= time(NULL
);
5642 if (conn
&& conn
->ctx
) {
5643 uint64_t nonce
= (uint64_t)(conn
->ctx
->start_time
);
5645 (void)pthread_mutex_lock(&conn
->ctx
->nonce_mutex
);
5646 nonce
+= conn
->ctx
->nonce_count
;
5647 ++conn
->ctx
->nonce_count
;
5648 (void)pthread_mutex_unlock(&conn
->ctx
->nonce_mutex
);
5650 nonce
^= conn
->ctx
->auth_nonce_mask
;
5651 conn
->status_code
= 401;
5652 conn
->must_close
= 1;
5654 gmt_time_string(date
, sizeof(date
), &curtime
);
5656 mg_printf(conn
, "HTTP/1.1 401 Unauthorized\r\n");
5657 send_no_cache_header(conn
);
5660 "Connection: %s\r\n"
5661 "Content-Length: 0\r\n"
5662 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
5663 "nonce=\"%" UINT64_FMT
"\"\r\n\r\n",
5665 suggest_connection_header(conn
),
5666 conn
->ctx
->config
[AUTHENTICATION_DOMAIN
],
5672 #if !defined(NO_FILES)
5674 is_authorized_for_put(struct mg_connection
*conn
)
5677 struct file file
= STRUCT_FILE_INITIALIZER
;
5678 const char *passfile
= conn
->ctx
->config
[PUT_DELETE_PASSWORDS_FILE
];
5681 if (passfile
!= NULL
&& mg_fopen(conn
, passfile
, "r", &file
)) {
5682 ret
= authorize(conn
, &file
);
5694 mg_modify_passwords_file(const char *fname
,
5700 char line
[512], u
[512] = "", d
[512] = "", ha1
[33], tmp
[PATH_MAX
+ 8];
5706 /* Regard empty password as no password - remove user record. */
5707 if (pass
!= NULL
&& pass
[0] == '\0') {
5711 /* Other arguments must not be empty */
5712 if (fname
== NULL
|| domain
== NULL
|| user
== NULL
) {
5716 /* Using the given file format, user name and domain must not contain ':'
5718 if (strchr(user
, ':') != NULL
) {
5721 if (strchr(domain
, ':') != NULL
) {
5725 /* Do not allow control characters like newline in user name and domain.
5726 * Do not allow excessively long names either. */
5727 for (i
= 0; i
< 255 && user
[i
] != 0; i
++) {
5728 if (iscntrl(user
[i
])) {
5735 for (i
= 0; i
< 255 && domain
[i
] != 0; i
++) {
5736 if (iscntrl(domain
[i
])) {
5744 /* The maximum length of the path to the password file is limited */
5745 if ((strlen(fname
) + 4) >= PATH_MAX
) {
5749 /* Create a temporary file name. Length has been checked before. */
5751 strcat(tmp
, ".tmp");
5753 /* Create the file if does not exist */
5754 /* Use of fopen here is OK, since fname is only ASCII */
5755 if ((fp
= fopen(fname
, "a+")) != NULL
) {
5759 /* Open the given file and temporary file */
5760 if ((fp
= fopen(fname
, "r")) == NULL
) {
5762 } else if ((fp2
= fopen(tmp
, "w+")) == NULL
) {
5767 /* Copy the stuff to temporary file */
5768 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
5769 if (sscanf(line
, "%255[^:]:%255[^:]:%*s", u
, d
) != 2) {
5775 if (!strcmp(u
, user
) && !strcmp(d
, domain
)) {
5778 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5779 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5782 fprintf(fp2
, "%s", line
);
5786 /* If new user, just add it */
5787 if (!found
&& pass
!= NULL
) {
5788 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5789 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5796 /* Put the temp file in place of real file */
5797 IGNORE_UNUSED_RESULT(remove(fname
));
5798 IGNORE_UNUSED_RESULT(rename(tmp
, fname
));
5805 is_valid_port(unsigned long port
)
5807 return port
< 0xffff;
5812 mg_inet_pton(int af
, const char *src
, void *dst
, size_t dstlen
)
5814 struct addrinfo hints
, *res
, *ressave
;
5818 memset(&hints
, 0, sizeof(struct addrinfo
));
5819 hints
.ai_family
= af
;
5821 gai_ret
= getaddrinfo(src
, NULL
, &hints
, &res
);
5823 /* gai_strerror could be used to convert gai_ret to a string */
5824 /* POSIX return values: see
5825 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
5827 /* Windows return values: see
5828 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
5836 if (dstlen
>= res
->ai_addrlen
) {
5837 memcpy(dst
, res
->ai_addr
, res
->ai_addrlen
);
5843 freeaddrinfo(ressave
);
5849 connect_socket(struct mg_context
*ctx
/* may be NULL */,
5855 SOCKET
*sock
/* output: socket, must not be NULL */,
5856 union usa
*sa
/* output: socket address, must not be NULL */
5860 *sock
= INVALID_SOCKET
;
5861 memset(sa
, 0, sizeof(*sa
));
5869 NULL
, /* No truncation check for ebuf */
5877 if (port
< 0 || !is_valid_port((unsigned)port
)) {
5879 NULL
, /* No truncation check for ebuf */
5887 if (use_ssl
&& (SSLv23_client_method
== NULL
)) {
5889 NULL
, /* No truncation check for ebuf */
5893 "SSL is not initialized");
5897 if (mg_inet_pton(AF_INET
, host
, &sa
->sin
, sizeof(sa
->sin
))) {
5898 sa
->sin
.sin_port
= htons((uint16_t)port
);
5901 } else if (mg_inet_pton(AF_INET6
, host
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5902 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5904 } else if (host
[0] == '[') {
5905 /* While getaddrinfo on Windows will work with [::1],
5906 * getaddrinfo on Linux only works with ::1 (without []). */
5907 size_t l
= strlen(host
+ 1);
5908 char *h
= l
> 1 ? mg_strdup(host
+ 1) : NULL
;
5911 if (mg_inet_pton(AF_INET6
, h
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5912 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5922 NULL
, /* No truncation check for ebuf */
5931 *sock
= socket(PF_INET
, SOCK_STREAM
, 0);
5934 else if (ip_ver
== 6) {
5935 *sock
= socket(PF_INET6
, SOCK_STREAM
, 0);
5939 if (*sock
== INVALID_SOCKET
) {
5941 NULL
, /* No truncation check for ebuf */
5949 set_close_on_exec(*sock
, fc(ctx
));
5952 && (connect(*sock
, (struct sockaddr
*)&sa
->sin
, sizeof(sa
->sin
))
5954 /* connected with IPv4 */
5960 && (connect(*sock
, (struct sockaddr
*)&sa
->sin6
, sizeof(sa
->sin6
))
5962 /* connected with IPv6 */
5969 NULL
, /* No truncation check for ebuf */
5972 "connect(%s:%d): %s",
5977 *sock
= INVALID_SOCKET
;
5983 mg_url_encode(const char *src
, char *dst
, size_t dst_len
)
5985 static const char *dont_escape
= "._-$,;~()";
5986 static const char *hex
= "0123456789abcdef";
5988 const char *end
= dst
+ dst_len
- 1;
5990 for (; *src
!= '\0' && pos
< end
; src
++, pos
++) {
5991 if (isalnum(*(const unsigned char *)src
)
5992 || strchr(dont_escape
, *(const unsigned char *)src
) != NULL
) {
5994 } else if (pos
+ 2 < end
) {
5996 pos
[1] = hex
[(*(const unsigned char *)src
) >> 4];
5997 pos
[2] = hex
[(*(const unsigned char *)src
) & 0xf];
6005 return (*src
== '\0') ? (int)(pos
- dst
) : -1;
6010 print_dir_entry(struct de
*de
)
6012 char size
[64], mod
[64], href
[PATH_MAX
];
6015 if (de
->file
.is_directory
) {
6016 mg_snprintf(de
->conn
,
6017 NULL
, /* Buffer is big enough */
6023 /* We use (signed) cast below because MSVC 6 compiler cannot
6024 * convert unsigned __int64 to double. Sigh. */
6025 if (de
->file
.size
< 1024) {
6026 mg_snprintf(de
->conn
,
6027 NULL
, /* Buffer is big enough */
6031 (int)de
->file
.size
);
6032 } else if (de
->file
.size
< 0x100000) {
6033 mg_snprintf(de
->conn
,
6034 NULL
, /* Buffer is big enough */
6038 (double)de
->file
.size
/ 1024.0);
6039 } else if (de
->file
.size
< 0x40000000) {
6040 mg_snprintf(de
->conn
,
6041 NULL
, /* Buffer is big enough */
6045 (double)de
->file
.size
/ 1048576);
6047 mg_snprintf(de
->conn
,
6048 NULL
, /* Buffer is big enough */
6052 (double)de
->file
.size
/ 1073741824);
6056 /* Note: mg_snprintf will not cause a buffer overflow above.
6057 * So, string truncation checks are not required here. */
6059 tm
= localtime(&de
->file
.last_modified
);
6061 strftime(mod
, sizeof(mod
), "%d-%b-%Y %H:%M", tm
);
6063 mg_strlcpy(mod
, "01-Jan-1970 00:00", sizeof(mod
));
6064 mod
[sizeof(mod
) - 1] = '\0';
6066 mg_url_encode(de
->file_name
, href
, sizeof(href
));
6067 de
->conn
->num_bytes_sent
+=
6069 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
6070 "<td> %s</td><td> %s</td></tr>\n",
6071 de
->conn
->request_info
.local_uri
,
6073 de
->file
.is_directory
? "/" : "",
6075 de
->file
.is_directory
? "/" : "",
6081 /* This function is called from send_directory() and used for
6082 * sorting directory entries by size, or name, or modification time.
6083 * On windows, __cdecl specification is needed in case if project is built
6084 * with __stdcall convention. qsort always requires __cdels callback. */
6086 compare_dir_entries(const void *p1
, const void *p2
)
6089 const struct de
*a
= (const struct de
*)p1
, *b
= (const struct de
*)p2
;
6090 const char *query_string
= a
->conn
->request_info
.query_string
;
6093 if (query_string
== NULL
) {
6094 query_string
= "na";
6097 if (a
->file
.is_directory
&& !b
->file
.is_directory
) {
6098 return -1; /* Always put directories on top */
6099 } else if (!a
->file
.is_directory
&& b
->file
.is_directory
) {
6100 return 1; /* Always put directories on top */
6101 } else if (*query_string
== 'n') {
6102 cmp_result
= strcmp(a
->file_name
, b
->file_name
);
6103 } else if (*query_string
== 's') {
6104 cmp_result
= a
->file
.size
== b
->file
.size
6106 : a
->file
.size
> b
->file
.size
? 1 : -1;
6107 } else if (*query_string
== 'd') {
6109 (a
->file
.last_modified
== b
->file
.last_modified
)
6111 : ((a
->file
.last_modified
> b
->file
.last_modified
) ? 1
6115 return query_string
[1] == 'd' ? -cmp_result
: cmp_result
;
6122 must_hide_file(struct mg_connection
*conn
, const char *path
)
6124 if (conn
&& conn
->ctx
) {
6125 const char *pw_pattern
= "**" PASSWORDS_FILE_NAME
"$";
6126 const char *pattern
= conn
->ctx
->config
[HIDE_FILES
];
6127 return match_prefix(pw_pattern
, strlen(pw_pattern
), path
) > 0
6129 && match_prefix(pattern
, strlen(pattern
), path
) > 0);
6136 scan_directory(struct mg_connection
*conn
,
6139 void (*cb
)(struct de
*, void *))
6141 char path
[PATH_MAX
];
6147 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6152 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6153 /* Do not show current dir and hidden files */
6154 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")
6155 || must_hide_file(conn
, dp
->d_name
)) {
6160 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6162 /* If we don't memset stat structure to zero, mtime will have
6163 * garbage and strftime() will segfault later on in
6164 * print_dir_entry(). memset is required only if mg_stat()
6165 * fails. For more details, see
6166 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6167 memset(&de
.file
, 0, sizeof(de
.file
));
6170 /* If the path is not complete, skip processing. */
6174 if (!mg_stat(conn
, path
, &de
.file
)) {
6176 "%s: mg_stat(%s) failed: %s",
6181 de
.file_name
= dp
->d_name
;
6184 (void)mg_closedir(dirp
);
6190 #if !defined(NO_FILES)
6192 remove_directory(struct mg_connection
*conn
, const char *dir
)
6194 char path
[PATH_MAX
];
6201 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6206 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6207 /* Do not show current dir (but show hidden files as they will
6208 * also be removed) */
6209 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")) {
6214 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6216 /* If we don't memset stat structure to zero, mtime will have
6217 * garbage and strftime() will segfault later on in
6218 * print_dir_entry(). memset is required only if mg_stat()
6219 * fails. For more details, see
6220 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6221 memset(&de
.file
, 0, sizeof(de
.file
));
6224 /* Do not delete anything shorter */
6229 if (!mg_stat(conn
, path
, &de
.file
)) {
6231 "%s: mg_stat(%s) failed: %s",
6237 if (de
.file
.membuf
== NULL
) {
6238 /* file is not in memory */
6239 if (de
.file
.is_directory
) {
6240 if (remove_directory(conn
, path
) == 0) {
6244 if (mg_remove(conn
, path
) == 0) {
6249 /* file is in memory. It can not be deleted. */
6253 (void)mg_closedir(dirp
);
6255 IGNORE_UNUSED_RESULT(rmdir(dir
));
6263 struct dir_scan_data
{
6265 unsigned int num_entries
;
6266 unsigned int arr_size
;
6270 /* Behaves like realloc(), but frees original pointer on failure */
6272 realloc2(void *ptr
, size_t size
)
6274 void *new_ptr
= mg_realloc(ptr
, size
);
6275 if (new_ptr
== NULL
) {
6283 dir_scan_callback(struct de
*de
, void *data
)
6285 struct dir_scan_data
*dsd
= (struct dir_scan_data
*)data
;
6287 if (dsd
->entries
== NULL
|| dsd
->num_entries
>= dsd
->arr_size
) {
6290 (struct de
*)realloc2(dsd
->entries
,
6291 dsd
->arr_size
* sizeof(dsd
->entries
[0]));
6293 if (dsd
->entries
== NULL
) {
6294 /* TODO(lsm, low): propagate an error to the caller */
6295 dsd
->num_entries
= 0;
6297 dsd
->entries
[dsd
->num_entries
].file_name
= mg_strdup(de
->file_name
);
6298 dsd
->entries
[dsd
->num_entries
].file
= de
->file
;
6299 dsd
->entries
[dsd
->num_entries
].conn
= de
->conn
;
6306 handle_directory_request(struct mg_connection
*conn
, const char *dir
)
6310 struct dir_scan_data data
= {NULL
, 0, 128};
6312 time_t curtime
= time(NULL
);
6314 if (!scan_directory(conn
, dir
, &data
, dir_scan_callback
)) {
6315 send_http_error(conn
,
6317 "Error: Cannot open directory\nopendir(%s): %s",
6323 gmt_time_string(date
, sizeof(date
), &curtime
);
6329 sort_direction
= conn
->request_info
.query_string
!= NULL
6330 && conn
->request_info
.query_string
[1] == 'd'
6334 conn
->must_close
= 1;
6335 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
6336 send_static_cache_header(conn
);
6339 "Connection: close\r\n"
6340 "Content-Type: text/html; charset=utf-8\r\n\r\n",
6343 conn
->num_bytes_sent
+=
6345 "<html><head><title>Index of %s</title>"
6346 "<style>th {text-align: left;}</style></head>"
6347 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
6348 "<tr><th><a href=\"?n%c\">Name</a></th>"
6349 "<th><a href=\"?d%c\">Modified</a></th>"
6350 "<th><a href=\"?s%c\">Size</a></th></tr>"
6351 "<tr><td colspan=\"3\"><hr></td></tr>",
6352 conn
->request_info
.local_uri
,
6353 conn
->request_info
.local_uri
,
6358 /* Print first entry - link to a parent directory */
6359 conn
->num_bytes_sent
+=
6361 "<tr><td><a href=\"%s%s\">%s</a></td>"
6362 "<td> %s</td><td> %s</td></tr>\n",
6363 conn
->request_info
.local_uri
,
6369 /* Sort and print directory entries */
6370 if (data
.entries
!= NULL
) {
6372 (size_t)data
.num_entries
,
6373 sizeof(data
.entries
[0]),
6374 compare_dir_entries
);
6375 for (i
= 0; i
< data
.num_entries
; i
++) {
6376 print_dir_entry(&data
.entries
[i
]);
6377 mg_free(data
.entries
[i
].file_name
);
6379 mg_free(data
.entries
);
6382 conn
->num_bytes_sent
+= mg_printf(conn
, "%s", "</table></body></html>");
6383 conn
->status_code
= 200;
6387 /* Send len bytes from the opened file to the client. */
6389 send_file_data(struct mg_connection
*conn
,
6394 char buf
[MG_BUF_LEN
];
6395 int to_read
, num_read
, num_written
;
6398 if (!filep
|| !conn
) {
6402 /* Sanity check the offset */
6403 size
= filep
->size
> INT64_MAX
? INT64_MAX
: (int64_t)(filep
->size
);
6404 offset
= offset
< 0 ? 0 : offset
> size
? size
: offset
;
6406 if (len
> 0 && filep
->membuf
!= NULL
&& size
> 0) {
6407 /* file stored in memory */
6408 if (len
> size
- offset
) {
6409 len
= size
- offset
;
6411 mg_write(conn
, filep
->membuf
+ offset
, (size_t)len
);
6412 } else if (len
> 0 && filep
->fp
!= NULL
) {
6413 /* file stored on disk */
6414 #if defined(__linux__)
6415 /* sendfile is only available for Linux */
6416 if (conn
->throttle
== 0 && conn
->ssl
== 0) {
6417 off_t sf_offs
= (off_t
)offset
;
6419 int sf_file
= fileno(filep
->fp
);
6423 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
6424 * 64 bit Linux (2^31 minus one memory page of 4k?). */
6426 (size_t)((len
< 0x7FFFF000) ? len
: 0x7FFFF000);
6428 sendfile(conn
->client
.sock
, sf_file
, &sf_offs
, sf_tosend
);
6430 conn
->num_bytes_sent
+= sf_sent
;
6433 } else if (loop_cnt
== 0) {
6434 /* This file can not be sent using sendfile.
6435 * This might be the case for pseudo-files in the
6436 * /sys/ and /proc/ file system.
6437 * Use the regular user mode copy code instead. */
6439 } else if (sf_sent
== 0) {
6440 /* No error, but 0 bytes sent. May be EOF? */
6445 } while ((len
> 0) && (sf_sent
>= 0));
6451 /* sf_sent<0 means error, thus fall back to the classic way */
6452 /* This is always the case, if sf_file is not a "normal" file,
6453 * e.g., for sending data from the output of a CGI process. */
6454 offset
= (int64_t)sf_offs
;
6457 if ((offset
> 0) && (fseeko(filep
->fp
, offset
, SEEK_SET
) != 0)) {
6458 mg_cry(conn
, "%s: fseeko() failed: %s", __func__
, strerror(ERRNO
));
6463 "Error: Unable to access file at requested position.");
6466 /* Calculate how much to read from the file in the buffer */
6467 to_read
= sizeof(buf
);
6468 if ((int64_t)to_read
> len
) {
6472 /* Read from file, exit the loop on error */
6473 if ((num_read
= (int)fread(buf
, 1, (size_t)to_read
, filep
->fp
))
6478 /* Send read bytes to the client, exit the loop on error */
6479 if ((num_written
= mg_write(conn
, buf
, (size_t)num_read
))
6484 /* Both read and were successful, adjust counters */
6485 conn
->num_bytes_sent
+= num_written
;
6494 parse_range_header(const char *header
, int64_t *a
, int64_t *b
)
6496 return sscanf(header
, "bytes=%" INT64_FMT
"-%" INT64_FMT
, a
, b
);
6501 construct_etag(char *buf
, size_t buf_len
, const struct file
*filep
)
6503 if (filep
!= NULL
&& buf
!= NULL
) {
6505 NULL
, /* All calls to construct_etag use 64 byte buffer */
6508 "\"%lx.%" INT64_FMT
"\"",
6509 (unsigned long)filep
->last_modified
,
6516 fclose_on_exec(struct file
*filep
, struct mg_connection
*conn
)
6518 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
6520 (void)conn
; /* Unused. */
6522 if (fcntl(fileno(filep
->fp
), F_SETFD
, FD_CLOEXEC
) != 0) {
6524 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
6534 handle_static_file_request(struct mg_connection
*conn
,
6537 const char *mime_type
)
6539 char date
[64], lm
[64], etag
[64];
6540 char range
[128]; /* large enough, so there will be no overflow */
6541 const char *msg
= "OK", *hdr
;
6542 time_t curtime
= time(NULL
);
6544 struct vec mime_vec
;
6546 char gz_path
[PATH_MAX
];
6547 const char *encoding
= "";
6548 const char *cors1
, *cors2
, *cors3
;
6550 if (conn
== NULL
|| conn
->ctx
== NULL
|| filep
== NULL
) {
6554 if (mime_type
== NULL
) {
6555 get_mime_type(conn
->ctx
, path
, &mime_vec
);
6557 mime_vec
.ptr
= mime_type
;
6558 mime_vec
.len
= strlen(mime_type
);
6560 if (filep
->size
> INT64_MAX
) {
6561 send_http_error(conn
,
6563 "Error: File size is too large to send\n%" INT64_FMT
,
6566 cl
= (int64_t)filep
->size
;
6567 conn
->status_code
= 200;
6570 /* if this file is in fact a pre-gzipped file, rewrite its filename
6571 * it's important to rewrite the filename after resolving
6572 * the mime type from it, to preserve the actual file's type */
6573 if (filep
->gzipped
) {
6574 mg_snprintf(conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", path
);
6577 send_http_error(conn
,
6579 "Error: Path of zipped file too long (%s)",
6585 encoding
= "Content-Encoding: gzip\r\n";
6588 if (!mg_fopen(conn
, path
, "rb", filep
)) {
6589 send_http_error(conn
,
6591 "Error: Cannot open file\nfopen(%s): %s",
6597 fclose_on_exec(filep
, conn
);
6599 /* If Range: header specified, act accordingly */
6601 hdr
= mg_get_header(conn
, "Range");
6602 if (hdr
!= NULL
&& (n
= parse_range_header(hdr
, &r1
, &r2
)) > 0 && r1
>= 0
6604 /* actually, range requests don't play well with a pre-gzipped
6605 * file (since the range is specified in the uncompressed space) */
6606 if (filep
->gzipped
) {
6611 "Error: Range requests in gzipped files are not supported");
6615 conn
->status_code
= 206;
6616 cl
= n
== 2 ? (r2
> cl
? cl
: r2
) - r1
+ 1 : cl
- r1
;
6618 NULL
, /* range buffer is big enough */
6621 "Content-Range: bytes "
6622 "%" INT64_FMT
"-%" INT64_FMT
"/%" INT64_FMT
"\r\n",
6626 msg
= "Partial Content";
6629 hdr
= mg_get_header(conn
, "Origin");
6631 /* Cross-origin resource sharing (CORS), see
6632 * http://www.html5rocks.com/en/tutorials/cors/,
6633 * http://www.html5rocks.com/static/images/cors_server_flowchart.png -
6634 * preflight is not supported for files. */
6635 cors1
= "Access-Control-Allow-Origin: ";
6636 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
6639 cors1
= cors2
= cors3
= "";
6642 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
6643 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
6644 gmt_time_string(date
, sizeof(date
), &curtime
);
6645 gmt_time_string(lm
, sizeof(lm
), &filep
->last_modified
);
6646 construct_etag(etag
, sizeof(etag
), filep
);
6648 (void)mg_printf(conn
,
6649 "HTTP/1.1 %d %s\r\n"
6658 send_static_cache_header(conn
);
6659 (void)mg_printf(conn
,
6660 "Last-Modified: %s\r\n"
6662 "Content-Type: %.*s\r\n"
6663 "Content-Length: %" INT64_FMT
"\r\n"
6664 "Connection: %s\r\n"
6665 "Accept-Ranges: bytes\r\n"
6672 suggest_connection_header(conn
),
6676 if (strcmp(conn
->request_info
.request_method
, "HEAD") != 0) {
6677 send_file_data(conn
, filep
, r1
, cl
);
6684 mg_send_file(struct mg_connection
*conn
, const char *path
)
6686 mg_send_mime_file(conn
, path
, NULL
);
6691 mg_send_mime_file(struct mg_connection
*conn
,
6693 const char *mime_type
)
6695 struct file file
= STRUCT_FILE_INITIALIZER
;
6696 if (mg_stat(conn
, path
, &file
)) {
6697 if (file
.is_directory
) {
6701 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
6703 handle_directory_request(conn
, path
);
6705 send_http_error(conn
,
6708 "Error: Directory listing denied");
6711 handle_static_file_request(conn
, path
, &file
, mime_type
);
6714 send_http_error(conn
, 404, "%s", "Error: File not found");
6719 /* For a given PUT path, create all intermediate subdirectories.
6720 * Return 0 if the path itself is a directory.
6721 * Return 1 if the path leads to a file.
6722 * Return -1 for if the path is too long.
6723 * Return -2 if path can not be created.
6726 put_dir(struct mg_connection
*conn
, const char *path
)
6730 struct file file
= STRUCT_FILE_INITIALIZER
;
6734 for (s
= p
= path
+ 2; (p
= strchr(s
, '/')) != NULL
; s
= ++p
) {
6735 len
= (size_t)(p
- path
);
6736 if (len
>= sizeof(buf
)) {
6741 memcpy(buf
, path
, len
);
6744 /* Try to create intermediate directory */
6745 DEBUG_TRACE("mkdir(%s)", buf
);
6746 if (!mg_stat(conn
, buf
, &file
) && mg_mkdir(conn
, buf
, 0755) != 0) {
6747 /* path does not exixt and can not be created */
6752 /* Is path itself a directory? */
6763 remove_bad_file(const struct mg_connection
*conn
, const char *path
)
6765 int r
= mg_remove(conn
, path
);
6767 mg_cry(conn
, "%s: Cannot remove invalid file %s", __func__
, path
);
6773 mg_store_body(struct mg_connection
*conn
, const char *path
)
6775 char buf
[MG_BUF_LEN
];
6780 if (conn
->consumed_content
!= 0) {
6781 mg_cry(conn
, "%s: Contents already consumed", __func__
);
6785 ret
= put_dir(conn
, path
);
6787 /* -1 for path too long,
6788 * -2 for path can not be created. */
6792 /* Return 0 means, path itself is a directory. */
6796 if (mg_fopen(conn
, path
, "w", &fi
) == 0) {
6800 ret
= mg_read(conn
, buf
, sizeof(buf
));
6802 n
= (int)fwrite(buf
, 1, (size_t)ret
, fi
.fp
);
6805 remove_bad_file(conn
, path
);
6808 ret
= mg_read(conn
, buf
, sizeof(buf
));
6811 /* TODO: mg_fclose should return an error,
6812 * and every caller should check and handle it. */
6813 if (fclose(fi
.fp
) != 0) {
6814 remove_bad_file(conn
, path
);
6822 /* Parse HTTP headers from the given buffer, advance buffer to the point
6823 * where parsing stopped. */
6825 parse_http_headers(char **buf
, struct mg_request_info
*ri
)
6833 ri
->num_headers
= 0;
6835 for (i
= 0; i
< (int)ARRAY_SIZE(ri
->http_headers
); i
++) {
6837 while ((*dp
!= ':') && (*dp
!= '\r') && (*dp
!= 0)) {
6841 /* neither : nor \r\n. This is not a valid field. */
6845 if (dp
[1] == '\n') {
6847 ri
->http_headers
[i
].name
= *buf
;
6848 ri
->http_headers
[i
].value
= 0;
6851 /* stray \r. This is not valid. */
6857 ri
->http_headers
[i
].name
= *buf
;
6860 } while (*dp
== ' ');
6862 ri
->http_headers
[i
].value
= dp
;
6863 *buf
= strstr(dp
, "\r\n");
6866 ri
->num_headers
= i
+ 1;
6876 if (*buf
[0] == '\r') {
6877 /* This is the end of the header */
6885 is_valid_http_method(const char *method
)
6887 return !strcmp(method
, "GET") /* HTTP (RFC 2616) */
6888 || !strcmp(method
, "POST") /* HTTP (RFC 2616) */
6889 || !strcmp(method
, "HEAD") /* HTTP (RFC 2616) */
6890 || !strcmp(method
, "PUT") /* HTTP (RFC 2616) */
6891 || !strcmp(method
, "DELETE") /* HTTP (RFC 2616) */
6892 || !strcmp(method
, "OPTIONS") /* HTTP (RFC 2616) */
6893 /* TRACE method (RFC 2616) is not supported for security reasons */
6894 || !strcmp(method
, "CONNECT") /* HTTP (RFC 2616) */
6896 || !strcmp(method
, "PROPFIND") /* WEBDAV (RFC 2518) */
6897 || !strcmp(method
, "MKCOL") /* WEBDAV (RFC 2518) */
6899 /* Unsupported WEBDAV Methods: */
6900 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
6901 /* + 11 methods from RFC 3253 */
6902 /* ORDERPATCH (RFC 3648) */
6903 /* ACL (RFC 3744) */
6904 /* SEARCH (RFC 5323) */
6905 /* + MicroSoft extensions
6906 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
6908 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
6909 || !strcmp(method
, "PATCH"); /* PATCH method (RFC 5789) */
6913 /* Parse HTTP request, fill in mg_request_info structure.
6914 * This function modifies the buffer by NUL-terminating
6915 * HTTP request components, header names and header values. */
6917 parse_http_message(char *buf
, int len
, struct mg_request_info
*ri
)
6919 int is_request
, request_length
;
6925 request_length
= get_request_len(buf
, len
);
6927 if (request_length
> 0) {
6928 /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
6930 ri
->remote_user
= ri
->request_method
= ri
->request_uri
=
6931 ri
->http_version
= NULL
;
6932 ri
->num_headers
= 0;
6934 buf
[request_length
- 1] = '\0';
6936 /* RFC says that all initial whitespaces should be ingored */
6937 while (*buf
!= '\0' && isspace(*(unsigned char *)buf
)) {
6940 ri
->request_method
= skip(&buf
, " ");
6941 ri
->request_uri
= skip(&buf
, " ");
6942 ri
->http_version
= skip(&buf
, "\r\n");
6944 /* HTTP message could be either HTTP request or HTTP response, e.g.
6945 * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
6946 is_request
= is_valid_http_method(ri
->request_method
);
6947 if ((is_request
&& memcmp(ri
->http_version
, "HTTP/", 5) != 0)
6948 || (!is_request
&& memcmp(ri
->request_method
, "HTTP/", 5) != 0)) {
6949 request_length
= -1;
6952 ri
->http_version
+= 5;
6954 parse_http_headers(&buf
, ri
);
6957 return request_length
;
6961 /* Keep reading the input (either opened file descriptor fd, or socket sock,
6962 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
6963 * buffer (which marks the end of HTTP request). Buffer buf may already
6964 * have some data. The length of the data is stored in nread.
6965 * Upon every read operation, increase nread by the number of bytes read. */
6967 read_request(FILE *fp
,
6968 struct mg_connection
*conn
,
6973 int request_len
, n
= 0;
6974 struct timespec last_action_time
;
6975 double request_timeout
;
6981 memset(&last_action_time
, 0, sizeof(last_action_time
));
6983 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
6984 /* value of request_timeout is in seconds, config in milliseconds */
6985 request_timeout
= atof(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
6987 request_timeout
= -1.0;
6990 request_len
= get_request_len(buf
, *nread
);
6992 /* first time reading from this connection */
6993 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
6996 (conn
->ctx
->stop_flag
== 0) && (*nread
< bufsiz
) && (request_len
== 0)
6997 && ((mg_difftimespec(&last_action_time
, &(conn
->req_time
))
6998 <= request_timeout
) || (request_timeout
< 0))
6999 && ((n
= pull(fp
, conn
, buf
+ *nread
, bufsiz
- *nread
, request_timeout
))
7002 /* assert(*nread <= bufsiz); */
7003 if (*nread
> bufsiz
) {
7006 request_len
= get_request_len(buf
, *nread
);
7007 if (request_timeout
> 0.0) {
7008 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
7012 return (request_len
<= 0 && n
<= 0) ? -1 : request_len
;
7015 #if !defined(NO_FILES)
7016 /* For given directory path, substitute it to valid index file.
7017 * Return 1 if index file has been found, 0 if not found.
7018 * If the file is found, it's stats is returned in stp. */
7020 substitute_index_file(struct mg_connection
*conn
,
7025 if (conn
&& conn
->ctx
) {
7026 const char *list
= conn
->ctx
->config
[INDEX_FILES
];
7027 struct file file
= STRUCT_FILE_INITIALIZER
;
7028 struct vec filename_vec
;
7029 size_t n
= strlen(path
);
7032 /* The 'path' given to us points to the directory. Remove all trailing
7033 * directory separator characters from the end of the path, and
7034 * then append single directory separator character. */
7035 while (n
> 0 && path
[n
- 1] == '/') {
7040 /* Traverse index files list. For each entry, append it to the given
7041 * path and see if the file exists. If it exists, break the loop */
7042 while ((list
= next_option(list
, &filename_vec
, NULL
)) != NULL
) {
7043 /* Ignore too long entries that may overflow path buffer */
7044 if (filename_vec
.len
> path_len
- (n
+ 2)) {
7048 /* Prepare full path to the index file */
7049 mg_strlcpy(path
+ n
+ 1, filename_vec
.ptr
, filename_vec
.len
+ 1);
7051 /* Does it exist? */
7052 if (mg_stat(conn
, path
, &file
)) {
7053 /* Yes it does, break the loop */
7060 /* If no index file exists, restore directory path */
7072 #if !defined(NO_CACHING)
7073 /* Return True if we should reply 304 Not Modified. */
7075 is_not_modified(const struct mg_connection
*conn
, const struct file
*filep
)
7078 const char *ims
= mg_get_header(conn
, "If-Modified-Since");
7079 const char *inm
= mg_get_header(conn
, "If-None-Match");
7080 construct_etag(etag
, sizeof(etag
), filep
);
7084 return (inm
!= NULL
&& !mg_strcasecmp(etag
, inm
))
7085 || (ims
!= NULL
&& (filep
->last_modified
<= parse_date_string(ims
)));
7087 #endif /* !NO_CACHING */
7090 #if !defined(NO_CGI) || !defined(NO_FILES)
7092 forward_body_data(struct mg_connection
*conn
, FILE *fp
, SOCKET sock
, SSL
*ssl
)
7094 const char *expect
, *body
;
7095 char buf
[MG_BUF_LEN
];
7096 int to_read
, nread
, success
= 0;
7097 int64_t buffered_len
;
7098 double timeout
= -1.0;
7103 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
7104 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
7107 expect
= mg_get_header(conn
, "Expect");
7108 /* assert(fp != NULL); */
7110 send_http_error(conn
, 500, "%s", "Error: NULL File");
7114 if (conn
->content_len
== -1 && !conn
->is_chunked
) {
7115 /* Content length is not specified by the client. */
7116 send_http_error(conn
,
7119 "Error: Client did not specify content length");
7120 } else if ((expect
!= NULL
)
7121 && (mg_strcasecmp(expect
, "100-continue") != 0)) {
7122 /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
7123 send_http_error(conn
,
7125 "Error: Can not fulfill expectation %s",
7128 if (expect
!= NULL
) {
7129 (void)mg_printf(conn
, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
7130 conn
->status_code
= 100;
7132 conn
->status_code
= 200;
7135 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
7136 - conn
->consumed_content
;
7138 /* assert(buffered_len >= 0); */
7139 /* assert(conn->consumed_content == 0); */
7141 if ((buffered_len
< 0) || (conn
->consumed_content
!= 0)) {
7142 send_http_error(conn
, 500, "%s", "Error: Size mismatch");
7146 if (buffered_len
> 0) {
7147 if ((int64_t)buffered_len
> conn
->content_len
) {
7148 buffered_len
= (int)conn
->content_len
;
7150 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
7151 push_all(conn
->ctx
, fp
, sock
, ssl
, body
, (int64_t)buffered_len
);
7152 conn
->consumed_content
+= buffered_len
;
7156 while (conn
->consumed_content
< conn
->content_len
) {
7157 to_read
= sizeof(buf
);
7158 if ((int64_t)to_read
> conn
->content_len
- conn
->consumed_content
) {
7159 to_read
= (int)(conn
->content_len
- conn
->consumed_content
);
7161 nread
= pull(NULL
, conn
, buf
, to_read
, timeout
);
7163 || push_all(conn
->ctx
, fp
, sock
, ssl
, buf
, nread
) != nread
) {
7166 conn
->consumed_content
+= nread
;
7169 if (conn
->consumed_content
== conn
->content_len
) {
7170 success
= (nread
>= 0);
7173 /* Each error code path in this function must send an error */
7175 /* NOTE: Maybe some data has already been sent. */
7176 /* TODO (low): If some data has been sent, a correct error
7177 * reply can no longer be sent, so just close the connection */
7178 send_http_error(conn
, 500, "%s", "");
7186 #if !defined(NO_CGI)
7187 /* This structure helps to create an environment for the spawned CGI program.
7188 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
7189 * last element must be NULL.
7190 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
7191 * strings must reside in a contiguous buffer. The end of the buffer is
7192 * marked by two '\0' characters.
7193 * We satisfy both worlds: we create an envp array (which is vars), all
7194 * entries are actually pointers inside buf. */
7195 struct cgi_environment
{
7196 struct mg_connection
*conn
;
7198 char *buf
; /* Environment buffer */
7199 size_t buflen
; /* Space available in buf */
7200 size_t bufused
; /* Space taken in buf */
7202 char **var
; /* char **envp */
7203 size_t varlen
; /* Number of variables available in var */
7204 size_t varused
; /* Number of variables stored in var */
7208 static void addenv(struct cgi_environment
*env
,
7209 PRINTF_FORMAT_STRING(const char *fmt
),
7210 ...) PRINTF_ARGS(2, 3);
7212 /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
7213 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
7215 addenv(struct cgi_environment
*env
, const char *fmt
, ...)
7222 /* Calculate how much space is left in the buffer */
7223 space
= (env
->buflen
- env
->bufused
);
7225 /* Calculate an estimate for the required space */
7226 n
= strlen(fmt
) + 2 + 128;
7230 /* Allocate new buffer */
7231 n
= env
->buflen
+ CGI_ENVIRONMENT_SIZE
;
7232 added
= (char *)mg_realloc(env
->buf
, n
);
7236 "%s: Cannot allocate memory for CGI variable [%s]",
7243 space
= (env
->buflen
- env
->bufused
);
7246 /* Make a pointer to the free space int the buffer */
7247 added
= env
->buf
+ env
->bufused
;
7249 /* Copy VARIABLE=VALUE\0 string into the free space */
7251 mg_vsnprintf(env
->conn
, &truncated
, added
, (size_t)space
, fmt
, ap
);
7254 /* Do not add truncated strings to the environment */
7256 /* Reallocate the buffer */
7260 } while (truncated
);
7262 /* Calculate number of bytes added to the environment */
7263 n
= strlen(added
) + 1;
7266 /* Now update the variable index */
7267 space
= (env
->varlen
- env
->varused
);
7270 "%s: Cannot register CGI variable [%s]",
7276 /* Append a pointer to the added string into the envp array */
7277 env
->var
[env
->varused
] = added
;
7283 prepare_cgi_environment(struct mg_connection
*conn
,
7285 struct cgi_environment
*env
)
7289 char *p
, src_addr
[IP_ADDR_STR_LEN
], http_var_name
[128];
7292 if (conn
== NULL
|| prog
== NULL
|| env
== NULL
) {
7297 env
->buflen
= CGI_ENVIRONMENT_SIZE
;
7299 env
->buf
= (char *)mg_malloc(env
->buflen
);
7300 env
->varlen
= MAX_CGI_ENVIR_VARS
;
7302 env
->var
= (char **)mg_malloc(env
->buflen
* sizeof(char *));
7304 addenv(env
, "SERVER_NAME=%s", conn
->ctx
->config
[AUTHENTICATION_DOMAIN
]);
7305 addenv(env
, "SERVER_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7306 addenv(env
, "DOCUMENT_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7307 addenv(env
, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
7309 /* Prepare the environment block */
7310 addenv(env
, "%s", "GATEWAY_INTERFACE=CGI/1.1");
7311 addenv(env
, "%s", "SERVER_PROTOCOL=HTTP/1.1");
7312 addenv(env
, "%s", "REDIRECT_STATUS=200"); /* For PHP */
7314 #if defined(USE_IPV6)
7315 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
7316 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin6
.sin6_port
));
7320 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin
.sin_port
));
7323 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
7324 addenv(env
, "REMOTE_ADDR=%s", src_addr
);
7326 addenv(env
, "REQUEST_METHOD=%s", conn
->request_info
.request_method
);
7327 addenv(env
, "REMOTE_PORT=%d", conn
->request_info
.remote_port
);
7329 addenv(env
, "REQUEST_URI=%s", conn
->request_info
.request_uri
);
7330 addenv(env
, "LOCAL_URI=%s", conn
->request_info
.local_uri
);
7335 (int)strlen(conn
->request_info
.local_uri
)
7336 - ((conn
->path_info
== NULL
) ? 0 : (int)strlen(conn
->path_info
)),
7337 conn
->request_info
.local_uri
);
7339 addenv(env
, "SCRIPT_FILENAME=%s", prog
);
7340 if (conn
->path_info
== NULL
) {
7341 addenv(env
, "PATH_TRANSLATED=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7344 "PATH_TRANSLATED=%s%s",
7345 conn
->ctx
->config
[DOCUMENT_ROOT
],
7349 addenv(env
, "HTTPS=%s", conn
->ssl
== NULL
? "off" : "on");
7351 if ((s
= mg_get_header(conn
, "Content-Type")) != NULL
) {
7352 addenv(env
, "CONTENT_TYPE=%s", s
);
7354 if (conn
->request_info
.query_string
!= NULL
) {
7355 addenv(env
, "QUERY_STRING=%s", conn
->request_info
.query_string
);
7357 if ((s
= mg_get_header(conn
, "Content-Length")) != NULL
) {
7358 addenv(env
, "CONTENT_LENGTH=%s", s
);
7360 if ((s
= getenv("PATH")) != NULL
) {
7361 addenv(env
, "PATH=%s", s
);
7363 if (conn
->path_info
!= NULL
) {
7364 addenv(env
, "PATH_INFO=%s", conn
->path_info
);
7367 if (conn
->status_code
> 0) {
7368 /* CGI error handler should show the status code */
7369 addenv(env
, "STATUS=%d", conn
->status_code
);
7373 if ((s
= getenv("COMSPEC")) != NULL
) {
7374 addenv(env
, "COMSPEC=%s", s
);
7376 if ((s
= getenv("SYSTEMROOT")) != NULL
) {
7377 addenv(env
, "SYSTEMROOT=%s", s
);
7379 if ((s
= getenv("SystemDrive")) != NULL
) {
7380 addenv(env
, "SystemDrive=%s", s
);
7382 if ((s
= getenv("ProgramFiles")) != NULL
) {
7383 addenv(env
, "ProgramFiles=%s", s
);
7385 if ((s
= getenv("ProgramFiles(x86)")) != NULL
) {
7386 addenv(env
, "ProgramFiles(x86)=%s", s
);
7389 if ((s
= getenv("LD_LIBRARY_PATH")) != NULL
) {
7390 addenv(env
, "LD_LIBRARY_PATH=%s", s
);
7394 if ((s
= getenv("PERLLIB")) != NULL
) {
7395 addenv(env
, "PERLLIB=%s", s
);
7398 if (conn
->request_info
.remote_user
!= NULL
) {
7399 addenv(env
, "REMOTE_USER=%s", conn
->request_info
.remote_user
);
7400 addenv(env
, "%s", "AUTH_TYPE=Digest");
7403 /* Add all headers as HTTP_* variables */
7404 for (i
= 0; i
< conn
->request_info
.num_headers
; i
++) {
7406 (void)mg_snprintf(conn
,
7409 sizeof(http_var_name
),
7411 conn
->request_info
.http_headers
[i
].name
);
7415 "%s: HTTP header variable too long [%s]",
7417 conn
->request_info
.http_headers
[i
].name
);
7421 /* Convert variable name into uppercase, and change - to _ */
7422 for (p
= http_var_name
; *p
!= '\0'; p
++) {
7426 *p
= (char)toupper(*(unsigned char *)p
);
7432 conn
->request_info
.http_headers
[i
].value
);
7435 /* Add user-specified variables */
7436 s
= conn
->ctx
->config
[CGI_ENVIRONMENT
];
7437 while ((s
= next_option(s
, &var_vec
, NULL
)) != NULL
) {
7438 addenv(env
, "%.*s", (int)var_vec
.len
, var_vec
.ptr
);
7441 env
->var
[env
->varused
] = NULL
;
7442 env
->buf
[env
->bufused
] = '\0';
7447 handle_cgi_request(struct mg_connection
*conn
, const char *prog
)
7451 int headers_len
, data_len
, i
, truncated
;
7452 int fdin
[2] = {-1, -1}, fdout
[2] = {-1, -1}, fderr
[2] = {-1, -1};
7453 const char *status
, *status_text
, *connection_state
;
7454 char *pbuf
, dir
[PATH_MAX
], *p
;
7455 struct mg_request_info ri
;
7456 struct cgi_environment blk
;
7457 FILE *in
= NULL
, *out
= NULL
, *err
= NULL
;
7458 struct file fout
= STRUCT_FILE_INITIALIZER
;
7459 pid_t pid
= (pid_t
)-1;
7467 prepare_cgi_environment(conn
, prog
, &blk
);
7469 /* CGI must be executed in its own directory. 'dir' must point to the
7470 * directory containing executable program, 'p' must point to the
7471 * executable program name relative to 'dir'. */
7472 (void)mg_snprintf(conn
, &truncated
, dir
, sizeof(dir
), "%s", prog
);
7475 mg_cry(conn
, "Error: CGI program \"%s\": Path too long", prog
);
7476 send_http_error(conn
, 500, "Error: %s", "CGI path too long");
7480 if ((p
= strrchr(dir
, '/')) != NULL
) {
7483 dir
[0] = '.', dir
[1] = '\0';
7487 if (pipe(fdin
) != 0 || pipe(fdout
) != 0 || pipe(fderr
) != 0) {
7488 status
= strerror(ERRNO
);
7490 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
7493 send_http_error(conn
, 500, "Error: Cannot create CGI pipe: %s", status
);
7497 pid
= spawn_process(conn
, p
, blk
.buf
, blk
.var
, fdin
, fdout
, fderr
, dir
);
7499 if (pid
== (pid_t
)-1) {
7500 status
= strerror(ERRNO
);
7502 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
7505 send_http_error(conn
,
7507 "Error: Cannot spawn CGI process [%s]: %s",
7513 /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
7514 set_close_on_exec((SOCKET
)fdin
[0], conn
); /* stdin read */
7515 set_close_on_exec((SOCKET
)fdout
[1], conn
); /* stdout write */
7516 set_close_on_exec((SOCKET
)fderr
[1], conn
); /* stderr write */
7517 set_close_on_exec((SOCKET
)fdin
[1], conn
); /* stdin write */
7518 set_close_on_exec((SOCKET
)fdout
[0], conn
); /* stdout read */
7519 set_close_on_exec((SOCKET
)fderr
[0], conn
); /* stderr read */
7521 /* Parent closes only one side of the pipes.
7522 * If we don't mark them as closed, close() attempt before
7523 * return from this function throws an exception on Windows.
7524 * Windows does not like when closed descriptor is closed again. */
7525 (void)close(fdin
[0]);
7526 (void)close(fdout
[1]);
7527 (void)close(fderr
[1]);
7528 fdin
[0] = fdout
[1] = fderr
[1] = -1;
7530 if ((in
= fdopen(fdin
[1], "wb")) == NULL
) {
7531 status
= strerror(ERRNO
);
7533 "Error: CGI program \"%s\": Can not open stdin: %s",
7536 send_http_error(conn
,
7538 "Error: CGI can not open fdin\nfopen: %s",
7543 if ((out
= fdopen(fdout
[0], "rb")) == NULL
) {
7544 status
= strerror(ERRNO
);
7546 "Error: CGI program \"%s\": Can not open stdout: %s",
7549 send_http_error(conn
,
7551 "Error: CGI can not open fdout\nfopen: %s",
7556 if ((err
= fdopen(fderr
[0], "rb")) == NULL
) {
7557 status
= strerror(ERRNO
);
7559 "Error: CGI program \"%s\": Can not open stderr: %s",
7562 send_http_error(conn
,
7564 "Error: CGI can not open fdout\nfopen: %s",
7574 if ((conn
->request_info
.content_length
> 0) || conn
->is_chunked
) {
7575 /* This is a POST/PUT request, or another request with body data. */
7576 if (!forward_body_data(conn
, in
, INVALID_SOCKET
, NULL
)) {
7577 /* Error sending the body data */
7579 "Error: CGI program \"%s\": Forward body data failed",
7585 /* Close so child gets an EOF. */
7590 /* Now read CGI reply into a buffer. We need to set correct
7591 * status code, thus we need to see all HTTP headers first.
7592 * Do not send anything back to client, until we buffer in all
7595 buf
= (char *)mg_malloc(buflen
);
7597 send_http_error(conn
,
7599 "Error: Not enough memory for CGI buffer (%u bytes)",
7600 (unsigned int)buflen
);
7602 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
7605 (unsigned int)buflen
);
7608 headers_len
= read_request(out
, conn
, buf
, (int)buflen
, &data_len
);
7609 if (headers_len
<= 0) {
7611 /* Could not parse the CGI response. Check if some error message on
7613 i
= pull_all(err
, conn
, buf
, (int)buflen
);
7616 "Error: CGI program \"%s\" sent error "
7621 send_http_error(conn
,
7623 "Error: CGI program \"%s\" sent error "
7630 "Error: CGI program sent malformed or too big "
7631 "(>%u bytes) HTTP headers: [%.*s]",
7636 send_http_error(conn
,
7638 "Error: CGI program sent malformed or too big "
7639 "(>%u bytes) HTTP headers: [%.*s]",
7648 buf
[headers_len
- 1] = '\0';
7649 parse_http_headers(&pbuf
, &ri
);
7651 /* Make up and send the status line */
7653 if ((status
= get_header(&ri
, "Status")) != NULL
) {
7654 conn
->status_code
= atoi(status
);
7655 status_text
= status
;
7656 while (isdigit(*(const unsigned char *)status_text
)
7657 || *status_text
== ' ') {
7660 } else if (get_header(&ri
, "Location") != NULL
) {
7661 conn
->status_code
= 302;
7663 conn
->status_code
= 200;
7665 connection_state
= get_header(&ri
, "Connection");
7666 if (!header_has_option(connection_state
, "keep-alive")) {
7667 conn
->must_close
= 1;
7669 (void)mg_printf(conn
, "HTTP/1.1 %d %s\r\n", conn
->status_code
, status_text
);
7672 for (i
= 0; i
< ri
.num_headers
; i
++) {
7675 ri
.http_headers
[i
].name
,
7676 ri
.http_headers
[i
].value
);
7678 mg_write(conn
, "\r\n", 2);
7680 /* Send chunk of data that may have been read after the headers */
7681 conn
->num_bytes_sent
+=
7682 mg_write(conn
, buf
+ headers_len
, (size_t)(data_len
- headers_len
));
7684 /* Read the rest of CGI output and send to the client */
7685 send_file_data(conn
, &fout
, 0, INT64_MAX
);
7691 if (pid
!= (pid_t
)-1) {
7693 #if !defined(_WIN32)
7696 while (waitpid(pid
, &st
, 0) != -1)
7697 ; /* clean zombies */
7701 if (fdin
[0] != -1) {
7704 if (fdout
[1] != -1) {
7710 } else if (fdin
[1] != -1) {
7716 } else if (fdout
[0] != -1) {
7722 } else if (fderr
[0] != -1) {
7730 #endif /* !NO_CGI */
7733 #if !defined(NO_FILES)
7735 mkcol(struct mg_connection
*conn
, const char *path
)
7740 time_t curtime
= time(NULL
);
7746 /* TODO (mid): Check the send_http_error situations in this function */
7748 memset(&de
.file
, 0, sizeof(de
.file
));
7749 if (!mg_stat(conn
, path
, &de
.file
)) {
7751 "%s: mg_stat(%s) failed: %s",
7757 if (de
.file
.last_modified
) {
7758 /* TODO (high): This check does not seem to make any sense ! */
7760 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7764 body_len
= conn
->data_len
- conn
->request_len
;
7767 conn
, 415, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7771 rc
= mg_mkdir(conn
, path
, 0755);
7774 conn
->status_code
= 201;
7775 gmt_time_string(date
, sizeof(date
), &curtime
);
7777 "HTTP/1.1 %d Created\r\n"
7781 send_static_cache_header(conn
);
7783 "Content-Length: 0\r\n"
7784 "Connection: %s\r\n\r\n",
7785 suggest_connection_header(conn
));
7786 } else if (rc
== -1) {
7787 if (errno
== EEXIST
) {
7789 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7790 } else if (errno
== EACCES
) {
7792 conn
, 403, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7793 } else if (errno
== ENOENT
) {
7795 conn
, 409, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7797 send_http_error(conn
, 500, "fopen(%s): %s", path
, strerror(ERRNO
));
7804 put_file(struct mg_connection
*conn
, const char *path
)
7806 struct file file
= STRUCT_FILE_INITIALIZER
;
7811 time_t curtime
= time(NULL
);
7817 if (mg_stat(conn
, path
, &file
)) {
7818 /* File already exists */
7819 conn
->status_code
= 200;
7821 if (file
.is_directory
) {
7822 /* This is an already existing directory,
7823 * so there is nothing to do for the server. */
7827 /* File exists and is not a directory. */
7828 /* Can it be replaced? */
7830 if (file
.membuf
!= NULL
) {
7831 /* This is an "in-memory" file, that can not be replaced */
7835 "Error: Put not possible\nReplacing %s is not supported",
7840 /* Check if the server may write this file */
7841 if (access(path
, W_OK
) == 0) {
7842 /* Access granted */
7843 conn
->status_code
= 200;
7849 "Error: Put not possible\nReplacing %s is not allowed",
7855 /* File should be created */
7856 conn
->status_code
= 201;
7857 rc
= put_dir(conn
, path
);
7861 /* put_dir returns 0 if path is a directory */
7862 gmt_time_string(date
, sizeof(date
), &curtime
);
7864 "HTTP/1.1 %d %s\r\n",
7866 mg_get_response_code_text(NULL
, conn
->status_code
));
7867 send_no_cache_header(conn
);
7870 "Content-Length: 0\r\n"
7871 "Connection: %s\r\n\r\n",
7873 suggest_connection_header(conn
));
7875 /* Request to create a directory has been fulfilled successfully.
7876 * No need to put a file. */
7881 /* put_dir returns -1 if the path is too long */
7882 send_http_error(conn
,
7884 "Error: Path too long\nput_dir(%s): %s",
7891 /* put_dir returns -2 if the directory can not be created */
7892 send_http_error(conn
,
7894 "Error: Can not create directory\nput_dir(%s): %s",
7900 /* A file should be created or overwritten. */
7901 if (!mg_fopen(conn
, path
, "wb+", &file
) || file
.fp
== NULL
) {
7903 send_http_error(conn
,
7905 "Error: Can not create file\nfopen(%s): %s",
7911 fclose_on_exec(&file
, conn
);
7912 range
= mg_get_header(conn
, "Content-Range");
7914 if (range
!= NULL
&& parse_range_header(range
, &r1
, &r2
) > 0) {
7915 conn
->status_code
= 206; /* Partial content */
7916 fseeko(file
.fp
, r1
, SEEK_SET
);
7919 if (!forward_body_data(conn
, file
.fp
, INVALID_SOCKET
, NULL
)) {
7920 /* forward_body_data failed.
7921 * The error code has already been sent to the client,
7922 * and conn->status_code is already set. */
7927 gmt_time_string(date
, sizeof(date
), &curtime
);
7929 "HTTP/1.1 %d %s\r\n",
7931 mg_get_response_code_text(NULL
, conn
->status_code
));
7932 send_no_cache_header(conn
);
7935 "Content-Length: 0\r\n"
7936 "Connection: %s\r\n\r\n",
7938 suggest_connection_header(conn
));
7945 delete_file(struct mg_connection
*conn
, const char *path
)
7948 memset(&de
.file
, 0, sizeof(de
.file
));
7949 if (!mg_stat(conn
, path
, &de
.file
)) {
7950 /* mg_stat returns 0 if the file does not exist */
7951 send_http_error(conn
,
7953 "Error: Cannot delete file\nFile %s not found",
7958 if (de
.file
.membuf
!= NULL
) {
7959 /* the file is cached in memory */
7963 "Error: Delete not possible\nDeleting %s is not supported",
7968 if (de
.file
.is_directory
) {
7969 if (remove_directory(conn
, path
)) {
7970 /* Delete is successful: Return 204 without content. */
7971 send_http_error(conn
, 204, "%s", "");
7973 /* Delete is not successful: Return 500 (Server error). */
7974 send_http_error(conn
, 500, "Error: Could not delete %s", path
);
7979 /* This is an existing file (not a directory).
7980 * Check if write permission is granted. */
7981 if (access(path
, W_OK
) != 0) {
7982 /* File is read only */
7986 "Error: Delete not possible\nDeleting %s is not allowed",
7991 /* Try to delete it. */
7992 if (mg_remove(conn
, path
) == 0) {
7993 /* Delete was successful: Return 204 without content. */
7994 send_http_error(conn
, 204, "%s", "");
7996 /* Delete not successful (file locked). */
7997 send_http_error(conn
,
7999 "Error: Cannot delete file\nremove(%s): %s",
8004 #endif /* !NO_FILES */
8008 send_ssi_file(struct mg_connection
*, const char *, struct file
*, int);
8012 do_ssi_include(struct mg_connection
*conn
,
8017 char file_name
[MG_BUF_LEN
], path
[512], *p
;
8018 struct file file
= STRUCT_FILE_INITIALIZER
;
8026 /* sscanf() is safe here, since send_ssi_file() also uses buffer
8027 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
8028 * always < MG_BUF_LEN. */
8029 if (sscanf(tag
, " virtual=\"%511[^\"]\"", file_name
) == 1) {
8030 /* File name is relative to the webserver root */
8032 (void)mg_snprintf(conn
,
8037 conn
->ctx
->config
[DOCUMENT_ROOT
],
8040 } else if (sscanf(tag
, " abspath=\"%511[^\"]\"", file_name
) == 1) {
8041 /* File name is relative to the webserver working directory
8042 * or it is absolute system path */
8045 mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", file_name
);
8047 } else if (sscanf(tag
, " file=\"%511[^\"]\"", file_name
) == 1
8048 || sscanf(tag
, " \"%511[^\"]\"", file_name
) == 1) {
8049 /* File name is relative to the currect document */
8051 (void)mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", ssi
);
8054 if ((p
= strrchr(path
, '/')) != NULL
) {
8058 (void)mg_snprintf(conn
,
8067 mg_cry(conn
, "Bad SSI #include: [%s]", tag
);
8072 mg_cry(conn
, "SSI #include path length overflow: [%s]", tag
);
8076 if (!mg_fopen(conn
, path
, "rb", &file
)) {
8078 "Cannot open SSI #include: [%s]: fopen(%s): %s",
8083 fclose_on_exec(&file
, conn
);
8084 if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
8085 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
8087 send_ssi_file(conn
, path
, &file
, include_level
+ 1);
8089 send_file_data(conn
, &file
, 0, INT64_MAX
);
8096 #if !defined(NO_POPEN)
8098 do_ssi_exec(struct mg_connection
*conn
, char *tag
)
8100 char cmd
[1024] = "";
8101 struct file file
= STRUCT_FILE_INITIALIZER
;
8103 if (sscanf(tag
, " \"%1023[^\"]\"", cmd
) != 1) {
8104 mg_cry(conn
, "Bad SSI #exec: [%s]", tag
);
8107 if ((file
.fp
= popen(cmd
, "r")) == NULL
) {
8108 mg_cry(conn
, "Cannot SSI #exec: [%s]: %s", cmd
, strerror(ERRNO
));
8110 send_file_data(conn
, &file
, 0, INT64_MAX
);
8115 #endif /* !NO_POPEN */
8119 mg_fgetc(struct file
*filep
, int offset
)
8121 if (filep
== NULL
) {
8124 if (filep
->membuf
!= NULL
&& offset
>= 0
8125 && ((unsigned int)(offset
)) < filep
->size
) {
8126 return ((const unsigned char *)filep
->membuf
)[offset
];
8127 } else if (filep
->fp
!= NULL
) {
8128 return fgetc(filep
->fp
);
8136 send_ssi_file(struct mg_connection
*conn
,
8141 char buf
[MG_BUF_LEN
];
8142 int ch
, offset
, len
, in_ssi_tag
;
8144 if (include_level
> 10) {
8145 mg_cry(conn
, "SSI #include level is too deep (%s)", path
);
8149 in_ssi_tag
= len
= offset
= 0;
8150 while ((ch
= mg_fgetc(filep
, offset
)) != EOF
) {
8151 if (in_ssi_tag
&& ch
== '>') {
8153 buf
[len
++] = (char)ch
;
8155 /* assert(len <= (int) sizeof(buf)); */
8156 if (len
> (int)sizeof(buf
)) {
8159 if (len
< 6 || memcmp(buf
, "<!--#", 5) != 0) {
8160 /* Not an SSI tag, pass it */
8161 (void)mg_write(conn
, buf
, (size_t)len
);
8163 if (!memcmp(buf
+ 5, "include", 7)) {
8164 do_ssi_include(conn
, path
, buf
+ 12, include_level
);
8165 #if !defined(NO_POPEN)
8166 } else if (!memcmp(buf
+ 5, "exec", 4)) {
8167 do_ssi_exec(conn
, buf
+ 9);
8168 #endif /* !NO_POPEN */
8178 } else if (in_ssi_tag
) {
8179 if (len
== 5 && memcmp(buf
, "<!--#", 5) != 0) {
8180 /* Not an SSI tag */
8182 } else if (len
== (int)sizeof(buf
) - 2) {
8183 mg_cry(conn
, "%s: SSI tag is too large", path
);
8186 buf
[len
++] = (char)(ch
& 0xff);
8187 } else if (ch
== '<') {
8190 mg_write(conn
, buf
, (size_t)len
);
8193 buf
[len
++] = (char)(ch
& 0xff);
8195 buf
[len
++] = (char)(ch
& 0xff);
8196 if (len
== (int)sizeof(buf
)) {
8197 mg_write(conn
, buf
, (size_t)len
);
8203 /* Send the rest of buffered data */
8205 mg_write(conn
, buf
, (size_t)len
);
8211 handle_ssi_file_request(struct mg_connection
*conn
,
8216 time_t curtime
= time(NULL
);
8217 const char *cors1
, *cors2
, *cors3
;
8219 if (conn
== NULL
|| path
== NULL
|| filep
== NULL
) {
8223 if (mg_get_header(conn
, "Origin")) {
8224 /* Cross-origin resource sharing (CORS). */
8225 cors1
= "Access-Control-Allow-Origin: ";
8226 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
8229 cors1
= cors2
= cors3
= "";
8232 if (!mg_fopen(conn
, path
, "rb", filep
)) {
8233 /* File exists (precondition for calling this function),
8234 * but can not be opened by the server. */
8235 send_http_error(conn
,
8237 "Error: Cannot read file\nfopen(%s): %s",
8241 conn
->must_close
= 1;
8242 gmt_time_string(date
, sizeof(date
), &curtime
);
8243 fclose_on_exec(filep
, conn
);
8244 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
8245 send_no_cache_header(conn
);
8249 "Content-Type: text/html\r\n"
8250 "Connection: %s\r\n\r\n",
8255 suggest_connection_header(conn
));
8256 send_ssi_file(conn
, path
, filep
, 0);
8262 #if !defined(NO_FILES)
8264 send_options(struct mg_connection
*conn
)
8267 time_t curtime
= time(NULL
);
8273 conn
->status_code
= 200;
8274 conn
->must_close
= 1;
8275 gmt_time_string(date
, sizeof(date
), &curtime
);
8278 "HTTP/1.1 200 OK\r\n"
8280 /* TODO: "Cache-Control" (?) */
8281 "Connection: %s\r\n"
8282 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
8283 "PROPFIND, MKCOL\r\n"
8286 suggest_connection_header(conn
));
8290 /* Writes PROPFIND properties for a collection element */
8292 print_props(struct mg_connection
*conn
, const char *uri
, struct file
*filep
)
8296 if (conn
== NULL
|| uri
== NULL
|| filep
== NULL
) {
8300 gmt_time_string(mtime
, sizeof(mtime
), &filep
->last_modified
);
8301 conn
->num_bytes_sent
+=
8304 "<d:href>%s</d:href>"
8307 "<d:resourcetype>%s</d:resourcetype>"
8308 "<d:getcontentlength>%" INT64_FMT
"</d:getcontentlength>"
8309 "<d:getlastmodified>%s</d:getlastmodified>"
8311 "<d:status>HTTP/1.1 200 OK</d:status>"
8315 filep
->is_directory
? "<d:collection/>" : "",
8322 print_dav_dir_entry(struct de
*de
, void *data
)
8324 char href
[PATH_MAX
];
8325 char href_encoded
[PATH_MAX
];
8328 struct mg_connection
*conn
= (struct mg_connection
*)data
;
8337 conn
->request_info
.local_uri
,
8341 mg_url_encode(href
, href_encoded
, PATH_MAX
- 1);
8342 print_props(conn
, href_encoded
, &de
->file
);
8348 handle_propfind(struct mg_connection
*conn
,
8352 const char *depth
= mg_get_header(conn
, "Depth");
8354 time_t curtime
= time(NULL
);
8356 gmt_time_string(date
, sizeof(date
), &curtime
);
8358 if (!conn
|| !path
|| !filep
|| !conn
->ctx
) {
8362 conn
->must_close
= 1;
8363 conn
->status_code
= 207;
8365 "HTTP/1.1 207 Multi-Status\r\n"
8368 send_static_cache_header(conn
);
8370 "Connection: %s\r\n"
8371 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
8372 suggest_connection_header(conn
));
8374 conn
->num_bytes_sent
+=
8376 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
8377 "<d:multistatus xmlns:d='DAV:'>\n");
8379 /* Print properties for the requested resource itself */
8380 print_props(conn
, conn
->request_info
.local_uri
, filep
);
8382 /* If it is a directory, print directory entries too if Depth is not 0 */
8383 if (filep
&& filep
->is_directory
8384 && !mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
], "yes")
8385 && (depth
== NULL
|| strcmp(depth
, "0") != 0)) {
8386 scan_directory(conn
, path
, conn
, &print_dav_dir_entry
);
8389 conn
->num_bytes_sent
+= mg_printf(conn
, "%s\n", "</d:multistatus>");
8394 mg_lock_connection(struct mg_connection
*conn
)
8397 (void)pthread_mutex_lock(&conn
->mutex
);
8402 mg_unlock_connection(struct mg_connection
*conn
)
8405 (void)pthread_mutex_unlock(&conn
->mutex
);
8410 mg_lock_context(struct mg_context
*ctx
)
8413 (void)pthread_mutex_lock(&ctx
->nonce_mutex
);
8418 mg_unlock_context(struct mg_context
*ctx
)
8421 (void)pthread_mutex_unlock(&ctx
->nonce_mutex
);
8425 #if defined(USE_TIMERS)
8426 #include "timer.inl"
8427 #endif /* USE_TIMERS */
8430 #include "mod_lua.inl"
8431 #endif /* USE_LUA */
8434 #include "mod_duktape.inl"
8435 #endif /* USE_DUKTAPE */
8437 #if defined(USE_WEBSOCKET)
8439 /* START OF SHA-1 code
8440 * Copyright(c) By Steve Reid <steve@edmweb.com> */
8441 #define SHA1HANDSOFF
8443 /* According to current tests (May 2015), the <solarisfixes.h> is not required.
8445 * #if defined(__sun)
8446 * #include "solarisfixes.h"
8454 static const int n
= 1;
8455 return ((char *)&n
)[0] == 0;
8459 union char64long16
{
8460 unsigned char c
[64];
8464 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
8468 blk0(union char64long16
*block
, int i
)
8470 /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
8471 if (!is_big_endian()) {
8472 block
->l
[i
] = (rol(block
->l
[i
], 24) & 0xFF00FF00)
8473 | (rol(block
->l
[i
], 8) & 0x00FF00FF);
8479 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
8480 ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
8482 #define R0(v, w, x, y, z, i) \
8483 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
8485 #define R1(v, w, x, y, z, i) \
8486 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
8488 #define R2(v, w, x, y, z, i) \
8489 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
8491 #define R3(v, w, x, y, z, i) \
8492 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
8494 #define R4(v, w, x, y, z, i) \
8495 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
8502 unsigned char buffer
[64];
8507 SHA1Transform(uint32_t state
[5], const unsigned char buffer
[64])
8509 uint32_t a
, b
, c
, d
, e
;
8510 union char64long16 block
[1];
8512 memcpy(block
, buffer
, 64);
8518 R0(a
, b
, c
, d
, e
, 0);
8519 R0(e
, a
, b
, c
, d
, 1);
8520 R0(d
, e
, a
, b
, c
, 2);
8521 R0(c
, d
, e
, a
, b
, 3);
8522 R0(b
, c
, d
, e
, a
, 4);
8523 R0(a
, b
, c
, d
, e
, 5);
8524 R0(e
, a
, b
, c
, d
, 6);
8525 R0(d
, e
, a
, b
, c
, 7);
8526 R0(c
, d
, e
, a
, b
, 8);
8527 R0(b
, c
, d
, e
, a
, 9);
8528 R0(a
, b
, c
, d
, e
, 10);
8529 R0(e
, a
, b
, c
, d
, 11);
8530 R0(d
, e
, a
, b
, c
, 12);
8531 R0(c
, d
, e
, a
, b
, 13);
8532 R0(b
, c
, d
, e
, a
, 14);
8533 R0(a
, b
, c
, d
, e
, 15);
8534 R1(e
, a
, b
, c
, d
, 16);
8535 R1(d
, e
, a
, b
, c
, 17);
8536 R1(c
, d
, e
, a
, b
, 18);
8537 R1(b
, c
, d
, e
, a
, 19);
8538 R2(a
, b
, c
, d
, e
, 20);
8539 R2(e
, a
, b
, c
, d
, 21);
8540 R2(d
, e
, a
, b
, c
, 22);
8541 R2(c
, d
, e
, a
, b
, 23);
8542 R2(b
, c
, d
, e
, a
, 24);
8543 R2(a
, b
, c
, d
, e
, 25);
8544 R2(e
, a
, b
, c
, d
, 26);
8545 R2(d
, e
, a
, b
, c
, 27);
8546 R2(c
, d
, e
, a
, b
, 28);
8547 R2(b
, c
, d
, e
, a
, 29);
8548 R2(a
, b
, c
, d
, e
, 30);
8549 R2(e
, a
, b
, c
, d
, 31);
8550 R2(d
, e
, a
, b
, c
, 32);
8551 R2(c
, d
, e
, a
, b
, 33);
8552 R2(b
, c
, d
, e
, a
, 34);
8553 R2(a
, b
, c
, d
, e
, 35);
8554 R2(e
, a
, b
, c
, d
, 36);
8555 R2(d
, e
, a
, b
, c
, 37);
8556 R2(c
, d
, e
, a
, b
, 38);
8557 R2(b
, c
, d
, e
, a
, 39);
8558 R3(a
, b
, c
, d
, e
, 40);
8559 R3(e
, a
, b
, c
, d
, 41);
8560 R3(d
, e
, a
, b
, c
, 42);
8561 R3(c
, d
, e
, a
, b
, 43);
8562 R3(b
, c
, d
, e
, a
, 44);
8563 R3(a
, b
, c
, d
, e
, 45);
8564 R3(e
, a
, b
, c
, d
, 46);
8565 R3(d
, e
, a
, b
, c
, 47);
8566 R3(c
, d
, e
, a
, b
, 48);
8567 R3(b
, c
, d
, e
, a
, 49);
8568 R3(a
, b
, c
, d
, e
, 50);
8569 R3(e
, a
, b
, c
, d
, 51);
8570 R3(d
, e
, a
, b
, c
, 52);
8571 R3(c
, d
, e
, a
, b
, 53);
8572 R3(b
, c
, d
, e
, a
, 54);
8573 R3(a
, b
, c
, d
, e
, 55);
8574 R3(e
, a
, b
, c
, d
, 56);
8575 R3(d
, e
, a
, b
, c
, 57);
8576 R3(c
, d
, e
, a
, b
, 58);
8577 R3(b
, c
, d
, e
, a
, 59);
8578 R4(a
, b
, c
, d
, e
, 60);
8579 R4(e
, a
, b
, c
, d
, 61);
8580 R4(d
, e
, a
, b
, c
, 62);
8581 R4(c
, d
, e
, a
, b
, 63);
8582 R4(b
, c
, d
, e
, a
, 64);
8583 R4(a
, b
, c
, d
, e
, 65);
8584 R4(e
, a
, b
, c
, d
, 66);
8585 R4(d
, e
, a
, b
, c
, 67);
8586 R4(c
, d
, e
, a
, b
, 68);
8587 R4(b
, c
, d
, e
, a
, 69);
8588 R4(a
, b
, c
, d
, e
, 70);
8589 R4(e
, a
, b
, c
, d
, 71);
8590 R4(d
, e
, a
, b
, c
, 72);
8591 R4(c
, d
, e
, a
, b
, 73);
8592 R4(b
, c
, d
, e
, a
, 74);
8593 R4(a
, b
, c
, d
, e
, 75);
8594 R4(e
, a
, b
, c
, d
, 76);
8595 R4(d
, e
, a
, b
, c
, 77);
8596 R4(c
, d
, e
, a
, b
, 78);
8597 R4(b
, c
, d
, e
, a
, 79);
8603 a
= b
= c
= d
= e
= 0;
8604 memset(block
, '\0', sizeof(block
));
8609 SHA1Init(SHA1_CTX
*context
)
8611 context
->state
[0] = 0x67452301;
8612 context
->state
[1] = 0xEFCDAB89;
8613 context
->state
[2] = 0x98BADCFE;
8614 context
->state
[3] = 0x10325476;
8615 context
->state
[4] = 0xC3D2E1F0;
8616 context
->count
[0] = context
->count
[1] = 0;
8621 SHA1Update(SHA1_CTX
*context
, const unsigned char *data
, uint32_t len
)
8625 j
= context
->count
[0];
8626 if ((context
->count
[0] += len
<< 3) < j
) {
8627 context
->count
[1]++;
8629 context
->count
[1] += (len
>> 29);
8631 if ((j
+ len
) > 63) {
8632 memcpy(&context
->buffer
[j
], data
, (i
= 64 - j
));
8633 SHA1Transform(context
->state
, context
->buffer
);
8634 for (; i
+ 63 < len
; i
+= 64) {
8635 SHA1Transform(context
->state
, &data
[i
]);
8640 memcpy(&context
->buffer
[j
], &data
[i
], len
- i
);
8645 SHA1Final(unsigned char digest
[20], SHA1_CTX
*context
)
8648 unsigned char finalcount
[8], c
;
8650 for (i
= 0; i
< 8; i
++) {
8651 finalcount
[i
] = (unsigned char)((context
->count
[(i
>= 4 ? 0 : 1)]
8652 >> ((3 - (i
& 3)) * 8)) & 255);
8655 SHA1Update(context
, &c
, 1);
8656 while ((context
->count
[0] & 504) != 448) {
8658 SHA1Update(context
, &c
, 1);
8660 SHA1Update(context
, finalcount
, 8);
8661 for (i
= 0; i
< 20; i
++) {
8662 digest
[i
] = (unsigned char)((context
->state
[i
>> 2]
8663 >> ((3 - (i
& 3)) * 8)) & 255);
8665 memset(context
, '\0', sizeof(*context
));
8666 memset(&finalcount
, '\0', sizeof(finalcount
));
8668 /* END OF SHA1 CODE */
8672 send_websocket_handshake(struct mg_connection
*conn
, const char *websock_key
)
8674 static const char *magic
= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8675 const char *protocol
= NULL
;
8676 char buf
[100], sha
[20], b64_sha
[sizeof(sha
) * 2];
8680 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
8681 mg_snprintf(conn
, &truncated
, buf
, sizeof(buf
), "%s%s", websock_key
, magic
);
8683 conn
->must_close
= 1;
8688 SHA1Update(&sha_ctx
, (unsigned char *)buf
, (uint32_t)strlen(buf
));
8689 SHA1Final((unsigned char *)sha
, &sha_ctx
);
8690 base64_encode((unsigned char *)sha
, sizeof(sha
), b64_sha
);
8692 "HTTP/1.1 101 Switching Protocols\r\n"
8693 "Upgrade: websocket\r\n"
8694 "Connection: Upgrade\r\n"
8695 "Sec-WebSocket-Accept: %s\r\n",
8697 protocol
= mg_get_header(conn
, "Sec-WebSocket-Protocol");
8699 /* The protocol is a comma seperated list of names. */
8700 /* The server must only return one value from this list. */
8701 /* First check if it is a list or just a single value. */
8702 const char *sep
= strchr(protocol
, ',');
8704 /* Just a single protocol -> accept it. */
8705 mg_printf(conn
, "Sec-WebSocket-Protocol: %s\r\n\r\n", protocol
);
8707 /* Multiple protocols -> accept the first one. */
8708 /* This is just a quick fix if the client offers multiple
8709 * protocols. In order to get the behavior intended by
8710 * RFC 6455 (https://tools.ietf.org/rfc/rfc6455.txt), it is
8711 * required to have a list of websocket subprotocols accepted
8712 * by the server. Then the server must either select a subprotocol
8713 * supported by client and server, or the server has to abort the
8714 * handshake by not returning a Sec-Websocket-Protocol header if
8715 * no subprotocol is acceptable.
8718 "Sec-WebSocket-Protocol: %.*s\r\n\r\n",
8719 (int)(sep
- protocol
),
8722 /* TODO: Real subprotocol negotiation instead of just taking the first
8723 * websocket subprotocol suggested by the client. */
8725 mg_printf(conn
, "%s", "\r\n");
8733 read_websocket(struct mg_connection
*conn
,
8734 mg_websocket_data_handler ws_data_handler
,
8735 void *callback_data
)
8737 /* Pointer to the beginning of the portion of the incoming websocket
8739 * The original websocket upgrade request is never removed, so the queue
8740 * begins after it. */
8741 unsigned char *buf
= (unsigned char *)conn
->buf
+ conn
->request_len
;
8742 int n
, error
, exit_by_callback
;
8744 /* body_len is the length of the entire queue in bytes
8745 * len is the length of the current message
8746 * data_len is the length of the current message's data payload
8747 * header_len is the length of the current message's header */
8748 size_t i
, len
, mask_len
= 0, data_len
= 0, header_len
, body_len
;
8750 /* "The masking key is a 32-bit value chosen at random by the client."
8751 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
8753 unsigned char mask
[4];
8755 /* data points to the place where the message is stored when passed to
8757 * websocket_data callback. This is either mem on the stack, or a
8758 * dynamically allocated buffer if it is too large. */
8761 unsigned char mop
; /* mask flag and opcode */
8762 double timeout
= -1.0;
8764 if (conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) {
8765 timeout
= atoi(conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) / 1000.0;
8767 if ((timeout
<= 0.0) && (conn
->ctx
->config
[REQUEST_TIMEOUT
])) {
8768 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
8771 mg_set_thread_name("wsock");
8773 /* Loop continuously, reading messages from the socket, invoking the
8774 * callback, and waiting repeatedly until an error occurs. */
8775 while (!conn
->ctx
->stop_flag
) {
8777 assert(conn
->data_len
>= conn
->request_len
);
8778 if ((body_len
= (size_t)(conn
->data_len
- conn
->request_len
)) >= 2) {
8780 mask_len
= buf
[1] & 128 ? 4 : 0;
8781 if (len
< 126 && body_len
>= mask_len
) {
8783 header_len
= 2 + mask_len
;
8784 } else if (len
== 126 && body_len
>= 4 + mask_len
) {
8785 header_len
= 4 + mask_len
;
8786 data_len
= ((((size_t)buf
[2]) << 8) + buf
[3]);
8787 } else if (body_len
>= 10 + mask_len
) {
8788 header_len
= 10 + mask_len
;
8789 data_len
= (((uint64_t)ntohl(*(uint32_t *)(void *)&buf
[2]))
8790 << 32) + ntohl(*(uint32_t *)(void *)&buf
[6]);
8794 if (header_len
> 0 && body_len
>= header_len
) {
8795 /* Allocate space to hold websocket payload */
8797 if (data_len
> sizeof(mem
)) {
8798 data
= (char *)mg_malloc(data_len
);
8800 /* Allocation failed, exit the loop and then close the
8802 mg_cry(conn
, "websocket out of memory; closing connection");
8807 /* Copy the mask before we shift the queue and destroy it */
8809 memcpy(mask
, buf
+ header_len
- mask_len
, sizeof(mask
));
8811 memset(mask
, 0, sizeof(mask
));
8814 /* Read frame payload from the first message in the queue into
8815 * data and advance the queue by moving the memory in place. */
8816 assert(body_len
>= header_len
);
8817 if (data_len
+ header_len
> body_len
) {
8818 mop
= buf
[0]; /* current mask and opcode */
8820 len
= body_len
- header_len
;
8821 memcpy(data
, buf
+ header_len
, len
);
8823 while (len
< data_len
) {
8825 NULL
, conn
, data
+ len
, (int)(data_len
- len
), timeout
);
8833 mg_cry(conn
, "Websocket pull failed; closing connection");
8836 conn
->data_len
= conn
->request_len
;
8838 mop
= buf
[0]; /* current mask and opcode, overwritten by
8840 /* Length of the message being read at the front of the
8842 len
= data_len
+ header_len
;
8844 /* Copy the data payload into the data pointer for the
8846 memcpy(data
, buf
+ header_len
, data_len
);
8848 /* Move the queue forward len bytes */
8849 memmove(buf
, buf
+ len
, body_len
- len
);
8851 /* Mark the queue as advanced */
8852 conn
->data_len
-= (int)len
;
8855 /* Apply mask if necessary */
8857 for (i
= 0; i
< data_len
; ++i
) {
8858 data
[i
] ^= mask
[i
& 3];
8862 /* Exit the loop if callback signals to exit (server side),
8863 * or "connection close" opcode received (client side). */
8864 exit_by_callback
= 0;
8865 if ((ws_data_handler
!= NULL
)
8866 && !ws_data_handler(conn
, mop
, data
, data_len
, callback_data
)) {
8867 exit_by_callback
= 1;
8874 if (exit_by_callback
8875 || ((mop
& 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE
)) {
8876 /* Opcode == 8, connection close */
8880 /* Not breaking the loop, process next websocket frame. */
8882 /* Read from the socket into the next available location in the
8886 conn
->buf
+ conn
->data_len
,
8887 conn
->buf_size
- conn
->data_len
,
8889 /* Error, no bytes read */
8892 conn
->data_len
+= n
;
8896 mg_set_thread_name("worker");
8901 mg_websocket_write_exec(struct mg_connection
*conn
,
8905 uint32_t masking_key
)
8907 unsigned char header
[14];
8908 size_t headerLen
= 1;
8912 header
[0] = 0x80 + (opcode
& 0xF);
8914 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
8915 if (dataLen
< 126) {
8916 /* inline 7-bit length field */
8917 header
[1] = (unsigned char)dataLen
;
8919 } else if (dataLen
<= 0xFFFF) {
8920 /* 16-bit length field */
8922 *(uint16_t *)(void *)(header
+ 2) = htons((uint16_t)dataLen
);
8925 /* 64-bit length field */
8927 *(uint32_t *)(void *)(header
+ 2) = htonl((uint64_t)dataLen
>> 32);
8928 *(uint32_t *)(void *)(header
+ 6) = htonl(dataLen
& 0xFFFFFFFF);
8935 *(uint32_t *)(void *)(header
+ headerLen
) = masking_key
;
8940 /* Note that POSIX/Winsock's send() is threadsafe
8941 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
8942 * but mongoose's mg_printf/mg_write is not (because of the loop in
8943 * push(), although that is only a problem if the packet is large or
8944 * outgoing buffer is full). */
8945 (void)mg_lock_connection(conn
);
8946 retval
= mg_write(conn
, header
, headerLen
);
8948 retval
= mg_write(conn
, data
, dataLen
);
8950 mg_unlock_connection(conn
);
8956 mg_websocket_write(struct mg_connection
*conn
,
8961 return mg_websocket_write_exec(conn
, opcode
, data
, dataLen
, 0);
8966 mask_data(const char *in
, size_t in_len
, uint32_t masking_key
, char *out
)
8971 if ((in_len
> 3) && ((ptrdiff_t)in
% 4) == 0) {
8972 /* Convert in 32 bit words, if data is 4 byte aligned */
8973 while (i
< (in_len
- 3)) {
8974 *(uint32_t *)(void *)(out
+ i
) =
8975 *(uint32_t *)(void *)(in
+ i
) ^ masking_key
;
8980 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
8981 while (i
< in_len
) {
8982 *(uint8_t *)(void *)(out
+ i
) =
8983 *(uint8_t *)(void *)(in
+ i
)
8984 ^ *(((uint8_t *)&masking_key
) + (i
% 4));
8992 mg_websocket_client_write(struct mg_connection
*conn
,
8998 char *masked_data
= (char *)mg_malloc(((dataLen
+ 7) / 4) * 4);
8999 uint32_t masking_key
= (uint32_t)get_random();
9001 if (masked_data
== NULL
) {
9002 /* Return -1 in an error case */
9004 "Cannot allocate buffer for masked websocket response: "
9009 mask_data(data
, dataLen
, masking_key
, masked_data
);
9011 retval
= mg_websocket_write_exec(
9012 conn
, opcode
, masked_data
, dataLen
, masking_key
);
9013 mg_free(masked_data
);
9020 handle_websocket_request(struct mg_connection
*conn
,
9022 int is_callback_resource
,
9023 mg_websocket_connect_handler ws_connect_handler
,
9024 mg_websocket_ready_handler ws_ready_handler
,
9025 mg_websocket_data_handler ws_data_handler
,
9026 mg_websocket_close_handler ws_close_handler
,
9029 const char *websock_key
= mg_get_header(conn
, "Sec-WebSocket-Key");
9030 const char *version
= mg_get_header(conn
, "Sec-WebSocket-Version");
9031 int lua_websock
= 0;
9033 #if !defined(USE_LUA)
9037 /* Step 1: Check websocket protocol version. */
9038 /* Step 1.1: Check Sec-WebSocket-Key. */
9040 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
9041 * requires a Sec-WebSocket-Key header.
9043 /* It could be the hixie draft version
9044 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
9046 const char *key1
= mg_get_header(conn
, "Sec-WebSocket-Key1");
9047 const char *key2
= mg_get_header(conn
, "Sec-WebSocket-Key2");
9050 if ((key1
!= NULL
) && (key2
!= NULL
)) {
9051 /* This version uses 8 byte body data in a GET request */
9052 conn
->content_len
= 8;
9053 if (8 == mg_read(conn
, key3
, 8)) {
9054 /* This is the hixie version */
9055 send_http_error(conn
,
9058 "Protocol upgrade to RFC 6455 required");
9062 /* This is an unknown version */
9063 send_http_error(conn
, 400, "%s", "Malformed websocket request");
9067 /* Step 1.2: Check websocket protocol version. */
9068 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
9069 if (version
== NULL
|| strcmp(version
, "13") != 0) {
9070 /* Reject wrong versions */
9071 send_http_error(conn
, 426, "%s", "Protocol upgrade required");
9075 /* Step 1.3: Could check for "Host", but we do not really nead this
9076 * value for anything, so just ignore it. */
9078 /* Step 2: If a callback is responsible, call it. */
9079 if (is_callback_resource
) {
9080 if (ws_connect_handler
!= NULL
9081 && ws_connect_handler(conn
, cbData
) != 0) {
9082 /* C callback has returned non-zero, do not proceed with
9085 /* Note that C callbacks are no longer called when Lua is
9086 * responsible, so C can no longer filter callbacks for Lua. */
9090 #if defined(USE_LUA)
9091 /* Step 3: No callback. Check if Lua is responsible. */
9093 /* Step 3.1: Check if Lua is responsible. */
9094 if (conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]) {
9096 match_prefix(conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
],
9098 conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]),
9103 /* Step 3.2: Lua is responsible: call it. */
9104 conn
->lua_websocket_state
= lua_websocket_new(path
, conn
);
9105 if (!conn
->lua_websocket_state
) {
9106 /* Lua rejected the new client */
9113 /* Step 4: Check if there is a responsible websocket handler. */
9114 if (!is_callback_resource
&& !lua_websock
) {
9115 /* There is no callback, an Lua is not responsible either. */
9116 /* Reply with a 404 Not Found or with nothing at all?
9117 * TODO (mid): check the websocket standards, how to reply to
9118 * requests to invalid websocket addresses. */
9119 send_http_error(conn
, 404, "%s", "Not found");
9123 /* Step 5: The websocket connection has been accepted */
9124 if (!send_websocket_handshake(conn
, websock_key
)) {
9125 send_http_error(conn
, 500, "%s", "Websocket handshake failed");
9129 /* Step 6: Call the ready handler */
9130 if (is_callback_resource
) {
9131 if (ws_ready_handler
!= NULL
) {
9132 ws_ready_handler(conn
, cbData
);
9134 #if defined(USE_LUA)
9135 } else if (lua_websock
) {
9136 if (!lua_websocket_ready(conn
, conn
->lua_websocket_state
)) {
9137 /* the ready handler returned false */
9143 /* Step 7: Enter the read loop */
9144 if (is_callback_resource
) {
9145 read_websocket(conn
, ws_data_handler
, cbData
);
9146 #if defined(USE_LUA)
9147 } else if (lua_websock
) {
9148 read_websocket(conn
, lua_websocket_data
, conn
->lua_websocket_state
);
9152 /* Step 8: Call the close handler */
9153 if (ws_close_handler
) {
9154 ws_close_handler(conn
, cbData
);
9160 is_websocket_protocol(const struct mg_connection
*conn
)
9162 const char *upgrade
, *connection
;
9164 /* A websocket protocoll has the following HTTP headers:
9166 * Connection: Upgrade
9167 * Upgrade: Websocket
9170 upgrade
= mg_get_header(conn
, "Upgrade");
9171 if (upgrade
== NULL
) {
9172 return 0; /* fail early, don't waste time checking other header
9176 if (!mg_strcasestr(upgrade
, "websocket")) {
9180 connection
= mg_get_header(conn
, "Connection");
9181 if (connection
== NULL
) {
9184 if (!mg_strcasestr(connection
, "upgrade")) {
9188 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
9189 * "Sec-WebSocket-Version" are also required.
9190 * Don't check them here, since even an unsupported websocket protocol
9191 * request still IS a websocket request (in contrast to a standard HTTP
9192 * request). It will fail later in handle_websocket_request.
9197 #endif /* !USE_WEBSOCKET */
9203 return n
>= 0 && n
<= 255;
9208 parse_net(const char *spec
, uint32_t *net
, uint32_t *mask
)
9210 int n
, a
, b
, c
, d
, slash
= 32, len
= 0;
9212 if ((sscanf(spec
, "%d.%d.%d.%d/%d%n", &a
, &b
, &c
, &d
, &slash
, &n
) == 5
9213 || sscanf(spec
, "%d.%d.%d.%d%n", &a
, &b
, &c
, &d
, &n
) == 4) && isbyte(a
)
9214 && isbyte(b
) && isbyte(c
) && isbyte(d
) && slash
>= 0
9217 *net
= ((uint32_t)a
<< 24) | ((uint32_t)b
<< 16) | ((uint32_t)c
<< 8)
9219 *mask
= slash
? 0xffffffffU
<< (32 - slash
) : 0;
9227 set_throttle(const char *spec
, uint32_t remote_ip
, const char *uri
)
9230 struct vec vec
, val
;
9235 while ((spec
= next_option(spec
, &vec
, &val
)) != NULL
) {
9237 if (sscanf(val
.ptr
, "%lf%c", &v
, &mult
) < 1 || v
< 0
9238 || (lowercase(&mult
) != 'k' && lowercase(&mult
) != 'm'
9242 v
*= lowercase(&mult
) == 'k' ? 1024 : lowercase(&mult
) == 'm' ? 1048576
9244 if (vec
.len
== 1 && vec
.ptr
[0] == '*') {
9246 } else if (parse_net(vec
.ptr
, &net
, &mask
) > 0) {
9247 if ((remote_ip
& mask
) == net
) {
9250 } else if (match_prefix(vec
.ptr
, vec
.len
, uri
) > 0) {
9260 get_remote_ip(const struct mg_connection
*conn
)
9265 return ntohl(*(const uint32_t *)&conn
->client
.rsa
.sin
.sin_addr
);
9269 /* The mg_upload function is superseeded by mg_handle_form_request. */
9270 #include "handle_form.inl"
9273 #if defined(MG_LEGACY_INTERFACE)
9274 /* Implement the deprecated mg_upload function by calling the new
9275 * mg_handle_form_request function. While mg_upload could only handle
9276 * HTML forms sent as POST request in multipart/form-data format
9277 * containing only file input elements, mg_handle_form_request can
9278 * handle all form input elements and all standard request methods. */
9279 struct mg_upload_user_data
{
9280 struct mg_connection
*conn
;
9281 const char *destination_dir
;
9282 int num_uploaded_files
;
9286 /* Helper function for deprecated mg_upload. */
9288 mg_upload_field_found(const char *key
,
9289 const char *filename
,
9295 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9299 mg_cry(fud
->conn
, "%s: No filename set", __func__
);
9300 return FORM_FIELD_STORAGE_ABORT
;
9302 mg_snprintf(fud
->conn
,
9307 fud
->destination_dir
,
9310 mg_cry(fud
->conn
, "%s: File path too long", __func__
);
9311 return FORM_FIELD_STORAGE_ABORT
;
9313 return FORM_FIELD_STORAGE_STORE
;
9317 /* Helper function for deprecated mg_upload. */
9319 mg_upload_field_get(const char *key
,
9324 /* Function should never be called */
9334 /* Helper function for deprecated mg_upload. */
9336 mg_upload_field_stored(const char *path
, long long file_size
, void *user_data
)
9338 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9341 fud
->num_uploaded_files
++;
9342 fud
->conn
->ctx
->callbacks
.upload(fud
->conn
, path
);
9348 /* Deprecated function mg_upload - use mg_handle_form_request instead. */
9350 mg_upload(struct mg_connection
*conn
, const char *destination_dir
)
9352 struct mg_upload_user_data fud
= {conn
, destination_dir
, 0};
9353 struct mg_form_data_handler fdh
= {mg_upload_field_found
,
9354 mg_upload_field_get
,
9355 mg_upload_field_stored
,
9359 fdh
.user_data
= (void *)&fud
;
9360 ret
= mg_handle_form_request(conn
, &fdh
);
9363 mg_cry(conn
, "%s: Error while parsing the request", __func__
);
9366 return fud
.num_uploaded_files
;
9372 get_first_ssl_listener_index(const struct mg_context
*ctx
)
9377 for (i
= 0; idx
== -1 && i
< ctx
->num_listening_sockets
; i
++) {
9378 idx
= ctx
->listening_sockets
[i
].is_ssl
? ((int)(i
)) : -1;
9386 redirect_to_https_port(struct mg_connection
*conn
, int ssl_index
)
9389 const char *host_header
;
9392 host_header
= mg_get_header(conn
, "Host");
9393 hostlen
= sizeof(host
);
9394 if (host_header
!= NULL
) {
9397 mg_strlcpy(host
, host_header
, hostlen
);
9398 host
[hostlen
- 1] = '\0';
9399 pos
= strchr(host
, ':');
9404 /* Cannot get host from the Host: header.
9405 * Fallback to our IP address. */
9407 sockaddr_to_string(host
, hostlen
, &conn
->client
.lsa
);
9411 /* Send host, port, uri and (if it exists) ?query_string */
9414 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
9417 conn
->ctx
->listening_sockets
[ssl_index
].lsa
.sin
.sin_port
),
9418 conn
->request_info
.local_uri
,
9419 (conn
->request_info
.query_string
== NULL
) ? "" : "?",
9420 (conn
->request_info
.query_string
== NULL
)
9422 : conn
->request_info
.query_string
);
9428 mg_set_handler_type(struct mg_context
*ctx
,
9431 int is_delete_request
,
9432 mg_request_handler handler
,
9433 mg_websocket_connect_handler connect_handler
,
9434 mg_websocket_ready_handler ready_handler
,
9435 mg_websocket_data_handler data_handler
,
9436 mg_websocket_close_handler close_handler
,
9437 mg_authorization_handler auth_handler
,
9440 struct mg_handler_info
*tmp_rh
, **lastref
;
9441 size_t urilen
= strlen(uri
);
9443 if (handler_type
== WEBSOCKET_HANDLER
) {
9444 /* assert(handler == NULL); */
9445 /* assert(is_delete_request || connect_handler!=NULL ||
9446 * ready_handler!=NULL || data_handler!=NULL ||
9447 * close_handler!=NULL);
9449 /* assert(auth_handler == NULL); */
9450 if (handler
!= NULL
) {
9453 if (!is_delete_request
&& connect_handler
== NULL
9454 && ready_handler
== NULL
9455 && data_handler
== NULL
9456 && close_handler
== NULL
) {
9459 if (auth_handler
!= NULL
) {
9462 } else if (handler_type
== REQUEST_HANDLER
) {
9463 /* assert(connect_handler==NULL && ready_handler==NULL &&
9464 * data_handler==NULL && close_handler==NULL); */
9465 /* assert(is_delete_request || (handler!=NULL));
9467 /* assert(auth_handler == NULL); */
9468 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9469 || data_handler
!= NULL
9470 || close_handler
!= NULL
) {
9473 if (!is_delete_request
&& (handler
== NULL
)) {
9476 if (auth_handler
!= NULL
) {
9479 } else { /* AUTH_HANDLER */
9480 /* assert(handler == NULL); */
9481 /* assert(connect_handler==NULL && ready_handler==NULL &&
9482 * data_handler==NULL && close_handler==NULL); */
9483 /* assert(auth_handler != NULL); */
9484 if (handler
!= NULL
) {
9487 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9488 || data_handler
!= NULL
9489 || close_handler
!= NULL
) {
9492 if (!is_delete_request
&& (auth_handler
== NULL
)) {
9501 mg_lock_context(ctx
);
9503 /* first try to find an existing handler */
9504 lastref
= &(ctx
->handlers
);
9505 for (tmp_rh
= ctx
->handlers
; tmp_rh
!= NULL
; tmp_rh
= tmp_rh
->next
) {
9506 if (tmp_rh
->handler_type
== handler_type
) {
9507 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9508 if (!is_delete_request
) {
9509 /* update existing handler */
9510 if (handler_type
== REQUEST_HANDLER
) {
9511 tmp_rh
->handler
= handler
;
9512 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9513 tmp_rh
->connect_handler
= connect_handler
;
9514 tmp_rh
->ready_handler
= ready_handler
;
9515 tmp_rh
->data_handler
= data_handler
;
9516 tmp_rh
->close_handler
= close_handler
;
9517 } else { /* AUTH_HANDLER */
9518 tmp_rh
->auth_handler
= auth_handler
;
9520 tmp_rh
->cbdata
= cbdata
;
9522 /* remove existing handler */
9523 *lastref
= tmp_rh
->next
;
9524 mg_free(tmp_rh
->uri
);
9527 mg_unlock_context(ctx
);
9531 lastref
= &(tmp_rh
->next
);
9534 if (is_delete_request
) {
9535 /* no handler to set, this was a remove request to a non-existing
9537 mg_unlock_context(ctx
);
9542 (struct mg_handler_info
*)mg_calloc(sizeof(struct mg_handler_info
), 1);
9543 if (tmp_rh
== NULL
) {
9544 mg_unlock_context(ctx
);
9545 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9548 tmp_rh
->uri
= mg_strdup(uri
);
9550 mg_unlock_context(ctx
);
9552 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9555 tmp_rh
->uri_len
= urilen
;
9556 if (handler_type
== REQUEST_HANDLER
) {
9557 tmp_rh
->handler
= handler
;
9558 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9559 tmp_rh
->connect_handler
= connect_handler
;
9560 tmp_rh
->ready_handler
= ready_handler
;
9561 tmp_rh
->data_handler
= data_handler
;
9562 tmp_rh
->close_handler
= close_handler
;
9563 } else { /* AUTH_HANDLER */
9564 tmp_rh
->auth_handler
= auth_handler
;
9566 tmp_rh
->cbdata
= cbdata
;
9567 tmp_rh
->handler_type
= handler_type
;
9568 tmp_rh
->next
= NULL
;
9571 mg_unlock_context(ctx
);
9576 mg_set_request_handler(struct mg_context
*ctx
,
9578 mg_request_handler handler
,
9581 mg_set_handler_type(ctx
,
9596 mg_set_websocket_handler(struct mg_context
*ctx
,
9598 mg_websocket_connect_handler connect_handler
,
9599 mg_websocket_ready_handler ready_handler
,
9600 mg_websocket_data_handler data_handler
,
9601 mg_websocket_close_handler close_handler
,
9604 int is_delete_request
= (connect_handler
== NULL
) && (ready_handler
== NULL
)
9605 && (data_handler
== NULL
)
9606 && (close_handler
== NULL
);
9607 mg_set_handler_type(ctx
,
9622 mg_set_auth_handler(struct mg_context
*ctx
,
9624 mg_request_handler handler
,
9627 mg_set_handler_type(ctx
,
9642 get_request_handler(struct mg_connection
*conn
,
9644 mg_request_handler
*handler
,
9645 mg_websocket_connect_handler
*connect_handler
,
9646 mg_websocket_ready_handler
*ready_handler
,
9647 mg_websocket_data_handler
*data_handler
,
9648 mg_websocket_close_handler
*close_handler
,
9649 mg_authorization_handler
*auth_handler
,
9652 const struct mg_request_info
*request_info
= mg_get_request_info(conn
);
9654 const char *uri
= request_info
->local_uri
;
9655 size_t urilen
= strlen(uri
);
9656 struct mg_handler_info
*tmp_rh
;
9658 if (!conn
|| !conn
->ctx
) {
9662 mg_lock_context(conn
->ctx
);
9664 /* first try for an exact match */
9665 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9666 tmp_rh
= tmp_rh
->next
) {
9667 if (tmp_rh
->handler_type
== handler_type
) {
9668 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9669 if (handler_type
== WEBSOCKET_HANDLER
) {
9670 *connect_handler
= tmp_rh
->connect_handler
;
9671 *ready_handler
= tmp_rh
->ready_handler
;
9672 *data_handler
= tmp_rh
->data_handler
;
9673 *close_handler
= tmp_rh
->close_handler
;
9674 } else if (handler_type
== REQUEST_HANDLER
) {
9675 *handler
= tmp_rh
->handler
;
9676 } else { /* AUTH_HANDLER */
9677 *auth_handler
= tmp_rh
->auth_handler
;
9679 *cbdata
= tmp_rh
->cbdata
;
9680 mg_unlock_context(conn
->ctx
);
9686 /* next try for a partial match, we will accept uri/something */
9687 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9688 tmp_rh
= tmp_rh
->next
) {
9689 if (tmp_rh
->handler_type
== handler_type
) {
9690 if (tmp_rh
->uri_len
< urilen
&& uri
[tmp_rh
->uri_len
] == '/'
9691 && memcmp(tmp_rh
->uri
, uri
, tmp_rh
->uri_len
) == 0) {
9692 if (handler_type
== WEBSOCKET_HANDLER
) {
9693 *connect_handler
= tmp_rh
->connect_handler
;
9694 *ready_handler
= tmp_rh
->ready_handler
;
9695 *data_handler
= tmp_rh
->data_handler
;
9696 *close_handler
= tmp_rh
->close_handler
;
9697 } else if (handler_type
== REQUEST_HANDLER
) {
9698 *handler
= tmp_rh
->handler
;
9699 } else { /* AUTH_HANDLER */
9700 *auth_handler
= tmp_rh
->auth_handler
;
9702 *cbdata
= tmp_rh
->cbdata
;
9703 mg_unlock_context(conn
->ctx
);
9709 /* finally try for pattern match */
9710 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9711 tmp_rh
= tmp_rh
->next
) {
9712 if (tmp_rh
->handler_type
== handler_type
) {
9713 if (match_prefix(tmp_rh
->uri
, tmp_rh
->uri_len
, uri
) > 0) {
9714 if (handler_type
== WEBSOCKET_HANDLER
) {
9715 *connect_handler
= tmp_rh
->connect_handler
;
9716 *ready_handler
= tmp_rh
->ready_handler
;
9717 *data_handler
= tmp_rh
->data_handler
;
9718 *close_handler
= tmp_rh
->close_handler
;
9719 } else if (handler_type
== REQUEST_HANDLER
) {
9720 *handler
= tmp_rh
->handler
;
9721 } else { /* AUTH_HANDLER */
9722 *auth_handler
= tmp_rh
->auth_handler
;
9724 *cbdata
= tmp_rh
->cbdata
;
9725 mg_unlock_context(conn
->ctx
);
9731 mg_unlock_context(conn
->ctx
);
9733 return 0; /* none found */
9737 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
9739 deprecated_websocket_connect_wrapper(const struct mg_connection
*conn
,
9742 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9743 if (pcallbacks
->websocket_connect
) {
9744 return pcallbacks
->websocket_connect(conn
);
9746 /* No handler set - assume "OK" */
9752 deprecated_websocket_ready_wrapper(struct mg_connection
*conn
, void *cbdata
)
9754 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9755 if (pcallbacks
->websocket_ready
) {
9756 pcallbacks
->websocket_ready(conn
);
9762 deprecated_websocket_data_wrapper(struct mg_connection
*conn
,
9768 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9769 if (pcallbacks
->websocket_data
) {
9770 return pcallbacks
->websocket_data(conn
, bits
, data
, len
);
9772 /* No handler set - assume "OK" */
9778 /* This is the heart of the Civetweb's logic.
9779 * This function is called when the request is read, parsed and validated,
9780 * and Civetweb must decide what action to take: serve a file, or
9781 * a directory, or call embedded function, etcetera. */
9783 handle_request(struct mg_connection
*conn
)
9786 struct mg_request_info
*ri
= &conn
->request_info
;
9787 char path
[PATH_MAX
];
9788 int uri_len
, ssl_index
;
9789 int is_found
= 0, is_script_resource
= 0, is_websocket_request
= 0,
9790 is_put_or_delete_request
= 0, is_callback_resource
= 0;
9792 struct file file
= STRUCT_FILE_INITIALIZER
;
9793 mg_request_handler callback_handler
= NULL
;
9794 mg_websocket_connect_handler ws_connect_handler
= NULL
;
9795 mg_websocket_ready_handler ws_ready_handler
= NULL
;
9796 mg_websocket_data_handler ws_data_handler
= NULL
;
9797 mg_websocket_close_handler ws_close_handler
= NULL
;
9798 void *callback_data
= NULL
;
9799 mg_authorization_handler auth_handler
= NULL
;
9800 void *auth_callback_data
= NULL
;
9801 #if !defined(NO_FILES)
9802 time_t curtime
= time(NULL
);
9812 /* 1. get the request url */
9813 /* 1.1. split into url and query string */
9814 if ((conn
->request_info
.query_string
= strchr(ri
->request_uri
, '?'))
9816 *((char *)conn
->request_info
.query_string
++) = '\0';
9818 uri_len
= (int)strlen(ri
->local_uri
);
9820 /* 1.2. decode url (if config says so) */
9821 if (should_decode_url(conn
)) {
9823 ri
->local_uri
, uri_len
, (char *)ri
->local_uri
, uri_len
+ 1, 0);
9826 /* 1.3. clean URIs, so a path like allowed_dir/../forbidden_file is
9828 remove_double_dots_and_double_slashes((char *)ri
->local_uri
);
9830 /* step 1. completed, the url is known now */
9831 DEBUG_TRACE("URL: %s", ri
->local_uri
);
9833 /* 2. do a https redirect, if required */
9834 if (!conn
->client
.is_ssl
&& conn
->client
.ssl_redir
) {
9835 ssl_index
= get_first_ssl_listener_index(conn
->ctx
);
9836 if (ssl_index
>= 0) {
9837 redirect_to_https_port(conn
, ssl_index
);
9839 /* A http to https forward port has been specified,
9840 * but no https port to forward to. */
9841 send_http_error(conn
,
9844 "Error: SSL forward not configured properly");
9845 mg_cry(conn
, "Can not redirect to SSL, no SSL port available");
9850 /* 3. if this ip has limited speed, set it for this connection */
9851 conn
->throttle
= set_throttle(conn
->ctx
->config
[THROTTLE
],
9852 get_remote_ip(conn
),
9855 /* 4. call a "handle everything" callback, if registered */
9856 if (conn
->ctx
->callbacks
.begin_request
!= NULL
) {
9857 /* Note that since V1.7 the "begin_request" function is called
9858 * before an authorization check. If an authorization check is
9859 * required, use a request_handler instead. */
9860 i
= conn
->ctx
->callbacks
.begin_request(conn
);
9862 /* callback already processed the request. Store the
9863 return value as a status code for the access log. */
9864 conn
->status_code
= i
;
9866 } else if (i
== 0) {
9867 /* civetweb should process the request */
9869 /* unspecified - may change with the next version */
9874 /* request not yet handled by a handler or redirect, so the request
9875 * is processed here */
9877 /* 5. interpret the url to find out how the request must be handled
9879 /* 5.1. first test, if the request targets the regular http(s)://
9880 * protocol namespace or the websocket ws(s):// protocol namespace.
9882 is_websocket_request
= is_websocket_protocol(conn
);
9884 /* 5.2. check if the request will be handled by a callback */
9885 if (get_request_handler(conn
,
9886 is_websocket_request
? WEBSOCKET_HANDLER
9889 &ws_connect_handler
,
9895 /* 5.2.1. A callback will handle this request. All requests
9897 * by a callback have to be considered as requests to a script
9899 is_callback_resource
= 1;
9900 is_script_resource
= 1;
9901 is_put_or_delete_request
= is_put_or_delete_method(conn
);
9903 no_callback_resource
:
9904 /* 5.2.2. No callback is responsible for this request. The URI
9905 * addresses a file based resource (static content or Lua/cgi
9906 * scripts in the file system). */
9907 is_callback_resource
= 0;
9913 &is_script_resource
,
9914 &is_websocket_request
,
9915 &is_put_or_delete_request
);
9918 /* 6. authorization check */
9919 /* 6.1. a custom authorization handler is installed */
9920 if (get_request_handler(conn
,
9928 &auth_callback_data
)) {
9929 if (!auth_handler(conn
, auth_callback_data
)) {
9932 } else if (is_put_or_delete_request
&& !is_script_resource
9933 && !is_callback_resource
) {
9934 /* 6.2. this request is a PUT/DELETE to a real file */
9935 /* 6.2.1. thus, the server must have real files */
9936 #if defined(NO_FILES)
9939 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
9941 /* This server does not have any real files, thus the
9942 * PUT/DELETE methods are not valid. */
9943 send_http_error(conn
,
9945 "%s method not allowed",
9946 conn
->request_info
.request_method
);
9950 #if !defined(NO_FILES)
9951 /* 6.2.2. Check if put authorization for static files is
9954 if (!is_authorized_for_put(conn
)) {
9955 send_authorization_request(conn
);
9961 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
9962 * or it is a PUT or DELETE request to a resource that does not
9963 * correspond to a file. Check authorization. */
9964 if (!check_authorization(conn
, path
)) {
9965 send_authorization_request(conn
);
9970 /* request is authorized or does not need authorization */
9972 /* 7. check if there are request handlers for this uri */
9973 if (is_callback_resource
) {
9974 if (!is_websocket_request
) {
9975 i
= callback_handler(conn
, callback_data
);
9977 /* Do nothing, callback has served the request. Store
9979 * return value as status code for the log and discard
9981 * data from the client not used by the callback. */
9982 conn
->status_code
= i
;
9983 discard_unread_request_data(conn
);
9985 /* TODO (high): what if the handler did NOT handle the
9987 /* The last version did handle this as a file request,
9989 * since a file request is not always a script resource,
9990 * the authorization check might be different */
9996 &is_script_resource
,
9997 &is_websocket_request
,
9998 &is_put_or_delete_request
);
9999 callback_handler
= NULL
;
10001 /* TODO (very low): goto is deprecated but for the
10003 * a goto is simpler than some curious loop. */
10004 /* The situation "callback does not handle the request"
10005 * needs to be reconsidered anyway. */
10006 goto no_callback_resource
;
10009 #if defined(USE_WEBSOCKET)
10010 handle_websocket_request(conn
,
10012 is_callback_resource
,
10013 ws_connect_handler
,
10023 /* 8. handle websocket requests */
10024 #if defined(USE_WEBSOCKET)
10025 if (is_websocket_request
) {
10026 if (is_script_resource
) {
10027 /* Websocket Lua script */
10028 handle_websocket_request(conn
,
10030 0 /* Lua Script */,
10035 &conn
->ctx
->callbacks
);
10037 #if defined(MG_LEGACY_INTERFACE)
10038 handle_websocket_request(
10041 !is_script_resource
/* could be deprecated global callback */,
10042 deprecated_websocket_connect_wrapper
,
10043 deprecated_websocket_ready_wrapper
,
10044 deprecated_websocket_data_wrapper
,
10046 &conn
->ctx
->callbacks
);
10048 send_http_error(conn
, 404, "%s", "Not found");
10055 #if defined(NO_FILES)
10056 /* 9a. In case the server uses only callbacks, this uri is
10058 * Then, all request handling ends here. */
10059 send_http_error(conn
, 404, "%s", "Not Found");
10062 /* 9b. This request is either for a static file or resource handled
10063 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
10064 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
10065 send_http_error(conn
, 404, "%s", "Not Found");
10069 /* 10. File is handled by a script. */
10070 if (is_script_resource
) {
10071 handle_file_based_request(conn
, path
, &file
);
10075 /* 11. Handle put/delete/mkcol requests */
10076 if (is_put_or_delete_request
) {
10077 /* 11.1. PUT method */
10078 if (!strcmp(ri
->request_method
, "PUT")) {
10079 put_file(conn
, path
);
10082 /* 11.2. DELETE method */
10083 if (!strcmp(ri
->request_method
, "DELETE")) {
10084 delete_file(conn
, path
);
10087 /* 11.3. MKCOL method */
10088 if (!strcmp(ri
->request_method
, "MKCOL")) {
10092 /* 11.4. PATCH method
10093 * This method is not supported for static resources,
10094 * only for scripts (Lua, CGI) and callbacks. */
10095 send_http_error(conn
,
10097 "%s method not allowed",
10098 conn
->request_info
.request_method
);
10102 /* 11. File does not exist, or it was configured that it should be
10104 if (!is_found
|| (must_hide_file(conn
, path
))) {
10105 send_http_error(conn
, 404, "%s", "Not found");
10109 /* 12. Directory uris should end with a slash */
10110 if (file
.is_directory
&& ri
->local_uri
[uri_len
- 1] != '/') {
10111 gmt_time_string(date
, sizeof(date
), &curtime
);
10113 "HTTP/1.1 301 Moved Permanently\r\n"
10114 "Location: %s/\r\n"
10116 /* "Cache-Control: private\r\n" (= default) */
10117 "Content-Length: 0\r\n"
10118 "Connection: %s\r\n\r\n",
10121 suggest_connection_header(conn
));
10125 /* 13. Handle other methods than GET/HEAD */
10126 /* 13.1. Handle PROPFIND */
10127 if (!strcmp(ri
->request_method
, "PROPFIND")) {
10128 handle_propfind(conn
, path
, &file
);
10131 /* 13.2. Handle OPTIONS for files */
10132 if (!strcmp(ri
->request_method
, "OPTIONS")) {
10133 /* This standard handler is only used for real files.
10134 * Scripts should support the OPTIONS method themselves, to allow a
10135 * maximum flexibility.
10136 * Lua and CGI scripts may fully support CORS this way (including
10138 send_options(conn
);
10141 /* 13.3. everything but GET and HEAD (e.g. POST) */
10142 if (0 != strcmp(ri
->request_method
, "GET")
10143 && 0 != strcmp(ri
->request_method
, "HEAD")) {
10144 send_http_error(conn
,
10146 "%s method not allowed",
10147 conn
->request_info
.request_method
);
10151 /* 14. directories */
10152 if (file
.is_directory
) {
10153 if (substitute_index_file(conn
, path
, sizeof(path
), &file
)) {
10154 /* 14.1. use a substitute file */
10155 /* TODO (high): substitute index may be a script resource.
10156 * define what should be possible in this case. */
10158 /* 14.2. no substitute file */
10159 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
10161 handle_directory_request(conn
, path
);
10163 send_http_error(conn
,
10166 "Error: Directory listing denied");
10172 handle_file_based_request(conn
, path
, &file
);
10173 #endif /* !defined(NO_FILES) */
10176 /* Perform redirect and auth checks before calling begin_request()
10178 * Otherwise, begin_request() would need to perform auth checks and
10187 handle_file_based_request(struct mg_connection
*conn
,
10191 if (!conn
|| !conn
->ctx
) {
10197 } else if (match_prefix(conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
],
10199 conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
]),
10201 /* Lua server page: an SSI like page containing mostly plain html
10203 * plus some tags with server generated contents. */
10204 handle_lsp_request(conn
, path
, file
, NULL
);
10205 } else if (match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
10206 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
10208 /* Lua in-server module script: a CGI like script used to generate
10211 mg_exec_lua_script(conn
, path
, NULL
);
10213 #if defined(USE_DUKTAPE)
10214 } else if (match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
10216 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
10218 /* Call duktape to generate the page */
10219 mg_exec_duktape_script(conn
, path
);
10221 #if !defined(NO_CGI)
10222 } else if (match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
10223 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
10225 /* CGI scripts may support all HTTP methods */
10226 handle_cgi_request(conn
, path
);
10227 #endif /* !NO_CGI */
10228 } else if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
10229 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
10231 handle_ssi_file_request(conn
, path
, file
);
10232 #if !defined(NO_CACHING)
10233 } else if ((!conn
->in_error_handler
) && is_not_modified(conn
, file
)) {
10234 /* Send 304 "Not Modified" - this must not send any body data */
10235 send_http_error(conn
, 304, "%s", "");
10236 #endif /* !NO_CACHING */
10238 handle_static_file_request(conn
, path
, file
, NULL
);
10244 close_all_listening_sockets(struct mg_context
*ctx
)
10251 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
10252 closesocket(ctx
->listening_sockets
[i
].sock
);
10253 ctx
->listening_sockets
[i
].sock
= INVALID_SOCKET
;
10255 mg_free(ctx
->listening_sockets
);
10256 ctx
->listening_sockets
= NULL
;
10257 mg_free(ctx
->listening_ports
);
10258 ctx
->listening_ports
= NULL
;
10262 /* Valid listening port specification is: [ip_address:]port[s]
10263 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
10264 * Examples for IPv6: [::]:80, [::1]:80,
10265 * [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443s
10266 * see https://tools.ietf.org/html/rfc3513#section-2.2 */
10268 parse_port_string(const struct vec
*vec
, struct socket
*so
)
10270 unsigned int a
, b
, c
, d
, port
;
10272 #if defined(USE_IPV6)
10273 char buf
[100] = {0};
10276 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
10277 * Also, all-zeroes in the socket address means binding to all addresses
10278 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
10279 memset(so
, 0, sizeof(*so
));
10280 so
->lsa
.sin
.sin_family
= AF_INET
;
10282 if (sscanf(vec
->ptr
, "%u.%u.%u.%u:%u%n", &a
, &b
, &c
, &d
, &port
, &len
)
10284 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
10285 so
->lsa
.sin
.sin_addr
.s_addr
=
10286 htonl((a
<< 24) | (b
<< 16) | (c
<< 8) | d
);
10287 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10288 #if defined(USE_IPV6)
10289 } else if (sscanf(vec
->ptr
, "[%49[^]]]:%u%n", buf
, &port
, &len
) == 2
10291 AF_INET6
, buf
, &so
->lsa
.sin6
, sizeof(so
->lsa
.sin6
))) {
10292 /* IPv6 address, examples: see above */
10293 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
10295 so
->lsa
.sin6
.sin6_port
= htons((uint16_t)port
);
10297 } else if (sscanf(vec
->ptr
, "%u%n", &port
, &len
) == 1) {
10298 /* If only port is specified, bind to IPv4, INADDR_ANY */
10299 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10301 /* Parsing failure. Make port invalid. */
10306 /* sscanf and the option splitting code ensure the following condition
10308 if ((len
< 0) && ((unsigned)len
> (unsigned)vec
->len
)) {
10311 ch
= vec
->ptr
[len
]; /* Next character after the port number */
10312 so
->is_ssl
= (ch
== 's');
10313 so
->ssl_redir
= (ch
== 'r');
10315 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
10316 return is_valid_port(port
)
10317 && (ch
== '\0' || ch
== 's' || ch
== 'r' || ch
== ',');
10322 set_ports_option(struct mg_context
*ctx
)
10326 #if defined(USE_IPV6)
10330 struct socket so
, *ptr
;
10332 in_port_t
*portPtr
;
10336 int portsTotal
= 0;
10343 memset(&so
, 0, sizeof(so
));
10344 memset(&usa
, 0, sizeof(usa
));
10346 list
= ctx
->config
[LISTENING_PORTS
];
10347 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10351 if (!parse_port_string(&vec
, &so
)) {
10353 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
10357 "[IP_ADDRESS:]PORT[s|r]");
10361 if (so
.is_ssl
&& ctx
->ssl_ctx
== NULL
) {
10364 "Cannot add SSL socket (entry %i). Is -ssl_certificate "
10370 if ((so
.sock
= socket(so
.lsa
.sa
.sa_family
, SOCK_STREAM
, 6))
10371 == INVALID_SOCKET
) {
10373 mg_cry(fc(ctx
), "cannot create socket (entry %i)", portsTotal
);
10378 /* Windows SO_REUSEADDR lets many procs binds to a
10379 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
10380 * if someone already has the socket -- DTL */
10381 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
10382 * Windows might need a few seconds before
10383 * the same port can be used again in the
10384 * same process, so a short Sleep may be
10385 * required between mg_stop and mg_start.
10387 if (setsockopt(so
.sock
,
10389 SO_EXCLUSIVEADDRUSE
,
10390 (SOCK_OPT_TYPE
)&on
,
10391 sizeof(on
)) != 0) {
10394 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
10398 if (setsockopt(so
.sock
,
10401 (SOCK_OPT_TYPE
)&on
,
10402 sizeof(on
)) != 0) {
10405 "cannot set socket option SO_REUSEADDR (entry %i)",
10410 #if defined(USE_IPV6)
10411 if (so
.lsa
.sa
.sa_family
== AF_INET6
10412 && setsockopt(so
.sock
,
10416 sizeof(off
)) != 0) {
10419 "cannot set socket option IPV6_V6ONLY (entry %i)",
10424 if (so
.lsa
.sa
.sa_family
== AF_INET
) {
10426 len
= sizeof(so
.lsa
.sin
);
10427 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10429 "cannot bind to %.*s: %d (%s)",
10434 closesocket(so
.sock
);
10435 so
.sock
= INVALID_SOCKET
;
10439 #if defined(USE_IPV6)
10440 else if (so
.lsa
.sa
.sa_family
== AF_INET6
) {
10442 len
= sizeof(so
.lsa
.sin6
);
10443 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10445 "cannot bind to IPv6 %.*s: %d (%s)",
10450 closesocket(so
.sock
);
10451 so
.sock
= INVALID_SOCKET
;
10458 "cannot bind: address family not supported (entry %i)",
10463 if (listen(so
.sock
, SOMAXCONN
) != 0) {
10466 "cannot listen to %.*s: %d (%s)",
10471 closesocket(so
.sock
);
10472 so
.sock
= INVALID_SOCKET
;
10476 if (getsockname(so
.sock
, &(usa
.sa
), &len
) != 0) {
10478 int err
= (int)ERRNO
;
10480 "call to getsockname failed %.*s: %d (%s)",
10485 closesocket(so
.sock
);
10486 so
.sock
= INVALID_SOCKET
;
10490 if ((ptr
= (struct socket
*)
10491 mg_realloc(ctx
->listening_sockets
,
10492 (ctx
->num_listening_sockets
+ 1)
10493 * sizeof(ctx
->listening_sockets
[0]))) == NULL
) {
10495 mg_cry(fc(ctx
), "%s", "Out of memory");
10496 closesocket(so
.sock
);
10497 so
.sock
= INVALID_SOCKET
;
10502 (in_port_t
*)mg_realloc(ctx
->listening_ports
,
10503 (ctx
->num_listening_sockets
+ 1)
10504 * sizeof(ctx
->listening_ports
[0])))
10507 mg_cry(fc(ctx
), "%s", "Out of memory");
10508 closesocket(so
.sock
);
10509 so
.sock
= INVALID_SOCKET
;
10514 set_close_on_exec(so
.sock
, fc(ctx
));
10515 ctx
->listening_sockets
= ptr
;
10516 ctx
->listening_sockets
[ctx
->num_listening_sockets
] = so
;
10517 ctx
->listening_ports
= portPtr
;
10518 ctx
->listening_ports
[ctx
->num_listening_sockets
] =
10519 ntohs(usa
.sin
.sin_port
);
10520 ctx
->num_listening_sockets
++;
10524 if (portsOk
!= portsTotal
) {
10525 close_all_listening_sockets(ctx
);
10533 static const char *
10534 header_val(const struct mg_connection
*conn
, const char *header
)
10536 const char *header_value
;
10538 if ((header_value
= mg_get_header(conn
, header
)) == NULL
) {
10541 return header_value
;
10547 log_access(const struct mg_connection
*conn
)
10549 const struct mg_request_info
*ri
;
10551 char date
[64], src_addr
[IP_ADDR_STR_LEN
];
10554 const char *referer
;
10555 const char *user_agent
;
10559 if (!conn
|| !conn
->ctx
) {
10563 if (conn
->ctx
->config
[ACCESS_LOG_FILE
] != NULL
) {
10564 if (mg_fopen(conn
, conn
->ctx
->config
[ACCESS_LOG_FILE
], "a+", &fi
)
10572 if (fi
.fp
== NULL
&& conn
->ctx
->callbacks
.log_message
== NULL
) {
10576 tm
= localtime(&conn
->conn_birth_time
);
10578 strftime(date
, sizeof(date
), "%d/%b/%Y:%H:%M:%S %z", tm
);
10580 mg_strlcpy(date
, "01/Jan/1970:00:00:00 +0000", sizeof(date
));
10581 date
[sizeof(date
) - 1] = '\0';
10584 ri
= &conn
->request_info
;
10586 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
10587 referer
= header_val(conn
, "Referer");
10588 user_agent
= header_val(conn
, "User-Agent");
10591 NULL
, /* Ignore truncation in access log */
10594 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT
" %s %s",
10596 ri
->remote_user
== NULL
? "-" : ri
->remote_user
,
10598 ri
->request_method
? ri
->request_method
: "-",
10599 ri
->request_uri
? ri
->request_uri
: "-",
10600 ri
->query_string
? "?" : "",
10601 ri
->query_string
? ri
->query_string
: "",
10604 conn
->num_bytes_sent
,
10608 if (conn
->ctx
->callbacks
.log_access
) {
10609 conn
->ctx
->callbacks
.log_access(conn
, buf
);
10614 fprintf(fi
.fp
, "%s\n", buf
);
10616 funlockfile(fi
.fp
);
10622 /* Verify given socket address against the ACL.
10623 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
10626 check_acl(struct mg_context
*ctx
, uint32_t remote_ip
)
10629 uint32_t net
, mask
;
10633 const char *list
= ctx
->config
[ACCESS_CONTROL_LIST
];
10635 /* If any ACL is set, deny by default */
10636 allowed
= list
== NULL
? '+' : '-';
10638 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10640 if ((flag
!= '+' && flag
!= '-')
10641 || parse_net(&vec
.ptr
[1], &net
, &mask
) == 0) {
10643 "%s: subnet must be [+|-]x.x.x.x[/x]",
10648 if (net
== (remote_ip
& mask
)) {
10653 return allowed
== '+';
10659 #if !defined(_WIN32)
10661 set_uid_option(struct mg_context
*ctx
)
10665 const char *uid
= ctx
->config
[RUN_AS_USER
];
10671 if ((pw
= getpwnam(uid
)) == NULL
) {
10672 mg_cry(fc(ctx
), "%s: unknown user [%s]", __func__
, uid
);
10673 } else if (setgid(pw
->pw_gid
) == -1) {
10675 "%s: setgid(%s): %s",
10679 } else if (setgroups(0, NULL
)) {
10681 "%s: setgroups(): %s",
10684 } else if (setuid(pw
->pw_uid
) == -1) {
10686 "%s: setuid(%s): %s",
10699 #endif /* !_WIN32 */
10703 tls_dtor(void *key
)
10705 struct mg_workerTLS
*tls
= (struct mg_workerTLS
*)key
;
10706 /* key == pthread_getspecific(sTlsKey); */
10709 if (tls
->is_master
== 2) {
10710 tls
->is_master
= -3; /* Mark memory as dead */
10714 pthread_setspecific(sTlsKey
, NULL
);
10718 #if !defined(NO_SSL)
10720 /* Must be set if sizeof(pthread_t) > sizeof(unsigned long) */
10721 static unsigned long
10722 ssl_id_callback(void)
10725 return GetCurrentThreadId();
10729 #pragma clang diagnostic push
10730 #pragma clang diagnostic ignored "-Wunreachable-code"
10731 /* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
10732 * or not, so one of the two conditions will be unreachable by construction.
10733 * Unfortunately the C standard does not define a way to check this at
10734 * compile time, since the #if preprocessor conditions can not use the sizeof
10735 * operator as an argument. */
10738 if (sizeof(pthread_t
) > sizeof(unsigned long)) {
10739 /* This is the problematic case for CRYPTO_set_id_callback:
10740 * The OS pthread_t can not be cast to unsigned long. */
10741 struct mg_workerTLS
*tls
=
10742 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
10744 /* SSL called from an unknown thread: Create some thread index.
10746 tls
= (struct mg_workerTLS
*)mg_malloc(sizeof(struct mg_workerTLS
));
10747 tls
->is_master
= -2; /* -2 means "3rd party thread" */
10748 tls
->thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
10749 pthread_setspecific(sTlsKey
, tls
);
10751 return tls
->thread_idx
;
10753 /* pthread_t may be any data type, so a simple cast to unsigned long
10754 * can rise a warning/error, depending on the platform.
10755 * Here memcpy is used as an anything-to-anything cast. */
10756 unsigned long ret
= 0;
10757 pthread_t t
= pthread_self();
10758 memcpy(&ret
, &t
, sizeof(pthread_t
));
10763 #pragma clang diagnostic pop
10770 static int ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
);
10771 static const char *ssl_error(void);
10775 refresh_trust(struct mg_connection
*conn
)
10777 static int reload_lock
= 0;
10778 static long int data_check
= 0;
10780 struct stat cert_buf
;
10783 int should_verify_peer
;
10785 if ((pem
= conn
->ctx
->config
[SSL_CERTIFICATE
]) == NULL
10786 && conn
->ctx
->callbacks
.init_ssl
== NULL
) {
10791 if (stat(pem
, &cert_buf
) != -1) {
10792 t
= (long int)cert_buf
.st_mtime
;
10795 if (data_check
!= t
) {
10798 should_verify_peer
=
10799 (conn
->ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
10800 && (mg_strcasecmp(conn
->ctx
->config
[SSL_DO_VERIFY_PEER
], "yes")
10803 if (should_verify_peer
) {
10804 char *ca_path
= conn
->ctx
->config
[SSL_CA_PATH
];
10805 char *ca_file
= conn
->ctx
->config
[SSL_CA_FILE
];
10806 if (SSL_CTX_load_verify_locations(conn
->ctx
->ssl_ctx
,
10809 mg_cry(fc(conn
->ctx
),
10810 "SSL_CTX_load_verify_locations error: %s "
10811 "ssl_verify_peer requires setting "
10812 "either ssl_ca_path or ssl_ca_file. Is any of them "
10820 if (!reload_lock
) {
10822 if (ssl_use_pem_file(conn
->ctx
, pem
) == 0) {
10828 /* lock while cert is reloading */
10829 while (reload_lock
) {
10837 static pthread_mutex_t
*ssl_mutexes
;
10841 sslize(struct mg_connection
*conn
, SSL_CTX
*s
, int (*func
)(SSL
*))
10851 (conn
->ctx
->config
[SSL_SHORT_TRUST
] != NULL
)
10852 && (mg_strcasecmp(conn
->ctx
->config
[SSL_SHORT_TRUST
], "yes") == 0);
10855 int trust_ret
= refresh_trust(conn
);
10861 conn
->ssl
= SSL_new(s
);
10862 if (conn
->ssl
== NULL
) {
10866 ret
= SSL_set_fd(conn
->ssl
, conn
->client
.sock
);
10868 err
= SSL_get_error(conn
->ssl
, ret
);
10869 (void)err
; /* TODO: set some error message */
10870 SSL_free(conn
->ssl
);
10872 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10874 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10875 ERR_remove_state(0);
10879 ret
= func(conn
->ssl
);
10881 err
= SSL_get_error(conn
->ssl
, ret
);
10882 (void)err
; /* TODO: set some error message */
10883 SSL_free(conn
->ssl
);
10885 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10887 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10888 ERR_remove_state(0);
10896 /* Return OpenSSL error message (from CRYPTO lib) */
10897 static const char *
10901 err
= ERR_get_error();
10902 return err
== 0 ? "" : ERR_error_string(err
, NULL
);
10907 ssl_locking_callback(int mode
, int mutex_num
, const char *file
, int line
)
10913 /* 1 is CRYPTO_LOCK */
10914 (void)pthread_mutex_lock(&ssl_mutexes
[mutex_num
]);
10916 (void)pthread_mutex_unlock(&ssl_mutexes
[mutex_num
]);
10921 #if !defined(NO_SSL_DL)
10923 load_dll(struct mg_context
*ctx
, const char *dll_name
, struct ssl_func
*sw
)
10930 struct ssl_func
*fp
;
10932 if ((dll_handle
= dlopen(dll_name
, RTLD_LAZY
)) == NULL
) {
10933 mg_cry(fc(ctx
), "%s: cannot load %s", __func__
, dll_name
);
10937 for (fp
= sw
; fp
->name
!= NULL
; fp
++) {
10939 /* GetProcAddress() returns pointer to function */
10940 u
.fp
= (void (*)(void))dlsym(dll_handle
, fp
->name
);
10942 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
10943 * pointers to function pointers. We need to use a union to make a
10945 u
.p
= dlsym(dll_handle
, fp
->name
);
10946 #endif /* _WIN32 */
10947 if (u
.fp
== NULL
) {
10949 "%s: %s: cannot find %s",
10953 dlclose(dll_handle
);
10964 static void *ssllib_dll_handle
; /* Store the ssl library handle. */
10965 static void *cryptolib_dll_handle
; /* Store the crypto library handle. */
10967 #endif /* NO_SSL_DL */
10970 #if defined(SSL_ALREADY_INITIALIZED)
10971 static int cryptolib_users
= 1; /* Reference counter for crypto library. */
10973 static int cryptolib_users
= 0; /* Reference counter for crypto library. */
10978 initialize_ssl(struct mg_context
*ctx
)
10983 #if !defined(NO_SSL_DL)
10984 if (!cryptolib_dll_handle
) {
10985 cryptolib_dll_handle
= load_dll(ctx
, CRYPTO_LIB
, crypto_sw
);
10986 if (!cryptolib_dll_handle
) {
10990 #endif /* NO_SSL_DL */
10992 if (mg_atomic_inc(&cryptolib_users
) > 1) {
10996 /* Initialize locking callbacks, needed for thread safety.
10997 * http://www.openssl.org/support/faq.html#PROG1
10999 i
= CRYPTO_num_locks();
11003 size
= sizeof(pthread_mutex_t
) * ((size_t)(i
));
11004 if ((ssl_mutexes
= (pthread_mutex_t
*)mg_malloc(size
)) == NULL
) {
11006 "%s: cannot allocate mutexes: %s",
11012 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11013 pthread_mutex_init(&ssl_mutexes
[i
], &pthread_mutex_attr
);
11016 CRYPTO_set_locking_callback(&ssl_locking_callback
);
11017 CRYPTO_set_id_callback(&ssl_id_callback
);
11024 ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
)
11026 if (SSL_CTX_use_certificate_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11028 "%s: cannot open certificate file %s: %s",
11035 /* could use SSL_CTX_set_default_passwd_cb_userdata */
11036 if (SSL_CTX_use_PrivateKey_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11038 "%s: cannot open private key file %s: %s",
11045 if (SSL_CTX_check_private_key(ctx
->ssl_ctx
) == 0) {
11047 "%s: certificate and private key do not match: %s",
11053 if (SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
) == 0) {
11055 "%s: cannot use certificate chain file %s: %s",
11066 ssl_get_protocol(int version_id
)
11068 long ret
= SSL_OP_ALL
;
11069 if (version_id
> 0)
11070 ret
|= SSL_OP_NO_SSLv2
;
11071 if (version_id
> 1)
11072 ret
|= SSL_OP_NO_SSLv3
;
11073 if (version_id
> 2)
11074 ret
|= SSL_OP_NO_TLSv1
;
11075 if (version_id
> 3)
11076 ret
|= SSL_OP_NO_TLSv1_1
;
11081 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
11083 set_ssl_option(struct mg_context
*ctx
)
11087 int should_verify_peer
;
11088 const char *ca_path
;
11089 const char *ca_file
;
11090 int use_default_verify_paths
;
11092 time_t now_rt
= time(NULL
);
11093 struct timespec now_mt
;
11094 md5_byte_t ssl_context_id
[16];
11095 md5_state_t md5state
;
11098 /* If PEM file is not specified and the init_ssl callback
11099 * is not specified, skip SSL initialization. */
11103 if ((pem
= ctx
->config
[SSL_CERTIFICATE
]) == NULL
11104 && ctx
->callbacks
.init_ssl
== NULL
) {
11108 if (!initialize_ssl(ctx
)) {
11112 #if !defined(NO_SSL_DL)
11113 if (!ssllib_dll_handle
) {
11114 ssllib_dll_handle
= load_dll(ctx
, SSL_LIB
, ssl_sw
);
11115 if (!ssllib_dll_handle
) {
11119 #endif /* NO_SSL_DL */
11121 /* Initialize SSL library */
11122 SSL_library_init();
11123 SSL_load_error_strings();
11125 if ((ctx
->ssl_ctx
= SSL_CTX_new(SSLv23_server_method())) == NULL
) {
11126 mg_cry(fc(ctx
), "SSL_CTX_new (server) error: %s", ssl_error());
11130 SSL_CTX_clear_options(ctx
->ssl_ctx
,
11131 SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
| SSL_OP_NO_TLSv1
11132 | SSL_OP_NO_TLSv1_1
);
11133 protocol_ver
= atoi(ctx
->config
[SSL_PROTOCOL_VERSION
]);
11134 SSL_CTX_set_options(ctx
->ssl_ctx
, ssl_get_protocol(protocol_ver
));
11135 SSL_CTX_set_options(ctx
->ssl_ctx
, SSL_OP_SINGLE_DH_USE
);
11136 SSL_CTX_set_ecdh_auto(ctx
->ssl_ctx
, 1);
11138 /* If a callback has been specified, call it. */
11140 (ctx
->callbacks
.init_ssl
== NULL
)
11142 : (ctx
->callbacks
.init_ssl(ctx
->ssl_ctx
, ctx
->user_data
));
11144 /* If callback returns 0, civetweb sets up the SSL certificate.
11145 * If it returns 1, civetweb assumes the calback already did this.
11146 * If it returns -1, initializing ssl fails. */
11147 if (callback_ret
< 0) {
11148 mg_cry(fc(ctx
), "SSL callback returned error: %i", callback_ret
);
11151 if (callback_ret
> 0) {
11153 (void)SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
);
11158 /* Use some UID as session context ID. */
11159 md5_init(&md5state
);
11160 md5_append(&md5state
, (const md5_byte_t
*)&now_rt
, sizeof(now_rt
));
11161 clock_gettime(CLOCK_MONOTONIC
, &now_mt
);
11162 md5_append(&md5state
, (const md5_byte_t
*)&now_mt
, sizeof(now_mt
));
11163 md5_append(&md5state
,
11164 (const md5_byte_t
*)ctx
->config
[LISTENING_PORTS
],
11165 strlen(ctx
->config
[LISTENING_PORTS
]));
11166 md5_append(&md5state
, (const md5_byte_t
*)ctx
, sizeof(*ctx
));
11167 md5_finish(&md5state
, ssl_context_id
);
11169 SSL_CTX_set_session_id_context(ctx
->ssl_ctx
,
11170 (const unsigned char *)&ssl_context_id
,
11171 sizeof(ssl_context_id
));
11174 if (!ssl_use_pem_file(ctx
, pem
)) {
11179 should_verify_peer
=
11180 (ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
11181 && (mg_strcasecmp(ctx
->config
[SSL_DO_VERIFY_PEER
], "yes") == 0);
11183 use_default_verify_paths
=
11184 (ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
] != NULL
)
11185 && (mg_strcasecmp(ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
], "yes") == 0);
11187 if (should_verify_peer
) {
11188 ca_path
= ctx
->config
[SSL_CA_PATH
];
11189 ca_file
= ctx
->config
[SSL_CA_FILE
];
11190 if (SSL_CTX_load_verify_locations(ctx
->ssl_ctx
, ca_file
, ca_path
)
11193 "SSL_CTX_load_verify_locations error: %s "
11194 "ssl_verify_peer requires setting "
11195 "either ssl_ca_path or ssl_ca_file. Is any of them "
11202 SSL_CTX_set_verify(ctx
->ssl_ctx
,
11203 SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
,
11206 if (use_default_verify_paths
11207 && SSL_CTX_set_default_verify_paths(ctx
->ssl_ctx
) != 1) {
11209 "SSL_CTX_set_default_verify_paths error: %s",
11214 if (ctx
->config
[SSL_VERIFY_DEPTH
]) {
11215 verify_depth
= atoi(ctx
->config
[SSL_VERIFY_DEPTH
]);
11216 SSL_CTX_set_verify_depth(ctx
->ssl_ctx
, verify_depth
);
11220 if (ctx
->config
[SSL_CIPHER_LIST
] != NULL
) {
11221 if (SSL_CTX_set_cipher_list(ctx
->ssl_ctx
, ctx
->config
[SSL_CIPHER_LIST
])
11223 mg_cry(fc(ctx
), "SSL_CTX_set_cipher_list error: %s", ssl_error());
11232 uninitialize_ssl(struct mg_context
*ctx
)
11237 if (mg_atomic_dec(&cryptolib_users
) == 0) {
11239 /* Shutdown according to
11240 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
11241 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
11243 CRYPTO_set_locking_callback(NULL
);
11244 CRYPTO_set_id_callback(NULL
);
11246 CONF_modules_unload(1);
11247 ERR_free_strings();
11249 CRYPTO_cleanup_all_ex_data();
11250 ERR_remove_state(0);
11252 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11253 pthread_mutex_destroy(&ssl_mutexes
[i
]);
11255 mg_free(ssl_mutexes
);
11256 ssl_mutexes
= NULL
;
11259 #endif /* !NO_SSL */
11263 set_gpass_option(struct mg_context
*ctx
)
11266 struct file file
= STRUCT_FILE_INITIALIZER
;
11267 const char *path
= ctx
->config
[GLOBAL_PASSWORDS_FILE
];
11268 if (path
!= NULL
&& !mg_stat(fc(ctx
), path
, &file
)) {
11269 mg_cry(fc(ctx
), "Cannot open %s: %s", path
, strerror(ERRNO
));
11279 set_acl_option(struct mg_context
*ctx
)
11281 return check_acl(ctx
, (uint32_t)0x7f000001UL
) != -1;
11286 reset_per_request_attributes(struct mg_connection
*conn
)
11291 conn
->path_info
= NULL
;
11292 conn
->num_bytes_sent
= conn
->consumed_content
= 0;
11293 conn
->status_code
= -1;
11294 conn
->is_chunked
= 0;
11295 conn
->must_close
= conn
->request_len
= conn
->throttle
= 0;
11296 conn
->request_info
.content_length
= -1;
11297 conn
->request_info
.remote_user
= NULL
;
11298 conn
->request_info
.request_method
= NULL
;
11299 conn
->request_info
.request_uri
= NULL
;
11300 conn
->request_info
.local_uri
= NULL
;
11301 conn
->request_info
.uri
= NULL
; /* TODO: cleanup uri,
11302 * local_uri and request_uri */
11303 conn
->request_info
.http_version
= NULL
;
11304 conn
->request_info
.num_headers
= 0;
11305 conn
->data_len
= 0;
11306 conn
->chunk_remainder
= 0;
11307 conn
->internal_error
= 0;
11312 set_sock_timeout(SOCKET sock
, int milliseconds
)
11314 int r0
= 0, r1
, r2
;
11317 /* Windows specific */
11319 DWORD tv
= (DWORD
)milliseconds
;
11322 /* Linux, ... (not Windows) */
11326 /* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
11327 * max. time waiting for the acknowledged of TCP data before the connection
11328 * will be forcefully closed and ETIMEDOUT is returned to the application.
11329 * If this option is not set, the default timeout of 20-30 minutes is used.
11331 /* #define TCP_USER_TIMEOUT (18) */
11333 #if defined(TCP_USER_TIMEOUT)
11334 unsigned int uto
= (unsigned int)milliseconds
;
11335 r0
= setsockopt(sock
, 6, TCP_USER_TIMEOUT
, (const void *)&uto
, sizeof(uto
));
11338 memset(&tv
, 0, sizeof(tv
));
11339 tv
.tv_sec
= milliseconds
/ 1000;
11340 tv
.tv_usec
= (milliseconds
* 1000) % 1000000;
11342 #endif /* _WIN32 */
11345 sock
, SOL_SOCKET
, SO_RCVTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11347 sock
, SOL_SOCKET
, SO_SNDTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11349 return r0
|| r1
|| r2
;
11354 set_tcp_nodelay(SOCKET sock
, int nodelay_on
)
11356 if (setsockopt(sock
,
11359 (SOCK_OPT_TYPE
)&nodelay_on
,
11360 sizeof(nodelay_on
)) != 0) {
11370 close_socket_gracefully(struct mg_connection
*conn
)
11372 #if defined(_WIN32)
11373 char buf
[MG_BUF_LEN
];
11376 struct linger linger
;
11382 /* Set linger option to avoid socket hanging out after close. This
11384 * ephemeral port exhaust problem under high QPS. */
11385 linger
.l_onoff
= 1;
11386 linger
.l_linger
= 1;
11388 if (setsockopt(conn
->client
.sock
,
11392 sizeof(linger
)) != 0) {
11394 "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
11399 /* Send FIN to the client */
11400 shutdown(conn
->client
.sock
, SHUT_WR
);
11401 set_non_blocking_mode(conn
->client
.sock
);
11403 #if defined(_WIN32)
11404 /* Read and discard pending incoming data. If we do not do that and
11406 * the socket, the data in the send buffer may be discarded. This
11407 * behaviour is seen on Windows, when client keeps sending data
11408 * when server decides to close the connection; then when client
11409 * does recv() it gets no data back. */
11412 NULL
, conn
, buf
, sizeof(buf
), 1E-10 /* TODO: allow 0 as timeout */);
11416 /* Now we know that our FIN is ACK-ed, safe to close */
11417 closesocket(conn
->client
.sock
);
11418 conn
->client
.sock
= INVALID_SOCKET
;
11423 close_connection(struct mg_connection
*conn
)
11425 if (!conn
|| !conn
->ctx
) {
11429 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
11430 if (conn
->lua_websocket_state
) {
11431 lua_websocket_close(conn
, conn
->lua_websocket_state
);
11432 conn
->lua_websocket_state
= NULL
;
11436 /* call the connection_close callback if assigned */
11437 if ((conn
->ctx
->callbacks
.connection_close
!= NULL
)
11438 && (conn
->ctx
->context_type
== 1)) {
11439 conn
->ctx
->callbacks
.connection_close(conn
);
11442 mg_lock_connection(conn
);
11444 conn
->must_close
= 1;
11447 if (conn
->ssl
!= NULL
) {
11448 /* Run SSL_shutdown twice to ensure completly close SSL connection
11450 SSL_shutdown(conn
->ssl
);
11451 SSL_free(conn
->ssl
);
11452 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
11454 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
11455 ERR_remove_state(0);
11459 if (conn
->client
.sock
!= INVALID_SOCKET
) {
11460 close_socket_gracefully(conn
);
11461 conn
->client
.sock
= INVALID_SOCKET
;
11464 mg_unlock_connection(conn
);
11468 mg_close_connection(struct mg_connection
*conn
)
11470 struct mg_context
*client_ctx
= NULL
;
11473 if (conn
== NULL
) {
11477 if (conn
->ctx
->context_type
== 2) {
11478 client_ctx
= conn
->ctx
;
11479 /* client context: loops must end */
11480 conn
->ctx
->stop_flag
= 1;
11484 if (conn
->client_ssl_ctx
!= NULL
) {
11485 SSL_CTX_free((SSL_CTX
*)conn
->client_ssl_ctx
);
11488 close_connection(conn
);
11489 if (client_ctx
!= NULL
) {
11490 /* join worker thread and free context */
11491 for (i
= 0; i
< client_ctx
->cfg_worker_threads
; i
++) {
11492 if (client_ctx
->workerthreadids
[i
] != 0) {
11493 mg_join_thread(client_ctx
->workerthreadids
[i
]);
11496 mg_free(client_ctx
->workerthreadids
);
11497 mg_free(client_ctx
);
11498 (void)pthread_mutex_destroy(&conn
->mutex
);
11504 static struct mg_connection
*
11505 mg_connect_client_impl(const struct mg_client_options
*client_options
,
11510 static struct mg_context fake_ctx
;
11511 struct mg_connection
*conn
= NULL
;
11515 if (!connect_socket(&fake_ctx
,
11516 client_options
->host
,
11517 client_options
->port
,
11524 } else if ((conn
= (struct mg_connection
*)
11525 mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
)) == NULL
) {
11527 NULL
, /* No truncation check for ebuf */
11535 && (conn
->client_ssl_ctx
= SSL_CTX_new(SSLv23_client_method()))
11538 NULL
, /* No truncation check for ebuf */
11541 "SSL_CTX_new error");
11545 #endif /* NO_SSL */
11550 socklen_t len
= (sa
.sa
.sa_family
== AF_INET
)
11551 ? sizeof(conn
->client
.rsa
.sin
)
11552 : sizeof(conn
->client
.rsa
.sin6
);
11553 struct sockaddr
*psa
=
11554 (sa
.sa
.sa_family
== AF_INET
)
11555 ? (struct sockaddr
*)&(conn
->client
.rsa
.sin
)
11556 : (struct sockaddr
*)&(conn
->client
.rsa
.sin6
);
11558 socklen_t len
= sizeof(conn
->client
.rsa
.sin
);
11559 struct sockaddr
*psa
= (struct sockaddr
*)&(conn
->client
.rsa
.sin
);
11562 conn
->buf_size
= MAX_REQUEST_SIZE
;
11563 conn
->buf
= (char *)(conn
+ 1);
11564 conn
->ctx
= &fake_ctx
;
11565 conn
->client
.sock
= sock
;
11566 conn
->client
.lsa
= sa
;
11568 if (getsockname(sock
, psa
, &len
) != 0) {
11570 "%s: getsockname() failed: %s",
11575 conn
->client
.is_ssl
= use_ssl
? 1 : 0;
11576 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
11580 fake_ctx
.ssl_ctx
= conn
->client_ssl_ctx
;
11582 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
11583 * SSL_CTX_set_verify call is needed to switch off server
11584 * certificate checking, which is off by default in OpenSSL and
11586 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
11587 * SSL_VERIFY_PEER, verify_ssl_server); */
11589 if (client_options
->client_cert
) {
11590 if (!ssl_use_pem_file(&fake_ctx
, client_options
->client_cert
)) {
11592 NULL
, /* No truncation check for ebuf */
11595 "Can not use SSL client certificate");
11596 SSL_CTX_free(conn
->client_ssl_ctx
);
11603 if (client_options
->server_cert
) {
11604 SSL_CTX_load_verify_locations(conn
->client_ssl_ctx
,
11605 client_options
->server_cert
,
11607 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_PEER
, NULL
);
11609 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
11612 if (!sslize(conn
, conn
->client_ssl_ctx
, SSL_connect
)) {
11614 NULL
, /* No truncation check for ebuf */
11617 "SSL connection error");
11618 SSL_CTX_free(conn
->client_ssl_ctx
);
11631 CIVETWEB_API
struct mg_connection
*
11632 mg_connect_client_secure(const struct mg_client_options
*client_options
,
11633 char *error_buffer
,
11634 size_t error_buffer_size
)
11636 return mg_connect_client_impl(client_options
,
11639 error_buffer_size
);
11643 struct mg_connection
*
11644 mg_connect_client(const char *host
,
11647 char *error_buffer
,
11648 size_t error_buffer_size
)
11650 struct mg_client_options opts
;
11651 memset(&opts
, 0, sizeof(opts
));
11654 return mg_connect_client_impl(&opts
,
11657 error_buffer_size
);
11661 static const struct {
11664 unsigned default_port
;
11665 } abs_uri_protocols
[] = {{"http://", 7, 80},
11666 {"https://", 8, 443},
11668 {"wss://", 6, 443},
11672 /* Check if the uri is valid.
11673 * return 0 for invalid uri,
11675 * return 2 for relative uri,
11676 * return 3 for absolute uri without port,
11677 * return 4 for absolute uri with port */
11679 get_uri_type(const char *uri
)
11682 char *hostend
, *portbegin
, *portend
;
11683 unsigned long port
;
11685 /* According to the HTTP standard
11686 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
11687 * URI can be an asterisk (*) or should start with slash (relative uri),
11688 * or it should start with the protocol (absolute uri). */
11689 if (uri
[0] == '*' && uri
[1] == '\0') {
11693 if (uri
[0] == '/') {
11698 /* It could be an absolute uri: */
11699 /* This function only checks if the uri is valid, not if it is
11700 * addressing the current server. So civetweb can also be used
11701 * as a proxy server. */
11702 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11703 if (mg_strncasecmp(uri
,
11704 abs_uri_protocols
[i
].proto
,
11705 abs_uri_protocols
[i
].proto_len
) == 0) {
11707 hostend
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, '/');
11711 portbegin
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, ':');
11716 port
= strtoul(portbegin
+ 1, &portend
, 10);
11717 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11729 /* Return NULL or the relative uri at the current server */
11730 static const char *
11731 get_rel_url_at_current_server(const char *uri
, const struct mg_connection
*conn
)
11733 const char *server_domain
;
11734 size_t server_domain_len
;
11735 size_t request_domain_len
= 0;
11736 unsigned long port
= 0;
11738 const char *hostbegin
= NULL
;
11739 const char *hostend
= NULL
;
11740 const char *portbegin
;
11743 /* DNS is case insensitive, so use case insensitive string compare here
11745 server_domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
11746 if (!server_domain
) {
11749 server_domain_len
= strlen(server_domain
);
11750 if (!server_domain_len
) {
11754 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11755 if (mg_strncasecmp(uri
,
11756 abs_uri_protocols
[i
].proto
,
11757 abs_uri_protocols
[i
].proto_len
) == 0) {
11759 hostbegin
= uri
+ abs_uri_protocols
[i
].proto_len
;
11760 hostend
= strchr(hostbegin
, '/');
11764 portbegin
= strchr(hostbegin
, ':');
11765 if ((!portbegin
) || (portbegin
> hostend
)) {
11766 port
= abs_uri_protocols
[i
].default_port
;
11767 request_domain_len
= (size_t)(hostend
- hostbegin
);
11769 port
= strtoul(portbegin
+ 1, &portend
, 10);
11770 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11773 request_domain_len
= (size_t)(portbegin
- hostbegin
);
11775 /* protocol found, port set */
11781 /* port remains 0 if the protocol is not found */
11785 #if defined(USE_IPV6)
11786 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
11787 if (ntohs(conn
->client
.lsa
.sin6
.sin6_port
) != port
) {
11788 /* Request is directed to a different port */
11794 if (ntohs(conn
->client
.lsa
.sin
.sin_port
) != port
) {
11795 /* Request is directed to a different port */
11800 if ((request_domain_len
!= server_domain_len
)
11801 || (0 != memcmp(server_domain
, hostbegin
, server_domain_len
))) {
11802 /* Request is directed to another server */
11811 getreq(struct mg_connection
*conn
, char *ebuf
, size_t ebuf_len
, int *err
)
11815 if (ebuf_len
> 0) {
11820 reset_per_request_attributes(conn
);
11824 NULL
, /* No truncation check for ebuf */
11832 /* Set the time the request was received. This value should be used for
11834 clock_gettime(CLOCK_MONOTONIC
, &(conn
->req_time
));
11836 conn
->request_len
=
11837 read_request(NULL
, conn
, conn
->buf
, conn
->buf_size
, &conn
->data_len
);
11838 /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
11840 if (conn
->request_len
>= 0 && conn
->data_len
< conn
->request_len
) {
11842 NULL
, /* No truncation check for ebuf */
11846 "Invalid request size");
11851 if (conn
->request_len
== 0 && conn
->data_len
== conn
->buf_size
) {
11853 NULL
, /* No truncation check for ebuf */
11857 "Request Too Large");
11860 } else if (conn
->request_len
<= 0) {
11861 if (conn
->data_len
> 0) {
11863 NULL
, /* No truncation check for ebuf */
11867 "Client sent malformed request");
11870 /* Server did not send anything -> just close the connection */
11871 conn
->must_close
= 1;
11873 NULL
, /* No truncation check for ebuf */
11877 "Client did not send a request");
11881 } else if (parse_http_message(conn
->buf
,
11883 &conn
->request_info
) <= 0) {
11885 NULL
, /* No truncation check for ebuf */
11893 /* Message is a valid request or response */
11894 if ((cl
= get_header(&conn
->request_info
, "Content-Length")) != NULL
) {
11895 /* Request/response has content length set */
11896 char *endptr
= NULL
;
11897 conn
->content_len
= strtoll(cl
, &endptr
, 10);
11898 if (endptr
== cl
) {
11900 NULL
, /* No truncation check for ebuf */
11908 /* Publish the content length back to the request info. */
11909 conn
->request_info
.content_length
= conn
->content_len
;
11910 } else if ((cl
= get_header(&conn
->request_info
, "Transfer-Encoding"))
11912 && !mg_strcasecmp(cl
, "chunked")) {
11913 conn
->is_chunked
= 1;
11914 } else if (!mg_strcasecmp(conn
->request_info
.request_method
, "POST")
11915 || !mg_strcasecmp(conn
->request_info
.request_method
,
11917 /* POST or PUT request without content length set */
11918 conn
->content_len
= -1;
11919 } else if (!mg_strncasecmp(conn
->request_info
.request_method
,
11922 /* Response without content length set */
11923 conn
->content_len
= -1;
11925 /* Other request */
11926 conn
->content_len
= 0;
11934 mg_get_response(struct mg_connection
*conn
,
11940 /* Implementation of API function for HTTP clients */
11942 struct mg_context
*octx
= conn
->ctx
;
11943 struct mg_context rctx
= *(conn
->ctx
);
11944 char txt
[32]; /* will not overflow */
11946 if (timeout
>= 0) {
11947 mg_snprintf(conn
, NULL
, txt
, sizeof(txt
), "%i", timeout
);
11948 rctx
.config
[REQUEST_TIMEOUT
] = txt
;
11949 set_sock_timeout(conn
->client
.sock
, timeout
);
11951 rctx
.config
[REQUEST_TIMEOUT
] = NULL
;
11955 ret
= getreq(conn
, ebuf
, ebuf_len
, &err
);
11958 /* TODO: 1) uri is deprecated;
11959 * 2) here, ri.uri is the http response code */
11960 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
11962 /* TODO (mid): Define proper return values - maybe return length?
11963 * For the first test use <0 for error and >0 for OK */
11964 return (ret
== 0) ? -1 : +1;
11970 struct mg_connection
*
11971 mg_download(const char *host
,
11979 struct mg_connection
*conn
;
11987 /* open a connection */
11988 conn
= mg_connect_client(host
, port
, use_ssl
, ebuf
, ebuf_len
);
11990 if (conn
!= NULL
) {
11991 i
= mg_vprintf(conn
, fmt
, ap
);
11994 NULL
, /* No truncation check for ebuf */
11998 "Error sending request");
12000 getreq(conn
, ebuf
, ebuf_len
, &reqerr
);
12002 /* TODO: 1) uri is deprecated;
12003 * 2) here, ri.uri is the http response code */
12004 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
12008 /* if an error occured, close the connection */
12009 if (ebuf
[0] != '\0' && conn
!= NULL
) {
12010 mg_close_connection(conn
);
12019 struct websocket_client_thread_data
{
12020 struct mg_connection
*conn
;
12021 mg_websocket_data_handler data_handler
;
12022 mg_websocket_close_handler close_handler
;
12023 void *callback_data
;
12027 #if defined(USE_WEBSOCKET)
12029 static unsigned __stdcall
websocket_client_thread(void *data
)
12032 websocket_client_thread(void *data
)
12035 struct websocket_client_thread_data
*cdata
=
12036 (struct websocket_client_thread_data
*)data
;
12038 mg_set_thread_name("ws-client");
12040 if (cdata
->conn
->ctx
) {
12041 if (cdata
->conn
->ctx
->callbacks
.init_thread
) {
12042 /* 3 indicates a websocket client thread */
12043 /* TODO: check if conn->ctx can be set */
12044 cdata
->conn
->ctx
->callbacks
.init_thread(cdata
->conn
->ctx
, 3);
12048 read_websocket(cdata
->conn
, cdata
->data_handler
, cdata
->callback_data
);
12050 DEBUG_TRACE("%s", "Websocket client thread exited\n");
12052 if (cdata
->close_handler
!= NULL
) {
12053 cdata
->close_handler(cdata
->conn
, cdata
->callback_data
);
12056 mg_free((void *)cdata
);
12067 struct mg_connection
*
12068 mg_connect_websocket_client(const char *host
,
12071 char *error_buffer
,
12072 size_t error_buffer_size
,
12074 const char *origin
,
12075 mg_websocket_data_handler data_func
,
12076 mg_websocket_close_handler close_func
,
12079 struct mg_connection
*conn
= NULL
;
12081 #if defined(USE_WEBSOCKET)
12082 struct mg_context
*newctx
= NULL
;
12083 struct websocket_client_thread_data
*thread_data
;
12084 static const char *magic
= "x3JJHMbDL1EzLkh9GBhXDw==";
12085 static const char *handshake_req
;
12087 if (origin
!= NULL
) {
12088 handshake_req
= "GET %s HTTP/1.1\r\n"
12090 "Upgrade: websocket\r\n"
12091 "Connection: Upgrade\r\n"
12092 "Sec-WebSocket-Key: %s\r\n"
12093 "Sec-WebSocket-Version: 13\r\n"
12097 handshake_req
= "GET %s HTTP/1.1\r\n"
12099 "Upgrade: websocket\r\n"
12100 "Connection: Upgrade\r\n"
12101 "Sec-WebSocket-Key: %s\r\n"
12102 "Sec-WebSocket-Version: 13\r\n"
12106 /* Establish the client connection and request upgrade */
12107 conn
= mg_download(host
,
12118 /* Connection object will be null if something goes wrong */
12119 if (conn
== NULL
|| (strcmp(conn
->request_info
.request_uri
, "101") != 0)) {
12120 if (!*error_buffer
) {
12121 /* if there is a connection, but it did not return 101,
12122 * error_buffer is not yet set */
12124 NULL
, /* No truncation check for ebuf */
12127 "Unexpected server reply");
12129 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer
);
12130 if (conn
!= NULL
) {
12137 /* For client connections, mg_context is fake. Since we need to set a
12138 * callback function, we need to create a copy and modify it. */
12139 newctx
= (struct mg_context
*)mg_malloc(sizeof(struct mg_context
));
12140 memcpy(newctx
, conn
->ctx
, sizeof(struct mg_context
));
12141 newctx
->user_data
= user_data
;
12142 newctx
->context_type
= 2; /* client context type */
12143 newctx
->cfg_worker_threads
= 1; /* one worker thread will be created */
12144 newctx
->workerthreadids
=
12145 (pthread_t
*)mg_calloc(newctx
->cfg_worker_threads
, sizeof(pthread_t
));
12146 conn
->ctx
= newctx
;
12147 thread_data
= (struct websocket_client_thread_data
*)
12148 mg_calloc(sizeof(struct websocket_client_thread_data
), 1);
12149 thread_data
->conn
= conn
;
12150 thread_data
->data_handler
= data_func
;
12151 thread_data
->close_handler
= close_func
;
12152 thread_data
->callback_data
= NULL
;
12154 /* Start a thread to read the websocket client connection
12155 * This thread will automatically stop when mg_disconnect is
12156 * called on the client connection */
12157 if (mg_start_thread_with_id(websocket_client_thread
,
12158 (void *)thread_data
,
12159 newctx
->workerthreadids
) != 0) {
12160 mg_free((void *)thread_data
);
12161 mg_free((void *)newctx
->workerthreadids
);
12162 mg_free((void *)newctx
);
12163 mg_free((void *)conn
);
12166 "Websocket client connect thread could not be started\r\n");
12169 /* Appease "unused parameter" warnings */
12173 (void)error_buffer
;
12174 (void)error_buffer_size
;
12187 process_new_connection(struct mg_connection
*conn
)
12189 if (conn
&& conn
->ctx
) {
12190 struct mg_request_info
*ri
= &conn
->request_info
;
12191 int keep_alive_enabled
, keep_alive
, discard_len
;
12193 const char *hostend
;
12194 int reqerr
, uri_type
;
12196 keep_alive_enabled
=
12197 !strcmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes");
12199 /* Important: on new connection, reset the receiving buffer. Credit
12200 * goes to crule42. */
12201 conn
->data_len
= 0;
12203 if (!getreq(conn
, ebuf
, sizeof(ebuf
), &reqerr
)) {
12204 /* The request sent by the client could not be understood by
12205 * the server, or it was incomplete or a timeout. Send an
12206 * error message and close the connection. */
12208 /*assert(ebuf[0] != '\0');*/
12209 send_http_error(conn
, reqerr
, "%s", ebuf
);
12211 } else if (strcmp(ri
->http_version
, "1.0")
12212 && strcmp(ri
->http_version
, "1.1")) {
12214 NULL
, /* No truncation check for ebuf */
12217 "Bad HTTP version: [%s]",
12219 send_http_error(conn
, 505, "%s", ebuf
);
12222 if (ebuf
[0] == '\0') {
12223 uri_type
= get_uri_type(conn
->request_info
.request_uri
);
12224 switch (uri_type
) {
12227 conn
->request_info
.local_uri
= NULL
;
12231 conn
->request_info
.local_uri
=
12232 conn
->request_info
.request_uri
;
12236 /* absolute uri (with/without port) */
12237 hostend
= get_rel_url_at_current_server(
12238 conn
->request_info
.request_uri
, conn
);
12240 conn
->request_info
.local_uri
= hostend
;
12242 conn
->request_info
.local_uri
= NULL
;
12247 NULL
, /* No truncation check for ebuf */
12250 "Invalid URI: [%s]",
12252 send_http_error(conn
, 400, "%s", ebuf
);
12256 /* TODO: cleanup uri, local_uri and request_uri */
12257 conn
->request_info
.uri
= conn
->request_info
.local_uri
;
12260 if (ebuf
[0] == '\0') {
12261 if (conn
->request_info
.local_uri
) {
12262 /* handle request to local server */
12263 handle_request(conn
);
12264 if (conn
->ctx
->callbacks
.end_request
!= NULL
) {
12265 conn
->ctx
->callbacks
.end_request(conn
,
12266 conn
->status_code
);
12270 /* TODO: handle non-local request (PROXY) */
12271 conn
->must_close
= 1;
12274 conn
->must_close
= 1;
12277 if (ri
->remote_user
!= NULL
) {
12278 mg_free((void *)ri
->remote_user
);
12279 /* Important! When having connections with and without auth
12280 * would cause double free and then crash */
12281 ri
->remote_user
= NULL
;
12284 /* NOTE(lsm): order is important here. should_keep_alive() call
12286 * using parsed request, which will be invalid after memmove's
12288 * Therefore, memorize should_keep_alive() result now for later
12290 * in loop exit condition. */
12291 keep_alive
= conn
->ctx
->stop_flag
== 0 && keep_alive_enabled
12292 && conn
->content_len
>= 0 && should_keep_alive(conn
);
12294 /* Discard all buffered data for this request */
12295 discard_len
= conn
->content_len
>= 0 && conn
->request_len
> 0
12296 && conn
->request_len
+ conn
->content_len
12297 < (int64_t)conn
->data_len
12298 ? (int)(conn
->request_len
+ conn
->content_len
)
12300 /*assert(discard_len >= 0);*/
12301 if (discard_len
< 0)
12303 conn
->data_len
-= discard_len
;
12304 if (conn
->data_len
> 0) {
12306 conn
->buf
+ discard_len
,
12307 (size_t)conn
->data_len
);
12310 /* assert(conn->data_len >= 0); */
12311 /* assert(conn->data_len <= conn->buf_size); */
12313 if ((conn
->data_len
< 0) || (conn
->data_len
> conn
->buf_size
)) {
12317 } while (keep_alive
);
12322 /* Worker threads take accepted socket from the queue */
12324 consume_socket(struct mg_context
*ctx
, struct socket
*sp
)
12326 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12331 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12332 DEBUG_TRACE("%s", "going idle");
12334 /* If the queue is empty, wait. We're idle at this point. */
12335 while (ctx
->sq_head
== ctx
->sq_tail
&& ctx
->stop_flag
== 0) {
12336 pthread_cond_wait(&ctx
->sq_full
, &ctx
->thread_mutex
);
12339 /* If we're stopping, sq_head may be equal to sq_tail. */
12340 if (ctx
->sq_head
> ctx
->sq_tail
) {
12341 /* Copy socket from the queue and increment tail */
12342 *sp
= ctx
->queue
[ctx
->sq_tail
% QUEUE_SIZE(ctx
)];
12345 DEBUG_TRACE("grabbed socket %d, going busy", sp
? sp
->sock
: -1);
12347 /* Wrap pointers if needed */
12348 while (ctx
->sq_tail
> QUEUE_SIZE(ctx
)) {
12349 ctx
->sq_tail
-= QUEUE_SIZE(ctx
);
12350 ctx
->sq_head
-= QUEUE_SIZE(ctx
);
12354 (void)pthread_cond_signal(&ctx
->sq_empty
);
12355 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12357 return !ctx
->stop_flag
;
12363 worker_thread_run(void *thread_func_param
)
12365 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12366 struct mg_connection
*conn
;
12367 struct mg_workerTLS tls
;
12368 #if defined(MG_LEGACY_INTERFACE)
12372 mg_set_thread_name("worker");
12375 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12376 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12377 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12380 if (ctx
->callbacks
.init_thread
) {
12381 /* call init_thread for a worker thread (type 1) */
12382 ctx
->callbacks
.init_thread(ctx
, 1);
12386 (struct mg_connection
*)mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
);
12387 if (conn
== NULL
) {
12388 mg_cry(fc(ctx
), "%s", "Cannot create new connection struct, OOM");
12390 pthread_setspecific(sTlsKey
, &tls
);
12391 conn
->buf_size
= MAX_REQUEST_SIZE
;
12392 conn
->buf
= (char *)(conn
+ 1);
12394 conn
->request_info
.user_data
= ctx
->user_data
;
12395 /* Allocate a mutex for this connection to allow communication both
12396 * within the request handler and from elsewhere in the application
12398 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
12400 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
12401 * signal sq_empty condvar to wake up the master waiting in
12402 * produce_socket() */
12403 while (consume_socket(ctx
, &conn
->client
)) {
12404 conn
->conn_birth_time
= time(NULL
);
12406 /* Fill in IP, port info early so even if SSL setup below fails,
12407 * error handler would have the corresponding info.
12408 * Thanks to Johannes Winkelmann for the patch.
12410 #if defined(USE_IPV6)
12411 if (conn
->client
.rsa
.sa
.sa_family
== AF_INET6
) {
12412 conn
->request_info
.remote_port
=
12413 ntohs(conn
->client
.rsa
.sin6
.sin6_port
);
12417 conn
->request_info
.remote_port
=
12418 ntohs(conn
->client
.rsa
.sin
.sin_port
);
12421 sockaddr_to_string(conn
->request_info
.remote_addr
,
12422 sizeof(conn
->request_info
.remote_addr
),
12423 &conn
->client
.rsa
);
12425 #if defined(MG_LEGACY_INTERFACE)
12426 /* This legacy interface only works for the IPv4 case */
12427 addr
= ntohl(conn
->client
.rsa
.sin
.sin_addr
.s_addr
);
12428 memcpy(&conn
->request_info
.remote_ip
, &addr
, 4);
12431 conn
->request_info
.is_ssl
= conn
->client
.is_ssl
;
12433 if (!conn
->client
.is_ssl
12435 || sslize(conn
, conn
->ctx
->ssl_ctx
, SSL_accept
)
12440 process_new_connection(conn
);
12443 close_connection(conn
);
12447 /* Signal master that we're done with connection and exiting */
12448 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12449 ctx
->running_worker_threads
--;
12450 (void)pthread_cond_signal(&ctx
->thread_cond
);
12451 /* assert(ctx->running_worker_threads >= 0); */
12452 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12454 pthread_setspecific(sTlsKey
, NULL
);
12455 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12456 CloseHandle(tls
.pthread_cond_helper_mutex
);
12458 pthread_mutex_destroy(&conn
->mutex
);
12461 DEBUG_TRACE("%s", "exiting");
12466 /* Threads have different return types on Windows and Unix. */
12468 static unsigned __stdcall
worker_thread(void *thread_func_param
)
12470 worker_thread_run(thread_func_param
);
12475 worker_thread(void *thread_func_param
)
12477 worker_thread_run(thread_func_param
);
12480 #endif /* _WIN32 */
12483 /* Master thread adds accepted socket to a queue */
12485 produce_socket(struct mg_context
*ctx
, const struct socket
*sp
)
12487 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12491 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12493 /* If the queue is full, wait */
12494 while (ctx
->stop_flag
== 0
12495 && ctx
->sq_head
- ctx
->sq_tail
>= QUEUE_SIZE(ctx
)) {
12496 (void)pthread_cond_wait(&ctx
->sq_empty
, &ctx
->thread_mutex
);
12499 if (ctx
->sq_head
- ctx
->sq_tail
< QUEUE_SIZE(ctx
)) {
12500 /* Copy socket to the queue and increment head */
12501 ctx
->queue
[ctx
->sq_head
% QUEUE_SIZE(ctx
)] = *sp
;
12503 DEBUG_TRACE("queued socket %d", sp
? sp
->sock
: -1);
12506 (void)pthread_cond_signal(&ctx
->sq_full
);
12507 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12513 accept_new_connection(const struct socket
*listener
, struct mg_context
*ctx
)
12516 char src_addr
[IP_ADDR_STR_LEN
];
12517 socklen_t len
= sizeof(so
.rsa
);
12525 if ((so
.sock
= accept(listener
->sock
, &so
.rsa
.sa
, &len
))
12526 == INVALID_SOCKET
) {
12527 } else if (!check_acl(ctx
, ntohl(*(uint32_t *)&so
.rsa
.sin
.sin_addr
))) {
12528 sockaddr_to_string(src_addr
, sizeof(src_addr
), &so
.rsa
);
12529 mg_cry(fc(ctx
), "%s: %s is not allowed to connect", __func__
, src_addr
);
12530 closesocket(so
.sock
);
12531 so
.sock
= INVALID_SOCKET
;
12533 /* Put so socket structure into the queue */
12534 DEBUG_TRACE("Accepted socket %d", (int)so
.sock
);
12535 set_close_on_exec(so
.sock
, fc(ctx
));
12536 so
.is_ssl
= listener
->is_ssl
;
12537 so
.ssl_redir
= listener
->ssl_redir
;
12538 if (getsockname(so
.sock
, &so
.lsa
.sa
, &len
) != 0) {
12540 "%s: getsockname() failed: %s",
12545 /* Set TCP keep-alive. This is needed because if HTTP-level
12547 * is enabled, and client resets the connection, server won't get
12548 * TCP FIN or RST and will keep the connection open forever. With
12549 * TCP keep-alive, next keep-alive handshake will figure out that
12550 * the client is down and will close the server end.
12551 * Thanks to Igor Klopov who suggested the patch. */
12552 if (setsockopt(so
.sock
,
12555 (SOCK_OPT_TYPE
)&on
,
12556 sizeof(on
)) != 0) {
12558 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
12564 /* Disable TCP Nagle's algorithm. Normally TCP packets are
12566 * to effectively fill up the underlying IP packet payload and
12568 * the overhead of sending lots of small buffers. However this hurts
12569 * the server's throughput (ie. operations per second) when HTTP 1.1
12570 * persistent connections are used and the responses are relatively
12571 * small (eg. less than 1400 bytes).
12573 if ((ctx
!= NULL
) && (ctx
->config
[CONFIG_TCP_NODELAY
] != NULL
)
12574 && (!strcmp(ctx
->config
[CONFIG_TCP_NODELAY
], "1"))) {
12575 if (set_tcp_nodelay(so
.sock
, 1) != 0) {
12577 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
12583 if (ctx
&& ctx
->config
[REQUEST_TIMEOUT
]) {
12584 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]);
12589 /* Set socket timeout to the given value, but not more than a
12590 * a certain limit (SOCKET_TIMEOUT_QUANTUM, default 10 seconds),
12591 * so the server can exit after that time if requested. */
12592 if ((timeout
> 0) && (timeout
< SOCKET_TIMEOUT_QUANTUM
)) {
12593 set_sock_timeout(so
.sock
, timeout
);
12595 set_sock_timeout(so
.sock
, SOCKET_TIMEOUT_QUANTUM
);
12598 produce_socket(ctx
, &so
);
12604 master_thread_run(void *thread_func_param
)
12606 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12607 struct mg_workerTLS tls
;
12608 struct pollfd
*pfd
;
12610 unsigned int workerthreadcount
;
12616 mg_set_thread_name("master");
12618 /* Increase priority of the master thread */
12619 #if defined(_WIN32)
12620 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
12621 #elif defined(USE_MASTER_THREAD_PRIORITY)
12622 int min_prio
= sched_get_priority_min(SCHED_RR
);
12623 int max_prio
= sched_get_priority_max(SCHED_RR
);
12624 if ((min_prio
>= 0) && (max_prio
>= 0)
12625 && ((USE_MASTER_THREAD_PRIORITY
) <= max_prio
)
12626 && ((USE_MASTER_THREAD_PRIORITY
) >= min_prio
)) {
12627 struct sched_param sched_param
= {0};
12628 sched_param
.sched_priority
= (USE_MASTER_THREAD_PRIORITY
);
12629 pthread_setschedparam(pthread_self(), SCHED_RR
, &sched_param
);
12633 /* Initialize thread local storage */
12634 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12635 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12638 pthread_setspecific(sTlsKey
, &tls
);
12640 if (ctx
->callbacks
.init_thread
) {
12641 /* Callback for the master thread (type 0) */
12642 ctx
->callbacks
.init_thread(ctx
, 0);
12645 /* Server starts *now* */
12646 ctx
->start_time
= time(NULL
);
12648 /* Allocate memory for the listening sockets, and start the server */
12650 (struct pollfd
*)mg_calloc(ctx
->num_listening_sockets
, sizeof(pfd
[0]));
12651 while (pfd
!= NULL
&& ctx
->stop_flag
== 0) {
12652 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12653 pfd
[i
].fd
= ctx
->listening_sockets
[i
].sock
;
12654 pfd
[i
].events
= POLLIN
;
12657 if (poll(pfd
, ctx
->num_listening_sockets
, 200) > 0) {
12658 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12659 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
12660 * successful poll, and POLLIN is defined as
12661 * (POLLRDNORM | POLLRDBAND)
12662 * Therefore, we're checking pfd[i].revents & POLLIN, not
12663 * pfd[i].revents == POLLIN. */
12664 if (ctx
->stop_flag
== 0 && (pfd
[i
].revents
& POLLIN
)) {
12665 accept_new_connection(&ctx
->listening_sockets
[i
], ctx
);
12671 DEBUG_TRACE("%s", "stopping workers");
12673 /* Stop signal received: somebody called mg_stop. Quit. */
12674 close_all_listening_sockets(ctx
);
12676 /* Wakeup workers that are waiting for connections to handle. */
12677 pthread_cond_broadcast(&ctx
->sq_full
);
12679 /* Wait until all threads finish */
12680 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12681 while (ctx
->running_worker_threads
> 0) {
12682 (void)pthread_cond_wait(&ctx
->thread_cond
, &ctx
->thread_mutex
);
12684 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12686 /* Join all worker threads to avoid leaking threads. */
12687 workerthreadcount
= ctx
->cfg_worker_threads
;
12688 for (i
= 0; i
< workerthreadcount
; i
++) {
12689 if (ctx
->workerthreadids
[i
] != 0) {
12690 mg_join_thread(ctx
->workerthreadids
[i
]);
12694 #if !defined(NO_SSL)
12695 if (ctx
->ssl_ctx
!= NULL
) {
12696 uninitialize_ssl(ctx
);
12699 DEBUG_TRACE("%s", "exiting");
12701 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12702 CloseHandle(tls
.pthread_cond_helper_mutex
);
12704 pthread_setspecific(sTlsKey
, NULL
);
12706 /* Signal mg_stop() that we're done.
12707 * WARNING: This must be the very last thing this
12708 * thread does, as ctx becomes invalid after this line. */
12709 ctx
->stop_flag
= 2;
12713 /* Threads have different return types on Windows and Unix. */
12715 static unsigned __stdcall
master_thread(void *thread_func_param
)
12717 master_thread_run(thread_func_param
);
12722 master_thread(void *thread_func_param
)
12724 master_thread_run(thread_func_param
);
12727 #endif /* _WIN32 */
12731 free_context(struct mg_context
*ctx
)
12734 struct mg_handler_info
*tmp_rh
;
12740 if (ctx
->callbacks
.exit_context
) {
12741 ctx
->callbacks
.exit_context(ctx
);
12744 /* All threads exited, no sync is needed. Destroy thread mutex and
12747 (void)pthread_mutex_destroy(&ctx
->thread_mutex
);
12748 (void)pthread_cond_destroy(&ctx
->thread_cond
);
12749 (void)pthread_cond_destroy(&ctx
->sq_empty
);
12750 (void)pthread_cond_destroy(&ctx
->sq_full
);
12752 /* Destroy other context global data structures mutex */
12753 (void)pthread_mutex_destroy(&ctx
->nonce_mutex
);
12755 #if defined(USE_TIMERS)
12759 /* Deallocate config parameters */
12760 for (i
= 0; i
< NUM_OPTIONS
; i
++) {
12761 if (ctx
->config
[i
] != NULL
) {
12762 #if defined(_MSC_VER)
12763 #pragma warning(suppress : 6001)
12765 mg_free(ctx
->config
[i
]);
12769 /* Deallocate request handlers */
12770 while (ctx
->handlers
) {
12771 tmp_rh
= ctx
->handlers
;
12772 ctx
->handlers
= tmp_rh
->next
;
12773 mg_free(tmp_rh
->uri
);
12778 /* Deallocate SSL context */
12779 if (ctx
->ssl_ctx
!= NULL
) {
12780 SSL_CTX_free(ctx
->ssl_ctx
);
12782 #endif /* !NO_SSL */
12784 /* Deallocate worker thread ID array */
12785 if (ctx
->workerthreadids
!= NULL
) {
12786 mg_free(ctx
->workerthreadids
);
12789 /* Deallocate the tls variable */
12790 if (mg_atomic_dec(&sTlsInit
) == 0) {
12791 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12792 DeleteCriticalSection(&global_log_file_lock
);
12793 #endif /* _WIN32 && !__SYMBIAN32__ */
12794 #if !defined(_WIN32)
12795 pthread_mutexattr_destroy(&pthread_mutex_attr
);
12798 pthread_key_delete(sTlsKey
);
12801 /* deallocate system name string */
12802 mg_free(ctx
->systemName
);
12804 /* Deallocate context itself */
12810 mg_stop(struct mg_context
*ctx
)
12817 /* We don't use a lock here. Calling mg_stop with the same ctx from
12818 * two threads is not allowed. */
12819 mt
= ctx
->masterthreadid
;
12824 ctx
->masterthreadid
= 0;
12825 ctx
->stop_flag
= 1;
12827 /* Wait until mg_fini() stops */
12828 while (ctx
->stop_flag
!= 2) {
12829 (void)mg_sleep(10);
12832 mg_join_thread(mt
);
12835 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12836 (void)WSACleanup();
12837 #endif /* _WIN32 && !__SYMBIAN32__ */
12842 get_system_name(char **sysName
)
12844 #if defined(_WIN32)
12845 #if !defined(__SYMBIAN32__)
12847 DWORD dwVersion
= 0;
12848 DWORD dwMajorVersion
= 0;
12849 DWORD dwMinorVersion
= 0;
12853 #pragma warning(push)
12854 // GetVersion was declared deprecated
12855 #pragma warning(disable : 4996)
12857 dwVersion
= GetVersion();
12859 #pragma warning(pop)
12862 dwMajorVersion
= (DWORD
)(LOBYTE(LOWORD(dwVersion
)));
12863 dwMinorVersion
= (DWORD
)(HIBYTE(LOWORD(dwVersion
)));
12864 dwBuild
= ((dwVersion
< 0x80000000) ? (DWORD
)(HIWORD(dwVersion
)) : 0);
12869 (unsigned)dwMajorVersion
,
12870 (unsigned)dwMinorVersion
);
12871 *sysName
= mg_strdup(name
);
12873 *sysName
= mg_strdup("Symbian");
12876 struct utsname name
;
12877 memset(&name
, 0, sizeof(name
));
12879 *sysName
= mg_strdup(name
.sysname
);
12884 struct mg_context
*
12885 mg_start(const struct mg_callbacks
*callbacks
,
12887 const char **options
)
12889 struct mg_context
*ctx
;
12890 const char *name
, *value
, *default_value
;
12891 int idx
, ok
, workerthreadcount
;
12893 void (*exit_callback
)(const struct mg_context
*ctx
) = 0;
12895 struct mg_workerTLS tls
;
12897 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12899 WSAStartup(MAKEWORD(2, 2), &data
);
12900 #endif /* _WIN32 && !__SYMBIAN32__ */
12902 /* Allocate context and initialize reasonable general case defaults. */
12903 if ((ctx
= (struct mg_context
*)mg_calloc(1, sizeof(*ctx
))) == NULL
) {
12907 /* Random number generator will initialize at the first call */
12908 ctx
->auth_nonce_mask
=
12909 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options
);
12911 if (mg_atomic_inc(&sTlsInit
) == 1) {
12913 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12914 InitializeCriticalSection(&global_log_file_lock
);
12915 #endif /* _WIN32 && !__SYMBIAN32__ */
12916 #if !defined(_WIN32)
12917 pthread_mutexattr_init(&pthread_mutex_attr
);
12918 pthread_mutexattr_settype(&pthread_mutex_attr
, PTHREAD_MUTEX_RECURSIVE
);
12921 if (0 != pthread_key_create(&sTlsKey
, tls_dtor
)) {
12922 /* Fatal error - abort start. However, this situation should
12924 * occur in practice. */
12925 mg_atomic_dec(&sTlsInit
);
12926 mg_cry(fc(ctx
), "Cannot initialize thread local storage");
12931 /* TODO (low): istead of sleeping, check if sTlsKey is already
12936 tls
.is_master
= -1;
12937 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12938 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12939 tls
.pthread_cond_helper_mutex
= NULL
;
12941 pthread_setspecific(sTlsKey
, &tls
);
12943 #if defined(USE_LUA)
12944 lua_init_optional_libraries();
12947 ok
= 0 == pthread_mutex_init(&ctx
->thread_mutex
, &pthread_mutex_attr
);
12948 ok
&= 0 == pthread_cond_init(&ctx
->thread_cond
, NULL
);
12949 ok
&= 0 == pthread_cond_init(&ctx
->sq_empty
, NULL
);
12950 ok
&= 0 == pthread_cond_init(&ctx
->sq_full
, NULL
);
12951 ok
&= 0 == pthread_mutex_init(&ctx
->nonce_mutex
, &pthread_mutex_attr
);
12953 /* Fatal error - abort start. However, this situation should never
12954 * occur in practice. */
12955 mg_cry(fc(ctx
), "Cannot initialize thread synchronization objects");
12957 pthread_setspecific(sTlsKey
, NULL
);
12962 ctx
->callbacks
= *callbacks
;
12963 exit_callback
= callbacks
->exit_context
;
12964 ctx
->callbacks
.exit_context
= 0;
12966 ctx
->user_data
= user_data
;
12967 ctx
->handlers
= NULL
;
12969 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
12970 ctx
->shared_lua_websockets
= 0;
12973 while (options
&& (name
= *options
++) != NULL
) {
12974 if ((idx
= get_option_index(name
)) == -1) {
12975 mg_cry(fc(ctx
), "Invalid option: %s", name
);
12977 pthread_setspecific(sTlsKey
, NULL
);
12979 } else if ((value
= *options
++) == NULL
) {
12980 mg_cry(fc(ctx
), "%s: option value cannot be NULL", name
);
12982 pthread_setspecific(sTlsKey
, NULL
);
12985 if (ctx
->config
[idx
] != NULL
) {
12986 mg_cry(fc(ctx
), "warning: %s: duplicate option", name
);
12987 mg_free(ctx
->config
[idx
]);
12989 ctx
->config
[idx
] = mg_strdup(value
);
12990 DEBUG_TRACE("[%s] -> [%s]", name
, value
);
12993 /* Set default value if needed */
12994 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
12995 default_value
= config_options
[i
].default_value
;
12996 if (ctx
->config
[i
] == NULL
&& default_value
!= NULL
) {
12997 ctx
->config
[i
] = mg_strdup(default_value
);
13001 #if defined(NO_FILES)
13002 if (ctx
->config
[DOCUMENT_ROOT
] != NULL
) {
13003 mg_cry(fc(ctx
), "%s", "Document root must not be set");
13005 pthread_setspecific(sTlsKey
, NULL
);
13010 get_system_name(&ctx
->systemName
);
13012 /* NOTE(lsm): order is important here. SSL certificates must
13013 * be initialized before listening ports. UID must be set last. */
13014 if (!set_gpass_option(ctx
) ||
13015 #if !defined(NO_SSL)
13016 !set_ssl_option(ctx
) ||
13018 !set_ports_option(ctx
) ||
13019 #if !defined(_WIN32)
13020 !set_uid_option(ctx
) ||
13022 !set_acl_option(ctx
)) {
13024 pthread_setspecific(sTlsKey
, NULL
);
13028 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
13029 /* Ignore SIGPIPE signal, so if browser cancels the request, it
13030 * won't kill the whole process. */
13031 (void)signal(SIGPIPE
, SIG_IGN
);
13032 #endif /* !_WIN32 && !__SYMBIAN32__ */
13034 workerthreadcount
= atoi(ctx
->config
[NUM_THREADS
]);
13036 if (workerthreadcount
> MAX_WORKER_THREADS
) {
13037 mg_cry(fc(ctx
), "Too many worker threads");
13039 pthread_setspecific(sTlsKey
, NULL
);
13043 if (workerthreadcount
> 0) {
13044 ctx
->cfg_worker_threads
= ((unsigned int)(workerthreadcount
));
13045 ctx
->workerthreadids
=
13046 (pthread_t
*)mg_calloc(ctx
->cfg_worker_threads
, sizeof(pthread_t
));
13047 if (ctx
->workerthreadids
== NULL
) {
13048 mg_cry(fc(ctx
), "Not enough memory for worker thread ID array");
13050 pthread_setspecific(sTlsKey
, NULL
);
13055 #if defined(USE_TIMERS)
13056 if (timers_init(ctx
) != 0) {
13057 mg_cry(fc(ctx
), "Error creating timers");
13059 pthread_setspecific(sTlsKey
, NULL
);
13064 /* Context has been created - init user libraries */
13065 if (ctx
->callbacks
.init_context
) {
13066 ctx
->callbacks
.init_context(ctx
);
13068 ctx
->callbacks
.exit_context
= exit_callback
;
13069 ctx
->context_type
= 1; /* server context */
13071 /* Start master (listening) thread */
13072 mg_start_thread_with_id(master_thread
, ctx
, &ctx
->masterthreadid
);
13074 /* Start worker threads */
13075 for (i
= 0; i
< ctx
->cfg_worker_threads
; i
++) {
13076 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13077 ctx
->running_worker_threads
++;
13078 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13079 if (mg_start_thread_with_id(worker_thread
,
13081 &ctx
->workerthreadids
[i
]) != 0) {
13082 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13083 ctx
->running_worker_threads
--;
13084 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13087 "Cannot start worker thread %i: error %ld",
13092 "Cannot create threads: error %ld",
13095 pthread_setspecific(sTlsKey
, NULL
);
13102 pthread_setspecific(sTlsKey
, NULL
);
13107 /* Feature check API function */
13109 mg_check_feature(unsigned feature
)
13111 static const unsigned feature_set
= 0
13112 /* Set bits for available features according to API documentation.
13113 * This bit mask is created at compile time, according to the active
13114 * preprocessor defines. It is a single const value at runtime. */
13115 #if !defined(NO_FILES)
13118 #if !defined(NO_SSL)
13121 #if !defined(NO_CGI)
13124 #if defined(USE_IPV6)
13127 #if defined(USE_WEBSOCKET)
13130 #if defined(USE_LUA)
13133 #if defined(USE_DUKTAPE)
13136 #if !defined(NO_CACHING)
13140 /* Set some extra bits not defined in the API documentation.
13141 * These bits may change without further notice. */
13142 #if defined(MG_LEGACY_INTERFACE)
13145 #if defined(MEMORY_DEBUGGING)
13148 #if defined(USE_TIMERS)
13151 #if !defined(NO_NONCE_CHECK)
13154 #if !defined(NO_POPEN)
13158 return (feature
& feature_set
);