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


Reply via email to