changeset 727:7bc4eb666b7f

ConverterHttpClient - filters
author Devel 1
date Fri, 01 Dec 2017 14:25:20 +0100
parents af5daf4a3879
children c3a2898241a0
files stress-tester/src/main/java/com/passus/st/ConverterHttpClient.java stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java
diffstat 2 files changed, 354 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/stress-tester/src/main/java/com/passus/st/ConverterHttpClient.java	Fri Dec 01 14:25:05 2017 +0100
+++ b/stress-tester/src/main/java/com/passus/st/ConverterHttpClient.java	Fri Dec 01 14:25:20 2017 +0100
@@ -4,10 +4,17 @@
 import com.passus.commons.service.Service;
 import com.passus.st.client.Event;
 import com.passus.st.client.EventHandler;
+import com.passus.st.client.SessionStatusEvent;
+import com.passus.st.client.http.HttpFlowContext;
+import com.passus.st.client.http.HttpScopes;
+import com.passus.st.client.http.HttpSessionPayloadEvent;
 import com.passus.st.client.http.filter.HttpFilter;
 import com.passus.st.client.http.filter.HttpFilterAware;
 import com.passus.st.client.http.filter.HttpFilterChain;
+import com.passus.st.emitter.SessionInfo;
 import com.passus.st.source.EventDestination;
+import java.util.HashMap;
+import java.util.Map;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -21,6 +28,8 @@
 
     private final EventDestination dst;
     private final HttpFilterChain filterChain = new HttpFilterChain();
+    private final HttpScopes scopes = new HttpScopes();
+    protected final Map<SessionInfo, HttpFlowContext> sessions = new HashMap<>();
 
     private boolean started;
 
@@ -66,6 +75,29 @@
         }
 
         try {
+            switch (event.getType()) {
+                case SessionStatusEvent.TYPE: {
+                    SessionStatusEvent e = (SessionStatusEvent) event;
+                    // tworzyc HttpFlowContext ???
+                    if (e.getStatus() == SessionStatusEvent.STATUS_CLOSED) {
+                        deregisterFlow(e.getSessionInfo());
+                    }
+                }
+                case HttpSessionPayloadEvent.TYPE: {
+                    HttpSessionPayloadEvent e = (HttpSessionPayloadEvent) event;
+                    HttpFlowContext flow = getFlow(e.getSessionInfo());
+                    int result = filterChain.filterOutbound(e.getRequest(), e.getResponse(), flow);
+                    if (result == HttpFilter.ACCEPT) {
+                        // krok potrzebny dla kilku filtrów, np session, digestLogin
+                        flow.setSentEvent(e);
+                        filterChain.filterInbound(e.getRequest(), e.getResponse(), flow);
+                    } else {
+                        return; // skip dst.handle()
+                    }
+                    break;
+                }
+            }
+
             dst.handle(event);
         } catch (Exception e) {
             LOGGER.debug(e.getMessage(), e);
@@ -81,4 +113,21 @@
     public void join() {
     }
 
+    HttpScopes scopes() {
+        return scopes;
+    }
+
+    private HttpFlowContext getFlow(SessionInfo session) {
+        HttpFlowContext flowContext = sessions.get(session);
+        if (flowContext == null) {
+            flowContext = new HttpFlowContext(session, scopes);
+            sessions.put(session, flowContext);
+        }
+        return flowContext;
+
+    }
+
+    private HttpFlowContext deregisterFlow(SessionInfo session) {
+        return sessions.remove(session);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/test/java/com/passus/st/ConverterHttpClientTest.java	Fri Dec 01 14:25:20 2017 +0100
@@ -0,0 +1,305 @@
+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.st.client.Event;
+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.HttpMessageModificationFilter.PostDataSetParamOperation;
+import com.passus.st.client.http.filter.HttpMessageModificationFilter.SetCookieOperation;
+import com.passus.st.client.http.filter.HttpMessageModificationFilter.SetHeaderOperation;
+import com.passus.st.client.http.filter.HttpMessageModificationFilter.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.Arrays;
+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;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ */
+public class ConverterHttpClientTest {
+
+    static SessionInfo SI = new SessionInfo("1.1.1.1", 11000, "1.1.1.2", 80);
+    static Credentials CREDENTIALS = new Credentials("test", "test");
+    static CredentialsProvider PROVIDER = HttpAbstractLoginFilterTest.provider(CREDENTIALS);
+    static NullEventDestination DST = new NullEventDestination();
+
+    static {
+        Log4jConfigurationFactory.enableFactory(Level.DEBUG);
+    }
+
+    @BeforeClass
+    public static void beforeClass() {
+        AppUtils.registerAll();
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        AppUtils.unregisterAll();
+    }
+
+    static HttpSessionPayloadEvent ev(HttpRequest req, HttpResponse resp) {
+        return new HttpSessionPayloadEvent(SI, req, resp, "test");
+    }
+
+    static ConverterHttpClient client(HttpFilter... filters) {
+        ConverterHttpClient client = new ConverterHttpClient(DST);
+        for (HttpFilter filter : filters) {
+            client.addFilter(filter);
+        }
+        client.start();
+        return client;
+    }
+
+    @Test
+    public void testBasicLogin_filterShouldReplaceCredentials() {
+        final String REQS = "GET /basic/index.html HTTP/1.1\r\n"
+                + "Authorization: Basic dXNlcjpwYXNzd29yZA==\r\n\r\n";
+        HttpRequest req = TestHttpUtils.request(REQS);
+        HttpResponse resp = HttpResponseBuilder.ok().build();
+
+        HttpBasicAuthLoginFilter f = HttpBasicAuthLoginFilterTest.createFilter(PROVIDER);
+        ConverterHttpClient client = client(f);
+        client.handle(ev(req, resp));
+
+        assertEquals(req.getHeaders().get(HttpHeaders.AUTHORIZATION).toString(), "Basic dGVzdDp0ZXN0");
+        assertEquals(client.scopes().getConversation(req).get(PARAM_USERNAME), "test");
+    }
+
+    @Test
+    public void testDigestLogin_filterShouldReplaceCredentials() {
+        final String RESP1S = "HTTP/1.1 401 Unauthorized\r\n"
+                + "Date: Fri, 09 Jun 2017 06:25:27 GMT\r\n"
+                + "WWW-Authenticate: Digest realm=\"realm\", nonce=\"old-nonce\", algorithm=MD5, qop=\"auth\"\r\n"
+                + "Content-Length: 12\r\n\r\nUnauthorized";
+        final String REQ2S = "GET /html/digest/index2.html HTTP/1.1\r\n"
+                + "Host: 172.16.60.101\r\n"
+                + "Authorization: Digest username=\"user\", realm=\"realm\", nonce=\"old-nonce\","
+                + " uri=\"/html/digest/index2.html\", algorithm=MD5, response=\"774280b22c9ed40bc500bba5c431d8c7\","
+                + " qop=auth, nc=00000001, cnonce=\"cnonce\"\r\n\r\n";
+        final String RESP2S = "HTTP/1.1 200 OK\n"
+                + "Authentication-Info: rspauth=\"?\", cnonce=\"?\", nc=00000001, qop=auth\r\n"
+                + "Content-Length: 33\r\n\r\n<html><body>content</body></html>";
+
+        HttpRequest req1 = HttpRequestBuilder.get("http://html/digest/index2.html").build();
+        HttpResponse resp1 = TestHttpUtils.response(RESP1S);
+        HttpRequest req2 = TestHttpUtils.request(REQ2S);
+        HttpResponse resp2 = TestHttpUtils.response(RESP2S);
+        req2.setTag(TAG_SESSION_ID, "sid1");
+
+        HttpDigestAuthLoginFilter f = HttpDigestAuthLoginFilterTest.createFilter(CREDENTIALS);
+        ConverterHttpClient client = client(f);
+        client.handle(ev(req1, resp1));
+        client.handle(ev(req2, resp2));
+
+        assertEquals(client.scopes().getConversation(req2).get(PARAM_USERNAME), "test");
+        assertEquals(client.scopes().getSession(req2).get(PARAM_USERNAME), "test");
+    }
+
+    @Test
+    public void testFormLogin() throws IOException {
+        final String REQS = "POST /login_check HTTP/1.1\r\n"
+                + "Host: 172.16.60.23\r\n"
+                + "Content-Type: application/x-www-form-urlencoded\r\n"
+                + "Content-Length: 32\r\n"
+                + "Cookie: PHPSESSID=4r7tg8275ih7p0uh79im6q5643\r\n\r\n"
+                + "_username=admin&_password=qwerty";
+        final String RESPS = "HTTP/1.1 302 Found\r\n"
+                + "Set-Cookie: PHPSESSID=pcap_post; path=/; HttpOnly\r\n"
+                + "Location: http://172.16.60.23/\r\n"
+                + "Content-Length: 2\r\n\r\n"
+                + "OK";
+
+        HttpRequest req = TestHttpUtils.request(REQS);
+        HttpResponse resp = TestHttpUtils.response(RESPS);
+        req.setTag(TAG_SESSION_ID, "sid1");
+
+        HttpFormLoginFilter f = HttpFormLoginFilterTest.createFilter(PROVIDER);
+        ConverterHttpClient client = client(f);
+        client.handle(ev(req, resp));
+
+        HttpFormLoginFilterTest.assertContent(req, "_username=test&_password=test");
+        assertEquals(client.scopes().getConversation(req).get(PARAM_USERNAME), "test");
+        assertEquals(client.scopes().getSession(req).get(PARAM_USERNAME), "test");
+    }
+
+    @Test
+    public void testMatcher() {
+        HttpRequest req1 = HttpRequestBuilder.get("http://test.com/test").build();
+        HttpRequest req2 = HttpRequestBuilder.get("http://test2.com/test2").build();
+        HttpResponse resp1 = HttpResponseBuilder.ok().build();
+        HttpResponse resp2 = HttpResponseBuilder.status(HttpStatus.NO_CONTENT).build();
+
+        ArrayListEventDestination dst = new ArrayListEventDestination();
+        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{req.url: {$contains: test2}}");
+        HttpMatchFilter f = new HttpMatchFilter();
+        f.setPredicate(predicate);
+        f.setAcceptOnMatch(false);
+
+        ConverterHttpClient client = new ConverterHttpClient(dst);
+        client.addFilter(f);
+        client.start();
+
+        client.handle(ev(req1, resp1)); // match:false filter:dunno chain:accept
+        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());
+    }
+
+    @Test
+    public void testModifyMessage() throws IOException {
+        HttpRequest req = HttpRequestBuilder
+                .post("http://test.com/path/test?uParam1=1", "param1=value1&param2=value2")
+                .header("Header1", "Header1Value1")
+                .header("Cookie", "myCookie1=myValue1;myCookie2=myValue2")
+                .build();
+
+        HttpMessageModificationFilter f = new HttpMessageModificationFilter();
+        f.addOperation(new SetHeaderOperation("Header1", "Header1Value1a"));
+        f.addOperation(new SetCookieOperation("myCookie1", "myValue1a"));
+        f.addOperation(new PostDataSetParamOperation("param1", "value1a"));
+        f.addOperation(new SetQueryParameterOperation("uParam1", "11"));
+        ConverterHttpClient client = client(f);
+
+        client.handle(ev(req, null));
+        HttpHeaders headers = req.getHeaders();
+        HttpParameters params = HttpMessageHelper.get().decodeFormUrlencoded(req);
+
+        assertEquals("/path/test?uParam1=11", req.getUri().toString());
+        assertEquals("Header1Value1a", headers.get("Header1").toString());
+        assertEquals("myCookie1=myValue1a;myCookie2=myValue2", headers.get("Cookie").toString());
+        assertEquals("param2=value2&param1=value1a", params.toString());
+    }
+
+    @Test
+    public void testDateRewriter_() {
+        HttpRequest req = HttpRequestBuilder.get("http://example.com/")
+                .header(HttpHeaders.DATE, "Wed, 09-Sep-2009 09:09:00 GMT")
+                .build();
+
+        HttpDateFilter f = new HttpDateFilter();
+        HttpDateFilterTest.setDate(f, 1500_000_000_000L);
+        ConverterHttpClient client = client(f);
+
+        client.handle(ev(req, null));
+        assertEquals(req.getHeaders().get(HttpHeaders.DATE).toString(), "Fri, 14 Jul 2017 02:40:00 GMT");
+    }
+
+    @Test
+    public void testHostRewriter() {
+        HttpRequest req = HttpRequestBuilder.get("http://example.com:8080/site1/resource1")
+                .header(HttpHeaders.ORIGIN, "http://example.com:8080/site1")
+                .header(HttpHeaders.REFERER, "http://example.com:8080/site1/index")
+                .build();
+
+        HttpHostRewriterFilter f = new HttpHostRewriterFilter();
+        f.setHostMap(map(e("example.com:8080", "example.org")));
+        ConverterHttpClient client = client(f);
+
+        client.handle(ev(req, null));
+
+        HttpHeaders headers = req.getHeaders();
+        assertEquals(headers.get(HttpHeaders.HOST).toString(), "example.org");
+        assertEquals(headers.get(HttpHeaders.ORIGIN).toString(), "http://example.org/site1");
+        assertEquals(headers.get(HttpHeaders.REFERER).toString(), "http://example.org/site1/index");
+    }
+
+    @Test
+    public void testHeaderCleaners() {
+        HttpRequest req = HttpRequestBuilder.get("http://www.example.com/abc")
+                .header(HttpHeaders.ACCEPT, "*/*;q=0.5")
+                .header(HttpHeaders.IF_MODIFIED_SINCE, "09 Sep 2009 09:09:00 GMT")
+                .header(HttpHeaders.X_FORWARDED_FOR, "15.16.73.33")
+                .build();
+        HttpResponse resp = HttpResponseBuilder.ok().build();
+
+        HttpFilter f1 = new HttpRequestCacheHeadersCleanerFilter();
+        HttpFilter f2 = new HttpRequestProxyHeadersCleanerFilter();
+        ConverterHttpClient client = client(f1, f2);
+
+        client.handle(ev(req, resp));
+        HttpHeaders headers = req.getHeaders();
+
+        assertTrue(headers.contains(HttpHeaders.ACCEPT));
+        assertFalse(headers.contains(HttpHeaders.IF_MODIFIED_SINCE));
+        assertFalse(headers.contains(HttpHeaders.X_FORWARDED_FOR));
+    }
+
+    @Test
+    public void testZone_() {
+        HttpRequest req = HttpRequestBuilder.get("http://test.com/test").build();
+        HttpResponse resp = HttpResponseBuilder.ok().build();
+        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{req.url: {$contains: test}}");
+
+        HttpZoneFilter f = new HttpZoneFilter();
+        f.addRule(new HttpZoneFilter.Rule("testZone", predicate));
+        ConverterHttpClient client = client(f);
+
+        client.handle(ev(req, resp));
+
+        assertEquals("testZone", req.getTag(TAG_ZONE));
+        assertEquals("testZone", resp.getTag(TAG_ZONE));
+    }
+
+    @Test
+    public void testMVEL() {
+        HttpRequest req = HttpRequestBuilder.get("http://example.com/index.html").build();
+
+        String expression = "$req.setMethod(com.passus.net.http.HttpMethod.HEAD);"
+                + "$req.getUri().toString().equals(\"/index.html\") ? 1 : 0";
+
+        HttpMvelFilter f = new HttpMvelFilter();
+        f.setStatement(HttpMvelFilterTest.es(expression));
+        f.setDirection(HttpFilterDirection.OUT);
+        ConverterHttpClient client = client(f);
+
+        client.handle(ev(req, null));
+
+        assertEquals(HttpMethod.HEAD, req.getMethod());
+    }
+
+    @Test
+    public void testMarker_() {
+        HttpRequest req = HttpRequestBuilder.get("http://test/test").build();
+
+        HttpMessagePredicate predicate = HttpFilterTestUtils.createPredicate("{req.url: {$contains: test}}");
+        HttpMarkFilter f = new HttpMarkFilter();
+        f.addRule(new HttpMarkFilter.MarkerRule("category1", predicate));
+        ConverterHttpClient client = client(f);
+
+        client.handle(ev(req, null));
+
+        List<HttpMarkFilter.Marker> markers = (List<HttpMarkFilter.Marker>) req.getTag(TAG_MARKER);
+        assertFalse(markers == null);
+        assertFalse(markers.isEmpty());
+        HttpMarkFilter.Marker marker = markers.get(0);
+
+        assertEquals("category1", marker.getCategory());
+    }
+}