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.Method;
40  import org.apache.hc.core5.http.NotImplementedException;
41  import org.apache.hc.core5.http.ProtocolException;
42  import org.apache.hc.core5.http.config.Http1Config;
43  import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
44  import org.apache.hc.core5.http.io.entity.StringEntity;
45  import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
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 TestDefaultBHttpServerConnection {
54  
55      @Mock
56      private Socket socket;
57  
58      private DefaultBHttpServerConnection conn;
59  
60      @Before
61      public void setUp() throws Exception {
62          MockitoAnnotations.initMocks(this);
63          conn = new DefaultBHttpServerConnection("http", Http1Config.DEFAULT,
64              null, null,
65              DefaultContentLengthStrategy.INSTANCE,
66              DefaultContentLengthStrategy.INSTANCE,
67              DefaultHttpRequestParserFactory.INSTANCE,
68              DefaultHttpResponseWriterFactory.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 testReadRequestHead() throws Exception {
79          final String s = "GET / HTTP/1.1\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().getRequestCount());
86  
87          final ClassicHttpRequest request = conn.receiveRequestHeader();
88          Assert.assertNotNull(request);
89          Assert.assertEquals("/", request.getPath());
90          Assert.assertEquals(Method.GET.name(), request.getMethod());
91          Assert.assertTrue(request.containsHeader("User-Agent"));
92          Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
93      }
94  
95      @Test
96      public void testReadRequestEntityWithContentLength() throws Exception {
97          final String s = "POST / HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 3\r\n\r\n123";
98          final ByteArrayInputStream inStream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
99          Mockito.when(socket.getInputStream()).thenReturn(inStream);
100 
101         conn.bind(socket);
102 
103         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
104 
105         final ClassicHttpRequest request = conn.receiveRequestHeader();
106 
107         Assert.assertNotNull(request);
108         Assert.assertEquals("/", request.getPath());
109         Assert.assertEquals(Method.POST.name(), request.getMethod());
110         Assert.assertTrue(request.containsHeader("User-Agent"));
111         Assert.assertNull(request.getEntity());
112         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
113 
114         conn.receiveRequestEntity(request);
115 
116         final HttpEntity entity = request.getEntity();
117         Assert.assertNotNull(entity);
118         Assert.assertEquals(3, entity.getContentLength());
119         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
120         final InputStream content = entity.getContent();
121         Assert.assertNotNull(content);
122         Assert.assertTrue(content instanceof ContentLengthInputStream);
123     }
124 
125     @Test
126     public void testReadRequestEntityChunckCoded() throws Exception {
127         final String s = "POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nTransfer-Encoding: " +
128                 "chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n";
129         final ByteArrayInputStream inStream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
130         Mockito.when(socket.getInputStream()).thenReturn(inStream);
131 
132         conn.bind(socket);
133 
134         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
135 
136         final ClassicHttpRequest request = conn.receiveRequestHeader();
137 
138         Assert.assertNotNull(request);
139         Assert.assertEquals("/stuff", request.getPath());
140         Assert.assertEquals(Method.POST.name(), request.getMethod());
141         Assert.assertTrue(request.containsHeader("User-Agent"));
142         Assert.assertNull(request.getEntity());
143         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
144 
145         conn.receiveRequestEntity(request);
146 
147         final HttpEntity entity = request.getEntity();
148         Assert.assertNotNull(entity);
149         Assert.assertEquals(-1, entity.getContentLength());
150         Assert.assertEquals(true, entity.isChunked());
151         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
152         final InputStream content = entity.getContent();
153         Assert.assertNotNull(content);
154         Assert.assertTrue(content instanceof ChunkedInputStream);
155     }
156 
157     @Test(expected = ProtocolException.class)
158     public void testReadRequestEntityIdentity() throws Exception {
159         final String s = "POST /stuff HTTP/1.1\r\nUser-Agent: test\r\nTransfer-Encoding: " +
160                 "identity\r\n\r\n123";
161         final ByteArrayInputStream inStream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
162         Mockito.when(socket.getInputStream()).thenReturn(inStream);
163 
164         conn.bind(socket);
165 
166         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
167 
168         final ClassicHttpRequest request = conn.receiveRequestHeader();
169 
170         Assert.assertNotNull(request);
171         Assert.assertEquals("/stuff", request.getPath());
172         Assert.assertEquals(Method.POST.name(), request.getMethod());
173         Assert.assertTrue(request.containsHeader("User-Agent"));
174         Assert.assertNull(request.getEntity());
175         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
176 
177         conn.receiveRequestEntity(request);
178     }
179 
180     @Test
181     public void testReadRequestNoEntity() throws Exception {
182         final String s = "POST /stuff HTTP/1.1\r\nUser-Agent: test\r\n\r\n";
183         final ByteArrayInputStream inStream = new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII));
184         Mockito.when(socket.getInputStream()).thenReturn(inStream);
185 
186         conn.bind(socket);
187 
188         Assert.assertEquals(0, conn.getEndpointDetails().getRequestCount());
189 
190         final ClassicHttpRequest request = conn.receiveRequestHeader();
191 
192         Assert.assertNotNull(request);
193         Assert.assertEquals("/stuff", request.getPath());
194         Assert.assertEquals(Method.POST.name(), request.getMethod());
195         Assert.assertTrue(request.containsHeader("User-Agent"));
196         Assert.assertNull(request.getEntity());
197         Assert.assertEquals(1, conn.getEndpointDetails().getRequestCount());
198 
199         conn.receiveRequestEntity(request);
200 
201         final HttpEntity entity = request.getEntity();
202         Assert.assertNull(entity);
203     }
204 
205     @Test
206     public void testWriteResponseHead() throws Exception {
207         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
208         Mockito.when(socket.getOutputStream()).thenReturn(outStream);
209 
210         conn.bind(socket);
211 
212         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
213 
214         final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
215         response.addHeader("User-Agent", "test");
216 
217         conn.sendResponseHeader(response);
218         conn.flush();
219 
220         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
221         final String s = new String(outStream.toByteArray(), StandardCharsets.US_ASCII);
222         Assert.assertEquals("HTTP/1.1 200 OK\r\nUser-Agent: test\r\n\r\n", s);
223     }
224 
225     @Test
226     public void testWriteResponse100Head() throws Exception {
227         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
228         Mockito.when(socket.getOutputStream()).thenReturn(outStream);
229 
230         conn.bind(socket);
231 
232         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
233 
234         final ClassicHttpResponse response = new BasicClassicHttpResponse(100, "Go on");
235 
236         conn.sendResponseHeader(response);
237         conn.flush();
238 
239         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
240         final String s = new String(outStream.toByteArray(), StandardCharsets.US_ASCII);
241         Assert.assertEquals("HTTP/1.1 100 Go on\r\n\r\n", s);
242     }
243 
244     @Test
245     public void testWriteResponseEntityWithContentLength() throws Exception {
246         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
247         Mockito.when(socket.getOutputStream()).thenReturn(outStream);
248 
249         conn.bind(socket);
250 
251         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
252 
253         final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
254         response.addHeader("Server", "test");
255         response.addHeader("Content-Length", "3");
256         response.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN));
257 
258         conn.sendResponseHeader(response);
259         conn.sendResponseEntity(response);
260         conn.flush();
261 
262         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
263         final String s = new String(outStream.toByteArray(), StandardCharsets.US_ASCII);
264         Assert.assertEquals("HTTP/1.1 200 OK\r\nServer: test\r\nContent-Length: 3\r\n\r\n123", s);
265     }
266 
267     @Test
268     public void testWriteResponseEntityChunkCoded() throws Exception {
269         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
270         Mockito.when(socket.getOutputStream()).thenReturn(outStream);
271 
272         conn.bind(socket);
273 
274         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
275 
276         final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
277         response.addHeader("Server", "test");
278         response.addHeader("Transfer-Encoding", "chunked");
279         response.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN));
280 
281         conn.sendResponseHeader(response);
282         conn.sendResponseEntity(response);
283         conn.flush();
284 
285         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
286         final String s = new String(outStream.toByteArray(), StandardCharsets.US_ASCII);
287         Assert.assertEquals("HTTP/1.1 200 OK\r\nServer: test\r\nTransfer-Encoding: " +
288                 "chunked\r\n\r\n3\r\n123\r\n0\r\n\r\n", s);
289     }
290 
291     @Test(expected = NotImplementedException.class)
292     public void testWriteResponseEntityIdentity() throws Exception {
293         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
294         Mockito.when(socket.getOutputStream()).thenReturn(outStream);
295 
296         conn.bind(socket);
297 
298         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
299 
300         final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
301         response.addHeader("Server", "test");
302         response.addHeader("Transfer-Encoding", "identity");
303         response.setEntity(new StringEntity("123", ContentType.TEXT_PLAIN));
304 
305         conn.sendResponseHeader(response);
306         conn.sendResponseEntity(response);
307         conn.flush();
308     }
309 
310     @Test
311     public void testWriteResponseNoEntity() throws Exception {
312         final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
313         Mockito.when(socket.getOutputStream()).thenReturn(outStream);
314 
315         conn.bind(socket);
316 
317         Assert.assertEquals(0, conn.getEndpointDetails().getResponseCount());
318 
319         final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
320         response.addHeader("Server", "test");
321 
322         conn.sendResponseHeader(response);
323         conn.sendResponseEntity(response);
324         conn.flush();
325 
326         Assert.assertEquals(1, conn.getEndpointDetails().getResponseCount());
327         final String s = new String(outStream.toByteArray(), StandardCharsets.US_ASCII);
328         Assert.assertEquals("HTTP/1.1 200 OK\r\nServer: test\r\n\r\n", s);
329     }
330 
331 }