Hi all,

The attached two patches implement KeepAlive support.

I don't want to commit these just yet until a few people have given it a
look-see, as there are a few outstanding problems with it.

Known Bugs:

- Lack of DECHUNK support from downstream server.

If a downstream server sends a response that is chunked, there is no way
for the proxy to determine the content length. As a result the
connection between the proxy and the downstream server hangs until the
downstream server times out it's connection, causing a delay.

There is DECHUNK filter inside Apache - but it depends on a request_rec
being available. In the ap_proxy_http_handler() there is only a conn_rec
defined, but no request_rec. Any ideas on the correct way to fix this?

- Connection fails after HEAD request.

If a connection is made to a reverse proxy, and a HEAD request is sent,
this request is completed successfully. The problem is that the next
request (on the same keepalive connection) will fail with a "Document
contains no data" on line 593 of proxy_http.c.

If a third request is sent, this request will work - it would seem that
the request directly following a HEAD request (and I suspect any request
that returns no body) always fails.

I have tried to track this problem down with no success :(

Regards,
Graham
-- 
-----------------------------------------
[EMAIL PROTECTED]               "There's a moon
                                        over Bourbon Street
                                                tonight..."
diff -u3 -r --exclude=CVS ../../pristine/httpd-2.0/include/httpd.h 
httpd-2.0/include/httpd.h
--- ../../pristine/httpd-2.0/include/httpd.h    Mon Mar 26 00:08:43 2001
+++ httpd-2.0/include/httpd.h   Thu Mar 29 15:29:20 2001
@@ -884,6 +884,10 @@
     /** The length of the current request body
      *  @defvar long remain */
     long remain;
+
+    /** Connection to a downstream server/proxy */
+    conn_rec *proxy;
+
 };
 
 /* Per-vhost config... */
diff -u3 -r --exclude=CVS 
../../../../pristine/httpd-proxy/module-2.0/mod_proxy.c proxy/mod_proxy.c
--- ../../../../pristine/httpd-proxy/module-2.0/mod_proxy.c     Mon Mar 26 
00:35:07 2001
+++ proxy/mod_proxy.c   Fri Mar 30 14:53:59 2001
@@ -430,7 +430,6 @@
     ps->raliases = ap_make_array(p, 10, sizeof(struct proxy_alias));
     ps->noproxies = ap_make_array(p, 10, sizeof(struct noproxy_entry));
     ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));
-    ps->nocaches = ap_make_array(p, 10, sizeof(struct nocache_entry));
     ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));
     ps->cache_completion = DEFAULT_CACHE_COMPLETION;
     ps->domain = NULL;
@@ -455,7 +454,6 @@
     ps->raliases = ap_append_arrays(p, base->raliases, overrides->raliases);
     ps->noproxies = ap_append_arrays(p, base->noproxies, overrides->noproxies);
     ps->dirconn = ap_append_arrays(p, base->dirconn, overrides->dirconn);
-    ps->nocaches = ap_append_arrays(p, base->nocaches, overrides->nocaches);
     ps->allowed_connect_ports = ap_append_arrays(p, 
base->allowed_connect_ports, overrides->allowed_connect_ports);
 
     ps->domain = (overrides->domain == NULL) ? base->domain : 
overrides->domain;
@@ -549,6 +547,7 @@
     struct noproxy_entry *new;
     struct noproxy_entry *list = (struct noproxy_entry *) 
conf->noproxies->elts;
     struct hostent hp;
+    struct apr_sockaddr_t *addr;
     int found = 0;
     int i;
 
@@ -563,11 +562,12 @@
        new->name = arg;
        /* Don't do name lookups on things that aren't dotted */
         if (ap_strchr_c(arg, '.') != NULL &&
-          ap_proxy_host2addr(new->name, &hp) == NULL)
-        /*@@@FIXME: This copies only the first of (possibly many) IP addrs */
-           memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
-       else
-           new->addr.s_addr = 0;
+           apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, 
parms->pool)) {
+           new->addr = addr;
+       }
+       else {
+           new->addr = NULL;
+       }
     }
     return NULL;
 }
diff -u3 -r --exclude=CVS 
../../../../pristine/httpd-proxy/module-2.0/mod_proxy.h proxy/mod_proxy.h
--- ../../../../pristine/httpd-proxy/module-2.0/mod_proxy.h     Fri Mar 23 
23:26:26 2001
+++ proxy/mod_proxy.h   Fri Mar 30 14:50:16 2001
@@ -163,12 +163,7 @@
 
 struct noproxy_entry {
     const char *name;
-    struct in_addr addr;
-};
-
-struct nocache_entry {
-    const char *name;
-    struct in_addr addr;
+    struct apr_sockaddr_t *addr;
 };
 
 typedef struct {
diff -u3 -r --exclude=CVS 
../../../../pristine/httpd-proxy/module-2.0/proxy_connect.c 
proxy/proxy_connect.c
--- ../../../../pristine/httpd-proxy/module-2.0/proxy_connect.c Fri Mar 23 
23:28:17 2001
+++ proxy/proxy_connect.c       Thu Mar 29 19:31:29 2001
@@ -143,10 +143,12 @@
     }
 
 /* check if ProxyBlock directive on this host */
-    destaddr.s_addr = ap_inet_addr(host);
+/* XXX FIXME */
+/*    destaddr.s_addr = ap_inet_addr(host); */
     for (i = 0; i < conf->noproxies->nelts; i++) {
        if ((npent[i].name != NULL && ap_strstr_c(host, npent[i].name) != NULL)
-           || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == 
'*')
+/*         || destaddr.s_addr == npent[i].addr.s_addr */
+           || npent[i].name[0] == '*')
            return ap_proxyerror(r, HTTP_FORBIDDEN,
                 "Connect to remote machine blocked");
     }
diff -u3 -r --exclude=CVS 
../../../../pristine/httpd-proxy/module-2.0/proxy_http.c proxy/proxy_http.c
--- ../../../../pristine/httpd-proxy/module-2.0/proxy_http.c    Mon Mar 26 
00:35:36 2001
+++ proxy/proxy_http.c  Fri Mar 30 17:59:35 2001
@@ -177,70 +177,63 @@
  * route.)
  */
 int ap_proxy_http_handler(request_rec *r, char *url,
-                      const char *proxyhost, int proxyport)
+                      const char *proxyname, int proxyport)
 {
-    apr_pool_t *p = r->pool;
-    char *desthost;
-    int destport = 0;
-    char *destportstr = NULL;
+    request_rec *rp;
+    apr_pool_t *p = r->connection->pool;
+    struct hostent *connecthost;
+    const char *connectname;
+    int connectport = 0;
+    apr_sockaddr_t *uri_addr;
+    apr_sockaddr_t *connect_addr;
     char server_portstr[32];
-    const char *uri = NULL;
     apr_socket_t *sock;
-    int i, len, backasswards;
+    int i, j, k, len, backasswards, close=0, failed=0;
     apr_status_t err;
     apr_array_header_t *headers_in_array;
     apr_table_entry_t *headers_in;
-    struct sockaddr_in server;
-    struct in_addr destaddr;
     char buffer[HUGE_STRING_LEN];
     char *response;
     char *buf;
     conn_rec *origin;
     apr_bucket *e;
     apr_bucket_brigade *bb = apr_brigade_create(p);
+    uri_components uri;
 
     void *sconf = r->server->module_config;
     proxy_server_conf *conf =
     (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
-    struct noproxy_entry *npent = (struct noproxy_entry *) 
conf->noproxies->elts;
 
-    memset(&server, '\0', sizeof(server));
-    server.sin_family = AF_INET;
 
-    /* We break the URL into host, port, uri */
-    {
-        const char *buf;
+    /*
+     * Step One: Determine Who To Connect To
+     *
+     * Break up the URL to determine the host to connect to
+     */
 
-        uri = strstr(url, "://");
-        if (uri == NULL)
-           return HTTP_BAD_REQUEST;
-        uri += 3;
-        destport = DEFAULT_HTTP_PORT;
-        buf = ap_strchr_c(uri, '/');
-        if (buf == NULL) {
-           desthost = apr_pstrdup(p, uri);
-           uri = "/";
-        }
-        else {
-           char *q = apr_palloc(p, buf - uri + 1);
-           memcpy(q, uri, buf - uri);
-           q[buf - uri] = '\0';
-           uri = buf;
-            desthost = q;
-        }
+    /* we break the URL into host, port, uri */
+    if (HTTP_OK != ap_parse_uri_components(p, url, &uri)) {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                     "proxy: URI %s cannot be parsed", url);
+       return HTTP_BAD_REQUEST;
     }
 
-    /* Get the port number - put it in destport and destportstr */
-    {
-        char *buf;
-        buf = ap_strchr(desthost, ':');
-        if (buf != NULL) {
-           *(buf++) = '\0';
-           if (apr_isdigit(*buf)) {
-               destport = atoi(buf);
-               destportstr = buf;
-           }
-        }
+    /* do a DNS lookup for the destination host */
+    err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 
0, p);
+
+    /* are we connecting directly, or via a proxy? */
+    if (proxyname) {
+       connectname = proxyname;
+       connectport = proxyport;
+        err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, 
proxyport, 0, p);
+    }
+    else {
+       connectname = 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 */
@@ -254,73 +247,192 @@
     }
 
     /* check if ProxyBlock directive on this host */
-    destaddr.s_addr = apr_inet_addr(desthost);
-    for (i = 0; i < conf->noproxies->nelts; i++) {
-       if ((npent[i].name != NULL
-            && ap_strstr_c(desthost, npent[i].name) != NULL)
-           || destaddr.s_addr == npent[i].addr.s_addr
-            || npent[i].name[0] == '*')
+    for (j = 0; j < conf->noproxies->nelts; j++) {
+        struct noproxy_entry *npent = (struct noproxy_entry *) 
conf->noproxies->elts;
+       struct apr_sockaddr_t *conf_addr = npent[j].addr;
+       if ((npent[j].name && ap_strstr_c(uri.hostname, npent[j].name))
+            || npent[j].name[0] == '*') {
            return ap_proxyerror(r, HTTP_FORBIDDEN,
-                                "Connect to remote machine blocked");
+                                "Connect to remote machine blocked (by name)");
+       }
+       while (conf_addr) {
+           while (uri_addr) {
+               char *conf_ip;
+               char *uri_ip;
+               apr_sockaddr_ip_get(&conf_ip, conf_addr);
+               apr_sockaddr_ip_get(&uri_ip, uri_addr);
+/*             ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, 
r->server,
+                            "Testing %s and %s", conf_ip, uri_ip); */
+               if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
+                   return ap_proxyerror(r, HTTP_FORBIDDEN,
+                                        "Connect to remote machine blocked (by 
IP address)");
+               }
+               uri_addr = uri_addr->next;
+           }
+           conf_addr = conf_addr->next;
+       }
     }
 
-    if ((apr_socket_create(&sock, APR_INET, SOCK_STREAM, p)) != APR_SUCCESS) {
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                      "proxy: error creating socket");
-        return HTTP_INTERNAL_SERVER_ERROR;
+
+    /*
+     * Step Two: Make the Connection
+     *
+     * 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) {
+       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                     "proxy: DNS lookup failure for %s", connectname);
+       return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+                             "DNS lookup failure for: ",
+                             connectname, NULL));
     }
+    else {
+
+       /* if a KeepAlive socket is already open, check whether it must stay
+        * open, or whether it should be closed and a new socket created.
+        */
+       if (r->connection->proxy) {
+           struct apr_sockaddr_t *remote_addr;
+           apr_port_t port;
+           if ((remote_addr = r->connection->proxy->remote_addr) &&
+               (APR_SUCCESS == apr_sockaddr_port_get(&port, remote_addr)) &&
+                (port == connectport) &&
+                
(!apr_strnatcasecmp(r->connection->proxy->remote_addr->hostname,connectname))) {
+               ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, 
r->server,
+                            "Keepalive addresses match!!! - keep original 
socket");
+            }
+           else {
+               ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, 
r->server,
+                            "Keepalive addresses do not match - close old 
socket (%s/%s, %d/%d)", connectname, 
r->connection->proxy->remote_addr->hostname, connectport, port);
+               apr_socket_close(r->connection->proxy->client_socket);
+               r->connection->proxy = NULL;
+            }
+       }
+
+       /* get a socket - either a keepalive one, or a new one */
+       if (r->connection->proxy) {
+
+           /* use previous keepalive socket */
+           origin = r->connection->proxy;
+           sock = origin->client_socket;
+           origin->keepalives++;
+
+        }
+        else {
+
+           /* create a new socket */
+           if ((apr_socket_create(&sock, APR_INET, SOCK_STREAM, p)) != 
APR_SUCCESS) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+                             "proxy: error creating socket");
+               return HTTP_INTERNAL_SERVER_ERROR;
+           }
 
 #if !defined(TPF) && !defined(BEOS)
-    if (conf->recv_buffer_size > 0 && apr_setsocketopt(sock, APR_SO_RCVBUF,
-       conf->recv_buffer_size)) {
-           ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
-                "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, 
using default");
-    }
+           if (conf->recv_buffer_size > 0 && apr_setsocketopt(sock, 
APR_SO_RCVBUF,
+               conf->recv_buffer_size)) {
+               ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+                             "setsockopt(SO_RCVBUF): Failed to set 
ProxyReceiveBufferSize, using default");
+           }
 #endif
 
-    if (proxyhost != NULL) {
-        err = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r);
-    }
-    else {
-        err = ap_proxy_doconnect(sock, (char *)desthost, destport, r);
-    }
+           /*
+            * 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
+            */
 
-    if (err != APR_SUCCESS) {
-       if (proxyhost != NULL)
-           return DECLINED;    /* try again another way */
-       else
-           return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
-                               "Could not connect to remote machine: ",
-                               desthost, NULL));
-    }
-
-    origin = ap_new_connection(p, r->server, sock, 0);
-    if (!origin) {
-        /* the peer reset the connection already; ap_new_connection() 
-         * closed the socket */
-        /* XXX somebody that knows what they're doing add an error path */
-       /* XXX how's this? */
-       return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
-                            "Connection reset by peer: ",
-                            desthost, NULL));
+
+            /* try each IP address until we connect successfully */
+           failed = 1;
+            while (connect_addr) {
+
+               /* make the connection out of the socket */
+               err = apr_connect(sock, connect_addr);
+
+               /* if an error occurred, loop round and try again */
+               if (err != APR_SUCCESS) {
+                   ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
+                                "proxy connect to %pI (%s) failed", 
connect_addr, connectname);
+                   connect_addr = connect_addr->next;
+                   continue;
+               }
+
+               /* the socket is now open, create a new connection */
+               origin = ap_new_connection(r->connection->pool, r->server, 
sock, 0);
+               r->connection->proxy = origin;
+               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,
+                                "an error occurred creating a new connection 
to %pI (%s)", connect_addr, connectname);
+                   connect_addr = connect_addr->next;
+                   continue;
+               }
+
+               /* we use keepalives unless later specified */
+               origin->keepalive = 1;
+               origin->keepalives = 1;
+
+               /* if we get here, all is well */
+               failed = 0;
+               break;
+           }
+
+           /* handle a permanent error from the above loop */
+           if (failed) {
+               if (proxyname) {
+                   return DECLINED;
+               }
+               else {
+                   return HTTP_BAD_GATEWAY;
+               }
+           }
+        }
     }
 
+
+    /*
+     * Step Three: Send the Request
+     *
+     * Send the HTTP/1.1 request to the remote server
+     */
+
     ap_add_output_filter("CORE", NULL, NULL, origin);
 
     /* 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");
     ap_proxy_clear_connection(p, r->headers_in);
+    if (close) {
+       apr_table_mergen(r->headers_in, "Connection", "close");
+       origin->keepalive = 0;
+    }
 
-    buf = apr_pstrcat(p, r->method, " ", proxyhost ? url : uri,
+    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 (destportstr != NULL && destport != DEFAULT_HTTP_PORT) {
-        buf = apr_pstrcat(p, "Host: ", desthost, ":", destportstr, 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: ", desthost, CRLF, NULL);
+        buf = apr_pstrcat(p, "Host: ", uri.hostname, CRLF, NULL);
         e = apr_bucket_pool_create(buf, strlen(buf), p);
         APR_BRIGADE_INSERT_TAIL(bb, e);
     }
@@ -425,11 +537,6 @@
 
     }
 
-    /* we don't yet support keepalives - but we will soon, I promise! */
-    buf = apr_pstrcat(p, "Connection: close", 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 */
     e = apr_bucket_pool_create(CRLF, strlen(CRLF), p);
     APR_BRIGADE_INSERT_TAIL(bb, e);
@@ -439,6 +546,7 @@
     ap_pass_brigade(origin->output_filters, bb);
 
     /* send the request data, if any. */
+    /* XXX FIXME: This doesn't handle large block sizes */
     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);
@@ -450,8 +558,17 @@
     APR_BRIGADE_INSERT_TAIL(bb, e);
     ap_pass_brigade(origin->output_filters, bb);
 
+
+    /*
+     * Step Four: Receive the Response
+     *
+     * Get response from the remote server, and pass it up the
+     * filter chain
+     */
+
     ap_add_input_filter("HTTP_IN", NULL, NULL, origin);
     ap_add_input_filter("CORE_IN", NULL, NULL, origin);
+//    ap_add_input_filter("DECHUNK", NULL, rp, origin);
 
     apr_brigade_destroy(bb);
     bb = apr_brigade_create(p);
@@ -463,13 +580,15 @@
     e = APR_BRIGADE_FIRST(bb);
     apr_bucket_read(e, (const char **)&response, &len, APR_BLOCK_READ);
     if (len == -1) {
+       r->connection->proxy = NULL;
        apr_socket_close(sock);
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
             "ap_get_brigade() - proxy receive - Error reading from remote 
server %s (length %d)",
-            proxyhost ? proxyhost : desthost, len);
+            connectname, len);
        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Error reading from remote server");
     } else if (len == 0) {
+       r->connection->proxy = NULL;
        apr_socket_close(sock);
        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                             "Document contains no data");
@@ -488,6 +607,7 @@
         /* If not an HTTP/1 message or if the status line was > 8192 bytes */
        if (response[5] != '1' || response[len - 1] != '\n') {
            apr_socket_close(sock);
+           r->connection->proxy = NULL;
            return HTTP_BAD_GATEWAY;
        }
        backasswards = 0;
@@ -508,11 +628,13 @@
            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
         {
            /* strip connection listed hop-by-hop headers from response */
            const char *buf;
+            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);
@@ -535,12 +657,19 @@
                                    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;
+        }
     }
     else {
         /* an http/0.9 response */
        backasswards = 1;
        r->status = 200;
        r->status_line = "200 OK";
+        close += 1;
     }
 
     /* munge the Location and URI response headers according to 
ProxyPassReverse */
@@ -563,21 +692,56 @@
         APR_BRIGADE_INSERT_TAIL(bb, e);
     }
 
+    /* get content-length */
+    {
+       const char *buf;
+       if ((buf = apr_table_get(r->headers_out, "Content-Length"))) {
+           origin->remain = atol(buf);
+       }
+       else {
+           origin->remain = -1;
+       }
+       if (close) {
+           origin->remain = -1;
+       }
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                 "proxy: start body send");
+
     /* send body */
-    /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
     if (!r->header_only) {
-        origin->remain = -1;
-        while (ap_get_brigade(origin->input_filters, bb, AP_MODE_BLOCKING) == 
APR_SUCCESS) {
-            if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
-                ap_pass_brigade(r->output_filters, bb);
-                break;
-            }
-            ap_pass_brigade(r->output_filters, bb);
-            apr_brigade_destroy(bb);
-            bb = apr_brigade_create(p);
-        }
+
+       /* if HTTP/1.0, or keepalives are off, read till EOF */
+       while (ap_get_brigade(origin->input_filters, bb, AP_MODE_BLOCKING) == 
APR_SUCCESS) {
+           if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
+               ap_pass_brigade(r->output_filters, bb);
+               break;
+           }
+           ap_pass_brigade(r->output_filters, bb);
+           apr_brigade_destroy(bb);
+           bb = apr_brigade_create(p);
+       }
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                 "proxy: end body send");
+
+
+    /*
+     * Step Five: Clean Up
+     *
+     * 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 (close) {
+        apr_socket_close(sock);
+        r->connection->proxy = NULL;
     }
 
-    apr_socket_close(sock);
     return OK;
 }

Reply via email to