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.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.HeaderElements;
36 import org.apache.hc.core5.http.HttpEntity;
37 import org.apache.hc.core5.http.HttpHeaders;
38 import org.apache.hc.core5.http.HttpResponse;
39 import org.apache.hc.core5.http.Method;
40 import org.apache.hc.core5.http.io.HttpClientConnection;
41 import org.apache.hc.core5.http.io.HttpResponseInformationCallback;
42 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
43 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
44 import org.apache.hc.core5.http.protocol.HttpCoreContext;
45 import org.apache.hc.core5.http.protocol.HttpProcessor;
46 import org.apache.hc.core5.util.Timeout;
47 import org.junit.Assert;
48 import org.junit.Test;
49 import org.mockito.ArgumentCaptor;
50 import org.mockito.ArgumentMatchers;
51 import org.mockito.Mockito;
52
53 public class TestHttpRequestExecutor {
54
55 @Test
56 public void testInvalidInput() throws Exception {
57 final HttpCoreContext context = HttpCoreContext.create();
58 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
59 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
60 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
61 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
62 try {
63 final HttpRequestExecutor executor = new HttpRequestExecutor();
64 executor.execute(null, conn, context);
65 Assert.fail("NullPointerException expected");
66 } catch (final NullPointerException expected) {
67 }
68 try {
69 final HttpRequestExecutor executor = new HttpRequestExecutor();
70 executor.execute(request, null, context);
71 Assert.fail("NullPointerException expected");
72 } catch (final NullPointerException expected) {
73 }
74 try {
75 final HttpRequestExecutor executor = new HttpRequestExecutor();
76 executor.execute(request, conn, null);
77 Assert.fail("NullPointerException expected");
78 } catch (final NullPointerException expected) {
79 }
80
81 try {
82 final HttpRequestExecutor executor = new HttpRequestExecutor();
83 executor.preProcess(null, httprocessor, context);
84 Assert.fail("NullPointerException expected");
85 } catch (final NullPointerException expected) {
86 }
87 try {
88 final HttpRequestExecutor executor = new HttpRequestExecutor();
89 executor.preProcess(request, null, context);
90 Assert.fail("NullPointerException expected");
91 } catch (final NullPointerException expected) {
92 }
93 try {
94 final HttpRequestExecutor executor = new HttpRequestExecutor();
95 executor.preProcess(request, httprocessor, null);
96 Assert.fail("NullPointerException expected");
97 } catch (final NullPointerException expected) {
98 }
99
100 try {
101 final HttpRequestExecutor executor = new HttpRequestExecutor();
102 executor.postProcess(null, httprocessor, context);
103 Assert.fail("NullPointerException expected");
104 } catch (final NullPointerException expected) {
105 }
106 try {
107 final HttpRequestExecutor executor = new HttpRequestExecutor();
108 executor.postProcess(response, null, context);
109 Assert.fail("NullPointerException expected");
110 } catch (final NullPointerException expected) {
111 }
112 try {
113 final HttpRequestExecutor executor = new HttpRequestExecutor();
114 executor.postProcess(response, httprocessor, null);
115 Assert.fail("NullPointerException expected");
116 } catch (final NullPointerException expected) {
117 }
118 }
119
120 @Test
121 public void testBasicExecution() throws Exception {
122 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
123 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
124 final HttpRequestExecutor executor = new HttpRequestExecutor();
125
126 final HttpCoreContext context = HttpCoreContext.create();
127 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
128
129 executor.preProcess(request, httprocessor, context);
130 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
131
132 Mockito.when(conn.receiveResponseHeader()).thenReturn(
133 new BasicClassicHttpResponse(200, "OK"));
134
135 final ClassicHttpResponse response = executor.execute(request, conn, context);
136 Mockito.verify(conn).sendRequestHeader(request);
137 Mockito.verify(conn).flush();
138 Mockito.verify(conn).receiveResponseHeader();
139 Mockito.verify(conn).receiveResponseEntity(response);
140
141 executor.postProcess(response, httprocessor, context);
142 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
143
144 Assert.assertSame(request, context.getRequest());
145 Assert.assertSame(response, context.getResponse());
146 }
147
148 @Test
149 public void testExecutionSkipIntermediateResponses() throws Exception {
150 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
151 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
152 final HttpRequestExecutor executor = new HttpRequestExecutor();
153
154 final HttpCoreContext context = HttpCoreContext.create();
155 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
156
157 executor.preProcess(request, httprocessor, context);
158 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
159
160 Mockito.when(conn.receiveResponseHeader()).thenReturn(
161 new BasicClassicHttpResponse(100, "Continue"),
162 new BasicClassicHttpResponse(110, "Huh?"),
163 new BasicClassicHttpResponse(111, "Huh?"),
164 new BasicClassicHttpResponse(200, "OK"));
165
166 final HttpResponseInformationCallback callback = Mockito.mock(HttpResponseInformationCallback.class);
167
168 final ClassicHttpResponse response = executor.execute(request, conn, callback, context);
169 Mockito.verify(conn).sendRequestHeader(request);
170 Mockito.verify(conn).flush();
171 Mockito.verify(conn, Mockito.times(4)).receiveResponseHeader();
172 Mockito.verify(conn, Mockito.times(1)).receiveResponseEntity(response);
173
174 final ArgumentCaptor<HttpResponse> responseCaptor = ArgumentCaptor.forClass(HttpResponse.class);
175 Mockito.verify(callback, Mockito.times(2)).execute(responseCaptor.capture(), ArgumentMatchers.eq(conn), ArgumentMatchers.eq(context));
176 final List<HttpResponse> infos = responseCaptor.getAllValues();
177 Assert.assertNotNull(infos);
178 Assert.assertEquals(2, infos.size());
179 final HttpResponse info1 = infos.get(0);
180 Assert.assertNotNull(info1);
181 Assert.assertEquals(110, info1.getCode());
182 final HttpResponse info2 = infos.get(1);
183 Assert.assertNotNull(info2);
184 Assert.assertEquals(111, info2.getCode());
185
186 executor.postProcess(response, httprocessor, context);
187 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
188
189 Assert.assertSame(request, context.getRequest());
190 Assert.assertSame(response, context.getResponse());
191 }
192
193 @Test
194 public void testExecutionNoResponseBody() throws Exception {
195 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
196 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
197 final HttpRequestExecutor executor = new HttpRequestExecutor();
198
199 final HttpCoreContext context = HttpCoreContext.create();
200 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
201
202 executor.preProcess(request, httprocessor, context);
203 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
204
205 Mockito.when(conn.receiveResponseHeader()).thenReturn(
206 new BasicClassicHttpResponse(204, "OK"));
207
208 final ClassicHttpResponse response = executor.execute(request, conn, context);
209 Mockito.verify(conn).sendRequestHeader(request);
210 Mockito.verify(conn).flush();
211 Mockito.verify(conn).receiveResponseHeader();
212 Mockito.verify(conn, Mockito.never()).receiveResponseEntity(response);
213
214 executor.postProcess(response, httprocessor, context);
215 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
216 }
217
218 @Test
219 public void testExecutionHead() throws Exception {
220 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
221 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
222 final HttpRequestExecutor executor = new HttpRequestExecutor();
223
224 final HttpCoreContext context = HttpCoreContext.create();
225 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.HEAD, "/");
226
227 executor.preProcess(request, httprocessor, context);
228 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
229
230 Mockito.when(conn.receiveResponseHeader()).thenReturn(
231 new BasicClassicHttpResponse(200, "OK"));
232
233 final ClassicHttpResponse response = executor.execute(request, conn, context);
234 Mockito.verify(conn).sendRequestHeader(request);
235 Mockito.verify(conn).flush();
236 Mockito.verify(conn).receiveResponseHeader();
237 Mockito.verify(conn, Mockito.never()).receiveResponseEntity(response);
238
239 executor.postProcess(response, httprocessor, context);
240 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
241 }
242
243 @Test
244 public void testExecutionEntityEnclosingRequest() throws Exception {
245 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
246 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
247 final HttpRequestExecutor executor = new HttpRequestExecutor();
248
249 final HttpCoreContext context = HttpCoreContext.create();
250 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
251 final HttpEntity entity = Mockito.mock(HttpEntity.class);
252 request.setEntity(entity);
253
254 executor.preProcess(request, httprocessor, context);
255 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
256
257 Mockito.when(conn.receiveResponseHeader()).thenReturn(
258 new BasicClassicHttpResponse(200, "OK"));
259
260 final ClassicHttpResponse response = executor.execute(request, conn, context);
261 Mockito.verify(conn).sendRequestHeader(request);
262 Mockito.verify(conn).sendRequestEntity(request);
263 Mockito.verify(conn).flush();
264 Mockito.verify(conn).receiveResponseHeader();
265 Mockito.verify(conn).receiveResponseEntity(response);
266
267 executor.postProcess(response, httprocessor, context);
268 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
269 }
270
271 @Test
272 public void testExecutionEntityEnclosingRequestWithExpectContinueSuccess() throws Exception {
273 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
274 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
275 final HttpRequestExecutor executor = new HttpRequestExecutor();
276
277 final HttpCoreContext context = HttpCoreContext.create();
278 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
279 request.addHeader(HttpHeaders.EXPECT, HeaderElements.CONTINUE);
280 final HttpEntity entity = Mockito.mock(HttpEntity.class);
281 request.setEntity(entity);
282
283 executor.preProcess(request, httprocessor, context);
284 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
285
286 Mockito.when(conn.receiveResponseHeader()).thenReturn(
287 new BasicClassicHttpResponse(100, "Continue"),
288 new BasicClassicHttpResponse(200, "OK"));
289 Mockito.when(conn.isDataAvailable(ArgumentMatchers.any(Timeout.class))).thenReturn(Boolean.TRUE);
290
291 final ClassicHttpResponse response = executor.execute(request, conn, context);
292 Mockito.verify(conn).sendRequestHeader(request);
293 Mockito.verify(conn).sendRequestEntity(request);
294 Mockito.verify(conn, Mockito.times(2)).flush();
295 Mockito.verify(conn).isDataAvailable(Timeout.ofMilliseconds(3000));
296 Mockito.verify(conn, Mockito.times(2)).receiveResponseHeader();
297 Mockito.verify(conn).receiveResponseEntity(response);
298
299 executor.postProcess(response, httprocessor, context);
300 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
301 }
302
303 @Test
304 public void testExecutionEntityEnclosingRequestWithExpectContinueFailure() throws Exception {
305 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
306 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
307 final HttpRequestExecutor executor = new HttpRequestExecutor();
308
309 final HttpCoreContext context = HttpCoreContext.create();
310 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
311 request.addHeader(HttpHeaders.EXPECT, HeaderElements.CONTINUE);
312 final HttpEntity entity = Mockito.mock(HttpEntity.class);
313 request.setEntity(entity);
314
315 executor.preProcess(request, httprocessor, context);
316 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
317
318 Mockito.when(conn.receiveResponseHeader()).thenReturn(
319 new BasicClassicHttpResponse(402, "OK"));
320 Mockito.when(conn.isDataAvailable(ArgumentMatchers.any(Timeout.class))).thenReturn(Boolean.TRUE);
321
322 final ClassicHttpResponse response = executor.execute(request, conn, context);
323 Mockito.verify(conn).sendRequestHeader(request);
324 Mockito.verify(conn, Mockito.never()).sendRequestEntity(request);
325 Mockito.verify(conn).terminateRequest(request);
326 Mockito.verify(conn, Mockito.times(2)).flush();
327 Mockito.verify(conn).isDataAvailable(Timeout.ofMilliseconds(3000));
328 Mockito.verify(conn).receiveResponseHeader();
329 Mockito.verify(conn).receiveResponseEntity(response);
330
331 executor.postProcess(response, httprocessor, context);
332 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
333 }
334
335 @Test
336 public void testExecutionEntityEnclosingRequestWithExpectContinueMultiple1xxResponses() throws Exception {
337 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
338 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
339 final HttpRequestExecutor executor = new HttpRequestExecutor();
340
341 final HttpCoreContext context = HttpCoreContext.create();
342 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
343 request.addHeader(HttpHeaders.EXPECT, HeaderElements.CONTINUE);
344 final HttpEntity entity = Mockito.mock(HttpEntity.class);
345 request.setEntity(entity);
346
347 executor.preProcess(request, httprocessor, context);
348 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
349
350 Mockito.when(conn.receiveResponseHeader()).thenReturn(
351 new BasicClassicHttpResponse(110, "Huh?"),
352 new BasicClassicHttpResponse(100, "Continue"),
353 new BasicClassicHttpResponse(111, "Huh?"),
354 new BasicClassicHttpResponse(200, "OK"));
355 Mockito.when(conn.isDataAvailable(ArgumentMatchers.any(Timeout.class))).thenReturn(Boolean.TRUE);
356
357 final HttpResponseInformationCallback callback = Mockito.mock(HttpResponseInformationCallback.class);
358
359 final ClassicHttpResponse response = executor.execute(request, conn, callback, context);
360 Mockito.verify(conn).sendRequestHeader(request);
361 Mockito.verify(conn).sendRequestEntity(request);
362 Mockito.verify(conn, Mockito.times(2)).flush();
363 Mockito.verify(conn, Mockito.times(2)).isDataAvailable(Timeout.ofMilliseconds(3000));
364 Mockito.verify(conn, Mockito.times(4)).receiveResponseHeader();
365 Mockito.verify(conn).receiveResponseEntity(response);
366
367 final ArgumentCaptor<HttpResponse> responseCaptor = ArgumentCaptor.forClass(HttpResponse.class);
368 Mockito.verify(callback, Mockito.times(2)).execute(responseCaptor.capture(), ArgumentMatchers.eq(conn), ArgumentMatchers.eq(context));
369 final List<HttpResponse> infos = responseCaptor.getAllValues();
370 Assert.assertNotNull(infos);
371 Assert.assertEquals(2, infos.size());
372 final HttpResponse info1 = infos.get(0);
373 Assert.assertNotNull(info1);
374 Assert.assertEquals(110, info1.getCode());
375 final HttpResponse info2 = infos.get(1);
376 Assert.assertNotNull(info2);
377 Assert.assertEquals(111, info2.getCode());
378
379 executor.postProcess(response, httprocessor, context);
380 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
381 }
382
383 @Test
384 public void testExecutionEntityEnclosingRequestWithExpectContinueNoResponse() throws Exception {
385 final HttpProcessor httprocessor = Mockito.mock(HttpProcessor.class);
386 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
387 final HttpRequestExecutor executor = new HttpRequestExecutor();
388
389 final HttpCoreContext context = HttpCoreContext.create();
390 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.POST, "/");
391 request.addHeader(HttpHeaders.EXPECT, HeaderElements.CONTINUE);
392 final HttpEntity entity = Mockito.mock(HttpEntity.class);
393 request.setEntity(entity);
394
395 executor.preProcess(request, httprocessor, context);
396 Mockito.verify(httprocessor).process(request, request.getEntity(), context);
397
398 Mockito.when(conn.receiveResponseHeader()).thenReturn(
399 new BasicClassicHttpResponse(200, "OK"));
400 Mockito.when(conn.isDataAvailable(ArgumentMatchers.any(Timeout.class))).thenReturn(Boolean.FALSE);
401
402 final ClassicHttpResponse response = executor.execute(request, conn, context);
403 Mockito.verify(conn).sendRequestHeader(request);
404 Mockito.verify(conn).sendRequestEntity(request);
405 Mockito.verify(conn, Mockito.times(2)).flush();
406 Mockito.verify(conn).isDataAvailable(Timeout.ofMilliseconds(3000));
407 Mockito.verify(conn).receiveResponseHeader();
408 Mockito.verify(conn).receiveResponseEntity(response);
409
410 executor.postProcess(response, httprocessor, context);
411 Mockito.verify(httprocessor).process(response, response.getEntity(), context);
412 }
413
414 @Test
415 public void testExecutionIOException() throws Exception {
416 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
417 final HttpRequestExecutor executor = new HttpRequestExecutor();
418
419 final HttpCoreContext context = HttpCoreContext.create();
420 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
421
422 Mockito.doThrow(new IOException("Oopsie")).when(conn).sendRequestHeader(request);
423 try {
424 executor.execute(request, conn, context);
425 Assert.fail("IOException should have been thrown");
426 } catch (final IOException ex) {
427 Mockito.verify(conn).close();
428 }
429 }
430
431 @Test
432 public void testExecutionRuntimeException() throws Exception {
433 final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
434 final HttpRequestExecutor executor = new HttpRequestExecutor();
435
436 final HttpCoreContext context = HttpCoreContext.create();
437 final ClassicHttpRequest request = new BasicClassicHttpRequest(Method.GET, "/");
438
439 Mockito.doThrow(new RuntimeException("Oopsie")).when(conn).receiveResponseHeader();
440 try {
441 executor.execute(request, conn, context);
442 Assert.fail("IOException should have been thrown");
443 } catch (final RuntimeException ex) {
444 Mockito.verify(conn).close();
445 }
446 }
447
448 }