You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2008/05/21 19:06:18 UTC
svn commit: r658759 - in /httpcomponents/httpclient/trunk: ./
module-client/src/main/java/org/apache/http/client/
module-client/src/main/java/org/apache/http/client/protocol/
module-client/src/main/java/org/apache/http/impl/client/
module-client/src/te...
Author: olegk
Date: Wed May 21 10:06:17 2008
New Revision: 658759
URL: http://svn.apache.org/viewvc?rev=658759&view=rev
Log:
Resolved a long standing problem with HttpClient not taking into account the user context when pooling / re-using connections. HttpClient now correctly handles stateful / user specific connections such as persistent NTLM connections and SSL connections with client side authentication.
Added:
httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java (with props)
httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java (with props)
httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java (with props)
Modified:
httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContext.java
httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java
httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java
httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestAllHttpClientImpl.java
Modified: httpcomponents/httpclient/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/RELEASE_NOTES.txt?rev=658759&r1=658758&r2=658759&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/RELEASE_NOTES.txt (original)
+++ httpcomponents/httpclient/trunk/RELEASE_NOTES.txt Wed May 21 10:06:17 2008
@@ -1,6 +1,12 @@
Changes since 4.0 Alpha 4
-------------------
+* Resolved a long standing problem with HttpClient not taking into account
+ the user context when pooling / re-using connections. HttpClient now
+ correctly handles stateful / user specific connections such as persistent
+ NTLM connections and SSL connections with client side authentication.
+ Contributed by Oleg Kalnichevski <olegk at apache.org>
+
* [HTTPCLIENT-773] Improved handling of the 'expires' attribute by the
'Best Match' cookie spec.
Contributed by Oleg Kalnichevski <olegk at apache.org>
Added: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java?rev=658759&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java (added)
+++ httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java Wed May 21 10:06:17 2008
@@ -0,0 +1,64 @@
+/*
+ * $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;
+
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * A handler for determining if the given execution context is user specific
+ * or not. The token object returned by this handler is expected to uniquely
+ * identify the current user if the context is user specific or to be
+ * <code>null</code> if the context does not contain any resources or details
+ * specific to the current user.
+ * <p/>
+ * The user token will be used to ensure that user specific resouces will not
+ * shared with or reused by other users.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @since 4.0
+ */
+public interface UserTokenHandler {
+
+ /**
+ * The token object returned by this method is expected to uniquely
+ * identify the current user if the context is user specific or to be
+ * <code>null</code> if it is not.
+ *
+ * @param context the execution context
+ *
+ * @return user token that uniquely identifies the user or
+ * <code>null</null> if the context is not user specific.
+ */
+ Object getUserToken(HttpContext context);
+
+}
Propchange: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/UserTokenHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContext.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContext.java?rev=658759&r1=658758&r2=658759&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContext.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/client/protocol/ClientContext.java Wed May 21 10:06:17 2008
@@ -47,5 +47,6 @@
public static final String TARGET_AUTH_STATE = "http.auth.target-scope";
public static final String PROXY_AUTH_STATE = "http.auth.proxy-scope";
public static final String AUTH_SCHEME_PREF = "http.auth.scheme-pref";
+ public static final String USER_TOKEN = "http.user-token";
}
Modified: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java?rev=658759&r1=658758&r2=658759&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/AbstractHttpClient.java Wed May 21 10:06:17 2008
@@ -49,6 +49,7 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
@@ -110,9 +111,12 @@
/** The credentials provider. */
private CredentialsProvider credsProvider;
- /** The HttpRoutePlanner object. */
+ /** The route planner. */
private HttpRoutePlanner routePlanner;
+ /** The user token handler. */
+ private UserTokenHandler userTokenHandler;
+
/**
* Creates a new HTTP client.
@@ -169,18 +173,8 @@
protected abstract HttpRoutePlanner createHttpRoutePlanner();
- public synchronized final HttpRoutePlanner getRoutePlanner() {
- if (this.routePlanner == null) {
- this.routePlanner = createHttpRoutePlanner();
- }
- return this.routePlanner;
- }
-
+ protected abstract UserTokenHandler createUserTokenHandler();
- public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
- this.routePlanner = routePlanner;
- }
-
// non-javadoc, see interface HttpClient
public synchronized final HttpParams getParams() {
@@ -334,6 +328,32 @@
}
+ public synchronized final HttpRoutePlanner getRoutePlanner() {
+ if (this.routePlanner == null) {
+ this.routePlanner = createHttpRoutePlanner();
+ }
+ return this.routePlanner;
+ }
+
+
+ public synchronized void setRoutePlanner(final HttpRoutePlanner routePlanner) {
+ this.routePlanner = routePlanner;
+ }
+
+
+ public synchronized final UserTokenHandler getUserTokenHandler() {
+ if (this.userTokenHandler == null) {
+ this.userTokenHandler = createUserTokenHandler();
+ }
+ return this.userTokenHandler;
+ }
+
+
+ public synchronized void setUserTokenHandler(final UserTokenHandler userTokenHandler) {
+ this.userTokenHandler = userTokenHandler;
+ }
+
+
protected synchronized final BasicHttpProcessor getHttpProcessor() {
if (httpProcessor == null) {
httpProcessor = createHttpProcessor();
@@ -500,6 +520,7 @@
getRedirectHandler(),
getTargetAuthenticationHandler(),
getProxyAuthenticationHandler(),
+ getUserTokenHandler(),
determineParams(request));
}
@@ -524,6 +545,7 @@
final RedirectHandler redirectHandler,
final AuthenticationHandler targetAuthHandler,
final AuthenticationHandler proxyAuthHandler,
+ final UserTokenHandler stateHandler,
final HttpParams params) {
return new DefaultClientRequestDirector(
conman,
@@ -534,6 +556,7 @@
redirectHandler,
targetAuthHandler,
proxyAuthHandler,
+ stateHandler,
params);
}
Modified: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java?rev=658759&r1=658758&r2=658759&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultClientRequestDirector.java Wed May 21 10:06:17 2008
@@ -63,6 +63,7 @@
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.RedirectException;
import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.methods.AbortableHttpRequest;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
@@ -134,6 +135,9 @@
/** The proxy authentication handler. */
private final AuthenticationHandler proxyAuthHandler;
+ /** The user token handler. */
+ private final UserTokenHandler userTokenHandler;
+
/** The HTTP parameters. */
protected final HttpParams params;
@@ -157,6 +161,7 @@
final RedirectHandler redirectHandler,
final AuthenticationHandler targetAuthHandler,
final AuthenticationHandler proxyAuthHandler,
+ final UserTokenHandler userTokenHandler,
final HttpParams params) {
if (conman == null) {
@@ -191,6 +196,10 @@
throw new IllegalArgumentException
("Proxy authentication handler may not be null.");
}
+ if (userTokenHandler == null) {
+ throw new IllegalArgumentException
+ ("User token handler may not be null.");
+ }
if (params == null) {
throw new IllegalArgumentException
("HTTP parameters may not be null");
@@ -203,6 +212,7 @@
this.redirectHandler = redirectHandler;
this.targetAuthHandler = targetAuthHandler;
this.proxyAuthHandler = proxyAuthHandler;
+ this.userTokenHandler = userTokenHandler;
this.params = params;
this.requestExec = new HttpRequestExecutor();
@@ -283,10 +293,13 @@
RequestWrapper wrapper = roureq.getRequest();
HttpRoute route = roureq.getRoute();
+ // See if we have a user token bound to the execution context
+ Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
+
// Allocate connection if needed
if (managedConn == null) {
ClientConnectionRequest connRequest = connManager.requestConnection(
- route, null);
+ route, userToken);
if (orig instanceof AbortableHttpRequest) {
((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
}
@@ -415,6 +428,12 @@
followup.getRequest().clearHeaders();
roureq = followup;
}
+
+ userToken = this.userTokenHandler.getUserToken(context);
+ context.setAttribute(ClientContext.USER_TOKEN, userToken);
+ if (managedConn != null) {
+ managedConn.setState(userToken);
+ }
} // while not done
// The connection is in or can be brought to a re-usable state.
Modified: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java?rev=658759&r1=658758&r2=658759&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultHttpClient.java Wed May 21 10:06:17 2008
@@ -39,6 +39,7 @@
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.RedirectHandler;
+import org.apache.http.client.UserTokenHandler;
import org.apache.http.client.params.AuthPolicy;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
@@ -289,11 +290,16 @@
}
- // non-javadoc, see base class AbstractHttpClient
@Override
protected HttpRoutePlanner createHttpRoutePlanner() {
return new DefaultHttpRoutePlanner
(getConnectionManager().getSchemeRegistry());
}
+
+
+ @Override
+ protected UserTokenHandler createUserTokenHandler() {
+ return new DefaultUserTokenHandler();
+ }
} // class DefaultHttpClient
Added: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java?rev=658759&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java (added)
+++ httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java Wed May 21 10:06:17 2008
@@ -0,0 +1,88 @@
+/*
+ * $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.impl.client;
+
+import java.security.Principal;
+
+import javax.net.ssl.SSLSession;
+
+import org.apache.http.auth.AuthScheme;
+import org.apache.http.auth.Credentials;
+import org.apache.http.client.AuthState;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+
+public class DefaultUserTokenHandler implements UserTokenHandler {
+
+ public Object getUserToken(final HttpContext context) {
+
+ Principal userPrincipal = null;
+
+ AuthState targetAuthState = (AuthState) context.getAttribute(
+ ClientContext.TARGET_AUTH_STATE);
+ if (targetAuthState != null) {
+ userPrincipal = getAuthPrincipal(targetAuthState);
+ if (userPrincipal == null) {
+ AuthState proxyAuthState = (AuthState) context.getAttribute(
+ ClientContext.PROXY_AUTH_STATE);
+ userPrincipal = getAuthPrincipal(proxyAuthState);
+ }
+ }
+
+ if (userPrincipal == null) {
+ ManagedClientConnection conn = (ManagedClientConnection) context.getAttribute(
+ ExecutionContext.HTTP_CONNECTION);
+ if (conn.isOpen()) {
+ SSLSession sslsession = conn.getSSLSession();
+ if (sslsession != null) {
+ userPrincipal = sslsession.getLocalPrincipal();
+ }
+ }
+ }
+
+ return userPrincipal;
+ }
+
+ private static Principal getAuthPrincipal(final AuthState authState) {
+ AuthScheme scheme = authState.getAuthScheme();
+ if (scheme != null && scheme.isComplete() && scheme.isConnectionBased()) {
+ Credentials creds = authState.getCredentials();
+ if (creds != null) {
+ return creds.getUserPrincipal();
+ }
+ }
+ return null;
+ }
+
+}
Propchange: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/client/DefaultUserTokenHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestAllHttpClientImpl.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestAllHttpClientImpl.java?rev=658759&r1=658758&r2=658759&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestAllHttpClientImpl.java (original)
+++ httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestAllHttpClientImpl.java Wed May 21 10:06:17 2008
@@ -45,6 +45,7 @@
suite.addTest(TestBasicCredentialsProvider.suite());
suite.addTest(TestRequestWrapper.suite());
suite.addTest(TestDefaultClientRequestDirector.suite());
+ suite.addTest(TestStatefulConnManagement.suite());
return suite;
}
Added: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java?rev=658759&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java (added)
+++ httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java Wed May 21 10:06:17 2008
@@ -0,0 +1,219 @@
+/*
+ * $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.impl.client;
+
+import java.io.IOException;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.UserTokenHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.params.HttpClientParams;
+import org.apache.http.conn.ManagedClientConnection;
+import org.apache.http.conn.params.ConnPerRouteBean;
+import org.apache.http.conn.params.HttpConnectionManagerParams;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.localserver.ServerTestBase;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+
+/**
+ * Unit tests for {@link DefaultClientRequestDirector}
+ */
+public class TestStatefulConnManagement extends ServerTestBase {
+
+ public TestStatefulConnManagement(final String testName) throws IOException {
+ super(testName);
+ }
+
+ public static void main(String args[]) {
+ String[] testCaseName = { TestStatefulConnManagement.class.getName() };
+ junit.textui.TestRunner.main(testCaseName);
+ }
+
+ public static Test suite() {
+ return new TestSuite(TestStatefulConnManagement.class);
+ }
+
+ private class SimpleService implements HttpRequestHandler {
+
+ public SimpleService() {
+ super();
+ }
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+ response.setStatusCode(HttpStatus.SC_OK);
+ StringEntity entity = new StringEntity("Whatever");
+ response.setEntity(entity);
+ }
+ }
+
+ public void testStatefulConnections() throws Exception {
+
+ int workerCount = 5;
+ int requestCount = 5;
+
+ int port = this.localServer.getServicePort();
+ this.localServer.register("*", new SimpleService());
+
+ HttpHost target = new HttpHost("localhost", port);
+
+ HttpParams params = defaultParams.copy();
+ HttpConnectionManagerParams.setMaxTotalConnections(params, workerCount);
+ HttpConnectionManagerParams.setMaxConnectionsPerRoute(params,
+ new ConnPerRouteBean(workerCount));
+ HttpClientParams.setConnectionManagerTimeout(params, 10L);
+
+ ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(
+ params, supportedSchemes);
+
+ DefaultHttpClient client = new DefaultHttpClient(mgr, params);
+
+ HttpContext[] contexts = new HttpContext[workerCount];
+ HttpWorker[] workers = new HttpWorker[workerCount];
+ for (int i = 0; i < contexts.length; i++) {
+ HttpContext context = new BasicHttpContext();
+ context.setAttribute("user", Integer.valueOf(i));
+ contexts[i] = context;
+ workers[i] = new HttpWorker(context, requestCount, target, client);
+ }
+
+ client.setUserTokenHandler(new UserTokenHandler() {
+
+ public Object getUserToken(final HttpContext context) {
+ Integer id = (Integer) context.getAttribute("user");
+ return id;
+ }
+
+ });
+
+
+ for (int i = 0; i < workers.length; i++) {
+ workers[i].start();
+ }
+ for (int i = 0; i < workers.length; i++) {
+ workers[i].join(10000);
+ }
+ for (int i = 0; i < workers.length; i++) {
+ Exception ex = workers[i].getException();
+ if (ex != null) {
+ throw ex;
+ }
+ assertEquals(requestCount, workers[i].getCount());
+ }
+
+ for (int i = 0; i < contexts.length; i++) {
+ HttpContext context = contexts[i];
+ Integer id = (Integer) context.getAttribute("user");
+
+ for (int r = 0; r < requestCount; r++) {
+ Integer state = (Integer) context.getAttribute("r" + r);
+ assertNotNull(state);
+ assertEquals(id, state);
+ }
+ }
+
+ }
+
+ static class HttpWorker extends Thread {
+
+ private final HttpContext context;
+ private final int requestCount;
+ private final HttpHost target;
+ private final HttpClient httpclient;
+
+ private volatile Exception exception;
+ private volatile int count;
+
+ public HttpWorker(
+ final HttpContext context,
+ int requestCount,
+ final HttpHost target,
+ final HttpClient httpclient) {
+ super();
+ this.context = context;
+ this.requestCount = requestCount;
+ this.target = target;
+ this.httpclient = httpclient;
+ this.count = 0;
+ }
+
+ public int getCount() {
+ return this.count;
+ }
+
+ public Exception getException() {
+ return this.exception;
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (int r = 0; r < this.requestCount; r++) {
+ HttpGet httpget = new HttpGet("/");
+ HttpResponse response = this.httpclient.execute(
+ this.target,
+ httpget,
+ this.context);
+ this.count++;
+
+ ManagedClientConnection conn = (ManagedClientConnection) this.context.getAttribute(
+ ExecutionContext.HTTP_CONNECTION);
+
+ this.context.setAttribute("r" + r, conn.getState());
+
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ entity.consumeContent();
+ }
+ }
+
+ } catch (Exception ex) {
+ this.exception = ex;
+ }
+ }
+
+ }
+
+}
Propchange: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: httpcomponents/httpclient/trunk/module-client/src/test/java/org/apache/http/impl/client/TestStatefulConnManagement.java
------------------------------------------------------------------------------
svn:mime-type = text/plain