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