1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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 import org.apache.commons.httpclient.server.SimpleRequest;
49 import org.apache.commons.httpclient.server.SimpleResponse;
50
51 /***
52 * Unit tests for {@link HttpConnectionManager}.
53 *
54 * @author Marc A. Saegesser
55 * @version $Id: TestHttpConnectionManager.java 179178 2005-05-31 01:09:19Z mbecke $
56 */
57 public class TestHttpConnectionManager extends HttpClientTestBase {
58
59
60 public TestHttpConnectionManager(String testName) throws IOException {
61 super(testName);
62 }
63
64
65 public static void main(String args[]) {
66 String[] testCaseName = { TestHttpConnectionManager.class.getName() };
67 junit.textui.TestRunner.main(testCaseName);
68 }
69
70
71
72 public static Test suite() {
73 return new TestSuite(TestHttpConnectionManager.class);
74 }
75
76
77
78
79 /***
80 * Test that the ConnectMethod correctly releases connections when
81 * CONNECT fails.
82 */
83 public void testConnectMethodFailureRelease() throws Exception {
84
85 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
86 mgr.getParams().setIntParameter(
87 HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
88 client.setHttpConnectionManager(mgr);
89 this.server.setHttpService(new RejectConnectService());
90
91
92
93
94 client.getHostConfiguration().setProxy(server.getLocalAddress(), server.getLocalPort());
95
96
97 client.getHostConfiguration().setHost(
98 "notARealHost",
99 1234,
100 new Protocol(
101 "https",
102 (ProtocolSocketFactory)new FakeSecureProtocolSocketFactory(),
103 443)
104 );
105
106 GetMethod get = new GetMethod("/");
107 try {
108 assertTrue(client.executeMethod(get) != 200);
109 } catch (IOException e) {
110 e.printStackTrace();
111 fail("Error executing connect: " + e);
112 }
113
114
115 try {
116 get.releaseConnection();
117 mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
118 } catch (ConnectTimeoutException e1) {
119 fail("Connection should have been available.");
120 }
121
122 get = new GetMethod("/");
123
124 try {
125 assertTrue(client.executeMethod(get) != 200);
126 } catch (IOException e) {
127 e.printStackTrace();
128 fail("Error executing connect: " + e);
129 }
130
131
132 try {
133 get.getResponseBodyAsString();
134 mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
135 } catch (ConnectTimeoutException e1) {
136 fail("Connection should have been available.");
137 }
138
139 get = new GetMethod("/");
140
141 try {
142 assertTrue(client.executeMethod(get) != 200);
143 } catch (IOException e) {
144 e.printStackTrace();
145 fail("Error executing connect: " + e);
146 }
147
148
149 try {
150 get.getResponseBodyAsStream().close();
151 mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
152 } catch (ConnectTimeoutException e) {
153 fail("Connection should have been available.");
154 } catch (IOException e) {
155 e.printStackTrace();
156 fail("Close connection failed: " + e);
157 }
158 }
159
160 public void testGetConnection() {
161 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
162
163 HostConfiguration hostConfiguration = new HostConfiguration();
164 hostConfiguration.setHost("www.nosuchserver.com", 80, "http");
165
166
167 HttpConnection conn = mgr.getConnection(hostConfiguration);
168
169 assertEquals("Host", "www.nosuchserver.com", conn.getHost());
170 assertEquals("Port", 80, conn.getPort());
171
172 mgr.releaseConnection(conn);
173
174
175 hostConfiguration.setHost("www.nosuchserver.com", -1, "https");
176 conn = mgr.getConnection(hostConfiguration);
177
178 assertEquals("Host", "www.nosuchserver.com", conn.getHost());
179 assertEquals("Port", 443, conn.getPort());
180
181 mgr.releaseConnection(conn);
182
183
184 hostConfiguration.setHost("www.nowhere.org", 8080, "http");
185 conn = mgr.getConnection(hostConfiguration);
186
187 assertEquals("Host", "www.nowhere.org", conn.getHost());
188 assertEquals("Port", 8080, conn.getPort());
189
190 mgr.releaseConnection(conn);
191
192 }
193
194 public void testDroppedThread() throws Exception {
195
196 this.server.setHttpService(new EchoService());
197
198 MultiThreadedHttpConnectionManager mthcm = new MultiThreadedHttpConnectionManager();
199 client.setHttpConnectionManager(mthcm);
200 WeakReference wr = new WeakReference(mthcm);
201
202 GetMethod method = new GetMethod("/");
203 client.executeMethod(method);
204 method.releaseConnection();
205
206 mthcm = null;
207 client = null;
208 method = null;
209
210 System.gc();
211
212
213
214 try {
215 Thread.sleep(1000);
216 } catch (InterruptedException e) {
217 fail("shouldn't be interrupted.");
218 }
219
220 Object connectionManager = wr.get();
221 assertNull("connectionManager should be null", connectionManager);
222 }
223
224 public void testWriteRequestReleaseConnection() {
225
226 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
227 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
228
229 client.setHttpConnectionManager(connectionManager);
230
231 GetMethod get = new GetMethod("/") {
232 protected boolean writeRequestBody(HttpState state, HttpConnection conn)
233 throws IOException, HttpException {
234 throw new IOException("Oh no!!");
235 }
236 };
237
238 try {
239 client.executeMethod(get);
240 fail("An exception should have occurred.");
241 } catch (HttpException e) {
242 e.printStackTrace();
243 fail("HttpException should not have occurred: " + e);
244 } catch (IOException e) {
245
246 }
247
248 try {
249 connectionManager.getConnectionWithTimeout(client.getHostConfiguration(), 1);
250 } catch (ConnectTimeoutException e) {
251 e.printStackTrace();
252 fail("Connection was not released: " + e);
253 }
254
255 }
256
257 public void testReleaseConnection() {
258
259 this.server.setHttpService(new EchoService());
260
261 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
262 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
263
264 client.setHttpConnectionManager(connectionManager);
265
266 client.getParams().setConnectionManagerTimeout(1);
267
268 GetMethod getMethod = new GetMethod("/");
269
270 try {
271 client.executeMethod(getMethod);
272 } catch (Exception e) {
273 fail("error reading from server: " + e);
274 }
275
276 try {
277
278 client.executeMethod(getMethod);
279 fail("a httpConnection should not be available");
280 } catch (ConnectTimeoutException e) {
281 } catch (HttpException e) {
282 fail("error reading from server; " + e);
283 } catch (IOException e) {
284 e.printStackTrace();
285 fail("error reading from server; " + e);
286 }
287
288
289 getMethod.releaseConnection();
290
291 getMethod = new GetMethod("/");
292
293 try {
294
295 client.executeMethod(getMethod);
296 } catch (HttpException e) {
297 fail("httpConnection does not appear to have been released: " + e);
298 } catch (IOException e) {
299 fail("error reading from server; " + e);
300 }
301
302 }
303
304 /***
305 * Makes sure that a connection gets released after the content of the body
306 * is read.
307 */
308 public void testResponseAutoRelease() throws Exception {
309
310 this.server.setHttpService(new EchoService());
311
312 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
313 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
314
315 client.setHttpConnectionManager(connectionManager);
316
317 client.getParams().setConnectionManagerTimeout( 1 );
318
319 GetMethod getMethod = new GetMethod("/");
320
321 try {
322 client.executeMethod(getMethod);
323 } catch (Exception e) {
324 fail("error reading from server: " + e);
325 }
326
327
328 getMethod.getResponseBody();
329
330 getMethod = new GetMethod("/");
331
332 try {
333
334 client.executeMethod(getMethod);
335 } catch (HttpException e) {
336 fail("httpConnection does not appear to have been released: " + e);
337 } catch (IOException e) {
338 fail("error reading from server; " + e);
339 }
340
341 }
342
343 /***
344 * Tests the MultiThreadedHttpConnectionManager's ability to reclaim unused
345 * connections.
346 */
347 public void testConnectionReclaiming() {
348
349 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
350 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
351 connectionManager.getParams().setMaxTotalConnections(1);
352
353 HostConfiguration host1 = new HostConfiguration();
354 host1.setHost("host1", -1, "http");
355
356 HostConfiguration host2 = new HostConfiguration();
357 host2.setHost("host2", -1, "http");
358
359 HttpConnection connection = connectionManager.getConnection(host1);
360
361 connection.releaseConnection();
362 connection = null;
363
364 try {
365
366 connection = connectionManager.getConnectionWithTimeout(host2, 100);
367 } catch (ConnectTimeoutException e) {
368 e.printStackTrace();
369 fail("a httpConnection should have been available: " + e);
370 }
371 }
372
373 /***
374 * Tests that {@link MultiThreadedHttpConnectionManager#shutdownAll()} closes all resources
375 * and makes all connection mangers unusable.
376 */
377 public void testShutdownAll() {
378
379 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
380 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
381 connectionManager.getParams().setMaxTotalConnections(1);
382
383 HostConfiguration host1 = new HostConfiguration();
384 host1.setHost("host1", -1, "http");
385
386
387 HttpConnection connection = connectionManager.getConnection(host1);
388
389
390 GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
391 getConn.start();
392
393 MultiThreadedHttpConnectionManager.shutdownAll();
394
395
396 connection.releaseConnection();
397 connection = null;
398
399 try {
400 getConn.join();
401 } catch (InterruptedException e) {
402 e.printStackTrace();
403 }
404
405
406 assertNull("Not connection should have been checked out", getConn.getConnection());
407 assertNotNull("There should have been an exception", getConn.getException());
408
409 try {
410 connectionManager.getConnection(host1);
411 fail("An exception should have occurred");
412 } catch (Exception e) {
413
414 }
415 }
416
417 /***
418 * Tests that {@link MultiThreadedHttpConnectionManager#shutdown()} closes all resources
419 * and makes the connection manger unusable.
420 */
421 public void testShutdown() {
422
423 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
424 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
425 connectionManager.getParams().setMaxTotalConnections(1);
426
427 HostConfiguration host1 = new HostConfiguration();
428 host1.setHost("host1", -1, "http");
429
430
431 HttpConnection connection = connectionManager.getConnection(host1);
432
433
434 GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
435 getConn.start();
436
437 connectionManager.shutdown();
438
439
440 connection.releaseConnection();
441 connection = null;
442
443 try {
444 getConn.join();
445 } catch (InterruptedException e) {
446 e.printStackTrace();
447 }
448
449
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
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().setDefaultMaxConnectionsPerHost(1);
469 connectionManager.getParams().setMaxTotalConnections(2);
470
471 HostConfiguration host1 = new HostConfiguration();
472 host1.setHost("host1", -1, "http");
473
474 HostConfiguration host2 = new HostConfiguration();
475 host2.setHost("host2", -1, "http");
476
477 HttpConnection connection1 = connectionManager.getConnection(host1);
478 HttpConnection connection2 = connectionManager.getConnection(host2);
479
480 try {
481
482 connectionManager.getConnectionWithTimeout(host2, 100);
483 fail("a httpConnection should not be available");
484 } catch (ConnectTimeoutException e) {
485
486 }
487
488
489 connection2.releaseConnection();
490 connection2 = null;
491
492 try {
493
494 connection2 = connectionManager.getConnectionWithTimeout(host2, 100);
495 } catch (ConnectTimeoutException e) {
496 e.printStackTrace();
497 fail("a httpConnection should have been available: " + e);
498 }
499 }
500
501 public void testHostReusePreference() {
502
503 final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
504 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
505 connectionManager.getParams().setMaxTotalConnections(1);
506
507 final HostConfiguration host1 = new HostConfiguration();
508 host1.setHost("host1", -1, "http");
509
510 final HostConfiguration host2 = new HostConfiguration();
511 host2.setHost("host2", -1, "http");
512
513 HttpConnection connection = connectionManager.getConnection(host1);
514
515 GetConnectionThread getHost1 = new GetConnectionThread(host1, connectionManager, 200);
516 GetConnectionThread getHost2 = new GetConnectionThread(host2, connectionManager, 200);
517
518 getHost2.start();
519 getHost1.start();
520
521
522 try {
523 Thread.sleep(100);
524 } catch (InterruptedException e1) {
525 e1.printStackTrace();
526 }
527
528
529 connection.releaseConnection();
530 connection = null;
531
532 try {
533 getHost1.join();
534 getHost2.join();
535 } catch (InterruptedException e) {
536 e.printStackTrace();
537 }
538
539 assertNotSame(
540 "Connection should have been given to someone",
541 getHost1.getConnection(),
542 getHost2.getConnection()
543 );
544 assertNotNull("Connection should have been given to host1", getHost1.getConnection());
545 assertNull("Connection should NOT have been given to host2", getHost2.getConnection());
546
547 }
548
549 public void testMaxConnectionsPerServer() {
550
551 this.server.setHttpService(new EchoService());
552
553 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
554 connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
555
556 client.setHttpConnectionManager(connectionManager);
557
558 client.getParams().setConnectionManagerTimeout( 1 );
559
560 GetMethod getMethod = new GetMethod("/");
561
562 try {
563 client.executeMethod(getMethod);
564 } catch (Exception e) {
565 fail("error reading from server: " + e);
566 }
567
568 GetMethod getMethod2 = new GetMethod("/");
569
570 try {
571
572 client.executeMethod(getMethod2);
573 fail("a httpConnection should not be available");
574 } catch (ConnectTimeoutException e) {
575 } catch (HttpException e) {
576 fail("error reading from server; " + e);
577 } catch (IOException e) {
578 fail("error reading from server; " + e);
579 }
580
581 }
582
583 public void testDeleteClosedConnections() {
584
585 MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
586
587 HttpConnection conn = manager.getConnection(client.getHostConfiguration());
588
589 assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
590 assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 1);
591
592 conn.close();
593 conn.releaseConnection();
594
595 assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
596 assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 1);
597
598 manager.deleteClosedConnections();
599
600 assertEquals("connectionsInPool", manager.getConnectionsInPool(), 0);
601 assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 0);
602 }
603
604 public void testReclaimUnusedConnection() {
605
606 this.server.setHttpService(new EchoService());
607
608 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
609 connectionManager.getParams().setIntParameter(
610 HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
611
612 client.setHttpConnectionManager(connectionManager);
613
614 client.getParams().setConnectionManagerTimeout( 30000 );
615
616 GetMethod getMethod = new GetMethod("/");
617
618 try {
619 client.executeMethod(getMethod);
620 } catch (Exception e) {
621 fail("error reading from server: " + e);
622 }
623
624 getMethod = new GetMethod("/");
625
626 Runtime.getRuntime().gc();
627
628 try {
629
630
631 client.executeMethod(getMethod);
632 } catch (HttpException e) {
633 fail("httpConnection does not appear to have been reclaimed by the GC: " + e);
634 } catch (IOException e) {
635 fail("error reading from server; " + e);
636 }
637
638 }
639
640 public void testGetFromMultipleThreads() {
641
642 this.server.setHttpService(new EchoService());
643
644 client.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
645 ExecuteMethodThread[] threads = new ExecuteMethodThread[10];
646
647 for (int i = 0; i < threads.length; i++) {
648 GetMethod method = new GetMethod("/");
649 method.setFollowRedirects(true);
650
651 threads[i] = new ExecuteMethodThread(method, client);
652 threads[i].start();
653 }
654
655 for (int i = 0; i < threads.length; i++) {
656 try {
657
658
659 threads[i].join(10000);
660 } catch (InterruptedException e) {
661 }
662
663 Exception e = threads[i].getException();
664 if (e != null) {
665 fail("An error occured in the get: " + e);
666 }
667
668 assertEquals(threads[i].getMethod().getStatusCode(), HttpStatus.SC_OK);
669 }
670 }
671
672 public void testTimeout() {
673 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
674 mgr.getParams().setDefaultMaxConnectionsPerHost(2);
675
676 try{
677 HostConfiguration hostConfig = new HostConfiguration();
678 hostConfig.setHost("www.nosuchserver.com", 80, "http");
679
680 HttpConnection conn1 = mgr.getConnection(hostConfig);
681 HttpConnection conn2 = mgr.getConnection(hostConfig);
682
683 HttpConnection conn3 = mgr.getConnectionWithTimeout(hostConfig, 1000);
684 fail("Expected an HttpException.");
685
686 }catch(ConnectTimeoutException e){
687
688 }
689 }
690
691 static class FakeSecureProtocolSocketFactory implements SecureProtocolSocketFactory {
692
693 public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
694 throws IOException, UnknownHostException {
695 throw new IllegalStateException("createSocket() should never have been called.");
696 }
697
698 public Socket createSocket(String host, int port)
699 throws IOException, UnknownHostException {
700 throw new IllegalStateException("createSocket() should never have been called.");
701 }
702
703 public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
704 throws IOException, UnknownHostException {
705 throw new IllegalStateException("createSocket() should never have been called.");
706 }
707
708 public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort,
709 HttpConnectionParams params)
710 throws IOException, UnknownHostException {
711 throw new IllegalStateException("createSocket() should never have been called.");
712 }
713 }
714
715 static class RejectConnectService extends EchoService {
716 public boolean process(SimpleRequest request, SimpleResponse response)
717 throws IOException {
718 if (request.getRequestLine().getMethod().equalsIgnoreCase("CONNECT")) {
719 response.setStatusLine(request.getRequestLine().getHttpVersion(), HttpStatus.SC_METHOD_NOT_ALLOWED);
720 response.setHeader(new Header("Connection", "close"));
721 return true;
722 } else {
723 return super.process(request, response);
724 }
725 }
726 }
727
728 static class GetConnectionThread extends Thread {
729
730 private HostConfiguration hostConfiguration;
731 private MultiThreadedHttpConnectionManager connectionManager;
732 private HttpConnection connection;
733 private long timeout;
734 private Exception exception;
735
736 public GetConnectionThread(
737 HostConfiguration hostConfiguration,
738 MultiThreadedHttpConnectionManager connectionManager,
739 long timeout
740 ) {
741 this.hostConfiguration = hostConfiguration;
742 this.connectionManager = connectionManager;
743 this.timeout = timeout;
744 }
745
746 public void run() {
747 try {
748 connection = connectionManager.getConnectionWithTimeout(hostConfiguration, timeout);
749 } catch (Exception e) {
750 this.exception = e;
751 }
752 }
753
754 public Exception getException() {
755 return exception;
756 }
757
758 public HttpConnection getConnection() {
759 return connection;
760 }
761
762 }
763
764 }
765