-
Notifications
You must be signed in to change notification settings - Fork 85
test: use TestRequestHeaderMapImpl for building custom headers #2455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
0f08b73
bbb24fd
d7f31d3
3ac0389
fe86f65
defc626
a398b4e
fb2276d
9e72e3c
464f0e6
2703f3a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,14 +9,14 @@ namespace Envoy { | |
| namespace Http { | ||
| namespace Utility { | ||
|
|
||
| void toEnvoyHeaders(HeaderMap& transformed_headers, envoy_headers headers) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The edits to this file aren't strictly part of this diff. I just noticed that the |
||
| Envoy::Http::StatefulHeaderKeyFormatter& formatter = transformed_headers.formatter().value(); | ||
| void toEnvoyHeaders(HeaderMap& envoy_result_headers, envoy_headers headers) { | ||
| Envoy::Http::StatefulHeaderKeyFormatter& formatter = envoy_result_headers.formatter().value(); | ||
| for (envoy_map_size_t i = 0; i < headers.length; i++) { | ||
| std::string key = Data::Utility::copyToString(headers.entries[i].key); | ||
| // Make sure the formatter knows the original case. | ||
| formatter.processKey(key); | ||
| transformed_headers.addCopy(LowerCaseString(key), | ||
| Data::Utility::copyToString(headers.entries[i].value)); | ||
| envoy_result_headers.addCopy(LowerCaseString(key), | ||
| Data::Utility::copyToString(headers.entries[i].value)); | ||
| } | ||
| // The C envoy_headers struct can be released now because the headers have been copied. | ||
| release_envoy_headers(headers); | ||
|
|
@@ -62,7 +62,6 @@ envoy_headers toBridgeHeaders(const HeaderMap& header_map, absl::string_view alp | |
| } | ||
| envoy_data key = Data::Utility::copyToBridgeData(key_val); | ||
| envoy_data value = Data::Utility::copyToBridgeData(header.value().getStringView()); | ||
|
|
||
| transformed_headers.entries[transformed_headers.length] = {key, value}; | ||
| transformed_headers.length++; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| #include "test/common/integration/base_client_integration_test.h" | ||
|
|
||
| #include "gtest/gtest.h" | ||
| #include "library/cc/bridge_utility.h" | ||
| #include "library/common/config/internal.h" | ||
| #include "library/common/http/header_utility.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace { | ||
|
|
@@ -90,16 +92,30 @@ void BaseClientIntegrationTest::initialize() { | |
| stream_ = (*stream_prototype_).start(explicit_flow_control_); | ||
| std::string host(fake_upstreams_[0]->localAddress()->asStringView()); | ||
| Platform::RequestHeadersBuilder builder(Platform::RequestMethod::GET, scheme_, host, "/"); | ||
| for (auto& entry : custom_headers_) { | ||
| auto values = {entry.second}; | ||
| builder.set(entry.first, values); | ||
| } | ||
| if (upstreamProtocol() == Http::CodecType::HTTP2) { | ||
| builder.addUpstreamHttpProtocol(Platform::UpstreamHttpProtocol::HTTP2); | ||
| } | ||
| default_request_headers_ = std::make_shared<Platform::RequestHeaders>(builder.build()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we want to move default_request_headers_ to be a TestRequestHeaderMap impl, and shift all the tests over to using the new utility. |
||
| } | ||
|
|
||
| std::shared_ptr<Platform::RequestHeaders> BaseClientIntegrationTest::envoyToMobileHeaders( | ||
|
alyssawilk marked this conversation as resolved.
|
||
| const Http::TestRequestHeaderMapImpl& request_headers) { | ||
| std::string host(fake_upstreams_[0]->localAddress()->asStringView()); | ||
|
|
||
| envoy_headers envoyHeaders = Http::Utility::toBridgeHeaders(request_headers); | ||
| Platform::RawHeaderMap rawHeaderMap = Platform::envoyHeadersAsRawHeaderMap(envoyHeaders); | ||
|
|
||
| Platform::RequestHeadersBuilder builder(Platform::RequestMethod::GET, scheme_, host, "/"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we actually want to get the scheme and host and path from the request headers, which may mean setting the host and scheme in default_request_headers in the test set up (like they were before) |
||
| for (const auto& pair : rawHeaderMap) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we do something like |
||
| builder.set(pair.first, pair.second); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I follow L117-133. In L117, we iterate over
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch yeah looks like I forgot to delete some code :O |
||
| if (upstreamProtocol() == Http::CodecType::HTTP2) { | ||
| builder.addUpstreamHttpProtocol(Platform::UpstreamHttpProtocol::HTTP2); | ||
| } | ||
| auto mobile_headers = std::make_shared<Platform::RequestHeaders>(builder.build()); | ||
| return mobile_headers; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: consider skipping the temporary variable and just return the make_shared |
||
| } | ||
|
|
||
| void BaseClientIntegrationTest::threadRoutine(absl::Notification& engine_running) { | ||
| setOnEngineRunning([&]() { engine_running.Notify(); }); | ||
| engine_ = build(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,13 +44,14 @@ class BaseClientIntegrationTest : public BaseIntegrationTest, public Platform::E | |
| void threadRoutine(absl::Notification& engine_running); | ||
| // Must be called manually by subclasses in their TearDown(); | ||
| void TearDown(); | ||
| std::shared_ptr<Platform::RequestHeaders> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. comment? |
||
| envoyToMobileHeaders(const Http::TestRequestHeaderMapImpl& request_headers); | ||
|
|
||
| Event::ProvisionalDispatcherPtr dispatcher_ = std::make_unique<Event::ProvisionalDispatcher>(); | ||
| envoy_http_callbacks bridge_callbacks_; | ||
| ConditionalInitializer terminal_callback_; | ||
| callbacks_called cc_{0, 0, 0, 0, 0, 0, 0, "", &terminal_callback_, {}}; | ||
| std::shared_ptr<Platform::RequestHeaders> default_request_headers_; | ||
| absl::flat_hash_map<std::string, std::string> custom_headers_; | ||
| Event::DispatcherPtr full_dispatcher_; | ||
| Platform::StreamPrototypeSharedPtr stream_prototype_; | ||
| Platform::StreamSharedPtr stream_; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| #include "source/extensions/http/header_formatters/preserve_case/config.h" | ||
| #include "source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.h" | ||
|
|
||
| #include "test/common/http/common.h" | ||
| #include "test/common/integration/base_client_integration_test.h" | ||
| #include "test/integration/autonomous_upstream.h" | ||
|
|
||
|
|
@@ -39,11 +40,16 @@ INSTANTIATE_TEST_SUITE_P(IpVersions, ClientIntegrationTest, | |
| TestUtility::ipTestParamsToString); | ||
|
|
||
| TEST_P(ClientIntegrationTest, Basic) { | ||
| Buffer::OwnedImpl request_data = Buffer::OwnedImpl("request body"); | ||
| custom_headers_.emplace(AutonomousStream::EXPECT_REQUEST_SIZE_BYTES, | ||
| std::to_string(request_data.length())); | ||
| initialize(); | ||
|
|
||
| Buffer::OwnedImpl request_data = Buffer::OwnedImpl("request body"); | ||
| Http::TestRequestHeaderMapImpl custom_headers; | ||
| HttpTestUtility::addDefaultHeaders(custom_headers); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can use default_request_headers_ and make sure we addDefaultHeaders in initialize() to avoid having to create headers in each test case |
||
| custom_headers.addCopy(AutonomousStream::EXPECT_REQUEST_SIZE_BYTES, | ||
| std::to_string(request_data.length())); | ||
| std::shared_ptr<Platform::RequestHeaders> custom_request_headers = | ||
| envoyToMobileHeaders(custom_headers); | ||
|
|
||
| stream_prototype_->setOnData([this](envoy_data c_data, bool end_stream) { | ||
| if (end_stream) { | ||
| EXPECT_EQ(Data::Utility::copyToString(c_data), ""); | ||
|
|
@@ -54,7 +60,7 @@ TEST_P(ClientIntegrationTest, Basic) { | |
| release_envoy_data(c_data); | ||
| }); | ||
|
|
||
| stream_->sendHeaders(default_request_headers_, false); | ||
| stream_->sendHeaders(custom_request_headers, false); | ||
|
|
||
| envoy_data c_data = Data::Utility::toBridgeData(request_data); | ||
| stream_->sendData(c_data); | ||
|
|
@@ -92,10 +98,15 @@ TEST_P(ClientIntegrationTest, BasicNon2xx) { | |
| } | ||
|
|
||
| TEST_P(ClientIntegrationTest, BasicReset) { | ||
| custom_headers_.emplace(AutonomousStream::RESET_AFTER_REQUEST, "yes"); | ||
| initialize(); | ||
|
|
||
| stream_->sendHeaders(default_request_headers_, true); | ||
| Http::TestRequestHeaderMapImpl custom_headers; | ||
| HttpTestUtility::addDefaultHeaders(custom_headers); | ||
| custom_headers.addCopy(AutonomousStream::RESET_AFTER_REQUEST, "yes"); | ||
| std::shared_ptr<Platform::RequestHeaders> custom_request_headers = | ||
| envoyToMobileHeaders(custom_headers); | ||
|
|
||
| stream_->sendHeaders(custom_request_headers, true); | ||
| terminal_callback_.waitReady(); | ||
|
|
||
| ASSERT_EQ(cc_.on_error_calls, 1); | ||
|
|
@@ -198,10 +209,39 @@ TEST_P(ClientIntegrationTest, CancelWithPartialStream) { | |
|
|
||
| // Test header key case sensitivity. | ||
| TEST_P(ClientIntegrationTest, CaseSensitive) { | ||
| custom_headers_.emplace("FoO", "bar"); | ||
| autonomous_upstream_ = false; | ||
| Envoy::Extensions::Http::HeaderFormatters::PreserveCase:: | ||
| forceRegisterPreserveCaseFormatterFactoryConfig(); | ||
| config_helper_.addConfigModifier([](envoy::config::bootstrap::v3::Bootstrap& bootstrap) { | ||
| ConfigHelper::HttpProtocolOptions protocol_options; | ||
| auto typed_extension_config = protocol_options.mutable_explicit_http_config() | ||
| ->mutable_http_protocol_options() | ||
| ->mutable_header_key_format() | ||
| ->mutable_stateful_formatter(); | ||
| typed_extension_config->set_name("preserve_case"); | ||
| typed_extension_config->mutable_typed_config()->set_type_url( | ||
| "type.googleapis.com/" | ||
| "envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig"); | ||
| ConfigHelper::setProtocolOptions(*bootstrap.mutable_static_resources()->mutable_clusters(0), | ||
| protocol_options); | ||
| }); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need this? Envoy defaults should include stateful formatter |
||
| initialize(); | ||
|
|
||
| Http::TestRequestHeaderMapImpl custom_headers; | ||
| HttpTestUtility::addDefaultHeaders(custom_headers); | ||
|
|
||
| custom_headers.header_map_->setFormatter( | ||
| std::make_unique< | ||
| Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>( | ||
| false, envoy::extensions::http::header_formatters::preserve_case::v3:: | ||
| PreserveCaseFormatterConfig::DEFAULT)); | ||
|
|
||
| custom_headers.addCopy("FoO", "bar"); | ||
| custom_headers.header_map_->formatter().value().get().processKey("FoO"); | ||
|
|
||
| std::shared_ptr<Platform::RequestHeaders> custom_request_headers = | ||
| envoyToMobileHeaders(custom_headers); | ||
|
|
||
| stream_prototype_->setOnHeaders( | ||
| [this](Platform::ResponseHeadersSharedPtr headers, bool, envoy_stream_intel) { | ||
| cc_.status = absl::StrCat(headers->httpStatus()); | ||
|
|
@@ -211,7 +251,7 @@ TEST_P(ClientIntegrationTest, CaseSensitive) { | |
| return nullptr; | ||
| }); | ||
|
|
||
| stream_->sendHeaders(default_request_headers_, true); | ||
| stream_->sendHeaders(custom_request_headers, true); | ||
|
|
||
| Envoy::FakeRawConnectionPtr upstream_connection; | ||
| ASSERT_TRUE(fake_upstreams_[0]->waitForRawConnection(upstream_connection)); | ||
|
|
@@ -220,6 +260,7 @@ TEST_P(ClientIntegrationTest, CaseSensitive) { | |
| std::string upstream_request; | ||
| EXPECT_TRUE(upstream_connection->waitForData(FakeRawConnection::waitForInexactMatch("GET /"), | ||
| &upstream_request)); | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: always good to revert non-necessary changes just to reduce churn :-) |
||
| EXPECT_TRUE(absl::StrContains(upstream_request, "FoO: bar")) << upstream_request; | ||
|
|
||
| // Send mixed case headers, and verify via setOnHeaders they are received correctly. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like changes to this file can be reverted?