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.sync;
28  
29  import static org.hamcrest.MatcherAssert.assertThat;
30  
31  import java.io.IOException;
32  import java.net.URI;
33  import java.util.Collections;
34  import java.util.Queue;
35  import java.util.concurrent.ConcurrentLinkedQueue;
36  import java.util.function.Consumer;
37  
38  import org.apache.hc.client5.http.CircularRedirectException;
39  import org.apache.hc.client5.http.ClientProtocolException;
40  import org.apache.hc.client5.http.RedirectException;
41  import org.apache.hc.client5.http.classic.methods.HttpGet;
42  import org.apache.hc.client5.http.classic.methods.HttpPost;
43  import org.apache.hc.client5.http.config.RequestConfig;
44  import org.apache.hc.client5.http.cookie.BasicCookieStore;
45  import org.apache.hc.client5.http.cookie.CookieStore;
46  import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
47  import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
48  import org.apache.hc.client5.http.impl.cookie.BasicClientCookie;
49  import org.apache.hc.client5.http.protocol.HttpClientContext;
50  import org.apache.hc.client5.http.protocol.RedirectLocations;
51  import org.apache.hc.client5.testing.OldPathRedirectResolver;
52  import org.apache.hc.client5.testing.classic.EchoHandler;
53  import org.apache.hc.client5.testing.classic.RandomHandler;
54  import org.apache.hc.client5.testing.classic.RedirectingDecorator;
55  import org.apache.hc.client5.testing.redirect.Redirect;
56  import org.apache.hc.client5.testing.sync.extension.TestClientResources;
57  import org.apache.hc.core5.function.Decorator;
58  import org.apache.hc.core5.http.ClassicHttpRequest;
59  import org.apache.hc.core5.http.Header;
60  import org.apache.hc.core5.http.HttpException;
61  import org.apache.hc.core5.http.HttpHeaders;
62  import org.apache.hc.core5.http.HttpHost;
63  import org.apache.hc.core5.http.HttpRequest;
64  import org.apache.hc.core5.http.HttpStatus;
65  import org.apache.hc.core5.http.ProtocolException;
66  import org.apache.hc.core5.http.URIScheme;
67  import org.apache.hc.core5.http.io.HttpServerRequestHandler;
68  import org.apache.hc.core5.http.io.entity.EntityUtils;
69  import org.apache.hc.core5.http.io.entity.StringEntity;
70  import org.apache.hc.core5.http.message.BasicHeader;
71  import org.apache.hc.core5.http.protocol.HttpContext;
72  import org.apache.hc.core5.http.protocol.HttpProcessor;
73  import org.apache.hc.core5.net.URIBuilder;
74  import org.apache.hc.core5.testing.classic.ClassicTestServer;
75  import org.apache.hc.core5.util.Timeout;
76  import org.hamcrest.CoreMatchers;
77  import org.junit.jupiter.api.Assertions;
78  import org.junit.jupiter.api.Test;
79  import org.junit.jupiter.api.extension.RegisterExtension;
80  
81  /**
82   * Redirection test cases.
83   */
84  public abstract class TestRedirects {
85  
86      public static final Timeout TIMEOUT = Timeout.ofMinutes(1);
87  
88      @RegisterExtension
89      private TestClientResources testResources;
90  
91      protected TestRedirects(final URIScheme scheme) {
92          this.testResources = new TestClientResources(scheme, TIMEOUT);
93      }
94  
95      public URIScheme scheme() {
96          return testResources.scheme();
97      }
98  
99      public ClassicTestServer startServer(final HttpProcessor httpProcessor,
100                                          final Decorator<HttpServerRequestHandler> handlerDecorator) throws IOException {
101         return testResources.startServer(null, httpProcessor, handlerDecorator);
102     }
103 
104     public CloseableHttpClient startClient(final Consumer<HttpClientBuilder> clientCustomizer) throws Exception {
105         return testResources.startClient(clientCustomizer);
106     }
107 
108     public CloseableHttpClient startClient() throws Exception {
109         return testResources.startClient(builder -> {});
110     }
111 
112     public HttpHost targetHost() {
113         return testResources.targetHost();
114     }
115 
116     @Test
117     public void testBasicRedirect300() throws Exception {
118         final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
119                 requestHandler,
120                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES)));
121         server.registerHandler("/random/*", new RandomHandler());
122         final HttpHost target = targetHost();
123 
124         final CloseableHttpClient client = startClient();
125         final HttpClientContext context = HttpClientContext.create();
126 
127         final HttpGet httpget = new HttpGet("/oldlocation/100");
128         client.execute(target, httpget, context, response -> {
129             Assertions.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode());
130             EntityUtils.consume(response.getEntity());
131             return null;
132         });
133         final HttpRequest reqWrapper = context.getRequest();
134         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/oldlocation/100").build(),
135                 reqWrapper.getUri());
136 
137         final RedirectLocations redirects = context.getRedirectLocations();
138         Assertions.assertNotNull(redirects);
139         Assertions.assertEquals(0, redirects.size());
140     }
141 
142     @Test
143     public void testBasicRedirect300NoKeepAlive() throws Exception {
144          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
145                 requestHandler,
146                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES,
147                         Redirect.ConnControl.CLOSE)));
148         server.registerHandler("/random/*", new RandomHandler());
149         final HttpHost target = targetHost();
150 
151         final CloseableHttpClient client = startClient();
152         final HttpClientContext context = HttpClientContext.create();
153 
154         final HttpGet httpget = new HttpGet("/oldlocation/100");
155         client.execute(target, httpget, context, response -> {
156             Assertions.assertEquals(HttpStatus.SC_MULTIPLE_CHOICES, response.getCode());
157             EntityUtils.consume(response.getEntity());
158             return null;
159         });
160         final HttpRequest reqWrapper = context.getRequest();
161 
162         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/oldlocation/100").build(),
163                 reqWrapper.getUri());
164 
165         final RedirectLocations redirects = context.getRedirectLocations();
166         Assertions.assertNotNull(redirects);
167         Assertions.assertEquals(0, redirects.size());
168     }
169 
170     @Test
171     public void testBasicRedirect301() throws Exception {
172          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
173                 requestHandler,
174                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY)));
175         server.registerHandler("/random/*", new RandomHandler());
176         final HttpHost target = targetHost();
177 
178         final CloseableHttpClient client = startClient();
179         final HttpClientContext context = HttpClientContext.create();
180 
181         final HttpGet httpget = new HttpGet("/oldlocation/100");
182 
183         client.execute(target, httpget, context, response -> {
184             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
185             EntityUtils.consume(response.getEntity());
186             return null;
187         });
188         final HttpRequest reqWrapper = context.getRequest();
189 
190         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/100").build(),
191                 reqWrapper.getUri());
192 
193         final RedirectLocations redirects = context.getRedirectLocations();
194         Assertions.assertNotNull(redirects);
195         Assertions.assertEquals(1, redirects.size());
196 
197         final URI redirect = new URIBuilder().setHttpHost(target).setPath("/random/100").build();
198         Assertions.assertTrue(redirects.contains(redirect));
199     }
200 
201     @Test
202     public void testBasicRedirect302() throws Exception {
203          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
204                 requestHandler,
205                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)));
206         server.registerHandler("/random/*", new RandomHandler());
207         final HttpHost target = targetHost();
208 
209         final CloseableHttpClient client = startClient();
210         final HttpClientContext context = HttpClientContext.create();
211 
212         final HttpGet httpget = new HttpGet("/oldlocation/50");
213 
214         client.execute(target, httpget, context, response -> {
215             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
216             EntityUtils.consume(response.getEntity());
217             return null;
218         });
219         final HttpRequest reqWrapper = context.getRequest();
220 
221         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/50").build(),
222                 reqWrapper.getUri());
223 
224     }
225 
226     @Test
227     public void testBasicRedirect302NoLocation() throws Exception {
228          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
229                 requestHandler,
230                 requestUri -> {
231                     final String path = requestUri.getPath();
232                     if (path.startsWith("/oldlocation")) {
233                         return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null);
234                     }
235                     return null;
236                 }));
237         server.registerHandler("/random/*", new RandomHandler());
238         final HttpHost target = targetHost();
239 
240         final CloseableHttpClient client = startClient();
241         final HttpClientContext context = HttpClientContext.create();
242 
243         final HttpGet httpget = new HttpGet("/oldlocation/100");
244 
245         client.execute(target, httpget, context, response -> {
246             final HttpRequest reqWrapper = context.getRequest();
247 
248             Assertions.assertEquals(HttpStatus.SC_MOVED_TEMPORARILY, response.getCode());
249             Assertions.assertEquals("/oldlocation/100", reqWrapper.getRequestUri());
250 
251             EntityUtils.consume(response.getEntity());
252             return null;
253         });
254     }
255 
256     @Test
257     public void testBasicRedirect303() throws Exception {
258          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
259                 requestHandler,
260                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER)));
261         server.registerHandler("/random/*", new RandomHandler());
262         final HttpHost target = targetHost();
263 
264         final CloseableHttpClient client = startClient();
265         final HttpClientContext context = HttpClientContext.create();
266 
267         final HttpGet httpget = new HttpGet("/oldlocation/123");
268 
269         client.execute(target, httpget, context, response -> {
270             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
271             EntityUtils.consume(response.getEntity());
272             return null;
273         });
274         final HttpRequest reqWrapper = context.getRequest();
275 
276         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/123").build(),
277                 reqWrapper.getUri());
278     }
279 
280     @Test
281     public void testBasicRedirect304() throws Exception {
282         final ClassicTestServer server = startServer(null ,null);
283         server.registerHandler("/oldlocation/*", (request, response, context) -> {
284             response.setCode(HttpStatus.SC_NOT_MODIFIED);
285             response.addHeader(HttpHeaders.LOCATION, "/random/100");
286         });
287 
288         server.registerHandler("/random/*", new RandomHandler());
289         final HttpHost target = targetHost();
290 
291         final CloseableHttpClient client = startClient();
292         final HttpClientContext context = HttpClientContext.create();
293 
294         final HttpGet httpget = new HttpGet("/oldlocation/stuff");
295 
296         client.execute(target, httpget, context, response -> {
297             Assertions.assertEquals(HttpStatus.SC_NOT_MODIFIED, response.getCode());
298             EntityUtils.consume(response.getEntity());
299             return null;
300         });
301         final HttpRequest reqWrapper = context.getRequest();
302 
303         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/oldlocation/stuff").build(),
304                 reqWrapper.getUri());
305 
306         final RedirectLocations redirects = context.getRedirectLocations();
307         Assertions.assertNotNull(redirects);
308         Assertions.assertEquals(0, redirects.size());
309     }
310 
311     @Test
312     public void testBasicRedirect305() throws Exception {
313         final ClassicTestServer server =  startServer(null ,null);
314         server.registerHandler("/oldlocation/*", (request, response, context) -> {
315             response.setCode(HttpStatus.SC_USE_PROXY);
316             response.addHeader(HttpHeaders.LOCATION, "/random/100");
317         });
318 
319         server.registerHandler("/random/*", new RandomHandler());
320         final HttpHost target = targetHost();
321 
322         final CloseableHttpClient client = startClient();
323         final HttpClientContext context = HttpClientContext.create();
324 
325         final HttpGet httpget = new HttpGet("/oldlocation/stuff");
326 
327         client.execute(target, httpget, context, response -> {
328             Assertions.assertEquals(HttpStatus.SC_USE_PROXY, response.getCode());
329             EntityUtils.consume(response.getEntity());
330             return null;
331         });
332         final HttpRequest reqWrapper = context.getRequest();
333 
334         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/oldlocation/stuff").build(),
335                 reqWrapper.getUri());
336 
337         final RedirectLocations redirects = context.getRedirectLocations();
338         Assertions.assertNotNull(redirects);
339         Assertions.assertEquals(0, redirects.size());
340     }
341 
342     @Test
343     public void testBasicRedirect307() throws Exception {
344          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
345                 requestHandler,
346                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT)));
347         server.registerHandler("/random/*", new RandomHandler());
348         final HttpHost target = targetHost();
349 
350         final CloseableHttpClient client = startClient();
351         final HttpClientContext context = HttpClientContext.create();
352 
353         final HttpGet httpget = new HttpGet("/oldlocation/123");
354 
355         client.execute(target, httpget, context, response -> {
356             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
357             EntityUtils.consume(response.getEntity());
358             return null;
359         });
360         final HttpRequest reqWrapper = context.getRequest();
361 
362         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/123").build(),
363                 reqWrapper.getUri());
364     }
365 
366     @Test
367     public void testMaxRedirectCheck() throws Exception {
368          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
369                 requestHandler,
370                 new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/",
371                         HttpStatus.SC_MOVED_TEMPORARILY)));
372         server.registerHandler("/random/*", new RandomHandler());
373         final HttpHost target = targetHost();
374 
375         final CloseableHttpClient client = startClient();
376         final RequestConfig config = RequestConfig.custom()
377                 .setCircularRedirectsAllowed(true)
378                 .setMaxRedirects(5)
379                 .build();
380 
381         final HttpGet httpget = new HttpGet("/circular-oldlocation/123");
382         httpget.setConfig(config);
383         final ClientProtocolException exception = Assertions.assertThrows(ClientProtocolException.class, () ->
384                 client.execute(target, httpget, response -> null));
385         Assertions.assertTrue(exception.getCause() instanceof RedirectException);
386     }
387 
388     @Test
389     public void testCircularRedirect() throws Exception {
390          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
391                 requestHandler,
392                 new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/",
393                         HttpStatus.SC_MOVED_TEMPORARILY)));
394         server.registerHandler("/random/*", new RandomHandler());
395         final HttpHost target = targetHost();
396 
397         final CloseableHttpClient client = startClient();
398         final RequestConfig config = RequestConfig.custom()
399                 .setCircularRedirectsAllowed(false)
400                 .build();
401 
402         final HttpGet httpget = new HttpGet("/circular-oldlocation/123");
403         httpget.setConfig(config);
404         final ClientProtocolException exception = Assertions.assertThrows(ClientProtocolException.class, () ->
405                 client.execute(target, httpget, response -> null));
406         Assertions.assertTrue(exception.getCause() instanceof CircularRedirectException);
407     }
408 
409     @Test
410     public void testPostRedirectSeeOther() throws Exception {
411          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
412                 requestHandler,
413                 new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER)));
414         server.registerHandler("/echo/*", new EchoHandler());
415         final HttpHost target = targetHost();
416 
417         final CloseableHttpClient client = startClient();
418         final HttpClientContext context = HttpClientContext.create();
419 
420         final HttpPost httppost = new HttpPost("/oldlocation/stuff");
421         httppost.setEntity(new StringEntity("stuff"));
422 
423         client.execute(target, httppost, context, response -> {
424             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
425             EntityUtils.consume(response.getEntity());
426             return null;
427         });
428         final HttpRequest reqWrapper = context.getRequest();
429 
430         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/echo/stuff").build(),
431                 reqWrapper.getUri());
432         Assertions.assertEquals("GET", reqWrapper.getMethod());
433     }
434 
435     @Test
436     public void testRelativeRedirect() throws Exception {
437          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
438                 requestHandler,
439                 requestUri -> {
440                     final String path = requestUri.getPath();
441                     if (path.startsWith("/oldlocation")) {
442                         return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100");
443 
444                     }
445                     return null;
446                 }));        server.registerHandler("/random/*", new RandomHandler());
447         final HttpHost target = targetHost();
448 
449         final CloseableHttpClient client = startClient();
450         final HttpClientContext context = HttpClientContext.create();
451 
452         final HttpGet httpget = new HttpGet("/oldlocation/stuff");
453 
454         client.execute(target, httpget, context, response -> {
455             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
456             EntityUtils.consume(response.getEntity());
457             return null;
458         });
459         final HttpRequest reqWrapper = context.getRequest();
460 
461         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/100").build(),
462                 reqWrapper.getUri());
463     }
464 
465     @Test
466     public void testRelativeRedirect2() throws Exception {
467          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
468                 requestHandler,
469                 requestUri -> {
470                     final String path = requestUri.getPath();
471                     if (path.equals("/random/oldlocation")) {
472                         return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100");
473 
474                     }
475                     return null;
476                 }));
477         server.registerHandler("/random/*", new RandomHandler());
478         final HttpHost target = targetHost();
479 
480         final CloseableHttpClient client = startClient();
481         final HttpClientContext context = HttpClientContext.create();
482 
483         final HttpGet httpget = new HttpGet("/random/oldlocation");
484 
485         client.execute(target, httpget, context, response -> {
486             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
487             EntityUtils.consume(response.getEntity());
488             return null;
489         });
490         final HttpRequest reqWrapper = context.getRequest();
491 
492         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/100").build(),
493                 reqWrapper.getUri());
494     }
495 
496     @Test
497     public void testRejectBogusRedirectLocation() throws Exception {
498          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
499                 requestHandler,
500                 requestUri -> {
501                     final String path = requestUri.getPath();
502                     if (path.equals("/oldlocation")) {
503                         return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus");
504 
505                     }
506                     return null;
507                 }));
508         server.registerHandler("/random/*", new RandomHandler());
509         final HttpHost target = targetHost();
510 
511         final CloseableHttpClient client = startClient();
512         final HttpGet httpget = new HttpGet("/oldlocation");
513 
514         final ClientProtocolException exception = Assertions.assertThrows(ClientProtocolException.class, () ->
515                 client.execute(target, httpget, response -> null));
516         assertThat(exception.getCause(), CoreMatchers.instanceOf(HttpException.class));
517     }
518 
519     @Test
520     public void testRejectInvalidRedirectLocation() throws Exception {
521          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
522                 requestHandler,
523                 requestUri -> {
524                     final String path = requestUri.getPath();
525                     if (path.equals("/oldlocation")) {
526                         return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces");
527 
528                     }
529                     return null;
530                 }));
531         server.registerHandler("/random/*", new RandomHandler());
532         final HttpHost target = targetHost();
533 
534         final CloseableHttpClient client = startClient();
535         final HttpGet httpget = new HttpGet("/oldlocation");
536 
537         final ClientProtocolException exception = Assertions.assertThrows(ClientProtocolException.class, () ->
538                 client.execute(target, httpget, response -> null));
539         assertThat(exception.getCause(), CoreMatchers.instanceOf(ProtocolException.class));
540     }
541 
542     @Test
543     public void testRedirectWithCookie() throws Exception {
544          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
545                 requestHandler,
546                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)));
547         server.registerHandler("/random/*", new RandomHandler());
548         final HttpHost target = targetHost();
549 
550         final CloseableHttpClient client = startClient();
551         final CookieStore cookieStore = new BasicCookieStore();
552 
553         final BasicClientCookie cookie = new BasicClientCookie("name", "value");
554         cookie.setDomain(target.getHostName());
555         cookie.setPath("/");
556 
557         cookieStore.addCookie(cookie);
558 
559         final HttpClientContext context = HttpClientContext.create();
560 
561         context.setCookieStore(cookieStore);
562         final HttpGet httpget = new HttpGet("/oldlocation/100");
563 
564         client.execute(target, httpget, context, response -> {
565             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
566             EntityUtils.consume(response.getEntity());
567             return null;
568         });
569         final HttpRequest reqWrapper = context.getRequest();
570 
571         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/100").build(),
572                 reqWrapper.getUri());
573 
574         final Header[] headers = reqWrapper.getHeaders("Cookie");
575         Assertions.assertEquals(1, headers.length, "There can only be one (cookie)");
576     }
577 
578     @Test
579     public void testDefaultHeadersRedirect() throws Exception {
580         final CloseableHttpClient client = startClient(builder -> builder
581                 .setDefaultHeaders(Collections.singletonList(new BasicHeader(HttpHeaders.USER_AGENT, "my-test-client")))
582         );
583 
584          final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator(
585                 requestHandler,
586                 new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)));
587         server.registerHandler("/random/*", new RandomHandler());
588         final HttpHost target = targetHost();
589 
590         final HttpClientContext context = HttpClientContext.create();
591 
592         final HttpGet httpget = new HttpGet("/oldlocation/100");
593 
594         client.execute(target, httpget, context, response -> {
595             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
596             EntityUtils.consume(response.getEntity());
597             return null;
598         });
599         final HttpRequest reqWrapper = context.getRequest();
600 
601         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/100").build(),
602                 reqWrapper.getUri());
603 
604         final Header header = reqWrapper.getFirstHeader(HttpHeaders.USER_AGENT);
605         Assertions.assertEquals("my-test-client", header.getValue());
606     }
607 
608     @Test
609     public void testCompressionHeaderRedirect() throws Exception {
610         final Queue<String> values = new ConcurrentLinkedQueue<>();
611          final ClassicTestServer server = startServer(null, new Decorator<HttpServerRequestHandler>() {
612 
613             @Override
614             public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) {
615                 return new RedirectingDecorator(
616                         requestHandler,
617                         new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)) {
618 
619                     @Override
620                     public void handle(final ClassicHttpRequest request,
621                                        final ResponseTrigger responseTrigger,
622                                        final HttpContext context) throws HttpException, IOException {
623                         final Header header = request.getHeader(HttpHeaders.ACCEPT_ENCODING);
624                         if (header != null) {
625                             values.add(header.getValue());
626                         }
627                         super.handle(request, responseTrigger, context);
628                     }
629 
630                 };
631             }
632 
633         });
634         server.registerHandler("/random/*", new RandomHandler());
635         final HttpHost target = targetHost();
636 
637         final CloseableHttpClient client = startClient();
638         final HttpClientContext context = HttpClientContext.create();
639 
640         final HttpGet httpget = new HttpGet("/oldlocation/100");
641 
642         client.execute(target, httpget, context, response -> {
643             Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
644             EntityUtils.consume(response.getEntity());
645             return null;
646         });
647         final HttpRequest reqWrapper = context.getRequest();
648 
649         Assertions.assertEquals(new URIBuilder().setHttpHost(target).setPath("/random/100").build(),
650                 reqWrapper.getUri());
651 
652         assertThat(values.poll(), CoreMatchers.equalTo("gzip, x-gzip, deflate"));
653         assertThat(values.poll(), CoreMatchers.equalTo("gzip, x-gzip, deflate"));
654         assertThat(values.poll(), CoreMatchers.nullValue());
655     }
656 
657 }