inflate_header_block: Terminate session on compression error
Code cleanup is done as well
This commit is contained in:
parent
1daf6de102
commit
5d535766bf
|
@ -1873,6 +1873,25 @@ static int nghttp2_session_validate_request_headers(nghttp2_session *session,
|
||||||
return 0;
|
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,
|
static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
int call_header_cb)
|
int call_header_cb)
|
||||||
{
|
{
|
||||||
|
@ -1889,8 +1908,15 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
if(rv < 0) {
|
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);
|
NGHTTP2_COMPRESSION_ERROR);
|
||||||
|
if(rv != 0) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nghttp2_session_terminate_session(session,
|
||||||
|
NGHTTP2_COMPRESSION_ERROR);
|
||||||
}
|
}
|
||||||
session->iframe.inflate_offset += rv;
|
session->iframe.inflate_offset += rv;
|
||||||
if(final) {
|
if(final) {
|
||||||
|
@ -1905,7 +1931,10 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
|
nghttp2_hd_inflate_end_headers(&session->hd_inflater);
|
||||||
return session_call_on_end_headers(session, frame, NGHTTP2_NO_ERROR);
|
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,
|
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;
|
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
|
static int nghttp2_session_inflate_handle_invalid_stream
|
||||||
(nghttp2_session *session,
|
(nghttp2_session *session,
|
||||||
nghttp2_frame *frame,
|
nghttp2_frame *frame,
|
||||||
nghttp2_error_code error_code)
|
nghttp2_error_code error_code)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
session->iframe.inflate_offset = get_payload_nv_offset(frame);
|
rv = session_skip_inflate_header_block(session, frame);
|
||||||
rv = inflate_header_block(session, frame, 0);
|
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -1999,8 +2039,7 @@ static int nghttp2_session_inflate_handle_invalid_connection
|
||||||
nghttp2_error_code error_code)
|
nghttp2_error_code error_code)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
session->iframe.inflate_offset = get_payload_nv_offset(frame);
|
rv = session_skip_inflate_header_block(session, frame);
|
||||||
rv = inflate_header_block(session, frame, 0);
|
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2094,9 +2133,7 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
if(session->goaway_flags) {
|
if(session->goaway_flags) {
|
||||||
/* We don't accept new stream after GOAWAY is sent or received. */
|
/* We don't accept new stream after GOAWAY is sent or received. */
|
||||||
session->iframe.inflate_offset =
|
return session_skip_inflate_header_block(session, frame);
|
||||||
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
|
|
||||||
return inflate_header_block(session, frame, 0);
|
|
||||||
}
|
}
|
||||||
if(!nghttp2_session_is_new_peer_stream_id(session, frame->hd.stream_id)) {
|
if(!nghttp2_session_is_new_peer_stream_id(session, frame->hd.stream_id)) {
|
||||||
/* The spec says if an endpoint receives a HEADERS with invalid
|
/* 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) {
|
if(session->goaway_flags) {
|
||||||
/* We don't accept new stream after GOAWAY is sent or received. */
|
/* We don't accept new stream after GOAWAY is sent or received. */
|
||||||
session->iframe.inflate_offset =
|
return session_skip_inflate_header_block(session, frame);
|
||||||
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
|
|
||||||
return inflate_header_block(session, frame, 0);
|
|
||||||
}
|
}
|
||||||
rv = nghttp2_session_validate_request_headers(session, &frame->headers);
|
rv = nghttp2_session_validate_request_headers(session, &frame->headers);
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
|
@ -2253,9 +2288,7 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||||
/* This is race condition. NGHTTP2_STREAM_CLOSING indicates
|
/* This is race condition. NGHTTP2_STREAM_CLOSING indicates
|
||||||
that we queued RST_STREAM but it has not been sent. It will
|
that we queued RST_STREAM but it has not been sent. It will
|
||||||
eventually sent, so we just ignore this frame. */
|
eventually sent, so we just ignore this frame. */
|
||||||
session->iframe.inflate_offset =
|
return session_skip_inflate_header_block(session, frame);
|
||||||
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
|
|
||||||
return inflate_header_block(session, frame, 0);
|
|
||||||
} else {
|
} else {
|
||||||
return nghttp2_session_inflate_handle_invalid_stream
|
return nghttp2_session_inflate_handle_invalid_stream
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(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);
|
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
|
||||||
return session_end_headers_received(session, frame);
|
return session_end_headers_received(session, frame);
|
||||||
}
|
}
|
||||||
session->iframe.inflate_offset =
|
return session_skip_inflate_header_block(session, frame);
|
||||||
nghttp2_frame_headers_payload_nv_offset(&frame->headers);
|
|
||||||
return inflate_header_block(session, frame, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2728,8 +2759,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
if(session->goaway_flags) {
|
if(session->goaway_flags) {
|
||||||
/* We just dicard PUSH_PROMISE after GOAWAY is sent or
|
/* We just dicard PUSH_PROMISE after GOAWAY is sent or
|
||||||
received. */
|
received. */
|
||||||
session->iframe.inflate_offset = 4;
|
return session_skip_inflate_header_block(session, frame);
|
||||||
return inflate_header_block(session, frame, 0);
|
|
||||||
}
|
}
|
||||||
if(!nghttp2_session_is_new_peer_stream_id
|
if(!nghttp2_session_is_new_peer_stream_id
|
||||||
(session, frame->push_promise.promised_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;
|
session->last_recv_stream_id = frame->push_promise.promised_stream_id;
|
||||||
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
|
||||||
if(!stream) {
|
if(!stream) {
|
||||||
session->iframe.inflate_offset = 4;
|
rv = session_skip_inflate_header_block(session, frame);
|
||||||
rv = inflate_header_block(session, frame, 0);
|
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2756,8 +2785,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
(session, frame, NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
if(stream->shut_flags & NGHTTP2_SHUT_RD) {
|
if(stream->shut_flags & NGHTTP2_SHUT_RD) {
|
||||||
session->iframe.inflate_offset = 4;
|
rv = session_skip_inflate_header_block(session, frame);
|
||||||
rv = inflate_header_block(session, frame, 0);
|
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -2772,8 +2800,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||||
NGHTTP2_PROTOCOL_ERROR);
|
NGHTTP2_PROTOCOL_ERROR);
|
||||||
}
|
}
|
||||||
if(stream->state == NGHTTP2_STREAM_CLOSING) {
|
if(stream->state == NGHTTP2_STREAM_CLOSING) {
|
||||||
session->iframe.inflate_offset = 4;
|
rv = session_skip_inflate_header_block(session, frame);
|
||||||
rv = inflate_header_block(session, frame, 0);
|
|
||||||
if(rv != 0) {
|
if(rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -818,7 +818,8 @@ void test_nghttp2_session_on_request_headers_received(void)
|
||||||
|
|
||||||
/* More than max concurrent streams leads REFUSED_STREAM */
|
/* More than max concurrent streams leads REFUSED_STREAM */
|
||||||
session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] = 1;
|
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);
|
3, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
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
|
/* Stream ID less than or equal to the previouly received request
|
||||||
HEADERS leads to connection error */
|
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);
|
3, NGHTTP2_PRI_DEFAULT, NULL, 0);
|
||||||
user_data.invalid_frame_recv_cb_called = 0;
|
user_data.invalid_frame_recv_cb_called = 0;
|
||||||
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
|
||||||
|
|
Loading…
Reference in New Issue