1 #include "first.h" 2 3 #include "response.h" 4 #include "base.h" 5 #include "burl.h" 6 #include "fdevent.h" 7 #include "http_header.h" 8 #include "http_kv.h" 9 #include "log.h" 10 #include "stat_cache.h" 11 #include "chunk.h" 12 13 #include "configfile.h" 14 15 #include "plugin.h" 16 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 20 #include <limits.h> 21 #include <errno.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <time.h> 25 26 int http_response_write_header(server *srv, connection *con) { 27 buffer * const b = chunkqueue_prepend_buffer_open(con->write_queue); 28 29 if (con->request.http_version == HTTP_VERSION_1_1) { 30 buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 ")); 31 } else { 32 buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 ")); 33 } 34 http_status_append(b, con->http_status); 35 36 /* disable keep-alive if requested */ 37 if (con->request_count > con->conf.max_keep_alive_requests || 0 == con->conf.max_keep_alive_idle) { 38 con->keep_alive = 0; 39 } else if (0 != con->request.content_length 40 && con->request.content_length != con->request_content_queue->bytes_in 41 && (con->mode == DIRECT || 0 == con->conf.stream_request_body)) { 42 con->keep_alive = 0; 43 } else { 44 con->keep_alive_idle = con->conf.max_keep_alive_idle; 45 } 46 47 if ((con->response.htags & HTTP_HEADER_UPGRADE) && con->request.http_version == HTTP_VERSION_1_1) { 48 http_header_response_set(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("upgrade")); 49 } else if (0 == con->keep_alive) { 50 http_header_response_set(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); 51 } else if (con->request.http_version == HTTP_VERSION_1_0) {/*(&& con->keep_alive != 0)*/ 52 http_header_response_set(con, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); 53 } 54 55 if (304 == con->http_status && (con->response.htags & HTTP_HEADER_CONTENT_ENCODING)) { 56 http_header_response_unset(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding")); 57 } 58 59 /* add all headers */ 60 for (size_t i = 0; i < con->response.headers->used; ++i) { 61 const data_string * const ds = (data_string *)con->response.headers->data[i]; 62 63 if (buffer_string_is_empty(ds->value) || buffer_string_is_empty(ds->key)) continue; 64 if ((ds->key->ptr[0] & 0xdf) == 'X') { 65 if (0 == strncasecmp(ds->key->ptr, CONST_STR_LEN("X-Sendfile"))) continue; 66 if (0 == strncasecmp(ds->key->ptr, CONST_STR_LEN("X-LIGHTTPD-"))) { 67 if (0 == strncasecmp(ds->key->ptr+sizeof("X-LIGHTTPD-")-1, CONST_STR_LEN("KBytes-per-second"))) { 68 /* "X-LIGHTTPD-KBytes-per-second" */ 69 long limit = strtol(ds->value->ptr, NULL, 10); 70 if (limit > 0 71 && (limit < con->conf.kbytes_per_second 72 || 0 == con->conf.kbytes_per_second)) { 73 if (limit > USHRT_MAX) limit= USHRT_MAX; 74 con->conf.kbytes_per_second = limit; 75 } 76 } 77 continue; 78 } 79 } 80 81 buffer_append_string_len(b, CONST_STR_LEN("\r\n")); 82 buffer_append_string_buffer(b, ds->key); 83 buffer_append_string_len(b, CONST_STR_LEN(": ")); 84 buffer_append_string_buffer(b, ds->value); 85 } 86 87 if (!(con->response.htags & HTTP_HEADER_DATE)) { 88 /* HTTP/1.1 requires a Date: header */ 89 buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: ")); 90 91 /* cache the generated timestamp */ 92 if (srv->cur_ts != srv->last_generated_date_ts) { 93 buffer_clear(srv->ts_date_str); 94 buffer_append_strftime(srv->ts_date_str, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts))); 95 srv->last_generated_date_ts = srv->cur_ts; 96 } 97 98 buffer_append_string_buffer(b, srv->ts_date_str); 99 } 100 101 if (!(con->response.htags & HTTP_HEADER_SERVER)) { 102 if (!buffer_string_is_empty(con->conf.server_tag)) { 103 buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: ")); 104 buffer_append_string_len(b, CONST_BUF_LEN(con->conf.server_tag)); 105 } 106 } 107 108 buffer_append_string_len(b, CONST_STR_LEN("\r\n\r\n")); 109 110 con->bytes_header = buffer_string_length(b); 111 112 if (con->conf.log_response_header) { 113 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b); 114 } 115 116 chunkqueue_prepend_buffer_commit(con->write_queue); 117 return 0; 118 } 119 120 static handler_t http_response_physical_path_check(server *srv, connection *con) { 121 stat_cache_entry *sce = NULL; 122 123 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { 124 /* file exists */ 125 } else { 126 char *pathinfo = NULL; 127 switch (errno) { 128 case EACCES: 129 con->http_status = 403; 130 131 if (con->conf.log_request_handling) { 132 log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied"); 133 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 134 } 135 136 buffer_reset(con->physical.path); 137 return HANDLER_FINISHED; 138 case ENAMETOOLONG: 139 /* file name to be read was too long. return 404 */ 140 case ENOENT: 141 if (con->request.http_method == HTTP_METHOD_OPTIONS 142 && NULL != http_header_response_get(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"))) { 143 con->http_status = 200; 144 return HANDLER_FINISHED; 145 } 146 147 con->http_status = 404; 148 149 if (con->conf.log_request_handling) { 150 log_error_write(srv, __FILE__, __LINE__, "s", "-- file not found"); 151 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 152 } 153 154 buffer_reset(con->physical.path); 155 return HANDLER_FINISHED; 156 case ENOTDIR: 157 /* PATH_INFO ! :) */ 158 break; 159 default: 160 /* we have no idea what happend. let's tell the user so. */ 161 log_error_write(srv, __FILE__, __LINE__, "ssbsb", 162 "file not found ... or so: ", strerror(errno), 163 con->uri.path, 164 "->", con->physical.path); 165 166 con->http_status = 500; 167 buffer_reset(con->physical.path); 168 169 return HANDLER_FINISHED; 170 } 171 172 /* not found, perhaps PATHINFO */ 173 174 { 175 /*(might check at startup that s->document_root does not end in '/')*/ 176 size_t len = buffer_string_length(con->physical.basedir); 177 if (len > 0 && '/' == con->physical.basedir->ptr[len-1]) --len; 178 pathinfo = con->physical.path->ptr + len; 179 if ('/' != *pathinfo) { 180 pathinfo = NULL; 181 } 182 else if (pathinfo == con->physical.path->ptr) { /*(basedir is "/")*/ 183 pathinfo = strchr(pathinfo+1, '/'); 184 } 185 } 186 187 for (char *pprev = pathinfo; pathinfo; pprev = pathinfo, pathinfo = strchr(pathinfo+1, '/')) { 188 stat_cache_entry *nsce = NULL; 189 buffer_copy_string_len(srv->tmp_buf, con->physical.path->ptr, pathinfo - con->physical.path->ptr); 190 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, srv->tmp_buf, &nsce)) { 191 pathinfo = pathinfo != pprev ? pprev : NULL; 192 break; 193 } 194 sce = nsce; 195 if (!S_ISDIR(sce->st.st_mode)) break; 196 } 197 198 if (NULL == pathinfo || !S_ISREG(sce->st.st_mode)) { 199 /* no it really doesn't exists */ 200 con->http_status = 404; 201 202 if (con->conf.log_file_not_found) { 203 log_error_write(srv, __FILE__, __LINE__, "sbsb", 204 "file not found:", con->uri.path, 205 "->", con->physical.path); 206 } 207 208 buffer_reset(con->physical.path); 209 210 return HANDLER_FINISHED; 211 } 212 213 /* we have a PATHINFO */ 214 if (pathinfo) { 215 size_t len = strlen(pathinfo), reqlen; 216 if (con->conf.force_lowercase_filenames 217 && len <= (reqlen = buffer_string_length(con->request.uri)) 218 && 0 == strncasecmp(con->request.uri->ptr + reqlen - len, pathinfo, len)) { 219 /* attempt to preserve case-insensitive PATH_INFO 220 * (works in common case where mod_alias, mod_magnet, and other modules 221 * have not modified the PATH_INFO portion of request URI, or did so 222 * with exactly the PATH_INFO desired) */ 223 buffer_copy_string_len(con->request.pathinfo, con->request.uri->ptr + reqlen - len, len); 224 } else { 225 buffer_copy_string_len(con->request.pathinfo, pathinfo, len); 226 } 227 228 /* 229 * shorten uri.path 230 */ 231 232 buffer_string_set_length(con->uri.path, buffer_string_length(con->uri.path) - len); 233 buffer_string_set_length(con->physical.path, (size_t)(pathinfo - con->physical.path->ptr)); 234 } 235 } 236 237 if (!con->conf.follow_symlink 238 && 0 != stat_cache_path_contains_symlink(srv, con->physical.path)) { 239 con->http_status = 403; 240 241 if (con->conf.log_request_handling) { 242 log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); 243 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 244 } 245 246 buffer_reset(con->physical.path); 247 return HANDLER_FINISHED; 248 } 249 250 if (S_ISDIR(sce->st.st_mode)) { 251 if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') { 252 /* redirect to .../ */ 253 254 http_response_redirect_to_directory(srv, con, 301); 255 256 return HANDLER_FINISHED; 257 } 258 } else if (!S_ISREG(sce->st.st_mode)) { 259 /* any special handling of non-reg files ?*/ 260 } 261 262 return HANDLER_GO_ON; 263 } 264 265 handler_t http_response_prepare(server *srv, connection *con) { 266 handler_t r; 267 268 /* looks like someone has already done a decision */ 269 if (con->mode == DIRECT && 270 (con->http_status != 0 && con->http_status != 200)) { 271 /* remove a packets in the queue */ 272 if (con->file_finished == 0) { 273 http_response_body_clear(con, 0); 274 } 275 276 return HANDLER_FINISHED; 277 } 278 279 /* no decision yet, build conf->filename */ 280 if (con->mode == DIRECT && buffer_is_empty(con->physical.path)) { 281 282 /* we only come here when we have the parse the full request again 283 * 284 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a 285 * problem here as mod_setenv might get called multiple times 286 * 287 * fastcgi-auth might lead to a COMEBACK too 288 * fastcgi again dead server too 289 * 290 * mod_compress might add headers twice too 291 * 292 * */ 293 294 if (!con->async_callback) { 295 296 config_cond_cache_reset(srv, con); 297 config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */ 298 299 if (con->conf.log_condition_handling) { 300 log_error_write(srv, __FILE__, __LINE__, "s", "run condition"); 301 } 302 303 /** 304 * prepare strings 305 * 306 * - uri.path_raw 307 * - uri.path 308 * - uri.query 309 * 310 */ 311 312 /** 313 * Name according to RFC 2396 314 * 315 * - scheme 316 * - authority 317 * - path 318 * - query 319 * 320 * (scheme)://(authority)(path)?(query)#fragment 321 * 322 * 323 */ 324 325 /* take initial scheme value from connection-level state 326 * (request con->uri.scheme can be overwritten for later, 327 * for example by mod_extforward or mod_magnet) */ 328 buffer_copy_buffer(con->uri.scheme, con->proto); 329 buffer_copy_buffer(con->uri.authority, con->request.http_host); 330 buffer_to_lower(con->uri.authority); 331 332 if (con->request.http_method == HTTP_METHOD_CONNECT 333 || (con->request.http_method == HTTP_METHOD_OPTIONS 334 && con->request.uri->ptr[0] == '*' 335 && con->request.uri->ptr[1] == '\0')) { 336 /* CONNECT ... (or) OPTIONS * ... */ 337 buffer_copy_buffer(con->uri.path_raw, con->request.uri); 338 buffer_copy_buffer(con->uri.path, con->uri.path_raw); 339 buffer_reset(con->uri.query); 340 } else { 341 char *qstr; 342 if (con->conf.http_parseopts & HTTP_PARSEOPT_URL_NORMALIZE) { 343 /*size_t len = buffer_string_length(con->request.uri);*/ 344 int qs = burl_normalize(con->request.uri, srv->tmp_buf, con->conf.http_parseopts); 345 if (-2 == qs) { 346 log_error_write(srv, __FILE__, __LINE__, "sb", 347 "invalid character in URI -> 400", 348 con->request.uri); 349 con->keep_alive = 0; 350 con->http_status = 400; /* Bad Request */ 351 con->file_finished = 1; 352 return HANDLER_FINISHED; 353 } 354 qstr = (-1 == qs) ? NULL : con->request.uri->ptr+qs; 355 #if 0 /* future: might enable here, or below for all requests */ 356 /* (Note: total header size not recalculated on HANDLER_COMEBACK 357 * even if other request headers changed during processing) 358 * (If (0 != con->loops_per_request), then the generated request 359 * is too large. Should a different error be returned?) */ 360 con->header_len -= len; 361 len = buffer_string_length(con->request.uri); 362 con->header_len += len; 363 if (len > MAX_HTTP_REQUEST_URI) { 364 con->keep_alive = 0; 365 con->http_status = 414; /* Request-URI Too Long */ 366 con->file_finished = 1; 367 return HANDLER_FINISHED; 368 } 369 if (con->header_len > MAX_HTTP_REQUEST_HEADER) { 370 log_error_write(srv, __FILE__, __LINE__, "sds", 371 "request header fields too large:", con->header_len, "-> 431"); 372 con->keep_alive = 0; 373 con->http_status = 431; /* Request Header Fields Too Large */ 374 con->file_finished = 1; 375 return HANDLER_FINISHED; 376 } 377 #endif 378 } else { 379 size_t rlen = buffer_string_length(con->request.uri); 380 qstr = memchr(con->request.uri->ptr, '#', rlen);/* discard fragment */ 381 if (qstr) { 382 rlen = (size_t)(qstr - con->request.uri->ptr); 383 buffer_string_set_length(con->request.uri, rlen); 384 } 385 qstr = memchr(con->request.uri->ptr, '?', rlen); 386 } 387 388 /** extract query string from request.uri */ 389 if (NULL != qstr) { 390 const char * const pstr = con->request.uri->ptr; 391 const size_t plen = (size_t)(qstr - pstr); 392 const size_t rlen = buffer_string_length(con->request.uri); 393 buffer_copy_string_len(con->uri.query, qstr + 1, rlen - plen - 1); 394 buffer_copy_string_len(con->uri.path_raw, pstr, plen); 395 } else { 396 buffer_reset(con->uri.query); 397 buffer_copy_buffer(con->uri.path_raw, con->request.uri); 398 } 399 400 /* decode url to path 401 * 402 * - decode url-encodings (e.g. %20 -> ' ') 403 * - remove path-modifiers (e.g. /../) 404 */ 405 406 buffer_copy_buffer(con->uri.path, con->uri.path_raw); 407 buffer_urldecode_path(con->uri.path); 408 buffer_path_simplify(con->uri.path, con->uri.path); 409 if (buffer_string_is_empty(con->uri.path) || con->uri.path->ptr[0] != '/') { 410 log_error_write(srv, __FILE__, __LINE__, "sbs", 411 "uri-path does not begin with '/':", con->uri.path, "-> 400"); 412 con->keep_alive = 0; 413 con->http_status = 400; 414 con->file_finished = 1; 415 return HANDLER_FINISHED; 416 } 417 } 418 419 con->conditional_is_valid[COMP_SERVER_SOCKET] = 1; /* SERVERsocket */ 420 con->conditional_is_valid[COMP_HTTP_SCHEME] = 1; /* Scheme: */ 421 con->conditional_is_valid[COMP_HTTP_HOST] = 1; /* Host: */ 422 con->conditional_is_valid[COMP_HTTP_REMOTE_IP] = 1; /* Client-IP */ 423 con->conditional_is_valid[COMP_HTTP_REQUEST_METHOD] = 1; /* REQUEST_METHOD */ 424 con->conditional_is_valid[COMP_HTTP_URL] = 1; /* HTTPurl */ 425 con->conditional_is_valid[COMP_HTTP_QUERY_STRING] = 1; /* HTTPqs */ 426 con->conditional_is_valid[COMP_HTTP_REQUEST_HEADER] = 1; /* HTTP request header */ 427 config_patch_connection(srv, con); 428 429 /* do we have to downgrade to 1.0 ? */ 430 if (!con->conf.allow_http11) { 431 con->request.http_version = HTTP_VERSION_1_0; 432 } 433 434 if (con->conf.log_request_handling) { 435 log_error_write(srv, __FILE__, __LINE__, "s", "-- splitting Request-URI"); 436 log_error_write(srv, __FILE__, __LINE__, "sb", "Request-URI : ", con->request.uri); 437 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-scheme : ", con->uri.scheme); 438 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-authority : ", con->uri.authority); 439 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (raw) : ", con->uri.path_raw); 440 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path (clean): ", con->uri.path); 441 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query); 442 } 443 444 /* con->conf.max_request_size is in kBytes */ 445 if (0 != con->conf.max_request_size && 446 (off_t)con->request.content_length > ((off_t)con->conf.max_request_size << 10)) { 447 log_error_write(srv, __FILE__, __LINE__, "sos", 448 "request-size too long:", (off_t) con->request.content_length, "-> 413"); 449 con->keep_alive = 0; 450 con->http_status = 413; 451 con->file_finished = 1; 452 453 return HANDLER_FINISHED; 454 } 455 456 457 } 458 con->async_callback = 0; /* reset */ 459 460 461 /** 462 * 463 * call plugins 464 * 465 * - based on the raw URL 466 * 467 */ 468 469 switch(r = plugins_call_handle_uri_raw(srv, con)) { 470 case HANDLER_GO_ON: 471 break; 472 case HANDLER_FINISHED: 473 case HANDLER_COMEBACK: 474 case HANDLER_WAIT_FOR_EVENT: 475 case HANDLER_ERROR: 476 return r; 477 default: 478 log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r); 479 break; 480 } 481 482 /** 483 * 484 * call plugins 485 * 486 * - based on the clean URL 487 * 488 */ 489 490 switch(r = plugins_call_handle_uri_clean(srv, con)) { 491 case HANDLER_GO_ON: 492 break; 493 case HANDLER_FINISHED: 494 case HANDLER_COMEBACK: 495 case HANDLER_WAIT_FOR_EVENT: 496 case HANDLER_ERROR: 497 return r; 498 default: 499 log_error_write(srv, __FILE__, __LINE__, ""); 500 break; 501 } 502 503 if (con->request.http_method == HTTP_METHOD_OPTIONS && 504 con->uri.path->ptr[0] == '*' && con->uri.path->ptr[1] == '\0') { 505 /* option requests are handled directly without checking of the path */ 506 507 http_header_response_append(con, HTTP_HEADER_OTHER, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); 508 509 con->http_status = 200; 510 con->file_finished = 1; 511 512 return HANDLER_FINISHED; 513 } 514 515 if (con->request.http_method == HTTP_METHOD_CONNECT && con->mode == DIRECT) { 516 con->keep_alive = 0; 517 con->http_status = 405; /* Method Not Allowed */ 518 con->file_finished = 1; 519 return HANDLER_FINISHED; 520 } 521 522 /*** 523 * 524 * border 525 * 526 * logical filename (URI) becomes a physical filename here 527 * 528 * 529 * 530 */ 531 532 533 534 535 /* 1. stat() 536 * ... ISREG() -> ok, go on 537 * ... ISDIR() -> index-file -> redirect 538 * 539 * 2. pathinfo() 540 * ... ISREG() 541 * 542 * 3. -> 404 543 * 544 */ 545 546 /* 547 * SEARCH DOCUMENT ROOT 548 */ 549 550 /* set a default */ 551 552 buffer_copy_buffer(con->physical.doc_root, con->conf.document_root); 553 buffer_copy_buffer(con->physical.rel_path, con->uri.path); 554 555 #if defined(__WIN32) || defined(__CYGWIN__) 556 /* strip dots from the end and spaces 557 * 558 * windows/dos handle those filenames as the same file 559 * 560 * foo == foo. == foo..... == "foo... " == "foo.. ./" 561 * 562 * This will affect in some cases PATHINFO 563 * 564 * on native windows we could prepend the filename with \\?\ to circumvent 565 * this behaviour. I have no idea how to push this through cygwin 566 * 567 * */ 568 569 if (con->physical.rel_path->used > 1) { 570 buffer *b = con->physical.rel_path; 571 size_t len = buffer_string_length(b); 572 573 /* strip trailing " /" or "./" once */ 574 if (len > 1 && 575 b->ptr[len - 1] == '/' && 576 (b->ptr[len - 2] == ' ' || b->ptr[len - 2] == '.')) { 577 len -= 2; 578 } 579 /* strip all trailing " " and "." */ 580 while (len > 0 && ( ' ' == b->ptr[len-1] || '.' == b->ptr[len-1] ) ) --len; 581 buffer_string_set_length(b, len); 582 } 583 #endif 584 585 if (con->conf.log_request_handling) { 586 log_error_write(srv, __FILE__, __LINE__, "s", "-- before doc_root"); 587 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); 588 log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); 589 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 590 } 591 /* the docroot plugin should set the doc_root and might also set the physical.path 592 * for us (all vhost-plugins are supposed to set the doc_root) 593 * */ 594 switch(r = plugins_call_handle_docroot(srv, con)) { 595 case HANDLER_GO_ON: 596 break; 597 case HANDLER_FINISHED: 598 case HANDLER_COMEBACK: 599 case HANDLER_WAIT_FOR_EVENT: 600 case HANDLER_ERROR: 601 return r; 602 default: 603 log_error_write(srv, __FILE__, __LINE__, ""); 604 break; 605 } 606 607 /* MacOS X and Windows can't distiguish between upper and lower-case 608 * 609 * convert to lower-case 610 */ 611 if (con->conf.force_lowercase_filenames) { 612 buffer_to_lower(con->physical.rel_path); 613 } 614 615 /* the docroot plugins might set the servername, if they don't we take http-host */ 616 if (buffer_string_is_empty(con->server_name)) { 617 buffer_copy_buffer(con->server_name, con->uri.authority); 618 } 619 620 /** 621 * create physical filename 622 * -> physical.path = docroot + rel_path 623 * 624 */ 625 626 buffer_copy_buffer(con->physical.basedir, con->physical.doc_root); 627 buffer_copy_buffer(con->physical.path, con->physical.doc_root); 628 buffer_append_path_len(con->physical.path, CONST_BUF_LEN(con->physical.rel_path)); 629 630 if (con->conf.log_request_handling) { 631 log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root"); 632 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); 633 log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); 634 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 635 } 636 637 if (con->request.http_method == HTTP_METHOD_CONNECT) { 638 /* do not permit CONNECT requests to hit filesystem hooks 639 * since the CONNECT URI bypassed path normalization */ 640 /* (This check is located here so that con->physical.path 641 * is filled in above to avoid repeating work next time 642 * http_response_prepare() is called while processing request) */ 643 } else 644 switch(r = plugins_call_handle_physical(srv, con)) { 645 case HANDLER_GO_ON: 646 break; 647 case HANDLER_FINISHED: 648 case HANDLER_COMEBACK: 649 case HANDLER_WAIT_FOR_EVENT: 650 case HANDLER_ERROR: 651 return r; 652 default: 653 log_error_write(srv, __FILE__, __LINE__, ""); 654 break; 655 } 656 657 if (con->conf.log_request_handling) { 658 log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical"); 659 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); 660 log_error_write(srv, __FILE__, __LINE__, "sb", "Basedir :", con->physical.basedir); 661 log_error_write(srv, __FILE__, __LINE__, "sb", "Rel-Path :", con->physical.rel_path); 662 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 663 } 664 } 665 666 /* 667 * Noone catched away the file from normal path of execution yet (like mod_access) 668 * 669 * Go on and check of the file exists at all 670 */ 671 672 if (con->mode == DIRECT) { 673 if (con->conf.log_request_handling) { 674 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path"); 675 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 676 } 677 678 r = http_response_physical_path_check(srv, con); 679 if (HANDLER_GO_ON != r) return r; 680 681 if (con->conf.log_request_handling) { 682 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest"); 683 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); 684 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); 685 log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo); 686 } 687 688 /* call the handlers */ 689 r = plugins_call_handle_subrequest_start(srv, con); 690 if (HANDLER_GO_ON != r) { 691 if (con->conf.log_request_handling) { 692 log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished"); 693 } 694 return r; 695 } 696 697 /* if we are still here, no one wanted the file, status 403 is ok I think */ 698 if (con->mode == DIRECT && con->http_status == 0) { 699 con->http_status = (con->request.http_method != HTTP_METHOD_OPTIONS) ? 403 : 200; 700 return HANDLER_FINISHED; 701 } 702 703 } 704 705 r = plugins_call_handle_subrequest(srv, con); 706 if (HANDLER_GO_ON == r) r = HANDLER_FINISHED; /* request was not handled, looks like we are done */ 707 return r; 708 } 709