1   /*
2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.23 2004/07/17 18:58:33 mbecke Exp $
3    * $Revision: 312494 $
4    * $Date: 2005-10-09 15:53:32 -0400 (Sun, 09 Oct 2005) $
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  
28  package org.apache.commons.httpclient;
29  
30  import java.io.IOException;
31  import java.lang.ref.WeakReference;
32  import java.net.InetAddress;
33  import java.net.Socket;
34  import java.net.UnknownHostException;
35  
36  import junit.framework.Test;
37  import junit.framework.TestSuite;
38  
39  import org.apache.commons.httpclient.methods.GetMethod;
40  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
41  import org.apache.commons.httpclient.params.HttpConnectionParams;
42  import org.apache.commons.httpclient.protocol.Protocol;
43  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
44  import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
45  import org.apache.commons.httpclient.server.SimpleRequest;
46  import org.apache.commons.httpclient.server.SimpleResponse;
47  
48  /***
49   * Unit tests for {@link HttpConnectionManager}.
50   *
51   * @author Marc A. Saegesser
52   * @version $Id: TestHttpConnectionManager.java 312494 2005-10-09 19:53:32Z olegk $
53   */
54  public class TestHttpConnectionManager extends HttpClientTestBase {
55  
56      // ------------------------------------------------------------ Constructor
57      public TestHttpConnectionManager(String testName) throws IOException {
58          super(testName);
59      }
60  
61      // ------------------------------------------------------------------- Main
62      public static void main(String args[]) {
63          String[] testCaseName = { TestHttpConnectionManager.class.getName() };
64          junit.textui.TestRunner.main(testCaseName);
65      }
66  
67      // ------------------------------------------------------- TestCase Methods
68  
69      public static Test suite() {
70          return new TestSuite(TestHttpConnectionManager.class);
71      }
72  
73  
74      // ----------------------------------------------------------- Test Methods
75  
76      /***
77       * Test that the ConnectMethod correctly releases connections when
78       * CONNECT fails.
79       */
80      public void testConnectMethodFailureRelease() throws Exception {
81          
82          MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
83          mgr.getParams().setIntParameter(
84              HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
85          client.setHttpConnectionManager(mgr);
86          this.server.setHttpService(new RejectConnectService());
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(server.getLocalAddress(), server.getLocalPort());
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         this.server.setHttpService(new EchoService());
194 
195         MultiThreadedHttpConnectionManager mthcm = new MultiThreadedHttpConnectionManager();
196         client.setHttpConnectionManager(mthcm);
197         WeakReference wr = new WeakReference(mthcm);
198 
199         GetMethod method = new GetMethod("/");
200         client.executeMethod(method);
201         method.releaseConnection();
202 
203         mthcm = null;
204         client = null;
205         method = null;
206         
207         System.gc();
208 
209         // this sleep appears to be necessary in order to give the JVM
210         // time to clean up the miscellaneous pointers to the connection manager
211         try {
212             Thread.sleep(1000);
213         } catch (InterruptedException e) {
214             fail("shouldn't be interrupted.");
215         }
216 
217         Object connectionManager = wr.get();
218         assertNull("connectionManager should be null", connectionManager);
219     }    
220     
221     public void testWriteRequestReleaseConnection() {
222 
223         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
224         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
225 
226         client.setHttpConnectionManager(connectionManager);
227         
228         GetMethod get = new GetMethod("/") {
229             protected boolean writeRequestBody(HttpState state, HttpConnection conn)
230                 throws IOException, HttpException {
231                 throw new IOException("Oh no!!");
232             }
233         };
234         
235         try {
236             client.executeMethod(get);
237             fail("An exception should have occurred.");
238         } catch (HttpException e) {
239             e.printStackTrace();
240             fail("HttpException should not have occurred: " + e);
241         } catch (IOException e) {
242             // expected
243         }
244         
245         try {
246             connectionManager.getConnectionWithTimeout(client.getHostConfiguration(), 1);
247         } catch (ConnectTimeoutException e) {
248             e.printStackTrace();
249             fail("Connection was not released: " + e);
250         }
251         
252     }
253     
254     public void testReleaseConnection() {
255 
256         this.server.setHttpService(new EchoService());
257 
258         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
259         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
260 
261         client.setHttpConnectionManager(connectionManager);
262         // we shouldn't have to wait if a connection is available
263         client.getParams().setConnectionManagerTimeout(1);
264 
265         GetMethod getMethod = new GetMethod("/");
266 
267         try {
268             client.executeMethod(getMethod);
269         } catch (Exception e) {
270             fail("error reading from server: " + e);
271         }
272 
273         try {
274             // this should fail quickly since the connection has not been released
275             client.executeMethod(getMethod);
276             fail("a httpConnection should not be available");
277         } catch (ConnectTimeoutException e) {            
278         } catch (HttpException e) {
279             fail("error reading from server; " + e);
280         } catch (IOException e) {
281             e.printStackTrace();
282             fail("error reading from server; " + e);
283         }
284 
285         // this should release the connection
286         getMethod.releaseConnection();
287 
288         getMethod = new GetMethod("/");
289 
290         try {
291             // this should fail quickly if the connection has not been released
292             client.executeMethod(getMethod);
293         } catch (HttpException e) {
294             fail("httpConnection does not appear to have been released: " + e);
295         } catch (IOException e) {
296             fail("error reading from server; " + e);
297         }
298 
299     }
300 
301     /***
302      * Makes sure that a connection gets released after the content of the body
303      * is read.
304      */
305     public void testResponseAutoRelease() throws Exception  {
306 
307         this.server.setHttpService(new EchoService());
308 
309         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
310         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
311 
312         client.setHttpConnectionManager(connectionManager);
313         // we shouldn't have to wait if a connection is available
314         client.getParams().setConnectionManagerTimeout( 1 );
315 
316         GetMethod getMethod = new GetMethod("/");
317 
318         try {
319             client.executeMethod(getMethod);
320         } catch (Exception e) {
321             fail("error reading from server: " + e);
322         }
323         
324         // this should release the connection
325         getMethod.getResponseBody();
326 
327         getMethod = new GetMethod("/");
328 
329         try {
330             // this should fail quickly if the connection has not been released
331             client.executeMethod(getMethod);
332         } catch (HttpException e) {
333             fail("httpConnection does not appear to have been released: " + e);
334         } catch (IOException e) {
335             fail("error reading from server; " + e);
336         }
337 
338     }
339     
340     /***
341      * Tests the MultiThreadedHttpConnectionManager's ability to reclaim unused 
342      * connections.
343      */
344     public void testConnectionReclaiming() {
345         
346         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
347         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
348         connectionManager.getParams().setMaxTotalConnections(1);
349 
350         HostConfiguration host1 = new HostConfiguration();
351         host1.setHost("host1", -1, "http");
352 
353         HostConfiguration host2 = new HostConfiguration();
354         host2.setHost("host2", -1, "http");
355 
356         HttpConnection connection = connectionManager.getConnection(host1);
357         // now release this connection
358         connection.releaseConnection();
359         connection = null;
360         
361         try {
362             // the connection from host1 should be reclaimed
363             connection = connectionManager.getConnectionWithTimeout(host2, 100);
364         } catch (ConnectTimeoutException e) {
365             e.printStackTrace();
366             fail("a httpConnection should have been available: " + e);
367         }        
368     }
369     
370     /***
371      * Tests that {@link MultiThreadedHttpConnectionManager#shutdownAll()} closes all resources
372      * and makes all connection mangers unusable.
373      */
374     public void testShutdownAll() {
375 
376         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
377         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
378         connectionManager.getParams().setMaxTotalConnections(1);
379 
380         HostConfiguration host1 = new HostConfiguration();
381         host1.setHost("host1", -1, "http");
382 
383         // hold on to the only connection
384         HttpConnection connection = connectionManager.getConnection(host1);
385 
386         // wait for a connection on another thread
387         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
388         getConn.start();
389         
390         MultiThreadedHttpConnectionManager.shutdownAll();
391         
392         // now release this connection, this should close the connection, but have no other effect
393         connection.releaseConnection();
394         connection = null;
395         
396         try {
397             getConn.join();
398         } catch (InterruptedException e) {
399             e.printStackTrace();
400         }
401         
402         // this thread should have caught an exception without getting a connection
403         assertNull("Not connection should have been checked out", getConn.getConnection());
404         assertNotNull("There should have been an exception", getConn.getException());
405         
406         try {
407             connectionManager.getConnection(host1);
408             fail("An exception should have occurred");
409         } catch (Exception e) {
410             // this is expected
411         }
412     }
413         
414     /***
415      * Tests that {@link MultiThreadedHttpConnectionManager#shutdown()} closes all resources
416      * and makes the connection manger unusable.
417      */
418     public void testShutdown() {
419 
420         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
421         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
422         connectionManager.getParams().setMaxTotalConnections(1);
423 
424         HostConfiguration host1 = new HostConfiguration();
425         host1.setHost("host1", -1, "http");
426 
427         // hold on to the only connection
428         HttpConnection connection = connectionManager.getConnection(host1);
429 
430         // wait for a connection on another thread
431         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
432         getConn.start();
433         
434         connectionManager.shutdown();
435         
436         // now release this connection, this should close the connection, but have no other effect
437         connection.releaseConnection();
438         connection = null;
439         
440         try {
441             getConn.join();
442         } catch (InterruptedException e) {
443             e.printStackTrace();
444         }
445         
446         // this thread should have caught an exception without getting a connection
447         assertNull("Not connection should have been checked out", getConn.getConnection());
448         assertNotNull("There should have been an exception", getConn.getException());
449         
450         try {
451             connectionManager.getConnection(host1);
452             fail("An exception should have occurred");
453         } catch (Exception e) {
454             // this is expected
455         }
456     }
457     
458     /***
459      * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number 
460      * of connections.
461      */    
462     public void testMaxConnections() {
463         
464         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
465         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
466         connectionManager.getParams().setMaxTotalConnections(2);
467 
468         HostConfiguration host1 = new HostConfiguration();
469         host1.setHost("host1", -1, "http");
470 
471         HostConfiguration host2 = new HostConfiguration();
472         host2.setHost("host2", -1, "http");
473 
474         HttpConnection connection1 = connectionManager.getConnection(host1);
475         HttpConnection connection2 = connectionManager.getConnection(host2);
476     
477         try {
478             // this should fail quickly since the connection has not been released
479             connectionManager.getConnectionWithTimeout(host2, 100);
480             fail("ConnectionPoolTimeoutException should not be available");
481         } catch (ConnectionPoolTimeoutException e) {
482             // this should throw an exception
483         }
484         
485         // release one of the connections
486         connection2.releaseConnection();
487         connection2 = null;
488         
489         try {
490             // there should be a connection available now
491             connection2 = connectionManager.getConnectionWithTimeout(host2, 100);
492         } catch (ConnectionPoolTimeoutException e) {
493             e.printStackTrace();
494             fail("a httpConnection should have been available: " + e);
495         }
496     }    
497 
498     /***
499      * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number 
500      * of connections per host.
501      */    
502     public void testMaxConnectionsPerHost() throws Exception {
503         
504         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
505         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
506         connectionManager.getParams().setMaxTotalConnections(100);
507 
508         HostConfiguration host1 = new HostConfiguration();
509         host1.setHost("host1", -1, "http");
510 
511         HostConfiguration host2 = new HostConfiguration();
512         host2.setHost("host2", -1, "http");
513 
514         HostConfiguration host3 = new HostConfiguration();
515         host3.setHost("host3", -1, "http");
516 
517         connectionManager.getParams().setMaxConnectionsPerHost(host1, 3);
518         connectionManager.getParams().setMaxConnectionsPerHost(host2, 2);
519 
520         // Host1
521         HttpConnection connection1 = connectionManager.getConnectionWithTimeout(host1, 1000);
522         HttpConnection connection2 = connectionManager.getConnectionWithTimeout(host1, 1000);
523         HttpConnection connection3 = connectionManager.getConnectionWithTimeout(host1, 1000);
524         try {
525             // this should fail quickly since the connection has not been released
526             connectionManager.getConnectionWithTimeout(host1, 100);
527             fail("ConnectionPoolTimeoutException should not be available");
528         } catch (ConnectionPoolTimeoutException e) {
529             // expected
530         }
531         
532         // Host2
533         connection1 = connectionManager.getConnectionWithTimeout(host2, 1000);
534         connection2 = connectionManager.getConnectionWithTimeout(host2, 1000);
535         try {
536             // this should fail quickly since the connection has not been released
537             connectionManager.getConnectionWithTimeout(host2, 100);
538             fail("ConnectionPoolTimeoutException should not be available");
539         } catch (ConnectionPoolTimeoutException e) {
540             // expected
541         }
542 
543         // Host3 (should use the default per host value)
544         connection1 = connectionManager.getConnectionWithTimeout(host3, 1000);
545         try {
546             // this should fail quickly since the connection has not been released
547             connectionManager.getConnectionWithTimeout(host3, 100);
548             fail("ConnectionPoolTimeoutException should not be available");
549         } catch (ConnectionPoolTimeoutException e) {
550             // expected
551         }
552     }    
553 
554     public void testHostReusePreference() {
555         
556         final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
557         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
558         connectionManager.getParams().setMaxTotalConnections(1);
559 
560         final HostConfiguration host1 = new HostConfiguration();
561         host1.setHost("host1", -1, "http");
562 
563         final HostConfiguration host2 = new HostConfiguration();
564         host2.setHost("host2", -1, "http");
565 
566         HttpConnection connection = connectionManager.getConnection(host1);
567 
568         GetConnectionThread getHost1 = new GetConnectionThread(host1, connectionManager, 200);
569         GetConnectionThread getHost2 = new GetConnectionThread(host2, connectionManager, 200);
570         
571         getHost2.start();
572         getHost1.start();
573         
574         // give the threads some time to startup
575         try {
576             Thread.sleep(100);
577         } catch (InterruptedException e1) {
578             e1.printStackTrace();
579         }
580             
581         // after the connection to host1 is released it should be given to getHost1
582         connection.releaseConnection();
583         connection = null;
584 
585         try {
586             getHost1.join();
587             getHost2.join();
588         } catch (InterruptedException e) {
589             e.printStackTrace();
590         }
591 
592         assertNotSame(
593             "Connection should have been given to someone", 
594             getHost1.getConnection(),
595             getHost2.getConnection()
596         );        
597         assertNotNull("Connection should have been given to host1", getHost1.getConnection());
598         assertNull("Connection should NOT have been given to host2", getHost2.getConnection());
599         
600     } 
601     
602     public void testMaxConnectionsPerServer() {
603      
604         this.server.setHttpService(new EchoService());
605 
606         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
607         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
608 
609         client.setHttpConnectionManager(connectionManager);
610         // we shouldn't have to wait if a connection is available
611         client.getParams().setConnectionManagerTimeout( 1 );
612 
613         GetMethod getMethod = new GetMethod("/");
614 
615         try {
616             client.executeMethod(getMethod);
617         } catch (Exception e) {
618             fail("error reading from server: " + e);
619         }
620 
621         GetMethod getMethod2 = new GetMethod("/");
622 
623         try {
624             // this should fail quickly since the connection has not been released
625             client.executeMethod(getMethod2);
626             fail("a httpConnection should not be available");
627         } catch (ConnectTimeoutException e) {
628         } catch (HttpException e) {
629             fail("error reading from server; " + e);
630         } catch (IOException e) {
631             fail("error reading from server; " + e);
632         }
633                 
634     }
635     
636     public void testDeleteClosedConnections() {
637         
638         MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
639         
640         HttpConnection conn = manager.getConnection(client.getHostConfiguration());
641         
642         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
643         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 1);
644         
645         conn.close();
646         conn.releaseConnection();
647 
648         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
649         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 1);
650 
651         manager.deleteClosedConnections();
652         
653         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 0);
654         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 0);
655     }
656     
657     public void testReclaimUnusedConnection() {
658 
659         this.server.setHttpService(new EchoService());
660 
661         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
662         connectionManager.getParams().setIntParameter(
663             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
664 
665         client.setHttpConnectionManager(connectionManager);
666         // we shouldn't have to wait if a connection is available
667         client.getParams().setConnectionManagerTimeout( 30000 );
668 
669         GetMethod getMethod = new GetMethod("/");
670 
671         try {
672             client.executeMethod(getMethod);
673         } catch (Exception e) {
674             fail("error reading from server: " + e);
675         }
676 
677         getMethod = new GetMethod("/");
678         
679         Runtime.getRuntime().gc();
680 
681         try {
682             // we didn't explicitly release the connection, but it should be 
683             // reclaimed by the garbage collector, we hope:)
684             client.executeMethod(getMethod);
685         } catch (HttpException e) {
686             fail("httpConnection does not appear to have been reclaimed by the GC: " + e);
687         } catch (IOException e) {
688             fail("error reading from server; " + e);
689         }
690 
691     }
692     
693     public void testGetFromMultipleThreads() {
694         
695         this.server.setHttpService(new EchoService());
696 
697         client.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
698         ExecuteMethodThread[] threads = new ExecuteMethodThread[10];
699         
700         for (int i = 0; i < threads.length; i++) {
701             GetMethod method = new GetMethod("/");
702             method.setFollowRedirects(true);
703             
704             threads[i] = new ExecuteMethodThread(method, client);
705             threads[i].start();
706         }
707         
708         for (int i = 0; i < threads.length; i++) {
709             try {
710                 // wait until this thread finishes. we'll give it 10 seconds,
711                 // but it shouldn't take that long
712                 threads[i].join(10000);
713             } catch (InterruptedException e) {
714             }
715             // make sure an exception did not occur
716             Exception e = threads[i].getException();
717             if (e != null) {
718                 fail("An error occured in the get: " + e);
719             }
720             // we should have a 200 status
721             assertEquals(threads[i].getMethod().getStatusCode(), HttpStatus.SC_OK);
722         }
723     }
724 
725     public void testTimeout() {
726         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
727         mgr.getParams().setDefaultMaxConnectionsPerHost(2);
728         
729         try{
730             HostConfiguration hostConfig = new HostConfiguration();
731             hostConfig.setHost("www.nosuchserver.com", 80, "http");
732             
733             HttpConnection conn1 = mgr.getConnection(hostConfig);
734             HttpConnection conn2 = mgr.getConnection(hostConfig);
735             
736             HttpConnection conn3 = mgr.getConnectionWithTimeout(hostConfig, 1000);
737             fail("Expected an HttpException.");
738             
739         }catch(ConnectTimeoutException e){
740             //Expected result
741         }
742     }
743     
744     static class FakeSecureProtocolSocketFactory implements SecureProtocolSocketFactory {
745         
746         public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
747             throws IOException, UnknownHostException {
748             throw new IllegalStateException("createSocket() should never have been called.");
749         }
750         
751         public Socket createSocket(String host, int port)
752             throws IOException, UnknownHostException {
753             throw new IllegalStateException("createSocket() should never have been called.");
754         }
755         
756         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
757             throws IOException, UnknownHostException {
758             throw new IllegalStateException("createSocket() should never have been called.");
759         }
760         
761         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, 
762             HttpConnectionParams params)
763             throws IOException, UnknownHostException {
764             throw new IllegalStateException("createSocket() should never have been called.");
765         }
766     }
767     
768     static class RejectConnectService extends EchoService {
769 		public boolean process(SimpleRequest request, SimpleResponse response)
770 				throws IOException {
771             if (request.getRequestLine().getMethod().equalsIgnoreCase("CONNECT")) {
772                 response.setStatusLine(request.getRequestLine().getHttpVersion(), HttpStatus.SC_METHOD_NOT_ALLOWED);
773                 response.setHeader(new Header("Connection", "close"));
774                 return true;
775             } else {
776                 return super.process(request, response);
777             }
778 		}
779     }
780     
781     static class GetConnectionThread extends Thread {
782         
783         private HostConfiguration hostConfiguration;
784         private MultiThreadedHttpConnectionManager connectionManager;
785         private HttpConnection connection;
786         private long timeout;
787         private Exception exception;
788         
789         public GetConnectionThread(
790             HostConfiguration hostConfiguration, 
791             MultiThreadedHttpConnectionManager connectionManager,
792             long timeout
793         ) {
794             this.hostConfiguration = hostConfiguration;
795             this.connectionManager = connectionManager; 
796             this.timeout = timeout;
797         }
798         
799         public void run() {
800             try {
801                 connection = connectionManager.getConnectionWithTimeout(hostConfiguration, timeout);
802             } catch (Exception e) {
803                 this.exception = e;
804             }            
805         }
806         
807         public Exception getException() {
808             return exception;
809         }
810         
811         public HttpConnection getConnection() {
812             return connection;
813         }
814 
815     }
816     
817 }
818