Merge pull request #4586 from rbdixon/meta_replay_filter
Metadata and replay filter syntax
This commit is contained in:
commit
b70358cbde
|
@ -61,6 +61,7 @@ If you depend on these features, please raise your voice in
|
|||
* Multiple Browsers: The `browser.start` command may be executed more than once to start additional
|
||||
browser sessions. (@rbdixon)
|
||||
* Improve readability of SHA256 fingerprint. (@wrekone)
|
||||
* Metadata and Replay Flow Filters: Flows may be filtered based on metadata and replay status. (@rbdixon)
|
||||
* --- TODO: add new PRs above this line ---
|
||||
* ... and various other fixes, documentation improvements, dependency version bumps, etc.
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import functools
|
|||
import re
|
||||
import sys
|
||||
from typing import Callable, ClassVar, Optional, Sequence, Type
|
||||
|
||||
import pyparsing as pp
|
||||
|
||||
from mitmproxy import flow, http, tcp
|
||||
|
@ -382,6 +381,41 @@ class FDst(_Rex):
|
|||
return f.server_conn.address and self.re.search(r)
|
||||
|
||||
|
||||
class FReplay(_Action):
|
||||
code = "replay"
|
||||
help = "Match replayed flows"
|
||||
|
||||
def __call__(self, f):
|
||||
return f.is_replay is not None
|
||||
|
||||
|
||||
class FReplayClient(_Action):
|
||||
code = "replayq"
|
||||
help = "Match replayed client request"
|
||||
|
||||
def __call__(self, f):
|
||||
return f.is_replay == 'request'
|
||||
|
||||
|
||||
class FReplayServer(_Action):
|
||||
code = "replays"
|
||||
help = "Match replayed server response"
|
||||
|
||||
def __call__(self, f):
|
||||
return f.is_replay == 'response'
|
||||
|
||||
|
||||
class FMeta(_Rex):
|
||||
code = "meta"
|
||||
help = "Flow metadata"
|
||||
flags = re.MULTILINE
|
||||
is_binary = False
|
||||
|
||||
def __call__(self, f):
|
||||
m = "\n".join([f"{key}: {value}" for key, value in f.metadata.items()])
|
||||
return self.re.search(m)
|
||||
|
||||
|
||||
class _Int(_Action):
|
||||
|
||||
def __init__(self, num):
|
||||
|
@ -444,6 +478,9 @@ filter_unary: Sequence[Type[_Action]] = [
|
|||
FErr,
|
||||
FHTTP,
|
||||
FMarked,
|
||||
FReplay,
|
||||
FReplayClient,
|
||||
FReplayServer,
|
||||
FReq,
|
||||
FResp,
|
||||
FTCP,
|
||||
|
@ -464,6 +501,7 @@ filter_rex: Sequence[Type[_Rex]] = [
|
|||
FMethod,
|
||||
FSrc,
|
||||
FUrl,
|
||||
FMeta,
|
||||
]
|
||||
filter_int = [
|
||||
FCode
|
||||
|
|
|
@ -24,6 +24,9 @@ class TestParsing:
|
|||
assert flowfilter.parse("~m foobar")
|
||||
assert flowfilter.parse("~u foobar")
|
||||
assert flowfilter.parse("~q ~c 10")
|
||||
assert flowfilter.parse("~replay")
|
||||
assert flowfilter.parse("~replayq")
|
||||
assert flowfilter.parse("~replays")
|
||||
p = flowfilter.parse("~q ~c 10")
|
||||
self._dump(p)
|
||||
assert len(p.lst) == 2
|
||||
|
@ -296,6 +299,31 @@ class TestMatchingHTTPFlow:
|
|||
assert self.q("!~c 201 !~c 202", s)
|
||||
assert not self.q("!~c 201 !~c 200", s)
|
||||
|
||||
def test_replay(self):
|
||||
f = tflow.tflow()
|
||||
assert not self.q("~replay", f)
|
||||
f.is_replay = "request"
|
||||
assert self.q("~replay", f)
|
||||
assert self.q("~replayq", f)
|
||||
assert not self.q("~replays", f)
|
||||
f.is_replay = "response"
|
||||
assert self.q("~replay", f)
|
||||
assert not self.q("~replayq", f)
|
||||
assert self.q("~replays", f)
|
||||
|
||||
def test_metadata(self):
|
||||
f = tflow.tflow()
|
||||
f.metadata["a"] = 1
|
||||
f.metadata["b"] = "string"
|
||||
f.metadata["c"] = {"key": "value"}
|
||||
assert self.q("~meta a", f)
|
||||
assert not self.q("~meta no", f)
|
||||
assert self.q("~meta string", f)
|
||||
assert self.q("~meta key", f)
|
||||
assert self.q("~meta value", f)
|
||||
assert self.q("~meta \"b: string\"", f)
|
||||
assert self.q("~meta \"'key': 'value'\"", f)
|
||||
|
||||
|
||||
class TestMatchingTCPFlow:
|
||||
|
||||
|
|
Loading…
Reference in New Issue