adjust to netlib response changes + docs

This commit is contained in:
Maximilian Hils 2015-09-26 17:41:14 +02:00
parent b13acd7956
commit 1b6ea5caf3
12 changed files with 58 additions and 57 deletions

View File

@ -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

View File

@ -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")

View File

@ -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)

View File

@ -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,
) )

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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")])

View File

@ -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

View File

@ -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)