changeset 957:8fc6d1cae116

Refactorization in progress
author Devel 2
date Wed, 29 May 2019 15:03:59 +0200
parents b0867db5ea27
children c15144d4da64
files stress-tester/src/main/java/com/passus/st/ConverterHttpClient.java stress-tester/src/main/java/com/passus/st/client/http/HttpAsynchClientWorker.java stress-tester/src/main/java/com/passus/st/client/http/HttpClientWorkerDispatcher.java stress-tester/src/main/java/com/passus/st/client/http/HttpClientWorkerFactory.java stress-tester/src/main/java/com/passus/st/client/http/HttpFlowContext.java stress-tester/src/main/java/com/passus/st/client/http/HttpStresserWorker.java stress-tester/src/main/java/com/passus/st/client/http/HttpSynchClientWorker.java stress-tester/src/main/java/com/passus/st/client/http/extractor/ContentExtractor.java stress-tester/src/main/java/com/passus/st/client/http/extractor/ContentExtractorUtils.java stress-tester/src/main/java/com/passus/st/client/http/extractor/ContentReplacer.java stress-tester/src/main/java/com/passus/st/client/http/extractor/JsonValueExtractor.java stress-tester/src/main/java/com/passus/st/client/http/extractor/PostValueExtractor.java stress-tester/src/main/java/com/passus/st/client/http/extractor/RegexValueExtractor.java stress-tester/src/main/java/com/passus/st/client/http/extractor/XmlValueExtractor.java stress-tester/src/main/java/com/passus/st/client/http/extractor/YamlExtractor.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationFilterTransformer.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationOperations.java stress-tester/src/main/java/com/passus/st/extractor/ContentExtractor.java stress-tester/src/main/java/com/passus/st/extractor/ContentExtractorUtils.java stress-tester/src/main/java/com/passus/st/extractor/ContentReplacer.java stress-tester/src/main/java/com/passus/st/extractor/JsonValueExtractor.java stress-tester/src/main/java/com/passus/st/extractor/PostValueExtractor.java stress-tester/src/main/java/com/passus/st/extractor/RegexValueExtractor.java stress-tester/src/main/java/com/passus/st/extractor/XmlValueExtractor.java stress-tester/src/main/java/com/passus/st/extractor/YamlExtractor.java stress-tester/src/main/java/com/passus/st/filter/HttpMessageWrapperStaticExtractor.java stress-tester/src/main/java/com/passus/st/reader/nc/HttpSessionPayloadEventDataWriter.java stress-tester/src/main/java/com/passus/st/source/NcEventDestination.java stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java stress-tester/src/test/java/com/passus/st/client/http/HttpAsynchClientWorkerTest.java stress-tester/src/test/java/com/passus/st/client/http/extractor/ContentExtractorUtilsTest.java stress-tester/src/test/java/com/passus/st/client/http/extractor/JsonValueExtractorTest.java stress-tester/src/test/java/com/passus/st/client/http/extractor/PostValueExtractorTest.java stress-tester/src/test/java/com/passus/st/client/http/extractor/RegexValueExtractorTest.java stress-tester/src/test/java/com/passus/st/client/http/extractor/XmlValueExtractorTest.java stress-tester/src/test/java/com/passus/st/client/http/extractor/YamlExtractorTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageModificationFilterTest.java stress-tester/src/test/java/com/passus/st/extractor/ContentExtractorUtilsTest.java stress-tester/src/test/java/com/passus/st/extractor/JsonValueExtractorTest.java stress-tester/src/test/java/com/passus/st/extractor/PostValueExtractorTest.java stress-tester/src/test/java/com/passus/st/extractor/RegexValueExtractorTest.java stress-tester/src/test/java/com/passus/st/extractor/XmlValueExtractorTest.java stress-tester/src/test/java/com/passus/st/extractor/YamlExtractorTest.java stress-tester/src/test/java/com/passus/st/filter/HttpMessageValueExtractorTest.java stress-tester/src/test/java/com/passus/st/source/NcEventDestinationTest.java stress-tester/src/test/java/com/passus/st/source/PcapSessionEventSourceTest.java
diffstat 47 files changed, 1119 insertions(+), 1140 deletions(-) [+]
line wrap: on
line diff
--- a/stress-tester/src/main/java/com/passus/st/ConverterHttpClient.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/ConverterHttpClient.java	Wed May 29 15:03:59 2019 +0200
@@ -17,8 +17,6 @@
 import java.util.List;
 import java.util.Map;
 
-import static com.passus.st.client.http.filter.HttpFlowUtils.createFlowContext;
-
 /**
  * @author mikolaj.podbielski
  */
@@ -85,8 +83,8 @@
 
                     break;
                 }
-                case HttpSessionPayloadEvent.TYPE: {
-                    HttpSessionPayloadEvent e = (HttpSessionPayloadEvent) event;
+                case SessionPayloadEvent.TYPE: {
+                    SessionPayloadEvent e = (SessionPayloadEvent) event;
                     FlowContext flow = getFlow(e.getSessionInfo());
                     int result = filterChain.filterOutbound(e.getRequest(), e.getResponse(), flow);
                     if (result == HttpFilter.ACCEPT) {
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpAsynchClientWorker.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpAsynchClientWorker.java	Wed May 29 15:03:59 2019 +0200
@@ -6,10 +6,7 @@
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.DataEvents.DataEnd;
 import com.passus.st.client.DataEvents.DataLoopEnd;
-import com.passus.st.client.Event;
-import com.passus.st.client.FlowContext;
-import com.passus.st.client.SessionEvent;
-import com.passus.st.client.SessionStatusEvent;
+import com.passus.st.client.*;
 import com.passus.st.emitter.Emitter;
 import com.passus.st.emitter.SessionInfo;
 import com.passus.st.plugin.PluginConstants;
@@ -184,18 +181,18 @@
 
     private void addEvent(Event event, TasksTimeWindow window) {
         switch (event.getType()) {
-            case HttpSessionPayloadEvent.TYPE: {
+            case SessionPayloadEvent.TYPE: {
                 Event newEvent = eventInstanceForWorker(event);
                 long time = newEvent.getTimestamp();
-                HttpSessionPayloadEvent payloadEvent = (HttpSessionPayloadEvent) newEvent;
+                SessionPayloadEvent payloadEvent = (SessionPayloadEvent) newEvent;
                 SessionInfo session = payloadEvent.getSessionInfo();
 
                 SessionEventsTask task = window.getSessionEventsTask(session, true);
                 task.events.add(payloadEvent);
 
                 if (responseSynch) {
-                    HttpResponse resp = payloadEvent.getResponse();
-                    HttpRequest req = payloadEvent.getRequest();
+                    HttpResponse resp = (HttpResponse) payloadEvent.getResponse();
+                    HttpRequest req = (HttpRequest) payloadEvent.getRequest();
                     long respTime = time + (resp.getTimestamp() - req.getTimestamp());
                     HttpResponseEvent respEvent = new HttpResponseEvent(session, event.getSourceName(), resp, respTime);
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpClientWorkerDispatcher.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpClientWorkerDispatcher.java	Wed May 29 15:03:59 2019 +0200
@@ -5,6 +5,7 @@
 /**
  * @author Mirosław Hawrot
  */
+@Deprecated
 public interface HttpClientWorkerDispatcher {
 
     HttpClientWorker find(Event event, HttpClientWorker[] workers);
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpClientWorkerFactory.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpClientWorkerFactory.java	Wed May 29 15:03:59 2019 +0200
@@ -6,6 +6,7 @@
 /**
  * @author Mirosław Hawrot
  */
+@Deprecated
 public class HttpClientWorkerFactory extends PluginFactory<HttpClientWorker> {
 
     private static HttpClientWorkerFactory instance;
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpFlowContext.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpFlowContext.java	Wed May 29 15:03:59 2019 +0200
@@ -3,6 +3,7 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpResponse;
 import com.passus.st.client.FlowContext;
+import com.passus.st.client.SessionPayloadEvent;
 
 /**
  * @author Mirosław Hawrot
@@ -33,18 +34,18 @@
     }
 
     public HttpResponse origResponse() {
-        HttpSessionPayloadEvent sentEvent = (HttpSessionPayloadEvent) flowContext.sentEvent();
+        SessionPayloadEvent sentEvent = flowContext.sentEvent();
         if (sentEvent != null && sentEvent.getResponse() != null) {
-            return sentEvent.getResponse();
+            return (HttpResponse) sentEvent.getResponse();
         }
 
         return null;
     }
 
     HttpRequest sentRequest() {
-        HttpSessionPayloadEvent sentEvent = (HttpSessionPayloadEvent) flowContext.sentEvent();
+        SessionPayloadEvent sentEvent = flowContext.sentEvent();
         if (sentEvent != null && sentEvent.getRequest() != null) {
-            return sentEvent.getRequest();
+            return (HttpRequest) sentEvent.getRequest();
         }
 
         return null;
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpStresserWorker.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpStresserWorker.java	Wed May 29 15:03:59 2019 +0200
@@ -4,11 +4,11 @@
 import com.passus.net.http.HttpRequest;
 import com.passus.st.client.DataEvents;
 import com.passus.st.client.Event;
+import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.emitter.Emitter;
 import com.passus.st.emitter.SessionInfo;
 
 /**
- *
  * @author Mirosław Hawrot
  */
 @Deprecated
@@ -57,18 +57,18 @@
     public void handle(Event event) {
         if (event.getType() == DataEvents.DataLoopEnd.TYPE) {
             waitAndClose();
-        } else if (event.getType() != HttpSessionPayloadEvent.TYPE) {
+        } else if (event.getType() != SessionPayloadEvent.TYPE) {
             return;
         }
 
-        HttpSessionPayloadEvent payloadEvent = (HttpSessionPayloadEvent) event;
-        HttpRequest req = payloadEvent.getRequest();
+        SessionPayloadEvent payloadEvent = (SessionPayloadEvent) event;
+        HttpRequest req = (HttpRequest) payloadEvent.getRequest();
         send(req);
     }
 
     @Override
     public void run() {
-        
+
     }
 
 }
--- a/stress-tester/src/main/java/com/passus/st/client/http/HttpSynchClientWorker.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/HttpSynchClientWorker.java	Wed May 29 15:03:59 2019 +0200
@@ -267,6 +267,7 @@
         synchronized (lock) {
             eventsQueue.clear();
             super.close();
+            working = false;
             lock.notifyAll();
         }
     }
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/ContentExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.passus.net.http.HttpMessage;
-import com.passus.net.http.HttpMessageHelper;
-import java.io.IOException;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public interface ContentExtractor {
-
-    public default CharSequence extract(HttpMessage message) throws IOException {
-        String content = HttpMessageHelper.get().contentToString(message, true);
-        return extract(content);
-    }
-
-    public CharSequence extract(CharSequence content) throws IOException;
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/ContentExtractorUtils.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.passus.commons.Assert;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public class ContentExtractorUtils {
-
-    private ContentExtractorUtils() {
-    }
-
-    public static ContentReplacer createReplacer(String rule) {
-        Assert.notNull(rule, "rule");
-        if (rule.length() < 4) {
-            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'.");
-        }
-
-        int pos = rule.indexOf(':');
-        if (pos == -1) {
-            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'.");
-        }
-
-        ContentReplacer contentReplacer = null;
-        try {
-            String extractorType = rule.substring(0, pos);
-            String expr = rule.substring(pos + 1);
-
-            switch (extractorType.toLowerCase()) {
-                case "yaml":
-                    contentReplacer = new YamlExtractor(expr);
-                    break;
-                case "json":
-                    contentReplacer = new JsonValueExtractor(expr);
-                    break;
-                case "xml":
-                    contentReplacer = new XmlValueExtractor(expr);
-                    break;
-                case "post":
-                    contentReplacer = new PostValueExtractor(expr);
-                    break;
-                case "regexp":
-                    contentReplacer = new RegexValueExtractor(expr);
-                    break;
-                default:
-                    throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'. Invalid replacer type '" + extractorType + "'.");
-            }
-        } catch (Exception e) {
-            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'." + e.getMessage(), e);
-        }
-
-        if (contentReplacer == null) {
-            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'.");
-        }
-
-        return contentReplacer;
-    }
-
-    public static ContentExtractor createExtractor(String rule) {
-        Assert.notNull(rule, "rule");
-        if (rule.length() < 4) {
-            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'.");
-        }
-
-        int pos = rule.indexOf(':');
-        if (pos == -1) {
-            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'.");
-        }
-
-        ContentExtractor contentExtractor = null;
-        try {
-            String extractorType = rule.substring(0, pos);
-            String expr = rule.substring(pos + 1);
-
-            switch (extractorType.toLowerCase()) {
-                case "yaml":
-                    contentExtractor = new YamlExtractor(expr);
-                    break;
-                case "json":
-                    contentExtractor = new JsonValueExtractor(expr);
-                    break;
-                case "xml":
-                    contentExtractor = new XmlValueExtractor(expr);
-                    break;
-                case "post":
-                    contentExtractor = new PostValueExtractor(expr);
-                    break;
-                case "regexp":
-                    contentExtractor = new RegexValueExtractor(expr);
-                    break;
-                default:
-                    throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'. Invalid extractor type '" + extractorType + "'.");
-            }
-        } catch (Exception e) {
-            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'." + e.getMessage(), e);
-        }
-
-        if (contentExtractor == null) {
-            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'.");
-        }
-
-        return contentExtractor;
-    }
-
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/ContentReplacer.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.passus.net.http.HttpMessage;
-import com.passus.net.http.HttpMessageHelper;
-import java.io.IOException;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public interface ContentReplacer {
-
-    public default void replace(HttpMessage message, CharSequence value) throws IOException {
-        HttpMessageHelper helper = HttpMessageHelper.get();
-        CharSequence content = helper.contentToString(message, true);
-        if (content != null) {
-            CharSequence newContent = replace(content, value);
-            helper.setContent(message, newContent);
-        }
-    }
-
-    public CharSequence replace(CharSequence content, CharSequence value) throws IOException;
-
-    public default void setOption(String name, Object value) {
-    }
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/JsonValueExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.jayway.jsonpath.Configuration;
-import com.jayway.jsonpath.DocumentContext;
-import com.jayway.jsonpath.JsonPath;
-import static com.jayway.jsonpath.Option.DEFAULT_PATH_LEAF_TO_NULL;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public class JsonValueExtractor implements ContentExtractor, ContentReplacer {
-
-    private static final Logger LOGGER = LogManager.getLogger(JsonValueExtractor.class);
-
-    private final Configuration configuration = Configuration.builder()
-            .options(DEFAULT_PATH_LEAF_TO_NULL)
-            .build();
-
-    private final JsonPath path;
-
-    public JsonValueExtractor(String path) {
-        this.path = JsonPath.compile(path);
-    }
-
-    private DocumentContext parse(String json) {
-        try {
-            return JsonPath
-                    .using(configuration)
-                    .parse(json);
-        } catch (Exception ex) {
-            return null;
-        }
-    }
-
-    @Override
-    public CharSequence replace(CharSequence content, CharSequence value) {
-        try {
-            DocumentContext context = parse(content.toString());
-            if (context == null) {
-                return null;
-            }
-
-            context.set(path, value);
-            return context.jsonString();
-        } catch (Exception e) {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug(e.getMessage(), e);
-            }
-
-            return null;
-        }
-    }
-
-    @Override
-    public CharSequence extract(CharSequence content) {
-        try {
-            DocumentContext context = parse(content.toString());
-            if (context == null) {
-                return null;
-            }
-
-            Object result = context.read(path);
-            return result == null ? null : result.toString();
-        } catch (Exception e) {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug(e.getMessage(), e);
-            }
-
-            return null;
-        }
-    }
-
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/PostValueExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.passus.commons.Assert;
-import com.passus.data.ByteString;
-import com.passus.net.http.HttpMessage;
-import com.passus.net.http.HttpMessageHelper;
-import com.passus.net.http.HttpParameters;
-import java.io.IOException;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public class PostValueExtractor implements ContentExtractor, ContentReplacer {
-
-    protected final HttpMessageHelper helper = HttpMessageHelper.get();
-
-    private final ByteString fieldName;
-
-    private boolean escape = true;
-
-    public PostValueExtractor(CharSequence fieldName) {
-        Assert.notNull(fieldName, "fieldName");
-        this.fieldName = ByteString.create(fieldName);
-    }
-
-    @Override
-    public void setOption(String name, Object value) {
-        switch (name) {
-            case "escape":
-                if (Boolean.FALSE.equals(value)) {
-                    escape = false;
-                } else if (Boolean.TRUE.equals(value)) {
-                    escape = true;
-                }
-                break;
-        }
-    }
-
-    @Override
-    public void replace(HttpMessage message, CharSequence value) throws IOException {
-        HttpParameters params = helper.decodeFormUrlencoded(message, escape);
-        if (params != null) {
-            params.set(fieldName, value);
-            helper.setFormUrlencoded(message, params, escape);
-        }
-    }
-
-    @Override
-    public CharSequence replace(CharSequence content, CharSequence value) throws IOException {
-        HttpParameters params = helper.decodeFormUrlencoded(content, escape);
-        if (params != null) {
-            params.set(fieldName, value);
-            return params.toString(escape);
-        }
-
-        return null;
-    }
-
-    @Override
-    public CharSequence extract(HttpMessage message) throws IOException {
-        HttpParameters params = helper.decodeFormUrlencoded(message);
-        if (params != null) {
-            ByteString value = params.get(fieldName);
-            if (value != null) {
-                return value;
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public CharSequence extract(CharSequence content) throws IOException {
-        HttpParameters params = helper.decodeFormUrlencoded(content);
-        if (params != null) {
-            ByteString value = params.get(fieldName);
-            if (value != null) {
-                return value;
-            }
-        }
-
-        return null;
-    }
-
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/RegexValueExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public class RegexValueExtractor implements ContentExtractor, ContentReplacer {
-
-    private final Pattern pattern;
-
-    private final StringBuilder sb = new StringBuilder();
-
-    public RegexValueExtractor(CharSequence expression) {
-        pattern = Pattern.compile(expression.toString());
-    }
-
-    @Override
-    public CharSequence replace(CharSequence object, CharSequence value) {
-        if (object == null || object.length() == 0) {
-            return object;
-        }
-
-        Matcher matcher = pattern.matcher(object);
-        if (matcher.find()) {
-            if (matcher.groupCount() >= 1) {
-                int start = matcher.start(1);
-                int end = matcher.end(1);
-                if (start != -1 && end != -1) {
-                    sb.setLength(0);
-                    sb.append(object);
-                    sb.replace(start, end, value.toString());
-                    return sb.toString();
-                }
-
-            }
-        }
-        return object;
-    }
-
-    @Override
-    public CharSequence extract(CharSequence object) {
-        Matcher matcher = pattern.matcher(object);
-        if (matcher.find()) {
-            if (matcher.groupCount() >= 1) {
-                int start = matcher.start(1);
-                int end = matcher.end(1);
-                if (start != -1 && end != -1) {
-                    return object.subSequence(start, end);
-                }
-            }
-        }
-        return null;
-    }
-
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/XmlValueExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.passus.commons.Assert;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.xml.sax.InputSource;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.xpath.*;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Objects;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public class XmlValueExtractor implements ContentExtractor, ContentReplacer {
-
-    public static final Logger LOGGER = LogManager.getLogger(XmlValueExtractor.class);
-
-    private final XPathExpression xPathExpr;
-
-    private DocumentBuilder docBuilder;
-
-    private Transformer xmlTransformer;
-
-    private boolean returnNullIfPathNotFound;
-
-    public XmlValueExtractor(String expression) throws XPathExpressionException {
-        Assert.notNull(expression, "expression");
-        XPath xPath = XPathFactory.newInstance().newXPath();
-        xPathExpr = xPath.compile(expression);
-    }
-
-    public XmlValueExtractor(XPathExpression xPathExpr) {
-        Assert.notNull(xPathExpr, "xPathExpr");
-        this.xPathExpr = xPathExpr;
-    }
-
-    public void setReturnNullIfPathNotFound(boolean returnNullIfPathNotFound) {
-        this.returnNullIfPathNotFound = returnNullIfPathNotFound;
-    }
-
-    private DocumentBuilder getDocBuilder() {
-        try {
-            if (docBuilder == null) {
-                DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
-                docBuilder = builderFactory.newDocumentBuilder();
-            }
-
-            return docBuilder;
-        } catch (Exception e) {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug(e.getMessage(), e);
-            }
-
-            return null;
-        }
-    }
-
-    private Transformer getXmlTransformer() {
-        try {
-            if (xmlTransformer == null) {
-                TransformerFactory transformerFactory = TransformerFactory.newInstance();
-                xmlTransformer = transformerFactory.newTransformer();
-            }
-
-            return xmlTransformer;
-        } catch (Exception e) {
-            if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug(e.getMessage(), e);
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public CharSequence replace(CharSequence content, CharSequence value) {
-        DocumentBuilder builder = getDocBuilder();
-        if (builder != null) {
-            try (StringReader sr = new StringReader(content.toString())) {
-                Document doc = builder.parse(new InputSource(sr));
-                Node node = (Node) xPathExpr.evaluate(doc, XPathConstants.NODE);
-                Transformer transformer = getXmlTransformer();
-                if (node != null && transformer != null) {
-                    node.setTextContent(Objects.toString(value));
-                    try (StringWriter writer = new StringWriter()) {
-                        transformer.transform(new DOMSource(doc), new StreamResult(writer));
-                        return writer.getBuffer().toString();
-                    }
-                }
-            } catch (Exception e) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug(e.getMessage(), e);
-                }
-            }
-        }
-
-        return content;
-    }
-
-    @Override
-    public CharSequence extract(CharSequence content) {
-        if( content == null ) {
-            return null;
-        }
-        
-        DocumentBuilder builder = getDocBuilder();
-        if (builder != null) {
-            try (StringReader sr = new StringReader(content.toString())) {
-                Document doc = builder.parse(new InputSource(sr));
-                if (returnNullIfPathNotFound) {
-                    Node node = (Node) xPathExpr.evaluate(doc, XPathConstants.NODE);
-                    node.getTextContent();
-                }
-                return xPathExpr.evaluate(doc);
-            } catch (Exception e) {
-                if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug(e.getMessage(), e);
-                }
-            }
-        }
-
-        return null;
-    }
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/extractor/YamlExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import org.yaml.snakeyaml.Yaml;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author norbert.rostkowski
- */
-public class YamlExtractor implements ContentExtractor, ContentReplacer {
-
-    private static final Pattern PATH_PATTERN = Pattern.compile("\\.([a-zA-Z0-9_]+)|\\[([0-9]+)\\]");
-
-    private final List<Step> steps = new ArrayList<>();
-    private final String path;
-
-    public YamlExtractor(String path) {
-        this.path = path;
-        convertPath(path);
-    }
-
-    private void convertPath(String path) {
-        Matcher m = PATH_PATTERN.matcher(path);
-        while (m.find()) {
-            String g1 = m.group(1);
-            String g2 = m.group(2);
-            if (g1 != null) {
-                steps.add(new YamlExtractor.MapStep(g1));
-            }
-            if (g2 != null) {
-                int index = Integer.parseInt(g2);
-                steps.add(new YamlExtractor.ArrayStep(index));
-            }
-        }
-    }
-
-    @Override
-    public CharSequence extract(CharSequence content) throws IOException {
-        Yaml yaml = new Yaml();
-        Object o = yaml.load(content.toString());
-
-        for (Step step : steps) {
-            o = step.step(o);
-            if (o == null) {
-                return null;
-            }
-        }
-        return o.toString();
-    }
-
-    @Override
-    public CharSequence replace(CharSequence content, CharSequence value) throws IOException {
-        Yaml yaml = new Yaml();
-        Object o = yaml.load(content.toString());
-        Object root = o;
-        if (value != null) {
-            int stepSize = steps.size();
-            for (int i = 0; i < stepSize - 1; i++) {
-                o = steps.get(i).step(o);
-            }
-            steps.get(stepSize - 1).replace(o, (String) value);
-        }
-        return yaml.dump(root);
-    }
-
-
-    private static class ArrayStep implements Step {
-
-        private final int index;
-
-        public ArrayStep(int index) {
-            this.index = index;
-        }
-
-        @Override
-        public Object step(Object in) {
-            if (in instanceof List) {
-                List l = (List) in;
-                if (index < l.size() && index >= 0) {
-                    return l.get(index);
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public void replace(Object in, String newValue) {
-            if (in instanceof List) {
-                List l = (List) in;
-                if (index < l.size() && index >= 0) {
-                    l.set(index, newValue);
-                }
-
-            }
-
-        }
-    }
-
-    private static class MapStep implements Step {
-
-        private final String key;
-
-        public MapStep(String key) {
-            this.key = key;
-        }
-
-        @Override
-        public Object step(Object in) {
-            if (in instanceof Map) {
-                Map m = (Map) in;
-                return m.get(key);
-            } else {
-                return null;
-            }
-        }
-
-        @Override
-        public void replace(Object in, String newValue) {
-            if (in instanceof Map) {
-                Map m = (Map) in;
-                if (m.containsKey(key)) {
-                    m.put(key, newValue);
-                }
-            }
-
-        }
-
-    }
-
-
-    private static interface Step {
-
-        Object step(Object in);
-
-        void replace(Object in, String newValue);
-    }
-}
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilter.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilter.java	Wed May 29 15:03:59 2019 +0200
@@ -13,7 +13,7 @@
     @Override
     public int filterInbound(Object req, Object resp, FlowContext context) {
         if (req instanceof HttpRequest
-                && resp instanceof HttpResponse) {
+                || resp instanceof HttpResponse) {
             return filterInbound((HttpRequest) req, (HttpResponse) resp, context);
         }
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationFilterTransformer.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationFilterTransformer.java	Wed May 29 15:03:59 2019 +0200
@@ -4,8 +4,8 @@
 import com.passus.config.schema.NodeTransformer;
 import com.passus.config.validation.Errors;
 import com.passus.filter.ValueExtractor;
-import com.passus.st.client.http.extractor.ContentExtractorUtils;
-import com.passus.st.client.http.extractor.ContentReplacer;
+import com.passus.st.extractor.ContentExtractorUtils;
+import com.passus.st.extractor.ContentReplacer;
 import com.passus.st.client.http.filter.HttpMessageModificationOperations.*;
 import com.passus.st.config.FieldValueExtractorTransformer;
 
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationOperations.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMessageModificationOperations.java	Wed May 29 15:03:59 2019 +0200
@@ -6,8 +6,8 @@
 import com.passus.filter.ValueExtractor;
 import com.passus.net.http.*;
 import com.passus.st.client.FlowContext;
-import com.passus.st.client.http.extractor.ContentReplacer;
-import com.passus.st.client.http.extractor.RegexValueExtractor;
+import com.passus.st.extractor.ContentReplacer;
+import com.passus.st.extractor.RegexValueExtractor;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -16,7 +16,6 @@
 import java.util.List;
 
 /**
- *
  * @author mikolaj.podbielski
  */
 public class HttpMessageModificationOperations {
@@ -532,7 +531,12 @@
             }
 
             try {
-                replacer.replace(req, newValue);
+                HttpMessageHelper helper = HttpMessageHelper.get();
+                CharSequence content = helper.contentToString(req, true);
+                if (content != null) {
+                    CharSequence newContent = replacer.replace(content, newValue);
+                    helper.setContent(req, newContent);
+                }
             } catch (Exception e) {
                 if (LOGGER.isDebugEnabled()) {
                     LOGGER.debug(e.getMessage(), e);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/ContentExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,11 @@
+package com.passus.st.extractor;
+
+import java.io.IOException;
+
+/**
+ * @author mikolaj.podbielski
+ */
+public interface ContentExtractor {
+
+    CharSequence extract(CharSequence content) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/ContentExtractorUtils.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,106 @@
+package com.passus.st.extractor;
+
+import com.passus.commons.Assert;
+
+/**
+ *
+ * @author Mirosław Hawrot
+ */
+public class ContentExtractorUtils {
+
+    private ContentExtractorUtils() {
+    }
+
+    public static ContentReplacer createReplacer(String rule) {
+        Assert.notNull(rule, "rule");
+        if (rule.length() < 4) {
+            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'.");
+        }
+
+        int pos = rule.indexOf(':');
+        if (pos == -1) {
+            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'.");
+        }
+
+        ContentReplacer contentReplacer = null;
+        try {
+            String extractorType = rule.substring(0, pos);
+            String expr = rule.substring(pos + 1);
+
+            switch (extractorType.toLowerCase()) {
+                case "yaml":
+                    contentReplacer = new YamlExtractor(expr);
+                    break;
+                case "json":
+                    contentReplacer = new JsonValueExtractor(expr);
+                    break;
+                case "xml":
+                    contentReplacer = new XmlValueExtractor(expr);
+                    break;
+                case "post":
+                    contentReplacer = new PostValueExtractor(expr);
+                    break;
+                case "regexp":
+                    contentReplacer = new RegexValueExtractor(expr);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'. Invalid replacer type '" + extractorType + "'.");
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'." + e.getMessage(), e);
+        }
+
+        if (contentReplacer == null) {
+            throw new IllegalArgumentException("Invalid replacer rule '" + rule + "'.");
+        }
+
+        return contentReplacer;
+    }
+
+    public static ContentExtractor createExtractor(String rule) {
+        Assert.notNull(rule, "rule");
+        if (rule.length() < 4) {
+            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'.");
+        }
+
+        int pos = rule.indexOf(':');
+        if (pos == -1) {
+            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'.");
+        }
+
+        ContentExtractor contentExtractor = null;
+        try {
+            String extractorType = rule.substring(0, pos);
+            String expr = rule.substring(pos + 1);
+
+            switch (extractorType.toLowerCase()) {
+                case "yaml":
+                    contentExtractor = new YamlExtractor(expr);
+                    break;
+                case "json":
+                    contentExtractor = new JsonValueExtractor(expr);
+                    break;
+                case "xml":
+                    contentExtractor = new XmlValueExtractor(expr);
+                    break;
+                case "post":
+                    contentExtractor = new PostValueExtractor(expr);
+                    break;
+                case "regexp":
+                    contentExtractor = new RegexValueExtractor(expr);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'. Invalid extractor type '" + extractorType + "'.");
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'." + e.getMessage(), e);
+        }
+
+        if (contentExtractor == null) {
+            throw new IllegalArgumentException("Invalid extractor rule '" + rule + "'.");
+        }
+
+        return contentExtractor;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/ContentReplacer.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,14 @@
+package com.passus.st.extractor;
+
+import java.io.IOException;
+
+/**
+ * @author Mirosław Hawrot
+ */
+public interface ContentReplacer {
+
+    CharSequence replace(CharSequence content, CharSequence value) throws IOException;
+
+    default void setOption(String name, Object value) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/JsonValueExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,76 @@
+package com.passus.st.extractor;
+
+import com.jayway.jsonpath.Configuration;
+import com.jayway.jsonpath.DocumentContext;
+import com.jayway.jsonpath.JsonPath;
+import static com.jayway.jsonpath.Option.DEFAULT_PATH_LEAF_TO_NULL;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+public class JsonValueExtractor implements ContentExtractor, ContentReplacer {
+
+    private static final Logger LOGGER = LogManager.getLogger(JsonValueExtractor.class);
+
+    private final Configuration configuration = Configuration.builder()
+            .options(DEFAULT_PATH_LEAF_TO_NULL)
+            .build();
+
+    private final JsonPath path;
+
+    public JsonValueExtractor(String path) {
+        this.path = JsonPath.compile(path);
+    }
+
+    private DocumentContext parse(String json) {
+        try {
+            return JsonPath
+                    .using(configuration)
+                    .parse(json);
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    @Override
+    public CharSequence replace(CharSequence content, CharSequence value) {
+        try {
+            DocumentContext context = parse(content.toString());
+            if (context == null) {
+                return null;
+            }
+
+            context.set(path, value);
+            return context.jsonString();
+        } catch (Exception e) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug(e.getMessage(), e);
+            }
+
+            return null;
+        }
+    }
+
+    @Override
+    public CharSequence extract(CharSequence content) {
+        try {
+            DocumentContext context = parse(content.toString());
+            if (context == null) {
+                return null;
+            }
+
+            Object result = context.read(path);
+            return result == null ? null : result.toString();
+        } catch (Exception e) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug(e.getMessage(), e);
+            }
+
+            return null;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/PostValueExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,84 @@
+package com.passus.st.extractor;
+
+import com.passus.commons.Assert;
+import com.passus.data.ByteString;
+import com.passus.net.http.HttpMessage;
+import com.passus.net.http.HttpMessageHelper;
+import com.passus.net.http.HttpParameters;
+
+import java.io.IOException;
+
+/**
+ * @author Mirosław Hawrot
+ */
+public class PostValueExtractor implements ContentExtractor, ContentReplacer {
+
+    protected final HttpMessageHelper helper = HttpMessageHelper.get();
+
+    private final ByteString fieldName;
+
+    private boolean escape = true;
+
+    public PostValueExtractor(CharSequence fieldName) {
+        Assert.notNull(fieldName, "fieldName");
+        this.fieldName = ByteString.create(fieldName);
+    }
+
+    @Override
+    public void setOption(String name, Object value) {
+        switch (name) {
+            case "escape":
+                if (Boolean.FALSE.equals(value)) {
+                    escape = false;
+                } else if (Boolean.TRUE.equals(value)) {
+                    escape = true;
+                }
+                break;
+        }
+    }
+
+    public void replace(HttpMessage message, CharSequence value) throws IOException {
+        HttpParameters params = helper.decodeFormUrlencoded(message, escape);
+        if (params != null) {
+            params.set(fieldName, value);
+            helper.setFormUrlencoded(message, params, escape);
+        }
+    }
+
+    @Override
+    public CharSequence replace(CharSequence content, CharSequence value) throws IOException {
+        HttpParameters params = helper.decodeFormUrlencoded(content, escape);
+        if (params != null) {
+            params.set(fieldName, value);
+            return params.toString(escape);
+        }
+
+        return null;
+    }
+
+    public CharSequence extract(HttpMessage message) throws IOException {
+        HttpParameters params = helper.decodeFormUrlencoded(message);
+        if (params != null) {
+            ByteString value = params.get(fieldName);
+            if (value != null) {
+                return value;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public CharSequence extract(CharSequence content) throws IOException {
+        HttpParameters params = helper.decodeFormUrlencoded(content);
+        if (params != null) {
+            ByteString value = params.get(fieldName);
+            if (value != null) {
+                return value;
+            }
+        }
+
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/RegexValueExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,58 @@
+package com.passus.st.extractor;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+public class RegexValueExtractor implements ContentExtractor, ContentReplacer {
+
+    private final Pattern pattern;
+
+    private final StringBuilder sb = new StringBuilder();
+
+    public RegexValueExtractor(CharSequence expression) {
+        pattern = Pattern.compile(expression.toString());
+    }
+
+    @Override
+    public CharSequence replace(CharSequence object, CharSequence value) {
+        if (object == null || object.length() == 0) {
+            return object;
+        }
+
+        Matcher matcher = pattern.matcher(object);
+        if (matcher.find()) {
+            if (matcher.groupCount() >= 1) {
+                int start = matcher.start(1);
+                int end = matcher.end(1);
+                if (start != -1 && end != -1) {
+                    sb.setLength(0);
+                    sb.append(object);
+                    sb.replace(start, end, value.toString());
+                    return sb.toString();
+                }
+
+            }
+        }
+        return object;
+    }
+
+    @Override
+    public CharSequence extract(CharSequence object) {
+        Matcher matcher = pattern.matcher(object);
+        if (matcher.find()) {
+            if (matcher.groupCount() >= 1) {
+                int start = matcher.start(1);
+                int end = matcher.end(1);
+                if (start != -1 && end != -1) {
+                    return object.subSequence(start, end);
+                }
+            }
+        }
+        return null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/XmlValueExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,135 @@
+package com.passus.st.extractor;
+
+import com.passus.commons.Assert;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.xpath.*;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Objects;
+
+/**
+ *
+ * @author Mirosław Hawrot
+ */
+public class XmlValueExtractor implements ContentExtractor, ContentReplacer {
+
+    public static final Logger LOGGER = LogManager.getLogger(XmlValueExtractor.class);
+
+    private final XPathExpression xPathExpr;
+
+    private DocumentBuilder docBuilder;
+
+    private Transformer xmlTransformer;
+
+    private boolean returnNullIfPathNotFound;
+
+    public XmlValueExtractor(String expression) throws XPathExpressionException {
+        Assert.notNull(expression, "expression");
+        XPath xPath = XPathFactory.newInstance().newXPath();
+        xPathExpr = xPath.compile(expression);
+    }
+
+    public XmlValueExtractor(XPathExpression xPathExpr) {
+        Assert.notNull(xPathExpr, "xPathExpr");
+        this.xPathExpr = xPathExpr;
+    }
+
+    public void setReturnNullIfPathNotFound(boolean returnNullIfPathNotFound) {
+        this.returnNullIfPathNotFound = returnNullIfPathNotFound;
+    }
+
+    private DocumentBuilder getDocBuilder() {
+        try {
+            if (docBuilder == null) {
+                DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+                docBuilder = builderFactory.newDocumentBuilder();
+            }
+
+            return docBuilder;
+        } catch (Exception e) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug(e.getMessage(), e);
+            }
+
+            return null;
+        }
+    }
+
+    private Transformer getXmlTransformer() {
+        try {
+            if (xmlTransformer == null) {
+                TransformerFactory transformerFactory = TransformerFactory.newInstance();
+                xmlTransformer = transformerFactory.newTransformer();
+            }
+
+            return xmlTransformer;
+        } catch (Exception e) {
+            if (LOGGER.isDebugEnabled()) {
+                LOGGER.debug(e.getMessage(), e);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public CharSequence replace(CharSequence content, CharSequence value) {
+        DocumentBuilder builder = getDocBuilder();
+        if (builder != null) {
+            try (StringReader sr = new StringReader(content.toString())) {
+                Document doc = builder.parse(new InputSource(sr));
+                Node node = (Node) xPathExpr.evaluate(doc, XPathConstants.NODE);
+                Transformer transformer = getXmlTransformer();
+                if (node != null && transformer != null) {
+                    node.setTextContent(Objects.toString(value));
+                    try (StringWriter writer = new StringWriter()) {
+                        transformer.transform(new DOMSource(doc), new StreamResult(writer));
+                        return writer.getBuffer().toString();
+                    }
+                }
+            } catch (Exception e) {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug(e.getMessage(), e);
+                }
+            }
+        }
+
+        return content;
+    }
+
+    @Override
+    public CharSequence extract(CharSequence content) {
+        if( content == null ) {
+            return null;
+        }
+        
+        DocumentBuilder builder = getDocBuilder();
+        if (builder != null) {
+            try (StringReader sr = new StringReader(content.toString())) {
+                Document doc = builder.parse(new InputSource(sr));
+                if (returnNullIfPathNotFound) {
+                    Node node = (Node) xPathExpr.evaluate(doc, XPathConstants.NODE);
+                    node.getTextContent();
+                }
+                return xPathExpr.evaluate(doc);
+            } catch (Exception e) {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug(e.getMessage(), e);
+                }
+            }
+        }
+
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/extractor/YamlExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,140 @@
+package com.passus.st.extractor;
+
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author norbert.rostkowski
+ */
+public class YamlExtractor implements ContentExtractor, ContentReplacer {
+
+    private static final Pattern PATH_PATTERN = Pattern.compile("\\.([a-zA-Z0-9_]+)|\\[([0-9]+)\\]");
+
+    private final List<Step> steps = new ArrayList<>();
+    private final String path;
+
+    public YamlExtractor(String path) {
+        this.path = path;
+        convertPath(path);
+    }
+
+    private void convertPath(String path) {
+        Matcher m = PATH_PATTERN.matcher(path);
+        while (m.find()) {
+            String g1 = m.group(1);
+            String g2 = m.group(2);
+            if (g1 != null) {
+                steps.add(new YamlExtractor.MapStep(g1));
+            }
+            if (g2 != null) {
+                int index = Integer.parseInt(g2);
+                steps.add(new YamlExtractor.ArrayStep(index));
+            }
+        }
+    }
+
+    @Override
+    public CharSequence extract(CharSequence content) throws IOException {
+        Yaml yaml = new Yaml();
+        Object o = yaml.load(content.toString());
+
+        for (Step step : steps) {
+            o = step.step(o);
+            if (o == null) {
+                return null;
+            }
+        }
+        return o.toString();
+    }
+
+    @Override
+    public CharSequence replace(CharSequence content, CharSequence value) throws IOException {
+        Yaml yaml = new Yaml();
+        Object o = yaml.load(content.toString());
+        Object root = o;
+        if (value != null) {
+            int stepSize = steps.size();
+            for (int i = 0; i < stepSize - 1; i++) {
+                o = steps.get(i).step(o);
+            }
+            steps.get(stepSize - 1).replace(o, (String) value);
+        }
+        return yaml.dump(root);
+    }
+
+    private static class ArrayStep implements Step {
+
+        private final int index;
+
+        public ArrayStep(int index) {
+            this.index = index;
+        }
+
+        @Override
+        public Object step(Object in) {
+            if (in instanceof List) {
+                List l = (List) in;
+                if (index < l.size() && index >= 0) {
+                    return l.get(index);
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void replace(Object in, String newValue) {
+            if (in instanceof List) {
+                List l = (List) in;
+                if (index < l.size() && index >= 0) {
+                    l.set(index, newValue);
+                }
+
+            }
+
+        }
+    }
+
+    private static class MapStep implements Step {
+
+        private final String key;
+
+        public MapStep(String key) {
+            this.key = key;
+        }
+
+        @Override
+        public Object step(Object in) {
+            if (in instanceof Map) {
+                Map m = (Map) in;
+                return m.get(key);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public void replace(Object in, String newValue) {
+            if (in instanceof Map) {
+                Map m = (Map) in;
+                if (m.containsKey(key)) {
+                    m.put(key, newValue);
+                }
+            }
+
+        }
+
+    }
+
+    private static interface Step {
+
+        Object step(Object in);
+
+        void replace(Object in, String newValue);
+    }
+}
--- a/stress-tester/src/main/java/com/passus/st/filter/HttpMessageWrapperStaticExtractor.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/filter/HttpMessageWrapperStaticExtractor.java	Wed May 29 15:03:59 2019 +0200
@@ -5,8 +5,8 @@
 import com.passus.net.http.HttpMessage;
 import com.passus.net.http.HttpMessageHelper;
 import com.passus.st.ParametersBag;
-import com.passus.st.client.http.extractor.ContentExtractor;
-import com.passus.st.client.http.extractor.ContentExtractorUtils;
+import com.passus.st.extractor.ContentExtractor;
+import com.passus.st.extractor.ContentExtractorUtils;
 import com.passus.st.client.http.filter.HttpMessageWrapper;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -167,7 +167,8 @@
                 }
 
                 if (contentExtractor != null) {
-                    return contentExtractor.extract(message);
+                    String content = HttpMessageHelper.get().contentToString(message, true);
+                    return contentExtractor.extract(content);
                 } else {
                     return httpMessageHelper.contentToString(message, true);
                 }
--- a/stress-tester/src/main/java/com/passus/st/reader/nc/HttpSessionPayloadEventDataWriter.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/reader/nc/HttpSessionPayloadEventDataWriter.java	Wed May 29 15:03:59 2019 +0200
@@ -5,11 +5,12 @@
 import com.passus.data.DataSource;
 import com.passus.data.HeapByteBuff;
 import com.passus.net.http.*;
-import com.passus.st.client.http.HttpSessionPayloadEvent;
+import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.emitter.SessionInfo;
 
 import java.io.IOException;
 
+import static com.passus.st.Protocols.HTTP;
 import static com.passus.st.reader.nc.NcHttpDataUtils.FLAG_REQUEST;
 import static com.passus.st.reader.nc.NcHttpDataUtils.FLAG_RESPONSE;
 
@@ -205,10 +206,14 @@
         writer.closeSessionPayloadBlock();
     }
 
-    public void write(HttpSessionPayloadEvent event, NcDataBlockWriter writer) throws IOException {
+    public void write(SessionPayloadEvent event, NcDataBlockWriter writer) throws IOException {
+        if (event.getProtocolId() != HTTP) {
+            throw new IllegalArgumentException("event.getProtocolId() != HTTP");
+        }
+
         long time = event.getTimestamp();
         SessionInfo session = event.getSessionInfo();
-        encodeFullMessages(time, session, event.getRequest(), event.getResponse(), writer);
+        encodeFullMessages(time, session, (HttpRequest) event.getRequest(), (HttpResponse) event.getResponse(), writer);
     }
 
 }
--- a/stress-tester/src/main/java/com/passus/st/source/NcEventDestination.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/main/java/com/passus/st/source/NcEventDestination.java	Wed May 29 15:03:59 2019 +0200
@@ -5,20 +5,22 @@
 import com.passus.config.ConfigurationContext;
 import com.passus.data.ByteBuff;
 import com.passus.data.HeapByteBuff;
+import com.passus.net.http.HttpRequest;
 import com.passus.net.http.HttpRequestEncoder;
+import com.passus.net.http.HttpResponse;
 import com.passus.net.http.HttpResponseEncoder;
 import com.passus.st.client.DataEvents.DataEnd;
 import com.passus.st.client.Event;
+import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.client.SessionStatusEvent;
-import com.passus.st.client.http.HttpSessionPayloadEvent;
 import com.passus.st.reader.nc.HttpSessionPayloadEventDataWriter;
 import com.passus.st.reader.nc.HttpWriteMode;
 import com.passus.st.reader.nc.NcDataBlockWriter;
+
 import java.io.File;
 import java.io.IOException;
 
 /**
- *
  * @author Mirosław Hawrot
  */
 public class NcEventDestination implements EventDestination {
@@ -139,10 +141,10 @@
 
     }
 
-    private void writeNotEncoded(HttpSessionPayloadEvent event) throws IOException {
+    private void writeNotEncoded(SessionPayloadEvent event) throws IOException {
         if (event.getRequest() != null) {
             ByteBuff buff = new HeapByteBuff();
-            requestEncoder.encode(event.getRequest(), buff);
+            requestEncoder.encode((HttpRequest) event.getRequest(), buff);
             writer.writeSessionPayload(event.getTimestamp(), event.getSessionInfo(), (byte) 1, buff);
         }
 
@@ -151,12 +153,12 @@
                 || mode == HttpWriteMode.HEADERS_ONLY);
         if (event.getResponse() != null && encodeResponse) {
             ByteBuff buff = new HeapByteBuff();
-            responseEncoder.encode(event.getResponse(), buff);
+            responseEncoder.encode((HttpResponse) event.getResponse(), buff);
             writer.writeSessionPayload(event.getTimestamp(), event.getSessionInfo(), (byte) 1, buff);
         }
     }
 
-    private void writeEncoded(HttpSessionPayloadEvent event) throws IOException {
+    private void writeEncoded(SessionPayloadEvent event) throws IOException {
         httpPayloadWriter.write(event, writer);
     }
 
@@ -170,8 +172,8 @@
                     SessionStatusEvent statusEvent = (SessionStatusEvent) event;
                     writer.writeSessionStatus(statusEvent.getTimestamp(), statusEvent.getSessionInfo(), (byte) statusEvent.getStatus());
                     break;
-                case HttpSessionPayloadEvent.TYPE:
-                    HttpSessionPayloadEvent payloadEvent = (HttpSessionPayloadEvent) event;
+                case SessionPayloadEvent.TYPE:
+                    SessionPayloadEvent payloadEvent = (SessionPayloadEvent) event;
 
                     if (encodeData) {
                         writeEncoded(payloadEvent);
--- a/stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java	Wed May 29 15:03:59 2019 +0200
@@ -1,39 +1,32 @@
 package com.passus.st;
 
-import static com.passus.commons.collection.FluentBuilder.e;
-import static com.passus.commons.collection.FluentBuilder.map;
-import com.passus.net.http.HttpHeaders;
-import com.passus.net.http.HttpMessageHelper;
-import com.passus.net.http.HttpMethod;
-import com.passus.net.http.HttpParameters;
-import com.passus.net.http.HttpRequest;
-import com.passus.net.http.HttpRequestBuilder;
-import com.passus.net.http.HttpResponse;
-import com.passus.net.http.HttpResponseBuilder;
-import com.passus.net.http.HttpStatus;
+import com.passus.net.http.*;
+import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.client.credentials.Credentials;
 import com.passus.st.client.credentials.CredentialsProvider;
-import static com.passus.st.client.http.HttpConsts.PARAM_USERNAME;
-import static com.passus.st.client.http.HttpConsts.TAG_MARKER;
-import static com.passus.st.client.http.HttpConsts.TAG_SESSION_ID;
-import static com.passus.st.client.http.HttpConsts.TAG_ZONE;
-import com.passus.st.client.http.HttpSessionPayloadEvent;
 import com.passus.st.client.http.filter.*;
-import com.passus.st.client.http.filter.HttpMessageModificationOperations.*;
+import com.passus.st.client.http.filter.HttpMessageModificationOperations.PostDataSetParamOperation;
+import com.passus.st.client.http.filter.HttpMessageModificationOperations.SetCookieOperation;
+import com.passus.st.client.http.filter.HttpMessageModificationOperations.SetHeaderOperation;
+import com.passus.st.client.http.filter.HttpMessageModificationOperations.SetQueryParameterOperation;
 import com.passus.st.emitter.SessionInfo;
 import com.passus.st.source.ArrayListEventDestination;
 import com.passus.st.source.NullEventDestination;
 import com.passus.st.utils.TestHttpUtils;
-import java.io.IOException;
-import java.util.List;
-import org.apache.logging.log4j.Level;
-import static org.testng.AssertJUnit.*;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 
+import java.io.IOException;
+import java.util.List;
+
+import static com.passus.commons.collection.FluentBuilder.e;
+import static com.passus.commons.collection.FluentBuilder.map;
+import static com.passus.st.Protocols.HTTP;
+import static com.passus.st.client.http.HttpConsts.*;
+import static org.testng.AssertJUnit.*;
+
 /**
- *
  * @author mikolaj.podbielski
  */
 public class ConverterHttpClientTest {
@@ -57,8 +50,8 @@
         AppUtils.unregisterAll();
     }
 
-    static HttpSessionPayloadEvent ev(HttpRequest req, HttpResponse resp) {
-        return new HttpSessionPayloadEvent(SI, req, resp, "test");
+    static SessionPayloadEvent ev(HttpRequest req, HttpResponse resp) {
+        return new SessionPayloadEvent(SI, req, resp, HTTP, "test");
     }
 
     static ConverterHttpClient client(HttpFilter... filters) {
@@ -163,8 +156,8 @@
         client.handle(ev(req2, resp2)); // match:true  filter:deny  chain:deny
 
         assertEquals(1, dst.getEvents().size());
-        HttpSessionPayloadEvent event = dst.findFirst(HttpSessionPayloadEvent.class);
-        assertEquals(200, event.getResponse().getStatus().getCode());
+        SessionPayloadEvent event = dst.findFirst(SessionPayloadEvent.class);
+        assertEquals(200, ((HttpResponse) event.getResponse()).getStatus().getCode());
     }
 
     @Test
--- a/stress-tester/src/test/java/com/passus/st/client/http/HttpAsynchClientWorkerTest.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/test/java/com/passus/st/client/http/HttpAsynchClientWorkerTest.java	Wed May 29 15:03:59 2019 +0200
@@ -46,7 +46,7 @@
                         .withBody(content)));
     }
 
-    @Test
+    @Test(enabled = false)
     public void testHandle() throws Exception {
         Properties props = new Properties();
         props.put("allowPartialSession", "true");
--- a/stress-tester/src/test/java/com/passus/st/client/http/extractor/ContentExtractorUtilsTest.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import static com.passus.st.client.http.extractor.ContentExtractorUtils.createExtractor;
-import static com.passus.st.client.http.extractor.ContentExtractorUtils.createReplacer;
-
-import java.io.IOException;
-
-import static org.testng.AssertJUnit.*;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-/**
- * @author mikolaj.podbielski
- */
-public class ContentExtractorUtilsTest {
-
-    @DataProvider(name = "validExtractors")
-    public Object[][] validExtractors() {
-        String xmlPrefix = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
-        return new Object[][]{
-                {"regexp:aaa(.+)bbb", RegexValueExtractor.class, "aaaXbbbY", "aaaVALUEbbbY"},
-                {"json:$.xx.yy", JsonValueExtractor.class, "{\"xx\": {\"yy\": \"X\"}}", "{\"xx\":{\"yy\":\"VALUE\"}}"},
-                {"xml:/root/node1", XmlValueExtractor.class, "<root><node1>X</node1></root>", xmlPrefix + "<root><node1>VALUE</node1></root>"},
-                {"post:fld1", PostValueExtractor.class, "fld1=X&fld2=Y", "fld1=VALUE&fld2=Y"},
-                {"yaml:$.scalar1", YamlExtractor.class, "scalar1: X", "{scalar1: VALUE}\n"}
-        };
-    }
-
-    @Test(dataProvider = "validExtractors")
-    public void testCreateReplacer(String rule, Class cls, String content, String expected) throws IOException {
-        ContentReplacer r = createReplacer(rule);
-        assertTrue(cls.isInstance(r));
-        CharSequence replaced = r.replace(content, "VALUE");
-        assertEquals(expected, replaced);
-    }
-
-    @Test(dataProvider = "validExtractors")
-    public void testCreateExtractor(String rule, Class cls, String content, String ignored) throws IOException {
-        ContentExtractor e = createExtractor(rule);
-        assertTrue(cls.isInstance(e));
-        CharSequence extracted = e.extract(content);
-        assertEquals("X", extracted.toString()); //PostValueExtractor extracts ByteStringImpl
-    }
-
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/extractor/JsonValueExtractorTest.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import static org.testng.AssertJUnit.*;
-import org.testng.annotations.Test;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public class JsonValueExtractorTest {
-
-    private static String extract(String path, String content) {
-        CharSequence value = new JsonValueExtractor(path).extract(content);
-        if (value == null) {
-            return null;
-        }
-        return value.toString();
-    }
-
-    private static CharSequence replace(String path, String content, String value) {
-        return new JsonValueExtractor(path).replace(content, value);
-    }
-
-    @Test
-    public void testExtract() {
-        String json = "{\n"
-                + "  \"node1\": \"value1\",\n"
-                + "  \"node2\": \"value2\",\n"
-                + "  \"node2\": \"value3\",\n" // this is invalid JSON containing duplicate key
-                + "  \"node3\": {\"node4\": \"value4\"},\n"
-                + "  \"emptyString\": \"\",\n"
-                + "  \"emptyObject\": {},\n"
-                + "  \"emptyArray\": []\n"
-                + "}";
-
-        assertEquals("value1", extract("$.node1", json));
-        assertEquals("value3", extract("$.node2", json)); // duplicate key
-        assertEquals("value4", extract("$.node3.node4", json));
-        assertEquals("", extract("$.emptyString", json));
-        assertEquals("{}", extract("$.emptyObject", json));
-        assertEquals("[]", extract("$.emptyArray", json));
-        assertEquals(null, extract("$.noSuchPath", json));
-        assertEquals(null, extract("$.node", "NOT A JSON"));
-    }
-
-    @Test
-    public void testInvalidJsonPath() {
-        try {
-            JsonValueExtractor e = new JsonValueExtractor("not a path");
-            fail("should throw exception");
-        } catch (Exception ignore) {
-        }
-    }
-
-    @Test
-    public void testReplace() {
-        String json = "{\"node1\": \"value1\"}";
-        assertEquals("{\"node1\":\"newValue1\"}", replace("$.node1", json, "newValue1"));
-
-    }
-
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/extractor/PostValueExtractorTest.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import com.passus.net.MimeTypes;
-import com.passus.net.http.HttpHeaders;
-import com.passus.net.http.HttpMessageHelper;
-import com.passus.net.http.HttpRequest;
-import com.passus.net.http.HttpRequestBuilder;
-import java.io.IOException;
-import static org.testng.AssertJUnit.*;
-import org.testng.annotations.Test;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public class PostValueExtractorTest {
-
-    @Test
-    public void testReplace() throws IOException {
-        String content = "a=value1&b=value2";
-        PostValueExtractor replacer = new PostValueExtractor("b");
-        assertEquals("a=value1&b=newValue2", replacer.replace(content, "newValue2"));
-    }
-
-    @Test
-    public void testReplaceSpecialCharacters() throws IOException {
-        String contentString = "a=%40%26%3D&b=value2";
-        byte[] content = contentString.getBytes();
-        HttpRequest req = HttpRequestBuilder.post("http://www.example.com")
-                .content(content, MimeTypes.APPLICATION_FORM_URLENCODED)
-                .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(content.length))
-                .build();
-        HttpMessageHelper helper = HttpMessageHelper.get();
-
-        PostValueExtractor replacer = new PostValueExtractor("b");
-        String expectedEnc = "a=%40%26%3D&b=%7B%40var%7D";
-        String expectedRaw = "a=%40%26%3D&b={@var}";
-
-        replacer.setOption("escape", true);
-        replacer.replace(req, "{@var}");
-        assertEquals(expectedEnc, helper.contentToString(req));
-        assertEquals(expectedEnc, replacer.replace(contentString, "{@var}"));
-
-        replacer.setOption("escape", false);
-        replacer.replace(req, "{@var}");
-        assertEquals(expectedRaw, helper.contentToString(req));
-        assertEquals(expectedRaw, replacer.replace(contentString, "{@var}"));
-    }
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/extractor/RegexValueExtractorTest.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import static org.testng.AssertJUnit.*;
-import org.testng.annotations.Test;
-
-/**
- *
- * @author mikolaj.podbielski
- */
-public class RegexValueExtractorTest {
-
-    private static CharSequence extract(String regex, String content) {
-        return new RegexValueExtractor(regex).extract(content);
-    }
-
-    private static CharSequence replace(String regex, String content, String value) {
-        return new RegexValueExtractor(regex).replace(content, value);
-    }
-
-    @Test
-    public void testExtract() {
-        String content = "<!DOCTYPE html>\n"
-                + "<html xmlns:ajxp>\n"
-                + "<head>\n"
-                + "	<title>Pydio</title>\n"
-                + "	<base href=\"/pydio/\"/>\n"
-                + "	<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
-                + "</head>\n"
-                + "<body style=\"overflow: hidden;\">\n"
-                + "	<script type=\"text/javascript\">\n"
-                + "	var startParameters = {\n"
-                + "		\"session_timeout\":1440,\n"
-                + "		\"usersEditable\":true,\n"
-                + "		\"SECURE_TOKEN\":\"a5UrXJGaMULhiejTuGeAIwlDN9gEvTUf\"\n"
-                + "	};\n"
-                + "	</script>\n"
-                + "	<div id=\"hidden_frames\" style=\"display:none;\"></div>\n"
-                + "</body>\n"
-                + "</html>";
-
-        assertEquals("a5UrXJGaMULhiejTuGeAIwlDN9gEvTUf", extract("\"SECURE_TOKEN\"[ ]*:[ ]*\"(.*?)\"", content));
-        assertEquals(null, extract("\"SECURE_TOKEN\"[ ]*:[ ]*\"\"", content));
-        assertEquals(null, extract("no_such_pattern(.*?)", content));
-    }
-
-    @Test
-    public void testInvalidRegex() {
-        try {
-            RegexValueExtractor e = new RegexValueExtractor("(((");
-            fail("should throw exception");
-        } catch (Exception ignore) {
-        }
-    }
-
-    @Test
-    public void testReplace() {
-        String content = "abc 123 def";
-        assertEquals("abc newValue def", replace("(\\d+)", content, "newValue"));
-        assertEquals("abc 123 def", replace("\\d+", content, "newValue"));
-    }
-
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/extractor/XmlValueExtractorTest.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import static org.testng.AssertJUnit.*;
-import org.testng.annotations.Test;
-
-/**
- *
- * @author Mirosław Hawrot
- */
-public class XmlValueExtractorTest {
-
-    final String xml = "<?xml version=\"1.0\"?>"
-            + "<root>"
-            + " <node1>value1</node1>"
-            + " <node2>value2</node2>"
-            + " <node2>value3</node2>"
-            + " <node3><node4>value4</node4></node3>"
-            + " <emptyNode></emptyNode>"
-            + "</root>";
-
-    private static CharSequence extract(String path, String content) throws Exception {
-        return new XmlValueExtractor(path).extract(content);
-    }
-
-    private static CharSequence extractWithNull(String path, String content) throws Exception {
-        XmlValueExtractor e = new XmlValueExtractor(path);
-        e.setReturnNullIfPathNotFound(true);
-        return e.extract(content);
-    }
-
-    private static String replace(String path, String content, String value) throws Exception {
-        CharSequence newValue = new XmlValueExtractor(path).replace(content, value);
-        if (newValue == null) {
-            return null;
-        }
-
-        return newValue.toString();
-    }
-
-    @Test
-    public void testExtract() throws Exception {
-        assertEquals("value1", extract("/root/node1", xml));
-        assertEquals("value2", extract("/root/node2", xml));
-        assertEquals("value3", extract("/root/node2[2]", xml));
-        assertEquals("value4", extract("/root/node3/node4", xml));
-        assertEquals("", extract("/root/emptyNode", xml));
-
-        assertEquals("", extract("/root/noSuchNode", xml));
-        assertEquals("", extract("/root/node1/@noSuchAttribute", xml));
-        assertEquals(null, extract("/root/node1", "NOT AN XML"));
-        // TODO: zwraca pusty string, gdy nie ma podanej ścieżki, przydałby się null
-        // TODO: sprawdzić zachowanie i wydajność Apache JXPath
-    }
-
-    @Test
-    public void testExtractWithNull() throws Exception {
-        assertEquals("value1", extractWithNull("/root/node1", xml));
-        assertEquals("value2", extractWithNull("/root/node2", xml));
-        assertEquals("value3", extractWithNull("/root/node2[2]", xml));
-        assertEquals("value4", extractWithNull("/root/node3/node4", xml));
-        assertEquals("", extractWithNull("/root/emptyNode", xml));
-
-        assertEquals(null, extractWithNull("/root/noSuchNode", xml));
-        assertEquals(null, extractWithNull("/root/node1/@noSuchAttribute", xml));
-        assertEquals(null, extractWithNull("/root/node1", "NOT AN XML"));
-    }
-
-    @Test
-    public void testInvalidXPath() {
-        try {
-            XmlValueExtractor e = new XmlValueExtractor("not a path");
-            fail("should throw exception");
-        } catch (Exception ignore) {
-        }
-    }
-
-    @Test
-    public void testReplace() throws Exception {
-        String xml = "<?xml version=\"1.0\"?><root><node1>value1</node1></root>";
-        assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><root><node1>newValue1</node1></root>", replace("/root/node1", xml, "newValue1"));
-        assertEquals(xml, replace("/root/unknwonNode", xml, "newValue1"));
-    }
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/extractor/YamlExtractorTest.java	Wed May 29 12:32:29 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-package com.passus.st.client.http.extractor;
-
-import static org.testng.AssertJUnit.*;
-import org.testng.annotations.Test;
-import org.yaml.snakeyaml.Yaml;
-
-import java.util.Map;
-
-/**
- *
- * @author norbert.rostkowski
- */
-public class YamlExtractorTest {   /* RAW YAML:
-scalar1: value1
-object1:
-  nested_list:
-    - a
-    - b
-  description: 'this is nested list'
-list_of_scalars:
-  - x
-  - y
-  - z
-list_of_objects:
-  - name: nested1
-    a: 1
-    b: 2
-  - name: nested2
-    a: 3
-    b: 4
-  - some_scalar
-  -
-    - aa
-    - bb
-    - cc
-
-         */
-    String yaml = ""
-            + "scalar1: value1\n"
-            + "object1:\n"
-            + "  nested_list:\n"
-            + "    - a\n"
-            + "    - b\n"
-            + "  description: 'this is nested list'\n"
-            + "list_of_scalars:\n"
-            + "  - x\n"
-            + "  - y\n"
-            + "  - z\n"
-            + "list_of_objects:\n"
-            + "  - name: nested1\n"
-            + "    a: 1\n"
-            + "    b: 2\n"
-            + "  - name: nested2\n"
-            + "    a: 3\n"
-            + "    b: 4\n"
-            + "  - some_scalar\n"
-            + "  - \n"
-            + "    - aa\n"
-            + "    - bb\n"
-            + "    - cc\n";
-
-    @Test
-    public void replaceAndLoad() throws Exception {
-
-        testReplace("x", "$.object1.nested_list[1]");
-        testReplace("xx", "$.list_of_scalars[1]");
-        testReplace("val22", "$.scalar1");
-        testReplace("desc", "$.object1.description");
-        testReplace("name33", "$.list_of_objects[1].name");
-        testReplace("val44", "$.list_of_objects[2]");
-        testReplace("val44", "$.list_of_objects[3][1]");
-        testReplaceForNull("val44", "$.no_such_node");
-        testReplaceForNull("val44", "$.object1.no_such_node");
-        testReplaceForNull("val44", "$.no_such_node");
-        testReplaceForNull("val44", "$.list_of_scalars[777]");
-        testReplaceForNull("val44", "$.list_of_objects[3].kaczka");
-        testReplaceForNull("val44", "$.list_of_objects[1][0]");
-    }
-
-    private void testReplaceForNull(String newValue, String path) throws Exception {
-
-        YamlExtractor extractor = new YamlExtractor(path);
-        String replaced = extractor.replace(yaml, newValue).toString();
-        assertNull(new YamlExtractor(path).extract(yaml));
-    }
-
-    private void testReplace(String newValue, String path) throws Exception {
-        YamlExtractor extractor = new YamlExtractor(path);
-        String replaced = extractor.replace(yaml, newValue).toString();
-        assertEquals(newValue, extractor.extract(replaced).toString());
-    }
-
-    @Test
-    public void testExtract() throws Exception {
-
-
-        assertEquals("value1", new YamlExtractor("$.scalar1").extract(yaml));
-        assertEquals("this is nested list", new YamlExtractor("$.object1.description").extract(yaml));
-        assertEquals("b", new YamlExtractor("$.object1.nested_list[1]").extract(yaml));
-        assertEquals("y", new YamlExtractor("$.list_of_scalars[1]").extract(yaml));
-        assertEquals("nested2", new YamlExtractor("$.list_of_objects[1].name").extract(yaml));
-        assertEquals("some_scalar", new YamlExtractor("$.list_of_objects[2]").extract(yaml));
-        assertEquals("bb", new YamlExtractor("$.list_of_objects[3][1]").extract(yaml));
-//
-        assertNull(new YamlExtractor("$.no_such_node").extract(yaml));
-        assertNull(new YamlExtractor("$.object1.no_such_node").extract(yaml));
-        assertNull(new YamlExtractor("$.list_of_scalars[777]").extract(yaml));
-
-        assertNull(new YamlExtractor("$.list_of_objects[3].kaczka").extract(yaml));
-        assertNull(new YamlExtractor("$.list_of_objects[1][0]").extract(yaml));
-    }
-
-}
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageModificationFilterTest.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMessageModificationFilterTest.java	Wed May 29 15:03:59 2019 +0200
@@ -7,7 +7,7 @@
 import com.passus.net.http.*;
 import com.passus.st.AppUtils;
 import com.passus.st.client.FlowContext;
-import com.passus.st.client.http.extractor.ContentExtractorUtils;
+import com.passus.st.extractor.ContentExtractorUtils;
 import com.passus.st.client.http.filter.HttpMessageModificationOperations.*;
 import com.passus.st.utils.ConfigurationContextConsts;
 import org.testng.annotations.AfterClass;
@@ -185,7 +185,7 @@
                 + "        setHeader: \n"
                 + "            Header3: Header1Value3a\n"
                 + "        setHeader: \n"
-                + "            Header6: \"@extractHttpContext.getSession('testId').get('testParam')\"\n"
+                + "            Header6: \"@scopes.getSession('testId').get('testParam')\"\n"
                 + "        setHeader: \n"
                 + "            Header7: \"@httpSession.get('testParam')\"\n";
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/extractor/ContentExtractorUtilsTest.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,46 @@
+package com.passus.st.extractor;
+
+import static com.passus.st.extractor.ContentExtractorUtils.createExtractor;
+import static com.passus.st.extractor.ContentExtractorUtils.createReplacer;
+
+import java.io.IOException;
+
+import static org.testng.AssertJUnit.*;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author mikolaj.podbielski
+ */
+public class ContentExtractorUtilsTest {
+
+    @DataProvider(name = "validExtractors")
+    public Object[][] validExtractors() {
+        String xmlPrefix = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>";
+        return new Object[][]{
+                {"regexp:aaa(.+)bbb", RegexValueExtractor.class, "aaaXbbbY", "aaaVALUEbbbY"},
+                {"json:$.xx.yy", JsonValueExtractor.class, "{\"xx\": {\"yy\": \"X\"}}", "{\"xx\":{\"yy\":\"VALUE\"}}"},
+                {"xml:/root/node1", XmlValueExtractor.class, "<root><node1>X</node1></root>", xmlPrefix + "<root><node1>VALUE</node1></root>"},
+                {"post:fld1", PostValueExtractor.class, "fld1=X&fld2=Y", "fld1=VALUE&fld2=Y"},
+                {"yaml:$.scalar1", YamlExtractor.class, "scalar1: X", "{scalar1: VALUE}\n"}
+        };
+    }
+
+    @Test(dataProvider = "validExtractors")
+    public void testCreateReplacer(String rule, Class cls, String content, String expected) throws IOException {
+        ContentReplacer r = createReplacer(rule);
+        assertTrue(cls.isInstance(r));
+        CharSequence replaced = r.replace(content, "VALUE");
+        assertEquals(expected, replaced);
+    }
+
+    @Test(dataProvider = "validExtractors")
+    public void testCreateExtractor(String rule, Class cls, String content, String ignored) throws IOException {
+        ContentExtractor e = createExtractor(rule);
+        assertTrue(cls.isInstance(e));
+        CharSequence extracted = e.extract(content);
+        assertEquals("X", extracted.toString()); //PostValueExtractor extracts ByteStringImpl
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/extractor/JsonValueExtractorTest.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,62 @@
+package com.passus.st.extractor;
+
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+public class JsonValueExtractorTest {
+
+    private static String extract(String path, String content) {
+        CharSequence value = new JsonValueExtractor(path).extract(content);
+        if (value == null) {
+            return null;
+        }
+        return value.toString();
+    }
+
+    private static CharSequence replace(String path, String content, String value) {
+        return new JsonValueExtractor(path).replace(content, value);
+    }
+
+    @Test
+    public void testExtract() {
+        String json = "{\n"
+                + "  \"node1\": \"value1\",\n"
+                + "  \"node2\": \"value2\",\n"
+                + "  \"node2\": \"value3\",\n" // this is invalid JSON containing duplicate key
+                + "  \"node3\": {\"node4\": \"value4\"},\n"
+                + "  \"emptyString\": \"\",\n"
+                + "  \"emptyObject\": {},\n"
+                + "  \"emptyArray\": []\n"
+                + "}";
+
+        assertEquals("value1", extract("$.node1", json));
+        assertEquals("value3", extract("$.node2", json)); // duplicate key
+        assertEquals("value4", extract("$.node3.node4", json));
+        assertEquals("", extract("$.emptyString", json));
+        assertEquals("{}", extract("$.emptyObject", json));
+        assertEquals("[]", extract("$.emptyArray", json));
+        assertEquals(null, extract("$.noSuchPath", json));
+        assertEquals(null, extract("$.node", "NOT A JSON"));
+    }
+
+    @Test
+    public void testInvalidJsonPath() {
+        try {
+            JsonValueExtractor e = new JsonValueExtractor("not a path");
+            fail("should throw exception");
+        } catch (Exception ignore) {
+        }
+    }
+
+    @Test
+    public void testReplace() {
+        String json = "{\"node1\": \"value1\"}";
+        assertEquals("{\"node1\":\"newValue1\"}", replace("$.node1", json, "newValue1"));
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/extractor/PostValueExtractorTest.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,49 @@
+package com.passus.st.extractor;
+
+import com.passus.net.MimeTypes;
+import com.passus.net.http.HttpHeaders;
+import com.passus.net.http.HttpMessageHelper;
+import com.passus.net.http.HttpRequest;
+import com.passus.net.http.HttpRequestBuilder;
+import java.io.IOException;
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Mirosław Hawrot
+ */
+public class PostValueExtractorTest {
+
+    @Test
+    public void testReplace() throws IOException {
+        String content = "a=value1&b=value2";
+        PostValueExtractor replacer = new PostValueExtractor("b");
+        assertEquals("a=value1&b=newValue2", replacer.replace(content, "newValue2"));
+    }
+
+    @Test
+    public void testReplaceSpecialCharacters() throws IOException {
+        String contentString = "a=%40%26%3D&b=value2";
+        byte[] content = contentString.getBytes();
+        HttpRequest req = HttpRequestBuilder.post("http://www.example.com")
+                .content(content, MimeTypes.APPLICATION_FORM_URLENCODED)
+                .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(content.length))
+                .build();
+        HttpMessageHelper helper = HttpMessageHelper.get();
+
+        PostValueExtractor replacer = new PostValueExtractor("b");
+        String expectedEnc = "a=%40%26%3D&b=%7B%40var%7D";
+        String expectedRaw = "a=%40%26%3D&b={@var}";
+
+        replacer.setOption("escape", true);
+        replacer.replace(req, "{@var}");
+        assertEquals(expectedEnc, helper.contentToString(req));
+        assertEquals(expectedEnc, replacer.replace(contentString, "{@var}"));
+
+        replacer.setOption("escape", false);
+        replacer.replace(req, "{@var}");
+        assertEquals(expectedRaw, helper.contentToString(req));
+        assertEquals(expectedRaw, replacer.replace(contentString, "{@var}"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/extractor/RegexValueExtractorTest.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,62 @@
+package com.passus.st.extractor;
+
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+public class RegexValueExtractorTest {
+
+    private static CharSequence extract(String regex, String content) {
+        return new RegexValueExtractor(regex).extract(content);
+    }
+
+    private static CharSequence replace(String regex, String content, String value) {
+        return new RegexValueExtractor(regex).replace(content, value);
+    }
+
+    @Test
+    public void testExtract() {
+        String content = "<!DOCTYPE html>\n"
+                + "<html xmlns:ajxp>\n"
+                + "<head>\n"
+                + "	<title>Pydio</title>\n"
+                + "	<base href=\"/pydio/\"/>\n"
+                + "	<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
+                + "</head>\n"
+                + "<body style=\"overflow: hidden;\">\n"
+                + "	<script type=\"text/javascript\">\n"
+                + "	var startParameters = {\n"
+                + "		\"session_timeout\":1440,\n"
+                + "		\"usersEditable\":true,\n"
+                + "		\"SECURE_TOKEN\":\"a5UrXJGaMULhiejTuGeAIwlDN9gEvTUf\"\n"
+                + "	};\n"
+                + "	</script>\n"
+                + "	<div id=\"hidden_frames\" style=\"display:none;\"></div>\n"
+                + "</body>\n"
+                + "</html>";
+
+        assertEquals("a5UrXJGaMULhiejTuGeAIwlDN9gEvTUf", extract("\"SECURE_TOKEN\"[ ]*:[ ]*\"(.*?)\"", content));
+        assertEquals(null, extract("\"SECURE_TOKEN\"[ ]*:[ ]*\"\"", content));
+        assertEquals(null, extract("no_such_pattern(.*?)", content));
+    }
+
+    @Test
+    public void testInvalidRegex() {
+        try {
+            RegexValueExtractor e = new RegexValueExtractor("(((");
+            fail("should throw exception");
+        } catch (Exception ignore) {
+        }
+    }
+
+    @Test
+    public void testReplace() {
+        String content = "abc 123 def";
+        assertEquals("abc newValue def", replace("(\\d+)", content, "newValue"));
+        assertEquals("abc 123 def", replace("\\d+", content, "newValue"));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/extractor/XmlValueExtractorTest.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,83 @@
+package com.passus.st.extractor;
+
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Mirosław Hawrot
+ */
+public class XmlValueExtractorTest {
+
+    final String xml = "<?xml version=\"1.0\"?>"
+            + "<root>"
+            + " <node1>value1</node1>"
+            + " <node2>value2</node2>"
+            + " <node2>value3</node2>"
+            + " <node3><node4>value4</node4></node3>"
+            + " <emptyNode></emptyNode>"
+            + "</root>";
+
+    private static CharSequence extract(String path, String content) throws Exception {
+        return new XmlValueExtractor(path).extract(content);
+    }
+
+    private static CharSequence extractWithNull(String path, String content) throws Exception {
+        XmlValueExtractor e = new XmlValueExtractor(path);
+        e.setReturnNullIfPathNotFound(true);
+        return e.extract(content);
+    }
+
+    private static String replace(String path, String content, String value) throws Exception {
+        CharSequence newValue = new XmlValueExtractor(path).replace(content, value);
+        if (newValue == null) {
+            return null;
+        }
+
+        return newValue.toString();
+    }
+
+    @Test
+    public void testExtract() throws Exception {
+        assertEquals("value1", extract("/root/node1", xml));
+        assertEquals("value2", extract("/root/node2", xml));
+        assertEquals("value3", extract("/root/node2[2]", xml));
+        assertEquals("value4", extract("/root/node3/node4", xml));
+        assertEquals("", extract("/root/emptyNode", xml));
+
+        assertEquals("", extract("/root/noSuchNode", xml));
+        assertEquals("", extract("/root/node1/@noSuchAttribute", xml));
+        assertEquals(null, extract("/root/node1", "NOT AN XML"));
+        // TODO: zwraca pusty string, gdy nie ma podanej ścieżki, przydałby się null
+        // TODO: sprawdzić zachowanie i wydajność Apache JXPath
+    }
+
+    @Test
+    public void testExtractWithNull() throws Exception {
+        assertEquals("value1", extractWithNull("/root/node1", xml));
+        assertEquals("value2", extractWithNull("/root/node2", xml));
+        assertEquals("value3", extractWithNull("/root/node2[2]", xml));
+        assertEquals("value4", extractWithNull("/root/node3/node4", xml));
+        assertEquals("", extractWithNull("/root/emptyNode", xml));
+
+        assertEquals(null, extractWithNull("/root/noSuchNode", xml));
+        assertEquals(null, extractWithNull("/root/node1/@noSuchAttribute", xml));
+        assertEquals(null, extractWithNull("/root/node1", "NOT AN XML"));
+    }
+
+    @Test
+    public void testInvalidXPath() {
+        try {
+            XmlValueExtractor e = new XmlValueExtractor("not a path");
+            fail("should throw exception");
+        } catch (Exception ignore) {
+        }
+    }
+
+    @Test
+    public void testReplace() throws Exception {
+        String xml = "<?xml version=\"1.0\"?><root><node1>value1</node1></root>";
+        assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><root><node1>newValue1</node1></root>", replace("/root/node1", xml, "newValue1"));
+        assertEquals(xml, replace("/root/unknwonNode", xml, "newValue1"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/extractor/YamlExtractorTest.java	Wed May 29 15:03:59 2019 +0200
@@ -0,0 +1,110 @@
+package com.passus.st.extractor;
+
+import static org.testng.AssertJUnit.*;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author norbert.rostkowski
+ */
+public class YamlExtractorTest {   /* RAW YAML:
+scalar1: value1
+object1:
+  nested_list:
+    - a
+    - b
+  description: 'this is nested list'
+list_of_scalars:
+  - x
+  - y
+  - z
+list_of_objects:
+  - name: nested1
+    a: 1
+    b: 2
+  - name: nested2
+    a: 3
+    b: 4
+  - some_scalar
+  -
+    - aa
+    - bb
+    - cc
+
+         */
+    String yaml = ""
+            + "scalar1: value1\n"
+            + "object1:\n"
+            + "  nested_list:\n"
+            + "    - a\n"
+            + "    - b\n"
+            + "  description: 'this is nested list'\n"
+            + "list_of_scalars:\n"
+            + "  - x\n"
+            + "  - y\n"
+            + "  - z\n"
+            + "list_of_objects:\n"
+            + "  - name: nested1\n"
+            + "    a: 1\n"
+            + "    b: 2\n"
+            + "  - name: nested2\n"
+            + "    a: 3\n"
+            + "    b: 4\n"
+            + "  - some_scalar\n"
+            + "  - \n"
+            + "    - aa\n"
+            + "    - bb\n"
+            + "    - cc\n";
+
+    @Test
+    public void replaceAndLoad() throws Exception {
+
+        testReplace("x", "$.object1.nested_list[1]");
+        testReplace("xx", "$.list_of_scalars[1]");
+        testReplace("val22", "$.scalar1");
+        testReplace("desc", "$.object1.description");
+        testReplace("name33", "$.list_of_objects[1].name");
+        testReplace("val44", "$.list_of_objects[2]");
+        testReplace("val44", "$.list_of_objects[3][1]");
+        testReplaceForNull("val44", "$.no_such_node");
+        testReplaceForNull("val44", "$.object1.no_such_node");
+        testReplaceForNull("val44", "$.no_such_node");
+        testReplaceForNull("val44", "$.list_of_scalars[777]");
+        testReplaceForNull("val44", "$.list_of_objects[3].kaczka");
+        testReplaceForNull("val44", "$.list_of_objects[1][0]");
+    }
+
+    private void testReplaceForNull(String newValue, String path) throws Exception {
+
+        YamlExtractor extractor = new YamlExtractor(path);
+        String replaced = extractor.replace(yaml, newValue).toString();
+        assertNull(new YamlExtractor(path).extract(yaml));
+    }
+
+    private void testReplace(String newValue, String path) throws Exception {
+        YamlExtractor extractor = new YamlExtractor(path);
+        String replaced = extractor.replace(yaml, newValue).toString();
+        assertEquals(newValue, extractor.extract(replaced).toString());
+    }
+
+    @Test
+    public void testExtract() throws Exception {
+
+
+        assertEquals("value1", new YamlExtractor("$.scalar1").extract(yaml));
+        assertEquals("this is nested list", new YamlExtractor("$.object1.description").extract(yaml));
+        assertEquals("b", new YamlExtractor("$.object1.nested_list[1]").extract(yaml));
+        assertEquals("y", new YamlExtractor("$.list_of_scalars[1]").extract(yaml));
+        assertEquals("nested2", new YamlExtractor("$.list_of_objects[1].name").extract(yaml));
+        assertEquals("some_scalar", new YamlExtractor("$.list_of_objects[2]").extract(yaml));
+        assertEquals("bb", new YamlExtractor("$.list_of_objects[3][1]").extract(yaml));
+//
+        assertNull(new YamlExtractor("$.no_such_node").extract(yaml));
+        assertNull(new YamlExtractor("$.object1.no_such_node").extract(yaml));
+        assertNull(new YamlExtractor("$.list_of_scalars[777]").extract(yaml));
+
+        assertNull(new YamlExtractor("$.list_of_objects[3].kaczka").extract(yaml));
+        assertNull(new YamlExtractor("$.list_of_objects[1][0]").extract(yaml));
+    }
+
+}
--- a/stress-tester/src/test/java/com/passus/st/filter/HttpMessageValueExtractorTest.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/test/java/com/passus/st/filter/HttpMessageValueExtractorTest.java	Wed May 29 15:03:59 2019 +0200
@@ -100,10 +100,10 @@
                 {"resp.cookie@Unknown", null},
 
                 //Scopes
-                {"extractHttpContext", HttpScopes.class},
-                {"extractHttpContext.global", ParametersBag.class},
-                {"extractHttpContext.global.get('GlobalVar1')", "GlobalVal1"},
-                {"extractHttpContext.getSession('sessId').get('Var1')", "Val1"},
+                {"scopes", HttpScopes.class},
+                {"scopes.global", ParametersBag.class},
+                {"scopes.global.get('GlobalVar1')", "GlobalVal1"},
+                {"scopes.getSession('sessId').get('Var1')", "Val1"},
                 {"globalParams", ParametersBag.class},
                 {"globalParams.get('GlobalVar1')", "GlobalVal1"},
                 {"globalParams@GlobalVar1", "GlobalVal1"},
--- a/stress-tester/src/test/java/com/passus/st/source/NcEventDestinationTest.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/test/java/com/passus/st/source/NcEventDestinationTest.java	Wed May 29 15:03:59 2019 +0200
@@ -2,6 +2,7 @@
 
 import static com.passus.commons.utils.ResourceUtils.createTmpFile;
 import com.passus.st.client.Event;
+import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.client.SessionStatusEvent;
 import com.passus.st.client.http.HttpSessionPayloadEvent;
 import com.passus.st.emitter.SessionInfo;
@@ -32,7 +33,7 @@
         List<Event> events = EventUtils.readEvents("pcap/http/http_req_resp.pcap", props);
         assertEquals(4, events.size());
 
-        HttpSessionPayloadEvent payloadEvent = (HttpSessionPayloadEvent) events.get(0);
+        SessionPayloadEvent payloadEvent = (SessionPayloadEvent) events.get(0);
         SessionStatusEvent statusEvent = (SessionStatusEvent) events.get(1);
         SessionInfo sessionInfo = payloadEvent.getSessionInfo();
 
--- a/stress-tester/src/test/java/com/passus/st/source/PcapSessionEventSourceTest.java	Wed May 29 12:32:29 2019 +0200
+++ b/stress-tester/src/test/java/com/passus/st/source/PcapSessionEventSourceTest.java	Wed May 29 15:03:59 2019 +0200
@@ -1,5 +1,6 @@
 package com.passus.st.source;
 
+import com.passus.st.client.SessionPayloadEvent;
 import com.passus.st.client.http.HttpSessionPayloadEvent;
 import com.passus.commons.utils.ResourceUtils;
 import com.passus.st.client.ArrayListEventHandler;
@@ -33,7 +34,7 @@
         src.stop();
 
         assertTrue(handler.get(handler.size() - 3) instanceof SessionStatusEvent);
-        assertTrue(handler.findFirst(HttpSessionPayloadEvent.TYPE) instanceof HttpSessionPayloadEvent);
+        assertTrue(handler.findFirst(SessionPayloadEvent.TYPE) instanceof SessionPayloadEvent);
         assertTrue(handler.get(handler.size() - 2) instanceof DataLoopEnd);
         assertTrue(handler.get(handler.size() - 1) instanceof DataEnd);
     }