13

I have a setup where tomcat server hosting my REST servers redirects calls from HTTP (port 9080) to HTTPS ( port 9443 ).

I'm using jersey 2.5 implementation and cannot manage to configure the clients to follow redirections.

I've found this SO question( Jersey client doesn't follow redirects ), however it's provided for jersey 1.X series and the API has changed.

I've tried to adapt it for 2.5 with the following test code :

 SSLContextProvider ssl = new TrustAllSSLContextImpl(); // just trust all certs
 Response response  =     ClientBuilder.newBuilder()
     .sslContext(ssl.getContext()).newClient()
     .register(LoggingFilter.class)
     .target("http://testhost.domain.org:9080/rest.webapp/api/v1/hello/")
     .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE)
     .request().get();   
 Assertions.assertThat(response.getStatus()).isNotEqualTo(302);

Which fails as the client does not seem to follow the redirections. Here is what the logging filter provides :

Feb 14, 2014 12:23:45 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 1 * Sending client request on thread main
1 > GET http://testhost.domain.org:9080/rest.webapp/api/v1/hello/

Feb 14, 2014 12:23:45 PM org.glassfish.jersey.filter.LoggingFilter log
INFO: 1 * Client response received on thread main
1 < 302
1 < Cache-Control: private
1 < Content-Length: 0
1 < Date: Fri, 14 Feb 2014 11:38:59 GMT
1 < Expires: Thu, 01 Jan 1970 01:00:00 CET
1 < Location: https://testhost.domain.org:9443/rest.webapp/api/v1/hello/
1 < Server: Apache-Coyote/1.1

From the jersey doc I understood that all that needs to be done is to add the ClientProperties.FOLLOW_REDIRECTS property to the client, but this obviously not to be the case.I've also found messages indicating that maybe a client side filter is required to follow the redirections, but found no examples or guidelines on this.

So if anyone having some experience with jax.rs and redirection could point me to some directions/docs/example code I'd really appreciate.

sleske
  • 81,358
  • 34
  • 189
  • 227
devlearn
  • 1,725
  • 2
  • 17
  • 30

3 Answers3

14

correct way to do this is:

webTarget.property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE);
harschware
  • 13,006
  • 17
  • 55
  • 87
Nitin
  • 181
  • 1
  • 2
  • 6
    are you sure that the last param is "false" ? Seems to me that this simply disables the redirection :) – devlearn Aug 19 '14 at 14:10
  • 5
    This should be `webTarget.property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE)`, as the prior commenter noted. – Laird Nelson Jun 28 '16 at 22:23
  • 1
    This only works for Jersey only; ClientProperties is a Jersey class. JAX-RS doesn't specify any redirect handling options, yet – rü- Oct 27 '17 at 04:14
  • 1
    This is wrong; this will only enable redirects if the protocol does _not_ change, not redirects HTTP->HTTPS. Also, this setting is already "true" by default anyway. – sleske Sep 26 '19 at 13:54
  • 2
    -1 because this is jersey only, but the original author explicitely asked for JAX-RS (which is a standard implemented by jersey which he is currently using). – Benjamin Marwell Jan 13 '20 at 11:08
10

Well I finally figured this out using a filter, not sure this is the best solution, any comments are appreciated :

public class FollowRedirectFilter implements ClientResponseFilter
{
   @Override
   public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException
   {
      if (responseContext.getStatusInfo().getFamily() != Response.Status.Family.REDIRECTION)
         return;

      Response resp = requestContext.getClient().target(responseContext.getLocation()).request().method(requestContext.getMethod());

      responseContext.setEntityStream((InputStream) resp.getEntity());
      responseContext.setStatusInfo(resp.getStatusInfo());
      responseContext.setStatus(resp.getStatus());
   }
}
devlearn
  • 1,725
  • 2
  • 17
  • 30
  • I found an answer here http://stackoverflow.com/questions/1884230/urlconnection-doesnt-follow-redirect: there redirect from http to https doesn't work for security reasons. – Maxim Mazin Jan 12 '17 at 13:58
  • do not forget to a) Annotate the Filter with `@javax.ws.rs.ext.Provider` and b) `register` it at the Client. – Frank Neblung Feb 25 '19 at 15:08
  • @FrankNeblung: Depending on how it is registered, the annotation may not be required. But it definitely needs to be registered with JAX-RS. – sleske Sep 27 '19 at 11:33
  • While this does work in the sense that it successfully follows the redirect, it has some issues. When I tried to use it, the Content-Type as returned by response.getMediaType() was the Content-Type returned by the first request, not by the redirected request. So it seems that re-using the ResponseContext like this is not a clean solution. – sleske Sep 27 '19 at 12:28
2

This happens because Http(s)UrlConnection doesn't follow redirect if URL scheme changes during the redirect (see e.g. HTTPURLConnection Doesn't Follow Redirect from HTTP to HTTPS ). So the possible solution is to use alternative client transport connector.

This could look like

SSLContextProvider ssl = new TrustAllSSLContextImpl(); // just trust all certs

JerseyClientBuilder clientBuilder = new JerseyClientBuilder()
 .sslContext(ssl.getContext())
 .register(LoggingFilter.class);
clientBuilder.getConfiguration().connectorProvider(new org.glassfish.jersey.apache.connector.ApacheConnectorProvider());

JerseyClient client = clientBuilder.build();

Response response = client    
 .target("http://testhost.domain.org:9080/rest.webapp/api/v1/hello/")
 .property(ClientProperties.FOLLOW_REDIRECTS, Boolean.TRUE)
 .request().get();
Assertions.assertThat(response.getStatus()).isNotEqualTo(302);
sleske
  • 81,358
  • 34
  • 189
  • 227
Maxim Mazin
  • 3,816
  • 1
  • 21
  • 15