Author: rhuijben Date: Wed Nov 25 00:26:13 2015 New Revision: 1716282 URL: http://svn.apache.org/viewvc?rev=1716282&view=rev Log: * buckets/http2_frame_buckets.c (serf__bucket_http2_unframe_read_info): When bucket reading doesn't return enough bytes but success, read again instead of returning EAGAIN. (serf_http2_frame_context_t): Remove unused variable. Add config. (serf_http2_frame_get_remaining, serf_http2_frame_set_config): New function. (serf_bucket_type__http2_frame): Add get remaining and config support.
Modified: serf/trunk/buckets/http2_frame_buckets.c Modified: serf/trunk/buckets/http2_frame_buckets.c URL: http://svn.apache.org/viewvc/serf/trunk/buckets/http2_frame_buckets.c?rev=1716282&r1=1716281&r2=1716282&view=diff ============================================================================== --- serf/trunk/buckets/http2_frame_buckets.c (original) +++ serf/trunk/buckets/http2_frame_buckets.c Wed Nov 25 00:26:13 2015 @@ -87,6 +87,7 @@ serf__bucket_http2_unframe_read_info(ser const char *data; apr_size_t len; apr_status_t status; + const unsigned char *header; if (ctx->prefix_remaining == 0) { if (stream_id) @@ -99,9 +100,11 @@ serf__bucket_http2_unframe_read_info(ser return APR_SUCCESS; } - status = serf_bucket_read(ctx->stream, ctx->prefix_remaining, &data, &len); - if (!SERF_BUCKET_READ_ERROR(status)) { - const unsigned char *header; + do + { + status = serf_bucket_read(ctx->stream, ctx->prefix_remaining, &data, &len); + if (SERF_BUCKET_READ_ERROR(status)) + return status; if (len < FRAME_PREFIX_SIZE) { memcpy(ctx->buffer + FRAME_PREFIX_SIZE - ctx->prefix_remaining, @@ -114,81 +117,79 @@ serf__bucket_http2_unframe_read_info(ser header = (const void *)data; ctx->prefix_remaining = 0; } + } while (!status && ctx->prefix_remaining > 0); - if (ctx->prefix_remaining == 0) { - apr_size_t payload_length = (header[0] << 16) - | (header[1] << 8) - | (header[2]); - ctx->frame_type = header[3]; - ctx->flags = header[4]; - /* Highest bit of stream_id MUST be ignored */ - ctx->stream_id = ((header[5] & 0x7F) << 24) - | (header[6] << 16) - | (header[7] << 8) - | (header[8]); - - ctx->payload_remaining = payload_length; - - /* Fill output arguments if necessary */ - if (stream_id) - *stream_id = ctx->stream_id; - if (frame_type) - *frame_type = ctx->frame_type; - if (flags) - *flags = ctx->flags; - - /* https://tools.ietf.org/html/rfc7540#section-4.2 - An endpoint MUST send an error code of FRAME_SIZE_ERROR if a - frame exceeds the size defined in SETTINGS_MAX_FRAME_SIZE, - exceeds any limit defined for the frame type, or is too small - to contain mandatory frame data. - */ - if (ctx->max_payload_size < payload_length) - { - if (payload_length == 0x485454 && ctx->frame_type == 0x50 - && ctx->flags == 0x2F) - { - /* We found "HTTP/" instead of an actual frame. This - is clearly above the initial max payload size of 16384, - which applies before we negotiate a bigger size. - - We found a HTTP/1.1 server that didn't understand our - HTTP2 prefix "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" - */ - - return SERF_ERROR_HTTP2_PROTOCOL_ERROR; - } - - return SERF_ERROR_HTTP2_FRAME_SIZE_ERROR; - } + if (ctx->prefix_remaining == 0) { + apr_size_t payload_length = (header[0] << 16) + | (header[1] << 8) + | (header[2]); + ctx->frame_type = header[3]; + ctx->flags = header[4]; + /* Highest bit of stream_id MUST be ignored */ + ctx->stream_id = ((header[5] & 0x7F) << 24) + | (header[6] << 16) + | (header[7] << 8) + | (header[8]); - status = (ctx->payload_remaining == 0) ? APR_EOF - : APR_SUCCESS; + ctx->payload_remaining = payload_length; - /* 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->end_of_frame) { - apr_status_t cb_status; + /* Fill output arguments if necessary */ + if (stream_id) + *stream_id = ctx->stream_id; + if (frame_type) + *frame_type = ctx->frame_type; + if (flags) + *flags = ctx->flags; - cb_status = (*ctx->end_of_frame)(ctx->end_of_frame_baton, - bucket); + /* https://tools.ietf.org/html/rfc7540#section-4.2 + An endpoint MUST send an error code of FRAME_SIZE_ERROR if a + frame exceeds the size defined in SETTINGS_MAX_FRAME_SIZE, + exceeds any limit defined for the frame type, or is too small + to contain mandatory frame data. + */ + if (ctx->max_payload_size < payload_length) + { + if (payload_length == 0x485454 && ctx->frame_type == 0x50 + && ctx->flags == 0x2F) + { + /* We found "HTTP/" instead of an actual frame. This + is clearly above the initial max payload size of 16384, + which applies before we negotiate a bigger size. + + We found a HTTP/1.1 server that didn't understand our + HTTP2 prefix "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + */ - if (SERF_BUCKET_READ_ERROR(cb_status)) - status = cb_status; + return SERF_ERROR_HTTP2_PROTOCOL_ERROR; } + + return SERF_ERROR_HTTP2_FRAME_SIZE_ERROR; } - 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 */ - if (ctx->prefix_remaining == FRAME_PREFIX_SIZE) - status = SERF_ERROR_EMPTY_STREAM; - else - status = SERF_ERROR_HTTP2_FRAME_SIZE_ERROR; - } - else if (!status) - status = APR_EAGAIN; + 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->end_of_frame) { + apr_status_t cb_status; + + cb_status = (*ctx->end_of_frame)(ctx->end_of_frame_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 */ + if (ctx->prefix_remaining == FRAME_PREFIX_SIZE) + status = SERF_ERROR_EMPTY_STREAM; + else + status = SERF_ERROR_HTTP2_FRAME_SIZE_ERROR; } + return status; } @@ -612,7 +613,7 @@ typedef struct serf_http2_frame_context_ void *stream_id_baton; void(*stream_id_alloc)(void *baton, apr_int32_t *stream_id); - apr_size_t current_window; + serf_config_t *config; } serf_http2_frame_context_t; @@ -662,7 +663,7 @@ serf__bucket_http2_frame_create(serf_buc ctx->stream_id_baton = stream_id_baton; } - ctx->current_window = 0; + ctx->config = NULL; ctx->created_frame = FALSE; return serf_bucket_create(&serf_bucket_type__http2_frame, alloc, ctx); @@ -924,6 +925,26 @@ serf_http2_frame_peek(serf_bucket_t *buc return serf_bucket_peek(ctx->chunk, data, len); } +static apr_uint64_t +serf_http2_frame_get_remaining(serf_bucket_t *bucket) +{ + serf_http2_frame_context_t *ctx = bucket->data; + + if (!ctx->created_frame) + return SERF_LENGTH_UNKNOWN; + else + return ctx->bytes_remaining; +} + +static apr_status_t +serf_http2_frame_set_config(serf_bucket_t *bucket, + serf_config_t *config) +{ + serf_http2_frame_context_t *ctx = bucket->data; + ctx->config = config; + return APR_SUCCESS; +} + static void serf_http2_frame_destroy(serf_bucket_t *bucket) { @@ -948,7 +969,7 @@ const serf_bucket_type_t serf_bucket_typ serf_http2_frame_peek, serf_http2_frame_destroy, serf_default_read_bucket, - serf_default_get_remaining, - serf_default_ignore_config + serf_http2_frame_get_remaining, + serf_http2_frame_set_config };