You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by pq...@apache.org on 2005/12/30 21:59:32 UTC

svn commit: r360164 - /httpd/httpd/branches/fcgi-proxy-dev/modules/proxy/mod_proxy_fcgi.c

Author: pquerna
Date: Fri Dec 30 12:59:30 2005
New Revision: 360164

URL: http://svn.apache.org/viewcvs?rev=360164&view=rev
Log:
Handle reading fastcgi records with content length larger than AP_IOBUFSIZE.

* modules/proxy/mod_proxy_fcgi.c
  (proxy_fcgi_baton_t): New struct, holds per-connection data.
  (dispatch): Set buckets aside into the scratch pool in the baton,
   clearing it when we pass the baton on.  Deal with the case where
   the content length is larger than AP_IOBUFSIZE.  Consistently use
   sizeof when referring to the length of buffers.  Explicitly null
   terminate the read buffer after reading.  Read the padding bytes
   in a second pass to simplify logic.
  (proxy_fcgi_handler): Create our baton and stash it in the connection's
   data member.

Submitted By: Garrett Rooney <rooneg apache.org>

Modified:
    httpd/httpd/branches/fcgi-proxy-dev/modules/proxy/mod_proxy_fcgi.c

Modified: httpd/httpd/branches/fcgi-proxy-dev/modules/proxy/mod_proxy_fcgi.c
URL: http://svn.apache.org/viewcvs/httpd/httpd/branches/fcgi-proxy-dev/modules/proxy/mod_proxy_fcgi.c?rev=360164&r1=360163&r2=360164&view=diff
==============================================================================
--- httpd/httpd/branches/fcgi-proxy-dev/modules/proxy/mod_proxy_fcgi.c (original)
+++ httpd/httpd/branches/fcgi-proxy-dev/modules/proxy/mod_proxy_fcgi.c Fri Dec 30 12:59:30 2005
@@ -351,11 +351,16 @@
     return 0;
 }
 
+typedef struct {
+    apr_pool_t *scratch_pool;
+} proxy_fcgi_baton_t;
+
 static apr_status_t dispatch(proxy_conn_rec *conn, request_rec *r,
                              int request_id)
 {
     apr_bucket_brigade *ib, *ob;
     int seen_end_of_headers = 0, done = 0;
+    proxy_fcgi_baton_t *pfb = conn->data;
     apr_status_t rv = APR_SUCCESS;
     conn_rec *c = r->connection;
     struct iovec vec[2];
@@ -388,7 +393,7 @@
 
             rv = ap_get_brigade(r->input_filters, ib,
                                 AP_MODE_READBYTES, APR_BLOCK_READ,
-                                AP_IOBUFSIZE);
+                                sizeof(writebuf));
             if (rv != APR_SUCCESS) {
                 break;
             }
@@ -496,33 +501,29 @@
             /* Clear out the header so our buffer is zeroed out again */
             memset(readbuf, 0, 8);
 
-            /* XXX We need support for content length > buffer size, but for
-             *     now just punt. */
-            if ((clen + plen) > sizeof(readbuf) - 1) {
-                ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
-                             "proxy: FCGI: back end server send more data "
-                             "than fits in buffer");
-                rv = APR_EINVAL;
-                break;
+recv_again:
+            if (clen > sizeof(readbuf) - 1) {
+                readbuflen = sizeof(readbuf) - 1;
+            } else {
+                readbuflen = clen;
             }
 
             /* Now get the actual data.  Yes it sucks to do this in a second
              * recv call, this will eventually change when we move to real
              * nonblocking recv calls. */
-            if ((clen + plen) != 0) {
-                readbuflen = clen + plen;
-
+            if (readbuflen != 0) {
                 rv = apr_socket_recv(conn->sock, readbuf, &readbuflen);
                 if (rv != APR_SUCCESS) {
                     break;
                 }
+                readbuf[readbuflen] = 0;
             }
 
             switch (type) {
             case FCGI_STDOUT:
                 if (clen != 0) {
                     b = apr_bucket_transient_create(readbuf,
-                                                    clen,
+                                                    readbuflen,
                                                     c->bucket_alloc);
 
                     APR_BRIGADE_INSERT_TAIL(ob, b);
@@ -548,10 +549,28 @@
                         }
 
                         apr_brigade_cleanup(ob);
+
+                        apr_pool_clear(pfb->scratch_pool);
                     } else {
                         /* We're still looking for the end of the headers,
                          * so this part of the data will need to persist. */
-                        apr_bucket_setaside(b, r->pool);
+                        apr_bucket_setaside(b, pfb->scratch_pool);
+                    }
+
+                    /* If we didn't read all the data go back and get the
+                     * rest of it. */
+                    if (clen > readbuflen) {
+                        clen -= readbuflen;
+                        goto recv_again;
+                    }
+
+                    if (plen) {
+                        readbuflen = plen;
+
+                        rv = apr_socket_recv(conn->sock, readbuf, &readbuflen);
+                        if (rv != APR_SUCCESS) {
+                            break;
+                        }
                     }
                 } else {
                     b = apr_bucket_eos_create(c->bucket_alloc);
@@ -698,6 +717,14 @@
                 ap_proxy_release_connection(scheme, backend, r->server);
             }
             return status;
+        }
+
+        {
+            proxy_fcgi_baton_t *pfb = apr_pcalloc(r->pool, sizeof(*pfb));
+
+            apr_pool_create(&pfb->scratch_pool, r->pool);
+
+            backend->data = pfb;
         }
     }