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:
Tatsuhiro Tsujikawa 2012-01-27 17:09:40 +09:00
parent 19096a74a3
commit beb509ef39
4 changed files with 116 additions and 4 deletions

View File

@ -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, ssize_t spdylay_session_prep_frame(spdylay_session *session,
spdylay_outbound_item *item, spdylay_outbound_item *item,
uint8_t **framebuf_ptr) uint8_t **framebuf_ptr)
@ -286,6 +319,10 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
break; break;
} }
case SPDYLAY_SYN_REPLY: { 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, framebuflen = spdylay_frame_pack_syn_reply(&framebuf,
&item->frame->syn_reply, &item->frame->syn_reply,
&session->hd_deflater); &session->hd_deflater);
@ -295,6 +332,9 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
break; break;
} }
case SPDYLAY_DATA: { 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, framebuflen = spdylay_session_pack_data(session, &framebuf,
&item->frame->data); &item->frame->data);
if(framebuflen < 0) { if(framebuflen < 0) {
@ -564,10 +604,18 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session,
{ {
int r; int r;
if(spdylay_session_validate_syn_stream(session, &frame->syn_stream) == 0) { 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, r = spdylay_session_open_stream(session, frame->syn_stream.stream_id,
frame->syn_stream.hd.flags, frame->syn_stream.hd.flags,
frame->syn_stream.pri, frame->syn_stream.pri,
SPDYLAY_STREAM_OPENING); SPDYLAY_STREAM_OPENING);
}
if(r == 0) { if(r == 0) {
session->last_recv_stream_id = frame->syn_stream.stream_id; session->last_recv_stream_id = frame->syn_stream.stream_id;
spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_SYN_STREAM, spdylay_session_call_on_ctrl_frame_received(session, SPDYLAY_SYN_STREAM,

View File

@ -80,6 +80,8 @@ int main()
!CU_add_test(pSuite, "session_send_syn_reply", !CU_add_test(pSuite, "session_send_syn_reply",
test_spdylay_session_send_syn_reply) || test_spdylay_session_send_syn_reply) ||
!CU_add_test(pSuite, "reply_submit", test_spdylay_reply_submit) || !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_unpack_nv", test_spdylay_frame_unpack_nv) ||
!CU_add_test(pSuite, "frame_count_nv_space", !CU_add_test(pSuite, "frame_count_nv_space",
test_spdylay_frame_count_nv_space)) { test_spdylay_frame_count_nv_space)) {

View File

@ -70,6 +70,13 @@ static ssize_t null_send_callback(spdylay_session *session,
return len; 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, static ssize_t scripted_recv_callback(spdylay_session *session,
uint8_t* data, size_t len, int flags, uint8_t* data, size_t len, int flags,
void *user_data) void *user_data)
@ -417,3 +424,57 @@ void test_spdylay_reply_submit()
spdylay_session_del(session); 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);
}

View File

@ -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_stream();
void test_spdylay_session_send_syn_reply(); void test_spdylay_session_send_syn_reply();
void test_spdylay_reply_submit(); void test_spdylay_reply_submit();
void test_spdylay_session_reply_fail();
#endif // SPDYLAY_SESSION_TEST_H #endif // SPDYLAY_SESSION_TEST_H