From 45d4c9dece1f154f470eedd3c9a8647ab03ec410 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 3 Oct 2015 17:00:16 +0900 Subject: [PATCH] Add new error code NGHTTP2_ERR_PAUSE to send_data_callback If application returns NGHTTP2_ERR_PAUSE from send_data_callback, it means application processed all data, but wants to make nghttp2_session_mem_send or nghttp2_session_send return immediately. This is useful if application writes to fixed sized buffers, and there is no room to write more data. --- lib/includes/nghttp2/nghttp2.h | 20 ++++++++++++-------- lib/nghttp2_session.c | 18 +++++++++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 6cedb5df..4b506157 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1199,18 +1199,22 @@ typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session, * The application has to send complete DATA frame in this callback. * If all data were written successfully, return 0. * - * If it cannot send it all, just return + * If it cannot send any data at all, just return * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback * with the same parameters later (It is recommended to send complete * DATA frame at once in this function to deal with error; if partial * frame data has already sent, it is impossible to send another data - * in that state, and all we can do is tear down connection). If - * application decided to reset this stream, return - * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then the library - * will send RST_STREAM with INTERNAL_ERROR as error code. The - * application can also return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, - * which will result in connection closure. Returning any other value - * is treated as :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. + * in that state, and all we can do is tear down connection). When + * data is fully processed, but application wants to make + * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return + * immediately without processing next frames, return + * :enum:`NGHTTP2_ERR_PAUSE`. If application decided to reset this + * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then + * the library will send RST_STREAM with INTERNAL_ERROR as error code. + * The application can also return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in + * connection closure. Returning any other value is treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned. */ typedef int (*nghttp2_send_data_callback)(nghttp2_session *session, nghttp2_frame *frame, diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 4b39ef4c..4ddb06f7 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -2610,12 +2610,15 @@ static int session_call_send_data(nghttp2_session *session, &aux_data->data_prd.source, session->user_data); - if (rv == 0 || rv == NGHTTP2_ERR_WOULDBLOCK || - rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + switch (rv) { + case 0: + case NGHTTP2_ERR_WOULDBLOCK: + case NGHTTP2_ERR_PAUSE: + case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE: return rv; + default: + return NGHTTP2_ERR_CALLBACK_FAILURE; } - - return NGHTTP2_ERR_CALLBACK_FAILURE; } static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, @@ -2790,6 +2793,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, case NGHTTP2_OB_SEND_NO_COPY: { nghttp2_stream *stream; nghttp2_frame *frame; + int pause; DEBUGF(fprintf(stderr, "send: no copy DATA\n")); @@ -2833,7 +2837,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, return 0; } - assert(rv == 0); + pause = (rv == NGHTTP2_ERR_PAUSE); rv = session_after_frame_sent1(session); if (rv < 0) { @@ -2848,6 +2852,10 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, /* We have already adjusted the next state */ + if (pause) { + return 0; + } + break; } case NGHTTP2_OB_SEND_CLIENT_MAGIC: {