From bbebc9339e52c0b6622aa129c292cf8cd6b9da8c Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 2 Nov 2007 16:45:46 +0000 Subject: [PATCH] Fix handling of buffered request body for per-location SSL renegotiation when an internal redirect occurs: * modules/ssl/ssl_engine_io.c (ssl_io_buffer_fill): Remove protocol-level filters before inserting the buffering filter. (ssl_io_filter_buffer): Return an EOS if invoked with an empty brigade; do not remove the filter after exhausting the buffer. (ssl_io_filter_buffer): Increase the type of the buffer filter to be AP_FTYPE_PROTOCOL. PR: 43738 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@591393 13f79535-47bb-0310-9956-ffa450edef68 --- modules/ssl/ssl_engine_io.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index de9db34829..147da22881 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -1539,14 +1539,25 @@ int ssl_io_buffer_fill(request_rec *r) apr_brigade_destroy(tempb); - /* Insert the filter which will supply the buffered data. */ + /* After consuming all protocol-level input, remove all protocol-level + * filters. It should strictly only be necessary to remove filters + * at exactly ftype == AP_FTYPE_PROTOCOL, since this filter will + * precede all > AP_FTYPE_PROTOCOL anyway. */ + while (r->proto_input_filters->frec->ftype < AP_FTYPE_CONNECTION) { + ap_remove_input_filter(r->proto_input_filters); + } + + /* Insert the filter which will supply the buffered content. */ ap_add_input_filter(ssl_io_buffer, ctx, r, c); return 0; } /* This input filter supplies the buffered request body to the caller - * from the brigade stored in f->ctx. */ + * from the brigade stored in f->ctx. Note that the placement of this + * filter in the filter stack is important; it must be the first + * r->proto_input_filter; lower-typed filters will not be preserved + * across internal redirects (see PR 43738). */ static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, @@ -1565,6 +1576,19 @@ static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, return APR_ENOTIMPL; } + if (APR_BRIGADE_EMPTY(ctx->bb)) { + /* Suprisingly (and perhaps, wrongly), the request body can be + * pulled from the input filter stack more than once; a + * handler may read it, and ap_discard_request_body() will + * attempt to do so again after *every* request. So input + * filters must be prepared to give up an EOS if invoked after + * initially reading the request. The HTTP_IN filter does this + * with its ->eos_sent flag. */ + + APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc)); + return APR_SUCCESS; + } + if (mode == AP_MODE_READBYTES) { apr_bucket *e; @@ -1619,8 +1643,9 @@ static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, } ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c, - "buffered SSL brigade now exhausted; removing filter"); - ap_remove_input_filter(f); + "buffered SSL brigade exhausted"); + /* Note that the filter must *not* be removed here; it may be + * invoked again, see comment above. */ } return APR_SUCCESS; @@ -1695,7 +1720,7 @@ void ssl_io_filter_register(apr_pool_t *p) ap_register_input_filter (ssl_io_filter, ssl_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5); ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5); - ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1); + ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL); return; } -- 2.50.1