www-modproxy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bar...@veribox.net
Subject [PATCH]: slight cleanup
Date Mon, 13 Aug 2001 18:23:29 GMT
this is merely a cleanup patch.
i split out ap_proxy_http_handler into five smaller functions.

barbee.

Index: proxy_http.c
===================================================================
RCS file: /home/cvspublic/httpd-proxy/module-2.0/proxy_http.c,v
retrieving revision 1.87
diff -u -r1.87 proxy_http.c
--- proxy_http.c        2001/08/12 21:24:35     1.87
+++ proxy_http.c        2001/08/13 16:30:00
@@ -67,6 +67,13 @@
                           char *url, const char *proxyname,
                           apr_port_t proxyport);

+typedef struct {
+    const char *name;
+    int port;
+    apr_sockaddr_t *addr;
+    apr_socket_t *sock;
+    int close;
+} proxy_http_conn_t;

 /*
  * Canonicalise http-like URLs.
@@ -178,339 +185,308 @@
     apr_table_unset(headers, "Connection");
 }

-/*
- * This handles http:// URLs, and other URLs using a remote proxy
over http
- * If proxyhost is NULL, then contact the server directly, otherwise
- * go via the proxy.
- * Note that if a proxy is used, then URLs other than http: can be
accessed,
- * also, if we have trouble which is clearly specific to the proxy,
then
- * we return DECLINED so that we can try another proxy. (Or the direct
- * route.)
- */
-int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
-                          char *url, const char *proxyname,
-                          apr_port_t proxyport)
-{
-    request_rec *rp;
-    const char *connectname;
-    int connectport = 0;
+static
+apr_status_t ap_proxy_http_determine_connection(apr_pool_t *p, request_rec
*r,
+                                                proxy_http_conn_t
*p_conn,
+                                                conn_rec *c,
+                                                proxy_server_conf
*conf,
+                                                apr_uri_components
*uri,
+                                                char *url,
+                                                const char *proxyname,
+                                                apr_port_t proxyport,
+                                                char *server_portstr)
{
+    int server_port;
+    apr_status_t err;
     apr_sockaddr_t *uri_addr;
-    apr_sockaddr_t *connect_addr;
-    char server_portstr[32];
-    apr_socket_t *sock;
-    int i, len, backasswards, eos, close=0, failed=0, new=0;
-    apr_status_t err, rv;
-    apr_array_header_t *headers_in_array;
-    apr_table_entry_t *headers_in;
-    char buffer[HUGE_STRING_LEN];
-    char *buf;
-    conn_rec *origin = NULL;
-    apr_uri_components uri;
-    proxy_conn_rec *backend;
-    int received_continue = 1; /* flag to indicate if we should

-                                * loop over response parsing logic
-                                * in the case that the origin told
us
-                                * to HTTP_CONTINUE
-                                */
-
-    /* Note: Memory pool allocation.
-     * A downstream keepalive connection is always connected to the
existence
-     * (or not) of an upstream keepalive connection. If this is not
done then
-     * load balancing against multiple backend servers breaks (one
backend
-     * server ends up taking 100% of the load), and the risk is run
of
-     * downstream keepalive connections being kept open unnecessarily.
This
-     * keeps webservers busy and ties up resources.
-     *
-     * As a result, we allocate all sockets out of the upstream connection
-     * pool, and when we want to reuse a socket, we check first whether
the
-     * connection ID of the current upstream connection is the same
as that
-     * of the connection when the socket was opened.
-     */
-    apr_pool_t *p = r->connection->pool;
-    conn_rec *c = r->connection;
-    apr_bucket *e;
-    apr_bucket_brigade *bb = apr_brigade_create(p);
-
-    /* is it for us? */
-    if (strncasecmp(url, "http:", 5)) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: HTTP: rejecting URL %s", url);
-       return DECLINED; /* only interested in HTTP */
-    }
-    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                "proxy: HTTP: serving URL %s", url);
-
-    /* create space for state information */
-    backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
&proxy_http_module);
-    if (!backend) {
-       backend = ap_pcalloc(c->pool, sizeof(proxy_conn_rec));
-       backend->connection = NULL;
-       backend->hostname = NULL;
-       backend->port = 0;
-       ap_set_module_config(c->conn_config, &proxy_http_module, backend);
-    }
-
     /*
-     * Step One: Determine Who To Connect To
-     *
      * Break up the URL to determine the host to connect to
      */

     /* we break the URL into host, port, uri */
-    if (APR_SUCCESS != apr_uri_parse_components(p, url, &uri)) {
-       return ap_proxyerror(r, HTTP_BAD_REQUEST,
-                            apr_pstrcat(p,"URI cannot be parsed:
", url, NULL));
+    if (APR_SUCCESS != apr_uri_parse_components(p, url, uri)) {

+        return ap_proxyerror(r, HTTP_BAD_REQUEST,
+                             apr_pstrcat(p,"URI cannot be parsed:
", url,
+                                         NULL));
     }
-    if (!uri.port) {
-       uri.port = apr_uri_default_port_for_scheme(uri.scheme);
+    if (!uri->port) {
+        uri->port = apr_uri_default_port_for_scheme(uri->scheme);
}

     ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                "proxy: HTTP connecting %s to %s:%d", url, uri.hostname,
uri.port);
+                 "proxy: HTTP connecting %s to %s:%d", url, uri->hostname,
+                 uri->port);

     /* do a DNS lookup for the destination host */
     /* see memory note above */
-    err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri.hostname),
APR_UNSPEC, uri.port, 0, c->pool);
+    err = apr_sockaddr_info_get(&uri_addr, apr_pstrdup(c->pool, uri->hostname),
+                                APR_UNSPEC, uri->port, 0, c->pool);
-    /* allocate these out of the connection pool - the check on r->connection->id
makes
-     * sure that this string does not get accessed past the connection
lifetime */
+    /* allocate these out of the connection pool - the check on

+     * r->connection->id makes sure that this string does not get
accessed
+     * past the connection lifetime */
     /* are we connecting directly, or via a proxy? */
     if (proxyname) {
-       connectname = apr_pstrdup(c->pool,proxyname);
-       connectport = proxyport;
-       /* see memory note above */
-        err = apr_sockaddr_info_get(&connect_addr, connectname, APR_UNSPEC,
connectport, 0, c->pool);
+        p_conn->name = apr_pstrdup(c->pool, proxyname);
+        p_conn->port = proxyport;
+        /* see memory note above */
+        err = apr_sockaddr_info_get(&p_conn->addr, p_conn->name,
APR_UNSPEC,
+                                    p_conn->port, 0, c->pool);
+    } else {
+        p_conn->name = apr_pstrdup(c->pool, uri->hostname);
+        p_conn->port = uri->port;
+        p_conn->addr = uri_addr;
+        url = apr_pstrcat(p, uri->path, uri->query ? "?" : "",
+                          uri->query ? uri->query : "",
+                          uri->fragment ? "#" : "",
+                          uri->fragment ? uri->fragment : "", NULL);
+    }
+
+    if (err != APR_SUCCESS) {
+        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                             apr_pstrcat(p, "DNS lookup failure for:
",
+                                         p_conn->name, NULL));
     }
-    else {
-       connectname = apr_pstrdup(c->pool, uri.hostname);
-       connectport = uri.port;
-       connect_addr = uri_addr;
-       url = apr_pstrcat(p, uri.path, uri.query ? "?" : "",
-                         uri.query ? uri.query : "", uri.fragment
? "#" : "",
-                         uri.fragment ? uri.fragment : "", NULL);
-    }

-
     /* Get the server port for the Via headers */
     {
-       i = ap_get_server_port(r);
-       if (ap_is_default_port(i,r)) {
-           strcpy(server_portstr,"");
-       } else {
-           apr_snprintf(server_portstr, sizeof server_portstr, ":%d",
i);
-       }
+        server_port = ap_get_server_port(r);
+        if (ap_is_default_port(server_port, r)) {
+            strcpy(server_portstr,"");
+        } else {
+            apr_snprintf(server_portstr, sizeof(server_portstr),
":%d",
+                         server_port);
+        }
     }

     /* check if ProxyBlock directive on this host */
     if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
-       return ap_proxyerror(r, HTTP_FORBIDDEN,
-                            "Connect to remote machine blocked");
+        return ap_proxyerror(r, HTTP_FORBIDDEN,
+                             "Connect to remote machine blocked");
}
+    return OK;
+}

+static
+apr_status_t ap_proxy_http_create_connection(apr_pool_t *p, request_rec
*r,
+                                             proxy_http_conn_t *p_conn,
+                                             conn_rec *c, conn_rec
**origin,
+                                             proxy_conn_rec *backend,
+                                             proxy_server_conf *conf,
+                                             const char *proxyname)
{
+    int failed=0, new=0;
+    apr_status_t err, rv;

-    /*
-     * Step Two: Make the Connection
-     *
-     * We have determined who to connect to. Now make the connection,
supporting
+    /* We have determined who to connect to. Now make the connection,
supporting
      * a KeepAlive connection.
      */

     /* get all the possible IP addresses for the destname and loop
through them
      * until we get a successful connection
      */
-    if (APR_SUCCESS != err) {
-       return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,

-                             "DNS lookup failure for: ",
-                             connectname, NULL));
-    }

     /* if a keepalive socket is already open, check whether it must
stay
      * open, or whether it should be closed and a new socket created.
*/
     /* see memory note above */
     if (backend->connection) {
-       if ((backend->connection->id == c->id) &&
-           (backend->port == connectport) &&
-           (backend->hostname) &&
-            (!apr_strnatcasecmp(backend->hostname,connectname)))
{
-           ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
-                        "proxy: keepalive address match (keep original
socket)");
-        }
-       else {
+        if ((backend->connection->id == c->id) &&
+            (backend->port == p_conn->port) &&
+            (backend->hostname) &&
+            (!apr_strnatcasecmp(backend->hostname, p_conn->name)))
{
+            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
+                         "proxy: keepalive address match (keep original
socket)");
+        } else {
             ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
-                        "proxy: keepalive address mismatch / connection
has"
-                        " changed (close old socket (%s/%s, %d/%d))",
-                        connectname, backend->hostname,
-                        connectport, backend->port);
+                         "proxy: keepalive address mismatch / connection
has"
+                         " changed (close old socket (%s/%s, %d/%d))",
+                         p_conn->name, backend->hostname, p_conn->port,
+                         backend->port);
             apr_socket_close(backend->connection->client_socket);
backend->connection = NULL;
-       }
+        }
     }

     /* get a socket - either a keepalive one, or a new one */
     new = 1;
     if ((backend->connection) && (backend->connection->id == c->id))
{

-       /* use previous keepalive socket */
-       origin = backend->connection;
-       sock = origin->client_socket;
-       new = 0;
+        /* use previous keepalive socket */
+        *origin = backend->connection;
+        p_conn->sock = (*origin)->client_socket;
+        new = 0;

-       /* reset the connection filters */
-       ap_proxy_reset_output_filters(origin);
+        /* reset the connection filters */
+        ap_proxy_reset_output_filters(*origin);

-       /* XXX FIXME: If the socket has since closed, change new to
1 so
-        * a new socket is opened */
+        /* XXX FIXME: If the socket has since closed, change new
to 1 so
+         * a new socket is opened */
     }
     if (new) {

-       /* create a new socket */
-       backend->connection = NULL;
+        /* create a new socket */
+        backend->connection = NULL;

-       /* see memory note above */
-       if ((rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM,
c->pool)) != APR_SUCCESS) {
+        /* see memory note above */
+        if ((rv = apr_socket_create(&p_conn->sock, APR_INET, SOCK_STREAM,
+                                    c->pool)) != APR_SUCCESS) {

ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
-                        "proxy: error creating socket");
-           return HTTP_INTERNAL_SERVER_ERROR;
-       }
+                         "proxy: error creating socket");
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }

 #if !defined(TPF) && !defined(BEOS)
-       if (conf->recv_buffer_size > 0 && (rv = apr_setsocketopt(sock,
APR_SO_RCVBUF,
-           conf->recv_buffer_size))) {
-           ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                         "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize,
using default");
-       }
+        if (conf->recv_buffer_size > 0 &&
+            (rv = apr_setsocketopt(p_conn->sock, APR_SO_RCVBUF,

+                                   conf->recv_buffer_size))) {
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+                          "setsockopt(SO_RCVBUF): Failed to set "
+                          "ProxyReceiveBufferSize, using default");
+        }
 #endif

         /* Set a timeout on the socket */
-        apr_setsocketopt(sock, APR_SO_TIMEOUT, (int)(r->server->timeout
* APR_USEC_PER_SEC));
+        apr_setsocketopt(p_conn->sock, APR_SO_TIMEOUT,
+                         (int)(r->server->timeout * APR_USEC_PER_SEC));
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: socket has been created");
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                     "proxy: socket has been created");

-       /*
-        * At this point we have a list of one or more IP addresses
of
-        * the machine to connect to. If configured, reorder this
-        * list so that the "best candidate" is first try. "best

-        * candidate" could mean the least loaded server, the fastest
-        * responding server, whatever.
+        /*
+         * At this point we have a list of one or more IP addresses
of
+         * the machine to connect to. If configured, reorder this
+         * list so that the "best candidate" is first try. "best
+         * candidate" could mean the least loaded server, the fastest
+         * responding server, whatever.
          *
          * For now we do nothing, ie we get DNS round robin.
-        * XXX FIXME
-        */
-
+         * XXX FIXME
+         */

-       /* try each IP address until we connect successfully */
-       failed = 1;
-       while (connect_addr) {
+        /* try each IP address until we connect successfully */

+        failed = 1;
+        while (p_conn->addr) {

-           /* make the connection out of the socket */
-           rv = apr_connect(sock, connect_addr);
+            /* make the connection out of the socket */
+            rv = apr_connect(p_conn->sock, p_conn->addr);

-           /* if an error occurred, loop round and try again */

+            /* if an error occurred, loop round and try again */
if (rv != APR_SUCCESS) {
-               ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
-                            "proxy: attempt to connect to %pI (%s)
failed",
-                            connect_addr, connectname);
-               connect_addr = connect_addr->next;
-               continue;
+                ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
+                             "proxy: attempt to connect to %pI (%s)
failed",
+                             p_conn->addr, p_conn->name);
+                p_conn->addr = p_conn->addr->next;
+                continue;
+            }
+
+            /* if we get here, all is well */
+            failed = 0;
+            break;
+        }
+
+        /* handle a permanent error from the above loop */
+        if (failed) {
+            apr_socket_close(p_conn->sock);
+            if (proxyname) {
+                return DECLINED;
+            } else {
+                return HTTP_BAD_GATEWAY;
             }
-
-           /* if we get here, all is well */
-           failed = 0;
-           break;
-       }
-
-       /* handle a permanent error from the above loop */
-       if (failed) {
-           apr_socket_close(sock);
-           if (proxyname) {
-               return DECLINED;
-           }
-           else {
-               return HTTP_BAD_GATEWAY;
-           }
-       }
-
-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: socket is connected");
+        }

-       /* the socket is now open, create a new backend server connection
*/
-       origin = ap_new_connection(c->pool, r->server, sock, r->connection->id);
-       if (!origin) {
-           /* the peer reset the connection already; ap_new_connection()
-            * closed the socket */
-           ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
-                        "proxy: an error occurred creating a new
connection to %pI (%s)", connect_addr, connectname);
-           apr_socket_close(sock);
-           return HTTP_INTERNAL_SERVER_ERROR;
-       }
-       backend->connection = origin;
-       backend->hostname = apr_pstrdup(c->pool, connectname);
-       backend->port = connectport;
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                     "proxy: socket is connected");

-       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                    "proxy: connection complete");
+        /* the socket is now open, create a new backend server connection
*/
+        *origin = ap_new_connection(c->pool, r->server, p_conn->sock,
+                                   r->connection->id);
+        if (!origin) {
+        /* the peer reset the connection already; ap_new_connection()
+         * closed the socket
+         */
+            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
+                         r->server, "proxy: an error occurred creating
a "
+                         "new connection to %pI (%s)", p_conn->addr,
+                         p_conn->name);
+            apr_socket_close(p_conn->sock);
+            return HTTP_INTERNAL_SERVER_ERROR;
+        }
+        backend->connection = *origin;
+        backend->hostname = apr_pstrdup(c->pool, p_conn->name);

+        backend->port = p_conn->port;

-       /* set up the connection filters */
-       ap_proxy_pre_http_connection(origin, NULL);
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                     "proxy: connection complete");

+        /* set up the connection filters */
+        ap_proxy_pre_http_connection(*origin, NULL);
     }
-
+    return OK;
+}

+static
+apr_status_t ap_proxy_http_request(apr_pool_t *p, request_rec *r,
+                                   proxy_http_conn_t *p_conn, conn_rec
*origin,
+                                   proxy_server_conf *conf,
+                                   apr_uri_components *uri,
+                                   char *url, apr_bucket_brigade
*bb,
+                                   char *server_portstr) {
+    char buffer[HUGE_STRING_LEN];
+    char *buf;
+    apr_bucket *e;
+    apr_array_header_t *headers_in_array;
+    apr_table_entry_t *headers_in;
+    int counter;
     /*
-     * Step Three: Send the Request
-     *
      * Send the HTTP/1.1 request to the remote server
      */

-
     /* strip connection listed hop-by-hop headers from the request
*/
     /* even though in theory a connection: close coming from the
client
      * should not affect the connection to the server, it's unlikely
* that subsequent client requests will hit this thread/process, so
* we cancel server keepalive if the client does.
      */
-    close += ap_proxy_liststr(apr_table_get(r->headers_in, "Connection"),
"close");
+    p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_in,
+                                                     "Connection"),
"close");
     ap_proxy_clear_connection(p, r->headers_in);
-    if (close) {
-       apr_table_setn(r->headers_in, "Connection", "close");
-       origin->keepalive = 0;
+    if (p_conn->close) {
+        apr_table_setn(r->headers_in, "Connection", "close");
+        origin->keepalive = 0;
     }

     buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
e = apr_bucket_pool_create(buf, strlen(buf), p);
     APR_BRIGADE_INSERT_TAIL(bb, e);
-    if (uri.port_str && uri.port != DEFAULT_HTTP_PORT) {
-        buf = apr_pstrcat(p, "Host: ", uri.hostname, ":", uri.port_str,
CRLF, NULL);
+    if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
+        buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
CRLF,
+                          NULL);
         e = apr_bucket_pool_create(buf, strlen(buf), p);
         APR_BRIGADE_INSERT_TAIL(bb, e);
-    }
-    else {
-        buf = apr_pstrcat(p, "Host: ", uri.hostname, CRLF, NULL);
+    } else {
+        buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
e = apr_bucket_pool_create(buf, strlen(buf), p);
         APR_BRIGADE_INSERT_TAIL(bb, e);
     }

     /* handle Via */
     if (conf->viaopt == via_block) {
-       /* Block all outgoing Via: headers */
-       apr_table_unset(r->headers_in, "Via");
+        /* Block all outgoing Via: headers */
+        apr_table_unset(r->headers_in, "Via");
     } else if (conf->viaopt != via_off) {
-       /* Create a "Via:" request header entry and merge it */
-       /* Generate outgoing Via: header with/without server comment:
*/
-       apr_table_mergen(r->headers_in, "Via",
-                   (conf->viaopt == via_full)
-                       ? apr_psprintf(p, "%d.%d %s%s (%s)",
-                               HTTP_VERSION_MAJOR(r->proto_num),
-                               HTTP_VERSION_MINOR(r->proto_num),
-                               ap_get_server_name(r), server_portstr,
-                               AP_SERVER_BASEVERSION)
-                       : apr_psprintf(p, "%d.%d %s%s",
-                               HTTP_VERSION_MAJOR(r->proto_num),
-                               HTTP_VERSION_MINOR(r->proto_num),
-                               ap_get_server_name(r), server_portstr)
-                       );
+        /* Create a "Via:" request header entry and merge it */

+        /* Generate outgoing Via: header with/without server comment:
*/
+        apr_table_mergen(r->headers_in, "Via",
+                         (conf->viaopt == via_full)
+                         ? apr_psprintf(p, "%d.%d %s%s (%s)",
+                                        HTTP_VERSION_MAJOR(r->proto_num),
+                                        HTTP_VERSION_MINOR(r->proto_num),
+                                        ap_get_server_name(r), server_portstr,
+                                        AP_SERVER_BASEVERSION)
+                         : apr_psprintf(p, "%d.%d %s%s",
+                                        HTTP_VERSION_MAJOR(r->proto_num),
+                                        HTTP_VERSION_MINOR(r->proto_num),
+                                        ap_get_server_name(r), server_portstr)
+        );
     }

     /* X-Forwarded-*: handling
@@ -540,7 +516,8 @@
         /* Add X-Forwarded-For: so that the upstream has a chance
to
          * determine, where the original request came from.
          */
-        apr_table_setn(r->headers_in, "X-Forwarded-For", r->connection->remote_ip);
+        apr_table_setn(r->headers_in, "X-Forwarded-For",
+                       r->connection->remote_ip);

         /* Add X-Forwarded-Host: so that upstream knows what the
* original request hostname was.
@@ -554,42 +531,46 @@
          * XXX: This duplicates Via: - do we strictly need it?
          */
         apr_table_setn(r->headers_in, "X-Forwarded-Server",
-                         r->server->server_hostname);
+                       r->server->server_hostname);
     }

     /* send request headers */
     headers_in_array = apr_table_elts(r->headers_in);
     headers_in = (apr_table_entry_t *) headers_in_array->elts;
-    for (i = 0; i < headers_in_array->nelts; i++) {
-       if (headers_in[i].key == NULL || headers_in[i].val == NULL
+    for (counter = 0; counter < headers_in_array->nelts; counter++)
{
+        if (headers_in[counter].key == NULL || headers_in[counter].val
== NULL

-       /* Clear out hop-by-hop request headers not to send
-        * RFC2616 13.5.1 says we should strip these headers
-        */
-           || !apr_strnatcasecmp(headers_in[i].key, "Host")    /*
Already sent */
-            || !apr_strnatcasecmp(headers_in[i].key, "Keep-Alive")
-            || !apr_strnatcasecmp(headers_in[i].key, "TE")
-            || !apr_strnatcasecmp(headers_in[i].key, "Trailer")

-            || !apr_strnatcasecmp(headers_in[i].key, "Transfer-Encoding")
-            || !apr_strnatcasecmp(headers_in[i].key, "Upgrade")

+        /* Clear out hop-by-hop request headers not to send
+         * RFC2616 13.5.1 says we should strip these headers
+         */
+                /* Already sent */
+            || !apr_strnatcasecmp(headers_in[counter].key, "Host")
+
+            || !apr_strnatcasecmp(headers_in[counter].key, "Keep-Alive")
+            || !apr_strnatcasecmp(headers_in[counter].key, "TE")
+            || !apr_strnatcasecmp(headers_in[counter].key, "Trailer")
+            || !apr_strnatcasecmp(headers_in[counter].key, "Transfer-Encoding")
+            || !apr_strnatcasecmp(headers_in[counter].key, "Upgrade")
/* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be
             * suppressed if THIS server requested the authentication,
* not when a frontend proxy requested it!
-             *
-             * The solution to this problem is probably to strip
out
-             * the Proxy-Authorisation header in the authorisation
-             * code itself, not here. This saves us having to signal
-             * somehow whether this request was authenticated or
not.
+         *
+         * The solution to this problem is probably to strip out
+         * the Proxy-Authorisation header in the authorisation
+         * code itself, not here. This saves us having to signal
+         * somehow whether this request was authenticated or not.
*/
-           || !apr_strnatcasecmp(headers_in[i].key, "Proxy-Authorization")
-           || !apr_strnatcasecmp(headers_in[i].key, "Proxy-Authenticate"))
-           continue;
+            || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authorization")
+            || !apr_strnatcasecmp(headers_in[counter].key,"Proxy-Authenticate"))
{
+            continue;
+        }

-        buf = apr_pstrcat(p, headers_in[i].key, ": ", headers_in[i].val,
CRLF, NULL);
+        buf = apr_pstrcat(p, headers_in[counter].key, ": ",
+                          headers_in[counter].val, CRLF,
+                          NULL);
         e = apr_bucket_pool_create(buf, strlen(buf), p);
         APR_BRIGADE_INSERT_TAIL(bb, e);
-
     }

     /* add empty line at the end of the headers */
@@ -602,152 +583,186 @@

     /* send the request data, if any. */
     if (ap_should_client_block(r)) {
-       while ((i = ap_get_client_block(r, buffer, sizeof buffer))
> 0) {
-            e = apr_bucket_pool_create(buffer, i, p);
+        while ((counter = ap_get_client_block(r, buffer, sizeof(buffer)))
> 0) {
+            e = apr_bucket_pool_create(buffer, counter, p);
+            APR_BRIGADE_INSERT_TAIL(bb, e);
+            e = apr_bucket_flush_create();
             APR_BRIGADE_INSERT_TAIL(bb, e);
-           e = apr_bucket_flush_create();
-           APR_BRIGADE_INSERT_TAIL(bb, e);
-           ap_pass_brigade(origin->output_filters, bb);
-           apr_brigade_cleanup(bb);
+            ap_pass_brigade(origin->output_filters, bb);
+            apr_brigade_cleanup(bb);
         }
     }
+    return OK;
+}

+static
+apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec
*r,
+                                            proxy_http_conn_t *p_conn,
+                                            conn_rec *origin,
+                                            proxy_conn_rec *backend,
+                                            proxy_server_conf *conf,
+                                            apr_bucket_brigade *bb,
+                                            char *server_portstr)
{
+    char buffer[HUGE_STRING_LEN];
+    char *buf;
+    request_rec *rp;
+    apr_bucket *e;
+    apr_status_t rv;
+    int eos, len, backasswards;
+    int received_continue = 1; /* flag to indicate if we should

+                                * loop over response parsing logic
+                                * in the case that the origin told
us
+                                * to HTTP_CONTINUE
+                                */

-    /*
-     * Step Four: Receive the Response
-     *
-     * Get response from the remote server, and pass it up the
+    /* Get response from the remote server, and pass it up the
      * filter chain
      */

     rp = ap_proxy_make_fake_req(origin, r);

-    apr_brigade_cleanup(bb);
-
     while (received_continue) {
+        apr_brigade_cleanup(bb);
+
         if (APR_SUCCESS != (rv = ap_proxy_string_read(origin, bb,
buffer, sizeof(buffer), &eos))) {
-            apr_socket_close(sock);
+            apr_socket_close(p_conn->sock);
             backend->connection = NULL;
             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
-                 "proxy: error reading status line from remote server
%s",
-                 connectname);
-              return ap_proxyerror(r, HTTP_BAD_GATEWAY,
-                             "Error reading from remote server");
+                          "proxy: error reading status line from
remote "
+                          "server %s", p_conn->name);
+            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
+                                 "Error reading from remote server");
}
         len = strlen(buffer);
-
-        /* Is it an HTTP/1 response?  This is buggy if we ever see
an HTTP/1.10 */
+
+       /* Is it an HTTP/1 response?
+        * This is buggy if we ever see an HTTP/1.10
+        */
         if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
             int major, minor;
-
+
             if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor))
{
                 major = 1;
                 minor = 1;
             }
-
-            /* If not an HTTP/1 message or if the status line was
> 8192 bytes */
+            /* If not an HTTP/1 message or
+             * if the status line was > 8192 bytes
+             */
             else if ((buffer[5] != '1') || (len >= sizeof(buffer)-1))
{
-                apr_socket_close(sock);
+                apr_socket_close(p_conn->sock);
                 backend->connection = NULL;
                 return ap_proxyerror(r, HTTP_BAD_GATEWAY,
-                                apr_pstrcat(p, "Corrupt status line
returned by remote server: ", buffer, NULL));
+                apr_pstrcat(p, "Corrupt status line returned by remote
"
+                            "server: ", buffer, NULL));
             }
             backasswards = 0;
             buffer[--len] = '\0';
-
+
             buffer[12] = '\0';
             r->status = atoi(&buffer[9]);
-
+
             buffer[12] = ' ';
             r->status_line = apr_pstrdup(p, &buffer[9]);
-
+
             /* read the headers. */
-            /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped
headers */
+            /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped
headers*/
             /* Also, take care with headers with multiple occurences.
*/
-
-            r->headers_out = ap_proxy_read_headers(r, rp, buffer,
sizeof(buffer), origin);
+
+            r->headers_out = ap_proxy_read_headers(r, rp, buffer,
+                                                   sizeof(buffer),
origin);
             if (r->headers_out == NULL) {
-                ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO,
0, r->server,
-                        "proxy: bad HTTP/%d.%d header returned by
%s (%s)",
-                        major, minor, r->uri, r->method);
-                close += 1;
-            }
-            else
-            {
+                ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO,
0,
+                             r->server, "proxy: bad HTTP/%d.%d header
"
+                             "returned by %s (%s)", major, minor,
r->uri,
+                             r->method);
+                p_conn->close += 1;
+            } else {
                 /* strip connection listed hop-by-hop headers from
response */
                 const char *buf;
-                close += ap_proxy_liststr(apr_table_get(r->headers_out,
"Connection"), "close");
+                p_conn->close += ap_proxy_liststr(apr_table_get(r->headers_out,
+                                                                "Connection"),
+                                                  "close");
                 ap_proxy_clear_connection(p, r->headers_out);
                 if ((buf = apr_table_get(r->headers_out, "Content-Type")))
{
                     r->content_type = apr_pstrdup(p, buf);
-                }
+                }
             }
-
+
             /* handle Via header in response */
             if (conf->viaopt != via_off && conf->viaopt != via_block)
{
                 /* create a "Via:" response header entry and merge
it */
                 ap_table_mergen(r->headers_out, "Via",
-                           (conf->viaopt == via_full)
-                           ? apr_psprintf(p, "%d.%d %s%s (%s)",

-                                   HTTP_VERSION_MAJOR(r->proto_num),
-                                   HTTP_VERSION_MINOR(r->proto_num),
-                                   ap_get_server_name(r), server_portstr,
-                                   AP_SERVER_BASEVERSION)
-                           : apr_psprintf(p, "%d.%d %s%s",
-                                   HTTP_VERSION_MAJOR(r->proto_num),
-                                   HTTP_VERSION_MINOR(r->proto_num),
-                                   ap_get_server_name(r), server_portstr)
-                                );
+                                (conf->viaopt == via_full)
+                                ? apr_psprintf(p, "%d.%d %s%s (%s)",
+                                               HTTP_VERSION_MAJOR(r->proto_num),
+                                               HTTP_VERSION_MINOR(r->proto_num),
+                                               ap_get_server_name(r),
+                                               server_portstr,
+                                               AP_SERVER_BASEVERSION)
+                                : apr_psprintf(p, "%d.%d %s%s",

+                                               HTTP_VERSION_MAJOR(r->proto_num),
+                                               HTTP_VERSION_MINOR(r->proto_num),
+                                               ap_get_server_name(r),
+                                               server_portstr)
+                );
             }
-
+
             /* cancel keepalive if HTTP/1.0 or less */
             if ((major < 1) || (minor < 1)) {
-                close += 1;
-            origin->keepalive = 0;
+                p_conn->close += 1;
+                origin->keepalive = 0;
             }
-        }
-        else {
+        } else {
             /* an http/0.9 response */
-                backasswards = 1;
-                r->status = 200;
-                   r->status_line = "200 OK";
-                close += 1;
+            backasswards = 1;
+            r->status = 200;
+            r->status_line = "200 OK";
+            p_conn->close += 1;
         }
-
-            if ( r->status != HTTP_CONTINUE ) {
-                received_continue = 0;
-            } else {
-                ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG,
0, NULL,
-                             "proxy: HTTP: received 100 CONTINUE");
-            }
+
+        if ( r->status != HTTP_CONTINUE ) {
+            received_continue = 0;
+        } else {
+            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_DEBUG, 0,
NULL,
+                         "proxy: HTTP: received 100 CONTINUE");

+        }
+
         /* we must accept 3 kinds of date, but generate only 1 kind
of date */
         {
             const char *buf;
             if ((buf = apr_table_get(r->headers_out, "Date")) !=
NULL) {
-                apr_table_set(r->headers_out, "Date", ap_proxy_date_canon(p,
buf));
+                apr_table_set(r->headers_out, "Date",
+                              ap_proxy_date_canon(p, buf));
             }
             if ((buf = apr_table_get(r->headers_out, "Expires"))
!= NULL) {
-                apr_table_set(r->headers_out, "Expires", ap_proxy_date_canon(p,
buf));
+                apr_table_set(r->headers_out, "Expires",
+                              ap_proxy_date_canon(p, buf));
             }
             if ((buf = apr_table_get(r->headers_out, "Last-Modified"))
!= NULL) {
-                apr_table_set(r->headers_out, "Last-Modified", ap_proxy_date_canon(p,
buf));
+                apr_table_set(r->headers_out, "Last-Modified",
+                              ap_proxy_date_canon(p, buf));
             }
         }
-
-        /* munge the Location and URI response headers according
to ProxyPassReverse */
+
+        /* munge the Location and URI response headers according
to
+         * ProxyPassReverse
+         */
         {
-            const char *buf;
+            char *buf;
             if ((buf = apr_table_get(r->headers_out, "Location"))
!= NULL) {
-                apr_table_set(r->headers_out, "Location", ap_proxy_location_reverse_map(r,
conf, buf));
+                apr_table_set(r->headers_out, "Location",
+                              ap_proxy_location_reverse_map(r, conf,
buf));
             }
             if ((buf = apr_table_get(r->headers_out, "Content-Location"))
!= NULL) {
-                apr_table_set(r->headers_out, "Content-Location",
ap_proxy_location_reverse_map(r, conf, buf));
+                apr_table_set(r->headers_out, "Content-Location",
+                              ap_proxy_location_reverse_map(r, conf,
buf));
             }
             if ((buf = apr_table_get(r->headers_out, "URI")) != NULL)
{
-                apr_table_set(r->headers_out, "URI", ap_proxy_location_reverse_map(r,
conf, buf));
+                apr_table_set(r->headers_out, "URI",
+                              ap_proxy_location_reverse_map(r, conf,
buf));
             }
         }
-
+
         r->sent_bodyct = 1;
         /* Is it an HTTP/0.9 response? If so, send the extra data
*/
         if (backasswards) {
@@ -755,85 +770,184 @@
             e = apr_bucket_heap_create(buffer, cntr, 0, NULL);
             APR_BRIGADE_INSERT_TAIL(bb, e);
         }
-
+
         /* send body - but only if a body is expected */
-        if ((!r->header_only) &&                       /* not HEAD
request */
-            (r->status > 199) &&                       /* not any
1xx response */
-            (r->status != HTTP_NO_CONTENT) &&        /* not 204 */
-            (r->status != HTTP_RESET_CONTENT) &&        /* not 205
*/
-            (r->status != HTTP_NOT_MODIFIED)) {        /* not 304
*/
-
+        if ((!r->header_only) &&                       /* not HEAD
request */
+            (r->status > 199) &&                       /* not any
1xx response */
+            (r->status != HTTP_NO_CONTENT) &&  /* not 204 */
+            (r->status != HTTP_RESET_CONTENT) &&       /* not 205
*/
+            (r->status != HTTP_NOT_MODIFIED)) {        /* not 304
*/
+
             const char *buf;
             apr_off_t readbytes;
-
+
             /* if chunked - insert DECHUNK filter */
-            if (ap_proxy_liststr((buf = apr_table_get(r->headers_out,
"Transfer-Encoding")), "chunked")) {
+            if (ap_proxy_liststr((buf = apr_table_get(r->headers_out,
+                                  "Transfer-Encoding")), "chunked"))
{
                 rp->read_chunked = 1;
                 apr_table_unset(r->headers_out, "Transfer-Encoding");
if ((buf = ap_proxy_removestr(r->pool, buf, "chunked"))) {
-               apr_table_set(r->headers_out, "Transfer-Encoding",
buf);
+                    apr_table_set(r->headers_out, "Transfer-Encoding",
buf);
                 }
                 ap_add_input_filter("DECHUNK", NULL, rp, origin);
readbytes = -1;
             }
-
             /* if content length - set the length to read */
             else if ((buf = apr_table_get(r->headers_out, "Content-Length")))
{
                 readbytes = atol(buf);
             }
-
-            /* no chunked / no length therefore read till EOF and
cancel keepalive */
+            /* no chunked / no length therefore read till EOF and
+             * cancel keepalive
+             */
             else {
-                close += 1;
+                p_conn->close += 1;
             }
-
+
             /* if keepalive cancelled, read to EOF */
-            if (close) {
+            if (p_conn->close) {
                 readbytes = -1;
             }
-
+
             ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
-                    "proxy: start body send");
+                         "proxy: start body send");

             /* read the body, pass it to the output filters */
             while (ap_get_brigade(rp->input_filters, bb, AP_MODE_NONBLOCKING,
&readbytes) == APR_SUCCESS) {
 #if DEBUGGING
-            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
-                    "proxy (PID %d): readbytes: %#x", getpid(), readbytes);
+                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO,
0,
+                             r->server, "proxy (PID %d): readbytes:
%#x",
+                             getpid(), readbytes);
 #endif
+
                 if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
-               ap_pass_brigade(r->output_filters, bb);
-               break;
+                    ap_pass_brigade(r->output_filters, bb);
+                       break;
                 }
                 if (ap_pass_brigade(r->output_filters, bb) != APR_SUCCESS)
{
                     /* Ack! Phbtt! Die! User aborted! */
-                    close = 1;  /* this causes socket close below
*/
+                    p_conn->close = 1;  /* this causes socket close
below */
                     break;
                 }
                 apr_brigade_cleanup(bb);
             }
             ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
                          "proxy: end body send");
-        }
-        else {
+        } else {
             ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0,
r->server,
-                    "proxy: header only");
+                         "proxy: header only");
         }
     }
+    return OK;
+}

-    /*
-     * Step Five: Clean Up
-     *
-     * If there are no KeepAlives, or if the connection has been
signalled
+static
+apr_status_t ap_proxy_http_cleanup(request_rec *r, proxy_http_conn_t
*p_conn,
+                                   proxy_conn_rec *backend) {
+    /* If there are no KeepAlives, or if the connection has been
signalled
      * to close, close the socket and clean up
      */

     /* if the connection is < HTTP/1.1, or Connection: close,
      * we close the socket, otherwise we leave it open for KeepAlive
support
+     */
+    if (p_conn->close || (r->proto_num < HTTP_VERSION(1,1))) {
+        apr_socket_close(p_conn->sock);
+        backend->connection = NULL;
+    }
+    return OK;
+}
+
+/*
+ * This handles http:// URLs, and other URLs using a remote proxy
over http
+ * If proxyhost is NULL, then contact the server directly, otherwise
+ * go via the proxy.
+ * Note that if a proxy is used, then URLs other than http: can be
accessed,
+ * also, if we have trouble which is clearly specific to the proxy,
then
+ * we return DECLINED so that we can try another proxy. (Or the direct
+ * route.)
+ */
+int ap_proxy_http_handler(request_rec *r, proxy_server_conf *conf,
+                          char *url, const char *proxyname,
+                          apr_port_t proxyport)
+{
+    int status;
+    char server_portstr[32];
+    conn_rec *origin = NULL;
+    proxy_conn_rec *backend;
+
+    /* Note: Memory pool allocation.
+     * A downstream keepalive connection is always connected to the
existence
+     * (or not) of an upstream keepalive connection. If this is not
done then
+     * load balancing against multiple backend servers breaks (one
backend
+     * server ends up taking 100% of the load), and the risk is run
of
+     * downstream keepalive connections being kept open unnecessarily.
This
+     * keeps webservers busy and ties up resources.
+     *
+     * As a result, we allocate all sockets out of the upstream connection
+     * pool, and when we want to reuse a socket, we check first whether
the
+     * connection ID of the current upstream connection is the same
as that
+     * of the connection when the socket was opened.
      */
-    if (close || (r->proto_num < HTTP_VERSION(1,1))) {
-        apr_socket_close(sock);
-       backend->connection = NULL;
+    apr_pool_t *p = r->connection->pool;
+    conn_rec *c = r->connection;
+    apr_bucket_brigade *bb = apr_brigade_create(p);
+    apr_uri_components *uri = apr_palloc(r->connection->pool, sizeof(*uri));
+    proxy_http_conn_t *p_conn = apr_palloc(r->connection->pool,

+                                           sizeof(*p_conn));
+
+    /* is it for us? */
+    if (strncasecmp(url, "http:", 5)) {
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                     "proxy: HTTP: rejecting URL %s", url);
+        return DECLINED; /* only interested in HTTP */
+    }
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: HTTP: serving URL %s", url);
+
+    /* create space for state information */
+    backend = (proxy_conn_rec *) ap_get_module_config(c->conn_config,
+                                                      &proxy_http_module);
+    if (!backend) {
+        backend = ap_pcalloc(c->pool, sizeof(proxy_conn_rec));
+        backend->connection = NULL;
+        backend->hostname = NULL;
+        backend->port = 0;
+        ap_set_module_config(c->conn_config, &proxy_http_module,
backend);
+    }
+
+    /* Step One: Determine Who To Connect To */
+    status = ap_proxy_http_determine_connection(p, r, p_conn, c,
conf, uri, url,
+                                                proxyname, proxyport,
+                                                server_portstr);
+    if ( status != OK ) {
+        return status;
+    }
+
+    /* Step Two: Make the Connection */
+    status = ap_proxy_http_create_connection(p, r, p_conn, c, &origin,
backend,
+                                             conf, proxyname);
+    if ( status != OK ) {
+        return status;
+    }
+
+    /* Step Three: Send the Request */
+    status = ap_proxy_http_request(p, r, p_conn, origin, conf, uri,
url, bb,
+                                   server_portstr);
+    if ( status != OK ) {
+        return status;
+    }
+
+    /* Step Four: Receive the Response */
+    status = ap_proxy_http_process_response(p, r, p_conn, origin,
backend, conf,
+                                            bb, server_portstr);
+    if ( status != OK ) {
+        return status;
+    }
+
+    /* Step Five: Clean Up */
+    status = ap_proxy_http_cleanup(r, p_conn, backend);
+    if ( status != OK ) {
+        return status;
     }

     return OK;

Mime
View raw message