diff options
-rw-r--r-- | docs/install.rst | 5 | ||||
-rw-r--r-- | mitmproxy/addons/__init__.py | 28 | ||||
-rw-r--r-- | mitmproxy/addons/check_alpn.py | 17 | ||||
-rw-r--r-- | mitmproxy/addons/check_ca.py | 24 | ||||
-rw-r--r-- | mitmproxy/addons/termlog.py | 4 | ||||
-rw-r--r-- | mitmproxy/certs.py | 4 | ||||
-rw-r--r-- | mitmproxy/test/tflow.py | 56 | ||||
-rw-r--r-- | mitmproxy/tools/console/master.py | 12 | ||||
-rw-r--r-- | mitmproxy/tools/dump.py | 18 | ||||
-rw-r--r-- | test/mitmproxy/addons/test_check_alpn.py | 23 | ||||
-rw-r--r-- | test/mitmproxy/addons/test_check_ca.py | 19 | ||||
-rw-r--r-- | test/mitmproxy/addons/test_disable_h2c_upgrade.py | 17 | ||||
-rw-r--r-- | test/mitmproxy/addons/test_dumper.py | 20 | ||||
-rw-r--r-- | test/mitmproxy/test_tools_dump.py | 21 | ||||
-rw-r--r-- | test/mitmproxy/test_web_master.py | 5 | ||||
-rw-r--r-- | web/src/js/filt/filt.js | 971 | ||||
-rw-r--r-- | web/src/js/filt/filt.peg | 58 |
17 files changed, 790 insertions, 512 deletions
diff --git a/docs/install.rst b/docs/install.rst index bcf07023..9a2aca0a 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -20,7 +20,7 @@ You can use Homebrew to install everything: brew install mitmproxy -Or you can download the pre-built binary packages from `mitmproxy.org`_. +Or you can download the pre-built binary packages from our `releases`_. .. _install-windows: @@ -44,7 +44,7 @@ Installation on Linux --------------------- The recommended way to run mitmproxy on Linux is to use the pre-built binaries -provided at `mitmproxy.org`_. +provided at `releases`_. Our pre-built binaries provide you with the latest version of mitmproxy, a self-contained Python 3.5 environment and a recent version of OpenSSL that @@ -144,6 +144,7 @@ by running: ``mitmproxy --version`` .. _Hacking: https://github.com/mitmproxy/mitmproxy/blob/master/README.rst#hacking +.. _releases: https://github.com/mitmproxy/mitmproxy/releases .. _mitmproxy.org: https://mitmproxy.org/ .. _`Python website`: https://www.python.org/downloads/windows/ .. _pip: https://pip.pypa.io/en/latest/installing.html diff --git a/mitmproxy/addons/__init__.py b/mitmproxy/addons/__init__.py index 8a2f2974..2e1d1c67 100644 --- a/mitmproxy/addons/__init__.py +++ b/mitmproxy/addons/__init__.py @@ -1,35 +1,39 @@ from mitmproxy.addons import anticache from mitmproxy.addons import anticomp +from mitmproxy.addons import check_alpn +from mitmproxy.addons import check_ca from mitmproxy.addons import clientplayback -from mitmproxy.addons import streamfile +from mitmproxy.addons import disable_h2c_upgrade from mitmproxy.addons import onboarding from mitmproxy.addons import proxyauth from mitmproxy.addons import replace from mitmproxy.addons import script -from mitmproxy.addons import setheaders from mitmproxy.addons import serverplayback +from mitmproxy.addons import setheaders from mitmproxy.addons import stickyauth from mitmproxy.addons import stickycookie from mitmproxy.addons import streambodies +from mitmproxy.addons import streamfile from mitmproxy.addons import upstream_auth -from mitmproxy.addons import disable_h2c_upgrade def default_addons(): return [ - onboarding.Onboarding(), - proxyauth.ProxyAuth(), anticache.AntiCache(), anticomp.AntiComp(), + check_alpn.CheckALPN(), + check_ca.CheckCA(), + clientplayback.ClientPlayback(), + disable_h2c_upgrade.DisableH2CleartextUpgrade(), + onboarding.Onboarding(), + proxyauth.ProxyAuth(), + replace.Replace(), + script.ScriptLoader(), + serverplayback.ServerPlayback(), + setheaders.SetHeaders(), stickyauth.StickyAuth(), stickycookie.StickyCookie(), - script.ScriptLoader(), - streamfile.StreamFile(), streambodies.StreamBodies(), - replace.Replace(), - setheaders.SetHeaders(), - serverplayback.ServerPlayback(), - clientplayback.ClientPlayback(), + streamfile.StreamFile(), upstream_auth.UpstreamAuth(), - disable_h2c_upgrade.DisableH2CleartextUpgrade(), ] diff --git a/mitmproxy/addons/check_alpn.py b/mitmproxy/addons/check_alpn.py new file mode 100644 index 00000000..c288d788 --- /dev/null +++ b/mitmproxy/addons/check_alpn.py @@ -0,0 +1,17 @@ +import mitmproxy +from mitmproxy.net import tcp + + +class CheckALPN: + def __init__(self): + self.failed = False + + def configure(self, options, updated): + self.failed = mitmproxy.ctx.master.options.http2 and not tcp.HAS_ALPN + if self.failed: + mitmproxy.ctx.master.add_log( + "HTTP/2 is disabled because ALPN support missing!\n" + "OpenSSL 1.0.2+ required to support HTTP/2 connections.\n" + "Use --no-http2 to silence this warning.", + "warn", + ) diff --git a/mitmproxy/addons/check_ca.py b/mitmproxy/addons/check_ca.py new file mode 100644 index 00000000..a83ab8e1 --- /dev/null +++ b/mitmproxy/addons/check_ca.py @@ -0,0 +1,24 @@ +import mitmproxy + + +class CheckCA: + def __init__(self): + self.failed = False + + def configure(self, options, updated): + has_ca = ( + mitmproxy.ctx.master.server and + mitmproxy.ctx.master.server.config and + mitmproxy.ctx.master.server.config.certstore and + mitmproxy.ctx.master.server.config.certstore.default_ca + ) + if has_ca: + self.failed = mitmproxy.ctx.master.server.config.certstore.default_ca.has_expired() + if self.failed: + mitmproxy.ctx.master.add_log( + "The mitmproxy certificate authority has expired!\n" + "Please delete all CA-related files in your ~/.mitmproxy folder.\n" + "The CA will be regenerated automatically after restarting mitmproxy.\n" + "Then make sure all your clients have the new CA installed.", + "warn", + ) diff --git a/mitmproxy/addons/termlog.py b/mitmproxy/addons/termlog.py index b75f5f5a..f7739efe 100644 --- a/mitmproxy/addons/termlog.py +++ b/mitmproxy/addons/termlog.py @@ -5,9 +5,9 @@ from mitmproxy import log class TermLog: - def __init__(self, outfile=sys.stdout): + def __init__(self, outfile=None): self.options = None - self.outfile = outfile + self.outfile = outfile or sys.stdout def configure(self, options, updated): self.options = options diff --git a/mitmproxy/certs.py b/mitmproxy/certs.py index 4e4eb4d1..4b939c80 100644 --- a/mitmproxy/certs.py +++ b/mitmproxy/certs.py @@ -3,8 +3,8 @@ import ssl import time import datetime import ipaddress - import sys + from pyasn1.type import univ, constraint, char, namedtype, tag from pyasn1.codec.der.decoder import decode from pyasn1.error import PyAsn1Error @@ -13,8 +13,8 @@ import OpenSSL from mitmproxy.types import serializable # Default expiry must not be too long: https://github.com/mitmproxy/mitmproxy/issues/815 - DEFAULT_EXP = 94608000 # = 24 * 60 * 60 * 365 * 3 + # Generated with "openssl dhparam". It's too slow to generate this on startup. DEFAULT_DHPARAM = b""" -----BEGIN DH PARAMETERS----- diff --git a/mitmproxy/test/tflow.py b/mitmproxy/test/tflow.py index 959c9a2c..edf4d7a7 100644 --- a/mitmproxy/test/tflow.py +++ b/mitmproxy/test/tflow.py @@ -1,9 +1,11 @@ from mitmproxy.test import tutils from mitmproxy import tcp +from mitmproxy import websocket from mitmproxy import controller from mitmproxy import http from mitmproxy import connections from mitmproxy import flow +from mitmproxy.net import http as net_http def ttcpflow(client_conn=True, server_conn=True, messages=True, err=None): @@ -26,6 +28,60 @@ def ttcpflow(client_conn=True, server_conn=True, messages=True, err=None): return f +def twebsocketflow(client_conn=True, server_conn=True, messages=True, err=None, handshake_flow=True): + + if client_conn is True: + client_conn = tclient_conn() + if server_conn is True: + server_conn = tserver_conn() + if handshake_flow is True: + req = http.HTTPRequest( + "relative", + "GET", + "http", + "example.com", + "80", + "/ws", + "HTTP/1.1", + headers=net_http.Headers( + connection="upgrade", + upgrade="websocket", + sec_websocket_version="13", + sec_websocket_key="1234", + ), + content=b'' + ) + resp = http.HTTPResponse( + "HTTP/1.1", + 101, + reason=net_http.status_codes.RESPONSES.get(101), + headers=net_http.Headers( + connection='upgrade', + upgrade='websocket', + sec_websocket_accept=b'', + ), + content=b'', + ) + handshake_flow = http.HTTPFlow(client_conn, server_conn) + handshake_flow.request = req + handshake_flow.response = resp + + f = websocket.WebSocketFlow(client_conn, server_conn, handshake_flow) + + if messages is True: + messages = [ + websocket.WebSocketBinaryMessage(f, True, b"hello binary"), + websocket.WebSocketTextMessage(f, False, "hello text".encode()), + ] + if err is True: + err = terr() + + f.messages = messages + f.error = err + f.reply = controller.DummyReply() + return f + + def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None): """ @type client_conn: bool | None | mitmproxy.proxy.connection.ClientConnection diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index 8afdce2c..10f8cbf5 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -33,8 +33,6 @@ from mitmproxy.tools.console import statusbar from mitmproxy.tools.console import window from mitmproxy.utils import strutils -from mitmproxy.net import tcp - EVENTLOG_SIZE = 10000 @@ -272,16 +270,6 @@ class ConsoleMaster(master.Master): print("Could not load file: {}".format(ret), file=sys.stderr) sys.exit(1) - self.loop.set_alarm_in(0.01, self.ticker) - if self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover - def http2err(*args, **kwargs): - signals.status_message.send( - message = "HTTP/2 disabled - OpenSSL 1.0.2+ required." - " Use --no-http2 to silence this warning.", - expire=5 - ) - self.loop.set_alarm_in(0.01, http2err) - self.loop.set_alarm_in( 0.0001, lambda *args: self.view_flowlist() diff --git a/mitmproxy/tools/dump.py b/mitmproxy/tools/dump.py index 4e2844a1..e1e40fb0 100644 --- a/mitmproxy/tools/dump.py +++ b/mitmproxy/tools/dump.py @@ -6,7 +6,6 @@ from mitmproxy import addons from mitmproxy import options from mitmproxy import master from mitmproxy.addons import dumper, termlog -from mitmproxy.net import tcp class DumpError(Exception): @@ -30,7 +29,13 @@ class Options(options.Options): class DumpMaster(master.Master): - def __init__(self, options, server, with_termlog=True, with_dumper=True): + def __init__( + self, + options: Options, + server, + with_termlog=True, + with_dumper=True, + ) -> None: master.Master.__init__(self, options, server) self.has_errored = False if with_termlog: @@ -38,8 +43,6 @@ class DumpMaster(master.Master): self.addons.add(*addons.default_addons()) if with_dumper: self.addons.add(dumper.Dumper()) - # This line is just for type hinting - self.options = self.options # type: Options if not self.options.no_server: self.add_log( @@ -47,13 +50,6 @@ class DumpMaster(master.Master): "info" ) - if self.server and self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover - self.add_log( - "ALPN support missing (OpenSSL 1.0.2+ required)!\n" - "HTTP/2 is disabled. Use --no-http2 to silence this warning.", - "error" - ) - if options.rfile: try: self.load_flows_file(options.rfile) diff --git a/test/mitmproxy/addons/test_check_alpn.py b/test/mitmproxy/addons/test_check_alpn.py new file mode 100644 index 00000000..2dc0c835 --- /dev/null +++ b/test/mitmproxy/addons/test_check_alpn.py @@ -0,0 +1,23 @@ +from mitmproxy.addons import check_alpn +from mitmproxy.test import taddons +from ...conftest import requires_alpn + + +class TestCheckALPN: + + @requires_alpn + def test_check_alpn(self): + msg = 'ALPN support missing' + + with taddons.context() as tctx: + a = check_alpn.CheckALPN() + tctx.configure(a) + assert not any(msg in m for l, m in tctx.master.event_log) + + def test_check_no_alpn(self, disable_alpn): + msg = 'ALPN support missing' + + with taddons.context() as tctx: + a = check_alpn.CheckALPN() + tctx.configure(a) + assert any(msg in m for l, m in tctx.master.event_log) diff --git a/test/mitmproxy/addons/test_check_ca.py b/test/mitmproxy/addons/test_check_ca.py new file mode 100644 index 00000000..fc64621c --- /dev/null +++ b/test/mitmproxy/addons/test_check_ca.py @@ -0,0 +1,19 @@ +import pytest +from unittest import mock + +from mitmproxy.addons import check_ca +from mitmproxy.test import taddons + + +class TestCheckCA: + + @pytest.mark.parametrize('expired', [False, True]) + def test_check_ca(self, expired): + msg = 'The mitmproxy certificate authority has expired!' + + with taddons.context() as tctx: + tctx.master.server = mock.MagicMock() + tctx.master.server.config.certstore.default_ca.has_expired = mock.MagicMock(return_value=expired) + a = check_ca.CheckCA() + tctx.configure(a) + assert any(msg in m for l, m in tctx.master.event_log) is expired diff --git a/test/mitmproxy/addons/test_disable_h2c_upgrade.py b/test/mitmproxy/addons/test_disable_h2c_upgrade.py new file mode 100644 index 00000000..6cab713d --- /dev/null +++ b/test/mitmproxy/addons/test_disable_h2c_upgrade.py @@ -0,0 +1,17 @@ +from mitmproxy.addons import disable_h2c_upgrade +from mitmproxy.test import tflow + + +class TestTermLog: + def test_simple(self): + a = disable_h2c_upgrade.DisableH2CleartextUpgrade() + + f = tflow.tflow() + f.request.headers['upgrade'] = 'h2c' + f.request.headers['connection'] = 'foo' + f.request.headers['http2-settings'] = 'bar' + + a.request(f) + assert 'upgrade' not in f.request.headers + assert 'connection' not in f.request.headers + assert 'http2-settings' not in f.request.headers diff --git a/test/mitmproxy/addons/test_dumper.py b/test/mitmproxy/addons/test_dumper.py index 7ac17a7c..8fa8a22a 100644 --- a/test/mitmproxy/addons/test_dumper.py +++ b/test/mitmproxy/addons/test_dumper.py @@ -157,7 +157,7 @@ def test_tcp(): d = dumper.Dumper(sio) with taddons.context(options=dump.Options()) as ctx: ctx.configure(d, flow_detail=3, showhost=True) - f = tflow.ttcpflow(client_conn=True, server_conn=True) + f = tflow.ttcpflow() d.tcp_message(f) assert "it's me" in sio.getvalue() sio.truncate(0) @@ -165,3 +165,21 @@ def test_tcp(): f = tflow.ttcpflow(client_conn=True, err=True) d.tcp_error(f) assert "Error in TCP" in sio.getvalue() + + +def test_websocket(): + sio = io.StringIO() + d = dumper.Dumper(sio) + with taddons.context(options=dump.Options()) as ctx: + ctx.configure(d, flow_detail=3, showhost=True) + f = tflow.twebsocketflow() + d.websocket_message(f) + assert "hello text" in sio.getvalue() + sio.truncate(0) + + d.websocket_end(f) + assert "WebSocket connection closed by" in sio.getvalue() + + f = tflow.twebsocketflow(client_conn=True, err=True) + d.websocket_error(f) + assert "Error in WebSocket" in sio.getvalue() diff --git a/test/mitmproxy/test_tools_dump.py b/test/mitmproxy/test_tools_dump.py index 2e64d2d2..505f514b 100644 --- a/test/mitmproxy/test_tools_dump.py +++ b/test/mitmproxy/test_tools_dump.py @@ -1,10 +1,13 @@ import os +import pytest +from unittest import mock -from mitmproxy.tools import dump from mitmproxy import proxy -from mitmproxy.test import tutils from mitmproxy import log from mitmproxy import controller +from mitmproxy.tools import dump + +from mitmproxy.test import tutils from . import mastertest @@ -37,3 +40,17 @@ class TestDumpMaster(mastertest.MasterTest): ent.reply = controller.DummyReply() m.log(ent) assert m.has_errored + + @pytest.mark.parametrize("termlog", [False, True]) + def test_addons_termlog(self, termlog): + with mock.patch('sys.stdout'): + o = dump.Options() + m = dump.DumpMaster(o, proxy.DummyServer(), with_termlog=termlog) + assert (m.addons.get('termlog') is not None) == termlog + + @pytest.mark.parametrize("dumper", [False, True]) + def test_addons_dumper(self, dumper): + with mock.patch('sys.stdout'): + o = dump.Options() + m = dump.DumpMaster(o, proxy.DummyServer(), with_dumper=dumper) + assert (m.addons.get('dumper') is not None) == dumper diff --git a/test/mitmproxy/test_web_master.py b/test/mitmproxy/test_web_master.py index 08dce8f3..3591284d 100644 --- a/test/mitmproxy/test_web_master.py +++ b/test/mitmproxy/test_web_master.py @@ -1,13 +1,16 @@ from mitmproxy.tools.web import master from mitmproxy import proxy from mitmproxy import options +from mitmproxy.proxy.config import ProxyConfig + from . import mastertest class TestWebMaster(mastertest.MasterTest): def mkmaster(self, **opts): o = options.Options(**opts) - return master.WebMaster(o, proxy.DummyServer(o)) + c = ProxyConfig(o) + return master.WebMaster(o, proxy.DummyServer(c)) def test_basic(self): m = self.mkmaster() diff --git a/web/src/js/filt/filt.js b/web/src/js/filt/filt.js index f2c5ded2..a15f5f9f 100644 --- a/web/src/js/filt/filt.js +++ b/web/src/js/filt/filt.js @@ -59,94 +59,100 @@ module.exports = (function() { peg$c20 = ")", peg$c21 = { type: "literal", value: ")", description: "\")\"" }, peg$c22 = function(expr) { return binding(expr); }, - peg$c23 = "~a", - peg$c24 = { type: "literal", value: "~a", description: "\"~a\"" }, - peg$c25 = function() { return assetFilter; }, - peg$c26 = "~e", - peg$c27 = { type: "literal", value: "~e", description: "\"~e\"" }, - peg$c28 = function() { return errorFilter; }, - peg$c29 = "~http", - peg$c30 = { type: "literal", value: "~http", description: "\"~http\"" }, - peg$c31 = function() { return httpFilter; }, - peg$c32 = "~marked", - peg$c33 = { type: "literal", value: "~marked", description: "\"~marked\"" }, - peg$c34 = function() { return markedFilter; }, - peg$c35 = "~q", - peg$c36 = { type: "literal", value: "~q", description: "\"~q\"" }, - peg$c37 = function() { return noResponseFilter; }, - peg$c38 = "~s", - peg$c39 = { type: "literal", value: "~s", description: "\"~s\"" }, - peg$c40 = function() { return responseFilter; }, - peg$c41 = "~tcp", - peg$c42 = { type: "literal", value: "~tcp", description: "\"~tcp\"" }, - peg$c43 = function() { return tcpFilter; }, - peg$c44 = "true", - peg$c45 = { type: "literal", value: "true", description: "\"true\"" }, - peg$c46 = function() { return trueFilter; }, - peg$c47 = "false", - peg$c48 = { type: "literal", value: "false", description: "\"false\"" }, - peg$c49 = function() { return falseFilter; }, - peg$c50 = "~c", - peg$c51 = { type: "literal", value: "~c", description: "\"~c\"" }, - peg$c52 = function(s) { return responseCode(s); }, - peg$c53 = "~d", - peg$c54 = { type: "literal", value: "~d", description: "\"~d\"" }, - peg$c55 = function(s) { return domain(s); }, - peg$c56 = "~h", - peg$c57 = { type: "literal", value: "~h", description: "\"~h\"" }, - peg$c58 = function(s) { return header(s); }, - peg$c59 = "~hq", - peg$c60 = { type: "literal", value: "~hq", description: "\"~hq\"" }, - peg$c61 = function(s) { return requestHeader(s); }, - peg$c62 = "~hs", - peg$c63 = { type: "literal", value: "~hs", description: "\"~hs\"" }, - peg$c64 = function(s) { return responseHeader(s); }, - peg$c65 = "~m", - peg$c66 = { type: "literal", value: "~m", description: "\"~m\"" }, - peg$c67 = function(s) { return method(s); }, - peg$c68 = "~t", - peg$c69 = { type: "literal", value: "~t", description: "\"~t\"" }, - peg$c70 = function(s) { return contentType(s); }, - peg$c71 = "~tq", - peg$c72 = { type: "literal", value: "~tq", description: "\"~tq\"" }, - peg$c73 = function(s) { return requestContentType(s); }, - peg$c74 = "~ts", - peg$c75 = { type: "literal", value: "~ts", description: "\"~ts\"" }, - peg$c76 = function(s) { return responseContentType(s); }, - peg$c77 = "~u", - peg$c78 = { type: "literal", value: "~u", description: "\"~u\"" }, - peg$c79 = function(s) { return url(s); }, - peg$c80 = { type: "other", description: "integer" }, - peg$c81 = /^['"]/, - peg$c82 = { type: "class", value: "['\"]", description: "['\"]" }, - peg$c83 = /^[0-9]/, - peg$c84 = { type: "class", value: "[0-9]", description: "[0-9]" }, - peg$c85 = function(digits) { return parseInt(digits.join(""), 10); }, - peg$c86 = { type: "other", description: "string" }, - peg$c87 = "\"", - peg$c88 = { type: "literal", value: "\"", description: "\"\\\"\"" }, - peg$c89 = function(chars) { return chars.join(""); }, - peg$c90 = "'", - peg$c91 = { type: "literal", value: "'", description: "\"'\"" }, - peg$c92 = /^["\\]/, - peg$c93 = { type: "class", value: "[\"\\\\]", description: "[\"\\\\]" }, - peg$c94 = { type: "any", description: "any character" }, - peg$c95 = function(char) { return char; }, - peg$c96 = "\\", - peg$c97 = { type: "literal", value: "\\", description: "\"\\\\\"" }, - peg$c98 = /^['\\]/, - peg$c99 = { type: "class", value: "['\\\\]", description: "['\\\\]" }, - peg$c100 = /^['"\\]/, - peg$c101 = { type: "class", value: "['\"\\\\]", description: "['\"\\\\]" }, - peg$c102 = "n", - peg$c103 = { type: "literal", value: "n", description: "\"n\"" }, - peg$c104 = function() { return "\n"; }, - peg$c105 = "r", - peg$c106 = { type: "literal", value: "r", description: "\"r\"" }, - peg$c107 = function() { return "\r"; }, - peg$c108 = "t", - peg$c109 = { type: "literal", value: "t", description: "\"t\"" }, - peg$c110 = function() { return "\t"; }, + peg$c23 = "true", + peg$c24 = { type: "literal", value: "true", description: "\"true\"" }, + peg$c25 = function() { return trueFilter; }, + peg$c26 = "false", + peg$c27 = { type: "literal", value: "false", description: "\"false\"" }, + peg$c28 = function() { return falseFilter; }, + peg$c29 = "~a", + peg$c30 = { type: "literal", value: "~a", description: "\"~a\"" }, + peg$c31 = function() { return assetFilter; }, + peg$c32 = "~c", + peg$c33 = { type: "literal", value: "~c", description: "\"~c\"" }, + peg$c34 = function(s) { return responseCode(s); }, + peg$c35 = "~d", + peg$c36 = { type: "literal", value: "~d", description: "\"~d\"" }, + peg$c37 = function(s) { return domain(s); }, + peg$c38 = "~dst", + peg$c39 = { type: "literal", value: "~dst", description: "\"~dst\"" }, + peg$c40 = function(s) { return destination(s); }, + peg$c41 = "~e", + peg$c42 = { type: "literal", value: "~e", description: "\"~e\"" }, + peg$c43 = function() { return errorFilter; }, + peg$c44 = "~h", + peg$c45 = { type: "literal", value: "~h", description: "\"~h\"" }, + peg$c46 = function(s) { return header(s); }, + peg$c47 = "~hq", + peg$c48 = { type: "literal", value: "~hq", description: "\"~hq\"" }, + peg$c49 = function(s) { return requestHeader(s); }, + peg$c50 = "~hs", + peg$c51 = { type: "literal", value: "~hs", description: "\"~hs\"" }, + peg$c52 = function(s) { return responseHeader(s); }, + peg$c53 = "~http", + peg$c54 = { type: "literal", value: "~http", description: "\"~http\"" }, + peg$c55 = function() { return httpFilter; }, + peg$c56 = "~m", + peg$c57 = { type: "literal", value: "~m", description: "\"~m\"" }, + peg$c58 = function(s) { return method(s); }, + peg$c59 = "~marked", + peg$c60 = { type: "literal", value: "~marked", description: "\"~marked\"" }, + peg$c61 = function() { return markedFilter; }, + peg$c62 = "~q", + peg$c63 = { type: "literal", value: "~q", description: "\"~q\"" }, + peg$c64 = function() { return noResponseFilter; }, + peg$c65 = "~src", + peg$c66 = { type: "literal", value: "~src", description: "\"~src\"" }, + peg$c67 = function(s) { return source(s); }, + peg$c68 = "~s", + peg$c69 = { type: "literal", value: "~s", description: "\"~s\"" }, + peg$c70 = function() { return responseFilter; }, + peg$c71 = "~t", + peg$c72 = { type: "literal", value: "~t", description: "\"~t\"" }, + peg$c73 = function(s) { return contentType(s); }, + peg$c74 = "~tcp", + peg$c75 = { type: "literal", value: "~tcp", description: "\"~tcp\"" }, + peg$c76 = function() { return tcpFilter; }, + peg$c77 = "~tq", + peg$c78 = { type: "literal", value: "~tq", description: "\"~tq\"" }, + peg$c79 = function(s) { return requestContentType(s); }, + peg$c80 = "~ts", + peg$c81 = { type: "literal", value: "~ts", description: "\"~ts\"" }, + peg$c82 = function(s) { return responseContentType(s); }, + peg$c83 = "~u", + peg$c84 = { type: "literal", value: "~u", description: "\"~u\"" }, + peg$c85 = function(s) { return url(s); }, + peg$c86 = { type: "other", description: "integer" }, + peg$c87 = /^['"]/, + peg$c88 = { type: "class", value: "['\"]", description: "['\"]" }, + peg$c89 = /^[0-9]/, + peg$c90 = { type: "class", value: "[0-9]", description: "[0-9]" }, + peg$c91 = function(digits) { return parseInt(digits.join(""), 10); }, + peg$c92 = { type: "other", description: "string" }, + peg$c93 = "\"", + peg$c94 = { type: "literal", value: "\"", description: "\"\\\"\"" }, + peg$c95 = function(chars) { return chars.join(""); }, + peg$c96 = "'", + peg$c97 = { type: "literal", value: "'", description: "\"'\"" }, + peg$c98 = /^["\\]/, + peg$c99 = { type: "class", value: "[\"\\\\]", description: "[\"\\\\]" }, + peg$c100 = { type: "any", description: "any character" }, + peg$c101 = function(char) { return char; }, + peg$c102 = "\\", + peg$c103 = { type: "literal", value: "\\", description: "\"\\\\\"" }, + peg$c104 = /^['\\]/, + peg$c105 = { type: "class", value: "['\\\\]", description: "['\\\\]" }, + peg$c106 = /^['"\\]/, + peg$c107 = { type: "class", value: "['\"\\\\]", description: "['\"\\\\]" }, + peg$c108 = "n", + peg$c109 = { type: "literal", value: "n", description: "\"n\"" }, + peg$c110 = function() { return "\n"; }, + peg$c111 = "r", + peg$c112 = { type: "literal", value: "r", description: "\"r\"" }, + peg$c113 = function() { return "\r"; }, + peg$c114 = "t", + peg$c115 = { type: "literal", value: "t", description: "\"t\"" }, + peg$c116 = function() { return "\t"; }, peg$currPos = 0, peg$savedPos = 0, @@ -655,288 +661,57 @@ module.exports = (function() { } function peg$parseExpr() { - var s0; - - s0 = peg$parseNullaryExpr(); - if (s0 === peg$FAILED) { - s0 = peg$parseUnaryExpr(); - } - - return s0; - } - - function peg$parseNullaryExpr() { - var s0, s1; - - s0 = peg$parseBooleanLiteral(); - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c23) { - s1 = peg$c23; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c24); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c25(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c26) { - s1 = peg$c26; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c27); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c28(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c29) { - s1 = peg$c29; - peg$currPos += 5; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c30); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c31(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 7) === peg$c32) { - s1 = peg$c32; - peg$currPos += 7; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c33); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c34(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c35) { - s1 = peg$c35; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c36); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c37(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c38) { - s1 = peg$c38; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c39); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c40(); - } - s0 = s1; - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c41) { - s1 = peg$c41; - peg$currPos += 4; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c42); } - } - if (s1 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c43(); - } - s0 = s1; - } - } - } - } - } - } - } - - return s0; - } - - function peg$parseBooleanLiteral() { - var s0, s1; + var s0, s1, s2, s3; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c44) { - s1 = peg$c44; + if (input.substr(peg$currPos, 4) === peg$c23) { + s1 = peg$c23; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c45); } + if (peg$silentFails === 0) { peg$fail(peg$c24); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c46(); + s1 = peg$c25(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 5) === peg$c47) { - s1 = peg$c47; + if (input.substr(peg$currPos, 5) === peg$c26) { + s1 = peg$c26; peg$currPos += 5; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c48); } + if (peg$silentFails === 0) { peg$fail(peg$c27); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c49(); + s1 = peg$c28(); } s0 = s1; - } - - return s0; - } - - function peg$parseUnaryExpr() { - var s0, s1, s2, s3; - - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c50) { - s1 = peg$c50; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c51); } - } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parsews(); - if (s3 !== peg$FAILED) { - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parsews(); - } - } else { - s2 = peg$FAILED; - } - if (s2 !== peg$FAILED) { - s3 = peg$parseIntegerLiteral(); - if (s3 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c52(s3); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c53) { - s1 = peg$c53; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c54); } - } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parsews(); - if (s3 !== peg$FAILED) { - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parsews(); - } - } else { - s2 = peg$FAILED; - } - if (s2 !== peg$FAILED) { - s3 = peg$parseStringLiteral(); - if (s3 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c55(s3); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c56) { - s1 = peg$c56; + if (input.substr(peg$currPos, 2) === peg$c29) { + s1 = peg$c29; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c57); } + if (peg$silentFails === 0) { peg$fail(peg$c30); } } if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parsews(); - if (s3 !== peg$FAILED) { - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parsews(); - } - } else { - s2 = peg$FAILED; - } - if (s2 !== peg$FAILED) { - s3 = peg$parseStringLiteral(); - if (s3 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c58(s3); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; + peg$savedPos = s0; + s1 = peg$c31(); } + s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c59) { - s1 = peg$c59; - peg$currPos += 3; + if (input.substr(peg$currPos, 2) === peg$c32) { + s1 = peg$c32; + peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c60); } + if (peg$silentFails === 0) { peg$fail(peg$c33); } } if (s1 !== peg$FAILED) { s2 = []; @@ -950,10 +725,10 @@ module.exports = (function() { s2 = peg$FAILED; } if (s2 !== peg$FAILED) { - s3 = peg$parseStringLiteral(); + s3 = peg$parseIntegerLiteral(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c61(s3); + s1 = peg$c34(s3); s0 = s1; } else { peg$currPos = s0; @@ -969,12 +744,12 @@ module.exports = (function() { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c62) { - s1 = peg$c62; - peg$currPos += 3; + if (input.substr(peg$currPos, 2) === peg$c35) { + s1 = peg$c35; + peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c63); } + if (peg$silentFails === 0) { peg$fail(peg$c36); } } if (s1 !== peg$FAILED) { s2 = []; @@ -991,7 +766,7 @@ module.exports = (function() { s3 = peg$parseStringLiteral(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c64(s3); + s1 = peg$c37(s3); s0 = s1; } else { peg$currPos = s0; @@ -1007,12 +782,12 @@ module.exports = (function() { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c65) { - s1 = peg$c65; - peg$currPos += 2; + if (input.substr(peg$currPos, 4) === peg$c38) { + s1 = peg$c38; + peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c66); } + if (peg$silentFails === 0) { peg$fail(peg$c39); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1029,7 +804,7 @@ module.exports = (function() { s3 = peg$parseStringLiteral(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c67(s3); + s1 = peg$c40(s3); s0 = s1; } else { peg$currPos = s0; @@ -1045,50 +820,26 @@ module.exports = (function() { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c68) { - s1 = peg$c68; + if (input.substr(peg$currPos, 2) === peg$c41) { + s1 = peg$c41; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c69); } + if (peg$silentFails === 0) { peg$fail(peg$c42); } } if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parsews(); - if (s3 !== peg$FAILED) { - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parsews(); - } - } else { - s2 = peg$FAILED; - } - if (s2 !== peg$FAILED) { - s3 = peg$parseStringLiteral(); - if (s3 !== peg$FAILED) { - peg$savedPos = s0; - s1 = peg$c70(s3); - s0 = s1; - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; + peg$savedPos = s0; + s1 = peg$c43(); } + s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c71) { - s1 = peg$c71; - peg$currPos += 3; + if (input.substr(peg$currPos, 2) === peg$c44) { + s1 = peg$c44; + peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c72); } + if (peg$silentFails === 0) { peg$fail(peg$c45); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1105,7 +856,7 @@ module.exports = (function() { s3 = peg$parseStringLiteral(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c73(s3); + s1 = peg$c46(s3); s0 = s1; } else { peg$currPos = s0; @@ -1121,12 +872,12 @@ module.exports = (function() { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 3) === peg$c74) { - s1 = peg$c74; + if (input.substr(peg$currPos, 3) === peg$c47) { + s1 = peg$c47; peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c75); } + if (peg$silentFails === 0) { peg$fail(peg$c48); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1143,7 +894,7 @@ module.exports = (function() { s3 = peg$parseStringLiteral(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c76(s3); + s1 = peg$c49(s3); s0 = s1; } else { peg$currPos = s0; @@ -1159,12 +910,12 @@ module.exports = (function() { } if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c77) { - s1 = peg$c77; - peg$currPos += 2; + if (input.substr(peg$currPos, 3) === peg$c50) { + s1 = peg$c50; + peg$currPos += 3; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c78); } + if (peg$silentFails === 0) { peg$fail(peg$c51); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1181,7 +932,7 @@ module.exports = (function() { s3 = peg$parseStringLiteral(); if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c79(s3); + s1 = peg$c52(s3); s0 = s1; } else { peg$currPos = s0; @@ -1197,12 +948,321 @@ module.exports = (function() { } if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = peg$parseStringLiteral(); + if (input.substr(peg$currPos, 5) === peg$c53) { + s1 = peg$c53; + peg$currPos += 5; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c54); } + } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c79(s1); + s1 = peg$c55(); } s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c56) { + s1 = peg$c56; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c57); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsews(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseStringLiteral(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c58(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 7) === peg$c59) { + s1 = peg$c59; + peg$currPos += 7; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c60); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c61(); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c62) { + s1 = peg$c62; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c63); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c64(); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 4) === peg$c65) { + s1 = peg$c65; + peg$currPos += 4; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c66); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsews(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseStringLiteral(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c67(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c68) { + s1 = peg$c68; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c69); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c70(); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c71) { + s1 = peg$c71; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c72); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsews(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseStringLiteral(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c73(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 4) === peg$c74) { + s1 = peg$c74; + peg$currPos += 4; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c75); } + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c76(); + } + s0 = s1; + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 3) === peg$c77) { + s1 = peg$c77; + peg$currPos += 3; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c78); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsews(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseStringLiteral(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c79(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 3) === peg$c80) { + s1 = peg$c80; + peg$currPos += 3; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c81); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsews(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseStringLiteral(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c82(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c83) { + s1 = peg$c83; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$c84); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parsews(); + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parsews(); + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = peg$parseStringLiteral(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c85(s3); + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + if (s0 === peg$FAILED) { + s0 = peg$currPos; + s1 = peg$parseStringLiteral(); + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$c85(s1); + } + s0 = s1; + } + } + } + } + } + } + } + } + } + } + } } } } @@ -1222,53 +1282,53 @@ module.exports = (function() { peg$silentFails++; s0 = peg$currPos; - if (peg$c81.test(input.charAt(peg$currPos))) { + if (peg$c87.test(input.charAt(peg$currPos))) { s1 = input.charAt(peg$currPos); peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c82); } + if (peg$silentFails === 0) { peg$fail(peg$c88); } } if (s1 === peg$FAILED) { s1 = null; } if (s1 !== peg$FAILED) { s2 = []; - if (peg$c83.test(input.charAt(peg$currPos))) { + if (peg$c89.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c84); } + if (peg$silentFails === 0) { peg$fail(peg$c90); } } if (s3 !== peg$FAILED) { while (s3 !== peg$FAILED) { s2.push(s3); - if (peg$c83.test(input.charAt(peg$currPos))) { + if (peg$c89.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c84); } + if (peg$silentFails === 0) { peg$fail(peg$c90); } } } } else { s2 = peg$FAILED; } if (s2 !== peg$FAILED) { - if (peg$c81.test(input.charAt(peg$currPos))) { + if (peg$c87.test(input.charAt(peg$currPos))) { s3 = input.charAt(peg$currPos); peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c82); } + if (peg$silentFails === 0) { peg$fail(peg$c88); } } if (s3 === peg$FAILED) { s3 = null; } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c85(s2); + s1 = peg$c91(s2); s0 = s1; } else { peg$currPos = s0; @@ -1285,7 +1345,7 @@ module.exports = (function() { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c80); } + if (peg$silentFails === 0) { peg$fail(peg$c86); } } return s0; @@ -1297,11 +1357,11 @@ module.exports = (function() { peg$silentFails++; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c87; + s1 = peg$c93; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c88); } + if (peg$silentFails === 0) { peg$fail(peg$c94); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1312,15 +1372,15 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c87; + s3 = peg$c93; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c88); } + if (peg$silentFails === 0) { peg$fail(peg$c94); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c89(s2); + s1 = peg$c95(s2); s0 = s1; } else { peg$currPos = s0; @@ -1337,11 +1397,11 @@ module.exports = (function() { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 39) { - s1 = peg$c90; + s1 = peg$c96; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c91); } + if (peg$silentFails === 0) { peg$fail(peg$c97); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1352,15 +1412,15 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { if (input.charCodeAt(peg$currPos) === 39) { - s3 = peg$c90; + s3 = peg$c96; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c91); } + if (peg$silentFails === 0) { peg$fail(peg$c97); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c89(s2); + s1 = peg$c95(s2); s0 = s1; } else { peg$currPos = s0; @@ -1399,7 +1459,7 @@ module.exports = (function() { } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c89(s2); + s1 = peg$c95(s2); s0 = s1; } else { peg$currPos = s0; @@ -1414,7 +1474,7 @@ module.exports = (function() { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c86); } + if (peg$silentFails === 0) { peg$fail(peg$c92); } } return s0; @@ -1426,12 +1486,12 @@ module.exports = (function() { s0 = peg$currPos; s1 = peg$currPos; peg$silentFails++; - if (peg$c92.test(input.charAt(peg$currPos))) { + if (peg$c98.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c93); } + if (peg$silentFails === 0) { peg$fail(peg$c99); } } peg$silentFails--; if (s2 === peg$FAILED) { @@ -1446,11 +1506,11 @@ module.exports = (function() { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c94); } + if (peg$silentFails === 0) { peg$fail(peg$c100); } } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c95(s2); + s1 = peg$c101(s2); s0 = s1; } else { peg$currPos = s0; @@ -1463,17 +1523,17 @@ module.exports = (function() { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 92) { - s1 = peg$c96; + s1 = peg$c102; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c97); } + if (peg$silentFails === 0) { peg$fail(peg$c103); } } if (s1 !== peg$FAILED) { s2 = peg$parseEscapeSequence(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c95(s2); + s1 = peg$c101(s2); s0 = s1; } else { peg$currPos = s0; @@ -1494,12 +1554,12 @@ module.exports = (function() { s0 = peg$currPos; s1 = peg$currPos; peg$silentFails++; - if (peg$c98.test(input.charAt(peg$currPos))) { + if (peg$c104.test(input.charAt(peg$currPos))) { s2 = input.charAt(peg$currPos); peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c99); } + if (peg$silentFails === 0) { peg$fail(peg$c105); } } peg$silentFails--; if (s2 === peg$FAILED) { @@ -1514,11 +1574,11 @@ module.exports = (function() { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c94); } + if (peg$silentFails === 0) { peg$fail(peg$c100); } } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c95(s2); + s1 = peg$c101(s2); s0 = s1; } else { peg$currPos = s0; @@ -1531,17 +1591,17 @@ module.exports = (function() { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 92) { - s1 = peg$c96; + s1 = peg$c102; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c97); } + if (peg$silentFails === 0) { peg$fail(peg$c103); } } if (s1 !== peg$FAILED) { s2 = peg$parseEscapeSequence(); if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c95(s2); + s1 = peg$c101(s2); s0 = s1; } else { peg$currPos = s0; @@ -1576,11 +1636,11 @@ module.exports = (function() { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c94); } + if (peg$silentFails === 0) { peg$fail(peg$c100); } } if (s2 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c95(s2); + s1 = peg$c101(s2); s0 = s1; } else { peg$currPos = s0; @@ -1597,53 +1657,53 @@ module.exports = (function() { function peg$parseEscapeSequence() { var s0, s1; - if (peg$c100.test(input.charAt(peg$currPos))) { + if (peg$c106.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c101); } + if (peg$silentFails === 0) { peg$fail(peg$c107); } } if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 110) { - s1 = peg$c102; + s1 = peg$c108; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c103); } + if (peg$silentFails === 0) { peg$fail(peg$c109); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c104(); + s1 = peg$c110(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 114) { - s1 = peg$c105; + s1 = peg$c111; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c106); } + if (peg$silentFails === 0) { peg$fail(peg$c112); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c107(); + s1 = peg$c113(); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 116) { - s1 = peg$c108; + s1 = peg$c114; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$c109); } + if (peg$silentFails === 0) { peg$fail(peg$c115); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$c110(); + s1 = peg$c116(); } s0 = s1; } @@ -1730,6 +1790,16 @@ module.exports = (function() { domainFilter.desc = "domain matches " + regex; return domainFilter; } + function destination(regex){ + regex = new RegExp(regex, "i"); + function destinationFilter(flow){ + return (!!flow.server_conn.address) + && + regex.test(flow.server_conn.address.address[0] + ":" + flow.server_conn.address.address[1]); + } + destinationFilter.desc = "destination address matches " + regex; + return destinationFilter; + } function errorFilter(flow){ return !!flow.error; } @@ -1786,7 +1856,16 @@ module.exports = (function() { return !!flow.response; } responseFilter.desc = "has response"; - + function source(regex){ + regex = new RegExp(regex, "i"); + function sourceFilter(flow){ + return (!!flow.client_conn.address) + && + regex.test(flow.client_conn.address.address[0] + ":" + flow.client_conn.address.address[1]); + } + sourceFilter.desc = "source address matches " + regex; + return sourceFilter; + } function contentType(regex){ regex = new RegExp(regex, "i"); function contentTypeFilter(flow){ diff --git a/web/src/js/filt/filt.peg b/web/src/js/filt/filt.peg index f3235ccd..64780d8a 100644 --- a/web/src/js/filt/filt.peg +++ b/web/src/js/filt/filt.peg @@ -77,6 +77,16 @@ function domain(regex){ domainFilter.desc = "domain matches " + regex; return domainFilter; } +function destination(regex){ + regex = new RegExp(regex, "i"); + function destinationFilter(flow){ + return (!!flow.server_conn.address) + && + regex.test(flow.server_conn.address.address[0] + ":" + flow.server_conn.address.address[1]); + } + destinationFilter.desc = "destination address matches " + regex; + return destinationFilter; +} function errorFilter(flow){ return !!flow.error; } @@ -133,7 +143,16 @@ function responseFilter(flow){ return !!flow.response; } responseFilter.desc = "has response"; - +function source(regex){ + regex = new RegExp(regex, "i"); + function sourceFilter(flow){ + return (!!flow.client_conn.address) + && + regex.test(flow.client_conn.address.address[0] + ":" + flow.client_conn.address.address[1]); + } + sourceFilter.desc = "source address matches " + regex; + return sourceFilter; +} function contentType(regex){ regex = new RegExp(regex, "i"); function contentTypeFilter(flow){ @@ -205,36 +224,33 @@ BindingExpr { return binding(expr); } / Expr -Expr - = NullaryExpr - / UnaryExpr +/* All the filters except "~s" and "~src" are arranged in the ascending order as + given in the docs(http://docs.mitmproxy.org/en/latest/features/filters.html). + "~s" and "~src" are so arranged as "~s" caused problems in the evaluation of + "~src". */ -NullaryExpr - = BooleanLiteral +Expr + = "true" { return trueFilter; } + / "false" { return falseFilter; } / "~a" { return assetFilter; } + / "~c" ws+ s:IntegerLiteral { return responseCode(s); } + / "~d" ws+ s:StringLiteral { return domain(s); } + / "~dst" ws+ s:StringLiteral { return destination(s); } / "~e" { return errorFilter; } + / "~h" ws+ s:StringLiteral { return header(s); } + / "~hq" ws+ s:StringLiteral { return requestHeader(s); } + / "~hs" ws+ s:StringLiteral { return responseHeader(s); } / "~http" { return httpFilter; } + / "~m" ws+ s:StringLiteral { return method(s); } / "~marked" { return markedFilter; } / "~q" { return noResponseFilter; } + / "~src" ws+ s:StringLiteral { return source(s); } / "~s" { return responseFilter; } + / "~t" ws+ s:StringLiteral { return contentType(s); } / "~tcp" { return tcpFilter; } - - -BooleanLiteral - = "true" { return trueFilter; } - / "false" { return falseFilter; } - -UnaryExpr - = "~c" ws+ s:IntegerLiteral { return responseCode(s); } - / "~d" ws+ s:StringLiteral { return domain(s); } - / "~h" ws+ s:StringLiteral { return header(s); } - / "~hq" ws+ s:StringLiteral { return requestHeader(s); } - / "~hs" ws+ s:StringLiteral { return responseHeader(s); } - / "~m" ws+ s:StringLiteral { return method(s); } - / "~t" ws+ s:StringLiteral { return contentType(s); } / "~tq" ws+ s:StringLiteral { return requestContentType(s); } / "~ts" ws+ s:StringLiteral { return responseContentType(s); } - / "~u" ws+ s:StringLiteral { return url(s); } + / "~u" ws+ s:StringLiteral { return url(s); } / s:StringLiteral { return url(s); } IntegerLiteral "integer" |