Lines Matching +full:clang +full:- +full:3

1 /* Copyright (c) 2013-2018 the Civetweb developers
2 * Copyright (c) 2004-2013 Sergey Lyubka
33 /* Disable unused macros warnings - not all defines are required
35 #pragma GCC diagnostic ignored "-Wunused-macros"
37 #pragma GCC diagnostic ignored "-Wpadded"
45 #pragma GCC diagnostic ignored "-Wreserved-id-macro"
52 #if !defined(_WIN32_WINNT) /* defined for tdm-gcc so we can use getnameinfo */
70 #define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
88 /* Enable reserved-id-macro warning again. */
102 /* non-constant aggregate initializer: issued due to missing C99 support */
125 extern char static_assert_replacement[(cond) ? 1 : -1]
148 /* DTL -- including winsock2.h works better if lean and mean */
155 * Symbian is no longer maintained since 2014-01-01.
182 * and minus the main civetweb thread, thus -2
184 #define MAX_WORKER_THREADS (CONFIG_MAX_PTHREAD_COUNT - 2)
212 ...) PRINTF_ARGS(3, 4);
277 * Either the compiler creates an "unused-function" warning if a
281 * "used-but-marked-unused" warning - and
282 * #pragma GCC diagnostic ignored "-Wused-but-marked-unused"
288 #pragma GCC diagnostic ignored "-Wunused-function"
309 /* When using -Weverything, clang does not accept it's own headers
311 * -Weverything. */
312 #pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
322 * #pragma clang diagnostic ignored "-Wno-error=date-time"
323 * #pragma clang diagnostic ignored "-Wdate-time"
335 #if (__clang_major__ == 3) && ((__clang_minor__ == 7) || (__clang_minor__ == 8))
337 #pragma clang diagnostic ignored "-Wno-reserved-id-macro"
338 #pragma clang diagnostic ignored "-Wno-keyword-macro"
362 t->tv_sec = now.tv_sec; in _civet_clock_gettime()
363 t->tv_nsec = now.tv_usec * 1000; in _civet_clock_gettime()
382 now = (uint64_t)((double)(now - clock_start_time) in _civet_clock_gettime()
386 t->tv_sec = now / 1000000000; in _civet_clock_gettime()
387 t->tv_nsec = now % 1000000000; in _civet_clock_gettime()
390 return -1; /* EINVAL - Clock ID is unknown */ in _civet_clock_gettime()
502 /* at most three UTF-8 chars per wchar_t */
503 #define PATH_MAX (W_PATH_MAX * 3)
505 #define W_PATH_MAX ((PATH_MAX + 2) / 3)
527 #define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
535 ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
575 #define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
596 #define fseeko(x, y, z) ((_lseeki64(_fileno(x), (y), (z)) == -1) ? -1 : 0)
637 #define CLOCK_THREAD (3)
685 li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */ in clock_gettime()
686 tp->tv_sec = (time_t)(li.QuadPart / 10000000); in clock_gettime()
687 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; in clock_gettime()
696 tp->tv_sec = (time_t)d; in clock_gettime()
697 d -= (double)tp->tv_sec; in clock_gettime()
698 tp->tv_nsec = (long)(d * 1.0E9); in clock_gettime()
716 tp->tv_sec = (time_t)(li.QuadPart / 10000000); in clock_gettime()
717 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; in clock_gettime()
736 tp->tv_sec = (time_t)(li.QuadPart / 10000000); in clock_gettime()
737 tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100; in clock_gettime()
750 return ok ? 0 : -1; in clock_gettime()
798 #else /* defined(_WIN32) - WINDOWS vs UNIX include block */
861 #define INVALID_SOCKET (-1)
879 * their typedef with int. - DTL
886 #endif /* defined(_WIN32) - WINDOWS vs UNIX include block */
899 return (y - 1969) / 4 - (y - 1901) / 100 + (y - 1601) / 400; in count_leap()
907 int year = tm->tm_year + 1900; in timegm()
908 int mon = tm->tm_mon; in timegm()
909 int mday = tm->tm_mday - 1; in timegm()
910 int hour = tm->tm_hour; in timegm()
911 int min = tm->tm_min; in timegm()
912 int sec = tm->tm_sec; in timegm()
915 || (mday >= ydays[mon + 1] - ydays[mon] in timegm()
918 return -1; in timegm()
920 time_t res = year - 1970; in timegm()
937 /* va_copy should always be a macro, C99 and C++11 - DTL */
949 #pragma GCC diagnostic ignored "-Wunused-function"
974 return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1; in pthread_key_create()
976 return -2; in pthread_key_create()
1020 #pragma GCC diagnostic ignored "-Wunused-function"
1060 ptm->tm_year = st.wYear - 1900; in localtime_s()
1061 ptm->tm_mon = st.wMonth - 1; in localtime_s()
1062 ptm->tm_wday = st.wDayOfWeek; in localtime_s()
1063 ptm->tm_mday = st.wDay; in localtime_s()
1064 ptm->tm_hour = st.wHour; in localtime_s()
1065 ptm->tm_min = st.wMinute; in localtime_s()
1066 ptm->tm_sec = st.wSecond; in localtime_s()
1067 ptm->tm_yday = 0; /* hope nobody uses this */ in localtime_s()
1068 ptm->tm_isdst = in localtime_s()
1131 return MoveFileW(wa, wb) ? 0 : -1; in rename()
1153 st->st_size = in stat()
1162 st->st_mtime = creation_time; in stat()
1164 st->st_mtime = write_time; in stat()
1171 /* WinCE-TODO: define stat, remove, rename, _rmdir, _lseeki64 */
1188 #pragma GCC diagnostic ignored "-Wunused-function"
1192 #pragma clang diagnostic push
1193 #pragma clang diagnostic ignored "-Wunused-function"
1254 ret = (--(*addr)); in mg_atomic_dec()
1289 #pragma clang diagnostic pop
1323 int64_t mmem = mg_atomic_add(&mstat->totalMemUsed, (int64_t)size); in mg_malloc_ex()
1324 if (mmem > mstat->maxMemUsed) { in mg_malloc_ex()
1327 mstat->maxMemUsed = mmem; in mg_malloc_ex()
1330 mg_atomic_inc(&mstat->blockCount); in mg_malloc_ex()
1338 "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n", in mg_malloc_ex()
1341 (unsigned long)mstat->totalMemUsed, in mg_malloc_ex()
1342 (unsigned long)mstat->blockCount, in mg_malloc_ex()
1375 void *data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t)); in mg_free_ex()
1389 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)size); in mg_free_ex()
1390 mg_atomic_dec(&mstat->blockCount); in mg_free_ex()
1393 "MEM: %p %5lu free %7lu %4lu --- %s:%u\n", in mg_free_ex()
1396 (unsigned long)mstat->totalMemUsed, in mg_free_ex()
1397 (unsigned long)mstat->blockCount, in mg_free_ex()
1433 data = (void *)(((char *)memory) - 2 * sizeof(uintptr_t)); in mg_realloc_ex()
1439 mg_atomic_add(&mstat->totalMemUsed, -(int64_t)oldsize); in mg_realloc_ex()
1442 "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n", in mg_realloc_ex()
1445 (unsigned long)mstat->totalMemUsed, in mg_realloc_ex()
1446 (unsigned long)mstat->blockCount, in mg_realloc_ex()
1455 mg_atomic_add(&mstat->totalMemUsed, (int64_t)newsize); in mg_realloc_ex()
1458 "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n", in mg_realloc_ex()
1461 (unsigned long)mstat->totalMemUsed, in mg_realloc_ex()
1462 (unsigned long)mstat->blockCount, in mg_realloc_ex()
1553 /* This following lines are just meant as a reminder to use the mg-functions
1616 #pragma GCC diagnostic ignored "-Wunused-function"
1620 #pragma clang diagnostic push
1621 #pragma clang diagnostic ignored "-Wunused-function"
1644 #pragma clang diagnostic push in mg_current_thread_id()
1645 #pragma clang diagnostic ignored "-Wunreachable-code" in mg_current_thread_id()
1662 tls->is_master = -2; /* -2 means "3rd party thread" */ in mg_current_thread_id()
1663 tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max); in mg_current_thread_id()
1666 return tls->thread_idx; in mg_current_thread_id()
1670 * Here memcpy is used as an anything-to-anything cast. */ in mg_current_thread_id()
1678 #pragma clang diagnostic pop in mg_current_thread_id()
1701 #pragma clang diagnostic pop
1729 nsnow - nslast, in DEBUG_TRACE_FUNC()
1843 #define SSL_ERROR_WANT_WRITE (3)
1855 #define SSL_TLSEXT_ERR_NOACK (3)
1868 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
1943 #define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
1944 #define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
1952 #define X509_free (*(void (*)(X509 *))crypto_sw[3].ptr)
2047 #define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
2119 #define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
2120 #define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
2130 #define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
2285 * case we need a "Content-Eencoding: gzip" header */
2302 * we decided to get rid of this feature (after some fade-out
2336 /* Describes listening socket, or socket which was accept()-ed by the master
2342 unsigned char is_ssl; /* Is port SSL-ed */
2645 /* Part 1 - Physical context:
2658 struct mg_connection *worker_connections; /* The connection struct, pre-
2716 struct mg_callbacks callbacks; /* User-defined callback function */
2717 void *user_data; /* User-defined data */
2719 /* Part 2 - Logical domain:
2737 return &(ctx->ctx_memory); in get_memory_stat()
2773 * !is_chunked: Content-Length header value
2774 * or -1 (until connection closed,
2779 int is_chunked; /* Transfer-Encoding is chunked:
2783 * 3 = chunked, all data read except trailer,
2850 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
2856 DWORD dwThreadID; /* Thread ID (-1=caller thread). */
2878 if (evhdl == -1) { in event_create()
2879 /* Linux uses -1 on error, Windows NULL. */ in event_create()
2976 if (0 != pthread_mutex_init(&(ret->mutex), NULL)) { in event_create()
2981 if (0 != pthread_cond_init(&(ret->cond), NULL)) { in event_create()
2983 pthread_mutex_destroy(&(ret->mutex)); in event_create()
2987 ret->signaled = 0; in event_create()
2996 pthread_mutex_lock(&(ev->mutex)); in event_wait()
2997 while (!ev->signaled) { in event_wait()
2998 pthread_cond_wait(&(ev->cond), &(ev->mutex)); in event_wait()
3000 ev->signaled = 0; in event_wait()
3001 pthread_mutex_unlock(&(ev->mutex)); in event_wait()
3010 pthread_mutex_lock(&(ev->mutex)); in event_signal()
3011 pthread_cond_signal(&(ev->cond)); in event_signal()
3012 ev->signaled = 1; in event_signal()
3013 pthread_mutex_unlock(&(ev->mutex)); in event_signal()
3022 pthread_cond_destroy(&(ev->cond)); in event_destroy()
3023 pthread_mutex_destroy(&(ev->mutex)); in event_destroy()
3035 NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name); in mg_set_thread_name()
3138 if (conn->phys_ctx->callbacks.open_file) { in open_file_in_memory()
3139 buf = conn->phys_ctx->callbacks.open_file(conn, path, &size); in open_file_in_memory()
3149 /* NOTE: override filep->size only on success. Otherwise, it in open_file_in_memory()
3152 filep->access.membuf = buf; in open_file_in_memory()
3153 filep->access.fp = NULL; in open_file_in_memory()
3156 filep->stat.size = size; in open_file_in_memory()
3160 filep->stat.last_modified = time(NULL); in open_file_in_memory()
3162 filep->stat.is_directory = 0; in open_file_in_memory()
3163 filep->stat.is_gzipped = 0; in open_file_in_memory()
3196 return (fileacc->membuf != NULL) || (fileacc->fp != NULL); in is_file_opened()
3198 return (fileacc->fp != NULL); in is_file_opened()
3210 * The input parameter path is a string in UTF-8 encoding.
3226 filep->access.fp = NULL; in mg_fopen()
3228 filep->access.membuf = NULL; in mg_fopen()
3235 found = mg_stat(conn, path, &(filep->stat)); in mg_fopen()
3248 filep->access.fp = _wfopen(wbuf, L"rb"); in mg_fopen()
3251 filep->access.fp = _wfopen(wbuf, L"wb"); in mg_fopen()
3254 filep->access.fp = _wfopen(wbuf, L"ab"); in mg_fopen()
3262 filep->access.fp = fopen(path, "r"); in mg_fopen()
3265 filep->access.fp = fopen(path, "w"); in mg_fopen()
3268 filep->access.fp = fopen(path, "a"); in mg_fopen()
3277 found = mg_stat(conn, path, &(filep->stat)); in mg_fopen()
3282 return (filep->access.fp != NULL); in mg_fopen()
3289 return (filep->access.membuf != NULL); in mg_fopen()
3303 int ret = -1; in mg_fclose()
3305 if (fileacc->fp != NULL) { in mg_fclose()
3306 ret = fclose(fileacc->fp); in mg_fclose()
3308 } else if (fileacc->membuf != NULL) { in mg_fclose()
3323 for (; *src != '\0' && n > 1; n--) { in mg_strlcpy()
3344 diff = lowercase(s1++) - lowercase(s2++); in mg_strncasecmp()
3345 } while (diff == 0 && s1[-1] != '\0' && --len > 0); in mg_strncasecmp()
3358 diff = lowercase(s1++) - lowercase(s2++); in mg_strcasecmp()
3359 } while (diff == 0 && s1[-1] != '\0'); in mg_strcasecmp()
3399 for (i = 0; i <= (big_len - small_len); i++) { in mg_strcasestr()
3430 #pragma clang diagnostic push in mg_vsnprintf()
3431 #pragma clang diagnostic ignored "-Wformat-nonliteral" in mg_vsnprintf()
3432 /* Using fmt as a non-literal is intended here, since it is mostly called in mg_vsnprintf()
3440 #pragma clang diagnostic pop in mg_vsnprintf()
3453 (int)((buflen > 200) ? 200 : (buflen - 1)), in mg_vsnprintf()
3455 n = (int)buflen - 1; in mg_vsnprintf()
3487 return -1; in get_option_index()
3495 if ((i = get_option_index(name)) == -1) { in mg_get_option()
3497 } else if (!ctx || ctx->dd.config[i] == NULL) { in mg_get_option()
3500 return ctx->dd.config[i]; in mg_get_option()
3509 return (conn == NULL) ? (struct mg_context *)NULL : (conn->phys_ctx); in mg_get_context()
3516 return (ctx == NULL) ? NULL : ctx->user_data; in mg_get_user_data()
3526 return conn->tls_user_ptr; in mg_get_thread_pointer()
3531 return tls->user_ptr; in mg_get_thread_pointer()
3540 conn->request_info.conn_data = data; in mg_set_user_connection_data()
3549 return conn->request_info.conn_data; in mg_get_user_connection_data()
3564 for (i = 0; i < size && i < ctx->num_listening_sockets; i++) { in mg_get_ports()
3565 ssl[i] = ctx->listening_sockets[i].is_ssl; in mg_get_ports()
3568 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) in mg_get_ports()
3569 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port) in mg_get_ports()
3572 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port); in mg_get_ports()
3587 return -1; in mg_get_server_ports()
3591 return -1; in mg_get_server_ports()
3593 if (!ctx->listening_sockets) { in mg_get_server_ports()
3594 return -1; in mg_get_server_ports()
3597 for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) { in mg_get_server_ports()
3601 (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) in mg_get_server_ports()
3602 ? ntohs(ctx->listening_sockets[i].lsa.sin6.sin6_port) in mg_get_server_ports()
3605 ntohs(ctx->listening_sockets[i].lsa.sin.sin_port); in mg_get_server_ports()
3606 ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl; in mg_get_server_ports()
3607 ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir; in mg_get_server_ports()
3609 if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) { in mg_get_server_ports()
3613 } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) { in mg_get_server_ports()
3615 ports[cnt].protocol = 3; in mg_get_server_ports()
3633 if (usa->sa.sa_family == AF_INET) { in sockaddr_to_string()
3634 getnameinfo(&usa->sa, in sockaddr_to_string()
3635 sizeof(usa->sin), in sockaddr_to_string()
3643 else if (usa->sa.sa_family == AF_INET6) { in sockaddr_to_string()
3644 getnameinfo(&usa->sa, in sockaddr_to_string()
3645 sizeof(usa->sin6), in sockaddr_to_string()
3676 buf[buf_len - 1] = '\0';
3685 return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
3686 + (double)(ts_now->tv_sec - ts_before->tv_sec);
3717 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
3726 buf[sizeof(buf) - 1] = 0;
3738 if ((conn->phys_ctx->callbacks.log_message == NULL)
3739 || (conn->phys_ctx->callbacks.log_message(conn, buf) == 0)) {
3741 if (conn->dom_ctx->config[ERROR_LOG_FILE] != NULL) {
3743 conn->dom_ctx->config[ERROR_LOG_FILE],
3757 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
3763 if (conn->request_info.request_method != NULL) {
3766 conn->request_info.request_method,
3767 conn->request_info.request_uri
3768 ? conn->request_info.request_uri
3777 * mg_cry here anyway ;-) */
3793 fc->phys_ctx = ctx;
3794 fc->dom_ctx = &(ctx->dd);
3846 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
3851 sprintf(txt, "%03i", conn->response_info.status_code);
3852 if (strlen(txt) == 3) {
3853 memcpy(tls->txtbuf, txt, 4);
3855 strcpy(tls->txtbuf, "ERR");
3858 ((struct mg_connection *)conn)->request_info.local_uri =
3859 ((struct mg_connection *)conn)->request_info.request_uri =
3860 tls->txtbuf; /* use thread safe buffer */
3862 ((struct mg_connection *)conn)->request_info.num_headers =
3863 conn->response_info.num_headers;
3864 memcpy(((struct mg_connection *)conn)->request_info.http_headers,
3865 conn->response_info.http_headers,
3866 sizeof(conn->response_info.http_headers));
3869 if (conn->connection_type != CONNECTION_TYPE_REQUEST) {
3872 return &conn->request_info;
3882 if (conn->connection_type != CONNECTION_TYPE_RESPONSE) {
3885 return &conn->response_info;
3893 #pragma clang diagnostic push
3894 #pragma clang diagnostic ignored "-Wunreachable-code"
3896 * not supported. Clang raises an "unreachable code" warning for parts of ?:
3902 const struct mg_request_info *ri = &conn->request_info;
3905 (is_websocket_protocol(conn) ? (ri->is_ssl ? "wss" : "ws")
3906 : (ri->is_ssl ? "https" : "http"));
3911 #pragma clang diagnostic pop
3920 return -1;
3924 const struct mg_request_info *ri = &conn->request_info;
3928 if (ri->local_uri == NULL) {
3929 return -1;
3932 if ((ri->request_uri != NULL)
3933 && (0 != strcmp(ri->local_uri, ri->request_uri))) {
3943 ri->request_uri);
3945 return -1;
3955 int is_ipv6 = (conn->client.lsa.sa.sa_family == AF_INET6);
3956 int port = is_ipv6 ? htons(conn->client.lsa.sin6.sin6_port)
3957 : htons(conn->client.lsa.sin.sin_port);
3959 int port = htons(conn->client.lsa.sin.sin_port);
3961 int def_port = ri->is_ssl ? 443 : 80;
3963 conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK]
3965 conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes"));
3967 conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
3982 &conn->client.lsa);
3995 ri->local_uri);
3997 return -1;
4005 * 0-terminate resulting word. Skip the delimiter and following whitespaces.
4006 * Advance pointer to buffer to the next word. Return found 0-terminated
4022 p = end_word - 1;
4033 p += end_off; /* p must correspond to end_word - 1 */
4052 #pragma GCC diagnostic ignored "-Wsign-conversion"
4099 for (i = 0; i < ri->num_headers && cnt < output_max_size; i++) {
4100 if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
4101 output[cnt++] = ri->http_headers[i].value;
4117 if (conn->connection_type == CONNECTION_TYPE_REQUEST) {
4118 return get_header(conn->request_info.http_headers,
4119 conn->request_info.num_headers,
4122 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
4123 return get_header(conn->response_info.http_headers,
4124 conn->response_info.num_headers,
4138 if (conn->connection_type == CONNECTION_TYPE_REQUEST) {
4139 return conn->request_info.http_version;
4141 if (conn->connection_type == CONNECTION_TYPE_RESPONSE) {
4142 return conn->response_info.http_version;
4169 val->ptr = list;
4170 if ((list = strchr(val->ptr, ',')) != NULL) {
4172 val->len = ((size_t)(list - val->ptr));
4176 list = val->ptr + strlen(val->ptr);
4177 val->len = ((size_t)(list - val->ptr));
4181 end = (int)val->len - 1;
4182 while (end >= 0 && ((val->ptr[end] == ' ') || (val->ptr[end] == '\t')))
4183 end--;
4184 val->len = (size_t)(end) + (size_t)(1);
4186 if (val->len == 0) {
4194 eq_val->len = 0;
4195 eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len);
4196 if (eq_val->ptr != NULL) {
4197 eq_val->ptr++; /* Skip over '=' character */
4198 eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
4199 val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1;
4229 /* Perform case-insensitive match of string against pattern */
4237 res = match_prefix(pattern, (size_t)(or_str - pattern), str);
4241 - (or_str + 1)),
4249 return (str[j] == '\0') ? j : -1;
4262 res = match_prefix(pattern + i, pattern_len - i, str + j + len);
4263 } while (res == -1 && len-- > 0);
4264 return (res == -1) ? -1 : j + res + len;
4266 return -1;
4283 if ((conn == NULL) || conn->must_close) {
4288 if (mg_strcasecmp(conn->dom_ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0) {
4297 if (header_has_option(header, "keep-alive")) {
4318 if (!conn || !conn->dom_ctx) {
4322 return (mg_strcasecmp(conn->dom_ctx->config[DECODE_URL], "yes") == 0);
4329 return should_keep_alive(conn) ? "keep-alive" : "close";
4336 /* Send all current and obsolete cache opt-out directives. */
4338 "Cache-Control: no-cache, no-store, "
4339 "must-revalidate, private, max-age=0\r\n"
4340 "Pragma: no-cache\r\n"
4351 int max_age = atoi(conn->dom_ctx->config[STATIC_FILE_MAX_AGE]);
4356 * max-age=0, but also pragmas and Expires headers. */
4360 /* Use "Cache-Control: max-age" instead of "Expires" header.
4361 * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
4369 return mg_printf(conn, "Cache-Control: max-age=%u\r\n", (unsigned)max_age);
4380 const char *header = conn->dom_ctx->config[ADDITIONAL_HEADER];
4383 if (conn->dom_ctx->config[STRICT_HTTPS_MAX_AGE]) {
4384 int max_age = atoi(conn->dom_ctx->config[STRICT_HTTPS_MAX_AGE]);
4387 "Strict-Transport-Security: max-age=%u\r\n",
4412 * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
4416 /* RFC2616 Section 10.1 - Informational 1xx */
4424 /* RFC2616 Section 10.2 - Successful 2xx */
4430 return "Accepted"; /* RFC2616 Section 10.2.3 */
4432 return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
4440 return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1
4448 /* RFC2616 Section 10.3 - Redirection 3xx */
4454 return "Found"; /* RFC2616 Section 10.3.3 */
4464 return "Permanent Redirect"; /* RFC7238 Section 3 */
4466 /* RFC2616 Section 10.4 - Client Error 4xx */
4472 return "Payment Required"; /* RFC2616 Section 10.4.3 */
4484 return "Request Time-out"; /* RFC2616 Section 10.4.9 */
4496 return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
4520 return "Precondition Required"; /* RFC 6585, Section 3 */
4528 return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
4529 * Section 3 */
4531 /* RFC2616 Section 10.5 - Server Error 5xx */
4537 return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
4541 return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
4630 return -2;
4634 conn->status_code = status;
4641 || (!conn->in_error_handler
4642 && (conn->phys_ctx->callbacks.http_error != NULL))) {
4648 DEBUG_TRACE("Error %i - [%s]", status, errmsg_buf);
4654 if (!conn->in_error_handler
4655 && (conn->phys_ctx->callbacks.http_error != NULL)) {
4657 conn->in_error_handler = 1;
4659 (conn->phys_ctx->callbacks.http_error(conn, status, errmsg_buf)
4661 conn->in_error_handler = 0;
4666 if (conn->in_error_handler) {
4668 "Recursion when handling error %u - fall back to default",
4673 error_handler = conn->dom_ctx->config[ERROR_PAGES];
4674 error_page_file_ext = conn->dom_ctx->config[INDEX_FILES];
4678 for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
4684 sizeof(path_buf) - 32,
4691 * for all server errors (500-599) */
4695 sizeof(path_buf) - 32,
4704 sizeof(path_buf) - 32,
4724 * (i < 32) && (len < sizeof(path_buf) - 32)
4726 path_buf[len + i - 1] = tstr[i];
4729 * (i <= 32) && (len < sizeof(path_buf) - 32)
4731 path_buf[len + i - 1] = 0;
4734 DEBUG_TRACE("Check error page %s - found",
4739 DEBUG_TRACE("Check error page %s - not found",
4748 conn->in_error_handler = 1;
4750 conn->in_error_handler = 0;
4759 conn->must_close = 1;
4766 "Content-Type: text/plain; charset=utf-8\r\n");
4812 return -2;
4819 "Content-Type: %s\r\n"
4829 mg_printf(conn, "Transfer-Encoding: chunked\r\n\r\n");
4832 "Content-Length: %" UINT64_FMT "\r\n\r\n",
4850 * 301 | permanent | POST->GET undefined | HTTP/1.0
4851 * 302 | temporary | POST->GET undefined | HTTP/1.0
4871 return -2;
4924 "Content-Length: %u\r\n"
4935 if (0 != strcmp(conn->request_info.request_method, "HEAD")) {
4940 return (ret > 0) ? ret : -1;
4950 #pragma GCC diagnostic ignored "-Wunused-function"
4959 InitializeCriticalSection(&mutex->sec);
4967 DeleteCriticalSection(&mutex->sec);
4975 EnterCriticalSection(&mutex->sec);
4983 LeaveCriticalSection(&mutex->sec);
4993 (void)pthread_mutex_init(&cv->threadIdSec, &pthread_mutex_attr);
4994 cv->waiting_thread = NULL;
5011 pthread_mutex_lock(&cv->threadIdSec);
5013 ptls = &cv->waiting_thread;
5014 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread)
5016 tls->next_waiting_thread = NULL;
5018 pthread_mutex_unlock(&cv->threadIdSec);
5023 (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
5024 nswaitrel = nswaitabs - nsnow;
5035 == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
5038 pthread_mutex_lock(&cv->threadIdSec);
5039 ptls = &cv->waiting_thread;
5040 for (; *ptls != NULL; ptls = &(*ptls)->next_waiting_thread) {
5042 *ptls = tls->next_waiting_thread;
5047 pthread_mutex_unlock(&cv->threadIdSec);
5049 WaitForSingleObject(tls->pthread_cond_helper_mutex,
5056 return ok ? 0 : -1;
5075 pthread_mutex_lock(&cv->threadIdSec);
5076 if (cv->waiting_thread) {
5077 wkup = cv->waiting_thread->pthread_cond_helper_mutex;
5078 cv->waiting_thread = cv->waiting_thread->next_waiting_thread;
5083 pthread_mutex_unlock(&cv->threadIdSec);
5093 pthread_mutex_lock(&cv->threadIdSec);
5094 while (cv->waiting_thread) {
5097 pthread_mutex_unlock(&cv->threadIdSec);
5107 pthread_mutex_lock(&cv->threadIdSec);
5108 DEBUG_ASSERT(cv->waiting_thread == NULL);
5109 pthread_mutex_unlock(&cv->threadIdSec);
5110 pthread_mutex_destroy(&cv->threadIdSec);
5185 diff = ((*s1 >= L'A') && (*s1 <= L'Z') ? (*s1 - L'A' + L'a') : *s1)
5186 - ((*s2 >= L'A') && (*s2 <= L'Z') ? (*s2 - L'A' + L'a') : *s2);
5189 } while ((diff == 0) && (s1[-1] != L'\0'));
5195 /* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
5211 /* Convert to Unicode and back. If doubly-converted string does not
5214 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
5227 * (like /a and /A) - this would be possible in Linux.
5231 if (conn->dom_ctx->config[CASE_SENSITIVE_FILES]
5232 && !mg_strcasecmp(conn->dom_ctx->config[CASE_SENSITIVE_FILES],
5243 long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1);
5284 /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
5291 filep->size = tmp_file.stat.size;
5292 filep->location = 2;
5300 filep->last_modified = time(NULL); /* TODO */
5304 /* last_modified = conn->phys_ctx.start_time;
5317 if ((len > 0) && (path[len - 1] != ' ') && (path[len - 1] != '.')
5319 filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
5320 filep->last_modified =
5326 * Since the Last-Modified timestamp is used for caching
5330 if (creation_time > filep->last_modified) {
5331 filep->last_modified = creation_time;
5334 filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
5348 return DeleteFileW(wbuf) ? 0 : -1;
5358 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
5367 #pragma GCC diagnostic ignored "-Wunused-function"
5390 dir->handle = FindFirstFileW(wpath, &dir->info);
5391 dir->result.d_name[0] = '\0';
5409 if (dir->handle != INVALID_HANDLE_VALUE)
5410 result = FindClose(dir->handle) ? 0 : -1;
5414 result = -1;
5429 if (dir->handle != INVALID_HANDLE_VALUE) {
5430 result = &dir->result;
5433 dir->info.cFileName,
5434 -1,
5435 result->d_name,
5436 sizeof(result->d_name),
5440 if (!FindNextFileW(dir->handle, &dir->info)) {
5441 (void)FindClose(dir->handle);
5442 dir->handle = INVALID_HANDLE_VALUE;
5460 #define POLLIN (1) /* Data ready - read will not block. */
5462 #define POLLOUT (4) /* Send queue not full - write will not block. */
5511 * See http://man7.org/linux/man-pages/man2/select.2.html */
5543 /* Compile-time option to control stack size, e.g.
5544 * -DUSE_STACK_SIZE=16384
5547 == ((uintptr_t)(-1L)))
5548 ? -1
5552 (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L)))
5553 ? -1
5567 int result = -1;
5587 result = -1;
5608 #pragma GCC diagnostic ignored "-Wunused-function"
5632 result = -1;
5684 return (pid_t)-1;
5692 while ((e > s) && isspace((unsigned char)e[-1])) {
5693 *(--e) = '\0';
5748 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
5761 interp = conn->dom_ctx->config[CGI_INTERPRETER];
5770 pi.hProcess = (pid_t)-1;
5782 buf[sizeof(buf) - 1] = '\0';
5819 pi.hProcess = (pid_t)-1;
5837 pi.hProcess = (pid_t)-1;
5888 filep->size = tmp_file.stat.size;
5889 filep->last_modified = time(NULL);
5890 filep->location = 2;
5897 filep->size = (uint64_t)(st.st_size);
5898 filep->last_modified = st.st_mtime;
5899 filep->is_directory = S_ISDIR(st.st_mode);
5944 /* Compile-time option to control stack size,
5945 * e.g. -DUSE_STACK_SIZE=16384 */
5973 /* Compile-time option to control stack size,
5974 * e.g. -DUSE_STACK_SIZE=16384 */
6014 if ((pid = fork()) == -1) {
6018 /* Make sure children close parent-side descriptors.
6019 * The caller will close the child-side immediately. */
6028 } else if (dup2(fdin[0], 0) == -1) {
6034 } else if (dup2(fdout[1], 1) == -1) {
6040 } else if (dup2(fderr[1], 2) == -1) {
6063 * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler
6070 interp = conn->dom_ctx->config[CGI_INTERPRETER];
6101 return -1;
6105 return -1;
6115 return -1;
6119 return -1;
6144 | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
6149 /* Combining two pseudo-random number generators and a high resolution
6174 return -2;
6183 /* Poll returned either success (1) or error (-1).
6190 milliseconds -= ms_now;
6200 /* Write data to the IO channel - opened file descriptor, socket or SSL
6204 * -1 .. timeout
6205 * -2 .. error
6233 return -2;
6238 return -2;
6251 if ((err == SSL_ERROR_SYSCALL) && (n == -1)) {
6258 return -2;
6268 n = -1;
6289 return -2;
6293 if (ctx->stop_flag) {
6294 return -2;
6302 /* socket error - check errno */
6311 return -2;
6328 pollres = mg_poll(pfd, 1, (int)(ms_wait), &(ctx->stop_flag));
6329 if (ctx->stop_flag) {
6330 return -2;
6339 if ((now - start) > timeout_ns) {
6349 return -1;
6361 double timeout = -1.0;
6365 return -1;
6368 if (ctx->dd.config[REQUEST_TIMEOUT]) {
6369 timeout = atoi(ctx->dd.config[REQUEST_TIMEOUT]) / 1000.0;
6372 while ((len > 0) && (ctx->stop_flag == 0)) {
6376 nwritten = -1; /* Propagate the error */
6383 len -= n;
6391 /* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
6394 * -1 .. timeout
6395 * -2 .. error
6434 return -2;
6438 } else if ((conn->ssl != NULL)
6439 && ((ssl_pending = SSL_pending(conn->ssl)) > 0)) {
6440 /* We already know there is no more data buffered in conn->buf
6442 * conn->client.sock yet. */
6446 nread = SSL_read(conn->ssl, buf, ssl_pending);
6448 err = SSL_get_error(conn->ssl, nread);
6449 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
6455 /* All errors should return -2 */
6457 return -2;
6465 } else if (conn->ssl != NULL) {
6470 pfd[0].fd = conn->client.sock;
6475 &(conn->phys_ctx->stop_flag));
6476 if (conn->phys_ctx->stop_flag) {
6477 return -2;
6480 nread = SSL_read(conn->ssl, buf, len);
6482 err = SSL_get_error(conn->ssl, nread);
6483 if ((err == SSL_ERROR_SYSCALL) && (nread == -1)) {
6490 return -2;
6498 return -2;
6509 pfd[0].fd = conn->client.sock;
6514 &(conn->phys_ctx->stop_flag));
6515 if (conn->phys_ctx->stop_flag) {
6516 return -2;
6519 nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
6523 return -2;
6527 return -2;
6534 if (conn->phys_ctx->stop_flag) {
6535 return -2;
6544 /* socket error - check errno */
6549 return -2;
6556 return -2;
6559 return -2;
6563 * if the timeout is reached and if the socket was set to non-
6571 * => should return -1 */
6581 return -2;
6587 return -1;
6595 double timeout = -1.0;
6598 if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
6599 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
6606 while ((len > 0) && (conn->phys_ctx->stop_flag == 0)) {
6608 if (n == -2) {
6610 nread = -1; /* Propagate the error */
6613 } else if (n == -1) {
6617 if ((now - start_time) <= timeout_ns) {
6626 len -= n;
6658 /* If Content-Length is not set for a response with body data,
6660 content_len = conn->content_len;
6667 if (conn->consumed_content < content_len) {
6669 int64_t left_to_read = content_len - conn->consumed_content;
6678 buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
6679 - conn->consumed_content;
6684 body = conn->buf + conn->request_len + conn->consumed_content;
6686 len64 -= buffered_len;
6687 conn->consumed_content += buffered_len;
6696 conn->consumed_content += n;
6717 if (conn->is_chunked) {
6721 if (conn->is_chunked >= 3) {
6725 if (conn->is_chunked != 1) {
6727 return -1;
6730 if (conn->consumed_content != conn->content_len) {
6736 conn->is_chunked = 2;
6737 return -1;
6741 len -= (size_t)read_ret;
6743 if (conn->consumed_content == conn->content_len) {
6747 conn->content_len += 2;
6751 conn->is_chunked = 2;
6752 return -1;
6763 for (i = 0; i < (sizeof(lenbuf) - 1); i++) {
6764 conn->content_len++;
6769 && (lenbuf[i - 1] != '\r')) {
6773 && (lenbuf[i - 1] == '\r')) {
6778 conn->is_chunked = 3;
6784 conn->is_chunked = 2;
6785 return -1;
6790 conn->is_chunked = 2;
6791 return -1;
6794 /* try discarding trailer for keep-alive */
6795 conn->content_len += 2;
6798 conn->is_chunked = 4;
6804 conn->content_len += chunkSize;
6824 return -1;
6827 if (conn->throttle > 0) {
6828 if ((now = time(NULL)) != conn->last_throttle_time) {
6829 conn->last_throttle_time = now;
6830 conn->last_throttle_bytes = 0;
6832 allowed = conn->throttle - conn->last_throttle_bytes;
6836 if ((total = push_all(conn->phys_ctx,
6838 conn->client.sock,
6839 conn->ssl,
6844 conn->last_throttle_bytes += total;
6845 while ((total < (int)len) && (conn->phys_ctx->stop_flag == 0)) {
6846 allowed = (conn->throttle > ((int)len - total))
6847 ? (int)len - total
6848 : conn->throttle;
6849 if ((n = push_all(conn->phys_ctx,
6851 conn->client.sock,
6852 conn->ssl,
6859 conn->last_throttle_bytes = allowed;
6860 conn->last_throttle_time = time(NULL);
6866 total = push_all(conn->phys_ctx,
6868 conn->client.sock,
6869 conn->ssl,
6874 conn->num_bytes_sent += total;
6880 /* Send a chunk, if "Transfer-Encoding: chunked" is used */
6898 return -1;
6904 return -1;
6910 return -1;
6920 * so we need to disable the format-nonliteral warning. */
6922 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
6926 /* Alternative alloc_vprintf() for non-compliant C runtimes */
6932 int len = -1;
6947 len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy);
6949 (*buf)[size - 1] = 0;
6970 /* Windows is not standard-compliant, and vsnprintf() returns -1 if
6981 /* C runtime is not standard compliant, vsnprintf() returned -1.
6990 /* The pre-allocated buffer not large enough. */
6994 /* Allocation failed. Return -1 as "out of memory" error. */
6995 return -1;
7004 /* The pre-allocated buffer is large enough.
7018 /* Enable format-nonliteral warning again. */
7063 #define HEXTOI(x) (isdigit(x) ? (x - '0') : (x - 'W'))
7065 for (i = j = 0; (i < src_len) && (j < (dst_len - 1)); i++, j++) {
7066 if ((i < src_len - 2) && (src[i] == '%')
7080 dst[j] = '\0'; /* Null-terminate the destination */
7082 return (i >= src_len) ? j : -1;
7110 len = -2;
7112 len = -1;
7117 len = -1;
7122 if (((p == data) || (p[-1] == '&')) && (p[name_len] == '=')
7123 && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
7128 s = (const char *)memchr(p, '&', (size_t)(e - p));
7134 return -3;
7138 len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
7140 /* Redirect error code from -1 to -2 (destination buffer too
7142 if (len == -1) {
7143 len = -2;
7162 int name_len, len = -1;
7165 return -2;
7170 return -1;
7178 if ((s == cookie_header) || (s[-1] == ' ')) {
7183 if (p[-1] == ';') {
7184 p--;
7186 if ((*s == '"') && (p[-1] == '"') && (p > s + 1)) {
7188 p--;
7190 if ((size_t)(p - s) < dst_size) {
7191 len = (int)(p - s);
7194 len = -3;
7212 for (i = j = 0; i < src_len; i += 3) {
7218 dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
7239 return letter - 'A';
7242 return letter - 'a' + 26;
7245 return letter - '0' + 52;
7284 d = b64reverse(((i + 3) >= src_len) ? 0 : src[i + 3]);
7286 return i + 3;
7297 return -1;
7306 const char *s = conn->request_info.request_method;
7323 if (match_prefix(conn->dom_ctx->config[CGI_EXTENSIONS],
7324 strlen(conn->dom_ctx->config[CGI_EXTENSIONS]),
7331 if (match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
7332 strlen(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
7339 if (match_prefix(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
7340 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
7364 const char *list = conn->dom_ctx->config[INDEX_FILES];
7372 while ((n > 0) && (path[n - 1] == '/')) {
7373 n--;
7381 if ((filename_vec.len + 1) > (path_len - (n + 1))) {
7420 const char *uri = conn->request_info.local_uri;
7421 const char *root = conn->dom_ctx->config[DOCUMENT_ROOT];
7445 /* Step 3: Check if it is a websocket request, and modify the document
7450 if (*is_websocket_request && conn->dom_ctx->config[WEBSOCKET_ROOT]) {
7451 root = conn->dom_ctx->config[WEBSOCKET_ROOT];
7459 conn->accept_gzip = 0;
7460 if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
7462 conn->accept_gzip = 1;
7479 /* Using filename_buf_len - 1 because memmove() for PATH_INFO may shift
7482 conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
7489 rewrite = conn->dom_ctx->config[URL_REWRITE_PATTERN];
7495 filename_buf_len - 1,
7513 int is_uri_end_slash = (uri_len > 0) && (uri[uri_len - 1] == '/');
7521 * server-side javascript.
7536 if (filestat->is_directory && is_uri_end_slash) {
7568 * to indicate that the response need to have the content-
7571 if (conn->accept_gzip) {
7581 filestat->is_gzipped = 1;
7590 /* Step 10: Script resources may handle sub-resources */
7593 tmp_str = (char *)mg_malloc_ctx(tmp_str_len + PATH_MAX + 1, conn->phys_ctx);
7600 /* Check config, if index scripts may have sub-resources */
7602 !mg_strcasecmp(conn->dom_ctx->config[ALLOW_INDEX_SCRIPT_SUB_RES],
7607 sep_pos--;
7622 conn->path_info = filename + sep_pos + 1;
7644 conn->phys_ctx);
7660 conn->path_info = filename + sep_pos + 1;
7671 /* non-script files will not have sub-resources */
7673 conn->path_info = 0;
7705 * -1 if request or response is malformed
7719 return -1;
7722 if (i < buflen - 1) {
7724 /* Two newline, no carriage return - not standard compliant,
7732 if (i < buflen - 3) {
7734 && (buf[i + 3] == '\n')) {
7735 /* Two \r\n - standard compliant */
7746 /* Convert month to the month number. Return -1 on error, or month number */
7758 return -1;
7762 /* Parse UTC date-time string, and return the corresponding time_t value. */
7772 "%d/%3s/%d %d:%d:%d",
7781 "%d %3s %d %d:%d:%d",
7790 "%*3s, %d %3s %d %d:%d:%d",
7799 "%d-%3s-%d %d:%d:%d",
7810 tm.tm_year = year - 1900;
7838 if ((s[-1] == '/') || (s[-1] == '\\')) {
7839 /* Skip all following slashes, backslashes and double-dots */
7861 * (http://www.iana.org/assignments/media-types)
7865 {".exe", 4, "application/octet-stream"},
7866 {".js", 3, "application/javascript"},
7869 {".ps", 3, "application/postscript"},
7876 {".ttf", 4, "application/font-sfnt"},
7877 {".cff", 4, "application/font-sfnt"},
7878 {".otf", 4, "application/font-sfnt"},
7879 {".aat", 4, "application/font-sfnt"},
7880 {".sil", 4, "application/font-sfnt"},
7881 {".pfr", 4, "application/font-tdpfr"},
7882 {".woff", 5, "application/font-woff"},
7921 {".qt", 3, "video/quicktime"},
7924 * (http://reference.sitepoint.com/html/mime-types-full,
7926 {".arj", 4, "application/x-arj-compressed"},
7927 {".gz", 3, "application/x-gunzip"},
7928 {".rar", 4, "application/x-arj-compressed"},
7929 {".swf", 4, "application/x-shockwave-flash"},
7930 {".tar", 4, "application/x-tar"},
7931 {".tgz", 4, "application/x-tar-gz"},
7932 {".torrent", 8, "application/x-bittorrent"},
7933 {".ppt", 4, "application/x-mspowerpoint"},
7934 {".xls", 4, "application/x-msexcel"},
7935 {".zip", 4, "application/x-zip-compressed"},
7939 {".aif", 4, "audio/x-aif"},
7940 {".m3u", 4, "audio/x-mpegurl"},
7941 {".mid", 4, "audio/x-midi"},
7942 {".ra", 3, "audio/x-pn-realaudio"},
7943 {".ram", 4, "audio/x-pn-realaudio"},
7944 {".wav", 4, "audio/x-wav"},
7946 {".ico", 4, "image/x-icon"},
7947 {".pct", 4, "image/x-pct"},
7949 {".rgb", 4, "image/x-rgb"},
7951 {".asf", 4, "video/x-ms-asf"},
7952 {".avi", 4, "video/x-msvideo"},
7953 {".m4v", 4, "video/x-m4v"},
7966 ext = path + (path_len - builtin_mime_types[i].ext_len);
7995 /* Scan user-defined mime types first, in case user wants to
7997 list = conn->dom_ctx->config[EXTRA_MIME_TYPES];
8000 ext = path + path_len - ext_vec.len;
8007 vec->ptr = mg_get_builtin_mime_type(path);
8008 vec->len = strlen(vec->ptr);
8019 for (; len--; p++) {
8102 if ((conn != NULL) && (conn->dom_ctx != NULL)) {
8105 *gpass = conn->dom_ctx->config[GLOBAL_PASSWORDS_FILE];
8121 } else if (mg_stat(conn, path, &filep->stat)
8122 && filep->stat.is_directory) {
8142 for (p = path, e = p + strlen(p) - 1; e > p; e--) {
8152 (int)(e - p),
8209 /* Value is either quote-delimited, or ends at first comma or space.
8226 ah->user = value;
8228 ah->cnonce = value;
8230 ah->response = value;
8232 ah->uri = value;
8234 ah->qop = value;
8236 ah->nc = value;
8238 ah->nonce = value;
8244 if (ah->nonce == NULL) {
8248 nonce = strtoull(ah->nonce, &s, 10);
8254 nonce ^= conn->dom_ctx->auth_nonce_mask;
8264 if (nonce < (uint64_t)conn->phys_ctx->start_time) {
8271 if (nonce >= ((uint64_t)conn->phys_ctx->start_time
8272 + conn->dom_ctx->nonce_count)) {
8280 if (ah->user != NULL) {
8281 conn->request_info.remote_user =
8282 mg_strdup_ctx(ah->user, conn->phys_ctx);
8307 if ((filep->access.membuf != NULL) && (*p != NULL)) {
8308 memend = (const char *)&filep->access.membuf[filep->stat.size];
8310 eof = (char *)memchr(*p, '\n', (size_t)(memend - *p));
8317 ((size_t)(eof - *p) > (size - 1)) ? (size - 1) : (size_t)(eof - *p);
8322 } else /* filep->access.fp block below */
8324 if (filep->access.fp != NULL) {
8325 return fgets(buf, (int)size, filep->access.fp);
8370 p = (char *)filep->access.membuf;
8372 while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) {
8373 l = strlen(workdata->buf);
8375 if (isspace((unsigned char)workdata->buf[l - 1])
8376 || iscntrl((unsigned char)workdata->buf[l - 1])) {
8377 l--;
8378 workdata->buf[l] = 0;
8386 workdata->f_user = workdata->buf;
8388 if (workdata->f_user[0] == ':') {
8392 if (workdata->f_user[1] == '#') {
8395 } else if (!strncmp(workdata->f_user + 1, "include=", 8)) {
8396 if (mg_fopen(workdata->conn,
8397 workdata->f_user + 9,
8400 is_authorized = read_auth_file(&fp, workdata, depth - 1);
8412 mg_cry_internal(workdata->conn,
8415 workdata->buf);
8421 mg_cry_internal(workdata->conn,
8424 workdata->buf);
8428 workdata->f_domain = strchr(workdata->f_user, ':');
8429 if (workdata->f_domain == NULL) {
8430 mg_cry_internal(workdata->conn,
8433 workdata->buf);
8436 *(char *)(workdata->f_domain) = 0;
8437 (workdata->f_domain)++;
8439 workdata->f_ha1 = strchr(workdata->f_domain, ':');
8440 if (workdata->f_ha1 == NULL) {
8441 mg_cry_internal(workdata->conn,
8444 workdata->buf);
8447 *(char *)(workdata->f_ha1) = 0;
8448 (workdata->f_ha1)++;
8450 if (!strcmp(workdata->ah.user, workdata->f_user)
8451 && !strcmp(workdata->domain, workdata->f_domain)) {
8452 return check_password(workdata->conn->request_info.request_method,
8453 workdata->f_ha1,
8454 workdata->ah.uri,
8455 workdata->ah.nonce,
8456 workdata->ah.nc,
8457 workdata->ah.cnonce,
8458 workdata->ah.qop,
8459 workdata->ah.response);
8474 if (!conn || !conn->dom_ctx) {
8488 workdata.domain = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
8505 return -1;
8508 return -2;
8531 if (!conn || !conn->dom_ctx) {
8535 list = conn->dom_ctx->config[PROTECT_URI];
8537 if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
8582 uint64_t nonce = (uint64_t)(conn->phys_ctx->start_time);
8585 realm = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
8588 (void)pthread_mutex_lock(&conn->phys_ctx->nonce_mutex);
8589 nonce += conn->dom_ctx->nonce_count;
8590 ++conn->dom_ctx->nonce_count;
8591 (void)pthread_mutex_unlock(&conn->phys_ctx->nonce_mutex);
8593 nonce ^= conn->dom_ctx->auth_nonce_mask;
8594 conn->status_code = 401;
8595 conn->must_close = 1;
8605 "Content-Length: 0\r\n"
8606 "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
8622 if (conn && conn->dom_ctx) {
8626 return -1;
8636 const char *passfile = conn->dom_ctx->config[PUT_DELETE_PASSWORDS_FILE];
8665 /* Regard empty password as no password - remove user record. */
8788 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
8796 if (dstlen >= (size_t)res->ai_addrlen) {
8797 memcpy(dst, res->ai_addr, res->ai_addrlen);
8800 res = res->ai_next;
8820 int conn_ret = -1;
8880 if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) {
8881 sa->sin.sin_family = AF_INET;
8882 sa->sin.sin_port = htons((uint16_t)port);
8885 } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) {
8886 sa->sin6.sin6_family = AF_INET6;
8887 sa->sin6.sin6_port = htons((uint16_t)port);
8895 h[l - 1] = 0;
8896 if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) {
8897 sa->sin6.sin6_family = AF_INET6;
8898 sa->sin6.sin6_port = htons((uint16_t)port);
8940 "Cannot set socket to non-blocking: %s",
8952 (struct sockaddr *)((void *)&sa->sin),
8953 sizeof(sa->sin));
8959 (struct sockaddr *)((void *)&sa->sin6),
8960 sizeof(sa->sin6));
8989 /* For a non-blocking socket, the connect sequence is:
8992 * 3) check connection state with getsockopt
8996 pollres = mg_poll(pfd, 1, ms_wait, ctx ? &(ctx->stop_flag) : &nonstop);
9045 static const char *dont_escape = "._-$,;~()";
9048 const char *end = dst + dst_len - 1;
9065 return (*src == '\0') ? (int)(pos - dst) : -1;
9068 /* Return 0 on success, non-zero if an error occurs. */
9084 namesize = strlen(de->file_name) + 1;
9085 escsize = de->file_name[strcspn(de->file_name, "&<>")] ? namesize * 5 : 0;
9086 href = (char *)mg_malloc(namesize * 3 + escsize);
9088 return -1;
9090 mg_url_encode(de->file_name, href, namesize * 3);
9094 esc = href + namesize * 3;
9095 for (i = 0, p = esc; de->file_name[i]; i++, p += strlen(p)) {
9096 mg_strlcpy(p, de->file_name + i, 2);
9107 if (de->file.is_directory) {
9108 mg_snprintf(de->conn,
9117 if (de->file.size < 1024) {
9118 mg_snprintf(de->conn,
9123 (int)de->file.size);
9124 } else if (de->file.size < 0x100000) {
9125 mg_snprintf(de->conn,
9130 (double)de->file.size / 1024.0);
9131 } else if (de->file.size < 0x40000000) {
9132 mg_snprintf(de->conn,
9137 (double)de->file.size / 1048576);
9139 mg_snprintf(de->conn,
9144 (double)de->file.size / 1073741824);
9152 localtime_r(&de->file.last_modified, tm);
9154 tm = localtime(&de->file.last_modified);
9157 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
9159 mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
9160 mod[sizeof(mod) - 1] = '\0';
9162 mg_printf(de->conn,
9166 de->file.is_directory ? "/" : "",
9167 esc ? esc : de->file_name,
9168 de->file.is_directory ? "/" : "",
9185 const char *query_string = a->conn->request_info.query_string;
9192 if (a->file.is_directory && !b->file.is_directory) {
9193 return -1; /* Always put directories on top */
9194 } else if (!a->file.is_directory && b->file.is_directory) {
9197 cmp_result = strcmp(a->file_name, b->file_name);
9199 cmp_result = (a->file.size == b->file.size)
9201 : ((a->file.size > b->file.size) ? 1 : -1);
9204 (a->file.last_modified == b->file.last_modified)
9206 : ((a->file.last_modified > b->file.last_modified) ? 1
9207 : -1);
9210 return (query_string[1] == 'd') ? -cmp_result : cmp_result;
9219 if (conn && conn->dom_ctx) {
9221 const char *pattern = conn->dom_ctx->config[HIDE_FILES];
9250 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
9251 || must_hide_file(conn, dp->d_name)) {
9256 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
9277 de.file_name = dp->d_name;
9306 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
9311 conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
9381 if ((dsd->entries == NULL) || (dsd->num_entries >= dsd->arr_size)) {
9382 dsd->arr_size *= 2;
9383 dsd->entries =
9384 (struct de *)realloc2(dsd->entries,
9385 dsd->arr_size * sizeof(dsd->entries[0]));
9387 if (dsd->entries == NULL) {
9389 dsd->num_entries = 0;
9391 dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
9392 dsd->entries[dsd->num_entries].file = de->file;
9393 dsd->entries[dsd->num_entries].conn = de->conn;
9394 dsd->num_entries++;
9427 title = conn->request_info.local_uri;
9447 sort_direction = ((conn->request_info.query_string != NULL)
9448 && (conn->request_info.query_string[0] != '\0')
9449 && (conn->request_info.query_string[1] == 'd'))
9453 conn->must_close = 1;
9460 "Content-Type: text/html; charset=utf-8\r\n\r\n",
9464 "<style>th {text-align: left;}</style></head>"
9469 "<tr><td colspan=\"3\"><hr></td></tr>",
9477 /* Print first entry - link to a parent directory */
9483 "-",
9484 "-");
9500 conn->status_code = 200;
9521 size = (filep->stat.size > INT64_MAX) ? INT64_MAX
9522 : (int64_t)(filep->stat.size);
9526 if ((len > 0) && (filep->access.membuf != NULL) && (size > 0)) {
9528 if (len > size - offset) {
9529 len = size - offset;
9531 mg_write(conn, filep->access.membuf + offset, (size_t)len);
9534 if (len > 0 && filep->access.fp != NULL) {
9538 if ((conn->ssl == 0) && (conn->throttle == 0)
9539 && (!mg_strcasecmp(conn->dom_ctx->config[ALLOW_SENDFILE_CALL],
9543 int sf_file = fileno(filep->access.fp);
9552 sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
9554 len -= sf_sent;
9558 * This might be the case for pseudo-files in the
9580 if ((offset > 0) && (fseeko(filep->access.fp, offset, SEEK_SET) != 0)) {
9600 (int)fread(buf, 1, (size_t)to_read, filep->access.fp))
9612 len -= num_written;
9622 return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
9635 (unsigned long)filestat->last_modified,
9636 filestat->size);
9644 if (filep != NULL && filep->fp != NULL) {
9648 if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
9694 if ((conn == NULL) || (conn->dom_ctx == NULL) || (filep == NULL)) {
9698 is_head_request = !strcmp(conn->request_info.request_method, "HEAD");
9706 if (filep->stat.size > INT64_MAX) {
9710 filep->stat.size);
9713 cl = (int64_t)filep->stat.size;
9714 conn->status_code = 200;
9718 /* if this file is in fact a pre-gzipped file, rewrite its filename
9721 if (!conn->accept_gzip) {
9730 if (filep->stat.is_gzipped) {
9742 encoding = "Content-Encoding: gzip\r\n";
9748 } else if ((conn->accept_gzip) && (range_hdr == NULL)
9749 && (filep->stat.size >= MG_FILE_COMPRESSION_SIZE_LIMIT)) {
9757 filep->stat = file_stat;
9758 cl = (int64_t)filep->stat.size;
9760 encoding = "Content-Encoding: gzip\r\n";
9778 fclose_on_exec(&filep->access, conn);
9786 /* actually, range requests don't play well with a pre-gzipped
9788 if (filep->stat.is_gzipped) {
9795 &filep->access); /* ignore error on read only file */
9798 conn->status_code = 206;
9799 cl = (n == 2) ? (((r2 > cl) ? cl : r2) - r1 + 1) : (cl - r1);
9804 "Content-Range: bytes "
9805 "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
9807 r1 + cl - 1,
9808 filep->stat.size);
9820 if (filep->stat.size < MG_FILE_COMPRESSION_SIZE_LIMIT) {
9827 cors_orig_cfg = conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
9830 /* Cross-origin resource sharing (CORS), see
9833 * -
9835 cors1 = "Access-Control-Allow-Origin: ";
9842 /* Prepare Etag, Date, Last-Modified headers. Must be in UTC,
9844 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
9846 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
9847 construct_etag(etag, sizeof(etag), &filep->stat);
9854 "Last-Modified: %s\r\n"
9856 "Content-Type: %.*s\r\n"
9858 conn->status_code,
9878 "Content-Encoding: gzip\r\n"
9879 "Transfer-Encoding: chunked\r\n");
9883 /* Without on-the-fly compression, we know the content-length
9884 * and we can use ranges (with on-the-fly compression we cannot).
9887 "Content-Length: %" INT64_FMT "\r\n"
9888 "Accept-Ranges: bytes\r\n"
9896 /* The previous code must not add any header starting with X- to make
9919 (void)mg_fclose(&filep->access); /* ignore error on read only file */
9928 return -1;
9945 const char *ims = mg_get_header(conn, "If-Modified-Since");
9946 const char *inm = mg_get_header(conn, "If-None-Match");
9951 && (filestat->last_modified <= parse_date_string(ims)));
9964 conn->status_code = 304;
9966 gmt_time_string(lm, sizeof(lm), &filep->stat.last_modified);
9967 construct_etag(etag, sizeof(etag), &filep->stat);
9972 conn->status_code,
9973 mg_get_response_code_text(conn, conn->status_code),
9978 "Last-Modified: %s\r\n"
10022 /* Send 304 "Not Modified" - this must not send any body data */
10027 if (!mg_strcasecmp(conn->dom_ctx->config[ENABLE_DIRECTORY_LISTING],
10049 * Return -1 for if the path is too long.
10050 * Return -2 if path can not be created.
10062 len = (size_t)(p - path);
10065 res = -1;
10075 res = -2;
10110 if (conn->consumed_content != 0) {
10112 return -11;
10117 /* -1 for path too long,
10118 * -2 for path can not be created. */
10127 return -12;
10137 return -13;
10148 return -14;
10163 /* Forward until a space is found - use isgraph here */
10173 return -1;
10178 return -1;
10192 return -1;
10224 return -1;
10251 return -1;
10287 /* https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods */
10329 * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
10335 * (https://tools.ietf.org/html/rfc3253#section-3.6), but seems
10349 * http://www.iana.org/assignments/http-methods/http-methods.xhtml
10353 while (m->name) {
10354 if (!strcmp(m->name, method)) {
10371 * This function modifies the buffer by NUL-terminating
10387 ri->remote_user = ri->request_method = ri->request_uri = ri->http_version =
10389 ri->num_headers = 0;
10396 len--;
10407 return -1;
10415 buf[request_length - 1] = '\0';
10418 return -1;
10422 ri->request_method = buf;
10425 return -1;
10429 if (!is_valid_http_method(ri->request_method)) {
10430 return -1;
10434 ri->request_uri = buf;
10437 return -1;
10441 ri->http_version = buf;
10444 return -1;
10448 if (strncmp(ri->http_version, "HTTP/", 5) != 0) {
10450 return -1;
10452 ri->http_version += 5;
10456 ri->num_headers = parse_http_headers(&buf, ri->http_headers);
10457 if (ri->num_headers < 0) {
10459 return -1;
10475 ri->http_version = ri->status_text = NULL;
10476 ri->num_headers = ri->status_code = 0;
10483 len--;
10494 return -1;
10502 buf[response_length - 1] = '\0';
10505 return -1;
10512 return -1;
10517 return -1;
10519 ri->http_version = buf;
10522 return -1;
10529 return -1;
10533 if ((l < 100) || (l >= 1000) || ((tmp2 - tmp) != 3) || (*tmp2 != 0)) {
10534 /* Everything else but a 3 digit code is invalid */
10535 return -1;
10537 ri->status_code = (int)l;
10540 ri->status_text = buf;
10548 return -1;
10558 ri->num_headers = parse_http_headers(&buf, ri->http_headers);
10559 if (ri->num_headers < 0) {
10561 return -1;
10590 if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
10592 request_timeout = atof(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
10594 request_timeout = -1.0;
10596 if (conn->handled_requests > 0) {
10597 if (conn->dom_ctx->config[KEEP_ALIVE_TIMEOUT]) {
10599 atof(conn->dom_ctx->config[KEEP_ALIVE_TIMEOUT]) / 1000.0;
10607 if (conn->phys_ctx->stop_flag != 0) {
10609 return -1;
10614 return -2;
10618 fp, conn, buf + *nread, bufsiz - *nread, request_timeout);
10619 if (n == -2) {
10621 return -1;
10635 if (mg_difftimespec(&last_action_time, &(conn->req_time))
10638 return -1;
10666 if ((expect != NULL) && (mg_strcasecmp(expect, "100-continue") != 0)) {
10667 /* Client sent an "Expect: xyz" header and xyz is not 100-continue.
10673 conn->status_code = 100;
10675 conn->status_code = 200;
10678 DEBUG_ASSERT(conn->consumed_content == 0);
10680 if (conn->consumed_content != 0) {
10691 if (push_all(conn->phys_ctx, fp, sock, ssl, buf, nread) != nread) {
10744 ...) PRINTF_ARGS(2, 3);
10756 if ((env->varlen - env->varused) < 2) {
10757 mg_cry_internal(env->conn,
10765 space = (env->buflen - env->bufused);
10771 n = env->buflen + CGI_ENVIRONMENT_SIZE;
10772 added = (char *)mg_realloc_ctx(env->buf, n, env->conn->phys_ctx);
10776 env->conn,
10783 env->buf = added;
10784 env->buflen = n;
10785 for (i = 0, n = 0; i < env->varused; i++) {
10786 env->var[i] = added + n;
10789 space = (env->buflen - env->bufused);
10793 added = env->buf + env->bufused;
10797 mg_vsnprintf(env->conn, &truncated, added, space - 1, fmt, ap);
10809 env->bufused += n;
10812 env->var[env->varused] = added;
10813 env->varused++;
10816 /* Return 0 on success, non-zero if an error occurs. */
10829 return -1;
10832 env->conn = conn;
10833 env->buflen = CGI_ENVIRONMENT_SIZE;
10834 env->bufused = 0;
10835 env->buf = (char *)mg_malloc_ctx(env->buflen, conn->phys_ctx);
10836 if (env->buf == NULL) {
10840 return -1;
10842 env->varlen = MAX_CGI_ENVIR_VARS;
10843 env->varused = 0;
10844 env->var =
10845 (char **)mg_malloc_ctx(env->varlen * sizeof(char *), conn->phys_ctx);
10846 if (env->var == NULL) {
10850 mg_free(env->buf);
10851 return -1;
10854 addenv(env, "SERVER_NAME=%s", conn->dom_ctx->config[AUTHENTICATION_DOMAIN]);
10855 addenv(env, "SERVER_ROOT=%s", conn->dom_ctx->config[DOCUMENT_ROOT]);
10856 addenv(env, "DOCUMENT_ROOT=%s", conn->dom_ctx->config[DOCUMENT_ROOT]);
10865 if (conn->client.lsa.sa.sa_family == AF_INET6) {
10866 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
10870 addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
10873 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
10876 addenv(env, "REQUEST_METHOD=%s", conn->request_info.request_method);
10877 addenv(env, "REMOTE_PORT=%d", conn->request_info.remote_port);
10879 addenv(env, "REQUEST_URI=%s", conn->request_info.request_uri);
10880 addenv(env, "LOCAL_URI=%s", conn->request_info.local_uri);
10883 uri_len = (int)strlen(conn->request_info.local_uri);
10884 if (conn->path_info == NULL) {
10885 if (conn->request_info.local_uri[uri_len - 1] != '/') {
10887 addenv(env, "SCRIPT_NAME=%s", conn->request_info.local_uri);
10894 conn->request_info.local_uri,
10902 uri_len - (int)strlen(conn->path_info),
10903 conn->request_info.local_uri);
10907 if (conn->path_info == NULL) {
10908 addenv(env, "PATH_TRANSLATED=%s", conn->dom_ctx->config[DOCUMENT_ROOT]);
10912 conn->dom_ctx->config[DOCUMENT_ROOT],
10913 conn->path_info);
10916 addenv(env, "HTTPS=%s", (conn->ssl == NULL) ? "off" : "on");
10918 if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
10921 if (conn->request_info.query_string != NULL) {
10922 addenv(env, "QUERY_STRING=%s", conn->request_info.query_string);
10924 if ((s = mg_get_header(conn, "Content-Length")) != NULL) {
10930 if (conn->path_info != NULL) {
10931 addenv(env, "PATH_INFO=%s", conn->path_info);
10934 if (conn->status_code > 0) {
10936 addenv(env, "STATUS=%d", conn->status_code);
10965 if (conn->request_info.remote_user != NULL) {
10966 addenv(env, "REMOTE_USER=%s", conn->request_info.remote_user);
10971 for (i = 0; i < conn->request_info.num_headers; i++) {
10978 conn->request_info.http_headers[i].name);
10984 conn->request_info.http_headers[i].name);
10988 /* Convert variable name into uppercase, and change - to _ */
10990 if (*p == '-') {
10999 conn->request_info.http_headers[i].value);
11002 /* Add user-specified variables */
11003 s = conn->dom_ctx->config[CGI_ENVIRONMENT];
11008 env->var[env->varused] = NULL;
11009 env->buf[env->bufused] = '\0';
11032 ret_pid = waitpid(proc->pid, &status, WNOHANG);
11033 if ((ret_pid != (pid_t)-1) && (status == 0)) {
11035 DEBUG_TRACE("CGI timer: Stop child process %d\n", proc->pid);
11036 kill(proc->pid, SIGABRT);
11039 while (waitpid(proc->pid, &status, 0) != (pid_t)-1) /* nop */
11042 DEBUG_TRACE("CGI timer: Child process %d already stopped\n", proc->pid);
11045 refs = mg_atomic_dec(&proc->references);
11047 /* no more references - free data */
11062 int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
11069 pid_t pid = (pid_t)-1;
11073 double cgi_timeout = -1.0;
11074 if (conn->dom_ctx->config[CGI_TIMEOUT]) {
11076 cgi_timeout = atof(conn->dom_ctx->config[CGI_TIMEOUT]) * 0.001;
11081 buflen = conn->phys_ctx->max_request_size;
11123 mg_malloc_ctx(sizeof(struct process_control_data), conn->phys_ctx);
11133 if (pid == (pid_t)-1) {
11151 proc->pid = pid;
11152 proc->references = 1;
11156 proc->references = 2;
11159 timer_add(conn->phys_ctx,
11175 fdin[0] = fdout[1] = fderr[1] = -1;
11197 if ((conn->content_len != 0) || (conn->is_chunked)) {
11199 conn->content_len);
11215 fdin[1] = -1;
11222 buf = (char *)mg_malloc_ctx(buflen, conn->phys_ctx);
11284 buf[headers_len - 1] = '\0';
11291 conn->status_code = atoi(status);
11298 conn->status_code = 307;
11300 conn->status_code = 200;
11304 if (!header_has_option(connection_state, "keep-alive")) {
11305 conn->must_close = 1;
11308 DEBUG_TRACE("CGI: response %u %s", conn->status_code, status_text);
11310 (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
11325 mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
11336 if (pid != (pid_t)-1) {
11340 if (fdin[0] != -1) {
11343 if (fdout[1] != -1) {
11346 if (fderr[1] != -1) {
11352 } else if (fdin[1] != -1) {
11358 } else if (fdout[0] != -1) {
11364 } else if (fderr[0] != -1) {
11407 body_len = conn->data_len - conn->request_len;
11417 conn->status_code = 201;
11422 conn->status_code,
11427 "Content-Length: 0\r\n"
11464 conn->status_code = 200;
11477 /* This is an "in-memory" file, that can not be replaced */
11490 conn->status_code = 200;
11503 conn->status_code = 201;
11512 conn->status_code,
11513 mg_get_response_code_text(NULL, conn->status_code));
11518 "Content-Length: 0\r\n"
11528 if (rc == -1) {
11529 /* put_dir returns -1 if the path is too long */
11538 if (rc == -2) {
11539 /* put_dir returns -2 if the directory can not be created */
11562 range = mg_get_header(conn, "Content-Range");
11565 conn->status_code = 206; /* Partial content */
11572 * and conn->status_code is already set. */
11580 conn->status_code = 507;
11586 conn->status_code,
11587 mg_get_response_code_text(NULL, conn->status_code));
11592 "Content-Length: 0\r\n"
11695 conn->dom_ctx->config[DOCUMENT_ROOT],
11719 sizeof(path) - len,
11742 if (match_prefix(conn->dom_ctx->config[SSI_EXTENSIONS],
11743 strlen(conn->dom_ctx->config[SSI_EXTENSIONS]),
11789 if ((filep->access.membuf != NULL) && (offset >= 0)
11790 && (((unsigned int)(offset)) < filep->stat.size)) {
11791 return ((const unsigned char *)filep->access.membuf)[offset];
11794 if (filep->access.fp != NULL) {
11795 return fgetc(filep->access.fp);
11860 if ((len == 5) && !memcmp(buf, "<!--#", 5)) {
11861 /* All SSI tags start with <!--# */
11922 cors_orig_cfg = conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
11924 /* Cross-origin resource sharing (CORS). */
11925 cors1 = "Access-Control-Allow-Origin: ";
11941 conn->must_close = 1;
11943 fclose_on_exec(&filep->access, conn);
11950 "Content-Type: text/html\r\n"
11958 (void)mg_fclose(&filep->access); /* Ignore errors for readonly files */
11975 conn->status_code = 200;
11976 conn->must_close = 1;
11979 /* We do not set a "Cache-Control" header here, but leave the default.
12011 href_size = (strlen(uri) + strlen(name)) * 3 + 1;
12019 mg_url_encode(name, href + len, href_size - (size_t)len);
12023 if (!strncmp(href + i, "%2f", 3)) {
12025 i += 3;
12032 gmt_time_string(mtime, sizeof(mtime), &filep->last_modified);
12046 filep->is_directory ? "<d:collection/>" : "",
12047 filep->size,
12060 conn, conn->request_info.local_uri, de->file_name, &de->file)) {
12061 return -1;
12078 if (!conn || !path || !filep || !conn->dom_ctx) {
12082 conn->must_close = 1;
12083 conn->status_code = 207;
12085 "HTTP/1.1 207 Multi-Status\r\n"
12092 "Content-Type: text/xml; charset=utf-8\r\n\r\n",
12096 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
12100 print_props(conn, conn->request_info.local_uri, "", filep);
12104 if (filep->is_directory
12105 && !mg_strcasecmp(conn->dom_ctx->config[ENABLE_DIRECTORY_LISTING],
12119 (void)pthread_mutex_lock(&conn->mutex);
12127 (void)pthread_mutex_unlock(&conn->mutex);
12135 (void)pthread_mutex_lock(&ctx->nonce_mutex);
12143 (void)pthread_mutex_unlock(&ctx->nonce_mutex);
12166 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
12171 /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
12174 conn->must_close = 1;
12188 "Sec-WebSocket-Accept: %s\r\n",
12190 if (conn->request_info.acceptedWebSocketSubprotocol) {
12192 "Sec-WebSocket-Protocol: %s\r\n\r\n",
12193 conn->request_info.acceptedWebSocketSubprotocol);
12221 unsigned char *buf = (unsigned char *)conn->buf + conn->request_len;
12232 /* "The masking key is a 32-bit value chosen at random by the client."
12233 * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
12245 double timeout = -1.0;
12249 if (conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG]) {
12251 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_WEBSOCKET_PING_PONG],
12255 if (conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) {
12256 timeout = atoi(conn->dom_ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
12258 if ((timeout <= 0.0) && (conn->dom_ctx->config[REQUEST_TIMEOUT])) {
12259 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]) / 1000.0;
12264 conn->request_info.remote_addr,
12265 conn->request_info.remote_port);
12266 conn->in_websocket_handling = 1;
12271 while (!conn->phys_ctx->stop_flag && !conn->must_close) {
12273 DEBUG_ASSERT(conn->data_len >= conn->request_len);
12274 if ((body_len = (size_t)(conn->data_len - conn->request_len)) >= 2) {
12278 /* inline 7-bit length field */
12282 /* 16-bit length field */
12284 data_len = ((((size_t)buf[2]) << 8) + buf[3]);
12286 /* 64-bit length field */
12310 conn->phys_ctx);
12324 memcpy(mask, buf + header_len - mask_len, sizeof(mask));
12335 len = body_len - header_len;
12342 (int)(data_len - len),
12344 if (n <= -2) {
12365 conn->data_len = conn->request_len;
12383 memmove(buf, buf + len, body_len - len);
12386 conn->data_len -= (int)len;
12392 data[i] ^= mask[i & 3];
12400 conn->request_info.remote_addr,
12401 conn->request_info.remote_port);
12408 conn->request_info.remote_addr,
12409 conn->request_info.remote_port);
12441 conn->request_info.remote_addr,
12442 conn->request_info.remote_port);
12448 conn->request_info.remote_addr,
12449 conn->request_info.remote_port);
12459 conn->buf + conn->data_len,
12460 conn->buf_size - conn->data_len,
12462 if (n <= -2) {
12465 conn->request_info.remote_addr,
12466 conn->request_info.remote_port);
12470 conn->data_len += n;
12474 if (!conn->phys_ctx->stop_flag && !conn->must_close) {
12478 "- closing connection",
12480 conn->request_info.remote_addr,
12481 conn->request_info.remote_port);
12487 conn->request_info.remote_addr,
12488 conn->request_info.remote_port);
12510 conn->in_websocket_handling = 0;
12512 conn->request_info.remote_addr,
12513 conn->request_info.remote_port);
12531 #pragma GCC diagnostic ignored "-Wconversion"
12540 /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
12542 /* inline 7-bit length field */
12546 /* 16-bit length field */
12552 /* 64-bit length field */
12569 …* http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-va…
12584 retval = -1;
12614 if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
12616 while (i < (in_len - 3)) {
12623 /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
12640 int retval = -1;
12642 (char *)mg_malloc_ctx(((dataLen + 7) / 4) * 4, conn->phys_ctx);
12646 /* Return -1 in an error case */
12651 return -1;
12655 /* Get a masking key - but not 0 */
12680 const char *websock_key = mg_get_header(conn, "Sec-WebSocket-Key");
12681 const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
12689 /* Step 1.1: Check Sec-WebSocket-Key. */
12692 * requires a Sec-WebSocket-Key header.
12695 * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
12697 const char *key1 = mg_get_header(conn, "Sec-WebSocket-Key1");
12698 const char *key2 = mg_get_header(conn, "Sec-WebSocket-Key2");
12703 conn->content_len = 8;
12733 int nbSubprotocolHeader = get_req_headers(&conn->request_info,
12734 "Sec-WebSocket-Protocol",
12752 len = sep ? (unsigned long)(sep - protocol)
12759 for (idx = 0; idx < subprotocols->nb_subprotocols; idx++) {
12760 if ((strlen(subprotocols->subprotocols[idx]) == len)
12762 subprotocols->subprotocols[idx],
12766 subprotocols->subprotocols[idx];
12774 conn->request_info.acceptedWebSocketSubprotocol =
12786 /* Just a single protocol -> accept it. */
12787 conn->request_info.acceptedWebSocketSubprotocol = protocol;
12789 /* Multiple protocols -> accept the last one. */
12800 conn->request_info.acceptedWebSocketSubprotocol = sep;
12806 /* C callback has returned non-zero, do not proceed with
12816 /* Step 3: No callback. Check if Lua is responsible. */
12819 if (conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
12821 conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS],
12822 strlen(conn->dom_ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
12828 conn->lua_websocket_state = lua_websocket_new(path, conn);
12829 if (!conn->lua_websocket_state) {
12860 if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
12872 read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
12913 /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
12914 * "Sec-WebSocket-Version" are also required.
12944 *mask = slash ? (0xffffffffU << (32 - slash)) : 0;
12992 return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr);
13003 * HTML forms sent as POST request in multipart/form-data format
13026 mg_cry_internal(fud->conn, "%s: No filename set", __func__);
13029 mg_snprintf(fud->conn,
13032 pathlen - 1,
13034 fud->destination_dir,
13037 mg_cry_internal(fud->conn, "%s: File path too long", __func__);
13068 fud->num_uploaded_files++;
13069 fud->conn->phys_ctx->callbacks.upload(fud->conn, path);
13075 /* Deprecated function mg_upload - use mg_handle_form_request instead. */
13102 int idx = -1;
13104 for (i = 0; ((idx == -1) && (i < ctx->num_listening_sockets)); i++) {
13105 idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
13119 const char *host_header = get_header(conn->request_info.http_headers,
13120 conn->request_info.num_headers,
13130 buf[buflen - 1] = '\0';
13155 if (conn->ssl) {
13158 const char *sslhost = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
13159 if (sslhost && (conn->dom_ctx != &(conn->phys_ctx->dd))) {
13172 struct mg_domain_context *dom = &(conn->phys_ctx->dd);
13174 if (!mg_strcasecmp(host, dom->config[AUTHENTICATION_DOMAIN])) {
13178 dom->config[AUTHENTICATION_DOMAIN]);
13181 conn->dom_ctx = dom;
13184 dom = dom->next;
13191 sockaddr_to_string(buf, buflen, &conn->client.lsa);
13197 return mg_strdup_ctx(host, conn->phys_ctx);
13207 conn->must_close = 1;
13210 if (conn->host) {
13223 conn->host,
13225 (conn->phys_ctx->listening_sockets[ssl_index].lsa.sa.sa_family
13227 ? (int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13231 (int)ntohs(conn->phys_ctx->listening_sockets[ssl_index]
13233 conn->request_info.local_uri,
13234 (conn->request_info.query_string == NULL) ? "" : "?",
13235 (conn->request_info.query_string == NULL)
13237 : conn->request_info.query_string);
13255 pthread_mutex_lock(&handler_info->refcount_mutex);
13256 handler_info->refcount++;
13257 pthread_mutex_unlock(&handler_info->refcount_mutex);
13264 pthread_mutex_lock(&handler_info->refcount_mutex);
13265 handler_info->refcount--;
13266 pthread_cond_signal(&handler_info->refcount_cond);
13267 pthread_mutex_unlock(&handler_info->refcount_mutex);
13274 pthread_mutex_lock(&handler_info->refcount_mutex);
13275 while (handler_info->refcount) {
13276 pthread_cond_wait(&handler_info->refcount_cond,
13277 &handler_info->refcount_mutex);
13279 pthread_mutex_unlock(&handler_info->refcount_mutex);
13359 lastref = &(dom_ctx->handlers);
13360 for (tmp_rh = dom_ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
13361 if (tmp_rh->handler_type == handler_type) {
13362 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13369 /* Ok, the handler is no more use -> Update it */
13370 tmp_rh->handler = handler;
13372 tmp_rh->subprotocols = subprotocols;
13373 tmp_rh->connect_handler = connect_handler;
13374 tmp_rh->ready_handler = ready_handler;
13375 tmp_rh->data_handler = data_handler;
13376 tmp_rh->close_handler = close_handler;
13378 tmp_rh->auth_handler = auth_handler;
13380 tmp_rh->cbdata = cbdata;
13387 /* Ok, the handler is no more used -> Destroy resources
13389 pthread_cond_destroy(&tmp_rh->refcount_cond);
13390 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13392 *lastref = tmp_rh->next;
13393 mg_free(tmp_rh->uri);
13400 lastref = &(tmp_rh->next);
13404 /* no handler to set, this was a remove request to a non-existing
13421 tmp_rh->uri = mg_strdup_ctx(uri, phys_ctx);
13422 if (!tmp_rh->uri) {
13430 tmp_rh->uri_len = urilen;
13433 if (0 != pthread_mutex_init(&tmp_rh->refcount_mutex, NULL)) {
13439 if (0 != pthread_cond_init(&tmp_rh->refcount_cond, NULL)) {
13441 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
13446 tmp_rh->refcount = 0;
13447 tmp_rh->handler = handler;
13449 tmp_rh->subprotocols = subprotocols;
13450 tmp_rh->connect_handler = connect_handler;
13451 tmp_rh->ready_handler = ready_handler;
13452 tmp_rh->data_handler = data_handler;
13453 tmp_rh->close_handler = close_handler;
13455 tmp_rh->auth_handler = auth_handler;
13457 tmp_rh->cbdata = cbdata;
13458 tmp_rh->handler_type = handler_type;
13459 tmp_rh->next = NULL;
13473 &(ctx->dd),
13523 &(ctx->dd),
13545 &(ctx->dd),
13575 const char *uri = request_info->local_uri;
13579 if (!conn || !conn->phys_ctx || !conn->dom_ctx) {
13583 mg_lock_context(conn->phys_ctx);
13586 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13587 tmp_rh = tmp_rh->next) {
13588 if (tmp_rh->handler_type == handler_type) {
13589 if ((urilen == tmp_rh->uri_len) && !strcmp(tmp_rh->uri, uri)) {
13591 *subprotocols = tmp_rh->subprotocols;
13592 *connect_handler = tmp_rh->connect_handler;
13593 *ready_handler = tmp_rh->ready_handler;
13594 *data_handler = tmp_rh->data_handler;
13595 *close_handler = tmp_rh->close_handler;
13597 *handler = tmp_rh->handler;
13602 *auth_handler = tmp_rh->auth_handler;
13604 *cbdata = tmp_rh->cbdata;
13605 mg_unlock_context(conn->phys_ctx);
13612 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13613 tmp_rh = tmp_rh->next) {
13614 if (tmp_rh->handler_type == handler_type) {
13615 if ((tmp_rh->uri_len < urilen) && (uri[tmp_rh->uri_len] == '/')
13616 && (memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0)) {
13618 *subprotocols = tmp_rh->subprotocols;
13619 *connect_handler = tmp_rh->connect_handler;
13620 *ready_handler = tmp_rh->ready_handler;
13621 *data_handler = tmp_rh->data_handler;
13622 *close_handler = tmp_rh->close_handler;
13624 *handler = tmp_rh->handler;
13629 *auth_handler = tmp_rh->auth_handler;
13631 *cbdata = tmp_rh->cbdata;
13632 mg_unlock_context(conn->phys_ctx);
13639 for (tmp_rh = conn->dom_ctx->handlers; tmp_rh != NULL;
13640 tmp_rh = tmp_rh->next) {
13641 if (tmp_rh->handler_type == handler_type) {
13642 if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
13644 *subprotocols = tmp_rh->subprotocols;
13645 *connect_handler = tmp_rh->connect_handler;
13646 *ready_handler = tmp_rh->ready_handler;
13647 *data_handler = tmp_rh->data_handler;
13648 *close_handler = tmp_rh->close_handler;
13650 *handler = tmp_rh->handler;
13655 *auth_handler = tmp_rh->auth_handler;
13657 *cbdata = tmp_rh->cbdata;
13658 mg_unlock_context(conn->phys_ctx);
13664 mg_unlock_context(conn->phys_ctx);
13691 if (pcallbacks->websocket_connect) {
13692 return pcallbacks->websocket_connect(conn);
13694 /* No handler set - assume "OK" */
13703 if (pcallbacks->websocket_ready) {
13704 pcallbacks->websocket_ready(conn);
13717 if (pcallbacks->websocket_data) {
13718 return pcallbacks->websocket_data(conn, bits, data, len);
13720 /* No handler set - assume "OK" */
13733 struct mg_request_info *ri = &conn->request_info;
13758 if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
13760 *((char *)conn->request_info.query_string++) = '\0';
13764 if (!conn->client.is_ssl && conn->client.ssl_redir) {
13765 ssl_index = get_first_ssl_listener_index(conn->phys_ctx);
13781 uri_len = (int)strlen(ri->local_uri);
13786 ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
13791 remove_double_dots_and_double_slashes((char *)ri->local_uri);
13794 uri_len = (int)strlen(ri->local_uri);
13795 DEBUG_TRACE("URL: %s", ri->local_uri);
13798 conn->throttle = set_throttle(conn->dom_ctx->config[THROTTLE],
13800 ri->local_uri);
13802 /* 3. call a "handle everything" callback, if registered */
13803 if (conn->phys_ctx->callbacks.begin_request != NULL) {
13807 i = conn->phys_ctx->callbacks.begin_request(conn);
13811 conn->status_code = i;
13817 /* unspecified - may change with the next version */
13826 * https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
13828 if (!strcmp(ri->request_method, "OPTIONS")) {
13833 conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_METHODS];
13835 conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
13837 get_header(ri->http_headers, ri->num_headers, "Origin");
13838 const char *cors_acrm = get_header(ri->http_headers,
13839 ri->num_headers,
13840 "Access-Control-Request-Method");
13852 get_header(ri->http_headers,
13853 ri->num_headers,
13854 "Access-Control-Request-Headers");
13860 "Access-Control-Allow-Origin: %s\r\n"
13861 "Access-Control-Allow-Methods: %s\r\n"
13862 "Content-Length: 0\r\n"
13872 conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_HEADERS];
13881 "Access-Control-Allow-Headers: %s\r\n",
13886 mg_printf(conn, "Access-Control-Max-Age: 60\r\n");
13963 if (conn->dom_ctx->config[DOCUMENT_ROOT] == NULL) {
13970 conn->request_info.request_method);
14008 conn->status_code = i;
14017 * implementation, and return 1 - we cannot do anything
14080 conn->phys_ctx->user_data);
14096 conn->phys_ctx->user_data);
14114 if (conn->dom_ctx->config[DOCUMENT_ROOT] == NULL) {
14128 if (!strcmp(ri->request_method, "PUT")) {
14133 if (!strcmp(ri->request_method, "DELETE")) {
14138 if (!strcmp(ri->request_method, "MKCOL")) {
14148 conn->request_info.request_method);
14161 && (ri->local_uri[uri_len - 1] != '/')) {
14167 /* "Cache-Control: private\r\n" (= default) */
14168 "Content-Length: 0\r\n"
14170 ri->request_uri,
14180 if (!strcmp(ri->request_method, "PROPFIND")) {
14185 if (!strcmp(ri->request_method, "OPTIONS")) {
14195 if ((0 != strcmp(ri->request_method, "GET"))
14196 && (0 != strcmp(ri->request_method, "HEAD"))) {
14200 conn->request_info.request_method);
14209 if (!mg_strcasecmp(conn->dom_ctx->config[ENABLE_DIRECTORY_LISTING],
14233 if (!conn || !conn->dom_ctx) {
14240 conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
14241 strlen(conn->dom_ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
14255 } else if (match_prefix(conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS],
14257 conn->dom_ctx->config[LUA_SCRIPT_EXTENSIONS]),
14261 /* Lua in-server module script: a CGI like script used to
14273 conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
14274 strlen(conn->dom_ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
14286 } else if (match_prefix(conn->dom_ctx->config[CGI_EXTENSIONS],
14287 strlen(conn->dom_ctx->config[CGI_EXTENSIONS]),
14298 } else if (match_prefix(conn->dom_ctx->config[SSI_EXTENSIONS],
14299 strlen(conn->dom_ctx->config[SSI_EXTENSIONS]),
14309 } else if ((!conn->in_error_handler)
14310 && is_not_modified(conn, &file->stat)) {
14311 /* Send 304 "Not Modified" - this must not send any body data */
14329 for (i = 0; i < ctx->num_listening_sockets; i++) {
14330 closesocket(ctx->listening_sockets[i].sock);
14331 ctx->listening_sockets[i].sock = INVALID_SOCKET;
14333 mg_free(ctx->listening_sockets);
14334 ctx->listening_sockets = NULL;
14335 mg_free(ctx->listening_socket_fds);
14336 ctx->listening_socket_fds = NULL;
14344 * see https://tools.ietf.org/html/rfc3513#section-2.2
14351 * at all - it must be tested what options work best in the
14366 * Also, all-zeroes in the socket address means binding to all addresses
14369 so->lsa.sin.sin_family = AF_INET;
14377 if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
14380 so->lsa.sin.sin_addr.s_addr =
14382 so->lsa.sin.sin_port = htons((uint16_t)port);
14386 } else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
14388 AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
14390 /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
14392 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14396 } else if ((vec->ptr[0] == '+')
14397 && (sscanf(vec->ptr + 1, "%u%n", &port, &len) == 1)) {
14405 so->lsa.sin6.sin6_family = AF_INET6;
14406 so->lsa.sin6.sin6_port = htons((uint16_t)port);
14410 so->lsa.sin.sin_port = htons((uint16_t)port);
14414 } else if (is_valid_port(port = strtoul(vec->ptr, &endptr, 0))
14415 && vec->ptr != endptr) {
14416 len = endptr - vec->ptr;
14418 so->lsa.sin.sin_port = htons((uint16_t)port);
14421 } else if ((cb = strchr(vec->ptr, ':')) != NULL) {
14425 * digits and hyphen ('-'). Newer specs may allow
14432 size_t hostnlen = (size_t)(cb - vec->ptr);
14440 memcpy(hostname, vec->ptr, hostnlen);
14444 AF_INET, vec->ptr, &so->lsa.sin, sizeof(so->lsa.sin))) {
14447 so->lsa.sin.sin_family = AF_INET;
14448 so->lsa.sin.sin_port = htons((uint16_t)port);
14456 vec->ptr,
14457 &so->lsa.sin6,
14458 sizeof(so->lsa.sin6))) {
14461 so->lsa.sin6.sin6_family = AF_INET6;
14462 so->lsa.sin.sin_port = htons((uint16_t)port);
14478 if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
14482 ch = vec->ptr[len]; /* Next character after the port number */
14483 so->is_ssl = (ch == 's');
14484 so->ssl_redir = (ch == 'r');
14504 * - "80" for a single port using every network interface
14505 * - "localhost:80" for a single port using only localhost
14506 * - "80,localhost:8080" for two ports, one bound to localhost
14507 * - "80,127.0.0.1:8084,[::1]:8086" for three ports, one bound
14509 * - "+80" use port 80 for IPv4 and IPv6
14510 * - "+80r,+443s" port 80 (HTTP) is a redirect to port 443 (HTTPS),
14512 * - "+443s,localhost:8080" port 443 (HTTPS) for every interface,
14585 list = phys_ctx->dd.config[LISTENING_PORTS];
14603 if (so.is_ssl && phys_ctx->dd.ssl_ctx == NULL) {
14624 * if someone already has the socket -- DTL */
14744 opt_txt = phys_ctx->dd.config[MAX_CONNECTIONS];
14792 mg_realloc_ctx(phys_ctx->listening_sockets,
14793 (phys_ctx->num_listening_sockets + 1)
14794 * sizeof(phys_ctx->listening_sockets[0]),
14805 mg_realloc_ctx(phys_ctx->listening_socket_fds,
14806 (phys_ctx->num_listening_sockets + 1)
14807 * sizeof(phys_ctx->listening_socket_fds[0]),
14819 phys_ctx->listening_sockets = ptr;
14820 phys_ctx->listening_sockets[phys_ctx->num_listening_sockets] = so;
14821 phys_ctx->listening_socket_fds = pfd;
14822 phys_ctx->num_listening_sockets++;
14841 return "-";
14866 if (!conn || !conn->dom_ctx) {
14870 if (conn->dom_ctx->config[ACCESS_LOG_FILE] != NULL) {
14872 conn->dom_ctx->config[ACCESS_LOG_FILE],
14885 && (conn->phys_ctx->callbacks.log_access == NULL)) {
14889 tm = localtime(&conn->conn_birth_time);
14894 date[sizeof(date) - 1] = '\0';
14897 ri = &conn->request_info;
14899 sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
14901 user_agent = header_val(conn, "User-Agent");
14907 "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
14909 (ri->remote_user == NULL) ? "-" : ri->remote_user,
14911 ri->request_method ? ri->request_method : "-",
14912 ri->request_uri ? ri->request_uri : "-",
14913 ri->query_string ? "?" : "",
14914 ri->query_string ? ri->query_string : "",
14915 ri->http_version,
14916 conn->status_code,
14917 conn->num_bytes_sent,
14921 if (conn->phys_ctx->callbacks.log_access) {
14922 conn->phys_ctx->callbacks.log_access(conn, buf);
14941 conn->dom_ctx->config[ACCESS_LOG_FILE]);
14951 * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
14961 const char *list = phys_ctx->dd.config[ACCESS_CONTROL_LIST];
14964 allowed = (list == NULL) ? '+' : '-';
14968 if ((flag != '+' && flag != '-')
14971 "%s: subnet must be [+|-]x.x.x.x[/x]",
14973 return -1;
14983 return -1;
14997 const char *run_as_user = phys_ctx->dd.config[RUN_AS_USER];
15007 } else if (run_as_user == NULL || curr_uid == to_pw->pw_uid) {
15014 if (setgid(to_pw->pw_gid) == -1) {
15020 } else if (setgroups(0, NULL) == -1) {
15025 } else if (setuid(to_pw->pw_uid) == -1) {
15049 if (tls->is_master == 2) {
15050 tls->is_master = -3; /* Mark memory as dead */
15080 if ((pem = conn->dom_ctx->config[SSL_CERTIFICATE]) == NULL) {
15081 /* If peem is NULL and conn->phys_ctx->callbacks.init_ssl is not,
15085 chain = conn->dom_ctx->config[SSL_CERTIFICATE_CHAIN];
15095 if (stat(pem, &cert_buf) != -1) {
15103 if (conn->dom_ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
15104 if (mg_strcasecmp(conn->dom_ctx->config[SSL_DO_VERIFY_PEER], "yes")
15107 } else if (mg_strcasecmp(conn->dom_ctx->config[SSL_DO_VERIFY_PEER],
15115 char *ca_path = conn->dom_ctx->config[SSL_CA_PATH];
15116 char *ca_file = conn->dom_ctx->config[SSL_CA_FILE];
15117 if (SSL_CTX_load_verify_locations(conn->dom_ctx->ssl_ctx,
15122 conn->phys_ctx,
15134 if (ssl_use_pem_file(conn->phys_ctx, conn->dom_ctx, pem, chain)
15171 (conn->dom_ctx->config[SSL_SHORT_TRUST] != NULL)
15172 && (mg_strcasecmp(conn->dom_ctx->config[SSL_SHORT_TRUST], "yes") == 0);
15181 conn->ssl = SSL_new(s);
15182 if (conn->ssl == NULL) {
15185 SSL_set_app_data(conn->ssl, (char *)conn);
15187 ret = SSL_set_fd(conn->ssl, conn->client.sock);
15189 err = SSL_get_error(conn->ssl, ret);
15191 SSL_free(conn->ssl);
15192 conn->ssl = NULL;
15198 if (client_options->host_name) {
15199 SSL_set_tlsext_host_name(conn->ssl, client_options->host_name);
15204 if (conn->dom_ctx->config[REQUEST_TIMEOUT]) {
15205 /* NOTE: The loop below acts as a back-off, so we can end
15207 timeout = atoi(conn->dom_ctx->config[REQUEST_TIMEOUT]);
15214 ret = func(conn->ssl);
15216 err = SSL_get_error(conn->ssl, ret);
15230 * See https://linux.die.net/man/3/ssl_get_error
15231 * This is typical for non-blocking sockets. */
15234 pfd.fd = conn->client.sock;
15241 /* Break if error occured (-1)
15242 * or server shutdown (-2) */
15267 SSL_free(conn->ssl);
15268 conn->ssl = NULL;
15296 if (buflen < (3 * memlen)) {
15302 buf[3 * i - 1] = ' ';
15304 buf[3 * i] = hexdigit[(((uint8_t *)mem)[i] >> 4) & 0xF];
15305 buf[3 * i + 1] = hexdigit[((uint8_t *)mem)[i] & 0xF];
15307 buf[3 * memlen - 1] = 0;
15316 X509 *cert = SSL_get_peer_certificate(conn->ssl);
15355 conn->phys_ctx)
15372 conn->request_info.client_cert = (struct mg_client_cert *)
15373 mg_malloc_ctx(sizeof(struct mg_client_cert), conn->phys_ctx);
15374 if (conn->request_info.client_cert) {
15375 conn->request_info.client_cert->peer_cert = (void *)cert;
15376 conn->request_info.client_cert->subject =
15377 mg_strdup_ctx(str_subject, conn->phys_ctx);
15378 conn->request_info.client_cert->issuer =
15379 mg_strdup_ctx(str_issuer, conn->phys_ctx);
15380 conn->request_info.client_cert->serial =
15381 mg_strdup_ctx(str_serial, conn->phys_ctx);
15382 conn->request_info.client_cert->finger =
15383 mg_strdup_ctx(str_finger, conn->phys_ctx);
15392 * see https://linux.die.net/man/3/bn_bn2hex */
15441 for (fp = sw; fp->name != NULL; fp++) {
15444 u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
15449 u.p = dlsym(dll_handle, fp->name);
15460 fp->name);
15468 ebuf_len - cur_len - 3,
15470 fp->name);
15478 * printf("Missing function: %s\n", fp->name); */
15480 fp->ptr = u.fp;
15578 /* Mutex array required - allocate it */
15651 if (SSL_CTX_use_certificate_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
15661 if (SSL_CTX_use_PrivateKey_file(dom_ctx->ssl_ctx, pem, 1) == 0) {
15670 if (SSL_CTX_check_private_key(dom_ctx->ssl_ctx) == 0) {
15681 * The CivetWeb-Server used pem-Files that contained both information.
15687 if (SSL_CTX_use_certificate_chain_file(dom_ctx->ssl_ctx, chain) == 0) {
15711 if (version_id > 3)
15732 if (version_id > 3)
15747 * https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_info_callback(3)
15748 * https://linux.die.net/man/3/ssl_set_info_callback */
15766 // ssl->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
15776 (struct mg_domain_context *)ctx ? &(ctx->dd) : NULL;
15780 #pragma GCC diagnostic ignored "-Wcast-align"
15794 if ((ctx == NULL) || (conn->phys_ctx == ctx)) {
15795 DEBUG_TRACE("%s", "internal error - assertion failed");
15800 * is no server name available in the request - we can
15807 conn->dom_ctx = &(ctx->dd);
15808 SSL_set_SSL_CTX(ssl, conn->dom_ctx->ssl_ctx);
15815 if (!mg_strcasecmp(servername, dom->config[AUTHENTICATION_DOMAIN])) {
15819 dom->config[AUTHENTICATION_DOMAIN]);
15820 SSL_set_SSL_CTX(ssl, dom->ssl_ctx);
15821 conn->dom_ctx = dom;
15824 dom = dom->next;
15829 ctx->dd.config[AUTHENTICATION_DOMAIN]);
15830 conn->dom_ctx = &(ctx->dd);
15831 SSL_set_SSL_CTX(ssl, conn->dom_ctx->ssl_ctx);
15856 if ((dom_ctx->ssl_ctx = SSL_CTX_new(TLS_server_method())) == NULL) {
15863 if ((dom_ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
15871 SSL_CTX_clear_options(dom_ctx->ssl_ctx,
15874 protocol_ver = atoi(dom_ctx->config[SSL_PROTOCOL_VERSION]);
15875 SSL_CTX_set_options(dom_ctx->ssl_ctx, ssl_get_protocol(protocol_ver));
15876 SSL_CTX_set_options(dom_ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE);
15877 SSL_CTX_set_options(dom_ctx->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
15878 SSL_CTX_set_options(dom_ctx->ssl_ctx,
15880 SSL_CTX_set_options(dom_ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
15883 SSL_CTX_set_options(dom_ctx->ssl_ctx, SSL_OP_NO_RENEGOTIATION);
15887 SSL_CTX_set_ecdh_auto(dom_ctx->ssl_ctx, 1);
15903 SSL_CTX_set_info_callback(dom_ctx->ssl_ctx, ssl_info_callback);
15905 SSL_CTX_set_tlsext_servername_callback(dom_ctx->ssl_ctx,
15907 SSL_CTX_set_tlsext_servername_arg(dom_ctx->ssl_ctx, phys_ctx);
15910 callback_ret = (phys_ctx->callbacks.init_ssl == NULL)
15912 : (phys_ctx->callbacks.init_ssl(dom_ctx->ssl_ctx,
15913 phys_ctx->user_data));
15917 * If it returns -1, initializing ssl fails. */
15935 (const md5_byte_t *)phys_ctx->dd.config[LISTENING_PORTS],
15936 strlen(phys_ctx->dd.config[LISTENING_PORTS]));
15938 (const md5_byte_t *)dom_ctx->config[AUTHENTICATION_DOMAIN],
15939 strlen(dom_ctx->config[AUTHENTICATION_DOMAIN]));
15944 SSL_CTX_set_session_id_context(dom_ctx->ssl_ctx,
15958 if (dom_ctx->config[SSL_DO_VERIFY_PEER] != NULL) {
15959 if (mg_strcasecmp(dom_ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0) {
15963 } else if (mg_strcasecmp(dom_ctx->config[SSL_DO_VERIFY_PEER],
15973 (dom_ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
15974 && (mg_strcasecmp(dom_ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes")
15978 ca_path = dom_ctx->config[SSL_CA_PATH];
15979 ca_file = dom_ctx->config[SSL_CA_FILE];
15980 if (SSL_CTX_load_verify_locations(dom_ctx->ssl_ctx, ca_file, ca_path)
15993 SSL_CTX_set_verify(dom_ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
15995 SSL_CTX_set_verify(dom_ctx->ssl_ctx,
16002 && (SSL_CTX_set_default_verify_paths(dom_ctx->ssl_ctx) != 1)) {
16009 if (dom_ctx->config[SSL_VERIFY_DEPTH]) {
16010 verify_depth = atoi(dom_ctx->config[SSL_VERIFY_DEPTH]);
16011 SSL_CTX_set_verify_depth(dom_ctx->ssl_ctx, verify_depth);
16015 if (dom_ctx->config[SSL_CIPHER_LIST] != NULL) {
16016 if (SSL_CTX_set_cipher_list(dom_ctx->ssl_ctx,
16017 dom_ctx->config[SSL_CIPHER_LIST])
16031 * and set up ctx->ssl_ctx pointer. */
16046 dom_ctx = &(phys_ctx->dd);
16049 if (!is_ssl_port_used(dom_ctx->config[LISTENING_PORTS])) {
16056 (phys_ctx->callbacks.external_ssl_ctx == NULL)
16058 : (phys_ctx->callbacks.external_ssl_ctx(&ssl_ctx,
16059 phys_ctx->user_data));
16067 dom_ctx->ssl_ctx = (SSL_CTX *)ssl_ctx;
16079 if (((pem = dom_ctx->config[SSL_CERTIFICATE]) == NULL)
16080 && (phys_ctx->callbacks.init_ssl == NULL)) {
16085 "Initializing SSL failed: -%s is not set",
16090 chain = dom_ctx->config[SSL_CERTIFICATE_CHAIN];
16116 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
16126 * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
16157 dom_ctx = &(phys_ctx->dd);
16159 path = dom_ctx->config[GLOBAL_PASSWORDS_FILE];
16178 return check_acl(phys_ctx, (uint32_t)0x7f000001UL) != -1;
16188 conn->connection_type =
16191 conn->num_bytes_sent = conn->consumed_content = 0;
16193 conn->path_info = NULL;
16194 conn->status_code = -1;
16195 conn->content_len = -1;
16196 conn->is_chunked = 0;
16197 conn->must_close = 0;
16198 conn->request_len = 0;
16199 conn->throttle = 0;
16200 conn->accept_gzip = 0;
16202 conn->response_info.content_length = conn->request_info.content_length = -1;
16203 conn->response_info.http_version = conn->request_info.http_version = NULL;
16204 conn->response_info.num_headers = conn->request_info.num_headers = 0;
16205 conn->response_info.status_text = NULL;
16206 conn->response_info.status_code = 0;
16208 conn->request_info.remote_user = NULL;
16209 conn->request_info.request_method = NULL;
16210 conn->request_info.request_uri = NULL;
16211 conn->request_info.local_uri = NULL;
16215 conn->request_info.uri = NULL;
16247 int linger_timeout = -2;
16254 /* http://msdn.microsoft.com/en-us/library/ms739165(v=vs.85).aspx:
16257 set_blocking_mode(conn->client.sock);
16260 shutdown(conn->client.sock, SHUTDOWN_WR);
16275 if (conn->dom_ctx->config[LINGER_TIMEOUT]) {
16276 linger_timeout = atoi(conn->dom_ctx->config[LINGER_TIMEOUT]);
16291 #pragma GCC diagnostic ignored "-Wconversion"
16311 if (linger_timeout < -1) {
16313 } else if (getsockopt(conn->client.sock,
16340 if (setsockopt(conn->client.sock,
16356 /* Now we know that our FIN is ACK-ed, safe to close */
16357 closesocket(conn->client.sock);
16358 conn->client.sock = INVALID_SOCKET;
16367 conn->conn_state = 6; /* to close */
16371 if (conn->lua_websocket_state) {
16372 lua_websocket_close(conn, conn->lua_websocket_state);
16373 conn->lua_websocket_state = NULL;
16379 /* Set close flag, so keep-alive loops will stop */
16380 conn->must_close = 1;
16383 if (conn->phys_ctx->callbacks.connection_close != NULL) {
16384 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
16385 conn->phys_ctx->callbacks.connection_close(conn);
16396 conn->conn_state = 7; /* closing */
16400 if (conn->ssl != NULL) {
16403 SSL_shutdown(conn->ssl);
16404 SSL_free(conn->ssl);
16406 conn->ssl = NULL;
16409 if (conn->client.sock != INVALID_SOCKET) {
16411 closesocket(conn->client.sock);
16415 conn->client.sock = INVALID_SOCKET;
16418 if (conn->host) {
16419 mg_free((void *)conn->host);
16420 conn->host = NULL;
16426 conn->conn_state = 8; /* closed */
16434 if ((conn == NULL) || (conn->phys_ctx == NULL)) {
16439 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
16440 if (conn->in_websocket_handling) {
16442 conn->must_close = 1;
16446 if (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT) {
16451 conn->phys_ctx->stop_flag = 1;
16452 conn->must_close = 1;
16460 for (i = 0; i < conn->phys_ctx->cfg_worker_threads; i++) {
16461 mg_join_thread(conn->phys_ctx->worker_threadids[i]);
16469 if (((conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT)
16470 || (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT))
16471 && (conn->phys_ctx->dd.ssl_ctx != NULL)) {
16472 SSL_CTX_free(conn->phys_ctx->dd.ssl_ctx);
16477 if (conn->phys_ctx->context_type == CONTEXT_WS_CLIENT) {
16478 mg_free(conn->phys_ctx->worker_threadids);
16479 (void)pthread_mutex_destroy(&conn->mutex);
16481 } else if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) {
16485 if (conn->phys_ctx->context_type == CONTEXT_HTTP_CLIENT) { /* Client */
16508 size_t conn_size = ((sizeof(struct mg_connection) + 7) >> 3) << 3;
16509 size_t ctx_size = ((sizeof(struct mg_context) + 7) >> 3) << 3;
16527 #pragma GCC diagnostic ignored "-Wcast-align"
16531 conn->phys_ctx = (struct mg_context *)(((char *)conn) + conn_size);
16537 conn->buf = (((char *)conn) + conn_size + ctx_size);
16538 conn->buf_size = (int)max_req_size;
16539 conn->phys_ctx->context_type = CONTEXT_HTTP_CLIENT;
16540 conn->dom_ctx = &(conn->phys_ctx->dd);
16542 if (!connect_socket(conn->phys_ctx,
16543 client_options->host,
16544 client_options->port,
16559 && (conn->dom_ctx->ssl_ctx = SSL_CTX_new(TLS_client_method()))
16573 && (conn->dom_ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
16590 len = (sa.sa.sa_family == AF_INET) ? sizeof(conn->client.rsa.sin)
16591 : sizeof(conn->client.rsa.sin6);
16593 ? (struct sockaddr *)&(conn->client.rsa.sin)
16594 : (struct sockaddr *)&(conn->client.rsa.sin6);
16596 len = sizeof(conn->client.rsa.sin);
16597 psa = (struct sockaddr *)&(conn->client.rsa.sin);
16600 conn->client.sock = sock;
16601 conn->client.lsa = sa;
16610 conn->client.is_ssl = use_ssl ? 1 : 0;
16611 if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
16618 SSL_CTX_free(conn->dom_ctx->ssl_ctx);
16632 /* TODO: SSL_CTX_set_verify(conn->dom_ctx,
16635 if (client_options->client_cert) {
16636 if (!ssl_use_pem_file(conn->phys_ctx,
16637 conn->dom_ctx,
16638 client_options->client_cert,
16645 SSL_CTX_free(conn->dom_ctx->ssl_ctx);
16652 if (client_options->server_cert) {
16653 if (SSL_CTX_load_verify_locations(conn->dom_ctx->ssl_ctx,
16654 client_options->server_cert,
16660 SSL_CTX_free(conn->dom_ctx->ssl_ctx);
16665 SSL_CTX_set_verify(conn->dom_ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
16667 SSL_CTX_set_verify(conn->dom_ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
16671 conn->dom_ctx->ssl_ctx,
16673 &(conn->phys_ctx->stop_flag),
16680 SSL_CTX_free(conn->dom_ctx->ssl_ctx);
16737 * return 3 for absolute uri without port,
16748 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
16759 * and unreserved characters A-Z a-z 0-9 and -._~
16768 /* non-ascii characters must be % encoded */
16811 return 3;
16842 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_AUTH_DOMAIN_CHECK], "yes");
16860 request_domain_len = (size_t)(hostend - hostbegin);
16867 request_domain_len = (size_t)(portbegin - hostbegin);
16882 if (conn->client.lsa.sa.sa_family == AF_INET6) {
16883 if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
16890 if (ntohs(conn->client.lsa.sin.sin_port) != port) {
16905 server_domain = conn->dom_ctx->config[AUTHENTICATION_DOMAIN];
16912 /* Request is directed to this server - full name match. */
16921 if (hostbegin[request_domain_len - server_domain_len - 1] != '.') {
16929 hostbegin + request_domain_len - server_domain_len,
16964 clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
16966 conn->request_len =
16967 read_message(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
16968 DEBUG_ASSERT(conn->request_len < 0 || conn->data_len >= conn->request_len);
16969 if ((conn->request_len >= 0) && (conn->data_len < conn->request_len)) {
16980 if ((conn->request_len == 0) && (conn->data_len == conn->buf_size)) {
16991 if (conn->request_len <= 0) {
16992 if (conn->data_len > 0) {
17001 /* Server did not recv anything -> just close the connection */
17002 conn->must_close = 1;
17025 if (parse_http_request(conn->buf, conn->buf_size, &conn->request_info)
17040 if (conn->host != NULL) {
17041 mg_free((void *)conn->host);
17043 conn->host = alloc_get_host(conn);
17044 if (!conn->host) {
17055 if (((cl = get_header(conn->request_info.http_headers,
17056 conn->request_info.num_headers,
17057 "Transfer-Encoding"))
17070 conn->is_chunked = 1;
17071 conn->content_len = 0; /* not yet read */
17072 } else if ((cl = get_header(conn->request_info.http_headers,
17073 conn->request_info.num_headers,
17074 "Content-Length"))
17078 conn->content_len = strtoll(cl, &endptr, 10);
17079 if ((endptr == cl) || (conn->content_len < 0)) {
17090 conn->request_info.content_length = conn->content_len;
17093 conn->content_len = 0;
17096 conn->connection_type = CONNECTION_TYPE_REQUEST; /* Valid request */
17110 if (parse_http_response(conn->buf, conn->buf_size, &conn->response_info)
17124 if (((cl = get_header(conn->response_info.http_headers,
17125 conn->response_info.num_headers,
17126 "Transfer-Encoding"))
17139 conn->is_chunked = 1;
17140 conn->content_len = 0; /* not yet read */
17141 } else if ((cl = get_header(conn->response_info.http_headers,
17142 conn->response_info.num_headers,
17143 "Content-Length"))
17146 conn->content_len = strtoll(cl, &endptr, 10);
17147 if ((endptr == cl) || (conn->content_len < 0)) {
17158 conn->response_info.content_length = conn->content_len;
17161 conn->request_info.content_length = conn->content_len;
17164 if (conn->response_info.status_code == 304) {
17165 conn->content_len = 0;
17169 if (((conn->response_info.status_code >= 100)
17170 && (conn->response_info.status_code <= 199))
17171 || (conn->response_info.status_code == 204)
17172 || (conn->response_info.status_code == 304)) {
17173 conn->content_len = 0;
17175 conn->content_len = -1; /* unknown content length */
17179 conn->connection_type = CONNECTION_TYPE_RESPONSE; /* Valid response */
17206 return -1;
17210 conn->data_len = 0;
17213 save_timeout = conn->dom_ctx->config[REQUEST_TIMEOUT];
17222 conn->dom_ctx->config[REQUEST_TIMEOUT] = new_timeout;
17224 conn->dom_ctx->config[REQUEST_TIMEOUT] = save_timeout;
17229 conn->request_info.uri = conn->request_info.request_uri;
17231 conn->request_info.local_uri = conn->request_info.request_uri;
17233 /* TODO (mid): Define proper return values - maybe return length?
17235 return (ret == 0) ? -1 : +1;
17273 conn->data_len = 0;
17279 conn->request_info.uri = conn->request_info.request_uri;
17281 conn->request_info.local_uri = conn->request_info.request_uri;
17326 mg_set_thread_name("ws-clnt");
17328 if (cdata->conn->phys_ctx) {
17329 if (cdata->conn->phys_ctx->callbacks.init_thread) {
17330 /* 3 indicates a websocket client thread */
17331 /* TODO: check if conn->phys_ctx can be set */
17332 user_thread_ptr = cdata->conn->phys_ctx->callbacks.init_thread(
17333 cdata->conn->phys_ctx, 3);
17337 read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
17341 if (cdata->close_handler != NULL) {
17342 cdata->close_handler(cdata->conn, cdata->callback_data);
17347 cdata->conn->phys_ctx->stop_flag = 2;
17349 if (cdata->conn->phys_ctx->callbacks.exit_thread) {
17350 cdata->conn->phys_ctx->callbacks.exit_thread(cdata->conn->phys_ctx,
17351 3,
17390 "Sec-WebSocket-Key: %s\r\n"
17391 "Sec-WebSocket-Version: 13\r\n"
17399 "Sec-WebSocket-Key: %s\r\n"
17400 "Sec-WebSocket-Version: 13\r\n"
17405 #pragma clang diagnostic push
17406 #pragma clang diagnostic ignored "-Wformat-nonliteral"
17422 #pragma clang diagnostic pop
17438 if (conn->response_info.status_code != 101) {
17458 1, sizeof(struct websocket_client_thread_data), conn->phys_ctx);
17465 thread_data->conn = conn;
17466 thread_data->data_handler = data_func;
17467 thread_data->close_handler = close_func;
17468 thread_data->callback_data = user_data;
17470 conn->phys_ctx->worker_threadids =
17471 (pthread_t *)mg_calloc_ctx(1, sizeof(pthread_t), conn->phys_ctx);
17472 if (!conn->phys_ctx->worker_threadids) {
17480 conn->phys_ctx->user_data = user_data;
17481 conn->phys_ctx->context_type = CONTEXT_WS_CLIENT;
17482 conn->phys_ctx->cfg_worker_threads = 1; /* one worker thread */
17489 conn->phys_ctx->worker_threadids)
17491 conn->phys_ctx->cfg_worker_threads = 0;
17523 !mg_strcasecmp(conn->dom_ctx->config[ENABLE_KEEP_ALIVE], "yes");
17526 conn->must_close = 1;
17531 conn->data_len = 0;
17532 conn->handled_requests = 0;
17536 conn->conn_state = 2; /* init */
17540 if (conn->phys_ctx->callbacks.init_connection != NULL) {
17541 if (conn->phys_ctx->context_type == CONTEXT_SERVER) {
17543 conn->phys_ctx->callbacks.init_connection(conn, &conn_data);
17550 /* Process a connection - may handle multiple requests
17553 * conn->phys_ctx must be valid).
17558 struct mg_request_info *ri = &conn->request_info;
17565 int mcon = mg_atomic_inc(&(conn->phys_ctx->active_connections));
17566 mg_atomic_add(&(conn->phys_ctx->total_connections), 1);
17567 if (mcon > (conn->phys_ctx->max_connections)) {
17570 conn->phys_ctx->max_connections = mcon;
17577 conn->request_info.remote_addr);
17584 conn->handled_requests + 1);
17587 conn->conn_state = 3; /* ready */
17598 } else if (strcmp(ri->http_version, "1.0")
17599 && strcmp(ri->http_version, "1.1")) {
17605 ri->http_version);
17610 uri_type = get_uri_type(conn->request_info.request_uri);
17614 conn->request_info.local_uri = NULL;
17618 conn->request_info.local_uri = conn->request_info.request_uri;
17620 case 3:
17624 conn->request_info.request_uri, conn);
17626 conn->request_info.local_uri = hostend;
17628 conn->request_info.local_uri = NULL;
17638 conn->request_info.local_uri = NULL;
17644 conn->request_info.uri = conn->request_info.local_uri;
17649 (ri->http_version ? ri->http_version : "none"),
17653 if (conn->request_info.local_uri) {
17657 conn->conn_state = 4; /* processing */
17662 conn->conn_state = 5; /* processed */
17664 mg_atomic_add(&(conn->phys_ctx->total_data_read),
17665 conn->consumed_content);
17666 mg_atomic_add(&(conn->phys_ctx->total_data_written),
17667 conn->num_bytes_sent);
17672 if (conn->phys_ctx->callbacks.end_request != NULL) {
17673 conn->phys_ctx->callbacks.end_request(conn,
17674 conn->status_code);
17679 /* TODO: handle non-local request (PROXY) */
17680 conn->must_close = 1;
17683 conn->must_close = 1;
17686 if (ri->remote_user != NULL) {
17687 mg_free((void *)ri->remote_user);
17690 ri->remote_user = NULL;
17699 keep_alive = (conn->phys_ctx->stop_flag == 0) && should_keep_alive(conn)
17700 && (conn->content_len >= 0) && (conn->request_len > 0)
17701 && ((conn->is_chunked == 4)
17702 || (!conn->is_chunked
17703 && ((conn->consumed_content == conn->content_len)
17704 || ((conn->request_len + conn->content_len)
17705 <= conn->data_len))));
17710 ((conn->request_len + conn->content_len) < conn->data_len)
17711 ? (int)(conn->request_len + conn->content_len)
17712 : conn->data_len;
17713 conn->data_len -= discard_len;
17714 if (conn->data_len > 0) {
17716 memmove(conn->buf,
17717 conn->buf + discard_len,
17718 (size_t)conn->data_len);
17722 DEBUG_ASSERT(conn->data_len >= 0);
17723 DEBUG_ASSERT(conn->data_len <= conn->buf_size);
17725 if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
17727 (long int)conn->data_len,
17728 (long int)conn->buf_size);
17732 conn->handled_requests++;
17737 conn->request_info.remote_addr,
17738 difftime(time(NULL), conn->conn_birth_time));
17743 mg_atomic_add(&(conn->phys_ctx->total_requests), conn->handled_requests);
17744 mg_atomic_dec(&(conn->phys_ctx->active_connections));
17756 while (!ctx->stop_flag) {
17757 for (i = 0; i < ctx->cfg_worker_threads; i++) {
17759 if (ctx->client_socks[i].in_use == 2) {
17760 (void)pthread_mutex_lock(&ctx->thread_mutex);
17761 if ((ctx->client_socks[i].in_use == 2) && !ctx->stop_flag) {
17762 ctx->client_socks[i] = *sp;
17763 ctx->client_socks[i].in_use = 1;
17765 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17766 (void)event_signal(ctx->client_wait_events[i]);
17769 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17776 set_blocking_mode(sp->sock);
17777 closesocket(sp->sock);
17785 (void)pthread_mutex_lock(&ctx->thread_mutex);
17786 ctx->client_socks[thread_index].in_use = 2;
17787 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17789 event_wait(ctx->client_wait_events[thread_index]);
17791 (void)pthread_mutex_lock(&ctx->thread_mutex);
17792 *sp = ctx->client_socks[thread_index];
17793 if (ctx->stop_flag) {
17794 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17795 if (sp->in_use == 1) {
17797 set_blocking_mode(sp->sock);
17798 closesocket(sp->sock);
17802 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17803 if (sp->in_use == 1) {
17804 DEBUG_TRACE("grabbed socket %d, going busy", sp->sock);
17818 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17822 (void)pthread_mutex_lock(&ctx->thread_mutex);
17826 while ((ctx->sq_head == ctx->sq_tail) && (ctx->stop_flag == 0)) {
17827 pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
17831 if (ctx->sq_head > ctx->sq_tail) {
17833 *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
17834 ctx->sq_tail++;
17836 DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
17839 while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
17840 ctx->sq_tail -= QUEUE_SIZE(ctx);
17841 ctx->sq_head -= QUEUE_SIZE(ctx);
17845 (void)pthread_cond_signal(&ctx->sq_empty);
17846 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17848 return !ctx->stop_flag;
17857 #define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
17861 (void)pthread_mutex_lock(&ctx->thread_mutex);
17864 while ((ctx->stop_flag == 0)
17865 && (ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx))) {
17866 (void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
17869 if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
17871 ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
17872 ctx->sq_head++;
17873 DEBUG_TRACE("queued socket %d", sp ? sp->sock : -1);
17876 (void)pthread_cond_signal(&ctx->sq_full);
17877 (void)pthread_mutex_unlock(&ctx->thread_mutex);
17886 struct mg_context *ctx = conn->phys_ctx;
17906 if (ctx->callbacks.init_thread) {
17909 tls.user_ptr = ctx->callbacks.init_thread(ctx, 1);
17915 /* Connection structure has been pre-allocated */
17916 thread_index = (int)(conn - ctx->worker_connections);
17918 || ((unsigned)thread_index >= (unsigned)ctx->cfg_worker_threads)) {
17925 /* Request buffers are not pre-allocated. They are private to the
17928 conn->buf = (char *)mg_malloc_ctx(ctx->max_request_size, conn->phys_ctx);
17929 if (conn->buf == NULL) {
17936 conn->buf_size = (int)ctx->max_request_size;
17938 conn->dom_ctx = &(ctx->dd); /* Use default domain and default host */
17939 conn->host = NULL; /* until we have more information. */
17941 conn->tls_user_ptr = tls.user_ptr; /* store ptr for quick access */
17943 conn->request_info.user_data = ctx->user_data;
17947 if (0 != pthread_mutex_init(&conn->mutex, &pthread_mutex_attr)) {
17948 mg_free(conn->buf);
17954 conn->conn_state = 1; /* not consumed */
17957 /* Call consume_socket() even when ctx->stop_flag > 0, to let it
17960 while (consume_socket(ctx, &conn->client, thread_index)) {
17962 conn->conn_birth_time = time(NULL);
17969 if (conn->client.rsa.sa.sa_family == AF_INET6) {
17970 conn->request_info.remote_port =
17971 ntohs(conn->client.rsa.sin6.sin6_port);
17975 conn->request_info.remote_port =
17976 ntohs(conn->client.rsa.sin.sin_port);
17979 sockaddr_to_string(conn->request_info.remote_addr,
17980 sizeof(conn->request_info.remote_addr),
17981 &conn->client.rsa);
17984 conn->request_info.remote_addr);
17986 conn->request_info.is_ssl = conn->client.is_ssl;
17988 if (conn->client.is_ssl) {
17992 conn->dom_ctx->ssl_ctx,
17994 &(conn->phys_ctx->stop_flag),
17996 /* conn->dom_ctx is set in get_request */
18005 if (conn->request_info.client_cert) {
18006 mg_free((void *)(conn->request_info.client_cert->subject));
18007 mg_free((void *)(conn->request_info.client_cert->issuer));
18008 mg_free((void *)(conn->request_info.client_cert->serial));
18009 mg_free((void *)(conn->request_info.client_cert->finger));
18012 (X509 *)conn->request_info.client_cert->peer_cert);
18013 conn->request_info.client_cert->peer_cert = 0;
18014 conn->request_info.client_cert->subject = 0;
18015 conn->request_info.client_cert->issuer = 0;
18016 conn->request_info.client_cert->serial = 0;
18017 conn->request_info.client_cert->finger = 0;
18018 mg_free(conn->request_info.client_cert);
18019 conn->request_info.client_cert = 0;
18036 if (ctx->callbacks.exit_thread) {
18037 ctx->callbacks.exit_thread(ctx, 1, tls.user_ptr);
18045 pthread_mutex_destroy(&conn->mutex);
18048 conn->buf_size = 0;
18049 mg_free(conn->buf);
18050 conn->buf = NULL;
18053 conn->conn_state = 9; /* done */
18087 * valid - a NULL check is not required. */
18098 if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
18111 so.is_ssl = listener->is_ssl;
18112 so.ssl_redir = listener->ssl_redir;
18121 /* Set TCP keep-alive. This is needed because if HTTP-level
18122 * keep-alive
18125 * TCP keep-alive, next keep-alive handshake will figure out that
18149 if ((ctx->dd.config[CONFIG_TCP_NODELAY] != NULL)
18150 && (!strcmp(ctx->dd.config[CONFIG_TCP_NODELAY], "1"))) {
18162 * non-compliant socket implementations. */
18207 if (ctx->callbacks.init_thread) {
18209 tls.user_ptr = ctx->callbacks.init_thread(ctx, 0);
18215 ctx->start_time = time(NULL);
18218 pfd = ctx->listening_socket_fds;
18219 while (ctx->stop_flag == 0) {
18220 for (i = 0; i < ctx->num_listening_sockets; i++) {
18221 pfd[i].fd = ctx->listening_sockets[i].sock;
18225 if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
18226 for (i = 0; i < ctx->num_listening_sockets; i++) {
18232 if ((ctx->stop_flag == 0) && (pfd[i].revents & POLLIN)) {
18233 accept_new_connection(&ctx->listening_sockets[i], ctx);
18239 /* Here stop_flag is 1 - Initiate shutdown. */
18247 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18248 event_signal(ctx->client_wait_events[i]);
18251 (void)pthread_mutex_lock(&ctx->thread_mutex);
18252 pthread_cond_broadcast(&ctx->sq_full);
18253 (void)pthread_mutex_unlock(&ctx->thread_mutex);
18257 workerthreadcount = ctx->cfg_worker_threads;
18259 if (ctx->worker_threadids[i] != 0) {
18260 mg_join_thread(ctx->worker_threadids[i]);
18266 if (ctx->lua_background_state) {
18267 lua_State *lstate = (lua_State *)ctx->lua_background_state;
18269 if (lua_istable(lstate, -1)) {
18275 ctx->lua_background_state = 0;
18282 if (ctx->callbacks.exit_thread) {
18284 ctx->callbacks.exit_thread(ctx, 0, tls.user_ptr);
18295 ctx->stop_flag = 2;
18335 if (ctx->callbacks.exit_context) {
18336 ctx->callbacks.exit_context(ctx);
18342 (void)pthread_mutex_destroy(&ctx->thread_mutex);
18344 mg_free(ctx->client_socks);
18345 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18346 event_destroy(ctx->client_wait_events[i]);
18348 mg_free(ctx->client_wait_events);
18350 (void)pthread_cond_destroy(&ctx->sq_empty);
18351 (void)pthread_cond_destroy(&ctx->sq_full);
18355 (void)pthread_mutex_destroy(&ctx->nonce_mutex);
18363 if (ctx->dd.config[i] != NULL) {
18367 mg_free(ctx->dd.config[i]);
18372 while (ctx->dd.handlers) {
18373 tmp_rh = ctx->dd.handlers;
18374 ctx->dd.handlers = tmp_rh->next;
18375 if (tmp_rh->handler_type == REQUEST_HANDLER) {
18376 pthread_cond_destroy(&tmp_rh->refcount_cond);
18377 pthread_mutex_destroy(&tmp_rh->refcount_mutex);
18379 mg_free(tmp_rh->uri);
18385 if (ctx->dd.ssl_ctx != NULL) {
18386 void *ssl_ctx = (void *)ctx->dd.ssl_ctx;
18388 (ctx->callbacks.external_ssl_ctx == NULL)
18390 : (ctx->callbacks.external_ssl_ctx(&ssl_ctx, ctx->user_data));
18393 SSL_CTX_free(ctx->dd.ssl_ctx);
18401 mg_free(ctx->worker_threadids);
18404 mg_free(ctx->worker_connections);
18407 mg_free(ctx->systemName);
18424 mt = ctx->masterthreadid;
18429 ctx->masterthreadid = 0;
18432 ctx->stop_flag = 1;
18435 while (ctx->stop_flag != 2) {
18560 ctx->dd.auth_nonce_mask =
18563 tls.is_master = -1;
18570 ok = (0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr));
18572 ok &= (0 == pthread_cond_init(&ctx->sq_empty, NULL));
18573 ok &= (0 == pthread_cond_init(&ctx->sq_full, NULL));
18575 ok &= (0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr));
18577 /* Fatal error - abort start. However, this situation should never
18588 ctx->callbacks = *callbacks;
18589 exit_callback = callbacks->exit_context;
18590 ctx->callbacks.exit_context = 0;
18592 ctx->user_data = user_data;
18593 ctx->dd.handlers = NULL;
18594 ctx->dd.next = NULL;
18597 ctx->dd.shared_lua_websockets = NULL;
18602 if ((idx = get_option_index(name)) == -1) {
18613 if (ctx->dd.config[idx] != NULL) {
18615 mg_free(ctx->dd.config[idx]);
18617 ctx->dd.config[idx] = mg_strdup_ctx(value, ctx);
18618 DEBUG_TRACE("[%s] -> [%s]", name, value);
18624 if ((ctx->dd.config[i] == NULL) && (default_value != NULL)) {
18625 ctx->dd.config[i] = mg_strdup_ctx(default_value, ctx);
18630 itmp = atoi(ctx->dd.config[MAX_REQUEST_SIZE]);
18637 ctx->max_request_size = (unsigned)itmp;
18640 workerthreadcount = atoi(ctx->dd.config[NUM_THREADS]);
18658 if (ctx->dd.config[DOCUMENT_ROOT] != NULL) {
18666 get_system_name(&ctx->systemName);
18670 if (ctx->dd.config[LUA_BACKGROUND_SCRIPT] != NULL) {
18676 ctx->dd.config[LUA_BACKGROUND_SCRIPT], ctx, ebuf, sizeof(ebuf));
18683 ctx->lua_background_state = (void *)state;
18688 sparams = ctx->dd.config[LUA_BACKGROUND_SCRIPT_PARAMS];
18699 ctx->lua_background_state = 0;
18722 ctx->cfg_worker_threads = ((unsigned int)(workerthreadcount));
18723 ctx->worker_threadids = (pthread_t *)mg_calloc_ctx(ctx->cfg_worker_threads,
18727 if (ctx->worker_threadids == NULL) {
18735 ctx->worker_connections =
18736 (struct mg_connection *)mg_calloc_ctx(ctx->cfg_worker_threads,
18739 if (ctx->worker_connections == NULL) {
18749 ctx->client_wait_events =
18750 (void **)mg_calloc_ctx(ctx->cfg_worker_threads,
18751 sizeof(ctx->client_wait_events[0]),
18753 if (ctx->client_wait_events == NULL) {
18757 mg_free(ctx->worker_threadids);
18763 ctx->client_socks =
18764 (struct socket *)mg_calloc_ctx(ctx->cfg_worker_threads,
18765 sizeof(ctx->client_socks[0]),
18767 if (ctx->client_socks == NULL) {
18771 mg_free(ctx->client_wait_events);
18772 mg_free(ctx->worker_threadids);
18778 for (i = 0; (unsigned)i < ctx->cfg_worker_threads; i++) {
18779 ctx->client_wait_events[i] = event_create();
18780 if (ctx->client_wait_events[i] == 0) {
18783 i--;
18784 event_destroy(ctx->client_wait_events[i]);
18786 mg_free(ctx->client_socks);
18787 mg_free(ctx->client_wait_events);
18788 mg_free(ctx->worker_threadids);
18806 /* Context has been created - init user libraries */
18807 if (ctx->callbacks.init_context) {
18808 ctx->callbacks.init_context(ctx);
18810 ctx->callbacks.exit_context = exit_callback;
18811 ctx->context_type = CONTEXT_SERVER; /* server context */
18814 mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
18817 for (i = 0; i < ctx->cfg_worker_threads; i++) {
18819 ctx->worker_connections[i].phys_ctx = ctx;
18821 &ctx->worker_connections[i],
18822 &ctx->worker_threadids[i])
18860 if ((ctx == NULL) || (ctx->stop_flag != 0) || (options == NULL)) {
18861 return -1;
18869 return -6;
18872 /* Store options - TODO: unite duplicate code */
18874 if ((idx = get_option_index(name)) == -1) {
18877 return -2;
18881 return -2;
18883 if (new_dom->config[idx] != NULL) {
18885 mg_free(new_dom->config[idx]);
18887 new_dom->config[idx] = mg_strdup_ctx(value, ctx);
18888 DEBUG_TRACE("[%s] -> [%s]", name, value);
18893 if (!new_dom->config[AUTHENTICATION_DOMAIN]) {
18896 return -4;
18902 default_value = ctx->dd.config[i];
18903 if ((new_dom->config[i] == NULL) && (default_value != NULL)) {
18904 new_dom->config[i] = mg_strdup_ctx(default_value, ctx);
18908 new_dom->handlers = NULL;
18909 new_dom->next = NULL;
18910 new_dom->nonce_count = 0;
18911 new_dom->auth_nonce_mask =
18915 new_dom->shared_lua_websockets = NULL;
18921 return -3;
18928 dom = &(ctx->dd);
18930 if (!mg_strcasecmp(new_dom->config[AUTHENTICATION_DOMAIN],
18931 dom->config[AUTHENTICATION_DOMAIN])) {
18935 new_dom->config[AUTHENTICATION_DOMAIN]);
18937 return -5;
18943 if (dom->next == NULL) {
18944 dom->next = new_dom;
18947 dom = dom->next;
19028 if ((size_t)(end - *dst) > len) {
19060 if (buflen > (int)(sizeof(eoobj) - 1)) {
19063 end -= sizeof(eoobj) - 1;
19143 ",%s\"os\" : \"%s %s (%s) - %s\"",
19206 /* Disable bogus compiler warning -Wdate-time, appeared in gcc5 */
19207 #pragma GCC diagnostic ignored "-Wdate-time"
19275 ",%s\"compiler\" : \"clang: %u.%u.%u (%s)\"",
19332 * see https://en.wikipedia.org/wiki/64-bit_computing */
19361 system_info_length += sizeof(eoobj) - 1;
19390 if (buflen > (int)(sizeof(eoobj) - 1)) {
19393 end -= sizeof(eoobj) - 1;
19398 if (ms) { /* <-- should be always true */
19411 ms->blockCount,
19413 ms->totalMemUsed,
19415 ms->maxMemUsed,
19425 time_t start_time = ctx->start_time;
19440 ctx->active_connections,
19442 ctx->max_connections,
19444 ctx->total_connections,
19458 ctx->total_requests,
19473 ctx->total_data_read,
19475 ctx->total_data_written,
19481 sizeof(start_time_str) - 1,
19483 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
19509 context_info_length += sizeof(eoobj) - 1;
19551 if (buflen > (int)(sizeof(eoobj) - 1)) {
19554 end -= sizeof(eoobj) - 1;
19562 if ((unsigned)idx >= ctx->cfg_worker_threads) {
19569 conn = (ctx->worker_connections) + idx;
19575 ri = &(conn->request_info);
19578 state = conn->conn_state;
19591 case 3:
19616 if ((state >= 3) && (state < 9)) {
19634 ri->remote_addr,
19636 ri->remote_port,
19639 conn->handled_requests,
19658 ri->request_method,
19660 ri->request_uri,
19662 ri->query_string ? "\"" : "",
19663 ri->query_string ? ri->query_string : "null",
19664 ri->query_string ? "\"" : "",
19673 time_t start_time = conn->conn_birth_time;
19677 sizeof(start_time_str) - 1,
19679 gmt_time_string(now_str, sizeof(now_str) - 1, &now);
19703 if ((ri->remote_user) && (state < 9)) {
19714 ri->remote_user,
19720 if (state >= 3) {
19732 conn->consumed_content,
19734 conn->num_bytes_sent,
19754 connection_info_length += sizeof(eoobj) - 1;
19784 /* Fatal error - abort start. However, this situation should
19837 /* Un-initialize this library. */
19847 mg_init_library_called--;