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