in buckets/copy_buckets.c [170:265]
static apr_status_t serf_copy_read_iovec(serf_bucket_t *bucket,
apr_size_t requested,
int vecs_size,
struct iovec *vecs,
int *vecs_used)
{
copy_context_t *ctx = bucket->data;
apr_status_t status;
apr_size_t total;
apr_size_t fetched;
int i;
/* If somebody really wants to call us for 1 iovec, call the function
that already implements the copying for this */
if (vecs_size == 1) {
const char *data;
apr_size_t len;
*vecs_used = 1;
status = serf_copy_read(bucket, requested, &data, &len);
vecs[0].iov_base = (void*)data;
vecs[0].iov_len = len;
*vecs_used = 1;
return status;
}
status = serf_bucket_read_iovec(ctx->wrapped, requested,
vecs_size, vecs, vecs_used);
/* There are four possible results:
EOF: if the wrapped bucket is done, then we must be done, too. it is
quite possible we'll return less than MIN_SIZE, but with EOF, there
is no way we'll be able to return that.
EAGAIN: we cannot possibly read more (right now), so return. whatever
was read, it is all we have, whether we met MIN_SIZE or not.
error: any other error will prevent us from further work; return it.
SUCCESS: we read a portion, and the bucket says we can read more.
For all but SUCCESS, we simply return the status. We're done now. */
if (status)
return status;
/* How much was read on this pass? */
for (total = 0, i = *vecs_used; i-- > 0; )
total += vecs[i].iov_len;
/* The IOVEC holds at least MIN_SIZE data, so we're good. Or, it
holds precisely the amount requested, so we shouldn't try to
gather/accumulate more data. */
if (total >= ctx->min_size || total == requested)
return APR_SUCCESS;
/* TOTAL < REQUESTED. TOTAL < MIN_SIZE. We should try and fetch more. */
/* Copy what we have into our buffer. Then continue reading to get at
least MIN_SIZE or REQUESTED bytes of data. */
if (! ctx->hold_buf)
ctx->hold_buf = serf_bucket_mem_alloc(bucket->allocator,
ctx->min_size);
/* ### copy into HOLD_BUF. then read/append some more. */
fetched = total;
serf__copy_iovec(ctx->hold_buf, NULL, vecs, *vecs_used);
/* ### point vecs[0] at HOLD_BUF. */
vecs[0].iov_base = ctx->hold_buf;
vecs[0].iov_len = fetched;
while (TRUE) {
int v_used;
status = serf_bucket_read_iovec(ctx->wrapped, requested - fetched,
vecs_size - 1, &vecs[1], &v_used);
if (SERF_BUCKET_READ_ERROR(status)) {
*vecs_used = 1;
return APR_EAGAIN;
}
for (i = 1; i <= v_used; i++)
total += vecs[i].iov_len;
if (status || total >= ctx->min_size || total == requested) {
*vecs_used = v_used + 1;
return status;
}
serf__copy_iovec(ctx->hold_buf + fetched, NULL, &vecs[1], v_used);
fetched += total;
vecs[0].iov_len = fetched;
}
}