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;