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