1 #include "first.h" 2 3 #include "response.h" 4 #include "request.h" 5 #include "reqpool.h" 6 #include "base.h" 7 #include "fdevent.h" 8 #include "http_header.h" 9 #include "http_kv.h" 10 #include "log.h" 11 #include "stat_cache.h" 12 #include "chunk.h" 13 #include "http_chunk.h" 14 #include "http_date.h" 15 #include "http_range.h" 16 17 #include "plugin.h" 18 #include "plugins.h" 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include "sys-time.h" 23 24 #include <limits.h> 25 #include <errno.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 30 int 31 http_response_omit_header (request_st * const r, const data_string * const ds) 32 { 33 const size_t klen = buffer_clen(&ds->key); 34 if (klen == sizeof("X-Sendfile")-1 35 && buffer_eq_icase_ssn(ds->key.ptr, CONST_STR_LEN("X-Sendfile"))) 36 return 1; 37 if (klen >= sizeof("X-LIGHTTPD-")-1 38 && buffer_eq_icase_ssn(ds->key.ptr, CONST_STR_LEN("X-LIGHTTPD-"))) { 39 if (klen == sizeof("X-LIGHTTPD-KBytes-per-second")-1 40 && buffer_eq_icase_ssn(ds->key.ptr+sizeof("X-LIGHTTPD-")-1, 41 CONST_STR_LEN("KBytes-per-second"))) { 42 /* "X-LIGHTTPD-KBytes-per-second" */ 43 off_t limit = strtol(ds->value.ptr, NULL, 10) << 10; /*(*=1024)*/ 44 if (limit > 0 45 && (limit < r->conf.bytes_per_second 46 || 0 == r->conf.bytes_per_second)) { 47 r->conf.bytes_per_second = limit; 48 } 49 } 50 return 1; 51 } 52 return 0; 53 } 54 55 56 __attribute_cold__ 57 static void 58 http_response_write_header_partial_1xx (request_st * const r, buffer * const b) 59 { 60 /* take data in con->write_queue and move into b 61 * (to be sent prior to final response headers in r->write_queue) */ 62 connection * const con = r->con; 63 /*assert(&r->write_queue != con->write_queue);*/ 64 chunkqueue * const cq = con->write_queue; 65 con->write_queue = &r->write_queue; 66 67 /*assert(0 == buffer_clen(b));*//*expect empty buffer from caller*/ 68 uint32_t len = (uint32_t)chunkqueue_length(cq); 69 /*(expecting MEM_CHUNK(s), so not expecting error reading files)*/ 70 if (chunkqueue_read_data(cq, buffer_string_prepare_append(b, len), 71 len, r->conf.errh) < 0) 72 len = 0; 73 buffer_truncate(b, len);/*expect initial empty buffer from caller*/ 74 chunkqueue_free(cq); 75 } 76 77 78 void 79 http_response_write_header (request_st * const r) 80 { 81 /* disable keep-alive if requested */ 82 83 r->con->keep_alive_idle = r->conf.max_keep_alive_idle; 84 if (__builtin_expect( (0 == r->conf.max_keep_alive_idle), 0) 85 || r->con->request_count > r->conf.max_keep_alive_requests) { 86 r->keep_alive = 0; 87 } else if (0 != r->reqbody_length 88 && r->reqbody_length != r->reqbody_queue.bytes_in 89 && (NULL == r->handler_module 90 || 0 == (r->conf.stream_request_body 91 & (FDEVENT_STREAM_REQUEST 92 | FDEVENT_STREAM_REQUEST_BUFMIN)))) { 93 r->keep_alive = 0; 94 } 95 96 if (light_btst(r->resp_htags, HTTP_HEADER_UPGRADE) 97 && r->http_version == HTTP_VERSION_1_1) { 98 http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("upgrade")); 99 } else if (r->keep_alive <= 0) { 100 http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); 101 } else if (r->http_version == HTTP_VERSION_1_0) {/*(&& r->keep_alive > 0)*/ 102 http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); 103 } 104 105 if (304 == r->http_status 106 && light_btst(r->resp_htags, HTTP_HEADER_CONTENT_ENCODING)) { 107 http_header_response_unset(r, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding")); 108 } 109 110 chunkqueue * const cq = &r->write_queue; 111 buffer * const b = chunkqueue_prepend_buffer_open(cq); 112 113 if (cq != r->con->write_queue) 114 http_response_write_header_partial_1xx(r, b); 115 116 buffer_append_string_len(b, 117 (r->http_version == HTTP_VERSION_1_1) 118 ? "HTTP/1.1 " 119 : "HTTP/1.0 ", 120 sizeof("HTTP/1.1 ")-1); 121 http_status_append(b, r->http_status); 122 123 /* add all headers */ 124 for (size_t i = 0, used = r->resp_headers.used; i < used; ++i) { 125 const data_string * const ds = (data_string *)r->resp_headers.data[i]; 126 const uint32_t klen = buffer_clen(&ds->key); 127 const uint32_t vlen = buffer_clen(&ds->value); 128 if (__builtin_expect( (0 == klen), 0)) continue; 129 if (__builtin_expect( (0 == vlen), 0)) continue; 130 if ((ds->key.ptr[0] & 0xdf) == 'X' && http_response_omit_header(r, ds)) 131 continue; 132 char * restrict s = buffer_extend(b, klen+vlen+4); 133 s[0] = '\r'; 134 s[1] = '\n'; 135 memcpy(s+2, ds->key.ptr, klen); 136 s += 2+klen; 137 s[0] = ':'; 138 s[1] = ' '; 139 memcpy(s+2, ds->value.ptr, vlen); 140 } 141 142 if (!light_btst(r->resp_htags, HTTP_HEADER_DATE)) { 143 /* HTTP/1.1 and later requires a Date: header */ 144 /* "\r\nDate: " 8-chars + 30-chars "%a, %d %b %Y %T GMT" + '\0' */ 145 static unix_time64_t tlast = 0; 146 static char tstr[40] = "\r\nDate: "; 147 148 /* cache the generated timestamp */ 149 const unix_time64_t cur_ts = log_epoch_secs; 150 if (__builtin_expect ( (tlast != cur_ts), 0)) 151 http_date_time_to_str(tstr+8, sizeof(tstr)-8, (tlast = cur_ts)); 152 153 buffer_append_string_len(b, tstr, 37); 154 } 155 156 if (!light_btst(r->resp_htags, HTTP_HEADER_SERVER) && r->conf.server_tag) 157 buffer_append_str2(b, CONST_STR_LEN("\r\nServer: "), 158 BUF_PTR_LEN(r->conf.server_tag)); 159 160 buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); 161 162 r->resp_header_len = buffer_clen(b); 163 164 if (r->conf.log_response_header) { 165 log_error_multiline(r->conf.errh, __FILE__, __LINE__, 166 BUF_PTR_LEN(b), "fd:%d resp: ", r->con->fd); 167 } 168 169 chunkqueue_prepend_buffer_commit(cq); 170 171 /*(optimization to use fewer syscalls to send a small response)*/ 172 off_t cqlen; 173 if (r->resp_body_finished 174 && light_btst(r->resp_htags, HTTP_HEADER_CONTENT_LENGTH) 175 && (cqlen = chunkqueue_length(cq) - r->resp_header_len) > 0 176 && cqlen < 16384) 177 chunkqueue_small_resp_optim(cq); 178 } 179 180 181 __attribute_cold__ 182 static handler_t 183 http_response_physical_path_error (request_st * const r, const int code, const char * const msg) 184 { 185 r->http_status = code; 186 if ((code == 404 && r->conf.log_file_not_found) 187 || r->conf.log_request_handling) { 188 if (NULL == msg) 189 log_perror(r->conf.errh, __FILE__, __LINE__, "-- "); 190 else 191 log_error(r->conf.errh, __FILE__, __LINE__, "%s", msg); 192 log_error(r->conf.errh, __FILE__, __LINE__, 193 "Path : %s", r->physical.path.ptr); 194 log_error(r->conf.errh, __FILE__, __LINE__, 195 "URI : %s", r->uri.path.ptr); 196 } 197 return HANDLER_FINISHED; 198 } 199 200 201 static handler_t http_response_physical_path_check(request_st * const r) { 202 stat_cache_entry *sce = stat_cache_get_entry(&r->physical.path); 203 204 if (__builtin_expect( (sce != NULL), 1)) { 205 /* file exists */ 206 } else { 207 switch (errno) { 208 case ENOTDIR: 209 /* PATH_INFO ! :) */ 210 break; 211 case EACCES: 212 return http_response_physical_path_error(r, 403, NULL); 213 case ENAMETOOLONG: 214 /* file name to be read was too long. return 404 */ 215 case ENOENT: 216 if (r->http_method == HTTP_METHOD_OPTIONS 217 && light_btst(r->resp_htags, HTTP_HEADER_ALLOW)) { 218 r->http_status = 200; 219 return HANDLER_FINISHED; 220 } 221 return http_response_physical_path_error(r, 404, NULL); 222 default: 223 /* we have no idea what happened. let's tell the user so. */ 224 return http_response_physical_path_error(r, 500, NULL); 225 } 226 227 /* not found, perhaps PATHINFO */ 228 229 char *pathinfo; 230 { 231 /*(might check at startup that s->document_root does not end in '/')*/ 232 size_t len = buffer_clen(&r->physical.basedir) 233 - (buffer_has_pathsep_suffix(&r->physical.basedir)); 234 pathinfo = r->physical.path.ptr + len; 235 if ('/' != *pathinfo) { 236 pathinfo = NULL; 237 } 238 else if (pathinfo == r->physical.path.ptr) { /*(basedir is "/")*/ 239 pathinfo = strchr(pathinfo+1, '/'); 240 } 241 } 242 243 const uint32_t pathused = r->physical.path.used; 244 for (char *pprev = pathinfo; pathinfo; pprev = pathinfo, pathinfo = strchr(pathinfo+1, '/')) { 245 /*(temporarily modify r->physical.path in-place)*/ 246 r->physical.path.used = pathinfo - r->physical.path.ptr + 1; 247 *pathinfo = '\0'; 248 stat_cache_entry * const nsce = stat_cache_get_entry(&r->physical.path); 249 *pathinfo = '/'; 250 r->physical.path.used = pathused; 251 if (NULL == nsce) { 252 pathinfo = pathinfo != pprev ? pprev : NULL; 253 break; 254 } 255 sce = nsce; 256 if (!S_ISDIR(sce->st.st_mode)) break; 257 } 258 259 if (NULL == pathinfo || !S_ISREG(sce->st.st_mode)) { 260 /* no it really doesn't exists */ 261 return http_response_physical_path_error(r, 404, "-- file not found"); 262 } 263 /* note: historical behavior checks S_ISREG() above, permitting 264 * path-info only on regular files, not dirs or special files */ 265 266 /* we have a PATHINFO */ 267 if (pathinfo) { 268 size_t len = r->physical.path.ptr+pathused-1-pathinfo, reqlen; 269 if (r->conf.force_lowercase_filenames 270 && len <= (reqlen = buffer_clen(&r->target)) 271 && buffer_eq_icase_ssn(r->target.ptr + reqlen - len, pathinfo, len)) { 272 /* attempt to preserve case-insensitive PATH_INFO 273 * (works in common case where mod_alias, mod_magnet, and other modules 274 * have not modified the PATH_INFO portion of request URI, or did so 275 * with exactly the PATH_INFO desired) */ 276 buffer_copy_string_len(&r->pathinfo, r->target.ptr + reqlen - len, len); 277 } else { 278 buffer_copy_string_len(&r->pathinfo, pathinfo, len); 279 } 280 281 /* 282 * shorten uri.path 283 */ 284 285 buffer_truncate(&r->uri.path, buffer_clen(&r->uri.path) - len); 286 buffer_truncate(&r->physical.path, (size_t)(pathinfo - r->physical.path.ptr)); 287 } 288 } 289 290 if (!r->conf.follow_symlink 291 && 0 != stat_cache_path_contains_symlink(&r->physical.path, r->conf.errh)) { 292 return http_response_physical_path_error(r, 403, "-- access denied due to symlink restriction"); 293 } 294 295 /* r->tmp_sce is valid in handle_subrequest_start callback -- 296 * handle_subrquest_start callbacks should not change r->physical.path 297 * (or should invalidate r->tmp_sce). r->tmp_sce is not reset between 298 * requests and is valid only for sequential code after this func succeeds*/ 299 r->tmp_sce = sce; 300 301 if (S_ISREG(sce->st.st_mode)) /*(common case)*/ 302 return HANDLER_GO_ON; 303 304 if (S_ISDIR(sce->st.st_mode)) { 305 if (!buffer_has_slash_suffix(&r->uri.path)) { 306 http_response_redirect_to_directory(r, 301); 307 return HANDLER_FINISHED; 308 } 309 } else { 310 /* any special handling of other non-reg files ?*/ 311 } 312 313 return HANDLER_GO_ON; 314 } 315 316 __attribute_cold__ 317 __attribute_noinline__ 318 static handler_t http_status_set_error_close (request_st * const r, int status) { 319 r->keep_alive = 0; 320 r->resp_body_finished = 1; 321 r->handler_module = NULL; 322 r->http_status = status; 323 return HANDLER_FINISHED; 324 } 325 326 __attribute_cold__ 327 static handler_t http_response_prepare_options_star (request_st * const r) { 328 r->http_status = 200; 329 r->resp_body_finished = 1; 330 http_header_response_append(r, HTTP_HEADER_ALLOW, CONST_STR_LEN("Allow"), 331 CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); 332 return HANDLER_FINISHED; 333 } 334 335 336 __attribute_cold__ 337 static handler_t http_response_prepare_connect (request_st * const r) { 338 return (r->handler_module) 339 ? HANDLER_GO_ON 340 : http_status_set_error_close(r, 405);/* 405 Method Not Allowed */ 341 } 342 343 344 static handler_t http_response_config (request_st * const r) { 345 config_cond_cache_reset(r); 346 config_patch_config(r); 347 348 r->server_name = r->conf.server_name 349 ? r->conf.server_name 350 : &r->uri.authority; 351 352 /* do we have to downgrade from 1.1 to 1.0 ? (ignore for HTTP/2) */ 353 if (__builtin_expect( (!r->conf.allow_http11), 0) 354 && r->http_version == HTTP_VERSION_1_1) { 355 r->http_version = HTTP_VERSION_1_0; 356 /*(when forcing HTTP/1.0, ignore (unlikely) Connection: keep-alive)*/ 357 r->keep_alive = 0; 358 } 359 360 if (__builtin_expect( (r->reqbody_length > 0), 0) 361 && 0 != r->conf.max_request_size /* r->conf.max_request_size in kB */ 362 && (off_t)r->reqbody_length > ((off_t)r->conf.max_request_size << 10)) { 363 log_error(r->conf.errh, __FILE__, __LINE__, 364 "request-size too long: %lld -> 413", (long long) r->reqbody_length); 365 return /* 413 Payload Too Large */ 366 http_status_set_error_close(r, 413); 367 } 368 369 return HANDLER_GO_ON; 370 } 371 372 373 __attribute_noinline__ 374 static handler_t 375 http_response_prepare (request_st * const r) 376 { 377 handler_t rc; 378 379 /* looks like someone has already made a decision */ 380 if (__builtin_expect( (r->http_status > 200), 0)) { /* yes, > 200 */ 381 if (0 == r->resp_body_finished) 382 http_response_body_clear(r, 0); 383 return HANDLER_FINISHED; 384 } 385 386 /* no decision yet, build conf->filename */ 387 if (buffer_is_unset(&r->physical.path)) { 388 389 if (__builtin_expect( (!r->async_callback), 1)) { 390 rc = http_response_config(r); 391 if (HANDLER_GO_ON != rc) return rc; 392 } 393 else 394 r->async_callback = 0; /* reset */ 395 396 /* we only come here when we have the parse the full request again 397 * 398 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 399 * problem here as mod_setenv might get called multiple times 400 * 401 * fastcgi-auth might lead to a COMEBACK too 402 * fastcgi again dead server too 403 */ 404 405 if (r->conf.log_request_handling) { 406 log_error(r->conf.errh, __FILE__, __LINE__, 407 "-- parsed Request-URI"); 408 log_error(r->conf.errh, __FILE__, __LINE__, 409 "Request-URI : %s", r->target.ptr); 410 log_error(r->conf.errh, __FILE__, __LINE__, 411 "URI-scheme : %s", r->uri.scheme.ptr); 412 log_error(r->conf.errh, __FILE__, __LINE__, 413 "URI-authority : %s", r->uri.authority.ptr); 414 log_error(r->conf.errh, __FILE__, __LINE__, 415 "URI-path (clean): %s", r->uri.path.ptr); 416 log_error(r->conf.errh, __FILE__, __LINE__, 417 "URI-query : %.*s", 418 BUFFER_INTLEN_PTR(&r->uri.query)); 419 } 420 421 422 rc = plugins_call_handle_uri_clean(r); 423 if (HANDLER_GO_ON != rc) return rc; 424 425 if (__builtin_expect( (r->http_method == HTTP_METHOD_OPTIONS), 0) 426 && r->uri.path.ptr[0] == '*' && r->uri.path.ptr[1] == '\0') 427 return http_response_prepare_options_star(r); 428 429 if (__builtin_expect( (r->http_method == HTTP_METHOD_CONNECT), 0)) 430 return http_response_prepare_connect(r); 431 432 433 /* 434 * border between logical and physical 435 * logical path (URI) becomes a physical filename 436 */ 437 438 439 /* docroot: set r->physical.doc_root and might set r->server_name */ 440 buffer_clear(&r->physical.doc_root); 441 442 rc = plugins_call_handle_docroot(r); 443 if (HANDLER_GO_ON != rc) return rc; 444 445 446 /* transform r->uri.path to r->physical.rel_path (relative file path) */ 447 buffer_copy_buffer(&r->physical.rel_path, &r->uri.path); 448 #if defined(__WIN32) || defined(__CYGWIN__) 449 /* strip dots from the end and spaces 450 * 451 * windows/dos handle those filenames as the same file 452 * 453 * foo == foo. == foo..... == "foo... " == "foo.. ./" 454 * 455 * This will affect in some cases PATHINFO 456 * 457 * on native windows we could prepend the filename with \\?\ to circumvent 458 * this behaviour. I have no idea how to push this through cygwin 459 * 460 * */ 461 { 462 buffer *b = &r->physical.rel_path; 463 size_t len = buffer_clen(b); 464 465 /* strip trailing " /" or "./" once */ 466 if (len > 1 && 467 b->ptr[len - 1] == '/' && 468 (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) { 469 len -= 2; 470 } 471 /* strip all trailing " " and "." */ 472 while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len; 473 buffer_truncate(b, len); 474 } 475 #endif 476 /* MacOS X and Windows (typically) case-insensitive filesystems */ 477 if (r->conf.force_lowercase_filenames) { 478 buffer_to_lower(&r->physical.rel_path); 479 } 480 481 482 /* compose physical filename: physical.path = doc_root + rel_path */ 483 if (buffer_is_unset(&r->physical.doc_root)) 484 buffer_copy_buffer(&r->physical.doc_root, r->conf.document_root); 485 buffer_copy_buffer(&r->physical.basedir, &r->physical.doc_root); 486 buffer_copy_path_len2(&r->physical.path, 487 BUF_PTR_LEN(&r->physical.doc_root), 488 BUF_PTR_LEN(&r->physical.rel_path)); 489 490 rc = plugins_call_handle_physical(r); 491 if (HANDLER_GO_ON != rc) return rc; 492 493 if (r->conf.log_request_handling) { 494 log_error(r->conf.errh, __FILE__, __LINE__, 495 "-- logical -> physical"); 496 log_error(r->conf.errh, __FILE__, __LINE__, 497 "Doc-Root : %s", r->physical.doc_root.ptr); 498 log_error(r->conf.errh, __FILE__, __LINE__, 499 "Basedir : %s", r->physical.basedir.ptr); 500 log_error(r->conf.errh, __FILE__, __LINE__, 501 "Rel-Path : %s", r->physical.rel_path.ptr); 502 log_error(r->conf.errh, __FILE__, __LINE__, 503 "Path : %s", r->physical.path.ptr); 504 } 505 } 506 507 if (NULL != r->handler_module) return HANDLER_GO_ON; 508 509 /* 510 * No module grabbed the request yet (like mod_access) 511 * 512 * Go on and check if the file exists at all 513 */ 514 515 rc = http_response_physical_path_check(r); 516 if (HANDLER_GO_ON != rc) return rc; 517 518 /* r->physical.path is non-empty and exists in the filesystem */ 519 520 if (r->conf.log_request_handling) { 521 log_error(r->conf.errh, __FILE__, __LINE__, 522 "-- handling subrequest"); 523 log_error(r->conf.errh, __FILE__, __LINE__, 524 "Path : %s", r->physical.path.ptr); 525 log_error(r->conf.errh, __FILE__, __LINE__, 526 "URI : %s", r->uri.path.ptr); 527 log_error(r->conf.errh, __FILE__, __LINE__, 528 "Pathinfo : %s", r->pathinfo.ptr 529 ? r->pathinfo.ptr 530 : ""); 531 } 532 533 /* call the handlers */ 534 rc = plugins_call_handle_subrequest_start(r); 535 if (HANDLER_GO_ON != rc) return rc; 536 537 if (__builtin_expect( (NULL == r->handler_module), 0)) { 538 /* no handler; finish request */ 539 if (__builtin_expect( (0 == r->http_status), 0)) { 540 if (r->http_method == HTTP_METHOD_OPTIONS) { 541 http_response_body_clear(r, 0); 542 http_response_prepare_options_star(r); /*(treat like "*")*/ 543 } 544 else if (!http_method_get_head_post(r->http_method)) 545 r->http_status = 501; 546 else 547 r->http_status = 403; 548 } 549 return HANDLER_FINISHED; 550 } 551 552 return HANDLER_GO_ON; 553 } 554 555 556 __attribute_cold__ 557 __attribute_noinline__ 558 static handler_t http_response_comeback (request_st * const r) 559 { 560 if (NULL != r->handler_module || !buffer_is_unset(&r->physical.path)) 561 return HANDLER_GO_ON; 562 563 request_config_reset(r); 564 565 if (__builtin_expect( (r->http_host != NULL), 1)) 566 buffer_copy_string_len_lc(&r->uri.authority, BUF_PTR_LEN(r->http_host)); 567 else /*(buffer_blank(&r->uri.authority) w/o code inline)*/ 568 buffer_copy_string_len(&r->uri.authority, CONST_STR_LEN("")); 569 570 int status = http_request_parse_target(r, r->con->proto_default_port); 571 if (0 == status) { 572 r->conditional_is_valid = (1 << COMP_SERVER_SOCKET) 573 | (1 << COMP_HTTP_SCHEME) 574 | (1 << COMP_HTTP_HOST) 575 | (1 << COMP_HTTP_REMOTE_IP) 576 | (1 << COMP_HTTP_REQUEST_METHOD) 577 | (1 << COMP_HTTP_URL) 578 | (1 << COMP_HTTP_QUERY_STRING) 579 | (1 << COMP_HTTP_REQUEST_HEADER); 580 return HANDLER_GO_ON; 581 } 582 else { 583 r->conditional_is_valid = (1 << COMP_SERVER_SOCKET) 584 | (1 << COMP_HTTP_REMOTE_IP); 585 config_cond_cache_reset(r); 586 return http_status_set_error_close(r, status); 587 } 588 } 589 590 591 __attribute_cold__ 592 static void 593 http_response_errdoc_init (request_st * const r) 594 { 595 /* modules that produce headers required with error response should 596 * typically also produce an error document. Make an exception for 597 * mod_auth WWW-Authenticate response header. */ 598 buffer *www_auth = NULL; 599 if (401 == r->http_status) { 600 const buffer * const vb = 601 http_header_response_get(r, HTTP_HEADER_WWW_AUTHENTICATE, 602 CONST_STR_LEN("WWW-Authenticate")); 603 if (NULL != vb) buffer_copy_buffer((www_auth = buffer_init()), vb); 604 } 605 606 buffer_reset(&r->physical.path); 607 r->resp_htags = 0; 608 array_reset_data_strings(&r->resp_headers); 609 http_response_body_clear(r, 0); 610 611 if (NULL != www_auth) { 612 http_header_response_set(r, HTTP_HEADER_WWW_AUTHENTICATE, 613 CONST_STR_LEN("WWW-Authenticate"), 614 BUF_PTR_LEN(www_auth)); 615 buffer_free(www_auth); 616 } 617 } 618 619 620 __attribute_cold__ 621 static void 622 http_response_static_errdoc (request_st * const r) 623 { 624 if (NULL == r->handler_module 625 ? r->error_handler_saved_status >= 65535 626 : (!r->conf.error_intercept || r->error_handler_saved_status)) 627 return; 628 629 http_response_errdoc_init(r); 630 r->resp_body_finished = 1; 631 632 /* try to send static errorfile */ 633 if (r->conf.errorfile_prefix) { 634 buffer_copy_buffer(&r->physical.path, r->conf.errorfile_prefix); 635 buffer_append_int(&r->physical.path, r->http_status); 636 buffer_append_string_len(&r->physical.path, CONST_STR_LEN(".html")); 637 stat_cache_entry *sce = 638 stat_cache_get_entry_open(&r->physical.path, r->conf.follow_symlink); 639 if (sce && 0 == http_chunk_append_file_ref(r, sce)) { 640 const buffer *content_type = stat_cache_content_type_get(sce, r); 641 if (content_type) 642 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 643 CONST_STR_LEN("Content-Type"), 644 BUF_PTR_LEN(content_type)); 645 return; 646 } 647 buffer_clear(&r->physical.path); 648 } 649 650 /* build default error-page */ 651 buffer * const b = chunkqueue_append_buffer_open(&r->write_queue); 652 buffer_copy_string_len(b, CONST_STR_LEN( 653 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" 654 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" 655 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" 656 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" 657 " <head>\n" 658 " <title>")); 659 http_status_append(b, r->http_status); 660 buffer_append_string_len(b, CONST_STR_LEN( 661 "</title>\n" 662 " </head>\n" 663 " <body>\n" 664 " <h1>")); 665 http_status_append(b, r->http_status); 666 buffer_append_string_len(b, CONST_STR_LEN( 667 "</h1>\n" 668 " </body>\n" 669 "</html>\n")); 670 chunkqueue_append_buffer_commit(&r->write_queue); 671 672 http_header_response_set(r, HTTP_HEADER_CONTENT_TYPE, 673 CONST_STR_LEN("Content-Type"), 674 CONST_STR_LEN("text/html")); 675 } 676 677 678 __attribute_cold__ 679 static void 680 http_response_merge_trailers (request_st * const r) 681 { 682 /* attempt to merge trailers into headers; header not yet sent by caller */ 683 if (buffer_is_blank(&r->gw_dechunk->b)) return; 684 const int done = r->gw_dechunk->done; 685 if (!done) return; /* XXX: !done; could scan for '\n' and send only those */ 686 687 /* do not include trailers if success status (when response was read from 688 * backend) subsequently changed to error status. http_chunk could add the 689 * trailers, but such actions are better on a different code layer than in 690 * http_chunk.c */ 691 if (done < 400 && r->http_status >= 400) return; 692 693 /* XXX: trailers passed through; no sanity check currently done 694 * https://tools.ietf.org/html/rfc7230#section-4.1.2 695 * 696 * Not checking for disallowed fields 697 * Not handling (deprecated) line wrapping 698 * Not strictly checking fields 699 */ 700 const char *k = strchr(r->gw_dechunk->b.ptr, '\n'); /*(skip final chunk)*/ 701 if (NULL == k) return; /*(should not happen)*/ 702 ++k; 703 for (const char *v, *e; (e = strchr(k, '\n')); k = e+1) { 704 v = memchr(k, ':', (size_t)(e - k)); 705 if (NULL == v || v == k || *k == ' ' || *k == '\t') continue; 706 uint32_t klen = (uint32_t)(v - k); 707 do { ++v; } while (*v == ' ' || *v == '\t'); 708 if (*v == '\r' || *v == '\n') continue; 709 enum http_header_e id = http_header_hkey_get(k, klen); 710 http_header_response_insert(r, id, k, klen, v, (size_t)(e - v)); 711 } 712 http_header_response_unset(r, HTTP_HEADER_OTHER, CONST_STR_LEN("Trailer")); 713 buffer_clear(&r->gw_dechunk->b); 714 } 715 716 717 __attribute_noinline__ 718 static handler_t 719 http_response_write_prepare(request_st * const r) 720 { 721 switch (r->http_status) { 722 case 200: /* common case */ 723 break; 724 case 204: /* class: header only */ 725 case 205: 726 case 304: 727 /* disable chunked encoding again as we have no body */ 728 http_response_body_clear(r, 1); 729 /* no Content-Body, no Content-Length */ 730 http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH, 731 CONST_STR_LEN("Content-Length")); 732 r->resp_body_finished = 1; 733 break; 734 default: /* class: header + body */ 735 /* only custom body for 4xx and 5xx */ 736 if (r->http_status >= 400 && r->http_status < 600) 737 http_response_static_errdoc(r); 738 break; 739 } 740 741 if (r->gw_dechunk) 742 http_response_merge_trailers(r); 743 744 /* Allow filter plugins to change response headers */ 745 switch (plugins_call_handle_response_start(r)) { 746 case HANDLER_GO_ON: 747 case HANDLER_FINISHED: 748 break; 749 default: 750 log_error(r->conf.errh, __FILE__, __LINE__, 751 "response_start plugin failed"); 752 return HANDLER_ERROR; 753 } 754 755 if (r->resp_body_finished) { 756 /* check for Range request (current impl requires resp_body_finished) */ 757 if (r->conf.range_requests && http_range_rfc7233(r) >= 400) 758 http_response_static_errdoc(r); /* 416 Range Not Satisfiable */ 759 760 /* set content-length if length is known and not already set */ 761 if (!(r->resp_htags 762 & (light_bshift(HTTP_HEADER_CONTENT_LENGTH) 763 |light_bshift(HTTP_HEADER_TRANSFER_ENCODING)))) { 764 off_t qlen = chunkqueue_length(&r->write_queue); 765 /** 766 * The Content-Length header can only be sent if we have content: 767 * - HEAD does not have a content-body (but can have content-length) 768 * - 1xx, 204 and 304 does not have a content-body 769 * (RFC 2616 Section 4.3) 770 * 771 * Otherwise generate a Content-Length header 772 * (if chunked encoding is not available) 773 * 774 * (should not reach here if 1xx (r->http_status < 200)) 775 */ 776 if (qlen > 0) { 777 buffer_append_int( 778 http_header_response_set_ptr(r, HTTP_HEADER_CONTENT_LENGTH, 779 CONST_STR_LEN("Content-Length")), 780 qlen); 781 } 782 else if (r->http_method != HTTP_METHOD_HEAD 783 && r->http_status != 204 && r->http_status != 304) { 784 /* Content-Length: 0 is important for Redirects (301, ...) as 785 * there might be content. */ 786 http_header_response_set(r, HTTP_HEADER_CONTENT_LENGTH, 787 CONST_STR_LEN("Content-Length"), 788 CONST_STR_LEN("0")); 789 } 790 } 791 } 792 else if (r->http_version == HTTP_VERSION_2) { 793 /* handled by HTTP/2 framing */ 794 } 795 else { 796 /** 797 * response is not yet finished, but we have all headers 798 * 799 * keep-alive requires one of: 800 * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) 801 * - Transfer-Encoding: chunked (HTTP/1.1) 802 * - Upgrade: ... (lighttpd then acts as transparent proxy) 803 */ 804 805 if (!(r->resp_htags 806 & (light_bshift(HTTP_HEADER_CONTENT_LENGTH) 807 |light_bshift(HTTP_HEADER_TRANSFER_ENCODING) 808 |light_bshift(HTTP_HEADER_UPGRADE)))) { 809 if (r->http_method == HTTP_METHOD_CONNECT && r->http_status == 200){ 810 /*(no transfer-encoding if successful CONNECT)*/ 811 } 812 else if (r->http_version == HTTP_VERSION_1_1) { 813 off_t qlen = chunkqueue_length(&r->write_queue); 814 r->resp_send_chunked = 1; 815 if (r->resp_decode_chunked) { 816 /*(reconstitute initial partially-decoded chunk)*/ 817 off_t gw_chunked = r->gw_dechunk->gw_chunked; 818 if (gw_chunked >= 2) 819 qlen += gw_chunked - 2; 820 else if (1 == gw_chunked) 821 chunkqueue_append_mem(&r->write_queue, 822 CONST_STR_LEN("\r")); 823 else { 824 if (qlen) 825 chunkqueue_append_mem(&r->write_queue, 826 CONST_STR_LEN("\r\n")); 827 const buffer * const hdr = &r->gw_dechunk->b; 828 if (!buffer_is_blank(hdr)) /*(partial chunked header)*/ 829 chunkqueue_append_mem(&r->write_queue, 830 BUF_PTR_LEN(hdr)); 831 } 832 } 833 else if (qlen) { 834 chunkqueue_append_mem(&r->write_queue, 835 CONST_STR_LEN("\r\n")); 836 } 837 if (qlen) { 838 /* create initial Transfer-Encoding: chunked segment */ 839 buffer * const b = 840 chunkqueue_prepend_buffer_open(&r->write_queue); 841 buffer_append_uint_hex(b, (uintmax_t)qlen); 842 buffer_append_string_len(b, CONST_STR_LEN("\r\n")); 843 chunkqueue_prepend_buffer_commit(&r->write_queue); 844 } 845 http_header_response_append(r, HTTP_HEADER_TRANSFER_ENCODING, 846 CONST_STR_LEN("Transfer-Encoding"), 847 CONST_STR_LEN("chunked")); 848 } 849 else { /* if (r->http_version == HTTP_VERSION_1_0) */ 850 r->keep_alive = 0; 851 } 852 } 853 } 854 855 if (r->http_method == HTTP_METHOD_HEAD) { 856 /* HEAD request is like a GET, but without the content */ 857 http_response_body_clear(r, 1); 858 r->resp_body_finished = 1; 859 } 860 861 return HANDLER_GO_ON; 862 } 863 864 865 __attribute_cold__ 866 static int 867 http_response_call_error_handler (request_st * const r, const buffer * const error_handler) 868 { 869 /* call error-handler */ 870 871 /* set REDIRECT_STATUS to save current HTTP status code 872 * for access by dynamic handlers 873 * https://redmine.lighttpd.net/issues/1828 */ 874 buffer_append_int( 875 http_header_env_set_ptr(r, CONST_STR_LEN("REDIRECT_STATUS")), 876 r->http_status); 877 878 if (error_handler == r->conf.error_handler) { 879 plugins_call_handle_request_reset(r); 880 881 if (r->reqbody_length) { 882 if (r->reqbody_length != r->reqbody_queue.bytes_in) 883 r->keep_alive = 0; 884 r->reqbody_length = 0; 885 chunkqueue_reset(&r->reqbody_queue); 886 } 887 888 r->con->is_writable = 1; 889 r->resp_body_finished = 0; 890 r->resp_body_started = 0; 891 892 r->error_handler_saved_status = r->http_status; 893 r->error_handler_saved_method = r->http_method; 894 895 r->http_method = HTTP_METHOD_GET; 896 } 897 else { /*(preserve behavior for server.error-handler-404)*/ 898 /*(negative to flag old behavior)*/ 899 r->error_handler_saved_status = -r->http_status; 900 } 901 902 if (r->http_version == HTTP_VERSION_UNSET) 903 r->http_version = HTTP_VERSION_1_0; 904 905 buffer_copy_buffer(&r->target, error_handler); 906 http_response_errdoc_init(r); 907 r->http_status = 0; /*(after http_response_errdoc_init())*/ 908 return 1; 909 } 910 911 912 __attribute_cold__ 913 __attribute_noinline__ 914 static int 915 http_response_has_error_handler (request_st * const r) 916 { 917 if (r->error_handler_saved_status > 0) 918 r->http_method = r->error_handler_saved_method; 919 if (NULL == r->handler_module || r->conf.error_intercept) { 920 if (__builtin_expect( (r->error_handler_saved_status), 0)) { 921 const int subreq_status = r->http_status; 922 if (r->error_handler_saved_status > 0) 923 r->http_status = r->error_handler_saved_status; 924 else if (r->http_status == 404 || r->http_status == 403) 925 /* error-handler-404 is a 404 */ 926 r->http_status = -r->error_handler_saved_status; 927 else { 928 /* error-handler-404 is back and has generated content */ 929 /* if Status: was set, take it otherwise use 200 */ 930 } 931 if (200 <= subreq_status && subreq_status <= 299) { 932 /*(flag value to indicate that error handler succeeded) 933 *(for (NULL == r->handler_module))*/ 934 r->error_handler_saved_status = 65535; /* >= 1000 */ 935 } 936 } 937 else if (__builtin_expect( (r->http_status >= 400), 0)) { 938 const buffer *error_handler = NULL; 939 if (r->conf.error_handler) 940 error_handler = r->conf.error_handler; 941 else if ((r->http_status == 404 || r->http_status == 403) 942 && r->conf.error_handler_404) 943 error_handler = r->conf.error_handler_404; 944 945 if (error_handler) 946 return http_response_call_error_handler(r, error_handler); 947 } 948 } 949 return 0; 950 } 951 952 953 handler_t 954 http_response_handler (request_st * const r) 955 { 956 int rc; 957 do { 958 const plugin *p = r->handler_module; 959 if (NULL != p 960 || ((rc = http_response_prepare(r)) == HANDLER_GO_ON 961 && NULL != (p = r->handler_module))) 962 rc = p->handle_subrequest(r, p->data); 963 964 switch (rc) { 965 case HANDLER_WAIT_FOR_EVENT: 966 if (!r->resp_body_finished 967 && (!r->resp_body_started 968 || 0 == (r->conf.stream_response_body 969 & (FDEVENT_STREAM_RESPONSE 970 |FDEVENT_STREAM_RESPONSE_BUFMIN)))) 971 return HANDLER_WAIT_FOR_EVENT; /* come back here */ 972 /* response headers received from backend; start response */ 973 __attribute_fallthrough__ 974 case HANDLER_GO_ON: 975 case HANDLER_FINISHED: 976 if (r->http_status == 0) r->http_status = 200; 977 if ((__builtin_expect( (r->http_status < 400), 1) 978 && __builtin_expect( (0 == r->error_handler_saved_status), 1)) 979 || __builtin_expect( (!http_response_has_error_handler(r)), 1)) 980 /* we have something to send; go on */ 981 /*(CON_STATE_RESPONSE_START; transient state)*/ 982 return http_response_write_prepare(r); 983 __attribute_fallthrough__ 984 case HANDLER_COMEBACK: 985 http_response_comeback(r); 986 rc = HANDLER_COMEBACK; 987 continue; 988 /*case HANDLER_ERROR:*/ 989 default: 990 return HANDLER_ERROR; /* something went wrong */ 991 } 992 } while (rc == HANDLER_COMEBACK); 993 #ifndef __COVERITY__ 994 return HANDLER_ERROR; /* should not happen */ /*(not reached)*/ 995 #endif 996 } 997