1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* 18 * http_protocol.c --- routines which directly communicate with the client. 19 * 20 * Code originally by Rob McCool; much redone by Robert S. Thau 21 * and the Apache Software Foundation. 22 */ 23 24#include "apr.h" 25#include "apr_strings.h" 26#include "apr_buckets.h" 27#include "apr_lib.h" 28#include "apr_signal.h" 29 30#define APR_WANT_STDIO /* for sscanf */ 31#define APR_WANT_STRFUNC 32#define APR_WANT_MEMFUNC 33#include "apr_want.h" 34 35#include "util_filter.h" 36#include "ap_config.h" 37#include "httpd.h" 38#include "http_config.h" 39#include "http_core.h" 40#include "http_protocol.h" 41#include "http_main.h" 42#include "http_request.h" 43#include "http_vhost.h" 44#include "http_log.h" /* For errors detected in basic auth common 45 * support code... */ 46#include "apr_date.h" /* For apr_date_parse_http and APR_DATE_BAD */ 47#include "util_charset.h" 48#include "util_ebcdic.h" 49#include "util_time.h" 50#include "ap_mpm.h" 51 52#include "mod_core.h" 53 54#if APR_HAVE_STDARG_H 55#include <stdarg.h> 56#endif 57#if APR_HAVE_UNISTD_H 58#include <unistd.h> 59#endif 60 61APLOG_USE_MODULE(http); 62 63/* New Apache routine to map status codes into array indicies 64 * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ... 65 * The number of status lines must equal the value of 66 * RESPONSE_CODES (httpd.h) and must be listed in order. 67 * No gaps are allowed between X00 and the largest Xnn 68 * for any X (see ap_index_of_response). 69 * When adding a new code here, add a define to httpd.h 70 * as well. 71 */ 72 73static const char * const status_lines[RESPONSE_CODES] = 74{ 75 "100 Continue", 76 "101 Switching Protocols", 77 "102 Processing", 78#define LEVEL_200 3 79 "200 OK", 80 "201 Created", 81 "202 Accepted", 82 "203 Non-Authoritative Information", 83 "204 No Content", 84 "205 Reset Content", 85 "206 Partial Content", 86 "207 Multi-Status", 87 "208 Already Reported", 88 NULL, /* 209 */ 89 NULL, /* 210 */ 90 NULL, /* 211 */ 91 NULL, /* 212 */ 92 NULL, /* 213 */ 93 NULL, /* 214 */ 94 NULL, /* 215 */ 95 NULL, /* 216 */ 96 NULL, /* 217 */ 97 NULL, /* 218 */ 98 NULL, /* 219 */ 99 NULL, /* 220 */ 100 NULL, /* 221 */ 101 NULL, /* 222 */ 102 NULL, /* 223 */ 103 NULL, /* 224 */ 104 NULL, /* 225 */ 105 "226 IM Used", 106#define LEVEL_300 30 107 "300 Multiple Choices", 108 "301 Moved Permanently", 109 "302 Found", 110 "303 See Other", 111 "304 Not Modified", 112 "305 Use Proxy", 113 NULL, /* 306 */ 114 "307 Temporary Redirect", 115 "308 Permanent Redirect", 116#define LEVEL_400 39 117 "400 Bad Request", 118 "401 Unauthorized", 119 "402 Payment Required", 120 "403 Forbidden", 121 "404 Not Found", 122 "405 Method Not Allowed", 123 "406 Not Acceptable", 124 "407 Proxy Authentication Required", 125 "408 Request Timeout", 126 "409 Conflict", 127 "410 Gone", 128 "411 Length Required", 129 "412 Precondition Failed", 130 "413 Request Entity Too Large", 131 "414 Request-URI Too Long", 132 "415 Unsupported Media Type", 133 "416 Requested Range Not Satisfiable", 134 "417 Expectation Failed", 135 NULL, /* 418 */ 136 NULL, /* 419 */ 137 NULL, /* 420 */ 138 NULL, /* 421 */ 139 "422 Unprocessable Entity", 140 "423 Locked", 141 "424 Failed Dependency", 142 NULL, /* 425 */ 143 "426 Upgrade Required", 144 NULL, /* 427 */ 145 "428 Precondition Required", 146 "429 Too Many Requests", 147 NULL, /* 430 */ 148 "431 Request Header Fields Too Large", 149#define LEVEL_500 71 150 "500 Internal Server Error", 151 "501 Not Implemented", 152 "502 Bad Gateway", 153 "503 Service Unavailable", 154 "504 Gateway Timeout", 155 "505 HTTP Version Not Supported", 156 "506 Variant Also Negotiates", 157 "507 Insufficient Storage", 158 "508 Loop Detected", 159 NULL, /* 509 */ 160 "510 Not Extended", 161 "511 Network Authentication Required" 162}; 163 164APR_HOOK_STRUCT( 165 APR_HOOK_LINK(insert_error_filter) 166) 167 168AP_IMPLEMENT_HOOK_VOID(insert_error_filter, (request_rec *r), (r)) 169 170/* The index of the first bit field that is used to index into a limit 171 * bitmask. M_INVALID + 1 to METHOD_NUMBER_LAST. 172 */ 173#define METHOD_NUMBER_FIRST (M_INVALID + 1) 174 175/* The max method number. Method numbers are used to shift bitmasks, 176 * so this cannot exceed 63, and all bits high is equal to -1, which is a 177 * special flag, so the last bit used has index 62. 178 */ 179#define METHOD_NUMBER_LAST 62 180 181static int is_mpm_running(void) 182{ 183 int mpm_state = 0; 184 185 if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) { 186 return 0; 187 } 188 189 if (mpm_state == AP_MPMQ_STOPPING) { 190 return 0; 191 } 192 193 return 1; 194} 195 196 197AP_DECLARE(int) ap_set_keepalive(request_rec *r) 198{ 199 int ka_sent = 0; 200 int left = r->server->keep_alive_max - r->connection->keepalives; 201 int wimpy = ap_find_token(r->pool, 202 apr_table_get(r->headers_out, "Connection"), 203 "close"); 204 const char *conn = apr_table_get(r->headers_in, "Connection"); 205 206 /* The following convoluted conditional determines whether or not 207 * the current connection should remain persistent after this response 208 * (a.k.a. HTTP Keep-Alive) and whether or not the output message 209 * body should use the HTTP/1.1 chunked transfer-coding. In English, 210 * 211 * IF we have not marked this connection as errored; 212 * and the client isn't expecting 100-continue (PR47087 - more 213 * input here could be the client continuing when we're 214 * closing the request). 215 * and the response body has a defined length due to the status code 216 * being 304 or 204, the request method being HEAD, already 217 * having defined Content-Length or Transfer-Encoding: chunked, or 218 * the request version being HTTP/1.1 and thus capable of being set 219 * as chunked [we know the (r->chunked = 1) side-effect is ugly]; 220 * and the server configuration enables keep-alive; 221 * and the server configuration has a reasonable inter-request timeout; 222 * and there is no maximum # requests or the max hasn't been reached; 223 * and the response status does not require a close; 224 * and the response generator has not already indicated close; 225 * and the client did not request non-persistence (Connection: close); 226 * and we haven't been configured to ignore the buggy twit 227 * or they're a buggy twit coming through a HTTP/1.1 proxy 228 * and the client is requesting an HTTP/1.0-style keep-alive 229 * or the client claims to be HTTP/1.1 compliant (perhaps a proxy); 230 * and this MPM process is not already exiting 231 * THEN we can be persistent, which requires more headers be output. 232 * 233 * Note that the condition evaluation order is extremely important. 234 */ 235 if ((r->connection->keepalive != AP_CONN_CLOSE) 236 && !r->expecting_100 237 && ((r->status == HTTP_NOT_MODIFIED) 238 || (r->status == HTTP_NO_CONTENT) 239 || r->header_only 240 || apr_table_get(r->headers_out, "Content-Length") 241 || ap_find_last_token(r->pool, 242 apr_table_get(r->headers_out, 243 "Transfer-Encoding"), 244 "chunked") 245 || ((r->proto_num >= HTTP_VERSION(1,1)) 246 && (r->chunked = 1))) /* THIS CODE IS CORRECT, see above. */ 247 && r->server->keep_alive 248 && (r->server->keep_alive_timeout > 0) 249 && ((r->server->keep_alive_max == 0) 250 || (left > 0)) 251 && !ap_status_drops_connection(r->status) 252 && !wimpy 253 && !ap_find_token(r->pool, conn, "close") 254 && (!apr_table_get(r->subprocess_env, "nokeepalive") 255 || apr_table_get(r->headers_in, "Via")) 256 && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) 257 || (r->proto_num >= HTTP_VERSION(1,1))) 258 && is_mpm_running()) { 259 260 r->connection->keepalive = AP_CONN_KEEPALIVE; 261 r->connection->keepalives++; 262 263 /* If they sent a Keep-Alive token, send one back */ 264 if (ka_sent) { 265 if (r->server->keep_alive_max) { 266 apr_table_setn(r->headers_out, "Keep-Alive", 267 apr_psprintf(r->pool, "timeout=%d, max=%d", 268 (int)apr_time_sec(r->server->keep_alive_timeout), 269 left)); 270 } 271 else { 272 apr_table_setn(r->headers_out, "Keep-Alive", 273 apr_psprintf(r->pool, "timeout=%d", 274 (int)apr_time_sec(r->server->keep_alive_timeout))); 275 } 276 apr_table_mergen(r->headers_out, "Connection", "Keep-Alive"); 277 } 278 279 return 1; 280 } 281 282 /* Otherwise, we need to indicate that we will be closing this 283 * connection immediately after the current response. 284 * 285 * We only really need to send "close" to HTTP/1.1 clients, but we 286 * always send it anyway, because a broken proxy may identify itself 287 * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag 288 * to a HTTP/1.1 client. Better safe than sorry. 289 */ 290 if (!wimpy) { 291 apr_table_mergen(r->headers_out, "Connection", "close"); 292 } 293 294 /* 295 * If we had previously been a keepalive connection and this 296 * is the last one, then bump up the number of keepalives 297 * we've had 298 */ 299 if ((r->connection->keepalive != AP_CONN_CLOSE) 300 && r->server->keep_alive_max 301 && !left) { 302 r->connection->keepalives++; 303 } 304 r->connection->keepalive = AP_CONN_CLOSE; 305 306 return 0; 307} 308 309AP_DECLARE(ap_condition_e) ap_condition_if_match(request_rec *r, 310 apr_table_t *headers) 311{ 312 const char *if_match, *etag; 313 314 /* A server MUST use the strong comparison function (see section 13.3.3) 315 * to compare the entity tags in If-Match. 316 */ 317 if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) { 318 if (if_match[0] == '*' 319 || ((etag = apr_table_get(headers, "ETag")) == NULL 320 && !ap_find_etag_strong(r->pool, if_match, etag))) { 321 return AP_CONDITION_STRONG; 322 } 323 else { 324 return AP_CONDITION_NOMATCH; 325 } 326 } 327 328 return AP_CONDITION_NONE; 329} 330 331AP_DECLARE(ap_condition_e) ap_condition_if_unmodified_since(request_rec *r, 332 apr_table_t *headers) 333{ 334 const char *if_unmodified; 335 336 if_unmodified = apr_table_get(r->headers_in, "If-Unmodified-Since"); 337 if (if_unmodified) { 338 apr_int64_t mtime, reqtime; 339 340 apr_time_t ius = apr_time_sec(apr_date_parse_http(if_unmodified)); 341 342 /* All of our comparisons must be in seconds, because that's the 343 * highest time resolution the HTTP specification allows. 344 */ 345 mtime = apr_time_sec(apr_date_parse_http( 346 apr_table_get(headers, "Last-Modified"))); 347 if (mtime == APR_DATE_BAD) { 348 mtime = apr_time_sec(r->mtime ? r->mtime : apr_time_now()); 349 } 350 351 reqtime = apr_time_sec(apr_date_parse_http( 352 apr_table_get(headers, "Date"))); 353 if (!reqtime) { 354 reqtime = apr_time_sec(r->request_time); 355 } 356 357 if ((ius != APR_DATE_BAD) && (mtime > ius)) { 358 if (reqtime < mtime + 60) { 359 if (apr_table_get(r->headers_in, "Range")) { 360 /* weak matches not allowed with Range requests */ 361 return AP_CONDITION_NOMATCH; 362 } 363 else { 364 return AP_CONDITION_WEAK; 365 } 366 } 367 else { 368 return AP_CONDITION_STRONG; 369 } 370 } 371 else { 372 return AP_CONDITION_NOMATCH; 373 } 374 } 375 376 return AP_CONDITION_NONE; 377} 378 379AP_DECLARE(ap_condition_e) ap_condition_if_none_match(request_rec *r, 380 apr_table_t *headers) 381{ 382 const char *if_nonematch, *etag; 383 384 if_nonematch = apr_table_get(r->headers_in, "If-None-Match"); 385 if (if_nonematch != NULL) { 386 387 if (if_nonematch[0] == '*') { 388 return AP_CONDITION_STRONG; 389 } 390 391 /* See section 13.3.3 for rules on how to determine if two entities tags 392 * match. The weak comparison function can only be used with GET or HEAD 393 * requests. 394 */ 395 if (r->method_number == M_GET) { 396 if ((etag = apr_table_get(headers, "ETag")) != NULL) { 397 if (apr_table_get(r->headers_in, "Range")) { 398 if (ap_find_etag_strong(r->pool, if_nonematch, etag)) { 399 return AP_CONDITION_STRONG; 400 } 401 } 402 else { 403 if (ap_find_etag_weak(r->pool, if_nonematch, etag)) { 404 return AP_CONDITION_WEAK; 405 } 406 } 407 } 408 } 409 410 else if ((etag = apr_table_get(headers, "ETag")) != NULL 411 && ap_find_etag_strong(r->pool, if_nonematch, etag)) { 412 return AP_CONDITION_STRONG; 413 } 414 return AP_CONDITION_NOMATCH; 415 } 416 417 return AP_CONDITION_NONE; 418} 419 420AP_DECLARE(ap_condition_e) ap_condition_if_modified_since(request_rec *r, 421 apr_table_t *headers) 422{ 423 const char *if_modified_since; 424 425 if ((if_modified_since = apr_table_get(r->headers_in, "If-Modified-Since")) 426 != NULL) { 427 apr_int64_t mtime; 428 apr_int64_t ims, reqtime; 429 430 /* All of our comparisons must be in seconds, because that's the 431 * highest time resolution the HTTP specification allows. 432 */ 433 434 mtime = apr_time_sec(apr_date_parse_http( 435 apr_table_get(headers, "Last-Modified"))); 436 if (mtime == APR_DATE_BAD) { 437 mtime = apr_time_sec(r->mtime ? r->mtime : apr_time_now()); 438 } 439 440 reqtime = apr_time_sec(apr_date_parse_http( 441 apr_table_get(headers, "Date"))); 442 if (!reqtime) { 443 reqtime = apr_time_sec(r->request_time); 444 } 445 446 ims = apr_time_sec(apr_date_parse_http(if_modified_since)); 447 448 if (ims >= mtime && ims <= reqtime) { 449 if (reqtime < mtime + 60) { 450 if (apr_table_get(r->headers_in, "Range")) { 451 /* weak matches not allowed with Range requests */ 452 return AP_CONDITION_NOMATCH; 453 } 454 else { 455 return AP_CONDITION_WEAK; 456 } 457 } 458 else { 459 return AP_CONDITION_STRONG; 460 } 461 } 462 else { 463 return AP_CONDITION_NOMATCH; 464 } 465 } 466 467 return AP_CONDITION_NONE; 468} 469 470AP_DECLARE(ap_condition_e) ap_condition_if_range(request_rec *r, 471 apr_table_t *headers) 472{ 473 const char *if_range, *etag; 474 475 if ((if_range = apr_table_get(r->headers_in, "If-Range")) 476 && apr_table_get(r->headers_in, "Range")) { 477 if (if_range[0] == '"') { 478 479 if ((etag = apr_table_get(headers, "ETag")) 480 && !strcmp(if_range, etag)) { 481 return AP_CONDITION_STRONG; 482 } 483 else { 484 return AP_CONDITION_NOMATCH; 485 } 486 487 } 488 else { 489 apr_int64_t mtime; 490 apr_int64_t rtime, reqtime; 491 492 /* All of our comparisons must be in seconds, because that's the 493 * highest time resolution the HTTP specification allows. 494 */ 495 496 mtime = apr_time_sec(apr_date_parse_http( 497 apr_table_get(headers, "Last-Modified"))); 498 if (mtime == APR_DATE_BAD) { 499 mtime = apr_time_sec(r->mtime ? r->mtime : apr_time_now()); 500 } 501 502 reqtime = apr_time_sec(apr_date_parse_http( 503 apr_table_get(headers, "Date"))); 504 if (!reqtime) { 505 reqtime = apr_time_sec(r->request_time); 506 } 507 508 rtime = apr_time_sec(apr_date_parse_http(if_range)); 509 510 if (rtime == mtime) { 511 if (reqtime < mtime + 60) { 512 /* weak matches not allowed with Range requests */ 513 return AP_CONDITION_NOMATCH; 514 } 515 else { 516 return AP_CONDITION_STRONG; 517 } 518 } 519 else { 520 return AP_CONDITION_NOMATCH; 521 } 522 } 523 } 524 525 return AP_CONDITION_NONE; 526} 527 528AP_DECLARE(int) ap_meets_conditions(request_rec *r) 529{ 530 int not_modified = -1; /* unset by default */ 531 ap_condition_e cond; 532 533 /* Check for conditional requests --- note that we only want to do 534 * this if we are successful so far and we are not processing a 535 * subrequest or an ErrorDocument. 536 * 537 * The order of the checks is important, since ETag checks are supposed 538 * to be more accurate than checks relative to the modification time. 539 * However, not all documents are guaranteed to *have* ETags, and some 540 * might have Last-Modified values w/o ETags, so this gets a little 541 * complicated. 542 */ 543 544 if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) { 545 return OK; 546 } 547 548 /* If an If-Match request-header field was given 549 * AND the field value is not "*" (meaning match anything) 550 * AND if our strong ETag does not match any entity tag in that field, 551 * respond with a status of 412 (Precondition Failed). 552 */ 553 cond = ap_condition_if_match(r, r->headers_out); 554 if (AP_CONDITION_NOMATCH == cond) { 555 not_modified = 0; 556 } 557 else if (cond >= AP_CONDITION_WEAK) { 558 return HTTP_PRECONDITION_FAILED; 559 } 560 561 /* Else if a valid If-Unmodified-Since request-header field was given 562 * AND the requested resource has been modified since the time 563 * specified in this field, then the server MUST 564 * respond with a status of 412 (Precondition Failed). 565 */ 566 cond = ap_condition_if_unmodified_since(r, r->headers_out); 567 if (AP_CONDITION_NOMATCH == cond) { 568 not_modified = 0; 569 } 570 else if (cond >= AP_CONDITION_WEAK) { 571 return HTTP_PRECONDITION_FAILED; 572 } 573 574 /* If an If-None-Match request-header field was given 575 * AND the field value is "*" (meaning match anything) 576 * OR our ETag matches any of the entity tags in that field, fail. 577 * 578 * If the request method was GET or HEAD, failure means the server 579 * SHOULD respond with a 304 (Not Modified) response. 580 * For all other request methods, failure means the server MUST 581 * respond with a status of 412 (Precondition Failed). 582 * 583 * GET or HEAD allow weak etag comparison, all other methods require 584 * strong comparison. We can only use weak if it's not a range request. 585 */ 586 cond = ap_condition_if_none_match(r, r->headers_out); 587 if (AP_CONDITION_NOMATCH == cond) { 588 not_modified = 0; 589 } 590 else if (cond >= AP_CONDITION_WEAK) { 591 if (r->method_number == M_GET) { 592 if (not_modified) { 593 not_modified = 1; 594 } 595 } 596 else { 597 return HTTP_PRECONDITION_FAILED; 598 } 599 } 600 601 /* If a valid If-Modified-Since request-header field was given 602 * AND it is a GET or HEAD request 603 * AND the requested resource has not been modified since the time 604 * specified in this field, then the server MUST 605 * respond with a status of 304 (Not Modified). 606 * A date later than the server's current request time is invalid. 607 */ 608 cond = ap_condition_if_modified_since(r, r->headers_out); 609 if (AP_CONDITION_NOMATCH == cond) { 610 not_modified = 0; 611 } 612 else if (cond >= AP_CONDITION_WEAK) { 613 if (r->method_number == M_GET) { 614 if (not_modified) { 615 not_modified = 1; 616 } 617 } 618 } 619 620 /* If an If-Range and an Range header is present, we must return 621 * 200 OK. The byterange filter will convert it to a range response. 622 */ 623 cond = ap_condition_if_range(r, r->headers_out); 624 if (cond > AP_CONDITION_NONE) { 625 return OK; 626 } 627 628 if (not_modified == 1) { 629 return HTTP_NOT_MODIFIED; 630 } 631 632 return OK; 633} 634 635/** 636 * Singleton registry of additional methods. This maps new method names 637 * such as "MYGET" to methnums, which are int offsets into bitmasks. 638 * 639 * This follows the same technique as standard M_GET, M_POST, etc. These 640 * are dynamically assigned when modules are loaded and <Limit GET MYGET> 641 * directives are processed. 642 */ 643static apr_hash_t *methods_registry = NULL; 644static int cur_method_number = METHOD_NUMBER_FIRST; 645 646/* internal function to register one method/number pair */ 647static void register_one_method(apr_pool_t *p, const char *methname, 648 int methnum) 649{ 650 int *pnum = apr_palloc(p, sizeof(*pnum)); 651 652 *pnum = methnum; 653 apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, pnum); 654} 655 656/* This internal function is used to clear the method registry 657 * and reset the cur_method_number counter. 658 */ 659static apr_status_t ap_method_registry_destroy(void *notused) 660{ 661 methods_registry = NULL; 662 cur_method_number = METHOD_NUMBER_FIRST; 663 return APR_SUCCESS; 664} 665 666AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p) 667{ 668 methods_registry = apr_hash_make(p); 669 apr_pool_cleanup_register(p, NULL, 670 ap_method_registry_destroy, 671 apr_pool_cleanup_null); 672 673 /* put all the standard methods into the registry hash to ease the 674 mapping operations between name and number */ 675 register_one_method(p, "GET", M_GET); 676 register_one_method(p, "PUT", M_PUT); 677 register_one_method(p, "POST", M_POST); 678 register_one_method(p, "DELETE", M_DELETE); 679 register_one_method(p, "CONNECT", M_CONNECT); 680 register_one_method(p, "OPTIONS", M_OPTIONS); 681 register_one_method(p, "TRACE", M_TRACE); 682 register_one_method(p, "PATCH", M_PATCH); 683 register_one_method(p, "PROPFIND", M_PROPFIND); 684 register_one_method(p, "PROPPATCH", M_PROPPATCH); 685 register_one_method(p, "MKCOL", M_MKCOL); 686 register_one_method(p, "COPY", M_COPY); 687 register_one_method(p, "MOVE", M_MOVE); 688 register_one_method(p, "LOCK", M_LOCK); 689 register_one_method(p, "UNLOCK", M_UNLOCK); 690 register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL); 691 register_one_method(p, "CHECKOUT", M_CHECKOUT); 692 register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT); 693 register_one_method(p, "CHECKIN", M_CHECKIN); 694 register_one_method(p, "UPDATE", M_UPDATE); 695 register_one_method(p, "LABEL", M_LABEL); 696 register_one_method(p, "REPORT", M_REPORT); 697 register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE); 698 register_one_method(p, "MKACTIVITY", M_MKACTIVITY); 699 register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL); 700 register_one_method(p, "MERGE", M_MERGE); 701} 702 703AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname) 704{ 705 int *methnum; 706 707 if (methods_registry == NULL) { 708 ap_method_registry_init(p); 709 } 710 711 if (methname == NULL) { 712 return M_INVALID; 713 } 714 715 /* Check if the method was previously registered. If it was 716 * return the associated method number. 717 */ 718 methnum = (int *)apr_hash_get(methods_registry, methname, 719 APR_HASH_KEY_STRING); 720 if (methnum != NULL) 721 return *methnum; 722 723 if (cur_method_number > METHOD_NUMBER_LAST) { 724 /* The method registry has run out of dynamically 725 * assignable method numbers. Log this and return M_INVALID. 726 */ 727 ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, APLOGNO(01610) 728 "Maximum new request methods %d reached while " 729 "registering method %s.", 730 METHOD_NUMBER_LAST, methname); 731 return M_INVALID; 732 } 733 734 register_one_method(p, methname, cur_method_number); 735 return cur_method_number++; 736} 737 738#define UNKNOWN_METHOD (-1) 739 740static int lookup_builtin_method(const char *method, apr_size_t len) 741{ 742 /* Note: the following code was generated by the "shilka" tool from 743 the "cocom" parsing/compilation toolkit. It is an optimized lookup 744 based on analysis of the input keywords. Postprocessing was done 745 on the shilka output, but the basic structure and analysis is 746 from there. Should new HTTP methods be added, then manual insertion 747 into this code is fine, or simply re-running the shilka tool on 748 the appropriate input. */ 749 750 /* Note: it is also quite reasonable to just use our method_registry, 751 but I'm assuming (probably incorrectly) we want more speed here 752 (based on the optimizations the previous code was doing). */ 753 754 switch (len) 755 { 756 case 3: 757 switch (method[0]) 758 { 759 case 'P': 760 return (method[1] == 'U' 761 && method[2] == 'T' 762 ? M_PUT : UNKNOWN_METHOD); 763 case 'G': 764 return (method[1] == 'E' 765 && method[2] == 'T' 766 ? M_GET : UNKNOWN_METHOD); 767 default: 768 return UNKNOWN_METHOD; 769 } 770 771 case 4: 772 switch (method[0]) 773 { 774 case 'H': 775 return (method[1] == 'E' 776 && method[2] == 'A' 777 && method[3] == 'D' 778 ? M_GET : UNKNOWN_METHOD); 779 case 'P': 780 return (method[1] == 'O' 781 && method[2] == 'S' 782 && method[3] == 'T' 783 ? M_POST : UNKNOWN_METHOD); 784 case 'M': 785 return (method[1] == 'O' 786 && method[2] == 'V' 787 && method[3] == 'E' 788 ? M_MOVE : UNKNOWN_METHOD); 789 case 'L': 790 return (method[1] == 'O' 791 && method[2] == 'C' 792 && method[3] == 'K' 793 ? M_LOCK : UNKNOWN_METHOD); 794 case 'C': 795 return (method[1] == 'O' 796 && method[2] == 'P' 797 && method[3] == 'Y' 798 ? M_COPY : UNKNOWN_METHOD); 799 default: 800 return UNKNOWN_METHOD; 801 } 802 803 case 5: 804 switch (method[2]) 805 { 806 case 'T': 807 return (memcmp(method, "PATCH", 5) == 0 808 ? M_PATCH : UNKNOWN_METHOD); 809 case 'R': 810 return (memcmp(method, "MERGE", 5) == 0 811 ? M_MERGE : UNKNOWN_METHOD); 812 case 'C': 813 return (memcmp(method, "MKCOL", 5) == 0 814 ? M_MKCOL : UNKNOWN_METHOD); 815 case 'B': 816 return (memcmp(method, "LABEL", 5) == 0 817 ? M_LABEL : UNKNOWN_METHOD); 818 case 'A': 819 return (memcmp(method, "TRACE", 5) == 0 820 ? M_TRACE : UNKNOWN_METHOD); 821 default: 822 return UNKNOWN_METHOD; 823 } 824 825 case 6: 826 switch (method[0]) 827 { 828 case 'U': 829 switch (method[5]) 830 { 831 case 'K': 832 return (memcmp(method, "UNLOCK", 6) == 0 833 ? M_UNLOCK : UNKNOWN_METHOD); 834 case 'E': 835 return (memcmp(method, "UPDATE", 6) == 0 836 ? M_UPDATE : UNKNOWN_METHOD); 837 default: 838 return UNKNOWN_METHOD; 839 } 840 case 'R': 841 return (memcmp(method, "REPORT", 6) == 0 842 ? M_REPORT : UNKNOWN_METHOD); 843 case 'D': 844 return (memcmp(method, "DELETE", 6) == 0 845 ? M_DELETE : UNKNOWN_METHOD); 846 default: 847 return UNKNOWN_METHOD; 848 } 849 850 case 7: 851 switch (method[1]) 852 { 853 case 'P': 854 return (memcmp(method, "OPTIONS", 7) == 0 855 ? M_OPTIONS : UNKNOWN_METHOD); 856 case 'O': 857 return (memcmp(method, "CONNECT", 7) == 0 858 ? M_CONNECT : UNKNOWN_METHOD); 859 case 'H': 860 return (memcmp(method, "CHECKIN", 7) == 0 861 ? M_CHECKIN : UNKNOWN_METHOD); 862 default: 863 return UNKNOWN_METHOD; 864 } 865 866 case 8: 867 switch (method[0]) 868 { 869 case 'P': 870 return (memcmp(method, "PROPFIND", 8) == 0 871 ? M_PROPFIND : UNKNOWN_METHOD); 872 case 'C': 873 return (memcmp(method, "CHECKOUT", 8) == 0 874 ? M_CHECKOUT : UNKNOWN_METHOD); 875 default: 876 return UNKNOWN_METHOD; 877 } 878 879 case 9: 880 return (memcmp(method, "PROPPATCH", 9) == 0 881 ? M_PROPPATCH : UNKNOWN_METHOD); 882 883 case 10: 884 switch (method[0]) 885 { 886 case 'U': 887 return (memcmp(method, "UNCHECKOUT", 10) == 0 888 ? M_UNCHECKOUT : UNKNOWN_METHOD); 889 case 'M': 890 return (memcmp(method, "MKACTIVITY", 10) == 0 891 ? M_MKACTIVITY : UNKNOWN_METHOD); 892 default: 893 return UNKNOWN_METHOD; 894 } 895 896 case 11: 897 return (memcmp(method, "MKWORKSPACE", 11) == 0 898 ? M_MKWORKSPACE : UNKNOWN_METHOD); 899 900 case 15: 901 return (memcmp(method, "VERSION-CONTROL", 15) == 0 902 ? M_VERSION_CONTROL : UNKNOWN_METHOD); 903 904 case 16: 905 return (memcmp(method, "BASELINE-CONTROL", 16) == 0 906 ? M_BASELINE_CONTROL : UNKNOWN_METHOD); 907 908 default: 909 return UNKNOWN_METHOD; 910 } 911 912 /* NOTREACHED */ 913} 914 915/* Get the method number associated with the given string, assumed to 916 * contain an HTTP method. Returns M_INVALID if not recognized. 917 * 918 * This is the first step toward placing method names in a configurable 919 * list. Hopefully it (and other routines) can eventually be moved to 920 * something like a mod_http_methods.c, complete with config stuff. 921 */ 922AP_DECLARE(int) ap_method_number_of(const char *method) 923{ 924 int len = strlen(method); 925 int which = lookup_builtin_method(method, len); 926 927 if (which != UNKNOWN_METHOD) 928 return which; 929 930 /* check if the method has been dynamically registered */ 931 if (methods_registry != NULL) { 932 int *methnum = apr_hash_get(methods_registry, method, len); 933 934 if (methnum != NULL) { 935 return *methnum; 936 } 937 } 938 939 return M_INVALID; 940} 941 942/* 943 * Turn a known method number into a name. 944 */ 945AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum) 946{ 947 apr_hash_index_t *hi = apr_hash_first(p, methods_registry); 948 949 /* scan through the hash table, looking for a value that matches 950 the provided method number. */ 951 for (; hi; hi = apr_hash_next(hi)) { 952 const void *key; 953 void *val; 954 955 apr_hash_this(hi, &key, NULL, &val); 956 if (*(int *)val == methnum) 957 return key; 958 } 959 960 /* it wasn't found in the hash */ 961 return NULL; 962} 963 964/* The index is found by its offset from the x00 code of each level. 965 * Although this is fast, it will need to be replaced if some nutcase 966 * decides to define a high-numbered code before the lower numbers. 967 * If that sad event occurs, replace the code below with a linear search 968 * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1]; 969 * or use NULL to fill the gaps. 970 */ 971AP_DECLARE(int) ap_index_of_response(int status) 972{ 973 static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400, 974 LEVEL_500, RESPONSE_CODES}; 975 int i, pos; 976 977 if (status < 100) { /* Below 100 is illegal for HTTP status */ 978 return LEVEL_500; 979 } 980 981 for (i = 0; i < 5; i++) { 982 status -= 100; 983 if (status < 100) { 984 pos = (status + shortcut[i]); 985 if (pos < shortcut[i + 1] && status_lines[pos] != NULL) { 986 return pos; 987 } 988 else { 989 return LEVEL_500; /* status unknown (falls in gap) */ 990 } 991 } 992 } 993 return LEVEL_500; /* 600 or above is also illegal */ 994} 995 996AP_DECLARE(const char *) ap_get_status_line(int status) 997{ 998 return status_lines[ap_index_of_response(status)]; 999} 1000 1001/* Build the Allow field-value from the request handler method mask. 1002 */ 1003static char *make_allow(request_rec *r) 1004{ 1005 apr_int64_t mask; 1006 apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *)); 1007 apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry); 1008 /* For TRACE below */ 1009 core_server_config *conf = 1010 ap_get_core_module_config(r->server->module_config); 1011 1012 mask = r->allowed_methods->method_mask; 1013 1014 for (; hi; hi = apr_hash_next(hi)) { 1015 const void *key; 1016 void *val; 1017 1018 apr_hash_this(hi, &key, NULL, &val); 1019 if ((mask & (AP_METHOD_BIT << *(int *)val)) != 0) { 1020 *(const char **)apr_array_push(allow) = key; 1021 1022 /* the M_GET method actually refers to two methods */ 1023 if (*(int *)val == M_GET) 1024 *(const char **)apr_array_push(allow) = "HEAD"; 1025 } 1026 } 1027 1028 /* TRACE is tested on a per-server basis */ 1029 if (conf->trace_enable != AP_TRACE_DISABLE) 1030 *(const char **)apr_array_push(allow) = "TRACE"; 1031 1032 /* ### this is rather annoying. we should enforce registration of 1033 ### these methods */ 1034 if ((mask & (AP_METHOD_BIT << M_INVALID)) 1035 && (r->allowed_methods->method_list != NULL) 1036 && (r->allowed_methods->method_list->nelts != 0)) { 1037 apr_array_cat(allow, r->allowed_methods->method_list); 1038 } 1039 1040 return apr_array_pstrcat(r->pool, allow, ','); 1041} 1042 1043AP_DECLARE(int) ap_send_http_options(request_rec *r) 1044{ 1045 if (r->assbackwards) { 1046 return DECLINED; 1047 } 1048 1049 apr_table_setn(r->headers_out, "Allow", make_allow(r)); 1050 1051 /* the request finalization will send an EOS, which will flush all 1052 * the headers out (including the Allow header) 1053 */ 1054 1055 return OK; 1056} 1057 1058AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct) 1059{ 1060 if (!ct) { 1061 r->content_type = NULL; 1062 } 1063 else if (!r->content_type || strcmp(r->content_type, ct)) { 1064 r->content_type = ct; 1065 } 1066} 1067 1068AP_DECLARE(void) ap_set_accept_ranges(request_rec *r) 1069{ 1070 core_dir_config *d = ap_get_core_module_config(r->per_dir_config); 1071 apr_table_setn(r->headers_out, "Accept-Ranges", 1072 (d->max_ranges == AP_MAXRANGES_NORANGES) ? "none" 1073 : "bytes"); 1074} 1075static const char *add_optional_notes(request_rec *r, 1076 const char *prefix, 1077 const char *key, 1078 const char *suffix) 1079{ 1080 const char *notes, *result; 1081 1082 if ((notes = apr_table_get(r->notes, key)) == NULL) { 1083 result = apr_pstrcat(r->pool, prefix, suffix, NULL); 1084 } 1085 else { 1086 result = apr_pstrcat(r->pool, prefix, notes, suffix, NULL); 1087 } 1088 1089 return result; 1090} 1091 1092/* construct and return the default error message for a given 1093 * HTTP defined error code 1094 */ 1095static const char *get_canned_error_string(int status, 1096 request_rec *r, 1097 const char *location) 1098{ 1099 apr_pool_t *p = r->pool; 1100 const char *error_notes, *h1, *s1; 1101 1102 switch (status) { 1103 case HTTP_MOVED_PERMANENTLY: 1104 case HTTP_MOVED_TEMPORARILY: 1105 case HTTP_TEMPORARY_REDIRECT: 1106 case HTTP_PERMANENT_REDIRECT: 1107 return(apr_pstrcat(p, 1108 "<p>The document has moved <a href=\"", 1109 ap_escape_html(r->pool, location), 1110 "\">here</a>.</p>\n", 1111 NULL)); 1112 case HTTP_SEE_OTHER: 1113 return(apr_pstrcat(p, 1114 "<p>The answer to your request is located " 1115 "<a href=\"", 1116 ap_escape_html(r->pool, location), 1117 "\">here</a>.</p>\n", 1118 NULL)); 1119 case HTTP_USE_PROXY: 1120 return(apr_pstrcat(p, 1121 "<p>This resource is only accessible " 1122 "through the proxy\n", 1123 ap_escape_html(r->pool, location), 1124 "<br />\nYou will need to configure " 1125 "your client to use that proxy.</p>\n", 1126 NULL)); 1127 case HTTP_PROXY_AUTHENTICATION_REQUIRED: 1128 case HTTP_UNAUTHORIZED: 1129 return("<p>This server could not verify that you\n" 1130 "are authorized to access the document\n" 1131 "requested. Either you supplied the wrong\n" 1132 "credentials (e.g., bad password), or your\n" 1133 "browser doesn't understand how to supply\n" 1134 "the credentials required.</p>\n"); 1135 case HTTP_BAD_REQUEST: 1136 return(add_optional_notes(r, 1137 "<p>Your browser sent a request that " 1138 "this server could not understand.<br />\n", 1139 "error-notes", 1140 "</p>\n")); 1141 case HTTP_FORBIDDEN: 1142 return(apr_pstrcat(p, 1143 "<p>You don't have permission to access ", 1144 ap_escape_html(r->pool, r->uri), 1145 "\non this server.</p>\n", 1146 NULL)); 1147 case HTTP_NOT_FOUND: 1148 return(apr_pstrcat(p, 1149 "<p>The requested URL ", 1150 ap_escape_html(r->pool, r->uri), 1151 " was not found on this server.</p>\n", 1152 NULL)); 1153 case HTTP_METHOD_NOT_ALLOWED: 1154 return(apr_pstrcat(p, 1155 "<p>The requested method ", 1156 ap_escape_html(r->pool, r->method), 1157 " is not allowed for the URL ", 1158 ap_escape_html(r->pool, r->uri), 1159 ".</p>\n", 1160 NULL)); 1161 case HTTP_NOT_ACCEPTABLE: 1162 s1 = apr_pstrcat(p, 1163 "<p>An appropriate representation of the " 1164 "requested resource ", 1165 ap_escape_html(r->pool, r->uri), 1166 " could not be found on this server.</p>\n", 1167 NULL); 1168 return(add_optional_notes(r, s1, "variant-list", "")); 1169 case HTTP_MULTIPLE_CHOICES: 1170 return(add_optional_notes(r, "", "variant-list", "")); 1171 case HTTP_LENGTH_REQUIRED: 1172 s1 = apr_pstrcat(p, 1173 "<p>A request of the requested method ", 1174 ap_escape_html(r->pool, r->method), 1175 " requires a valid Content-length.<br />\n", 1176 NULL); 1177 return(add_optional_notes(r, s1, "error-notes", "</p>\n")); 1178 case HTTP_PRECONDITION_FAILED: 1179 return(apr_pstrcat(p, 1180 "<p>The precondition on the request " 1181 "for the URL ", 1182 ap_escape_html(r->pool, r->uri), 1183 " evaluated to false.</p>\n", 1184 NULL)); 1185 case HTTP_NOT_IMPLEMENTED: 1186 s1 = apr_pstrcat(p, 1187 "<p>", 1188 ap_escape_html(r->pool, r->method), " to ", 1189 ap_escape_html(r->pool, r->uri), 1190 " not supported.<br />\n", 1191 NULL); 1192 return(add_optional_notes(r, s1, "error-notes", "</p>\n")); 1193 case HTTP_BAD_GATEWAY: 1194 s1 = "<p>The proxy server received an invalid" CRLF 1195 "response from an upstream server.<br />" CRLF; 1196 return(add_optional_notes(r, s1, "error-notes", "</p>\n")); 1197 case HTTP_VARIANT_ALSO_VARIES: 1198 return(apr_pstrcat(p, 1199 "<p>A variant for the requested " 1200 "resource\n<pre>\n", 1201 ap_escape_html(r->pool, r->uri), 1202 "\n</pre>\nis itself a negotiable resource. " 1203 "This indicates a configuration error.</p>\n", 1204 NULL)); 1205 case HTTP_REQUEST_TIME_OUT: 1206 return("<p>Server timeout waiting for the HTTP request from the client.</p>\n"); 1207 case HTTP_GONE: 1208 return(apr_pstrcat(p, 1209 "<p>The requested resource<br />", 1210 ap_escape_html(r->pool, r->uri), 1211 "<br />\nis no longer available on this server " 1212 "and there is no forwarding address.\n" 1213 "Please remove all references to this " 1214 "resource.</p>\n", 1215 NULL)); 1216 case HTTP_REQUEST_ENTITY_TOO_LARGE: 1217 return(apr_pstrcat(p, 1218 "The requested resource<br />", 1219 ap_escape_html(r->pool, r->uri), "<br />\n", 1220 "does not allow request data with ", 1221 ap_escape_html(r->pool, r->method), 1222 " requests, or the amount of data provided in\n" 1223 "the request exceeds the capacity limit.\n", 1224 NULL)); 1225 case HTTP_REQUEST_URI_TOO_LARGE: 1226 s1 = "<p>The requested URL's length exceeds the capacity\n" 1227 "limit for this server.<br />\n"; 1228 return(add_optional_notes(r, s1, "error-notes", "</p>\n")); 1229 case HTTP_UNSUPPORTED_MEDIA_TYPE: 1230 return("<p>The supplied request data is not in a format\n" 1231 "acceptable for processing by this resource.</p>\n"); 1232 case HTTP_RANGE_NOT_SATISFIABLE: 1233 return("<p>None of the range-specifier values in the Range\n" 1234 "request-header field overlap the current extent\n" 1235 "of the selected resource.</p>\n"); 1236 case HTTP_EXPECTATION_FAILED: 1237 s1 = apr_table_get(r->headers_in, "Expect"); 1238 if (s1) 1239 s1 = apr_pstrcat(p, 1240 "<p>The expectation given in the Expect request-header\n" 1241 "field could not be met by this server.\n" 1242 "The client sent<pre>\n Expect: ", 1243 ap_escape_html(r->pool, s1), "\n</pre>\n", 1244 NULL); 1245 else 1246 s1 = "<p>No expectation was seen, the Expect request-header \n" 1247 "field was not presented by the client.\n"; 1248 return add_optional_notes(r, s1, "error-notes", "</p>" 1249 "<p>Only the 100-continue expectation is supported.</p>\n"); 1250 case HTTP_UNPROCESSABLE_ENTITY: 1251 return("<p>The server understands the media type of the\n" 1252 "request entity, but was unable to process the\n" 1253 "contained instructions.</p>\n"); 1254 case HTTP_LOCKED: 1255 return("<p>The requested resource is currently locked.\n" 1256 "The lock must be released or proper identification\n" 1257 "given before the method can be applied.</p>\n"); 1258 case HTTP_FAILED_DEPENDENCY: 1259 return("<p>The method could not be performed on the resource\n" 1260 "because the requested action depended on another\n" 1261 "action and that other action failed.</p>\n"); 1262 case HTTP_UPGRADE_REQUIRED: 1263 return("<p>The requested resource can only be retrieved\n" 1264 "using SSL. The server is willing to upgrade the current\n" 1265 "connection to SSL, but your client doesn't support it.\n" 1266 "Either upgrade your client, or try requesting the page\n" 1267 "using https://\n"); 1268 case HTTP_PRECONDITION_REQUIRED: 1269 return("<p>The request is required to be conditional.</p>\n"); 1270 case HTTP_TOO_MANY_REQUESTS: 1271 return("<p>The user has sent too many requests\n" 1272 "in a given amount of time.</p>\n"); 1273 case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE: 1274 return("<p>The server refused this request because\n" 1275 "the request header fields are too large.</p>\n"); 1276 case HTTP_INSUFFICIENT_STORAGE: 1277 return("<p>The method could not be performed on the resource\n" 1278 "because the server is unable to store the\n" 1279 "representation needed to successfully complete the\n" 1280 "request. There is insufficient free space left in\n" 1281 "your storage allocation.</p>\n"); 1282 case HTTP_SERVICE_UNAVAILABLE: 1283 return("<p>The server is temporarily unable to service your\n" 1284 "request due to maintenance downtime or capacity\n" 1285 "problems. Please try again later.</p>\n"); 1286 case HTTP_GATEWAY_TIME_OUT: 1287 return("<p>The gateway did not receive a timely response\n" 1288 "from the upstream server or application.</p>\n"); 1289 case HTTP_LOOP_DETECTED: 1290 return("<p>The server terminated an operation because\n" 1291 "it encountered an infinite loop.</p>\n"); 1292 case HTTP_NOT_EXTENDED: 1293 return("<p>A mandatory extension policy in the request is not\n" 1294 "accepted by the server for this resource.</p>\n"); 1295 case HTTP_NETWORK_AUTHENTICATION_REQUIRED: 1296 return("<p>The client needs to authenticate to gain\n" 1297 "network access.</p>\n"); 1298 default: /* HTTP_INTERNAL_SERVER_ERROR */ 1299 /* 1300 * This comparison to expose error-notes could be modified to 1301 * use a configuration directive and export based on that 1302 * directive. For now "*" is used to designate an error-notes 1303 * that is totally safe for any user to see (ie lacks paths, 1304 * database passwords, etc.) 1305 */ 1306 if (((error_notes = apr_table_get(r->notes, 1307 "error-notes")) != NULL) 1308 && (h1 = apr_table_get(r->notes, "verbose-error-to")) != NULL 1309 && (strcmp(h1, "*") == 0)) { 1310 return(apr_pstrcat(p, error_notes, "<p />\n", NULL)); 1311 } 1312 else { 1313 return(apr_pstrcat(p, 1314 "<p>The server encountered an internal " 1315 "error or\n" 1316 "misconfiguration and was unable to complete\n" 1317 "your request.</p>\n" 1318 "<p>Please contact the server " 1319 "administrator at \n ", 1320 ap_escape_html(r->pool, 1321 r->server->server_admin), 1322 " to inform them of the time this " 1323 "error occurred,\n" 1324 " and the actions you performed just before " 1325 "this error.</p>\n" 1326 "<p>More information about this error " 1327 "may be available\n" 1328 "in the server error log.</p>\n", 1329 NULL)); 1330 } 1331 /* 1332 * It would be nice to give the user the information they need to 1333 * fix the problem directly since many users don't have access to 1334 * the error_log (think University sites) even though they can easily 1335 * get this error by misconfiguring an htaccess file. However, the 1336 * e error notes tend to include the real file pathname in this case, 1337 * which some people consider to be a breach of privacy. Until we 1338 * can figure out a way to remove the pathname, leave this commented. 1339 * 1340 * if ((error_notes = apr_table_get(r->notes, 1341 * "error-notes")) != NULL) { 1342 * return(apr_pstrcat(p, error_notes, "<p />\n", NULL); 1343 * } 1344 * else { 1345 * return ""; 1346 * } 1347 */ 1348 } 1349} 1350 1351/* We should have named this send_canned_response, since it is used for any 1352 * response that can be generated by the server from the request record. 1353 * This includes all 204 (no content), 3xx (redirect), 4xx (client error), 1354 * and 5xx (server error) messages that have not been redirected to another 1355 * handler via the ErrorDocument feature. 1356 */ 1357AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error) 1358{ 1359 int status = r->status; 1360 int idx = ap_index_of_response(status); 1361 char *custom_response; 1362 const char *location = apr_table_get(r->headers_out, "Location"); 1363 1364 /* At this point, we are starting the response over, so we have to reset 1365 * this value. 1366 */ 1367 r->eos_sent = 0; 1368 1369 /* and we need to get rid of any RESOURCE filters that might be lurking 1370 * around, thinking they are in the middle of the original request 1371 */ 1372 1373 r->output_filters = r->proto_output_filters; 1374 1375 ap_run_insert_error_filter(r); 1376 1377 /* 1378 * It's possible that the Location field might be in r->err_headers_out 1379 * instead of r->headers_out; use the latter if possible, else the 1380 * former. 1381 */ 1382 if (location == NULL) { 1383 location = apr_table_get(r->err_headers_out, "Location"); 1384 } 1385 /* We need to special-case the handling of 204 and 304 responses, 1386 * since they have specific HTTP requirements and do not include a 1387 * message body. Note that being assbackwards here is not an option. 1388 */ 1389 if (status == HTTP_NOT_MODIFIED) { 1390 ap_finalize_request_protocol(r); 1391 return; 1392 } 1393 1394 if (status == HTTP_NO_CONTENT) { 1395 ap_finalize_request_protocol(r); 1396 return; 1397 } 1398 1399 if (!r->assbackwards) { 1400 apr_table_t *tmp = r->headers_out; 1401 1402 /* For all HTTP/1.x responses for which we generate the message, 1403 * we need to avoid inheriting the "normal status" header fields 1404 * that may have been set by the request handler before the 1405 * error or redirect, except for Location on external redirects. 1406 */ 1407 r->headers_out = r->err_headers_out; 1408 r->err_headers_out = tmp; 1409 apr_table_clear(r->err_headers_out); 1410 1411 if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) { 1412 if ((location != NULL) && *location) { 1413 apr_table_setn(r->headers_out, "Location", location); 1414 } 1415 else { 1416 location = ""; /* avoids coredump when printing, below */ 1417 } 1418 } 1419 1420 r->content_languages = NULL; 1421 r->content_encoding = NULL; 1422 r->clength = 0; 1423 1424 if (apr_table_get(r->subprocess_env, 1425 "suppress-error-charset") != NULL) { 1426 core_request_config *request_conf = 1427 ap_get_core_module_config(r->request_config); 1428 request_conf->suppress_charset = 1; /* avoid adding default 1429 * charset later 1430 */ 1431 ap_set_content_type(r, "text/html"); 1432 } 1433 else { 1434 ap_set_content_type(r, "text/html; charset=iso-8859-1"); 1435 } 1436 1437 if ((status == HTTP_METHOD_NOT_ALLOWED) 1438 || (status == HTTP_NOT_IMPLEMENTED)) { 1439 apr_table_setn(r->headers_out, "Allow", make_allow(r)); 1440 } 1441 1442 if (r->header_only) { 1443 ap_finalize_request_protocol(r); 1444 return; 1445 } 1446 } 1447 1448 if ((custom_response = ap_response_code_string(r, idx))) { 1449 /* 1450 * We have a custom response output. This should only be 1451 * a text-string to write back. But if the ErrorDocument 1452 * was a local redirect and the requested resource failed 1453 * for any reason, the custom_response will still hold the 1454 * redirect URL. We don't really want to output this URL 1455 * as a text message, so first check the custom response 1456 * string to ensure that it is a text-string (using the 1457 * same test used in ap_die(), i.e. does it start with a "). 1458 * 1459 * If it's not a text string, we've got a recursive error or 1460 * an external redirect. If it's a recursive error, ap_die passes 1461 * us the second error code so we can write both, and has already 1462 * backed up to the original error. If it's an external redirect, 1463 * it hasn't happened yet; we may never know if it fails. 1464 */ 1465 if (custom_response[0] == '\"') { 1466 ap_rputs(custom_response + 1, r); 1467 ap_finalize_request_protocol(r); 1468 return; 1469 } 1470 } 1471 { 1472 const char *title = status_lines[idx]; 1473 const char *h1; 1474 1475 /* Accept a status_line set by a module, but only if it begins 1476 * with the correct 3 digit status code 1477 */ 1478 if (r->status_line) { 1479 char *end; 1480 int len = strlen(r->status_line); 1481 if (len >= 3 1482 && apr_strtoi64(r->status_line, &end, 10) == r->status 1483 && (end - 3) == r->status_line 1484 && (len < 4 || apr_isspace(r->status_line[3])) 1485 && (len < 5 || apr_isalnum(r->status_line[4]))) { 1486 /* Since we passed the above check, we know that length three 1487 * is equivalent to only a 3 digit numeric http status. 1488 * RFC2616 mandates a trailing space, let's add it. 1489 * If we have an empty reason phrase, we also add "Unknown Reason". 1490 */ 1491 if (len == 3) { 1492 r->status_line = apr_pstrcat(r->pool, r->status_line, " Unknown Reason", NULL); 1493 } else if (len == 4) { 1494 r->status_line = apr_pstrcat(r->pool, r->status_line, "Unknown Reason", NULL); 1495 } 1496 title = r->status_line; 1497 } 1498 } 1499 1500 /* folks decided they didn't want the error code in the H1 text */ 1501 h1 = &title[4]; 1502 1503 /* can't count on a charset filter being in place here, 1504 * so do ebcdic->ascii translation explicitly (if needed) 1505 */ 1506 1507 ap_rvputs_proto_in_ascii(r, 1508 DOCTYPE_HTML_2_0 1509 "<html><head>\n<title>", title, 1510 "</title>\n</head><body>\n<h1>", h1, "</h1>\n", 1511 NULL); 1512 1513 ap_rvputs_proto_in_ascii(r, 1514 get_canned_error_string(status, r, location), 1515 NULL); 1516 1517 if (recursive_error) { 1518 ap_rvputs_proto_in_ascii(r, "<p>Additionally, a ", 1519 status_lines[ap_index_of_response(recursive_error)], 1520 "\nerror was encountered while trying to use an " 1521 "ErrorDocument to handle the request.</p>\n", NULL); 1522 } 1523 ap_rvputs_proto_in_ascii(r, ap_psignature("<hr>\n", r), NULL); 1524 ap_rvputs_proto_in_ascii(r, "</body></html>\n", NULL); 1525 } 1526 ap_finalize_request_protocol(r); 1527} 1528 1529/* 1530 * Create a new method list with the specified number of preallocated 1531 * extension slots. 1532 */ 1533AP_DECLARE(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts) 1534{ 1535 ap_method_list_t *ml; 1536 1537 ml = (ap_method_list_t *) apr_palloc(p, sizeof(ap_method_list_t)); 1538 ml->method_mask = 0; 1539 ml->method_list = apr_array_make(p, nelts, sizeof(char *)); 1540 return ml; 1541} 1542 1543/* 1544 * Make a copy of a method list (primarily for subrequests that may 1545 * subsequently change it; don't want them changing the parent's, too!). 1546 */ 1547AP_DECLARE(void) ap_copy_method_list(ap_method_list_t *dest, 1548 ap_method_list_t *src) 1549{ 1550 int i; 1551 char **imethods; 1552 char **omethods; 1553 1554 dest->method_mask = src->method_mask; 1555 imethods = (char **) src->method_list->elts; 1556 for (i = 0; i < src->method_list->nelts; ++i) { 1557 omethods = (char **) apr_array_push(dest->method_list); 1558 *omethods = apr_pstrdup(dest->method_list->pool, imethods[i]); 1559 } 1560} 1561 1562/* 1563 * Return true if the specified HTTP method is in the provided 1564 * method list. 1565 */ 1566AP_DECLARE(int) ap_method_in_list(ap_method_list_t *l, const char *method) 1567{ 1568 int methnum; 1569 int i; 1570 char **methods; 1571 1572 /* 1573 * If it's one of our known methods, use the shortcut and check the 1574 * bitmask. 1575 */ 1576 methnum = ap_method_number_of(method); 1577 if (methnum != M_INVALID) { 1578 return !!(l->method_mask & (AP_METHOD_BIT << methnum)); 1579 } 1580 /* 1581 * Otherwise, see if the method name is in the array or string names 1582 */ 1583 if ((l->method_list == NULL) || (l->method_list->nelts == 0)) { 1584 return 0; 1585 } 1586 methods = (char **)l->method_list->elts; 1587 for (i = 0; i < l->method_list->nelts; ++i) { 1588 if (strcmp(method, methods[i]) == 0) { 1589 return 1; 1590 } 1591 } 1592 return 0; 1593} 1594 1595/* 1596 * Add the specified method to a method list (if it isn't already there). 1597 */ 1598AP_DECLARE(void) ap_method_list_add(ap_method_list_t *l, const char *method) 1599{ 1600 int methnum; 1601 int i; 1602 const char **xmethod; 1603 char **methods; 1604 1605 /* 1606 * If it's one of our known methods, use the shortcut and use the 1607 * bitmask. 1608 */ 1609 methnum = ap_method_number_of(method); 1610 l->method_mask |= (AP_METHOD_BIT << methnum); 1611 if (methnum != M_INVALID) { 1612 return; 1613 } 1614 /* 1615 * Otherwise, see if the method name is in the array of string names. 1616 */ 1617 if (l->method_list->nelts != 0) { 1618 methods = (char **)l->method_list->elts; 1619 for (i = 0; i < l->method_list->nelts; ++i) { 1620 if (strcmp(method, methods[i]) == 0) { 1621 return; 1622 } 1623 } 1624 } 1625 xmethod = (const char **) apr_array_push(l->method_list); 1626 *xmethod = method; 1627} 1628 1629/* 1630 * Remove the specified method from a method list. 1631 */ 1632AP_DECLARE(void) ap_method_list_remove(ap_method_list_t *l, 1633 const char *method) 1634{ 1635 int methnum; 1636 char **methods; 1637 1638 /* 1639 * If it's a known methods, either builtin or registered 1640 * by a module, use the bitmask. 1641 */ 1642 methnum = ap_method_number_of(method); 1643 l->method_mask |= ~(AP_METHOD_BIT << methnum); 1644 if (methnum != M_INVALID) { 1645 return; 1646 } 1647 /* 1648 * Otherwise, see if the method name is in the array of string names. 1649 */ 1650 if (l->method_list->nelts != 0) { 1651 register int i, j, k; 1652 methods = (char **)l->method_list->elts; 1653 for (i = 0; i < l->method_list->nelts; ) { 1654 if (strcmp(method, methods[i]) == 0) { 1655 for (j = i, k = i + 1; k < l->method_list->nelts; ++j, ++k) { 1656 methods[j] = methods[k]; 1657 } 1658 --l->method_list->nelts; 1659 } 1660 else { 1661 ++i; 1662 } 1663 } 1664 } 1665} 1666 1667/* 1668 * Reset a method list to be completely empty. 1669 */ 1670AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l) 1671{ 1672 l->method_mask = 0; 1673 l->method_list->nelts = 0; 1674} 1675 1676