Issue connection error if client receives HEADERS with idle stream ID

If stream ID is not idle, it might be valid HEADERS.  If stream ID is
idle, it is invalid regardless stream ID is even or odd, since client
is not expected to recieve request from server.  nghttp2 library
historically allows this, but now we forbids this.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-11-28 01:22:57 +09:00
parent babfa41424
commit 382a328ead
2 changed files with 63 additions and 0 deletions

View File

@ -2993,6 +2993,17 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
/* We don't accept new stream after GOAWAY is sent or received. */
return NGHTTP2_ERR_IGN_HEADER_BLOCK;
}
/* If client recieves idle stream from server, it is invalid
regardless stream ID is even or odd. This is because client is
not expected to receive request from server. */
if (!session->server &&
session_detect_idle_stream(session, frame->hd.stream_id)) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_PROTOCOL_ERROR,
"request HEADERS: client received request");
}
if (!session_is_new_peer_stream_id(session, frame->hd.stream_id)) {
/* The spec says if an endpoint receives a HEADERS with invalid
stream ID, it MUST issue connection error with error code

View File

@ -1767,6 +1767,58 @@ void test_nghttp2_session_on_request_headers_received(void) {
nghttp2_frame_headers_free(&frame.headers);
nghttp2_session_del(session);
/* Check client side */
nghttp2_session_client_new(&session, &callbacks, &user_data);
/* Receiving peer's idle stream ID is subject to connection error */
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_request_headers_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND);
nghttp2_frame_headers_free(&frame.headers);
nghttp2_session_del(session);
nghttp2_session_client_new(&session, &callbacks, &user_data);
/* Receiving our's idle stream ID is subject to connection error */
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_request_headers_received(session, &frame));
CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND);
nghttp2_frame_headers_free(&frame.headers);
nghttp2_session_del(session);
nghttp2_session_client_new(&session, &callbacks, &user_data);
session->next_stream_id = 5;
/* Stream ID which is not idle and not in stream map is just
ignored */
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3,
NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
nghttp2_session_on_request_headers_received(session, &frame));
CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_FAIL_ON_SEND));
nghttp2_frame_headers_free(&frame.headers);
nghttp2_session_del(session);
}
void test_nghttp2_session_on_response_headers_received(void) {