Changelog:

* Removed static instances from SchemeRegistry, CookieSpecRegistry and AuthSchemeRegistry
* Made sure there is only one instance of SchemeRegistry per HttpClient / ClientConnectionManager
* HostConfiguration, HttpRoute and RouteTracker no longer implement Cloneable as they do not override #clone() method
* AbstractHttpClient should now be threading safe
* DefaultHttpClient populates HTTP execution context with data required for request execution

git-svn-id: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpclient/trunk@534769 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2007-05-03 09:51:22 +00:00
parent 9fb978483a
commit 7cda278cd5
19 changed files with 404 additions and 251 deletions

View File

@ -50,12 +50,6 @@ import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams; import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams; import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
@ -139,16 +133,7 @@ public class ClientExecuteDirect {
// new SingleClientConnManager(getParams(), supportedSchemes); // new SingleClientConnManager(getParams(), supportedSchemes);
DefaultHttpClient dhc = DefaultHttpClient dhc =
new DefaultHttpClient(getParams(), ccm, supportedSchemes); new DefaultHttpClient(ccm, getParams());
BasicHttpProcessor bhp = dhc.getProcessor();
// Required protocol interceptors
bhp.addInterceptor(new RequestContent());
bhp.addInterceptor(new RequestTargetHost());
// Recommended protocol interceptors
bhp.addInterceptor(new RequestConnControl());
bhp.addInterceptor(new RequestUserAgent());
bhp.addInterceptor(new RequestExpectContinue());
return dhc; return dhc;
} }

View File

@ -53,12 +53,6 @@ import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams; import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams; import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
@ -151,16 +145,7 @@ public class ClientExecuteProxy {
// new SingleClientConnManager(getParams(), supportedSchemes); // new SingleClientConnManager(getParams(), supportedSchemes);
DefaultHttpClient dhc = DefaultHttpClient dhc =
new DefaultHttpClient(getParams(), ccm, supportedSchemes); new DefaultHttpClient(ccm, getParams());
BasicHttpProcessor bhp = dhc.getProcessor();
// Required protocol interceptors
bhp.addInterceptor(new RequestContent());
bhp.addInterceptor(new RequestTargetHost());
// Recommended protocol interceptors
bhp.addInterceptor(new RequestConnControl());
bhp.addInterceptor(new RequestUserAgent());
bhp.addInterceptor(new RequestExpectContinue());
return dhc; return dhc;
} }

View File

@ -35,20 +35,15 @@ import org.apache.http.HttpEntity;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion; import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.PlainSocketFactory; import org.apache.http.conn.PlainSocketFactory;
import org.apache.http.conn.Scheme; import org.apache.http.conn.Scheme;
import org.apache.http.conn.SchemeRegistry; import org.apache.http.conn.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.BasicHttpParams; import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams; import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
/** /**
* How to abort an HTTP method before its normal completion. * How to abort an HTTP method before its normal completion.
@ -74,20 +69,8 @@ public class MethodAbort {
HttpProtocolParams.setContentCharset(params, "UTF-8"); HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUserAgent(params, "Jakarta-HttpClient/4.0"); HttpProtocolParams.setUserAgent(params, "Jakarta-HttpClient/4.0");
DefaultHttpClient httpclient = new DefaultHttpClient( HttpClient httpclient = new DefaultHttpClient(params);
params,
new SingleClientConnManager(params, supportedSchemes),
supportedSchemes);
// Required protocol interceptors
httpclient.getProcessor().addInterceptor(new RequestContent());
httpclient.getProcessor().addInterceptor(new RequestTargetHost());
// Recommended protocol interceptors
httpclient.getProcessor().addInterceptor(new RequestConnControl());
httpclient.getProcessor().addInterceptor(new RequestUserAgent());
httpclient.getProcessor().addInterceptor(new RequestExpectContinue());
HttpHost target = new HttpHost("www.apache.org", 80, "http"); HttpHost target = new HttpHost("www.apache.org", 80, "http");
HttpGet httpget = new HttpGet("/"); HttpGet httpget = new HttpGet("/");

View File

@ -48,8 +48,6 @@ import org.apache.http.params.HttpParams;
*/ */
public final class AuthSchemeRegistry { public final class AuthSchemeRegistry {
public final static AuthSchemeRegistry DEFAULT = new AuthSchemeRegistry();
private final Map registeredSchemes = new LinkedHashMap(); private final Map registeredSchemes = new LinkedHashMap();
/** /**

View File

@ -0,0 +1,48 @@
/*
* $HeadURL$
* $Revision$
* $Date$
*
* ====================================================================
* 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
* <http://www.apache.org/>.
*
*/
package org.apache.http.client.protocol;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpExecutionContext;
public class HttpClientContext extends HttpExecutionContext {
public static final String SCHEME_REGISTRY = "http.scheme-registry";
public static final String COOKIESPEC_REGISTRY = "http.cookiespec-registry";
public static final String AUTHSCHEME_REGISTRY = "http.authscheme-registry";
public static final String HTTP_STATE = "http.state";
public HttpClientContext(final HttpContext parentContext) {
super(parentContext);
}
}

View File

@ -49,6 +49,8 @@ package org.apache.http.conn;
*/ */
public interface ClientConnectionManager { public interface ClientConnectionManager {
SchemeRegistry getSchemeRegistry();
/** /**
* Obtains a connection. * Obtains a connection.
* This method will block until a connection becomes available * This method will block until a connection becomes available

View File

@ -54,7 +54,7 @@ import org.apache.http.util.LangUtils;
* *
* @since 4.0 * @since 4.0
*/ */
public class HostConfiguration implements Cloneable { public class HostConfiguration {
/** /**
* Constant representing a configuration for <i>any</i> host. * Constant representing a configuration for <i>any</i> host.

View File

@ -50,7 +50,7 @@ import org.apache.http.util.CharArrayBuffer;
* *
* @since 4.0 * @since 4.0
*/ */
public final class HttpRoute implements Cloneable { public final class HttpRoute {
/** The target host to connect to. */ /** The target host to connect to. */
private final HttpHost targetHost; private final HttpHost targetHost;

View File

@ -48,7 +48,7 @@ import org.apache.http.util.CharArrayBuffer;
* *
* @since 4.0 * @since 4.0
*/ */
public final class RouteTracker implements Cloneable { public final class RouteTracker {
/** The target host to connect to. */ /** The target host to connect to. */
private final HttpHost targetHost; private final HttpHost targetHost;

View File

@ -52,17 +52,6 @@ import org.apache.http.HttpHost;
*/ */
public final class SchemeRegistry { public final class SchemeRegistry {
/**
* A default scheme registry.
* It is empty by default, but can be initialized by any application.
* The default scheme registry should only be used by applications that
* know for sure that this class is NOT shared with any other application.
* For example a Servlet, Portlet or EJB should not rely on being the
* only user of this class.
*/
public final static SchemeRegistry DEFAULT = new SchemeRegistry();
/** The available schemes in this registry. */ /** The available schemes in this registry. */
private final Map registeredSchemes; private final Map registeredSchemes;

View File

@ -51,8 +51,6 @@ import org.apache.http.params.HttpParams;
*/ */
public final class CookieSpecRegistry { public final class CookieSpecRegistry {
public final static CookieSpecRegistry DEFAULT = new CookieSpecRegistry();
private final Map registeredSpecs; private final Map registeredSpecs;
public CookieSpecRegistry() { public CookieSpecRegistry() {

View File

@ -32,21 +32,29 @@
package org.apache.http.impl.client; package org.apache.http.impl.client;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpException;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpException; import org.apache.http.HttpResponseInterceptor;
import org.apache.http.ConnectionReuseStrategy; import org.apache.http.auth.AuthSchemeRegistry;
import org.apache.http.params.HttpParams; import org.apache.http.client.ClientRequestDirector;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.SyncHttpExecutionContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.conn.SchemeRegistry;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpState;
import org.apache.http.client.RoutedRequest; import org.apache.http.client.RoutedRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.cookie.CookieSpecRegistry;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpExecutionContext;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.HttpRequestInterceptorList;
import org.apache.http.protocol.HttpResponseInterceptorList;
@ -62,84 +70,79 @@ import org.apache.http.client.RoutedRequest;
* @since 4.0 * @since 4.0
*/ */
public abstract class AbstractHttpClient public abstract class AbstractHttpClient
implements HttpClient { implements HttpClient, HttpRequestInterceptorList, HttpResponseInterceptorList {
/** The default context. */ /** The default context. */
protected HttpContext defaultContext; private HttpContext defaultContext;
/** The parameters. */ /** The parameters. */
protected HttpParams defaultParams; private HttpParams defaultParams;
/** The connection manager. */ /** The connection manager. */
protected ClientConnectionManager connManager; private ClientConnectionManager connManager;
/** The connection re-use strategy. */ /** The connection re-use strategy. */
protected ConnectionReuseStrategy reuseStrategy; private ConnectionReuseStrategy reuseStrategy;
/** The HTTP processor, if defined. */ /** The cookie spec registry. */
protected BasicHttpProcessor httpProcessor; private CookieSpecRegistry supportedCookieSpecs;
/** The scheme registry. */ /** The authentication scheme registry. */
protected SchemeRegistry supportedSchemes; private AuthSchemeRegistry supportedAuthSchemes;
/** The HTTP processor. */
private BasicHttpProcessor httpProcessor;
/** The default HTTP state. */
private HttpState defaultState;
/** /**
* Creates a new HTTP client. * Creates a new HTTP client.
* *
* @param context the context, or <code>null</code> to use an instance of
* {@link SyncHttpExecutionContext SyncHttpExecutionContext}
* @param params the parameters
* @param conman the connection manager * @param conman the connection manager
* @param schemes the scheme registry, or * @param params the parameters
* <code>null</code> to use the
* {@link SchemeRegistry#DEFAULT default}
*/ */
protected AbstractHttpClient(HttpContext context, HttpParams params, protected AbstractHttpClient(
ClientConnectionManager conman, final ClientConnectionManager conman,
SchemeRegistry schemes) { final HttpParams params) {
if (params == null) defaultParams = params;
throw new IllegalArgumentException connManager = conman;
("Parameters must not be null.");
if (conman == null)
throw new IllegalArgumentException
("Connection manager must not be null.");
defaultContext = (context != null) ?
context : new SyncHttpExecutionContext(null);
defaultParams = params;
connManager = conman;
supportedSchemes = (schemes != null) ?
schemes : SchemeRegistry.DEFAULT;
// to be initialized by derived class constructors, if needed:
reuseStrategy = null;
httpProcessor = null;
} // constructor } // constructor
protected abstract HttpParams createHttpParams();
protected abstract HttpContext createHttpContext();
protected abstract ClientConnectionManager createClientConnectionManager();
protected abstract AuthSchemeRegistry createAuthSchemeRegistry();
protected abstract CookieSpecRegistry createCookieSpecRegistry();
protected abstract ConnectionReuseStrategy createConnectionReuseStrategy();
protected abstract BasicHttpProcessor createHttpProcessor();
protected abstract HttpState createHttpState();
protected abstract void populateContext(HttpContext context);
// non-javadoc, see interface HttpClient // non-javadoc, see interface HttpClient
public final HttpContext getContext() { public synchronized final HttpParams getParams() {
return defaultContext; if (defaultParams == null) {
} defaultParams = createHttpParams();
}
/**
* Replaces the default context.
*
* @param context the new default context
*/
public void setContext(HttpContext context) {
if (context == null)
throw new IllegalArgumentException
("Context must not be null.");
defaultContext = context;
}
// non-javadoc, see interface HttpClient
public final HttpParams getParams() {
return defaultParams; return defaultParams;
} }
@ -150,16 +153,16 @@ public abstract class AbstractHttpClient
* *
* @param params the new default parameters * @param params the new default parameters
*/ */
public void setParams(HttpParams params) { public synchronized void setParams(HttpParams params) {
if (params == null)
throw new IllegalArgumentException
("Parameters must not be null.");
defaultParams = params; defaultParams = params;
} }
// non-javadoc, see interface HttpClient // non-javadoc, see interface HttpClient
public final ClientConnectionManager getConnectionManager() { public synchronized final ClientConnectionManager getConnectionManager() {
if (connManager == null) {
connManager = createClientConnectionManager();
}
return connManager; return connManager;
} }
@ -168,23 +171,116 @@ public abstract class AbstractHttpClient
// derived classes may offer that method at their own risk // derived classes may offer that method at their own risk
/** public synchronized final AuthSchemeRegistry getAuthSchemes() {
* Obtains the HTTP processor. if (supportedAuthSchemes == null) {
* supportedAuthSchemes = createAuthSchemeRegistry();
* @return the HTTP processor, or <code>null</code> if not set }
*/ return supportedAuthSchemes;
public BasicHttpProcessor getProcessor() { }
public synchronized void setAuthSchemes(final AuthSchemeRegistry authSchemeRegistry) {
supportedAuthSchemes = authSchemeRegistry;
}
public synchronized final CookieSpecRegistry getCookieSpecs() {
if (supportedCookieSpecs == null) {
supportedCookieSpecs = createCookieSpecRegistry();
}
return supportedCookieSpecs;
}
public synchronized void setCookieSpecs(final CookieSpecRegistry cookieSpecRegistry) {
supportedCookieSpecs = cookieSpecRegistry;
}
public synchronized final ConnectionReuseStrategy getConnectionReuseStrategy() {
if (reuseStrategy == null) {
reuseStrategy = createConnectionReuseStrategy();
}
return reuseStrategy;
}
public synchronized void setReuseStrategy(final ConnectionReuseStrategy reuseStrategy) {
this.reuseStrategy = reuseStrategy;
}
public synchronized final HttpState getState() {
if (defaultState == null) {
defaultState = createHttpState();
}
return defaultState;
}
public synchronized void setState(final HttpState state) {
defaultState = state;
}
protected synchronized final BasicHttpProcessor getHttpProcessor() {
if (httpProcessor == null) {
httpProcessor = createHttpProcessor();
}
return httpProcessor; return httpProcessor;
} }
/** public synchronized final HttpContext getContext() {
* Specifies the HTTP processor. if (defaultContext == null) {
* defaultContext = createHttpContext();
* @param hproc the HTTP processor, or <code>null</code> to unset }
*/ return defaultContext;
public void setProcessor(BasicHttpProcessor hproc) { }
httpProcessor = hproc;
public synchronized void addResponseInterceptor(final HttpResponseInterceptor itcp) {
getHttpProcessor().addInterceptor(itcp);
}
public synchronized void clearResponseInterceptors() {
getHttpProcessor().clearResponseInterceptors();
}
public synchronized HttpResponseInterceptor getResponseInterceptor(int index) {
return getHttpProcessor().getResponseInterceptor(index);
}
public synchronized int getResponseInterceptorCount() {
return getHttpProcessor().getResponseInterceptorCount();
}
public synchronized void addRequestInterceptor(final HttpRequestInterceptor itcp) {
getHttpProcessor().addInterceptor(itcp);
}
public synchronized void clearRequestInterceptors() {
getHttpProcessor().clearRequestInterceptors();
}
public synchronized HttpRequestInterceptor getRequestInterceptor(int index) {
return getHttpProcessor().getRequestInterceptor(index);
}
public synchronized int getRequestInterceptorCount() {
return getHttpProcessor().getRequestInterceptorCount();
}
public synchronized void setInterceptors(final List itcps) {
getHttpProcessor().setInterceptors(itcps);
} }
@ -204,7 +300,7 @@ public abstract class AbstractHttpClient
public final HttpResponse execute(HttpHost target, HttpRequest request) public final HttpResponse execute(HttpHost target, HttpRequest request)
throws HttpException, IOException { throws HttpException, IOException {
return execute(target, request, defaultContext); return execute(target, request, null);
} }
@ -229,12 +325,63 @@ public abstract class AbstractHttpClient
// Otherwise, the null target is detected in determineRoute(). // Otherwise, the null target is detected in determineRoute().
if (context == null) if (context == null)
context = defaultContext; context = new HttpExecutionContext(getContext());
RoutedRequest roureq = determineRoute(target, request, context); RoutedRequest roureq = determineRoute(target, request, context);
return execute(roureq, context); return execute(roureq, context);
} }
// non-javadoc, see interface HttpClient
public final HttpResponse execute(RoutedRequest roureq, HttpContext context)
throws HttpException, IOException {
if (roureq == null) {
throw new IllegalArgumentException
("Routed request must not be null.");
}
if (roureq.getRequest() == null) {
throw new IllegalArgumentException
("Request must not be null.");
}
if (roureq.getRoute() == null) {
throw new IllegalArgumentException
("Route must not be null.");
}
if (context == null)
context = new HttpExecutionContext(getContext());
ClientRequestDirector director = null;
// Initialize the request execution context making copies of
// all shared objects that are potentially threading unsafe.
synchronized (this) {
// Populate the context for this request
populateContext(context);
// Create a copy of the HTTP processor
BasicHttpProcessor httpproc = getHttpProcessor().copy();
// Create an HTTP request executor for this request
HttpRequestExecutor reqexec = new HttpRequestExecutor(httpproc);
reqexec.setParams(getParams());
// Create a director for this request
director = new DefaultClientRequestDirector(
getConnectionManager(),
getConnectionReuseStrategy(),
reqexec);
}
HttpResponse response = director.execute(roureq, context);
// If the response depends on the connection, the director
// will have set up an auto-release input stream.
//@@@ or move that logic here into the client?
//@@@ "finalize" response, to allow for buffering of entities?
//@@@ here or in director?
return response;
} // execute
/** /**
* Determines the route for a request. * Determines the route for a request.

View File

@ -48,7 +48,6 @@ import org.apache.http.conn.HttpRoute;
import org.apache.http.conn.ManagedClientConnection; import org.apache.http.conn.ManagedClientConnection;
import org.apache.http.conn.RouteDirector; import org.apache.http.conn.RouteDirector;
import org.apache.http.message.BasicHttpRequest; import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpExecutionContext; import org.apache.http.protocol.HttpExecutionContext;
import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.protocol.HttpRequestExecutor;
@ -80,22 +79,17 @@ public class DefaultClientRequestDirector
/** The request executor. */ /** The request executor. */
protected final HttpRequestExecutor requestExec; protected final HttpRequestExecutor requestExec;
/** The parameters. */
protected final HttpParams defaultParams;
/** The currently allocated connection. */ /** The currently allocated connection. */
protected ManagedClientConnection managedConn; protected ManagedClientConnection managedConn;
public DefaultClientRequestDirector(ClientConnectionManager conman, public DefaultClientRequestDirector(ClientConnectionManager conman,
ConnectionReuseStrategy reustrat, ConnectionReuseStrategy reustrat,
HttpRequestExecutor reqexec, HttpRequestExecutor reqexec) {
HttpParams params) {
this.connManager = conman; this.connManager = conman;
this.reuseStrategy = reustrat; this.reuseStrategy = reustrat;
this.requestExec = reqexec; this.requestExec = reqexec;
this.defaultParams = params;
this.managedConn = null; this.managedConn = null;
@ -224,16 +218,16 @@ public class DefaultClientRequestDirector
case RouteDirector.CONNECT_TARGET: case RouteDirector.CONNECT_TARGET:
case RouteDirector.CONNECT_PROXY: case RouteDirector.CONNECT_PROXY:
managedConn.open(route, context, defaultParams); managedConn.open(route, context, requestExec.getParams());
break; break;
case RouteDirector.CREATE_TUNNEL: case RouteDirector.CREATE_TUNNEL:
boolean secure = createTunnel(route, context); boolean secure = createTunnel(route, context);
managedConn.tunnelCreated(secure, defaultParams); managedConn.tunnelCreated(secure, requestExec.getParams());
break; break;
case RouteDirector.LAYER_PROTOCOL: case RouteDirector.LAYER_PROTOCOL:
managedConn.layerProtocol(context, defaultParams); managedConn.layerProtocol(context, requestExec.getParams());
break; break;
case RouteDirector.UNREACHABLE: case RouteDirector.UNREACHABLE:

View File

@ -31,24 +31,33 @@
package org.apache.http.impl.client; package org.apache.http.impl.client;
import java.io.IOException;
import org.apache.http.ConnectionReuseStrategy; import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpException; import org.apache.http.HttpException;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.auth.AuthSchemeRegistry;
import org.apache.http.client.ClientRequestDirector; import org.apache.http.client.HttpState;
import org.apache.http.client.RoutedRequest; import org.apache.http.client.RoutedRequest;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.HttpRoute; import org.apache.http.conn.HttpRoute;
import org.apache.http.conn.PlainSocketFactory;
import org.apache.http.conn.Scheme; import org.apache.http.conn.Scheme;
import org.apache.http.conn.SchemeRegistry; import org.apache.http.conn.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.cookie.CookieSpecRegistry;
import org.apache.http.impl.DefaultConnectionReuseStrategy; import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestExecutor; import org.apache.http.protocol.RequestConnControl;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestExpectContinue;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.protocol.RequestUserAgent;
import org.apache.http.protocol.SyncHttpExecutionContext;
@ -77,79 +86,88 @@ public class DefaultHttpClient extends AbstractHttpClient {
* <code>null</code> to use the * <code>null</code> to use the
* {@link SchemeRegistry#DEFAULT default} * {@link SchemeRegistry#DEFAULT default}
*/ */
public DefaultHttpClient(HttpParams params, public DefaultHttpClient(
ClientConnectionManager conman, final ClientConnectionManager conman,
SchemeRegistry schemes) { final HttpParams params) {
super(conman, params);
}
super(null, params, conman, schemes);
public DefaultHttpClient(final HttpParams params) {
super(null, params);
}
httpProcessor = createProcessor();
reuseStrategy = createReuseStrategy(); protected HttpParams createHttpParams() {
return new BasicHttpParams();
}
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(
new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
} }
/** protected HttpContext createHttpContext() {
* Creates and initializes an HTTP processor. return new SyncHttpExecutionContext(null);
* This method is typically called by the constructor, }
* after the base class has been initialized.
*
* @return a new, initialized HTTP processor
*/
protected BasicHttpProcessor createProcessor() {
BasicHttpProcessor bhp = new BasicHttpProcessor();
//@@@ evaluate defaultParams to initialize interceptors protected ConnectionReuseStrategy createConnectionReuseStrategy() {
return new DefaultConnectionReuseStrategy();
}
return bhp; protected AuthSchemeRegistry createAuthSchemeRegistry() {
AuthSchemeRegistry registry = new AuthSchemeRegistry();
return registry;
} }
/** protected CookieSpecRegistry createCookieSpecRegistry() {
* Creates a connection reuse strategy. CookieSpecRegistry registry = new CookieSpecRegistry();
* This method is typically called by the constructor, return registry;
* after the base class has been initialized.
*/
protected ConnectionReuseStrategy createReuseStrategy() {
//@@@ evaluate defaultParams to determine implementation
ConnectionReuseStrategy rus = new DefaultConnectionReuseStrategy();
return rus;
} }
// non-javadoc, see interface HttpClient protected BasicHttpProcessor createHttpProcessor() {
public HttpResponse execute(RoutedRequest roureq, HttpContext context) BasicHttpProcessor httpproc = new BasicHttpProcessor();
throws HttpException, IOException { // Required protocol interceptors
httpproc.addInterceptor(new RequestContent());
httpproc.addInterceptor(new RequestTargetHost());
// Recommended protocol interceptors
httpproc.addInterceptor(new RequestConnControl());
httpproc.addInterceptor(new RequestUserAgent());
httpproc.addInterceptor(new RequestExpectContinue());
return httpproc;
}
if (roureq == null) {
throw new IllegalArgumentException
("Routed request must not be null.");
}
if (roureq.getRequest() == null) {
throw new IllegalArgumentException
("Request must not be null.");
}
if (roureq.getRoute() == null) {
throw new IllegalArgumentException
("Route must not be null.");
}
if (context == null) protected HttpState createHttpState() {
context = defaultContext; return new HttpState();
}
ClientRequestDirector director = createDirector(context);
HttpResponse response = director.execute(roureq, context);
// If the response depends on the connection, the director
// will have set up an auto-release input stream.
//@@@ or move that logic here into the client?
//@@@ "finalize" response, to allow for buffering of entities? protected void populateContext(final HttpContext context) {
//@@@ here or in director? context.setAttribute(
HttpClientContext.SCHEME_REGISTRY,
return response; getConnectionManager().getSchemeRegistry());
context.setAttribute(
} // execute HttpClientContext.AUTHSCHEME_REGISTRY,
getAuthSchemes());
context.setAttribute(
HttpClientContext.COOKIESPEC_REGISTRY,
getCookieSpecs());
context.setAttribute(
HttpClientContext.HTTP_STATE,
getState());
}
// non-javadoc, see base class AbstractHttpClient // non-javadoc, see base class AbstractHttpClient
@ -165,7 +183,8 @@ public class DefaultHttpClient extends AbstractHttpClient {
("Target host must not be null."); ("Target host must not be null.");
} }
Scheme schm = supportedSchemes.getScheme(target.getSchemeName()); SchemeRegistry schemeRegistry = getConnectionManager().getSchemeRegistry();
Scheme schm = schemeRegistry.getScheme(target.getSchemeName());
// as it is typically used for TLS/SSL, we assume that // as it is typically used for TLS/SSL, we assume that
// a layered scheme implies a secure connection // a layered scheme implies a secure connection
HttpRoute route = new HttpRoute(target, null, schm.isLayered()); HttpRoute route = new HttpRoute(target, null, schm.isLayered());
@ -174,23 +193,4 @@ public class DefaultHttpClient extends AbstractHttpClient {
} }
/**
* Creates a new director for a request execution.
*
* @param context the context to use for the execution,
* never <code>null</code>
*
* @return the new director for executing a method in the given context
*/
protected ClientRequestDirector createDirector(HttpContext context) {
//@@@ can we use a single reqexec without sacrificing thread safety?
//@@@ it seems wasteful to throw away both director and reqexec
HttpRequestExecutor reqexec = new HttpRequestExecutor(httpProcessor);
reqexec.setParams(defaultParams);
return new DefaultClientRequestDirector
(connManager, reuseStrategy, reqexec, defaultParams);
}
} // class DefaultHttpClient } // class DefaultHttpClient

View File

@ -86,7 +86,11 @@ public class DefaultClientConnectionOperator
* {@link SchemeRegistry#DEFAULT SchemeRegistry.DEFAULT} * {@link SchemeRegistry#DEFAULT SchemeRegistry.DEFAULT}
*/ */
public DefaultClientConnectionOperator(SchemeRegistry schemes) { public DefaultClientConnectionOperator(SchemeRegistry schemes) {
schemeRegistry = (schemes != null) ? schemes : SchemeRegistry.DEFAULT; if (schemes == null) {
throw new IllegalArgumentException
("Scheme registry must not be null.");
}
schemeRegistry = schemes;
} }

View File

@ -78,6 +78,9 @@ public class SingleClientConnManager implements ClientConnectionManager {
"Make sure to release the connection before allocating another one."; "Make sure to release the connection before allocating another one.";
/** The schemes supported by this connection manager. */
protected SchemeRegistry schemeRegistry;
/** The parameters of this connection manager. */ /** The parameters of this connection manager. */
protected HttpParams params = new BasicHttpParams(); protected HttpParams params = new BasicHttpParams();
@ -115,7 +118,11 @@ public class SingleClientConnManager implements ClientConnectionManager {
if (params == null) { if (params == null) {
throw new IllegalArgumentException("Parameters must not be null."); throw new IllegalArgumentException("Parameters must not be null.");
} }
if (schreg == null) {
throw new IllegalArgumentException("Scheme registry must not be null.");
}
this.params = params; this.params = params;
this.schemeRegistry = schreg;
this.connOperator = createConnectionOperator(schreg); this.connOperator = createConnectionOperator(schreg);
this.uniquePoolEntry = new PoolEntry(connOperator.createConnection()); this.uniquePoolEntry = new PoolEntry(connOperator.createConnection());
this.managedConn = null; this.managedConn = null;
@ -126,6 +133,11 @@ public class SingleClientConnManager implements ClientConnectionManager {
} // <constructor> } // <constructor>
public SchemeRegistry getSchemeRegistry() {
return this.schemeRegistry;
}
/** /**
* Hook for creating the connection operator. * Hook for creating the connection operator.
* It is called by the constructor. * It is called by the constructor.

View File

@ -104,6 +104,9 @@ public class ThreadSafeClientConnManager
private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap(); private static WeakHashMap ALL_CONNECTION_MANAGERS = new WeakHashMap();
/** The schemes supported by this connection manager. */
protected SchemeRegistry schemeRegistry;
/** The parameters of this connection manager. */ /** The parameters of this connection manager. */
private HttpParams params = new BasicHttpParams(); private HttpParams params = new BasicHttpParams();
@ -133,6 +136,7 @@ public class ThreadSafeClientConnManager
throw new IllegalArgumentException("Parameters must not be null."); throw new IllegalArgumentException("Parameters must not be null.");
} }
this.params = params; this.params = params;
this.schemeRegistry = schreg;
this.connectionPool = new ConnectionPool(); this.connectionPool = new ConnectionPool();
this.connOperator = createConnectionOperator(schreg); this.connOperator = createConnectionOperator(schreg);
this.isShutDown = false; this.isShutDown = false;
@ -143,7 +147,11 @@ public class ThreadSafeClientConnManager
} // <constructor> } // <constructor>
public SchemeRegistry getSchemeRegistry() {
return this.schemeRegistry;
}
// non-javadoc, see interface ClientConnectionManager // non-javadoc, see interface ClientConnectionManager
public ManagedClientConnection getConnection(HttpRoute route) { public ManagedClientConnection getConnection(HttpRoute route) {

View File

@ -63,7 +63,7 @@ public class TestCookiePolicy extends TestCase {
} }
public void testRegisterUnregisterCookieSpecFactory() { public void testRegisterUnregisterCookieSpecFactory() {
CookieSpecRegistry registry = CookieSpecRegistry.DEFAULT; CookieSpecRegistry registry = new CookieSpecRegistry();
List names = registry.getSpecNames(); List names = registry.getSpecNames();
assertNotNull(names); assertNotNull(names);
assertEquals(0, names.size()); assertEquals(0, names.size());
@ -98,7 +98,7 @@ public class TestCookiePolicy extends TestCase {
} }
public void testGetNewCookieSpec() { public void testGetNewCookieSpec() {
CookieSpecRegistry registry = CookieSpecRegistry.DEFAULT; CookieSpecRegistry registry = new CookieSpecRegistry();
registry.register(CookieSpecParams.BROWSER_COMPATIBILITY, registry.register(CookieSpecParams.BROWSER_COMPATIBILITY,
new BrowserCompatSpecFactory()); new BrowserCompatSpecFactory());
registry.register(CookieSpecParams.NETSCAPE, registry.register(CookieSpecParams.NETSCAPE,
@ -131,7 +131,7 @@ public class TestCookiePolicy extends TestCase {
} }
public void testInvalidInput() { public void testInvalidInput() {
CookieSpecRegistry registry = CookieSpecRegistry.DEFAULT; CookieSpecRegistry registry = new CookieSpecRegistry();
try { try {
registry.register(null, null); registry.register(null, null);
fail("IllegalArgumentException should have been thrown"); fail("IllegalArgumentException should have been thrown");

View File

@ -147,7 +147,7 @@ public class TestTSCCMNoServer extends TestCase {
} }
mgr = null; mgr = null;
mgr = new ThreadSafeClientConnManager(params, null); mgr = new ThreadSafeClientConnManager(params, schreg);
assertNotNull(mgr); assertNotNull(mgr);
assertNotNull(mgr.getParams()); assertNotNull(mgr.getParams());
assertEquals(paramval, mgr.getParams().getParameter(paramkey)); assertEquals(paramval, mgr.getParams().getParameter(paramkey));