diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index c5a5298e..de4870d2 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -928,8 +928,13 @@ typedef int (*nghttp2_on_stream_close_callback) * received. In other words, the frame with END_STREAM flag set is * received. In HTTP, this means HTTP request, including request * body, is fully received. + * + * The implementation of this function must return 0 if it + * succeeds. If nonzero is returned, it is treated as fatal error and + * `nghttp2_session_recv()` and `nghttp2_session_send()` functions + * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. */ -typedef void (*nghttp2_on_request_recv_callback) +typedef int (*nghttp2_on_request_recv_callback) (nghttp2_session *session, int32_t stream_id, void *user_data); /** diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index d1e914ba..356afd12 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1611,13 +1611,16 @@ static ssize_t nghttp2_recv(nghttp2_session *session, uint8_t *buf, size_t len) return r; } -static void nghttp2_session_call_on_request_recv +static int nghttp2_session_call_on_request_recv (nghttp2_session *session, int32_t stream_id) { if(session->callbacks.on_request_recv_callback) { - session->callbacks.on_request_recv_callback(session, stream_id, - session->user_data); + if(session->callbacks.on_request_recv_callback(session, stream_id, + session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } } + return 0; } static int nghttp2_session_call_on_frame_received @@ -1776,7 +1779,10 @@ int nghttp2_session_on_request_headers_received(nghttp2_session *session, return r; } if(flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_session_call_on_request_recv(session, frame->hd.stream_id); + r = nghttp2_session_call_on_request_recv(session, frame->hd.stream_id); + if(r != 0) { + return r; + } } } else { r = nghttp2_session_handle_invalid_stream(session, frame, error_code); @@ -1909,7 +1915,11 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, return r; } if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_session_call_on_request_recv(session, frame->hd.stream_id); + r = nghttp2_session_call_on_request_recv(session, + frame->hd.stream_id); + if(r != 0) { + return r; + } nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD); r = nghttp2_session_close_stream_if_shut_rdwr(session, stream); if(r != 0 && nghttp2_is_fatal(r)) { @@ -2717,7 +2727,10 @@ int nghttp2_session_on_data_received(nghttp2_session *session, } } if(flags & NGHTTP2_FLAG_END_STREAM) { - nghttp2_session_call_on_request_recv(session, stream_id); + r = nghttp2_session_call_on_request_recv(session, stream_id); + if(r != 0) { + return r; + } } } if(valid) { diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 5618261f..e7eb58b6 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -728,7 +728,7 @@ int hd_on_frame_recv_callback } } // namespace -void htdocs_on_request_recv_callback +int htdocs_on_request_recv_callback (nghttp2_session *session, int32_t stream_id, void *user_data) { auto hd = reinterpret_cast(user_data); @@ -736,6 +736,7 @@ void htdocs_on_request_recv_callback if(stream) { prepare_response(hd->get_stream(stream_id), hd); } + return 0; } namespace { diff --git a/src/HttpServer.h b/src/HttpServer.h index fe1d9568..1d88657d 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -134,7 +134,7 @@ private: const Config *config_; }; -void htdocs_on_request_recv_callback +int htdocs_on_request_recv_callback (nghttp2_session *session, int32_t stream_id, void *user_data); ssize_t file_read_callback diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index b322e34f..92c92031 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -221,12 +221,13 @@ static ssize_t fail_data_source_read_callback return NGHTTP2_ERR_CALLBACK_FAILURE; } -static void on_request_recv_callback(nghttp2_session *session, - int32_t stream_id, - void *user_data) +static int on_request_recv_callback(nghttp2_session *session, + int32_t stream_id, + void *user_data) { my_user_data *ud = (my_user_data*)user_data; ud->stream_id = stream_id; + return 0; } /* static void no_stream_user_data_stream_close_callback */