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