Author: rhuijben
Date: Sat Nov 14 12:24:27 2015
New Revision: 1714307
URL: http://svn.apache.org/viewvc?rev=1714307&view=rev
Log:
Use the recently added split buckets to allow sending more hpack headers than
that fit in a single HEADERS frame.
* buckets/split_buckets.c
(serf_bucket_split_create): Fix two issues when creating more than one
tail in a split stream. Fix indentation.
* protocols/http2_protocol.c
(enqueue_http2_request): Update caller.
* protocols/http2_protocol.h
(serf_http2__stream_setup_next_request): Add argument.
* protocols/http2_stream.c
(serf_http2__stream_setup_next_request): Create CONTINUATION frames
directly after the initial HEADERS frame when the data doesn't fit
in the frame.
Modified:
serf/trunk/buckets/split_buckets.c
serf/trunk/protocols/http2_protocol.c
serf/trunk/protocols/http2_protocol.h
serf/trunk/protocols/http2_stream.c
Modified: serf/trunk/buckets/split_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/split_buckets.c?rev=1714307&r1=1714306&r2=1714307&view=diff
==============================================================================
--- serf/trunk/buckets/split_buckets.c (original)
+++ serf/trunk/buckets/split_buckets.c Sat Nov 14 12:24:27 2015
@@ -390,43 +390,46 @@ void serf_bucket_split_create(serf_bucke
apr_size_t min_chunk_size,
apr_size_t max_chunk_size)
{
- split_stream_ctx_t *tail_ctx, *head_ctx;
- split_context_t *ctx;
- serf_bucket_alloc_t *allocator = stream->allocator;
-
- tail_ctx = serf_bucket_mem_calloc(allocator, sizeof(*tail_ctx));
- tail_ctx->tail_size = SERF_LENGTH_UNKNOWN;
-
- if (SERF_BUCKET_IS__SPLIT(stream)) {
- ctx = stream->data;
- *head = stream;
-
- head_ctx = tail_ctx->prev = ctx->tail;
- ctx->tail->next = tail_ctx;
- ctx->tail = tail_ctx;
- }
- else {
- ctx = serf_bucket_mem_calloc(allocator, sizeof(*ctx));
- ctx->stream = stream;
-
- head_ctx = serf_bucket_mem_calloc(allocator, sizeof(*head_ctx));
- head_ctx->ctx = ctx;
-
- ctx->tail = head_ctx->next = tail_ctx;
- ctx->head = tail_ctx->prev = head_ctx;
-
- *head = serf_bucket_create(&serf_bucket_type__split, allocator,
- head_ctx);
- }
-
- *tail = serf_bucket_create(&serf_bucket_type__split, allocator, tail_ctx);
-
- tail_ctx->ctx = ctx;
- /* head_ctx->fixed_size = 0; // Unknown */
- head_ctx->min_size = min_chunk_size;
- head_ctx->max_size = max_chunk_size;
-
- /* tail_ctx->fixed_size = 0; // Unknown */
- tail_ctx->min_size = SERF_READ_ALL_AVAIL;
- tail_ctx->max_size = SERF_READ_ALL_AVAIL;
+ split_stream_ctx_t *tail_ctx, *head_ctx;
+ split_context_t *ctx;
+ serf_bucket_alloc_t *allocator = stream->allocator;
+
+ tail_ctx = serf_bucket_mem_calloc(allocator, sizeof(*tail_ctx));
+ tail_ctx->tail_size = SERF_LENGTH_UNKNOWN;
+
+ if (SERF_BUCKET_IS__SPLIT(stream)) {
+ head_ctx = stream->data;
+ ctx = head_ctx->ctx;
+ *head = stream;
+
+ head_ctx = tail_ctx->prev = ctx->tail;
+ ctx->tail->next = tail_ctx;
+ ctx->tail = tail_ctx;
+ }
+ else {
+ ctx = serf_bucket_mem_calloc(allocator, sizeof(*ctx));
+ ctx->stream = stream;
+
+ head_ctx = serf_bucket_mem_calloc(allocator, sizeof(*head_ctx));
+ head_ctx->ctx = ctx;
+ head_ctx->tail_size = SERF_LENGTH_UNKNOWN;
+
+ ctx->tail = head_ctx->next = tail_ctx;
+ ctx->head = tail_ctx->prev = head_ctx;
+
+ *head = serf_bucket_create(&serf_bucket_type__split, allocator,
+ head_ctx);
+ }
+
+ *tail = serf_bucket_create(&serf_bucket_type__split, allocator, tail_ctx);
+
+ tail_ctx->ctx = ctx;
+ head_ctx->fixed_size = 0; /* Not fixed yet. This might change an existing
+ tail bucket that we received as stream! */
+ head_ctx->min_size = min_chunk_size;
+ head_ctx->max_size = max_chunk_size;
+
+ /* tail_ctx->fixed_size = 0; // Unknown */
+ tail_ctx->min_size = SERF_READ_ALL_AVAIL;
+ tail_ctx->max_size = SERF_READ_ALL_AVAIL;
}
Modified: serf/trunk/protocols/http2_protocol.c
URL:
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1714307&r1=1714306&r2=1714307&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.c (original)
+++ serf/trunk/protocols/http2_protocol.c Sat Nov 14 12:24:27 2015
@@ -310,6 +310,7 @@ enqueue_http2_request(serf_http2_protoco
h2->last = h2->first = stream;
return serf_http2__stream_setup_next_request(stream, h2->conn,
+ h2->lr_max_framesize,
h2->hpack_tbl);
}
Modified: serf/trunk/protocols/http2_protocol.h
URL:
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.h?rev=1714307&r1=1714306&r2=1714307&view=diff
==============================================================================
--- serf/trunk/protocols/http2_protocol.h (original)
+++ serf/trunk/protocols/http2_protocol.h Sat Nov 14 12:24:27 2015
@@ -195,6 +195,7 @@ serf_http2__stream_get(serf_http2_protoc
apr_status_t
serf_http2__stream_setup_next_request(serf_http2_stream_t *stream,
serf_connection_t *conn,
+ apr_size_t max_payload_size,
serf_hpack_table_t *hpack_tbl);
apr_status_t
Modified: serf/trunk/protocols/http2_stream.c
URL:
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_stream.c?rev=1714307&r1=1714306&r2=1714307&view=diff
==============================================================================
--- serf/trunk/protocols/http2_stream.c (original)
+++ serf/trunk/protocols/http2_stream.c Sat Nov 14 12:24:27 2015
@@ -85,12 +85,15 @@ serf_http2__stream_cleanup(serf_http2_st
apr_status_t
serf_http2__stream_setup_next_request(serf_http2_stream_t *stream,
serf_connection_t *conn,
+ apr_size_t max_payload_size,
serf_hpack_table_t *hpack_tbl)
{
serf_request_t *request = conn->unwritten_reqs;
apr_status_t status;
serf_bucket_t *hpack;
serf_bucket_t *body;
+ bool first_frame;
+ bool end_stream;
SERF_H2_assert(request != NULL);
if (!request)
@@ -126,24 +129,76 @@ serf_http2__stream_setup_next_request(se
if (!body)
{
- /* This destroys the body... Perhaps we should make an extract
- and clear api */
serf_bucket_destroy(request->req_bkt);
request->req_bkt = NULL;
+ end_stream = true;
}
+ else
+ end_stream = false;
- hpack = serf__bucket_http2_frame_create(hpack, HTTP2_FRAME_TYPE_HEADERS,
- HTTP2_FLAG_END_STREAM
- | HTTP2_FLAG_END_HEADERS,
- &stream->streamid,
- serf_http2__allocate_stream_id,
- stream,
- HTTP2_DEFAULT_MAX_FRAMESIZE,
- request->allocator);
+ first_frame = true;
- serf_http2__enqueue_frame(stream->h2, hpack, TRUE);
+ /* And now schedule the packet for writing. Note that it is required
+ by the HTTP/2 spec to send HEADERS and CONTINUATION directly after
+ each other, without other frames inbetween. */
+ while (hpack != NULL)
+ {
+ serf_bucket_t *next;
+ apr_uint64_t remaining;
+
+ /* hpack buckets implement get_remaining. And if they didn't adding the
+ framing around them would apply some reads that fix the buckets.
+
+ So we can ignore the theoretical endless loop here for two different
+ reasons
+ */
+ remaining = serf_bucket_get_remaining(hpack);
+
+ if (remaining > max_payload_size)
+ {
+ serf_bucket_split_create(&next, &hpack, hpack,
+ max_payload_size - (max_payload_size / 4),
+ max_payload_size);
+ }
+ else
+ {
+ next = hpack;
+ hpack = NULL;
+ }
+
+ next = serf__bucket_http2_frame_create(next,
+ first_frame
+ ? HTTP2_FRAME_TYPE_HEADERS
+ : HTTP2_FRAME_TYPE_CONTINUATION,
+ (end_stream
+ ? HTTP2_FLAG_END_STREAM
+ : 0)
+ | ((hpack != NULL)
+ ? 0
+ : HTTP2_FLAG_END_HEADERS),
+ &stream->streamid,
+ serf_http2__allocate_stream_id,
+ stream,
+ max_payload_size,
+ request->allocator);
+ status = serf_http2__enqueue_frame(stream->h2, next, TRUE);
+
+ if (SERF_BUCKET_READ_ERROR(status))
+ return status; /* Connection dead */
+
+ first_frame = false; /* Continue with 'continuation' frames */
+ }
- stream->status = H2S_HALFCLOSED_LOCAL; /* Headers sent */
+
+ if (end_stream)
+ {
+ stream->status = H2S_HALFCLOSED_LOCAL; /* Headers sent; no body */
+ }
+ else
+ {
+ stream->status = H2S_OPEN; /* Headers sent. Body to go */
+ /* ### TODO: Schedule body to be sent */
+ }
return APR_SUCCESS;
}