Skip to content

Commit e5c2e25

Browse files
authored
Support URL-encoded values for OTEL_EXPORTER_OTLP_HEADERS (#2579)
1 parent 14f7542 commit e5c2e25

File tree

5 files changed

+68
-2
lines changed

5 files changed

+68
-2
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Increment the:
1717

1818
* [EXPORTER] Gzip compression support for OTLP/HTTP and OTLP/gRPC exporter
1919
[#2530](https://github.com/open-telemetry/opentelemetry-cpp/pull/2530)
20+
* [EXPORTER] Support URL-encoded values for `OTEL_EXPORTER_OTLP_HEADERS`
21+
[#2579](https://github.com/open-telemetry/opentelemetry-cpp/pull/2579)
2022

2123
Important changes:
2224

exporters/otlp/src/otlp_grpc_client.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@ std::unique_ptr<grpc::ClientContext> OtlpGrpcClient::MakeClientContext(
342342

343343
for (auto &header : options.metadata)
344344
{
345-
context->AddMetadata(header.first, header.second);
345+
context->AddMetadata(header.first,
346+
opentelemetry::ext::http::common::UrlDecoder::Decode(header.second));
346347
}
347348

348349
return context;

exporters/otlp/src/otlp_http_client.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,8 @@ OtlpHttpClient::createSession(
948948

949949
for (auto &header : options_.http_headers)
950950
{
951-
request->AddHeader(header.first, header.second);
951+
request->AddHeader(header.first,
952+
opentelemetry::ext::http::common::UrlDecoder::Decode(header.second));
952953
}
953954
request->SetUri(http_uri_);
954955
request->SetSslOptions(options_.ssl_options);

ext/include/opentelemetry/ext/http/common/url_parser.h

+44
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,50 @@ class UrlParser
131131
}
132132
};
133133

134+
class UrlDecoder
135+
{
136+
public:
137+
static std::string Decode(const std::string &encoded)
138+
{
139+
std::string result;
140+
result.reserve(encoded.size());
141+
142+
for (size_t pos = 0; pos < encoded.size(); pos++)
143+
{
144+
if (encoded[pos] == '%')
145+
{
146+
147+
// Invalid input: less than two characters left after '%'
148+
if (encoded.size() < pos + 3)
149+
{
150+
return encoded;
151+
}
152+
153+
char hex[3] = {0};
154+
hex[0] = encoded[++pos];
155+
hex[1] = encoded[++pos];
156+
157+
char *endptr;
158+
long value = strtol(hex, &endptr, 16);
159+
160+
// Invalid input: no valid hex characters after '%'
161+
if (endptr != &hex[2])
162+
{
163+
return encoded;
164+
}
165+
166+
result.push_back(static_cast<char>(value));
167+
}
168+
else
169+
{
170+
result.push_back(encoded[pos]);
171+
}
172+
}
173+
174+
return result;
175+
}
176+
};
177+
134178
} // namespace common
135179

136180
} // namespace http

ext/test/http/url_parser_test.cc

+18
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,21 @@ TEST(UrlParserTests, BasicTests)
134134
ASSERT_EQ(url.query_, url_properties["query"]);
135135
}
136136
}
137+
138+
TEST(UrlDecoderTests, BasicTests)
139+
{
140+
std::map<std::string, std::string> testdata{
141+
{"Authentication=Basic xxx", "Authentication=Basic xxx"},
142+
{"Authentication=Basic%20xxx", "Authentication=Basic xxx"},
143+
{"%C3%B6%C3%A0%C2%A7%C3%96abcd%C3%84", "öà§ÖabcdÄ"},
144+
{"%2x", "%2x"},
145+
{"%20", " "},
146+
{"text%2", "text%2"},
147+
};
148+
149+
for (auto &testsample : testdata)
150+
{
151+
ASSERT_EQ(http_common::UrlDecoder::Decode(testsample.first), testsample.second);
152+
ASSERT_TRUE(http_common::UrlDecoder::Decode(testsample.first) == testsample.second);
153+
}
154+
}

0 commit comments

Comments
 (0)