On 01/06/2008 11:39 AM, Ruediger Pluem wrote: > > On 01/06/2008 02:20 AM, Nick Kew wrote: >> On Sat, 05 Jan 2008 20:28:33 +0100 >> Ruediger Pluem <[EMAIL PROTECTED]> wrote: >> >>> On 01/05/2008 07:04 PM, Nick Kew wrote: >>>> On Sat, 05 Jan 2008 12:38:58 +0100 >>>> Ruediger Pluem <[EMAIL PROTECTED]> wrote: >>>> >>>>> Ok. Can you setup a tcpdump between proxy and server and between >>>>> client and proxy? I guess the network traces would be very helpful >>>>> in finding out where things are starting to get wrong. >>>> One testcase with its tcpdump at >>>> http://people.apache.org/~niq/2.2.7/ >>> Thanks for this, but I think this is not sufficient: >>> >>> 1. It seems the dump is incomplete as I cannot see a 0 chunk at the >>> end. 2. I would prefer the binary dump as it offers more >>> possibilities to analyse it with wireshark. >>> >>> Sorry for being that demanding :-) >> Do you mean as in tcpdump -x? I've uploaded a pair of dumps >> (one of client-proxy, the other of proxy-server) at the same >> location. > >
Ok, next one. I missed to set the correct state in some situations. Can you please give it a try again? Regards RĂ¼diger
Index: modules/http/http_filters.c =================================================================== --- modules/http/http_filters.c (Revision 609355) +++ modules/http/http_filters.c (Arbeitskopie) @@ -68,8 +68,43 @@ BODY_CHUNK_PART } state; int eos_sent; + char chunk_ln[30]; + char *pos; } http_ctx_t; +static apr_status_t get_chunk_line(http_ctx_t *ctx, int len) +{ + /* + * Check if we do not overflow our chunksize / empty line buffer + * (ctx->chunk_ln). If we do the chunksize / empty line is bogus anyway so + * bail out in this case. + * XXX: Currently we are very limited in accepting chunk-extensions. If + * this is needed the chunk_ln buffer must be much larger or we must + * find a different way to discard them as we do not process them anyway. + */ + if ((ctx->pos - ctx->chunk_ln) + len < sizeof(ctx->chunk_ln)) { + ctx->pos += len; + *(ctx->pos) = '\0'; + /* + * Check if we really got a full line. If yes the + * last char in the just read buffer must be LF. + * If not advance the buffer and return APR_EAGAIN. + * We do not start processing until we have the + * full line. + */ + if (ctx->pos[-1] != APR_ASCII_LF) { + return APR_EAGAIN; + } + /* + * Line is complete. So reset ctx->pos for next round. + */ + ctx->pos = ctx->chunk_ln; + return APR_SUCCESS; + } + return APR_ENOSPC; +} + + /* This is the HTTP_INPUT filter for HTTP requests and responses from * proxied servers (mod_proxy). It handles chunked and content-length * bodies. This can only be inserted/used after the headers @@ -96,6 +131,7 @@ ctx->remaining = 0; ctx->limit_used = 0; ctx->eos_sent = 0; + ctx->pos = ctx->chunk_ln; /* LimitRequestBody does not apply to proxied responses. * Consider implementing this check in its own filter. @@ -227,9 +263,8 @@ /* We can't read the chunk until after sending 100 if required. */ if (ctx->state == BODY_CHUNK) { - char line[30]; apr_bucket_brigade *bb; - apr_size_t len = 30; + apr_size_t len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln); apr_off_t brigade_length; bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); @@ -256,9 +291,17 @@ rv = APR_ENOSPC; } if (rv == APR_SUCCESS) { - rv = apr_brigade_flatten(bb, line, &len); + rv = apr_brigade_flatten(bb, ctx->pos, &len); if (rv == APR_SUCCESS) { - ctx->remaining = get_chunk_size(line); + rv = get_chunk_line(ctx, len); + if (APR_STATUS_IS_EAGAIN(rv)) { + apr_brigade_cleanup(bb); + ctx->state = BODY_CHUNK_PART; + return rv; + } + if (rv == APR_SUCCESS) { + ctx->remaining = get_chunk_size(ctx->chunk_ln); + } } } } @@ -308,9 +351,9 @@ case BODY_CHUNK: case BODY_CHUNK_PART: { - char line[30]; apr_bucket_brigade *bb; - apr_size_t len = 30; + apr_size_t len = sizeof(ctx->chunk_ln) + - (ctx->pos - ctx->chunk_ln); apr_status_t http_error = HTTP_REQUEST_ENTITY_TOO_LARGE; bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); @@ -319,11 +362,21 @@ if (ctx->state == BODY_CHUNK) { rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, block, 0); - apr_brigade_cleanup(bb); if (block == APR_NONBLOCK_READ && - (APR_STATUS_IS_EAGAIN(rv))) { + ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) || + (APR_STATUS_IS_EAGAIN(rv)) )) { return APR_EAGAIN; } + rv = apr_brigade_flatten(bb, ctx->pos, &len); + apr_brigade_cleanup(bb); + if (rv == APR_SUCCESS) { + rv = get_chunk_line(ctx, len); + if (APR_STATUS_IS_EAGAIN(rv)) { + return rv; + } + } + /* Reset len */ + len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln); } else { rv = APR_SUCCESS; } @@ -341,7 +394,7 @@ } ctx->state = BODY_CHUNK; if (rv == APR_SUCCESS) { - rv = apr_brigade_flatten(bb, line, &len); + rv = apr_brigade_flatten(bb, ctx->pos, &len); if (rv == APR_SUCCESS) { /* Wait a sec, that's a blank line! Oh no. */ if (!len) { @@ -349,7 +402,15 @@ http_error = HTTP_SERVICE_UNAVAILABLE; } else { - ctx->remaining = get_chunk_size(line); + rv = get_chunk_line(ctx, len); + if (APR_STATUS_IS_EAGAIN(rv)) { + ctx->state = BODY_CHUNK_PART; + apr_brigade_cleanup(bb); + return rv; + } + if (rv == APR_SUCCESS) { + ctx->remaining = get_chunk_size(ctx->chunk_ln); + } } } }