From e5c2e251442fa5071cb16b446ce4f91131662a3c Mon Sep 17 00:00:00 2001 From: Johannes Tax Date: Thu, 7 Mar 2024 16:16:16 +0100 Subject: [PATCH] Support URL-encoded values for `OTEL_EXPORTER_OTLP_HEADERS` (#2579) --- CHANGELOG.md | 2 + exporters/otlp/src/otlp_grpc_client.cc | 3 +- exporters/otlp/src/otlp_http_client.cc | 3 +- .../ext/http/common/url_parser.h | 44 +++++++++++++++++++ ext/test/http/url_parser_test.cc | 18 ++++++++ 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 719def9844..ccb629074e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ Increment the: * [EXPORTER] Gzip compression support for OTLP/HTTP and OTLP/gRPC exporter [#2530](https://github.com/open-telemetry/opentelemetry-cpp/pull/2530) +* [EXPORTER] Support URL-encoded values for `OTEL_EXPORTER_OTLP_HEADERS` + [#2579](https://github.com/open-telemetry/opentelemetry-cpp/pull/2579) Important changes: diff --git a/exporters/otlp/src/otlp_grpc_client.cc b/exporters/otlp/src/otlp_grpc_client.cc index f57e476955..90bbd41938 100644 --- a/exporters/otlp/src/otlp_grpc_client.cc +++ b/exporters/otlp/src/otlp_grpc_client.cc @@ -342,7 +342,8 @@ std::unique_ptr OtlpGrpcClient::MakeClientContext( for (auto &header : options.metadata) { - context->AddMetadata(header.first, header.second); + context->AddMetadata(header.first, + opentelemetry::ext::http::common::UrlDecoder::Decode(header.second)); } return context; diff --git a/exporters/otlp/src/otlp_http_client.cc b/exporters/otlp/src/otlp_http_client.cc index 151873c221..4b4a92c2b0 100644 --- a/exporters/otlp/src/otlp_http_client.cc +++ b/exporters/otlp/src/otlp_http_client.cc @@ -948,7 +948,8 @@ OtlpHttpClient::createSession( for (auto &header : options_.http_headers) { - request->AddHeader(header.first, header.second); + request->AddHeader(header.first, + opentelemetry::ext::http::common::UrlDecoder::Decode(header.second)); } request->SetUri(http_uri_); request->SetSslOptions(options_.ssl_options); diff --git a/ext/include/opentelemetry/ext/http/common/url_parser.h b/ext/include/opentelemetry/ext/http/common/url_parser.h index 31da004003..5e18d85bb6 100644 --- a/ext/include/opentelemetry/ext/http/common/url_parser.h +++ b/ext/include/opentelemetry/ext/http/common/url_parser.h @@ -131,6 +131,50 @@ class UrlParser } }; +class UrlDecoder +{ +public: + static std::string Decode(const std::string &encoded) + { + std::string result; + result.reserve(encoded.size()); + + for (size_t pos = 0; pos < encoded.size(); pos++) + { + if (encoded[pos] == '%') + { + + // Invalid input: less than two characters left after '%' + if (encoded.size() < pos + 3) + { + return encoded; + } + + char hex[3] = {0}; + hex[0] = encoded[++pos]; + hex[1] = encoded[++pos]; + + char *endptr; + long value = strtol(hex, &endptr, 16); + + // Invalid input: no valid hex characters after '%' + if (endptr != &hex[2]) + { + return encoded; + } + + result.push_back(static_cast(value)); + } + else + { + result.push_back(encoded[pos]); + } + } + + return result; + } +}; + } // namespace common } // namespace http diff --git a/ext/test/http/url_parser_test.cc b/ext/test/http/url_parser_test.cc index e205ff6ef7..212c5655a7 100644 --- a/ext/test/http/url_parser_test.cc +++ b/ext/test/http/url_parser_test.cc @@ -134,3 +134,21 @@ TEST(UrlParserTests, BasicTests) ASSERT_EQ(url.query_, url_properties["query"]); } } + +TEST(UrlDecoderTests, BasicTests) +{ + std::map testdata{ + {"Authentication=Basic xxx", "Authentication=Basic xxx"}, + {"Authentication=Basic%20xxx", "Authentication=Basic xxx"}, + {"%C3%B6%C3%A0%C2%A7%C3%96abcd%C3%84", "öà§ÖabcdÄ"}, + {"%2x", "%2x"}, + {"%20", " "}, + {"text%2", "text%2"}, + }; + + for (auto &testsample : testdata) + { + ASSERT_EQ(http_common::UrlDecoder::Decode(testsample.first), testsample.second); + ASSERT_TRUE(http_common::UrlDecoder::Decode(testsample.first) == testsample.second); + } +}