Path: blob/trunk/java/src/org/openqa/selenium/Proxy.java
3991 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617package org.openqa.selenium;1819import java.util.HashMap;20import java.util.List;21import java.util.Locale;22import java.util.Map;23import java.util.Objects;24import java.util.Optional;25import java.util.function.Consumer;26import java.util.stream.Collectors;27import org.jspecify.annotations.Nullable;2829/**30* Configuration parameters for using proxies in WebDriver. Generally you should pass an object of31* this type to a WebDriver constructor, or in some cases to the profile object used in the32* WebDriver construction. For simplicity, setting values here commits the proxy to a certain33* configuration. That is, it is an error to set an <code>httpProxy</code> manually and then turn on34* proxy autodetect.35*/36public class Proxy {3738public enum ProxyType {39// Keep these in sync with the Firefox preferences numbers:40// http://kb.mozillazine.org/Network.proxy.type4142DIRECT("direct"), // Direct connection, no proxy (default on Windows)43MANUAL("manual"), // Manual proxy settings (e.g. for httpProxy)44PAC("pac"), // Proxy auto-configuration from URL4546RESERVED_1("reserved_1"), // Never used (but reserved in Firefox)4748AUTODETECT("autodetect"), // Proxy auto-detection (presumably with WPAD)49SYSTEM("system"), // Use system settings (default on Linux)5051UNSPECIFIED("unspecified");5253private final String type;5455ProxyType(String type) {56this.type = type;57}5859@Override60public String toString() {61return String.valueOf(type);62}63}6465private static final String PROXY_TYPE = "proxyType";66@Deprecated private static final String FTP_PROXY = "ftpProxy";67private static final String HTTP_PROXY = "httpProxy";68private static final String NO_PROXY = "noProxy";69private static final String SSL_PROXY = "sslProxy";70private static final String SOCKS_PROXY = "socksProxy";71private static final String SOCKS_VERSION = "socksVersion";72private static final String SOCKS_USERNAME = "socksUsername";73private static final String SOCKS_PASSWORD = "socksPassword";74private static final String PROXY_AUTOCONFIG_URL = "proxyAutoconfigUrl";75private static final String AUTODETECT = "autodetect";7677private ProxyType proxyType = ProxyType.UNSPECIFIED;78private boolean autodetect = false;79@Deprecated private @Nullable String ftpProxy;80private @Nullable String httpProxy;81private @Nullable String noProxy;82private @Nullable String sslProxy;83private @Nullable String socksProxy;84private @Nullable Integer socksVersion;85private @Nullable String socksUsername;86private @Nullable String socksPassword;87private @Nullable String proxyAutoconfigUrl;8889public Proxy() {90// Empty default constructor91}9293public Proxy(Map<String, ?> raw) {94Map<String, Consumer<Object>> setters = new HashMap<>();95setters.put(96PROXY_TYPE,97value -> setProxyType(ProxyType.valueOf(((String) value).toUpperCase(Locale.ENGLISH))));98setters.put(FTP_PROXY, value -> setFtpProxy((String) value));99setters.put(HTTP_PROXY, value -> setHttpProxy((String) value));100setters.put(101NO_PROXY,102rawData -> {103if (rawData instanceof List) {104// w3c105setNoProxy(106((List<?>) rawData)107.stream().map(Object::toString).collect(Collectors.joining(", ")));108} else {109// legacy110setNoProxy((String) rawData);111}112});113setters.put(SSL_PROXY, value -> setSslProxy((String) value));114setters.put(SOCKS_PROXY, value -> setSocksProxy((String) value));115setters.put(SOCKS_VERSION, value -> setSocksVersion(((Number) value).intValue()));116setters.put(SOCKS_USERNAME, value -> setSocksUsername((String) value));117setters.put(SOCKS_PASSWORD, value -> setSocksPassword((String) value));118setters.put(PROXY_AUTOCONFIG_URL, value -> setProxyAutoconfigUrl((String) value));119setters.put(AUTODETECT, value -> setAutodetect((Boolean) value));120raw.forEach(121(key, value) -> {122if (key != null && value != null && setters.containsKey(key)) {123setters.get(key).accept(value);124}125});126}127128public Map<String, Object> toJson() {129Map<String, Object> m = new HashMap<>();130131if (proxyType != ProxyType.UNSPECIFIED) {132m.put(PROXY_TYPE, proxyType.toString());133}134if (ftpProxy != null) {135m.put(FTP_PROXY, ftpProxy);136}137if (httpProxy != null) {138m.put(HTTP_PROXY, httpProxy);139}140if (noProxy != null) {141m.put(NO_PROXY, List.of(noProxy.split(",\\s*")));142}143if (sslProxy != null) {144m.put(SSL_PROXY, sslProxy);145}146if (socksProxy != null) {147m.put(SOCKS_PROXY, socksProxy);148}149if (socksVersion != null) {150m.put(SOCKS_VERSION, socksVersion);151}152if (socksUsername != null) {153m.put(SOCKS_USERNAME, socksUsername);154}155if (socksPassword != null) {156m.put(SOCKS_PASSWORD, socksPassword);157}158if (proxyAutoconfigUrl != null) {159m.put(PROXY_AUTOCONFIG_URL, proxyAutoconfigUrl);160}161if (autodetect) {162m.put(AUTODETECT, true);163}164return m;165}166167/**168* Gets the {@link ProxyType}. This can signal if set to use a direct connection (without proxy),169* manually set proxy settings, auto-configured proxy settings, or whether to use the default170* system proxy settings. It defaults to {@link ProxyType#UNSPECIFIED}.171*172* @return the proxy type employed173*/174public ProxyType getProxyType() {175return this.proxyType;176}177178/**179* Explicitly sets the proxy type, useful for forcing direct connection on Linux.180*181* @param proxyType type of proxy being used182* @return reference to self183*/184public Proxy setProxyType(ProxyType proxyType) {185verifyProxyTypeCompatibility(proxyType);186this.proxyType = proxyType;187return this;188}189190/**191* Whether to autodetect proxy settings.192*193* @return true if set to autodetect proxy settings, false otherwise194*/195public boolean isAutodetect() {196return autodetect;197}198199/**200* Specifies whether to autodetect proxy settings.201*202* @param autodetect set to true to use proxy auto detection, false to leave proxy settings203* unspecified204* @return reference to self205*/206public Proxy setAutodetect(boolean autodetect) {207if (this.autodetect == autodetect) {208return this;209}210if (autodetect) {211verifyProxyTypeCompatibility(ProxyType.AUTODETECT);212this.proxyType = ProxyType.AUTODETECT;213} else {214this.proxyType = ProxyType.UNSPECIFIED;215}216this.autodetect = autodetect;217return this;218}219220/**221* Gets the FTP proxy.222*223* @return the FTP proxy hostname if present, or null if not set224* @deprecated getFtpProxy is deprecated and will be removed in a future release.225*/226@Deprecated227public @Nullable String getFtpProxy() {228return ftpProxy;229}230231/**232* Specify which proxy to use for FTP connections.233*234* @param ftpProxy the proxy host, expected format is <code>hostname.com:1234</code>235* @return reference to self236* @deprecated setFtpProxy is deprecated and will be removed in a future release.237*/238@Deprecated239public Proxy setFtpProxy(String ftpProxy) {240verifyProxyTypeCompatibility(ProxyType.MANUAL);241this.proxyType = ProxyType.MANUAL;242this.ftpProxy = ftpProxy;243return this;244}245246/**247* Gets the HTTP proxy.248*249* @return the HTTP proxy hostname if present, or null if not set250*/251public @Nullable String getHttpProxy() {252return httpProxy;253}254255/**256* Specify which proxy to use for HTTP connections.257*258* @param httpProxy the proxy host, expected format is <code>hostname:1234</code>259* @return reference to self260*/261public Proxy setHttpProxy(String httpProxy) {262verifyProxyTypeCompatibility(ProxyType.MANUAL);263this.proxyType = ProxyType.MANUAL;264this.httpProxy = httpProxy;265return this;266}267268/**269* Gets proxy bypass (noproxy) addresses.270*271* @return The proxy bypass (noproxy) addresses272*/273public @Nullable String getNoProxy() {274return noProxy;275}276277/**278* Sets proxy bypass (noproxy) addresses279*280* @param noProxy The proxy bypass (noproxy) addresses separated by commas281* @return reference to self282*/283public Proxy setNoProxy(String noProxy) {284verifyProxyTypeCompatibility(ProxyType.MANUAL);285this.proxyType = ProxyType.MANUAL;286this.noProxy = noProxy;287return this;288}289290/**291* Gets the SSL tunnel proxy.292*293* @return the SSL tunnel proxy hostname if present, null otherwise294*/295public @Nullable String getSslProxy() {296return sslProxy;297}298299/**300* Specify which proxy to use for SSL connections.301*302* @param sslProxy the proxy host, expected format is <code>hostname.com:1234</code>303* @return reference to self304*/305public Proxy setSslProxy(String sslProxy) {306verifyProxyTypeCompatibility(ProxyType.MANUAL);307this.proxyType = ProxyType.MANUAL;308this.sslProxy = sslProxy;309return this;310}311312/**313* Gets the SOCKS proxy.314*315* @return the SOCKS proxy if present, null otherwise316*/317public @Nullable String getSocksProxy() {318return socksProxy;319}320321/**322* Specifies which proxy to use for SOCKS.323*324* @param socksProxy the proxy host, expected format is <code>hostname.com:1234</code>325* @return reference to self326*/327public Proxy setSocksProxy(String socksProxy) {328verifyProxyTypeCompatibility(ProxyType.MANUAL);329this.proxyType = ProxyType.MANUAL;330this.socksProxy = socksProxy;331return this;332}333334/**335* Gets the SOCKS version (4 or 5).336*337* @return the SOCKS version if present, null otherwise338*/339public @Nullable Integer getSocksVersion() {340return socksVersion;341}342343/**344* Specifies which version of SOCKS to use (4 or 5).345*346* @param socksVersion SOCKS version, 4 or 5347* @return reference to self348*/349public Proxy setSocksVersion(Integer socksVersion) {350verifyProxyTypeCompatibility(ProxyType.MANUAL);351this.proxyType = ProxyType.MANUAL;352this.socksVersion = socksVersion;353return this;354}355356/**357* Gets the SOCKS proxy's username. Supported by SOCKS v5 and above.358*359* @return the SOCKS proxy's username360*/361public @Nullable String getSocksUsername() {362return socksUsername;363}364365/**366* Specifies a username for the SOCKS proxy. Supported by SOCKS v5 and above.367*368* @param username username for the SOCKS proxy369* @return reference to self370*/371public Proxy setSocksUsername(String username) {372verifyProxyTypeCompatibility(ProxyType.MANUAL);373this.proxyType = ProxyType.MANUAL;374this.socksUsername = username;375return this;376}377378/**379* Gets the SOCKS proxy's password. Supported by SOCKS v5 and above.380*381* @return the SOCKS proxy's password382*/383public @Nullable String getSocksPassword() {384return socksPassword;385}386387/**388* Specifies a password for the SOCKS proxy. Supported by SOCKS v5 and above.389*390* @param password password for the SOCKS proxy391* @return reference to self392*/393public Proxy setSocksPassword(String password) {394verifyProxyTypeCompatibility(ProxyType.MANUAL);395this.proxyType = ProxyType.MANUAL;396this.socksPassword = password;397return this;398}399400/**401* Gets the proxy auto-configuration URL.402*403* @return the proxy auto-configuration URL404*/405public @Nullable String getProxyAutoconfigUrl() {406return proxyAutoconfigUrl;407}408409/**410* Specifies the URL to be used for proxy auto-configuration. Expected format is <code>411* http://hostname.com:1234/pacfile</code>. This is required if {@link #getProxyType()} is set to412* {@link ProxyType#PAC}, ignored otherwise.413*414* @param proxyAutoconfigUrl the URL for proxy auto-configuration415* @return reference to self416*/417public Proxy setProxyAutoconfigUrl(String proxyAutoconfigUrl) {418verifyProxyTypeCompatibility(ProxyType.PAC);419this.proxyType = ProxyType.PAC;420this.proxyAutoconfigUrl = proxyAutoconfigUrl;421return this;422}423424private void verifyProxyTypeCompatibility(ProxyType compatibleProxy) {425if (proxyType != ProxyType.UNSPECIFIED && proxyType != compatibleProxy) {426throw new IllegalStateException(427String.format(428"Specified proxy type (%s) not compatible with current setting (%s)",429compatibleProxy, proxyType));430}431}432433@SuppressWarnings({"unchecked"})434public static @Nullable Proxy extractFrom(Capabilities capabilities) {435Object rawProxy = capabilities.getCapability("proxy");436Proxy proxy = null;437if (rawProxy != null) {438if (rawProxy instanceof Proxy) {439proxy = (Proxy) rawProxy;440} else if (rawProxy instanceof Map) {441proxy = new Proxy((Map<String, ?>) rawProxy);442}443}444return proxy;445}446447@Override448public String toString() {449StringBuilder builder = new StringBuilder("Proxy(");450451switch (getProxyType()) {452case AUTODETECT:453case DIRECT:454case MANUAL:455case SYSTEM:456builder.append(getProxyType().toString().toLowerCase(Locale.ENGLISH));457break;458459case PAC:460builder.append("pac: ").append(getProxyAutoconfigUrl());461break;462463case RESERVED_1:464case UNSPECIFIED:465break;466}467468Optional.ofNullable(getFtpProxy()).ifPresent(p -> builder.append(", ftp=").append(p));469Optional.ofNullable(getHttpProxy()).ifPresent(p -> builder.append(", http=").append(p));470Optional.ofNullable(getSocksProxy()).ifPresent(p -> builder.append(", socks=").append(p));471Optional.ofNullable(getSslProxy()).ifPresent(p -> builder.append(", ssl=").append(p));472473builder.append(")");474return builder.toString();475}476477@Override478public boolean equals(@Nullable Object o) {479if (this == o) {480return true;481}482if (o == null || getClass() != o.getClass()) {483return false;484}485Proxy proxy = (Proxy) o;486return isAutodetect() == proxy.isAutodetect()487&& getProxyType() == proxy.getProxyType()488&& Objects.equals(getFtpProxy(), proxy.getFtpProxy())489&& Objects.equals(getHttpProxy(), proxy.getHttpProxy())490&& Objects.equals(getNoProxy(), proxy.getNoProxy())491&& Objects.equals(getSslProxy(), proxy.getSslProxy())492&& Objects.equals(getSocksProxy(), proxy.getSocksProxy())493&& Objects.equals(getSocksVersion(), proxy.getSocksVersion())494&& Objects.equals(getSocksUsername(), proxy.getSocksUsername())495&& Objects.equals(getSocksPassword(), proxy.getSocksPassword())496&& Objects.equals(getProxyAutoconfigUrl(), proxy.getProxyAutoconfigUrl());497}498499@Override500public int hashCode() {501return Objects.hash(502getProxyType(),503isAutodetect(),504getFtpProxy(),505getHttpProxy(),506getNoProxy(),507getSslProxy(),508getSocksProxy(),509getSocksVersion(),510getSocksUsername(),511getSocksPassword(),512getProxyAutoconfigUrl());513}514}515516517