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          * @return this instance.
336          */
337         public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {
338             this.expectContinueEnabled = expectContinueEnabled;
339             return this;
340         }
341 
342         /**
343          * Returns HTTP proxy to be used for request execution.
344          * <p>
345          * Default: {@code null}
346          * </p>
347          *
348          * @return this instance.
349          * @deprecated Use {@link org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner}
350          * or a custom {@link org.apache.hc.client5.http.routing.HttpRoutePlanner}.
351          */
352         @Deprecated
353         public Builder setProxy(final HttpHost proxy) {
354             this.proxy = proxy;
355             return this;
356         }
357 
358         /**
359          * Determines the name of the cookie specification to be used for HTTP state
360          * management.
361          * <p>
362          * Default: {@code null}
363          * </p>
364          *
365          * @return this instance.
366          */
367         public Builder setCookieSpec(final String cookieSpec) {
368             this.cookieSpec = cookieSpec;
369             return this;
370         }
371 
372         /**
373          * Determines whether redirects should be handled automatically.
374          * <p>
375          * Default: {@code true}
376          * </p>
377          *
378          * @return this instance.
379          */
380         public Builder setRedirectsEnabled(final boolean redirectsEnabled) {
381             this.redirectsEnabled = redirectsEnabled;
382             return this;
383         }
384 
385         /**
386          * Determines whether circular redirects (redirects to the same location) should
387          * be allowed. The HTTP spec is not sufficiently clear whether circular redirects
388          * are permitted, therefore optionally they can be enabled
389          * <p>
390          * Default: {@code false}
391          * </p>
392          *
393          * @return this instance.
394          */
395         public Builder setCircularRedirectsAllowed(final boolean circularRedirectsAllowed) {
396             this.circularRedirectsAllowed = circularRedirectsAllowed;
397             return this;
398         }
399 
400         /**
401          * Returns the maximum number of redirects to be followed. The limit on number
402          * of redirects is intended to prevent infinite loops.
403          * <p>
404          * Default: {@code 50}
405          * </p>
406          *
407          * @return this instance.
408          */
409         public Builder setMaxRedirects(final int maxRedirects) {
410             this.maxRedirects = maxRedirects;
411             return this;
412         }
413 
414         /**
415          * Determines whether authentication should be handled automatically.
416          * <p>
417          * Default: {@code true}
418          * </p>
419          *
420          * @return this instance.
421          */
422         public Builder setAuthenticationEnabled(final boolean authenticationEnabled) {
423             this.authenticationEnabled = authenticationEnabled;
424             return this;
425         }
426 
427         /**
428          * Determines the order of preference for supported authentication schemes
429          * by their names when authenticating with the target host.
430          * <p>
431          * Default: {@code null}
432          * </p>
433          *
434          * @return this instance.
435          */
436         public Builder setTargetPreferredAuthSchemes(final Collection<String> targetPreferredAuthSchemes) {
437             this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
438             return this;
439         }
440 
441         /**
442          * Determines the order of preference for supported authentication schemes
443          * by their names when authenticating with the proxy host.
444          * <p>
445          * Default: {@code null}
446          * </p>
447          *
448          * @return this instance.
449          */
450         public Builder setProxyPreferredAuthSchemes(final Collection<String> proxyPreferredAuthSchemes) {
451             this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
452             return this;
453         }
454         /**
455          * Returns the connection lease request timeout used when requesting
456          * a connection from the connection manager.
457          * <p>
458          * Default: 3 minutes.
459          * </p>
460          *
461          * @return this instance.
462          */
463         public Builder setConnectionRequestTimeout(final Timeout connectionRequestTimeout) {
464             this.connectionRequestTimeout = connectionRequestTimeout;
465             return this;
466         }
467 
468         /**
469          * @return this instance.
470          * @see #setConnectionRequestTimeout(Timeout)
471          */
472         public Builder setConnectionRequestTimeout(final long connectionRequestTimeout, final TimeUnit timeUnit) {
473             this.connectionRequestTimeout = Timeout.of(connectionRequestTimeout, timeUnit);
474             return this;
475         }
476 
477         /**
478          * Determines the timeout until a new connection is fully established.
479          * This may also include transport security negotiation exchanges
480          * such as {@code SSL} or {@code TLS} protocol negotiation).
481          * <p>
482          * A timeout value of zero is interpreted as an infinite timeout.
483          * </p>
484          * <p>
485          * Default: 3 minutes
486          * </p>
487          *
488          * @return this instance.
489          * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(Timeout)}.
490          */
491         @Deprecated
492         public Builder setConnectTimeout(final Timeout connectTimeout) {
493             this.connectTimeout = connectTimeout;
494             return this;
495         }
496 
497         /**
498          * @see #setConnectTimeout(Timeout)
499          *
500          * @return this instance.
501          * @deprecated Use {@link ConnectionConfig.Builder#setConnectTimeout(long, TimeUnit)}.
502          */
503         @Deprecated
504         public Builder setConnectTimeout(final long connectTimeout, final TimeUnit timeUnit) {
505             this.connectTimeout = Timeout.of(connectTimeout, timeUnit);
506             return this;
507         }
508 
509         /**
510          * Determines the timeout until arrival of a response from the opposite
511          * endpoint.
512          * <p>
513          * A timeout value of zero is interpreted as an infinite timeout.
514          * </p>
515          * <p>
516          * Please note that response timeout may be unsupported by
517          * HTTP transports with message multiplexing.
518          * </p>
519          * <p>
520          * Default: {@code null}
521          * </p>
522          *
523          * @return this instance.
524          * @since 5.0
525          */
526         public Builder setResponseTimeout(final Timeout responseTimeout) {
527             this.responseTimeout = responseTimeout;
528             return this;
529         }
530 
531         /**
532          * @see #setResponseTimeout(Timeout)
533          */
534         public Builder setResponseTimeout(final long responseTimeout, final TimeUnit timeUnit) {
535             this.responseTimeout = Timeout.of(responseTimeout, timeUnit);
536             return this;
537         }
538 
539         /**
540          * Determines the default of value of connection keep-alive time period when not
541          * explicitly communicated by the origin server with a {@code Keep-Alive} response
542          * header.
543          * <p>
544          * A negative value is interpreted as an infinite keep-alive period.
545          * </p>
546          * <p>
547          * Default: 3 minutes
548          * </p>
549          *
550          * @return this instance.
551          * @since 5.0
552          */
553         public Builder setConnectionKeepAlive(final TimeValue connectionKeepAlive) {
554             this.connectionKeepAlive = connectionKeepAlive;
555             return this;
556         }
557 
558         /**
559          * @return this instance.
560          * @see #setConnectionKeepAlive(TimeValue)
561          */
562         public Builder setDefaultKeepAlive(final long defaultKeepAlive, final TimeUnit timeUnit) {
563             this.connectionKeepAlive = TimeValue.of(defaultKeepAlive, timeUnit);
564             return this;
565         }
566 
567         /**
568          * Determines whether the target server is requested to compress content.
569          * <p>
570          * Default: {@code true}
571          * </p>
572          *
573          * @return this instance.
574          * @since 4.5
575          */
576         public Builder setContentCompressionEnabled(final boolean contentCompressionEnabled) {
577             this.contentCompressionEnabled = contentCompressionEnabled;
578             return this;
579         }
580 
581         /**
582          * Determines whether request cancellation, such as through {@code
583          * Future#cancel(boolean)}, should kill the underlying connection. If this
584          * option is set to false, the client will attempt to preserve the
585          * underlying connection by allowing the request to complete in the
586          * background, discarding the response.
587          * <p>
588          * Note that when this option is {@code true}, cancelling a request may
589          * cause other requests to fail, if they are waiting to use the same
590          * connection.
591          * </p>
592          * <p>
593          * On HTTP/2, this option has no effect. Request cancellation will always
594          * result in the stream being cancelled with a {@code RST_STREAM}. This
595          * has no effect on connection reuse.
596          * </p>
597          * <p>
598          * On non-asynchronous clients, this option has no effect. Request
599          * cancellation, such as through {@code HttpUriRequestBase#cancel()}, will
600          * always kill the underlying connection.
601          * </p>
602          * <p>
603          * Default: {@code true}
604          * </p>
605          *
606          * @return this instance.
607          * @since 5.0
608          */
609         public Builder setHardCancellationEnabled(final boolean hardCancellationEnabled) {
610             this.hardCancellationEnabled = hardCancellationEnabled;
611             return this;
612         }
613 
614         /**
615          * Determines whether the client server should automatically attempt to upgrade
616          * to a safer or a newer version of the protocol, whenever possible.
617          * <p>
618          * Presently supported: HTTP/1.1 TLS upgrade
619          * </p>
620          * <p>
621          * Default: {@code true}
622          * </p>
623          *
624          * @return this instance.
625          * @since 5.4
626          */
627         public Builder setProtocolUpgradeEnabled(final boolean protocolUpgradeEnabled) {
628             this.protocolUpgradeEnabled = protocolUpgradeEnabled;
629             return this;
630         }
631 
632         public RequestConfig build() {
633             return new RequestConfig(
634                     expectContinueEnabled,
635                     proxy,
636                     cookieSpec,
637                     redirectsEnabled,
638                     circularRedirectsAllowed,
639                     maxRedirects,
640                     authenticationEnabled,
641                     targetPreferredAuthSchemes,
642                     proxyPreferredAuthSchemes,
643                     connectionRequestTimeout != null ? connectionRequestTimeout : DEFAULT_CONNECTION_REQUEST_TIMEOUT,
644                     connectTimeout,
645                     responseTimeout,
646                     connectionKeepAlive != null ? connectionKeepAlive : DEFAULT_CONN_KEEP_ALIVE,
647                     contentCompressionEnabled,
648                     hardCancellationEnabled,
649                     protocolUpgradeEnabled);
650         }
651 
652     }
653 
654 }