Author: joes
Date: Mon Mar 14 20:43:03 2005
New Revision: 157510
URL: http://svn.apache.org/viewcvs?view=rev&rev=157510
Log:
Factor prefetch logic out of apreq_filter and into apreq_filter_prefetch.
Also add some special cases for M_GET to prevent subrequests from
stealing the parsed body away from the main request.
Modified:
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
httpd/apreq/branches/multi-env-unstable/module/apache2/filter.c
httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c
Modified:
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h?view=diff&r1=157509&r2=157510
==============================================================================
---
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
(original)
+++
httpd/apreq/branches/multi-env-unstable/module/apache2/apreq_private_apache2.h
Mon Mar 14 20:43:03 2005
@@ -19,19 +19,20 @@
/* Tracks the apreq filter state */
struct filter_ctx {
apr_bucket_brigade *bb; /* input brigade that's passed to the parser */
+ apr_bucket_brigade *bbtmp; /* temporary copy of bb, destined for the spool
*/
apr_bucket_brigade *spool; /* copied prefetch data for downstream filters
*/
- apr_table_t *body;
apreq_parser_t *parser;
apreq_hook_t *hook_queue;
- apr_status_t status;
- unsigned saw_eos; /* Has EOS bucket appeared in filter? */
- apr_uint64_t bytes_read; /* Total bytes read into this filter. */
- apr_uint64_t read_limit; /* Max bytes the filter may show to
parser */
+ apr_table_t *body;
+ apr_status_t body_status;
+ apr_status_t filter_error;
+ apr_uint64_t bytes_read; /* Total bytes read into this filter.
*/
+ apr_uint64_t read_limit; /* Max bytes the filter may show to
parser */
apr_size_t brigade_limit;
const char *temp_dir;
};
-
+apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes);
apr_status_t apreq_filter(ap_filter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
@@ -53,45 +54,3 @@
f->next = top;
}
}
-
-APR_INLINE
-static ap_filter_t *get_apreq_filter(apreq_handle_t *env)
-{
- struct apache2_handle *handle = (struct apache2_handle *)env;
-
- if (handle->f == NULL) {
- handle->f = ap_add_input_filter(APREQ_FILTER_NAME, NULL,
- handle->r,
- handle->r->connection);
- /* ap_add_input_filter does not guarantee cfg->f == r->input_filters,
- * so we reposition the new filter there as necessary.
- */
- apreq_filter_relocate(handle->f);
- }
-
- return handle->f;
-}
-
-APR_INLINE
-static apr_status_t apreq_filter_read(ap_filter_t *f, apr_off_t bytes)
-{
- struct filter_ctx *ctx = f->ctx;
- apr_status_t s;
-
- if (ctx->status == APR_EINIT)
- apreq_filter_init_context(f);
-
- if (ctx->status != APR_INCOMPLETE || bytes == 0)
- return ctx->status;
-
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->r,
- "prefetching %" APR_OFF_T_FMT " bytes", bytes);
- s = ap_get_brigade(f, NULL, AP_MODE_READBYTES, APR_BLOCK_READ, bytes);
- if (s != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, s, f->r,
- "apreq filter error detected during prefetch");
- return s;
- }
- return ctx->status;
-}
-
Modified: httpd/apreq/branches/multi-env-unstable/module/apache2/filter.c
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/module/apache2/filter.c?view=diff&r1=157509&r2=157510
==============================================================================
--- httpd/apreq/branches/multi-env-unstable/module/apache2/filter.c (original)
+++ httpd/apreq/branches/multi-env-unstable/module/apache2/filter.c Mon Mar 14
20:43:03 2005
@@ -202,7 +202,15 @@
request_rec *r = f->r;
struct filter_ctx *ctx = f->ctx;
apr_bucket_alloc_t *ba = r->connection->bucket_alloc;
- const char *cl_header = apr_table_get(r->headers_in, "Content-Length");
+ const char *cl_header;
+
+ if (r->method_number == M_GET) {
+ /* Don't parse GET (this protects against subrequest body parsing). */
+ ctx->body_status = APREQ_ERROR_NODATA;
+ return;
+ }
+
+ cl_header = apr_table_get(r->headers_in, "Content-Length");
if (cl_header != NULL) {
char *dummy;
@@ -211,7 +219,7 @@
if (dummy == NULL || *dummy != 0) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r,
"Invalid Content-Length header (%s)", cl_header);
- ctx->status = APREQ_ERROR_BADHEADER;
+ ctx->body_status = APREQ_ERROR_BADHEADER;
return;
}
else if (content_length > ctx->read_limit) {
@@ -219,7 +227,7 @@
"Content-Length header (%s) exceeds configured "
"max_body limit (%" APR_UINT64_T_FMT ")",
cl_header, ctx->read_limit);
- ctx->status = APREQ_ERROR_OVERLIMIT;
+ ctx->body_status = APREQ_ERROR_OVERLIMIT;
return;
}
}
@@ -238,12 +246,12 @@
NULL);
}
else {
- ctx->status = APREQ_ERROR_NOPARSER;
+ ctx->body_status = APREQ_ERROR_NOPARSER;
return;
}
}
else {
- ctx->status = APREQ_ERROR_NOHEADER;
+ ctx->body_status = APREQ_ERROR_NOHEADER;
return;
}
}
@@ -258,9 +266,10 @@
ctx->hook_queue = NULL;
ctx->bb = apr_brigade_create(r->pool, ba);
+ ctx->bbtmp = apr_brigade_create(r->pool, ba);
ctx->spool = apr_brigade_create(r->pool, ba);
ctx->body = apr_table_make(r->pool, APREQ_DEFAULT_NELTS);
- ctx->status = APR_INCOMPLETE;
+ ctx->body_status = APR_INCOMPLETE;
}
@@ -293,7 +302,11 @@
struct apache2_handle *handle =
(struct apache2_handle *)apreq_handle_apache2(r);
- if (ctx == NULL || ctx->status == APR_EINIT) {
+ /* Don't parse GET (this protects against subrequest body parsing). */
+ if (f->r->method_number == M_GET)
+ return APR_SUCCESS;
+
+ if (ctx == NULL || ctx->body_status == APR_EINIT) {
if (f == r->input_filters) {
handle->f = f;
}
@@ -319,27 +332,89 @@
if (handle->f == f) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
"disabling stale protocol filter");
- if (ctx->status == APR_INCOMPLETE)
- ctx->status = APREQ_ERROR_INTERRUPT;
+ if (ctx->body_status == APR_INCOMPLETE)
+ ctx->body_status = APREQ_ERROR_INTERRUPT;
handle->f = NULL;
}
return APR_SUCCESS;
}
-static APR_INLINE
-unsigned apreq_filter_status_is_error(apr_status_t s)
+
+
+apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes)
{
- switch (s) {
- case APR_INCOMPLETE:
- case APREQ_ERROR_INTERRUPT:
- case APR_SUCCESS:
- return 0;
- default:
- return 1;
+ struct filter_ctx *ctx = f->ctx;
+ request_rec *r = f->r;
+ apr_status_t rv;
+ apr_off_t len;
+
+ if (ctx->body_status == APR_EINIT)
+ apreq_filter_init_context(f);
+
+ if (ctx->body_status != APR_INCOMPLETE || readbytes == 0)
+ return ctx->body_status;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r,
+ "prefetching %" APR_OFF_T_FMT " bytes", readbytes);
+
+ rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES,
+ APR_BLOCK_READ, readbytes);
+
+ if (rv != APR_SUCCESS) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "ap_get_brigade failed during prefetch");
+ ctx->filter_error = rv;
+ return ctx->body_status = APREQ_ERROR_GENERAL;
}
+
+ apreq_brigade_setaside(ctx->bb, r->pool);
+ apreq_brigade_copy(ctx->bbtmp, ctx->bb);
+
+ rv = apreq_brigade_concat(r->pool, ctx->temp_dir, ctx->brigade_limit,
+ ctx->spool, ctx->bbtmp);
+ if (rv != APR_SUCCESS && rv != APR_EOF) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "apreq_brigade_concat failed; TempDir problem?");
+ ctx->filter_error = APR_EGENERAL;
+ return ctx->body_status = rv;
+ }
+
+ /* Adding "f" to the protocol filter chain ensures the
+ * spooled data is preserved across internal redirects.
+ */
+
+ if (f != r->proto_input_filters) {
+ ap_filter_t *in;
+ for (in = r->input_filters; in != r->proto_input_filters;
+ in = in->next)
+ {
+ if (f == in) {
+ r->proto_input_filters = f;
+ break;
+ }
+ }
+ }
+
+ apr_brigade_length(ctx->bb, 1, &len);
+ ctx->bytes_read += len;
+
+ if (ctx->bytes_read > ctx->read_limit) {
+ ctx->body_status = APREQ_ERROR_OVERLIMIT;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r,
+ "Bytes read (%" APR_UINT64_T_FMT
+ ") exceeds configured read limit (%" APR_UINT64_T_FMT
")",
+ ctx->bytes_read, ctx->read_limit);
+ return ctx->body_status;
+ }
+
+ ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
+ apr_brigade_cleanup(ctx->bb);
+
+ return ctx->body_status;
}
+
apr_status_t apreq_filter(ap_filter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
@@ -349,164 +424,71 @@
request_rec *r = f->r;
struct filter_ctx *ctx;
apr_status_t rv;
+ apr_off_t len;
switch (mode) {
case AP_MODE_READBYTES:
- case AP_MODE_EXHAUSTIVE:
/* only the modes above are supported */
break;
- case AP_MODE_GETLINE: /* punt- chunks are b0rked in ap_http_filter */
+
+ case AP_MODE_EXHAUSTIVE: /* not worth supporting at this level */
+ case AP_MODE_GETLINE: /* punt- chunked trailers are b0rked in
ap_http_filter */
return ap_get_brigade(f->next, bb, mode, block, readbytes);
+
default:
return APR_ENOTIMPL;
}
-
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
- if (ctx->status == APR_EINIT)
+ if (ctx->body_status == APR_EINIT)
apreq_filter_init_context(f);
- if (apreq_filter_status_is_error(ctx->status)) {
- rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
- ap_remove_input_filter(f);
- return rv;
- }
-
+ if (ctx->spool && !APR_BRIGADE_EMPTY(ctx->spool)) {
+ apr_bucket *e;
+ rv = apr_brigade_partition(ctx->spool, readbytes, &e);
+ if (rv != APR_SUCCESS && rv != APR_INCOMPLETE)
+ return rv;
- if (bb != NULL) {
+ if (APR_BUCKET_IS_EOS(e))
+ e = APR_BUCKET_NEXT(e);
- if (!ctx->saw_eos) {
-
- if (ctx->status == APR_INCOMPLETE) {
- apr_off_t len;
- rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
-
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "ap_get_brigade failed");
- return rv;
- }
-
- apreq_brigade_copy(ctx->bb, bb);
- apr_brigade_length(bb, 1, &len);
- ctx->bytes_read += len;
-
- if (ctx->bytes_read > ctx->read_limit) {
- ctx->status = APREQ_ERROR_OVERLIMIT;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->status, r,
- "Bytes read (%" APR_UINT64_T_FMT
- ") exceeds configured max_body limit (%"
- APR_UINT64_T_FMT ")",
- ctx->bytes_read, ctx->read_limit);
- }
- }
- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(ctx->bb)))
- ctx->saw_eos = 1;
- }
-
- if (!APR_BRIGADE_EMPTY(ctx->spool)) {
- APR_BRIGADE_CONCAT(ctx->spool, bb);
- if (mode == AP_MODE_READBYTES) {
- apr_bucket *e;
- rv = apr_brigade_partition(ctx->spool, readbytes, &e);
- if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "partition failed");
- return rv;
- }
- if (APR_BUCKET_IS_EOS(e))
- e = APR_BUCKET_NEXT(e);
- apreq_brigade_move(bb, ctx->spool, e);
- apreq_brigade_setaside(ctx->spool, r->pool);
- }
- }
-
- if (ctx->status != APR_INCOMPLETE) {
-
- if (APR_BRIGADE_EMPTY(ctx->spool)) {
- ap_filter_t *next = f->next;
-
- ap_remove_input_filter(f);
- if (APR_BRIGADE_EMPTY(bb))
- return ap_get_brigade(next, bb, mode, block, readbytes);
- }
- return APR_SUCCESS;
- }
+ apreq_brigade_move(bb, ctx->spool, e);
+ return APR_SUCCESS;
}
- else if (!ctx->saw_eos) {
- /* bb == NULL, so this is a prefetch read! */
- apr_off_t total_read = 0;
-
- /* XXX cache this thing in somewhere */
- bb = apr_brigade_create(ctx->bb->p, ctx->bb->bucket_alloc);
-
- while (total_read < readbytes) {
- apr_off_t len;
- apr_bucket *last = APR_BRIGADE_LAST(ctx->spool);
-
- if (APR_BUCKET_IS_EOS(last)) {
- ctx->saw_eos = 1;
- break;
- }
-
- rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
- if (rv != APR_SUCCESS) {
- /*XXX how should we handle this filter-chain error? */
- return rv;
- }
- apreq_brigade_setaside(bb, r->pool);
- apreq_brigade_copy(ctx->bb, bb);
+ else if (ctx->body_status != APR_INCOMPLETE) {
+ if (ctx->filter_error)
+ return ctx->filter_error;
- apr_brigade_length(bb, 1, &len);
- total_read += len;
-
- rv = apreq_brigade_concat(r->pool, ctx->temp_dir,
ctx->brigade_limit,
- ctx->spool, bb);
- if (rv != APR_SUCCESS && rv != APR_EOF) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "apreq_brigade_concat failed; TempDir problem?");
- /*XXX how should we handle this apreq-based error? */
- return ctx->status = rv;
- }
- }
+ rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
+ ap_remove_input_filter(f);
+ return rv;
+ }
- ctx->bytes_read += total_read;
- if (ctx->bytes_read > ctx->read_limit) {
- ctx->status = APREQ_ERROR_OVERLIMIT;
- ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->status, r,
- "Bytes read (%" APR_UINT64_T_FMT
- ") exceeds configured read limit (%" APR_UINT64_T_FMT
")",
- ctx->bytes_read, ctx->read_limit);
- }
+ rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
+ if (rv != APR_SUCCESS)
+ return rv;
- /* Adding "f" to the protocol filter chain ensures the
- * spooled data is preserved across internal redirects.
- */
- if (f != r->proto_input_filters) {
- ap_filter_t *in;
- for (in = r->input_filters; in != r->proto_input_filters;
- in = in->next)
- {
- if (f == in) {
- r->proto_input_filters = f;
- break;
- }
- }
- }
+ apreq_brigade_copy(ctx->bb, bb);
+ apr_brigade_length(bb, 1, &len);
+ ctx->bytes_read += len;
+
+ if (ctx->bytes_read > ctx->read_limit) {
+ ctx->body_status = APREQ_ERROR_OVERLIMIT;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r,
+ "Bytes read (%" APR_UINT64_T_FMT
+ ") exceeds configured max_body limit (%"
+ APR_UINT64_T_FMT ")",
+ ctx->bytes_read, ctx->read_limit);
}
- else
- return APR_SUCCESS;
-
- if (ctx->status == APR_INCOMPLETE) {
- ctx->status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
+ else {
+ ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
apr_brigade_cleanup(ctx->bb);
}
-
return APR_SUCCESS;
}
@@ -562,14 +544,18 @@
if (f == r->input_filters
&& r->proto_input_filters == f->next
- && f->next->frec->filter_func.in_func == apreq_filter)
+ && f->next->frec->filter_func.in_func == apreq_filter
+ && f->r->method_number != M_GET)
{
ctx = f->next->ctx;
- switch (ctx->status) {
+ switch (ctx->body_status) {
+
case APREQ_ERROR_INTERRUPT:
- ctx->status = APR_INCOMPLETE;
+ ctx->body_status = APR_INCOMPLETE;
+ /* fall thru */
+
case APR_SUCCESS:
if (d != NULL) {
@@ -593,14 +579,13 @@
return;
default:
- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, ctx->status, r,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, ctx->body_status, r,
"cannot steal context: bad filter status");
}
}
-
ctx = apr_pcalloc(r->pool, sizeof *ctx);
- ctx->status = APR_EINIT;
+ ctx->body_status = APR_EINIT;
if (d == NULL) {
ctx->read_limit = (apr_uint64_t)-1;
@@ -613,3 +598,4 @@
f->ctx = ctx;
}
+
Modified: httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c
URL:
http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c?view=diff&r1=157509&r2=157510
==============================================================================
--- httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c (original)
+++ httpd/apreq/branches/multi-env-unstable/module/apache2/handle.c Mon Mar 14
20:43:03 2005
@@ -29,6 +29,26 @@
#include "apreq_private_apache2.h"
#include "apreq_error.h"
+
+APR_INLINE
+static ap_filter_t *get_apreq_filter(apreq_handle_t *env)
+{
+ struct apache2_handle *handle = (struct apache2_handle *)env;
+
+ if (handle->f == NULL) {
+ handle->f = ap_add_input_filter(APREQ_FILTER_NAME, NULL,
+ handle->r,
+ handle->r->connection);
+ /* ap_add_input_filter does not guarantee cfg->f == r->input_filters,
+ * so we reposition the new filter there as necessary.
+ */
+ apreq_filter_relocate(handle->f);
+ }
+
+ return handle->f;
+}
+
+
static apr_status_t apache2_jar(apreq_handle_t *env, const apr_table_t **t)
{
struct apache2_handle *handle = (struct apache2_handle*)env;
@@ -138,20 +158,20 @@
ctx = f->ctx;
- switch (ctx->status) {
+ switch (ctx->body_status) {
case APR_EINIT:
apreq_filter_init_context(f);
- if (ctx->status != APR_INCOMPLETE)
+ if (ctx->body_status != APR_INCOMPLETE)
break;
case APR_INCOMPLETE:
- while (apreq_filter_read(f, APREQ_DEFAULT_READ_BLOCK_SIZE) ==
APR_INCOMPLETE)
+ while (apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE) ==
APR_INCOMPLETE)
; /*loop*/
}
*t = ctx->body;
- return ctx->status;
+ return ctx->body_status;
}
static apreq_param_t *apache2_body_get(apreq_handle_t *env, const char *name)
@@ -165,14 +185,14 @@
ctx = f->ctx;
- switch (ctx->status) {
+ switch (ctx->body_status) {
case APR_EINIT:
apreq_filter_init_context(f);
- if (ctx->status != APR_INCOMPLETE)
+ if (ctx->body_status != APR_INCOMPLETE)
return NULL;
- apreq_filter_read(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
+ apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
case APR_INCOMPLETE:
@@ -182,7 +202,7 @@
do {
/* riff on Duff's device */
- apreq_filter_read(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
+ apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
case APR_SUCCESS:
@@ -190,7 +210,7 @@
if (val != NULL)
return apreq_value_to_param(val);
- } while (ctx->status == APR_INCOMPLETE);
+ } while (ctx->body_status == APR_INCOMPLETE);
break;
@@ -218,7 +238,7 @@
return APR_EINIT;
}
*parser = ctx->parser;
- return ctx->status;
+ return APR_SUCCESS;
}
static
@@ -283,7 +303,7 @@
ctx = f->ctx;
- if (ctx->status == APR_EINIT || ctx->brigade_limit > bytes) {
+ if (ctx->body_status == APR_EINIT || ctx->brigade_limit > bytes) {
ctx->brigade_limit = bytes;
return APR_SUCCESS;
}
@@ -377,7 +397,7 @@
return APR_SUCCESS;
}
-static APREQ_MODULE(apache2, 20050131);
+static APREQ_MODULE(apache2, 20050315);
APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r)
{
@@ -385,10 +405,10 @@
ap_get_module_config(r->request_config, &apreq_module);
if (handle != NULL) {
- if (handle->f == NULL)
- get_apreq_filter(&handle->env);
+ get_apreq_filter(&handle->env);
return &handle->env;
}
+
handle = apr_palloc(r->pool, sizeof *handle);
ap_set_module_config(r->request_config, &apreq_module, handle);