I am using httpclient 4.1.3 in my project.
I am creating single httpclient instance with ThreadSafeClientConnManager.
I don't see alternative to ThreadSafeClientConnManager in httpclient 4.1.3.
Intermittently I am experiencing that http request being made for another
user which is not the intended user. I am setting credentials in AuthState
and using localHttpClient.
My test includes -
- Six threads running in parallel each calling REST API 10 time
- Endpoint URL is same for all request so HttpHost is same.
- There are six authenticating users. Each thread correspond to 1 thread.
Pasting code below. Please let me know if i am missing anything in main
code. I am not printing my test code here.
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.log4j.Logger;
public class BasicAuthRestClient extends AbstractRestClient{
private static int HTTP_CONN_TIMEOUT = 30*1000; //30 second
private static int HTTP_SOCKET_TIMEOUT = 5*60*1000; //5 minute
private static int HTTP_MAX_CONN = 1000;
private static int HTTP_MAX_PER_ROUTE = 100;
public BasicAuthRestClient(String baseUrl){
this.baseUrl = baseUrl;
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory;
try {
socketFactory = new SSLSocketFactory(new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
return true;
}
}, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
registry.register(new Scheme("https", HTTP_SSL_PORT,
socketFactory));
} catch (Exception e) {
logger.error("exception in creating SSLSocketFactory", e);
}
ClientConnectionManager connMgr = new
ThreadSafeClientConnManager(registry);
((ThreadSafeClientConnManager)connMgr).setMaxTotal(HTTP_MAX_CONN);
((ThreadSafeClientConnManager)connMgr).setDefaultMaxPerRoute(
HTTP_MAX_PER_ROUTE);
httpClient = new DefaultHttpClient(connMgr);
//setting request interceptor
((DefaultHttpClient)httpClient).addRequestInterceptor(new
HttpBasicAuthInterceptor(), 0);
HttpConnectionParams.setConnectionTimeout(httpClient.getParams(),
HTTP_CONN_TIMEOUT);
HttpConnectionParams.setSoTimeout(httpClient.getParams(),
HTTP_SOCKET_TIMEOUT);
HttpConnectionParams.setStaleCheckingEnabled(httpClient.getParams(),
true);
HttpConnectionParams.setTcpNoDelay(httpClient.getParams(), true);
HttpClientParams.setAuthenticating(httpClient.getParams(), true);
HttpClientParams.setRedirecting(httpClient.getParams(), false);
}
static class HttpBasicAuthInterceptor implements HttpRequestInterceptor
{
public void process(
final HttpRequest request,
final HttpContext context) throws HttpException,
IOException {
AuthState authState = (AuthState)
context.getAttribute(ClientContext.TARGET_AUTH_STATE);
CredentialsProvider credProvider =
(CredentialsProvider)context.getAttribute(
ClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost)context.getAttribute(
ExecutionContext.HTTP_TARGET_HOST);
authState.setCredentials(credProvider.getCredentials(
new AuthScope(targetHost.getHostName(),
targetHost.getPort())));
authState.setAuthScheme((BasicScheme)context.getAttribute(
"preemptive-auth"));
}
}
private HttpContext createHttpContext(String userName, String password){
String host = Utils.getHostName(baseUrl);
BasicHttpContext localcontext = new BasicHttpContext();
BasicScheme basicAuth = new BasicScheme();
localcontext.setAttribute("preemptive-auth", basicAuth);
CredentialsProvider credProvider = new BasicCredentialsProvider();
credProvider.setCredentials(
new AuthScope(host, HTTP_SSL_PORT),
new UsernamePasswordCredentials(userName, password));
localcontext.setAttribute(ClientContext.CREDS_PROVIDER, credProvider);
localcontext.setAttribute(
ClientContext.TARGET_AUTH_STATE, new AuthState());
HttpHost targetHost = new HttpHost(host, HTTP_SSL_PORT, "https");
localcontext.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost);
return localcontext;
}
public String doGet(final String url,
final String userName, final String password) throws
RestClientException {
HttpGet httpget = new HttpGet(this.baseUrl + url);
HttpResponse response = null;
try {
HttpContext localcontext = createHttpContext(userName, password);
response = httpClient.execute(httpget, localcontext);
return handleHttpResponse(response);
} catch (ClientProtocolException e) {
throw new RestClientException(e);
} catch (IllegalStateException e) {
throw new RestClientException(e);
} catch (IOException e) {
throw new RestClientException(e);
} catch (Exception e){
throw new RestClientException(e);
}finally{
try {
EntityUtils.consume(response.getEntity());
} catch (Exception e) {
logger.warn("Exception in EntityUtils.consume - ", e);
}
httpClient.getConnectionManager().closeIdleConnections(60000,
TimeUnit.MILLISECONDS);
httpClient.getConnectionManager().closeExpiredConnections();
}
}
}
Regards
Sukhdev