Take into account shut_flags when accepting DATA frame
This commit is contained in:
parent
14d1a5a547
commit
5236394c1c
|
@ -2449,6 +2449,32 @@ static int spdylay_session_update_recv_window_size(spdylay_session *session,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns nonzero if the reception of DATA for stream |stream_id| is
|
||||
* allowed.
|
||||
*/
|
||||
static int spdylay_session_check_data_recv_allowed(spdylay_session *session,
|
||||
int32_t stream_id)
|
||||
{
|
||||
spdylay_stream *stream;
|
||||
stream = spdylay_session_get_stream(session, stream_id);
|
||||
if(stream) {
|
||||
if((stream->shut_flags & SPDYLAY_SHUT_RD) == 0) {
|
||||
if(spdylay_session_is_my_stream_id(session, stream_id)) {
|
||||
if(stream->state == SPDYLAY_STREAM_OPENED) {
|
||||
return 1;
|
||||
}
|
||||
} else if(stream->state != SPDYLAY_STREAM_CLOSING) {
|
||||
/* It is OK if this is remote peer initiated stream and we did
|
||||
not receive FIN unless stream is in SPDYLAY_STREAM_CLOSING
|
||||
state. This is a race condition. */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
|
@ -2510,6 +2536,14 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
|||
assert(r < SPDYLAY_ERR_FATAL);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
/* Check stream is open. If it is not open or closing,
|
||||
ignore payload. */
|
||||
int32_t stream_id;
|
||||
stream_id = spdylay_get_uint32(session->iframe.headbuf);
|
||||
if(!spdylay_session_check_data_recv_allowed(session, stream_id)) {
|
||||
session->iframe.state = SPDYLAY_RECV_PAYLOAD_IGN;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
|
@ -2523,7 +2557,6 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
|||
size_t bufavail, readlen;
|
||||
int32_t data_stream_id = 0;
|
||||
uint8_t data_flags = SPDYLAY_DATA_FLAG_NONE;
|
||||
spdylay_stream *data_stream = NULL;
|
||||
|
||||
rempayloadlen = session->iframe.payloadlen - session->iframe.off;
|
||||
bufavail = inlimit - inmark;
|
||||
|
@ -2583,8 +2616,7 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
|||
data_stream_id = spdylay_get_uint32(session->iframe.headbuf) &
|
||||
SPDYLAY_STREAM_ID_MASK;
|
||||
data_flags = session->iframe.headbuf[4];
|
||||
data_stream = spdylay_session_get_stream(session, data_stream_id);
|
||||
if(data_stream && data_stream->state != SPDYLAY_STREAM_CLOSING) {
|
||||
if(session->iframe.state != SPDYLAY_RECV_PAYLOAD_IGN) {
|
||||
if(session->callbacks.on_data_chunk_recv_callback) {
|
||||
session->callbacks.on_data_chunk_recv_callback(session,
|
||||
data_flags,
|
||||
|
@ -2599,7 +2631,7 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
|||
inmark += readlen;
|
||||
|
||||
if(session->flow_control &&
|
||||
data_stream && data_stream->state != SPDYLAY_STREAM_CLOSING &&
|
||||
session->iframe.state != SPDYLAY_RECV_PAYLOAD_IGN &&
|
||||
!spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||
if(readlen > 0 &&
|
||||
(session->iframe.payloadlen != session->iframe.off ||
|
||||
|
@ -2618,11 +2650,7 @@ ssize_t spdylay_session_mem_recv(spdylay_session *session,
|
|||
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
|
||||
r = spdylay_session_process_ctrl_frame(session);
|
||||
} else {
|
||||
if(data_stream && data_stream->state != SPDYLAY_STREAM_CLOSING) {
|
||||
r = spdylay_session_process_data_frame(session);
|
||||
} else {
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
if(r < 0) {
|
||||
/* FATAL */
|
||||
|
|
|
@ -162,6 +162,8 @@ int main(int argc, char* argv[])
|
|||
test_spdylay_session_data_read_temporal_failure) ||
|
||||
!CU_add_test(pSuite, "session_recv_eof",
|
||||
test_spdylay_session_recv_eof) ||
|
||||
!CU_add_test(pSuite, "session_recv_data",
|
||||
test_spdylay_session_recv_data) ||
|
||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy2",
|
||||
test_spdylay_frame_unpack_nv_spdy2) ||
|
||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",
|
||||
|
|
|
@ -65,6 +65,8 @@ typedef struct {
|
|||
size_t data_source_length;
|
||||
int32_t stream_id;
|
||||
size_t block_count;
|
||||
int data_chunk_recv_cb_called;
|
||||
int data_recv_cb_called;
|
||||
} my_user_data;
|
||||
|
||||
static void scripted_data_feed_init(scripted_data_feed *df,
|
||||
|
@ -166,6 +168,23 @@ static void on_ctrl_not_send_callback(spdylay_session *session,
|
|||
ud->not_sent_error = error;
|
||||
}
|
||||
|
||||
static void on_data_chunk_recv_callback(spdylay_session *session,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
my_user_data *ud = (my_user_data*)user_data;
|
||||
++ud->data_chunk_recv_cb_called;
|
||||
}
|
||||
|
||||
static void on_data_recv_callback(spdylay_session *session,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t length, void *user_data)
|
||||
{
|
||||
my_user_data *ud = (my_user_data*)user_data;
|
||||
++ud->data_recv_cb_called;
|
||||
}
|
||||
|
||||
static ssize_t fixed_length_data_source_read_callback
|
||||
(spdylay_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t len, int *eof,
|
||||
|
@ -2546,3 +2565,67 @@ void test_spdylay_session_recv_eof(void)
|
|||
|
||||
spdylay_session_del(session);
|
||||
}
|
||||
|
||||
void test_spdylay_session_recv_data(void)
|
||||
{
|
||||
spdylay_session *session;
|
||||
spdylay_session_callbacks callbacks;
|
||||
my_user_data ud;
|
||||
uint8_t data[8092];
|
||||
int rv;
|
||||
spdylay_outbound_item *item;
|
||||
spdylay_stream *stream;
|
||||
|
||||
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
callbacks.on_data_recv_callback = on_data_recv_callback;
|
||||
|
||||
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, &ud);
|
||||
|
||||
/* Create DATA frame with length 4KiB */
|
||||
memset(data, 0, sizeof(data));
|
||||
spdylay_put_uint32be(data, 1);
|
||||
spdylay_put_uint32be(data+4, 4096);
|
||||
|
||||
/* stream 1 is not opened, so it must be responded with RST_STREAM */
|
||||
ud.data_chunk_recv_cb_called = 0;
|
||||
ud.data_recv_cb_called = 0;
|
||||
rv = spdylay_session_mem_recv(session, data, 8+4096);
|
||||
CU_ASSERT(8+4096 == rv);
|
||||
|
||||
CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
|
||||
CU_ASSERT(0 == ud.data_recv_cb_called);
|
||||
item = spdylay_session_get_next_ob_item(session);
|
||||
CU_ASSERT(SPDYLAY_RST_STREAM == OB_CTRL_TYPE(item));
|
||||
|
||||
CU_ASSERT(0 == spdylay_session_send(session));
|
||||
|
||||
/* Create stream 1 with CLOSING state. It is ignored. */
|
||||
stream = spdylay_session_open_stream(session, 1,
|
||||
SPDYLAY_CTRL_FLAG_NONE, 3,
|
||||
SPDYLAY_STREAM_CLOSING, NULL);
|
||||
|
||||
ud.data_chunk_recv_cb_called = 0;
|
||||
ud.data_recv_cb_called = 0;
|
||||
rv = spdylay_session_mem_recv(session, data, 8+4096);
|
||||
CU_ASSERT(8+4096 == rv);
|
||||
|
||||
CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
|
||||
CU_ASSERT(0 == ud.data_recv_cb_called);
|
||||
item = spdylay_session_get_next_ob_item(session);
|
||||
CU_ASSERT(NULL == item);
|
||||
|
||||
/* This is normal case. DATA is acceptable. */
|
||||
stream->state = SPDYLAY_STREAM_OPENED;
|
||||
|
||||
ud.data_chunk_recv_cb_called = 0;
|
||||
ud.data_recv_cb_called = 0;
|
||||
rv = spdylay_session_mem_recv(session, data, 8+4096);
|
||||
CU_ASSERT(8+4096 == rv);
|
||||
|
||||
CU_ASSERT(1 == ud.data_chunk_recv_cb_called);
|
||||
CU_ASSERT(1 == ud.data_recv_cb_called);
|
||||
|
||||
spdylay_session_del(session);
|
||||
}
|
||||
|
|
|
@ -71,5 +71,6 @@ void test_spdylay_session_set_option(void);
|
|||
void test_spdylay_submit_window_update(void);
|
||||
void test_spdylay_session_data_read_temporal_failure(void);
|
||||
void test_spdylay_session_recv_eof(void);
|
||||
void test_spdylay_session_recv_data(void);
|
||||
|
||||
#endif /* SPDYLAY_SESSION_TEST_H */
|
||||
|
|
Loading…
Reference in New Issue