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.http.conn.routing;
29  
30  import java.net.InetAddress;
31  import java.util.HashSet;
32  import java.util.Set;
33  
34  import org.apache.http.HttpHost;
35  import org.apache.http.conn.routing.RouteInfo.LayerType;
36  import org.apache.http.conn.routing.RouteInfo.TunnelType;
37  import org.junit.Assert;
38  import org.junit.Test;
39  
40  /**
41   * Tests for {@link RouteTracker}.
42   */
43  @SuppressWarnings("boxing") // test code
44  public class TestRouteTracker {
45  
46      // a selection of constants for generating routes
47      public final static
48          HttpHost TARGET1 = new HttpHost("target1.test.invalid", 80);
49      public final static
50          HttpHost TARGET2 = new HttpHost("target2.test.invalid", 8080);
51      // It is not necessary to have extra targets for https.
52      // The 'layered' and 'secure' flags are specified explicitly
53      // for routes, they will not be determined from the scheme.
54  
55      public final static
56          HttpHost PROXY1 = new HttpHost("proxy1.test.invalid", 80);
57      public final static
58          HttpHost PROXY2 = new HttpHost("proxy2.test.invalid", 1080);
59      public final static
60          HttpHost PROXY3 = new HttpHost("proxy3.test.invalid", 88);
61  
62      public final static InetAddress LOCAL41;
63      public final static InetAddress LOCAL42;
64      public final static InetAddress LOCAL61;
65      public final static InetAddress LOCAL62;
66  
67      // need static initializer to deal with exceptions
68      static {
69          try {
70              LOCAL41 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
71              LOCAL42 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 2 });
72  
73              LOCAL61 = InetAddress.getByAddress(new byte[]{
74                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
75              });
76              LOCAL62 = InetAddress.getByAddress(new byte[]{
77                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
78              });
79  
80          } catch (final Exception x) {
81              throw new ExceptionInInitializerError(x);
82          }
83      }
84  
85      @SuppressWarnings("unused")
86      @Test
87      public void testCstrTargetLocal() {
88  
89          RouteTracker rt = new RouteTracker(TARGET1, null);
90          Assert.assertEquals("wrong target (target,null)",
91                       TARGET1, rt.getTargetHost());
92          Assert.assertEquals("wrong local address (target,null)",
93                       null, rt.getLocalAddress());
94          Assert.assertEquals("wrong hop count (target,null)",
95                       0, rt.getHopCount());
96          Assert.assertEquals("wrong proxy (target,null)",
97                       null, rt.getProxyHost());
98          Assert.assertEquals("wrong route (target,null)",
99                       null, rt.toRoute());
100         checkCTLS(rt, false, false, false, false);
101 
102 
103         rt = new RouteTracker(TARGET2, LOCAL61);
104         Assert.assertEquals("wrong target (target,local)",
105                      TARGET2, rt.getTargetHost());
106         Assert.assertEquals("wrong local address (target,local)",
107                      LOCAL61, rt.getLocalAddress());
108         Assert.assertEquals("wrong hop count (target,local)",
109                      0, rt.getHopCount());
110         Assert.assertEquals("wrong proxy (target,local)",
111                      null, rt.getProxyHost());
112         Assert.assertEquals("wrong route (target,local)",
113                      null, rt.toRoute());
114         checkCTLS(rt, false, false, false, false);
115 
116 
117         rt = null;
118         try {
119             new RouteTracker(null, LOCAL41);
120             Assert.fail("null target not detected");
121         } catch (final IllegalArgumentException iax) {
122             // expected
123         }
124     }
125 
126     @SuppressWarnings("unused")
127     @Test
128     public void testCstrRoute() {
129 
130         HttpRoute    r  = new HttpRoute(TARGET1);
131         RouteTracker rt = new RouteTracker(r);
132         Assert.assertEquals("wrong target (r1)",
133                      TARGET1, rt.getTargetHost());
134         Assert.assertEquals("wrong local address (r1)",
135                      null, rt.getLocalAddress());
136         Assert.assertEquals("wrong hop count (r1)",
137                      0, rt.getHopCount());
138         Assert.assertEquals("wrong proxy (r1)",
139                      null, rt.getProxyHost());
140         Assert.assertEquals("wrong route (r1)",
141                      null, rt.toRoute());
142         checkCTLS(rt, false, false, false, false);
143 
144         r  = new HttpRoute(TARGET2, LOCAL61, true);
145         rt = new RouteTracker(r);
146         Assert.assertEquals("wrong target (r2)",
147                      TARGET2, rt.getTargetHost());
148         Assert.assertEquals("wrong local address (r2)",
149                      LOCAL61, rt.getLocalAddress());
150         Assert.assertEquals("wrong hop count (r2)",
151                      0, rt.getHopCount());
152         Assert.assertEquals("wrong proxy (r2)",
153                      null, rt.getProxyHost());
154         Assert.assertEquals("wrong route (r2)",
155                      null, rt.toRoute());
156         checkCTLS(rt, false, false, false, false);
157 
158 
159         r  = new HttpRoute(TARGET1, LOCAL42, PROXY3, true);
160         rt = new RouteTracker(r);
161         Assert.assertEquals("wrong target (r3)",
162                      TARGET1, rt.getTargetHost());
163         Assert.assertEquals("wrong local address (r3)",
164                      LOCAL42, rt.getLocalAddress());
165         Assert.assertEquals("wrong hop count (r3)",
166                      0, rt.getHopCount());
167         Assert.assertEquals("wrong proxy (r3)",
168                      null, rt.getProxyHost());
169         Assert.assertEquals("wrong route (r3)",
170                      null, rt.toRoute());
171         checkCTLS(rt, false, false, false, false);
172 
173 
174         rt = null;
175         try {
176             new RouteTracker(null);
177             Assert.fail("null route not detected");
178         } catch (final NullPointerException npx) {
179             // expected
180         }
181     }
182 
183     @Test
184     public void testIllegalArgs() {
185 
186         final RouteTracker rt = new RouteTracker(TARGET2, null);
187 
188         try {
189             rt.connectProxy(null, true);
190             Assert.fail("missing proxy argument not detected (connect/false)");
191         } catch (final IllegalArgumentException iax) {
192             // expected
193         }
194 
195         try {
196             rt.connectProxy(null, false);
197             Assert.fail("missing proxy argument not detected (connect/true)");
198         } catch (final IllegalArgumentException iax) {
199             // expected
200         }
201 
202         rt.connectProxy(PROXY1, false);
203 
204         try {
205             rt.tunnelProxy(null, false);
206             Assert.fail("missing proxy argument not detected (tunnel/false)");
207         } catch (final IllegalArgumentException iax) {
208             // expected
209         }
210 
211         try {
212             rt.tunnelProxy(null, true);
213             Assert.fail("missing proxy argument not detected (tunnel/true)");
214         } catch (final IllegalArgumentException iax) {
215             // expected
216         }
217 
218         try {
219             rt.getHopTarget(-1);
220             Assert.fail("negative hop index not detected");
221         } catch (final IllegalArgumentException iax) {
222             // expected
223         }
224 
225         try {
226             rt.getHopTarget(2);
227             Assert.fail("excessive hop index not detected");
228         } catch (final IllegalArgumentException iax) {
229             // expected
230         }
231     }
232 
233     @Test
234     public void testIllegalStates() {
235 
236         final RouteTracker rt = new RouteTracker(TARGET1, null);
237 
238         try {
239             rt.tunnelTarget(false);
240             Assert.fail("unconnectedness not detected (tunnelTarget)");
241         } catch (final IllegalStateException isx) {
242             // expected
243         }
244 
245         try {
246             rt.tunnelProxy(PROXY1, false);
247             Assert.fail("unconnectedness not detected (tunnelProxy)");
248         } catch (final IllegalStateException isx) {
249             // expected
250         }
251 
252         try {
253             rt.layerProtocol(true);
254             Assert.fail("unconnectedness not detected (layerProtocol)");
255         } catch (final IllegalStateException isx) {
256             // expected
257         }
258 
259 
260         // connect directly
261         rt.connectTarget(false);
262 
263         try {
264             rt.connectTarget(false);
265             Assert.fail("connectedness not detected (connectTarget)");
266         } catch (final IllegalStateException isx) {
267             // expected
268         }
269 
270         try {
271             rt.connectProxy(PROXY2, false);
272             Assert.fail("connectedness not detected (connectProxy)");
273         } catch (final IllegalStateException isx) {
274             // expected
275         }
276 
277         try {
278             rt.tunnelTarget(false);
279             Assert.fail("unproxiedness not detected (tunnelTarget)");
280         } catch (final IllegalStateException isx) {
281             // expected
282         }
283 
284         try {
285             rt.tunnelProxy(PROXY1, false);
286             Assert.fail("unproxiedness not detected (tunnelProxy)");
287         } catch (final IllegalStateException isx) {
288             // expected
289         }
290     }
291 
292     @Test
293     public void testDirectRoutes() {
294 
295         final HttpRouteDirector rd = new BasicRouteDirector();
296         HttpRoute r = new HttpRoute(TARGET1, LOCAL41, false);
297         RouteTracker rt = new RouteTracker(r);
298         boolean complete = checkVia(rt, r, rd, 2);
299         Assert.assertTrue("incomplete route 1", complete);
300 
301         r = new HttpRoute(TARGET2, LOCAL62, true);
302         rt = new RouteTracker(r);
303         complete = checkVia(rt, r, rd, 2);
304         Assert.assertTrue("incomplete route 2", complete);
305     }
306 
307     @Test
308     public void testProxyRoutes() {
309 
310         final HttpRouteDirector rd = new BasicRouteDirector();
311         HttpRoute r = new HttpRoute(TARGET2, null, PROXY1, false);
312         RouteTracker rt = new RouteTracker(r);
313         boolean complete = checkVia(rt, r, rd, 2);
314         Assert.assertTrue("incomplete route 1", complete);
315 
316         // tunnelled, but neither secure nor layered
317         r = new HttpRoute(TARGET1, LOCAL61, PROXY3, false,
318                           TunnelType.TUNNELLED, LayerType.PLAIN);
319         rt = new RouteTracker(r);
320         complete = checkVia(rt, r, rd, 3);
321         Assert.assertTrue("incomplete route 2", complete);
322 
323         // tunnelled, layered, but not secure
324         r = new HttpRoute(TARGET1, LOCAL61, PROXY3, false,
325                           TunnelType.TUNNELLED, LayerType.LAYERED);
326         rt = new RouteTracker(r);
327         complete = checkVia(rt, r, rd, 4);
328         Assert.assertTrue("incomplete route 3", complete);
329 
330         // tunnelled, layered, secure
331         r = new HttpRoute(TARGET1, LOCAL61, PROXY3, true);
332         rt = new RouteTracker(r);
333         complete = checkVia(rt, r, rd, 4);
334         Assert.assertTrue("incomplete route 4", complete);
335     }
336 
337     @Test
338     public void testProxyChainRoutes() {
339 
340         final HttpRouteDirector rd = new BasicRouteDirector();
341         HttpHost[] proxies = { PROXY1, PROXY2 };
342         HttpRoute r = new HttpRoute(TARGET2, LOCAL42, proxies, false,
343                                     TunnelType.PLAIN, LayerType.PLAIN);
344         RouteTracker rt = new RouteTracker(r);
345         boolean complete = checkVia(rt, r, rd, 3);
346         Assert.assertTrue("incomplete route 1", complete);
347 
348         // tunnelled, but neither secure nor layered
349         proxies = new HttpHost[]{ PROXY3, PROXY2 };
350         r = new HttpRoute(TARGET1, null, proxies, false,
351                           TunnelType.TUNNELLED, LayerType.PLAIN);
352         rt = new RouteTracker(r);
353         complete = checkVia(rt, r, rd, 4);
354         Assert.assertTrue("incomplete route 2", complete);
355 
356         // tunnelled, layered, but not secure
357         proxies = new HttpHost[]{ PROXY3, PROXY2, PROXY1 };
358         r = new HttpRoute(TARGET2, LOCAL61, proxies, false,
359                           TunnelType.TUNNELLED, LayerType.LAYERED);
360         rt = new RouteTracker(r);
361         complete = checkVia(rt, r, rd, 6);
362         Assert.assertTrue("incomplete route 3", complete);
363 
364         // tunnelled, layered, secure
365         proxies = new HttpHost[]{ PROXY1, PROXY3 };
366         r = new HttpRoute(TARGET1, LOCAL61, proxies, true,
367                           TunnelType.TUNNELLED, LayerType.LAYERED);
368         rt = new RouteTracker(r);
369         complete = checkVia(rt, r, rd, 5);
370         Assert.assertTrue("incomplete route 4", complete);
371     }
372 
373     @Test
374     public void testEqualsHashcodeCloneToString()
375         throws CloneNotSupportedException {
376 
377         final RouteTracker rt0 = new RouteTracker(TARGET1, null);
378         final RouteTracker rt1 = new RouteTracker(TARGET2, null);
379         final RouteTracker rt2 = new RouteTracker(TARGET1, null);
380         final RouteTracker rt3 = new RouteTracker(TARGET1, null);
381         final RouteTracker rt4 = new RouteTracker(TARGET1, LOCAL41);
382         final RouteTracker rt6 = new RouteTracker(TARGET1, LOCAL62);
383 
384         Assert.assertFalse("rt0", rt0.equals(null));
385         Assert.assertTrue("rt0", rt0.equals(rt0));
386         Assert.assertFalse("rt0", rt0.equals(rt0.toString()));
387 
388         Assert.assertFalse("rt0 == rt4", rt0.equals(rt4));
389         Assert.assertFalse("rt0 == rt1", rt0.equals(rt1)); // Check host takes part in equals
390 
391         // Check that connection takes part in equals
392         Assert.assertTrue("rt0 != rt2", rt0.equals(rt2));
393         rt2.connectTarget(false);
394         Assert.assertFalse("rt0 == rt2", rt0.equals(rt2));
395 
396         Assert.assertTrue("rt0 != rt3", rt0.equals(rt3));
397         rt3.connectTarget(true);
398         Assert.assertFalse("rt0 == rt3", rt0.equals(rt3));
399         Assert.assertFalse("rt2 == rt3", rt2.equals(rt3)); // Test secure takes part
400 
401         // TODO needs tests for tunnel and layered
402 
403         Assert.assertFalse("rt4 == rt0", rt4.equals(rt0));
404         Assert.assertFalse("rt0 == rt6", rt0.equals(rt6));
405         Assert.assertFalse("rt6 == rt0", rt6.equals(rt0));
406         Assert.assertFalse("rt4 == rt6", rt4.equals(rt6));
407         Assert.assertFalse("rt6 == rt4", rt6.equals(rt4));
408 
409         // it is likely but not guaranteed that the hashcodes are different
410         Assert.assertFalse("rt0 == rt4 (hashcode)", rt0.hashCode() == rt4.hashCode());
411         Assert.assertFalse("rt0 == rt6 (hashcode)", rt0.hashCode() == rt6.hashCode());
412         Assert.assertFalse("rt6 == rt4 (hashcode)", rt6.hashCode() == rt4.hashCode());
413 
414         Assert.assertEquals("rt0 (clone)", rt0, rt0.clone());
415         Assert.assertEquals("rt4 (clone)", rt4, rt4.clone());
416         Assert.assertEquals("rt6 (clone)", rt6, rt6.clone());
417 
418 
419         // we collect (clones of) the different tracked routes along the way
420         // rt0 -> direct connection
421         // rt1 -> via single proxy
422         // rt2 -> via proxy chain
423         final Set<RouteTracker> hs = new HashSet<RouteTracker>();
424 
425         // we also collect hashcodes for the different paths
426         // since we can't guarantee what influence the HttpHost hashcodes have,
427         // we keep separate sets here
428         final Set<Integer> hc0 = new HashSet<Integer>();
429         final Set<Integer> hc4 = new HashSet<Integer>();
430         final Set<Integer> hc6 = new HashSet<Integer>();
431 
432         RouteTracker rt = null;
433 
434         Assert.assertTrue(hs.add(rt0));
435         Assert.assertTrue(hs.add(rt4));
436         Assert.assertTrue(hs.add(rt6));
437 
438         Assert.assertTrue(hc0.add(Integer.valueOf(rt0.hashCode())));
439         Assert.assertTrue(hc4.add(Integer.valueOf(rt4.hashCode())));
440         Assert.assertTrue(hc6.add(Integer.valueOf(rt6.hashCode())));
441 
442         rt = (RouteTracker) rt0.clone();
443         rt.connectTarget(false);
444         Assert.assertTrue(hs.add(rt));
445         Assert.assertTrue(hc0.add(Integer.valueOf(rt.hashCode())));
446 
447         rt = (RouteTracker) rt0.clone();
448         rt.connectTarget(true);
449         Assert.assertTrue(hs.add(rt));
450         Assert.assertTrue(hc0.add(Integer.valueOf(rt.hashCode())));
451 
452 
453         // proxy (insecure) -> tunnel (insecure) -> layer (secure)
454         rt = (RouteTracker) rt4.clone();
455         rt.connectProxy(PROXY1, false);
456         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
457         // this is not guaranteed to be unique...
458         Assert.assertTrue(hc4.add(Integer.valueOf(rt.hashCode())));
459 
460         rt.tunnelTarget(false);
461         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
462         Assert.assertTrue(hc4.add(Integer.valueOf(rt.hashCode())));
463 
464         rt.layerProtocol(true);
465         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
466         Assert.assertTrue(hc4.add(Integer.valueOf(rt.hashCode())));
467 
468 
469         // proxy (secure) -> tunnel (secure) -> layer (insecure)
470         rt = (RouteTracker) rt4.clone();
471         rt.connectProxy(PROXY1, true);
472         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
473         // this is not guaranteed to be unique...
474         Assert.assertTrue(hc4.add(Integer.valueOf(rt.hashCode())));
475 
476         rt.tunnelTarget(true);
477         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
478         Assert.assertTrue(hc4.add(Integer.valueOf(rt.hashCode())));
479 
480         rt.layerProtocol(false);
481         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
482         Assert.assertTrue(hc4.add(Integer.valueOf(rt.hashCode())));
483 
484 
485         // PROXY1/i -> PROXY2/i -> tunnel/i -> layer/s
486         rt = (RouteTracker) rt6.clone();
487         rt.connectProxy(PROXY1, false);
488         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
489         // this is not guaranteed to be unique...
490         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
491 
492         rt.tunnelProxy(PROXY2, false);
493         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
494         // this is not guaranteed to be unique...
495         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
496 
497         rt.tunnelTarget(false);
498         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
499         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
500 
501         rt.layerProtocol(true);
502         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
503         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
504 
505 
506         // PROXY1/s -> PROXY2/s -> tunnel/s -> layer/i
507         rt = (RouteTracker) rt6.clone();
508         rt.connectProxy(PROXY1, true);
509         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
510         // this is not guaranteed to be unique...
511         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
512 
513         rt.tunnelProxy(PROXY2, true);
514         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
515         // this is not guaranteed to be unique...
516         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
517 
518         rt.tunnelTarget(true);
519         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
520         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
521 
522         rt.layerProtocol(false);
523         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
524         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
525 
526 
527         // PROXY2/i -> PROXY1/i -> tunnel/i -> layer/s
528         rt = (RouteTracker) rt6.clone();
529         rt.connectProxy(PROXY2, false);
530         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
531         // this is not guaranteed to be unique...
532         Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
533 
534         rt.tunnelProxy(PROXY1, false);
535         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
536         // proxy chain sequence does not affect hashcode, so duplicate:
537         // Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
538 
539         rt.tunnelTarget(false);
540         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
541         // proxy chain sequence does not affect hashcode, so duplicate:
542         // Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
543 
544         rt.layerProtocol(true);
545         Assert.assertTrue(hs.add((RouteTracker) rt.clone()));
546         // proxy chain sequence does not affect hashcode, so duplicate:
547         // Assert.assertTrue(hc6.add(Integer.valueOf(rt.hashCode())));
548 
549 
550         // check that all toString are OK and different
551         final Set<String> rtstrings = new HashSet<String>();
552         for (final RouteTracker current: hs) {
553             final String rts = checkToString(current);
554             Assert.assertTrue("duplicate toString: " + rts, rtstrings.add(rts));
555         }
556     }
557 
558 
559     /** Helper to check the status of the four flags. */
560     public final static void checkCTLS(final RouteTracker rt,
561                                        final boolean c, final boolean t,
562                                        final boolean l, final boolean s) {
563         final String rts = rt.toString();
564         Assert.assertEquals("wrong flag connected: " + rts, c, rt.isConnected());
565         Assert.assertEquals("wrong flag tunnelled: " + rts, t, rt.isTunnelled());
566         Assert.assertEquals("wrong enum tunnelled: " + rts,
567                      t ? TunnelType.TUNNELLED : TunnelType.PLAIN,
568                      rt.getTunnelType());
569         Assert.assertEquals("wrong flag layered: "   + rts, l, rt.isLayered());
570         Assert.assertEquals("wrong enum layered: "   + rts,
571                      l ? LayerType.LAYERED : LayerType.PLAIN,
572                      rt.getLayerType());
573         Assert.assertEquals("wrong flag secure: "    + rts, s, rt.isSecure());
574     }
575 
576 
577     /**
578      * Helper to check tracking of a route.
579      * This uses a {@link HttpRouteDirector} to fake establishing the route,
580      * checking the intermediate steps.
581      *
582      * @param rt        the tracker to check with
583      * @param r         the route to establish
584      * @param rd        the director to check with
585      * @param steps     the step count for this invocation
586      *
587      * @return  {@code true} iff the route is complete
588      */
589     public final static boolean checkVia(final RouteTracker rt, final HttpRoute r,
590                                          final HttpRouteDirector rd, final int steps) {
591 
592         final String msg = r.toString() + " @ " + rt.toString();
593 
594         boolean complete = false;
595         int n = steps;
596         while (!complete && (n > 0)) {
597 
598             final int action = rd.nextStep(r, rt.toRoute());
599             switch (action) {
600 
601             case HttpRouteDirector.COMPLETE:
602                 complete = true;
603                 Assert.assertEquals(r, rt.toRoute());
604                 break;
605 
606             case HttpRouteDirector.CONNECT_TARGET: {
607                 final boolean sec = r.isSecure();
608                 rt.connectTarget(sec);
609                 checkCTLS(rt, true, false, false, sec);
610                 Assert.assertEquals("wrong hop count "+msg,
611                              1, rt.getHopCount());
612                 Assert.assertEquals("wrong hop0 "+msg,
613                              r.getTargetHost(), rt.getHopTarget(0));
614             } break;
615 
616             case HttpRouteDirector.CONNECT_PROXY: {
617                 // we assume an insecure proxy connection
618                 final boolean sec = false;
619                 rt.connectProxy(r.getProxyHost(), sec);
620                 checkCTLS(rt, true, false, false, sec);
621                 Assert.assertEquals("wrong hop count "+msg,
622                              2, rt.getHopCount());
623                 Assert.assertEquals("wrong hop0 "+msg,
624                              r.getProxyHost(), rt.getHopTarget(0));
625                 Assert.assertEquals("wrong hop1 "+msg,
626                              r.getTargetHost(), rt.getHopTarget(1));
627             } break;
628 
629             case HttpRouteDirector.TUNNEL_TARGET: {
630                 final int hops = rt.getHopCount();
631                 // we assume an insecure tunnel
632                 final boolean sec = false;
633                 rt.tunnelTarget(sec);
634                 checkCTLS(rt, true, true, false, sec);
635                 Assert.assertEquals("wrong hop count "+msg,
636                              hops, rt.getHopCount());
637                 Assert.assertEquals("wrong hop0 "+msg,
638                              r.getProxyHost(), rt.getHopTarget(0));
639                 Assert.assertEquals("wrong hopN "+msg,
640                              r.getTargetHost(), rt.getHopTarget(hops-1));
641             } break;
642 
643             case HttpRouteDirector.TUNNEL_PROXY: {
644                 final int hops = rt.getHopCount(); // before tunnelling
645                 // we assume an insecure tunnel
646                 final boolean  sec = false;
647                 final HttpHost pxy = r.getHopTarget(hops-1);
648                 rt.tunnelProxy(pxy, sec);
649                 // Since we're tunnelling to a proxy and not the target,
650                 // the 'tunelling' flag is false: no end-to-end tunnel.
651                 checkCTLS(rt, true, false, false, sec);
652                 Assert.assertEquals("wrong hop count "+msg,
653                              hops+1, rt.getHopCount());
654                 Assert.assertEquals("wrong hop0 "+msg,
655                              r.getProxyHost(), rt.getHopTarget(0));
656                 Assert.assertEquals("wrong hop"+hops+" "+msg,
657                              pxy, rt.getHopTarget(hops-1));
658                 Assert.assertEquals("wrong hopN "+msg,
659                              r.getTargetHost(), rt.getHopTarget(hops));
660             } break;
661 
662             case HttpRouteDirector.LAYER_PROTOCOL: {
663                 final int    hops = rt.getHopCount();
664                 final boolean tun = rt.isTunnelled();
665                 final boolean sec = r.isSecure();
666                 rt.layerProtocol(sec);
667                 checkCTLS(rt, true, tun, true, sec);
668                 Assert.assertEquals("wrong hop count "+msg,
669                              hops, rt.getHopCount());
670                 Assert.assertEquals("wrong proxy "+msg,
671                              r.getProxyHost(), rt.getProxyHost());
672                 Assert.assertEquals("wrong target "+msg,
673                              r.getTargetHost(), rt.getTargetHost());
674             } break;
675 
676 
677             // UNREACHABLE
678             default:
679                 Assert.fail("unexpected action " + action + " from director, "+msg);
680                 break;
681 
682             } // switch
683             n--;
684         }
685 
686         return complete;
687     } // checkVia
688 
689 
690     /**
691      * Checks the output of {@code toString}.
692      *
693      * @param rt        the tracker for which to check the output
694      *
695      * @return  the result of {@code rt.toString()}
696      */
697     public final static String checkToString(final RouteTracker rt) {
698         if (rt == null) {
699             return null;
700         }
701 
702         final String rts = rt.toString();
703 
704         if (rt.getLocalAddress() != null) {
705             final String las = rt.getLocalAddress().toString();
706             Assert.assertFalse("no local address in toString(): " + rts,
707                     !rts.contains(las));
708         }
709 
710         for (int i=0; i<rt.getHopCount(); i++) {
711             final String hts = rt.getHopTarget(i).toString();
712             Assert.assertFalse("hop "+i+" ("+hts+") missing in toString(): " + rts,
713                     !rts.contains(hts));
714         }
715 
716         return rts;
717     }
718 
719 }