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
28 package org.apache.hc.core5.http.impl.io;
29
30 import java.io.InputStream;
31 import java.util.List;
32
33 import org.apache.hc.core5.http.ClassicHttpRequest;
34 import org.apache.hc.core5.http.ClassicHttpResponse;
35 import org.apache.hc.core5.http.ConnectionReuseStrategy;
36 import org.apache.hc.core5.http.HeaderElements;
37 import org.apache.hc.core5.http.HttpHeaders;
38 import org.apache.hc.core5.http.HttpRequestMapper;
39 import org.apache.hc.core5.http.HttpResponseFactory;
40 import org.apache.hc.core5.http.HttpStatus;
41 import org.apache.hc.core5.http.Method;
42 import org.apache.hc.core5.http.MethodNotSupportedException;
43 import org.apache.hc.core5.http.ProtocolException;
44 import org.apache.hc.core5.http.UnsupportedHttpVersionException;
45 import org.apache.hc.core5.http.io.HttpRequestHandler;
46 import org.apache.hc.core5.http.io.HttpServerConnection;
47 import org.apache.hc.core5.http.io.entity.InputStreamEntity;
48 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
49 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
50 import org.apache.hc.core5.http.protocol.HttpCoreContext;
51 import org.apache.hc.core5.http.protocol.HttpProcessor;
52 import org.junit.jupiter.api.Assertions;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Test;
55 import org.mockito.ArgumentCaptor;
56 import org.mockito.ArgumentMatchers;
57 import org.mockito.Mock;
58 import org.mockito.Mockito;
59 import org.mockito.MockitoAnnotations;
60 import org.mockito.Spy;
61
62 public class TestHttpService {
63
64 @Mock
65 private HttpProcessor httprocessor;
66 @Mock
67 private ConnectionReuseStrategy connReuseStrategy;
68 @Spy
69 private final ClassicHttpResponse response = new BasicClassicHttpResponse(HttpStatus.SC_OK);
70 @Mock
71 private HttpResponseFactory<ClassicHttpResponse> responseFactory;
72 @Mock
73 private HttpRequestMapper<HttpRequestHandler> handlerResolver;
74 @Mock
75 private HttpRequestHandler requestHandler;
76 @Mock
77 private HttpServerConnection conn;
78
79 private HttpService httpservice;
80
81 @BeforeEach
82 public void prepareMocks() {
83 MockitoAnnotations.openMocks(this);
84 httpservice = new HttpService(
85 httprocessor,
86 handlerResolver,
87 connReuseStrategy,
88 responseFactory);
89 }
90
91 @Test
92 public void testInvalidInitialization() throws Exception {
93 Assertions.assertThrows(NullPointerException.class, () ->
94 new HttpService(
95 null,
96 handlerResolver,
97 connReuseStrategy,
98 responseFactory));
99 }
100
101 @Test
102 public void testBasicExecution() throws Exception {
103 final HttpCoreContext context = HttpCoreContext.create();
104 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
105 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
106 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
107 Mockito.when(connReuseStrategy.keepAlive(request, response, context)).thenReturn(Boolean.FALSE);
108
109 httpservice.handleRequest(conn, context);
110
111 Assertions.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getCode());
112
113 Assertions.assertSame(request, context.getRequest());
114 Assertions.assertSame(response, context.getResponse());
115
116 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
117 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
118 Mockito.verify(conn).sendResponseHeader(response);
119 Mockito.verify(conn).sendResponseEntity(response);
120 Mockito.verify(conn).flush();
121 Mockito.verify(conn).close();
122 Mockito.verify(response).close();
123 }
124
125 @Test
126 public void testExecutionEntityEnclosingRequest() throws Exception {
127 final HttpCoreContext context = HttpCoreContext.create();
128 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
129 final InputStream inStream = Mockito.mock(InputStream.class);
130 final InputStreamEntity entity = new InputStreamEntity(inStream, -1, null);
131 request.setEntity(entity);
132
133 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
134 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
135 Mockito.when(connReuseStrategy.keepAlive(ArgumentMatchers.eq(request), ArgumentMatchers.argThat(errorResponse -> errorResponse.getCode() == HttpStatus.SC_NOT_IMPLEMENTED), ArgumentMatchers.eq(context))).thenReturn(Boolean.TRUE);
136
137 httpservice.handleRequest(conn, context);
138 final ArgumentCaptor<ClassicHttpResponse> responseCaptor = ArgumentCaptor.forClass(ClassicHttpResponse.class);
139 Mockito.verify(conn).sendResponseHeader(responseCaptor.capture());
140 final ClassicHttpResponse response = responseCaptor.getValue();
141 Assertions.assertNotNull(response);
142
143 Assertions.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getCode());
144
145 Assertions.assertSame(request, context.getRequest());
146
147 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
148 Mockito.verify(inStream).close();
149 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
150 Mockito.verify(conn).sendResponseHeader(response);
151 Mockito.verify(conn).sendResponseEntity(response);
152 Mockito.verify(conn).flush();
153 Mockito.verify(conn, Mockito.never()).close();
154 Mockito.verify(response).close();
155 }
156
157 @Test
158 public void testExecutionEntityEnclosingRequestWithExpectContinue() throws Exception {
159 final HttpCoreContext context = HttpCoreContext.create();
160 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
161 request.addHeader(HttpHeaders.EXPECT, HeaderElements.CONTINUE);
162 final InputStream inStream = Mockito.mock(InputStream.class);
163 final InputStreamEntity entity = new InputStreamEntity(inStream, -1, null);
164 request.setEntity(entity);
165
166 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
167 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
168 Mockito.when(connReuseStrategy.keepAlive(ArgumentMatchers.eq(request), ArgumentMatchers.argThat(errorResponse -> errorResponse.getCode() == HttpStatus.SC_NOT_IMPLEMENTED), ArgumentMatchers.eq(context))).thenReturn(Boolean.TRUE);
169
170 httpservice.handleRequest(conn, context);
171 final ArgumentCaptor<ClassicHttpResponse> responseCaptor = ArgumentCaptor.forClass(ClassicHttpResponse.class);
172 Mockito.verify(conn, Mockito.times(2)).sendResponseHeader(responseCaptor.capture());
173 final List<ClassicHttpResponse> responses = responseCaptor.getAllValues();
174 Assertions.assertNotNull(responses);
175 Assertions.assertEquals(2, responses.size());
176 final ClassicHttpResponse ack = responses.get(0);
177 final ClassicHttpResponse response = responses.get(1);
178
179 Assertions.assertEquals(HttpStatus.SC_CONTINUE, ack.getCode());
180 Assertions.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, response.getCode());
181
182 Assertions.assertSame(request, context.getRequest());
183
184 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
185 Mockito.verify(inStream).close();
186 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
187 Mockito.verify(conn).sendResponseHeader(response);
188 Mockito.verify(conn).sendResponseEntity(response);
189 Mockito.verify(conn, Mockito.times(2)).flush();
190 Mockito.verify(conn, Mockito.never()).close();
191 Mockito.verify(response).close();
192 }
193
194 @Test
195 public void testMethodNotSupported() throws Exception {
196 final HttpCoreContext context = HttpCoreContext.create();
197 final ClassicHttpRequest request = new BasicClassicHttpRequest("whatever", "/");
198
199 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
200 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
201 Mockito.when(handlerResolver.resolve(request, context)).thenReturn(requestHandler);
202 Mockito.doThrow(new MethodNotSupportedException("whatever")).when(
203 requestHandler).handle(request, response, context);
204
205 httpservice.handleRequest(conn, context);
206 final ArgumentCaptor<ClassicHttpResponse> responseCaptor = ArgumentCaptor.forClass(ClassicHttpResponse.class);
207 Mockito.verify(conn).sendResponseHeader(responseCaptor.capture());
208 final ClassicHttpResponse error = responseCaptor.getValue();
209 Assertions.assertNotNull(error);
210
211 Assertions.assertSame(request, context.getRequest());
212
213 Assertions.assertEquals(HttpStatus.SC_NOT_IMPLEMENTED, error.getCode());
214
215 Mockito.verify(httprocessor).process(error, error.getEntity(), context);
216 Mockito.verify(conn).sendResponseHeader(error);
217 Mockito.verify(conn).sendResponseEntity(error);
218 Mockito.verify(conn).close();
219 }
220
221 @Test
222 public void testUnsupportedHttpVersionException() throws Exception {
223 final HttpCoreContext context = HttpCoreContext.create();
224 final ClassicHttpRequest request = new BasicClassicHttpRequest("whatever", "/");
225
226 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
227 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
228 Mockito.when(handlerResolver.resolve(request, context)).thenReturn(requestHandler);
229 Mockito.doThrow(new UnsupportedHttpVersionException()).when(
230 requestHandler).handle(request, response, context);
231
232 httpservice.handleRequest(conn, context);
233 final ArgumentCaptor<ClassicHttpResponse> responseCaptor = ArgumentCaptor.forClass(ClassicHttpResponse.class);
234 Mockito.verify(conn).sendResponseHeader(responseCaptor.capture());
235 final ClassicHttpResponse error = responseCaptor.getValue();
236 Assertions.assertNotNull(error);
237
238 Assertions.assertSame(request, context.getRequest());
239
240 Assertions.assertEquals(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED, error.getCode());
241
242 Mockito.verify(httprocessor).process(error, error.getEntity(), context);
243 Mockito.verify(conn).sendResponseHeader(error);
244 Mockito.verify(conn).sendResponseEntity(error);
245 Mockito.verify(conn).close();
246 }
247
248 @Test
249 public void testProtocolException() throws Exception {
250 final HttpCoreContext context = HttpCoreContext.create();
251 final ClassicHttpRequest request = new BasicClassicHttpRequest("whatever", "/");
252
253 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
254 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
255 Mockito.when(handlerResolver.resolve(request, context)).thenReturn(requestHandler);
256 Mockito.doThrow(new ProtocolException("oh, this world is wrong")).when(
257 requestHandler).handle(request, response, context);
258
259 httpservice.handleRequest(conn, context);
260 final ArgumentCaptor<ClassicHttpResponse> responseCaptor = ArgumentCaptor.forClass(ClassicHttpResponse.class);
261 Mockito.verify(conn).sendResponseHeader(responseCaptor.capture());
262 final ClassicHttpResponse error = responseCaptor.getValue();
263 Assertions.assertNotNull(error);
264
265 Assertions.assertSame(request, context.getRequest());
266
267 Assertions.assertEquals(HttpStatus.SC_BAD_REQUEST, error.getCode());
268
269 Mockito.verify(httprocessor).process(error, error.getEntity(), context);
270 Mockito.verify(conn).sendResponseHeader(error);
271 Mockito.verify(conn).sendResponseEntity(error);
272 Mockito.verify(conn).close();
273 }
274
275 @Test
276 public void testConnectionKeepAlive() throws Exception {
277 final HttpCoreContext context = HttpCoreContext.create();
278 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
279 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
280 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
281 Mockito.when(handlerResolver.resolve(request, context)).thenReturn(requestHandler);
282 Mockito.when(connReuseStrategy.keepAlive(request, response, context)).thenReturn(Boolean.TRUE);
283
284 httpservice.handleRequest(conn, context);
285
286 Assertions.assertEquals(HttpStatus.SC_OK, response.getCode());
287
288 Assertions.assertSame(request, context.getRequest());
289 Assertions.assertSame(response, context.getResponse());
290
291 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
292 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
293 Mockito.verify(conn).sendResponseHeader(response);
294 Mockito.verify(conn).sendResponseEntity(response);
295 Mockito.verify(conn).flush();
296 Mockito.verify(conn, Mockito.never()).close();
297 Mockito.verify(response).close();
298 }
299
300 @Test
301 public void testNoContentResponse() throws Exception {
302 final HttpCoreContext context = HttpCoreContext.create();
303 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
304
305 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
306 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
307 Mockito.when(handlerResolver.resolve(request, context)).thenReturn((request1, response, context1) -> response.setCode(HttpStatus.SC_NO_CONTENT));
308 Mockito.when(connReuseStrategy.keepAlive(request, response, context)).thenReturn(Boolean.TRUE);
309
310 httpservice.handleRequest(conn, context);
311
312 Assertions.assertSame(request, context.getRequest());
313
314 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
315
316 Mockito.verify(conn).sendResponseHeader(response);
317 Mockito.verify(conn, Mockito.never()).sendResponseEntity(ArgumentMatchers.any());
318 Mockito.verify(conn).flush();
319 Mockito.verify(conn, Mockito.never()).close();
320 Mockito.verify(response).close();
321 }
322
323 @Test
324 public void testResponseToHead() throws Exception {
325 final HttpCoreContext context = HttpCoreContext.create();
326 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.HEAD, "/");
327
328 Mockito.when(conn.receiveRequestHeader()).thenReturn(request);
329 Mockito.when(responseFactory.newHttpResponse(200)).thenReturn(response);
330 Mockito.when(handlerResolver.resolve(request, context)).thenReturn(requestHandler);
331 Mockito.when(connReuseStrategy.keepAlive(request, response, context)).thenReturn(Boolean.TRUE);
332
333 httpservice.handleRequest(conn, context);
334
335 Assertions.assertSame(request, context.getRequest());
336
337 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
338 Mockito.verify(requestHandler).handle(request, response, context);
339
340 Mockito.verify(conn).sendResponseHeader(response);
341 Mockito.verify(conn, Mockito.never()).sendResponseEntity(ArgumentMatchers.any());
342 Mockito.verify(conn).flush();
343 Mockito.verify(conn, Mockito.never()).close();
344 Mockito.verify(response).close();
345 }
346
347 }