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" #include "spdylay_helper.h"
/* int spdylay_session_is_my_stream_id(spdylay_session *session,
* Returns non-zero value if |stream_id| is initiated by local host. int32_t stream_id)
* Otherwrise returns 0.
*/
static int spdylay_session_is_my_stream_id(spdylay_session *session,
int32_t stream_id)
{ {
int r; int r;
if(stream_id == 0) { if(stream_id == 0) {
return 0; return 0;
} }
r = stream_id % 2; 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, 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 * Returns non-zero value if local peer can send SYN_REPLY with stream
* ID |stream_id| at the moment, or 0. * 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) uint8_t **framebuf_ptr)
{ {
/* TODO Get or validate stream ID here */ /* TODO Get or validate stream ID here */
/* TODO Validate assoc_stream_id here */
uint8_t *framebuf; uint8_t *framebuf;
ssize_t framebuflen; ssize_t framebuflen;
switch(item->frame_type) { switch(item->frame_type) {
@ -582,6 +594,12 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
break; break;
} }
case SPDYLAY_RST_STREAM: 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, spdylay_session_close_stream(session, frame->rst_stream.stream_id,
frame->rst_stream.status_code); frame->rst_stream.status_code);
break; 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, int spdylay_session_on_rst_stream_received(spdylay_session *session,
spdylay_frame *frame) 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, spdylay_session_close_stream(session, frame->rst_stream.stream_id,
frame->rst_stream.status_code); frame->rst_stream.status_code);
return 0; return 0;

View File

@ -125,6 +125,13 @@ struct spdylay_session {
/* TODO stream timeout etc */ /* 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|. * Adds frame |frame| of type |frame_type| to tx queue in |session|.
* |aux_data| is a pointer to arbitrary data. Its interpretation is * |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, int spdylay_session_close_stream(spdylay_session *session, int32_t stream_id,
spdylay_status_code status_code); 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 * If further receptions and transmissions over this stream are
* disallowed, close this stream. This function returns 0 if it * disallowed, close this stream. This function returns 0 if it

View File

@ -95,6 +95,12 @@ int main()
test_spdylay_session_on_goaway_received) || test_spdylay_session_on_goaway_received) ||
!CU_add_test(pSuite, "session_on_data_received", !CU_add_test(pSuite, "session_on_data_received",
test_spdylay_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_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

@ -707,3 +707,88 @@ void test_spdylay_session_on_data_received()
spdylay_session_del(session); 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_ping_received();
void test_spdylay_session_on_goaway_received(); void test_spdylay_session_on_goaway_received();
void test_spdylay_session_on_data_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 #endif // SPDYLAY_SESSION_TEST_H