Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#788 Add setting to enable/disable proxy server #791

Merged
merged 2 commits into from Aug 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,7 @@

## 4.14.0 (planned to xx.09.2018)
* #784 Enable BasicAuth through Selenide proxy server -- see https://github.com/codeborne/selenide/pull/785
* #788 Add setting to enable/disable proxy server
* #789 Remove `?timestamp` parameter for IE

## 4.13.0 (released 20.08.2018)
Expand Down
29 changes: 29 additions & 0 deletions src/main/java/com/codeborne/selenide/Configuration.java
Expand Up @@ -380,6 +380,35 @@ public enum FileDownloadMode {
public static FileDownloadMode fileDownload = FileDownloadMode.valueOf(
System.getProperty("selenide.fileDownload", HTTPGET.name()));

/**
* If Selenide should run browser through its own proxy server.
* It allows some additional features which are not possible with plain Selenium.
* But it's not enabled by default because sometimes it would not work (more exactly, if tests and browser and
* executed on different machines, and "test machine" is not accessible from "browser machine"). If it's not your
* case, I recommend to enable proxy.
*
* Default: false
*/
public static boolean proxyEnabled = Boolean.parseBoolean(System.getProperty("selenide.proxyEnabled", "false"));

/**
* Host of Selenide proxy server.
* Used only if proxyEnabled == true.
*
* Default: empty (meaning that Selenide will detect current machine's ip/hostname automatically)
*
* @see net.lightbody.bmp.client.ClientUtil#getConnectableAddress()
*/
public static String proxyHost = System.getProperty("selenide.proxyHost", "");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In parent task default value was described as localhost not an empty value

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which parent task do you mean? I don't see it.


/**
* Port of Selenide proxy server.
* Used only if proxyEnabled == true.
*
* Default: 0 (meaning that Selenide will choose a random free port on current machine)
*/
public static int proxyPort = Integer.parseInt(System.getProperty("selenide.proxyPort", "0"));

/**
* Controls Selenide and WebDriverManager integration.
* When integration is enabled you don't need to download and setup any browser driver executables.
Expand Down
29 changes: 19 additions & 10 deletions src/main/java/com/codeborne/selenide/commands/DownloadFile.java
Expand Up @@ -10,7 +10,6 @@

import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.logging.Logger;

import static com.codeborne.selenide.Configuration.FileDownloadMode.HTTPGET;
Expand All @@ -19,8 +18,17 @@
public class DownloadFile implements Command<File> {
private static final Logger LOG = Logger.getLogger(DownloadFile.class.getName());

DownloadFileWithHttpRequest downloadFileWithHttpRequest = new DownloadFileWithHttpRequest();
DownloadFileWithProxyServer downloadFileWithProxyServer = new DownloadFileWithProxyServer();
private final DownloadFileWithHttpRequest downloadFileWithHttpRequest;
private final DownloadFileWithProxyServer downloadFileWithProxyServer;

public DownloadFile() {
this(new DownloadFileWithHttpRequest(), new DownloadFileWithProxyServer());
}

DownloadFile(DownloadFileWithHttpRequest httpget, DownloadFileWithProxyServer proxy) {
downloadFileWithHttpRequest = httpget;
downloadFileWithProxyServer = proxy;
}

@Override
public File execute(SelenideElement proxy, WebElementSource linkWithHref, Object[] args) throws IOException {
Expand All @@ -32,18 +40,19 @@ public File execute(SelenideElement proxy, WebElementSource linkWithHref, Object
LOG.config("selenide.fileDownload = " + System.getProperty("selenide.fileDownload") + " download file via http get");
return downloadFileWithHttpRequest.download(link, timeout);
}
else if (webdriverContainer.getProxyServer() == null) {
LOG.config("Proxy server is not started - download file via http get");
return downloadFileWithHttpRequest.download(link, timeout);
if (!Configuration.proxyEnabled) {
throw new IllegalStateException("Cannot download file: proxy server is not enabled. Setup Configuration.proxyEnabled");
}
else {
return downloadFileWithProxyServer.download(linkWithHref, link, webdriverContainer.getProxyServer(), timeout);
if (webdriverContainer.getProxyServer() == null) {
throw new IllegalStateException("Cannot download file: proxy server is not started");
}

return downloadFileWithProxyServer.download(linkWithHref, link, webdriverContainer.getProxyServer(), timeout);
}

private long getTimeout(Object[] args) {
long getTimeout(Object[] args) {
try {
if (Objects.nonNull(args) && args.length > 0) {
if (args != null && args.length > 0) {
return (long) args[0];
}
else {
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/com/codeborne/selenide/impl/Navigator.java
Expand Up @@ -12,7 +12,6 @@

import java.net.URL;

import static com.codeborne.selenide.Configuration.FileDownloadMode.PROXY;
import static com.codeborne.selenide.Configuration.baseUrl;
import static com.codeborne.selenide.WebDriverRunner.getAndCheckWebDriver;
import static com.codeborne.selenide.WebDriverRunner.getSelenideProxy;
Expand Down Expand Up @@ -76,7 +75,7 @@ private void navigateTo(String url, AuthenticationType authenticationType, Strin
}

private void beforeNavigateTo(AuthenticationType authenticationType, String domain, String login, String password) {
if (Configuration.fileDownload == PROXY) {
if (Configuration.proxyEnabled) {
beforeNavigateToWithProxy(authenticationType, domain, login, password);
}
else {
Expand Down Expand Up @@ -111,7 +110,7 @@ private String appendBasicAuthIfNeeded(String url, AuthenticationType authType,

private boolean passBasicAuthThroughUrl(AuthenticationType authenticationType, String domain, String login, String password) {
return hasAuthentication(domain, login, password) &&
Configuration.fileDownload != PROXY &&
!Configuration.proxyEnabled &&
authenticationType == AuthenticationType.BASIC;
}

Expand Down
Expand Up @@ -221,7 +221,13 @@ protected WebDriver createDriver() {

Proxy userProvidedProxy = proxy;

if (Configuration.fileDownload == PROXY) {
if (!Configuration.proxyEnabled && Configuration.fileDownload == PROXY) {
log.warning("Configuration.proxyEnabled == false but Configuration.fileDownload == PROXY. " +
"We will enable proxy server automatically.");
Configuration.proxyEnabled = true;
}

if (Configuration.proxyEnabled) {
SelenideProxyServer selenideProxyServer = new SelenideProxyServer(proxy);
selenideProxyServer.start();
THREAD_PROXY_SERVER.put(currentThread().getId(), selenideProxyServer);
Expand Down
@@ -0,0 +1,25 @@
package com.codeborne.selenide.proxy;

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;

/**
* By default, BrowserMobProxyServer doesn't allow requests/responses bugger than 2 MB.
* We need this class to enable bigger sizes.
*/
class BrowserMobProxyServerUnlimited extends BrowserMobProxyServer {
private static final int maxSize = 64 * 1024 * 1024; // 64 MB

@Override
public void addRequestFilter(RequestFilter filter) {
addFirstHttpFilterFactory(new RequestFilterAdapter.FilterSource(filter, maxSize));
}

@Override
public void addResponseFilter(ResponseFilter filter) {
addLastHttpFilterFactory(new ResponseFilterAdapter.FilterSource(filter, maxSize));
}
}
@@ -0,0 +1,15 @@
package com.codeborne.selenide.proxy;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressResolver {
InetAddress getInetAddressByName(String hostname) {
try {
return InetAddress.getByName(hostname);
}
catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
}
}
58 changes: 27 additions & 31 deletions src/main/java/com/codeborne/selenide/proxy/SelenideProxyServer.java
@@ -1,52 +1,31 @@
package com.codeborne.selenide.proxy;

import com.codeborne.selenide.Configuration;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.client.ClientUtil;
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 org.openqa.selenium.Proxy;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

import static java.lang.Integer.parseInt;
import static org.apache.commons.lang3.StringUtils.isEmpty;

/**
* Selenide own proxy server to intercept server responses
*
* It holds map of request and response filters by name.
*/
public class SelenideProxyServer {
protected final Proxy outsideProxy;

protected BrowserMobProxy proxy = new BrowserMobProxyServer() {
int maxSize = 64 * 1024 * 1024; // 64 MB
@Override
public void addRequestFilter(RequestFilter filter) {
addFirstHttpFilterFactory(new RequestFilterAdapter.FilterSource(filter, maxSize));
}

@Override public void addResponseFilter(ResponseFilter filter) {
addLastHttpFilterFactory(new ResponseFilterAdapter.FilterSource(filter, maxSize));
}
};

/**
* Method return current instance of browser mob proxy
*
* @return browser mob proxy instance
*/
public BrowserMobProxy getProxy() {
return proxy;
}

protected int port;
protected Map<String, RequestFilter> requestFilters = new HashMap<>();
protected Map<String, ResponseFilter> responseFilters = new HashMap<>();
private final InetAddressResolver inetAddressResolver;
private final Proxy outsideProxy;
private final BrowserMobProxy proxy;
private final Map<String, RequestFilter> requestFilters = new HashMap<>();
private final Map<String, ResponseFilter> responseFilters = new HashMap<>();
private int port;

/**
* Create server
Expand All @@ -55,7 +34,13 @@ public BrowserMobProxy getProxy() {
* @param outsideProxy another proxy server used by test author for his own need (can be null)
*/
public SelenideProxyServer(Proxy outsideProxy) {
this(outsideProxy, new InetAddressResolver(), new BrowserMobProxyServerUnlimited());
}

protected SelenideProxyServer(Proxy outsideProxy, InetAddressResolver inetAddressResolver, BrowserMobProxy proxy) {
this.outsideProxy = outsideProxy;
this.inetAddressResolver = inetAddressResolver;
this.proxy = proxy;
}

/**
Expand All @@ -74,7 +59,7 @@ public void start() {
addResponseFilter("responseSizeWatchdog", new ResponseSizeWatchdog());
addResponseFilter("download", new FileDownloadFilter());

proxy.start();
proxy.start(Configuration.proxyPort);
port = proxy.getPort();
}

Expand Down Expand Up @@ -121,7 +106,9 @@ static InetSocketAddress getProxyAddress(Proxy proxy) {
* Converts this proxy to a "selenium" proxy that can be used by webdriver
*/
public Proxy createSeleniumProxy() {
return ClientUtil.createSeleniumProxy(proxy);
return isEmpty(Configuration.proxyHost)
? ClientUtil.createSeleniumProxy(proxy)
: ClientUtil.createSeleniumProxy(proxy, inetAddressResolver.getInetAddressByName(Configuration.proxyHost));
}

/**
Expand All @@ -131,6 +118,15 @@ public void shutdown() {
proxy.abort();
}

/**
* Method return current instance of browser mob proxy
*
* @return browser mob proxy instance
*/
public BrowserMobProxy getProxy() {
return proxy;
}

@Override
public String toString() {
return String.format("Selenide proxy server :%s", port);
Expand Down
2 changes: 0 additions & 2 deletions src/test/java/com/codeborne/selenide/WebDriverRunnerTest.java
Expand Up @@ -16,7 +16,6 @@

import java.net.URL;

import static com.codeborne.selenide.Configuration.FileDownloadMode.HTTPGET;
import static com.codeborne.selenide.Selenide.open;
import static com.codeborne.selenide.WebDriverRunner.FIREFOX;
import static com.codeborne.selenide.WebDriverRunner.HTMLUNIT;
Expand All @@ -43,7 +42,6 @@ void resetWebDriverContainer() {

WebDriverRunner.webdriverContainer = spy(new WebDriverThreadLocalContainer());
doReturn(null).when((JavascriptExecutor) driver).executeScript(anyString(), any());
Configuration.fileDownload = HTTPGET;
}

@AfterEach
Expand Down