00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "mod_proxy.h"
00020
00021 module AP_MODULE_DECLARE_DATA proxy_http_module;
00022
00023 int ap_proxy_http_canon(request_rec *r, char *url);
00024 int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
00025 char *url, const char *proxyname,
00026 apr_port_t proxyport);
00027
00028 typedef struct {
00029 const char *name;
00030 apr_port_t port;
00031 apr_sockaddr_t *addr;
00032 apr_socket_t *sock;
00033 int close;
00034 } proxy_http_conn_t;
00035
00036 static apr_status_t ap_proxy_http_cleanup(request_rec *r,
00037 proxy_http_conn_t *p_conn,
00038 proxy_conn_rec *backend);
00039
00040
00041
00042
00043
00044
00045
00046 int ap_proxy_http_canon(request_rec *r, char *url)
00047 {
00048 char *host, *path, *search, sport[7];
00049 const char *err;
00050 const char *scheme;
00051 apr_port_t port, def_port;
00052
00053
00054 if (strncasecmp(url, "http:", 5) == 0) {
00055 url += 5;
00056 scheme = "http";
00057 }
00058 else if (strncasecmp(url, "https:", 6) == 0) {
00059 url += 6;
00060 scheme = "https";
00061 }
00062 else {
00063 return DECLINED;
00064 }
00065 def_port = apr_uri_port_of_scheme(scheme);
00066
00067 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00068 "proxy: HTTP: canonicalising URL %s", url);
00069
00070
00071
00072
00073 port = def_port;
00074 err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
00075 if (err) {
00076 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00077 "error parsing URL %s: %s",
00078 url, err);
00079 return HTTP_BAD_REQUEST;
00080 }
00081
00082
00083
00084
00085
00086
00087 if (r->uri == r->unparsed_uri) {
00088 search = strchr(url, '?');
00089 if (search != NULL)
00090 *(search++) = '\0';
00091 }
00092 else
00093 search = r->args;
00094
00095
00096 path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
00097 if (path == NULL)
00098 return HTTP_BAD_REQUEST;
00099
00100 if (port != def_port)
00101 apr_snprintf(sport, sizeof(sport), ":%d", port);
00102 else
00103 sport[0] = '\0';
00104
00105 if (ap_strchr_c(host, ':')) {
00106 host = apr_pstrcat(r->pool, "[", host, "]", NULL);
00107 }
00108 r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
00109 "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
00110 return OK;
00111 }
00112
00113 static const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
00114 {
00115 struct proxy_alias *ent;
00116 int i, l1, l2;
00117 char *u;
00118
00119
00120
00121
00122 l1 = strlen(url);
00123 ent = (struct proxy_alias *)conf->raliases->elts;
00124 for (i = 0; i < conf->raliases->nelts; i++) {
00125 l2 = strlen(ent[i].real);
00126 if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) {
00127 u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
00128 return ap_construct_url(r->pool, u, r);
00129 }
00130 }
00131 return url;
00132 }
00133
00134
00135 static void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
00136 {
00137 const char *name;
00138 char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));
00139
00140 apr_table_unset(headers, "Proxy-Connection");
00141 if (!next)
00142 return;
00143
00144 while (*next) {
00145 name = next;
00146 while (*next && !apr_isspace(*next) && (*next != ',')) {
00147 ++next;
00148 }
00149 while (*next && (apr_isspace(*next) || (*next == ','))) {
00150 *next = '\0';
00151 ++next;
00152 }
00153 apr_table_unset(headers, name);
00154 }
00155 apr_table_unset(headers, "Connection");
00156 }
00157
00158 static
00159 apr_status_t ap_proxy_http_determine_connection(apr_pool_t *p, request_rec *r,
00160 proxy_http_conn_t *p_conn,
00161 conn_rec *c,
00162 proxy_server_conf *conf,
00163 apr_uri_t *uri,
00164 char **url,
00165 const char *proxyname,
00166 apr_port_t proxyport,
00167 char *server_portstr,
00168 int server_portstr_size) {
00169 int server_port;
00170 apr_status_t err;
00171 apr_sockaddr_t *uri_addr;
00172
00173
00174
00175
00176
00177 if (APR_SUCCESS != apr_uri_parse(p, *url, uri)) {
00178 return ap_proxyerror(r, HTTP_BAD_REQUEST,
00179 apr_pstrcat(p,"URI cannot be parsed: ", *url,
00180 NULL));
00181 }
00182 if (!uri->port) {
00183 uri->port = apr_uri_port_of_scheme(uri->scheme);
00184 }
00185
00186 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00187 "proxy: HTTP connecting %s to %s:%d", *url, uri->hostname,
00188 uri->port);
00189
00190
00191
00192 err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri->hostname),
00193 APR_UNSPEC, uri->port, 0, c->pool);
00194
00195
00196
00197
00198
00199 if (proxyname) {
00200 p_conn->name = apr_pstrdup(c->pool, proxyname);
00201 p_conn->port = proxyport;
00202
00203 err = apr_sockaddr_info_get(&p_conn->addr, p_conn->name, APR_UNSPEC,
00204 p_conn->port, 0, c->pool);
00205 } else {
00206 p_conn->name = apr_pstrdup(c->pool, uri->hostname);
00207 p_conn->port = uri->port;
00208 p_conn->addr = uri_addr;
00209 *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
00210 uri->query ? uri->query : "",
00211 uri->fragment ? "#" : "",
00212 uri->fragment ? uri->fragment : "", NULL);
00213 }
00214
00215 if (err != APR_SUCCESS) {
00216 return ap_proxyerror(r, HTTP_BAD_GATEWAY,
00217 apr_pstrcat(p, "DNS lookup failure for: ",
00218 p_conn->name, NULL));
00219 }
00220
00221
00222 {
00223 server_port = ap_get_server_port(r);
00224 if (ap_is_default_port(server_port, r)) {
00225 strcpy(server_portstr,"");
00226 } else {
00227 apr_snprintf(server_portstr, server_portstr_size, ":%d",
00228 server_port);
00229 }
00230 }
00231
00232
00233 if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
00234 return ap_proxyerror(r, HTTP_FORBIDDEN,
00235 "Connect to remote machine blocked");
00236 }
00237 return OK;
00238 }
00239
00240 static
00241 apr_status_t ap_proxy_http_create_connection(apr_pool_t *p, request_rec *r,
00242 proxy_http_conn_t *p_conn,
00243 conn_rec *c, conn_rec **origin,
00244 proxy_conn_rec *backend,
00245 proxy_server_conf *conf,
00246 const char *proxyname) {
00247 int failed=0, new=0;
00248 apr_socket_t *client_socket = NULL;
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 if (backend->connection) {
00263 client_socket = ap_get_module_config(backend->connection->conn_config, &core_module);
00264 if ((backend->connection->id == c->id) &&
00265 (backend->port == p_conn->port) &&
00266 (backend->hostname) &&
00267 (!apr_strnatcasecmp(backend->hostname, p_conn->name))) {
00268 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00269 "proxy: keepalive address match (keep original socket)");
00270 } else {
00271 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00272 "proxy: keepalive address mismatch / connection has"
00273 " changed (close old socket (%s/%s, %d/%d))",
00274 p_conn->name, backend->hostname, p_conn->port,
00275 backend->port);
00276 apr_socket_close(client_socket);
00277 backend->connection = NULL;
00278 }
00279 }
00280
00281
00282 new = 1;
00283 if ((backend->connection) && (backend->connection->id == c->id)) {
00284 apr_size_t buffer_len = 1;
00285 char test_buffer[1];
00286 apr_status_t socket_status;
00287 apr_interval_time_t current_timeout;
00288
00289
00290 *origin = backend->connection;
00291 p_conn->sock = client_socket;
00292 new = 0;
00293
00294
00295 apr_socket_timeout_get(p_conn->sock, ¤t_timeout);
00296
00297 apr_socket_timeout_set(p_conn->sock, 0);
00298 socket_status = apr_recv(p_conn->sock, test_buffer, &buffer_len);
00299
00300 apr_socket_timeout_set(p_conn->sock, current_timeout);
00301 if ( APR_STATUS_IS_EOF(socket_status) ) {
00302 ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL,
00303 "proxy: previous connection is closed, creating a new connection.");
00304 new = 1;
00305 }
00306 }
00307 if (new) {
00308 int rc;
00309
00310
00311 backend->connection = NULL;
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 failed = ap_proxy_connect_to_backend(&p_conn->sock, "HTTP",
00324 p_conn->addr, p_conn->name,
00325 conf, r->server, c->pool);
00326
00327
00328 if (failed) {
00329 if (proxyname) {
00330 return DECLINED;
00331 } else {
00332 return HTTP_BAD_GATEWAY;
00333 }
00334 }
00335
00336 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00337 "proxy: socket is connected");
00338
00339
00340 *origin = ap_run_create_connection(c->pool, r->server, p_conn->sock,
00341 r->connection->id,
00342 r->connection->sbh, c->bucket_alloc);
00343 if (!*origin) {
00344
00345
00346
00347 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
00348 r->server, "proxy: an error occurred creating a "
00349 "new connection to %pI (%s)", p_conn->addr,
00350 p_conn->name);
00351 apr_socket_close(p_conn->sock);
00352 return HTTP_INTERNAL_SERVER_ERROR;
00353 }
00354 backend->connection = *origin;
00355 backend->hostname = apr_pstrdup(c->pool, p_conn->name);
00356 backend->port = p_conn->port;
00357
00358 if (backend->is_ssl) {
00359 if (!ap_proxy_ssl_enable(backend->connection)) {
00360 ap_log_error(APLOG_MARK, APLOG_ERR, 0,
00361 r->server, "proxy: failed to enable ssl support "
00362 "for %pI (%s)", p_conn->addr, p_conn->name);
00363 return HTTP_INTERNAL_SERVER_ERROR;
00364 }
00365 }
00366 else {
00367 ap_proxy_ssl_disable(backend->connection);
00368 }
00369
00370 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00371 "proxy: connection complete to %pI (%s)",
00372 p_conn->addr, p_conn->name);
00373
00374
00375 rc = ap_run_pre_connection(*origin, p_conn->sock);
00376 if (rc != OK && rc != DONE) {
00377 (*origin)->aborted = 1;
00378 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00379 "proxy: HTTP: pre_connection setup failed (%d)",
00380 rc);
00381 return rc;
00382 }
00383 }
00384 return OK;
00385 }
00386
00387 static
00388 apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
00389 proxy_http_conn_t *p_conn, conn_rec *origin,
00390 proxy_server_conf *conf,
00391 apr_uri_t *uri,
00392 char *url, apr_bucket_brigade *bb,
00393 char *server_portstr) {
00394 conn_rec *c = r->connection;
00395 char *buf;
00396 apr_bucket *e;
00397 const apr_array_header_t *headers_in_array;
00398 const apr_table_entry_t *headers_in;
00399 int counter, seen_eos;
00400 apr_status_t status;
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_in,
00413 "Connection"), "close");
00414
00415 if (r->main) {
00416 p_conn->close++;
00417 }
00418
00419 ap_proxy_clear_connection(p, r->headers_in);
00420 if (p_conn->close) {
00421 apr_table_setn(r->headers_in, "Connection", "close");
00422 origin->keepalive = AP_CONN_CLOSE;
00423 }
00424
00425 if ( apr_table_get(r->subprocess_env,"force-proxy-request-1.0")) {
00426 buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
00427 } else {
00428 buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
00429 }
00430 if ( apr_table_get(r->subprocess_env,"proxy-nokeepalive")) {
00431 apr_table_unset(r->headers_in, "Connection");
00432 origin->keepalive = AP_CONN_CLOSE;
00433 }
00434 ap_xlate_proto_to_ascii(buf, strlen(buf));
00435 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
00436 APR_BRIGADE_INSERT_TAIL(bb, e);
00437 if ( conf->preserve_host == 0 ) {
00438 if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
00439 buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str, CRLF,
00440 NULL);
00441 } else {
00442 buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
00443 }
00444 }
00445 else {
00446
00447
00448
00449 const char* hostname = apr_table_get(r->headers_in,"Host");
00450 if (!hostname) {
00451 hostname = r->server->server_hostname;
00452 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
00453 "proxy: no HTTP 0.9 request (with no host line) "
00454 "on incoming request and preserve host set "
00455 "forcing hostname to be %s for uri %s",
00456 hostname,
00457 r->uri );
00458 }
00459 buf = apr_pstrcat(p, "Host: ", hostname, CRLF, NULL);
00460 }
00461 ap_xlate_proto_to_ascii(buf, strlen(buf));
00462 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
00463 APR_BRIGADE_INSERT_TAIL(bb, e);
00464
00465
00466 if (conf->viaopt == via_block) {
00467
00468 apr_table_unset(r->headers_in, "Via");
00469 } else if (conf->viaopt != via_off) {
00470
00471
00472 apr_table_mergen(r->headers_in, "Via",
00473 (conf->viaopt == via_full)
00474 ? apr_psprintf(p, "%d.%d %s%s (%s)",
00475 HTTP_VERSION_MAJOR(r->proto_num),
00476 HTTP_VERSION_MINOR(r->proto_num),
00477 ap_get_server_name(r), server_portstr,
00478 AP_SERVER_BASEVERSION)
00479 : apr_psprintf(p, "%d.%d %s%s",
00480 HTTP_VERSION_MAJOR(r->proto_num),
00481 HTTP_VERSION_MINOR(r->proto_num),
00482 ap_get_server_name(r), server_portstr)
00483 );
00484 }
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 if (PROXYREQ_REVERSE == r->proxyreq) {
00508 const char *buf;
00509
00510
00511
00512
00513 apr_table_mergen(r->headers_in, "X-Forwarded-For",
00514 r->connection->remote_ip);
00515
00516
00517
00518
00519 if ((buf = apr_table_get(r->headers_in, "Host"))) {
00520 apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf);
00521 }
00522
00523
00524
00525
00526
00527 apr_table_mergen(r->headers_in, "X-Forwarded-Server",
00528 r->server->server_hostname);
00529 }
00530
00531
00532 proxy_run_fixups(r);
00533 headers_in_array = apr_table_elts(r->headers_in);
00534 headers_in = (const apr_table_entry_t *) headers_in_array->elts;
00535 for (counter = 0; counter < headers_in_array->nelts; counter++) {
00536 if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
00537
00538
00539
00540
00541
00542 || !apr_strnatcasecmp(headers_in[counter].key, "Host")
00543
00544 || !apr_strnatcasecmp(headers_in[counter].key, "Keep-Alive")
00545 || !apr_strnatcasecmp(headers_in[counter].key, "TE")
00546 || !apr_strnatcasecmp(headers_in[counter].key, "Trailer")
00547 || !apr_strnatcasecmp(headers_in[counter].key, "Transfer-Encoding")
00548 || !apr_strnatcasecmp(headers_in[counter].key, "Upgrade")
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559 || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authorization")
00560 || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authenticate")) {
00561 continue;
00562 }
00563
00564 if (r->main) {
00565 if (headers_in[counter].key == NULL || headers_in[counter].val == NULL
00566 || !apr_strnatcasecmp(headers_in[counter].key, "If-Match")
00567 || !apr_strnatcasecmp(headers_in[counter].key, "If-Modified-Since")
00568 || !apr_strnatcasecmp(headers_in[counter].key, "If-Range")
00569 || !apr_strnatcasecmp(headers_in[counter].key, "If-Unmodified-Since")
00570 || !apr_strnatcasecmp(headers_in[counter].key, "If-None-Match")) {
00571 continue;
00572 }
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 if ((r->method_number == M_GET) && headers_in[counter].key &&
00587 !apr_strnatcasecmp(headers_in[counter].key,
00588 "Content-Length")) {
00589 continue;
00590 }
00591 }
00592
00593
00594 buf = apr_pstrcat(p, headers_in[counter].key, ": ",
00595 headers_in[counter].val, CRLF,
00596 NULL);
00597 ap_xlate_proto_to_ascii(buf, strlen(buf));
00598 e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
00599 APR_BRIGADE_INSERT_TAIL(bb, e);
00600 }
00601
00602
00603 #if APR_CHARSET_EBCDIC
00604 e = apr_bucket_immortal_create("\015\012", 2, c->bucket_alloc);
00605 #else
00606 e = apr_bucket_immortal_create(CRLF, sizeof(CRLF)-1, c->bucket_alloc);
00607 #endif
00608 APR_BRIGADE_INSERT_TAIL(bb, e);
00609 e = apr_bucket_flush_create(c->bucket_alloc);
00610 APR_BRIGADE_INSERT_TAIL(bb, e);
00611
00612 status = ap_pass_brigade(origin->output_filters, bb);
00613
00614 if (status != APR_SUCCESS) {
00615 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
00616 "proxy: request failed to %pI (%s)",
00617 p_conn->addr, p_conn->name);
00618 return status;
00619 }
00620
00621
00622 seen_eos = 0;
00623 do {
00624 status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES,
00625 APR_BLOCK_READ, HUGE_STRING_LEN);
00626
00627 if (status != APR_SUCCESS) {
00628 return status;
00629 }
00630
00631
00632 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
00633
00634
00635
00636 if (APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(bb))) {
00637 break;
00638 }
00639
00640
00641 e = APR_BRIGADE_LAST(bb);
00642 apr_bucket_delete(e);
00643 seen_eos = 1;
00644 }
00645
00646 e = apr_bucket_flush_create(c->bucket_alloc);
00647 APR_BRIGADE_INSERT_TAIL(bb, e);
00648
00649 status = ap_pass_brigade(origin->output_filters, bb);
00650 if (status != APR_SUCCESS) {
00651 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
00652 "proxy: pass request data failed to %pI (%s)",
00653 p_conn->addr, p_conn->name);
00654 return status;
00655 }
00656 apr_brigade_cleanup(bb);
00657 } while (!seen_eos);
00658
00659 return APR_SUCCESS;
00660 }
00661
00662 static
00663 apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
00664 proxy_http_conn_t *p_conn,
00665 conn_rec *origin,
00666 proxy_conn_rec *backend,
00667 proxy_server_conf *conf,
00668 apr_bucket_brigade *bb,
00669 char *server_portstr) {
00670 conn_rec *c = r->connection;
00671 char buffer[HUGE_STRING_LEN];
00672 char keepchar;
00673 request_rec *rp;
00674 apr_bucket *e;
00675 int len, backasswards;
00676 int received_continue = 1;
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686 rp = ap_proxy_make_fake_req(origin, r);
00687
00688
00689
00690 rp->proxyreq = PROXYREQ_RESPONSE;
00691
00692 while (received_continue) {
00693 apr_brigade_cleanup(bb);
00694
00695 len = ap_getline(buffer, sizeof(buffer), rp, 0);
00696 if (len == 0) {
00697
00698 len = ap_getline(buffer, sizeof(buffer), rp, 0);
00699 }
00700 if (len <= 0) {
00701 apr_socket_close(p_conn->sock);
00702 backend->connection = NULL;
00703 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00704 "proxy: error reading status line from remote "
00705 "server %s", p_conn->name);
00706 return ap_proxyerror(r, HTTP_BAD_GATEWAY,
00707 "Error reading from remote server");
00708 }
00709
00710
00711
00712
00713 if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
00714 int major, minor;
00715
00716 if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
00717 major = 1;
00718 minor = 1;
00719 }
00720
00721
00722
00723 else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1)) {
00724 apr_socket_close(p_conn->sock);
00725 backend->connection = NULL;
00726 return ap_proxyerror(r, HTTP_BAD_GATEWAY,
00727 apr_pstrcat(p, "Corrupt status line returned by remote "
00728 "server: ", buffer, NULL));
00729 }
00730 backasswards = 0;
00731
00732 keepchar = buffer[12];
00733 buffer[12] = '\0';
00734 r->status = atoi(&buffer[9]);
00735
00736 if (keepchar != '\0') {
00737 buffer[12] = keepchar;
00738 } else {
00739
00740
00741
00742 buffer[12] = ' ';
00743 buffer[13] = '\0';
00744 }
00745 r->status_line = apr_pstrdup(p, &buffer[9]);
00746
00747
00748
00749
00750
00751
00752 r->headers_out = ap_proxy_read_headers(r, rp, buffer,
00753 sizeof(buffer), origin);
00754 if (r->headers_out == NULL) {
00755 ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
00756 r->server, "proxy: bad HTTP/%d.%d header "
00757 "returned by %s (%s)", major, minor, r->uri,
00758 r->method);
00759 p_conn->close += 1;
00760
00761
00762
00763
00764
00765 r->headers_out = apr_table_make(r->pool,1);
00766 r->status = HTTP_BAD_GATEWAY;
00767 r->status_line = "bad gateway";
00768 return r->status;
00769
00770 } else {
00771
00772 const char *buf;
00773 p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out,
00774 "Connection"),
00775 "close");
00776 ap_proxy_clear_connection(p, r->headers_out);
00777 if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
00778 ap_set_content_type(r, apr_pstrdup(p, buf));
00779 }
00780 ap_proxy_pre_http_request(origin,rp);
00781 }
00782
00783
00784 if (conf->viaopt != via_off && conf->viaopt != via_block) {
00785
00786 apr_table_mergen(r->headers_out, "Via",
00787 (conf->viaopt == via_full)
00788 ? apr_psprintf(p, "%d.%d %s%s (%s)",
00789 HTTP_VERSION_MAJOR(r->proto_num),
00790 HTTP_VERSION_MINOR(r->proto_num),
00791 ap_get_server_name(r),
00792 server_portstr,
00793 AP_SERVER_BASEVERSION)
00794 : apr_psprintf(p, "%d.%d %s%s",
00795 HTTP_VERSION_MAJOR(r->proto_num),
00796 HTTP_VERSION_MINOR(r->proto_num),
00797 ap_get_server_name(r),
00798 server_portstr)
00799 );
00800 }
00801
00802
00803 if ((major < 1) || (minor < 1)) {
00804 p_conn->close += 1;
00805 origin->keepalive = AP_CONN_CLOSE;
00806 }
00807 } else {
00808
00809 backasswards = 1;
00810 r->status = 200;
00811 r->status_line = "200 OK";
00812 p_conn->close += 1;
00813 }
00814
00815 if ( r->status != HTTP_CONTINUE ) {
00816 received_continue = 0;
00817 } else {
00818 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
00819 "proxy: HTTP: received 100 CONTINUE");
00820 }
00821
00822
00823 {
00824 const char *buf;
00825 if ((buf = apr_table_get(r->headers_out, "Date")) != NULL) {
00826 apr_table_set(r->headers_out, "Date",
00827 ap_proxy_date_canon(p, buf));
00828 }
00829 if ((buf = apr_table_get(r->headers_out, "Expires")) != NULL) {
00830 apr_table_set(r->headers_out, "Expires",
00831 ap_proxy_date_canon(p, buf));
00832 }
00833 if ((buf = apr_table_get(r->headers_out, "Last-Modified")) != NULL) {
00834 apr_table_set(r->headers_out, "Last-Modified",
00835 ap_proxy_date_canon(p, buf));
00836 }
00837 }
00838
00839
00840
00841
00842 {
00843 const char *buf;
00844 if ((buf = apr_table_get(r->headers_out, "Location")) != NULL) {
00845 apr_table_set(r->headers_out, "Location",
00846 ap_proxy_location_reverse_map(r, conf, buf));
00847 }
00848 if ((buf = apr_table_get(r->headers_out, "Content-Location")) != NULL) {
00849 apr_table_set(r->headers_out, "Content-Location",
00850 ap_proxy_location_reverse_map(r, conf, buf));
00851 }
00852 if ((buf = apr_table_get(r->headers_out, "URI")) != NULL) {
00853 apr_table_set(r->headers_out, "URI",
00854 ap_proxy_location_reverse_map(r, conf, buf));
00855 }
00856 }
00857
00858 if ((r->status == 401) && (conf->error_override != 0)) {
00859 const char *buf;
00860 const char *wa = "WWW-Authenticate";
00861 if ((buf = apr_table_get(r->headers_out, wa))) {
00862 apr_table_set(r->err_headers_out, wa, buf);
00863 } else {
00864 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00865 "proxy: origin server sent 401 without WWW-Authenticate header");
00866 }
00867 }
00868
00869 r->sent_bodyct = 1;
00870
00871 if (backasswards) {
00872 apr_ssize_t cntr = len;
00873 e = apr_bucket_heap_create(buffer, cntr, NULL, c->bucket_alloc);
00874 APR_BRIGADE_INSERT_TAIL(bb, e);
00875 }
00876
00877
00878 if ((!r->header_only) &&
00879 (r->status > 199) &&
00880 (r->status != HTTP_NO_CONTENT) &&
00881 (r->status != HTTP_RESET_CONTENT) &&
00882 (r->status != HTTP_NOT_MODIFIED)) {
00883
00884
00885
00886
00887
00888
00889 rp->headers_in = apr_table_copy(r->pool, r->headers_out);
00890
00891 apr_table_unset(r->headers_out,"Transfer-Encoding");
00892
00893 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00894 "proxy: start body send");
00895
00896
00897
00898
00899
00900 if ( (conf->error_override ==0) || r->status < 400 ) {
00901
00902
00903 int finish = FALSE;
00904 while (ap_get_brigade(rp->input_filters,
00905 bb,
00906 AP_MODE_READBYTES,
00907 APR_BLOCK_READ,
00908 conf->io_buffer_size) == APR_SUCCESS) {
00909 #if DEBUGGING
00910 {
00911 apr_off_t readbytes;
00912 apr_brigade_length(bb, 0, &readbytes);
00913 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
00914 r->server, "proxy (PID %d): readbytes: %#x",
00915 getpid(), readbytes);
00916 }
00917 #endif
00918
00919 if (APR_BRIGADE_EMPTY(bb)) {
00920 apr_brigade_cleanup(bb);
00921 break;
00922 }
00923
00924
00925 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
00926
00927
00928
00929
00930
00931 ap_proxy_http_cleanup(r, p_conn, backend);
00932
00933 finish = TRUE;
00934 }
00935
00936
00937 if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS
00938 || c->aborted) {
00939
00940 p_conn->close = 1;
00941 finish = TRUE;
00942 }
00943
00944
00945 apr_brigade_cleanup(bb);
00946
00947
00948 if (TRUE == finish) {
00949 break;
00950 }
00951 }
00952 }
00953 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00954 "proxy: end body send");
00955 } else {
00956 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
00957 "proxy: header only");
00958 }
00959 }
00960
00961 if ( conf->error_override ) {
00962
00963 if ( r->status == HTTP_OK )
00964 return OK;
00965 else {
00966
00967
00968
00969
00970 int status = r->status;
00971 r->status = HTTP_OK;
00972
00973 if ((status > 199) &&
00974 (status != HTTP_NO_CONTENT) &&
00975 (status != HTTP_RESET_CONTENT) &&
00976 (status != HTTP_NOT_MODIFIED)) {
00977 ap_discard_request_body(rp);
00978 }
00979 return status;
00980 }
00981 } else
00982 return OK;
00983 }
00984
00985 static
00986 apr_status_t ap_proxy_http_cleanup(request_rec *r, proxy_http_conn_t *p_conn,
00987 proxy_conn_rec *backend) {
00988
00989
00990
00991
00992
00993
00994
00995 if (p_conn->close || (r->proto_num < HTTP_VERSION(1,1))) {
00996 if (p_conn->sock) {
00997 apr_socket_close(p_conn->sock);
00998 p_conn->sock = NULL;
00999 backend->connection = NULL;
01000 }
01001 }
01002 return OK;
01003 }
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
01015 char *url, const char *proxyname,
01016 apr_port_t proxyport)
01017 {
01018 int status;
01019 char server_portstr[32];
01020 conn_rec *origin = NULL;
01021 proxy_conn_rec *backend = NULL;
01022 int is_ssl = 0;
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 apr_pool_t *p = r->connection->pool;
01038 conn_rec *c = r->connection;
01039 apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc);
01040 apr_uri_t *uri = apr_palloc(r->connection->pool, sizeof(*uri));
01041 proxy_http_conn_t *p_conn = apr_pcalloc(r->connection->pool,
01042 sizeof(*p_conn));
01043
01044
01045 if (strncasecmp(url, "https:", 6) == 0) {
01046 if (!ap_proxy_ssl_enable(NULL)) {
01047 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
01048 "proxy: HTTPS: declining URL %s"
01049 " (mod_ssl not configured?)", url);
01050 return DECLINED;
01051 }
01052 is_ssl = 1;
01053 }
01054 else if (!(strncasecmp(url, "http:", 5)==0 || (strncasecmp(url, "ftp:", 4)==0 && proxyname))) {
01055 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
01056 "proxy: HTTP: declining URL %s", url);
01057 return DECLINED;
01058 }
01059 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
01060 "proxy: HTTP: serving URL %s", url);
01061
01062
01063
01064
01065
01066 if (!r->main) {
01067 backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
01068 &proxy_http_module);
01069 }
01070
01071 if (!backend) {
01072 backend = apr_pcalloc(c->pool, sizeof(proxy_conn_rec));
01073 backend->connection = NULL;
01074 backend->hostname = NULL;
01075 backend->port = 0;
01076 if (!r->main) {
01077 ap_set_module_config(c->conn_config, &proxy_http_module, backend);
01078 }
01079 }
01080
01081 backend->is_ssl = is_ssl;
01082
01083
01084 status = ap_proxy_http_determine_connection(p, r, p_conn, c, conf, uri,
01085 &url, proxyname, proxyport,
01086 server_portstr,
01087 sizeof(server_portstr));
01088 if ( status != OK ) {
01089 return status;
01090 }
01091
01092
01093 status = ap_proxy_http_create_connection(p, r, p_conn, c, &origin, backend,
01094 conf, proxyname);
01095 if ( status != OK ) {
01096 return status;
01097 }
01098
01099
01100 status = ap_proxy_http_request(p, r, p_conn, origin, conf, uri, url, bb,
01101 server_portstr);
01102 if ( status != OK ) {
01103 return status;
01104 }
01105
01106
01107 status = ap_proxy_http_process_response(p, r, p_conn, origin, backend, conf,
01108 bb, server_portstr);
01109 if ( status != OK ) {
01110
01111 ap_proxy_http_cleanup(r, p_conn, backend);
01112 return status;
01113 }
01114
01115
01116 status = ap_proxy_http_cleanup(r, p_conn, backend);
01117 if ( status != OK ) {
01118 return status;
01119 }
01120
01121 return OK;
01122 }
01123
01124 static void ap_proxy_http_register_hook(apr_pool_t *p)
01125 {
01126 proxy_hook_scheme_handler(ap_proxy_http_handler, NULL, NULL, APR_HOOK_FIRST);
01127 proxy_hook_canon_handler(ap_proxy_http_canon, NULL, NULL, APR_HOOK_FIRST);
01128 }
01129
01130 module AP_MODULE_DECLARE_DATA proxy_http_module = {
01131 STANDARD20_MODULE_STUFF,
01132 NULL,
01133 NULL,
01134 NULL,
01135 NULL,
01136 NULL,
01137 ap_proxy_http_register_hook
01138 };
01139