diff --git a/include/envoy/http/filter.h b/include/envoy/http/filter.h index 609205443d254..116506541d9e4 100644 --- a/include/envoy/http/filter.h +++ b/include/envoy/http/filter.h @@ -609,6 +609,13 @@ class StreamEncoderFilterCallbacks : public virtual StreamFilterCallbacks { */ virtual HeaderMap& addEncodedTrailers() PURE; + /** + * Adds new metadata to be encoded. + * + * @param metadata_map supplies the unique_ptr of the metadata to be encoded. + */ + virtual void addEncodedMetadata(MetadataMapPtr&& metadata_map) PURE; + /** * Called when an encoder filter goes over its high watermark. */ diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 398abbf306d38..8229c9ce9f37d 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -1309,6 +1309,7 @@ void ConnectionManagerImpl::ActiveStream::encodeHeaders(ActiveStreamEncoderFilte ENVOY_STREAM_LOG(trace, "encode headers called: filter={} status={}", *this, static_cast((*entry).get()), static_cast(status)); + (*entry)->encode_headers_called_ = true; const auto continue_iteration = (*entry)->commonHandleAfterHeadersCallback(status, encoding_headers_only_); @@ -1438,10 +1439,19 @@ void ConnectionManagerImpl::ActiveStream::encodeMetadata(ActiveStreamEncoderFilt MetadataMapPtr&& metadata_map_ptr) { resetIdleTimer(); - // Metadata currently go through all filters. - ASSERT(filter == nullptr); - std::list::iterator entry = encoder_filters_.begin(); + std::list::iterator entry = + commonEncodePrefix(filter, false, FilterIterationStartState::CanStartFromCurrent); + for (; entry != encoder_filters_.end(); entry++) { + // If the filter pointed by entry has stopped for all frame type, stores metadata and returns. + // If the filter pointed by entry hasn't returned from encodeHeaders, stores newly added + // metadata in case encodeHeaders returns StopAllIteration. The latter can happen when headers + // callbacks generate new metadata. + if (!(*entry)->encode_headers_called_ || (*entry)->stoppedAll()) { + (*entry)->getSavedResponseMetadata()->emplace_back(std::move(metadata_map_ptr)); + return; + } + FilterMetadataStatus status = (*entry)->handle_->encodeMetadata(*metadata_map_ptr); ENVOY_STREAM_LOG(trace, "encode metadata called: filter={} status={}", *this, static_cast((*entry).get()), static_cast(status)); @@ -2086,6 +2096,19 @@ Buffer::WatermarkBufferPtr ConnectionManagerImpl::ActiveStreamEncoderFilter::cre return Buffer::WatermarkBufferPtr{buffer}; } +void ConnectionManagerImpl::ActiveStreamEncoderFilter::handleMetadataAfterHeadersCallback() { + // If we drain accumulated metadata, the iteration must start with the current filter. + const bool saved_state = iterate_from_current_filter_; + iterate_from_current_filter_ = true; + // If encodeHeaders() returns StopAllIteration, we should skip draining metadata, and wait + // for doMetadata() to drain the metadata after iteration continues. + if (!stoppedAll() && saved_response_metadata_ != nullptr && + !getSavedResponseMetadata()->empty()) { + drainSavedResponseMetadata(); + } + // Restores the original value of iterate_from_current_filter_. + iterate_from_current_filter_ = saved_state; +} void ConnectionManagerImpl::ActiveStreamEncoderFilter::addEncodedData(Buffer::Instance& data, bool streaming) { return parent_.addEncodedData(*this, data, streaming); @@ -2101,6 +2124,11 @@ HeaderMap& ConnectionManagerImpl::ActiveStreamEncoderFilter::addEncodedTrailers( return parent_.addEncodedTrailers(); } +void ConnectionManagerImpl::ActiveStreamEncoderFilter::addEncodedMetadata( + MetadataMapPtr&& metadata_map_ptr) { + return parent_.encodeMetadata(this, std::move(metadata_map_ptr)); +} + void ConnectionManagerImpl::ActiveStreamEncoderFilter:: onEncoderFilterAboveWriteBufferHighWatermark() { ENVOY_STREAM_LOG(debug, "Disabling upstream stream due to filter callbacks.", parent_); diff --git a/source/common/http/conn_manager_impl.h b/source/common/http/conn_manager_impl.h index a72dab9069cda..1b99c6ad6c98a 100644 --- a/source/common/http/conn_manager_impl.h +++ b/source/common/http/conn_manager_impl.h @@ -101,7 +101,7 @@ class ConnectionManagerImpl : Logger::Loggable, : parent_(parent), iteration_state_(IterationState::Continue), iterate_from_current_filter_(false), headers_continued_(false), continue_headers_continued_(false), end_stream_(false), dual_filter_(dual_filter), - decode_headers_called_(false) {} + decode_headers_called_(false), encode_headers_called_(false) {} // Functions in the following block are called after the filter finishes processing // corresponding data. Those functions handle state updates and data storage (if needed) @@ -131,7 +131,7 @@ class ConnectionManagerImpl : Logger::Loggable, virtual const HeaderMapPtr& trailers() PURE; virtual void doMetadata() PURE; // TODO(soya3129): make this pure when adding impl to encodefilter. - virtual void handleMetadataAfterHeadersCallback() {} + virtual void handleMetadataAfterHeadersCallback() PURE; // Http::StreamFilterCallbacks const Network::Connection* connection() override; @@ -173,8 +173,8 @@ class ConnectionManagerImpl : Logger::Loggable, // either because [de|en]codeHeaders() of the current filter returns StopAllIteration or because // [de|en]codeHeaders() adds new metadata to [de|en]code, but we don't know // [de|en]codeHeaders()'s return value yet. The storage is created on demand. - std::unique_ptr saved_request_metadata_; - std::unique_ptr saved_response_metadata_; + std::unique_ptr saved_request_metadata_{nullptr}; + std::unique_ptr saved_response_metadata_{nullptr}; // The state of iteration. enum class IterationState { Continue, // Iteration has not stopped for any frame type. @@ -197,6 +197,7 @@ class ConnectionManagerImpl : Logger::Loggable, bool end_stream_ : 1; const bool dual_filter_ : 1; bool decode_headers_called_ : 1; + bool encode_headers_called_ : 1; }; /** @@ -346,6 +347,7 @@ class ConnectionManagerImpl : Logger::Loggable, } getSavedResponseMetadata()->clear(); } + void handleMetadataAfterHeadersCallback() override; void doMetadata() override { if (saved_response_metadata_ != nullptr) { @@ -359,6 +361,7 @@ class ConnectionManagerImpl : Logger::Loggable, void addEncodedData(Buffer::Instance& data, bool streaming) override; void injectEncodedDataToFilterChain(Buffer::Instance& data, bool end_stream) override; HeaderMap& addEncodedTrailers() override; + void addEncodedMetadata(MetadataMapPtr&& metadata_map) override; void onEncoderFilterAboveWriteBufferHighWatermark() override; void onEncoderFilterBelowWriteBufferLowWatermark() override; void setEncoderBufferLimit(uint32_t limit) override { parent_.setBufferLimit(limit); } diff --git a/source/docs/h2_metadata.md b/source/docs/h2_metadata.md index 81fce3daac7aa..c066efc36b4a0 100644 --- a/source/docs/h2_metadata.md +++ b/source/docs/h2_metadata.md @@ -85,19 +85,16 @@ StreamDecoderFilter::decodeMetadata(MetadataMap metadata\_map). New metadata can be added directly to metadata\_map. If users need to add new metadata for a response to downstream, a -StreamFilter should be created. Users pass the metadata to be added to -StreamDecoderFilterCallbacks::encodeMetadata(MetadataMapPtr&& +StreamEncoderFilter should be created. Users pass the metadata to be added to +StreamEncoderFilterCallbacks::addEncodedMetadata(MetadataMapPtr&& metadata\_map\_ptr). This function can be called in -StreamFilter::encode100ContinueHeaders(HeaderMap& headers), StreamFilter::encodeHeaders(HeaderMap& headers, bool end\_stream), -StreamFilter::encodeData(Buffer::Instance& data, bool end\_stream), StreamFilter::encodeTrailers(HeaderMap& trailers). -Consequently, the new metadata will be passed through all the encoding filters. Note that, the added -metadata should not share the same key as the metadata to be consumed. Otherwise, the added metadata -will be consumed. +StreamEncoderFilter::encode100ContinueHeaders(HeaderMap& headers), StreamEncoderFilter::encodeHeaders(HeaderMap& headers, bool end\_stream), +StreamEncoderFilter::encodeData(Buffer::Instance& data, bool end\_stream), StreamEncoderFilter::encodeTrailers(HeaderMap& trailers). +Consequently, the new metadata will be passed through all the encoding filters that follow the filter +where the new metadata are added. If users receive metadata from upstream, new metadata can be added directly to -the input argument metadata\_map in StreamFilter::encodeMetadata(MetadataMap& metadata\_map). Note that, -users should never call StreamDecoderFilterCallbacks::encodeMetadata(MetadataMapPtr&& -metadata\_map\_ptr) to add new metadata in StreamFilter::encodeMetadata(MetadataMap& metadata\_map). +the input argument metadata\_map in StreamFilter::encodeMetadata(MetadataMap& metadata\_map). ### Metadata implementation diff --git a/test/common/http/http1/BUILD b/test/common/http/http1/BUILD index efee73f47d1b0..bbc1464177922 100644 --- a/test/common/http/http1/BUILD +++ b/test/common/http/http1/BUILD @@ -27,6 +27,7 @@ envoy_cc_test( "//test/mocks/protobuf:protobuf_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", + "//test/test_common:logging_lib", ], ) diff --git a/test/common/http/http1/codec_impl_test.cc b/test/common/http/http1/codec_impl_test.cc index 793a4b003f9c3..f2b04b6e088ab 100644 --- a/test/common/http/http1/codec_impl_test.cc +++ b/test/common/http/http1/codec_impl_test.cc @@ -18,6 +18,7 @@ #include "test/mocks/protobuf/mocks.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/thread_local/mocks.h" +#include "test/test_common/logging.h" #include "test/test_common/printers.h" #include "test/test_common/utility.h" diff --git a/test/integration/filters/encode_headers_return_stop_all_filter.cc b/test/integration/filters/encode_headers_return_stop_all_filter.cc index 559121efea37e..778c4897a15a9 100644 --- a/test/integration/filters/encode_headers_return_stop_all_filter.cc +++ b/test/integration/filters/encode_headers_return_stop_all_filter.cc @@ -35,6 +35,10 @@ class EncodeHeadersReturnStopAllFilter : public Http::PassThroughFilter { createTimerForContinue(); + Http::MetadataMap metadata_map = {{"headers", "headers"}}; + Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); + Http::HeaderEntry* entry_buffer = header_map.get(Envoy::Http::LowerCaseString("buffer_limit")); if (entry_buffer == nullptr) { return Http::FilterHeadersStatus::StopAllIterationAndBuffer; @@ -56,6 +60,10 @@ class EncodeHeadersReturnStopAllFilter : public Http::PassThroughFilter { // encodeData will only be called once after iteration resumes. EXPECT_EQ(data.length(), content_size_); } + Http::MetadataMap metadata_map = {{"data", "data"}}; + Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); + Buffer::OwnedImpl added_data(std::string(added_size_, 'a')); encoder_callbacks_->addEncodedData(added_data, false); return Http::FilterDataStatus::Continue; @@ -63,6 +71,10 @@ class EncodeHeadersReturnStopAllFilter : public Http::PassThroughFilter { Http::FilterTrailersStatus encodeTrailers(Http::HeaderMap&) override { ASSERT(timer_triggered_); + Http::MetadataMap metadata_map = {{"trailers", "trailers"}}; + Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); + Buffer::OwnedImpl data(std::string(added_size_, 'a')); encoder_callbacks_->addEncodedData(data, false); return Http::FilterTrailersStatus::Continue; diff --git a/test/integration/filters/response_metadata_filter.cc b/test/integration/filters/response_metadata_filter.cc index bc3779d3692e5..07cc21ac98a2b 100644 --- a/test/integration/filters/response_metadata_filter.cc +++ b/test/integration/filters/response_metadata_filter.cc @@ -16,42 +16,39 @@ class ResponseMetadataStreamFilter : public Http::PassThroughFilter { public: // Inserts one new metadata_map. Http::FilterHeadersStatus encodeHeaders(Http::HeaderMap&, bool) override { - Http::MetadataMap metadata_map = { - {"headers", "headers"}, {"duplicate", "duplicate"}, {"remove", "remove"}}; + Http::MetadataMap metadata_map = {{"headers", "headers"}, {"duplicate", "duplicate"}}; Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); - decoder_callbacks_->encodeMetadata(std::move(metadata_map_ptr)); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); return Http::FilterHeadersStatus::Continue; } // Inserts one new metadata_map. Http::FilterDataStatus encodeData(Buffer::Instance&, bool) override { - Http::MetadataMap metadata_map = { - {"data", "data"}, {"duplicate", "duplicate"}, {"remove", "remove"}}; + Http::MetadataMap metadata_map = {{"data", "data"}, {"duplicate", "duplicate"}}; Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); - decoder_callbacks_->encodeMetadata(std::move(metadata_map_ptr)); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); return Http::FilterDataStatus::Continue; } // Inserts two metadata_maps by calling decoder_callbacks_->encodeMetadata() twice. Http::FilterTrailersStatus encodeTrailers(Http::HeaderMap&) override { - Http::MetadataMap metadata_map = {{"trailers", "trailers"}, {"remove", "remove"}}; + Http::MetadataMap metadata_map = {{"trailers", "trailers"}}; Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); - decoder_callbacks_->encodeMetadata(std::move(metadata_map_ptr)); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); metadata_map = {{"duplicate", "duplicate"}}; metadata_map_ptr = std::make_unique(metadata_map); - decoder_callbacks_->encodeMetadata(std::move(metadata_map_ptr)); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); return Http::FilterTrailersStatus::Continue; } // Inserts two metadata_maps by calling decoder_callbacks_->encodeMetadata() twice. Http::FilterHeadersStatus encode100ContinueHeaders(Http::HeaderMap&) override { - Http::MetadataMap metadata_map = { - {"100-continue", "100-continue"}, {"duplicate", "duplicate"}, {"remove", "remove"}}; + Http::MetadataMap metadata_map = {{"100-continue", "100-continue"}, {"duplicate", "duplicate"}}; Http::MetadataMapPtr metadata_map_ptr = std::make_unique(metadata_map); - decoder_callbacks_->encodeMetadata(std::move(metadata_map_ptr)); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); metadata_map = {{"duplicate", "duplicate"}}; metadata_map_ptr = std::make_unique(metadata_map); - decoder_callbacks_->encodeMetadata(std::move(metadata_map_ptr)); + encoder_callbacks_->addEncodedMetadata(std::move(metadata_map_ptr)); return Http::FilterHeadersStatus::Continue; } @@ -66,10 +63,6 @@ class ResponseMetadataStreamFilter : public Http::PassThroughFilter { metadata_map.erase("consume"); metadata_map.emplace("replace", "replace"); } - it = metadata_map.find("remove"); - if (it != metadata_map.end()) { - metadata_map.erase("remove"); - } it = metadata_map.find("metadata"); if (it != metadata_map.end()) { metadata_map.erase("metadata"); diff --git a/test/integration/http2_integration_test.cc b/test/integration/http2_integration_test.cc index f59c55e59cf13..d03a7d1eacc20 100644 --- a/test/integration/http2_integration_test.cc +++ b/test/integration/http2_integration_test.cc @@ -280,8 +280,7 @@ TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { response->waitForEndStream(); ASSERT_TRUE(response->complete()); - // Verify metadata added in encodeHeaders(): "headers", "duplicate" and "keep". - std::set expected_metadata_keys = {"headers", "duplicate", "keep"}; + std::set expected_metadata_keys = {"headers", "duplicate"}; verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys); // Upstream responds with headers and data. @@ -292,13 +291,9 @@ TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { response->waitForEndStream(); ASSERT_TRUE(response->complete()); - // Verify metadata added in encodeHeaders(): "headers" and "duplicate" and metadata added in - // encodeData(): "data" and "duplicate" are received by the client. Note that "remove" is - // consumed. expected_metadata_keys.insert("data"); verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys); EXPECT_EQ(response->keyCount("duplicate"), 2); - EXPECT_EQ(response->keyCount("keep"), 2); // Upstream responds with headers, data and trailers. response = codec_client_->makeRequestWithBody(default_request_headers_, 10); @@ -310,13 +305,9 @@ TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { response->waitForEndStream(); ASSERT_TRUE(response->complete()); - // Verify metadata added in encodeHeaders(): "headers" and "duplicate", and metadata added in - // encodeData(): "data" and "duplicate", and metadata added in encodeTrailer(): "trailers" and - // "duplicate" are received by the client. Note that "remove" is consumed. expected_metadata_keys.insert("trailers"); verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys); EXPECT_EQ(response->keyCount("duplicate"), 3); - EXPECT_EQ(response->keyCount("keep"), 4); // Upstream responds with headers, 100-continue and data. response = codec_client_->makeRequestWithBody(Http::TestHeaderMapImpl{{":method", "GET"}, @@ -334,14 +325,10 @@ TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { response->waitForEndStream(); ASSERT_TRUE(response->complete()); - // Verify metadata added in encodeHeaders: "headers" and "duplicate", and metadata added in - // encodeData(): "data" and "duplicate", and metadata added in encode100Continue(): "100-continue" - // and "duplicate" are received by the client. Note that "remove" is consumed. expected_metadata_keys.erase("trailers"); expected_metadata_keys.insert("100-continue"); verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys); EXPECT_EQ(response->keyCount("duplicate"), 4); - EXPECT_EQ(response->keyCount("keep"), 4); // Upstream responds with headers and metadata that will not be consumed. response = codec_client_->makeRequestWithBody(default_request_headers_, 10); @@ -355,19 +342,16 @@ TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { response->waitForEndStream(); ASSERT_TRUE(response->complete()); - // Verify metadata added in encodeHeaders(): "headers" and "duplicate", and metadata added in - // encodeMetadata(): "aaa", "keep" and "duplicate" are received by the client. Note that "remove" - // is consumed. expected_metadata_keys.erase("data"); expected_metadata_keys.erase("100-continue"); expected_metadata_keys.insert("aaa"); + expected_metadata_keys.insert("keep"); verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys); - EXPECT_EQ(response->keyCount("keep"), 2); // Upstream responds with headers, data and metadata that will be consumed. response = codec_client_->makeRequestWithBody(default_request_headers_, 10); waitForNextUpstreamRequest(); - metadata_map = {{"consume", "consume"}, {"remove", "remove"}}; + metadata_map = {{"consume", "consume"}}; metadata_map_ptr = std::make_unique(metadata_map); metadata_map_vector.clear(); metadata_map_vector.push_back(std::move(metadata_map_ptr)); @@ -377,15 +361,11 @@ TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { response->waitForEndStream(); ASSERT_TRUE(response->complete()); - // Verify metadata added in encodeHeaders(): "headers" and "duplicate", and metadata added in - // encodeData(): "data", "duplicate", and metadata added in encodeMetadata(): "keep", "duplicate", - // "replace" are received by the client. Note that key "remove" and "consume" are consumed. expected_metadata_keys.erase("aaa"); expected_metadata_keys.insert("data"); expected_metadata_keys.insert("replace"); verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys); EXPECT_EQ(response->keyCount("duplicate"), 2); - EXPECT_EQ(response->keyCount("keep"), 3); } TEST_P(Http2MetadataIntegrationTest, ProxyMultipleMetadataReachSizeLimit) { @@ -729,6 +709,44 @@ TEST_P(Http2MetadataIntegrationTest, RequestMetadataWithStopAllFilterAfterMetada testRequestMetadataWithStopAllFilter(); } +TEST_P(Http2MetadataIntegrationTest, TestAddEncodedMetadata) { + config_helper_.addFilter(R"EOF( +name: encode-headers-return-stop-all-filter +)EOF"); + + initialize(); + codec_client_ = makeHttpConnection(lookupPort("http")); + + // Upstream responds with headers, data and trailers. + auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10); + waitForNextUpstreamRequest(); + + const int count = 70; + const int size = 1000; + const int added_decoded_data_size = 1; + + default_response_headers_.addCopy("content_size", std::to_string(count * size)); + default_response_headers_.addCopy("added_size", std::to_string(added_decoded_data_size)); + default_response_headers_.addCopy("is_first_trigger", "value"); + + upstream_request_->encodeHeaders(default_response_headers_, false); + for (int i = 0; i < count - 1; i++) { + upstream_request_->encodeData(size, false); + } + + upstream_request_->encodeData(size, false); + Http::TestHeaderMapImpl response_trailers{{"response", "trailer"}}; + upstream_request_->encodeTrailers(response_trailers); + + response->waitForEndStream(); + ASSERT_TRUE(response->complete()); + EXPECT_EQ(response->metadata_map().find("headers")->second, "headers"); + EXPECT_EQ(response->metadata_map().find("data")->second, "data"); + EXPECT_EQ(response->metadata_map().find("trailers")->second, "trailers"); + EXPECT_EQ(response->metadata_map().size(), 3); + EXPECT_EQ(count * size + added_decoded_data_size * 2, response->body().size()); +} + TEST_P(Http2IntegrationTest, GrpcRouterNotFound) { config_helper_.setDefaultHostAndRoute("foo.com", "/found"); initialize(); diff --git a/test/integration/protocol_integration_test.cc b/test/integration/protocol_integration_test.cc index ae7801e4176e9..d550d793b9994 100644 --- a/test/integration/protocol_integration_test.cc +++ b/test/integration/protocol_integration_test.cc @@ -959,6 +959,9 @@ TEST_P(DownstreamProtocolIntegrationTest, testEncodeHeadersReturnsStopAll) { config_helper_.addFilter(R"EOF( name: encode-headers-return-stop-all-filter )EOF"); + config_helper_.addConfigModifier( + [&](envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& hcm) + -> void { hcm.mutable_http2_protocol_options()->set_allow_metadata(true); }); initialize(); codec_client_ = makeHttpConnection(lookupPort("http")); @@ -988,6 +991,9 @@ TEST_P(DownstreamProtocolIntegrationTest, testEncodeHeadersReturnsStopAllWaterma config_helper_.addFilter(R"EOF( name: encode-headers-return-stop-all-filter )EOF"); + config_helper_.addConfigModifier( + [&](envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& hcm) + -> void { hcm.mutable_http2_protocol_options()->set_allow_metadata(true); }); // Sets initial stream window to min value to make the upstream sensitive to a low watermark. config_helper_.addConfigModifier( diff --git a/test/mocks/http/mocks.h b/test/mocks/http/mocks.h index 13f5d6717a031..afc56eb159fba 100644 --- a/test/mocks/http/mocks.h +++ b/test/mocks/http/mocks.h @@ -224,6 +224,7 @@ class MockStreamEncoderFilterCallbacks : public StreamEncoderFilterCallbacks, MOCK_METHOD2(addEncodedData, void(Buffer::Instance& data, bool streaming)); MOCK_METHOD2(injectEncodedDataToFilterChain, void(Buffer::Instance& data, bool end_stream)); MOCK_METHOD0(addEncodedTrailers, HeaderMap&()); + MOCK_METHOD1(addEncodedMetadata, void(Http::MetadataMapPtr&&)); MOCK_METHOD0(continueEncoding, void()); MOCK_METHOD0(encodingBuffer, const Buffer::Instance*()); MOCK_METHOD1(modifyEncodingBuffer, void(std::function));