Jersey Client: java.net.ProtocolException: Server redirected too many times/Setting cookies on request
A couple of weeks ago I was trying to write a test around some OAuth code that we have on an internal application and I was using Jersey Client to send the various requests.
I initially started with the following code:
Client = Client.create();
ClientResponse response = client.resource( "http://localhost:59680" ).get( ClientResponse.class );
but when I ran the test I was getting the following exception:
com.sun.jersey.api.client.ClientHandlerException: java.net.ProtocolException: Server redirected too many times (20)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:151)
at com.sun.jersey.api.client.Client.handle(Client.java:648)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680)
at com.sun.jersey.api.client.WebResource.get(WebResource.java:191)
at com.neotechnology.testlab.manager.webapp.AuthenticationIntegrationTest.shouldRedirectToGitHubForAuthentication(AuthenticationIntegrationTest.java:81)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at com.neotechnology.kirkaldy.testing.Resources$1.evaluate(Resources.java:84)
at com.neotechnology.kirkaldy.testing.FailureOutput$2.evaluate(FailureOutput.java:37)
at org.junit.rules.RunRules.evaluate(RunRules.java:18)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
Caused by: java.net.ProtocolException: Server redirected too many times (20)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1446)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:249)
at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:149)
... 28 more
If we check the traffic going across port 59680 we can see what’s going wrong:
$ sudo ngrep -d lo0 port 59680
interface: lo0 (127.0.0.0/255.0.0.0)
filter: (ip) and ( port 59680 )
#####
T 127.0.0.1:59704 -> 127.0.0.1:59680 [AP]
GET / HTTP/1.1..User-Agent: Java/1.6.0_45..Host: localhost:59680..Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2..Connection: keep-alive....
##
T 127.0.0.1:59680 -> 127.0.0.1:59704 [AP]
HTTP/1.1 302 Found..Set-Cookie: JSESSIONID=mdyw3a4fmqc1b6p53birm4dd;Path=/..Expires: Thu, 01 Jan 1970 00:00:00 GMT..Location: http://localhost:59679/authorize?client_id=basic-client&state=the-state&scope=user%2Crepo..Content-Length
: 0..Server: Jetty(8.1.8.v20121106)....
###########
T 127.0.0.1:59707 -> 127.0.0.1:59680 [AP]
GET /auth/callback?code=timey-wimey&state=the-state HTTP/1.1..User-Agent: Java/1.6.0_45..Host: localhost:59680..Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2..Connection: keep-alive....
##
T 127.0.0.1:59680 -> 127.0.0.1:59707 [AP]
HTTP/1.1 302 Found..Cache-Control: no-cache..Set-Cookie: JSESSIONID=8gggez0ns9ftiex4314mbgz9;Path=/..Expires: Thu, 01 Jan 1970 00:00:00 GMT..Location: http://localhost:59680/..Content-Length: 0..Server: Jetty(8.1.8.v20121106)....
###########
T 127.0.0.1:59713 -> 127.0.0.1:59680 [AP]
GET / HTTP/1.1..User-Agent: Java/1.6.0_45..Host: localhost:59680..Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2..Connection: keep-alive....
##
The response we receive includes a direction to the client to store a cookie but we can see on the next request that the cookie hasn’t been included.
I came across this post which had a few suggestions on how to get around the problem but the only approach that worked for me was to use jersey-apache-client for which I added the following dependency:
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client</artifactId>
<version>1.13</version>
<type>jar</type>
</dependency>
I then change my client code to read like this:
ApacheHttpClientConfig config = new DefaultApacheHttpClientConfig();
config.getProperties().put(ApacheHttpClientConfig.PROPERTY_HANDLE_COOKIES, true);
ApacheHttpClient client = ApacheHttpClient.create( config );
client.setFollowRedirects(true);
client.getClientHandler().getHttpClient().getParams().setBooleanParameter( HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, true );
ClientResponse response = client.resource( "http://localhost:59680" ).get( ClientResponse.class );
If we run that and watch the output using ngrep we can see that it now handles cookies correctly:
$ sudo ngrep -d lo0 port 59680
Password:
interface: lo0 (127.0.0.0/255.0.0.0)
filter: (ip) and ( port 59680 )
#####
T 127.0.0.1:60372 -> 127.0.0.1:59680 [AP]
GET / HTTP/1.1..User-Agent: Jakarta Commons-HttpClient/3.1..Host: localhost:59680....
##
T 127.0.0.1:59680 -> 127.0.0.1:60372 [AP]
HTTP/1.1 302 Found..Set-Cookie: JSESSIONID=vn8zzf9ep3x4mtw66ydm0n6a;Path=/..Expires: Thu, 01 Jan 1970 00:00:00 GMT..Location: http://localhost:60322/authorize?client_id=basic-client&state=the-state&scope=user%2Crepo..Content-Length
: 0..Server: Jetty(8.1.8.v20121106)....
##
T 127.0.0.1:60372 -> 127.0.0.1:59680 [AP]
GET /auth/callback?code=timey-wimey&state=the-state HTTP/1.1..User-Agent: Jakarta Commons-HttpClient/3.1..Host: localhost:59680..Cookie: $Version=0; JSESSIONID=vn8zzf9ep3x4mtw66ydm0n6a; $Path=/....
##
T 127.0.0.1:59680 -> 127.0.0.1:60372 [AP]
HTTP/1.1 302 Found..Cache-Control: no-cache..Location: http://localhost:59680/..Content-Length: 0..Server: Jetty(8.1.8.v20121106)....
##
T 127.0.0.1:60372 -> 127.0.0.1:59680 [AP]
GET / HTTP/1.1..User-Agent: Jakarta Commons-HttpClient/3.1..Host: localhost:59680..Cookie: $Version=0; JSESSIONID=vn8zzf9ep3x4mtw66ydm0n6a; $Path=/....
##
T 127.0.0.1:59680 -> 127.0.0.1:60372 [AP]
HTTP/1.1 200 OK..Vary: Accept-Encoding..Accept-Ranges: bytes..Content-Type: text/html..Content-Length: 2439..Last-Modified: Tue, 23 Jul 2013 10:48:15 GMT..Server: Jetty(8.1.8.v20121106)....<!DOCTYPE html>.<html>.<head>. <title>Tes
t Lab</title>. <meta name="viewport" content="width=device-width initial-scale=1.0 maximum-scale=1.0 user-scalable=0"/>. <link rel="stylesheet" type="text/css" href="css/bootstrap.css">. <link rel="stylesheet" type="text/css" hr
ef="css/bootstrap-responsive.css">. <link rel="stylesheet" type="text/css" href="css/test-lab.css">. <link rel="icon" type="image/png" href="images/testlab-16.png">. <script src="js/require.js"></script>. <script src="js/d3.v3.
js" charset="UTF-8"></script>. <script src="js/jquery-1.8.3.min.js"></script>. <script src="js/bootstrap.js"></script>. <script src="js/test-lab.js"></script>. <script type="text/javascript" src="js/google-analytics.js"></scrip
t>.</head>.<body>..<a href="navbar.html" class="inline-replacement"></a>..<div class="container">.. <h1 class="title">Neo Technology Test Lab</h1>.. <div class="dev-mode">Viewing dev-mode</div>.. <h2>Benchmark Series Results</h2
>.. <table id="benchmarkseries_list" class="table">. <thead></thead>. <tbody></tbody>. </table>.. <a href="new-benchmark-series.html" class="btn load-modal"><i class="icon-plus"></i> Create Benchmark Series...</a>.. <h2>T
ests</h2>.. <table id="test_list" class="table">. <thead></thead>. <tbody></tbody>. </table>.. <a href="run-test.html" class="btn load-modal"><i class="icon-plus"></i> Run Test...</a>. <a href="run-benchmark.html" class="
btn load-modal"><i class="icon-plus"></i> Run Benchmark...</a>.. <h2>Clusters</h2>.. <table id="cluster_list" class="table"></table>.. <a href="new-database-cluster.html" class="btn load-modal"><i class="icon-plus"></i> New Data
base Cluster...</a>. <a href="new-load-generation-cluster.html" class="btn load-modal"><i class="icon-plus"></i> New Load Generation Cluster...</a>.. <h2>Datasets</h2>.. <table id="dataset_list" class="table">. <thead></thead
>. <tbody></tbody>. </table>.. <a href="new-dataset.html" class="btn load-modal"><i class="icon-plus"></i> Create New Dataset...</a>.. <a href="confirm.html" class="inline-replacement"></a>..</div>..<script type="text/javascr
ipt">. (function (). {. window.setInterval( function (). {. d3.json( "/public/authenticated", function ( status ). {. if ( !status.authenticated ). {. window.location.reload();. }.
} );. }, 5000 );. kirkaldy.initializeUI();. })();.</script>..</body>.</html>.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.