Check stream before sending SYN_REPLY and DATA. Don't make stream if incoming SYN_STREAM has FIN and UNIDIRECTIONAL set.
This commit is contained in:
parent
19096a74a3
commit
beb509ef39
|
@ -257,6 +257,39 @@ int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns non-zero value if local peer can send SYN_REPLY with stream
|
||||
* ID |stream_id| at the moment, or 0.
|
||||
*/
|
||||
static int spdylay_session_is_reply_allowed(spdylay_session *session,
|
||||
int32_t stream_id)
|
||||
{
|
||||
spdylay_stream *stream = spdylay_session_get_stream(session, stream_id);
|
||||
if(stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if(spdylay_session_is_my_stream_id(session, stream_id)) {
|
||||
return 0;
|
||||
} else {
|
||||
return stream->state == SPDYLAY_STREAM_OPENING &&
|
||||
(stream->flags & SPDYLAY_FLAG_UNIDIRECTIONAL) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int spdylay_session_is_data_allowed(spdylay_session *session,
|
||||
int32_t stream_id)
|
||||
{
|
||||
spdylay_stream *stream = spdylay_session_get_stream(session, stream_id);
|
||||
if(stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if(spdylay_session_is_my_stream_id(session, stream_id)) {
|
||||
return (stream->flags & SPDYLAY_FLAG_FIN) == 0;
|
||||
} else {
|
||||
return stream->state == SPDYLAY_STREAM_OPENED;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||
spdylay_outbound_item *item,
|
||||
uint8_t **framebuf_ptr)
|
||||
|
@ -286,6 +319,10 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
|||
break;
|
||||
}
|
||||
case SPDYLAY_SYN_REPLY: {
|
||||
if(!spdylay_session_is_reply_allowed(session,
|
||||
item->frame->syn_reply.stream_id)) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
framebuflen = spdylay_frame_pack_syn_reply(&framebuf,
|
||||
&item->frame->syn_reply,
|
||||
&session->hd_deflater);
|
||||
|
@ -295,6 +332,9 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
|||
break;
|
||||
}
|
||||
case SPDYLAY_DATA: {
|
||||
if(!spdylay_session_is_data_allowed(session, item->frame->data.stream_id)) {
|
||||
return SPDYLAY_ERR_INVALID_FRAME;
|
||||
}
|
||||
framebuflen = spdylay_session_pack_data(session, &framebuf,
|
||||
&item->frame->data);
|
||||
if(framebuflen < 0) {
|
||||
|
@ -564,10 +604,18 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session,
|
|||
{
|
||||
int r;
|
||||
if(spdylay_session_validate_syn_stream(session, &frame->syn_stream) == 0) {
|
||||
uint8_t flags = frame->syn_stream.hd.flags;
|
||||
if((flags & SPDYLAY_FLAG_FIN) && (flags & SPDYLAY_FLAG_UNIDIRECTIONAL)) {
|
||||
/* If the stream is UNIDIRECTIONAL and FIN bit set, we can close
|
||||
stream upon receiving SYN_STREAM. So, the stream needs not to
|
||||
be opened. */
|
||||
r = 0;
|
||||
} else {
|
||||
r = spdylay_session_open_stream(session, frame->syn_stream.stream_id,
|
||||
frame->syn_stream.hd.flags,
|
||||
frame->syn_stream.pri,
|
||||
SPDYLAY_STREAM_OPENING);
|
||||
}
|
||||
if(r == 0) {
|
||||
session->last_recv_stream_id = frame->syn_stream.stream_id;
|
||||
spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_SYN_STREAM,
|
||||
|
|
|
@ -80,6 +80,8 @@ int main()
|
|||
!CU_add_test(pSuite, "session_send_syn_reply",
|
||||
test_spdylay_session_send_syn_reply) ||
|
||||
!CU_add_test(pSuite, "reply_submit", test_spdylay_reply_submit) ||
|
||||
!CU_add_test(pSuite, "session_reply_fail",
|
||||
test_spdylay_session_reply_fail) ||
|
||||
!CU_add_test(pSuite, "frame_unpack_nv", test_spdylay_frame_unpack_nv) ||
|
||||
!CU_add_test(pSuite, "frame_count_nv_space",
|
||||
test_spdylay_frame_count_nv_space)) {
|
||||
|
|
|
@ -70,6 +70,13 @@ static ssize_t null_send_callback(spdylay_session *session,
|
|||
return len;
|
||||
}
|
||||
|
||||
static ssize_t fail_send_callback(spdylay_session *session,
|
||||
const uint8_t *data, size_t len, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
static ssize_t scripted_recv_callback(spdylay_session *session,
|
||||
uint8_t* data, size_t len, int flags,
|
||||
void *user_data)
|
||||
|
@ -417,3 +424,57 @@ void test_spdylay_reply_submit()
|
|||
spdylay_session_del(session);
|
||||
}
|
||||
|
||||
void test_spdylay_session_reply_fail()
|
||||
{
|
||||
spdylay_session *session;
|
||||
spdylay_session_callbacks callbacks = {
|
||||
fail_send_callback,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
const char *nv[] = { NULL };
|
||||
spdylay_stream *stream;
|
||||
int32_t stream_id = 2;
|
||||
spdylay_data_source source;
|
||||
spdylay_data_provider data_prd = {
|
||||
source,
|
||||
fixed_length_data_source_read_callback
|
||||
};
|
||||
my_user_data ud;
|
||||
ud.data_source_length = 4*1024;
|
||||
CU_ASSERT(0 == spdylay_session_client_new(&session, &callbacks, &ud));
|
||||
CU_ASSERT(0 == spdylay_reply_submit(session, stream_id, nv, &data_prd));
|
||||
CU_ASSERT(0 == spdylay_session_send(session));
|
||||
spdylay_session_del(session);
|
||||
}
|
||||
|
||||
void test_spdylay_session_on_syn_stream_received_with_unidir_fin()
|
||||
{
|
||||
spdylay_session *session;
|
||||
spdylay_session_callbacks callbacks = {
|
||||
NULL,
|
||||
NULL,
|
||||
on_ctrl_recv_callback,
|
||||
NULL
|
||||
};
|
||||
my_user_data user_data;
|
||||
const char *nv[] = { NULL };
|
||||
spdylay_frame frame;
|
||||
spdylay_stream *stream;
|
||||
user_data.valid = 0;
|
||||
user_data.invalid = 0;
|
||||
|
||||
spdylay_session_client_new(&session, &callbacks, &user_data);
|
||||
spdylay_frame_syn_stream_init(&frame.syn_stream,
|
||||
SPDYLAY_FLAG_FIN | SPDYLAY_FLAG_UNIDIRECTIONAL,
|
||||
2, 0, 3, dup_nv(nv));
|
||||
|
||||
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
|
||||
CU_ASSERT(1 == user_data.valid);
|
||||
stream = (spdylay_stream*)spdylay_map_find(&session->streams, 2);
|
||||
CU_ASSERT(NULL == stream);
|
||||
|
||||
spdylay_frame_syn_stream_free(&frame.syn_stream);
|
||||
spdylay_session_del(session);
|
||||
}
|
||||
|
|
|
@ -33,5 +33,6 @@ void test_spdylay_session_on_syn_reply_received();
|
|||
void test_spdylay_session_send_syn_stream();
|
||||
void test_spdylay_session_send_syn_reply();
|
||||
void test_spdylay_reply_submit();
|
||||
void test_spdylay_session_reply_fail();
|
||||
|
||||
#endif // SPDYLAY_SESSION_TEST_H
|
||||
|
|
Loading…
Reference in New Issue