mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 16:17:49 +00:00
commit
6c86d7bd4f
@ -7,6 +7,7 @@ from mitmproxy.builtins import stickyauth
|
|||||||
from mitmproxy.builtins import stickycookie
|
from mitmproxy.builtins import stickycookie
|
||||||
from mitmproxy.builtins import script
|
from mitmproxy.builtins import script
|
||||||
from mitmproxy.builtins import replace
|
from mitmproxy.builtins import replace
|
||||||
|
from mitmproxy.builtins import setheaders
|
||||||
|
|
||||||
|
|
||||||
def default_addons():
|
def default_addons():
|
||||||
@ -18,4 +19,5 @@ def default_addons():
|
|||||||
script.ScriptLoader(),
|
script.ScriptLoader(),
|
||||||
filestreamer.FileStreamer(),
|
filestreamer.FileStreamer(),
|
||||||
replace.Replace(),
|
replace.Replace(),
|
||||||
|
setheaders.SetHeaders(),
|
||||||
]
|
]
|
||||||
|
39
mitmproxy/builtins/setheaders.py
Normal file
39
mitmproxy/builtins/setheaders.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
from mitmproxy import exceptions
|
||||||
|
from mitmproxy import filt
|
||||||
|
|
||||||
|
|
||||||
|
class SetHeaders:
|
||||||
|
def __init__(self):
|
||||||
|
self.lst = []
|
||||||
|
|
||||||
|
def configure(self, options):
|
||||||
|
"""
|
||||||
|
options.setheaders is a tuple of (fpatt, header, value)
|
||||||
|
|
||||||
|
fpatt: String specifying a filter pattern.
|
||||||
|
header: Header name.
|
||||||
|
value: Header value string
|
||||||
|
"""
|
||||||
|
for fpatt, header, value in options.setheaders:
|
||||||
|
cpatt = filt.parse(fpatt)
|
||||||
|
if not cpatt:
|
||||||
|
raise exceptions.OptionsError(
|
||||||
|
"Invalid setheader filter pattern %s" % fpatt
|
||||||
|
)
|
||||||
|
self.lst.append((fpatt, header, value, cpatt))
|
||||||
|
|
||||||
|
def run(self, f, hdrs):
|
||||||
|
for _, header, value, cpatt in self.lst:
|
||||||
|
if cpatt(f):
|
||||||
|
hdrs.pop(header, None)
|
||||||
|
for _, header, value, cpatt in self.lst:
|
||||||
|
if cpatt(f):
|
||||||
|
hdrs.add(header, value)
|
||||||
|
|
||||||
|
def request(self, flow):
|
||||||
|
if not flow.reply.acked:
|
||||||
|
self.run(flow, flow.request.headers)
|
||||||
|
|
||||||
|
def response(self, flow):
|
||||||
|
if not flow.reply.acked:
|
||||||
|
self.run(flow, flow.response.headers)
|
@ -210,10 +210,6 @@ class ConsoleMaster(flow.FlowMaster):
|
|||||||
self.options = self.options # type: Options
|
self.options = self.options # type: Options
|
||||||
self.options.errored.connect(self.options_error)
|
self.options.errored.connect(self.options_error)
|
||||||
|
|
||||||
if options.setheaders:
|
|
||||||
for i in options.setheaders:
|
|
||||||
self.setheaders.add(*i)
|
|
||||||
|
|
||||||
r = self.set_intercept(options.intercept)
|
r = self.set_intercept(options.intercept)
|
||||||
if r:
|
if r:
|
||||||
print("Intercept error: {}".format(r), file=sys.stderr)
|
print("Intercept error: {}".format(r), file=sys.stderr)
|
||||||
|
@ -36,7 +36,7 @@ class Options(urwid.WidgetWrap):
|
|||||||
select.Option(
|
select.Option(
|
||||||
"Header Set Patterns",
|
"Header Set Patterns",
|
||||||
"H",
|
"H",
|
||||||
lambda: master.setheaders.count(),
|
lambda: len(master.options.setheaders),
|
||||||
self.setheaders
|
self.setheaders
|
||||||
),
|
),
|
||||||
select.Option(
|
select.Option(
|
||||||
@ -156,7 +156,6 @@ class Options(urwid.WidgetWrap):
|
|||||||
self.master.showhost = False
|
self.master.showhost = False
|
||||||
self.master.refresh_server_playback = True
|
self.master.refresh_server_playback = True
|
||||||
self.master.server.config.no_upstream_cert = False
|
self.master.server.config.no_upstream_cert = False
|
||||||
self.master.setheaders.clear()
|
|
||||||
self.master.set_ignore_filter([])
|
self.master.set_ignore_filter([])
|
||||||
self.master.set_tcp_filter([])
|
self.master.set_tcp_filter([])
|
||||||
|
|
||||||
@ -165,6 +164,7 @@ class Options(urwid.WidgetWrap):
|
|||||||
anticomp = False,
|
anticomp = False,
|
||||||
replacements = [],
|
replacements = [],
|
||||||
scripts = [],
|
scripts = [],
|
||||||
|
setheaders = [],
|
||||||
stickyauth = None,
|
stickyauth = None,
|
||||||
stickycookie = None
|
stickycookie = None
|
||||||
)
|
)
|
||||||
@ -197,13 +197,12 @@ class Options(urwid.WidgetWrap):
|
|||||||
signals.update_settings.send(self)
|
signals.update_settings.send(self)
|
||||||
|
|
||||||
def setheaders(self):
|
def setheaders(self):
|
||||||
def _set(*args, **kwargs):
|
def _set(shdrs):
|
||||||
self.master.setheaders.set(*args, **kwargs)
|
self.master.options.setheaders = shdrs
|
||||||
signals.update_settings.send(self)
|
|
||||||
self.master.view_grideditor(
|
self.master.view_grideditor(
|
||||||
grideditor.SetHeadersEditor(
|
grideditor.SetHeadersEditor(
|
||||||
self.master,
|
self.master,
|
||||||
self.master.setheaders.get_specs(),
|
self.master.options.setheaders,
|
||||||
_set
|
_set
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -211,7 +210,6 @@ class Options(urwid.WidgetWrap):
|
|||||||
def ignorepatterns(self):
|
def ignorepatterns(self):
|
||||||
def _set(ignore):
|
def _set(ignore):
|
||||||
self.master.set_ignore_filter(ignore)
|
self.master.set_ignore_filter(ignore)
|
||||||
signals.update_settings.send(self)
|
|
||||||
self.master.view_grideditor(
|
self.master.view_grideditor(
|
||||||
grideditor.HostPatternEditor(
|
grideditor.HostPatternEditor(
|
||||||
self.master,
|
self.master,
|
||||||
|
@ -137,7 +137,7 @@ class StatusBar(urwid.WidgetWrap):
|
|||||||
def get_status(self):
|
def get_status(self):
|
||||||
r = []
|
r = []
|
||||||
|
|
||||||
if self.master.setheaders.count():
|
if len(self.master.options.setheaders):
|
||||||
r.append("[")
|
r.append("[")
|
||||||
r.append(("heading_key", "H"))
|
r.append(("heading_key", "H"))
|
||||||
r.append("eaders]")
|
r.append("eaders]")
|
||||||
|
@ -58,10 +58,6 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
"HTTP/2 is disabled. Use --no-http2 to silence this warning.",
|
"HTTP/2 is disabled. Use --no-http2 to silence this warning.",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
|
|
||||||
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),
|
||||||
|
@ -4,8 +4,7 @@ from mitmproxy.flow import export, modules
|
|||||||
from mitmproxy.flow.io import FlowWriter, FilteredFlowWriter, FlowReader, read_flows_from_paths
|
from mitmproxy.flow.io import FlowWriter, FilteredFlowWriter, FlowReader, read_flows_from_paths
|
||||||
from mitmproxy.flow.master import FlowMaster
|
from mitmproxy.flow.master import FlowMaster
|
||||||
from mitmproxy.flow.modules import (
|
from mitmproxy.flow.modules import (
|
||||||
AppRegistry, SetHeaders, StreamLargeBodies, ClientPlaybackState,
|
AppRegistry, StreamLargeBodies, ClientPlaybackState, ServerPlaybackState
|
||||||
ServerPlaybackState
|
|
||||||
)
|
)
|
||||||
from mitmproxy.flow.state import State, FlowView
|
from mitmproxy.flow.state import State, FlowView
|
||||||
from mitmproxy.flow import options
|
from mitmproxy.flow import options
|
||||||
@ -16,7 +15,6 @@ __all__ = [
|
|||||||
"export", "modules",
|
"export", "modules",
|
||||||
"FlowWriter", "FilteredFlowWriter", "FlowReader", "read_flows_from_paths",
|
"FlowWriter", "FilteredFlowWriter", "FlowReader", "read_flows_from_paths",
|
||||||
"FlowMaster",
|
"FlowMaster",
|
||||||
"AppRegistry", "SetHeaders", "StreamLargeBodies", "ClientPlaybackState",
|
"AppRegistry", "StreamLargeBodies", "ClientPlaybackState",
|
||||||
"ServerPlaybackState", "State", "FlowView",
|
"ServerPlaybackState", "State", "FlowView", "options",
|
||||||
"options",
|
|
||||||
]
|
]
|
||||||
|
@ -36,7 +36,6 @@ class FlowMaster(controller.Master):
|
|||||||
|
|
||||||
self.stream_large_bodies = None # type: Optional[modules.StreamLargeBodies]
|
self.stream_large_bodies = None # type: Optional[modules.StreamLargeBodies]
|
||||||
self.refresh_server_playback = False
|
self.refresh_server_playback = False
|
||||||
self.setheaders = modules.SetHeaders()
|
|
||||||
self.replay_ignore_params = False
|
self.replay_ignore_params = False
|
||||||
self.replay_ignore_content = None
|
self.replay_ignore_content = None
|
||||||
self.replay_ignore_host = False
|
self.replay_ignore_host = False
|
||||||
@ -328,8 +327,6 @@ class FlowMaster(controller.Master):
|
|||||||
return
|
return
|
||||||
if f not in self.state.flows: # don't add again on replay
|
if f not in self.state.flows: # don't add again on replay
|
||||||
self.state.add_flow(f)
|
self.state.add_flow(f)
|
||||||
if not f.reply.acked:
|
|
||||||
self.setheaders.run(f)
|
|
||||||
if not f.reply.acked:
|
if not f.reply.acked:
|
||||||
self.process_new_request(f)
|
self.process_new_request(f)
|
||||||
return f
|
return f
|
||||||
@ -347,8 +344,6 @@ class FlowMaster(controller.Master):
|
|||||||
@controller.handler
|
@controller.handler
|
||||||
def response(self, f):
|
def response(self, f):
|
||||||
self.state.update_flow(f)
|
self.state.update_flow(f)
|
||||||
if not f.reply.acked:
|
|
||||||
self.setheaders.run(f)
|
|
||||||
if not f.reply.acked:
|
if not f.reply.acked:
|
||||||
if self.client_playback:
|
if self.client_playback:
|
||||||
self.client_playback.clear(f)
|
self.client_playback.clear(f)
|
||||||
|
@ -5,7 +5,6 @@ import hashlib
|
|||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
|
|
||||||
from mitmproxy import controller
|
from mitmproxy import controller
|
||||||
from mitmproxy import filt
|
|
||||||
from netlib import wsgi
|
from netlib import wsgi
|
||||||
from netlib import version
|
from netlib import version
|
||||||
from netlib import strutils
|
from netlib import strutils
|
||||||
@ -39,60 +38,6 @@ class AppRegistry:
|
|||||||
return self.apps.get((host, request.port), None)
|
return self.apps.get((host, request.port), None)
|
||||||
|
|
||||||
|
|
||||||
class SetHeaders:
|
|
||||||
def __init__(self):
|
|
||||||
self.lst = []
|
|
||||||
|
|
||||||
def set(self, r):
|
|
||||||
self.clear()
|
|
||||||
for i in r:
|
|
||||||
self.add(*i)
|
|
||||||
|
|
||||||
def add(self, fpatt, header, value):
|
|
||||||
"""
|
|
||||||
Add a set header hook.
|
|
||||||
|
|
||||||
fpatt: String specifying a filter pattern.
|
|
||||||
header: Header name.
|
|
||||||
value: Header value string
|
|
||||||
|
|
||||||
Returns True if hook was added, False if the pattern could not be
|
|
||||||
parsed.
|
|
||||||
"""
|
|
||||||
cpatt = filt.parse(fpatt)
|
|
||||||
if not cpatt:
|
|
||||||
return False
|
|
||||||
self.lst.append((fpatt, header, value, cpatt))
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_specs(self):
|
|
||||||
"""
|
|
||||||
Retrieve the hook specifcations. Returns a list of (fpatt, rex, s)
|
|
||||||
tuples.
|
|
||||||
"""
|
|
||||||
return [i[:3] for i in self.lst]
|
|
||||||
|
|
||||||
def count(self):
|
|
||||||
return len(self.lst)
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self.lst = []
|
|
||||||
|
|
||||||
def run(self, f):
|
|
||||||
for _, header, value, cpatt in self.lst:
|
|
||||||
if cpatt(f):
|
|
||||||
if f.response:
|
|
||||||
f.response.headers.pop(header, None)
|
|
||||||
else:
|
|
||||||
f.request.headers.pop(header, None)
|
|
||||||
for _, header, value, cpatt in self.lst:
|
|
||||||
if cpatt(f):
|
|
||||||
if f.response:
|
|
||||||
f.response.headers.add(header, value)
|
|
||||||
else:
|
|
||||||
f.request.headers.add(header, value)
|
|
||||||
|
|
||||||
|
|
||||||
class StreamLargeBodies(object):
|
class StreamLargeBodies(object):
|
||||||
def __init__(self, max_size):
|
def __init__(self, max_size):
|
||||||
self.max_size = max_size
|
self.max_size = max_size
|
||||||
|
64
test/mitmproxy/builtins/test_setheaders.py
Normal file
64
test/mitmproxy/builtins/test_setheaders.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from .. import tutils, mastertest
|
||||||
|
|
||||||
|
from mitmproxy.builtins import setheaders
|
||||||
|
from mitmproxy.flow import state
|
||||||
|
from mitmproxy.flow import options
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetHeaders(mastertest.MasterTest):
|
||||||
|
def mkmaster(self, **opts):
|
||||||
|
s = state.State()
|
||||||
|
m = mastertest.RecordingMaster(options.Options(**opts), None, s)
|
||||||
|
sh = setheaders.SetHeaders()
|
||||||
|
m.addons.add(sh)
|
||||||
|
return m, sh
|
||||||
|
|
||||||
|
def test_configure(self):
|
||||||
|
sh = setheaders.SetHeaders()
|
||||||
|
tutils.raises(
|
||||||
|
"invalid setheader filter pattern",
|
||||||
|
sh.configure,
|
||||||
|
options.Options(
|
||||||
|
setheaders = [("~b", "one", "two")]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_setheaders(self):
|
||||||
|
m, sh = self.mkmaster(
|
||||||
|
setheaders = [
|
||||||
|
("~q", "one", "two"),
|
||||||
|
("~s", "one", "three")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
f = tutils.tflow()
|
||||||
|
f.request.headers["one"] = "xxx"
|
||||||
|
self.invoke(m, "request", f)
|
||||||
|
assert f.request.headers["one"] == "two"
|
||||||
|
|
||||||
|
f = tutils.tflow(resp=True)
|
||||||
|
f.response.headers["one"] = "xxx"
|
||||||
|
self.invoke(m, "response", f)
|
||||||
|
assert f.response.headers["one"] == "three"
|
||||||
|
|
||||||
|
m, sh = self.mkmaster(
|
||||||
|
setheaders = [
|
||||||
|
("~s", "one", "two"),
|
||||||
|
("~s", "one", "three")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
f = tutils.tflow(resp=True)
|
||||||
|
f.request.headers["one"] = "xxx"
|
||||||
|
f.response.headers["one"] = "xxx"
|
||||||
|
self.invoke(m, "response", f)
|
||||||
|
assert f.response.headers.get_all("one") == ["two", "three"]
|
||||||
|
|
||||||
|
m, sh = self.mkmaster(
|
||||||
|
setheaders = [
|
||||||
|
("~q", "one", "two"),
|
||||||
|
("~q", "one", "three")
|
||||||
|
]
|
||||||
|
)
|
||||||
|
f = tutils.tflow()
|
||||||
|
f.request.headers["one"] = "xxx"
|
||||||
|
self.invoke(m, "request", f)
|
||||||
|
assert f.request.headers.get_all("one") == ["two", "three"]
|
@ -961,55 +961,3 @@ class TestClientConnection:
|
|||||||
assert c3.get_state() == c.get_state()
|
assert c3.get_state() == c.get_state()
|
||||||
|
|
||||||
assert str(c)
|
assert str(c)
|
||||||
|
|
||||||
|
|
||||||
def test_setheaders():
|
|
||||||
h = flow.SetHeaders()
|
|
||||||
h.add("~q", "foo", "bar")
|
|
||||||
assert h.lst
|
|
||||||
|
|
||||||
h.set(
|
|
||||||
[
|
|
||||||
(".*", "one", "two"),
|
|
||||||
(".*", "three", "four"),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
assert h.count() == 2
|
|
||||||
|
|
||||||
h.clear()
|
|
||||||
assert not h.lst
|
|
||||||
|
|
||||||
h.add("~q", "foo", "bar")
|
|
||||||
h.add("~s", "foo", "bar")
|
|
||||||
|
|
||||||
v = h.get_specs()
|
|
||||||
assert v == [('~q', 'foo', 'bar'), ('~s', 'foo', 'bar')]
|
|
||||||
assert h.count() == 2
|
|
||||||
h.clear()
|
|
||||||
assert h.count() == 0
|
|
||||||
|
|
||||||
f = tutils.tflow()
|
|
||||||
f.request.content = b"foo"
|
|
||||||
h.add("~s", "foo", "bar")
|
|
||||||
h.run(f)
|
|
||||||
assert f.request.content == b"foo"
|
|
||||||
|
|
||||||
h.clear()
|
|
||||||
h.add("~s", "one", "two")
|
|
||||||
h.add("~s", "one", "three")
|
|
||||||
f = tutils.tflow(resp=True)
|
|
||||||
f.request.headers["one"] = "xxx"
|
|
||||||
f.response.headers["one"] = "xxx"
|
|
||||||
h.run(f)
|
|
||||||
assert f.request.headers["one"] == "xxx"
|
|
||||||
assert f.response.headers.get_all("one") == ["two", "three"]
|
|
||||||
|
|
||||||
h.clear()
|
|
||||||
h.add("~q", "one", "two")
|
|
||||||
h.add("~q", "one", "three")
|
|
||||||
f = tutils.tflow()
|
|
||||||
f.request.headers["one"] = "xxx"
|
|
||||||
h.run(f)
|
|
||||||
assert f.request.headers.get_all("one") == ["two", "three"]
|
|
||||||
|
|
||||||
assert not h.add("~", "foo", "bar")
|
|
||||||
|
Loading…
Reference in New Issue
Block a user