Allow NGHTTP2_ERR_PAUSE from nghttp2_data_source_read_callback
This commit is contained in:
parent
1064e017c6
commit
581e0938a9
|
@ -860,8 +860,13 @@ typedef enum {
|
||||||
* achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
|
* achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
|
||||||
* any data in this invocation. The library removes DATA frame from
|
* any data in this invocation. The library removes DATA frame from
|
||||||
* the outgoing queue temporarily. To move back deferred DATA frame
|
* the outgoing queue temporarily. To move back deferred DATA frame
|
||||||
* to outgoing queue, call `nghttp2_session_resume_data()`. In case
|
* to outgoing queue, call `nghttp2_session_resume_data()`.
|
||||||
* of error, there are 2 choices. Returning
|
*
|
||||||
|
* If the application just wants to return from
|
||||||
|
* `nghttp2_session_send()` or `nghttp2_session_mem_send()` without
|
||||||
|
* sending anything, return :enum:`NGHTTP2_ERR_PAUSE`.
|
||||||
|
*
|
||||||
|
* In case of error, there are 2 choices. Returning
|
||||||
* :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
|
* :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
|
||||||
* by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. If a
|
* by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`. If a
|
||||||
* different error code is desirable, use
|
* different error code is desirable, use
|
||||||
|
|
|
@ -2263,6 +2263,9 @@ static int session_prep_frame(nghttp2_session *session,
|
||||||
rv = nghttp2_session_pack_data(session, &session->aob.framebufs,
|
rv = nghttp2_session_pack_data(session, &session->aob.framebufs,
|
||||||
next_readmax, frame, &item->aux_data.data,
|
next_readmax, frame, &item->aux_data.data,
|
||||||
stream);
|
stream);
|
||||||
|
if (rv == NGHTTP2_ERR_PAUSE) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
if (rv == NGHTTP2_ERR_DEFERRED) {
|
if (rv == NGHTTP2_ERR_DEFERRED) {
|
||||||
rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
rv = nghttp2_stream_defer_item(stream, NGHTTP2_STREAM_FLAG_DEFERRED_USER);
|
||||||
|
|
||||||
|
@ -2918,6 +2921,9 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = session_prep_frame(session, item);
|
rv = session_prep_frame(session, item);
|
||||||
|
if (rv == NGHTTP2_ERR_PAUSE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (rv == NGHTTP2_ERR_DEFERRED) {
|
if (rv == NGHTTP2_ERR_DEFERRED) {
|
||||||
DEBUGF(fprintf(stderr, "send: frame transmission deferred\n"));
|
DEBUGF(fprintf(stderr, "send: frame transmission deferred\n"));
|
||||||
break;
|
break;
|
||||||
|
@ -7020,7 +7026,8 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||||
&aux_data->data_prd.source, session->user_data);
|
&aux_data->data_prd.source, session->user_data);
|
||||||
|
|
||||||
if (payloadlen == NGHTTP2_ERR_DEFERRED ||
|
if (payloadlen == NGHTTP2_ERR_DEFERRED ||
|
||||||
payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE ||
|
||||||
|
payloadlen == NGHTTP2_ERR_PAUSE) {
|
||||||
DEBUGF(fprintf(stderr, "send: DATA postponed due to %s\n",
|
DEBUGF(fprintf(stderr, "send: DATA postponed due to %s\n",
|
||||||
nghttp2_strerror((int)payloadlen)));
|
nghttp2_strerror((int)payloadlen)));
|
||||||
|
|
||||||
|
|
|
@ -310,6 +310,8 @@ int main(int argc _U_, char *argv[] _U_) {
|
||||||
test_nghttp2_session_cancel_from_before_frame_send) ||
|
test_nghttp2_session_cancel_from_before_frame_send) ||
|
||||||
!CU_add_test(pSuite, "session_removed_closed_stream",
|
!CU_add_test(pSuite, "session_removed_closed_stream",
|
||||||
test_nghttp2_session_removed_closed_stream) ||
|
test_nghttp2_session_removed_closed_stream) ||
|
||||||
|
!CU_add_test(pSuite, "session_pause_data",
|
||||||
|
test_nghttp2_session_pause_data) ||
|
||||||
!CU_add_test(pSuite, "http_mandatory_headers",
|
!CU_add_test(pSuite, "http_mandatory_headers",
|
||||||
test_nghttp2_http_mandatory_headers) ||
|
test_nghttp2_http_mandatory_headers) ||
|
||||||
!CU_add_test(pSuite, "http_content_length",
|
!CU_add_test(pSuite, "http_content_length",
|
||||||
|
|
|
@ -77,6 +77,7 @@ typedef struct {
|
||||||
size_t padlen;
|
size_t padlen;
|
||||||
int begin_frame_cb_called;
|
int begin_frame_cb_called;
|
||||||
nghttp2_buf scratchbuf;
|
nghttp2_buf scratchbuf;
|
||||||
|
size_t data_source_read_cb_paused;
|
||||||
} my_user_data;
|
} my_user_data;
|
||||||
|
|
||||||
static const nghttp2_nv reqnv[] = {
|
static const nghttp2_nv reqnv[] = {
|
||||||
|
@ -9934,6 +9935,53 @@ void test_nghttp2_session_removed_closed_stream(void) {
|
||||||
nghttp2_bufs_free(&bufs);
|
nghttp2_bufs_free(&bufs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t pause_once_data_source_read_callback(
|
||||||
|
nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t len,
|
||||||
|
uint32_t *data_flags, nghttp2_data_source *source, void *user_data) {
|
||||||
|
my_user_data *ud = user_data;
|
||||||
|
if (ud->data_source_read_cb_paused == 0) {
|
||||||
|
++ud->data_source_read_cb_paused;
|
||||||
|
return NGHTTP2_ERR_PAUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixed_length_data_source_read_callback(session, stream_id, buf, len,
|
||||||
|
data_flags, source, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_session_pause_data(void) {
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
nghttp2_data_provider data_prd;
|
||||||
|
my_user_data ud;
|
||||||
|
|
||||||
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
|
callbacks.send_callback = null_send_callback;
|
||||||
|
callbacks.on_frame_send_callback = on_frame_send_callback;
|
||||||
|
|
||||||
|
data_prd.read_callback = pause_once_data_source_read_callback;
|
||||||
|
ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN;
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, &ud);
|
||||||
|
|
||||||
|
open_recv_stream(session, 1);
|
||||||
|
|
||||||
|
CU_ASSERT(
|
||||||
|
0 == nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 1, &data_prd));
|
||||||
|
|
||||||
|
ud.frame_send_cb_called = 0;
|
||||||
|
ud.data_source_read_cb_paused = 0;
|
||||||
|
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(0 == ud.frame_send_cb_called);
|
||||||
|
CU_ASSERT(NULL == session->aob.item);
|
||||||
|
CU_ASSERT(0 == nghttp2_session_send(session));
|
||||||
|
CU_ASSERT(1 == ud.frame_send_cb_called);
|
||||||
|
CU_ASSERT(NGHTTP2_DATA == ud.sent_frame_type);
|
||||||
|
CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_nghttp2_http_recv_headers_fail(
|
static void check_nghttp2_http_recv_headers_fail(
|
||||||
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
nghttp2_session *session, nghttp2_hd_deflater *deflater, int32_t stream_id,
|
||||||
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
int stream_state, const nghttp2_nv *nva, size_t nvlen) {
|
||||||
|
|
|
@ -153,6 +153,7 @@ void test_nghttp2_session_repeated_priority_submission(void);
|
||||||
void test_nghttp2_session_set_local_window_size(void);
|
void test_nghttp2_session_set_local_window_size(void);
|
||||||
void test_nghttp2_session_cancel_from_before_frame_send(void);
|
void test_nghttp2_session_cancel_from_before_frame_send(void);
|
||||||
void test_nghttp2_session_removed_closed_stream(void);
|
void test_nghttp2_session_removed_closed_stream(void);
|
||||||
|
void test_nghttp2_session_pause_data(void);
|
||||||
void test_nghttp2_http_mandatory_headers(void);
|
void test_nghttp2_http_mandatory_headers(void);
|
||||||
void test_nghttp2_http_content_length(void);
|
void test_nghttp2_http_content_length(void);
|
||||||
void test_nghttp2_http_content_length_mismatch(void);
|
void test_nghttp2_http_content_length_mismatch(void);
|
||||||
|
|
Loading…
Reference in New Issue