Skip to content
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

api: relax inline_string length limitation in DataSource #14461

Merged
merged 2 commits into from
Dec 19, 2020
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
4 changes: 2 additions & 2 deletions api/envoy/config/core/v3/base.proto
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,10 @@ message DataSource {
string filename = 1 [(validate.rules).string = {min_len: 1}];

// Bytes inlined in the configuration.
bytes inline_bytes = 2 [(validate.rules).bytes = {min_len: 1}];
bytes inline_bytes = 2;

// String inlined in the configuration.
string inline_string = 3 [(validate.rules).string = {min_len: 1}];
string inline_string = 3;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also relax on inline_bytes?

}
}

Expand Down
4 changes: 2 additions & 2 deletions api/envoy/config/core/v4alpha/base.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions generated_api_shadow/envoy/config/core/v3/base.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions generated_api_shadow/envoy/config/core/v4alpha/base.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions source/common/config/datasource.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,27 @@ static constexpr uint32_t RetryCount = 1;

std::string read(const envoy::config::core::v3::DataSource& source, bool allow_empty,
Api::Api& api) {
std::string data;
switch (source.specifier_case()) {
case envoy::config::core::v3::DataSource::SpecifierCase::kFilename:
return api.fileSystem().fileReadToEnd(source.filename());
data = api.fileSystem().fileReadToEnd(source.filename());
break;
case envoy::config::core::v3::DataSource::SpecifierCase::kInlineBytes:
return source.inline_bytes();
data = source.inline_bytes();
break;
case envoy::config::core::v3::DataSource::SpecifierCase::kInlineString:
return source.inline_string();
data = source.inline_string();
break;
default:
if (!allow_empty) {
throw EnvoyException(
fmt::format("Unexpected DataSource::specifier_case(): {}", source.specifier_case()));
}
return "";
}
if (!allow_empty && data.empty()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this start enforcing allow_empty on the kFilename case where it didn't previously?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and this is intended in that way. I took quick look on existing use and mostly are allowing empty so this shouldn't be a big issue.

throw EnvoyException("DataSource cannot be empty");
}
return data;
}

absl::optional<std::string> getPath(const envoy::config::core::v3::DataSource& source) {
Expand Down
30 changes: 30 additions & 0 deletions test/common/config/datasource_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,36 @@ TEST_F(AsyncDataSourceTest, LoadLocalDataSource) {
EXPECT_EQ(async_data, "xxxxxx");
}

TEST_F(AsyncDataSourceTest, LoadLocalEmptyDataSource) {
AsyncDataSourcePb config;

std::string yaml = R"EOF(
local:
inline_string: ""
)EOF";
TestUtility::loadFromYamlAndValidate(yaml, config);
EXPECT_TRUE(config.has_local());

std::string async_data;

EXPECT_CALL(init_manager_, add(_)).WillOnce(Invoke([this](const Init::Target& target) {
init_target_handle_ = target.createHandle("test");
}));

local_data_provider_ = std::make_unique<Config::DataSource::LocalAsyncDataProvider>(
init_manager_, config.local(), true, *api_, [&](const std::string& data) {
EXPECT_EQ(init_manager_.state(), Init::Manager::State::Initializing);
EXPECT_EQ(data, "");
async_data = data;
});

EXPECT_CALL(init_manager_, state()).WillOnce(Return(Init::Manager::State::Initializing));
EXPECT_CALL(init_watcher_, ready());

init_target_handle_->initialize(init_watcher_);
EXPECT_EQ(async_data, "");
}

TEST_F(AsyncDataSourceTest, LoadRemoteDataSourceNoCluster) {
AsyncDataSourcePb config;

Expand Down
55 changes: 55 additions & 0 deletions test/integration/local_reply_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -411,4 +411,59 @@ TEST_P(LocalReplyIntegrationTest, ShouldFormatResponseToCustomString) {
EXPECT_EQ(response->body(), "513 - customized body text");
}

// Should return formatted text/plain response.
TEST_P(LocalReplyIntegrationTest, ShouldFormatResponseToEmptyBody) {
const std::string yaml = R"EOF(
mappers:
- filter:
status_code_filter:
comparison:
op: EQ
value:
default_value: 503
runtime_key: key_b
status_code: 513
body:
inline_string: ""
body_format:
text_format_source:
inline_string: ""
)EOF";
setLocalReplyConfig(yaml);
initialize();

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

auto encoder_decoder = codec_client_->startRequest(
Http::TestRequestHeaderMapImpl{{":method", "POST"},
{":path", "/test/long/url"},
{":scheme", "http"},
{":authority", "host"},
{"test-header", "exact-match-value-2"}});
auto response = std::move(encoder_decoder.second);

ASSERT_TRUE(fake_upstreams_[0]->waitForHttpConnection(*dispatcher_, fake_upstream_connection_));

ASSERT_TRUE(fake_upstream_connection_->waitForNewStream(*dispatcher_, upstream_request_));
ASSERT_TRUE(upstream_request_->waitForHeadersComplete());
ASSERT_TRUE(fake_upstream_connection_->close());
ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect());
response->waitForEndStream();

if (downstream_protocol_ == Http::CodecClient::Type::HTTP1) {
ASSERT_TRUE(codec_client_->waitForDisconnect());
} else {
codec_client_->close();
}

EXPECT_FALSE(upstream_request_->complete());
EXPECT_EQ(0U, upstream_request_->bodyLength());

EXPECT_TRUE(response->complete());

EXPECT_EQ("513", response->headers().Status()->value().getStringView());

EXPECT_EQ(response->body(), "");
}

} // namespace Envoy