I'm using BrowserMob in embedded mode to record HTTP/S traffic for Java Selenium tests.
I never got BrowserMob to work for Chrome, but it used to work fine on Firefox until version 35 got released. I never figured out why, but I couldn't get BrowserMob (version 2.0-beta10) to run stably after that.
Eventually I gave up and switched to LittleProxy as per a recommendation on Patrick's blog. I've found LittleProxy to be a lot faster and never had any performance or stability issues with it. Unfortunately it doesn't expose the full path in the URI (just the domain), so by itself it's incapable of recording or manipulating the full URL and/or parameters.
When I saw that BrowserMob contributors were incorporating LittleProxy on
GitHub I was ecstatic! I decided to build the 2.10-beta-1-SNAPSHOT from today and see if the stability had improved.
It has not. After the proxy starts and the Selenium WebDriver makes the first navigation request the browser hangs for about 2 minutes before anything shows up. When it does all of the images are stripped from the page and the text is aligned very strangely. Fortunately the links still show up so my tests can proceed to the next page. That page takes another minute to load and is still missing some images, but seems to be more fully loaded. Starting with the third page everything seems to begin working as expected. I'm not sure what's happening here, but it seems like there's some sort of timeout which is preventing javascript and/or image files from making it through the proxy (only theorizing here).
Chrome also still doesn't seem to work behind BrowserMob the way I'm running it (it works fine when using LittleProxy directly).
Here's the code I'm using to generate/start the proxy:
/** * Generates a BrowserMobProxyServer object. This proxy will be run asynchronously on a separate thread.
* Method is synchronized to prevent port collisions while starting the proxy on multiple test threads.
* @return proxyServer: the HttpProxyServer object that was generated
*/
private synchronized static BrowserMobProxyServer generateProxyServer()
{
// Create the proxy server object
BrowserMobProxyServer proxyServer = new BrowserMobProxyServer();
long associatedThreadId = Thread.currentThread().getId();
// Generate and attach proxy request filter
ProxyRequestFilter proxyRequestFilter = new ProxyRequestFilter(associatedThreadId);
Context.put("proxyRequestFilter", proxyRequestFilter);
proxyServer.addRequestFilter(proxyRequestFilter);
// Generate and attach proxy response filter
ProxyResponseFilter proxyResponseFilter = new ProxyResponseFilter(associatedThreadId);
Context.put("proxyResponseFilter", proxyResponseFilter);
proxyServer.addResponseFilter(proxyResponseFilter);
// Load port configuration for proxy (defaults to 0, which signals Proxy to find its own port)
int port = Config.getInteger("proxyPort");
// Start the proxy server
String proxyInfo = String.format("Starting proxy server on port [%s]... ", port == 0 ? "next available" : port);
try
{
proxyServer.start(port);
}
catch(Exception e)
{
CombinedLogger.error(proxyInfo + "FAILURE (HALTING)!", e);
}
CombinedLogger.info(proxyInfo + "success");
return proxyServer;
}. Note that the problems occur even if the request/response filters are set to do nothing.
Here's the code that's used to configure the WebDriver to connect to the proxy (this code is identical to what was used with LittleProxy directly):
private static void configureGenericCapabilities(DesiredCapabilities capabilities)
{
if(Config.getBoolean("useProxy"))
{
// Start the proxy server
BrowserMobProxyServer proxyServer = generateProxyServer();
Context.put("proxyServer", proxyServer);
// Get the proxy server address. Note: The NODE_NAME variable (used by Jenkins) overrides any value
// which was set for proxyServerAddress. This allows us to redirect browsers back to the Jenkins
// machines without knowing beforehand what the machine label is. If you still want to manually configure
// the proxy server address for Jenkins jobs you'll also need to set
// proxyServerAddressOverridesJenkinsNodeName to true.
String proxyServerAddress = Config.getString("proxyServerAddress");
if(!Config.getBoolean("proxyServerAddressOverridesJenkinsNodeName"))
{
String jenkinsNodeName = Config.getString("NODE_NAME");
if(jenkinsNodeName != null && !jenkinsNodeName.isEmpty())
{
String infoString = String.format("Jenkins NODE_NAME variable has been externally set to [%s]. " +
"Using this value to assign proxy server address to current " +
"node. Please set proxyServerAddressOverridesJenkinsNodeName " +
"to true if you still wish to manually define the proxy " +
"server address.", jenkinsNodeName);
CombinedLogger.info(infoString);
proxyServerAddress = jenkinsNodeName;
}
}
// Add proxy connection information to the WebDriver capabilities object
Proxy proxy = new Proxy();
proxy.setProxyType(Proxy.ProxyType.MANUAL);
proxy.setHttpProxy(String.format("%s:%s", proxyServerAddress, proxyServer.getPort()));
proxy.setSslProxy(String.format("%s:%s", proxyServerAddress, proxyServer.getPort()));
capabilities.setCapability(CapabilityType.PROXY, proxy);
}
capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
capabilities.setCapability(CapabilityType.SUPPORTS_JAVASCRIPT, true);
capabilities.setCapability(CapabilityType.SUPPORTS_WEB_STORAGE, false);
}For reference: proxyServerAddress is localhost when I'm seeing these issues and I'm not running through Selenium Grid at the moment.
What might be different about BrowserMob sitting on top of LittleProxy (or Jetty for that matter) that causes it to fail in these scenarios?