Author: rhuijben Date: Wed Nov 11 14:36:21 2015 New Revision: 1713852 URL: http://svn.apache.org/viewvc?rev=1713852&view=rev Log: In preparation for improving the capabilities of the deflate stream, split the serf_deflate_read() function in 3 functions that now call each other. No functional changes yet.
* buckets/deflate_buckets.c (deflate_read3, deflate_read2): New functions, extracted from... (serf_deflate_read): ... here. Call deflate_read2. Modified: serf/trunk/buckets/deflate_buckets.c Modified: serf/trunk/buckets/deflate_buckets.c URL: http://svn.apache.org/viewvc/serf/trunk/buckets/deflate_buckets.c?rev=1713852&r1=1713851&r2=1713852&view=diff ============================================================================== --- serf/trunk/buckets/deflate_buckets.c (original) +++ serf/trunk/buckets/deflate_buckets.c Wed Nov 11 14:36:21 2015 @@ -146,7 +146,195 @@ static void serf_deflate_destroy_and_dat serf_default_destroy_and_data(bucket); } -static apr_status_t serf_deflate_read(serf_bucket_t *bucket, +static apr_status_t deflate_read3(serf_bucket_t *bucket, + apr_size_t requested, + const char **data, + apr_size_t *len) +{ + deflate_context_t *ctx = bucket->data; + apr_status_t status; + int zRC; + + /* Do we have anything already uncompressed to read? */ + status = serf_bucket_read(ctx->inflate_stream, requested, data, + len); + if (SERF_BUCKET_READ_ERROR(status)) { + return status; + } + /* Hide EOF. */ + if (APR_STATUS_IS_EOF(status)) { + status = ctx->stream_status; + if (APR_STATUS_IS_EOF(status)) { + /* We've read all of the data from our stream, but we + * need to continue to iterate until we flush + * out the zlib buffer. + */ + status = APR_SUCCESS; + } + } + if (*len != 0) { + return status; + } + + /* We tried; but we have nothing buffered. Fetch more. */ + + /* It is possible that we maxed out avail_out before + * exhausting avail_in; therefore, continue using the + * previous buffer. Otherwise, fetch more data from + * our stream bucket. + */ + if (ctx->zstream.avail_in == 0) { + const char *private_data; + apr_size_t private_len; + + /* When we empty our inflated stream, we'll return this + * status - this allow us to eventually pass up EAGAINs. + */ + ctx->stream_status = serf_bucket_read(ctx->stream, + ctx->bufferSize, + &private_data, + &private_len); + + if (SERF_BUCKET_READ_ERROR(ctx->stream_status)) { + return ctx->stream_status; + } + + if (!private_len && APR_STATUS_IS_EAGAIN(ctx->stream_status)) { + *len = 0; + status = ctx->stream_status; + ctx->stream_status = APR_SUCCESS; + return status; + } + + /* Make valgrind happy and explictly initialize next_in to specific + * value for empty buffer. */ + if (private_len) { + ctx->zstream.next_in = (unsigned char*)private_data; + ctx->zstream.avail_in = private_len; + } else { + ctx->zstream.next_in = Z_NULL; + ctx->zstream.avail_in = 0; + } + } + + while (1) { + + zRC = inflate(&ctx->zstream, Z_NO_FLUSH); + + /* We're full or zlib requires more space. Either case, clear + out our buffer, reset, and return. */ + if (zRC == Z_BUF_ERROR || ctx->zstream.avail_out == 0) { + apr_size_t private_len; + serf_bucket_t *tmp; + + ctx->zstream.next_out = ctx->buffer; + private_len = ctx->bufferSize - ctx->zstream.avail_out; + + ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, + private_len); + + /* FIXME: There probably needs to be a free func. */ + tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer, + private_len, + bucket->allocator); + serf_bucket_aggregate_append(ctx->inflate_stream, tmp); + ctx->zstream.avail_out = ctx->bufferSize; + break; + } + + if (zRC == Z_STREAM_END) { + apr_size_t private_len; + serf_bucket_t *tmp; + + private_len = ctx->bufferSize - ctx->zstream.avail_out; + ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, + private_len); + /* FIXME: There probably needs to be a free func. */ + tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer, + private_len, + bucket->allocator); + serf_bucket_aggregate_append(ctx->inflate_stream, tmp); + + ctx->zstream.avail_out = ctx->bufferSize; + + /* Push back the remaining data to be read. */ + tmp = serf_bucket_aggregate_create(bucket->allocator); + serf_bucket_set_config(tmp, ctx->config); + serf_bucket_aggregate_prepend(tmp, ctx->stream); + ctx->stream = tmp; + + /* We now need to take the remaining avail_in and + * throw it in ctx->stream so our next read picks it up. + */ + tmp = SERF_BUCKET_SIMPLE_STRING_LEN( + (const char*)ctx->zstream.next_in, + ctx->zstream.avail_in, + bucket->allocator); + serf_bucket_aggregate_prepend(ctx->stream, tmp); + + switch (ctx->format) { + case SERF_DEFLATE_GZIP: + ctx->stream_left = ctx->stream_size = + DEFLATE_VERIFY_SIZE; + ctx->state++; + break; + case SERF_DEFLATE_DEFLATE: + /* Deflate does not have a verify footer. */ + ctx->state = STATE_FINISH; + break; + default: + /* Not reachable */ + return APR_EGENERAL; + } + + break; + } + + /* Any other error? */ + if (zRC != Z_OK) { + serf__log(LOGLVL_ERROR, LOGCOMP_COMPR, __FILE__, + ctx->config, "inflate error %d - %s\n", + zRC, ctx->zstream.msg); + return SERF_ERROR_DECOMPRESSION_FAILED; + } + + /* As long as zRC == Z_OK, just keep looping. */ + } + /* Okay, we've inflated. Try to read. */ + status = serf_bucket_read(ctx->inflate_stream, requested, data, + len); + /* Hide EOF. */ + if (APR_STATUS_IS_EOF(status)) { + status = ctx->stream_status; + + /* If the inflation wasn't finished, return APR_SUCCESS. */ + if (zRC != Z_STREAM_END) + return APR_SUCCESS; + + /* If our stream is finished too and all data was inflated, + * return SUCCESS so we'll iterate one more time. + */ + if (APR_STATUS_IS_EOF(status)) { + /* No more data to read from the stream, and everything + inflated. If all data was received correctly, state + should have been advanced to STATE_READING_VERIFY or + STATE_FINISH. If not, then the data was incomplete + and we have an error. */ + if (ctx->state != STATE_INFLATE) + return APR_SUCCESS; + else { + serf__log(LOGLVL_ERROR, LOGCOMP_COMPR, __FILE__, + ctx->config, + "Unexpected EOF on input stream\n"); + return SERF_ERROR_DECOMPRESSION_FAILED; + } + } + } + + return status; +} + +static apr_status_t deflate_read2(serf_bucket_t *bucket, apr_size_t requested, const char **data, apr_size_t *len) { @@ -252,176 +440,7 @@ static apr_status_t serf_deflate_read(se ctx->state++; break; case STATE_INFLATE: - /* Do we have anything already uncompressed to read? */ - status = serf_bucket_read(ctx->inflate_stream, requested, data, - len); - if (SERF_BUCKET_READ_ERROR(status)) { - return status; - } - /* Hide EOF. */ - if (APR_STATUS_IS_EOF(status)) { - status = ctx->stream_status; - if (APR_STATUS_IS_EOF(status)) { - /* We've read all of the data from our stream, but we - * need to continue to iterate until we flush - * out the zlib buffer. - */ - status = APR_SUCCESS; - } - } - if (*len != 0) { - return status; - } - - /* We tried; but we have nothing buffered. Fetch more. */ - - /* It is possible that we maxed out avail_out before - * exhausting avail_in; therefore, continue using the - * previous buffer. Otherwise, fetch more data from - * our stream bucket. - */ - if (ctx->zstream.avail_in == 0) { - /* When we empty our inflated stream, we'll return this - * status - this allow us to eventually pass up EAGAINs. - */ - ctx->stream_status = serf_bucket_read(ctx->stream, - ctx->bufferSize, - &private_data, - &private_len); - - if (SERF_BUCKET_READ_ERROR(ctx->stream_status)) { - return ctx->stream_status; - } - - if (!private_len && APR_STATUS_IS_EAGAIN(ctx->stream_status)) { - *len = 0; - status = ctx->stream_status; - ctx->stream_status = APR_SUCCESS; - return status; - } - - /* Make valgrind happy and explictly initialize next_in to specific - * value for empty buffer. */ - if (private_len) { - ctx->zstream.next_in = (unsigned char*)private_data; - ctx->zstream.avail_in = private_len; - } else { - ctx->zstream.next_in = Z_NULL; - ctx->zstream.avail_in = 0; - } - } - - while (1) { - - zRC = inflate(&ctx->zstream, Z_NO_FLUSH); - - /* We're full or zlib requires more space. Either case, clear - out our buffer, reset, and return. */ - if (zRC == Z_BUF_ERROR || ctx->zstream.avail_out == 0) { - serf_bucket_t *tmp; - ctx->zstream.next_out = ctx->buffer; - private_len = ctx->bufferSize - ctx->zstream.avail_out; - - ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, - private_len); - - /* FIXME: There probably needs to be a free func. */ - tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer, - private_len, - bucket->allocator); - serf_bucket_aggregate_append(ctx->inflate_stream, tmp); - ctx->zstream.avail_out = ctx->bufferSize; - break; - } - - if (zRC == Z_STREAM_END) { - serf_bucket_t *tmp; - - private_len = ctx->bufferSize - ctx->zstream.avail_out; - ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, - private_len); - /* FIXME: There probably needs to be a free func. */ - tmp = SERF_BUCKET_SIMPLE_STRING_LEN((char *)ctx->buffer, - private_len, - bucket->allocator); - serf_bucket_aggregate_append(ctx->inflate_stream, tmp); - - ctx->zstream.avail_out = ctx->bufferSize; - - /* Push back the remaining data to be read. */ - tmp = serf_bucket_aggregate_create(bucket->allocator); - serf_bucket_set_config(tmp, ctx->config); - serf_bucket_aggregate_prepend(tmp, ctx->stream); - ctx->stream = tmp; - - /* We now need to take the remaining avail_in and - * throw it in ctx->stream so our next read picks it up. - */ - tmp = SERF_BUCKET_SIMPLE_STRING_LEN( - (const char*)ctx->zstream.next_in, - ctx->zstream.avail_in, - bucket->allocator); - serf_bucket_aggregate_prepend(ctx->stream, tmp); - - switch (ctx->format) { - case SERF_DEFLATE_GZIP: - ctx->stream_left = ctx->stream_size = - DEFLATE_VERIFY_SIZE; - ctx->state++; - break; - case SERF_DEFLATE_DEFLATE: - /* Deflate does not have a verify footer. */ - ctx->state = STATE_FINISH; - break; - default: - /* Not reachable */ - return APR_EGENERAL; - } - - break; - } - - /* Any other error? */ - if (zRC != Z_OK) { - serf__log(LOGLVL_ERROR, LOGCOMP_COMPR, __FILE__, - ctx->config, "inflate error %d - %s\n", - zRC, ctx->zstream.msg); - return SERF_ERROR_DECOMPRESSION_FAILED; - } - - /* As long as zRC == Z_OK, just keep looping. */ - } - /* Okay, we've inflated. Try to read. */ - status = serf_bucket_read(ctx->inflate_stream, requested, data, - len); - /* Hide EOF. */ - if (APR_STATUS_IS_EOF(status)) { - status = ctx->stream_status; - - /* If the inflation wasn't finished, return APR_SUCCESS. */ - if (zRC != Z_STREAM_END) - return APR_SUCCESS; - - /* If our stream is finished too and all data was inflated, - * return SUCCESS so we'll iterate one more time. - */ - if (APR_STATUS_IS_EOF(status)) { - /* No more data to read from the stream, and everything - inflated. If all data was received correctly, state - should have been advanced to STATE_READING_VERIFY or - STATE_FINISH. If not, then the data was incomplete - and we have an error. */ - if (ctx->state != STATE_INFLATE) - return APR_SUCCESS; - else { - serf__log(LOGLVL_ERROR, LOGCOMP_COMPR, __FILE__, - ctx->config, - "Unexpected EOF on input stream\n"); - return SERF_ERROR_DECOMPRESSION_FAILED; - } - } - } - return status; + return deflate_read3(bucket, requested, data, len); case STATE_DONE: /* We're done inflating. Use our finished buffer. */ return serf_bucket_read(ctx->stream, requested, data, len); @@ -434,6 +453,13 @@ static apr_status_t serf_deflate_read(se /* NOTREACHED */ } +static apr_status_t serf_deflate_read(serf_bucket_t *bucket, + apr_size_t requested, + const char **data, apr_size_t *len) +{ + return deflate_read2(bucket, requested, data, len); +} + static apr_status_t serf_deflate_set_config(serf_bucket_t *bucket, serf_config_t *config) {