mitmproxy/libmproxy/protocol/primitives.py
2014-02-04 05:02:17 +01:00

124 lines
3.3 KiB
Python

from .. import stateobject, utils, version
from ..proxy import ServerConnection, ClientConnection
import copy
class _BackreferenceMixin(object):
"""
If an attribute from the _backrefattr tuple is set,
this mixin sets a reference back on the attribute object.
Example:
e = Error()
f = Flow()
f.error = e
assert f is e.flow
"""
_backrefattr = tuple()
def __setattr__(self, key, value):
super(_BackreferenceMixin, self).__setattr__(key, value)
if key in self._backrefattr and value is not None:
setattr(value, self._backrefname, self)
class Error(stateobject.SimpleStateObject):
"""
An Error.
This is distinct from an HTTP error response (say, a code 500), which
is represented by a normal Response object. This class is responsible
for indicating errors that fall outside of normal HTTP communications,
like interrupted connections, timeouts, protocol errors.
Exposes the following attributes:
flow: Flow object
msg: Message describing the error
timestamp: Seconds since the epoch
"""
def __init__(self, msg, timestamp=None):
"""
@type msg: str
@type timestamp: float
"""
self.msg = msg
self.timestamp = timestamp or utils.timestamp()
_stateobject_attributes = dict(
msg=str,
timestamp=float
)
@classmethod
def _from_state(cls, state):
f = cls(None) # the default implementation assumes an empty constructor. Override accordingly.
f._load_state(state)
return f
def copy(self):
c = copy.copy(self)
return c
class Flow(stateobject.SimpleStateObject, _BackreferenceMixin):
def __init__(self, conntype, client_conn, server_conn):
self.conntype = conntype
self.client_conn = client_conn
self.server_conn = server_conn
self.error = None
_backrefattr = ("error",)
_backrefname = "flow"
_stateobject_attributes = dict(
error=Error,
client_conn=ClientConnection,
server_conn=ServerConnection,
conntype=str
)
def _get_state(self):
d = super(Flow, self)._get_state()
d.update(version=version.IVERSION)
return d
@classmethod
def _from_state(cls, state):
f = cls(None, None, None)
f._load_state(state)
return f
def copy(self):
f = copy.copy(self)
f.client_conn = self.client_conn.copy()
f.server_conn = self.server_conn.copy()
if self.error:
f.error = self.error.copy()
return f
def modified(self):
"""
Has this Flow been modified?
"""
if self._backup:
return self._backup != self._get_state()
else:
return False
def backup(self, force=False):
"""
Save a backup of this Flow, which can be reverted to using a
call to .revert().
"""
if not self._backup:
self._backup = self._get_state()
def revert(self):
"""
Revert to the last backed up state.
"""
if self._backup:
self._load_state(self._backup)
self._backup = None