diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 624289bb..20c6ff1f 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -904,6 +904,47 @@ int on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame, } } // namespace +namespace { +int on_invalid_header_callback2(nghttp2_session *session, + const nghttp2_frame *frame, nghttp2_rcbuf *name, + nghttp2_rcbuf *value, uint8_t flags, + void *user_data) { + auto http2session = static_cast(user_data); + auto sd = static_cast( + nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)); + if (!sd || !sd->dconn) { + return 0; + } + auto downstream = sd->dconn->get_downstream(); + if (!downstream) { + return 0; + } + + int32_t stream_id; + + if (frame->hd.type == NGHTTP2_PUSH_PROMISE) { + stream_id = frame->push_promise.promised_stream_id; + } else { + stream_id = frame->hd.stream_id; + } + + if (LOG_ENABLED(INFO)) { + auto namebuf = nghttp2_rcbuf_get_buf(name); + auto valuebuf = nghttp2_rcbuf_get_buf(value); + + SSLOG(INFO, http2session) + << "Invalid header field for stream_id=" << stream_id + << " in frame type=" << static_cast(frame->hd.type) + << ": name=[" << StringRef{namebuf.base, namebuf.len} << "], value=[" + << StringRef{valuebuf.base, valuebuf.len} << "]"; + } + + http2session->submit_rst_stream(stream_id, NGHTTP2_PROTOCOL_ERROR); + + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; +} +} // namespace + namespace { int on_begin_headers_callback(nghttp2_session *session, const nghttp2_frame *frame, void *user_data) { @@ -1486,6 +1527,9 @@ nghttp2_session_callbacks *create_http2_downstream_callbacks() { nghttp2_session_callbacks_set_on_header_callback2(callbacks, on_header_callback2); + nghttp2_session_callbacks_set_on_invalid_header_callback2( + callbacks, on_invalid_header_callback2); + nghttp2_session_callbacks_set_on_begin_headers_callback( callbacks, on_begin_headers_callback); diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 202d46ae..42ec9561 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -227,6 +227,34 @@ int on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame, } } // namespace +namespace { +int on_invalid_header_callback2(nghttp2_session *session, + const nghttp2_frame *frame, nghttp2_rcbuf *name, + nghttp2_rcbuf *value, uint8_t flags, + void *user_data) { + auto upstream = static_cast(user_data); + auto downstream = static_cast( + nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)); + if (!downstream) { + return 0; + } + + if (LOG_ENABLED(INFO)) { + auto namebuf = nghttp2_rcbuf_get_buf(name); + auto valuebuf = nghttp2_rcbuf_get_buf(value); + + ULOG(INFO, upstream) << "Invalid header field for stream_id=" + << frame->hd.stream_id << ": name=[" + << StringRef{namebuf.base, namebuf.len} << "], value=[" + << StringRef{valuebuf.base, valuebuf.len} << "]"; + } + + upstream->rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR); + + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; +} +} // namespace + namespace { int on_begin_headers_callback(nghttp2_session *session, const nghttp2_frame *frame, void *user_data) { @@ -852,6 +880,9 @@ nghttp2_session_callbacks *create_http2_upstream_callbacks() { nghttp2_session_callbacks_set_on_header_callback2(callbacks, on_header_callback2); + nghttp2_session_callbacks_set_on_invalid_header_callback2( + callbacks, on_invalid_header_callback2); + nghttp2_session_callbacks_set_on_begin_headers_callback( callbacks, on_begin_headers_callback);