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;