Add timestamps to flows.

For now, these are only displayed on the connection view screen, with second
granularity.
This commit is contained in:
Aldo Cortesi 2011-02-03 13:30:47 +13:00
parent 673ff01acc
commit 6c89749f0a
6 changed files with 56 additions and 12 deletions

View File

@ -44,13 +44,19 @@ def format_keyvals(lst, key="key", val="text", space=5, indent=0):
return ret return ret
def format_flow(f, focus, padding=3): def format_flow(f, focus, extended=False, padding=3):
if not f.request and not f.response: if not f.request and not f.response:
txt = [ txt = [
("title", " Connection from %s..."%(f.connection.address)), ("title", " Connection from %s..."%(f.connection.address)),
] ]
else: else:
if extended:
ts = ("highlight", utils.format_timestamp(f.request.timestamp))
else:
ts = ""
txt = [ txt = [
ts,
("ack", "!") if f.intercepting and not f.request.acked else " ", ("ack", "!") if f.intercepting and not f.request.acked else " ",
("method", f.request.method), ("method", f.request.method),
" ", " ",
@ -60,7 +66,16 @@ def format_flow(f, focus, padding=3):
), ),
] ]
if f.response or f.error or f.is_replay(): if f.response or f.error or f.is_replay():
txt.append("\n" + " "*(padding+2))
tsr = f.response or f.error
if extended and tsr:
ts = ("highlight", utils.format_timestamp(tsr.timestamp))
else:
ts = ""
txt.append("\n")
txt.append(("text", ts))
txt.append(" "*(padding+2))
met = "" met = ""
if f.is_replay(): if f.is_replay():
txt.append(("method", "[replay] ")) txt.append(("method", "[replay] "))
@ -198,11 +213,11 @@ class ConnectionListView(urwid.ListWalker):
class ConnectionViewHeader(WWrap): class ConnectionViewHeader(WWrap):
def __init__(self, master, f): def __init__(self, master, f):
self.master, self.flow = master, f self.master, self.flow = master, f
self.w = urwid.Text(format_flow(f, False, padding=0)) self.w = urwid.Text(format_flow(f, False, extended=True, padding=0))
def refresh_connection(self, f): def refresh_connection(self, f):
if f == self.flow: if f == self.flow:
self.w = urwid.Text(format_flow(f, False, padding=0)) self.w = urwid.Text(format_flow(f, False, extended=True, padding=0))
VIEW_BODY_RAW = 0 VIEW_BODY_RAW = 0
@ -810,6 +825,7 @@ class ConsoleMaster(controller.Master):
('error', 'light red', 'default'), ('error', 'light red', 'default'),
('header', 'dark cyan', 'default'), ('header', 'dark cyan', 'default'),
('heading', 'white', 'dark blue'), ('heading', 'white', 'dark blue'),
('highlight', 'white', 'default'),
('inactive', 'dark gray', 'default'), ('inactive', 'dark gray', 'default'),
('ack', 'light red', 'default'), ('ack', 'light red', 'default'),

View File

@ -84,10 +84,11 @@ def parse_proxy_request(request):
class Request(controller.Msg): class Request(controller.Msg):
FMT = '%s %s HTTP/1.0\r\n%s\r\n%s' FMT = '%s %s HTTP/1.0\r\n%s\r\n%s'
def __init__(self, connection, host, port, scheme, method, path, headers, content): def __init__(self, connection, host, port, scheme, method, path, headers, content, timestamp=None):
self.connection = connection self.connection = connection
self.host, self.port, self.scheme = host, port, scheme self.host, self.port, self.scheme = host, port, scheme
self.method, self.path, self.headers, self.content = method, path, headers, content self.method, self.path, self.headers, self.content = method, path, headers, content
self.timestamp = timestamp or time.time()
controller.Msg.__init__(self) controller.Msg.__init__(self)
def get_state(self): def get_state(self):
@ -98,7 +99,8 @@ class Request(controller.Msg):
method = self.method, method = self.method,
path = self.path, path = self.path,
headers = self.headers.get_state(), headers = self.headers.get_state(),
content = self.content content = self.content,
timestamp = self.timestamp,
) )
@classmethod @classmethod
@ -111,7 +113,8 @@ class Request(controller.Msg):
state["method"], state["method"],
state["path"], state["path"],
utils.Headers.from_state(state["headers"]), utils.Headers.from_state(state["headers"]),
state["content"] state["content"],
state["timestamp"]
) )
def __eq__(self, other): def __eq__(self, other):
@ -159,10 +162,11 @@ class Request(controller.Msg):
class Response(controller.Msg): class Response(controller.Msg):
FMT = '%s\r\n%s\r\n%s' FMT = '%s\r\n%s\r\n%s'
def __init__(self, request, code, proto, msg, headers, content): def __init__(self, request, code, proto, msg, headers, content, timestamp=None):
self.request = request self.request = request
self.code, self.proto, self.msg = code, proto, msg self.code, self.proto, self.msg = code, proto, msg
self.headers, self.content = headers, content self.headers, self.content = headers, content
self.timestamp = timestamp or time.time()
controller.Msg.__init__(self) controller.Msg.__init__(self)
def get_state(self): def get_state(self):
@ -171,6 +175,7 @@ class Response(controller.Msg):
proto = self.proto, proto = self.proto,
msg = self.msg, msg = self.msg,
headers = self.headers.get_state(), headers = self.headers.get_state(),
timestamp = self.timestamp,
content = self.content content = self.content
) )
@ -182,7 +187,8 @@ class Response(controller.Msg):
state["proto"], state["proto"],
state["msg"], state["msg"],
utils.Headers.from_state(state["headers"]), utils.Headers.from_state(state["headers"]),
state["content"] state["content"],
state["timestamp"],
) )
def __eq__(self, other): def __eq__(self, other):
@ -225,8 +231,9 @@ class BrowserConnection(controller.Msg):
class Error(controller.Msg): class Error(controller.Msg):
def __init__(self, connection, msg): def __init__(self, connection, msg, timestamp=None):
self.connection, self.msg = connection, msg self.connection, self.msg = connection, msg
self.timestamp = timestamp or time.time()
controller.Msg.__init__(self) controller.Msg.__init__(self)
def copy(self): def copy(self):
@ -235,6 +242,7 @@ class Error(controller.Msg):
def get_state(self): def get_state(self):
return dict( return dict(
msg = self.msg, msg = self.msg,
timestamp = self.timestamp,
) )
@classmethod @classmethod
@ -242,6 +250,7 @@ class Error(controller.Msg):
return klass( return klass(
None, None,
state["msg"], state["msg"],
state["timestamp"],
) )
def __eq__(self, other): def __eq__(self, other):

View File

@ -13,9 +13,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import re, os, subprocess import re, os, subprocess, datetime
from contrib import BeautifulSoup from contrib import BeautifulSoup
def format_timestamp(s):
d = datetime.datetime.fromtimestamp(s)
return d.strftime("%Y-%m-%d %H:%M:%S")
def isBin(s): def isBin(s):
""" """
Does this string have any non-ASCII characters? Does this string have any non-ASCII characters?

View File

@ -108,13 +108,18 @@ class uformat_flow(libpry.AutoTree):
assert ('focus', '>> ') not in console.format_flow(f, False) assert ('focus', '>> ') not in console.format_flow(f, False)
assert ('focus', '>> ') in console.format_flow(f, True) assert ('focus', '>> ') in console.format_flow(f, True)
assert ('focus', '>> ') not in console.format_flow(f, False, True)
assert ('focus', '>> ') in console.format_flow(f, True, True)
f.response = utils.tresp() f.response = utils.tresp()
f.request = f.response.request f.request = f.response.request
f.backup() f.backup()
assert ('method', '[edited] ') in console.format_flow(f, True) assert ('method', '[edited] ') in console.format_flow(f, True)
assert ('method', '[edited] ') in console.format_flow(f, True, True)
f.connection = flow.ReplayConnection() f.connection = flow.ReplayConnection()
assert ('method', '[replay] ') in console.format_flow(f, True) assert ('method', '[replay] ') in console.format_flow(f, True)
assert ('method', '[replay] ') in console.format_flow(f, True, True)
class uPathCompleter(libpry.AutoTree): class uPathCompleter(libpry.AutoTree):

View File

@ -267,6 +267,8 @@ class uError(libpry.AutoTree):
state = e.get_state() state = e.get_state()
assert proxy.Error.from_state(state) == e assert proxy.Error.from_state(state) == e
assert e.copy()
class uProxyError(libpry.AutoTree): class uProxyError(libpry.AutoTree):
def test_simple(self): def test_simple(self):

View File

@ -1,8 +1,13 @@
import textwrap, cStringIO, os import textwrap, cStringIO, os, time
import libpry import libpry
from libmproxy import utils from libmproxy import utils
class uformat_timestamp(libpry.AutoTree):
def test_simple(self):
assert utils.format_timestamp(time.time())
class uisBin(libpry.AutoTree): class uisBin(libpry.AutoTree):
def test_simple(self): def test_simple(self):
assert not utils.isBin("testing\n\r") assert not utils.isBin("testing\n\r")
@ -234,6 +239,7 @@ class uprettybody(libpry.AutoTree):
tests = [ tests = [
uformat_timestamp(),
umake_bogus_cert(), umake_bogus_cert(),
uisBin(), uisBin(),
uhexdump(), uhexdump(),