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