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:
parent
45376c6b11
commit
562278194c
|
@ -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|.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue