Index: buckets/response_buckets.c =================================================================== --- buckets/response_buckets.c (revision 1674) +++ buckets/response_buckets.c (working copy) @@ -41,6 +41,12 @@ typedef struct { int chunked; /* Do we need to read trailers? */ int head_req; /* Was this a HEAD request? */ + + int check_length; /* Indicates we need calculate # of bytes in the + body and return error if it's too short. */ + apr_size_t exp_body_len; /* expected size of body, 0 if not known. */ + apr_size_t actual_body_len; /* Keep track of actual bytes read from the body + to see if we received the full response. */ } response_context_t; @@ -57,6 +63,9 @@ serf_bucket_t *serf_bucket_response_create( ctx->state = STATE_STATUS_LINE; ctx->chunked = 0; ctx->head_req = 0; + ctx->check_length = 0; + ctx->exp_body_len = 0; + ctx->actual_body_len = 0; serf_linebuf_init(&ctx->linebuf); @@ -251,6 +260,8 @@ static apr_status_t run_machine(serf_bucket_t *bkt } ctx->body = serf_bucket_limit_create(ctx->body, length, bkt->allocator); + ctx->check_length = 1; + ctx->exp_body_len = length; } else { v = serf_bucket_headers_get(ctx->headers, "Transfer-Encoding"); @@ -268,6 +279,8 @@ static apr_status_t run_machine(serf_bucket_t *bkt } v = serf_bucket_headers_get(ctx->headers, "Content-Encoding"); if (v) { + ctx->check_length = 0; /* deflate bucket will check this. */ + /* Need to handle multiple content-encoding. */ if (v && strcasecmp("gzip", v) == 0) { ctx->body = @@ -385,6 +398,12 @@ static apr_status_t serf_response_read(serf_bucket } rv = serf_bucket_read(ctx->body, requested, data, len); + if (SERF_BUCKET_READ_ERROR(rv)) + return rv; + + if (ctx->check_length) + ctx->actual_body_len += *len; + if (APR_STATUS_IS_EOF(rv)) { if (ctx->chunked) { ctx->state = STATE_TRAILERS; @@ -392,6 +411,8 @@ static apr_status_t serf_response_read(serf_bucket rv = APR_SUCCESS; } else { + if (ctx->check_length && ctx->actual_body_len < ctx->exp_body_len) + return SERF_ERROR_BAD_HTTP_RESPONSE; ctx->state = STATE_DONE; } }