31#if !defined(_CRT_SECURE_NO_WARNINGS)
32#define _CRT_SECURE_NO_WARNINGS
36#define _XOPEN_SOURCE 600
38#if !defined(_LARGEFILE_SOURCE)
39#define _LARGEFILE_SOURCE
41#define __STDC_FORMAT_MACROS
42#define __STDC_LIMIT_MACROS
47#pragma warning (disable : 4127)
49#pragma warning (disable : 4204)
54#ifdef WIN32_LEAN_AND_MEAN
55#undef WIN32_LEAN_AND_MEAN
58#if defined(__SYMBIAN32__)
61#define PATH_MAX FILENAME_MAX
82#if defined(_WIN32) && !defined(__SYMBIAN32__)
84#define _WIN32_WINNT 0x0400
88#define PATH_MAX MAX_PATH
100#define errno GetLastError()
101#define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
104#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
105 ((uint64_t)((uint32_t)(hi))) << 32))
106#define RATE_DIFF 10000000
107#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
108#define SYS2UNIX_TIME(lo, hi) \
109 (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
114#if defined(_MSC_VER) && _MSC_VER < 1300
116#define STR(x) STRX(x)
117#define __func__ __FILE__ ":" STR(__LINE__)
118#define strtoull(x, y, z) (unsigned __int64) _atoi64(x)
119#define strtoll(x, y, z) _atoi64(x)
121#define __func__ __FUNCTION__
122#define strtoull(x, y, z) _strtoui64(x, y, z)
123#define strtoll(x, y, z) _strtoi64(x, y, z)
126#define ERRNO GetLastError()
128#define SSL_LIB "ssleay32.dll"
129#define CRYPTO_LIB "libeay32.dll"
131#if !defined(EWOULDBLOCK)
132#define EWOULDBLOCK WSAEWOULDBLOCK
135#define INT64_FMT "I64d"
137#define WINCDECL __cdecl
139#define snprintf _snprintf
140#define vsnprintf _vsnprintf
141#define mg_sleep(x) Sleep(x)
143#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
145#define popen(x, y) _popen(x, y)
148#define pclose(x) _pclose(x)
150#define close(x) _close(x)
151#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
153#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
154#define fdopen(x, y) _fdopen((x), (y))
155#define write(x, y, z) _write((x), (y), (unsigned) z)
156#define read(x, y, z) _read((x), (y), (unsigned) z)
158#define funlockfile(x)
159#define sleep(x) Sleep((x) * 1000)
160#define rmdir(x) _rmdir(x)
163#define va_copy(x, y) x = y
167#define fileno(x) _fileno(x)
170typedef HANDLE pthread_mutex_t;
171typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
172typedef DWORD pthread_t;
175static int pthread_mutex_lock(pthread_mutex_t *);
176static int pthread_mutex_unlock(pthread_mutex_t *);
177static void to_unicode(
const char *path,
wchar_t *wbuf,
size_t wbuf_len);
179#if defined(HAVE_STDINT)
182typedef unsigned int uint32_t;
183typedef unsigned short uint16_t;
184typedef unsigned __int64 uint64_t;
185typedef __int64 int64_t;
186#define INT64_MAX 9223372036854775807
196 WIN32_FIND_DATAW
info;
197 struct dirent result;
212#pragma comment(lib, "Ws2_32.lib")
217#include <sys/socket.h>
219#include <netinet/in.h>
220#include <arpa/inet.h>
229#if !defined(NO_SSL_DL) && !defined(NO_SSL)
234#define SSL_LIB "libssl.dylib"
235#define CRYPTO_LIB "libcrypto.dylib"
238#define SSL_LIB "libssl.so"
240#if !defined(CRYPTO_LIB)
241#define CRYPTO_LIB "libcrypto.so"
247#define closesocket(a) close(a)
248#define mg_mkdir(x, y) mkdir(x, y)
249#define mg_remove(x) remove(x)
250#define mg_sleep(x) usleep((x) * 1000)
252#define INVALID_SOCKET (-1)
253#define INT64_FMT PRId64
261#define MONGOOSE_VERSION "4.2"
262#define PASSWORDS_FILE_NAME ".htpasswd"
263#define CGI_ENVIRONMENT_SIZE 4096
264#define MAX_CGI_ENVIR_VARS 64
265#define MG_BUF_LEN 8192
266#define MAX_REQUEST_SIZE 16384
267#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
271#define DEBUG_TRACE(x)
274#define DEBUG_TRACE(x) do { \
276 printf("*** %lu.%p.%s.%d: ", \
277 (unsigned long) time(NULL), (void *) pthread_self(), \
278 __func__, __LINE__); \
282 funlockfile(stdout); \
285#define DEBUG_TRACE(x)
291typedef int socklen_t;
293#define _DARWIN_UNLIMITED_SELECT
295#define IP_ADDR_STR_LEN 50
297#if !defined(MSG_NOSIGNAL)
298#define MSG_NOSIGNAL 0
301#if !defined(SOMAXCONN)
305#if !defined(PATH_MAX)
315#if !defined(EXTRA_HTTP_HEADERS)
316#define EXTRA_HTTP_HEADERS ""
321#if defined(NO_SSL_DL)
322#include <openssl/ssl.h>
323#include <openssl/err.h>
327typedef struct ssl_st
SSL;
328typedef struct ssl_method_st SSL_METHOD;
329typedef struct ssl_ctx_st
SSL_CTX;
332#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L
335#define SSL_OP_SINGLE_ECDH_USE 0x00080000L
337#define SSL_OP_SINGLE_DH_USE 0x00100000L
339#define SSL_OP_NO_SSLv2 0x01000000L
340#define SSL_OP_NO_SSLv3 0x02000000L
341#define SSL_OP_NO_TLSv1 0x04000000L
342#define SSL_OP_NO_TLSv1_2 0x08000000L
343#define SSL_OP_NO_TLSv1_1 0x10000000L
347#define NID_X9_62_prime256v1 415
349#define SSL_CTRL_SET_TMP_RSA 2
350#define SSL_CTRL_SET_TMP_DH 3
351#define SSL_CTRL_SET_TMP_ECDH 4
352#define SSL_CTRL_SET_TMP_RSA_CB 5
353#define SSL_CTRL_SET_TMP_DH_CB 6
354#define SSL_CTRL_SET_TMP_ECDH_CB 7
356#define SSL_CTRL_OPTIONS 32
358#define SSL_CTX_set_options(ctx,op) SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
359#define SSL_CTX_clear_options(ctx,op) SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
360#define SSL_CTX_get_options(ctx) SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
362#define SSL_CTX_set_tmp_dh(ctx,dh) SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
363#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
370#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
371#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
372#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
373#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
374#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
375#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
376#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
377#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
378#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
379#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
380#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
381#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
382 const char *, int)) ssl_sw[11].ptr)
383#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
384 const char *, int)) ssl_sw[12].ptr)
385#define SSL_CTX_set_default_passwd_cb \
386 (* (void (*)(SSL_CTX *, mg_event_handler_t)) ssl_sw[13].ptr)
387#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
388#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
389#define SSL_CTX_use_certificate_chain_file \
390 (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
391#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
392#define SSL_pending (* (int (*)(SSL *)) ssl_sw[18].ptr)
393#define SSL_CTX_set_verify (* (void (*)(SSL_CTX *, int, int)) ssl_sw[19].ptr)
394#define SSL_shutdown (* (int (*)(SSL *)) ssl_sw[20].ptr)
395#define SSL_CTX_ctrl (* (int (*)(SSL_CTX *ctx, int cmd, long larg, void *parg)) ssl_sw[21].ptr)
396#define SSL_CTX_set_cipher_list (* (int (*)(SSL_CTX *ctx, const char *str)) ssl_sw[22].ptr)
397#define EC_KEY_new_by_curve_name (* (EC_KEY* (*)(int nid)) ssl_sw[23].ptr)
398#define EC_KEY_free (* (int (*)(EC_KEY *)) ssl_sw[24].ptr)
399#define SSL_get_cipher_list (* (const char* (*)(const SSL*, int)) ssl_sw[25].ptr)
401#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
402#define CRYPTO_set_locking_callback \
403 (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
404#define CRYPTO_set_id_callback \
405 (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
406#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
407#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
416 struct sockaddr_in6 sin6;
434#define STRUCT_FILE_INITIALIZER { 0, 0, 0, 0 }
508static FILE *
mg_fopen(
const char *path,
const char *mode);
509static int mg_stat(
const char *path,
struct file *filep);
518#include "lua_5.2.1.h"
519static int handle_lsp_request(
struct mg_connection *,
const char *,
520 struct file *,
struct lua_State *);
527 fake_connection.
ctx =
ctx;
530 return &fake_connection;
533static void mg_strlcpy(
register char *dst,
register const char *src,
size_t n) {
534 for (; *src !=
'\0' &&
n > 1;
n--) {
541 return tolower(* (
const unsigned char *) s);
550 }
while (diff == 0 && s1[-1] !=
'\0' && --len > 0);
560 }
while (diff == 0 && s1[-1] !=
'\0');
568 if ((p = (
char *) malloc(len + 1)) != NULL) {
579static const char *
mg_strcasestr(
const char *big_str,
const char *small_str) {
580 int i, big_len = strlen(big_str), small_len = strlen(small_str);
582 for (
i = 0;
i <= big_len - small_len;
i++) {
602 n = vsnprintf(
buf, buflen, fmt, ap);
606 }
else if (
n >= (
int) buflen) {
607 n = (int) buflen - 1;
633 const char *whitespace,
char quotechar) {
634 char *p, *begin_word, *end_word, *end_whitespace;
637 end_word = begin_word + strcspn(begin_word, delimiters);
640 if (end_word > begin_word) {
642 while (*p == quotechar) {
644 if (*end_word ==
'\0') {
648 size_t end_off = strcspn(end_word + 1, delimiters);
649 memmove (p, end_word, end_off + 1);
651 end_word += end_off + 1;
654 for (p++; p < end_word; p++) {
659 if (*end_word ==
'\0') {
662 end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
664 for (p = end_word; p < end_whitespace; p++) {
668 *
buf = end_whitespace;
676static char *
skip(
char **
buf,
const char *delimiters) {
704 struct vec *eq_val) {
705 if (
list == NULL || *
list ==
'\0') {
710 if ((
list = strchr(val->
ptr,
',')) != NULL) {
720 if (eq_val != NULL) {
724 eq_val->
ptr = (
const char *) memchr(val->
ptr,
'=', val->
len);
725 if (eq_val->
ptr != NULL) {
741 if ((or_str = (
const char *) memchr(pattern,
'|', pattern_len)) != NULL) {
743 return res > 0 ? res :
749 for (;
i < pattern_len;
i++,
j++) {
750 if (pattern[
i] ==
'?' &&
str[
j] !=
'\0') {
752 }
else if (pattern[
i] ==
'$') {
753 return str[
j] ==
'\0' ?
j : -1;
754 }
else if (pattern[
i] ==
'*') {
756 if (pattern[
i] ==
'*') {
758 len = (int) strlen(
str +
j);
760 len = (int) strcspn(
str +
j,
"/");
762 if (
i == pattern_len) {
767 }
while (res == -1 && len-- > 0);
768 return res == -1 ? -1 :
j + res + len;
778 "Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
779 "Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
794 return year / 4 - year / 100 + year / 400;
799 static const unsigned short days_before_month[] = {
800 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
803 int second, minute, hour, day, month, year, leap_days, days;
804 time_t result = (time_t) 0;
806 if (((sscanf(datetime,
"%d/%3s/%d %d:%d:%d",
807 &day, month_str, &year, &hour, &minute, &second) == 6) ||
808 (sscanf(datetime,
"%d %3s %d %d:%d:%d",
809 &day, month_str, &year, &hour, &minute, &second) == 6) ||
810 (sscanf(datetime,
"%*3s, %d %3s %d %d:%d:%d",
811 &day, month_str, &year, &hour, &minute, &second) == 6) ||
812 (sscanf(datetime,
"%d-%3s-%d %d:%d:%d",
813 &day, month_str, &year, &hour, &minute, &second) == 6)) &&
818 days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
819 result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
827 "cgi_pattern",
"**.cgi$|**.pl$|**.php$",
828 "cgi_environment", NULL,
829 "put_delete_auth_file", NULL,
830 "cgi_interpreter", NULL,
832 "authentication_domain",
"mydomain.com",
833 "ssi_pattern",
"**.shtml$|**.shtm$",
835 "access_log_file", NULL,
836 "enable_directory_listing",
"yes",
837 "error_log_file", NULL,
838 "global_auth_file", NULL,
840 "index.html,index.htm,index.cgi,index.shtml,index.php,index.lp",
841 "enable_keep_alive",
"no",
842 "access_control_list", NULL,
843 "extra_mime_types", NULL,
844 "listening_ports",
"8080",
845 "document_root", NULL,
846 "ssl_certificate", NULL,
849 "url_rewrite_patterns", NULL,
850 "hide_files_patterns", NULL,
851 "request_timeout_ms",
"30000",
881 static const int n = 1;
882 return ((
char *) &
n)[0] == 0;
889 unsigned char in[64];
898 t = (uint32_t) ((
unsigned) buf[3] << 8 | buf[2]) << 16 |
899 ((
unsigned) buf[1] << 8 | buf[0]);
900 * (uint32_t *) buf = t;
906#define F1(x, y, z) (z ^ (x & (y ^ z)))
907#define F2(x, y, z) F1(z, x, y)
908#define F3(x, y, z) (x ^ y ^ z)
909#define F4(x, y, z) (y ^ (x | ~z))
911#define MD5STEP(f, w, x, y, z, data, s) \
912 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
917 ctx->
buf[0] = 0x67452301;
918 ctx->
buf[1] = 0xefcdab89;
919 ctx->
buf[2] = 0x98badcfe;
920 ctx->
buf[3] = 0x10325476;
927 register uint32_t a, b,
c,
d;
1012 if ((ctx->
bits[0] = t + ((uint32_t) len << 3)) < t)
1014 ctx->
bits[1] += len >> 29;
1016 t = (t >> 3) & 0x3f;
1019 unsigned char *p = (
unsigned char *) ctx->
in + t;
1023 memcpy(p, buf, len);
1034 memcpy(ctx->
in, buf, 64);
1041 memcpy(ctx->
in, buf, len);
1055 memset(p, 0,
count);
1058 memset(ctx->
in, 0, 56);
1060 memset(p, 0,
count - 8);
1064 a = (uint32_t *)ctx->
in;
1065 a[14] = ctx->
bits[0];
1066 a[15] = ctx->
bits[1];
1070 memcpy(digest, ctx->
buf, 16);
1071 memset((
char *) ctx, 0,
sizeof(*ctx));
1079static void bin2str(
char *to,
const unsigned char *p,
size_t len) {
1080 static const char *hex =
"0123456789abcdef";
1082 for (; len--; p++) {
1083 *to++ = hex[p[0] >> 4];
1084 *to++ = hex[p[0] & 0x0f];
1091 unsigned char hash[16];
1099 while ((p = va_arg(ap,
const char *)) != NULL) {
1100 MD5Update(&ctx, (
const unsigned char *) p, (
unsigned) strlen(p));
1105 bin2str(buf, hash,
sizeof(hash));
1111 const char *nonce,
const char *nc,
const char *cnonce,
1112 const char *qop,
const char *
response) {
1113 char ha2[32 + 1], expected_response[32 + 1];
1116 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
1130 mg_md5(ha2, method,
":", uri, NULL);
1131 mg_md5(expected_response, ha1,
":", nonce,
":", nc,
1132 ":", cnonce,
":", qop,
":", ha2, NULL);
1145 if (gpass != NULL) {
1156 for (p = path,
e = p + strlen(p) - 1;
e > p;
e--)
1174 size_t buf_size,
struct ah *
ah) {
1176 const char *auth_header;
1178 (void) memset(
ah, 0,
sizeof(*
ah));
1179 if ((auth_header =
mg_get_header(conn,
"Authorization")) == NULL ||
1185 (void)
mg_strlcpy(buf, auth_header + 7, buf_size);
1191 while (isspace(* (
unsigned char *) s)) {
1205 if (*
name ==
'\0') {
1209 if (!strcmp(
name,
"username")) {
1211 }
else if (!strcmp(
name,
"cnonce")) {
1213 }
else if (!strcmp(
name,
"response")) {
1215 }
else if (!strcmp(
name,
"uri")) {
1217 }
else if (!strcmp(
name,
"qop")) {
1219 }
else if (!strcmp(
name,
"nc")) {
1221 }
else if (!strcmp(
name,
"nonce")) {
1239 char line[256], f_user[256], ha1[256], f_domain[256], buf[
MG_BUF_LEN];
1246 while (fgets(line,
sizeof(line),
fp) != NULL) {
1247 if (sscanf(line,
"%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
1251 if (!strcmp(
ah.
user, f_user) &&
1263 struct vec uri_vec, filename_vec;
1272 (
int) filename_vec.
len, filename_vec.
ptr);
1293 "HTTP/1.1 401 Unauthorized\r\n"
1294 "Content-Length: 0\r\n"
1295 "WWW-Authenticate: Digest qop=\"auth\", "
1296 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
1298 (
unsigned long) time(NULL));
1306 if (passfile != NULL && (
fp =
mg_fopen(passfile,
"r")) != NULL) {
1315 const char *user,
const char *pass) {
1317 char line[512], u[512],
d[512], ha1[33], tmp[
PATH_MAX];
1324 if (pass != NULL && pass[0] ==
'\0') {
1328 (void) snprintf(tmp,
sizeof(tmp),
"%s.tmp", fname);
1331 if ((
fp = fopen(fname,
"a+")) != NULL) {
1336 if ((
fp = fopen(fname,
"r")) == NULL) {
1338 }
else if ((fp2 = fopen(tmp,
"w+")) == NULL) {
1344 while (fgets(line,
sizeof(line),
fp) != NULL) {
1345 if (sscanf(line,
"%[^:]:%[^:]:%*s", u,
d) != 2) {
1349 if (!strcmp(u, user) && !strcmp(
d, domain)) {
1352 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
1353 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
1356 fprintf(fp2,
"%s", line);
1361 if (!found && pass != NULL) {
1362 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
1363 fprintf(fp2,
"%s:%s:%s\n", user, domain, ha1);
1378static pthread_t pthread_self(
void) {
1379 return GetCurrentThreadId();
1382static int pthread_mutex_init(pthread_mutex_t *mutex,
void *unused) {
1384 *mutex = CreateMutex(NULL,
FALSE, NULL);
1385 return *mutex == NULL ? -1 : 0;
1388static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
1389 return CloseHandle(*mutex) == 0 ? -1 : 0;
1392static int pthread_mutex_lock(pthread_mutex_t *mutex) {
1393 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1396static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
1397 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
1400static int pthread_cond_init(pthread_cond_t *cv,
const void *unused) {
1402 cv->signal = CreateEvent(NULL,
FALSE,
FALSE, NULL);
1403 cv->broadcast = CreateEvent(NULL,
TRUE,
FALSE, NULL);
1404 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
1407static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
1408 HANDLE handles[] = {cv->signal, cv->broadcast};
1409 ReleaseMutex(*mutex);
1410 WaitForMultipleObjects(2, handles,
FALSE, INFINITE);
1411 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1414static int pthread_cond_signal(pthread_cond_t *cv) {
1415 return SetEvent(cv->signal) == 0 ? -1 : 0;
1418static int pthread_cond_broadcast(pthread_cond_t *cv) {
1421 return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
1424static int pthread_cond_destroy(pthread_cond_t *cv) {
1425 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
1429static void change_slashes_to_backslashes(
char *path) {
1432 for (
i = 0; path[
i] !=
'\0';
i++) {
1436 if (path[
i] ==
'\\' &&
i > 0)
1437 while (path[
i + 1] ==
'\\' || path[
i + 1] ==
'/')
1438 (void) memmove(path +
i + 1,
1439 path +
i + 2, strlen(path +
i + 1));
1445static void to_unicode(
const char *path,
wchar_t *wbuf,
size_t wbuf_len) {
1449 change_slashes_to_backslashes(buf);
1453 memset(wbuf, 0, wbuf_len *
sizeof(
wchar_t));
1454 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (
int) wbuf_len);
1455 WideCharToMultiByte(CP_UTF8, 0, wbuf, (
int) wbuf_len, buf2,
sizeof(buf2),
1457 if (strcmp(buf, buf2) != 0) {
1462#if defined(_WIN32_WCE)
1463static time_t time(time_t *ptime) {
1469 SystemTimeToFileTime(&st, &ft);
1470 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
1472 if (ptime != NULL) {
1479static struct tm *
localtime(
const time_t *ptime,
struct tm *ptm) {
1480 int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
1483 TIME_ZONE_INFORMATION tzinfo;
1489 * (int64_t *) &ft = t;
1490 FileTimeToLocalFileTime(&ft, &lft);
1491 FileTimeToSystemTime(&lft, &st);
1492 ptm->tm_year = st.wYear - 1900;
1493 ptm->tm_mon = st.wMonth - 1;
1494 ptm->tm_wday = st.wDayOfWeek;
1495 ptm->tm_mday = st.wDay;
1496 ptm->tm_hour = st.wHour;
1497 ptm->tm_min = st.wMinute;
1498 ptm->tm_sec = st.wSecond;
1501 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
1506static struct tm *
gmtime(
const time_t *ptime,
struct tm *ptm) {
1511static size_t strftime(
char *dst,
size_t dst_size,
const char *fmt,
1512 const struct tm *
tm) {
1513 (void) snprintf(dst, dst_size,
"implement strftime() for WinCE");
1522static int path_cannot_disclose_cgi(
const char *path) {
1523 static const char *allowed_last_characters =
"_-";
1524 int last = path[strlen(path) - 1];
1525 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
1528static int mg_stat(
const char *path,
struct file *filep) {
1529 wchar_t wbuf[
PATH_MAX] = L
"\\\\?\\";
1530 WIN32_FILE_ATTRIBUTE_DATA
info;
1533 to_unicode(path, wbuf + 4,
ARRAY_SIZE(wbuf) - 4);
1534 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &
info) != 0) {
1535 filep->
size = MAKEUQUAD(
info.nFileSizeLow,
info.nFileSizeHigh);
1537 info.ftLastWriteTime.dwLowDateTime,
1538 info.ftLastWriteTime.dwHighDateTime);
1543 if (!filep->
is_directory && !path_cannot_disclose_cgi(path)) {
1544 memset(filep, 0,
sizeof(*filep));
1554 return DeleteFileW(wbuf) ? 0 : -1;
1557static int mg_mkdir(
const char *path,
int mode) {
1563 change_slashes_to_backslashes(buf);
1565 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf,
ARRAY_SIZE(wbuf));
1567 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1571static DIR * opendir(
const char *
name) {
1577 SetLastError(ERROR_BAD_ARGUMENTS);
1578 }
else if ((dir = (
DIR *) malloc(
sizeof(*dir))) == NULL) {
1579 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1582 attrs = GetFileAttributesW(wpath);
1583 if (attrs != 0xFFFFFFFF &&
1584 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1585 (void) wcscat(wpath, L
"\\*");
1586 dir->handle = FindFirstFileW(wpath, &dir->info);
1587 dir->result.d_name[0] =
'\0';
1597static int closedir(
DIR *dir) {
1601 if (dir->handle != INVALID_HANDLE_VALUE)
1602 result = FindClose(dir->handle) ? 0 : -1;
1607 SetLastError(ERROR_BAD_ARGUMENTS);
1613static struct dirent *readdir(
DIR *dir) {
1614 struct dirent *result = 0;
1617 if (dir->handle != INVALID_HANDLE_VALUE) {
1618 result = &dir->result;
1619 (void) WideCharToMultiByte(CP_UTF8, 0,
1620 dir->info.cFileName, -1, result->d_name,
1621 sizeof(result->d_name), NULL, NULL);
1623 if (!FindNextFileW(dir->handle, &dir->info)) {
1624 (void) FindClose(dir->handle);
1625 dir->handle = INVALID_HANDLE_VALUE;
1629 SetLastError(ERROR_FILE_NOT_FOUND);
1632 SetLastError(ERROR_BAD_ARGUMENTS);
1639static int poll(
struct pollfd *pfd,
int n,
int milliseconds) {
1645 tv.tv_sec = milliseconds / 1000;
1646 tv.tv_usec = (milliseconds % 1000) * 1000;
1649 for (
i = 0;
i <
n;
i++) {
1653 if (pfd[
i].fd > maxfd) {
1658 if ((result = select(maxfd + 1, &
set, NULL, NULL, &
tv)) > 0) {
1659 for (
i = 0;
i <
n;
i++) {
1660 if (FD_ISSET(pfd[
i].fd, &
set)) {
1661 pfd[
i].revents = POLLIN;
1671 (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
1675 return (
long)_beginthread((
void (__cdecl *)(
void *)) f, 0, p) == -1L ? -1 : 0;
1678static HANDLE dlopen(
const char *dll_name,
int flags) {
1681 to_unicode(dll_name, wbuf,
ARRAY_SIZE(wbuf));
1682 return LoadLibraryW(wbuf);
1687static int kill(pid_t pid,
int sig_num) {
1688 (void) TerminateProcess(pid, sig_num);
1689 (void) CloseHandle(pid);
1693static void trim_trailing_whitespaces(
char *s) {
1694 char *
e = s + strlen(s) - 1;
1695 while (
e > s && isspace(* (
unsigned char *)
e)) {
1701 char *envblk,
char *envp[],
int fdin,
1702 int fdout,
const char *dir) {
1708 PROCESS_INFORMATION
pi = { 0 };
1712 memset(&si, 0,
sizeof(si));
1716 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1717 si.wShowWindow = SW_HIDE;
1719 me = GetCurrentProcess();
1720 DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
1721 &si.hStdInput, 0,
TRUE, DUPLICATE_SAME_ACCESS);
1722 DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
1723 &si.hStdOutput, 0,
TRUE, DUPLICATE_SAME_ACCESS);
1727 if (interp == NULL) {
1728 buf[0] = buf[1] =
'\0';
1731 snprintf(cmdline,
sizeof(cmdline),
"%s%c%s", dir,
'/', prog);
1733 fgets(buf,
sizeof(buf),
fp);
1735 buf[
sizeof(buf) - 1] =
'\0';
1738 if (buf[0] ==
'#' && buf[1] ==
'!') {
1739 trim_trailing_whitespaces(buf + 2);
1746 if (interp[0] !=
'\0') {
1747 GetFullPathNameA(interp,
sizeof(full_interp), full_interp, NULL);
1748 interp = full_interp;
1750 GetFullPathNameA(dir,
sizeof(full_dir), full_dir, NULL);
1752 mg_snprintf(cmdline,
sizeof(cmdline),
"%s%s\"%s\\%s\"",
1753 interp, interp[0] ==
'\0' ?
"" :
" ", full_dir, prog);
1756 if (CreateProcessA(NULL, cmdline, NULL, NULL,
TRUE,
1757 CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &
pi) == 0) {
1758 cry(conn,
"%s: CreateProcess(%s): %ld",
1759 __func__, cmdline,
ERRNO);
1760 pi.hProcess = (pid_t) -1;
1763 (void) CloseHandle(si.hStdOutput);
1764 (void) CloseHandle(si.hStdInput);
1765 (void) CloseHandle(
pi.hThread);
1767 return (pid_t)
pi.hProcess;
1772 unsigned long on = 1;
1773 return ioctlsocket(sock, FIONBIO, &on);
1782 if (stat(path, &st) == 0) {
1783 filep->
size = st.st_size;
1799 fcntl(fd, F_SETFD, FD_CLOEXEC);
1803 pthread_t thread_id;
1804 pthread_attr_t attr;
1807 (void) pthread_attr_init(&attr);
1808 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1810#if USE_STACK_SIZE > 1
1812 (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
1815 result = pthread_create(&thread_id, &attr, func,
param);
1816 pthread_attr_destroy(&attr);
1823 char *envblk,
char *envp[],
int fdin,
1824 int fdout,
const char *dir) {
1830 if ((pid = fork()) == -1) {
1833 }
else if (pid == 0) {
1835 if (chdir(dir) != 0) {
1836 cry(conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
1837 }
else if (dup2(fdin, 0) == -1) {
1838 cry(conn,
"%s: dup2(%d, 0): %s", __func__, fdin, strerror(
ERRNO));
1839 }
else if (dup2(fdout, 1) == -1) {
1840 cry(conn,
"%s: dup2(%d, 1): %s", __func__, fdout, strerror(
ERRNO));
1845 (void) close(fdout);
1851 signal(SIGCHLD, SIG_DFL);
1854 if (interp == NULL) {
1855 (void) execle(prog, prog, NULL, envp);
1856 cry(conn,
"%s: execle(%s): %s", __func__, prog, strerror(
ERRNO));
1858 (void) execle(interp, interp, prog, NULL, envp);
1859 cry(conn,
"%s: execle(%s %s): %s", __func__, interp, prog,
1873 flags = fcntl(sock, F_GETFL, 0);
1874 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1893 va_copy(ap_copy, ap);
1894 len = vsnprintf(NULL, 0, fmt, ap_copy);
1896 if (len > (
int) size &&
1897 (size = len + 1) > 0 &&
1898 (*buf = (
char *) malloc(size)) == NULL) {
1901 va_copy(ap_copy, ap);
1902 vsnprintf(*buf, size, fmt, ap_copy);
1912 if ((len =
alloc_vprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
1913 len =
mg_write(conn, buf, (
size_t) len);
1915 if (buf != mem && buf != NULL) {
1934 if ((len =
alloc_vprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
1935 len =
mg_printf(conn,
"%X\r\n%s\r\n", len, buf);
1938 if (buf != mem && buf != NULL) {
1949#if !defined(NO_SSL_DL)
1954static struct ssl_func ssl_sw[] = {
1956 {
"SSL_accept", NULL},
1957 {
"SSL_connect", NULL},
1959 {
"SSL_write", NULL},
1960 {
"SSL_get_error", NULL},
1961 {
"SSL_set_fd", NULL},
1963 {
"SSL_CTX_new", NULL},
1964 {
"SSLv23_server_method", NULL},
1965 {
"SSL_library_init", NULL},
1966 {
"SSL_CTX_use_PrivateKey_file", NULL},
1967 {
"SSL_CTX_use_certificate_file",NULL},
1968 {
"SSL_CTX_set_default_passwd_cb",NULL},
1969 {
"SSL_CTX_free", NULL},
1970 {
"SSL_load_error_strings", NULL},
1971 {
"SSL_CTX_use_certificate_chain_file", NULL},
1972 {
"SSLv23_client_method", NULL},
1973 {
"SSL_pending", NULL},
1974 {
"SSL_CTX_set_verify", NULL},
1975 {
"SSL_shutdown", NULL},
1976 {
"SSL_CTX_ctrl", NULL},
1977 {
"SSL_CTX_set_cipher_list", NULL},
1978 {
"EC_KEY_new_by_curve_name", NULL},
1979 {
"EC_KEY_free", NULL},
1980 {
"SSL_get_cipher_list", NULL},
1985static struct ssl_func crypto_sw[] = {
1986 {
"CRYPTO_num_locks", NULL},
1987 {
"CRYPTO_set_locking_callback", NULL},
1988 {
"CRYPTO_set_id_callback", NULL},
1989 {
"ERR_get_error", NULL},
1990 {
"ERR_error_string", NULL},
1998 return (conn->
ssl = SSL_new(s)) != NULL &&
2000 func(conn->
ssl) == 1;
2006 err = ERR_get_error();
2007 return err == 0 ?
"" : ERR_error_string(err, NULL);
2016 (void) pthread_mutex_lock(&
ssl_mutexes[mutex_num]);
2018 (void) pthread_mutex_unlock(&
ssl_mutexes[mutex_num]);
2023 return (
unsigned long) pthread_self();
2026#if !defined(NO_SSL_DL)
2027static int load_dll(
struct mg_context *ctx,
const char *dll_name,
2028 struct ssl_func *sw) {
2029 union {
void *p; void (*
fp)(void);} u;
2031 struct ssl_func *
fp;
2033 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
2034 cry(
fc(ctx),
"%s: cannot load %s", __func__, dll_name);
2038 for (
fp = sw;
fp->name != NULL;
fp++) {
2041 u.fp = (void (*)(void)) dlsym(dll_handle,
fp->name);
2045 u.p = dlsym(dll_handle,
fp->name);
2048 cry(
fc(ctx),
"%s: %s: cannot find %s", __func__, dll_name,
fp->name);
2063 int ecdh_enabled = 0;
2064 int ecdh_available = 0;
2074#if !defined(NO_SSL_DL)
2075 if (!load_dll(ctx,
SSL_LIB, ssl_sw) ||
2083 SSL_load_error_strings();
2085 if ((ctx->
ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
2090 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_NO_SSLv2);
2091 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_NO_SSLv3);
2103 void *dh_2048 = NULL;
2105 paramfile = fopen(
"dh_param_2048.pem",
"r");
2107 dh_2048 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
2112 if (dh_2048 == NULL) {
2115 if (SSL_CTX_set_tmp_dh(ctx->
ssl_ctx, dh_2048) != 1) {
2121#ifdef OPENSSL_EC_NAMED_CURVE
2127 EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
2129 cry(
fc(ctx),
"%s: EC_KEY_new_by_curve_name (NID_X9_62_prime256v1) failed: %s", __func__,
ssl_error());
2131 if (1 != SSL_CTX_set_tmp_ecdh (ctx->
ssl_ctx, ecdh)) {
2132 cry(
fc(ctx),
"%s: SSL_CTX_set_tmp_ecdh (ctx->ssl_ctx, ecdh) failed: %s", __func__,
ssl_error());
2139#warning Very old openssl, no EC_KEY, no ECDH for modern criptography!
2142 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_SINGLE_DH_USE);
2143 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
2150 for (priority=0; 1; priority++) {
2151 const char* available_cipher_list = SSL_get_cipher_list(ssl, priority);
2152 if (available_cipher_list == NULL)
2155 if (strstr(available_cipher_list,
"ECDHE") != NULL)
2161 if (!ecdh_available || !ecdh_enabled) {
2162 cry(
fc(ctx),
"%s: openssl \"modern cryptography\" ECDH ciphers not available", __func__);
2166 const char* cipher_list =
"ALL:!RC4:!DES-CBC-SHA:!DES:!DES-CBC3-SHA:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW";
2169 if (ecdh_available && ecdh_enabled)
2170 cipher_list =
"ALL:!AECDH:!RC4:!DES-CBC-SHA:!DES:!AES128-SHA+RSA:!AES256-SHA+RSA:!DES-CBC3-SHA:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW";
2172 SSL_CTX_set_cipher_list(ctx->
ssl_ctx, cipher_list);
2177 if (SSL_CTX_use_certificate_file(ctx->
ssl_ctx, pem, 1) == 0 ||
2178 SSL_CTX_use_PrivateKey_file(ctx->
ssl_ctx, pem, 1) == 0) {
2179 cry(
fc(ctx),
"%s: cannot open %s: %s", __func__, pem,
ssl_error());
2184 (void) SSL_CTX_use_certificate_chain_file(ctx->
ssl_ctx, pem);
2189 size =
sizeof(pthread_mutex_t) * CRYPTO_num_locks();
2190 if ((
ssl_mutexes = (pthread_mutex_t *) malloc((
size_t)size)) == NULL) {
2191 cry(
fc(ctx),
"%s: cannot allocate mutexes: %s", __func__,
ssl_error());
2195 for (
i = 0;
i < CRYPTO_num_locks();
i++) {
2208 CRYPTO_set_locking_callback(NULL);
2209 for (
i = 0;
i < CRYPTO_num_locks();
i++) {
2212 CRYPTO_set_locking_callback(NULL);
2213 CRYPTO_set_id_callback(NULL);
2219 char *ebuf,
size_t ebuf_len) {
2220 struct sockaddr_in sin;
2221 struct hostent *he = NULL;
2227 snprintf(ebuf, ebuf_len,
"%s",
"NULL host");
2229 }
else if (use_ssl && (
void *)SSLv23_client_method == NULL) {
2230 snprintf(ebuf, ebuf_len,
"%s",
"SSL is not initialized");
2233 }
else if ((he = gethostbyname(host)) == NULL) {
2234 snprintf(ebuf, ebuf_len,
"gethostbyname(%s): %s", host, strerror(
ERRNO));
2236 snprintf(ebuf, ebuf_len,
"socket(): %s", strerror(
ERRNO));
2239 sin.sin_family = AF_INET;
2240 sin.sin_port = htons((uint16_t) port);
2241 sin.sin_addr = * (
struct in_addr *) he->h_addr_list[0];
2242 if (connect(sock, (
struct sockaddr *) &sin,
sizeof(sin)) != 0) {
2243 snprintf(ebuf, ebuf_len,
"connect(%s:%d): %s",
2244 host, port, strerror(
ERRNO));
2253 char *ebuf,
size_t ebuf_len) {
2261 snprintf(ebuf, ebuf_len,
"calloc(): %s", strerror(
ERRNO));
2265 SSL_CTX_new(SSLv23_client_method())) == NULL) {
2266 snprintf(ebuf, ebuf_len,
"SSL_CTX_new error");
2272 socklen_t len =
sizeof(
struct sockaddr);
2274 conn->
buf = (
char *) (conn + 1);
2275 conn->
ctx = &fake_ctx;
2293 char *ebuf,
size_t ebuf_len,
2294 const char *fmt, ...) {
2300 if ((conn =
mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
2302 snprintf(ebuf, ebuf_len,
"%s",
"Error sending request");
2304 getreq(conn, ebuf, ebuf_len);
2306 if (ebuf[0] !=
'\0' && conn != NULL) {
2320 if (conn != NULL && conn->
ctx != NULL) {
2331static FILE *
mg_fopen(
const char *path,
const char *mode) {
2335 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode,
ARRAY_SIZE(wmode));
2336 return _wfopen(wbuf, wmode);
2338 return fopen(path, mode);
2345#if defined(USE_IPV6)
2347 (
void *) &
usa->
sin.sin_addr :
2348 (
void *) &
usa->sin6.sin6_addr,
buf, len);
2349#elif defined(_WIN32)
2365 (void) vsnprintf(
buf,
sizeof(
buf), fmt, ap);
2377 timestamp = time(NULL);
2380 fprintf(
fp,
"[%010lu] [error] [client %s] ", (
unsigned long) timestamp,
2388 fprintf(
fp,
"%s",
buf);
2409 (header != NULL &&
mg_strcasecmp(header,
"keep-alive") != 0) ||
2410 (header == NULL && http_version && strcmp(http_version,
"1.1"))) {
2421 const char *reason,
const char *fmt, ...) {
2442 "Content-Length: %d\r\n"
2443 "Connection: %s\r\n\r\n",
status, reason, len,
2458 while (sent < len) {
2461 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
2469 n = (int) fwrite(
buf + sent, 1, (
size_t)
k,
fp);
2490 if (len <= 0)
return 0;
2495 nread =
read(fileno(
fp),
buf, (
size_t) len);
2497 }
else if (conn->
ssl != NULL) {
2498 nread = SSL_read(conn->
ssl,
buf, len);
2518 }
else if (
n == 0) {
2530 int n, buffered_len, nread = 0;
2545 if (buffered_len > len) buffered_len = len;
2548 memcpy(
buf, body, (
size_t) buffered_len);
2549 memmove(body, body + buffered_len,
2550 &conn->
buf[conn->
data_len] - &body[buffered_len]);
2551 len -= buffered_len;
2553 nread += buffered_len;
2561 n =
pull_all(NULL, conn, (
char *)
buf + nread, (
int) len);
2562 nread =
n >= 0 ? nread +
n :
n;
2570 int64_t
n,
total, allowed;
2578 if (allowed > (int64_t) len) {
2582 (int64_t) allowed)) == allowed) {
2589 (int64_t) allowed)) != allowed) {
2607 int dst_len,
int is_form_url_encoded) {
2609#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
2611 for (
i =
j = 0;
i < src_len &&
j < dst_len - 1;
i++,
j++) {
2612 if (src[
i] ==
'%' &&
i < src_len - 2 &&
2613 isxdigit(* (
const unsigned char *) (src +
i + 1)) &&
2614 isxdigit(* (
const unsigned char *) (src +
i + 2))) {
2615 a = tolower(* (
const unsigned char *) (src +
i + 1));
2616 b = tolower(* (
const unsigned char *) (src +
i + 2));
2619 }
else if (is_form_url_encoded && src[
i] ==
'+') {
2628 return i >= src_len ?
j : -1;
2632 char *dst,
size_t dst_len) {
2633 const char *p, *
e, *s;
2637 if (dst == NULL || dst_len == 0) {
2643 name_len = strlen(
name);
2649 for (p =
data; p + name_len <
e; p++) {
2650 if ((p ==
data || p[-1] ==
'&') && p[name_len] ==
'=' &&
2657 s = (
const char *) memchr(p,
'&', (
size_t)(
e - p));
2679 char *dst,
size_t dst_size) {
2680 const char *s, *p, *
end;
2681 int name_len, len = -1;
2683 if (dst == NULL || dst_size == 0) {
2685 }
else if (
var_name == NULL || (s = cookie_header) == NULL) {
2690 end = s + strlen(s);
2694 if (s[name_len] ==
'=') {
2696 if ((p = strchr(s,
' ')) == NULL)
2700 if (*s ==
'"' && p[-1] ==
'"' && p > s + 1) {
2704 if ((
size_t) (p - s) < dst_size) {
2719 size_t buf_len,
struct file *filep) {
2726 char const* accept_encoding;
2739 while ((rewrite =
next_option(rewrite, &a, &b)) != NULL) {
2757 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
2758 if (strstr(accept_encoding,
"gzip") != NULL) {
2759 snprintf(gz_path,
sizeof(gz_path),
"%s.gz", buf);
2760 if (
mg_stat(gz_path, filep)) {
2768 for (p = buf + strlen(root == NULL ?
"" : root); *p !=
'\0'; p++) {
2780 memmove(p + 2, p + 1, strlen(p + 1) + 1);
2799 for (
i = 0;
i < buf_len;
i++) {
2803 if (!isprint(* (
const unsigned char *) &buf[
i]) && buf[
i] !=
'\r' &&
2804 buf[
i] !=
'\n' && * (
const unsigned char *) &buf[
i] < 128) {
2806 }
else if (buf[
i] ==
'\n' &&
i + 1 < buf_len && buf[
i + 1] ==
'\n') {
2808 }
else if (buf[
i] ==
'\n' &&
i + 2 < buf_len && buf[
i + 1] ==
'\r' &&
2809 buf[
i + 2] ==
'\n') {
2822 while (*s !=
'\0') {
2824 if (s[-1] ==
'/' || s[-1] ==
'\\') {
2826 while (s[0] !=
'\0') {
2827 if (s[0] ==
'/' || s[0] ==
'\\') {
2829 }
else if (s[0] ==
'.' && s[1] ==
'.') {
2840static const struct {
2845 {
".html", 5,
"text/html"},
2846 {
".htm", 4,
"text/html"},
2847 {
".shtm", 5,
"text/html"},
2848 {
".shtml", 6,
"text/html"},
2849 {
".css", 4,
"text/css"},
2850 {
".js", 3,
"application/x-javascript"},
2851 {
".ico", 4,
"image/x-icon"},
2852 {
".gif", 4,
"image/gif"},
2853 {
".jpg", 4,
"image/jpeg"},
2854 {
".jpeg", 5,
"image/jpeg"},
2855 {
".png", 4,
"image/png"},
2856 {
".svg", 4,
"image/svg+xml"},
2857 {
".txt", 4,
"text/plain"},
2858 {
".torrent", 8,
"application/x-bittorrent"},
2859 {
".wav", 4,
"audio/x-wav"},
2860 {
".mp3", 4,
"audio/x-mp3"},
2861 {
".mid", 4,
"audio/mid"},
2862 {
".m3u", 4,
"audio/x-mpegurl"},
2863 {
".ogg", 4,
"application/ogg"},
2864 {
".ram", 4,
"audio/x-pn-realaudio"},
2865 {
".xml", 4,
"text/xml"},
2866 {
".json", 5,
"text/json"},
2867 {
".xslt", 5,
"application/xml"},
2868 {
".xsl", 4,
"application/xml"},
2869 {
".ra", 3,
"audio/x-pn-realaudio"},
2870 {
".doc", 4,
"application/msword"},
2871 {
".exe", 4,
"application/octet-stream"},
2872 {
".zip", 4,
"application/x-zip-compressed"},
2873 {
".xls", 4,
"application/excel"},
2874 {
".tgz", 4,
"application/x-tar-gz"},
2875 {
".tar", 4,
"application/x-tar"},
2876 {
".gz", 3,
"application/x-gunzip"},
2877 {
".arj", 4,
"application/x-arj-compressed"},
2878 {
".rar", 4,
"application/x-arj-compressed"},
2879 {
".rtf", 4,
"application/rtf"},
2880 {
".pdf", 4,
"application/pdf"},
2881 {
".swf", 4,
"application/x-shockwave-flash"},
2882 {
".mpg", 4,
"video/mpeg"},
2883 {
".webm", 5,
"video/webm"},
2884 {
".mpeg", 5,
"video/mpeg"},
2885 {
".mov", 4,
"video/quicktime"},
2886 {
".mp4", 4,
"video/mp4"},
2887 {
".m4v", 4,
"video/x-m4v"},
2888 {
".asf", 4,
"video/x-ms-asf"},
2889 {
".avi", 4,
"video/x-msvideo"},
2890 {
".bmp", 4,
"image/bmp"},
2891 {
".ttf", 4,
"application/x-font-ttf"},
2899 path_len = strlen(path);
2909 return "text/plain";
2916 struct vec ext_vec, mime_vec;
2917 const char *
list, *ext;
2920 path_len = strlen(path);
2927 ext = path + path_len - ext_vec.
len;
2939 static const char *dont_escape =
"._-$,;~()";
2940 static const char *hex =
"0123456789abcdef";
2941 const char *
end = dst + dst_len - 1;
2943 for (; *src !=
'\0' && dst <
end; src++, dst++) {
2944 if (isalnum(*(
const unsigned char *) src) ||
2945 strchr(dont_escape, * (
const unsigned char *) src) != NULL) {
2947 }
else if (dst + 2 <
end) {
2949 dst[1] = hex[(* (
const unsigned char *) src) >> 4];
2950 dst[2] = hex[(* (
const unsigned char *) src) & 0xf];
2959 char size[64], mod[64], href[
PATH_MAX * 3];
2963 mg_snprintf(size,
sizeof(size),
"%s",
"[DIRECTORY]");
2977 "%.1fG", (
double)
de->
file.
size / 1073741824);
2980 strftime(mod,
sizeof(mod),
"%d-%b-%Y %H:%M",
2984 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
2985 "<td> %s</td><td> %s</td></tr>\n",
2994 const struct de *a = (
const struct de *) p1, *b = (
const struct de *) p2;
2998 if (query_string == NULL) {
2999 query_string =
"na";
3006 }
else if (*query_string ==
'n') {
3007 cmp_result = strcmp(a->
file_name, b->file_name);
3008 }
else if (*query_string ==
's') {
3009 cmp_result = a->
file.
size == b->file.size ? 0 :
3010 a->
file.
size > b->file.size ? 1 : -1;
3011 }
else if (*query_string ==
'd') {
3016 return query_string[1] ==
'd' ? -cmp_result : cmp_result;
3022 return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
3023 (pattern != NULL &&
match_prefix(pattern, strlen(pattern), path) > 0);
3027 void *
data,
void (*cb)(
struct de *,
void *)) {
3033 if ((dirp = opendir(dir)) == NULL) {
3038 while ((dp = readdir(dirp)) != NULL) {
3040 if (!strcmp(dp->d_name,
".") ||
3041 !strcmp(dp->d_name,
"..") ||
3046 mg_snprintf(path,
sizeof(path),
"%s%c%s", dir,
'/', dp->d_name);
3059 (void) closedir(dirp);
3070 if ((dirp = opendir(dir)) == NULL) {
3075 while ((dp = readdir(dirp)) != NULL) {
3077 if (!strcmp(dp->d_name,
".") ||
3078 !strcmp(dp->d_name,
"..")) {
3082 mg_snprintf(path,
sizeof(path),
"%s%c%s", dir,
'/', dp->d_name);
3100 (void) closedir(dirp);
3116 void *new_ptr = realloc(ptr, size);
3117 if (new_ptr == NULL) {
3144 int i, sort_direction;
3149 "Error: opendir(%s): %s", dir, strerror(
ERRNO));
3158 "HTTP/1.1 200 OK\r\n"
3159 "Transfer-Encoding: Chunked\r\n"
3160 "Content-Type: text/html; charset=utf-8\r\n\r\n");
3163 "<html><head><title>Index of %s</title>"
3164 "<style>th {text-align: left;}</style></head>"
3165 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
3166 "<tr><th><a href=\"?n%c\">Name</a></th>"
3167 "<th><a href=\"?d%c\">Modified</a></th>"
3168 "<th><a href=\"?s%c\">Size</a></th></tr>"
3169 "<tr><td colspan=\"3\"><hr></td></tr>",
3171 sort_direction, sort_direction, sort_direction);
3175 "<tr><td><a href=\"%s%s\">%s</a></td>"
3176 "<td> %s</td><td> %s</td></tr>\n",
3180 qsort(
data.entries, (
size_t)
data.num_entries,
sizeof(
data.entries[0]),
3182 for (
i = 0;
i <
data.num_entries;
i++) {
3184 free(
data.entries[
i].file_name);
3189 "</table></body></html>");
3196 int64_t
offset, int64_t len) {
3198 int num_read, num_written, to_read;
3207 to_read =
sizeof(buf);
3208 if ((int64_t) to_read > len) {
3209 to_read = (int) len;
3213 if ((num_read = fread(buf, 1, (
size_t) to_read,
fp)) <= 0) {
3218 if ((num_written =
mg_write(conn, buf, (
size_t) num_read)) != num_read) {
3233 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT",
gmtime(t));
3237 const struct file *filep) {
3238 snprintf(buf, buf_len,
"\"%lx.%" INT64_FMT "\"",
3245 fcntl(fileno(
fp), F_SETFD, FD_CLOEXEC);
3251 struct file *filep) {
3252 char date[64], lm[64], etag[64], range[64];
3253 const char *msg =
"OK", *hdr;
3254 time_t curtime = time(NULL);
3256 struct vec mime_vec;
3259 char const* encoding =
"";
3271 snprintf(gz_path,
sizeof(gz_path),
"%s.gz", path);
3273 encoding =
"Content-Encoding: gzip\r\n";
3278 "fopen(%s): %s", path, strerror(
ERRNO));
3288 r1 >= 0 && r2 >= 0) {
3293 "range requests in gzipped files are not supported");
3297 cl =
n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
3299 "Content-Range: bytes "
3302 r1, r1 + cl - 1, filep->
size);
3303 msg =
"Partial Content";
3313 "HTTP/1.1 %d %s\r\n"
3315 "Last-Modified: %s\r\n"
3317 "Content-Type: %.*s\r\n"
3319 "Connection: %s\r\n"
3320 "Accept-Ranges: bytes\r\n"
3357 return !strcmp(method,
"GET") || !strcmp(method,
"POST") ||
3358 !strcmp(method,
"HEAD") || !strcmp(method,
"CONNECT") ||
3359 !strcmp(method,
"PUT") || !strcmp(method,
"DELETE") ||
3360 !strcmp(method,
"OPTIONS") || !strcmp(method,
"PROPFIND")
3361 || !strcmp(method,
"MKCOL")
3370 if (request_length > 0) {
3375 buf[request_length - 1] =
'\0';
3378 while (*buf !=
'\0' && isspace(* (
unsigned char *) buf)) {
3388 if ((is_request && memcmp(ri->
http_version,
"HTTP/", 5) != 0) ||
3390 request_length = -1;
3398 return request_length;
3407 char *buf,
int bufsiz,
int *nread) {
3408 int request_len,
n = 0;
3414 (
n =
pull(
fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
3416 assert(*nread <= bufsiz);
3420 return request_len <= 0 &&
n <= 0 ? -1 : request_len;
3427 size_t path_len,
struct file *filep) {
3430 struct vec filename_vec;
3431 size_t n = strlen(path);
3437 while (
n > 0 && path[
n - 1] ==
'/') {
3447 if (filename_vec.
len > path_len - (
n + 2))
3472 const struct file *filep) {
3483 const char *
expect, *body;
3485 int nread, buffered_len, success = 0;
3497 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
3502 assert(buffered_len >= 0);
3504 if (buffered_len > 0) {
3508 push(
fp, sock, ssl, body, (int64_t) buffered_len);
3509 memmove((
char *) body, body + buffered_len, buffered_len);
3516 if (
left > (int64_t)
sizeof(buf)) {
3519 nread =
pull(NULL, conn, buf, (
int)
left);
3520 if (nread <= 0 ||
push(
fp, sock, ssl, buf, nread) != nread) {
3526 success = nread >= 0;
3567 space =
sizeof(block->buf) - block->len - 2;
3571 added = block->buf + block->len;
3579 if (
n > 0 &&
n + 1 < space &&
3580 block->nvars < (
int)
ARRAY_SIZE(block->vars) - 2) {
3582 block->vars[block->nvars++] = added;
3584 block->len +=
n + 1;
3586 cry(block->conn,
"%s: CGI env buffer truncated for [%s]", __func__, fmt);
3596 const char *s, *slash;
3611 addenv(
blk,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
3612 addenv(
blk,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
3613 addenv(
blk,
"%s",
"REDIRECT_STATUS=200");
3619 addenv(
blk,
"REMOTE_ADDR=%s", src_addr);
3631 s = strrchr(prog,
'/');
3632 slash = strrchr(ri->
uri,
'/');
3634 slash == NULL ? 0 : (int) (slash - ri->
uri), ri->
uri,
3635 s == NULL ? prog : s);
3638 addenv(
blk,
"SCRIPT_FILENAME=%s", prog);
3639 addenv(
blk,
"PATH_TRANSLATED=%s", prog);
3640 addenv(
blk,
"HTTPS=%s", conn->
ssl == NULL ?
"off" :
"on");
3652 if ((s = getenv(
"PATH")) != NULL)
3656 if ((s = getenv(
"COMSPEC")) != NULL) {
3659 if ((s = getenv(
"SYSTEMROOT")) != NULL) {
3662 if ((s = getenv(
"SystemDrive")) != NULL) {
3665 if ((s = getenv(
"ProgramFiles")) != NULL) {
3668 if ((s = getenv(
"ProgramFiles(x86)")) != NULL) {
3671 if ((s = getenv(
"CommonProgramFiles(x86)")) != NULL) {
3672 addenv(
blk,
"CommonProgramFiles(x86)=%s", s);
3675 if ((s = getenv(
"LD_LIBRARY_PATH")) != NULL)
3679 if ((s = getenv(
"PERLLIB")) != NULL)
3693 for (; *p !=
'=' && *p !=
'\0'; p++) {
3696 *p = (char) toupper(* (
unsigned char *) p);
3702 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
3706 blk->vars[
blk->nvars++] = NULL;
3707 blk->buf[
blk->len++] =
'\0';
3710 assert(
blk->len > 0);
3711 assert(
blk->len < (
int)
sizeof(
blk->buf));
3715 int headers_len, data_len,
i, fdin[2], fdout[2];
3716 const char *
status, *status_text;
3717 char buf[16384], *pbuf, dir[
PATH_MAX], *p;
3720 FILE *in = NULL, *out = NULL;
3721 pid_t pid = (pid_t) -1;
3729 if ((p = strrchr(dir,
'/')) != NULL) {
3732 dir[0] =
'.', dir[1] =
'\0';
3736 if (pipe(fdin) != 0 || pipe(fdout) != 0) {
3738 "Cannot create CGI pipe: %s", strerror(
ERRNO));
3743 if (pid == (pid_t) -1) {
3745 "Cannot spawn CGI process [%s]: %s", prog, strerror(
ERRNO));
3759 (void) close(fdin[0]);
3760 (void) close(fdout[1]);
3761 fdin[0] = fdout[1] = -1;
3764 if ((in = fdopen(fdin[1],
"wb")) == NULL ||
3765 (out = fdopen(fdout[0],
"rb")) == NULL) {
3767 "fopen: %s", strerror(
ERRNO));
3791 if (headers_len <= 0) {
3793 "CGI program sent malformed or too big (>%u bytes) "
3794 "HTTP headers: [%.*s]",
3795 (
unsigned)
sizeof(
buf), data_len,
buf);
3799 buf[headers_len - 1] =
'\0';
3807 while (isdigit(* (
unsigned char *) status_text) || *status_text ==
' ') {
3810 }
else if (
get_header(&ri,
"Location") != NULL) {
3831 (
size_t)(data_len - headers_len));
3837 if (pid != (pid_t) -1) {
3840 if (fdin[0] != -1) {
3843 if (fdout[1] != -1) {
3849 }
else if (fdin[1] != -1) {
3855 }
else if (fdout[0] != -1) {
3870 for (s = p = path + 2; (p = strchr(s,
'/')) != NULL; s = ++p) {
3872 if (len >= (
int)
sizeof(buf)) {
3876 memcpy(buf, path, len);
3904 "mkcol(%s): %s", path, strerror(
ERRNO));
3911 "mkcol(%s): %s", path, strerror(
ERRNO));
3920 }
else if (rc == -1) {
3923 "mkcol(%s): %s", path, strerror(
ERRNO));
3924 else if(errno == EACCES)
3926 "mkcol(%s): %s", path, strerror(
ERRNO));
3927 else if(errno == ENOENT)
3929 "mkcol(%s): %s", path, strerror(
ERRNO));
3932 "fopen(%s): %s", path, strerror(
ERRNO));
3945 if ((rc =
put_dir(path)) == 0) {
3947 }
else if (rc == -1) {
3949 "put_dir(%s): %s", path, strerror(
ERRNO));
3950 }
else if ((
fp =
mg_fopen(path,
"wb+")) == NULL) {
3953 "fopen(%s): %s", path, strerror(
ERRNO));
3960 fseeko(
fp, r1, SEEK_SET);
3965 mg_printf(conn,
"HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
3973 char *tag,
int include_level) {
3979 if (sscanf(tag,
" virtual=\"%[^\"]\"",
file_name) == 1) {
3983 }
else if (sscanf(tag,
" abspath=\"%[^\"]\"",
file_name) == 1) {
3987 }
else if (sscanf(tag,
" file=\"%[^\"]\"",
file_name) == 1 ||
3988 sscanf(tag,
" \"%[^\"]\"",
file_name) == 1) {
3990 (void)
mg_snprintf(path,
sizeof(path),
"%s", ssi);
3991 if ((p = strrchr(path,
'/')) != NULL) {
3995 sizeof(path) - strlen(path),
"%s",
file_name);
3997 cry(conn,
"Bad SSI #include: [%s]", tag);
4002 cry(conn,
"Cannot open SSI #include: [%s]: fopen(%s): %s",
4003 tag, path, strerror(
ERRNO));
4016#if !defined(NO_POPEN)
4021 if (sscanf(tag,
" \"%[^\"]\"", cmd) != 1) {
4022 cry(conn,
"Bad SSI #exec: [%s]", tag);
4023 }
else if ((
fp = popen(cmd,
"r")) == NULL) {
4024 cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
4033 FILE *
fp,
int include_level) {
4035 int ch,
offset, len, in_ssi_tag;
4037 if (include_level > 10) {
4038 cry(conn,
"SSI #include level is too deep (%s)", path);
4042 in_ssi_tag = len =
offset = 0;
4043 while ((ch = fgetc(
fp)) != EOF) {
4044 if (in_ssi_tag && ch ==
'>') {
4046 buf[len++] = (char) ch;
4048 assert(len <= (
int)
sizeof(buf));
4049 if (len < 6 || memcmp(buf,
"<!--#", 5) != 0) {
4051 (void)
mg_write(conn, buf, (
size_t) len);
4053 if (!memcmp(buf + 5,
"include", 7)) {
4055#if !defined(NO_POPEN)
4056 }
else if (!memcmp(buf + 5,
"exec", 4)) {
4060 cry(conn,
"%s: unknown SSI " "command: \"%s\"", path, buf);
4064 }
else if (in_ssi_tag) {
4065 if (len == 5 && memcmp(buf,
"<!--#", 5) != 0) {
4068 }
else if (len == (
int)
sizeof(buf) - 2) {
4069 cry(conn,
"%s: SSI tag is too large", path);
4072 buf[len++] = ch & 0xff;
4073 }
else if (ch ==
'<') {
4079 buf[len++] = ch & 0xff;
4081 buf[len++] = ch & 0xff;
4082 if (len == (
int)
sizeof(buf)) {
4097 struct vec mime_vec;
4108 "Content-Type: %.*s\r\n"
4109 "Connection: close\r\n\r\n",
4110 (
int) mime_vec.
len, mime_vec.
ptr);
4117 static const char reply[] =
"HTTP/1.1 200 OK\r\n"
4118 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
4122 mg_write(conn, reply,
sizeof(reply) - 1);
4127 struct file *filep) {
4132 "<d:href>%s</d:href>"
4135 "<d:resourcetype>%s</d:resourcetype>"
4136 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
4137 "<d:getlastmodified>%s</d:getlastmodified>"
4139 "<d:status>HTTP/1.1 200 OK</d:status>"
4159 struct file *filep) {
4164 mg_printf(conn,
"HTTP/1.1 207 Multi-Status\r\n"
4165 "Connection: close\r\n"
4166 "Content-Type: text/xml; charset=utf-8\r\n\r\n");
4169 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
4170 "<d:multistatus xmlns:d='DAV:'>\n");
4178 (depth == NULL || strcmp(depth,
"0") != 0)) {
4185#if defined(USE_WEBSOCKET)
4191#include "solarisfixes.h"
4196#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
4201 block->
l[
i] = (
rol(block->
l[
i], 24) & 0xFF00FF00) |
4202 (
rol(block->
l[
i], 8) & 0x00FF00FF);
4207#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
4208 ^block->l[(i+2)&15]^block->l[i&15],1))
4209#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
4210#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
4211#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
4212#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
4213#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
4218 unsigned char buffer[64];
4221static void SHA1Transform(uint32_t
state[5],
const unsigned char buffer[64]) {
4222 uint32_t a, b,
c,
d,
e;
4225 memcpy(block, buffer, 64);
4231 R0(a,b,
c,
d,
e, 0);
R0(
e,a,b,
c,
d, 1);
R0(
d,
e,a,b,
c, 2);
R0(
c,
d,
e,a,b, 3);
4232 R0(b,
c,
d,
e,a, 4);
R0(a,b,
c,
d,
e, 5);
R0(
e,a,b,
c,
d, 6);
R0(
d,
e,a,b,
c, 7);
4233 R0(
c,
d,
e,a,b, 8);
R0(b,
c,
d,
e,a, 9);
R0(a,b,
c,
d,
e,10);
R0(
e,a,b,
c,
d,11);
4234 R0(
d,
e,a,b,
c,12);
R0(
c,
d,
e,a,b,13);
R0(b,
c,
d,
e,a,14);
R0(a,b,
c,
d,
e,15);
4235 R1(
e,a,b,
c,
d,16);
R1(
d,
e,a,b,
c,17);
R1(
c,
d,
e,a,b,18);
R1(b,
c,
d,
e,a,19);
4236 R2(a,b,
c,
d,
e,20);
R2(
e,a,b,
c,
d,21);
R2(
d,
e,a,b,
c,22);
R2(
c,
d,
e,a,b,23);
4237 R2(b,
c,
d,
e,a,24);
R2(a,b,
c,
d,
e,25);
R2(
e,a,b,
c,
d,26);
R2(
d,
e,a,b,
c,27);
4238 R2(
c,
d,
e,a,b,28);
R2(b,
c,
d,
e,a,29);
R2(a,b,
c,
d,
e,30);
R2(
e,a,b,
c,
d,31);
4239 R2(
d,
e,a,b,
c,32);
R2(
c,
d,
e,a,b,33);
R2(b,
c,
d,
e,a,34);
R2(a,b,
c,
d,
e,35);
4240 R2(
e,a,b,
c,
d,36);
R2(
d,
e,a,b,
c,37);
R2(
c,
d,
e,a,b,38);
R2(b,
c,
d,
e,a,39);
4241 R3(a,b,
c,
d,
e,40);
R3(
e,a,b,
c,
d,41);
R3(
d,
e,a,b,
c,42);
R3(
c,
d,
e,a,b,43);
4242 R3(b,
c,
d,
e,a,44);
R3(a,b,
c,
d,
e,45);
R3(
e,a,b,
c,
d,46);
R3(
d,
e,a,b,
c,47);
4243 R3(
c,
d,
e,a,b,48);
R3(b,
c,
d,
e,a,49);
R3(a,b,
c,
d,
e,50);
R3(
e,a,b,
c,
d,51);
4244 R3(
d,
e,a,b,
c,52);
R3(
c,
d,
e,a,b,53);
R3(b,
c,
d,
e,a,54);
R3(a,b,
c,
d,
e,55);
4245 R3(
e,a,b,
c,
d,56);
R3(
d,
e,a,b,
c,57);
R3(
c,
d,
e,a,b,58);
R3(b,
c,
d,
e,a,59);
4246 R4(a,b,
c,
d,
e,60);
R4(
e,a,b,
c,
d,61);
R4(
d,
e,a,b,
c,62);
R4(
c,
d,
e,a,b,63);
4247 R4(b,
c,
d,
e,a,64);
R4(a,b,
c,
d,
e,65);
R4(
e,a,b,
c,
d,66);
R4(
d,
e,a,b,
c,67);
4248 R4(
c,
d,
e,a,b,68);
R4(b,
c,
d,
e,a,69);
R4(a,b,
c,
d,
e,70);
R4(
e,a,b,
c,
d,71);
4249 R4(
d,
e,a,b,
c,72);
R4(
c,
d,
e,a,b,73);
R4(b,
c,
d,
e,a,74);
R4(a,b,
c,
d,
e,75);
4250 R4(
e,a,b,
c,
d,76);
R4(
d,
e,a,b,
c,77);
R4(
c,
d,
e,a,b,78);
R4(b,
c,
d,
e,a,79);
4256 a = b =
c =
d =
e = 0;
4257 memset(block,
'\0',
sizeof(block));
4260static void SHA1Init(SHA1_CTX* context) {
4261 context->state[0] = 0x67452301;
4262 context->state[1] = 0xEFCDAB89;
4263 context->state[2] = 0x98BADCFE;
4264 context->state[3] = 0x10325476;
4265 context->state[4] = 0xC3D2E1F0;
4266 context->count[0] = context->count[1] = 0;
4269static void SHA1Update(SHA1_CTX* context,
const unsigned char*
data,
4273 j = context->count[0];
4274 if ((context->count[0] += len << 3) <
j)
4275 context->count[1]++;
4276 context->count[1] += (len>>29);
4278 if ((
j + len) > 63) {
4279 memcpy(&context->buffer[
j],
data, (
i = 64-
j));
4280 SHA1Transform(context->state, context->buffer);
4281 for ( ;
i + 63 < len;
i += 64) {
4282 SHA1Transform(context->state, &
data[
i]);
4287 memcpy(&context->buffer[
j], &
data[
i], len -
i);
4290static void SHA1Final(
unsigned char digest[20], SHA1_CTX* context) {
4292 unsigned char finalcount[8],
c;
4294 for (
i = 0;
i < 8;
i++) {
4295 finalcount[
i] = (
unsigned char)((context->count[(
i >= 4 ? 0 : 1)]
4296 >> ((3-(
i & 3)) * 8) ) & 255);
4299 SHA1Update(context, &
c, 1);
4300 while ((context->count[0] & 504) != 448) {
4302 SHA1Update(context, &
c, 1);
4304 SHA1Update(context, finalcount, 8);
4305 for (
i = 0;
i < 20;
i++) {
4306 digest[
i] = (
unsigned char)
4307 ((context->state[
i>>2] >> ((3-(
i & 3)) * 8) ) & 255);
4309 memset(context,
'\0',
sizeof(*context));
4310 memset(&finalcount,
'\0',
sizeof(finalcount));
4314static void base64_encode(
const unsigned char *src,
int src_len,
char *dst) {
4315 static const char *b64 =
4316 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4319 for (
i =
j = 0;
i < src_len;
i += 3) {
4321 b =
i + 1 >= src_len ? 0 : src[
i + 1];
4322 c =
i + 2 >= src_len ? 0 : src[
i + 2];
4324 dst[
j++] = b64[a >> 2];
4325 dst[
j++] = b64[((a & 3) << 4) | (b >> 4)];
4326 if (
i + 1 < src_len) {
4327 dst[
j++] = b64[(b & 15) << 2 | (
c >> 6)];
4329 if (
i + 2 < src_len) {
4330 dst[
j++] = b64[
c & 63];
4333 while (
j % 4 != 0) {
4340 static const char *magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4341 char buf[100], sha[20], b64_sha[
sizeof(sha) * 2];
4347 SHA1Update(&sha_ctx, (
unsigned char *) buf, strlen(buf));
4348 SHA1Final((
unsigned char *) sha, &sha_ctx);
4351 "HTTP/1.1 101 Switching Protocols\r\n"
4352 "Upgrade: websocket\r\n"
4353 "Connection: Upgrade\r\n"
4354 "Sec-WebSocket-Accept: ", b64_sha,
"\r\n\r\n");
4361 unsigned char *buf = (
unsigned char *) conn->
buf + conn->
request_len;
4363 size_t i, len, mask_len, data_len, header_len, body_len;
4378 mask_len = buf[1] & 128 ? 4 : 0;
4379 if (len < 126 && body_len >= mask_len) {
4381 header_len = 2 + mask_len;
4382 }
else if (len == 126 && body_len >= 4 + mask_len) {
4383 header_len = 4 + mask_len;
4384 data_len = ((((int) buf[2]) << 8) + buf[3]);
4385 }
else if (body_len >= 10 + mask_len) {
4386 header_len = 10 + mask_len;
4387 data_len = (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
4388 htonl(* (uint32_t *) &buf[6]);
4400 if (header_len > 0) {
4402 if ((*
data = malloc(data_len)) == NULL) {
4411 memcpy(
mask, buf + header_len - mask_len, mask_len);
4414 assert(body_len >= header_len);
4415 if (data_len + header_len > body_len) {
4416 len = body_len - header_len;
4417 memcpy(*
data, buf + header_len, len);
4422 len = data_len + header_len;
4423 memcpy(*
data, buf + header_len, data_len);
4424 memmove(buf, buf + len, body_len - len);
4430 for (
i = 0;
i < data_len;
i++) {
4431 (*data)[
i] ^=
mask[
i % 4];
4450 const char *
data,
size_t data_len) {
4451 unsigned char *copy;
4452 size_t copy_len = 0;
4455 if ((copy = (
unsigned char *) malloc(data_len + 10)) == NULL) {
4459 copy[0] = 0x80 + (opcode & 0x0f);
4462 if (data_len < 126) {
4465 memcpy(copy + 2,
data, data_len);
4466 copy_len = 2 + data_len;
4467 }
else if (data_len <= 0xFFFF) {
4470 * (uint16_t *) (copy + 2) = htons(data_len);
4471 memcpy(copy + 4,
data, data_len);
4472 copy_len = 4 + data_len;
4476 * (uint32_t *) (copy + 2) = htonl((uint64_t) data_len >> 32);
4477 * (uint32_t *) (copy + 6) = htonl(data_len & 0xffffffff);
4478 memcpy(copy + 10,
data, data_len);
4479 copy_len = 10 + data_len;
4484 retval =
mg_write(conn, copy, copy_len);
4493 return n >= 0 &&
n <= 255;
4497 int n, a, b,
c,
d, slash = 32, len = 0;
4499 if ((sscanf(spec,
"%d.%d.%d.%d/%d%n", &a, &b, &
c, &
d, &slash, &
n) == 5 ||
4500 sscanf(spec,
"%d.%d.%d.%d%n", &a, &b, &
c, &
d, &
n) == 4) &&
4502 slash >= 0 && slash < 33) {
4504 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)
c << 8) |
d;
4505 *
mask = slash ? 0xffffffffU << (32 - slash) : 0;
4511static int set_throttle(
const char *spec, uint32_t remote_ip,
const char *uri) {
4520 if (sscanf(val.
ptr,
"%lf%c", &v, &mult) < 1 || v < 0 ||
4528 if ((remote_ip &
mask) == net) {
4540 return ntohl(* (uint32_t *) &conn->
client.
rsa.
sin.sin_addr);
4544 char *path,
int path_len) {
4545 const char *content_type_header, *boundary_start;
4546 char *buf, fname[1024], boundary[100], *s;
4547 int bl,
n,
i,
j, headers_len, boundary_len, eof, buf_len, to_read,
len = 0;
4566 if ((content_type_header =
mg_get_header(conn,
"Content-Type")) == NULL ||
4568 "boundary=")) == NULL ||
4569 (sscanf(boundary_start,
"boundary=\"%99[^\"]\"", boundary) == 0 &&
4570 sscanf(boundary_start,
"boundary=%99s", boundary) == 0) ||
4571 boundary[0] ==
'\0') {
4575 boundary_len = strlen(boundary);
4576 bl = boundary_len + 4;
4590 assert(
len >= 0 &&
len <= buf_len);
4591 to_read = buf_len -
len;
4595 while (
len < buf_len &&
4596 (
n =
pull(NULL, conn, buf +
len, to_read)) > 0) {
4605 for (
i =
j = 0;
i < headers_len;
i++) {
4606 if (buf[
i] ==
'\r' && buf[
i + 1] ==
'\n') {
4607 buf[
i] = buf[
i + 1] =
'\0';
4610 sscanf(&buf[
j],
"Content-Disposition: %*s %*s filename=\"%1023[^\"]",
4617 if (fname[0] ==
'\0') {
4622 assert(
len >= headers_len);
4623 memmove(buf, &buf[headers_len],
len - headers_len);
4632 if ((s = strrchr(fname,
'/')) == NULL &&
4633 (s = strrchr(fname,
'\\')) == NULL) {
4638 snprintf(path, path_len,
"%s/%s", destination_dir, s);
4639 if ((
fp = fopen(path,
"wb")) == NULL) {
4648 if (!memcmp(&buf[
i],
"\r\n--", 4) &&
4649 !memcmp(&buf[
i + 4], boundary, boundary_len)) {
4651 fwrite(buf, 1,
i,
fp);
4653 memmove(buf, &buf[
i +
bl],
len - (
i +
bl));
4658 if (!eof &&
len >
bl) {
4660 memmove(buf, &buf[
len -
bl],
bl);
4663 to_read = buf_len -
len;
4667 }
while (!eof && (
n =
pull(NULL, conn, buf +
len, to_read)) > 0);
4683 return s != NULL && (!strcmp(s,
"PUT") ||
4684 !strcmp(s,
"DELETE") ||
4685 !strcmp(s,
"MKCOL"));
4698 const char *host_header;
4701 sscanf(host_header,
"%1024[^:]", host) == 0) {
4706 mg_printf(conn,
"HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s\r\n\r\n",
4738 int uri_len, ssl_index;
4744 uri_len = (int) strlen(ri->
uri);
4781 mg_printf(conn,
"HTTP/1.1 301 Moved Permanently\r\n"
4782 "Location: %s/\r\n\r\n", ri->
uri);
4791 "Directory listing denied");
4795 handle_lsp_request(conn, path, &
file, NULL);
4830 return port > 0 && port < 0xffff;
4837 unsigned int a, b,
c,
d, ch, port;
4839#if defined(USE_IPV6)
4846 memset(so, 0,
sizeof(*so));
4847 so->
lsa.
sin.sin_family = AF_INET;
4849 if (sscanf(
vec->
ptr,
"%u.%u.%u.%u:%u%n", &a, &b, &
c, &
d, &port, &len) == 5) {
4851 so->
lsa.
sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (
c << 8) |
d);
4852 so->
lsa.
sin.sin_port = htons((uint16_t) port);
4853#if defined(USE_IPV6)
4855 }
else if (sscanf(
vec->
ptr,
"[%49[^]]]:%d%n", buf, &port, &len) == 2 &&
4858 so->
lsa.sin6.sin6_family = AF_INET6;
4859 so->
lsa.sin6.sin6_port = htons((uint16_t) port);
4861 }
else if (sscanf(
vec->
ptr,
"%u%n", &port, &len) == 1) {
4863 so->
lsa.
sin.sin_port = htons((uint16_t) port);
4874 (ch ==
'\0' || ch ==
's' || ch ==
'r' || ch ==
',');
4879 int on = 1, success = 1;
4880#if defined(USE_IPV6)
4888 cry(
fc(ctx),
"%s: %.*s: invalid port spec. Expecting list of: %s",
4889 __func__, (
int)
vec.
len,
vec.
ptr,
"[IP_ADDRESS:]PORT[s|r]");
4892 cry(
fc(ctx),
"Cannot add SSL socket, is -ssl_certificate option set?");
4898 setsockopt(so.
sock, SOL_SOCKET, SO_REUSEADDR,
4899 (
void *) &on,
sizeof(on)) != 0 ||
4900#
if defined(USE_IPV6)
4901 (so.
lsa.
sa.sa_family == AF_INET6 &&
4902 setsockopt(so.
sock, IPPROTO_IPV6, IPV6_V6ONLY, (
void *) &off,
4903 sizeof(off)) != 0) ||
4906 sizeof(so.
lsa.
sin) :
sizeof(so.
lsa)) != 0 ||
4908 cry(
fc(ctx),
"%s: cannot bind to %.*s: %d (%s)", __func__,
4934 const char *header_value;
4937 (void) fprintf(
fp,
"%s",
" -");
4939 (void) fprintf(
fp,
" \"%s\"", header_value);
4954 strftime(date,
sizeof(date),
"%d/%b/%Y:%H:%M:%S %z",
4961 fprintf(
fp,
"%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
4984 allowed =
list == NULL ?
'+' :
'-';
4988 if ((flag !=
'+' && flag !=
'-') ||
4990 cry(
fc(ctx),
"%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
4994 if (net == (remote_ip &
mask)) {
4999 return allowed ==
'+';
5011 if ((pw = getpwnam(uid)) == NULL) {
5012 cry(
fc(ctx),
"%s: unknown user [%s]", __func__, uid);
5013 }
else if (setgid(pw->pw_gid) == -1) {
5014 cry(
fc(ctx),
"%s: setgid(%s): %s", __func__, uid, strerror(errno));
5015 }
else if (setuid(pw->pw_uid) == -1) {
5016 cry(
fc(ctx),
"%s: setuid(%s): %s", __func__, uid, strerror(errno));
5030 cry(
fc(ctx),
"Cannot open %s: %s", path, strerror(
ERRNO));
5037 return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
5052 struct linger linger;
5057 linger.l_linger = 1;
5058 setsockopt(conn->
client.
sock, SOL_SOCKET, SO_LINGER,
5059 (
char *) &linger,
sizeof(linger));
5072 n =
pull(NULL, conn, buf,
sizeof(buf));
5084 if (conn->
ssl != NULL) {
5086 SSL_shutdown(conn->
ssl);
5087 SSL_free(conn->
ssl);
5110 return uri[0] ==
'/' || (uri[0] ==
'*' && uri[1] ==
'\0');
5123 snprintf(ebuf, ebuf_len,
"%s",
"Request Too Large");
5125 snprintf(ebuf, ebuf_len,
"%s",
"Client closed connection");
5128 snprintf(ebuf, ebuf_len,
"Bad request: [%.*s]", conn->
data_len, conn->
buf);
5147 return ebuf[0] ==
'\0';
5152 int keep_alive_enabled, keep_alive, discard_len;
5162 if (!
getreq(conn, ebuf,
sizeof(ebuf))) {
5166 snprintf(ebuf,
sizeof(ebuf),
"Invalid URI: [%s]", ri->
uri);
5170 snprintf(ebuf,
sizeof(ebuf),
"Bad HTTP version: [%s]", ri->
http_version);
5174 if (ebuf[0] ==
'\0') {
5190 keep_alive = conn->
ctx->
stop_flag == 0 && keep_alive_enabled &&
5197 assert(discard_len >= 0);
5198 memmove(conn->
buf, conn->
buf + discard_len, conn->
data_len - discard_len);
5202 }
while (keep_alive);
5207 (void) pthread_mutex_lock(&ctx->
mutex);
5229 (void) pthread_cond_signal(&ctx->
sq_empty);
5230 (void) pthread_mutex_unlock(&ctx->
mutex);
5241 cry(
fc(
ctx),
"%s",
"Cannot create new connection struct, OOM");
5244 conn->
buf = (
char *) (conn + 1);
5280 (void) pthread_mutex_lock(&
ctx->
mutex);
5282 (void) pthread_cond_signal(&
ctx->
cond);
5284 (void) pthread_mutex_unlock(&
ctx->
mutex);
5292 (void) pthread_mutex_lock(&
ctx->
mutex);
5308 (void) pthread_mutex_unlock(&
ctx->
mutex);
5313 DWORD t = milliseconds;
5316 t.tv_sec = milliseconds / 1000;
5317 t.tv_usec = (milliseconds * 1000) % 1000000;
5319 return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (
void *) &t,
sizeof(t)) ||
5320 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (
void *) &t,
sizeof(t));
5327 socklen_t len =
sizeof(so.
rsa);
5329 extern int check_midas_acl(
const struct sockaddr *sa,
int len);
5332 }
else if ((!
check_acl(ctx, ntohl(* (uint32_t *) &so.
rsa.
sin.sin_addr))) || (!check_midas_acl(&so.
rsa.
sa, len))) {
5334 cry(
fc(ctx),
"%s: %s is not allowed to connect", __func__, src_addr);
5349 setsockopt(so.
sock, SOL_SOCKET, SO_KEEPALIVE, (
void *) &on,
sizeof(on));
5362 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
5365#if defined(ISSUE_317)
5366 struct sched_param sched_param;
5367 sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
5368 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
5374 while (pfd != NULL && ctx->
stop_flag == 0) {
5377 pfd[
i].events = POLLIN;
5386 if (ctx->
stop_flag == 0 && (pfd[
i].revents & POLLIN)) {
5399 pthread_cond_broadcast(&ctx->
sq_full);
5402 (void) pthread_mutex_lock(&ctx->
mutex);
5404 (void) pthread_cond_wait(&ctx->
cond, &ctx->
mutex);
5406 (void) pthread_mutex_unlock(&ctx->
mutex);
5409 (void) pthread_mutex_destroy(&ctx->
mutex);
5410 (void) pthread_cond_destroy(&ctx->
cond);
5411 (void) pthread_cond_destroy(&ctx->
sq_empty);
5412 (void) pthread_cond_destroy(&ctx->
sq_full);
5461#if defined(_WIN32) && !defined(__SYMBIAN32__)
5462 (void) WSACleanup();
5470 const char *
name, *
value, *default_value;
5473#if defined(_WIN32) && !defined(__SYMBIAN32__)
5475 WSAStartup(MAKEWORD(2,2), &
data);
5480 if ((ctx = (
struct mg_context *) calloc(1,
sizeof(*ctx))) == NULL) {
5486 while (options && (
name = *options++) != NULL) {
5488 cry(
fc(ctx),
"Invalid option: %s",
name);
5491 }
else if ((
value = *options++) == NULL) {
5492 cry(
fc(ctx),
"%s: option value cannot be NULL",
name);
5497 cry(
fc(ctx),
"warning: %s: duplicate option",
name);
5507 if (ctx->
config[
i] == NULL && default_value != NULL) {
5527#if !defined(_WIN32) && !defined(__SYMBIAN32__)
5530 (void) signal(SIGPIPE, SIG_IGN);
5533 (void) pthread_mutex_init(&ctx->
mutex, NULL);
5534 (void) pthread_cond_init(&ctx->
cond, NULL);
5535 (void) pthread_cond_init(&ctx->
sq_empty, NULL);
5536 (void) pthread_cond_init(&ctx->
sq_full, NULL);
5544 cry(
fc(ctx),
"Cannot start worker thread: %ld", (
long)
ERRNO);
5555static void *mmap(
void *
addr, int64_t len,
int prot,
int flags,
int fd,
5557 HANDLE fh = (HANDLE) _get_osfhandle(fd);
5558 HANDLE
mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
5559 void *p = MapViewOfFile(
mh, FILE_MAP_READ, 0, 0, (
size_t) len);
5563#define munmap(x, y) UnmapViewOfFile(x)
5564#define MAP_FAILED NULL
5565#define MAP_PRIVATE 0
5568#include <sys/mman.h>
5571static const char *LUASOCKET =
"luasocket";
5574static int handle_lsp_request(
struct mg_connection *,
const char *,
5575 struct file *,
struct lua_State *);
5577static void reg_string(
struct lua_State *L,
const char *
name,
const char *val) {
5578 lua_pushstring(L,
name);
5579 lua_pushstring(L, val);
5583static void reg_int(
struct lua_State *L,
const char *
name,
int val) {
5584 lua_pushstring(L,
name);
5585 lua_pushinteger(L, val);
5589static void reg_function(
struct lua_State *L,
const char *
name,
5591 lua_pushstring(L,
name);
5592 lua_pushlightuserdata(L, conn);
5593 lua_pushcclosure(L, func, 1);
5597static int lsp_sock_close(lua_State *L) {
5598 if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
5599 lua_getfield(L, -1,
"sock");
5602 return luaL_error(L,
"invalid :close() call");
5607static int lsp_sock_recv(lua_State *L) {
5611 if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
5612 lua_getfield(L, -1,
"sock");
5613 n = recv((
SOCKET) lua_tonumber(L, -1), buf,
sizeof(buf), 0);
5617 lua_pushlstring(L, buf,
n);
5620 return luaL_error(L,
"invalid :close() call");
5625static int lsp_sock_send(lua_State *L) {
5627 size_t len, sent = 0;
5630 if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) {
5631 buf = lua_tolstring(L, -1, &len);
5632 lua_getfield(L, -2,
"sock");
5633 sock = (int) lua_tonumber(L, -1);
5634 while (sent < len) {
5635 if ((
n = send(sock, buf + sent, len - sent, 0)) <= 0) {
5640 lua_pushnumber(L,
n);
5642 return luaL_error(L,
"invalid :close() call");
5647static const struct luaL_Reg luasocket_methods[] = {
5648 {
"close", lsp_sock_close},
5649 {
"send", lsp_sock_send},
5650 {
"recv", lsp_sock_recv},
5654static int lsp_connect(lua_State *L) {
5658 if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
5659 sock =
conn2(lua_tostring(L, -3), (
int) lua_tonumber(L, -2),
5660 (
int) lua_tonumber(L, -1), ebuf,
sizeof(ebuf));
5662 return luaL_error(L, ebuf);
5665 reg_int(L,
"sock", sock);
5666 reg_string(L,
"host", lua_tostring(L, -4));
5667 luaL_getmetatable(L, LUASOCKET);
5668 lua_setmetatable(L, -2);
5671 return luaL_error(L,
"connect(host,port,is_ssl): invalid parameter given.");
5676static int lsp_error(lua_State *L) {
5677 lua_getglobal(L,
"mg");
5678 lua_getfield(L, -1,
"onerror");
5679 lua_pushvalue(L, -3);
5680 lua_pcall(L, 1, 0, 0);
5685static void lsp_abort(lua_State *L) {
5686 int top = lua_gettop(L);
5687 lua_getglobal(L,
"mg");
5689 lua_setfield(L, -2,
"onerror");
5691 lua_pushstring(L,
"aborting");
5696 const char *p, int64_t len, lua_State *L) {
5697 int i,
j, pos = 0, lines = 1, lualines = 0;
5700 for (
i = 0;
i < len;
i++) {
5701 if (p[
i] ==
'\n') lines++;
5702 if (p[
i] ==
'<' && p[
i + 1] ==
'?') {
5703 for (
j =
i + 1;
j < len ;
j++) {
5704 if (p[
j] ==
'\n') lualines++;
5705 if (p[
j] ==
'?' && p[
j + 1] ==
'>') {
5708 snprintf(chunkname,
sizeof(chunkname),
"@%s+%i", path, lines);
5709 lua_pushlightuserdata(L, conn);
5710 lua_pushcclosure(L, lsp_error, 1);
5711 if (luaL_loadbuffer(L, p + (
i + 2),
j - (
i + 2), chunkname)) {
5713 lua_pcall(L, 1, 0, 0);
5716 lua_pcall(L, 0, 0, 1);
5738static int lsp_write(lua_State *L) {
5742 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5744 num_args = lua_gettop(L);
5745 for (
i = 1;
i <= num_args;
i++) {
5746 if (lua_isstring(L,
i)) {
5747 str = lua_tolstring(L,
i, &size);
5755static int lsp_read(lua_State *L) {
5756 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5760 if (len <= 0)
return 0;
5761 lua_pushlstring(L,
buf, len);
5767static int lsp_include(lua_State *L) {
5768 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5770 if (handle_lsp_request(conn, lua_tostring(L, -1), &
file, L)) {
5779static int lsp_cry(lua_State *L){
5780 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5781 cry(conn,
"%s", lua_tostring(L, -1));
5786static int lsp_redirect(lua_State *L) {
5787 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5794static void prepare_lua_environment(
struct mg_connection *conn, lua_State *L) {
5796 extern void luaL_openlibs(lua_State *);
5800#ifdef USE_LUA_SQLITE3
5801 {
extern int luaopen_lsqlite3(lua_State *); luaopen_lsqlite3(L); }
5804 luaL_newmetatable(L, LUASOCKET);
5805 lua_pushliteral(L,
"__index");
5806 luaL_newlib(L, luasocket_methods);
5809 lua_register(L,
"connect", lsp_connect);
5811 if (conn == NULL)
return;
5816 reg_function(L,
"read", lsp_read, conn);
5817 reg_function(L,
"write", lsp_write, conn);
5818 reg_function(L,
"cry", lsp_cry, conn);
5819 reg_function(L,
"include", lsp_include, conn);
5820 reg_function(L,
"redirect", lsp_redirect, conn);
5824 lua_pushstring(L,
"request_info");
5827 reg_string(L,
"uri", ri->
uri);
5833 lua_pushstring(L,
"http_headers");
5841 lua_setglobal(L,
"mg");
5844 luaL_dostring(L,
"mg.onerror = function(e) mg.write('\\nLua error:\\n', "
5845 "debug.traceback(e, 1)) end");
5848static int lua_error_handler(lua_State *L) {
5849 const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) :
"?\n";
5851 lua_getglobal(L,
"mg");
5852 if (!lua_isnil(L, -1)) {
5853 lua_getfield(L, -1,
"write");
5854 lua_pushstring(L, error_msg);
5855 lua_pushliteral(L,
"\n");
5857 luaL_dostring(L,
"mg.write(debug.traceback(), '\\n')");
5859 printf(
"Lua error: [%s]\n", error_msg);
5860 luaL_dostring(L,
"print(debug.traceback(), '\\n')");
5867void mg_exec_lua_script(
struct mg_connection *conn,
const char *path,
5868 const void **exports) {
5872 if (path != NULL && (L = luaL_newstate()) != NULL) {
5873 prepare_lua_environment(conn, L);
5874 lua_pushcclosure(L, &lua_error_handler, 0);
5876 lua_pushglobaltable(L);
5877 if (exports != NULL) {
5878 for (
i = 0; exports[
i] != NULL && exports[
i + 1] != NULL;
i += 2) {
5879 lua_pushstring(L, exports[
i]);
5880 lua_pushcclosure(L, (lua_CFunction) exports[
i + 1], 0);
5885 if (luaL_loadfile(L, path) != 0) {
5886 lua_error_handler(L);
5888 lua_pcall(L, 0, 0, -2);
5893static void lsp_send_err(
struct mg_connection *conn,
struct lua_State *L,
5894 const char *fmt, ...) {
5899 vsnprintf(buf,
sizeof(buf), fmt, ap);
5905 lua_pushstring(L, buf);
5910static int handle_lsp_request(
struct mg_connection *conn,
const char *path,
5911 struct file *filep,
struct lua_State *ls) {
5913 lua_State *L = NULL;
5919 lsp_send_err(conn, ls,
"File [%s] not found", path);
5920 }
else if ((p = mmap(NULL, (
size_t) filep->
size, PROT_READ, MAP_PRIVATE,
5921 fileno(
fp), 0)) == MAP_FAILED) {
5922 lsp_send_err(conn, ls,
"mmap(%s, %zu, %d): %s", path, (
size_t) filep->
size,
5923 fileno(
fp), strerror(errno));
5924 }
else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) {
5929 prepare_lua_environment(conn, L);
5931 error = lsp(conn, path, p, filep->
size, L);
5934 if (L != NULL && ls == NULL) lua_close(L);
5935 if (p != NULL) munmap(p, filep->
size);
int mg_modify_passwords_file(const char *fname, const char *domain, const char *user, const char *pass)
int mg_websocket_read(struct mg_connection *, int *bits, char **data)
void *(* mg_thread_func_t)(void *)
void mg_close_connection(struct mg_connection *conn)
int mg_websocket_write(struct mg_connection *conn, int opcode, const char *data, size_t data_len)
#define PRINTF_FORMAT_STRING(s)
const char * mg_get_option(const struct mg_context *ctx, const char *name)
const char * mg_get_header(const struct mg_connection *conn, const char *name)
int mg_get_var(const char *data, size_t data_len, const char *name, char *dst, size_t dst_len)
int mg_start_thread(mg_thread_func_t func, void *param)
const char * request_method
struct mg_request_info * request_info
struct mg_connection * conn
char * mg_md5(char buf[33],...)
const char * query_string
struct mg_context * mg_start(const char **options, mg_event_handler_t func, void *user_data)
int mg_url_decode(const char *src, int src_len, char *dst, int dst_len, int is_form_url_encoded)
#define PRINTF_ARGS(x, y)
int mg_write(struct mg_connection *conn, const void *buf, int len)
const char * mg_get_builtin_mime_type(const char *path)
const char ** mg_get_valid_option_names(void)
FILE * mg_upload(struct mg_connection *conn, const char *destination_dir, char *path, int path_len)
void mg_send_file(struct mg_connection *conn, const char *path)
const char * http_version
int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, size_t dst_size)
void mg_stop(struct mg_context *ctx)
int(* mg_event_handler_t)(struct mg_event *event)
void mg_websocket_handshake(struct mg_connection *)
const char * mg_version(void)
struct mg_request_info::mg_header http_headers[64]
int mg_read(struct mg_connection *conn, void *buf, int len)
int mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
int mg_printf(struct mg_connection *conn, const char *fmt,...)
void base64_encode(char *s, char *d)
MidasHistoryInterface * mh
static std::string remove(const std::string s, char c)
static int is_put_or_delete_request(const struct mg_connection *conn)
static void process_new_connection(struct mg_connection *conn)
static int mg_strncasecmp(const char *s1, const char *s2, size_t len)
static int is_authorized_for_put(struct mg_connection *conn)
static void sockaddr_to_string(char *buf, size_t len, const union usa *usa)
#define MD5STEP(f, w, x, y, z, data, s)
static int consume_socket(struct mg_context *ctx, struct socket *sp)
static int check_authorization(struct mg_connection *conn, const char *path)
static void mkcol(struct mg_connection *conn, const char *path)
static int check_acl(struct mg_context *ctx, uint32_t remote_ip)
static int64_t left_to_read(const struct mg_connection *conn)
static int set_non_blocking_mode(SOCKET sock)
static void ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
static int set_ports_option(struct mg_context *ctx)
static void put_file(struct mg_connection *conn, const char *path)
static int set_uid_option(struct mg_context *ctx)
static void do_ssi_exec(struct mg_connection *conn, char *tag)
static void mg_strlcpy(register char *dst, register const char *src, size_t n)
void mg_url_encode(const char *src, char *dst, size_t dst_len)
static int set_sock_timeout(SOCKET sock, int milliseconds)
static int set_gpass_option(struct mg_context *ctx)
static int mg_strcasecmp(const char *s1, const char *s2)
static void * realloc2(void *ptr, size_t size)
static void send_http_error(struct mg_connection *, int, const char *, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(4
static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
static void uninitialize_ssl(struct mg_context *ctx)
static int num_leap_years(int year)
static int WINCDECL compare_dir_entries(const void *p1, const void *p2)
static int should_keep_alive(const struct mg_connection *conn)
static SOCKET conn2(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len)
static void handle_file_request(struct mg_connection *conn, const char *path, struct file *filep)
static const char * ssl_error(void)
static int must_hide_file(struct mg_connection *conn, const char *path)
static int parse_net(const char *spec, uint32_t *net, uint32_t *mask)
static int substitute_index_file(struct mg_connection *conn, char *path, size_t path_len, struct file *filep)
static void close_all_listening_sockets(struct mg_context *ctx)
static void prepare_cgi_environment(struct mg_connection *conn, const char *prog, struct cgi_env_block *blk)
static int check_password(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response)
static const char * get_header(const struct mg_request_info *ri, const char *name)
static int mg_chunked_printf(struct mg_connection *conn, const char *fmt,...)
static void print_dav_dir_entry(struct de *de, void *data)
static void dir_scan_callback(struct de *de, void *data)
static void remove_double_dots_and_double_slashes(char *s)
static void reset_per_request_attributes(struct mg_connection *conn)
static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap)
static pthread_mutex_t * ssl_mutexes
static int is_not_modified(const struct mg_connection *conn, const struct file *filep)
static int get_option_index(const char *name)
static void print_props(struct mg_connection *conn, const char *uri, struct file *filep)
static void handle_propfind(struct mg_connection *conn, const char *path, struct file *filep)
static char * mg_strdup(const char *str)
static void accept_new_connection(const struct socket *listener, struct mg_context *ctx)
#define CGI_ENVIRONMENT_SIZE
static void MD5Final(unsigned char digest[16], MD5_CTX *ctx)
static int put_dir(const char *path)
struct mg_connection * mg_download(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len, const char *fmt,...)
static void parse_http_headers(char **buf, struct mg_request_info *ri)
static void get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf, int64_t len)
static char * skip_quoted(char **buf, const char *delimiters, const char *whitespace, char quotechar)
static FILE * open_auth_file(struct mg_connection *conn, const char *path)
static char * skip(char **buf, const char *delimiters)
static int forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
static int set_ssl_option(struct mg_context *ctx)
static int sslize(struct mg_connection *conn, SSL_CTX *s, int(*func)(SSL *))
static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
static void set_close_on_exec(int fd)
#define ARRAY_SIZE(array)
static int get_first_ssl_listener_index(const struct mg_context *ctx)
static void log_header(const struct mg_connection *conn, const char *header, FILE *fp)
static uint32_t get_remote_ip(const struct mg_connection *conn)
static void handle_directory_request(struct mg_connection *conn, const char *dir)
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
static const char * mg_strcasestr(const char *big_str, const char *small_str)
static int pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
static const char * config_options[]
static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t offset, int64_t len)
static int authorize(struct mg_connection *conn, FILE *fp)
static void bin2str(char *to, const unsigned char *p, size_t len)
static void byteReverse(unsigned char *buf, unsigned longs)
static void handle_options_request(struct mg_connection *conn)
static int is_valid_uri(const char *uri)
static const char * next_option(const char *list, struct vec *val, struct vec *eq_val)
static const char * suggest_connection_header(const struct mg_connection *conn)
#define EXTRA_HTTP_HEADERS
static time_t parse_date_string(const char *datetime)
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level)
static int read_request(FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread)
static void handle_ssi_file_request(struct mg_connection *conn, const char *path)
static void MD5Init(MD5_CTX *ctx)
static int lowercase(const char *s)
static int parse_range_header(const char *header, int64_t *a, int64_t *b)
static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fdin, int fdout, const char *dir)
static void handle_delete_request(struct mg_connection *conn, const char *path)
#define MAX_CGI_ENVIR_VARS
static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_size, struct ah *ah)
static void * master_thread(void *thread_func_param)
@ ENABLE_DIRECTORY_LISTING
@ PUT_DELETE_PASSWORDS_FILE
struct mg_connection * mg_connect(const char *host, int port, int use_ssl, char *ebuf, size_t ebuf_len)
static void fclose_on_exec(FILE *fp)
static void construct_etag(char *buf, size_t buf_len, const struct file *filep)
static int mg_stat(const char *path, struct file *filep)
static void send_ssi_file(struct mg_connection *, const char *, FILE *, int)
static void print_dir_entry(const struct de *de)
static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void(*cb)(struct de *, void *))
static void produce_socket(struct mg_context *ctx, const struct socket *sp)
static void send_authorization_request(struct mg_connection *conn)
static void free_context(struct mg_context *ctx)
static int convert_uri_to_file_name(struct mg_connection *conn, char *buf, size_t buf_len, struct file *filep)
static unsigned long ssl_id_callback(void)
static int parse_port_string(const struct vec *vec, struct socket *so)
static const char * month_names[]
static char * addenv(struct cgi_env_block *block, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
static const struct @22 builtin_mime_types[]
static int match_prefix(const char *pattern, int pattern_len, const char *str)
static void handle_request(struct mg_connection *conn)
struct MD5Context MD5_CTX
static int is_big_endian(void)
static int remove_directory(struct mg_connection *conn, const char *dir)
static int get_request_len(const char *buf, int buf_len)
static int mg_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap)
static void handle_cgi_request(struct mg_connection *conn, const char *prog)
static void static void static int getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len)
static int mg_snprintf(char *buf, size_t buflen, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(3
static struct mg_connection * fc(struct mg_context *ctx)
static void * worker_thread(void *thread_func_param)
static FILE * mg_fopen(const char *path, const char *mode)
static void static void cry(struct mg_connection *conn, PRINTF_FORMAT_STRING(const char *fmt),...) PRINTF_ARGS(2
static void close_socket_gracefully(struct mg_connection *conn)
static int call_user(int type, struct mg_connection *conn, void *p)
static int parse_http_message(char *buf, int len, struct mg_request_info *ri)
static char * mg_strndup(const char *ptr, size_t len)
static const char * http_500_error
static int set_acl_option(struct mg_context *ctx)
static int get_month_index(const char *s)
static int is_valid_port(unsigned int port)
#define PASSWORDS_FILE_NAME
static void log_access(const struct mg_connection *conn)
static void close_connection(struct mg_connection *conn)
static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len)
static void redirect_to_https_port(struct mg_connection *conn, int ssl_index)
#define STRUCT_FILE_INITIALIZER
static int is_valid_http_method(const char *method)
char * inet_ntoa(struct in_addr n)
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size)
int inet_pton(int af, const char *src, void *dst)
#define R1(v, w, x, y, z, i)
static int left(const struct frozen *f)
#define R2(v, w, x, y, z, i)
#define R0(v, w, x, y, z, i)
static int expect(struct frozen *f, const char *s, int len, enum json_type t)
#define R3(v, w, x, y, z, i)
static uint32_t blk0(union char64long16 *block, int i)
#define R4(v, w, x, y, z, i)
char * vars[MAX_CGI_ENVIR_VARS]
struct mg_connection * conn
char buf[CGI_ENVIRONMENT_SIZE]
struct mg_connection * conn
time_t last_throttle_time
struct mg_request_info request_info
int64_t last_throttle_bytes
int num_listening_sockets
mg_event_handler_t event_handler
struct socket * listening_sockets
struct socket queue[MGSQLEN]
char * config[NUM_OPTIONS]
bool rmdir(HNDLE hDB, HNDLE hROOT, const char *path)
static te_expr * list(state *s)