static apr_status_t serf_copy_read()

in buckets/copy_buckets.c [80:154]


static apr_status_t serf_copy_read(serf_bucket_t *bucket,
                                   apr_size_t requested,
                                   const char **data, apr_size_t *len)
{
    copy_context_t *ctx = bucket->data;
    apr_status_t status;
    const char *wdata;
    apr_size_t peek_len;
    apr_size_t fetched;

    status = serf_bucket_peek(ctx->wrapped, &wdata, &peek_len);

    if (SERF_BUCKET_READ_ERROR(status)) {
        *len = 0;
        return status;
    }

    /* Can we just return the peeked result? */
    if (status || requested <= peek_len || ctx->min_size <= peek_len) {

        return serf_bucket_read(ctx->wrapped, requested, data, len);
    }

    /* Reduce requested to fit in our buffer */
    if (requested > ctx->min_size)
        requested = ctx->min_size;

    fetched = 0;
    while (fetched < requested) {
        struct iovec vecs[16];
        int vecs_used;
        apr_size_t read;

        status = serf_bucket_read_iovec(ctx->wrapped, requested - fetched,
                                        16, vecs, &vecs_used);

        if (SERF_BUCKET_READ_ERROR(status)) {
            if (fetched > 0)
                status = APR_EAGAIN;
            break;
        }
        else if (!fetched && vecs_used == 1
                 && (status || (vecs[0].iov_len == requested))) {

            /* Easy out
                * We don't have anything stashed
                * We only have one buffer to return
                * And either
                    - We can't read any further at this time
                    - Or the buffer is already filled
             */

            *data = vecs[0].iov_base;
            *len = vecs[0].iov_len;
            return status;
        }
        else if (!ctx->hold_buf && vecs_used > 0) {
            /* We have something that we want to store */

            ctx->hold_buf = serf_bucket_mem_alloc(bucket->allocator,
                                                  ctx->min_size);
        }

        serf__copy_iovec(ctx->hold_buf + fetched, &read, vecs, vecs_used);
        fetched += read;

        if (status)
            break;
    }

    *data = ctx->hold_buf;
    *len = fetched;

    return status;
}