Added status_code handling to GOAWAY

This commit is contained in:
Tatsuhiro Tsujikawa 2012-02-26 16:26:38 +09:00
parent 88cd97843f
commit d5cc71c636
11 changed files with 83 additions and 34 deletions

View File

@ -121,7 +121,7 @@ void on_stream_close_callback
if(itr != stream2req.end()) {
++complete;
if(complete == numreq) {
spdylay_submit_goaway(session);
spdylay_submit_goaway(session, SPDYLAY_GOAWAY_OK);
}
}
}

View File

@ -116,7 +116,10 @@ typedef enum {
/* Default maximum concurrent streams */
#define SPDYLAY_CONCURRENT_STREAMS_MAX 100
/* Status code for RST_STREAM */
typedef enum {
/* SPDYLAY_OK is not valid status code for RST_STREAM. It is defined
just for spdylay library use. */
SPDYLAY_OK = 0,
SPDYLAY_PROTOCOL_ERROR = 1,
SPDYLAY_INVALID_STREAM = 2,
@ -124,9 +127,21 @@ typedef enum {
SPDYLAY_UNSUPPORTED_VERSION = 4,
SPDYLAY_CANCEL = 5,
SPDYLAY_INTERNAL_ERROR = 6,
SPDYLAY_FLOW_CONTROL_ERROR = 7
SPDYLAY_FLOW_CONTROL_ERROR = 7,
/* Following status codes were introduced in SPDY/3 */
SPDYLAY_STREAM_IN_USE = 8,
SPDYLAY_STREAM_ALREADY_CLOSED = 9,
SPDYLAY_INVALID_CREDENTIALS = 10,
FRAME_TOO_LARGE = 11
} spdylay_status_code;
/* Status code for GOAWAY, introduced in SPDY/3 */
typedef enum {
SPDYLAY_GOAWAY_OK = 0,
SPDYLAY_GOAWAY_PROTOCOL_ERROR = 1,
SPDYLAY_GOAWAY_INTERNAL_ERROR = 11
} spdylay_goaway_status_code;
#define SPDYLAY_SPDY2_PRI_LOWEST 3
#define SPDYLAY_SPDY3_PRI_LOWEST 7
@ -643,7 +658,8 @@ int spdylay_submit_rst_stream(spdylay_session *session, int32_t stream_id,
int spdylay_submit_ping(spdylay_session *session);
/*
* Submits GOAWAY frame.
* Submits GOAWAY frame. The status code |status_code| is ignored if
* the protocol version is SPDYLAY_PROTO_SPDY2.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@ -651,7 +667,7 @@ int spdylay_submit_ping(spdylay_session *session);
* SPDYLAY_ERR_NOMEM
* Out of memory.
*/
int spdylay_submit_goaway(spdylay_session *session);
int spdylay_submit_goaway(spdylay_session *session, uint32_t status_code);
/*
* A helper function for dealing with NPN in client side.

View File

@ -449,7 +449,8 @@ void spdylay_frame_ping_free(spdylay_ping *frame)
{}
void spdylay_frame_goaway_init(spdylay_goaway *frame,
uint16_t version, int32_t last_good_stream_id)
uint16_t version, int32_t last_good_stream_id,
uint32_t status_code)
{
memset(frame, 0, sizeof(spdylay_goaway));
frame->hd.version = version;
@ -458,11 +459,11 @@ void spdylay_frame_goaway_init(spdylay_goaway *frame,
frame->hd.length = 4;
} else if(version == SPDYLAY_PROTO_SPDY3) {
frame->hd.length = 8;
frame->status_code = status_code;
} else {
frame->hd.length = 0;
}
frame->last_good_stream_id = last_good_stream_id;
frame->status_code = 0; /* TODO Add status_code arg for spdy/3 */
}
void spdylay_frame_goaway_free(spdylay_goaway *frame)

View File

@ -463,8 +463,13 @@ void spdylay_frame_ping_init(spdylay_ping *frame, uint16_t version,
void spdylay_frame_ping_free(spdylay_ping *frame);
/*
* Initializes GOAWAY frame |frame| with given values. The
* |status_code| is ignored if |version| == SPDYLAY_PROTO_SPDY2.
*/
void spdylay_frame_goaway_init(spdylay_goaway *frame, uint16_t version,
int32_t last_good_stream_id);
int32_t last_good_stream_id,
uint32_t status_code);
void spdylay_frame_goaway_free(spdylay_goaway *frame);

View File

@ -1489,13 +1489,14 @@ int spdylay_session_on_headers_received(spdylay_session *session,
/*
* This function should be called when the session wants to drop
* connection after sending GOAWAY. For example, when it receives bad
* zlib data.
* connection after sending GOAWAY. These cases are called as the
* session error. For example, when it receives bad zlib data.
*/
static int spdylay_session_fail_session(spdylay_session *session)
static int spdylay_session_fail_session(spdylay_session *session,
uint32_t status_code)
{
session->goaway_flags |= SPDYLAY_GOAWAY_FAIL_ON_SEND;
return spdylay_submit_goaway(session);
return spdylay_submit_goaway(session, status_code);
}
/*
@ -1533,7 +1534,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
invalid frame, send RST_STREAM with PROTOCOL_ERROR. Same for
other control frames. */
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_SYN_REPLY:
@ -1551,7 +1552,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_syn_reply_received(session, &frame);
spdylay_frame_syn_reply_free(&frame.syn_reply);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_RST_STREAM:
@ -1564,7 +1565,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_rst_stream_received(session, &frame);
spdylay_frame_rst_stream_free(&frame.rst_stream);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_SETTINGS:
@ -1577,7 +1578,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_settings_received(session, &frame);
spdylay_frame_settings_free(&frame.settings);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_NOOP:
@ -1592,7 +1593,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_ping_received(session, &frame);
spdylay_frame_ping_free(&frame.ping);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_GOAWAY:
@ -1605,7 +1606,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_goaway_received(session, &frame);
spdylay_frame_goaway_free(&frame.goaway);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_HEADERS:
@ -1623,7 +1624,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_headers_received(session, &frame);
spdylay_frame_headers_free(&frame.headers);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
case SPDYLAY_WINDOW_UPDATE:
@ -1636,7 +1637,7 @@ static int spdylay_session_process_ctrl_frame(spdylay_session *session)
r = spdylay_session_on_window_update_received(session, &frame);
spdylay_frame_window_update_free(&frame.window_update);
} else if(spdylay_is_non_fatal(r)) {
r = spdylay_session_fail_session(session);
r = spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
}
break;
}
@ -1923,7 +1924,8 @@ int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id)
}
int spdylay_session_add_goaway(spdylay_session *session,
int32_t last_good_stream_id)
int32_t last_good_stream_id,
uint32_t status_code)
{
int r;
spdylay_frame *frame;
@ -1932,7 +1934,7 @@ int spdylay_session_add_goaway(spdylay_session *session,
return SPDYLAY_ERR_NOMEM;
}
spdylay_frame_goaway_init(&frame->goaway, session->version,
last_good_stream_id);
last_good_stream_id, status_code);
r = spdylay_session_add_frame(session, SPDYLAY_GOAWAY, frame, NULL);
if(r != 0) {
spdylay_frame_goaway_free(&frame->goaway);

View File

@ -218,9 +218,11 @@ int spdylay_session_add_rst_stream(spdylay_session *session,
int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id);
/*
* Adds GOAWAY frame with last-good-stream-ID
* |last_good_stream_id|. This is a convenient function built on top
* of spdylay_session_add_frame() to add GOAWAY easily.
* Adds GOAWAY frame with last-good-stream-ID |last_good_stream_id|
* and the status code |status_code|. The |status_code| is ignored if
* the protocol version is SPDYLAY_PROTO_SPDY2. This is a convenient
* function built on top of spdylay_session_add_frame() to add GOAWAY
* easily.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
@ -229,7 +231,8 @@ int spdylay_session_add_ping(spdylay_session *session, uint32_t unique_id);
* Out of memory.
*/
int spdylay_session_add_goaway(spdylay_session *session,
int32_t last_good_stream_id);
int32_t last_good_stream_id,
uint32_t status_code);
/*
* Adds WINDOW_UPDATE frame with stream ID |stream_id| and

View File

@ -151,9 +151,10 @@ int spdylay_submit_rst_stream(spdylay_session *session, int32_t stream_id,
return spdylay_session_add_rst_stream(session, stream_id, status_code);
}
int spdylay_submit_goaway(spdylay_session *session)
int spdylay_submit_goaway(spdylay_session *session, uint32_t status_code)
{
return spdylay_session_add_goaway(session, session->last_recv_stream_id);
return spdylay_session_add_goaway(session, session->last_recv_stream_id,
status_code);
}
int spdylay_submit_request(spdylay_session *session, uint8_t pri,

View File

@ -141,8 +141,10 @@ int main(int argc, char* argv[])
!CU_add_test(pSuite, "frame_count_unpack_nv_space",
test_spdylay_frame_count_unpack_nv_space) ||
!CU_add_test(pSuite, "frame_pack_ping", test_spdylay_frame_pack_ping) ||
!CU_add_test(pSuite, "frame_pack_goaway",
test_spdylay_frame_pack_goaway) ||
!CU_add_test(pSuite, "frame_pack_goaway_spdy2",
test_spdylay_frame_pack_goaway_spdy2) ||
!CU_add_test(pSuite, "frame_pack_goaway_spdy3",
test_spdylay_frame_pack_goaway_spdy3) ||
!CU_add_test(pSuite, "frame_pack_syn_stream",
test_spdylay_frame_pack_syn_stream) ||
!CU_add_test(pSuite, "frame_pack_syn_reply",

View File

@ -216,13 +216,14 @@ void test_spdylay_frame_pack_ping()
spdylay_frame_ping_free(&frame.ping);
}
void test_spdylay_frame_pack_goaway()
void test_spdylay_frame_pack_goaway_version(uint16_t version)
{
spdylay_frame frame, oframe;
uint8_t *buf = NULL;
size_t buflen = 0;
ssize_t framelen;
spdylay_frame_goaway_init(&frame.goaway, SPDYLAY_PROTO_SPDY2, 1000000007);
spdylay_frame_goaway_init(&frame.goaway, version, 1000000007,
SPDYLAY_GOAWAY_PROTOCOL_ERROR);
framelen = spdylay_frame_pack_goaway(&buf, &buflen, &frame.goaway);
CU_ASSERT(0 == spdylay_frame_unpack_goaway
(&oframe.goaway,
@ -230,7 +231,13 @@ void test_spdylay_frame_pack_goaway()
&buf[SPDYLAY_FRAME_HEAD_LENGTH],
framelen-SPDYLAY_FRAME_HEAD_LENGTH));
CU_ASSERT(1000000007 == oframe.goaway.last_good_stream_id);
CU_ASSERT(SPDYLAY_PROTO_SPDY2 == oframe.headers.hd.version);
if(version == SPDYLAY_PROTO_SPDY2) {
/* The status code is ignored in SPDY/2 */
CU_ASSERT(0 == oframe.goaway.status_code);
} else if(version == SPDYLAY_PROTO_SPDY3) {
CU_ASSERT(SPDYLAY_GOAWAY_PROTOCOL_ERROR == oframe.goaway.status_code);
}
CU_ASSERT(version == oframe.headers.hd.version);
CU_ASSERT(SPDYLAY_GOAWAY == oframe.headers.hd.type);
CU_ASSERT(SPDYLAY_CTRL_FLAG_NONE == oframe.headers.hd.flags);
CU_ASSERT(framelen-SPDYLAY_FRAME_HEAD_LENGTH == oframe.ping.hd.length);
@ -239,6 +246,16 @@ void test_spdylay_frame_pack_goaway()
spdylay_frame_goaway_free(&frame.goaway);
}
void test_spdylay_frame_pack_goaway_spdy2()
{
test_spdylay_frame_pack_goaway_version(SPDYLAY_PROTO_SPDY2);
}
void test_spdylay_frame_pack_goaway_spdy3()
{
test_spdylay_frame_pack_goaway_version(SPDYLAY_PROTO_SPDY3);
}
void test_spdylay_frame_pack_syn_stream_with(uint16_t version)
{
spdylay_zlib deflater, inflater;

View File

@ -30,7 +30,8 @@ void test_spdylay_frame_pack_nv_duplicate_keys();
void test_spdylay_frame_count_nv_space();
void test_spdylay_frame_count_unpack_nv_space();
void test_spdylay_frame_pack_ping();
void test_spdylay_frame_pack_goaway();
void test_spdylay_frame_pack_goaway_spdy2();
void test_spdylay_frame_pack_goaway_spdy3();
void test_spdylay_frame_pack_syn_stream();
void test_spdylay_frame_pack_syn_reply();
void test_spdylay_frame_pack_headers();

View File

@ -913,7 +913,8 @@ void test_spdylay_session_on_goaway_received()
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2, &callbacks,
&user_data);
spdylay_frame_goaway_init(&frame.goaway, SPDYLAY_PROTO_SPDY2, stream_id);
spdylay_frame_goaway_init(&frame.goaway, SPDYLAY_PROTO_SPDY2, stream_id,
SPDYLAY_GOAWAY_OK);
CU_ASSERT(0 == spdylay_session_on_goaway_received(session, &frame));
CU_ASSERT(1 == user_data.ctrl_recv_cb_called);