mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-30 03:14:22 +00:00
Command-line options for header setting.
This commit is contained in:
parent
3e96015e61
commit
1b7990897e
@ -17,9 +17,28 @@ import proxy
|
|||||||
import re, filt
|
import re, filt
|
||||||
|
|
||||||
|
|
||||||
class ParseReplaceException(Exception): pass
|
class ParseException(Exception): pass
|
||||||
class OptionException(Exception): pass
|
class OptionException(Exception): pass
|
||||||
|
|
||||||
|
def _parse_hook(s):
|
||||||
|
sep, rem = s[0], s[1:]
|
||||||
|
parts = rem.split(sep, 2)
|
||||||
|
if len(parts) == 2:
|
||||||
|
patt = ".*"
|
||||||
|
a, b = parts
|
||||||
|
elif len(parts) == 3:
|
||||||
|
patt, a, b = parts
|
||||||
|
else:
|
||||||
|
raise ParseException("Malformed hook specifier - too few clauses: %s"%s)
|
||||||
|
|
||||||
|
if not a:
|
||||||
|
raise ParseException("Empty clause: %s"%str(patt))
|
||||||
|
|
||||||
|
if not filt.parse(patt):
|
||||||
|
raise ParseException("Malformed filter pattern: %s"%patt)
|
||||||
|
|
||||||
|
return patt, a, b
|
||||||
|
|
||||||
|
|
||||||
def parse_replace_hook(s):
|
def parse_replace_hook(s):
|
||||||
"""
|
"""
|
||||||
@ -45,32 +64,45 @@ def parse_replace_hook(s):
|
|||||||
/one/two/foo/bar/
|
/one/two/foo/bar/
|
||||||
|
|
||||||
Checks that pattern and regex are both well-formed. Raises
|
Checks that pattern and regex are both well-formed. Raises
|
||||||
ParseReplaceException on error.
|
ParseException on error.
|
||||||
"""
|
"""
|
||||||
sep, rem = s[0], s[1:]
|
patt, regex, replacement = _parse_hook(s)
|
||||||
parts = rem.split(sep, 2)
|
|
||||||
if len(parts) == 2:
|
|
||||||
patt = ".*"
|
|
||||||
regex, replacement = parts
|
|
||||||
elif len(parts) == 3:
|
|
||||||
patt, regex, replacement = parts
|
|
||||||
else:
|
|
||||||
raise ParseReplaceException("Malformed replacement specifier - too few clauses: %s"%s)
|
|
||||||
|
|
||||||
if not regex:
|
|
||||||
raise ParseReplaceException("Empty replacement regex: %s"%str(patt))
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
re.compile(regex)
|
re.compile(regex)
|
||||||
except re.error, e:
|
except re.error, e:
|
||||||
raise ParseReplaceException("Malformed replacement regex: %s"%str(e.message))
|
raise ParseException("Malformed replacement regex: %s"%str(e.message))
|
||||||
|
|
||||||
if not filt.parse(patt):
|
|
||||||
raise ParseReplaceException("Malformed replacement filter pattern: %s"%patt)
|
|
||||||
|
|
||||||
return patt, regex, replacement
|
return patt, regex, replacement
|
||||||
|
|
||||||
|
|
||||||
|
def parse_setheader(s):
|
||||||
|
"""
|
||||||
|
Returns a (pattern, header, value) tuple.
|
||||||
|
|
||||||
|
The general form for a replacement hook is as follows:
|
||||||
|
|
||||||
|
/patt/header/value
|
||||||
|
|
||||||
|
The first character specifies the separator. Example:
|
||||||
|
|
||||||
|
:~q:foo:bar
|
||||||
|
|
||||||
|
If only two clauses are specified, the pattern is set to match
|
||||||
|
universally (i.e. ".*"). Example:
|
||||||
|
|
||||||
|
/foo/bar/
|
||||||
|
|
||||||
|
Clauses are parsed from left to right. Extra separators are taken to be
|
||||||
|
part of the final clause. For instance, the value clause below is
|
||||||
|
"foo/bar/":
|
||||||
|
|
||||||
|
/one/two/foo/bar/
|
||||||
|
|
||||||
|
Checks that pattern and regex are both well-formed. Raises
|
||||||
|
ParseException on error.
|
||||||
|
"""
|
||||||
|
return _parse_hook(s)
|
||||||
|
|
||||||
|
|
||||||
def get_common_options(options):
|
def get_common_options(options):
|
||||||
stickycookie, stickyauth = None, None
|
stickycookie, stickyauth = None, None
|
||||||
if options.stickycookie_filt:
|
if options.stickycookie_filt:
|
||||||
@ -83,13 +115,13 @@ def get_common_options(options):
|
|||||||
for i in options.replace:
|
for i in options.replace:
|
||||||
try:
|
try:
|
||||||
p = parse_replace_hook(i)
|
p = parse_replace_hook(i)
|
||||||
except ParseReplaceException, e:
|
except ParseException, e:
|
||||||
raise OptionException(e.message)
|
raise OptionException(e.message)
|
||||||
reps.append(p)
|
reps.append(p)
|
||||||
for i in options.replace_file:
|
for i in options.replace_file:
|
||||||
try:
|
try:
|
||||||
patt, rex, path = parse_replace_hook(i)
|
patt, rex, path = parse_replace_hook(i)
|
||||||
except ParseReplaceException, e:
|
except ParseException, e:
|
||||||
raise OptionException(e.message)
|
raise OptionException(e.message)
|
||||||
try:
|
try:
|
||||||
v = open(path, "r").read()
|
v = open(path, "r").read()
|
||||||
@ -97,6 +129,15 @@ def get_common_options(options):
|
|||||||
raise OptionException("Could not read replace file: %s"%path)
|
raise OptionException("Could not read replace file: %s"%path)
|
||||||
reps.append((patt, rex, v))
|
reps.append((patt, rex, v))
|
||||||
|
|
||||||
|
|
||||||
|
setheaders = []
|
||||||
|
for i in options.setheader:
|
||||||
|
try:
|
||||||
|
p = parse_setheader(i)
|
||||||
|
except ParseException, e:
|
||||||
|
raise OptionException(e.message)
|
||||||
|
setheaders.append(p)
|
||||||
|
|
||||||
return dict(
|
return dict(
|
||||||
anticache = options.anticache,
|
anticache = options.anticache,
|
||||||
anticomp = options.anticomp,
|
anticomp = options.anticomp,
|
||||||
@ -108,6 +149,7 @@ def get_common_options(options):
|
|||||||
rheaders = options.rheaders,
|
rheaders = options.rheaders,
|
||||||
rfile = options.rfile,
|
rfile = options.rfile,
|
||||||
replacements = reps,
|
replacements = reps,
|
||||||
|
setheaders = setheaders,
|
||||||
server_replay = options.server_replay,
|
server_replay = options.server_replay,
|
||||||
script = options.script,
|
script = options.script,
|
||||||
stickycookie = stickycookie,
|
stickycookie = stickycookie,
|
||||||
@ -211,6 +253,7 @@ def common_options(parser):
|
|||||||
action="store", dest="cert_wait_time", default=0,
|
action="store", dest="cert_wait_time", default=0,
|
||||||
help="Wait for specified number of seconds after a new cert is generated. This can smooth over small discrepancies between the client and server times."
|
help="Wait for specified number of seconds after a new cert is generated. This can smooth over small discrepancies between the client and server times."
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--no-upstream-cert", default=False,
|
"--no-upstream-cert", default=False,
|
||||||
action="store_true", dest="no_upstream_cert",
|
action="store_true", dest="no_upstream_cert",
|
||||||
@ -271,14 +314,24 @@ def common_options(parser):
|
|||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--replace-from-file",
|
"--replace-from-file",
|
||||||
action="append", type=str, dest="replace_file", default=[],
|
action="append", type=str, dest="replace_file", default=[],
|
||||||
metavar="PATTERN",
|
metavar="PATH",
|
||||||
help="Replacement pattern, where the replacement clause is a path to a file."
|
help="Replacement pattern, where the replacement clause is a path to a file."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
group = parser.add_argument_group(
|
||||||
|
"Set Headers",
|
||||||
|
"""
|
||||||
|
Header specifications are of the form "/pattern/header/value",
|
||||||
|
where the separator can be any character. Please see the
|
||||||
|
documentation for more information.
|
||||||
|
""".strip()
|
||||||
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--dummy-certs", action="store",
|
"--setheader",
|
||||||
type = str, dest = "certdir", default=None,
|
action="append", type=str, dest="setheader", default=[],
|
||||||
help = "Generated dummy certs directory."
|
metavar="PATTERN",
|
||||||
|
help="Header set pattern."
|
||||||
)
|
)
|
||||||
|
|
||||||
proxy.certificate_option_group(parser)
|
proxy.certificate_option_group(parser)
|
||||||
|
@ -339,6 +339,7 @@ class Options(object):
|
|||||||
"script",
|
"script",
|
||||||
"replacements",
|
"replacements",
|
||||||
"rheaders",
|
"rheaders",
|
||||||
|
"setheaders",
|
||||||
"server_replay",
|
"server_replay",
|
||||||
"stickycookie",
|
"stickycookie",
|
||||||
"stickyauth",
|
"stickyauth",
|
||||||
@ -369,6 +370,9 @@ class ConsoleMaster(flow.FlowMaster):
|
|||||||
for i in options.replacements:
|
for i in options.replacements:
|
||||||
self.replacehooks.add(*i)
|
self.replacehooks.add(*i)
|
||||||
|
|
||||||
|
for i in options.setheaders:
|
||||||
|
self.setheaders.add(*i)
|
||||||
|
|
||||||
self.flow_list_walker = None
|
self.flow_list_walker = None
|
||||||
self.set_palette(options.palette)
|
self.set_palette(options.palette)
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ class Options(object):
|
|||||||
"replacements",
|
"replacements",
|
||||||
"rfile",
|
"rfile",
|
||||||
"rheaders",
|
"rheaders",
|
||||||
|
"setheaders",
|
||||||
"server_replay",
|
"server_replay",
|
||||||
"script",
|
"script",
|
||||||
"stickycookie",
|
"stickycookie",
|
||||||
@ -99,6 +100,10 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
for i in options.replacements:
|
for i in options.replacements:
|
||||||
self.replacehooks.add(*i)
|
self.replacehooks.add(*i)
|
||||||
|
|
||||||
|
if options.setheaders:
|
||||||
|
for i in options.setheaders:
|
||||||
|
self.setheaders.add(*i)
|
||||||
|
|
||||||
if options.server_replay:
|
if options.server_replay:
|
||||||
self.start_server_playback(
|
self.start_server_playback(
|
||||||
self._readflow(options.server_replay),
|
self._readflow(options.server_replay),
|
||||||
|
@ -475,6 +475,11 @@ def certificate_option_group(parser):
|
|||||||
type = str, dest = "clientcerts", default=None,
|
type = str, dest = "clientcerts", default=None,
|
||||||
help = "Client certificate directory."
|
help = "Client certificate directory."
|
||||||
)
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--dummy-certs", action="store",
|
||||||
|
type = str, dest = "certdir", default=None,
|
||||||
|
help = "Generated dummy certs directory."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
TRANSPARENT_SSL_PORTS = [443, 8443]
|
TRANSPARENT_SSL_PORTS = [443, 8443]
|
||||||
|
@ -14,7 +14,7 @@ def test_parse_replace_hook():
|
|||||||
assert x == (".*", "bar", "voing")
|
assert x == (".*", "bar", "voing")
|
||||||
|
|
||||||
tutils.raises(
|
tutils.raises(
|
||||||
cmdline.ParseReplaceException,
|
cmdline.ParseException,
|
||||||
cmdline.parse_replace_hook,
|
cmdline.parse_replace_hook,
|
||||||
"/foo"
|
"/foo"
|
||||||
)
|
)
|
||||||
@ -29,11 +29,17 @@ def test_parse_replace_hook():
|
|||||||
"/~/foo/rep"
|
"/~/foo/rep"
|
||||||
)
|
)
|
||||||
tutils.raises(
|
tutils.raises(
|
||||||
"empty replacement regex",
|
"empty clause",
|
||||||
cmdline.parse_replace_hook,
|
cmdline.parse_replace_hook,
|
||||||
"//"
|
"//"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_setheaders():
|
||||||
|
x = cmdline.parse_replace_hook("/foo/bar/voing")
|
||||||
|
assert x == ("foo", "bar", "voing")
|
||||||
|
|
||||||
|
|
||||||
def test_common():
|
def test_common():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
cmdline.common_options(parser)
|
cmdline.common_options(parser)
|
||||||
@ -53,7 +59,7 @@ def test_common():
|
|||||||
|
|
||||||
opts.replace = ["//"]
|
opts.replace = ["//"]
|
||||||
tutils.raises(
|
tutils.raises(
|
||||||
"empty replacement regex",
|
"empty clause",
|
||||||
cmdline.get_common_options,
|
cmdline.get_common_options,
|
||||||
opts
|
opts
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user