Author: rhuijben
Date: Wed Oct 28 10:37:37 2015
New Revision: 1710981

URL: http://svn.apache.org/viewvc?rev=1710981&view=rev
Log:
Add an eof callback to the http2 unframe bucket (modeled after the similar
callback on the aggregate bucket), to ease handling frame buckets that are
handed of to separate handlers.

* buckets/http2_frame_buckets.c
  (http2_unframe_context_t): Add callback info.
  (serf__bucket_http2_unframe_create): Default callback to NULL.
  (serf__bucket_http2_unframe_set_eof): New function.
  (serf__bucket_http2_unframe_read_info,
   serf_http2_unframe_read,
   serf_http2_unframe_read_iovec): Call callback when hitting eof.

* protocols/http2_buckets.h
  (serf__bucket_http2_unframe_create): Extend documentation.
  (serf__bucket_http2_unframe_set_eof): New function.

Modified:
    serf/trunk/buckets/http2_frame_buckets.c
    serf/trunk/protocols/http2_buckets.h

Modified: serf/trunk/buckets/http2_frame_buckets.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/buckets/http2_frame_buckets.c?rev=1710981&r1=1710980&r2=1710981&view=diff
==============================================================================
--- serf/trunk/buckets/http2_frame_buckets.c (original)
+++ serf/trunk/buckets/http2_frame_buckets.c Wed Oct 28 10:37:37 2015
@@ -38,6 +38,10 @@ typedef struct http2_unframe_context_t
 
   apr_size_t prefix_remaining;
 
+  apr_status_t (*eof_callback)(void *baton,
+                               serf_bucket_t *bucket);
+  void *eof_callback_baton;
+
   /* These fields are only set after prefix_remaining is 0 */
   apr_size_t payload_remaining;  /* 0 <= payload_length < 2^24 */
   apr_int32_t stream_id;         /* 0 <= stream_id < 2^31 */
@@ -60,11 +64,26 @@ serf__bucket_http2_unframe_create(serf_b
   ctx->stream = stream;
   ctx->max_payload_size = max_payload_size;
   ctx->prefix_remaining = sizeof(ctx->prefix_buffer);
+  ctx->eof_callback = NULL;
+
   ctx->destroy_stream = (destroy_stream != 0);
 
   return serf_bucket_create(&serf_bucket_type__http2_unframe, allocator, ctx);
 }
 
+void
+serf__bucket_http2_unframe_set_eof(serf_bucket_t *bucket,
+                                   apr_status_t (*eof_callback)(
+                                                    void *baton,
+                                                    serf_bucket_t *bucket),
+                                   void *eof_callback_baton)
+{
+  http2_unframe_context_t *ctx = bucket->data;
+
+  ctx->eof_callback = eof_callback;
+  ctx->eof_callback_baton = eof_callback_baton;
+}
+
 apr_status_t
 serf__bucket_http2_unframe_read_info(serf_bucket_t *bucket,
                                      apr_int32_t *stream_id,
@@ -123,6 +142,28 @@ serf__bucket_http2_unframe_read_info(ser
           */
           if (ctx->max_payload_size < payload_length)
               return SERF_ERROR_HTTP2_FRAME_SIZE_ERROR;
+
+          status = (ctx->payload_remaining == 0) ? APR_EOF
+                                                 : APR_SUCCESS;
+
+          /* If we hava a zero-length frame we have to call the eof callback
+             now, as the read operations will just shortcut to APR_EOF */
+          if (ctx->payload_remaining == 0 && ctx->eof_callback)
+            {
+              apr_status_t cb_status;
+
+              cb_status = ctx->eof_callback(ctx->eof_callback_baton,
+                                            bucket);
+
+              if (SERF_BUCKET_READ_ERROR(cb_status))
+                status = cb_status;
+            }
+        }
+      else if (APR_STATUS_IS_EOF(status))
+        {
+          /* Reading frame failed because we couldn't read the header. Report
+             a read failure instead of semi-success */
+          status = SERF_ERROR_HTTP2_FRAME_SIZE_ERROR;
         }
       else if (!status)
         status = APR_EAGAIN;
@@ -163,7 +204,14 @@ serf_http2_unframe_read(serf_bucket_t *b
       ctx->payload_remaining -= *len;
 
       if (ctx->payload_remaining == 0)
-        status = APR_EOF;
+        {
+          if (ctx->eof_callback)
+            status = ctx->eof_callback(ctx->eof_callback_baton,
+                                       bucket);
+
+          if (!SERF_BUCKET_READ_ERROR(status))
+            status = APR_EOF;
+        }
     }
 
   return status;
@@ -209,7 +257,14 @@ serf_http2_unframe_read_iovec(serf_bucke
       ctx->payload_remaining -= len;
 
       if (ctx->payload_remaining == 0)
-        status = APR_EOF;
+        {
+          if (ctx->eof_callback)
+            status = ctx->eof_callback(ctx->eof_callback_baton,
+                                       bucket);
+
+          if (!SERF_BUCKET_READ_ERROR(status))
+            status = APR_EOF;
+        }
     }
 
   return status;

Modified: serf/trunk/protocols/http2_buckets.h
URL: 
http://svn.apache.org/viewvc/serf/trunk/protocols/http2_buckets.h?rev=1710981&r1=1710980&r2=1710981&view=diff
==============================================================================
--- serf/trunk/protocols/http2_buckets.h (original)
+++ serf/trunk/protocols/http2_buckets.h Wed Oct 28 10:37:37 2015
@@ -38,12 +38,32 @@ extern "C" {
 extern const serf_bucket_type_t serf_bucket_type__http2_unframe;
 #define SERF__BUCKET_IS_HTTP2_UNFRAME(b) SERF_BUCKET_CHECK((b), _http2_unframe)
 
+/* Creates a bucket that reads a single http2 frame from stream. If
+   DESTROY_STREAM is true STREAM will be destroyed with the bucket, otherwise
+   it won't.
+
+   The frame header information can be obtained by calling
+   serf__bucket_http2_unframe_read_info().
+
+   After the header has been read the remaining payload size can be retrieved
+   using serf_bucket_get_remaining()
+ */
 serf_bucket_t *
 serf__bucket_http2_unframe_create(serf_bucket_t *stream,
                                   int destroy_stream,
                                   apr_size_t max_payload_size,
                                   serf_bucket_alloc_t *allocator);
 
+/* Sets the end of frame handler on the frame, which will be called as soon as
+   the whole frame has been read from the contained stream */
+void
+serf__bucket_http2_unframe_set_eof(serf_bucket_t *bucket,
+                                   apr_status_t (*eof_callback)(
+                                                    void *baton,
+                                                    serf_bucket_t *bucket),
+                                   void *eof_callback_baton);
+
+
 /* Obtains the frame header state, reading from the bucket if necessary.
    If the header was read successfully (or was already read before calling)
    the *stream_id, * frame_type and *flags values (when not pointing to NULL)


Reply via email to