1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.nio.client.integration;
28
29 import java.io.IOException;
30 import java.net.InetSocketAddress;
31 import java.net.URISyntaxException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.List;
36 import java.util.Queue;
37 import java.util.concurrent.ConcurrentLinkedQueue;
38 import java.util.concurrent.ExecutionException;
39 import java.util.concurrent.Future;
40 import java.util.concurrent.TimeUnit;
41
42 import org.apache.http.Header;
43 import org.apache.http.impl.client.DefaultRedirectStrategy;
44 import org.apache.http.localserver.HttpAsyncTestBase;
45 import org.apache.http.HttpException;
46 import org.apache.http.HttpHost;
47 import org.apache.http.HttpInetConnection;
48 import org.apache.http.HttpRequest;
49 import org.apache.http.HttpResponse;
50 import org.apache.http.HttpStatus;
51 import org.apache.http.ProtocolException;
52 import org.apache.http.ProtocolVersion;
53 import org.apache.http.client.CircularRedirectException;
54 import org.apache.http.client.CookieStore;
55 import org.apache.http.client.RedirectException;
56 import org.apache.http.client.config.RequestConfig;
57 import org.apache.http.client.methods.HttpGet;
58 import org.apache.http.client.methods.HttpPost;
59 import org.apache.http.client.protocol.HttpClientContext;
60 import org.apache.http.client.utils.URIBuilder;
61 import org.apache.http.cookie.SM;
62 import org.apache.http.entity.StringEntity;
63 import org.apache.http.impl.client.BasicCookieStore;
64 import org.apache.http.impl.cookie.BasicClientCookie;
65 import org.apache.http.impl.nio.bootstrap.HttpServer;
66 import org.apache.http.localserver.RandomHandler;
67 import org.apache.http.message.BasicHeader;
68 import org.apache.http.nio.entity.NStringEntity;
69 import org.apache.http.nio.protocol.BasicAsyncRequestHandler;
70 import org.apache.http.nio.reactor.ListenerEndpoint;
71 import org.apache.http.protocol.HTTP;
72 import org.apache.http.protocol.HttpContext;
73 import org.apache.http.protocol.HttpCoreContext;
74 import org.apache.http.protocol.HttpRequestHandler;
75 import org.junit.Assert;
76 import org.junit.Test;
77 import org.junit.runner.RunWith;
78 import org.junit.runners.Parameterized;
79
80
81
82
83 @RunWith(Parameterized.class)
84 public class TestRedirects extends HttpAsyncTestBase {
85
86 @Parameterized.Parameters(name = "{0}")
87 public static Collection<Object[]> protocols() {
88 return Arrays.asList(new Object[][]{
89 {ProtocolScheme.http},
90 {ProtocolScheme.https},
91 });
92 }
93
94 public TestRedirects(final ProtocolScheme scheme) {
95 super(scheme);
96 }
97
98 static class BasicRedirectService implements HttpRequestHandler {
99
100 private final String schemeName;
101 private final int statuscode;
102
103 public BasicRedirectService(final String schemeName, final int statuscode) {
104 super();
105 this.schemeName = schemeName;
106 this.statuscode = statuscode;
107 }
108
109 @Override
110 public void handle(
111 final HttpRequest request,
112 final HttpResponse response,
113 final HttpContext context) throws HttpException, IOException {
114 final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(
115 HttpCoreContext.HTTP_CONNECTION);
116 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
117 final String uri = request.getRequestLine().getUri();
118 if (uri.equals("/oldlocation/")) {
119 final String redirectUrl = this.schemeName + "://localhost:" + conn.getLocalPort() + "/newlocation/";
120 response.setStatusLine(ver, this.statuscode);
121 response.addHeader(new BasicHeader("Location", redirectUrl));
122 response.addHeader(new BasicHeader("Connection", "close"));
123 } else if (uri.equals("/newlocation/")) {
124 response.setStatusLine(ver, HttpStatus.SC_OK);
125 final StringEntity entity = new StringEntity("Successful redirect");
126 response.setEntity(entity);
127 } else {
128 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
129 }
130 }
131 }
132
133 static class CircularRedirectService implements HttpRequestHandler {
134
135 public CircularRedirectService() {
136 super();
137 }
138
139 @Override
140 public void handle(
141 final HttpRequest request,
142 final HttpResponse response,
143 final HttpContext context) throws HttpException, IOException {
144 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
145 final String uri = request.getRequestLine().getUri();
146 if (uri.startsWith("/circular-oldlocation")) {
147 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
148 response.addHeader(new BasicHeader("Location", "/circular-location2"));
149 } else if (uri.startsWith("/circular-location2")) {
150 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
151 response.addHeader(new BasicHeader("Location", "/circular-oldlocation"));
152 } else {
153 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
154 }
155 }
156 }
157
158 static class RelativeRedirectService implements HttpRequestHandler {
159
160 public RelativeRedirectService() {
161 super();
162 }
163
164 @Override
165 public void handle(
166 final HttpRequest request,
167 final HttpResponse response,
168 final HttpContext context) throws HttpException, IOException {
169 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
170 final String uri = request.getRequestLine().getUri();
171 if (uri.equals("/oldlocation/")) {
172 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
173 response.addHeader(new BasicHeader("Location", "/relativelocation/"));
174 } else if (uri.equals("/relativelocation/")) {
175 response.setStatusLine(ver, HttpStatus.SC_OK);
176 final StringEntity entity = new StringEntity("Successful redirect");
177 response.setEntity(entity);
178 } else {
179 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
180 }
181 }
182 }
183
184 static class RelativeRedirectService2 implements HttpRequestHandler {
185
186 public RelativeRedirectService2() {
187 super();
188 }
189
190 @Override
191 public void handle(
192 final HttpRequest request,
193 final HttpResponse response,
194 final HttpContext context) throws HttpException, IOException {
195 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
196 final String uri = request.getRequestLine().getUri();
197 if (uri.equals("/test/oldlocation")) {
198 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
199 response.addHeader(new BasicHeader("Location", "relativelocation"));
200 } else if (uri.equals("/test/relativelocation")) {
201 response.setStatusLine(ver, HttpStatus.SC_OK);
202 final StringEntity entity = new StringEntity("Successful redirect");
203 response.setEntity(entity);
204 } else {
205 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
206 }
207 }
208 }
209
210 static class BogusRedirectService implements HttpRequestHandler {
211
212 private final String schemeName;
213 private final String url;
214 private final boolean absolute;
215
216 public BogusRedirectService(final String schemeName, final String url, final boolean absolute) {
217 super();
218 this.schemeName = schemeName;
219 this.url = url;
220 this.absolute = absolute;
221 }
222
223 @Override
224 public void handle(
225 final HttpRequest request,
226 final HttpResponse response,
227 final HttpContext context) throws HttpException, IOException {
228 final HttpInetConnection conn = (HttpInetConnection) context.getAttribute(
229 HttpCoreContext.HTTP_CONNECTION);
230 String redirectUrl = this.url;
231 if (!this.absolute) {
232 redirectUrl = this.schemeName + "://localhost:" + conn.getLocalPort() + redirectUrl;
233 }
234
235 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
236 final String uri = request.getRequestLine().getUri();
237 if (uri.equals("/oldlocation/")) {
238 response.setStatusLine(ver, HttpStatus.SC_MOVED_TEMPORARILY);
239 response.addHeader(new BasicHeader("Location", redirectUrl));
240 } else if (uri.equals("/relativelocation/")) {
241 response.setStatusLine(ver, HttpStatus.SC_OK);
242 final StringEntity entity = new StringEntity("Successful redirect");
243 response.setEntity(entity);
244 } else {
245 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
246 }
247 }
248 }
249
250 private static class RomeRedirectService implements HttpRequestHandler {
251
252 public RomeRedirectService() {
253 super();
254 }
255
256 @Override
257 public void handle(
258 final HttpRequest request,
259 final HttpResponse response,
260 final HttpContext context) throws HttpException, IOException {
261 final String uri = request.getRequestLine().getUri();
262 if (uri.equals("/rome")) {
263 response.setStatusCode(HttpStatus.SC_OK);
264 final StringEntity entity = new StringEntity("Successful redirect");
265 response.setEntity(entity);
266 } else {
267 response.setStatusCode(HttpStatus.SC_MOVED_TEMPORARILY);
268 response.addHeader(new BasicHeader("Location", "/rome"));
269 }
270 }
271 }
272
273 private static class DifferentHostRedirectService implements HttpRequestHandler {
274
275 private final String schemeName;
276 private final int statusCode;
277 private int targetHostPort;
278
279 public DifferentHostRedirectService(final String schemeName, final int statusCode) {
280 this.schemeName = schemeName;
281 this.statusCode = statusCode;
282 }
283
284 @Override
285 public void handle(final HttpRequest request, final HttpResponse response,
286 final HttpContext context) throws HttpException, IOException {
287
288 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
289 final String uri = request.getRequestLine().getUri();
290 if (uri.equals("/oldlocation/")) {
291 final String redirectUrl =
292 this.schemeName + "://localhost:" + targetHostPort + "/newlocation/";
293 response.setStatusLine(ver, this.statusCode);
294 response.addHeader(new BasicHeader("Location", redirectUrl));
295 response.addHeader(new BasicHeader("Connection", "close"));
296 } else if (uri.equals("/newlocation/")) {
297 final String hostHeaderValue = request.getFirstHeader("Host").getValue();
298
299 if (hostHeaderValue.equals("localhost:" + targetHostPort)) {
300 response.setStatusLine(ver, HttpStatus.SC_OK);
301 final StringEntity entity = new StringEntity("Successful redirect");
302 response.setEntity(entity);
303 } else {
304 response.setStatusLine(ver, 421, "Misdirected Request");
305 }
306 } else {
307 response.setStatusLine(ver, HttpStatus.SC_NOT_FOUND);
308 }
309 }
310
311 public void setTargetHostPort(final int targetHostPort) {
312 this.targetHostPort = targetHostPort;
313 }
314 }
315
316 @Test
317 public void testBasicRedirect300() throws Exception {
318 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
319 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MULTIPLE_CHOICES)));
320 final HttpHost target = start();
321
322 final HttpClientContext context = HttpClientContext.create();
323
324 final HttpGet httpget = new HttpGet("/oldlocation/");
325
326 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
327 final HttpResponse response = future.get();
328 Assert.assertNotNull(response);
329
330 final HttpRequest reqWrapper = context.getRequest();
331
332 Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getStatusLine().getStatusCode());
333 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
334 }
335
336 @Test
337 public void testBasicRedirect301() throws Exception {
338 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
339 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_PERMANENTLY)));
340 final HttpHost target = start();
341
342 final HttpClientContext context = HttpClientContext.create();
343
344 final HttpGet httpget = new HttpGet("/oldlocation/");
345
346 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
347 final HttpResponse response = future.get();
348 Assert.assertNotNull(response);
349
350 final HttpRequest reqWrapper = context.getRequest();
351 final HttpHost host = context.getTargetHost();
352
353 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
354 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
355 Assert.assertEquals(target, host);
356 }
357
358 @Test
359 public void testBasicRedirect302() throws Exception {
360 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
361 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
362 final HttpHost target = start();
363
364 final HttpClientContext context = HttpClientContext.create();
365
366 final HttpGet httpget = new HttpGet("/oldlocation/");
367
368 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
369 final HttpResponse response = future.get();
370 Assert.assertNotNull(response);
371
372 final HttpRequest reqWrapper = context.getRequest();
373 final HttpHost host = context.getTargetHost();
374
375 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
376 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
377 Assert.assertEquals(target, host);
378 }
379
380 @Test
381 public void testBasicRedirect302NoLocation() throws Exception {
382 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new HttpRequestHandler() {
383
384 @Override
385 public void handle(
386 final HttpRequest request,
387 final HttpResponse response,
388 final HttpContext context) throws HttpException, IOException {
389 response.setStatusCode(HttpStatus.SC_MOVED_TEMPORARILY);
390 }
391
392 }));
393 final HttpHost target = start();
394
395 final HttpClientContext context = HttpClientContext.create();
396
397 final HttpGet httpget = new HttpGet("/oldlocation/");
398
399 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
400 final HttpResponse response = future.get();
401 Assert.assertNotNull(response);
402
403 final HttpRequest reqWrapper = context.getRequest();
404 final HttpHost host = context.getTargetHost();
405
406 Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getStatusLine().getStatusCode());
407 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
408 Assert.assertEquals(target, host);
409 }
410
411 @Test
412 public void testBasicRedirect303() throws Exception {
413 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
414 new BasicRedirectService(getSchemeName(), HttpStatus.SC_SEE_OTHER)));
415 final HttpHost target = start();
416
417 final HttpClientContext context = HttpClientContext.create();
418
419 final HttpGet httpget = new HttpGet("/oldlocation/");
420
421 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
422 final HttpResponse response = future.get();
423 Assert.assertNotNull(response);
424
425 final HttpRequest reqWrapper = context.getRequest();
426 final HttpHost host = context.getTargetHost();
427
428 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
429 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
430 Assert.assertEquals(target, host);
431 }
432
433 @Test
434 public void testBasicRedirect304() throws Exception {
435 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
436 new BasicRedirectService(getSchemeName(), HttpStatus.SC_NOT_MODIFIED)));
437 final HttpHost target = start();
438
439 final HttpClientContext context = HttpClientContext.create();
440
441 final HttpGet httpget = new HttpGet("/oldlocation/");
442
443 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
444 final HttpResponse response = future.get();
445 Assert.assertNotNull(response);
446
447 final HttpRequest reqWrapper = context.getRequest();
448
449 Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, response.getStatusLine().getStatusCode());
450 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
451 }
452
453 @Test
454 public void testBasicRedirect305() throws Exception {
455 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
456 new BasicRedirectService(getSchemeName(), HttpStatus.SC_USE_PROXY)));
457 final HttpHost target = start();
458
459 final HttpClientContext context = HttpClientContext.create();
460
461 final HttpGet httpget = new HttpGet("/oldlocation/");
462
463 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
464 final HttpResponse response = future.get();
465 Assert.assertNotNull(response);
466
467 final HttpRequest reqWrapper = context.getRequest();
468
469 Assert.assertEquals(HttpStatus.SC_USE_PROXY, response.getStatusLine().getStatusCode());
470 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
471 }
472
473 @Test
474 public void testBasicRedirect307() throws Exception {
475 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
476 new BasicRedirectService(getSchemeName(), HttpStatus.SC_TEMPORARY_REDIRECT)));
477 final HttpHost target = start();
478
479 final HttpClientContext context = HttpClientContext.create();
480
481 final HttpGet httpget = new HttpGet("/oldlocation/");
482
483 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
484 final HttpResponse response = future.get();
485 Assert.assertNotNull(response);
486
487 final HttpRequest reqWrapper = context.getRequest();
488 final HttpHost host = context.getTargetHost();
489
490 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
491 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
492 Assert.assertEquals(target, host);
493 }
494
495 @Test(expected=ExecutionException.class)
496 public void testMaxRedirectCheck() throws Exception {
497 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new CircularRedirectService()));
498 final HttpHost target = start();
499
500 final RequestConfig config = RequestConfig.custom()
501 .setCircularRedirectsAllowed(true)
502 .setMaxRedirects(5).build();
503
504 final HttpGet httpget = new HttpGet("/circular-oldlocation/");
505 httpget.setConfig(config);
506 try {
507 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
508 future.get();
509 } catch (final ExecutionException e) {
510 Assert.assertTrue(e.getCause() instanceof RedirectException);
511 throw e;
512 }
513 }
514
515 @Test(expected=ExecutionException.class)
516 public void testCircularRedirect() throws Exception {
517 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new CircularRedirectService()));
518 final HttpHost target = start();
519
520 final RequestConfig config = RequestConfig.custom()
521 .setCircularRedirectsAllowed(false)
522 .setRelativeRedirectsAllowed(true)
523 .build();
524
525 final HttpGet httpget = new HttpGet("/circular-oldlocation/");
526 httpget.setConfig(config);
527 try {
528 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
529 future.get();
530 } catch (final ExecutionException e) {
531 Assert.assertTrue(e.getCause() instanceof CircularRedirectException);
532 throw e;
533 }
534 }
535
536 @Test
537 public void testPostNoRedirect() throws Exception {
538 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
539 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
540 final HttpHost target = start();
541
542 final HttpClientContext context = HttpClientContext.create();
543
544 final HttpPost httppost = new HttpPost("/oldlocation/");
545 httppost.setEntity(new NStringEntity("stuff"));
546
547 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, context, null);
548 final HttpResponse response = future.get();
549 Assert.assertNotNull(response);
550
551 final HttpRequest reqWrapper = context.getRequest();
552
553 Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getStatusLine().getStatusCode());
554 Assert.assertEquals("/oldlocation/", reqWrapper.getRequestLine().getUri());
555 Assert.assertEquals("POST", reqWrapper.getRequestLine().getMethod());
556 }
557
558 @Test
559 public void testPostRedirectSeeOther() throws Exception {
560 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
561 new BasicRedirectService(getSchemeName(), HttpStatus.SC_SEE_OTHER)));
562 final HttpHost target = start();
563
564 final HttpClientContext context = HttpClientContext.create();
565
566 final HttpPost httppost = new HttpPost("/oldlocation/");
567 httppost.setEntity(new NStringEntity("stuff"));
568
569 final Future<HttpResponse> future = this.httpclient.execute(target, httppost, context, null);
570 final HttpResponse response = future.get();
571 Assert.assertNotNull(response);
572
573 final HttpRequest reqWrapper = context.getRequest();
574
575 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
576 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
577 Assert.assertEquals("GET", reqWrapper.getRequestLine().getMethod());
578 }
579
580 @Test
581 public void testRelativeRedirect() throws Exception {
582 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RelativeRedirectService()));
583 final HttpHost target = start();
584
585 final HttpClientContext context = HttpClientContext.create();
586
587 final RequestConfig config = RequestConfig.custom()
588 .setRelativeRedirectsAllowed(true)
589 .build();
590
591 final HttpGet httpget = new HttpGet("/oldlocation/");
592 httpget.setConfig(config);
593
594 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
595 final HttpResponse response = future.get();
596 Assert.assertNotNull(response);
597
598 final HttpRequest reqWrapper = context.getRequest();
599 final HttpHost host = context.getTargetHost();
600
601 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
602 Assert.assertEquals("/relativelocation/", reqWrapper.getRequestLine().getUri());
603 Assert.assertEquals(target, host);
604 }
605
606 @Test
607 public void testRelativeRedirect2() throws Exception {
608 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RelativeRedirectService2()));
609 final HttpHost target = start();
610
611 final HttpClientContext context = HttpClientContext.create();
612
613 final RequestConfig config = RequestConfig.custom()
614 .setRelativeRedirectsAllowed(true)
615 .build();
616
617 final HttpGet httpget = new HttpGet("/test/oldlocation");
618 httpget.setConfig(config);
619
620 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
621 final HttpResponse response = future.get();
622 Assert.assertNotNull(response);
623
624 final HttpRequest reqWrapper = context.getRequest();
625 final HttpHost host = context.getTargetHost();
626
627 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
628 Assert.assertEquals("/test/relativelocation", reqWrapper.getRequestLine().getUri());
629 Assert.assertEquals(target, host);
630 }
631
632 @Test(expected=ExecutionException.class)
633 public void testRejectRelativeRedirect() throws Exception {
634 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RelativeRedirectService()));
635 final HttpHost target = start();
636
637 final RequestConfig config = RequestConfig.custom()
638 .setRelativeRedirectsAllowed(false)
639 .build();
640
641 final HttpGet httpget = new HttpGet("/oldlocation/");
642 httpget.setConfig(config);
643 try {
644 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
645 future.get();
646 } catch (final ExecutionException e) {
647 Assert.assertTrue(e.getCause() instanceof ProtocolException);
648 throw e;
649 }
650 }
651
652 @Test(expected=ExecutionException.class)
653 public void testRejectBogusRedirectLocation() throws Exception {
654 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
655 new BogusRedirectService(getSchemeName(), "xxx://bogus", true)));
656 final HttpHost target = start();
657
658 final HttpGet httpget = new HttpGet("/oldlocation/");
659
660 try {
661 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
662 future.get();
663 } catch (final ExecutionException ex) {
664 Assert.assertTrue(ex.getCause() instanceof HttpException);
665 throw ex;
666 }
667 }
668
669 @Test(expected=ExecutionException.class)
670 public void testRejectInvalidRedirectLocation() throws Exception {
671 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
672 new BogusRedirectService(getSchemeName(), "/newlocation/?p=I have spaces", false)));
673 final HttpHost target = start();
674
675 final HttpGet httpget = new HttpGet("/oldlocation/");
676 try {
677 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, null);
678 future.get();
679 } catch (final ExecutionException e) {
680 Assert.assertTrue(e.getCause() instanceof ProtocolException);
681 throw e;
682 }
683 }
684
685 @Test
686 public void testRedirectWithCookie() throws Exception {
687 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
688 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
689 final HttpHost target = start();
690
691 final CookieStore cookieStore = new BasicCookieStore();
692 final HttpClientContext context = HttpClientContext.create();
693 context.setCookieStore(cookieStore);
694
695 final BasicClientCookie cookie = new BasicClientCookie("name", "value");
696 cookie.setDomain(target.getHostName());
697 cookie.setPath("/");
698
699 cookieStore.addCookie(cookie);
700
701 final HttpGet httpget = new HttpGet("/oldlocation/");
702
703 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
704 final HttpResponse response = future.get();
705 Assert.assertNotNull(response);
706
707 final HttpRequest reqWrapper = context.getRequest();
708
709 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
710 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
711
712 final Header[] headers = reqWrapper.getHeaders(SM.COOKIE);
713 Assert.assertEquals("There can only be one (cookie)", 1, headers.length);
714 }
715
716 @Test
717 public void testDefaultHeadersRedirect() throws Exception {
718 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(
719 new BasicRedirectService(getSchemeName(), HttpStatus.SC_MOVED_TEMPORARILY)));
720
721 final List<Header> defaultHeaders = new ArrayList<Header>(1);
722 defaultHeaders.add(new BasicHeader(HTTP.USER_AGENT, "my-test-client"));
723 this.clientBuilder.setDefaultHeaders(defaultHeaders);
724
725 final HttpHost target = start();
726
727 final HttpClientContext context = HttpClientContext.create();
728
729 final HttpGet httpget = new HttpGet("/oldlocation/");
730
731 final Future<HttpResponse> future = this.httpclient.execute(target, httpget, context, null);
732 final HttpResponse response = future.get();
733 Assert.assertNotNull(response);
734
735 final HttpRequest reqWrapper = context.getRequest();
736
737 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
738 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
739
740 final Header header = reqWrapper.getFirstHeader(HTTP.USER_AGENT);
741 Assert.assertEquals("my-test-client", header.getValue());
742 }
743
744 static class CrossSiteRedirectService implements HttpRequestHandler {
745
746 private final HttpHost host;
747
748 public CrossSiteRedirectService(final HttpHost host) {
749 super();
750 this.host = host;
751 }
752
753 @Override
754 public void handle(
755 final HttpRequest request,
756 final HttpResponse response,
757 final HttpContext context) throws HttpException, IOException {
758 final ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
759 final String location;
760 try {
761 final URIBuilder uribuilder = new URIBuilder(request.getRequestLine().getUri());
762 uribuilder.setScheme(this.host.getSchemeName());
763 uribuilder.setHost(this.host.getHostName());
764 uribuilder.setPort(this.host.getPort());
765 uribuilder.setPath("/random/1024");
766 location = uribuilder.build().toASCIIString();
767 } catch (final URISyntaxException ex) {
768 throw new ProtocolException("Invalid request URI", ex);
769 }
770 response.setStatusLine(ver, HttpStatus.SC_TEMPORARY_REDIRECT);
771 response.addHeader(new BasicHeader("Location", location));
772 }
773 }
774
775 @Test
776 public void testCrossSiteRedirect() throws Exception {
777 this.serverBootstrap.registerHandler("/random/*", new BasicAsyncRequestHandler(
778 new RandomHandler()));
779 final HttpHost redirectTarget = start();
780
781 this.serverBootstrap.registerHandler("/redirect/*", new BasicAsyncRequestHandler(
782 new CrossSiteRedirectService(redirectTarget)));
783
784 final HttpServer secondServer = this.serverBootstrap.create();
785 try {
786 secondServer.start();
787 final ListenerEndpoint endpoint2 = secondServer.getEndpoint();
788 endpoint2.waitFor();
789
790 final InetSocketAddress address2 = (InetSocketAddress) endpoint2.getAddress();
791 final HttpHost initialTarget = new HttpHost("localhost", address2.getPort(), getSchemeName());
792
793 final Queue<Future<HttpResponse>> queue = new ConcurrentLinkedQueue<Future<HttpResponse>>();
794 for (int i = 0; i < 4; i++) {
795 final HttpClientContext context = HttpClientContext.create();
796 final HttpGet httpget = new HttpGet("/redirect/anywhere");
797 queue.add(this.httpclient.execute(initialTarget, httpget, context, null));
798 }
799 while (!queue.isEmpty()) {
800 final Future<HttpResponse> future = queue.remove();
801 final HttpResponse response = future.get();
802 Assert.assertNotNull(response);
803 Assert.assertEquals(200, response.getStatusLine().getStatusCode());
804 }
805 } finally {
806 this.server.shutdown(10, TimeUnit.SECONDS);
807 }
808 }
809
810 @Test
811 public void testRepeatRequest() throws Exception {
812 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RomeRedirectService()));
813 final HttpHost target = start();
814
815 final HttpClientContext context = HttpClientContext.create();
816
817 final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(true).build();
818 final HttpGet first = new HttpGet("/rome");
819 first.setConfig(config);
820
821 final Future<HttpResponse> future1 = this.httpclient.execute(target, first, context, null);
822 final HttpResponse response1 = future1.get();
823 Assert.assertNotNull(response1);
824
825 final HttpGet second = new HttpGet("/rome");
826 second.setConfig(config);
827
828 final Future<HttpResponse> future2 = this.httpclient.execute(target, second, context, null);
829 final HttpResponse response2 = future2.get();
830 Assert.assertNotNull(response2);
831
832 final HttpRequest reqWrapper = context.getRequest();
833 final HttpHost host = context.getTargetHost();
834
835 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
836 Assert.assertEquals("/rome", reqWrapper.getRequestLine().getUri());
837 Assert.assertEquals(host, target);
838 }
839
840 @Test
841 public void testRepeatRequestRedirect() throws Exception {
842 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RomeRedirectService()));
843 final HttpHost target = start();
844
845 final HttpClientContext context = HttpClientContext.create();
846
847 final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(true).build();
848 final HttpGet first = new HttpGet("/lille");
849 first.setConfig(config);
850
851 final Future<HttpResponse> future1 = this.httpclient.execute(target, first, context, null);
852 final HttpResponse response1 = future1.get();
853 Assert.assertNotNull(response1);
854
855 final HttpGet second = new HttpGet("/lille");
856 second.setConfig(config);
857
858 final Future<HttpResponse> future2 = this.httpclient.execute(target, second, context, null);
859 final HttpResponse response2 = future2.get();
860 Assert.assertNotNull(response2);
861
862 final HttpRequest reqWrapper = context.getRequest();
863 final HttpHost host = context.getTargetHost();
864
865 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
866 Assert.assertEquals("/rome", reqWrapper.getRequestLine().getUri());
867 Assert.assertEquals(host, target);
868 }
869
870 @Test
871 public void testDifferentRequestSameRedirect() throws Exception {
872 this.serverBootstrap.registerHandler("*", new BasicAsyncRequestHandler(new RomeRedirectService()));
873 final HttpHost target = start();
874
875 final HttpClientContext context = HttpClientContext.create();
876
877 final RequestConfig config = RequestConfig.custom().setRelativeRedirectsAllowed(true).build();
878 final HttpGet first = new HttpGet("/alian");
879 first.setConfig(config);
880
881 final Future<HttpResponse> future1 = this.httpclient.execute(target, first, context, null);
882 final HttpResponse response1 = future1.get();
883 Assert.assertNotNull(response1);
884
885 final HttpGet second = new HttpGet("/lille");
886 second.setConfig(config);
887
888 final Future<HttpResponse> future2 = this.httpclient.execute(target, second, context, null);
889 final HttpResponse response2 = future2.get();
890 Assert.assertNotNull(response2);
891
892 final HttpRequest reqWrapper = context.getRequest();
893 final HttpHost host = context.getTargetHost();
894
895 Assert.assertEquals(HttpStatus.SC_OK, response2.getStatusLine().getStatusCode());
896 Assert.assertEquals("/rome", reqWrapper.getRequestLine().getUri());
897 Assert.assertEquals(host, target);
898 }
899
900 @Test
901 public void testPostRedirectWithDifferentHost() throws Exception {
902
903 this.clientBuilder.setRedirectStrategy(new DefaultRedirectStrategy() {
904 @Override
905 public boolean isRedirected(final HttpRequest request, final HttpResponse response,
906 final HttpContext context)
907 throws ProtocolException {
908
909 return super.isRedirected(request, response, context)
910 || response.getStatusLine().getStatusCode() == HttpStatus.SC_TEMPORARY_REDIRECT;
911 }
912 });
913
914 final DifferentHostRedirectService differentHostRequestHandler = new DifferentHostRedirectService(
915 getSchemeName(), HttpStatus.SC_TEMPORARY_REDIRECT);
916
917 this.serverBootstrap.registerHandler("*",
918 new BasicAsyncRequestHandler(differentHostRequestHandler));
919 final HttpHost originalHost = start();
920 final HttpHost targetHost = startServer();
921
922 differentHostRequestHandler.setTargetHostPort(targetHost.getPort());
923
924 final HttpClientContext context = HttpClientContext.create();
925
926 final HttpPost httpPost = new HttpPost("/oldlocation/");
927
928 final Future<HttpResponse> future = this.httpclient.execute(originalHost, httpPost, context, null);
929 final HttpResponse response = future.get();
930 Assert.assertNotNull(response);
931
932 final HttpRequest reqWrapper = context.getRequest();
933 final HttpHost host = context.getTargetHost();
934
935 Assert.assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
936 Assert.assertEquals("/newlocation/", reqWrapper.getRequestLine().getUri());
937 Assert.assertEquals(targetHost, host);
938 }
939 }