Skip to content

Commit 68bc8ac

Browse files
sukolenvombadov
authored andcommitted
http-tap: gracefully handle request termination (envoyproxy#40907)
Commit Message: http-tap: gracefully handle request termination Additional Description: Steps to reproduce the issue and backstrace are awailable in the ticket. Additionally I've recorded sequence of method calls in TapFilter with short header and large header for comparison. Issue is caused because request headers were accessed without `HttpPerRequestTapperImpl::onRequestHeaders` being called. <details> <summary>Short header (successfull) call sequence</summary> ``` #0 0x000055555c422214 in Envoy::Extensions::HttpFilters::TapFilter::TapFilterFactory::createFilterFactoryFromProtoTyped(envoy::extensions::filters::http::tap::v3::Tap const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, Envoy::Server::Configuration::FactoryContext&)::$_0::operator()(Envoy::Http::FilterChainFactoryCallbacks&) const () #0 0x000055555c425174 in Envoy::Extensions::HttpFilters::TapFilter::Filter* std::__1::__construct_at[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::Filter, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&, Envoy::Extensions::HttpFilters::TapFilter::Filter*>(Envoy::Extensions::HttpFilters::TapFilter::Filter*, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&) () #0 0x000055555c4251a4 in Envoy::Extensions::HttpFilters::TapFilter::Filter* std::__1::construct_at[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::Filter, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&, Envoy::Extensions::HttpFilters::TapFilter::Filter*>(Envoy::Extensions::HttpFilters::TapFilter::Filter*, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&) () #0 0x000055555c425224 in Envoy::Extensions::HttpFilters::TapFilter::Filter::Filter(std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig>) () #0 0x000055555c42ee44 in Envoy::Extensions::HttpFilters::TapFilter::Filter::setDecoderFilterCallbacks(Envoy::Http::StreamDecoderFilterCallbacks&) () #0 0x000055555c42e4c4 in Envoy::Extensions::HttpFilters::TapFilter::FilterConfigImpl::currentConfig() () #0 0x000055555c42f184 in Envoy::Extensions::HttpFilters::TapFilter::FilterConfigImpl::getTapConfig() const () #0 0x000055555c426134 in Envoy::Extensions::HttpFilters::TapFilter::HttpTapConfigImpl::createPerRequestTapper(envoy::extensions::filters::http::tap::v3::Tap const&, unsigned long, Envoy::OptRef<Envoy::Network::Connection const>) () #0 0x000055555c42d7a4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::HttpPerRequestTapperImpl(std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::HttpTapConfig>, envoy::extensions::filters::http::tap::v3::Tap const&, unsigned long, Envoy::OptRef<Envoy::Network::Connection const>) () #0 0x000055555c42da44 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper::HttpPerRequestTapper() () #0 0x000055555c42dbe4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*& std::__1::__compressed_pair<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*, std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl> >::__compressed_pair[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*&, std::__1::__value_init_tag>(std::__1::__value_init_tag&&) () #0 0x000055555c42ddc4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*&& std::__1::__compressed_pair<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper*, std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper> >::__compressed_pair[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*, std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl> >(std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl>&&) () #0 0x000055555c42efd4 in Envoy::Extensions::HttpFilters::TapFilter::Filter::setEncoderFilterCallbacks(Envoy::Http::StreamEncoderFilterCallbacks&) () #0 0x000055555c42e724 in Envoy::Extensions::HttpFilters::TapFilter::Filter::decodeHeaders(Envoy::Http::RequestHeaderMap&, bool) () #0 0x000055555c4263e4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onRequestHeaders(Envoy::Http::RequestHeaderMap const&) () #0 0x000055555c426234 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::streamRequestHeaders() () #0 0x000055555c42a334 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::makeTraceSegment() () #0 0x000055555c4263a4 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*) () #0 0x000055555c428db4 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0&& std::__1::__function::__value_func<Envoy::Http::HeaderMap::Iterate (Envoy::Http::HeaderEntry const&)>::__value_func[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0, std::__1::allocator<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0> >(std::__1::allocator<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0> const&) () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c42e914 in Envoy::Extensions::HttpFilters::TapFilter::Filter::encodeHeaders(Envoy::Http::ResponseHeaderMap&, bool) () #0 0x000055555c427c74 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onResponseHeaders(Envoy::Http::ResponseHeaderMap const&) () #0 0x000055555c427b04 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::streamResponseHeaders() () #0 0x000055555c42a334 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::makeTraceSegment() () #0 0x000055555c4263a4 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*) () #0 0x000055555c428db4 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0&& std::__1::__function::__value_func<Envoy::Http::HeaderMap::Iterate (Envoy::Http::HeaderEntry const&)>::__value_func[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0, std::__1::allocator<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0> >(std::__1::allocator<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0> const&) () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c429e24 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0::operator()(Envoy::Http::HeaderEntry const&) const () #0 0x000055555c42e9b4 in Envoy::Extensions::HttpFilters::TapFilter::Filter::encodeData(Envoy::Buffer::Instance&, bool) () #0 0x000055555c427df4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onResponseBody(Envoy::Buffer::Instance const&) () #0 0x000055555c4269b4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onBody(Envoy::Buffer::Instance const&, std::__1::unique_ptr<envoy::data::tap::v3::TraceWrapper, std::__1::default_delete<envoy::data::tap::v3::TraceWrapper> >&, unsigned int, envoy::data::tap::v3::Body* (envoy::data::tap::v3::HttpStreamedTraceSegment::*)(), envoy::data::tap::v3::HttpBufferedTrace_Message* (envoy::data::tap::v3::HttpBufferedTrace::*)(), bool) () #0 0x000055555c42a334 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::makeTraceSegment() () #0 0x000055555c42e9b4 in Envoy::Extensions::HttpFilters::TapFilter::Filter::encodeData(Envoy::Buffer::Instance&, bool) () #0 0x000055555c427df4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onResponseBody(Envoy::Buffer::Instance const&) () #0 0x000055555c4269b4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onBody(Envoy::Buffer::Instance const&, std::__1::unique_ptr<envoy::data::tap::v3::TraceWrapper, std::__1::default_delete<envoy::data::tap::v3::TraceWrapper> >&, unsigned int, envoy::data::tap::v3::Body* (envoy::data::tap::v3::HttpStreamedTraceSegment::*)(), envoy::data::tap::v3::HttpBufferedTrace_Message* (envoy::data::tap::v3::HttpBufferedTrace::*)(), bool) () #0 0x000055555c42a334 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::makeTraceSegment() () #0 0x000055555c42e9b4 in Envoy::Extensions::HttpFilters::TapFilter::Filter::encodeData(Envoy::Buffer::Instance&, bool) () #0 0x000055555c42eb04 in Envoy::Extensions::HttpFilters::TapFilter::Filter::log(Envoy::Formatter::HttpFormatterContext const&, Envoy::StreamInfo::StreamInfo const&) () #0 0x000055555c428114 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onDestroyLog() () #0 0x000055555c42f1a4 in Envoy::Extensions::HttpFilters::TapFilter::FilterConfigImpl::stats() () [New Thread 0x7fffe8ad16c0 (LWP 336946)] [2025-08-31T11:23:18.073Z] "GET / HTTP/1.1" 200 - 0 15986 427 243 "-" "curl/8.5.0" "266b6d40-7784-4a7c-919d-d8ae6401442a" "www.envoyproxy.io" "54.253.94.210:443" #0 0x000055555c42ee34 in Envoy::Extensions::HttpFilters::TapFilter::Filter::onDestroy() () #0 0x000055555c42eda4 in Envoy::Extensions::HttpFilters::TapFilter::Filter::~Filter() () #0 0x000055555c42f274 in Envoy::Extensions::HttpFilters::TapFilter::Filter::~Filter() () #0 0x000055555c42aca4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::~HttpPerRequestTapperImpl() () #0 0x000055555c42ac14 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::~HttpPerRequestTapperImpl() () #0 0x000055555c42db14 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper::~HttpPerRequestTapper() () ``` </details> <details> <summary>Large header (segfault) call sequence</summary> ``` #0 0x000055555c422214 in Envoy::Extensions::HttpFilters::TapFilter::TapFilterFactory::createFilterFactoryFromProtoTyped(envoy::extensions::filters::http::tap::v3::Tap const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, Envoy::Server::Configuration::FactoryContext&)::$_0::operator()(Envoy::Http::FilterChainFactoryCallbacks&) const () #0 0x000055555c425174 in Envoy::Extensions::HttpFilters::TapFilter::Filter* std::__1::__construct_at[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::Filter, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&, Envoy::Extensions::HttpFilters::TapFilter::Filter*>(Envoy::Extensions::HttpFilters::TapFilter::Filter*, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&) () #0 0x000055555c4251a4 in Envoy::Extensions::HttpFilters::TapFilter::Filter* std::__1::construct_at[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::Filter, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&, Envoy::Extensions::HttpFilters::TapFilter::Filter*>(Envoy::Extensions::HttpFilters::TapFilter::Filter*, std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig> const&) () #0 0x000055555c425224 in Envoy::Extensions::HttpFilters::TapFilter::Filter::Filter(std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::FilterConfig>) () #0 0x000055555c42ee44 in Envoy::Extensions::HttpFilters::TapFilter::Filter::setDecoderFilterCallbacks(Envoy::Http::StreamDecoderFilterCallbacks&) () #0 0x000055555c42e4c4 in Envoy::Extensions::HttpFilters::TapFilter::FilterConfigImpl::currentConfig() () #0 0x000055555c42f184 in Envoy::Extensions::HttpFilters::TapFilter::FilterConfigImpl::getTapConfig() const () #0 0x000055555c426134 in Envoy::Extensions::HttpFilters::TapFilter::HttpTapConfigImpl::createPerRequestTapper(envoy::extensions::filters::http::tap::v3::Tap const&, unsigned long, Envoy::OptRef<Envoy::Network::Connection const>) () #0 0x000055555c42d7a4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::HttpPerRequestTapperImpl(std::__1::shared_ptr<Envoy::Extensions::HttpFilters::TapFilter::HttpTapConfig>, envoy::extensions::filters::http::tap::v3::Tap const&, unsigned long, Envoy::OptRef<Envoy::Network::Connection const>) () #0 0x000055555c42da44 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper::HttpPerRequestTapper() () #0 0x000055555c42dbe4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*& std::__1::__compressed_pair<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*, std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl> >::__compressed_pair[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*&, std::__1::__value_init_tag>(std::__1::__value_init_tag&&) () #0 0x000055555c42ddc4 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*&& std::__1::__compressed_pair<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper*, std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapper> >::__compressed_pair[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl*, std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl> >(std::__1::default_delete<Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl>&&) () #0 0x000055555c42efd4 in Envoy::Extensions::HttpFilters::TapFilter::Filter::setEncoderFilterCallbacks(Envoy::Http::StreamEncoderFilterCallbacks&) () #0 0x000055555c42e914 in Envoy::Extensions::HttpFilters::TapFilter::Filter::encodeHeaders(Envoy::Http::ResponseHeaderMap&, bool) () #0 0x000055555c427c74 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::onResponseHeaders(Envoy::Http::ResponseHeaderMap const&) () #0 0x000055555c426234 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::streamRequestHeaders() () #0 0x000055555c42a334 in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::makeTraceSegment() () #0 0x000055555c4263a4 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*) () #0 0x000055555c428db4 in Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0&& std::__1::__function::__value_func<Envoy::Http::HeaderMap::Iterate (Envoy::Http::HeaderEntry const&)>::__value_func[abi:ne180100]<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0, std::__1::allocator<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0> >(std::__1::allocator<Envoy::Extensions::HttpFilters::TapFilter::(anonymous namespace)::fillHeaderList(google::protobuf::RepeatedPtrField<envoy::config::core::v3::HeaderValue>*)::$_0> const&) () Thread 16 "wrk:worker_4" received signal SIGSEGV, Segmentation fault. 0x000055555c4262cd in Envoy::Extensions::HttpFilters::TapFilter::HttpPerRequestTapperImpl::streamRequestHeaders() () ``` </details> Risk Level: Low Testing: Unit test added. Also I manually tested locally - after fix Response code 431 returned for large header instead of segmentation fault. Docs Changes: N/A Release Notes: N/A Platform Specific Features: N/A Fixes envoyproxy#39063 --------- Signed-off-by: Vadym Sukolen <[email protected]> Signed-off-by: Vadym S <[email protected]> Signed-off-by: Misha Badov <[email protected]>
1 parent 5948d46 commit 68bc8ac

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

source/extensions/filters/http/tap/tap_config_impl.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ HttpPerRequestTapperPtr HttpTapConfigImpl::createPerRequestTapper(
4444

4545
void HttpPerRequestTapperImpl::streamRequestHeaders() {
4646
TapCommon::TraceWrapperPtr trace = makeTraceSegment();
47-
request_headers_->iterate(fillHeaderList(
48-
trace->mutable_http_streamed_trace_segment()->mutable_request_headers()->mutable_headers()));
47+
if (request_headers_ != nullptr) {
48+
request_headers_->iterate(fillHeaderList(trace->mutable_http_streamed_trace_segment()
49+
->mutable_request_headers()
50+
->mutable_headers()));
51+
}
4952
sink_handle_->submitTrace(std::move(trace));
5053
}
5154

test/extensions/filters/http/tap/tap_config_impl_test.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,37 @@ TEST_F(HttpPerRequestTapperImplTest, StreamedMatchResponseTrailers) {
323323
EXPECT_TRUE(tapper_->onDestroyLog());
324324
}
325325

326+
// Request headers are not guaranteed to be present during
327+
// response reply.
328+
// One known scenario is - request headers are too large. In this
329+
// case processing of the request will be terminated with 431
330+
// status before request headers are parsed.
331+
TEST_F(HttpPerRequestTapperImplTest, StreamNoRequestHeader) {
332+
EXPECT_CALL(*config_, streaming()).WillRepeatedly(Return(true));
333+
EXPECT_CALL(*config_, maxBufferedRxBytes()).WillRepeatedly(Return(1024));
334+
EXPECT_CALL(*config_, maxBufferedTxBytes()).WillRepeatedly(Return(1024));
335+
336+
InSequence s;
337+
EXPECT_CALL(matcher_, onHttpResponseHeaders(_, _))
338+
.WillOnce(Assign(&(*statuses_)[0].matches_, true));
339+
EXPECT_CALL(*sink_manager_, submitTrace_(TraceEqual(
340+
R"EOF(
341+
http_streamed_trace_segment:
342+
trace_id: 1
343+
)EOF")));
344+
EXPECT_CALL(*sink_manager_, submitTrace_(TraceEqual(
345+
R"EOF(
346+
http_streamed_trace_segment:
347+
trace_id: 1
348+
response_headers:
349+
headers:
350+
- key: e
351+
value: f
352+
)EOF")));
353+
// onResponseHeaders called without onRequestHeaders prior
354+
tapper_->onResponseHeaders(response_headers_);
355+
}
356+
326357
class HttpPerRequestTapperImplForSpecificConfigTest : public testing::Test {
327358
public:
328359
HttpPerRequestTapperImplForSpecificConfigTest() {

0 commit comments

Comments
 (0)