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

Do not crash when converting YAML to JSON fails #4110

Merged
merged 7 commits into from
Aug 12, 2018
Merged

Do not crash when converting YAML to JSON fails #4110

merged 7 commits into from
Aug 12, 2018

Conversation

dio
Copy link
Member

@dio dio commented Aug 10, 2018

Description: Do not crash when converting YAML to JSON fails.
Risk Level: Low
Testing: Added
Docs Changes: N/A
Release Notes: N/A
Fixes #3990

Signed-off-by: Dhi Aurrahman dio@tetrate.io

Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks for fixing.

@@ -253,6 +253,13 @@ TEST(UtilityTest, JsonConvertCamelSnake) {
.string_value());
}

TEST(UtilityTest, YamlLoadFromStringFail) {
envoy::config::bootstrap::v2::Bootstrap bootstrap;
EXPECT_THROW_WITH_MESSAGE(MessageUtil::loadFromYaml("/home/configs/config.yaml", bootstrap),
Copy link
Member

Choose a reason for hiding this comment

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

I don't think this path is available in CI? Is it possible to do a more direct test case of the actual issue potentially not even loading from a file?

Copy link
Member Author

@dio dio Aug 10, 2018

Choose a reason for hiding this comment

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

This simulates what is described in the issue #3990, that gave input to --config-yaml a file path string (while this config option expects a valid yaml string instead). #3990 (comment)

This doesn't try to load a file. The --config-yaml perceives this as a string (in this case the string value is a file path).

Copy link
Member

Choose a reason for hiding this comment

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

Ah I see. Got it.

Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
mattklein123
mattklein123 previously approved these changes Aug 10, 2018
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Awesome, thank you!

@dio
Copy link
Member Author

dio commented Aug 10, 2018

I'm fixing the approach...

Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
@dio
Copy link
Member Author

dio commented Aug 11, 2018

It seems fine now. I deferred the checking until at the protobuf util.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks, so what was wrong with the previous approach for reference?

@@ -58,8 +58,14 @@ void MessageUtil::loadFromJson(const std::string& json, Protobuf::Message& messa
}

void MessageUtil::loadFromYaml(const std::string& yaml, Protobuf::Message& message) {
const std::string json = Json::Factory::loadFromYamlString(yaml)->asJsonString();
loadFromJson(json, message);
const auto& loaded_object = Json::Factory::loadFromYamlString(yaml);
Copy link
Member

Choose a reason for hiding this comment

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

nit: technically this should not be a reference so I would remove &.

const std::string json = Json::Factory::loadFromYamlString(yaml)->asJsonString();
loadFromJson(json, message);
const auto& loaded_object = Json::Factory::loadFromYamlString(yaml);
// Load to the message if the loaded object has type Object or Array.
Copy link
Member

Choose a reason for hiding this comment

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

s/to the/the

@mattklein123 mattklein123 self-assigned this Aug 11, 2018
Signed-off-by: Dhi Aurrahman <dio@tetrate.io>
@dio
Copy link
Member Author

dio commented Aug 11, 2018

The previous attempt failed to pass the following unit tests,

[  FAILED  ] JsonLoaderTest.YamlScalar
[  FAILED  ] JsonLoaderTest.YamlObject
[  FAILED  ] JsonLoaderTest.YamlAsJsonString
[  FAILED  ] JsonLoaderTest.BadYamlException

TEST(JsonLoaderTest, YamlScalar) {
EXPECT_EQ(true, Factory::loadFromYamlString("true")->asBoolean());
EXPECT_EQ("true", Factory::loadFromYamlString("\"true\"")->asString());
EXPECT_EQ(1, Factory::loadFromYamlString("1")->asInteger());
EXPECT_EQ("1", Factory::loadFromYamlString("\"1\"")->asString());
EXPECT_DOUBLE_EQ(1.0, Factory::loadFromYamlString("1.0")->asDouble());
EXPECT_EQ("1.0", Factory::loadFromYamlString("\"1.0\"")->asString());
}
TEST(JsonLoaderTest, YamlObject) {
{
const Json::ObjectSharedPtr json = Json::Factory::loadFromYamlString("[foo, bar]");
std::vector<Json::ObjectSharedPtr> output = json->asObjectArray();
EXPECT_EQ(2, output.size());
EXPECT_EQ("foo", output[0]->asString());
EXPECT_EQ("bar", output[1]->asString());
}
{
const Json::ObjectSharedPtr json = Json::Factory::loadFromYamlString("foo: bar");
EXPECT_EQ("bar", json->getString("foo"));
}
{
const Json::ObjectSharedPtr json = Json::Factory::loadFromYamlString("Null");
EXPECT_TRUE(json->isNull());
}
}
TEST(JsonLoaderTest, YamlAsJsonString) {
const Json::ObjectSharedPtr json = Json::Factory::loadFromYamlString("");
EXPECT_EQ(json->asJsonString(), "null");
}
TEST(JsonLoaderTest, BadYamlException) {
std::string bad_yaml = R"EOF(
admin:
access_log_path: /dev/null
address:
socket_address:
address: {{ ntop_ip_loopback_address }}
port_value: 0
)EOF";
EXPECT_THROW_WITH_REGEX(Json::Factory::loadFromYamlString(bad_yaml), EnvoyException,
"bad conversion");
EXPECT_THROW_WITHOUT_REGEX(Json::Factory::loadFromYamlString(bad_yaml), EnvoyException,
"Unexpected YAML exception");
}

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks, LGTM. It would be good if @htuch could take a quick look since he is more familiar w/ the YAML parsing code.

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

LGTM, thanks.

loadFromJson(json, message);
const auto loaded_object = Json::Factory::loadFromYamlString(yaml);
// Load the message if the loaded object has type Object or Array.
if (loaded_object->isObject() || loaded_object->isArray()) {
Copy link
Member

Choose a reason for hiding this comment

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

I guess this works because 100% of the time we use loadFromYaml it's for non-trivial compound types.

@htuch htuch merged commit 1381673 into envoyproxy:master Aug 12, 2018
snowp added a commit to snowp/envoy that referenced this pull request Aug 14, 2018
* origin/master: (38 commits)
  test: add tests for corner-cases around sending requests before run() starts or after run() ends. (envoyproxy#4114)
  perf: reduce the memory usage of LC Trie construction (envoyproxy#4117)
  test: moving redundant code in websocket_integration_test to utilities (envoyproxy#4127)
  test: make YamlLoadFromStringFail less picky about error msg. (envoyproxy#4141)
  rbac: add rbac network filter. (envoyproxy#4083)
  fuzz: route lookup and header finalization fuzzer. (envoyproxy#4116)
  Set content-type and content-length (envoyproxy#4113)
  fault: use FractionalPercent for percent (envoyproxy#3978)
  test: Fix inverted exact match logic in IntegrationTcpClient::waitForData() (envoyproxy#4134)
  Added cluster_name to load assignment config for static cluster (envoyproxy#4123)
  ssl: refactor ContextConfig to use TlsCertificateConfig (envoyproxy#4115)
  syscall: refactor OsSysCalls for deeper errno latching (envoyproxy#4111)
  thrift_proxy: fix oneway bugs (envoyproxy#4025)
  Do not crash when converting YAML to JSON fails (envoyproxy#4110)
  config: allow unknown fields flag (take 2) (envoyproxy#4096)
  Use a jittered backoff strategy for handling HdsDelegate stream/connection failures (envoyproxy#4108)
  bazel: use GCS remote cache (envoyproxy#4050)
  Add thread local cache of overload action states (envoyproxy#4090)
  Added TCP healthcheck capabilities to the HdsDelegate (envoyproxy#4079)
  secret: add secret provider interface and use it for TlsCertificates (envoyproxy#4086)
  ...

Signed-off-by: Snow Pettersen <snowp@squareup.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants