Merge pull request #1073 from mitmproxy/first-line-format

form_(in|out) -> first_line_format
This commit is contained in:
Thomas Kriechbaumer 2016-04-03 10:16:06 +02:00
commit 16fdbb4f2f
9 changed files with 37 additions and 76 deletions

View File

@ -80,18 +80,13 @@ class HTTPRequest(MessageMixin, Request):
content: Content of the request, the value is None if there is content content: Content of the request, the value is None if there is content
associated, but not present. associated, but not present.
form_in: The request form which mitmproxy has received. The following first_line_format: The request form. The following values are possible:
values are possible:
- relative (GET /index.html, OPTIONS *) (covers origin form and - relative (GET /index.html, OPTIONS *) (origin form or asterisk form)
asterisk form)
- absolute (GET http://example.com:80/index.html) - absolute (GET http://example.com:80/index.html)
- authority-form (CONNECT example.com:443) - authority-form (CONNECT example.com:443)
Details: http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-25#section-5.3 Details: http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-25#section-5.3
form_out: The request form which mitmproxy will send out to the
destination
timestamp_start: Timestamp indicating when request transmission started timestamp_start: Timestamp indicating when request transmission started
timestamp_end: Timestamp indicating when request transmission ended timestamp_end: Timestamp indicating when request transmission ended
@ -110,7 +105,6 @@ class HTTPRequest(MessageMixin, Request):
content, content,
timestamp_start=None, timestamp_start=None,
timestamp_end=None, timestamp_end=None,
form_out=None,
is_replay=False, is_replay=False,
stickycookie=False, stickycookie=False,
stickyauth=False, stickyauth=False,
@ -129,7 +123,6 @@ class HTTPRequest(MessageMixin, Request):
timestamp_start, timestamp_start,
timestamp_end, timestamp_end,
) )
self.form_out = form_out or first_line_format # FIXME remove
# Have this request's cookies been modified by sticky cookies or auth? # Have this request's cookies been modified by sticky cookies or auth?
self.stickycookie = stickycookie self.stickycookie = stickycookie
@ -167,20 +160,9 @@ class HTTPRequest(MessageMixin, Request):
content=request.data.content, content=request.data.content,
timestamp_start=request.data.timestamp_start, timestamp_start=request.data.timestamp_start,
timestamp_end=request.data.timestamp_end, timestamp_end=request.data.timestamp_end,
form_out=(request.form_out if hasattr(request, 'form_out') else None),
) )
return req return req
@property
def form_out(self):
warnings.warn(".form_out is deprecated, use .first_line_format instead.", DeprecationWarning)
return self.first_line_format
@form_out.setter
def form_out(self, value):
warnings.warn(".form_out is deprecated, use .first_line_format instead.", DeprecationWarning)
self.first_line_format = value
def __hash__(self): def __hash__(self):
return id(self) return id(self)

View File

@ -167,7 +167,7 @@ class HttpLayer(Layer):
self.validate_request(request) self.validate_request(request)
# Regular Proxy Mode: Handle CONNECT # Regular Proxy Mode: Handle CONNECT
if self.mode == "regular" and request.form_in == "authority": if self.mode == "regular" and request.first_line_format == "authority":
self.handle_regular_mode_connect(request) self.handle_regular_mode_connect(request)
return return
@ -215,7 +215,7 @@ class HttpLayer(Layer):
return return
# Upstream Proxy Mode: Handle CONNECT # Upstream Proxy Mode: Handle CONNECT
if flow.request.form_in == "authority" and flow.response.status_code == 200: if flow.request.first_line_format == "authority" and flow.response.status_code == 200:
self.handle_upstream_mode_connect(flow.request.copy()) self.handle_upstream_mode_connect(flow.request.copy())
return return
@ -340,7 +340,7 @@ class HttpLayer(Layer):
if self.mode == "regular": if self.mode == "regular":
pass # only absolute-form at this point, nothing to do here. pass # only absolute-form at this point, nothing to do here.
elif self.mode == "upstream": elif self.mode == "upstream":
if flow.request.form_in == "authority": if flow.request.first_line_format == "authority":
flow.request.scheme = "http" # pseudo value flow.request.scheme = "http" # pseudo value
else: else:
# Setting request.host also updates the host header, which we want to preserve # Setting request.host also updates the host header, which we want to preserve
@ -390,7 +390,7 @@ class HttpLayer(Layer):
""" """
def validate_request(self, request): def validate_request(self, request):
if request.form_in == "absolute" and request.scheme != "http": if request.first_line_format == "absolute" and request.scheme != "http":
raise HttpException("Invalid request scheme: %s" % request.scheme) raise HttpException("Invalid request scheme: %s" % request.scheme)
expected_request_forms = { expected_request_forms = {
@ -400,14 +400,14 @@ class HttpLayer(Layer):
} }
allowed_request_forms = expected_request_forms[self.mode] allowed_request_forms = expected_request_forms[self.mode]
if request.form_in not in allowed_request_forms: if request.first_line_format not in allowed_request_forms:
err_message = "Invalid HTTP request form (expected: %s, got: %s)" % ( err_message = "Invalid HTTP request form (expected: %s, got: %s)" % (
" or ".join(allowed_request_forms), request.form_in " or ".join(allowed_request_forms), request.first_line_format
) )
raise HttpException(err_message) raise HttpException(err_message)
if self.mode == "regular" and request.form_in == "absolute": if self.mode == "regular" and request.first_line_format == "absolute":
request.form_out = "relative" request.first_line_format = "relative"
def authenticate(self, request): def authenticate(self, request):
if self.config.authenticator: if self.config.authenticator:

View File

@ -54,7 +54,7 @@ class Http1Layer(_HttpTransmissionLayer):
) )
read_until_eof = http1.expected_http_body_size(flow.request, flow.response) == -1 read_until_eof = http1.expected_http_body_size(flow.request, flow.response) == -1
close_connection = request_close or response_close or read_until_eof close_connection = request_close or response_close or read_until_eof
if flow.request.form_in == "authority" and flow.response.status_code == 200: if flow.request.first_line_format == "authority" and flow.response.status_code == 200:
# Workaround for https://github.com/mitmproxy/mitmproxy/issues/313: # Workaround for https://github.com/mitmproxy/mitmproxy/issues/313:
# Charles Proxy sends a CONNECT response with HTTP/1.0 # Charles Proxy sends a CONNECT response with HTTP/1.0
# and no Content-Length header # and no Content-Length header

View File

@ -303,11 +303,11 @@ class Http2SingleStreamLayer(_HttpTransmissionLayer, threading.Thread):
port = None port = None
if path == '*' or path.startswith("/"): if path == '*' or path.startswith("/"):
form_in = "relative" first_line_format = "relative"
elif method == 'CONNECT': # pragma: no cover elif method == 'CONNECT': # pragma: no cover
raise NotImplementedError("CONNECT over HTTP/2 is not implemented.") raise NotImplementedError("CONNECT over HTTP/2 is not implemented.")
else: # pragma: no cover else: # pragma: no cover
form_in = "absolute" first_line_format = "absolute"
# FIXME: verify if path or :host contains what we need # FIXME: verify if path or :host contains what we need
scheme, host, port, _ = utils.parse_url(path) scheme, host, port, _ = utils.parse_url(path)
@ -326,7 +326,7 @@ class Http2SingleStreamLayer(_HttpTransmissionLayer, threading.Thread):
data = b"".join(data) data = b"".join(data)
return HTTPRequest( return HTTPRequest(
form_in, first_line_format,
method, method,
scheme, scheme,
host, host,

View File

@ -30,7 +30,7 @@ class RequestReplayThread(threading.Thread):
def run(self): def run(self):
r = self.flow.request r = self.flow.request
form_out_backup = r.form_out first_line_format_backup = r.first_line_format
try: try:
self.flow.response = None self.flow.response = None
@ -63,9 +63,9 @@ class RequestReplayThread(threading.Thread):
self.config.clientcerts, self.config.clientcerts,
sni=self.flow.server_conn.sni sni=self.flow.server_conn.sni
) )
r.form_out = "relative" r.first_line_format = "relative"
else: else:
r.form_out = "absolute" r.first_line_format= "absolute"
else: else:
server_address = (r.host, r.port) server_address = (r.host, r.port)
server = ServerConnection(server_address, (self.config.host, 0)) server = ServerConnection(server_address, (self.config.host, 0))
@ -75,7 +75,7 @@ class RequestReplayThread(threading.Thread):
self.config.clientcerts, self.config.clientcerts,
sni=self.flow.server_conn.sni sni=self.flow.server_conn.sni
) )
r.form_out = "relative" r.first_line_format = "relative"
server.wfile.write(http1.assemble_request(r)) server.wfile.write(http1.assemble_request(r))
server.wfile.flush() server.wfile.flush()
@ -102,4 +102,4 @@ class RequestReplayThread(threading.Thread):
from ..proxy.root_context import Log from ..proxy.root_context import Log
self.channel.tell("log", Log(traceback.format_exc(), "error")) self.channel.tell("log", Log(traceback.format_exc(), "error"))
finally: finally:
r.form_out = form_out_backup r.first_line_format = first_line_format_backup

View File

@ -102,15 +102,15 @@ class HTTP2Protocol(object):
port = None port = None
if path == '*' or path.startswith("/"): if path == '*' or path.startswith("/"):
form_in = "relative" first_line_format = "relative"
elif method == 'CONNECT': elif method == 'CONNECT':
form_in = "authority" first_line_format = "authority"
if ":" in authority: if ":" in authority:
host, port = authority.split(":", 1) host, port = authority.split(":", 1)
else: else:
host = authority host = authority
else: else:
form_in = "absolute" first_line_format = "absolute"
# FIXME: verify if path or :host contains what we need # FIXME: verify if path or :host contains what we need
scheme, host, port, _ = utils.parse_url(path) scheme, host, port, _ = utils.parse_url(path)
scheme = scheme.decode('ascii') scheme = scheme.decode('ascii')
@ -123,7 +123,7 @@ class HTTP2Protocol(object):
port = int(port) port = int(port)
request = Request( request = Request(
form_in, first_line_format,
method.encode('ascii'), method.encode('ascii'),
scheme.encode('ascii'), scheme.encode('ascii'),
host.encode('ascii'), host.encode('ascii'),

View File

@ -358,24 +358,3 @@ class Request(Message):
def get_form_multipart(self): # pragma: no cover def get_form_multipart(self): # pragma: no cover
warnings.warn(".get_form_multipart is deprecated, use .multipart_form instead.", DeprecationWarning) warnings.warn(".get_form_multipart is deprecated, use .multipart_form instead.", DeprecationWarning)
return self.multipart_form or ODict([]) return self.multipart_form or ODict([])
@property
def form_in(self): # pragma: no cover
warnings.warn(".form_in is deprecated, use .first_line_format instead.", DeprecationWarning)
return self.first_line_format
@form_in.setter
def form_in(self, form_in): # pragma: no cover
warnings.warn(".form_in is deprecated, use .first_line_format instead.", DeprecationWarning)
self.first_line_format = form_in
@property
def form_out(self): # pragma: no cover
warnings.warn(".form_out is deprecated, use .first_line_format instead.", DeprecationWarning)
return self.first_line_format
@form_out.setter
def form_out(self, form_out): # pragma: no cover
warnings.warn(".form_out is deprecated, use .first_line_format instead.", DeprecationWarning)
self.first_line_format = form_out

View File

@ -973,22 +973,22 @@ class TestProxyChainingSSLReconnect(tservers.HTTPUpstreamProxyTest):
assert not self.chain[1].tmaster.state.flows[0].response # killed assert not self.chain[1].tmaster.state.flows[0].response # killed
assert self.chain[1].tmaster.state.flows[1].response assert self.chain[1].tmaster.state.flows[1].response
assert self.proxy.tmaster.state.flows[0].request.form_in == "authority" assert self.proxy.tmaster.state.flows[0].request.first_line_format == "authority"
assert self.proxy.tmaster.state.flows[1].request.form_in == "relative" assert self.proxy.tmaster.state.flows[1].request.first_line_format == "relative"
assert self.chain[0].tmaster.state.flows[ assert self.chain[0].tmaster.state.flows[
0].request.form_in == "authority" 0].request.first_line_format == "authority"
assert self.chain[0].tmaster.state.flows[ assert self.chain[0].tmaster.state.flows[
1].request.form_in == "relative" 1].request.first_line_format == "relative"
assert self.chain[0].tmaster.state.flows[ assert self.chain[0].tmaster.state.flows[
2].request.form_in == "authority" 2].request.first_line_format == "authority"
assert self.chain[0].tmaster.state.flows[ assert self.chain[0].tmaster.state.flows[
3].request.form_in == "relative" 3].request.first_line_format == "relative"
assert self.chain[1].tmaster.state.flows[ assert self.chain[1].tmaster.state.flows[
0].request.form_in == "relative" 0].request.first_line_format == "relative"
assert self.chain[1].tmaster.state.flows[ assert self.chain[1].tmaster.state.flows[
1].request.form_in == "relative" 1].request.first_line_format == "relative"
req = p.request("get:'/p/418:b\"content2\"'") req = p.request("get:'/p/418:b\"content2\"'")

View File

@ -325,7 +325,7 @@ class TestReadRequestRelative(tservers.ServerTestBase):
ssl = True ssl = True
def test_asterisk_form_in(self): def test_asterisk_form(self):
c = tcp.TCPClient(("127.0.0.1", self.port)) c = tcp.TCPClient(("127.0.0.1", self.port))
c.connect() c.connect()
c.convert_to_ssl() c.convert_to_ssl()
@ -334,7 +334,7 @@ class TestReadRequestRelative(tservers.ServerTestBase):
req = protocol.read_request(NotImplemented) req = protocol.read_request(NotImplemented)
assert req.form_in == "relative" assert req.first_line_format == "relative"
assert req.method == "OPTIONS" assert req.method == "OPTIONS"
assert req.path == "*" assert req.path == "*"
@ -348,7 +348,7 @@ class TestReadRequestAbsolute(tservers.ServerTestBase):
ssl = True ssl = True
def test_absolute_form_in(self): def test_absolute_form(self):
c = tcp.TCPClient(("127.0.0.1", self.port)) c = tcp.TCPClient(("127.0.0.1", self.port))
c.connect() c.connect()
c.convert_to_ssl() c.convert_to_ssl()
@ -357,7 +357,7 @@ class TestReadRequestAbsolute(tservers.ServerTestBase):
req = protocol.read_request(NotImplemented) req = protocol.read_request(NotImplemented)
assert req.form_in == "absolute" assert req.first_line_format == "absolute"
assert req.scheme == "http" assert req.scheme == "http"
assert req.host == "address" assert req.host == "address"
assert req.port == 22 assert req.port == 22
@ -382,13 +382,13 @@ class TestReadRequestConnect(tservers.ServerTestBase):
protocol.connection_preface_performed = True protocol.connection_preface_performed = True
req = protocol.read_request(NotImplemented) req = protocol.read_request(NotImplemented)
assert req.form_in == "authority" assert req.first_line_format == "authority"
assert req.method == "CONNECT" assert req.method == "CONNECT"
assert req.host == "address" assert req.host == "address"
assert req.port == 22 assert req.port == 22
req = protocol.read_request(NotImplemented) req = protocol.read_request(NotImplemented)
assert req.form_in == "authority" assert req.first_line_format == "authority"
assert req.method == "CONNECT" assert req.method == "CONNECT"
assert req.host == "example.com" assert req.host == "example.com"
assert req.port == 443 assert req.port == 443