mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-22 15:37:45 +00:00
Add timestamps to flows.
For now, these are only displayed on the connection view screen, with second granularity.
This commit is contained in:
parent
673ff01acc
commit
6c89749f0a
@ -44,13 +44,19 @@ def format_keyvals(lst, key="key", val="text", space=5, indent=0):
|
||||
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:
|
||||
txt = [
|
||||
("title", " Connection from %s..."%(f.connection.address)),
|
||||
]
|
||||
else:
|
||||
if extended:
|
||||
ts = ("highlight", utils.format_timestamp(f.request.timestamp))
|
||||
else:
|
||||
ts = ""
|
||||
|
||||
txt = [
|
||||
ts,
|
||||
("ack", "!") if f.intercepting and not f.request.acked else " ",
|
||||
("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():
|
||||
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 = ""
|
||||
if f.is_replay():
|
||||
txt.append(("method", "[replay] "))
|
||||
@ -198,11 +213,11 @@ class ConnectionListView(urwid.ListWalker):
|
||||
class ConnectionViewHeader(WWrap):
|
||||
def __init__(self, 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):
|
||||
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
|
||||
@ -810,6 +825,7 @@ class ConsoleMaster(controller.Master):
|
||||
('error', 'light red', 'default'),
|
||||
('header', 'dark cyan', 'default'),
|
||||
('heading', 'white', 'dark blue'),
|
||||
('highlight', 'white', 'default'),
|
||||
('inactive', 'dark gray', 'default'),
|
||||
('ack', 'light red', 'default'),
|
||||
|
||||
|
@ -84,10 +84,11 @@ def parse_proxy_request(request):
|
||||
|
||||
class Request(controller.Msg):
|
||||
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.host, self.port, self.scheme = host, port, scheme
|
||||
self.method, self.path, self.headers, self.content = method, path, headers, content
|
||||
self.timestamp = timestamp or time.time()
|
||||
controller.Msg.__init__(self)
|
||||
|
||||
def get_state(self):
|
||||
@ -98,7 +99,8 @@ class Request(controller.Msg):
|
||||
method = self.method,
|
||||
path = self.path,
|
||||
headers = self.headers.get_state(),
|
||||
content = self.content
|
||||
content = self.content,
|
||||
timestamp = self.timestamp,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -111,7 +113,8 @@ class Request(controller.Msg):
|
||||
state["method"],
|
||||
state["path"],
|
||||
utils.Headers.from_state(state["headers"]),
|
||||
state["content"]
|
||||
state["content"],
|
||||
state["timestamp"]
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
@ -159,10 +162,11 @@ class Request(controller.Msg):
|
||||
|
||||
class Response(controller.Msg):
|
||||
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.code, self.proto, self.msg = code, proto, msg
|
||||
self.headers, self.content = headers, content
|
||||
self.timestamp = timestamp or time.time()
|
||||
controller.Msg.__init__(self)
|
||||
|
||||
def get_state(self):
|
||||
@ -171,6 +175,7 @@ class Response(controller.Msg):
|
||||
proto = self.proto,
|
||||
msg = self.msg,
|
||||
headers = self.headers.get_state(),
|
||||
timestamp = self.timestamp,
|
||||
content = self.content
|
||||
)
|
||||
|
||||
@ -182,7 +187,8 @@ class Response(controller.Msg):
|
||||
state["proto"],
|
||||
state["msg"],
|
||||
utils.Headers.from_state(state["headers"]),
|
||||
state["content"]
|
||||
state["content"],
|
||||
state["timestamp"],
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
@ -225,8 +231,9 @@ class BrowserConnection(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.timestamp = timestamp or time.time()
|
||||
controller.Msg.__init__(self)
|
||||
|
||||
def copy(self):
|
||||
@ -235,6 +242,7 @@ class Error(controller.Msg):
|
||||
def get_state(self):
|
||||
return dict(
|
||||
msg = self.msg,
|
||||
timestamp = self.timestamp,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -242,6 +250,7 @@ class Error(controller.Msg):
|
||||
return klass(
|
||||
None,
|
||||
state["msg"],
|
||||
state["timestamp"],
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
|
@ -13,9 +13,15 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# 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
|
||||
|
||||
|
||||
def format_timestamp(s):
|
||||
d = datetime.datetime.fromtimestamp(s)
|
||||
return d.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
def isBin(s):
|
||||
"""
|
||||
Does this string have any non-ASCII characters?
|
||||
|
@ -108,13 +108,18 @@ class uformat_flow(libpry.AutoTree):
|
||||
assert ('focus', '>> ') not in console.format_flow(f, False)
|
||||
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.request = f.response.request
|
||||
f.backup()
|
||||
|
||||
assert ('method', '[edited] ') in console.format_flow(f, True)
|
||||
assert ('method', '[edited] ') in console.format_flow(f, True, True)
|
||||
f.connection = flow.ReplayConnection()
|
||||
assert ('method', '[replay] ') in console.format_flow(f, True)
|
||||
assert ('method', '[replay] ') in console.format_flow(f, True, True)
|
||||
|
||||
|
||||
class uPathCompleter(libpry.AutoTree):
|
||||
|
@ -267,6 +267,8 @@ class uError(libpry.AutoTree):
|
||||
state = e.get_state()
|
||||
assert proxy.Error.from_state(state) == e
|
||||
|
||||
assert e.copy()
|
||||
|
||||
|
||||
class uProxyError(libpry.AutoTree):
|
||||
def test_simple(self):
|
||||
|
@ -1,8 +1,13 @@
|
||||
import textwrap, cStringIO, os
|
||||
import textwrap, cStringIO, os, time
|
||||
import libpry
|
||||
from libmproxy import utils
|
||||
|
||||
|
||||
class uformat_timestamp(libpry.AutoTree):
|
||||
def test_simple(self):
|
||||
assert utils.format_timestamp(time.time())
|
||||
|
||||
|
||||
class uisBin(libpry.AutoTree):
|
||||
def test_simple(self):
|
||||
assert not utils.isBin("testing\n\r")
|
||||
@ -234,6 +239,7 @@ class uprettybody(libpry.AutoTree):
|
||||
|
||||
|
||||
tests = [
|
||||
uformat_timestamp(),
|
||||
umake_bogus_cert(),
|
||||
uisBin(),
|
||||
uhexdump(),
|
||||
|
Loading…
Reference in New Issue
Block a user