On Fri, 11 Jul 2003, Ronald K Park, Jr wrote:

> Ok, I've finally created a simple example.  Unfortunately, I'm
> working from home today and having trouble getting the file on
> my local machine to send as an attachment.

Please try the attached patch and see if it passes your tests.  It also
adds a lot of assertions which we needed to help debug our patch, but I'll
remove those before committing.

--Cliff
Index: modules/filters/mod_include.c
===================================================================
RCS file: /home/cvs/httpd-2.0/modules/filters/mod_include.c,v
retrieving revision 1.233
diff -u -d -r1.233 mod_include.c
--- modules/filters/mod_include.c       3 Feb 2003 17:53:01 -0000       1.233
+++ modules/filters/mod_include.c       11 Jul 2003 22:54:52 -0000
@@ -92,6 +92,8 @@
 #include "mod_include.h"
 #include "util_ebcdic.h"
 
+#include <assert.h>
+
 module AP_MODULE_DECLARE_DATA include_module;
 static apr_hash_t *include_hash;
 static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
@@ -429,7 +431,8 @@
         }
 
         if (len == 0) { /* end of pipe? */
-            break;
+            dptr = APR_BUCKET_NEXT(dptr);
+            continue;
         }
 
         /* Set our buffer to use. */
@@ -477,7 +480,7 @@
 
         if (len)
         {
-            pos = bndm(str, slen, c, len, ctx->start_seq_pat);
+            pos = bndm(str, slen, buf, len, ctx->start_seq_pat);
             if (pos != len)
             {
                 ctx->head_start_bucket = dptr;
@@ -600,7 +603,8 @@
         }
 
         if (len == 0) { /* end of pipe? */
-            break;
+            dptr = APR_BUCKET_NEXT(dptr);
+            continue;
         }
         if (dptr == ctx->tag_start_bucket) {
             c = buf + ctx->tag_start_index;
@@ -2910,12 +2914,41 @@
 
 /* -------------------------- The main function --------------------------- */
 
+static int bucket_is_in_brigade(apr_bucket *b, apr_bucket_brigade *bb)
+{
+    apr_bucket *a = APR_BRIGADE_FIRST(bb);
+
+    while (a != APR_BRIGADE_SENTINEL(bb)) {
+        if (a == b) {
+            return 1;
+        }
+        a = APR_BUCKET_NEXT(a);
+    }
+    return 0;
+}
+
+static int brigade_is_not_corrupt(apr_bucket_brigade *bb)
+{
+    apr_bucket *b = APR_BRIGADE_SENTINEL(bb);
+
+    do {
+        b = APR_BUCKET_NEXT(b);
+        if ((APR_BUCKET_PREV(APR_BUCKET_NEXT(b)) != b) ||
+            (APR_BUCKET_NEXT(APR_BUCKET_PREV(b)) != b))
+        {
+            return 0;
+        }
+    } while (b != APR_BRIGADE_SENTINEL(bb));
+
+    return 1;
+}
+
 static apr_status_t send_parsed_content(apr_bucket_brigade **bb, 
                                         request_rec *r, ap_filter_t *f)
 {
     include_ctx_t *ctx = f->ctx;
     apr_bucket *dptr = APR_BRIGADE_FIRST(*bb);
-    apr_bucket *tmp_dptr;
+    apr_bucket *tmp_dptr, *last_dptr=NULL;
     apr_bucket_brigade *tag_and_after;
     apr_status_t rv = APR_SUCCESS;
 
@@ -2929,6 +2962,10 @@
     }
 
     while (dptr != APR_BRIGADE_SENTINEL(*bb) && !APR_BUCKET_IS_EOS(dptr)) {
+
+        assert(brigade_is_not_corrupt(*bb));
+        assert(brigade_is_not_corrupt(ctx->ssi_tag_brigade));
+
         /* State to check for the STARTING_SEQUENCE. */
         if ((ctx->state == PRE_HEAD) || (ctx->state == PARSE_HEAD)) {
             int do_cleanup = 0;
@@ -2951,6 +2988,7 @@
                                                   r->connection->bucket_alloc);
                 APR_BRIGADE_INSERT_HEAD(*bb, tmp_bkt);
                 apr_brigade_cleanup(ctx->ssi_tag_brigade);
+                assert(brigade_is_not_corrupt(ctx->ssi_tag_brigade));
             }
 
             /* If I am inside a conditional (if, elif, else) that is false
@@ -2958,6 +2996,7 @@
              */
             if ((!(ctx->flags & FLAG_PRINTING)) && (tmp_dptr != NULL) &&
                 (dptr != APR_BRIGADE_SENTINEL(*bb))) {
+                assert(bucket_is_in_brigade(dptr, *bb));
                 while ((dptr != APR_BRIGADE_SENTINEL(*bb)) &&
                        (dptr != tmp_dptr)) {
                     apr_bucket *free_bucket = dptr;
@@ -2965,6 +3004,7 @@
                     dptr = APR_BUCKET_NEXT (dptr);
                     apr_bucket_delete(free_bucket);
                 }
+                assert(brigade_is_not_corrupt(*bb));
             }
 
             /* Adjust the current bucket position based on what was found... */
@@ -2980,7 +3020,9 @@
                      (ctx->output_now ||
                       (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD))) {
                 /* Send the large chunk of pre-tag bytes...  */
+                assert(brigade_is_not_corrupt(*bb));
                 tag_and_after = apr_brigade_split(*bb, tmp_dptr);
+                assert(brigade_is_not_corrupt(tag_and_after));
                 if (ctx->output_flush) {
                     APR_BRIGADE_INSERT_TAIL(*bb, 
apr_bucket_flush_create((*bb)->bucket_alloc));
                 }
@@ -2998,6 +3040,8 @@
             else if (tmp_dptr == NULL) { 
                 /* There was no possible SSI tag in the
                  * remainder of this brigade... */
+                assert(brigade_is_not_corrupt(*bb));
+                last_dptr = dptr;
                 dptr = APR_BRIGADE_SENTINEL(*bb);  
             }
         }
@@ -3024,13 +3068,17 @@
                  * be in one place or another.
                  */
                 if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+                    assert(brigade_is_not_corrupt(*bb));
                     tag_and_after = apr_brigade_split(*bb, dptr);
                     APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
+                    assert(brigade_is_not_corrupt(tag_and_after));
                     *bb = tag_and_after;
                 }
                 else if (ctx->output_now ||
                          (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD)) {
+                    assert(brigade_is_not_corrupt(*bb));
                     SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next, rv);
+                    assert(brigade_is_not_corrupt(*bb));
                     if (rv != APR_SUCCESS) {
                         return rv;
                     }
@@ -3040,6 +3088,7 @@
             }
             else {
                 /* remainder of this brigade...    */
+                assert(brigade_is_not_corrupt(*bb));
                 dptr = APR_BRIGADE_SENTINEL(*bb);  
             }
         }
@@ -3071,6 +3120,8 @@
 
                 /* DO CLEANUP HERE!!!!! */
                 tmp_dptr = ctx->head_start_bucket;
+                assert(brigade_is_not_corrupt(ctx->ssi_tag_brigade));
+                assert(brigade_is_not_corrupt(*bb));
                 if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
                     apr_brigade_cleanup(ctx->ssi_tag_brigade);
                 }
@@ -3142,10 +3193,10 @@
                 content_head = dptr;
             }
             tmp_dptr = ctx->head_start_bucket;
-            if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
-                apr_brigade_cleanup(ctx->ssi_tag_brigade);
-            }
-            else {
+            assert(brigade_is_not_corrupt(ctx->ssi_tag_brigade));
+            assert(brigade_is_not_corrupt(*bb));
+            if (APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
+                tmp_dptr = ctx->head_start_bucket;
                 do {
                     tmp_bkt  = tmp_dptr;
                     tmp_dptr = APR_BUCKET_NEXT (tmp_dptr);
@@ -3153,6 +3204,7 @@
                 } while ((tmp_dptr != content_head) &&
                          (tmp_dptr != APR_BRIGADE_SENTINEL(*bb)));
             }
+
             if (ctx->combined_tag == tmp_buf) {
                 ctx->combined_tag = NULL;
             }
@@ -3169,6 +3221,7 @@
             ctx->tag_length        = 0;
             ctx->directive_length  = 0;
 
+            assert(brigade_is_not_corrupt(ctx->ssi_tag_brigade));
             if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
                 apr_brigade_cleanup(ctx->ssi_tag_brigade);
             }
@@ -3183,6 +3236,8 @@
         /* We might have something saved that we never completed, but send
          * down unparsed.  This allows for <!-- at the end of files to be
          * sent correctly. */
+        assert(brigade_is_not_corrupt(ctx->ssi_tag_brigade));
+        assert(brigade_is_not_corrupt(*bb));
         if (!APR_BRIGADE_EMPTY(ctx->ssi_tag_brigade)) {
             APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
             return ap_pass_brigade(f->next, ctx->ssi_tag_brigade);
@@ -3197,17 +3252,17 @@
      *   once the whole tag has been found.
      */
     if (ctx->state == PRE_HEAD) {
-        /* Inside a false conditional (if, elif, else), so toss it all... */
-        if ((dptr != APR_BRIGADE_SENTINEL(*bb)) &&
-            (!(ctx->flags & FLAG_PRINTING))) {
+        if ((dptr == APR_BRIGADE_SENTINEL(*bb)) &&
+            (!(ctx->flags & FLAG_PRINTING)) && (last_dptr != NULL))
+        {
             apr_bucket *free_bucket;
             do {
-                free_bucket = dptr;
-                dptr = APR_BUCKET_NEXT (dptr);
+                free_bucket = last_dptr;
+                last_dptr = APR_BUCKET_NEXT(last_dptr);
                 apr_bucket_delete(free_bucket);
-            } while (dptr != APR_BRIGADE_SENTINEL(*bb));
+            } while (last_dptr != dptr);
         }
-        else { 
+        else {
             /* Otherwise pass it along...
              * No SSI tags in this brigade... */
             rv = ap_pass_brigade(f->next, *bb);  
@@ -3236,7 +3291,10 @@
                 ctx->head_start_index = 0;
             }
                            /* Set aside tag, pass pre-tag... */
+            assert(brigade_is_not_corrupt(*bb));
+            assert(bucket_is_in_brigade(ctx->head_start_bucket, *bb));
             tag_and_after = apr_brigade_split(*bb, ctx->head_start_bucket);
+            assert(brigade_is_not_corrupt(tag_and_after));
             rv = ap_pass_brigade(f->next, *bb);
             if (rv != APR_SUCCESS) {
                 return rv;

Reply via email to