mod_proxy_http.c revision a25139a3cea752311a32b30b9b406fee8b87042e
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* Licensed to the Apache Software Foundation (ASF) under one or more
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * contributor license agreements. See the NOTICE file distributed with
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * this work for additional information regarding copyright ownership.
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * The ASF licenses this file to You under the Apache License, Version 2.0
fd9abdda70912b99b24e3bf1a38f26fde908a74cnd * (the "License"); you may not use this file except in compliance with
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * the License. You may obtain a copy of the License at
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * Unless required by applicable law or agreed to in writing, software
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * distributed under the License is distributed on an "AS IS" BASIS,
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
2e545ce2450a9953665f701bb05350f0d3f26275nd * limitations under the License.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* HTTP routines for Apache proxy */
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic int (*ap_proxy_clear_connection_fn)(request_rec *r, apr_table_t *headers) =
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic apr_status_t ap_proxy_http_cleanup(const char *scheme,
f3ec420152ca921e4c1ce77782f51b53f659018dnd * Canonicalise http-like URLs.
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * scheme is the scheme for the URL
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * url is the URL starting with the first '/'
4b575a6b6704b516f22d65a3ad35696d7b9ba372rpluem * def_port is the default port for this scheme.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd const char *err;
a78048ccbdb6256da15e6b0e7e95355e480c2301nd const char *scheme;
a78048ccbdb6256da15e6b0e7e95355e480c2301nd /* ap_port_of_scheme() */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* do syntatic check.
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * We break the URL into host, port, path, search
a78048ccbdb6256da15e6b0e7e95355e480c2301nd err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
a78048ccbdb6256da15e6b0e7e95355e480c2301nd ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01083)
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * now parse path/search args, according to rfc1738:
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * process the path.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * In a reverse proxy, our URL has been processed, so canonicalise
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * unless proxy-nocanon is set to say it's raw
a78048ccbdb6256da15e6b0e7e95355e480c2301nd * In a forward proxy, we have and MUST NOT MANGLE the original.
a78048ccbdb6256da15e6b0e7e95355e480c2301nd switch (r->proxyreq) {
a78048ccbdb6256da15e6b0e7e95355e480c2301nd default: /* wtf are we doing here? */
a78048ccbdb6256da15e6b0e7e95355e480c2301nd if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
a78048ccbdb6256da15e6b0e7e95355e480c2301nd r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
a78048ccbdb6256da15e6b0e7e95355e480c2301nd "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
a78048ccbdb6256da15e6b0e7e95355e480c2301nd/* Clear all connection-based headers from the incoming headers table */
a78048ccbdb6256da15e6b0e7e95355e480c2301ndtypedef struct header_dptr {
a78048ccbdb6256da15e6b0e7e95355e480c2301ndstatic int clean_warning_headers(void *data, const char *key, const char *val)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar ((header_dptr*)data)->table = headers = apr_table_make(pool, 2);
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Parse this, suckers!
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Warning = "Warning" ":" 1#warning-value
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * warning-value = warn-code SP warn-agent SP warn-text
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * [SP warn-date]
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * warn-code = 3DIGIT
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * warn-agent = ( host [ ":" port ] ) | pseudonym
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * ; the name or pseudonym of the server adding
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * ; the Warning header, for use in debugging
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * warn-text = quoted-string
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * warn-date = <"> HTTP-date <">
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * Buggrit, use a bloomin' regexp!
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar * (\d{3}\s+\S+\s+\".*?\"(\s+\"(.*?)\")?) --> whole in $1, date in $3
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar /* OK, we have a date here */
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar if (!warn_time || (warn_time == ((header_dptr*)data)->time)) {
1f1b6bf13313fdd14a45e52e553d3ff28689b717coarstatic apr_table_t *ap_proxy_clean_warnings(apr_pool_t *p, apr_table_t *headers)
1f1b6bf13313fdd14a45e52e553d3ff28689b717coar x.time = apr_date_parse_http(apr_table_get(headers, "Date"));
a78048ccbdb6256da15e6b0e7e95355e480c2301nd apr_table_do(clean_warning_headers, &x, headers, "Warning", NULL);
0d0ba3a410038e179b695446bb149cce6264e0abnd e = apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, bucket_alloc);
0d0ba3a410038e179b695446bb149cce6264e0abnd const char *cl_val)
CRLF,
NULL);
apr_bucket *e;
request_rec *r,
apr_bucket *e;
if (header_brigade) {
return HTTP_INTERNAL_SERVER_ERROR;
return rv;
if (seen_eos) {
return HTTP_BAD_REQUEST;
if (header_brigade) {
return rv;
request_rec *r,
char *old_cl_val)
apr_bucket *e;
if (old_cl_val) {
char *endstr;
return HTTP_BAD_REQUEST;
return HTTP_INTERNAL_SERVER_ERROR;
if (header_brigade) {
return HTTP_INTERNAL_SERVER_ERROR;
return rv ;
if (seen_eos) {
return HTTP_BAD_REQUEST;
return HTTP_BAD_REQUEST;
if (header_brigade) {
return OK;
request_rec *r,
int force_cl)
int seen_eos = 0;
apr_bucket *e;
return HTTP_REQUEST_ENTITY_TOO_LARGE;
const char *temp_dir;
char *template;
return HTTP_INTERNAL_SERVER_ERROR;
"modproxy.tmp.XXXXXX",
APR_FILEPATH_NATIVE, p);
return HTTP_INTERNAL_SERVER_ERROR;
e = APR_BUCKET_NEXT(e)) {
const char *data;
const char *tmpfile_name;
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
if (seen_eos) {
return HTTP_BAD_REQUEST;
if (tmpfile) {
apr_bucket *e;
const char *data;
e = APR_BUCKET_NEXT(e)) {
if (!APR_BUCKET_IS_METADATA(e)) {
else if (APR_BUCKET_IS_FLUSH(e)) {
else if (APR_BUCKET_IS_EOS(e)) {
return rv;
apr_bucket *e;
char *buf;
if (r->expecting_100) {
return HTTP_EXPECTATION_FAILED;
force10 = 0;
return rv;
if (old_cl_val) {
if (old_te_val) {
goto skip_body;
return HTTP_INTERNAL_SERVER_ERROR;
* This helps us avoid any election of C-L v.s. T-E
return HTTP_BAD_REQUEST;
return HTTP_INTERNAL_SERVER_ERROR;
else if (old_te_val) {
if (force10
else if (old_cl_val) {
else if (!force10
if (!force10) {
switch(rb_method) {
case RB_STREAM_CHUNKED:
case RB_STREAM_CL:
case RB_SPOOL_CL:
|| (bytes_read > 0));
return rv;
return OK;
char* ndate;
if (!time) {
return date;
return date;
return ndate;
return rp;
static const char *date_hdrs[]
const char *name;
} transform_hdrs[] = {
for (i = 0; date_hdrs[i]; ++i) {
int len;
int saw_headers = 0;
*pread_len = 0;
if (saw_headers) {
++value;
end)
char *tmp_s = s;
*writen = n;
return rv;
#ifndef AP_MAX_INTERIM_RESPONSES
const char *buf;
char keepchar;
apr_bucket *e;
int pread_len = 0;
int backend_broke = 0;
static const char *hop_by_hop_hdrs[] =
int do_100_continue;
&& ap_request_has_body(r));
if (do_100_continue) {
if (len == 0) {
if (len <= 0) {
if (do_100_continue) {
return OK;
else if (!c->keepalives) {
backasswards = 0;
&pread_len);
return r->status;
r->headers_out,
for (i=0; hop_by_hop_hdrs[i]; ++i) {
if (do_100_continue
interim_response = 0;
if (interim_response) {
if (!policy
* ProxyPassReverse/etc from here to ap_proxy_read_headers
const char *buf;
if (backasswards) {
return proxy_status;
|| c->aborted) {
#if DEBUGGING
= APR_BUCKET_NEXT(e)) {
|| c->aborted) {
if (*backend_ptr) {
} while (!finish);
else if (!interim_response) {
apr_psprintf(p,
return DONE;
return OK;
return OK;
int status;
char *scheme;
const char *proxy_function;
int is_ssl = 0;
int retry = 0;
return DECLINED;
return HTTP_BAD_REQUEST;
url);
return DECLINED;
url);
goto cleanup;
if (is_ssl) {
if (is_ssl) {
const char *ssl_hostname;
* backend's socket/connection is reused (ie. no Step Three).
retry++;
retry++;
if (backend) {
return status;
return OK;
if (!ap_proxy_clear_connection_fn) {
if (!ap_proxy_clear_connection_fn) {
return !OK;
return OK;