mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2025-01-30 23:09:44 +00:00
adjust to netlib response changes + docs
This commit is contained in:
parent
b13acd7956
commit
1b6ea5caf3
@ -3,11 +3,6 @@
|
|||||||
Models
|
Models
|
||||||
======
|
======
|
||||||
|
|
||||||
.. warning::
|
|
||||||
The documentation for models has not been converted to rst yet and **many attributes/features
|
|
||||||
are missing**.
|
|
||||||
Please read the source code instead.
|
|
||||||
|
|
||||||
.. automodule:: netlib.http
|
.. automodule:: netlib.http
|
||||||
|
|
||||||
.. autoclass:: Request
|
.. autoclass:: Request
|
||||||
@ -40,15 +35,23 @@ Models
|
|||||||
|
|
||||||
.. autoclass:: Response
|
.. autoclass:: Response
|
||||||
|
|
||||||
.. warning:: Docs missing.
|
.. rubric:: Data
|
||||||
|
.. autoattribute:: http_version
|
||||||
|
.. autoattribute:: status_code
|
||||||
|
.. autoattribute:: reason
|
||||||
|
.. autoattribute:: headers
|
||||||
|
.. autoattribute:: content
|
||||||
|
.. autoattribute:: timestamp_start
|
||||||
|
.. autoattribute:: timestamp_end
|
||||||
|
.. rubric:: Computed Properties and Convenience Methods
|
||||||
|
.. autoattribute:: text
|
||||||
|
.. autoattribute:: cookies
|
||||||
|
|
||||||
.. autoclass:: Headers
|
.. autoclass:: Headers
|
||||||
:members:
|
:members:
|
||||||
:special-members:
|
:special-members:
|
||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
|
|
||||||
|
|
||||||
.. autoclass:: decoded
|
.. autoclass:: decoded
|
||||||
|
|
||||||
.. automodule:: libmproxy.models
|
.. automodule:: libmproxy.models
|
||||||
|
@ -168,7 +168,7 @@ class FlowView(tabs.Tabs):
|
|||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
def content_view(self, viewmode, message):
|
def content_view(self, viewmode, message):
|
||||||
if message.body == CONTENT_MISSING:
|
if message.content == CONTENT_MISSING:
|
||||||
msg, body = "", [urwid.Text([("error", "[content missing]")])]
|
msg, body = "", [urwid.Text([("error", "[content missing]")])]
|
||||||
return msg, body
|
return msg, body
|
||||||
else:
|
else:
|
||||||
@ -193,13 +193,13 @@ class FlowView(tabs.Tabs):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
description, lines = contentviews.get_content_view(
|
description, lines = contentviews.get_content_view(
|
||||||
viewmode, message.body, headers=message.headers
|
viewmode, message.content, headers=message.headers
|
||||||
)
|
)
|
||||||
except ContentViewException:
|
except ContentViewException:
|
||||||
s = "Content viewer failed: \n" + traceback.format_exc()
|
s = "Content viewer failed: \n" + traceback.format_exc()
|
||||||
signals.add_event(s, "error")
|
signals.add_event(s, "error")
|
||||||
description, lines = contentviews.get_content_view(
|
description, lines = contentviews.get_content_view(
|
||||||
contentviews.get("Raw"), message.body, headers=message.headers
|
contentviews.get("Raw"), message.content, headers=message.headers
|
||||||
)
|
)
|
||||||
description = description.replace("Raw", "Couldn't parse: falling back to Raw")
|
description = description.replace("Raw", "Couldn't parse: falling back to Raw")
|
||||||
|
|
||||||
|
@ -174,15 +174,15 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
)
|
)
|
||||||
self.echo(headers, indent=4)
|
self.echo(headers, indent=4)
|
||||||
if self.o.flow_detail >= 3:
|
if self.o.flow_detail >= 3:
|
||||||
if message.body == CONTENT_MISSING:
|
if message.content == CONTENT_MISSING:
|
||||||
self.echo("(content missing)", indent=4)
|
self.echo("(content missing)", indent=4)
|
||||||
elif message.body:
|
elif message.content:
|
||||||
self.echo("")
|
self.echo("")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
type, lines = contentviews.get_content_view(
|
type, lines = contentviews.get_content_view(
|
||||||
contentviews.get("Auto"),
|
contentviews.get("Auto"),
|
||||||
message.body,
|
message.content,
|
||||||
headers=message.headers
|
headers=message.headers
|
||||||
)
|
)
|
||||||
except ContentViewException:
|
except ContentViewException:
|
||||||
@ -190,7 +190,7 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
self.add_event(s, "debug")
|
self.add_event(s, "debug")
|
||||||
type, lines = contentviews.get_content_view(
|
type, lines = contentviews.get_content_view(
|
||||||
contentviews.get("Raw"),
|
contentviews.get("Raw"),
|
||||||
message.body,
|
message.content,
|
||||||
headers=message.headers
|
headers=message.headers
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -270,7 +270,7 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
elif 400 <= code < 600:
|
elif 400 <= code < 600:
|
||||||
code_color = "red"
|
code_color = "red"
|
||||||
code = click.style(str(code), fg=code_color, bold=True, blink=(code == 418))
|
code = click.style(str(code), fg=code_color, bold=True, blink=(code == 418))
|
||||||
msg = click.style(flow.response.msg, fg=code_color, bold=True)
|
reason = click.style(flow.response.reason, fg=code_color, bold=True)
|
||||||
|
|
||||||
if flow.response.content == CONTENT_MISSING:
|
if flow.response.content == CONTENT_MISSING:
|
||||||
size = "(content missing)"
|
size = "(content missing)"
|
||||||
@ -280,11 +280,11 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
|
|
||||||
arrows = click.style("<<", bold=True)
|
arrows = click.style("<<", bold=True)
|
||||||
|
|
||||||
line = "{replay} {arrows} {code} {msg} {size}".format(
|
line = "{replay} {arrows} {code} {reason} {size}".format(
|
||||||
replay=replay,
|
replay=replay,
|
||||||
arrows=arrows,
|
arrows=arrows,
|
||||||
code=code,
|
code=code,
|
||||||
msg=msg,
|
reason=reason,
|
||||||
size=size
|
size=size
|
||||||
)
|
)
|
||||||
self.echo(line)
|
self.echo(line)
|
||||||
|
@ -24,9 +24,9 @@ class MessageMixin(stateobject.StateObject):
|
|||||||
def get_state(self, short=False):
|
def get_state(self, short=False):
|
||||||
ret = super(MessageMixin, self).get_state(short)
|
ret = super(MessageMixin, self).get_state(short)
|
||||||
if short:
|
if short:
|
||||||
if self.body:
|
if self.content:
|
||||||
ret["contentLength"] = len(self.body)
|
ret["contentLength"] = len(self.content)
|
||||||
elif self.body == CONTENT_MISSING:
|
elif self.content == CONTENT_MISSING:
|
||||||
ret["contentLength"] = None
|
ret["contentLength"] = None
|
||||||
else:
|
else:
|
||||||
ret["contentLength"] = 0
|
ret["contentLength"] = 0
|
||||||
@ -39,9 +39,9 @@ class MessageMixin(stateobject.StateObject):
|
|||||||
Doesn't change the message iteself or its headers.
|
Doesn't change the message iteself or its headers.
|
||||||
"""
|
"""
|
||||||
ce = self.headers.get("content-encoding")
|
ce = self.headers.get("content-encoding")
|
||||||
if not self.body or ce not in encoding.ENCODINGS:
|
if not self.content or ce not in encoding.ENCODINGS:
|
||||||
return self.body
|
return self.content
|
||||||
return encoding.decode(ce, self.body)
|
return encoding.decode(ce, self.content)
|
||||||
|
|
||||||
def decode(self):
|
def decode(self):
|
||||||
"""
|
"""
|
||||||
@ -52,12 +52,12 @@ class MessageMixin(stateobject.StateObject):
|
|||||||
Returns True if decoding succeeded, False otherwise.
|
Returns True if decoding succeeded, False otherwise.
|
||||||
"""
|
"""
|
||||||
ce = self.headers.get("content-encoding")
|
ce = self.headers.get("content-encoding")
|
||||||
if not self.body or ce not in encoding.ENCODINGS:
|
if not self.content or ce not in encoding.ENCODINGS:
|
||||||
return False
|
return False
|
||||||
data = encoding.decode(ce, self.body)
|
data = encoding.decode(ce, self.content)
|
||||||
if data is None:
|
if data is None:
|
||||||
return False
|
return False
|
||||||
self.body = data
|
self.content = data
|
||||||
self.headers.pop("content-encoding", None)
|
self.headers.pop("content-encoding", None)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class MessageMixin(stateobject.StateObject):
|
|||||||
or "identity".
|
or "identity".
|
||||||
"""
|
"""
|
||||||
# FIXME: Error if there's an existing encoding header?
|
# FIXME: Error if there's an existing encoding header?
|
||||||
self.body = encoding.encode(e, self.body)
|
self.content = encoding.encode(e, self.content)
|
||||||
self.headers["content-encoding"] = e
|
self.headers["content-encoding"] = e
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
@ -87,8 +87,8 @@ class MessageMixin(stateobject.StateObject):
|
|||||||
Returns the number of replacements made.
|
Returns the number of replacements made.
|
||||||
"""
|
"""
|
||||||
with decoded(self):
|
with decoded(self):
|
||||||
self.body, count = utils.safe_subn(
|
self.content, count = utils.safe_subn(
|
||||||
pattern, repl, self.body, *args, **kwargs
|
pattern, repl, self.content, *args, **kwargs
|
||||||
)
|
)
|
||||||
fields = []
|
fields = []
|
||||||
for name, value in self.headers.fields:
|
for name, value in self.headers.fields:
|
||||||
@ -290,9 +290,9 @@ class HTTPResponse(MessageMixin, Response):
|
|||||||
self,
|
self,
|
||||||
http_version,
|
http_version,
|
||||||
status_code,
|
status_code,
|
||||||
msg,
|
reason,
|
||||||
headers,
|
headers,
|
||||||
body,
|
content,
|
||||||
timestamp_start=None,
|
timestamp_start=None,
|
||||||
timestamp_end=None,
|
timestamp_end=None,
|
||||||
):
|
):
|
||||||
@ -300,9 +300,9 @@ class HTTPResponse(MessageMixin, Response):
|
|||||||
self,
|
self,
|
||||||
http_version,
|
http_version,
|
||||||
status_code,
|
status_code,
|
||||||
msg,
|
reason,
|
||||||
headers,
|
headers,
|
||||||
body,
|
content,
|
||||||
timestamp_start=timestamp_start,
|
timestamp_start=timestamp_start,
|
||||||
timestamp_end=timestamp_end,
|
timestamp_end=timestamp_end,
|
||||||
)
|
)
|
||||||
@ -339,9 +339,9 @@ class HTTPResponse(MessageMixin, Response):
|
|||||||
resp = HTTPResponse(
|
resp = HTTPResponse(
|
||||||
http_version=response.http_version,
|
http_version=response.http_version,
|
||||||
status_code=response.status_code,
|
status_code=response.status_code,
|
||||||
msg=response.msg,
|
reason=response.reason,
|
||||||
headers=response.headers,
|
headers=response.headers,
|
||||||
body=response.body,
|
content=response.content,
|
||||||
timestamp_start=response.timestamp_start,
|
timestamp_start=response.timestamp_start,
|
||||||
timestamp_end=response.timestamp_end,
|
timestamp_end=response.timestamp_end,
|
||||||
)
|
)
|
||||||
|
@ -51,7 +51,7 @@ class _StreamingHttpLayer(_HttpLayer):
|
|||||||
|
|
||||||
def read_response(self, request):
|
def read_response(self, request):
|
||||||
response = self.read_response_headers()
|
response = self.read_response_headers()
|
||||||
response.body = b"".join(
|
response.content = b"".join(
|
||||||
self.read_response_body(request, response)
|
self.read_response_body(request, response)
|
||||||
)
|
)
|
||||||
return response
|
return response
|
||||||
@ -63,10 +63,10 @@ class _StreamingHttpLayer(_HttpLayer):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def send_response(self, response):
|
def send_response(self, response):
|
||||||
if response.body == CONTENT_MISSING:
|
if response.content == CONTENT_MISSING:
|
||||||
raise HttpException("Cannot assemble flow with CONTENT_MISSING")
|
raise HttpException("Cannot assemble flow with CONTENT_MISSING")
|
||||||
self.send_response_headers(response)
|
self.send_response_headers(response)
|
||||||
self.send_response_body(response, [response.body])
|
self.send_response_body(response, [response.content])
|
||||||
|
|
||||||
|
|
||||||
class Http1Layer(_StreamingHttpLayer):
|
class Http1Layer(_StreamingHttpLayer):
|
||||||
|
@ -7,7 +7,6 @@ from construct import ConstructError
|
|||||||
import six
|
import six
|
||||||
from netlib.exceptions import InvalidCertificateException, TcpException, TlsException
|
from netlib.exceptions import InvalidCertificateException, TcpException, TlsException
|
||||||
|
|
||||||
from netlib.http import ALPN_PROTO_HTTP1
|
|
||||||
from ..contrib.tls._constructs import ClientHello
|
from ..contrib.tls._constructs import ClientHello
|
||||||
from ..exceptions import ProtocolException, TlsProtocolException, ClientHandshakeException
|
from ..exceptions import ProtocolException, TlsProtocolException, ClientHandshakeException
|
||||||
from .base import Layer
|
from .base import Layer
|
||||||
@ -367,8 +366,8 @@ class TlsLayer(Layer):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# This gets triggered if we haven't established an upstream connection yet.
|
# This gets triggered if we haven't established an upstream connection yet.
|
||||||
default_alpn = ALPN_PROTO_HTTP1
|
default_alpn = b'http/1.1'
|
||||||
# alpn_preference = ALPN_PROTO_H2
|
# alpn_preference = b'h2'
|
||||||
|
|
||||||
if self.alpn_for_client_connection in options:
|
if self.alpn_for_client_connection in options:
|
||||||
choice = bytes(self.alpn_for_client_connection)
|
choice = bytes(self.alpn_for_client_connection)
|
||||||
|
@ -6,7 +6,6 @@ import six
|
|||||||
|
|
||||||
from libmproxy.exceptions import ProtocolException
|
from libmproxy.exceptions import ProtocolException
|
||||||
from netlib.exceptions import TcpException
|
from netlib.exceptions import TcpException
|
||||||
from netlib.http import ALPN_PROTO_H2, ALPN_PROTO_HTTP1
|
|
||||||
from ..protocol import (
|
from ..protocol import (
|
||||||
RawTCPLayer, TlsLayer, Http1Layer, Http2Layer, is_tls_record_magic, ServerConnectionMixin,
|
RawTCPLayer, TlsLayer, Http1Layer, Http2Layer, is_tls_record_magic, ServerConnectionMixin,
|
||||||
UpstreamConnectLayer
|
UpstreamConnectLayer
|
||||||
@ -85,9 +84,9 @@ class RootContext(object):
|
|||||||
# 5. Check for TLS ALPN (HTTP1/HTTP2)
|
# 5. Check for TLS ALPN (HTTP1/HTTP2)
|
||||||
if isinstance(top_layer, TlsLayer):
|
if isinstance(top_layer, TlsLayer):
|
||||||
alpn = top_layer.client_conn.get_alpn_proto_negotiated()
|
alpn = top_layer.client_conn.get_alpn_proto_negotiated()
|
||||||
if alpn == ALPN_PROTO_H2:
|
if alpn == b'h2':
|
||||||
return Http2Layer(top_layer, 'transparent')
|
return Http2Layer(top_layer, 'transparent')
|
||||||
if alpn == ALPN_PROTO_HTTP1:
|
if alpn == b'http/1.1':
|
||||||
return Http1Layer(top_layer, 'transparent')
|
return Http1Layer(top_layer, 'transparent')
|
||||||
|
|
||||||
# 6. Check for raw tcp mode
|
# 6. Check for raw tcp mode
|
||||||
|
@ -29,7 +29,7 @@ class RequestHandler(tornado.web.RequestHandler):
|
|||||||
def json(self):
|
def json(self):
|
||||||
if not self.request.headers.get("Content-Type").startswith("application/json"):
|
if not self.request.headers.get("Content-Type").startswith("application/json"):
|
||||||
return None
|
return None
|
||||||
return json.loads(self.request.body)
|
return json.loads(self.request.content)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
|
@ -38,13 +38,13 @@ def test_strfuncs():
|
|||||||
flow.request.stickycookie = True
|
flow.request.stickycookie = True
|
||||||
flow.client_conn = mock.MagicMock()
|
flow.client_conn = mock.MagicMock()
|
||||||
flow.client_conn.address.host = "foo"
|
flow.client_conn.address.host = "foo"
|
||||||
flow.response = netlib.tutils.tresp(body=CONTENT_MISSING)
|
flow.response = netlib.tutils.tresp(content=CONTENT_MISSING)
|
||||||
flow.response.is_replay = True
|
flow.response.is_replay = True
|
||||||
flow.response.status_code = 300
|
flow.response.status_code = 300
|
||||||
m.echo_flow(flow)
|
m.echo_flow(flow)
|
||||||
|
|
||||||
|
|
||||||
flow = tutils.tflow(resp=netlib.tutils.tresp(body="{"))
|
flow = tutils.tflow(resp=netlib.tutils.tresp(content="{"))
|
||||||
flow.response.headers["content-type"] = "application/json"
|
flow.response.headers["content-type"] = "application/json"
|
||||||
flow.response.status_code = 400
|
flow.response.status_code = 400
|
||||||
m.echo_flow(flow)
|
m.echo_flow(flow)
|
||||||
@ -69,7 +69,7 @@ class TestDumpMaster:
|
|||||||
m.handle_clientconnect(f.client_conn)
|
m.handle_clientconnect(f.client_conn)
|
||||||
m.handle_serverconnect(f.server_conn)
|
m.handle_serverconnect(f.server_conn)
|
||||||
m.handle_request(f)
|
m.handle_request(f)
|
||||||
f.response = HTTPResponse.wrap(netlib.tutils.tresp(body=content))
|
f.response = HTTPResponse.wrap(netlib.tutils.tresp(content=content))
|
||||||
f = m.handle_response(f)
|
f = m.handle_response(f)
|
||||||
m.handle_clientdisconnect(f.client_conn)
|
m.handle_clientdisconnect(f.client_conn)
|
||||||
return f
|
return f
|
||||||
|
@ -8,8 +8,8 @@ import mock
|
|||||||
|
|
||||||
import netlib.utils
|
import netlib.utils
|
||||||
from netlib import odict
|
from netlib import odict
|
||||||
from netlib.http import CONTENT_MISSING, HDR_FORM_URLENCODED, Headers
|
from netlib.http import CONTENT_MISSING, Headers
|
||||||
from libmproxy import filt, protocol, controller, tnetstring, flow
|
from libmproxy import filt, controller, tnetstring, flow
|
||||||
from libmproxy.models import Error, Flow, HTTPRequest, HTTPResponse, HTTPFlow, decoded
|
from libmproxy.models import Error, Flow, HTTPRequest, HTTPResponse, HTTPFlow, decoded
|
||||||
from libmproxy.proxy.config import HostMatcher
|
from libmproxy.proxy.config import HostMatcher
|
||||||
from libmproxy.proxy import ProxyConfig
|
from libmproxy.proxy import ProxyConfig
|
||||||
@ -849,7 +849,7 @@ class TestFlowMaster:
|
|||||||
s = flow.State()
|
s = flow.State()
|
||||||
|
|
||||||
f = tutils.tflow()
|
f = tutils.tflow()
|
||||||
f.response = HTTPResponse.wrap(netlib.tutils.tresp(body=f.request))
|
f.response = HTTPResponse.wrap(netlib.tutils.tresp(content=f.request))
|
||||||
pb = [f]
|
pb = [f]
|
||||||
|
|
||||||
fm = flow.FlowMaster(None, s)
|
fm = flow.FlowMaster(None, s)
|
||||||
@ -903,7 +903,7 @@ class TestFlowMaster:
|
|||||||
def test_server_playback_kill(self):
|
def test_server_playback_kill(self):
|
||||||
s = flow.State()
|
s = flow.State()
|
||||||
f = tutils.tflow()
|
f = tutils.tflow()
|
||||||
f.response = HTTPResponse.wrap(netlib.tutils.tresp(body=f.request))
|
f.response = HTTPResponse.wrap(netlib.tutils.tresp(content=f.request))
|
||||||
pb = [f]
|
pb = [f]
|
||||||
fm = flow.FlowMaster(None, s)
|
fm = flow.FlowMaster(None, s)
|
||||||
fm.refresh_server_playback = True
|
fm.refresh_server_playback = True
|
||||||
@ -1044,7 +1044,7 @@ class TestRequest:
|
|||||||
def test_getset_form_urlencoded(self):
|
def test_getset_form_urlencoded(self):
|
||||||
d = odict.ODict([("one", "two"), ("three", "four")])
|
d = odict.ODict([("one", "two"), ("three", "four")])
|
||||||
r = HTTPRequest.wrap(netlib.tutils.treq(content=netlib.utils.urlencode(d.lst)))
|
r = HTTPRequest.wrap(netlib.tutils.treq(content=netlib.utils.urlencode(d.lst)))
|
||||||
r.headers["content-type"] = HDR_FORM_URLENCODED
|
r.headers["content-type"] = "application/x-www-form-urlencoded"
|
||||||
assert r.get_form_urlencoded() == d
|
assert r.get_form_urlencoded() == d
|
||||||
|
|
||||||
d = odict.ODict([("x", "y")])
|
d = odict.ODict([("x", "y")])
|
||||||
|
@ -46,11 +46,11 @@ class TestInvalidRequests(tservers.HTTPProxTest):
|
|||||||
p = self.pathoc()
|
p = self.pathoc()
|
||||||
r = p.request("connect:'%s:%s'" % ("127.0.0.1", self.server2.port))
|
r = p.request("connect:'%s:%s'" % ("127.0.0.1", self.server2.port))
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
assert "Invalid HTTP request form" in r.body
|
assert "Invalid HTTP request form" in r.content
|
||||||
|
|
||||||
def test_relative_request(self):
|
def test_relative_request(self):
|
||||||
p = self.pathoc_raw()
|
p = self.pathoc_raw()
|
||||||
p.connect()
|
p.connect()
|
||||||
r = p.request("get:/p/200")
|
r = p.request("get:/p/200")
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
assert "Invalid HTTP request form" in r.body
|
assert "Invalid HTTP request form" in r.content
|
||||||
|
@ -616,7 +616,7 @@ class MasterRedirectRequest(tservers.TestMaster):
|
|||||||
super(MasterRedirectRequest, self).handle_request(f)
|
super(MasterRedirectRequest, self).handle_request(f)
|
||||||
|
|
||||||
def handle_response(self, f):
|
def handle_response(self, f):
|
||||||
f.response.body = str(f.client_conn.address.port)
|
f.response.content = str(f.client_conn.address.port)
|
||||||
f.response.headers["server-conn-id"] = str(f.server_conn.source_address.port)
|
f.response.headers["server-conn-id"] = str(f.server_conn.source_address.port)
|
||||||
super(MasterRedirectRequest, self).handle_response(f)
|
super(MasterRedirectRequest, self).handle_response(f)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user