aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/models
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy/models')
-rw-r--r--libmproxy/models/connections.py44
-rw-r--r--libmproxy/models/flow.py19
-rw-r--r--libmproxy/models/http.py166
3 files changed, 58 insertions, 171 deletions
diff --git a/libmproxy/models/connections.py b/libmproxy/models/connections.py
index a45e1629..d5920256 100644
--- a/libmproxy/models/connections.py
+++ b/libmproxy/models/connections.py
@@ -42,28 +42,14 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject):
return self.ssl_established
_stateobject_attributes = dict(
+ address=tcp.Address,
+ clientcert=certutils.SSLCert,
ssl_established=bool,
timestamp_start=float,
timestamp_end=float,
timestamp_ssl_setup=float
)
- def get_state(self, short=False):
- d = super(ClientConnection, self).get_state(short)
- d.update(
- address=({
- "address": self.address(),
- "use_ipv6": self.address.use_ipv6} if self.address else {}),
- clientcert=self.cert.to_pem() if self.clientcert else None)
- return d
-
- def load_state(self, state):
- super(ClientConnection, self).load_state(state)
- self.address = tcp.Address(
- **state["address"]) if state["address"] else None
- self.clientcert = certutils.SSLCert.from_pem(
- state["clientcert"]) if state["clientcert"] else None
-
def copy(self):
return copy.copy(self)
@@ -76,7 +62,7 @@ class ClientConnection(tcp.BaseHandler, stateobject.StateObject):
@classmethod
def from_state(cls, state):
f = cls(None, tuple(), None)
- f.load_state(state)
+ f.set_state(state)
return f
def convert_to_ssl(self, *args, **kwargs):
@@ -130,33 +116,11 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject):
ssl_established=bool,
sni=str
)
- _stateobject_long_attributes = {"cert"}
-
- def get_state(self, short=False):
- d = super(ServerConnection, self).get_state(short)
- d.update(
- address=({"address": self.address(),
- "use_ipv6": self.address.use_ipv6} if self.address else {}),
- source_address=({"address": self.source_address(),
- "use_ipv6": self.source_address.use_ipv6} if self.source_address else None),
- cert=self.cert.to_pem() if self.cert else None
- )
- return d
-
- def load_state(self, state):
- super(ServerConnection, self).load_state(state)
-
- self.address = tcp.Address(
- **state["address"]) if state["address"] else None
- self.source_address = tcp.Address(
- **state["source_address"]) if state["source_address"] else None
- self.cert = certutils.SSLCert.from_pem(
- state["cert"]) if state["cert"] else None
@classmethod
def from_state(cls, state):
f = cls(tuple())
- f.load_state(state)
+ f.set_state(state)
return f
def copy(self):
diff --git a/libmproxy/models/flow.py b/libmproxy/models/flow.py
index b4e8cb88..10255dad 100644
--- a/libmproxy/models/flow.py
+++ b/libmproxy/models/flow.py
@@ -45,7 +45,7 @@ class Error(stateobject.StateObject):
# the default implementation assumes an empty constructor. Override
# accordingly.
f = cls(None)
- f.load_state(state)
+ f.set_state(state)
return f
def copy(self):
@@ -86,16 +86,19 @@ class Flow(stateobject.StateObject):
intercepted=bool
)
- def get_state(self, short=False):
- d = super(Flow, self).get_state(short)
+ def get_state(self):
+ d = super(Flow, self).get_state()
d.update(version=version.IVERSION)
if self._backup and self._backup != d:
- if short:
- d.update(modified=True)
- else:
- d.update(backup=self._backup)
+ d.update(backup=self._backup)
return d
+ def set_state(self, state):
+ state.pop("version")
+ if "backup" in state:
+ self._backup = state.pop("backup")
+ super(Flow, self).set_state(state)
+
def __eq__(self, other):
return self is other
@@ -133,7 +136,7 @@ class Flow(stateobject.StateObject):
Revert to the last backed up state.
"""
if self._backup:
- self.load_state(self._backup)
+ self.set_state(self._backup)
self._backup = None
def kill(self, master):
diff --git a/libmproxy/models/http.py b/libmproxy/models/http.py
index e07dff69..3c024e76 100644
--- a/libmproxy/models/http.py
+++ b/libmproxy/models/http.py
@@ -1,36 +1,20 @@
from __future__ import (absolute_import, print_function, division)
import Cookie
import copy
+import warnings
from email.utils import parsedate_tz, formatdate, mktime_tz
import time
from libmproxy import utils
from netlib import encoding
-from netlib.http import status_codes, Headers, Request, Response, CONTENT_MISSING, decoded
+from netlib.http import status_codes, Headers, Request, Response, decoded
from netlib.tcp import Address
-from .. import version, stateobject
+from .. import version
from .flow import Flow
-class MessageMixin(stateobject.StateObject):
- _stateobject_attributes = dict(
- http_version=bytes,
- headers=Headers,
- timestamp_start=float,
- timestamp_end=float
- )
- _stateobject_long_attributes = {"body"}
-
- def get_state(self, short=False):
- ret = super(MessageMixin, self).get_state(short)
- if short:
- if self.content:
- ret["contentLength"] = len(self.content)
- elif self.content == CONTENT_MISSING:
- ret["contentLength"] = None
- else:
- ret["contentLength"] = 0
- return ret
+
+class MessageMixin(object):
def get_decoded_content(self):
"""
@@ -43,33 +27,6 @@ class MessageMixin(stateobject.StateObject):
return self.content
return encoding.decode(ce, self.content)
- def decode(self):
- """
- Decodes body based on the current Content-Encoding header, then
- removes the header. If there is no Content-Encoding header, no
- action is taken.
-
- Returns True if decoding succeeded, False otherwise.
- """
- ce = self.headers.get("content-encoding")
- if not self.content or ce not in encoding.ENCODINGS:
- return False
- data = encoding.decode(ce, self.content)
- if data is None:
- return False
- self.content = data
- self.headers.pop("content-encoding", None)
- return True
-
- def encode(self, e):
- """
- Encodes body with the encoding e, where e is "gzip", "deflate"
- or "identity".
- """
- # FIXME: Error if there's an existing encoding header?
- self.content = encoding.encode(e, self.content)
- self.headers["content-encoding"] = e
-
def copy(self):
c = copy.copy(self)
if hasattr(self, "data"): # FIXME remove condition
@@ -86,10 +43,12 @@ class MessageMixin(stateobject.StateObject):
Returns the number of replacements made.
"""
- with decoded(self):
- self.content, count = utils.safe_subn(
- pattern, repl, self.content, *args, **kwargs
- )
+ count = 0
+ if self.content:
+ with decoded(self):
+ self.content, count = utils.safe_subn(
+ pattern, repl, self.content, *args, **kwargs
+ )
fields = []
for name, value in self.headers.fields:
name, c = utils.safe_subn(pattern, repl, name, *args, **kwargs)
@@ -161,6 +120,9 @@ class HTTPRequest(MessageMixin, Request):
timestamp_start=None,
timestamp_end=None,
form_out=None,
+ is_replay=False,
+ stickycookie=False,
+ stickyauth=False,
):
Request.__init__(
self,
@@ -179,51 +141,26 @@ class HTTPRequest(MessageMixin, Request):
self.form_out = form_out or first_line_format # FIXME remove
# Have this request's cookies been modified by sticky cookies or auth?
- self.stickycookie = False
- self.stickyauth = False
+ self.stickycookie = stickycookie
+ self.stickyauth = stickyauth
# Is this request replayed?
- self.is_replay = False
-
- _stateobject_attributes = MessageMixin._stateobject_attributes.copy()
- _stateobject_attributes.update(
- content=bytes,
- first_line_format=str,
- method=bytes,
- scheme=bytes,
- host=bytes,
- port=int,
- path=bytes,
- form_out=str,
- is_replay=bool
- )
-
- @classmethod
- def from_state(cls, state):
- f = cls(
- None,
- b"",
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None,
- None)
- f.load_state(state)
- return f
+ self.is_replay = is_replay
+
+ def get_state(self):
+ state = super(HTTPRequest, self).get_state()
+ state.update(
+ stickycookie = self.stickycookie,
+ stickyauth = self.stickyauth,
+ is_replay = self.is_replay,
+ )
+ return state
- @classmethod
- def from_protocol(
- self,
- protocol,
- *args,
- **kwargs
- ):
- req = protocol.read_request(*args, **kwargs)
- return self.wrap(req)
+ def set_state(self, state):
+ self.stickycookie = state.pop("stickycookie")
+ self.stickyauth = state.pop("stickyauth")
+ self.is_replay = state.pop("is_replay")
+ super(HTTPRequest, self).set_state(state)
@classmethod
def wrap(self, request):
@@ -241,10 +178,17 @@ class HTTPRequest(MessageMixin, Request):
timestamp_end=request.timestamp_end,
form_out=(request.form_out if hasattr(request, 'form_out') else None),
)
- if hasattr(request, 'stream_id'):
- req.stream_id = request.stream_id
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)
+
def __hash__(self):
return id(self)
@@ -297,6 +241,7 @@ class HTTPResponse(MessageMixin, Response):
content,
timestamp_start=None,
timestamp_end=None,
+ is_replay = False
):
Response.__init__(
self,
@@ -310,32 +255,9 @@ class HTTPResponse(MessageMixin, Response):
)
# Is this request replayed?
- self.is_replay = False
+ self.is_replay = is_replay
self.stream = False
- _stateobject_attributes = MessageMixin._stateobject_attributes.copy()
- _stateobject_attributes.update(
- body=bytes,
- status_code=int,
- msg=bytes
- )
-
- @classmethod
- def from_state(cls, state):
- f = cls(None, None, None, None, None)
- f.load_state(state)
- return f
-
- @classmethod
- def from_protocol(
- self,
- protocol,
- *args,
- **kwargs
- ):
- resp = protocol.read_response(*args, **kwargs)
- return self.wrap(resp)
-
@classmethod
def wrap(self, response):
resp = HTTPResponse(
@@ -347,8 +269,6 @@ class HTTPResponse(MessageMixin, Response):
timestamp_start=response.timestamp_start,
timestamp_end=response.timestamp_end,
)
- if hasattr(response, 'stream_id'):
- resp.stream_id = response.stream_id
return resp
def _refresh_cookie(self, c, delta):
@@ -448,7 +368,7 @@ class HTTPFlow(Flow):
@classmethod
def from_state(cls, state):
f = cls(None, None)
- f.load_state(state)
+ f.set_state(state)
return f
def __repr__(self):