static apr_status_t refill_output()

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;
            }
        }
    }
}