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