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

Decode URL-encoded headers in environment vars #2312

Merged
merged 10 commits into from
Jan 4, 2022
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2253](https://github.com/open-telemetry/opentelemetry-python/pull/2253))
- Rename ConsoleExporter to ConsoleLogExporter
([#2307](https://github.com/open-telemetry/opentelemetry-python/pull/2307))
- Decode URL-encoded headers in environment variables
([#2312](https://github.com/open-telemetry/opentelemetry-python/pull/2312))

## [1.7.1-0.26b1](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.7.0-0.26b0) - 2021-11-11

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from collections.abc import Sequence
from os import environ
from time import sleep
from typing import Any, Callable, Dict, Generic, List, Optional
from typing import Any, Callable, Dict, Generic, List, Optional, Tuple, Union
from typing import Sequence as TypingSequence
from typing import TypeVar
from urllib.parse import urlparse
Expand Down Expand Up @@ -204,7 +204,9 @@ def __init__(
endpoint: Optional[str] = None,
insecure: Optional[bool] = None,
credentials: Optional[ChannelCredentials] = None,
headers: Optional[Sequence] = None,
headers: Union[
mattoberle marked this conversation as resolved.
Show resolved Hide resolved
TypingSequence[Tuple[str, str]], Dict[str, str], None
lzchen marked this conversation as resolved.
Show resolved Hide resolved
] = None,
timeout: Optional[int] = None,
compression: Optional[Compression] = None,
):
Expand All @@ -229,6 +231,8 @@ def __init__(
if isinstance(self._headers, str):
temp_headers = parse_headers(self._headers)
self._headers = tuple(temp_headers.items())
elif isinstance(self._headers, dict):
self._headers = tuple(self._headers.items())

self._timeout = timeout or int(
environ.get(OTEL_EXPORTER_OTLP_TIMEOUT, 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ def test_otlp_headers_from_env(self, mock_ssl_channel, mock_secure):
self.assertEqual(
exporter._headers, (("key3", "value3"), ("key4", "value4"))
)
exporter = OTLPSpanExporter(
headers={"key5": "value5", "key6": "value6"}
)
# pylint: disable=protected-access
self.assertEqual(
exporter._headers, (("key5", "value5"), ("key6", "value6"))
)

# pylint: disable=no-self-use
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel")
Expand Down
5 changes: 3 additions & 2 deletions opentelemetry-api/src/opentelemetry/util/re.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import logging
from re import compile, split
from typing import Mapping
from urllib.parse import unquote

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -51,8 +52,8 @@ def parse_headers(s: str) -> Mapping[str, str]:
continue
# value may contain any number of `=`
name, value = match.string.split("=", 1)
name = name.strip().lower()
value = value.strip()
name = unquote(name).strip().lower()
lzchen marked this conversation as resolved.
Show resolved Hide resolved
value = unquote(value).strip()
headers[name] = value

return headers
6 changes: 6 additions & 0 deletions opentelemetry-api/tests/util/test_re.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ def test_parse_headers(self):
# different header values
("name=", [("name", "")], False),
("name===value=", [("name", "==value=")], False),
# url-encoded headers
("key=value%20with%20space", [("key", "value with space")], False),
("key%21=value", [("key!", "value")], False),
("%20key%20=%20value%20", [("key", "value")], False),
# header name case normalization
("Key=Value", [("key", "Value")], False),
# mix of valid and invalid headers
(
"name1=value1,invalidName, name2 = value2 , name3=value3==",
Expand Down