in buckets/brotli_buckets.c [62:131]
static apr_status_t refill_output(void *baton, serf_bucket_t *aggregate_bkt)
{
brotli_decompress_context_t *ctx = baton;
while (1) {
if (ctx->pending_len == 0 && !ctx->hit_eof) {
apr_status_t status;
status = serf_bucket_read(ctx->input, SERF_READ_ALL_AVAIL,
&ctx->pending_data, &ctx->pending_len);
if (APR_STATUS_IS_EOF(status))
ctx->hit_eof = TRUE;
else if (status)
return status;
}
if (ctx->done && ctx->hit_eof && ctx->pending_len == 0) {
return APR_EOF;
}
else if (ctx->done) {
/* Finished with some input still there in the bucket, that's
* an error. */
return SERF_ERROR_DECOMPRESSION_FAILED;
}
else {
BrotliDecoderResult result;
apr_size_t avail_out = 0;
result = BrotliDecoderDecompressStream(
ctx->state, &ctx->pending_len,
(const uint8_t **)&ctx->pending_data, &avail_out,
NULL, NULL);
if (result == BROTLI_DECODER_RESULT_ERROR) {
return SERF_ERROR_DECOMPRESSION_FAILED;
}
else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
&& ctx->hit_eof) {
/* The decoder says it requires more data, but we don't have
* it. This could happen either if the input is truncated or
* corrupted, but as we don't know for sure, return a generic
* error. */
return SERF_ERROR_DECOMPRESSION_FAILED;
}
else if (result == BROTLI_DECODER_RESULT_SUCCESS
&& !BrotliDecoderHasMoreOutput(ctx->state)) {
ctx->done = TRUE;
}
if (BrotliDecoderHasMoreOutput(ctx->state)) {
serf_bucket_t *output_bkt;
const uint8_t *output;
apr_size_t output_len = 0;
/* There is some output for us. Place it into the aggregate
* bucket, and avoid making a copy by wrapping a pointer to
* the internal output buffer. This data is valid until the
* next call to BrotliDecoderDecompressStream(), which won't
* happen until this bucket is read. */
output = BrotliDecoderTakeOutput(ctx->state, &output_len);
output_bkt = serf_bucket_simple_create((const char *)output,
output_len, NULL, NULL,
aggregate_bkt->allocator);
serf_bucket_aggregate_append(aggregate_bkt, output_bkt);
return APR_SUCCESS;
}
}
}
}