On 01/05/2008 12:27 PM, Nick Kew wrote:
> On Sat, 05 Jan 2008 12:11:07 +0100
> Ruediger Pluem <[EMAIL PROTECTED]> wrote:
> 
>>>> Can you please try if the following patch against the vanilla tar
>>>> ball fixes the problem?
>>> Nope.  Causes both test cases to give just one byte of response.
>> Sorry my first patch was bogus of course :-(. Please try the
>> following:
> 
> Back to square one, with 433 bytes of response.
> 
> (FWIW, I already tried moving the cleanup last night).
> 

Ok, next round. I think that I ironed out various edge cases. One remains
(see XXX in get_chunk_line) but I guess this one could be addressed later.
So can you please test 2.2.7 vanilla + attached patch?

Regards

RĂ¼diger

Index: modules/http/http_filters.c
===================================================================
--- modules/http/http_filters.c	(Revision 609114)
+++ modules/http/http_filters.c	(Arbeitskopie)
@@ -68,8 +68,43 @@
         BODY_CHUNK_PART
     } state;
     int eos_sent;
+    char chunk_ln[30];
+    char *pos;
 } http_ctx_t;
 
+static apr_status_t get_chunk_line(http_ctx_t *ctx, int len)
+{
+    /*
+     * Check if we do not overflow our chunksize / empty line buffer
+     * (ctx->chunk_ln). If we do the chunksize / empty line is bogus anyway so
+     * bail out in this case.
+     * XXX: Currently we are very limited in accepting chunk-extensions. If
+     * this is needed the chunk_ln buffer must be much larger or we must
+     * find a different way to discard them as we do not process them anyway.
+     */
+    if ((ctx->pos - ctx->chunk_ln) + len < sizeof(ctx->chunk_ln)) {
+        ctx->pos += len;
+        *(ctx->pos) = '\0';
+        /*
+         * Check if we really got a full line. If yes the
+         * last char in the just read buffer must be LF.
+         * If not advance the buffer and return APR_EAGAIN.
+         * We do not start processing until we have the
+         * full line.
+         */
+        if (ctx->pos[-1] != APR_ASCII_LF) {
+            return APR_EAGAIN;
+        }
+        /*
+         * Line is complete. So reset ctx->pos for next round.
+         */
+        ctx->pos = ctx->chunk_ln;
+        return APR_SUCCESS;
+    }
+    return APR_ENOSPC;
+}
+
+
 /* This is the HTTP_INPUT filter for HTTP requests and responses from
  * proxied servers (mod_proxy).  It handles chunked and content-length
  * bodies.  This can only be inserted/used after the headers
@@ -96,6 +131,7 @@
         ctx->remaining = 0;
         ctx->limit_used = 0;
         ctx->eos_sent = 0;
+        ctx->pos = ctx->chunk_ln;
 
         /* LimitRequestBody does not apply to proxied responses.
          * Consider implementing this check in its own filter.
@@ -227,9 +263,8 @@
 
         /* We can't read the chunk until after sending 100 if required. */
         if (ctx->state == BODY_CHUNK) {
-            char line[30];
             apr_bucket_brigade *bb;
-            apr_size_t len = 30;
+            apr_size_t len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln);
             apr_off_t brigade_length;
 
             bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
@@ -256,9 +291,16 @@
                     rv = APR_ENOSPC;
                 }
                 if (rv == APR_SUCCESS) {
-                    rv = apr_brigade_flatten(bb, line, &len);
+                    rv = apr_brigade_flatten(bb, ctx->pos, &len);
                     if (rv == APR_SUCCESS) {
-                        ctx->remaining = get_chunk_size(line);
+                        rv = get_chunk_line(ctx, len);
+                        if (APR_STATUS_IS_EAGAIN(rv)) {
+                            apr_brigade_cleanup(bb);
+                            return rv;
+                        }
+                        if (rv == APR_SUCCESS) {
+                            ctx->remaining = get_chunk_size(ctx->chunk_ln);
+                        }
                     }
                 }
             }
@@ -308,9 +350,9 @@
         case BODY_CHUNK:
         case BODY_CHUNK_PART:
             {
-                char line[30];
                 apr_bucket_brigade *bb;
-                apr_size_t len = 30;
+                apr_size_t len = sizeof(ctx->chunk_ln)
+                                 - (ctx->pos - ctx->chunk_ln);
                 apr_status_t http_error = HTTP_REQUEST_ENTITY_TOO_LARGE;
 
                 bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);
@@ -319,11 +361,21 @@
                 if (ctx->state == BODY_CHUNK) {
                     rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,
                                         block, 0);
-                    apr_brigade_cleanup(bb);
                     if (block == APR_NONBLOCK_READ &&
-                        (APR_STATUS_IS_EAGAIN(rv))) {
+                        ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ||
+                          (APR_STATUS_IS_EAGAIN(rv)) )) {
                         return APR_EAGAIN;
                     }
+                    rv = apr_brigade_flatten(bb, ctx->pos, &len);
+                    apr_brigade_cleanup(bb);
+                    if (rv == APR_SUCCESS) {
+                        rv = get_chunk_line(ctx, len);
+                        if (APR_STATUS_IS_EAGAIN(rv)) {
+                            return rv;
+                        }
+                    }
+                    /* Reset len */
+                    len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln);
                 } else {
                     rv = APR_SUCCESS;
                 }
@@ -341,7 +393,7 @@
                     }
                     ctx->state = BODY_CHUNK;
                     if (rv == APR_SUCCESS) {
-                        rv = apr_brigade_flatten(bb, line, &len);
+                        rv = apr_brigade_flatten(bb, ctx->pos, &len);
                         if (rv == APR_SUCCESS) {
                             /* Wait a sec, that's a blank line!  Oh no. */
                             if (!len) {
@@ -349,7 +401,14 @@
                                 http_error = HTTP_SERVICE_UNAVAILABLE;
                             }
                             else {
-                                ctx->remaining = get_chunk_size(line);
+                                rv = get_chunk_line(ctx, len);
+                                if (APR_STATUS_IS_EAGAIN(rv)) {
+                                    apr_brigade_cleanup(bb);
+                                    return rv;
+                                }
+                               if (rv == APR_SUCCESS) {
+                                   ctx->remaining = get_chunk_size(ctx->chunk_ln);
+                               }
                             }
                         }
                     }

Reply via email to