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  package org.apache.hc.client5.testing.sync;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.IOException;
31  import java.net.URI;
32  
33  import org.apache.hc.client5.http.HttpRequestRetryStrategy;
34  import org.apache.hc.client5.http.classic.methods.HttpGet;
35  import org.apache.hc.client5.http.classic.methods.HttpPost;
36  import org.apache.hc.client5.http.protocol.HttpClientContext;
37  import org.apache.hc.client5.http.protocol.RedirectLocations;
38  import org.apache.hc.client5.http.utils.URIUtils;
39  import org.apache.hc.core5.http.ClassicHttpRequest;
40  import org.apache.hc.core5.http.ClassicHttpResponse;
41  import org.apache.hc.core5.http.EntityDetails;
42  import org.apache.hc.core5.http.Header;
43  import org.apache.hc.core5.http.HttpException;
44  import org.apache.hc.core5.http.HttpHost;
45  import org.apache.hc.core5.http.HttpRequest;
46  import org.apache.hc.core5.http.HttpRequestInterceptor;
47  import org.apache.hc.core5.http.HttpResponse;
48  import org.apache.hc.core5.http.HttpStatus;
49  import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
50  import org.apache.hc.core5.http.io.HttpClientConnection;
51  import org.apache.hc.core5.http.io.HttpRequestHandler;
52  import org.apache.hc.core5.http.io.entity.EntityUtils;
53  import org.apache.hc.core5.http.io.entity.InputStreamEntity;
54  import org.apache.hc.core5.http.io.entity.StringEntity;
55  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
56  import org.apache.hc.core5.http.protocol.HttpContext;
57  import org.apache.hc.core5.net.URIBuilder;
58  import org.apache.hc.core5.util.TimeValue;
59  import org.junit.Assert;
60  import org.junit.Test;
61  
62  /**
63   * Client protocol handling tests.
64   */
65  public class TestClientRequestExecution extends LocalServerTestBase {
66  
67      private static class SimpleService implements HttpRequestHandler {
68  
69          public SimpleService() {
70              super();
71          }
72  
73          @Override
74          public void handle(
75                  final ClassicHttpRequest request,
76                  final ClassicHttpResponse response,
77                  final HttpContext context) throws HttpException, IOException {
78              response.setCode(HttpStatus.SC_OK);
79              final StringEntity entity = new StringEntity("Whatever");
80              response.setEntity(entity);
81          }
82      }
83  
84      private static class FaultyHttpRequestExecutor extends HttpRequestExecutor {
85  
86          private static final String MARKER = "marker";
87  
88          private final String failureMsg;
89  
90          public FaultyHttpRequestExecutor(final String failureMsg) {
91              this.failureMsg = failureMsg;
92          }
93  
94          @Override
95          public ClassicHttpResponse execute(
96                  final ClassicHttpRequest request,
97                  final HttpClientConnection conn,
98                  final HttpContext context) throws IOException, HttpException {
99  
100             final ClassicHttpResponse response = super.execute(request, conn, context);
101             final Object marker = context.getAttribute(MARKER);
102             if (marker == null) {
103                 context.setAttribute(MARKER, Boolean.TRUE);
104                 throw new IOException(failureMsg);
105             }
106             return response;
107         }
108 
109     }
110 
111     @Test
112     public void testAutoGeneratedHeaders() throws Exception {
113         this.server.registerHandler("*", new SimpleService());
114 
115         final HttpRequestInterceptor interceptor = new HttpRequestInterceptor() {
116 
117             @Override
118             public void process(
119                     final HttpRequest request,
120                     final EntityDetails entityDetails,
121                     final HttpContext context) throws HttpException, IOException {
122                 request.addHeader("my-header", "stuff");
123             }
124 
125         };
126 
127         final HttpRequestRetryStrategy requestRetryStrategy = new HttpRequestRetryStrategy() {
128 
129             @Override
130             public boolean retryRequest(
131                     final HttpRequest request,
132                     final IOException exception,
133                     final int executionCount,
134                     final HttpContext context) {
135                 return true;
136             }
137 
138             @Override
139             public boolean retryRequest(
140                     final HttpResponse response,
141                     final int executionCount,
142                     final HttpContext context) {
143                 return false;
144             }
145 
146             @Override
147             public TimeValue getRetryInterval(
148                     final HttpResponse response,
149                     final int executionCount,
150                     final HttpContext context) {
151                 return TimeValue.ofSeconds(1L);
152             }
153 
154         };
155 
156         this.httpclient = this.clientBuilder
157             .addRequestInterceptorFirst(interceptor)
158             .setRequestExecutor(new FaultyHttpRequestExecutor("Oppsie"))
159             .setRetryStrategy(requestRetryStrategy)
160             .build();
161 
162         final HttpHost target = start();
163 
164         final HttpClientContext context = HttpClientContext.create();
165 
166         final HttpGet httpget = new HttpGet("/");
167 
168         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
169         EntityUtils.consume(response.getEntity());
170 
171         final HttpRequest reqWrapper = context.getRequest();
172 
173         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
174 
175         final Header[] myheaders = reqWrapper.getHeaders("my-header");
176         Assert.assertNotNull(myheaders);
177         Assert.assertEquals(1, myheaders.length);
178     }
179 
180     @Test(expected=IOException.class)
181     public void testNonRepeatableEntity() throws Exception {
182         this.server.registerHandler("*", new SimpleService());
183 
184         final HttpRequestRetryStrategy requestRetryStrategy = new HttpRequestRetryStrategy() {
185 
186             @Override
187             public boolean retryRequest(
188                     final HttpRequest request,
189                     final IOException exception,
190                     final int executionCount,
191                     final HttpContext context) {
192                 return true;
193             }
194 
195             @Override
196             public boolean retryRequest(
197                     final HttpResponse response,
198                     final int executionCount,
199                     final HttpContext context) {
200                 return false;
201             }
202 
203             @Override
204             public TimeValue getRetryInterval(
205                     final HttpResponse response,
206                     final int executionCount,
207                     final HttpContext context) {
208                 return TimeValue.ofSeconds(1L);
209             }
210 
211         };
212 
213         this.httpclient = this.clientBuilder
214             .setRequestExecutor(new FaultyHttpRequestExecutor("a message showing that this failed"))
215             .setRetryStrategy(requestRetryStrategy)
216             .build();
217 
218         final HttpHost target = start();
219 
220         final HttpClientContext context = HttpClientContext.create();
221 
222         final HttpPost httppost = new HttpPost("/");
223         httppost.setEntity(new InputStreamEntity(
224                 new ByteArrayInputStream(
225                         new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ),
226                         -1, null));
227         this.httpclient.execute(target, httppost, context);
228     }
229 
230     @Test
231     public void testNonCompliantURI() throws Exception {
232         this.server.registerHandler("*", new SimpleService());
233 
234         final HttpHost target = start();
235 
236         final HttpClientContext context = HttpClientContext.create();
237         final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", "{{|boom|}}");
238         final ClassicHttpResponse response = this.httpclient.execute(target, request, context);
239         EntityUtils.consume(response.getEntity());
240 
241         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
242 
243         final HttpRequest reqWrapper = context.getRequest();
244 
245         Assert.assertEquals("{{|boom|}}", reqWrapper.getRequestUri());
246     }
247 
248     @Test
249     public void testRelativeRequestURIWithFragment() throws Exception {
250         this.server.registerHandler("*", new SimpleService());
251 
252         final HttpHost target = start();
253 
254         final HttpGet httpget = new HttpGet("/stuff#blahblah");
255         final HttpClientContext context = HttpClientContext.create();
256 
257         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
258         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
259         EntityUtils.consume(response.getEntity());
260 
261         final HttpRequest request = context.getRequest();
262         Assert.assertEquals("/stuff", request.getRequestUri());
263     }
264 
265     @Test
266     public void testAbsoluteRequestURIWithFragment() throws Exception {
267         this.server.registerHandler("*", new SimpleService());
268 
269         final HttpHost target = start();
270 
271         final URI uri = new URIBuilder()
272             .setHost(target.getHostName())
273             .setPort(target.getPort())
274             .setScheme(target.getSchemeName())
275             .setPath("/stuff")
276             .setFragment("blahblah")
277             .build();
278 
279         final HttpGet httpget = new HttpGet(uri);
280         final HttpClientContext context = HttpClientContext.create();
281 
282         final ClassicHttpResponse response = this.httpclient.execute(httpget, context);
283         Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
284         EntityUtils.consume(response.getEntity());
285 
286         final HttpRequest request = context.getRequest();
287         Assert.assertEquals("/stuff", request.getRequestUri());
288 
289         final RedirectLocations redirectLocations = context.getRedirectLocations();
290         final URI location = URIUtils.resolve(uri, target, redirectLocations.getAll());
291         Assert.assertEquals(uri, location);
292     }
293 
294 }