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.client5.http.config;
29  
30  import java.util.Collection;
31  import java.util.concurrent.TimeUnit;
32  
33  import org.apache.hc.core5.annotation.Contract;
34  import org.apache.hc.core5.annotation.ThreadingBehavior;
35  import org.apache.hc.core5.http.HttpHost;
36  import org.apache.hc.core5.util.TimeValue;
37  import org.apache.hc.core5.util.Timeout;
38  
39  /**
40   *  Immutable class encapsulating request configuration items.
41   */
42  @Contract(threading = ThreadingBehavior.IMMUTABLE)
43  public class RequestConfig implements Cloneable {
44  
45      private static final Timeout DEFAULT_CONNECTION_REQUEST_TIMEOUT = Timeout.ofMinutes(3);
46      private static final TimeValue DEFAULT_CONN_KEEP_ALIVE = TimeValue.ofMinutes(3);
47  
48      public static final RequestConfig DEFAULT = new Builder().build();
49  
50      private final boolean expectContinueEnabled;
51      private final HttpHost proxy;
52      private final String cookieSpec;
53      private final boolean redirectsEnabled;
54      private final boolean circularRedirectsAllowed;
55      private final int maxRedirects;
56      private final boolean authenticationEnabled;
57      private final Collection<String> targetPreferredAuthSchemes;
58      private final Collection<String> proxyPreferredAuthSchemes;
59      private final Timeout connectionRequestTimeout;
60      private final Timeout connectTimeout;
61      private final Timeout responseTimeout;
62      private final TimeValue connectionKeepAlive;
63      private final boolean contentCompressionEnabled;
64      private final boolean hardCancellationEnabled;
65  
66      /**
67       * Intended for CDI compatibility
68      */
69      protected RequestConfig() {
70          this(false, null, null, false, false, 0, false, null, null,
71                  DEFAULT_CONNECTION_REQUEST_TIMEOUT, null, null, DEFAULT_CONN_KEEP_ALIVE, false, false);
72      }
73  
74      RequestConfig(
75              final boolean expectContinueEnabled,
76              final HttpHost proxy,
77              final String cookieSpec,
78              final boolean redirectsEnabled,
79              final boolean circularRedirectsAllowed,
80              final int maxRedirects,
81              final boolean authenticationEnabled,
82              final Collection<String> targetPreferredAuthSchemes,
83              final Collection<String> proxyPreferredAuthSchemes,
84              final Timeout connectionRequestTimeout,
85              final Timeout connectTimeout,
86              final Timeout responseTimeout,
87              final TimeValue connectionKeepAlive,
88              final boolean contentCompressionEnabled,
89              final boolean hardCancellationEnabled) {
90          super();
91          this.expectContinueEnabled = expectContinueEnabled;
92          this.proxy = proxy;
93          this.cookieSpec = cookieSpec;
94          this.redirectsEnabled = redirectsEnabled;
95          this.circularRedirectsAllowed = circularRedirectsAllowed;
96          this.maxRedirects = maxRedirects;
97          this.authenticationEnabled = authenticationEnabled;
98          this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
99          this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
100         this.connectionRequestTimeout = connectionRequestTimeout;
101         this.connectTimeout = connectTimeout;
102         this.responseTimeout = responseTimeout;
103         this.connectionKeepAlive = connectionKeepAlive;
104         this.contentCompressionEnabled = contentCompressionEnabled;
105         this.hardCancellationEnabled = hardCancellationEnabled;
106     }
107 
108     /**
109      * @see Builder#setExpectContinueEnabled(boolean)
110      */
111     public boolean isExpectContinueEnabled() {
112         return expectContinueEnabled;
113     }
114 
115     /**
116      * @see Builder#setProxy(HttpHost)
117      *
118      * @deprecated Use {@link org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner}
119      * or a custom {@link org.apache.hc.client5.http.routing.HttpRoutePlanner}.
120      */
121     @Deprecated
122     public HttpHost getProxy() {
123         return proxy;
124     }
125 
126     /**
127      * @see Builder#setCookieSpec(String)
128      */
129     public String getCookieSpec() {
130         return cookieSpec;
131     }
132 
133     /**
134      * @see Builder#setRedirectsEnabled(boolean)
135      */
136     public boolean isRedirectsEnabled() {
137         return redirectsEnabled;
138     }
139 
140     /**
141      * @see Builder#setCircularRedirectsAllowed(boolean)
142      */
143     public boolean isCircularRedirectsAllowed() {
144         return circularRedirectsAllowed;
145     }
146 
147     /**
148      * @see Builder#setMaxRedirects(int)
149      */
150     public int getMaxRedirects() {
151         return maxRedirects;
152     }
153 
154     /**
155      * @see Builder#setAuthenticationEnabled(boolean)
156      */
157     public boolean isAuthenticationEnabled() {
158         return authenticationEnabled;
159     }
160 
161     /**
162      * @see Builder#setTargetPreferredAuthSchemes(Collection)
163      */
164     public Collection<String> getTargetPreferredAuthSchemes() {
165         return targetPreferredAuthSchemes;
166     }
167 
168     /**
169      * @see Builder#setProxyPreferredAuthSchemes(Collection)
170      */
171     public Collection<String> getProxyPreferredAuthSchemes() {
172         return proxyPreferredAuthSchemes;
173     }
174 
175     /**
176      * @see Builder#setConnectionRequestTimeout(Timeout)
177      */
178     public Timeout getConnectionRequestTimeout() {
179         return connectionRequestTimeout;
180     }
181 
182     /**
183      * @see Builder#setConnectTimeout(Timeout)
184      *
185      * @deprecated Use {@link ConnectionConfig#getConnectTimeout()}.
186      */
187     @Deprecated
188     public Timeout getConnectTimeout() {
189         return connectTimeout;
190     }
191 
192     /**
193      * @see Builder#setResponseTimeout(Timeout)
194      */
195     public Timeout getResponseTimeout() {
196         return responseTimeout;
197     }
198 
199     /**
200      * @see Builder#setConnectionKeepAlive(TimeValue)
201      */
202     public TimeValue getConnectionKeepAlive() {
203         return connectionKeepAlive;
204     }
205 
206     /**
207      * @see Builder#setContentCompressionEnabled(boolean)
208      */
209     public boolean isContentCompressionEnabled() {
210         return contentCompressionEnabled;
211     }
212 
213     /**
214      * @see Builder#setHardCancellationEnabled(boolean)
215      */
216     public boolean isHardCancellationEnabled() {
217         return hardCancellationEnabled;
218     }
219 
220     @Override
221     protected RequestConfig clone() throws CloneNotSupportedException {
222         return (RequestConfig) super.clone();
223     }
224 
225     @Override
226     public String toString() {
227         final StringBuilder builder = new StringBuilder();
228         builder.append("[");
229         builder.append("expectContinueEnabled=").append(expectContinueEnabled);
230         builder.append(", proxy=").append(proxy);
231         builder.append(", cookieSpec=").append(cookieSpec);
232         builder.append(", redirectsEnabled=").append(redirectsEnabled);
233         builder.append(", maxRedirects=").append(maxRedirects);
234         builder.append(", circularRedirectsAllowed=").append(circularRedirectsAllowed);
235         builder.append(", authenticationEnabled=").append(authenticationEnabled);
236         builder.append(", targetPreferredAuthSchemes=").append(targetPreferredAuthSchemes);
237         builder.append(", proxyPreferredAuthSchemes=").append(proxyPreferredAuthSchemes);
238         builder.append(", connectionRequestTimeout=").append(connectionRequestTimeout);
239         builder.append(", connectTimeout=").append(connectTimeout);
240         builder.append(", responseTimeout=").append(responseTimeout);
241         builder.append(", connectionKeepAlive=").append(connectionKeepAlive);
242         builder.append(", contentCompressionEnabled=").append(contentCompressionEnabled);
243         builder.append(", hardCancellationEnabled=").append(hardCancellationEnabled);
244         builder.append("]");
245         return builder.toString();
246     }
247 
248     public static RequestConfig.Builder custom() {
249         return new Builder();
250     }
251     @SuppressWarnings("deprecation")
252     public static RequestConfig.Builder copy(final RequestConfig config) {
253         return new Builder()
254             .setExpectContinueEnabled(config.isExpectContinueEnabled())
255             .setProxy(config.getProxy())
256             .setCookieSpec(config.getCookieSpec())
257             .setRedirectsEnabled(config.isRedirectsEnabled())
258             .setCircularRedirectsAllowed(config.isCircularRedirectsAllowed())
259             .setMaxRedirects(config.getMaxRedirects())
260             .setAuthenticationEnabled(config.isAuthenticationEnabled())
261             .setTargetPreferredAuthSchemes(config.getTargetPreferredAuthSchemes())
262             .setProxyPreferredAuthSchemes(config.getProxyPreferredAuthSchemes())
263             .setConnectionRequestTimeout(config.getConnectionRequestTimeout())
264             .setConnectTimeout(config.getConnectTimeout())
265             .setResponseTimeout(config.getResponseTimeout())
266             .setConnectionKeepAlive(config.getConnectionKeepAlive())
267             .setContentCompressionEnabled(config.isContentCompressionEnabled())
268             .setHardCancellationEnabled(config.isHardCancellationEnabled());
269     }
270 
271     public static class Builder {
272 
273         private boolean expectContinueEnabled;
274         private HttpHost proxy;
275         private String cookieSpec;
276         private boolean redirectsEnabled;
277         private boolean circularRedirectsAllowed;
278         private int maxRedirects;
279         private boolean authenticationEnabled;
280         private Collection<String> targetPreferredAuthSchemes;
281         private Collection<String> proxyPreferredAuthSchemes;
282         private Timeout connectionRequestTimeout;
283         private Timeout connectTimeout;
284         private Timeout responseTimeout;
285         private TimeValue connectionKeepAlive;
286         private boolean contentCompressionEnabled;
287         private boolean hardCancellationEnabled;
288 
289         Builder() {
290             super();
291             this.redirectsEnabled = true;
292             this.maxRedirects = 50;
293             this.authenticationEnabled = true;
294             this.connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
295             this.contentCompressionEnabled = true;
296             this.hardCancellationEnabled = true;
297         }
298 
299         /**
300          * Determines whether the 'Expect: 100-Continue' handshake is enabled
301          * for entity enclosing methods. The purpose of the 'Expect: 100-Continue'
302          * handshake is to allow a client that is sending a request message with
303          * a request body to determine if the origin server is willing to
304          * accept the request (based on the request headers) before the client
305          * sends the request body.
306          * <p>
307          * The use of the 'Expect: 100-continue' handshake can result in
308          * a noticeable performance improvement for entity enclosing requests
309          * (such as POST and PUT) that require the target server's
310          * authentication.
311          * </p>
312          * <p>
313          * 'Expect: 100-continue' handshake should be used with caution, as it
314          * may cause problems with HTTP servers and proxies that do not support
315          * HTTP/1.1 protocol.
316          * </p>
317          * <p>
318          * Default: {@code false}
319          * </p>
320          */
321         public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {
322             this.expectContinueEnabled = expectContinueEnabled;
323             return this;
324         }
325 
326         /**
327          * Returns HTTP proxy to be used for request execution.
328          * <p>
329          * Default: {@code null}
330          * </p>
331          *
332          * @deprecated Use {@link org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner}
333          * or a custom {@link org.apache.hc.client5.http.routing.HttpRoutePlanner}.
334          */
335         @Deprecated
336         public Builder setProxy(final HttpHost proxy) {
337             this.proxy = proxy;
338             return this;
339         }
340 
341         /**
342          * Determines the name of the cookie specification to be used for HTTP state
343          * management.
344          * <p>
345          * Default: {@code null}
346          * </p>
347          */
348         public Builder setCookieSpec(final String cookieSpec) {
349             this.cookieSpec = cookieSpec;
350             return this;
351         }
352 
353         /**
354          * Determines whether redirects should be handled automatically.
355          * <p>
356          * Default: {@code true}
357          * </p>
358          */
359         public Builder setRedirectsEnabled(final boolean redirectsEnabled) {
360             this.redirectsEnabled = redirectsEnabled;
361             return this;
362         }
363 
364         /**
365          * Determines whether circular redirects (redirects to the same location) should
366          * be allowed. The HTTP spec is not sufficiently clear whether circular redirects
367          * are permitted, therefore optionally they can be enabled
368          * <p>
369          * Default: {@code false}
370          * </p>
371          */
372         public Builder setCircularRedirectsAllowed(final boolean circularRedirectsAllowed) {
373             this.circularRedirectsAllowed = circularRedirectsAllowed;
374             return this;
375         }
376 
377         /**
378          * Returns the maximum number of redirects to be followed. The limit on number
379          * of redirects is intended to prevent infinite loops.
380          * <p>
381          * Default: {@code 50}
382          * </p>
383          */
384         public Builder setMaxRedirects(final int maxRedirects) {
385             this.maxRedirects = maxRedirects;
386             return this;
387         }
388 
389         /**
390          * Determines whether authentication should be handled automatically.
391          * <p>
392          * Default: {@code true}
393          * </p>
394          */
395         public Builder setAuthenticationEnabled(final boolean authenticationEnabled) {
396             this.authenticationEnabled = authenticationEnabled;
397             return this;
398         }
399 
400         /**
401          * Determines the order of preference for supported authentication schemes
402          * by their names when authenticating with the target host.
403          * <p>
404          * Default: {@code null}
405          * </p>
406          */
407         public Builder setTargetPreferredAuthSchemes(final Collection<String> targetPreferredAuthSchemes) {
408             this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
409             return this;
410         }
411 
412         /**
413          * Determines the order of preference for supported authentication schemes
414          * by their names when authenticating with the proxy host.
415          * <p>
416          * Default: {@code null}
417          * </p>
418          */
419         public Builder setProxyPreferredAuthSchemes(final Collection<String> proxyPreferredAuthSchemes) {
420             this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
421             return this;
422         }
423         /**
424          * Returns the connection lease request timeout used when requesting
425          * a connection from the connection manager.
426          * <p>
427          * Default: 3 minutes.
428          * </p>
429          */
430         public Builder setConnectionRequestTimeout(final Timeout connectionRequestTimeout) {
431             this.connectionRequestTimeout = connectionRequestTimeout;
432             return this;
433         }
434 
435         /**
436          * @see #setConnectionRequestTimeout(Timeout)
437          */
438         public Builder setConnectionRequestTimeout(final long connectionRequestTimeout, final TimeUnit timeUnit) {
439             this.connectionRequestTimeout = Timeout.of(connectionRequestTimeout, timeUnit);
440             return this;
441         }
442 
443         /**
444          * Determines the timeout until a new connection is fully established.
445          * This may also include transport security negotiation exchanges
446          * such as {@code SSL} or {@code TLS} protocol negotiation).
447          * <p>
448          * A timeout value of zero is interpreted as an infinite timeout.
449          * </p>
450          * <p>
451          * Default: 3 minutes
452          * </p>
453          *
454          * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(Timeout)}.
455          */
456         @Deprecated
457         public Builder setConnectTimeout(final Timeout connectTimeout) {
458             this.connectTimeout = connectTimeout;
459             return this;
460         }
461 
462         /**
463          * @see #setConnectTimeout(Timeout)
464          *
465          * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(long, TimeUnit)}.
466          */
467         @Deprecated
468         public Builder setConnectTimeout(final long connectTimeout, final TimeUnit timeUnit) {
469             this.connectTimeout = Timeout.of(connectTimeout, timeUnit);
470             return this;
471         }
472 
473         /**
474          * Determines the timeout until arrival of a response from the opposite
475          * endpoint.
476          * <p>
477          * A timeout value of zero is interpreted as an infinite timeout.
478          * </p>
479          * <p>
480          * Please note that response timeout may be unsupported by
481          * HTTP transports with message multiplexing.
482          * </p>
483          * <p>
484          * Default: {@code null}
485          * </p>
486          *
487          * @since 5.0
488          */
489         public Builder setResponseTimeout(final Timeout responseTimeout) {
490             this.responseTimeout = responseTimeout;
491             return this;
492         }
493 
494         /**
495          * @see #setResponseTimeout(Timeout)
496          */
497         public Builder setResponseTimeout(final long responseTimeout, final TimeUnit timeUnit) {
498             this.responseTimeout = Timeout.of(responseTimeout, timeUnit);
499             return this;
500         }
501 
502         /**
503          * Determines the default of value of connection keep-alive time period when not
504          * explicitly communicated by the origin server with a {@code Keep-Alive} response
505          * header.
506          * <p>
507          * A negative value is interpreted as an infinite keep-alive period.
508          * </p>
509          * <p>
510          * Default: 3 minutes
511          * </p>
512          *
513          * @since 5.0
514          */
515         public Builder setConnectionKeepAlive(final TimeValue connectionKeepAlive) {
516             this.connectionKeepAlive = connectionKeepAlive;
517             return this;
518         }
519 
520         /**
521          * @see #setConnectionKeepAlive(TimeValue)
522          */
523         public Builder setDefaultKeepAlive(final long defaultKeepAlive, final TimeUnit timeUnit) {
524             this.connectionKeepAlive = TimeValue.of(defaultKeepAlive, timeUnit);
525             return this;
526         }
527 
528         /**
529          * Determines whether the target server is requested to compress content.
530          * <p>
531          * Default: {@code true}
532          * </p>
533          *
534          * @since 4.5
535          */
536         public Builder setContentCompressionEnabled(final boolean contentCompressionEnabled) {
537             this.contentCompressionEnabled = contentCompressionEnabled;
538             return this;
539         }
540 
541         /**
542          * Determines whether request cancellation, such as through {@code
543          * Future#cancel(boolean)}, should kill the underlying connection. If this
544          * option is set to false, the client will attempt to preserve the
545          * underlying connection by allowing the request to complete in the
546          * background, discarding the response.
547          * <p>
548          * Note that when this option is {@code true}, cancelling a request may
549          * cause other requests to fail, if they are waiting to use the same
550          * connection.
551          * </p>
552          * <p>
553          * On HTTP/2, this option has no effect. Request cancellation will always
554          * result in the stream being cancelled with a {@code RST_STREAM}. This
555          * has no effect on connection reuse.
556          * </p>
557          * <p>
558          * On non-asynchronous clients, this option has no effect. Request
559          * cancellation, such as through {@code HttpUriRequestBase#cancel()}, will
560          * always kill the underlying connection.
561          * </p>
562          * <p>
563          * Default: {@code true}
564          * </p>
565          *
566          * @since 5.0
567          */
568         public Builder setHardCancellationEnabled(final boolean hardCancellationEnabled) {
569             this.hardCancellationEnabled = hardCancellationEnabled;
570             return this;
571         }
572 
573         public RequestConfig build() {
574             return new RequestConfig(
575                     expectContinueEnabled,
576                     proxy,
577                     cookieSpec,
578                     redirectsEnabled,
579                     circularRedirectsAllowed,
580                     maxRedirects,
581                     authenticationEnabled,
582                     targetPreferredAuthSchemes,
583                     proxyPreferredAuthSchemes,
584                     connectionRequestTimeout != null ? connectionRequestTimeout : DEFAULT_CONNECTION_REQUEST_TIMEOUT,
585                     connectTimeout,
586                     responseTimeout,
587                     connectionKeepAlive != null ? connectionKeepAlive : DEFAULT_CONN_KEEP_ALIVE,
588                     contentCompressionEnabled,
589                     hardCancellationEnabled);
590         }
591 
592     }
593 
594 }