]> granicus.if.org Git - apache/commitdiff
Handle reading fastcgi records with content length larger than AP_IOBUFSIZE.
authorPaul Querna <pquerna@apache.org>
Fri, 30 Dec 2005 20:59:30 +0000 (20:59 +0000)
committerPaul Querna <pquerna@apache.org>
Fri, 30 Dec 2005 20:59:30 +0000 (20:59 +0000)
* 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>

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/fcgi-proxy-dev@360164 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy_fcgi.c

index 48c66ed433c72d9945146b871e59c0c4bb956cd8..b34e058ad10f07596da4439200ef1a7dad6a8ad8 100644 (file)
@@ -351,11 +351,16 @@ static int handle_headers(request_rec *r,
     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 @@ static apr_status_t dispatch(proxy_conn_rec *conn, request_rec *r,
 
             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 @@ static apr_status_t dispatch(proxy_conn_rec *conn, request_rec *r,
             /* 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 @@ static apr_status_t dispatch(proxy_conn_rec *conn, request_rec *r,
                         }
 
                         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);
@@ -699,6 +718,14 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker,
             }
             return status;
         }
+
+        {
+            proxy_fcgi_baton_t *pfb = apr_pcalloc(r->pool, sizeof(*pfb));
+
+            apr_pool_create(&pfb->scratch_pool, r->pool);
+
+            backend->data = pfb;
+        }
     }
 
     backend->is_ssl = 0;