package io.searchbox.client.config;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthenticationStrategy;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.nio.conn.NoopIOSessionStrategy;
import org.apache.http.nio.conn.SchemeIOSessionStrategy;
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
import java.net.ProxySelector;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author Dogukan Sonmez
* @author cihat keser
*/
public class HttpClientConfig extends ClientConfig {
private final Integer maxTotalConnection;
private final Integer defaultMaxTotalConnectionPerRoute;
private final Map<HttpRoute, Integer> maxTotalConnectionPerRoute;
private final CredentialsProvider credentialsProvider;
private final LayeredConnectionSocketFactory sslSocketFactory;
private final ConnectionSocketFactory plainSocketFactory;
private final HttpRoutePlanner httpRoutePlanner;
private final AuthenticationStrategy proxyAuthenticationStrategy;
private final SchemeIOSessionStrategy httpIOSessionStrategy;
private final SchemeIOSessionStrategy httpsIOSessionStrategy;
private Set<HttpHost> preemptiveAuthTargetHosts;
public HttpClientConfig(Builder builder) {
super(builder);
this.maxTotalConnection = builder.maxTotalConnection;
this.defaultMaxTotalConnectionPerRoute = builder.defaultMaxTotalConnectionPerRoute;
this.maxTotalConnectionPerRoute = builder.maxTotalConnectionPerRoute;
this.credentialsProvider = builder.credentialsProvider;
this.sslSocketFactory = builder.sslSocketFactory;
this.plainSocketFactory = builder.plainSocketFactory;
this.httpRoutePlanner = builder.httpRoutePlanner;
this.proxyAuthenticationStrategy = builder.proxyAuthenticationStrategy;
this.httpIOSessionStrategy = builder.httpIOSessionStrategy;
this.httpsIOSessionStrategy = builder.httpsIOSessionStrategy;
this.preemptiveAuthTargetHosts = builder.preemptiveAuthTargetHosts;
}
public Map<HttpRoute, Integer> getMaxTotalConnectionPerRoute() {
return maxTotalConnectionPerRoute;
}
public Integer getMaxTotalConnection() {
return maxTotalConnection;
}
public Integer getDefaultMaxTotalConnectionPerRoute() {
return defaultMaxTotalConnectionPerRoute;
}
public CredentialsProvider getCredentialsProvider() {
return credentialsProvider;
}
public LayeredConnectionSocketFactory getSslSocketFactory() {
return sslSocketFactory;
}
public ConnectionSocketFactory getPlainSocketFactory() {
return plainSocketFactory;
}
public HttpRoutePlanner getHttpRoutePlanner() {
return httpRoutePlanner;
}
public AuthenticationStrategy getProxyAuthenticationStrategy() {
return proxyAuthenticationStrategy;
}
public SchemeIOSessionStrategy getHttpIOSessionStrategy() {
return httpIOSessionStrategy;
}
public SchemeIOSessionStrategy getHttpsIOSessionStrategy() {
return httpsIOSessionStrategy;
}
public Set<HttpHost> getPreemptiveAuthTargetHosts() {
return preemptiveAuthTargetHosts;
}
public static class Builder extends ClientConfig.AbstractBuilder<HttpClientConfig, Builder> {
private Integer maxTotalConnection;
private Integer defaultMaxTotalConnectionPerRoute;
private Map<HttpRoute, Integer> maxTotalConnectionPerRoute = new HashMap<HttpRoute, Integer>();
private CredentialsProvider credentialsProvider;
private LayeredConnectionSocketFactory sslSocketFactory;
private ConnectionSocketFactory plainSocketFactory;
private HttpRoutePlanner httpRoutePlanner;
private AuthenticationStrategy proxyAuthenticationStrategy;
private SchemeIOSessionStrategy httpIOSessionStrategy;
private SchemeIOSessionStrategy httpsIOSessionStrategy;
private Set<HttpHost> preemptiveAuthTargetHosts = Collections.emptySet();
public Builder(HttpClientConfig httpClientConfig) {
super(httpClientConfig);
this.maxTotalConnection = httpClientConfig.maxTotalConnection;
this.defaultMaxTotalConnectionPerRoute = httpClientConfig.defaultMaxTotalConnectionPerRoute;
this.maxTotalConnectionPerRoute = httpClientConfig.maxTotalConnectionPerRoute;
}
public Builder(Collection<String> serverUris) {
super(serverUris);
}
public Builder(String serverUri) {
super(serverUri);
}
public Builder maxTotalConnection(int maxTotalConnection) {
this.maxTotalConnection = maxTotalConnection;
return this;
}
public Builder defaultMaxTotalConnectionPerRoute(int defaultMaxTotalConnectionPerRoute) {
this.defaultMaxTotalConnectionPerRoute = defaultMaxTotalConnectionPerRoute;
return this;
}
public Builder maxTotalConnectionPerRoute(Map<HttpRoute, Integer> maxTotalConnectionPerRoute) {
this.maxTotalConnectionPerRoute.putAll(maxTotalConnectionPerRoute);
return this;
}
public Builder maxTotalConnectionPerRoute(HttpRoute httpRoute, int maxTotalConnection) {
this.maxTotalConnectionPerRoute.put(httpRoute, maxTotalConnection);
return this;
}
/**
* Set a custom instance of an implementation of <code>CredentialsProvider</code>.
* This method will override any previous credential setting (including <code>defaultCredentials</code>) on this builder instance.
*/
public Builder credentialsProvider(CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
return this;
}
public Builder defaultCredentials(String username, String password) {
this.credentialsProvider = new BasicCredentialsProvider();
this.credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(username, password)
);
return this;
}
/**
* Sets the socket factory that will be used by <b>sync</b> client for HTTP scheme.
* <p>
* <code>SSLConnectionSocketFactory.getSocketFactory()</code> is used by default.
* </p><p>
* A bad example of trust-all socket factory creation can be done as below:
* </p>
* <pre>
* // trust ALL certificates
* SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
* public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
* return true;
* }
* }).build();
*
* // skip hostname checks
* HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
*
* SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
* </pre>
*
* @param socketFactory socket factory instance that will be registered for <code>https</code> scheme.
* @see SSLConnectionSocketFactory
*/
public Builder sslSocketFactory(LayeredConnectionSocketFactory socketFactory) {
this.sslSocketFactory = socketFactory;
return this;
}
/**
* Sets the socket factory that will be used by <b>sync</b> client for HTTPS scheme.
* <p>
* <code>PlainConnectionSocketFactory.getSocketFactory()</code> is used by default.
* </p>
*
* @param socketFactory socket factory instance that will be registered for <code>http</code> scheme.
* @see PlainConnectionSocketFactory
*/
public Builder plainSocketFactory(ConnectionSocketFactory socketFactory) {
this.plainSocketFactory = socketFactory;
return this;
}
/**
* Sets the socket factory that will be used by <b>async</b> client for HTTP scheme.
* <p>
* <code>NoopIOSessionStrategy.INSTANCE</code> is used by default.
* </p>
*
* @param httpIOSessionStrategy SchemeIOSessionStrategy instance that will be registered for <code>http</code> scheme.
* @see NoopIOSessionStrategy
*/
public Builder httpIOSessionStrategy(SchemeIOSessionStrategy httpIOSessionStrategy) {
this.httpIOSessionStrategy = httpIOSessionStrategy;
return this;
}
/**
* Sets the socket factory that will be used by <b>async</b> client for HTTPS scheme.
* <p>
* <code>SSLIOSessionStrategy.getSystemDefaultStrategy()</code> is used by default.
* </p>
*
* @param httpsIOSessionStrategy SchemeIOSessionStrategy instance that will be registered for <code>https</code> scheme.
* @see SSLIOSessionStrategy
*/
public Builder httpsIOSessionStrategy(SchemeIOSessionStrategy httpsIOSessionStrategy) {
this.httpsIOSessionStrategy = httpsIOSessionStrategy;
return this;
}
/**
* Sets preemptive authentication for the specified <b>target host</b> by pre-populating an authentication data cache.
* <p>
* It is mandatory to set a credentials provider to use preemptive authentication.
* </p><p>
* If preemptive authentication is set without setting a credentials provider an exception will be thrown.
* </p>
*/
public Builder setPreemptiveAuth(HttpHost targetHost) {
return preemptiveAuthTargetHosts(Collections.singleton(targetHost));
}
/**
* Sets preemptive authentication for the specified set of <b>target hosts</b> by pre-populating an authentication data cache.
* <p>
* It is mandatory to set a credentials provider to use preemptive authentication.
* </p><p>
* If preemptive authentication is set without setting a credentials provider an exception will be thrown.
* </p>
* @param preemptiveAuthTargetHosts set of hosts targeted for preemptive authentication
*/
public Builder preemptiveAuthTargetHosts(Set<HttpHost> preemptiveAuthTargetHosts) {
if (preemptiveAuthTargetHosts != null) {
this.preemptiveAuthTargetHosts = new HashSet<HttpHost>(preemptiveAuthTargetHosts);
}
return this;
}
public Builder proxy(HttpHost proxy) {
return proxy(proxy, null);
}
public Builder proxy(HttpHost proxy, AuthenticationStrategy proxyAuthenticationStrategy) {
this.httpRoutePlanner = new DefaultProxyRoutePlanner(proxy);
this.proxyAuthenticationStrategy = proxyAuthenticationStrategy;
return this;
}
public HttpClientConfig build() {
// Lazily initialize if necessary, as the call can be expensive when done eagerly.
if (this.sslSocketFactory == null) {
this.sslSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
}
if(this.plainSocketFactory == null) {
this.plainSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
}
if(this.httpRoutePlanner == null) {
this.httpRoutePlanner = new SystemDefaultRoutePlanner(ProxySelector.getDefault());
}
if(this.httpIOSessionStrategy == null) {
this.httpIOSessionStrategy = NoopIOSessionStrategy.INSTANCE;
}
if(this.httpsIOSessionStrategy == null) {
this.httpsIOSessionStrategy = SSLIOSessionStrategy.getSystemDefaultStrategy();
}
if (preemptiveAuthSetWithoutCredentials()) {
throw new IllegalArgumentException("Preemptive authentication set without credentials provider");
}
return new HttpClientConfig(this);
}
private boolean preemptiveAuthSetWithoutCredentials() {
return !preemptiveAuthTargetHosts.isEmpty() && credentialsProvider == null;
}
}
}