Commit 8fd5e953 authored by Justin Erenkrantz's avatar Justin Erenkrantz
Browse files

Make mod_include check for BYTE_COUNT_THRESHOLD on a per-bucket basis

rather than on a per-character basis.  A significant amount of time
was spent checking the limit.  A better place to check for the threshold
is when we read the bucket in not as we read each character in the bucket.

If a bucket manages to be 200MB, it is not this code's problem as it
is a mere filter.

I ran this with the mod_include stuff in httpd-test and it looks good
from here.

Submitted by:	Brian Pane <bpane@pacbell.net>
Reviewed by:	Justin Erenkrantz, Ryan Bloom, Greg Stein, Cliff Woolley,
		Paul Reder, etc, etc, etc...


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@90869 13f79535-47bb-0310-9956-ffa450edef68
parent f4bebbb9
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
Changes with Apache 2.0.26-dev

  *) Make mod_include check for BYTE_CHECK_THRESHOLD per bucket rather 
     than per character.  [Brian Pane <bpane@pacbell.net>]

  *) Normalize the primary request, redirects and sub-requests to
     run the same ap_process_request_internal for consistency in
     robustness, behavior and security.  [William Rowe]
+94 −44
Original line number Diff line number Diff line
@@ -137,8 +137,6 @@ static void add_include_vars(request_rec *r, char *timefmt)
    }
}



/* --------------------------- Parser functions --------------------------- */

/* This function returns either a pointer to the split bucket containing the
@@ -158,39 +156,56 @@ static apr_bucket *find_start_sequence(apr_bucket *dptr, include_ctx_t *ctx,
    *do_cleanup = 0;

    do {
        apr_status_t rv;
        int read_done = 0;

        if (APR_BUCKET_IS_EOS(dptr)) {
            break;
        }
        apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ);
        /* XXX handle retcodes */
        if (len == 0) { /* end of pipe? */
            break;
        }
        c = buf;
        while (c < buf + len) {

        if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
                apr_bucket *start_bucket;
            ctx->output_now = 1;
        }
        else if (ctx->bytes_parsed > 0) {
            rv = apr_bucket_read(dptr, &buf, &len, APR_NONBLOCK_READ);
            read_done = 1;
            if (APR_STATUS_IS_EAGAIN(rv)) {
                ctx->output_now = 1;
            }
        }

        if (ctx->output_now) {
            apr_size_t start_index;
            apr_bucket *start_bucket;
            apr_bucket_brigade *remainder;
            if (ctx->head_start_index > 0) {
                    start_index  = ctx->head_start_index;
                start_bucket = ctx->head_start_bucket;
                }
                else {
                    start_index  = (c - buf);
                    start_bucket = dptr;
                }
                apr_bucket_split(start_bucket, start_index);
                tmp_bkt = APR_BUCKET_NEXT(start_bucket);
                if (ctx->head_start_index > 0) {
                start_bucket = APR_BUCKET_NEXT(start_bucket);
                ctx->head_start_index = 0;
                    ctx->head_start_bucket = tmp_bkt;
                ctx->head_start_bucket = start_bucket;
                ctx->parse_pos = 0;
                ctx->state = PRE_HEAD;
            }
            else {
                start_bucket = dptr;
            }
            return start_bucket;
        }

                return tmp_bkt;
        if (!read_done) {
            rv = apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ);
        }
        if (!APR_STATUS_IS_SUCCESS(rv)) {
            ctx->status = rv;
            return NULL;
        }

        if (len == 0) { /* end of pipe? */
            break;
        }
        c = buf;
        while (c < buf + len) {
            if (*c == str[ctx->parse_pos]) {
                if (ctx->state == PRE_HEAD) {
                    ctx->state             = PARSE_HEAD;
@@ -210,7 +225,8 @@ static apr_bucket *find_start_sequence(apr_bucket *dptr, include_ctx_t *ctx,
                    ctx->tag_start_index  = c - buf;
                    if (ctx->head_start_index > 0) {
                        start_index = (c - buf) - ctx->head_start_index;
                        apr_bucket_split(ctx->head_start_bucket, ctx->head_start_index);
                        apr_bucket_split(ctx->head_start_bucket, 
                                         ctx->head_start_index);
                        tmp_bkt = APR_BUCKET_NEXT(ctx->head_start_bucket);
                        if (dptr == ctx->head_start_bucket) {
                            ctx->tag_start_bucket = tmp_bkt;
@@ -258,22 +274,24 @@ static apr_bucket *find_end_sequence(apr_bucket *dptr, include_ctx_t *ctx, apr_b
    const char *str = ENDING_SEQUENCE;

    do {
        apr_status_t rv;
        int read_done = 0;

        if (APR_BUCKET_IS_EOS(dptr)) {
            break;
        }
        apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ);
        /* XXX handle retcodes */
        if (len == 0) { /* end of pipe? */
            break;
        if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
            ctx->output_now = 1;
        }
        if (dptr == ctx->tag_start_bucket) {
            c = buf + ctx->tag_start_index;
        else if (ctx->bytes_parsed > 0) {
            rv = apr_bucket_read(dptr, &buf, &len, APR_NONBLOCK_READ);
            read_done = 1;
            if (APR_STATUS_IS_EAGAIN(rv)) {
                ctx->output_now = 1;
            }
        else {
            c = buf;
        }
        while (c < buf + len) {
            if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {

        if (ctx->output_now) {
            if (ctx->state == PARSE_DIRECTIVE) {
                /* gonna start over parsing the directive next time through */
                ctx->directive_length = 0;
@@ -282,6 +300,24 @@ static apr_bucket *find_end_sequence(apr_bucket *dptr, include_ctx_t *ctx, apr_b
            return dptr;
        }

        if (!read_done) {
            rv = apr_bucket_read(dptr, &buf, &len, APR_BLOCK_READ);
        }
        if (!APR_STATUS_IS_SUCCESS(rv)) {
            ctx->status = rv;
            return NULL;
        }

        if (len == 0) { /* end of pipe? */
            break;
        }
        if (dptr == ctx->tag_start_bucket) {
            c = buf + ctx->tag_start_index;
        }
        else {
            c = buf;
        }
        while (c < buf + len) {
            if (*c == str[ctx->parse_pos]) {
                if (ctx->state != PARSE_TAIL) {
                    ctx->state             = PARSE_TAIL;
@@ -2366,6 +2402,9 @@ static apr_status_t send_parsed_content(apr_bucket_brigade **bb,
            apr_size_t cleanup_bytes = ctx->parse_pos;

            tmp_dptr = find_start_sequence(dptr, ctx, *bb, &do_cleanup);
            if (!APR_STATUS_IS_SUCCESS(ctx->status)) {
                return ctx->status;
            }

            /* The few bytes stored in the ssi_tag_brigade turned out not to
             * be a tag after all. This can only happen if the starting
@@ -2403,7 +2442,9 @@ static apr_status_t send_parsed_content(apr_bucket_brigade **bb,
                    dptr = APR_BRIGADE_SENTINEL(*bb);
                }
            }
            else if ((tmp_dptr != NULL) && (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD)) {
            else if ((tmp_dptr != NULL) &&
                     (ctx->output_now ||
                      (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD))) {
                               /* Send the large chunk of pre-tag bytes...  */
                tag_and_after = apr_brigade_split(*bb, tmp_dptr);
                rv = ap_pass_brigade(f->next, *bb);
@@ -2413,9 +2454,12 @@ static apr_status_t send_parsed_content(apr_bucket_brigade **bb,
                *bb  = tag_and_after;
                dptr = tmp_dptr;
                ctx->bytes_parsed = 0;
                ctx->output_now = 0;
            }
            else if (tmp_dptr == NULL) { /* There was no possible SSI tag in the */
                dptr = APR_BRIGADE_SENTINEL(*bb);  /* remainder of this brigade...    */
            else if (tmp_dptr == NULL) { 
                /* There was no possible SSI tag in the
                 * remainder of this brigade... */
                dptr = APR_BRIGADE_SENTINEL(*bb);  
            }
        }

@@ -2425,6 +2469,9 @@ static apr_status_t send_parsed_content(apr_bucket_brigade **bb,
             (ctx->state == PARSE_TAIL))       &&
            (dptr != APR_BRIGADE_SENTINEL(*bb))) {
            tmp_dptr = find_end_sequence(dptr, ctx, *bb);
            if (!APR_STATUS_IS_SUCCESS(ctx->status)) {
                return ctx->status;
            }

            if (tmp_dptr != NULL) {
                dptr = tmp_dptr;  /* Adjust bucket pos... */
@@ -2440,11 +2487,13 @@ static apr_status_t send_parsed_content(apr_bucket_brigade **bb,
                    APR_BRIGADE_CONCAT(ctx->ssi_tag_brigade, *bb);
                    *bb = tag_and_after;
                }
                else if (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD) {
                else if (ctx->output_now ||
                         (ctx->bytes_parsed >= BYTE_COUNT_THRESHOLD)) {
                    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next, rv);
                    if (rv != APR_SUCCESS) {
                        return rv;
                    }
                    ctx->output_now = 0;
                }
            }
            else {
@@ -2717,6 +2766,7 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
                ctx->flags |= FLAG_NO_EXEC;
            }
            ctx->ssi_tag_brigade = apr_brigade_create(f->c->pool);
            ctx->status = APR_SUCCESS;

            apr_cpystrn(ctx->error_str, conf->default_error_msg, sizeof(ctx->error_str));
            apr_cpystrn(ctx->time_str, conf->default_time_fmt, sizeof(ctx->time_str));
+2 −0
Original line number Diff line number Diff line
@@ -138,6 +138,8 @@ typedef struct include_filter_ctx {
    int          if_nesting_level;
    apr_size_t   parse_pos;
    int          bytes_parsed;
    apr_status_t status;
    int          output_now;
    
    apr_bucket   *head_start_bucket;
    apr_size_t   head_start_index;