diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index db7c208c..481c846d 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1099,9 +1099,18 @@ typedef int (*nghttp2_on_unknown_frame_recv_callback) * to produce these parameters, because it may refer to the memory * region included in the input bytes. * + * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close + * the stream by issuing RST_STREAM with + * :enum:`NGHTTP2_INTERNAL_ERROR`. In this case, + * :type:`nghttp2_on_end_headers_callback` will not be invoked. + * * The implementation of this function must return 0 if it - * succeeds. It may return :enum:`NGHTTP2_ERR_PAUSE`. If the other - * nonzero value is returned, it is treated as fatal error and + * succeeds. It may return :enum:`NGHTTP2_ERR_PAUSE` or + * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. For other critical + * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If + * the other nonzero value is returned, it is treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. If + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned, * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 45108ebc..f1e18339 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1861,7 +1861,8 @@ static int session_call_on_header(nghttp2_session *session, nv->name, nv->namelen, nv->value, nv->valuelen, session->user_data); - if(rv == NGHTTP2_ERR_PAUSE) { + if(rv == NGHTTP2_ERR_PAUSE || + rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { return rv; } if(rv != 0) { @@ -1988,7 +1989,8 @@ static ssize_t inflate_header_block(nghttp2_session *session, *readlen_ptr += rv; if(call_header_cb && (inflate_flags & NGHTTP2_HD_INFLATE_EMIT)) { rv = session_call_on_header(session, frame, &nv); - /* This handles NGHTTP2_ERR_PAUSE as well */ + /* This handles NGHTTP2_ERR_PAUSE and + NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */ if(rv != 0) { return rv; } @@ -3643,6 +3645,19 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(rv == NGHTTP2_ERR_PAUSE) { return in - first; } + if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + /* The application says no more headers. We decompress the + rest of the header block but not invoke + on_header_callback and on_end_headers_callback. */ + rv = nghttp2_session_add_rst_stream(session, + iframe->frame.hd.stream_id, + NGHTTP2_INTERNAL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } if(rv == NGHTTP2_ERR_HEADER_COMP) { /* GOAWAY is already issued */ if(iframe->payloadleft == 0) {