diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index ff6ed7ae..f801b7a6 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -816,8 +816,13 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback) * necessarily mean this chunk of data is the last one in the * stream. You should use :type:`nghttp2_on_data_recv_callback` to * know all data frames are 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_data_chunk_recv_callback) +typedef int (*nghttp2_on_data_chunk_recv_callback) (nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *data, size_t len, void *user_data); diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index e2345d95..b6572bf0 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -2908,12 +2908,15 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, data_flags = session->iframe.headbuf[3]; if(session->iframe.state != NGHTTP2_RECV_PAYLOAD_IGN) { if(session->callbacks.on_data_chunk_recv_callback) { - session->callbacks.on_data_chunk_recv_callback(session, - data_flags, - data_stream_id, - inmark, - readlen, - session->user_data); + if(session->callbacks.on_data_chunk_recv_callback + (session, + data_flags, + data_stream_id, + inmark, + readlen, + session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } } } /* TODO We need on_ignored_data_chunk_recv_callback, for diff --git a/src/HttpServer.cc b/src/HttpServer.cc index fa912b17..a63ca1a3 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -752,11 +752,12 @@ void hd_on_frame_send_callback } // namespace namespace { -void on_data_chunk_recv_callback +int on_data_chunk_recv_callback (nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *data, size_t len, void *user_data) { // TODO Handle POST + return 0; } } // namespace diff --git a/src/nghttp.cc b/src/nghttp.cc index bfb3f9cd..4babde42 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -930,7 +930,7 @@ HttpClient* get_session(void *user_data) return reinterpret_cast(user_data); } -void on_data_chunk_recv_callback +int on_data_chunk_recv_callback (nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *data, size_t len, void *user_data) { @@ -963,6 +963,7 @@ void on_data_chunk_recv_callback update_html_parser(client, req, data, len, 0); } } + return 0; } namespace { diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 42650dbf..4269416d 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -291,17 +291,17 @@ int on_frame_recv_callback } // namespace namespace { -void on_data_chunk_recv_callback(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - const uint8_t *data, size_t len, - void *user_data) +int on_data_chunk_recv_callback(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const uint8_t *data, size_t len, + void *user_data) { Http2Upstream *upstream = reinterpret_cast(user_data); Downstream *downstream = upstream->find_downstream(stream_id); if(downstream) { if(downstream->push_upload_data_chunk(data, len) != 0) { upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR); - return; + return 0; } if(upstream->get_flow_control()) { downstream->inc_recv_window_size(len); @@ -319,13 +319,14 @@ void on_data_chunk_recv_callback(nghttp2_session *session, << upstream->get_initial_window_size(); } upstream->rst_stream(downstream, NGHTTP2_FLOW_CONTROL_ERROR); - return; + return 0; } } if(flags & NGHTTP2_FLAG_END_STREAM) { downstream->set_request_state(Downstream::MSG_COMPLETE); } } + return 0; } } // namespace diff --git a/src/shrpx_spdy_session.cc b/src/shrpx_spdy_session.cc index 7e76ed5d..5221aef3 100644 --- a/src/shrpx_spdy_session.cc +++ b/src/shrpx_spdy_session.cc @@ -895,10 +895,10 @@ int on_frame_recv_callback } // namespace namespace { -void on_data_chunk_recv_callback(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - const uint8_t *data, size_t len, - void *user_data) +int on_data_chunk_recv_callback(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const uint8_t *data, size_t len, + void *user_data) { int rv; auto spdy = reinterpret_cast(user_data); @@ -906,12 +906,12 @@ void on_data_chunk_recv_callback(nghttp2_session *session, (nghttp2_session_get_stream_user_data(session, stream_id)); if(!sd || !sd->dconn) { nghttp2_submit_rst_stream(session, stream_id, NGHTTP2_INTERNAL_ERROR); - return; + return 0; } auto downstream = sd->dconn->get_downstream(); if(!downstream || downstream->get_downstream_stream_id() != stream_id) { nghttp2_submit_rst_stream(session, stream_id, NGHTTP2_INTERNAL_ERROR); - return; + return 0; } if(spdy->get_flow_control()) { @@ -929,7 +929,7 @@ void on_data_chunk_recv_callback(nghttp2_session *session, NGHTTP2_FLOW_CONTROL_ERROR); downstream->set_response_state(Downstream::MSG_RESET); call_downstream_readcb(spdy, downstream); - return; + return 0; } } @@ -940,6 +940,7 @@ void on_data_chunk_recv_callback(nghttp2_session *session, downstream->set_response_state(Downstream::MSG_RESET); } call_downstream_readcb(spdy, downstream); + return 0; } } // namespace diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 3d3537f0..25d16058 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -165,13 +165,14 @@ static void on_frame_not_send_callback(nghttp2_session *session, ud->not_sent_error = lib_error; } -static void on_data_chunk_recv_callback(nghttp2_session *session, - uint8_t flags, int32_t stream_id, - const uint8_t *data, size_t len, - void *user_data) +static int on_data_chunk_recv_callback(nghttp2_session *session, + uint8_t flags, int32_t stream_id, + const uint8_t *data, size_t len, + void *user_data) { my_user_data *ud = (my_user_data*)user_data; ++ud->data_chunk_recv_cb_called; + return 0; } static void on_data_recv_callback(nghttp2_session *session,