diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2015-06-04 18:14:25 +1200 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2015-06-04 18:14:25 +1200 |
commit | 5a33f310412d57c975ff26ddc5653c6cca05a433 (patch) | |
tree | 1283088d2be001b2cf3cfa9b65412bd48bf7bdf3 | |
parent | 9fda74c65a632bda5176e2ccafbbcab2af27d77d (diff) | |
download | mitmproxy-5a33f310412d57c975ff26ddc5653c6cca05a433.tar.gz mitmproxy-5a33f310412d57c975ff26ddc5653c6cca05a433.tar.bz2 mitmproxy-5a33f310412d57c975ff26ddc5653c6cca05a433.zip |
Clarify nomenclature, complete nested frame language spec.
-rw-r--r-- | libpathod/language/__init__.py | 2 | ||||
-rw-r--r-- | libpathod/language/base.py | 39 | ||||
-rw-r--r-- | libpathod/language/http.py | 47 | ||||
-rw-r--r-- | libpathod/language/websockets.py | 88 | ||||
-rw-r--r-- | test/test_language_http.py | 12 | ||||
-rw-r--r-- | test/test_language_websocket.py | 29 |
6 files changed, 112 insertions, 105 deletions
diff --git a/libpathod/language/__init__.py b/libpathod/language/__init__.py index e2e3e57d..12378607 100644 --- a/libpathod/language/__init__.py +++ b/libpathod/language/__init__.py @@ -40,7 +40,7 @@ def parse_pathoc(s): reqs = pp.OneOrMore( pp.Or( [ - websockets.WebsocketFrame.expr(), + websockets.WebsocketClientFrame.expr(), http.Request.expr(), ] ) diff --git a/libpathod/language/base.py b/libpathod/language/base.py index 4475d15b..ee5d05b5 100644 --- a/libpathod/language/base.py +++ b/libpathod/language/base.py @@ -519,3 +519,42 @@ class IntField(_Component): def spec(self): return "%s%s" % (self.preamble, self.origvalue) + + +class NestedMessage(Token): + """ + A nested message, as an escaped string with a preamble. + """ + preamble = "" + nest_type = None + + def __init__(self, value): + Token.__init__(self) + self.value = value + try: + self.parsed = self.nest_type( + self.nest_type.expr().parseString( + value.val, + parseAll=True + ) + ) + except pp.ParseException as v: + raise exceptions.ParseException(v.msg, v.line, v.col) + + @classmethod + def expr(klass): + e = pp.Literal(klass.preamble).suppress() + e = e + TokValueLiteral.expr() + return e.setParseAction(lambda x: klass(*x)) + + def values(self, settings): + return [ + self.value.get_generator(settings), + ] + + def spec(self): + return "%s%s" % (self.preamble, self.value.spec()) + + def freeze(self, settings): + f = self.parsed.freeze(settings).spec() + return self.__class__(TokValueLiteral(f.encode("string_escape"))) diff --git a/libpathod/language/http.py b/libpathod/language/http.py index 76362253..9a8404f0 100644 --- a/libpathod/language/http.py +++ b/libpathod/language/http.py @@ -94,38 +94,6 @@ class ShortcutUserAgent(_HeaderMixin, base.OptionsOrValue): ) -class PathodResponse(base.Token): - def __init__(self, value): - self.value = value - try: - self.parsed = Response( - Response.expr().parseString( - value.val, - parseAll=True - ) - ) - except pp.ParseException as v: - raise exceptions.ParseException(v.msg, v.line, v.col) - - @classmethod - def expr(klass): - e = pp.Literal("s").suppress() - e = e + base.TokValueLiteral.expr() - return e.setParseAction(lambda x: klass(*x)) - - def values(self, settings): - return [ - self.value.get_generator(settings), - ] - - def spec(self): - return "s%s" % (self.value.spec()) - - def freeze(self, settings): - f = self.parsed.freeze(settings).spec() - return PathodResponse(base.TokValueLiteral(f.encode("string_escape"))) - - def get_header(val, headers): """ Header keys may be Values, so we have to "generate" them as we try the @@ -281,6 +249,11 @@ class Response(_HTTPMessage): return ":".join([i.spec() for i in self.tokens]) +class NestedResponse(base.NestedMessage): + preamble = "s" + nest_type = Response + + class Request(_HTTPMessage): comps = ( Body, @@ -288,7 +261,7 @@ class Request(_HTTPMessage): ShortcutContentType, ShortcutUserAgent, Raw, - PathodResponse, + NestedResponse, Times, actions.PauseAt, @@ -314,15 +287,15 @@ class Request(_HTTPMessage): return self.tok(Times) @property - def pathodspec(self): - return self.tok(PathodResponse) + def nested_response(self): + return self.tok(NestedResponse) def preamble(self, settings): v = self.method.values(settings) v.append(" ") v.extend(self.path.values(settings)) - if self.pathodspec: - v.append(self.pathodspec.parsed.spec()) + if self.nested_response: + v.append(self.nested_response.parsed.spec()) v.append(" ") v.append(self.version) return v diff --git a/libpathod/language/websockets.py b/libpathod/language/websockets.py index 3869bd85..44c12f64 100644 --- a/libpathod/language/websockets.py +++ b/libpathod/language/websockets.py @@ -68,60 +68,31 @@ class Length(base.Integer): class Times(base.Integer): preamble = "x" - -class NestedFrame(base.Token): - def __init__(self, value): - self.value = value - try: - self.parsed = WebsocketFrame( - Response.expr().parseString( - value.val, - parseAll=True - ) - ) - except pp.ParseException as v: - raise exceptions.ParseException(v.msg, v.line, v.col) - - @classmethod - def expr(klass): - e = pp.Literal("wf").suppress() - e = e + base.TokValueLiteral.expr() - return e.setParseAction(lambda x: klass(*x)) - - def values(self, settings): - return [ - self.value.get_generator(settings), - ] - - def spec(self): - return "s%s" % (self.value.spec()) - - def freeze(self, settings): - f = self.parsed.freeze(settings).spec() - return NestedFrame(base.TokValueLiteral(f.encode("string_escape"))) +COMPONENTS = ( + OpCode, + Length, + # Bit flags + Fin, + RSV1, + RSV2, + RSV3, + Mask, + actions.PauseAt, + actions.DisconnectAt, + actions.InjectAt, + KeyNone, + Key, + Times, + + Body, + RawBody, +) class WebsocketFrame(message.Message): - comps = ( - OpCode, - Length, - # Bit flags - Fin, - RSV1, - RSV2, - RSV3, - Mask, - actions.PauseAt, - actions.DisconnectAt, - actions.InjectAt, - KeyNone, - Key, - Times, - - Body, - RawBody, - ) + components = COMPONENTS logattrs = ["body"] + unique_name = "body" @property def actions(self): @@ -177,7 +148,7 @@ class WebsocketFrame(message.Message): @classmethod def expr(klass): - parts = [i.expr() for i in klass.comps] + parts = [i.expr() for i in klass.components] atom = pp.MatchFirst(parts) resp = pp.And( [ @@ -246,3 +217,18 @@ class WebsocketFrame(message.Message): def spec(self): return ":".join([i.spec() for i in self.tokens]) + + +class NestedFrame(base.NestedMessage): + preamble = "f" + nest_type = WebsocketFrame + + +class WebsocketClientFrame(WebsocketFrame): + components = COMPONENTS + ( + NestedFrame, + ) + + @property + def nested_frame(self): + return self.tok(NestedFrame) diff --git a/test/test_language_http.py b/test/test_language_http.py index 4851beaa..f1484da5 100644 --- a/test/test_language_http.py +++ b/test/test_language_http.py @@ -66,12 +66,12 @@ class TestRequest: assert r[0].method.string() == "GET" assert r[1].method.string() == "GET" - def test_pathodspec(self): + def test_nested_response(self): l = "get:/p:s'200'" r = language.parse_pathoc(l) assert len(r) == 1 assert len(r[0].tokens) == 3 - assert isinstance(r[0].tokens[2], http.PathodResponse) + assert isinstance(r[0].tokens[2], http.NestedResponse) assert r[0].values({}) def test_render(self): @@ -318,8 +318,8 @@ def test_user_agent(): assert v2.value.val == v3.value.val -def test_pathodspec(): - e = http.PathodResponse.expr() +def test_nested_response(): + e = http.NestedResponse.expr() v = e.parseString("s'200'")[0] assert v.value.val == "200" tutils.raises( @@ -334,8 +334,8 @@ def test_pathodspec(): assert "@1" not in f.spec() -def test_pathodspec_freeze(): - e = http.PathodResponse( +def test_nested_response_freeze(): + e = http.NestedResponse( base.TokValueLiteral( "200:b'foo':i10,'\\x27'".encode( "string_escape" diff --git a/test/test_language_websocket.py b/test/test_language_websocket.py index f55e6e37..70a626e6 100644 --- a/test/test_language_websocket.py +++ b/test/test_language_websocket.py @@ -10,7 +10,19 @@ def parse_request(s): class TestWebsocketFrame: - def test_values(self): + def _test_messages(self, specs, message_klass): + for i in specs: + wf = parse_request(i) + assert isinstance(wf, message_klass) + assert wf + assert wf.values(language.Settings()) + assert wf.resolve(language.Settings()) + + spec = wf.spec() + wf2 = parse_request(spec) + assert wf2.spec() == spec + + def test_server_values(self): specs = [ "wf", "wf:dr", @@ -25,16 +37,13 @@ class TestWebsocketFrame: "wf:-fin:-rsv1:-rsv2:-rsv3:-mask", "wf:k@4", ] - for i in specs: - wf = parse_request(i) - assert isinstance(wf, websockets.WebsocketFrame) - assert wf - assert wf.values(language.Settings()) - assert wf.resolve(language.Settings()) + self._test_messages(specs, websockets.WebsocketFrame) - spec = wf.spec() - wf2 = parse_request(spec) - assert wf2.spec() == spec + def test_client_values(self): + specs = [ + "wf:f'wf'", + ] + self._test_messages(specs, websockets.WebsocketClientFrame) def test_flags(self): wf = parse_request("wf:fin:mask:rsv1:rsv2:rsv3") |