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.examples;
29  
30  import java.net.InetAddress;
31  import java.net.UnknownHostException;
32  import java.nio.charset.CodingErrorAction;
33  import java.nio.charset.StandardCharsets;
34  import java.util.Arrays;
35  import java.util.Collections;
36  
37  import javax.net.ssl.SSLContext;
38  
39  import org.apache.hc.client5.http.ContextBuilder;
40  import org.apache.hc.client5.http.DnsResolver;
41  import org.apache.hc.client5.http.HttpRoute;
42  import org.apache.hc.client5.http.SystemDefaultDnsResolver;
43  import org.apache.hc.client5.http.auth.CredentialsProvider;
44  import org.apache.hc.client5.http.auth.StandardAuthScheme;
45  import org.apache.hc.client5.http.classic.methods.HttpGet;
46  import org.apache.hc.client5.http.config.ConnectionConfig;
47  import org.apache.hc.client5.http.config.RequestConfig;
48  import org.apache.hc.client5.http.config.TlsConfig;
49  import org.apache.hc.client5.http.cookie.BasicCookieStore;
50  import org.apache.hc.client5.http.cookie.CookieStore;
51  import org.apache.hc.client5.http.cookie.StandardCookieSpec;
52  import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
53  import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
54  import org.apache.hc.client5.http.impl.classic.HttpClients;
55  import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory;
56  import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
57  import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
58  import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
59  import org.apache.hc.client5.http.protocol.HttpClientContext;
60  import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
61  import org.apache.hc.core5.http.ClassicHttpRequest;
62  import org.apache.hc.core5.http.ClassicHttpResponse;
63  import org.apache.hc.core5.http.Header;
64  import org.apache.hc.core5.http.HttpHost;
65  import org.apache.hc.core5.http.ParseException;
66  import org.apache.hc.core5.http.config.CharCodingConfig;
67  import org.apache.hc.core5.http.config.Http1Config;
68  import org.apache.hc.core5.http.impl.io.DefaultClassicHttpResponseFactory;
69  import org.apache.hc.core5.http.impl.io.DefaultHttpRequestWriterFactory;
70  import org.apache.hc.core5.http.impl.io.DefaultHttpResponseParser;
71  import org.apache.hc.core5.http.impl.io.DefaultHttpResponseParserFactory;
72  import org.apache.hc.core5.http.io.HttpConnectionFactory;
73  import org.apache.hc.core5.http.io.HttpMessageParser;
74  import org.apache.hc.core5.http.io.HttpMessageParserFactory;
75  import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
76  import org.apache.hc.core5.http.io.SocketConfig;
77  import org.apache.hc.core5.http.io.entity.EntityUtils;
78  import org.apache.hc.core5.http.message.BasicHeader;
79  import org.apache.hc.core5.http.message.BasicLineParser;
80  import org.apache.hc.core5.http.message.LineParser;
81  import org.apache.hc.core5.http.message.StatusLine;
82  import org.apache.hc.core5.http.ssl.TLS;
83  import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
84  import org.apache.hc.core5.pool.PoolReusePolicy;
85  import org.apache.hc.core5.ssl.SSLContexts;
86  import org.apache.hc.core5.util.CharArrayBuffer;
87  import org.apache.hc.core5.util.TimeValue;
88  import org.apache.hc.core5.util.Timeout;
89  
90  /**
91   * This example demonstrates how to customize and configure the most common aspects
92   * of HTTP request execution and connection management.
93   */
94  public class ClientConfiguration {
95  
96      public final static void main(final String[] args) throws Exception {
97  
98          // Use custom message parser / writer to customize the way HTTP
99          // messages are parsed from and written out to the data stream.
100         final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory = new DefaultHttpResponseParserFactory() {
101 
102             @Override
103             public HttpMessageParser<ClassicHttpResponse> create(final Http1Config h1Config) {
104                 final LineParser lineParser = new BasicLineParser() {
105 
106                     @Override
107                     public Header parseHeader(final CharArrayBuffer buffer) {
108                         try {
109                             return super.parseHeader(buffer);
110                         } catch (final ParseException ex) {
111                             return new BasicHeader(buffer.toString(), null);
112                         }
113                     }
114 
115                 };
116                 return new DefaultHttpResponseParser(lineParser, DefaultClassicHttpResponseFactory.INSTANCE, h1Config);
117             }
118 
119         };
120         final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();
121 
122         // Create HTTP/1.1 protocol configuration
123         final Http1Config h1Config = Http1Config.custom()
124                 .setMaxHeaderCount(200)
125                 .setMaxLineLength(2000)
126                 .build();
127         // Create connection configuration
128         final CharCodingConfig connectionConfig = CharCodingConfig.custom()
129                 .setMalformedInputAction(CodingErrorAction.IGNORE)
130                 .setUnmappableInputAction(CodingErrorAction.IGNORE)
131                 .setCharset(StandardCharsets.UTF_8)
132                 .build();
133 
134         // Use a custom connection factory to customize the process of
135         // initialization of outgoing HTTP connections. Beside standard connection
136         // configuration parameters HTTP connection factory can define message
137         // parser / writer routines to be employed by individual connections.
138         final HttpConnectionFactory<ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
139                 h1Config, connectionConfig, requestWriterFactory, responseParserFactory);
140 
141         // Client HTTP connection objects when fully initialized can be bound to
142         // an arbitrary network socket. The process of network socket initialization,
143         // its connection to a remote address and binding to a local one is controlled
144         // by a connection socket factory.
145 
146         // SSL context for secure connections can be created either based on
147         // system or application specific properties.
148         final SSLContext sslContext = SSLContexts.createSystemDefault();
149 
150         // Create a registry of custom connection socket factories for supported
151         // protocol schemes.
152         final SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
153 
154         // Use custom DNS resolver to override the system DNS resolution.
155         final DnsResolver dnsResolver = new SystemDefaultDnsResolver() {
156 
157             @Override
158             public InetAddress[] resolve(final String host) throws UnknownHostException {
159                 if (host.equalsIgnoreCase("myhost")) {
160                     return new InetAddress[] { InetAddress.getByAddress(new byte[] {127, 0, 0, 1}) };
161                 } else {
162                     return super.resolve(host);
163                 }
164             }
165 
166         };
167 
168         // Create a connection manager with custom configuration.
169         final PoolingHttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create()
170                 .setSSLSocketFactory(sslConnectionSocketFactory)
171                 .setConnectionFactory(connFactory)
172                 .setDnsResolver(dnsResolver)
173                 .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
174                 .setConnPoolPolicy(PoolReusePolicy.LIFO)
175                 .build();
176 
177         // Configure the connection manager to use socket configuration either
178         // by default or for a specific host.
179         connManager.setDefaultSocketConfig(SocketConfig.custom()
180                 .setTcpNoDelay(true)
181                 .build());
182         // Validate connections after 10 sec of inactivity
183         connManager.setDefaultConnectionConfig(ConnectionConfig.custom()
184                 .setConnectTimeout(Timeout.ofSeconds(30))
185                 .setSocketTimeout(Timeout.ofSeconds(30))
186                 .setValidateAfterInactivity(TimeValue.ofSeconds(10))
187                 .setTimeToLive(TimeValue.ofHours(1))
188                 .build());
189 
190         // Use TLS v1.3 only
191         connManager.setDefaultTlsConfig(TlsConfig.custom()
192                 .setHandshakeTimeout(Timeout.ofSeconds(30))
193                 .setSupportedProtocols(TLS.V_1_3)
194                 .build());
195 
196         // Configure total max or per route limits for persistent connections
197         // that can be kept in the pool or leased by the connection manager.
198         connManager.setMaxTotal(100);
199         connManager.setDefaultMaxPerRoute(10);
200         connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 20);
201 
202         // Use custom cookie store if necessary.
203         final CookieStore cookieStore = new BasicCookieStore();
204         // Use custom credentials provider if necessary.
205         final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
206                 .build();
207         // Create global request configuration
208         final RequestConfig defaultRequestConfig = RequestConfig.custom()
209             .setCookieSpec(StandardCookieSpec.STRICT)
210             .setExpectContinueEnabled(true)
211             .setTargetPreferredAuthSchemes(Arrays.asList(StandardAuthScheme.DIGEST))
212             .setProxyPreferredAuthSchemes(Collections.singletonList(StandardAuthScheme.BASIC))
213             .build();
214 
215         // Create an HttpClient with the given custom dependencies and configuration.
216 
217         try (final CloseableHttpClient httpclient = HttpClients.custom()
218                 .setConnectionManager(connManager)
219                 .setDefaultCookieStore(cookieStore)
220                 .setDefaultCredentialsProvider(credentialsProvider)
221                 .setProxy(new HttpHost("myproxy", 8080))
222                 .setDefaultRequestConfig(defaultRequestConfig)
223                 .build()) {
224             final HttpGet httpget = new HttpGet("http://httpbin.org/get");
225             // Request configuration can be overridden at the request level.
226             // They will take precedence over the one set at the client level.
227             final RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
228                     .setConnectionRequestTimeout(Timeout.ofSeconds(5))
229                     .build();
230             httpget.setConfig(requestConfig);
231 
232             // Execution context can be customized locally.
233             // Contextual attributes set the local context level will take
234             // precedence over those set at the client level.
235             final HttpClientContext context = ContextBuilder.create()
236                     .useCookieStore(cookieStore)
237                     .useCredentialsProvider(credentialsProvider)
238                     .build();
239 
240             System.out.println("Executing request " + httpget.getMethod() + " " + httpget.getUri());
241             httpclient.execute(httpget, context, response -> {
242                 System.out.println("----------------------------------------");
243                 System.out.println(httpget + "->" + new StatusLine(response));
244                 EntityUtils.consume(response.getEntity());
245                 return null;
246             });
247             // Last executed request
248             context.getRequest();
249             // Execution route
250             context.getHttpRoute();
251             // Auth exchanges
252             context.getAuthExchanges();
253             // Cookie origin
254             context.getCookieOrigin();
255             // Cookie spec used
256             context.getCookieSpec();
257             // User security token
258             context.getUserToken();
259         }
260     }
261 
262 }
263