diff --git a/lib/spdylay_session.c b/lib/spdylay_session.c index ee829294..7c5f6886 100644 --- a/lib/spdylay_session.c +++ b/lib/spdylay_session.c @@ -1529,6 +1529,7 @@ int spdylay_session_on_syn_reply_received(spdylay_session *session, { int r = 0; int valid = 0; + int status_code = SPDYLAY_PROTOCOL_ERROR; spdylay_stream *stream; if(!spdylay_session_check_version(session, frame->syn_reply.hd.version)) { return 0; @@ -1554,13 +1555,21 @@ int spdylay_session_on_syn_reply_received(spdylay_session *session, that we queued RST_STREAM but it has not been sent. It will eventually sent, so we just ignore this frame. */ valid = 1; + } else { + if(session->version == SPDYLAY_PROTO_SPDY3) { + /* SPDY/3 spec says if multiple SYN_REPLY frames for the + same active stream ID are received, the receiver must + issue a stream error with the status code + STREAM_IN_USE. */ + status_code = SPDYLAY_STREAM_IN_USE; + } } } } if(!valid) { r = spdylay_session_handle_invalid_stream (session, frame->syn_reply.stream_id, SPDYLAY_SYN_REPLY, frame, - SPDYLAY_PROTOCOL_ERROR); + status_code); } return r; } diff --git a/tests/spdylay_session_test.c b/tests/spdylay_session_test.c index 4d99dd2f..a45a2997 100644 --- a/tests/spdylay_session_test.c +++ b/tests/spdylay_session_test.c @@ -473,20 +473,19 @@ void test_spdylay_session_on_syn_stream_received_with_push() void test_spdylay_session_on_syn_reply_received() { spdylay_session *session; - spdylay_session_callbacks callbacks = { - NULL, - NULL, - on_ctrl_recv_callback, - on_invalid_ctrl_recv_callback - }; + spdylay_session_callbacks callbacks; my_user_data user_data; const char *nv[] = { NULL }; const char *upcase_nv[] = { "version", "http/1.1", "methoD", "get", NULL }; spdylay_frame frame; spdylay_stream *stream; + spdylay_outbound_item *item; user_data.ctrl_recv_cb_called = 0; user_data.invalid_ctrl_recv_cb_called = 0; + memset(&callbacks, 0, sizeof(spdylay_session_callbacks)); + callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback; + callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback; spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks, &user_data); spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0, @@ -527,6 +526,25 @@ void test_spdylay_session_on_syn_reply_received() spdylay_frame_syn_reply_free(&frame.syn_reply); spdylay_session_del(session); + + spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, + &user_data); + + /* Multiple SYN_REPLY frames for the same active stream ID */ + spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_NONE, 0, + SPDYLAY_STREAM_OPENED, NULL); + spdylay_frame_syn_reply_init(&frame.syn_reply, SPDYLAY_PROTO_SPDY3, + SPDYLAY_CTRL_FLAG_NONE, 1, dup_nv(nv)); + user_data.invalid_ctrl_recv_cb_called = 0; + CU_ASSERT(0 == spdylay_session_on_syn_reply_received(session, &frame)); + CU_ASSERT(1 == user_data.invalid_ctrl_recv_cb_called); + item = spdylay_session_get_next_ob_item(session); + CU_ASSERT(SPDYLAY_RST_STREAM == item->frame_type); + CU_ASSERT(SPDYLAY_STREAM_IN_USE == item->frame->rst_stream.status_code); + + spdylay_frame_syn_reply_free(&frame.syn_reply); + + spdylay_session_del(session); } void test_spdylay_session_send_syn_stream()