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;
|
ssize_t r;
|
||||||
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
|
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
|
||||||
if(r == -1) {
|
if(r == -1) {
|
||||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
if(r == 0) {
|
if(r == 0) {
|
||||||
*eof = 1;
|
*eof = 1;
|
||||||
|
|
|
@ -164,6 +164,10 @@ typedef enum {
|
||||||
* The gzip error.
|
* The gzip error.
|
||||||
*/
|
*/
|
||||||
SPDYLAY_ERR_GZIP = -520,
|
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
|
* The errors < :enum:`SPDYLAY_ERR_FATAL` mean that the library is
|
||||||
* under unexpected condition and cannot process any further data
|
* 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
|
* reading any data in this invocation. The library removes DATA
|
||||||
* frame from the outgoing queue temporarily. To move back deferred
|
* frame from the outgoing queue temporarily. To move back deferred
|
||||||
* DATA frame to outgoing queue, call `spdylay_session_resume_data()`.
|
* DATA frame to outgoing queue, call `spdylay_session_resume_data()`.
|
||||||
* In case of error, return :enum:`SPDYLAY_ERR_CALLBACK_FAILURE`,
|
* In case of error, there are 2 choices. Returning
|
||||||
* which leads to session failure.
|
* :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)
|
typedef ssize_t (*spdylay_data_source_read_callback)
|
||||||
(spdylay_session *session, int32_t stream_id,
|
(spdylay_session *session, int32_t stream_id,
|
||||||
|
|
|
@ -115,6 +115,8 @@ const char* spdylay_strerror(int error_code)
|
||||||
return "Invalid state";
|
return "Invalid state";
|
||||||
case SPDYLAY_ERR_GZIP:
|
case SPDYLAY_ERR_GZIP:
|
||||||
return "Gzip error";
|
return "Gzip error";
|
||||||
|
case SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE:
|
||||||
|
return "The user callback function failed due to the temporal error";
|
||||||
case SPDYLAY_ERR_NOMEM:
|
case SPDYLAY_ERR_NOMEM:
|
||||||
return "Out of memory";
|
return "Out of memory";
|
||||||
case SPDYLAY_ERR_CALLBACK_FAILURE:
|
case SPDYLAY_ERR_CALLBACK_FAILURE:
|
||||||
|
|
|
@ -1123,6 +1123,14 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
|
||||||
if(framebuflen == SPDYLAY_ERR_DEFERRED) {
|
if(framebuflen == SPDYLAY_ERR_DEFERRED) {
|
||||||
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_NONE);
|
spdylay_stream_defer_data(stream, item, SPDYLAY_DEFERRED_NONE);
|
||||||
return SPDYLAY_ERR_DEFERRED;
|
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) {
|
} else if(framebuflen < 0) {
|
||||||
return framebuflen;
|
return framebuflen;
|
||||||
}
|
}
|
||||||
|
@ -1395,6 +1403,16 @@ static int spdylay_session_after_frame_sent(spdylay_session *session)
|
||||||
SPDYLAY_DEFERRED_NONE);
|
SPDYLAY_DEFERRED_NONE);
|
||||||
session->aob.item = NULL;
|
session->aob.item = NULL;
|
||||||
spdylay_active_outbound_item_reset(&session->aob);
|
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) {
|
} else if(r < 0) {
|
||||||
/* In this context, r is either SPDYLAY_ERR_NOMEM or
|
/* In this context, r is either SPDYLAY_ERR_NOMEM or
|
||||||
SPDYLAY_ERR_CALLBACK_FAILURE */
|
SPDYLAY_ERR_CALLBACK_FAILURE */
|
||||||
|
@ -2606,7 +2624,7 @@ ssize_t spdylay_session_pack_data(spdylay_session *session,
|
||||||
r = frame->data_prd.read_callback
|
r = frame->data_prd.read_callback
|
||||||
(session, frame->stream_id, (*buf_ptr)+8, datamax,
|
(session, frame->stream_id, (*buf_ptr)+8, datamax,
|
||||||
&eof, &frame->data_prd.source, session->user_data);
|
&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;
|
return r;
|
||||||
} else if(r < 0 || datamax < (size_t)r) {
|
} else if(r < 0 || datamax < (size_t)r) {
|
||||||
/* This is the error code when callback is failed. */
|
/* 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
|
* This function returns the size of packed frame if it succeeds, or
|
||||||
* one of the following negative error codes:
|
* one of the following negative error codes:
|
||||||
*
|
*
|
||||||
* SPDYLAY_ERR_NOMEM
|
|
||||||
* Out of memory.
|
|
||||||
* SPDYLAY_ERR_DEFERRED
|
* SPDYLAY_ERR_DEFERRED
|
||||||
* The DATA frame is postponed.
|
* 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
|
* SPDYLAY_ERR_CALLBACK_FAILURE
|
||||||
* The read_callback failed.
|
* The read_callback failed (session error).
|
||||||
*/
|
*/
|
||||||
ssize_t spdylay_session_pack_data(spdylay_session *session,
|
ssize_t spdylay_session_pack_data(spdylay_session *session,
|
||||||
uint8_t **buf_ptr, size_t *buflen_ptr,
|
uint8_t **buf_ptr, size_t *buflen_ptr,
|
||||||
|
|
|
@ -156,6 +156,8 @@ int main(int argc, char* argv[])
|
||||||
test_spdylay_session_set_option) ||
|
test_spdylay_session_set_option) ||
|
||||||
!CU_add_test(pSuite, "submit_window_update",
|
!CU_add_test(pSuite, "submit_window_update",
|
||||||
test_spdylay_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",
|
!CU_add_test(pSuite, "frame_unpack_nv_spdy2",
|
||||||
test_spdylay_frame_unpack_nv_spdy2) ||
|
test_spdylay_frame_unpack_nv_spdy2) ||
|
||||||
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",
|
!CU_add_test(pSuite, "frame_unpack_nv_spdy3",
|
||||||
|
|
|
@ -176,6 +176,22 @@ static ssize_t fixed_length_data_source_read_callback
|
||||||
return wlen;
|
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,
|
static void on_request_recv_callback(spdylay_session *session,
|
||||||
int32_t stream_id,
|
int32_t stream_id,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
|
@ -2328,3 +2344,58 @@ void test_spdylay_submit_window_update(void)
|
||||||
|
|
||||||
spdylay_session_del(session);
|
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_initial_client_cert_origin(void);
|
||||||
void test_spdylay_session_set_option(void);
|
void test_spdylay_session_set_option(void);
|
||||||
void test_spdylay_submit_window_update(void);
|
void test_spdylay_submit_window_update(void);
|
||||||
|
void test_spdylay_session_data_read_temporal_failure(void);
|
||||||
|
|
||||||
#endif /* SPDYLAY_SESSION_TEST_H */
|
#endif /* SPDYLAY_SESSION_TEST_H */
|
||||||
|
|
Loading…
Reference in New Issue