spdylay_data_source_read_callback can return
SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE to signal stream error.
This commit is contained in:
parent
42c0e3c758
commit
5c187b950f
|
@ -402,7 +402,7 @@ ssize_t file_read_callback
|
|||
ssize_t r;
|
||||
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||
return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
} else {
|
||||
if(r == 0) {
|
||||
*eof = 1;
|
||||
|
|
|
@ -164,6 +164,10 @@ typedef enum {
|
|||
* The gzip error.
|
||||
*/
|
||||
SPDYLAY_ERR_GZIP = -520,
|
||||
/**
|
||||
* The user callback function failed due to the temporal error.
|
||||
*/
|
||||
SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE = -521,
|
||||
/**
|
||||
* The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is
|
||||
* under unexpected condition and cannot process any further data
|
||||
|
@ -737,8 +741,11 @@ typedef union {
|
|||
* reading any data in this invocation. The library removes DATA
|
||||
* frame from the outgoing queue temporarily. To move back deferred
|
||||
* DATA frame to outgoing queue, call `spdylay_session_resume_data()`.
|
||||
* In case of error, return :enum:`SPDYLAY_ERR_CALLBACK_FAILURE`,
|
||||
* which leads to session failure.
|
||||
* In case of error, there are 2 choices. Returning
|
||||
* :enum:`SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
|
||||
* by issuing RST_STREAM with :enum:`SPDYLAY_INTERNAL_ERROR`.
|
||||
* Returning :enum:`SPDYLAY_ERR_CALLBACK_FAILURE` will signal the
|
||||
* entire session failure.
|
||||
*/
|
||||
typedef ssize_t (*spdylay_data_source_read_callback)
|
||||
(spdylay_session *session, int32_t stream_id,
|
||||
|
|
|
@ -115,6 +115,8 @@ const char* spdylay_strerror(int error_code)
|
|||
return "Invalid state";
|
||||
case SPDYLAY_ERR_GZIP:
|
||||
return "Gzip error";
|
||||
case SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE:
|
||||
return "The user callback function failed due to the temporal error";
|
||||
case SPDYLAY_ERR_NOMEM:
|
||||
return "Out of memory";
|
||||
case SPDYLAY_ERR_CALLBACK_FAILURE:
|
||||
|
|
|
@ -1123,6 +1123,14 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
|||
if(framebuflen == SPDYLAY_ERR_DEFERRED) {
|
||||
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_NONE);
|
||||
return SPDYLAY_ERR_DEFERRED;
|
||||
} else if(framebuflen == SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
r = spdylay_session_add_rst_stream(session, data_frame->stream_id,
|
||||
SPDYLAY_INTERNAL_ERROR);
|
||||
if(r == 0) {
|
||||
return framebuflen;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
} else if(framebuflen < 0) {
|
||||
return framebuflen;
|
||||
}
|
||||
|
@ -1395,6 +1403,16 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
|
|||
SPDYLAY_DEFERRED_NONE);
|
||||
session->aob.item = NULL;
|
||||
spdylay_active_outbound_item_reset(&session->aob);
|
||||
} else if(r == SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
/* Stop DATA frame chain and issue RST_STREAM to close the
|
||||
stream. We don't return
|
||||
SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE intentionally. */
|
||||
r = spdylay_session_add_rst_stream(session, data_frame->stream_id,
|
||||
SPDYLAY_INTERNAL_ERROR);
|
||||
spdylay_active_outbound_item_reset(&session->aob);
|
||||
if(r != 0) {
|
||||
return r;
|
||||
}
|
||||
} else if(r < 0) {
|
||||
/* In this context, r is either SPDYLAY_ERR_NOMEM or
|
||||
SPDYLAY_ERR_CALLBACK_FAILURE */
|
||||
|
@ -2606,7 +2624,7 @@ ssize_t spdylay_session_pack_data(spdylay_session *session,
|
|||
r = frame->data_prd.read_callback
|
||||
(session, frame->stream_id, (*buf_ptr)+8, datamax,
|
||||
&eof, &frame->data_prd.source, session->user_data);
|
||||
if(r == SPDYLAY_ERR_DEFERRED) {
|
||||
if(r == SPDYLAY_ERR_DEFERRED || r == SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
return r;
|
||||
} else if(r < 0 || datamax < (size_t)r) {
|
||||
/* This is the error code when callback is failed. */
|
||||
|
|
|
@ -484,12 +484,14 @@ spdylay_stream* spdylay_session_get_stream(spdylay_session *session,
|
|||
* This function returns the size of packed frame if it succeeds, or
|
||||
* one of the following negative error codes:
|
||||
*
|
||||
* SPDYLAY_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* SPDYLAY_ERR_DEFERRED
|
||||
* The DATA frame is postponed.
|
||||
* SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||
* The read_callback failed (stream error).
|
||||
* SPDYLAY_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* SPDYLAY_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed.
|
||||
* The read_callback failed (session error).
|
||||
*/
|
||||
ssize_t spdylay_session_pack_data(spdylay_session *session,
|
||||
uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||
|
|
|
@ -156,6 +156,8 @@ int main(int argc, char* argv[])
|
|||
test_spdylay_session_set_option) ||
|
||||
!CU_add_test(pSuite, "submit_window_update",
|
||||
test_spdylay_submit_window_update) ||
|
||||
!CU_add_test(pSuite, "session_data_read_temporal_failure",
|
||||
test_spdylay_session_data_read_temporal_failure) ||
|
||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy2",
|
||||
test_spdylay_frame_unpack_nv_spdy2) ||
|
||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",
|
||||
|
|
|
@ -176,6 +176,22 @@ static ssize_t fixed_length_data_source_read_callback
|
|||
return wlen;
|
||||
}
|
||||
|
||||
static ssize_t temporal_failure_data_source_read_callback
|
||||
(spdylay_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t len, int *eof,
|
||||
spdylay_data_source *source, void *user_data)
|
||||
{
|
||||
return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
static ssize_t fail_data_source_read_callback
|
||||
(spdylay_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t len, int *eof,
|
||||
spdylay_data_source *source, void *user_data)
|
||||
{
|
||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
static void on_request_recv_callback(spdylay_session *session,
|
||||
int32_t stream_id,
|
||||
void *user_data)
|
||||
|
@ -2328,3 +2344,58 @@ void test_spdylay_submit_window_update(void)
|
|||
|
||||
spdylay_session_del(session);
|
||||
}
|
||||
|
||||
void test_spdylay_session_data_read_temporal_failure(void)
|
||||
{
|
||||
spdylay_session *session;
|
||||
spdylay_session_callbacks callbacks;
|
||||
const char *nv[] = { NULL };
|
||||
my_user_data ud;
|
||||
spdylay_data_provider data_prd;
|
||||
spdylay_frame frame;
|
||||
spdylay_data *data_frame;
|
||||
spdylay_stream *stream;
|
||||
|
||||
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
|
||||
callbacks.send_callback = null_send_callback;
|
||||
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
|
||||
data_prd.read_callback = fixed_length_data_source_read_callback;
|
||||
|
||||
ud.data_source_length = 128*1024;
|
||||
|
||||
/* Initial window size is 64KiB */
|
||||
spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY3, &callbacks, &ud);
|
||||
spdylay_submit_request(session, 3, nv, &data_prd, NULL);
|
||||
|
||||
/* Sends 64KiB data */
|
||||
CU_ASSERT(0 == spdylay_session_send(session));
|
||||
CU_ASSERT(64*1024 == ud.data_source_length);
|
||||
|
||||
stream = spdylay_session_get_stream(session, 1);
|
||||
CU_ASSERT(NULL != stream->deferred_data);
|
||||
CU_ASSERT(SPDYLAY_DATA == stream->deferred_data->frame_cat);
|
||||
data_frame = (spdylay_data*)stream->deferred_data->frame;
|
||||
data_frame->data_prd.read_callback =
|
||||
temporal_failure_data_source_read_callback;
|
||||
|
||||
/* Back 64KiB */
|
||||
spdylay_frame_window_update_init(&frame.window_update, SPDYLAY_PROTO_SPDY3,
|
||||
1, 64*1024);
|
||||
spdylay_session_on_window_update_received(session, &frame);
|
||||
spdylay_frame_window_update_free(&frame.window_update);
|
||||
|
||||
/* Sending data will fail */
|
||||
ud.ctrl_send_cb_called = 0;
|
||||
CU_ASSERT(0 == spdylay_session_send(session));
|
||||
CU_ASSERT(64*1024 == ud.data_source_length);
|
||||
|
||||
CU_ASSERT(1 == ud.ctrl_send_cb_called);
|
||||
CU_ASSERT(SPDYLAY_RST_STREAM == ud.sent_frame_type);
|
||||
|
||||
data_prd.read_callback = fail_data_source_read_callback;
|
||||
spdylay_submit_request(session, 3, nv, &data_prd, NULL);
|
||||
/* Sending data will fail */
|
||||
CU_ASSERT(SPDYLAY_ERR_CALLBACK_FAILURE == spdylay_session_send(session));
|
||||
|
||||
spdylay_session_del(session);
|
||||
}
|
||||
|
|
|
@ -69,5 +69,6 @@ void test_spdylay_submit_syn_stream_with_credential(void);
|
|||
void test_spdylay_session_set_initial_client_cert_origin(void);
|
||||
void test_spdylay_session_set_option(void);
|
||||
void test_spdylay_submit_window_update(void);
|
||||
void test_spdylay_session_data_read_temporal_failure(void);
|
||||
|
||||
#endif /* SPDYLAY_SESSION_TEST_H */
|
||||
|
|
Loading…
Reference in New Issue