Detect frame reception for idle stream and make it connection error

Only stream ID which larger than currently used stream ID is
detected as idle.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-02-01 16:05:58 +09:00
parent 2402b46cf3
commit 08ff95d402
2 changed files with 49 additions and 3 deletions

View File

@ -1893,6 +1893,22 @@ static int nghttp2_session_is_new_peer_stream_id(nghttp2_session *session,
} }
} }
static int session_detect_idle_stream(nghttp2_session *session,
int32_t stream_id)
{
/* Assume that stream object with stream_id does not exist */
if(nghttp2_session_is_my_stream_id(session, stream_id)) {
if(session->next_stream_id >= (uint32_t)stream_id) {
return 1;
}
return 0;
}
if(nghttp2_session_is_new_peer_stream_id(session, stream_id)) {
return 1;
}
return 0;
}
/* /*
* Validates received HEADERS frame |frame| with NGHTTP2_HCAT_REQUEST * Validates received HEADERS frame |frame| with NGHTTP2_HCAT_REQUEST
* or NGHTTP2_HCAT_PUSH_RESPONSE category, which both opens new * or NGHTTP2_HCAT_PUSH_RESPONSE category, which both opens new
@ -2397,6 +2413,10 @@ int nghttp2_session_on_priority_received(nghttp2_session *session,
} }
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if(!stream) { if(!stream) {
if(session_detect_idle_stream(session, frame->hd.stream_id)) {
return nghttp2_session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR);
}
return 0; return 0;
} }
if(state_reserved_remote(session, stream)) { if(state_reserved_remote(session, stream)) {
@ -2430,10 +2450,19 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
nghttp2_frame *frame) nghttp2_frame *frame)
{ {
int rv; int rv;
nghttp2_stream *stream;
if(frame->hd.stream_id == 0) { if(frame->hd.stream_id == 0) {
return nghttp2_session_handle_invalid_connection(session, frame, return nghttp2_session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR); NGHTTP2_PROTOCOL_ERROR);
} }
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if(!stream) {
if(session_detect_idle_stream(session, frame->hd.stream_id)) {
return nghttp2_session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR);
}
}
rv = nghttp2_session_call_on_frame_received(session, frame); rv = nghttp2_session_call_on_frame_received(session, frame);
if(rv != 0) { if(rv != 0) {
return rv; return rv;
@ -2883,6 +2912,12 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
} }
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if(!stream || stream->state == NGHTTP2_STREAM_CLOSING) { if(!stream || stream->state == NGHTTP2_STREAM_CLOSING) {
if(!stream) {
if(session_detect_idle_stream(session, frame->hd.stream_id)) {
return nghttp2_session_handle_invalid_connection
(session, frame, NGHTTP2_PROTOCOL_ERROR);
}
}
rv = nghttp2_session_add_rst_stream rv = nghttp2_session_add_rst_stream
(session, frame->push_promise.promised_stream_id, (session, frame->push_promise.promised_stream_id,
NGHTTP2_REFUSED_STREAM); NGHTTP2_REFUSED_STREAM);
@ -3062,6 +3097,10 @@ static int session_on_stream_window_update_received
nghttp2_stream *stream; nghttp2_stream *stream;
stream = nghttp2_session_get_stream(session, frame->hd.stream_id); stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
if(!stream) { if(!stream) {
if(session_detect_idle_stream(session, frame->hd.stream_id)) {
return nghttp2_session_handle_invalid_connection(session, frame,
NGHTTP2_PROTOCOL_ERROR);
}
return 0; return 0;
} }
if(stream->state == NGHTTP2_STREAM_RESERVED) { if(stream->state == NGHTTP2_STREAM_RESERVED) {
@ -3307,6 +3346,9 @@ static int nghttp2_session_on_data_received_fail_fast(nghttp2_session *session)
} }
stream = nghttp2_session_get_stream(session, stream_id); stream = nghttp2_session_get_stream(session, stream_id);
if(!stream) { if(!stream) {
if(session_detect_idle_stream(session, stream_id)) {
goto fail;
}
return NGHTTP2_ERR_IGN_PAYLOAD; return NGHTTP2_ERR_IGN_PAYLOAD;
} }
if(stream->shut_flags & NGHTTP2_SHUT_RD) { if(stream->shut_flags & NGHTTP2_SHUT_RD) {
@ -3330,7 +3372,7 @@ static int nghttp2_session_on_data_received_fail_fast(nghttp2_session *session)
return 0; return 0;
fail: fail:
rv = nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); rv = nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR);
if(rv != 0) { if(nghttp2_is_fatal(rv)) {
return rv; return rv;
} }
return NGHTTP2_ERR_IGN_PAYLOAD; return NGHTTP2_ERR_IGN_PAYLOAD;

View File

@ -555,7 +555,11 @@ void test_nghttp2_session_recv_data(void)
CU_ASSERT(0 == ud.data_chunk_recv_cb_called); CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
CU_ASSERT(0 == ud.frame_recv_cb_called); CU_ASSERT(0 == ud.frame_recv_cb_called);
item = nghttp2_session_get_next_ob_item(session); item = nghttp2_session_get_next_ob_item(session);
CU_ASSERT(NULL == item); CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
nghttp2_session_del(session);
nghttp2_session_client_new(&session, &callbacks, &ud);
/* Create stream 1 with CLOSING state. DATA is ignored. */ /* Create stream 1 with CLOSING state. DATA is ignored. */
stream = nghttp2_session_open_stream(session, 1, stream = nghttp2_session_open_stream(session, 1,
@ -610,7 +614,7 @@ void test_nghttp2_session_recv_data(void)
in the error condition. We have received 4096 * 4 bytes of in the error condition. We have received 4096 * 4 bytes of
DATA. Additional 4 DATA frames, connection flow control will kick DATA. Additional 4 DATA frames, connection flow control will kick
in. */ in. */
for(i = 0; i < 4; ++i) { for(i = 0; i < 5; ++i) {
rv = nghttp2_session_mem_recv(session, data, 8+4096); rv = nghttp2_session_mem_recv(session, data, 8+4096);
CU_ASSERT(8+4096 == rv); CU_ASSERT(8+4096 == rv);
} }