Check protocol version. Check incoming DATA frame's stream ID.

This commit is contained in:
Tatsuhiro Tsujikawa 2012-01-28 22:46:12 +09:00
parent 5fdadc4806
commit e7489503b8
1 changed files with 71 additions and 37 deletions

View File

@ -685,27 +685,30 @@ static int spdylay_session_is_new_peer_stream_id(spdylay_session *session,
/* /*
* Validates SYN_STREAM frame |frame|. This function returns 0 if it * Validates SYN_STREAM frame |frame|. This function returns 0 if it
* succeeds, or -1. * succeeds, or non-zero spdylay_status_code.
*/ */
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 */ /* 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 0; return SPDYLAY_PROTOCOL_ERROR;
} else {
return -1;
} }
if(frame->hd.version != SPDYLAY_PROTO_VERSION) {
return SPDYLAY_UNSUPPORTED_VERSION;
}
return 0;
} }
static int spdylay_session_handle_invalid_ctrl_frame(spdylay_session *session, static int spdylay_session_handle_invalid_stream
(spdylay_session *session,
int32_t stream_id, int32_t stream_id,
spdylay_frame_type type, spdylay_frame_type type,
spdylay_frame *frame) spdylay_frame *frame,
spdylay_status_code status_code)
{ {
int r; int r;
r = spdylay_session_add_rst_stream(session, stream_id, r = spdylay_session_add_rst_stream(session, stream_id, status_code);
SPDYLAY_PROTOCOL_ERROR);
if(r != 0) { if(r != 0) {
return r; return r;
} }
@ -724,7 +727,8 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session,
/* We don't accept SYN_STREAM after GOAWAY is sent or received. */ /* We don't accept SYN_STREAM after GOAWAY is sent or received. */
return 0; return 0;
} }
if(spdylay_session_validate_syn_stream(session, &frame->syn_stream) == 0) { r = spdylay_session_validate_syn_stream(session, &frame->syn_stream);
if(r == 0) {
uint8_t flags = frame->syn_stream.hd.flags; uint8_t flags = frame->syn_stream.hd.flags;
if((flags & SPDYLAY_FLAG_FIN) && (flags & SPDYLAY_FLAG_UNIDIRECTIONAL)) { if((flags & SPDYLAY_FLAG_FIN) && (flags & SPDYLAY_FLAG_UNIDIRECTIONAL)) {
/* If the stream is UNIDIRECTIONAL and FIN bit set, we can close /* If the stream is UNIDIRECTIONAL and FIN bit set, we can close
@ -743,8 +747,8 @@ int spdylay_session_on_syn_stream_received(spdylay_session *session,
frame); frame);
} }
} else { } else {
r = spdylay_session_handle_invalid_ctrl_frame r = spdylay_session_handle_invalid_stream
(session, frame->syn_stream.stream_id, SPDYLAY_SYN_STREAM, frame); (session, frame->syn_stream.stream_id, SPDYLAY_SYN_STREAM, frame, r);
} }
return r; return r;
} }
@ -778,8 +782,9 @@ int spdylay_session_on_syn_reply_received(spdylay_session *session,
} }
} }
if(!valid) { if(!valid) {
r = spdylay_session_handle_invalid_ctrl_frame r = spdylay_session_handle_invalid_stream
(session, frame->syn_reply.stream_id, SPDYLAY_SYN_REPLY, frame); (session, frame->syn_reply.stream_id, SPDYLAY_SYN_REPLY, frame,
SPDYLAY_PROTOCOL_ERROR);
} }
return r; return r;
} }
@ -886,13 +891,14 @@ int spdylay_session_on_headers_received(spdylay_session *session,
} }
} }
if(!valid) { if(!valid) {
r = spdylay_session_handle_invalid_ctrl_frame r = spdylay_session_handle_invalid_stream
(session, frame->headers.stream_id, SPDYLAY_HEADERS, frame); (session, frame->headers.stream_id, SPDYLAY_HEADERS, frame,
SPDYLAY_PROTOCOL_ERROR);
} }
return r; return r;
} }
int spdylay_session_process_ctrl_frame(spdylay_session *session) static int spdylay_session_process_ctrl_frame(spdylay_session *session)
{ {
int r = 0; int r = 0;
uint16_t type; uint16_t type;
@ -983,21 +989,49 @@ int spdylay_session_process_ctrl_frame(spdylay_session *session)
} }
} }
int spdylay_session_process_data_frame(spdylay_session *session) static int spdylay_session_process_data_frame(spdylay_session *session)
{ {
if(session->callbacks.on_data_recv_callback) {
int32_t stream_id; int32_t stream_id;
uint8_t flags; uint8_t flags;
int32_t length; int32_t length;
spdylay_stream *stream;
int status_code = 0;
int valid = 0;
int r = 0;
stream_id = spdylay_get_uint32(session->iframe.headbuf) & stream_id = spdylay_get_uint32(session->iframe.headbuf) &
SPDYLAY_STREAM_ID_MASK; SPDYLAY_STREAM_ID_MASK;
flags = session->iframe.headbuf[4]; flags = session->iframe.headbuf[4];
length = spdylay_get_uint32(&session->iframe.headbuf[4]) & length = spdylay_get_uint32(&session->iframe.headbuf[4]) &
SPDYLAY_LENGTH_MASK; SPDYLAY_LENGTH_MASK;
stream = spdylay_session_get_stream(session, stream_id);
if(stream) {
if(spdylay_session_is_my_stream_id(session, stream_id)) {
if(stream->state == SPDYLAY_STREAM_OPENED) {
valid = 1;
} else if(stream->state != SPDYLAY_STREAM_CLOSING) {
status_code = SPDYLAY_PROTOCOL_ERROR;
}
} else if(stream->flags & SPDYLAY_FLAG_FIN) {
status_code = SPDYLAY_PROTOCOL_ERROR;
} else {
valid = 1;
}
} else {
status_code = SPDYLAY_INVALID_STREAM;
}
if(valid) {
if(session->callbacks.on_data_recv_callback) {
session->callbacks.on_data_recv_callback session->callbacks.on_data_recv_callback
(session, flags, stream_id, length, session->user_data); (session, flags, stream_id, length, session->user_data);
} }
} else if(status_code != 0) {
r = spdylay_session_add_rst_stream(session, stream_id, status_code);
}
if(r < SPDYLAY_ERR_FATAL) {
return r;
} else {
return 0; return 0;
}
} }
int spdylay_session_recv(spdylay_session *session) int spdylay_session_recv(spdylay_session *session)
@ -1077,13 +1111,13 @@ int spdylay_session_recv(spdylay_session *session)
if(session->iframe.len == session->iframe.off) { if(session->iframe.len == session->iframe.off) {
if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) { if(spdylay_frame_is_ctrl_frame(session->iframe.headbuf[0])) {
r = spdylay_session_process_ctrl_frame(session); r = spdylay_session_process_ctrl_frame(session);
} else {
r = spdylay_session_process_data_frame(session);
}
if(r < 0) { if(r < 0) {
/* Fatal error */ /* Fatal error */
return r; return r;
} }
} else {
spdylay_session_process_data_frame(session);
}
spdylay_inbound_frame_reset(&session->iframe); spdylay_inbound_frame_reset(&session->iframe);
} }
} }