From: Ryan Bloom Date: Thu, 12 Oct 2000 16:35:39 +0000 (+0000) Subject: Implement a length argument on input filters. There are three possible X-Git-Tag: APACHE_2_0_ALPHA_8~385 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c27033df766451cb3e3c19a251e6ffb777dbf9bd;p=apache Implement a length argument on input filters. There are three possible values for the length, -1, 0, and a positive number. -1 means that the next filter should return all the data it has, the current filter will take care to ensure that the protocol is followed. Most filters will never use this, because it implies they are implementing a conn_based input filter. 0 means give me exactly one line of data. A positive number means give me a maximum of n bytes. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86567 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/http_protocol.h b/include/http_protocol.h index 1900d36c6d..789ba228ed 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -529,7 +529,7 @@ API_EXPORT(int) ap_method_number_of(const char *method); */ API_EXPORT(const char *) ap_method_name_of(int methnum); -int http_filter(ap_filter_t *f, ap_bucket_brigade *b); +int http_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length); /* Hooks */ /* diff --git a/include/httpd.h b/include/httpd.h index fe63ab82be..9f6fe25e90 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -906,8 +906,6 @@ struct conn_rec { /** A list of output filters to be used for this connection * @defvar ap_filter_t *filters */ struct ap_filter_t *output_filters; - /** bytes left to read in the current request body */ - long remaining; }; /* Per-vhost config... */ diff --git a/include/util_filter.h b/include/util_filter.h index f6b3791f19..927880374a 100644 --- a/include/util_filter.h +++ b/include/util_filter.h @@ -74,6 +74,12 @@ extern "C" { #define AP_NOBODY_WROTE -1 #define AP_NOBODY_READ -2 +/* Input filtering macros */ +#define AP_GET_LINE 0 /* Get one line from the next filter */ +#define AP_GET_ANY_AMOUNT -1 /* Get as much data as the next filter + * is willing to give up. + */ + /* * FILTER CHAIN * @@ -125,7 +131,12 @@ typedef struct ap_filter_t ap_filter_t; * * The return value of a filter should be an APR status value. */ -typedef apr_status_t (*ap_filter_func)(ap_filter_t *f, ap_bucket_brigade *b); +typedef apr_status_t (*ap_out_filter_func)(ap_filter_t *f, ap_bucket_brigade *b); +typedef apr_status_t (*ap_in_filter_func)(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length); +typedef union ap_filter_func { + ap_out_filter_func out_func; + ap_in_filter_func in_func; +} ap_filter_func; /* * ap_filter_type: @@ -232,10 +243,19 @@ struct ap_filter_t { * filter doesn't write to the network, then AP_NOBODY_READ is returned. * @param filter The next filter in the chain * @param bucket The current bucket brigade + * @param length The maximum amount of data to be returned from the next + * lowest filter. If filter a requests 15 bytes + * from the filter b, that doesn't stop the b + * from requesting 30 bytes from filter c. It just + * stops b from returning more that 15 bytes to a. The other + * 15 must be stored by b. A value of AP_GET_LINE (0) tells + * the filter to only ever return a single line. A value of + * AP_GET_ANY_AMOUNT (-1) tells a filter to return everything + * it has. * @return apr_status_t value - * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket) + * @deffunc apr_status_t ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, int length) */ -API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket); +API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *filter, ap_bucket_brigade *bucket, int length); /** * Pass the current bucket brigade down to the next filter on the filter @@ -264,10 +284,10 @@ API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *filter, ap_bucket_brigade * @param name The name to attach to the filter function * @param filter_func The filter function to name * @param The type of filter function, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION - * @deffunc void ap_register_input_filter(const char *name, ap_filter_func filter_func, ap_filter_type ftype) + * @deffunc void ap_register_input_filter(const char *name, ap_in_filter_func filter_func, ap_filter_type ftype) */ API_EXPORT(void) ap_register_input_filter(const char *name, - ap_filter_func filter_func, + ap_in_filter_func filter_func, ap_filter_type ftype); /* * ap_register_output_filter(): @@ -285,10 +305,10 @@ API_EXPORT(void) ap_register_input_filter(const char *name, * @param name The name to attach to the filter function * @param filter_func The filter function to name * @param The type of filter function, either AP_FTYPE_CONTENT or AP_FTYPE_CONNECTION - * @deffunc void ap_register_output_filter(const char *name, ap_filter_func filter_func, ap_filter_type ftype) + * @deffunc void ap_register_output_filter(const char *name, ap_out_filter_func filter_func, ap_filter_type ftype) */ API_EXPORT(void) ap_register_output_filter(const char *name, - ap_filter_func filter_func, + ap_out_filter_func filter_func, ap_filter_type ftype); /* diff --git a/modules/http/http_core.c b/modules/http/http_core.c index d71a5bc589..2c3329dda5 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -3303,7 +3303,12 @@ static apr_status_t chunk_filter(ap_filter_t *f, ap_bucket_brigade *b) return APR_SUCCESS; } -static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b) +/* This function only understands a length of AP_GET_ANY_AMOUNT. It will + * ignore length values and always return the entire brigade. This is + * pretty safe to do, because we know there always needs to be an intervening + * filter just above this that will only make requests for AP_GET_ANY_AMOUNT + */ +static int core_input_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length) { apr_socket_t *csock = NULL; ap_bucket *e; diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 6228f25239..814c12e6d3 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -860,13 +860,13 @@ typedef struct http_filter_ctx { ap_bucket_brigade *b; } http_ctx_t; -apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b) +apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b, apr_ssize_t length) { #define ASCII_CR '\015' #define ASCII_LF '\012' ap_bucket *e; char *buff; - apr_ssize_t length; + apr_ssize_t len; char *pos; http_ctx_t *ctx = f->ctx; ap_bucket_brigade *bb; @@ -874,7 +874,7 @@ apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b) if (!ctx) { f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx)); - if ((rv = ap_get_brigade(f->next, b)) != APR_SUCCESS) { + if ((rv = ap_get_brigade(f->next, b, AP_GET_ANY_AMOUNT)) != APR_SUCCESS) { return rv; } } @@ -884,14 +884,14 @@ apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b) ctx->b = NULL; /* XXX we just leaked a brigade structure */ } else { - if ((rv = ap_get_brigade(f->next, b)) != APR_SUCCESS) { + if ((rv = ap_get_brigade(f->next, b, AP_GET_LINE)) != APR_SUCCESS) { return rv; } } } - if (f->c->remaining > 0) { - int remain = f->c->remaining; + if (length > 0) { + int remain = length; e = AP_BRIGADE_FIRST(b); while (remain > e->length && e != AP_BRIGADE_SENTINEL(b)) { remain -= e->length; @@ -903,24 +903,22 @@ apr_status_t http_filter(ap_filter_t *f, ap_bucket_brigade *b) remain = 0; } bb = ap_brigade_split(b, AP_BUCKET_NEXT(e)); - f->c->remaining = remain; ctx->b = bb; return APR_SUCCESS; } else { - f->c->remaining = remain; ctx->b = NULL; return APR_SUCCESS; } } AP_BRIGADE_FOREACH(e, b) { - if ((rv = e->read(e, (const char **)&buff, &length, 0)) != APR_SUCCESS) { + if ((rv = e->read(e, (const char **)&buff, &len, 0)) != APR_SUCCESS) { return rv; } pos = buff; - while (pos < buff + length) { + while (pos < buff + len) { if (*pos == ASCII_LF) { e->split(e, pos - buff + 1); bb = ap_brigade_split(b, AP_BUCKET_NEXT(e)); @@ -960,7 +958,7 @@ static int getline(char *s, int n, conn_rec *c, int fold) while (1) { if (AP_BRIGADE_EMPTY(b)) { - if (ap_get_brigade(c->input_filters, b) != APR_SUCCESS) { + if (ap_get_brigade(c->input_filters, b, AP_GET_LINE) != APR_SUCCESS) { return -1; } } @@ -2286,7 +2284,6 @@ API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy) } r->remaining = atol(lenp); - r->connection->remaining = r->remaining; } if ((r->read_body == REQUEST_NO_BODY) && @@ -2407,8 +2404,7 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz) if (AP_BRIGADE_EMPTY(bb)) { apr_getsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, &timeout); apr_setsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, 0); - r->connection->remaining = len_to_read; - if (ap_get_brigade(r->input_filters, bb) != APR_SUCCESS) { + if (ap_get_brigade(r->input_filters, bb, len_to_read) != APR_SUCCESS) { /* if we actually fail here, we want to just return and * stop trying to read data from the client. */ diff --git a/server/util_filter.c b/server/util_filter.c index 14ef6553d0..9be310b5cc 100644 --- a/server/util_filter.c +++ b/server/util_filter.c @@ -103,18 +103,22 @@ static void register_filter(const char *name, } API_EXPORT(void) ap_register_input_filter(const char *name, - ap_filter_func filter_func, + ap_in_filter_func filter_func, ap_filter_type ftype) { - register_filter(name, filter_func, ftype, + ap_filter_func f; + f.in_func = filter_func; + register_filter(name, f, ftype, ®istered_input_filters); } API_EXPORT(void) ap_register_output_filter(const char *name, - ap_filter_func filter_func, + ap_out_filter_func filter_func, ap_filter_type ftype) { - register_filter(name, filter_func, ftype, + ap_filter_func f; + f.out_func = filter_func; + register_filter(name, f, ftype, ®istered_output_filters); } @@ -191,10 +195,11 @@ API_EXPORT(void) ap_add_output_filter(const char *name, void *ctx, * save data off to the side should probably create their own temporary * brigade especially for that use. */ -API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *next, ap_bucket_brigade *bb) +API_EXPORT(apr_status_t) ap_get_brigade(ap_filter_t *next, + ap_bucket_brigade *bb, int length) { if (next) { - return next->frec->filter_func(next, bb); + return next->frec->filter_func.in_func(next, bb, length); } return AP_NOBODY_READ; } @@ -210,7 +215,7 @@ API_EXPORT(apr_status_t) ap_pass_brigade(ap_filter_t *next, ap_bucket_brigade *b if (AP_BRIGADE_LAST(bb)->type == AP_BUCKET_EOS && next->r) { next->r->eos_sent = 1; } - return next->frec->filter_func(next, bb); + return next->frec->filter_func.out_func(next, bb); } return AP_NOBODY_WROTE; }