proxy_http.c revision 10306ac2c175f420e6989568f4c8535a5dbc1349
e609c337f729875bc20e01096c7e610f45356f54nilgun/* ====================================================================
e609c337f729875bc20e01096c7e610f45356f54nilgun * The Apache Software License, Version 1.1
e609c337f729875bc20e01096c7e610f45356f54nilgun * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
e609c337f729875bc20e01096c7e610f45356f54nilgun * reserved.
e609c337f729875bc20e01096c7e610f45356f54nilgun * Redistribution and use in source and binary forms, with or without
96ad5d81ee4a2cc66a4ae19893efc8aa6d06fae7jailletc * modification, are permitted provided that the following conditions
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 1. Redistributions of source code must retain the above copyright
2e545ce2450a9953665f701bb05350f0d3f26275nd * notice, this list of conditions and the following disclaimer.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 2. Redistributions in binary form must reproduce the above copyright
e609c337f729875bc20e01096c7e610f45356f54nilgun * notice, this list of conditions and the following disclaimer in
e609c337f729875bc20e01096c7e610f45356f54nilgun * the documentation and/or other materials provided with the
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * distribution.
e609c337f729875bc20e01096c7e610f45356f54nilgun * 3. The end-user documentation included with the redistribution,
e609c337f729875bc20e01096c7e610f45356f54nilgun * if any, must include the following acknowledgment:
e609c337f729875bc20e01096c7e610f45356f54nilgun * "This product includes software developed by the
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Apache Software Foundation (http://www.apache.org/)."
e609c337f729875bc20e01096c7e610f45356f54nilgun * Alternately, this acknowledgment may appear in the software itself,
e609c337f729875bc20e01096c7e610f45356f54nilgun * if and wherever such third-party acknowledgments normally appear.
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung * 4. The names "Apache" and "Apache Software Foundation" must
e609c337f729875bc20e01096c7e610f45356f54nilgun * not be used to endorse or promote products derived from this
e8897b2f72c5fc3bf4a5da96745a320a8b2acae7rbowen * software without prior written permission. For written
e609c337f729875bc20e01096c7e610f45356f54nilgun * permission, please contact apache@apache.org.
e609c337f729875bc20e01096c7e610f45356f54nilgun * 5. Products derived from this software may not be called "Apache",
e609c337f729875bc20e01096c7e610f45356f54nilgun * nor may "Apache" appear in their name, without prior written
e609c337f729875bc20e01096c7e610f45356f54nilgun * permission of the Apache Software Foundation.
e609c337f729875bc20e01096c7e610f45356f54nilgun * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
e609c337f729875bc20e01096c7e610f45356f54nilgun * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
e609c337f729875bc20e01096c7e610f45356f54nilgun * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
e609c337f729875bc20e01096c7e610f45356f54nilgun * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
e609c337f729875bc20e01096c7e610f45356f54nilgun * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
e609c337f729875bc20e01096c7e610f45356f54nilgun * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
e609c337f729875bc20e01096c7e610f45356f54nilgun * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
e609c337f729875bc20e01096c7e610f45356f54nilgun * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
e609c337f729875bc20e01096c7e610f45356f54nilgun * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
e609c337f729875bc20e01096c7e610f45356f54nilgun * SUCH DAMAGE.
e609c337f729875bc20e01096c7e610f45356f54nilgun * ====================================================================
e609c337f729875bc20e01096c7e610f45356f54nilgun * This software consists of voluntary contributions made by many
e609c337f729875bc20e01096c7e610f45356f54nilgun * individuals on behalf of the Apache Software Foundation. For more
e609c337f729875bc20e01096c7e610f45356f54nilgun * information on the Apache Software Foundation, please see
e609c337f729875bc20e01096c7e610f45356f54nilgun * Portions of this software are based upon public domain software
e609c337f729875bc20e01096c7e610f45356f54nilgun * originally written at the National Center for Supercomputing Applications,
e609c337f729875bc20e01096c7e610f45356f54nilgun * University of Illinois, Urbana-Champaign.
e609c337f729875bc20e01096c7e610f45356f54nilgun/* HTTP routines for Apache proxy */
e609c337f729875bc20e01096c7e610f45356f54nilgunint ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
e609c337f729875bc20e01096c7e610f45356f54nilguntypedef struct {
e609c337f729875bc20e01096c7e610f45356f54nilgun const char *name;
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgunstatic apr_status_t ap_proxy_http_cleanup(request_rec *r,
e609c337f729875bc20e01096c7e610f45356f54nilgun * Canonicalise http-like URLs.
e609c337f729875bc20e01096c7e610f45356f54nilgun * scheme is the scheme for the URL
e609c337f729875bc20e01096c7e610f45356f54nilgun * url is the URL starting with the first '/'
e609c337f729875bc20e01096c7e610f45356f54nilgun * def_port is the default port for this scheme.
e609c337f729875bc20e01096c7e610f45356f54nilgun const char *err;
e609c337f729875bc20e01096c7e610f45356f54nilgun const char *scheme;
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* ap_default_port_for_scheme() */
e609c337f729875bc20e01096c7e610f45356f54nilgun ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
e609c337f729875bc20e01096c7e610f45356f54nilgun /* do syntatic check.
e609c337f729875bc20e01096c7e610f45356f54nilgun * We break the URL into host, port, path, search
e609c337f729875bc20e01096c7e610f45356f54nilgun err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
e609c337f729875bc20e01096c7e610f45356f54nilgun /* now parse path/search args, according to rfc1738 */
e609c337f729875bc20e01096c7e610f45356f54nilgun /* N.B. if this isn't a true proxy request, then the URL _path_
e609c337f729875bc20e01096c7e610f45356f54nilgun * has already been decoded. True proxy requests have r->uri
e609c337f729875bc20e01096c7e610f45356f54nilgun * == r->unparsed_uri, and no others have that property.
e609c337f729875bc20e01096c7e610f45356f54nilgun /* process path */
e609c337f729875bc20e01096c7e610f45356f54nilgun path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
e609c337f729875bc20e01096c7e610f45356f54nilgun r->filename = apr_pstrcat(r->pool, "proxy:", scheme, "://", host, sport,
e609c337f729875bc20e01096c7e610f45356f54nilgun "/", path, (search) ? "?" : "", (search) ? search : "", NULL);
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic const char *ap_proxy_location_reverse_map(request_rec *r, proxy_server_conf *conf, const char *url)
e609c337f729875bc20e01096c7e610f45356f54nilgun /* XXX FIXME: Make sure this handled the ambiguous case of the :80
e609c337f729875bc20e01096c7e610f45356f54nilgun * after the hostname */
e609c337f729875bc20e01096c7e610f45356f54nilgun if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) {
e609c337f729875bc20e01096c7e610f45356f54nilgun u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
e609c337f729875bc20e01096c7e610f45356f54nilgun/* Clear all connection-based headers from the incoming headers table */
e609c337f729875bc20e01096c7e610f45356f54nilgunstatic void ap_proxy_clear_connection(apr_pool_t *p, apr_table_t *headers)
e609c337f729875bc20e01096c7e610f45356f54nilgun const char *name;
e609c337f729875bc20e01096c7e610f45356f54nilgun char *next = apr_pstrdup(p, apr_table_get(headers, "Connection"));
e609c337f729875bc20e01096c7e610f45356f54nilgun while (*next && !apr_isspace(*next) && (*next != ',')) {
e609c337f729875bc20e01096c7e610f45356f54nilgun while (*next && (apr_isspace(*next) || (*next == ','))) {
e609c337f729875bc20e01096c7e610f45356f54nilgunapr_status_t ap_proxy_http_determine_connection(apr_pool_t *p, request_rec *r,
e609c337f729875bc20e01096c7e610f45356f54nilgun const char *proxyname,
e609c337f729875bc20e01096c7e610f45356f54nilgun * Break up the URL to determine the host to connect to
e609c337f729875bc20e01096c7e610f45356f54nilgun /* we break the URL into host, port, uri */
e609c337f729875bc20e01096c7e610f45356f54nilgun uri->port = apr_uri_default_port_for_scheme(uri->scheme);
e609c337f729875bc20e01096c7e610f45356f54nilgun ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
e609c337f729875bc20e01096c7e610f45356f54nilgun "proxy: HTTP connecting %s to %s:%d", *url, uri->hostname,
e609c337f729875bc20e01096c7e610f45356f54nilgun /* do a DNS lookup for the destination host */
e609c337f729875bc20e01096c7e610f45356f54nilgun /* see memory note above */
e609c337f729875bc20e01096c7e610f45356f54nilgun err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri->hostname),
e609c337f729875bc20e01096c7e610f45356f54nilgun /* allocate these out of the connection pool - the check on
e609c337f729875bc20e01096c7e610f45356f54nilgun * r->connection->id makes sure that this string does not get accessed
e609c337f729875bc20e01096c7e610f45356f54nilgun * past the connection lifetime */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* are we connecting directly, or via a proxy? */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* see memory note above */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun err = apr_sockaddr_info_get(&p_conn->addr, p_conn->name, APR_UNSPEC,
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* Get the server port for the Via headers */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun apr_snprintf(server_portstr, server_portstr_size, ":%d",
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* check if ProxyBlock directive on this host */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun "Connect to remote machine blocked");
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgunapr_status_t ap_proxy_http_create_connection(apr_pool_t *p, request_rec *r,
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun const char *proxyname) {
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* We have determined who to connect to. Now make the connection, supporting
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * a KeepAlive connection.
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* get all the possible IP addresses for the destname and loop through them
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * until we get a successful connection
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* if a keepalive socket is already open, check whether it must stay
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun * open, or whether it should be closed and a new socket created.
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* see memory note above */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun client_socket = ap_get_module_config(backend->connection->conn_config, &core_module);
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun (!apr_strnatcasecmp(backend->hostname, p_conn->name))) {
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun "proxy: keepalive address match (keep original socket)");
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun "proxy: keepalive address mismatch / connection has"
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun " changed (close old socket (%s/%s, %d/%d))",
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun /* get a socket - either a keepalive one, or a new one */
b9bf3918f6eaf7747bcbfbd02792bcbe4a052784nilgun if ((backend->connection) && (backend->connection->id == c->id)) {
e609c337f729875bc20e01096c7e610f45356f54nilgun /* use previous keepalive socket */
e609c337f729875bc20e01096c7e610f45356f54nilgun /* reset the connection filters */
e609c337f729875bc20e01096c7e610f45356f54nilgun /* save timeout */
e609c337f729875bc20e01096c7e610f45356f54nilgun apr_getsocketopt(p_conn->sock, APR_SO_TIMEOUT, ¤t_timeout);
e609c337f729875bc20e01096c7e610f45356f54nilgun /* set no timeout */
e609c337f729875bc20e01096c7e610f45356f54nilgun socket_status = apr_recv(p_conn->sock, test_buffer, &buffer_len);
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung /* put back old timeout */
727872d18412fc021f03969b8641810d8896820bhumbedooh apr_setsocketopt(p_conn->sock, APR_SO_TIMEOUT, current_timeout);
727872d18412fc021f03969b8641810d8896820bhumbedooh ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, NULL,
cc7e1025de9ac63bd4db6fe7f71c158b2cf09fe4humbedooh "proxy: HTTP: previous connection is closed");
0d0ba3a410038e179b695446bb149cce6264e0abnd /* create a new socket */
0d0ba3a410038e179b695446bb149cce6264e0abnd * At this point we have a list of one or more IP addresses of
727872d18412fc021f03969b8641810d8896820bhumbedooh * the machine to connect to. If configured, reorder this
0d0ba3a410038e179b695446bb149cce6264e0abnd * list so that the "best candidate" is first try. "best
0d0ba3a410038e179b695446bb149cce6264e0abnd * candidate" could mean the least loaded server, the fastest
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh * responding server, whatever.
af33a4994ae2ff15bc67d19ff1a7feb906745bf8rbowen * For now we do nothing, ie we get DNS round robin.
0d0ba3a410038e179b695446bb149cce6264e0abnd * XXX FIXME
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd failed = ap_proxy_connect_to_backend(&p_conn->sock, "HTTP",
if (failed) {
if (proxyname) {
return DECLINED;
return HTTP_BAD_GATEWAY;
if (!origin) {
return HTTP_INTERNAL_SERVER_ERROR;
return OK;
char *server_portstr) {
char *buf;
apr_bucket *e;
int counter;
if (r->main) {
NULL);
if (!hostname) {
r->uri );
const char *buf;
if (r->main) {
NULL);
e = apr_bucket_flush_create();
if (ap_should_client_block(r)) {
e = apr_bucket_flush_create();
return OK;
char *server_portstr) {
apr_bucket *e;
while (received_continue) {
if (len <= 0) {
backasswards = 0;
r->method);
return r->status;
const char *buf;
received_continue = 0;
const char *buf;
const char *buf;
if (backasswards) {
apr_bucket *e;
bb,
#if DEBUGGING
e = apr_bucket_flush_create();
return OK;
return status;
return OK;
return OK;
int status;
sizeof(*p_conn));
if (!r->main) {
if (!backend) {
if (!r->main) {
sizeof(server_portstr));
return status;
return status;
return status;
return status;
return status;
return OK;