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.impl.client.integration;
29  
30  import java.io.ByteArrayOutputStream;
31  import java.io.IOException;
32  import java.io.OutputStream;
33  import java.util.concurrent.TimeUnit;
34  
35  import org.apache.http.HttpClientConnection;
36  import org.apache.http.HttpEntity;
37  import org.apache.http.HttpException;
38  import org.apache.http.HttpHost;
39  import org.apache.http.HttpRequest;
40  import org.apache.http.HttpResponse;
41  import org.apache.http.MalformedChunkCodingException;
42  import org.apache.http.client.methods.HttpGet;
43  import org.apache.http.conn.ConnectionPoolTimeoutException;
44  import org.apache.http.conn.ConnectionRequest;
45  import org.apache.http.conn.routing.HttpRoute;
46  import org.apache.http.entity.BasicHttpEntity;
47  import org.apache.http.impl.DefaultBHttpServerConnection;
48  import org.apache.http.localserver.LocalServerTestBase;
49  import org.apache.http.pool.PoolStats;
50  import org.apache.http.protocol.HttpContext;
51  import org.apache.http.protocol.HttpCoreContext;
52  import org.apache.http.protocol.HttpRequestHandler;
53  import org.apache.http.util.EntityUtils;
54  import org.junit.Assert;
55  import org.junit.Test;
56  
57  public class TestConnectionAutoRelease extends LocalServerTestBase {
58  
59      @Test
60      public void testReleaseOnEntityConsumeContent() throws Exception {
61          this.connManager.setDefaultMaxPerRoute(1);
62          this.connManager.setMaxTotal(1);
63  
64          // Zero connections in the pool
65          PoolStats stats = this.connManager.getTotalStats();
66          Assert.assertEquals(0, stats.getAvailable());
67  
68          final HttpHost target = start();
69          // Get some random data
70          final HttpGet httpget = new HttpGet("/random/20000");
71          final HttpResponse response = this.httpclient.execute(target, httpget);
72  
73          ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
74          try {
75              connreq.get(250, TimeUnit.MILLISECONDS);
76              Assert.fail("ConnectionPoolTimeoutException should have been thrown");
77          } catch (final ConnectionPoolTimeoutException expected) {
78          }
79  
80          final HttpEntity e = response.getEntity();
81          Assert.assertNotNull(e);
82          EntityUtils.consume(e);
83  
84          // Expect one connection in the pool
85          stats = this.connManager.getTotalStats();
86          Assert.assertEquals(1, stats.getAvailable());
87  
88          // Make sure one connection is available
89          connreq = this.connManager.requestConnection(new HttpRoute(target), null);
90          final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
91  
92          this.connManager.releaseConnection(conn, null, -1, null);
93      }
94  
95      @Test
96      public void testReleaseOnEntityWriteTo() throws Exception {
97          this.connManager.setDefaultMaxPerRoute(1);
98          this.connManager.setMaxTotal(1);
99  
100         // Zero connections in the pool
101         PoolStats stats = this.connManager.getTotalStats();
102         Assert.assertEquals(0, stats.getAvailable());
103 
104         final HttpHost target = start();
105         // Get some random data
106         final HttpGet httpget = new HttpGet("/random/20000");
107         final HttpResponse response = this.httpclient.execute(target, httpget);
108 
109         ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
110         try {
111             connreq.get(250, TimeUnit.MILLISECONDS);
112             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
113         } catch (final ConnectionPoolTimeoutException expected) {
114         }
115 
116         final HttpEntity e = response.getEntity();
117         Assert.assertNotNull(e);
118         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
119         e.writeTo(outstream);
120 
121         // Expect one connection in the pool
122         stats = this.connManager.getTotalStats();
123         Assert.assertEquals(1, stats.getAvailable());
124 
125         // Make sure one connection is available
126         connreq = this.connManager.requestConnection(new HttpRoute(target), null);
127         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
128 
129         this.connManager.releaseConnection(conn, null, -1, null);
130     }
131 
132     @Test
133     public void testReleaseOnAbort() throws Exception {
134         this.connManager.setDefaultMaxPerRoute(1);
135         this.connManager.setMaxTotal(1);
136 
137         // Zero connections in the pool
138         final PoolStats stats = this.connManager.getTotalStats();
139         Assert.assertEquals(0, stats.getAvailable());
140 
141         final HttpHost target = start();
142 
143         // Get some random data
144         final HttpGet httpget = new HttpGet("/random/20000");
145         final HttpResponse response = this.httpclient.execute(target, httpget);
146 
147         ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
148         try {
149             connreq.get(250, TimeUnit.MILLISECONDS);
150             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
151         } catch (final ConnectionPoolTimeoutException expected) {
152         }
153 
154         final HttpEntity e = response.getEntity();
155         Assert.assertNotNull(e);
156         httpget.abort();
157 
158         // Expect zero connections in the pool
159         Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
160 
161         // Make sure one connection is available
162         connreq = this.connManager.requestConnection(new HttpRoute(target), null);
163         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
164 
165         this.connManager.releaseConnection(conn, null, -1, null);
166     }
167 
168     @Test
169     public void testReleaseOnIOException() throws Exception {
170         this.serverBootstrap.registerHandler("/dropdead", new HttpRequestHandler() {
171 
172             @Override
173             public void handle(
174                     final HttpRequest request,
175                     final HttpResponse response,
176                     final HttpContext context) throws HttpException, IOException {
177                 final BasicHttpEntity entity = new BasicHttpEntity() {
178 
179                     @Override
180                     public void writeTo(
181                             final OutputStream outStream) throws IOException {
182                         final byte[] tmp = new byte[5];
183                         outStream.write(tmp);
184                         outStream.flush();
185 
186                         // do something comletely ugly in order to trigger
187                         // MalformedChunkCodingException
188                         final DefaultBHttpServerConnection conn = (DefaultBHttpServerConnection)
189                                 context.getAttribute(HttpCoreContext.HTTP_CONNECTION);
190                         try {
191                             conn.sendResponseHeader(response);
192                         } catch (final HttpException ignore) {
193                         }
194                     }
195 
196                 };
197                 entity.setChunked(true);
198                 response.setEntity(entity);
199             }
200 
201         });
202 
203         this.connManager.setDefaultMaxPerRoute(1);
204         this.connManager.setMaxTotal(1);
205 
206         // Zero connections in the pool
207         Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
208 
209         final HttpHost target = start();
210 
211         // Get some random data
212         final HttpGet httpget = new HttpGet("/dropdead");
213         final HttpResponse response = this.httpclient.execute(target, httpget);
214 
215         ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
216         try {
217             connreq.get(250, TimeUnit.MILLISECONDS);
218             Assert.fail("ConnectionPoolTimeoutException should have been thrown");
219         } catch (final ConnectionPoolTimeoutException expected) {
220         }
221 
222         final HttpEntity e = response.getEntity();
223         Assert.assertNotNull(e);
224         // Read the content
225         try {
226             EntityUtils.toByteArray(e);
227             Assert.fail("MalformedChunkCodingException should have been thrown");
228         } catch (final MalformedChunkCodingException expected) {
229 
230         }
231 
232         // Expect zero connections in the pool
233         Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
234 
235         // Make sure one connection is available
236         connreq = this.connManager.requestConnection(new HttpRoute(target), null);
237         final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
238 
239         this.connManager.releaseConnection(conn, null, -1, null);
240     }
241 
242 }