mitmproxy/netlib/http/semantics.py

205 lines
5.2 KiB
Python
Raw Normal View History

2015-07-14 21:02:14 +00:00
from __future__ import (absolute_import, print_function, division)
import binascii
import collections
import string
import sys
import urlparse
2015-07-22 11:01:24 +00:00
from .. import utils, odict
2015-07-14 21:02:14 +00:00
class Request(object):
def __init__(
self,
form_in,
method,
scheme,
host,
port,
path,
httpversion,
headers,
2015-07-19 15:52:10 +00:00
body,
2015-07-27 07:36:50 +00:00
timestamp_start=None,
timestamp_end=None,
):
2015-07-27 07:36:50 +00:00
assert isinstance(headers, odict.ODictCaseless) or not headers
self.form_in = form_in
self.method = method
self.scheme = scheme
self.host = host
self.port = port
self.path = path
self.httpversion = httpversion
self.headers = headers
2015-07-19 15:52:10 +00:00
self.body = body
2015-07-27 07:36:50 +00:00
self.timestamp_start = timestamp_start
self.timestamp_end = timestamp_end
def __eq__(self, other):
2015-07-27 07:36:50 +00:00
try:
self_d = [self.__dict__[k] for k in self.__dict__ if k not in ('timestamp_start', 'timestamp_end')]
other_d = [other.__dict__[k] for k in other.__dict__ if k not in ('timestamp_start', 'timestamp_end')]
return self_d == other_d
except:
return False
def __repr__(self):
return "Request(%s - %s, %s)" % (self.method, self.host, self.path)
2015-07-22 11:01:24 +00:00
@property
def content(self):
2015-07-27 07:36:50 +00:00
# TODO: remove deprecated getter
2015-07-22 11:01:24 +00:00
return self.body
2015-07-27 07:36:50 +00:00
@content.setter
def content(self, content):
# TODO: remove deprecated setter
self.body = content
2015-07-19 18:46:26 +00:00
class EmptyRequest(Request):
def __init__(self):
super(EmptyRequest, self).__init__(
form_in="",
method="",
scheme="",
host="",
port="",
path="",
2015-07-22 11:01:24 +00:00
httpversion=(0, 0),
headers=odict.ODictCaseless(),
2015-07-19 15:52:10 +00:00
body="",
)
2015-07-14 21:02:14 +00:00
class Response(object):
def __init__(
self,
httpversion,
status_code,
msg,
headers,
2015-07-19 15:52:10 +00:00
body,
2015-07-14 21:02:14 +00:00
sslinfo=None,
2015-07-27 07:36:50 +00:00
timestamp_start=None,
timestamp_end=None,
2015-07-14 21:02:14 +00:00
):
2015-07-27 07:36:50 +00:00
assert isinstance(headers, odict.ODictCaseless) or not headers
2015-07-14 21:02:14 +00:00
self.httpversion = httpversion
self.status_code = status_code
self.msg = msg
self.headers = headers
2015-07-19 15:52:10 +00:00
self.body = body
2015-07-14 21:02:14 +00:00
self.sslinfo = sslinfo
2015-07-27 07:36:50 +00:00
self.timestamp_start = timestamp_start
self.timestamp_end = timestamp_end
2015-07-14 21:02:14 +00:00
def __eq__(self, other):
2015-07-27 07:36:50 +00:00
try:
self_d = [self.__dict__[k] for k in self.__dict__ if k not in ('timestamp_start', 'timestamp_end')]
other_d = [other.__dict__[k] for k in other.__dict__ if k not in ('timestamp_start', 'timestamp_end')]
return self_d == other_d
except:
return False
2015-07-14 21:02:14 +00:00
def __repr__(self):
return "Response(%s - %s)" % (self.status_code, self.msg)
2015-07-22 11:01:24 +00:00
@property
def content(self):
2015-07-27 07:36:50 +00:00
# TODO: remove deprecated getter
2015-07-22 11:01:24 +00:00
return self.body
2015-07-27 07:36:50 +00:00
@content.setter
def content(self, content):
# TODO: remove deprecated setter
self.body = content
@property
def code(self):
# TODO: remove deprecated getter
return self.status_code
@code.setter
def code(self, code):
# TODO: remove deprecated setter
self.status_code = code
2015-07-14 21:02:14 +00:00
def is_valid_port(port):
if not 0 <= port <= 65535:
return False
return True
def is_valid_host(host):
try:
host.decode("idna")
except ValueError:
return False
if "\0" in host:
return None
return True
def parse_url(url):
"""
Returns a (scheme, host, port, path) tuple, or None on error.
Checks that:
port is an integer 0-65535
host is a valid IDNA-encoded hostname with no null-bytes
path is valid ASCII
"""
try:
scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
except ValueError:
return None
if not scheme:
return None
if '@' in netloc:
# FIXME: Consider what to do with the discarded credentials here Most
# probably we should extend the signature to return these as a separate
# value.
_, netloc = string.rsplit(netloc, '@', maxsplit=1)
if ':' in netloc:
host, port = string.rsplit(netloc, ':', maxsplit=1)
try:
port = int(port)
except ValueError:
return None
else:
host = netloc
if scheme == "https":
port = 443
else:
port = 80
path = urlparse.urlunparse(('', '', path, params, query, fragment))
if not path.startswith("/"):
path = "/" + path
if not is_valid_host(host):
return None
if not utils.isascii(path):
return None
if not is_valid_port(port):
return None
return scheme, host, port, path
def get_header_tokens(headers, key):
"""
Retrieve all tokens for a header key. A number of different headers
follow a pattern where each header line can containe comma-separated
tokens, and headers can be set multiple times.
"""
toks = []
for i in headers[key]:
for j in i.split(","):
toks.append(j.strip())
return toks