All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.com.agic.apptesting.utils.impl.BrowsermobProxyUtilsImpl Maven / Gradle / Ivy

package au.com.agic.apptesting.utils.impl;

import static com.google.common.base.Preconditions.checkNotNull;

import au.com.agic.apptesting.exception.ProxyException;
import au.com.agic.apptesting.utils.FileSystemUtils;
import au.com.agic.apptesting.utils.LocalProxyUtils;
import au.com.agic.apptesting.utils.ProxyDetails;
import au.com.agic.apptesting.utils.ProxySettings;
import au.com.agic.apptesting.utils.ServerPortUtils;
import au.com.agic.apptesting.utils.SystemPropertyUtils;

import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.filters.ResponseFilter;
import net.lightbody.bmp.proxy.auth.AuthType;
import net.lightbody.bmp.util.HttpMessageContents;
import net.lightbody.bmp.util.HttpMessageInfo;

import org.apache.commons.lang3.StringUtils;
import org.littleshoot.proxy.HttpFiltersSourceAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.validation.constraints.NotNull;

import io.netty.handler.codec.http.HttpResponse;

/**
 * An implementation of the browsermob proxy. This proxy allows us to block access to urls
 * and can work with an upstream proxy like ZAP.
 */
public class BrowsermobProxyUtilsImpl implements LocalProxyUtils {

	public static final String PROXY_NAME = "BROWSERMOB";
	/**
	 * This is the name of the key that will be saved in ProxyDetails properties
	 * that keeps track of any error responses that have been passed through the
	 * proxy.
	 */
	public static final String INVALID_REQUESTS = "Invalid Requests";
	private static final Logger LOGGER = LoggerFactory.getLogger(BrowsermobProxyUtilsImpl.class);
	private static final SystemPropertyUtils SYSTEM_PROPERTY_UTILS = new SystemPropertyUtilsImpl();
	private static final ServerPortUtils SERVER_PORT_UTILS = new ServerPortUtilsImpl();
	private static final FileSystemUtils FILE_SYSTEM_UTILS = new FileSystemUtilsImpl();

	private static final int WAIT_FOR_START = 30000;
	private static final int START_HTTP_ERROR = 400;
	private static final int END_HTTP_ERROR = 599;

	@Override
	public Optional> initProxy(
			@NotNull final List tempFolders,
			@NotNull final Optional upstreamProxy) {
		checkNotNull(tempFolders);

		try {
			return Optional.of(startBrowsermobProxy(upstreamProxy));
		} catch (final Exception ex) {
			throw new ProxyException(ex);
		}
	}

	/**
	 * Starts the Browsermob Proxy
	 *
	 * @return The port that the proxy is listening on
	 */
	private ProxyDetails startBrowsermobProxy(
			@NotNull final Optional upstreamProxy) throws Exception {

		final BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
		browserMobProxy.setTrustAllServers(true);

		/*
			Prevent errors like this:

			09:58:29.348 [LittleProxy-0-ProxyToServerWorker-2] ERROR o.l.p.impl.ProxyToServerConnection -
			(AWAITING_INITIAL) [id: 0x95af9921, L:/127.0.0.1:60359 - R:/127.0.0.1:3128]:
			Caught an exception on ProxyToServerConnection io.netty.handler.codec.TooLongFrameException:
			HTTP content length exceeded 2097152 bytes.
		 */
		browserMobProxy.addFirstHttpFilterFactory(new HttpFiltersSourceAdapter() {
			@Override
			public int getMaximumRequestBufferSizeInBytes() {
				return Integer.MAX_VALUE;
			}

			@Override
			public int getMaximumResponseBufferSizeInBytes() {
				return Integer.MAX_VALUE;
			}
		});

		if (upstreamProxy.isPresent()) {
			browserMobProxy.setChainedProxy(new InetSocketAddress(
				upstreamProxy.get().getHost(),
				upstreamProxy.get().getPort()));

			if (StringUtils.isNotBlank(upstreamProxy.get().getUsername())) {
				browserMobProxy.chainedProxyAuthorization(
					upstreamProxy.get().getUsername(),
					upstreamProxy.get().getPassword(),
					AuthType.BASIC);
			}
		}

		browserMobProxy.start(0);

		final ProxyDetails proxyDetails =
			new ProxyDetailsImpl<>(browserMobProxy.getPort(), true, PROXY_NAME, browserMobProxy);

		trackErrorResponses(browserMobProxy, proxyDetails);

		return proxyDetails;
	}

	@SuppressWarnings("unchecked")
	private void trackErrorResponses(
		final BrowserMobProxy proxy,
		final ProxyDetails proxyDetails) {

		proxy.addResponseFilter(new ResponseFilter() {
			@Override
			public void filterResponse(
				final HttpResponse response,
				final HttpMessageContents contents,
				final HttpMessageInfo messageInfo) {

				/*
					Track anything other than a 200 range response
				 */
				if (response.getStatus().code() >= START_HTTP_ERROR
					&& response.getStatus().code() <= END_HTTP_ERROR) {

					synchronized (proxyDetails) {
						final Map properties = proxyDetails.getProperties();
						if (!properties.containsKey(INVALID_REQUESTS)) {
							properties.put(
								INVALID_REQUESTS,
								new ArrayList());
						}
						ArrayList.class.cast(properties.get(INVALID_REQUESTS)).add(messageInfo);
						proxyDetails.setProperties(properties);
					}
				}
			}
		});
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy