codekingpro/portable-devtools
114k
1from __future__ import annotations2 3import mimetypes4import re5import warnings6from urllib.parse import quote7 8from mitmproxy.net.http import headers9 10 11def encode_multipart(content_type: str, parts: list[tuple[bytes, bytes]]) -> bytes:12 if content_type:13 ct = headers.parse_content_type(content_type)14 if ct is not None:15 try:16 raw_boundary = ct[2]["boundary"].encode("ascii")17 boundary = quote(raw_boundary)18 except (KeyError, UnicodeError):19 return b""20 hdrs = []21 for key, value in parts:22 file_type = (23 mimetypes.guess_type(str(key))[0] or "text/plain; charset=utf-8"24 )25 26 if key:27 hdrs.append(b"--%b" % boundary.encode("utf-8"))28 disposition = b'form-data; name="%b"' % key29 hdrs.append(b"Content-Disposition: %b" % disposition)30 hdrs.append(b"Content-Type: %b" % file_type.encode("utf-8"))31 hdrs.append(b"")32 hdrs.append(value)33 hdrs.append(b"")34 35 if value is not None:36 # If boundary is found in value then raise ValueError37 if re.search(38 rb"^--%b$" % re.escape(boundary.encode("utf-8")), value39 ):40 raise ValueError(b"boundary found in encoded string")41 42 hdrs.append(b"--%b--\r\n" % boundary.encode("utf-8"))43 temp = b"\r\n".join(hdrs)44 return temp45 return b""46 47 48def decode_multipart(49 content_type: str | None, content: bytes50) -> list[tuple[bytes, bytes]]:51 """52 Takes a multipart boundary encoded string and returns list of (key, value) tuples.53 """54 if content_type:55 ct = headers.parse_content_type(content_type)56 if not ct:57 return []58 try:59 boundary = ct[2]["boundary"].encode("ascii")60 except (KeyError, UnicodeError):61 return []62 63 rx = re.compile(rb'\bname="([^"]+)"')64 r = []65 if content is not None:66 for i in content.split(b"--" + boundary):67 parts = i.splitlines()68 if len(parts) > 1 and parts[0][0:2] != b"--":69 match = rx.search(parts[1])70 if match:71 key = match.group(1)72 value = b"".join(parts[3 + parts[2:].index(b"") :])73 r.append((key, value))74 return r75 return []76 77 78def encode(ct, parts): # pragma: no cover79 # 2023-0280 warnings.warn(81 "multipart.encode is deprecated, use multipart.encode_multipart instead.",82 DeprecationWarning,83 stacklevel=2,84 )85 return encode_multipart(ct, parts)86 87 88def decode(ct, content): # pragma: no cover89 # 2023-0290 warnings.warn(91 "multipart.decode is deprecated, use multipart.decode_multipart instead.",92 DeprecationWarning,93 stacklevel=2,94 )95 return encode_multipart(ct, content)96 