Closes all server-pushed streams when original stream is closed by RST_STREAM with CANCEL from client.

Fixed spdylay_session_is_my_stream_id()
This commit is contained in:
Tatsuhiro Tsujikawa 2012-02-02 23:19:01 +09:00
parent bb6a90dc4d
commit 4030c5ccf5
5 changed files with 140 additions and 7 deletions

View File

@ -32,19 +32,15 @@
#include "spdylay_helper.h"
/*
* Returns non-zero value if |stream_id| is initiated by local host.
* Otherwrise returns 0.
*/
static int spdylay_session_is_my_stream_id(spdylay_session *session,
int32_t stream_id)
int spdylay_session_is_my_stream_id(spdylay_session *session,
int32_t stream_id)
{
int r;
if(stream_id == 0) {
return 0;
}
r = stream_id % 2;
return (session->server && r == 0) || r == 1;
return (session->server && r == 0) || (!session->server && r == 1);
}
spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
@ -359,6 +355,21 @@ int spdylay_session_close_stream_if_shut_rdwr(spdylay_session *session,
}
}
void spdylay_session_close_pushed_streams(spdylay_session *session,
int32_t stream_id,
spdylay_status_code status_code)
{
spdylay_stream *stream;
stream = spdylay_session_get_stream(session, stream_id);
if(stream) {
int i;
for(i = 0; i < stream->pushed_streams_length; ++i) {
spdylay_session_close_stream(session, stream->pushed_streams[i],
status_code);
}
}
}
/*
* Returns non-zero value if local peer can send SYN_REPLY with stream
* ID |stream_id| at the moment, or 0.
@ -398,6 +409,7 @@ ssize_t spdylay_session_prep_frame(spdylay_session *session,
uint8_t **framebuf_ptr)
{
/* TODO Get or validate stream ID here */
/* TODO Validate assoc_stream_id here */
uint8_t *framebuf;
ssize_t framebuflen;
switch(item->frame_type) {
@ -582,6 +594,12 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
break;
}
case SPDYLAY_RST_STREAM:
if(!session->server &&
spdylay_session_is_my_stream_id(session, frame->rst_stream.stream_id) &&
frame->rst_stream.status_code == SPDYLAY_CANCEL) {
spdylay_session_close_pushed_streams(session, frame->rst_stream.stream_id,
frame->rst_stream.status_code);
}
spdylay_session_close_stream(session, frame->rst_stream.stream_id,
frame->rst_stream.status_code);
break;
@ -931,6 +949,12 @@ int spdylay_session_on_syn_reply_received(spdylay_session *session,
int spdylay_session_on_rst_stream_received(spdylay_session *session,
spdylay_frame *frame)
{
if(session->server &&
!spdylay_session_is_my_stream_id(session, frame->rst_stream.stream_id) &&
frame->rst_stream.status_code == SPDYLAY_CANCEL) {
spdylay_session_close_pushed_streams(session, frame->rst_stream.stream_id,
frame->rst_stream.status_code);
}
spdylay_session_close_stream(session, frame->rst_stream.stream_id,
frame->rst_stream.status_code);
return 0;

View File

@ -125,6 +125,13 @@ struct spdylay_session {
/* TODO stream timeout etc */
/*
* Returns non-zero value if |stream_id| is initiated by local host.
* Otherwrise returns 0.
*/
int spdylay_session_is_my_stream_id(spdylay_session *session,
int32_t stream_id);
/*
* Adds frame |frame| of type |frame_type| to tx queue in |session|.
* |aux_data| is a pointer to arbitrary data. Its interpretation is
@ -169,6 +176,14 @@ spdylay_stream* spdylay_session_open_stream(spdylay_session *session,
int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id,
spdylay_status_code status_code);
/*
* Closes all pushed streams which associate them to stream
* |stream_id| with the status code |status_code|.
*/
void spdylay_session_close_pushed_streams(spdylay_session *session,
int32_t stream_id,
spdylay_status_code status_code);
/*
* If further receptions and transmissions over this stream are
* disallowed, close this stream. This function returns 0 if it

View File

@ -95,6 +95,12 @@ int main()
test_spdylay_session_on_goaway_received) ||
!CU_add_test(pSuite, "session_on_data_received",
test_spdylay_session_on_data_received) ||
!CU_add_test(pSuite, "session_on_rst_stream_received",
test_spdylay_session_on_rst_received) ||
!CU_add_test(pSuite, "session_is_my_stream_id",
test_spdylay_session_is_my_stream_id) ||
!CU_add_test(pSuite, "session_send_rst_stream",
test_spdylay_session_send_rst_stream) ||
!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) ||

View File

@ -707,3 +707,88 @@ void test_spdylay_session_on_data_received()
spdylay_session_del(session);
}
void test_spdylay_session_is_my_stream_id()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, &callbacks, NULL);
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0));
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 1));
CU_ASSERT(1 == spdylay_session_is_my_stream_id(session, 2));
spdylay_session_del(session);
spdylay_session_client_new(&session, &callbacks, NULL);
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 0));
CU_ASSERT(1 == spdylay_session_is_my_stream_id(session, 1));
CU_ASSERT(0 == spdylay_session_is_my_stream_id(session, 2));
spdylay_session_del(session);
}
void test_spdylay_session_on_rst_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream;
spdylay_frame frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
spdylay_session_server_new(&session, &callbacks, &user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING);
/* server push */
spdylay_session_open_stream(session, 2, SPDYLAY_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING);
spdylay_stream_add_pushed_stream(stream, 2);
spdylay_session_open_stream(session, 4, SPDYLAY_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING);
spdylay_stream_add_pushed_stream(stream, 4);
spdylay_frame_rst_stream_init(&frame.rst_stream, 1, SPDYLAY_CANCEL);
CU_ASSERT(0 == spdylay_session_on_rst_stream_received(session, &frame));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 1));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 2));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 4));
spdylay_frame_rst_stream_free(&frame.rst_stream);
spdylay_session_del(session);
}
void test_spdylay_session_send_rst_stream()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
spdylay_stream *stream;
spdylay_frame *frame;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
spdylay_session_client_new(&session, &callbacks, &user_data);
stream = spdylay_session_open_stream(session, 1, SPDYLAY_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING);
/* server push */
spdylay_session_open_stream(session, 2, SPDYLAY_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING);
spdylay_stream_add_pushed_stream(stream, 2);
spdylay_session_open_stream(session, 4, SPDYLAY_FLAG_NONE,
3, SPDYLAY_STREAM_OPENING);
spdylay_stream_add_pushed_stream(stream, 4);
frame = malloc(sizeof(spdylay_frame));
spdylay_frame_rst_stream_init(&frame->rst_stream, 1, SPDYLAY_CANCEL);
spdylay_session_add_frame(session, SPDYLAY_RST_STREAM, frame, NULL);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 1));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 2));
CU_ASSERT(NULL == spdylay_session_get_stream(session, 4));
spdylay_session_del(session);
}

View File

@ -40,5 +40,8 @@ void test_spdylay_session_on_headers_received();
void test_spdylay_session_on_ping_received();
void test_spdylay_session_on_goaway_received();
void test_spdylay_session_on_data_received();
void test_spdylay_session_on_rst_received();
void test_spdylay_session_is_my_stream_id();
void test_spdylay_session_send_rst_stream();
#endif // SPDYLAY_SESSION_TEST_H