changeset 476:a49913dd5064

benchmarks for CSRF extraction
author Devel 1
date Tue, 08 Aug 2017 09:30:02 +0200
parents 803b20d6f0cb
children ee228e860ea2
files stress-tester-benchmark/pom.xml stress-tester-benchmark/src/main/java/com/passus/st/client/http/filter/CsrfBenchmark.java stress-tester-benchmark/src/main/java/com/passus/st/client/http/filter/HttpCsrfFormExtractor.java stress-tester-benchmark/src/main/resources/html/form_csrf.html stress-tester-benchmark/src/main/resources/html/form_csrf1.html stress-tester-benchmark/src/main/resources/html/form_csrf_mini.html
diffstat 6 files changed, 758 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/stress-tester-benchmark/pom.xml	Tue Aug 08 09:29:09 2017 +0200
+++ b/stress-tester-benchmark/pom.xml	Tue Aug 08 09:30:02 2017 +0200
@@ -121,7 +121,7 @@
         <dependency>
             <groupId>org.brotli</groupId>
             <artifactId>dec</artifactId>
-            <version>0.1.1</version>
+            <version>0.1.2</version>
         </dependency>
 
         <dependency>
@@ -139,13 +139,19 @@
             <groupId>com.passus</groupId>
             <artifactId>passus-data</artifactId>
             <version>1.0-SNAPSHOT</version>
-            <type>jar</type>
         </dependency>
+
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15</artifactId>
             <version>1.46</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+            <version>1.9.2</version>
+        </dependency>
     </dependencies>
     
     <build>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester-benchmark/src/main/java/com/passus/st/client/http/filter/CsrfBenchmark.java	Tue Aug 08 09:30:02 2017 +0200
@@ -0,0 +1,140 @@
+package com.passus.st.client.http.filter;
+
+import com.passus.commons.utils.ResourceUtils;
+import com.passus.st.client.http.filter.HttpCsrfFormExtractor.FormBoundary;
+import com.passus.st.client.http.filter.HttpCsrfFormExtractor.TokenEntry;
+import com.passus.utils.AllocationUtils;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+@State(Scope.Thread)
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@Fork(value = 1)
+@Measurement(iterations = 6)
+@Warmup(iterations = 6)
+public class CsrfBenchmark {
+
+    String small, medium, large;
+    String form;
+    String smallForm = "<form name=\"f1\" action=\"/svc/save\" method=\"post\"><input type=\"hidden\" id=\"t_id\" name=\"t_n\" value=\"t4val\" /></form>";
+    
+//    @Benchmark
+//    public Object scanLarge() {
+//        return HttpCsrfFormExtractor.scan(large);
+//    }
+//
+//    @Benchmark
+//    public Object scanMedium() {
+//        return HttpCsrfFormExtractor.scan(medium);
+//    }
+//
+//    @Benchmark
+//    public Object scanSmall() {
+//        return HttpCsrfFormExtractor.scan(small);
+//    }
+//    @Benchmark
+//    public Object jsoupParse() {
+//        return Jsoup.parse(form);
+//    }
+//
+//    @Benchmark
+//    public Object jsoupParseBodyFragment() {
+//        return Jsoup.parseBodyFragment(form);
+//    }
+    @Benchmark
+    public TokenEntry extract() {
+        return HttpCsrfFormExtractor.extract(form, "form__token", "form[_token]");
+    }
+
+    @Benchmark
+    public TokenEntry extract1() {
+        return HttpCsrfFormExtractor.extract1(form, "form__token", "form[_token]");
+    }
+
+    @Benchmark
+    public TokenEntry extractSmall() {
+        return HttpCsrfFormExtractor.extract(smallForm, "form__token", "form[_token]");
+    }
+
+//    @Benchmark
+//    public TokenEntry extractSelect() {
+//        return HttpCsrfFormExtractor.extractSelect(form);
+//    }
+//
+//    @Benchmark
+//    public TokenEntry extractSelectById() {
+//        return HttpCsrfFormExtractor.extractSelectById(form, "form__token");
+//    }
+//
+//    @Benchmark
+//    public TokenEntry extractSelectByName() {
+//        return HttpCsrfFormExtractor.extractSelectByName(form, "form[_token]");
+//    }
+    @Benchmark
+    public List<String> regexpOnly() {
+        return HttpCsrfFormExtractor.regexp(form);
+    }
+    @Benchmark
+    public TokenEntry regexpFull() {
+        return HttpCsrfFormExtractor.extractRegex(form, "form__token", "form[_token]");
+    }
+
+    @Setup
+    public void setup() throws IOException {
+        small = load("html/form_csrf1.html");
+        medium = load("html/form_csrf_mini.html");
+        large = load("html/form_csrf.html");
+        FormBoundary bound = HttpCsrfFormExtractor.scan(small).get(0);
+        form = small.substring(bound.start, bound.end);
+    }
+
+    private static String load(String path) throws IOException {
+        File file = ResourceUtils.getFile(path);
+        byte[] bytes = Files.readAllBytes(Paths.get(file.toURI()));
+        return new String(bytes);
+    }
+
+    public static void main(String[] args) throws Throwable {
+        Options opt = new OptionsBuilder().include(CsrfBenchmark.class.getSimpleName() + ".*").build();
+//        new Runner(opt).run();
+        CsrfBenchmark cb = new CsrfBenchmark();
+        cb.setup();
+        AllocationUtils au = new AllocationUtils();
+        au.checkAllocation(cb);
+        au.checkAllocation(cb);
+
+        System.out.println("large=" + cb.large.length());
+        System.out.println("medium=" + cb.medium.length());
+        System.out.println("small=" + cb.small.length());
+        System.out.println("large form=" + cb.form.length());
+        System.out.println("small form=" + cb.smallForm.length());
+
+        cb.regexpOnly();
+//        TokenEntry t1 = cb.extractSelect();
+//        TokenEntry t2 = cb.extractSelectById();
+//        TokenEntry t3 = cb.extractSelectByName();
+        System.out.println("");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester-benchmark/src/main/java/com/passus/st/client/http/filter/HttpCsrfFormExtractor.java	Tue Aug 08 09:30:02 2017 +0200
@@ -0,0 +1,280 @@
+package com.passus.st.client.http.filter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.FormElement;
+import org.jsoup.select.Elements;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+public class HttpCsrfFormExtractor {
+
+    private static final String TAG_FORM = "form";
+    private static final String TAG_INPUT = "input";
+
+    private static final String FORM_START = "<form";
+    private static final String FORM_END = "</form>";
+
+    private static final String ATTR_ACTION = "action";
+    private static final String ATTR_METHOD = "method";
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_VALUE = "value";
+
+    // TODO: obsługiwać '< form' itp
+    static List<FormBoundary> scan(String document) {
+        document = document.toLowerCase();
+        List<FormBoundary> result = new ArrayList<>();
+
+        int startPos = 0;
+        while (true) {
+            startPos = document.indexOf(FORM_START, startPos);
+            if (startPos < 0) {
+                break;
+            }
+
+            int endPos = document.indexOf(FORM_END, startPos);
+            if (endPos < 0) {
+                break;
+            }
+            endPos += FORM_END.length();
+
+            result.add(new FormBoundary(startPos, endPos));
+            startPos = endPos;
+        }
+
+        return result;
+    }
+    private static final String PATTERN_STR = "\\<\\s*input (?>.|\\n)*?(?>\\/\\>|\\<\\/input\\>)";
+    private static final Pattern PATTERN = Pattern.compile(PATTERN_STR, Pattern.MULTILINE);
+
+    static public List<String> regexp(String formString) {
+        Matcher m = PATTERN.matcher(formString);
+        List<String> result = new ArrayList<>();
+        while (m.find()) {
+            result.add(formString.substring(m.start(), m.end()));
+        }
+        return result;
+    }
+
+    static TokenEntry extractRegex(String formString, String tokenId, String tokenName) {
+        List<String> inputStrings = regexp(formString);
+
+        Element tokenInput = null;
+        for (String inputString : inputStrings) {
+            Document doc = Jsoup.parse(inputString);
+            Elements inputs = doc.getElementsByTag(TAG_INPUT);
+            Element input = inputs.get(0);
+
+            if (!input.attr("type").equals("hidden")) {
+                continue;
+            }
+            if (tokenId != null) {
+                if (!tokenId.equals(input.id())) {
+                    continue;
+                }
+            }
+            if (tokenName != null) {
+                if (!tokenName.equals(input.attr("name"))) {
+                    continue;
+                }
+            }
+            tokenInput = input;
+            break;
+        }
+
+        if (tokenInput != null) {
+            String action = "";// form.attr(ATTR_ACTION);
+            String method = "";//form.attr(ATTR_METHOD);
+            String name = "";//form.attr(ATTR_NAME);
+            String value = tokenInput.attr(ATTR_VALUE);
+
+            return new TokenEntry(action, method, name, value);
+        } else {
+            return null;
+        }
+    }
+
+    static TokenEntry extract(String formString, String tokenId, String tokenName) {
+        Document root = Jsoup.parse(formString);
+        Elements forms = root.getElementsByTag(TAG_FORM);
+        if (forms.size() != 1) {
+            throw new IllegalArgumentException("Given fragment is not a form.");
+        }
+        FormElement form = (FormElement) forms.get(0);
+//        Elements inputs = form.getElementsByTag(TAG_INPUT);
+        Elements inputs = form.elements();
+
+        Element tokenInput = null;
+        for (Element input : inputs) {
+            if (!input.tagName().equals("input")) {
+                continue;
+            }
+            if (!input.attr("type").equals("hidden")) {
+                continue;
+            }
+            if (tokenId != null) {
+                if (!tokenId.equals(input.id())) {
+                    continue;
+                }
+            }
+            if (tokenName != null) {
+                if (!tokenName.equals(input.attr("name"))) {
+                    continue;
+                }
+            }
+            tokenInput = input;
+            break;
+        }
+
+        if (tokenInput != null) {
+            String action = form.attr(ATTR_ACTION);
+            String method = form.attr(ATTR_METHOD);
+            String name = form.attr(ATTR_NAME);
+            String value = tokenInput.attr(ATTR_VALUE);
+
+            return new TokenEntry(action, method, name, value);
+        } else {
+            return null;
+        }
+    }
+
+    static TokenEntry extract1(String formString, String tokenId, String tokenName) {
+        Document root = Jsoup.parse(formString);
+        Elements forms = root.getElementsByTag(TAG_FORM);
+        if (forms.size() != 1) {
+            throw new IllegalArgumentException("Given fragment is not a form.");
+        }
+        FormElement form = (FormElement) forms.get(0);
+        Elements inputs = form.getElementsByTag(TAG_INPUT);
+//        Elements inputs = form.elements();
+
+        Element tokenInput = null;
+        for (Element input : inputs) {
+            if (!input.attr("type").equals("hidden")) {
+                continue;
+            }
+            if (tokenId != null) {
+                if (!tokenId.equals(input.id())) {
+                    continue;
+                }
+            }
+            if (tokenName != null) {
+                if (!tokenName.equals(input.attr("name"))) {
+                    continue;
+                }
+            }
+            tokenInput = input;
+            break;
+        }
+
+        if (tokenInput != null) {
+            String action = form.attr(ATTR_ACTION);
+            String method = form.attr(ATTR_METHOD);
+            String name = form.attr(ATTR_NAME);
+            String value = tokenInput.attr(ATTR_VALUE);
+            return new TokenEntry(action, method, name, value);
+        } else {
+            return null;
+        }
+    }
+
+    static TokenEntry extractSelect(String formString) {
+        Document root = Jsoup.parse(formString);
+        Elements forms = root.getElementsByTag(TAG_FORM);
+        if (forms.size() != 1) {
+            throw new IllegalArgumentException("Given fragment is not a form.");
+        }
+        FormElement form = (FormElement) forms.get(0);
+
+        Elements elements = form.select("input[type=hidden]");
+        if (elements.size() > 0) {
+            Element tokenInput = elements.get(0);
+            String action = form.attr(ATTR_ACTION);
+            String method = form.attr(ATTR_METHOD);
+            String name = form.attr(ATTR_NAME);
+            String value = tokenInput.attr(ATTR_VALUE);
+            return new TokenEntry(action, method, name, value);
+        } else {
+            return null;
+        }
+    }
+
+    static TokenEntry extractSelectById(String formString, String tokenId) {
+        Document root = Jsoup.parse(formString);
+        Elements forms = root.getElementsByTag(TAG_FORM);
+        if (forms.size() != 1) {
+            throw new IllegalArgumentException("Given fragment is not a form.");
+        }
+        FormElement form = (FormElement) forms.get(0);
+
+        Elements elements = form.select("#" + tokenId);
+        if (elements.size() > 0) {
+            Element tokenInput = elements.get(0);
+            String action = form.attr(ATTR_ACTION);
+            String method = form.attr(ATTR_METHOD);
+            String name = form.attr(ATTR_NAME);
+            String value = tokenInput.attr(ATTR_VALUE);
+            return new TokenEntry(action, method, name, value);
+
+        } else {
+            return null;
+        }
+    }
+
+    static TokenEntry extractSelectByName(String formString, String tokenName) {
+        Document root = Jsoup.parse(formString);
+        Elements forms = root.getElementsByTag(TAG_FORM);
+        if (forms.size() != 1) {
+            throw new IllegalArgumentException("Given fragment is not a form.");
+        }
+        FormElement form = (FormElement) forms.get(0);
+
+        Elements elements = form.select("input[name=" + tokenName + "]");
+        if (elements.size() > 0) {
+            Element tokenInput = elements.get(0);
+            String action = form.attr(ATTR_ACTION);
+            String method = form.attr(ATTR_METHOD);
+            String name = form.attr(ATTR_NAME);
+            String value = tokenInput.attr(ATTR_VALUE);
+            return new TokenEntry(action, method, name, value);
+        } else {
+            return null;
+
+        }
+    }
+
+    public static class FormBoundary {
+
+        int start;
+        int end;
+
+        public FormBoundary(int start, int end) {
+            this.start = start;
+            this.end = end;
+        }
+    }
+
+    public static class TokenEntry {
+
+        String action;
+        String method;
+        String name;
+        String value;
+
+        public TokenEntry(String action, String method, String name, String value) {
+            this.action = action;
+            this.method = method;
+            this.name = name;
+            this.value = value;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester-benchmark/src/main/resources/html/form_csrf.html	Tue Aug 08 09:30:02 2017 +0200
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head lang="en">
+        <title>Ambience</title>
+        <meta charset="UTF-8" />
+
+        <link rel="icon" href="/bundles/passusambience/images/favicon.png"  />
+        <link rel="shortcut icon" href="/bundles/passusambience/images/favicon.png"  />
+
+                                <script src="/js/400f5eb_jquery.min_1.js"></script>
+                        <script src="/js/400f5eb_kendo.all.min_2.js"></script>
+                        <script src="/js/400f5eb_kendo.culture.custom_3.js"></script>
+                        
+            <script type="text/javascript" src="/bundles/passusambience/js/codemirror.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.core.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.ui-utils.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.mvel-editor.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.mvel-popupeditor.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.event-fields-dropdownlist.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.event-fields-multiselect.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.rule-matcher.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.rule-modifier.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.dialog-window.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.rule-lookup.js" ></script>
+<script type="text/javascript" src="/bundles/passusambience/js/passus.event-filter.js" ></script>
+
+        
+                                <link rel="stylesheet" href="/css/6aebdf5_materialdesignicons.min_1.css" />
+                        <link rel="stylesheet" href="/css/6aebdf5_bootstrap.min_2.css" />
+                        <link rel="stylesheet" href="/css/6aebdf5_kendo.common.min_3.css" />
+                        <link rel="stylesheet" href="/css/6aebdf5_kendo.common-material.min_4.css" />
+                        <link rel="stylesheet" href="/css/6aebdf5_kendo.material.min_5.css" />
+                        <link rel="stylesheet" href="/css/6aebdf5_style_6.css" />
+                        <link rel="stylesheet" href="/css/6aebdf5_style_bart_7.css" />
+                        
+            <link rel="stylesheet" href="/bundles/passusambience/css/rules.css" />
+<link rel="stylesheet" href="/bundles/passusambience/css/codemirror.css" />
+
+        
+        <script>
+            kendo.culture("custom");
+        </script>
+
+    </head>
+    <body class="main">
+            <header id="header" class="black-header smaller-header">
+        <div class="logo-container">
+            <a href="/" title="Psssus">
+                <img src="/bundles/passusambience/images/logo-passus.svg" alt="logo" />
+            </a>
+            <p class="description"><span>Ambience</span></p>
+        </div>
+
+        
+<ul id="menu" style="display: none" ><li><a href="/config/profiles">Profile</a></li><li><a href="">Configuration</a><ul><li><a href="/config/lookups">Lookups</a></li><li><a href="/config/scripts">Global MVEL scripts</a></li><li><a href="/config/sensors">Sensors</a></li><li><a href="/config/ldap">LDAP</a></li><li><a href="/config/ntp">NTP</a></li><li><a href="/config/support">Support</a></li><li><a href="/config/export_import">Export / Import</a></li></ul></li><li><a href="">System</a><ul><li><a href="/system/backup">Backup</a></li><li><a href="/system/supportws">Support WS</a></li><li><a href="/system/logs">Support logs</a></li></ul></li><li><a href="">Security</a><ul><li><a href="/security/users">Users</a></li><li><a href="/security/roles">Roles</a></li><li><a href="/security/perms">Permissions</a></li><li><a href="/security/settings">Settings</a></li><li><a href="/security/audit_log">Audit Log</a></li></ul></li></ul>
+        <div id="profile-settings" class="profile-settings" style="display: none">
+            <ul id="help" class="settings">
+                <li><a href="#" title="help"><i class="mdi mdi-help" style="z-index: 100"></i></a>
+                    <ul>
+                        <li><a href="/about" title="About">About</a></li>
+                    </ul>
+                </li>
+            </ul>
+            <ul id="user-profile" class="user-settings">
+                                <li>
+                    <a href="#" title="admin">
+                        <span class="logo"><span>A</span></span>
+                    </a>
+                    <ul>
+                        <li><a href="/security/password" title="Change password">Change password</a></li>
+                        <li><a href="/logout" title="Logout" onClick="return confirm('Do you want to sign out?');">Log out</a></li>
+                    </ul>
+                </li>
+                            </ul>
+        </div>
+    </header>
+
+    <div id="content" class="content" style="display: none">
+            <div>
+        <section class="container title">
+            <div class="row">
+                <h2>Edit HTTP</h2>
+            </div>
+        </section>
+
+        <section class="container">
+            <div class="row" >
+                    <div>
+        <form name="form" method="post" novalidate="novalidate">
+        <div class="col-md-12 input-container label-left">
+            <div class="row">
+
+                <div class="col-md-12">
+                    <span class="caption">General</span>
+                </div>
+
+                <div class="col-md-12">
+                        <label for="form_name" class="control-label required">Name:</label><input type="text" id="form_name" name="form[name]" required="required" class="mp-textbox k-textbox" value="httpx" />
+                </div>
+
+                <div class="col-md-12">
+                        <label for="form_active" class="control-label required">Active:</label>
+                    <input type="checkbox" id="form_active" name="form[active]" required="required" value="1" checked="checked" />
+                </div>
+
+                <div class="col-md-12">
+                        <label for="form_disabledEvents" class="control-label required">Disabled Events:</label><select id="form_disabledEvents" name="form[disabledEvents][]" required="required" style="width: 600px" multiple="multiple"><option value="session.http" >session.http</option><option value="session.http.request" >session.http.request</option><option value="session.http.response" >session.http.response</option></select><script type="text/javascript">
+            $(function () {
+                $("#form_disabledEvents").kendoMultiSelect({});
+            });
+        </script>
+                </div>
+
+                                    <div class="col-md-12">
+                            <label for="form_ports" class="control-label required">Ports:</label><textarea id="form_ports" name="form[ports]" required="required" cols="40" rows="4" class="mp-textbox k-textbox">80</textarea>
+                    </div>
+                
+                <div class="col-md-12">
+                    <span class="caption">Parameters</span>
+                </div>
+
+                                                            <div class="col-md-12">
+                            <input type="hidden" id="form_type" name="form[type]" value="session.http" />
+                        </div>
+                                                                                                                                                        <div class="col-md-12">
+                            
+                        </div>
+                                                                                                                                                        <div class="col-md-12">
+                                <label for="form_defaultEncoding" class="control-label required">Default Encoding:</label><input type="text" id="form_defaultEncoding" name="form[defaultEncoding]" required="required" class="mp-textbox k-textbox" value="UTF-8" />
+                        </div>
+                                                                                <div class="col-md-12">
+                                <label for="form_threadsNum" class="control-label required">Number of Threads:</label><input id="form_threadsNum" name="form[threadsNum]" type="text" value="1" /><script type="text/javascript">
+            $(function () {
+                $("#form_threadsNum").kendoNumericTextBox({"format":"#","decimals":0,"min":0,"max":256,"step":1});
+            });
+        </script>
+                        </div>
+                                                                                <div class="col-md-12">
+                                <label for="form_encodeMimeTypes" class="control-label required">Encode MIME Types:</label><textarea id="form_encodeMimeTypes" name="form[encodeMimeTypes]" required="required" rows="10 4" style="width: 400px" cols="40" class="mp-textbox k-textbox">text/html
+text/plain
+text/xml
+application/json
+application/x-www-form-urlencoded
+multipart/form-data</textarea>
+                        </div>
+                                                                                                                                                        <div class="col-md-12">
+                            <input type="hidden" id="form__token" name="form[_token]" value="ltZxeOCIr-kgGzU8qvTl2HMwDe1RhU9WmxIcW25whoY" />
+                        </div>
+                                    
+                
+                <div class="col-md-12">
+                    <span class="caption">Post Filters</span>
+                </div>
+
+                <div class="col-md-12">
+                        <input id="form_postFilter" name="form[postFilter]" type="hidden" value="[{&quot;type&quot;:&quot;match&quot;,&quot;match&quot;:{&quot;$and&quot;:[{&quot;session_post_match&quot;:{&quot;$eq&quot;:&quot;value1&quot;}}]},&quot;acceptOnMatch&quot;:true,&quot;desc&quot;:&quot;ACCEPT when $and: session_post_match $eq value1, &quot;},{&quot;type&quot;:&quot;modify&quot;,&quot;modify&quot;:[{&quot;$add&quot;:{&quot;session_post_modify&quot;:&quot;2&quot;}}]}]" /><div id="filter_form_postFilter" ></div><script type="text/javascript">
+            $(function () {
+                var filterList_form_postFilter = $("#filter_form_postFilter").kendoEventFilterList({
+                }).data("kendoEventFilterList");
+                var form = $('form:first');
+
+                var filterInput_form_postFilter = $('#form_postFilter');
+                form.submit(function () {
+                    filterInput_form_postFilter.val(JSON.stringify(filterList_form_postFilter.value(), null, ""));
+                    return true;
+                });
+
+                var filterJson = filterInput_form_postFilter.val();
+                if (filterJson) {
+                    filterList_form_postFilter.value($.parseJSON(filterJson));
+                }
+            });
+        </script>
+                        
+                </div>
+
+                <div class="col-md-12">
+                    <div class="buttons-container" >
+                        <button type="submit" id="form_save" name="form[save]" class="k-button k-primary">Save</button>
+                        <button type="submit" id="form_cancel" name="form[cancel]" class="k-button">Cancel</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        </form>
+    </div>
+
+            </div>
+        </section>
+    </div>
+    </div>
+
+    <script>
+        $().ready(function () {
+                $('#menu').kendoMenu();
+                $('#help').kendoMenu({openOnClick: false});
+                $('#user-profile').kendoMenu();
+
+                $('#menu').show();
+                $('#profile-settings').show();
+                $('#content').show();
+            });    </script>
+    
+    
+<div id="sfwdtc554ef" class="sf-toolbar" style="display: none"></div><script>/*<![CDATA[*/        Sfjs = (function() {        "use strict";        var classListIsSupported = 'classList' in document.documentElement;        if (classListIsSupported) {            var hasClass = function (el, cssClass) { return el.classList.contains(cssClass); };            var removeClass = function(el, cssClass) { el.classList.remove(cssClass); };            var addClass = function(el, cssClass) { el.classList.add(cssClass); };            var toggleClass = function(el, cssClass) { el.classList.toggle(cssClass); };        } else {            var hasClass = function (el, cssClass) { return el.className.match(new RegExp('\\b' + cssClass + '\\b')); };            var removeClass = function(el, cssClass) { el.className = el.className.replace(new RegExp('\\b' + cssClass + '\\b'), ' '); };            var addClass = function(el, cssClass) { if (!hasClass(el, cssClass)) { el.className += " " + cssClass; } };            var toggleClass = function(el, cssClass) { hasClass(el, cssClass) ? removeClass(el, cssClass) : addClass(el, cssClass); };        }        var noop = function() {},            collectionToArray = function (collection) {                var length = collection.length || 0,                    results = new Array(length);                while (length--) {                    results[length] = collection[length];                }                return results;            },            profilerStorageKey = 'sf2/profiler/',            request = function(url, onSuccess, onError, payload, options) {                var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');                options = options || {};                options.maxTries = options.maxTries || 0;                xhr.open(options.method || 'GET', url, true);                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');                xhr.onreadystatechange = function(state) {                    if (4 !== xhr.readyState) {                        return null;                    }                    if (xhr.status == 404 && options.maxTries > 1) {                        setTimeout(function(){                            options.maxTries--;                            request(url, onSuccess, onError, payload, options);                        }, 500);                        return null;                    }                    if (200 === xhr.status) {                        (onSuccess || noop)(xhr);                    } else {                        (onError || noop)(xhr);                    }                };                xhr.send(payload || '');            },            getPreference = function(name) {                if (!window.localStorage) {                    return null;                }                return localStorage.getItem(profilerStorageKey + name);            },            setPreference = function(name, value) {                if (!window.localStorage) {                    return null;                }                localStorage.setItem(profilerStorageKey + name, value);            },            requestStack = [],            extractHeaders = function(xhr, stackElement) {                /* Here we avoid to call xhr.getResponseHeader in order to */                /* prevent polluting the console with CORS security errors */                var allHeaders = xhr.getAllResponseHeaders();                var ret;                if (ret = allHeaders.match(/^x-debug-token:\s+(.*)$/im)) {                    stackElement.profile = ret[1];                }                if (ret = allHeaders.match(/^x-debug-token-link:\s+(.*)$/im)) {                    stackElement.profilerUrl = ret[1];                }            },            renderAjaxRequests = function() {                var requestCounter = document.querySelectorAll('.sf-toolbar-ajax-requests');                if (!requestCounter.length) {                    return;                }                var ajaxToolbarPanel = document.querySelector('.sf-toolbar-block-ajax');                var tbodies = document.querySelectorAll('.sf-toolbar-ajax-request-list');                var state = 'ok';                if (tbodies.length) {                    var tbody = tbodies[0];                    var rows = document.createDocumentFragment();                    if (requestStack.length) {                        for (var i = 0; i < requestStack.length; i++) {                            var request = requestStack[i];                            var row = document.createElement('tr');                            rows.insertBefore(row, rows.firstChild);                            var methodCell = document.createElement('td');                            if (request.error) {                                methodCell.className = 'sf-ajax-request-error';                            }                            methodCell.textContent = request.method;                            row.appendChild(methodCell);                            var pathCell = document.createElement('td');                            pathCell.className = 'sf-ajax-request-url';                            if ('GET' === request.method) {                                var pathLink = document.createElement('a');                                pathLink.setAttribute('href', request.url);                                pathLink.textContent = request.url;                                pathCell.appendChild(pathLink);                            } else {                                pathCell.textContent = request.url;                            }                            pathCell.setAttribute('title', request.url);                            row.appendChild(pathCell);                            var durationCell = document.createElement('td');                            durationCell.className = 'sf-ajax-request-duration';                            if (request.duration) {                                durationCell.textContent = request.duration + "ms";                            } else {                                durationCell.textContent = '-';                            }                            row.appendChild(durationCell);                            row.appendChild(document.createTextNode(' '));                            var profilerCell = document.createElement('td');                            if (request.profilerUrl) {                                var profilerLink = document.createElement('a');                                profilerLink.setAttribute('href', request.profilerUrl);                                profilerLink.textContent = request.profile;                                profilerCell.appendChild(profilerLink);                            } else {                                profilerCell.textContent = 'n/a';                            }                            row.appendChild(profilerCell);                            var requestState = 'ok';                            if (request.error) {                                requestState = 'error';                                if (state != "loading" && i > requestStack.length - 4) {                                    state = 'error';                                }                            } else if (request.loading) {                                requestState = 'loading';                                state = 'loading';                            }                            row.className = 'sf-ajax-request sf-ajax-request-' + requestState;                        }                        var infoSpan = document.querySelectorAll(".sf-toolbar-ajax-info")[0];                        var children = collectionToArray(tbody.children);                        for (var i = 0; i < children.length; i++) {                            tbody.removeChild(children[i]);                        }                        tbody.appendChild(rows);                        if (infoSpan) {                            var text = requestStack.length + ' AJAX request' + (requestStack.length > 1 ? 's' : '');                            infoSpan.textContent = text;                        }                        ajaxToolbarPanel.style.display = 'block';                    } else {                        ajaxToolbarPanel.style.display = 'none';                    }                }                requestCounter[0].textContent = requestStack.length;                var className = 'sf-toolbar-ajax-requests sf-toolbar-value';                requestCounter[0].className = className;                if (state == 'ok') {                    Sfjs.removeClass(ajaxToolbarPanel, 'sf-ajax-request-loading');                    Sfjs.removeClass(ajaxToolbarPanel, 'sf-toolbar-status-red');                } else if (state == 'error') {                    Sfjs.addClass(ajaxToolbarPanel, 'sf-toolbar-status-red');                    Sfjs.removeClass(ajaxToolbarPanel, 'sf-ajax-request-loading');                } else {                    Sfjs.addClass(ajaxToolbarPanel, 'sf-ajax-request-loading');                }            };        var addEventListener;        var el = document.createElement('div');        if (!('addEventListener' in el)) {            addEventListener = function (element, eventName, callback) {                element.attachEvent('on' + eventName, callback);            };        } else {            addEventListener = function (element, eventName, callback) {                element.addEventListener(eventName, callback, false);            };        }                    if (window.XMLHttpRequest && XMLHttpRequest.prototype.addEventListener) {                var proxied = XMLHttpRequest.prototype.open;                XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {                    var self = this;                    /* prevent logging AJAX calls to static and inline files, like templates */                    var path = url;                    if (url.substr(0, 1) === '/') {                        if (0 === url.indexOf('')) {                            path = url.substr(0);                        }                    }                    else if (0 === url.indexOf('http\x3A\x2F\x2F172.16.60.23')) {                        path = url.substr(19);                    }                    if (!path.match(new RegExp("^\/(app(_[\\w]+)?\\.php\/)?_wdt"))) {                        var stackElement = {                            loading: true,                            error: false,                            url: url,                            method: method,                            start: new Date()                        };                        requestStack.push(stackElement);                        this.addEventListener('readystatechange', function() {                            if (self.readyState == 4) {                                stackElement.duration = new Date() - stackElement.start;                                stackElement.loading = false;                                stackElement.error = self.status < 200 || self.status >= 400;                                extractHeaders(self, stackElement);                                Sfjs.renderAjaxRequests();                            }                        }, false);                        Sfjs.renderAjaxRequests();                    }                    proxied.apply(this, Array.prototype.slice.call(arguments));                };            }                return {            hasClass: hasClass,            removeClass: removeClass,            addClass: addClass,            toggleClass: toggleClass,            getPreference: getPreference,            setPreference: setPreference,            addEventListener: addEventListener,            request: request,            renderAjaxRequests: renderAjaxRequests,            load: function(selector, url, onSuccess, onError, options) {                var el = document.getElementById(selector);                if (el && el.getAttribute('data-sfurl') !== url) {                    request(                        url,                        function(xhr) {                            el.innerHTML = xhr.responseText;                            el.setAttribute('data-sfurl', url);                            removeClass(el, 'loading');                            (onSuccess || noop)(xhr, el);                        },                        function(xhr) { (onError || noop)(xhr, el); },                        '',                        options                    );                }                return this;            },            toggle: function(selector, elOn, elOff) {                var tmp = elOn.style.display,                    el = document.getElementById(selector);                elOn.style.display = elOff.style.display;                elOff.style.display = tmp;                if (el) {                    el.style.display = 'none' === tmp ? 'none' : 'block';                }                return this;            },            createTabs: function() {                var tabGroups = document.querySelectorAll('.sf-tabs');                /* create the tab navigation for each group of tabs */                for (var i = 0; i < tabGroups.length; i++) {                    var tabs = tabGroups[i].querySelectorAll('.tab');                    var tabNavigation = document.createElement('ul');                    tabNavigation.className = 'tab-navigation';                    for (var j = 0; j < tabs.length; j++) {                        var tabId = 'tab-' + i + '-' + j;                        var tabTitle = tabs[j].querySelector('.tab-title').innerHTML;                        var tabNavigationItem = document.createElement('li');                        tabNavigationItem.setAttribute('data-tab-id', tabId);                        if (j == 0) { Sfjs.addClass(tabNavigationItem, 'active'); }                        if (Sfjs.hasClass(tabs[j], 'disabled')) { Sfjs.addClass(tabNavigationItem, 'disabled'); }                        tabNavigationItem.innerHTML = tabTitle;                        tabNavigation.appendChild(tabNavigationItem);                        var tabContent = tabs[j].querySelector('.tab-content');                        tabContent.parentElement.setAttribute('id', tabId);                    }                    tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild);                }                /* display the active tab and add the 'click' event listeners */                for (i = 0; i < tabGroups.length; i++) {                    tabNavigation = tabGroups[i].querySelectorAll('.tab-navigation li');                    for (j = 0; j < tabNavigation.length; j++) {                        tabId = tabNavigation[j].getAttribute('data-tab-id');                        document.getElementById(tabId).querySelector('.tab-title').className = 'hidden';                        if (Sfjs.hasClass(tabNavigation[j], 'active')) {                            document.getElementById(tabId).className = 'block';                        } else {                            document.getElementById(tabId).className = 'hidden';                        }                        tabNavigation[j].addEventListener('click', function(e) {                            var activeTab = e.target || e.srcElement;                            /* needed because when the tab contains HTML contents, user can click */                            /* on any of those elements instead of their parent '<li>' element */                            while (activeTab.tagName.toLowerCase() !== 'li') {                                activeTab = activeTab.parentNode;                            }                            /* get the full list of tabs through the parent of the active tab element */                            var tabNavigation = activeTab.parentNode.children;                            for (var k = 0; k < tabNavigation.length; k++) {                                var tabId = tabNavigation[k].getAttribute('data-tab-id');                                document.getElementById(tabId).className = 'hidden';                                Sfjs.removeClass(tabNavigation[k], 'active');                            }                            Sfjs.addClass(activeTab, 'active');                            var activeTabId = activeTab.getAttribute('data-tab-id');                            document.getElementById(activeTabId).className = 'block';                        });                    }                }            },            createToggles: function() {                var toggles = document.querySelectorAll('.sf-toggle');                for (var i = 0; i < toggles.length; i++) {                    var elementSelector = toggles[i].getAttribute('data-toggle-selector');                    var element = document.querySelector(elementSelector);                    Sfjs.addClass(element, 'sf-toggle-content');                    if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') {                        Sfjs.addClass(element, 'sf-toggle-visible');                    } else {                        Sfjs.addClass(element, 'sf-toggle-hidden');                    }                    Sfjs.addEventListener(toggles[i], 'click', function(e) {                        e.preventDefault();                        var toggle = e.target || e.srcElement;                        /* needed because when the toggle contains HTML contents, user can click */                        /* on any of those elements instead of their parent '.sf-toggle' element */                        while (!Sfjs.hasClass(toggle, 'sf-toggle')) {                            toggle = toggle.parentNode;                        }                        var element = document.querySelector(toggle.getAttribute('data-toggle-selector'));                        Sfjs.toggleClass(element, 'sf-toggle-hidden');                        Sfjs.toggleClass(element, 'sf-toggle-visible');                        /* the toggle doesn't change its contents when clicking on it */                        if (!toggle.hasAttribute('data-toggle-alt-content')) {                            return;                        }                        if (!toggle.hasAttribute('data-toggle-original-content')) {                            toggle.setAttribute('data-toggle-original-content', toggle.innerHTML);                        }                        var currentContent = toggle.innerHTML;                        var originalContent = toggle.getAttribute('data-toggle-original-content');                        var altContent = toggle.getAttribute('data-toggle-alt-content');                        toggle.innerHTML = currentContent !== altContent ? altContent : originalContent;                    });                }            }        };    })();    Sfjs.addEventListener(window, 'load', function() {        Sfjs.createTabs();        Sfjs.createToggles();    });/*]]>*/</script><script>/*<![CDATA[*/    (function () {                Sfjs.load(            'sfwdtc554ef',            '/_wdt/c554ef',            function(xhr, el) {                el.style.display = -1 !== xhr.responseText.indexOf('sf-toolbarreset') ? 'block' : 'none';                if (el.style.display == 'none') {                    return;                }                if (Sfjs.getPreference('toolbar/displayState') == 'none') {                    document.getElementById('sfToolbarMainContent-c554ef').style.display = 'none';                    document.getElementById('sfToolbarClearer-c554ef').style.display = 'none';                    document.getElementById('sfMiniToolbar-c554ef').style.display = 'block';                } else {                    document.getElementById('sfToolbarMainContent-c554ef').style.display = 'block';                    document.getElementById('sfToolbarClearer-c554ef').style.display = 'block';                    document.getElementById('sfMiniToolbar-c554ef').style.display = 'none';                }                Sfjs.renderAjaxRequests();                /* Handle toolbar-info position */                var toolbarBlocks = document.querySelectorAll('.sf-toolbar-block');                for (var i = 0; i < toolbarBlocks.length; i += 1) {                    toolbarBlocks[i].onmouseover = function () {                        var toolbarInfo = this.querySelectorAll('.sf-toolbar-info')[0];                        var pageWidth = document.body.clientWidth;                        var elementWidth = toolbarInfo.offsetWidth;                        var leftValue = (elementWidth + this.offsetLeft) - pageWidth;                        var rightValue = (elementWidth + (pageWidth - this.offsetLeft)) - pageWidth;                        /* Reset right and left value, useful on window resize */                        toolbarInfo.style.right = '';                        toolbarInfo.style.left = '';                        if (elementWidth > pageWidth) {                            toolbarInfo.style.left = 0;                        }                        else if (leftValue > 0 && rightValue > 0) {                            toolbarInfo.style.right = (rightValue * -1) + 'px';                        } else if (leftValue < 0) {                            toolbarInfo.style.left = 0;                        } else {                            toolbarInfo.style.right = '0px';                        }                    };                }            },            function(xhr) {                if (xhr.status !== 0) {                    confirm('An error occurred while loading the web debug toolbar (' + xhr.status + ': ' + xhr.statusText + ').\n\nDo you want to open the profiler?') && (window.location = '/_profiler/c554ef');                }            },            {'maxTries': 5}        );    })();/*]]>*/</script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester-benchmark/src/main/resources/html/form_csrf1.html	Tue Aug 08 09:30:02 2017 +0200
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head lang="en">
+	<title>Title</title>
+</head>
+
+<body class="main">
+	<section class="container">
+	<ForM name="form1" method="post" novalidate="novalidate">
+		<div class="row">
+			<input type="text" id="form_name" name="form[name]" required="required" class="mp-textbox k-textbox" value="httpx" />
+			<input type="checkbox" id="form_active" name="form[active]" required="required" value="1" checked="checked" />
+			<input type="hidden" id="form_type" name="form[type]" value="session.http" />
+			<textarea id="form_mimeTypes" name="form[mimeTypes]" required="required" rows="10 4" style="width: 400px" cols="40" class="mp-textbox k-textbox">text/html
+text/plain
+text/xml
+application/json
+application/x-www-form-urlencoded
+multipart/form-data</textarea>
+			<input type="hidden" id="form__token" name="form[_token]" value="token-1qwerty" />
+			<button type="submit" id="form_save" name="form[save]" class="k-button k-primary">Save</button>
+			<button type="submit" id="form_cancel" name="form[cancel]" class="k-button">Cancel</button>
+		</div>
+	</ForM>
+	</section>
+	<section class="container2">
+	<form name="form2" action="" method="post">
+		<input type="hidden" id="form__token" name="form[_token]" value="token-2qwerty" />
+	</form><form name="form3" action="save_form" method="post">
+		<input type="hidden" id="form__token" name="form[_token]" value="token-3qwerty" />
+	</form>
+	<form name="form4" action="/service/save_form" method="post">
+		<input type="hidden" id="form__token" name="form[_token]" value="token-4qwerty" />
+	</form>
+	</section>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester-benchmark/src/main/resources/html/form_csrf_mini.html	Tue Aug 08 09:30:02 2017 +0200
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head lang="en">
+	<title>Ambience</title>
+	<meta charset="UTF-8" />
+	<link rel="icon" href="/bundles/passusambience/images/favicon.png"  />
+	<link rel="shortcut icon" href="/bundles/passusambience/images/favicon.png"  />
+	<script src="/js/400f5eb_jquery.min_1.js"></script>
+	<link rel="stylesheet" href="/css/6aebdf5_bootstrap.min_2.css" />
+	<link rel="stylesheet" href="/css/6aebdf5_style_6.css" />
+</head>
+
+<body class="main">
+	<section class="container">
+	<div class="row" >
+	<form name="form" method="post" novalidate="novalidate">
+	<div class="col-md-12 input-container label-left">
+		<div class="row">
+			<div class="col-md-12">
+				<label for="form_name" class="control-label required">Name:</label>
+				<input type="text" id="form_name" name="form[name]" required="required" class="mp-textbox k-textbox" value="httpx" />
+			</div>
+			<div class="col-md-12">
+				<label for="form_active" class="control-label required">Active:</label>
+				<input type="checkbox" id="form_active" name="form[active]" required="required" value="1" checked="checked" />
+			</div>
+			<div class="col-md-12">
+				<input type="hidden" id="form_type" name="form[type]" value="session.http" />
+			</div>
+			<div class="col-md-12">
+				<label for="form_defaultEncoding" class="control-label required">Default Encoding:</label>
+				<input type="text" id="form_defaultEncoding" name="form[defaultEncoding]" required="required" class="mp-textbox k-textbox" value="UTF-8" />
+			</div>
+			<div class="col-md-12">
+				<label for="form_threadsNum" class="control-label required">Number of Threads:</label>
+				<input id="form_threadsNum" name="form[threadsNum]" type="text" value="1" />
+				<script type="text/javascript">
+		$(function () {
+			$("#form_threadsNum").kendoNumericTextBox({"format":"#","decimals":0,"min":0,"max":256,"step":1});
+		});
+				</script>
+			</div>
+			<div class="col-md-12">
+				<label for="form_encodeMimeTypes" class="control-label required">Encode MIME Types:</label>
+				<textarea id="form_encodeMimeTypes" name="form[encodeMimeTypes]" required="required" rows="10 4" style="width: 400px" cols="40" class="mp-textbox k-textbox">text/html
+text/plain
+text/xml
+application/json
+application/x-www-form-urlencoded
+multipart/form-data</textarea>
+			</div>
+			<div class="col-md-12">
+				<input type="hidden" id="form__token" name="form[_token]" value="ltZxeOCIr-kgGzU8qvTl2HMwDe1RhU9WmxIcW25whoY" />
+			</div>
+			<div class="col-md-12">
+				<input id="form_postFilter" name="form[postFilter]" type="hidden" value="[{&quot;type&quot;:&quot;match&quot;,&quot;match&quot;:{&quot;$and&quot;:[]},&quot;acceptOnMatch&quot;:true,&quot;desc&quot;:&quot;ACCEPT when $and: session_post_match $eq value1, &quot;}]" />
+				<div id="filter_form_postFilter" ></div>
+				<script type="text/javascript">
+		$(function () {
+			var filterList_form_postFilter = $("#filter_form_postFilter").kendoEventFilterList({
+			}).data("kendoEventFilterList");
+			var form = $('form:first');
+
+			var filterInput_form_postFilter = $('#form_postFilter');
+			form.submit(function () {
+				filterInput_form_postFilter.val(JSON.stringify(filterList_form_postFilter.value(), null, ""));
+				return true;
+			});
+		});
+				</script>
+			</div>
+
+			<div class="col-md-12">
+				<div class="buttons-container" >
+					<button type="submit" id="form_save" name="form[save]" class="k-button k-primary">Save</button>
+					<button type="submit" id="form_cancel" name="form[cancel]" class="k-button">Cancel</button>
+				</div>
+			</div>
+		</div>
+	</div>
+	</form>
+	</div>
+	</section>
+</body>
+</html>
\ No newline at end of file