1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.21 2004/04/13 21:47:29 olegk Exp $
3    * $Revision: 1.21 $
4    * $Date: 2004/04/13 21:47:29 $
5    * ====================================================================
6    *
7    *  Copyright 1999-2004 The Apache Software Foundation
8    *
9    *  Licensed under the Apache License, Version 2.0 (the "License");
10   *  you may not use this file except in compliance with the License.
11   *  You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   *  Unless required by applicable law or agreed to in writing, software
16   *  distributed under the License is distributed on an "AS IS" BASIS,
17   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   *  See the License for the specific language governing permissions and
19   *  limitations under the License.
20   * ====================================================================
21   *
22   * This software consists of voluntary contributions made by many
23   * individuals on behalf of the Apache Software Foundation.  For more
24   * information on the Apache Software Foundation, please see
25   * <http://www.apache.org/>.
26   *
27   * [Additional notices, if required by prior licensing conditions]
28   *
29   */
30  
31  package org.apache.commons.httpclient;
32  
33  import java.io.IOException;
34  import java.lang.ref.WeakReference;
35  import java.net.InetAddress;
36  import java.net.Socket;
37  import java.net.UnknownHostException;
38  
39  import junit.framework.Test;
40  import junit.framework.TestSuite;
41  
42  import org.apache.commons.httpclient.methods.GetMethod;
43  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
44  import org.apache.commons.httpclient.params.HttpConnectionParams;
45  import org.apache.commons.httpclient.protocol.Protocol;
46  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
47  import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
48  
49  /***
50   * Unit tests for {@link HttpConnectionManager}.
51   *
52   * @author Marc A. Saegesser
53   * @version $Id: TestHttpConnectionManager.java,v 1.21 2004/04/13 21:47:29 olegk Exp $
54   */
55  public class TestHttpConnectionManager extends TestLocalHostBase {
56  
57      // ------------------------------------------------------------ Constructor
58      public TestHttpConnectionManager(String testName) {
59          super(testName);
60      }
61  
62      // ------------------------------------------------------------------- Main
63      public static void main(String args[]) {
64          String[] testCaseName = { TestHttpConnectionManager.class.getName() };
65          junit.textui.TestRunner.main(testCaseName);
66      }
67  
68      // ------------------------------------------------------- TestCase Methods
69  
70      public static Test suite() {
71          return new TestSuite(TestHttpConnectionManager.class);
72      }
73  
74  
75      // ----------------------------------------------------------- Test Methods
76  
77      /***
78       * Test that the ConnectMethod correctly releases connections when
79       * CONNECT fails.
80       */
81      public void testConnectMethodFailureRelease() throws Exception {
82          
83          MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
84          mgr.getParams().setIntParameter(
85              HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
86          HttpClient client = createHttpClient(mgr);
87          
88          // we're going to execute a connect method against the localhost, assuming
89          // that CONNECT is not supported.  This should test the fakeResponse()
90          // code on HttpMethodBase.
91          client.getHostConfiguration().setProxy(getHost(), getPort());
92          // we must set the host to a secure destination or the CONNECT method
93          // will not be used
94          client.getHostConfiguration().setHost(
95              "notARealHost", 
96              1234, 
97              new Protocol(
98                  "https", 
99                  (ProtocolSocketFactory)new FakeSecureProtocolSocketFactory(), 
100                 443)
101         );
102         
103         GetMethod get = new GetMethod("/");
104         try {
105             assertTrue(client.executeMethod(get) != 200);
106         } catch (IOException e) {
107             e.printStackTrace();
108             fail("Error executing connect: " + e);
109         }
110 
111         // this should calling releaseConnection() releases the connection
112         try {
113             get.releaseConnection();
114             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
115         } catch (ConnectTimeoutException e1) {
116             fail("Connection should have been available.");
117         }
118         
119         get = new GetMethod("/");
120         
121         try {
122             assertTrue(client.executeMethod(get) != 200);
123         } catch (IOException e) {
124             e.printStackTrace();
125             fail("Error executing connect: " + e);
126         }
127 
128         // make sure reading the response fully releases the connection        
129         try {
130             get.getResponseBodyAsString();
131             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
132         } catch (ConnectTimeoutException e1) {
133             fail("Connection should have been available.");
134         }     
135         
136         get = new GetMethod("/");
137         
138         try {
139             assertTrue(client.executeMethod(get) != 200);
140         } catch (IOException e) {
141             e.printStackTrace();
142             fail("Error executing connect: " + e);
143         }
144 
145         // make sure closing the output stream releases the connection        
146         try {
147             get.getResponseBodyAsStream().close();
148             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
149         } catch (ConnectTimeoutException e) {
150             fail("Connection should have been available.");
151         } catch (IOException e) {
152             e.printStackTrace();
153             fail("Close connection failed: " + e);   
154         }
155     }
156 
157     public void testGetConnection() {
158         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
159 
160         HostConfiguration hostConfiguration = new HostConfiguration();
161         hostConfiguration.setHost("www.nosuchserver.com", 80, "http");
162 
163         // Create a new connection
164         HttpConnection conn = mgr.getConnection(hostConfiguration);
165         // Validate the connection properties
166         assertEquals("Host", "www.nosuchserver.com", conn.getHost());
167         assertEquals("Port", 80, conn.getPort());
168         // Release the connection
169         mgr.releaseConnection(conn);
170 
171         // Create a new connection
172         hostConfiguration.setHost("www.nosuchserver.com", -1, "https");
173         conn = mgr.getConnection(hostConfiguration);
174         // Validate the connection properties
175         assertEquals("Host", "www.nosuchserver.com", conn.getHost());
176         assertEquals("Port", 443, conn.getPort());
177         // Release the connection
178         mgr.releaseConnection(conn);
179 
180         // Create a new connection
181         hostConfiguration.setHost("www.nowhere.org", 8080, "http");
182         conn = mgr.getConnection(hostConfiguration);
183         // Validate the connection properties
184         assertEquals("Host", "www.nowhere.org", conn.getHost());
185         assertEquals("Port", 8080, conn.getPort());
186         // Release the connection
187         mgr.releaseConnection(conn);
188 
189     }
190 
191     public void testDroppedThread() throws Exception {
192 
193         MultiThreadedHttpConnectionManager mthcm = new MultiThreadedHttpConnectionManager();
194         HttpClient httpClient = createHttpClient(mthcm);
195         WeakReference wr = new WeakReference(mthcm);
196 
197         GetMethod method = new GetMethod("/");
198         httpClient.executeMethod(method);
199         method.releaseConnection();
200 
201         mthcm = null;
202         httpClient = null;
203         method = null;
204         
205         System.gc();
206 
207         // this sleep appears to be necessary in order to give the JVM
208         // time to clean up the miscellaneous pointers to the connection manager
209         try {
210             Thread.sleep(1000);
211         } catch (InterruptedException e) {
212             fail("shouldn't be interrupted.");
213         }
214 
215         Object connectionManager = wr.get();
216         assertNull("connectionManager should be null", connectionManager);
217     }    
218     
219     public void testWriteRequestReleaseConnection() {
220 
221         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
222         connectionManager.getParams().setIntParameter(
223             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
224 
225         HttpClient client = createHttpClient(connectionManager);
226         
227         GetMethod get = new GetMethod("/") {
228             protected boolean writeRequestBody(HttpState state, HttpConnection conn)
229                 throws IOException, HttpException {
230                 throw new IOException("Oh no!!");
231             }
232         };
233         
234         try {
235             client.executeMethod(get);
236             fail("An exception should have occurred.");
237         } catch (HttpException e) {
238             e.printStackTrace();
239             fail("HttpException should not have occurred: " + e);
240         } catch (IOException e) {
241             // expected
242         }
243         
244         try {
245             connectionManager.getConnectionWithTimeout(client.getHostConfiguration(), 1);
246         } catch (ConnectTimeoutException e) {
247             e.printStackTrace();
248             fail("Connection was not released: " + e);
249         }
250         
251     }
252     
253     public void testReleaseConnection() {
254 
255         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
256         connectionManager.getParams().setIntParameter(
257             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
258 
259         HttpClient client = createHttpClient(connectionManager);
260         // we shouldn't have to wait if a connection is available
261         client.getParams().setConnectionManagerTimeout(1);
262 
263         GetMethod getMethod = new GetMethod("/");
264 
265         try {
266             client.executeMethod(getMethod);
267         } catch (Exception e) {
268             fail("error reading from server: " + e);
269         }
270 
271         try {
272             // this should fail quickly since the connection has not been released
273             client.executeMethod(getMethod);
274             fail("a httpConnection should not be available");
275         } catch (ConnectTimeoutException e) {            
276         } catch (HttpException e) {
277             fail("error reading from server; " + e);
278         } catch (IOException e) {
279             e.printStackTrace();
280             fail("error reading from server; " + e);
281         }
282 
283         // this should release the connection
284         getMethod.releaseConnection();
285 
286         getMethod = new GetMethod("/");
287 
288         try {
289             // this should fail quickly if the connection has not been released
290             client.executeMethod(getMethod);
291         } catch (HttpException e) {
292             fail("httpConnection does not appear to have been released: " + e);
293         } catch (IOException e) {
294             fail("error reading from server; " + e);
295         }
296 
297     }
298 
299     /***
300      * Makes sure that a connection gets released after the content of the body
301      * is read.
302      */
303     public void testResponseAutoRelease() throws Exception  {
304 
305         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
306         connectionManager.getParams().setIntParameter(
307             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
308 
309         HttpClient client = createHttpClient(connectionManager);
310         // we shouldn't have to wait if a connection is available
311         client.getParams().setConnectionManagerTimeout( 1 );
312 
313         GetMethod getMethod = new GetMethod("/");
314 
315         try {
316             client.executeMethod(getMethod);
317         } catch (Exception e) {
318             fail("error reading from server: " + e);
319         }
320         
321         // this should release the connection
322         getMethod.getResponseBody();
323 
324         getMethod = new GetMethod("/");
325 
326         try {
327             // this should fail quickly if the connection has not been released
328             client.executeMethod(getMethod);
329         } catch (HttpException e) {
330             fail("httpConnection does not appear to have been released: " + e);
331         } catch (IOException e) {
332             fail("error reading from server; " + e);
333         }
334 
335     }
336     
337     /***
338      * Tests the MultiThreadedHttpConnectionManager's ability to reclaim unused 
339      * connections.
340      */
341     public void testConnectionReclaiming() {
342         
343         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
344         connectionManager.getParams().setIntParameter(
345             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
346         connectionManager.getParams().setIntParameter(
347             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
348 
349         HostConfiguration host1 = new HostConfiguration();
350         host1.setHost("host1", -1, "http");
351 
352         HostConfiguration host2 = new HostConfiguration();
353         host2.setHost("host2", -1, "http");
354 
355         HttpConnection connection = connectionManager.getConnection(host1);
356         // now release this connection
357         connection.releaseConnection();
358         connection = null;
359         
360         try {
361             // the connection from host1 should be reclaimed
362             connection = connectionManager.getConnectionWithTimeout(host2, 100);
363         } catch (ConnectTimeoutException e) {
364             e.printStackTrace();
365             fail("a httpConnection should have been available: " + e);
366         }        
367     }
368     
369     /***
370      * Tests that {@link MultiThreadedHttpConnectionManager#shutdownAll()} closes all resources
371      * and makes all connection mangers unusable.
372      */
373     public void testShutdownAll() {
374 
375         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
376         connectionManager.getParams().setIntParameter(
377             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
378         connectionManager.getParams().setIntParameter(
379             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
380 
381         HostConfiguration host1 = new HostConfiguration();
382         host1.setHost("host1", -1, "http");
383 
384         // hold on to the only connection
385         HttpConnection connection = connectionManager.getConnection(host1);
386 
387         // wait for a connection on another thread
388         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
389         getConn.start();
390         
391         MultiThreadedHttpConnectionManager.shutdownAll();
392         
393         // now release this connection, this should close the connection, but have no other effect
394         connection.releaseConnection();
395         connection = null;
396         
397         try {
398             getConn.join();
399         } catch (InterruptedException e) {
400             e.printStackTrace();
401         }
402         
403         // this thread should have caught an exception without getting a connection
404         assertNull("Not connection should have been checked out", getConn.getConnection());
405         assertNotNull("There should have been an exception", getConn.getException());
406         
407         try {
408             connectionManager.getConnection(host1);
409             fail("An exception should have occurred");
410         } catch (Exception e) {
411             // this is expected
412         }
413     }
414         
415     /***
416      * Tests that {@link MultiThreadedHttpConnectionManager#shutdown()} closes all resources
417      * and makes the connection manger unusable.
418      */
419     public void testShutdown() {
420 
421         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
422         connectionManager.getParams().setIntParameter(
423             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
424         connectionManager.getParams().setIntParameter(
425             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
426 
427         HostConfiguration host1 = new HostConfiguration();
428         host1.setHost("host1", -1, "http");
429 
430         // hold on to the only connection
431         HttpConnection connection = connectionManager.getConnection(host1);
432 
433         // wait for a connection on another thread
434         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
435         getConn.start();
436         
437         connectionManager.shutdown();
438         
439         // now release this connection, this should close the connection, but have no other effect
440         connection.releaseConnection();
441         connection = null;
442         
443         try {
444             getConn.join();
445         } catch (InterruptedException e) {
446             e.printStackTrace();
447         }
448         
449         // this thread should have caught an exception without getting a connection
450         assertNull("Not connection should have been checked out", getConn.getConnection());
451         assertNotNull("There should have been an exception", getConn.getException());
452         
453         try {
454             connectionManager.getConnection(host1);
455             fail("An exception should have occurred");
456         } catch (Exception e) {
457             // this is expected
458         }
459     }
460     
461     /***
462      * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number 
463      * of connections.
464      */    
465     public void testMaxConnections() {
466         
467         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
468         connectionManager.getParams().setIntParameter(
469             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
470         connectionManager.getParams().setIntParameter(
471             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 2);
472 
473         HostConfiguration host1 = new HostConfiguration();
474         host1.setHost("host1", -1, "http");
475 
476         HostConfiguration host2 = new HostConfiguration();
477         host2.setHost("host2", -1, "http");
478 
479         HttpConnection connection1 = connectionManager.getConnection(host1);
480         HttpConnection connection2 = connectionManager.getConnection(host2);
481     
482         try {
483             // this should fail quickly since the connection has not been released
484             connectionManager.getConnectionWithTimeout(host2, 100);
485             fail("a httpConnection should not be available");
486         } catch (ConnectTimeoutException e) {
487             // this should throw an exception
488         }
489         
490         // release one of the connections
491         connection2.releaseConnection();
492         connection2 = null;
493         
494         try {
495             // there should be a connection available now
496             connection2 = connectionManager.getConnectionWithTimeout(host2, 100);
497         } catch (ConnectTimeoutException e) {
498             e.printStackTrace();
499             fail("a httpConnection should have been available: " + e);
500         }
501     }    
502 
503     public void testHostReusePreference() {
504         
505         final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
506         connectionManager.getParams().setIntParameter(
507             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
508         connectionManager.getParams().setIntParameter(
509             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
510 
511         final HostConfiguration host1 = new HostConfiguration();
512         host1.setHost("host1", -1, "http");
513 
514         final HostConfiguration host2 = new HostConfiguration();
515         host2.setHost("host2", -1, "http");
516 
517         HttpConnection connection = connectionManager.getConnection(host1);
518 
519         GetConnectionThread getHost1 = new GetConnectionThread(host1, connectionManager, 200);
520         GetConnectionThread getHost2 = new GetConnectionThread(host2, connectionManager, 200);
521         
522         getHost2.start();
523         getHost1.start();
524         
525         // give the threads some time to startup
526         try {
527             Thread.sleep(100);
528         } catch (InterruptedException e1) {
529             e1.printStackTrace();
530         }
531             
532         // after the connection to host1 is released it should be given to getHost1
533         connection.releaseConnection();
534         connection = null;
535 
536         try {
537             getHost1.join();
538             getHost2.join();
539         } catch (InterruptedException e) {
540             e.printStackTrace();
541         }
542 
543         assertNotSame(
544             "Connection should have been given to someone", 
545             getHost1.getConnection(),
546             getHost2.getConnection()
547         );        
548         assertNotNull("Connection should have been given to host1", getHost1.getConnection());
549         assertNull("Connection should NOT have been given to host2", getHost2.getConnection());
550         
551     } 
552     
553     public void testMaxConnectionsPerServer() {
554      
555         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
556         connectionManager.getParams().setIntParameter(
557             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 1);
558 
559         HttpClient client = createHttpClient(connectionManager);
560         // we shouldn't have to wait if a connection is available
561         client.getParams().setConnectionManagerTimeout( 1 );
562 
563         GetMethod getMethod = new GetMethod("/");
564 
565         try {
566             client.executeMethod(getMethod);
567         } catch (Exception e) {
568             fail("error reading from server: " + e);
569         }
570 
571         GetMethod getMethod2 = new GetMethod("/");
572 
573         try {
574             // this should fail quickly since the connection has not been released
575             client.executeMethod(getMethod2);
576             fail("a httpConnection should not be available");
577         } catch (ConnectTimeoutException e) {
578         } catch (HttpException e) {
579             fail("error reading from server; " + e);
580         } catch (IOException e) {
581             fail("error reading from server; " + e);
582         }
583                 
584     }
585     
586     public void testReclaimUnusedConnection() {
587 
588         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
589         connectionManager.getParams().setIntParameter(
590             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
591 
592         HttpClient client = createHttpClient(connectionManager);
593         // we shouldn't have to wait if a connection is available
594         client.getParams().setConnectionManagerTimeout( 30000 );
595 
596         GetMethod getMethod = new GetMethod("/");
597 
598         try {
599             client.executeMethod(getMethod);
600         } catch (Exception e) {
601             fail("error reading from server: " + e);
602         }
603 
604         getMethod = new GetMethod("/");
605         
606         Runtime.getRuntime().gc();
607 
608         try {
609             // we didn't explicitly release the connection, but it should be 
610             // reclaimed by the garbage collector, we hope:)
611             client.executeMethod(getMethod);
612         } catch (HttpException e) {
613             fail("httpConnection does not appear to have been reclaimed by the GC: " + e);
614         } catch (IOException e) {
615             fail("error reading from server; " + e);
616         }
617 
618     }
619     
620     public void testGetFromMultipleThreads() {
621         
622         HttpClient client = createHttpClient(new MultiThreadedHttpConnectionManager());
623         ExecuteMethodThread[] threads = new ExecuteMethodThread[10];
624         
625         for (int i = 0; i < threads.length; i++) {
626             GetMethod method = new GetMethod("/");
627             method.setFollowRedirects(true);
628             
629             threads[i] = new ExecuteMethodThread(method, client);
630             threads[i].start();
631         }
632         
633         for (int i = 0; i < threads.length; i++) {
634             try {
635                 // wait until this thread finishes. we'll give it 10 seconds,
636                 // but it shouldn't take that long
637                 threads[i].join(10000);
638             } catch (InterruptedException e) {
639             }
640             // make sure an exception did not occur
641             Exception e = threads[i].getException();
642             if (e != null) {
643                 fail("An error occured in the get: " + e);
644             }
645             // we should have a 200 status
646             assertEquals(threads[i].getMethod().getStatusCode(), HttpStatus.SC_OK);
647         }
648     }
649 
650     public void testTimeout() {
651         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
652         mgr.getParams().setIntParameter(
653             HttpConnectionManagerParams.MAX_HOST_CONNECTIONS, 2);
654         
655         try{
656             HostConfiguration hostConfig = new HostConfiguration();
657             hostConfig.setHost("www.nosuchserver.com", 80, "http");
658             
659             HttpConnection conn1 = mgr.getConnection(hostConfig);
660             HttpConnection conn2 = mgr.getConnection(hostConfig);
661             
662             HttpConnection conn3 = mgr.getConnectionWithTimeout(hostConfig, 1000);
663             fail("Expected an HttpException.");
664             
665         }catch(ConnectTimeoutException e){
666             //Expected result
667         }
668     }
669     
670     static class FakeSecureProtocolSocketFactory implements SecureProtocolSocketFactory {
671         
672         public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
673             throws IOException, UnknownHostException {
674             throw new IllegalStateException("createSocket() should never have been called.");
675         }
676         
677         public Socket createSocket(String host, int port)
678             throws IOException, UnknownHostException {
679             throw new IllegalStateException("createSocket() should never have been called.");
680         }
681         
682         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
683             throws IOException, UnknownHostException {
684             throw new IllegalStateException("createSocket() should never have been called.");
685         }
686         
687         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, 
688             HttpConnectionParams params)
689             throws IOException, UnknownHostException {
690             throw new IllegalStateException("createSocket() should never have been called.");
691         }
692     }
693     
694     static class GetConnectionThread extends Thread {
695         
696         private HostConfiguration hostConfiguration;
697         private MultiThreadedHttpConnectionManager connectionManager;
698         private HttpConnection connection;
699         private long timeout;
700         private Exception exception;
701         
702         public GetConnectionThread(
703             HostConfiguration hostConfiguration, 
704             MultiThreadedHttpConnectionManager connectionManager,
705             long timeout
706         ) {
707             this.hostConfiguration = hostConfiguration;
708             this.connectionManager = connectionManager; 
709             this.timeout = timeout;
710         }
711         
712         public void run() {
713             try {
714                 connection = connectionManager.getConnectionWithTimeout(hostConfiguration, timeout);
715             } catch (Exception e) {
716                 this.exception = e;
717             }            
718         }
719         
720         public Exception getException() {
721             return exception;
722         }
723         
724         public HttpConnection getConnection() {
725             return connection;
726         }
727 
728     }
729     
730 }
731