From: Ryan Bloom Date: Sat, 7 Oct 2000 05:41:59 +0000 (+0000) Subject: The newest incarnation of http_filter. This is far from perfect, but it X-Git-Tag: APACHE_2_0_ALPHA_7~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bf4966e64c525951303d5543ab2f6eddf947424c;p=apache The newest incarnation of http_filter. This is far from perfect, but it is a step in the right direction. The idea is that the http_filter knows about the http protocol. So, it uses that knowledge to discover HTTP request headers, and sends those headers up to getline. However, it keeps the request body saved in it's ctx pointer. Later, when ap_get_client_block is called, we have set the remaining field in the conn_rec. This tells the http_filter how much of the remaining data is request body, and how much isn't. So, the http_filter can return the request body unparsed up throught ap_get_client_block. This doesn't even try to work with chunked input data, and there are still some other bugs in it, but it works for small-ish files in my tests, and it lets other people play with the concept of input filters. I will try to play with this more, but others should feel free to hack around in it too. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86426 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/httpd.h b/include/httpd.h index 77f7c7ca63..c2c2d21bf9 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -887,6 +887,9 @@ 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/modules/http/http_protocol.c b/modules/http/http_protocol.c index e62322497e..55420dcdb5 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -856,6 +856,10 @@ API_EXPORT(const char *) ap_method_name_of(int methnum) return AP_HTTP_METHODS[methnum]; } +typedef struct http_filter_ctx { + ap_bucket_brigade *b; + int c_len; +} http_ctx_t; int http_filter(ap_filter_t *f, ap_bucket_brigade *b) { #define ASCII_CR '\015' @@ -864,8 +868,47 @@ int http_filter(ap_filter_t *f, ap_bucket_brigade *b) char *buff; int length; char *pos; + int state = 0; + http_ctx_t *ctx = f->ctx; + ap_bucket_brigade *bb; + + + if (!ctx) { + f->ctx = ctx = apr_pcalloc(f->c->pool, sizeof(*ctx)); + ap_get_brigade(f->next, b); + } + else { + if (ctx->b) { + AP_BRIGADE_CONCAT(b, ctx->b); + ctx->b = NULL; + } + else { + ap_get_brigade(f->next, b); + } + } - ap_get_brigade(f->next, b); + if (f->c->remaining > 0) { + int remain = f->c->remaining; + e = AP_BRIGADE_FIRST(b); + while (remain > e->length && e != AP_BRIGADE_SENTINEL(b)) { + remain -= e->length; + e = AP_BUCKET_NEXT(e); + } + if (e != AP_BRIGADE_SENTINEL(b)) { + if (remain <= e->length) { + e->split(e, remain); + remain = 0; + } + bb = ap_brigade_split(b, AP_BUCKET_NEXT(e)); + f->c->remaining = remain; + ctx->b = bb; + return length; + } + else { + ctx->b = NULL; + return length; + } + } AP_BRIGADE_FOREACH(e, b) { @@ -873,11 +916,28 @@ int http_filter(ap_filter_t *f, ap_bucket_brigade *b) pos = buff + 1; while (pos < buff + length) { + + /* We are at the start of one line, but it actually has data. */ + if ((*pos != ASCII_LF) && (*pos != ASCII_CR)) { + state = 0; + } + else { + if (*pos == ASCII_LF) { + state++; + } + } + if ((*pos == ASCII_LF) && (*(pos - 1) == ASCII_CR)) { *(pos - 1) = ASCII_LF; *pos = '\0'; } pos++; + if (state == 2) { + e->split(e, pos - buff); + bb = ap_brigade_split(b, AP_BUCKET_NEXT(e)); + ctx->b = bb; + return length; + } } } return APR_SUCCESS; @@ -2266,6 +2326,7 @@ 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) && @@ -2378,20 +2439,31 @@ API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz) const char *tempbuf; len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining; - if (AP_BRIGADE_EMPTY(r->connection->input_data)) { - apr_getsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, &timeout); - apr_setsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, 0); - rv = ap_get_brigade(r->connection->input_filters, r->connection->input_data); - apr_setsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, timeout); - } - if (AP_BRIGADE_EMPTY(r->connection->input_data)) { - if (rv != APR_SUCCESS) { - r->connection->keepalive = -1; - return -1; + + do { + if (AP_BRIGADE_EMPTY(r->connection->input_data)) { + apr_getsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, &timeout); + apr_setsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, 0); + rv = ap_get_brigade(r->connection->input_filters, r->connection->input_data); + apr_setsocketopt(r->connection->client->bsock, APR_SO_TIMEOUT, timeout); } - return 0; - } - b = AP_BRIGADE_FIRST(r->connection->input_data); + if (AP_BRIGADE_EMPTY(r->connection->input_data)) { + if (rv != APR_SUCCESS) { + r->connection->keepalive = -1; + return -1; + } + return 0; + } + b = AP_BRIGADE_FIRST(r->connection->input_data); + + while (b->length == 0 && b != AP_BRIGADE_SENTINEL(r->connection->input_data)) { + ap_bucket *e = b; + b = AP_BUCKET_NEXT(e); + AP_BUCKET_REMOVE(e); + e->destroy(e); + } + } while (AP_BRIGADE_EMPTY(r->connection->input_data)); + len_read = len_to_read; rv = b->read(b, &tempbuf, &len_read, 0); if (len_to_read < b->length) {