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,
|
const spdylay_session_callbacks *callbacks,
|
||||||
void *user_data);
|
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|.
|
* 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,
|
const spdylay_session_callbacks *callbacks,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -76,10 +76,9 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
}
|
}
|
||||||
memset(*session_ptr, 0, sizeof(spdylay_session));
|
memset(*session_ptr, 0, sizeof(spdylay_session));
|
||||||
|
|
||||||
/* IDs for use in client */
|
/* next_stream_id, last_recv_stream_id and next_unique_id are
|
||||||
(*session_ptr)->next_stream_id = 1;
|
initialized in either spdylay_session_client_new or
|
||||||
(*session_ptr)->last_recv_stream_id = 0;
|
spdylay_session_server_new */
|
||||||
(*session_ptr)->next_unique_id = 1;
|
|
||||||
|
|
||||||
(*session_ptr)->last_ping_unique_id = 0;
|
(*session_ptr)->last_ping_unique_id = 0;
|
||||||
|
|
||||||
|
@ -124,6 +123,37 @@ int spdylay_session_client_new(spdylay_session **session_ptr,
|
||||||
return 0;
|
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)
|
static void spdylay_free_streams(key_type key, void *val)
|
||||||
{
|
{
|
||||||
spdylay_stream_free((spdylay_stream*)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,
|
static int spdylay_session_validate_syn_stream(spdylay_session *session,
|
||||||
spdylay_syn_stream *frame)
|
spdylay_syn_stream *frame)
|
||||||
{
|
{
|
||||||
/* TODO Check assoc_stream_id */
|
|
||||||
if(!spdylay_session_is_new_peer_stream_id(session, frame->stream_id)) {
|
if(!spdylay_session_is_new_peer_stream_id(session, frame->stream_id)) {
|
||||||
return SPDYLAY_PROTOCOL_ERROR;
|
return SPDYLAY_PROTOCOL_ERROR;
|
||||||
}
|
}
|
||||||
if(frame->hd.version != SPDYLAY_PROTO_VERSION) {
|
if(frame->hd.version != SPDYLAY_PROTO_VERSION) {
|
||||||
return SPDYLAY_UNSUPPORTED_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,9 @@ typedef struct {
|
||||||
uint8_t pri;
|
uint8_t pri;
|
||||||
/* Bitwise OR of zero or more spdylay_shut_flag values */
|
/* Bitwise OR of zero or more spdylay_shut_flag values */
|
||||||
uint8_t shut_flags;
|
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;
|
} spdylay_stream;
|
||||||
|
|
||||||
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
|
void spdylay_stream_init(spdylay_stream *stream, int32_t stream_id,
|
||||||
|
|
|
@ -73,6 +73,8 @@ int main()
|
||||||
test_spdylay_session_add_frame) ||
|
test_spdylay_session_add_frame) ||
|
||||||
!CU_add_test(pSuite, "session_on_syn_stream_received",
|
!CU_add_test(pSuite, "session_on_syn_stream_received",
|
||||||
test_spdylay_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",
|
!CU_add_test(pSuite, "session_on_syn_reply_received",
|
||||||
test_spdylay_session_on_syn_reply_received) ||
|
test_spdylay_session_on_syn_reply_received) ||
|
||||||
!CU_add_test(pSuite, "session_send_syn_stream",
|
!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()
|
void test_spdylay_session_on_syn_stream_received()
|
||||||
{
|
{
|
||||||
spdylay_session *session;
|
spdylay_session *session;
|
||||||
spdylay_session_callbacks callbacks = {
|
spdylay_session_callbacks callbacks;
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
on_ctrl_recv_callback,
|
|
||||||
on_invalid_ctrl_recv_callback
|
|
||||||
};
|
|
||||||
my_user_data user_data;
|
my_user_data user_data;
|
||||||
const char *nv[] = { NULL };
|
const char *nv[] = { NULL };
|
||||||
spdylay_frame frame;
|
spdylay_frame frame;
|
||||||
spdylay_stream *stream;
|
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.valid = 0;
|
||||||
user_data.invalid = 0;
|
user_data.invalid = 0;
|
||||||
|
|
||||||
spdylay_session_client_new(&session, &callbacks, &user_data);
|
spdylay_session_client_new(&session, &callbacks, &user_data);
|
||||||
spdylay_frame_syn_stream_init(&frame.syn_stream, SPDYLAY_FLAG_NONE,
|
spdylay_session_open_stream(session, assoc_stream_id, SPDYLAY_FLAG_NONE,
|
||||||
2, 0, 3, dup_nv(nv));
|
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(0 == spdylay_session_on_syn_stream_received(session, &frame));
|
||||||
CU_ASSERT(1 == user_data.valid);
|
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(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(0 == spdylay_session_on_syn_stream_received(session, &frame));
|
||||||
CU_ASSERT(1 == user_data.invalid);
|
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_frame_syn_stream_free(&frame.syn_stream);
|
||||||
spdylay_session_del(session);
|
spdylay_session_del(session);
|
||||||
|
@ -476,36 +535,6 @@ void test_spdylay_session_reply_fail()
|
||||||
spdylay_session_del(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_spdylay_session_on_headers_received()
|
void test_spdylay_session_on_headers_received()
|
||||||
{
|
{
|
||||||
spdylay_session *session;
|
spdylay_session *session;
|
||||||
|
|
|
@ -29,6 +29,7 @@ void test_spdylay_session_recv();
|
||||||
void test_spdylay_session_recv_invalid_stream_id();
|
void test_spdylay_session_recv_invalid_stream_id();
|
||||||
void test_spdylay_session_add_frame();
|
void test_spdylay_session_add_frame();
|
||||||
void test_spdylay_session_on_syn_stream_received();
|
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_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();
|
||||||
|
|
Loading…
Reference in New Issue