Author: rhuijben Date: Sat Oct 31 21:37:13 2015 New Revision: 1711689 URL: http://svn.apache.org/viewvc?rev=1711689&view=rev Log: In the http2 protocol handler: handle incoming window updates and pass a proper maximum maximum header entry size, instead of the maximum total entry size (which currently defaults to +- unlimited).
* protocols/http2_protocol.c (http2_handle_stream_window_update, http2_handle_connection_window_update): Add implementation. (http2_process): Update caller. * protocols/http2_protocol.h (HTTP2_WINDOW_MAX_ALLOWED, HTTP2_MAX_HEADER_ENTRYSIZE): New define. Modified: serf/trunk/protocols/http2_protocol.c serf/trunk/protocols/http2_protocol.h Modified: serf/trunk/protocols/http2_protocol.c URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1711689&r1=1711688&r2=1711689&view=diff ============================================================================== --- serf/trunk/protocols/http2_protocol.c (original) +++ serf/trunk/protocols/http2_protocol.c Sat Oct 31 21:37:13 2015 @@ -431,11 +431,49 @@ http2_handle_stream_window_update(void * apr_size_t len) { serf_http2_stream_t *stream = baton; + apr_uint32_t value; + const struct window_update_t + { + unsigned char v3, v2, v1, v0; + } *window_update; + if (len != HTTP2_WINDOW_UPDATE_DATA_SIZE) return SERF_ERROR_HTTP2_FRAME_SIZE_ERROR; - SERF_H2_assert(stream->h2 != NULL); + window_update = (const void *)data; + + value = (window_update->v3 << 24) | (window_update->v2 << 16) + | (window_update->v2 << 8) | window_update->v0; + + value &= HTTP2_WINDOW_MAX_ALLOWED; /* The highest bit is reserved */ + + if (value == 0) + { + /* A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an + flow - control window increment of 0 as a stream error(Section 5.4.2) + of type PROTOCOL_ERROR; errors on the connection flow - control window + MUST be treated as a connection error(Section 5.4.1). */ + return SERF_ERROR_HTTP2_PROTOCOL_ERROR; + } + + stream->lr_window += value; + + if (stream->lr_window > HTTP2_WINDOW_MAX_ALLOWED) + { + /* A sender MUST NOT allow a flow-control window to exceed 2^31-1 + octets. If a sender receives a WINDOW_UPDATE that causes a flow- + control window to exceed this maximum, it MUST terminate either the + stream or the connection, as appropriate. For streams, the sender + sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the + connection, a GOAWAY frame with an error code of FLOW_CONTROL_ERROR + is sent.*/ + return SERF_ERROR_HTTP2_FLOW_CONTROL_ERROR; + } + + serf__log(LOGLVL_INFO, SERF_LOGHTTP2, stream->h2->config, + "Increasing window on frame %d with 0x%x to 0x%x\n", + stream->streamid, value, stream->lr_window); return APR_SUCCESS; } @@ -449,12 +487,51 @@ http2_handle_connection_window_update(vo apr_size_t len) { serf_http2_protocol_t *h2 = baton; + apr_uint32_t value; + const struct window_update_t + { + unsigned char v3, v2, v1, v0; + } *window_update; if (len != HTTP2_WINDOW_UPDATE_DATA_SIZE) return SERF_ERROR_HTTP2_FRAME_SIZE_ERROR; SERF_H2_assert(h2 != NULL); + window_update = (const void *)data; + + value = (window_update->v3 << 24) | (window_update->v2 << 16) + | (window_update->v2 << 8) | window_update->v0; + + value &= HTTP2_WINDOW_MAX_ALLOWED; /* The highest bit is reserved */ + + if (value == 0) + { + /* A receiver MUST treat the receipt of a WINDOW_UPDATE frame with an + flow - control window increment of 0 as a stream error(Section 5.4.2) + of type PROTOCOL_ERROR; errors on the connection flow - control window + MUST be treated as a connection error(Section 5.4.1). */ + return SERF_ERROR_HTTP2_PROTOCOL_ERROR; + } + + h2->lr_window += value; + + if (h2->lr_window > HTTP2_WINDOW_MAX_ALLOWED) + { + /* A sender MUST NOT allow a flow-control window to exceed 2^31-1 + octets. If a sender receives a WINDOW_UPDATE that causes a flow- + control window to exceed this maximum, it MUST terminate either the + stream or the connection, as appropriate. For streams, the sender + sends a RST_STREAM with an error code of FLOW_CONTROL_ERROR; for the + connection, a GOAWAY frame with an error code of FLOW_CONTROL_ERROR + is sent.*/ + return SERF_ERROR_HTTP2_FLOW_CONTROL_ERROR; + } + + serf__log(LOGLVL_INFO, SERF_LOGHTTP2, h2->config, + "Increasing window on connection with 0x%x to 0x%x\n", + value, h2->lr_window); + return APR_SUCCESS; } @@ -931,7 +1008,7 @@ http2_process(serf_http2_protocol_t *h2) body = serf_http2__stream_handle_hpack( stream, body, frametype, (frameflags & HTTP2_FLAG_END_STREAM), - h2->rl_max_headersize, + HTTP2_MAX_HEADER_ENTRYSIZE, h2->hpack_tbl, h2->config, h2->allocator); } @@ -940,7 +1017,8 @@ http2_process(serf_http2_protocol_t *h2) /* Even when we don't want to process the headers we must read them to update the HPACK state */ body = serf__bucket_hpack_decode_create( - body, NULL, NULL, h2->rl_max_headersize, + body, NULL, NULL, + HTTP2_MAX_HEADER_ENTRYSIZE, h2->hpack_tbl, h2->allocator); } } Modified: serf/trunk/protocols/http2_protocol.h URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.h?rev=1711689&r1=1711688&r2=1711689&view=diff ============================================================================== --- serf/trunk/protocols/http2_protocol.h (original) +++ serf/trunk/protocols/http2_protocol.h Sat Oct 31 21:37:13 2015 @@ -55,6 +55,8 @@ extern "C" { #define HTTP2_SETTING_SIZE 6 +#define HTTP2_WINDOW_MAX_ALLOWED 0x7FFFFFF + /* Frame type is an 8 bit unsigned integer */ /* http://tools.ietf.org/html/rfc7540#section-11.2 */ @@ -101,6 +103,9 @@ extern "C" { #define HTTP2_CONNECTION_PREFIX "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" +/* Maximum size for a headerline in HPACK */ +#define HTTP2_MAX_HEADER_ENTRYSIZE 0x20000 /* 128 KByte */ + /* ------------------------------------- */ typedef struct serf_http2_protocol_t serf_http2_protocol_t;