Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
347 changes: 342 additions & 5 deletions test/integration/http2_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,355 @@ TEST_P(Http2IntegrationTest, RetryAttemptCount) { testRetryAttemptCountHeader();

TEST_P(Http2IntegrationTest, EnvoyHandling100Continue) { testEnvoyHandling100Continue(); }

static std::string response_metadata_filter = R"EOF(
name: response-metadata-filter
config: {}
)EOF";

// Verifies metadata can be sent at different locations of the responses.
TEST_P(Http2MetadataIntegrationTest, ProxyMetadataInResponse) {
testEnvoyProxyMetadataInResponse();
initialize();
codec_client_ = makeHttpConnection(lookupPort("http"));

// Sends the first request.
auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends metadata before response header.
const std::string key = "key";
std::string value = std::string(80 * 1024, '1');
Http::MetadataMap metadata_map = {{key, value}};
Http::MetadataMapPtr metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
Http::MetadataMapVector metadata_map_vector;
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(12, true);

// Verifies metadata is received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
EXPECT_EQ(response->metadata_map().find(key)->second, value);

// Sends the second request.
response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends metadata after response header followed by an empty data frame with end_stream true.
value = std::string(10, '2');
upstream_request_->encodeHeaders(default_response_headers_, false);
metadata_map = {{key, value}};
metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
metadata_map_vector.erase(metadata_map_vector.begin());
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeData(0, true);

// Verifies metadata is received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
EXPECT_EQ(response->metadata_map().find(key)->second, value);

// Sends the third request.
response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends metadata after response header and before data.
value = std::string(10, '3');
upstream_request_->encodeHeaders(default_response_headers_, false);
metadata_map = {{key, value}};
metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
metadata_map_vector.erase(metadata_map_vector.begin());
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeData(10, true);

// Verifies metadata is received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
EXPECT_EQ(response->metadata_map().find(key)->second, value);

// Sends the fourth request.
response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends metadata between data frames.
value = std::string(10, '4');
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(10, false);
metadata_map = {{key, value}};
metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
metadata_map_vector.erase(metadata_map_vector.begin());
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeData(10, true);

// Verifies metadata is received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
EXPECT_EQ(response->metadata_map().find(key)->second, value);

// Sends the fifth request.
response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends metadata after the last non-empty data frames.
value = std::string(10, '5');
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(10, false);
metadata_map = {{key, value}};
metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
metadata_map_vector.erase(metadata_map_vector.begin());
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeData(0, true);

// Verifies metadata is received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
EXPECT_EQ(response->metadata_map().find(key)->second, value);

// Sends the sixth request.
response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends metadata before reset.
value = std::string(10, '6');
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(10, false);
metadata_map = {{key, value}};
metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
metadata_map_vector.erase(metadata_map_vector.begin());
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeResetStream();

// Verifies stream is reset.
response->waitForReset();
ASSERT_FALSE(response->complete());
}

TEST_P(Http2MetadataIntegrationTest, ProxyMultipleMetadata) { testEnvoyProxyMultipleMetadata(); }
TEST_P(Http2MetadataIntegrationTest, ProxyMultipleMetadata) {
initialize();
codec_client_ = makeHttpConnection(lookupPort("http"));

// Sends a request.
auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

const int size = 4;
std::vector<Http::MetadataMapVector> multiple_vecs(size);
for (int i = 0; i < size; i++) {
Runtime::RandomGeneratorImpl random;
int value_size = random.random() % Http::METADATA_MAX_PAYLOAD_SIZE + 1;
Http::MetadataMap metadata_map = {{std::string(i, 'a'), std::string(value_size, 'b')}};
Http::MetadataMapPtr metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
multiple_vecs[i].push_back(std::move(metadata_map_ptr));
}
upstream_request_->encodeMetadata(multiple_vecs[0]);
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeMetadata(multiple_vecs[1]);
upstream_request_->encodeData(12, false);
upstream_request_->encodeMetadata(multiple_vecs[2]);
upstream_request_->encodeData(12, false);
upstream_request_->encodeMetadata(multiple_vecs[3]);
upstream_request_->encodeData(12, true);

// Verifies multiple metadata are received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
for (int i = 0; i < size; i++) {
for (const auto& metadata : *multiple_vecs[i][0]) {
EXPECT_EQ(response->metadata_map().find(metadata.first)->second, metadata.second);
}
}
EXPECT_EQ(response->metadata_map().size(), multiple_vecs.size());
}

TEST_P(Http2MetadataIntegrationTest, ProxyInvalidMetadata) { testEnvoyProxyInvalidMetadata(); }
TEST_P(Http2MetadataIntegrationTest, ProxyInvalidMetadata) {
initialize();
codec_client_ = makeHttpConnection(lookupPort("http"));

TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) { testResponseMetadata(); }
// Sends a request.
auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends over-sized metadata before response header.
const std::string key = "key";
std::string value = std::string(1024 * 1024, 'a');
Http::MetadataMap metadata_map = {{key, value}};
Http::MetadataMapPtr metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
Http::MetadataMapVector metadata_map_vector;
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeData(12, false);
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeData(12, true);

// Verifies metadata is not received by the client.
response->waitForEndStream();
ASSERT_TRUE(response->complete());
EXPECT_EQ(response->metadata_map().size(), 0);
}

void verifyExpectedMetadata(Http::MetadataMap metadata_map, std::set<std::string> keys) {
for (const auto key : keys) {
// keys are the same as their corresponding values.
EXPECT_EQ(metadata_map.find(key)->second, key);
}
EXPECT_EQ(metadata_map.size(), keys.size());
}

TEST_P(Http2MetadataIntegrationTest, TestResponseMetadata) {

addFilters({response_metadata_filter});
config_helper_.addConfigModifier(
[&](envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager& hcm)
-> void { hcm.set_proxy_100_continue(true); });

initialize();
codec_client_ = makeHttpConnection(lookupPort("http"));

// Upstream responds with headers.
auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();
upstream_request_->encodeHeaders(default_response_headers_, true);

response->waitForEndStream();
ASSERT_TRUE(response->complete());
// Verify metadata added in encodeHeaders(): "headers", "duplicate" and "keep".
std::set<std::string> expected_metadata_keys = {"headers", "duplicate", "keep"};
verifyExpectedMetadata(response->metadata_map(), expected_metadata_keys);

// Upstream responds with headers and data.
response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(100, true);

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);
waitForNextUpstreamRequest();
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(10, false);
Http::TestHeaderMapImpl response_trailers{{"response", "trailer"}};
upstream_request_->encodeTrailers(response_trailers);

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"},
{":path", "/dynamo/url"},
{":scheme", "http"},
{":authority", "host"},
{"expect", "100-continue"}},
10);

waitForNextUpstreamRequest();
upstream_request_->encode100ContinueHeaders(Http::TestHeaderMapImpl{{":status", "100"}});
response->waitForContinueHeaders();
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(100, true);

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);
waitForNextUpstreamRequest();
Http::MetadataMap metadata_map = {{"aaa", "aaa"}};
Http::MetadataMapPtr metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
Http::MetadataMapVector metadata_map_vector;
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeHeaders(default_response_headers_, true);

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");
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_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
metadata_map_vector.clear();
metadata_map_vector.push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(metadata_map_vector);
upstream_request_->encodeHeaders(default_response_headers_, false);
upstream_request_->encodeData(100, true);

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) {
testEnvoyMultipleMetadataReachSizeLimit();
initialize();
codec_client_ = makeHttpConnection(lookupPort("http"));

// Sends a request.
auto response = codec_client_->makeRequestWithBody(default_request_headers_, 10);
waitForNextUpstreamRequest();

// Sends multiple metadata after response header until max size limit is reached.
upstream_request_->encodeHeaders(default_response_headers_, false);
const int size = 200;
std::vector<Http::MetadataMapVector> multiple_vecs(size);
for (int i = 0; i < size; i++) {
Http::MetadataMap metadata_map = {{"key", std::string(10000, 'a')}};
Http::MetadataMapPtr metadata_map_ptr = std::make_unique<Http::MetadataMap>(metadata_map);
multiple_vecs[i].push_back(std::move(metadata_map_ptr));
upstream_request_->encodeMetadata(multiple_vecs[i]);
}
upstream_request_->encodeData(12, true);

// Verifies reset is received.
response->waitForReset();
ASSERT_FALSE(response->complete());
}

TEST_P(Http2IntegrationTest, EnvoyHandlingDuplicate100Continue) {
Expand Down
Loading