00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "apr.h"
00025 #include "apr_strings.h"
00026 #include "apr_buckets.h"
00027 #include "apr_lib.h"
00028 #include "apr_signal.h"
00029
00030 #define APR_WANT_STDIO
00031 #define APR_WANT_STRFUNC
00032 #define APR_WANT_MEMFUNC
00033 #include "apr_want.h"
00034
00035 #define CORE_PRIVATE
00036 #include "util_filter.h"
00037 #include "ap_config.h"
00038 #include "httpd.h"
00039 #include "http_config.h"
00040 #include "http_core.h"
00041 #include "http_protocol.h"
00042 #include "http_main.h"
00043 #include "http_request.h"
00044 #include "http_vhost.h"
00045 #include "http_log.h"
00046
00047 #include "apr_date.h"
00048 #include "util_charset.h"
00049 #include "util_ebcdic.h"
00050 #include "util_time.h"
00051
00052 #include "mod_core.h"
00053
00054 #if APR_HAVE_STDARG_H
00055 #include <stdarg.h>
00056 #endif
00057 #if APR_HAVE_UNISTD_H
00058 #include <unistd.h>
00059 #endif
00060
00061
00062
00063
00064
00065
00066
00067 #ifdef UTS21
00068
00069
00070
00071
00072 static const char * status_lines[RESPONSE_CODES] =
00073 #else
00074 static const char * const status_lines[RESPONSE_CODES] =
00075 #endif
00076 {
00077 "100 Continue",
00078 "101 Switching Protocols",
00079 "102 Processing",
00080 #define LEVEL_200 3
00081 "200 OK",
00082 "201 Created",
00083 "202 Accepted",
00084 "203 Non-Authoritative Information",
00085 "204 No Content",
00086 "205 Reset Content",
00087 "206 Partial Content",
00088 "207 Multi-Status",
00089 #define LEVEL_300 11
00090 "300 Multiple Choices",
00091 "301 Moved Permanently",
00092 "302 Found",
00093 "303 See Other",
00094 "304 Not Modified",
00095 "305 Use Proxy",
00096 "306 unused",
00097 "307 Temporary Redirect",
00098 #define LEVEL_400 19
00099 "400 Bad Request",
00100 "401 Authorization Required",
00101 "402 Payment Required",
00102 "403 Forbidden",
00103 "404 Not Found",
00104 "405 Method Not Allowed",
00105 "406 Not Acceptable",
00106 "407 Proxy Authentication Required",
00107 "408 Request Time-out",
00108 "409 Conflict",
00109 "410 Gone",
00110 "411 Length Required",
00111 "412 Precondition Failed",
00112 "413 Request Entity Too Large",
00113 "414 Request-URI Too Large",
00114 "415 Unsupported Media Type",
00115 "416 Requested Range Not Satisfiable",
00116 "417 Expectation Failed",
00117 "418 unused",
00118 "419 unused",
00119 "420 unused",
00120 "421 unused",
00121 "422 Unprocessable Entity",
00122 "423 Locked",
00123 "424 Failed Dependency",
00124
00125
00126
00127 "425 No code",
00128 "426 Upgrade Required",
00129 #define LEVEL_500 46
00130 "500 Internal Server Error",
00131 "501 Method Not Implemented",
00132 "502 Bad Gateway",
00133 "503 Service Temporarily Unavailable",
00134 "504 Gateway Time-out",
00135 "505 HTTP Version Not Supported",
00136 "506 Variant Also Negotiates",
00137 "507 Insufficient Storage",
00138 "508 unused",
00139 "509 unused",
00140 "510 Not Extended"
00141 };
00142
00143 APR_HOOK_STRUCT(
00144 APR_HOOK_LINK(insert_error_filter)
00145 )
00146
00147 AP_IMPLEMENT_HOOK_VOID(insert_error_filter, (request_rec *r), (r))
00148
00149
00150
00151
00152 #define METHOD_NUMBER_FIRST (M_INVALID + 1)
00153
00154
00155
00156
00157
00158 #define METHOD_NUMBER_LAST 62
00159
00160
00161 AP_DECLARE(int) ap_set_keepalive(request_rec *r)
00162 {
00163 int ka_sent = 0;
00164 int wimpy = ap_find_token(r->pool,
00165 apr_table_get(r->headers_out, "Connection"),
00166 "close");
00167 const char *conn = apr_table_get(r->headers_in, "Connection");
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 if ((r->connection->keepalive != AP_CONN_CLOSE)
00195 && ((r->status == HTTP_NOT_MODIFIED)
00196 || (r->status == HTTP_NO_CONTENT)
00197 || r->header_only
00198 || apr_table_get(r->headers_out, "Content-Length")
00199 || ap_find_last_token(r->pool,
00200 apr_table_get(r->headers_out,
00201 "Transfer-Encoding"),
00202 "chunked")
00203 || ((r->proto_num >= HTTP_VERSION(1,1))
00204 && (r->chunked = 1)))
00205 && r->server->keep_alive
00206 && (r->server->keep_alive_timeout > 0)
00207 && ((r->server->keep_alive_max == 0)
00208 || (r->server->keep_alive_max > r->connection->keepalives))
00209 && !ap_status_drops_connection(r->status)
00210 && !wimpy
00211 && !ap_find_token(r->pool, conn, "close")
00212 && (!apr_table_get(r->subprocess_env, "nokeepalive")
00213 || apr_table_get(r->headers_in, "Via"))
00214 && ((ka_sent = ap_find_token(r->pool, conn, "keep-alive"))
00215 || (r->proto_num >= HTTP_VERSION(1,1)))) {
00216 int left = r->server->keep_alive_max - r->connection->keepalives;
00217
00218 r->connection->keepalive = AP_CONN_KEEPALIVE;
00219 r->connection->keepalives++;
00220
00221
00222 if (ka_sent) {
00223 if (r->server->keep_alive_max) {
00224 apr_table_setn(r->headers_out, "Keep-Alive",
00225 apr_psprintf(r->pool, "timeout=%d, max=%d",
00226 (int)apr_time_sec(r->server->keep_alive_timeout),
00227 left));
00228 }
00229 else {
00230 apr_table_setn(r->headers_out, "Keep-Alive",
00231 apr_psprintf(r->pool, "timeout=%d",
00232 (int)apr_time_sec(r->server->keep_alive_timeout)));
00233 }
00234 apr_table_mergen(r->headers_out, "Connection", "Keep-Alive");
00235 }
00236
00237 return 1;
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 if (!wimpy) {
00249 apr_table_mergen(r->headers_out, "Connection", "close");
00250 }
00251
00252 r->connection->keepalive = AP_CONN_CLOSE;
00253
00254 return 0;
00255 }
00256
00257 AP_DECLARE(int) ap_meets_conditions(request_rec *r)
00258 {
00259 const char *etag;
00260 const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
00261 apr_time_t tmp_time;
00262 apr_int64_t mtime;
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
00276 return OK;
00277 }
00278
00279 etag = apr_table_get(r->headers_out, "ETag");
00280
00281
00282
00283
00284
00285 tmp_time = ((r->mtime != 0) ? r->mtime : apr_time_now());
00286 mtime = apr_time_sec(tmp_time);
00287
00288
00289
00290
00291
00292
00293 if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) {
00294 if (if_match[0] != '*'
00295 && (etag == NULL || etag[0] == 'W'
00296 || !ap_find_list_item(r->pool, if_match, etag))) {
00297 return HTTP_PRECONDITION_FAILED;
00298 }
00299 }
00300 else {
00301
00302
00303
00304
00305
00306 if_unmodified = apr_table_get(r->headers_in, "If-Unmodified-Since");
00307 if (if_unmodified != NULL) {
00308 apr_time_t ius = apr_date_parse_http(if_unmodified);
00309
00310 if ((ius != APR_DATE_BAD) && (mtime > apr_time_sec(ius))) {
00311 return HTTP_PRECONDITION_FAILED;
00312 }
00313 }
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328 if_nonematch = apr_table_get(r->headers_in, "If-None-Match");
00329 if (if_nonematch != NULL) {
00330 if (r->method_number == M_GET) {
00331 if (if_nonematch[0] == '*') {
00332 return HTTP_NOT_MODIFIED;
00333 }
00334 if (etag != NULL) {
00335 if (apr_table_get(r->headers_in, "Range")) {
00336 if (etag[0] != 'W'
00337 && ap_find_list_item(r->pool, if_nonematch, etag)) {
00338 return HTTP_NOT_MODIFIED;
00339 }
00340 }
00341 else if (ap_strstr_c(if_nonematch, etag)) {
00342 return HTTP_NOT_MODIFIED;
00343 }
00344 }
00345 }
00346 else if (if_nonematch[0] == '*'
00347 || (etag != NULL
00348 && ap_find_list_item(r->pool, if_nonematch, etag))) {
00349 return HTTP_PRECONDITION_FAILED;
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359 else if ((r->method_number == M_GET)
00360 && ((if_modified_since =
00361 apr_table_get(r->headers_in,
00362 "If-Modified-Since")) != NULL)) {
00363 apr_time_t ims_time;
00364 apr_int64_t ims, reqtime;
00365
00366 ims_time = apr_date_parse_http(if_modified_since);
00367 ims = apr_time_sec(ims_time);
00368 reqtime = apr_time_sec(r->request_time);
00369
00370 if ((ims >= mtime) && (ims <= reqtime)) {
00371 return HTTP_NOT_MODIFIED;
00372 }
00373 }
00374 return OK;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 static apr_hash_t *methods_registry = NULL;
00386 static int cur_method_number = METHOD_NUMBER_FIRST;
00387
00388
00389 static void register_one_method(apr_pool_t *p, const char *methname,
00390 int methnum)
00391 {
00392 int *pnum = apr_palloc(p, sizeof(*pnum));
00393
00394 *pnum = methnum;
00395 apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, pnum);
00396 }
00397
00398
00399
00400
00401 static apr_status_t ap_method_registry_destroy(void *notused)
00402 {
00403 methods_registry = NULL;
00404 cur_method_number = METHOD_NUMBER_FIRST;
00405 return APR_SUCCESS;
00406 }
00407
00408 AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p)
00409 {
00410 methods_registry = apr_hash_make(p);
00411 apr_pool_cleanup_register(p, NULL,
00412 ap_method_registry_destroy,
00413 apr_pool_cleanup_null);
00414
00415
00416
00417 register_one_method(p, "GET", M_GET);
00418 register_one_method(p, "PUT", M_PUT);
00419 register_one_method(p, "POST", M_POST);
00420 register_one_method(p, "DELETE", M_DELETE);
00421 register_one_method(p, "CONNECT", M_CONNECT);
00422 register_one_method(p, "OPTIONS", M_OPTIONS);
00423 register_one_method(p, "TRACE", M_TRACE);
00424 register_one_method(p, "PATCH", M_PATCH);
00425 register_one_method(p, "PROPFIND", M_PROPFIND);
00426 register_one_method(p, "PROPPATCH", M_PROPPATCH);
00427 register_one_method(p, "MKCOL", M_MKCOL);
00428 register_one_method(p, "COPY", M_COPY);
00429 register_one_method(p, "MOVE", M_MOVE);
00430 register_one_method(p, "LOCK", M_LOCK);
00431 register_one_method(p, "UNLOCK", M_UNLOCK);
00432 register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL);
00433 register_one_method(p, "CHECKOUT", M_CHECKOUT);
00434 register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT);
00435 register_one_method(p, "CHECKIN", M_CHECKIN);
00436 register_one_method(p, "UPDATE", M_UPDATE);
00437 register_one_method(p, "LABEL", M_LABEL);
00438 register_one_method(p, "REPORT", M_REPORT);
00439 register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE);
00440 register_one_method(p, "MKACTIVITY", M_MKACTIVITY);
00441 register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL);
00442 register_one_method(p, "MERGE", M_MERGE);
00443 }
00444
00445 AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname)
00446 {
00447 int *methnum;
00448
00449 if (methods_registry == NULL) {
00450 ap_method_registry_init(p);
00451 }
00452
00453 if (methname == NULL) {
00454 return M_INVALID;
00455 }
00456
00457
00458
00459
00460 methnum = (int *)apr_hash_get(methods_registry, methname,
00461 APR_HASH_KEY_STRING);
00462 if (methnum != NULL)
00463 return *methnum;
00464
00465 if (cur_method_number > METHOD_NUMBER_LAST) {
00466
00467
00468
00469 ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p,
00470 "Maximum new request methods %d reached while "
00471 "registering method %s.",
00472 METHOD_NUMBER_LAST, methname);
00473 return M_INVALID;
00474 }
00475
00476 register_one_method(p, methname, cur_method_number);
00477 return cur_method_number++;
00478 }
00479
00480 #define UNKNOWN_METHOD (-1)
00481
00482 static int lookup_builtin_method(const char *method, apr_size_t len)
00483 {
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 switch (len)
00497 {
00498 case 3:
00499 switch (method[0])
00500 {
00501 case 'P':
00502 return (method[1] == 'U'
00503 && method[2] == 'T'
00504 ? M_PUT : UNKNOWN_METHOD);
00505 case 'G':
00506 return (method[1] == 'E'
00507 && method[2] == 'T'
00508 ? M_GET : UNKNOWN_METHOD);
00509 default:
00510 return UNKNOWN_METHOD;
00511 }
00512
00513 case 4:
00514 switch (method[0])
00515 {
00516 case 'H':
00517 return (method[1] == 'E'
00518 && method[2] == 'A'
00519 && method[3] == 'D'
00520 ? M_GET : UNKNOWN_METHOD);
00521 case 'P':
00522 return (method[1] == 'O'
00523 && method[2] == 'S'
00524 && method[3] == 'T'
00525 ? M_POST : UNKNOWN_METHOD);
00526 case 'M':
00527 return (method[1] == 'O'
00528 && method[2] == 'V'
00529 && method[3] == 'E'
00530 ? M_MOVE : UNKNOWN_METHOD);
00531 case 'L':
00532 return (method[1] == 'O'
00533 && method[2] == 'C'
00534 && method[3] == 'K'
00535 ? M_LOCK : UNKNOWN_METHOD);
00536 case 'C':
00537 return (method[1] == 'O'
00538 && method[2] == 'P'
00539 && method[3] == 'Y'
00540 ? M_COPY : UNKNOWN_METHOD);
00541 default:
00542 return UNKNOWN_METHOD;
00543 }
00544
00545 case 5:
00546 switch (method[2])
00547 {
00548 case 'T':
00549 return (memcmp(method, "PATCH", 5) == 0
00550 ? M_PATCH : UNKNOWN_METHOD);
00551 case 'R':
00552 return (memcmp(method, "MERGE", 5) == 0
00553 ? M_MERGE : UNKNOWN_METHOD);
00554 case 'C':
00555 return (memcmp(method, "MKCOL", 5) == 0
00556 ? M_MKCOL : UNKNOWN_METHOD);
00557 case 'B':
00558 return (memcmp(method, "LABEL", 5) == 0
00559 ? M_LABEL : UNKNOWN_METHOD);
00560 case 'A':
00561 return (memcmp(method, "TRACE", 5) == 0
00562 ? M_TRACE : UNKNOWN_METHOD);
00563 default:
00564 return UNKNOWN_METHOD;
00565 }
00566
00567 case 6:
00568 switch (method[0])
00569 {
00570 case 'U':
00571 switch (method[5])
00572 {
00573 case 'K':
00574 return (memcmp(method, "UNLOCK", 6) == 0
00575 ? M_UNLOCK : UNKNOWN_METHOD);
00576 case 'E':
00577 return (memcmp(method, "UPDATE", 6) == 0
00578 ? M_UPDATE : UNKNOWN_METHOD);
00579 default:
00580 return UNKNOWN_METHOD;
00581 }
00582 case 'R':
00583 return (memcmp(method, "REPORT", 6) == 0
00584 ? M_REPORT : UNKNOWN_METHOD);
00585 case 'D':
00586 return (memcmp(method, "DELETE", 6) == 0
00587 ? M_DELETE : UNKNOWN_METHOD);
00588 default:
00589 return UNKNOWN_METHOD;
00590 }
00591
00592 case 7:
00593 switch (method[1])
00594 {
00595 case 'P':
00596 return (memcmp(method, "OPTIONS", 7) == 0
00597 ? M_OPTIONS : UNKNOWN_METHOD);
00598 case 'O':
00599 return (memcmp(method, "CONNECT", 7) == 0
00600 ? M_CONNECT : UNKNOWN_METHOD);
00601 case 'H':
00602 return (memcmp(method, "CHECKIN", 7) == 0
00603 ? M_CHECKIN : UNKNOWN_METHOD);
00604 default:
00605 return UNKNOWN_METHOD;
00606 }
00607
00608 case 8:
00609 switch (method[0])
00610 {
00611 case 'P':
00612 return (memcmp(method, "PROPFIND", 8) == 0
00613 ? M_PROPFIND : UNKNOWN_METHOD);
00614 case 'C':
00615 return (memcmp(method, "CHECKOUT", 8) == 0
00616 ? M_CHECKOUT : UNKNOWN_METHOD);
00617 default:
00618 return UNKNOWN_METHOD;
00619 }
00620
00621 case 9:
00622 return (memcmp(method, "PROPPATCH", 9) == 0
00623 ? M_PROPPATCH : UNKNOWN_METHOD);
00624
00625 case 10:
00626 switch (method[0])
00627 {
00628 case 'U':
00629 return (memcmp(method, "UNCHECKOUT", 10) == 0
00630 ? M_UNCHECKOUT : UNKNOWN_METHOD);
00631 case 'M':
00632 return (memcmp(method, "MKACTIVITY", 10) == 0
00633 ? M_MKACTIVITY : UNKNOWN_METHOD);
00634 default:
00635 return UNKNOWN_METHOD;
00636 }
00637
00638 case 11:
00639 return (memcmp(method, "MKWORKSPACE", 11) == 0
00640 ? M_MKWORKSPACE : UNKNOWN_METHOD);
00641
00642 case 15:
00643 return (memcmp(method, "VERSION-CONTROL", 15) == 0
00644 ? M_VERSION_CONTROL : UNKNOWN_METHOD);
00645
00646 case 16:
00647 return (memcmp(method, "BASELINE-CONTROL", 16) == 0
00648 ? M_BASELINE_CONTROL : UNKNOWN_METHOD);
00649
00650 default:
00651 return UNKNOWN_METHOD;
00652 }
00653
00654
00655 }
00656
00657
00658
00659
00660
00661
00662
00663
00664 AP_DECLARE(int) ap_method_number_of(const char *method)
00665 {
00666 int len = strlen(method);
00667 int which = lookup_builtin_method(method, len);
00668
00669 if (which != UNKNOWN_METHOD)
00670 return which;
00671
00672
00673 if (methods_registry != NULL) {
00674 int *methnum = apr_hash_get(methods_registry, method, len);
00675
00676 if (methnum != NULL) {
00677 return *methnum;
00678 }
00679 }
00680
00681 return M_INVALID;
00682 }
00683
00684
00685
00686
00687 AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum)
00688 {
00689 apr_hash_index_t *hi = apr_hash_first(p, methods_registry);
00690
00691
00692
00693 for (; hi; hi = apr_hash_next(hi)) {
00694 const void *key;
00695 void *val;
00696
00697 apr_hash_this(hi, &key, NULL, &val);
00698 if (*(int *)val == methnum)
00699 return key;
00700 }
00701
00702
00703 return NULL;
00704 }
00705
00706 static long get_chunk_size(char *);
00707
00708 typedef struct http_filter_ctx {
00709 apr_off_t remaining;
00710 apr_off_t limit;
00711 apr_off_t limit_used;
00712 enum {
00713 BODY_NONE,
00714 BODY_LENGTH,
00715 BODY_CHUNK
00716 } state;
00717 int eos_sent;
00718 } http_ctx_t;
00719
00720
00721
00722
00723
00724
00725 apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
00726 ap_input_mode_t mode, apr_read_type_e block,
00727 apr_off_t readbytes)
00728 {
00729 apr_bucket *e;
00730 http_ctx_t *ctx = f->ctx;
00731 apr_status_t rv;
00732 apr_off_t totalread;
00733
00734
00735 if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) {
00736 return ap_get_brigade(f->next, b, mode, block, readbytes);
00737 }
00738
00739 if (!ctx) {
00740 const char *tenc, *lenp;
00741 f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
00742 ctx->state = BODY_NONE;
00743 ctx->remaining = 0;
00744 ctx->limit_used = 0;
00745 ctx->eos_sent = 0;
00746
00747
00748
00749
00750
00751
00752 if (!f->r->proxyreq) {
00753 ctx->limit = ap_get_limit_req_body(f->r);
00754 }
00755 else {
00756 ctx->limit = 0;
00757 }
00758
00759 tenc = apr_table_get(f->r->headers_in, "Transfer-Encoding");
00760 lenp = apr_table_get(f->r->headers_in, "Content-Length");
00761
00762 if (tenc) {
00763 if (!strcasecmp(tenc, "chunked")) {
00764 ctx->state = BODY_CHUNK;
00765 }
00766 }
00767 else if (lenp) {
00768 int conversion_error = 0;
00769 char *endstr;
00770
00771 ctx->state = BODY_LENGTH;
00772 errno = 0;
00773 ctx->remaining = strtol(lenp, &endstr, 10);
00774
00775
00776
00777
00778
00779
00780 if (errno || (endstr && *endstr) || (ctx->remaining < 0)) {
00781 conversion_error = 1;
00782 }
00783
00784 if (conversion_error) {
00785 apr_bucket_brigade *bb;
00786
00787 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
00788 "Invalid Content-Length");
00789
00790 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
00791 e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, NULL,
00792 f->r->pool, f->c->bucket_alloc);
00793 APR_BRIGADE_INSERT_TAIL(bb, e);
00794 e = apr_bucket_eos_create(f->c->bucket_alloc);
00795 APR_BRIGADE_INSERT_TAIL(bb, e);
00796 ctx->eos_sent = 1;
00797 return ap_pass_brigade(f->r->output_filters, bb);
00798 }
00799
00800
00801
00802
00803 if (ctx->limit && ctx->limit < ctx->remaining) {
00804 apr_bucket_brigade *bb;
00805 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
00806 "Requested content-length of %" APR_OFF_T_FMT
00807 " is larger than the configured limit"
00808 " of %" APR_OFF_T_FMT, ctx->remaining, ctx->limit);
00809 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
00810 e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, NULL,
00811 f->r->pool, f->c->bucket_alloc);
00812 APR_BRIGADE_INSERT_TAIL(bb, e);
00813 e = apr_bucket_eos_create(f->c->bucket_alloc);
00814 APR_BRIGADE_INSERT_TAIL(bb, e);
00815 ctx->eos_sent = 1;
00816 return ap_pass_brigade(f->r->output_filters, bb);
00817 }
00818 }
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831 if (ctx->state == BODY_NONE && f->r->proxyreq != PROXYREQ_RESPONSE) {
00832 e = apr_bucket_eos_create(f->c->bucket_alloc);
00833 APR_BRIGADE_INSERT_TAIL(b, e);
00834 ctx->eos_sent = 1;
00835 return APR_SUCCESS;
00836 }
00837
00838
00839
00840 if ((ctx->state == BODY_CHUNK ||
00841 (ctx->state == BODY_LENGTH && ctx->remaining > 0)) &&
00842 f->r->expecting_100 && f->r->proto_num >= HTTP_VERSION(1,1)) {
00843 char *tmp;
00844 apr_bucket_brigade *bb;
00845
00846 tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ",
00847 status_lines[0], CRLF CRLF, NULL);
00848 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
00849 e = apr_bucket_pool_create(tmp, strlen(tmp), f->r->pool,
00850 f->c->bucket_alloc);
00851 APR_BRIGADE_INSERT_HEAD(bb, e);
00852 e = apr_bucket_flush_create(f->c->bucket_alloc);
00853 APR_BRIGADE_INSERT_TAIL(bb, e);
00854
00855 ap_pass_brigade(f->c->output_filters, bb);
00856 }
00857
00858
00859 if (ctx->state == BODY_CHUNK) {
00860 char line[30];
00861 apr_bucket_brigade *bb;
00862 apr_size_t len = 30;
00863
00864 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
00865
00866 rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
00867 APR_BLOCK_READ, 0);
00868
00869 if (rv == APR_SUCCESS) {
00870 rv = apr_brigade_flatten(bb, line, &len);
00871 if (rv == APR_SUCCESS) {
00872 ctx->remaining = get_chunk_size(line);
00873 }
00874 }
00875 apr_brigade_cleanup(bb);
00876
00877
00878 if (rv != APR_SUCCESS || ctx->remaining < 0) {
00879 ctx->remaining = 0;
00880
00881 e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, NULL,
00882 f->r->pool,
00883 f->c->bucket_alloc);
00884 APR_BRIGADE_INSERT_TAIL(bb, e);
00885 e = apr_bucket_eos_create(f->c->bucket_alloc);
00886 APR_BRIGADE_INSERT_TAIL(bb, e);
00887 ctx->eos_sent = 1;
00888 return ap_pass_brigade(f->r->output_filters, bb);
00889 }
00890
00891 if (!ctx->remaining) {
00892
00893 ctx->state = BODY_NONE;
00894 ap_get_mime_headers(f->r);
00895 e = apr_bucket_eos_create(f->c->bucket_alloc);
00896 APR_BRIGADE_INSERT_TAIL(b, e);
00897 ctx->eos_sent = 1;
00898 return APR_SUCCESS;
00899 }
00900 }
00901 }
00902
00903 if (ctx->eos_sent) {
00904 e = apr_bucket_eos_create(f->c->bucket_alloc);
00905 APR_BRIGADE_INSERT_TAIL(b, e);
00906 return APR_SUCCESS;
00907 }
00908
00909 if (!ctx->remaining) {
00910 switch (ctx->state) {
00911 case BODY_NONE:
00912 break;
00913 case BODY_LENGTH:
00914 e = apr_bucket_eos_create(f->c->bucket_alloc);
00915 APR_BRIGADE_INSERT_TAIL(b, e);
00916 ctx->eos_sent = 1;
00917 return APR_SUCCESS;
00918 case BODY_CHUNK:
00919 {
00920 char line[30];
00921 apr_bucket_brigade *bb;
00922 apr_size_t len = 30;
00923
00924 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
00925
00926
00927 rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
00928 APR_BLOCK_READ, 0);
00929 apr_brigade_cleanup(bb);
00930
00931 if (rv == APR_SUCCESS) {
00932
00933 rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
00934 APR_BLOCK_READ, 0);
00935 if (rv == APR_SUCCESS) {
00936 rv = apr_brigade_flatten(bb, line, &len);
00937 if (rv == APR_SUCCESS) {
00938 ctx->remaining = get_chunk_size(line);
00939 }
00940 }
00941 apr_brigade_cleanup(bb);
00942 }
00943
00944
00945 if (rv != APR_SUCCESS || ctx->remaining < 0) {
00946 ctx->remaining = 0;
00947
00948 e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE,
00949 NULL, f->r->pool,
00950 f->c->bucket_alloc);
00951 APR_BRIGADE_INSERT_TAIL(bb, e);
00952 e = apr_bucket_eos_create(f->c->bucket_alloc);
00953 APR_BRIGADE_INSERT_TAIL(bb, e);
00954 ctx->eos_sent = 1;
00955 return ap_pass_brigade(f->r->output_filters, bb);
00956 }
00957
00958 if (!ctx->remaining) {
00959
00960 ctx->state = BODY_NONE;
00961 ap_get_mime_headers(f->r);
00962 e = apr_bucket_eos_create(f->c->bucket_alloc);
00963 APR_BRIGADE_INSERT_TAIL(b, e);
00964 ctx->eos_sent = 1;
00965 return APR_SUCCESS;
00966 }
00967 }
00968 break;
00969 }
00970 }
00971
00972
00973 if (ctx->state == BODY_LENGTH || ctx->state == BODY_CHUNK) {
00974 if (ctx->remaining < readbytes) {
00975 readbytes = ctx->remaining;
00976 }
00977 AP_DEBUG_ASSERT(readbytes > 0);
00978 }
00979
00980 rv = ap_get_brigade(f->next, b, mode, block, readbytes);
00981
00982 if (rv != APR_SUCCESS) {
00983 return rv;
00984 }
00985
00986
00987 apr_brigade_length(b, 0, &totalread);
00988
00989
00990
00991 AP_DEBUG_ASSERT(totalread >= 0);
00992
00993 if (ctx->state != BODY_NONE) {
00994 ctx->remaining -= totalread;
00995 }
00996
00997
00998
00999
01000 if (ctx->state == BODY_LENGTH && ctx->remaining == 0) {
01001 e = apr_bucket_eos_create(f->c->bucket_alloc);
01002 APR_BRIGADE_INSERT_TAIL(b, e);
01003 }
01004
01005
01006 if (ctx->limit) {
01007
01008
01009
01010 ctx->limit_used += totalread;
01011 if (ctx->limit < ctx->limit_used) {
01012 apr_bucket_brigade *bb;
01013 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
01014 "Read content-length of %" APR_OFF_T_FMT
01015 " is larger than the configured limit"
01016 " of %" APR_OFF_T_FMT, ctx->limit_used, ctx->limit);
01017 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
01018 e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, NULL,
01019 f->r->pool,
01020 f->c->bucket_alloc);
01021 APR_BRIGADE_INSERT_TAIL(bb, e);
01022 e = apr_bucket_eos_create(f->c->bucket_alloc);
01023 APR_BRIGADE_INSERT_TAIL(bb, e);
01024 ctx->eos_sent = 1;
01025 return ap_pass_brigade(f->r->output_filters, bb);
01026 }
01027 }
01028
01029 return APR_SUCCESS;
01030 }
01031
01032
01033
01034
01035
01036
01037
01038 AP_DECLARE(int) ap_index_of_response(int status)
01039 {
01040 static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400,
01041 LEVEL_500, RESPONSE_CODES};
01042 int i, pos;
01043
01044 if (status < 100) {
01045 return LEVEL_500;
01046 }
01047
01048 for (i = 0; i < 5; i++) {
01049 status -= 100;
01050 if (status < 100) {
01051 pos = (status + shortcut[i]);
01052 if (pos < shortcut[i + 1]) {
01053 return pos;
01054 }
01055 else {
01056 return LEVEL_500;
01057 }
01058 }
01059 }
01060 return LEVEL_500;
01061 }
01062
01063 AP_DECLARE(const char *) ap_get_status_line(int status)
01064 {
01065 return status_lines[ap_index_of_response(status)];
01066 }
01067
01068 typedef struct header_struct {
01069 apr_pool_t *pool;
01070 apr_bucket_brigade *bb;
01071 } header_struct;
01072
01073
01074
01075
01076
01077
01078 static int form_header_field(header_struct *h,
01079 const char *fieldname, const char *fieldval)
01080 {
01081 #if APR_CHARSET_EBCDIC
01082 char *headfield;
01083 apr_size_t len;
01084 apr_size_t name_len;
01085 apr_size_t val_len;
01086 char *next;
01087
01088 name_len = strlen(fieldname);
01089 val_len = strlen(fieldval);
01090 len = name_len + val_len + 4;
01091 headfield = (char *)apr_palloc(h->pool, len + 1);
01092 memcpy(headfield, fieldname, name_len);
01093 next = headfield + name_len;
01094 *next++ = ':';
01095 *next++ = ' ';
01096 memcpy(next, fieldval, val_len);
01097 next += val_len;
01098 *next++ = CR;
01099 *next++ = LF;
01100 *next = 0;
01101 ap_xlate_proto_to_ascii(headfield, len);
01102 apr_brigade_write(h->bb, NULL, NULL, headfield, len);
01103 #else
01104 struct iovec vec[4];
01105 struct iovec *v = vec;
01106 v->iov_base = (void *)fieldname;
01107 v->iov_len = strlen(fieldname);
01108 v++;
01109 v->iov_base = ": ";
01110 v->iov_len = sizeof(": ") - 1;
01111 v++;
01112 v->iov_base = (void *)fieldval;
01113 v->iov_len = strlen(fieldval);
01114 v++;
01115 v->iov_base = CRLF;
01116 v->iov_len = sizeof(CRLF) - 1;
01117 apr_brigade_writev(h->bb, NULL, NULL, vec, 4);
01118 #endif
01119 return 1;
01120 }
01121
01122
01123
01124 static apr_status_t send_all_header_fields(header_struct *h,
01125 const request_rec *r)
01126 {
01127 const apr_array_header_t *elts;
01128 const apr_table_entry_t *t_elt;
01129 const apr_table_entry_t *t_end;
01130 struct iovec *vec;
01131 struct iovec *vec_next;
01132
01133 elts = apr_table_elts(r->headers_out);
01134 if (elts->nelts == 0) {
01135 return APR_SUCCESS;
01136 }
01137 t_elt = (const apr_table_entry_t *)(elts->elts);
01138 t_end = t_elt + elts->nelts;
01139 vec = (struct iovec *)apr_palloc(h->pool, 4 * elts->nelts *
01140 sizeof(struct iovec));
01141 vec_next = vec;
01142
01143
01144
01145
01146 do {
01147 vec_next->iov_base = (void*)(t_elt->key);
01148 vec_next->iov_len = strlen(t_elt->key);
01149 vec_next++;
01150 vec_next->iov_base = ": ";
01151 vec_next->iov_len = sizeof(": ") - 1;
01152 vec_next++;
01153 vec_next->iov_base = (void*)(t_elt->val);
01154 vec_next->iov_len = strlen(t_elt->val);
01155 vec_next++;
01156 vec_next->iov_base = CRLF;
01157 vec_next->iov_len = sizeof(CRLF) - 1;
01158 vec_next++;
01159 t_elt++;
01160 } while (t_elt < t_end);
01161
01162 #if APR_CHARSET_EBCDIC
01163 {
01164 apr_size_t len;
01165 char *tmp = apr_pstrcatv(r->pool, vec, vec_next - vec, &len);
01166 ap_xlate_proto_to_ascii(tmp, len);
01167 return apr_brigade_write(h->bb, NULL, NULL, tmp, len);
01168 }
01169 #else
01170 return apr_brigade_writev(h->bb, NULL, NULL, vec, vec_next - vec);
01171 #endif
01172 }
01173
01174
01175
01176
01177
01178
01179
01180 static void basic_http_header_check(request_rec *r,
01181 const char **protocol)
01182 {
01183 if (r->assbackwards) {
01184
01185 return;
01186 }
01187
01188 if (!r->status_line) {
01189 r->status_line = status_lines[ap_index_of_response(r->status)];
01190 }
01191
01192
01193 if (r->proto_num > HTTP_VERSION(1,0)
01194 && apr_table_get(r->subprocess_env, "downgrade-1.0")) {
01195 r->proto_num = HTTP_VERSION(1,0);
01196 }
01197
01198
01199
01200 if (r->proto_num == HTTP_VERSION(1,0)
01201 && apr_table_get(r->subprocess_env, "force-response-1.0")) {
01202 *protocol = "HTTP/1.0";
01203 r->connection->keepalive = AP_CONN_CLOSE;
01204 }
01205 else {
01206 *protocol = AP_SERVER_PROTOCOL;
01207 }
01208
01209 }
01210
01211
01212 static void basic_http_header(request_rec *r, apr_bucket_brigade *bb,
01213 const char *protocol)
01214 {
01215 char *date;
01216 const char *server;
01217 header_struct h;
01218 struct iovec vec[4];
01219
01220 if (r->assbackwards) {
01221
01222 return;
01223 }
01224
01225
01226
01227 vec[0].iov_base = (void *)protocol;
01228 vec[0].iov_len = strlen(protocol);
01229 vec[1].iov_base = (void *)" ";
01230 vec[1].iov_len = sizeof(" ") - 1;
01231 vec[2].iov_base = (void *)(r->status_line);
01232 vec[2].iov_len = strlen(r->status_line);
01233 vec[3].iov_base = (void *)CRLF;
01234 vec[3].iov_len = sizeof(CRLF) - 1;
01235 #if APR_CHARSET_EBCDIC
01236 {
01237 char *tmp;
01238 apr_size_t len;
01239 tmp = apr_pstrcatv(r->pool, vec, 4, &len);
01240 ap_xlate_proto_to_ascii(tmp, len);
01241 apr_brigade_write(bb, NULL, NULL, tmp, len);
01242 }
01243 #else
01244 apr_brigade_writev(bb, NULL, NULL, vec, 4);
01245 #endif
01246
01247 date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
01248 ap_recent_rfc822_date(date, r->request_time);
01249
01250 h.pool = r->pool;
01251 h.bb = bb;
01252 form_header_field(&h, "Date", date);
01253
01254
01255
01256 if (r->proxyreq != PROXYREQ_NONE) {
01257 server = apr_table_get(r->headers_out, "Server");
01258 if (server) {
01259 form_header_field(&h, "Server", server);
01260 }
01261 }
01262 else {
01263 form_header_field(&h, "Server", ap_get_server_version());
01264 }
01265
01266
01267 apr_table_unset(r->headers_out, "Date");
01268 apr_table_unset(r->headers_out, "Server");
01269 }
01270
01271 AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb)
01272 {
01273 const char *protocol;
01274
01275 basic_http_header_check(r, &protocol);
01276 basic_http_header(r, bb, protocol);
01277 }
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296 static void terminate_header(apr_bucket_brigade *bb)
01297 {
01298 char tmp[] = "X-Pad: avoid browser bug" CRLF;
01299 char crlf[] = CRLF;
01300 apr_off_t len;
01301 apr_size_t buflen;
01302
01303 (void) apr_brigade_length(bb, 1, &len);
01304
01305 if (len >= 255 && len <= 257) {
01306 buflen = strlen(tmp);
01307 ap_xlate_proto_to_ascii(tmp, buflen);
01308 apr_brigade_write(bb, NULL, NULL, tmp, buflen);
01309 }
01310 buflen = strlen(crlf);
01311 ap_xlate_proto_to_ascii(crlf, buflen);
01312 apr_brigade_write(bb, NULL, NULL, crlf, buflen);
01313 }
01314
01315
01316
01317
01318 static char *make_allow(request_rec *r)
01319 {
01320 char *list;
01321 apr_int64_t mask;
01322 apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *));
01323 apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry);
01324
01325 mask = r->allowed_methods->method_mask;
01326
01327 for (; hi; hi = apr_hash_next(hi)) {
01328 const void *key;
01329 void *val;
01330
01331 apr_hash_this(hi, &key, NULL, &val);
01332 if ((mask & (AP_METHOD_BIT << *(int *)val)) != 0) {
01333 *(const char **)apr_array_push(allow) = key;
01334
01335
01336 if (*(int *)val == M_GET)
01337 *(const char **)apr_array_push(allow) = "HEAD";
01338 }
01339 }
01340
01341
01342 *(const char **)apr_array_push(allow) = "TRACE";
01343
01344 list = apr_array_pstrcat(r->pool, allow, ',');
01345
01346
01347
01348 if ((mask & (AP_METHOD_BIT << M_INVALID))
01349 && (r->allowed_methods->method_list != NULL)
01350 && (r->allowed_methods->method_list->nelts != 0)) {
01351 int i;
01352 char **xmethod = (char **) r->allowed_methods->method_list->elts;
01353
01354
01355
01356
01357 for (i = 0; i < r->allowed_methods->method_list->nelts; ++i) {
01358 list = apr_pstrcat(r->pool, list, ",", xmethod[i], NULL);
01359 }
01360 }
01361
01362 return list;
01363 }
01364
01365 AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
01366 {
01367 int rv;
01368 apr_bucket_brigade *b;
01369 header_struct h;
01370
01371 if (r->method_number != M_TRACE) {
01372 return DECLINED;
01373 }
01374
01375
01376 while (r->prev) {
01377 r = r->prev;
01378 }
01379
01380 if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY))) {
01381 return