Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1044 lines
23 KiB

  1. /* See LICENSE file for copyright and license details. */
  2. #include <arpa/inet.h>
  3. #include <ctype.h>
  4. #include <errno.h>
  5. #include <limits.h>
  6. #include <netinet/in.h>
  7. #include <regex.h>
  8. #include <stddef.h>
  9. #include <stdint.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <strings.h>
  13. #include <sys/socket.h>
  14. #include <sys/stat.h>
  15. #include <sys/types.h>
  16. #include <time.h>
  17. #include <unistd.h>
  18. #include "config.h"
  19. #include "http.h"
  20. #include "util.h"
  21. const char *req_field_str[] = {
  22. [REQ_HOST] = "Host",
  23. [REQ_RANGE] = "Range",
  24. [REQ_IF_MODIFIED_SINCE] = "If-Modified-Since",
  25. };
  26. const char *req_method_str[] = {
  27. [M_GET] = "GET",
  28. [M_HEAD] = "HEAD",
  29. };
  30. const char *status_str[] = {
  31. [S_OK] = "OK",
  32. [S_PARTIAL_CONTENT] = "Partial Content",
  33. [S_MOVED_PERMANENTLY] = "Moved Permanently",
  34. [S_NOT_MODIFIED] = "Not Modified",
  35. [S_BAD_REQUEST] = "Bad Request",
  36. [S_FORBIDDEN] = "Forbidden",
  37. [S_NOT_FOUND] = "Not Found",
  38. [S_METHOD_NOT_ALLOWED] = "Method Not Allowed",
  39. [S_REQUEST_TIMEOUT] = "Request Time-out",
  40. [S_RANGE_NOT_SATISFIABLE] = "Range Not Satisfiable",
  41. [S_REQUEST_TOO_LARGE] = "Request Header Fields Too Large",
  42. [S_INTERNAL_SERVER_ERROR] = "Internal Server Error",
  43. [S_VERSION_NOT_SUPPORTED] = "HTTP Version not supported",
  44. };
  45. const char *res_field_str[] = {
  46. [RES_ACCEPT_RANGES] = "Accept-Ranges",
  47. [RES_ALLOW] = "Allow",
  48. [RES_LOCATION] = "Location",
  49. [RES_LAST_MODIFIED] = "Last-Modified",
  50. [RES_CONTENT_LENGTH] = "Content-Length",
  51. [RES_CONTENT_RANGE] = "Content-Range",
  52. [RES_CONTENT_TYPE] = "Content-Type",
  53. };
  54. enum status
  55. http_prepare_header_buf(const struct response *res, struct buffer *buf)
  56. {
  57. char tstmp[FIELD_MAX];
  58. size_t i;
  59. /* reset buffer */
  60. memset(buf, 0, sizeof(*buf));
  61. /* generate timestamp */
  62. if (timestamp(tstmp, sizeof(tstmp), time(NULL))) {
  63. goto err;
  64. }
  65. /* write data */
  66. if (buffer_appendf(buf,
  67. "HTTP/1.1 %d %s\r\n"
  68. "Date: %s\r\n"
  69. "Connection: close\r\n",
  70. res->status, status_str[res->status], tstmp)) {
  71. goto err;
  72. }
  73. for (i = 0; i < NUM_RES_FIELDS; i++) {
  74. if (res->field[i][0] != '\0' &&
  75. buffer_appendf(buf, "%s: %s\r\n", res_field_str[i],
  76. res->field[i])) {
  77. goto err;
  78. }
  79. }
  80. if (buffer_appendf(buf, "\r\n")) {
  81. goto err;
  82. }
  83. return 0;
  84. err:
  85. memset(buf, 0, sizeof(*buf));
  86. return S_INTERNAL_SERVER_ERROR;
  87. }
  88. enum status
  89. http_send_buf(int fd, struct buffer *buf)
  90. {
  91. ssize_t r;
  92. if (buf == NULL) {
  93. return S_INTERNAL_SERVER_ERROR;
  94. }
  95. while (buf->len > 0) {
  96. if ((r = write(fd, buf->data, buf->len)) <= 0) {
  97. if (errno == EAGAIN || errno == EWOULDBLOCK) {
  98. /*
  99. * socket is blocking, return normally.
  100. * given the buffer still contains data,
  101. * this indicates to the caller that we
  102. * have been interrupted.
  103. */
  104. return 0;
  105. } else {
  106. return S_REQUEST_TIMEOUT;
  107. }
  108. }
  109. memmove(buf->data, buf->data + r, buf->len - r);
  110. buf->len -= r;
  111. }
  112. return 0;
  113. }
  114. static void
  115. decode(const char src[PATH_MAX], char dest[PATH_MAX])
  116. {
  117. size_t i;
  118. uint8_t n;
  119. const char *s;
  120. for (s = src, i = 0; *s; s++, i++) {
  121. if (*s == '%' && (sscanf(s + 1, "%2hhx", &n) == 1)) {
  122. dest[i] = n;
  123. s += 2;
  124. } else {
  125. dest[i] = *s;
  126. }
  127. }
  128. dest[i] = '\0';
  129. }
  130. enum status
  131. http_recv_header(int fd, struct buffer *buf, int *done)
  132. {
  133. enum status s;
  134. ssize_t r;
  135. while (1) {
  136. if ((r = read(fd, buf->data + buf->len,
  137. sizeof(buf->data) - buf->len)) < 0) {
  138. if (errno == EAGAIN || errno == EWOULDBLOCK) {
  139. /*
  140. * socket is drained, return normally,
  141. * but set done to zero
  142. */
  143. *done = 0;
  144. return 0;
  145. } else {
  146. s = S_REQUEST_TIMEOUT;
  147. goto err;
  148. }
  149. } else if (r == 0) {
  150. /*
  151. * unexpected EOF because the client probably
  152. * hung up. This is technically a bad request,
  153. * because it's incomplete
  154. */
  155. s = S_BAD_REQUEST;
  156. goto err;
  157. }
  158. buf->len += r;
  159. /* check if we are done (header terminated) */
  160. if (buf->len >= 4 && !memcmp(buf->data + buf->len - 4,
  161. "\r\n\r\n", 4)) {
  162. break;
  163. }
  164. /* buffer is full or read over, but header is not terminated */
  165. if (r == 0 || buf->len == sizeof(buf->data)) {
  166. s = S_REQUEST_TOO_LARGE;
  167. goto err;
  168. }
  169. }
  170. /* header is complete, remove last \r\n and set done */
  171. buf->len -= 2;
  172. *done = 1;
  173. return 0;
  174. err:
  175. memset(buf, 0, sizeof(*buf));
  176. return s;
  177. }
  178. enum status
  179. http_parse_header(const char *h, struct request *req)
  180. {
  181. struct in6_addr addr;
  182. size_t i, mlen;
  183. const char *p, *q, *r, *s, *t;
  184. char *m, *n;
  185. /* empty the request struct */
  186. memset(req, 0, sizeof(*req));
  187. /*
  188. * parse request line
  189. */
  190. /* METHOD */
  191. for (i = 0; i < NUM_REQ_METHODS; i++) {
  192. mlen = strlen(req_method_str[i]);
  193. if (!strncmp(req_method_str[i], h, mlen)) {
  194. req->method = i;
  195. break;
  196. }
  197. }
  198. if (i == NUM_REQ_METHODS) {
  199. return S_METHOD_NOT_ALLOWED;
  200. }
  201. /* a single space must follow the method */
  202. if (h[mlen] != ' ') {
  203. return S_BAD_REQUEST;
  204. }
  205. /* basis for next step */
  206. p = h + mlen + 1;
  207. /* RESOURCE */
  208. /*
  209. * path?query#fragment
  210. * ^ ^ ^ ^
  211. * | | | |
  212. * p r s q
  213. *
  214. */
  215. if (!(q = strchr(p, ' '))) {
  216. return S_BAD_REQUEST;
  217. }
  218. /* search for first '?' */
  219. for (r = p; r < q; r++) {
  220. if (!isprint(*r)) {
  221. return S_BAD_REQUEST;
  222. }
  223. if (*r == '?') {
  224. break;
  225. }
  226. }
  227. if (r == q) {
  228. /* not found */
  229. r = NULL;
  230. }
  231. /* search for first '#' */
  232. for (s = p; s < q; s++) {
  233. if (!isprint(*s)) {
  234. return S_BAD_REQUEST;
  235. }
  236. if (*s == '#') {
  237. break;
  238. }
  239. }
  240. if (s == q) {
  241. /* not found */
  242. s = NULL;
  243. }
  244. if (r != NULL && s != NULL && s < r) {
  245. /*
  246. * '#' comes before '?' and thus the '?' is literal,
  247. * because the query must come before the fragment
  248. */
  249. r = NULL;
  250. }
  251. /* write path using temporary endpointer t */
  252. if (r != NULL) {
  253. /* resource contains a query, path ends at r */
  254. t = r;
  255. } else if (s != NULL) {
  256. /* resource contains only a fragment, path ends at s */
  257. t = s;
  258. } else {
  259. /* resource contains no queries, path ends at q */
  260. t = q;
  261. }
  262. if ((size_t)(t - p + 1) > LEN(req->path)) {
  263. return S_REQUEST_TOO_LARGE;
  264. }
  265. memcpy(req->path, p, t - p);
  266. req->path[t - p] = '\0';
  267. decode(req->path, req->path);
  268. /* write query if present */
  269. if (r != NULL) {
  270. /* query ends either at s (if fragment present) or q */
  271. t = (s != NULL) ? s : q;
  272. if ((size_t)(t - (r + 1) + 1) > LEN(req->query)) {
  273. return S_REQUEST_TOO_LARGE;
  274. }
  275. memcpy(req->query, r + 1, t - (r + 1));
  276. req->query[t - (r + 1)] = '\0';
  277. }
  278. /* write fragment if present */
  279. if (s != NULL) {
  280. /* the fragment always starts at s + 1 and ends at q */
  281. if ((size_t)(q - (s + 1) + 1) > LEN(req->fragment)) {
  282. return S_REQUEST_TOO_LARGE;
  283. }
  284. memcpy(req->fragment, s + 1, q - (s + 1));
  285. req->fragment[q - (s + 1)] = '\0';
  286. }
  287. /* basis for next step */
  288. p = q + 1;
  289. /* HTTP-VERSION */
  290. if (strncmp(p, "HTTP/", sizeof("HTTP/") - 1)) {
  291. return S_BAD_REQUEST;
  292. }
  293. p += sizeof("HTTP/") - 1;
  294. if (strncmp(p, "1.0", sizeof("1.0") - 1) &&
  295. strncmp(p, "1.1", sizeof("1.1") - 1)) {
  296. return S_VERSION_NOT_SUPPORTED;
  297. }
  298. p += sizeof("1.*") - 1;
  299. /* check terminator */
  300. if (strncmp(p, "\r\n", sizeof("\r\n") - 1)) {
  301. return S_BAD_REQUEST;
  302. }
  303. /* basis for next step */
  304. p += sizeof("\r\n") - 1;
  305. /*
  306. * parse request-fields
  307. */
  308. /* match field type */
  309. for (; *p != '\0';) {
  310. for (i = 0; i < NUM_REQ_FIELDS; i++) {
  311. if (!strncasecmp(p, req_field_str[i],
  312. strlen(req_field_str[i]))) {
  313. break;
  314. }
  315. }
  316. if (i == NUM_REQ_FIELDS) {
  317. /* unmatched field, skip this line */
  318. if (!(q = strstr(p, "\r\n"))) {
  319. return S_BAD_REQUEST;
  320. }
  321. p = q + (sizeof("\r\n") - 1);
  322. continue;
  323. }
  324. p += strlen(req_field_str[i]);
  325. /* a single colon must follow the field name */
  326. if (*p != ':') {
  327. return S_BAD_REQUEST;
  328. }
  329. /* skip whitespace */
  330. for (++p; *p == ' ' || *p == '\t'; p++)
  331. ;
  332. /* extract field content */
  333. if (!(q = strstr(p, "\r\n"))) {
  334. return S_BAD_REQUEST;
  335. }
  336. if ((size_t)(q - p + 1) > LEN(req->field[i])) {
  337. return S_REQUEST_TOO_LARGE;
  338. }
  339. memcpy(req->field[i], p, q - p);
  340. req->field[i][q - p] = '\0';
  341. /* go to next line */
  342. p = q + (sizeof("\r\n") - 1);
  343. }
  344. /*
  345. * clean up host
  346. */
  347. m = strrchr(req->field[REQ_HOST], ':');
  348. n = strrchr(req->field[REQ_HOST], ']');
  349. /* strip port suffix but don't interfere with IPv6 bracket notation
  350. * as per RFC 2732 */
  351. if (m && (!n || m > n)) {
  352. /* port suffix must not be empty */
  353. if (*(m + 1) == '\0') {
  354. return S_BAD_REQUEST;
  355. }
  356. *m = '\0';
  357. }
  358. /* strip the brackets from the IPv6 notation and validate the address */
  359. if (n) {
  360. /* brackets must be on the outside */
  361. if (req->field[REQ_HOST][0] != '[' || *(n + 1) != '\0') {
  362. return S_BAD_REQUEST;
  363. }
  364. /* remove the right bracket */
  365. *n = '\0';
  366. m = req->field[REQ_HOST] + 1;
  367. /* validate the contained IPv6 address */
  368. if (inet_pton(AF_INET6, m, &addr) != 1) {
  369. return S_BAD_REQUEST;
  370. }
  371. /* copy it into the host field */
  372. memmove(req->field[REQ_HOST], m, n - m + 1);
  373. }
  374. return 0;
  375. }
  376. static void
  377. encode(const char src[PATH_MAX], char dest[PATH_MAX])
  378. {
  379. size_t i;
  380. const char *s;
  381. for (s = src, i = 0; *s && i < (PATH_MAX - 4); s++) {
  382. if (iscntrl(*s) || (unsigned char)*s > 127) {
  383. i += snprintf(dest + i, PATH_MAX - i, "%%%02X",
  384. (unsigned char)*s);
  385. } else {
  386. dest[i] = *s;
  387. i++;
  388. }
  389. }
  390. dest[i] = '\0';
  391. }
  392. static enum status
  393. path_normalize(char *uri, int *redirect)
  394. {
  395. size_t len;
  396. int last = 0;
  397. char *p, *q;
  398. /* require and skip first slash */
  399. if (uri[0] != '/') {
  400. return S_BAD_REQUEST;
  401. }
  402. p = uri + 1;
  403. /* get length of URI */
  404. len = strlen(p);
  405. for (; !last; ) {
  406. /* bound uri component within (p,q) */
  407. if (!(q = strchr(p, '/'))) {
  408. q = strchr(p, '\0');
  409. last = 1;
  410. }
  411. if (*p == '\0') {
  412. break;
  413. } else if (p == q || (q - p == 1 && p[0] == '.')) {
  414. /* "/" or "./" */
  415. goto squash;
  416. } else if (q - p == 2 && p[0] == '.' && p[1] == '.') {
  417. /* "../" */
  418. if (p != uri + 1) {
  419. /* place p right after the previous / */
  420. for (p -= 2; p > uri && *p != '/'; p--);
  421. p++;
  422. }
  423. goto squash;
  424. } else {
  425. /* move on */
  426. p = q + 1;
  427. continue;
  428. }
  429. squash:
  430. /* squash (p,q) into void */
  431. if (last) {
  432. *p = '\0';
  433. len = p - uri;
  434. } else {
  435. memmove(p, q + 1, len - ((q + 1) - uri) + 2);
  436. len -= (q + 1) - p;
  437. }
  438. if (redirect != NULL) {
  439. *redirect = 1;
  440. }
  441. }
  442. return 0;
  443. }
  444. static enum status
  445. path_add_vhost_prefix(char uri[PATH_MAX], int *redirect,
  446. const struct server *srv, const struct response *res)
  447. {
  448. if (srv->vhost && res->vhost && res->vhost->prefix) {
  449. if (prepend(uri, PATH_MAX, res->vhost->prefix)) {
  450. return S_REQUEST_TOO_LARGE;
  451. }
  452. if (redirect != NULL) {
  453. *redirect = 1;
  454. }
  455. }
  456. return 0;
  457. }
  458. static enum status
  459. path_apply_prefix_mapping(char uri[PATH_MAX], int *redirect,
  460. const struct server *srv, const struct response *res)
  461. {
  462. size_t i, len;
  463. for (i = 0; i < srv->map_len; i++) {
  464. len = strlen(srv->map[i].from);
  465. if (!strncmp(uri, srv->map[i].from, len)) {
  466. /*
  467. * if vhosts are enabled only apply mappings
  468. * defined for the current canonical host
  469. */
  470. if (srv->vhost && res->vhost && srv->map[i].chost &&
  471. strcmp(srv->map[i].chost, res->vhost->chost)) {
  472. continue;
  473. }
  474. /* swap out URI prefix */
  475. memmove(uri, uri + len, strlen(uri) + 1);
  476. if (prepend(uri, PATH_MAX, srv->map[i].to)) {
  477. return S_REQUEST_TOO_LARGE;
  478. }
  479. if (redirect != NULL) {
  480. *redirect = 1;
  481. }
  482. /* break so we don't possibly hit an infinite loop */
  483. break;
  484. }
  485. }
  486. return 0;
  487. }
  488. static enum status
  489. path_ensure_dirslash(char uri[PATH_MAX], int *redirect)
  490. {
  491. size_t len;
  492. /* append '/' to URI if not present */
  493. len = strlen(uri);
  494. if (len + 1 + 1 > PATH_MAX) {
  495. return S_REQUEST_TOO_LARGE;
  496. }
  497. if (len > 0 && uri[len - 1] != '/') {
  498. uri[len] = '/';
  499. uri[len + 1] = '\0';
  500. if (redirect != NULL) {
  501. *redirect = 1;
  502. }
  503. }
  504. return 0;
  505. }
  506. static enum status
  507. parse_range(const char *str, size_t size, size_t *lower, size_t *upper)
  508. {
  509. char first[FIELD_MAX], last[FIELD_MAX];
  510. const char *p, *q, *r, *err;
  511. /* default to the complete range */
  512. *lower = 0;
  513. *upper = size - 1;
  514. /* done if no range-string is given */
  515. if (str == NULL || *str == '\0') {
  516. return 0;
  517. }
  518. /* skip opening statement */
  519. if (strncmp(str, "bytes=", sizeof("bytes=") - 1)) {
  520. return S_BAD_REQUEST;
  521. }
  522. p = str + (sizeof("bytes=") - 1);
  523. /* check string (should only contain numbers and a hyphen) */
  524. for (r = p, q = NULL; *r != '\0'; r++) {
  525. if (*r < '0' || *r > '9') {
  526. if (*r == '-') {
  527. if (q != NULL) {
  528. /* we have already seen a hyphen */
  529. return S_BAD_REQUEST;
  530. } else {
  531. /* place q after the hyphen */
  532. q = r + 1;
  533. }
  534. } else if (*r == ',' && r > p) {
  535. /*
  536. * we refuse to accept range-lists out
  537. * of spite towards this horrible part
  538. * of the spec
  539. */
  540. return S_RANGE_NOT_SATISFIABLE;
  541. } else {
  542. return S_BAD_REQUEST;
  543. }
  544. }
  545. }
  546. if (q == NULL) {
  547. /* the input string must contain a hyphen */
  548. return S_BAD_REQUEST;
  549. }
  550. r = q + strlen(q);
  551. /*
  552. * byte-range=first-last\0
  553. * ^ ^ ^
  554. * | | |
  555. * p q r
  556. */
  557. /* copy 'first' and 'last' to their respective arrays */
  558. if ((size_t)((q - 1) - p + 1) > sizeof(first) ||
  559. (size_t)(r - q + 1) > sizeof(last)) {
  560. return S_REQUEST_TOO_LARGE;
  561. }
  562. memcpy(first, p, (q - 1) - p);
  563. first[(q - 1) - p] = '\0';
  564. memcpy(last, q, r - q);
  565. last[r - q] = '\0';
  566. if (first[0] != '\0') {
  567. /*
  568. * range has format "first-last" or "first-",
  569. * i.e. return bytes 'first' to 'last' (or the
  570. * last byte if 'last' is not given),
  571. * inclusively, and byte-numbering beginning at 0
  572. */
  573. *lower = strtonum(first, 0, MIN(SIZE_MAX, LLONG_MAX),
  574. &err);
  575. if (!err) {
  576. if (last[0] != '\0') {
  577. *upper = strtonum(last, 0,
  578. MIN(SIZE_MAX, LLONG_MAX),
  579. &err);
  580. } else {
  581. *upper = size - 1;
  582. }
  583. }
  584. if (err) {
  585. /* one of the strtonum()'s failed */
  586. return S_BAD_REQUEST;
  587. }
  588. /* check ranges */
  589. if (*lower > *upper || *lower >= size) {
  590. return S_RANGE_NOT_SATISFIABLE;
  591. }
  592. /* adjust upper limit to be at most the last byte */
  593. *upper = MIN(*upper, size - 1);
  594. } else {
  595. /* last must not also be empty */
  596. if (last[0] == '\0') {
  597. return S_BAD_REQUEST;
  598. }
  599. /*
  600. * Range has format "-num", i.e. return the 'num'
  601. * last bytes
  602. */
  603. /*
  604. * use upper as a temporary storage for 'num',
  605. * as we know 'upper' is size - 1
  606. */
  607. *upper = strtonum(last, 0, MIN(SIZE_MAX, LLONG_MAX), &err);
  608. if (err) {
  609. return S_BAD_REQUEST;
  610. }
  611. /* determine lower */
  612. if (*upper > size) {
  613. /* more bytes requested than we have */
  614. *lower = 0;
  615. } else {
  616. *lower = size - *upper;
  617. }
  618. /* set upper to the correct value */
  619. *upper = size - 1;
  620. }
  621. return 0;
  622. }
  623. void
  624. http_prepare_response(const struct request *req, struct response *res,
  625. const struct server *srv)
  626. {
  627. enum status s, tmps;
  628. struct in6_addr addr;
  629. struct stat st;
  630. struct tm tm = { 0 };
  631. size_t i;
  632. int redirect, hasport, ipv6host;
  633. static char tmppath[PATH_MAX];
  634. char *p, *mime;
  635. /* empty all response fields */
  636. memset(res, 0, sizeof(*res));
  637. /* determine virtual host */
  638. if (srv->vhost) {
  639. for (i = 0; i < srv->vhost_len; i++) {
  640. if (!regexec(&(srv->vhost[i].re),
  641. req->field[REQ_HOST], 0, NULL, 0)) {
  642. /* we have a matching vhost */
  643. res->vhost = &(srv->vhost[i]);
  644. break;
  645. }
  646. }
  647. if (i == srv->vhost_len) {
  648. s = S_NOT_FOUND;
  649. goto err;
  650. }
  651. }
  652. /* copy request-path to response-path and clean it up */
  653. redirect = 0;
  654. memcpy(res->path, req->path, MIN(sizeof(res->path), sizeof(req->path)));
  655. if ((tmps = path_normalize(res->path, &redirect)) ||
  656. (tmps = path_add_vhost_prefix(res->path, &redirect, srv, res)) ||
  657. (tmps = path_apply_prefix_mapping(res->path, &redirect, srv, res)) ||
  658. (tmps = path_normalize(res->path, &redirect))) {
  659. s = tmps;
  660. goto err;
  661. }
  662. /* redirect all non-canonical hosts to their canonical forms */
  663. if (srv->vhost && res->vhost &&
  664. strcmp(req->field[REQ_HOST], res->vhost->chost)) {
  665. redirect = 1;
  666. }
  667. /* reject all non-well-known hidden targets (see RFC 8615) */
  668. if (strstr(res->path, "/.") && strncmp(res->path, "/.well-known/",
  669. sizeof("/.well-known/") - 1)) {
  670. s = S_FORBIDDEN;
  671. goto err;
  672. }
  673. /*
  674. * generate and stat internal path based on the cleaned up request
  675. * path and the virtual host while ignoring query and fragment
  676. * (valid according to RFC 3986)
  677. */
  678. if (esnprintf(res->internal_path, sizeof(res->internal_path), "/%s/%s",
  679. (srv->vhost && res->vhost) ? res->vhost->dir : "",
  680. res->path)) {
  681. s = S_REQUEST_TOO_LARGE;
  682. goto err;
  683. }
  684. if ((tmps = path_normalize(res->internal_path, NULL))) {
  685. s = tmps;
  686. goto err;
  687. }
  688. if (stat(res->internal_path, &st) < 0) {
  689. s = (errno == EACCES) ? S_FORBIDDEN : S_NOT_FOUND;
  690. goto err;
  691. }
  692. /*
  693. * if the path points at a directory, make sure both the path
  694. * and internal path have a trailing slash
  695. */
  696. if (S_ISDIR(st.st_mode)) {
  697. if ((tmps = path_ensure_dirslash(res->path, &redirect)) ||
  698. (tmps = path_ensure_dirslash(res->internal_path, NULL))) {
  699. s = tmps;
  700. goto err;
  701. }
  702. }
  703. /* redirect if the path-cleanup necessitated it earlier */
  704. if (redirect) {
  705. res->status = S_MOVED_PERMANENTLY;
  706. /* encode path */
  707. encode(res->path, tmppath);
  708. /* determine target location */
  709. if (srv->vhost && res->vhost) {
  710. /* absolute redirection URL */
  711. /* do we need to add a port to the Location? */
  712. hasport = srv->port && strcmp(srv->port, "80");
  713. /* RFC 2732 specifies to use brackets for IPv6-addresses
  714. * in URLs, so we need to check if our host is one and
  715. * honor that later when we fill the "Location"-field */
  716. if ((ipv6host = inet_pton(AF_INET6, res->vhost->chost,
  717. &addr)) < 0) {
  718. s = S_INTERNAL_SERVER_ERROR;
  719. goto err;
  720. }
  721. /*
  722. * write location to response struct (re-including
  723. * the query and fragment, if present)
  724. */
  725. if (esnprintf(res->field[RES_LOCATION],
  726. sizeof(res->field[RES_LOCATION]),
  727. "//%s%s%s%s%s%s%s%s%s%s",
  728. ipv6host ? "[" : "",
  729. res->vhost->chost,
  730. ipv6host ? "]" : "",
  731. hasport ? ":" : "",
  732. hasport ? srv->port : "",
  733. tmppath,
  734. req->query[0] ? "?" : "",
  735. req->query,
  736. req->fragment[0] ? "#" : "",
  737. req->fragment)) {
  738. s = S_REQUEST_TOO_LARGE;
  739. goto err;
  740. }
  741. } else {
  742. /*
  743. * write relative redirection URI to response struct
  744. * (re-including the query and fragment, if present)
  745. */
  746. if (esnprintf(res->field[RES_LOCATION],
  747. sizeof(res->field[RES_LOCATION]),
  748. "%s%s%s%s%s",
  749. tmppath,
  750. req->query[0] ? "?" : "",
  751. req->query,
  752. req->fragment[0] ? "#" : "",
  753. req->fragment)) {
  754. s = S_REQUEST_TOO_LARGE;
  755. goto err;
  756. }
  757. }
  758. return;
  759. }
  760. if (S_ISDIR(st.st_mode)) {
  761. /*
  762. * when we serve a directory, we first check if there
  763. * exists a directory index. If not, we either make
  764. * a directory listing (if enabled) or send an error
  765. */
  766. /*
  767. * append docindex to internal_path temporarily
  768. * (internal_path is guaranteed to end with '/')
  769. */
  770. if (esnprintf(tmppath, sizeof(tmppath), "%s%s",
  771. res->internal_path, srv->docindex)) {
  772. s = S_REQUEST_TOO_LARGE;
  773. goto err;
  774. }
  775. /* stat the temporary path, which must be a regular file */
  776. if (stat(tmppath, &st) < 0 || !S_ISREG(st.st_mode)) {
  777. if (srv->listdirs) {
  778. /* serve directory listing */
  779. /* check if directory is accessible */
  780. if (access(res->internal_path, R_OK) != 0) {
  781. s = S_FORBIDDEN;
  782. goto err;
  783. } else {
  784. res->status = S_OK;
  785. }
  786. res->type = RESTYPE_DIRLISTING;
  787. if (esnprintf(res->field[RES_CONTENT_TYPE],
  788. sizeof(res->field[RES_CONTENT_TYPE]),
  789. "%s", "text/html; charset=utf-8")) {
  790. s = S_INTERNAL_SERVER_ERROR;
  791. goto err;
  792. }
  793. return;
  794. } else {
  795. /* reject */
  796. s = (!S_ISREG(st.st_mode) || errno == EACCES) ?
  797. S_FORBIDDEN : S_NOT_FOUND;
  798. goto err;
  799. }
  800. } else {
  801. /* the docindex exists; copy tmppath to internal path */
  802. if (esnprintf(res->internal_path,
  803. sizeof(res->internal_path), "%s",
  804. tmppath)) {
  805. s = S_REQUEST_TOO_LARGE;
  806. goto err;
  807. }
  808. }
  809. }
  810. /* modified since */
  811. if (req->field[REQ_IF_MODIFIED_SINCE][0]) {
  812. /* parse field */
  813. if (!strptime(req->field[REQ_IF_MODIFIED_SINCE],
  814. "%a, %d %b %Y %T GMT", &tm)) {
  815. s = S_BAD_REQUEST;
  816. goto err;
  817. }
  818. /* compare with last modification date of the file */
  819. if (difftime(st.st_mtim.tv_sec, timegm(&tm)) <= 0) {
  820. res->status = S_NOT_MODIFIED;
  821. return;
  822. }
  823. }
  824. /* range */
  825. if ((s = parse_range(req->field[REQ_RANGE], st.st_size,
  826. &(res->file.lower), &(res->file.upper)))) {
  827. if (s == S_RANGE_NOT_SATISFIABLE) {
  828. res->status = S_RANGE_NOT_SATISFIABLE;
  829. if (esnprintf(res->field[RES_CONTENT_RANGE],
  830. sizeof(res->field[RES_CONTENT_RANGE]),
  831. "bytes */%zu", st.st_size)) {
  832. s = S_INTERNAL_SERVER_ERROR;
  833. goto err;
  834. }
  835. return;
  836. } else {
  837. goto err;
  838. }
  839. }
  840. /* mime */
  841. mime = "application/octet-stream";
  842. if ((p = strrchr(res->internal_path, '.'))) {
  843. for (i = 0; i < LEN(mimes); i++) {
  844. if (!strcmp(mimes[i].ext, p + 1)) {
  845. mime = mimes[i].type;
  846. break;
  847. }
  848. }
  849. }
  850. /* fill response struct */
  851. res->type = RESTYPE_FILE;
  852. /* check if file is readable */
  853. res->status = (access(res->internal_path, R_OK)) ? S_FORBIDDEN :
  854. (req->field[REQ_RANGE][0] != '\0') ?
  855. S_PARTIAL_CONTENT : S_OK;
  856. if (esnprintf(res->field[RES_ACCEPT_RANGES],
  857. sizeof(res->field[RES_ACCEPT_RANGES]),
  858. "%s", "bytes")) {
  859. s = S_INTERNAL_SERVER_ERROR;
  860. goto err;
  861. }
  862. if (esnprintf(res->field[RES_CONTENT_LENGTH],
  863. sizeof(res->field[RES_CONTENT_LENGTH]),
  864. "%zu", res->file.upper - res->file.lower + 1)) {
  865. s = S_INTERNAL_SERVER_ERROR;
  866. goto err;
  867. }
  868. if (req->field[REQ_RANGE][0] != '\0') {
  869. if (esnprintf(res->field[RES_CONTENT_RANGE],
  870. sizeof(res->field[RES_CONTENT_RANGE]),
  871. "bytes %zd-%zd/%zu", res->file.lower,
  872. res->file.upper, st.st_size)) {
  873. s = S_INTERNAL_SERVER_ERROR;
  874. goto err;
  875. }
  876. }
  877. if (esnprintf(res->field[RES_CONTENT_TYPE],
  878. sizeof(res->field[RES_CONTENT_TYPE]),
  879. "%s", mime)) {
  880. s = S_INTERNAL_SERVER_ERROR;
  881. goto err;
  882. }
  883. if (timestamp(res->field[RES_LAST_MODIFIED],
  884. sizeof(res->field[RES_LAST_MODIFIED]),
  885. st.st_mtim.tv_sec)) {
  886. s = S_INTERNAL_SERVER_ERROR;
  887. goto err;
  888. }
  889. return;
  890. err:
  891. http_prepare_error_response(req, res, s);
  892. }
  893. void
  894. http_prepare_error_response(const struct request *req,
  895. struct response *res, enum status s)
  896. {
  897. /* used later */
  898. (void)req;
  899. /* empty all response fields */
  900. memset(res, 0, sizeof(*res));
  901. res->type = RESTYPE_ERROR;
  902. res->status = s;
  903. if (esnprintf(res->field[RES_CONTENT_TYPE],
  904. sizeof(res->field[RES_CONTENT_TYPE]),
  905. "text/html; charset=utf-8")) {
  906. res->status = S_INTERNAL_SERVER_ERROR;
  907. }
  908. if (res->status == S_METHOD_NOT_ALLOWED) {
  909. if (esnprintf(res->field[RES_ALLOW],
  910. sizeof(res->field[RES_ALLOW]),
  911. "Allow: GET, HEAD")) {
  912. res->status = S_INTERNAL_SERVER_ERROR;
  913. }
  914. }
  915. }