codekingpro/portable-devtools
114k
1# Copyright The OpenTelemetry Authors2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7# http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15from logging import getLogger16from re import compile, split17from typing import Dict, List, Mapping18from urllib.parse import unquote19 20from typing_extensions import deprecated21 22_logger = getLogger(__name__)23 24# The following regexes reference this spec: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#specifying-headers-via-environment-variables25 26# Optional whitespace27_OWS = r"[ \t]*"28# A key contains printable US-ASCII characters except: SP and "(),/:;<=>?@[\]{}29_KEY_FORMAT = (30 r"[\x21\x23-\x27\x2a\x2b\x2d\x2e\x30-\x39\x41-\x5a\x5e-\x7a\x7c\x7e]+"31)32# A value contains a URL-encoded UTF-8 string. The encoded form can contain any33# printable US-ASCII characters (0x20-0x7f) other than SP, DEL, and ",;/34_VALUE_FORMAT = r"[\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*"35# Like above with SP included36_LIBERAL_VALUE_FORMAT = r"[\x20\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]*"37# A key-value is key=value, with optional whitespace surrounding key and value38_KEY_VALUE_FORMAT = rf"{_OWS}{_KEY_FORMAT}{_OWS}={_OWS}{_VALUE_FORMAT}{_OWS}"39 40_HEADER_PATTERN = compile(_KEY_VALUE_FORMAT)41_LIBERAL_HEADER_PATTERN = compile(42 rf"{_OWS}{_KEY_FORMAT}{_OWS}={_OWS}{_LIBERAL_VALUE_FORMAT}{_OWS}"43)44_DELIMITER_PATTERN = compile(r"[ \t]*,[ \t]*")45 46_BAGGAGE_PROPERTY_FORMAT = rf"{_KEY_VALUE_FORMAT}|{_OWS}{_KEY_FORMAT}{_OWS}"47 48_INVALID_HEADER_ERROR_MESSAGE_STRICT_TEMPLATE = (49 "Header format invalid! Header values in environment variables must be "50 "URL encoded per the OpenTelemetry Protocol Exporter specification: %s"51)52 53_INVALID_HEADER_ERROR_MESSAGE_LIBERAL_TEMPLATE = (54 "Header format invalid! Header values in environment variables must be "55 "URL encoded per the OpenTelemetry Protocol Exporter specification or "56 "a comma separated list of name=value occurrences: %s"57)58 59# pylint: disable=invalid-name60 61 62@deprecated(63 "You should use parse_env_headers. Deprecated since version 1.15.0."64)65def parse_headers(s: str) -> Mapping[str, str]:66 return parse_env_headers(s)67 68 69def parse_env_headers(s: str, liberal: bool = False) -> Mapping[str, str]:70 """71 Parse ``s``, which is a ``str`` instance containing HTTP headers encoded72 for use in ENV variables per the W3C Baggage HTTP header format at73 https://www.w3.org/TR/baggage/#baggage-http-header-format, except that74 additional semi-colon delimited metadata is not supported.75 If ``liberal`` is True we try to parse ``s`` anyway to be more compatible76 with other languages SDKs that accept non URL-encoded headers by default.77 """78 headers: Dict[str, str] = {}79 headers_list: List[str] = split(_DELIMITER_PATTERN, s)80 for header in headers_list:81 if not header: # empty string82 continue83 header_match = _HEADER_PATTERN.fullmatch(header.strip())84 if not header_match and not liberal:85 _logger.warning(86 _INVALID_HEADER_ERROR_MESSAGE_STRICT_TEMPLATE, header87 )88 continue89 90 if header_match:91 match_string: str = header_match.string92 # value may contain any number of `=`93 name, value = match_string.split("=", 1)94 name = unquote(name).strip().lower()95 value = unquote(value).strip()96 headers[name] = value97 else:98 # this is not url-encoded and does not match the spec but we decided to be99 # liberal in what we accept to match other languages SDKs behaviour100 liberal_header_match = _LIBERAL_HEADER_PATTERN.fullmatch(101 header.strip()102 )103 if not liberal_header_match:104 _logger.warning(105 _INVALID_HEADER_ERROR_MESSAGE_LIBERAL_TEMPLATE, header106 )107 continue108 109 liberal_match_string: str = liberal_header_match.string110 # value may contain any number of `=`111 name, value = liberal_match_string.split("=", 1)112 name = name.strip().lower()113 value = value.strip()114 headers[name] = value115 116 return headers117 