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          * A timeout value of zero is interpreted as an infinite timeout.
428          * </p>
429          * <p>
430          * Default: 3 minutes.
431          * </p>
432          */
433         public Builder setConnectionRequestTimeout(final Timeout connectionRequestTimeout) {
434             this.connectionRequestTimeout = connectionRequestTimeout;
435             return this;
436         }
437 
438         /**
439          * @see #setConnectionRequestTimeout(Timeout)
440          */
441         public Builder setConnectionRequestTimeout(final long connectionRequestTimeout, final TimeUnit timeUnit) {
442             this.connectionRequestTimeout = Timeout.of(connectionRequestTimeout, timeUnit);
443             return this;
444         }
445 
446         /**
447          * Determines the timeout until a new connection is fully established.
448          * This may also include transport security negotiation exchanges
449          * such as {@code SSL} or {@code TLS} protocol negotiation).
450          * <p>
451          * A timeout value of zero is interpreted as an infinite timeout.
452          * </p>
453          * <p>
454          * Default: 3 minutes
455          * </p>
456          *
457          * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(Timeout)}.
458          */
459         @Deprecated
460         public Builder setConnectTimeout(final Timeout connectTimeout) {
461             this.connectTimeout = connectTimeout;
462             return this;
463         }
464 
465         /**
466          * @see #setConnectTimeout(Timeout)
467          *
468          * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(long, TimeUnit)}.
469          */
470         @Deprecated
471         public Builder setConnectTimeout(final long connectTimeout, final TimeUnit timeUnit) {
472             this.connectTimeout = Timeout.of(connectTimeout, timeUnit);
473             return this;
474         }
475 
476         /**
477          * Determines the timeout until arrival of a response from the opposite
478          * endpoint.
479          * <p>
480          * A timeout value of zero is interpreted as an infinite timeout.
481          * </p>
482          * <p>
483          * Please note that response timeout may be unsupported by
484          * HTTP transports with message multiplexing.
485          * </p>
486          * <p>
487          * Default: {@code null}
488          * </p>
489          *
490          * @since 5.0
491          */
492         public Builder setResponseTimeout(final Timeout responseTimeout) {
493             this.responseTimeout = responseTimeout;
494             return this;
495         }
496 
497         /**
498          * @see #setResponseTimeout(Timeout)
499          */
500         public Builder setResponseTimeout(final long responseTimeout, final TimeUnit timeUnit) {
501             this.responseTimeout = Timeout.of(responseTimeout, timeUnit);
502             return this;
503         }
504 
505         /**
506          * Determines the default of value of connection keep-alive time period when not
507          * explicitly communicated by the origin server with a {@code Keep-Alive} response
508          * header.
509          * <p>
510          * A negative value is interpreted as an infinite keep-alive period.
511          * </p>
512          * <p>
513          * Default: 3 minutes
514          * </p>
515          *
516          * @since 5.0
517          */
518         public Builder setConnectionKeepAlive(final TimeValue connectionKeepAlive) {
519             this.connectionKeepAlive = connectionKeepAlive;
520             return this;
521         }
522 
523         /**
524          * @see #setConnectionKeepAlive(TimeValue)
525          */
526         public Builder setDefaultKeepAlive(final long defaultKeepAlive, final TimeUnit timeUnit) {
527             this.connectionKeepAlive = TimeValue.of(defaultKeepAlive, timeUnit);
528             return this;
529         }
530 
531         /**
532          * Determines whether the target server is requested to compress content.
533          * <p>
534          * Default: {@code true}
535          * </p>
536          *
537          * @since 4.5
538          */
539         public Builder setContentCompressionEnabled(final boolean contentCompressionEnabled) {
540             this.contentCompressionEnabled = contentCompressionEnabled;
541             return this;
542         }
543 
544         /**
545          * Determines whether request cancellation, such as through {@code
546          * Future#cancel(boolean)}, should kill the underlying connection. If this
547          * option is set to false, the client will attempt to preserve the
548          * underlying connection by allowing the request to complete in the
549          * background, discarding the response.
550          * <p>
551          * Note that when this option is {@code true}, cancelling a request may
552          * cause other requests to fail, if they are waiting to use the same
553          * connection.
554          * </p>
555          * <p>
556          * On HTTP/2, this option has no effect. Request cancellation will always
557          * result in the stream being cancelled with a {@code RST_STREAM}. This
558          * has no effect on connection reuse.
559          * </p>
560          * <p>
561          * On non-asynchronous clients, this option has no effect. Request
562          * cancellation, such as through {@code HttpUriRequestBase#cancel()}, will
563          * always kill the underlying connection.
564          * </p>
565          * <p>
566          * Default: {@code true}
567          * </p>
568          *
569          * @since 5.0
570          */
571         public Builder setHardCancellationEnabled(final boolean hardCancellationEnabled) {
572             this.hardCancellationEnabled = hardCancellationEnabled;
573             return this;
574         }
575 
576         public RequestConfig build() {
577             return new RequestConfig(
578                     expectContinueEnabled,
579                     proxy,
580                     cookieSpec,
581                     redirectsEnabled,
582                     circularRedirectsAllowed,
583                     maxRedirects,
584                     authenticationEnabled,
585                     targetPreferredAuthSchemes,
586                     proxyPreferredAuthSchemes,
587                     connectionRequestTimeout != null ? connectionRequestTimeout : DEFAULT_CONNECTION_REQUEST_TIMEOUT,
588                     connectTimeout,
589                     responseTimeout,
590                     connectionKeepAlive != null ? connectionKeepAlive : DEFAULT_CONN_KEEP_ALIVE,
591                     contentCompressionEnabled,
592                     hardCancellationEnabled);
593         }
594 
595     }
596 
597 }