Mercurial > stress-tester
changeset 472:cdff69867843
ST-48 (host req headers), ST-49 (Date req header)
author | Devel 1 |
---|---|
date | Fri, 04 Aug 2017 12:23:28 +0200 |
parents | 34545d3acba8 |
children | 629e5b412864 |
files | stress-tester/src/main/java/com/passus/st/client/http/filter/HttpDateFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpHostRewriterFilter.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpDateFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpHostRewriterFilterTest.java |
diffstat | 4 files changed, 376 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpDateFilter.java Fri Aug 04 12:23:28 2017 +0200 @@ -0,0 +1,41 @@ +package com.passus.st.client.http.filter; + +import com.passus.commons.annotations.Plugin; +import com.passus.commons.time.TimeGenerator; +import com.passus.data.ByteString; +import com.passus.net.http.HttpDateFormatter; +import com.passus.net.http.HttpHeaders; +import com.passus.net.http.HttpRequest; +import com.passus.net.http.HttpResponse; +import com.passus.st.client.http.HttpFlowContext; +import com.passus.st.plugin.PluginConstants; +import java.util.Date; + +@Plugin(name = HttpDateFilter.TYPE, category = PluginConstants.CATEGORY_HTTP_FILTER) +public class HttpDateFilter extends HttpFilter { + + public static final String TYPE = "date"; + + private TimeGenerator generator = TimeGenerator.getDefaultGenerator(); + + void setGenerator(TimeGenerator generator) { + this.generator = generator; + } + + @Override + public int filterOutbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) { + HttpHeaders headers = request.getHeaders(); + ByteString date = headers.get(HttpHeaders.DATE); + if (date != null) { + String dateString = HttpDateFormatter.format(new Date(generator.currentTimeMillis())); + headers.set(HttpHeaders.DATE, dateString); + } + return DUNNO; + } + + @Override + public HttpFilter instanceForWorker(int index) { + return new HttpDateFilter(); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpHostRewriterFilter.java Fri Aug 04 12:23:28 2017 +0200 @@ -0,0 +1,172 @@ +package com.passus.st.client.http.filter; + +import com.passus.commons.annotations.Plugin; +import com.passus.config.Configuration; +import com.passus.config.annotations.NodeDefinitionCreate; +import static com.passus.config.schema.ConfigurationSchemaBuilder.*; +import com.passus.config.schema.MappingNodeDefinition; +import com.passus.config.schema.NodeDefinition; +import com.passus.config.schema.NodeDefinitionCreator; +import com.passus.data.ByteString; +import com.passus.data.ByteStringBuilder; +import com.passus.data.ByteStringImpl; +import com.passus.data.ByteStringUtils; +import com.passus.net.http.HttpHeaders; +import com.passus.net.http.HttpRequest; +import com.passus.net.http.HttpResponse; +import com.passus.net.http.URL; +import com.passus.net.http.URLBuilder; +import com.passus.st.client.http.HttpFlowContext; +import com.passus.st.plugin.PluginConstants; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@NodeDefinitionCreate(HttpHostRewriterFilter.NodeDefCreator.class) +@Plugin(name = HttpHostRewriterFilter.TYPE, category = PluginConstants.CATEGORY_HTTP_FILTER) +public class HttpHostRewriterFilter extends HttpFilter { + + public static final String TYPE = "host"; + + private static final Logger LOGGER = LogManager.getLogger(HttpHostRewriterFilter.class); + + private final Map<ByteString, ByteString> hostMap = new HashMap<>(); + private final Map<HostPort, HostPort> urlMap = new HashMap<>(); + + public void setHostMap(Map<? extends CharSequence, ? extends CharSequence> map) { + hostMap.clear(); + urlMap.clear(); + for (Map.Entry<? extends CharSequence, ? extends CharSequence> e : map.entrySet()) { + ByteString key = ByteString.create(e.getKey()); + ByteString value = ByteString.create(e.getValue()); + hostMap.put(key, value); + urlMap.put(new HostPort(key), new HostPort(value)); + } + + } + + @Override + public void configure(Configuration config) { + Map map = (Map) config.get("hostMap", Collections.EMPTY_MAP); + setHostMap(map); + } + + @Override + public int filterOutbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) { + HttpHeaders headers = request.getHeaders(); + replaceHost(headers, HttpHeaders.HOST); + replaceUrl(headers, HttpHeaders.ORIGIN); + replaceUrl(headers, HttpHeaders.REFERER); + return DUNNO; + } + + @Override + public HttpFilter instanceForWorker(int index) { + return new HttpHostRewriterFilter(); + } + + private void replaceHost(HttpHeaders headers, ByteString headerName) { + ByteString headerValue = headers.get(headerName); + ByteString mappedValue = hostMap.get(headerValue); + if (mappedValue != null) { + headers.set(headerName, mappedValue); + } + } + + private void replaceUrl(HttpHeaders headers, ByteStringImpl headerName) { + ByteString headerValue = headers.get(headerName); + if (headerValue != null) { + try { + URL url = URL.parse(headerValue); + HostPort headerHostPort = new HostPort(url); + HostPort mappedHostPort = urlMap.get(headerHostPort); + if (mappedHostPort != null) { + URLBuilder builder = new URLBuilder(url); + builder.setHost(mappedHostPort.host); + builder.setPort(mappedHostPort.port); + URL mappedUrl = builder.build(); + ByteString mappedHeaderValue = mappedUrl.toByteString(); + headers.set(headerName, mappedHeaderValue); + } + } catch (Exception ex) { + LOGGER.debug("Cannot parse URL in header {}: {}", headerName, headerValue); + } + } + } + + private static ByteStringImpl bsImpl(ByteString bs) { + return (bs instanceof ByteStringImpl) ? (ByteStringImpl) bs : new ByteStringImpl(bs); + } + + static class HostPort { + + final ByteString host; + final int port; + + HostPort(URL url) { + this(url.getHost(), url.getPort()); + } + + HostPort(ByteString host, int port) { + this.host = bsImpl(host); + this.port = port; + } + + HostPort(ByteString hostPortString) { + int lastIndex = hostPortString.lastIndexOf(":"); + if (lastIndex >= 0) { + this.host = bsImpl(hostPortString.subSequence(0, lastIndex)); // workaround (equals vs SliceByteString) + this.port = ByteStringUtils.parseInt(hostPortString.subSequence(lastIndex + 1)); + } else { + this.host = bsImpl(hostPortString); // workaround (equals vs SliceByteString) + this.port = -1; + } + } + + public ByteString getHostPort() { + if (port == URL.PORT_UNSPECIFIED) { + return host; + } else { + ByteStringBuilder bsb = new ByteStringBuilder(); + bsb.append(host).append(URL.PORT_SEPARATOR).append(port); + return bsb.toByteString(); + } + } + + @Override + public int hashCode() { + return 89 * Objects.hashCode(this.host) + this.port; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof HostPort)) { + return false; + } + final HostPort other = (HostPort) obj; + return this.port == other.port && Objects.equals(this.host, other.host); + } + + @Override + public String toString() { + return "HostPort{" + hashCode() + "=" + getHostPort() + '}'; + } + } + + public static class NodeDefCreator implements NodeDefinitionCreator { + + @Override + public NodeDefinition create() { + return mapDef( + tupleDef("hostMap", new MappingNodeDefinition()) + ); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpDateFilterTest.java Fri Aug 04 12:23:28 2017 +0200 @@ -0,0 +1,29 @@ +package com.passus.st.client.http.filter; + +import com.passus.commons.time.CustomTimeGenerator; +import com.passus.net.http.HttpHeaders; +import com.passus.net.http.HttpRequest; +import com.passus.net.http.HttpRequestBuilder; +import static org.testng.Assert.*; +import org.testng.annotations.Test; + +/** + * + * @author mikolaj.podbielski + */ +public class HttpDateFilterTest { + + @Test + public void testFilterOutbound() { + HttpRequest req = HttpRequestBuilder.get("http://example.com/") + .header(HttpHeaders.DATE, "Wed, 09-Sep-2009 09:09:00 GMT") + .build(); + + HttpDateFilter filter = new HttpDateFilter(); + filter.setGenerator(new CustomTimeGenerator(1500_000_000_000L)); + + filter.filterOutbound(req, null, null); + assertEquals(req.getHeaders().get(HttpHeaders.DATE).toString(), "Fri, 14 Jul 2017 02:40:00 GMT"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpHostRewriterFilterTest.java Fri Aug 04 12:23:28 2017 +0200 @@ -0,0 +1,134 @@ +package com.passus.st.client.http.filter; + +import static com.passus.commons.collection.FluentBuilder.*; +import com.passus.config.validation.Errors; +import com.passus.data.ByteString; +import com.passus.net.http.HttpHeaders; +import static com.passus.net.http.HttpHeaders.*; +import com.passus.net.http.HttpRequest; +import com.passus.net.http.HttpRequestBuilder; +import com.passus.st.client.http.filter.HttpHostRewriterFilter.HostPort; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; +import static org.testng.AssertJUnit.*; +import org.testng.annotations.Test; + +/** + * + * @author mikolaj.podbielski + */ +public class HttpHostRewriterFilterTest { + + @Test + public void testFilterOutbound() { + Map<String, String> hostMap = map( + e("example.com", "mapped.com:8088"), + e("example.com:8080", "mapped.com") + ); + HttpHostRewriterFilter filter = new HttpHostRewriterFilter(); + filter.setHostMap(hostMap); + + HttpRequest req0 = request("http://wp.pl/site1/resource1", "http://wp.pl/site1", "http://wp.pl/site1/index"); + filter.filterOutbound(req0, null, null); + assertHeaderValues(req0, "wp.pl", "http://wp.pl/site1", "http://wp.pl/site1/index"); + + HttpRequest req1 = request("http://example.com/site1/resource1", "http://example.com/site1", "http://example.com/site1/index"); + filter.filterOutbound(req1, null, null); + assertHeaderValues(req1, "mapped.com:8088", "http://mapped.com:8088/site1", "http://mapped.com:8088/site1/index"); + + HttpRequest req2 = request("http://example.com:8080/site1/resource1", "http://example.com:8080/site1", "http://example.com:8080/site1/index"); + filter.filterOutbound(req2, null, null); + assertHeaderValues(req2, "mapped.com", "http://mapped.com/site1", "http://mapped.com/site1/index"); + } + + private static HttpRequest request(String url, String origin, String referer) { + return HttpRequestBuilder.get(url).header(ORIGIN, origin).header(REFERER, referer).build(); + } + + private static void assertHeaderValues(HttpRequest req, String host, String origin, String referer) { + HttpHeaders headers = req.getHeaders(); + assertEquals(headers.get(HOST).toString(), host); + assertEquals(headers.get(ORIGIN).toString(), origin); + assertEquals(headers.get(REFERER).toString(), referer); + } + + @Test + public void testHostPort() { + assertEquals(new HostPort(bs("abc.def"), -1).getHostPort().toString(), "abc.def"); + assertEquals(new HostPort(bs("abc.def"), 80).getHostPort().toString(), "abc.def:80"); + + HostPort hp1 = new HostPort(bs("abc.def")); + assertEquals(hp1.host.toString(), "abc.def"); + assertEquals(hp1.port, -1); + HostPort hp2 = new HostPort(bs("abc.def:80")); + assertEquals(hp2.host.toString(), "abc.def"); + assertEquals(hp2.port, 80); + + try { + HostPort hp = new HostPort(bs("abc:")); + fail(); + } catch (Exception ignore) { + } + try { + HostPort hp = new HostPort(bs(":")); + fail(); + } catch (Exception ignore) { + } + HostPort hp = new HostPort(bs(":80")); + assertEquals(hp.host.toString(), ""); + assertEquals(hp.port, 80); + } + + private static final Field hostMapField; + private static final Field urlMapField; + + static { + try { + hostMapField = HttpHostRewriterFilter.class.getDeclaredField("hostMap"); + hostMapField.setAccessible(true); + urlMapField = HttpHostRewriterFilter.class.getDeclaredField("urlMap"); + urlMapField.setAccessible(true); + } catch (Exception ex) { + throw new ExceptionInInitializerError(ex); + } + } + + @Test + public void testConfigure() throws Exception { + String filterConfig = "filters:\n" + + " - type: host\n" + + " hostMap:\n" + + " \"example.com\": \"mapped.com:8088\"\n" + + " \"example.com:8080\": \"mapped.com\"\n"; + + Errors errors = new Errors(); + List<HttpFilter> filters = HttpFiltersConfigurator.getFilters(filterConfig, errors); + + assertEquals(0, errors.getErrorCount()); + assertEquals(1, filters.size()); + assertTrue(filters.get(0) instanceof HttpHostRewriterFilter); + + HttpHostRewriterFilter filter = (HttpHostRewriterFilter) filters.get(0); + + Map<ByteString, ByteString> expectedHostMap = map( + e(bs("example.com"), bs("mapped.com:8088")), + e(bs("example.com:8080"), bs("mapped.com")) + ); + Map<HostPort, HostPort> expectedUrlMap = map( + e(hp("example.com", -1), hp("mapped.com", 8088)), + e(hp("example.com", 8080), hp("mapped.com", -1)) + ); + + assertEquals(expectedHostMap, hostMapField.get(filter)); + assertEquals(expectedUrlMap, urlMapField.get(filter)); + } + + private static ByteString bs(CharSequence cs) { + return ByteString.create(cs); + } + + private static HostPort hp(String h, int p) { + return new HostPort(bs(h), p); + } +}