Uploaded image for project: 'Spring Web Services'
  1. Spring Web Services
  2. SWS-563

Provide support for Apache HttpClient 4.0

    Details

    • Type: New Feature
    • Status: Resolved
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: None
    • Fix Version/s: 2.1 RC1
    • Component/s: Core
    • Labels:
      None

      Description

      I would like to be able to use the Apache HttpClient 4.0 in Spring WS, now that it is out of beta

      1. HttpClientMessageSender.java
        8 kB
        Alan Stewart (personal account)
      2. HttpClientMessageSender.java
        8 kB
        Alan Stewart (personal account)
      3. HttpClientConnection.java
        4 kB
        Alan Stewart (personal account)
      4. HttpClientMessageSender.java
        9 kB
        Barry
      5. HttpClientConnection.java
        6 kB
        Barry
      6. ProtocolExceptionOverrideInterceptor.java
        2 kB
        Barry

        Activity

        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        This is now in SVN, as HttpComponentsMessageSender.

        Thanks for the patches, guys, it really made my job a lot easier!

        Show
        arjen.poutsma Arjen Poutsma added a comment - This is now in SVN, as HttpComponentsMessageSender. Thanks for the patches, guys, it really made my job a lot easier!
        Hide
        barrypitman Barry added a comment -

        Hi Arjen,

        One of my use-cases is that I need to be able to specify different HTTP Basic Auth credentials per request, based on the current user (the context). Looking at the changes at https://fisheye.springsource.org/browse/~br=trunk/spring-ws/trunk/core/src/main/java/org/springframework/ws/transport/http/HttpComponentsConnection.java?r=1981&r=1981, I don't think that will be possible, because I need to specify a org.apache.http.protocol.HttpContext when making the request.

        Oleg alluded to using the HttpContext to supply credentials earlier:

        There are better ways of providing auth credentials at run-time, for instance by binding a custom credentials provider to the local execution context or by using a custom protocol interceptor. For details see:

        http://hc.apache.org/httpcomponents-client/tutorial/html/authentication.html#d4e909
        http://hc.apache.org/httpcomponents-client/tutorial/html/authentication.html#d4e942

        The problem is that there is no way to provide a org.apache.http.protocol.HttpContext for httpClient.execute(httpPost, httpContext).

        What I have been doing in the past is subclassing HttpComponentsMessageSender to override createConnection(URI uri), creating a HttpComponentsConnection with a HttpContext instance like so:

        public abstract class BasicAuthHttpComponentsMessageSender extends HttpComponentsMessageSender {
         
            @Override
            public WebServiceConnection createConnection(URI uri) throws IOException {
                HttpPost httpPost = new HttpPost(uri);
                if (isAcceptGzipEncoding()) {
                    httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING, HttpTransportConstants.CONTENT_ENCODING_GZIP);
                }
         
                HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
         
                ((DefaultHttpClient) getHttpClient()).getCredentialsProvider().setCredentials(
                        new AuthScope(targetHost.getHostName(), targetHost.getPort()), getCredentials());
         
         
                AuthCache authCache = new BasicAuthCache();
                BasicScheme basicAuth = new BasicScheme();
                authCache.put(targetHost, basicAuth);
         
                BasicHttpContext localContext = new BasicHttpContext();
                localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
         
                return new HttpComponentsConnection(getHttpClient(), httpPost, localContext);
            }
         
            protected abstract UsernamePasswordCredentials getCredentials();
        }

        Would it be possible to include a constructor for HttpComponentsConnection that takes a org.apache.http.protocol.HttpContext?

        Thanks a lot

        Show
        barrypitman Barry added a comment - Hi Arjen, One of my use-cases is that I need to be able to specify different HTTP Basic Auth credentials per request, based on the current user (the context). Looking at the changes at https://fisheye.springsource.org/browse/~br=trunk/spring-ws/trunk/core/src/main/java/org/springframework/ws/transport/http/HttpComponentsConnection.java?r=1981&r=1981 , I don't think that will be possible, because I need to specify a org.apache.http.protocol.HttpContext when making the request. Oleg alluded to using the HttpContext to supply credentials earlier: There are better ways of providing auth credentials at run-time, for instance by binding a custom credentials provider to the local execution context or by using a custom protocol interceptor. For details see: http://hc.apache.org/httpcomponents-client/tutorial/html/authentication.html#d4e909 http://hc.apache.org/httpcomponents-client/tutorial/html/authentication.html#d4e942 The problem is that there is no way to provide a org.apache.http.protocol.HttpContext for httpClient.execute(httpPost, httpContext). What I have been doing in the past is subclassing HttpComponentsMessageSender to override createConnection(URI uri) , creating a HttpComponentsConnection with a HttpContext instance like so: public abstract class BasicAuthHttpComponentsMessageSender extends HttpComponentsMessageSender {   @Override public WebServiceConnection createConnection(URI uri) throws IOException { HttpPost httpPost = new HttpPost(uri); if (isAcceptGzipEncoding()) { httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING, HttpTransportConstants.CONTENT_ENCODING_GZIP); }   HttpHost targetHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());   ((DefaultHttpClient) getHttpClient()).getCredentialsProvider().setCredentials( new AuthScope(targetHost.getHostName(), targetHost.getPort()), getCredentials());     AuthCache authCache = new BasicAuthCache(); BasicScheme basicAuth = new BasicScheme(); authCache.put(targetHost, basicAuth);   BasicHttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);   return new HttpComponentsConnection(getHttpClient(), httpPost, localContext); }   protected abstract UsernamePasswordCredentials getCredentials(); } Would it be possible to include a constructor for HttpComponentsConnection that takes a org.apache.http.protocol.HttpContext ? Thanks a lot
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        I'll take a look tomorrow.

        Show
        arjen.poutsma Arjen Poutsma added a comment - I'll take a look tomorrow.
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        I've added a createContext(URI) template method that allows you to create a http context for a given URI. The default implementation returns null.

        Hope that helps!

        Show
        arjen.poutsma Arjen Poutsma added a comment - I've added a createContext(URI) template method that allows you to create a http context for a given URI. The default implementation returns null. Hope that helps!
        Hide
        barrypitman Barry added a comment -

        Great, thanks!

        Show
        barrypitman Barry added a comment - Great, thanks!

          People

          • Assignee:
            arjen.poutsma Arjen Poutsma
            Reporter:
            alankstewart Alan Stewart (personal account)
          • Votes:
            27 Vote for this issue
            Watchers:
            27 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - Not Specified
              Not Specified
              Remaining:
              Remaining Estimate - 0d
              0d
              Logged:
              Time Spent - 6h 8m
              6h 8m