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)