inflate_header_block: Terminate session on compression error

Code cleanup is done as well
This commit is contained in:
Tatsuhiro Tsujikawa 2014-01-17 10:13:33 +09:00
parent 1daf6de102
commit 5d535766bf
2 changed files with 57 additions and 28 deletions

View File

@ -1873,6 +1873,25 @@ static int nghttp2_session_validate_request_headers(nghttp2_session *session,
return 0;
}
/*
* Inflates header block in session->iframe.buf. The offset inside the
* buffer must be initialized before this call. If this function
* returns NGHTTP2_ERR_PAUSE, the caller must call this function
* again, until it returns 0 or one of negative error code. If
* |call_header_cb| is zero, the on_header_callback and
* on_end_headers_callback are not invoked and the function never
* return NGHTTP2_ERR_PAUSE.
*
* This function return 0 if it succeeds, or one of the negative error
* codes:
*
* NGHTTP2_ERR_CALLBACK_FAILURE
* The callback function failed.
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_PAUSE
* The callback function returned NGHTTP2_ERR_PAUSE
*/
static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
int call_header_cb)
{
@ -1889,7 +1908,14 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
return rv;
}
if(rv < 0) {
return session_call_on_end_headers(session, frame,
if(call_header_cb) {
rv = session_call_on_end_headers(session, frame,
NGHTTP2_COMPRESSION_ERROR);
if(rv != 0) {
return rv;
}
}
return nghttp2_session_terminate_session(session,
NGHTTP2_COMPRESSION_ERROR);
}
session->iframe.inflate_offset += rv;
@ -1905,7 +1931,10 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
}
}
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
if(call_header_cb) {
return session_call_on_end_headers(session, frame, NGHTTP2_NO_ERROR);
}
return 0;
}
static int nghttp2_session_handle_parse_error(nghttp2_session *session,
@ -1962,14 +1991,25 @@ static size_t get_payload_nv_offset(nghttp2_frame *frame)
return 0;
}
/*
* Inflates header block without invoking on_header_callback and
* on_end_headers_callback. The initial offset inside
* session->iframe.buf is calculated based on |frame|.
*/
static int session_skip_inflate_header_block(nghttp2_session *session,
nghttp2_frame *frame)
{
session->iframe.inflate_offset = get_payload_nv_offset(frame);
return inflate_header_block(session, frame, 0);
}
static int nghttp2_session_inflate_handle_invalid_stream
(nghttp2_session *session,
nghttp2_frame *frame,
nghttp2_error_code error_code)
{
int rv;
session->iframe.inflate_offset = get_payload_nv_offset(frame);
rv = inflate_header_block(session, frame, 0);
rv = session_skip_inflate_header_block(session, frame);
if(rv != 0) {
return rv;
}
@ -1999,8 +2039,7 @@ static int nghttp2_session_inflate_handle_invalid_connection
nghttp2_error_code error_code)
{
int rv;
session->iframe.inflate_offset = get_payload_nv_offset(frame);
rv = inflate_header_block(session, frame, 0);
rv = session_skip_inflate_header_block(session, frame);
if(rv != 0) {
return rv;
}
@ -2094,9 +2133,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
}
if(session->goaway_flags) {
/* We don't accept new stream after GOAWAY is sent or received. */
session->iframe.inflate_offset =
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
return inflate_header_block(session, frame, 0);
return session_skip_inflate_header_block(session, frame);
}
if(!nghttp2_session_is_new_peer_stream_id(session, frame->hd.stream_id)) {
/* The spec says if an endpoint receives a HEADERS with invalid
@ -2189,9 +2226,7 @@ int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
}
if(session->goaway_flags) {
/* We don't accept new stream after GOAWAY is sent or received. */
session->iframe.inflate_offset =
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
return inflate_header_block(session, frame, 0);
return session_skip_inflate_header_block(session, frame);
}
rv = nghttp2_session_validate_request_headers(session, &frame->headers);
if(rv != 0) {
@ -2253,9 +2288,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
/* This is race condition. NGHTTP2_STREAM_CLOSING indicates
that we queued RST_STREAM but it has not been sent. It will
eventually sent, so we just ignore this frame. */
session->iframe.inflate_offset =
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
return inflate_header_block(session, frame, 0);
return session_skip_inflate_header_block(session, frame);
} else {
return nghttp2_session_inflate_handle_invalid_stream
(session, frame, NGHTTP2_PROTOCOL_ERROR);
@ -2274,9 +2307,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
return session_end_headers_received(session, frame);
}
session->iframe.inflate_offset =
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
return inflate_header_block(session, frame, 0);
return session_skip_inflate_header_block(session, frame);
}
}
@ -2728,8 +2759,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
if(session->goaway_flags) {
/* We just dicard PUSH_PROMISE after GOAWAY is sent or
received. */
session->iframe.inflate_offset = 4;
return inflate_header_block(session, frame, 0);
return session_skip_inflate_header_block(session, frame);
}
if(!nghttp2_session_is_new_peer_stream_id
(session, frame->push_promise.promised_stream_id)) {
@ -2742,8 +2772,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
session->last_recv_stream_id = frame->push_promise.promised_stream_id;
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if(!stream) {
session->iframe.inflate_offset = 4;
rv = inflate_header_block(session, frame, 0);
rv = session_skip_inflate_header_block(session, frame);
if(rv != 0) {
return rv;
}
@ -2756,8 +2785,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
(session, frame, NGHTTP2_PROTOCOL_ERROR);
}
if(stream->shut_flags & NGHTTP2_SHUT_RD) {
session->iframe.inflate_offset = 4;
rv = inflate_header_block(session, frame, 0);
rv = session_skip_inflate_header_block(session, frame);
if(rv != 0) {
return rv;
}
@ -2772,8 +2800,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
NGHTTP2_PROTOCOL_ERROR);
}
if(stream->state == NGHTTP2_STREAM_CLOSING) {
session->iframe.inflate_offset = 4;
rv = inflate_header_block(session, frame, 0);
rv = session_skip_inflate_header_block(session, frame);
if(rv != 0) {
return rv;
}

View File

@ -818,7 +818,8 @@ void test_nghttp2_session_on_request_headers_received(void)
/* More than max concurrent streams leads REFUSED_STREAM */
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
nghttp2_frame_headers_init(&frame.headers,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
3, NGHTTP2_PRI_DEFAULT, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
@ -831,7 +832,8 @@ void test_nghttp2_session_on_request_headers_received(void)
/* Stream ID less than or equal to the previouly received request
HEADERS leads to connection error */
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS,
nghttp2_frame_headers_init(&frame.headers,
NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
3, NGHTTP2_PRI_DEFAULT, NULL, 0);
user_data.invalid_frame_recv_cb_called = 0;
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));