001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.client.config;
029
030import java.net.InetAddress;
031import java.util.Collection;
032
033import org.apache.http.HttpHost;
034import org.apache.http.annotation.Contract;
035import org.apache.http.annotation.ThreadingBehavior;
036
037/**
038 *  Immutable class encapsulating request configuration items.
039 *  The default setting for stale connection checking changed
040 *  to false, and the feature was deprecated starting with version 4.4.
041 */
042@Contract(threading = ThreadingBehavior.IMMUTABLE)
043public class RequestConfig implements Cloneable {
044
045    public static final RequestConfig DEFAULT = new Builder().build();
046
047    private final boolean expectContinueEnabled;
048    private final HttpHost proxy;
049    private final InetAddress localAddress;
050    private final boolean staleConnectionCheckEnabled;
051    private final String cookieSpec;
052    private final boolean redirectsEnabled;
053    private final boolean relativeRedirectsAllowed;
054    private final boolean circularRedirectsAllowed;
055    private final int maxRedirects;
056    private final boolean authenticationEnabled;
057    private final Collection<String> targetPreferredAuthSchemes;
058    private final Collection<String> proxyPreferredAuthSchemes;
059    private final int connectionRequestTimeout;
060    private final int connectTimeout;
061    private final int socketTimeout;
062    private final boolean contentCompressionEnabled;
063
064    /**
065     * Intended for CDI compatibility
066    */
067    protected RequestConfig() {
068        this(false, null, null, false, null, false, false, false, 0, false, null, null, 0, 0, 0, true);
069    }
070
071    RequestConfig(
072            final boolean expectContinueEnabled,
073            final HttpHost proxy,
074            final InetAddress localAddress,
075            final boolean staleConnectionCheckEnabled,
076            final String cookieSpec,
077            final boolean redirectsEnabled,
078            final boolean relativeRedirectsAllowed,
079            final boolean circularRedirectsAllowed,
080            final int maxRedirects,
081            final boolean authenticationEnabled,
082            final Collection<String> targetPreferredAuthSchemes,
083            final Collection<String> proxyPreferredAuthSchemes,
084            final int connectionRequestTimeout,
085            final int connectTimeout,
086            final int socketTimeout,
087            final boolean contentCompressionEnabled) {
088        super();
089        this.expectContinueEnabled = expectContinueEnabled;
090        this.proxy = proxy;
091        this.localAddress = localAddress;
092        this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
093        this.cookieSpec = cookieSpec;
094        this.redirectsEnabled = redirectsEnabled;
095        this.relativeRedirectsAllowed = relativeRedirectsAllowed;
096        this.circularRedirectsAllowed = circularRedirectsAllowed;
097        this.maxRedirects = maxRedirects;
098        this.authenticationEnabled = authenticationEnabled;
099        this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
100        this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
101        this.connectionRequestTimeout = connectionRequestTimeout;
102        this.connectTimeout = connectTimeout;
103        this.socketTimeout = socketTimeout;
104        this.contentCompressionEnabled = contentCompressionEnabled;
105    }
106
107    /**
108     * Determines whether the 'Expect: 100-Continue' handshake is enabled
109     * for entity enclosing methods. The purpose of the 'Expect: 100-Continue'
110     * handshake is to allow a client that is sending a request message with
111     * a request body to determine if the origin server is willing to
112     * accept the request (based on the request headers) before the client
113     * sends the request body.
114     * <p>
115     * The use of the 'Expect: 100-continue' handshake can result in
116     * a noticeable performance improvement for entity enclosing requests
117     * (such as POST and PUT) that require the target server's
118     * authentication.
119     * </p>
120     * <p>
121     * 'Expect: 100-continue' handshake should be used with caution, as it
122     * may cause problems with HTTP servers and proxies that do not support
123     * HTTP/1.1 protocol.
124     * </p>
125     * <p>
126     * Default: {@code false}
127     * </p>
128     */
129    public boolean isExpectContinueEnabled() {
130        return expectContinueEnabled;
131    }
132
133    /**
134     * Returns HTTP proxy to be used for request execution.
135     * <p>
136     * Default: {@code null}
137     * </p>
138     */
139    public HttpHost getProxy() {
140        return proxy;
141    }
142
143    /**
144     * Returns local address to be used for request execution.
145     * <p>
146     * On machines with multiple network interfaces, this parameter
147     * can be used to select the network interface from which the
148     * connection originates.
149     * </p>
150     * <p>
151     * Default: {@code null}
152     * </p>
153     */
154    public InetAddress getLocalAddress() {
155        return localAddress;
156    }
157
158    /**
159     * Determines whether stale connection check is to be used. The stale
160     * connection check can cause up to 30 millisecond overhead per request and
161     * should be used only when appropriate. For performance critical
162     * operations this check should be disabled.
163     * <p>
164     * Default: {@code false} since 4.4
165     * </p>
166     *
167     * @deprecated (4.4) Use {@link
168     *   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#getValidateAfterInactivity()}
169     */
170    @Deprecated
171    public boolean isStaleConnectionCheckEnabled() {
172        return staleConnectionCheckEnabled;
173    }
174
175    /**
176     * Determines the name of the cookie specification to be used for HTTP state
177     * management.
178     * <p>
179     * Default: {@code null}
180     * </p>
181     */
182    public String getCookieSpec() {
183        return cookieSpec;
184    }
185
186    /**
187     * Determines whether redirects should be handled automatically.
188     * <p>
189     * Default: {@code true}
190     * </p>
191     */
192    public boolean isRedirectsEnabled() {
193        return redirectsEnabled;
194    }
195
196    /**
197     * Determines whether relative redirects should be rejected. HTTP specification
198     * requires the location value be an absolute URI.
199     * <p>
200     * Default: {@code true}
201     * </p>
202     */
203    public boolean isRelativeRedirectsAllowed() {
204        return relativeRedirectsAllowed;
205    }
206
207    /**
208     * Determines whether circular redirects (redirects to the same location) should
209     * be allowed. The HTTP spec is not sufficiently clear whether circular redirects
210     * are permitted, therefore optionally they can be enabled
211     * <p>
212     * Default: {@code false}
213     * </p>
214     */
215    public boolean isCircularRedirectsAllowed() {
216        return circularRedirectsAllowed;
217    }
218
219    /**
220     * Returns the maximum number of redirects to be followed. The limit on number
221     * of redirects is intended to prevent infinite loops.
222     * <p>
223     * Default: {@code 50}
224     * </p>
225     */
226    public int getMaxRedirects() {
227        return maxRedirects;
228    }
229
230    /**
231     * Determines whether authentication should be handled automatically.
232     * <p>
233     * Default: {@code true}
234     * </p>
235     */
236    public boolean isAuthenticationEnabled() {
237        return authenticationEnabled;
238    }
239
240    /**
241     * Determines the order of preference for supported authentication schemes
242     * when authenticating with the target host.
243     * <p>
244     * Default: {@code null}
245     * </p>
246     */
247    public Collection<String> getTargetPreferredAuthSchemes() {
248        return targetPreferredAuthSchemes;
249    }
250
251    /**
252     * Determines the order of preference for supported authentication schemes
253     * when authenticating with the proxy host.
254     * <p>
255     * Default: {@code null}
256     * </p>
257     */
258    public Collection<String> getProxyPreferredAuthSchemes() {
259        return proxyPreferredAuthSchemes;
260    }
261
262    /**
263     * Returns the timeout in milliseconds used when requesting a connection
264     * from the connection manager. A timeout value of zero is interpreted
265     * as an infinite timeout.
266     * <p>
267     * A timeout value of zero is interpreted as an infinite timeout.
268     * A negative value is interpreted as undefined (system default).
269     * </p>
270     * <p>
271     * Default: {@code -1}
272     * </p>
273     */
274    public int getConnectionRequestTimeout() {
275        return connectionRequestTimeout;
276    }
277
278    /**
279     * Determines the timeout in milliseconds until a connection is established.
280     * A timeout value of zero is interpreted as an infinite timeout.
281     * <p>
282     * A timeout value of zero is interpreted as an infinite timeout.
283     * A negative value is interpreted as undefined (system default).
284     * </p>
285     * <p>
286     * Default: {@code -1}
287     * </p>
288     */
289    public int getConnectTimeout() {
290        return connectTimeout;
291    }
292
293    /**
294     * Defines the socket timeout ({@code SO_TIMEOUT}) in milliseconds,
295     * which is the timeout for waiting for data  or, put differently,
296     * a maximum period inactivity between two consecutive data packets).
297     * <p>
298     * A timeout value of zero is interpreted as an infinite timeout.
299     * A negative value is interpreted as undefined (system default).
300     * </p>
301     * <p>
302     * Default: {@code -1}
303     * </p>
304     */
305    public int getSocketTimeout() {
306        return socketTimeout;
307    }
308
309    /**
310     * Determines whether compressed entities should be decompressed automatically.
311     * <p>
312     * Default: {@code true}
313     * </p>
314     *
315     * @since 4.4
316     * @deprecated (4.5) Use {@link #isContentCompressionEnabled()}
317     */
318    @Deprecated
319    public boolean isDecompressionEnabled() {
320        return contentCompressionEnabled;
321    }
322
323    /**
324     * Determines whether the target server is requested to compress content.
325     * <p>
326     * Default: {@code true}
327     * </p>
328     *
329     * @since 4.5
330     */
331    public boolean isContentCompressionEnabled() {
332        return contentCompressionEnabled;
333    }
334
335    @Override
336    protected RequestConfig clone() throws CloneNotSupportedException {
337        return (RequestConfig) super.clone();
338    }
339
340    @Override
341    public String toString() {
342        final StringBuilder builder = new StringBuilder();
343        builder.append("[");
344        builder.append("expectContinueEnabled=").append(expectContinueEnabled);
345        builder.append(", proxy=").append(proxy);
346        builder.append(", localAddress=").append(localAddress);
347        builder.append(", cookieSpec=").append(cookieSpec);
348        builder.append(", redirectsEnabled=").append(redirectsEnabled);
349        builder.append(", relativeRedirectsAllowed=").append(relativeRedirectsAllowed);
350        builder.append(", maxRedirects=").append(maxRedirects);
351        builder.append(", circularRedirectsAllowed=").append(circularRedirectsAllowed);
352        builder.append(", authenticationEnabled=").append(authenticationEnabled);
353        builder.append(", targetPreferredAuthSchemes=").append(targetPreferredAuthSchemes);
354        builder.append(", proxyPreferredAuthSchemes=").append(proxyPreferredAuthSchemes);
355        builder.append(", connectionRequestTimeout=").append(connectionRequestTimeout);
356        builder.append(", connectTimeout=").append(connectTimeout);
357        builder.append(", socketTimeout=").append(socketTimeout);
358        builder.append(", contentCompressionEnabled=").append(contentCompressionEnabled);
359        builder.append("]");
360        return builder.toString();
361    }
362
363    public static RequestConfig.Builder custom() {
364        return new Builder();
365    }
366
367    @SuppressWarnings("deprecation")
368    public static RequestConfig.Builder copy(final RequestConfig config) {
369        return new Builder()
370            .setExpectContinueEnabled(config.isExpectContinueEnabled())
371            .setProxy(config.getProxy())
372            .setLocalAddress(config.getLocalAddress())
373            .setStaleConnectionCheckEnabled(config.isStaleConnectionCheckEnabled())
374            .setCookieSpec(config.getCookieSpec())
375            .setRedirectsEnabled(config.isRedirectsEnabled())
376            .setRelativeRedirectsAllowed(config.isRelativeRedirectsAllowed())
377            .setCircularRedirectsAllowed(config.isCircularRedirectsAllowed())
378            .setMaxRedirects(config.getMaxRedirects())
379            .setAuthenticationEnabled(config.isAuthenticationEnabled())
380            .setTargetPreferredAuthSchemes(config.getTargetPreferredAuthSchemes())
381            .setProxyPreferredAuthSchemes(config.getProxyPreferredAuthSchemes())
382            .setConnectionRequestTimeout(config.getConnectionRequestTimeout())
383            .setConnectTimeout(config.getConnectTimeout())
384            .setSocketTimeout(config.getSocketTimeout())
385            .setDecompressionEnabled(config.isDecompressionEnabled())
386            .setContentCompressionEnabled(config.isContentCompressionEnabled());
387    }
388
389    public static class Builder {
390
391        private boolean expectContinueEnabled;
392        private HttpHost proxy;
393        private InetAddress localAddress;
394        private boolean staleConnectionCheckEnabled;
395        private String cookieSpec;
396        private boolean redirectsEnabled;
397        private boolean relativeRedirectsAllowed;
398        private boolean circularRedirectsAllowed;
399        private int maxRedirects;
400        private boolean authenticationEnabled;
401        private Collection<String> targetPreferredAuthSchemes;
402        private Collection<String> proxyPreferredAuthSchemes;
403        private int connectionRequestTimeout;
404        private int connectTimeout;
405        private int socketTimeout;
406        private boolean contentCompressionEnabled;
407
408        Builder() {
409            super();
410            this.staleConnectionCheckEnabled = false;
411            this.redirectsEnabled = true;
412            this.maxRedirects = 50;
413            this.relativeRedirectsAllowed = true;
414            this.authenticationEnabled = true;
415            this.connectionRequestTimeout = -1;
416            this.connectTimeout = -1;
417            this.socketTimeout = -1;
418            this.contentCompressionEnabled = true;
419        }
420
421        public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {
422            this.expectContinueEnabled = expectContinueEnabled;
423            return this;
424        }
425
426        public Builder setProxy(final HttpHost proxy) {
427            this.proxy = proxy;
428            return this;
429        }
430
431        public Builder setLocalAddress(final InetAddress localAddress) {
432            this.localAddress = localAddress;
433            return this;
434        }
435
436        /**
437         * @deprecated (4.4) Use {@link
438         *   org.apache.http.impl.conn.PoolingHttpClientConnectionManager#setValidateAfterInactivity(int)}
439         */
440        @Deprecated
441        public Builder setStaleConnectionCheckEnabled(final boolean staleConnectionCheckEnabled) {
442            this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
443            return this;
444        }
445
446        public Builder setCookieSpec(final String cookieSpec) {
447            this.cookieSpec = cookieSpec;
448            return this;
449        }
450
451        public Builder setRedirectsEnabled(final boolean redirectsEnabled) {
452            this.redirectsEnabled = redirectsEnabled;
453            return this;
454        }
455
456        public Builder setRelativeRedirectsAllowed(final boolean relativeRedirectsAllowed) {
457            this.relativeRedirectsAllowed = relativeRedirectsAllowed;
458            return this;
459        }
460
461        public Builder setCircularRedirectsAllowed(final boolean circularRedirectsAllowed) {
462            this.circularRedirectsAllowed = circularRedirectsAllowed;
463            return this;
464        }
465
466        public Builder setMaxRedirects(final int maxRedirects) {
467            this.maxRedirects = maxRedirects;
468            return this;
469        }
470
471        public Builder setAuthenticationEnabled(final boolean authenticationEnabled) {
472            this.authenticationEnabled = authenticationEnabled;
473            return this;
474        }
475
476        public Builder setTargetPreferredAuthSchemes(final Collection<String> targetPreferredAuthSchemes) {
477            this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
478            return this;
479        }
480
481        public Builder setProxyPreferredAuthSchemes(final Collection<String> proxyPreferredAuthSchemes) {
482            this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
483            return this;
484        }
485
486        public Builder setConnectionRequestTimeout(final int connectionRequestTimeout) {
487            this.connectionRequestTimeout = connectionRequestTimeout;
488            return this;
489        }
490
491        public Builder setConnectTimeout(final int connectTimeout) {
492            this.connectTimeout = connectTimeout;
493            return this;
494        }
495
496        public Builder setSocketTimeout(final int socketTimeout) {
497            this.socketTimeout = socketTimeout;
498            return this;
499        }
500
501        /**
502         * @deprecated (4.5) Set {@link #setContentCompressionEnabled(boolean)} to {@code false} and
503         * add the {@code Accept-Encoding} request header.
504         */
505        @Deprecated
506        public Builder setDecompressionEnabled(final boolean decompressionEnabled) {
507            this.contentCompressionEnabled = decompressionEnabled;
508            return this;
509        }
510
511        public Builder setContentCompressionEnabled(final boolean contentCompressionEnabled) {
512            this.contentCompressionEnabled = contentCompressionEnabled;
513            return this;
514        }
515
516        public RequestConfig build() {
517            return new RequestConfig(
518                    expectContinueEnabled,
519                    proxy,
520                    localAddress,
521                    staleConnectionCheckEnabled,
522                    cookieSpec,
523                    redirectsEnabled,
524                    relativeRedirectsAllowed,
525                    circularRedirectsAllowed,
526                    maxRedirects,
527                    authenticationEnabled,
528                    targetPreferredAuthSchemes,
529                    proxyPreferredAuthSchemes,
530                    connectionRequestTimeout,
531                    connectTimeout,
532                    socketTimeout,
533                    contentCompressionEnabled);
534        }
535
536    }
537
538}