chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
Utility functions shared across the library.
|
||||
Small helpers that don't belong in any one module.
|
||||
"""
|
||||
import re
|
||||
from models import Cookies
|
||||
|
||||
|
||||
SENSITIVE_HEADERS = {"authorization", "cookie", "set-cookie", "proxy-authorization"}
|
||||
|
||||
|
||||
def primitive_value_to_str(value) -> str:
|
||||
"""Convert a primitive value to its string representation."""
|
||||
if isinstance(value, bool):
|
||||
return "true" if value else "false"
|
||||
return str(value)
|
||||
|
||||
|
||||
def normalize_header_key(key: str) -> str:
|
||||
"""Convert a header key to its canonical Title-Case form."""
|
||||
return "-".join(word.capitalize() for word in key.split("-"))
|
||||
|
||||
|
||||
def flatten_queryparams(params: dict) -> list:
|
||||
"""
|
||||
Expand a params dict into a flat list of (key, value) pairs.
|
||||
List values become multiple pairs with the same key.
|
||||
"""
|
||||
result = []
|
||||
for key, value in params.items():
|
||||
if isinstance(value, list):
|
||||
for item in value:
|
||||
result.append((key, primitive_value_to_str(item)))
|
||||
else:
|
||||
result.append((key, primitive_value_to_str(value)))
|
||||
return result
|
||||
|
||||
|
||||
def parse_content_type(content_type: str) -> tuple:
|
||||
"""
|
||||
Parse a Content-Type header value.
|
||||
Returns (media_type, params_dict).
|
||||
Example: 'application/json; charset=utf-8' -> ('application/json', {'charset': 'utf-8'})
|
||||
"""
|
||||
parts = [p.strip() for p in content_type.split(";")]
|
||||
media_type = parts[0]
|
||||
params = {}
|
||||
for part in parts[1:]:
|
||||
if "=" in part:
|
||||
key, _, value = part.partition("=")
|
||||
params[key.strip()] = value.strip()
|
||||
return media_type, params
|
||||
|
||||
|
||||
def obfuscate_sensitive_headers(headers: dict) -> dict:
|
||||
"""Return a copy of headers with sensitive values replaced by [obfuscated]."""
|
||||
return {
|
||||
k: "[obfuscated]" if k.lower() in SENSITIVE_HEADERS else v
|
||||
for k, v in headers.items()
|
||||
}
|
||||
|
||||
|
||||
def unset_all_cookies(cookies: Cookies) -> None:
|
||||
"""Clear all cookies from a cookie jar in place."""
|
||||
cookies.clear()
|
||||
|
||||
|
||||
def is_known_encoding(encoding: str) -> bool:
|
||||
"""Check if a character encoding label is recognized by Python's codec system."""
|
||||
import codecs
|
||||
try:
|
||||
codecs.lookup(encoding)
|
||||
return True
|
||||
except LookupError:
|
||||
return False
|
||||
|
||||
|
||||
def build_url_with_params(base_url: str, params: dict) -> str:
|
||||
"""Append query parameters to a URL string."""
|
||||
if not params:
|
||||
return base_url
|
||||
pairs = flatten_queryparams(params)
|
||||
query = "&".join(f"{k}={v}" for k, v in pairs)
|
||||
separator = "&" if "?" in base_url else "?"
|
||||
return f"{base_url}{separator}{query}"
|
||||
Reference in New Issue
Block a user