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
,
1126 VALIDATE_HTTP_METHOD
,
1127 CANONICALIZE_URL_PATH
,
1133 /* Config option name, config types, default value */
1134 static struct mg_option config_options
[] = {
1135 {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.cgi$|**.pl$|**.php$"},
1136 {"cgi_environment", CONFIG_TYPE_STRING
, NULL
},
1137 {"put_delete_auth_file", CONFIG_TYPE_FILE
, NULL
},
1138 {"cgi_interpreter", CONFIG_TYPE_FILE
, NULL
},
1139 {"protect_uri", CONFIG_TYPE_STRING
, NULL
},
1140 {"authentication_domain", CONFIG_TYPE_STRING
, "mydomain.com"},
1141 {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.shtml$|**.shtm$"},
1142 {"throttle", CONFIG_TYPE_STRING
, NULL
},
1143 {"access_log_file", CONFIG_TYPE_FILE
, NULL
},
1144 {"enable_directory_listing", CONFIG_TYPE_BOOLEAN
, "yes"},
1145 {"error_log_file", CONFIG_TYPE_FILE
, NULL
},
1146 {"global_auth_file", CONFIG_TYPE_FILE
, NULL
},
1150 "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,"
1151 "index.shtml,index.php"},
1153 "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
1155 {"enable_keep_alive", CONFIG_TYPE_BOOLEAN
, "no"},
1156 {"access_control_list", CONFIG_TYPE_STRING
, NULL
},
1157 {"extra_mime_types", CONFIG_TYPE_STRING
, NULL
},
1158 {"listening_ports", CONFIG_TYPE_STRING
, "8080"},
1159 {"document_root", CONFIG_TYPE_DIRECTORY
, NULL
},
1160 {"ssl_certificate", CONFIG_TYPE_FILE
, NULL
},
1161 {"num_threads", CONFIG_TYPE_NUMBER
, "50"},
1162 {"run_as_user", CONFIG_TYPE_STRING
, NULL
},
1163 {"url_rewrite_patterns", CONFIG_TYPE_STRING
, NULL
},
1164 {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN
, NULL
},
1165 {"request_timeout_ms", CONFIG_TYPE_NUMBER
, "30000"},
1166 {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN
, "no"},
1167 {"ssl_ca_path", CONFIG_TYPE_DIRECTORY
, NULL
},
1168 {"ssl_ca_file", CONFIG_TYPE_FILE
, NULL
},
1169 {"ssl_verify_depth", CONFIG_TYPE_NUMBER
, "9"},
1170 {"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN
, "yes"},
1171 {"ssl_cipher_list", CONFIG_TYPE_STRING
, NULL
},
1172 {"ssl_protocol_version", CONFIG_TYPE_NUMBER
, "0"},
1173 {"ssl_short_trust", CONFIG_TYPE_BOOLEAN
, "no"},
1174 #if defined(USE_WEBSOCKET)
1175 {"websocket_timeout_ms", CONFIG_TYPE_NUMBER
, "30000"},
1177 {"decode_url", CONFIG_TYPE_BOOLEAN
, "yes"},
1179 #if defined(USE_LUA)
1180 {"lua_preload_file", CONFIG_TYPE_FILE
, NULL
},
1181 {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lua$"},
1182 {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lp$|**.lsp$"},
1184 #if defined(USE_DUKTAPE)
1185 /* The support for duktape is still in alpha version state.
1186 * The name of this config option might change. */
1187 {"duktape_script_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.ssjs$"},
1190 #if defined(USE_WEBSOCKET)
1191 {"websocket_root", CONFIG_TYPE_DIRECTORY
, NULL
},
1193 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1194 {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN
, "**.lua$"},
1196 {"access_control_allow_origin", CONFIG_TYPE_STRING
, "*"},
1197 {"error_pages", CONFIG_TYPE_DIRECTORY
, NULL
},
1198 {"tcp_nodelay", CONFIG_TYPE_NUMBER
, "0"},
1199 #if !defined(NO_CACHING)
1200 {"static_file_max_age", CONFIG_TYPE_NUMBER
, "3600"},
1202 {"validate_http_method", CONFIG_TYPE_BOOLEAN
, "yes"},
1203 {"canonicalize_url_path", CONFIG_TYPE_BOOLEAN
, "yes"},
1205 {NULL
, CONFIG_TYPE_UNKNOWN
, NULL
}};
1207 /* Check if the config_options and the corresponding enum have compatible
1209 mg_static_assert((sizeof(config_options
) / sizeof(config_options
[0]))
1210 == (NUM_OPTIONS
+ 1),
1211 "config_options and enum not sync");
1213 enum { REQUEST_HANDLER
, WEBSOCKET_HANDLER
, AUTH_HANDLER
};
1215 struct mg_handler_info
{
1216 /* Name/Pattern of the URI. */
1223 /* Handler for http/https or authorization requests. */
1224 mg_request_handler handler
;
1226 /* Handler for ws/wss (websocket) requests. */
1227 mg_websocket_connect_handler connect_handler
;
1228 mg_websocket_ready_handler ready_handler
;
1229 mg_websocket_data_handler data_handler
;
1230 mg_websocket_close_handler close_handler
;
1232 /* Handler for authorization requests */
1233 mg_authorization_handler auth_handler
;
1235 /* User supplied argument for the handler function. */
1238 /* next handler in a linked list */
1239 struct mg_handler_info
*next
;
1243 volatile int stop_flag
; /* Should we stop event loop */
1244 SSL_CTX
*ssl_ctx
; /* SSL context */
1245 char *config
[NUM_OPTIONS
]; /* Civetweb configuration parameters */
1246 struct mg_callbacks callbacks
; /* User-defined callback function */
1247 void *user_data
; /* User-defined data */
1248 int context_type
; /* 1 = server context, 2 = client context */
1250 struct socket
*listening_sockets
;
1251 in_port_t
*listening_ports
;
1252 unsigned int num_listening_sockets
;
1255 running_worker_threads
; /* Number of currently running worker threads */
1256 pthread_mutex_t thread_mutex
; /* Protects (max|num)_threads */
1257 pthread_cond_t thread_cond
; /* Condvar for tracking workers terminations */
1259 struct socket queue
[MGSQLEN
]; /* Accepted sockets */
1260 volatile int sq_head
; /* Head of the socket queue */
1261 volatile int sq_tail
; /* Tail of the socket queue */
1262 pthread_cond_t sq_full
; /* Signaled when socket is produced */
1263 pthread_cond_t sq_empty
; /* Signaled when socket is consumed */
1264 pthread_t masterthreadid
; /* The master thread ID */
1266 cfg_worker_threads
; /* The number of configured worker threads. */
1267 pthread_t
*workerthreadids
; /* The worker thread IDs */
1269 time_t start_time
; /* Server start time, used for authentication */
1270 uint64_t auth_nonce_mask
; /* Mask for all nonce values */
1271 pthread_mutex_t nonce_mutex
; /* Protects nonce_count */
1272 unsigned long nonce_count
; /* Used nonces, used for authentication */
1274 char *systemName
; /* What operating system is running */
1276 /* linked list of uri handlers */
1277 struct mg_handler_info
*handlers
;
1279 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1280 /* linked list of shared lua websockets */
1281 struct mg_shared_lua_websocket_list
*shared_lua_websockets
;
1285 struct ttimers
*timers
;
1290 struct mg_connection
{
1291 struct mg_request_info request_info
;
1292 struct mg_context
*ctx
;
1293 SSL
*ssl
; /* SSL descriptor */
1294 SSL_CTX
*client_ssl_ctx
; /* SSL context for client connections */
1295 struct socket client
; /* Connected client */
1296 time_t conn_birth_time
; /* Time (wall clock) when connection was
1298 struct timespec req_time
; /* Time (since system start) when the request
1300 int64_t num_bytes_sent
; /* Total bytes sent to client */
1301 int64_t content_len
; /* Content-Length header value */
1302 int64_t consumed_content
; /* How many bytes of content have been read */
1303 int is_chunked
; /* Transfer-Encoding is chunked: 0=no, 1=yes:
1304 * data available, 2: all data read */
1305 size_t chunk_remainder
; /* Unread data from the last chunk */
1306 char *buf
; /* Buffer for received data */
1307 char *path_info
; /* PATH_INFO part of the URL */
1309 int must_close
; /* 1 if connection must be closed */
1310 int in_error_handler
; /* 1 if in handler for user defined error
1312 int internal_error
; /* 1 if an error occured while processing the
1315 int buf_size
; /* Buffer size */
1316 int request_len
; /* Size of the request + headers in a buffer */
1317 int data_len
; /* Total size of data in a buffer */
1318 int status_code
; /* HTTP reply status code, e.g. 200 */
1319 int throttle
; /* Throttling, bytes/sec. <= 0 means no
1321 time_t last_throttle_time
; /* Last time throttled data was sent */
1322 int64_t last_throttle_bytes
; /* Bytes sent this second */
1323 pthread_mutex_t mutex
; /* Used by mg_(un)lock_connection to ensure
1324 * atomic transmissions for websockets */
1325 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
1326 void *lua_websocket_state
; /* Lua_State for a websocket connection */
1331 static pthread_key_t sTlsKey
; /* Thread local storage index */
1332 static int sTlsInit
= 0;
1333 static int thread_idx_max
= 0;
1336 struct mg_workerTLS
{
1338 unsigned long thread_idx
;
1339 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1340 HANDLE pthread_cond_helper_mutex
;
1344 /* Directory entry */
1346 struct mg_connection
*conn
;
1352 #if defined(USE_WEBSOCKET)
1353 static int is_websocket_protocol(const struct mg_connection
*conn
);
1355 #define is_websocket_protocol(conn) (0)
1360 mg_atomic_inc(volatile int *addr
)
1363 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1364 /* Depending on the SDK, this function uses either
1365 * (volatile unsigned int *) or (volatile LONG *),
1366 * so whatever you use, the other SDK is likely to raise a warning. */
1367 ret
= InterlockedIncrement((volatile long *)addr
);
1368 #elif defined(__GNUC__) \
1369 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1370 ret
= __sync_add_and_fetch(addr
, 1);
1379 mg_atomic_dec(volatile int *addr
)
1382 #if defined(_WIN32) && !defined(__SYMBIAN32__)
1383 /* Depending on the SDK, this function uses either
1384 * (volatile unsigned int *) or (volatile LONG *),
1385 * so whatever you use, the other SDK is likely to raise a warning. */
1386 ret
= InterlockedDecrement((volatile long *)addr
);
1387 #elif defined(__GNUC__) \
1388 && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
1389 ret
= __sync_sub_and_fetch(addr
, 1);
1396 #if !defined(NO_THREAD_NAME)
1397 #if defined(_WIN32) && defined(_MSC_VER)
1398 /* Set the thread name for debugging purposes in Visual Studio
1399 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
1401 #pragma pack(push, 8)
1402 typedef struct tagTHREADNAME_INFO
{
1403 DWORD dwType
; /* Must be 0x1000. */
1404 LPCSTR szName
; /* Pointer to name (in user addr space). */
1405 DWORD dwThreadID
; /* Thread ID (-1=caller thread). */
1406 DWORD dwFlags
; /* Reserved for future use, must be zero. */
1409 #elif defined(__linux__)
1410 #include <sys/prctl.h>
1411 #include <sys/sendfile.h>
1416 mg_set_thread_name(const char *name
)
1418 char threadName
[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
1421 NULL
, NULL
, threadName
, sizeof(threadName
), "civetweb-%s", name
);
1424 #if defined(_MSC_VER)
1425 /* Windows and Visual Studio Compiler */
1428 THREADNAME_INFO info
;
1429 info
.dwType
= 0x1000;
1430 info
.szName
= threadName
;
1431 info
.dwThreadID
= ~0U;
1434 RaiseException(0x406D1388,
1436 sizeof(info
) / sizeof(ULONG_PTR
),
1437 (ULONG_PTR
*)&info
);
1439 __except(EXCEPTION_EXECUTE_HANDLER
)
1442 #elif defined(__MINGW32__)
1443 /* No option known to set thread name for MinGW */
1445 #elif defined(__GLIBC__) \
1446 && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
1447 /* pthread_setname_np first appeared in glibc in version 2.12*/
1448 (void)pthread_setname_np(pthread_self(), threadName
);
1449 #elif defined(__linux__)
1450 /* on linux we can use the old prctl function */
1451 (void)prctl(PR_SET_NAME
, threadName
, 0, 0, 0);
1454 #else /* !defined(NO_THREAD_NAME) */
1456 mg_set_thread_name(const char *threadName
)
1462 #if defined(MG_LEGACY_INTERFACE)
1464 mg_get_valid_option_names(void)
1466 /* This function is deprecated. Use mg_get_valid_options instead. */
1468 data
[2 * sizeof(config_options
) / sizeof(config_options
[0])] = {0};
1471 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
1472 data
[i
* 2] = config_options
[i
].name
;
1473 data
[i
* 2 + 1] = config_options
[i
].default_value
;
1481 const struct mg_option
*
1482 mg_get_valid_options(void)
1484 return config_options
;
1489 is_file_in_memory(const struct mg_connection
*conn
,
1494 if (!conn
|| !filep
) {
1498 if (conn
->ctx
->callbacks
.open_file
) {
1499 filep
->membuf
= conn
->ctx
->callbacks
.open_file(conn
, path
, &size
);
1500 if (filep
->membuf
!= NULL
) {
1501 /* NOTE: override filep->size only on success. Otherwise, it might
1502 * break constructs like if (!mg_stat() || !mg_fopen()) ... */
1507 return filep
->membuf
!= NULL
;
1512 is_file_opened(const struct file
*filep
)
1518 return filep
->membuf
!= NULL
|| filep
->fp
!= NULL
;
1522 /* mg_fopen will open a file either in memory or on the disk.
1523 * The input parameter path is a string in UTF-8 encoding.
1524 * The input parameter mode is the same as for fopen.
1525 * Either fp or membuf will be set in the output struct filep.
1526 * The function returns 1 on success, 0 on error. */
1528 mg_fopen(const struct mg_connection
*conn
,
1539 /* TODO (high): mg_fopen should only open a file, while mg_stat should
1540 * only get the file status. They should not work on different members of
1541 * the same structure (bad cohesion). */
1542 memset(filep
, 0, sizeof(*filep
));
1544 if (stat(path
, &st
) == 0) {
1545 filep
->size
= (uint64_t)(st
.st_size
);
1548 if (!is_file_in_memory(conn
, path
, filep
)) {
1550 wchar_t wbuf
[PATH_MAX
], wmode
[20];
1551 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
1552 MultiByteToWideChar(CP_UTF8
, 0, mode
, -1, wmode
, ARRAY_SIZE(wmode
));
1553 filep
->fp
= _wfopen(wbuf
, wmode
);
1555 /* Linux et al already use unicode. No need to convert. */
1556 filep
->fp
= fopen(path
, mode
);
1560 return is_file_opened(filep
);
1565 mg_fclose(struct file
*filep
)
1567 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
1574 mg_strlcpy(register char *dst
, register const char *src
, size_t n
)
1576 for (; *src
!= '\0' && n
> 1; n
--) {
1584 lowercase(const char *s
)
1586 return tolower(*(const unsigned char *)s
);
1591 mg_strncasecmp(const char *s1
, const char *s2
, size_t len
)
1597 diff
= lowercase(s1
++) - lowercase(s2
++);
1598 } while (diff
== 0 && s1
[-1] != '\0' && --len
> 0);
1606 mg_strcasecmp(const char *s1
, const char *s2
)
1611 diff
= lowercase(s1
++) - lowercase(s2
++);
1612 } while (diff
== 0 && s1
[-1] != '\0');
1619 mg_strndup(const char *ptr
, size_t len
)
1623 if ((p
= (char *)mg_malloc(len
+ 1)) != NULL
) {
1624 mg_strlcpy(p
, ptr
, len
+ 1);
1632 mg_strdup(const char *str
)
1634 return mg_strndup(str
, strlen(str
));
1639 mg_strcasestr(const char *big_str
, const char *small_str
)
1641 size_t i
, big_len
= strlen(big_str
), small_len
= strlen(small_str
);
1643 if (big_len
>= small_len
) {
1644 for (i
= 0; i
<= (big_len
- small_len
); i
++) {
1645 if (mg_strncasecmp(big_str
+ i
, small_str
, small_len
) == 0) {
1655 /* Return null terminated string of given maximum length.
1656 * Report errors if length is exceeded. */
1658 mg_vsnprintf(const struct mg_connection
*conn
,
1672 #pragma clang diagnostic push
1673 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1674 /* Using fmt as a non-literal is intended here, since it is mostly called
1675 * indirectly by mg_snprintf */
1678 n
= (int)vsnprintf_impl(buf
, buflen
, fmt
, ap
);
1679 ok
= (n
>= 0) && ((size_t)n
< buflen
);
1682 #pragma clang diagnostic pop
1694 "truncating vsnprintf buffer: [%.*s]",
1695 (int)((buflen
> 200) ? 200 : (buflen
- 1)),
1697 n
= (int)buflen
- 1;
1704 mg_snprintf(const struct mg_connection
*conn
,
1714 mg_vsnprintf(conn
, truncated
, buf
, buflen
, fmt
, ap
);
1720 get_option_index(const char *name
)
1724 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
1725 if (strcmp(config_options
[i
].name
, name
) == 0) {
1734 mg_get_option(const struct mg_context
*ctx
, const char *name
)
1737 if ((i
= get_option_index(name
)) == -1) {
1739 } else if (!ctx
|| ctx
->config
[i
] == NULL
) {
1742 return ctx
->config
[i
];
1748 mg_get_context(const struct mg_connection
*conn
)
1750 return (conn
== NULL
) ? (struct mg_context
*)NULL
: (conn
->ctx
);
1755 mg_get_user_data(const struct mg_context
*ctx
)
1757 return (ctx
== NULL
) ? NULL
: ctx
->user_data
;
1762 mg_set_user_connection_data(struct mg_connection
*conn
, void *data
)
1765 conn
->request_info
.conn_data
= data
;
1771 mg_get_user_connection_data(const struct mg_connection
*conn
)
1774 return conn
->request_info
.conn_data
;
1781 mg_get_ports(const struct mg_context
*ctx
, size_t size
, int *ports
, int *ssl
)
1787 for (i
= 0; i
< size
&& i
< ctx
->num_listening_sockets
; i
++) {
1788 ssl
[i
] = ctx
->listening_sockets
[i
].is_ssl
;
1789 ports
[i
] = ctx
->listening_ports
[i
];
1796 mg_get_server_ports(const struct mg_context
*ctx
,
1798 struct mg_server_ports
*ports
)
1805 memset(ports
, 0, sizeof(*ports
) * (size_t)size
);
1809 if (!ctx
->listening_sockets
|| !ctx
->listening_ports
) {
1813 for (i
= 0; (i
< size
) && (i
< (int)ctx
->num_listening_sockets
); i
++) {
1815 ports
[cnt
].port
= ctx
->listening_ports
[i
];
1816 ports
[cnt
].is_ssl
= ctx
->listening_sockets
[i
].is_ssl
;
1817 ports
[cnt
].is_redirect
= ctx
->listening_sockets
[i
].ssl_redir
;
1819 if (ctx
->listening_sockets
[i
].lsa
.sa
.sa_family
== AF_INET
) {
1821 ports
[cnt
].protocol
= 1;
1823 } else if (ctx
->listening_sockets
[i
].lsa
.sa
.sa_family
== AF_INET6
) {
1825 ports
[cnt
].protocol
= 3;
1835 sockaddr_to_string(char *buf
, size_t len
, const union usa
*usa
)
1843 if (usa
->sa
.sa_family
== AF_INET
) {
1844 getnameinfo(&usa
->sa
,
1852 #if defined(USE_IPV6)
1853 else if (usa
->sa
.sa_family
== AF_INET6
) {
1854 getnameinfo(&usa
->sa
,
1866 /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
1867 * included in all responses other than 100, 101, 5xx. */
1869 gmt_time_string(char *buf
, size_t buf_len
, time_t *t
)
1873 tm
= ((t
!= NULL
) ? gmtime(t
) : NULL
);
1875 strftime(buf
, buf_len
, "%a, %d %b %Y %H:%M:%S GMT", tm
);
1877 mg_strlcpy(buf
, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len
);
1878 buf
[buf_len
- 1] = '\0';
1883 /* difftime for struct timespec. Return value is in seconds. */
1885 mg_difftimespec(const struct timespec
*ts_now
, const struct timespec
*ts_before
)
1887 return (double)(ts_now
->tv_nsec
- ts_before
->tv_nsec
) * 1.0E-9
1888 + (double)(ts_now
->tv_sec
- ts_before
->tv_sec
);
1892 /* Print error message to the opened error log stream. */
1894 mg_cry(const struct mg_connection
*conn
, const char *fmt
, ...)
1896 char buf
[MG_BUF_LEN
], src_addr
[IP_ADDR_STR_LEN
];
1902 IGNORE_UNUSED_RESULT(vsnprintf_impl(buf
, sizeof(buf
), fmt
, ap
));
1904 buf
[sizeof(buf
) - 1] = 0;
1911 /* Do not lock when getting the callback value, here and below.
1912 * I suppose this is fine, since function cannot disappear in the
1913 * same way string option can. */
1914 if ((conn
->ctx
->callbacks
.log_message
== NULL
)
1915 || (conn
->ctx
->callbacks
.log_message(conn
, buf
) == 0)) {
1917 if (conn
->ctx
->config
[ERROR_LOG_FILE
] != NULL
) {
1918 if (mg_fopen(conn
, conn
->ctx
->config
[ERROR_LOG_FILE
], "a+", &fi
)
1926 if (fi
.fp
!= NULL
) {
1928 timestamp
= time(NULL
);
1930 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
1932 "[%010lu] [error] [client %s] ",
1933 (unsigned long)timestamp
,
1936 if (conn
->request_info
.request_method
!= NULL
) {
1939 conn
->request_info
.request_method
,
1940 conn
->request_info
.request_uri
);
1943 fprintf(fi
.fp
, "%s", buf
);
1953 mg_set_http_status(struct mg_connection
*conn
, int status
)
1955 conn
->status_code
= status
;
1958 /* Return fake connection structure. Used for logging, if connection
1959 * is not applicable at the moment of logging. */
1960 static struct mg_connection
*
1961 fc(struct mg_context
*ctx
)
1963 static struct mg_connection fake_connection
;
1964 fake_connection
.ctx
= ctx
;
1965 return &fake_connection
;
1972 return CIVETWEB_VERSION
;
1976 const struct mg_request_info
*
1977 mg_get_request_info(const struct mg_connection
*conn
)
1982 return &conn
->request_info
;
1987 mg_get_local_addr(struct mg_connection
*conn
)
1989 return &conn
->client
.lsa
.sa
;
1993 /* Skip the characters until one of the delimiters characters found.
1994 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
1995 * Advance pointer to buffer to the next word. Return found 0-terminated word.
1996 * Delimiters can be quoted with quotechar. */
1998 skip_quoted(char **buf
,
1999 const char *delimiters
,
2000 const char *whitespace
,
2003 char *p
, *begin_word
, *end_word
, *end_whitespace
;
2006 end_word
= begin_word
+ strcspn(begin_word
, delimiters
);
2008 /* Check for quotechar */
2009 if (end_word
> begin_word
) {
2011 while (*p
== quotechar
) {
2012 /* While the delimiter is quoted, look for the next delimiter. */
2013 /* This happens, e.g., in calls from parse_auth_header,
2014 * if the user name contains a " character. */
2016 /* If there is anything beyond end_word, copy it. */
2017 if (*end_word
!= '\0') {
2018 size_t end_off
= strcspn(end_word
+ 1, delimiters
);
2019 memmove(p
, end_word
, end_off
+ 1);
2020 p
+= end_off
; /* p must correspond to end_word - 1 */
2021 end_word
+= end_off
+ 1;
2027 for (p
++; p
< end_word
; p
++) {
2032 if (*end_word
== '\0') {
2035 end_whitespace
= end_word
+ 1 + strspn(end_word
+ 1, whitespace
);
2037 for (p
= end_word
; p
< end_whitespace
; p
++) {
2041 *buf
= end_whitespace
;
2048 /* Simplified version of skip_quoted without quote char
2049 * and whitespace == delimiters */
2051 skip(char **buf
, const char *delimiters
)
2053 return skip_quoted(buf
, delimiters
, delimiters
, 0);
2057 /* Return HTTP header value, or NULL if not found. */
2059 get_header(const struct mg_request_info
*ri
, const char *name
)
2063 for (i
= 0; i
< ri
->num_headers
; i
++) {
2064 if (!mg_strcasecmp(name
, ri
->http_headers
[i
].name
)) {
2065 return ri
->http_headers
[i
].value
;
2075 mg_get_header(const struct mg_connection
*conn
, const char *name
)
2081 return get_header(&conn
->request_info
, name
);
2085 /* A helper function for traversing a comma separated list of values.
2086 * It returns a list pointer shifted to the next value, or NULL if the end
2087 * of the list found.
2088 * Value is stored in val vector. If value has form "x=y", then eq_val
2089 * vector is initialized to point to the "y" part, and val vector length
2090 * is adjusted to point only to "x". */
2092 next_option(const char *list
, struct vec
*val
, struct vec
*eq_val
)
2097 if (val
== NULL
|| list
== NULL
|| *list
== '\0') {
2098 /* End of the list */
2101 /* Skip over leading LWS */
2102 while (*list
== ' ' || *list
== '\t')
2106 if ((list
= strchr(val
->ptr
, ',')) != NULL
) {
2107 /* Comma found. Store length and shift the list ptr */
2108 val
->len
= ((size_t)(list
- val
->ptr
));
2111 /* This value is the last one */
2112 list
= val
->ptr
+ strlen(val
->ptr
);
2113 val
->len
= ((size_t)(list
- val
->ptr
));
2116 /* Adjust length for trailing LWS */
2117 end
= (int)val
->len
- 1;
2118 while (end
>= 0 && (val
->ptr
[end
] == ' ' || val
->ptr
[end
] == '\t'))
2120 val
->len
= (size_t)(end
+ 1);
2122 if (val
->len
== 0) {
2123 /* Ignore any empty entries. */
2127 if (eq_val
!= NULL
) {
2128 /* Value has form "x=y", adjust pointers and lengths
2129 * so that val points to "x", and eq_val points to "y". */
2131 eq_val
->ptr
= (const char *)memchr(val
->ptr
, '=', val
->len
);
2132 if (eq_val
->ptr
!= NULL
) {
2133 eq_val
->ptr
++; /* Skip over '=' character */
2134 eq_val
->len
= ((size_t)(val
->ptr
- eq_val
->ptr
)) + val
->len
;
2135 val
->len
= ((size_t)(eq_val
->ptr
- val
->ptr
)) - 1;
2143 /* A helper function for checking if a comma separated list of values contains
2144 * the given option (case insensitvely).
2145 * 'header' can be NULL, in which case false is returned. */
2147 header_has_option(const char *header
, const char *option
)
2152 assert(option
!= NULL
);
2153 assert(option
[0] != '\0');
2155 while ((header
= next_option(header
, &opt_vec
, &eq_vec
)) != NULL
) {
2156 if (mg_strncasecmp(option
, opt_vec
.ptr
, opt_vec
.len
) == 0)
2163 /* Perform case-insensitive match of string against pattern */
2165 match_prefix(const char *pattern
, size_t pattern_len
, const char *str
)
2171 if ((or_str
= (const char *)memchr(pattern
, '|', pattern_len
)) != NULL
) {
2172 res
= match_prefix(pattern
, (size_t)(or_str
- pattern
), str
);
2173 return res
> 0 ? res
: match_prefix(or_str
+ 1,
2174 (size_t)((pattern
+ pattern_len
)
2179 for (i
= 0, j
= 0; i
< pattern_len
; i
++, j
++) {
2180 if (pattern
[i
] == '?' && str
[j
] != '\0') {
2182 } else if (pattern
[i
] == '$') {
2183 return str
[j
] == '\0' ? j
: -1;
2184 } else if (pattern
[i
] == '*') {
2186 if (pattern
[i
] == '*') {
2188 len
= (int)strlen(str
+ j
);
2190 len
= (int)strcspn(str
+ j
, "/");
2192 if (i
== pattern_len
) {
2196 res
= match_prefix(pattern
+ i
, pattern_len
- i
, str
+ j
+ len
);
2197 } while (res
== -1 && len
-- > 0);
2198 return res
== -1 ? -1 : j
+ res
+ len
;
2199 } else if (lowercase(&pattern
[i
]) != lowercase(&str
[j
])) {
2207 /* HTTP 1.1 assumes keep alive if "Connection:" header is not set
2208 * This function must tolerate situations when connection info is not
2209 * set up, for example if request parsing failed. */
2211 should_keep_alive(const struct mg_connection
*conn
)
2214 const char *http_version
= conn
->request_info
.http_version
;
2215 const char *header
= mg_get_header(conn
, "Connection");
2216 if (conn
->must_close
|| conn
->internal_error
|| conn
->status_code
== 401
2217 || mg_strcasecmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes") != 0
2218 || (header
!= NULL
&& !header_has_option(header
, "keep-alive"))
2219 || (header
== NULL
&& http_version
2220 && 0 != strcmp(http_version
, "1.1"))) {
2230 should_decode_url(const struct mg_connection
*conn
)
2232 if (!conn
|| !conn
->ctx
) {
2236 return (mg_strcasecmp(conn
->ctx
->config
[DECODE_URL
], "yes") == 0);
2240 should_validate_http_method(const struct mg_connection
*conn
)
2242 if (!conn
|| !conn
->ctx
|| !conn
->ctx
->config
[VALIDATE_HTTP_METHOD
]) {
2246 return (mg_strcasecmp(conn
->ctx
->config
[VALIDATE_HTTP_METHOD
], "yes") == 0);
2251 suggest_connection_header(const struct mg_connection
*conn
)
2253 return should_keep_alive(conn
) ? "keep-alive" : "close";
2258 send_no_cache_header(struct mg_connection
*conn
)
2260 /* Send all current and obsolete cache opt-out directives. */
2261 return mg_printf(conn
,
2262 "Cache-Control: no-cache, no-store, "
2263 "must-revalidate, private, max-age=0\r\n"
2264 "Pragma: no-cache\r\n"
2270 send_static_cache_header(struct mg_connection
*conn
)
2272 #if !defined(NO_CACHING)
2273 /* Read the server config to check how long a file may be cached.
2274 * The configuration is in seconds. */
2275 int max_age
= atoi(conn
->ctx
->config
[STATIC_FILE_MAX_AGE
]);
2277 /* 0 means "do not cache". All values <0 are reserved
2278 * and may be used differently in the future. */
2279 /* If a file should not be cached, do not only send
2280 * max-age=0, but also pragmas and Expires headers. */
2281 return send_no_cache_header(conn
);
2284 /* Use "Cache-Control: max-age" instead of "Expires" header.
2285 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
2286 /* See also https://www.mnot.net/cache_docs/ */
2287 /* According to RFC 2616, Section 14.21, caching times should not exceed
2288 * one year. A year with 365 days corresponds to 31536000 seconds, a leap
2289 * year to 31622400 seconds. For the moment, we just send whatever has
2290 * been configured, still the behavior for >1 year should be considered
2292 return mg_printf(conn
, "Cache-Control: max-age=%u\r\n", (unsigned)max_age
);
2293 #else /* NO_CACHING */
2294 return send_no_cache_header(conn
);
2295 #endif /* !NO_CACHING */
2299 static void handle_file_based_request(struct mg_connection
*conn
,
2301 struct file
*filep
);
2304 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
);
2308 mg_get_response_code_text(struct mg_connection
*conn
, int response_code
)
2310 /* See IANA HTTP status code assignment:
2311 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
2314 switch (response_code
) {
2315 /* RFC2616 Section 10.1 - Informational 1xx */
2317 return "Continue"; /* RFC2616 Section 10.1.1 */
2319 return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
2321 return "Processing"; /* RFC2518 Section 10.1 */
2323 /* RFC2616 Section 10.2 - Successful 2xx */
2325 return "OK"; /* RFC2616 Section 10.2.1 */
2327 return "Created"; /* RFC2616 Section 10.2.2 */
2329 return "Accepted"; /* RFC2616 Section 10.2.3 */
2331 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
2333 return "No Content"; /* RFC2616 Section 10.2.5 */
2335 return "Reset Content"; /* RFC2616 Section 10.2.6 */
2337 return "Partial Content"; /* RFC2616 Section 10.2.7 */
2339 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */
2341 return "Already Reported"; /* RFC5842 Section 7.1 */
2344 return "IM used"; /* RFC3229 Section 10.4.1 */
2346 /* RFC2616 Section 10.3 - Redirection 3xx */
2348 return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
2350 return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
2352 return "Found"; /* RFC2616 Section 10.3.3 */
2354 return "See Other"; /* RFC2616 Section 10.3.4 */
2356 return "Not Modified"; /* RFC2616 Section 10.3.5 */
2358 return "Use Proxy"; /* RFC2616 Section 10.3.6 */
2360 return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
2362 return "Permanent Redirect"; /* RFC7238 Section 3 */
2364 /* RFC2616 Section 10.4 - Client Error 4xx */
2366 return "Bad Request"; /* RFC2616 Section 10.4.1 */
2368 return "Unauthorized"; /* RFC2616 Section 10.4.2 */
2370 return "Payment Required"; /* RFC2616 Section 10.4.3 */
2372 return "Forbidden"; /* RFC2616 Section 10.4.4 */
2374 return "Not Found"; /* RFC2616 Section 10.4.5 */
2376 return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
2378 return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
2380 return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
2382 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
2384 return "Conflict"; /* RFC2616 Section 10.4.10 */
2386 return "Gone"; /* RFC2616 Section 10.4.11 */
2388 return "Length Required"; /* RFC2616 Section 10.4.12 */
2390 return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
2392 return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
2394 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
2396 return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
2398 return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */
2400 return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
2403 return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
2405 return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
2408 return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
2410 return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
2414 return "Upgrade Required"; /* RFC 2817 Section 4 */
2417 return "Precondition Required"; /* RFC 6585, Section 3 */
2419 return "Too Many Requests"; /* RFC 6585, Section 4 */
2422 return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
2425 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
2428 /* RFC2616 Section 10.5 - Server Error 5xx */
2430 return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
2432 return "Not Implemented"; /* RFC2616 Section 10.5.2 */
2434 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
2436 return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
2438 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
2440 return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
2442 return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
2444 return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
2447 return "Loop Detected"; /* RFC5842 Section 7.1 */
2450 return "Not Extended"; /* RFC 2774, Section 7 */
2452 return "Network Authentication Required"; /* RFC 6585, Section 6 */
2454 /* Other status codes, not shown in the IANA HTTP status code assignment.
2455 * E.g., "de facto" standards due to common use, ... */
2457 return "I am a teapot"; /* RFC2324 Section 2.3.2 */
2459 return "Authentication Timeout"; /* common use */
2461 return "Enhance Your Calm"; /* common use */
2463 return "Login Timeout"; /* common use */
2465 return "Bandwidth Limit Exceeded"; /* common use */
2468 /* This error code is unknown. This should not happen. */
2470 mg_cry(conn
, "Unknown HTTP response code: %u", response_code
);
2473 /* Return at least a category according to RFC 2616 Section 10. */
2474 if (response_code
>= 100 && response_code
< 200) {
2475 /* Unknown informational status code */
2476 return "Information";
2478 if (response_code
>= 200 && response_code
< 300) {
2479 /* Unknown success code */
2482 if (response_code
>= 300 && response_code
< 400) {
2483 /* Unknown redirection code */
2484 return "Redirection";
2486 if (response_code
>= 400 && response_code
< 500) {
2487 /* Unknown request error code */
2488 return "Client Error";
2490 if (response_code
>= 500 && response_code
< 600) {
2491 /* Unknown server error code */
2492 return "Server Error";
2495 /* Response code not even within reasonable range */
2501 static void send_http_error(struct mg_connection
*,
2503 PRINTF_FORMAT_STRING(const char *fmt
),
2504 ...) PRINTF_ARGS(3, 4);
2507 send_http_error(struct mg_connection
*conn
, int status
, const char *fmt
, ...)
2509 char buf
[MG_BUF_LEN
];
2511 int len
, i
, page_handler_found
, scope
, truncated
;
2513 time_t curtime
= time(NULL
);
2514 const char *error_handler
= NULL
;
2515 struct file error_page_file
= STRUCT_FILE_INITIALIZER
;
2516 const char *error_page_file_ext
, *tstr
;
2518 const char *status_text
= mg_get_response_code_text(conn
, status
);
2524 conn
->status_code
= status
;
2525 if (conn
->in_error_handler
|| conn
->ctx
->callbacks
.http_error
== NULL
2526 || conn
->ctx
->callbacks
.http_error(conn
, status
)) {
2527 if (!conn
->in_error_handler
) {
2528 /* Send user defined error pages, if defined */
2529 error_handler
= conn
->ctx
->config
[ERROR_PAGES
];
2530 error_page_file_ext
= conn
->ctx
->config
[INDEX_FILES
];
2531 page_handler_found
= 0;
2532 if (error_handler
!= NULL
) {
2533 for (scope
= 1; (scope
<= 3) && !page_handler_found
; scope
++) {
2535 case 1: /* Handler for specific error, e.g. 404 error */
2544 case 2: /* Handler for error group, e.g., 5xx error handler
2545 * for all server errors (500-599) */
2554 default: /* Handler for all errors */
2564 /* String truncation in buf may only occur if error_handler
2565 * is too long. This string is from the config, not from a
2569 len
= (int)strlen(buf
);
2571 tstr
= strchr(error_page_file_ext
, '.');
2574 for (i
= 1; i
< 32 && tstr
[i
] != 0 && tstr
[i
] != ',';
2576 buf
[len
+ i
- 1] = tstr
[i
];
2577 buf
[len
+ i
- 1] = 0;
2578 if (mg_stat(conn
, buf
, &error_page_file
)) {
2579 page_handler_found
= 1;
2582 tstr
= strchr(tstr
+ i
, '.');
2587 if (page_handler_found
) {
2588 conn
->in_error_handler
= 1;
2589 handle_file_based_request(conn
, buf
, &error_page_file
);
2590 conn
->in_error_handler
= 0;
2595 /* No custom error page. Send default error page. */
2596 gmt_time_string(date
, sizeof(date
), &curtime
);
2598 conn
->must_close
= 1;
2599 mg_printf(conn
, "HTTP/1.1 %d %s\r\n", status
, status_text
);
2600 send_no_cache_header(conn
);
2603 "Connection: close\r\n\r\n",
2606 /* Errors 1xx, 204 and 304 MUST NOT send a body */
2607 if (status
> 199 && status
!= 204 && status
!= 304) {
2609 mg_printf(conn
, "Error %d: %s\n", status
, status_text
);
2613 mg_vsnprintf(conn
, NULL
, buf
, sizeof(buf
), fmt
, ap
);
2615 mg_write(conn
, buf
, strlen(buf
));
2616 DEBUG_TRACE("Error %i - [%s]", status
, buf
);
2620 /* No body allowed. Close the connection. */
2621 DEBUG_TRACE("Error %i", status
);
2626 #if defined(_WIN32) && !defined(__SYMBIAN32__)
2627 /* Create substitutes for POSIX functions in Win32. */
2629 #if defined(__MINGW32__)
2630 /* Show no warning in case system functions are not used. */
2631 #pragma GCC diagnostic push
2632 #pragma GCC diagnostic ignored "-Wunused-function"
2637 pthread_mutex_init(pthread_mutex_t
*mutex
, void *unused
)
2640 *mutex
= CreateMutex(NULL
, FALSE
, NULL
);
2641 return *mutex
== NULL
? -1 : 0;
2646 pthread_mutex_destroy(pthread_mutex_t
*mutex
)
2648 return CloseHandle(*mutex
) == 0 ? -1 : 0;
2653 pthread_mutex_lock(pthread_mutex_t
*mutex
)
2655 return WaitForSingleObject(*mutex
, INFINITE
) == WAIT_OBJECT_0
? 0 : -1;
2659 #ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
2661 pthread_mutex_trylock(pthread_mutex_t
*mutex
)
2663 switch (WaitForSingleObject(*mutex
, 0)) {
2667 return -2; /* EBUSY */
2675 pthread_mutex_unlock(pthread_mutex_t
*mutex
)
2677 return ReleaseMutex(*mutex
) == 0 ? -1 : 0;
2681 #ifndef WIN_PTHREADS_TIME_H
2683 clock_gettime(clockid_t clk_id
, struct timespec
*tp
)
2689 static double perfcnt_per_sec
= 0.0;
2692 memset(tp
, 0, sizeof(*tp
));
2693 if (clk_id
== CLOCK_REALTIME
) {
2694 GetSystemTimeAsFileTime(&ft
);
2695 li
.LowPart
= ft
.dwLowDateTime
;
2696 li
.HighPart
= ft
.dwHighDateTime
;
2697 li
.QuadPart
-= 116444736000000000; /* 1.1.1970 in filedate */
2698 tp
->tv_sec
= (time_t)(li
.QuadPart
/ 10000000);
2699 tp
->tv_nsec
= (long)(li
.QuadPart
% 10000000) * 100;
2701 } else if (clk_id
== CLOCK_MONOTONIC
) {
2702 if (perfcnt_per_sec
== 0.0) {
2703 QueryPerformanceFrequency((LARGE_INTEGER
*)&li
);
2704 perfcnt_per_sec
= 1.0 / li
.QuadPart
;
2706 if (perfcnt_per_sec
!= 0.0) {
2707 QueryPerformanceCounter((LARGE_INTEGER
*)&li
);
2708 d
= li
.QuadPart
* perfcnt_per_sec
;
2709 tp
->tv_sec
= (time_t)d
;
2711 tp
->tv_nsec
= (long)(d
* 1.0E9
);
2723 pthread_cond_init(pthread_cond_t
*cv
, const void *unused
)
2726 InitializeCriticalSection(&cv
->threadIdSec
);
2727 cv
->waitingthreadcount
= 0;
2728 cv
->waitingthreadhdls
=
2729 (pthread_t
*)mg_calloc(MAX_WORKER_THREADS
, sizeof(pthread_t
));
2730 return (cv
->waitingthreadhdls
!= NULL
) ? 0 : -1;
2735 pthread_cond_timedwait(pthread_cond_t
*cv
,
2736 pthread_mutex_t
*mutex
,
2737 const struct timespec
*abstime
)
2739 struct mg_workerTLS
*tls
=
2740 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
2742 struct timespec tsnow
;
2743 int64_t nsnow
, nswaitabs
, nswaitrel
;
2746 EnterCriticalSection(&cv
->threadIdSec
);
2747 assert(cv
->waitingthreadcount
< MAX_WORKER_THREADS
);
2748 cv
->waitingthreadhdls
[cv
->waitingthreadcount
] =
2749 tls
->pthread_cond_helper_mutex
;
2750 cv
->waitingthreadcount
++;
2751 LeaveCriticalSection(&cv
->threadIdSec
);
2754 clock_gettime(CLOCK_REALTIME
, &tsnow
);
2755 nsnow
= (((int64_t)tsnow
.tv_sec
) * 1000000000) + tsnow
.tv_nsec
;
2757 (((int64_t)abstime
->tv_sec
) * 1000000000) + abstime
->tv_nsec
;
2758 nswaitrel
= nswaitabs
- nsnow
;
2759 if (nswaitrel
< 0) {
2762 mswaitrel
= (DWORD
)(nswaitrel
/ 1000000);
2764 mswaitrel
= INFINITE
;
2767 pthread_mutex_unlock(mutex
);
2769 == WaitForSingleObject(tls
->pthread_cond_helper_mutex
, mswaitrel
));
2770 pthread_mutex_lock(mutex
);
2777 pthread_cond_wait(pthread_cond_t
*cv
, pthread_mutex_t
*mutex
)
2779 return pthread_cond_timedwait(cv
, mutex
, NULL
);
2784 pthread_cond_signal(pthread_cond_t
*cv
)
2790 EnterCriticalSection(&cv
->threadIdSec
);
2791 if (cv
->waitingthreadcount
) {
2792 wkup
= cv
->waitingthreadhdls
[0];
2793 ok
= SetEvent(wkup
);
2795 for (i
= 1; i
< cv
->waitingthreadcount
; i
++) {
2796 cv
->waitingthreadhdls
[i
- 1] = cv
->waitingthreadhdls
[i
];
2798 cv
->waitingthreadcount
--;
2802 LeaveCriticalSection(&cv
->threadIdSec
);
2809 pthread_cond_broadcast(pthread_cond_t
*cv
)
2811 EnterCriticalSection(&cv
->threadIdSec
);
2812 while (cv
->waitingthreadcount
) {
2813 pthread_cond_signal(cv
);
2815 LeaveCriticalSection(&cv
->threadIdSec
);
2822 pthread_cond_destroy(pthread_cond_t
*cv
)
2824 EnterCriticalSection(&cv
->threadIdSec
);
2825 assert(cv
->waitingthreadcount
== 0);
2826 mg_free(cv
->waitingthreadhdls
);
2827 cv
->waitingthreadhdls
= 0;
2828 LeaveCriticalSection(&cv
->threadIdSec
);
2829 DeleteCriticalSection(&cv
->threadIdSec
);
2835 #if defined(__MINGW32__)
2836 /* Enable unused function warning again */
2837 #pragma GCC diagnostic pop
2841 /* For Windows, change all slashes to backslashes in path names. */
2843 change_slashes_to_backslashes(char *path
)
2847 for (i
= 0; path
[i
] != '\0'; i
++) {
2848 if (path
[i
] == '/') {
2852 /* remove double backslash (check i > 0 to preserve UNC paths,
2853 * like \\server\file.txt) */
2854 if ((path
[i
] == '\\') && (i
> 0)) {
2855 while (path
[i
+ 1] == '\\' || path
[i
+ 1] == '/') {
2856 (void)memmove(path
+ i
+ 1, path
+ i
+ 2, strlen(path
+ i
+ 1));
2864 mg_wcscasecmp(const wchar_t *s1
, const wchar_t *s2
)
2869 diff
= tolower(*s1
) - tolower(*s2
);
2872 } while (diff
== 0 && s1
[-1] != '\0');
2878 /* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
2879 * wbuf and wbuf_len is a target buffer and its length. */
2881 path_to_unicode(const struct mg_connection
*conn
,
2886 char buf
[PATH_MAX
], buf2
[PATH_MAX
];
2887 wchar_t wbuf2
[MAX_PATH
+ 1];
2888 DWORD long_len
, err
;
2889 int (*fcompare
)(const wchar_t *, const wchar_t *) = mg_wcscasecmp
;
2891 mg_strlcpy(buf
, path
, sizeof(buf
));
2892 change_slashes_to_backslashes(buf
);
2894 /* Convert to Unicode and back. If doubly-converted string does not
2895 * match the original, something is fishy, reject. */
2896 memset(wbuf
, 0, wbuf_len
* sizeof(wchar_t));
2897 MultiByteToWideChar(CP_UTF8
, 0, buf
, -1, wbuf
, (int)wbuf_len
);
2898 WideCharToMultiByte(
2899 CP_UTF8
, 0, wbuf
, (int)wbuf_len
, buf2
, sizeof(buf2
), NULL
, NULL
);
2900 if (strcmp(buf
, buf2
) != 0) {
2904 /* TODO: Add a configuration to switch between case sensitive and
2905 * case insensitive URIs for Windows server. */
2908 if (conn->ctx->config[WINDOWS_CASE_SENSITIVE]) {
2913 (void)conn
; /* conn is currently unused */
2915 /* Only accept a full file path, not a Windows short (8.3) path. */
2916 memset(wbuf2
, 0, ARRAY_SIZE(wbuf2
) * sizeof(wchar_t));
2917 long_len
= GetLongPathNameW(wbuf
, wbuf2
, ARRAY_SIZE(wbuf2
) - 1);
2918 if (long_len
== 0) {
2919 err
= GetLastError();
2920 if (err
== ERROR_FILE_NOT_FOUND
) {
2921 /* File does not exist. This is not always a problem here. */
2925 if ((long_len
>= ARRAY_SIZE(wbuf2
)) || (fcompare(wbuf
, wbuf2
) != 0)) {
2926 /* Short name is used. */
2932 #if defined(_WIN32_WCE)
2933 /* Create substitutes for POSIX functions in Win32. */
2935 #if defined(__MINGW32__)
2936 /* Show no warning in case system functions are not used. */
2937 #pragma GCC diagnostic push
2938 #pragma GCC diagnostic ignored "-Wunused-function"
2950 SystemTimeToFileTime(&st
, &ft
);
2951 t
= SYS2UNIX_TIME(ft
.dwLowDateTime
, ft
.dwHighDateTime
);
2953 if (ptime
!= NULL
) {
2962 localtime(const time_t *ptime
, struct tm
*ptm
)
2964 int64_t t
= ((int64_t)*ptime
) * RATE_DIFF
+ EPOCH_DIFF
;
2967 TIME_ZONE_INFORMATION tzinfo
;
2973 *(int64_t *)&ft
= t
;
2974 FileTimeToLocalFileTime(&ft
, &lft
);
2975 FileTimeToSystemTime(&lft
, &st
);
2976 ptm
->tm_year
= st
.wYear
- 1900;
2977 ptm
->tm_mon
= st
.wMonth
- 1;
2978 ptm
->tm_wday
= st
.wDayOfWeek
;
2979 ptm
->tm_mday
= st
.wDay
;
2980 ptm
->tm_hour
= st
.wHour
;
2981 ptm
->tm_min
= st
.wMinute
;
2982 ptm
->tm_sec
= st
.wSecond
;
2983 ptm
->tm_yday
= 0; /* hope nobody uses this */
2985 GetTimeZoneInformation(&tzinfo
) == TIME_ZONE_ID_DAYLIGHT
? 1 : 0;
2992 gmtime(const time_t *ptime
, struct tm
*ptm
)
2994 /* FIXME(lsm): fix this. */
2995 return localtime(ptime
, ptm
);
3000 strftime(char *dst
, size_t dst_size
, const char *fmt
, const struct tm
*tm
)
3002 (void)mg_snprintf(NULL
, dst
, dst_size
, "implement strftime() for WinCE");
3007 #if defined(__MINGW32__)
3008 /* Enable unused function warning again */
3009 #pragma GCC diagnostic pop
3015 /* Windows happily opens files with some garbage at the end of file name.
3016 * For example, fopen("a.cgi ", "r") on Windows successfully opens
3017 * "a.cgi", despite one would expect an error back.
3018 * This function returns non-0 if path ends with some garbage. */
3020 path_cannot_disclose_cgi(const char *path
)
3022 static const char *allowed_last_characters
= "_-";
3023 int last
= path
[strlen(path
) - 1];
3024 return isalnum(last
) || strchr(allowed_last_characters
, last
) != NULL
;
3029 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3031 wchar_t wbuf
[PATH_MAX
];
3032 WIN32_FILE_ATTRIBUTE_DATA info
;
3033 time_t creation_time
;
3038 memset(filep
, 0, sizeof(*filep
));
3040 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3041 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
3043 filep
->last_modified
= time(NULL
);
3044 /* last_modified = now ... assumes the file may change during runtime,
3045 * so every mg_fopen call may return different data */
3046 /* last_modified = conn->ctx.start_time;
3047 * May be used it the data does not change during runtime. This allows
3048 * browser caching. Since we do not know, we have to assume the file
3049 * in memory may change. */
3053 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3054 if (GetFileAttributesExW(wbuf
, GetFileExInfoStandard
, &info
) != 0) {
3055 filep
->size
= MAKEUQUAD(info
.nFileSizeLow
, info
.nFileSizeHigh
);
3056 filep
->last_modified
=
3057 SYS2UNIX_TIME(info
.ftLastWriteTime
.dwLowDateTime
,
3058 info
.ftLastWriteTime
.dwHighDateTime
);
3060 /* On Windows, the file creation time can be higher than the
3061 * modification time, e.g. when a file is copied.
3062 * Since the Last-Modified timestamp is used for caching
3063 * it should be based on the most recent timestamp. */
3064 creation_time
= SYS2UNIX_TIME(info
.ftCreationTime
.dwLowDateTime
,
3065 info
.ftCreationTime
.dwHighDateTime
);
3066 if (creation_time
> filep
->last_modified
) {
3067 filep
->last_modified
= creation_time
;
3070 filep
->is_directory
= info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
;
3071 /* If file name is fishy, reset the file structure and return
3073 * Note it is important to reset, not just return the error, cause
3074 * functions like is_file_opened() check the struct. */
3075 if (!filep
->is_directory
&& !path_cannot_disclose_cgi(path
)) {
3076 memset(filep
, 0, sizeof(*filep
));
3088 mg_remove(const struct mg_connection
*conn
, const char *path
)
3090 wchar_t wbuf
[PATH_MAX
];
3091 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3092 return DeleteFileW(wbuf
) ? 0 : -1;
3097 mg_mkdir(const struct mg_connection
*conn
, const char *path
, int mode
)
3099 wchar_t wbuf
[PATH_MAX
];
3101 path_to_unicode(conn
, path
, wbuf
, ARRAY_SIZE(wbuf
));
3102 return CreateDirectoryW(wbuf
, NULL
) ? 0 : -1;
3106 /* Create substitutes for POSIX functions in Win32. */
3108 #if defined(__MINGW32__)
3109 /* Show no warning in case system functions are not used. */
3110 #pragma GCC diagnostic push
3111 #pragma GCC diagnostic ignored "-Wunused-function"
3115 /* Implementation of POSIX opendir/closedir/readdir for Windows. */
3117 mg_opendir(const struct mg_connection
*conn
, const char *name
)
3120 wchar_t wpath
[PATH_MAX
];
3124 SetLastError(ERROR_BAD_ARGUMENTS
);
3125 } else if ((dir
= (DIR *)mg_malloc(sizeof(*dir
))) == NULL
) {
3126 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
3128 path_to_unicode(conn
, name
, wpath
, ARRAY_SIZE(wpath
));
3129 attrs
= GetFileAttributesW(wpath
);
3130 if (attrs
!= 0xFFFFFFFF && ((attrs
& FILE_ATTRIBUTE_DIRECTORY
)
3131 == FILE_ATTRIBUTE_DIRECTORY
)) {
3132 (void)wcscat(wpath
, L
"\\*");
3133 dir
->handle
= FindFirstFileW(wpath
, &dir
->info
);
3134 dir
->result
.d_name
[0] = '\0';
3146 mg_closedir(DIR *dir
)
3151 if (dir
->handle
!= INVALID_HANDLE_VALUE
)
3152 result
= FindClose(dir
->handle
) ? 0 : -1;
3157 SetLastError(ERROR_BAD_ARGUMENTS
);
3164 static struct dirent
*
3165 mg_readdir(DIR *dir
)
3167 struct dirent
*result
= 0;
3170 if (dir
->handle
!= INVALID_HANDLE_VALUE
) {
3171 result
= &dir
->result
;
3172 (void)WideCharToMultiByte(CP_UTF8
,
3174 dir
->info
.cFileName
,
3177 sizeof(result
->d_name
),
3181 if (!FindNextFileW(dir
->handle
, &dir
->info
)) {
3182 (void)FindClose(dir
->handle
);
3183 dir
->handle
= INVALID_HANDLE_VALUE
;
3187 SetLastError(ERROR_FILE_NOT_FOUND
);
3190 SetLastError(ERROR_BAD_ARGUMENTS
);
3199 poll(struct pollfd
*pfd
, unsigned int n
, int milliseconds
)
3207 memset(&tv
, 0, sizeof(tv
));
3208 tv
.tv_sec
= milliseconds
/ 1000;
3209 tv
.tv_usec
= (milliseconds
% 1000) * 1000;
3212 for (i
= 0; i
< n
; i
++) {
3213 FD_SET((SOCKET
)pfd
[i
].fd
, &set
);
3216 if (pfd
[i
].fd
> maxfd
) {
3221 if ((result
= select((int)maxfd
+ 1, &set
, NULL
, NULL
, &tv
)) > 0) {
3222 for (i
= 0; i
< n
; i
++) {
3223 if (FD_ISSET(pfd
[i
].fd
, &set
)) {
3224 pfd
[i
].revents
= POLLIN
;
3231 #endif /* HAVE_POLL */
3233 #if defined(__MINGW32__)
3234 /* Enable unused function warning again */
3235 #pragma GCC diagnostic pop
3240 set_close_on_exec(SOCKET sock
, struct mg_connection
*conn
/* may be null */)
3242 (void)conn
; /* Unused. */
3243 (void)SetHandleInformation((HANDLE
)(intptr_t)sock
, HANDLE_FLAG_INHERIT
, 0);
3248 mg_start_thread(mg_thread_func_t f
, void *p
)
3250 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3251 /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
3253 return ((_beginthread((void(__cdecl
*)(void *))f
, USE_STACK_SIZE
, p
)
3254 == ((uintptr_t)(-1L)))
3259 (_beginthread((void(__cdecl
*)(void *))f
, 0, p
) == ((uintptr_t)(-1L)))
3262 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3266 /* Start a thread storing the thread context. */
3268 mg_start_thread_with_id(unsigned(__stdcall
*f
)(void *),
3270 pthread_t
*threadidptr
)
3273 HANDLE threadhandle
;
3276 uip
= _beginthreadex(NULL
, 0, (unsigned(__stdcall
*)(void *))f
, p
, 0, NULL
);
3277 threadhandle
= (HANDLE
)uip
;
3278 if ((uip
!= (uintptr_t)(-1L)) && (threadidptr
!= NULL
)) {
3279 *threadidptr
= threadhandle
;
3287 /* Wait for a thread to finish. */
3289 mg_join_thread(pthread_t threadid
)
3295 dwevent
= WaitForSingleObject(threadid
, INFINITE
);
3296 if (dwevent
== WAIT_FAILED
) {
3297 DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO
);
3299 if (dwevent
== WAIT_OBJECT_0
) {
3300 CloseHandle(threadid
);
3308 #if !defined(NO_SSL_DL)
3309 /* Create substitutes for POSIX functions in Win32. */
3311 #if defined(__MINGW32__)
3312 /* Show no warning in case system functions are not used. */
3313 #pragma GCC diagnostic push
3314 #pragma GCC diagnostic ignored "-Wunused-function"
3319 dlopen(const char *dll_name
, int flags
)
3321 wchar_t wbuf
[PATH_MAX
];
3323 path_to_unicode(NULL
, dll_name
, wbuf
, ARRAY_SIZE(wbuf
));
3324 return LoadLibraryW(wbuf
);
3329 dlclose(void *handle
)
3333 if (FreeLibrary((HMODULE
)handle
) != 0) {
3343 #if defined(__MINGW32__)
3344 /* Enable unused function warning again */
3345 #pragma GCC diagnostic pop
3351 #if !defined(NO_CGI)
3355 kill(pid_t pid
, int sig_num
)
3357 (void)TerminateProcess((HANDLE
)pid
, (UINT
)sig_num
);
3358 (void)CloseHandle((HANDLE
)pid
);
3364 trim_trailing_whitespaces(char *s
)
3366 char *e
= s
+ strlen(s
) - 1;
3367 while (e
> s
&& isspace(*(unsigned char *)e
)) {
3374 spawn_process(struct mg_connection
*conn
,
3384 char *p
, *interp
, full_interp
[PATH_MAX
], full_dir
[PATH_MAX
],
3385 cmdline
[PATH_MAX
], buf
[PATH_MAX
];
3387 struct file file
= STRUCT_FILE_INITIALIZER
;
3389 PROCESS_INFORMATION pi
= {0};
3393 memset(&si
, 0, sizeof(si
));
3396 si
.dwFlags
= STARTF_USESTDHANDLES
| STARTF_USESHOWWINDOW
;
3397 si
.wShowWindow
= SW_HIDE
;
3399 me
= GetCurrentProcess();
3401 (HANDLE
)_get_osfhandle(fdin
[0]),
3406 DUPLICATE_SAME_ACCESS
);
3408 (HANDLE
)_get_osfhandle(fdout
[1]),
3413 DUPLICATE_SAME_ACCESS
);
3415 (HANDLE
)_get_osfhandle(fderr
[1]),
3420 DUPLICATE_SAME_ACCESS
);
3422 /* Mark handles that should not be inherited. See
3423 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
3425 SetHandleInformation((HANDLE
)_get_osfhandle(fdin
[1]),
3426 HANDLE_FLAG_INHERIT
,
3428 SetHandleInformation((HANDLE
)_get_osfhandle(fdout
[0]),
3429 HANDLE_FLAG_INHERIT
,
3431 SetHandleInformation((HANDLE
)_get_osfhandle(fderr
[0]),
3432 HANDLE_FLAG_INHERIT
,
3435 /* If CGI file is a script, try to read the interpreter line */
3436 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3437 if (interp
== NULL
) {
3438 buf
[0] = buf
[1] = '\0';
3440 /* Read the first line of the script into the buffer */
3442 conn
, &truncated
, cmdline
, sizeof(cmdline
), "%s/%s", dir
, prog
);
3445 pi
.hProcess
= (pid_t
)-1;
3449 if (mg_fopen(conn
, cmdline
, "r", &file
)) {
3450 p
= (char *)file
.membuf
;
3451 mg_fgets(buf
, sizeof(buf
), &file
, &p
);
3453 buf
[sizeof(buf
) - 1] = '\0';
3456 if (buf
[0] == '#' && buf
[1] == '!') {
3457 trim_trailing_whitespaces(buf
+ 2);
3464 if (interp
[0] != '\0') {
3465 GetFullPathNameA(interp
, sizeof(full_interp
), full_interp
, NULL
);
3466 interp
= full_interp
;
3468 GetFullPathNameA(dir
, sizeof(full_dir
), full_dir
, NULL
);
3470 if (interp
[0] != '\0') {
3475 "\"%s\" \"%s\\%s\"",
3490 pi
.hProcess
= (pid_t
)-1;
3494 DEBUG_TRACE("Running [%s]", cmdline
);
3495 if (CreateProcessA(NULL
,
3500 CREATE_NEW_PROCESS_GROUP
,
3506 conn
, "%s: CreateProcess(%s): %ld", __func__
, cmdline
, (long)ERRNO
);
3507 pi
.hProcess
= (pid_t
)-1;
3508 /* goto spawn_cleanup; */
3512 (void)CloseHandle(si
.hStdOutput
);
3513 (void)CloseHandle(si
.hStdError
);
3514 (void)CloseHandle(si
.hStdInput
);
3515 if (pi
.hThread
!= NULL
) {
3516 (void)CloseHandle(pi
.hThread
);
3519 return (pid_t
)pi
.hProcess
;
3521 #endif /* !NO_CGI */
3525 set_non_blocking_mode(SOCKET sock
)
3527 unsigned long on
= 1;
3528 return ioctlsocket(sock
, (long)FIONBIO
, &on
);
3534 mg_stat(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
3540 memset(filep
, 0, sizeof(*filep
));
3542 if (conn
&& is_file_in_memory(conn
, path
, filep
)) {
3546 if (0 == stat(path
, &st
)) {
3547 filep
->size
= (uint64_t)(st
.st_size
);
3548 filep
->last_modified
= st
.st_mtime
;
3549 filep
->is_directory
= S_ISDIR(st
.st_mode
);
3558 set_close_on_exec(SOCKET fd
, struct mg_connection
*conn
/* may be null */)
3560 if (fcntl(fd
, F_SETFD
, FD_CLOEXEC
) != 0) {
3563 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
3572 mg_start_thread(mg_thread_func_t func
, void *param
)
3574 pthread_t thread_id
;
3575 pthread_attr_t attr
;
3578 (void)pthread_attr_init(&attr
);
3579 (void)pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
3581 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3582 /* Compile-time option to control stack size,
3583 * e.g. -DUSE_STACK_SIZE=16384 */
3584 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3585 #endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
3587 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3588 pthread_attr_destroy(&attr
);
3594 /* Start a thread storing the thread context. */
3596 mg_start_thread_with_id(mg_thread_func_t func
,
3598 pthread_t
*threadidptr
)
3600 pthread_t thread_id
;
3601 pthread_attr_t attr
;
3604 (void)pthread_attr_init(&attr
);
3606 #if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
3607 /* Compile-time option to control stack size,
3608 * e.g. -DUSE_STACK_SIZE=16384 */
3609 (void)pthread_attr_setstacksize(&attr
, USE_STACK_SIZE
);
3610 #endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
3612 result
= pthread_create(&thread_id
, &attr
, func
, param
);
3613 pthread_attr_destroy(&attr
);
3614 if ((result
== 0) && (threadidptr
!= NULL
)) {
3615 *threadidptr
= thread_id
;
3621 /* Wait for a thread to finish. */
3623 mg_join_thread(pthread_t threadid
)
3627 result
= pthread_join(threadid
, NULL
);
3634 spawn_process(struct mg_connection
*conn
,
3652 if ((pid
= fork()) == -1) {
3654 send_http_error(conn
,
3656 "Error: Creating CGI process\nfork(): %s",
3658 } else if (pid
== 0) {
3660 if (chdir(dir
) != 0) {
3661 mg_cry(conn
, "%s: chdir(%s): %s", __func__
, dir
, strerror(ERRNO
));
3662 } else if (dup2(fdin
[0], 0) == -1) {
3664 "%s: dup2(%d, 0): %s",
3668 } else if (dup2(fdout
[1], 1) == -1) {
3670 "%s: dup2(%d, 1): %s",
3674 } else if (dup2(fderr
[1], 2) == -1) {
3676 "%s: dup2(%d, 2): %s",
3681 /* Keep stderr and stdout in two different pipes.
3682 * Stdout will be sent back to the client,
3683 * stderr should go into a server error log. */
3684 (void)close(fdin
[0]);
3685 (void)close(fdout
[1]);
3686 (void)close(fderr
[1]);
3688 /* Close write end fdin and read end fdout and fderr */
3689 (void)close(fdin
[1]);
3690 (void)close(fdout
[0]);
3691 (void)close(fderr
[0]);
3693 /* After exec, all signal handlers are restored to their default
3694 * values, with one exception of SIGCHLD. According to
3695 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
3696 * leave unchanged after exec if it was set to be ignored. Restore
3697 * it to default action. */
3698 signal(SIGCHLD
, SIG_DFL
);
3700 interp
= conn
->ctx
->config
[CGI_INTERPRETER
];
3701 if (interp
== NULL
) {
3702 (void)execle(prog
, prog
, NULL
, envp
);
3704 "%s: execle(%s): %s",
3709 (void)execle(interp
, interp
, prog
, NULL
, envp
);
3711 "%s: execle(%s %s): %s",
3723 #endif /* !NO_CGI */
3727 set_non_blocking_mode(SOCKET sock
)
3731 flags
= fcntl(sock
, F_GETFL
, 0);
3732 (void)fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
3737 /* End of initial operating system specific define block. */
3740 /* Get a random number (independent of C rand function) */
3744 static uint64_t lfsr
= 0; /* Linear feedback shift register */
3745 static uint64_t lcg
= 0; /* Linear congruential generator */
3746 struct timespec now
;
3748 memset(&now
, 0, sizeof(now
));
3749 clock_gettime(CLOCK_MONOTONIC
, &now
);
3752 /* lfsr will be only 0 if has not been initialized,
3753 * so this code is called only once. */
3754 lfsr
= (((uint64_t)now
.tv_sec
) << 21) ^ ((uint64_t)now
.tv_nsec
)
3755 ^ ((uint64_t)(ptrdiff_t)&now
) ^ (((uint64_t)time(NULL
)) << 33);
3756 lcg
= (((uint64_t)now
.tv_sec
) << 25) + (uint64_t)now
.tv_nsec
3757 + (uint64_t)(ptrdiff_t)&now
;
3759 /* Get the next step of both random number generators. */
3761 | ((((lfsr
>> 0) ^ (lfsr
>> 1) ^ (lfsr
>> 3) ^ (lfsr
>> 4)) & 1)
3763 lcg
= lcg
* 6364136223846793005 + 1442695040888963407;
3766 /* Combining two pseudo-random number generators and a high resolution part
3767 * of the current server time will make it hard (impossible?) to guess the
3769 return (lfsr
^ lcg
^ (uint64_t)now
.tv_nsec
);
3773 /* Write data to the IO channel - opened file descriptor, socket or SSL
3774 * descriptor. Return number of bytes written. */
3776 push(struct mg_context
*ctx
,
3784 struct timespec start
, now
;
3790 typedef size_t len_t
;
3794 memset(&start
, 0, sizeof(start
));
3795 memset(&now
, 0, sizeof(now
));
3796 clock_gettime(CLOCK_MONOTONIC
, &start
);
3813 n
= SSL_write(ssl
, buf
, len
);
3815 err
= SSL_get_error(ssl
, n
);
3816 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (n
== -1)) {
3819 DEBUG_TRACE("SSL_write() failed, error %d", err
);
3828 n
= (int)fwrite(buf
, 1, (size_t)len
, fp
);
3836 n
= (int)send(sock
, buf
, (len_t
)len
, MSG_NOSIGNAL
);
3837 err
= (n
< 0) ? ERRNO
: 0;
3840 if (ctx
->stop_flag
) {
3844 if ((n
> 0) || (n
== 0 && len
== 0)) {
3845 /* some data has been read, or no data was requested */
3849 /* shutdown of the socket at client side */
3853 /* socket error - check errno */
3854 DEBUG_TRACE("send() failed, error %d", err
);
3856 /* TODO: error handling depending on the error code.
3857 * These codes are different between Windows and Linux.
3862 /* This code is not reached in the moment.
3863 * ==> Fix the TODOs above first. */
3866 clock_gettime(CLOCK_MONOTONIC
, &now
);
3869 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
3871 (void)err
; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
3879 push_all(struct mg_context
*ctx
,
3886 double timeout
= -1.0;
3887 int64_t n
, nwritten
= 0;
3893 if (ctx
->config
[REQUEST_TIMEOUT
]) {
3894 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
3897 while (len
> 0 && ctx
->stop_flag
== 0) {
3898 n
= push(ctx
, fp
, sock
, ssl
, buf
+ nwritten
, (int)len
, timeout
);
3900 if (nwritten
== 0) {
3901 nwritten
= n
; /* Propagate the error */
3904 } else if (n
== 0) {
3905 break; /* No more data to write */
3916 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
3917 * Return negative value on error, or number of bytes read on success. */
3919 pull(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
, double timeout
)
3922 struct timespec start
, now
;
3927 typedef size_t len_t
;
3931 memset(&start
, 0, sizeof(start
));
3932 memset(&now
, 0, sizeof(now
));
3933 clock_gettime(CLOCK_MONOTONIC
, &start
);
3938 /* Use read() instead of fread(), because if we're reading from the
3939 * CGI pipe, fread() may block until IO buffer is filled up. We
3940 * cannot afford to block and must pass all read bytes immediately
3942 nread
= (int)read(fileno(fp
), buf
, (size_t)len
);
3943 err
= (nread
< 0) ? ERRNO
: 0;
3946 } else if (conn
->ssl
!= NULL
) {
3947 nread
= SSL_read(conn
->ssl
, buf
, len
);
3949 err
= SSL_get_error(conn
->ssl
, nread
);
3950 if ((err
== 5 /* SSL_ERROR_SYSCALL */) && (nread
== -1)) {
3953 DEBUG_TRACE("SSL_read() failed, error %d", err
);
3962 nread
= (int)recv(conn
->client
.sock
, buf
, (len_t
)len
, 0);
3963 err
= (nread
< 0) ? ERRNO
: 0;
3966 if (conn
->ctx
->stop_flag
) {
3970 if ((nread
> 0) || (nread
== 0 && len
== 0)) {
3971 /* some data has been read, or no data was requested */
3975 /* shutdown of the socket at client side */
3979 /* socket error - check errno */
3981 if (err
== WSAEWOULDBLOCK
) {
3982 /* standard case if called from close_socket_gracefully */
3984 } else if (err
== WSAETIMEDOUT
) {
3985 /* timeout is handled by the while loop */
3987 DEBUG_TRACE("recv() failed, error %d", err
);
3991 /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
3992 * if the timeout is reached and if the socket was set to non-
3993 * blocking in close_socket_gracefully, so we can not distinguish
3994 * here. We have to wait for the timeout in both cases for now.
3996 if (err
== EAGAIN
|| err
== EWOULDBLOCK
|| err
== EINTR
) {
3997 /* EAGAIN/EWOULDBLOCK:
3998 * standard case if called from close_socket_gracefully
3999 * => should return -1 */
4000 /* or timeout occured
4001 * => the code must stay in the while loop */
4003 /* EINTR can be generated on a socket with a timeout set even
4004 * when SA_RESTART is effective for all relevant signals
4006 * => stay in the while loop */
4008 DEBUG_TRACE("recv() failed, error %d", err
);
4014 clock_gettime(CLOCK_MONOTONIC
, &now
);
4016 } while ((timeout
<= 0) || (mg_difftimespec(&now
, &start
) <= timeout
));
4018 /* Timeout occured, but no data available. */
4024 pull_all(FILE *fp
, struct mg_connection
*conn
, char *buf
, int len
)
4027 double timeout
= -1.0;
4029 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
4030 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
4033 while (len
> 0 && conn
->ctx
->stop_flag
== 0) {
4034 n
= pull(fp
, conn
, buf
+ nread
, len
, timeout
);
4037 nread
= n
; /* Propagate the error */
4040 } else if (n
== 0) {
4041 break; /* No more data to read */
4043 conn
->consumed_content
+= n
;
4054 discard_unread_request_data(struct mg_connection
*conn
)
4056 char buf
[MG_BUF_LEN
];
4064 to_read
= sizeof(buf
);
4066 if (conn
->is_chunked
) {
4067 /* Chunked encoding: 1=chunk not read completely, 2=chunk read
4069 while (conn
->is_chunked
== 1) {
4070 nread
= mg_read(conn
, buf
, to_read
);
4077 /* Not chunked: content length is known */
4078 while (conn
->consumed_content
< conn
->content_len
) {
4080 > (size_t)(conn
->content_len
- conn
->consumed_content
)) {
4081 to_read
= (size_t)(conn
->content_len
- conn
->consumed_content
);
4084 nread
= mg_read(conn
, buf
, to_read
);
4094 mg_read_inner(struct mg_connection
*conn
, void *buf
, size_t len
)
4096 int64_t n
, buffered_len
, nread
;
4098 (int64_t)(len
> INT_MAX
? INT_MAX
: len
); /* since the return value is
4099 * int, we may not read more
4107 /* If Content-Length is not set for a PUT or POST request, read until
4108 * socket is closed */
4109 if (conn
->consumed_content
== 0 && conn
->content_len
== -1) {
4110 conn
->content_len
= INT64_MAX
;
4111 conn
->must_close
= 1;
4115 if (conn
->consumed_content
< conn
->content_len
) {
4116 /* Adjust number of bytes to read. */
4117 int64_t left_to_read
= conn
->content_len
- conn
->consumed_content
;
4118 if (left_to_read
< len64
) {
4119 /* Do not read more than the total content length of the request.
4121 len64
= left_to_read
;
4124 /* Return buffered data */
4125 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
4126 - conn
->consumed_content
;
4127 if (buffered_len
> 0) {
4128 if (len64
< buffered_len
) {
4129 buffered_len
= len64
;
4131 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
4132 memcpy(buf
, body
, (size_t)buffered_len
);
4133 len64
-= buffered_len
;
4134 conn
->consumed_content
+= buffered_len
;
4135 nread
+= buffered_len
;
4136 buf
= (char *)buf
+ buffered_len
;
4139 /* We have returned all buffered data. Read new data from the remote
4142 if ((n
= pull_all(NULL
, conn
, (char *)buf
, (int)len64
)) >= 0) {
4145 nread
= (nread
> 0 ? nread
: n
);
4153 mg_getc(struct mg_connection
*conn
)
4159 conn
->content_len
++;
4160 if (mg_read_inner(conn
, &c
, 1) <= 0) {
4168 mg_read(struct mg_connection
*conn
, void *buf
, size_t len
)
4170 if (len
> INT_MAX
) {
4178 if (conn
->is_chunked
) {
4179 size_t all_read
= 0;
4183 if (conn
->is_chunked
== 2) {
4184 /* No more data left to read */
4188 if (conn
->chunk_remainder
) {
4189 /* copy from the remainder of the last received chunk */
4192 ((conn
->chunk_remainder
> len
) ? (len
)
4193 : (conn
->chunk_remainder
));
4195 conn
->content_len
+= (int)read_now
;
4197 mg_read_inner(conn
, (char *)buf
+ all_read
, read_now
);
4198 all_read
+= (size_t)read_ret
;
4200 conn
->chunk_remainder
-= read_now
;
4203 if (conn
->chunk_remainder
== 0) {
4204 /* the rest of the data in the current chunk has been read
4206 if ((mg_getc(conn
) != '\r') || (mg_getc(conn
) != '\n')) {
4207 /* Protocol violation */
4213 /* fetch a new chunk */
4217 unsigned long chunkSize
= 0;
4219 for (i
= 0; i
< ((int)sizeof(lenbuf
) - 1); i
++) {
4220 lenbuf
[i
] = mg_getc(conn
);
4221 if (i
> 0 && lenbuf
[i
] == '\r' && lenbuf
[i
- 1] != '\r') {
4224 if (i
> 1 && lenbuf
[i
] == '\n' && lenbuf
[i
- 1] == '\r') {
4226 chunkSize
= strtoul(lenbuf
, &end
, 16);
4227 if (chunkSize
== 0) {
4228 /* regular end of content */
4229 conn
->is_chunked
= 2;
4233 if (!isalnum(lenbuf
[i
])) {
4234 /* illegal character for chunk length */
4238 if ((end
== NULL
) || (*end
!= '\r')) {
4239 /* chunksize not set correctly */
4242 if (chunkSize
== 0) {
4246 conn
->chunk_remainder
= chunkSize
;
4250 return (int)all_read
;
4252 return mg_read_inner(conn
, buf
, len
);
4257 mg_write(struct mg_connection
*conn
, const void *buf
, size_t len
)
4260 int64_t n
, total
, allowed
;
4266 if (conn
->throttle
> 0) {
4267 if ((now
= time(NULL
)) != conn
->last_throttle_time
) {
4268 conn
->last_throttle_time
= now
;
4269 conn
->last_throttle_bytes
= 0;
4271 allowed
= conn
->throttle
- conn
->last_throttle_bytes
;
4272 if (allowed
> (int64_t)len
) {
4273 allowed
= (int64_t)len
;
4275 if ((total
= push_all(conn
->ctx
,
4280 (int64_t)allowed
)) == allowed
) {
4281 buf
= (const char *)buf
+ total
;
4282 conn
->last_throttle_bytes
+= total
;
4283 while (total
< (int64_t)len
&& conn
->ctx
->stop_flag
== 0) {
4284 allowed
= conn
->throttle
> (int64_t)len
- total
4285 ? (int64_t)len
- total
4287 if ((n
= push_all(conn
->ctx
,
4292 (int64_t)allowed
)) != allowed
) {
4296 conn
->last_throttle_bytes
= allowed
;
4297 conn
->last_throttle_time
= time(NULL
);
4298 buf
= (const char *)buf
+ n
;
4303 total
= push_all(conn
->ctx
,
4314 /* Alternative alloc_vprintf() for non-compliant C runtimes */
4316 alloc_vprintf2(char **buf
, const char *fmt
, va_list ap
)
4319 size_t size
= MG_BUF_LEN
/ 4;
4329 *buf
= (char *)mg_malloc(size
);
4334 va_copy(ap_copy
, ap
);
4335 len
= vsnprintf_impl(*buf
, size
- 1, fmt
, ap_copy
);
4337 (*buf
)[size
- 1] = 0;
4344 /* Print message to buffer. If buffer is large enough to hold the message,
4345 * return buffer. If buffer is to small, allocate large enough buffer on heap,
4346 * and return allocated buffer. */
4348 alloc_vprintf(char **out_buf
,
4350 size_t prealloc_size
,
4357 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
4358 * buffer is too small. Also, older versions of msvcrt.dll do not have
4359 * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
4360 * Therefore, we make two passes: on first pass, get required message
4362 * On second pass, actually print the message. */
4363 va_copy(ap_copy
, ap
);
4364 len
= vsnprintf_impl(NULL
, 0, fmt
, ap_copy
);
4368 /* C runtime is not standard compliant, vsnprintf() returned -1.
4369 * Switch to alternative code path that uses incremental allocations.
4371 va_copy(ap_copy
, ap
);
4372 len
= alloc_vprintf2(out_buf
, fmt
, ap
);
4375 } else if ((size_t)(len
) >= prealloc_size
) {
4376 /* The pre-allocated buffer not large enough. */
4377 /* Allocate a new buffer. */
4378 *out_buf
= (char *)mg_malloc((size_t)(len
) + 1);
4380 /* Allocation failed. Return -1 as "out of memory" error. */
4383 /* Buffer allocation successful. Store the string there. */
4384 va_copy(ap_copy
, ap
);
4385 IGNORE_UNUSED_RESULT(
4386 vsnprintf_impl(*out_buf
, (size_t)(len
) + 1, fmt
, ap_copy
));
4390 /* The pre-allocated buffer is large enough.
4391 * Use it to store the string and return the address. */
4392 va_copy(ap_copy
, ap
);
4393 IGNORE_UNUSED_RESULT(
4394 vsnprintf_impl(prealloc_buf
, prealloc_size
, fmt
, ap_copy
));
4396 *out_buf
= prealloc_buf
;
4404 mg_vprintf(struct mg_connection
*conn
, const char *fmt
, va_list ap
)
4406 char mem
[MG_BUF_LEN
];
4410 if ((len
= alloc_vprintf(&buf
, mem
, sizeof(mem
), fmt
, ap
)) > 0) {
4411 len
= mg_write(conn
, buf
, (size_t)len
);
4413 if (buf
!= mem
&& buf
!= NULL
) {
4422 mg_printf(struct mg_connection
*conn
, const char *fmt
, ...)
4428 result
= mg_vprintf(conn
, fmt
, ap
);
4436 mg_url_decode(const char *src
,
4440 int is_form_url_encoded
)
4443 #define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
4445 for (i
= j
= 0; i
< src_len
&& j
< dst_len
- 1; i
++, j
++) {
4446 if (i
< src_len
- 2 && src
[i
] == '%'
4447 && isxdigit(*(const unsigned char *)(src
+ i
+ 1))
4448 && isxdigit(*(const unsigned char *)(src
+ i
+ 2))) {
4449 a
= tolower(*(const unsigned char *)(src
+ i
+ 1));
4450 b
= tolower(*(const unsigned char *)(src
+ i
+ 2));
4451 dst
[j
] = (char)((HEXTOI(a
) << 4) | HEXTOI(b
));
4453 } else if (is_form_url_encoded
&& src
[i
] == '+') {
4460 dst
[j
] = '\0'; /* Null-terminate the destination */
4462 return i
>= src_len
? j
: -1;
4467 mg_get_var(const char *data
,
4473 return mg_get_var2(data
, data_len
, name
, dst
, dst_len
, 0);
4478 mg_get_var2(const char *data
,
4485 const char *p
, *e
, *s
;
4489 if (dst
== NULL
|| dst_len
== 0) {
4491 } else if (data
== NULL
|| name
== NULL
|| data_len
== 0) {
4495 name_len
= strlen(name
);
4496 e
= data
+ data_len
;
4500 /* data is "var1=val1&var2=val2...". Find variable first */
4501 for (p
= data
; p
+ name_len
< e
; p
++) {
4502 if ((p
== data
|| p
[-1] == '&') && p
[name_len
] == '='
4503 && !mg_strncasecmp(name
, p
, name_len
) && 0 == occurrence
--) {
4504 /* Point p to variable value */
4507 /* Point s to the end of the value */
4508 s
= (const char *)memchr(p
, '&', (size_t)(e
- p
));
4512 /* assert(s >= p); */
4517 /* Decode variable into destination buffer */
4518 len
= mg_url_decode(p
, (int)(s
- p
), dst
, (int)dst_len
, 1);
4520 /* Redirect error code from -1 to -2 (destination buffer too
4535 mg_get_cookie(const char *cookie_header
,
4536 const char *var_name
,
4540 const char *s
, *p
, *end
;
4541 int name_len
, len
= -1;
4543 if (dst
== NULL
|| dst_size
== 0) {
4545 } else if (var_name
== NULL
|| (s
= cookie_header
) == NULL
) {
4549 name_len
= (int)strlen(var_name
);
4550 end
= s
+ strlen(s
);
4553 for (; (s
= mg_strcasestr(s
, var_name
)) != NULL
; s
+= name_len
) {
4554 if (s
[name_len
] == '=') {
4556 if ((p
= strchr(s
, ' ')) == NULL
) {
4562 if (*s
== '"' && p
[-1] == '"' && p
> s
+ 1) {
4566 if ((size_t)(p
- s
) < dst_size
) {
4568 mg_strlcpy(dst
, s
, (size_t)len
+ 1);
4580 #if defined(USE_WEBSOCKET) || defined(USE_LUA)
4582 base64_encode(const unsigned char *src
, int src_len
, char *dst
)
4584 static const char *b64
=
4585 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4588 for (i
= j
= 0; i
< src_len
; i
+= 3) {
4590 b
= i
+ 1 >= src_len
? 0 : src
[i
+ 1];
4591 c
= i
+ 2 >= src_len
? 0 : src
[i
+ 2];
4593 dst
[j
++] = b64
[a
>> 2];
4594 dst
[j
++] = b64
[((a
& 3) << 4) | (b
>> 4)];
4595 if (i
+ 1 < src_len
) {
4596 dst
[j
++] = b64
[(b
& 15) << 2 | (c
>> 6)];
4598 if (i
+ 2 < src_len
) {
4599 dst
[j
++] = b64
[c
& 63];
4602 while (j
% 4 != 0) {
4610 #if defined(USE_LUA)
4611 static unsigned char
4612 b64reverse(char letter
)
4614 if (letter
>= 'A' && letter
<= 'Z') {
4615 return letter
- 'A';
4617 if (letter
>= 'a' && letter
<= 'z') {
4618 return letter
- 'a' + 26;
4620 if (letter
>= '0' && letter
<= '9') {
4621 return letter
- '0' + 52;
4623 if (letter
== '+') {
4626 if (letter
== '/') {
4629 if (letter
== '=') {
4630 return 255; /* normal end */
4632 return 254; /* error */
4637 base64_decode(const unsigned char *src
, int src_len
, char *dst
, size_t *dst_len
)
4640 unsigned char a
, b
, c
, d
;
4644 for (i
= 0; i
< src_len
; i
+= 4) {
4645 a
= b64reverse(src
[i
]);
4650 b
= b64reverse(i
+ 1 >= src_len
? 0 : src
[i
+ 1]);
4655 c
= b64reverse(i
+ 2 >= src_len
? 0 : src
[i
+ 2]);
4660 d
= b64reverse(i
+ 3 >= src_len
? 0 : src
[i
+ 3]);
4665 dst
[(*dst_len
)++] = (a
<< 2) + (b
>> 4);
4667 dst
[(*dst_len
)++] = (b
<< 4) + (c
>> 2);
4669 dst
[(*dst_len
)++] = (c
<< 6) + d
;
4679 is_put_or_delete_method(const struct mg_connection
*conn
)
4682 const char *s
= conn
->request_info
.request_method
;
4683 return s
!= NULL
&& (!strcmp(s
, "PUT") || !strcmp(s
, "DELETE")
4684 || !strcmp(s
, "MKCOL") || !strcmp(s
, "PATCH"));
4691 interpret_uri(struct mg_connection
*conn
, /* in: request (must be valid) */
4692 char *filename
, /* out: filename */
4693 size_t filename_buf_len
, /* in: size of filename buffer */
4694 struct file
*filep
, /* out: file structure */
4695 int *is_found
, /* out: file is found (directly) */
4696 int *is_script_resource
, /* out: handled by a script? */
4697 int *is_websocket_request
, /* out: websocket connetion? */
4698 int *is_put_or_delete_request
/* out: put/delete a file? */
4701 /* TODO (high): Restructure this function */
4703 #if !defined(NO_FILES)
4704 const char *uri
= conn
->request_info
.local_uri
;
4705 const char *root
= conn
->ctx
->config
[DOCUMENT_ROOT
];
4706 const char *rewrite
;
4709 char gz_path
[PATH_MAX
];
4710 char const *accept_encoding
;
4712 #if !defined(NO_CGI) || defined(USE_LUA)
4716 (void)filename_buf_len
; /* unused if NO_FILES is defined */
4719 memset(filep
, 0, sizeof(*filep
));
4722 *is_script_resource
= 0;
4723 *is_put_or_delete_request
= is_put_or_delete_method(conn
);
4725 #if defined(USE_WEBSOCKET)
4726 *is_websocket_request
= is_websocket_protocol(conn
);
4727 #if !defined(NO_FILES)
4728 if (*is_websocket_request
&& conn
->ctx
->config
[WEBSOCKET_ROOT
]) {
4729 root
= conn
->ctx
->config
[WEBSOCKET_ROOT
];
4731 #endif /* !NO_FILES */
4732 #else /* USE_WEBSOCKET */
4733 *is_websocket_request
= 0;
4734 #endif /* USE_WEBSOCKET */
4736 #if !defined(NO_FILES)
4737 /* Note that root == NULL is a regular use case here. This occurs,
4738 * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
4739 * config is not required. */
4741 /* all file related outputs have already been set to 0, just return
4746 /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
4747 * of the path one byte on the right.
4748 * If document_root is NULL, leave the file empty. */
4750 conn
, &truncated
, filename
, filename_buf_len
- 1, "%s%s", root
, uri
);
4753 goto interpret_cleanup
;
4756 rewrite
= conn
->ctx
->config
[REWRITE
];
4757 while ((rewrite
= next_option(rewrite
, &a
, &b
)) != NULL
) {
4758 if ((match_len
= match_prefix(a
.ptr
, a
.len
, uri
)) > 0) {
4762 filename_buf_len
- 1,
4772 goto interpret_cleanup
;
4775 /* Local file path and name, corresponding to requested URI
4776 * is now stored in "filename" variable. */
4777 if (mg_stat(conn
, filename
, filep
)) {
4778 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4779 /* File exists. Check if it is a script type. */
4781 #if !defined(NO_CGI)
4782 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4783 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4786 #if defined(USE_LUA)
4787 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4788 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4791 #if defined(USE_DUKTAPE)
4792 || match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4794 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4798 /* The request addresses a CGI script or a Lua script. The URI
4799 * corresponds to the script itself (like /path/script.cgi),
4800 * and there is no additional resource path
4801 * (like /path/script.cgi/something).
4802 * Requests that modify (replace or delete) a resource, like
4803 * PUT and DELETE requests, should replace/delete the script
4805 * Requests that read or write from/to a resource, like GET and
4806 * POST requests, should call the script and return the
4807 * generated response. */
4808 *is_script_resource
= !*is_put_or_delete_request
;
4810 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4815 /* If we can't find the actual file, look for the file
4816 * with the same name but a .gz extension. If we find it,
4817 * use that and set the gzipped flag in the file struct
4818 * to indicate that the response need to have the content-
4819 * encoding: gzip header.
4820 * We can only do this if the browser declares support. */
4821 if ((accept_encoding
= mg_get_header(conn
, "Accept-Encoding")) != NULL
) {
4822 if (strstr(accept_encoding
, "gzip") != NULL
) {
4824 conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", filename
);
4827 goto interpret_cleanup
;
4830 if (mg_stat(conn
, gz_path
, filep
)) {
4835 /* Currently gz files can not be scripts. */
4841 #if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
4842 /* Support PATH_INFO for CGI scripts. */
4843 for (p
= filename
+ strlen(filename
); p
> filename
+ 1; p
--) {
4847 #if !defined(NO_CGI)
4848 || match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
4849 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
4852 #if defined(USE_LUA)
4853 || match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
4855 conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
4858 #if defined(USE_DUKTAPE)
4860 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
4861 strlen(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
4864 ) && mg_stat(conn
, filename
, filep
)) {
4865 /* Shift PATH_INFO block one character right, e.g.
4866 * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
4867 * conn->path_info is pointing to the local variable "path"
4868 * declared in handle_request(), so PATH_INFO is not valid
4869 * after handle_request returns. */
4870 conn
->path_info
= p
+ 1;
4871 memmove(p
+ 2, p
+ 1, strlen(p
+ 1) + 1); /* +1 is for
4874 *is_script_resource
= 1;
4881 #endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
4882 #endif /* !defined(NO_FILES) */
4885 #if !defined(NO_FILES)
4886 /* Reset all outputs */
4888 memset(filep
, 0, sizeof(*filep
));
4891 *is_script_resource
= 0;
4892 *is_websocket_request
= 0;
4893 *is_put_or_delete_request
= 0;
4894 #endif /* !defined(NO_FILES) */
4898 /* Check whether full request is buffered. Return:
4899 * -1 if request is malformed
4900 * 0 if request is not yet fully buffered
4901 * >0 actual request length, including last \r\n\r\n */
4903 get_request_len(const char *buf
, int buflen
)
4909 for (s
= buf
, e
= s
+ buflen
- 1; len
<= 0 && s
< e
; s
++) {
4910 /* Control characters are not allowed but >=128 is. */
4911 if (!in_content
&& !isprint(*(const unsigned char *)s
) && *s
!= '\r'
4913 && *(const unsigned char *)s
< 128) {
4915 break; /* [i_a] abort scan as soon as one malformed character is
4917 /* don't let subsequent \r\n\r\n win us over anyhow */
4918 } else if (s
[0] == '\n' && s
[1] == '\n') {
4919 len
= (int)(s
- buf
) + 2;
4920 } else if (s
[0] == '\n' && &s
[1] < e
&& s
[1] == '\r' && s
[2] == '\n') {
4921 len
= (int)(s
- buf
) + 3;
4925 if (!in_content
&& *s
== ':') {
4934 #if !defined(NO_CACHING)
4935 /* Convert month to the month number. Return -1 on error, or month number */
4937 get_month_index(const char *s
)
4941 for (i
= 0; i
< ARRAY_SIZE(month_names
); i
++) {
4942 if (!strcmp(s
, month_names
[i
])) {
4951 /* Parse UTC date-time string, and return the corresponding time_t value. */
4953 parse_date_string(const char *datetime
)
4955 char month_str
[32] = {0};
4956 int second
, minute
, hour
, day
, month
, year
;
4957 time_t result
= (time_t)0;
4960 if ((sscanf(datetime
,
4961 "%d/%3s/%d %d:%d:%d",
4967 &second
) == 6) || (sscanf(datetime
,
4968 "%d %3s %d %d:%d:%d",
4975 || (sscanf(datetime
,
4976 "%*3s, %d %3s %d %d:%d:%d",
4982 &second
) == 6) || (sscanf(datetime
,
4983 "%d-%3s-%d %d:%d:%d",
4990 month
= get_month_index(month_str
);
4991 if ((month
>= 0) && (year
>= 1970)) {
4992 memset(&tm
, 0, sizeof(tm
));
4993 tm
.tm_year
= year
- 1900;
4999 result
= timegm(&tm
);
5005 #endif /* !NO_CACHING */
5008 /* Protect against directory disclosure attack by removing '..',
5009 * excessive '/' and '\' characters */
5011 remove_double_dots_and_double_slashes(char *s
)
5015 while (*s
!= '\0') {
5017 if (s
[-1] == '/' || s
[-1] == '\\') {
5018 /* Skip all following slashes, backslashes and double-dots */
5019 while (s
[0] != '\0') {
5020 if (s
[0] == '/' || s
[0] == '\\') {
5022 } else if (s
[0] == '.' && s
[1] == '.') {
5034 static const struct {
5035 const char *extension
;
5037 const char *mime_type
;
5038 } builtin_mime_types
[] = {
5039 /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
5040 * application types */
5041 {".doc", 4, "application/msword"},
5042 {".eps", 4, "application/postscript"},
5043 {".exe", 4, "application/octet-stream"},
5044 {".js", 3, "application/javascript"},
5045 {".json", 5, "application/json"},
5046 {".pdf", 4, "application/pdf"},
5047 {".ps", 3, "application/postscript"},
5048 {".rtf", 4, "application/rtf"},
5049 {".xhtml", 6, "application/xhtml+xml"},
5050 {".xsl", 4, "application/xml"},
5051 {".xslt", 5, "application/xml"},
5054 {".ttf", 4, "application/font-sfnt"},
5055 {".cff", 4, "application/font-sfnt"},
5056 {".otf", 4, "application/font-sfnt"},
5057 {".aat", 4, "application/font-sfnt"},
5058 {".sil", 4, "application/font-sfnt"},
5059 {".pfr", 4, "application/font-tdpfr"},
5060 {".woff", 5, "application/font-woff"},
5063 {".mp3", 4, "audio/mpeg"},
5064 {".oga", 4, "audio/ogg"},
5065 {".ogg", 4, "audio/ogg"},
5068 {".gif", 4, "image/gif"},
5069 {".ief", 4, "image/ief"},
5070 {".jpeg", 5, "image/jpeg"},
5071 {".jpg", 4, "image/jpeg"},
5072 {".jpm", 4, "image/jpm"},
5073 {".jpx", 4, "image/jpx"},
5074 {".png", 4, "image/png"},
5075 {".svg", 4, "image/svg+xml"},
5076 {".tif", 4, "image/tiff"},
5077 {".tiff", 5, "image/tiff"},
5080 {".wrl", 4, "model/vrml"},
5083 {".css", 4, "text/css"},
5084 {".csv", 4, "text/csv"},
5085 {".htm", 4, "text/html"},
5086 {".html", 5, "text/html"},
5087 {".sgm", 4, "text/sgml"},
5088 {".shtm", 5, "text/html"},
5089 {".shtml", 6, "text/html"},
5090 {".txt", 4, "text/plain"},
5091 {".xml", 4, "text/xml"},
5094 {".mov", 4, "video/quicktime"},
5095 {".mp4", 4, "video/mp4"},
5096 {".mpeg", 5, "video/mpeg"},
5097 {".mpg", 4, "video/mpeg"},
5098 {".ogv", 4, "video/ogg"},
5099 {".qt", 3, "video/quicktime"},
5101 /* not registered types
5102 * (http://reference.sitepoint.com/html/mime-types-full,
5103 * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
5104 {".arj", 4, "application/x-arj-compressed"},
5105 {".gz", 3, "application/x-gunzip"},
5106 {".rar", 4, "application/x-arj-compressed"},
5107 {".swf", 4, "application/x-shockwave-flash"},
5108 {".tar", 4, "application/x-tar"},
5109 {".tgz", 4, "application/x-tar-gz"},
5110 {".torrent", 8, "application/x-bittorrent"},
5111 {".ppt", 4, "application/x-mspowerpoint"},
5112 {".xls", 4, "application/x-msexcel"},
5113 {".zip", 4, "application/x-zip-compressed"},
5116 "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
5117 {".aif", 4, "audio/x-aif"},
5118 {".m3u", 4, "audio/x-mpegurl"},
5119 {".mid", 4, "audio/x-midi"},
5120 {".ra", 3, "audio/x-pn-realaudio"},
5121 {".ram", 4, "audio/x-pn-realaudio"},
5122 {".wav", 4, "audio/x-wav"},
5123 {".bmp", 4, "image/bmp"},
5124 {".ico", 4, "image/x-icon"},
5125 {".pct", 4, "image/x-pct"},
5126 {".pict", 5, "image/pict"},
5127 {".rgb", 4, "image/x-rgb"},
5128 {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
5129 {".asf", 4, "video/x-ms-asf"},
5130 {".avi", 4, "video/x-msvideo"},
5131 {".m4v", 4, "video/x-m4v"},
5136 mg_get_builtin_mime_type(const char *path
)
5141 path_len
= strlen(path
);
5143 for (i
= 0; builtin_mime_types
[i
].extension
!= NULL
; i
++) {
5144 ext
= path
+ (path_len
- builtin_mime_types
[i
].ext_len
);
5145 if (path_len
> builtin_mime_types
[i
].ext_len
5146 && mg_strcasecmp(ext
, builtin_mime_types
[i
].extension
) == 0) {
5147 return builtin_mime_types
[i
].mime_type
;
5151 return "text/plain";
5155 /* Look at the "path" extension and figure what mime type it has.
5156 * Store mime type in the vector. */
5158 get_mime_type(struct mg_context
*ctx
, const char *path
, struct vec
*vec
)
5160 struct vec ext_vec
, mime_vec
;
5161 const char *list
, *ext
;
5164 path_len
= strlen(path
);
5166 if (ctx
== NULL
|| vec
== NULL
) {
5170 /* Scan user-defined mime types first, in case user wants to
5171 * override default mime types. */
5172 list
= ctx
->config
[EXTRA_MIME_TYPES
];
5173 while ((list
= next_option(list
, &ext_vec
, &mime_vec
)) != NULL
) {
5174 /* ext now points to the path suffix */
5175 ext
= path
+ path_len
- ext_vec
.len
;
5176 if (mg_strncasecmp(ext
, ext_vec
.ptr
, ext_vec
.len
) == 0) {
5182 vec
->ptr
= mg_get_builtin_mime_type(path
);
5183 vec
->len
= strlen(vec
->ptr
);
5187 /* Stringify binary data. Output buffer must be twice as big as input,
5188 * because each byte takes 2 bytes in string representation */
5190 bin2str(char *to
, const unsigned char *p
, size_t len
)
5192 static const char *hex
= "0123456789abcdef";
5194 for (; len
--; p
++) {
5195 *to
++ = hex
[p
[0] >> 4];
5196 *to
++ = hex
[p
[0] & 0x0f];
5202 /* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
5204 mg_md5(char buf
[33], ...)
5206 md5_byte_t hash
[16];
5214 while ((p
= va_arg(ap
, const char *)) != NULL
) {
5215 md5_append(&ctx
, (const md5_byte_t
*)p
, strlen(p
));
5219 md5_finish(&ctx
, hash
);
5220 bin2str(buf
, hash
, sizeof(hash
));
5225 /* Check the user's password, return 1 if OK */
5227 check_password(const char *method
,
5234 const char *response
)
5236 char ha2
[32 + 1], expected_response
[32 + 1];
5238 /* Some of the parameters may be NULL */
5239 if (method
== NULL
|| nonce
== NULL
|| nc
== NULL
|| cnonce
== NULL
5241 || response
== NULL
) {
5245 /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
5246 if (strlen(response
) != 32) {
5250 mg_md5(ha2
, method
, ":", uri
, NULL
);
5251 mg_md5(expected_response
,
5265 return mg_strcasecmp(response
, expected_response
) == 0;
5269 /* Use the global passwords file, if specified by auth_gpass option,
5270 * or search for .htpasswd in the requested directory. */
5272 open_auth_file(struct mg_connection
*conn
, const char *path
, struct file
*filep
)
5274 if (conn
!= NULL
&& conn
->ctx
!= NULL
) {
5275 char name
[PATH_MAX
];
5276 const char *p
, *e
, *gpass
= conn
->ctx
->config
[GLOBAL_PASSWORDS_FILE
];
5277 struct file file
= STRUCT_FILE_INITIALIZER
;
5280 if (gpass
!= NULL
) {
5281 /* Use global passwords file */
5282 if (!mg_fopen(conn
, gpass
, "r", filep
)) {
5284 mg_cry(conn
, "fopen(%s): %s", gpass
, strerror(ERRNO
));
5287 /* Important: using local struct file to test path for is_directory
5288 * flag. If filep is used, mg_stat() makes it appear as if auth file
5290 } else if (mg_stat(conn
, path
, &file
) && file
.is_directory
) {
5297 PASSWORDS_FILE_NAME
);
5299 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5301 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5305 /* Try to find .htpasswd in requested directory. */
5306 for (p
= path
, e
= p
+ strlen(p
) - 1; e
> p
; e
--) {
5318 PASSWORDS_FILE_NAME
);
5320 if (truncated
|| !mg_fopen(conn
, name
, "r", filep
)) {
5322 mg_cry(conn
, "fopen(%s): %s", name
, strerror(ERRNO
));
5330 /* Parsed Authorization header */
5332 char *user
, *uri
, *cnonce
, *response
, *qop
, *nc
, *nonce
;
5336 /* Return 1 on success. Always initializes the ah structure. */
5338 parse_auth_header(struct mg_connection
*conn
,
5343 char *name
, *value
, *s
;
5344 const char *auth_header
;
5351 (void)memset(ah
, 0, sizeof(*ah
));
5352 if ((auth_header
= mg_get_header(conn
, "Authorization")) == NULL
5353 || mg_strncasecmp(auth_header
, "Digest ", 7) != 0) {
5357 /* Make modifiable copy of the auth header */
5358 (void)mg_strlcpy(buf
, auth_header
+ 7, buf_size
);
5361 /* Parse authorization header */
5363 /* Gobble initial spaces */
5364 while (isspace(*(unsigned char *)s
)) {
5367 name
= skip_quoted(&s
, "=", " ", 0);
5368 /* Value is either quote-delimited, or ends at first comma or space. */
5371 value
= skip_quoted(&s
, "\"", " ", '\\');
5376 value
= skip_quoted(&s
, ", ", " ", 0); /* IE uses commas, FF uses
5379 if (*name
== '\0') {
5383 if (!strcmp(name
, "username")) {
5385 } else if (!strcmp(name
, "cnonce")) {
5387 } else if (!strcmp(name
, "response")) {
5388 ah
->response
= value
;
5389 } else if (!strcmp(name
, "uri")) {
5391 } else if (!strcmp(name
, "qop")) {
5393 } else if (!strcmp(name
, "nc")) {
5395 } else if (!strcmp(name
, "nonce")) {
5400 #ifndef NO_NONCE_CHECK
5401 /* Read the nonce from the response. */
5402 if (ah
->nonce
== NULL
) {
5406 nonce
= strtoull(ah
->nonce
, &s
, 10);
5407 if ((s
== NULL
) || (*s
!= 0)) {
5411 /* Convert the nonce from the client to a number. */
5412 nonce
^= conn
->ctx
->auth_nonce_mask
;
5414 /* The converted number corresponds to the time the nounce has been
5415 * created. This should not be earlier than the server start. */
5416 /* Server side nonce check is valuable in all situations but one:
5417 * if the server restarts frequently, but the client should not see
5418 * that, so the server should accept nonces from previous starts. */
5419 /* However, the reasonable default is to not accept a nonce from a
5420 * previous start, so if anyone changed the access rights between
5421 * two restarts, a new login is required. */
5422 if (nonce
< (uint64_t)conn
->ctx
->start_time
) {
5423 /* nonce is from a previous start of the server and no longer valid
5424 * (replay attack?) */
5427 /* Check if the nonce is too high, so it has not (yet) been used by the
5429 if (nonce
>= ((uint64_t)conn
->ctx
->start_time
+ conn
->ctx
->nonce_count
)) {
5434 /* CGI needs it as REMOTE_USER */
5435 if (ah
->user
!= NULL
) {
5436 conn
->request_info
.remote_user
= mg_strdup(ah
->user
);
5446 mg_fgets(char *buf
, size_t size
, struct file
*filep
, char **p
)
5456 if (filep
->membuf
!= NULL
&& *p
!= NULL
) {
5457 memend
= (const char *)&filep
->membuf
[filep
->size
];
5458 /* Search for \n from p till the end of stream */
5459 eof
= (char *)memchr(*p
, '\n', (size_t)(memend
- *p
));
5461 eof
+= 1; /* Include \n */
5463 eof
= memend
; /* Copy remaining data */
5465 len
= (size_t)(eof
- *p
) > size
- 1 ? size
- 1 : (size_t)(eof
- *p
);
5466 memcpy(buf
, *p
, len
);
5469 return len
? eof
: NULL
;
5470 } else if (filep
->fp
!= NULL
) {
5471 return fgets(buf
, (int)size
, filep
->fp
);
5477 struct read_auth_file_struct
{
5478 struct mg_connection
*conn
;
5481 char buf
[256 + 256 + 40];
5489 read_auth_file(struct file
*filep
, struct read_auth_file_struct
*workdata
)
5492 int is_authorized
= 0;
5496 if (!filep
|| !workdata
) {
5500 /* Loop over passwords file */
5501 p
= (char *)filep
->membuf
;
5502 while (mg_fgets(workdata
->buf
, sizeof(workdata
->buf
), filep
, &p
) != NULL
) {
5503 l
= strlen(workdata
->buf
);
5505 if (isspace(workdata
->buf
[l
- 1])
5506 || iscntrl(workdata
->buf
[l
- 1])) {
5508 workdata
->buf
[l
] = 0;
5516 workdata
->f_user
= workdata
->buf
;
5518 if (workdata
->f_user
[0] == ':') {
5519 /* user names may not contain a ':' and may not be empty,
5520 * so lines starting with ':' may be used for a special purpose */
5521 if (workdata
->f_user
[1] == '#') {
5522 /* :# is a comment */
5524 } else if (!strncmp(workdata
->f_user
+ 1, "include=", 8)) {
5525 if (mg_fopen(workdata
->conn
, workdata
->f_user
+ 9, "r", &fp
)) {
5526 is_authorized
= read_auth_file(&fp
, workdata
);
5529 mg_cry(workdata
->conn
,
5530 "%s: cannot open authorization file: %s",
5536 /* everything is invalid for the moment (might change in the
5538 mg_cry(workdata
->conn
,
5539 "%s: syntax error in authorization file: %s",
5545 workdata
->f_domain
= strchr(workdata
->f_user
, ':');
5546 if (workdata
->f_domain
== NULL
) {
5547 mg_cry(workdata
->conn
,
5548 "%s: syntax error in authorization file: %s",
5553 *(workdata
->f_domain
) = 0;
5554 (workdata
->f_domain
)++;
5556 workdata
->f_ha1
= strchr(workdata
->f_domain
, ':');
5557 if (workdata
->f_ha1
== NULL
) {
5558 mg_cry(workdata
->conn
,
5559 "%s: syntax error in authorization file: %s",
5564 *(workdata
->f_ha1
) = 0;
5565 (workdata
->f_ha1
)++;
5567 if (!strcmp(workdata
->ah
.user
, workdata
->f_user
)
5568 && !strcmp(workdata
->domain
, workdata
->f_domain
)) {
5569 return check_password(workdata
->conn
->request_info
.request_method
,
5574 workdata
->ah
.cnonce
,
5576 workdata
->ah
.response
);
5580 return is_authorized
;
5584 /* Authorize against the opened passwords file. Return 1 if authorized. */
5586 authorize(struct mg_connection
*conn
, struct file
*filep
)
5588 struct read_auth_file_struct workdata
;
5589 char buf
[MG_BUF_LEN
];
5591 if (!conn
|| !conn
->ctx
) {
5595 memset(&workdata
, 0, sizeof(workdata
));
5596 workdata
.conn
= conn
;
5598 if (!parse_auth_header(conn
, buf
, sizeof(buf
), &workdata
.ah
)) {
5601 workdata
.domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
5603 return read_auth_file(filep
, &workdata
);
5607 /* Return 1 if request is authorised, 0 otherwise. */
5609 check_authorization(struct mg_connection
*conn
, const char *path
)
5611 char fname
[PATH_MAX
];
5612 struct vec uri_vec
, filename_vec
;
5614 struct file file
= STRUCT_FILE_INITIALIZER
;
5615 int authorized
= 1, truncated
;
5617 if (!conn
|| !conn
->ctx
) {
5621 list
= conn
->ctx
->config
[PROTECT_URI
];
5622 while ((list
= next_option(list
, &uri_vec
, &filename_vec
)) != NULL
) {
5623 if (!memcmp(conn
->request_info
.local_uri
, uri_vec
.ptr
, uri_vec
.len
)) {
5629 (int)filename_vec
.len
,
5632 if (truncated
|| !mg_fopen(conn
, fname
, "r", &file
)) {
5634 "%s: cannot open %s: %s",
5643 if (!is_file_opened(&file
)) {
5644 open_auth_file(conn
, path
, &file
);
5647 if (is_file_opened(&file
)) {
5648 authorized
= authorize(conn
, &file
);
5657 send_authorization_request(struct mg_connection
*conn
)
5660 time_t curtime
= time(NULL
);
5662 if (conn
&& conn
->ctx
) {
5663 uint64_t nonce
= (uint64_t)(conn
->ctx
->start_time
);
5665 (void)pthread_mutex_lock(&conn
->ctx
->nonce_mutex
);
5666 nonce
+= conn
->ctx
->nonce_count
;
5667 ++conn
->ctx
->nonce_count
;
5668 (void)pthread_mutex_unlock(&conn
->ctx
->nonce_mutex
);
5670 nonce
^= conn
->ctx
->auth_nonce_mask
;
5671 conn
->status_code
= 401;
5672 conn
->must_close
= 1;
5674 gmt_time_string(date
, sizeof(date
), &curtime
);
5676 mg_printf(conn
, "HTTP/1.1 401 Unauthorized\r\n");
5677 send_no_cache_header(conn
);
5680 "Connection: %s\r\n"
5681 "Content-Length: 0\r\n"
5682 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
5683 "nonce=\"%" UINT64_FMT
"\"\r\n\r\n",
5685 suggest_connection_header(conn
),
5686 conn
->ctx
->config
[AUTHENTICATION_DOMAIN
],
5692 #if !defined(NO_FILES)
5694 is_authorized_for_put(struct mg_connection
*conn
)
5697 struct file file
= STRUCT_FILE_INITIALIZER
;
5698 const char *passfile
= conn
->ctx
->config
[PUT_DELETE_PASSWORDS_FILE
];
5701 if (passfile
!= NULL
&& mg_fopen(conn
, passfile
, "r", &file
)) {
5702 ret
= authorize(conn
, &file
);
5714 mg_modify_passwords_file(const char *fname
,
5720 char line
[512], u
[512] = "", d
[512] = "", ha1
[33], tmp
[PATH_MAX
+ 8];
5726 /* Regard empty password as no password - remove user record. */
5727 if (pass
!= NULL
&& pass
[0] == '\0') {
5731 /* Other arguments must not be empty */
5732 if (fname
== NULL
|| domain
== NULL
|| user
== NULL
) {
5736 /* Using the given file format, user name and domain must not contain ':'
5738 if (strchr(user
, ':') != NULL
) {
5741 if (strchr(domain
, ':') != NULL
) {
5745 /* Do not allow control characters like newline in user name and domain.
5746 * Do not allow excessively long names either. */
5747 for (i
= 0; i
< 255 && user
[i
] != 0; i
++) {
5748 if (iscntrl(user
[i
])) {
5755 for (i
= 0; i
< 255 && domain
[i
] != 0; i
++) {
5756 if (iscntrl(domain
[i
])) {
5764 /* The maximum length of the path to the password file is limited */
5765 if ((strlen(fname
) + 4) >= PATH_MAX
) {
5769 /* Create a temporary file name. Length has been checked before. */
5771 strcat(tmp
, ".tmp");
5773 /* Create the file if does not exist */
5774 /* Use of fopen here is OK, since fname is only ASCII */
5775 if ((fp
= fopen(fname
, "a+")) != NULL
) {
5779 /* Open the given file and temporary file */
5780 if ((fp
= fopen(fname
, "r")) == NULL
) {
5782 } else if ((fp2
= fopen(tmp
, "w+")) == NULL
) {
5787 /* Copy the stuff to temporary file */
5788 while (fgets(line
, sizeof(line
), fp
) != NULL
) {
5789 if (sscanf(line
, "%255[^:]:%255[^:]:%*s", u
, d
) != 2) {
5795 if (!strcmp(u
, user
) && !strcmp(d
, domain
)) {
5798 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5799 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5802 fprintf(fp2
, "%s", line
);
5806 /* If new user, just add it */
5807 if (!found
&& pass
!= NULL
) {
5808 mg_md5(ha1
, user
, ":", domain
, ":", pass
, NULL
);
5809 fprintf(fp2
, "%s:%s:%s\n", user
, domain
, ha1
);
5816 /* Put the temp file in place of real file */
5817 IGNORE_UNUSED_RESULT(remove(fname
));
5818 IGNORE_UNUSED_RESULT(rename(tmp
, fname
));
5825 is_valid_port(unsigned long port
)
5827 return port
< 0xffff;
5832 mg_inet_pton(int af
, const char *src
, void *dst
, size_t dstlen
)
5834 struct addrinfo hints
, *res
, *ressave
;
5838 memset(&hints
, 0, sizeof(struct addrinfo
));
5839 hints
.ai_family
= af
;
5841 gai_ret
= getaddrinfo(src
, NULL
, &hints
, &res
);
5843 /* gai_strerror could be used to convert gai_ret to a string */
5844 /* POSIX return values: see
5845 * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
5847 /* Windows return values: see
5848 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
5856 if (dstlen
>= res
->ai_addrlen
) {
5857 memcpy(dst
, res
->ai_addr
, res
->ai_addrlen
);
5863 freeaddrinfo(ressave
);
5869 connect_socket(struct mg_context
*ctx
/* may be NULL */,
5875 SOCKET
*sock
/* output: socket, must not be NULL */,
5876 union usa
*sa
/* output: socket address, must not be NULL */
5880 *sock
= INVALID_SOCKET
;
5881 memset(sa
, 0, sizeof(*sa
));
5889 NULL
, /* No truncation check for ebuf */
5897 if (port
< 0 || !is_valid_port((unsigned)port
)) {
5899 NULL
, /* No truncation check for ebuf */
5908 if (use_ssl
&& (SSLv23_client_method
== NULL
)) {
5910 NULL
, /* No truncation check for ebuf */
5914 "SSL is not initialized");
5919 if (mg_inet_pton(AF_INET
, host
, &sa
->sin
, sizeof(sa
->sin
))) {
5920 sa
->sin
.sin_port
= htons((uint16_t)port
);
5923 } else if (mg_inet_pton(AF_INET6
, host
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5924 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5926 } else if (host
[0] == '[') {
5927 /* While getaddrinfo on Windows will work with [::1],
5928 * getaddrinfo on Linux only works with ::1 (without []). */
5929 size_t l
= strlen(host
+ 1);
5930 char *h
= l
> 1 ? mg_strdup(host
+ 1) : NULL
;
5933 if (mg_inet_pton(AF_INET6
, h
, &sa
->sin6
, sizeof(sa
->sin6
))) {
5934 sa
->sin6
.sin6_port
= htons((uint16_t)port
);
5944 NULL
, /* No truncation check for ebuf */
5953 *sock
= socket(PF_INET
, SOCK_STREAM
, 0);
5956 else if (ip_ver
== 6) {
5957 *sock
= socket(PF_INET6
, SOCK_STREAM
, 0);
5961 if (*sock
== INVALID_SOCKET
) {
5963 NULL
, /* No truncation check for ebuf */
5971 set_close_on_exec(*sock
, fc(ctx
));
5974 && (connect(*sock
, (struct sockaddr
*)&sa
->sin
, sizeof(sa
->sin
))
5976 /* connected with IPv4 */
5982 && (connect(*sock
, (struct sockaddr
*)&sa
->sin6
, sizeof(sa
->sin6
))
5984 /* connected with IPv6 */
5991 NULL
, /* No truncation check for ebuf */
5994 "connect(%s:%d): %s",
5999 *sock
= INVALID_SOCKET
;
6005 mg_url_encode(const char *src
, char *dst
, size_t dst_len
)
6007 static const char *dont_escape
= "._-$,;~()";
6008 static const char *hex
= "0123456789abcdef";
6010 const char *end
= dst
+ dst_len
- 1;
6012 for (; *src
!= '\0' && pos
< end
; src
++, pos
++) {
6013 if (isalnum(*(const unsigned char *)src
)
6014 || strchr(dont_escape
, *(const unsigned char *)src
) != NULL
) {
6016 } else if (pos
+ 2 < end
) {
6018 pos
[1] = hex
[(*(const unsigned char *)src
) >> 4];
6019 pos
[2] = hex
[(*(const unsigned char *)src
) & 0xf];
6027 return (*src
== '\0') ? (int)(pos
- dst
) : -1;
6032 print_dir_entry(struct de
*de
)
6034 char size
[64], mod
[64], href
[PATH_MAX
];
6037 if (de
->file
.is_directory
) {
6038 mg_snprintf(de
->conn
,
6039 NULL
, /* Buffer is big enough */
6045 /* We use (signed) cast below because MSVC 6 compiler cannot
6046 * convert unsigned __int64 to double. Sigh. */
6047 if (de
->file
.size
< 1024) {
6048 mg_snprintf(de
->conn
,
6049 NULL
, /* Buffer is big enough */
6053 (int)de
->file
.size
);
6054 } else if (de
->file
.size
< 0x100000) {
6055 mg_snprintf(de
->conn
,
6056 NULL
, /* Buffer is big enough */
6060 (double)de
->file
.size
/ 1024.0);
6061 } else if (de
->file
.size
< 0x40000000) {
6062 mg_snprintf(de
->conn
,
6063 NULL
, /* Buffer is big enough */
6067 (double)de
->file
.size
/ 1048576);
6069 mg_snprintf(de
->conn
,
6070 NULL
, /* Buffer is big enough */
6074 (double)de
->file
.size
/ 1073741824);
6078 /* Note: mg_snprintf will not cause a buffer overflow above.
6079 * So, string truncation checks are not required here. */
6081 tm
= localtime(&de
->file
.last_modified
);
6083 strftime(mod
, sizeof(mod
), "%d-%b-%Y %H:%M", tm
);
6085 mg_strlcpy(mod
, "01-Jan-1970 00:00", sizeof(mod
));
6086 mod
[sizeof(mod
) - 1] = '\0';
6088 mg_url_encode(de
->file_name
, href
, sizeof(href
));
6089 de
->conn
->num_bytes_sent
+=
6091 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
6092 "<td> %s</td><td> %s</td></tr>\n",
6093 de
->conn
->request_info
.local_uri
,
6095 de
->file
.is_directory
? "/" : "",
6097 de
->file
.is_directory
? "/" : "",
6103 /* This function is called from send_directory() and used for
6104 * sorting directory entries by size, or name, or modification time.
6105 * On windows, __cdecl specification is needed in case if project is built
6106 * with __stdcall convention. qsort always requires __cdels callback. */
6108 compare_dir_entries(const void *p1
, const void *p2
)
6111 const struct de
*a
= (const struct de
*)p1
, *b
= (const struct de
*)p2
;
6112 const char *query_string
= a
->conn
->request_info
.query_string
;
6115 if (query_string
== NULL
) {
6116 query_string
= "na";
6119 if (a
->file
.is_directory
&& !b
->file
.is_directory
) {
6120 return -1; /* Always put directories on top */
6121 } else if (!a
->file
.is_directory
&& b
->file
.is_directory
) {
6122 return 1; /* Always put directories on top */
6123 } else if (*query_string
== 'n') {
6124 cmp_result
= strcmp(a
->file_name
, b
->file_name
);
6125 } else if (*query_string
== 's') {
6126 cmp_result
= a
->file
.size
== b
->file
.size
6128 : a
->file
.size
> b
->file
.size
? 1 : -1;
6129 } else if (*query_string
== 'd') {
6131 (a
->file
.last_modified
== b
->file
.last_modified
)
6133 : ((a
->file
.last_modified
> b
->file
.last_modified
) ? 1
6137 return query_string
[1] == 'd' ? -cmp_result
: cmp_result
;
6144 must_hide_file(struct mg_connection
*conn
, const char *path
)
6146 if (conn
&& conn
->ctx
) {
6147 const char *pw_pattern
= "**" PASSWORDS_FILE_NAME
"$";
6148 const char *pattern
= conn
->ctx
->config
[HIDE_FILES
];
6149 return match_prefix(pw_pattern
, strlen(pw_pattern
), path
) > 0
6151 && match_prefix(pattern
, strlen(pattern
), path
) > 0);
6158 scan_directory(struct mg_connection
*conn
,
6161 void (*cb
)(struct de
*, void *))
6163 char path
[PATH_MAX
];
6169 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6174 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6175 /* Do not show current dir and hidden files */
6176 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")
6177 || must_hide_file(conn
, dp
->d_name
)) {
6182 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6184 /* If we don't memset stat structure to zero, mtime will have
6185 * garbage and strftime() will segfault later on in
6186 * print_dir_entry(). memset is required only if mg_stat()
6187 * fails. For more details, see
6188 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6189 memset(&de
.file
, 0, sizeof(de
.file
));
6192 /* If the path is not complete, skip processing. */
6196 if (!mg_stat(conn
, path
, &de
.file
)) {
6198 "%s: mg_stat(%s) failed: %s",
6203 de
.file_name
= dp
->d_name
;
6206 (void)mg_closedir(dirp
);
6212 #if !defined(NO_FILES)
6214 remove_directory(struct mg_connection
*conn
, const char *dir
)
6216 char path
[PATH_MAX
];
6223 if ((dirp
= mg_opendir(conn
, dir
)) == NULL
) {
6228 while ((dp
= mg_readdir(dirp
)) != NULL
) {
6229 /* Do not show current dir (but show hidden files as they will
6230 * also be removed) */
6231 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")) {
6236 conn
, &truncated
, path
, sizeof(path
), "%s/%s", dir
, dp
->d_name
);
6238 /* If we don't memset stat structure to zero, mtime will have
6239 * garbage and strftime() will segfault later on in
6240 * print_dir_entry(). memset is required only if mg_stat()
6241 * fails. For more details, see
6242 * http://code.google.com/p/mongoose/issues/detail?id=79 */
6243 memset(&de
.file
, 0, sizeof(de
.file
));
6246 /* Do not delete anything shorter */
6251 if (!mg_stat(conn
, path
, &de
.file
)) {
6253 "%s: mg_stat(%s) failed: %s",
6259 if (de
.file
.membuf
== NULL
) {
6260 /* file is not in memory */
6261 if (de
.file
.is_directory
) {
6262 if (remove_directory(conn
, path
) == 0) {
6266 if (mg_remove(conn
, path
) == 0) {
6271 /* file is in memory. It can not be deleted. */
6275 (void)mg_closedir(dirp
);
6277 IGNORE_UNUSED_RESULT(rmdir(dir
));
6285 struct dir_scan_data
{
6287 unsigned int num_entries
;
6288 unsigned int arr_size
;
6292 /* Behaves like realloc(), but frees original pointer on failure */
6294 realloc2(void *ptr
, size_t size
)
6296 void *new_ptr
= mg_realloc(ptr
, size
);
6297 if (new_ptr
== NULL
) {
6305 dir_scan_callback(struct de
*de
, void *data
)
6307 struct dir_scan_data
*dsd
= (struct dir_scan_data
*)data
;
6309 if (dsd
->entries
== NULL
|| dsd
->num_entries
>= dsd
->arr_size
) {
6312 (struct de
*)realloc2(dsd
->entries
,
6313 dsd
->arr_size
* sizeof(dsd
->entries
[0]));
6315 if (dsd
->entries
== NULL
) {
6316 /* TODO(lsm, low): propagate an error to the caller */
6317 dsd
->num_entries
= 0;
6319 dsd
->entries
[dsd
->num_entries
].file_name
= mg_strdup(de
->file_name
);
6320 dsd
->entries
[dsd
->num_entries
].file
= de
->file
;
6321 dsd
->entries
[dsd
->num_entries
].conn
= de
->conn
;
6328 handle_directory_request(struct mg_connection
*conn
, const char *dir
)
6332 struct dir_scan_data data
= {NULL
, 0, 128};
6334 time_t curtime
= time(NULL
);
6336 if (!scan_directory(conn
, dir
, &data
, dir_scan_callback
)) {
6337 send_http_error(conn
,
6339 "Error: Cannot open directory\nopendir(%s): %s",
6345 gmt_time_string(date
, sizeof(date
), &curtime
);
6351 sort_direction
= conn
->request_info
.query_string
!= NULL
6352 && conn
->request_info
.query_string
[1] == 'd'
6356 conn
->must_close
= 1;
6357 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
6358 send_static_cache_header(conn
);
6361 "Connection: close\r\n"
6362 "Content-Type: text/html; charset=utf-8\r\n\r\n",
6365 conn
->num_bytes_sent
+=
6367 "<html><head><title>Index of %s</title>"
6368 "<style>th {text-align: left;}</style></head>"
6369 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
6370 "<tr><th><a href=\"?n%c\">Name</a></th>"
6371 "<th><a href=\"?d%c\">Modified</a></th>"
6372 "<th><a href=\"?s%c\">Size</a></th></tr>"
6373 "<tr><td colspan=\"3\"><hr></td></tr>",
6374 conn
->request_info
.local_uri
,
6375 conn
->request_info
.local_uri
,
6380 /* Print first entry - link to a parent directory */
6381 conn
->num_bytes_sent
+=
6383 "<tr><td><a href=\"%s%s\">%s</a></td>"
6384 "<td> %s</td><td> %s</td></tr>\n",
6385 conn
->request_info
.local_uri
,
6391 /* Sort and print directory entries */
6392 if (data
.entries
!= NULL
) {
6394 (size_t)data
.num_entries
,
6395 sizeof(data
.entries
[0]),
6396 compare_dir_entries
);
6397 for (i
= 0; i
< data
.num_entries
; i
++) {
6398 print_dir_entry(&data
.entries
[i
]);
6399 mg_free(data
.entries
[i
].file_name
);
6401 mg_free(data
.entries
);
6404 conn
->num_bytes_sent
+= mg_printf(conn
, "%s", "</table></body></html>");
6405 conn
->status_code
= 200;
6409 /* Send len bytes from the opened file to the client. */
6411 send_file_data(struct mg_connection
*conn
,
6416 char buf
[MG_BUF_LEN
];
6417 int to_read
, num_read
, num_written
;
6420 if (!filep
|| !conn
) {
6424 /* Sanity check the offset */
6425 size
= filep
->size
> INT64_MAX
? INT64_MAX
: (int64_t)(filep
->size
);
6426 offset
= offset
< 0 ? 0 : offset
> size
? size
: offset
;
6428 if (len
> 0 && filep
->membuf
!= NULL
&& size
> 0) {
6429 /* file stored in memory */
6430 if (len
> size
- offset
) {
6431 len
= size
- offset
;
6433 mg_write(conn
, filep
->membuf
+ offset
, (size_t)len
);
6434 } else if (len
> 0 && filep
->fp
!= NULL
) {
6435 /* file stored on disk */
6436 #if defined(__linux__)
6437 /* sendfile is only available for Linux */
6438 if (conn
->throttle
== 0 && conn
->ssl
== 0) {
6439 off_t sf_offs
= (off_t
)offset
;
6441 int sf_file
= fileno(filep
->fp
);
6445 /* 2147479552 (0x7FFFF000) is a limit found by experiment on
6446 * 64 bit Linux (2^31 minus one memory page of 4k?). */
6448 (size_t)((len
< 0x7FFFF000) ? len
: 0x7FFFF000);
6450 sendfile(conn
->client
.sock
, sf_file
, &sf_offs
, sf_tosend
);
6452 conn
->num_bytes_sent
+= sf_sent
;
6455 } else if (loop_cnt
== 0) {
6456 /* This file can not be sent using sendfile.
6457 * This might be the case for pseudo-files in the
6458 * /sys/ and /proc/ file system.
6459 * Use the regular user mode copy code instead. */
6461 } else if (sf_sent
== 0) {
6462 /* No error, but 0 bytes sent. May be EOF? */
6467 } while ((len
> 0) && (sf_sent
>= 0));
6473 /* sf_sent<0 means error, thus fall back to the classic way */
6474 /* This is always the case, if sf_file is not a "normal" file,
6475 * e.g., for sending data from the output of a CGI process. */
6476 offset
= (int64_t)sf_offs
;
6479 if ((offset
> 0) && (fseeko(filep
->fp
, offset
, SEEK_SET
) != 0)) {
6480 mg_cry(conn
, "%s: fseeko() failed: %s", __func__
, strerror(ERRNO
));
6485 "Error: Unable to access file at requested position.");
6488 /* Calculate how much to read from the file in the buffer */
6489 to_read
= sizeof(buf
);
6490 if ((int64_t)to_read
> len
) {
6494 /* Read from file, exit the loop on error */
6495 if ((num_read
= (int)fread(buf
, 1, (size_t)to_read
, filep
->fp
))
6500 /* Send read bytes to the client, exit the loop on error */
6501 if ((num_written
= mg_write(conn
, buf
, (size_t)num_read
))
6506 /* Both read and were successful, adjust counters */
6507 conn
->num_bytes_sent
+= num_written
;
6516 parse_range_header(const char *header
, int64_t *a
, int64_t *b
)
6518 return sscanf(header
, "bytes=%" INT64_FMT
"-%" INT64_FMT
, a
, b
);
6523 construct_etag(char *buf
, size_t buf_len
, const struct file
*filep
)
6525 if (filep
!= NULL
&& buf
!= NULL
) {
6527 NULL
, /* All calls to construct_etag use 64 byte buffer */
6530 "\"%lx.%" INT64_FMT
"\"",
6531 (unsigned long)filep
->last_modified
,
6538 fclose_on_exec(struct file
*filep
, struct mg_connection
*conn
)
6540 if (filep
!= NULL
&& filep
->fp
!= NULL
) {
6542 (void)conn
; /* Unused. */
6544 if (fcntl(fileno(filep
->fp
), F_SETFD
, FD_CLOEXEC
) != 0) {
6546 "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
6556 handle_static_file_request(struct mg_connection
*conn
,
6559 const char *mime_type
)
6561 char date
[64], lm
[64], etag
[64];
6562 char range
[128]; /* large enough, so there will be no overflow */
6563 const char *msg
= "OK", *hdr
;
6564 time_t curtime
= time(NULL
);
6566 struct vec mime_vec
;
6568 char gz_path
[PATH_MAX
];
6569 const char *encoding
= "";
6570 const char *cors1
, *cors2
, *cors3
;
6572 if (conn
== NULL
|| conn
->ctx
== NULL
|| filep
== NULL
) {
6576 if (mime_type
== NULL
) {
6577 get_mime_type(conn
->ctx
, path
, &mime_vec
);
6579 mime_vec
.ptr
= mime_type
;
6580 mime_vec
.len
= strlen(mime_type
);
6582 if (filep
->size
> INT64_MAX
) {
6583 send_http_error(conn
,
6585 "Error: File size is too large to send\n%" INT64_FMT
,
6588 cl
= (int64_t)filep
->size
;
6589 conn
->status_code
= 200;
6592 /* if this file is in fact a pre-gzipped file, rewrite its filename
6593 * it's important to rewrite the filename after resolving
6594 * the mime type from it, to preserve the actual file's type */
6595 if (filep
->gzipped
) {
6596 mg_snprintf(conn
, &truncated
, gz_path
, sizeof(gz_path
), "%s.gz", path
);
6599 send_http_error(conn
,
6601 "Error: Path of zipped file too long (%s)",
6607 encoding
= "Content-Encoding: gzip\r\n";
6610 if (!mg_fopen(conn
, path
, "rb", filep
)) {
6611 send_http_error(conn
,
6613 "Error: Cannot open file\nfopen(%s): %s",
6619 fclose_on_exec(filep
, conn
);
6621 /* If Range: header specified, act accordingly */
6623 hdr
= mg_get_header(conn
, "Range");
6624 if (hdr
!= NULL
&& (n
= parse_range_header(hdr
, &r1
, &r2
)) > 0 && r1
>= 0
6626 /* actually, range requests don't play well with a pre-gzipped
6627 * file (since the range is specified in the uncompressed space) */
6628 if (filep
->gzipped
) {
6633 "Error: Range requests in gzipped files are not supported");
6637 conn
->status_code
= 206;
6638 cl
= n
== 2 ? (r2
> cl
? cl
: r2
) - r1
+ 1 : cl
- r1
;
6640 NULL
, /* range buffer is big enough */
6643 "Content-Range: bytes "
6644 "%" INT64_FMT
"-%" INT64_FMT
"/%" INT64_FMT
"\r\n",
6648 msg
= "Partial Content";
6651 hdr
= mg_get_header(conn
, "Origin");
6653 /* Cross-origin resource sharing (CORS), see
6654 * http://www.html5rocks.com/en/tutorials/cors/,
6655 * http://www.html5rocks.com/static/images/cors_server_flowchart.png -
6656 * preflight is not supported for files. */
6657 cors1
= "Access-Control-Allow-Origin: ";
6658 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
6661 cors1
= cors2
= cors3
= "";
6664 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
6665 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
6666 gmt_time_string(date
, sizeof(date
), &curtime
);
6667 gmt_time_string(lm
, sizeof(lm
), &filep
->last_modified
);
6668 construct_etag(etag
, sizeof(etag
), filep
);
6670 (void)mg_printf(conn
,
6671 "HTTP/1.1 %d %s\r\n"
6680 send_static_cache_header(conn
);
6681 (void)mg_printf(conn
,
6682 "Last-Modified: %s\r\n"
6684 "Content-Type: %.*s\r\n"
6685 "Content-Length: %" INT64_FMT
"\r\n"
6686 "Connection: %s\r\n"
6687 "Accept-Ranges: bytes\r\n"
6694 suggest_connection_header(conn
),
6698 if (strcmp(conn
->request_info
.request_method
, "HEAD") != 0) {
6699 send_file_data(conn
, filep
, r1
, cl
);
6706 mg_send_file(struct mg_connection
*conn
, const char *path
)
6708 mg_send_mime_file(conn
, path
, NULL
);
6713 mg_send_mime_file(struct mg_connection
*conn
,
6715 const char *mime_type
)
6717 struct file file
= STRUCT_FILE_INITIALIZER
;
6718 if (mg_stat(conn
, path
, &file
)) {
6719 if (file
.is_directory
) {
6723 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
6725 handle_directory_request(conn
, path
);
6727 send_http_error(conn
,
6730 "Error: Directory listing denied");
6733 handle_static_file_request(conn
, path
, &file
, mime_type
);
6736 send_http_error(conn
, 404, "%s", "Error: File not found");
6741 /* For a given PUT path, create all intermediate subdirectories.
6742 * Return 0 if the path itself is a directory.
6743 * Return 1 if the path leads to a file.
6744 * Return -1 for if the path is too long.
6745 * Return -2 if path can not be created.
6748 put_dir(struct mg_connection
*conn
, const char *path
)
6752 struct file file
= STRUCT_FILE_INITIALIZER
;
6756 for (s
= p
= path
+ 2; (p
= strchr(s
, '/')) != NULL
; s
= ++p
) {
6757 len
= (size_t)(p
- path
);
6758 if (len
>= sizeof(buf
)) {
6763 memcpy(buf
, path
, len
);
6766 /* Try to create intermediate directory */
6767 DEBUG_TRACE("mkdir(%s)", buf
);
6768 if (!mg_stat(conn
, buf
, &file
) && mg_mkdir(conn
, buf
, 0755) != 0) {
6769 /* path does not exixt and can not be created */
6774 /* Is path itself a directory? */
6785 remove_bad_file(const struct mg_connection
*conn
, const char *path
)
6787 int r
= mg_remove(conn
, path
);
6789 mg_cry(conn
, "%s: Cannot remove invalid file %s", __func__
, path
);
6795 mg_store_body(struct mg_connection
*conn
, const char *path
)
6797 char buf
[MG_BUF_LEN
];
6802 if (conn
->consumed_content
!= 0) {
6803 mg_cry(conn
, "%s: Contents already consumed", __func__
);
6807 ret
= put_dir(conn
, path
);
6809 /* -1 for path too long,
6810 * -2 for path can not be created. */
6814 /* Return 0 means, path itself is a directory. */
6818 if (mg_fopen(conn
, path
, "w", &fi
) == 0) {
6822 ret
= mg_read(conn
, buf
, sizeof(buf
));
6824 n
= (int)fwrite(buf
, 1, (size_t)ret
, fi
.fp
);
6827 remove_bad_file(conn
, path
);
6830 ret
= mg_read(conn
, buf
, sizeof(buf
));
6833 /* TODO: mg_fclose should return an error,
6834 * and every caller should check and handle it. */
6835 if (fclose(fi
.fp
) != 0) {
6836 remove_bad_file(conn
, path
);
6844 /* Parse HTTP headers from the given buffer, advance buffer to the point
6845 * where parsing stopped. */
6847 parse_http_headers(char **buf
, struct mg_request_info
*ri
)
6855 ri
->num_headers
= 0;
6857 for (i
= 0; i
< (int)ARRAY_SIZE(ri
->http_headers
); i
++) {
6859 while ((*dp
!= ':') && (*dp
!= '\r') && (*dp
!= 0)) {
6863 /* neither : nor \r\n. This is not a valid field. */
6867 if (dp
[1] == '\n') {
6869 ri
->http_headers
[i
].name
= *buf
;
6870 ri
->http_headers
[i
].value
= 0;
6873 /* stray \r. This is not valid. */
6879 ri
->http_headers
[i
].name
= *buf
;
6882 } while (*dp
== ' ');
6884 ri
->http_headers
[i
].value
= dp
;
6885 *buf
= strstr(dp
, "\r\n");
6888 ri
->num_headers
= i
+ 1;
6898 if (*buf
[0] == '\r') {
6899 /* This is the end of the header */
6907 is_valid_http_method(const char *method
)
6909 return !strcmp(method
, "GET") /* HTTP (RFC 2616) */
6910 || !strcmp(method
, "POST") /* HTTP (RFC 2616) */
6911 || !strcmp(method
, "HEAD") /* HTTP (RFC 2616) */
6912 || !strcmp(method
, "PUT") /* HTTP (RFC 2616) */
6913 || !strcmp(method
, "DELETE") /* HTTP (RFC 2616) */
6914 || !strcmp(method
, "OPTIONS") /* HTTP (RFC 2616) */
6915 /* TRACE method (RFC 2616) is not supported for security reasons */
6916 || !strcmp(method
, "CONNECT") /* HTTP (RFC 2616) */
6918 || !strcmp(method
, "PROPFIND") /* WEBDAV (RFC 2518) */
6919 || !strcmp(method
, "MKCOL") /* WEBDAV (RFC 2518) */
6921 /* Unsupported WEBDAV Methods: */
6922 /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
6923 /* + 11 methods from RFC 3253 */
6924 /* ORDERPATCH (RFC 3648) */
6925 /* ACL (RFC 3744) */
6926 /* SEARCH (RFC 5323) */
6927 /* + MicroSoft extensions
6928 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
6930 /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
6931 || !strcmp(method
, "PATCH"); /* PATCH method (RFC 5789) */
6935 /* Parse HTTP request, fill in mg_request_info structure.
6936 * This function modifies the buffer by NUL-terminating
6937 * HTTP request components, header names and header values. */
6939 parse_http_message(int check_method
,
6942 struct mg_request_info
*ri
)
6944 int is_request
, request_length
;
6950 request_length
= get_request_len(buf
, len
);
6952 if (request_length
> 0) {
6953 /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
6955 ri
->remote_user
= ri
->request_method
= ri
->request_uri
=
6956 ri
->http_version
= NULL
;
6957 ri
->num_headers
= 0;
6959 buf
[request_length
- 1] = '\0';
6961 /* RFC says that all initial whitespaces should be ingored */
6962 while (*buf
!= '\0' && isspace(*(unsigned char *)buf
)) {
6965 ri
->request_method
= skip(&buf
, " ");
6966 ri
->request_uri
= skip(&buf
, " ");
6967 ri
->http_version
= skip(&buf
, "\r\n");
6969 /* HTTP message could be either HTTP request or HTTP response, e.g.
6970 * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
6972 check_method
? is_valid_http_method(ri
->request_method
) : 1;
6973 if ((is_request
&& memcmp(ri
->http_version
, "HTTP/", 5) != 0)
6974 || (!is_request
&& memcmp(ri
->request_method
, "HTTP/", 5) != 0)) {
6975 request_length
= -1;
6978 ri
->http_version
+= 5;
6980 parse_http_headers(&buf
, ri
);
6983 return request_length
;
6987 /* Keep reading the input (either opened file descriptor fd, or socket sock,
6988 * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
6989 * buffer (which marks the end of HTTP request). Buffer buf may already
6990 * have some data. The length of the data is stored in nread.
6991 * Upon every read operation, increase nread by the number of bytes read. */
6993 read_request(FILE *fp
,
6994 struct mg_connection
*conn
,
6999 int request_len
, n
= 0;
7000 struct timespec last_action_time
;
7001 double request_timeout
;
7007 memset(&last_action_time
, 0, sizeof(last_action_time
));
7009 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
7010 /* value of request_timeout is in seconds, config in milliseconds */
7011 request_timeout
= atof(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
7013 request_timeout
= -1.0;
7016 request_len
= get_request_len(buf
, *nread
);
7018 /* first time reading from this connection */
7019 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
7022 (conn
->ctx
->stop_flag
== 0) && (*nread
< bufsiz
) && (request_len
== 0)
7023 && ((mg_difftimespec(&last_action_time
, &(conn
->req_time
))
7024 <= request_timeout
) || (request_timeout
< 0))
7025 && ((n
= pull(fp
, conn
, buf
+ *nread
, bufsiz
- *nread
, request_timeout
))
7028 /* assert(*nread <= bufsiz); */
7029 if (*nread
> bufsiz
) {
7032 request_len
= get_request_len(buf
, *nread
);
7033 if (request_timeout
> 0.0) {
7034 clock_gettime(CLOCK_MONOTONIC
, &last_action_time
);
7038 return (request_len
<= 0 && n
<= 0) ? -1 : request_len
;
7041 #if !defined(NO_FILES)
7042 /* For given directory path, substitute it to valid index file.
7043 * Return 1 if index file has been found, 0 if not found.
7044 * If the file is found, it's stats is returned in stp. */
7046 substitute_index_file(struct mg_connection
*conn
,
7051 if (conn
&& conn
->ctx
) {
7052 const char *list
= conn
->ctx
->config
[INDEX_FILES
];
7053 struct file file
= STRUCT_FILE_INITIALIZER
;
7054 struct vec filename_vec
;
7055 size_t n
= strlen(path
);
7058 /* The 'path' given to us points to the directory. Remove all trailing
7059 * directory separator characters from the end of the path, and
7060 * then append single directory separator character. */
7061 while (n
> 0 && path
[n
- 1] == '/') {
7066 /* Traverse index files list. For each entry, append it to the given
7067 * path and see if the file exists. If it exists, break the loop */
7068 while ((list
= next_option(list
, &filename_vec
, NULL
)) != NULL
) {
7069 /* Ignore too long entries that may overflow path buffer */
7070 if (filename_vec
.len
> path_len
- (n
+ 2)) {
7074 /* Prepare full path to the index file */
7075 mg_strlcpy(path
+ n
+ 1, filename_vec
.ptr
, filename_vec
.len
+ 1);
7077 /* Does it exist? */
7078 if (mg_stat(conn
, path
, &file
)) {
7079 /* Yes it does, break the loop */
7086 /* If no index file exists, restore directory path */
7098 #if !defined(NO_CACHING)
7099 /* Return True if we should reply 304 Not Modified. */
7101 is_not_modified(const struct mg_connection
*conn
, const struct file
*filep
)
7104 const char *ims
= mg_get_header(conn
, "If-Modified-Since");
7105 const char *inm
= mg_get_header(conn
, "If-None-Match");
7106 construct_etag(etag
, sizeof(etag
), filep
);
7110 return (inm
!= NULL
&& !mg_strcasecmp(etag
, inm
))
7111 || (ims
!= NULL
&& (filep
->last_modified
<= parse_date_string(ims
)));
7113 #endif /* !NO_CACHING */
7116 #if !defined(NO_CGI) || !defined(NO_FILES)
7118 forward_body_data(struct mg_connection
*conn
, FILE *fp
, SOCKET sock
, SSL
*ssl
)
7120 const char *expect
, *body
;
7121 char buf
[MG_BUF_LEN
];
7122 int to_read
, nread
, success
= 0;
7123 int64_t buffered_len
;
7124 double timeout
= -1.0;
7129 if (conn
->ctx
->config
[REQUEST_TIMEOUT
]) {
7130 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
7133 expect
= mg_get_header(conn
, "Expect");
7134 /* assert(fp != NULL); */
7136 send_http_error(conn
, 500, "%s", "Error: NULL File");
7140 if (conn
->content_len
== -1 && !conn
->is_chunked
) {
7141 /* Content length is not specified by the client. */
7142 send_http_error(conn
,
7145 "Error: Client did not specify content length");
7146 } else if ((expect
!= NULL
)
7147 && (mg_strcasecmp(expect
, "100-continue") != 0)) {
7148 /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
7149 send_http_error(conn
,
7151 "Error: Can not fulfill expectation %s",
7154 if (expect
!= NULL
) {
7155 (void)mg_printf(conn
, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
7156 conn
->status_code
= 100;
7158 conn
->status_code
= 200;
7161 buffered_len
= (int64_t)(conn
->data_len
) - (int64_t)conn
->request_len
7162 - conn
->consumed_content
;
7164 /* assert(buffered_len >= 0); */
7165 /* assert(conn->consumed_content == 0); */
7167 if ((buffered_len
< 0) || (conn
->consumed_content
!= 0)) {
7168 send_http_error(conn
, 500, "%s", "Error: Size mismatch");
7172 if (buffered_len
> 0) {
7173 if ((int64_t)buffered_len
> conn
->content_len
) {
7174 buffered_len
= (int)conn
->content_len
;
7176 body
= conn
->buf
+ conn
->request_len
+ conn
->consumed_content
;
7177 push_all(conn
->ctx
, fp
, sock
, ssl
, body
, (int64_t)buffered_len
);
7178 conn
->consumed_content
+= buffered_len
;
7182 while (conn
->consumed_content
< conn
->content_len
) {
7183 to_read
= sizeof(buf
);
7184 if ((int64_t)to_read
> conn
->content_len
- conn
->consumed_content
) {
7185 to_read
= (int)(conn
->content_len
- conn
->consumed_content
);
7187 nread
= pull(NULL
, conn
, buf
, to_read
, timeout
);
7189 || push_all(conn
->ctx
, fp
, sock
, ssl
, buf
, nread
) != nread
) {
7192 conn
->consumed_content
+= nread
;
7195 if (conn
->consumed_content
== conn
->content_len
) {
7196 success
= (nread
>= 0);
7199 /* Each error code path in this function must send an error */
7201 /* NOTE: Maybe some data has already been sent. */
7202 /* TODO (low): If some data has been sent, a correct error
7203 * reply can no longer be sent, so just close the connection */
7204 send_http_error(conn
, 500, "%s", "");
7212 #if !defined(NO_CGI)
7213 /* This structure helps to create an environment for the spawned CGI program.
7214 * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
7215 * last element must be NULL.
7216 * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
7217 * strings must reside in a contiguous buffer. The end of the buffer is
7218 * marked by two '\0' characters.
7219 * We satisfy both worlds: we create an envp array (which is vars), all
7220 * entries are actually pointers inside buf. */
7221 struct cgi_environment
{
7222 struct mg_connection
*conn
;
7224 char *buf
; /* Environment buffer */
7225 size_t buflen
; /* Space available in buf */
7226 size_t bufused
; /* Space taken in buf */
7228 char **var
; /* char **envp */
7229 size_t varlen
; /* Number of variables available in var */
7230 size_t varused
; /* Number of variables stored in var */
7234 static void addenv(struct cgi_environment
*env
,
7235 PRINTF_FORMAT_STRING(const char *fmt
),
7236 ...) PRINTF_ARGS(2, 3);
7238 /* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
7239 * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
7241 addenv(struct cgi_environment
*env
, const char *fmt
, ...)
7248 /* Calculate how much space is left in the buffer */
7249 space
= (env
->buflen
- env
->bufused
);
7251 /* Calculate an estimate for the required space */
7252 n
= strlen(fmt
) + 2 + 128;
7256 /* Allocate new buffer */
7257 n
= env
->buflen
+ CGI_ENVIRONMENT_SIZE
;
7258 added
= (char *)mg_realloc(env
->buf
, n
);
7262 "%s: Cannot allocate memory for CGI variable [%s]",
7269 space
= (env
->buflen
- env
->bufused
);
7272 /* Make a pointer to the free space int the buffer */
7273 added
= env
->buf
+ env
->bufused
;
7275 /* Copy VARIABLE=VALUE\0 string into the free space */
7277 mg_vsnprintf(env
->conn
, &truncated
, added
, (size_t)space
, fmt
, ap
);
7280 /* Do not add truncated strings to the environment */
7282 /* Reallocate the buffer */
7286 } while (truncated
);
7288 /* Calculate number of bytes added to the environment */
7289 n
= strlen(added
) + 1;
7292 /* Now update the variable index */
7293 space
= (env
->varlen
- env
->varused
);
7296 "%s: Cannot register CGI variable [%s]",
7302 /* Append a pointer to the added string into the envp array */
7303 env
->var
[env
->varused
] = added
;
7309 prepare_cgi_environment(struct mg_connection
*conn
,
7311 struct cgi_environment
*env
)
7315 char *p
, src_addr
[IP_ADDR_STR_LEN
], http_var_name
[128];
7318 if (conn
== NULL
|| prog
== NULL
|| env
== NULL
) {
7323 env
->buflen
= CGI_ENVIRONMENT_SIZE
;
7325 env
->buf
= (char *)mg_malloc(env
->buflen
);
7326 env
->varlen
= MAX_CGI_ENVIR_VARS
;
7328 env
->var
= (char **)mg_malloc(env
->buflen
* sizeof(char *));
7330 addenv(env
, "SERVER_NAME=%s", conn
->ctx
->config
[AUTHENTICATION_DOMAIN
]);
7331 addenv(env
, "SERVER_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7332 addenv(env
, "DOCUMENT_ROOT=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7333 addenv(env
, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
7335 /* Prepare the environment block */
7336 addenv(env
, "%s", "GATEWAY_INTERFACE=CGI/1.1");
7337 addenv(env
, "%s", "SERVER_PROTOCOL=HTTP/1.1");
7338 addenv(env
, "%s", "REDIRECT_STATUS=200"); /* For PHP */
7340 #if defined(USE_IPV6)
7341 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
7342 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin6
.sin6_port
));
7346 addenv(env
, "SERVER_PORT=%d", ntohs(conn
->client
.lsa
.sin
.sin_port
));
7349 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
7350 addenv(env
, "REMOTE_ADDR=%s", src_addr
);
7352 addenv(env
, "REQUEST_METHOD=%s", conn
->request_info
.request_method
);
7353 addenv(env
, "REMOTE_PORT=%d", conn
->request_info
.remote_port
);
7355 addenv(env
, "REQUEST_URI=%s", conn
->request_info
.request_uri
);
7356 addenv(env
, "LOCAL_URI=%s", conn
->request_info
.local_uri
);
7361 (int)strlen(conn
->request_info
.local_uri
)
7362 - ((conn
->path_info
== NULL
) ? 0 : (int)strlen(conn
->path_info
)),
7363 conn
->request_info
.local_uri
);
7365 addenv(env
, "SCRIPT_FILENAME=%s", prog
);
7366 if (conn
->path_info
== NULL
) {
7367 addenv(env
, "PATH_TRANSLATED=%s", conn
->ctx
->config
[DOCUMENT_ROOT
]);
7370 "PATH_TRANSLATED=%s%s",
7371 conn
->ctx
->config
[DOCUMENT_ROOT
],
7375 addenv(env
, "HTTPS=%s", conn
->ssl
== NULL
? "off" : "on");
7377 if ((s
= mg_get_header(conn
, "Content-Type")) != NULL
) {
7378 addenv(env
, "CONTENT_TYPE=%s", s
);
7380 if (conn
->request_info
.query_string
!= NULL
) {
7381 addenv(env
, "QUERY_STRING=%s", conn
->request_info
.query_string
);
7383 if ((s
= mg_get_header(conn
, "Content-Length")) != NULL
) {
7384 addenv(env
, "CONTENT_LENGTH=%s", s
);
7386 if ((s
= getenv("PATH")) != NULL
) {
7387 addenv(env
, "PATH=%s", s
);
7389 if (conn
->path_info
!= NULL
) {
7390 addenv(env
, "PATH_INFO=%s", conn
->path_info
);
7393 if (conn
->status_code
> 0) {
7394 /* CGI error handler should show the status code */
7395 addenv(env
, "STATUS=%d", conn
->status_code
);
7399 if ((s
= getenv("COMSPEC")) != NULL
) {
7400 addenv(env
, "COMSPEC=%s", s
);
7402 if ((s
= getenv("SYSTEMROOT")) != NULL
) {
7403 addenv(env
, "SYSTEMROOT=%s", s
);
7405 if ((s
= getenv("SystemDrive")) != NULL
) {
7406 addenv(env
, "SystemDrive=%s", s
);
7408 if ((s
= getenv("ProgramFiles")) != NULL
) {
7409 addenv(env
, "ProgramFiles=%s", s
);
7411 if ((s
= getenv("ProgramFiles(x86)")) != NULL
) {
7412 addenv(env
, "ProgramFiles(x86)=%s", s
);
7415 if ((s
= getenv("LD_LIBRARY_PATH")) != NULL
) {
7416 addenv(env
, "LD_LIBRARY_PATH=%s", s
);
7420 if ((s
= getenv("PERLLIB")) != NULL
) {
7421 addenv(env
, "PERLLIB=%s", s
);
7424 if (conn
->request_info
.remote_user
!= NULL
) {
7425 addenv(env
, "REMOTE_USER=%s", conn
->request_info
.remote_user
);
7426 addenv(env
, "%s", "AUTH_TYPE=Digest");
7429 /* Add all headers as HTTP_* variables */
7430 for (i
= 0; i
< conn
->request_info
.num_headers
; i
++) {
7432 (void)mg_snprintf(conn
,
7435 sizeof(http_var_name
),
7437 conn
->request_info
.http_headers
[i
].name
);
7441 "%s: HTTP header variable too long [%s]",
7443 conn
->request_info
.http_headers
[i
].name
);
7447 /* Convert variable name into uppercase, and change - to _ */
7448 for (p
= http_var_name
; *p
!= '\0'; p
++) {
7452 *p
= (char)toupper(*(unsigned char *)p
);
7458 conn
->request_info
.http_headers
[i
].value
);
7461 /* Add user-specified variables */
7462 s
= conn
->ctx
->config
[CGI_ENVIRONMENT
];
7463 while ((s
= next_option(s
, &var_vec
, NULL
)) != NULL
) {
7464 addenv(env
, "%.*s", (int)var_vec
.len
, var_vec
.ptr
);
7467 env
->var
[env
->varused
] = NULL
;
7468 env
->buf
[env
->bufused
] = '\0';
7473 handle_cgi_request(struct mg_connection
*conn
, const char *prog
)
7477 int headers_len
, data_len
, i
, truncated
;
7478 int fdin
[2] = {-1, -1}, fdout
[2] = {-1, -1}, fderr
[2] = {-1, -1};
7479 const char *status
, *status_text
, *connection_state
;
7480 char *pbuf
, dir
[PATH_MAX
], *p
;
7481 struct mg_request_info ri
;
7482 struct cgi_environment blk
;
7483 FILE *in
= NULL
, *out
= NULL
, *err
= NULL
;
7484 struct file fout
= STRUCT_FILE_INITIALIZER
;
7485 pid_t pid
= (pid_t
)-1;
7493 prepare_cgi_environment(conn
, prog
, &blk
);
7495 /* CGI must be executed in its own directory. 'dir' must point to the
7496 * directory containing executable program, 'p' must point to the
7497 * executable program name relative to 'dir'. */
7498 (void)mg_snprintf(conn
, &truncated
, dir
, sizeof(dir
), "%s", prog
);
7501 mg_cry(conn
, "Error: CGI program \"%s\": Path too long", prog
);
7502 send_http_error(conn
, 500, "Error: %s", "CGI path too long");
7506 if ((p
= strrchr(dir
, '/')) != NULL
) {
7509 dir
[0] = '.', dir
[1] = '\0';
7513 if (pipe(fdin
) != 0 || pipe(fdout
) != 0 || pipe(fderr
) != 0) {
7514 status
= strerror(ERRNO
);
7516 "Error: CGI program \"%s\": Can not create CGI pipes: %s",
7519 send_http_error(conn
, 500, "Error: Cannot create CGI pipe: %s", status
);
7523 pid
= spawn_process(conn
, p
, blk
.buf
, blk
.var
, fdin
, fdout
, fderr
, dir
);
7525 if (pid
== (pid_t
)-1) {
7526 status
= strerror(ERRNO
);
7528 "Error: CGI program \"%s\": Can not spawn CGI process: %s",
7531 send_http_error(conn
,
7533 "Error: Cannot spawn CGI process [%s]: %s",
7539 /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
7540 set_close_on_exec((SOCKET
)fdin
[0], conn
); /* stdin read */
7541 set_close_on_exec((SOCKET
)fdout
[1], conn
); /* stdout write */
7542 set_close_on_exec((SOCKET
)fderr
[1], conn
); /* stderr write */
7543 set_close_on_exec((SOCKET
)fdin
[1], conn
); /* stdin write */
7544 set_close_on_exec((SOCKET
)fdout
[0], conn
); /* stdout read */
7545 set_close_on_exec((SOCKET
)fderr
[0], conn
); /* stderr read */
7547 /* Parent closes only one side of the pipes.
7548 * If we don't mark them as closed, close() attempt before
7549 * return from this function throws an exception on Windows.
7550 * Windows does not like when closed descriptor is closed again. */
7551 (void)close(fdin
[0]);
7552 (void)close(fdout
[1]);
7553 (void)close(fderr
[1]);
7554 fdin
[0] = fdout
[1] = fderr
[1] = -1;
7556 if ((in
= fdopen(fdin
[1], "wb")) == NULL
) {
7557 status
= strerror(ERRNO
);
7559 "Error: CGI program \"%s\": Can not open stdin: %s",
7562 send_http_error(conn
,
7564 "Error: CGI can not open fdin\nfopen: %s",
7569 if ((out
= fdopen(fdout
[0], "rb")) == NULL
) {
7570 status
= strerror(ERRNO
);
7572 "Error: CGI program \"%s\": Can not open stdout: %s",
7575 send_http_error(conn
,
7577 "Error: CGI can not open fdout\nfopen: %s",
7582 if ((err
= fdopen(fderr
[0], "rb")) == NULL
) {
7583 status
= strerror(ERRNO
);
7585 "Error: CGI program \"%s\": Can not open stderr: %s",
7588 send_http_error(conn
,
7590 "Error: CGI can not open fdout\nfopen: %s",
7600 if ((conn
->request_info
.content_length
> 0) || conn
->is_chunked
) {
7601 /* This is a POST/PUT request, or another request with body data. */
7602 if (!forward_body_data(conn
, in
, INVALID_SOCKET
, NULL
)) {
7603 /* Error sending the body data */
7605 "Error: CGI program \"%s\": Forward body data failed",
7611 /* Close so child gets an EOF. */
7616 /* Now read CGI reply into a buffer. We need to set correct
7617 * status code, thus we need to see all HTTP headers first.
7618 * Do not send anything back to client, until we buffer in all
7621 buf
= (char *)mg_malloc(buflen
);
7623 send_http_error(conn
,
7625 "Error: Not enough memory for CGI buffer (%u bytes)",
7626 (unsigned int)buflen
);
7628 "Error: CGI program \"%s\": Not enough memory for buffer (%u "
7631 (unsigned int)buflen
);
7634 headers_len
= read_request(out
, conn
, buf
, (int)buflen
, &data_len
);
7635 if (headers_len
<= 0) {
7637 /* Could not parse the CGI response. Check if some error message on
7639 i
= pull_all(err
, conn
, buf
, (int)buflen
);
7642 "Error: CGI program \"%s\" sent error "
7647 send_http_error(conn
,
7649 "Error: CGI program \"%s\" sent error "
7656 "Error: CGI program sent malformed or too big "
7657 "(>%u bytes) HTTP headers: [%.*s]",
7662 send_http_error(conn
,
7664 "Error: CGI program sent malformed or too big "
7665 "(>%u bytes) HTTP headers: [%.*s]",
7674 buf
[headers_len
- 1] = '\0';
7675 parse_http_headers(&pbuf
, &ri
);
7677 /* Make up and send the status line */
7679 if ((status
= get_header(&ri
, "Status")) != NULL
) {
7680 conn
->status_code
= atoi(status
);
7681 status_text
= status
;
7682 while (isdigit(*(const unsigned char *)status_text
)
7683 || *status_text
== ' ') {
7686 } else if (get_header(&ri
, "Location") != NULL
) {
7687 conn
->status_code
= 302;
7689 conn
->status_code
= 200;
7691 connection_state
= get_header(&ri
, "Connection");
7692 if (!header_has_option(connection_state
, "keep-alive")) {
7693 conn
->must_close
= 1;
7695 (void)mg_printf(conn
, "HTTP/1.1 %d %s\r\n", conn
->status_code
, status_text
);
7698 for (i
= 0; i
< ri
.num_headers
; i
++) {
7701 ri
.http_headers
[i
].name
,
7702 ri
.http_headers
[i
].value
);
7704 mg_write(conn
, "\r\n", 2);
7706 /* Send chunk of data that may have been read after the headers */
7707 conn
->num_bytes_sent
+=
7708 mg_write(conn
, buf
+ headers_len
, (size_t)(data_len
- headers_len
));
7710 /* Read the rest of CGI output and send to the client */
7711 send_file_data(conn
, &fout
, 0, INT64_MAX
);
7717 if (pid
!= (pid_t
)-1) {
7719 #if !defined(_WIN32)
7722 while (waitpid(pid
, &st
, 0) != -1)
7723 ; /* clean zombies */
7727 if (fdin
[0] != -1) {
7730 if (fdout
[1] != -1) {
7736 } else if (fdin
[1] != -1) {
7742 } else if (fdout
[0] != -1) {
7748 } else if (fderr
[0] != -1) {
7756 #endif /* !NO_CGI */
7759 #if !defined(NO_FILES)
7761 mkcol(struct mg_connection
*conn
, const char *path
)
7766 time_t curtime
= time(NULL
);
7772 /* TODO (mid): Check the send_http_error situations in this function */
7774 memset(&de
.file
, 0, sizeof(de
.file
));
7775 if (!mg_stat(conn
, path
, &de
.file
)) {
7777 "%s: mg_stat(%s) failed: %s",
7783 if (de
.file
.last_modified
) {
7784 /* TODO (high): This check does not seem to make any sense ! */
7786 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7790 body_len
= conn
->data_len
- conn
->request_len
;
7793 conn
, 415, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7797 rc
= mg_mkdir(conn
, path
, 0755);
7800 conn
->status_code
= 201;
7801 gmt_time_string(date
, sizeof(date
), &curtime
);
7803 "HTTP/1.1 %d Created\r\n"
7807 send_static_cache_header(conn
);
7809 "Content-Length: 0\r\n"
7810 "Connection: %s\r\n\r\n",
7811 suggest_connection_header(conn
));
7812 } else if (rc
== -1) {
7813 if (errno
== EEXIST
) {
7815 conn
, 405, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7816 } else if (errno
== EACCES
) {
7818 conn
, 403, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7819 } else if (errno
== ENOENT
) {
7821 conn
, 409, "Error: mkcol(%s): %s", path
, strerror(ERRNO
));
7823 send_http_error(conn
, 500, "fopen(%s): %s", path
, strerror(ERRNO
));
7830 put_file(struct mg_connection
*conn
, const char *path
)
7832 struct file file
= STRUCT_FILE_INITIALIZER
;
7837 time_t curtime
= time(NULL
);
7843 if (mg_stat(conn
, path
, &file
)) {
7844 /* File already exists */
7845 conn
->status_code
= 200;
7847 if (file
.is_directory
) {
7848 /* This is an already existing directory,
7849 * so there is nothing to do for the server. */
7853 /* File exists and is not a directory. */
7854 /* Can it be replaced? */
7856 if (file
.membuf
!= NULL
) {
7857 /* This is an "in-memory" file, that can not be replaced */
7861 "Error: Put not possible\nReplacing %s is not supported",
7866 /* Check if the server may write this file */
7867 if (access(path
, W_OK
) == 0) {
7868 /* Access granted */
7869 conn
->status_code
= 200;
7875 "Error: Put not possible\nReplacing %s is not allowed",
7881 /* File should be created */
7882 conn
->status_code
= 201;
7883 rc
= put_dir(conn
, path
);
7887 /* put_dir returns 0 if path is a directory */
7888 gmt_time_string(date
, sizeof(date
), &curtime
);
7890 "HTTP/1.1 %d %s\r\n",
7892 mg_get_response_code_text(NULL
, conn
->status_code
));
7893 send_no_cache_header(conn
);
7896 "Content-Length: 0\r\n"
7897 "Connection: %s\r\n\r\n",
7899 suggest_connection_header(conn
));
7901 /* Request to create a directory has been fulfilled successfully.
7902 * No need to put a file. */
7907 /* put_dir returns -1 if the path is too long */
7908 send_http_error(conn
,
7910 "Error: Path too long\nput_dir(%s): %s",
7917 /* put_dir returns -2 if the directory can not be created */
7918 send_http_error(conn
,
7920 "Error: Can not create directory\nput_dir(%s): %s",
7926 /* A file should be created or overwritten. */
7927 if (!mg_fopen(conn
, path
, "wb+", &file
) || file
.fp
== NULL
) {
7929 send_http_error(conn
,
7931 "Error: Can not create file\nfopen(%s): %s",
7937 fclose_on_exec(&file
, conn
);
7938 range
= mg_get_header(conn
, "Content-Range");
7940 if (range
!= NULL
&& parse_range_header(range
, &r1
, &r2
) > 0) {
7941 conn
->status_code
= 206; /* Partial content */
7942 fseeko(file
.fp
, r1
, SEEK_SET
);
7945 if (!forward_body_data(conn
, file
.fp
, INVALID_SOCKET
, NULL
)) {
7946 /* forward_body_data failed.
7947 * The error code has already been sent to the client,
7948 * and conn->status_code is already set. */
7953 gmt_time_string(date
, sizeof(date
), &curtime
);
7955 "HTTP/1.1 %d %s\r\n",
7957 mg_get_response_code_text(NULL
, conn
->status_code
));
7958 send_no_cache_header(conn
);
7961 "Content-Length: 0\r\n"
7962 "Connection: %s\r\n\r\n",
7964 suggest_connection_header(conn
));
7971 delete_file(struct mg_connection
*conn
, const char *path
)
7974 memset(&de
.file
, 0, sizeof(de
.file
));
7975 if (!mg_stat(conn
, path
, &de
.file
)) {
7976 /* mg_stat returns 0 if the file does not exist */
7977 send_http_error(conn
,
7979 "Error: Cannot delete file\nFile %s not found",
7984 if (de
.file
.membuf
!= NULL
) {
7985 /* the file is cached in memory */
7989 "Error: Delete not possible\nDeleting %s is not supported",
7994 if (de
.file
.is_directory
) {
7995 if (remove_directory(conn
, path
)) {
7996 /* Delete is successful: Return 204 without content. */
7997 send_http_error(conn
, 204, "%s", "");
7999 /* Delete is not successful: Return 500 (Server error). */
8000 send_http_error(conn
, 500, "Error: Could not delete %s", path
);
8005 /* This is an existing file (not a directory).
8006 * Check if write permission is granted. */
8007 if (access(path
, W_OK
) != 0) {
8008 /* File is read only */
8012 "Error: Delete not possible\nDeleting %s is not allowed",
8017 /* Try to delete it. */
8018 if (mg_remove(conn
, path
) == 0) {
8019 /* Delete was successful: Return 204 without content. */
8020 send_http_error(conn
, 204, "%s", "");
8022 /* Delete not successful (file locked). */
8023 send_http_error(conn
,
8025 "Error: Cannot delete file\nremove(%s): %s",
8030 #endif /* !NO_FILES */
8034 send_ssi_file(struct mg_connection
*, const char *, struct file
*, int);
8038 do_ssi_include(struct mg_connection
*conn
,
8043 char file_name
[MG_BUF_LEN
], path
[512], *p
;
8044 struct file file
= STRUCT_FILE_INITIALIZER
;
8052 /* sscanf() is safe here, since send_ssi_file() also uses buffer
8053 * of size MG_BUF_LEN to get the tag. So strlen(tag) is
8054 * always < MG_BUF_LEN. */
8055 if (sscanf(tag
, " virtual=\"%511[^\"]\"", file_name
) == 1) {
8056 /* File name is relative to the webserver root */
8058 (void)mg_snprintf(conn
,
8063 conn
->ctx
->config
[DOCUMENT_ROOT
],
8066 } else if (sscanf(tag
, " abspath=\"%511[^\"]\"", file_name
) == 1) {
8067 /* File name is relative to the webserver working directory
8068 * or it is absolute system path */
8071 mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", file_name
);
8073 } else if (sscanf(tag
, " file=\"%511[^\"]\"", file_name
) == 1
8074 || sscanf(tag
, " \"%511[^\"]\"", file_name
) == 1) {
8075 /* File name is relative to the currect document */
8077 (void)mg_snprintf(conn
, &truncated
, path
, sizeof(path
), "%s", ssi
);
8080 if ((p
= strrchr(path
, '/')) != NULL
) {
8084 (void)mg_snprintf(conn
,
8093 mg_cry(conn
, "Bad SSI #include: [%s]", tag
);
8098 mg_cry(conn
, "SSI #include path length overflow: [%s]", tag
);
8102 if (!mg_fopen(conn
, path
, "rb", &file
)) {
8104 "Cannot open SSI #include: [%s]: fopen(%s): %s",
8109 fclose_on_exec(&file
, conn
);
8110 if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
8111 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
8113 send_ssi_file(conn
, path
, &file
, include_level
+ 1);
8115 send_file_data(conn
, &file
, 0, INT64_MAX
);
8122 #if !defined(NO_POPEN)
8124 do_ssi_exec(struct mg_connection
*conn
, char *tag
)
8126 char cmd
[1024] = "";
8127 struct file file
= STRUCT_FILE_INITIALIZER
;
8129 if (sscanf(tag
, " \"%1023[^\"]\"", cmd
) != 1) {
8130 mg_cry(conn
, "Bad SSI #exec: [%s]", tag
);
8133 if ((file
.fp
= popen(cmd
, "r")) == NULL
) {
8134 mg_cry(conn
, "Cannot SSI #exec: [%s]: %s", cmd
, strerror(ERRNO
));
8136 send_file_data(conn
, &file
, 0, INT64_MAX
);
8141 #endif /* !NO_POPEN */
8145 mg_fgetc(struct file
*filep
, int offset
)
8147 if (filep
== NULL
) {
8150 if (filep
->membuf
!= NULL
&& offset
>= 0
8151 && ((unsigned int)(offset
)) < filep
->size
) {
8152 return ((const unsigned char *)filep
->membuf
)[offset
];
8153 } else if (filep
->fp
!= NULL
) {
8154 return fgetc(filep
->fp
);
8162 send_ssi_file(struct mg_connection
*conn
,
8167 char buf
[MG_BUF_LEN
];
8168 int ch
, offset
, len
, in_ssi_tag
;
8170 if (include_level
> 10) {
8171 mg_cry(conn
, "SSI #include level is too deep (%s)", path
);
8175 in_ssi_tag
= len
= offset
= 0;
8176 while ((ch
= mg_fgetc(filep
, offset
)) != EOF
) {
8177 if (in_ssi_tag
&& ch
== '>') {
8179 buf
[len
++] = (char)ch
;
8181 /* assert(len <= (int) sizeof(buf)); */
8182 if (len
> (int)sizeof(buf
)) {
8185 if (len
< 6 || memcmp(buf
, "<!--#", 5) != 0) {
8186 /* Not an SSI tag, pass it */
8187 (void)mg_write(conn
, buf
, (size_t)len
);
8189 if (!memcmp(buf
+ 5, "include", 7)) {
8190 do_ssi_include(conn
, path
, buf
+ 12, include_level
);
8191 #if !defined(NO_POPEN)
8192 } else if (!memcmp(buf
+ 5, "exec", 4)) {
8193 do_ssi_exec(conn
, buf
+ 9);
8194 #endif /* !NO_POPEN */
8204 } else if (in_ssi_tag
) {
8205 if (len
== 5 && memcmp(buf
, "<!--#", 5) != 0) {
8206 /* Not an SSI tag */
8208 } else if (len
== (int)sizeof(buf
) - 2) {
8209 mg_cry(conn
, "%s: SSI tag is too large", path
);
8212 buf
[len
++] = (char)(ch
& 0xff);
8213 } else if (ch
== '<') {
8216 mg_write(conn
, buf
, (size_t)len
);
8219 buf
[len
++] = (char)(ch
& 0xff);
8221 buf
[len
++] = (char)(ch
& 0xff);
8222 if (len
== (int)sizeof(buf
)) {
8223 mg_write(conn
, buf
, (size_t)len
);
8229 /* Send the rest of buffered data */
8231 mg_write(conn
, buf
, (size_t)len
);
8237 handle_ssi_file_request(struct mg_connection
*conn
,
8242 time_t curtime
= time(NULL
);
8243 const char *cors1
, *cors2
, *cors3
;
8245 if (conn
== NULL
|| path
== NULL
|| filep
== NULL
) {
8249 if (mg_get_header(conn
, "Origin")) {
8250 /* Cross-origin resource sharing (CORS). */
8251 cors1
= "Access-Control-Allow-Origin: ";
8252 cors2
= conn
->ctx
->config
[ACCESS_CONTROL_ALLOW_ORIGIN
];
8255 cors1
= cors2
= cors3
= "";
8258 if (!mg_fopen(conn
, path
, "rb", filep
)) {
8259 /* File exists (precondition for calling this function),
8260 * but can not be opened by the server. */
8261 send_http_error(conn
,
8263 "Error: Cannot read file\nfopen(%s): %s",
8267 conn
->must_close
= 1;
8268 gmt_time_string(date
, sizeof(date
), &curtime
);
8269 fclose_on_exec(filep
, conn
);
8270 mg_printf(conn
, "HTTP/1.1 200 OK\r\n");
8271 send_no_cache_header(conn
);
8275 "Content-Type: text/html\r\n"
8276 "Connection: %s\r\n\r\n",
8281 suggest_connection_header(conn
));
8282 send_ssi_file(conn
, path
, filep
, 0);
8288 #if !defined(NO_FILES)
8290 send_options(struct mg_connection
*conn
)
8293 time_t curtime
= time(NULL
);
8299 conn
->status_code
= 200;
8300 conn
->must_close
= 1;
8301 gmt_time_string(date
, sizeof(date
), &curtime
);
8304 "HTTP/1.1 200 OK\r\n"
8306 /* TODO: "Cache-Control" (?) */
8307 "Connection: %s\r\n"
8308 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
8309 "PROPFIND, MKCOL\r\n"
8312 suggest_connection_header(conn
));
8316 /* Writes PROPFIND properties for a collection element */
8318 print_props(struct mg_connection
*conn
, const char *uri
, struct file
*filep
)
8322 if (conn
== NULL
|| uri
== NULL
|| filep
== NULL
) {
8326 gmt_time_string(mtime
, sizeof(mtime
), &filep
->last_modified
);
8327 conn
->num_bytes_sent
+=
8330 "<d:href>%s</d:href>"
8333 "<d:resourcetype>%s</d:resourcetype>"
8334 "<d:getcontentlength>%" INT64_FMT
"</d:getcontentlength>"
8335 "<d:getlastmodified>%s</d:getlastmodified>"
8337 "<d:status>HTTP/1.1 200 OK</d:status>"
8341 filep
->is_directory
? "<d:collection/>" : "",
8348 print_dav_dir_entry(struct de
*de
, void *data
)
8350 char href
[PATH_MAX
];
8351 char href_encoded
[PATH_MAX
];
8354 struct mg_connection
*conn
= (struct mg_connection
*)data
;
8363 conn
->request_info
.local_uri
,
8367 mg_url_encode(href
, href_encoded
, PATH_MAX
- 1);
8368 print_props(conn
, href_encoded
, &de
->file
);
8374 handle_propfind(struct mg_connection
*conn
,
8378 const char *depth
= mg_get_header(conn
, "Depth");
8380 time_t curtime
= time(NULL
);
8382 gmt_time_string(date
, sizeof(date
), &curtime
);
8384 if (!conn
|| !path
|| !filep
|| !conn
->ctx
) {
8388 conn
->must_close
= 1;
8389 conn
->status_code
= 207;
8391 "HTTP/1.1 207 Multi-Status\r\n"
8394 send_static_cache_header(conn
);
8396 "Connection: %s\r\n"
8397 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
8398 suggest_connection_header(conn
));
8400 conn
->num_bytes_sent
+=
8402 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
8403 "<d:multistatus xmlns:d='DAV:'>\n");
8405 /* Print properties for the requested resource itself */
8406 print_props(conn
, conn
->request_info
.local_uri
, filep
);
8408 /* If it is a directory, print directory entries too if Depth is not 0 */
8409 if (filep
&& filep
->is_directory
8410 && !mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
], "yes")
8411 && (depth
== NULL
|| strcmp(depth
, "0") != 0)) {
8412 scan_directory(conn
, path
, conn
, &print_dav_dir_entry
);
8415 conn
->num_bytes_sent
+= mg_printf(conn
, "%s\n", "</d:multistatus>");
8420 mg_lock_connection(struct mg_connection
*conn
)
8423 (void)pthread_mutex_lock(&conn
->mutex
);
8428 mg_unlock_connection(struct mg_connection
*conn
)
8431 (void)pthread_mutex_unlock(&conn
->mutex
);
8436 mg_lock_context(struct mg_context
*ctx
)
8439 (void)pthread_mutex_lock(&ctx
->nonce_mutex
);
8444 mg_unlock_context(struct mg_context
*ctx
)
8447 (void)pthread_mutex_unlock(&ctx
->nonce_mutex
);
8451 #if defined(USE_TIMERS)
8452 #include "timer.inl"
8453 #endif /* USE_TIMERS */
8456 #include "mod_lua.inl"
8457 #endif /* USE_LUA */
8460 #include "mod_duktape.inl"
8461 #endif /* USE_DUKTAPE */
8463 #if defined(USE_WEBSOCKET)
8465 /* START OF SHA-1 code
8466 * Copyright(c) By Steve Reid <steve@edmweb.com> */
8467 #define SHA1HANDSOFF
8469 /* According to current tests (May 2015), the <solarisfixes.h> is not required.
8471 * #if defined(__sun)
8472 * #include "solarisfixes.h"
8480 static const int n
= 1;
8481 return ((char *)&n
)[0] == 0;
8485 union char64long16
{
8486 unsigned char c
[64];
8490 #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
8494 blk0(union char64long16
*block
, int i
)
8496 /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
8497 if (!is_big_endian()) {
8498 block
->l
[i
] = (rol(block
->l
[i
], 24) & 0xFF00FF00)
8499 | (rol(block
->l
[i
], 8) & 0x00FF00FF);
8505 (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
8506 ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
8508 #define R0(v, w, x, y, z, i) \
8509 z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
8511 #define R1(v, w, x, y, z, i) \
8512 z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
8514 #define R2(v, w, x, y, z, i) \
8515 z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
8517 #define R3(v, w, x, y, z, i) \
8518 z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
8520 #define R4(v, w, x, y, z, i) \
8521 z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
8528 unsigned char buffer
[64];
8533 SHA1Transform(uint32_t state
[5], const unsigned char buffer
[64])
8535 uint32_t a
, b
, c
, d
, e
;
8536 union char64long16 block
[1];
8538 memcpy(block
, buffer
, 64);
8544 R0(a
, b
, c
, d
, e
, 0);
8545 R0(e
, a
, b
, c
, d
, 1);
8546 R0(d
, e
, a
, b
, c
, 2);
8547 R0(c
, d
, e
, a
, b
, 3);
8548 R0(b
, c
, d
, e
, a
, 4);
8549 R0(a
, b
, c
, d
, e
, 5);
8550 R0(e
, a
, b
, c
, d
, 6);
8551 R0(d
, e
, a
, b
, c
, 7);
8552 R0(c
, d
, e
, a
, b
, 8);
8553 R0(b
, c
, d
, e
, a
, 9);
8554 R0(a
, b
, c
, d
, e
, 10);
8555 R0(e
, a
, b
, c
, d
, 11);
8556 R0(d
, e
, a
, b
, c
, 12);
8557 R0(c
, d
, e
, a
, b
, 13);
8558 R0(b
, c
, d
, e
, a
, 14);
8559 R0(a
, b
, c
, d
, e
, 15);
8560 R1(e
, a
, b
, c
, d
, 16);
8561 R1(d
, e
, a
, b
, c
, 17);
8562 R1(c
, d
, e
, a
, b
, 18);
8563 R1(b
, c
, d
, e
, a
, 19);
8564 R2(a
, b
, c
, d
, e
, 20);
8565 R2(e
, a
, b
, c
, d
, 21);
8566 R2(d
, e
, a
, b
, c
, 22);
8567 R2(c
, d
, e
, a
, b
, 23);
8568 R2(b
, c
, d
, e
, a
, 24);
8569 R2(a
, b
, c
, d
, e
, 25);
8570 R2(e
, a
, b
, c
, d
, 26);
8571 R2(d
, e
, a
, b
, c
, 27);
8572 R2(c
, d
, e
, a
, b
, 28);
8573 R2(b
, c
, d
, e
, a
, 29);
8574 R2(a
, b
, c
, d
, e
, 30);
8575 R2(e
, a
, b
, c
, d
, 31);
8576 R2(d
, e
, a
, b
, c
, 32);
8577 R2(c
, d
, e
, a
, b
, 33);
8578 R2(b
, c
, d
, e
, a
, 34);
8579 R2(a
, b
, c
, d
, e
, 35);
8580 R2(e
, a
, b
, c
, d
, 36);
8581 R2(d
, e
, a
, b
, c
, 37);
8582 R2(c
, d
, e
, a
, b
, 38);
8583 R2(b
, c
, d
, e
, a
, 39);
8584 R3(a
, b
, c
, d
, e
, 40);
8585 R3(e
, a
, b
, c
, d
, 41);
8586 R3(d
, e
, a
, b
, c
, 42);
8587 R3(c
, d
, e
, a
, b
, 43);
8588 R3(b
, c
, d
, e
, a
, 44);
8589 R3(a
, b
, c
, d
, e
, 45);
8590 R3(e
, a
, b
, c
, d
, 46);
8591 R3(d
, e
, a
, b
, c
, 47);
8592 R3(c
, d
, e
, a
, b
, 48);
8593 R3(b
, c
, d
, e
, a
, 49);
8594 R3(a
, b
, c
, d
, e
, 50);
8595 R3(e
, a
, b
, c
, d
, 51);
8596 R3(d
, e
, a
, b
, c
, 52);
8597 R3(c
, d
, e
, a
, b
, 53);
8598 R3(b
, c
, d
, e
, a
, 54);
8599 R3(a
, b
, c
, d
, e
, 55);
8600 R3(e
, a
, b
, c
, d
, 56);
8601 R3(d
, e
, a
, b
, c
, 57);
8602 R3(c
, d
, e
, a
, b
, 58);
8603 R3(b
, c
, d
, e
, a
, 59);
8604 R4(a
, b
, c
, d
, e
, 60);
8605 R4(e
, a
, b
, c
, d
, 61);
8606 R4(d
, e
, a
, b
, c
, 62);
8607 R4(c
, d
, e
, a
, b
, 63);
8608 R4(b
, c
, d
, e
, a
, 64);
8609 R4(a
, b
, c
, d
, e
, 65);
8610 R4(e
, a
, b
, c
, d
, 66);
8611 R4(d
, e
, a
, b
, c
, 67);
8612 R4(c
, d
, e
, a
, b
, 68);
8613 R4(b
, c
, d
, e
, a
, 69);
8614 R4(a
, b
, c
, d
, e
, 70);
8615 R4(e
, a
, b
, c
, d
, 71);
8616 R4(d
, e
, a
, b
, c
, 72);
8617 R4(c
, d
, e
, a
, b
, 73);
8618 R4(b
, c
, d
, e
, a
, 74);
8619 R4(a
, b
, c
, d
, e
, 75);
8620 R4(e
, a
, b
, c
, d
, 76);
8621 R4(d
, e
, a
, b
, c
, 77);
8622 R4(c
, d
, e
, a
, b
, 78);
8623 R4(b
, c
, d
, e
, a
, 79);
8629 a
= b
= c
= d
= e
= 0;
8630 memset(block
, '\0', sizeof(block
));
8635 SHA1Init(SHA1_CTX
*context
)
8637 context
->state
[0] = 0x67452301;
8638 context
->state
[1] = 0xEFCDAB89;
8639 context
->state
[2] = 0x98BADCFE;
8640 context
->state
[3] = 0x10325476;
8641 context
->state
[4] = 0xC3D2E1F0;
8642 context
->count
[0] = context
->count
[1] = 0;
8647 SHA1Update(SHA1_CTX
*context
, const unsigned char *data
, uint32_t len
)
8651 j
= context
->count
[0];
8652 if ((context
->count
[0] += len
<< 3) < j
) {
8653 context
->count
[1]++;
8655 context
->count
[1] += (len
>> 29);
8657 if ((j
+ len
) > 63) {
8658 memcpy(&context
->buffer
[j
], data
, (i
= 64 - j
));
8659 SHA1Transform(context
->state
, context
->buffer
);
8660 for (; i
+ 63 < len
; i
+= 64) {
8661 SHA1Transform(context
->state
, &data
[i
]);
8666 memcpy(&context
->buffer
[j
], &data
[i
], len
- i
);
8671 SHA1Final(unsigned char digest
[20], SHA1_CTX
*context
)
8674 unsigned char finalcount
[8], c
;
8676 for (i
= 0; i
< 8; i
++) {
8677 finalcount
[i
] = (unsigned char)((context
->count
[(i
>= 4 ? 0 : 1)]
8678 >> ((3 - (i
& 3)) * 8)) & 255);
8681 SHA1Update(context
, &c
, 1);
8682 while ((context
->count
[0] & 504) != 448) {
8684 SHA1Update(context
, &c
, 1);
8686 SHA1Update(context
, finalcount
, 8);
8687 for (i
= 0; i
< 20; i
++) {
8688 digest
[i
] = (unsigned char)((context
->state
[i
>> 2]
8689 >> ((3 - (i
& 3)) * 8)) & 255);
8691 memset(context
, '\0', sizeof(*context
));
8692 memset(&finalcount
, '\0', sizeof(finalcount
));
8694 /* END OF SHA1 CODE */
8698 send_websocket_handshake(struct mg_connection
*conn
, const char *websock_key
)
8700 static const char *magic
= "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
8701 const char *protocol
= NULL
;
8702 char buf
[100], sha
[20], b64_sha
[sizeof(sha
) * 2];
8706 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
8707 mg_snprintf(conn
, &truncated
, buf
, sizeof(buf
), "%s%s", websock_key
, magic
);
8709 conn
->must_close
= 1;
8714 SHA1Update(&sha_ctx
, (unsigned char *)buf
, (uint32_t)strlen(buf
));
8715 SHA1Final((unsigned char *)sha
, &sha_ctx
);
8716 base64_encode((unsigned char *)sha
, sizeof(sha
), b64_sha
);
8718 "HTTP/1.1 101 Switching Protocols\r\n"
8719 "Upgrade: websocket\r\n"
8720 "Connection: Upgrade\r\n"
8721 "Sec-WebSocket-Accept: %s\r\n",
8723 protocol
= mg_get_header(conn
, "Sec-WebSocket-Protocol");
8725 /* The protocol is a comma seperated list of names. */
8726 /* The server must only return one value from this list. */
8727 /* First check if it is a list or just a single value. */
8728 const char *sep
= strchr(protocol
, ',');
8730 /* Just a single protocol -> accept it. */
8731 mg_printf(conn
, "Sec-WebSocket-Protocol: %s\r\n\r\n", protocol
);
8733 /* Multiple protocols -> accept the first one. */
8734 /* This is just a quick fix if the client offers multiple
8735 * protocols. In order to get the behavior intended by
8736 * RFC 6455 (https://tools.ietf.org/rfc/rfc6455.txt), it is
8737 * required to have a list of websocket subprotocols accepted
8738 * by the server. Then the server must either select a subprotocol
8739 * supported by client and server, or the server has to abort the
8740 * handshake by not returning a Sec-Websocket-Protocol header if
8741 * no subprotocol is acceptable.
8744 "Sec-WebSocket-Protocol: %.*s\r\n\r\n",
8745 (int)(sep
- protocol
),
8748 /* TODO: Real subprotocol negotiation instead of just taking the first
8749 * websocket subprotocol suggested by the client. */
8751 mg_printf(conn
, "%s", "\r\n");
8759 read_websocket(struct mg_connection
*conn
,
8760 mg_websocket_data_handler ws_data_handler
,
8761 void *callback_data
)
8763 /* Pointer to the beginning of the portion of the incoming websocket
8765 * The original websocket upgrade request is never removed, so the queue
8766 * begins after it. */
8767 unsigned char *buf
= (unsigned char *)conn
->buf
+ conn
->request_len
;
8768 int n
, error
, exit_by_callback
;
8770 /* body_len is the length of the entire queue in bytes
8771 * len is the length of the current message
8772 * data_len is the length of the current message's data payload
8773 * header_len is the length of the current message's header */
8774 size_t i
, len
, mask_len
= 0, data_len
= 0, header_len
, body_len
;
8776 /* "The masking key is a 32-bit value chosen at random by the client."
8777 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
8779 unsigned char mask
[4];
8781 /* data points to the place where the message is stored when passed to
8783 * websocket_data callback. This is either mem on the stack, or a
8784 * dynamically allocated buffer if it is too large. */
8787 unsigned char mop
; /* mask flag and opcode */
8788 double timeout
= -1.0;
8790 if (conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) {
8791 timeout
= atoi(conn
->ctx
->config
[WEBSOCKET_TIMEOUT
]) / 1000.0;
8793 if ((timeout
<= 0.0) && (conn
->ctx
->config
[REQUEST_TIMEOUT
])) {
8794 timeout
= atoi(conn
->ctx
->config
[REQUEST_TIMEOUT
]) / 1000.0;
8797 mg_set_thread_name("wsock");
8799 /* Loop continuously, reading messages from the socket, invoking the
8800 * callback, and waiting repeatedly until an error occurs. */
8801 while (!conn
->ctx
->stop_flag
) {
8803 assert(conn
->data_len
>= conn
->request_len
);
8804 if ((body_len
= (size_t)(conn
->data_len
- conn
->request_len
)) >= 2) {
8806 mask_len
= buf
[1] & 128 ? 4 : 0;
8807 if (len
< 126 && body_len
>= mask_len
) {
8809 header_len
= 2 + mask_len
;
8810 } else if (len
== 126 && body_len
>= 4 + mask_len
) {
8811 header_len
= 4 + mask_len
;
8812 data_len
= ((((size_t)buf
[2]) << 8) + buf
[3]);
8813 } else if (body_len
>= 10 + mask_len
) {
8814 header_len
= 10 + mask_len
;
8815 data_len
= (((uint64_t)ntohl(*(uint32_t *)(void *)&buf
[2]))
8816 << 32) + ntohl(*(uint32_t *)(void *)&buf
[6]);
8820 if (header_len
> 0 && body_len
>= header_len
) {
8821 /* Allocate space to hold websocket payload */
8823 if (data_len
> sizeof(mem
)) {
8824 data
= (char *)mg_malloc(data_len
);
8826 /* Allocation failed, exit the loop and then close the
8828 mg_cry(conn
, "websocket out of memory; closing connection");
8833 /* Copy the mask before we shift the queue and destroy it */
8835 memcpy(mask
, buf
+ header_len
- mask_len
, sizeof(mask
));
8837 memset(mask
, 0, sizeof(mask
));
8840 /* Read frame payload from the first message in the queue into
8841 * data and advance the queue by moving the memory in place. */
8842 assert(body_len
>= header_len
);
8843 if (data_len
+ header_len
> body_len
) {
8844 mop
= buf
[0]; /* current mask and opcode */
8846 len
= body_len
- header_len
;
8847 memcpy(data
, buf
+ header_len
, len
);
8849 while (len
< data_len
) {
8851 NULL
, conn
, data
+ len
, (int)(data_len
- len
), timeout
);
8859 mg_cry(conn
, "Websocket pull failed; closing connection");
8862 conn
->data_len
= conn
->request_len
;
8864 mop
= buf
[0]; /* current mask and opcode, overwritten by
8866 /* Length of the message being read at the front of the
8868 len
= data_len
+ header_len
;
8870 /* Copy the data payload into the data pointer for the
8872 memcpy(data
, buf
+ header_len
, data_len
);
8874 /* Move the queue forward len bytes */
8875 memmove(buf
, buf
+ len
, body_len
- len
);
8877 /* Mark the queue as advanced */
8878 conn
->data_len
-= (int)len
;
8881 /* Apply mask if necessary */
8883 for (i
= 0; i
< data_len
; ++i
) {
8884 data
[i
] ^= mask
[i
& 3];
8888 /* Exit the loop if callback signals to exit (server side),
8889 * or "connection close" opcode received (client side). */
8890 exit_by_callback
= 0;
8891 if ((ws_data_handler
!= NULL
)
8892 && !ws_data_handler(conn
, mop
, data
, data_len
, callback_data
)) {
8893 exit_by_callback
= 1;
8900 if (exit_by_callback
8901 || ((mop
& 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE
)) {
8902 /* Opcode == 8, connection close */
8906 /* Not breaking the loop, process next websocket frame. */
8908 /* Read from the socket into the next available location in the
8912 conn
->buf
+ conn
->data_len
,
8913 conn
->buf_size
- conn
->data_len
,
8915 /* Error, no bytes read */
8918 conn
->data_len
+= n
;
8922 mg_set_thread_name("worker");
8927 mg_websocket_write_exec(struct mg_connection
*conn
,
8931 uint32_t masking_key
)
8933 unsigned char header
[14];
8934 size_t headerLen
= 1;
8938 header
[0] = 0x80 + (opcode
& 0xF);
8940 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
8941 if (dataLen
< 126) {
8942 /* inline 7-bit length field */
8943 header
[1] = (unsigned char)dataLen
;
8945 } else if (dataLen
<= 0xFFFF) {
8946 /* 16-bit length field */
8948 *(uint16_t *)(void *)(header
+ 2) = htons((uint16_t)dataLen
);
8951 /* 64-bit length field */
8953 *(uint32_t *)(void *)(header
+ 2) = htonl((uint64_t)dataLen
>> 32);
8954 *(uint32_t *)(void *)(header
+ 6) = htonl(dataLen
& 0xFFFFFFFF);
8961 *(uint32_t *)(void *)(header
+ headerLen
) = masking_key
;
8966 /* Note that POSIX/Winsock's send() is threadsafe
8967 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
8968 * but mongoose's mg_printf/mg_write is not (because of the loop in
8969 * push(), although that is only a problem if the packet is large or
8970 * outgoing buffer is full). */
8971 (void)mg_lock_connection(conn
);
8972 retval
= mg_write(conn
, header
, headerLen
);
8974 retval
= mg_write(conn
, data
, dataLen
);
8976 mg_unlock_connection(conn
);
8982 mg_websocket_write(struct mg_connection
*conn
,
8987 return mg_websocket_write_exec(conn
, opcode
, data
, dataLen
, 0);
8992 mask_data(const char *in
, size_t in_len
, uint32_t masking_key
, char *out
)
8997 if ((in_len
> 3) && ((ptrdiff_t)in
% 4) == 0) {
8998 /* Convert in 32 bit words, if data is 4 byte aligned */
8999 while (i
< (in_len
- 3)) {
9000 *(uint32_t *)(void *)(out
+ i
) =
9001 *(uint32_t *)(void *)(in
+ i
) ^ masking_key
;
9006 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
9007 while (i
< in_len
) {
9008 *(uint8_t *)(void *)(out
+ i
) =
9009 *(uint8_t *)(void *)(in
+ i
)
9010 ^ *(((uint8_t *)&masking_key
) + (i
% 4));
9018 mg_websocket_client_write(struct mg_connection
*conn
,
9024 char *masked_data
= (char *)mg_malloc(((dataLen
+ 7) / 4) * 4);
9025 uint32_t masking_key
= (uint32_t)get_random();
9027 if (masked_data
== NULL
) {
9028 /* Return -1 in an error case */
9030 "Cannot allocate buffer for masked websocket response: "
9035 mask_data(data
, dataLen
, masking_key
, masked_data
);
9037 retval
= mg_websocket_write_exec(
9038 conn
, opcode
, masked_data
, dataLen
, masking_key
);
9039 mg_free(masked_data
);
9046 handle_websocket_request(struct mg_connection
*conn
,
9048 int is_callback_resource
,
9049 mg_websocket_connect_handler ws_connect_handler
,
9050 mg_websocket_ready_handler ws_ready_handler
,
9051 mg_websocket_data_handler ws_data_handler
,
9052 mg_websocket_close_handler ws_close_handler
,
9055 const char *websock_key
= mg_get_header(conn
, "Sec-WebSocket-Key");
9056 const char *version
= mg_get_header(conn
, "Sec-WebSocket-Version");
9057 int lua_websock
= 0;
9059 #if !defined(USE_LUA)
9063 /* Step 1: Check websocket protocol version. */
9064 /* Step 1.1: Check Sec-WebSocket-Key. */
9066 /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
9067 * requires a Sec-WebSocket-Key header.
9069 /* It could be the hixie draft version
9070 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
9072 const char *key1
= mg_get_header(conn
, "Sec-WebSocket-Key1");
9073 const char *key2
= mg_get_header(conn
, "Sec-WebSocket-Key2");
9076 if ((key1
!= NULL
) && (key2
!= NULL
)) {
9077 /* This version uses 8 byte body data in a GET request */
9078 conn
->content_len
= 8;
9079 if (8 == mg_read(conn
, key3
, 8)) {
9080 /* This is the hixie version */
9081 send_http_error(conn
,
9084 "Protocol upgrade to RFC 6455 required");
9088 /* This is an unknown version */
9089 send_http_error(conn
, 400, "%s", "Malformed websocket request");
9093 /* Step 1.2: Check websocket protocol version. */
9094 /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
9095 if (version
== NULL
|| strcmp(version
, "13") != 0) {
9096 /* Reject wrong versions */
9097 send_http_error(conn
, 426, "%s", "Protocol upgrade required");
9101 /* Step 1.3: Could check for "Host", but we do not really nead this
9102 * value for anything, so just ignore it. */
9104 /* Step 2: If a callback is responsible, call it. */
9105 if (is_callback_resource
) {
9106 if (ws_connect_handler
!= NULL
9107 && ws_connect_handler(conn
, cbData
) != 0) {
9108 /* C callback has returned non-zero, do not proceed with
9111 /* Note that C callbacks are no longer called when Lua is
9112 * responsible, so C can no longer filter callbacks for Lua. */
9116 #if defined(USE_LUA)
9117 /* Step 3: No callback. Check if Lua is responsible. */
9119 /* Step 3.1: Check if Lua is responsible. */
9120 if (conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]) {
9122 match_prefix(conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
],
9124 conn
->ctx
->config
[LUA_WEBSOCKET_EXTENSIONS
]),
9129 /* Step 3.2: Lua is responsible: call it. */
9130 conn
->lua_websocket_state
= lua_websocket_new(path
, conn
);
9131 if (!conn
->lua_websocket_state
) {
9132 /* Lua rejected the new client */
9139 /* Step 4: Check if there is a responsible websocket handler. */
9140 if (!is_callback_resource
&& !lua_websock
) {
9141 /* There is no callback, an Lua is not responsible either. */
9142 /* Reply with a 404 Not Found or with nothing at all?
9143 * TODO (mid): check the websocket standards, how to reply to
9144 * requests to invalid websocket addresses. */
9145 send_http_error(conn
, 404, "%s", "Not found");
9149 /* Step 5: The websocket connection has been accepted */
9150 if (!send_websocket_handshake(conn
, websock_key
)) {
9151 send_http_error(conn
, 500, "%s", "Websocket handshake failed");
9155 /* Step 6: Call the ready handler */
9156 if (is_callback_resource
) {
9157 if (ws_ready_handler
!= NULL
) {
9158 ws_ready_handler(conn
, cbData
);
9160 #if defined(USE_LUA)
9161 } else if (lua_websock
) {
9162 if (!lua_websocket_ready(conn
, conn
->lua_websocket_state
)) {
9163 /* the ready handler returned false */
9169 /* Step 7: Enter the read loop */
9170 if (is_callback_resource
) {
9171 read_websocket(conn
, ws_data_handler
, cbData
);
9172 #if defined(USE_LUA)
9173 } else if (lua_websock
) {
9174 read_websocket(conn
, lua_websocket_data
, conn
->lua_websocket_state
);
9178 /* Step 8: Call the close handler */
9179 if (ws_close_handler
) {
9180 ws_close_handler(conn
, cbData
);
9186 is_websocket_protocol(const struct mg_connection
*conn
)
9188 const char *upgrade
, *connection
;
9190 /* A websocket protocoll has the following HTTP headers:
9192 * Connection: Upgrade
9193 * Upgrade: Websocket
9196 upgrade
= mg_get_header(conn
, "Upgrade");
9197 if (upgrade
== NULL
) {
9198 return 0; /* fail early, don't waste time checking other header
9202 if (!mg_strcasestr(upgrade
, "websocket")) {
9206 connection
= mg_get_header(conn
, "Connection");
9207 if (connection
== NULL
) {
9210 if (!mg_strcasestr(connection
, "upgrade")) {
9214 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
9215 * "Sec-WebSocket-Version" are also required.
9216 * Don't check them here, since even an unsupported websocket protocol
9217 * request still IS a websocket request (in contrast to a standard HTTP
9218 * request). It will fail later in handle_websocket_request.
9223 #endif /* !USE_WEBSOCKET */
9229 return n
>= 0 && n
<= 255;
9234 parse_net(const char *spec
, uint32_t *net
, uint32_t *mask
)
9236 int n
, a
, b
, c
, d
, slash
= 32, len
= 0;
9238 if ((sscanf(spec
, "%d.%d.%d.%d/%d%n", &a
, &b
, &c
, &d
, &slash
, &n
) == 5
9239 || sscanf(spec
, "%d.%d.%d.%d%n", &a
, &b
, &c
, &d
, &n
) == 4) && isbyte(a
)
9240 && isbyte(b
) && isbyte(c
) && isbyte(d
) && slash
>= 0
9243 *net
= ((uint32_t)a
<< 24) | ((uint32_t)b
<< 16) | ((uint32_t)c
<< 8)
9245 *mask
= slash
? 0xffffffffU
<< (32 - slash
) : 0;
9253 set_throttle(const char *spec
, uint32_t remote_ip
, const char *uri
)
9256 struct vec vec
, val
;
9261 while ((spec
= next_option(spec
, &vec
, &val
)) != NULL
) {
9263 if (sscanf(val
.ptr
, "%lf%c", &v
, &mult
) < 1 || v
< 0
9264 || (lowercase(&mult
) != 'k' && lowercase(&mult
) != 'm'
9268 v
*= lowercase(&mult
) == 'k' ? 1024 : lowercase(&mult
) == 'm' ? 1048576
9270 if (vec
.len
== 1 && vec
.ptr
[0] == '*') {
9272 } else if (parse_net(vec
.ptr
, &net
, &mask
) > 0) {
9273 if ((remote_ip
& mask
) == net
) {
9276 } else if (match_prefix(vec
.ptr
, vec
.len
, uri
) > 0) {
9286 get_remote_ip(const struct mg_connection
*conn
)
9291 return ntohl(*(const uint32_t *)&conn
->client
.rsa
.sin
.sin_addr
);
9295 /* The mg_upload function is superseeded by mg_handle_form_request. */
9296 #include "handle_form.inl"
9299 #if defined(MG_LEGACY_INTERFACE)
9300 /* Implement the deprecated mg_upload function by calling the new
9301 * mg_handle_form_request function. While mg_upload could only handle
9302 * HTML forms sent as POST request in multipart/form-data format
9303 * containing only file input elements, mg_handle_form_request can
9304 * handle all form input elements and all standard request methods. */
9305 struct mg_upload_user_data
{
9306 struct mg_connection
*conn
;
9307 const char *destination_dir
;
9308 int num_uploaded_files
;
9312 /* Helper function for deprecated mg_upload. */
9314 mg_upload_field_found(const char *key
,
9315 const char *filename
,
9321 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9325 mg_cry(fud
->conn
, "%s: No filename set", __func__
);
9326 return FORM_FIELD_STORAGE_ABORT
;
9328 mg_snprintf(fud
->conn
,
9333 fud
->destination_dir
,
9336 mg_cry(fud
->conn
, "%s: File path too long", __func__
);
9337 return FORM_FIELD_STORAGE_ABORT
;
9339 return FORM_FIELD_STORAGE_STORE
;
9343 /* Helper function for deprecated mg_upload. */
9345 mg_upload_field_get(const char *key
,
9350 /* Function should never be called */
9360 /* Helper function for deprecated mg_upload. */
9362 mg_upload_field_stored(const char *path
, long long file_size
, void *user_data
)
9364 struct mg_upload_user_data
*fud
= (struct mg_upload_user_data
*)user_data
;
9367 fud
->num_uploaded_files
++;
9368 fud
->conn
->ctx
->callbacks
.upload(fud
->conn
, path
);
9374 /* Deprecated function mg_upload - use mg_handle_form_request instead. */
9376 mg_upload(struct mg_connection
*conn
, const char *destination_dir
)
9378 struct mg_upload_user_data fud
= {conn
, destination_dir
, 0};
9379 struct mg_form_data_handler fdh
= {mg_upload_field_found
,
9380 mg_upload_field_get
,
9381 mg_upload_field_stored
,
9385 fdh
.user_data
= (void *)&fud
;
9386 ret
= mg_handle_form_request(conn
, &fdh
);
9389 mg_cry(conn
, "%s: Error while parsing the request", __func__
);
9392 return fud
.num_uploaded_files
;
9398 get_first_ssl_listener_index(const struct mg_context
*ctx
)
9403 for (i
= 0; idx
== -1 && i
< ctx
->num_listening_sockets
; i
++) {
9404 idx
= ctx
->listening_sockets
[i
].is_ssl
? ((int)(i
)) : -1;
9412 redirect_to_https_port(struct mg_connection
*conn
, int ssl_index
)
9415 const char *host_header
;
9418 host_header
= mg_get_header(conn
, "Host");
9419 hostlen
= sizeof(host
);
9420 if (host_header
!= NULL
) {
9423 mg_strlcpy(host
, host_header
, hostlen
);
9424 host
[hostlen
- 1] = '\0';
9425 pos
= strchr(host
, ':');
9430 /* Cannot get host from the Host: header.
9431 * Fallback to our IP address. */
9433 sockaddr_to_string(host
, hostlen
, &conn
->client
.lsa
);
9437 /* Send host, port, uri and (if it exists) ?query_string */
9440 "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
9443 conn
->ctx
->listening_sockets
[ssl_index
].lsa
.sin
.sin_port
),
9444 conn
->request_info
.local_uri
,
9445 (conn
->request_info
.query_string
== NULL
) ? "" : "?",
9446 (conn
->request_info
.query_string
== NULL
)
9448 : conn
->request_info
.query_string
);
9454 mg_set_handler_type(struct mg_context
*ctx
,
9457 int is_delete_request
,
9458 mg_request_handler handler
,
9459 mg_websocket_connect_handler connect_handler
,
9460 mg_websocket_ready_handler ready_handler
,
9461 mg_websocket_data_handler data_handler
,
9462 mg_websocket_close_handler close_handler
,
9463 mg_authorization_handler auth_handler
,
9466 struct mg_handler_info
*tmp_rh
, **lastref
;
9467 size_t urilen
= strlen(uri
);
9469 if (handler_type
== WEBSOCKET_HANDLER
) {
9470 /* assert(handler == NULL); */
9471 /* assert(is_delete_request || connect_handler!=NULL ||
9472 * ready_handler!=NULL || data_handler!=NULL ||
9473 * close_handler!=NULL);
9475 /* assert(auth_handler == NULL); */
9476 if (handler
!= NULL
) {
9479 if (!is_delete_request
&& connect_handler
== NULL
9480 && ready_handler
== NULL
9481 && data_handler
== NULL
9482 && close_handler
== NULL
) {
9485 if (auth_handler
!= NULL
) {
9488 } else if (handler_type
== REQUEST_HANDLER
) {
9489 /* assert(connect_handler==NULL && ready_handler==NULL &&
9490 * data_handler==NULL && close_handler==NULL); */
9491 /* assert(is_delete_request || (handler!=NULL));
9493 /* assert(auth_handler == NULL); */
9494 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9495 || data_handler
!= NULL
9496 || close_handler
!= NULL
) {
9499 if (!is_delete_request
&& (handler
== NULL
)) {
9502 if (auth_handler
!= NULL
) {
9505 } else { /* AUTH_HANDLER */
9506 /* assert(handler == NULL); */
9507 /* assert(connect_handler==NULL && ready_handler==NULL &&
9508 * data_handler==NULL && close_handler==NULL); */
9509 /* assert(auth_handler != NULL); */
9510 if (handler
!= NULL
) {
9513 if (connect_handler
!= NULL
|| ready_handler
!= NULL
9514 || data_handler
!= NULL
9515 || close_handler
!= NULL
) {
9518 if (!is_delete_request
&& (auth_handler
== NULL
)) {
9527 mg_lock_context(ctx
);
9529 /* first try to find an existing handler */
9530 lastref
= &(ctx
->handlers
);
9531 for (tmp_rh
= ctx
->handlers
; tmp_rh
!= NULL
; tmp_rh
= tmp_rh
->next
) {
9532 if (tmp_rh
->handler_type
== handler_type
) {
9533 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9534 if (!is_delete_request
) {
9535 /* update existing handler */
9536 if (handler_type
== REQUEST_HANDLER
) {
9537 tmp_rh
->handler
= handler
;
9538 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9539 tmp_rh
->connect_handler
= connect_handler
;
9540 tmp_rh
->ready_handler
= ready_handler
;
9541 tmp_rh
->data_handler
= data_handler
;
9542 tmp_rh
->close_handler
= close_handler
;
9543 } else { /* AUTH_HANDLER */
9544 tmp_rh
->auth_handler
= auth_handler
;
9546 tmp_rh
->cbdata
= cbdata
;
9548 /* remove existing handler */
9549 *lastref
= tmp_rh
->next
;
9550 mg_free(tmp_rh
->uri
);
9553 mg_unlock_context(ctx
);
9557 lastref
= &(tmp_rh
->next
);
9560 if (is_delete_request
) {
9561 /* no handler to set, this was a remove request to a non-existing
9563 mg_unlock_context(ctx
);
9568 (struct mg_handler_info
*)mg_calloc(sizeof(struct mg_handler_info
), 1);
9569 if (tmp_rh
== NULL
) {
9570 mg_unlock_context(ctx
);
9571 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9574 tmp_rh
->uri
= mg_strdup(uri
);
9576 mg_unlock_context(ctx
);
9578 mg_cry(fc(ctx
), "%s", "Cannot create new request handler struct, OOM");
9581 tmp_rh
->uri_len
= urilen
;
9582 if (handler_type
== REQUEST_HANDLER
) {
9583 tmp_rh
->handler
= handler
;
9584 } else if (handler_type
== WEBSOCKET_HANDLER
) {
9585 tmp_rh
->connect_handler
= connect_handler
;
9586 tmp_rh
->ready_handler
= ready_handler
;
9587 tmp_rh
->data_handler
= data_handler
;
9588 tmp_rh
->close_handler
= close_handler
;
9589 } else { /* AUTH_HANDLER */
9590 tmp_rh
->auth_handler
= auth_handler
;
9592 tmp_rh
->cbdata
= cbdata
;
9593 tmp_rh
->handler_type
= handler_type
;
9594 tmp_rh
->next
= NULL
;
9597 mg_unlock_context(ctx
);
9602 mg_set_request_handler(struct mg_context
*ctx
,
9604 mg_request_handler handler
,
9607 mg_set_handler_type(ctx
,
9622 mg_set_websocket_handler(struct mg_context
*ctx
,
9624 mg_websocket_connect_handler connect_handler
,
9625 mg_websocket_ready_handler ready_handler
,
9626 mg_websocket_data_handler data_handler
,
9627 mg_websocket_close_handler close_handler
,
9630 int is_delete_request
= (connect_handler
== NULL
) && (ready_handler
== NULL
)
9631 && (data_handler
== NULL
)
9632 && (close_handler
== NULL
);
9633 mg_set_handler_type(ctx
,
9648 mg_set_auth_handler(struct mg_context
*ctx
,
9650 mg_request_handler handler
,
9653 mg_set_handler_type(ctx
,
9668 get_request_handler(struct mg_connection
*conn
,
9670 mg_request_handler
*handler
,
9671 mg_websocket_connect_handler
*connect_handler
,
9672 mg_websocket_ready_handler
*ready_handler
,
9673 mg_websocket_data_handler
*data_handler
,
9674 mg_websocket_close_handler
*close_handler
,
9675 mg_authorization_handler
*auth_handler
,
9678 const struct mg_request_info
*request_info
= mg_get_request_info(conn
);
9680 const char *uri
= request_info
->local_uri
;
9681 size_t urilen
= strlen(uri
);
9682 struct mg_handler_info
*tmp_rh
;
9684 if (!conn
|| !conn
->ctx
) {
9688 mg_lock_context(conn
->ctx
);
9690 /* first try for an exact match */
9691 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9692 tmp_rh
= tmp_rh
->next
) {
9693 if (tmp_rh
->handler_type
== handler_type
) {
9694 if (urilen
== tmp_rh
->uri_len
&& !strcmp(tmp_rh
->uri
, uri
)) {
9695 if (handler_type
== WEBSOCKET_HANDLER
) {
9696 *connect_handler
= tmp_rh
->connect_handler
;
9697 *ready_handler
= tmp_rh
->ready_handler
;
9698 *data_handler
= tmp_rh
->data_handler
;
9699 *close_handler
= tmp_rh
->close_handler
;
9700 } else if (handler_type
== REQUEST_HANDLER
) {
9701 *handler
= tmp_rh
->handler
;
9702 } else { /* AUTH_HANDLER */
9703 *auth_handler
= tmp_rh
->auth_handler
;
9705 *cbdata
= tmp_rh
->cbdata
;
9706 mg_unlock_context(conn
->ctx
);
9712 /* next try for a partial match, we will accept uri/something */
9713 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9714 tmp_rh
= tmp_rh
->next
) {
9715 if (tmp_rh
->handler_type
== handler_type
) {
9716 if (tmp_rh
->uri_len
< urilen
&& uri
[tmp_rh
->uri_len
] == '/'
9717 && memcmp(tmp_rh
->uri
, uri
, tmp_rh
->uri_len
) == 0) {
9718 if (handler_type
== WEBSOCKET_HANDLER
) {
9719 *connect_handler
= tmp_rh
->connect_handler
;
9720 *ready_handler
= tmp_rh
->ready_handler
;
9721 *data_handler
= tmp_rh
->data_handler
;
9722 *close_handler
= tmp_rh
->close_handler
;
9723 } else if (handler_type
== REQUEST_HANDLER
) {
9724 *handler
= tmp_rh
->handler
;
9725 } else { /* AUTH_HANDLER */
9726 *auth_handler
= tmp_rh
->auth_handler
;
9728 *cbdata
= tmp_rh
->cbdata
;
9729 mg_unlock_context(conn
->ctx
);
9735 /* finally try for pattern match */
9736 for (tmp_rh
= conn
->ctx
->handlers
; tmp_rh
!= NULL
;
9737 tmp_rh
= tmp_rh
->next
) {
9738 if (tmp_rh
->handler_type
== handler_type
) {
9739 if (match_prefix(tmp_rh
->uri
, tmp_rh
->uri_len
, uri
) > 0) {
9740 if (handler_type
== WEBSOCKET_HANDLER
) {
9741 *connect_handler
= tmp_rh
->connect_handler
;
9742 *ready_handler
= tmp_rh
->ready_handler
;
9743 *data_handler
= tmp_rh
->data_handler
;
9744 *close_handler
= tmp_rh
->close_handler
;
9745 } else if (handler_type
== REQUEST_HANDLER
) {
9746 *handler
= tmp_rh
->handler
;
9747 } else { /* AUTH_HANDLER */
9748 *auth_handler
= tmp_rh
->auth_handler
;
9750 *cbdata
= tmp_rh
->cbdata
;
9751 mg_unlock_context(conn
->ctx
);
9757 mg_unlock_context(conn
->ctx
);
9759 return 0; /* none found */
9763 #if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
9765 deprecated_websocket_connect_wrapper(const struct mg_connection
*conn
,
9768 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9769 if (pcallbacks
->websocket_connect
) {
9770 return pcallbacks
->websocket_connect(conn
);
9772 /* No handler set - assume "OK" */
9778 deprecated_websocket_ready_wrapper(struct mg_connection
*conn
, void *cbdata
)
9780 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9781 if (pcallbacks
->websocket_ready
) {
9782 pcallbacks
->websocket_ready(conn
);
9788 deprecated_websocket_data_wrapper(struct mg_connection
*conn
,
9794 struct mg_callbacks
*pcallbacks
= (struct mg_callbacks
*)cbdata
;
9795 if (pcallbacks
->websocket_data
) {
9796 return pcallbacks
->websocket_data(conn
, bits
, data
, len
);
9798 /* No handler set - assume "OK" */
9804 /* This is the heart of the Civetweb's logic.
9805 * This function is called when the request is read, parsed and validated,
9806 * and Civetweb must decide what action to take: serve a file, or
9807 * a directory, or call embedded function, etcetera. */
9809 handle_request(struct mg_connection
*conn
)
9812 struct mg_request_info
*ri
= &conn
->request_info
;
9813 char path
[PATH_MAX
];
9814 int uri_len
, ssl_index
;
9815 int is_found
= 0, is_script_resource
= 0, is_websocket_request
= 0,
9816 is_put_or_delete_request
= 0, is_callback_resource
= 0;
9818 struct file file
= STRUCT_FILE_INITIALIZER
;
9819 mg_request_handler callback_handler
= NULL
;
9820 mg_websocket_connect_handler ws_connect_handler
= NULL
;
9821 mg_websocket_ready_handler ws_ready_handler
= NULL
;
9822 mg_websocket_data_handler ws_data_handler
= NULL
;
9823 mg_websocket_close_handler ws_close_handler
= NULL
;
9824 void *callback_data
= NULL
;
9825 mg_authorization_handler auth_handler
= NULL
;
9826 void *auth_callback_data
= NULL
;
9827 #if !defined(NO_FILES)
9828 time_t curtime
= time(NULL
);
9838 /* 1. get the request url */
9839 /* 1.1. split into url and query string */
9840 if ((conn
->request_info
.query_string
= strchr(ri
->request_uri
, '?'))
9842 *((char *)conn
->request_info
.query_string
++) = '\0';
9844 uri_len
= (int)strlen(ri
->local_uri
);
9846 /* 1.2. decode url (if config says so) */
9847 if (should_decode_url(conn
)) {
9849 ri
->local_uri
, uri_len
, (char *)ri
->local_uri
, uri_len
+ 1, 0);
9852 /* 1.3. clean URIs, so a path like allowed_dir/../forbidden_file is
9853 * not possible (if config says so) */
9854 if (!mg_strcasecmp(conn
->ctx
->config
[CANONICALIZE_URL_PATH
], "yes")) {
9855 remove_double_dots_and_double_slashes((char *)ri
->local_uri
);
9858 /* step 1. completed, the url is known now */
9859 DEBUG_TRACE("URL: %s", ri
->local_uri
);
9861 /* 2. do a https redirect, if required */
9862 if (!conn
->client
.is_ssl
&& conn
->client
.ssl_redir
) {
9863 ssl_index
= get_first_ssl_listener_index(conn
->ctx
);
9864 if (ssl_index
>= 0) {
9865 redirect_to_https_port(conn
, ssl_index
);
9867 /* A http to https forward port has been specified,
9868 * but no https port to forward to. */
9869 send_http_error(conn
,
9872 "Error: SSL forward not configured properly");
9873 mg_cry(conn
, "Can not redirect to SSL, no SSL port available");
9878 /* 3. if this ip has limited speed, set it for this connection */
9879 conn
->throttle
= set_throttle(conn
->ctx
->config
[THROTTLE
],
9880 get_remote_ip(conn
),
9883 /* 4. call a "handle everything" callback, if registered */
9884 if (conn
->ctx
->callbacks
.begin_request
!= NULL
) {
9885 /* Note that since V1.7 the "begin_request" function is called
9886 * before an authorization check. If an authorization check is
9887 * required, use a request_handler instead. */
9888 i
= conn
->ctx
->callbacks
.begin_request(conn
);
9890 /* callback already processed the request. Store the
9891 return value as a status code for the access log. */
9892 conn
->status_code
= i
;
9893 discard_unread_request_data(conn
);
9895 } else if (i
== 0) {
9896 /* civetweb should process the request */
9898 /* unspecified - may change with the next version */
9903 /* request not yet handled by a handler or redirect, so the request
9904 * is processed here */
9906 /* 5. interpret the url to find out how the request must be handled
9908 /* 5.1. first test, if the request targets the regular http(s)://
9909 * protocol namespace or the websocket ws(s):// protocol namespace.
9911 is_websocket_request
= is_websocket_protocol(conn
);
9913 /* 5.2. check if the request will be handled by a callback */
9914 if (get_request_handler(conn
,
9915 is_websocket_request
? WEBSOCKET_HANDLER
9918 &ws_connect_handler
,
9924 /* 5.2.1. A callback will handle this request. All requests
9926 * by a callback have to be considered as requests to a script
9928 is_callback_resource
= 1;
9929 is_script_resource
= 1;
9930 is_put_or_delete_request
= is_put_or_delete_method(conn
);
9932 no_callback_resource
:
9933 /* 5.2.2. No callback is responsible for this request. The URI
9934 * addresses a file based resource (static content or Lua/cgi
9935 * scripts in the file system). */
9936 is_callback_resource
= 0;
9942 &is_script_resource
,
9943 &is_websocket_request
,
9944 &is_put_or_delete_request
);
9947 /* 6. authorization check */
9948 /* 6.1. a custom authorization handler is installed */
9949 if (get_request_handler(conn
,
9957 &auth_callback_data
)) {
9958 if (!auth_handler(conn
, auth_callback_data
)) {
9961 } else if (is_put_or_delete_request
&& !is_script_resource
9962 && !is_callback_resource
) {
9963 /* 6.2. this request is a PUT/DELETE to a real file */
9964 /* 6.2.1. thus, the server must have real files */
9965 #if defined(NO_FILES)
9968 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
9970 /* This server does not have any real files, thus the
9971 * PUT/DELETE methods are not valid. */
9972 send_http_error(conn
,
9974 "%s method not allowed",
9975 conn
->request_info
.request_method
);
9979 #if !defined(NO_FILES)
9980 /* 6.2.2. Check if put authorization for static files is
9983 if (!is_authorized_for_put(conn
)) {
9984 send_authorization_request(conn
);
9990 /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
9991 * or it is a PUT or DELETE request to a resource that does not
9992 * correspond to a file. Check authorization. */
9993 if (!check_authorization(conn
, path
)) {
9994 send_authorization_request(conn
);
9999 /* request is authorized or does not need authorization */
10001 /* 7. check if there are request handlers for this uri */
10002 if (is_callback_resource
) {
10003 if (!is_websocket_request
) {
10004 i
= callback_handler(conn
, callback_data
);
10006 /* Do nothing, callback has served the request. Store
10008 * return value as status code for the log and discard
10010 * data from the client not used by the callback. */
10011 conn
->status_code
= i
;
10012 discard_unread_request_data(conn
);
10014 /* TODO (high): what if the handler did NOT handle the
10016 /* The last version did handle this as a file request,
10018 * since a file request is not always a script resource,
10019 * the authorization check might be different */
10020 interpret_uri(conn
,
10025 &is_script_resource
,
10026 &is_websocket_request
,
10027 &is_put_or_delete_request
);
10028 callback_handler
= NULL
;
10030 /* TODO (very low): goto is deprecated but for the
10032 * a goto is simpler than some curious loop. */
10033 /* The situation "callback does not handle the request"
10034 * needs to be reconsidered anyway. */
10035 goto no_callback_resource
;
10038 #if defined(USE_WEBSOCKET)
10039 handle_websocket_request(conn
,
10041 is_callback_resource
,
10042 ws_connect_handler
,
10052 /* 8. handle websocket requests */
10053 #if defined(USE_WEBSOCKET)
10054 if (is_websocket_request
) {
10055 if (is_script_resource
) {
10056 /* Websocket Lua script */
10057 handle_websocket_request(conn
,
10059 0 /* Lua Script */,
10064 &conn
->ctx
->callbacks
);
10066 #if defined(MG_LEGACY_INTERFACE)
10067 handle_websocket_request(
10070 !is_script_resource
/* could be deprecated global callback */,
10071 deprecated_websocket_connect_wrapper
,
10072 deprecated_websocket_ready_wrapper
,
10073 deprecated_websocket_data_wrapper
,
10075 &conn
->ctx
->callbacks
);
10077 send_http_error(conn
, 404, "%s", "Not found");
10084 #if defined(NO_FILES)
10085 /* 9a. In case the server uses only callbacks, this uri is
10087 * Then, all request handling ends here. */
10088 send_http_error(conn
, 404, "%s", "Not Found");
10091 /* 9b. This request is either for a static file or resource handled
10092 * by a script file. Thus, a DOCUMENT_ROOT must exist. */
10093 if (conn
->ctx
->config
[DOCUMENT_ROOT
] == NULL
) {
10094 send_http_error(conn
, 404, "%s", "Not Found");
10098 /* 10. File is handled by a script. */
10099 if (is_script_resource
) {
10100 handle_file_based_request(conn
, path
, &file
);
10104 /* 11. Handle put/delete/mkcol requests */
10105 if (is_put_or_delete_request
) {
10106 /* 11.1. PUT method */
10107 if (!strcmp(ri
->request_method
, "PUT")) {
10108 put_file(conn
, path
);
10111 /* 11.2. DELETE method */
10112 if (!strcmp(ri
->request_method
, "DELETE")) {
10113 delete_file(conn
, path
);
10116 /* 11.3. MKCOL method */
10117 if (!strcmp(ri
->request_method
, "MKCOL")) {
10121 /* 11.4. PATCH method
10122 * This method is not supported for static resources,
10123 * only for scripts (Lua, CGI) and callbacks. */
10124 send_http_error(conn
,
10126 "%s method not allowed",
10127 conn
->request_info
.request_method
);
10131 /* 11. File does not exist, or it was configured that it should be
10133 if (!is_found
|| (must_hide_file(conn
, path
))) {
10134 send_http_error(conn
, 404, "%s", "Not found");
10138 /* 12. Directory uris should end with a slash */
10139 if (file
.is_directory
&& ri
->local_uri
[uri_len
- 1] != '/') {
10140 gmt_time_string(date
, sizeof(date
), &curtime
);
10142 "HTTP/1.1 301 Moved Permanently\r\n"
10143 "Location: %s/\r\n"
10145 /* "Cache-Control: private\r\n" (= default) */
10146 "Content-Length: 0\r\n"
10147 "Connection: %s\r\n\r\n",
10150 suggest_connection_header(conn
));
10154 /* 13. Handle other methods than GET/HEAD */
10155 /* 13.1. Handle PROPFIND */
10156 if (!strcmp(ri
->request_method
, "PROPFIND")) {
10157 handle_propfind(conn
, path
, &file
);
10160 /* 13.2. Handle OPTIONS for files */
10161 if (!strcmp(ri
->request_method
, "OPTIONS")) {
10162 /* This standard handler is only used for real files.
10163 * Scripts should support the OPTIONS method themselves, to allow a
10164 * maximum flexibility.
10165 * Lua and CGI scripts may fully support CORS this way (including
10167 send_options(conn
);
10170 /* 13.3. everything but GET and HEAD (e.g. POST) */
10171 if (0 != strcmp(ri
->request_method
, "GET")
10172 && 0 != strcmp(ri
->request_method
, "HEAD")) {
10173 send_http_error(conn
,
10175 "%s method not allowed",
10176 conn
->request_info
.request_method
);
10180 /* 14. directories */
10181 if (file
.is_directory
) {
10182 if (substitute_index_file(conn
, path
, sizeof(path
), &file
)) {
10183 /* 14.1. use a substitute file */
10184 /* TODO (high): substitute index may be a script resource.
10185 * define what should be possible in this case. */
10187 /* 14.2. no substitute file */
10188 if (!mg_strcasecmp(conn
->ctx
->config
[ENABLE_DIRECTORY_LISTING
],
10190 handle_directory_request(conn
, path
);
10192 send_http_error(conn
,
10195 "Error: Directory listing denied");
10201 handle_file_based_request(conn
, path
, &file
);
10202 #endif /* !defined(NO_FILES) */
10205 /* Perform redirect and auth checks before calling begin_request()
10207 * Otherwise, begin_request() would need to perform auth checks and
10216 handle_file_based_request(struct mg_connection
*conn
,
10220 if (!conn
|| !conn
->ctx
) {
10226 } else if (match_prefix(conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
],
10228 conn
->ctx
->config
[LUA_SERVER_PAGE_EXTENSIONS
]),
10230 /* Lua server page: an SSI like page containing mostly plain html
10232 * plus some tags with server generated contents. */
10233 handle_lsp_request(conn
, path
, file
, NULL
);
10234 } else if (match_prefix(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
],
10235 strlen(conn
->ctx
->config
[LUA_SCRIPT_EXTENSIONS
]),
10237 /* Lua in-server module script: a CGI like script used to generate
10240 mg_exec_lua_script(conn
, path
, NULL
);
10242 #if defined(USE_DUKTAPE)
10243 } else if (match_prefix(conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
],
10245 conn
->ctx
->config
[DUKTAPE_SCRIPT_EXTENSIONS
]),
10247 /* Call duktape to generate the page */
10248 mg_exec_duktape_script(conn
, path
);
10250 #if !defined(NO_CGI)
10251 } else if (match_prefix(conn
->ctx
->config
[CGI_EXTENSIONS
],
10252 strlen(conn
->ctx
->config
[CGI_EXTENSIONS
]),
10254 /* CGI scripts may support all HTTP methods */
10255 handle_cgi_request(conn
, path
);
10256 #endif /* !NO_CGI */
10257 } else if (match_prefix(conn
->ctx
->config
[SSI_EXTENSIONS
],
10258 strlen(conn
->ctx
->config
[SSI_EXTENSIONS
]),
10260 handle_ssi_file_request(conn
, path
, file
);
10261 #if !defined(NO_CACHING)
10262 } else if ((!conn
->in_error_handler
) && is_not_modified(conn
, file
)) {
10263 /* Send 304 "Not Modified" - this must not send any body data */
10264 send_http_error(conn
, 304, "%s", "");
10265 #endif /* !NO_CACHING */
10267 handle_static_file_request(conn
, path
, file
, NULL
);
10273 close_all_listening_sockets(struct mg_context
*ctx
)
10280 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
10281 closesocket(ctx
->listening_sockets
[i
].sock
);
10282 ctx
->listening_sockets
[i
].sock
= INVALID_SOCKET
;
10284 mg_free(ctx
->listening_sockets
);
10285 ctx
->listening_sockets
= NULL
;
10286 mg_free(ctx
->listening_ports
);
10287 ctx
->listening_ports
= NULL
;
10291 /* Valid listening port specification is: [ip_address:]port[s]
10292 * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
10293 * Examples for IPv6: [::]:80, [::1]:80,
10294 * [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443s
10295 * see https://tools.ietf.org/html/rfc3513#section-2.2 */
10297 parse_port_string(const struct vec
*vec
, struct socket
*so
)
10299 unsigned int a
, b
, c
, d
, port
;
10301 #if defined(USE_IPV6)
10302 char buf
[100] = {0};
10305 /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
10306 * Also, all-zeroes in the socket address means binding to all addresses
10307 * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
10308 memset(so
, 0, sizeof(*so
));
10309 so
->lsa
.sin
.sin_family
= AF_INET
;
10311 if (sscanf(vec
->ptr
, "%u.%u.%u.%u:%u%n", &a
, &b
, &c
, &d
, &port
, &len
)
10313 /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
10314 so
->lsa
.sin
.sin_addr
.s_addr
=
10315 htonl((a
<< 24) | (b
<< 16) | (c
<< 8) | d
);
10316 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10317 #if defined(USE_IPV6)
10318 } else if (sscanf(vec
->ptr
, "[%49[^]]]:%u%n", buf
, &port
, &len
) == 2
10320 AF_INET6
, buf
, &so
->lsa
.sin6
, sizeof(so
->lsa
.sin6
))) {
10321 /* IPv6 address, examples: see above */
10322 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
10324 so
->lsa
.sin6
.sin6_port
= htons((uint16_t)port
);
10326 } else if (sscanf(vec
->ptr
, "%u%n", &port
, &len
) == 1) {
10327 /* If only port is specified, bind to IPv4, INADDR_ANY */
10328 so
->lsa
.sin
.sin_port
= htons((uint16_t)port
);
10330 /* Parsing failure. Make port invalid. */
10335 /* sscanf and the option splitting code ensure the following condition
10337 if ((len
< 0) && ((unsigned)len
> (unsigned)vec
->len
)) {
10340 ch
= vec
->ptr
[len
]; /* Next character after the port number */
10341 so
->is_ssl
= (ch
== 's');
10342 so
->ssl_redir
= (ch
== 'r');
10344 /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
10345 return is_valid_port(port
)
10346 && (ch
== '\0' || ch
== 's' || ch
== 'r' || ch
== ',');
10351 set_ports_option(struct mg_context
*ctx
)
10355 #if defined(USE_IPV6)
10359 struct socket so
, *ptr
;
10361 in_port_t
*portPtr
;
10365 int portsTotal
= 0;
10372 memset(&so
, 0, sizeof(so
));
10373 memset(&usa
, 0, sizeof(usa
));
10375 list
= ctx
->config
[LISTENING_PORTS
];
10376 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10380 if (!parse_port_string(&vec
, &so
)) {
10382 "%.*s: invalid port spec (entry %i). Expecting list of: %s",
10386 "[IP_ADDRESS:]PORT[s|r]");
10390 if (so
.is_ssl
&& ctx
->ssl_ctx
== NULL
) {
10393 "Cannot add SSL socket (entry %i). Is -ssl_certificate "
10399 if ((so
.sock
= socket(so
.lsa
.sa
.sa_family
, SOCK_STREAM
, 6))
10400 == INVALID_SOCKET
) {
10402 mg_cry(fc(ctx
), "cannot create socket (entry %i)", portsTotal
);
10407 /* Windows SO_REUSEADDR lets many procs binds to a
10408 * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
10409 * if someone already has the socket -- DTL */
10410 /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
10411 * Windows might need a few seconds before
10412 * the same port can be used again in the
10413 * same process, so a short Sleep may be
10414 * required between mg_stop and mg_start.
10416 if (setsockopt(so
.sock
,
10418 SO_EXCLUSIVEADDRUSE
,
10419 (SOCK_OPT_TYPE
)&on
,
10420 sizeof(on
)) != 0) {
10423 "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
10427 if (setsockopt(so
.sock
,
10430 (SOCK_OPT_TYPE
)&on
,
10431 sizeof(on
)) != 0) {
10434 "cannot set socket option SO_REUSEADDR (entry %i)",
10439 #if defined(USE_IPV6)
10440 if (so
.lsa
.sa
.sa_family
== AF_INET6
10441 && setsockopt(so
.sock
,
10445 sizeof(off
)) != 0) {
10448 "cannot set socket option IPV6_V6ONLY (entry %i)",
10453 if (so
.lsa
.sa
.sa_family
== AF_INET
) {
10455 len
= sizeof(so
.lsa
.sin
);
10456 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10458 "cannot bind to %.*s: %d (%s)",
10463 closesocket(so
.sock
);
10464 so
.sock
= INVALID_SOCKET
;
10468 #if defined(USE_IPV6)
10469 else if (so
.lsa
.sa
.sa_family
== AF_INET6
) {
10471 len
= sizeof(so
.lsa
.sin6
);
10472 if (bind(so
.sock
, &so
.lsa
.sa
, len
) != 0) {
10474 "cannot bind to IPv6 %.*s: %d (%s)",
10479 closesocket(so
.sock
);
10480 so
.sock
= INVALID_SOCKET
;
10487 "cannot bind: address family not supported (entry %i)",
10492 if (listen(so
.sock
, SOMAXCONN
) != 0) {
10495 "cannot listen to %.*s: %d (%s)",
10500 closesocket(so
.sock
);
10501 so
.sock
= INVALID_SOCKET
;
10505 if (getsockname(so
.sock
, &(usa
.sa
), &len
) != 0) {
10507 int err
= (int)ERRNO
;
10509 "call to getsockname failed %.*s: %d (%s)",
10514 closesocket(so
.sock
);
10515 so
.sock
= INVALID_SOCKET
;
10519 if ((ptr
= (struct socket
*)
10520 mg_realloc(ctx
->listening_sockets
,
10521 (ctx
->num_listening_sockets
+ 1)
10522 * sizeof(ctx
->listening_sockets
[0]))) == NULL
) {
10524 mg_cry(fc(ctx
), "%s", "Out of memory");
10525 closesocket(so
.sock
);
10526 so
.sock
= INVALID_SOCKET
;
10531 (in_port_t
*)mg_realloc(ctx
->listening_ports
,
10532 (ctx
->num_listening_sockets
+ 1)
10533 * sizeof(ctx
->listening_ports
[0])))
10536 mg_cry(fc(ctx
), "%s", "Out of memory");
10537 closesocket(so
.sock
);
10538 so
.sock
= INVALID_SOCKET
;
10543 set_close_on_exec(so
.sock
, fc(ctx
));
10544 ctx
->listening_sockets
= ptr
;
10545 ctx
->listening_sockets
[ctx
->num_listening_sockets
] = so
;
10546 ctx
->listening_ports
= portPtr
;
10547 ctx
->listening_ports
[ctx
->num_listening_sockets
] =
10548 ntohs(usa
.sin
.sin_port
);
10549 ctx
->num_listening_sockets
++;
10553 if (portsOk
!= portsTotal
) {
10554 close_all_listening_sockets(ctx
);
10562 static const char *
10563 header_val(const struct mg_connection
*conn
, const char *header
)
10565 const char *header_value
;
10567 if ((header_value
= mg_get_header(conn
, header
)) == NULL
) {
10570 return header_value
;
10576 log_access(const struct mg_connection
*conn
)
10578 const struct mg_request_info
*ri
;
10580 char date
[64], src_addr
[IP_ADDR_STR_LEN
];
10583 const char *referer
;
10584 const char *user_agent
;
10588 if (!conn
|| !conn
->ctx
) {
10592 if (conn
->ctx
->config
[ACCESS_LOG_FILE
] != NULL
) {
10593 if (mg_fopen(conn
, conn
->ctx
->config
[ACCESS_LOG_FILE
], "a+", &fi
)
10601 if (fi
.fp
== NULL
&& conn
->ctx
->callbacks
.log_message
== NULL
) {
10605 tm
= localtime(&conn
->conn_birth_time
);
10607 strftime(date
, sizeof(date
), "%d/%b/%Y:%H:%M:%S %z", tm
);
10609 mg_strlcpy(date
, "01/Jan/1970:00:00:00 +0000", sizeof(date
));
10610 date
[sizeof(date
) - 1] = '\0';
10613 ri
= &conn
->request_info
;
10615 sockaddr_to_string(src_addr
, sizeof(src_addr
), &conn
->client
.rsa
);
10616 referer
= header_val(conn
, "Referer");
10617 user_agent
= header_val(conn
, "User-Agent");
10620 NULL
, /* Ignore truncation in access log */
10623 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT
" %s %s",
10625 ri
->remote_user
== NULL
? "-" : ri
->remote_user
,
10627 ri
->request_method
? ri
->request_method
: "-",
10628 ri
->request_uri
? ri
->request_uri
: "-",
10629 ri
->query_string
? "?" : "",
10630 ri
->query_string
? ri
->query_string
: "",
10633 conn
->num_bytes_sent
,
10637 if (conn
->ctx
->callbacks
.log_access
) {
10638 conn
->ctx
->callbacks
.log_access(conn
, buf
);
10643 fprintf(fi
.fp
, "%s\n", buf
);
10645 funlockfile(fi
.fp
);
10651 /* Verify given socket address against the ACL.
10652 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
10655 check_acl(struct mg_context
*ctx
, uint32_t remote_ip
)
10658 uint32_t net
, mask
;
10662 const char *list
= ctx
->config
[ACCESS_CONTROL_LIST
];
10664 /* If any ACL is set, deny by default */
10665 allowed
= list
== NULL
? '+' : '-';
10667 while ((list
= next_option(list
, &vec
, NULL
)) != NULL
) {
10669 if ((flag
!= '+' && flag
!= '-')
10670 || parse_net(&vec
.ptr
[1], &net
, &mask
) == 0) {
10672 "%s: subnet must be [+|-]x.x.x.x[/x]",
10677 if (net
== (remote_ip
& mask
)) {
10682 return allowed
== '+';
10688 #if !defined(_WIN32)
10690 set_uid_option(struct mg_context
*ctx
)
10694 const char *uid
= ctx
->config
[RUN_AS_USER
];
10700 if ((pw
= getpwnam(uid
)) == NULL
) {
10701 mg_cry(fc(ctx
), "%s: unknown user [%s]", __func__
, uid
);
10702 } else if (setgid(pw
->pw_gid
) == -1) {
10704 "%s: setgid(%s): %s",
10708 } else if (setgroups(0, NULL
)) {
10710 "%s: setgroups(): %s",
10713 } else if (setuid(pw
->pw_uid
) == -1) {
10715 "%s: setuid(%s): %s",
10728 #endif /* !_WIN32 */
10732 tls_dtor(void *key
)
10734 struct mg_workerTLS
*tls
= (struct mg_workerTLS
*)key
;
10735 /* key == pthread_getspecific(sTlsKey); */
10738 if (tls
->is_master
== 2) {
10739 tls
->is_master
= -3; /* Mark memory as dead */
10743 pthread_setspecific(sTlsKey
, NULL
);
10747 #if !defined(NO_SSL)
10749 /* Must be set if sizeof(pthread_t) > sizeof(unsigned long) */
10750 static unsigned long
10751 ssl_id_callback(void)
10754 return GetCurrentThreadId();
10758 #pragma clang diagnostic push
10759 #pragma clang diagnostic ignored "-Wunreachable-code"
10760 /* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
10761 * or not, so one of the two conditions will be unreachable by construction.
10762 * Unfortunately the C standard does not define a way to check this at
10763 * compile time, since the #if preprocessor conditions can not use the sizeof
10764 * operator as an argument. */
10767 if (sizeof(pthread_t
) > sizeof(unsigned long)) {
10768 /* This is the problematic case for CRYPTO_set_id_callback:
10769 * The OS pthread_t can not be cast to unsigned long. */
10770 struct mg_workerTLS
*tls
=
10771 (struct mg_workerTLS
*)pthread_getspecific(sTlsKey
);
10773 /* SSL called from an unknown thread: Create some thread index.
10775 tls
= (struct mg_workerTLS
*)mg_malloc(sizeof(struct mg_workerTLS
));
10776 tls
->is_master
= -2; /* -2 means "3rd party thread" */
10777 tls
->thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
10778 pthread_setspecific(sTlsKey
, tls
);
10780 return tls
->thread_idx
;
10782 /* pthread_t may be any data type, so a simple cast to unsigned long
10783 * can rise a warning/error, depending on the platform.
10784 * Here memcpy is used as an anything-to-anything cast. */
10785 unsigned long ret
= 0;
10786 pthread_t t
= pthread_self();
10787 memcpy(&ret
, &t
, sizeof(pthread_t
));
10792 #pragma clang diagnostic pop
10799 static int ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
);
10800 static const char *ssl_error(void);
10804 refresh_trust(struct mg_connection
*conn
)
10806 static int reload_lock
= 0;
10807 static long int data_check
= 0;
10809 struct stat cert_buf
;
10812 int should_verify_peer
;
10814 if ((pem
= conn
->ctx
->config
[SSL_CERTIFICATE
]) == NULL
10815 && conn
->ctx
->callbacks
.init_ssl
== NULL
) {
10820 if (stat(pem
, &cert_buf
) != -1) {
10821 t
= (long int)cert_buf
.st_mtime
;
10824 if (data_check
!= t
) {
10827 should_verify_peer
=
10828 (conn
->ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
10829 && (mg_strcasecmp(conn
->ctx
->config
[SSL_DO_VERIFY_PEER
], "yes")
10832 if (should_verify_peer
) {
10833 char *ca_path
= conn
->ctx
->config
[SSL_CA_PATH
];
10834 char *ca_file
= conn
->ctx
->config
[SSL_CA_FILE
];
10835 if (SSL_CTX_load_verify_locations(conn
->ctx
->ssl_ctx
,
10838 mg_cry(fc(conn
->ctx
),
10839 "SSL_CTX_load_verify_locations error: %s "
10840 "ssl_verify_peer requires setting "
10841 "either ssl_ca_path or ssl_ca_file. Is any of them "
10849 if (!reload_lock
) {
10851 if (ssl_use_pem_file(conn
->ctx
, pem
) == 0) {
10857 /* lock while cert is reloading */
10858 while (reload_lock
) {
10866 static pthread_mutex_t
*ssl_mutexes
;
10870 sslize(struct mg_connection
*conn
, SSL_CTX
*s
, int (*func
)(SSL
*))
10880 (conn
->ctx
->config
[SSL_SHORT_TRUST
] != NULL
)
10881 && (mg_strcasecmp(conn
->ctx
->config
[SSL_SHORT_TRUST
], "yes") == 0);
10884 int trust_ret
= refresh_trust(conn
);
10890 conn
->ssl
= SSL_new(s
);
10891 if (conn
->ssl
== NULL
) {
10895 ret
= SSL_set_fd(conn
->ssl
, conn
->client
.sock
);
10897 err
= SSL_get_error(conn
->ssl
, ret
);
10898 (void)err
; /* TODO: set some error message */
10899 SSL_free(conn
->ssl
);
10901 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10903 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10904 ERR_remove_state(0);
10908 ret
= func(conn
->ssl
);
10910 err
= SSL_get_error(conn
->ssl
, ret
);
10911 (void)err
; /* TODO: set some error message */
10912 SSL_free(conn
->ssl
);
10914 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
10916 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
10917 ERR_remove_state(0);
10925 /* Return OpenSSL error message (from CRYPTO lib) */
10926 static const char *
10930 err
= ERR_get_error();
10931 return err
== 0 ? "" : ERR_error_string(err
, NULL
);
10936 ssl_locking_callback(int mode
, int mutex_num
, const char *file
, int line
)
10942 /* 1 is CRYPTO_LOCK */
10943 (void)pthread_mutex_lock(&ssl_mutexes
[mutex_num
]);
10945 (void)pthread_mutex_unlock(&ssl_mutexes
[mutex_num
]);
10950 #if !defined(NO_SSL_DL)
10952 load_dll(struct mg_context
*ctx
, const char *dll_name
, struct ssl_func
*sw
)
10959 struct ssl_func
*fp
;
10961 if ((dll_handle
= dlopen(dll_name
, RTLD_LAZY
)) == NULL
) {
10962 mg_cry(fc(ctx
), "%s: cannot load %s", __func__
, dll_name
);
10966 for (fp
= sw
; fp
->name
!= NULL
; fp
++) {
10968 /* GetProcAddress() returns pointer to function */
10969 u
.fp
= (void (*)(void))dlsym(dll_handle
, fp
->name
);
10971 /* dlsym() on UNIX returns void *. ISO C forbids casts of data
10972 * pointers to function pointers. We need to use a union to make a
10974 u
.p
= dlsym(dll_handle
, fp
->name
);
10975 #endif /* _WIN32 */
10976 if (u
.fp
== NULL
) {
10978 "%s: %s: cannot find %s",
10982 dlclose(dll_handle
);
10993 static void *ssllib_dll_handle
; /* Store the ssl library handle. */
10994 static void *cryptolib_dll_handle
; /* Store the crypto library handle. */
10996 #endif /* NO_SSL_DL */
10999 #if defined(SSL_ALREADY_INITIALIZED)
11000 static int cryptolib_users
= 1; /* Reference counter for crypto library. */
11002 static int cryptolib_users
= 0; /* Reference counter for crypto library. */
11007 initialize_ssl(struct mg_context
*ctx
)
11012 #if !defined(NO_SSL_DL)
11013 if (!cryptolib_dll_handle
) {
11014 cryptolib_dll_handle
= load_dll(ctx
, CRYPTO_LIB
, crypto_sw
);
11015 if (!cryptolib_dll_handle
) {
11019 #endif /* NO_SSL_DL */
11021 if (mg_atomic_inc(&cryptolib_users
) > 1) {
11025 /* Initialize locking callbacks, needed for thread safety.
11026 * http://www.openssl.org/support/faq.html#PROG1
11028 i
= CRYPTO_num_locks();
11032 size
= sizeof(pthread_mutex_t
) * ((size_t)(i
));
11033 if ((ssl_mutexes
= (pthread_mutex_t
*)mg_malloc(size
)) == NULL
) {
11035 "%s: cannot allocate mutexes: %s",
11041 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11042 pthread_mutex_init(&ssl_mutexes
[i
], &pthread_mutex_attr
);
11045 CRYPTO_set_locking_callback(&ssl_locking_callback
);
11046 CRYPTO_set_id_callback(&ssl_id_callback
);
11053 ssl_use_pem_file(struct mg_context
*ctx
, const char *pem
)
11055 if (SSL_CTX_use_certificate_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11057 "%s: cannot open certificate file %s: %s",
11064 /* could use SSL_CTX_set_default_passwd_cb_userdata */
11065 if (SSL_CTX_use_PrivateKey_file(ctx
->ssl_ctx
, pem
, 1) == 0) {
11067 "%s: cannot open private key file %s: %s",
11074 if (SSL_CTX_check_private_key(ctx
->ssl_ctx
) == 0) {
11076 "%s: certificate and private key do not match: %s",
11082 if (SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
) == 0) {
11084 "%s: cannot use certificate chain file %s: %s",
11095 ssl_get_protocol(int version_id
)
11097 long ret
= SSL_OP_ALL
;
11098 if (version_id
> 0)
11099 ret
|= SSL_OP_NO_SSLv2
;
11100 if (version_id
> 1)
11101 ret
|= SSL_OP_NO_SSLv3
;
11102 if (version_id
> 2)
11103 ret
|= SSL_OP_NO_TLSv1
;
11104 if (version_id
> 3)
11105 ret
|= SSL_OP_NO_TLSv1_1
;
11110 /* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
11112 set_ssl_option(struct mg_context
*ctx
)
11116 int should_verify_peer
;
11117 const char *ca_path
;
11118 const char *ca_file
;
11119 int use_default_verify_paths
;
11121 time_t now_rt
= time(NULL
);
11122 struct timespec now_mt
;
11123 md5_byte_t ssl_context_id
[16];
11124 md5_state_t md5state
;
11127 /* If PEM file is not specified and the init_ssl callback
11128 * is not specified, skip SSL initialization. */
11132 if ((pem
= ctx
->config
[SSL_CERTIFICATE
]) == NULL
11133 && ctx
->callbacks
.init_ssl
== NULL
) {
11137 if (!initialize_ssl(ctx
)) {
11141 #if !defined(NO_SSL_DL)
11142 if (!ssllib_dll_handle
) {
11143 ssllib_dll_handle
= load_dll(ctx
, SSL_LIB
, ssl_sw
);
11144 if (!ssllib_dll_handle
) {
11148 #endif /* NO_SSL_DL */
11150 /* Initialize SSL library */
11151 SSL_library_init();
11152 SSL_load_error_strings();
11154 if ((ctx
->ssl_ctx
= SSL_CTX_new(SSLv23_server_method())) == NULL
) {
11155 mg_cry(fc(ctx
), "SSL_CTX_new (server) error: %s", ssl_error());
11159 SSL_CTX_clear_options(ctx
->ssl_ctx
,
11160 SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
| SSL_OP_NO_TLSv1
11161 | SSL_OP_NO_TLSv1_1
);
11162 protocol_ver
= atoi(ctx
->config
[SSL_PROTOCOL_VERSION
]);
11163 SSL_CTX_set_options(ctx
->ssl_ctx
, ssl_get_protocol(protocol_ver
));
11164 SSL_CTX_set_options(ctx
->ssl_ctx
, SSL_OP_SINGLE_DH_USE
);
11165 SSL_CTX_set_ecdh_auto(ctx
->ssl_ctx
, 1);
11167 /* If a callback has been specified, call it. */
11169 (ctx
->callbacks
.init_ssl
== NULL
)
11171 : (ctx
->callbacks
.init_ssl(ctx
->ssl_ctx
, ctx
->user_data
));
11173 /* If callback returns 0, civetweb sets up the SSL certificate.
11174 * If it returns 1, civetweb assumes the calback already did this.
11175 * If it returns -1, initializing ssl fails. */
11176 if (callback_ret
< 0) {
11177 mg_cry(fc(ctx
), "SSL callback returned error: %i", callback_ret
);
11180 if (callback_ret
> 0) {
11182 (void)SSL_CTX_use_certificate_chain_file(ctx
->ssl_ctx
, pem
);
11187 /* Use some UID as session context ID. */
11188 md5_init(&md5state
);
11189 md5_append(&md5state
, (const md5_byte_t
*)&now_rt
, sizeof(now_rt
));
11190 clock_gettime(CLOCK_MONOTONIC
, &now_mt
);
11191 md5_append(&md5state
, (const md5_byte_t
*)&now_mt
, sizeof(now_mt
));
11192 md5_append(&md5state
,
11193 (const md5_byte_t
*)ctx
->config
[LISTENING_PORTS
],
11194 strlen(ctx
->config
[LISTENING_PORTS
]));
11195 md5_append(&md5state
, (const md5_byte_t
*)ctx
, sizeof(*ctx
));
11196 md5_finish(&md5state
, ssl_context_id
);
11198 SSL_CTX_set_session_id_context(ctx
->ssl_ctx
,
11199 (const unsigned char *)&ssl_context_id
,
11200 sizeof(ssl_context_id
));
11203 if (!ssl_use_pem_file(ctx
, pem
)) {
11208 should_verify_peer
=
11209 (ctx
->config
[SSL_DO_VERIFY_PEER
] != NULL
)
11210 && (mg_strcasecmp(ctx
->config
[SSL_DO_VERIFY_PEER
], "yes") == 0);
11212 use_default_verify_paths
=
11213 (ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
] != NULL
)
11214 && (mg_strcasecmp(ctx
->config
[SSL_DEFAULT_VERIFY_PATHS
], "yes") == 0);
11216 if (should_verify_peer
) {
11217 ca_path
= ctx
->config
[SSL_CA_PATH
];
11218 ca_file
= ctx
->config
[SSL_CA_FILE
];
11219 if (SSL_CTX_load_verify_locations(ctx
->ssl_ctx
, ca_file
, ca_path
)
11222 "SSL_CTX_load_verify_locations error: %s "
11223 "ssl_verify_peer requires setting "
11224 "either ssl_ca_path or ssl_ca_file. Is any of them "
11231 SSL_CTX_set_verify(ctx
->ssl_ctx
,
11232 SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
,
11235 if (use_default_verify_paths
11236 && SSL_CTX_set_default_verify_paths(ctx
->ssl_ctx
) != 1) {
11238 "SSL_CTX_set_default_verify_paths error: %s",
11243 if (ctx
->config
[SSL_VERIFY_DEPTH
]) {
11244 verify_depth
= atoi(ctx
->config
[SSL_VERIFY_DEPTH
]);
11245 SSL_CTX_set_verify_depth(ctx
->ssl_ctx
, verify_depth
);
11249 if (ctx
->config
[SSL_CIPHER_LIST
] != NULL
) {
11250 if (SSL_CTX_set_cipher_list(ctx
->ssl_ctx
, ctx
->config
[SSL_CIPHER_LIST
])
11252 mg_cry(fc(ctx
), "SSL_CTX_set_cipher_list error: %s", ssl_error());
11261 uninitialize_ssl(struct mg_context
*ctx
)
11266 if (mg_atomic_dec(&cryptolib_users
) == 0) {
11268 /* Shutdown according to
11269 * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
11270 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
11272 CRYPTO_set_locking_callback(NULL
);
11273 CRYPTO_set_id_callback(NULL
);
11275 CONF_modules_unload(1);
11276 ERR_free_strings();
11278 CRYPTO_cleanup_all_ex_data();
11279 ERR_remove_state(0);
11281 for (i
= 0; i
< CRYPTO_num_locks(); i
++) {
11282 pthread_mutex_destroy(&ssl_mutexes
[i
]);
11284 mg_free(ssl_mutexes
);
11285 ssl_mutexes
= NULL
;
11288 #endif /* !NO_SSL */
11292 set_gpass_option(struct mg_context
*ctx
)
11295 struct file file
= STRUCT_FILE_INITIALIZER
;
11296 const char *path
= ctx
->config
[GLOBAL_PASSWORDS_FILE
];
11297 if (path
!= NULL
&& !mg_stat(fc(ctx
), path
, &file
)) {
11298 mg_cry(fc(ctx
), "Cannot open %s: %s", path
, strerror(ERRNO
));
11308 set_acl_option(struct mg_context
*ctx
)
11310 return check_acl(ctx
, (uint32_t)0x7f000001UL
) != -1;
11315 reset_per_request_attributes(struct mg_connection
*conn
)
11320 conn
->path_info
= NULL
;
11321 conn
->num_bytes_sent
= conn
->consumed_content
= 0;
11322 conn
->status_code
= -1;
11323 conn
->is_chunked
= 0;
11324 conn
->must_close
= conn
->request_len
= conn
->throttle
= 0;
11325 conn
->request_info
.content_length
= -1;
11326 conn
->request_info
.remote_user
= NULL
;
11327 conn
->request_info
.request_method
= NULL
;
11328 conn
->request_info
.request_uri
= NULL
;
11329 conn
->request_info
.local_uri
= NULL
;
11330 conn
->request_info
.uri
= NULL
; /* TODO: cleanup uri,
11331 * local_uri and request_uri */
11332 conn
->request_info
.http_version
= NULL
;
11333 conn
->request_info
.num_headers
= 0;
11334 conn
->data_len
= 0;
11335 conn
->chunk_remainder
= 0;
11336 conn
->internal_error
= 0;
11341 set_sock_timeout(SOCKET sock
, int milliseconds
)
11343 int r0
= 0, r1
, r2
;
11346 /* Windows specific */
11348 DWORD tv
= (DWORD
)milliseconds
;
11351 /* Linux, ... (not Windows) */
11355 /* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
11356 * max. time waiting for the acknowledged of TCP data before the connection
11357 * will be forcefully closed and ETIMEDOUT is returned to the application.
11358 * If this option is not set, the default timeout of 20-30 minutes is used.
11360 /* #define TCP_USER_TIMEOUT (18) */
11362 #if defined(TCP_USER_TIMEOUT)
11363 unsigned int uto
= (unsigned int)milliseconds
;
11364 r0
= setsockopt(sock
, 6, TCP_USER_TIMEOUT
, (const void *)&uto
, sizeof(uto
));
11367 memset(&tv
, 0, sizeof(tv
));
11368 tv
.tv_sec
= milliseconds
/ 1000;
11369 tv
.tv_usec
= (milliseconds
* 1000) % 1000000;
11371 #endif /* _WIN32 */
11374 sock
, SOL_SOCKET
, SO_RCVTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11376 sock
, SOL_SOCKET
, SO_SNDTIMEO
, (SOCK_OPT_TYPE
)&tv
, sizeof(tv
));
11378 return r0
|| r1
|| r2
;
11383 set_tcp_nodelay(SOCKET sock
, int nodelay_on
)
11385 if (setsockopt(sock
,
11388 (SOCK_OPT_TYPE
)&nodelay_on
,
11389 sizeof(nodelay_on
)) != 0) {
11399 close_socket_gracefully(struct mg_connection
*conn
)
11401 #if defined(_WIN32)
11402 char buf
[MG_BUF_LEN
];
11405 struct linger linger
;
11411 /* Set linger option to avoid socket hanging out after close. This
11413 * ephemeral port exhaust problem under high QPS. */
11414 linger
.l_onoff
= 1;
11415 linger
.l_linger
= 1;
11417 if (setsockopt(conn
->client
.sock
,
11421 sizeof(linger
)) != 0) {
11423 "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
11428 /* Send FIN to the client */
11429 shutdown(conn
->client
.sock
, SHUT_WR
);
11430 set_non_blocking_mode(conn
->client
.sock
);
11432 #if defined(_WIN32)
11433 /* Read and discard pending incoming data. If we do not do that and
11435 * the socket, the data in the send buffer may be discarded. This
11436 * behaviour is seen on Windows, when client keeps sending data
11437 * when server decides to close the connection; then when client
11438 * does recv() it gets no data back. */
11441 NULL
, conn
, buf
, sizeof(buf
), 1E-10 /* TODO: allow 0 as timeout */);
11445 /* Now we know that our FIN is ACK-ed, safe to close */
11446 closesocket(conn
->client
.sock
);
11447 conn
->client
.sock
= INVALID_SOCKET
;
11452 close_connection(struct mg_connection
*conn
)
11454 if (!conn
|| !conn
->ctx
) {
11458 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
11459 if (conn
->lua_websocket_state
) {
11460 lua_websocket_close(conn
, conn
->lua_websocket_state
);
11461 conn
->lua_websocket_state
= NULL
;
11465 /* call the connection_close callback if assigned */
11466 if ((conn
->ctx
->callbacks
.connection_close
!= NULL
)
11467 && (conn
->ctx
->context_type
== 1)) {
11468 conn
->ctx
->callbacks
.connection_close(conn
);
11471 mg_lock_connection(conn
);
11473 conn
->must_close
= 1;
11476 if (conn
->ssl
!= NULL
) {
11477 /* Run SSL_shutdown twice to ensure completly close SSL connection
11479 SSL_shutdown(conn
->ssl
);
11480 SSL_free(conn
->ssl
);
11481 /* maybe not? CRYPTO_cleanup_all_ex_data(); */
11483 * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
11484 ERR_remove_state(0);
11488 if (conn
->client
.sock
!= INVALID_SOCKET
) {
11489 close_socket_gracefully(conn
);
11490 conn
->client
.sock
= INVALID_SOCKET
;
11493 mg_unlock_connection(conn
);
11497 mg_close_connection(struct mg_connection
*conn
)
11499 struct mg_context
*client_ctx
= NULL
;
11502 if (conn
== NULL
) {
11506 if (conn
->ctx
->context_type
== 2) {
11507 client_ctx
= conn
->ctx
;
11508 /* client context: loops must end */
11509 conn
->ctx
->stop_flag
= 1;
11513 if (conn
->client_ssl_ctx
!= NULL
) {
11514 SSL_CTX_free((SSL_CTX
*)conn
->client_ssl_ctx
);
11517 close_connection(conn
);
11518 if (client_ctx
!= NULL
) {
11519 /* join worker thread and free context */
11520 for (i
= 0; i
< client_ctx
->cfg_worker_threads
; i
++) {
11521 if (client_ctx
->workerthreadids
[i
] != 0) {
11522 mg_join_thread(client_ctx
->workerthreadids
[i
]);
11525 mg_free(client_ctx
->workerthreadids
);
11526 mg_free(client_ctx
);
11527 (void)pthread_mutex_destroy(&conn
->mutex
);
11533 static struct mg_connection
*
11534 mg_connect_client_impl(const struct mg_client_options
*client_options
,
11539 static struct mg_context fake_ctx
;
11540 struct mg_connection
*conn
= NULL
;
11544 if (!connect_socket(&fake_ctx
,
11545 client_options
->host
,
11546 client_options
->port
,
11553 } else if ((conn
= (struct mg_connection
*)
11554 mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
)) == NULL
) {
11556 NULL
, /* No truncation check for ebuf */
11564 && (conn
->client_ssl_ctx
= SSL_CTX_new(SSLv23_client_method()))
11567 NULL
, /* No truncation check for ebuf */
11570 "SSL_CTX_new error");
11574 #endif /* NO_SSL */
11579 socklen_t len
= (sa
.sa
.sa_family
== AF_INET
)
11580 ? sizeof(conn
->client
.rsa
.sin
)
11581 : sizeof(conn
->client
.rsa
.sin6
);
11582 struct sockaddr
*psa
=
11583 (sa
.sa
.sa_family
== AF_INET
)
11584 ? (struct sockaddr
*)&(conn
->client
.rsa
.sin
)
11585 : (struct sockaddr
*)&(conn
->client
.rsa
.sin6
);
11587 socklen_t len
= sizeof(conn
->client
.rsa
.sin
);
11588 struct sockaddr
*psa
= (struct sockaddr
*)&(conn
->client
.rsa
.sin
);
11591 conn
->buf_size
= MAX_REQUEST_SIZE
;
11592 conn
->buf
= (char *)(conn
+ 1);
11593 conn
->ctx
= &fake_ctx
;
11594 conn
->client
.sock
= sock
;
11595 conn
->client
.lsa
= sa
;
11597 if (getsockname(sock
, psa
, &len
) != 0) {
11599 "%s: getsockname() failed: %s",
11604 conn
->client
.is_ssl
= use_ssl
? 1 : 0;
11605 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
11609 fake_ctx
.ssl_ctx
= conn
->client_ssl_ctx
;
11611 /* TODO: Check ssl_verify_peer and ssl_ca_path here.
11612 * SSL_CTX_set_verify call is needed to switch off server
11613 * certificate checking, which is off by default in OpenSSL and
11615 /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
11616 * SSL_VERIFY_PEER, verify_ssl_server); */
11618 if (client_options
->client_cert
) {
11619 if (!ssl_use_pem_file(&fake_ctx
, client_options
->client_cert
)) {
11621 NULL
, /* No truncation check for ebuf */
11624 "Can not use SSL client certificate");
11625 SSL_CTX_free(conn
->client_ssl_ctx
);
11632 if (client_options
->server_cert
) {
11633 SSL_CTX_load_verify_locations(conn
->client_ssl_ctx
,
11634 client_options
->server_cert
,
11636 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_PEER
, NULL
);
11638 SSL_CTX_set_verify(conn
->client_ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
11641 if (!sslize(conn
, conn
->client_ssl_ctx
, SSL_connect
)) {
11643 NULL
, /* No truncation check for ebuf */
11646 "SSL connection error");
11647 SSL_CTX_free(conn
->client_ssl_ctx
);
11660 CIVETWEB_API
struct mg_connection
*
11661 mg_connect_client_secure(const struct mg_client_options
*client_options
,
11662 char *error_buffer
,
11663 size_t error_buffer_size
)
11665 return mg_connect_client_impl(client_options
,
11668 error_buffer_size
);
11672 struct mg_connection
*
11673 mg_connect_client(const char *host
,
11676 char *error_buffer
,
11677 size_t error_buffer_size
)
11679 struct mg_client_options opts
;
11680 memset(&opts
, 0, sizeof(opts
));
11683 return mg_connect_client_impl(&opts
,
11686 error_buffer_size
);
11690 static const struct {
11693 unsigned default_port
;
11694 } abs_uri_protocols
[] = {{"http://", 7, 80},
11695 {"https://", 8, 443},
11697 {"wss://", 6, 443},
11701 /* Check if the uri is valid.
11702 * return 0 for invalid uri,
11704 * return 2 for relative uri,
11705 * return 3 for absolute uri without port,
11706 * return 4 for absolute uri with port */
11708 get_uri_type(const char *uri
)
11711 char *hostend
, *portbegin
, *portend
;
11712 unsigned long port
;
11714 /* According to the HTTP standard
11715 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
11716 * URI can be an asterisk (*) or should start with slash (relative uri),
11717 * or it should start with the protocol (absolute uri). */
11718 if (uri
[0] == '*' && uri
[1] == '\0') {
11722 if (uri
[0] == '/') {
11727 /* It could be an absolute uri: */
11728 /* This function only checks if the uri is valid, not if it is
11729 * addressing the current server. So civetweb can also be used
11730 * as a proxy server. */
11731 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11732 if (mg_strncasecmp(uri
,
11733 abs_uri_protocols
[i
].proto
,
11734 abs_uri_protocols
[i
].proto_len
) == 0) {
11736 hostend
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, '/');
11740 portbegin
= strchr(uri
+ abs_uri_protocols
[i
].proto_len
, ':');
11745 port
= strtoul(portbegin
+ 1, &portend
, 10);
11746 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11758 /* Return NULL or the relative uri at the current server */
11759 static const char *
11760 get_rel_url_at_current_server(const char *uri
, const struct mg_connection
*conn
)
11762 const char *server_domain
;
11763 size_t server_domain_len
;
11764 size_t request_domain_len
= 0;
11765 unsigned long port
= 0;
11767 const char *hostbegin
= NULL
;
11768 const char *hostend
= NULL
;
11769 const char *portbegin
;
11772 /* DNS is case insensitive, so use case insensitive string compare here
11774 server_domain
= conn
->ctx
->config
[AUTHENTICATION_DOMAIN
];
11775 if (!server_domain
) {
11778 server_domain_len
= strlen(server_domain
);
11779 if (!server_domain_len
) {
11783 for (i
= 0; abs_uri_protocols
[i
].proto
!= NULL
; i
++) {
11784 if (mg_strncasecmp(uri
,
11785 abs_uri_protocols
[i
].proto
,
11786 abs_uri_protocols
[i
].proto_len
) == 0) {
11788 hostbegin
= uri
+ abs_uri_protocols
[i
].proto_len
;
11789 hostend
= strchr(hostbegin
, '/');
11793 portbegin
= strchr(hostbegin
, ':');
11794 if ((!portbegin
) || (portbegin
> hostend
)) {
11795 port
= abs_uri_protocols
[i
].default_port
;
11796 request_domain_len
= (size_t)(hostend
- hostbegin
);
11798 port
= strtoul(portbegin
+ 1, &portend
, 10);
11799 if ((portend
!= hostend
) || !port
|| !is_valid_port(port
)) {
11802 request_domain_len
= (size_t)(portbegin
- hostbegin
);
11804 /* protocol found, port set */
11810 /* port remains 0 if the protocol is not found */
11814 #if defined(USE_IPV6)
11815 if (conn
->client
.lsa
.sa
.sa_family
== AF_INET6
) {
11816 if (ntohs(conn
->client
.lsa
.sin6
.sin6_port
) != port
) {
11817 /* Request is directed to a different port */
11823 if (ntohs(conn
->client
.lsa
.sin
.sin_port
) != port
) {
11824 /* Request is directed to a different port */
11829 if ((request_domain_len
!= server_domain_len
)
11830 || (0 != memcmp(server_domain
, hostbegin
, server_domain_len
))) {
11831 /* Request is directed to another server */
11840 getreq(struct mg_connection
*conn
, char *ebuf
, size_t ebuf_len
, int *err
)
11843 int check_method
= should_validate_http_method(conn
);
11845 if (ebuf_len
> 0) {
11850 reset_per_request_attributes(conn
);
11854 NULL
, /* No truncation check for ebuf */
11862 /* Set the time the request was received. This value should be used for
11864 clock_gettime(CLOCK_MONOTONIC
, &(conn
->req_time
));
11866 conn
->request_len
=
11867 read_request(NULL
, conn
, conn
->buf
, conn
->buf_size
, &conn
->data_len
);
11868 /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
11870 if (conn
->request_len
>= 0 && conn
->data_len
< conn
->request_len
) {
11872 NULL
, /* No truncation check for ebuf */
11876 "Invalid request size");
11881 if (conn
->request_len
== 0 && conn
->data_len
== conn
->buf_size
) {
11883 NULL
, /* No truncation check for ebuf */
11887 "Request Too Large");
11890 } else if (conn
->request_len
<= 0) {
11891 if (conn
->data_len
> 0) {
11893 NULL
, /* No truncation check for ebuf */
11897 "Client sent malformed request");
11900 /* Server did not send anything -> just close the connection */
11901 conn
->must_close
= 1;
11903 NULL
, /* No truncation check for ebuf */
11907 "Client did not send a request");
11911 } else if (parse_http_message(
11912 check_method
, conn
->buf
, conn
->buf_size
, &conn
->request_info
)
11915 NULL
, /* No truncation check for ebuf */
11923 /* Message is a valid request or response */
11924 if ((cl
= get_header(&conn
->request_info
, "Content-Length")) != NULL
) {
11925 /* Request/response has content length set */
11926 char *endptr
= NULL
;
11927 conn
->content_len
= strtoll(cl
, &endptr
, 10);
11928 if (endptr
== cl
) {
11930 NULL
, /* No truncation check for ebuf */
11938 /* Publish the content length back to the request info. */
11939 conn
->request_info
.content_length
= conn
->content_len
;
11940 } else if ((cl
= get_header(&conn
->request_info
, "Transfer-Encoding"))
11942 && !mg_strcasecmp(cl
, "chunked")) {
11943 conn
->is_chunked
= 1;
11944 } else if (!mg_strcasecmp(conn
->request_info
.request_method
, "POST")
11945 || !mg_strcasecmp(conn
->request_info
.request_method
,
11947 /* POST or PUT request without content length set */
11948 conn
->content_len
= -1;
11949 } else if (!mg_strncasecmp(conn
->request_info
.request_method
,
11952 /* Response without content length set */
11953 conn
->content_len
= -1;
11955 /* Other request */
11956 conn
->content_len
= 0;
11964 mg_get_response(struct mg_connection
*conn
,
11970 /* Implementation of API function for HTTP clients */
11972 struct mg_context
*octx
= conn
->ctx
;
11973 struct mg_context rctx
= *(conn
->ctx
);
11974 char txt
[32]; /* will not overflow */
11976 if (timeout
>= 0) {
11977 mg_snprintf(conn
, NULL
, txt
, sizeof(txt
), "%i", timeout
);
11978 rctx
.config
[REQUEST_TIMEOUT
] = txt
;
11979 set_sock_timeout(conn
->client
.sock
, timeout
);
11981 rctx
.config
[REQUEST_TIMEOUT
] = NULL
;
11985 ret
= getreq(conn
, ebuf
, ebuf_len
, &err
);
11988 /* TODO: 1) uri is deprecated;
11989 * 2) here, ri.uri is the http response code */
11990 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
11992 /* TODO (mid): Define proper return values - maybe return length?
11993 * For the first test use <0 for error and >0 for OK */
11994 return (ret
== 0) ? -1 : +1;
12000 struct mg_connection
*
12001 mg_download(const char *host
,
12009 struct mg_connection
*conn
;
12017 /* open a connection */
12018 conn
= mg_connect_client(host
, port
, use_ssl
, ebuf
, ebuf_len
);
12020 if (conn
!= NULL
) {
12021 i
= mg_vprintf(conn
, fmt
, ap
);
12024 NULL
, /* No truncation check for ebuf */
12028 "Error sending request");
12030 getreq(conn
, ebuf
, ebuf_len
, &reqerr
);
12032 /* TODO: 1) uri is deprecated;
12033 * 2) here, ri.uri is the http response code */
12034 conn
->request_info
.uri
= conn
->request_info
.request_uri
;
12038 /* if an error occured, close the connection */
12039 if (ebuf
[0] != '\0' && conn
!= NULL
) {
12040 mg_close_connection(conn
);
12049 struct websocket_client_thread_data
{
12050 struct mg_connection
*conn
;
12051 mg_websocket_data_handler data_handler
;
12052 mg_websocket_close_handler close_handler
;
12053 void *callback_data
;
12057 #if defined(USE_WEBSOCKET)
12059 static unsigned __stdcall
websocket_client_thread(void *data
)
12062 websocket_client_thread(void *data
)
12065 struct websocket_client_thread_data
*cdata
=
12066 (struct websocket_client_thread_data
*)data
;
12068 mg_set_thread_name("ws-client");
12070 if (cdata
->conn
->ctx
) {
12071 if (cdata
->conn
->ctx
->callbacks
.init_thread
) {
12072 /* 3 indicates a websocket client thread */
12073 /* TODO: check if conn->ctx can be set */
12074 cdata
->conn
->ctx
->callbacks
.init_thread(cdata
->conn
->ctx
, 3);
12078 read_websocket(cdata
->conn
, cdata
->data_handler
, cdata
->callback_data
);
12080 DEBUG_TRACE("%s", "Websocket client thread exited\n");
12082 if (cdata
->close_handler
!= NULL
) {
12083 cdata
->close_handler(cdata
->conn
, cdata
->callback_data
);
12086 mg_free((void *)cdata
);
12097 struct mg_connection
*
12098 mg_connect_websocket_client(const char *host
,
12101 char *error_buffer
,
12102 size_t error_buffer_size
,
12104 const char *origin
,
12105 mg_websocket_data_handler data_func
,
12106 mg_websocket_close_handler close_func
,
12109 struct mg_connection
*conn
= NULL
;
12111 #if defined(USE_WEBSOCKET)
12112 struct mg_context
*newctx
= NULL
;
12113 struct websocket_client_thread_data
*thread_data
;
12114 static const char *magic
= "x3JJHMbDL1EzLkh9GBhXDw==";
12115 static const char *handshake_req
;
12117 if (origin
!= NULL
) {
12118 handshake_req
= "GET %s HTTP/1.1\r\n"
12120 "Upgrade: websocket\r\n"
12121 "Connection: Upgrade\r\n"
12122 "Sec-WebSocket-Key: %s\r\n"
12123 "Sec-WebSocket-Version: 13\r\n"
12127 handshake_req
= "GET %s HTTP/1.1\r\n"
12129 "Upgrade: websocket\r\n"
12130 "Connection: Upgrade\r\n"
12131 "Sec-WebSocket-Key: %s\r\n"
12132 "Sec-WebSocket-Version: 13\r\n"
12136 /* Establish the client connection and request upgrade */
12137 conn
= mg_download(host
,
12148 /* Connection object will be null if something goes wrong */
12149 if (conn
== NULL
|| (strcmp(conn
->request_info
.request_uri
, "101") != 0)) {
12150 if (!*error_buffer
) {
12151 /* if there is a connection, but it did not return 101,
12152 * error_buffer is not yet set */
12154 NULL
, /* No truncation check for ebuf */
12157 "Unexpected server reply");
12159 DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer
);
12160 if (conn
!= NULL
) {
12167 /* For client connections, mg_context is fake. Since we need to set a
12168 * callback function, we need to create a copy and modify it. */
12169 newctx
= (struct mg_context
*)mg_malloc(sizeof(struct mg_context
));
12170 memcpy(newctx
, conn
->ctx
, sizeof(struct mg_context
));
12171 newctx
->user_data
= user_data
;
12172 newctx
->context_type
= 2; /* client context type */
12173 newctx
->cfg_worker_threads
= 1; /* one worker thread will be created */
12174 newctx
->workerthreadids
=
12175 (pthread_t
*)mg_calloc(newctx
->cfg_worker_threads
, sizeof(pthread_t
));
12176 conn
->ctx
= newctx
;
12177 thread_data
= (struct websocket_client_thread_data
*)
12178 mg_calloc(sizeof(struct websocket_client_thread_data
), 1);
12179 thread_data
->conn
= conn
;
12180 thread_data
->data_handler
= data_func
;
12181 thread_data
->close_handler
= close_func
;
12182 thread_data
->callback_data
= NULL
;
12184 /* Start a thread to read the websocket client connection
12185 * This thread will automatically stop when mg_disconnect is
12186 * called on the client connection */
12187 if (mg_start_thread_with_id(websocket_client_thread
,
12188 (void *)thread_data
,
12189 newctx
->workerthreadids
) != 0) {
12190 mg_free((void *)thread_data
);
12191 mg_free((void *)newctx
->workerthreadids
);
12192 mg_free((void *)newctx
);
12193 mg_free((void *)conn
);
12196 "Websocket client connect thread could not be started\r\n");
12199 /* Appease "unused parameter" warnings */
12203 (void)error_buffer
;
12204 (void)error_buffer_size
;
12217 process_new_connection(struct mg_connection
*conn
)
12219 if (conn
&& conn
->ctx
) {
12220 struct mg_request_info
*ri
= &conn
->request_info
;
12221 int keep_alive_enabled
, keep_alive
, discard_len
;
12223 const char *hostend
;
12224 int reqerr
, uri_type
;
12226 keep_alive_enabled
=
12227 !strcmp(conn
->ctx
->config
[ENABLE_KEEP_ALIVE
], "yes");
12229 /* Important: on new connection, reset the receiving buffer. Credit
12230 * goes to crule42. */
12231 conn
->data_len
= 0;
12233 if (!getreq(conn
, ebuf
, sizeof(ebuf
), &reqerr
)) {
12234 /* The request sent by the client could not be understood by
12235 * the server, or it was incomplete or a timeout. Send an
12236 * error message and close the connection. */
12238 /*assert(ebuf[0] != '\0');*/
12239 send_http_error(conn
, reqerr
, "%s", ebuf
);
12241 } else if (strcmp(ri
->http_version
, "1.0")
12242 && strcmp(ri
->http_version
, "1.1")) {
12244 NULL
, /* No truncation check for ebuf */
12247 "Bad HTTP version: [%s]",
12249 send_http_error(conn
, 505, "%s", ebuf
);
12252 if (ebuf
[0] == '\0') {
12253 uri_type
= get_uri_type(conn
->request_info
.request_uri
);
12254 switch (uri_type
) {
12257 conn
->request_info
.local_uri
= NULL
;
12261 conn
->request_info
.local_uri
=
12262 conn
->request_info
.request_uri
;
12266 /* absolute uri (with/without port) */
12267 hostend
= get_rel_url_at_current_server(
12268 conn
->request_info
.request_uri
, conn
);
12270 conn
->request_info
.local_uri
= hostend
;
12272 conn
->request_info
.local_uri
= NULL
;
12277 NULL
, /* No truncation check for ebuf */
12280 "Invalid URI: [%s]",
12282 send_http_error(conn
, 400, "%s", ebuf
);
12286 /* TODO: cleanup uri, local_uri and request_uri */
12287 conn
->request_info
.uri
= conn
->request_info
.local_uri
;
12290 if (ebuf
[0] == '\0') {
12291 if (conn
->request_info
.local_uri
) {
12292 /* handle request to local server */
12293 handle_request(conn
);
12294 if (conn
->ctx
->callbacks
.end_request
!= NULL
) {
12295 conn
->ctx
->callbacks
.end_request(conn
,
12296 conn
->status_code
);
12300 /* TODO: handle non-local request (PROXY) */
12301 conn
->must_close
= 1;
12304 conn
->must_close
= 1;
12307 if (ri
->remote_user
!= NULL
) {
12308 mg_free((void *)ri
->remote_user
);
12309 /* Important! When having connections with and without auth
12310 * would cause double free and then crash */
12311 ri
->remote_user
= NULL
;
12314 /* NOTE(lsm): order is important here. should_keep_alive() call
12316 * using parsed request, which will be invalid after memmove's
12318 * Therefore, memorize should_keep_alive() result now for later
12320 * in loop exit condition. */
12321 keep_alive
= conn
->ctx
->stop_flag
== 0 && keep_alive_enabled
12322 && conn
->content_len
>= 0 && should_keep_alive(conn
);
12324 /* Discard all buffered data for this request */
12325 discard_len
= conn
->content_len
>= 0 && conn
->request_len
> 0
12326 && conn
->request_len
+ conn
->content_len
12327 < (int64_t)conn
->data_len
12328 ? (int)(conn
->request_len
+ conn
->content_len
)
12330 /*assert(discard_len >= 0);*/
12331 if (discard_len
< 0)
12333 conn
->data_len
-= discard_len
;
12334 if (conn
->data_len
> 0) {
12336 conn
->buf
+ discard_len
,
12337 (size_t)conn
->data_len
);
12340 /* assert(conn->data_len >= 0); */
12341 /* assert(conn->data_len <= conn->buf_size); */
12343 if ((conn
->data_len
< 0) || (conn
->data_len
> conn
->buf_size
)) {
12347 } while (keep_alive
);
12352 /* Worker threads take accepted socket from the queue */
12354 consume_socket(struct mg_context
*ctx
, struct socket
*sp
)
12356 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12361 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12362 DEBUG_TRACE("%s", "going idle");
12364 /* If the queue is empty, wait. We're idle at this point. */
12365 while (ctx
->sq_head
== ctx
->sq_tail
&& ctx
->stop_flag
== 0) {
12366 pthread_cond_wait(&ctx
->sq_full
, &ctx
->thread_mutex
);
12369 /* If we're stopping, sq_head may be equal to sq_tail. */
12370 if (ctx
->sq_head
> ctx
->sq_tail
) {
12371 /* Copy socket from the queue and increment tail */
12372 *sp
= ctx
->queue
[ctx
->sq_tail
% QUEUE_SIZE(ctx
)];
12375 DEBUG_TRACE("grabbed socket %d, going busy", sp
? sp
->sock
: -1);
12377 /* Wrap pointers if needed */
12378 while (ctx
->sq_tail
> QUEUE_SIZE(ctx
)) {
12379 ctx
->sq_tail
-= QUEUE_SIZE(ctx
);
12380 ctx
->sq_head
-= QUEUE_SIZE(ctx
);
12384 (void)pthread_cond_signal(&ctx
->sq_empty
);
12385 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12387 return !ctx
->stop_flag
;
12393 worker_thread_run(void *thread_func_param
)
12395 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12396 struct mg_connection
*conn
;
12397 struct mg_workerTLS tls
;
12398 #if defined(MG_LEGACY_INTERFACE)
12402 mg_set_thread_name("worker");
12405 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12406 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12407 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12410 if (ctx
->callbacks
.init_thread
) {
12411 /* call init_thread for a worker thread (type 1) */
12412 ctx
->callbacks
.init_thread(ctx
, 1);
12416 (struct mg_connection
*)mg_calloc(1, sizeof(*conn
) + MAX_REQUEST_SIZE
);
12417 if (conn
== NULL
) {
12418 mg_cry(fc(ctx
), "%s", "Cannot create new connection struct, OOM");
12420 pthread_setspecific(sTlsKey
, &tls
);
12421 conn
->buf_size
= MAX_REQUEST_SIZE
;
12422 conn
->buf
= (char *)(conn
+ 1);
12424 conn
->request_info
.user_data
= ctx
->user_data
;
12425 /* Allocate a mutex for this connection to allow communication both
12426 * within the request handler and from elsewhere in the application
12428 (void)pthread_mutex_init(&conn
->mutex
, &pthread_mutex_attr
);
12430 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
12431 * signal sq_empty condvar to wake up the master waiting in
12432 * produce_socket() */
12433 while (consume_socket(ctx
, &conn
->client
)) {
12434 conn
->conn_birth_time
= time(NULL
);
12436 /* Fill in IP, port info early so even if SSL setup below fails,
12437 * error handler would have the corresponding info.
12438 * Thanks to Johannes Winkelmann for the patch.
12440 #if defined(USE_IPV6)
12441 if (conn
->client
.rsa
.sa
.sa_family
== AF_INET6
) {
12442 conn
->request_info
.remote_port
=
12443 ntohs(conn
->client
.rsa
.sin6
.sin6_port
);
12447 conn
->request_info
.remote_port
=
12448 ntohs(conn
->client
.rsa
.sin
.sin_port
);
12451 sockaddr_to_string(conn
->request_info
.remote_addr
,
12452 sizeof(conn
->request_info
.remote_addr
),
12453 &conn
->client
.rsa
);
12455 #if defined(MG_LEGACY_INTERFACE)
12456 /* This legacy interface only works for the IPv4 case */
12457 addr
= ntohl(conn
->client
.rsa
.sin
.sin_addr
.s_addr
);
12458 memcpy(&conn
->request_info
.remote_ip
, &addr
, 4);
12461 conn
->request_info
.is_ssl
= conn
->client
.is_ssl
;
12463 if (!conn
->client
.is_ssl
12465 || sslize(conn
, conn
->ctx
->ssl_ctx
, SSL_accept
)
12470 process_new_connection(conn
);
12473 close_connection(conn
);
12477 /* Signal master that we're done with connection and exiting */
12478 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12479 ctx
->running_worker_threads
--;
12480 (void)pthread_cond_signal(&ctx
->thread_cond
);
12481 /* assert(ctx->running_worker_threads >= 0); */
12482 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12484 pthread_setspecific(sTlsKey
, NULL
);
12485 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12486 CloseHandle(tls
.pthread_cond_helper_mutex
);
12488 pthread_mutex_destroy(&conn
->mutex
);
12491 DEBUG_TRACE("%s", "exiting");
12496 /* Threads have different return types on Windows and Unix. */
12498 static unsigned __stdcall
worker_thread(void *thread_func_param
)
12500 worker_thread_run(thread_func_param
);
12505 worker_thread(void *thread_func_param
)
12507 worker_thread_run(thread_func_param
);
12510 #endif /* _WIN32 */
12513 /* Master thread adds accepted socket to a queue */
12515 produce_socket(struct mg_context
*ctx
, const struct socket
*sp
)
12517 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
12521 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12523 /* If the queue is full, wait */
12524 while (ctx
->stop_flag
== 0
12525 && ctx
->sq_head
- ctx
->sq_tail
>= QUEUE_SIZE(ctx
)) {
12526 (void)pthread_cond_wait(&ctx
->sq_empty
, &ctx
->thread_mutex
);
12529 if (ctx
->sq_head
- ctx
->sq_tail
< QUEUE_SIZE(ctx
)) {
12530 /* Copy socket to the queue and increment head */
12531 ctx
->queue
[ctx
->sq_head
% QUEUE_SIZE(ctx
)] = *sp
;
12533 DEBUG_TRACE("queued socket %d", sp
? sp
->sock
: -1);
12536 (void)pthread_cond_signal(&ctx
->sq_full
);
12537 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12543 accept_new_connection(const struct socket
*listener
, struct mg_context
*ctx
)
12546 char src_addr
[IP_ADDR_STR_LEN
];
12547 socklen_t len
= sizeof(so
.rsa
);
12555 if ((so
.sock
= accept(listener
->sock
, &so
.rsa
.sa
, &len
))
12556 == INVALID_SOCKET
) {
12557 } else if (!check_acl(ctx
, ntohl(*(uint32_t *)&so
.rsa
.sin
.sin_addr
))) {
12558 sockaddr_to_string(src_addr
, sizeof(src_addr
), &so
.rsa
);
12559 mg_cry(fc(ctx
), "%s: %s is not allowed to connect", __func__
, src_addr
);
12560 closesocket(so
.sock
);
12561 so
.sock
= INVALID_SOCKET
;
12563 /* Put so socket structure into the queue */
12564 DEBUG_TRACE("Accepted socket %d", (int)so
.sock
);
12565 set_close_on_exec(so
.sock
, fc(ctx
));
12566 so
.is_ssl
= listener
->is_ssl
;
12567 so
.ssl_redir
= listener
->ssl_redir
;
12568 if (getsockname(so
.sock
, &so
.lsa
.sa
, &len
) != 0) {
12570 "%s: getsockname() failed: %s",
12575 /* Set TCP keep-alive. This is needed because if HTTP-level
12577 * is enabled, and client resets the connection, server won't get
12578 * TCP FIN or RST and will keep the connection open forever. With
12579 * TCP keep-alive, next keep-alive handshake will figure out that
12580 * the client is down and will close the server end.
12581 * Thanks to Igor Klopov who suggested the patch. */
12582 if (setsockopt(so
.sock
,
12585 (SOCK_OPT_TYPE
)&on
,
12586 sizeof(on
)) != 0) {
12588 "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
12594 /* Disable TCP Nagle's algorithm. Normally TCP packets are
12596 * to effectively fill up the underlying IP packet payload and
12598 * the overhead of sending lots of small buffers. However this hurts
12599 * the server's throughput (ie. operations per second) when HTTP 1.1
12600 * persistent connections are used and the responses are relatively
12601 * small (eg. less than 1400 bytes).
12603 if ((ctx
!= NULL
) && (ctx
->config
[CONFIG_TCP_NODELAY
] != NULL
)
12604 && (!strcmp(ctx
->config
[CONFIG_TCP_NODELAY
], "1"))) {
12605 if (set_tcp_nodelay(so
.sock
, 1) != 0) {
12607 "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
12613 if (ctx
&& ctx
->config
[REQUEST_TIMEOUT
]) {
12614 timeout
= atoi(ctx
->config
[REQUEST_TIMEOUT
]);
12619 /* Set socket timeout to the given value, but not more than a
12620 * a certain limit (SOCKET_TIMEOUT_QUANTUM, default 10 seconds),
12621 * so the server can exit after that time if requested. */
12622 if ((timeout
> 0) && (timeout
< SOCKET_TIMEOUT_QUANTUM
)) {
12623 set_sock_timeout(so
.sock
, timeout
);
12625 set_sock_timeout(so
.sock
, SOCKET_TIMEOUT_QUANTUM
);
12628 produce_socket(ctx
, &so
);
12634 master_thread_run(void *thread_func_param
)
12636 struct mg_context
*ctx
= (struct mg_context
*)thread_func_param
;
12637 struct mg_workerTLS tls
;
12638 struct pollfd
*pfd
;
12640 unsigned int workerthreadcount
;
12646 mg_set_thread_name("master");
12648 /* Increase priority of the master thread */
12649 #if defined(_WIN32)
12650 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
12651 #elif defined(USE_MASTER_THREAD_PRIORITY)
12652 int min_prio
= sched_get_priority_min(SCHED_RR
);
12653 int max_prio
= sched_get_priority_max(SCHED_RR
);
12654 if ((min_prio
>= 0) && (max_prio
>= 0)
12655 && ((USE_MASTER_THREAD_PRIORITY
) <= max_prio
)
12656 && ((USE_MASTER_THREAD_PRIORITY
) >= min_prio
)) {
12657 struct sched_param sched_param
= {0};
12658 sched_param
.sched_priority
= (USE_MASTER_THREAD_PRIORITY
);
12659 pthread_setschedparam(pthread_self(), SCHED_RR
, &sched_param
);
12663 /* Initialize thread local storage */
12664 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12665 tls
.pthread_cond_helper_mutex
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
12668 pthread_setspecific(sTlsKey
, &tls
);
12670 if (ctx
->callbacks
.init_thread
) {
12671 /* Callback for the master thread (type 0) */
12672 ctx
->callbacks
.init_thread(ctx
, 0);
12675 /* Server starts *now* */
12676 ctx
->start_time
= time(NULL
);
12678 /* Allocate memory for the listening sockets, and start the server */
12680 (struct pollfd
*)mg_calloc(ctx
->num_listening_sockets
, sizeof(pfd
[0]));
12681 while (pfd
!= NULL
&& ctx
->stop_flag
== 0) {
12682 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12683 pfd
[i
].fd
= ctx
->listening_sockets
[i
].sock
;
12684 pfd
[i
].events
= POLLIN
;
12687 if (poll(pfd
, ctx
->num_listening_sockets
, 200) > 0) {
12688 for (i
= 0; i
< ctx
->num_listening_sockets
; i
++) {
12689 /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
12690 * successful poll, and POLLIN is defined as
12691 * (POLLRDNORM | POLLRDBAND)
12692 * Therefore, we're checking pfd[i].revents & POLLIN, not
12693 * pfd[i].revents == POLLIN. */
12694 if (ctx
->stop_flag
== 0 && (pfd
[i
].revents
& POLLIN
)) {
12695 accept_new_connection(&ctx
->listening_sockets
[i
], ctx
);
12701 DEBUG_TRACE("%s", "stopping workers");
12703 /* Stop signal received: somebody called mg_stop. Quit. */
12704 close_all_listening_sockets(ctx
);
12706 /* Wakeup workers that are waiting for connections to handle. */
12707 pthread_cond_broadcast(&ctx
->sq_full
);
12709 /* Wait until all threads finish */
12710 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
12711 while (ctx
->running_worker_threads
> 0) {
12712 (void)pthread_cond_wait(&ctx
->thread_cond
, &ctx
->thread_mutex
);
12714 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
12716 /* Join all worker threads to avoid leaking threads. */
12717 workerthreadcount
= ctx
->cfg_worker_threads
;
12718 for (i
= 0; i
< workerthreadcount
; i
++) {
12719 if (ctx
->workerthreadids
[i
] != 0) {
12720 mg_join_thread(ctx
->workerthreadids
[i
]);
12724 #if !defined(NO_SSL)
12725 if (ctx
->ssl_ctx
!= NULL
) {
12726 uninitialize_ssl(ctx
);
12729 DEBUG_TRACE("%s", "exiting");
12731 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12732 CloseHandle(tls
.pthread_cond_helper_mutex
);
12734 pthread_setspecific(sTlsKey
, NULL
);
12736 /* Signal mg_stop() that we're done.
12737 * WARNING: This must be the very last thing this
12738 * thread does, as ctx becomes invalid after this line. */
12739 ctx
->stop_flag
= 2;
12743 /* Threads have different return types on Windows and Unix. */
12745 static unsigned __stdcall
master_thread(void *thread_func_param
)
12747 master_thread_run(thread_func_param
);
12752 master_thread(void *thread_func_param
)
12754 master_thread_run(thread_func_param
);
12757 #endif /* _WIN32 */
12761 free_context(struct mg_context
*ctx
)
12764 struct mg_handler_info
*tmp_rh
;
12770 if (ctx
->callbacks
.exit_context
) {
12771 ctx
->callbacks
.exit_context(ctx
);
12774 /* All threads exited, no sync is needed. Destroy thread mutex and
12777 (void)pthread_mutex_destroy(&ctx
->thread_mutex
);
12778 (void)pthread_cond_destroy(&ctx
->thread_cond
);
12779 (void)pthread_cond_destroy(&ctx
->sq_empty
);
12780 (void)pthread_cond_destroy(&ctx
->sq_full
);
12782 /* Destroy other context global data structures mutex */
12783 (void)pthread_mutex_destroy(&ctx
->nonce_mutex
);
12785 #if defined(USE_TIMERS)
12789 /* Deallocate config parameters */
12790 for (i
= 0; i
< NUM_OPTIONS
; i
++) {
12791 if (ctx
->config
[i
] != NULL
) {
12792 #if defined(_MSC_VER)
12793 #pragma warning(suppress : 6001)
12795 mg_free(ctx
->config
[i
]);
12799 /* Deallocate request handlers */
12800 while (ctx
->handlers
) {
12801 tmp_rh
= ctx
->handlers
;
12802 ctx
->handlers
= tmp_rh
->next
;
12803 mg_free(tmp_rh
->uri
);
12808 /* Deallocate SSL context */
12809 if (ctx
->ssl_ctx
!= NULL
) {
12810 SSL_CTX_free(ctx
->ssl_ctx
);
12812 #endif /* !NO_SSL */
12814 /* Deallocate worker thread ID array */
12815 if (ctx
->workerthreadids
!= NULL
) {
12816 mg_free(ctx
->workerthreadids
);
12819 /* Deallocate the tls variable */
12820 if (mg_atomic_dec(&sTlsInit
) == 0) {
12821 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12822 DeleteCriticalSection(&global_log_file_lock
);
12823 #endif /* _WIN32 && !__SYMBIAN32__ */
12824 #if !defined(_WIN32)
12825 pthread_mutexattr_destroy(&pthread_mutex_attr
);
12828 pthread_key_delete(sTlsKey
);
12831 /* deallocate system name string */
12832 mg_free(ctx
->systemName
);
12834 /* Deallocate context itself */
12840 mg_stop(struct mg_context
*ctx
)
12847 /* We don't use a lock here. Calling mg_stop with the same ctx from
12848 * two threads is not allowed. */
12849 mt
= ctx
->masterthreadid
;
12854 ctx
->masterthreadid
= 0;
12855 ctx
->stop_flag
= 1;
12857 /* Wait until mg_fini() stops */
12858 while (ctx
->stop_flag
!= 2) {
12859 (void)mg_sleep(10);
12862 mg_join_thread(mt
);
12865 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12866 (void)WSACleanup();
12867 #endif /* _WIN32 && !__SYMBIAN32__ */
12872 get_system_name(char **sysName
)
12874 #if defined(_WIN32)
12875 #if !defined(__SYMBIAN32__)
12877 DWORD dwVersion
= 0;
12878 DWORD dwMajorVersion
= 0;
12879 DWORD dwMinorVersion
= 0;
12883 #pragma warning(push)
12884 // GetVersion was declared deprecated
12885 #pragma warning(disable : 4996)
12887 dwVersion
= GetVersion();
12889 #pragma warning(pop)
12892 dwMajorVersion
= (DWORD
)(LOBYTE(LOWORD(dwVersion
)));
12893 dwMinorVersion
= (DWORD
)(HIBYTE(LOWORD(dwVersion
)));
12894 dwBuild
= ((dwVersion
< 0x80000000) ? (DWORD
)(HIWORD(dwVersion
)) : 0);
12899 (unsigned)dwMajorVersion
,
12900 (unsigned)dwMinorVersion
);
12901 *sysName
= mg_strdup(name
);
12903 *sysName
= mg_strdup("Symbian");
12906 struct utsname name
;
12907 memset(&name
, 0, sizeof(name
));
12909 *sysName
= mg_strdup(name
.sysname
);
12914 struct mg_context
*
12915 mg_start(const struct mg_callbacks
*callbacks
,
12917 const char **options
)
12919 struct mg_context
*ctx
;
12920 const char *name
, *value
, *default_value
;
12921 int idx
, ok
, workerthreadcount
;
12923 void (*exit_callback
)(const struct mg_context
*ctx
) = 0;
12925 struct mg_workerTLS tls
;
12927 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12929 WSAStartup(MAKEWORD(2, 2), &data
);
12930 #endif /* _WIN32 && !__SYMBIAN32__ */
12932 /* Allocate context and initialize reasonable general case defaults. */
12933 if ((ctx
= (struct mg_context
*)mg_calloc(1, sizeof(*ctx
))) == NULL
) {
12937 /* Random number generator will initialize at the first call */
12938 ctx
->auth_nonce_mask
=
12939 (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options
);
12941 if (mg_atomic_inc(&sTlsInit
) == 1) {
12943 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12944 InitializeCriticalSection(&global_log_file_lock
);
12945 #endif /* _WIN32 && !__SYMBIAN32__ */
12946 #if !defined(_WIN32)
12947 pthread_mutexattr_init(&pthread_mutex_attr
);
12948 pthread_mutexattr_settype(&pthread_mutex_attr
, PTHREAD_MUTEX_RECURSIVE
);
12951 if (0 != pthread_key_create(&sTlsKey
, tls_dtor
)) {
12952 /* Fatal error - abort start. However, this situation should
12954 * occur in practice. */
12955 mg_atomic_dec(&sTlsInit
);
12956 mg_cry(fc(ctx
), "Cannot initialize thread local storage");
12961 /* TODO (low): istead of sleeping, check if sTlsKey is already
12966 tls
.is_master
= -1;
12967 tls
.thread_idx
= (unsigned)mg_atomic_inc(&thread_idx_max
);
12968 #if defined(_WIN32) && !defined(__SYMBIAN32__)
12969 tls
.pthread_cond_helper_mutex
= NULL
;
12971 pthread_setspecific(sTlsKey
, &tls
);
12973 #if defined(USE_LUA)
12974 lua_init_optional_libraries();
12977 ok
= 0 == pthread_mutex_init(&ctx
->thread_mutex
, &pthread_mutex_attr
);
12978 ok
&= 0 == pthread_cond_init(&ctx
->thread_cond
, NULL
);
12979 ok
&= 0 == pthread_cond_init(&ctx
->sq_empty
, NULL
);
12980 ok
&= 0 == pthread_cond_init(&ctx
->sq_full
, NULL
);
12981 ok
&= 0 == pthread_mutex_init(&ctx
->nonce_mutex
, &pthread_mutex_attr
);
12983 /* Fatal error - abort start. However, this situation should never
12984 * occur in practice. */
12985 mg_cry(fc(ctx
), "Cannot initialize thread synchronization objects");
12987 pthread_setspecific(sTlsKey
, NULL
);
12992 ctx
->callbacks
= *callbacks
;
12993 exit_callback
= callbacks
->exit_context
;
12994 ctx
->callbacks
.exit_context
= 0;
12996 ctx
->user_data
= user_data
;
12997 ctx
->handlers
= NULL
;
12999 #if defined(USE_LUA) && defined(USE_WEBSOCKET)
13000 ctx
->shared_lua_websockets
= 0;
13003 while (options
&& (name
= *options
++) != NULL
) {
13004 if ((idx
= get_option_index(name
)) == -1) {
13005 mg_cry(fc(ctx
), "Invalid option: %s", name
);
13007 pthread_setspecific(sTlsKey
, NULL
);
13009 } else if ((value
= *options
++) == NULL
) {
13010 mg_cry(fc(ctx
), "%s: option value cannot be NULL", name
);
13012 pthread_setspecific(sTlsKey
, NULL
);
13015 if (ctx
->config
[idx
] != NULL
) {
13016 mg_cry(fc(ctx
), "warning: %s: duplicate option", name
);
13017 mg_free(ctx
->config
[idx
]);
13019 ctx
->config
[idx
] = mg_strdup(value
);
13020 DEBUG_TRACE("[%s] -> [%s]", name
, value
);
13023 /* Set default value if needed */
13024 for (i
= 0; config_options
[i
].name
!= NULL
; i
++) {
13025 default_value
= config_options
[i
].default_value
;
13026 if (ctx
->config
[i
] == NULL
&& default_value
!= NULL
) {
13027 ctx
->config
[i
] = mg_strdup(default_value
);
13031 #if defined(NO_FILES)
13032 if (ctx
->config
[DOCUMENT_ROOT
] != NULL
) {
13033 mg_cry(fc(ctx
), "%s", "Document root must not be set");
13035 pthread_setspecific(sTlsKey
, NULL
);
13040 get_system_name(&ctx
->systemName
);
13042 /* NOTE(lsm): order is important here. SSL certificates must
13043 * be initialized before listening ports. UID must be set last. */
13044 if (!set_gpass_option(ctx
) ||
13045 #if !defined(NO_SSL)
13046 !set_ssl_option(ctx
) ||
13048 !set_ports_option(ctx
) ||
13049 #if !defined(_WIN32)
13050 !set_uid_option(ctx
) ||
13052 !set_acl_option(ctx
)) {
13054 pthread_setspecific(sTlsKey
, NULL
);
13058 #if !defined(_WIN32) && !defined(__SYMBIAN32__)
13059 /* Ignore SIGPIPE signal, so if browser cancels the request, it
13060 * won't kill the whole process. */
13061 (void)signal(SIGPIPE
, SIG_IGN
);
13062 #endif /* !_WIN32 && !__SYMBIAN32__ */
13064 workerthreadcount
= atoi(ctx
->config
[NUM_THREADS
]);
13066 if (workerthreadcount
> MAX_WORKER_THREADS
) {
13067 mg_cry(fc(ctx
), "Too many worker threads");
13069 pthread_setspecific(sTlsKey
, NULL
);
13073 if (workerthreadcount
> 0) {
13074 ctx
->cfg_worker_threads
= ((unsigned int)(workerthreadcount
));
13075 ctx
->workerthreadids
=
13076 (pthread_t
*)mg_calloc(ctx
->cfg_worker_threads
, sizeof(pthread_t
));
13077 if (ctx
->workerthreadids
== NULL
) {
13078 mg_cry(fc(ctx
), "Not enough memory for worker thread ID array");
13080 pthread_setspecific(sTlsKey
, NULL
);
13085 #if defined(USE_TIMERS)
13086 if (timers_init(ctx
) != 0) {
13087 mg_cry(fc(ctx
), "Error creating timers");
13089 pthread_setspecific(sTlsKey
, NULL
);
13094 /* Context has been created - init user libraries */
13095 if (ctx
->callbacks
.init_context
) {
13096 ctx
->callbacks
.init_context(ctx
);
13098 ctx
->callbacks
.exit_context
= exit_callback
;
13099 ctx
->context_type
= 1; /* server context */
13101 /* Start master (listening) thread */
13102 mg_start_thread_with_id(master_thread
, ctx
, &ctx
->masterthreadid
);
13104 /* Start worker threads */
13105 for (i
= 0; i
< ctx
->cfg_worker_threads
; i
++) {
13106 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13107 ctx
->running_worker_threads
++;
13108 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13109 if (mg_start_thread_with_id(worker_thread
,
13111 &ctx
->workerthreadids
[i
]) != 0) {
13112 (void)pthread_mutex_lock(&ctx
->thread_mutex
);
13113 ctx
->running_worker_threads
--;
13114 (void)pthread_mutex_unlock(&ctx
->thread_mutex
);
13117 "Cannot start worker thread %i: error %ld",
13122 "Cannot create threads: error %ld",
13125 pthread_setspecific(sTlsKey
, NULL
);
13132 pthread_setspecific(sTlsKey
, NULL
);
13137 /* Feature check API function */
13139 mg_check_feature(unsigned feature
)
13141 static const unsigned feature_set
= 0
13142 /* Set bits for available features according to API documentation.
13143 * This bit mask is created at compile time, according to the active
13144 * preprocessor defines. It is a single const value at runtime. */
13145 #if !defined(NO_FILES)
13148 #if !defined(NO_SSL)
13151 #if !defined(NO_CGI)
13154 #if defined(USE_IPV6)
13157 #if defined(USE_WEBSOCKET)
13160 #if defined(USE_LUA)
13163 #if defined(USE_DUKTAPE)
13166 #if !defined(NO_CACHING)
13170 /* Set some extra bits not defined in the API documentation.
13171 * These bits may change without further notice. */
13172 #if defined(MG_LEGACY_INTERFACE)
13175 #if defined(MEMORY_DEBUGGING)
13178 #if defined(USE_TIMERS)
13181 #if !defined(NO_NONCE_CHECK)
13184 #if !defined(NO_POPEN)
13188 return (feature
& feature_set
);