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