diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java b/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java new file mode 100644 index 000000000..65ce15f68 --- /dev/null +++ b/httpclient/src/examples/org/apache/http/examples/client/ClientConfiguration.java @@ -0,0 +1,240 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.examples.client; + +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; + +import javax.net.ssl.SSLContext; + +import org.apache.http.Consts; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpResponseFactory; +import org.apache.http.client.CookieStore; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.AuthSchemes; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.ConnectionConfig; +import org.apache.http.config.MessageConstraints; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.DnsResolver; +import org.apache.http.conn.HttpConnectionFactory; +import org.apache.http.conn.SocketClientConnection; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainSocketFactory; +import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.conn.ssl.X509HostnameVerifier; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.client.BasicCookieStore; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.DefaultClientConnectionFactory; +import org.apache.http.impl.conn.DefaultHttpResponseParserFactory; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.impl.conn.SystemDefaultDnsResolver; +import org.apache.http.impl.io.DefaultHttpRequestWriterFactory; +import org.apache.http.io.HttpMessageParserFactory; +import org.apache.http.io.HttpMessageWriterFactory; + +/** + * This example demonstrates how to customize and configure the most common aspects + * of HTTP request execution and connection management. + */ +public class ClientConfiguration { + + public final static void main(String[] args) throws Exception { + + // Use a custom response factory to customize the way HTTP response + // objects are generated. + HttpResponseFactory responseFactory = new DefaultHttpResponseFactory(); + + // Use custom message parser / writer to customize the way HTTP + // messages are parsed from and written out to the data stream. + HttpMessageParserFactory responseParserFactory = new DefaultHttpResponseParserFactory( + responseFactory); + HttpMessageWriterFactory requestWriterFactory = new DefaultHttpRequestWriterFactory(); + + // Use a custom connection factory to customize the process of + // initialization of outgoing HTTP connections. Beside standard connection + // configuration parameters HTTP connection factory can control the size of + // input / output buffers as well as determine message parser / writer routines + // to be employed by individual connections. + HttpConnectionFactory connFactory = new DefaultClientConnectionFactory( + 8 * 1024, requestWriterFactory, responseParserFactory); + + // Client HTTP connection objects when fully initialized can be bound to + // an arbitrary network socket. The process of network socket initialization, + // its connection to a remote address and binding to a local one is controlled + // by a connection socket factory. + + // SSL context for secure connections can be created either based on + // system or application specific properties. + SSLContext sslcontext = SSLSocketFactory.createSystemSSLContext(); + // Use custom hostname verifier to customize SSL hostname verification. + X509HostnameVerifier hostnameVerifier = new BrowserCompatHostnameVerifier(); + + // Create a registry of custom connection socket factories for supported + // protocol schemes. + Registry socketFactoryRegistry = RegistryBuilder.create() + .register("http", PlainSocketFactory.INSTANCE) + .register("https", new SSLSocketFactory(sslcontext, hostnameVerifier)) + .build(); + + // Use custom DNS resolver to override the system DNS resolution. + DnsResolver dnsResolver = new SystemDefaultDnsResolver(); + + // Create a connection manager with custom configuration. + PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager( + socketFactoryRegistry, connFactory, dnsResolver); + + // Create socket configuration + SocketConfig socketConfig = SocketConfig.custom() + .setTcpNoDelay(true) + .build(); + // Configure the connection manager to use socket configuration either + // by default or for a specific host. + connManager.setDefaultSocketConfig(socketConfig); + connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig); + + // Create message constraints + MessageConstraints messageConstraints = MessageConstraints.custom() + .setMaxHeaderCount(200) + .setMaxLineLength(2000) + .build(); + // Create connection configuration + ConnectionConfig connectionConfig = ConnectionConfig.custom() + .setMalformedInputAction(CodingErrorAction.IGNORE) + .setUnmappableInputAction(CodingErrorAction.IGNORE) + .setCharset(Consts.UTF_8) + .setMessageConstraints(messageConstraints) + .build(); + // Configure the connection manager to use connection configuration either + // by default or for a specific host. + connManager.setDefaultConnectionConfig(connectionConfig); + connManager.setConnectionConfig(new HttpHost("somehost", 80), ConnectionConfig.DEFAULT); + + // Configure total max or per route limits for persistent connections + // that can be kept in the pool or leased by the connection manager. + connManager.setMaxTotal(100); + connManager.setDefaultMaxPerRoute(10); + connManager.setMaxPerRoute(new HttpRoute(new HttpHost("somehost", 80)), 20); + + // Use custom cookie store if necessary. + CookieStore cookieStore = new BasicCookieStore(); + // Use custom credentials provider if necessary. + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + // Create global request configuration + RequestConfig defaultRequestConfig = RequestConfig.custom() + .setCookieSpec(CookieSpecs.BEST_MATCH) + .setExpectContinueEnabled(true) + .setStaleConnectionCheckEnabled(true) + .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST)) + .setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)) + .setDefaultProxy(new HttpHost("myproxy", 8080)) + .build(); + + // Create an HttpClient with the given custom dependencies and configuration. + CloseableHttpClient httpclient = HttpClients.custom() + .setConnectionManager(connManager) + .setCookieStore(cookieStore) + .setCredentialsProvider(credentialsProvider) + .setDefaultRequestConfig(defaultRequestConfig) + .build(); + + try { + HttpGet httpget = new HttpGet("http://www.apache.org/"); + // Request configuration can be overridden at the request level. + // They will take precedence over the one set at the client level. + RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig) + .setSocketTimeout(5000) + .setConnectTimeout(5000) + .setConnectionRequestTimeout(5000) + .build(); + httpget.setConfig(requestConfig); + + // Execution context can be customized locally. + HttpClientContext context = HttpClientContext.create(); + // Contextual attributes set the local context level will take + // precedence over those set at the client level. + context.setCookieStore(cookieStore); + context.setCredentialsProvider(credentialsProvider); + context.setSocketFactoryRegistry(socketFactoryRegistry); + + System.out.println("executing request " + httpget.getURI()); + CloseableHttpResponse response = httpclient.execute(httpget, context); + try { + HttpEntity entity = response.getEntity(); + + System.out.println("----------------------------------------"); + System.out.println(response.getStatusLine()); + if (entity != null) { + System.out.println("Response content length: " + entity.getContentLength()); + } + System.out.println("----------------------------------------"); + + // Once the request has been executed the local context can + // be used to examine updated state and various objects affected + // by the request execution. + + // Last executed request + context.getRequest(); + // Execution route + context.getHttpRoute(); + // Target auth state + context.getTargetAuthState(); + // Proxy auth state + context.getTargetAuthState(); + // Cookie origin + context.getCookieOrigin(); + // Cookie spec used + context.getCookieSpec(); + // User security token + context.getUserToken(); + + } finally { + response.close(); + } + } finally { + httpclient.close(); + } + } + +} + diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java b/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java deleted file mode 100644 index dde3ffd9b..000000000 --- a/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteDirect.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package org.apache.http.examples.client; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; - -/** - * How to send a request directly using {@link HttpClient}. - * - * @since 4.0 - */ -public class ClientExecuteDirect { - - public static void main(String[] args) throws Exception { - CloseableHttpClient httpclient = HttpClients.createDefault(); - try { - HttpHost target = new HttpHost("www.apache.org", 80, "http"); - HttpGet request = new HttpGet("/"); - - System.out.println("executing request to " + target); - - CloseableHttpResponse response = httpclient.execute(target, request); - try { - HttpEntity entity = response.getEntity(); - - System.out.println("----------------------------------------"); - System.out.println(response.getStatusLine()); - Header[] headers = response.getAllHeaders(); - for (int i = 0; i < headers.length; i++) { - System.out.println(headers[i]); - } - System.out.println("----------------------------------------"); - - if (entity != null) { - System.out.println(EntityUtils.toString(entity)); - } - } finally { - response.close(); - } - } finally { - httpclient.close(); - } - } - -} diff --git a/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java b/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java index e069cdc17..6f6ae2fae 100644 --- a/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java +++ b/httpclient/src/examples/org/apache/http/examples/client/ClientWithResponseHandler.java @@ -27,11 +27,16 @@ package org.apache.http.examples.client; +import java.io.IOException; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; /** * This example demonstrates the use of the {@link ResponseHandler} to simplify @@ -46,8 +51,21 @@ public class ClientWithResponseHandler { System.out.println("executing request " + httpget.getURI()); - // Create a response handler - ResponseHandler responseHandler = new BasicResponseHandler(); + // Create a custom response handler + ResponseHandler responseHandler = new ResponseHandler() { + + public String handleResponse( + final HttpResponse response) throws ClientProtocolException, IOException { + int status = response.getStatusLine().getStatusCode(); + if (status >= 200 && status < 300) { + HttpEntity entity = response.getEntity(); + return entity != null ? EntityUtils.toString(entity) : null; + } else { + throw new ClientProtocolException("Unexpected response status: " + status); + } + } + + }; String responseBody = httpclient.execute(httpget, responseHandler); System.out.println("----------------------------------------"); System.out.println(responseBody); diff --git a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java index 79be403ca..0d7743e28 100644 --- a/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java +++ b/httpclient/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java @@ -349,7 +349,10 @@ public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeL return sslcontext; } - private static SSLContext createDefaultSSLContext() throws SSLInitializationException { + /** + * @since 4.3 + */ + public static SSLContext createDefaultSSLContext() throws SSLInitializationException { try { return createSSLContext(TLS, null, null, null, null, null); } catch (Exception ex) { @@ -357,7 +360,10 @@ public class SSLSocketFactory implements LayeredConnectionSocketFactory, SchemeL } } - private static SSLContext createSystemSSLContext() throws SSLInitializationException { + /** + * @since 4.3 + */ + public static SSLContext createSystemSSLContext() throws SSLInitializationException { try { return createSystemSSLContext(TLS, null); } catch (Exception ex) { diff --git a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionFactory.java b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionFactory.java index cb7877c30..3dd8ce555 100644 --- a/httpclient/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionFactory.java +++ b/httpclient/src/main/java/org/apache/http/impl/conn/DefaultClientConnectionFactory.java @@ -32,10 +32,16 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; import org.apache.http.annotation.Immutable; import org.apache.http.config.ConnectionConfig; import org.apache.http.conn.HttpConnectionFactory; import org.apache.http.conn.SocketClientConnection; +import org.apache.http.impl.io.DefaultHttpRequestWriterFactory; +import org.apache.http.io.HttpMessageParserFactory; +import org.apache.http.io.HttpMessageWriterFactory; +import org.apache.http.util.Args; /** * @since 4.3 @@ -45,6 +51,36 @@ public class DefaultClientConnectionFactory implements HttpConnectionFactory requestWriterFactory; + private final HttpMessageParserFactory responseParserFactory; + + public DefaultClientConnectionFactory( + int bufferSize, + final HttpMessageWriterFactory requestWriterFactory, + final HttpMessageParserFactory responseParserFactory) { + super(); + this.bufferSize = Args.notNegative(bufferSize, "Buffer size"); + this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory : + DefaultHttpRequestWriterFactory.INSTANCE; + this.responseParserFactory = responseParserFactory != null ? responseParserFactory : + DefaultHttpResponseParserFactory.INSTANCE; + } + + public DefaultClientConnectionFactory( + final HttpMessageParserFactory responseParserFactory) { + this(8 * 1024, null, responseParserFactory); + } + + public DefaultClientConnectionFactory( + int bufferSize) { + this(bufferSize, null, null); + } + + public DefaultClientConnectionFactory() { + this(8 * 1024, null, null); + } + public SocketClientConnection create(final ConnectionConfig config) { ConnectionConfig cconfig = config != null ? config : ConnectionConfig.DEFAULT; CharsetDecoder chardecoder = null; @@ -62,11 +98,12 @@ public class DefaultClientConnectionFactory implements HttpConnectionFactory socketFactoryRegistry, + final HttpConnectionFactory connFactory, + final DnsResolver dnsResolver) { + this(socketFactoryRegistry, connFactory, null, dnsResolver, -1, TimeUnit.MILLISECONDS); + } + public PoolingHttpClientConnectionManager( final Registry socketFactoryRegistry, final HttpConnectionFactory connFactory,