From 1959aebc087db0cb3bb12546ec2671356829b482 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 3 Jan 2015 11:46:51 +1300 Subject: Add PEG support to gulpfile - Extract conf - all project specific conf outside gulpfile - Generalize filt.js exports, add required imports --- web/conf.js | 33 ++++++ web/gulpfile.js | 97 +++++++--------- web/src/js/app.js | 3 +- web/src/js/components/header.js | 5 +- web/src/js/filt/filt.js | 30 +++-- web/src/js/filt/filt.peg | 249 ++++++++++++++++++++++++++++++++++++++++ web/src/js/filt/filt.pegjs | 247 --------------------------------------- 7 files changed, 343 insertions(+), 321 deletions(-) create mode 100644 web/conf.js create mode 100644 web/src/js/filt/filt.peg delete mode 100644 web/src/js/filt/filt.pegjs (limited to 'web') diff --git a/web/conf.js b/web/conf.js new file mode 100644 index 00000000..5106bae2 --- /dev/null +++ b/web/conf.js @@ -0,0 +1,33 @@ + +var conf = { + src: "src/", + dist: "../libmproxy/web", + static: "../libmproxy/web/static", + js: { + // Don't package these in the vendor distribution + vendor_excludes: [ + "bootstrap" + ], + // Package these as well as the dependencies + vendor_includes: [ + "react/addons" + ], + app: 'src/js/app.js', + jshint: ["src/js/**.js", "!src/js/filt/filt.js"] + }, + css: { + vendor: ["src/css/vendor.less"], + app: ["src/css/app.less"] + }, + copy: [ + "src/images/**", + ], + templates: [ + "src/templates/*" + ], + fonts: ["src/fontawesome/fontawesome-webfont.*"], + peg: ["src/js/filt/filt.peg"], + port: 8082 +}; + +module.exports = conf; \ No newline at end of file diff --git a/web/gulpfile.js b/web/gulpfile.js index 65766d66..3a39ce14 100644 --- a/web/gulpfile.js +++ b/web/gulpfile.js @@ -22,8 +22,11 @@ var source = require('vinyl-source-stream'); var sourcemaps = require('gulp-sourcemaps'); var transform = require('vinyl-transform'); var uglify = require('gulp-uglify'); +var peg = require("gulp-peg"); +var filelog = require('gulp-filelog'); var packagejs = require('./package.json'); +var conf = require('./conf.js'); // FIXME: react-with-addons.min.js for prod use issue @@ -35,41 +38,13 @@ var manifest = { "app.js": "app.js", }; -var CONF = { - dist: "../libmproxy/web", - static: "../libmproxy/web/static", - js: { - // Don't package these in the vendor distribution - vendor_excludes: [ - "bootstrap" - ], - // Package these as well as the dependencies - vendor_includes: [ - "react/addons" - ], - app: 'src/js/app.js' - }, - css: { - vendor: ["src/css/vendor.less"], - app: ["src/css/app.less"] - }, - copy: [ - "src/images/**", - ], - templates: [ - "src/templates/*" - ], - fonts: ["src/fontawesome/fontawesome-webfont.*"], - port: 8082 -}; - var vendor_packages = _.difference( - _.union( - _.keys(packagejs.dependencies), - CONF.js.vendor_includes - ), - CONF.js.vendor_excludes - ); + _.union( + _.keys(packagejs.dependencies), + conf.js.vendor_includes + ), + conf.js.vendor_excludes +); // Custom linting reporter used for error notify @@ -113,8 +88,8 @@ var dont_break_on_errors = function(){ gulp.task("fonts", function () { - return gulp.src(CONF.fonts) - .pipe(gulp.dest(CONF.dist + "fonts")); + return gulp.src(conf.fonts) + .pipe(gulp.dest(conf.dist + "fonts")); }); @@ -124,14 +99,14 @@ function styles_dev(files) { .pipe(sourcemaps.init()) .pipe(less()) .pipe(sourcemaps.write(".", {sourceRoot: "/static"})) - .pipe(gulp.dest(CONF.static)) + .pipe(gulp.dest(conf.static)) .pipe(livereload({ auto: false }))); } gulp.task("styles-app-dev", function(){ - styles_dev(CONF.css.app); + styles_dev(conf.css.app); }); gulp.task("styles-vendor-dev", function(){ - styles_dev(CONF.css.vendor); + styles_dev(conf.css.vendor); }); @@ -143,14 +118,14 @@ function styles_prod(files) { .pipe(minifyCSS()) .pipe(rev()) .pipe(save_rev()) - .pipe(gulp.dest(CONF.static)) + .pipe(gulp.dest(conf.static)) .pipe(livereload({ auto: false }))); } gulp.task("styles-app-prod", function(){ - styles_prod(CONF.css.app); + styles_prod(conf.css.app); }); gulp.task("styles-vendor-prod", function(){ - styles_prod(CONF.css.vendor); + styles_prod(conf.css.vendor); }); @@ -165,7 +140,7 @@ function vendor_stream(debug){ } gulp.task("scripts-vendor-dev", function (){ return vendor_stream(true) - .pipe(gulp.dest(CONF.static)); + .pipe(gulp.dest(conf.static)); }); gulp.task("scripts-vendor-prod", function(){ return vendor_stream(false) @@ -173,7 +148,7 @@ gulp.task("scripts-vendor-prod", function(){ .pipe(uglify()) .pipe(rev()) .pipe(save_rev()) - .pipe(gulp.dest(CONF.static)); + .pipe(gulp.dest(conf.static)); }); @@ -186,14 +161,14 @@ function app_stream(debug) { b.transform(reactify); return b.bundle(); }); - return gulp.src([CONF.js.app]) + return gulp.src([conf.js.app]) .pipe(dont_break_on_errors()) .pipe(browserified) .pipe(rename("app.js")); }; gulp.task('scripts-app-dev', function () { return app_stream(true) - .pipe(gulp.dest(CONF.static)) + .pipe(gulp.dest(conf.static)) .pipe(livereload({ auto: false })); }); gulp.task('scripts-app-prod', function () { @@ -202,12 +177,12 @@ gulp.task('scripts-app-prod', function () { .pipe(uglify()) .pipe(rev()) .pipe(save_rev()) - .pipe(gulp.dest(CONF.static)); + .pipe(gulp.dest(conf.static)); }); gulp.task("jshint", function () { - return gulp.src(["src/js/**.js"]) + return gulp.src(conf.js.jshint) .pipe(dont_break_on_errors()) .pipe(react()) .pipe(plumber()) @@ -217,27 +192,34 @@ gulp.task("jshint", function () { }); gulp.task("copy", function(){ - return gulp.src(CONF.copy, {base:"src/"}) - .pipe(gulp.dest(CONF.dist)); + return gulp.src(conf.copy, {base:"src/"}) + .pipe(gulp.dest(conf.dist)); }); function templates(){ - return gulp.src(CONF.templates, {base:"src/"}) + return gulp.src(conf.templates, {base:"src/"}) .pipe(replace(/\{\{\{(\S*)\}\}\}/g, function(match, p1) { return manifest[p1]; })) - .pipe(gulp.dest(CONF.dist)); + .pipe(gulp.dest(conf.dist)); }; gulp.task('templates', templates); +gulp.task("peg", function () { + return gulp.src(conf.peg, {base: "src/"}) + .pipe(dont_break_on_errors()) + .pipe(peg()) + .pipe(filelog()) + .pipe(gulp.dest("src/")); +}); + gulp.task('connect', function() { connect.server({ - port: CONF.port + port: conf.port }); }); -common = ["fonts", "copy"]; gulp.task( "dev", [ @@ -246,6 +228,7 @@ gulp.task( "styles-vendor-dev", "styles-app-dev", "scripts-vendor-dev", + "peg", "scripts-app-dev", ], templates @@ -258,6 +241,7 @@ gulp.task( "styles-vendor-prod", "styles-app-prod", "scripts-vendor-prod", + "peg", "scripts-app-prod", "connect" ], @@ -267,8 +251,9 @@ gulp.task( gulp.task("default", ["dev", "connect"], function () { livereload.listen({auto: true}); gulp.watch(["src/css/vendor*"], ["styles-vendor-dev"]); + gulp.watch(conf.peg, ["peg", "scripts-app-dev"]); gulp.watch(["src/js/**"], ["scripts-app-dev", "jshint"]); gulp.watch(["src/css/**"], ["styles-app-dev"]); - gulp.watch(CONF.templates, ["templates"]); - gulp.watch(CONF.copy, ["copy"]); + gulp.watch(conf.templates, ["templates"]); + gulp.watch(conf.copy, ["copy"]); }); diff --git a/web/src/js/app.js b/web/src/js/app.js index 4ec7d699..a7f3570e 100644 --- a/web/src/js/app.js +++ b/web/src/js/app.js @@ -12,4 +12,5 @@ $(function () { ReactRouter.run(proxyapp.routes, function (Handler) { React.render(, document.body); }); -}); \ No newline at end of file +}); + diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js index 796f567f..c8f4ce3b 100644 --- a/web/src/js/components/header.js +++ b/web/src/js/components/header.js @@ -1,6 +1,9 @@ var React = require("react"); var $ = require("jquery"); +var Filt = require("../filt/filt.js"); +var utils = require("../utils.js"); + var common = require("./common.js"); var FilterDocs = React.createClass({ @@ -105,7 +108,7 @@ var FilterInput = React.createClass({ this.setState({mousefocus: false}); }, onKeyDown: function (e) { - if (e.keyCode === Key.ESC || e.keyCode === Key.ENTER) { + if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) { this.blur(); // If closed using ESC/ENTER, hide the tooltip. this.setState({mousefocus: false}); diff --git a/web/src/js/filt/filt.js b/web/src/js/filt/filt.js index 095081ac..78d6a67c 100644 --- a/web/src/js/filt/filt.js +++ b/web/src/js/filt/filt.js @@ -1,5 +1,4 @@ -/* jshint ignore:start */ -Filt = (function() { +module.exports = (function() { /* * Generated by PEG.js 0.8.0. * @@ -1592,6 +1591,8 @@ Filt = (function() { } + var flowutils = require("../flow/utils.js"); + function or(first, second) { // Add explicit function names to ease debugging. function orFilter() { @@ -1640,7 +1641,7 @@ Filt = (function() { ]; function assetFilter(flow) { if (flow.response) { - var ct = ResponseUtils.getContentType(flow.response); + var ct = flowutils.ResponseUtils.getContentType(flow.response); var i = ASSET_TYPES.length; while (i--) { if (ASSET_TYPES[i].test(ct)) { @@ -1674,9 +1675,9 @@ Filt = (function() { regex = new RegExp(regex, "i"); function headerFilter(flow){ return ( - (flow.request && RequestUtils.match_header(flow.request, regex)) + (flow.request && flowutils.RequestUtils.match_header(flow.request, regex)) || - (flow.response && ResponseUtils.match_header(flow.response, regex)) + (flow.response && flowutils.ResponseUtils.match_header(flow.response, regex)) ); } headerFilter.desc = "header matches " + regex; @@ -1685,7 +1686,7 @@ Filt = (function() { function requestHeader(regex){ regex = new RegExp(regex, "i"); function requestHeaderFilter(flow){ - return (flow.request && RequestUtils.match_header(flow.request, regex)); + return (flow.request && flowutils.RequestUtils.match_header(flow.request, regex)); } requestHeaderFilter.desc = "req. header matches " + regex; return requestHeaderFilter; @@ -1693,7 +1694,7 @@ Filt = (function() { function responseHeader(regex){ regex = new RegExp(regex, "i"); function responseHeaderFilter(flow){ - return (flow.response && ResponseUtils.match_header(flow.response, regex)); + return (flow.response && flowutils.ResponseUtils.match_header(flow.response, regex)); } responseHeaderFilter.desc = "resp. header matches " + regex; return responseHeaderFilter; @@ -1719,9 +1720,9 @@ Filt = (function() { regex = new RegExp(regex, "i"); function contentTypeFilter(flow){ return ( - (flow.request && regex.test(RequestUtils.getContentType(flow.request))) + (flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request))) || - (flow.response && regex.test(ResponseUtils.getContentType(flow.response))) + (flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response))) ); } contentTypeFilter.desc = "content type matches " + regex; @@ -1730,7 +1731,7 @@ Filt = (function() { function requestContentType(regex){ regex = new RegExp(regex, "i"); function requestContentTypeFilter(flow){ - return flow.request && regex.test(RequestUtils.getContentType(flow.request)); + return flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request)); } requestContentTypeFilter.desc = "req. content type matches " + regex; return requestContentTypeFilter; @@ -1738,7 +1739,7 @@ Filt = (function() { function responseContentType(regex){ regex = new RegExp(regex, "i"); function responseContentTypeFilter(flow){ - return flow.response && regex.test(ResponseUtils.getContentType(flow.response)); + return flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response)); } responseContentTypeFilter.desc = "resp. content type matches " + regex; return responseContentTypeFilter; @@ -1746,7 +1747,7 @@ Filt = (function() { function url(regex){ regex = new RegExp(regex, "i"); function urlFilter(flow){ - return flow.request && regex.test(RequestUtils.pretty_url(flow.request)); + return flow.request && regex.test(flowutils.RequestUtils.pretty_url(flow.request)); } urlFilter.desc = "url matches " + regex; return urlFilter; @@ -1770,7 +1771,4 @@ Filt = (function() { SyntaxError: SyntaxError, parse: parse }; -})(); -/* jshint ignore:end */ - -module.exports = Filt; +})(); \ No newline at end of file diff --git a/web/src/js/filt/filt.peg b/web/src/js/filt/filt.peg new file mode 100644 index 00000000..b4763ccf --- /dev/null +++ b/web/src/js/filt/filt.peg @@ -0,0 +1,249 @@ +// PEG.js filter rules - see http://pegjs.majda.cz/online + +{ +var flowutils = require("../flow/utils.js"); + +function or(first, second) { + // Add explicit function names to ease debugging. + function orFilter() { + return first.apply(this, arguments) || second.apply(this, arguments); + } + orFilter.desc = first.desc + " or " + second.desc; + return orFilter; +} +function and(first, second) { + function andFilter() { + return first.apply(this, arguments) && second.apply(this, arguments); + } + andFilter.desc = first.desc + " and " + second.desc; + return andFilter; +} +function not(expr) { + function notFilter() { + return !expr.apply(this, arguments); + } + notFilter.desc = "not " + expr.desc; + return notFilter; +} +function binding(expr) { + function bindingFilter() { + return expr.apply(this, arguments); + } + bindingFilter.desc = "(" + expr.desc + ")"; + return bindingFilter; +} +function trueFilter(flow) { + return true; +} +trueFilter.desc = "true"; +function falseFilter(flow) { + return false; +} +falseFilter.desc = "false"; + +var ASSET_TYPES = [ + new RegExp("text/javascript"), + new RegExp("application/x-javascript"), + new RegExp("application/javascript"), + new RegExp("text/css"), + new RegExp("image/.*"), + new RegExp("application/x-shockwave-flash") +]; +function assetFilter(flow) { + if (flow.response) { + var ct = flowutils.ResponseUtils.getContentType(flow.response); + var i = ASSET_TYPES.length; + while (i--) { + if (ASSET_TYPES[i].test(ct)) { + return true; + } + } + } + return false; +} +assetFilter.desc = "is asset"; +function responseCode(code){ + function responseCodeFilter(flow){ + return flow.response && flow.response.code === code; + } + responseCodeFilter.desc = "resp. code is " + code; + return responseCodeFilter; +} +function domain(regex){ + regex = new RegExp(regex, "i"); + function domainFilter(flow){ + return flow.request && regex.test(flow.request.host); + } + domainFilter.desc = "domain matches " + regex; + return domainFilter; +} +function errorFilter(flow){ + return !!flow.error; +} +errorFilter.desc = "has error"; +function header(regex){ + regex = new RegExp(regex, "i"); + function headerFilter(flow){ + return ( + (flow.request && flowutils.RequestUtils.match_header(flow.request, regex)) + || + (flow.response && flowutils.ResponseUtils.match_header(flow.response, regex)) + ); + } + headerFilter.desc = "header matches " + regex; + return headerFilter; +} +function requestHeader(regex){ + regex = new RegExp(regex, "i"); + function requestHeaderFilter(flow){ + return (flow.request && flowutils.RequestUtils.match_header(flow.request, regex)); + } + requestHeaderFilter.desc = "req. header matches " + regex; + return requestHeaderFilter; +} +function responseHeader(regex){ + regex = new RegExp(regex, "i"); + function responseHeaderFilter(flow){ + return (flow.response && flowutils.ResponseUtils.match_header(flow.response, regex)); + } + responseHeaderFilter.desc = "resp. header matches " + regex; + return responseHeaderFilter; +} +function method(regex){ + regex = new RegExp(regex, "i"); + function methodFilter(flow){ + return flow.request && regex.test(flow.request.method); + } + methodFilter.desc = "method matches " + regex; + return methodFilter; +} +function noResponseFilter(flow){ + return flow.request && !flow.response; +} +noResponseFilter.desc = "has no response"; +function responseFilter(flow){ + return !!flow.response; +} +responseFilter.desc = "has response"; + +function contentType(regex){ + regex = new RegExp(regex, "i"); + function contentTypeFilter(flow){ + return ( + (flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request))) + || + (flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response))) + ); + } + contentTypeFilter.desc = "content type matches " + regex; + return contentTypeFilter; +} +function requestContentType(regex){ + regex = new RegExp(regex, "i"); + function requestContentTypeFilter(flow){ + return flow.request && regex.test(flowutils.RequestUtils.getContentType(flow.request)); + } + requestContentTypeFilter.desc = "req. content type matches " + regex; + return requestContentTypeFilter; +} +function responseContentType(regex){ + regex = new RegExp(regex, "i"); + function responseContentTypeFilter(flow){ + return flow.response && regex.test(flowutils.ResponseUtils.getContentType(flow.response)); + } + responseContentTypeFilter.desc = "resp. content type matches " + regex; + return responseContentTypeFilter; +} +function url(regex){ + regex = new RegExp(regex, "i"); + function urlFilter(flow){ + return flow.request && regex.test(flowutils.RequestUtils.pretty_url(flow.request)); + } + urlFilter.desc = "url matches " + regex; + return urlFilter; +} +} + +start "filter expression" + = __ orExpr:OrExpr __ { return orExpr; } + / {return trueFilter; } + +ws "whitespace" = [ \t\n\r] +cc "control character" = [|&!()~"] +__ "optional whitespace" = ws* + +OrExpr + = first:AndExpr __ "|" __ second:OrExpr + { return or(first, second); } + / AndExpr + +AndExpr + = first:NotExpr __ "&" __ second:AndExpr + { return and(first, second); } + / first:NotExpr ws+ second:AndExpr + { return and(first, second); } + / NotExpr + +NotExpr + = "!" __ expr:NotExpr + { return not(expr); } + / BindingExpr + +BindingExpr + = "(" __ expr:OrExpr __ ")" + { return binding(expr); } + / Expr + +Expr + = NullaryExpr + / UnaryExpr + +NullaryExpr + = BooleanLiteral + / "~a" { return assetFilter; } + / "~e" { return errorFilter; } + / "~q" { return noResponseFilter; } + / "~s" { return responseFilter; } + + +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); } + / s:StringLiteral { return url(s); } + +IntegerLiteral "integer" + = ['"]? digits:[0-9]+ ['"]? { return parseInt(digits.join(""), 10); } + +StringLiteral "string" + = '"' chars:DoubleStringChar* '"' { return chars.join(""); } + / "'" chars:SingleStringChar* "'" { return chars.join(""); } + / !cc chars:UnquotedStringChar+ { return chars.join(""); } + +DoubleStringChar + = !["\\] char:. { return char; } + / "\\" char:EscapeSequence { return char; } + +SingleStringChar + = !['\\] char:. { return char; } + / "\\" char:EscapeSequence { return char; } + +UnquotedStringChar + = !ws char:. { return char; } + +EscapeSequence + = ['"\\] + / "n" { return "\n"; } + / "r" { return "\r"; } + / "t" { return "\t"; } \ No newline at end of file diff --git a/web/src/js/filt/filt.pegjs b/web/src/js/filt/filt.pegjs deleted file mode 100644 index 0870e4fe..00000000 --- a/web/src/js/filt/filt.pegjs +++ /dev/null @@ -1,247 +0,0 @@ -// PEG.js filter rules - see http://pegjs.majda.cz/online - -{ -function or(first, second) { - // Add explicit function names to ease debugging. - function orFilter() { - return first.apply(this, arguments) || second.apply(this, arguments); - } - orFilter.desc = first.desc + " or " + second.desc; - return orFilter; -} -function and(first, second) { - function andFilter() { - return first.apply(this, arguments) && second.apply(this, arguments); - } - andFilter.desc = first.desc + " and " + second.desc; - return andFilter; -} -function not(expr) { - function notFilter() { - return !expr.apply(this, arguments); - } - notFilter.desc = "not " + expr.desc; - return notFilter; -} -function binding(expr) { - function bindingFilter() { - return expr.apply(this, arguments); - } - bindingFilter.desc = "(" + expr.desc + ")"; - return bindingFilter; -} -function trueFilter(flow) { - return true; -} -trueFilter.desc = "true"; -function falseFilter(flow) { - return false; -} -falseFilter.desc = "false"; - -var ASSET_TYPES = [ - new RegExp("text/javascript"), - new RegExp("application/x-javascript"), - new RegExp("application/javascript"), - new RegExp("text/css"), - new RegExp("image/.*"), - new RegExp("application/x-shockwave-flash") -]; -function assetFilter(flow) { - if (flow.response) { - var ct = ResponseUtils.getContentType(flow.response); - var i = ASSET_TYPES.length; - while (i--) { - if (ASSET_TYPES[i].test(ct)) { - return true; - } - } - } - return false; -} -assetFilter.desc = "is asset"; -function responseCode(code){ - function responseCodeFilter(flow){ - return flow.response && flow.response.code === code; - } - responseCodeFilter.desc = "resp. code is " + code; - return responseCodeFilter; -} -function domain(regex){ - regex = new RegExp(regex, "i"); - function domainFilter(flow){ - return flow.request && regex.test(flow.request.host); - } - domainFilter.desc = "domain matches " + regex; - return domainFilter; -} -function errorFilter(flow){ - return !!flow.error; -} -errorFilter.desc = "has error"; -function header(regex){ - regex = new RegExp(regex, "i"); - function headerFilter(flow){ - return ( - (flow.request && RequestUtils.match_header(flow.request, regex)) - || - (flow.response && ResponseUtils.match_header(flow.response, regex)) - ); - } - headerFilter.desc = "header matches " + regex; - return headerFilter; -} -function requestHeader(regex){ - regex = new RegExp(regex, "i"); - function requestHeaderFilter(flow){ - return (flow.request && RequestUtils.match_header(flow.request, regex)); - } - requestHeaderFilter.desc = "req. header matches " + regex; - return requestHeaderFilter; -} -function responseHeader(regex){ - regex = new RegExp(regex, "i"); - function responseHeaderFilter(flow){ - return (flow.response && ResponseUtils.match_header(flow.response, regex)); - } - responseHeaderFilter.desc = "resp. header matches " + regex; - return responseHeaderFilter; -} -function method(regex){ - regex = new RegExp(regex, "i"); - function methodFilter(flow){ - return flow.request && regex.test(flow.request.method); - } - methodFilter.desc = "method matches " + regex; - return methodFilter; -} -function noResponseFilter(flow){ - return flow.request && !flow.response; -} -noResponseFilter.desc = "has no response"; -function responseFilter(flow){ - return !!flow.response; -} -responseFilter.desc = "has response"; - -function contentType(regex){ - regex = new RegExp(regex, "i"); - function contentTypeFilter(flow){ - return ( - (flow.request && regex.test(RequestUtils.getContentType(flow.request))) - || - (flow.response && regex.test(ResponseUtils.getContentType(flow.response))) - ); - } - contentTypeFilter.desc = "content type matches " + regex; - return contentTypeFilter; -} -function requestContentType(regex){ - regex = new RegExp(regex, "i"); - function requestContentTypeFilter(flow){ - return flow.request && regex.test(RequestUtils.getContentType(flow.request)); - } - requestContentTypeFilter.desc = "req. content type matches " + regex; - return requestContentTypeFilter; -} -function responseContentType(regex){ - regex = new RegExp(regex, "i"); - function responseContentTypeFilter(flow){ - return flow.response && regex.test(ResponseUtils.getContentType(flow.response)); - } - responseContentTypeFilter.desc = "resp. content type matches " + regex; - return responseContentTypeFilter; -} -function url(regex){ - regex = new RegExp(regex, "i"); - function urlFilter(flow){ - return flow.request && regex.test(RequestUtils.pretty_url(flow.request)); - } - urlFilter.desc = "url matches " + regex; - return urlFilter; -} -} - -start "filter expression" - = __ orExpr:OrExpr __ { return orExpr; } - / {return trueFilter; } - -ws "whitespace" = [ \t\n\r] -cc "control character" = [|&!()~"] -__ "optional whitespace" = ws* - -OrExpr - = first:AndExpr __ "|" __ second:OrExpr - { return or(first, second); } - / AndExpr - -AndExpr - = first:NotExpr __ "&" __ second:AndExpr - { return and(first, second); } - / first:NotExpr ws+ second:AndExpr - { return and(first, second); } - / NotExpr - -NotExpr - = "!" __ expr:NotExpr - { return not(expr); } - / BindingExpr - -BindingExpr - = "(" __ expr:OrExpr __ ")" - { return binding(expr); } - / Expr - -Expr - = NullaryExpr - / UnaryExpr - -NullaryExpr - = BooleanLiteral - / "~a" { return assetFilter; } - / "~e" { return errorFilter; } - / "~q" { return noResponseFilter; } - / "~s" { return responseFilter; } - - -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); } - / s:StringLiteral { return url(s); } - -IntegerLiteral "integer" - = ['"]? digits:[0-9]+ ['"]? { return parseInt(digits.join(""), 10); } - -StringLiteral "string" - = '"' chars:DoubleStringChar* '"' { return chars.join(""); } - / "'" chars:SingleStringChar* "'" { return chars.join(""); } - / !cc chars:UnquotedStringChar+ { return chars.join(""); } - -DoubleStringChar - = !["\\] char:. { return char; } - / "\\" char:EscapeSequence { return char; } - -SingleStringChar - = !['\\] char:. { return char; } - / "\\" char:EscapeSequence { return char; } - -UnquotedStringChar - = !ws char:. { return char; } - -EscapeSequence - = ['"\\] - / "n" { return "\n"; } - / "r" { return "\r"; } - / "t" { return "\t"; } \ No newline at end of file -- cgit v1.2.3