View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.testing.async;
28  
29  import java.net.InetSocketAddress;
30  import java.net.URI;
31  import java.net.URISyntaxException;
32  import java.util.concurrent.ExecutionException;
33  import java.util.concurrent.Future;
34  
35  import org.apache.hc.client5.http.CircularRedirectException;
36  import org.apache.hc.client5.http.RedirectException;
37  import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
38  import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
39  import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
40  import org.apache.hc.client5.http.config.RequestConfig;
41  import org.apache.hc.client5.http.cookie.BasicCookieStore;
42  import org.apache.hc.client5.http.cookie.CookieStore;
43  import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
44  import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
45  import org.apache.hc.client5.http.protocol.HttpClientContext;
46  import org.apache.hc.client5.testing.OldPathRedirectResolver;
47  import org.apache.hc.client5.testing.SSLTestContexts;
48  import org.apache.hc.client5.testing.redirect.Redirect;
49  import org.apache.hc.client5.testing.redirect.RedirectResolver;
50  import org.apache.hc.core5.function.Decorator;
51  import org.apache.hc.core5.function.Supplier;
52  import org.apache.hc.core5.http.ContentType;
53  import org.apache.hc.core5.http.Header;
54  import org.apache.hc.core5.http.HttpException;
55  import org.apache.hc.core5.http.HttpHost;
56  import org.apache.hc.core5.http.HttpRequest;
57  import org.apache.hc.core5.http.HttpResponse;
58  import org.apache.hc.core5.http.HttpStatus;
59  import org.apache.hc.core5.http.HttpVersion;
60  import org.apache.hc.core5.http.ProtocolException;
61  import org.apache.hc.core5.http.URIScheme;
62  import org.apache.hc.core5.http.config.Http1Config;
63  import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
64  import org.apache.hc.core5.http.protocol.HttpCoreContext;
65  import org.apache.hc.core5.http2.config.H2Config;
66  import org.apache.hc.core5.net.URIBuilder;
67  import org.apache.hc.core5.reactive.ReactiveServerExchangeHandler;
68  import org.apache.hc.core5.reactor.IOReactorConfig;
69  import org.apache.hc.core5.testing.nio.H2TestServer;
70  import org.apache.hc.core5.testing.reactive.ReactiveRandomProcessor;
71  import org.apache.hc.core5.util.TimeValue;
72  import org.junit.Assert;
73  import org.junit.Test;
74  
75  public abstract class AbstractHttpAsyncRedirectsTest <T extends CloseableHttpAsyncClient> extends AbstractIntegrationTestBase<T> {
76  
77      protected final HttpVersion version;
78  
79      public AbstractHttpAsyncRedirectsTest(final HttpVersion version, final URIScheme scheme) {
80          super(scheme);
81          this.version = version;
82      }
83  
84      @Override
85      public final HttpHost start() throws Exception {
86          if (version.greaterEquals(HttpVersion.HTTP_2)) {
87              return super.start(null, H2Config.DEFAULT);
88          } else {
89              return super.start(null, Http1Config.DEFAULT);
90          }
91      }
92  
93      public final HttpHost start(final Decorator<AsyncServerExchangeHandler> exchangeHandlerDecorator) throws Exception {
94          if (version.greaterEquals(HttpVersion.HTTP_2)) {
95              return super.start(null, exchangeHandlerDecorator, H2Config.DEFAULT);
96          } else {
97              return super.start(null, exchangeHandlerDecorator, Http1Config.DEFAULT);
98          }
99      }
100 
101     @Test
102     public void testBasicRedirect300() throws Exception {
103         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
104 
105             @Override
106             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
107                 return new RedirectingAsyncDecorator(
108                         exchangeHandler,
109                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES));
110             }
111 
112         });
113 
114         final HttpClientContext context = HttpClientContext.create();
115         final Future<SimpleHttpResponse> future = httpclient.execute(
116                 SimpleRequestBuilder.get()
117                         .setHttpHost(target)
118                         .setPath("/oldlocation/")
119                         .build(), context, null);
120         final HttpResponse response = future.get();
121         Assert.assertNotNull(response);
122 
123         final HttpRequest request = context.getRequest();
124 
125         Assert.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode());
126         Assert.assertEquals("/oldlocation/", request.getRequestUri());
127     }
128 
129     @Test
130     public void testBasicRedirect301() throws Exception {
131         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
132 
133             @Override
134             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
135                 return new RedirectingAsyncDecorator(
136                         exchangeHandler,
137                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY));
138             }
139 
140         });
141         final HttpClientContext context = HttpClientContext.create();
142         final Future<SimpleHttpResponse> future = httpclient.execute(
143                 SimpleRequestBuilder.get()
144                         .setHttpHost(target)
145                         .setPath("/oldlocation/100")
146                         .build(), context, null);
147         final HttpResponse response = future.get();
148         Assert.assertNotNull(response);
149 
150         final HttpRequest request = context.getRequest();
151 
152         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
153         Assert.assertEquals("/random/100", request.getRequestUri());
154         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
155     }
156 
157     @Test
158     public void testBasicRedirect302() throws Exception {
159         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
160 
161             @Override
162             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
163                 return new RedirectingAsyncDecorator(
164                         exchangeHandler,
165                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY));
166             }
167 
168         });
169         final HttpClientContext context = HttpClientContext.create();
170         final Future<SimpleHttpResponse> future = httpclient.execute(
171                 SimpleRequestBuilder.get()
172                         .setHttpHost(target)
173                         .setPath("/oldlocation/123")
174                         .build(), context, null);
175         final HttpResponse response = future.get();
176         Assert.assertNotNull(response);
177 
178         final HttpRequest request = context.getRequest();
179 
180         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
181         Assert.assertEquals("/random/123", request.getRequestUri());
182         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
183     }
184 
185     @Test
186     public void testBasicRedirect302NoLocation() throws Exception {
187         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
188 
189             @Override
190             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
191                 return new RedirectingAsyncDecorator(
192                         exchangeHandler,
193                         new RedirectResolver() {
194 
195                             @Override
196                             public Redirect resolve(final URI requestUri) throws URISyntaxException {
197                                 final String path = requestUri.getPath();
198                                 if (path.startsWith("/oldlocation")) {
199                                     return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null);
200                                 }
201                                 return null;
202                             }
203 
204                         });
205             }
206 
207         });
208         final HttpClientContext context = HttpClientContext.create();
209         final Future<SimpleHttpResponse> future = httpclient.execute(
210                 SimpleRequestBuilder.get()
211                         .setHttpHost(target)
212                         .setPath("/oldlocation/100")
213                         .build(), context, null);
214         final HttpResponse response = future.get();
215         Assert.assertNotNull(response);
216 
217         final HttpRequest request = context.getRequest();
218         Assert.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getCode());
219         Assert.assertEquals("/oldlocation/100", request.getRequestUri());
220         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
221     }
222 
223     @Test
224     public void testBasicRedirect303() throws Exception {
225         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
226 
227             @Override
228             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
229                 return new RedirectingAsyncDecorator(
230                         exchangeHandler,
231                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER));
232             }
233 
234         });
235         final HttpClientContext context = HttpClientContext.create();
236         final Future<SimpleHttpResponse> future = httpclient.execute(
237                 SimpleRequestBuilder.get()
238                         .setHttpHost(target)
239                         .setPath("/oldlocation/123")
240                         .build(), context, null);
241         final HttpResponse response = future.get();
242         Assert.assertNotNull(response);
243 
244         final HttpRequest request = context.getRequest();
245 
246         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
247         Assert.assertEquals("/random/123", request.getRequestUri());
248         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
249     }
250 
251     @Test
252     public void testBasicRedirect304() throws Exception {
253         server.register("/oldlocation/*", new Supplier<AsyncServerExchangeHandler>() {
254 
255             @Override
256             public AsyncServerExchangeHandler get() {
257 
258                 return new AbstractSimpleServerExchangeHandler() {
259 
260                     @Override
261                     protected SimpleHttpResponse handle(final SimpleHttpRequest request,
262                                                         final HttpCoreContext context) throws HttpException {
263                         return SimpleHttpResponse.create(HttpStatus.SC_NOT_MODIFIED, (String) null);
264                     }
265                 };
266 
267             }
268         });
269         final HttpHost target = start();
270         final HttpClientContext context = HttpClientContext.create();
271         final Future<SimpleHttpResponse> future = httpclient.execute(
272                 SimpleRequestBuilder.get()
273                         .setHttpHost(target)
274                         .setPath("/oldlocation/")
275                         .build(), context, null);
276         final HttpResponse response = future.get();
277         Assert.assertNotNull(response);
278 
279         final HttpRequest request = context.getRequest();
280 
281         Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, response.getCode());
282         Assert.assertEquals("/oldlocation/", request.getRequestUri());
283     }
284 
285     @Test
286     public void testBasicRedirect305() throws Exception {
287         server.register("/oldlocation/*", new Supplier<AsyncServerExchangeHandler>() {
288 
289             @Override
290             public AsyncServerExchangeHandler get() {
291 
292                 return new AbstractSimpleServerExchangeHandler() {
293 
294                     @Override
295                     protected SimpleHttpResponse handle(final SimpleHttpRequest request,
296                                                         final HttpCoreContext context) throws HttpException {
297                         return SimpleHttpResponse.create(HttpStatus.SC_USE_PROXY, (String) null);
298                     }
299                 };
300 
301             }
302         });
303         final HttpHost target = start();
304         final HttpClientContext context = HttpClientContext.create();
305         final Future<SimpleHttpResponse> future = httpclient.execute(
306                 SimpleRequestBuilder.get()
307                         .setHttpHost(target)
308                         .setPath("/oldlocation/")
309                         .build(), context, null);
310         final HttpResponse response = future.get();
311         Assert.assertNotNull(response);
312 
313         final HttpRequest request = context.getRequest();
314 
315         Assert.assertEquals(HttpStatus.SC_USE_PROXY, response.getCode());
316         Assert.assertEquals("/oldlocation/", request.getRequestUri());
317     }
318 
319     @Test
320     public void testBasicRedirect307() throws Exception {
321         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
322 
323             @Override
324             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
325                 return new RedirectingAsyncDecorator(
326                         exchangeHandler,
327                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT));
328             }
329 
330         });
331         final HttpClientContext context = HttpClientContext.create();
332         final Future<SimpleHttpResponse> future = httpclient.execute(
333                 SimpleRequestBuilder.get()
334                         .setHttpHost(target)
335                         .setPath("/oldlocation/123")
336                         .build(), context, null);
337         final HttpResponse response = future.get();
338         Assert.assertNotNull(response);
339 
340         final HttpRequest request = context.getRequest();
341 
342         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
343         Assert.assertEquals("/random/123", request.getRequestUri());
344         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
345     }
346 
347     @Test(expected=ExecutionException.class)
348     public void testMaxRedirectCheck() throws Exception {
349         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
350 
351             @Override
352             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
353                 return new RedirectingAsyncDecorator(
354                         exchangeHandler,
355                         new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/",
356                                 HttpStatus.SC_MOVED_TEMPORARILY));
357             }
358 
359         });
360 
361         final RequestConfig config = RequestConfig.custom()
362                 .setCircularRedirectsAllowed(true)
363                 .setMaxRedirects(5).build();
364         try {
365             final Future<SimpleHttpResponse> future = httpclient.execute(SimpleRequestBuilder.get()
366                     .setHttpHost(target)
367                     .setPath("/circular-oldlocation/")
368                     .setRequestConfig(config)
369                     .build(), null);
370             future.get();
371         } catch (final ExecutionException e) {
372             Assert.assertTrue(e.getCause() instanceof RedirectException);
373             throw e;
374         }
375     }
376 
377     @Test(expected=ExecutionException.class)
378     public void testCircularRedirect() throws Exception {
379         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
380 
381             @Override
382             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
383                 return new RedirectingAsyncDecorator(
384                         exchangeHandler,
385                         new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/",
386                                 HttpStatus.SC_MOVED_TEMPORARILY));
387             }
388 
389         });
390 
391         final RequestConfig config = RequestConfig.custom()
392                 .setCircularRedirectsAllowed(false)
393                 .build();
394         try {
395             final Future<SimpleHttpResponse> future = httpclient.execute(
396                     SimpleRequestBuilder.get()
397                             .setHttpHost(target)
398                             .setPath("/circular-oldlocation/")
399                             .setRequestConfig(config)
400                             .build(), null);
401             future.get();
402         } catch (final ExecutionException e) {
403             Assert.assertTrue(e.getCause() instanceof CircularRedirectException);
404             throw e;
405         }
406     }
407 
408     @Test
409     public void testPostRedirect() throws Exception {
410         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
411 
412             @Override
413             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
414                 return new RedirectingAsyncDecorator(
415                         exchangeHandler,
416                         new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_TEMPORARY_REDIRECT));
417             }
418 
419         });
420 
421         final HttpClientContext context = HttpClientContext.create();
422         final Future<SimpleHttpResponse> future = httpclient.execute(
423                 SimpleRequestBuilder.post()
424                         .setHttpHost(target)
425                         .setPath("/oldlocation/stuff")
426                         .setBody("stuff", ContentType.TEXT_PLAIN)
427                         .build(), context, null);
428         final HttpResponse response = future.get();
429         Assert.assertNotNull(response);
430 
431         final HttpRequest request = context.getRequest();
432 
433         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
434         Assert.assertEquals("/echo/stuff", request.getRequestUri());
435         Assert.assertEquals("POST", request.getMethod());
436     }
437 
438     @Test
439     public void testPostRedirectSeeOther() throws Exception {
440         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
441 
442             @Override
443             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
444                 return new RedirectingAsyncDecorator(
445                         exchangeHandler,
446                         new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER));
447             }
448 
449         });
450 
451         final HttpClientContext context = HttpClientContext.create();
452         final Future<SimpleHttpResponse> future = httpclient.execute(
453                 SimpleRequestBuilder.post()
454                         .setHttpHost(target)
455                         .setPath("/oldlocation/stuff")
456                         .setBody("stuff", ContentType.TEXT_PLAIN)
457                         .build(), context, null);
458         final HttpResponse response = future.get();
459         Assert.assertNotNull(response);
460 
461         final HttpRequest request = context.getRequest();
462 
463         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
464         Assert.assertEquals("/echo/stuff", request.getRequestUri());
465         Assert.assertEquals("GET", request.getMethod());
466     }
467 
468     @Test
469     public void testRelativeRedirect() throws Exception {
470         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
471 
472             @Override
473             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
474                 return new RedirectingAsyncDecorator(
475                         exchangeHandler,
476                         new RedirectResolver() {
477 
478                             @Override
479                             public Redirect resolve(final URI requestUri) throws URISyntaxException {
480                                 final String path = requestUri.getPath();
481                                 if (path.startsWith("/oldlocation")) {
482                                     return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100");
483 
484                                 }
485                                 return null;
486                             }
487 
488                         });
489             }
490 
491         });
492 
493         final HttpClientContext context = HttpClientContext.create();
494 
495         final Future<SimpleHttpResponse> future = httpclient.execute(
496                 SimpleRequestBuilder.get()
497                         .setHttpHost(target)
498                         .setPath("/oldlocation/stuff")
499                         .build(), context, null);
500         final HttpResponse response = future.get();
501         Assert.assertNotNull(response);
502 
503         final HttpRequest request = context.getRequest();
504 
505         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
506         Assert.assertEquals("/random/100", request.getRequestUri());
507         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
508     }
509 
510     @Test
511     public void testRelativeRedirect2() throws Exception {
512         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
513 
514             @Override
515             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
516                 return new RedirectingAsyncDecorator(
517                         exchangeHandler,
518                         new RedirectResolver() {
519 
520                             @Override
521                             public Redirect resolve(final URI requestUri) throws URISyntaxException {
522                                 final String path = requestUri.getPath();
523                                 if (path.equals("/random/oldlocation")) {
524                                     return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100");
525 
526                                 }
527                                 return null;
528                             }
529 
530                         });
531             }
532 
533         });
534 
535         final HttpClientContext context = HttpClientContext.create();
536 
537         final Future<SimpleHttpResponse> future = httpclient.execute(
538                 SimpleRequestBuilder.get()
539                         .setHttpHost(target)
540                         .setPath("/random/oldlocation")
541                         .build(), context, null);
542         final HttpResponse response = future.get();
543         Assert.assertNotNull(response);
544 
545         final HttpRequest request = context.getRequest();
546 
547         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
548         Assert.assertEquals("/random/100", request.getRequestUri());
549         Assert.assertEquals(target, new HttpHost(request.getScheme(), request.getAuthority()));
550     }
551 
552     @Test(expected=ExecutionException.class)
553     public void testRejectBogusRedirectLocation() throws Exception {
554         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
555 
556             @Override
557             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
558                 return new RedirectingAsyncDecorator(
559                         exchangeHandler,
560                         new RedirectResolver() {
561 
562                             @Override
563                             public Redirect resolve(final URI requestUri) throws URISyntaxException {
564                                 final String path = requestUri.getPath();
565                                 if (path.equals("/oldlocation/")) {
566                                     return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus");
567 
568                                 }
569                                 return null;
570                             }
571 
572                         });
573             }
574 
575         });
576 
577         try {
578             final Future<SimpleHttpResponse> future = httpclient.execute(
579                     SimpleRequestBuilder.get()
580                             .setHttpHost(target)
581                             .setPath("/oldlocation/")
582                             .build(), null);
583             future.get();
584         } catch (final ExecutionException ex) {
585             Assert.assertTrue(ex.getCause() instanceof HttpException);
586             throw ex;
587         }
588     }
589 
590     @Test(expected=ExecutionException.class)
591     public void testRejectInvalidRedirectLocation() throws Exception {
592         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
593 
594             @Override
595             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
596                 return new RedirectingAsyncDecorator(
597                         exchangeHandler,
598                         new RedirectResolver() {
599 
600                             @Override
601                             public Redirect resolve(final URI requestUri) throws URISyntaxException {
602                                 final String path = requestUri.getPath();
603                                 if (path.equals("/oldlocation/")) {
604                                     return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces");
605 
606                                 }
607                                 return null;
608                             }
609 
610                         });
611             }
612 
613         });
614 
615         try {
616             final Future<SimpleHttpResponse> future = httpclient.execute(
617                     SimpleRequestBuilder.get()
618                             .setHttpHost(target)
619                             .setPath("/oldlocation/")
620                             .build(), null);
621             future.get();
622         } catch (final ExecutionException e) {
623             Assert.assertTrue(e.getCause() instanceof ProtocolException);
624             throw e;
625         }
626     }
627 
628     @Test
629     public void testRedirectWithCookie() throws Exception {
630         final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
631 
632             @Override
633             public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
634                 return new RedirectingAsyncDecorator(
635                         exchangeHandler,
636                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY));
637             }
638 
639         });
640 
641         final CookieStore cookieStore = new BasicCookieStore();
642         final HttpClientContext context = HttpClientContext.create();
643         context.setCookieStore(cookieStore);
644 
645         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
646         cookie.setDomain(target.getHostName());
647         cookie.setPath("/");
648 
649         cookieStore.addCookie(cookie);
650 
651         final Future<SimpleHttpResponse> future = httpclient.execute(
652                 SimpleRequestBuilder.get()
653                         .setHttpHost(target)
654                         .setPath("/oldlocation/100")
655                         .build(), context, null);
656         final HttpResponse response = future.get();
657         Assert.assertNotNull(response);
658 
659         final HttpRequest request = context.getRequest();
660 
661         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
662         Assert.assertEquals("/random/100", request.getRequestUri());
663 
664         final Header[] headers = request.getHeaders("Cookie");
665         Assert.assertEquals("There can only be one (cookie)", 1, headers.length);
666     }
667 
668     @Test
669     public void testCrossSiteRedirect() throws Exception {
670         final H2TestServer secondServer = new H2TestServer(IOReactorConfig.DEFAULT,
671                 scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, null, null);
672         try {
673             secondServer.register("/random/*", new Supplier<AsyncServerExchangeHandler>() {
674 
675                 @Override
676                 public AsyncServerExchangeHandler get() {
677                     if (isReactive()) {
678                         return new ReactiveServerExchangeHandler(new ReactiveRandomProcessor());
679                     } else {
680                         return new AsyncRandomHandler();
681                     }
682                 }
683 
684             });
685             final InetSocketAddress address2;
686             if (version.greaterEquals(HttpVersion.HTTP_2)) {
687                 address2 = secondServer.start(H2Config.DEFAULT);
688             } else {
689                 address2 = secondServer.start(Http1Config.DEFAULT);
690             }
691             final HttpHost redirectTarget = new HttpHost(scheme.name(), "localhost", address2.getPort());
692 
693             final HttpHost target = start(new Decorator<AsyncServerExchangeHandler>() {
694 
695                 @Override
696                 public AsyncServerExchangeHandler decorate(final AsyncServerExchangeHandler exchangeHandler) {
697                     return new RedirectingAsyncDecorator(
698                             exchangeHandler,
699                             new RedirectResolver() {
700 
701                                 @Override
702                                 public Redirect resolve(final URI requestUri) throws URISyntaxException {
703                                     final String path = requestUri.getPath();
704                                     if (path.equals("/oldlocation")) {
705                                         final URI location = new URIBuilder(requestUri)
706                                                 .setHttpHost(redirectTarget)
707                                                 .setPath("/random/100")
708                                                 .build();
709                                         return new Redirect(HttpStatus.SC_MOVED_PERMANENTLY, location.toString());
710                                     }
711                                     return null;
712                                 }
713 
714                             });
715                 }
716 
717             });
718 
719             final HttpClientContext context = HttpClientContext.create();
720             final Future<SimpleHttpResponse> future = httpclient.execute(
721                     SimpleRequestBuilder.get()
722                             .setHttpHost(target)
723                             .setPath("/oldlocation")
724                             .build(), context, null);
725             final HttpResponse response = future.get();
726             Assert.assertNotNull(response);
727 
728             final HttpRequest request = context.getRequest();
729 
730             Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
731             Assert.assertEquals("/random/100", request.getRequestUri());
732             Assert.assertEquals(redirectTarget, new HttpHost(request.getScheme(), request.getAuthority()));
733         } finally {
734             server.shutdown(TimeValue.ofSeconds(5));
735         }
736     }
737 
738 }