httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Justin Erenkrantz <jerenkra...@ebuilt.com>
Subject [PATCH] Take 2 of the http filter rewrite
Date Mon, 24 Sep 2001 01:58:19 GMT
Take two.

As Greg suggested, this merges the dechunk and core filters back
to one filter.  (This makes the diff in http_protocol.c a bit
gnarly.)

Other significant changes is that the HTTP_IN (ap_http_filter) is
now a request-level filter rather than a connection-level filter.
This makes a lot more sense to me.

This passes all of the tests in httpd-test (not to say that this
is perfect or anything).  There is a patch at the bottom for 
mod_input_body_filter.c in httpd-test that is required.  (It was 
expecting > readbytes to be read when asking for readbytes).

Comments and feedback?  -- justin

Index: buckets/apr_brigade.c
===================================================================
RCS file: /home/cvs/apr-util/buckets/apr_brigade.c,v
retrieving revision 1.25
diff -u -r1.25 apr_brigade.c
--- buckets/apr_brigade.c	2001/09/03 22:00:36	1.25
+++ buckets/apr_brigade.c	2001/09/24 01:48:04
@@ -221,6 +221,28 @@
     return APR_SUCCESS;
 }
 
+APU_DECLARE(apr_status_t) apr_brigade_to_buffer(apr_bucket_brigade *b, char *c,
+                                                apr_read_type_e mode)
+{
+    apr_bucket *e;
+    char *cur;
+    apr_size_t curlen;
+    apr_status_t status;
+
+    APR_BRIGADE_FOREACH(e, b) {
+
+        status = apr_bucket_read(e, (const char **)&cur, &curlen, mode);
+
+        if (status != APR_SUCCESS)
+            return status;
+        
+        memcpy(c, cur, curlen);
+        c += curlen;
+    }
+
+    return APR_SUCCESS;
+}
+
 APU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, 
                                                struct iovec *vec, int *nvec)
 {
Index: buckets/apr_buckets_pipe.c
===================================================================
RCS file: /home/cvs/apr-util/buckets/apr_buckets_pipe.c,v
retrieving revision 1.41
diff -u -r1.41 apr_buckets_pipe.c
--- buckets/apr_buckets_pipe.c	2001/09/22 22:36:07	1.41
+++ buckets/apr_buckets_pipe.c	2001/09/24 01:48:04
@@ -110,10 +110,6 @@
         *str = a->data;
         if (rv == APR_EOF) {
             apr_file_close(p);
-            if (block == APR_NONBLOCK_READ) {
-                /* XXX: this is bogus, should return APR_SUCCESS */
-                return APR_EOF;
-            }
         }
     }
     return APR_SUCCESS;
Index: buckets/apr_buckets_socket.c
===================================================================
RCS file: /home/cvs/apr-util/buckets/apr_buckets_socket.c,v
retrieving revision 1.30
diff -u -r1.30 apr_buckets_socket.c
--- buckets/apr_buckets_socket.c	2001/09/22 22:36:07	1.30
+++ buckets/apr_buckets_socket.c	2001/09/24 01:48:04
@@ -111,10 +111,6 @@
         free(buf);
         a = apr_bucket_immortal_make(a, "", 0);
         *str = a->data;
-        if (rv == APR_EOF && block == APR_NONBLOCK_READ) {
-            /* XXX: this is bogus... should return APR_SUCCESS */
-            return APR_EOF;
-        }
     }
     return APR_SUCCESS;
 }
Index: include/apr_buckets.h
===================================================================
RCS file: /home/cvs/apr-util/include/apr_buckets.h,v
retrieving revision 1.119
diff -u -r1.119 apr_buckets.h
--- include/apr_buckets.h	2001/09/24 01:47:10	1.119
+++ include/apr_buckets.h	2001/09/24 01:48:04
@@ -689,6 +689,17 @@
                                              apr_off_t *length);
 
 /**
+ * create a flat buffer of the elements in a bucket_brigade.
+ * @param b The bucket brigade to create the buffer from
+ * @param c The pointer to the returned character string
+ * @param mode Should we block when reading the buckets
+ * Note: You *must* have enough space allocated to store all of the data.
+ * See apr_brigade_length().
+ */
+APU_DECLARE(apr_status_t) apr_brigade_to_buffer(apr_bucket_brigade *b, char *c,
+                                                apr_read_type_e mode);
+
+/**
  * create an iovec of the elements in a bucket_brigade... return number 
  * of elements used.  This is useful for writing to a file or to the
  * network efficiently.

Index: server/core.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/core.c,v
retrieving revision 1.61
diff -u -r1.61 core.c
--- server/core.c	2001/09/19 05:52:42	1.61
+++ server/core.c	2001/09/24 01:45:18
@@ -2757,19 +2757,9 @@
 {
     apr_bucket *e;
 
-    if (!f->ctx) {    /* If we haven't passed up the socket yet... */
-        f->ctx = (void *)1;
-        e = apr_bucket_socket_create(f->c->client_socket);
-        APR_BRIGADE_INSERT_TAIL(b, e);
-        return APR_SUCCESS;
-    }
-    else {            
-        /* Either some code lost track of the socket
-         * bucket or we already found out that the
-         * client closed.
-         */
-        return APR_EOF;
-    }
+    e = apr_bucket_socket_create(f->c->client_socket);
+    APR_BRIGADE_INSERT_TAIL(b, e);
+    return APR_SUCCESS;
 }
 
 /* Default filter.  This filter should almost always be used.  Its only job
Index: server/protocol.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/protocol.c,v
retrieving revision 1.45
diff -u -r1.45 protocol.c
--- server/protocol.c	2001/09/18 22:13:57	1.45
+++ server/protocol.c	2001/09/24 01:45:18
@@ -219,7 +219,7 @@
     while (1) {
         if (APR_BRIGADE_EMPTY(b)) {
             apr_off_t zero = 0;
-            if ((retval = ap_get_brigade(c->input_filters, b,
+            if ((retval = ap_get_brigade(r->input_filters, b,
                                          AP_MODE_BLOCKING,
                                          &zero /* readline */)) != APR_SUCCESS ||
                 APR_BRIGADE_EMPTY(b)) {
@@ -562,6 +562,9 @@
     r->notes           = apr_table_make(r->pool, 5);
 
     r->request_config  = ap_create_request_config(r->pool);
+    /* Must be set before we run create request hook */
+    r->output_filters  = conn->output_filters;
+    r->input_filters   = conn->input_filters;
     ap_run_create_request(r);
     r->per_dir_config  = r->server->lookup_defaults;
 
@@ -572,8 +575,6 @@
 
     r->status          = HTTP_REQUEST_TIME_OUT;  /* Until we get a request */
     r->the_request     = NULL;
-    r->output_filters  = conn->output_filters;
-    r->input_filters   = conn->input_filters;
 
     apr_setsocketopt(conn->client_socket, APR_SO_TIMEOUT, 
                      (int)(keptalive
Index: modules/http/http_core.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/http/http_core.c,v
retrieving revision 1.282
diff -u -r1.282 http_core.c
--- modules/http/http_core.c	2001/08/25 23:43:18	1.282
+++ modules/http/http_core.c	2001/09/24 01:45:18
@@ -262,7 +262,6 @@
 
 static int ap_pre_http_connection(conn_rec *c)
 {
-    ap_add_input_filter("HTTP_IN", NULL, NULL, c);
     ap_add_input_filter("CORE_IN", NULL, NULL, c);
     ap_add_output_filter("CORE", NULL, NULL, c);
     return OK;
@@ -302,6 +301,15 @@
     return OK;
 }
 
+static int ap_http_create_req(request_rec *r)
+{
+    if (!r->main)
+    {
+        ap_add_input_filter("HTTP_IN", NULL, r, r->connection);
+    }
+    return OK;
+}
+
 static void ap_http_insert_filter(request_rec *r)
 {
     if (!r->main) {
@@ -320,10 +328,10 @@
     ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
     ap_hook_http_method(http_method,NULL,NULL,APR_HOOK_REALLY_LAST);
     ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
+    ap_hook_create_request(ap_http_create_req, NULL, NULL, APR_HOOK_MIDDLE);
 
     ap_hook_insert_filter(ap_http_insert_filter, NULL, NULL, APR_HOOK_REALLY_LAST);
     ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION);
-    ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE);
     ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, 
                               AP_FTYPE_HTTP_HEADER);
     ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
Index: modules/http/http_protocol.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/http/http_protocol.c,v
retrieving revision 1.362
diff -u -r1.362 http_protocol.c
--- modules/http/http_protocol.c	2001/09/17 13:12:37	1.362
+++ modules/http/http_protocol.c	2001/09/24 01:45:18
@@ -481,125 +481,115 @@
     return AP_HTTP_METHODS[methnum];
 }
 
-struct dechunk_ctx {
-    apr_size_t chunk_size;
-    apr_size_t bytes_delivered;
+static long get_chunk_size(char *);
+
+typedef struct http_filter_ctx {
+    apr_bucket_brigade *b;
+    int status;
+    apr_size_t remaining;
     enum {
-        WANT_HDR /* must have value zero */,
-        WANT_BODY,
-        WANT_TRL
+        BODY_NONE   /* must have value of zero */,
+        BODY_LENGTH,
+        BODY_CHUNK
     } state;
-};
-
-static long get_chunk_size(char *);
+} http_ctx_t;
 
-apr_status_t ap_dechunk_filter(ap_filter_t *f, apr_bucket_brigade *bb,
-                               ap_input_mode_t mode, apr_off_t *readbytes)
+/* Hi, I'm the main input filter for HTTP requests. 
+ * I handle chunked and content-length bodies. */
+apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode,
apr_off_t *readbytes)
 {
-    apr_status_t rv;
-    struct dechunk_ctx *ctx = f->ctx;
-    apr_bucket *b;
-    const char *buf;
+    apr_bucket *e;
+    char *buff;
     apr_size_t len;
+    char *pos;
+    http_ctx_t *ctx = f->ctx;
+    apr_status_t rv;
 
     if (!ctx) {
-        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(struct dechunk_ctx));
+        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
+        ctx->b = apr_brigade_create(f->r->pool);
+        ctx->status = f->r->status;
+    
+        /* Due to the way the core is designed, this should happen each time
+         * we get initialized. */
+        if ((rv = ap_get_brigade(f->next, ctx->b, mode, 
+                                 readbytes)) != APR_SUCCESS) {
+            return rv;
+        }
     }
 
-    do {
-        if (ctx->chunk_size == ctx->bytes_delivered) {
-            /* Time to read another chunk header or trailer...  ap_http_filter() is 
-             * the next filter in line and it knows how to return a brigade with 
-             * one line.
-             */
-            char line[30];
+    /* Basically, we have to stay out of the way until server/protocol.c
+     * says it is okay - which it does by setting r->status to OK. */
+    if (f->r->status != ctx->status)
+    {
+        int old_status;
+        /* Allow us to be reentrant! */
+        old_status = ctx->status;
+        ctx->status = f->r->status;
+
+        if (old_status == HTTP_REQUEST_TIME_OUT && f->r->status == HTTP_OK)
+        {
+            const char *tenc, *lenp;
+            tenc = apr_table_get(f->r->headers_in, "Transfer-Encoding");
+            lenp = apr_table_get(f->r->headers_in, "Content-Length");
+
+            if (tenc) {
+                if (!strcasecmp(tenc, "chunked")) {
+                    char line[30];
             
-            if ((rv = ap_getline(line, sizeof(line), f->r,
-                                 0 /* readline */)) < 0) {
-                return rv;
-            }
-            switch(ctx->state) {
-            case WANT_HDR:
-                ctx->chunk_size = get_chunk_size(line);
-                ctx->bytes_delivered = 0;
-                if (ctx->chunk_size == 0) {
-                    ctx->state = WANT_TRL;
+                    if ((rv = ap_getline(line, sizeof(line), f->r, 0)) < 0) {
+                        return rv;
+                    }
+                    ctx->state = BODY_CHUNK;
+                    ctx->remaining = get_chunk_size(line);
                 }
-                else {
-                    ctx->state = WANT_BODY;
-                }
-                break;
-            case WANT_TRL:
-                /* XXX sanity check end chunk here */
-                if (strlen(line)) {
-                    /* bad trailer */
-                }
-                if (ctx->chunk_size == 0) { /* we just finished the last chunk? */
-                    /* ### woah... ap_http_filter() is doing this, too */
-                    /* append eos bucket and get out */
-                    b = apr_bucket_eos_create();
-                    APR_BRIGADE_INSERT_TAIL(bb, b);
-                    return APR_SUCCESS;
-                }
-                ctx->state = WANT_HDR;
-                break;
-            default:
-                ap_assert(ctx->state == WANT_HDR || ctx->state == WANT_TRL);
             }
-        }
-    } while (ctx->state != WANT_BODY);
+            else if (lenp) {
+                const char *pos = lenp;
 
-    if (ctx->state == WANT_BODY) {
-        /* Tell ap_http_filter() how many bytes to deliver. */
-        apr_off_t chunk_bytes = ctx->chunk_size - ctx->bytes_delivered;
-
-        if ((rv = ap_get_brigade(f->next, bb, mode,
-                                 &chunk_bytes)) != APR_SUCCESS) {
-            return rv;
-        }
-
-        /* Walk through the body, accounting for bytes, and removing an eos
-         * bucket if ap_http_filter() delivered the entire chunk.
-         *
-         * ### this shouldn't be necessary. 1) ap_http_filter shouldn't be
-         * ### adding EOS buckets. 2) it shouldn't return more bytes than
-         * ### we requested, therefore the total len can be found with a
-         * ### simple call to apr_brigade_length(). no further munging
-         * ### would be needed.
-         */
-        b = APR_BRIGADE_FIRST(bb);
-        while (b != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(b)) {
-            apr_bucket_read(b, &buf, &len, mode);
-            AP_DEBUG_ASSERT(len <= ctx->chunk_size - ctx->bytes_delivered);
-            ctx->bytes_delivered += len;
-            b = APR_BUCKET_NEXT(b);
-        }
-        if (ctx->bytes_delivered == ctx->chunk_size) {
-            AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(b));
-            apr_bucket_delete(b);
-            ctx->state = WANT_TRL;
+                while (apr_isdigit(*pos) || apr_isspace(*pos))
+                    ++pos;
+                if (*pos == '\0') {
+                    ctx->state = BODY_LENGTH;
+                    ctx->remaining = atol(lenp);
+                }
+            }
         }
     }
 
-    return APR_SUCCESS;
-}
+    if (!ctx->remaining && ctx->state)
+    {
+        if (ctx->state == BODY_LENGTH)
+        {
+            e = apr_bucket_eos_create();
+            APR_BRIGADE_INSERT_TAIL(b, e);
+            return APR_SUCCESS;
+        }
+        else if (ctx->state == BODY_CHUNK)
+        {
+            char line[30];
+        
+            ctx->state = BODY_NONE;
 
-typedef struct http_filter_ctx {
-    apr_bucket_brigade *b;
-} http_ctx_t;
+            /* We need to read the CRLF after the chunk.  */
+            if ((rv = ap_getline(line, sizeof(line), f->r, 0)) < 0) {
+                return rv;
+            }
 
-apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode,
apr_off_t *readbytes)
-{
-    apr_bucket *e;
-    char *buff;
-    apr_size_t len;
-    char *pos;
-    http_ctx_t *ctx = f->ctx;
-    apr_status_t rv;
+            /* Read the real chunk line. */
+            if ((rv = ap_getline(line, sizeof(line), f->r, 0)) < 0) {
+                return rv;
+            }
+            ctx->state = BODY_CHUNK;
+            ctx->remaining = get_chunk_size(line);
 
-    if (!ctx) {
-        f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
-        ctx->b = apr_brigade_create(f->c->pool);
+            if (!ctx->remaining)
+            {
+                e = apr_bucket_eos_create();
+                APR_BRIGADE_INSERT_TAIL(b, e);
+                return APR_SUCCESS;
+            }
+        }
     }
 
     if (mode == AP_MODE_PEEK) {
@@ -640,12 +630,6 @@
         }
     }
 
-    if (APR_BRIGADE_EMPTY(ctx->b)) {
-        if ((rv = ap_get_brigade(f->next, ctx->b, mode, readbytes)) != APR_SUCCESS)
{
-            return rv;
-        }
-    }
-
     /* If readbytes is -1, we want to just read everything until the end
      * of the brigade, which in this case means the end of the socket.  To
      * do this, we loop through the entire brigade, until the socket is
@@ -655,14 +639,21 @@
     if (*readbytes == -1) {
         apr_bucket *e;
         apr_off_t total;
+        const char *str;
+        apr_size_t len;
         APR_BRIGADE_FOREACH(e, ctx->b) {
-            const char *str;
-            apr_size_t len;
+            /* We don't care about these values.  We just want to force the
+             * lower level to just read it. */
             apr_bucket_read(e, &str, &len, APR_BLOCK_READ);
         }
         APR_BRIGADE_CONCAT(b, ctx->b);
+
+        /* Force a recompute of the length */
         apr_brigade_length(b, 1, &total);
         *readbytes = total;
+        /* This had better be equal to zero now! */
+        if (ctx->status)
+            ctx->remaining -= total;
         e = apr_bucket_eos_create();
         APR_BRIGADE_INSERT_TAIL(b, e);
         return APR_SUCCESS;
@@ -670,56 +661,28 @@
     /* readbytes == 0 is "read a single line". otherwise, read a block. */
     if (*readbytes) {
         apr_off_t total;
+        apr_bucket *e;
+        apr_bucket_brigade *newbb;
 
-        /* ### the code below, which moves bytes from one brigade to the
-           ### other is probably bogus. presuming the next filter down was
-           ### working properly, it should not have returned more than
-           ### READBYTES bytes, and we wouldn't have to do any work.
-        */
-
-        APR_BRIGADE_NORMALIZE(ctx->b);
-        if (APR_BRIGADE_EMPTY(ctx->b)) {
-            if ((rv = ap_get_brigade(f->next, ctx->b, mode, readbytes)) != APR_SUCCESS)
{
-                return rv;
-            }
-        }
-            
+        newbb = NULL;
+
         apr_brigade_partition(ctx->b, *readbytes, &e);
-        APR_BRIGADE_CONCAT(b, ctx->b);
+        /* Must do split before CONCAT */
         if (e != APR_BRIGADE_SENTINEL(ctx->b)) {
-            apr_bucket_brigade *temp;
+            newbb = apr_brigade_split(ctx->b, e);
+        }
+        APR_BRIGADE_CONCAT(b, ctx->b);
 
-            temp = apr_brigade_split(b, e);
+        /* FIXME: Is this really needed?  Due to pointer use in sentinels,
+         * I think so. */
+        if (newbb)
+            APR_BRIGADE_CONCAT(ctx->b, newbb);
 
-            /* ### darn. gotta ensure the split brigade is in the proper pool.
-               ### this is a band-aid solution; we shouldn't even be doing
-               ### all of this brigade munging (per the comment above).
-               ### until then, this will get the right lifetimes. */
-            APR_BRIGADE_CONCAT(ctx->b, temp);
-        }
-        else {
-            if (!APR_BRIGADE_EMPTY(ctx->b)) {
-                ctx->b = NULL; /*XXX*/
-            }
-        }
         apr_brigade_length(b, 1, &total);
-        *readbytes -= total;
+        *readbytes = total;
+        if (ctx->status)
+            ctx->remaining -= total;
 
-        /* ### this is a hack. it is saying, "if we have read everything
-           ### that was requested, then we are at the end of the request."
-           ### it presumes that the next filter up will *only* call us
-           ### with readbytes set to the Content-Length of the request.
-           ### that may not always be true, and this code is *definitely*
-           ### too presumptive of the caller's intent. the point is: this
-           ### filter is not the guy that is parsing the headers or the
-           ### chunks to determine where the end of the request is, so we
-           ### shouldn't be monkeying with EOS buckets.
-        */
-        if (*readbytes == 0) {
-            apr_bucket *eos = apr_bucket_eos_create();
-                
-            APR_BRIGADE_INSERT_TAIL(b, eos);
-        }
         return APR_SUCCESS;
     }
 
@@ -731,14 +694,19 @@
         }
 
         pos = memchr(buff, APR_ASCII_LF, len);
+        /* We found a match. */
         if (pos != NULL) {
             apr_bucket_split(e, pos - buff + 1);
+            if (ctx->status)
+                ctx->remaining -= pos - buff + 1;
             APR_BUCKET_REMOVE(e);
             APR_BRIGADE_INSERT_TAIL(b, e);
             return APR_SUCCESS;
         }
         APR_BUCKET_REMOVE(e);
         APR_BRIGADE_INSERT_TAIL(b, e);
+        if (ctx->status)
+            ctx->remaining -= len;
     }
     return APR_SUCCESS;
 }
@@ -1406,7 +1374,6 @@
         }
 
         r->read_chunked = 1;
-        ap_add_input_filter("DECHUNK", NULL, r, r->connection);
     }
     else if (lenp) {
         const char *pos = lenp;
@@ -1517,14 +1484,12 @@
  */
 AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz)
 {
-    apr_size_t len_read, total;
-    apr_status_t rv;
-    apr_bucket *b, *old;
-    const char *tempbuf;
+    apr_off_t len;
+    apr_bucket *b;
     core_request_config *req_cfg =
 	(core_request_config *)ap_get_module_config(r->request_config,
                                                     &core_module);
-    apr_bucket_brigade *bb = req_cfg->bb;
+    apr_bucket_brigade *bb = req_cfg->bb, *newbb;
 
     do {
         if (APR_BRIGADE_EMPTY(bb)) {
@@ -1546,41 +1511,34 @@
         return 0;
     }
 
-    /* ### it would be nice to replace the code below with "consume N bytes
-       ### from this brigade, placing them into that buffer." there are
-       ### other places where we do the same...
-       ###
-       ### alternatively, we could partition the brigade, then call a
-       ### function which serializes a given brigade into a buffer. that
-       ### semantic is used elsewhere, too...
-    */
-
-    total = 0;
-    while (total < bufsiz
-           && b != APR_BRIGADE_SENTINEL(bb)
-           && !APR_BUCKET_IS_EOS(b)) {
-
-        if ((rv = apr_bucket_read(b, &tempbuf, &len_read, APR_BLOCK_READ)) != APR_SUCCESS)
{
-            return -1;
-        }
-        if (total + len_read > bufsiz) {
-            apr_bucket_split(b, bufsiz - total);
-            len_read = bufsiz - total;
-        }
-        memcpy(buffer, tempbuf, len_read);
-        buffer += len_read;
-        total += len_read;
-        /* XXX the next two fields shouldn't be mucked with here, as they are in terms
-         * of bytes in the unfiltered body; gotta see if anybody else actually uses 
-         * these
-         */
-        r->read_length += len_read;      /* XXX yank me? */
-        old = b;
-        b = APR_BUCKET_NEXT(b);
-        apr_bucket_delete(old);
-    }
+    /* 1) Determine length to see if we may overrun. 
+     * 2) Partition the brigade at the appropriate point.
+     * 3) Split the brigade at the new partition.
+     * 4) Read the old brigade into the buffer.
+     * 5) Destroy the old brigade.
+     * 6) Point the context at the new brigade.
+     */
+    apr_brigade_length(bb, 1, &len);
+
+    if (bufsiz < len)
+        len = bufsiz;
+
+    r->read_length += len;
+
+    if (apr_brigade_partition(bb, len, &b) != APR_SUCCESS)
+        return -1;
+
+    newbb = apr_brigade_split(bb, b);
+
+    if (apr_brigade_to_buffer(bb, buffer, APR_BLOCK_READ) != APR_SUCCESS)
+        return -1;
+
+    if (apr_brigade_destroy(bb) != APR_SUCCESS)
+        return -1;
+
+    req_cfg->bb = newbb;
 
-    return total;
+    return len;
 }
 
 /* In HTTP/1.1, any method can have a body.  However, most GET handlers

Index: perl-framework/c-modules/input_body_filter/mod_input_body_filter.c
===================================================================
RCS file: /home/cvs/httpd-test/perl-framework/c-modules/input_body_filter/mod_input_body_filter.c,v
retrieving revision 1.4
diff -u -r1.4 mod_input_body_filter.c
--- perl-framework/c-modules/input_body_filter/mod_input_body_filter.c	2001/09/08 22:07:14
1.4
+++ perl-framework/c-modules/input_body_filter/mod_input_body_filter.c	2001/09/24 01:53:15
@@ -76,25 +76,43 @@
     }
 }
 
+typedef struct input_body_ctx_t {
+    apr_bucket_brigade *b;
+} input_body_ctx_t;
+
 static int input_body_filter_handler(ap_filter_t *f, apr_bucket_brigade *bb, 
                                      ap_input_mode_t mode, apr_off_t *readbytes)
 {
     apr_status_t rv;
     apr_pool_t *p = f->r->pool;
+    input_body_ctx_t *ctx = f->ctx;
 
-    if (APR_BRIGADE_EMPTY(bb)) {
-        rv = ap_get_brigade(f->next, bb, mode, readbytes);
-        if (rv != APR_SUCCESS) {
+    if (!ctx) {
+        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
+        ctx->b = apr_brigade_create(f->r->pool);
+    }
+
+    if (APR_BRIGADE_EMPTY(ctx->b))
+    {
+        if ((rv = ap_get_brigade(f->next, ctx->b, mode,
+                                 readbytes)) != APR_SUCCESS) {
             return rv;
         }
     }
 
-    while (!APR_BRIGADE_EMPTY(bb)) {
+    while (!APR_BRIGADE_EMPTY(ctx->b)) {
         const char *data;
         apr_size_t len;
         apr_bucket *bucket;
 
-        bucket = APR_BRIGADE_FIRST(bb);
+        bucket = APR_BRIGADE_FIRST(ctx->b);
+
+        if (APR_BUCKET_IS_EOS(bucket)) {
+            APR_BUCKET_REMOVE(bucket);
+            APR_BRIGADE_INSERT_TAIL(bb, bucket);
+            break;
+        }
+
         rv = apr_bucket_read(bucket, &data, &len, mode);
 
         if (rv != APR_SUCCESS) {
@@ -110,10 +128,6 @@
         }
 
         APR_BRIGADE_INSERT_TAIL(bb, bucket);
-
-        if (APR_BUCKET_IS_EOS(bucket)) {
-            break;
-        }
     }
 
     return OK;


Mime
View raw message