mod_proxy_http.c revision 3709b26f3370ae89c5324a3c03fab56a93b09ecd
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu/* Licensed to the Apache Software Foundation (ASF) under one or more
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * contributor license agreements. See the NOTICE file distributed with
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * this work for additional information regarding copyright ownership.
765f3b8c82bca96eeb44463da2305201b1a493daChristian Maeder * The ASF licenses this file to You under the Apache License, Version 2.0
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * (the "License"); you may not use this file except in compliance with
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * the License. You may obtain a copy of the License at
765f3b8c82bca96eeb44463da2305201b1a493daChristian Maeder * http://www.apache.org/licenses/LICENSE-2.0
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * Unless required by applicable law or agreed to in writing, software
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * distributed under the License is distributed on an "AS IS" BASIS,
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * See the License for the specific language governing permissions and
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * limitations under the License.
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder/* HTTP routines for Apache proxy */
17f1de180b775332d98ff24c7ce51d6866272dcdChristian Maedermodule AP_MODULE_DECLARE_DATA proxy_http_module;
17f1de180b775332d98ff24c7ce51d6866272dcdChristian Maederstatic apr_status_t ap_proxy_http_cleanup(const char *scheme,
53d2d31717e8c65bb3c2d1f2cd891d626cf45e5bChristian Maeder * Canonicalise http-like URLs.
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * scheme is the scheme for the URL
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * url is the URL starting with the first '/'
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * def_port is the default port for this scheme.
53d2d31717e8c65bb3c2d1f2cd891d626cf45e5bChristian Maederstatic int proxy_http_canon(request_rec *r, char *url)
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu const char *err;
de2d031e186086e2cb775bc59bacda87c9b18371Christian Maeder /* ap_port_of_scheme() */
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu else if (strncasecmp(url, "https:", 6) == 0) {
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu /* do syntatic check.
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu * We break the URL into host, port, path, search
3f5d611a1388ce3cd33f86da3f1e9b7ad68d087cMihaela Turcu err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
1070181294f9381ac4ac19eba1c3ecc40fc731a4Mihaela Turcu "error parsing URL %s: %s",
d20b265a2765e843986ceed6bf0055582981bf0fChristian Maeder * now parse path/search args, according to rfc1738:
7cfd47f6dc4147e9a3d21d72f68c6325552092f0Christian Maeder * process the path.
7cfd47f6dc4147e9a3d21d72f68c6325552092f0Christian Maeder * In a reverse proxy, our URL has been processed, so canonicalise
7cfd47f6dc4147e9a3d21d72f68c6325552092f0Christian Maeder * unless proxy-nocanon is set to say it's raw
17f1de180b775332d98ff24c7ce51d6866272dcdChristian Maeder * In a forward proxy, we have and MUST NOT MANGLE the original.
de2d031e186086e2cb775bc59bacda87c9b18371Christian Maeder default: /* wtf are we doing here? */
de2d031e186086e2cb775bc59bacda87c9b18371Christian Maeder if (apr_table_get(r->notes, "proxy-nocanon")) {
de2d031e186086e2cb775bc59bacda87c9b18371Christian Maeder path = ap_proxy_canonenc(r->pool, url, strlen(url),
a62775006ae39677af366c0f7b599924243cc65bChristian Maeder apr_snprintf(sport, sizeof(sport), ":%d", port);
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder if (ap_strchr_c(host, ':')) { /* if literal IPv6 address */
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder host = apr_pstrcat(r->pool, "[", host, "]", NULL);
53d2d31717e8c65bb3c2d1f2cd891d626cf45e5bChristian Maeder r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
53d2d31717e8c65bb3c2d1f2cd891d626cf45e5bChristian Maeder "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder/* Clear all connection-based headers from the incoming headers table */
d12f7a58b996457c25e12d674153346a4e21930eChristian Maedertypedef struct header_dptr {
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maederstatic int clean_warning_headers(void *data, const char *key, const char *val)
53d2d31717e8c65bb3c2d1f2cd891d626cf45e5bChristian Maeder apr_table_t *headers = ((header_dptr*)data)->table;
398f02e814574f163278b28b5c78cd213493f7ccChristian Maeder apr_pool_t *pool = ((header_dptr*)data)->pool;
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder ((header_dptr*)data)->table = headers = apr_table_make(pool, 2);
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * Parse this, suckers!
712ff727df7fe324064a1082a40d66a18a3df352Christian Maeder * Warning = "Warning" ":" 1#warning-value
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder * warning-value = warn-code SP warn-agent SP warn-text
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * [SP warn-date]
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * warn-code = 3DIGIT
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder * warn-agent = ( host [ ":" port ] ) | pseudonym
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder * ; the name or pseudonym of the server adding
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * ; the Warning header, for use in debugging
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder * warn-text = quoted-string
712ff727df7fe324064a1082a40d66a18a3df352Christian Maeder * warn-date = <"> HTTP-date <">
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * Buggrit, use a bloomin' regexp!
dc792317de0a95aac4e9a6dadfb78df050e5022eChristian Maeder * (\d{3}\s+\S+\s+\".*?\"(\s+\"(.*?)\")?) --> whole in $1, date in $3
16779ccfe622e9db869898f724bc0132b90cb7d7Christian Maeder while (!ap_regexec(warn_rx, val, nmatch, pmatch, 0)) {
16779ccfe622e9db869898f724bc0132b90cb7d7Christian Maeder warning = apr_pstrndup(pool, val+pmatch[0].rm_so,
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder /* OK, we have a date here */
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder date = apr_pstrndup(pool, val+pmatch[2].rm_so,
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder if (!warn_time || (warn_time == ((header_dptr*)data)->time)) {
d12f7a58b996457c25e12d674153346a4e21930eChristian Maederstatic apr_table_t *ap_proxy_clean_warnings(apr_pool_t *p, apr_table_t *headers)
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder x.time = apr_date_parse_http(apr_table_get(headers, "Date"));
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder apr_table_do(clean_warning_headers, &x, headers, "Warning", NULL);
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder return apr_table_overlay(p, headers, x.table);
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maederstatic int clear_conn_headers(void *data, const char *key, const char *val)
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder apr_table_t *headers = ((header_dptr*)data)->table;
3397210aac34a94e9ae85faacf7f6a02a808097eChristian Maeder apr_pool_t *pool = ((header_dptr*)data)->pool;
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder while (*next && !apr_isspace(*next) && (*next != ',')) {
a2cc771b106f5792a02348fd36475550b8731792Christian Maeder while (*next && (apr_isspace(*next) || (*next == ','))) {
16779ccfe622e9db869898f724bc0132b90cb7d7Christian Maederstatic void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
c55f9e48a7d93c41ebfe7a3216ed305165346e2fChristian Maeder apr_table_unset(headers, "Proxy-Connection");
16779ccfe622e9db869898f724bc0132b90cb7d7Christian Maeder apr_table_do(clear_conn_headers, &x, headers, "Connection", NULL);
c55f9e48a7d93c41ebfe7a3216ed305165346e2fChristian Maeder const char te_hdr[] = "Transfer-Encoding: chunked" CRLF;
c55f9e48a7d93c41ebfe7a3216ed305165346e2fChristian Maeder buf = apr_pmemdup(p, te_hdr, sizeof(te_hdr)-1);
c55f9e48a7d93c41ebfe7a3216ed305165346e2fChristian Maeder ap_xlate_proto_to_ascii(buf, sizeof(te_hdr)-1);
c55f9e48a7d93c41ebfe7a3216ed305165346e2fChristian Maeder e = apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, bucket_alloc);
d12f7a58b996457c25e12d674153346a4e21930eChristian Maeder APR_BRIGADE_INSERT_TAIL(header_brigade, e);
c5ddf41fe430a758733dbc46db25d5910c85ab8cChristian Maeder e = apr_bucket_pool_create(buf, strlen(buf), p, bucket_alloc);
c5ddf41fe430a758733dbc46db25d5910c85ab8cChristian Maeder APR_BRIGADE_INSERT_TAIL(header_brigade, e);
c5ddf41fe430a758733dbc46db25d5910c85ab8cChristian Maederstatic void terminate_headers(apr_bucket_alloc_t *bucket_alloc,
apr_bucket *e;
int flush)
if (flush) {
return HTTP_BAD_REQUEST;
return OK;
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,
const 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;
const char *temp_dir;
char *template;
return HTTP_INTERNAL_SERVER_ERROR;
"modproxy.tmp.XXXXXX",
APR_FILEPATH_NATIVE, p);
temp_dir);
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;
char *buf;
int counter;
if (r->expecting_100) {
return HTTP_EXPECTATION_FAILED;
force10 = 0;
if (!hostname) {
r->uri );
const char *buf;
c->remote_ip);
proxy_run_fixups(r);
if (r->main) {
NULL);
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));
c->remote_ip,
return rv;
return OK;
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
char *server_portstr) {
const char *buf;
char keepchar;
apr_bucket *e;
int pread_len = 0;
int backend_broke = 0;
static const char *hop_by_hop_hdrs[] =
if (len == 0) {
if (len <= 0) {
c->keepalives);
return OK;
else if (!c->keepalives) {
backasswards = 0;
&pread_len);
r->method);
return r->status;
r->headers_out,
for (i=0; hop_by_hop_hdrs[i]; ++i) {
interim_response = 0;
if (interim_response) {
r->status);
* ProxyPassReverse/etc from here to ap_proxy_read_headers
const char *buf;
if (backasswards) {
|| c->aborted) {
#if DEBUGGING
|| c->aborted) {
} while (!finish);
else if (!interim_response) {
|| c->aborted) {
apr_psprintf(p,
return DONE;
return OK;
return status;
return OK;
return OK;
int status;
char *scheme;
const char *proxy_function;
int is_ssl = 0;
return DECLINED;
return HTTP_BAD_REQUEST;
return DECLINED;
goto cleanup;
if (is_ssl) {
goto cleanup;
goto cleanup;
goto cleanup;
if (is_ssl) {
goto cleanup;
goto cleanup;
if (backend) {
return status;
return APR_SUCCESS;