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