Added server push SYN_STREAM validation. Added spdylay_session_server_new()

We still does not check "url" is in nv.
This commit is contained in:
Tatsuhiro Tsujikawa 2012-02-02 00:19:31 +09:00
parent 45376c6b11
commit 562278194c
6 changed files with 139 additions and 48 deletions

View File

@ -316,6 +316,14 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
const spdylay_session_callbacks *callbacks,
void *user_data);
/*
* Initializes |*session_ptr| for server use. This function returns 0
* if it succeeds, or negative error code.
*/
int spdylay_session_server_new(spdylay_session **session_ptr,
const spdylay_session_callbacks *callbacks,
void *user_data);
/*
* Frees any resources allocated for |session|.
*/

View File

@ -65,7 +65,7 @@ int spdylay_outbound_item_compar(const void *lhsx, const void *rhsx)
}
}
int spdylay_session_client_new(spdylay_session **session_ptr,
static int spdylay_session_new(spdylay_session **session_ptr,
const spdylay_session_callbacks *callbacks,
void *user_data)
{
@ -76,10 +76,9 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
}
memset(*session_ptr, 0, sizeof(spdylay_session));
/* IDs for use in client */
(*session_ptr)->next_stream_id = 1;
(*session_ptr)->last_recv_stream_id = 0;
(*session_ptr)->next_unique_id = 1;
/* next_stream_id, last_recv_stream_id and next_unique_id are
initialized in either spdylay_session_client_new or
spdylay_session_server_new */
(*session_ptr)->last_ping_unique_id = 0;
@ -124,6 +123,37 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
return 0;
}
int spdylay_session_client_new(spdylay_session **session_ptr,
const spdylay_session_callbacks *callbacks,
void *user_data)
{
int r;
r = spdylay_session_new(session_ptr, callbacks, user_data);
if(r == 0) {
/* IDs for use in client */
(*session_ptr)->next_stream_id = 1;
(*session_ptr)->last_recv_stream_id = 0;
(*session_ptr)->next_unique_id = 1;
}
return r;
}
int spdylay_session_server_new(spdylay_session **session_ptr,
const spdylay_session_callbacks *callbacks,
void *user_data)
{
int r;
r = spdylay_session_new(session_ptr, callbacks, user_data);
if(r == 0) {
(*session_ptr)->server = 1;
/* IDs for use in client */
(*session_ptr)->next_stream_id = 2;
(*session_ptr)->last_recv_stream_id = 0;
(*session_ptr)->next_unique_id = 2;
}
return r;
}
static void spdylay_free_streams(key_type key, void *val)
{
spdylay_stream_free((spdylay_stream*)val);
@ -769,13 +799,31 @@ static int spdylay_session_is_new_peer_stream_id(spdylay_session *session,
static int spdylay_session_validate_syn_stream(spdylay_session *session,
spdylay_syn_stream *frame)
{
/* TODO Check assoc_stream_id */
if(!spdylay_session_is_new_peer_stream_id(session, frame->stream_id)) {
return SPDYLAY_PROTOCOL_ERROR;
}
if(frame->hd.version != SPDYLAY_PROTO_VERSION) {
return SPDYLAY_UNSUPPORTED_VERSION;
}
if(session->server) {
if(frame->assoc_stream_id != 0) {
return SPDYLAY_PROTOCOL_ERROR;
}
} else {
if(frame->assoc_stream_id == 0) {
/* spdy/2 spec: When a client receives a SYN_STREAM from the
server with an Associated-To-Stream-ID of 0, it must reply with
a RST_STREAM with error code INVALID_STREAM. */
return SPDYLAY_INVALID_STREAM;
}
if((frame->hd.flags & SPDYLAY_FLAG_UNIDIRECTIONAL) == 0 ||
frame->assoc_stream_id % 2 == 0 ||
spdylay_session_get_stream(session, frame->assoc_stream_id) == NULL) {
/* It seems spdy/2 spec does not say which status code should be
returned in these cases. */
return SPDYLAY_PROTOCOL_ERROR;
}
}
return 0;
}

View File

@ -77,6 +77,9 @@ typedef struct {
uint8_t pri;
/* Bitwise OR of zero or more spdylay_shut_flag values */
uint8_t shut_flags;
/* TODO spdylay_stream should remember pushed stream ID, so that if
RST_STREAM with CANCEL (mandatory?) is sent, we can close all of
them. */
} spdylay_stream;
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,

View File

@ -73,6 +73,8 @@ int main()
test_spdylay_session_add_frame) ||
!CU_add_test(pSuite, "session_on_syn_stream_received",
test_spdylay_session_on_syn_stream_received) ||
!CU_add_test(pSuite, "session_on_syn_stream_received_with_push",
test_spdylay_session_on_syn_stream_received_with_push) ||
!CU_add_test(pSuite, "session_on_syn_reply_received",
test_spdylay_session_on_syn_reply_received) ||
!CU_add_test(pSuite, "session_send_syn_stream",

View File

@ -279,33 +279,92 @@ void test_spdylay_session_recv_invalid_stream_id()
void test_spdylay_session_on_syn_stream_received()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
NULL,
NULL,
on_ctrl_recv_callback,
on_invalid_ctrl_recv_callback
};
spdylay_session_callbacks callbacks;
my_user_data user_data;
const char *nv[] = { NULL };
spdylay_frame frame;
spdylay_stream *stream;
int32_t stream_id = 1;
uint8_t pri = 3;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
user_data.valid = 0;
user_data.invalid = 0;
spdylay_session_server_new(&session, &callbacks, &user_data);
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_FLAG_NONE,
stream_id, 0, pri, dup_nv(nv));
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.valid);
stream = spdylay_session_get_stream(session, stream_id);
CU_ASSERT(SPDYLAY_STREAM_OPENING == stream->state);
CU_ASSERT(pri == stream->pri);
/* Same stream ID twice leads stream closing */
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.invalid);
CU_ASSERT(SPDYLAY_STREAM_CLOSING ==
spdylay_session_get_stream(session, stream_id)->state);
/* assoc_stream_id != 0 from client is invalid. */
frame.syn_stream.assoc_stream_id = 1;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(2 == user_data.invalid);
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
}
void test_spdylay_session_on_syn_stream_received_with_push()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
my_user_data user_data;
const char *nv[] = { NULL };
spdylay_frame frame;
spdylay_stream *stream;
int32_t stream_id = 2;
int32_t assoc_stream_id = 1;
uint8_t pri = 3;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.on_ctrl_recv_callback = on_ctrl_recv_callback;
callbacks.on_invalid_ctrl_recv_callback = on_invalid_ctrl_recv_callback;
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_NONE,
2, 0, 3, dup_nv(nv));
spdylay_session_open_stream(session, assoc_stream_id, SPDYLAY_FLAG_NONE,
pri, SPDYLAY_STREAM_OPENED);
spdylay_frame_syn_stream_init(&frame.syn_stream,
SPDYLAY_FLAG_UNIDIRECTIONAL,
stream_id, assoc_stream_id, pri, 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);
stream = spdylay_session_get_stream(session, stream_id);
CU_ASSERT(SPDYLAY_STREAM_OPENING == stream->state);
CU_ASSERT(3 == stream->pri);
/* assoc_stream_id == 0 is invalid */
frame.syn_stream.stream_id = 4;
frame.syn_stream.assoc_stream_id = 0;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(1 == user_data.invalid);
CU_ASSERT(SPDYLAY_STREAM_CLOSING ==
((spdylay_stream*)spdylay_map_find(&session->streams, 2))->state);
/* Push without SPDYLAY_FLAG_UNIDIRECTIONAL is invalid */
frame.syn_stream.stream_id = 6;
frame.syn_stream.assoc_stream_id = 1;
frame.syn_stream.hd.flags = SPDYLAY_FLAG_FIN;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(2 == user_data.invalid);
/* Push to non-existent stream is invalid */
frame.syn_stream.stream_id = 8;
frame.syn_stream.assoc_stream_id = 3;
frame.syn_stream.hd.flags = SPDYLAY_FLAG_UNIDIRECTIONAL;
CU_ASSERT(0 == spdylay_session_on_syn_stream_received(session, &frame));
CU_ASSERT(3 == user_data.invalid);
spdylay_frame_syn_stream_free(&frame.syn_stream);
spdylay_session_del(session);
@ -476,36 +535,6 @@ void test_spdylay_session_reply_fail()
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);
}
void test_spdylay_session_on_headers_received()
{
spdylay_session *session;

View File

@ -29,6 +29,7 @@ void test_spdylay_session_recv();
void test_spdylay_session_recv_invalid_stream_id();
void test_spdylay_session_add_frame();
void test_spdylay_session_on_syn_stream_received();
void test_spdylay_session_on_syn_stream_received_with_push();
void test_spdylay_session_on_syn_reply_received();
void test_spdylay_session_send_syn_stream();
void test_spdylay_session_send_syn_reply();