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/* HTTP routines for Apache proxy */ 18 19#include "mod_proxy.h" 20#include "ap_regex.h" 21 22module AP_MODULE_DECLARE_DATA proxy_http_module; 23 24static apr_status_t ap_proxy_http_cleanup(const char *scheme, 25 request_rec *r, 26 proxy_conn_rec *backend); 27 28/* 29 * Canonicalise http-like URLs. 30 * scheme is the scheme for the URL 31 * url is the URL starting with the first '/' 32 * def_port is the default port for this scheme. 33 */ 34static int proxy_http_canon(request_rec *r, char *url) 35{ 36 char *host, *path, sport[7]; 37 char *search = NULL; 38 const char *err; 39 const char *scheme; 40 apr_port_t port, def_port; 41 42 /* ap_port_of_scheme() */ 43 if (strncasecmp(url, "http:", 5) == 0) { 44 url += 5; 45 scheme = "http"; 46 } 47 else if (strncasecmp(url, "https:", 6) == 0) { 48 url += 6; 49 scheme = "https"; 50 } 51 else { 52 return DECLINED; 53 } 54 def_port = apr_uri_port_of_scheme(scheme); 55 56 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 57 "proxy: HTTP: canonicalising URL %s", url); 58 59 /* do syntatic check. 60 * We break the URL into host, port, path, search 61 */ 62 port = def_port; 63 err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); 64 if (err) { 65 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, 66 "error parsing URL %s: %s", 67 url, err); 68 return HTTP_BAD_REQUEST; 69 } 70 71 /* 72 * now parse path/search args, according to rfc1738: 73 * process the path. 74 * 75 * In a reverse proxy, our URL has been processed, so canonicalise 76 * unless proxy-nocanon is set to say it's raw 77 * In a forward proxy, we have and MUST NOT MANGLE the original. 78 */ 79 switch (r->proxyreq) { 80 default: /* wtf are we doing here? */ 81 case PROXYREQ_REVERSE: 82 if (apr_table_get(r->notes, "proxy-nocanon")) { 83 path = url; /* this is the raw path */ 84 } 85 else { 86 path = ap_proxy_canonenc(r->pool, url, strlen(url), 87 enc_path, 0, r->proxyreq); 88 search = r->args; 89 } 90 break; 91 case PROXYREQ_PROXY: 92 path = url; 93 break; 94 } 95 96 if (path == NULL) 97 return HTTP_BAD_REQUEST; 98 99 if (port != def_port) 100 apr_snprintf(sport, sizeof(sport), ":%d", port); 101 else 102 sport[0] = '\0'; 103 104 if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */ 105 host = apr_pstrcat(r->pool, "[", host, "]", NULL); 106 } 107 r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, 108 "/", path, (search) ? "?" : "", (search) ? search : "", NULL); 109 return OK; 110} 111 112/* Clear all connection-based headers from the incoming headers table */ 113typedef struct header_dptr { 114 apr_pool_t *pool; 115 apr_table_t *table; 116 apr_time_t time; 117} header_dptr; 118static ap_regex_t *warn_rx; 119static int clean_warning_headers(void *data, const char *key, const char *val) 120{ 121 apr_table_t *headers = ((header_dptr*)data)->table; 122 apr_pool_t *pool = ((header_dptr*)data)->pool; 123 char *warning; 124 char *date; 125 apr_time_t warn_time; 126 const int nmatch = 3; 127 ap_regmatch_t pmatch[3]; 128 129 if (headers == NULL) { 130 ((header_dptr*)data)->table = headers = apr_table_make(pool, 2); 131 } 132/* 133 * Parse this, suckers! 134 * 135 * Warning = "Warning" ":" 1#warning-value 136 * 137 * warning-value = warn-code SP warn-agent SP warn-text 138 * [SP warn-date] 139 * 140 * warn-code = 3DIGIT 141 * warn-agent = ( host [ ":" port ] ) | pseudonym 142 * ; the name or pseudonym of the server adding 143 * ; the Warning header, for use in debugging 144 * warn-text = quoted-string 145 * warn-date = <"> HTTP-date <"> 146 * 147 * Buggrit, use a bloomin' regexp! 148 * (\d{3}\s+\S+\s+\".*?\"(\s+\"(.*?)\")?) --> whole in $1, date in $3 149 */ 150 while (!ap_regexec(warn_rx, val, nmatch, pmatch, 0)) { 151 warning = apr_pstrndup(pool, val+pmatch[0].rm_so, 152 pmatch[0].rm_eo - pmatch[0].rm_so); 153 warn_time = 0; 154 if (pmatch[2].rm_eo > pmatch[2].rm_so) { 155 /* OK, we have a date here */ 156 date = apr_pstrndup(pool, val+pmatch[2].rm_so, 157 pmatch[2].rm_eo - pmatch[2].rm_so); 158 warn_time = apr_date_parse_http(date); 159 } 160 if (!warn_time || (warn_time == ((header_dptr*)data)->time)) { 161 apr_table_addn(headers, key, warning); 162 } 163 val += pmatch[0].rm_eo; 164 } 165 return 1; 166} 167static apr_table_t *ap_proxy_clean_warnings(apr_pool_t *p, apr_table_t *headers) 168{ 169 header_dptr x; 170 x.pool = p; 171 x.table = NULL; 172 x.time = apr_date_parse_http(apr_table_get(headers, "Date")); 173 apr_table_do(clean_warning_headers, &x, headers, "Warning", NULL); 174 if (x.table != NULL) { 175 apr_table_unset(headers, "Warning"); 176 return apr_table_overlay(p, headers, x.table); 177 } 178 else { 179 return headers; 180 } 181} 182static int clear_conn_headers(void *data, const char *key, const char *val) 183{ 184 apr_table_t *headers = ((header_dptr*)data)->table; 185 apr_pool_t *pool = ((header_dptr*)data)->pool; 186 const char *name; 187 char *next = apr_pstrdup(pool, val); 188 while (*next) { 189 name = next; 190 while (*next && !apr_isspace(*next) && (*next != ',')) { 191 ++next; 192 } 193 while (*next && (apr_isspace(*next) || (*next == ','))) { 194 *next++ = '\0'; 195 } 196 apr_table_unset(headers, name); 197 } 198 return 1; 199} 200static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers) 201{ 202 header_dptr x; 203 x.pool = p; 204 x.table = headers; 205 apr_table_unset(headers, "Proxy-Connection"); 206 apr_table_do(clear_conn_headers, &x, headers, "Connection", NULL); 207 apr_table_unset(headers, "Connection"); 208} 209static void add_te_chunked(apr_pool_t *p, 210 apr_bucket_alloc_t *bucket_alloc, 211 apr_bucket_brigade *header_brigade) 212{ 213 apr_bucket *e; 214 char *buf; 215 const char te_hdr[] = "Transfer-Encoding: chunked" CRLF; 216 217 buf = apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1); 218 ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1); 219 220 e = apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, bucket_alloc); 221 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 222} 223 224static void add_cl(apr_pool_t *p, 225 apr_bucket_alloc_t *bucket_alloc, 226 apr_bucket_brigade *header_brigade, 227 const char *cl_val) 228{ 229 apr_bucket *e; 230 char *buf; 231 232 buf = apr_pstrcat(p, "Content-Length: ", 233 cl_val, 234 CRLF, 235 NULL); 236 ap_xlate_proto_to_ascii(buf, strlen(buf)); 237 e = apr_bucket_pool_create(buf, strlen(buf), p, bucket_alloc); 238 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 239} 240 241#define ASCII_CRLF "\015\012" 242#define ASCII_ZERO "\060" 243 244static void terminate_headers(apr_bucket_alloc_t *bucket_alloc, 245 apr_bucket_brigade *header_brigade) 246{ 247 apr_bucket *e; 248 249 /* add empty line at the end of the headers */ 250 e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); 251 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 252} 253 254static int pass_brigade(apr_bucket_alloc_t *bucket_alloc, 255 request_rec *r, proxy_conn_rec *conn, 256 conn_rec *origin, apr_bucket_brigade *bb, 257 int flush) 258{ 259 apr_status_t status; 260 apr_off_t transferred; 261 262 if (flush) { 263 apr_bucket *e = apr_bucket_flush_create(bucket_alloc); 264 APR_BRIGADE_INSERT_TAIL(bb, e); 265 } 266 apr_brigade_length(bb, 0, &transferred); 267 if (transferred != -1) 268 conn->worker->s->transferred += transferred; 269 status = ap_pass_brigade(origin->output_filters, bb); 270 if (status != APR_SUCCESS) { 271 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, 272 "proxy: pass request body failed to %pI (%s)", 273 conn->addr, conn->hostname); 274 if (origin->aborted) { 275 const char *ssl_note; 276 277 if (((ssl_note = apr_table_get(origin->notes, "SSL_connect_rv")) 278 != NULL) && (strcmp(ssl_note, "err") == 0)) { 279 return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, 280 "Error during SSL Handshake with" 281 " remote server"); 282 } 283 return APR_STATUS_IS_TIMEUP(status) ? HTTP_GATEWAY_TIME_OUT : HTTP_BAD_GATEWAY; 284 } 285 else { 286 return HTTP_BAD_REQUEST; 287 } 288 } 289 apr_brigade_cleanup(bb); 290 return OK; 291} 292 293#define MAX_MEM_SPOOL 16384 294 295static int stream_reqbody_chunked(apr_pool_t *p, 296 request_rec *r, 297 proxy_conn_rec *p_conn, 298 conn_rec *origin, 299 apr_bucket_brigade *header_brigade, 300 apr_bucket_brigade *input_brigade) 301{ 302 int seen_eos = 0, rv = OK; 303 apr_size_t hdr_len; 304 apr_off_t bytes; 305 apr_status_t status; 306 apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; 307 apr_bucket_brigade *bb; 308 apr_bucket *e; 309 310 add_te_chunked(p, bucket_alloc, header_brigade); 311 terminate_headers(bucket_alloc, header_brigade); 312 313 while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) 314 { 315 char chunk_hdr[20]; /* must be here due to transient bucket. */ 316 317 /* If this brigade contains EOS, either stop or remove it. */ 318 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { 319 seen_eos = 1; 320 321 /* We can't pass this EOS to the output_filters. */ 322 e = APR_BRIGADE_LAST(input_brigade); 323 apr_bucket_delete(e); 324 } 325 326 apr_brigade_length(input_brigade, 1, &bytes); 327 328 hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), 329 "%" APR_UINT64_T_HEX_FMT CRLF, 330 (apr_uint64_t)bytes); 331 332 ap_xlate_proto_to_ascii(chunk_hdr, hdr_len); 333 e = apr_bucket_transient_create(chunk_hdr, hdr_len, 334 bucket_alloc); 335 APR_BRIGADE_INSERT_HEAD(input_brigade, e); 336 337 /* 338 * Append the end-of-chunk CRLF 339 */ 340 e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); 341 APR_BRIGADE_INSERT_TAIL(input_brigade, e); 342 343 if (header_brigade) { 344 /* we never sent the header brigade, so go ahead and 345 * take care of that now 346 */ 347 bb = header_brigade; 348 349 /* 350 * Save input_brigade in bb brigade. (At least) in the SSL case 351 * input_brigade contains transient buckets whose data would get 352 * overwritten during the next call of ap_get_brigade in the loop. 353 * ap_save_brigade ensures these buckets to be set aside. 354 * Calling ap_save_brigade with NULL as filter is OK, because 355 * bb brigade already has been created and does not need to get 356 * created by ap_save_brigade. 357 */ 358 status = ap_save_brigade(NULL, &bb, &input_brigade, p); 359 if (status != APR_SUCCESS) { 360 return HTTP_INTERNAL_SERVER_ERROR; 361 } 362 363 header_brigade = NULL; 364 } 365 else { 366 bb = input_brigade; 367 } 368 369 /* The request is flushed below this loop with chunk EOS header */ 370 rv = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0); 371 if (rv != OK) { 372 return rv; 373 } 374 375 if (seen_eos) { 376 break; 377 } 378 379 status = ap_get_brigade(r->input_filters, input_brigade, 380 AP_MODE_READBYTES, APR_BLOCK_READ, 381 HUGE_STRING_LEN); 382 383 if (status != APR_SUCCESS) { 384 return HTTP_BAD_REQUEST; 385 } 386 } 387 388 if (header_brigade) { 389 /* we never sent the header brigade because there was no request body; 390 * send it now 391 */ 392 bb = header_brigade; 393 } 394 else { 395 if (!APR_BRIGADE_EMPTY(input_brigade)) { 396 /* input brigade still has an EOS which we can't pass to the output_filters. */ 397 e = APR_BRIGADE_LAST(input_brigade); 398 AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(e)); 399 apr_bucket_delete(e); 400 } 401 bb = input_brigade; 402 } 403 404 e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF 405 /* <trailers> */ 406 ASCII_CRLF, 407 5, bucket_alloc); 408 APR_BRIGADE_INSERT_TAIL(bb, e); 409 410 /* Now we have headers-only, or the chunk EOS mark; flush it */ 411 rv = pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1); 412 return rv; 413} 414 415static int stream_reqbody_cl(apr_pool_t *p, 416 request_rec *r, 417 proxy_conn_rec *p_conn, 418 conn_rec *origin, 419 apr_bucket_brigade *header_brigade, 420 apr_bucket_brigade *input_brigade, 421 const char *old_cl_val) 422{ 423 int seen_eos = 0, rv = 0; 424 apr_status_t status = APR_SUCCESS; 425 apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; 426 apr_bucket_brigade *bb; 427 apr_bucket *e; 428 apr_off_t cl_val = 0; 429 apr_off_t bytes; 430 apr_off_t bytes_streamed = 0; 431 432 if (old_cl_val) { 433 char *endstr; 434 435 add_cl(p, bucket_alloc, header_brigade, old_cl_val); 436 status = apr_strtoff(&cl_val, old_cl_val, &endstr, 10); 437 438 if (status || *endstr || endstr == old_cl_val || cl_val < 0) { 439 ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, 440 "proxy: could not parse request Content-Length (%s)", 441 old_cl_val); 442 return HTTP_BAD_REQUEST; 443 } 444 } 445 terminate_headers(bucket_alloc, header_brigade); 446 447 while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) 448 { 449 apr_brigade_length(input_brigade, 1, &bytes); 450 bytes_streamed += bytes; 451 452 /* If this brigade contains EOS, either stop or remove it. */ 453 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { 454 seen_eos = 1; 455 456 /* We can't pass this EOS to the output_filters. */ 457 e = APR_BRIGADE_LAST(input_brigade); 458 apr_bucket_delete(e); 459 } 460 461 /* C-L < bytes streamed?!? 462 * We will error out after the body is completely 463 * consumed, but we can't stream more bytes at the 464 * back end since they would in part be interpreted 465 * as another request! If nothing is sent, then 466 * just send nothing. 467 * 468 * Prevents HTTP Response Splitting. 469 */ 470 if (bytes_streamed > cl_val) { 471 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, 472 "proxy: read more bytes of request body than expected " 473 "(got %" APR_OFF_T_FMT ", expected %" APR_OFF_T_FMT ")", 474 bytes_streamed, cl_val); 475 return HTTP_INTERNAL_SERVER_ERROR; 476 } 477 478 if (header_brigade) { 479 /* we never sent the header brigade, so go ahead and 480 * take care of that now 481 */ 482 bb = header_brigade; 483 484 /* 485 * Save input_brigade in bb brigade. (At least) in the SSL case 486 * input_brigade contains transient buckets whose data would get 487 * overwritten during the next call of ap_get_brigade in the loop. 488 * ap_save_brigade ensures these buckets to be set aside. 489 * Calling ap_save_brigade with NULL as filter is OK, because 490 * bb brigade already has been created and does not need to get 491 * created by ap_save_brigade. 492 */ 493 status = ap_save_brigade(NULL, &bb, &input_brigade, p); 494 if (status != APR_SUCCESS) { 495 return HTTP_INTERNAL_SERVER_ERROR; 496 } 497 498 header_brigade = NULL; 499 } 500 else { 501 bb = input_brigade; 502 } 503 504 /* Once we hit EOS, we are ready to flush. */ 505 rv = pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos); 506 if (rv != OK) { 507 return rv ; 508 } 509 510 if (seen_eos) { 511 break; 512 } 513 514 status = ap_get_brigade(r->input_filters, input_brigade, 515 AP_MODE_READBYTES, APR_BLOCK_READ, 516 HUGE_STRING_LEN); 517 518 if (status != APR_SUCCESS) { 519 return HTTP_BAD_REQUEST; 520 } 521 } 522 523 if (bytes_streamed != cl_val) { 524 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, 525 "proxy: client %s given Content-Length did not match" 526 " number of body bytes read", r->connection->remote_ip); 527 return HTTP_BAD_REQUEST; 528 } 529 530 if (header_brigade) { 531 /* we never sent the header brigade since there was no request 532 * body; send it now with the flush flag 533 */ 534 bb = header_brigade; 535 return(pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1)); 536 } 537 538 return OK; 539} 540 541static int spool_reqbody_cl(apr_pool_t *p, 542 request_rec *r, 543 proxy_conn_rec *p_conn, 544 conn_rec *origin, 545 apr_bucket_brigade *header_brigade, 546 apr_bucket_brigade *input_brigade, 547 int force_cl) 548{ 549 int seen_eos = 0; 550 apr_status_t status; 551 apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; 552 apr_bucket_brigade *body_brigade; 553 apr_bucket *e; 554 apr_off_t bytes, bytes_spooled = 0, fsize = 0; 555 apr_file_t *tmpfile = NULL; 556 557 body_brigade = apr_brigade_create(p, bucket_alloc); 558 559 while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) 560 { 561 /* If this brigade contains EOS, either stop or remove it. */ 562 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { 563 seen_eos = 1; 564 565 /* We can't pass this EOS to the output_filters. */ 566 e = APR_BRIGADE_LAST(input_brigade); 567 apr_bucket_delete(e); 568 } 569 570 apr_brigade_length(input_brigade, 1, &bytes); 571 572 if (bytes_spooled + bytes > MAX_MEM_SPOOL) { 573 /* can't spool any more in memory; write latest brigade to disk */ 574 if (tmpfile == NULL) { 575 const char *temp_dir; 576 char *template; 577 578 status = apr_temp_dir_get(&temp_dir, p); 579 if (status != APR_SUCCESS) { 580 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, 581 "proxy: search for temporary directory failed"); 582 return HTTP_INTERNAL_SERVER_ERROR; 583 } 584 apr_filepath_merge(&template, temp_dir, 585 "modproxy.tmp.XXXXXX", 586 APR_FILEPATH_NATIVE, p); 587 status = apr_file_mktemp(&tmpfile, template, 0, p); 588 if (status != APR_SUCCESS) { 589 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, 590 "proxy: creation of temporary file in directory %s failed", 591 temp_dir); 592 return HTTP_INTERNAL_SERVER_ERROR; 593 } 594 } 595 for (e = APR_BRIGADE_FIRST(input_brigade); 596 e != APR_BRIGADE_SENTINEL(input_brigade); 597 e = APR_BUCKET_NEXT(e)) { 598 const char *data; 599 apr_size_t bytes_read, bytes_written; 600 601 apr_bucket_read(e, &data, &bytes_read, APR_BLOCK_READ); 602 status = apr_file_write_full(tmpfile, data, bytes_read, &bytes_written); 603 if (status != APR_SUCCESS) { 604 const char *tmpfile_name; 605 606 if (apr_file_name_get(&tmpfile_name, tmpfile) != APR_SUCCESS) { 607 tmpfile_name = "(unknown)"; 608 } 609 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, 610 "proxy: write to temporary file %s failed", 611 tmpfile_name); 612 return HTTP_INTERNAL_SERVER_ERROR; 613 } 614 AP_DEBUG_ASSERT(bytes_read == bytes_written); 615 fsize += bytes_written; 616 } 617 apr_brigade_cleanup(input_brigade); 618 } 619 else { 620 621 /* 622 * Save input_brigade in body_brigade. (At least) in the SSL case 623 * input_brigade contains transient buckets whose data would get 624 * overwritten during the next call of ap_get_brigade in the loop. 625 * ap_save_brigade ensures these buckets to be set aside. 626 * Calling ap_save_brigade with NULL as filter is OK, because 627 * body_brigade already has been created and does not need to get 628 * created by ap_save_brigade. 629 */ 630 status = ap_save_brigade(NULL, &body_brigade, &input_brigade, p); 631 if (status != APR_SUCCESS) { 632 return HTTP_INTERNAL_SERVER_ERROR; 633 } 634 635 } 636 637 bytes_spooled += bytes; 638 639 if (seen_eos) { 640 break; 641 } 642 643 status = ap_get_brigade(r->input_filters, input_brigade, 644 AP_MODE_READBYTES, APR_BLOCK_READ, 645 HUGE_STRING_LEN); 646 647 if (status != APR_SUCCESS) { 648 return HTTP_BAD_REQUEST; 649 } 650 } 651 652 if (bytes_spooled || force_cl) { 653 add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled)); 654 } 655 terminate_headers(bucket_alloc, header_brigade); 656 APR_BRIGADE_CONCAT(header_brigade, body_brigade); 657 if (tmpfile) { 658 /* For platforms where the size of the file may be larger than 659 * that which can be stored in a single bucket (where the 660 * length field is an apr_size_t), split it into several 661 * buckets: */ 662 if (sizeof(apr_off_t) > sizeof(apr_size_t) 663 && fsize > AP_MAX_SENDFILE) { 664 e = apr_bucket_file_create(tmpfile, 0, AP_MAX_SENDFILE, p, 665 bucket_alloc); 666 while (fsize > AP_MAX_SENDFILE) { 667 apr_bucket *ce; 668 apr_bucket_copy(e, &ce); 669 APR_BRIGADE_INSERT_TAIL(header_brigade, ce); 670 e->start += AP_MAX_SENDFILE; 671 fsize -= AP_MAX_SENDFILE; 672 } 673 e->length = (apr_size_t)fsize; /* Resize just the last bucket */ 674 } 675 else { 676 e = apr_bucket_file_create(tmpfile, 0, (apr_size_t)fsize, p, 677 bucket_alloc); 678 } 679 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 680 } 681 /* This is all a single brigade, pass with flush flagged */ 682 return(pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1)); 683} 684 685static 686int ap_proxy_http_request(apr_pool_t *p, request_rec *r, 687 proxy_conn_rec *p_conn, conn_rec *origin, 688 proxy_server_conf *conf, 689 apr_uri_t *uri, 690 char *url, char *server_portstr) 691{ 692 conn_rec *c = r->connection; 693 apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; 694 apr_bucket_brigade *header_brigade; 695 apr_bucket_brigade *input_brigade; 696 apr_bucket_brigade *temp_brigade; 697 apr_bucket *e; 698 char *buf; 699 const apr_array_header_t *headers_in_array; 700 const apr_table_entry_t *headers_in; 701 int counter; 702 apr_status_t status; 703 enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL}; 704 enum rb_methods rb_method = RB_INIT; 705 const char *old_cl_val = NULL; 706 const char *old_te_val = NULL; 707 apr_off_t bytes_read = 0; 708 apr_off_t bytes; 709 int force10, rv; 710 apr_table_t *headers_in_copy; 711 712 header_brigade = apr_brigade_create(p, origin->bucket_alloc); 713 714 /* 715 * Send the HTTP/1.1 request to the remote server 716 */ 717 718 if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { 719 buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL); 720 force10 = 1; 721 /* 722 * According to RFC 2616 8.2.3 we are not allowed to forward an 723 * Expect: 100-continue to an HTTP/1.0 server. Instead we MUST return 724 * a HTTP_EXPECTATION_FAILED 725 */ 726 if (r->expecting_100) { 727 return HTTP_EXPECTATION_FAILED; 728 } 729 p_conn->close++; 730 } else { 731 buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL); 732 force10 = 0; 733 } 734 if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) { 735 origin->keepalive = AP_CONN_CLOSE; 736 p_conn->close++; 737 } 738 ap_xlate_proto_to_ascii(buf, strlen(buf)); 739 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); 740 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 741 if (conf->preserve_host == 0) { 742 if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */ 743 if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { 744 buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:", 745 uri->port_str, CRLF, NULL); 746 } else { 747 buf = apr_pstrcat(p, "Host: [", uri->hostname, "]", CRLF, NULL); 748 } 749 } else { 750 if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { 751 buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", 752 uri->port_str, CRLF, NULL); 753 } else { 754 buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL); 755 } 756 } 757 } 758 else { 759 /* don't want to use r->hostname, as the incoming header might have a 760 * port attached 761 */ 762 const char* hostname = apr_table_get(r->headers_in,"Host"); 763 if (!hostname) { 764 hostname = r->server->server_hostname; 765 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 766 "proxy: no HTTP 0.9 request (with no host line) " 767 "on incoming request and preserve host set " 768 "forcing hostname to be %s for uri %s", 769 hostname, 770 r->uri ); 771 } 772 buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL); 773 } 774 ap_xlate_proto_to_ascii(buf, strlen(buf)); 775 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); 776 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 777 778 /* handle Via */ 779 if (conf->viaopt == via_block) { 780 /* Block all outgoing Via: headers */ 781 apr_table_unset(r->headers_in, "Via"); 782 } else if (conf->viaopt != via_off) { 783 const char *server_name = ap_get_server_name(r); 784 /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, 785 * then the server name returned by ap_get_server_name() is the 786 * origin server name (which does make too much sense with Via: headers) 787 * so we use the proxy vhost's name instead. 788 */ 789 if (server_name == r->hostname) 790 server_name = r->server->server_hostname; 791 /* Create a "Via:" request header entry and merge it */ 792 /* Generate outgoing Via: header with/without server comment: */ 793 apr_table_mergen(r->headers_in, "Via", 794 (conf->viaopt == via_full) 795 ? apr_psprintf(p, "%d.%d %s%s (%s)", 796 HTTP_VERSION_MAJOR(r->proto_num), 797 HTTP_VERSION_MINOR(r->proto_num), 798 server_name, server_portstr, 799 AP_SERVER_BASEVERSION) 800 : apr_psprintf(p, "%d.%d %s%s", 801 HTTP_VERSION_MAJOR(r->proto_num), 802 HTTP_VERSION_MINOR(r->proto_num), 803 server_name, server_portstr) 804 ); 805 } 806 807 /* X-Forwarded-*: handling 808 * 809 * XXX Privacy Note: 810 * ----------------- 811 * 812 * These request headers are only really useful when the mod_proxy 813 * is used in a reverse proxy configuration, so that useful info 814 * about the client can be passed through the reverse proxy and on 815 * to the backend server, which may require the information to 816 * function properly. 817 * 818 * In a forward proxy situation, these options are a potential 819 * privacy violation, as information about clients behind the proxy 820 * are revealed to arbitrary servers out there on the internet. 821 * 822 * The HTTP/1.1 Via: header is designed for passing client 823 * information through proxies to a server, and should be used in 824 * a forward proxy configuation instead of X-Forwarded-*. See the 825 * ProxyVia option for details. 826 */ 827 828 if (PROXYREQ_REVERSE == r->proxyreq) { 829 const char *buf; 830 831 /* Add X-Forwarded-For: so that the upstream has a chance to 832 * determine, where the original request came from. 833 */ 834 apr_table_mergen(r->headers_in, "X-Forwarded-For", 835 c->remote_ip); 836 837 /* Add X-Forwarded-Host: so that upstream knows what the 838 * original request hostname was. 839 */ 840 if ((buf = apr_table_get(r->headers_in, "Host"))) { 841 apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf); 842 } 843 844 /* Add X-Forwarded-Server: so that upstream knows what the 845 * name of this proxy server is (if there are more than one) 846 * XXX: This duplicates Via: - do we strictly need it? 847 */ 848 apr_table_mergen(r->headers_in, "X-Forwarded-Server", 849 r->server->server_hostname); 850 } 851 852 proxy_run_fixups(r); 853 /* 854 * Make a copy of the headers_in table before clearing the connection 855 * headers as we need the connection headers later in the http output 856 * filter to prepare the correct response headers. 857 * 858 * Note: We need to take r->pool for apr_table_copy as the key / value 859 * pairs in r->headers_in have been created out of r->pool and 860 * p might be (and actually is) a longer living pool. 861 * This would trigger the bad pool ancestry abort in apr_table_copy if 862 * apr is compiled with APR_POOL_DEBUG. 863 */ 864 headers_in_copy = apr_table_copy(r->pool, r->headers_in); 865 ap_proxy_clear_connection(p, headers_in_copy); 866 /* send request headers */ 867 headers_in_array = apr_table_elts(headers_in_copy); 868 headers_in = (const apr_table_entry_t *) headers_in_array->elts; 869 for (counter = 0; counter < headers_in_array->nelts; counter++) { 870 if (headers_in[counter].key == NULL 871 || headers_in[counter].val == NULL 872 873 /* Already sent */ 874 || !strcasecmp(headers_in[counter].key, "Host") 875 876 /* Clear out hop-by-hop request headers not to send 877 * RFC2616 13.5.1 says we should strip these headers 878 */ 879 || !strcasecmp(headers_in[counter].key, "Keep-Alive") 880 || !strcasecmp(headers_in[counter].key, "TE") 881 || !strcasecmp(headers_in[counter].key, "Trailer") 882 || !strcasecmp(headers_in[counter].key, "Upgrade") 883 884 ) { 885 continue; 886 } 887 /* Do we want to strip Proxy-Authorization ? 888 * If we haven't used it, then NO 889 * If we have used it then MAYBE: RFC2616 says we MAY propagate it. 890 * So let's make it configurable by env. 891 */ 892 if (!strcasecmp(headers_in[counter].key,"Proxy-Authorization")) { 893 if (r->user != NULL) { /* we've authenticated */ 894 if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { 895 continue; 896 } 897 } 898 } 899 900 /* Skip Transfer-Encoding and Content-Length for now. 901 */ 902 if (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) { 903 old_te_val = headers_in[counter].val; 904 continue; 905 } 906 if (!strcasecmp(headers_in[counter].key, "Content-Length")) { 907 old_cl_val = headers_in[counter].val; 908 continue; 909 } 910 911 /* for sub-requests, ignore freshness/expiry headers */ 912 if (r->main) { 913 if ( !strcasecmp(headers_in[counter].key, "If-Match") 914 || !strcasecmp(headers_in[counter].key, "If-Modified-Since") 915 || !strcasecmp(headers_in[counter].key, "If-Range") 916 || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since") 917 || !strcasecmp(headers_in[counter].key, "If-None-Match")) { 918 continue; 919 } 920 } 921 922 buf = apr_pstrcat(p, headers_in[counter].key, ": ", 923 headers_in[counter].val, CRLF, 924 NULL); 925 ap_xlate_proto_to_ascii(buf, strlen(buf)); 926 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); 927 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 928 } 929 930 /* We have headers, let's figure out our request body... */ 931 input_brigade = apr_brigade_create(p, bucket_alloc); 932 933 /* sub-requests never use keepalives, and mustn't pass request bodies. 934 * Because the new logic looks at input_brigade, we will self-terminate 935 * input_brigade and jump past all of the request body logic... 936 * Reading anything with ap_get_brigade is likely to consume the 937 * main request's body or read beyond EOS - which would be unplesant. 938 */ 939 if (r->main) { 940 /* XXX: Why DON'T sub-requests use keepalives? */ 941 p_conn->close++; 942 if (old_cl_val) { 943 old_cl_val = NULL; 944 apr_table_unset(r->headers_in, "Content-Length"); 945 } 946 if (old_te_val) { 947 old_te_val = NULL; 948 apr_table_unset(r->headers_in, "Transfer-Encoding"); 949 } 950 rb_method = RB_STREAM_CL; 951 e = apr_bucket_eos_create(input_brigade->bucket_alloc); 952 APR_BRIGADE_INSERT_TAIL(input_brigade, e); 953 goto skip_body; 954 } 955 956 /* WE only understand chunked. Other modules might inject 957 * (and therefore, decode) other flavors but we don't know 958 * that the can and have done so unless they they remove 959 * their decoding from the headers_in T-E list. 960 * XXX: Make this extensible, but in doing so, presume the 961 * encoding has been done by the extensions' handler, and 962 * do not modify add_te_chunked's logic 963 */ 964 if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) { 965 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, 966 "proxy: %s Transfer-Encoding is not supported", 967 old_te_val); 968 return HTTP_INTERNAL_SERVER_ERROR; 969 } 970 971 if (old_cl_val && old_te_val) { 972 ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_ENOTIMPL, r->server, 973 "proxy: client %s (%s) requested Transfer-Encoding " 974 "chunked body with Content-Length (C-L ignored)", 975 c->remote_ip, c->remote_host ? c->remote_host: ""); 976 apr_table_unset(r->headers_in, "Content-Length"); 977 old_cl_val = NULL; 978 origin->keepalive = AP_CONN_CLOSE; 979 p_conn->close++; 980 } 981 982 /* Prefetch MAX_MEM_SPOOL bytes 983 * 984 * This helps us avoid any election of C-L v.s. T-E 985 * request bodies, since we are willing to keep in 986 * memory this much data, in any case. This gives 987 * us an instant C-L election if the body is of some 988 * reasonable size. 989 */ 990 temp_brigade = apr_brigade_create(p, bucket_alloc); 991 do { 992 status = ap_get_brigade(r->input_filters, temp_brigade, 993 AP_MODE_READBYTES, APR_BLOCK_READ, 994 MAX_MEM_SPOOL - bytes_read); 995 if (status != APR_SUCCESS) { 996 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, 997 "proxy: prefetch request body failed to %pI (%s)" 998 " from %s (%s)", 999 p_conn->addr, p_conn->hostname ? p_conn->hostname: "", 1000 c->remote_ip, c->remote_host ? c->remote_host: ""); 1001 return HTTP_BAD_REQUEST; 1002 } 1003 1004 apr_brigade_length(temp_brigade, 1, &bytes); 1005 bytes_read += bytes; 1006 1007 /* 1008 * Save temp_brigade in input_brigade. (At least) in the SSL case 1009 * temp_brigade contains transient buckets whose data would get 1010 * overwritten during the next call of ap_get_brigade in the loop. 1011 * ap_save_brigade ensures these buckets to be set aside. 1012 * Calling ap_save_brigade with NULL as filter is OK, because 1013 * input_brigade already has been created and does not need to get 1014 * created by ap_save_brigade. 1015 */ 1016 status = ap_save_brigade(NULL, &input_brigade, &temp_brigade, p); 1017 if (status != APR_SUCCESS) { 1018 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server, 1019 "proxy: processing prefetched request body failed" 1020 " to %pI (%s) from %s (%s)", 1021 p_conn->addr, p_conn->hostname ? p_conn->hostname: "", 1022 c->remote_ip, c->remote_host ? c->remote_host: ""); 1023 return HTTP_INTERNAL_SERVER_ERROR; 1024 } 1025 1026 /* Ensure we don't hit a wall where we have a buffer too small 1027 * for ap_get_brigade's filters to fetch us another bucket, 1028 * surrender once we hit 80 bytes less than MAX_MEM_SPOOL 1029 * (an arbitrary value.) 1030 */ 1031 } while ((bytes_read < MAX_MEM_SPOOL - 80) 1032 && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))); 1033 1034 /* Use chunked request body encoding or send a content-length body? 1035 * 1036 * Prefer C-L when: 1037 * 1038 * We have no request body (handled by RB_STREAM_CL) 1039 * 1040 * We have a request body length <= MAX_MEM_SPOOL 1041 * 1042 * The administrator has setenv force-proxy-request-1.0 1043 * 1044 * The client sent a C-L body, and the administrator has 1045 * not setenv proxy-sendchunked or has set setenv proxy-sendcl 1046 * 1047 * The client sent a T-E body, and the administrator has 1048 * setenv proxy-sendcl, and not setenv proxy-sendchunked 1049 * 1050 * If both proxy-sendcl and proxy-sendchunked are set, the 1051 * behavior is the same as if neither were set, large bodies 1052 * that can't be read will be forwarded in their original 1053 * form of C-L, or T-E. 1054 * 1055 * To ensure maximum compatibility, setenv proxy-sendcl 1056 * To reduce server resource use, setenv proxy-sendchunked 1057 * 1058 * Then address specific servers with conditional setenv 1059 * options to restore the default behavior where desireable. 1060 * 1061 * We have to compute content length by reading the entire request 1062 * body; if request body is not small, we'll spool the remaining 1063 * input to a temporary file. Chunked is always preferable. 1064 * 1065 * We can only trust the client-provided C-L if the T-E header 1066 * is absent, and the filters are unchanged (the body won't 1067 * be resized by another content filter). 1068 */ 1069 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { 1070 /* The whole thing fit, so our decision is trivial, use 1071 * the filtered bytes read from the client for the request 1072 * body Content-Length. 1073 * 1074 * If we expected no body, and read no body, do not set 1075 * the Content-Length. 1076 */ 1077 if (old_cl_val || old_te_val || bytes_read) { 1078 old_cl_val = apr_off_t_toa(r->pool, bytes_read); 1079 } 1080 rb_method = RB_STREAM_CL; 1081 } 1082 else if (old_te_val) { 1083 if (force10 1084 || (apr_table_get(r->subprocess_env, "proxy-sendcl") 1085 && !apr_table_get(r->subprocess_env, "proxy-sendchunks") 1086 && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { 1087 rb_method = RB_SPOOL_CL; 1088 } 1089 else { 1090 rb_method = RB_STREAM_CHUNKED; 1091 } 1092 } 1093 else if (old_cl_val) { 1094 if (r->input_filters == r->proto_input_filters) { 1095 rb_method = RB_STREAM_CL; 1096 } 1097 else if (!force10 1098 && (apr_table_get(r->subprocess_env, "proxy-sendchunks") 1099 || apr_table_get(r->subprocess_env, "proxy-sendchunked")) 1100 && !apr_table_get(r->subprocess_env, "proxy-sendcl")) { 1101 rb_method = RB_STREAM_CHUNKED; 1102 } 1103 else { 1104 rb_method = RB_SPOOL_CL; 1105 } 1106 } 1107 else { 1108 /* This is an appropriate default; very efficient for no-body 1109 * requests, and has the behavior that it will not add any C-L 1110 * when the old_cl_val is NULL. 1111 */ 1112 rb_method = RB_SPOOL_CL; 1113 } 1114 1115/* Yes I hate gotos. This is the subrequest shortcut */ 1116skip_body: 1117 /* 1118 * Handle Connection: header if we do HTTP/1.1 request: 1119 * If we plan to close the backend connection sent Connection: close 1120 * otherwise sent Connection: Keep-Alive. 1121 */ 1122 if (!force10) { 1123 if (p_conn->close || p_conn->close_on_recycle) { 1124 buf = apr_pstrdup(p, "Connection: close" CRLF); 1125 } 1126 else { 1127 buf = apr_pstrdup(p, "Connection: Keep-Alive" CRLF); 1128 } 1129 ap_xlate_proto_to_ascii(buf, strlen(buf)); 1130 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); 1131 APR_BRIGADE_INSERT_TAIL(header_brigade, e); 1132 } 1133 1134 /* send the request body, if any. */ 1135 switch(rb_method) { 1136 case RB_STREAM_CHUNKED: 1137 rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, 1138 input_brigade); 1139 break; 1140 case RB_STREAM_CL: 1141 rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, 1142 input_brigade, old_cl_val); 1143 break; 1144 case RB_SPOOL_CL: 1145 rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, 1146 input_brigade, (old_cl_val != NULL) 1147 || (old_te_val != NULL) 1148 || (bytes_read > 0)); 1149 break; 1150 default: 1151 /* shouldn't be possible */ 1152 rv = HTTP_INTERNAL_SERVER_ERROR ; 1153 break; 1154 } 1155 1156 if (rv != OK) { 1157 /* apr_errno value has been logged in lower level method */ 1158 ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, 1159 "proxy: pass request body failed to %pI (%s)" 1160 " from %s (%s)", 1161 p_conn->addr, 1162 p_conn->hostname ? p_conn->hostname: "", 1163 c->remote_ip, 1164 c->remote_host ? c->remote_host: ""); 1165 return rv; 1166 } 1167 1168 return OK; 1169} 1170 1171static void process_proxy_header(request_rec* r, proxy_dir_conf* c, 1172 const char* key, const char* value) 1173{ 1174 static const char* date_hdrs[] 1175 = { "Date", "Expires", "Last-Modified", NULL } ; 1176 static const struct { 1177 const char* name; 1178 ap_proxy_header_reverse_map_fn func; 1179 } transform_hdrs[] = { 1180 { "Location", ap_proxy_location_reverse_map } , 1181 { "Content-Location", ap_proxy_location_reverse_map } , 1182 { "URI", ap_proxy_location_reverse_map } , 1183 { "Destination", ap_proxy_location_reverse_map } , 1184 { "Set-Cookie", ap_proxy_cookie_reverse_map } , 1185 { NULL, NULL } 1186 } ; 1187 int i ; 1188 for ( i = 0 ; date_hdrs[i] ; ++i ) { 1189 if ( !strcasecmp(date_hdrs[i], key) ) { 1190 apr_table_add(r->headers_out, key, 1191 ap_proxy_date_canon(r->pool, value)) ; 1192 return ; 1193 } 1194 } 1195 for ( i = 0 ; transform_hdrs[i].name ; ++i ) { 1196 if ( !strcasecmp(transform_hdrs[i].name, key) ) { 1197 apr_table_add(r->headers_out, key, 1198 (*transform_hdrs[i].func)(r, c, value)) ; 1199 return ; 1200 } 1201 } 1202 apr_table_add(r->headers_out, key, value) ; 1203 return ; 1204} 1205 1206/* 1207 * Note: pread_len is the length of the response that we've mistakenly 1208 * read (assuming that we don't consider that an error via 1209 * ProxyBadHeader StartBody). This depends on buffer actually being 1210 * local storage to the calling code in order for pread_len to make 1211 * any sense at all, since we depend on buffer still containing 1212 * what was read by ap_getline() upon return. 1213 */ 1214static void ap_proxy_read_headers(request_rec *r, request_rec *rr, 1215 char *buffer, int size, 1216 conn_rec *c, int *pread_len) 1217{ 1218 int len; 1219 char *value, *end; 1220 char field[MAX_STRING_LEN]; 1221 int saw_headers = 0; 1222 void *sconf = r->server->module_config; 1223 proxy_server_conf *psc; 1224 proxy_dir_conf *dconf; 1225 1226 dconf = ap_get_module_config(r->per_dir_config, &proxy_module); 1227 psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); 1228 1229 r->headers_out = apr_table_make(r->pool, 20); 1230 *pread_len = 0; 1231 1232 /* 1233 * Read header lines until we get the empty separator line, a read error, 1234 * the connection closes (EOF), or we timeout. 1235 */ 1236 while ((len = ap_getline(buffer, size, rr, 1)) > 0) { 1237 1238 if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ 1239 1240 /* We may encounter invalid headers, usually from buggy 1241 * MS IIS servers, so we need to determine just how to handle 1242 * them. We can either ignore them, assume that they mark the 1243 * start-of-body (eg: a missing CRLF) or (the default) mark 1244 * the headers as totally bogus and return a 500. The sole 1245 * exception is an extra "HTTP/1.0 200, OK" line sprinkled 1246 * in between the usual MIME headers, which is a favorite 1247 * IIS bug. 1248 */ 1249 /* XXX: The mask check is buggy if we ever see an HTTP/1.10 */ 1250 1251 if (!apr_date_checkmask(buffer, "HTTP/#.# ###*")) { 1252 if (psc->badopt == bad_error) { 1253 /* Nope, it wasn't even an extra HTTP header. Give up. */ 1254 r->headers_out = NULL; 1255 return ; 1256 } 1257 else if (psc->badopt == bad_body) { 1258 /* if we've already started loading headers_out, then 1259 * return what we've accumulated so far, in the hopes 1260 * that they are useful; also note that we likely pre-read 1261 * the first line of the response. 1262 */ 1263 if (saw_headers) { 1264 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, 1265 "proxy: Starting body due to bogus non-header in headers " 1266 "returned by %s (%s)", r->uri, r->method); 1267 *pread_len = len; 1268 return ; 1269 } else { 1270 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, 1271 "proxy: No HTTP headers " 1272 "returned by %s (%s)", r->uri, r->method); 1273 return ; 1274 } 1275 } 1276 } 1277 /* this is the psc->badopt == bad_ignore case */ 1278 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, 1279 "proxy: Ignoring bogus HTTP header " 1280 "returned by %s (%s)", r->uri, r->method); 1281 continue; 1282 } 1283 1284 *value = '\0'; 1285 ++value; 1286 /* XXX: RFC2068 defines only SP and HT as whitespace, this test is 1287 * wrong... and so are many others probably. 1288 */ 1289 while (apr_isspace(*value)) 1290 ++value; /* Skip to start of value */ 1291 1292 /* should strip trailing whitespace as well */ 1293 for (end = &value[strlen(value)-1]; end > value && apr_isspace(*end); -- 1294end) 1295 *end = '\0'; 1296 1297 /* make sure we add so as not to destroy duplicated headers 1298 * Modify headers requiring canonicalisation and/or affected 1299 * by ProxyPassReverse and family with process_proxy_header 1300 */ 1301 process_proxy_header(r, dconf, buffer, value) ; 1302 saw_headers = 1; 1303 1304 /* the header was too long; at the least we should skip extra data */ 1305 if (len >= size - 1) { 1306 while ((len = ap_getline(field, MAX_STRING_LEN, rr, 1)) 1307 >= MAX_STRING_LEN - 1) { 1308 /* soak up the extra data */ 1309 } 1310 if (len == 0) /* time to exit the larger loop as well */ 1311 break; 1312 } 1313 } 1314} 1315 1316 1317 1318static int addit_dammit(void *v, const char *key, const char *val) 1319{ 1320 apr_table_addn(v, key, val); 1321 return 1; 1322} 1323 1324static 1325apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec *r, 1326 int fold, int *writen) 1327{ 1328 char *tmp_s = s; 1329 apr_status_t rv; 1330 apr_size_t len; 1331 1332 rv = ap_rgetline(&tmp_s, n, &len, r, fold, bb); 1333 apr_brigade_cleanup(bb); 1334 1335 if (rv == APR_SUCCESS) { 1336 *writen = (int) len; 1337 } else if (rv == APR_ENOSPC) { 1338 *writen = n; 1339 } else { 1340 *writen = -1; 1341 } 1342 1343 return rv; 1344} 1345 1346/* 1347 * Limit the number of interim respones we sent back to the client. Otherwise 1348 * we suffer from a memory build up. Besides there is NO sense in sending back 1349 * an unlimited number of interim responses to the client. Thus if we cross 1350 * this limit send back a 502 (Bad Gateway). 1351 */ 1352#ifndef AP_MAX_INTERIM_RESPONSES 1353#define AP_MAX_INTERIM_RESPONSES 10 1354#endif 1355 1356static 1357apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, 1358 proxy_conn_rec *backend, 1359 conn_rec *origin, 1360 proxy_server_conf *conf, 1361 char *server_portstr) { 1362 conn_rec *c = r->connection; 1363 char buffer[HUGE_STRING_LEN]; 1364 const char *buf; 1365 char keepchar; 1366 request_rec *rp; 1367 apr_bucket *e; 1368 apr_bucket_brigade *bb, *tmp_bb; 1369 apr_bucket_brigade *pass_bb; 1370 int len, backasswards; 1371 int interim_response = 0; /* non-zero whilst interim 1xx responses 1372 * are being read. */ 1373 int pread_len = 0; 1374 apr_table_t *save_table; 1375 int backend_broke = 0; 1376 static const char *hop_by_hop_hdrs[] = 1377 {"Keep-Alive", "Proxy-Authenticate", "TE", "Trailer", "Upgrade", NULL}; 1378 int i; 1379 const char *te = NULL; 1380 int original_status = r->status; 1381 int proxy_status = OK; 1382 const char *original_status_line = r->status_line; 1383 const char *proxy_status_line = NULL; 1384 1385 bb = apr_brigade_create(p, c->bucket_alloc); 1386 pass_bb = apr_brigade_create(p, c->bucket_alloc); 1387 1388 /* Get response from the remote server, and pass it up the 1389 * filter chain 1390 */ 1391 1392 rp = ap_proxy_make_fake_req(origin, r); 1393 /* In case anyone needs to know, this is a fake request that is really a 1394 * response. 1395 */ 1396 rp->proxyreq = PROXYREQ_RESPONSE; 1397 tmp_bb = apr_brigade_create(p, c->bucket_alloc); 1398 do { 1399 apr_status_t rc; 1400 1401 apr_brigade_cleanup(bb); 1402 1403 rc = ap_proxygetline(tmp_bb, buffer, sizeof(buffer), rp, 0, &len); 1404 if (len == 0) { 1405 /* handle one potential stray CRLF */ 1406 rc = ap_proxygetline(tmp_bb, buffer, sizeof(buffer), rp, 0, &len); 1407 } 1408 if (len <= 0) { 1409 ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, 1410 "proxy: error reading status line from remote " 1411 "server %s:%d", backend->hostname, backend->port); 1412 if (APR_STATUS_IS_TIMEUP(rc)) { 1413 apr_table_set(r->notes, "proxy_timedout", "1"); 1414 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1415 "proxy: read timeout"); 1416 } 1417 /* 1418 * If we are a reverse proxy request shutdown the connection 1419 * WITHOUT ANY response to trigger a retry by the client 1420 * if allowed (as for idempotent requests). 1421 * BUT currently we should not do this if the request is the 1422 * first request on a keepalive connection as browsers like 1423 * seamonkey only display an empty page in this case and do 1424 * not do a retry. We should also not do this on a 1425 * connection which times out; instead handle as 1426 * we normally would handle timeouts 1427 */ 1428 if (r->proxyreq == PROXYREQ_REVERSE && c->keepalives && 1429 !APR_STATUS_IS_TIMEUP(rc)) { 1430 apr_bucket *eos; 1431 1432 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1433 "proxy: Closing connection to client because" 1434 " reading from backend server %s:%d failed." 1435 " Number of keepalives %i", backend->hostname, 1436 backend->port, c->keepalives); 1437 ap_proxy_backend_broke(r, bb); 1438 /* 1439 * Add an EOC bucket to signal the ap_http_header_filter 1440 * that it should get out of our way, BUT ensure that the 1441 * EOC bucket is inserted BEFORE an EOS bucket in bb as 1442 * some resource filters like mod_deflate pass everything 1443 * up to the EOS down the chain immediately and sent the 1444 * remainder of the brigade later (or even never). But in 1445 * this case the ap_http_header_filter does not get out of 1446 * our way soon enough. 1447 */ 1448 e = ap_bucket_eoc_create(c->bucket_alloc); 1449 eos = APR_BRIGADE_LAST(bb); 1450 while ((APR_BRIGADE_SENTINEL(bb) != eos) 1451 && !APR_BUCKET_IS_EOS(eos)) { 1452 eos = APR_BUCKET_PREV(eos); 1453 } 1454 if (eos == APR_BRIGADE_SENTINEL(bb)) { 1455 APR_BRIGADE_INSERT_TAIL(bb, e); 1456 } 1457 else { 1458 APR_BUCKET_INSERT_BEFORE(eos, e); 1459 } 1460 ap_pass_brigade(r->output_filters, bb); 1461 /* Mark the backend connection for closing */ 1462 backend->close = 1; 1463 /* Need to return OK to avoid sending an error message */ 1464 return OK; 1465 } 1466 else if (!c->keepalives) { 1467 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1468 "proxy: NOT Closing connection to client" 1469 " although reading from backend server %s:%d" 1470 " failed.", backend->hostname, 1471 backend->port); 1472 } 1473 return ap_proxyerror(r, HTTP_BAD_GATEWAY, 1474 "Error reading from remote server"); 1475 } 1476 /* XXX: Is this a real headers length send from remote? */ 1477 backend->worker->s->read += len; 1478 1479 /* Is it an HTTP/1 response? 1480 * This is buggy if we ever see an HTTP/1.10 1481 */ 1482 if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { 1483 int major, minor; 1484 1485 major = buffer[5] - '0'; 1486 minor = buffer[7] - '0'; 1487 1488 /* If not an HTTP/1 message or 1489 * if the status line was > 8192 bytes 1490 */ 1491 if ((major != 1) || (len >= sizeof(buffer)-1)) { 1492 return ap_proxyerror(r, HTTP_BAD_GATEWAY, 1493 apr_pstrcat(p, "Corrupt status line returned by remote " 1494 "server: ", buffer, NULL)); 1495 } 1496 backasswards = 0; 1497 1498 keepchar = buffer[12]; 1499 buffer[12] = '\0'; 1500 proxy_status = atoi(&buffer[9]); 1501 1502 if (keepchar != '\0') { 1503 buffer[12] = keepchar; 1504 } else { 1505 /* 2616 requires the space in Status-Line; the origin 1506 * server may have sent one but ap_rgetline_core will 1507 * have stripped it. */ 1508 buffer[12] = ' '; 1509 buffer[13] = '\0'; 1510 } 1511 proxy_status_line = apr_pstrdup(p, &buffer[9]); 1512 1513 /* The status out of the front is the same as the status coming in 1514 * from the back, until further notice. 1515 */ 1516 r->status = proxy_status; 1517 r->status_line = proxy_status_line; 1518 1519 /* read the headers. */ 1520 /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/ 1521 /* Also, take care with headers with multiple occurences. */ 1522 1523 /* First, tuck away all already existing cookies */ 1524 save_table = apr_table_make(r->pool, 2); 1525 apr_table_do(addit_dammit, save_table, r->headers_out, 1526 "Set-Cookie", NULL); 1527 1528 /* shove the headers direct into r->headers_out */ 1529 ap_proxy_read_headers(r, rp, buffer, sizeof(buffer), origin, 1530 &pread_len); 1531 1532 if (r->headers_out == NULL) { 1533 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, 1534 r->server, "proxy: bad HTTP/%d.%d header " 1535 "returned by %s (%s)", major, minor, r->uri, 1536 r->method); 1537 backend->close += 1; 1538 /* 1539 * ap_send_error relies on a headers_out to be present. we 1540 * are in a bad position here.. so force everything we send out 1541 * to have nothing to do with the incoming packet 1542 */ 1543 r->headers_out = apr_table_make(r->pool,1); 1544 r->status = HTTP_BAD_GATEWAY; 1545 r->status_line = "bad gateway"; 1546 return r->status; 1547 } 1548 1549 /* Now, add in the just read cookies */ 1550 apr_table_do(addit_dammit, save_table, r->headers_out, 1551 "Set-Cookie", NULL); 1552 1553 /* and now load 'em all in */ 1554 if (!apr_is_empty_table(save_table)) { 1555 apr_table_unset(r->headers_out, "Set-Cookie"); 1556 r->headers_out = apr_table_overlay(r->pool, 1557 r->headers_out, 1558 save_table); 1559 } 1560 1561 /* can't have both Content-Length and Transfer-Encoding */ 1562 if (apr_table_get(r->headers_out, "Transfer-Encoding") 1563 && apr_table_get(r->headers_out, "Content-Length")) { 1564 /* 1565 * 2616 section 4.4, point 3: "if both Transfer-Encoding 1566 * and Content-Length are received, the latter MUST be 1567 * ignored"; 1568 * 1569 * To help mitigate HTTP Splitting, unset Content-Length 1570 * and shut down the backend server connection 1571 * XXX: We aught to treat such a response as uncachable 1572 */ 1573 apr_table_unset(r->headers_out, "Content-Length"); 1574 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1575 "proxy: server %s:%d returned Transfer-Encoding" 1576 " and Content-Length", backend->hostname, 1577 backend->port); 1578 backend->close += 1; 1579 } 1580 1581 /* 1582 * Save a possible Transfer-Encoding header as we need it later for 1583 * ap_http_filter to know where to end. 1584 */ 1585 te = apr_table_get(r->headers_out, "Transfer-Encoding"); 1586 /* strip connection listed hop-by-hop headers from response */ 1587 backend->close += ap_proxy_liststr(apr_table_get(r->headers_out, 1588 "Connection"), 1589 "close"); 1590 ap_proxy_clear_connection(p, r->headers_out); 1591 if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { 1592 ap_set_content_type(r, apr_pstrdup(p, buf)); 1593 } 1594 if (!ap_is_HTTP_INFO(proxy_status)) { 1595 ap_proxy_pre_http_request(origin, rp); 1596 } 1597 1598 /* Clear hop-by-hop headers */ 1599 for (i=0; hop_by_hop_hdrs[i]; ++i) { 1600 apr_table_unset(r->headers_out, hop_by_hop_hdrs[i]); 1601 } 1602 /* Delete warnings with wrong date */ 1603 r->headers_out = ap_proxy_clean_warnings(p, r->headers_out); 1604 1605 /* handle Via header in response */ 1606 if (conf->viaopt != via_off && conf->viaopt != via_block) { 1607 const char *server_name = ap_get_server_name(r); 1608 /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, 1609 * then the server name returned by ap_get_server_name() is the 1610 * origin server name (which does make too much sense with Via: headers) 1611 * so we use the proxy vhost's name instead. 1612 */ 1613 if (server_name == r->hostname) 1614 server_name = r->server->server_hostname; 1615 /* create a "Via:" response header entry and merge it */ 1616 apr_table_addn(r->headers_out, "Via", 1617 (conf->viaopt == via_full) 1618 ? apr_psprintf(p, "%d.%d %s%s (%s)", 1619 HTTP_VERSION_MAJOR(r->proto_num), 1620 HTTP_VERSION_MINOR(r->proto_num), 1621 server_name, 1622 server_portstr, 1623 AP_SERVER_BASEVERSION) 1624 : apr_psprintf(p, "%d.%d %s%s", 1625 HTTP_VERSION_MAJOR(r->proto_num), 1626 HTTP_VERSION_MINOR(r->proto_num), 1627 server_name, 1628 server_portstr) 1629 ); 1630 } 1631 1632 /* cancel keepalive if HTTP/1.0 or less */ 1633 if ((major < 1) || (minor < 1)) { 1634 backend->close += 1; 1635 origin->keepalive = AP_CONN_CLOSE; 1636 } 1637 } else { 1638 /* an http/0.9 response */ 1639 backasswards = 1; 1640 r->status = 200; 1641 r->status_line = "200 OK"; 1642 backend->close += 1; 1643 } 1644 1645 if (ap_is_HTTP_INFO(proxy_status)) { 1646 interim_response++; 1647 } 1648 else { 1649 interim_response = 0; 1650 } 1651 if (interim_response) { 1652 /* RFC2616 tells us to forward this. 1653 * 1654 * OTOH, an interim response here may mean the backend 1655 * is playing sillybuggers. The Client didn't ask for 1656 * it within the defined HTTP/1.1 mechanisms, and if 1657 * it's an extension, it may also be unsupported by us. 1658 * 1659 * There's also the possibility that changing existing 1660 * behaviour here might break something. 1661 * 1662 * So let's make it configurable. 1663 */ 1664 const char *policy = apr_table_get(r->subprocess_env, 1665 "proxy-interim-response"); 1666 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1667 "proxy: HTTP: received interim %d response", 1668 r->status); 1669 if (!policy || !strcasecmp(policy, "RFC")) { 1670 ap_send_interim_response(r, 1); 1671 } 1672 /* FIXME: refine this to be able to specify per-response-status 1673 * policies and maybe also add option to bail out with 502 1674 */ 1675 else if (strcasecmp(policy, "Suppress")) { 1676 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, 1677 "undefined proxy interim response policy"); 1678 } 1679 } 1680 /* Moved the fixups of Date headers and those affected by 1681 * ProxyPassReverse/etc from here to ap_proxy_read_headers 1682 */ 1683 1684 if ((proxy_status == 401) && (conf->error_override)) { 1685 const char *buf; 1686 const char *wa = "WWW-Authenticate"; 1687 if ((buf = apr_table_get(r->headers_out, wa))) { 1688 apr_table_set(r->err_headers_out, wa, buf); 1689 } else { 1690 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1691 "proxy: origin server sent 401 without WWW-Authenticate header"); 1692 } 1693 } 1694 1695 r->sent_bodyct = 1; 1696 /* 1697 * Is it an HTTP/0.9 response or did we maybe preread the 1st line of 1698 * the response? If so, load the extra data. These are 2 mutually 1699 * exclusive possibilities, that just happen to require very 1700 * similar behavior. 1701 */ 1702 if (backasswards || pread_len) { 1703 apr_ssize_t cntr = (apr_ssize_t)pread_len; 1704 if (backasswards) { 1705 /*@@@FIXME: 1706 * At this point in response processing of a 0.9 response, 1707 * we don't know yet whether data is binary or not. 1708 * mod_charset_lite will get control later on, so it cannot 1709 * decide on the conversion of this buffer full of data. 1710 * However, chances are that we are not really talking to an 1711 * HTTP/0.9 server, but to some different protocol, therefore 1712 * the best guess IMHO is to always treat the buffer as "text/x": 1713 */ 1714 ap_xlate_proto_to_ascii(buffer, len); 1715 cntr = (apr_ssize_t)len; 1716 } 1717 e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc); 1718 APR_BRIGADE_INSERT_TAIL(bb, e); 1719 } 1720 1721 /* send body - but only if a body is expected */ 1722 if ((!r->header_only) && /* not HEAD request */ 1723 !interim_response && /* not any 1xx response */ 1724 (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ 1725 (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ 1726 1727 /* We need to copy the output headers and treat them as input 1728 * headers as well. BUT, we need to do this before we remove 1729 * TE, so that they are preserved accordingly for 1730 * ap_http_filter to know where to end. 1731 */ 1732 rp->headers_in = apr_table_copy(r->pool, r->headers_out); 1733 /* 1734 * Restore Transfer-Encoding header from response if we saved 1735 * one before and there is none left. We need it for the 1736 * ap_http_filter. See above. 1737 */ 1738 if (te && !apr_table_get(rp->headers_in, "Transfer-Encoding")) { 1739 apr_table_add(rp->headers_in, "Transfer-Encoding", te); 1740 } 1741 1742 apr_table_unset(r->headers_out,"Transfer-Encoding"); 1743 1744 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1745 "proxy: start body send"); 1746 1747 /* 1748 * if we are overriding the errors, we can't put the content 1749 * of the page into the brigade 1750 */ 1751 if (!conf->error_override || !ap_is_HTTP_ERROR(proxy_status)) { 1752 /* read the body, pass it to the output filters */ 1753 apr_read_type_e mode = APR_NONBLOCK_READ; 1754 int finish = FALSE; 1755 1756 /* Handle the case where the error document is itself reverse 1757 * proxied and was successful. We must maintain any previous 1758 * error status so that an underlying error (eg HTTP_NOT_FOUND) 1759 * doesn't become an HTTP_OK. 1760 */ 1761 if (conf->error_override && !ap_is_HTTP_ERROR(proxy_status) 1762 && ap_is_HTTP_ERROR(original_status)) { 1763 r->status = original_status; 1764 r->status_line = original_status_line; 1765 } 1766 1767 do { 1768 apr_off_t readbytes; 1769 apr_status_t rv; 1770 1771 rv = ap_get_brigade(rp->input_filters, bb, 1772 AP_MODE_READBYTES, mode, 1773 conf->io_buffer_size); 1774 1775 /* ap_get_brigade will return success with an empty brigade 1776 * for a non-blocking read which would block: */ 1777 if (APR_STATUS_IS_EAGAIN(rv) 1778 || (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb))) { 1779 /* flush to the client and switch to blocking mode */ 1780 e = apr_bucket_flush_create(c->bucket_alloc); 1781 APR_BRIGADE_INSERT_TAIL(bb, e); 1782 if (ap_pass_brigade(r->output_filters, bb) 1783 || c->aborted) { 1784 backend->close = 1; 1785 break; 1786 } 1787 apr_brigade_cleanup(bb); 1788 mode = APR_BLOCK_READ; 1789 continue; 1790 } 1791 else if (rv == APR_EOF) { 1792 break; 1793 } 1794 else if (rv != APR_SUCCESS) { 1795 /* In this case, we are in real trouble because 1796 * our backend bailed on us. Pass along a 502 error 1797 * error bucket 1798 */ 1799 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, 1800 "proxy: error reading response"); 1801 ap_proxy_backend_broke(r, bb); 1802 ap_pass_brigade(r->output_filters, bb); 1803 backend_broke = 1; 1804 backend->close = 1; 1805 break; 1806 } 1807 /* next time try a non-blocking read */ 1808 mode = APR_NONBLOCK_READ; 1809 1810 apr_brigade_length(bb, 0, &readbytes); 1811 backend->worker->s->read += readbytes; 1812#if DEBUGGING 1813 { 1814 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 1815 r->server, "proxy (PID %d): readbytes: %#x", 1816 getpid(), readbytes); 1817 } 1818#endif 1819 /* sanity check */ 1820 if (APR_BRIGADE_EMPTY(bb)) { 1821 apr_brigade_cleanup(bb); 1822 break; 1823 } 1824 1825 /* Switch the allocator lifetime of the buckets */ 1826 ap_proxy_buckets_lifetime_transform(r, bb, pass_bb); 1827 1828 /* found the last brigade? */ 1829 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) { 1830 /* signal that we must leave */ 1831 finish = TRUE; 1832 } 1833 1834 /* try send what we read */ 1835 if (ap_pass_brigade(r->output_filters, pass_bb) != APR_SUCCESS 1836 || c->aborted) { 1837 /* Ack! Phbtt! Die! User aborted! */ 1838 backend->close = 1; /* this causes socket close below */ 1839 finish = TRUE; 1840 } 1841 1842 /* make sure we always clean up after ourselves */ 1843 apr_brigade_cleanup(bb); 1844 apr_brigade_cleanup(pass_bb); 1845 1846 } while (!finish); 1847 } 1848 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1849 "proxy: end body send"); 1850 } 1851 else if (!interim_response) { 1852 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1853 "proxy: header only"); 1854 1855 /* Pass EOS bucket down the filter chain. */ 1856 e = apr_bucket_eos_create(c->bucket_alloc); 1857 APR_BRIGADE_INSERT_TAIL(bb, e); 1858 if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS 1859 || c->aborted) { 1860 /* Ack! Phbtt! Die! User aborted! */ 1861 backend->close = 1; /* this causes socket close below */ 1862 } 1863 1864 apr_brigade_cleanup(bb); 1865 } 1866 } while (interim_response && (interim_response < AP_MAX_INTERIM_RESPONSES)); 1867 1868 /* See define of AP_MAX_INTERIM_RESPONSES for why */ 1869 if (interim_response >= AP_MAX_INTERIM_RESPONSES) { 1870 return ap_proxyerror(r, HTTP_BAD_GATEWAY, 1871 apr_psprintf(p, 1872 "Too many (%d) interim responses from origin server", 1873 interim_response)); 1874 } 1875 1876 /* If our connection with the client is to be aborted, return DONE. */ 1877 if (c->aborted || backend_broke) { 1878 return DONE; 1879 } 1880 1881 if (conf->error_override) { 1882 /* the code above this checks for 'OK' which is what the hook expects */ 1883 if (!ap_is_HTTP_ERROR(proxy_status)) { 1884 return OK; 1885 } 1886 else { 1887 /* clear r->status for override error, otherwise ErrorDocument 1888 * thinks that this is a recursive error, and doesn't find the 1889 * custom error page 1890 */ 1891 r->status = HTTP_OK; 1892 /* Discard body, if one is expected */ 1893 if (!r->header_only && /* not HEAD request */ 1894 (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ 1895 (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ 1896 ap_discard_request_body(rp); 1897 } 1898 return proxy_status; 1899 } 1900 } 1901 else { 1902 return OK; 1903 } 1904} 1905 1906static 1907apr_status_t ap_proxy_http_cleanup(const char *scheme, request_rec *r, 1908 proxy_conn_rec *backend) 1909{ 1910 ap_proxy_release_connection(scheme, backend, r->server); 1911 return OK; 1912} 1913 1914/* 1915 * This handles http:// URLs, and other URLs using a remote proxy over http 1916 * If proxyhost is NULL, then contact the server directly, otherwise 1917 * go via the proxy. 1918 * Note that if a proxy is used, then URLs other than http: can be accessed, 1919 * also, if we have trouble which is clearly specific to the proxy, then 1920 * we return DECLINED so that we can try another proxy. (Or the direct 1921 * route.) 1922 */ 1923static int proxy_http_handler(request_rec *r, proxy_worker *worker, 1924 proxy_server_conf *conf, 1925 char *url, const char *proxyname, 1926 apr_port_t proxyport) 1927{ 1928 int status; 1929 char server_portstr[32]; 1930 char *scheme; 1931 const char *proxy_function; 1932 const char *u; 1933 proxy_conn_rec *backend = NULL; 1934 int is_ssl = 0; 1935 conn_rec *c = r->connection; 1936 /* 1937 * Use a shorter-lived pool to reduce memory usage 1938 * and avoid a memory leak 1939 */ 1940 apr_pool_t *p = r->pool; 1941 apr_uri_t *uri = apr_palloc(p, sizeof(*uri)); 1942 1943 /* find the scheme */ 1944 u = strchr(url, ':'); 1945 if (u == NULL || u[1] != '/' || u[2] != '/' || u[3] == '\0') 1946 return DECLINED; 1947 if ((u - url) > 14) 1948 return HTTP_BAD_REQUEST; 1949 scheme = apr_pstrndup(p, url, u - url); 1950 /* scheme is lowercase */ 1951 ap_str_tolower(scheme); 1952 /* is it for us? */ 1953 if (strcmp(scheme, "https") == 0) { 1954 if (!ap_proxy_ssl_enable(NULL)) { 1955 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1956 "proxy: HTTPS: declining URL %s" 1957 " (mod_ssl not configured?)", url); 1958 return DECLINED; 1959 } 1960 is_ssl = 1; 1961 proxy_function = "HTTPS"; 1962 } 1963 else if (!(strcmp(scheme, "http") == 0 || (strcmp(scheme, "ftp") == 0 && proxyname))) { 1964 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1965 "proxy: HTTP: declining URL %s", url); 1966 return DECLINED; /* only interested in HTTP, or FTP via proxy */ 1967 } 1968 else { 1969 if (*scheme == 'h') 1970 proxy_function = "HTTP"; 1971 else 1972 proxy_function = "FTP"; 1973 } 1974 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, 1975 "proxy: HTTP: serving URL %s", url); 1976 1977 1978 /* create space for state information */ 1979 if ((status = ap_proxy_acquire_connection(proxy_function, &backend, 1980 worker, r->server)) != OK) 1981 goto cleanup; 1982 1983 1984 backend->is_ssl = is_ssl; 1985 if (is_ssl) { 1986 ap_proxy_ssl_connection_cleanup(backend, r); 1987 } 1988 1989 /* 1990 * In the case that we are handling a reverse proxy connection and this 1991 * is not a request that is coming over an already kept alive connection 1992 * with the client, do NOT reuse the connection to the backend, because 1993 * we cannot forward a failure to the client in this case as the client 1994 * does NOT expects this in this situation. 1995 * Yes, this creates a performance penalty. 1996 */ 1997 if ((r->proxyreq == PROXYREQ_REVERSE) && (!c->keepalives) 1998 && (apr_table_get(r->subprocess_env, "proxy-initial-not-pooled"))) { 1999 backend->close = 1; 2000 } 2001 2002 /* Step One: Determine Who To Connect To */ 2003 if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, 2004 uri, &url, proxyname, 2005 proxyport, server_portstr, 2006 sizeof(server_portstr))) != OK) 2007 goto cleanup; 2008 2009 /* Step Two: Make the Connection */ 2010 if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { 2011 status = HTTP_SERVICE_UNAVAILABLE; 2012 goto cleanup; 2013 } 2014 2015 /* Step Three: Create conn_rec */ 2016 if (!backend->connection) { 2017 if ((status = ap_proxy_connection_create(proxy_function, backend, 2018 c, r->server)) != OK) 2019 goto cleanup; 2020 /* 2021 * On SSL connections set a note on the connection what CN is 2022 * requested, such that mod_ssl can check if it is requested to do 2023 * so. 2024 */ 2025 if (is_ssl) { 2026 const char *ssl_hostname; 2027 2028 /* 2029 * In the case of ProxyPreserveHost on use the hostname of 2030 * the request if present otherwise use the one from the 2031 * backend request URI. 2032 */ 2033 if ((conf->preserve_host != 0) && (r->hostname != NULL)) { 2034 ssl_hostname = r->hostname; 2035 } 2036 else { 2037 ssl_hostname = uri->hostname; 2038 } 2039 2040 apr_table_set(backend->connection->notes, "proxy-request-hostname", 2041 ssl_hostname); 2042 } 2043 } 2044 2045 /* Step Four: Send the Request */ 2046 if ((status = ap_proxy_http_request(p, r, backend, backend->connection, 2047 conf, uri, url, server_portstr)) != OK) 2048 goto cleanup; 2049 2050 /* Step Five: Receive the Response */ 2051 if ((status = ap_proxy_http_process_response(p, r, backend, 2052 backend->connection, 2053 conf, server_portstr)) != OK) 2054 goto cleanup; 2055 2056 /* Step Six: Clean Up */ 2057 2058cleanup: 2059 if (backend) { 2060 if (status != OK) 2061 backend->close = 1; 2062 ap_proxy_http_cleanup(proxy_function, r, backend); 2063 } 2064 return status; 2065} 2066static apr_status_t warn_rx_free(void *p) 2067{ 2068 ap_pregfree((apr_pool_t*)p, warn_rx); 2069 return APR_SUCCESS; 2070} 2071static void ap_proxy_http_register_hook(apr_pool_t *p) 2072{ 2073 proxy_hook_scheme_handler(proxy_http_handler, NULL, NULL, APR_HOOK_FIRST); 2074 proxy_hook_canon_handler(proxy_http_canon, NULL, NULL, APR_HOOK_FIRST); 2075 warn_rx = ap_pregcomp(p, "[0-9]{3}[ \t]+[^ \t]+[ \t]+\"[^\"]*\"([ \t]+\"([^\"]+)\")?", 0); 2076 apr_pool_cleanup_register(p, p, warn_rx_free, apr_pool_cleanup_null); 2077} 2078 2079module AP_MODULE_DECLARE_DATA proxy_http_module = { 2080 STANDARD20_MODULE_STUFF, 2081 NULL, /* create per-directory config structure */ 2082 NULL, /* merge per-directory config structures */ 2083 NULL, /* create per-server config structure */ 2084 NULL, /* merge per-server config structures */ 2085 NULL, /* command apr_table_t */ 2086 ap_proxy_http_register_hook/* register hooks */ 2087}; 2088 2089