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,
|
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,
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue