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.http.fluent;
28  
29  import java.io.File;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.net.URI;
33  import java.net.URISyntaxException;
34  import java.nio.charset.Charset;
35  import java.nio.charset.StandardCharsets;
36  import java.text.SimpleDateFormat;
37  import java.util.ArrayList;
38  import java.util.Arrays;
39  import java.util.Date;
40  import java.util.List;
41  import java.util.Locale;
42  import java.util.TimeZone;
43  
44  import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
45  import org.apache.hc.client5.http.config.Configurable;
46  import org.apache.hc.client5.http.config.RequestConfig;
47  import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
48  import org.apache.hc.client5.http.protocol.HttpClientContext;
49  import org.apache.hc.core5.http.ClassicHttpRequest;
50  import org.apache.hc.core5.http.ClassicHttpResponse;
51  import org.apache.hc.core5.http.ContentType;
52  import org.apache.hc.core5.http.Header;
53  import org.apache.hc.core5.http.HttpEntity;
54  import org.apache.hc.core5.http.HttpHeaders;
55  import org.apache.hc.core5.http.HttpHost;
56  import org.apache.hc.core5.http.HttpVersion;
57  import org.apache.hc.core5.http.Method;
58  import org.apache.hc.core5.http.NameValuePair;
59  import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
60  import org.apache.hc.core5.http.io.entity.FileEntity;
61  import org.apache.hc.core5.http.io.entity.InputStreamEntity;
62  import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
63  import org.apache.hc.core5.net.WWWFormCodec;
64  import org.apache.hc.core5.util.Timeout;
65  
66  /**
67   * HTTP request used by the fluent facade.
68   *
69   * @since 4.2
70   */
71  public class Request {
72  
73      public static final String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
74      public static final Locale DATE_LOCALE = Locale.US;
75      public static final TimeZone TIME_ZONE = TimeZone.getTimeZone("GMT");
76  
77      private final ClassicHttpRequest request;
78      private Boolean useExpectContinue;
79      private Timeout connectTimeout;
80      private Timeout responseTimeout;
81      private HttpHost proxy;
82  
83      private SimpleDateFormat dateFormatter;
84  
85      public static Request create(final Method method, final URI uri) {
86        return new Request(new HttpUriRequestBase(method.name(), uri));
87    }
88  
89      public static Request create(final String methodName, final String uri) {
90          return new Request(new HttpUriRequestBase(methodName, URI.create(uri)));
91      }
92  
93      public static Request create(final String methodName, final URI uri) {
94        return new Request(new HttpUriRequestBase(methodName, uri));
95    }
96  
97      public static Request get(final URI uri) {
98         return new Request(new BasicClassicHttpRequest(Method.GET, uri));
99      }
100 
101     public static Request get(final String uri) {
102         return new Request(new BasicClassicHttpRequest(Method.GET, uri));
103     }
104 
105     public static Request head(final URI uri) {
106         return new Request(new BasicClassicHttpRequest(Method.HEAD, uri));
107     }
108 
109     public static Request head(final String uri) {
110         return new Request(new BasicClassicHttpRequest(Method.HEAD, uri));
111     }
112 
113     public static Request post(final URI uri) {
114         return new Request(new BasicClassicHttpRequest(Method.POST, uri));
115     }
116 
117     public static Request post(final String uri) {
118       return new Request(new BasicClassicHttpRequest(Method.POST, uri));
119     }
120 
121     public static Request patch(final URI uri) {
122       return new Request(new BasicClassicHttpRequest(Method.PATCH, uri));
123     }
124 
125     public static Request patch(final String uri) {
126       return new Request(new BasicClassicHttpRequest(Method.PATCH, uri));
127     }
128 
129     public static Request put(final URI uri) {
130       return new Request(new BasicClassicHttpRequest(Method.PUT, uri));
131     }
132 
133     public static Request put(final String uri) {
134       return new Request(new BasicClassicHttpRequest(Method.PUT, uri));
135     }
136 
137     public static Request trace(final URI uri) {
138       return new Request(new BasicClassicHttpRequest(Method.TRACE, uri));
139     }
140 
141     public static Request trace(final String uri) {
142       return new Request(new BasicClassicHttpRequest(Method.TRACE, uri));
143     }
144 
145     public static Request delete(final URI uri) {
146       return new Request(new BasicClassicHttpRequest(Method.DELETE, uri));
147     }
148 
149     public static Request delete(final String uri) {
150       return new Request(new BasicClassicHttpRequest(Method.DELETE, uri));
151     }
152 
153     public static Request options(final URI uri) {
154       return new Request(new BasicClassicHttpRequest(Method.OPTIONS, uri));
155     }
156 
157     public static Request options(final String uri) {
158       return new Request(new BasicClassicHttpRequest(Method.OPTIONS, uri));
159     }
160 
161     Request(final ClassicHttpRequest request) {
162         super();
163         this.request = request;
164     }
165 
166     ClassicHttpResponse internalExecute(
167             final CloseableHttpClient client,
168             final HttpClientContext localContext) throws IOException {
169         final RequestConfig.Builder builder;
170         if (client instanceof Configurable) {
171             builder = RequestConfig.copy(((Configurable) client).getConfig());
172         } else {
173             builder = RequestConfig.custom();
174         }
175         if (this.useExpectContinue != null) {
176             builder.setExpectContinueEnabled(this.useExpectContinue);
177         }
178         if (this.connectTimeout != null) {
179             builder.setConnectTimeout(this.connectTimeout);
180         }
181         if (this.responseTimeout != null) {
182             builder.setResponseTimeout(this.responseTimeout);
183         }
184         if (this.proxy != null) {
185             builder.setProxy(this.proxy);
186         }
187         final RequestConfig config = builder.build();
188         localContext.setRequestConfig(config);
189         return client.execute(this.request, localContext);
190     }
191 
192     public Response execute() throws IOException {
193         return execute(Executor.CLIENT);
194     }
195 
196     public Response execute(final CloseableHttpClient client) throws IOException {
197         return new Response(internalExecute(client, HttpClientContext.create()));
198     }
199 
200     //// HTTP header operations
201 
202     public Request addHeader(final Header header) {
203         this.request.addHeader(header);
204         return this;
205     }
206 
207     /**
208      * @since 4.3
209      */
210     public Request setHeader(final Header header) {
211         this.request.setHeader(header);
212         return this;
213     }
214 
215     public Request addHeader(final String name, final String value) {
216         this.request.addHeader(name, value);
217         return this;
218     }
219 
220     /**
221      * @since 4.3
222      */
223     public Request setHeader(final String name, final String value) {
224         this.request.setHeader(name, value);
225         return this;
226     }
227 
228     public Request removeHeader(final Header header) {
229         this.request.removeHeader(header);
230         return this;
231     }
232 
233     public Request removeHeaders(final String name) {
234         this.request.removeHeaders(name);
235         return this;
236     }
237 
238     public Request setHeaders(final Header... headers) {
239         this.request.setHeaders(headers);
240         return this;
241     }
242 
243     public Request setCacheControl(final String cacheControl) {
244         this.request.setHeader(HttpHeader.CACHE_CONTROL, cacheControl);
245         return this;
246     }
247 
248     private SimpleDateFormat getDateFormat() {
249         if (this.dateFormatter == null) {
250             this.dateFormatter = new SimpleDateFormat(DATE_FORMAT, DATE_LOCALE);
251             this.dateFormatter.setTimeZone(TIME_ZONE);
252         }
253         return this.dateFormatter;
254     }
255 
256     ClassicHttpRequest getRequest() {
257       return request;
258     }
259 
260     public Request setDate(final Date date) {
261         this.request.setHeader(HttpHeader.DATE, getDateFormat().format(date));
262         return this;
263     }
264 
265     public Request setIfModifiedSince(final Date date) {
266         this.request.setHeader(HttpHeader.IF_MODIFIED_SINCE, getDateFormat().format(date));
267         return this;
268     }
269 
270     public Request setIfUnmodifiedSince(final Date date) {
271         this.request.setHeader(HttpHeader.IF_UNMODIFIED_SINCE, getDateFormat().format(date));
272         return this;
273     }
274 
275     //// HTTP protocol parameter operations
276 
277     public Request version(final HttpVersion version) {
278         this.request.setVersion(version);
279         return this;
280     }
281 
282     public Request useExpectContinue() {
283         this.useExpectContinue = Boolean.TRUE;
284         return this;
285     }
286 
287     public Request userAgent(final String agent) {
288         this.request.setHeader(HttpHeaders.USER_AGENT, agent);
289         return this;
290     }
291 
292     //// HTTP connection parameter operations
293 
294     public Request connectTimeout(final Timeout timeout) {
295         this.connectTimeout = timeout;
296         return this;
297     }
298 
299     public Request responseTimeout(final Timeout timeout) {
300         this.responseTimeout = timeout;
301         return this;
302     }
303 
304     //// HTTP connection route operations
305 
306     public Request viaProxy(final HttpHost proxy) {
307         this.proxy = proxy;
308         return this;
309     }
310 
311     /**
312      * @since 4.4
313      */
314     public Request viaProxy(final String proxy) {
315         try {
316             this.proxy = HttpHost.create(proxy);
317         } catch (final URISyntaxException e) {
318             throw new IllegalArgumentException("Invalid host");
319         }
320         return this;
321     }
322 
323     //// HTTP entity operations
324 
325     public Request body(final HttpEntity entity) {
326         this.request.setEntity(entity);
327         return this;
328     }
329 
330     public Request bodyForm(final Iterable <? extends NameValuePair> formParams, final Charset charset) {
331         final List<NameValuePair> paramList = new ArrayList<>();
332         for (final NameValuePair param : formParams) {
333             paramList.add(param);
334         }
335         final ContentType contentType = charset != null ?
336                 ContentType.APPLICATION_FORM_URLENCODED.withCharset(charset) : ContentType.APPLICATION_FORM_URLENCODED;
337         final String s = WWWFormCodec.format(paramList, contentType.getCharset());
338         return bodyString(s, contentType);
339     }
340 
341     public Request bodyForm(final Iterable <? extends NameValuePair> formParams) {
342         return bodyForm(formParams, StandardCharsets.ISO_8859_1);
343     }
344 
345     public Request bodyForm(final NameValuePair... formParams) {
346         return bodyForm(Arrays.asList(formParams), StandardCharsets.ISO_8859_1);
347     }
348 
349     public Request bodyString(final String s, final ContentType contentType) {
350         final Charset charset = contentType != null ? contentType.getCharset() : null;
351         final byte[] raw = charset != null ? s.getBytes(charset) : s.getBytes();
352         return body(new ByteArrayEntity(raw, contentType));
353     }
354 
355     public Request bodyFile(final File file, final ContentType contentType) {
356         return body(new FileEntity(file, contentType));
357     }
358 
359     public Request bodyByteArray(final byte[] b) {
360         return body(new ByteArrayEntity(b, null));
361     }
362 
363     /**
364      * @since 4.4
365      */
366     public Request bodyByteArray(final byte[] b, final ContentType contentType) {
367         return body(new ByteArrayEntity(b, contentType));
368     }
369 
370     public Request bodyByteArray(final byte[] b, final int off, final int len) {
371         return body(new ByteArrayEntity(b, off, len, null));
372     }
373 
374     /**
375      * @since 4.4
376      */
377     public Request bodyByteArray(final byte[] b, final int off, final int len, final ContentType contentType) {
378         return body(new ByteArrayEntity(b, off, len, contentType));
379     }
380 
381     public Request bodyStream(final InputStream inStream) {
382         return body(new InputStreamEntity(inStream, -1, null));
383     }
384 
385     public Request bodyStream(final InputStream inStream, final ContentType contentType) {
386         return body(new InputStreamEntity(inStream, -1, contentType));
387     }
388 
389     @Override
390     public String toString() {
391         return this.request.toString();
392     }
393 
394 }