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