Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d8bebdd

Browse files
authored
Decode URL-encoded headers in environment vars (open-telemetry#2312)
1 parent 438d837 commit d8bebdd

File tree

5 files changed

+25
-4
lines changed

5 files changed

+25
-4
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v1.8.0-0.27b0...HEAD)
88

9+
- Decode URL-encoded headers in environment variables
10+
([#2312](https://github.com/open-telemetry/opentelemetry-python/pull/2312))
11+
912
## [1.8.0-0.27b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.8.0-0.27b0) - 2021-12-17
1013

1114
- Adds Aggregation and instruments as part of Metrics SDK

exporter/opentelemetry-exporter-otlp-proto-grpc/src/opentelemetry/exporter/otlp/proto/grpc/exporter.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from collections.abc import Sequence
2020
from os import environ
2121
from time import sleep
22-
from typing import Any, Callable, Dict, Generic, List, Optional
22+
from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, Union
2323
from typing import Sequence as TypingSequence
2424
from typing import TypeVar
2525
from urllib.parse import urlparse
@@ -204,7 +204,9 @@ def __init__(
204204
endpoint: Optional[str] = None,
205205
insecure: Optional[bool] = None,
206206
credentials: Optional[ChannelCredentials] = None,
207-
headers: Optional[Sequence] = None,
207+
headers: Optional[
208+
Union[TypingSequence[Tuple[str, str]], Dict[str, str], str]
209+
] = None,
208210
timeout: Optional[int] = None,
209211
compression: Optional[Compression] = None,
210212
):
@@ -229,6 +231,8 @@ def __init__(
229231
if isinstance(self._headers, str):
230232
temp_headers = parse_headers(self._headers)
231233
self._headers = tuple(temp_headers.items())
234+
elif isinstance(self._headers, dict):
235+
self._headers = tuple(self._headers.items())
232236

233237
self._timeout = timeout or int(
234238
environ.get(OTEL_EXPORTER_OTLP_TIMEOUT, 10)

exporter/opentelemetry-exporter-otlp-proto-grpc/tests/test_otlp_trace_exporter.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ def test_otlp_headers_from_env(self, mock_ssl_channel, mock_secure):
281281
self.assertEqual(
282282
exporter._headers, (("key3", "value3"), ("key4", "value4"))
283283
)
284+
exporter = OTLPSpanExporter(
285+
headers={"key5": "value5", "key6": "value6"}
286+
)
287+
# pylint: disable=protected-access
288+
self.assertEqual(
289+
exporter._headers, (("key5", "value5"), ("key6", "value6"))
290+
)
284291

285292
# pylint: disable=no-self-use
286293
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel")

opentelemetry-api/src/opentelemetry/util/re.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import logging
1616
from re import compile, split
1717
from typing import Mapping
18+
from urllib.parse import unquote
1819

1920
_logger = logging.getLogger(__name__)
2021

@@ -51,8 +52,8 @@ def parse_headers(s: str) -> Mapping[str, str]:
5152
continue
5253
# value may contain any number of `=`
5354
name, value = match.string.split("=", 1)
54-
name = name.strip().lower()
55-
value = value.strip()
55+
name = unquote(name).strip().lower()
56+
value = unquote(value).strip()
5657
headers[name] = value
5758

5859
return headers

opentelemetry-api/tests/util/test_re.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ def test_parse_headers(self):
3434
# different header values
3535
("name=", [("name", "")], False),
3636
("name===value=", [("name", "==value=")], False),
37+
# url-encoded headers
38+
("key=value%20with%20space", [("key", "value with space")], False),
39+
("key%21=value", [("key!", "value")], False),
40+
("%20key%20=%20value%20", [("key", "value")], False),
41+
# header name case normalization
42+
("Key=Value", [("key", "Value")], False),
3743
# mix of valid and invalid headers
3844
(
3945
"name1=value1,invalidName, name2 = value2 , name3=value3==",

0 commit comments

Comments
 (0)