codekingpro/portable-devtools
115k
1import re2from collections.abc import Sequence3from typing import NamedTuple4 5from mitmproxy import ctx6from mitmproxy import exceptions7from mitmproxy import flowfilter8from mitmproxy import http9from mitmproxy.utils.spec import parse_spec10 11 12class MapRemoteSpec(NamedTuple):13 matches: flowfilter.TFilter14 subject: str15 replacement: str16 17 18def parse_map_remote_spec(option: str) -> MapRemoteSpec:19 spec = MapRemoteSpec(*parse_spec(option))20 21 try:22 re.compile(spec.subject)23 except re.error as e:24 raise ValueError(f"Invalid regular expression {spec.subject!r} ({e})")25 26 return spec27 28 29class MapRemote:30 def __init__(self) -> None:31 self.replacements: list[MapRemoteSpec] = []32 33 def load(self, loader):34 loader.add_option(35 "map_remote",36 Sequence[str],37 [],38 """39 Map remote resources to another remote URL using a pattern of the form40 "[/flow-filter]/url-regex/replacement", where the separator can41 be any character.42 """,43 )44 45 def configure(self, updated):46 if "map_remote" in updated:47 self.replacements = []48 for option in ctx.options.map_remote:49 try:50 spec = parse_map_remote_spec(option)51 except ValueError as e:52 raise exceptions.OptionsError(53 f"Cannot parse map_remote option {option}: {e}"54 ) from e55 56 self.replacements.append(spec)57 58 def request(self, flow: http.HTTPFlow) -> None:59 if flow.response or flow.error or not flow.live:60 return61 for spec in self.replacements:62 if spec.matches(flow):63 url = flow.request.pretty_url64 new_url = re.sub(spec.subject, spec.replacement, url)65 # this is a bit messy: setting .url also updates the host header,66 # so we really only do that if the replacement affected the URL.67 if url != new_url:68 flow.request.url = new_url # type: ignore69 