915 {
916 ctx->buf[0] = 0x67452301;
917 ctx->buf[1] = 0xefcdab89;
918 ctx->buf[2] = 0x98badcfe;
919 ctx->buf[3] = 0x10325476;
920
921 ctx->bits[0] = 0;
922 ctx->bits[1] = 0;
923}
924
925static void MD5Transform(uint32_t buf[4], uint32_t
const in[16]) {
926 register uint32_t a, b,
c,
d;
927
928 a = buf[0];
929 b = buf[1];
932
949
966
983
1000
1001 buf[0] += a;
1002 buf[1] += b;
1005}
1006
1007static void MD5Update(
MD5_CTX *ctx,
unsigned char const *buf,
unsigned len) {
1008 uint32_t t;
1009
1011 if ((ctx->
bits[0] = t + ((uint32_t) len << 3)) < t)
1013 ctx->
bits[1] += len >> 29;
1014
1015 t = (t >> 3) & 0x3f;
1016
1017 if (t) {
1018 unsigned char *p = (
unsigned char *) ctx->
in + t;
1019
1020 t = 64 - t;
1021 if (len < t) {
1022 memcpy(p, buf, len);
1023 return;
1024 }
1025 memcpy(p, buf, t);
1028 buf += t;
1029 len -= t;
1030 }
1031
1032 while (len >= 64) {
1033 memcpy(ctx->
in, buf, 64);
1036 buf += 64;
1037 len -= 64;
1038 }
1039
1040 memcpy(ctx->
in, buf, len);
1041}
1042
1045 unsigned char *p;
1046 uint32_t *a;
1047
1049
1051 *p++ = 0x80;
1054 memset(p, 0,
count);
1057 memset(ctx->
in, 0, 56);
1058 } else {
1059 memset(p, 0,
count - 8);
1060 }
1062
1063 a = (uint32_t *)ctx->
in;
1064 a[14] = ctx->
bits[0];
1065 a[15] = ctx->
bits[1];
1066
1069 memcpy(digest, ctx->
buf, 16);
1070 memset((char *) ctx, 0, sizeof(*ctx));
1071}
1072#endif
1073
1074
1075
1076
1077
1078static void bin2str(
char *to,
const unsigned char *p,
size_t len) {
1079 static const char *hex = "0123456789abcdef";
1080
1081 for (; len--; p++) {
1082 *to++ = hex[p[0] >> 4];
1083 *to++ = hex[p[0] & 0x0f];
1084 }
1085 *to = '\0';
1086}
1087
1088
1089char *
mg_md5(
char buf[33], ...) {
1090 unsigned char hash[16];
1091 const char *p;
1092 va_list ap;
1094
1096
1097 va_start(ap, buf);
1098 while ((p = va_arg(ap, const char *)) != NULL) {
1099 MD5Update(&ctx, (
const unsigned char *) p, (
unsigned) strlen(p));
1100 }
1101 va_end(ap);
1102
1104 bin2str(buf, hash,
sizeof(hash));
1105 return buf;
1106}
1107
1108
1109static int check_password(
const char *method,
const char *ha1,
const char *uri,
1110 const char *nonce, const char *nc, const char *cnonce,
1111 const char *qop,
const char *
response) {
1112 char ha2[32 + 1], expected_response[32 + 1];
1113
1114
1115 if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
1117 return 0;
1118 }
1119
1120
1121
1122 if (
1124
1125 ) {
1126 return 0;
1127 }
1128
1129 mg_md5(ha2, method,
":", uri, NULL);
1130 mg_md5(expected_response, ha1,
":", nonce,
":", nc,
1131 ":", cnonce, ":", qop, ":", ha2, NULL);
1132
1134}
1135
1136
1137
1143
1144 if (gpass != NULL) {
1145
1147
1148
1153 } else {
1154
1155 for (p = path,
e = p + strlen(p) - 1;
e > p;
e--)
1157 break;
1161 }
1162
1164}
1165
1166
1169};
1170
1171
1173 size_t buf_size,
struct ah *
ah) {
1175 const char *auth_header;
1176
1177 (void) memset(
ah, 0,
sizeof(*
ah));
1178 if ((auth_header =
mg_get_header(conn,
"Authorization")) == NULL ||
1180 return 0;
1181 }
1182
1183
1184 (void)
mg_strlcpy(buf, auth_header + 7, buf_size);
1185 s = buf;
1186
1187
1188 for (;;) {
1189
1190 while (isspace(* (unsigned char *) s)) {
1191 s++;
1192 }
1194
1195 if (s[0] == '\"') {
1196 s++;
1198 if (s[0] == ',') {
1199 s++;
1200 }
1201 } else {
1203 }
1204 if (*
name ==
'\0') {
1205 break;
1206 }
1207
1208 if (!strcmp(
name,
"username")) {
1210 }
else if (!strcmp(
name,
"cnonce")) {
1212 }
else if (!strcmp(
name,
"response")) {
1214 }
else if (!strcmp(
name,
"uri")) {
1216 }
else if (!strcmp(
name,
"qop")) {
1218 }
else if (!strcmp(
name,
"nc")) {
1220 }
else if (!strcmp(
name,
"nonce")) {
1222 }
1223 }
1224
1225
1228 } else {
1229 return 0;
1230 }
1231
1232 return 1;
1233}
1234
1235
1238 char line[256], f_user[256], ha1[256], f_domain[256], buf[
MG_BUF_LEN];
1239
1241 return 0;
1242 }
1243
1244
1245 while (fgets(line,
sizeof(line),
fp) != NULL) {
1246 if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
1247 continue;
1248 }
1249
1250 if (!strcmp(
ah.
user, f_user) &&
1254 }
1255
1256 return 0;
1257}
1258
1259
1262 struct vec uri_vec, filename_vec;
1265 int authorized = 1;
1266
1271 (int) filename_vec.len, filename_vec.ptr);
1273 break;
1274 }
1275 }
1276
1279 }
1280
1284 }
1285
1286 return authorized;
1287}
1288
1292 "HTTP/1.1 401 Unauthorized\r\n"
1293 "Content-Length: 0\r\n"
1294 "WWW-Authenticate: Digest qop=\"auth\", "
1295 "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
1297 (unsigned long) time(NULL));
1298}
1299
1303 int ret = 0;
1304
1305 if (passfile != NULL && (
fp =
mg_fopen(passfile,
"r")) != NULL) {
1308 }
1309
1310 return ret;
1311}
1312
1314 const char *user, const char *pass) {
1315 int found;
1316 char line[512], u[512],
d[512], ha1[33], tmp[
PATH_MAX];
1318
1319 found = 0;
1321
1322
1323 if (pass != NULL && pass[0] == '\0') {
1324 pass = NULL;
1325 }
1326
1327 (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
1328
1329
1330 if ((
fp = fopen(fname,
"a+")) != NULL) {
1332 }
1333
1334
1335 if ((
fp = fopen(fname,
"r")) == NULL) {
1336 return 0;
1337 } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
1339 return 0;
1340 }
1341
1342
1343 while (fgets(line,
sizeof(line),
fp) != NULL) {
1344 if (sscanf(line,
"%[^:]:%[^:]:%*s", u,
d) != 2) {
1345 continue;
1346 }
1347
1348 if (!strcmp(u, user) && !strcmp(
d, domain)) {
1349 found++;
1350 if (pass != NULL) {
1351 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
1352 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
1353 }
1354 } else {
1355 fprintf(fp2, "%s", line);
1356 }
1357 }
1358
1359
1360 if (!found && pass != NULL) {
1361 mg_md5(ha1, user,
":", domain,
":", pass, NULL);
1362 fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
1363 }
1364
1365
1367 fclose(fp2);
1368
1369
1370 remove(fname);
1371 rename(tmp, fname);
1372
1373 return 1;
1374}
1375
1376#if defined(_WIN32)
1377static pthread_t pthread_self(void) {
1378 return GetCurrentThreadId();
1379}
1380
1381static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
1382 (void) unused;
1383 *mutex = CreateMutex(NULL,
FALSE, NULL);
1384 return *mutex == NULL ? -1 : 0;
1385}
1386
1387static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
1388 return CloseHandle(*mutex) == 0 ? -1 : 0;
1389}
1390
1391static int pthread_mutex_lock(pthread_mutex_t *mutex) {
1392 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1393}
1394
1395static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
1396 return ReleaseMutex(*mutex) == 0 ? -1 : 0;
1397}
1398
1399static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
1400 (void) unused;
1401 cv->signal = CreateEvent(NULL,
FALSE,
FALSE, NULL);
1402 cv->broadcast = CreateEvent(NULL,
TRUE,
FALSE, NULL);
1403 return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
1404}
1405
1406static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
1407 HANDLE handles[] = {cv->signal, cv->broadcast};
1408 ReleaseMutex(*mutex);
1409 WaitForMultipleObjects(2, handles,
FALSE, INFINITE);
1410 return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
1411}
1412
1413static int pthread_cond_signal(pthread_cond_t *cv) {
1414 return SetEvent(cv->signal) == 0 ? -1 : 0;
1415}
1416
1417static int pthread_cond_broadcast(pthread_cond_t *cv) {
1418
1419
1420 return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
1421}
1422
1423static int pthread_cond_destroy(pthread_cond_t *cv) {
1424 return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
1425}
1426
1427
1428static void change_slashes_to_backslashes(char *path) {
1430
1431 for (
i = 0; path[
i] !=
'\0';
i++) {
1434
1435 if (path[
i] ==
'\\' &&
i > 0)
1436 while (path[
i + 1] ==
'\\' || path[
i + 1] ==
'/')
1437 (void) memmove(path +
i + 1,
1438 path +
i + 2, strlen(path +
i + 1));
1439 }
1440}
1441
1442
1443
1444static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
1446
1448 change_slashes_to_backslashes(buf);
1449
1450
1451
1452 memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
1453 MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
1454 WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
1455 NULL, NULL);
1456 if (strcmp(buf, buf2) != 0) {
1457 wbuf[0] = L'\0';
1458 }
1459}
1460
1461#if defined(_WIN32_WCE)
1462static time_t time(time_t *ptime) {
1463 time_t t;
1464 SYSTEMTIME st;
1465 FILETIME ft;
1466
1467 GetSystemTime(&st);
1468 SystemTimeToFileTime(&st, &ft);
1469 t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
1470
1471 if (ptime != NULL) {
1472 *ptime = t;
1473 }
1474
1475 return t;
1476}
1477
1478static struct tm *
localtime(
const time_t *ptime,
struct tm *ptm) {
1479 int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
1480 FILETIME ft, lft;
1481 SYSTEMTIME st;
1482 TIME_ZONE_INFORMATION tzinfo;
1483
1484 if (ptm == NULL) {
1485 return NULL;
1486 }
1487
1488 * (int64_t *) &ft = t;
1489 FileTimeToLocalFileTime(&ft, &lft);
1490 FileTimeToSystemTime(&lft, &st);
1491 ptm->tm_year = st.wYear - 1900;
1492 ptm->tm_mon = st.wMonth - 1;
1493 ptm->tm_wday = st.wDayOfWeek;
1494 ptm->tm_mday = st.wDay;
1495 ptm->tm_hour = st.wHour;
1496 ptm->tm_min = st.wMinute;
1497 ptm->tm_sec = st.wSecond;
1498 ptm->tm_yday = 0;
1499 ptm->tm_isdst =
1500 GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
1501
1502 return ptm;
1503}
1504
1505static struct tm *
gmtime(
const time_t *ptime,
struct tm *ptm) {
1506
1508}
1509
1510static size_t strftime(char *dst, size_t dst_size, const char *fmt,
1511 const struct tm *
tm) {
1512 (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
1513 return 0;
1514}
1515#endif
1516
1517
1518
1519
1520
1521static int path_cannot_disclose_cgi(const char *path) {
1522 static const char *allowed_last_characters = "_-";
1523 int last = path[strlen(path) - 1];
1524 return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
1525}
1526
1527static int mg_stat(
const char *path,
struct file *filep) {
1528 wchar_t wbuf[
PATH_MAX] = L
"\\\\?\\";
1529 WIN32_FILE_ATTRIBUTE_DATA
info;
1530
1532 to_unicode(path, wbuf + 4,
ARRAY_SIZE(wbuf) - 4);
1533 if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &
info) != 0) {
1534 filep->
size = MAKEUQUAD(
info.nFileSizeLow,
info.nFileSizeHigh);
1536 info.ftLastWriteTime.dwLowDateTime,
1537 info.ftLastWriteTime.dwHighDateTime);
1539
1540
1541
1542 if (!filep->
is_directory && !path_cannot_disclose_cgi(path)) {
1543 memset(filep, 0, sizeof(*filep));
1544 }
1545 }
1546
1548}
1549
1553 return DeleteFileW(wbuf) ? 0 : -1;
1554}
1555
1556static int mg_mkdir(
const char *path,
int mode) {
1559
1560 (void) mode;
1562 change_slashes_to_backslashes(buf);
1563
1564 (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf,
ARRAY_SIZE(wbuf));
1565
1566 return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
1567}
1568
1569
1570static DIR * opendir(
const char *
name) {
1574
1576 SetLastError(ERROR_BAD_ARGUMENTS);
1577 }
else if ((dir = (
DIR *) malloc(
sizeof(*dir))) == NULL) {
1578 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1579 } else {
1581 attrs = GetFileAttributesW(wpath);
1582 if (attrs != 0xFFFFFFFF &&
1583 ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
1584 (void) wcscat(wpath, L"\\*");
1585 dir->handle = FindFirstFileW(wpath, &dir->info);
1586 dir->result.d_name[0] = '\0';
1587 } else {
1588 free(dir);
1589 dir = NULL;
1590 }
1591 }
1592
1593 return dir;
1594}
1595
1596static int closedir(
DIR *dir) {
1597 int result = 0;
1598
1599 if (dir != NULL) {
1600 if (dir->handle != INVALID_HANDLE_VALUE)
1601 result = FindClose(dir->handle) ? 0 : -1;
1602
1603 free(dir);
1604 } else {
1605 result = -1;
1606 SetLastError(ERROR_BAD_ARGUMENTS);
1607 }
1608
1609 return result;
1610}
1611
1612static struct dirent *readdir(
DIR *dir) {
1613 struct dirent *result = 0;
1614
1615 if (dir) {
1616 if (dir->handle != INVALID_HANDLE_VALUE) {
1617 result = &dir->result;
1618 (void) WideCharToMultiByte(CP_UTF8, 0,
1619 dir->info.cFileName, -1, result->d_name,
1620 sizeof(result->d_name), NULL, NULL);
1621
1622 if (!FindNextFileW(dir->handle, &dir->info)) {
1623 (void) FindClose(dir->handle);
1624 dir->handle = INVALID_HANDLE_VALUE;
1625 }
1626
1627 } else {
1628 SetLastError(ERROR_FILE_NOT_FOUND);
1629 }
1630 } else {
1631 SetLastError(ERROR_BAD_ARGUMENTS);
1632 }
1633
1634 return result;
1635}
1636
1637#ifndef HAVE_POLL
1638static int poll(
struct pollfd *pfd,
int n,
int milliseconds) {
1640 fd_set set;
1643
1644 tv.tv_sec = milliseconds / 1000;
1645 tv.tv_usec = (milliseconds % 1000) * 1000;
1646 FD_ZERO(&set);
1647
1648 for (
i = 0;
i <
n;
i++) {
1649 FD_SET((
SOCKET) pfd[
i].fd, &
set);
1651
1652 if (pfd[
i].fd > maxfd) {
1654 }
1655 }
1656
1657 if ((result = select(maxfd + 1, &
set, NULL, NULL, &
tv)) > 0) {
1658 for (
i = 0;
i <
n;
i++) {
1659 if (FD_ISSET(pfd[
i].fd, &
set)) {
1660 pfd[
i].revents = POLLIN;
1661 }
1662 }
1663 }
1664
1665 return result;
1666}
1667#endif
1668
1670 (void) SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0);
1671}
1672
1674 return (long)_beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
1675}
1676
1677static HANDLE dlopen(const char *dll_name, int flags) {
1679 (void) flags;
1680 to_unicode(dll_name, wbuf,
ARRAY_SIZE(wbuf));
1681 return LoadLibraryW(wbuf);
1682}
1683
1684#if !defined(NO_CGI)
1685#define SIGKILL 0
1686static int kill(pid_t pid, int sig_num) {
1687 (void) TerminateProcess(pid, sig_num);
1688 (void) CloseHandle(pid);
1689 return 0;
1690}
1691
1692static void trim_trailing_whitespaces(char *s) {
1693 char *
e = s + strlen(s) - 1;
1694 while (
e > s && isspace(* (
unsigned char *)
e)) {
1696 }
1697}
1698
1700 char *envblk, char *envp[], int fdin,
1701 int fdout, const char *dir) {
1702 HANDLE me;
1706 STARTUPINFOA si;
1707 PROCESS_INFORMATION
pi = { 0 };
1708
1709 (void) envp;
1710
1711 memset(&si, 0, sizeof(si));
1712 si.cb = sizeof(si);
1713
1714
1715 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
1716 si.wShowWindow = SW_HIDE;
1717
1718 me = GetCurrentProcess();
1719 DuplicateHandle(me, (HANDLE) _get_osfhandle(fdin), me,
1720 &si.hStdInput, 0,
TRUE, DUPLICATE_SAME_ACCESS);
1721 DuplicateHandle(me, (HANDLE) _get_osfhandle(fdout), me,
1722 &si.hStdOutput, 0,
TRUE, DUPLICATE_SAME_ACCESS);
1723
1724
1726 if (interp == NULL) {
1727 buf[0] = buf[1] = '\0';
1728
1729
1730 snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
1732 fgets(buf,
sizeof(buf),
fp);
1734 buf[sizeof(buf) - 1] = '\0';
1735 }
1736
1737 if (buf[0] == '#' && buf[1] == '!') {
1738 trim_trailing_whitespaces(buf + 2);
1739 } else {
1740 buf[2] = '\0';
1741 }
1742 interp = buf + 2;
1743 }
1744
1745 if (interp[0] != '\0') {
1746 GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
1747 interp = full_interp;
1748 }
1749 GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
1750
1751 mg_snprintf(cmdline,
sizeof(cmdline),
"%s%s\"%s\\%s\"",
1752 interp, interp[0] == '\0' ? "" : " ", full_dir, prog);
1753
1755 if (CreateProcessA(NULL, cmdline, NULL, NULL,
TRUE,
1756 CREATE_NEW_PROCESS_GROUP, envblk, NULL, &si, &
pi) == 0) {
1757 cry(conn,
"%s: CreateProcess(%s): %ld",
1758 __func__, cmdline,
ERRNO);
1759 pi.hProcess = (pid_t) -1;
1760 }
1761
1762 (void) CloseHandle(si.hStdOutput);
1763 (void) CloseHandle(si.hStdInput);
1764 (void) CloseHandle(
pi.hThread);
1765
1766 return (pid_t)
pi.hProcess;
1767}
1768#endif
1769
1771 unsigned long on = 1;
1772 return ioctlsocket(sock, FIONBIO, &on);
1773}
1774#endif
1775
1776#if !defined(_WIN32)
1777static int mg_stat(
const char *path,
struct file *filep) {
1778 struct stat st;
1779
1781 if (stat(path, &st) == 0) {
1782 filep->
size = st.st_size;
1785
1786
1787
1788
1791 }
1792 }
1793
1795}
1796
1798 fcntl(fd, F_SETFD, FD_CLOEXEC);
1799}
1800
1802 pthread_t thread_id;
1803 pthread_attr_t attr;
1804 int result;
1805
1806 (void) pthread_attr_init(&attr);
1807 (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1808
1809#if USE_STACK_SIZE > 1
1810
1811 (void) pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
1812#endif
1813
1814 result = pthread_create(&thread_id, &attr, func,
param);
1815 pthread_attr_destroy(&attr);
1816
1817 return result;
1818}
1819
1820#ifndef NO_CGI
1822 char *envblk, char *envp[], int fdin,
1823 int fdout, const char *dir) {
1824 pid_t pid;
1825 const char *interp;
1826
1827 (void) envblk;
1828
1829 if ((pid = fork()) == -1) {
1830
1832 } else if (pid == 0) {
1833
1834 if (chdir(dir) != 0) {
1835 cry(conn,
"%s: chdir(%s): %s", __func__, dir, strerror(
ERRNO));
1836 } else if (dup2(fdin, 0) == -1) {
1837 cry(conn,
"%s: dup2(%d, 0): %s", __func__, fdin, strerror(
ERRNO));
1838 } else if (dup2(fdout, 1) == -1) {
1839 cry(conn,
"%s: dup2(%d, 1): %s", __func__, fdout, strerror(
ERRNO));
1840 } else {
1841
1842
1843 (void) close(fdin);
1844 (void) close(fdout);
1845
1846
1847
1848
1849
1850 signal(SIGCHLD, SIG_DFL);
1851
1853 if (interp == NULL) {
1854 (void) execle(prog, prog, NULL, envp);
1855 cry(conn,
"%s: execle(%s): %s", __func__, prog, strerror(
ERRNO));
1856 } else {
1857 (void) execle(interp, interp, prog, NULL, envp);
1858 cry(conn,
"%s: execle(%s %s): %s", __func__, interp, prog,
1860 }
1861 }
1862 exit(EXIT_FAILURE);
1863 }
1864
1865 return pid;
1866}
1867#endif
1868
1870 int flags;
1871
1872 flags = fcntl(sock, F_GETFL, 0);
1873 (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
1874
1875 return 0;
1876}
1877#endif
1878
1879
1880
1881
1882
1883static int alloc_vprintf(
char **buf,
size_t size,
const char *fmt, va_list ap) {
1884 va_list ap_copy;
1885 int len;
1886
1887
1888
1889
1890
1891
1892 va_copy(ap_copy, ap);
1893 len = vsnprintf(NULL, 0, fmt, ap_copy);
1894
1895 if (len > (int) size &&
1896 (size = len + 1) > 0 &&
1897 (*buf = (char *) malloc(size)) == NULL) {
1898 len = -1;
1899 } else {
1900 va_copy(ap_copy, ap);
1901 vsnprintf(*buf, size, fmt, ap_copy);
1902 }
1903
1904 return len;
1905}
1906
1909 int len;
1910
1911 if ((len =
alloc_vprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
1912 len =
mg_write(conn, buf, (
size_t) len);
1913 }
1914 if (buf != mem && buf != NULL) {
1915 free(buf);
1916 }
1917
1918 return len;
1919}
1920
1922 va_list ap;
1923 va_start(ap, fmt);
1925}
1926
1929 int len;
1930
1931 va_list ap;
1932 va_start(ap, fmt);
1933 if ((len =
alloc_vprintf(&buf,
sizeof(mem), fmt, ap)) > 0) {
1934 len =
mg_printf(conn,
"%X\r\n%s\r\n", len, buf);
1935 }
1936
1937 if (buf != mem && buf != NULL) {
1938 free(buf);
1939 }
1940
1941 return len;
1942}
1943
1944
1945
1946#if !defined(NO_SSL)
1947
1948#if !defined(NO_SSL_DL)
1949
1950
1951
1952
1953static struct ssl_func ssl_sw[] = {
1954 {"SSL_free", NULL},
1955 {"SSL_accept", NULL},
1956 {"SSL_connect", NULL},
1957 {"SSL_read", NULL},
1958 {"SSL_write", NULL},
1959 {"SSL_get_error", NULL},
1960 {"SSL_set_fd", NULL},
1961 {"SSL_new", NULL},
1962 {"SSL_CTX_new", NULL},
1963 {"SSLv23_server_method", NULL},
1964 {"SSL_library_init", NULL},
1965 {"SSL_CTX_use_PrivateKey_file", NULL},
1966 {"SSL_CTX_use_certificate_file",NULL},
1967 {"SSL_CTX_set_default_passwd_cb",NULL},
1968 {"SSL_CTX_free", NULL},
1969 {"SSL_load_error_strings", NULL},
1970 {"SSL_CTX_use_certificate_chain_file", NULL},
1971 {"SSLv23_client_method", NULL},
1972 {"SSL_pending", NULL},
1973 {"SSL_CTX_set_verify", NULL},
1974 {"SSL_shutdown", NULL},
1975 {"SSL_CTX_ctrl", NULL},
1976 {"SSL_CTX_set_cipher_list", NULL},
1977 {"EC_KEY_new_by_curve_name", NULL},
1978 {"EC_KEY_free", NULL},
1979 {"SSL_get_cipher_list", NULL},
1980 {NULL, NULL}
1981};
1982
1983
1984static struct ssl_func crypto_sw[] = {
1985 {"CRYPTO_num_locks", NULL},
1986 {"CRYPTO_set_locking_callback", NULL},
1987 {"CRYPTO_set_id_callback", NULL},
1988 {"ERR_get_error", NULL},
1989 {"ERR_error_string", NULL},
1990 {NULL, NULL}
1991};
1992#endif
1993
1995
1997 return (conn->
ssl = SSL_new(s)) != NULL &&
1999 func(conn->
ssl) == 1;
2000}
2001
2002
2004 unsigned long err;
2005 err = ERR_get_error();
2006 return err == 0 ? "" : ERR_error_string(err, NULL);
2007}
2008
2010 int line) {
2011 (void) line;
2013
2014 if (mode & 1) {
2015 (void) pthread_mutex_lock(&
ssl_mutexes[mutex_num]);
2016 } else {
2017 (void) pthread_mutex_unlock(&
ssl_mutexes[mutex_num]);
2018 }
2019}
2020
2022 return (unsigned long) pthread_self();
2023}
2024
2025#if !defined(NO_SSL_DL)
2026static int load_dll(
struct mg_context *ctx,
const char *dll_name,
2027 struct ssl_func *sw) {
2028 union {
void *p; void (*
fp)(void);} u;
2029 void *dll_handle;
2030 struct ssl_func *
fp;
2031
2032 if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
2033 cry(
fc(ctx),
"%s: cannot load %s", __func__, dll_name);
2034 return 0;
2035 }
2036
2037 for (
fp = sw;
fp->name != NULL;
fp++) {
2038#ifdef _WIN32
2039
2040 u.fp = (void (*)(void)) dlsym(dll_handle,
fp->name);
2041#else
2042
2043
2044 u.p = dlsym(dll_handle,
fp->name);
2045#endif
2046 if (u.fp == NULL) {
2047 cry(
fc(ctx),
"%s: %s: cannot find %s", __func__, dll_name,
fp->name);
2048 return 0;
2049 } else {
2051 }
2052 }
2053
2054 return 1;
2055}
2056#endif
2057
2058
2061 const char *pem;
2062 int ecdh_enabled = 0;
2063 int ecdh_available = 0;
2064
2065
2066
2068
2069
2070 return 1;
2071 }
2072
2073#if !defined(NO_SSL_DL)
2074 if (!load_dll(ctx,
SSL_LIB, ssl_sw) ||
2076 return 0;
2077 }
2078#endif
2079
2080
2081 SSL_library_init();
2082 SSL_load_error_strings();
2083
2084 if ((ctx->
ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
2086 return 0;
2087 }
2088
2089 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_NO_SSLv2);
2090 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_NO_SSLv3);
2091
2092#if 0
2093 {
2094
2095
2096
2097
2098
2099
2100
2101
2102 void *dh_2048 = NULL;
2103 FILE *paramfile;
2104 paramfile = fopen("dh_param_2048.pem", "r");
2105 if (paramfile) {
2106 dh_2048 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
2107 fclose(paramfile);
2108 } else {
2109
2110 }
2111 if (dh_2048 == NULL) {
2112
2113 }
2114 if (SSL_CTX_set_tmp_dh(ctx->
ssl_ctx, dh_2048) != 1) {
2115
2116 }
2117 }
2118#endif
2119
2120#ifdef OPENSSL_EC_NAMED_CURVE
2121 {
2122
2123
2124
2125
2126 EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1);
2127 if (! ecdh) {
2128 cry(
fc(ctx),
"%s: EC_KEY_new_by_curve_name (NID_X9_62_prime256v1) failed: %s", __func__,
ssl_error());
2129 } else {
2130 if (1 != SSL_CTX_set_tmp_ecdh (ctx->
ssl_ctx, ecdh)) {
2131 cry(
fc(ctx),
"%s: SSL_CTX_set_tmp_ecdh (ctx->ssl_ctx, ecdh) failed: %s", __func__,
ssl_error());
2132 }
2133 EC_KEY_free (ecdh);
2134 ecdh_enabled = 1;
2135 }
2136 }
2137#else
2138#warning Very old openssl, no EC_KEY, no ECDH for modern criptography!
2139#endif
2140
2141 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_SINGLE_DH_USE);
2142 SSL_CTX_set_options(ctx->
ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
2143
2144
2145
2146 {
2147 int priority;
2149 for (priority=0; 1; priority++) {
2150 const char* available_cipher_list = SSL_get_cipher_list(ssl, priority);
2151 if (available_cipher_list == NULL)
2152 break;
2153
2154 if (strstr(available_cipher_list, "ECDHE") != NULL)
2155 ecdh_available = 1;
2156 }
2157 SSL_free(ssl);
2158 }
2159
2160 if (!ecdh_available || !ecdh_enabled) {
2161 cry(
fc(ctx),
"%s: openssl \"modern cryptography\" ECDH ciphers not available", __func__);
2162 }
2163
2164
2165 const char* cipher_list = "ALL:!RC4:!DES-CBC-SHA:!DES:!DES-CBC3-SHA:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW";
2166
2167
2168 if (ecdh_available && ecdh_enabled)
2169 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";
2170
2171 SSL_CTX_set_cipher_list(ctx->
ssl_ctx, cipher_list);
2172
2173
2174
2175
2176 if (SSL_CTX_use_certificate_file(ctx->
ssl_ctx, pem, 1) == 0 ||
2177 SSL_CTX_use_PrivateKey_file(ctx->
ssl_ctx, pem, 1) == 0) {
2178 cry(
fc(ctx),
"%s: cannot open %s: %s", __func__, pem,
ssl_error());
2179 return 0;
2180 }
2181
2182 if (pem != NULL) {
2183 (void) SSL_CTX_use_certificate_chain_file(ctx->
ssl_ctx, pem);
2184 }
2185
2186
2187
2188 size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
2189 if ((
ssl_mutexes = (pthread_mutex_t *) malloc((
size_t)size)) == NULL) {
2190 cry(
fc(ctx),
"%s: cannot allocate mutexes: %s", __func__,
ssl_error());
2191 return 0;
2192 }
2193
2194 for (
i = 0;
i < CRYPTO_num_locks();
i++) {
2196 }
2197
2200
2201 return 1;
2202}
2203
2207 CRYPTO_set_locking_callback(NULL);
2208 for (
i = 0;
i < CRYPTO_num_locks();
i++) {
2210 }
2211 CRYPTO_set_locking_callback(NULL);
2212 CRYPTO_set_id_callback(NULL);
2213 }
2214}
2215#endif
2216
2217static SOCKET conn2(
const char *host,
int port,
int use_ssl,
2218 char *ebuf, size_t ebuf_len) {
2219 struct sockaddr_in sin;
2220 struct hostent *he = NULL;
2222
2223 (void) use_ssl;
2224
2225 if (host == NULL) {
2226 snprintf(ebuf, ebuf_len, "%s", "NULL host");
2227#ifndef NO_SSL
2228 } else if (use_ssl && (void *)SSLv23_client_method == NULL) {
2229 snprintf(ebuf, ebuf_len, "%s", "SSL is not initialized");
2230
2231#endif
2232 } else if ((he = gethostbyname(host)) == NULL) {
2233 snprintf(ebuf, ebuf_len,
"gethostbyname(%s): %s", host, strerror(
ERRNO));
2235 snprintf(ebuf, ebuf_len,
"socket(): %s", strerror(
ERRNO));
2236 } else {
2238 sin.sin_family = AF_INET;
2239 sin.sin_port = htons((uint16_t) port);
2240 sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
2241 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
2242 snprintf(ebuf, ebuf_len, "connect(%s:%d): %s",
2243 host, port, strerror(
ERRNO));
2246 }
2247 }
2248 return sock;
2249}
2250
2252 char *ebuf, size_t ebuf_len) {
2256
2260 snprintf(ebuf, ebuf_len,
"calloc(): %s", strerror(
ERRNO));
2262#ifndef NO_SSL
2264 SSL_CTX_new(SSLv23_client_method())) == NULL) {
2265 snprintf(ebuf, ebuf_len, "SSL_CTX_new error");
2267 free(conn);
2268 conn = NULL;
2269#endif
2270 } else {
2271 socklen_t len = sizeof(struct sockaddr);
2273 conn->
buf = (
char *) (conn + 1);
2274 conn->
ctx = &fake_ctx;
2278#ifndef NO_SSL
2279 if (use_ssl) {
2280
2281
2284 }
2285#endif
2286 }
2287
2288 return conn;
2289}
2290
2292 char *ebuf, size_t ebuf_len,
2293 const char *fmt, ...) {
2295 va_list ap;
2296
2297 va_start(ap, fmt);
2298 ebuf[0] = '\0';
2299 if ((conn =
mg_connect(host, port, use_ssl, ebuf, ebuf_len)) == NULL) {
2301 snprintf(ebuf, ebuf_len, "%s", "Error sending request");
2302 } else {
2303 getreq(conn, ebuf, ebuf_len);
2304 }
2305 if (ebuf[0] != '\0' && conn != NULL) {
2307 conn = NULL;
2308 }
2309
2310 return conn;
2311}
2312
2313
2316}
2317
2319 if (conn != NULL && conn->
ctx != NULL) {
2325 }
2328}
2329
2330static FILE *
mg_fopen(
const char *path,
const char *mode) {
2331#ifdef _WIN32
2334 MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode,
ARRAY_SIZE(wmode));
2335 return _wfopen(wbuf, wmode);
2336#else
2337 return fopen(path, mode);
2338#endif
2339}
2340
2344#if defined(USE_IPV6)
2346 (
void *) &
usa->
sin.sin_addr :
2347 (void *) &
usa->sin6.sin6_addr,
buf, len);
2348#elif defined(_WIN32)
2349
2351#else
2353#endif
2354}
2355
2356
2359 va_list ap;
2361 time_t timestamp;
2362
2363 va_start(ap, fmt);
2364 (void) vsnprintf(
buf,
sizeof(
buf), fmt, ap);
2365 va_end(ap);
2366
2367
2368
2369
2373
2376 timestamp = time(NULL);
2377
2379 fprintf(
fp,
"[%010lu] [error] [client %s] ", (
unsigned long) timestamp,
2380 src_addr);
2381
2385 }
2386
2387 fprintf(
fp,
"%s",
buf);
2391 }
2392 }
2393}
2394
2397}
2398
2399
2400
2401
2408 (header != NULL &&
mg_strcasecmp(header,
"keep-alive") != 0) ||
2409 (header == NULL && http_version && strcmp(http_version, "1.1"))) {
2410 return 0;
2411 }
2412 return 1;
2413}
2414
2417}
2418
2420 const char *reason, const char *fmt, ...) {
2422 va_list ap;
2423 int len = 0;
2424
2427
2428
2432
2433 va_start(ap, fmt);
2435 va_end(ap);
2436 }
2438
2441 "Content-Length: %d\r\n"
2442 "Connection: %s\r\n\r\n",
status, reason, len,
2445 }
2446}
2447
2448
2449
2451 int64_t len) {
2452 int64_t sent;
2454
2456 sent = 0;
2457 while (sent < len) {
2458
2459
2460 k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
2461
2462#if !defined(NO_SSL)
2465 } else
2466#endif
2468 n = (int) fwrite(
buf + sent, 1, (
size_t)
k,
fp);
2471 } else {
2473 }
2474
2476 break;
2477
2479 }
2480
2481 return sent;
2482}
2483
2484
2485
2487 int nread;
2488
2489 if (len <= 0) return 0;
2491
2492
2493
2494 nread =
read(fileno(
fp),
buf, (
size_t) len);
2495#ifndef NO_SSL
2496 }
else if (conn->
ssl != NULL) {
2497 nread = SSL_read(conn->
ssl,
buf, len);
2498#endif
2499 } else {
2501 }
2502 if (nread > 0) {
2504 }
2505
2507}
2508
2511
2516 break;
2517 }
else if (
n == 0) {
2518 break;
2519 } else {
2522 }
2523 }
2524
2525 return nread;
2526}
2527
2529 int n, buffered_len, nread = 0;
2531
2533 return 0;
2534 }
2535
2536
2537
2538
2539
2540
2541
2544 if (buffered_len > len) buffered_len = len;
2546
2547 memcpy(
buf, body, (
size_t) buffered_len);
2548 memmove(body, body + buffered_len,
2549 &conn->
buf[conn->
data_len] - &body[buffered_len]);
2550 len -= buffered_len;
2552 nread += buffered_len;
2553 }
2554
2555
2559 }
2560 n =
pull_all(NULL, conn, (
char *)
buf + nread, (
int) len);
2561 nread =
n >= 0 ? nread +
n :
n;
2562 }
2563
2564 return nread;
2565}
2566
2568 time_t now;
2569 int64_t
n,
total, allowed;
2570
2575 }
2577 if (allowed > (int64_t) len) {
2578 allowed = len;
2579 }
2581 (int64_t) allowed)) == allowed) {
2588 (int64_t) allowed)) != allowed) {
2589 break;
2590 }
2596 }
2597 }
2598 } else {
2600 (int64_t) len);
2601 }
2603}
2604
2606 int dst_len, int is_form_url_encoded) {
2608#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
2609
2610 for (
i =
j = 0;
i < src_len &&
j < dst_len - 1;
i++,
j++) {
2611 if (src[
i] ==
'%' &&
i < src_len - 2 &&
2612 isxdigit(* (
const unsigned char *) (src +
i + 1)) &&
2613 isxdigit(* (
const unsigned char *) (src +
i + 2))) {
2614 a = tolower(* (
const unsigned char *) (src +
i + 1));
2615 b = tolower(* (
const unsigned char *) (src +
i + 2));
2618 }
else if (is_form_url_encoded && src[
i] ==
'+') {
2620 } else {
2622 }
2623 }
2624
2626
2627 return i >= src_len ?
j : -1;
2628}
2629
2631 char *dst, size_t dst_len) {
2632 const char *p, *
e, *s;
2633 size_t name_len;
2634 int len;
2635
2636 if (dst == NULL || dst_len == 0) {
2637 len = -2;
2639 len = -1;
2640 dst[0] = '\0';
2641 } else {
2642 name_len = strlen(
name);
2644 len = -1;
2645 dst[0] = '\0';
2646
2647
2648 for (p =
data; p + name_len <
e; p++) {
2649 if ((p ==
data || p[-1] ==
'&') && p[name_len] ==
'=' &&
2651
2652
2653 p += name_len + 1;
2654
2655
2656 s = (
const char *) memchr(p,
'&', (
size_t)(
e - p));
2657 if (s == NULL) {
2659 }
2660 assert(s >= p);
2661
2662
2664
2665
2666 if (len == -1) {
2667 len = -2;
2668 }
2669 break;
2670 }
2671 }
2672 }
2673
2674 return len;
2675}
2676
2678 char *dst, size_t dst_size) {
2679 const char *s, *p, *
end;
2680 int name_len, len = -1;
2681
2682 if (dst == NULL || dst_size == 0) {
2683 len = -2;
2684 }
else if (
var_name == NULL || (s = cookie_header) == NULL) {
2685 len = -1;
2686 dst[0] = '\0';
2687 } else {
2689 end = s + strlen(s);
2690 dst[0] = '\0';
2691
2693 if (s[name_len] == '=') {
2694 s += name_len + 1;
2695 if ((p = strchr(s, ' ')) == NULL)
2697 if (p[-1] == ';')
2698 p--;
2699 if (*s == '"' && p[-1] == '"' && p > s + 1) {
2700 s++;
2701 p--;
2702 }
2703 if ((size_t) (p - s) < dst_size) {
2704 len = p - s;
2706 } else {
2707 len = -3;
2708 }
2709 break;
2710 }
2711 }
2712 }
2713 return len;
2714}
2715
2716
2718 size_t buf_len,
struct file *filep) {
2722 char *p;
2723 int match_len;
2725 char const* accept_encoding;
2726
2727
2728 if (root == NULL) {
2729 return 0;
2730 }
2731
2732
2733
2734
2736
2738 while ((rewrite =
next_option(rewrite, &a, &b)) != NULL) {
2739 if ((match_len =
match_prefix(a.ptr, a.len, uri)) > 0) {
2740 mg_snprintf(buf, buf_len - 1,
"%.*s%s", (
int) b.len, b.ptr,
2741 uri + match_len);
2742 break;
2743 }
2744 }
2745
2747 return 1;
2748 }
2749
2750
2751
2752
2753
2754
2755
2756 if ((accept_encoding =
mg_get_header(conn,
"Accept-Encoding")) != NULL) {
2757 if (strstr(accept_encoding,"gzip") != NULL) {
2758 snprintf(gz_path, sizeof(gz_path), "%s.gz", buf);
2759 if (
mg_stat(gz_path, filep)) {
2761 return 1;
2762 }
2763 }
2764 }
2765
2766
2767 for (p = buf + strlen(root == NULL ? "" : root); *p != '\0'; p++) {
2768 if (*p == '/') {
2769 *p = '\0';
2773
2774
2775
2776
2777
2779 memmove(p + 2, p + 1, strlen(p + 1) + 1);
2780 p[1] = '/';
2781 return 1;
2782 } else {
2783 *p = '/';
2784 }
2785 }
2786 }
2787
2788 return 0;
2789}
2790
2791
2792
2793
2794
2797
2798 for (
i = 0;
i < buf_len;
i++) {
2799
2800
2801
2802 if (!isprint(* (
const unsigned char *) &buf[
i]) && buf[
i] !=
'\r' &&
2803 buf[
i] !=
'\n' && * (
const unsigned char *) &buf[
i] < 128) {
2804 return -1;
2805 }
else if (buf[
i] ==
'\n' &&
i + 1 < buf_len && buf[
i + 1] ==
'\n') {
2807 }
else if (buf[
i] ==
'\n' &&
i + 2 < buf_len && buf[
i + 1] ==
'\r' &&
2808 buf[
i + 2] ==
'\n') {
2810 }
2811 }
2812
2813 return 0;
2814}
2815
2816
2817
2819 char *p = s;
2820
2821 while (*s != '\0') {
2822 *p++ = *s++;
2823 if (s[-1] == '/' || s[-1] == '\\') {
2824
2825 while (s[0] != '\0') {
2826 if (s[0] == '/' || s[0] == '\\') {
2827 s++;
2828 } else if (s[0] == '.' && s[1] == '.') {
2829 s += 2;
2830 } else {
2831 break;
2832 }
2833 }
2834 }
2835 }
2836 *p = '\0';
2837}
2838
2839static const struct {
2844 {".html", 5, "text/html"},
2845 {".htm", 4, "text/html"},
2846 {".shtm", 5, "text/html"},
2847 {".shtml", 6, "text/html"},
2848 {".css", 4, "text/css"},
2849 {".js", 3, "application/x-javascript"},
2850 {".ico", 4, "image/x-icon"},
2851 {".gif", 4, "image/gif"},
2852 {".jpg", 4, "image/jpeg"},
2853 {".jpeg", 5, "image/jpeg"},
2854 {".png", 4, "image/png"},
2855 {".svg", 4, "image/svg+xml"},
2856 {".txt", 4, "text/plain"},
2857 {".torrent", 8, "application/x-bittorrent"},
2858 {".wav", 4, "audio/x-wav"},
2859 {".mp3", 4, "audio/x-mp3"},
2860 {".mid", 4, "audio/mid"},
2861 {".m3u", 4, "audio/x-mpegurl"},
2862 {".ogg", 4, "application/ogg"},
2863 {".ram", 4, "audio/x-pn-realaudio"},
2864 {".xml", 4, "text/xml"},
2865 {".json", 5, "text/json"},
2866 {".xslt", 5, "application/xml"},
2867 {".xsl", 4, "application/xml"},
2868 {".ra", 3, "audio/x-pn-realaudio"},
2869 {".doc", 4, "application/msword"},
2870 {".exe", 4, "application/octet-stream"},
2871 {".zip", 4, "application/x-zip-compressed"},
2872 {".xls", 4, "application/excel"},
2873 {".tgz", 4, "application/x-tar-gz"},
2874 {".tar", 4, "application/x-tar"},
2875 {".gz", 3, "application/x-gunzip"},
2876 {".arj", 4, "application/x-arj-compressed"},
2877 {".rar", 4, "application/x-arj-compressed"},
2878 {".rtf", 4, "application/rtf"},
2879 {".pdf", 4, "application/pdf"},
2880 {".swf", 4, "application/x-shockwave-flash"},
2881 {".mpg", 4, "video/mpeg"},
2882 {".webm", 5, "video/webm"},
2883 {".mpeg", 5, "video/mpeg"},
2884 {".mov", 4, "video/quicktime"},
2885 {".mp4", 4, "video/mp4"},
2886 {".m4v", 4, "video/x-m4v"},
2887 {".asf", 4, "video/x-ms-asf"},
2888 {".avi", 4, "video/x-msvideo"},
2889 {".bmp", 4, "image/bmp"},
2890 {".ttf", 4, "application/x-font-ttf"},
2891 {NULL, 0, NULL}
2892};
2893
2895 const char *ext;
2897
2898 path_len = strlen(path);
2899
2905 }
2906 }
2907
2908 return "text/plain";
2909}
2910
2911
2912
2915 struct vec ext_vec, mime_vec;
2916 const char *
list, *ext;
2917 size_t path_len;
2918
2919 path_len = strlen(path);
2920
2921
2922
2925
2926 ext = path + path_len - ext_vec.len;
2929 return;
2930 }
2931 }
2932
2935}
2936
2937void mg_url_encode(
const char *src,
char *dst,
size_t dst_len) {
2938 static const char *dont_escape = "._-$,;~()";
2939 static const char *hex = "0123456789abcdef";
2940 const char *
end = dst + dst_len - 1;
2941
2942 for (; *src !=
'\0' && dst <
end; src++, dst++) {
2943 if (isalnum(*(const unsigned char *) src) ||
2944 strchr(dont_escape, * (const unsigned char *) src) != NULL) {
2945 *dst = *src;
2946 }
else if (dst + 2 <
end) {
2947 dst[0] = '%';
2948 dst[1] = hex[(* (const unsigned char *) src) >> 4];
2949 dst[2] = hex[(* (const unsigned char *) src) & 0xf];
2950 dst += 2;
2951 }
2952 }
2953
2954 *dst = '\0';
2955}
2956
2958 char size[64], mod[64], href[
PATH_MAX * 3];
2960
2962 mg_snprintf(size,
sizeof(size),
"%s",
"[DIRECTORY]");
2963 } else {
2964
2965
2974 } else {
2976 "%.1fG", (
double)
de->
file.
size / 1073741824);
2977 }
2978 }
2979 strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
2983 "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
2984 "<td> %s</td><td> %s</td></tr>\n",
2986}
2987
2988
2989
2990
2991
2993 const struct de *a = (
const struct de *) p1, *b = (
const struct de *) p2;
2995 int cmp_result = 0;
2996
2997 if (query_string == NULL) {
2998 query_string = "na";
2999 }
3000
3002 return -1;
3004 return 1;
3005 } else if (*query_string == 'n') {
3006 cmp_result = strcmp(a->
file_name, b->file_name);
3007 } else if (*query_string == 's') {
3008 cmp_result = a->
file.
size == b->file.size ? 0 :
3009 a->
file.
size > b->file.size ? 1 : -1;
3010 } else if (*query_string == 'd') {
3013 }
3014
3015 return query_string[1] == 'd' ? -cmp_result : cmp_result;
3016}
3017
3021 return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
3022 (pattern != NULL &&
match_prefix(pattern, strlen(pattern), path) > 0);
3023}
3024
3026 void *
data,
void (*cb)(
struct de *,
void *)) {
3028 struct dirent *dp;
3031
3032 if ((dirp = opendir(dir)) == NULL) {
3033 return 0;
3034 } else {
3036
3037 while ((dp = readdir(dirp)) != NULL) {
3038
3039 if (!strcmp(dp->d_name, ".") ||
3040 !strcmp(dp->d_name, "..") ||
3042 continue;
3043 }
3044
3045 mg_snprintf(path,
sizeof(path),
"%s%c%s", dir,
'/', dp->d_name);
3046
3047
3048
3049
3050
3051
3054
3057 }
3058 (void) closedir(dirp);
3059 }
3060 return 1;
3061}
3062
3065 struct dirent *dp;
3068
3069 if ((dirp = opendir(dir)) == NULL) {
3070 return 0;
3071 } else {
3073
3074 while ((dp = readdir(dirp)) != NULL) {
3075
3076 if (!strcmp(dp->d_name, ".") ||
3077 !strcmp(dp->d_name, "..")) {
3078 continue;
3079 }
3080
3081 mg_snprintf(path,
sizeof(path),
"%s%c%s", dir,
'/', dp->d_name);
3082
3083
3084
3085
3086
3087
3093 } else {
3095 }
3096 }
3097
3098 }
3099 (void) closedir(dirp);
3100
3102 }
3103
3104 return 1;
3105}
3106
3111};
3112
3113
3114static void *
realloc2(
void *ptr,
size_t size) {
3115 void *new_ptr = realloc(ptr, size);
3116 if (new_ptr == NULL) {
3117 free(ptr);
3118 }
3119 return new_ptr;
3120}
3121
3124
3129 }
3131
3133 } else {
3138 }
3139}
3140
3142 const char *dir) {
3143 int i, sort_direction;
3145
3148 "Error: opendir(%s): %s", dir, strerror(
ERRNO));
3149 return;
3150 }
3151
3154
3157 "HTTP/1.1 200 OK\r\n"
3158 "Transfer-Encoding: Chunked\r\n"
3159 "Content-Type: text/html; charset=utf-8\r\n\r\n");
3160
3162 "<html><head><title>Index of %s</title>"
3163 "<style>th {text-align: left;}</style></head>"
3164 "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
3165 "<tr><th><a href=\"?n%c\">Name</a></th>"
3166 "<th><a href=\"?d%c\">Modified</a></th>"
3167 "<th><a href=\"?s%c\">Size</a></th></tr>"
3168 "<tr><td colspan=\"3\"><hr></td></tr>",
3170 sort_direction, sort_direction, sort_direction);
3171
3172
3174 "<tr><td><a href=\"%s%s\">%s</a></td>"
3175 "<td> %s</td><td> %s</td></tr>\n",
3177
3178
3179 qsort(
data.entries, (
size_t)
data.num_entries,
sizeof(
data.entries[0]),
3181 for (
i = 0;
i <
data.num_entries;
i++) {
3183 free(
data.entries[
i].file_name);
3184 }
3186
3188 "</table></body></html>");
3191}
3192
3193
3195 int64_t
offset, int64_t len) {
3197 int num_read, num_written, to_read;
3198
3199
3201 return;
3202 }
3203
3204 while (len > 0) {
3205
3206 to_read = sizeof(buf);
3207 if ((int64_t) to_read > len) {
3208 to_read = (int) len;
3209 }
3210
3211
3212 if ((num_read = fread(buf, 1, (
size_t) to_read,
fp)) <= 0) {
3213 break;
3214 }
3215
3216
3217 if ((num_written =
mg_write(conn, buf, (
size_t) num_read)) != num_read) {
3218 break;
3219 }
3220
3221
3223 len -= num_written;
3224 }
3225}
3226
3229}
3230
3232 strftime(buf, buf_len,
"%a, %d %b %Y %H:%M:%S GMT",
gmtime(t));
3233}
3234
3236 const struct file *filep) {
3237 snprintf(buf, buf_len,
"\"%lx.%" INT64_FMT "\"",
3239}
3240
3243#ifndef _WIN32
3244 fcntl(fileno(
fp), F_SETFD, FD_CLOEXEC);
3245#endif
3246 }
3247}
3248
3250 struct file *filep) {
3251 char date[64], lm[64], etag[64], range[64];
3252 const char *msg = "OK", *hdr;
3253 time_t curtime = time(NULL);
3254 int64_t cl, r1, r2;
3255 struct vec mime_vec;
3258 char const* encoding = "";
3260
3264 range[0] = '\0';
3265
3266
3267
3268
3270 snprintf(gz_path, sizeof(gz_path), "%s.gz", path);
3271 path = gz_path;
3272 encoding = "Content-Encoding: gzip\r\n";
3273 }
3274
3277 "fopen(%s): %s", path, strerror(
ERRNO));
3278 return;
3279 }
3280
3282
3283
3284 r1 = r2 = 0;
3287 r1 >= 0 && r2 >= 0) {
3288
3289
3292 "range requests in gzipped files are not supported");
3293 return;
3294 }
3296 cl =
n == 2 ? (r2 > cl ? cl : r2) - r1 + 1: cl - r1;
3298 "Content-Range: bytes "
3301 r1, r1 + cl - 1, filep->
size);
3302 msg = "Partial Content";
3303 }
3304
3305
3306
3310
3312 "HTTP/1.1 %d %s\r\n"
3313 "Date: %s\r\n"
3314 "Last-Modified: %s\r\n"
3315 "Etag: %s\r\n"
3316 "Content-Type: %.*s\r\n"
3318 "Connection: %s\r\n"
3319 "Accept-Ranges: bytes\r\n"
3320 "%s%s%s\r\n",
3321 conn->
status_code, msg, date, lm, etag, (
int) mime_vec.len,
3324
3327 }
3329}
3330
3335 } else {
3337 }
3338}
3339
3340
3341
3342
3345
3350 break;
3352 }
3353}
3354
3356 return !strcmp(method, "GET") || !strcmp(method, "POST") ||
3357 !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
3358 !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
3359 !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
3360 || !strcmp(method, "MKCOL")
3361 ;
3362}
3363
3364
3365
3366
3369 if (request_length > 0) {
3370
3373
3374 buf[request_length - 1] = '\0';
3375
3376
3377 while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
3378 buf++;
3379 }
3383
3384
3385
3387 if ((is_request && memcmp(ri->
http_version,
"HTTP/", 5) != 0) ||
3389 request_length = -1;
3390 } else {
3391 if (is_request) {
3393 }
3395 }
3396 }
3397 return request_length;
3398}
3399
3400
3401
3402
3403
3404
3406 char *buf, int bufsiz, int *nread) {
3407 int request_len,
n = 0;
3408
3411 *nread < bufsiz &&
3412 request_len == 0 &&
3413 (
n =
pull(
fp, conn, buf + *nread, bufsiz - *nread)) > 0) {
3415 assert(*nread <= bufsiz);
3417 }
3418
3419 return request_len <= 0 &&
n <= 0 ? -1 : request_len;
3420}
3421
3422
3423
3424
3426 size_t path_len,
struct file *filep) {
3429 struct vec filename_vec;
3430 size_t n = strlen(path);
3431 int found = 0;
3432
3433
3434
3435
3436 while (
n > 0 && path[
n - 1] ==
'/') {
3438 }
3440
3441
3442
3444
3445
3446 if (filename_vec.len > path_len - (
n + 2))
3447 continue;
3448
3449
3450 mg_strlcpy(path +
n + 1, filename_vec.ptr, filename_vec.len + 1);
3451
3452
3454
3456 found = 1;
3457 break;
3458 }
3459 }
3460
3461
3462 if (!found) {
3464 }
3465
3466 return found;
3467}
3468
3469
3471 const struct file *filep) {
3472 char etag[64];
3478}
3479
3482 const char *
expect, *body;
3484 int nread, buffered_len, success = 0;
3486
3489
3494 } else {
3496 (void)
mg_printf(conn,
"%s",
"HTTP/1.1 100 Continue\r\n\r\n");
3497 }
3498
3501 assert(buffered_len >= 0);
3502
3503 if (buffered_len > 0) {
3506 }
3507 push(
fp, sock, ssl, body, (int64_t) buffered_len);
3508 memmove((char *) body, body + buffered_len, buffered_len);
3510 }
3511
3512 nread = 0;
3515 if (
left > (int64_t)
sizeof(buf)) {
3517 }
3518 nread =
pull(NULL, conn, buf, (
int)
left);
3519 if (nread <= 0 ||
push(
fp, sock, ssl, buf, nread) != nread) {
3520 break;
3521 }
3522 }
3523
3525 success = nread >= 0;
3526 }
3527
3528
3529 if (!success) {
3531 }
3532 }
3533
3534 return success;
3535}
3536
3537#if !defined(NO_CGI)
3538
3539
3540
3541
3542
3543
3544
3545
3552};
3553
3557
3558
3559
3562 char *added;
3563 va_list ap;
3564
3565
3566 space = sizeof(block->buf) - block->len - 2;
3567 assert(space >= 0);
3568
3569
3570 added = block->
buf + block->
len;
3571
3572
3573 va_start(ap, fmt);
3575 va_end(ap);
3576
3577
3578 if (
n > 0 &&
n + 1 < space &&
3580
3582
3583 block->
len +=
n + 1;
3584 } else {
3585 cry(block->
conn,
"%s: CGI env buffer truncated for [%s]", __func__, fmt);
3586 }
3587
3588 return added;
3589}
3590
3592 const char *prog,
3595 const char *s, *slash;
3599
3603
3608
3609
3610 addenv(
blk,
"%s",
"GATEWAY_INTERFACE=CGI/1.1");
3611 addenv(
blk,
"%s",
"SERVER_PROTOCOL=HTTP/1.1");
3612 addenv(
blk,
"%s",
"REDIRECT_STATUS=200");
3613
3614
3616
3618 addenv(
blk,
"REMOTE_ADDR=%s", src_addr);
3622 ri->query_string == NULL ? "" : ri->query_string);
3623
3624
3629 } else {
3630 s = strrchr(prog, '/');
3631 slash = strrchr(ri->
uri,
'/');
3633 slash == NULL ? 0 : (int) (slash - ri->uri), ri->uri,
3634 s == NULL ? prog : s);
3635 }
3636
3637 addenv(
blk,
"SCRIPT_FILENAME=%s", prog);
3638 addenv(
blk,
"PATH_TRANSLATED=%s", prog);
3639 addenv(
blk,
"HTTPS=%s", conn->
ssl == NULL ?
"off" :
"on");
3640
3643
3646 }
3647
3650
3651 if ((s = getenv("PATH")) != NULL)
3653
3654#if defined(_WIN32)
3655 if ((s = getenv("COMSPEC")) != NULL) {
3657 }
3658 if ((s = getenv("SYSTEMROOT")) != NULL) {
3660 }
3661 if ((s = getenv("SystemDrive")) != NULL) {
3663 }
3664 if ((s = getenv("ProgramFiles")) != NULL) {
3666 }
3667 if ((s = getenv("ProgramFiles(x86)")) != NULL) {
3669 }
3670 if ((s = getenv("CommonProgramFiles(x86)")) != NULL) {
3671 addenv(
blk,
"CommonProgramFiles(x86)=%s", s);
3672 }
3673#else
3674 if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
3676#endif
3677
3678 if ((s = getenv("PERLLIB")) != NULL)
3680
3684 }
3685
3686
3690
3691
3692 for (; *p != '=' && *p != '\0'; p++) {
3693 if (*p == '-')
3694 *p = '_';
3695 *p = (char) toupper(* (unsigned char *) p);
3696 }
3697 }
3698
3699
3701 while ((s =
next_option(s, &var_vec, NULL)) != NULL) {
3702 addenv(
blk,
"%.*s", (
int) var_vec.len, var_vec.ptr);
3703 }
3704
3705 blk->vars[
blk->nvars++] = NULL;
3706 blk->buf[
blk->len++] =
'\0';
3707
3709 assert(
blk->len > 0);
3710 assert(
blk->len < (
int)
sizeof(
blk->buf));
3711}
3712
3714 int headers_len, data_len,
i, fdin[2], fdout[2];
3715 const char *
status, *status_text;
3716 char buf[16384], *pbuf, dir[
PATH_MAX], *p;
3719 FILE *in = NULL, *out = NULL;
3720 pid_t pid = (pid_t) -1;
3721
3723
3724
3725
3726
3728 if ((p = strrchr(dir, '/')) != NULL) {
3729 *p++ = '\0';
3730 } else {
3731 dir[0] = '.', dir[1] = '\0';
3732 p = (char *) prog;
3733 }
3734
3735 if (pipe(fdin) != 0 || pipe(fdout) != 0) {
3737 "Cannot create CGI pipe: %s", strerror(
ERRNO));
3739 }
3740
3742 if (pid == (pid_t) -1) {
3744 "Cannot spawn CGI process [%s]: %s", prog, strerror(
ERRNO));
3746 }
3747
3748
3753
3754
3755
3756
3757
3758 (void) close(fdin[0]);
3759 (void) close(fdout[1]);
3760 fdin[0] = fdout[1] = -1;
3761
3762
3763 if ((in = fdopen(fdin[1], "wb")) == NULL ||
3764 (out = fdopen(fdout[0], "rb")) == NULL) {
3766 "fopen: %s", strerror(
ERRNO));
3768 }
3769
3770 setbuf(in, NULL);
3771 setbuf(out, NULL);
3772
3773
3777 }
3778
3779
3780 fclose(in);
3781 in = NULL;
3782 fdin[1] = -1;
3783
3784
3785
3786
3787
3788 data_len = 0;
3790 if (headers_len <= 0) {
3792 "CGI program sent malformed or too big (>%u bytes) "
3793 "HTTP headers: [%.*s]",
3794 (
unsigned)
sizeof(
buf), data_len,
buf);
3796 }
3798 buf[headers_len - 1] =
'\0';
3800
3801
3802 status_text = "OK";
3806 while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
3807 status_text++;
3808 }
3809 }
else if (
get_header(&ri,
"Location") != NULL) {
3811 } else {
3813 }
3817 }
3819 status_text);
3820
3821
3825 }
3827
3828
3830 (size_t)(data_len - headers_len));
3831
3832
3834
3836 if (pid != (pid_t) -1) {
3837 kill(pid, SIGKILL);
3838 }
3839 if (fdin[0] != -1) {
3840 close(fdin[0]);
3841 }
3842 if (fdout[1] != -1) {
3843 close(fdout[1]);
3844 }
3845
3846 if (in != NULL) {
3847 fclose(in);
3848 } else if (fdin[1] != -1) {
3849 close(fdin[1]);
3850 }
3851
3852 if (out != NULL) {
3853 fclose(out);
3854 } else if (fdout[0] != -1) {
3855 close(fdout[0]);
3856 }
3857}
3858#endif
3859
3860
3861
3862
3863static int put_dir(
const char *path) {
3865 const char *s, *p;
3867 int len, res = 1;
3868
3869 for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
3870 len = p - path;
3871 if (len >= (int) sizeof(buf)) {
3872 res = -1;
3873 break;
3874 }
3875 memcpy(buf, path, len);
3876 buf[len] = '\0';
3877
3878
3881 res = -1;
3882 break;
3883 }
3884
3885
3886 if (p[1] == '\0') {
3887 res = 0;
3888 }
3889 }
3890
3891 return res;
3892}
3893
3895 int rc, body_len;
3897
3900
3903 "mkcol(%s): %s", path, strerror(
ERRNO));
3904 return;
3905 }
3906
3908 if(body_len > 0) {
3910 "mkcol(%s): %s", path, strerror(
ERRNO));
3911 return;
3912 }
3913
3915
3916 if (rc == 0) {
3919 } else if (rc == -1) {
3920 if(errno == EEXIST)
3922 "mkcol(%s): %s", path, strerror(
ERRNO));
3923 else if(errno == EACCES)
3925 "mkcol(%s): %s", path, strerror(
ERRNO));
3926 else if(errno == ENOENT)
3928 "mkcol(%s): %s", path, strerror(
ERRNO));
3929 else
3931 "fopen(%s): %s", path, strerror(
ERRNO));
3932 }
3933}
3934
3938 const char *range;
3939 int64_t r1, r2;
3940 int rc;
3941
3943
3944 if ((rc =
put_dir(path)) == 0) {
3946 } else if (rc == -1) {
3948 "put_dir(%s): %s", path, strerror(
ERRNO));
3949 }
else if ((
fp =
mg_fopen(path,
"wb+")) == NULL) {
3952 "fopen(%s): %s", path, strerror(
ERRNO));
3953 } else {
3956 r1 = r2 = 0;
3959 fseeko(
fp, r1, SEEK_SET);
3960 }
3963 }
3964 mg_printf(conn,
"HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n",
3967 }
3968}
3969
3972 char *tag, int include_level) {
3975
3976
3977
3978 if (sscanf(tag,
" virtual=\"%[^\"]\"",
file_name) == 1) {
3979
3982 }
else if (sscanf(tag,
" abspath=\"%[^\"]\"",
file_name) == 1) {
3983
3984
3986 }
else if (sscanf(tag,
" file=\"%[^\"]\"",
file_name) == 1 ||
3987 sscanf(tag,
" \"%[^\"]\"",
file_name) == 1) {
3988
3989 (void)
mg_snprintf(path,
sizeof(path),
"%s", ssi);
3990 if ((p = strrchr(path, '/')) != NULL) {
3991 p[1] = '\0';
3992 }
3994 sizeof(path) - strlen(path),
"%s",
file_name);
3995 } else {
3996 cry(conn,
"Bad SSI #include: [%s]", tag);
3997 return;
3998 }
3999
4001 cry(conn,
"Cannot open SSI #include: [%s]: fopen(%s): %s",
4002 tag, path, strerror(
ERRNO));
4003 } else {
4008 } else {
4010 }
4012 }
4013}
4014
4015#if !defined(NO_POPEN)
4019
4020 if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
4021 cry(conn,
"Bad SSI #exec: [%s]", tag);
4022 }
else if ((
fp = popen(cmd,
"r")) == NULL) {
4023 cry(conn,
"Cannot SSI #exec: [%s]: %s", cmd, strerror(
ERRNO));
4024 } else {
4027 }
4028}
4029#endif
4030
4032 FILE *
fp,
int include_level) {
4034 int ch,
offset, len, in_ssi_tag;
4035
4036 if (include_level > 10) {
4037 cry(conn,
"SSI #include level is too deep (%s)", path);
4038 return;
4039 }
4040
4041 in_ssi_tag = len =
offset = 0;
4042 while ((ch = fgetc(
fp)) != EOF) {
4043 if (in_ssi_tag && ch == '>') {
4044 in_ssi_tag = 0;
4045 buf[len++] = (char) ch;
4046 buf[len] = '\0';
4047 assert(len <= (int) sizeof(buf));
4048 if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
4049
4050 (void)
mg_write(conn, buf, (
size_t) len);
4051 } else {
4052 if (!memcmp(buf + 5, "include", 7)) {
4054#if !defined(NO_POPEN)
4055 } else if (!memcmp(buf + 5, "exec", 4)) {
4057#endif
4058 } else {
4059 cry(conn,
"%s: unknown SSI " "command: \"%s\"", path, buf);
4060 }
4061 }
4062 len = 0;
4063 } else if (in_ssi_tag) {
4064 if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
4065
4066 in_ssi_tag = 0;
4067 } else if (len == (int) sizeof(buf) - 2) {
4068 cry(conn,
"%s: SSI tag is too large", path);
4069 len = 0;
4070 }
4071 buf[len++] = ch & 0xff;
4072 } else if (ch == '<') {
4073 in_ssi_tag = 1;
4074 if (len > 0) {
4076 }
4077 len = 0;
4078 buf[len++] = ch & 0xff;
4079 } else {
4080 buf[len++] = ch & 0xff;
4081 if (len == (int) sizeof(buf)) {
4083 len = 0;
4084 }
4085 }
4086 }
4087
4088
4089 if (len > 0) {
4091 }
4092}
4093
4095 const char *path) {
4096 struct vec mime_vec;
4098
4102 } else {
4107 "Content-Type: %.*s\r\n"
4108 "Connection: close\r\n\r\n",
4109 (int) mime_vec.len, mime_vec.ptr);
4112 }
4113}
4114
4116 static const char reply[] = "HTTP/1.1 200 OK\r\n"
4117 "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
4118 "DAV: 1\r\n\r\n";
4119
4121 mg_write(conn, reply,
sizeof(reply) - 1);
4122}
4123
4124
4126 struct file *filep) {
4127 char mtime[64];
4130 "<d:response>"
4131 "<d:href>%s</d:href>"
4132 "<d:propstat>"
4133 "<d:prop>"
4134 "<d:resourcetype>%s</d:resourcetype>"
4135 "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
4136 "<d:getlastmodified>%s</d:getlastmodified>"
4137 "</d:prop>"
4138 "<d:status>HTTP/1.1 200 OK</d:status>"
4139 "</d:propstat>"
4140 "</d:response>\n",
4141 uri,
4143 filep->size,
4144 mtime);
4145}
4146
4155}
4156
4158 struct file *filep) {
4160
4163 mg_printf(conn,
"HTTP/1.1 207 Multi-Status\r\n"
4164 "Connection: close\r\n"
4165 "Content-Type: text/xml; charset=utf-8\r\n\r\n");
4166
4168 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
4169 "<d:multistatus xmlns:d='DAV:'>\n");
4170
4171
4173
4174
4177 (depth == NULL || strcmp(depth, "0") != 0)) {
4179 }
4180
4182}
4183
4184#if defined(USE_WEBSOCKET)
4185
4186
4187
4188#define SHA1HANDSOFF
4189#if defined(__sun)
4190#include "solarisfixes.h"
4191#endif
4192
4194
4195#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
4196
4198
4200 block->
l[
i] = (
rol(block->
l[
i], 24) & 0xFF00FF00) |
4201 (
rol(block->
l[
i], 8) & 0x00FF00FF);
4202 }
4204}
4205
4206#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
4207 ^block->l[(i+2)&15]^block->l[i&15],1))
4208#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(block, i)+0x5A827999+rol(v,5);w=rol(w,30);
4209#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
4210#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
4211#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
4212#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
4213
4214typedef struct {
4217 unsigned char buffer[64];
4218} SHA1_CTX;
4219
4220static void SHA1Transform(uint32_t
state[5],
const unsigned char buffer[64]) {
4221 uint32_t a, b,
c,
d,
e;
4223
4224 memcpy(block, buffer, 64);
4230 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);
4231 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);
4232 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);
4233 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);
4234 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);
4235 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);
4236 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);
4237 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);
4238 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);
4239 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);
4240 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);
4241 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);
4242 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);
4243 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);
4244 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);
4245 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);
4246 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);
4247 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);
4248 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);
4249 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);
4255 a = b =
c =
d =
e = 0;
4256 memset(block, '\0', sizeof(block));
4257}
4258
4259static void SHA1Init(SHA1_CTX* context) {
4260 context->state[0] = 0x67452301;
4261 context->state[1] = 0xEFCDAB89;
4262 context->state[2] = 0x98BADCFE;
4263 context->state[3] = 0x10325476;
4264 context->state[4] = 0xC3D2E1F0;
4265 context->count[0] = context->count[1] = 0;
4266}
4267
4268static void SHA1Update(SHA1_CTX* context,
const unsigned char*
data,
4269 uint32_t len) {
4271
4272 j = context->count[0];
4273 if ((context->count[0] += len << 3) <
j)
4274 context->count[1]++;
4275 context->count[1] += (len>>29);
4277 if ((
j + len) > 63) {
4278 memcpy(&context->buffer[
j],
data, (
i = 64-
j));
4279 SHA1Transform(context->state, context->buffer);
4280 for ( ;
i + 63 < len;
i += 64) {
4281 SHA1Transform(context->state, &
data[
i]);
4282 }
4284 }
4286 memcpy(&context->buffer[
j], &
data[
i], len -
i);
4287}
4288
4289static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
4291 unsigned char finalcount[8],
c;
4292
4293 for (
i = 0;
i < 8;
i++) {
4294 finalcount[
i] = (
unsigned char)((context->count[(
i >= 4 ? 0 : 1)]
4295 >> ((3-(
i & 3)) * 8) ) & 255);
4296 }
4298 SHA1Update(context, &
c, 1);
4299 while ((context->count[0] & 504) != 448) {
4301 SHA1Update(context, &
c, 1);
4302 }
4303 SHA1Update(context, finalcount, 8);
4304 for (
i = 0;
i < 20;
i++) {
4305 digest[
i] = (
unsigned char)
4306 ((context->state[
i>>2] >> ((3-(
i & 3)) * 8) ) & 255);
4307 }
4308 memset(context, '\0', sizeof(*context));
4309 memset(&finalcount, '\0', sizeof(finalcount));
4310}
4311
4312
4313static void base64_encode(
const unsigned char *src,
int src_len,
char *dst) {
4314 static const char *b64 =
4315 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4317
4318 for (
i =
j = 0;
i < src_len;
i += 3) {
4320 b =
i + 1 >= src_len ? 0 : src[
i + 1];
4321 c =
i + 2 >= src_len ? 0 : src[
i + 2];
4322
4323 dst[
j++] = b64[a >> 2];
4324 dst[
j++] = b64[((a & 3) << 4) | (b >> 4)];
4325 if (
i + 1 < src_len) {
4326 dst[
j++] = b64[(b & 15) << 2 | (
c >> 6)];
4327 }
4328 if (
i + 2 < src_len) {
4329 dst[
j++] = b64[
c & 63];
4330 }
4331 }
4332 while (
j % 4 != 0) {
4334 }
4336}
4337
4339 static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4340 char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
4341 SHA1_CTX sha_ctx;
4342
4345 SHA1Init(&sha_ctx);
4346 SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
4347 SHA1Final((unsigned char *) sha, &sha_ctx);
4350 "HTTP/1.1 101 Switching Protocols\r\n"
4351 "Upgrade: websocket\r\n"
4352 "Connection: Upgrade\r\n"
4353 "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
4354}
4355
4357
4358
4359
4360 unsigned char *buf = (
unsigned char *) conn->
buf + conn->
request_len;
4362 size_t i, len, mask_len, data_len, header_len, body_len;
4364
4366
4367
4368
4369 while (!stop) {
4370 header_len = 0;
4371
4372
4373
4374
4376 len = buf[1] & 127;
4377 mask_len = buf[1] & 128 ? 4 : 0;
4378 if (len < 126 && body_len >= mask_len) {
4379 data_len = len;
4380 header_len = 2 + mask_len;
4381 } else if (len == 126 && body_len >= 4 + mask_len) {
4382 header_len = 4 + mask_len;
4383 data_len = ((((int) buf[2]) << 8) + buf[3]);
4384 } else if (body_len >= 10 + mask_len) {
4385 header_len = 10 + mask_len;
4386 data_len = (((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32) +
4387 htonl(* (uint32_t *) &buf[6]);
4388 }
4389 }
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399 if (header_len > 0) {
4400
4401 if ((*
data = malloc(data_len)) == NULL) {
4402
4403
4404 data_len = 0;
4405 break;
4406 }
4407
4408
4409 *bits = buf[0];
4410 memcpy(
mask, buf + header_len - mask_len, mask_len);
4411
4412
4413 assert(body_len >= header_len);
4414 if (data_len + header_len > body_len) {
4415 len = body_len - header_len;
4416 memcpy(*
data, buf + header_len, len);
4417
4420 } else {
4421 len = data_len + header_len;
4422 memcpy(*
data, buf + header_len, data_len);
4423 memmove(buf, buf + len, body_len - len);
4425 }
4426
4427
4428 if (mask_len > 0) {
4429 for (
i = 0;
i < data_len;
i++) {
4430 (*data)[
i] ^=
mask[
i % 4];
4431 }
4432 }
4433
4434 return data_len;
4435 } else {
4436
4439 break;
4440 }
4442 }
4443 }
4444
4445 return 0;
4446}
4447
4449 const char *
data,
size_t data_len) {
4450 unsigned char *copy;
4451 size_t copy_len = 0;
4452 int retval = -1;
4453
4454 if ((copy = (unsigned char *) malloc(data_len + 10)) == NULL) {
4455 return -1;
4456 }
4457
4458 copy[0] = 0x80 + (opcode & 0x0f);
4459
4460
4461 if (data_len < 126) {
4462
4463 copy[1] = data_len;
4464 memcpy(copy + 2,
data, data_len);
4465 copy_len = 2 + data_len;
4466 } else if (data_len <= 0xFFFF) {
4467
4468 copy[1] = 126;
4469 * (uint16_t *) (copy + 2) = htons(data_len);
4470 memcpy(copy + 4,
data, data_len);
4471 copy_len = 4 + data_len;
4472 } else {
4473
4474 copy[1] = 127;
4475 * (uint32_t *) (copy + 2) = htonl((uint64_t) data_len >> 32);
4476 * (uint32_t *) (copy + 6) = htonl(data_len & 0xffffffff);
4477 memcpy(copy + 10,
data, data_len);
4478 copy_len = 10 + data_len;
4479 }
4480
4481
4482 if (copy_len > 0) {
4483 retval =
mg_write(conn, copy, copy_len);
4484 }
4485 free(copy);
4486
4487 return retval;
4488}
4489#endif
4490
4492 return n >= 0 &&
n <= 255;
4493}
4494
4495static int parse_net(
const char *spec, uint32_t *net, uint32_t *
mask) {
4496 int n, a, b,
c,
d, slash = 32, len = 0;
4497
4498 if ((sscanf(spec,
"%d.%d.%d.%d/%d%n", &a, &b, &
c, &
d, &slash, &
n) == 5 ||
4499 sscanf(spec,
"%d.%d.%d.%d%n", &a, &b, &
c, &
d, &
n) == 4) &&
4501 slash >= 0 && slash < 33) {
4503 *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)
c << 8) |
d;
4504 *
mask = slash ? 0xffffffffU << (32 - slash) : 0;
4505 }
4506
4507 return len;
4508}
4509
4510static int set_throttle(
const char *spec, uint32_t remote_ip,
const char *uri) {
4511 int throttle = 0;
4514 char mult;
4515 double v;
4516
4518 mult = ',';
4519 if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0 ||
4521 continue;
4522 }
4525 throttle = (int) v;
4527 if ((remote_ip &
mask) == net) {
4528 throttle = (int) v;
4529 }
4531 throttle = (int) v;
4532 }
4533 }
4534
4535 return throttle;
4536}
4537
4539 return ntohl(* (uint32_t *) &conn->
client.
rsa.
sin.sin_addr);
4540}
4541
4543 char *path, int path_len) {
4544 const char *content_type_header, *boundary_start;
4545 char *buf, fname[1024], boundary[100], *s;
4546 int bl,
n,
i,
j, headers_len, boundary_len, eof, buf_len, to_read,
len = 0;
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565 if ((content_type_header =
mg_get_header(conn,
"Content-Type")) == NULL ||
4567 "boundary=")) == NULL ||
4568 (sscanf(boundary_start, "boundary=\"%99[^\"]\"", boundary) == 0 &&
4569 sscanf(boundary_start, "boundary=%99s", boundary) == 0) ||
4570 boundary[0] == '\0') {
4571 return NULL;
4572 }
4573
4574 boundary_len = strlen(boundary);
4575 bl = boundary_len + 4;
4576
4577
4578
4579
4580
4581
4582
4586
4587 for (;;) {
4588
4589 assert(
len >= 0 &&
len <= buf_len);
4590 to_read = buf_len -
len;
4593 }
4594 while (
len < buf_len &&
4595 (
n =
pull(NULL, conn, buf +
len, to_read)) > 0) {
4597 }
4599 break;
4600 }
4601
4602
4603 fname[0] = '\0';
4604 for (
i =
j = 0;
i < headers_len;
i++) {
4605 if (buf[
i] ==
'\r' && buf[
i + 1] ==
'\n') {
4606 buf[
i] = buf[
i + 1] =
'\0';
4607
4608
4609 sscanf(&buf[
j],
"Content-Disposition: %*s %*s filename=\"%1023[^\"]",
4610 fname);
4612 }
4613 }
4614
4615
4616 if (fname[0] == '\0') {
4617 break;
4618 }
4619
4620
4621 assert(
len >= headers_len);
4622 memmove(buf, &buf[headers_len],
len - headers_len);
4625
4626
4627
4629
4630
4631 if ((s = strrchr(fname, '/')) == NULL &&
4632 (s = strrchr(fname, '\\')) == NULL) {
4633 s = fname;
4634 }
4635
4636
4637 snprintf(path, path_len, "%s/%s", destination_dir, s);
4638 if ((
fp = fopen(path,
"wb")) == NULL) {
4639 break;
4640 }
4641
4642
4644 do {
4647 if (!memcmp(&buf[
i],
"\r\n--", 4) &&
4648 !memcmp(&buf[
i + 4], boundary, boundary_len)) {
4649
4650 fwrite(buf, 1,
i,
fp);
4651 eof = 1;
4652 memmove(buf, &buf[
i +
bl],
len - (
i +
bl));
4654 break;
4655 }
4656 }
4657 if (!eof &&
len >
bl) {
4659 memmove(buf, &buf[
len -
bl],
bl);
4661 }
4662 to_read = buf_len -
len;
4665 }
4666 }
while (!eof && (
n =
pull(NULL, conn, buf +
len, to_read)) > 0);
4668
4669 if (eof) {
4672 } else {
4674 }
4675 }
4676
4677 return NULL;
4678}
4679
4682 return s != NULL && (!strcmp(s, "PUT") ||
4683 !strcmp(s, "DELETE") ||
4684 !strcmp(s, "MKCOL"));
4685}
4686
4691 }
4693}
4694
4696 char host[1025];
4697 const char *host_header;
4698
4700 sscanf(host_header, "%1024[^:]", host) == 0) {
4701
4703 }
4704
4705 mg_printf(conn,
"HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s\r\n\r\n",
4708}
4709
4711 const char *path) {
4713
4724 } else {
4727 }
4728}
4729
4730
4731
4732
4733
4737 int uri_len, ssl_index;
4739
4742 }
4743 uri_len = (int) strlen(ri->
uri);
4748 path[0] = '\0';
4750
4751
4752
4757
4762
4780 mg_printf(conn,
"HTTP/1.1 301 Moved Permanently\r\n"
4781 "Location: %s/\r\n\r\n", ri->
uri);
4788 } else {
4790 "Directory listing denied");
4791 }
4792#ifdef USE_LUA
4794 handle_lsp_request(conn, path, &
file, NULL);
4795#endif
4796#if !defined(NO_CGI)
4799 path) > 0) {
4805 } else {
4807 }
4808#endif
4811 path) > 0) {
4815 } else {
4817 }
4818}
4819
4824 }
4826}
4827
4829 return port > 0 && port < 0xffff;
4830}
4831
4832
4833
4834
4836 unsigned int a, b,
c,
d, ch, port;
4837 int len;
4838#if defined(USE_IPV6)
4839 char buf[100];
4840#endif
4841
4842
4843
4844
4845 memset(so, 0, sizeof(*so));
4846 so->
lsa.
sin.sin_family = AF_INET;
4847
4848 if (sscanf(
vec->
ptr,
"%u.%u.%u.%u:%u%n", &a, &b, &
c, &
d, &port, &len) == 5) {
4849
4850 so->
lsa.
sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (
c << 8) |
d);
4851 so->
lsa.
sin.sin_port = htons((uint16_t) port);
4852#if defined(USE_IPV6)
4853
4854 }
else if (sscanf(
vec->
ptr,
"[%49[^]]]:%d%n", buf, &port, &len) == 2 &&
4856
4857 so->
lsa.sin6.sin6_family = AF_INET6;
4858 so->
lsa.sin6.sin6_port = htons((uint16_t) port);
4859#endif
4860 }
else if (sscanf(
vec->
ptr,
"%u%n", &port, &len) == 1) {
4861
4862 so->
lsa.
sin.sin_port = htons((uint16_t) port);
4863 } else {
4864 port = len = 0;
4865 }
4866
4870
4871
4873 (ch == '\0' || ch == 's' || ch == 'r' || ch == ',');
4874}
4875
4878 int on = 1, success = 1;
4879#if defined(USE_IPV6)
4880 int off = 0;
4881#endif
4884
4887 cry(
fc(ctx),
"%s: %.*s: invalid port spec. Expecting list of: %s",
4888 __func__, (
int)
vec.
len,
vec.
ptr,
"[IP_ADDRESS:]PORT[s|r]");
4889 success = 0;
4891 cry(
fc(ctx),
"Cannot add SSL socket, is -ssl_certificate option set?");
4892 success = 0;
4895
4896
4897 setsockopt(so.
sock, SOL_SOCKET, SO_REUSEADDR,
4898 (void *) &on, sizeof(on)) != 0 ||
4899#if defined(USE_IPV6)
4900 (so.
lsa.
sa.sa_family == AF_INET6 &&
4901 setsockopt(so.
sock, IPPROTO_IPV6, IPV6_V6ONLY, (
void *) &off,
4902 sizeof(off)) != 0) ||
4903#endif
4905 sizeof(so.
lsa.
sin) : sizeof(so.
lsa)) != 0 ||
4907 cry(
fc(ctx),
"%s: cannot bind to %.*s: %d (%s)", __func__,
4910 success = 0;
4915 success = 0;
4916 } else {
4921 }
4922 }
4923
4924 if (!success) {
4926 }
4927
4928 return success;
4929}
4930
4933 const char *header_value;
4934
4936 (void) fprintf(
fp,
"%s",
" -");
4937 } else {
4938 (void) fprintf(
fp,
" \"%s\"", header_value);
4939 }
4940}
4941
4946
4949
4951 return;
4952
4953 strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
4955
4958
4960 fprintf(
fp,
"%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
4964 conn->status_code, conn->num_bytes_sent);
4969
4972}
4973
4974
4975
4977 int allowed, flag;
4981
4982
4983 allowed =
list == NULL ?
'+' :
'-';
4984
4987 if ((flag != '+' && flag != '-') ||
4989 cry(
fc(ctx),
"%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
4990 return -1;
4991 }
4992
4993 if (net == (remote_ip &
mask)) {
4994 allowed = flag;
4995 }
4996 }
4997
4998 return allowed == '+';
4999}
5000
5001#if !defined(_WIN32)
5003 struct passwd *pw;
5005 int success = 0;
5006
5007 if (uid == NULL) {
5008 success = 1;
5009 } else {
5010 if ((pw = getpwnam(uid)) == NULL) {
5011 cry(
fc(ctx),
"%s: unknown user [%s]", __func__, uid);
5012 } else if (setgid(pw->pw_gid) == -1) {
5013 cry(
fc(ctx),
"%s: setgid(%s): %s", __func__, uid, strerror(errno));
5014 } else if (setuid(pw->pw_uid) == -1) {
5015 cry(
fc(ctx),
"%s: setuid(%s): %s", __func__, uid, strerror(errno));
5016 } else {
5017 success = 1;
5018 }
5019 }
5020
5021 return success;
5022}
5023#endif
5024
5029 cry(
fc(ctx),
"Cannot open %s: %s", path, strerror(
ERRNO));
5030 return 0;
5031 }
5032 return 1;
5033}
5034
5036 return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
5037}
5038
5044}
5045
5047#if defined(_WIN32)
5050#endif
5051 struct linger linger;
5052
5053
5054
5055 linger.l_onoff = 1;
5056 linger.l_linger = 1;
5057 setsockopt(conn->
client.
sock, SOL_SOCKET, SO_LINGER,
5058 (char *) &linger, sizeof(linger));
5059
5060
5063
5064#if defined(_WIN32)
5065
5066
5067
5068
5069
5070 do {
5071 n =
pull(NULL, conn, buf,
sizeof(buf));
5073#endif
5074
5075
5077}
5078
5081
5082#ifndef NO_SSL
5083 if (conn->
ssl != NULL) {
5084
5085 SSL_shutdown(conn->
ssl);
5086 SSL_free(conn->
ssl);
5088 }
5089#endif
5093 }
5094}
5095
5097#ifndef NO_SSL
5100 }
5101#endif
5103 free(conn);
5104}
5105
5107
5108
5109 return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
5110}
5111
5113 const char *cl;
5114
5115 ebuf[0] = '\0';
5120
5122 snprintf(ebuf, ebuf_len, "%s", "Request Too Large");
5124 snprintf(ebuf, ebuf_len, "%s", "Client closed connection");
5127 snprintf(ebuf, ebuf_len,
"Bad request: [%.*s]", conn->
data_len, conn->
buf);
5128 } else {
5129
5130
5131
5132
5133
5134
5135
5136
5140 }
5143 }
5145 }
5146 return ebuf[0] == '\0';
5147}
5148
5151 int keep_alive_enabled, keep_alive, discard_len;
5152 char ebuf[100];
5153
5155 keep_alive = 0;
5156
5157
5158
5160 do {
5161 if (!
getreq(conn, ebuf,
sizeof(ebuf))) {
5165 snprintf(ebuf,
sizeof(ebuf),
"Invalid URI: [%s]", ri->
uri);
5169 snprintf(ebuf,
sizeof(ebuf),
"Bad HTTP version: [%s]", ri->
http_version);
5171 }
5172
5173 if (ebuf[0] == '\0') {
5177 }
5180
5181
5183 }
5184
5185
5186
5187
5188
5189 keep_alive = conn->
ctx->
stop_flag == 0 && keep_alive_enabled &&
5191
5192
5196 assert(discard_len >= 0);
5197 memmove(conn->
buf, conn->
buf + discard_len, conn->
data_len - discard_len);
5201 } while (keep_alive);
5202}
5203
5204
5206 (void) pthread_mutex_lock(&ctx->
mutex);
5208
5209
5212 }
5213
5214
5216
5220
5221
5225 }
5226 }
5227
5228 (void) pthread_cond_signal(&ctx->
sq_empty);
5229 (void) pthread_mutex_unlock(&ctx->
mutex);
5230
5232}
5233
5237
5239 if (conn == NULL) {
5240 cry(
fc(
ctx),
"%s",
"Cannot create new connection struct, OOM");
5241 } else {
5243 conn->
buf = (
char *) (conn + 1);
5246
5248
5249
5250
5253
5254
5255
5256
5257
5263
5265#ifndef NO_SSL
5267#endif
5268 ) {
5270 }
5271
5273 }
5275 free(conn);
5276 }
5277
5278
5279 (void) pthread_mutex_lock(&
ctx->
mutex);
5281 (void) pthread_cond_signal(&
ctx->
cond);
5283 (void) pthread_mutex_unlock(&
ctx->
mutex);
5284
5286 return NULL;
5287}
5288
5289
5291 (void) pthread_mutex_lock(&
ctx->
mutex);
5292
5293
5297 }
5298
5300
5304 }
5305
5307 (void) pthread_mutex_unlock(&
ctx->
mutex);
5308}
5309
5311#ifdef _WIN32
5312 DWORD t = milliseconds;
5313#else
5314 struct timeval t;
5315 t.tv_sec = milliseconds / 1000;
5316 t.tv_usec = (milliseconds * 1000) % 1000000;
5317#endif
5318 return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *) &t, sizeof(t)) ||
5319 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *) &t, sizeof(t));
5320}
5321
5326 socklen_t len =
sizeof(so.
rsa);
5327 int on = 1;
5328 extern int check_midas_acl(const struct sockaddr *sa, int len);
5329
5331 }
else if ((!
check_acl(ctx, ntohl(* (uint32_t *) &so.
rsa.
sin.sin_addr))) || (!check_midas_acl(&so.
rsa.
sa, len))) {
5333 cry(
fc(ctx),
"%s: %s is not allowed to connect", __func__, src_addr);
5335 } else {
5336
5342
5343
5344
5345
5346
5347
5348 setsockopt(so.
sock, SOL_SOCKET, SO_KEEPALIVE, (
void *) &on,
sizeof(on));
5351 }
5352}
5353
5356 struct pollfd *pfd;
5358
5359
5360#if defined(_WIN32)
5361 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
5362#endif
5363
5364#if defined(ISSUE_317)
5365 struct sched_param sched_param;
5366 sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
5367 pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
5368#endif
5369
5371
5373 while (pfd != NULL && ctx->
stop_flag == 0) {
5376 pfd[
i].events = POLLIN;
5377 }
5378
5381
5382
5383
5384
5385 if (ctx->
stop_flag == 0 && (pfd[
i].revents & POLLIN)) {
5387 }
5388 }
5389 }
5390 }
5391 free(pfd);
5393
5394
5396
5397
5398 pthread_cond_broadcast(&ctx->
sq_full);
5399
5400
5401 (void) pthread_mutex_lock(&ctx->
mutex);
5403 (void) pthread_cond_wait(&ctx->
cond, &ctx->
mutex);
5404 }
5405 (void) pthread_mutex_unlock(&ctx->
mutex);
5406
5407
5408 (void) pthread_mutex_destroy(&ctx->
mutex);
5409 (void) pthread_cond_destroy(&ctx->
cond);
5410 (void) pthread_cond_destroy(&ctx->
sq_empty);
5411 (void) pthread_cond_destroy(&ctx->
sq_full);
5412
5413#if !defined(NO_SSL)
5415#endif
5417
5419
5420
5421
5422
5424 return NULL;
5425}
5426
5429
5430
5434 }
5435
5436#ifndef NO_SSL
5437
5440 }
5444 }
5445#endif
5446
5447
5448 free(ctx);
5449}
5450
5453
5454
5457 }
5459
5460#if defined(_WIN32) && !defined(__SYMBIAN32__)
5461 (void) WSACleanup();
5462#endif
5463}
5464
5469 const char *
name, *
value, *default_value;
5471
5472#if defined(_WIN32) && !defined(__SYMBIAN32__)
5474 WSAStartup(MAKEWORD(2,2), &
data);
5475#endif
5476
5477
5478
5479 if ((ctx = (
struct mg_context *) calloc(1,
sizeof(*ctx))) == NULL) {
5480 return NULL;
5481 }
5484
5485 while (options && (
name = *options++) != NULL) {
5487 cry(
fc(ctx),
"Invalid option: %s",
name);
5489 return NULL;
5490 }
else if ((
value = *options++) == NULL) {
5491 cry(
fc(ctx),
"%s: option value cannot be NULL",
name);
5493 return NULL;
5494 }
5496 cry(
fc(ctx),
"warning: %s: duplicate option",
name);
5498 }
5501 }
5502
5503
5506 if (ctx->
config[
i] == NULL && default_value != NULL) {
5508 }
5509 }
5510
5511
5512
5514#if !defined(NO_SSL)
5516#endif
5518#if !defined(_WIN32)
5520#endif
5523 return NULL;
5524 }
5525
5526#if !defined(_WIN32) && !defined(__SYMBIAN32__)
5527
5528
5529 (void) signal(SIGPIPE, SIG_IGN);
5530#endif
5531
5532 (void) pthread_mutex_init(&ctx->
mutex, NULL);
5533 (void) pthread_cond_init(&ctx->
cond, NULL);
5534 (void) pthread_cond_init(&ctx->
sq_empty, NULL);
5535 (void) pthread_cond_init(&ctx->
sq_full, NULL);
5536
5537
5539
5540
5543 cry(
fc(ctx),
"Cannot start worker thread: %ld", (
long)
ERRNO);
5544 } else {
5546 }
5547 }
5548
5549 return ctx;
5550}
5551
5552#ifdef USE_LUA
5553#ifdef _WIN32
5554static void *mmap(
void *
addr, int64_t len,
int prot,
int flags,
int fd,
5556 HANDLE fh = (HANDLE) _get_osfhandle(fd);
5557 HANDLE
mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
5558 void *p = MapViewOfFile(
mh, FILE_MAP_READ, 0, 0, (
size_t) len);
5560 return p;
5561}
5562#define munmap(x, y) UnmapViewOfFile(x)
5563#define MAP_FAILED NULL
5564#define MAP_PRIVATE 0
5565#define PROT_READ 0
5566#else
5567#include <sys/mman.h>
5568#endif
5569
5570static const char *LUASOCKET = "luasocket";
5571
5572
5573static int handle_lsp_request(
struct mg_connection *,
const char *,
5574 struct file *,
struct lua_State *);
5575
5576static void reg_string(
struct lua_State *L,
const char *
name,
const char *val) {
5577 lua_pushstring(L,
name);
5578 lua_pushstring(L, val);
5579 lua_rawset(L, -3);
5580}
5581
5582static void reg_int(
struct lua_State *L,
const char *
name,
int val) {
5583 lua_pushstring(L,
name);
5584 lua_pushinteger(L, val);
5585 lua_rawset(L, -3);
5586}
5587
5588static void reg_function(
struct lua_State *L,
const char *
name,
5590 lua_pushstring(L,
name);
5591 lua_pushlightuserdata(L, conn);
5592 lua_pushcclosure(L, func, 1);
5593 lua_rawset(L, -3);
5594}
5595
5596static int lsp_sock_close(lua_State *L) {
5597 if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
5598 lua_getfield(L, -1, "sock");
5600 } else {
5601 return luaL_error(L, "invalid :close() call");
5602 }
5603 return 1;
5604}
5605
5606static int lsp_sock_recv(lua_State *L) {
5607 char buf[2000];
5609
5610 if (lua_gettop(L) > 0 && lua_istable(L, -1)) {
5611 lua_getfield(L, -1, "sock");
5612 n = recv((
SOCKET) lua_tonumber(L, -1), buf,
sizeof(buf), 0);
5614 lua_pushnil(L);
5615 } else {
5616 lua_pushlstring(L, buf,
n);
5617 }
5618 } else {
5619 return luaL_error(L, "invalid :close() call");
5620 }
5621 return 1;
5622}
5623
5624static int lsp_sock_send(lua_State *L) {
5625 const char *buf;
5626 size_t len, sent = 0;
5628
5629 if (lua_gettop(L) > 1 && lua_istable(L, -2) && lua_isstring(L, -1)) {
5630 buf = lua_tolstring(L, -1, &len);
5631 lua_getfield(L, -2, "sock");
5632 sock = (int) lua_tonumber(L, -1);
5633 while (sent < len) {
5634 if ((
n = send(sock, buf + sent, len - sent, 0)) <= 0) {
5635 break;
5636 }
5638 }
5639 lua_pushnumber(L,
n);
5640 } else {
5641 return luaL_error(L, "invalid :close() call");
5642 }
5643 return 1;
5644}
5645
5646static const struct luaL_Reg luasocket_methods[] = {
5647 {"close", lsp_sock_close},
5648 {"send", lsp_sock_send},
5649 {"recv", lsp_sock_recv},
5650 {NULL, NULL}
5651};
5652
5653static int lsp_connect(lua_State *L) {
5654 char ebuf[100];
5656
5657 if (lua_isstring(L, -3) && lua_isnumber(L, -2) && lua_isnumber(L, -1)) {
5658 sock =
conn2(lua_tostring(L, -3), (
int) lua_tonumber(L, -2),
5659 (int) lua_tonumber(L, -1), ebuf, sizeof(ebuf));
5661 return luaL_error(L, ebuf);
5662 } else {
5663 lua_newtable(L);
5664 reg_int(L, "sock", sock);
5665 reg_string(L, "host", lua_tostring(L, -4));
5666 luaL_getmetatable(L, LUASOCKET);
5667 lua_setmetatable(L, -2);
5668 }
5669 } else {
5670 return luaL_error(L, "connect(host,port,is_ssl): invalid parameter given.");
5671 }
5672 return 1;
5673}
5674
5675static int lsp_error(lua_State *L) {
5676 lua_getglobal(L, "mg");
5677 lua_getfield(L, -1, "onerror");
5678 lua_pushvalue(L, -3);
5679 lua_pcall(L, 1, 0, 0);
5680 return 0;
5681}
5682
5683
5684static void lsp_abort(lua_State *L) {
5685 int top = lua_gettop(L);
5686 lua_getglobal(L, "mg");
5687 lua_pushnil(L);
5688 lua_setfield(L, -2, "onerror");
5689 lua_settop(L, top);
5690 lua_pushstring(L, "aborting");
5691 lua_error(L);
5692}
5693
5695 const char *p, int64_t len, lua_State *L) {
5696 int i,
j, pos = 0, lines = 1, lualines = 0;
5698
5699 for (
i = 0;
i < len;
i++) {
5700 if (p[
i] ==
'\n') lines++;
5701 if (p[
i] ==
'<' && p[
i + 1] ==
'?') {
5702 for (
j =
i + 1;
j < len ;
j++) {
5703 if (p[
j] ==
'\n') lualines++;
5704 if (p[
j] ==
'?' && p[
j + 1] ==
'>') {
5706
5707 snprintf(chunkname, sizeof(chunkname), "@%s+%i", path, lines);
5708 lua_pushlightuserdata(L, conn);
5709 lua_pushcclosure(L, lsp_error, 1);
5710 if (luaL_loadbuffer(L, p + (
i + 2),
j - (
i + 2), chunkname)) {
5711
5712 lua_pcall(L, 1, 0, 0);
5713 } else {
5714
5715 lua_pcall(L, 0, 0, 1);
5716 }
5717
5720 break;
5721 }
5722 }
5723 if (lualines > 0) {
5724 lines += lualines;
5725 lualines = 0;
5726 }
5727 }
5728 }
5729
5732 }
5733
5734 return 0;
5735}
5736
5737static int lsp_write(lua_State *L) {
5740 size_t size;
5741 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5742
5743 num_args = lua_gettop(L);
5744 for (
i = 1;
i <= num_args;
i++) {
5745 if (lua_isstring(L,
i)) {
5746 str = lua_tolstring(L,
i, &size);
5748 }
5749 }
5750
5751 return 0;
5752}
5753
5754static int lsp_read(lua_State *L) {
5755 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5758
5759 if (len <= 0) return 0;
5760 lua_pushlstring(L,
buf, len);
5761
5762 return 1;
5763}
5764
5765
5766static int lsp_include(lua_State *L) {
5767 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5769 if (handle_lsp_request(conn, lua_tostring(L, -1), &
file, L)) {
5770
5771
5772 lsp_abort(L);
5773 }
5774 return 0;
5775}
5776
5777
5778static int lsp_cry(lua_State *L){
5779 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5780 cry(conn,
"%s", lua_tostring(L, -1));
5781 return 0;
5782}
5783
5784
5785static int lsp_redirect(lua_State *L) {
5786 struct mg_connection *conn = lua_touserdata(L, lua_upvalueindex(1));
5789 lsp_abort(L);
5790 return 0;
5791}
5792
5793static void prepare_lua_environment(
struct mg_connection *conn, lua_State *L) {
5795 extern void luaL_openlibs(lua_State *);
5797
5798 luaL_openlibs(L);
5799#ifdef USE_LUA_SQLITE3
5800 { extern int luaopen_lsqlite3(lua_State *); luaopen_lsqlite3(L); }
5801#endif
5802
5803 luaL_newmetatable(L, LUASOCKET);
5804 lua_pushliteral(L, "__index");
5805 luaL_newlib(L, luasocket_methods);
5806 lua_rawset(L, -3);
5807 lua_pop(L, 1);
5808 lua_register(L, "connect", lsp_connect);
5809
5810 if (conn == NULL) return;
5811
5812
5813 lua_newtable(L);
5814
5815 reg_function(L, "read", lsp_read, conn);
5816 reg_function(L, "write", lsp_write, conn);
5817 reg_function(L, "cry", lsp_cry, conn);
5818 reg_function(L, "include", lsp_include, conn);
5819 reg_function(L, "redirect", lsp_redirect, conn);
5821
5822
5823 lua_pushstring(L, "request_info");
5824 lua_newtable(L);
5826 reg_string(L,
"uri", ri->
uri);
5832 lua_pushstring(L, "http_headers");
5833 lua_newtable(L);
5836 }
5837 lua_rawset(L, -3);
5838 lua_rawset(L, -3);
5839
5840 lua_setglobal(L, "mg");
5841
5842
5843 luaL_dostring(L, "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
5844 "debug.traceback(e, 1)) end");
5845}
5846
5847static int lua_error_handler(lua_State *L) {
5848 const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
5849
5850 lua_getglobal(L, "mg");
5851 if (!lua_isnil(L, -1)) {
5852 lua_getfield(L, -1, "write");
5853 lua_pushstring(L, error_msg);
5854 lua_pushliteral(L, "\n");
5855 lua_call(L, 2, 0);
5856 luaL_dostring(L, "mg.write(debug.traceback(), '\\n')");
5857 } else {
5858 printf("Lua error: [%s]\n", error_msg);
5859 luaL_dostring(L, "print(debug.traceback(), '\\n')");
5860 }
5861
5862
5863 return 0;
5864}
5865
5866void mg_exec_lua_script(
struct mg_connection *conn,
const char *path,
5867 const void **exports) {
5869 lua_State *L;
5870
5871 if (path != NULL && (L = luaL_newstate()) != NULL) {
5872 prepare_lua_environment(conn, L);
5873 lua_pushcclosure(L, &lua_error_handler, 0);
5874
5875 lua_pushglobaltable(L);
5876 if (exports != NULL) {
5877 for (
i = 0; exports[
i] != NULL && exports[
i + 1] != NULL;
i += 2) {
5878 lua_pushstring(L, exports[
i]);
5879 lua_pushcclosure(L, (lua_CFunction) exports[
i + 1], 0);
5880 lua_rawset(L, -3);
5881 }
5882 }
5883
5884 if (luaL_loadfile(L, path) != 0) {
5885 lua_error_handler(L);
5886 }
5887 lua_pcall(L, 0, 0, -2);
5888 lua_close(L);
5889 }
5890}
5891
5892static void lsp_send_err(
struct mg_connection *conn,
struct lua_State *L,
5893 const char *fmt, ...) {
5895 va_list ap;
5896
5897 va_start(ap, fmt);
5898 vsnprintf(buf, sizeof(buf), fmt, ap);
5899 va_end(ap);
5900
5901 if (L == NULL) {
5903 } else {
5904 lua_pushstring(L, buf);
5905 lua_error(L);
5906 }
5907}
5908
5909static int handle_lsp_request(
struct mg_connection *conn,
const char *path,
5910 struct file *filep,
struct lua_State *ls) {
5911 void *p = NULL;
5912 lua_State *L = NULL;
5914 int error = 1;
5915
5916
5918 lsp_send_err(conn, ls, "File [%s] not found", path);
5919 }
else if ((p = mmap(NULL, (
size_t) filep->
size, PROT_READ, MAP_PRIVATE,
5920 fileno(
fp), 0)) == MAP_FAILED) {
5921 lsp_send_err(conn, ls,
"mmap(%s, %zu, %d): %s", path, (
size_t) filep->
size,
5922 fileno(
fp), strerror(errno));
5923 } else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) {
5925 } else {
5926
5927 if (ls == NULL) {
5928 prepare_lua_environment(conn, L);
5929 }
5930 error = lsp(conn, path, p, filep->
size, L);
5931 }
5932
5933 if (L != NULL && ls == NULL) lua_close(L);
5934 if (p != NULL) munmap(p, filep->
size);
5936
5937 return error;
5938}
5939#endif
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_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)
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 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 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 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)
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 const char * http_500_error
static int set_acl_option(struct mg_context *ctx)
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)