adjust to new netlib Headers class

This commit is contained in:
Maximilian Hils 2015-09-05 20:45:58 +02:00
parent 00561d280c
commit 5125c669cc
22 changed files with 224 additions and 242 deletions

View File

@ -1,2 +1,2 @@
def response(context, flow): def response(context, flow):
flow.response.headers["newheader"] = ["foo"] flow.response.headers["newheader"] = "foo"

View File

@ -147,8 +147,8 @@ def response(context, flow):
response_body_size = len(flow.response.content) response_body_size = len(flow.response.content)
response_body_decoded_size = len(flow.response.get_decoded_content()) response_body_decoded_size = len(flow.response.get_decoded_content())
response_body_compression = response_body_decoded_size - response_body_size response_body_compression = response_body_decoded_size - response_body_size
response_mime_type = flow.response.headers.get_first('Content-Type', '') response_mime_type = flow.response.headers.get('Content-Type', '')
response_redirect_url = flow.response.headers.get_first('Location', '') response_redirect_url = flow.response.headers.get('Location', '')
entry = HAR.entries( entry = HAR.entries(
{ {
@ -201,12 +201,12 @@ def response(context, flow):
# Lookup the referer in the page_ref of context.HARLog to point this entries # Lookup the referer in the page_ref of context.HARLog to point this entries
# pageref attribute to the right pages object, then set it as a new # pageref attribute to the right pages object, then set it as a new
# reference to build a reference tree. # reference to build a reference tree.
elif context.HARLog.get_page_ref(flow.request.headers.get('Referer', (None, ))[0]) is not None: elif context.HARLog.get_page_ref(flow.request.headers.get('Referer')) is not None:
entry['pageref'] = context.HARLog.get_page_ref( entry['pageref'] = context.HARLog.get_page_ref(
flow.request.headers['Referer'][0] flow.request.headers['Referer']
) )
context.HARLog.set_page_ref( context.HARLog.set_page_ref(
flow.request.headers['Referer'][0], entry['pageref'] flow.request.headers['Referer'], entry['pageref']
) )
context.HARLog.add(entry) context.HARLog.add(entry)

View File

@ -1,5 +1,5 @@
def request(context, flow): def request(context, flow):
if "application/x-www-form-urlencoded" in flow.request.headers["content-type"]: if "application/x-www-form-urlencoded" in flow.request.headers.get("content-type", ""):
form = flow.request.get_form_urlencoded() form = flow.request.get_form_urlencoded()
form["mitmproxy"] = ["rocks"] form["mitmproxy"] = ["rocks"]
flow.request.set_form_urlencoded(form) flow.request.set_form_urlencoded(form)

View File

@ -2,8 +2,7 @@
This example shows two ways to redirect flows to other destinations. This example shows two ways to redirect flows to other destinations.
""" """
from libmproxy.models import HTTPResponse from libmproxy.models import HTTPResponse
from netlib.odict import ODictCaseless from netlib.http import Headers
def request(context, flow): def request(context, flow):
# pretty_host(hostheader=True) takes the Host: header of the request into account, # pretty_host(hostheader=True) takes the Host: header of the request into account,
@ -14,7 +13,7 @@ def request(context, flow):
if flow.request.pretty_host(hostheader=True).endswith("example.com"): if flow.request.pretty_host(hostheader=True).endswith("example.com"):
resp = HTTPResponse( resp = HTTPResponse(
[1, 1], 200, "OK", [1, 1], 200, "OK",
ODictCaseless([["Content-Type", "text/html"]]), Headers(Content_Type="text/html"),
"helloworld") "helloworld")
flow.reply(resp) flow.reply(resp)

View File

@ -23,16 +23,16 @@ class StickyMaster(controller.Master):
def handle_request(self, flow): def handle_request(self, flow):
hid = (flow.request.host, flow.request.port) hid = (flow.request.host, flow.request.port)
if flow.request.headers["cookie"]: if "cookie" in flow.request.headers:
self.stickyhosts[hid] = flow.request.headers["cookie"] self.stickyhosts[hid] = flow.request.headers.get_all("cookie")
elif hid in self.stickyhosts: elif hid in self.stickyhosts:
flow.request.headers["cookie"] = self.stickyhosts[hid] flow.request.headers.set_all("cookie", self.stickyhosts[hid])
flow.reply() flow.reply()
def handle_response(self, flow): def handle_response(self, flow):
hid = (flow.request.host, flow.request.port) hid = (flow.request.host, flow.request.port)
if flow.response.headers["set-cookie"]: if "set-cookie" in flow.response.headers:
self.stickyhosts[hid] = flow.response.headers["set-cookie"] self.stickyhosts[hid] = flow.response.headers.get_all("set-cookie")
flow.reply() flow.reply()

View File

@ -4,7 +4,7 @@ from libmproxy.models import decoded
def response(context, flow): def response(context, flow):
if flow.response.headers.get_first("content-type", "").startswith("image"): if flow.response.headers.get("content-type", "").startswith("image"):
with decoded(flow.response): # automatically decode gzipped responses. with decoded(flow.response): # automatically decode gzipped responses.
try: try:
s = cStringIO.StringIO(flow.response.content) s = cStringIO.StringIO(flow.response.content)
@ -12,6 +12,6 @@ def response(context, flow):
s2 = cStringIO.StringIO() s2 = cStringIO.StringIO()
img.save(s2, "png") img.save(s2, "png")
flow.response.content = s2.getvalue() flow.response.content = s2.getvalue()
flow.response.headers["content-type"] = ["image/png"] flow.response.headers["content-type"] = "image/png"
except: # Unknown image types etc. except: # Unknown image types etc.
pass pass

View File

@ -415,9 +415,9 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2,
resp_clen = contentdesc, resp_clen = contentdesc,
roundtrip = roundtrip, roundtrip = roundtrip,
)) ))
t = f.response.headers["content-type"] t = f.response.headers.get("content-type")
if t: if t:
d["resp_ctype"] = t[0].split(";")[0] d["resp_ctype"] = t.split(";")[0]
else: else:
d["resp_ctype"] = "" d["resp_ctype"] = ""
return flowcache.get( return flowcache.get(

View File

@ -12,7 +12,7 @@ import urwid
import html2text import html2text
import netlib.utils import netlib.utils
from netlib import odict, encoding from netlib import encoding
from . import common, signals from . import common, signals
from .. import utils from .. import utils
@ -74,7 +74,7 @@ class ViewAuto:
content_types = [] content_types = []
def __call__(self, hdrs, content, limit): def __call__(self, hdrs, content, limit):
ctype = hdrs.get_first("content-type") ctype = hdrs.get("content-type")
if ctype: if ctype:
ct = netlib.utils.parse_content_type(ctype) if ctype else None ct = netlib.utils.parse_content_type(ctype) if ctype else None
ct = "%s/%s" % (ct[0], ct[1]) ct = "%s/%s" % (ct[0], ct[1])
@ -508,7 +508,7 @@ def get(name):
return i return i
def get_content_view(viewmode, hdrItems, content, limit, is_request): def get_content_view(viewmode, headers, content, limit, is_request):
""" """
Returns a (msg, body) tuple. Returns a (msg, body) tuple.
""" """
@ -519,16 +519,14 @@ def get_content_view(viewmode, hdrItems, content, limit, is_request):
return "No content", "" return "No content", ""
msg = [] msg = []
hdrs = odict.ODictCaseless([list(i) for i in hdrItems]) enc = headers.get("content-encoding")
enc = hdrs.get_first("content-encoding")
if enc and enc != "identity": if enc and enc != "identity":
decoded = encoding.decode(enc, content) decoded = encoding.decode(enc, content)
if decoded: if decoded:
content = decoded content = decoded
msg.append("[decoded %s]" % enc) msg.append("[decoded %s]" % enc)
try: try:
ret = viewmode(hdrs, content, limit) ret = viewmode(headers, content, limit)
# Third-party viewers can fail in unexpected ways... # Third-party viewers can fail in unexpected ways...
except Exception: except Exception:
s = traceback.format_exc() s = traceback.format_exc()
@ -536,7 +534,7 @@ def get_content_view(viewmode, hdrItems, content, limit, is_request):
signals.add_event(s, "error") signals.add_event(s, "error")
ret = None ret = None
if not ret: if not ret:
ret = get("Raw")(hdrs, content, limit) ret = get("Raw")(headers, content, limit)
msg.append("Couldn't parse: falling back to Raw") msg.append("Couldn't parse: falling back to Raw")
else: else:
msg.append(ret[0]) msg.append(ret[0])

View File

@ -4,7 +4,7 @@ import sys
import urwid import urwid
from netlib import odict from netlib import odict
from netlib.http.semantics import CONTENT_MISSING from netlib.http.semantics import CONTENT_MISSING, Headers
from . import common, grideditor, contentview, signals, searchable, tabs from . import common, grideditor, contentview, signals, searchable, tabs
from . import flowdetailview from . import flowdetailview
@ -182,7 +182,7 @@ class FlowView(tabs.Tabs):
description, text_objects = cache.get( description, text_objects = cache.get(
contentview.get_content_view, contentview.get_content_view,
viewmode, viewmode,
tuple(tuple(i) for i in conn.headers.lst), conn.headers,
conn.content, conn.content,
limit, limit,
isinstance(conn, HTTPRequest) isinstance(conn, HTTPRequest)
@ -199,7 +199,7 @@ class FlowView(tabs.Tabs):
def conn_text(self, conn): def conn_text(self, conn):
if conn: if conn:
txt = common.format_keyvals( txt = common.format_keyvals(
[(h + ":", v) for (h, v) in conn.headers.lst], [(h + ":", v) for (h, v) in conn.headers.fields],
key = "header", key = "header",
val = "text" val = "text"
) )
@ -284,8 +284,8 @@ class FlowView(tabs.Tabs):
response.msg = msg response.msg = msg
signals.flow_change.send(self, flow = self.flow) signals.flow_change.send(self, flow = self.flow)
def set_headers(self, lst, conn): def set_headers(self, fields, conn):
conn.headers = odict.ODictCaseless(lst) conn.headers = Headers(fields)
signals.flow_change.send(self, flow = self.flow) signals.flow_change.send(self, flow = self.flow)
def set_query(self, lst, conn): def set_query(self, lst, conn):
@ -330,7 +330,7 @@ class FlowView(tabs.Tabs):
if not self.flow.response: if not self.flow.response:
self.flow.response = HTTPResponse( self.flow.response = HTTPResponse(
self.flow.request.httpversion, self.flow.request.httpversion,
200, "OK", odict.ODictCaseless(), "" 200, "OK", Headers(), ""
) )
self.flow.response.reply = controller.DummyReply() self.flow.response.reply = controller.DummyReply()
message = self.flow.response message = self.flow.response
@ -381,7 +381,7 @@ class FlowView(tabs.Tabs):
self.master.view_grideditor( self.master.view_grideditor(
grideditor.HeaderEditor( grideditor.HeaderEditor(
self.master, self.master,
message.headers.lst, message.headers.fields,
self.set_headers, self.set_headers,
message message
) )
@ -616,8 +616,7 @@ class FlowView(tabs.Tabs):
key = None key = None
elif key == "v": elif key == "v":
if conn.content: if conn.content:
t = conn.headers["content-type"] or [None] t = conn.headers.get("content-type")
t = t[0]
if "EDITOR" in os.environ or "PAGER" in os.environ: if "EDITOR" in os.environ or "PAGER" in os.environ:
self.master.spawn_external_viewer(conn.content, t) self.master.spawn_external_viewer(conn.content, t)
else: else:
@ -626,7 +625,7 @@ class FlowView(tabs.Tabs):
) )
elif key == "z": elif key == "z":
self.flow.backup() self.flow.backup()
e = conn.headers.get_first("content-encoding", "identity") e = conn.headers.get("content-encoding", "identity")
if e != "identity": if e != "identity":
if not conn.decode(): if not conn.decode():
signals.status_message.send( signals.status_message.send(

View File

@ -174,7 +174,7 @@ class DumpMaster(flow.FlowMaster):
def _print_message(self, message): def _print_message(self, message):
if self.o.flow_detail >= 2: if self.o.flow_detail >= 2:
print(self.indent(4, message.headers.format()), file=self.outfile) print(self.indent(4, str(message.headers)), file=self.outfile)
if self.o.flow_detail >= 3: if self.o.flow_detail >= 3:
if message.content == CONTENT_MISSING: if message.content == CONTENT_MISSING:
print(self.indent(4, "(content missing)"), file=self.outfile) print(self.indent(4, "(content missing)"), file=self.outfile)

View File

@ -77,17 +77,19 @@ class FResp(_Action):
class _Rex(_Action): class _Rex(_Action):
flags = 0
def __init__(self, expr): def __init__(self, expr):
self.expr = expr self.expr = expr
try: try:
self.re = re.compile(self.expr) self.re = re.compile(self.expr, self.flags)
except: except:
raise ValueError("Cannot compile expression.") raise ValueError("Cannot compile expression.")
def _check_content_type(expr, o): def _check_content_type(expr, o):
val = o.headers["content-type"] val = o.headers.get("content-type")
if val and re.search(expr, val[0]): if val and re.search(expr, val):
return True return True
return False return False
@ -145,11 +147,12 @@ class FResponseContentType(_Rex):
class FHead(_Rex): class FHead(_Rex):
code = "h" code = "h"
help = "Header" help = "Header"
flags = re.MULTILINE
def __call__(self, f): def __call__(self, f):
if f.request.headers.match_re(self.expr): if f.request and self.re.search(str(f.request.headers)):
return True return True
elif f.response and f.response.headers.match_re(self.expr): if f.response and self.re.search(str(f.response.headers)):
return True return True
return False return False
@ -157,18 +160,20 @@ class FHead(_Rex):
class FHeadRequest(_Rex): class FHeadRequest(_Rex):
code = "hq" code = "hq"
help = "Request header" help = "Request header"
flags = re.MULTILINE
def __call__(self, f): def __call__(self, f):
if f.request.headers.match_re(self.expr): if f.request and self.re.search(str(f.request.headers)):
return True return True
class FHeadResponse(_Rex): class FHeadResponse(_Rex):
code = "hs" code = "hs"
help = "Response header" help = "Response header"
flags = re.MULTILINE
def __call__(self, f): def __call__(self, f):
if f.response and f.response.headers.match_re(self.expr): if f.response and self.re.search(str(f.response.headers)):
return True return True
@ -178,10 +183,10 @@ class FBod(_Rex):
def __call__(self, f): def __call__(self, f):
if f.request and f.request.content: if f.request and f.request.content:
if re.search(self.expr, f.request.get_decoded_content()): if self.re.search(f.request.get_decoded_content()):
return True return True
if f.response and f.response.content: if f.response and f.response.content:
if re.search(self.expr, f.response.get_decoded_content()): if self.re.search(f.response.get_decoded_content()):
return True return True
return False return False
@ -192,7 +197,7 @@ class FBodRequest(_Rex):
def __call__(self, f): def __call__(self, f):
if f.request and f.request.content: if f.request and f.request.content:
if re.search(self.expr, f.request.get_decoded_content()): if self.re.search(f.request.get_decoded_content()):
return True return True
@ -202,24 +207,26 @@ class FBodResponse(_Rex):
def __call__(self, f): def __call__(self, f):
if f.response and f.response.content: if f.response and f.response.content:
if re.search(self.expr, f.response.get_decoded_content()): if self.re.search(f.response.get_decoded_content()):
return True return True
class FMethod(_Rex): class FMethod(_Rex):
code = "m" code = "m"
help = "Method" help = "Method"
flags = re.IGNORECASE
def __call__(self, f): def __call__(self, f):
return bool(re.search(self.expr, f.request.method, re.IGNORECASE)) return bool(self.re.search(f.request.method))
class FDomain(_Rex): class FDomain(_Rex):
code = "d" code = "d"
help = "Domain" help = "Domain"
flags = re.IGNORECASE
def __call__(self, f): def __call__(self, f):
return bool(re.search(self.expr, f.request.host, re.IGNORECASE)) return bool(self.re.search(f.request.host))
class FUrl(_Rex): class FUrl(_Rex):
@ -234,21 +241,24 @@ class FUrl(_Rex):
return klass(*toks) return klass(*toks)
def __call__(self, f): def __call__(self, f):
return re.search(self.expr, f.request.url) return self.re.search(f.request.url)
class FSrc(_Rex): class FSrc(_Rex):
code = "src" code = "src"
help = "Match source address" help = "Match source address"
def __call__(self, f): def __call__(self, f):
return f.client_conn.address and re.search(self.expr, repr(f.client_conn.address)) return f.client_conn.address and self.re.search(repr(f.client_conn.address))
class FDst(_Rex): class FDst(_Rex):
code = "dst" code = "dst"
help = "Match destination address" help = "Match destination address"
def __call__(self, f): def __call__(self, f):
return f.server_conn.address and re.search(self.expr, repr(f.server_conn.address)) return f.server_conn.address and self.re.search(repr(f.server_conn.address))
class _Int(_Action): class _Int(_Action):
def __init__(self, num): def __init__(self, num):

View File

@ -11,8 +11,8 @@ import re
import urlparse import urlparse
from netlib import odict, wsgi from netlib import wsgi
from netlib.http.semantics import CONTENT_MISSING from netlib.http.semantics import CONTENT_MISSING, Headers
import netlib.http import netlib.http
from . import controller, tnetstring, filt, script, version from . import controller, tnetstring, filt, script, version
from .onboarding import app from .onboarding import app
@ -45,7 +45,7 @@ class AppRegistry:
if (request.host, request.port) in self.apps: if (request.host, request.port) in self.apps:
return self.apps[(request.host, request.port)] return self.apps[(request.host, request.port)]
if "host" in request.headers: if "host" in request.headers:
host = request.headers["host"][0] host = request.headers["host"]
return self.apps.get((host, request.port), None) return self.apps.get((host, request.port), None)
@ -144,15 +144,15 @@ class SetHeaders:
for _, header, value, cpatt in self.lst: for _, header, value, cpatt in self.lst:
if cpatt(f): if cpatt(f):
if f.response: if f.response:
del f.response.headers[header] f.response.headers.pop(header, None)
else: else:
del f.request.headers[header] f.request.headers.pop(header, None)
for _, header, value, cpatt in self.lst: for _, header, value, cpatt in self.lst:
if cpatt(f): if cpatt(f):
if f.response: if f.response:
f.response.headers.add(header, value) f.response.headers.fields.append((header, value))
else: else:
f.request.headers.add(header, value) f.request.headers.fields.append((header, value))
class StreamLargeBodies(object): class StreamLargeBodies(object):
@ -278,14 +278,11 @@ class ServerPlaybackState:
key.append(p[1]) key.append(p[1])
if self.headers: if self.headers:
hdrs = [] headers = []
for i in self.headers: for i in self.headers:
v = r.headers[i] v = r.headers.get(i)
# Slightly subtle: we need to convert everything to strings headers.append((i, v))
# to prevent a mismatch between unicode/non-unicode. key.append(headers)
v = [str(x) for x in v]
hdrs.append((i, v))
key.append(hdrs)
return hashlib.sha256(repr(key)).digest() return hashlib.sha256(repr(key)).digest()
def next_flow(self, request): def next_flow(self, request):
@ -329,7 +326,7 @@ class StickyCookieState:
return False return False
def handle_response(self, f): def handle_response(self, f):
for i in f.response.headers["set-cookie"]: for i in f.response.headers.get_all("set-cookie"):
# FIXME: We now know that Cookie.py screws up some cookies with # FIXME: We now know that Cookie.py screws up some cookies with
# valid RFC 822/1123 datetime specifications for expiry. Sigh. # valid RFC 822/1123 datetime specifications for expiry. Sigh.
c = Cookie.SimpleCookie(str(i)) c = Cookie.SimpleCookie(str(i))
@ -351,7 +348,7 @@ class StickyCookieState:
l.append(self.jar[i].output(header="").strip()) l.append(self.jar[i].output(header="").strip())
if l: if l:
f.request.stickycookie = True f.request.stickycookie = True
f.request.headers["cookie"] = l f.request.headers.set_all("cookie",l)
class StickyAuthState: class StickyAuthState:
@ -836,7 +833,7 @@ class FlowMaster(controller.Master):
ssl_established=True ssl_established=True
)) ))
f = HTTPFlow(c, s) f = HTTPFlow(c, s)
headers = odict.ODictCaseless() headers = Headers()
req = HTTPRequest( req = HTTPRequest(
"absolute", "absolute",
@ -930,8 +927,7 @@ class FlowMaster(controller.Master):
f.backup() f.backup()
f.request.is_replay = True f.request.is_replay = True
if f.request.content: if f.request.content:
f.request.headers[ f.request.headers["Content-Length"] = str(len(f.request.content))
"Content-Length"] = [str(len(f.request.content))]
f.response = None f.response = None
f.error = None f.error = None
self.process_new_request(f) self.process_new_request(f)

View File

@ -5,8 +5,8 @@ from email.utils import parsedate_tz, formatdate, mktime_tz
import time import time
from libmproxy import utils from libmproxy import utils
from netlib import odict, encoding from netlib import encoding
from netlib.http import status_codes from netlib.http import status_codes, Headers
from netlib.tcp import Address from netlib.tcp import Address
from netlib.http.semantics import Request, Response, CONTENT_MISSING from netlib.http.semantics import Request, Response, CONTENT_MISSING
from .. import version, stateobject from .. import version, stateobject
@ -16,7 +16,7 @@ from .flow import Flow
class MessageMixin(stateobject.StateObject): class MessageMixin(stateobject.StateObject):
_stateobject_attributes = dict( _stateobject_attributes = dict(
httpversion=tuple, httpversion=tuple,
headers=odict.ODictCaseless, headers=Headers,
body=str, body=str,
timestamp_start=float, timestamp_start=float,
timestamp_end=float timestamp_end=float
@ -40,7 +40,7 @@ class MessageMixin(stateobject.StateObject):
header. header.
Doesn't change the message iteself or its headers. Doesn't change the message iteself or its headers.
""" """
ce = self.headers.get_first("content-encoding") ce = self.headers.get("content-encoding")
if not self.body or ce not in encoding.ENCODINGS: if not self.body or ce not in encoding.ENCODINGS:
return self.body return self.body
return encoding.decode(ce, self.body) return encoding.decode(ce, self.body)
@ -53,14 +53,14 @@ class MessageMixin(stateobject.StateObject):
Returns True if decoding succeeded, False otherwise. Returns True if decoding succeeded, False otherwise.
""" """
ce = self.headers.get_first("content-encoding") ce = self.headers.get("content-encoding")
if not self.body or ce not in encoding.ENCODINGS: if not self.body or ce not in encoding.ENCODINGS:
return False return False
data = encoding.decode(ce, self.body) data = encoding.decode(ce, self.body)
if data is None: if data is None:
return False return False
self.body = data self.body = data
del self.headers["content-encoding"] self.headers.pop("content-encoding", None)
return True return True
def encode(self, e): def encode(self, e):
@ -70,7 +70,7 @@ class MessageMixin(stateobject.StateObject):
""" """
# 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.body = encoding.encode(e, self.body)
self.headers["content-encoding"] = [e] self.headers["content-encoding"] = e
def copy(self): def copy(self):
c = copy.copy(self) c = copy.copy(self)
@ -86,11 +86,18 @@ class MessageMixin(stateobject.StateObject):
Returns the number of replacements made. Returns the number of replacements made.
""" """
with decoded(self): with decoded(self):
self.body, c = utils.safe_subn( self.body, count = utils.safe_subn(
pattern, repl, self.body, *args, **kwargs pattern, repl, self.body, *args, **kwargs
) )
c += self.headers.replace(pattern, repl, *args, **kwargs) fields = []
return c for name, value in self.headers.fields:
name, c = utils.safe_subn(pattern, repl, name, *args, **kwargs)
count += c
value, c = utils.safe_subn(pattern, repl, value, *args, **kwargs)
count += c
fields.append([name, value])
self.headers.fields = fields
return count
class HTTPRequest(MessageMixin, Request): class HTTPRequest(MessageMixin, Request):
@ -115,7 +122,7 @@ class HTTPRequest(MessageMixin, Request):
httpversion: HTTP version tuple, e.g. (1,1) httpversion: HTTP version tuple, e.g. (1,1)
headers: odict.ODictCaseless object headers: Headers object
content: Content of the request, None, or CONTENT_MISSING if there content: Content of the request, None, or CONTENT_MISSING if there
is content associated, but not present. CONTENT_MISSING evaluates is content associated, but not present. CONTENT_MISSING evaluates
@ -266,7 +273,7 @@ class HTTPResponse(MessageMixin, Response):
msg: HTTP response message msg: HTTP response message
headers: ODict Caseless object headers: Headers object
content: Content of the request, None, or CONTENT_MISSING if there content: Content of the request, None, or CONTENT_MISSING if there
is content associated, but not present. CONTENT_MISSING evaluates is content associated, but not present. CONTENT_MISSING evaluates
@ -379,15 +386,15 @@ class HTTPResponse(MessageMixin, Response):
] ]
for i in refresh_headers: for i in refresh_headers:
if i in self.headers: if i in self.headers:
d = parsedate_tz(self.headers[i][0]) d = parsedate_tz(self.headers[i])
if d: if d:
new = mktime_tz(d) + delta new = mktime_tz(d) + delta
self.headers[i] = [formatdate(new)] self.headers[i] = formatdate(new)
c = [] c = []
for i in self.headers["set-cookie"]: for i in self.headers.get_all("set-cookie"):
c.append(self._refresh_cookie(i, delta)) c.append(self._refresh_cookie(i, delta))
if c: if c:
self.headers["set-cookie"] = c self.headers.set_all("set-cookie", c)
class HTTPFlow(Flow): class HTTPFlow(Flow):
@ -490,7 +497,7 @@ class decoded(object):
def __init__(self, o): def __init__(self, o):
self.o = o self.o = o
ce = o.headers.get_first("content-encoding") ce = o.headers.get("content-encoding")
if ce in encoding.ENCODINGS: if ce in encoding.ENCODINGS:
self.ce = ce self.ce = ce
else: else:
@ -517,11 +524,12 @@ def make_error_response(status_code, message, headers=None):
""".strip() % (status_code, response, message) """.strip() % (status_code, response, message)
if not headers: if not headers:
headers = odict.ODictCaseless() headers = Headers(
headers["Server"] = [version.NAMEVERSION] Server=version.NAMEVERSION,
headers["Connection"] = ["close"] Connection="close",
headers["Content-Length"] = [len(body)] Content_Length=str(len(body)),
headers["Content-Type"] = ["text/html"] Content_Type="text/html"
)
return HTTPResponse( return HTTPResponse(
(1, 1), # FIXME: Should be a string. (1, 1), # FIXME: Should be a string.
@ -536,15 +544,15 @@ def make_connect_request(address):
address = Address.wrap(address) address = Address.wrap(address)
return HTTPRequest( return HTTPRequest(
"authority", "CONNECT", None, address.host, address.port, None, (1, 1), "authority", "CONNECT", None, address.host, address.port, None, (1, 1),
odict.ODictCaseless(), "" Headers(), ""
) )
def make_connect_response(httpversion): def make_connect_response(httpversion):
headers = odict.ODictCaseless([ headers = Headers(
["Content-Length", "0"], Content_Length="0",
["Proxy-Agent", version.NAMEVERSION] Proxy_Agent=version.NAMEVERSION
]) )
return HTTPResponse( return HTTPResponse(
httpversion, httpversion,
200, 200,

View File

@ -1,7 +1,7 @@
from __future__ import (absolute_import, print_function, division) from __future__ import (absolute_import, print_function, division)
from netlib import tcp from netlib import tcp
from netlib.http import http1, HttpErrorConnClosed, HttpError from netlib.http import http1, HttpErrorConnClosed, HttpError, Headers
from netlib.http.semantics import CONTENT_MISSING from netlib.http.semantics import CONTENT_MISSING
from netlib import odict from netlib import odict
from netlib.tcp import NetLibError, Address from netlib.tcp import NetLibError, Address
@ -568,10 +568,6 @@ class HttpLayer(Layer):
self.send_response(make_error_response( self.send_response(make_error_response(
407, 407,
"Proxy Authentication Required", "Proxy Authentication Required",
odict.ODictCaseless( Headers(**self.config.authenticator.auth_challenge_headers())
[
[k, v] for k, v in
self.config.authenticator.auth_challenge_headers().items()
])
)) ))
raise InvalidCredentials("Proxy Authentication Required") raise InvalidCredentials("Proxy Authentication Required")

View File

@ -27,8 +27,7 @@ class RequestHandler(tornado.web.RequestHandler):
@property @property
def json(self): def json(self):
if not self.request.headers.get( if not self.request.headers.get("Content-Type").startswith("application/json"):
"Content-Type").startswith("application/json"):
return None return None
return json.loads(self.request.body) return json.loads(self.request.body)
@ -186,12 +185,12 @@ class FlowContent(RequestHandler):
if not message.content: if not message.content:
raise APIError(400, "No content.") raise APIError(400, "No content.")
content_encoding = message.headers.get_first("Content-Encoding", None) content_encoding = message.headers.get("Content-Encoding", None)
if content_encoding: if content_encoding:
content_encoding = re.sub(r"[^\w]", "", content_encoding) content_encoding = re.sub(r"[^\w]", "", content_encoding)
self.set_header("Content-Encoding", content_encoding) self.set_header("Content-Encoding", content_encoding)
original_cd = message.headers.get_first("Content-Disposition", None) original_cd = message.headers.get("Content-Disposition", None)
filename = None filename = None
if original_cd: if original_cd:
filename = re.search("filename=([\w\" \.\-\(\)]+)", original_cd) filename = re.search("filename=([\w\" \.\-\(\)]+)", original_cd)

View File

@ -1,11 +1,13 @@
import os import os
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
from netlib.http import Headers
if os.name == "nt": if os.name == "nt":
raise SkipTest("Skipped on Windows.") raise SkipTest("Skipped on Windows.")
import sys import sys
import netlib.utils import netlib.utils
from netlib import odict, encoding from netlib import encoding
import libmproxy.console.contentview as cv import libmproxy.console.contentview as cv
from libmproxy import utils, flow from libmproxy import utils, flow
@ -33,34 +35,28 @@ class TestContentView:
def test_view_auto(self): def test_view_auto(self):
v = cv.ViewAuto() v = cv.ViewAuto()
f = v( f = v(
odict.ODictCaseless(), Headers(),
"foo", "foo",
1000 1000
) )
assert f[0] == "Raw" assert f[0] == "Raw"
f = v( f = v(
odict.ODictCaseless( Headers(content_type="text/html"),
[["content-type", "text/html"]],
),
"<html></html>", "<html></html>",
1000 1000
) )
assert f[0] == "HTML" assert f[0] == "HTML"
f = v( f = v(
odict.ODictCaseless( Headers(content_type="text/flibble"),
[["content-type", "text/flibble"]],
),
"foo", "foo",
1000 1000
) )
assert f[0] == "Raw" assert f[0] == "Raw"
f = v( f = v(
odict.ODictCaseless( Headers(content_type="text/flibble"),
[["content-type", "text/flibble"]],
),
"<xml></xml>", "<xml></xml>",
1000 1000
) )
@ -168,28 +164,22 @@ Content-Disposition: form-data; name="submit-name"
Larry Larry
--AaB03x --AaB03x
""".strip() """.strip()
h = odict.ODictCaseless( h = Headers(content_type="multipart/form-data; boundary=AaB03x"),
[("Content-Type", "multipart/form-data; boundary=AaB03x")]
)
assert view(h, v, 1000) assert view(h, v, 1000)
h = odict.ODictCaseless() h = Headers(),
assert not view(h, v, 1000) assert not view(h, v, 1000)
h = odict.ODictCaseless( h = Headers(content_type="multipart/form-data"),
[("Content-Type", "multipart/form-data")]
)
assert not view(h, v, 1000) assert not view(h, v, 1000)
h = odict.ODictCaseless( h = Headers(content_type="unparseable"),
[("Content-Type", "unparseable")]
)
assert not view(h, v, 1000) assert not view(h, v, 1000)
def test_get_content_view(self): def test_get_content_view(self):
r = cv.get_content_view( r = cv.get_content_view(
cv.get("Raw"), cv.get("Raw"),
[["content-type", "application/json"]], Headers(content_type="application/json"),
"[1, 2, 3]", "[1, 2, 3]",
1000, 1000,
False False
@ -198,7 +188,7 @@ Larry
r = cv.get_content_view( r = cv.get_content_view(
cv.get("Auto"), cv.get("Auto"),
[["content-type", "application/json"]], Headers(content_type="application/json"),
"[1, 2, 3]", "[1, 2, 3]",
1000, 1000,
False False
@ -207,7 +197,7 @@ Larry
r = cv.get_content_view( r = cv.get_content_view(
cv.get("Auto"), cv.get("Auto"),
[["content-type", "application/json"]], Headers(content_type="application/json"),
"[1, 2", "[1, 2",
1000, 1000,
False False
@ -216,7 +206,7 @@ Larry
r = cv.get_content_view( r = cv.get_content_view(
cv.get("AMF"), cv.get("AMF"),
[], Headers(),
"[1, 2", "[1, 2",
1000, 1000,
False False
@ -225,10 +215,10 @@ Larry
r = cv.get_content_view( r = cv.get_content_view(
cv.get("Auto"), cv.get("Auto"),
[ Headers(
["content-type", "application/json"], content_type="application/json",
["content-encoding", "gzip"] content_encoding="gzip"
], ),
encoding.encode('gzip', "[1, 2, 3]"), encoding.encode('gzip', "[1, 2, 3]"),
1000, 1000,
False False
@ -238,10 +228,10 @@ Larry
r = cv.get_content_view( r = cv.get_content_view(
cv.get("XML"), cv.get("XML"),
[ Headers(
["content-type", "application/json"], content_type="application/json",
["content-encoding", "gzip"] content_encoding="gzip"
], ),
encoding.encode('gzip', "[1, 2, 3]"), encoding.encode('gzip', "[1, 2, 3]"),
1000, 1000,
False False

View File

@ -145,7 +145,7 @@ class TestDumpMaster:
o = dump.Options(setheaders=[(".*", "one", "two")]) o = dump.Options(setheaders=[(".*", "one", "two")])
m = dump.DumpMaster(None, o, outfile=cs) m = dump.DumpMaster(None, o, outfile=cs)
f = self._cycle(m, "content") f = self._cycle(m, "content")
assert f.request.headers["one"] == ["two"] assert f.request.headers["one"] == "two"
def test_basic(self): def test_basic(self):
for i in (1, 2, 3): for i in (1, 2, 3):

View File

@ -1,8 +1,8 @@
import cStringIO import cStringIO
from netlib import odict
from libmproxy import filt, flow from libmproxy import filt, flow
from libmproxy.protocol import http from libmproxy.protocol import http
from libmproxy.models import Error from libmproxy.models import Error
from netlib.http import Headers
import tutils import tutils
@ -76,8 +76,7 @@ class TestParsing:
class TestMatching: class TestMatching:
def req(self): def req(self):
headers = odict.ODictCaseless() headers = Headers(header="qvalue")
headers["header"] = ["qvalue"]
req = http.HTTPRequest( req = http.HTTPRequest(
"absolute", "absolute",
"GET", "GET",
@ -98,8 +97,7 @@ class TestMatching:
def resp(self): def resp(self):
f = self.req() f = self.req()
headers = odict.ODictCaseless() headers = Headers([["header_response", "svalue"]])
headers["header_response"] = ["svalue"]
f.response = http.HTTPResponse( f.response = http.HTTPResponse(
(1, (1,
1), 1),
@ -123,7 +121,7 @@ class TestMatching:
def test_asset(self): def test_asset(self):
s = self.resp() s = self.resp()
assert not self.q("~a", s) assert not self.q("~a", s)
s.response.headers["content-type"] = ["text/javascript"] s.response.headers["content-type"] = "text/javascript"
assert self.q("~a", s) assert self.q("~a", s)
def test_fcontenttype(self): def test_fcontenttype(self):
@ -132,16 +130,16 @@ class TestMatching:
assert not self.q("~t content", q) assert not self.q("~t content", q)
assert not self.q("~t content", s) assert not self.q("~t content", s)
q.request.headers["content-type"] = ["text/json"] q.request.headers["content-type"] = "text/json"
assert self.q("~t json", q) assert self.q("~t json", q)
assert self.q("~tq json", q) assert self.q("~tq json", q)
assert not self.q("~ts json", q) assert not self.q("~ts json", q)
s.response.headers["content-type"] = ["text/json"] s.response.headers["content-type"] = "text/json"
assert self.q("~t json", s) assert self.q("~t json", s)
del s.response.headers["content-type"] del s.response.headers["content-type"]
s.request.headers["content-type"] = ["text/json"] s.request.headers["content-type"] = "text/json"
assert self.q("~t json", s) assert self.q("~t json", s)
assert self.q("~tq json", s) assert self.q("~tq json", s)
assert not self.q("~ts json", s) assert not self.q("~ts json", s)

View File

@ -8,7 +8,7 @@ import mock
import netlib.utils import netlib.utils
from netlib import odict from netlib import odict
from netlib.http.semantics import CONTENT_MISSING, HDR_FORM_URLENCODED from netlib.http.semantics import CONTENT_MISSING, HDR_FORM_URLENCODED, Headers
from libmproxy import filt, protocol, controller, tnetstring, flow from libmproxy import filt, protocol, 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
@ -34,7 +34,7 @@ def test_app_registry():
r.host = "domain2" r.host = "domain2"
r.port = 80 r.port = 80
assert not ar.get(r) assert not ar.get(r)
r.headers["host"] = ["domain"] r.headers["host"] = "domain"
assert ar.get(r) assert ar.get(r)
@ -42,7 +42,7 @@ class TestStickyCookieState:
def _response(self, cookie, host): def _response(self, cookie, host):
s = flow.StickyCookieState(filt.parse(".*")) s = flow.StickyCookieState(filt.parse(".*"))
f = tutils.tflow(req=netlib.tutils.treq(host=host, port=80), resp=True) f = tutils.tflow(req=netlib.tutils.treq(host=host, port=80), resp=True)
f.response.headers["Set-Cookie"] = [cookie] f.response.headers["Set-Cookie"] = cookie
s.handle_response(f) s.handle_response(f)
return s, f return s, f
@ -75,13 +75,13 @@ class TestStickyAuthState:
def test_handle_response(self): def test_handle_response(self):
s = flow.StickyAuthState(filt.parse(".*")) s = flow.StickyAuthState(filt.parse(".*"))
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
f.request.headers["authorization"] = ["foo"] f.request.headers["authorization"] = "foo"
s.handle_request(f) s.handle_request(f)
assert "address" in s.hosts assert "address" in s.hosts
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
s.handle_request(f) s.handle_request(f)
assert f.request.headers["authorization"] == ["foo"] assert f.request.headers["authorization"] == "foo"
class TestClientPlaybackState: class TestClientPlaybackState:
@ -133,7 +133,7 @@ class TestServerPlaybackState:
assert s._hash(r) assert s._hash(r)
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
r.request.headers["foo"] = ["bar"] r.request.headers["foo"] = "bar"
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
r.request.path = "voing" r.request.path = "voing"
assert s._hash(r) != s._hash(r2) assert s._hash(r) != s._hash(r2)
@ -153,12 +153,12 @@ class TestServerPlaybackState:
None, None,
False) False)
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
r.request.headers["foo"] = ["bar"] r.request.headers["foo"] = "bar"
r2 = tutils.tflow(resp=True) r2 = tutils.tflow(resp=True)
assert not s._hash(r) == s._hash(r2) assert not s._hash(r) == s._hash(r2)
r2.request.headers["foo"] = ["bar"] r2.request.headers["foo"] = "bar"
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
r2.request.headers["oink"] = ["bar"] r2.request.headers["oink"] = "bar"
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
@ -167,10 +167,10 @@ class TestServerPlaybackState:
def test_load(self): def test_load(self):
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
r.request.headers["key"] = ["one"] r.request.headers["key"] = "one"
r2 = tutils.tflow(resp=True) r2 = tutils.tflow(resp=True)
r2.request.headers["key"] = ["two"] r2.request.headers["key"] = "two"
s = flow.ServerPlaybackState( s = flow.ServerPlaybackState(
None, [ None, [
@ -179,21 +179,21 @@ class TestServerPlaybackState:
assert len(s.fmap.keys()) == 1 assert len(s.fmap.keys()) == 1
n = s.next_flow(r) n = s.next_flow(r)
assert n.request.headers["key"] == ["one"] assert n.request.headers["key"] == "one"
assert s.count() == 1 assert s.count() == 1
n = s.next_flow(r) n = s.next_flow(r)
assert n.request.headers["key"] == ["two"] assert n.request.headers["key"] == "two"
assert s.count() == 0 assert s.count() == 0
assert not s.next_flow(r) assert not s.next_flow(r)
def test_load_with_nopop(self): def test_load_with_nopop(self):
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
r.request.headers["key"] = ["one"] r.request.headers["key"] = "one"
r2 = tutils.tflow(resp=True) r2 = tutils.tflow(resp=True)
r2.request.headers["key"] = ["two"] r2.request.headers["key"] = "two"
s = flow.ServerPlaybackState( s = flow.ServerPlaybackState(
None, [ None, [
@ -224,12 +224,10 @@ class TestServerPlaybackState:
None, [], False, False, None, False, [ None, [], False, False, None, False, [
"param1", "param2"], False) "param1", "param2"], False)
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
r.request.headers[ r.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
"Content-Type"] = ["application/x-www-form-urlencoded"]
r.request.content = "paramx=x&param1=1" r.request.content = "paramx=x&param1=1"
r2 = tutils.tflow(resp=True) r2 = tutils.tflow(resp=True)
r2.request.headers[ r2.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
"Content-Type"] = ["application/x-www-form-urlencoded"]
r2.request.content = "paramx=x&param1=1" r2.request.content = "paramx=x&param1=1"
# same parameters # same parameters
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
@ -254,10 +252,10 @@ class TestServerPlaybackState:
None, [], False, False, None, False, [ None, [], False, False, None, False, [
"param1", "param2"], False) "param1", "param2"], False)
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
r.request.headers["Content-Type"] = ["application/json"] r.request.headers["Content-Type"] = "application/json"
r.request.content = '{"param1":"1"}' r.request.content = '{"param1":"1"}'
r2 = tutils.tflow(resp=True) r2 = tutils.tflow(resp=True)
r2.request.headers["Content-Type"] = ["application/json"] r2.request.headers["Content-Type"] = "application/json"
r2.request.content = '{"param1":"1"}' r2.request.content = '{"param1":"1"}'
# same content # same content
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
@ -271,12 +269,10 @@ class TestServerPlaybackState:
None, [], False, False, None, True, [ None, [], False, False, None, True, [
"param1", "param2"], False) "param1", "param2"], False)
r = tutils.tflow(resp=True) r = tutils.tflow(resp=True)
r.request.headers[ r.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
"Content-Type"] = ["application/x-www-form-urlencoded"]
r.request.content = "paramx=y" r.request.content = "paramx=y"
r2 = tutils.tflow(resp=True) r2 = tutils.tflow(resp=True)
r2.request.headers[ r2.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
"Content-Type"] = ["application/x-www-form-urlencoded"]
r2.request.content = "paramx=x" r2.request.content = "paramx=x"
# same parameters # same parameters
assert s._hash(r) == s._hash(r2) assert s._hash(r) == s._hash(r2)
@ -460,17 +456,17 @@ class TestFlow:
def test_replace(self): def test_replace(self):
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
f.request.headers["foo"] = ["foo"] f.request.headers["foo"] = "foo"
f.request.content = "afoob" f.request.content = "afoob"
f.response.headers["foo"] = ["foo"] f.response.headers["foo"] = "foo"
f.response.content = "afoob" f.response.content = "afoob"
assert f.replace("foo", "bar") == 6 assert f.replace("foo", "bar") == 6
assert f.request.headers["bar"] == ["bar"] assert f.request.headers["bar"] == "bar"
assert f.request.content == "abarb" assert f.request.content == "abarb"
assert f.response.headers["bar"] == ["bar"] assert f.response.headers["bar"] == "bar"
assert f.response.content == "abarb" assert f.response.content == "abarb"
def test_replace_encoded(self): def test_replace_encoded(self):
@ -938,14 +934,14 @@ class TestFlowMaster:
fm.set_stickycookie(".*") fm.set_stickycookie(".*")
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
f.response.headers["set-cookie"] = ["foo=bar"] f.response.headers["set-cookie"] = "foo=bar"
fm.handle_request(f) fm.handle_request(f)
fm.handle_response(f) fm.handle_response(f)
assert fm.stickycookie_state.jar assert fm.stickycookie_state.jar
assert not "cookie" in f.request.headers assert not "cookie" in f.request.headers
f = f.copy() f = f.copy()
fm.handle_request(f) fm.handle_request(f)
assert f.request.headers["cookie"] == ["foo=bar"] assert f.request.headers["cookie"] == "foo=bar"
def test_stickyauth(self): def test_stickyauth(self):
s = flow.State() s = flow.State()
@ -958,14 +954,14 @@ class TestFlowMaster:
fm.set_stickyauth(".*") fm.set_stickyauth(".*")
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
f.request.headers["authorization"] = ["foo"] f.request.headers["authorization"] = "foo"
fm.handle_request(f) fm.handle_request(f)
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
assert fm.stickyauth_state.hosts assert fm.stickyauth_state.hosts
assert not "authorization" in f.request.headers assert not "authorization" in f.request.headers
fm.handle_request(f) fm.handle_request(f)
assert f.request.headers["authorization"] == ["foo"] assert f.request.headers["authorization"] == "foo"
def test_stream(self): def test_stream(self):
with tutils.tmpdir() as tdir: with tutils.tmpdir() as tdir:
@ -1022,7 +1018,7 @@ class TestRequest:
assert r.url == "https://address:22/path" assert r.url == "https://address:22/path"
assert r.pretty_url(True) == "https://address:22/path" assert r.pretty_url(True) == "https://address:22/path"
r.headers["Host"] = ["foo.com"] r.headers["Host"] = "foo.com"
assert r.pretty_url(False) == "https://address:22/path" assert r.pretty_url(False) == "https://address:22/path"
assert r.pretty_url(True) == "https://foo.com:22/path" assert r.pretty_url(True) == "https://foo.com:22/path"
@ -1048,19 +1044,17 @@ 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"] = HDR_FORM_URLENCODED
assert r.get_form_urlencoded() == d assert r.get_form_urlencoded() == d
d = odict.ODict([("x", "y")]) d = odict.ODict([("x", "y")])
r.set_form_urlencoded(d) r.set_form_urlencoded(d)
assert r.get_form_urlencoded() == d assert r.get_form_urlencoded() == d
r.headers["content-type"] = ["foo"] r.headers["content-type"] = "foo"
assert not r.get_form_urlencoded() assert not r.get_form_urlencoded()
def test_getset_query(self): def test_getset_query(self):
h = odict.ODictCaseless()
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.path = "/foo?x=y&a=b" r.path = "/foo?x=y&a=b"
q = r.get_query() q = r.get_query()
@ -1083,11 +1077,10 @@ class TestRequest:
assert r.get_query() == qv assert r.get_query() == qv
def test_anticache(self): def test_anticache(self):
h = odict.ODictCaseless()
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.headers = h r.headers = Headers()
h["if-modified-since"] = ["test"] r.headers["if-modified-since"] = "test"
h["if-none-match"] = ["test"] r.headers["if-none-match"] = "test"
r.anticache() r.anticache()
assert not "if-modified-since" in r.headers assert not "if-modified-since" in r.headers
assert not "if-none-match" in r.headers assert not "if-none-match" in r.headers
@ -1095,25 +1088,29 @@ class TestRequest:
def test_replace(self): def test_replace(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.path = "path/foo" r.path = "path/foo"
r.headers["Foo"] = ["fOo"] r.headers["Foo"] = "fOo"
r.content = "afoob" r.content = "afoob"
assert r.replace("foo(?i)", "boo") == 4 assert r.replace("foo(?i)", "boo") == 4
assert r.path == "path/boo" assert r.path == "path/boo"
assert not "foo" in r.content assert not "foo" in r.content
assert r.headers["boo"] == ["boo"] assert r.headers["boo"] == "boo"
def test_constrain_encoding(self): def test_constrain_encoding(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.headers["accept-encoding"] = ["gzip", "oink"] r.headers["accept-encoding"] = "gzip, oink"
r.constrain_encoding()
assert "oink" not in r.headers["accept-encoding"]
r.headers.set_all("accept-encoding", ["gzip", "oink"])
r.constrain_encoding() r.constrain_encoding()
assert "oink" not in r.headers["accept-encoding"] assert "oink" not in r.headers["accept-encoding"]
def test_decodeencode(self): def test_decodeencode(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
r.content = "falafel" r.content = "falafel"
r.decode() r.decode()
assert not r.headers["content-encoding"] assert "content-encoding" not in r.headers
assert r.content == "falafel" assert r.content == "falafel"
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
@ -1121,26 +1118,26 @@ class TestRequest:
assert not r.decode() assert not r.decode()
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
r.content = "falafel" r.content = "falafel"
r.encode("identity") r.encode("identity")
assert r.headers["content-encoding"] == ["identity"] assert r.headers["content-encoding"] == "identity"
assert r.content == "falafel" assert r.content == "falafel"
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
r.content = "falafel" r.content = "falafel"
r.encode("gzip") r.encode("gzip")
assert r.headers["content-encoding"] == ["gzip"] assert r.headers["content-encoding"] == "gzip"
assert r.content != "falafel" assert r.content != "falafel"
r.decode() r.decode()
assert not r.headers["content-encoding"] assert "content-encoding" not in r.headers
assert r.content == "falafel" assert r.content == "falafel"
def test_get_decoded_content(self): def test_get_decoded_content(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
r.content = None r.content = None
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
assert r.get_decoded_content() == None assert r.get_decoded_content() == None
r.content = "falafel" r.content = "falafel"
@ -1148,11 +1145,9 @@ class TestRequest:
assert r.get_decoded_content() == "falafel" assert r.get_decoded_content() == "falafel"
def test_get_content_type(self): def test_get_content_type(self):
h = odict.ODictCaseless()
h["Content-Type"] = ["text/plain"]
resp = HTTPResponse.wrap(netlib.tutils.tresp()) resp = HTTPResponse.wrap(netlib.tutils.tresp())
resp.headers = h resp.headers = Headers(content_type="text/plain")
assert resp.headers.get_first("content-type") == "text/plain" assert resp.headers["content-type"] == "text/plain"
class TestResponse: class TestResponse:
@ -1165,19 +1160,18 @@ class TestResponse:
def test_refresh(self): def test_refresh(self):
r = HTTPResponse.wrap(netlib.tutils.tresp()) r = HTTPResponse.wrap(netlib.tutils.tresp())
n = time.time() n = time.time()
r.headers["date"] = [email.utils.formatdate(n)] r.headers["date"] = email.utils.formatdate(n)
pre = r.headers["date"] pre = r.headers["date"]
r.refresh(n) r.refresh(n)
assert pre == r.headers["date"] assert pre == r.headers["date"]
r.refresh(n + 60) r.refresh(n + 60)
d = email.utils.parsedate_tz(r.headers["date"][0]) d = email.utils.parsedate_tz(r.headers["date"])
d = email.utils.mktime_tz(d) d = email.utils.mktime_tz(d)
# Weird that this is not exact... # Weird that this is not exact...
assert abs(60 - (d - n)) <= 1 assert abs(60 - (d - n)) <= 1
r.headers[ r.headers["set-cookie"] = "MOO=BAR; Expires=Tue, 08-Mar-2011 00:20:38 GMT; Path=foo.com; Secure"
"set-cookie"] = ["MOO=BAR; Expires=Tue, 08-Mar-2011 00:20:38 GMT; Path=foo.com; Secure"]
r.refresh() r.refresh()
def test_refresh_cookie(self): def test_refresh_cookie(self):
@ -1192,47 +1186,45 @@ class TestResponse:
def test_replace(self): def test_replace(self):
r = HTTPResponse.wrap(netlib.tutils.tresp()) r = HTTPResponse.wrap(netlib.tutils.tresp())
r.headers["Foo"] = ["fOo"] r.headers["Foo"] = "fOo"
r.content = "afoob" r.content = "afoob"
assert r.replace("foo(?i)", "boo") == 3 assert r.replace("foo(?i)", "boo") == 3
assert not "foo" in r.content assert not "foo" in r.content
assert r.headers["boo"] == ["boo"] assert r.headers["boo"] == "boo"
def test_decodeencode(self): def test_decodeencode(self):
r = HTTPResponse.wrap(netlib.tutils.tresp()) r = HTTPResponse.wrap(netlib.tutils.tresp())
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
r.content = "falafel" r.content = "falafel"
assert r.decode() assert r.decode()
assert not r.headers["content-encoding"] assert "content-encoding" not in r.headers
assert r.content == "falafel" assert r.content == "falafel"
r = HTTPResponse.wrap(netlib.tutils.tresp()) r = HTTPResponse.wrap(netlib.tutils.tresp())
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
r.content = "falafel" r.content = "falafel"
r.encode("identity") r.encode("identity")
assert r.headers["content-encoding"] == ["identity"] assert r.headers["content-encoding"] == "identity"
assert r.content == "falafel" assert r.content == "falafel"
r = HTTPResponse.wrap(netlib.tutils.tresp()) r = HTTPResponse.wrap(netlib.tutils.tresp())
r.headers["content-encoding"] = ["identity"] r.headers["content-encoding"] = "identity"
r.content = "falafel" r.content = "falafel"
r.encode("gzip") r.encode("gzip")
assert r.headers["content-encoding"] == ["gzip"] assert r.headers["content-encoding"] == "gzip"
assert r.content != "falafel" assert r.content != "falafel"
assert r.decode() assert r.decode()
assert not r.headers["content-encoding"] assert "content-encoding" not in r.headers
assert r.content == "falafel" assert r.content == "falafel"
r.headers["content-encoding"] = ["gzip"] r.headers["content-encoding"] = "gzip"
assert not r.decode() assert not r.decode()
assert r.content == "falafel" assert r.content == "falafel"
def test_get_content_type(self): def test_get_content_type(self):
h = odict.ODictCaseless()
h["Content-Type"] = ["text/plain"]
resp = HTTPResponse.wrap(netlib.tutils.tresp()) resp = HTTPResponse.wrap(netlib.tutils.tresp())
resp.headers = h resp.headers = Headers(content_type="text/plain")
assert resp.headers.get_first("content-type") == "text/plain" assert resp.headers["content-type"] == "text/plain"
class TestError: class TestError:
@ -1276,12 +1268,12 @@ class TestClientConnection:
def test_decoded(): def test_decoded():
r = HTTPRequest.wrap(netlib.tutils.treq()) r = HTTPRequest.wrap(netlib.tutils.treq())
assert r.content == "content" assert r.content == "content"
assert not r.headers["content-encoding"] assert "content-encoding" not in r.headers
r.encode("gzip") r.encode("gzip")
assert r.headers["content-encoding"] assert r.headers["content-encoding"]
assert r.content != "content" assert r.content != "content"
with decoded(r): with decoded(r):
assert not r.headers["content-encoding"] assert "content-encoding" not in r.headers
assert r.content == "content" assert r.content == "content"
assert r.headers["content-encoding"] assert r.headers["content-encoding"]
assert r.content != "content" assert r.content != "content"
@ -1378,18 +1370,18 @@ def test_setheaders():
h.add("~s", "one", "two") h.add("~s", "one", "two")
h.add("~s", "one", "three") h.add("~s", "one", "three")
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
f.request.headers["one"] = ["xxx"] f.request.headers["one"] = "xxx"
f.response.headers["one"] = ["xxx"] f.response.headers["one"] = "xxx"
h.run(f) h.run(f)
assert f.request.headers["one"] == ["xxx"] assert f.request.headers["one"] == "xxx"
assert f.response.headers["one"] == ["two", "three"] assert f.response.headers.get_all("one") == ["two", "three"]
h.clear() h.clear()
h.add("~q", "one", "two") h.add("~q", "one", "two")
h.add("~q", "one", "three") h.add("~q", "one", "three")
f = tutils.tflow() f = tutils.tflow()
f.request.headers["one"] = ["xxx"] f.request.headers["one"] = "xxx"
h.run(f) h.run(f)
assert f.request.headers["one"] == ["two", "three"] assert f.request.headers.get_all("one") == ["two", "three"]
assert not h.add("~", "foo", "bar") assert not h.add("~", "foo", "bar")

View File

@ -5,7 +5,6 @@ from mock import MagicMock
from libmproxy.protocol.http import * from libmproxy.protocol.http import *
import netlib.http import netlib.http
from netlib import odict
from netlib.http import http1 from netlib.http import http1
from netlib.http.semantics import CONTENT_MISSING from netlib.http.semantics import CONTENT_MISSING

View File

@ -623,8 +623,7 @@ class MasterRedirectRequest(tservers.TestMaster):
def handle_response(self, f): def handle_response(self, f):
f.response.content = str(f.client_conn.address.port) f.response.content = str(f.client_conn.address.port)
f.response.headers[ f.response.headers["server-conn-id"] = str(f.server_conn.source_address.port)
"server-conn-id"] = [str(f.server_conn.source_address.port)]
super(MasterRedirectRequest, self).handle_response(f) super(MasterRedirectRequest, self).handle_response(f)
@ -721,7 +720,7 @@ class TestStreamRequest(tservers.HTTPProxTest):
protocol = http.http1.HTTP1Protocol(rfile=fconn) protocol = http.http1.HTTP1Protocol(rfile=fconn)
resp = protocol.read_response("GET", None, include_body=False) resp = protocol.read_response("GET", None, include_body=False)
assert resp.headers["Transfer-Encoding"][0] == 'chunked' assert resp.headers["Transfer-Encoding"] == 'chunked'
assert resp.status_code == 200 assert resp.status_code == 200
chunks = list(protocol.read_http_body_chunked( chunks = list(protocol.read_http_body_chunked(
@ -743,7 +742,7 @@ class TestFakeResponse(tservers.HTTPProxTest):
def test_fake(self): def test_fake(self):
f = self.pathod("200") f = self.pathod("200")
assert "header_response" in f.headers.keys() assert "header_response" in f.headers
class TestServerConnect(tservers.HTTPProxTest): class TestServerConnect(tservers.HTTPProxTest):

View File

@ -1,6 +1,5 @@
import json import json
from libmproxy import utils from libmproxy import utils
from netlib import odict
import tutils import tutils
utils.CERT_SLEEP_TIME = 0 utils.CERT_SLEEP_TIME = 0