/* ========================================== * Laverca Project * https://sourceforge.net/projects/laverca/ * ========================================== * Copyright 2015 Laverca Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fi.laverca.util; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.TimeUnit; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSocketFactory; import org.apache.axis.components.logger.LogFactory; import org.apache.commons.logging.Log; import org.apache.http.ConnectionReuseStrategy; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.utils.HttpClientUtils; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; /** * Facade class for data used in setting up HttpClient 4.x clients + client constructor. *
* There are several tool methods that could be static, but are chosen to be class instance
* dependent because the experience is that updates to the HttpClient library need more and
* more of these facade methods to do the business without distributed code changes all over
* the places.
*/
public class LavercaHttpClient {
private static final Log log = LogFactory.getLog(LavercaHttpClient.class);
private final PoolingHttpClientConnectionManager connectionManager;
/** What authentication scheme? Currently only BasicAuth: */
private final UsernamePasswordCredentials targetAuthCredentials;
/** What authentication scheme? Currently only BasicAuth: */
private final AuthScheme targetAuthScheme;
private final HttpHost proxyHost;
private final AuthScope proxyAuthScope;
private final UsernamePasswordCredentials proxyAuthCredentials;
private final CloseableHttpClient client;
private final CredentialsProvider credentialsProvider;
private final AuthCache authCache;
private final RequestConfig.Builder requestConfigBuilder;
private final String poolUrl;
private final String username;
private final String password;
/**
* Use this method when you know the exact target URL.
*
* @param poolUrl target URL.
* @param newPoolSize connection pool size. 10 is good.
* @param newConnTimeout connection timeout in millis. 30000 is 30 sec.
* @param newSoTimeout protocol timeout in millis. 300000 is 300 sec / 5 minutes.
* @param newUsername if set, use this to authenticate to the remote service. Use null to not authenticate.
* @param newPassword see user.
* @param proxySettings Optional proxy parameters, null for none.
* @param ksf SSL Socket factory with specific client certificate and key, null for use of system wide default.
*
*/
public LavercaHttpClient( final String poolUrl,
final int newPoolSize,
final int newConnTimeout,
final int newSoTimeout,
final String newUsername,
final String newPassword,
final ProxySettings proxySettings,
final SSLSocketFactory ssf )
{
if (log.isTraceEnabled()) {
log.trace("Creating HttpClient instance...");
log.trace(" URL " + poolUrl);
}
this.poolUrl = poolUrl;
this.username = newUsername;
this.password = newPassword;
// Multiple threads (workers) share the HTTP connection pool
final RegistryBuilder
* This one is used when it is explicitly wanted that connection is not kept alive in pool.
*
* @param _url Target URL, note: this is not the same one that class constructor used.
* @return result
*/
public HttpGet buildHttpGet1( final String _url ) {
final HttpGet ret = this.buildHttpGet(_url);
// Note: Setting protocol version has the side-effect that
// the connection cannot be reused, but it also removes CLOSE_WAIT problems.
ret.setProtocolVersion(HttpVersion.HTTP_1_0);
return ret;
}
/**
* Convenience method building and initializing HttpPost
*
* @param _url Target URL, note: this is not the same one that class constructor used.
* @return result
*/
public HttpPost buildHttpPost( final String _url ) {
final HttpPost ret = new HttpPost(_url);
// AuthCredentials, if any
if (this.targetAuthCredentials != null) {
try {
URI uri = new URI(_url);
final HttpHost hh = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
this.authCache.put(hh, this.targetAuthScheme);
final AuthScope as = new AuthScope(hh.getHostName(), hh.getPort(), hh.getSchemeName());
this.credentialsProvider.setCredentials(as, this.targetAuthCredentials);
} catch (URISyntaxException e) {
log.debug("Unable to set auth credentials. URISyntaxException for URL: " + _url);
log.trace("URISyntaxException", e);
}
}
return ret;
}
/**
* Convenience method to build HTTP POST with ProtocolVersion HTTP1.0.
*
* This one is used when it is explicitly wanted that connection is not kept alive in pool.
*
* @param _url Target URL, note: this is not the same one that class constructor used.
* @return result
*/
public HttpPost buildHttpPost1( final String u ) {
final HttpPost ret = this.buildHttpPost(u);
// Note: Setting protocol version has the side-effect that
// the connection cannot be reused, but it also removes CLOSE_WAIT problems.
ret.setProtocolVersion(HttpVersion.HTTP_1_0);
return ret;
}
/**
* Helper to close HttpGet and its response
* @param get Thing to be closed
* @param resp Thing to be closed
*/
public void closeQuietly( final HttpGet get, final HttpResponse resp ) {
// First closing the response, then the request
HttpClientUtils.closeQuietly(resp);
if (get != null)
get.releaseConnection();
}
/**
* Helper to close HttpPost and its response
* @param post Thing to be closed
* @param resp Thing to be closed
*/
public void closeQuietly( final HttpPost post, final HttpResponse resp ) {
// First closing the response, then the request
HttpClientUtils.closeQuietly(resp);
if (post != null)
post.releaseConnection();
}
public PoolingHttpClientConnectionManager getConnectionManager() {
return this.connectionManager;
}
@Override
public String toString() {
return "[URL=" + this.poolUrl + "]";
}
}