diff --git a/.travis.yml b/.travis.yml
index 016ceb70b..a2b4446dc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,11 +1,9 @@
sudo: false
language: java
+dist: bionic
jdk:
- # Not running tests against openjdk7, since the SunEC is not included in travis-ci's version of openjdk7.
- # Not running tests against oraclejdk7, since travis-ci no longer provides it.
- # - openjdk7
- - oraclejdk8
+ - openjdk11
cache:
directories:
diff --git a/.whitesource b/.whitesource
new file mode 100644
index 000000000..d40db00ae
--- /dev/null
+++ b/.whitesource
@@ -0,0 +1,3 @@
+{
+ "settingsInheritedFrom": "hellofresh/whitesource-config@master"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index e932b282c..25ee51d33 100644
--- a/README.md
+++ b/README.md
@@ -144,7 +144,7 @@ Set a URL to blacklist | PUT | */proxy/[port]/blacklist* |
*regex* - The black
Clears all URL patterns from the blacklist | DELETE | */proxy/[port]/blacklist* ||
Limit the bandwidth through the proxy on the *[port]* | PUT | */proxy/[port]/limit* |
*downstreamKbps* - Sets the downstream bandwidth limit in kbps. Optional.
*upstreamKbps* - Sets the upstream bandwidth limit kbps. Optional, by default unlimited.
*downstreamMaxKB* - Specifies how many kilobytes in total the client is allowed to download through the proxy. Optional, by default unlimited.
*upstreamMaxKB* - Specifies how many kilobytes in total the client is allowed to upload through the proxy. Optional, by default unlimited.
*latency* - Add the given latency to each HTTP request. Optional, by default all requests are invoked without latency.
*enable* - A boolean that enable bandwidth limiter. Optional, by default to "false", but setting any of the properties above will implicitly enable throttling
*payloadPercentage* - Specifying what percentage of data sent is payload, e.g. use this to take into account overhead due to tcp/ip. Optional.
*maxBitsPerSecond* - The max bits per seconds you want this instance of StreamManager to respect. Optional.
Displays the amount of data remaining to be uploaded/downloaded until the limit is reached | GET | */proxy/[port]/limit* ||
-Set and override HTTP Request headers | POST | */proxy/[port]/headers* | Payload data should be **JSON** encoded set of headers. Where key is a header name (such as "User-Agent") and value is a value of HTTP header to setup (such as "BrowserMob-Agent"). Example: `{"User-Agent": "BrowserMob-Agent"}`|
+Set and override HTTP Request headers | POST | */proxy/[port]/headers* | Payload data should be **JSON** encoded set of headers and optionally `headersFilterRegexp: .*.*` . Where key is a header name (such as "User-Agent") and value is a value of HTTP header to setup (such as "BrowserMob-Agent"). Example: `{"User-Agent": "BrowserMob-Agent"}`|
Overrides normal DNS lookups and remaps the given hosts with the associated IP address | POST | */proxy/[port]/hosts* | Payload data should be **JSON** encoded set of hosts. Where key is a host name (such as "example.com") and value is a IP address which associatied with host hame (such as "1.2.3.4"'). Example: `{"example.com": "1.2.3.4"}`|
Sets automatic basic authentication for the specified domain | POST | */proxy/[port]/auth/basic/[domain]* | Payload data should be **JSON** encoded username and password name/value pairs. Example: `{"username": "myUsername", "password": "myPassword"}`|
Wait till all request are being made | PUT | */proxy/[port]/wait* |
*quietPeriodInMs* - Wait till all request are being made. Optional.
*timeoutInMs* - Sets quiet period in milliseconds. Optional.
|
@@ -190,6 +190,7 @@ system properties will be used to specify the upstream proxy.
- -proxyPortRange \-\
- Range of ports reserved for proxies. Only applies if *port* parameter is not supplied in the POST request. Default values are \+1 to \+500+1.
- -ttl \
+ - -maxResponseSizeBytes max size of response in bytes by default 2097152 (2 MB)
- Proxy will be automatically deleted after a specified time period. Off by default.
### Embedded Mode
@@ -395,7 +396,7 @@ When you build the latest code from source, you'll have access to the latest sna
net.lightbody.bmpbrowsermob-core
- 2.1.6-SNAPSHOT
+ 2.1.38test
```
diff --git a/browsermob-core/pom.xml b/browsermob-core/pom.xml
index 2071434ee..daa1d380a 100644
--- a/browsermob-core/pom.xml
+++ b/browsermob-core/pom.xml
@@ -1,11 +1,12 @@
-
+jarbrowsermob-proxynet.lightbody.bmp
- 2.1.6-SNAPSHOT
+ 2.1.384.0.0
@@ -13,7 +14,7 @@
BrowserMob Proxy Core (LittleProxy) Module
- 7.6.16.v20140903
+ 9.4.21.v20190926
@@ -41,7 +42,7 @@
org.apache.maven.pluginsmaven-surefire-plugin
- -Xmx1g -XX:MaxPermSize=256m
+ -Xmx1g
@@ -49,7 +50,7 @@
- net.lightbody.bmp
+ org.littleshootlittleproxy
@@ -68,6 +69,12 @@
jackson-core
+
+ co.elastic.logging
+ log4j2-ecs-layout
+
+
+
com.fasterxml.jackson.corejackson-databind
@@ -86,7 +93,7 @@
dnsjavadnsjava
- 2.1.8
+ 2.1.9
@@ -133,12 +140,24 @@
bcpkix-jdk15on
+
+ com.timgroup
+ java-statsd-client
+
+
net.lightbody.bmpmitm${project.version}
+
+
+ org.brotli
+ dec
+ 0.1.2
+
+
org.javassist
@@ -149,12 +168,10 @@
org.apache.logging.log4jlog4j-api
- testorg.apache.logging.log4jlog4j-core
- testorg.apache.logging.log4j
@@ -242,7 +259,12 @@
org.hamcrest
- hamcrest-library
+ hamcrest
+ test
+
+
+ org.apache.httpcomponents
+ httpclienttest
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxy.java b/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxy.java
index a04ffe7af..44f1ac326 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxy.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxy.java
@@ -39,7 +39,7 @@ public interface BrowserMobProxy {
* Starts the proxy on the specified port. The proxy will listen for connections on the network interface specified by the bindAddress, and will
* also initiate connections to upstream servers on the same network interface.
*
- * @param port port to listen on
+ * @param port port to listen on
* @param bindAddress address of the network interface on which the proxy will listen for connections and also attempt to connect to upstream servers.
* @throws java.lang.IllegalStateException if the proxy has already been started
*/
@@ -49,7 +49,7 @@ public interface BrowserMobProxy {
* Starts the proxy on the specified port. The proxy will listen for connections on the network interface specified by the clientBindAddress, and will
* initiate connections to upstream servers from the network interface specified by the serverBindAddress.
*
- * @param port port to listen on
+ * @param port port to listen on
* @param clientBindAddress address of the network interface on which the proxy will listen for connections
* @param serverBindAddress address of the network interface on which the proxy will connect to upstream servers
* @throws java.lang.IllegalStateException if the proxy has already been started
@@ -68,7 +68,7 @@ public interface BrowserMobProxy {
* @throws java.lang.IllegalStateException if the proxy has not been started.
*/
void stop();
-
+
/**
* Like {@link #stop()}, shuts down the proxy server and no longer accepts incoming connections, but does not wait for any existing
* network traffic to cease. Any existing connections to clients or to servers may be force-killed immediately.
@@ -125,7 +125,7 @@ public interface BrowserMobProxy {
/**
* Starts a new HAR file with the specified page name and page title. Enables HAR capture if it was not previously enabled.
*
- * @param initialPageRef initial page name of the new HAR file
+ * @param initialPageRef initial page name of the new HAR file
* @param initialPageTitle initial page title of the new HAR file
* @return existing HAR file, or null if none exists or HAR capture was disabled
*/
@@ -215,7 +215,7 @@ public interface BrowserMobProxy {
* Starts a new HAR page using the specified pageRef as the page name and the pageTitle as the page title. Populates the
* {@link net.lightbody.bmp.core.har.HarPageTimings#onLoad} value based on the amount of time the current page has been captured.
*
- * @param pageRef name of the new page
+ * @param pageRef name of the new page
* @param pageTitle title of the new page
* @return the HAR as it existed immediately after ending the current page
* @throws java.lang.IllegalStateException if HAR capture has not been enabled via {@link #newHar()} or {@link #newHar(String)}
@@ -258,7 +258,7 @@ public interface BrowserMobProxy {
* The minimum amount of time that will elapse between the time the proxy begins receiving a response from the server and the time the
* proxy begins sending the response to the client.
*
- * @param latency minimum latency, or 0 for no minimum
+ * @param latency minimum latency, or 0 for no minimum
* @param timeUnit TimeUnit for the latency
*/
void setLatency(long latency, TimeUnit timeUnit);
@@ -268,7 +268,7 @@ public interface BrowserMobProxy {
* specified time, the proxy will respond with an HTTP 502 Bad Gateway. The default value is 60 seconds.
*
* @param connectionTimeout maximum time to wait to establish a connection to a server, or 0 to wait indefinitely
- * @param timeUnit TimeUnit for the connectionTimeout
+ * @param timeUnit TimeUnit for the connectionTimeout
*/
void setConnectTimeout(int connectionTimeout, TimeUnit timeUnit);
@@ -279,7 +279,7 @@ public interface BrowserMobProxy {
* connection to the client may be closed abruptly. The default value is 60 seconds.
*
* @param idleConnectionTimeout maximum time to allow a connection to remain idle, or 0 to wait indefinitely.
- * @param timeUnit TimeUnit for the idleConnectionTimeout
+ * @param timeUnit TimeUnit for the idleConnectionTimeout
*/
void setIdleConnectionTimeout(int idleConnectionTimeout, TimeUnit timeUnit);
@@ -290,7 +290,7 @@ public interface BrowserMobProxy {
* connection to the client may be closed abruptly. The default value is 0 (wait indefinitely).
*
* @param requestTimeout maximum time to wait for an HTTP response, or 0 to wait indefinitely
- * @param timeUnit TimeUnit for the requestTimeout
+ * @param timeUnit TimeUnit for the requestTimeout
*/
void setRequestTimeout(int requestTimeout, TimeUnit timeUnit);
@@ -298,7 +298,7 @@ public interface BrowserMobProxy {
* Enables automatic authorization for the specified domain and auth type. Every request sent to the specified domain will contain the
* specified authorization information.
*
- * @param domain domain automatically send authorization information to
+ * @param domain domain automatically send authorization information to
* @param username authorization username
* @param password authorization password
* @param authType authorization type
@@ -340,7 +340,7 @@ public interface BrowserMobProxy {
* For example, the following rewrite rule:
*
*
* will match an HTTP request (but not HTTPS!) to www.yahoo.com or www.bing.com with exactly 1 query parameter,
* and replace it with a call to www.google.com with an 'originalDomain' query parameter, as well as the original query parameter.
*
@@ -353,7 +353,7 @@ public interface BrowserMobProxy {
* will result in the proxy making a request to:
*
*
- * @param urlPattern URL-matching regular expression
+ * @param urlPattern URL-matching regular expression
* @param replacementExpression an expression, which may optionally contain capture groups, which will replace any URL which matches urlPattern
*/
void rewriteUrl(String urlPattern, String replacementExpression);
@@ -410,8 +410,8 @@ public interface BrowserMobProxy {
*
* See {@link #blacklistRequests(String, int)} for details on the URL the urlPattern will match.
*
- * @param urlPattern URL-matching regular expression to blacklist
- * @param statusCode HTTP status code to return
+ * @param urlPattern URL-matching regular expression to blacklist
+ * @param statusCode HTTP status code to return
* @param httpMethodPattern regular expression matching a request's HTTP method
*/
void blacklistRequests(String urlPattern, int statusCode, String httpMethodPattern);
@@ -447,7 +447,7 @@ public interface BrowserMobProxy {
* whitelist response code.
*
* @param urlPatterns URL-matching regular expressions to whitelist; null or an empty collection will enable an empty whitelist
- * @param statusCode HTTP status code to return to clients when a URL matches a pattern
+ * @param statusCode HTTP status code to return to clients when a URL matches a pattern
*/
void whitelistRequests(Collection urlPatterns, int statusCode);
@@ -501,11 +501,18 @@ public interface BrowserMobProxy {
/**
* Adds a new HTTP header to every request. If the header already exists on the request, it will be replaced with the specified header.
*
- * @param name name of the header to add
+ * @param name name of the header to add
* @param value new header's value
*/
void addHeader(String name, String value);
+ /**
+ * Header filter regexp.
+ *
+ * @param headerFilterRegexp the header filter regexp
+ */
+ void headerFilterRegexp(String headerFilterRegexp);
+
/**
* Removes a header previously added with {@link #addHeader(String name, String value)}.
*
@@ -545,8 +552,8 @@ public interface BrowserMobProxy {
* for the quiet period within the specified timeout, otherwise returns false.
*
* @param quietPeriod amount of time after which network traffic will be considered "stopped"
- * @param timeout maximum amount of time to wait for network traffic to stop
- * @param timeUnit TimeUnit for the quietPeriod and timeout
+ * @param timeout maximum amount of time to wait for network traffic to stop
+ * @param timeUnit TimeUnit for the quietPeriod and timeout
* @return true if network traffic is stopped, otherwise false
*/
boolean waitForQuiescence(long quietPeriod, long timeout, TimeUnit timeUnit);
@@ -587,7 +594,7 @@ public interface BrowserMobProxy {
* {@link org.littleshoot.proxy.HttpFilters} instance (typically, a subclass of {@link org.littleshoot.proxy.HttpFiltersAdapter}).
* To disable or bypass a filter on a per-request basis, the filterRequest() method may return null.
*
- * @param filterFactory factory to generate HttpFilters
+ * @param filterFactory factory to generate HttpFilters
*/
void addLastHttpFilterFactory(HttpFiltersSource filterFactory);
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxyServer.java b/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxyServer.java
index d4ddc5543..0951594cb 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxyServer.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/BrowserMobProxyServer.java
@@ -4,7 +4,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.MapMaker;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import net.lightbody.bmp.client.ClientUtil;
@@ -12,48 +12,19 @@
import net.lightbody.bmp.core.har.HarLog;
import net.lightbody.bmp.core.har.HarNameVersion;
import net.lightbody.bmp.core.har.HarPage;
-import net.lightbody.bmp.filters.AddHeadersFilter;
-import net.lightbody.bmp.filters.AutoBasicAuthFilter;
-import net.lightbody.bmp.filters.BlacklistFilter;
-import net.lightbody.bmp.filters.BrowserMobHttpFilterChain;
-import net.lightbody.bmp.filters.HarCaptureFilter;
-import net.lightbody.bmp.filters.HttpConnectHarCaptureFilter;
-import net.lightbody.bmp.filters.HttpsHostCaptureFilter;
-import net.lightbody.bmp.filters.HttpsOriginalHostCaptureFilter;
-import net.lightbody.bmp.filters.LatencyFilter;
-import net.lightbody.bmp.filters.RegisterRequestFilter;
-import net.lightbody.bmp.filters.RequestFilter;
-import net.lightbody.bmp.filters.RequestFilterAdapter;
-import net.lightbody.bmp.filters.ResolvedHostnameCacheFilter;
-import net.lightbody.bmp.filters.ResponseFilter;
-import net.lightbody.bmp.filters.ResponseFilterAdapter;
-import net.lightbody.bmp.filters.RewriteUrlFilter;
-import net.lightbody.bmp.filters.UnregisterRequestFilter;
-import net.lightbody.bmp.filters.WhitelistFilter;
+import net.lightbody.bmp.filters.*;
import net.lightbody.bmp.mitm.KeyStoreFileCertificateSource;
import net.lightbody.bmp.mitm.TrustSource;
import net.lightbody.bmp.mitm.keys.ECKeyGenerator;
import net.lightbody.bmp.mitm.keys.RSAKeyGenerator;
import net.lightbody.bmp.mitm.manager.ImpersonatingMitmManager;
-import net.lightbody.bmp.proxy.ActivityMonitor;
-import net.lightbody.bmp.proxy.BlacklistEntry;
-import net.lightbody.bmp.proxy.CaptureType;
-import net.lightbody.bmp.proxy.RewriteRule;
-import net.lightbody.bmp.proxy.Whitelist;
+import net.lightbody.bmp.proxy.*;
import net.lightbody.bmp.proxy.auth.AuthType;
import net.lightbody.bmp.proxy.dns.AdvancedHostResolver;
import net.lightbody.bmp.proxy.dns.DelegatingHostResolver;
import net.lightbody.bmp.util.BrowserMobHttpUtil;
import net.lightbody.bmp.util.BrowserMobProxyUtil;
-import org.littleshoot.proxy.ChainedProxy;
-import org.littleshoot.proxy.ChainedProxyAdapter;
-import org.littleshoot.proxy.ChainedProxyManager;
-import org.littleshoot.proxy.HttpFilters;
-import org.littleshoot.proxy.HttpFiltersSource;
-import org.littleshoot.proxy.HttpFiltersSourceAdapter;
-import org.littleshoot.proxy.HttpProxyServer;
-import org.littleshoot.proxy.HttpProxyServerBootstrap;
-import org.littleshoot.proxy.MitmManager;
+import org.littleshoot.proxy.*;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import org.littleshoot.proxy.impl.ProxyUtils;
import org.littleshoot.proxy.impl.ThreadPoolConfiguration;
@@ -62,16 +33,7 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
@@ -183,6 +145,11 @@ public class BrowserMobProxyServer implements BrowserMobProxy {
*/
private volatile int connectTimeoutMs;
+ /**
+ * Regexp to check request url and inject headers if url match regexp.
+ */
+ private static String headersFilterRegexp;
+
/**
* The amount of time a connection to a server can remain idle while receiving data from the server.
*/
@@ -337,28 +304,25 @@ public int getMaximumResponseBufferSizeInBytes() {
// chained proxy after the proxy is started.
bootstrappedWithDefaultChainedProxy.set(true);
- bootstrap.withChainProxyManager(new ChainedProxyManager() {
- @Override
- public void lookupChainedProxies(HttpRequest httpRequest, Queue chainedProxies) {
- final InetSocketAddress upstreamProxy = upstreamProxyAddress;
- if (upstreamProxy != null) {
- chainedProxies.add(new ChainedProxyAdapter() {
- @Override
- public InetSocketAddress getChainedProxyAddress() {
- return upstreamProxy;
- }
-
- @Override
- public void filterRequest(HttpObject httpObject) {
- String chainedProxyAuth = chainedProxyCredentials;
- if (chainedProxyAuth != null) {
- if (httpObject instanceof HttpRequest) {
- HttpHeaders.addHeader((HttpRequest)httpObject, HttpHeaders.Names.PROXY_AUTHORIZATION, "Basic " + chainedProxyAuth);
- }
+ bootstrap.withChainProxyManager((httpRequest, chainedProxies) -> {
+ final InetSocketAddress upstreamProxy = upstreamProxyAddress;
+ if (upstreamProxy != null) {
+ chainedProxies.add(new ChainedProxyAdapter() {
+ @Override
+ public InetSocketAddress getChainedProxyAddress() {
+ return upstreamProxy;
+ }
+
+ @Override
+ public void filterRequest(HttpObject httpObject) {
+ String chainedProxyAuth = chainedProxyCredentials;
+ if (chainedProxyAuth != null) {
+ if (httpObject instanceof HttpRequest) {
+ ((HttpRequest) httpObject).headers().add(HttpHeaderNames.PROXY_AUTHORIZATION, "Basic " + chainedProxyAuth);
}
}
- });
- }
+ }
+ });
}
});
}
@@ -633,6 +597,11 @@ public void addHeaders(Map headers) {
this.additionalHeaders = newHeaders;
}
+ @Override
+ public void headerFilterRegexp(String headerFilterRegexp) {
+ this.headersFilterRegexp = headerFilterRegexp;
+ }
+
@Override
public void setLatency(long latency, TimeUnit timeUnit) {
this.latencyMs = (int) TimeUnit.MILLISECONDS.convert(latency, timeUnit);
@@ -934,7 +903,7 @@ public void addLastHttpFilterFactory(HttpFiltersSource filterFactory) {
*/
@Override
public void addResponseFilter(ResponseFilter filter) {
- addLastHttpFilterFactory(new ResponseFilterAdapter.FilterSource(filter));
+ addLastHttpFilterFactory(new ResponseFilterAdapter.FilterSource(filter, Integer.parseInt(System.getProperty("maxResponseSizeBytes", String.valueOf(ResponseFilterAdapter.FilterSource.DEFAULT_MAXIMUM_RESPONSE_BUFFER_SIZE)))));
}
/**
@@ -1093,8 +1062,8 @@ public HttpFilters filterRequest(HttpRequest originalRequest, ChannelHandlerCont
addHttpFilterFactory(new HttpFiltersSourceAdapter() {
@Override
- public HttpFilters filterRequest(HttpRequest originalRequest) {
- return new AddHeadersFilter(originalRequest, additionalHeaders);
+ public HttpFilters filterRequest(HttpRequest originalRequest,ChannelHandlerContext ctx) {
+ return new AddHeadersFilter(originalRequest,ctx, additionalHeaders, headersFilterRegexp);
}
});
@@ -1111,6 +1080,13 @@ public HttpFilters filterRequest(HttpRequest originalRequest, ChannelHandlerCont
return new UnregisterRequestFilter(originalRequest, ctx, activityMonitor);
}
});
+
+ addHttpFilterFactory(new HttpFiltersSourceAdapter() {
+ @Override
+ public HttpFilters filterRequest(HttpRequest originalRequest, ChannelHandlerContext ctx) {
+ return new StatsDMetricsFilter(originalRequest, ctx);
+ }
+ });
}
private int getMaximumRequestBufferSize() {
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarEntry.java b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarEntry.java
index 1864a78c7..5b6529322 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarEntry.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarEntry.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@@ -17,6 +18,8 @@ public class HarEntry {
private volatile HarCache cache = new HarCache();
private volatile HarTimings timings = new HarTimings();
private volatile String serverIPAddress;
+ @JsonProperty("time")
+ private volatile long time;
private volatile String connection;
private volatile String comment = "";
@@ -157,4 +160,10 @@ public String getConnection() {
public void setConnection(String connection) {
this.connection = connection;
}
+
+ public HarEntry setTime(long time) {
+ this.time = time;
+ return this;
+ }
+
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarLog.java b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarLog.java
index 879e071f3..c7a6d1ef5 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarLog.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarLog.java
@@ -10,8 +10,8 @@ public class HarLog {
private final String version = "1.2";
private volatile HarNameVersion creator;
private volatile HarNameVersion browser;
- private final List pages = new CopyOnWriteArrayList();
- private final List entries = new CopyOnWriteArrayList();
+ private final List pages = new CopyOnWriteArrayList<>();
+ private final List entries = new CopyOnWriteArrayList<>();
private volatile String comment = "";
public HarLog() {
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarRequest.java b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarRequest.java
index 2cfe68957..4e549ad77 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarRequest.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarRequest.java
@@ -1,6 +1,8 @@
package net.lightbody.bmp.core.har;
import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -10,9 +12,9 @@ public class HarRequest {
private volatile String method;
private volatile String url;
private volatile String httpVersion;
- private final List cookies = new CopyOnWriteArrayList();
- private final List headers = new CopyOnWriteArrayList();
- private final List queryString = new CopyOnWriteArrayList();
+ private final List cookies = new CopyOnWriteArrayList<>();
+ private final List headers = new CopyOnWriteArrayList<>();
+ private final List queryString = new CopyOnWriteArrayList<>();
private volatile HarPostData postData;
private volatile long headersSize; // Odd grammar in spec
private volatile long bodySize;
@@ -95,4 +97,41 @@ public void setComment(String comment) {
this.comment = comment;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (o == null || getClass() != o.getClass()) return false;
+
+ HarRequest that = (HarRequest) o;
+
+ return new EqualsBuilder()
+ .append(headersSize, that.headersSize)
+ .append(bodySize, that.bodySize)
+ .append(method, that.method)
+ .append(url, that.url)
+ .append(httpVersion, that.httpVersion)
+ .append(cookies, that.cookies)
+ .append(headers, that.headers)
+ .append(queryString, that.queryString)
+ .append(postData, that.postData)
+ .append(comment, that.comment)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(method)
+ .append(url)
+ .append(httpVersion)
+ .append(cookies)
+ .append(headers)
+ .append(queryString)
+ .append(postData)
+ .append(headersSize)
+ .append(bodySize)
+ .append(comment)
+ .toHashCode();
+ }
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarResponse.java b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarResponse.java
index f82f248dd..b0e562a3b 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarResponse.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarResponse.java
@@ -11,8 +11,8 @@ public class HarResponse {
private volatile int status;
private volatile String statusText;
private volatile String httpVersion;
- private final List cookies = new CopyOnWriteArrayList();
- private final List headers = new CopyOnWriteArrayList();
+ private final List cookies = new CopyOnWriteArrayList<>();
+ private final List headers = new CopyOnWriteArrayList<>();
private final HarContent content = new HarContent();
private volatile String redirectURL = "";
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarTimings.java b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarTimings.java
index efb8d8612..3849baf4b 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarTimings.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/core/har/HarTimings.java
@@ -1,15 +1,24 @@
package net.lightbody.bmp.core.har;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
import java.util.concurrent.TimeUnit;
public class HarTimings {
// optional values are initialized to -1, which indicates they do not apply to the current request, according to the HAR spec
+ @JsonProperty("blocked")
private volatile long blockedNanos = -1;
+ @JsonProperty("dns")
private volatile long dnsNanos = -1;
+ @JsonProperty("connect")
private volatile long connectNanos = -1;
+ @JsonProperty("send")
private volatile long sendNanos;
+ @JsonProperty("wait")
private volatile long waitNanos;
+ @JsonProperty("receive")
private volatile long receiveNanos;
+ @JsonProperty("ssl")
private volatile long sslNanos = -1;
private volatile String comment = "";
@@ -49,7 +58,7 @@ public long getDns(TimeUnit timeUnit) {
public void setDns(long dns, TimeUnit timeUnit) {
if (dns == -1) {
this.dnsNanos = -1;
- } else{
+ } else {
this.dnsNanos = TimeUnit.NANOSECONDS.convert(dns, timeUnit);
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/AddHeadersFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/AddHeadersFilter.java
index 5b584ecfd..16bdccc72 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/AddHeadersFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/AddHeadersFilter.java
@@ -1,9 +1,10 @@
package net.lightbody.bmp.filters;
+import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
-import org.littleshoot.proxy.HttpFiltersAdapter;
+import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.Map;
@@ -12,29 +13,48 @@
* Adds the headers specified in the constructor to this request. The filter does not make a defensive copy of the map, so there is no guarantee
* that the map at the time of construction will contain the same values when the filter is actually invoked, if the map is modified concurrently.
*/
-public class AddHeadersFilter extends HttpFiltersAdapter {
+public class AddHeadersFilter extends HttpsAwareFiltersAdapter {
private final Map additionalHeaders;
+ private static String headersSpecificFilter;
- public AddHeadersFilter(HttpRequest originalRequest, Map additionalHeaders) {
- super(originalRequest);
+ public AddHeadersFilter(HttpRequest originalRequest, ChannelHandlerContext ctx, Map additionalHeaders, String headersSpecificFilter) {
+ super(originalRequest, ctx);
if (additionalHeaders != null) {
this.additionalHeaders = additionalHeaders;
} else {
this.additionalHeaders = Collections.emptyMap();
}
+ if (StringUtils.isNotEmpty(headersSpecificFilter)) {
+ setHeadersSpecificFilter(headersSpecificFilter);
+ }
}
@Override
public HttpResponse clientToProxyRequest(HttpObject httpObject) {
if (httpObject instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest) httpObject;
-
- for (Map.Entry header : additionalHeaders.entrySet()) {
- httpRequest.headers().add(header.getKey(), header.getValue());
+ if (StringUtils.isNotEmpty(headersSpecificFilter)) {
+ if (getFullUrl(httpRequest).matches(headersSpecificFilter)) {
+ for (Map.Entry header : additionalHeaders.entrySet()) {
+ httpRequest.headers().add(header.getKey(), header.getValue());
+ }
+ }
+ } else {
+ for (Map.Entry header : additionalHeaders.entrySet()) {
+ httpRequest.headers().add(header.getKey(), header.getValue());
+ }
}
}
return null;
}
+
+ public String getHeadersSpecificFilter() {
+ return headersSpecificFilter;
+ }
+
+ private synchronized void setHeadersSpecificFilter(String headersSpecificFilter) {
+ this.headersSpecificFilter = headersSpecificFilter;
+ }
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/AutoBasicAuthFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/AutoBasicAuthFilter.java
index 758f9bfaa..4cc840d97 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/AutoBasicAuthFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/AutoBasicAuthFilter.java
@@ -1,10 +1,7 @@
package net.lightbody.bmp.filters;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.*;
import org.littleshoot.proxy.impl.ProxyUtils;
import java.util.Map;
@@ -45,7 +42,7 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
// if there is an entry in the credentials map matching this hostname, add the credentials to the request
String base64CredentialsForHostname = credentialsByHostname.get(hostname);
if (base64CredentialsForHostname != null) {
- httpRequest.headers().add(HttpHeaders.Names.AUTHORIZATION, "Basic " + base64CredentialsForHostname);
+ httpRequest.headers().add(HttpHeaderNames.AUTHORIZATION, "Basic " + base64CredentialsForHostname);
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/BlacklistFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/BlacklistFilter.java
index b267673e1..0eef83d36 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/BlacklistFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/BlacklistFilter.java
@@ -1,13 +1,7 @@
package net.lightbody.bmp.filters;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.DefaultFullHttpResponse;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpMethod;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.proxy.BlacklistEntry;
import java.util.Collection;
@@ -38,15 +32,15 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
String url = getFullUrl(httpRequest);
for (BlacklistEntry entry : blacklistedUrls) {
- if (HttpMethod.CONNECT.equals(httpRequest.getMethod()) && entry.getHttpMethodPattern() == null) {
+ if (HttpMethod.CONNECT.equals(httpRequest.method()) && entry.getHttpMethodPattern() == null) {
// do not allow CONNECTs to be blacklisted unless a method pattern is explicitly specified
continue;
}
- if (entry.matches(url, httpRequest.getMethod().name())) {
+ if (entry.matches(url, httpRequest.method().name())) {
HttpResponseStatus status = HttpResponseStatus.valueOf(entry.getStatusCode());
- HttpResponse resp = new DefaultFullHttpResponse(httpRequest.getProtocolVersion(), status);
- HttpHeaders.setContentLength(resp, 0L);
+ HttpResponse resp = new DefaultFullHttpResponse(httpRequest.protocolVersion(), status);
+ HttpUtil.setContentLength(resp, 0L);
return resp;
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/BrowserMobHttpFilterChain.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/BrowserMobHttpFilterChain.java
index 6ddf1331f..b7c11044e 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/BrowserMobHttpFilterChain.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/BrowserMobHttpFilterChain.java
@@ -1,12 +1,7 @@
package net.lightbody.bmp.filters;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.DefaultFullHttpResponse;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.BrowserMobProxyServer;
import org.littleshoot.proxy.HttpFilters;
import org.littleshoot.proxy.HttpFiltersAdapter;
@@ -54,9 +49,9 @@ public BrowserMobHttpFilterChain(BrowserMobProxyServer proxyServer, HttpRequest
@Override
public HttpResponse clientToProxyRequest(HttpObject httpObject) {
if (proxyServer.isStopped()) {
- log.warn("Aborting request to {} because proxy is stopped", originalRequest.getUri());
- HttpResponse abortedResponse = new DefaultFullHttpResponse(originalRequest.getProtocolVersion(), HttpResponseStatus.SERVICE_UNAVAILABLE);
- HttpHeaders.setContentLength(abortedResponse, 0L);
+ log.warn("Aborting request to {} because proxy is stopped", originalRequest.uri());
+ HttpResponse abortedResponse = new DefaultFullHttpResponse(originalRequest.protocolVersion(), HttpResponseStatus.SERVICE_UNAVAILABLE);
+ HttpUtil.setContentLength(abortedResponse, 0L);
return abortedResponse;
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/ClientRequestCaptureFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/ClientRequestCaptureFilter.java
index d6bd1b58c..3315c0640 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/ClientRequestCaptureFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/ClientRequestCaptureFilter.java
@@ -2,12 +2,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.HttpContent;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.LastHttpContent;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.util.BrowserMobHttpUtil;
import org.littleshoot.proxy.HttpFiltersAdapter;
@@ -60,7 +55,7 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
if (httpContent instanceof LastHttpContent) {
LastHttpContent lastHttpContent = (LastHttpContent) httpContent;
- trailingHeaders = lastHttpContent .trailingHeaders();
+ trailingHeaders = lastHttpContent.trailingHeaders();
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HarCaptureFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HarCaptureFilter.java
index ca8c044c2..e4aa0a582 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HarCaptureFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HarCaptureFilter.java
@@ -2,9 +2,13 @@
import com.google.common.collect.ImmutableList;
import com.google.common.io.BaseEncoding;
+import com.timgroup.statsd.NonBlockingStatsDClient;
+import com.timgroup.statsd.StatsDClient;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpContent;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
@@ -26,10 +30,12 @@
import net.lightbody.bmp.filters.support.HttpConnectTiming;
import net.lightbody.bmp.filters.util.HarCaptureUtil;
import net.lightbody.bmp.proxy.CaptureType;
+import net.lightbody.bmp.util.BeansJsonMapper;
import net.lightbody.bmp.util.BrowserMobHttpUtil;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.message.StringMapMessage;
import org.littleshoot.proxy.impl.ProxyUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -40,12 +46,20 @@
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import static net.lightbody.bmp.filters.StatsDMetricsFilter.getProxyPrefix;
+import static net.lightbody.bmp.filters.StatsDMetricsFilter.getStatsDHost;
+import static net.lightbody.bmp.filters.StatsDMetricsFilter.getStatsDPort;
+import static net.lightbody.bmp.filters.StatsDMetricsFilter.prepareMetric;
+
public class HarCaptureFilter extends HttpsAwareFiltersAdapter {
- private static final Logger log = LoggerFactory.getLogger(HarCaptureFilter.class);
+ private static final Logger log = LogManager.getLogger(HarCaptureFilter.class);
+
+ private static final InheritableThreadLocal isAlreadyLoggedIn = new InheritableThreadLocal<>();
/**
* The currently active HAR at the time the current request is received.
@@ -123,16 +137,16 @@ public class HarCaptureFilter extends HttpsAwareFiltersAdapter {
*
* Regardless of the CaptureTypes specified in dataToCapture, the HarCaptureFilter will always capture:
*
- *
Request and response sizes
- *
HTTP request and status lines
- *
Page timing information
+ *
Request and response sizes
+ *
HTTP request and status lines
+ *
Page timing information
*
*
* @param originalRequest the original HttpRequest from the HttpFiltersSource factory
- * @param har a reference to the ProxyServer's current HAR file at the time this request is received (can be null if HAR capture is not required)
- * @param currentPageRef the ProxyServer's currentPageRef at the time this request is received from the client
- * @param dataToCapture the data types to capture for this request. null or empty set indicates only basic information will be
- * captured (see {@link net.lightbody.bmp.proxy.CaptureType} for information on data collected for each CaptureType)
+ * @param har a reference to the ProxyServer's current HAR file at the time this request is received (can be null if HAR capture is not required)
+ * @param currentPageRef the ProxyServer's currentPageRef at the time this request is received from the client
+ * @param dataToCapture the data types to capture for this request. null or empty set indicates only basic information will be
+ * captured (see {@link net.lightbody.bmp.proxy.CaptureType} for information on data collected for each CaptureType)
*/
public HarCaptureFilter(HttpRequest originalRequest, ChannelHandlerContext ctx, Har har, String currentPageRef, Set dataToCapture) {
super(originalRequest, ctx);
@@ -269,7 +283,7 @@ public HttpObject serverToProxyResponse(HttpObject httpObject) {
harEntry.getResponse().setBodySize(responseBodySize.get());
}
-
+ logFailedRequestIfRequired(harEntry.getRequest(), harEntry.getResponse());
return super.serverToProxyResponse(httpObject);
}
@@ -297,6 +311,13 @@ else if (sendFinishedNanos > 0L && responseReceiveStartedNanos == 0L) {
else if (responseReceiveStartedNanos > 0L) {
harEntry.getTimings().setReceive(timeoutTimestampNanos - responseReceiveStartedNanos, TimeUnit.NANOSECONDS);
}
+
+ StatsDClient client = createStatsDClient();
+ client.increment(getProxyPrefix().concat(prepareMetric(harEntry.getRequest().getUrl()))
+ .concat("." + harEntry.getResponse().getStatus()).concat(".response_timeout"));
+ client.stop();
+
+ logFailedRequestIfRequired(harEntry.getRequest(), harEntry.getResponse());
}
/**
@@ -312,7 +333,7 @@ private HarRequest createHarRequestForHttpRequest(HttpRequest httpRequest) {
// the full URL consists of the scheme + host + port (if non-standard) + path + query params + fragment.
String url = getFullUrl(httpRequest);
- return new HarRequest(httpRequest.getMethod().toString(), url, httpRequest.getProtocolVersion().text());
+ return new HarRequest(httpRequest.method().toString(), url, httpRequest.protocolVersion().text());
}
//TODO: add unit tests for these utility-like capture() methods
@@ -320,7 +341,7 @@ private HarRequest createHarRequestForHttpRequest(HttpRequest httpRequest) {
protected void captureQueryParameters(HttpRequest httpRequest) {
// capture query parameters. it is safe to assume the query string is UTF-8, since it "should" be in US-ASCII (a subset of UTF-8),
// but sometimes does include UTF-8 characters.
- QueryStringDecoder queryStringDecoder = new QueryStringDecoder(httpRequest.getUri(), StandardCharsets.UTF_8);
+ QueryStringDecoder queryStringDecoder = new QueryStringDecoder(httpRequest.uri(), StandardCharsets.UTF_8);
try {
for (Map.Entry> entry : queryStringDecoder.parameters().entrySet()) {
@@ -331,13 +352,13 @@ protected void captureQueryParameters(HttpRequest httpRequest) {
} catch (IllegalArgumentException e) {
// QueryStringDecoder will throw an IllegalArgumentException if it cannot interpret a query string. rather than cause the entire request to
// fail by propagating the exception, simply skip the query parameter capture.
- harEntry.setComment("Unable to decode query parameters on URI: " + httpRequest.getUri());
- log.info("Unable to decode query parameters on URI: " + httpRequest.getUri(), e);
+ harEntry.setComment("Unable to decode query parameters on URI: " + httpRequest.uri());
+ log.info("Unable to decode query parameters on URI: " + httpRequest.uri(), e);
}
}
protected void captureRequestHeaderSize(HttpRequest httpRequest) {
- String requestLine = httpRequest.getMethod().toString() + ' ' + httpRequest.getUri() + ' ' + httpRequest.getProtocolVersion().toString();
+ String requestLine = httpRequest.method().toString() + ' ' + httpRequest.uri() + ' ' + httpRequest.protocolVersion().toString();
// +2 => CRLF after status line, +4 => header/data separation
long requestHeadersSize = requestLine.length() + 6;
@@ -348,7 +369,7 @@ protected void captureRequestHeaderSize(HttpRequest httpRequest) {
}
protected void captureRequestCookies(HttpRequest httpRequest) {
- String cookieHeader = httpRequest.headers().get(HttpHeaders.Names.COOKIE);
+ String cookieHeader = httpRequest.headers().get(HttpHeaderNames.COOKIE);
if (cookieHeader == null) {
return;
}
@@ -388,9 +409,9 @@ protected void captureRequestContent(HttpRequest httpRequest, byte[] fullMessage
return;
}
- String contentType = HttpHeaders.getHeader(httpRequest, HttpHeaders.Names.CONTENT_TYPE);
+ String contentType = httpRequest.headers().get(HttpHeaderNames.CONTENT_TYPE);
if (contentType == null) {
- log.warn("No content type specified in request to {}. Content will be treated as {}", httpRequest.getUri(), BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE);
+ log.warn("No content type specified in request to {}. Content will be treated as {}", httpRequest.uri(), BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE);
contentType = BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE;
}
@@ -400,24 +421,20 @@ protected void captureRequestContent(HttpRequest httpRequest, byte[] fullMessage
postData.setMimeType(contentType);
boolean urlEncoded;
- if (contentType.startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED)) {
- urlEncoded = true;
- } else {
- urlEncoded = false;
- }
+ urlEncoded = contentType.startsWith(HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED.toString());
Charset charset;
try {
- charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentType);
+ charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentType);
} catch (UnsupportedCharsetException e) {
- log.warn("Found unsupported character set in Content-Type header '{}' in HTTP request to {}. Content will not be captured in HAR.", contentType, httpRequest.getUri(), e);
+ log.warn("Found unsupported character set in Content-Type header '{}' in HTTP request to {}. Content will not be captured in HAR.", contentType, httpRequest.uri(), e);
return;
}
if (charset == null) {
// no charset specified, so use the default -- but log a message since this might not encode the data correctly
charset = BrowserMobHttpUtil.DEFAULT_HTTP_CHARSET;
- log.debug("No charset specified; using charset {} to decode contents to {}", charset, httpRequest.getUri());
+ log.debug("No charset specified; using charset {} to decode contents to {}", charset, httpRequest.uri());
}
if (urlEncoded) {
@@ -447,9 +464,9 @@ protected void captureResponseContent(HttpResponse httpResponse, byte[] fullMess
// force binary if the content encoding is not supported
boolean forceBinary = false;
- String contentType = HttpHeaders.getHeader(httpResponse, HttpHeaders.Names.CONTENT_TYPE);
+ String contentType = httpResponse.headers().get(HttpHeaderNames.CONTENT_TYPE);
if (contentType == null) {
- log.warn("No content type specified in response from {}. Content will be treated as {}", originalRequest.getUri(), BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE);
+ log.warn("No content type specified in response from {}. Content will be treated as {}", originalRequest.uri(), BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE);
contentType = BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE;
}
@@ -463,14 +480,14 @@ protected void captureResponseContent(HttpResponse httpResponse, byte[] fullMess
try {
charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentType);
} catch (UnsupportedCharsetException e) {
- log.warn("Found unsupported character set in Content-Type header '{}' in HTTP response from {}. Content will not be captured in HAR.", contentType, originalRequest.getUri(), e);
+ log.warn("Found unsupported character set in Content-Type header '{}' in HTTP response from {}. Content will not be captured in HAR.", contentType, originalRequest.uri(), e);
return;
}
if (charset == null) {
// no charset specified, so use the default -- but log a message since this might not encode the data correctly
charset = BrowserMobHttpUtil.DEFAULT_HTTP_CHARSET;
- log.debug("No charset specified; using charset {} to decode contents from {}", charset, originalRequest.getUri());
+ log.debug("No charset specified; using charset {} to decode contents from {}", charset, originalRequest.uri());
}
if (!forceBinary && BrowserMobHttpUtil.hasTextualContent(contentType)) {
@@ -485,7 +502,7 @@ protected void captureResponseContent(HttpResponse httpResponse, byte[] fullMess
}
protected void captureResponse(HttpResponse httpResponse) {
- HarResponse response = new HarResponse(httpResponse.getStatus().code(), httpResponse.getStatus().reasonPhrase(), httpResponse.getProtocolVersion().text());
+ HarResponse response = new HarResponse(httpResponse.status().code(), httpResponse.status().reasonPhrase(), httpResponse.protocolVersion().text());
harEntry.setResponse(response);
captureResponseHeaderSize(httpResponse);
@@ -506,7 +523,7 @@ protected void captureResponse(HttpResponse httpResponse) {
}
protected void captureResponseMimeType(HttpResponse httpResponse) {
- String contentType = HttpHeaders.getHeader(httpResponse, HttpHeaders.Names.CONTENT_TYPE);
+ String contentType = httpResponse.headers().get(HttpHeaderNames.CONTENT_TYPE);
// don't set the mimeType to null, since mimeType is a required field
if (contentType != null) {
harEntry.getResponse().getContent().setMimeType(contentType);
@@ -514,7 +531,7 @@ protected void captureResponseMimeType(HttpResponse httpResponse) {
}
protected void captureResponseCookies(HttpResponse httpResponse) {
- List setCookieHeaders = httpResponse.headers().getAll(HttpHeaders.Names.SET_COOKIE);
+ List setCookieHeaders = httpResponse.headers().getAll(HttpHeaderNames.SET_COOKIE);
if (setCookieHeaders == null) {
return;
}
@@ -552,7 +569,7 @@ protected void captureResponseCookies(HttpResponse httpResponse) {
}
protected void captureResponseHeaderSize(HttpResponse httpResponse) {
- String statusLine = httpResponse.getProtocolVersion().toString() + ' ' + httpResponse.getStatus().toString();
+ String statusLine = httpResponse.protocolVersion().toString() + ' ' + httpResponse.status().toString();
// +2 => CRLF after status line, +4 => header/data separation
long responseHeadersSize = statusLine.length() + 6;
HttpHeaders headers = httpResponse.headers();
@@ -569,7 +586,7 @@ protected void captureResponseHeaders(HttpResponse httpResponse) {
}
protected void captureRedirectUrl(HttpResponse httpResponse) {
- String locationHeaderValue = HttpHeaders.getHeader(httpResponse, HttpHeaders.Names.LOCATION);
+ String locationHeaderValue = httpResponse.headers().get(HttpHeaderNames.LOCATION);
if (locationHeaderValue != null) {
harEntry.getResponse().setRedirectURL(locationHeaderValue);
}
@@ -629,7 +646,7 @@ protected void populateAddressFromCache(HttpRequest httpRequest) {
log.trace("Unable to find cached IP address for host: {}. IP address in HAR entry will be blank.", serverHost);
}
} else {
- log.warn("Unable to identify host from request uri: {}", httpRequest.getUri());
+ log.warn("Unable to identify host from request uri: {}", httpRequest.uri());
}
}
@@ -658,6 +675,12 @@ public void proxyToServerResolutionFailed(String hostAndPort) {
if (dnsResolutionStartedNanos > 0L) {
harEntry.getTimings().setDns(System.nanoTime() - dnsResolutionStartedNanos, TimeUnit.NANOSECONDS);
}
+
+ StatsDClient client = createStatsDClient();
+ client.increment(getProxyPrefix().concat(prepareMetric(harEntry.getRequest().getUrl()))
+ .concat("." + harEntry.getResponse().getStatus()).concat(".server_resolution_fail"));
+ client.stop();
+ logFailedRequestIfRequired(harEntry.getRequest(), harEntry.getResponse());
}
@Override
@@ -692,6 +715,7 @@ public void proxyToServerConnectionStarted() {
@Override
public void proxyToServerConnectionFailed() {
HarResponse response = HarCaptureUtil.createHarResponseForFailure();
+
harEntry.setResponse(response);
response.setError(HarCaptureUtil.getConnectionFailedErrorMessage());
@@ -700,6 +724,11 @@ public void proxyToServerConnectionFailed() {
if (connectionStartedNanos > 0L) {
harEntry.getTimings().setConnect(System.nanoTime() - connectionStartedNanos, TimeUnit.NANOSECONDS);
}
+
+ StatsDClient client = createStatsDClient();
+ client.increment(getProxyPrefix().concat(prepareMetric(harEntry.getRequest().getUrl()))
+ .concat("." + harEntry.getResponse().getStatus()).concat(".server_connection_fail"));
+ client.stop();
}
@Override
@@ -763,4 +792,24 @@ public void serverToProxyResponseReceived() {
harEntry.getTimings().setReceive(0L, TimeUnit.NANOSECONDS);
}
}
+
+ protected static void logFailedRequestIfRequired(HarRequest request, HarResponse response) {
+ if ((Objects.isNull(isAlreadyLoggedIn.get()) ||
+ isAlreadyLoggedIn.get().hashCode() != request.hashCode())
+ && (response.getStatus() >= 500 || response.getStatus() == 0)) {
+ log.error(new StringMapMessage()
+ .with("message", "received bad status code")
+ .with("caller", "mobproxy")
+ .with("http_response_code", String.valueOf(response.getStatus()))
+ .with("http_host", request.getUrl())
+ .with("request_details", BeansJsonMapper.getJsonString(request))
+ .with("method", request.getMethod())
+ .with("response", BeansJsonMapper.getJsonString(response)));
+ isAlreadyLoggedIn.set(request);
+ }
+ }
+
+ private StatsDClient createStatsDClient() {
+ return new NonBlockingStatsDClient("automated_tests", getStatsDHost(), getStatsDPort());
+ }
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpConnectHarCaptureFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpConnectHarCaptureFilter.java
index 1717370a2..de4829a67 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpConnectHarCaptureFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpConnectHarCaptureFilter.java
@@ -5,11 +5,7 @@
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
-import net.lightbody.bmp.core.har.Har;
-import net.lightbody.bmp.core.har.HarEntry;
-import net.lightbody.bmp.core.har.HarRequest;
-import net.lightbody.bmp.core.har.HarResponse;
-import net.lightbody.bmp.core.har.HarTimings;
+import net.lightbody.bmp.core.har.*;
import net.lightbody.bmp.filters.support.HttpConnectTiming;
import net.lightbody.bmp.filters.util.HarCaptureUtil;
import net.lightbody.bmp.util.HttpUtil;
@@ -31,7 +27,6 @@
* static methods. This filter also handles HTTP CONNECT errors and creates HAR entries for those errors, since there
* would otherwise not be any record in the HAR of the error (if the CONNECT fails, there will be no subsequent "real"
* request in which to record the error).
- *
*/
public class HttpConnectHarCaptureFilter extends HttpsAwareFiltersAdapter implements ModifiedRequestAwareFilter {
private static final Logger log = LoggerFactory.getLogger(HttpConnectHarCaptureFilter.class);
@@ -104,7 +99,7 @@ public class HttpConnectHarCaptureFilter extends HttpsAwareFiltersAdapter implem
/**
* Stores SSL connection timing information from HTTP CONNNECT requests. This timing information is stored in the first HTTP request
* after the CONNECT, not in the CONNECT itself, so it needs to be stored across requests.
- *
+ *
* This is the only state stored across multiple requests.
*/
private static final ConcurrentMap httpConnectTimes =
@@ -159,6 +154,7 @@ public void proxyToServerResolutionFailed(String hostAndPort) {
harEntry.getTimings().setDns(System.nanoTime() - dnsResolutionStartedNanos, TimeUnit.NANOSECONDS);
}
+ HarCaptureFilter.logFailedRequestIfRequired(harEntry.getRequest(), harEntry.getResponse());
httpConnectTimes.remove(clientAddress);
}
@@ -219,6 +215,7 @@ else if (sendFinishedNanos > 0L && responseReceiveStartedNanos == 0L) {
else if (responseReceiveStartedNanos > 0L) {
harEntry.getTimings().setReceive(timeoutTimestampNanos - responseReceiveStartedNanos, TimeUnit.NANOSECONDS);
}
+ HarCaptureFilter.logFailedRequestIfRequired(harEntry.getRequest(), harEntry.getResponse());
}
@Override
@@ -337,7 +334,6 @@ private HarEntry createHarEntryForFailedCONNECT(String errorMessage) {
populateServerIpAddress(harEntry);
-
return harEntry;
}
@@ -358,7 +354,7 @@ private void populateServerIpAddress(HarEntry harEntry) {
log.trace("Unable to find cached IP address for host: {}. IP address in HAR entry will be blank.", serverHost);
}
} else {
- log.warn("Unable to identify host from request uri: {}", modifiedHttpRequest.getUri());
+ log.warn("Unable to identify host from request uri: {}", modifiedHttpRequest.uri());
}
}
}
@@ -373,7 +369,7 @@ private void populateServerIpAddress(HarEntry harEntry) {
private HarRequest createRequestForFailedConnect(HttpRequest httpConnectRequest) {
String url = getFullUrl(httpConnectRequest);
- return new HarRequest(httpConnectRequest.getMethod().toString(), url, httpConnectRequest.getProtocolVersion().text());
+ return new HarRequest(httpConnectRequest.method().toString(), url, httpConnectRequest.protocolVersion().text());
}
/**
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsAwareFiltersAdapter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsAwareFiltersAdapter.java
index e727f2b00..aa898e508 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsAwareFiltersAdapter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsAwareFiltersAdapter.java
@@ -32,7 +32,7 @@ public HttpsAwareFiltersAdapter(HttpRequest originalRequest, ChannelHandlerConte
* @return true if https, false if http
*/
public boolean isHttps() {
- Attribute isHttpsAttr = ctx.attr(AttributeKey.valueOf(IS_HTTPS_ATTRIBUTE_NAME));
+ Attribute isHttpsAttr = ctx.attr(AttributeKey.valueOf(IS_HTTPS_ATTRIBUTE_NAME));
Boolean isHttps = isHttpsAttr.get();
if (isHttps == null) {
@@ -54,14 +54,14 @@ public String getFullUrl(HttpRequest modifiedRequest) {
// special case: for HTTPS requests, the full URL is scheme (https://) + the URI of this request
if (ProxyUtils.isCONNECT(modifiedRequest)) {
// CONNECT requests contain the default port, even if it isn't specified on the request.
- String hostNoDefaultPort = BrowserMobHttpUtil.removeMatchingPort(modifiedRequest.getUri(), 443);
+ String hostNoDefaultPort = BrowserMobHttpUtil.removeMatchingPort(modifiedRequest.uri(), 443);
return "https://" + hostNoDefaultPort;
}
// To get the full URL, we need to retrieve the Scheme, Host + Port, Path, and Query Params from the request.
// If the request URI starts with http:// or https://, it is already a full URL and can be returned directly.
- if (HttpUtil.startsWithHttpOrHttps(modifiedRequest.getUri())) {
- return modifiedRequest.getUri();
+ if (HttpUtil.startsWithHttpOrHttps(modifiedRequest.uri())) {
+ return modifiedRequest.uri();
}
// The URI did not include the scheme and host, so examine the request to obtain them:
@@ -70,7 +70,7 @@ public String getFullUrl(HttpRequest modifiedRequest) {
// Path + Query Params: since the request URI doesn't start with the scheme, we can safely assume that the URI
// contains only the path and query params.
String hostAndPort = getHostAndPort(modifiedRequest);
- String path = modifiedRequest.getUri();
+ String path = modifiedRequest.uri();
String url;
if (isHttps()) {
url = "https://" + hostAndPort + path;
@@ -139,7 +139,7 @@ private String getHttpsRequestHostAndPort() throws IllegalStateException {
throw new IllegalStateException("Request is not HTTPS. Cannot get host and port on non-HTTPS request using this method.");
}
- Attribute hostnameAttr = ctx.attr(AttributeKey.valueOf(HOST_ATTRIBUTE_NAME));
+ Attribute hostnameAttr = ctx.attr(AttributeKey.valueOf(HOST_ATTRIBUTE_NAME));
return hostnameAttr.get();
}
@@ -156,7 +156,7 @@ private String getHttpsOriginalRequestHostAndPort() throws IllegalStateException
throw new IllegalStateException("Request is not HTTPS. Cannot get original host and port on non-HTTPS request using this method.");
}
- Attribute hostnameAttr = ctx.attr(AttributeKey.valueOf(ORIGINAL_HOST_ATTRIBUTE_NAME));
+ Attribute hostnameAttr = ctx.attr(AttributeKey.valueOf(ORIGINAL_HOST_ATTRIBUTE_NAME));
return hostnameAttr.get();
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsHostCaptureFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsHostCaptureFilter.java
index f2a52a014..3225ae8ad 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsHostCaptureFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsHostCaptureFilter.java
@@ -27,8 +27,8 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
HttpRequest httpRequest = (HttpRequest) httpObject;
if (ProxyUtils.isCONNECT(httpRequest)) {
- Attribute hostname = ctx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.HOST_ATTRIBUTE_NAME));
- String hostAndPort = httpRequest.getUri();
+ Attribute hostname = ctx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.HOST_ATTRIBUTE_NAME));
+ String hostAndPort = httpRequest.uri();
// CONNECT requests contain the port, even when using the default port. a sensible default is to remove the
// default port, since in most cases it is not explicitly specified and its presence (in a HAR file, for example)
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsOriginalHostCaptureFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsOriginalHostCaptureFilter.java
index 4a6894c4d..85a7b444a 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsOriginalHostCaptureFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/HttpsOriginalHostCaptureFilter.java
@@ -4,7 +4,6 @@
import io.netty.handler.codec.http.HttpRequest;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
-import org.littleshoot.proxy.HttpFiltersAdapter;
import org.littleshoot.proxy.impl.ProxyUtils;
/**
@@ -23,11 +22,11 @@ public HttpsOriginalHostCaptureFilter(HttpRequest originalRequest, ChannelHandle
// capturing the original host (and the remapped/modified host in clientToProxyRequest() below) guarantees that we will
// have the "true" host, rather than relying on the Host header in subsequent requests (which may be absent or spoofed by malicious clients).
if (ProxyUtils.isCONNECT(originalRequest)) {
- Attribute originalHostAttr = ctx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.ORIGINAL_HOST_ATTRIBUTE_NAME));
- String hostAndPort = originalRequest.getUri();
+ Attribute originalHostAttr = ctx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.ORIGINAL_HOST_ATTRIBUTE_NAME));
+ String hostAndPort = originalRequest.uri();
originalHostAttr.set(hostAndPort);
- Attribute isHttpsAttr = ctx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME));
+ Attribute isHttpsAttr = ctx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME));
isHttpsAttr.set(true);
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/ResponseFilterAdapter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/ResponseFilterAdapter.java
index 7edc34dd1..7097d07bd 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/ResponseFilterAdapter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/ResponseFilterAdapter.java
@@ -62,7 +62,7 @@ public void setModifiedHttpRequest(HttpRequest modifiedHttpRequest) {
* and sets a maximum response buffer size of 2 MiB.
*/
public static class FilterSource extends HttpFiltersSourceAdapter {
- private static final int DEFAULT_MAXIMUM_RESPONSE_BUFFER_SIZE = 2097152;
+ public static final int DEFAULT_MAXIMUM_RESPONSE_BUFFER_SIZE = 2097152;
private final ResponseFilter filter;
private final int maximumResponseBufferSizeInBytes;
@@ -100,7 +100,7 @@ public HttpFilters filterRequest(HttpRequest originalRequest, ChannelHandlerCont
@Override
public int getMaximumResponseBufferSizeInBytes() {
- return maximumResponseBufferSizeInBytes;
+ return Math.toIntExact(maximumResponseBufferSizeInBytes);
}
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/RewriteUrlFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/RewriteUrlFilter.java
index ef0e223c0..d1fc9f29b 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/RewriteUrlFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/RewriteUrlFilter.java
@@ -1,10 +1,7 @@
package net.lightbody.bmp.filters;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.util.HttpUtil;
import net.lightbody.bmp.proxy.RewriteRule;
import net.lightbody.bmp.util.BrowserMobHttpUtil;
@@ -64,7 +61,7 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
// if the URI in the request contains the scheme, host, and port, the request's URI can be replaced
// with the rewritten URI. if not (for example, on HTTPS requests), strip the scheme, host, and port from
// the rewritten URL before replacing the URI on the request.
- String uriFromRequest = httpRequest.getUri();
+ String uriFromRequest = httpRequest.uri();
if (HttpUtil.startsWithHttpOrHttps(uriFromRequest)) {
httpRequest.setUri(rewrittenUrl);
} else {
@@ -117,8 +114,8 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
originalHostAndPort, modifiedHostAndPort);
} else {
// only modify the Host header if it already exists
- if (httpRequest.headers().contains(HttpHeaders.Names.HOST)) {
- HttpHeaders.setHost(httpRequest, modifiedHostAndPort);
+ if (httpRequest.headers().contains(HttpHeaderNames.HOST)) {
+ httpRequest.headers().set(HttpHeaderNames.HOST, modifiedHostAndPort);
}
}
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/ServerResponseCaptureFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/ServerResponseCaptureFilter.java
index d69ad8f76..f40c8c6ab 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/ServerResponseCaptureFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/ServerResponseCaptureFilter.java
@@ -2,12 +2,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.HttpContent;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.LastHttpContent;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.util.BrowserMobHttpUtil;
import org.littleshoot.proxy.HttpFiltersAdapter;
import org.slf4j.Logger;
@@ -25,6 +20,7 @@
*/
public class ServerResponseCaptureFilter extends HttpFiltersAdapter {
private static final Logger log = LoggerFactory.getLogger(ServerResponseCaptureFilter.class);
+ private static final String BROTLI_COMPRESSION = "br";
/**
* Populated by serverToProxyResponse() when processing the HttpResponse object
@@ -116,7 +112,7 @@ protected void captureFullResponseContents() {
if (decompressEncodedContent) {
decompressContents();
- } else {
+ } else {
// will not decompress response
}
} else {
@@ -126,12 +122,19 @@ protected void captureFullResponseContents() {
}
protected void decompressContents() {
- if (contentEncoding.equals(HttpHeaders.Values.GZIP)) {
+ if (contentEncoding.equals(HttpHeaderValues.GZIP.toString())) {
try {
fullResponseContents = BrowserMobHttpUtil.decompressContents(getRawResponseContents());
decompressionSuccessful = true;
} catch (RuntimeException e) {
- log.warn("Failed to decompress response with encoding type " + contentEncoding + " when decoding request from " + originalRequest.getUri(), e);
+ log.warn("Failed to decompress response with encoding type " + contentEncoding + " when decoding request from " + originalRequest.uri(), e);
+ }
+ } else if (contentEncoding.equals(BROTLI_COMPRESSION)) {
+ try {
+ fullResponseContents = BrowserMobHttpUtil.decompressBrotliContents(getRawResponseContents());
+ decompressionSuccessful = true;
+ } catch (RuntimeException e) {
+ log.warn("Failed to decompress response with encoding type " + contentEncoding + " when decoding request from " + originalRequest.uri(), e);
}
} else {
log.warn("Cannot decode unsupported content encoding type {}", contentEncoding);
@@ -139,7 +142,7 @@ protected void decompressContents() {
}
protected void captureContentEncoding(HttpResponse httpResponse) {
- contentEncoding = HttpHeaders.getHeader(httpResponse, HttpHeaders.Names.CONTENT_ENCODING);
+ contentEncoding = httpResponse.headers().get(HttpHeaderNames.CONTENT_ENCODING);
}
protected void captureTrailingHeaders(LastHttpContent lastContent) {
@@ -147,7 +150,7 @@ protected void captureTrailingHeaders(LastHttpContent lastContent) {
// technically, the Content-Encoding header can be in a trailing header, although this is excruciatingly uncommon
if (trailingHeaders != null) {
- String trailingContentEncoding = trailingHeaders.get(HttpHeaders.Names.CONTENT_ENCODING);
+ String trailingContentEncoding = trailingHeaders.get(HttpHeaderNames.CONTENT_ENCODING);
if (trailingContentEncoding != null) {
contentEncoding = trailingContentEncoding;
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/StatsDMetricsFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/StatsDMetricsFilter.java
new file mode 100644
index 000000000..c5ff20642
--- /dev/null
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/StatsDMetricsFilter.java
@@ -0,0 +1,64 @@
+package net.lightbody.bmp.filters;
+
+import com.timgroup.statsd.NonBlockingStatsDClient;
+import com.timgroup.statsd.StatsDClient;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.HttpObject;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public class StatsDMetricsFilter extends HttpsAwareFiltersAdapter {
+ public StatsDMetricsFilter(HttpRequest originalRequest, ChannelHandlerContext ctx) {
+ super(originalRequest, ctx);
+ }
+
+ @Override
+ public HttpObject serverToProxyResponse(HttpObject httpObject) {
+ if (httpObject instanceof HttpResponse) {
+ HttpResponse httpResponse = (HttpResponse) httpObject;
+ prepareStatsDMetrics(httpResponse.status().code());
+ }
+ return super.serverToProxyResponse(httpObject);
+ }
+
+ private void prepareStatsDMetrics(int status) {
+ if (status > 399 || status == 0) {
+ String url = getFullUrl(originalRequest);
+ String metric = getProxyPrefix().concat(
+ prepareMetric(url)).concat(String.format(".%s", status));
+ StatsDClient client = new NonBlockingStatsDClient("automated_tests", getStatsDHost(), getStatsDPort());
+ client.increment(metric);
+ client.stop();
+ }
+ }
+
+
+ protected static String getStatsDHost() {
+ return StringUtils.isEmpty(System.getenv("STATSD_HOST")) ? "localhost" : System.getenv("STATSD_HOST");
+ }
+
+ protected static int getStatsDPort() {
+ return StringUtils.isEmpty(System.getenv("STATSD_PORT")) ? 8125 : NumberUtils.toInt(System.getenv("STATSD_PORT"));
+ }
+
+ protected static String getProxyPrefix() {
+ return "proxy.";
+ }
+
+ protected static String prepareMetric(String initialUrl) {
+ URI uri = null;
+ try {
+ uri = new URI(initialUrl);
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return uri.getHost().concat(uri.getPath()).replaceAll("/", "_")
+ .replaceAll("\\.", "_");
+ }
+
+}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/filters/WhitelistFilter.java b/browsermob-core/src/main/java/net/lightbody/bmp/filters/WhitelistFilter.java
index ad8fbf6f6..247769928 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/filters/WhitelistFilter.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/filters/WhitelistFilter.java
@@ -1,12 +1,7 @@
package net.lightbody.bmp.filters;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.DefaultFullHttpResponse;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.*;
import org.littleshoot.proxy.impl.ProxyUtils;
import java.util.Collection;
@@ -23,7 +18,7 @@ public class WhitelistFilter extends HttpsAwareFiltersAdapter {
private final int whitelistResponseCode;
private final Collection whitelistUrls;
- public WhitelistFilter(HttpRequest originalRequest, ChannelHandlerContext ctx, boolean whitelistEnabled,int whitelistResponseCode,
+ public WhitelistFilter(HttpRequest originalRequest, ChannelHandlerContext ctx, boolean whitelistEnabled, int whitelistResponseCode,
Collection whitelistUrls) {
super(originalRequest, ctx);
@@ -63,8 +58,8 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
if (!urlWhitelisted) {
HttpResponseStatus status = HttpResponseStatus.valueOf(whitelistResponseCode);
- HttpResponse resp = new DefaultFullHttpResponse(httpRequest.getProtocolVersion(), status);
- HttpHeaders.setContentLength(resp, 0L);
+ HttpResponse resp = new DefaultFullHttpResponse(httpRequest.protocolVersion(), status);
+ HttpUtil.setContentLength(resp, 0L);
return resp;
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/DnsJavaResolver.java b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/DnsJavaResolver.java
index 432032ed7..b45adb151 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/DnsJavaResolver.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/DnsJavaResolver.java
@@ -108,7 +108,7 @@ protected Collection resolveHostByType(String host, int type) {
}
// convert the records we found into IPv4/IPv6 InetAddress objects
- List addrList = new ArrayList(records.length);
+ List addrList = new ArrayList<>(records.length);
// the InetAddresses returned by dnsjava include the trailing dot, e.g. "www.google.com." -- use the passed-in (or remapped) host value instead
for (Record record : records) {
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/NativeResolver.java b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/NativeResolver.java
index c71c61495..00fd62390 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/NativeResolver.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/proxy/dns/NativeResolver.java
@@ -38,9 +38,8 @@ public void setNegativeDNSCacheTimeout(int timeout, TimeUnit timeUnit) {
@Override
public Collection resolveRemapped(String remappedHost) {
try {
- Collection addresses = Arrays.asList(InetAddress.getAllByName(remappedHost));
+ return Arrays.asList(InetAddress.getAllByName(remappedHost));
- return addresses;
} catch (UnknownHostException e) {
return Collections.emptyList();
}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/util/BeansJsonMapper.java b/browsermob-core/src/main/java/net/lightbody/bmp/util/BeansJsonMapper.java
new file mode 100644
index 000000000..5680b517a
--- /dev/null
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/util/BeansJsonMapper.java
@@ -0,0 +1,39 @@
+package net.lightbody.bmp.util;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class BeansJsonMapper {
+ static final ObjectMapper objectMapper = new ObjectMapper()
+ .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
+ .setVisibility(new ObjectMapper().getSerializationConfig().getDefaultVisibilityChecker()
+ .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
+ .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
+ .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
+ .withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
+
+ private BeansJsonMapper() {
+ }
+
+ public static T json2Bean(String json, Class classToInit) {
+ try {
+ return (T) objectMapper.readValue(json, classToInit);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to instantiate class: " + classToInit.getName());
+ }
+ }
+
+ public static String getJsonString(Object object) {
+ try {
+ return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to serialize object to json: " + object.getClass().getName());
+ }
+ }
+}
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobHttpUtil.java b/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobHttpUtil.java
index 98172810f..e8986680a 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobHttpUtil.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobHttpUtil.java
@@ -3,6 +3,7 @@
import com.google.common.io.BaseEncoding;
import com.google.common.net.HostAndPort;
import com.google.common.net.MediaType;
+import org.brotli.dec.BrotliInputStream;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
@@ -14,6 +15,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -49,7 +51,7 @@ public class BrowserMobHttpUtil {
* Likewise, special treatment of ISO-8859-1 has been removed from the
* Accept-Charset header field.
*
- *
+ *
* Technically, we would have to determine the charset on a per-content-type basis, but generally speaking, UTF-8 is a
* pretty safe default. (NOTE: In the previous HTTP/1.1 spec, section 3.7.1, the default charset was defined as ISO-8859-1.)
*/
@@ -78,7 +80,7 @@ public static long getHeaderSize(HttpHeaders headers) {
/**
* Decompresses the gzipped byte stream.
*
- * @param fullMessage gzipped byte stream to decomress
+ * @param fullMessage gzipped byte stream to decompress
* @return decompressed bytes
* @throws DecompressionException thrown if the fullMessage cannot be read or decompressed for any reason
*/
@@ -111,6 +113,42 @@ public static byte[] decompressContents(byte[] fullMessage) throws Decompression
return fullMessage;
}
+ /**
+ * Decompresses the brotli byze stream
+ *
+ * @param fullMessage brotli byte stream to decompress
+ * @return decompressed bytes
+ * @throws DecompressionException thrown if the fullMessage cannot be read or decompressed for any reason
+ */
+ public static byte[] decompressBrotliContents(byte[] fullMessage) throws DecompressionException {
+ InputStream brotliReader = null;
+ ByteArrayOutputStream uncompressed;
+ try {
+ brotliReader = new BrotliInputStream(new ByteArrayInputStream(fullMessage));
+
+ uncompressed = new ByteArrayOutputStream(fullMessage.length);
+
+ byte[] decompressBuffer = new byte[DECOMPRESS_BUFFER_SIZE];
+ int bytesRead;
+ while ((bytesRead = brotliReader.read(decompressBuffer)) > -1) {
+ uncompressed.write(decompressBuffer, 0, bytesRead);
+ }
+
+ fullMessage = uncompressed.toByteArray();
+ } catch (IOException e) {
+ throw new DecompressionException("Unable to decompress response", e);
+ } finally {
+ try {
+ if (brotliReader != null) {
+ brotliReader.close();
+ }
+ } catch (IOException e) {
+ log.warn("Unable to close brotli stream", e);
+ }
+ }
+ return fullMessage;
+ }
+
/**
* Returns true if the content type string indicates textual content. Currently these are any Content-Types that start with one of the
* following:
@@ -129,11 +167,12 @@ public static byte[] decompressContents(byte[] fullMessage) throws Decompression
public static boolean hasTextualContent(String contentType) {
return contentType != null &&
(contentType.startsWith("text/") ||
- contentType.startsWith("application/x-javascript") ||
- contentType.startsWith("application/javascript") ||
- contentType.startsWith("application/json") ||
- contentType.startsWith("application/xml") ||
- contentType.startsWith("application/xhtml+xml")
+ contentType.startsWith("application/x-javascript") ||
+ contentType.startsWith("application/javascript") ||
+ contentType.startsWith("application/json") ||
+ contentType.startsWith("application/xml") ||
+ contentType.startsWith("application/xhtml+xml") ||
+ (contentType.startsWith("application/") && contentType.endsWith("+json"))
);
}
@@ -184,8 +223,8 @@ public static Charset readCharsetInContentTypeHeader(String contentTypeHeader) t
MediaType mediaType;
try {
- mediaType = MediaType.parse(contentTypeHeader);
- } catch (IllegalArgumentException e) {
+ mediaType = MediaType.parse(contentTypeHeader);
+ } catch (java.lang.IllegalArgumentException e) {
log.info("Unable to parse Content-Type header: {}. Content-Type header will be ignored.", contentTypeHeader, e);
return null;
}
@@ -207,14 +246,14 @@ public static Charset readCharsetInContentTypeHeader(String contentTypeHeader) t
*/
public static String getRawPathAndParamsFromRequest(HttpRequest httpRequest) throws URISyntaxException {
// if this request's URI contains a full URI (including scheme, host, etc.), strip away the non-path components
- if (HttpUtil.startsWithHttpOrHttps(httpRequest.getUri())) {
- return getRawPathAndParamsFromUri(httpRequest.getUri());
+ if (HttpUtil.startsWithHttpOrHttps(httpRequest.uri())) {
+ return getRawPathAndParamsFromUri(httpRequest.uri());
} else {
// to provide consistent validation behavior for URIs that contain a scheme and those that don't, attempt to parse
// the URI, even though we discard the parsed URI object
- new URI(httpRequest.getUri());
+ new URI(httpRequest.uri());
- return httpRequest.getUri();
+ return httpRequest.uri();
}
}
@@ -246,7 +285,7 @@ public static String getRawPathAndParamsFromUri(String uriString) throws URISynt
* @return true if the response is a redirect, otherwise false
*/
public static boolean isRedirect(HttpResponse httpResponse) {
- switch (httpResponse.getStatus().code()) {
+ switch (httpResponse.status().code()) {
case 300:
case 301:
case 302:
@@ -269,7 +308,7 @@ public static boolean isRedirect(HttpResponse httpResponse) {
* parsing the hostname, but makes no guarantees. In general, it should be validated externally, if necessary.
*
* @param hostWithPort string containing a hostname and optional port
- * @param portNumber port to remove from the string
+ * @param portNumber port to remove from the string
* @return string with the specified port removed, or the original string if it did not contain the portNumber
*/
public static String removeMatchingPort(String hostWithPort, int portNumber) {
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobProxyUtil.java b/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobProxyUtil.java
index 62f33cf06..19001df25 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobProxyUtil.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/util/BrowserMobProxyUtil.java
@@ -33,19 +33,14 @@ public class BrowserMobProxyUtil {
/**
* Singleton version string loader.
*/
- private static final Supplier version = Suppliers.memoize(new Supplier() {
- @Override
- public String get() {
- return readVersionFileOnClasspath();
- }
- });
+ private static final Supplier version = Suppliers.memoize(BrowserMobProxyUtil::readVersionFileOnClasspath);
/**
* Copies {@link HarEntry} and {@link HarPage} references from the specified har to a new har copy, up to and including
* the specified pageRef. Does not perform a "deep copy", so any subsequent modification to the entries or pages will
* be reflected in the copied har.
*
- * @param har existing har to copy
+ * @param har existing har to copy
* @param pageRef last page ID to copy
* @return copy of a {@link Har} with entries and pages from the original har, or null if the input har is null
*/
@@ -59,7 +54,7 @@ public static Har copyHarThroughPageRef(Har har, String pageRef) {
}
// collect the page refs that need to be copied to new har copy.
- Set pageRefsToCopy = new HashSet();
+ Set pageRefsToCopy = new HashSet<>();
for (HarPage page : har.getLog().getPages()) {
pageRefsToCopy.add(page.getId());
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java b/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java
index 969a4d810..23a3cddcc 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java
@@ -1,7 +1,7 @@
package net.lightbody.bmp.util;
import io.netty.handler.codec.http.FullHttpMessage;
-import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpHeaderNames;
import net.lightbody.bmp.exception.UnsupportedCharsetException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,7 +11,7 @@
/**
* Helper class to wrap the contents of an {@link io.netty.handler.codec.http.HttpMessage}. Contains convenience methods to extract and
* manipulate the contents of the wrapped {@link io.netty.handler.codec.http.HttpMessage}.
- *
+ *
* TODO: Currently this class only wraps FullHttpMessages, since it must modify the Content-Length header; determine if this may be applied to chunked messages as well
*/
public class HttpMessageContents {
@@ -96,7 +96,7 @@ public byte[] getBinaryContents() {
* @return the message's content type
*/
public String getContentType() {
- String contentTypeHeader = HttpHeaders.getHeader(httpMessage, HttpHeaders.Names.CONTENT_TYPE);
+ String contentTypeHeader = httpMessage.headers().get(HttpHeaderNames.CONTENT_TYPE);
if (contentTypeHeader == null || contentTypeHeader.isEmpty()) {
return BrowserMobHttpUtil.UNKNOWN_CONTENT_TYPE;
} else {
diff --git a/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpObjectUtil.java b/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpObjectUtil.java
index 169a878f6..945f09d4a 100644
--- a/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpObjectUtil.java
+++ b/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpObjectUtil.java
@@ -1,9 +1,6 @@
package net.lightbody.bmp.util;
-import io.netty.handler.codec.http.FullHttpMessage;
-import io.netty.handler.codec.http.HttpContent;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpMessage;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.exception.UnsupportedCharsetException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,22 +18,22 @@ public class HttpObjectUtil {
* Replaces the entity body of the message with the specified contents. Encodes the message contents according to charset in the message's
* Content-Type header, or uses {@link BrowserMobHttpUtil#DEFAULT_HTTP_CHARSET} if none is specified.
* Note: If the charset of the message is not supported on this platform, this will throw an {@link java.nio.charset.UnsupportedCharsetException}.
- *
+ *
* TODO: Currently this method only works for FullHttpMessages, since it must modify the Content-Length header; determine if this may be applied to chunked messages as well
*
- * @param message the HTTP message to manipulate
+ * @param message the HTTP message to manipulate
* @param newContents the new entity body contents
* @throws java.nio.charset.UnsupportedCharsetException if the charset in the message is not supported on this platform
*/
public static void replaceTextHttpEntityBody(FullHttpMessage message, String newContents) {
// get the content type for this message so we can encode the newContents into a byte stream appropriately
- String contentTypeHeader = message.headers().get(HttpHeaders.Names.CONTENT_TYPE);
+ String contentTypeHeader = message.headers().get(HttpHeaderNames.CONTENT_TYPE);
Charset messageCharset;
try {
messageCharset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentTypeHeader);
} catch (UnsupportedCharsetException e) {
- java.nio.charset.UnsupportedCharsetException cause = e.getUnsupportedCharsetExceptionCause() ;
+ java.nio.charset.UnsupportedCharsetException cause = e.getUnsupportedCharsetExceptionCause();
log.error("Found unsupported character set in Content-Type header '{}' while attempting to replace contents of HTTP message.", contentTypeHeader, cause);
throw cause;
@@ -56,7 +53,7 @@ public static void replaceTextHttpEntityBody(FullHttpMessage message, String new
* Replaces an HTTP entity body with the specified binary contents.
* TODO: Currently this method only works for FullHttpMessages, since it must modify the Content-Length header; determine if this may be applied to chunked messages as well
*
- * @param message the HTTP message to manipulate
+ * @param message the HTTP message to manipulate
* @param newBinaryContents the new entity body contents
*/
public static void replaceBinaryHttpEntityBody(FullHttpMessage message, byte[] newBinaryContents) {
@@ -66,7 +63,7 @@ public static void replaceBinaryHttpEntityBody(FullHttpMessage message, byte[] n
message.content().writeBytes(newBinaryContents);
// update the Content-Length header, since the size may have changed
- message.headers().set(HttpHeaders.Names.CONTENT_LENGTH, newBinaryContents.length);
+ message.headers().set(HttpHeaderNames.CONTENT_LENGTH, newBinaryContents.length);
}
/**
@@ -74,7 +71,7 @@ public static void replaceBinaryHttpEntityBody(FullHttpMessage message, byte[] n
* the character set is not specified or is unknown, you still must specify a suitable default charset (see {@link BrowserMobHttpUtil#DEFAULT_HTTP_CHARSET}).
*
* @param httpContent HTTP content object to extract the entity body from
- * @param charset character set of the entity body
+ * @param charset character set of the entity body
* @return String representation of the entity body
* @throws IllegalArgumentException if the charset is null
*/
@@ -105,7 +102,7 @@ public static String extractHttpEntityBody(FullHttpMessage httpMessage) {
// to alert the client code.
java.nio.charset.UnsupportedCharsetException cause = e.getUnsupportedCharsetExceptionCause();
- String contentTypeHeader = HttpHeaders.getHeader(httpMessage, HttpHeaders.Names.CONTENT_TYPE);
+ String contentTypeHeader = httpMessage.headers().get(HttpHeaderNames.CONTENT_TYPE);
log.error("Cannot retrieve text contents of message because HTTP message declares a character set that is not supported on this platform. Content type header: {}.", contentTypeHeader, cause);
throw cause;
@@ -124,7 +121,7 @@ public static String extractHttpEntityBody(FullHttpMessage httpMessage) {
* @throws UnsupportedCharsetException if there is a charset specified in the content-type header, but it is not supported
*/
public static Charset getCharsetFromMessage(HttpMessage httpMessage) throws UnsupportedCharsetException {
- String contentTypeHeader = HttpHeaders.getHeader(httpMessage, HttpHeaders.Names.CONTENT_TYPE);
+ String contentTypeHeader = httpMessage.headers().get(HttpHeaderNames.CONTENT_TYPE);
Charset charset = BrowserMobHttpUtil.readCharsetInContentTypeHeader(contentTypeHeader);
if (charset == null) {
diff --git a/browsermob-core/src/test/groovy/net/lightbody/bmp/filters/RewriteUrlFilterTest.groovy b/browsermob-core/src/test/groovy/net/lightbody/bmp/filters/RewriteUrlFilterTest.groovy
index 0a6991b3e..d5e4f1a12 100644
--- a/browsermob-core/src/test/groovy/net/lightbody/bmp/filters/RewriteUrlFilterTest.groovy
+++ b/browsermob-core/src/test/groovy/net/lightbody/bmp/filters/RewriteUrlFilterTest.groovy
@@ -2,6 +2,7 @@ package net.lightbody.bmp.filters
import com.google.common.collect.ImmutableList
import io.netty.channel.ChannelHandlerContext
+import io.netty.handler.codec.http.HttpHeaderNames
import io.netty.handler.codec.http.HttpHeaders
import io.netty.handler.codec.http.HttpRequest
import io.netty.util.Attribute
@@ -37,10 +38,10 @@ class RewriteUrlFilterTest extends MockServerTest {
@Test
void testRewriteWithCaptureGroups() {
HttpHeaders mockHeaders = mock(HttpHeaders.class)
- when(mockHeaders.contains(HttpHeaders.Names.HOST)).thenReturn(false)
+ when(mockHeaders.contains(HttpHeaderNames.HOST)).thenReturn(false)
HttpRequest request = mock(HttpRequest.class);
- when(request.getUri()).thenReturn('http://www.yahoo.com?param=someValue');
+ when(request.uri()).thenReturn('http://www.yahoo.com?param=someValue');
when(request.headers()).thenReturn(mockHeaders)
Collection rewriteRules = ImmutableList.of(new RewriteRule('http://www\\.(yahoo|bing)\\.com\\?(\\w+)=(\\w+)', 'http://www.google.com?originalDomain=$1&$2=$3'));
@@ -50,7 +51,7 @@ class RewriteUrlFilterTest extends MockServerTest {
when(mockIsHttpsAttribute.get()).thenReturn(Boolean.FALSE)
ChannelHandlerContext mockCtx = mock(ChannelHandlerContext)
- when(mockCtx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME)))
+ when(mockCtx.attr(AttributeKey. valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME)))
.thenReturn(mockIsHttpsAttribute)
RewriteUrlFilter filter = new RewriteUrlFilter(request, mockCtx, rewriteRules);
@@ -62,10 +63,10 @@ class RewriteUrlFilterTest extends MockServerTest {
@Test
void testRewriteMultipleMatches() {
HttpHeaders mockHeaders = mock(HttpHeaders.class)
- when(mockHeaders.contains(HttpHeaders.Names.HOST)).thenReturn(false)
+ when(mockHeaders.contains(HttpHeaderNames.HOST)).thenReturn(false)
HttpRequest request = mock(HttpRequest.class);
- when(request.getUri()).thenReturn('http://www.yahoo.com?param=someValue');
+ when(request.uri()).thenReturn('http://www.yahoo.com?param=someValue');
when(request.headers()).thenReturn(mockHeaders)
Collection rewriteRules = ImmutableList.of(
@@ -78,13 +79,13 @@ class RewriteUrlFilterTest extends MockServerTest {
when(mockIsHttpsAttribute.get()).thenReturn(Boolean.FALSE)
ChannelHandlerContext mockCtx = mock(ChannelHandlerContext)
- when(mockCtx.attr(AttributeKey.valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME)))
+ when(mockCtx.attr(AttributeKey. valueOf(HttpsAwareFiltersAdapter.IS_HTTPS_ATTRIBUTE_NAME)))
.thenReturn(mockIsHttpsAttribute)
RewriteUrlFilter filter = new RewriteUrlFilter(request, mockCtx, rewriteRules);
filter.clientToProxyRequest(request);
- verify(request).setUri('http://www.google.com?originalDomain=bing&newparam=newsomeValue');
+ verify(request).setUri("http://www.google.com?originalDomain=bing&newparam=newsomeValue");
}
@Test
diff --git a/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/BindAddressTest.groovy b/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/BindAddressTest.groovy
index 16fd4b5c4..381008582 100644
--- a/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/BindAddressTest.groovy
+++ b/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/BindAddressTest.groovy
@@ -1,18 +1,21 @@
package net.lightbody.bmp.proxy
+
import net.lightbody.bmp.BrowserMobProxy
import net.lightbody.bmp.BrowserMobProxyServer
import net.lightbody.bmp.proxy.test.util.MockServerTest
import net.lightbody.bmp.proxy.test.util.NewProxyServerTestUtil
+import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.conn.HttpHostConnectException
+import org.apache.http.impl.client.CloseableHttpClient
+import org.apache.http.impl.client.HttpClients
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.mockserver.matchers.Times
import static org.junit.Assert.assertEquals
-import static org.junit.Assume.assumeNoException
import static org.mockserver.model.HttpRequest.request
import static org.mockserver.model.HttpResponse.response
@@ -58,16 +61,16 @@ class BindAddressTest extends MockServerTest {
// find the local host address to bind to that isn't loopback. since ProxyServerTest.getNewHtpClient creates an HTTP client that
// connects to a proxy at 127.0.0.1, the HTTP client should *not* be able to connect to the proxy
- InetAddress localHostAddr
- try {
- localHostAddr = InetAddress.getLocalHost()
- } catch (UnknownHostException e) {
- assumeNoException("Could not get a localhost address. Skipping test.", e)
- return
- }
+ Socket socket = new Socket()
+ socket.connect(new InetSocketAddress("google.com", 80))
+ socket.getLocalAddress()
proxy = new BrowserMobProxyServer()
- proxy.start(0, localHostAddr)
+ proxy.start(0, new InetAddress().getByName(socket.getLocalAddress().getHostAddress()))
+
+
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ CloseableHttpResponse response = httpclient.execute(new HttpGet("http://127.0.0.1:${mockServerPort}/clientbind"));
NewProxyServerTestUtil.getNewHttpClient(proxy.getPort()).withCloseable {
it.execute(new HttpGet("http://127.0.0.1:${mockServerPort}/clientbind"))
diff --git a/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/WhitelistTest.groovy b/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/WhitelistTest.groovy
index 22dd101bb..aa2d40b59 100644
--- a/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/WhitelistTest.groovy
+++ b/browsermob-core/src/test/groovy/net/lightbody/bmp/proxy/WhitelistTest.groovy
@@ -37,9 +37,9 @@ class WhitelistTest extends MockServerTest {
@Test
void testWhitelistCannotShortCircuitCONNECT() {
HttpRequest request = mock(HttpRequest.class)
- when(request.getMethod()).thenReturn(HttpMethod.CONNECT)
- when(request.getUri()).thenReturn('somedomain.com:443')
- when(request.getProtocolVersion()).thenReturn(HttpVersion.HTTP_1_1)
+ when(request.method()).thenReturn(HttpMethod.CONNECT)
+ when(request.uri()).thenReturn('somedomain.com:443')
+ when(request.protocolVersion()).thenReturn(HttpVersion.HTTP_1_1)
// create a whitelist filter that whitelists no requests (i.e., all requests should return the specified HTTP 500 status code)
WhitelistFilter filter = new WhitelistFilter(request, null, true, 500, [])
diff --git a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/InterceptorTest.java b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/InterceptorTest.java
index 3df880424..bdb2eb298 100644
--- a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/InterceptorTest.java
+++ b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/InterceptorTest.java
@@ -1,24 +1,13 @@
package net.lightbody.bmp.proxy;
import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.DefaultHttpResponse;
-import io.netty.handler.codec.http.FullHttpResponse;
-import io.netty.handler.codec.http.HttpHeaders;
-import io.netty.handler.codec.http.HttpMethod;
-import io.netty.handler.codec.http.HttpObject;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.*;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
-import net.lightbody.bmp.filters.RequestFilter;
import net.lightbody.bmp.filters.RequestFilterAdapter;
-import net.lightbody.bmp.filters.ResponseFilter;
import net.lightbody.bmp.filters.ResponseFilterAdapter;
import net.lightbody.bmp.proxy.test.util.MockServerTest;
import net.lightbody.bmp.proxy.test.util.NewProxyServerTestUtil;
-import net.lightbody.bmp.util.HttpMessageContents;
-import net.lightbody.bmp.util.HttpMessageInfo;
import net.lightbody.bmp.util.HttpObjectUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@@ -40,14 +29,9 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-import static org.hamcrest.Matchers.endsWith;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.CoreMatchers.endsWith;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.*;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
@@ -84,7 +68,7 @@ public void testCanShortCircuitResponse() throws IOException {
proxy.start();
final AtomicBoolean interceptorFired = new AtomicBoolean(false);
- final AtomicBoolean shortCircuitFired= new AtomicBoolean(false);
+ final AtomicBoolean shortCircuitFired = new AtomicBoolean(false);
proxy.addFirstHttpFilterFactory(new HttpFiltersSourceAdapter() {
@Override
@@ -97,8 +81,8 @@ public HttpResponse clientToProxyRequest(HttpObject httpObject) {
HttpRequest httpRequest = (HttpRequest) httpObject;
- if (httpRequest.getMethod().equals(HttpMethod.GET) && httpRequest.getUri().contains("/shortcircuit204")) {
- HttpResponse httpResponse = new DefaultHttpResponse(httpRequest.getProtocolVersion(), HttpResponseStatus.NO_CONTENT);
+ if (httpRequest.method().equals(HttpMethod.GET) && httpRequest.uri().contains("/shortcircuit204")) {
+ HttpResponse httpResponse = new DefaultHttpResponse(httpRequest.protocolVersion(), HttpResponseStatus.NO_CONTENT);
shortCircuitFired.set(true);
@@ -160,7 +144,7 @@ public void testCanModifyRequest() throws IOException {
Times.exactly(1))
.respond(response()
.withStatusCode(200)
- .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=utf-8"))
+ .withHeader(new Header(HttpHeaderNames.CONTENT_TYPE.toString(), "text/plain; charset=utf-8"))
.withBody("success"));
proxy = new BrowserMobProxyServer();
@@ -174,7 +158,7 @@ public HttpFilters filterRequest(HttpRequest originalRequest) {
public HttpResponse clientToProxyRequest(HttpObject httpObject) {
if (httpObject instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest) httpObject;
- httpRequest.setUri(httpRequest.getUri().replace("/originalrequest", "/modifyrequest"));
+ httpRequest.setUri(httpRequest.uri().replace("/originalrequest", "/modifyrequest"));
}
return super.clientToProxyRequest(httpObject);
@@ -209,17 +193,14 @@ public void testRequestFilterCanModifyHttpRequestBody() throws IOException {
proxy = new BrowserMobProxyServer();
proxy.start();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (contents.isText()) {
- if (contents.getTextContents().equals(originalText)) {
- contents.setTextContents(newText);
- }
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ if (contents.isText()) {
+ if (contents.getTextContents().equals(originalText)) {
+ contents.setTextContents(newText);
}
-
- return null;
}
+
+ return null;
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
@@ -251,17 +232,14 @@ public void testRequestFilterCanModifyHttpsRequestBody() throws IOException {
proxy.setTrustAllServers(true);
proxy.start();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (contents.isText()) {
- if (contents.getTextContents().equals(originalText)) {
- contents.setTextContents(newText);
- }
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ if (contents.isText()) {
+ if (contents.getTextContents().equals(originalText)) {
+ contents.setTextContents(newText);
}
-
- return null;
}
+
+ return null;
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
@@ -277,8 +255,8 @@ public HttpResponse filterRequest(HttpRequest request, HttpMessageContents conte
@Test
public void testResponseFilterCanModifyBinaryContents() throws IOException {
- final byte[] originalBytes = new byte[] {1, 2, 3, 4, 5};
- final byte[] newBytes = new byte[] {20, 30, 40, 50, 60};
+ final byte[] originalBytes = new byte[]{1, 2, 3, 4, 5};
+ final byte[] newBytes = new byte[]{20, 30, 40, 50, 60};
mockServer.when(request()
.withMethod("GET")
@@ -286,19 +264,16 @@ public void testResponseFilterCanModifyBinaryContents() throws IOException {
Times.exactly(1))
.respond(response()
.withStatusCode(200)
- .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream"))
+ .withHeader(new Header(HttpHeaderNames.CONTENT_TYPE.toString(), "application/octet-stream"))
.withBody(originalBytes));
proxy = new BrowserMobProxyServer();
proxy.start();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (!contents.isText()) {
- if (Arrays.equals(originalBytes, contents.getBinaryContents())) {
- contents.setBinaryContents(newBytes);
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ if (!contents.isText()) {
+ if (Arrays.equals(originalBytes, contents.getBinaryContents())) {
+ contents.setBinaryContents(newBytes);
}
}
});
@@ -324,19 +299,16 @@ public void testResponseFilterCanModifyHttpTextContents() throws IOException {
Times.exactly(1))
.respond(response()
.withStatusCode(200)
- .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=utf-8"))
+ .withHeader(new Header(HttpHeaderNames.CONTENT_TYPE.toString(), "text/plain; charset=utf-8"))
.withBody(originalText));
proxy = new BrowserMobProxyServer();
proxy.start();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (contents.isText()) {
- if (contents.getTextContents().equals(originalText)) {
- contents.setTextContents(newText);
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ if (contents.isText()) {
+ if (contents.getTextContents().equals(originalText)) {
+ contents.setTextContents(newText);
}
}
});
@@ -363,20 +335,17 @@ public void testResponseFilterCanModifyHttpsTextContents() throws IOException {
Times.exactly(1))
.respond(response()
.withStatusCode(200)
- .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=utf-8"))
+ .withHeader(new Header(HttpHeaderNames.CONTENT_TYPE.toString(), "text/plain; charset=utf-8"))
.withBody(originalText));
proxy = new BrowserMobProxyServer();
proxy.setTrustAllServers(true);
proxy.start();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (contents.isText()) {
- if (contents.getTextContents().equals(originalText)) {
- contents.setTextContents(newText);
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ if (contents.isText()) {
+ if (contents.getTextContents().equals(originalText)) {
+ contents.setTextContents(newText);
}
}
});
@@ -400,19 +369,14 @@ public void testResponseInterceptorWithoutBody() throws IOException {
Times.exactly(1))
.respond(response()
.withStatusCode(200)
- .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream")));
+ .withHeader(new Header(HttpHeaderNames.CONTENT_TYPE.toString(), "application/octet-stream")));
proxy = new BrowserMobProxyServer();
proxy.start();
final AtomicReference responseContents = new AtomicReference<>();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- responseContents.set(contents.getBinaryContents());
- }
- });
+ proxy.addResponseFilter((response, contents, messageInfo) -> responseContents.set(contents.getBinaryContents()));
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
CloseableHttpResponse response = httpClient.execute(new HttpHead("http://localhost:" + mockServerPort + "/interceptortest"));
@@ -435,25 +399,17 @@ public void testResponseFilterOriginalRequestNotModified() throws IOException {
proxy = new BrowserMobProxyServer();
proxy.start();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (request.getUri().endsWith("/originalendpoint")) {
- request.setUri(request.getUri().replaceAll("originalendpoint", "modifiedendpoint"));
- }
-
- return null;
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ if (request.uri().endsWith("/originalendpoint")) {
+ request.setUri(request.uri().replaceAll("originalendpoint", "modifiedendpoint"));
}
+
+ return null;
});
final AtomicReference originalRequestUri = new AtomicReference<>();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- originalRequestUri.set(messageInfo.getOriginalRequest().getUri());
- }
- });
+ proxy.addResponseFilter((response, contents, messageInfo) -> originalRequestUri.set(messageInfo.getOriginalRequest().uri()));
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
CloseableHttpResponse response = httpClient.execute(new HttpGet("http://localhost:" + mockServerPort + "/originalendpoint"));
@@ -479,23 +435,17 @@ public void testMessageContentsNotAvailableWithoutAggregation() throws IOExcepti
final AtomicBoolean requestContentsNull = new AtomicBoolean(false);
final AtomicBoolean responseContentsNull = new AtomicBoolean(false);
- proxy.addFirstHttpFilterFactory(new RequestFilterAdapter.FilterSource(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (contents == null) {
- requestContentsNull.set(true);
- }
-
- return null;
+ proxy.addFirstHttpFilterFactory(new RequestFilterAdapter.FilterSource((request, contents, messageInfo) -> {
+ if (contents == null) {
+ requestContentsNull.set(true);
}
+
+ return null;
}, 0));
- proxy.addFirstHttpFilterFactory(new ResponseFilterAdapter.FilterSource(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (contents == null) {
- responseContentsNull.set(true);
- }
+ proxy.addFirstHttpFilterFactory(new ResponseFilterAdapter.FilterSource((response, contents, messageInfo) -> {
+ if (contents == null) {
+ responseContentsNull.set(true);
}
}, 0));
@@ -526,16 +476,13 @@ public void testMitmDisabledHttpsRequestFilterNotAvailable() throws IOException
final AtomicBoolean connectRequestFilterFired = new AtomicBoolean(false);
final AtomicBoolean getRequestFilterFired = new AtomicBoolean(false);
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (request.getMethod().equals(HttpMethod.CONNECT)) {
- connectRequestFilterFired.set(true);
- } else if (request.getMethod().equals(HttpMethod.GET)) {
- getRequestFilterFired.set(true);
- }
- return null;
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ if (request.method().equals(HttpMethod.CONNECT)) {
+ connectRequestFilterFired.set(true);
+ } else if (request.method().equals(HttpMethod.GET)) {
+ getRequestFilterFired.set(true);
}
+ return null;
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
@@ -569,12 +516,7 @@ public void testMitmDisabledHttpsResponseFilterNotAvailable() throws IOException
final AtomicBoolean responseFilterFired = new AtomicBoolean(false);
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- responseFilterFired.set(true);
- }
- });
+ proxy.addResponseFilter((response, contents, messageInfo) -> responseFilterFired.set(true));
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
CloseableHttpResponse response = httpClient.execute(new HttpGet("https://localhost:" + mockServerPort + "/mitmdisabled"));
@@ -594,7 +536,7 @@ private void testModifiedResponse(final String originalText, final String newTex
Times.exactly(1))
.respond(response()
.withStatusCode(200)
- .withHeader(new Header(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=utf-8"))
+ .withHeader(new Header(HttpHeaderNames.CONTENT_TYPE.toString(), "text/plain; charset=utf-8"))
.withBody(originalText));
proxy = new BrowserMobProxyServer();
@@ -718,16 +660,13 @@ public void testHttpResponseFilterMessageInfoPopulated() throws IOException {
final AtomicReference requestFilterOriginalUrl = new AtomicReference<>();
final AtomicReference requestFilterUrl = new AtomicReference<>();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- requestCtx.set(messageInfo.getChannelHandlerContext());
- requestOriginalRequest.set(messageInfo.getOriginalRequest());
- requestIsHttps.set(messageInfo.isHttps());
- requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
- requestFilterUrl.set(messageInfo.getUrl());
- return null;
- }
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ requestCtx.set(messageInfo.getChannelHandlerContext());
+ requestOriginalRequest.set(messageInfo.getOriginalRequest());
+ requestIsHttps.set(messageInfo.isHttps());
+ requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
+ requestFilterUrl.set(messageInfo.getUrl());
+ return null;
});
final AtomicReference responseCtx = new AtomicReference<>();
@@ -736,15 +675,12 @@ public HttpResponse filterRequest(HttpRequest request, HttpMessageContents conte
final AtomicReference responseFilterOriginalUrl = new AtomicReference<>();
final AtomicReference responseFilterUrl = new AtomicReference<>();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- responseCtx.set(messageInfo.getChannelHandlerContext());
- responseOriginalRequest.set(messageInfo.getOriginalRequest());
- responseIsHttps.set(messageInfo.isHttps());
- responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
- responseFilterUrl.set(messageInfo.getUrl());
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ responseCtx.set(messageInfo.getChannelHandlerContext());
+ responseOriginalRequest.set(messageInfo.getOriginalRequest());
+ responseIsHttps.set(messageInfo.isHttps());
+ responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
+ responseFilterUrl.set(messageInfo.getUrl());
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
@@ -782,37 +718,28 @@ public void testHttpResponseFilterUrlReflectsModifications() throws IOException
final AtomicReference requestFilterOriginalUrl = new AtomicReference<>();
final AtomicReference requestFilterUrl = new AtomicReference<>();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
- requestFilterUrl.set(messageInfo.getUrl());
- return null;
- }
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
+ requestFilterUrl.set(messageInfo.getUrl());
+ return null;
});
// request filters get added to the beginning of the filter chain, so add this uri-modifying request filter after
// adding the capturing request filter above.
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (request.getUri().endsWith("/originalurl")) {
- String newUrl = request.getUri().replaceAll("originalurl", "urlreflectsmodifications");
- request.setUri(newUrl);
- }
- return null;
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ if (request.uri().endsWith("/originalurl")) {
+ String newUrl = request.uri().replaceAll("originalurl", "urlreflectsmodifications");
+ request.setUri(newUrl);
}
+ return null;
});
final AtomicReference responseFilterOriginalUrl = new AtomicReference<>();
final AtomicReference responseFilterUrl = new AtomicReference<>();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
- responseFilterUrl.set(messageInfo.getUrl());
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
+ responseFilterUrl.set(messageInfo.getUrl());
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
@@ -846,37 +773,28 @@ public void testHttpsResponseFilterUrlReflectsModifications() throws IOException
final AtomicReference requestFilterOriginalUrl = new AtomicReference<>();
final AtomicReference requestFilterUrl = new AtomicReference<>();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
- requestFilterUrl.set(messageInfo.getUrl());
- return null;
- }
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ requestFilterOriginalUrl.set(messageInfo.getOriginalUrl());
+ requestFilterUrl.set(messageInfo.getUrl());
+ return null;
});
// request filters get added to the beginning of the filter chain, so add this uri-modifying request filter after
// adding the capturing request filter above.
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- if (request.getUri().endsWith("/originalurl")) {
- String newUrl = request.getUri().replaceAll("originalurl", "urlreflectsmodifications");
- request.setUri(newUrl);
- }
- return null;
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ if (request.uri().endsWith("/originalurl")) {
+ String newUrl = request.uri().replaceAll("originalurl", "urlreflectsmodifications");
+ request.setUri(newUrl);
}
+ return null;
});
final AtomicReference responseFilterOriginalUrl = new AtomicReference<>();
final AtomicReference responseFilterUrl = new AtomicReference<>();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
- responseFilterUrl.set(messageInfo.getUrl());
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ responseFilterOriginalUrl.set(messageInfo.getOriginalUrl());
+ responseFilterUrl.set(messageInfo.getUrl());
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
@@ -913,15 +831,12 @@ public void testHttpsResponseFilterMessageInfoPopulated() throws IOException {
final AtomicBoolean requestIsHttps = new AtomicBoolean(false);
final AtomicReference requestOriginalUrl = new AtomicReference<>();
- proxy.addRequestFilter(new RequestFilter() {
- @Override
- public HttpResponse filterRequest(HttpRequest request, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- requestCtx.set(messageInfo.getChannelHandlerContext());
- requestOriginalRequest.set(messageInfo.getOriginalRequest());
- requestIsHttps.set(messageInfo.isHttps());
- requestOriginalUrl.set(messageInfo.getOriginalUrl());
- return null;
- }
+ proxy.addRequestFilter((request, contents, messageInfo) -> {
+ requestCtx.set(messageInfo.getChannelHandlerContext());
+ requestOriginalRequest.set(messageInfo.getOriginalRequest());
+ requestIsHttps.set(messageInfo.isHttps());
+ requestOriginalUrl.set(messageInfo.getOriginalUrl());
+ return null;
});
final AtomicReference responseCtx = new AtomicReference<>();
@@ -929,14 +844,11 @@ public HttpResponse filterRequest(HttpRequest request, HttpMessageContents conte
final AtomicBoolean responseIsHttps = new AtomicBoolean(false);
final AtomicReference responseOriginalUrl = new AtomicReference<>();
- proxy.addResponseFilter(new ResponseFilter() {
- @Override
- public void filterResponse(HttpResponse response, HttpMessageContents contents, HttpMessageInfo messageInfo) {
- responseCtx.set(messageInfo.getChannelHandlerContext());
- responseOriginalRequest.set(messageInfo.getOriginalRequest());
- responseIsHttps.set(messageInfo.isHttps());
- responseOriginalUrl.set(messageInfo.getOriginalUrl());
- }
+ proxy.addResponseFilter((response, contents, messageInfo) -> {
+ responseCtx.set(messageInfo.getChannelHandlerContext());
+ responseOriginalRequest.set(messageInfo.getOriginalRequest());
+ responseIsHttps.set(messageInfo.isHttps());
+ responseOriginalUrl.set(messageInfo.getOriginalUrl());
});
try (CloseableHttpClient httpClient = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
diff --git a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/QuiescenceTest.java b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/QuiescenceTest.java
index 60842b0be..cbbe669df 100644
--- a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/QuiescenceTest.java
+++ b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/QuiescenceTest.java
@@ -19,10 +19,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
@@ -218,7 +215,6 @@ public void testWaitForQuiescenceTimeoutLessThanQuietPeriodUnuccessful() throws
}
@Test
- @Ignore //TODO: ignoring this test because it seems to fail on Java 8 under travis-ci. determine if there is an actual code defect, or just a test/environment defect.
public void testWaitForQuiescenceInterruptedBySecondRequestSuccessful() throws InterruptedException {
mockServer.when(
request().withMethod("GET")
@@ -235,27 +231,24 @@ public void testWaitForQuiescenceInterruptedBySecondRequestSuccessful() throws I
final AtomicBoolean exceptionOccurred = new AtomicBoolean();
- new Thread(new Runnable() {
- @Override
- public void run() {
- try (CloseableHttpClient client = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
- HttpResponse response = client.execute(new HttpGet("http://127.0.0.1:" + mockServerPort + "/successquiesence2s"));
- EntityUtils.consumeQuietly(response.getEntity());
- firstRequestStatusCode.set(response.getStatusLine().getStatusCode());
+ new Thread(() -> {
+ try (CloseableHttpClient client = NewProxyServerTestUtil.getNewHttpClient(proxy.getPort())) {
+ HttpResponse response = client.execute(new HttpGet("http://127.0.0.1:" + mockServerPort + "/successquiesence2s"));
+ EntityUtils.consumeQuietly(response.getEntity());
+ firstRequestStatusCode.set(response.getStatusLine().getStatusCode());
- Thread.sleep(1000);
+ Thread.sleep(1000);
- response = client.execute(new HttpGet("http://127.0.0.1:" + mockServerPort + "/successquiesence2s"));
- EntityUtils.consumeQuietly(response.getEntity());
+ response = client.execute(new HttpGet("http://127.0.0.1:" + mockServerPort + "/successquiesence2s"));
+ EntityUtils.consumeQuietly(response.getEntity());
- secondRequestFinished.set(System.nanoTime());
+ secondRequestFinished.set(System.nanoTime());
- secondRequestStatusCode.set(response.getStatusLine().getStatusCode());
- } catch (IOException | InterruptedException e) {
- exceptionOccurred.set(true);
+ secondRequestStatusCode.set(response.getStatusLine().getStatusCode());
+ } catch (IOException | InterruptedException e) {
+ exceptionOccurred.set(true);
- log.error("Exception occurred while making HTTP request", e);
- }
+ log.error("Exception occurred while making HTTP request", e);
}
}).start();
diff --git a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/dns/ChainedHostResolverTest.java b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/dns/ChainedHostResolverTest.java
index fbf09d63c..04de7c9b9 100644
--- a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/dns/ChainedHostResolverTest.java
+++ b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/dns/ChainedHostResolverTest.java
@@ -17,20 +17,13 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
public class ChainedHostResolverTest {
@Test
@@ -62,7 +55,7 @@ public void testResolveReturnsFirstResults() {
ChainedHostResolver chainResolver = new ChainedHostResolver(ImmutableList.of(firstResolver, secondResolver));
when(firstResolver.resolve("1.1.1.1")).thenReturn(TestConstants.addressOnesList);
- when(secondResolver.resolve("1.1.1.1")).thenReturn(Collections.emptyList());
+ when(secondResolver.resolve("1.1.1.1")).thenReturn(Collections.emptyList());
Collection results = chainResolver.resolve("1.1.1.1");
assertNotNull("Resolver should not return null results", results);
diff --git a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/MockServerTest.java b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/MockServerTest.java
index 9e1ba94ef..24108d5cc 100644
--- a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/MockServerTest.java
+++ b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/MockServerTest.java
@@ -14,7 +14,7 @@ public class MockServerTest {
@Before
public void setUpMockServer() {
mockServer = new ClientAndServer(0);
- mockServerPort = mockServer.getPort();
+ mockServerPort = mockServer.getLocalPort();
}
@After
diff --git a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/NewProxyServerTestUtil.java b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/NewProxyServerTestUtil.java
index af86c4b96..b68e1bd85 100644
--- a/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/NewProxyServerTestUtil.java
+++ b/browsermob-core/src/test/java/net/lightbody/bmp/proxy/test/util/NewProxyServerTestUtil.java
@@ -2,8 +2,8 @@
import org.apache.http.HttpHost;
import org.apache.http.client.CookieStore;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
@@ -12,8 +12,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
public class NewProxyServerTestUtil {
/**
@@ -31,26 +29,19 @@ public static CloseableHttpClient getNewHttpClient(int proxyPort) {
* Creates an all-trusting CloseableHttpClient (for tests ONLY!) that will connect to a proxy at 127.0.0.1:proxyPort,
* using the specified cookie store.
*
- * @param proxyPort port of the proxy running at 127.0.0.1
+ * @param proxyPort port of the proxy running at 127.0.0.1
* @param cookieStore CookieStore for HTTP cookies
* @return a new CloseableHttpClient
*/
public static CloseableHttpClient getNewHttpClient(int proxyPort, CookieStore cookieStore) {
try {
// Trust all certs -- under no circumstances should this ever be used outside of testing
- SSLContext sslcontext = SSLContexts.custom()
- .useTLS()
- .loadTrustMaterial(null, new TrustStrategy() {
- @Override
- public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- return true;
- }
- })
+ SSLContext sslcontext = org.apache.http.ssl.SSLContexts.custom()
+ .loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true)
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
- sslcontext,
- SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+ sslcontext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
diff --git a/browsermob-dist/pom.xml b/browsermob-dist/pom.xml
index 59edc89cb..221cd5b83 100644
--- a/browsermob-dist/pom.xml
+++ b/browsermob-dist/pom.xml
@@ -1,9 +1,10 @@
-
+browsermob-proxynet.lightbody.bmp
- 2.1.6-SNAPSHOT
+ 2.1.384.0.0
@@ -14,7 +15,6 @@
${project.parent.artifactId}-${project.version}
- ${netty-4.1.version}
@@ -39,6 +39,17 @@
org.apache.logging.log4jlog4j-api
+
+
+ biz.paluch.logging
+ logstash-gelf
+
+
+
+ co.elastic.logging
+ log4j2-ecs-layout
+
+
org.apache.logging.log4jlog4j-core
@@ -98,7 +109,18 @@
org.apache.maven.pluginsmaven-shade-plugin
- 3.0.0
+ 3.2.0
+
+ false
+
+
+ *:*
+
+ **/Log4j2Plugins.dat
+
+
+
+ package
@@ -117,7 +139,10 @@
-
+
+ net.lightbody.bmp.proxy.Main
@@ -125,6 +150,13 @@
+
+
+ com.github.edwgiz
+ maven-shade-plugin.log4j2-cachefile-transformer
+ 2.8.1
+
+ maven-assembly-plugin
diff --git a/browsermob-dist/src/main/resources/bmp-logging.yaml b/browsermob-dist/src/main/resources/bmp-logging.yaml
index 3114ff47f..1a237ce8b 100644
--- a/browsermob-dist/src/main/resources/bmp-logging.yaml
+++ b/browsermob-dist/src/main/resources/bmp-logging.yaml
@@ -8,30 +8,41 @@ configuration:
name: console
target: SYSTEM_OUT
PatternLayout:
- pattern: "[%-5level %date{ISO8601} %logger] (%thread) %msg %xThrowable%n"
- file:
- -
- name: file
- fileName: bmp.log
- PatternLayout:
- pattern: "[%-5level %date{ISO8601} %logger] (%thread) %msg %xThrowable%n"
- append: false
+ pattern: "[%-5level %date{ISO8601} %c{1}] %msg %xThrowable%n"
+ gelf:
+ - name: gelf
+ host: tcp:localhost
+ port: 12204
+ filterStackTrace: true
+ mdcProfiling: true
+ includeFullMdc: true
+ facility: mobproxy
+ version: 1.1
+ originHost: "%host{fqdn}"
+ maximumMessageSize: "8192"
+ extractStackTrace: false
+ Field:
+ - name: simpleClassName
+ pattern: "%C{1}"
+ - name: server
+ pattern: "%host"
+ - name: timestamp
+ pattern: "%date{ISO8601}"
+
+
loggers:
logger:
- -
- name: net.lightbody.bmp.proxy.jetty.util.ThreadedServer
- level: warn
+ - name: net.lightbody.bmp.proxy.jetty.util.ThreadedServer
+ level: fatal
additivity: false
- -
- name: net.lightbody.bmp
+ - name: org.littleshoot.proxy
# to suppress unwanted BMP logging statements, set the level below for the source logger to WARN or ERROR.
# to enable more verbose logging, set the level to DEBUG or TRACE.
- level: info
+ level: fatal
+
root:
# to suppress unwanted logging statements globally, set the level below to WARN or ERROR.
- level: info
+ level: error
appender-ref:
- -
- ref: console
- -
- ref: file
\ No newline at end of file
+ - ref: console
+ - ref: gelf
\ No newline at end of file
diff --git a/browsermob-legacy/pom.xml b/browsermob-legacy/pom.xml
index 592543c91..985c60154 100644
--- a/browsermob-legacy/pom.xml
+++ b/browsermob-legacy/pom.xml
@@ -1,11 +1,12 @@
-
+jarbrowsermob-proxynet.lightbody.bmp
- 2.1.6-SNAPSHOT
+ 2.1.384.0.0
@@ -13,7 +14,7 @@
BrowserMob Proxy Legacy (Jetty) Module
- 7.6.16.v20140903
+ 9.4.31.v20200723true
@@ -23,7 +24,7 @@
org.apache.maven.pluginsmaven-surefire-plugin
- -Xmx1g -XX:MaxPermSize=256m
+ -Xmx1g${use.littleproxy}
@@ -80,13 +81,13 @@
commons-iocommons-io
- 2.5
+ 2.6javax.servlet
- servlet-api
- 2.5
+ javax.servlet-api
+ 4.0.1
@@ -109,7 +110,7 @@
org.hamcrest
- hamcrest-library
+ hamcresttest
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/LegacyProxyServer.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/LegacyProxyServer.java
index 103f2f25a..9e1f390f1 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/LegacyProxyServer.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/LegacyProxyServer.java
@@ -18,7 +18,7 @@
/**
* Describes the legacy BrowserMob Proxy 2.0 interface. Clients should not implement or use this interface.
- *
+ *
* Use {@link BrowserMobProxy}.
*/
public interface LegacyProxyServer {
@@ -122,6 +122,8 @@ public interface LegacyProxyServer {
void addHeader(String name, String value);
+ void headerFilterRegexp(String headerFilterRegexp);
+
void setCaptureHeaders(boolean captureHeaders);
void setCaptureContent(boolean captureContent);
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/ProxyServer.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/ProxyServer.java
index 29c5f897f..1b351d1f2 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/ProxyServer.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/ProxyServer.java
@@ -205,7 +205,7 @@ public void stop() {
server.stop();
}
} catch (InterruptedException e) {
- // the try/catch block in server.stop() is manufacturing a phantom InterruptedException, so this should not occur
+ // the try/catch block in server.stop() is manufacturing a phantom InterruptedException, so this should not occur
throw new JettyException("Exception occurred when stopping the server", e);
}
}
@@ -236,10 +236,10 @@ public void setPort(int port) {
/**
* Get the the InetAddress that the Proxy server binds to when it starts.
- *
+ *
* If not otherwise set via {@link #setLocalHost(InetAddress)}, defaults to
* 0.0.0.0 (i.e. bind to any interface).
- *
+ *
* Note - just because we bound to the address, doesn't mean that it can be
* reached. E.g. trying to connect to 0.0.0.0 is going to fail. Use
* {@link #getConnectableLocalHost()} if you're looking for a host that can be
@@ -258,22 +258,22 @@ public InetAddress getLocalHost() {
}
return localHost;
}
-
+
/**
* Return a plausible {@link InetAddress} that other processes can use to
* contact the proxy.
- *
+ *
* In essence, this is the same as {@link #getLocalHost()}, but avoids
* returning 0.0.0.0. as no-one can connect to that. If no other host has
* been set via {@link #setLocalHost(InetAddress)}, will return
* {@link InetAddress#getLocalHost()}
- *
+ *
* No attempt is made to check the address for reachability before it is
* returned.
*/
@Override
public InetAddress getConnectableLocalHost() throws UnknownHostException {
-
+
if (getLocalHost().equals(InetAddress.getByName("0.0.0.0"))) {
return InetAddress.getLocalHost();
} else {
@@ -295,12 +295,12 @@ public void setLocalHost(InetAddress localHost) {
throw new IllegalArgumentException("localHost address must be address of a local adapter (attempted to use: " + localHost + ")", e);
}
if (localInterface != null) {
- this.localHost = localHost;
+ this.localHost = localHost;
} else {
throw new IllegalArgumentException("localHost address must be address of a local adapter (attempted to use: " + localHost + ")");
}
}
-
+
}
@Override
@@ -544,6 +544,11 @@ public void addHeaders(Map headers) {
}
}
+ @Override
+ public void headerFilterRegexp(String headerFilterRegexp){
+ client.setHeadersFilterRegexp(headerFilterRegexp);
+ }
+
public void remapHost(String source, String target) {
if (client.getResolver() instanceof AdvancedHostResolver) {
AdvancedHostResolver advancedHostResolver = (AdvancedHostResolver) client.getResolver();
@@ -660,7 +665,7 @@ public void clearRewriteRules() {
public void blacklistRequests(String pattern, int responseCode) {
client.blacklistRequests(pattern, responseCode, null);
}
-
+
@Override
public void blacklistRequests(String pattern, int responseCode, String method) {
client.blacklistRequests(pattern, responseCode, method);
@@ -690,7 +695,7 @@ public Collection getBlacklist() {
public List getBlacklistedRequests() {
return client.getBlacklistedRequests();
}
-
+
@Override
public Collection getBlacklistedUrls() {
return client.getBlacklistedUrls();
@@ -709,7 +714,7 @@ public boolean isWhitelistEnabled() {
public List getWhitelistRequests() {
return client.getWhitelistRequests();
}
-
+
@Override
public Collection getWhitelistUrls() {
ImmutableList.Builder builder = ImmutableList.builder();
@@ -748,10 +753,10 @@ public void addWhitelistPattern(String urlPattern) {
}
/**
- * Whitelists the specified requests.
+ * Whitelists the specified requests.
*
* Note: This method overwrites any existing whitelist.
- *
+ *
* @param patterns regular expression patterns matching URLs to whitelist
* @param responseCode response code to return for non-whitelisted URLs
*/
@@ -759,10 +764,10 @@ public void addWhitelistPattern(String urlPattern) {
public void whitelistRequests(String[] patterns, int responseCode) {
client.whitelistRequests(patterns, responseCode);
}
-
+
/**
* Enables an empty whitelist, which will return the specified responseCode for all requests.
- *
+ *
* @param responseCode HTTP response code to return for all requests
*/
@Override
@@ -799,7 +804,7 @@ public void removeHeader(String name) {
@Override
public void removeAllHeaders() {
- client.setAdditionalHeaders(Collections.emptyMap());
+ client.setAdditionalHeaders(Collections.emptyMap());
}
@Override
@@ -847,7 +852,7 @@ public void setCaptureHeaders(boolean captureHeaders) {
public void setCaptureContent(boolean captureContent) {
client.setCaptureContent(captureContent);
}
-
+
@Override
public void setCaptureBinaryContent(boolean captureBinaryContent) {
client.setCaptureBinaryContent(captureBinaryContent);
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/BrowserMobHttpClient.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/BrowserMobHttpClient.java
index 00cdd8179..62c56d8d7 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/BrowserMobHttpClient.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/BrowserMobHttpClient.java
@@ -127,7 +127,7 @@ public class BrowserMobHttpClient {
private static final String VERSION = "2.1";
private static final Logger LOG = LoggerFactory.getLogger(BrowserMobHttpClient.class);
-
+
private static final int BUFFER = 4096;
private volatile Har har;
@@ -137,7 +137,7 @@ public class BrowserMobHttpClient {
* keep headers
*/
private volatile boolean captureHeaders;
-
+
/**
* keep contents
*/
@@ -152,7 +152,7 @@ public class BrowserMobHttpClient {
* socket factory dedicated to port 80 (HTTP)
*/
private final SimulatedSocketFactory socketFactory;
-
+
/**
* socket factory dedicated to port 443 (HTTPS)
*/
@@ -160,51 +160,56 @@ public class BrowserMobHttpClient {
private final PoolingHttpClientConnectionManager httpClientConnMgr;
-
+
/**
* Builders for httpClient
* Each time you change their configuration you should call updateHttpClient()
*/
private final Builder requestConfigBuilder;
private final HttpClientBuilder httpClientBuilder;
-
+
/**
* The current httpClient which will execute HTTP requests
*/
private volatile CloseableHttpClient httpClient;
-
+
private final BasicCookieStore cookieStore = new BasicCookieStore();
-
+
/**
* List of rejected URL patterns
*/
private final Collection blacklistEntries = new CopyOnWriteArrayList();
-
+
/**
* List of accepted URL patterns
*/
private volatile Whitelist whitelist = Whitelist.WHITELIST_DISABLED;
-
+
/**
* List of URLs to rewrite
*/
private final CopyOnWriteArrayList rewriteRules = new CopyOnWriteArrayList();
-
+
/**
* triggers to process when sending request
*/
private final List requestInterceptors = new CopyOnWriteArrayList();
-
+
/**
* triggers to process when receiving response
*/
private final List responseInterceptors = new CopyOnWriteArrayList();
-
+
/**
* additional headers sent with request
*/
private final Map additionalHeaders = new ConcurrentHashMap();
-
+
+ /**
+ * Regexp to check request url and inject headers if url match regexp.
+ */
+ private static String headersFilterRegexp;
+
/**
* request timeout: set to -1 to disable timeout
*/
@@ -214,7 +219,7 @@ public class BrowserMobHttpClient {
* is it possible to add a new request?
*/
private final AtomicBoolean allowNewRequests = new AtomicBoolean(true);
-
+
/**
* Hostname resolver that wraps a {@link net.lightbody.bmp.proxy.dns.HostResolver}. The wrapped HostResolver can be replaced safely at
* runtime using {@link LegacyHostResolverAdapter#setResolver(net.lightbody.bmp.proxy.dns.AdvancedHostResolver)}.
@@ -226,22 +231,22 @@ public class BrowserMobHttpClient {
* does the proxy support gzip compression? (set to false if you go through a browser)
*/
private boolean decompress = true;
-
+
/**
* set of active requests
*/
private final Set activeRequests = Collections.newSetFromMap(new ConcurrentHashMap());
-
+
/**
* credentials used for authentication
*/
private WildcardMatchingCredentialsProvider credsProvider;
-
+
/**
* is the client shutdown?
*/
private volatile boolean shutdown = false;
-
+
/**
* authentication type used
*/
@@ -251,17 +256,17 @@ public class BrowserMobHttpClient {
* does the proxy follow redirects? (set to false if you go through a browser)
*/
private boolean followRedirects = true;
-
+
/**
* maximum redirects supported by the proxy
*/
private static final int MAX_REDIRECT = 10;
-
+
/**
* remaining requests counter
*/
private final AtomicInteger requestCounter;
-
+
/**
* Init HTTP client
* @param streamManager will be capped to 100 Megabits (by default it is disabled)
@@ -276,13 +281,13 @@ public BrowserMobHttpClient(final StreamManager streamManager, AtomicInteger req
.setConnectionRequestTimeout(60000)
.setConnectTimeout(2000)
.setSocketTimeout(60000);
-
+
// we associate each SocketFactory with their protocols
Registry registry = RegistryBuilder.create()
.register("http", this.socketFactory)
.register("https", this.sslSocketFactory)
.build();
-
+
httpClientConnMgr = new PoolingHttpClientConnectionManager(registry, resolverWrapper) {
@Override
public ConnectionRequest requestConnection(HttpRoute route, Object state) {
@@ -312,7 +317,7 @@ public boolean cancel() {
credsProvider = new WildcardMatchingCredentialsProvider();
httpClientBuilder = getDefaultHttpClientBuilder(streamManager);
httpClient = httpClientBuilder.build();
-
+
HttpClientInterrupter.watch(this);
}
@@ -324,10 +329,10 @@ private HttpClientBuilder getDefaultHttpClientBuilder(final StreamManager stream
@Override
protected HttpResponse doSendRequest(HttpRequest request, HttpClientConnection conn, HttpContext context) throws IOException, HttpException {
long start = System.nanoTime();
-
+
// send request
HttpResponse response = super.doSendRequest(request, conn, context);
-
+
// set "sending" for resource
RequestInfo.get().send(start, System.nanoTime());
return response;
@@ -337,7 +342,7 @@ protected HttpResponse doSendRequest(HttpRequest request, HttpClientConnection c
protected HttpResponse doReceiveResponse(HttpRequest request, HttpClientConnection conn, HttpContext context) throws HttpException, IOException {
long start = System.nanoTime();
HttpResponse response = super.doReceiveResponse(request, conn, context);
-
+
// +4 => header/data separation
long responseHeadersSize = response.getStatusLine().toString().length() + 4;
for (Header header : response.getAllHeaders()) {
@@ -363,7 +368,7 @@ protected HttpResponse doReceiveResponse(HttpRequest request, HttpClientConnecti
}
// set waiting time
RequestInfo.get().wait(start, System.nanoTime());
-
+
return response;
}
})
@@ -471,7 +476,7 @@ public BrowserMobHttpRequest newGet(String url, net.lightbody.bmp.proxy.jetty.ht
throw reportBadURI(url, "GET", e);
}
}
-
+
public BrowserMobHttpRequest newPatch(String url, net.lightbody.bmp.proxy.jetty.http.HttpRequest proxyRequest) {
try {
URI uri = makeUri(url);
@@ -589,7 +594,7 @@ public void checkTimeout() {
for (ActiveRequest activeRequest : activeRequests) {
activeRequest.checkTimeout();
}
-
+
// Close expired connections
httpClientConnMgr.closeExpiredConnections();
// Optionally, close connections
@@ -601,7 +606,7 @@ public BrowserMobHttpResponse execute(BrowserMobHttpRequest req) {
if (!allowNewRequests.get()) {
throw new RuntimeException("No more requests allowed");
}
-
+
try {
requestCounter.incrementAndGet();
@@ -632,7 +637,7 @@ private BrowserMobHttpResponse execute(BrowserMobHttpRequest req, int depth) {
HttpRequestBase method = req.getMethod();
String url = method.getURI().toString();
-
+
// process any rewrite requests
boolean rewrote = false;
String newUrl = url;
@@ -663,7 +668,7 @@ private BrowserMobHttpResponse execute(BrowserMobHttpRequest req, int depth) {
break;
}
}
-
+
// url does not match whitelist, set the response code
if (!found) {
mockResponseCode = currentWhitelist.getResponseCode();
@@ -698,7 +703,7 @@ private BrowserMobHttpResponse execute(BrowserMobHttpRequest req, int depth) {
if (os == null) {
os = new CappedByteArrayOutputStream(1024 * 1024); // MOB-216 don't buffer more than 1 MB
}
-
+
// link the object up now, before we make the request, so that if we get cut off (ie: favicon.ico request and browser shuts down)
// we still have the attempt associated, even if we never got a response
HarEntry entry = new HarEntry(harPageRef);
@@ -815,10 +820,10 @@ public HeaderElement[] getElements() throws ParseException {
if(decompress && response.getEntity().getContentLength() != 0) { //getContentLength<0 if unknown
if (gzipping) {
is = new GZIPInputStream(is);
- } else if (deflating) {
+ } else if (deflating) {
// RAW deflate only
// WARN : if system is using zlib<=1.1.4 the stream must be append with a dummy byte
- // that is not requiered for zlib>1.1.4 (not mentioned on current Inflater javadoc)
+ // that is not requiered for zlib>1.1.4 (not mentioned on current Inflater javadoc)
is = new InflaterInputStream(is, new Inflater(true));
}
}
@@ -903,8 +908,8 @@ public HeaderElement[] getElements() throws ParseException {
}
}
}
-
-
+
+
// +4 => header/data separation
long requestHeadersSize = method.getRequestLine().toString().length() + 4;
long requestBodySize = 0;
@@ -919,7 +924,7 @@ public HeaderElement[] getElements() throws ParseException {
entry.getRequest().setHeadersSize(requestHeadersSize);
entry.getRequest().setBodySize(requestBodySize);
if (captureContent) {
-
+
// can we understand the POST data at all?
if (method instanceof HttpEntityEnclosingRequestBase && req.getCopy() != null) {
HttpEntityEnclosingRequestBase enclosingReq = (HttpEntityEnclosingRequestBase) method;
@@ -950,7 +955,7 @@ public HeaderElement[] getElements() throws ParseException {
LOG.info("Unexpected problem when parsing input copy", e);
} catch (RuntimeException e) {
LOG.info("Unexpected problem when parsing input copy", e);
- }
+ }
} else {
// not URL encoded, so let's grab the body of the POST and capture that
try {
@@ -988,12 +993,12 @@ public HeaderElement[] getElements() throws ParseException {
// ok, we need to decompress it before we can put it in the har file
try {
InputStream temp = null;
- if(gzipping){
+ if(gzipping){
temp = new GZIPInputStream(new ByteArrayInputStream(copy.toByteArray()));
} else if (deflating) {
// RAW deflate only?
// WARN : if system is using zlib<=1.1.4 the stream must be append with a dummy byte
- // that is not requiered for zlib>1.1.4 (not mentioned on current Inflater javadoc)
+ // that is not requiered for zlib>1.1.4 (not mentioned on current Inflater javadoc)
temp = new InflaterInputStream(new ByteArrayInputStream(copy.toByteArray()), new Inflater(true));
}
copy = new ByteArrayOutputStream();
@@ -1001,7 +1006,7 @@ public HeaderElement[] getElements() throws ParseException {
} catch (IOException e) {
throw new RuntimeException("Error when decompressing input stream", e);
}
- }
+ }
if (hasTextualContent(contentType)) {
setTextOfEntry(entry, copy, contentType);
@@ -1095,7 +1100,8 @@ private boolean hasTextualContent(String contentType) {
contentType.startsWith("application/javascript") ||
contentType.startsWith("application/json") ||
contentType.startsWith("application/xml") ||
- contentType.startsWith("application/xhtml+xml");
+ contentType.startsWith("application/xhtml+xml") ||
+ (contentType.startsWith("application/") && contentType.endsWith("+json"));
}
private void setBinaryContentOfEntry(HarEntry entry, ByteArrayOutputStream copy) {
@@ -1113,7 +1119,7 @@ private void setTextOfEntry(HarEntry entry, ByteArrayOutputStream copy, String c
}
}
-
+
public void shutdown() {
shutdown = true;
abortActiveRequests();
@@ -1129,7 +1135,7 @@ public void abortActiveRequests() {
for (ActiveRequest activeRequest : activeRequests) {
activeRequest.abort();
}
-
+
activeRequests.clear();
}
@@ -1221,10 +1227,10 @@ public void blacklistRequests(String pattern, int responseCode, String method) {
public List getBlacklistedRequests() {
List blacklist = new ArrayList(blacklistEntries.size());
blacklist.addAll(blacklistEntries);
-
+
return blacklist;
}
-
+
public Collection getBlacklistedUrls() {
return blacklistEntries;
}
@@ -1236,7 +1242,7 @@ public void clearBlacklist() {
public boolean isWhitelistEnabled() {
return whitelist.isEnabled();
}
-
+
/**
* @deprecated use getWhitelistUrls()
* @return unmodifiable list of whitelisted Patterns
@@ -1245,19 +1251,19 @@ public boolean isWhitelistEnabled() {
public List getWhitelistRequests() {
List whitelistPatterns = new ArrayList(whitelist.getPatterns().size());
whitelistPatterns.addAll(whitelist.getPatterns());
-
+
return Collections.unmodifiableList(whitelistPatterns);
}
-
+
/**
* Retrieves Patterns of URLs that have been whitelisted.
- *
+ *
* @return unmodifiable whitelisted URL Patterns
*/
public Collection getWhitelistUrls() {
return whitelist.getPatterns();
}
-
+
public int getWhitelistResponseCode() {
return whitelist.getResponseCode();
}
@@ -1265,9 +1271,9 @@ public int getWhitelistResponseCode() {
/**
* Whitelist the specified request patterns, returning the specified responseCode for non-whitelisted
* requests.
- *
- * @param patterns regular expression strings matching URL patterns to whitelist. if empty or null,
- * the whitelist will be enabled but will not match any URLs.
+ *
+ * @param patterns regular expression strings matching URL patterns to whitelist. if empty or null,
+ * the whitelist will be enabled but will not match any URLs.
* @param responseCode the HTTP response code to return for non-whitelisted requests
*/
public void whitelistRequests(String[] patterns, int responseCode) {
@@ -1277,14 +1283,14 @@ public void whitelistRequests(String[] patterns, int responseCode) {
whitelist = new Whitelist(patterns, responseCode);
}
}
-
+
/**
- * Clears and disables the current whitelist.
+ * Clears and disables the current whitelist.
*/
public void clearWhitelist() {
whitelist = Whitelist.WHITELIST_DISABLED;
}
-
+
public void addHeader(String name, String value) {
additionalHeaders.put(name, value);
}
@@ -1315,7 +1321,7 @@ public void validate(Cookie cookie, CookieOrigin origin)
};
}
};
-
+
Registry r = RegistryBuilder.create()
.register(CookieSpecs.BEST_MATCH,
new BestMatchSpecFactory())
@@ -1323,15 +1329,15 @@ public void validate(Cookie cookie, CookieOrigin origin)
new BrowserCompatSpecFactory())
.register("easy", easySpecProvider)
.build();
-
+
RequestConfig requestConfig = RequestConfig.custom()
.setCookieSpec("easy")
.build();
-
+
httpClientBuilder.setDefaultCookieSpecRegistry(r)
.setDefaultRequestConfig(requestConfig);
updateHttpClient();
-
+
decompress = false;
setFollowRedirects(false);
}
@@ -1340,13 +1346,13 @@ public void validate(Cookie cookie, CookieOrigin origin)
* CloseableHttpClient doesn't permit anymore to change parameters easily.
* This method allow you to rebuild the httpClientBuilder to get the CloseableHttpClient
* When the config is changed.
- *
+ *
* So httpClient reference change this may lead to concurrency issue.
*/
private void updateHttpClient(){
httpClient = httpClientBuilder.build();
}
-
+
public String remappedHost(String host) {
if (resolverWrapper.getResolver() instanceof AdvancedHostResolver) {
AdvancedHostResolver advancedHostResolver = (AdvancedHostResolver) resolverWrapper.getResolver();
@@ -1422,7 +1428,7 @@ class ActiveRequest {
this.request = request;
this.start = start;
}
-
+
/**
* Checks the timeout for this request, and aborts if necessary.
* @return true if the request was aborted for exceeding its timeout, otherwise false.
@@ -1431,7 +1437,7 @@ boolean checkTimeout() {
if (aborting.get()) {
return false;
}
-
+
if (requestTimeout != -1) {
if (request != null && start != null && new Date(System.currentTimeMillis() - requestTimeout).after(start)) {
boolean okayToAbort = aborting.compareAndSet(false, true);
@@ -1439,18 +1445,18 @@ boolean checkTimeout() {
LOG.info("Aborting request to {} after it failed to complete in {} ms", request.getURI().toString(), requestTimeout);
abort();
-
+
return true;
}
}
}
-
+
return false;
}
public void abort() {
request.abort();
-
+
// no need to close the connection -- the call to request.abort() releases the connection itself
}
}
@@ -1512,6 +1518,14 @@ public static long copyWithStats(InputStream is, OutputStream os) throws IOExcep
return bytesCopied;
}
+ public String getHeadersFilterRegexp() {
+ return headersFilterRegexp;
+ }
+
+ public void setHeadersFilterRegexp(String headersFilterRegexp) {
+ this.headersFilterRegexp = headersFilterRegexp;
+ }
+
public boolean isCaptureBinaryContent() {
return captureBinaryContent;
}
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/TrustingSSLSocketFactory.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/TrustingSSLSocketFactory.java
index 3b68802c5..bdf8bfa7a 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/TrustingSSLSocketFactory.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/http/TrustingSSLSocketFactory.java
@@ -34,16 +34,11 @@ public enum SSLAlgorithm {
private StreamManager streamManager;
static {
- sslContext = SSLContexts.createDefault();
+ sslContext = org.apache.http.ssl.SSLContexts.createDefault();
try {
- sslContext = SSLContexts.custom().loadTrustMaterial(null,
- new TrustStrategy() {
- @Override
- public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- return true;
- }
- }
- ).build();
+ sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null,
+ (TrustStrategy) (chain, authType) -> true
+ ).build();
sslContext.init(null, new TrustManager[]{new TrustEverythingSSLTrustManager()}, null);
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/http/SunJsseListener.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/http/SunJsseListener.java
index 0c2262bba..89b64a54a 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/http/SunJsseListener.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/http/SunJsseListener.java
@@ -15,13 +15,12 @@
package net.lightbody.bmp.proxy.jetty.http;
-import com.sun.net.ssl.*;
import net.lightbody.bmp.proxy.jetty.log.LogFactory;
import net.lightbody.bmp.proxy.jetty.util.InetAddrPort;
import net.lightbody.bmp.proxy.jetty.util.Password;
import org.apache.commons.logging.Log;
-import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
@@ -30,25 +29,26 @@
/* ------------------------------------------------------------ */
-/** SSL Socket Listener for Sun's JSSE.
- *
+
+/**
+ * SSL Socket Listener for Sun's JSSE.
+ *
* This specialization of JsseListener is an specific listener
* using the Sun reference implementation.
- *
+ *
* This is heavily based on the work from Court Demas, which in
* turn is based on the work from Forge Research.
*
- * @version $Id: SunJsseListener.java,v 1.20 2005/08/13 00:01:24 gregwilkins Exp $
- * @deprecated Use org.mortbay.http.SslListener
* @author Greg Wilkins (gregw@mortbay.com)
* @author Court Demas (court@kiwiconsulting.com)
* @author Forge Research Pty Ltd ACN 003 491 576
+ * @version $Id: SunJsseListener.java,v 1.20 2005/08/13 00:01:24 gregwilkins Exp $
+ * @deprecated Use org.mortbay.http.SslListener
**/
-public class SunJsseListener extends JsseListener
-{
+public class SunJsseListener extends JsseListener {
private static Log log = LogFactory.getLog(SunJsseListener.class);
- private String _keystore=DEFAULT_KEYSTORE ;
+ private String _keystore = DEFAULT_KEYSTORE;
private transient Password _password;
private transient Password _keypassword;
private String _keystore_type = DEFAULT_KEYSTORE_TYPE;
@@ -56,149 +56,136 @@ public class SunJsseListener extends JsseListener
private String _keystore_provider_class = DEFAULT_KEYSTORE_PROVIDER_CLASS;
private boolean _useDefaultTrustStore = false;
- /* ------------------------------------------------------------ */
- static
- {
- Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
- }
/* ------------------------------------------------------------ */
- public void setKeystore(String keystore)
- {
+ public void setKeystore(String keystore) {
_keystore = keystore;
}
-
+
/* ------------------------------------------------------------ */
- public String getKeystore()
- {
+ public String getKeystore() {
return _keystore;
}
-
+
/* ------------------------------------------------------------ */
- public void setPassword(String password)
- {
- _password = Password.getPassword(PASSWORD_PROPERTY,password,null);
+ public void setPassword(String password) {
+ _password = Password.getPassword(PASSWORD_PROPERTY, password, null);
}
/* ------------------------------------------------------------ */
- public void setKeyPassword(String password)
- {
- _keypassword = Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
+ public void setKeyPassword(String password) {
+ _keypassword = Password.getPassword(KEYPASSWORD_PROPERTY, password, null);
}
-
-
+
+
/* ------------------------------------------------------------ */
- public void setKeystoreType(String keystore_type)
- {
+ public void setKeystoreType(String keystore_type) {
_keystore_type = keystore_type;
}
-
+
/* ------------------------------------------------------------ */
- public String getKeystoreType()
- {
+ public String getKeystoreType() {
return _keystore_type;
}
/* ------------------------------------------------------------ */
- public void setKeystoreProviderName(String name)
- {
+ public void setKeystoreProviderName(String name) {
_keystore_provider_name = name;
}
/* ------------------------------------------------------------ */
- public String getKeystoreProviderName()
- {
+ public String getKeystoreProviderName() {
return _keystore_provider_name;
}
/* ------------------------------------------------------------ */
- public String getKeystoreProviderClass()
- {
+ public String getKeystoreProviderClass() {
return _keystore_provider_class;
}
/* ------------------------------------------------------------ */
- public void setKeystoreProviderClass(String classname)
- {
+ public void setKeystoreProviderClass(String classname) {
_keystore_provider_class = classname;
}
/* ------------------------------------------------------------ */
+
/**
* Gets the default trust store flag.
*
* @return true if the default truststore will be used to initialize the
* TrustManager, false otherwise.
*/
- public boolean getUseDefaultTrustStore()
- {
+ public boolean getUseDefaultTrustStore() {
return _useDefaultTrustStore;
}
/* ------------------------------------------------------------ */
+
/**
* Set a flag to determine if the default truststore should be used to
* initialize the TrustManager. The default truststore will typically be
* the ${JAVA_HOME}/jre/lib/security/cacerts.
*
* @param flag if true, the default truststore will be used. If false, the
- * configured keystore will be used as the truststore.
+ * configured keystore will be used as the truststore.
*/
- public void setUseDefaultTrustStore(boolean flag)
- {
+ public void setUseDefaultTrustStore(boolean flag) {
_useDefaultTrustStore = flag;
}
/* ------------------------------------------------------------ */
- /** Constructor.
+
+ /**
+ * Constructor.
*/
- public SunJsseListener()
- {
+ public SunJsseListener() {
super();
}
/* ------------------------------------------------------------ */
- /** Constructor.
- * @param p_address
+
+ /**
+ * Constructor.
+ *
+ * @param p_address
*/
- public SunJsseListener(InetAddrPort p_address)
- {
- super( p_address);
+ public SunJsseListener(InetAddrPort p_address) {
+ super(p_address);
}
-
+
/* ------------------------------------------------------------ */
- /*
- * @return
- * @exception Exception
+ /*
+ * @return
+ * @exception Exception
*/
protected SSLServerSocketFactory createFactory()
- throws Exception
- {
- _keystore = System.getProperty( KEYSTORE_PROPERTY,_keystore);
-
- log.info(KEYSTORE_PROPERTY+"="+_keystore);
-
- if (_password==null)
- _password = Password.getPassword(PASSWORD_PROPERTY,null,null);
- log.info(PASSWORD_PROPERTY+"="+_password.toStarString());
-
- if (_keypassword==null)
+ throws Exception {
+ _keystore = System.getProperty(KEYSTORE_PROPERTY, _keystore);
+
+ log.info(KEYSTORE_PROPERTY + "=" + _keystore);
+
+ if (_password == null)
+ _password = Password.getPassword(PASSWORD_PROPERTY, null, null);
+ log.info(PASSWORD_PROPERTY + "=" + _password.toStarString());
+
+ if (_keypassword == null)
_keypassword = Password.getPassword(KEYPASSWORD_PROPERTY,
- null,
- _password.toString());
- log.info(KEYPASSWORD_PROPERTY+"="+_keypassword.toStarString());
+ null,
+ _password.toString());
+ log.info(KEYPASSWORD_PROPERTY + "=" + _keypassword.toStarString());
KeyStore ks = null;
- log.info(KEYSTORE_TYPE_PROPERTY+"="+_keystore_type);
-
+ log.info(KEYSTORE_TYPE_PROPERTY + "=" + _keystore_type);
+
if (_keystore_provider_class != null) {
// find provider.
// avoid creating another instance if already installed in Security.
java.security.Provider[] installed_providers = Security.getProviders();
java.security.Provider myprovider = null;
- for (int i=0; i < installed_providers.length; i++) {
+ for (int i = 0; i < installed_providers.length; i++) {
if (installed_providers[i].getClass().getName().equals(_keystore_provider_class)) {
myprovider = installed_providers[i];
break;
@@ -209,37 +196,37 @@ protected SSLServerSocketFactory createFactory()
myprovider = (java.security.Provider) Class.forName(_keystore_provider_class).newInstance();
Security.addProvider(myprovider);
}
- log.info(KEYSTORE_PROVIDER_CLASS_PROPERTY+"="+_keystore_provider_class);
- ks = KeyStore.getInstance(_keystore_type,myprovider.getName());
+ log.info(KEYSTORE_PROVIDER_CLASS_PROPERTY + "=" + _keystore_provider_class);
+ ks = KeyStore.getInstance(_keystore_type, myprovider.getName());
} else if (_keystore_provider_name != null) {
- log.info(KEYSTORE_PROVIDER_NAME_PROPERTY+"="+_keystore_provider_name);
- ks = KeyStore.getInstance(_keystore_type,_keystore_provider_name);
+ log.info(KEYSTORE_PROVIDER_NAME_PROPERTY + "=" + _keystore_provider_name);
+ ks = KeyStore.getInstance(_keystore_type, _keystore_provider_name);
} else {
ks = KeyStore.getInstance(_keystore_type);
- log.info(KEYSTORE_PROVIDER_NAME_PROPERTY+"=[DEFAULT]");
+ log.info(KEYSTORE_PROVIDER_NAME_PROPERTY + "=[DEFAULT]");
}
-
- ks.load( new FileInputStream( new File( _keystore ) ),
- _password.toString().toCharArray());
-
- KeyManagerFactory km = KeyManagerFactory.getInstance( "SunX509","SunJSSE");
- km.init( ks, _keypassword.toString().toCharArray() );
- KeyManager[] kma = km.getKeyManagers();
-
- TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509","SunJSSE");
+
+ ks.load(new FileInputStream(new File(_keystore)),
+ _password.toString().toCharArray());
+
+ KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509", "SunJSSE");
+ km.init(ks, _keypassword.toString().toCharArray());
+ KeyManager[] kma = km.getKeyManagers();
+
+ TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
if (_useDefaultTrustStore) {
- tm.init( (KeyStore)null );
+ tm.init((KeyStore) null);
} else {
- tm.init( ks );
+ tm.init(ks);
}
TrustManager[] tma = tm.getTrustManagers();
-
- SSLContext sslc = SSLContext.getInstance( "SSL" );
- sslc.init( kma, tma, SecureRandom.getInstance("SHA1PRNG"));
-
+
+ SSLContext sslc = SSLContext.getInstance("SSL");
+ sslc.init(kma, tma, SecureRandom.getInstance("SHA1PRNG"));
+
SSLServerSocketFactory ssfc = sslc.getServerSocketFactory();
- log.info("SSLServerSocketFactory="+ssfc);
+ log.info("SSLServerSocketFactory=" + ssfc);
return ssfc;
}
}
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/Server.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/Server.java
index 6b04eafb6..d483f13ef 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/Server.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/Server.java
@@ -35,105 +35,104 @@
/* ------------------------------------------------------------ */
-/** The Jetty HttpServer.
- *
+
+/**
+ * The Jetty HttpServer.
+ *
* This specialization of org.mortbay.http.HttpServer adds knowledge
* about servlets and their specialized contexts. It also included
* support for initialization from xml configuration files
* that follow the XmlConfiguration dtd.
- *
+ *
* HttpContexts created by Server are of the type
* org.mortbay.jetty.servlet.ServletHttpContext unless otherwise
* specified.
- *
+ *
* This class also provides a main() method which starts a server for
* each config file passed on the command line. If the system
* property JETTY_NO_SHUTDOWN_HOOK is not set to true, then a shutdown
- * hook is thread is registered to stop these servers.
+ * hook is thread is registered to stop these servers.
*
+ * @author Greg Wilkins (gregw)
+ * @version $Revision: 1.40 $
* @see net.lightbody.bmp.proxy.jetty.xml.XmlConfiguration
* @see net.lightbody.bmp.proxy.jetty.jetty.servlet.ServletHttpContext
- * @version $Revision: 1.40 $
- * @author Greg Wilkins (gregw)
*/
-public class Server extends HttpServer
-{
+public class Server extends HttpServer {
static Log log = LogFactory.getLog(Server.class);
- private String[] _webAppConfigurationClassNames =
- new String[]{"XMLConfiguration", "JettyWebConfiguration"};
+ private String[] _webAppConfigurationClassNames =
+ new String[]{"XMLConfiguration", "JettyWebConfiguration"};
private String _configuration;
private String _rootWebApp;
private static ShutdownHookThread hookThread = new ShutdownHookThread();
-
+
/* ------------------------------------------------------------ */
- /** Constructor.
+
+ /**
+ * Constructor.
*/
- public Server()
- {
+ public Server() {
}
-
+
/* ------------------------------------------------------------ */
- /** Constructor.
+
+ /**
+ * Constructor.
+ *
* @param configuration The filename or URL of the XML
- * configuration file.
+ * configuration file.
*/
public Server(String configuration)
- throws IOException
- {
+ throws IOException {
this(Resource.newResource(configuration).getURL());
}
-
+
/* ------------------------------------------------------------ */
- /** Constructor.
+
+ /**
+ * Constructor.
+ *
* @param configuration The filename or URL of the XML
- * configuration file.
+ * configuration file.
*/
public Server(Resource configuration)
- throws IOException
- {
+ throws IOException {
this(configuration.getURL());
}
-
+
/* ------------------------------------------------------------ */
- /** Constructor.
+
+ /**
+ * Constructor.
+ *
* @param configuration The filename or URL of the XML
- * configuration file.
+ * configuration file.
*/
public Server(URL configuration)
- throws IOException
- {
- _configuration=configuration.toString();
+ throws IOException {
+ _configuration = configuration.toString();
Server.hookThread.add(this);
- try
- {
- XmlConfiguration config=new XmlConfiguration(configuration);
+ try {
+ XmlConfiguration config = new XmlConfiguration(configuration);
config.configure(this);
- }
- catch(IOException e)
- {
+ } catch (IOException e) {
throw e;
- }
- catch(InvocationTargetException e)
- {
- log.warn(LogSupport.EXCEPTION,e.getTargetException());
- throw new IOException("Jetty configuration problem: "+e.getTargetException());
- }
- catch(Exception e)
- {
- log.warn(LogSupport.EXCEPTION,e);
- throw new IOException("Jetty configuration problem: "+e);
+ } catch (InvocationTargetException e) {
+ log.warn(LogSupport.EXCEPTION, e.getTargetException());
+ throw new IOException("Jetty configuration problem: " + e.getTargetException());
+ } catch (Exception e) {
+ log.warn(LogSupport.EXCEPTION, e);
+ throw new IOException("Jetty configuration problem: " + e);
}
}
/* ------------------------------------------------------------ */
- public boolean getStopAtShutdown()
- {
+ public boolean getStopAtShutdown() {
return hookThread.contains(this);
}
-
+
/* ------------------------------------------------------------ */
- public void setStopAtShutdown(boolean stop)
- {
+ public void setStopAtShutdown(boolean stop) {
if (stop)
hookThread.add(this);
else
@@ -141,268 +140,283 @@ public void setStopAtShutdown(boolean stop)
}
/* ------------------------------------------------------------ */
- /** Get the root webapp name.
- * @return The name of the root webapp (eg. "root" for root.war).
+
+ /**
+ * Get the root webapp name.
+ *
+ * @return The name of the root webapp (eg. "root" for root.war).
*/
- public String getRootWebApp()
- {
+ public String getRootWebApp() {
return _rootWebApp;
}
-
+
/* ------------------------------------------------------------ */
- /** Set the root webapp name.
- * @param rootWebApp The name of the root webapp (eg. "root" for root.war).
+
+ /**
+ * Set the root webapp name.
+ *
+ * @param rootWebApp The name of the root webapp (eg. "root" for root.war).
*/
- public void setRootWebApp(String rootWebApp)
- {
+ public void setRootWebApp(String rootWebApp) {
_rootWebApp = rootWebApp;
}
-
+
/* ------------------------------------------------------------ */
- /** Configure the server from an XML file.
+
+ /**
+ * Configure the server from an XML file.
+ *
* @param configuration The filename or URL of the XML
- * configuration file.
+ * configuration file.
*/
public void configure(String configuration)
- throws IOException
- {
+ throws IOException {
- URL url=Resource.newResource(configuration).getURL();
- if (_configuration!=null && _configuration.equals(url.toString()))
+ URL url = Resource.newResource(configuration).getURL();
+ if (_configuration != null && _configuration.equals(url.toString()))
return;
- if (_configuration!=null)
- throw new IllegalStateException("Already configured with "+_configuration);
- try
- {
- XmlConfiguration config=new XmlConfiguration(url);
- _configuration=url.toString();
+ if (_configuration != null)
+ throw new IllegalStateException("Already configured with " + _configuration);
+ try {
+ XmlConfiguration config = new XmlConfiguration(url);
+ _configuration = url.toString();
config.configure(this);
- }
- catch(IOException e)
- {
+ } catch (IOException e) {
throw e;
- }
- catch(Exception e)
- {
- log.warn(LogSupport.EXCEPTION,e);
- throw new IOException("Jetty configuration problem: "+e);
+ } catch (Exception e) {
+ log.warn(LogSupport.EXCEPTION, e);
+ throw new IOException("Jetty configuration problem: " + e);
}
}
-
+
/* ------------------------------------------------------------ */
- public String getConfiguration()
- {
+ public String getConfiguration() {
return _configuration;
}
-
+
/* ------------------------------------------------------------ */
- /** Create a new ServletHttpContext.
+
+ /**
+ * Create a new ServletHttpContext.
* Ths method is called by HttpServer to creat new contexts. Thus
* calls to addContext or getContext that result in a new Context
* being created will return an
* org.mortbay.jetty.servlet.ServletHttpContext instance.
+ *
* @return ServletHttpContext
*/
- protected HttpContext newHttpContext()
- {
+ protected HttpContext newHttpContext() {
return new ServletHttpContext();
}
-
+
/* ------------------------------------------------------------ */
- /** Create a new WebApplicationContext.
- * Ths method is called by Server to creat new contexts for web
- * applications. Thus calls to addWebApplication that result in
+
+ /**
+ * Create a new WebApplicationContext.
+ * Ths method is called by Server to creat new contexts for web
+ * applications. Thus calls to addWebApplication that result in
* a new Context being created will return an correct class instance.
* Derived class can override this method to create instance of its
* own class derived from WebApplicationContext in case it needs more
* functionality.
+ *
* @param webApp The Web application directory or WAR file.
* @return WebApplicationContext
*/
protected WebApplicationContext newWebApplicationContext(
- String webApp
- )
- {
+ String webApp
+ ) {
return new WebApplicationContext(webApp);
}
/* ------------------------------------------------------------ */
- /** Add Web Application.
+
+ /**
+ * Add Web Application.
+ *
* @param contextPathSpec The context path spec. Which must be of
- * the form / or /path/*
- * @param webApp The Web application directory or WAR file.
+ * the form / or /path/*
+ * @param webApp The Web application directory or WAR file.
* @return The WebApplicationContext
- * @exception IOException
+ * @throws IOException
*/
public WebApplicationContext addWebApplication(String contextPathSpec,
String webApp)
- throws IOException
- {
- return addWebApplication(null,contextPathSpec,webApp);
+ throws IOException {
+ return addWebApplication(null, contextPathSpec, webApp);
}
-
+
/* ------------------------------------------------------------ */
- /** Add Web Application.
- * @param virtualHost Virtual host name or null
+
+ /**
+ * Add Web Application.
+ *
+ * @param virtualHost Virtual host name or null
* @param contextPathSpec The context path spec. Which must be of
- * the form / or /path/*
- * @param webApp The Web application directory or WAR file.
+ * the form / or /path/*
+ * @param webApp The Web application directory or WAR file.
* @return The WebApplicationContext
- * @exception IOException
+ * @throws IOException
*/
public WebApplicationContext addWebApplication(String virtualHost,
String contextPathSpec,
String webApp)
- throws IOException
- {
+ throws IOException {
WebApplicationContext appContext =
- newWebApplicationContext(webApp);
+ newWebApplicationContext(webApp);
appContext.setContextPath(contextPathSpec);
- addContext(virtualHost,appContext);
- if(log.isDebugEnabled())log.debug("Web Application "+appContext+" added");
+ addContext(virtualHost, appContext);
+ if (log.isDebugEnabled()) log.debug("Web Application " + appContext + " added");
return appContext;
}
-
+
/* ------------------------------------------------------------ */
- /** Add Web Applications.
+
+ /**
+ * Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If a
* webapp is called "root" it is added at "/".
+ *
* @param webapps Directory file name or URL to look for auto webapplication.
- * @exception IOException
+ * @throws IOException
*/
public WebApplicationContext[] addWebApplications(String webapps)
- throws IOException
- {
- return addWebApplications(null,webapps,null,false);
+ throws IOException {
+ return addWebApplications(null, webapps, null, false);
}
-
+
/* ------------------------------------------------------------ */
- /** Add Web Applications.
+
+ /**
+ * Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp matches the rootWebApp it is added as the "/" context.
- * @param host Virtual host name or null
+ *
+ * @param host Virtual host name or null
* @param webapps Directory file name or URL to look for auto webapplication.
- * @exception IOException
+ * @throws IOException
*/
public WebApplicationContext[] addWebApplications(String host,
String webapps)
- throws IOException
- {
- return addWebApplications(host,webapps,null,false);
+ throws IOException {
+ return addWebApplications(host, webapps, null, false);
}
-
+
/* ------------------------------------------------------------ */
- /** Add Web Applications.
+
+ /**
+ * Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp matches the rootWebApp it is added as the "/" context.
- * @param host Virtual host name or null
+ *
+ * @param host Virtual host name or null
* @param webapps Directory file name or URL to look for auto
- * webapplication.
+ * webapplication.
* @param extract If true, extract war files
- * @exception IOException
+ * @throws IOException
*/
public WebApplicationContext[] addWebApplications(String host,
String webapps,
boolean extract)
- throws IOException
- {
- return addWebApplications(host,webapps,null,extract);
+ throws IOException {
+ return addWebApplications(host, webapps, null, extract);
}
-
+
/* ------------------------------------------------------------ */
- /** Add Web Applications.
+
+ /**
+ * Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp matches the rootWebApp it is added as the "/" context.
- * @param host Virtual host name or null
- * @param webapps Directory file name or URL to look for auto
- * webapplication.
+ *
+ * @param host Virtual host name or null
+ * @param webapps Directory file name or URL to look for auto
+ * webapplication.
* @param defaults The defaults xml filename or URL which is
- * loaded before any in the web app. Must respect the web.dtd.
- * If null the default defaults file is used. If the empty string, then
- * no defaults file is used.
- * @param extract If true, extract war files
- * @exception IOException
+ * loaded before any in the web app. Must respect the web.dtd.
+ * If null the default defaults file is used. If the empty string, then
+ * no defaults file is used.
+ * @param extract If true, extract war files
+ * @throws IOException
*/
public WebApplicationContext[] addWebApplications(String host,
String webapps,
String defaults,
boolean extract)
- throws IOException
- {
- return addWebApplications(host,webapps,defaults,extract,true);
+ throws IOException {
+ return addWebApplications(host, webapps, defaults, extract, true);
}
/* ------------------------------------------------------------ */
- /** Add Web Applications.
+
+ /**
+ * Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp matches the rootWebApp it is added as the "/" context.
- * @param host Virtual host name or null
- * @param webapps Directory file name or URL to look for auto
- * webapplication.
- * @param defaults The defaults xml filename or URL which is
- * loaded before any in the web app. Must respect the web.dtd.
- * If null the default defaults file is used. If the empty string, then
- * no defaults file is used.
- * @param extract If true, extract war files
+ *
+ * @param host Virtual host name or null
+ * @param webapps Directory file name or URL to look for auto
+ * webapplication.
+ * @param defaults The defaults xml filename or URL which is
+ * loaded before any in the web app. Must respect the web.dtd.
+ * If null the default defaults file is used. If the empty string, then
+ * no defaults file is used.
+ * @param extract If true, extract war files
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
- * @exception IOException
+ * @throws IOException
*/
public WebApplicationContext[] addWebApplications(String host,
String webapps,
String defaults,
boolean extract,
- boolean java2CompliantClassLoader)
- throws IOException
- {
+ boolean java2CompliantClassLoader)
+ throws IOException {
ArrayList wacs = new ArrayList();
- Resource r=Resource.newResource(webapps);
+ Resource r = Resource.newResource(webapps);
if (!r.exists())
- throw new IllegalArgumentException("No such webapps resource "+r);
-
+ throw new IllegalArgumentException("No such webapps resource " + r);
+
if (!r.isDirectory())
- throw new IllegalArgumentException("Not directory webapps resource "+r);
-
- String[] files=r.list();
-
- for (int f=0;files!=null && f
+ * Thread is hooked first time list of servers is changed.
*/
- private void createShutdownHook() {
- if (!Boolean.getBoolean("JETTY_NO_SHUTDOWN_HOOK") && !hooked) {
- try {
- Method shutdownHook = java.lang.Runtime.class.getMethod("addShutdownHook",
- new Class[] { java.lang.Thread.class });
- shutdownHook.invoke(Runtime.getRuntime(), new Object[] { this });
- this.hooked = true;
- } catch (Exception e) {
- if (log.isDebugEnabled()) log.debug("No shutdown hook in JVM ", e);
+ private static class ShutdownHookThread extends Thread {
+ private boolean hooked = false;
+ private ArrayList servers = new ArrayList();
+
+ /**
+ * Hooks this thread for shutdown.
+ *
+ * @see java.lang.Runtime#addShutdownHook(java.lang.Thread)
+ */
+ private void createShutdownHook() {
+ if (!Boolean.getBoolean("JETTY_NO_SHUTDOWN_HOOK") && !hooked) {
+ try {
+ Method shutdownHook = java.lang.Runtime.class.getMethod("addShutdownHook",
+ new Class[]{java.lang.Thread.class});
+ shutdownHook.invoke(Runtime.getRuntime(), new Object[]{this});
+ this.hooked = true;
+ } catch (Exception e) {
+ if (log.isDebugEnabled()) log.debug("No shutdown hook in JVM ", e);
+ }
+ }
}
- }
- }
- /**
- * Add Server to servers list.
- */
- public boolean add(Server server) {
- createShutdownHook();
- return this.servers.add(server);
- }
-
- /**
- * Contains Server in servers list?
- */
- public boolean contains(Server server) {
- return this.servers.contains(server);
- }
+ /**
+ * Add Server to servers list.
+ */
+ public boolean add(Server server) {
+ createShutdownHook();
+ return this.servers.add(server);
+ }
- /**
- * Append all Servers from Collection
- */
- public boolean addAll(Collection c) {
- createShutdownHook();
- return this.servers.addAll(c);
- }
+ /**
+ * Contains Server in servers list?
+ */
+ public boolean contains(Server server) {
+ return this.servers.contains(server);
+ }
- /**
- * Clear list of Servers.
- */
- public void clear() {
- createShutdownHook();
- this.servers.clear();
- }
+ /**
+ * Append all Servers from Collection
+ */
+ public boolean addAll(Collection c) {
+ createShutdownHook();
+ return this.servers.addAll(c);
+ }
- /**
- * Remove Server from list.
- */
- public boolean remove(Server server) {
- createShutdownHook();
- return this.servers.remove(server);
- }
+ /**
+ * Clear list of Servers.
+ */
+ public void clear() {
+ createShutdownHook();
+ this.servers.clear();
+ }
- /**
- * Remove all Servers in Collection from list.
- */
- public boolean removeAll(Collection c) {
- createShutdownHook();
- return this.servers.removeAll(c);
- }
+ /**
+ * Remove Server from list.
+ */
+ public boolean remove(Server server) {
+ createShutdownHook();
+ return this.servers.remove(server);
+ }
- /**
- * Stop all Servers in list.
- */
- public void run() {
- setName("Shutdown");
- log.info("Shutdown hook executing");
- Iterator it = servers.iterator();
- while (it.hasNext()) {
- Server svr = (Server) it.next();
- if (svr == null) continue;
- try {
- svr.stop();
- } catch (Exception e) {
- log.warn(LogSupport.EXCEPTION, e);
+ /**
+ * Remove all Servers in Collection from list.
+ */
+ public boolean removeAll(Collection c) {
+ createShutdownHook();
+ return this.servers.removeAll(c);
}
- log.info("Shutdown hook complete");
- // Try to avoid JVM crash
- try {
- Thread.sleep(1000);
- } catch (Exception e) {
- log.warn(LogSupport.EXCEPTION, e);
+ /**
+ * Stop all Servers in list.
+ */
+ public void run() {
+ setName("Shutdown");
+ log.info("Shutdown hook executing");
+ Iterator it = servers.iterator();
+ while (it.hasNext()) {
+ Server svr = (Server) it.next();
+ if (svr == null) continue;
+ try {
+ svr.stop();
+ } catch (Exception e) {
+ log.warn(LogSupport.EXCEPTION, e);
+ }
+ log.info("Shutdown hook complete");
+
+ // Try to avoid JVM crash
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e) {
+ log.warn(LogSupport.EXCEPTION, e);
+ }
+ }
}
- }
}
- }
}
diff --git a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/servlet/ServletHandler.java b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/servlet/ServletHandler.java
index 220af438d..78414813c 100644
--- a/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/servlet/ServletHandler.java
+++ b/browsermob-legacy/src/main/java/net/lightbody/bmp/proxy/jetty/jetty/servlet/ServletHandler.java
@@ -30,6 +30,7 @@
import org.apache.commons.logging.Log;
import javax.servlet.*;
+import javax.servlet.descriptor.JspConfigDescriptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@@ -43,50 +44,52 @@
/* --------------------------------------------------------------------- */
-/** Servlet HttpHandler.
+
+/**
+ * Servlet HttpHandler.
* This handler maps requests to servlets that implement the
* javax.servlet.http.HttpServlet API.
- *
+ *
* This handler does not implement the full J2EE features and is intended to
* be used when a full web application is not required. Specifically filters
* and request wrapping are not supported.
- *
+ *
* If a SessionManager is not added to the handler before it is
* initialized, then a HashSessionManager with a standard
* java.util.Random generator is created.
- *