emailsec._utils
1import re 2import collections 3 4Body = bytes 5Header = tuple[bytes, bytes] 6Headers = dict[str, list[Header]] 7 8type BodyAndHeaders = tuple[Body, Headers] 9 10 11def body_and_headers_for_canonicalization(message: bytes) -> BodyAndHeaders: 12 lines = re.split(b"\r?\n", message) 13 14 headers_idx = collections.defaultdict(list) 15 headers = [] 16 for header_line in lines[: lines.index(b"")]: 17 if (m := re.match(rb"([\x21-\x7e]+?):", header_line)) is not None: 18 header_name = m.group(1) 19 header_value = header_line[m.end() :] + b"\r\n" 20 headers.append([header_name, header_value]) 21 elif header_line.startswith(b" ") or header_line.startswith(b"\t"): 22 # Unfold header values 23 headers[-1][1] += header_line + b"\r\n" 24 else: 25 raise ValueError(f"Invalid line {header_line!r}") 26 27 for header_name, header_value in headers: 28 headers_idx[header_name.decode().lower()].append((header_name, header_value)) 29 30 try: 31 # Split on the first empty line and join the remaining ones with CRLF 32 can_body = b"\r\n".join(lines[lines.index(b"") + 1 :]) 33 except ValueError: 34 # No body defaults to CRLF 35 can_body = b"\r\n" 36 37 return can_body, dict(headers_idx) 38 39 40def header_value(headers: Headers, header_name: str) -> str: 41 """Returns the first value matching the header name (case-insensitive lookup).""" 42 return headers[header_name][0][1].decode().strip()
Body =
<class 'bytes'>
Header =
tuple[bytes, bytes]
Headers =
dict[str, list[tuple[bytes, bytes]]]
type BodyAndHeaders =
tuple[bytes, dict[str, list[tuple[bytes, bytes]]]]
def
body_and_headers_for_canonicalization(message: bytes) -> BodyAndHeaders:
12def body_and_headers_for_canonicalization(message: bytes) -> BodyAndHeaders: 13 lines = re.split(b"\r?\n", message) 14 15 headers_idx = collections.defaultdict(list) 16 headers = [] 17 for header_line in lines[: lines.index(b"")]: 18 if (m := re.match(rb"([\x21-\x7e]+?):", header_line)) is not None: 19 header_name = m.group(1) 20 header_value = header_line[m.end() :] + b"\r\n" 21 headers.append([header_name, header_value]) 22 elif header_line.startswith(b" ") or header_line.startswith(b"\t"): 23 # Unfold header values 24 headers[-1][1] += header_line + b"\r\n" 25 else: 26 raise ValueError(f"Invalid line {header_line!r}") 27 28 for header_name, header_value in headers: 29 headers_idx[header_name.decode().lower()].append((header_name, header_value)) 30 31 try: 32 # Split on the first empty line and join the remaining ones with CRLF 33 can_body = b"\r\n".join(lines[lines.index(b"") + 1 :]) 34 except ValueError: 35 # No body defaults to CRLF 36 can_body = b"\r\n" 37 38 return can_body, dict(headers_idx)
def
header_value(headers: dict[str, list[tuple[bytes, bytes]]], header_name: str) -> str:
41def header_value(headers: Headers, header_name: str) -> str: 42 """Returns the first value matching the header name (case-insensitive lookup).""" 43 return headers[header_name][0][1].decode().strip()
Returns the first value matching the header name (case-insensitive lookup).