in protocols/http2_stream.c [221:313]
static apr_status_t stream_send_data(serf_http2_stream_t *stream,
serf_bucket_t *data)
{
apr_uint64_t remaining;
serf_bucket_t *next;
apr_size_t prefix_len;
bool end_stream;
apr_status_t status;
SERF_H2_assert(stream->status == H2S_OPEN
|| stream->status == H2S_HALFCLOSED_REMOTE);
SERF_H2_assert(!stream->data->data_tail || (data ==
stream->data->data_tail));
/* Sending DATA frames over HTTP/2 is not easy as this usually requires
handling windowing, priority, etc. This code will improve over time */
stream->data->data_tail = NULL;
if (!data)
remaining = 0;
else
remaining = serf_bucket_get_remaining(data);
/* If the stream decided we are already done */
if (remaining == 0) {
if (stream->status == H2S_OPEN)
stream->status = H2S_HALFCLOSED_LOCAL;
else
stream->status = H2S_CLOSED;
serf_bucket_destroy(data);
next = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_DATA,
HTTP2_FLAG_END_STREAM,
&stream->streamid,
serf_http2__allocate_stream_id,
stream, 0, stream->alloc);
return serf_http2__enqueue_frame(stream->h2, next, false);
}
prefix_len = serf_http2__alloc_window(stream->h2, stream,
(remaining >= APR_SIZE_MAX)
? SERF_READ_ALL_AVAIL
: (apr_size_t)remaining);
if (prefix_len == 0) {
/* No window left */
stream->data->data_tail = data;
/* Write more later */
serf_http2__ensure_writable(stream);
return APR_SUCCESS;
}
if (prefix_len < remaining) {
window_allocate_info_t *wai;
serf_bucket_split_create(&data, &stream->data->data_tail, data,
MIN(prefix_len, 1024), prefix_len);
wai = serf_bucket_mem_alloc(stream->alloc, sizeof(*wai));
wai->stream = stream;
wai->bkt = data;
wai->allocated = prefix_len;
data = serf__bucket_event_create(data, wai,
data_write_started,
data_write_done, NULL, stream->alloc);
end_stream = false;
serf_http2__ensure_writable(stream);
}
else {
end_stream = true;
if (stream->status == H2S_OPEN)
stream->status = H2S_HALFCLOSED_LOCAL;
else
stream->status = H2S_CLOSED;
}
next = serf__bucket_http2_frame_create(data, HTTP2_FRAME_TYPE_DATA,
end_stream ? HTTP2_FLAG_END_STREAM
: 0,
&stream->streamid,
serf_http2__allocate_stream_id,
stream, prefix_len,
data->allocator);
status = serf_http2__enqueue_frame(stream->h2, next, TRUE);
return status;
}