1 /* $OpenBSD: server_http.c,v 1.141 2020/09/12 07:34:17 yasuoka Exp $ */ 2 3 /* 4 * Copyright (c) 2006 - 2018 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/socket.h> 22 #include <sys/tree.h> 23 24 #include <netinet/in.h> 25 #include <arpa/inet.h> 26 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <limits.h> 32 #include <fnmatch.h> 33 #include <stdio.h> 34 #include <time.h> 35 #include <resolv.h> 36 #include <event.h> 37 #include <ctype.h> 38 #include <vis.h> 39 40 #include "httpd.h" 41 #include "http.h" 42 #include "patterns.h" 43 44 static int server_httpmethod_cmp(const void *, const void *); 45 static int server_httperror_cmp(const void *, const void *); 46 void server_httpdesc_free(struct http_descriptor *); 47 int server_http_authenticate(struct server_config *, 48 struct client *); 49 char *server_expand_http(struct client *, const char *, 50 char *, size_t); 51 52 static struct http_method http_methods[] = HTTP_METHODS; 53 static struct http_error http_errors[] = HTTP_ERRORS; 54 55 void 56 server_http(void) 57 { 58 DPRINTF("%s: sorting lookup tables, pid %d", __func__, getpid()); 59 60 /* Sort the HTTP lookup arrays */ 61 qsort(http_methods, sizeof(http_methods) / 62 sizeof(http_methods[0]) - 1, 63 sizeof(http_methods[0]), server_httpmethod_cmp); 64 qsort(http_errors, sizeof(http_errors) / 65 sizeof(http_errors[0]) - 1, 66 sizeof(http_errors[0]), server_httperror_cmp); 67 } 68 69 void 70 server_http_init(struct server *srv) 71 { 72 /* nothing */ 73 } 74 75 int 76 server_httpdesc_init(struct client *clt) 77 { 78 struct http_descriptor *desc; 79 80 if ((desc = calloc(1, sizeof(*desc))) == NULL) 81 return (-1); 82 RB_INIT(&desc->http_headers); 83 clt->clt_descreq = desc; 84 85 if ((desc = calloc(1, sizeof(*desc))) == NULL) { 86 /* req will be cleaned up later */ 87 return (-1); 88 } 89 RB_INIT(&desc->http_headers); 90 clt->clt_descresp = desc; 91 92 return (0); 93 } 94 95 void 96 server_httpdesc_free(struct http_descriptor *desc) 97 { 98 if (desc == NULL) 99 return; 100 101 free(desc->http_path); 102 desc->http_path = NULL; 103 free(desc->http_path_orig); 104 desc->http_path_orig = NULL; 105 free(desc->http_path_alias); 106 desc->http_path_alias = NULL; 107 free(desc->http_query); 108 desc->http_query = NULL; 109 free(desc->http_query_alias); 110 desc->http_query_alias = NULL; 111 free(desc->http_version); 112 desc->http_version = NULL; 113 free(desc->http_host); 114 desc->http_host = NULL; 115 116 kv_purge(&desc->http_headers); 117 desc->http_lastheader = NULL; 118 desc->http_method = 0; 119 desc->http_chunked = 0; 120 } 121 122 int 123 server_http_authenticate(struct server_config *srv_conf, struct client *clt) 124 { 125 char decoded[1024]; 126 FILE *fp = NULL; 127 struct http_descriptor *desc = clt->clt_descreq; 128 const struct auth *auth = srv_conf->auth; 129 struct kv *ba, key; 130 size_t linesize = 0; 131 ssize_t linelen; 132 int ret = -1; 133 char *line = NULL, *user = NULL, *pass = NULL; 134 char *clt_user = NULL, *clt_pass = NULL; 135 136 memset(decoded, 0, sizeof(decoded)); 137 key.kv_key = "Authorization"; 138 139 if ((ba = kv_find(&desc->http_headers, &key)) == NULL || 140 ba->kv_value == NULL) 141 goto done; 142 143 if (strncmp(ba->kv_value, "Basic ", strlen("Basic ")) != 0) 144 goto done; 145 146 if (b64_pton(strchr(ba->kv_value, ' ') + 1, (uint8_t *)decoded, 147 sizeof(decoded)) <= 0) 148 goto done; 149 150 if ((clt_pass = strchr(decoded, ':')) == NULL) 151 goto done; 152 153 clt_user = decoded; 154 *clt_pass++ = '\0'; 155 if ((clt->clt_remote_user = strdup(clt_user)) == NULL) 156 goto done; 157 158 if ((fp = fopen(auth->auth_htpasswd, "r")) == NULL) 159 goto done; 160 161 while ((linelen = getline(&line, &linesize, fp)) != -1) { 162 if (line[linelen - 1] == '\n') 163 line[linelen - 1] = '\0'; 164 user = line; 165 pass = strchr(line, ':'); 166 167 if (pass == NULL) { 168 explicit_bzero(line, linelen); 169 continue; 170 } 171 172 *pass++ = '\0'; 173 174 if (strcmp(clt_user, user) != 0) { 175 explicit_bzero(line, linelen); 176 continue; 177 } 178 179 if (crypt_checkpass(clt_pass, pass) == 0) { 180 explicit_bzero(line, linelen); 181 ret = 0; 182 break; 183 } 184 } 185 done: 186 free(line); 187 if (fp != NULL) 188 fclose(fp); 189 190 if (ba != NULL && ba->kv_value != NULL) { 191 explicit_bzero(ba->kv_value, strlen(ba->kv_value)); 192 explicit_bzero(decoded, sizeof(decoded)); 193 } 194 195 return (ret); 196 } 197 198 void 199 server_read_http(struct bufferevent *bev, void *arg) 200 { 201 struct client *clt = arg; 202 struct http_descriptor *desc = clt->clt_descreq; 203 struct evbuffer *src = EVBUFFER_INPUT(bev); 204 char *line = NULL, *key, *value; 205 const char *errstr; 206 size_t size, linelen; 207 struct kv *hdr = NULL; 208 209 getmonotime(&clt->clt_tv_last); 210 211 size = EVBUFFER_LENGTH(src); 212 DPRINTF("%s: session %d: size %lu, to read %lld", 213 __func__, clt->clt_id, size, clt->clt_toread); 214 if (!size) { 215 clt->clt_toread = TOREAD_HTTP_HEADER; 216 goto done; 217 } 218 219 while (!clt->clt_headersdone) { 220 if (!clt->clt_line) { 221 /* Peek into the buffer to see if it looks like HTTP */ 222 key = EVBUFFER_DATA(src); 223 if (!isalpha((unsigned char)*key)) { 224 server_abort_http(clt, 400, 225 "invalid request line"); 226 goto abort; 227 } 228 } 229 230 if ((line = evbuffer_readln(src, 231 &linelen, EVBUFFER_EOL_CRLF_STRICT)) == NULL) { 232 /* No newline found after too many bytes */ 233 if (size > SERVER_MAXHEADERLENGTH) { 234 server_abort_http(clt, 413, 235 "request line too long"); 236 goto abort; 237 } 238 break; 239 } 240 241 /* 242 * An empty line indicates the end of the request. 243 * libevent already stripped the \r\n for us. 244 */ 245 if (!linelen) { 246 clt->clt_headersdone = 1; 247 free(line); 248 break; 249 } 250 key = line; 251 252 /* Limit the total header length minus \r\n */ 253 clt->clt_headerlen += linelen; 254 if (clt->clt_headerlen > SERVER_MAXHEADERLENGTH) { 255 server_abort_http(clt, 413, "request too large"); 256 goto abort; 257 } 258 259 /* 260 * The first line is the GET/POST/PUT/... request, 261 * subsequent lines are HTTP headers. 262 */ 263 if (++clt->clt_line == 1) 264 value = strchr(key, ' '); 265 else if (*key == ' ' || *key == '\t') 266 /* Multiline headers wrap with a space or tab */ 267 value = NULL; 268 else 269 value = strchr(key, ':'); 270 if (value == NULL) { 271 if (clt->clt_line == 1) { 272 server_abort_http(clt, 400, "malformed"); 273 goto abort; 274 } 275 276 /* Append line to the last header, if present */ 277 if (kv_extend(&desc->http_headers, 278 desc->http_lastheader, line) == NULL) 279 goto fail; 280 281 free(line); 282 continue; 283 } 284 if (*value == ':') { 285 *value++ = '\0'; 286 value += strspn(value, " \t\r\n"); 287 } else { 288 *value++ = '\0'; 289 } 290 291 DPRINTF("%s: session %d: header '%s: %s'", __func__, 292 clt->clt_id, key, value); 293 294 /* 295 * Identify and handle specific HTTP request methods 296 */ 297 if (clt->clt_line == 1) { 298 if ((desc->http_method = server_httpmethod_byname(key)) 299 == HTTP_METHOD_NONE) { 300 server_abort_http(clt, 400, "malformed"); 301 goto abort; 302 } 303 304 /* 305 * Decode request path and query 306 */ 307 desc->http_path = strdup(value); 308 if (desc->http_path == NULL) 309 goto fail; 310 311 desc->http_version = strchr(desc->http_path, ' '); 312 if (desc->http_version == NULL) { 313 server_abort_http(clt, 400, "malformed"); 314 goto abort; 315 } 316 317 *desc->http_version++ = '\0'; 318 desc->http_query = strchr(desc->http_path, '?'); 319 if (desc->http_query != NULL) 320 *desc->http_query++ = '\0'; 321 322 /* 323 * Have to allocate the strings because they could 324 * be changed independently by the filters later. 325 */ 326 if ((desc->http_version = 327 strdup(desc->http_version)) == NULL) 328 goto fail; 329 330 if (desc->http_query != NULL && 331 (desc->http_query = 332 strdup(desc->http_query)) == NULL) 333 goto fail; 334 335 } else if (desc->http_method != HTTP_METHOD_NONE && 336 strcasecmp("Content-Length", key) == 0) { 337 if (desc->http_method == HTTP_METHOD_TRACE || 338 desc->http_method == HTTP_METHOD_CONNECT) { 339 /* 340 * These method should not have a body 341 * and thus no Content-Length header. 342 */ 343 server_abort_http(clt, 400, "malformed"); 344 goto abort; 345 } 346 347 /* 348 * Need to read data from the client after the 349 * HTTP header. 350 * XXX What about non-standard clients not using 351 * the carriage return? And some browsers seem to 352 * include the line length in the content-length. 353 */ 354 clt->clt_toread = strtonum(value, 0, LLONG_MAX, 355 &errstr); 356 if (errstr) { 357 server_abort_http(clt, 500, errstr); 358 goto abort; 359 } 360 } 361 362 if (strcasecmp("Transfer-Encoding", key) == 0 && 363 strcasecmp("chunked", value) == 0) 364 desc->http_chunked = 1; 365 366 if (clt->clt_line != 1) { 367 if ((hdr = kv_add(&desc->http_headers, key, 368 value)) == NULL) 369 goto fail; 370 371 desc->http_lastheader = hdr; 372 } 373 374 free(line); 375 } 376 if (clt->clt_headersdone) { 377 if (desc->http_method == HTTP_METHOD_NONE) { 378 server_abort_http(clt, 406, "no method"); 379 return; 380 } 381 382 switch (desc->http_method) { 383 case HTTP_METHOD_CONNECT: 384 /* Data stream */ 385 clt->clt_toread = TOREAD_UNLIMITED; 386 bev->readcb = server_read; 387 break; 388 case HTTP_METHOD_GET: 389 case HTTP_METHOD_HEAD: 390 /* WebDAV methods */ 391 case HTTP_METHOD_COPY: 392 case HTTP_METHOD_MOVE: 393 clt->clt_toread = 0; 394 break; 395 case HTTP_METHOD_DELETE: 396 case HTTP_METHOD_OPTIONS: 397 case HTTP_METHOD_POST: 398 case HTTP_METHOD_PUT: 399 case HTTP_METHOD_RESPONSE: 400 /* WebDAV methods */ 401 case HTTP_METHOD_PROPFIND: 402 case HTTP_METHOD_PROPPATCH: 403 case HTTP_METHOD_MKCOL: 404 case HTTP_METHOD_LOCK: 405 case HTTP_METHOD_UNLOCK: 406 case HTTP_METHOD_VERSION_CONTROL: 407 case HTTP_METHOD_REPORT: 408 case HTTP_METHOD_CHECKOUT: 409 case HTTP_METHOD_CHECKIN: 410 case HTTP_METHOD_UNCHECKOUT: 411 case HTTP_METHOD_MKWORKSPACE: 412 case HTTP_METHOD_UPDATE: 413 case HTTP_METHOD_LABEL: 414 case HTTP_METHOD_MERGE: 415 case HTTP_METHOD_BASELINE_CONTROL: 416 case HTTP_METHOD_MKACTIVITY: 417 case HTTP_METHOD_ORDERPATCH: 418 case HTTP_METHOD_ACL: 419 case HTTP_METHOD_MKREDIRECTREF: 420 case HTTP_METHOD_UPDATEREDIRECTREF: 421 case HTTP_METHOD_SEARCH: 422 case HTTP_METHOD_PATCH: 423 /* HTTP request payload */ 424 if (clt->clt_toread > 0) 425 bev->readcb = server_read_httpcontent; 426 427 /* Single-pass HTTP body */ 428 if (clt->clt_toread < 0) { 429 clt->clt_toread = TOREAD_UNLIMITED; 430 bev->readcb = server_read; 431 } 432 break; 433 default: 434 server_abort_http(clt, 405, "method not allowed"); 435 return; 436 } 437 if (desc->http_chunked) { 438 /* Chunked transfer encoding */ 439 clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH; 440 bev->readcb = server_read_httpchunks; 441 } 442 443 done: 444 if (clt->clt_toread != 0) 445 bufferevent_disable(bev, EV_READ); 446 server_response(httpd_env, clt); 447 return; 448 } 449 if (clt->clt_done) { 450 server_close(clt, "done"); 451 return; 452 } 453 if (EVBUFFER_LENGTH(src) && bev->readcb != server_read_http) 454 bev->readcb(bev, arg); 455 bufferevent_enable(bev, EV_READ); 456 return; 457 fail: 458 server_abort_http(clt, 500, strerror(errno)); 459 abort: 460 free(line); 461 } 462 463 void 464 server_read_httpcontent(struct bufferevent *bev, void *arg) 465 { 466 struct client *clt = arg; 467 struct evbuffer *src = EVBUFFER_INPUT(bev); 468 size_t size; 469 470 getmonotime(&clt->clt_tv_last); 471 472 size = EVBUFFER_LENGTH(src); 473 DPRINTF("%s: session %d: size %lu, to read %lld", __func__, 474 clt->clt_id, size, clt->clt_toread); 475 if (!size) 476 return; 477 478 if (clt->clt_toread > 0) { 479 /* Read content data */ 480 if ((off_t)size > clt->clt_toread) { 481 size = clt->clt_toread; 482 if (fcgi_add_stdin(clt, src) == -1) 483 goto fail; 484 clt->clt_toread = 0; 485 } else { 486 if (fcgi_add_stdin(clt, src) == -1) 487 goto fail; 488 clt->clt_toread -= size; 489 } 490 DPRINTF("%s: done, size %lu, to read %lld", __func__, 491 size, clt->clt_toread); 492 } 493 if (clt->clt_toread == 0) { 494 fcgi_add_stdin(clt, NULL); 495 clt->clt_toread = TOREAD_HTTP_HEADER; 496 bufferevent_disable(bev, EV_READ); 497 bev->readcb = server_read_http; 498 return; 499 } 500 if (clt->clt_done) 501 goto done; 502 if (bev->readcb != server_read_httpcontent) 503 bev->readcb(bev, arg); 504 505 return; 506 done: 507 return; 508 fail: 509 server_close(clt, strerror(errno)); 510 } 511 512 void 513 server_read_httpchunks(struct bufferevent *bev, void *arg) 514 { 515 struct client *clt = arg; 516 struct evbuffer *src = EVBUFFER_INPUT(bev); 517 char *line; 518 long long llval; 519 size_t size; 520 521 getmonotime(&clt->clt_tv_last); 522 523 size = EVBUFFER_LENGTH(src); 524 DPRINTF("%s: session %d: size %lu, to read %lld", __func__, 525 clt->clt_id, size, clt->clt_toread); 526 if (!size) 527 return; 528 529 if (clt->clt_toread > 0) { 530 /* Read chunk data */ 531 if ((off_t)size > clt->clt_toread) { 532 size = clt->clt_toread; 533 if (server_bufferevent_write_chunk(clt, src, size) 534 == -1) 535 goto fail; 536 clt->clt_toread = 0; 537 } else { 538 if (server_bufferevent_write_buffer(clt, src) == -1) 539 goto fail; 540 clt->clt_toread -= size; 541 } 542 DPRINTF("%s: done, size %lu, to read %lld", __func__, 543 size, clt->clt_toread); 544 } 545 switch (clt->clt_toread) { 546 case TOREAD_HTTP_CHUNK_LENGTH: 547 line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); 548 if (line == NULL) { 549 /* Ignore empty line, continue */ 550 bufferevent_enable(bev, EV_READ); 551 return; 552 } 553 if (strlen(line) == 0) { 554 free(line); 555 goto next; 556 } 557 558 /* 559 * Read prepended chunk size in hex, ignore the trailer. 560 * The returned signed value must not be negative. 561 */ 562 if (sscanf(line, "%llx", &llval) != 1 || llval < 0) { 563 free(line); 564 server_close(clt, "invalid chunk size"); 565 return; 566 } 567 568 if (server_bufferevent_print(clt, line) == -1 || 569 server_bufferevent_print(clt, "\r\n") == -1) { 570 free(line); 571 goto fail; 572 } 573 free(line); 574 575 if ((clt->clt_toread = llval) == 0) { 576 DPRINTF("%s: last chunk", __func__); 577 clt->clt_toread = TOREAD_HTTP_CHUNK_TRAILER; 578 } 579 break; 580 case TOREAD_HTTP_CHUNK_TRAILER: 581 /* Last chunk is 0 bytes followed by trailer and empty line */ 582 line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); 583 if (line == NULL) { 584 /* Ignore empty line, continue */ 585 bufferevent_enable(bev, EV_READ); 586 return; 587 } 588 if (server_bufferevent_print(clt, line) == -1 || 589 server_bufferevent_print(clt, "\r\n") == -1) { 590 free(line); 591 goto fail; 592 } 593 if (strlen(line) == 0) { 594 /* Switch to HTTP header mode */ 595 clt->clt_toread = TOREAD_HTTP_HEADER; 596 bev->readcb = server_read_http; 597 } 598 free(line); 599 break; 600 case 0: 601 /* Chunk is terminated by an empty newline */ 602 line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); 603 free(line); 604 if (server_bufferevent_print(clt, "\r\n") == -1) 605 goto fail; 606 clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH; 607 break; 608 } 609 610 next: 611 if (clt->clt_done) 612 goto done; 613 if (EVBUFFER_LENGTH(src)) 614 bev->readcb(bev, arg); 615 bufferevent_enable(bev, EV_READ); 616 return; 617 618 done: 619 server_close(clt, "last http chunk read (done)"); 620 return; 621 fail: 622 server_close(clt, strerror(errno)); 623 } 624 625 void 626 server_read_httprange(struct bufferevent *bev, void *arg) 627 { 628 struct client *clt = arg; 629 struct evbuffer *src = EVBUFFER_INPUT(bev); 630 size_t size; 631 struct media_type *media; 632 struct range_data *r = &clt->clt_ranges; 633 struct range *range; 634 635 getmonotime(&clt->clt_tv_last); 636 637 if (r->range_toread > 0) { 638 size = EVBUFFER_LENGTH(src); 639 if (!size) 640 return; 641 642 /* Read chunk data */ 643 if ((off_t)size > r->range_toread) { 644 size = r->range_toread; 645 if (server_bufferevent_write_chunk(clt, src, size) 646 == -1) 647 goto fail; 648 r->range_toread = 0; 649 } else { 650 if (server_bufferevent_write_buffer(clt, src) == -1) 651 goto fail; 652 r->range_toread -= size; 653 } 654 if (r->range_toread < 1) 655 r->range_toread = TOREAD_HTTP_RANGE; 656 DPRINTF("%s: done, size %lu, to read %lld", __func__, 657 size, r->range_toread); 658 } 659 660 switch (r->range_toread) { 661 case TOREAD_HTTP_RANGE: 662 if (r->range_index >= r->range_count) { 663 if (r->range_count > 1) { 664 /* Add end marker */ 665 if (server_bufferevent_printf(clt, 666 "\r\n--%llu--\r\n", 667 clt->clt_boundary) == -1) 668 goto fail; 669 } 670 r->range_toread = TOREAD_HTTP_NONE; 671 break; 672 } 673 674 range = &r->range[r->range_index]; 675 676 if (r->range_count > 1) { 677 media = r->range_media; 678 if (server_bufferevent_printf(clt, 679 "\r\n--%llu\r\n" 680 "Content-Type: %s/%s\r\n" 681 "Content-Range: bytes %lld-%lld/%zu\r\n\r\n", 682 clt->clt_boundary, 683 media->media_type, media->media_subtype, 684 range->start, range->end, r->range_total) == -1) 685 goto fail; 686 } 687 r->range_toread = range->end - range->start + 1; 688 689 if (lseek(clt->clt_fd, range->start, SEEK_SET) == -1) 690 goto fail; 691 692 /* Throw away bytes that are already in the input buffer */ 693 evbuffer_drain(src, EVBUFFER_LENGTH(src)); 694 695 /* Increment for the next part */ 696 r->range_index++; 697 break; 698 case TOREAD_HTTP_NONE: 699 goto done; 700 case 0: 701 break; 702 } 703 704 if (clt->clt_done) 705 goto done; 706 707 if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t) 708 SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) { 709 bufferevent_disable(clt->clt_srvbev, EV_READ); 710 clt->clt_srvbev_throttled = 1; 711 } 712 713 return; 714 done: 715 (*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg); 716 return; 717 fail: 718 server_close(clt, strerror(errno)); 719 } 720 721 void 722 server_reset_http(struct client *clt) 723 { 724 struct server *srv = clt->clt_srv; 725 726 server_log(clt, NULL); 727 728 server_httpdesc_free(clt->clt_descreq); 729 server_httpdesc_free(clt->clt_descresp); 730 clt->clt_headerlen = 0; 731 clt->clt_headersdone = 0; 732 clt->clt_done = 0; 733 clt->clt_line = 0; 734 clt->clt_chunk = 0; 735 free(clt->clt_remote_user); 736 clt->clt_remote_user = NULL; 737 clt->clt_bev->readcb = server_read_http; 738 clt->clt_srv_conf = &srv->srv_conf; 739 str_match_free(&clt->clt_srv_match); 740 } 741 742 ssize_t 743 server_http_time(time_t t, char *tmbuf, size_t len) 744 { 745 struct tm tm; 746 747 /* New HTTP/1.1 RFC 7231 prefers IMF-fixdate from RFC 5322 */ 748 if (t == -1 || gmtime_r(&t, &tm) == NULL) 749 return (-1); 750 else 751 return (strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm)); 752 } 753 754 const char * 755 server_http_host(struct sockaddr_storage *ss, char *buf, size_t len) 756 { 757 char hbuf[HOST_NAME_MAX+1]; 758 in_port_t port; 759 760 if (print_host(ss, buf, len) == NULL) 761 return (NULL); 762 763 port = ntohs(server_socket_getport(ss)); 764 if (port == HTTP_PORT) 765 return (buf); 766 767 switch (ss->ss_family) { 768 case AF_INET: 769 if ((size_t)snprintf(hbuf, sizeof(hbuf), 770 "%s:%u", buf, port) >= sizeof(hbuf)) 771 return (NULL); 772 break; 773 case AF_INET6: 774 if ((size_t)snprintf(hbuf, sizeof(hbuf), 775 "[%s]:%u", buf, port) >= sizeof(hbuf)) 776 return (NULL); 777 break; 778 } 779 780 if (strlcpy(buf, hbuf, len) >= len) 781 return (NULL); 782 783 return (buf); 784 } 785 786 char * 787 server_http_parsehost(char *host, char *buf, size_t len, int *portval) 788 { 789 char *start, *end, *port; 790 const char *errstr = NULL; 791 792 if (strlcpy(buf, host, len) >= len) { 793 log_debug("%s: host name too long", __func__); 794 return (NULL); 795 } 796 797 start = buf; 798 end = port = NULL; 799 800 if (*start == '[' && (end = strchr(start, ']')) != NULL) { 801 /* Address enclosed in [] with port, eg. [2001:db8::1]:80 */ 802 start++; 803 *end++ = '\0'; 804 if ((port = strchr(end, ':')) == NULL || *port == '\0') 805 port = NULL; 806 else 807 port++; 808 memmove(buf, start, strlen(start) + 1); 809 } else if ((end = strchr(start, ':')) != NULL) { 810 /* Name or address with port, eg. www.example.com:80 */ 811 *end++ = '\0'; 812 port = end; 813 } else { 814 /* Name or address with default port, eg. www.example.com */ 815 port = NULL; 816 } 817 818 if (port != NULL) { 819 /* Save the requested port */ 820 *portval = strtonum(port, 0, 0xffff, &errstr); 821 if (errstr != NULL) { 822 log_debug("%s: invalid port: %s", __func__, 823 strerror(errno)); 824 return (NULL); 825 } 826 *portval = htons(*portval); 827 } else { 828 /* Port not given, indicate the default port */ 829 *portval = -1; 830 } 831 832 return (start); 833 } 834 835 void 836 server_abort_http(struct client *clt, unsigned int code, const char *msg) 837 { 838 struct server_config *srv_conf = clt->clt_srv_conf; 839 struct bufferevent *bev = clt->clt_bev; 840 struct http_descriptor *desc = clt->clt_descreq; 841 const char *httperr = NULL, *style; 842 char *httpmsg, *body = NULL, *extraheader = NULL; 843 char tmbuf[32], hbuf[128], *hstsheader = NULL; 844 char *clenheader = NULL; 845 char buf[IBUF_READ_SIZE]; 846 char *escapedmsg = NULL; 847 int bodylen; 848 849 if (code == 0) { 850 server_close(clt, "dropped"); 851 return; 852 } 853 854 if ((httperr = server_httperror_byid(code)) == NULL) 855 httperr = "Unknown Error"; 856 857 if (bev == NULL) 858 goto done; 859 860 if (server_log_http(clt, code, 0) == -1) 861 goto done; 862 863 /* Some system information */ 864 if (print_host(&srv_conf->ss, hbuf, sizeof(hbuf)) == NULL) 865 goto done; 866 867 if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0) 868 goto done; 869 870 /* Do not send details of the Internal Server Error */ 871 switch (code) { 872 case 301: 873 case 302: 874 case 303: 875 case 307: 876 case 308: 877 if (msg == NULL) 878 break; 879 memset(buf, 0, sizeof(buf)); 880 if (server_expand_http(clt, msg, buf, sizeof(buf)) == NULL) 881 goto done; 882 if (asprintf(&extraheader, "Location: %s\r\n", buf) == -1) { 883 code = 500; 884 extraheader = NULL; 885 } 886 msg = buf; 887 break; 888 case 401: 889 if (msg == NULL) 890 break; 891 if (stravis(&escapedmsg, msg, VIS_DQ) == -1) { 892 code = 500; 893 extraheader = NULL; 894 } else if (asprintf(&extraheader, 895 "WWW-Authenticate: Basic realm=\"%s\"\r\n", escapedmsg) 896 == -1) { 897 code = 500; 898 extraheader = NULL; 899 } 900 break; 901 case 416: 902 if (msg == NULL) 903 break; 904 if (asprintf(&extraheader, 905 "Content-Range: %s\r\n", msg) == -1) { 906 code = 500; 907 extraheader = NULL; 908 } 909 break; 910 default: 911 /* 912 * Do not send details of the error. Traditionally, 913 * web servers responsed with the request path on 40x 914 * errors which could be abused to inject JavaScript etc. 915 * Instead of sanitizing the path here, we just don't 916 * reprint it. 917 */ 918 break; 919 } 920 921 free(escapedmsg); 922 923 /* A CSS stylesheet allows minimal customization by the user */ 924 style = "body { background-color: white; color: black; font-family: " 925 "'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }\n" 926 "hr { border: 0; border-bottom: 1px dashed; }\n" 927 "@media (prefers-color-scheme: dark) {\n" 928 "body { background-color: #1E1F21; color: #EEEFF1; }\n" 929 "a { color: #BAD7FF; }\n}"; 930 931 /* Generate simple HTML error document */ 932 if ((bodylen = asprintf(&body, 933 "<!DOCTYPE html>\n" 934 "<html>\n" 935 "<head>\n" 936 "<meta charset=\"utf-8\">\n" 937 "<title>%03d %s</title>\n" 938 "<style type=\"text/css\"><!--\n%s\n--></style>\n" 939 "</head>\n" 940 "<body>\n" 941 "<h1>%03d %s</h1>\n" 942 "<hr>\n<address>%s</address>\n" 943 "</body>\n" 944 "</html>\n", 945 code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) { 946 body = NULL; 947 goto done; 948 } 949 950 if (srv_conf->flags & SRVFLAG_SERVER_HSTS && 951 srv_conf->flags & SRVFLAG_TLS) { 952 if (asprintf(&hstsheader, "Strict-Transport-Security: " 953 "max-age=%d%s%s\r\n", srv_conf->hsts_max_age, 954 srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ? 955 "; includeSubDomains" : "", 956 srv_conf->hsts_flags & HSTSFLAG_PRELOAD ? 957 "; preload" : "") == -1) { 958 hstsheader = NULL; 959 goto done; 960 } 961 } 962 963 if ((code >= 100 && code < 200) || code == 204) 964 clenheader = NULL; 965 else { 966 if (asprintf(&clenheader, 967 "Content-Length: %d\r\n", bodylen) == -1) { 968 clenheader = NULL; 969 goto done; 970 } 971 } 972 973 /* Add basic HTTP headers */ 974 if (asprintf(&httpmsg, 975 "HTTP/1.0 %03d %s\r\n" 976 "Date: %s\r\n" 977 "Server: %s\r\n" 978 "Connection: close\r\n" 979 "Content-Type: text/html\r\n" 980 "%s" 981 "%s" 982 "%s" 983 "\r\n" 984 "%s", 985 code, httperr, tmbuf, HTTPD_SERVERNAME, 986 clenheader == NULL ? "" : clenheader, 987 extraheader == NULL ? "" : extraheader, 988 hstsheader == NULL ? "" : hstsheader, 989 desc->http_method == HTTP_METHOD_HEAD || clenheader == NULL ? 990 "" : body) == -1) 991 goto done; 992 993 /* Dump the message without checking for success */ 994 server_dump(clt, httpmsg, strlen(httpmsg)); 995 free(httpmsg); 996 997 done: 998 free(body); 999 free(extraheader); 1000 free(hstsheader); 1001 free(clenheader); 1002 if (msg == NULL) 1003 msg = "\"\""; 1004 if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) { 1005 server_close(clt, msg); 1006 } else { 1007 server_close(clt, httpmsg); 1008 free(httpmsg); 1009 } 1010 } 1011 1012 void 1013 server_close_http(struct client *clt) 1014 { 1015 struct http_descriptor *desc; 1016 1017 desc = clt->clt_descreq; 1018 server_httpdesc_free(desc); 1019 free(desc); 1020 clt->clt_descreq = NULL; 1021 1022 desc = clt->clt_descresp; 1023 server_httpdesc_free(desc); 1024 free(desc); 1025 clt->clt_descresp = NULL; 1026 free(clt->clt_remote_user); 1027 clt->clt_remote_user = NULL; 1028 1029 str_match_free(&clt->clt_srv_match); 1030 } 1031 1032 char * 1033 server_expand_http(struct client *clt, const char *val, char *buf, 1034 size_t len) 1035 { 1036 struct http_descriptor *desc = clt->clt_descreq; 1037 struct server_config *srv_conf = clt->clt_srv_conf; 1038 char ibuf[128], *str, *path, *query; 1039 const char *errstr = NULL, *p; 1040 size_t size; 1041 int n, ret; 1042 1043 if (strlcpy(buf, val, len) >= len) 1044 return (NULL); 1045 1046 /* Find previously matched substrings by index */ 1047 for (p = val; clt->clt_srv_match.sm_nmatch && 1048 (p = strstr(p, "%")) != NULL; p++) { 1049 if (!isdigit((unsigned char)*(p + 1))) 1050 continue; 1051 1052 /* Copy number, leading '%' char and add trailing \0 */ 1053 size = strspn(p + 1, "0123456789") + 2; 1054 if (size >= sizeof(ibuf)) 1055 return (NULL); 1056 (void)strlcpy(ibuf, p, size); 1057 n = strtonum(ibuf + 1, 0, 1058 clt->clt_srv_match.sm_nmatch - 1, &errstr); 1059 if (errstr != NULL) 1060 return (NULL); 1061 1062 /* Expand variable with matched value */ 1063 if ((str = url_encode(clt->clt_srv_match.sm_match[n])) == NULL) 1064 return (NULL); 1065 ret = expand_string(buf, len, ibuf, str); 1066 free(str); 1067 if (ret != 0) 1068 return (NULL); 1069 } 1070 if (strstr(val, "$DOCUMENT_URI") != NULL) { 1071 if ((path = url_encode(desc->http_path)) == NULL) 1072 return (NULL); 1073 ret = expand_string(buf, len, "$DOCUMENT_URI", path); 1074 free(path); 1075 if (ret != 0) 1076 return (NULL); 1077 } 1078 if (strstr(val, "$QUERY_STRING_ENC") != NULL) { 1079 if (desc->http_query == NULL) { 1080 ret = expand_string(buf, len, "$QUERY_STRING_ENC", ""); 1081 } else { 1082 if ((query = url_encode(desc->http_query)) == NULL) 1083 return (NULL); 1084 ret = expand_string(buf, len, "$QUERY_STRING_ENC", query); 1085 free(query); 1086 } 1087 if (ret != 0) 1088 return (NULL); 1089 } 1090 if (strstr(val, "$QUERY_STRING") != NULL) { 1091 if (desc->http_query == NULL) { 1092 ret = expand_string(buf, len, "$QUERY_STRING", ""); 1093 } else { 1094 ret = expand_string(buf, len, "$QUERY_STRING", 1095 desc->http_query); 1096 } 1097 if (ret != 0) 1098 return (NULL); 1099 } 1100 if (strstr(val, "$HTTP_HOST") != NULL) { 1101 if (desc->http_host == NULL) 1102 return (NULL); 1103 if ((str = url_encode(desc->http_host)) == NULL) 1104 return (NULL); 1105 expand_string(buf, len, "$HTTP_HOST", str); 1106 free(str); 1107 } 1108 if (strstr(val, "$REMOTE_") != NULL) { 1109 if (strstr(val, "$REMOTE_ADDR") != NULL) { 1110 if (print_host(&clt->clt_ss, 1111 ibuf, sizeof(ibuf)) == NULL) 1112 return (NULL); 1113 if (expand_string(buf, len, 1114 "$REMOTE_ADDR", ibuf) != 0) 1115 return (NULL); 1116 } 1117 if (strstr(val, "$REMOTE_PORT") != NULL) { 1118 snprintf(ibuf, sizeof(ibuf), 1119 "%u", ntohs(clt->clt_port)); 1120 if (expand_string(buf, len, 1121 "$REMOTE_PORT", ibuf) != 0) 1122 return (NULL); 1123 } 1124 if (strstr(val, "$REMOTE_USER") != NULL) { 1125 if ((srv_conf->flags & SRVFLAG_AUTH) && 1126 clt->clt_remote_user != NULL) { 1127 if ((str = url_encode(clt->clt_remote_user)) 1128 == NULL) 1129 return (NULL); 1130 } else 1131 str = strdup(""); 1132 ret = expand_string(buf, len, "$REMOTE_USER", str); 1133 free(str); 1134 if (ret != 0) 1135 return (NULL); 1136 } 1137 } 1138 if (strstr(val, "$REQUEST_URI") != NULL) { 1139 if ((path = url_encode(desc->http_path)) == NULL) 1140 return (NULL); 1141 if (desc->http_query == NULL) { 1142 str = path; 1143 } else { 1144 ret = asprintf(&str, "%s?%s", path, desc->http_query); 1145 free(path); 1146 if (ret == -1) 1147 return (NULL); 1148 } 1149 1150 ret = expand_string(buf, len, "$REQUEST_URI", str); 1151 free(str); 1152 if (ret != 0) 1153 return (NULL); 1154 } 1155 if (strstr(val, "$REQUEST_SCHEME") != NULL) { 1156 if (srv_conf->flags & SRVFLAG_TLS) { 1157 ret = expand_string(buf, len, "$REQUEST_SCHEME", "https"); 1158 } else { 1159 ret = expand_string(buf, len, "$REQUEST_SCHEME", "http"); 1160 } 1161 if (ret != 0) 1162 return (NULL); 1163 } 1164 if (strstr(val, "$SERVER_") != NULL) { 1165 if (strstr(val, "$SERVER_ADDR") != NULL) { 1166 if (print_host(&srv_conf->ss, 1167 ibuf, sizeof(ibuf)) == NULL) 1168 return (NULL); 1169 if (expand_string(buf, len, 1170 "$SERVER_ADDR", ibuf) != 0) 1171 return (NULL); 1172 } 1173 if (strstr(val, "$SERVER_PORT") != NULL) { 1174 snprintf(ibuf, sizeof(ibuf), "%u", 1175 ntohs(srv_conf->port)); 1176 if (expand_string(buf, len, 1177 "$SERVER_PORT", ibuf) != 0) 1178 return (NULL); 1179 } 1180 if (strstr(val, "$SERVER_NAME") != NULL) { 1181 if ((str = url_encode(srv_conf->name)) 1182 == NULL) 1183 return (NULL); 1184 ret = expand_string(buf, len, "$SERVER_NAME", str); 1185 free(str); 1186 if (ret != 0) 1187 return (NULL); 1188 } 1189 } 1190 1191 return (buf); 1192 } 1193 1194 int 1195 server_response(struct httpd *httpd, struct client *clt) 1196 { 1197 char path[PATH_MAX]; 1198 char hostname[HOST_NAME_MAX+1]; 1199 struct http_descriptor *desc = clt->clt_descreq; 1200 struct http_descriptor *resp = clt->clt_descresp; 1201 struct server *srv = clt->clt_srv; 1202 struct server_config *srv_conf = &srv->srv_conf; 1203 struct kv *kv, key, *host; 1204 struct str_find sm; 1205 int portval = -1, ret; 1206 char *hostval, *query; 1207 const char *errstr = NULL; 1208 1209 /* Preserve original path */ 1210 if (desc->http_path == NULL || 1211 (desc->http_path_orig = strdup(desc->http_path)) == NULL) 1212 goto fail; 1213 1214 /* Decode the URL */ 1215 if (url_decode(desc->http_path) == NULL) 1216 goto fail; 1217 1218 /* Canonicalize the request path */ 1219 if (canonicalize_path(desc->http_path, path, sizeof(path)) == NULL) 1220 goto fail; 1221 free(desc->http_path); 1222 if ((desc->http_path = strdup(path)) == NULL) 1223 goto fail; 1224 1225 key.kv_key = "Host"; 1226 if ((host = kv_find(&desc->http_headers, &key)) != NULL && 1227 host->kv_value == NULL) 1228 host = NULL; 1229 1230 if (strcmp(desc->http_version, "HTTP/1.1") == 0) { 1231 /* Host header is mandatory */ 1232 if (host == NULL) 1233 goto fail; 1234 1235 /* Is the connection persistent? */ 1236 key.kv_key = "Connection"; 1237 if ((kv = kv_find(&desc->http_headers, &key)) != NULL && 1238 strcasecmp("close", kv->kv_value) == 0) 1239 clt->clt_persist = 0; 1240 else 1241 clt->clt_persist++; 1242 } else { 1243 /* Is the connection persistent? */ 1244 key.kv_key = "Connection"; 1245 if ((kv = kv_find(&desc->http_headers, &key)) != NULL && 1246 strcasecmp("keep-alive", kv->kv_value) == 0) 1247 clt->clt_persist++; 1248 else 1249 clt->clt_persist = 0; 1250 } 1251 1252 /* 1253 * Do we have a Host header and matching configuration? 1254 * XXX the Host can also appear in the URL path. 1255 */ 1256 if (host != NULL) { 1257 if ((hostval = server_http_parsehost(host->kv_value, 1258 hostname, sizeof(hostname), &portval)) == NULL) 1259 goto fail; 1260 1261 TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) { 1262 #ifdef DEBUG 1263 if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) { 1264 DPRINTF("%s: virtual host \"%s:%u\"" 1265 " host \"%s\" (\"%s\")", 1266 __func__, srv_conf->name, 1267 ntohs(srv_conf->port), host->kv_value, 1268 hostname); 1269 } 1270 #endif 1271 if (srv_conf->flags & SRVFLAG_LOCATION) 1272 continue; 1273 else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) { 1274 str_find(hostname, srv_conf->name, 1275 &sm, 1, &errstr); 1276 ret = errstr == NULL ? 0 : -1; 1277 } else { 1278 ret = fnmatch(srv_conf->name, 1279 hostname, FNM_CASEFOLD); 1280 } 1281 if (ret == 0 && 1282 (portval == -1 || portval == srv_conf->port)) { 1283 /* Replace host configuration */ 1284 clt->clt_srv_conf = srv_conf; 1285 srv_conf = NULL; 1286 break; 1287 } 1288 } 1289 } 1290 1291 if (srv_conf != NULL) { 1292 /* Use the actual server IP address */ 1293 if (server_http_host(&clt->clt_srv_ss, hostname, 1294 sizeof(hostname)) == NULL) 1295 goto fail; 1296 } else { 1297 /* Host header was valid and found */ 1298 if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >= 1299 sizeof(hostname)) 1300 goto fail; 1301 srv_conf = clt->clt_srv_conf; 1302 } 1303 1304 if (clt->clt_persist >= srv_conf->maxrequests) 1305 clt->clt_persist = 0; 1306 1307 /* pipelining should end after the first "idempotent" method */ 1308 if (clt->clt_pipelining && clt->clt_toread > 0) 1309 clt->clt_persist = 0; 1310 1311 if ((desc->http_host = strdup(hostname)) == NULL) 1312 goto fail; 1313 1314 /* Now fill in the mandatory parts of the response descriptor */ 1315 resp->http_method = desc->http_method; 1316 if ((resp->http_version = strdup(desc->http_version)) == NULL) 1317 goto fail; 1318 1319 /* Now search for the location */ 1320 srv_conf = server_getlocation(clt, desc->http_path); 1321 1322 /* Optional rewrite */ 1323 if (srv_conf->flags & SRVFLAG_PATH_REWRITE) { 1324 /* Expand macros */ 1325 if (server_expand_http(clt, srv_conf->path, 1326 path, sizeof(path)) == NULL) 1327 goto fail; 1328 1329 /* 1330 * Reset and update the query. The updated query must already 1331 * be URL encoded - either specified by the user or by using the 1332 * original $QUERY_STRING. 1333 */ 1334 free(desc->http_query_alias); 1335 desc->http_query_alias = NULL; 1336 if ((query = strchr(path, '?')) != NULL) { 1337 *query++ = '\0'; 1338 if ((desc->http_query_alias = strdup(query)) == NULL) 1339 goto fail; 1340 } 1341 1342 /* Canonicalize the updated request path */ 1343 if (canonicalize_path(path, 1344 path, sizeof(path)) == NULL) 1345 goto fail; 1346 1347 log_debug("%s: rewrote %s?%s -> %s?%s", __func__, 1348 desc->http_path, desc->http_query ? desc->http_query : "", 1349 path, query ? query : ""); 1350 1351 free(desc->http_path_alias); 1352 if ((desc->http_path_alias = strdup(path)) == NULL) 1353 goto fail; 1354 1355 /* Now search for the updated location */ 1356 srv_conf = server_getlocation(clt, desc->http_path_alias); 1357 } 1358 1359 if (clt->clt_toread > 0 && (size_t)clt->clt_toread > 1360 srv_conf->maxrequestbody) { 1361 server_abort_http(clt, 413, NULL); 1362 return (-1); 1363 } 1364 1365 if (srv_conf->flags & SRVFLAG_BLOCK) { 1366 server_abort_http(clt, srv_conf->return_code, 1367 srv_conf->return_uri); 1368 return (-1); 1369 } else if (srv_conf->flags & SRVFLAG_AUTH && 1370 server_http_authenticate(srv_conf, clt) == -1) { 1371 server_abort_http(clt, 401, srv_conf->auth_realm); 1372 return (-1); 1373 } else 1374 return (server_file(httpd, clt)); 1375 fail: 1376 server_abort_http(clt, 400, "bad request"); 1377 return (-1); 1378 } 1379 1380 const char * 1381 server_root_strip(const char *path, int n) 1382 { 1383 const char *p; 1384 1385 /* Strip strip leading directories. Leading '/' is ignored. */ 1386 for (; n > 0 && *path != '\0'; n--) 1387 if ((p = strchr(++path, '/')) == NULL) 1388 path = strchr(path, '\0'); 1389 else 1390 path = p; 1391 1392 return (path); 1393 } 1394 1395 struct server_config * 1396 server_getlocation(struct client *clt, const char *path) 1397 { 1398 struct server *srv = clt->clt_srv; 1399 struct server_config *srv_conf = clt->clt_srv_conf, *location; 1400 const char *errstr = NULL; 1401 int ret; 1402 1403 /* Now search for the location */ 1404 TAILQ_FOREACH(location, &srv->srv_hosts, entry) { 1405 #ifdef DEBUG 1406 if (location->flags & SRVFLAG_LOCATION) { 1407 DPRINTF("%s: location \"%s\" path \"%s\"", 1408 __func__, location->location, path); 1409 } 1410 #endif 1411 if ((location->flags & SRVFLAG_LOCATION) && 1412 location->parent_id == srv_conf->parent_id) { 1413 errstr = NULL; 1414 if (location->flags & SRVFLAG_LOCATION_MATCH) { 1415 ret = str_match(path, location->location, 1416 &clt->clt_srv_match, &errstr); 1417 } else { 1418 ret = fnmatch(location->location, 1419 path, FNM_CASEFOLD); 1420 } 1421 if (ret == 0 && errstr == NULL) { 1422 /* Replace host configuration */ 1423 clt->clt_srv_conf = srv_conf = location; 1424 break; 1425 } 1426 } 1427 } 1428 1429 return (srv_conf); 1430 } 1431 1432 int 1433 server_response_http(struct client *clt, unsigned int code, 1434 struct media_type *media, off_t size, time_t mtime) 1435 { 1436 struct server_config *srv_conf = clt->clt_srv_conf; 1437 struct http_descriptor *desc = clt->clt_descreq; 1438 struct http_descriptor *resp = clt->clt_descresp; 1439 const char *error; 1440 struct kv *ct, *cl; 1441 char tmbuf[32]; 1442 1443 if (desc == NULL || media == NULL || 1444 (error = server_httperror_byid(code)) == NULL) 1445 return (-1); 1446 1447 if (server_log_http(clt, code, size >= 0 ? size : 0) == -1) 1448 return (-1); 1449 1450 /* Add error codes */ 1451 if (kv_setkey(&resp->http_pathquery, "%u", code) == -1 || 1452 kv_set(&resp->http_pathquery, "%s", error) == -1) 1453 return (-1); 1454 1455 /* Add headers */ 1456 if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL) 1457 return (-1); 1458 1459 /* Is it a persistent connection? */ 1460 if (clt->clt_persist) { 1461 if (kv_add(&resp->http_headers, 1462 "Connection", "keep-alive") == NULL) 1463 return (-1); 1464 } else if (kv_add(&resp->http_headers, "Connection", "close") == NULL) 1465 return (-1); 1466 1467 /* Set media type */ 1468 if ((ct = kv_add(&resp->http_headers, "Content-Type", NULL)) == NULL || 1469 kv_set(ct, "%s/%s", media->media_type, media->media_subtype) == -1) 1470 return (-1); 1471 1472 /* Set content length, if specified */ 1473 if (size >= 0 && ((cl = 1474 kv_add(&resp->http_headers, "Content-Length", NULL)) == NULL || 1475 kv_set(cl, "%lld", (long long)size) == -1)) 1476 return (-1); 1477 1478 /* Set last modification time */ 1479 if (server_http_time(mtime, tmbuf, sizeof(tmbuf)) <= 0 || 1480 kv_add(&resp->http_headers, "Last-Modified", tmbuf) == NULL) 1481 return (-1); 1482 1483 /* HSTS header */ 1484 if (srv_conf->flags & SRVFLAG_SERVER_HSTS && 1485 srv_conf->flags & SRVFLAG_TLS) { 1486 if ((cl = 1487 kv_add(&resp->http_headers, "Strict-Transport-Security", 1488 NULL)) == NULL || 1489 kv_set(cl, "max-age=%d%s%s", srv_conf->hsts_max_age, 1490 srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ? 1491 "; includeSubDomains" : "", 1492 srv_conf->hsts_flags & HSTSFLAG_PRELOAD ? 1493 "; preload" : "") == -1) 1494 return (-1); 1495 } 1496 1497 /* Date header is mandatory and should be added as late as possible */ 1498 if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 || 1499 kv_add(&resp->http_headers, "Date", tmbuf) == NULL) 1500 return (-1); 1501 1502 /* Write completed header */ 1503 if (server_writeresponse_http(clt) == -1 || 1504 server_bufferevent_print(clt, "\r\n") == -1 || 1505 server_headers(clt, resp, server_writeheader_http, NULL) == -1 || 1506 server_bufferevent_print(clt, "\r\n") == -1) 1507 return (-1); 1508 1509 if (size <= 0 || resp->http_method == HTTP_METHOD_HEAD) { 1510 bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); 1511 if (clt->clt_persist) 1512 clt->clt_toread = TOREAD_HTTP_HEADER; 1513 else 1514 clt->clt_toread = TOREAD_HTTP_NONE; 1515 clt->clt_done = 0; 1516 return (0); 1517 } 1518 1519 return (1); 1520 } 1521 1522 int 1523 server_writeresponse_http(struct client *clt) 1524 { 1525 struct http_descriptor *desc = clt->clt_descresp; 1526 1527 DPRINTF("version: %s rescode: %s resmsg: %s", desc->http_version, 1528 desc->http_rescode, desc->http_resmesg); 1529 1530 if (server_bufferevent_print(clt, desc->http_version) == -1 || 1531 server_bufferevent_print(clt, " ") == -1 || 1532 server_bufferevent_print(clt, desc->http_rescode) == -1 || 1533 server_bufferevent_print(clt, " ") == -1 || 1534 server_bufferevent_print(clt, desc->http_resmesg) == -1) 1535 return (-1); 1536 1537 return (0); 1538 } 1539 1540 int 1541 server_writeheader_http(struct client *clt, struct kv *hdr, void *arg) 1542 { 1543 char *ptr; 1544 const char *key; 1545 1546 if (hdr->kv_flags & KV_FLAG_INVALID) 1547 return (0); 1548 1549 /* The key might have been updated in the parent */ 1550 if (hdr->kv_parent != NULL && hdr->kv_parent->kv_key != NULL) 1551 key = hdr->kv_parent->kv_key; 1552 else 1553 key = hdr->kv_key; 1554 1555 ptr = hdr->kv_value; 1556 if (server_bufferevent_print(clt, key) == -1 || 1557 (ptr != NULL && 1558 (server_bufferevent_print(clt, ": ") == -1 || 1559 server_bufferevent_print(clt, ptr) == -1 || 1560 server_bufferevent_print(clt, "\r\n") == -1))) 1561 return (-1); 1562 DPRINTF("%s: %s: %s", __func__, key, 1563 hdr->kv_value == NULL ? "" : hdr->kv_value); 1564 1565 return (0); 1566 } 1567 1568 int 1569 server_headers(struct client *clt, void *descp, 1570 int (*hdr_cb)(struct client *, struct kv *, void *), void *arg) 1571 { 1572 struct kv *hdr, *kv; 1573 struct http_descriptor *desc = descp; 1574 1575 RB_FOREACH(hdr, kvtree, &desc->http_headers) { 1576 if ((hdr_cb)(clt, hdr, arg) == -1) 1577 return (-1); 1578 TAILQ_FOREACH(kv, &hdr->kv_children, kv_entry) { 1579 if ((hdr_cb)(clt, kv, arg) == -1) 1580 return (-1); 1581 } 1582 } 1583 1584 return (0); 1585 } 1586 1587 enum httpmethod 1588 server_httpmethod_byname(const char *name) 1589 { 1590 enum httpmethod id = HTTP_METHOD_NONE; 1591 struct http_method method, *res = NULL; 1592 1593 /* Set up key */ 1594 method.method_name = name; 1595 1596 if ((res = bsearch(&method, http_methods, 1597 sizeof(http_methods) / sizeof(http_methods[0]) - 1, 1598 sizeof(http_methods[0]), server_httpmethod_cmp)) != NULL) 1599 id = res->method_id; 1600 1601 return (id); 1602 } 1603 1604 const char * 1605 server_httpmethod_byid(unsigned int id) 1606 { 1607 const char *name = "<UNKNOWN>"; 1608 int i; 1609 1610 for (i = 0; http_methods[i].method_name != NULL; i++) { 1611 if (http_methods[i].method_id == id) { 1612 name = http_methods[i].method_name; 1613 break; 1614 } 1615 } 1616 1617 return (name); 1618 } 1619 1620 static int 1621 server_httpmethod_cmp(const void *a, const void *b) 1622 { 1623 const struct http_method *ma = a; 1624 const struct http_method *mb = b; 1625 1626 /* 1627 * RFC 2616 section 5.1.1 says that the method is case 1628 * sensitive so we don't do a strcasecmp here. 1629 */ 1630 return (strcmp(ma->method_name, mb->method_name)); 1631 } 1632 1633 const char * 1634 server_httperror_byid(unsigned int id) 1635 { 1636 struct http_error error, *res; 1637 1638 /* Set up key */ 1639 error.error_code = (int)id; 1640 1641 if ((res = bsearch(&error, http_errors, 1642 sizeof(http_errors) / sizeof(http_errors[0]) - 1, 1643 sizeof(http_errors[0]), server_httperror_cmp)) != NULL) 1644 return (res->error_name); 1645 1646 return (NULL); 1647 } 1648 1649 static int 1650 server_httperror_cmp(const void *a, const void *b) 1651 { 1652 const struct http_error *ea = a; 1653 const struct http_error *eb = b; 1654 return (ea->error_code - eb->error_code); 1655 } 1656 1657 int 1658 server_log_http(struct client *clt, unsigned int code, size_t len) 1659 { 1660 static char tstamp[64]; 1661 static char ip[INET6_ADDRSTRLEN]; 1662 time_t t; 1663 struct kv key, *agent, *referrer, *xff, *xfp; 1664 struct tm *tm; 1665 struct server_config *srv_conf; 1666 struct http_descriptor *desc; 1667 int ret = -1; 1668 char *user = NULL; 1669 char *path = NULL; 1670 char *version = NULL; 1671 char *referrer_v = NULL; 1672 char *agent_v = NULL; 1673 char *xff_v = NULL; 1674 char *xfp_v = NULL; 1675 1676 if ((srv_conf = clt->clt_srv_conf) == NULL) 1677 return (-1); 1678 if ((srv_conf->flags & SRVFLAG_LOG) == 0) 1679 return (0); 1680 if ((desc = clt->clt_descreq) == NULL) 1681 return (-1); 1682 1683 if ((t = time(NULL)) == -1) 1684 return (-1); 1685 if ((tm = localtime(&t)) == NULL) 1686 return (-1); 1687 if (strftime(tstamp, sizeof(tstamp), "%d/%b/%Y:%H:%M:%S %z", tm) == 0) 1688 return (-1); 1689 1690 if (print_host(&clt->clt_ss, ip, sizeof(ip)) == NULL) 1691 return (-1); 1692 1693 /* 1694 * For details on common log format, see: 1695 * https://httpd.apache.org/docs/current/mod/mod_log_config.html 1696 * 1697 * httpd's format is similar to these Apache LogFormats: 1698 * "%v %h %l %u %t \"%r\" %>s %B" 1699 * "%v %h %l %u %t \"%r\" %>s %B \"%{Referer}i\" \"%{User-agent}i\"" 1700 */ 1701 switch (srv_conf->logformat) { 1702 case LOG_FORMAT_COMMON: 1703 /* Use vis to encode input values from the header */ 1704 if (clt->clt_remote_user && 1705 stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1) 1706 goto done; 1707 if (desc->http_version && 1708 stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1) 1709 goto done; 1710 1711 /* The following should be URL-encoded */ 1712 if (desc->http_path && 1713 (path = url_encode(desc->http_path)) == NULL) 1714 goto done; 1715 1716 ret = evbuffer_add_printf(clt->clt_log, 1717 "%s %s - %s [%s] \"%s %s%s%s%s%s\" %03d %zu\n", 1718 srv_conf->name, ip, clt->clt_remote_user == NULL ? "-" : 1719 user, tstamp, 1720 server_httpmethod_byid(desc->http_method), 1721 desc->http_path == NULL ? "" : path, 1722 desc->http_query == NULL ? "" : "?", 1723 desc->http_query == NULL ? "" : desc->http_query, 1724 desc->http_version == NULL ? "" : " ", 1725 desc->http_version == NULL ? "" : version, 1726 code, len); 1727 1728 break; 1729 1730 case LOG_FORMAT_COMBINED: 1731 case LOG_FORMAT_FORWARDED: 1732 key.kv_key = "Referer"; /* sic */ 1733 if ((referrer = kv_find(&desc->http_headers, &key)) != NULL && 1734 referrer->kv_value == NULL) 1735 referrer = NULL; 1736 1737 key.kv_key = "User-Agent"; 1738 if ((agent = kv_find(&desc->http_headers, &key)) != NULL && 1739 agent->kv_value == NULL) 1740 agent = NULL; 1741 1742 /* Use vis to encode input values from the header */ 1743 if (clt->clt_remote_user && 1744 stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1) 1745 goto done; 1746 if (clt->clt_remote_user == NULL && 1747 clt->clt_tls_ctx != NULL && 1748 (srv_conf->tls_flags & TLSFLAG_CA) && 1749 tls_peer_cert_subject(clt->clt_tls_ctx) != NULL && 1750 stravis(&user, tls_peer_cert_subject(clt->clt_tls_ctx), 1751 HTTPD_LOGVIS) == -1) 1752 goto done; 1753 if (desc->http_version && 1754 stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1) 1755 goto done; 1756 if (agent && 1757 stravis(&agent_v, agent->kv_value, HTTPD_LOGVIS) == -1) 1758 goto done; 1759 1760 /* The following should be URL-encoded */ 1761 if (desc->http_path && 1762 (path = url_encode(desc->http_path)) == NULL) 1763 goto done; 1764 if (referrer && 1765 (referrer_v = url_encode(referrer->kv_value)) == NULL) 1766 goto done; 1767 1768 if ((ret = evbuffer_add_printf(clt->clt_log, 1769 "%s %s - %s [%s] \"%s %s%s%s%s%s\"" 1770 " %03d %zu \"%s\" \"%s\"", 1771 srv_conf->name, ip, user == NULL ? "-" : 1772 user, tstamp, 1773 server_httpmethod_byid(desc->http_method), 1774 desc->http_path == NULL ? "" : path, 1775 desc->http_query == NULL ? "" : "?", 1776 desc->http_query == NULL ? "" : desc->http_query, 1777 desc->http_version == NULL ? "" : " ", 1778 desc->http_version == NULL ? "" : version, 1779 code, len, 1780 referrer == NULL ? "" : referrer_v, 1781 agent == NULL ? "" : agent_v)) == -1) 1782 break; 1783 1784 if (srv_conf->logformat == LOG_FORMAT_COMBINED) 1785 goto finish; 1786 1787 xff = xfp = NULL; 1788 1789 key.kv_key = "X-Forwarded-For"; 1790 if ((xff = kv_find(&desc->http_headers, &key)) != NULL 1791 && xff->kv_value == NULL) 1792 xff = NULL; 1793 1794 if (xff && 1795 stravis(&xff_v, xff->kv_value, HTTPD_LOGVIS) == -1) 1796 goto finish; 1797 1798 key.kv_key = "X-Forwarded-Port"; 1799 if ((xfp = kv_find(&desc->http_headers, &key)) != NULL && 1800 (xfp->kv_value == NULL)) 1801 xfp = NULL; 1802 1803 if (xfp && 1804 stravis(&xfp_v, xfp->kv_value, HTTPD_LOGVIS) == -1) 1805 goto finish; 1806 1807 if ((ret = evbuffer_add_printf(clt->clt_log, " %s %s", 1808 xff == NULL ? "-" : xff_v, 1809 xfp == NULL ? "-" : xfp_v)) == -1) 1810 break; 1811 finish: 1812 ret = evbuffer_add_printf(clt->clt_log, "\n"); 1813 1814 break; 1815 1816 case LOG_FORMAT_CONNECTION: 1817 /* URL-encode the path */ 1818 if (desc->http_path && 1819 (path = url_encode(desc->http_path)) == NULL) 1820 goto done; 1821 1822 ret = evbuffer_add_printf(clt->clt_log, " [%s]", 1823 desc->http_path == NULL ? "" : path); 1824 1825 break; 1826 } 1827 1828 done: 1829 free(user); 1830 free(path); 1831 free(version); 1832 free(referrer_v); 1833 free(agent_v); 1834 free(xff_v); 1835 free(xfp_v); 1836 1837 return (ret); 1838 } 1839