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  package org.apache.hc.core5.http.impl.io;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.ByteArrayOutputStream;
31  import java.io.InputStream;
32  import java.net.Socket;
33  import java.nio.charset.StandardCharsets;
34  
35  import org.apache.hc.core5.http.ClassicHttpRequest;
36  import org.apache.hc.core5.http.ClassicHttpResponse;
37  import org.apache.hc.core5.http.ContentType;
38  import org.apache.hc.core5.http.HttpEntity;
39  import org.apache.hc.core5.http.LengthRequiredException;
40  import org.apache.hc.core5.http.NotImplementedException;
41  import org.apache.hc.core5.http.config.H1Config;
42  import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
43  import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
44  import org.apache.hc.core5.http.io.entity.StringEntity;
45  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
46  import org.junit.Assert;
47  import org.junit.Before;
48  import org.junit.Test;
49  import org.mockito.Mock;
50  import org.mockito.Mockito;
51  import org.mockito.MockitoAnnotations;
52  
53  public class TestDefaultBHttpClientConnection {
54  
55      @Mock
56      private Socket socket;
57  
58      private DefaultBHttpClientConnection conn;
59  
60      @Before
61      public void setUp() throws Exception {
62          MockitoAnnotations.initMocks(this);
63          conn = new DefaultBHttpClientConnection(H1Config.DEFAULT,
64              null, null,
65              DefaultContentLengthStrategy.INSTANCE,
66              DefaultContentLengthStrategy.INSTANCE,
67              DefaultHttpRequestWriterFactory.INSTANCE,
68              DefaultHttpResponseParserFactory.INSTANCE);
69      }
70  
71      @Test
72      public void testBasics() throws Exception {
73          Assert.assertFalse(conn.isOpen());
74          Assert.assertEquals("[Not bound]", conn.toString());
75      }
76  
77      @Test
78      public void testReadResponseHead() throws Exception {
79          final String s = "HTTP/1.1 200 OK\r\nUser-Agent: test\r\n\r\n";
80          final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
81          Mockito.when(socket.getInputStream()).thenReturn(instream);
82  
83          conn.bind(socket);
84  
85          Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
86  
87          final ClassicHttpResponse response = conn.receiveResponseHeader();
88          Assert.assertNotNull(response);
89          Assert.assertEquals(200, response.getCode());
90          Assert.assertTrue(response.containsHeader("User-Agent"));
91          Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
92      }
93  
94      @Test
95      public void testReadResponseEntityWithContentLength() throws Exception {
96          final String s = "HTTP/1.1 200 OK\r\nServer: test\r\nContent-Length: 3\r\n\r\n123";
97          final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
98          Mockito.when(socket.getInputStream()).thenReturn(instream);
99  
100         conn.bind(socket);
101 
102         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
103 
104         final ClassicHttpResponse response = conn.receiveResponseHeader();
105 
106         Assert.assertNotNull(response);
107         Assert.assertEquals(200, response.getCode());
108         Assert.assertTrue(response.containsHeader("Server"));
109         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
110 
111         conn.receiveResponseEntity(response);
112 
113         final HttpEntity entity = response.getEntity();
114         Assert.assertNotNull(entity);
115         Assert.assertEquals(3, entity.getContentLength());
116         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
117         final InputStream content = entity.getContent();
118         Assert.assertNotNull(content);
119         Assert.assertTrue(content instanceof ContentLengthInputStream);
120     }
121 
122     @Test
123     public void testReadResponseEntityChunkCoded() throws Exception {
124         final String s = "HTTP/1.1 200 OK\r\nServer: test\r\nTransfer-Encoding: " +
125                 "chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n";
126         final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
127         Mockito.when(socket.getInputStream()).thenReturn(instream);
128 
129         conn.bind(socket);
130 
131         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
132 
133         final ClassicHttpResponse response = conn.receiveResponseHeader();
134 
135         Assert.assertNotNull(response);
136         Assert.assertEquals(200, response.getCode());
137         Assert.assertTrue(response.containsHeader("Server"));
138         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
139 
140         conn.receiveResponseEntity(response);
141 
142         final HttpEntity entity = response.getEntity();
143         Assert.assertNotNull(entity);
144         Assert.assertEquals(-1, entity.getContentLength());
145         Assert.assertEquals(true, entity.isChunked());
146         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
147         final InputStream content = entity.getContent();
148         Assert.assertNotNull(content);
149         Assert.assertTrue(content instanceof ChunkedInputStream);
150     }
151 
152     @Test(expected = NotImplementedException.class)
153     public void testReadResponseEntityIdentity() throws Exception {
154         final String s = "HTTP/1.1 200 OK\r\nServer: test\r\nTransfer-Encoding: identity\r\n\r\n123";
155         final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
156         Mockito.when(socket.getInputStream()).thenReturn(instream);
157 
158         conn.bind(socket);
159 
160         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
161 
162         final ClassicHttpResponse response = conn.receiveResponseHeader();
163 
164         Assert.assertNotNull(response);
165         Assert.assertEquals(200, response.getCode());
166         Assert.assertTrue(response.containsHeader("Server"));
167         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
168 
169         conn.receiveResponseEntity(response);
170     }
171 
172     @Test
173     public void testReadResponseNoEntity() throws Exception {
174         final String s = "HTTP/1.1 200 OK\r\nServer: test\r\n\r\n";
175         final ByteArrayInputStream instream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
176         Mockito.when(socket.getInputStream()).thenReturn(instream);
177 
178         conn.bind(socket);
179 
180         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
181 
182         final ClassicHttpResponse response = conn.receiveResponseHeader();
183 
184         Assert.assertNotNull(response);
185         Assert.assertEquals(200, response.getCode());
186         Assert.assertTrue(response.containsHeader("Server"));
187         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
188 
189         conn.receiveResponseEntity(response);
190 
191         final HttpEntity entity = response.getEntity();
192         Assert.assertNull(entity);
193     }
194 
195     @Test
196     public void testWriteRequestHead() throws Exception {
197         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
198         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
199 
200         conn.bind(socket);
201 
202         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
203 
204         final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", "/stuff");
205         request.addHeader("User-Agent", "test");
206 
207         conn.sendRequestHeader(request);
208         conn.flush();
209 
210         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
211         final String s = new String(outstream.toByteArray(), "ASCII");
212         Assert.assertEquals("GET /stuff HTTP/1.1\r\nUser-Agent: test\r\n\r\n", s);
213     }
214 
215     @Test
216     public void testWriteRequestEntityWithContentLength() throws Exception {
217         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
218         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
219 
220         conn.bind(socket);
221 
222         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
223 
224         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
225         request.addHeader("User-Agent", "test");
226         request.addHeader("Content-Length", "3");
227         request.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN));
228 
229         conn.sendRequestHeader(request);
230         conn.sendRequestEntity(request);
231         conn.flush();
232 
233         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
234         final String s = new String(outstream.toByteArray(), "ASCII");
235         Assert.assertEquals("POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 3\r\n\r\n123", s);
236     }
237 
238     @Test
239     public void testWriteRequestEntityChunkCoded() throws Exception {
240         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
241         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
242 
243         conn.bind(socket);
244 
245         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
246 
247         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
248         request.addHeader("User-Agent", "test");
249         request.addHeader("Transfer-Encoding", "chunked");
250         request.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN));
251 
252         conn.sendRequestHeader(request);
253         conn.sendRequestEntity(request);
254         conn.flush();
255 
256         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
257         final String s = new String(outstream.toByteArray(), "ASCII");
258         Assert.assertEquals("POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nTransfer-Encoding: " +
259                 "chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n", s);
260     }
261 
262     @Test(expected = LengthRequiredException.class)
263     public void testWriteRequestEntityNoContentLength() throws Exception {
264         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
265         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
266 
267         conn.bind(socket);
268 
269         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
270 
271         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
272         request.addHeader("User-Agent", "test");
273         request.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN));
274 
275         conn.sendRequestHeader(request);
276         conn.sendRequestEntity(request);
277     }
278 
279     @Test
280     public void testWriteRequestNoEntity() throws Exception {
281         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
282         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
283 
284         conn.bind(socket);
285 
286         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
287 
288         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
289         request.addHeader("User-Agent", "test");
290 
291         conn.sendRequestHeader(request);
292         conn.sendRequestEntity(request);
293         conn.flush();
294 
295         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
296         final String s = new String(outstream.toByteArray(), "ASCII");
297         Assert.assertEquals("POST /stuff HTTP/1.1\r\nUser-Agent: test\r\n\r\n", s);
298     }
299 
300     @Test
301     public void testTerminateRequestChunkedEntity() throws Exception {
302         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
303         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
304 
305         conn.bind(socket);
306 
307         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
308 
309         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
310         request.addHeader("User-Agent", "test");
311         request.addHeader("Transfer-Encoding", "chunked");
312         final StringEntity entity = new StringEntity("123", ContentType.TEXT_PLAIN);
313         entity.setChunked(true);
314         request.setEntity(entity);
315 
316         conn.sendRequestHeader(request);
317         conn.terminateRequest(request);
318         conn.flush();
319 
320         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
321         final String s = new String(outstream.toByteArray(), "ASCII");
322         Assert.assertEquals("POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nTransfer-Encoding: " +
323                 "chunked\r\n\r\n0\r\n\r\n", s);
324         Assert.assertTrue(conn.isConsistent());
325     }
326 
327     @Test
328     public void testTerminateRequestContentLengthShort() throws Exception {
329         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
330         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
331 
332         conn.bind(socket);
333 
334         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
335 
336         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
337         request.addHeader("User-Agent", "test");
338         request.addHeader("Content-Length", "3");
339         final StringEntity entity = new StringEntity("123", ContentType.TEXT_PLAIN);
340         entity.setChunked(false);
341         request.setEntity(entity);
342 
343         conn.sendRequestHeader(request);
344         conn.terminateRequest(request);
345         conn.flush();
346 
347         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
348         final String s = new String(outstream.toByteArray(), "ASCII");
349         Assert.assertEquals("POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: " +
350                 "3\r\n\r\n123", s);
351         Assert.assertTrue(conn.isConsistent());
352     }
353 
354     @Test
355     public void testTerminateRequestContentLengthLong() throws Exception {
356         final ByteArrayOutputStream outstream = new ByteArrayOutputStream();
357         Mockito.when(socket.getOutputStream()).thenReturn(outstream);
358 
359         conn.bind(socket);
360 
361         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
362 
363         final ClassicHttpRequest request = new BasicClassicHttpRequest("POST", "/stuff");
364         request.addHeader("User-Agent", "test");
365         request.addHeader("Content-Length", "3000");
366         final ByteArrayEntity entity = new ByteArrayEntity(new byte[3000], ContentType.TEXT_PLAIN);
367         entity.setChunked(false);
368         request.setEntity(entity);
369 
370         conn.sendRequestHeader(request);
371         conn.terminateRequest(request);
372         conn.flush();
373 
374         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
375         final String s = new String(outstream.toByteArray(), "ASCII");
376         Assert.assertEquals("POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: " +
377                 "3000\r\n\r\n", s);
378         Assert.assertFalse(conn.isConsistent());
379     }
380 
381 }