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  
28  package org.apache.hc.client5.http.impl.routing;
29  
30  import java.net.InetAddress;
31  
32  import org.apache.hc.client5.http.HttpRoute;
33  import org.apache.hc.client5.http.RouteInfo.LayerType;
34  import org.apache.hc.client5.http.RouteInfo.TunnelType;
35  import org.apache.hc.client5.http.routing.HttpRouteDirector;
36  import org.apache.hc.core5.http.HttpHost;
37  import org.junit.Assert;
38  import org.junit.Test;
39  
40  /**
41   * Tests for {@link BasicRouteDirector}.
42   */
43  public class TestRouteDirector {
44  
45      // a selection of constants for generating routes
46      public final static
47          HttpHost TARGET1 = new HttpHost("target1.test.invalid", 80);
48      public final static
49          HttpHost TARGET2 = new HttpHost("target2.test.invalid", 8080);
50      // It is not necessary to have extra targets for https.
51      // The 'layered' and 'secure' flags are specified explicitly
52      // for routes, they will not be determined from the scheme.
53  
54      public final static
55          HttpHost PROXY1 = new HttpHost("proxy1.test.invalid", 80);
56      public final static
57          HttpHost PROXY2 = new HttpHost("proxy2.test.invalid", 1080);
58      public final static
59          HttpHost PROXY3 = new HttpHost("proxy3.test.invalid", 88);
60  
61      public final static InetAddress LOCAL41;
62      public final static InetAddress LOCAL42;
63      public final static InetAddress LOCAL61;
64      public final static InetAddress LOCAL62;
65  
66      // need static initializer to deal with exceptions
67      static {
68          try {
69              LOCAL41 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
70              LOCAL42 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 2 });
71  
72              LOCAL61 = InetAddress.getByAddress(new byte[]{
73                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
74              });
75              LOCAL62 = InetAddress.getByAddress(new byte[]{
76                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
77              });
78  
79          } catch (final Exception x) {
80              throw new ExceptionInInitializerError(x);
81          }
82      }
83  
84      @Test(expected=NullPointerException.class)
85      public void testIllegal() {
86          final HttpRouteDirector rowdy = new BasicRouteDirector();
87          final HttpRoute route = new HttpRoute(TARGET1);
88          rowdy.nextStep(null, route);
89      }
90  
91      @Test
92      public void testDirect() {
93  
94          final HttpRouteDirector rowdy = new BasicRouteDirector();
95          final HttpRoute route1   = new HttpRoute(TARGET1);
96          final HttpRoute route2   = new HttpRoute(TARGET2);
97          final HttpRoute route1p1 = new HttpRoute(TARGET1, null, PROXY1, false);
98  
99          int step = rowdy.nextStep(route1, null);
100         Assert.assertEquals("wrong step to route1",
101                      HttpRouteDirector.CONNECT_TARGET, step);
102 
103         step = rowdy.nextStep(route2, null);
104         Assert.assertEquals("wrong step to route2",
105                      HttpRouteDirector.CONNECT_TARGET, step);
106 
107         step = rowdy.nextStep(route1, route1);
108         Assert.assertEquals("complete route1 not detected",
109                      HttpRouteDirector.COMPLETE, step);
110 
111         step = rowdy.nextStep(route2, route2);
112         Assert.assertEquals("complete route2 not detected",
113                      HttpRouteDirector.COMPLETE, step);
114 
115         step = rowdy.nextStep(route1, route2);
116         Assert.assertEquals("unreachable target not detected",
117                      HttpRouteDirector.UNREACHABLE, step);
118 
119         step = rowdy.nextStep(route1, route1p1);
120         Assert.assertEquals("invalid proxy not detected",
121                      HttpRouteDirector.UNREACHABLE, step);
122     }
123 
124     @Test
125     public void testProxy() {
126 
127         final HttpRouteDirector rowdy = new BasicRouteDirector();
128         final HttpRoute route1p1 = new HttpRoute(TARGET1, null, PROXY1, false);
129         final HttpRoute route1p2 = new HttpRoute(TARGET1, null, PROXY2, false);
130         final HttpRoute route2p1 = new HttpRoute(TARGET2, null, PROXY1, false);
131         final HttpRoute route0   = new HttpRoute(PROXY1);
132         final HttpRoute route1   = new HttpRoute(TARGET1);
133 
134         int step = rowdy.nextStep(route1p1, null);
135         Assert.assertEquals("wrong step to route1p1",
136                      HttpRouteDirector.CONNECT_PROXY, step);
137 
138         step = rowdy.nextStep(route1p2, null);
139         Assert.assertEquals("wrong step to route1p2",
140                      HttpRouteDirector.CONNECT_PROXY, step);
141 
142         step = rowdy.nextStep(route1p1, route1p1);
143         Assert.assertEquals("complete route1p1 not detected",
144                      HttpRouteDirector.COMPLETE, step);
145 
146         step = rowdy.nextStep(route1p2, route1p2);
147         Assert.assertEquals("complete route1p2 not detected",
148                      HttpRouteDirector.COMPLETE, step);
149 
150         step = rowdy.nextStep(route2p1, route2p1);
151         Assert.assertEquals("complete route2p1 not detected",
152                      HttpRouteDirector.COMPLETE, step);
153 
154         step = rowdy.nextStep(route1p1, route1p2);
155         Assert.assertEquals("unreachable route1p1 via route1p2 not detected",
156                      HttpRouteDirector.UNREACHABLE, step);
157 
158         step = rowdy.nextStep(route1p1, route2p1);
159         Assert.assertEquals("unreachable route1p1 via route2p1 not detected",
160                      HttpRouteDirector.UNREACHABLE, step);
161 
162         step = rowdy.nextStep(route1p1, route0);
163         Assert.assertEquals("unreachable route1p1 via route0 not detected",
164                      HttpRouteDirector.UNREACHABLE, step);
165 
166         step = rowdy.nextStep(route1p1, route1);
167         Assert.assertEquals("unreachable route1p1 via route1 not detected",
168                      HttpRouteDirector.UNREACHABLE, step);
169     }
170 
171     @Test
172     public void testProxyChain() {
173         final HttpHost[] chainA = { PROXY1 };
174         final HttpHost[] chainB = { PROXY1, PROXY2 };
175         final HttpHost[] chainC = { PROXY2, PROXY1 };
176 
177         final HttpRouteDirector rowdy = new BasicRouteDirector();
178         final HttpRoute route1cA  = new HttpRoute(TARGET1, null, chainA, false,
179                                             TunnelType.PLAIN, LayerType.PLAIN);
180         final HttpRoute route1cB  = new HttpRoute(TARGET1, null, chainB, false,
181                                             TunnelType.PLAIN, LayerType.PLAIN);
182         final HttpRoute route1cC  = new HttpRoute(TARGET1, null, chainC, false,
183                                             TunnelType.PLAIN, LayerType.PLAIN);
184         final HttpRoute route1cD  = new HttpRoute(TARGET1, null, chainC, false,
185                                             TunnelType.PLAIN, LayerType.PLAIN);
186 
187         int step = rowdy.nextStep(route1cA, null);
188         Assert.assertEquals("wrong step to route1cA",
189                      HttpRouteDirector.CONNECT_PROXY, step);
190 
191         step = rowdy.nextStep(route1cB, null);
192         Assert.assertEquals("wrong step to route1cB",
193                      HttpRouteDirector.CONNECT_PROXY, step);
194 
195         step = rowdy.nextStep(route1cC, null);
196         Assert.assertEquals("wrong step to route1cC",
197                      HttpRouteDirector.CONNECT_PROXY, step);
198 
199         step = rowdy.nextStep(route1cD, null);
200         Assert.assertEquals("wrong step to route1cD",
201                      HttpRouteDirector.CONNECT_PROXY, step);
202 
203 
204         step = rowdy.nextStep(route1cB, route1cA);
205         Assert.assertEquals("wrong step to route 1cB from 1cA",
206                      HttpRouteDirector.TUNNEL_PROXY, step);
207 
208         step = rowdy.nextStep(route1cB, route1cB);
209         Assert.assertEquals("complete route 1cB not detected",
210                      HttpRouteDirector.COMPLETE, step);
211 
212         step = rowdy.nextStep(route1cB, route1cC);
213         Assert.assertEquals("unreachable route 1cB from 1cC not detected",
214                      HttpRouteDirector.UNREACHABLE, step);
215 
216         step = rowdy.nextStep(route1cB, route1cD);
217         Assert.assertEquals("unreachable route 1cB from 1cD not detected",
218                      HttpRouteDirector.UNREACHABLE, step);
219 
220 
221         step = rowdy.nextStep(route1cA, route1cB);
222         Assert.assertEquals("unreachable route 1cA from 1cB not detected",
223                      HttpRouteDirector.UNREACHABLE, step);
224     }
225 
226     @Test
227     public void testLocalDirect() {
228 
229         final HttpRouteDirector rowdy = new BasicRouteDirector();
230         final HttpRoute route1l41 = new HttpRoute(TARGET1, LOCAL41, false);
231         final HttpRoute route1l42 = new HttpRoute(TARGET1, LOCAL42, false);
232         final HttpRoute route1l61 = new HttpRoute(TARGET1, LOCAL61, false);
233         final HttpRoute route1l00 = new HttpRoute(TARGET1, null, false);
234 
235         int step = rowdy.nextStep(route1l41, null);
236         Assert.assertEquals("wrong step to route1l41",
237                      HttpRouteDirector.CONNECT_TARGET, step);
238 
239         step = rowdy.nextStep(route1l42, null);
240         Assert.assertEquals("wrong step to route1l42",
241                      HttpRouteDirector.CONNECT_TARGET, step);
242 
243         step = rowdy.nextStep(route1l61, null);
244         Assert.assertEquals("wrong step to route1l61",
245                      HttpRouteDirector.CONNECT_TARGET, step);
246 
247         step = rowdy.nextStep(route1l00, null);
248         Assert.assertEquals("wrong step to route1l00",
249                      HttpRouteDirector.CONNECT_TARGET, step);
250 
251         step = rowdy.nextStep(route1l41, route1l41);
252         Assert.assertEquals("complete route1l41 not detected",
253                      HttpRouteDirector.COMPLETE, step);
254 
255         step = rowdy.nextStep(route1l42, route1l42);
256         Assert.assertEquals("complete route1l42 not detected",
257                      HttpRouteDirector.COMPLETE, step);
258 
259         step = rowdy.nextStep(route1l61, route1l61);
260         Assert.assertEquals("complete route1l61 not detected",
261                      HttpRouteDirector.COMPLETE, step);
262 
263         step = rowdy.nextStep(route1l00, route1l00);
264         Assert.assertEquals("complete route1l00 not detected",
265                      HttpRouteDirector.COMPLETE, step);
266 
267 
268         step = rowdy.nextStep(route1l41, route1l42);
269         Assert.assertEquals("unreachable route1l41 via route1l42 not detected",
270                      HttpRouteDirector.UNREACHABLE, step);
271 
272         step = rowdy.nextStep(route1l41, route1l61);
273         Assert.assertEquals("unreachable route1l41 via route1l61 not detected",
274                      HttpRouteDirector.UNREACHABLE, step);
275 
276         step = rowdy.nextStep(route1l41, route1l00);
277         Assert.assertEquals("unreachable route1l41 via route1l00 not detected",
278                      HttpRouteDirector.UNREACHABLE, step);
279 
280 
281         step = rowdy.nextStep(route1l00, route1l41);
282         Assert.assertEquals("complete route1l00 as route1l41 not detected",
283                      HttpRouteDirector.COMPLETE, step);
284 
285         step = rowdy.nextStep(route1l00, route1l42);
286         Assert.assertEquals("complete route1l00 as route1l42 not detected",
287                      HttpRouteDirector.COMPLETE, step);
288 
289         step = rowdy.nextStep(route1l00, route1l61);
290         Assert.assertEquals("complete route1l00 as route1l61 not detected",
291                      HttpRouteDirector.COMPLETE, step);
292     }
293 
294     @Test
295     public void testDirectSecure() {
296 
297         final HttpRouteDirector rowdy = new BasicRouteDirector();
298         final HttpRoute route1u   = new HttpRoute(TARGET1, null, false);
299         final HttpRoute route1s   = new HttpRoute(TARGET1, null, true);
300         final HttpRoute route1p1u = new HttpRoute(TARGET1, null, PROXY1, false);
301         final HttpRoute route1p1s = new HttpRoute(TARGET1, null, PROXY1, true);
302 
303         int step = rowdy.nextStep(route1u, null);
304         Assert.assertEquals("wrong step to route1u",
305                      HttpRouteDirector.CONNECT_TARGET, step);
306 
307         step = rowdy.nextStep(route1s, null);
308         Assert.assertEquals("wrong step to route1s",
309                      HttpRouteDirector.CONNECT_TARGET, step);
310 
311         // unrequested security is currently not tolerated
312         step = rowdy.nextStep(route1u, route1s);
313         Assert.assertEquals("unreachable route 1u from 1s not detected",
314                      HttpRouteDirector.UNREACHABLE, step);
315 
316         // secure layering of direct connections is currently not supported
317         step = rowdy.nextStep(route1s, route1u);
318         Assert.assertEquals("unreachable route 1s from 1u not detected",
319                      HttpRouteDirector.UNREACHABLE, step);
320 
321 
322 
323         step = rowdy.nextStep(route1s, route1p1u);
324         Assert.assertEquals("unreachable route 1s from 1p1u not detected",
325                      HttpRouteDirector.UNREACHABLE, step);
326 
327         step = rowdy.nextStep(route1s, route1p1s);
328         Assert.assertEquals("unreachable route 1s from 1p1s not detected",
329                      HttpRouteDirector.UNREACHABLE, step);
330     }
331 
332     @Test
333     public void testProxyTLS() {
334 
335         final HttpRouteDirector rowdy = new BasicRouteDirector();
336         final HttpRoute route1    = new HttpRoute
337             (TARGET1, null, PROXY1, false,
338              TunnelType.PLAIN, LayerType.PLAIN);
339         final HttpRoute route1t   = new HttpRoute
340             (TARGET1, null, PROXY1, false,
341              TunnelType.TUNNELLED, LayerType.PLAIN);
342         final HttpRoute route1tl  = new HttpRoute
343             (TARGET1, null, PROXY1, false,
344              TunnelType.TUNNELLED, LayerType.LAYERED);
345         final HttpRoute route1s   = new HttpRoute
346             (TARGET1, null, PROXY1, true,
347              TunnelType.PLAIN, LayerType.PLAIN);
348         final HttpRoute route1ts  = new HttpRoute
349             (TARGET1, null, PROXY1, true,
350              TunnelType.TUNNELLED, LayerType.PLAIN);
351         final HttpRoute route1tls = new HttpRoute
352             (TARGET1, null, PROXY1, true,
353              TunnelType.TUNNELLED, LayerType.LAYERED);
354 
355         // we don't consider a route that is layered but not tunnelled
356 
357         int step = rowdy.nextStep(route1, null);
358         Assert.assertEquals("wrong step to route1",
359                      HttpRouteDirector.CONNECT_PROXY, step);
360 
361         step = rowdy.nextStep(route1t, null);
362         Assert.assertEquals("wrong step to route1t",
363                      HttpRouteDirector.CONNECT_PROXY, step);
364 
365         step = rowdy.nextStep(route1tl, null);
366         Assert.assertEquals("wrong step to route1tl",
367                      HttpRouteDirector.CONNECT_PROXY, step);
368 
369         step = rowdy.nextStep(route1s, null);
370         Assert.assertEquals("wrong step to route1s",
371                      HttpRouteDirector.CONNECT_PROXY, step);
372 
373         step = rowdy.nextStep(route1ts, null);
374         Assert.assertEquals("wrong step to route1ts",
375                      HttpRouteDirector.CONNECT_PROXY, step);
376 
377         step = rowdy.nextStep(route1tls, null);
378         Assert.assertEquals("wrong step to route1tls",
379                      HttpRouteDirector.CONNECT_PROXY, step);
380 
381 
382         step = rowdy.nextStep(route1, route1);
383         Assert.assertEquals("complete route1 not detected",
384                      HttpRouteDirector.COMPLETE, step);
385 
386         step = rowdy.nextStep(route1t, route1t);
387         Assert.assertEquals("complete route1t not detected",
388                      HttpRouteDirector.COMPLETE, step);
389 
390         step = rowdy.nextStep(route1tl, route1tl);
391         Assert.assertEquals("complete route1tl not detected",
392                      HttpRouteDirector.COMPLETE, step);
393 
394         step = rowdy.nextStep(route1s, route1s);
395         Assert.assertEquals("complete route1s not detected",
396                      HttpRouteDirector.COMPLETE, step);
397 
398         step = rowdy.nextStep(route1ts, route1ts);
399         Assert.assertEquals("complete route1ts not detected",
400                      HttpRouteDirector.COMPLETE, step);
401 
402         step = rowdy.nextStep(route1tls, route1tls);
403         Assert.assertEquals("complete route1tls not detected",
404                      HttpRouteDirector.COMPLETE, step);
405 
406 
407 
408         step = rowdy.nextStep(route1, route1t);
409         Assert.assertEquals("unreachable route1 from 1t not detected",
410                      HttpRouteDirector.UNREACHABLE, step);
411 
412         step = rowdy.nextStep(route1, route1tl);
413         Assert.assertEquals("unreachable route1 from 1tl not detected",
414                      HttpRouteDirector.UNREACHABLE, step);
415 
416         // unrequested security is currently not tolerated
417         step = rowdy.nextStep(route1, route1s);
418         Assert.assertEquals("unreachable route1 from 1s not detected",
419                      HttpRouteDirector.UNREACHABLE, step);
420 
421         step = rowdy.nextStep(route1, route1ts);
422         Assert.assertEquals("unreachable route1 from 1ts not detected",
423                      HttpRouteDirector.UNREACHABLE, step);
424 
425         step = rowdy.nextStep(route1, route1tls);
426         Assert.assertEquals("unreachable route1 from 1tls not detected",
427                      HttpRouteDirector.UNREACHABLE, step);
428 
429 
430         // securing requires layering
431         step = rowdy.nextStep(route1s, route1);
432         Assert.assertEquals("unreachable route1s from 1 not detected",
433                      HttpRouteDirector.UNREACHABLE, step);
434 
435         // securing requires layering, and multiple layers are not supported
436         step = rowdy.nextStep(route1tls, route1tl);
437         Assert.assertEquals("unreachable route1tls from 1tl not detected",
438                      HttpRouteDirector.UNREACHABLE, step);
439 
440 
441         // cases where tunnelling to the target is required
442         step = rowdy.nextStep(route1t, route1);
443         Assert.assertEquals("wrong step to route1t from 1",
444                      HttpRouteDirector.TUNNEL_TARGET, step);
445 
446         step = rowdy.nextStep(route1tl, route1);
447         Assert.assertEquals("wrong step to route1tl from 1",
448                      HttpRouteDirector.TUNNEL_TARGET, step);
449 
450         step = rowdy.nextStep(route1tls, route1);
451         Assert.assertEquals("wrong step to route1tls from 1",
452                      HttpRouteDirector.TUNNEL_TARGET, step);
453 
454 
455         // cases where layering on the tunnel is required
456         step = rowdy.nextStep(route1tl, route1t);
457         Assert.assertEquals("wrong step to route1tl from 1t",
458                      HttpRouteDirector.LAYER_PROTOCOL, step);
459 
460         step = rowdy.nextStep(route1tl, route1ts);
461         Assert.assertEquals("wrong step to route1tl from 1ts",
462                      HttpRouteDirector.LAYER_PROTOCOL, step);
463 
464         step = rowdy.nextStep(route1tls, route1t);
465         Assert.assertEquals("wrong step to route1tls from 1t",
466                      HttpRouteDirector.LAYER_PROTOCOL, step);
467 
468         step = rowdy.nextStep(route1tls, route1ts);
469         Assert.assertEquals("wrong step to route1tls from 1ts",
470                      HttpRouteDirector.LAYER_PROTOCOL, step);
471 
472         // There are some odd cases left over, like having a secure tunnel
473         // that becomes unsecure by layering, or a secure connection to a
474         // proxy that becomes unsecure by tunnelling to another proxy.
475     }
476 
477 }