One more observation on it.

I don't see this issue when I lock httpclient.execute (...) and let it run
by 1 thread at a time.
Looks like in httpclient 4.1.2, httpclient.execute(...) is not thread safe
as credentials are being overwritten by another thread.

How to fix this issue. Any setting in httpclient?

Regards
Sukhdev

On Wed, Sep 17, 2014 at 12:45 AM, Sukhdev Singh <[email protected]>
wrote:

> 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
>

Reply via email to