Redesign of classic (blocking) connection management APIs
git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1784138 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7637761238
commit
564537aebc
|
@ -34,7 +34,6 @@ import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
|
|||
import org.apache.hc.client5.http.osgi.services.ProxyConfiguration;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
|
||||
/**
|
||||
|
@ -53,7 +52,7 @@ final class OSGiHttpRoutePlanner extends DefaultRoutePlanner {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected HttpHost determineProxy(final HttpHost target, final HttpRequest request, final HttpContext context) throws HttpException {
|
||||
protected HttpHost determineProxy(final HttpHost target, final HttpContext context) throws HttpException {
|
||||
HttpHost proxyHost = null;
|
||||
for (final ProxyConfiguration proxyConfiguration : proxyConfigurations) {
|
||||
if (proxyConfiguration.isEnabled()) {
|
||||
|
|
|
@ -51,41 +51,41 @@ public class TestOSGiHttpRoutePlanner {
|
|||
public void testDeterminProxy() throws Exception {
|
||||
OSGiHttpRoutePlanner planner = new OSGiHttpRoutePlanner(singletonList(pc1));
|
||||
|
||||
HttpHost proxy = planner.determineProxy(new HttpHost("localhost", 8090), null, null);
|
||||
HttpHost proxy = planner.determineProxy(new HttpHost("localhost", 8090), null);
|
||||
assertNull(proxy);
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("there", 9090), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("there", 9090), null);
|
||||
assertNotNull(proxy);
|
||||
assertTrue(proxy.getHostName().equals("proxy1"));
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("10.2.144.23", 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("10.2.144.23", 4554), null);
|
||||
assertNotNull(proxy);
|
||||
assertTrue(proxy.getHostName().equals("proxy1"));
|
||||
|
||||
final InetAddress addr = InetAddress.getByName("localhost");
|
||||
proxy = planner.determineProxy(new HttpHost(addr, 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost(addr, 4554), null);
|
||||
assertNull(proxy);
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("hc.apache.org", 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("hc.apache.org", 4554), null);
|
||||
assertNull(proxy);
|
||||
|
||||
|
||||
// test with more than one registration of proxyConfiguration
|
||||
planner = new OSGiHttpRoutePlanner(asList(pc1, pc2));
|
||||
proxy = planner.determineProxy(new HttpHost("localhost", 8090), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("localhost", 8090), null);
|
||||
assertNull(proxy);
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("there", 9090), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("there", 9090), null);
|
||||
assertNotNull(proxy);
|
||||
assertTrue(proxy.getHostName().equals("proxy1")); // the first one
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost(addr, 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost(addr, 4554), null);
|
||||
assertNull(proxy);
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("hc.apache.org", 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("hc.apache.org", 4554), null);
|
||||
assertNull(proxy);
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("docs.oracle.com", 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("docs.oracle.com", 4554), null);
|
||||
assertNull(proxy);
|
||||
}
|
||||
|
||||
|
@ -93,11 +93,11 @@ public class TestOSGiHttpRoutePlanner {
|
|||
public void testMasking() throws Exception {
|
||||
final OSGiHttpRoutePlanner planner = new OSGiHttpRoutePlanner(singletonList(pc2));
|
||||
|
||||
HttpHost proxy = planner.determineProxy(new HttpHost("12.34.34.2", 4554), null, null);
|
||||
HttpHost proxy = planner.determineProxy(new HttpHost("12.34.34.2", 4554), null);
|
||||
assertNotNull(proxy);
|
||||
assertTrue(proxy.getHostName().equals("proxy2"));
|
||||
|
||||
proxy = planner.determineProxy(new HttpHost("12.34.34.8", 4554), null, null);
|
||||
proxy = planner.determineProxy(new HttpHost("12.34.34.8", 4554), null);
|
||||
assertNotNull(proxy);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import java.util.Arrays;
|
|||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.hc.client5.http.DnsResolver;
|
||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
||||
import org.apache.hc.client5.http.auth.CredentialsProvider;
|
||||
|
@ -45,15 +44,13 @@ import org.apache.hc.client5.http.config.CookieSpecs;
|
|||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.cookie.BasicCookieStore;
|
||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
||||
import org.apache.hc.client5.http.impl.io.DefaultHttpResponseParserFactory;
|
||||
import org.apache.hc.client5.http.impl.io.LenientHttpResponseParser;
|
||||
import org.apache.hc.client5.http.impl.io.ManagedHttpClientConnectionFactory;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider;
|
||||
import org.apache.hc.client5.http.impl.sync.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.sync.CloseableHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.sync.HttpClients;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.impl.sync.CloseableHttpResponse;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
|
@ -71,6 +68,9 @@ import org.apache.hc.core5.http.config.RegistryBuilder;
|
|||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultClassicHttpResponseFactory;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultHttpRequestWriterFactory;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultHttpResponseParser;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultHttpResponseParserFactory;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.http.io.HttpMessageParser;
|
||||
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
||||
|
@ -107,18 +107,30 @@ public class ClientConfiguration {
|
|||
}
|
||||
|
||||
};
|
||||
return new LenientHttpResponseParser(lineParser, DefaultClassicHttpResponseFactory.INSTANCE, h1Config);
|
||||
return new DefaultHttpResponseParser(lineParser, DefaultClassicHttpResponseFactory.INSTANCE, h1Config);
|
||||
}
|
||||
|
||||
};
|
||||
HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();
|
||||
|
||||
// Create HTTP/1.1 protocol configuration
|
||||
H1Config h1Config = H1Config.custom()
|
||||
.setMaxHeaderCount(200)
|
||||
.setMaxLineLength(2000)
|
||||
.build();
|
||||
// Create connection configuration
|
||||
ConnectionConfig connectionConfig = ConnectionConfig.custom()
|
||||
.setMalformedInputAction(CodingErrorAction.IGNORE)
|
||||
.setUnmappableInputAction(CodingErrorAction.IGNORE)
|
||||
.setCharset(StandardCharsets.UTF_8)
|
||||
.build();
|
||||
|
||||
// Use a custom connection factory to customize the process of
|
||||
// initialization of outgoing HTTP connections. Beside standard connection
|
||||
// configuration parameters HTTP connection factory can define message
|
||||
// parser / writer routines to be employed by individual connections.
|
||||
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
|
||||
H1Config.DEFAULT, requestWriterFactory, responseParserFactory);
|
||||
HttpConnectionFactory<ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
|
||||
h1Config, connectionConfig, requestWriterFactory, responseParserFactory);
|
||||
|
||||
// Client HTTP connection objects when fully initialized can be bound to
|
||||
// an arbitrary network socket. The process of network socket initialization,
|
||||
|
@ -161,26 +173,9 @@ public class ClientConfiguration {
|
|||
// 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);
|
||||
// Validate connections after 1 sec of inactivity
|
||||
connManager.setValidateAfterInactivity(1000);
|
||||
|
||||
// Create message constraints
|
||||
H1Config messageConstraints = H1Config.custom()
|
||||
.setMaxHeaderCount(200)
|
||||
.setMaxLineLength(2000)
|
||||
.build();
|
||||
// Create connection configuration
|
||||
ConnectionConfig connectionConfig = ConnectionConfig.custom()
|
||||
.setMalformedInputAction(CodingErrorAction.IGNORE)
|
||||
.setUnmappableInputAction(CodingErrorAction.IGNORE)
|
||||
.setCharset(StandardCharsets.UTF_8)
|
||||
.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);
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.hc.client5.http.impl;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.utils.Identifiable;
|
||||
import org.apache.hc.core5.pool.ConnPoolControl;
|
||||
import org.apache.hc.core5.pool.PoolStats;
|
||||
|
||||
public final class ConnPoolSupport {
|
||||
|
||||
public static String getId(final Object object) {
|
||||
if (object == null) {
|
||||
return null;
|
||||
}
|
||||
if (object instanceof Identifiable) {
|
||||
return ((Identifiable) object).getId();
|
||||
} else {
|
||||
return Integer.toHexString(System.identityHashCode(object));
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatStats(
|
||||
final Object object,
|
||||
final HttpRoute route,
|
||||
final Object state,
|
||||
final ConnPoolControl<HttpRoute> connPool) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
if (object != null) {
|
||||
buf.append("[id: ").append(getId(object)).append("]");
|
||||
}
|
||||
buf.append("[route: ").append(route).append("]");
|
||||
if (state != null) {
|
||||
buf.append("[state: ").append(state).append("]");
|
||||
}
|
||||
final PoolStats totals = connPool.getTotalStats();
|
||||
final PoolStats stats = connPool.getStats(route);
|
||||
buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
|
||||
buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
|
||||
buf.append(" of ").append(stats.getMax()).append("; ");
|
||||
buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
|
||||
buf.append(" of ").append(totals.getMax()).append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
package org.apache.hc.client5.http.impl;
|
||||
|
||||
/**
|
||||
* Signals that the connection has been shut down or released back to the
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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.hc.client5.http.impl;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* @since 5.0
|
||||
*/
|
||||
public class DefaultThreadFactory implements ThreadFactory {
|
||||
|
||||
private final String namePrefix;
|
||||
private final ThreadGroup group;
|
||||
private final AtomicLong count;
|
||||
private final boolean daemon;
|
||||
|
||||
public DefaultThreadFactory(final String namePrefix, final ThreadGroup group, final boolean daemon) {
|
||||
this.namePrefix = namePrefix;
|
||||
this.group = group;
|
||||
this.count = new AtomicLong();
|
||||
this.daemon = daemon;
|
||||
}
|
||||
|
||||
public DefaultThreadFactory(final String namePrefix) {
|
||||
this(namePrefix, null, false);
|
||||
}
|
||||
|
||||
public DefaultThreadFactory(final String namePrefix, final boolean daemon) {
|
||||
this(namePrefix, null, daemon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(final Runnable target) {
|
||||
final Thread thread = new Thread(this.group, target, this.namePrefix + "-" + this.count.incrementAndGet());
|
||||
thread.setDaemon(this.daemon);
|
||||
return thread;
|
||||
}
|
||||
|
||||
}
|
|
@ -27,33 +27,38 @@
|
|||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.hc.client5.http.DnsResolver;
|
||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.core5.http.config.Lookup;
|
||||
import org.apache.hc.core5.http.config.Registry;
|
||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.apache.hc.core5.util.Asserts;
|
||||
|
@ -80,12 +85,12 @@ import org.apache.logging.log4j.Logger;
|
|||
* @since 4.3
|
||||
*/
|
||||
@Contract(threading = ThreadingBehavior.SAFE)
|
||||
public class BasicHttpClientConnectionManager implements HttpClientConnectionManager, Closeable {
|
||||
public class BasicHttpClientConnectionManager implements HttpClientConnectionManager {
|
||||
|
||||
private final Logger log = LogManager.getLogger(getClass());
|
||||
|
||||
private final HttpClientConnectionOperator connectionOperator;
|
||||
private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
||||
private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||
|
||||
private ManagedHttpClientConnection conn;
|
||||
private HttpRoute route;
|
||||
|
@ -94,9 +99,8 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
private long expiry;
|
||||
private boolean leased;
|
||||
private SocketConfig socketConfig;
|
||||
private ConnectionConfig connConfig;
|
||||
|
||||
private final AtomicBoolean isShutdown;
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
||||
return RegistryBuilder.<ConnectionSocketFactory>create()
|
||||
|
@ -107,13 +111,11 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
|
||||
public BasicHttpClientConnectionManager(
|
||||
final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||
final SchemePortResolver schemePortResolver,
|
||||
final DnsResolver dnsResolver) {
|
||||
this(
|
||||
new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
|
||||
connFactory
|
||||
);
|
||||
this(new DefaultHttpClientConnectionOperator(
|
||||
socketFactoryRegistry, schemePortResolver, dnsResolver), connFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,19 +123,18 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
*/
|
||||
public BasicHttpClientConnectionManager(
|
||||
final HttpClientConnectionOperator httpClientConnectionOperator,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||
super();
|
||||
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
|
||||
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
|
||||
this.expiry = Long.MAX_VALUE;
|
||||
this.socketConfig = SocketConfig.DEFAULT;
|
||||
this.connConfig = ConnectionConfig.DEFAULT;
|
||||
this.isShutdown = new AtomicBoolean(false);
|
||||
this.closed = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
public BasicHttpClientConnectionManager(
|
||||
final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||
this(socketFactoryRegistry, connFactory, null, null);
|
||||
}
|
||||
|
||||
|
@ -149,7 +150,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
shutdown();
|
||||
close();
|
||||
} finally { // Make sure we call overridden method even if shutdown barfs
|
||||
super.finalize();
|
||||
}
|
||||
|
@ -157,7 +158,9 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
|
||||
@Override
|
||||
public void close() {
|
||||
shutdown();
|
||||
if (this.closed.compareAndSet(false, true)) {
|
||||
shutdownConnection();
|
||||
}
|
||||
}
|
||||
|
||||
HttpRoute getRoute() {
|
||||
|
@ -176,37 +179,30 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
this.socketConfig = socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
|
||||
}
|
||||
|
||||
public synchronized ConnectionConfig getConnectionConfig() {
|
||||
return connConfig;
|
||||
}
|
||||
|
||||
public synchronized void setConnectionConfig(final ConnectionConfig connConfig) {
|
||||
this.connConfig = connConfig != null ? connConfig : ConnectionConfig.DEFAULT;
|
||||
}
|
||||
@Override
|
||||
public LeaseRequest lease(final HttpRoute route, final Object state) {
|
||||
return new LeaseRequest() {
|
||||
|
||||
@Override
|
||||
public final ConnectionRequest requestConnection(
|
||||
final HttpRoute route,
|
||||
final Object state) {
|
||||
Args.notNull(route, "Route");
|
||||
return new ConnectionRequest() {
|
||||
public ConnectionEndpoint get(
|
||||
final long timeout,
|
||||
final TimeUnit tunit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
try {
|
||||
return new InternalConnectionEndpoint(route, getConnection(route, state));
|
||||
} catch (IOException ex) {
|
||||
throw new ExecutionException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
// Nothing to abort, since requests are immediate.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientConnection get(final long timeout, final TimeUnit tunit) {
|
||||
return BasicHttpClientConnectionManager.this.getConnection(
|
||||
route, state);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void closeConnection() {
|
||||
private synchronized void closeConnection() {
|
||||
if (this.conn != null) {
|
||||
this.log.debug("Closing connection");
|
||||
try {
|
||||
|
@ -220,7 +216,7 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
}
|
||||
}
|
||||
|
||||
private void shutdownConnection() {
|
||||
private synchronized void shutdownConnection() {
|
||||
if (this.conn != null) {
|
||||
this.log.debug("Shutting down connection");
|
||||
try {
|
||||
|
@ -243,8 +239,8 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
}
|
||||
}
|
||||
|
||||
synchronized HttpClientConnection getConnection(final HttpRoute route, final Object state) {
|
||||
Asserts.check(!this.isShutdown.get(), "Connection manager has been shut down");
|
||||
synchronized ManagedHttpClientConnection getConnection(final HttpRoute route, final Object state) throws IOException {
|
||||
Asserts.check(!this.closed.get(), "Connection manager has been shut down");
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Get connection for route " + route);
|
||||
}
|
||||
|
@ -256,23 +252,32 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
this.state = state;
|
||||
checkExpiry();
|
||||
if (this.conn == null) {
|
||||
this.conn = this.connFactory.create(route, this.connConfig);
|
||||
this.conn = this.connFactory.createConnection(null);
|
||||
}
|
||||
this.leased = true;
|
||||
return this.conn;
|
||||
}
|
||||
|
||||
private InternalConnectionEndpoint cast(final ConnectionEndpoint endpoint) {
|
||||
if (endpoint instanceof InternalConnectionEndpoint) {
|
||||
return (InternalConnectionEndpoint) endpoint;
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void releaseConnection(
|
||||
final HttpClientConnection conn,
|
||||
public synchronized void release(
|
||||
final ConnectionEndpoint endpoint,
|
||||
final Object state,
|
||||
final long keepalive, final TimeUnit tunit) {
|
||||
Args.notNull(conn, "Connection");
|
||||
Asserts.check(conn == this.conn, "Connection not obtained from this manager");
|
||||
if (this.log.isDebugEnabled()) {
|
||||
Args.notNull(endpoint, "Endpoint");
|
||||
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||
final ManagedHttpClientConnection conn = internalEndpoint.detach();
|
||||
if (conn != null && this.log.isDebugEnabled()) {
|
||||
this.log.debug("Releasing connection " + conn);
|
||||
}
|
||||
if (this.isShutdown.get()) {
|
||||
if (this.closed.get()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
|
@ -306,45 +311,47 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
|
||||
@Override
|
||||
public void connect(
|
||||
final HttpClientConnection conn,
|
||||
final HttpRoute route,
|
||||
final int connectTimeout,
|
||||
final ConnectionEndpoint endpoint,
|
||||
final long connectTimeout,
|
||||
final TimeUnit timeUnit,
|
||||
final HttpContext context) throws IOException {
|
||||
Args.notNull(conn, "Connection");
|
||||
Args.notNull(route, "HTTP route");
|
||||
Asserts.check(conn == this.conn, "Connection not obtained from this manager");
|
||||
Args.notNull(endpoint, "Endpoint");
|
||||
|
||||
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||
if (internalEndpoint.isConnected()) {
|
||||
return;
|
||||
}
|
||||
final HttpRoute route = internalEndpoint.getRoute();
|
||||
final HttpHost host;
|
||||
if (route.getProxyHost() != null) {
|
||||
host = route.getProxyHost();
|
||||
} else {
|
||||
host = route.getTargetHost();
|
||||
}
|
||||
final InetSocketAddress localAddress = route.getLocalSocketAddress();
|
||||
this.connectionOperator.connect(this.conn, host, localAddress,
|
||||
connectTimeout, this.socketConfig, context);
|
||||
this.connectionOperator.connect(
|
||||
internalEndpoint.getConnection(),
|
||||
host,
|
||||
route.getLocalSocketAddress(),
|
||||
(int) (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS).toMillis(connectTimeout),
|
||||
this.socketConfig,
|
||||
context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgrade(
|
||||
final HttpClientConnection conn,
|
||||
final HttpRoute route,
|
||||
final ConnectionEndpoint endpoint,
|
||||
final HttpContext context) throws IOException {
|
||||
Args.notNull(conn, "Connection");
|
||||
Args.notNull(endpoint, "Endpoint");
|
||||
Args.notNull(route, "HTTP route");
|
||||
Asserts.check(conn == this.conn, "Connection not obtained from this manager");
|
||||
this.connectionOperator.upgrade(this.conn, route.getTargetHost(), context);
|
||||
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||
this.connectionOperator.upgrade(
|
||||
internalEndpoint.getConnection(),
|
||||
internalEndpoint.getRoute().getTargetHost(),
|
||||
context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeComplete(
|
||||
final HttpClientConnection conn,
|
||||
final HttpRoute route,
|
||||
final HttpContext context) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeExpired() {
|
||||
if (this.isShutdown.get()) {
|
||||
if (this.closed.get()) {
|
||||
return;
|
||||
}
|
||||
if (!this.leased) {
|
||||
|
@ -352,10 +359,9 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void closeIdle(final long idletime, final TimeUnit tunit) {
|
||||
Args.notNull(tunit, "Time unit");
|
||||
if (this.isShutdown.get()) {
|
||||
if (this.closed.get()) {
|
||||
return;
|
||||
}
|
||||
if (!this.leased) {
|
||||
|
@ -370,11 +376,75 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||
}
|
||||
}
|
||||
|
||||
class InternalConnectionEndpoint extends ConnectionEndpoint {
|
||||
|
||||
private final HttpRoute route;
|
||||
private final AtomicReference<ManagedHttpClientConnection> connRef;
|
||||
|
||||
public InternalConnectionEndpoint(final HttpRoute route, final ManagedHttpClientConnection conn) {
|
||||
this.route = route;
|
||||
this.connRef = new AtomicReference<>(conn);
|
||||
}
|
||||
|
||||
HttpRoute getRoute() {
|
||||
return route;
|
||||
}
|
||||
|
||||
ManagedHttpClientConnection getConnection() {
|
||||
final ManagedHttpClientConnection conn = this.connRef.get();
|
||||
if (conn == null) {
|
||||
throw new ConnectionShutdownException();
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
ManagedHttpClientConnection getValidatedConnection() {
|
||||
final ManagedHttpClientConnection conn = getConnection();
|
||||
Asserts.check(conn.isOpen(), "Endpoint is not connected");
|
||||
return conn;
|
||||
}
|
||||
|
||||
ManagedHttpClientConnection detach() {
|
||||
return this.connRef.getAndSet(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void shutdown() {
|
||||
if (this.isShutdown.compareAndSet(false, true)) {
|
||||
shutdownConnection();
|
||||
public boolean isConnected() {
|
||||
final ManagedHttpClientConnection conn = getConnection();
|
||||
return conn != null && conn.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws IOException {
|
||||
final ManagedHttpClientConnection conn = detach();
|
||||
if (conn != null) {
|
||||
conn.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
final ManagedHttpClientConnection conn = detach();
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSocketTimeout(final int timeout) {
|
||||
getValidatedConnection().setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassicHttpResponse execute(
|
||||
final ClassicHttpRequest request,
|
||||
final HttpRequestExecutor requestExecutor,
|
||||
final HttpContext context) throws IOException, HttpException {
|
||||
Args.notNull(request, "HTTP request");
|
||||
Args.notNull(requestExecutor, "Request executor");
|
||||
return requestExecutor.execute(request, getValidatedConnection(), context);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,283 +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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpConnectionMetrics;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.ProtocolVersion;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.pool.PoolEntry;
|
||||
|
||||
/**
|
||||
* @since 4.3
|
||||
*/
|
||||
class CPoolProxy implements ManagedHttpClientConnection, HttpContext {
|
||||
|
||||
private volatile PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry;
|
||||
private volatile boolean routeComplete;
|
||||
|
||||
CPoolProxy(final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry) {
|
||||
super();
|
||||
this.poolEntry = entry;
|
||||
}
|
||||
|
||||
PoolEntry<HttpRoute, ManagedHttpClientConnection> getPoolEntry() {
|
||||
return this.poolEntry;
|
||||
}
|
||||
|
||||
boolean isDetached() {
|
||||
return this.poolEntry == null;
|
||||
}
|
||||
|
||||
PoolEntry<HttpRoute, ManagedHttpClientConnection> detach() {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> local = this.poolEntry;
|
||||
this.poolEntry = null;
|
||||
return local;
|
||||
}
|
||||
|
||||
public void markRouteComplete() {
|
||||
this.routeComplete = true;
|
||||
}
|
||||
|
||||
public boolean isRouteComplete() {
|
||||
return this.routeComplete;
|
||||
}
|
||||
|
||||
ManagedHttpClientConnection getConnection() {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> local = this.poolEntry;
|
||||
if (local == null) {
|
||||
return null;
|
||||
}
|
||||
return local.getConnection();
|
||||
}
|
||||
|
||||
ManagedHttpClientConnection getValidConnection() {
|
||||
final ManagedHttpClientConnection conn = getConnection();
|
||||
if (conn == null) {
|
||||
throw new ConnectionShutdownException();
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> local = this.poolEntry;
|
||||
if (local != null) {
|
||||
final ManagedHttpClientConnection conn = local.getConnection();
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws IOException {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> local = this.poolEntry;
|
||||
if (local != null) {
|
||||
final ManagedHttpClientConnection conn = local.getConnection();
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> local = this.poolEntry;
|
||||
if (local != null) {
|
||||
final ManagedHttpClientConnection conn = local.getConnection();
|
||||
if (conn != null) {
|
||||
return conn.isOpen();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStale() throws IOException {
|
||||
final HttpClientConnection conn = getConnection();
|
||||
if (conn != null) {
|
||||
return conn.isStale();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion() {
|
||||
return getValidConnection().getProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSocketTimeout(final int timeout) {
|
||||
getValidConnection().setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSocketTimeout() {
|
||||
return getValidConnection().getSocketTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return getValidConnection().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(final Socket socket) throws IOException {
|
||||
getValidConnection().bind(socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket getSocket() {
|
||||
return getValidConnection().getSocket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSession getSSLSession() {
|
||||
return getValidConnection().getSSLSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConsistent() {
|
||||
return getValidConnection().isConsistent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminateRequest(final ClassicHttpRequest request) throws HttpException, IOException {
|
||||
getValidConnection().terminateRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataAvailable(final int timeout) throws IOException {
|
||||
return getValidConnection().isDataAvailable(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRequestHeader(final ClassicHttpRequest request) throws HttpException, IOException {
|
||||
getValidConnection().sendRequestHeader(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRequestEntity(final ClassicHttpRequest request) throws HttpException, IOException {
|
||||
getValidConnection().sendRequestEntity(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassicHttpResponse receiveResponseHeader() throws HttpException, IOException {
|
||||
return getValidConnection().receiveResponseHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveResponseEntity(final ClassicHttpResponse response) throws HttpException, IOException {
|
||||
getValidConnection().receiveResponseEntity(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
getValidConnection().flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpConnectionMetrics getMetrics() {
|
||||
return getValidConnection().getMetrics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getLocalAddress() {
|
||||
return getValidConnection().getLocalAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress() {
|
||||
return getValidConnection().getRemoteAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(final String id) {
|
||||
final ManagedHttpClientConnection conn = getValidConnection();
|
||||
if (conn instanceof HttpContext) {
|
||||
return ((HttpContext) conn).getAttribute(id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(final String id, final Object obj) {
|
||||
final ManagedHttpClientConnection conn = getValidConnection();
|
||||
if (conn instanceof HttpContext) {
|
||||
((HttpContext) conn).setAttribute(id, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object removeAttribute(final String id) {
|
||||
final ManagedHttpClientConnection conn = getValidConnection();
|
||||
if (conn instanceof HttpContext) {
|
||||
return ((HttpContext) conn).removeAttribute(id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolVersion(final ProtocolVersion version) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("CPoolProxy{");
|
||||
final ManagedHttpClientConnection conn = getConnection();
|
||||
if (conn != null) {
|
||||
sb.append(conn);
|
||||
} else {
|
||||
sb.append("detached");
|
||||
}
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static CPoolProxy getProxy(final HttpClientConnection conn) {
|
||||
if (!CPoolProxy.class.isInstance(conn)) {
|
||||
throw new IllegalStateException("Unexpected connection proxy class: " + conn.getClass());
|
||||
}
|
||||
return CPoolProxy.class.cast(conn);
|
||||
}
|
||||
|
||||
}
|
|
@ -48,6 +48,7 @@ import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
|||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.ConnectionClosedException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.config.Lookup;
|
||||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
|
@ -191,6 +192,9 @@ public class DefaultHttpClientConnectionOperator implements HttpClientConnection
|
|||
}
|
||||
final LayeredConnectionSocketFactory lsf = (LayeredConnectionSocketFactory) sf;
|
||||
Socket sock = conn.getSocket();
|
||||
if (sock == null) {
|
||||
throw new ConnectionClosedException("Connection is closed");
|
||||
}
|
||||
final int port = this.schemePortResolver.resolve(host);
|
||||
sock = lsf.createLayeredSocket(sock, host.getHostName(), port, context);
|
||||
conn.bind(sock);
|
||||
|
|
|
@ -32,35 +32,41 @@ import java.io.InterruptedIOException;
|
|||
import java.net.Socket;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.apache.hc.client5.http.impl.logging.LoggingSocketHolder;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.utils.Identifiable;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.ContentLengthStrategy;
|
||||
import org.apache.hc.core5.http.ProtocolVersion;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.config.H1Config;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection;
|
||||
import org.apache.hc.core5.http.impl.io.SocketHolder;
|
||||
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.http.message.RequestLine;
|
||||
import org.apache.hc.core5.http.message.StatusLine;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Default {@link ManagedHttpClientConnection} implementation.
|
||||
* @since 4.3
|
||||
*/
|
||||
public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnection
|
||||
implements ManagedHttpClientConnection, HttpContext {
|
||||
public class DefaultManagedHttpClientConnection
|
||||
extends DefaultBHttpClientConnection implements ManagedHttpClientConnection, Identifiable {
|
||||
|
||||
private final Logger log = LogManager.getLogger(DefaultManagedHttpClientConnection.class);
|
||||
private final Logger headerlog = LogManager.getLogger("org.apache.hc.client5.http.headers");
|
||||
private final Logger wirelog = LogManager.getLogger("org.apache.hc.client5.http.wire");
|
||||
|
||||
private final String id;
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
private volatile boolean shutdown;
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
public DefaultManagedHttpClientConnection(
|
||||
final String id,
|
||||
|
@ -75,7 +81,7 @@ public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnec
|
|||
super(buffersize, chardecoder, charencoder, h1Config, incomingContentStrategy, outgoingContentStrategy,
|
||||
requestWriterFactory, responseParserFactory);
|
||||
this.id = id;
|
||||
this.attributes = new ConcurrentHashMap<>();
|
||||
this.closed = new AtomicBoolean();
|
||||
}
|
||||
|
||||
public DefaultManagedHttpClientConnection(
|
||||
|
@ -89,15 +95,9 @@ public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnec
|
|||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws IOException {
|
||||
this.shutdown = true;
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(final SocketHolder socketHolder) throws IOException {
|
||||
if (this.shutdown) {
|
||||
if (this.closed.get()) {
|
||||
final Socket socket = socketHolder.getSocket();
|
||||
socket.close(); // allow this to throw...
|
||||
// ...but if it doesn't, explicitly throw one ourselves.
|
||||
|
@ -123,22 +123,58 @@ public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnec
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setProtocolVersion(final ProtocolVersion version) {
|
||||
public void close() throws IOException {
|
||||
if (this.closed.compareAndSet(false, true)) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(this.id + ": Close connection");
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(final String id) {
|
||||
return this.attributes.get(id);
|
||||
public void setSocketTimeout(final int timeout) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(this.id + ": set socket timeout to " + timeout);
|
||||
}
|
||||
super.setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(final String id, final Object obj) {
|
||||
this.attributes.put(id, obj);
|
||||
public void shutdown() throws IOException {
|
||||
if (this.closed.compareAndSet(false, true)) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(this.id + ": Shutdown connection");
|
||||
}
|
||||
super.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object removeAttribute(final String id) {
|
||||
return this.attributes.remove(id);
|
||||
public void bind(final Socket socket) throws IOException {
|
||||
super.bind(this.wirelog.isDebugEnabled() ? new LoggingSocketHolder(socket, this.id, this.wirelog) : new SocketHolder(socket));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseReceived(final ClassicHttpResponse response) {
|
||||
if (response != null && this.headerlog.isDebugEnabled()) {
|
||||
this.headerlog.debug(this.id + " << " + new StatusLine(response));
|
||||
final Header[] headers = response.getAllHeaders();
|
||||
for (final Header header : headers) {
|
||||
this.headerlog.debug(this.id + " << " + header.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestSubmitted(final ClassicHttpRequest request) {
|
||||
if (request != null && this.headerlog.isDebugEnabled()) {
|
||||
this.headerlog.debug(this.id + " >> " + new RequestLine(request));
|
||||
final Header[] headers = request.getAllHeaders();
|
||||
for (final Header header : headers) {
|
||||
this.headerlog.debug(this.id + " >> " + header.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,127 +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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.ContentLengthStrategy;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.config.H1Config;
|
||||
import org.apache.hc.core5.http.impl.io.SocketHolder;
|
||||
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
||||
import org.apache.hc.core5.http.message.RequestLine;
|
||||
import org.apache.hc.core5.http.message.StatusLine;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
class LoggingManagedHttpClientConnection extends DefaultManagedHttpClientConnection {
|
||||
|
||||
private final Logger log;
|
||||
private final Logger headerlog;
|
||||
private final Wire wire;
|
||||
|
||||
public LoggingManagedHttpClientConnection(
|
||||
final String id,
|
||||
final Logger log,
|
||||
final Logger headerlog,
|
||||
final Logger wirelog,
|
||||
final int buffersize,
|
||||
final CharsetDecoder chardecoder,
|
||||
final CharsetEncoder charencoder,
|
||||
final H1Config h1Config,
|
||||
final ContentLengthStrategy incomingContentStrategy,
|
||||
final ContentLengthStrategy outgoingContentStrategy,
|
||||
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
||||
super(id, buffersize, chardecoder, charencoder, h1Config, incomingContentStrategy, outgoingContentStrategy,
|
||||
requestWriterFactory, responseParserFactory);
|
||||
this.log = log;
|
||||
this.headerlog = headerlog;
|
||||
this.wire = new Wire(wirelog, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
|
||||
if (super.isOpen()) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(getId() + ": Close connection");
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSocketTimeout(final int timeout) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(getId() + ": set socket timeout to " + timeout);
|
||||
}
|
||||
super.setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws IOException {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(getId() + ": Shutdown connection");
|
||||
}
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(final Socket socket) throws IOException {
|
||||
super.bind(this.wire.enabled() ? new LoggingSocketHolder(socket, this.wire) : new SocketHolder(socket));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResponseReceived(final ClassicHttpResponse response) {
|
||||
if (response != null && this.headerlog.isDebugEnabled()) {
|
||||
this.headerlog.debug(getId() + " << " + new StatusLine(response));
|
||||
final Header[] headers = response.getAllHeaders();
|
||||
for (final Header header : headers) {
|
||||
this.headerlog.debug(getId() + " << " + header.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRequestSubmitted(final ClassicHttpRequest request) {
|
||||
if (request != null && this.headerlog.isDebugEnabled()) {
|
||||
this.headerlog.debug(getId() + " >> " + new RequestLine(request));
|
||||
final Header[] headers = request.getAllHeaders();
|
||||
for (final Header header : headers) {
|
||||
this.headerlog.debug(getId() + " >> " + header.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -27,14 +27,14 @@
|
|||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
|
@ -45,43 +45,38 @@ import org.apache.hc.core5.http.config.ConnectionConfig;
|
|||
import org.apache.hc.core5.http.config.H1Config;
|
||||
import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultHttpRequestWriterFactory;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Factory for {@link ManagedHttpClientConnection} instances.
|
||||
* @since 4.3
|
||||
*/
|
||||
@Contract(threading = ThreadingBehavior.IMMUTABLE)
|
||||
public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> {
|
||||
public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory<ManagedHttpClientConnection> {
|
||||
|
||||
private static final AtomicLong COUNTER = new AtomicLong();
|
||||
|
||||
public static final ManagedHttpClientConnectionFactory INSTANCE = new ManagedHttpClientConnectionFactory();
|
||||
|
||||
private final Logger log = LogManager.getLogger(DefaultManagedHttpClientConnection.class);
|
||||
private final Logger headerlog = LogManager.getLogger("org.apache.hc.client5.http.headers");
|
||||
private final Logger wirelog = LogManager.getLogger("org.apache.hc.client5.http.wire");
|
||||
|
||||
private final H1Config h1Config;
|
||||
private final ConnectionConfig connectionConfig;
|
||||
private final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory;
|
||||
private final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory;
|
||||
private final ContentLengthStrategy incomingContentStrategy;
|
||||
private final ContentLengthStrategy outgoingContentStrategy;
|
||||
|
||||
/**
|
||||
* @since 4.4
|
||||
*/
|
||||
public ManagedHttpClientConnectionFactory(
|
||||
final H1Config h1Config,
|
||||
final ConnectionConfig connectionConfig,
|
||||
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory,
|
||||
final ContentLengthStrategy incomingContentStrategy,
|
||||
final ContentLengthStrategy outgoingContentStrategy) {
|
||||
super();
|
||||
this.h1Config = h1Config != null ? h1Config : H1Config.DEFAULT;
|
||||
this.connectionConfig = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
|
||||
this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
|
||||
DefaultHttpRequestWriterFactory.INSTANCE;
|
||||
this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
|
||||
|
@ -94,31 +89,32 @@ public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory
|
|||
|
||||
public ManagedHttpClientConnectionFactory(
|
||||
final H1Config h1Config,
|
||||
final ConnectionConfig connectionConfig,
|
||||
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
||||
this(h1Config, requestWriterFactory, responseParserFactory, null, null);
|
||||
this(h1Config, connectionConfig, requestWriterFactory, responseParserFactory, null, null);
|
||||
}
|
||||
|
||||
public ManagedHttpClientConnectionFactory(
|
||||
final H1Config h1Config,
|
||||
final ConnectionConfig connectionConfig,
|
||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
||||
this(h1Config, null, responseParserFactory);
|
||||
this(h1Config, connectionConfig, null, responseParserFactory);
|
||||
}
|
||||
|
||||
public ManagedHttpClientConnectionFactory() {
|
||||
this(null, null);
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedHttpClientConnection create(final HttpRoute route, final ConnectionConfig config) {
|
||||
final ConnectionConfig cconfig = config != null ? config : ConnectionConfig.DEFAULT;
|
||||
public ManagedHttpClientConnection createConnection(final Socket socket) throws IOException {
|
||||
CharsetDecoder chardecoder = null;
|
||||
CharsetEncoder charencoder = null;
|
||||
final Charset charset = cconfig.getCharset();
|
||||
final CodingErrorAction malformedInputAction = cconfig.getMalformedInputAction() != null ?
|
||||
cconfig.getMalformedInputAction() : CodingErrorAction.REPORT;
|
||||
final CodingErrorAction unmappableInputAction = cconfig.getUnmappableInputAction() != null ?
|
||||
cconfig.getUnmappableInputAction() : CodingErrorAction.REPORT;
|
||||
final Charset charset = this.connectionConfig.getCharset();
|
||||
final CodingErrorAction malformedInputAction = this.connectionConfig.getMalformedInputAction() != null ?
|
||||
this.connectionConfig.getMalformedInputAction() : CodingErrorAction.REPORT;
|
||||
final CodingErrorAction unmappableInputAction = this.connectionConfig.getUnmappableInputAction() != null ?
|
||||
this.connectionConfig.getUnmappableInputAction() : CodingErrorAction.REPORT;
|
||||
if (charset != null) {
|
||||
chardecoder = charset.newDecoder();
|
||||
chardecoder.onMalformedInput(malformedInputAction);
|
||||
|
@ -128,12 +124,9 @@ public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory
|
|||
charencoder.onUnmappableCharacter(unmappableInputAction);
|
||||
}
|
||||
final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
|
||||
return new LoggingManagedHttpClientConnection(
|
||||
final DefaultManagedHttpClientConnection conn = new DefaultManagedHttpClientConnection(
|
||||
id,
|
||||
log,
|
||||
headerlog,
|
||||
wirelog,
|
||||
cconfig.getBufferSize(),
|
||||
connectionConfig.getBufferSize(),
|
||||
chardecoder,
|
||||
charencoder,
|
||||
h1Config,
|
||||
|
@ -141,6 +134,10 @@ public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory
|
|||
outgoingContentStrategy,
|
||||
requestWriterFactory,
|
||||
responseParserFactory);
|
||||
if (socket != null) {
|
||||
conn.bind(socket);
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,9 +26,7 @@
|
|||
*/
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
@ -37,15 +35,17 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.client5.http.DnsResolver;
|
||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.impl.ConnPoolSupport;
|
||||
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||
|
@ -53,70 +53,68 @@ import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
|||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.function.Callback;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.core5.http.config.Lookup;
|
||||
import org.apache.hc.core5.http.config.Registry;
|
||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.pool.ConnPoolControl;
|
||||
import org.apache.hc.core5.pool.ConnPoolListener;
|
||||
import org.apache.hc.core5.pool.ConnPoolPolicy;
|
||||
import org.apache.hc.core5.pool.PoolEntry;
|
||||
import org.apache.hc.core5.pool.PoolStats;
|
||||
import org.apache.hc.core5.pool.StrictConnPool;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.apache.hc.core5.util.Asserts;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* {@code ClientConnectionPoolManager} maintains a pool of
|
||||
* {@link HttpClientConnection}s and is able to service connection requests
|
||||
* {@link ManagedHttpClientConnection}s and is able to service connection requests
|
||||
* from multiple execution threads. Connections are pooled on a per route
|
||||
* basis. A request for a route which already the manager has persistent
|
||||
* connections for available in the pool will be services by leasing
|
||||
* a connection from the pool rather than creating a brand new connection.
|
||||
* a connection from the pool rather than creating a new connection.
|
||||
* <p>
|
||||
* {@code ClientConnectionPoolManager} maintains a maximum limit of connection
|
||||
* on a per route basis and in total. Per default this implementation will
|
||||
* create no more than than 2 concurrent connections per given route
|
||||
* and no more 20 connections in total. For many real-world applications
|
||||
* these limits may prove too constraining, especially if they use HTTP
|
||||
* as a transport protocol for their services. Connection limits, however,
|
||||
* can be adjusted using {@link ConnPoolControl} methods.
|
||||
* </p>
|
||||
* on a per route basis and in total. Connection limits, however, can be adjusted
|
||||
* using {@link ConnPoolControl} methods.
|
||||
* <p>
|
||||
* Total time to live (TTL) set at construction time defines maximum life span
|
||||
* of persistent connections regardless of their expiration setting. No persistent
|
||||
* connection will be re-used past its TTL value.
|
||||
* </p>
|
||||
* <p>
|
||||
* The handling of stale connections was changed in version 4.4.
|
||||
* Previously, the code would check every connection by default before re-using it.
|
||||
* The code now only checks the connection if the elapsed time since
|
||||
* the last use of the connection exceeds the timeout that has been set.
|
||||
* The default timeout is set to 5000ms - see
|
||||
* {@link #PoolingHttpClientConnectionManager(HttpClientConnectionOperator, HttpConnectionFactory, long, TimeUnit)}
|
||||
* </p>
|
||||
* The default timeout is set to 5000ms.
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
|
||||
public class PoolingHttpClientConnectionManager
|
||||
implements HttpClientConnectionManager, ConnPoolControl<HttpRoute>, Closeable {
|
||||
implements HttpClientConnectionManager, ConnPoolControl<HttpRoute> {
|
||||
|
||||
private final Logger log = LogManager.getLogger(getClass());
|
||||
|
||||
public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 25;
|
||||
public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
|
||||
|
||||
private final ConfigData configData;
|
||||
private final StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool;
|
||||
private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
||||
private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||
private final HttpClientConnectionOperator connectionOperator;
|
||||
private final AtomicBoolean isShutDown;
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
private volatile SocketConfig defaultSocketConfig;
|
||||
private volatile int validateAfterInactivity;
|
||||
|
||||
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
||||
|
@ -130,8 +128,9 @@ public class PoolingHttpClientConnectionManager
|
|||
this(getDefaultRegistry());
|
||||
}
|
||||
|
||||
public PoolingHttpClientConnectionManager(final long timeToLive, final TimeUnit tunit) {
|
||||
this(getDefaultRegistry(), null, null ,null, timeToLive, tunit);
|
||||
public PoolingHttpClientConnectionManager(
|
||||
final long timeToLive, final TimeUnit tunit) {
|
||||
this(getDefaultRegistry(), null, null ,null, ConnPoolPolicy.LIFO, null, timeToLive, tunit);
|
||||
}
|
||||
|
||||
public PoolingHttpClientConnectionManager(
|
||||
|
@ -147,49 +146,46 @@ public class PoolingHttpClientConnectionManager
|
|||
|
||||
public PoolingHttpClientConnectionManager(
|
||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||
this(socketFactoryRegistry, connFactory, null);
|
||||
}
|
||||
|
||||
public PoolingHttpClientConnectionManager(
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||
this(getDefaultRegistry(), connFactory, null);
|
||||
}
|
||||
|
||||
public PoolingHttpClientConnectionManager(
|
||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||
final DnsResolver dnsResolver) {
|
||||
this(socketFactoryRegistry, connFactory, null, dnsResolver, -1, TimeUnit.MILLISECONDS);
|
||||
this(socketFactoryRegistry, connFactory, null, dnsResolver, ConnPoolPolicy.LIFO, null, -1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public PoolingHttpClientConnectionManager(
|
||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||
final SchemePortResolver schemePortResolver,
|
||||
final DnsResolver dnsResolver,
|
||||
final ConnPoolPolicy connPoolPolicy,
|
||||
final ConnPoolListener<HttpRoute> connPoolListener,
|
||||
final long timeToLive, final TimeUnit tunit) {
|
||||
this(
|
||||
new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
|
||||
connFactory,
|
||||
timeToLive, tunit
|
||||
);
|
||||
this(new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
|
||||
connFactory, connPoolPolicy, connPoolListener, timeToLive, tunit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.4
|
||||
*/
|
||||
public PoolingHttpClientConnectionManager(
|
||||
final HttpClientConnectionOperator httpClientConnectionOperator,
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||
final ConnPoolPolicy connPoolPolicy,
|
||||
final ConnPoolListener<HttpRoute> connPoolListener,
|
||||
final long timeToLive, final TimeUnit tunit) {
|
||||
super();
|
||||
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
|
||||
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
|
||||
this.configData = new ConfigData();
|
||||
this.pool = new StrictConnPool<>(
|
||||
DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive, tunit, ConnPoolPolicy.LIFO, null);
|
||||
this.isShutDown = new AtomicBoolean(false);
|
||||
DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive, tunit, connPoolPolicy, connPoolListener);
|
||||
this.closed = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,15 +200,14 @@ public class PoolingHttpClientConnectionManager
|
|||
this.connectionOperator = new DefaultHttpClientConnectionOperator(
|
||||
socketFactoryRegistry, schemePortResolver, dnsResolver);
|
||||
this.connFactory = ManagedHttpClientConnectionFactory.INSTANCE;
|
||||
this.configData = new ConfigData();
|
||||
this.pool = pool;
|
||||
this.isShutDown = new AtomicBoolean(false);
|
||||
this.closed = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
shutdown();
|
||||
close();
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
|
@ -220,139 +215,112 @@ public class PoolingHttpClientConnectionManager
|
|||
|
||||
@Override
|
||||
public void close() {
|
||||
shutdown();
|
||||
if (this.closed.compareAndSet(false, true)) {
|
||||
this.log.debug("Connection manager is shutting down");
|
||||
this.pool.shutdown();
|
||||
this.log.debug("Connection manager shut down");
|
||||
}
|
||||
}
|
||||
|
||||
private String format(final HttpRoute route, final Object state) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
buf.append("[route: ").append(route).append("]");
|
||||
if (state != null) {
|
||||
buf.append("[state: ").append(state).append("]");
|
||||
private InternalConnectionEndpoint cast(final ConnectionEndpoint endpoint) {
|
||||
if (endpoint instanceof InternalConnectionEndpoint) {
|
||||
return (InternalConnectionEndpoint) endpoint;
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected endpoint class: " + endpoint.getClass());
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String formatStats(final HttpRoute route) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
final PoolStats totals = this.pool.getTotalStats();
|
||||
final PoolStats stats = this.pool.getStats(route);
|
||||
buf.append("[total kept alive: ").append(totals.getAvailable()).append("; ");
|
||||
buf.append("route allocated: ").append(stats.getLeased() + stats.getAvailable());
|
||||
buf.append(" of ").append(stats.getMax()).append("; ");
|
||||
buf.append("total allocated: ").append(totals.getLeased() + totals.getAvailable());
|
||||
buf.append(" of ").append(totals.getMax()).append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String format(final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
final ManagedHttpClientConnection conn = entry.getConnection();
|
||||
buf.append("[id: ").append(conn != null ? conn.getId() : "unknown").append("]");
|
||||
buf.append("[route: ").append(entry.getRoute()).append("]");
|
||||
final Object state = entry.getState();
|
||||
if (state != null) {
|
||||
buf.append("[state: ").append(state).append("]");
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionRequest requestConnection(
|
||||
public LeaseRequest lease(
|
||||
final HttpRoute route,
|
||||
final Object state) {
|
||||
Args.notNull(route, "HTTP route");
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Connection request: " + format(route, state) + formatStats(route));
|
||||
this.log.debug("Connection request: " + ConnPoolSupport.formatStats(null, route, state, this.pool));
|
||||
}
|
||||
final Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> leaseFuture = this.pool.lease(route, state, null);
|
||||
return new LeaseRequest() {
|
||||
|
||||
private volatile ConnectionEndpoint endpoint;
|
||||
|
||||
@Override
|
||||
public synchronized ConnectionEndpoint get(
|
||||
final long timeout,
|
||||
final TimeUnit tunit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (this.endpoint != null) {
|
||||
return this.endpoint;
|
||||
}
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry;
|
||||
try {
|
||||
poolEntry = leaseFuture.get(timeout, tunit);
|
||||
if (poolEntry == null || leaseFuture.isCancelled()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} catch (final TimeoutException ex) {
|
||||
leaseFuture.cancel(true);
|
||||
throw ex;
|
||||
}
|
||||
try {
|
||||
if (validateAfterInactivity > 0) {
|
||||
final ManagedHttpClientConnection conn = poolEntry.getConnection();
|
||||
if (conn != null
|
||||
&& poolEntry.getUpdated() + validateAfterInactivity <= System.currentTimeMillis()) {
|
||||
boolean stale;
|
||||
try {
|
||||
stale = conn.isStale();
|
||||
} catch (IOException ignore) {
|
||||
stale = true;
|
||||
}
|
||||
if (stale) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Connection " + ConnPoolSupport.getId(conn) + " is stale");
|
||||
}
|
||||
poolEntry.discardConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!poolEntry.hasConnection()) {
|
||||
poolEntry.assignConnection(connFactory.createConnection(null));
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Connection leased: " + ConnPoolSupport.formatStats(
|
||||
poolEntry.getConnection(), route, state, pool));
|
||||
}
|
||||
if (leaseFuture.isCancelled()) {
|
||||
pool.release(poolEntry, false);
|
||||
} else {
|
||||
this.endpoint = new InternalConnectionEndpoint(poolEntry);
|
||||
}
|
||||
return this.endpoint;
|
||||
} catch (Exception ex) {
|
||||
pool.release(poolEntry, false);
|
||||
throw new ExecutionException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
final Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> future = this.pool.lease(route, state, null);
|
||||
return new ConnectionRequest() {
|
||||
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
return future.cancel(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientConnection get(
|
||||
final long timeout,
|
||||
final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
|
||||
return leaseConnection(future, timeout, tunit);
|
||||
return leaseFuture.cancel(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
protected HttpClientConnection leaseConnection(
|
||||
final Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> future,
|
||||
final long timeout,
|
||||
final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry;
|
||||
try {
|
||||
entry = future.get(timeout, tunit);
|
||||
if (entry == null || future.isCancelled()) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
} catch (final TimeoutException ex) {
|
||||
future.cancel(true);
|
||||
throw new ConnectionPoolTimeoutException("Timeout waiting for connection from pool");
|
||||
}
|
||||
if (this.validateAfterInactivity > 0) {
|
||||
final ManagedHttpClientConnection connection = entry.getConnection();
|
||||
if (connection != null
|
||||
&& entry.getUpdated() + this.validateAfterInactivity <= System.currentTimeMillis()) {
|
||||
boolean stale;
|
||||
try {
|
||||
stale = connection.isStale();
|
||||
} catch (IOException ignore) {
|
||||
stale = true;
|
||||
}
|
||||
if (stale) {
|
||||
entry.discardConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
final HttpRoute route = entry.getRoute();
|
||||
final CPoolProxy poolProxy = new CPoolProxy(entry);
|
||||
if (entry.hasConnection()) {
|
||||
poolProxy.markRouteComplete();
|
||||
} else {
|
||||
ConnectionConfig config = null;
|
||||
if (route.getProxyHost() != null) {
|
||||
config = this.configData.getConnectionConfig(route.getProxyHost());
|
||||
}
|
||||
if (config == null) {
|
||||
config = this.configData.getConnectionConfig(route.getTargetHost());
|
||||
}
|
||||
if (config == null) {
|
||||
config = this.configData.getDefaultConnectionConfig();
|
||||
}
|
||||
if (config == null) {
|
||||
config = ConnectionConfig.DEFAULT;
|
||||
}
|
||||
entry.assignConnection(this.connFactory.create(route, config));
|
||||
}
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Connection leased: " + format(entry) + formatStats(route));
|
||||
}
|
||||
return poolProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(
|
||||
final HttpClientConnection managedConn,
|
||||
public void release(
|
||||
final ConnectionEndpoint endpoint,
|
||||
final Object state,
|
||||
final long keepAlive, final TimeUnit timeUnit) {
|
||||
Args.notNull(managedConn, "Managed connection");
|
||||
synchronized (managedConn) {
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
||||
if (poolProxy.isDetached()) {
|
||||
Args.notNull(endpoint, "Managed endpoint");
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = cast(endpoint).detach();
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = poolProxy.detach();
|
||||
try {
|
||||
final ManagedHttpClientConnection conn = entry.getConnection();
|
||||
if (conn.isOpen()) {
|
||||
boolean reusable = conn != null && conn.isOpen();
|
||||
try {
|
||||
if (reusable) {
|
||||
final TimeUnit effectiveUnit = timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS;
|
||||
entry.updateConnection(keepAlive, effectiveUnit, state);
|
||||
if (this.log.isDebugEnabled()) {
|
||||
|
@ -362,85 +330,61 @@ public class PoolingHttpClientConnectionManager
|
|||
} else {
|
||||
s = "indefinitely";
|
||||
}
|
||||
this.log.debug("Connection " + format(entry) + " can be kept alive " + s);
|
||||
this.log.debug("Connection " + ConnPoolSupport.getId(conn) + " can be kept alive " + s);
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
reusable = false;
|
||||
throw ex;
|
||||
} finally {
|
||||
final ManagedHttpClientConnection conn = entry.getConnection();
|
||||
this.pool.release(entry, conn.isOpen() && poolProxy.isRouteComplete());
|
||||
this.pool.release(entry, reusable);
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Connection released: " + format(entry) + formatStats(entry.getRoute()));
|
||||
}
|
||||
this.log.debug("Connection released: " + ConnPoolSupport.formatStats(
|
||||
conn, entry.getRoute(), entry.getState(), pool));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(
|
||||
final HttpClientConnection managedConn,
|
||||
final HttpRoute route,
|
||||
final int connectTimeout,
|
||||
final ConnectionEndpoint endpoint,
|
||||
final long connectTimeout,
|
||||
final TimeUnit timeUnit,
|
||||
final HttpContext context) throws IOException {
|
||||
Args.notNull(managedConn, "Managed Connection");
|
||||
Args.notNull(route, "HTTP route");
|
||||
final ManagedHttpClientConnection conn;
|
||||
synchronized (managedConn) {
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
||||
conn = poolProxy.getConnection();
|
||||
Args.notNull(endpoint, "Managed endpoint");
|
||||
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||
if (internalEndpoint.isConnected()) {
|
||||
return;
|
||||
}
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getPoolEntry();
|
||||
if (!poolEntry.hasConnection()) {
|
||||
poolEntry.assignConnection(connFactory.createConnection(null));
|
||||
}
|
||||
final HttpRoute route = poolEntry.getRoute();
|
||||
final HttpHost host;
|
||||
if (route.getProxyHost() != null) {
|
||||
host = route.getProxyHost();
|
||||
} else {
|
||||
host = route.getTargetHost();
|
||||
}
|
||||
final InetSocketAddress localAddress = route.getLocalSocketAddress();
|
||||
SocketConfig socketConfig = this.configData.getSocketConfig(host);
|
||||
if (socketConfig == null) {
|
||||
socketConfig = this.configData.getDefaultSocketConfig();
|
||||
}
|
||||
if (socketConfig == null) {
|
||||
socketConfig = SocketConfig.DEFAULT;
|
||||
}
|
||||
this.connectionOperator.connect(
|
||||
conn, host, localAddress, connectTimeout, socketConfig, context);
|
||||
poolEntry.getConnection(),
|
||||
host,
|
||||
route.getLocalSocketAddress(),
|
||||
(int) (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS).toMillis(connectTimeout),
|
||||
this.defaultSocketConfig != null ? this.defaultSocketConfig : SocketConfig.DEFAULT,
|
||||
context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgrade(
|
||||
final HttpClientConnection managedConn,
|
||||
final HttpRoute route,
|
||||
final ConnectionEndpoint endpoint,
|
||||
final HttpContext context) throws IOException {
|
||||
Args.notNull(managedConn, "Managed Connection");
|
||||
Args.notNull(route, "HTTP route");
|
||||
final ManagedHttpClientConnection conn;
|
||||
synchronized (managedConn) {
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
||||
conn = poolProxy.getConnection();
|
||||
}
|
||||
this.connectionOperator.upgrade(conn, route.getTargetHost(), context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeComplete(
|
||||
final HttpClientConnection managedConn,
|
||||
final HttpRoute route,
|
||||
final HttpContext context) throws IOException {
|
||||
Args.notNull(managedConn, "Managed Connection");
|
||||
Args.notNull(route, "HTTP route");
|
||||
synchronized (managedConn) {
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
||||
poolProxy.markRouteComplete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (this.isShutDown.compareAndSet(false, true)) {
|
||||
this.log.debug("Connection manager is shutting down");
|
||||
this.pool.shutdown();
|
||||
this.log.debug("Connection manager shut down");
|
||||
}
|
||||
Args.notNull(endpoint, "Managed endpoint");
|
||||
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
|
||||
final HttpRoute route = poolEntry.getRoute();
|
||||
this.connectionOperator.upgrade(poolEntry.getConnection(), route.getTargetHost(), context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -513,35 +457,11 @@ public class PoolingHttpClientConnectionManager
|
|||
}
|
||||
|
||||
public SocketConfig getDefaultSocketConfig() {
|
||||
return this.configData.getDefaultSocketConfig();
|
||||
return this.defaultSocketConfig;
|
||||
}
|
||||
|
||||
public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
|
||||
this.configData.setDefaultSocketConfig(defaultSocketConfig);
|
||||
}
|
||||
|
||||
public ConnectionConfig getDefaultConnectionConfig() {
|
||||
return this.configData.getDefaultConnectionConfig();
|
||||
}
|
||||
|
||||
public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) {
|
||||
this.configData.setDefaultConnectionConfig(defaultConnectionConfig);
|
||||
}
|
||||
|
||||
public SocketConfig getSocketConfig(final HttpHost host) {
|
||||
return this.configData.getSocketConfig(host);
|
||||
}
|
||||
|
||||
public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig) {
|
||||
this.configData.setSocketConfig(host, socketConfig);
|
||||
}
|
||||
|
||||
public ConnectionConfig getConnectionConfig(final HttpHost host) {
|
||||
return this.configData.getConnectionConfig(host);
|
||||
}
|
||||
|
||||
public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) {
|
||||
this.configData.setConnectionConfig(host, connectionConfig);
|
||||
this.defaultSocketConfig = defaultSocketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -555,12 +475,11 @@ public class PoolingHttpClientConnectionManager
|
|||
|
||||
/**
|
||||
* Defines period of inactivity in milliseconds after which persistent connections must
|
||||
* be re-validated prior to being {@link #leaseConnection(java.util.concurrent.Future,
|
||||
* long, java.util.concurrent.TimeUnit) leased} to the consumer. Non-positive value passed
|
||||
* to this method disables connection validation. This check helps detect connections
|
||||
* that have become stale (half-closed) while kept inactive in the pool.
|
||||
* be re-validated prior to being {@link #lease(HttpRoute, Object)} leased} to the consumer.
|
||||
* Non-positive value passed to this method disables connection validation. This check helps
|
||||
* detect connections that have become stale (half-closed) while kept inactive in the pool.
|
||||
*
|
||||
* @see #leaseConnection(java.util.concurrent.Future, long, java.util.concurrent.TimeUnit)
|
||||
* @see #lease(HttpRoute, Object)
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
|
@ -571,14 +490,11 @@ public class PoolingHttpClientConnectionManager
|
|||
static class ConfigData {
|
||||
|
||||
private final Map<HttpHost, SocketConfig> socketConfigMap;
|
||||
private final Map<HttpHost, ConnectionConfig> connectionConfigMap;
|
||||
private volatile SocketConfig defaultSocketConfig;
|
||||
private volatile ConnectionConfig defaultConnectionConfig;
|
||||
|
||||
ConfigData() {
|
||||
super();
|
||||
this.socketConfigMap = new ConcurrentHashMap<>();
|
||||
this.connectionConfigMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public SocketConfig getDefaultSocketConfig() {
|
||||
|
@ -589,14 +505,6 @@ public class PoolingHttpClientConnectionManager
|
|||
this.defaultSocketConfig = defaultSocketConfig;
|
||||
}
|
||||
|
||||
public ConnectionConfig getDefaultConnectionConfig() {
|
||||
return this.defaultConnectionConfig;
|
||||
}
|
||||
|
||||
public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) {
|
||||
this.defaultConnectionConfig = defaultConnectionConfig;
|
||||
}
|
||||
|
||||
public SocketConfig getSocketConfig(final HttpHost host) {
|
||||
return this.socketConfigMap.get(host);
|
||||
}
|
||||
|
@ -605,12 +513,76 @@ public class PoolingHttpClientConnectionManager
|
|||
this.socketConfigMap.put(host, socketConfig);
|
||||
}
|
||||
|
||||
public ConnectionConfig getConnectionConfig(final HttpHost host) {
|
||||
return this.connectionConfigMap.get(host);
|
||||
}
|
||||
|
||||
public void setConnectionConfig(final HttpHost host, final ConnectionConfig connectionConfig) {
|
||||
this.connectionConfigMap.put(host, connectionConfig);
|
||||
class InternalConnectionEndpoint extends ConnectionEndpoint {
|
||||
|
||||
private final AtomicReference<PoolEntry<HttpRoute, ManagedHttpClientConnection>> poolEntryRef;
|
||||
|
||||
InternalConnectionEndpoint(
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry) {
|
||||
this.poolEntryRef = new AtomicReference<>(poolEntry);
|
||||
}
|
||||
|
||||
PoolEntry<HttpRoute, ManagedHttpClientConnection> getPoolEntry() {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
|
||||
if (poolEntry == null) {
|
||||
throw new ConnectionShutdownException();
|
||||
}
|
||||
return poolEntry;
|
||||
}
|
||||
|
||||
PoolEntry<HttpRoute, ManagedHttpClientConnection> getValidatedPoolEntry() {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = getPoolEntry();
|
||||
final ManagedHttpClientConnection connection = poolEntry.getConnection();
|
||||
Asserts.check(connection != null && connection.isOpen(), "Endpoint is not connected");
|
||||
return poolEntry;
|
||||
}
|
||||
|
||||
PoolEntry<HttpRoute, ManagedHttpClientConnection> detach() {
|
||||
return poolEntryRef.getAndSet(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws IOException {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
|
||||
if (poolEntry != null) {
|
||||
final HttpClientConnection connection = poolEntry.getConnection();
|
||||
poolEntry.discardConnection();
|
||||
if (connection != null) {
|
||||
connection.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = poolEntryRef.get();
|
||||
if (poolEntry != null) {
|
||||
poolEntry.discardConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = getPoolEntry();
|
||||
final ManagedHttpClientConnection connection = poolEntry.getConnection();
|
||||
return connection != null && connection.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSocketTimeout(final int timeout) {
|
||||
getValidatedPoolEntry().getConnection().setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassicHttpResponse execute(
|
||||
final ClassicHttpRequest request,
|
||||
final HttpRequestExecutor requestExecutor,
|
||||
final HttpContext context) throws IOException, HttpException {
|
||||
Args.notNull(request, "HTTP request");
|
||||
Args.notNull(requestExecutor, "Request executor");
|
||||
return requestExecutor.execute(request, getValidatedPoolEntry().getConnection(), context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,14 +30,18 @@ package org.apache.hc.client5.http.impl.io;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hc.client5.http.DnsResolver;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
import org.apache.hc.core5.util.TextUtils;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.pool.ConnPoolListener;
|
||||
import org.apache.hc.core5.pool.ConnPoolPolicy;
|
||||
|
||||
/**
|
||||
* Builder for {@link PoolingHttpClientConnectionManager} instances.
|
||||
|
@ -67,11 +71,13 @@ import org.apache.hc.core5.util.TextUtils;
|
|||
*/
|
||||
public class PoolingHttpClientConnectionManagerBuilder {
|
||||
|
||||
private HttpConnectionFactory<ManagedHttpClientConnection> connectionFactory;
|
||||
private LayeredConnectionSocketFactory sslSocketFactory;
|
||||
private SchemePortResolver schemePortResolver;
|
||||
private DnsResolver dnsResolver;
|
||||
|
||||
private ConnPoolPolicy connPoolPolicy;
|
||||
private ConnPoolListener<HttpRoute> connPoolListener;
|
||||
private SocketConfig defaultSocketConfig;
|
||||
private ConnectionConfig defaultConnectionConfig;
|
||||
|
||||
private boolean systemProperties;
|
||||
|
||||
|
@ -91,7 +97,16 @@ public class PoolingHttpClientConnectionManagerBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link LayeredConnectionSocketFactory} instance for SSL connections.
|
||||
* Assigns {@link HttpConnectionFactory} instance.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setConnectionFactory(
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connectionFactory) {
|
||||
this.connectionFactory = connectionFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link LayeredConnectionSocketFactory} instance.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setSSLSocketFactory(
|
||||
final LayeredConnectionSocketFactory sslSocketFactory) {
|
||||
|
@ -99,6 +114,38 @@ public class PoolingHttpClientConnectionManagerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link DnsResolver} instance.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setDnsResolver(final DnsResolver dnsResolver) {
|
||||
this.dnsResolver = dnsResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link SchemePortResolver} instance.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setSchemePortResolver(final SchemePortResolver schemePortResolver) {
|
||||
this.schemePortResolver = schemePortResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link ConnPoolPolicy} value.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setConnPoolPolicy(final ConnPoolPolicy connPoolPolicy) {
|
||||
this.connPoolPolicy = connPoolPolicy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link ConnPoolListener} instance.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setConnPoolListener(final ConnPoolListener<HttpRoute> connPoolListener) {
|
||||
this.connPoolListener = connPoolListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns maximum total connection value.
|
||||
*/
|
||||
|
@ -123,18 +170,8 @@ public class PoolingHttpClientConnectionManagerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns default {@link ConnectionConfig}.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setDefaultConnectionConfig(final ConnectionConfig config) {
|
||||
this.defaultConnectionConfig = config;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets maximum time to live for persistent connections
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {
|
||||
this.connTimeToLive = connTimeToLive;
|
||||
|
@ -153,14 +190,6 @@ public class PoolingHttpClientConnectionManagerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns {@link DnsResolver} instance.
|
||||
*/
|
||||
public final PoolingHttpClientConnectionManagerBuilder setDnsResolver(final DnsResolver dnsResolver) {
|
||||
this.dnsResolver = dnsResolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use system properties when creating and configuring default
|
||||
* implementations.
|
||||
|
@ -170,13 +199,6 @@ public class PoolingHttpClientConnectionManagerBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
private static String[] split(final String s) {
|
||||
if (TextUtils.isBlank(s)) {
|
||||
return null;
|
||||
}
|
||||
return s.split(" *, *");
|
||||
}
|
||||
|
||||
public PoolingHttpClientConnectionManager build() {
|
||||
@SuppressWarnings("resource")
|
||||
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
|
||||
|
@ -187,18 +209,17 @@ public class PoolingHttpClientConnectionManagerBuilder {
|
|||
SSLConnectionSocketFactory.getSystemSocketFactory() :
|
||||
SSLConnectionSocketFactory.getSocketFactory()))
|
||||
.build(),
|
||||
null,
|
||||
null,
|
||||
connectionFactory,
|
||||
schemePortResolver,
|
||||
dnsResolver,
|
||||
connPoolPolicy,
|
||||
connPoolListener,
|
||||
connTimeToLive,
|
||||
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
|
||||
poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
|
||||
if (defaultSocketConfig != null) {
|
||||
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
|
||||
}
|
||||
if (defaultConnectionConfig != null) {
|
||||
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
|
||||
}
|
||||
if (maxConnTotal > 0) {
|
||||
poolingmgr.setMaxTotal(maxConnTotal);
|
||||
}
|
||||
|
|
|
@ -25,16 +25,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
package org.apache.hc.client5.http.impl.logging;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Internal class.
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
class LoggingInputStream extends InputStream {
|
||||
|
||||
private final InputStream in;
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
package org.apache.hc.client5.http.impl.logging;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
@ -49,6 +49,7 @@ class LoggingOutputStream extends OutputStream {
|
|||
@Override
|
||||
public void write(final int b) throws IOException {
|
||||
try {
|
||||
out.write(b);
|
||||
wire.output(b);
|
||||
} catch (final IOException ex) {
|
||||
wire.output("[write] I/O error: " + ex.getMessage());
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
package org.apache.hc.client5.http.impl.logging;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -33,14 +33,15 @@ import java.io.OutputStream;
|
|||
import java.net.Socket;
|
||||
|
||||
import org.apache.hc.core5.http.impl.io.SocketHolder;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
class LoggingSocketHolder extends SocketHolder {
|
||||
public class LoggingSocketHolder extends SocketHolder {
|
||||
|
||||
private final Wire wire;
|
||||
|
||||
LoggingSocketHolder(final Socket socket, final Wire wire) {
|
||||
public LoggingSocketHolder(final Socket socket, final String id, final Logger log) {
|
||||
super(socket);
|
||||
this.wire = wire;
|
||||
this.wire = new Wire(log, id);
|
||||
}
|
||||
|
||||
@Override
|
|
@ -24,52 +24,36 @@
|
|||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
package org.apache.hc.client5.http.impl.logging;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Logs data to the wire LOG.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@Contract(threading = ThreadingBehavior.IMMUTABLE)
|
||||
class Wire {
|
||||
|
||||
private final Logger log;
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* @since 4.3
|
||||
*/
|
||||
public Wire(final Logger log, final String id) {
|
||||
Wire(final Logger log, final String id) {
|
||||
super();
|
||||
this.log = log;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Wire(final Logger log) {
|
||||
this(log, "");
|
||||
}
|
||||
|
||||
private void wire(final String header, final InputStream instream)
|
||||
throws IOException {
|
||||
private void wire(final String header, final byte[] b, final int pos, final int off) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
int ch;
|
||||
while ((ch = instream.read()) != -1) {
|
||||
for (int i = 0; i < off; i++) {
|
||||
final int ch = b[pos + i];
|
||||
if (ch == 13) {
|
||||
buffer.append("[\\r]");
|
||||
} else if (ch == 10) {
|
||||
buffer.append("[\\n]\"");
|
||||
buffer.insert(0, "\"");
|
||||
buffer.insert(0, header);
|
||||
log.debug(id + " " + buffer.toString());
|
||||
this.log.debug(this.id + " " + buffer.toString());
|
||||
buffer.setLength(0);
|
||||
} else if ((ch < 32) || (ch > 127)) {
|
||||
buffer.append("[0x");
|
||||
|
@ -83,70 +67,73 @@ class Wire {
|
|||
buffer.append('\"');
|
||||
buffer.insert(0, '\"');
|
||||
buffer.insert(0, header);
|
||||
log.debug(id + " " + buffer.toString());
|
||||
this.log.debug(this.id + " " + buffer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean enabled() {
|
||||
return log.isDebugEnabled();
|
||||
public boolean isEnabled() {
|
||||
return this.log.isDebugEnabled();
|
||||
}
|
||||
|
||||
public void output(final InputStream outstream)
|
||||
throws IOException {
|
||||
Args.notNull(outstream, "Output");
|
||||
wire(">> ", outstream);
|
||||
}
|
||||
|
||||
public void input(final InputStream instream)
|
||||
throws IOException {
|
||||
Args.notNull(instream, "Input");
|
||||
wire("<< ", instream);
|
||||
}
|
||||
|
||||
public void output(final byte[] b, final int off, final int len)
|
||||
throws IOException {
|
||||
public void output(final byte[] b, final int pos, final int off) {
|
||||
Args.notNull(b, "Output");
|
||||
wire(">> ", new ByteArrayInputStream(b, off, len));
|
||||
wire(">> ", b, pos, off);
|
||||
}
|
||||
|
||||
public void input(final byte[] b, final int off, final int len)
|
||||
throws IOException {
|
||||
public void input(final byte[] b, final int pos, final int off) {
|
||||
Args.notNull(b, "Input");
|
||||
wire("<< ", new ByteArrayInputStream(b, off, len));
|
||||
wire("<< ", b, pos, off);
|
||||
}
|
||||
|
||||
public void output(final byte[] b)
|
||||
throws IOException {
|
||||
public void output(final byte[] b) {
|
||||
Args.notNull(b, "Output");
|
||||
wire(">> ", new ByteArrayInputStream(b));
|
||||
output(b, 0, b.length);
|
||||
}
|
||||
|
||||
public void input(final byte[] b)
|
||||
throws IOException {
|
||||
public void input(final byte[] b) {
|
||||
Args.notNull(b, "Input");
|
||||
wire("<< ", new ByteArrayInputStream(b));
|
||||
input(b, 0, b.length);
|
||||
}
|
||||
|
||||
public void output(final int b)
|
||||
throws IOException {
|
||||
public void output(final int b) {
|
||||
output(new byte[] {(byte) b});
|
||||
}
|
||||
|
||||
public void input(final int b)
|
||||
throws IOException {
|
||||
public void input(final int b) {
|
||||
input(new byte[] {(byte) b});
|
||||
}
|
||||
|
||||
public void output(final String s)
|
||||
throws IOException {
|
||||
public void output(final String s) {
|
||||
Args.notNull(s, "Output");
|
||||
output(s.getBytes());
|
||||
}
|
||||
|
||||
public void input(final String s)
|
||||
throws IOException {
|
||||
public void input(final String s) {
|
||||
Args.notNull(s, "Input");
|
||||
input(s.getBytes());
|
||||
}
|
||||
|
||||
public void output(final ByteBuffer b) {
|
||||
Args.notNull(b, "Output");
|
||||
if (b.hasArray()) {
|
||||
output(b.array(), b.arrayOffset() + b.position(), b.remaining());
|
||||
} else {
|
||||
final byte[] tmp = new byte[b.remaining()];
|
||||
b.get(tmp);
|
||||
output(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
public void input(final ByteBuffer b) {
|
||||
Args.notNull(b, "Input");
|
||||
if (b.hasArray()) {
|
||||
input(b.array(), b.arrayOffset() + b.position(), b.remaining());
|
||||
} else {
|
||||
final byte[] tmp = new byte[b.remaining()];
|
||||
b.get(tmp);
|
||||
input(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -32,7 +32,6 @@ import org.apache.hc.core5.annotation.Contract;
|
|||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
|
||||
|
@ -59,7 +58,6 @@ public class DefaultProxyRoutePlanner extends DefaultRoutePlanner {
|
|||
@Override
|
||||
protected HttpHost determineProxy(
|
||||
final HttpHost target,
|
||||
final HttpRequest request,
|
||||
final HttpContext context) throws HttpException {
|
||||
return proxy;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import org.apache.hc.core5.http.HttpHost;
|
|||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.ProtocolException;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
import org.apache.hc.core5.net.URIAuthority;
|
||||
|
||||
/**
|
||||
* Default implementation of an {@link HttpRoutePlanner}. It will not make use of
|
||||
|
@ -63,11 +63,7 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
|
|||
}
|
||||
|
||||
@Override
|
||||
public HttpRoute determineRoute(
|
||||
final HttpHost host,
|
||||
final HttpRequest request,
|
||||
final HttpContext context) throws HttpException {
|
||||
Args.notNull(request, "Request");
|
||||
public HttpRoute determineRoute(final HttpHost host, final HttpContext context) throws HttpException {
|
||||
if (host == null) {
|
||||
throw new ProtocolException("Target host is not specified");
|
||||
}
|
||||
|
@ -76,7 +72,7 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
|
|||
final InetAddress local = config.getLocalAddress();
|
||||
HttpHost proxy = config.getProxy();
|
||||
if (proxy == null) {
|
||||
proxy = determineProxy(host, request, context);
|
||||
proxy = determineProxy(host, context);
|
||||
}
|
||||
|
||||
final HttpHost target;
|
||||
|
@ -100,6 +96,20 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHost determineTargetHost(final HttpRequest request, final HttpContext context) throws HttpException {
|
||||
final URIAuthority authority = request.getAuthority();
|
||||
if (authority != null) {
|
||||
final String scheme = request.getScheme();
|
||||
if (scheme == null) {
|
||||
throw new ProtocolException("Protocol scheme is not specified");
|
||||
}
|
||||
return new HttpHost(authority, scheme);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns null.
|
||||
*
|
||||
|
@ -107,7 +117,6 @@ public class DefaultRoutePlanner implements HttpRoutePlanner {
|
|||
*/
|
||||
protected HttpHost determineProxy(
|
||||
final HttpHost target,
|
||||
final HttpRequest request,
|
||||
final HttpContext context) throws HttpException {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ import org.apache.hc.core5.annotation.Contract;
|
|||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
|
||||
/**
|
||||
|
@ -73,10 +72,7 @@ public class SystemDefaultRoutePlanner extends DefaultRoutePlanner {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected HttpHost determineProxy(
|
||||
final HttpHost target,
|
||||
final HttpRequest request,
|
||||
final HttpContext context) throws HttpException {
|
||||
protected HttpHost determineProxy(final HttpHost target, final HttpContext context) throws HttpException {
|
||||
final URI targetURI;
|
||||
try {
|
||||
targetURI = new URI(target.toURI());
|
||||
|
|
|
@ -25,11 +25,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl;
|
||||
package org.apache.hc.client5.http.impl.sync;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.hc.client5.http.impl.sync.AbstractResponseHandler;
|
||||
import org.apache.hc.client5.http.protocol.ClientProtocolException;
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
|
@ -39,13 +38,13 @@ import org.apache.hc.core5.http.ParseException;
|
|||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
|
||||
/**
|
||||
* A {@link org.apache.hc.client5.http.sync.ResponseHandler} that returns the response body as a String
|
||||
* A {@link org.apache.hc.core5.http.io.ResponseHandler} that returns the response body as a String
|
||||
* for successful (2xx) responses. If the response code was >= 300, the response
|
||||
* body is consumed and an {@link org.apache.hc.client5.http.protocol.HttpResponseException} is thrown.
|
||||
* <p>
|
||||
* If this is used with
|
||||
* {@link org.apache.hc.client5.http.sync.HttpClient#execute(
|
||||
* org.apache.hc.core5.http.ClassicHttpRequest, org.apache.hc.client5.http.sync.ResponseHandler)},
|
||||
* org.apache.hc.core5.http.ClassicHttpRequest, org.apache.hc.core5.http.io.ResponseHandler)},
|
||||
* HttpClient may handle redirects (3xx responses) internally.
|
||||
* </p>
|
||||
*
|
|
@ -32,12 +32,11 @@ import java.io.IOException;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.hc.client5.http.io.ConnectionReleaseTrigger;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.concurrent.Cancellable;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
|
@ -46,26 +45,25 @@ import org.apache.logging.log4j.Logger;
|
|||
* @since 4.3
|
||||
*/
|
||||
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
|
||||
class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable {
|
||||
class EndpointHolder implements Cancellable, Closeable {
|
||||
|
||||
private final Logger log;
|
||||
|
||||
private final HttpClientConnectionManager manager;
|
||||
private final HttpClientConnection managedConn;
|
||||
private final ConnectionEndpoint endpoint;
|
||||
private final AtomicBoolean released;
|
||||
private volatile boolean reusable;
|
||||
private volatile Object state;
|
||||
private volatile long validDuration;
|
||||
private volatile TimeUnit tunit;
|
||||
|
||||
public ConnectionHolder(
|
||||
public EndpointHolder(
|
||||
final Logger log,
|
||||
final HttpClientConnectionManager manager,
|
||||
final HttpClientConnection managedConn) {
|
||||
final ConnectionEndpoint endpoint) {
|
||||
super();
|
||||
this.log = log;
|
||||
this.manager = manager;
|
||||
this.managedConn = managedConn;
|
||||
this.endpoint = endpoint;
|
||||
this.released = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
|
@ -86,54 +84,46 @@ class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeab
|
|||
}
|
||||
|
||||
public void setValidFor(final long duration, final TimeUnit tunit) {
|
||||
synchronized (this.managedConn) {
|
||||
this.validDuration = duration;
|
||||
this.tunit = tunit;
|
||||
}
|
||||
this.validDuration = (tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(duration);
|
||||
}
|
||||
|
||||
private void releaseConnection(final boolean reusable) {
|
||||
if (this.released.compareAndSet(false, true)) {
|
||||
synchronized (this.managedConn) {
|
||||
synchronized (this.endpoint) {
|
||||
if (reusable) {
|
||||
this.manager.releaseConnection(this.managedConn,
|
||||
this.state, this.validDuration, this.tunit);
|
||||
this.manager.release(this.endpoint, this.state, this.validDuration, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
try {
|
||||
this.managedConn.close();
|
||||
this.endpoint.close();
|
||||
log.debug("Connection discarded");
|
||||
} catch (final IOException ex) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(ex.getMessage(), ex);
|
||||
}
|
||||
} finally {
|
||||
this.manager.releaseConnection(
|
||||
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
this.manager.release(this.endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection() {
|
||||
releaseConnection(this.reusable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void abortConnection() {
|
||||
if (this.released.compareAndSet(false, true)) {
|
||||
synchronized (this.managedConn) {
|
||||
synchronized (this.endpoint) {
|
||||
try {
|
||||
this.managedConn.shutdown();
|
||||
this.endpoint.shutdown();
|
||||
log.debug("Connection discarded");
|
||||
} catch (final IOException ex) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(ex.getMessage(), ex);
|
||||
}
|
||||
} finally {
|
||||
this.manager.releaseConnection(
|
||||
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
this.manager.release(this.endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -99,7 +99,7 @@ import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
|
|||
import org.apache.hc.core5.http.protocol.RequestContent;
|
||||
import org.apache.hc.core5.http.protocol.RequestTargetHost;
|
||||
import org.apache.hc.core5.http.protocol.RequestUserAgent;
|
||||
import org.apache.hc.core5.util.TextUtils;
|
||||
import org.apache.hc.core5.pool.ConnPoolControl;
|
||||
import org.apache.hc.core5.util.VersionInfo;
|
||||
|
||||
/**
|
||||
|
@ -547,14 +547,11 @@ public class HttpClientBuilder {
|
|||
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
|
||||
* to stop and release the background thread.
|
||||
* <p>
|
||||
* Please note this method has no effect if the instance of HttpClient is configuted to
|
||||
* Please note this method has no effect if the instance of HttpClient is configured to
|
||||
* use a shared connection manager.
|
||||
* <p>
|
||||
* Please note this method may not be used when the instance of HttpClient is created
|
||||
* inside an EJB container.
|
||||
*
|
||||
* @see #setConnectionManagerShared(boolean)
|
||||
* @see HttpClientConnectionManager#closeExpired()
|
||||
* @see ConnPoolControl#closeExpired()
|
||||
*
|
||||
* @since 4.4
|
||||
*/
|
||||
|
@ -570,14 +567,11 @@ public class HttpClientBuilder {
|
|||
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
|
||||
* to stop and release the background thread.
|
||||
* <p>
|
||||
* Please note this method has no effect if the instance of HttpClient is configuted to
|
||||
* Please note this method has no effect if the instance of HttpClient is configured to
|
||||
* use a shared connection manager.
|
||||
* <p>
|
||||
* Please note this method may not be used when the instance of HttpClient is created
|
||||
* inside an EJB container.
|
||||
*
|
||||
* @see #setConnectionManagerShared(boolean)
|
||||
* @see HttpClientConnectionManager#closeExpired()
|
||||
* @see ConnPoolControl#closeIdle(long, TimeUnit)
|
||||
*
|
||||
* @param maxIdleTime maximum time persistent connections can stay idle while kept alive
|
||||
* in the connection pool. Connections whose inactivity period exceeds this value will
|
||||
|
@ -652,13 +646,6 @@ public class HttpClientBuilder {
|
|||
closeables.add(closeable);
|
||||
}
|
||||
|
||||
private static String[] split(final String s) {
|
||||
if (TextUtils.isBlank(s)) {
|
||||
return null;
|
||||
}
|
||||
return s.split(" *, *");
|
||||
}
|
||||
|
||||
public CloseableHttpClient build() {
|
||||
// Create main request executor
|
||||
// We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
|
||||
|
@ -873,10 +860,9 @@ public class HttpClientBuilder {
|
|||
if (closeablesCopy == null) {
|
||||
closeablesCopy = new ArrayList<>(1);
|
||||
}
|
||||
final HttpClientConnectionManager cm = connManagerCopy;
|
||||
|
||||
if (evictExpiredConnections || evictIdleConnections) {
|
||||
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
|
||||
if (connManagerCopy instanceof ConnPoolControl) {
|
||||
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor((ConnPoolControl<?>) connManagerCopy,
|
||||
maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS);
|
||||
closeablesCopy.add(new Closeable() {
|
||||
|
||||
|
@ -888,19 +874,12 @@ public class HttpClientBuilder {
|
|||
});
|
||||
connectionEvictor.start();
|
||||
}
|
||||
closeablesCopy.add(new Closeable() {
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
cm.shutdown();
|
||||
}
|
||||
|
||||
});
|
||||
closeablesCopy.add(connManagerCopy);
|
||||
}
|
||||
|
||||
return new InternalHttpClient(
|
||||
execChain,
|
||||
connManagerCopy,
|
||||
routePlannerCopy,
|
||||
cookieSpecRegistryCopy,
|
||||
authSchemeRegistryCopy,
|
||||
|
|
|
@ -30,7 +30,8 @@ package org.apache.hc.client5.http.impl.sync;
|
|||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.impl.DefaultThreadFactory;
|
||||
import org.apache.hc.core5.pool.ConnPoolControl;
|
||||
import org.apache.hc.core5.util.Args;
|
||||
|
||||
/**
|
||||
|
@ -41,7 +42,6 @@ import org.apache.hc.core5.util.Args;
|
|||
*/
|
||||
public final class IdleConnectionEvictor {
|
||||
|
||||
private final HttpClientConnectionManager connectionManager;
|
||||
private final ThreadFactory threadFactory;
|
||||
private final Thread thread;
|
||||
private final long sleepTimeMs;
|
||||
|
@ -50,12 +50,12 @@ public final class IdleConnectionEvictor {
|
|||
private volatile Exception exception;
|
||||
|
||||
public IdleConnectionEvictor(
|
||||
final HttpClientConnectionManager connectionManager,
|
||||
final ConnPoolControl<?> connectionManager,
|
||||
final ThreadFactory threadFactory,
|
||||
final long sleepTime, final TimeUnit sleepTimeUnit,
|
||||
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
||||
this.connectionManager = Args.notNull(connectionManager, "Connection manager");
|
||||
this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();
|
||||
Args.notNull(connectionManager, "Connection manager");
|
||||
this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory("idle-connection-evictor", true);
|
||||
this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
|
||||
this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;
|
||||
this.thread = this.threadFactory.newThread(new Runnable() {
|
||||
|
@ -78,14 +78,14 @@ public final class IdleConnectionEvictor {
|
|||
}
|
||||
|
||||
public IdleConnectionEvictor(
|
||||
final HttpClientConnectionManager connectionManager,
|
||||
final ConnPoolControl<?> connectionManager,
|
||||
final long sleepTime, final TimeUnit sleepTimeUnit,
|
||||
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
||||
this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);
|
||||
}
|
||||
|
||||
public IdleConnectionEvictor(
|
||||
final HttpClientConnectionManager connectionManager,
|
||||
final ConnPoolControl<?> connectionManager,
|
||||
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
||||
this(connectionManager, null,
|
||||
maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,
|
||||
|
@ -108,16 +108,4 @@ public final class IdleConnectionEvictor {
|
|||
thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time));
|
||||
}
|
||||
|
||||
static class DefaultThreadFactory implements ThreadFactory {
|
||||
|
||||
@Override
|
||||
public Thread newThread(final Runnable r) {
|
||||
final Thread t = new Thread(r, "Connection evictor");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.apache.hc.client5.http.auth.CredentialsProvider;
|
|||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
|
||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.methods.Configurable;
|
||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||
|
@ -70,7 +69,6 @@ class InternalHttpClient extends CloseableHttpClient implements Configurable {
|
|||
private final Logger log = LogManager.getLogger(getClass());
|
||||
|
||||
private final ClientExecChain execChain;
|
||||
private final HttpClientConnectionManager connManager;
|
||||
private final HttpRoutePlanner routePlanner;
|
||||
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
|
||||
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
|
||||
|
@ -81,7 +79,6 @@ class InternalHttpClient extends CloseableHttpClient implements Configurable {
|
|||
|
||||
public InternalHttpClient(
|
||||
final ClientExecChain execChain,
|
||||
final HttpClientConnectionManager connManager,
|
||||
final HttpRoutePlanner routePlanner,
|
||||
final Lookup<CookieSpecProvider> cookieSpecRegistry,
|
||||
final Lookup<AuthSchemeProvider> authSchemeRegistry,
|
||||
|
@ -91,10 +88,8 @@ class InternalHttpClient extends CloseableHttpClient implements Configurable {
|
|||
final List<Closeable> closeables) {
|
||||
super();
|
||||
Args.notNull(execChain, "HTTP client exec chain");
|
||||
Args.notNull(connManager, "HTTP connection manager");
|
||||
Args.notNull(routePlanner, "HTTP route planner");
|
||||
this.execChain = execChain;
|
||||
this.connManager = connManager;
|
||||
this.routePlanner = routePlanner;
|
||||
this.cookieSpecRegistry = cookieSpecRegistry;
|
||||
this.authSchemeRegistry = authSchemeRegistry;
|
||||
|
@ -105,10 +100,11 @@ class InternalHttpClient extends CloseableHttpClient implements Configurable {
|
|||
}
|
||||
|
||||
private HttpRoute determineRoute(
|
||||
final HttpHost target,
|
||||
final HttpHost host,
|
||||
final HttpRequest request,
|
||||
final HttpContext context) throws HttpException {
|
||||
return this.routePlanner.determineRoute(target, request, context);
|
||||
final HttpHost target = host != null ? host : this.routePlanner.determineTargetHost(request, context);
|
||||
return this.routePlanner.determineRoute(target, context);
|
||||
}
|
||||
|
||||
private void setupContext(final HttpClientContext context) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.io.IOException;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
|
@ -39,10 +40,11 @@ import org.apache.hc.client5.http.auth.AuthExchange;
|
|||
import org.apache.hc.client5.http.auth.ChallengeType;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
|
||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.impl.routing.BasicRouteDirector;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||
import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
|
||||
|
@ -54,6 +56,7 @@ import org.apache.hc.core5.annotation.Contract;
|
|||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
|
||||
import org.apache.hc.core5.http.ConnectionReuseStrategy;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
|
@ -64,7 +67,6 @@ import org.apache.hc.core5.http.HttpResponse;
|
|||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.HttpVersion;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.entity.BufferedHttpEntity;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
|
@ -162,22 +164,24 @@ public class MainClientExec implements ClientExecChain {
|
|||
|
||||
Object userToken = context.getUserToken();
|
||||
|
||||
final ConnectionRequest connRequest = connManager.requestConnection(route, userToken);
|
||||
final LeaseRequest leaseRequest = connManager.lease(route, userToken);
|
||||
if (execAware != null) {
|
||||
if (execAware.isAborted()) {
|
||||
connRequest.cancel();
|
||||
leaseRequest.cancel();
|
||||
throw new RequestAbortedException("Request aborted");
|
||||
} else {
|
||||
execAware.setCancellable(connRequest);
|
||||
execAware.setCancellable(leaseRequest);
|
||||
}
|
||||
}
|
||||
|
||||
final RequestConfig config = context.getRequestConfig();
|
||||
|
||||
final HttpClientConnection managedConn;
|
||||
final ConnectionEndpoint endpoint;
|
||||
try {
|
||||
final int timeout = config.getConnectionRequestTimeout();
|
||||
managedConn = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
|
||||
endpoint = leaseRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
|
||||
} catch(final TimeoutException ex) {
|
||||
throw new ConnectionRequestTimeoutException(ex.getMessage());
|
||||
} catch(final InterruptedException interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RequestAbortedException("Request aborted", interrupted);
|
||||
|
@ -189,12 +193,12 @@ public class MainClientExec implements ClientExecChain {
|
|||
throw new RequestAbortedException("Request execution failed", cause);
|
||||
}
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, endpoint);
|
||||
|
||||
final ConnectionHolder connHolder = new ConnectionHolder(this.log, this.connManager, managedConn);
|
||||
final EndpointHolder endpointHolder = new EndpointHolder(this.log, this.connManager, endpoint);
|
||||
try {
|
||||
if (execAware != null) {
|
||||
execAware.setCancellable(connHolder);
|
||||
execAware.setCancellable(endpointHolder);
|
||||
}
|
||||
|
||||
final AuthExchange targetAuthExchange = context.getAuthExchange(route.getTargetHost());
|
||||
|
@ -213,10 +217,12 @@ public class MainClientExec implements ClientExecChain {
|
|||
throw new RequestAbortedException("Request aborted");
|
||||
}
|
||||
|
||||
if (!managedConn.isOpen()) {
|
||||
if (!endpoint.isConnected()) {
|
||||
endpointHolder.markNonReusable();
|
||||
this.log.debug("Opening connection " + route);
|
||||
try {
|
||||
establishRoute(managedConn, route, request, context);
|
||||
establishRoute(endpoint, route, request, context);
|
||||
endpointHolder.markReusable();
|
||||
} catch (final TunnelRefusedException ex) {
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug(ex.getMessage());
|
||||
|
@ -227,7 +233,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
}
|
||||
final int timeout = config.getSocketTimeout();
|
||||
if (timeout >= 0) {
|
||||
managedConn.setSocketTimeout(timeout);
|
||||
endpoint.setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
if (execAware != null && execAware.isAborted()) {
|
||||
|
@ -253,7 +259,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
route.getProxyHost(), ChallengeType.PROXY, request, proxyAuthExchange, context);
|
||||
}
|
||||
|
||||
response = requestExecutor.execute(request, managedConn, context);
|
||||
response = endpoint.execute(request, requestExecutor, context);
|
||||
|
||||
// The connection is in or can be brought to a re-usable state.
|
||||
if (reuseStrategy.keepAlive(request, response, context)) {
|
||||
|
@ -268,10 +274,10 @@ public class MainClientExec implements ClientExecChain {
|
|||
}
|
||||
this.log.debug("Connection can be kept alive " + s);
|
||||
}
|
||||
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
||||
connHolder.markReusable();
|
||||
endpointHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
||||
endpointHolder.markReusable();
|
||||
} else {
|
||||
connHolder.markNonReusable();
|
||||
endpointHolder.markNonReusable();
|
||||
}
|
||||
|
||||
if (request.getMethod().equalsIgnoreCase("TRACE")) {
|
||||
|
@ -283,10 +289,10 @@ public class MainClientExec implements ClientExecChain {
|
|||
targetAuthExchange, proxyAuthExchange, route, request, response, context)) {
|
||||
// Make sure the response body is fully consumed, if present
|
||||
final HttpEntity entity = response.getEntity();
|
||||
if (connHolder.isReusable()) {
|
||||
if (endpointHolder.isReusable()) {
|
||||
EntityUtils.consume(entity);
|
||||
} else {
|
||||
managedConn.close();
|
||||
endpoint.close();
|
||||
if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
|
||||
&& proxyAuthExchange.getAuthScheme() != null
|
||||
&& proxyAuthExchange.getAuthScheme().isConnectionBased()) {
|
||||
|
@ -318,18 +324,18 @@ public class MainClientExec implements ClientExecChain {
|
|||
context.setAttribute(HttpClientContext.USER_TOKEN, userToken);
|
||||
}
|
||||
if (userToken != null) {
|
||||
connHolder.setState(userToken);
|
||||
endpointHolder.setState(userToken);
|
||||
}
|
||||
|
||||
// check for entity, release connection if possible
|
||||
final HttpEntity entity = response.getEntity();
|
||||
if (entity == null || !entity.isStreaming()) {
|
||||
// connection not needed and (assumed to be) in re-usable state
|
||||
connHolder.releaseConnection();
|
||||
endpointHolder.releaseConnection();
|
||||
return new CloseableHttpResponse(response, null);
|
||||
} else {
|
||||
ResponseEntityProxy.enchance(response, connHolder);
|
||||
return new CloseableHttpResponse(response, connHolder);
|
||||
ResponseEntityProxy.enchance(response, endpointHolder);
|
||||
return new CloseableHttpResponse(response, endpointHolder);
|
||||
}
|
||||
} catch (final ConnectionShutdownException ex) {
|
||||
final InterruptedIOException ioex = new InterruptedIOException(
|
||||
|
@ -337,7 +343,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
ioex.initCause(ex);
|
||||
throw ioex;
|
||||
} catch (final HttpException | RuntimeException | IOException ex) {
|
||||
connHolder.abortConnection();
|
||||
endpointHolder.abortConnection();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -346,7 +352,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
* Establishes the target route.
|
||||
*/
|
||||
void establishRoute(
|
||||
final HttpClientConnection managedConn,
|
||||
final ConnectionEndpoint endpoint,
|
||||
final HttpRoute route,
|
||||
final HttpRequest request,
|
||||
final HttpClientContext context) throws HttpException, IOException {
|
||||
|
@ -362,23 +368,23 @@ public class MainClientExec implements ClientExecChain {
|
|||
|
||||
case HttpRouteDirector.CONNECT_TARGET:
|
||||
this.connManager.connect(
|
||||
managedConn,
|
||||
route,
|
||||
endpoint,
|
||||
timeout > 0 ? timeout : 0,
|
||||
TimeUnit.MILLISECONDS,
|
||||
context);
|
||||
tracker.connectTarget(route.isSecure());
|
||||
break;
|
||||
case HttpRouteDirector.CONNECT_PROXY:
|
||||
this.connManager.connect(
|
||||
managedConn,
|
||||
route,
|
||||
endpoint,
|
||||
timeout > 0 ? timeout : 0,
|
||||
TimeUnit.MILLISECONDS,
|
||||
context);
|
||||
final HttpHost proxy = route.getProxyHost();
|
||||
tracker.connectProxy(proxy, false);
|
||||
break;
|
||||
case HttpRouteDirector.TUNNEL_TARGET: {
|
||||
final boolean secure = createTunnelToTarget(managedConn, route, request, context);
|
||||
final boolean secure = createTunnelToTarget(endpoint, route, request, context);
|
||||
this.log.debug("Tunnel to target created.");
|
||||
tracker.tunnelTarget(secure);
|
||||
} break;
|
||||
|
@ -395,7 +401,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
} break;
|
||||
|
||||
case HttpRouteDirector.LAYER_PROTOCOL:
|
||||
this.connManager.upgrade(managedConn, route, context);
|
||||
this.connManager.upgrade(endpoint, context);
|
||||
tracker.layerProtocol(route.isSecure());
|
||||
break;
|
||||
|
||||
|
@ -403,7 +409,6 @@ public class MainClientExec implements ClientExecChain {
|
|||
throw new HttpException("Unable to establish route: " +
|
||||
"planned = " + route + "; current = " + fact);
|
||||
case HttpRouteDirector.COMPLETE:
|
||||
this.connManager.routeComplete(managedConn, route, context);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown step indicator "
|
||||
|
@ -422,7 +427,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
* information about the tunnel, that is left to the caller.
|
||||
*/
|
||||
private boolean createTunnelToTarget(
|
||||
final HttpClientConnection managedConn,
|
||||
final ConnectionEndpoint endpoint,
|
||||
final HttpRoute route,
|
||||
final HttpRequest request,
|
||||
final HttpClientContext context) throws HttpException, IOException {
|
||||
|
@ -442,18 +447,18 @@ public class MainClientExec implements ClientExecChain {
|
|||
this.requestExecutor.preProcess(connect, this.proxyHttpProcessor, context);
|
||||
|
||||
while (response == null) {
|
||||
if (!managedConn.isOpen()) {
|
||||
if (!endpoint.isConnected()) {
|
||||
this.connManager.connect(
|
||||
managedConn,
|
||||
route,
|
||||
endpoint,
|
||||
timeout > 0 ? timeout : 0,
|
||||
TimeUnit.MILLISECONDS,
|
||||
context);
|
||||
}
|
||||
|
||||
connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
|
||||
this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, proxyAuthExchange, context);
|
||||
|
||||
response = this.requestExecutor.execute(connect, managedConn, context);
|
||||
response = endpoint.execute(connect, this.requestExecutor, context);
|
||||
|
||||
final int status = response.getCode();
|
||||
if (status < HttpStatus.SC_SUCCESS) {
|
||||
|
@ -472,7 +477,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
final HttpEntity entity = response.getEntity();
|
||||
EntityUtils.consume(entity);
|
||||
} else {
|
||||
managedConn.close();
|
||||
endpoint.close();
|
||||
}
|
||||
response = null;
|
||||
}
|
||||
|
@ -489,7 +494,7 @@ public class MainClientExec implements ClientExecChain {
|
|||
response.setEntity(new BufferedHttpEntity(entity));
|
||||
}
|
||||
|
||||
managedConn.close();
|
||||
endpoint.close();
|
||||
throw new TunnelRefusedException("CONNECT refused by proxy: " +
|
||||
new StatusLine(response), response);
|
||||
}
|
||||
|
|
|
@ -31,13 +31,16 @@ import java.io.IOException;
|
|||
import java.io.InterruptedIOException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
|
||||
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
|
@ -45,11 +48,12 @@ import org.apache.hc.client5.http.protocol.RequestClientConnControl;
|
|||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
|
||||
import org.apache.hc.core5.http.ConnectionReuseStrategy;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
|
||||
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpProcessor;
|
||||
|
@ -86,20 +90,16 @@ public class MinimalClientExec implements ClientExecChain {
|
|||
final HttpClientConnectionManager connManager,
|
||||
final ConnectionReuseStrategy reuseStrategy,
|
||||
final ConnectionKeepAliveStrategy keepAliveStrategy) {
|
||||
Args.notNull(requestExecutor, "HTTP request executor");
|
||||
Args.notNull(connManager, "Client connection manager");
|
||||
Args.notNull(reuseStrategy, "Connection reuse strategy");
|
||||
Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
|
||||
this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
|
||||
this.connManager = Args.notNull(connManager, "Connection manager");
|
||||
this.reuseStrategy = reuseStrategy != null ? reuseStrategy : DefaultConnectionReuseStrategy.INSTANCE;
|
||||
this.keepAliveStrategy = keepAliveStrategy != null ? keepAliveStrategy : DefaultConnectionKeepAliveStrategy.INSTANCE;
|
||||
this.httpProcessor = new DefaultHttpProcessor(
|
||||
new RequestContent(),
|
||||
new RequestTargetHost(),
|
||||
new RequestClientConnControl(),
|
||||
new RequestUserAgent(VersionInfo.getSoftwareInfo(
|
||||
"Apache-HttpClient", "org.apache.hc.client5", getClass())));
|
||||
this.requestExecutor = requestExecutor;
|
||||
this.connManager = connManager;
|
||||
this.reuseStrategy = reuseStrategy;
|
||||
this.keepAliveStrategy = keepAliveStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +111,7 @@ public class MinimalClientExec implements ClientExecChain {
|
|||
Args.notNull(context, "HTTP context");
|
||||
|
||||
final HttpRoute route = request.getRoute();
|
||||
final ConnectionRequest connRequest = connManager.requestConnection(route, null);
|
||||
final LeaseRequest connRequest = connManager.lease(route, null);
|
||||
if (execAware != null) {
|
||||
if (execAware.isAborted()) {
|
||||
connRequest.cancel();
|
||||
|
@ -122,10 +122,12 @@ public class MinimalClientExec implements ClientExecChain {
|
|||
|
||||
final RequestConfig config = context.getRequestConfig();
|
||||
|
||||
final HttpClientConnection managedConn;
|
||||
final ConnectionEndpoint endpoint;
|
||||
try {
|
||||
final int timeout = config.getConnectionRequestTimeout();
|
||||
managedConn = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
|
||||
endpoint = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
|
||||
} catch(final TimeoutException ex) {
|
||||
throw new ConnectionRequestTimeoutException(ex.getMessage());
|
||||
} catch(final InterruptedException interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RequestAbortedException("Request aborted", interrupted);
|
||||
|
@ -137,57 +139,54 @@ public class MinimalClientExec implements ClientExecChain {
|
|||
throw new RequestAbortedException("Request execution failed", cause);
|
||||
}
|
||||
|
||||
final ConnectionHolder connHolder = new ConnectionHolder(log, connManager, managedConn);
|
||||
final EndpointHolder endpointHolder = new EndpointHolder(log, connManager, endpoint);
|
||||
try {
|
||||
if (execAware != null) {
|
||||
if (execAware.isAborted()) {
|
||||
connHolder.close();
|
||||
endpointHolder.close();
|
||||
throw new RequestAbortedException("Request aborted");
|
||||
}
|
||||
execAware.setCancellable(connHolder);
|
||||
execAware.setCancellable(endpointHolder);
|
||||
}
|
||||
|
||||
if (!managedConn.isOpen()) {
|
||||
if (!endpoint.isConnected()) {
|
||||
final int timeout = config.getConnectTimeout();
|
||||
this.connManager.connect(
|
||||
managedConn,
|
||||
route,
|
||||
endpoint,
|
||||
timeout > 0 ? timeout : 0,
|
||||
TimeUnit.MILLISECONDS,
|
||||
context);
|
||||
this.connManager.routeComplete(managedConn, route, context);
|
||||
}
|
||||
final int timeout = config.getSocketTimeout();
|
||||
if (timeout >= 0) {
|
||||
managedConn.setSocketTimeout(timeout);
|
||||
endpoint.setSocketTimeout(timeout);
|
||||
}
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
|
||||
context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
|
||||
|
||||
httpProcessor.process(request, request.getEntity(), context);
|
||||
final ClassicHttpResponse response = requestExecutor.execute(request, managedConn, context);
|
||||
final ClassicHttpResponse response = endpoint.execute(request, requestExecutor, context);
|
||||
httpProcessor.process(response, response.getEntity(), context);
|
||||
|
||||
// The connection is in or can be brought to a re-usable state.
|
||||
if (reuseStrategy.keepAlive(request, response, context)) {
|
||||
// Set the idle duration of this connection
|
||||
final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
|
||||
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
||||
connHolder.markReusable();
|
||||
endpointHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
||||
endpointHolder.markReusable();
|
||||
} else {
|
||||
connHolder.markNonReusable();
|
||||
endpointHolder.markNonReusable();
|
||||
}
|
||||
|
||||
// check for entity, release connection if possible
|
||||
final HttpEntity entity = response.getEntity();
|
||||
if (entity == null || !entity.isStreaming()) {
|
||||
// connection not needed and (assumed to be) in re-usable state
|
||||
connHolder.releaseConnection();
|
||||
endpointHolder.releaseConnection();
|
||||
return new CloseableHttpResponse(response, null);
|
||||
} else {
|
||||
ResponseEntityProxy.enchance(response, connHolder);
|
||||
return new CloseableHttpResponse(response, connHolder);
|
||||
ResponseEntityProxy.enchance(response, endpointHolder);
|
||||
return new CloseableHttpResponse(response, endpointHolder);
|
||||
}
|
||||
} catch (final ConnectionShutdownException ex) {
|
||||
final InterruptedIOException ioex = new InterruptedIOException(
|
||||
|
@ -195,7 +194,7 @@ public class MinimalClientExec implements ClientExecChain {
|
|||
ioex.initCause(ex);
|
||||
throw ioex;
|
||||
} catch (final HttpException | RuntimeException | IOException ex) {
|
||||
connHolder.abortConnection();
|
||||
endpointHolder.abortConnection();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ class MinimalHttpClient extends CloseableHttpClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.connManager.shutdown();
|
||||
public void close() throws IOException {
|
||||
this.connManager.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ package org.apache.hc.client5.http.impl.sync;
|
|||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.RouteInfo.LayerType;
|
||||
import org.apache.hc.client5.http.RouteInfo.TunnelType;
|
||||
|
@ -66,6 +65,7 @@ import org.apache.hc.core5.http.config.Lookup;
|
|||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||
import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.http.io.entity.BufferedHttpEntity;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
|
@ -83,7 +83,7 @@ import org.apache.hc.core5.util.Args;
|
|||
*/
|
||||
public class ProxyClient {
|
||||
|
||||
private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
||||
private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||
private final ConnectionConfig connectionConfig;
|
||||
private final RequestConfig requestConfig;
|
||||
private final HttpProcessor httpProcessor;
|
||||
|
@ -98,7 +98,7 @@ public class ProxyClient {
|
|||
* @since 4.3
|
||||
*/
|
||||
public ProxyClient(
|
||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
||||
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||
final ConnectionConfig connectionConfig,
|
||||
final RequestConfig requestConfig) {
|
||||
super();
|
||||
|
@ -148,8 +148,7 @@ public class ProxyClient {
|
|||
this.requestConfig.getLocalAddress(),
|
||||
proxy, false, TunnelType.TUNNELLED, LayerType.PLAIN);
|
||||
|
||||
final ManagedHttpClientConnection conn = this.connFactory.create(
|
||||
route, this.connectionConfig);
|
||||
final ManagedHttpClientConnection conn = this.connFactory.createConnection(null);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
ClassicHttpResponse response;
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ public class RedirectExec implements ClientExecChain {
|
|||
}
|
||||
}
|
||||
|
||||
currentRoute = this.routePlanner.determineRoute(newTarget, redirect, context);
|
||||
currentRoute = this.routePlanner.determineRoute(newTarget, context);
|
||||
if (this.log.isDebugEnabled()) {
|
||||
this.log.debug("Redirecting to '" + redirectUri + "' via " + currentRoute);
|
||||
}
|
||||
|
|
|
@ -45,35 +45,35 @@ import org.apache.hc.core5.http.io.entity.HttpEntityWrapper;
|
|||
*/
|
||||
class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher {
|
||||
|
||||
private final ConnectionHolder connHolder;
|
||||
private final EndpointHolder endpointHolder;
|
||||
|
||||
public static void enchance(final ClassicHttpResponse response, final ConnectionHolder connHolder) {
|
||||
public static void enchance(final ClassicHttpResponse response, final EndpointHolder connHolder) {
|
||||
final HttpEntity entity = response.getEntity();
|
||||
if (entity != null && entity.isStreaming() && connHolder != null) {
|
||||
response.setEntity(new ResponseEntityProxy(entity, connHolder));
|
||||
}
|
||||
}
|
||||
|
||||
ResponseEntityProxy(final HttpEntity entity, final ConnectionHolder connHolder) {
|
||||
ResponseEntityProxy(final HttpEntity entity, final EndpointHolder endpointHolder) {
|
||||
super(entity);
|
||||
this.connHolder = connHolder;
|
||||
this.endpointHolder = endpointHolder;
|
||||
}
|
||||
|
||||
private void cleanup() throws IOException {
|
||||
if (this.connHolder != null) {
|
||||
this.connHolder.close();
|
||||
if (this.endpointHolder != null) {
|
||||
this.endpointHolder.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void abortConnection() {
|
||||
if (this.connHolder != null) {
|
||||
this.connHolder.abortConnection();
|
||||
if (this.endpointHolder != null) {
|
||||
this.endpointHolder.abortConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseConnection() {
|
||||
if (this.connHolder != null) {
|
||||
this.connHolder.releaseConnection();
|
||||
if (this.endpointHolder != null) {
|
||||
this.endpointHolder.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher
|
|||
@Override
|
||||
public boolean streamClosed(final InputStream wrapped) throws IOException {
|
||||
try {
|
||||
final boolean open = connHolder != null && !connHolder.isReleased();
|
||||
final boolean open = endpointHolder != null && !endpointHolder.isReleased();
|
||||
// this assumes that closing the stream will
|
||||
// consume the remainder of the response body:
|
||||
try {
|
||||
|
|
|
@ -25,33 +25,36 @@
|
|||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http;
|
||||
package org.apache.hc.client5.http.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.hc.core5.annotation.Contract;
|
||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
|
||||
/**
|
||||
* A timeout while waiting for an available connection
|
||||
* from a connection manager.
|
||||
* Client connection endpoint that can be used to execute message exchanges.
|
||||
*
|
||||
*
|
||||
* @since 4.0
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ConnectionPoolTimeoutException extends ConnectTimeoutException {
|
||||
@Contract(threading = ThreadingBehavior.SAFE)
|
||||
public abstract class ConnectionEndpoint implements Closeable {
|
||||
|
||||
private static final long serialVersionUID = -7898874842020245128L;
|
||||
public abstract ClassicHttpResponse execute(
|
||||
ClassicHttpRequest request,
|
||||
HttpRequestExecutor executor,
|
||||
HttpContext context) throws IOException, HttpException;
|
||||
|
||||
/**
|
||||
* Creates a ConnectTimeoutException with a {@code null} detail message.
|
||||
*/
|
||||
public ConnectionPoolTimeoutException() {
|
||||
super();
|
||||
}
|
||||
public abstract boolean isConnected();
|
||||
|
||||
/**
|
||||
* Creates a ConnectTimeoutException with the specified detail message.
|
||||
*
|
||||
* @param message The exception detail message
|
||||
*/
|
||||
public ConnectionPoolTimeoutException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
public abstract void setSocketTimeout(int timeout);
|
||||
|
||||
public abstract void shutdown() throws IOException;
|
||||
|
||||
}
|
|
@ -1,70 +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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.hc.client5.http.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Interface for releasing a connection. This can be implemented by various
|
||||
* "trigger" objects which are associated with a leased connection, for example
|
||||
* a {@link org.apache.hc.core5.http.io.EofSensorInputStream}
|
||||
* or the {@link ManagedHttpClientConnection} itself.
|
||||
* <p>
|
||||
* The methods in this interface can safely be called multiple times.
|
||||
* The first invocation releases the connection, subsequent calls
|
||||
* are ignored.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface ConnectionReleaseTrigger {
|
||||
|
||||
/**
|
||||
* Releases the connection with the option of keep-alive. This is a
|
||||
* "graceful" release and may cause IO operations for consuming the
|
||||
* remainder of a response entity. Use
|
||||
* {@link #abortConnection abortConnection} for a hard release. The
|
||||
* connection may be reused as specified by the duration.
|
||||
*
|
||||
* @throws IOException
|
||||
* in case of an IO problem. The connection will be released
|
||||
* anyway.
|
||||
*/
|
||||
void releaseConnection()
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Releases the connection without the option of keep-alive.
|
||||
* This is a "hard" release that implies a shutdown of the connection.
|
||||
* Use {@link #releaseConnection()} for a graceful release.
|
||||
*
|
||||
* @throws IOException in case of an IO problem.
|
||||
* The connection will be released anyway.
|
||||
*/
|
||||
void abortConnection()
|
||||
throws IOException;
|
||||
|
||||
}
|
|
@ -26,11 +26,11 @@
|
|||
*/
|
||||
package org.apache.hc.client5.http.io;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
|
||||
/**
|
||||
|
@ -40,137 +40,77 @@ import org.apache.hc.core5.http.protocol.HttpContext;
|
|||
* HTTP connections, manage persistent connections and synchronize access to
|
||||
* persistent connections making sure that only one thread of execution can
|
||||
* have access to a connection at a time.
|
||||
* </p>
|
||||
* <p>
|
||||
* Implementations of this interface must be thread-safe. Access to shared
|
||||
* data must be synchronized as methods of this interface may be executed
|
||||
* from multiple threads.
|
||||
* </p>
|
||||
*
|
||||
* @since 4.3
|
||||
*/
|
||||
public interface HttpClientConnectionManager {
|
||||
public interface HttpClientConnectionManager extends Closeable {
|
||||
|
||||
/**
|
||||
* Returns a new {@link ConnectionRequest}, from which a
|
||||
* {@link HttpClientConnection} can be obtained or the request can be
|
||||
* aborted.
|
||||
* Returns a {@link LeaseRequest} object which can be used to obtain
|
||||
* a {@link ConnectionEndpoint} to cancel the request by calling
|
||||
* {@link LeaseRequest#cancel()}.
|
||||
* <p>
|
||||
* Please note that newly allocated connections can be returned
|
||||
* in the closed state. The consumer of that connection is responsible
|
||||
* for fully establishing the route the to the connection target
|
||||
* by calling {@link #connect(HttpClientConnection, HttpRoute, int, HttpContext)} connect} in order to connect
|
||||
* directly to the target or to the first proxy hop, optionally calling
|
||||
* {@link #upgrade(HttpClientConnection, HttpRoute, HttpContext)} upgrade} method to upgrade
|
||||
* the connection after having executed {@code CONNECT} method to
|
||||
* all intermediate proxy hops and and finally calling {@link #routeComplete(HttpClientConnection, HttpRoute,
|
||||
* HttpContext)} routeComplete} to mark the route
|
||||
* as fully completed.
|
||||
* </p>
|
||||
* Please note that newly allocated endpoints can be leased
|
||||
* {@link ConnectionEndpoint#isConnected() disconnected}. The consumer of the endpoint
|
||||
* is responsible for fully establishing the route to the endpoint target
|
||||
* by calling {@link #connect(ConnectionEndpoint, long, TimeUnit, HttpContext)}
|
||||
* in order to connect directly to the target or to the first proxy hop,
|
||||
* and optionally calling {@link #upgrade(ConnectionEndpoint, HttpContext)} method
|
||||
* to upgrade the underlying transport to Transport Layer Security after having
|
||||
* executed a {@code CONNECT} method to all intermediate proxy hops.
|
||||
*
|
||||
* @param route HTTP route of the requested connection.
|
||||
* @param state expected state of the connection or {@code null}
|
||||
* if the connection is not expected to carry any state.
|
||||
*/
|
||||
ConnectionRequest requestConnection(HttpRoute route, Object state);
|
||||
LeaseRequest lease(HttpRoute route, Object state);
|
||||
|
||||
/**
|
||||
* Releases the connection back to the manager making it potentially
|
||||
* Releases the endpoint back to the manager making it potentially
|
||||
* re-usable by other consumers. Optionally, the maximum period
|
||||
* of how long the manager should keep the connection alive can be
|
||||
* defined using {@code validDuration} and {@code timeUnit}
|
||||
* parameters.
|
||||
*
|
||||
* @param conn the managed connection to release.
|
||||
* @param endpoint the managed endpoint.
|
||||
* @param newState the new connection state of {@code null} if state-less.
|
||||
* @param validDuration the duration of time this connection is valid for reuse.
|
||||
* @param timeUnit the time unit.
|
||||
*
|
||||
* @see #closeExpired()
|
||||
*/
|
||||
void releaseConnection(
|
||||
HttpClientConnection conn, Object newState, long validDuration, TimeUnit timeUnit);
|
||||
void release(ConnectionEndpoint endpoint, Object newState, long validDuration, TimeUnit timeUnit);
|
||||
|
||||
/**
|
||||
* Connects the underlying connection socket to the connection target in case
|
||||
* Connects the endpoint to the initial hop (connection target in case
|
||||
* of a direct route or to the first proxy hop in case of a route via a proxy
|
||||
* (or multiple proxies).
|
||||
* or multiple proxies).
|
||||
*
|
||||
* @param conn the managed connection.
|
||||
* @param route the route of the connection.
|
||||
* @param connectTimeout connect timeout in milliseconds.
|
||||
* @param endpoint the managed endpoint.
|
||||
* @param connectTimeout connect timeout.
|
||||
* @param timeUnit the time unit.
|
||||
* @param context the actual HTTP context.
|
||||
* @throws IOException
|
||||
*/
|
||||
void connect(
|
||||
HttpClientConnection conn,
|
||||
HttpRoute route,
|
||||
int connectTimeout,
|
||||
ConnectionEndpoint endpoint,
|
||||
long connectTimeout,
|
||||
TimeUnit timeUnit,
|
||||
HttpContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Upgrades the underlying connection socket to TLS/SSL (or another layering
|
||||
* protocol) after having executed {@code CONNECT} method to all
|
||||
* intermediate proxy hops
|
||||
* Upgrades the endpoint's underlying transport to Transport Layer Security.
|
||||
*
|
||||
* @param conn the managed connection.
|
||||
* @param route the route of the connection.
|
||||
* @param endpoint the managed endpoint.
|
||||
* @param context the actual HTTP context.
|
||||
* @throws IOException
|
||||
*/
|
||||
void upgrade(
|
||||
HttpClientConnection conn,
|
||||
HttpRoute route,
|
||||
ConnectionEndpoint endpoint,
|
||||
HttpContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Marks the connection as fully established with all its intermediate
|
||||
* hops completed.
|
||||
*
|
||||
* @param conn the managed connection.
|
||||
* @param route the route of the connection.
|
||||
* @param context the actual HTTP context.
|
||||
* @throws IOException
|
||||
*/
|
||||
void routeComplete(
|
||||
HttpClientConnection conn,
|
||||
HttpRoute route,
|
||||
HttpContext context) throws IOException;
|
||||
|
||||
/**
|
||||
* Closes idle connections in the pool.
|
||||
* <p>
|
||||
* Open connections in the pool that have not been used for the
|
||||
* timespan given by the argument will be closed.
|
||||
* Currently allocated connections are not subject to this method.
|
||||
* Times will be checked with milliseconds precision
|
||||
* </p>
|
||||
* <p>
|
||||
* All expired connections will also be closed.
|
||||
* </p>
|
||||
*
|
||||
* @param idletime the idle time of connections to be closed
|
||||
* @param tunit the unit for the {@code idletime}
|
||||
*
|
||||
* @see #closeExpired()
|
||||
*/
|
||||
void closeIdle(long idletime, TimeUnit tunit);
|
||||
|
||||
/**
|
||||
* Closes all expired connections in the pool.
|
||||
* <p>
|
||||
* Open connections in the pool that have not been used for
|
||||
* the timespan defined when the connection was released will be closed.
|
||||
* Currently allocated connections are not subject to this method.
|
||||
* Times will be checked with milliseconds precision.
|
||||
* </p>
|
||||
*/
|
||||
void closeExpired();
|
||||
|
||||
/**
|
||||
* Shuts down this connection manager and releases allocated resources.
|
||||
* This includes closing all connections, whether they are currently
|
||||
* used or not.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
}
|
||||
|
|
|
@ -29,21 +29,20 @@ package org.apache.hc.client5.http.io;
|
|||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.core5.concurrent.Cancellable;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
|
||||
/**
|
||||
* Represents a request for a {@link HttpClientConnection} whose life cycle
|
||||
* Represents a request for a {@link ConnectionEndpoint} whose life cycle
|
||||
* is managed by a connection manager.
|
||||
*
|
||||
* @since 4.3
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface ConnectionRequest extends Cancellable {
|
||||
public interface LeaseRequest extends Cancellable {
|
||||
|
||||
/**
|
||||
* Obtains a connection within a given time.
|
||||
* Returns {@link ConnectionEndpoint} within a given time.
|
||||
* This method will block until a connection becomes available,
|
||||
* the timeout expires, or the connection manager is shut down.
|
||||
* Timeouts are handled with millisecond precision.
|
||||
|
@ -59,12 +58,12 @@ public interface ConnectionRequest extends Cancellable {
|
|||
* @return a connection that can be used to communicate
|
||||
* along the given route
|
||||
*
|
||||
* @throws ConnectionPoolTimeoutException
|
||||
* @throws TimeoutException
|
||||
* in case of a timeout
|
||||
* @throws InterruptedException
|
||||
* if the calling thread is interrupted while waiting
|
||||
*/
|
||||
HttpClientConnection get(long timeout, TimeUnit tunit)
|
||||
throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException;
|
||||
ConnectionEndpoint get(long timeout, TimeUnit tunit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException;
|
||||
|
||||
}
|
|
@ -44,12 +44,6 @@ import org.apache.hc.core5.http.io.HttpClientConnection;
|
|||
*/
|
||||
public interface ManagedHttpClientConnection extends HttpClientConnection {
|
||||
|
||||
/**
|
||||
* Returns connection ID which is expected to be unique
|
||||
* for the life span of the connection manager.
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Binds this connection to the given socket. The connection
|
||||
* is considered open if it is bound and the underlying socket
|
||||
|
|
|
@ -48,13 +48,9 @@ import org.apache.hc.core5.http.protocol.HttpContext;
|
|||
public interface HttpRoutePlanner {
|
||||
|
||||
/**
|
||||
* Determines the route for a request.
|
||||
* Determines the route for the given host.
|
||||
*
|
||||
* @param target the target host for the request.
|
||||
* Implementations may accept {@code null}
|
||||
* if they can still determine a route, for example
|
||||
* to a default target or by inspecting the request.
|
||||
* @param request the request to execute
|
||||
* @param context the context to use for the subsequent execution.
|
||||
* Implementations may accept {@code null}.
|
||||
*
|
||||
|
@ -62,8 +58,19 @@ public interface HttpRoutePlanner {
|
|||
*
|
||||
* @throws HttpException in case of a problem
|
||||
*/
|
||||
HttpRoute determineRoute(HttpHost target,
|
||||
HttpRequest request,
|
||||
HttpContext context) throws HttpException;
|
||||
HttpRoute determineRoute(HttpHost target, HttpContext context) throws HttpException;
|
||||
|
||||
/**
|
||||
* Determines the target host for the given request.
|
||||
*
|
||||
* @param request the request to be executed
|
||||
* @param context the context to use for the subsequent execution.
|
||||
* Implementations may accept {@code null}.
|
||||
*
|
||||
* @return the route that the request should take
|
||||
*
|
||||
* @throws HttpException in case of a problem
|
||||
*/
|
||||
HttpHost determineTargetHost(HttpRequest request, HttpContext context) throws HttpException;
|
||||
|
||||
}
|
||||
|
|
|
@ -24,18 +24,16 @@
|
|||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.hc.client5.http;
|
||||
|
||||
import org.apache.hc.core5.http.HttpConnection;
|
||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
||||
package org.apache.hc.client5.http.utils;
|
||||
|
||||
/**
|
||||
* Generic {@link HttpConnection} factory.
|
||||
* Object with a unique identifier.
|
||||
*
|
||||
* @since 4.3
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface HttpConnectionFactory<T, C extends HttpConnection> {
|
||||
public interface Identifiable {
|
||||
|
||||
C create(T route, ConnectionConfig config);
|
||||
String getId();
|
||||
|
||||
}
|
|
@ -115,15 +115,4 @@ public class TestExceptions {
|
|||
Assert.assertEquals("Connect to localhost [/1.2.3.4, /5.6.7.8] refused", ctx.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionPoolTimeoutException() {
|
||||
final String msg = "sample exception message";
|
||||
ConnectionPoolTimeoutException cptx = new ConnectionPoolTimeoutException(msg);
|
||||
Assert.assertFalse(!cptx.toString().contains(msg));
|
||||
Assert.assertSame(msg, cptx.getMessage());
|
||||
|
||||
cptx = new ConnectionPoolTimeoutException();
|
||||
Assert.assertNull(cptx.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
|
||||
import org.apache.hc.client5.http.impl.sync.AbstractResponseHandler;
|
||||
import org.apache.hc.client5.http.impl.sync.BasicResponseHandler;
|
||||
import org.apache.hc.client5.http.protocol.HttpResponseException;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
|
|
|
@ -29,6 +29,7 @@ package org.apache.hc.client5.http.impl;
|
|||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.hc.client5.http.impl.sync.BasicResponseHandler;
|
||||
import org.apache.hc.client5.http.protocol.HttpResponseException;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
|
|
|
@ -1,533 +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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
package org.apache.hc.client5.http.impl.integration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.impl.sync.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.sync.HttpClients;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.core5.concurrent.Cancellable;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.HttpRequestHandler;
|
||||
import org.apache.hc.core5.http.io.UriHttpRequestHandlerMapper;
|
||||
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||
import org.apache.hc.core5.http.message.BasicHeader;
|
||||
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
/**
|
||||
* Tests for Abort handling.
|
||||
*/
|
||||
@SuppressWarnings("static-access") // test code
|
||||
public class TestAbortHandling extends LocalServerTestBase {
|
||||
|
||||
@Test
|
||||
public void testAbortRetry_HTTPCLIENT_1120() throws Exception {
|
||||
final CountDownLatch wait = new CountDownLatch(1);
|
||||
|
||||
this.serverBootstrap.registerHandler("*", new HttpRequestHandler() {
|
||||
@Override
|
||||
public void handle(
|
||||
final ClassicHttpRequest request,
|
||||
final ClassicHttpResponse response,
|
||||
final HttpContext context) throws HttpException, IOException {
|
||||
try {
|
||||
wait.countDown(); // trigger abort
|
||||
Thread.sleep(2000); // allow time for abort to happen
|
||||
response.setCode(HttpStatus.SC_OK);
|
||||
final StringEntity entity = new StringEntity("Whatever");
|
||||
response.setEntity(entity);
|
||||
} catch (final Exception e) {
|
||||
response.setCode(HttpStatus.SC_REQUEST_TIMEOUT);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
final HttpHost target = start();
|
||||
final HttpGet httpget = new HttpGet("/");
|
||||
|
||||
final Thread t = new Thread() {
|
||||
@Override
|
||||
public void run(){
|
||||
try {
|
||||
wait.await();
|
||||
} catch (final InterruptedException e) {
|
||||
}
|
||||
httpget.abort();
|
||||
}
|
||||
};
|
||||
|
||||
t.start();
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
try {
|
||||
this.httpclient.execute(target, httpget, context);
|
||||
} catch (final IllegalStateException | IOException e) {
|
||||
}
|
||||
|
||||
final HttpRequest reqWrapper = context.getRequest();
|
||||
Assert.assertNotNull("Request should exist",reqWrapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAbortInAllocate() throws Exception {
|
||||
final CountDownLatch connLatch = new CountDownLatch(1);
|
||||
final CountDownLatch awaitLatch = new CountDownLatch(1);
|
||||
final ConMan conMan = new ConMan(connLatch, awaitLatch);
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final CountDownLatch getLatch = new CountDownLatch(1);
|
||||
this.clientBuilder.setConnectionManager(conMan);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpGet httpget = new HttpGet("http://www.example.com/a");
|
||||
|
||||
start();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
httpclient.execute(httpget, context);
|
||||
} catch(final Throwable t) {
|
||||
throwableRef.set(t);
|
||||
} finally {
|
||||
getLatch.countDown();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
Assert.assertTrue("should have tried to get a connection", connLatch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
httpget.abort();
|
||||
|
||||
Assert.assertTrue("should have finished get request", getLatch.await(1, TimeUnit.SECONDS));
|
||||
Assert.assertTrue("should be instanceof IOException, was: " + throwableRef.get(),
|
||||
throwableRef.get() instanceof IOException);
|
||||
Assert.assertTrue("cause should be InterruptedException, was: " + throwableRef.get().getCause(),
|
||||
throwableRef.get().getCause() instanceof InterruptedException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an abort called after the connection has been retrieved
|
||||
* but before a release trigger is set does still abort the request.
|
||||
*/
|
||||
@Test
|
||||
public void testAbortAfterAllocateBeforeRequest() throws Exception {
|
||||
this.serverBootstrap.registerHandler("*", new BasicService());
|
||||
|
||||
final CountDownLatch releaseLatch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final CountDownLatch getLatch = new CountDownLatch(1);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpGet httpget = new CustomGet("a", releaseLatch);
|
||||
|
||||
final HttpHost target = start();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
httpclient.execute(target, httpget, context);
|
||||
} catch(final Throwable t) {
|
||||
throwableRef.set(t);
|
||||
} finally {
|
||||
getLatch.countDown();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
Thread.sleep(100); // Give it a little time to proceed to release...
|
||||
|
||||
httpget.abort();
|
||||
|
||||
releaseLatch.countDown();
|
||||
|
||||
Assert.assertTrue("should have finished get request", getLatch.await(1, TimeUnit.SECONDS));
|
||||
Assert.assertTrue("should be instanceof IOException, was: " + throwableRef.get(),
|
||||
throwableRef.get() instanceof IOException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an abort called completely before execute
|
||||
* still aborts the request.
|
||||
*/
|
||||
@Test
|
||||
public void testAbortBeforeExecute() throws Exception {
|
||||
this.serverBootstrap.registerHandler("*", new BasicService());
|
||||
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final CountDownLatch getLatch = new CountDownLatch(1);
|
||||
final CountDownLatch startLatch = new CountDownLatch(1);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpGet httpget = new HttpGet("a");
|
||||
|
||||
final HttpHost target = start();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
try {
|
||||
if(!startLatch.await(1, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("Took too long to start!");
|
||||
}
|
||||
} catch(final InterruptedException interrupted) {
|
||||
throw new RuntimeException("Never started!", interrupted);
|
||||
}
|
||||
httpclient.execute(target, httpget, context);
|
||||
} catch(final Throwable t) {
|
||||
throwableRef.set(t);
|
||||
} finally {
|
||||
getLatch.countDown();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
httpget.abort();
|
||||
startLatch.countDown();
|
||||
|
||||
Assert.assertTrue("should have finished get request", getLatch.await(1, TimeUnit.SECONDS));
|
||||
Assert.assertTrue("should be instanceof IOException, was: " + throwableRef.get(),
|
||||
throwableRef.get() instanceof IOException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an abort called after a redirect has found a new host
|
||||
* still aborts in the correct place (while trying to get the new
|
||||
* host's route, not while doing the subsequent request).
|
||||
*/
|
||||
@Test
|
||||
public void testAbortAfterRedirectedRoute() throws Exception {
|
||||
final UriHttpRequestHandlerMapper reqistry = new UriHttpRequestHandlerMapper();
|
||||
this.serverBootstrap.setHandlerMapper(reqistry);
|
||||
|
||||
final CountDownLatch connLatch = new CountDownLatch(1);
|
||||
final CountDownLatch awaitLatch = new CountDownLatch(1);
|
||||
final ConnMan4 conMan = new ConnMan4(connLatch, awaitLatch);
|
||||
final AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
final CountDownLatch getLatch = new CountDownLatch(1);
|
||||
this.clientBuilder.setConnectionManager(conMan);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpGet httpget = new HttpGet("a");
|
||||
|
||||
final HttpHost target = start();
|
||||
reqistry.register("*", new BasicRedirectService(target.getPort()));
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final HttpHost host = new HttpHost("127.0.0.1", target.getPort());
|
||||
httpclient.execute(host, httpget, context);
|
||||
} catch(final Throwable t) {
|
||||
throwableRef.set(t);
|
||||
} finally {
|
||||
getLatch.countDown();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
Assert.assertTrue("should have tried to get a connection", connLatch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
httpget.abort();
|
||||
|
||||
Assert.assertTrue("should have finished get request", getLatch.await(1, TimeUnit.SECONDS));
|
||||
Assert.assertTrue("should be instanceof IOException, was: " + throwableRef.get(),
|
||||
throwableRef.get() instanceof IOException);
|
||||
Assert.assertTrue("cause should be InterruptedException, was: " + throwableRef.get().getCause(),
|
||||
throwableRef.get().getCause() instanceof InterruptedException);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that if a socket fails to connect, the allocated connection is
|
||||
* properly released back to the connection manager.
|
||||
*/
|
||||
@Test
|
||||
public void testSocketConnectFailureReleasesConnection() throws Exception {
|
||||
final HttpClientConnection conn = Mockito.mock(HttpClientConnection.class);
|
||||
final ConnectionRequest connrequest = Mockito.mock(ConnectionRequest.class);
|
||||
Mockito.when(connrequest.get(
|
||||
Mockito.anyInt(), Mockito.any(TimeUnit.class))).thenReturn(conn);
|
||||
final HttpClientConnectionManager connmgr = Mockito.mock(HttpClientConnectionManager.class);
|
||||
Mockito.doThrow(new ConnectException()).when(connmgr).connect(
|
||||
Mockito.any(HttpClientConnection.class),
|
||||
Mockito.any(HttpRoute.class),
|
||||
Mockito.anyInt(),
|
||||
Mockito.any(HttpContext.class));
|
||||
|
||||
Mockito.when(connmgr.requestConnection(
|
||||
Mockito.any(HttpRoute.class), Mockito.any())).thenReturn(connrequest);
|
||||
|
||||
final CloseableHttpClient client = HttpClients.custom().setConnectionManager(connmgr).build();
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpGet httpget = new HttpGet("http://www.example.com/a");
|
||||
|
||||
try {
|
||||
client.execute(httpget, context);
|
||||
Assert.fail("expected IOException");
|
||||
} catch(final IOException expected) {}
|
||||
|
||||
Mockito.verify(connmgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private static class BasicService implements HttpRequestHandler {
|
||||
@Override
|
||||
public void handle(
|
||||
final ClassicHttpRequest request,
|
||||
final ClassicHttpResponse response,
|
||||
final HttpContext context) throws HttpException, IOException {
|
||||
response.setCode(200);
|
||||
response.setEntity(new StringEntity("Hello World"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class BasicRedirectService implements HttpRequestHandler {
|
||||
private final int statuscode = HttpStatus.SC_SEE_OTHER;
|
||||
private final int port;
|
||||
|
||||
public BasicRedirectService(final int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(
|
||||
final ClassicHttpRequest request,
|
||||
final ClassicHttpResponse response,
|
||||
final HttpContext context) throws HttpException, IOException {
|
||||
response.setCode(this.statuscode);
|
||||
response.addHeader(new BasicHeader("Location", "http://localhost:"
|
||||
+ this.port + "/newlocation/"));
|
||||
response.addHeader(new BasicHeader("Connection", "close"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConnMan4 extends PoolingHttpClientConnectionManager {
|
||||
private final CountDownLatch connLatch;
|
||||
private final CountDownLatch awaitLatch;
|
||||
|
||||
public ConnMan4(final CountDownLatch connLatch, final CountDownLatch awaitLatch) {
|
||||
super();
|
||||
this.connLatch = connLatch;
|
||||
this.awaitLatch = awaitLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionRequest requestConnection(final HttpRoute route, final Object state) {
|
||||
// If this is the redirect route, stub the return value
|
||||
// so-as to pretend the host is waiting on a slot...
|
||||
if(route.getTargetHost().getHostName().equals("localhost")) {
|
||||
final Thread currentThread = Thread.currentThread();
|
||||
|
||||
return new ConnectionRequest() {
|
||||
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
currentThread.interrupt();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientConnection get(
|
||||
final long timeout,
|
||||
final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
|
||||
connLatch.countDown(); // notify waiter that we're getting a connection
|
||||
|
||||
// zero usually means sleep forever, but CountDownLatch doesn't interpret it that way.
|
||||
if(!awaitLatch.await(timeout > 0 ? timeout : Integer.MAX_VALUE, tunit)) {
|
||||
throw new ConnectionPoolTimeoutException();
|
||||
}
|
||||
|
||||
return Mockito.mock(HttpClientConnection.class);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return super.requestConnection(route, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class ConMan implements HttpClientConnectionManager {
|
||||
private final CountDownLatch connLatch;
|
||||
private final CountDownLatch awaitLatch;
|
||||
|
||||
public ConMan(final CountDownLatch connLatch, final CountDownLatch awaitLatch) {
|
||||
this.connLatch = connLatch;
|
||||
this.awaitLatch = awaitLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeIdle(final long idletime, final TimeUnit tunit) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeExpired() {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
public HttpClientConnection getConnection(final HttpRoute route,
|
||||
final long timeout, final TimeUnit tunit) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionRequest requestConnection(
|
||||
final HttpRoute route,
|
||||
final Object state) {
|
||||
|
||||
final Thread currentThread = Thread.currentThread();
|
||||
|
||||
return new ConnectionRequest() {
|
||||
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
currentThread.interrupt();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientConnection get(
|
||||
final long timeout,
|
||||
final TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
|
||||
connLatch.countDown(); // notify waiter that we're getting a connection
|
||||
|
||||
// zero usually means sleep forever, but CountDownLatch doesn't interpret it that way.
|
||||
if(!awaitLatch.await(timeout > 0 ? timeout : Integer.MAX_VALUE, tunit)) {
|
||||
throw new ConnectionPoolTimeoutException();
|
||||
}
|
||||
|
||||
return Mockito.mock(HttpClientConnection.class);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(
|
||||
final HttpClientConnection conn,
|
||||
final Object newState,
|
||||
final long validDuration, final TimeUnit timeUnit) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(
|
||||
final HttpClientConnection conn,
|
||||
final HttpRoute route,
|
||||
final int connectTimeout,
|
||||
final HttpContext context) throws IOException {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgrade(
|
||||
final HttpClientConnection conn,
|
||||
final HttpRoute route,
|
||||
final HttpContext context) throws IOException {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void routeComplete(
|
||||
final HttpClientConnection conn,
|
||||
final HttpRoute route,
|
||||
final HttpContext context) throws IOException {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
public void connect(
|
||||
final HttpClientConnection conn,
|
||||
final HttpHost host,
|
||||
final InetSocketAddress localAddress,
|
||||
final int connectTimeout,
|
||||
final HttpContext context) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
|
||||
public void upgrade(
|
||||
final HttpClientConnection conn,
|
||||
final HttpHost host,
|
||||
final HttpContext context) {
|
||||
throw new UnsupportedOperationException("just a mockup");
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomGet extends HttpGet {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final CountDownLatch releaseTriggerLatch;
|
||||
|
||||
public CustomGet(final String uri, final CountDownLatch releaseTriggerLatch) {
|
||||
super(uri);
|
||||
this.releaseTriggerLatch = releaseTriggerLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancellable(final Cancellable cancellable) {
|
||||
try {
|
||||
if(!releaseTriggerLatch.await(1, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("Waited too long...");
|
||||
}
|
||||
} catch(final InterruptedException ie) {
|
||||
throw new RuntimeException(ie);
|
||||
}
|
||||
|
||||
super.setCancellable(cancellable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -31,10 +31,11 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
|
@ -44,13 +45,11 @@ import org.apache.hc.core5.http.HttpException;
|
|||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.MalformedChunkCodingException;
|
||||
import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnection;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.HttpRequestHandler;
|
||||
import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
||||
import org.apache.hc.core5.pool.PoolStats;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -62,19 +61,18 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
this.connManager.setMaxTotal(1);
|
||||
|
||||
// Zero connections in the pool
|
||||
PoolStats stats = this.connManager.getTotalStats();
|
||||
Assert.assertEquals(0, stats.getAvailable());
|
||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
final HttpHost target = start();
|
||||
// Get some random data
|
||||
final HttpGet httpget = new HttpGet("/random/20000");
|
||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
||||
|
||||
ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final LeaseRequest connreq1 = this.connManager.lease(new HttpRoute(target), null);
|
||||
try {
|
||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException expected) {
|
||||
} catch (final TimeoutException expected) {
|
||||
}
|
||||
|
||||
final HttpEntity e = response.getEntity();
|
||||
|
@ -82,14 +80,13 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
EntityUtils.consume(e);
|
||||
|
||||
// Expect one connection in the pool
|
||||
stats = this.connManager.getTotalStats();
|
||||
Assert.assertEquals(1, stats.getAvailable());
|
||||
Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
// Make sure one connection is available
|
||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
this.connManager.release(endpoint, null, -1, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -98,19 +95,18 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
this.connManager.setMaxTotal(1);
|
||||
|
||||
// Zero connections in the pool
|
||||
PoolStats stats = this.connManager.getTotalStats();
|
||||
Assert.assertEquals(0, stats.getAvailable());
|
||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
final HttpHost target = start();
|
||||
// Get some random data
|
||||
final HttpGet httpget = new HttpGet("/random/20000");
|
||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
||||
|
||||
ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final LeaseRequest connreq1 = this.connManager.lease(new HttpRoute(target), null);
|
||||
try {
|
||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException expected) {
|
||||
} catch (final TimeoutException expected) {
|
||||
}
|
||||
|
||||
final HttpEntity e = response.getEntity();
|
||||
|
@ -119,14 +115,13 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
e.writeTo(outsteam);
|
||||
|
||||
// Expect one connection in the pool
|
||||
stats = this.connManager.getTotalStats();
|
||||
Assert.assertEquals(1, stats.getAvailable());
|
||||
Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
// Make sure one connection is available
|
||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
this.connManager.release(endpoint, null, -1, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -135,8 +130,7 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
this.connManager.setMaxTotal(1);
|
||||
|
||||
// Zero connections in the pool
|
||||
final PoolStats stats = this.connManager.getTotalStats();
|
||||
Assert.assertEquals(0, stats.getAvailable());
|
||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
final HttpHost target = start();
|
||||
|
||||
|
@ -144,11 +138,11 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
final HttpGet httpget = new HttpGet("/random/20000");
|
||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
||||
|
||||
ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final LeaseRequest connreq1 = this.connManager.lease(new HttpRoute(target), null);
|
||||
try {
|
||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException expected) {
|
||||
} catch (final TimeoutException expected) {
|
||||
}
|
||||
|
||||
final HttpEntity e = response.getEntity();
|
||||
|
@ -159,10 +153,10 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
// Make sure one connection is available
|
||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
this.connManager.release(endpoint, null, -1, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,11 +206,11 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
final HttpGet httpget = new HttpGet("/dropdead");
|
||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
||||
|
||||
ConnectionRequest connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final LeaseRequest connreq1 = this.connManager.lease(new HttpRoute(target), null);
|
||||
try {
|
||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException expected) {
|
||||
} catch (final TimeoutException expected) {
|
||||
}
|
||||
|
||||
final HttpEntity e = response.getEntity();
|
||||
|
@ -233,10 +227,10 @@ public class TestConnectionAutoRelease extends LocalServerTestBase {
|
|||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
|
||||
// Make sure one connection is available
|
||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
this.connManager.release(endpoint, null, -1, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,27 +28,23 @@
|
|||
package org.apache.hc.client5.http.impl.integration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||
import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpProcessor;
|
||||
import org.apache.hc.core5.http.protocol.RequestConnControl;
|
||||
import org.apache.hc.core5.http.protocol.RequestContent;
|
||||
|
@ -62,22 +58,6 @@ import org.junit.Test;
|
|||
*/
|
||||
public class TestConnectionManagement extends LocalServerTestBase {
|
||||
|
||||
private static HttpClientConnection getConnection(
|
||||
final HttpClientConnectionManager mgr,
|
||||
final HttpRoute route,
|
||||
final long timeout,
|
||||
final TimeUnit unit) throws ConnectionPoolTimeoutException, ExecutionException, InterruptedException {
|
||||
final ConnectionRequest connRequest = mgr.requestConnection(route, null);
|
||||
return connRequest.get(timeout, unit);
|
||||
}
|
||||
|
||||
private static HttpClientConnection getConnection(
|
||||
final HttpClientConnectionManager mgr,
|
||||
final HttpRoute route) throws ConnectionPoolTimeoutException, ExecutionException, InterruptedException {
|
||||
final ConnectionRequest connRequest = mgr.requestConnection(route, null);
|
||||
return connRequest.get(0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests releasing and re-using a connection after a response is read.
|
||||
*/
|
||||
|
@ -91,79 +71,60 @@ public class TestConnectionManagement extends LocalServerTestBase {
|
|||
final int rsplen = 8;
|
||||
final String uri = "/random/" + rsplen;
|
||||
|
||||
final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", uri);
|
||||
final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", target, uri);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
|
||||
HttpClientConnection conn = getConnection(this.connManager, route);
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
||||
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
||||
|
||||
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
||||
exec.preProcess(request, httpProcessor, context);
|
||||
ClassicHttpResponse response = exec.execute(request, conn, context);
|
||||
|
||||
Assert.assertEquals("wrong status in first response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
byte[] data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of first response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
try (final ClassicHttpResponse response1 = endpoint1.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
|
||||
}
|
||||
|
||||
// check that there is no auto-release by default
|
||||
try {
|
||||
// this should fail quickly, connection has not been released
|
||||
getConnection(this.connManager, route, 10L, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException e) {
|
||||
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||
leaseRequest2.get(10, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("TimeoutException expected");
|
||||
} catch (final TimeoutException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
conn.close();
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
conn = getConnection(this.connManager, route);
|
||||
Assert.assertFalse("connection should have been closed", conn.isOpen());
|
||||
endpoint1.close();
|
||||
this.connManager.release(endpoint1, null, -1, null);
|
||||
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint2 = leaseRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertFalse(endpoint2.isConnected());
|
||||
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
this.connManager.connect(endpoint2, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
// repeat the communication, no need to prepare the request again
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
response = exec.execute(request, conn, context);
|
||||
|
||||
Assert.assertEquals("wrong status in second response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of second response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
try (final ClassicHttpResponse response2 = endpoint2.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
|
||||
}
|
||||
|
||||
// release connection after marking it for re-use
|
||||
// expect the next connection obtained to be open
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
conn = getConnection(this.connManager, route);
|
||||
Assert.assertTrue("connection should have been open", conn.isOpen());
|
||||
this.connManager.release(endpoint2, null, -1, null);
|
||||
|
||||
final LeaseRequest leaseRequest3 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint3 = leaseRequest3.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertTrue(endpoint3.isConnected());
|
||||
|
||||
// repeat the communication, no need to prepare the request again
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
response = exec.execute(request, conn, context);
|
||||
try (final ClassicHttpResponse response3 = endpoint3.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response3.getCode());
|
||||
}
|
||||
|
||||
Assert.assertEquals("wrong status in third response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of third response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
this.connManager.shutdown();
|
||||
this.connManager.release(endpoint3, null, -1, null);
|
||||
this.connManager.close();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,96 +140,71 @@ public class TestConnectionManagement extends LocalServerTestBase {
|
|||
final int rsplen = 8;
|
||||
final String uri = "/random/" + rsplen;
|
||||
|
||||
final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", uri);
|
||||
final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", target, uri);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
|
||||
HttpClientConnection conn = getConnection(this.connManager, route);
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
||||
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
||||
|
||||
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
||||
exec.preProcess(request, httpProcessor, context);
|
||||
ClassicHttpResponse response = exec.execute(request, conn, context);
|
||||
|
||||
Assert.assertEquals("wrong status in first response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
byte[] data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of first response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
try (final ClassicHttpResponse response1 = endpoint1.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
|
||||
}
|
||||
|
||||
// check that there is no auto-release by default
|
||||
try {
|
||||
// this should fail quickly, connection has not been released
|
||||
getConnection(this.connManager, route, 10L, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException e) {
|
||||
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||
leaseRequest2.get(10, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("TimeoutException expected");
|
||||
} catch (final TimeoutException ex) {
|
||||
// expected
|
||||
}
|
||||
|
||||
conn.close();
|
||||
this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
|
||||
conn = getConnection(this.connManager, route);
|
||||
Assert.assertFalse("connection should have been closed", conn.isOpen());
|
||||
endpoint1.close();
|
||||
this.connManager.release(endpoint1, null, 100, TimeUnit.MILLISECONDS);
|
||||
|
||||
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint2 = leaseRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertFalse(endpoint2.isConnected());
|
||||
|
||||
this.connManager.connect(endpoint2, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
try (final ClassicHttpResponse response2 = endpoint2.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
|
||||
}
|
||||
|
||||
this.connManager.release(endpoint2, null, 100, TimeUnit.MILLISECONDS);
|
||||
|
||||
final LeaseRequest leaseRequest3 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint3 = leaseRequest3.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertTrue(endpoint3.isConnected());
|
||||
|
||||
// repeat the communication, no need to prepare the request again
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
try (final ClassicHttpResponse response3 = endpoint3.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response3.getCode());
|
||||
}
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
response = exec.execute(request, conn, context);
|
||||
|
||||
Assert.assertEquals("wrong status in second response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of second response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
|
||||
this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
|
||||
conn = getConnection(this.connManager, route);
|
||||
Assert.assertTrue("connection should have been open", conn.isOpen());
|
||||
|
||||
// repeat the communication, no need to prepare the request again
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
response = exec.execute(request, conn, context);
|
||||
|
||||
Assert.assertEquals("wrong status in third response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of third response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
|
||||
this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
|
||||
this.connManager.release(endpoint3, null, 100, TimeUnit.MILLISECONDS);
|
||||
Thread.sleep(150);
|
||||
conn = getConnection(this.connManager, route);
|
||||
Assert.assertTrue("connection should have been closed", !conn.isOpen());
|
||||
|
||||
final LeaseRequest leaseRequest4 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint4 = leaseRequest4.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertFalse(endpoint4.isConnected());
|
||||
|
||||
// repeat the communication, no need to prepare the request again
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
this.connManager.connect(endpoint4, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
response = exec.execute(request, conn, context);
|
||||
try (final ClassicHttpResponse response4 = endpoint4.execute(request, exec, context)) {
|
||||
Assert.assertEquals(HttpStatus.SC_OK, response4.getCode());
|
||||
}
|
||||
|
||||
Assert.assertEquals("wrong status in third response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
data = EntityUtils.toByteArray(response.getEntity());
|
||||
Assert.assertEquals("wrong length of fourth response entity",
|
||||
rsplen, data.length);
|
||||
// ignore data, but it must be read
|
||||
|
||||
this.connManager.shutdown();
|
||||
this.connManager.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -280,15 +216,15 @@ public class TestConnectionManagement extends LocalServerTestBase {
|
|||
final HttpRoute route = new HttpRoute(target, null, false);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
|
||||
final HttpClientConnection conn = getConnection(this.connManager, route);
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||
Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
|
||||
Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
|
||||
|
||||
this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
|
||||
this.connManager.release(endpoint1, null, 100, TimeUnit.MILLISECONDS);
|
||||
|
||||
// Released, still active.
|
||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||
|
@ -311,7 +247,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
|
|||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
|
||||
|
||||
this.connManager.shutdown();
|
||||
this.connManager.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -327,15 +263,15 @@ public class TestConnectionManagement extends LocalServerTestBase {
|
|||
final HttpRoute route = new HttpRoute(target, null, false);
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
|
||||
final HttpClientConnection conn = getConnection(this.connManager, route);
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||
Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
|
||||
Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
|
||||
// Release, let remain idle for forever
|
||||
this.connManager.releaseConnection(conn, null, -1, TimeUnit.MILLISECONDS);
|
||||
this.connManager.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
// Released, still active.
|
||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||
|
@ -358,64 +294,7 @@ public class TestConnectionManagement extends LocalServerTestBase {
|
|||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||
Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
|
||||
|
||||
this.connManager.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests releasing connection from #abort method called from the
|
||||
* main execution thread while there is no blocking I/O operation.
|
||||
*/
|
||||
@Test
|
||||
public void testReleaseConnectionOnAbort() throws Exception {
|
||||
|
||||
this.connManager.setMaxTotal(1);
|
||||
|
||||
final HttpHost target = start();
|
||||
final HttpRoute route = new HttpRoute(target, null, false);
|
||||
final int rsplen = 8;
|
||||
final String uri = "/random/" + rsplen;
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
|
||||
final ClassicHttpRequest request =
|
||||
new BasicClassicHttpRequest("GET", uri);
|
||||
|
||||
HttpClientConnection conn = getConnection(this.connManager, route);
|
||||
this.connManager.connect(conn, route, 0, context);
|
||||
this.connManager.routeComplete(conn, route, context);
|
||||
|
||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
||||
|
||||
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
||||
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
||||
|
||||
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
||||
exec.preProcess(request, httpProcessor, context);
|
||||
final ClassicHttpResponse response = exec.execute(request, conn, context);
|
||||
|
||||
Assert.assertEquals("wrong status in first response",
|
||||
HttpStatus.SC_OK,
|
||||
response.getCode());
|
||||
|
||||
// check that there are no connections available
|
||||
try {
|
||||
// this should fail quickly, connection has not been released
|
||||
getConnection(this.connManager, route, 100L, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||
} catch (final ConnectionPoolTimeoutException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// abort the connection
|
||||
Assert.assertTrue(conn instanceof HttpClientConnection);
|
||||
conn.shutdown();
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
|
||||
// the connection is expected to be released back to the manager
|
||||
conn = getConnection(this.connManager, route, 5L, TimeUnit.SECONDS);
|
||||
Assert.assertFalse("connection should have been closed", conn.isOpen());
|
||||
|
||||
this.connManager.releaseConnection(conn, null, -1, null);
|
||||
this.connManager.shutdown();
|
||||
this.connManager.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ import java.util.concurrent.Executors;
|
|||
import java.util.zip.Deflater;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.apache.hc.client5.http.impl.BasicResponseHandler;
|
||||
import org.apache.hc.client5.http.impl.sync.BasicResponseHandler;
|
||||
import org.apache.hc.client5.http.impl.sync.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
|
|
|
@ -36,10 +36,10 @@ import org.apache.hc.client5.http.protocol.HttpClientContext;
|
|||
import org.apache.hc.client5.http.protocol.UserTokenHandler;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.HttpConnection;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.HttpRequestHandler;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||
|
@ -119,12 +119,10 @@ public class TestStatefulConnManagement extends LocalServerTestBase {
|
|||
}
|
||||
|
||||
for (final HttpContext context : contexts) {
|
||||
final String uid = (String) context.getAttribute("user");
|
||||
|
||||
for (int r = 0; r < requestCount; r++) {
|
||||
final String state = (String) context.getAttribute("r" + r);
|
||||
Assert.assertNotNull(state);
|
||||
Assert.assertEquals(uid, state);
|
||||
final String state0 = (String) context.getAttribute("r0");
|
||||
Assert.assertNotNull(state0);
|
||||
for (int r = 1; r < requestCount; r++) {
|
||||
Assert.assertEquals(state0, (String) context.getAttribute("r" + r));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,13 +174,8 @@ public class TestStatefulConnManagement extends LocalServerTestBase {
|
|||
this.context);
|
||||
this.count++;
|
||||
|
||||
final HttpClientConnection conn = this.context.getConnection(HttpClientConnection.class);
|
||||
final HttpContext connContext = (HttpContext) conn;
|
||||
String connuid = (String) connContext.getAttribute("user");
|
||||
if (connuid == null) {
|
||||
connContext.setAttribute("user", this.uid);
|
||||
connuid = this.uid;
|
||||
}
|
||||
final HttpConnection conn = this.context.getConnection();
|
||||
final String connuid = Integer.toHexString(System.identityHashCode(conn));
|
||||
this.context.setAttribute("r" + r, connuid);
|
||||
EntityUtils.consume(response.getEntity());
|
||||
}
|
||||
|
|
|
@ -33,19 +33,18 @@ import java.net.Socket;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hc.client5.http.DnsResolver;
|
||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.core5.http.config.Lookup;
|
||||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -60,7 +59,7 @@ public class TestBasicHttpClientConnectionManager {
|
|||
@Mock
|
||||
private ManagedHttpClientConnection conn;
|
||||
@Mock
|
||||
private HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
||||
private HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||
@Mock
|
||||
private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
|
||||
@Mock
|
||||
|
@ -88,26 +87,24 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("localhost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
Assert.assertFalse(conn1.isOpen());
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
Assert.assertFalse(endpoint1.isConnected());
|
||||
|
||||
mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 100, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertNull(mgr.getRoute());
|
||||
Assert.assertNull(mgr.getState());
|
||||
|
||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn2);
|
||||
Assert.assertFalse(conn2.isOpen());
|
||||
Assert.assertFalse(conn2.isConnected());
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(2)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -115,29 +112,27 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 10000, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 10000, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(route, mgr.getRoute());
|
||||
Assert.assertEquals(null, mgr.getState());
|
||||
|
||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn2);
|
||||
Assert.assertTrue(conn2.isOpen());
|
||||
Assert.assertTrue(conn2.isConnected());
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -145,30 +140,27 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, "some state");
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, "some state");
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
|
||||
mgr.releaseConnection(conn1, "some other state", 10000, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, "some other state", 10000, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(route, mgr.getRoute());
|
||||
Assert.assertEquals("some other state", mgr.getState());
|
||||
|
||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, "some other state");
|
||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connRequest2 = mgr.lease(route, "some other state");
|
||||
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn2);
|
||||
Assert.assertTrue(conn2.isOpen());
|
||||
Assert.assertTrue(conn2.isConnected());
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -176,35 +168,30 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target1 = new HttpHost("somehost", 80);
|
||||
final HttpRoute route1 = new HttpRoute(target1);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.<HttpRoute>any(), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route1, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route1, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route1), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(route1, mgr.getRoute());
|
||||
Assert.assertEquals(null, mgr.getState());
|
||||
|
||||
final HttpHost target2 = new HttpHost("otherhost", 80);
|
||||
final HttpRoute route2 = new HttpRoute(target2);
|
||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route2, null);
|
||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connRequest2 = mgr.lease(route2, null);
|
||||
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn2);
|
||||
Assert.assertFalse(conn2.isOpen());
|
||||
Assert.assertFalse(conn2.isConnected());
|
||||
|
||||
Mockito.verify(conn).close();
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route1), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route2), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,49 +199,41 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 10, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 10, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(route, mgr.getRoute());
|
||||
Assert.assertEquals(null, mgr.getState());
|
||||
|
||||
Thread.sleep(50);
|
||||
|
||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn2);
|
||||
Assert.assertFalse(conn2.isOpen());
|
||||
Assert.assertFalse(conn2.isConnected());
|
||||
|
||||
Mockito.verify(conn).close();
|
||||
Mockito.verify(connFactory, Mockito.times(2)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testLeaseInvalidArg() throws Exception {
|
||||
mgr.requestConnection(null, null);
|
||||
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testReleaseInvalidArg() throws Exception {
|
||||
mgr.releaseConnection(null, null, 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(null, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testReleaseAnotherConnection() throws Exception {
|
||||
final HttpClientConnection wrongCon = Mockito.mock(HttpClientConnection.class);
|
||||
mgr.releaseConnection(wrongCon, null, 0, TimeUnit.MILLISECONDS);
|
||||
final ConnectionEndpoint wrongCon = Mockito.mock(ConnectionEndpoint.class);
|
||||
mgr.release(wrongCon, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -262,26 +241,24 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
mgr.shutdown();
|
||||
mgr.close();
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||
|
||||
try {
|
||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
||||
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||
connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.fail("IllegalStateException expected");
|
||||
} catch (final IllegalStateException ex) {
|
||||
|
@ -290,7 +267,7 @@ public class TestBasicHttpClientConnectionManager {
|
|||
// Should have no effect
|
||||
mgr.closeExpired();
|
||||
mgr.closeIdle(0L, TimeUnit.MILLISECONDS);
|
||||
mgr.shutdown();
|
||||
mgr.close();
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||
}
|
||||
|
@ -300,19 +277,17 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 10, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 10, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(route, mgr.getRoute());
|
||||
Assert.assertEquals(null, mgr.getState());
|
||||
|
@ -329,19 +304,17 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
||||
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertEquals(route, mgr.getRoute());
|
||||
Assert.assertEquals(null, mgr.getState());
|
||||
|
@ -358,13 +331,12 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final HttpHost target = new HttpHost("somehost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
mgr.release(endpoint1, null, 100, TimeUnit.MILLISECONDS);
|
||||
|
||||
mgr.getConnection(route, null);
|
||||
mgr.getConnection(route, null);
|
||||
|
@ -377,12 +349,11 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
||||
final HttpRoute route = new HttpRoute(target, local, true);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||
|
@ -401,7 +372,7 @@ public class TestBasicHttpClientConnectionManager {
|
|||
Mockito.<InetSocketAddress>any(),
|
||||
Mockito.<HttpContext>any())).thenReturn(socket);
|
||||
|
||||
mgr.connect(conn1, route, 123, context);
|
||||
mgr.connect(endpoint1, 123, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
|
||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||
|
@ -409,8 +380,6 @@ public class TestBasicHttpClientConnectionManager {
|
|||
Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
|
||||
new InetSocketAddress(remote, 8443),
|
||||
new InetSocketAddress(local, 0), context);
|
||||
|
||||
mgr.routeComplete(conn1, route, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -421,12 +390,11 @@ public class TestBasicHttpClientConnectionManager {
|
|||
final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
||||
final HttpRoute route = new HttpRoute(target, local, proxy, true);
|
||||
|
||||
Mockito.when(connFactory.create(
|
||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
||||
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||
|
@ -447,7 +415,7 @@ public class TestBasicHttpClientConnectionManager {
|
|||
Mockito.<InetSocketAddress>any(),
|
||||
Mockito.<HttpContext>any())).thenReturn(socket);
|
||||
|
||||
mgr.connect(conn1, route, 123, context);
|
||||
mgr.connect(endpoint1, 123, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
|
||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
|
||||
|
@ -458,13 +426,11 @@ public class TestBasicHttpClientConnectionManager {
|
|||
|
||||
Mockito.when(conn.getSocket()).thenReturn(socket);
|
||||
|
||||
mgr.upgrade(conn1, route, context);
|
||||
mgr.upgrade(endpoint1, context);
|
||||
|
||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||
Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
|
||||
socket, "somehost", 8443, context);
|
||||
|
||||
mgr.routeComplete(conn1, route, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,115 +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
|
||||
* <http://www.apache.org/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.apache.hc.client5.http.impl.io;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||
import org.apache.hc.core5.http.Header;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpVersion;
|
||||
import org.apache.hc.core5.http.MessageConstraintException;
|
||||
import org.apache.hc.core5.http.NoHttpResponseException;
|
||||
import org.apache.hc.core5.http.config.H1Config;
|
||||
import org.apache.hc.core5.http.impl.io.SessionInputBufferImpl;
|
||||
import org.apache.hc.core5.http.io.HttpMessageParser;
|
||||
import org.apache.hc.core5.http.io.SessionInputBuffer;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link LenientHttpResponseParser}.
|
||||
*/
|
||||
public class TestDefaultHttpResponseParser {
|
||||
|
||||
@Test
|
||||
public void testResponseParsingWithSomeGarbage() throws Exception {
|
||||
final String s =
|
||||
"garbage\r\n" +
|
||||
"garbage\r\n" +
|
||||
"more garbage\r\n" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"header1: value1\r\n" +
|
||||
"header2: value2\r\n" +
|
||||
"\r\n";
|
||||
|
||||
final SessionInputBuffer inbuffer = new SessionInputBufferImpl(1024);
|
||||
final H1Config h1Config = H1Config.custom().setMaxEmptyLineCount(Integer.MAX_VALUE).build();
|
||||
final HttpMessageParser<ClassicHttpResponse> parser = new LenientHttpResponseParser(h1Config);
|
||||
|
||||
final HttpResponse response = parser.parse(inbuffer,
|
||||
new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)));
|
||||
Assert.assertNotNull(response);
|
||||
Assert.assertEquals(HttpVersion.HTTP_1_1, response.getVersion());
|
||||
Assert.assertEquals(200, response.getCode());
|
||||
|
||||
final Header[] headers = response.getAllHeaders();
|
||||
Assert.assertNotNull(headers);
|
||||
Assert.assertEquals(2, headers.length);
|
||||
Assert.assertEquals("header1", headers[0].getName());
|
||||
Assert.assertEquals("header2", headers[1].getName());
|
||||
}
|
||||
|
||||
@Test(expected=MessageConstraintException.class)
|
||||
public void testResponseParsingWithTooMuchGarbage() throws Exception {
|
||||
final String s =
|
||||
"garbage\r\n" +
|
||||
"garbage\r\n" +
|
||||
"more garbage\r\n" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"header1: value1\r\n" +
|
||||
"header2: value2\r\n" +
|
||||
"\r\n";
|
||||
|
||||
final SessionInputBuffer inbuffer = new SessionInputBufferImpl(1024);
|
||||
final H1Config h1Config = H1Config.custom().setMaxEmptyLineCount(2).build();
|
||||
final HttpMessageParser<ClassicHttpResponse> parser = new LenientHttpResponseParser(h1Config);
|
||||
parser.parse(inbuffer, new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)));
|
||||
}
|
||||
|
||||
@Test(expected=NoHttpResponseException.class)
|
||||
public void testResponseParsingNoResponse() throws Exception {
|
||||
final SessionInputBuffer inbuffer = new SessionInputBufferImpl(1024);
|
||||
final HttpMessageParser<ClassicHttpResponse> parser = new LenientHttpResponseParser(H1Config.DEFAULT);
|
||||
parser.parse(inbuffer, new ByteArrayInputStream(new byte[]{}));
|
||||
}
|
||||
|
||||
@Test(expected=NoHttpResponseException.class)
|
||||
public void testResponseParsingOnlyGarbage() throws Exception {
|
||||
final String s =
|
||||
"garbage\r\n" +
|
||||
"garbage\r\n" +
|
||||
"more garbage\r\n" +
|
||||
"a lot more garbage\r\n";
|
||||
final SessionInputBuffer inbuffer = new SessionInputBufferImpl(1024);
|
||||
final HttpMessageParser<ClassicHttpResponse> parser = new LenientHttpResponseParser(H1Config.DEFAULT);
|
||||
parser.parse(inbuffer, new ByteArrayInputStream(s.getBytes(StandardCharsets.US_ASCII)));
|
||||
}
|
||||
|
||||
}
|
|
@ -243,6 +243,8 @@ public class TestHttpClientConnectionOperator {
|
|||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpHost host = new HttpHost("somehost", -1, "https");
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(true);
|
||||
Mockito.when(conn.getSocket()).thenReturn(socket);
|
||||
Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
|
||||
Mockito.when(schemePortResolver.resolve(host)).thenReturn(443);
|
||||
Mockito.when(sslSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
|
||||
|
|
|
@ -34,20 +34,18 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.client5.http.DnsResolver;
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.core5.http.config.Lookup;
|
||||
import org.apache.hc.core5.http.config.SocketConfig;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.pool.PoolEntry;
|
||||
import org.apache.hc.core5.pool.StrictConnPool;
|
||||
|
@ -109,14 +107,12 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
Assert.assertNotSame(conn, conn1);
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
||||
poolProxy.markRouteComplete();
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
Assert.assertNotSame(conn, endpoint1);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(pool).release(entry, true);
|
||||
}
|
||||
|
@ -138,12 +134,12 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
Assert.assertNotSame(conn, conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
Assert.assertNotSame(conn, endpoint1);
|
||||
|
||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(pool).release(entry, false);
|
||||
}
|
||||
|
@ -160,11 +156,11 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
connRequest1.get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test(expected=ConnectionPoolTimeoutException.class)
|
||||
@Test(expected=TimeoutException.class)
|
||||
public void testLeaseFutureTimeout() throws Exception {
|
||||
final HttpHost target = new HttpHost("localhost", 80);
|
||||
final HttpRoute route = new HttpRoute(target);
|
||||
|
@ -173,7 +169,7 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
|
||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
connRequest1.get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
@ -190,14 +186,12 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
Assert.assertTrue(conn1.isOpen());
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
||||
poolProxy.markRouteComplete();
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
Assert.assertTrue(endpoint1.isConnected());
|
||||
|
||||
mgr.releaseConnection(conn1, "some state", 10, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, "some state", 10, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(pool).release(entry, true);
|
||||
Assert.assertEquals("some state", entry.getState());
|
||||
|
@ -216,14 +210,12 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
Assert.assertFalse(conn1.isOpen());
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
||||
poolProxy.markRouteComplete();
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
Assert.assertFalse(endpoint1.isConnected());
|
||||
|
||||
mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
|
||||
mgr.release(endpoint1, "some state", 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(pool).release(entry, false);
|
||||
Assert.assertEquals(null, entry.getState());
|
||||
|
@ -240,16 +232,14 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
entry.assignConnection(conn);
|
||||
|
||||
Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(conn.isOpen()).thenReturn(true);
|
||||
Mockito.when(conn.isOpen()).thenReturn(false);
|
||||
Mockito.when(future.isCancelled()).thenReturn(false);
|
||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
||||
poolProxy.markRouteComplete();
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||
|
@ -268,7 +258,7 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.<InetSocketAddress>any(),
|
||||
Mockito.<HttpContext>any())).thenReturn(socket);
|
||||
|
||||
mgr.connect(conn1, route, 123, context);
|
||||
mgr.connect(endpoint1, 123, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
|
||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||
|
@ -276,8 +266,6 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
|
||||
new InetSocketAddress(remote, 8443),
|
||||
new InetSocketAddress(local, 0), context);
|
||||
|
||||
mgr.routeComplete(conn1, route, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -292,24 +280,22 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
entry.assignConnection(conn);
|
||||
|
||||
Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(conn.isOpen()).thenReturn(true);
|
||||
Mockito.when(conn.isOpen()).thenReturn(false);
|
||||
Mockito.when(future.isCancelled()).thenReturn(false);
|
||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||
|
||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(conn1);
|
||||
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(endpoint1);
|
||||
|
||||
final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
|
||||
final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
|
||||
final Socket mockSock = Mockito.mock(Socket.class);
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||
final ConnectionConfig cconfig = ConnectionConfig.custom().build();
|
||||
|
||||
mgr.setDefaultSocketConfig(sconfig);
|
||||
mgr.setDefaultConnectionConfig(cconfig);
|
||||
|
||||
Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
|
||||
Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
|
||||
|
@ -325,7 +311,7 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
Mockito.<InetSocketAddress>any(),
|
||||
Mockito.<HttpContext>any())).thenReturn(mockSock);
|
||||
|
||||
mgr.connect(conn1, route, 123, context);
|
||||
mgr.connect(endpoint1, 123, TimeUnit.MILLISECONDS, context);
|
||||
|
||||
Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
|
||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
|
||||
|
@ -334,15 +320,14 @@ public class TestPoolingHttpClientConnectionManager {
|
|||
new InetSocketAddress(remote, 8080),
|
||||
new InetSocketAddress(local, 0), context);
|
||||
|
||||
Mockito.when(conn.isOpen()).thenReturn(true);
|
||||
Mockito.when(conn.getSocket()).thenReturn(mockSock);
|
||||
|
||||
mgr.upgrade(conn1, route, context);
|
||||
mgr.upgrade(endpoint1, context);
|
||||
|
||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||
Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
|
||||
mockSock, "somehost", 8443, context);
|
||||
|
||||
mgr.routeComplete(conn1, route, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -61,10 +61,9 @@ public class TestDefaultProxyRoutePlanner {
|
|||
@Test
|
||||
public void testDefaultProxyDirect() throws Exception {
|
||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(target, route.getTargetHost());
|
||||
Assert.assertEquals(defaultProxy, route.getProxyHost());
|
||||
|
@ -80,7 +79,7 @@ public class TestDefaultProxyRoutePlanner {
|
|||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
context.setRequestConfig(RequestConfig.custom().setProxy(proxy).build());
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(target, route.getTargetHost());
|
||||
Assert.assertEquals(proxy, route.getProxyHost());
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
package org.apache.hc.client5.http.impl.routing;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
|
@ -37,6 +39,8 @@ import org.apache.hc.core5.http.ProtocolException;
|
|||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.apache.hc.core5.net.URIAuthority;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -60,10 +64,9 @@ public class TestDefaultRoutePlanner {
|
|||
@Test
|
||||
public void testDirect() throws Exception {
|
||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(target, route.getTargetHost());
|
||||
Assert.assertEquals(1, route.getHopCount());
|
||||
|
@ -75,10 +78,9 @@ public class TestDefaultRoutePlanner {
|
|||
public void testDirectDefaultPort() throws Exception {
|
||||
final HttpHost target = new HttpHost("somehost", -1, "https");
|
||||
Mockito.when(schemePortResolver.resolve(target)).thenReturn(443);
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(new HttpHost("somehost", 443, "https"), route.getTargetHost());
|
||||
Assert.assertEquals(1, route.getHopCount());
|
||||
|
@ -89,11 +91,10 @@ public class TestDefaultRoutePlanner {
|
|||
public void testViaProxy() throws Exception {
|
||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||
final HttpHost proxy = new HttpHost("proxy", 8080);
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
context.setRequestConfig(RequestConfig.custom().setProxy(proxy).build());
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(target, route.getTargetHost());
|
||||
Assert.assertEquals(proxy, route.getProxyHost());
|
||||
|
@ -104,10 +105,28 @@ public class TestDefaultRoutePlanner {
|
|||
|
||||
@Test(expected= ProtocolException.class)
|
||||
public void testNullTarget() throws Exception {
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
routePlanner.determineRoute(null, request, context);
|
||||
routePlanner.determineRoute(null, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetermineHost() throws Exception {
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRequest request1 = new BasicHttpRequest("GET", "/");
|
||||
final HttpHost host1 = routePlanner.determineTargetHost(request1, context);
|
||||
Assert.assertThat(host1, CoreMatchers.nullValue());
|
||||
|
||||
final HttpRequest request2 = new BasicHttpRequest("GET", new URI("https://somehost:8443/"));
|
||||
final HttpHost host2 = routePlanner.determineTargetHost(request2, context);
|
||||
Assert.assertThat(host2, CoreMatchers.equalTo(new HttpHost("somehost", 8443, "https")));
|
||||
}
|
||||
|
||||
@Test(expected = ProtocolException.class)
|
||||
public void testDetermineHostMissingScheme() throws Exception {
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRequest request1 = new BasicHttpRequest("GET", "/");
|
||||
request1.setAuthority(new URIAuthority("host"));
|
||||
routePlanner.determineTargetHost(request1, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,8 +38,6 @@ import java.util.List;
|
|||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.SchemePortResolver;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||
import org.junit.Assert;
|
||||
|
@ -68,10 +66,9 @@ public class TestSystemDefaultRoutePlanner {
|
|||
@Test
|
||||
public void testDirect() throws Exception {
|
||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(target, route.getTargetHost());
|
||||
Assert.assertEquals(1, route.getHopCount());
|
||||
|
@ -83,10 +80,9 @@ public class TestSystemDefaultRoutePlanner {
|
|||
public void testDirectDefaultPort() throws Exception {
|
||||
final HttpHost target = new HttpHost("somehost", -1, "https");
|
||||
Mockito.when(schemePortResolver.resolve(target)).thenReturn(443);
|
||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(new HttpHost("somehost", 443, "https"), route.getTargetHost());
|
||||
Assert.assertEquals(1, route.getHopCount());
|
||||
|
@ -109,11 +105,9 @@ public class TestSystemDefaultRoutePlanner {
|
|||
Mockito.when(proxySelector.select(new URI("http://somehost:80"))).thenReturn(proxies);
|
||||
|
||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||
final HttpRequest request =
|
||||
new BasicHttpRequest("GET", "/");
|
||||
|
||||
final HttpContext context = new BasicHttpContext();
|
||||
final HttpRoute route = routePlanner.determineRoute(target, request, context);
|
||||
final HttpRoute route = routePlanner.determineRoute(target, context);
|
||||
|
||||
Assert.assertEquals(target, route.getTargetHost());
|
||||
Assert.assertEquals(2, route.getHopCount());
|
||||
|
|
|
@ -32,8 +32,7 @@ import static org.junit.Assert.assertTrue;
|
|||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
||||
import org.apache.hc.client5.http.sync.ConnectionBackoffStrategy;
|
||||
import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
|
||||
import org.apache.hc.core5.http.HttpResponse;
|
||||
import org.apache.hc.core5.http.HttpStatus;
|
||||
import org.apache.hc.core5.http.message.BasicHttpResponse;
|
||||
|
@ -50,11 +49,6 @@ public class TestDefaultBackoffStrategy {
|
|||
impl = new DefaultBackoffStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isABackoffStrategy() {
|
||||
assertTrue(impl instanceof ConnectionBackoffStrategy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void backsOffForSocketTimeouts() {
|
||||
assertTrue(impl.shouldBackoff(new SocketTimeoutException()));
|
||||
|
@ -67,7 +61,7 @@ public class TestDefaultBackoffStrategy {
|
|||
|
||||
@Test
|
||||
public void doesNotBackOffForConnectionManagerTimeout() {
|
||||
assertFalse(impl.shouldBackoff(new ConnectionPoolTimeoutException()));
|
||||
assertFalse(impl.shouldBackoff(new ConnectionRequestTimeoutException()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -29,28 +29,32 @@ package org.apache.hc.client5.http.impl.sync;
|
|||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@SuppressWarnings({"static-access"}) // test code
|
||||
public class TestConnectionHolder {
|
||||
public class TestEndpointHolder {
|
||||
|
||||
@Mock
|
||||
private Logger log;
|
||||
@Mock
|
||||
private HttpClientConnectionManager mgr;
|
||||
private HttpClientConnection conn;
|
||||
private ConnectionHolder connHolder;
|
||||
@Mock
|
||||
private ConnectionEndpoint endpoint;
|
||||
|
||||
private EndpointHolder connHolder;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
log = Mockito.mock(Logger.class);
|
||||
mgr = Mockito.mock(HttpClientConnectionManager.class);
|
||||
conn = Mockito.mock(HttpClientConnection.class);
|
||||
connHolder = new ConnectionHolder(log, mgr, conn);
|
||||
MockitoAnnotations.initMocks(this);
|
||||
connHolder = new EndpointHolder(log, mgr, endpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -59,14 +63,14 @@ public class TestConnectionHolder {
|
|||
|
||||
Assert.assertTrue(connHolder.isReleased());
|
||||
|
||||
Mockito.verify(conn).shutdown();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint).shutdown();
|
||||
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
connHolder.abortConnection();
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.verify(endpoint, Mockito.times(1)).shutdown();
|
||||
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||
Mockito.<ConnectionEndpoint>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
|
@ -74,14 +78,14 @@ public class TestConnectionHolder {
|
|||
|
||||
@Test
|
||||
public void testAbortConnectionIOError() throws Exception {
|
||||
Mockito.doThrow(new IOException()).when(conn).shutdown();
|
||||
Mockito.doThrow(new IOException()).when(endpoint).shutdown();
|
||||
|
||||
connHolder.abortConnection();
|
||||
|
||||
Assert.assertTrue(connHolder.isReleased());
|
||||
|
||||
Mockito.verify(conn).shutdown();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint).shutdown();
|
||||
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -90,14 +94,14 @@ public class TestConnectionHolder {
|
|||
|
||||
Assert.assertTrue(connHolder.isReleased());
|
||||
|
||||
Mockito.verify(conn).shutdown();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint).shutdown();
|
||||
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertFalse(connHolder.cancel());
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.verify(endpoint, Mockito.times(1)).shutdown();
|
||||
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||
Mockito.<ConnectionEndpoint>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
|
@ -113,13 +117,13 @@ public class TestConnectionHolder {
|
|||
|
||||
Assert.assertTrue(connHolder.isReleased());
|
||||
|
||||
Mockito.verify(conn, Mockito.never()).close();
|
||||
Mockito.verify(mgr).releaseConnection(conn, "some state", 100, TimeUnit.SECONDS);
|
||||
Mockito.verify(endpoint, Mockito.never()).close();
|
||||
Mockito.verify(mgr).release(endpoint, "some state", 100000, TimeUnit.MILLISECONDS);
|
||||
|
||||
connHolder.releaseConnection();
|
||||
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||
Mockito.<ConnectionEndpoint>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
||||
|
@ -135,13 +139,13 @@ public class TestConnectionHolder {
|
|||
|
||||
Assert.assertTrue(connHolder.isReleased());
|
||||
|
||||
Mockito.verify(conn, Mockito.times(1)).close();
|
||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
connHolder.releaseConnection();
|
||||
|
||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||
Mockito.<ConnectionEndpoint>any(),
|
||||
Mockito.anyObject(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.<TimeUnit>any());
|
|
@ -29,7 +29,7 @@ package org.apache.hc.client5.http.impl.sync;
|
|||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.core5.pool.ConnPoolControl;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
@ -41,7 +41,7 @@ public class TestIdleConnectionEvictor {
|
|||
|
||||
@Test
|
||||
public void testEvictExpiredAndIdle() throws Exception {
|
||||
final HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
|
||||
final ConnPoolControl<?> cm = Mockito.mock(ConnPoolControl.class);
|
||||
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
|
||||
500, TimeUnit.MILLISECONDS, 3, TimeUnit.SECONDS);
|
||||
connectionEvictor.start();
|
||||
|
@ -60,7 +60,7 @@ public class TestIdleConnectionEvictor {
|
|||
|
||||
@Test
|
||||
public void testEvictExpiredOnly() throws Exception {
|
||||
final HttpClientConnectionManager cm = Mockito.mock(HttpClientConnectionManager.class);
|
||||
final ConnPoolControl<?> cm = Mockito.mock(ConnPoolControl.class);
|
||||
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
|
||||
500, TimeUnit.MILLISECONDS, 0, TimeUnit.SECONDS);
|
||||
connectionEvictor.start();
|
||||
|
|
|
@ -36,7 +36,6 @@ import org.apache.hc.client5.http.auth.CredentialsProvider;
|
|||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
|
||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||
import org.apache.hc.client5.http.protocol.ClientProtocolException;
|
||||
|
@ -44,12 +43,10 @@ import org.apache.hc.client5.http.protocol.HttpClientContext;
|
|||
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
||||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.config.Lookup;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
/**
|
||||
|
@ -59,7 +56,6 @@ import org.mockito.Mockito;
|
|||
public class TestInternalHttpClient {
|
||||
|
||||
private ClientExecChain execChain;
|
||||
private HttpClientConnectionManager connManager;
|
||||
private HttpRoutePlanner routePlanner;
|
||||
private Lookup<CookieSpecProvider> cookieSpecRegistry;
|
||||
private Lookup<AuthSchemeProvider> authSchemeRegistry;
|
||||
|
@ -75,7 +71,6 @@ public class TestInternalHttpClient {
|
|||
@Before
|
||||
public void setup() throws Exception {
|
||||
execChain = Mockito.mock(ClientExecChain.class);
|
||||
connManager = Mockito.mock(HttpClientConnectionManager.class);
|
||||
routePlanner = Mockito.mock(HttpRoutePlanner.class);
|
||||
cookieSpecRegistry = Mockito.mock(Lookup.class);
|
||||
authSchemeRegistry = Mockito.mock(Lookup.class);
|
||||
|
@ -85,7 +80,7 @@ public class TestInternalHttpClient {
|
|||
closeable1 = Mockito.mock(Closeable.class);
|
||||
closeable2 = Mockito.mock(Closeable.class);
|
||||
|
||||
client = new InternalHttpClient(execChain, connManager, routePlanner,
|
||||
client = new InternalHttpClient(execChain, routePlanner,
|
||||
cookieSpecRegistry, authSchemeRegistry, cookieStore, credentialsProvider,
|
||||
defaultConfig, Arrays.asList(closeable1, closeable2));
|
||||
|
||||
|
@ -96,17 +91,12 @@ public class TestInternalHttpClient {
|
|||
final HttpGet httpget = new HttpGet("http://somehost/stuff");
|
||||
final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
|
||||
|
||||
final ArgumentCaptor<HttpRequest> argcap = ArgumentCaptor.forClass(HttpRequest.class);
|
||||
Mockito.when(routePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("somehost")),
|
||||
argcap.capture(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
client.execute(httpget);
|
||||
|
||||
Assert.assertNotNull(argcap.getValue());
|
||||
Assert.assertSame(httpget, argcap.getValue());
|
||||
|
||||
Mockito.verify(execChain).execute(
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any(),
|
||||
|
@ -120,7 +110,6 @@ public class TestInternalHttpClient {
|
|||
|
||||
Mockito.when(routePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("somehost")),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
Mockito.when(execChain.execute(
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
|
@ -137,7 +126,6 @@ public class TestInternalHttpClient {
|
|||
|
||||
Mockito.when(routePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("somehost")),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
@ -157,7 +145,6 @@ public class TestInternalHttpClient {
|
|||
|
||||
Mockito.when(routePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("somehost")),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
final RequestConfig config = RequestConfig.custom().build();
|
||||
|
@ -176,7 +163,6 @@ public class TestInternalHttpClient {
|
|||
|
||||
Mockito.when(routePlanner.determineRoute(
|
||||
Mockito.eq(new HttpHost("somehost")),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
final HttpClientContext context = HttpClientContext.create();
|
||||
|
|
|
@ -49,9 +49,10 @@ import org.apache.hc.client5.http.config.RequestConfig;
|
|||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||
import org.apache.hc.client5.http.impl.auth.BasicScheme;
|
||||
import org.apache.hc.client5.http.impl.auth.NTLMScheme;
|
||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.methods.HttpPost;
|
||||
|
@ -109,9 +110,9 @@ public class TestMainClientExec {
|
|||
@Mock
|
||||
private HttpExecutionAware execAware;
|
||||
@Mock
|
||||
private ConnectionRequest connRequest;
|
||||
private LeaseRequest connRequest;
|
||||
@Mock
|
||||
private HttpClientConnection managedConn;
|
||||
private ConnectionEndpoint endpoint;
|
||||
|
||||
private MainClientExec mainClientExec;
|
||||
private HttpHost target;
|
||||
|
@ -125,10 +126,10 @@ public class TestMainClientExec {
|
|||
target = new HttpHost("foo", 80);
|
||||
proxy = new HttpHost("bar", 8888);
|
||||
|
||||
Mockito.when(connManager.requestConnection(
|
||||
Mockito.when(connManager.lease(
|
||||
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
|
||||
Mockito.when(connRequest.get(
|
||||
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(managedConn);
|
||||
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(endpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -143,24 +144,22 @@ public class TestMainClientExec {
|
|||
context.setRequestConfig(config);
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
|
||||
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
||||
Mockito.verify(connManager).connect(managedConn, route, 123, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(managedConn).setSocketTimeout(234);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(connManager).connect(endpoint, 123, TimeUnit.MILLISECONDS, context);
|
||||
Mockito.verify(endpoint).setSocketTimeout(234);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertSame(managedConn, context.getConnection());
|
||||
Assert.assertNull(context.getUserToken());
|
||||
Assert.assertNotNull(finalResponse);
|
||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||
|
@ -177,11 +176,10 @@ public class TestMainClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -192,11 +190,11 @@ public class TestMainClientExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(678L);
|
||||
|
||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 678L, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(managedConn, Mockito.never()).close();
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(connManager).release(endpoint, null, 678L, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint, Mockito.never()).close();
|
||||
|
||||
Assert.assertNotNull(finalResponse);
|
||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||
|
@ -213,11 +211,10 @@ public class TestMainClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -228,11 +225,11 @@ public class TestMainClientExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn("this and that");
|
||||
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, "this and that", 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(managedConn, Mockito.never()).close();
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(connManager).release(endpoint, "this and that", 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint, Mockito.never()).close();
|
||||
|
||||
Assert.assertEquals("this and that", context.getUserToken());
|
||||
}
|
||||
|
@ -252,11 +249,10 @@ public class TestMainClientExec {
|
|||
.setStream(new ByteArrayInputStream(new byte[]{}))
|
||||
.build());
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -264,23 +260,23 @@ public class TestMainClientExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
||||
|
||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(connManager, Mockito.never()).releaseConnection(
|
||||
Mockito.same(managedConn),
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(connManager, Mockito.never()).release(
|
||||
Mockito.same(endpoint),
|
||||
Mockito.any(),
|
||||
Mockito.anyInt(),
|
||||
Mockito.<TimeUnit>any());
|
||||
Mockito.verify(managedConn, Mockito.never()).close();
|
||||
Mockito.verify(endpoint, Mockito.never()).close();
|
||||
|
||||
Assert.assertNotNull(finalResponse);
|
||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||
finalResponse.close();
|
||||
|
||||
Mockito.verify(connManager, Mockito.times(1)).releaseConnection(
|
||||
managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
||||
Mockito.verify(connManager, Mockito.times(1)).release(
|
||||
endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -291,14 +287,14 @@ public class TestMainClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
context.setRequestConfig(config);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(true);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(true);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(managedConn).setSocketTimeout(3000);
|
||||
Mockito.verify(endpoint).setSocketTimeout(3000);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -307,14 +303,14 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(managedConn, Mockito.never()).setSocketTimeout(Mockito.anyInt());
|
||||
Mockito.verify(endpoint, Mockito.never()).setSocketTimeout(Mockito.anyInt());
|
||||
}
|
||||
|
||||
@Test(expected=RequestAbortedException.class)
|
||||
|
@ -323,7 +319,7 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(execAware.isAborted()).thenReturn(Boolean.TRUE);
|
||||
try {
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
|
@ -343,7 +339,7 @@ public class TestMainClientExec {
|
|||
context.setRequestConfig(config);
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(execAware.isAborted()).thenReturn(Boolean.FALSE, Boolean.TRUE);
|
||||
try {
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
|
@ -351,9 +347,9 @@ public class TestMainClientExec {
|
|||
Mockito.verify(connRequest, Mockito.times(1)).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
||||
Mockito.verify(connManager, Mockito.never()).connect(
|
||||
Mockito.same(managedConn),
|
||||
Mockito.<HttpRoute>any(),
|
||||
Mockito.same(endpoint),
|
||||
Mockito.anyInt(),
|
||||
Mockito.<TimeUnit>any(),
|
||||
Mockito.<HttpContext>any());
|
||||
throw ex;
|
||||
}
|
||||
|
@ -370,13 +366,13 @@ public class TestMainClientExec {
|
|||
context.setRequestConfig(config);
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(execAware.isAborted()).thenReturn(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE);
|
||||
try {
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
} catch (final IOException ex) {
|
||||
Mockito.verify(connRequest, Mockito.times(1)).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(connManager, Mockito.times(1)).connect(managedConn, route, 567, context);
|
||||
Mockito.verify(connManager, Mockito.times(1)).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||
Mockito.verify(requestExecutor, Mockito.never()).execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
|
@ -417,11 +413,10 @@ public class TestMainClientExec {
|
|||
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||
context.setCredentialsProvider(credentialsProvider);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -434,7 +429,7 @@ public class TestMainClientExec {
|
|||
|
||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(
|
||||
request, context, execAware);
|
||||
Mockito.verify(requestExecutor, Mockito.times(2)).execute(request, managedConn, context);
|
||||
Mockito.verify(endpoint, Mockito.times(2)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(instream1).close();
|
||||
Mockito.verify(instream2, Mockito.never()).close();
|
||||
|
||||
|
@ -469,11 +464,10 @@ public class TestMainClientExec {
|
|||
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||
context.setCredentialsProvider(credentialsProvider);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -487,8 +481,8 @@ public class TestMainClientExec {
|
|||
|
||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(
|
||||
request, context, execAware);
|
||||
Mockito.verify(requestExecutor, Mockito.times(2)).execute(request, managedConn, context);
|
||||
Mockito.verify(managedConn).close();
|
||||
Mockito.verify(endpoint, Mockito.times(2)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(endpoint).close();
|
||||
Mockito.verify(instream2, Mockito.never()).close();
|
||||
|
||||
Assert.assertNotNull(finalResponse);
|
||||
|
@ -518,11 +512,10 @@ public class TestMainClientExec {
|
|||
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||
context.setCredentialsProvider(credentialsProvider);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenAnswer(new Answer<HttpResponse>() {
|
||||
|
||||
@Override
|
||||
|
@ -553,9 +546,9 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
|
||||
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
|
@ -567,15 +560,15 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
|
||||
|
||||
try {
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
|
@ -587,15 +580,15 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
|
||||
|
||||
try {
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
|
@ -607,15 +600,15 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
|
||||
|
||||
try {
|
||||
mainClientExec.execute(request, context, execAware);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
throw ex;
|
||||
}
|
||||
|
@ -631,12 +624,11 @@ public class TestMainClientExec {
|
|||
context.setRequestConfig(config);
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
|
||||
Mockito.verify(connManager).connect(managedConn, route, 567, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(connManager).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -649,12 +641,11 @@ public class TestMainClientExec {
|
|||
context.setRequestConfig(config);
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
|
||||
Mockito.verify(connManager).connect(managedConn, route, 567, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(connManager).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -668,20 +659,19 @@ public class TestMainClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
|
||||
Mockito.verify(connManager).connect(managedConn, route, 321, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(connManager).connect(endpoint, 321, TimeUnit.MILLISECONDS, context);
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(requestExecutor).execute(
|
||||
Mockito.verify(endpoint).execute(
|
||||
reqCaptor.capture(),
|
||||
Mockito.same(managedConn),
|
||||
Mockito.same(requestExecutor),
|
||||
Mockito.same(context));
|
||||
final HttpRequest connect = reqCaptor.getValue();
|
||||
Assert.assertNotNull(connect);
|
||||
|
@ -697,13 +687,13 @@ public class TestMainClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(101, "Lost");
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
}
|
||||
|
||||
@Test(expected = HttpException.class)
|
||||
|
@ -714,20 +704,18 @@ public class TestMainClientExec {
|
|||
final ClassicHttpResponse response = new BasicClassicHttpResponse(500, "Boom");
|
||||
response.setEntity(new StringEntity("Ka-boom"));
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
try {
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
} catch (final TunnelRefusedException ex) {
|
||||
final ClassicHttpResponse r = ex.getResponse();
|
||||
Assert.assertEquals("Ka-boom", EntityUtils.toString(r.getEntity()));
|
||||
|
||||
Mockito.verify(managedConn).close();
|
||||
|
||||
Mockito.verify(endpoint).close();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -753,14 +741,14 @@ public class TestMainClientExec {
|
|||
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||
context.setCredentialsProvider(credentialsProvider);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpResponse>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||
|
||||
Mockito.when(proxyAuthStrategy.select(
|
||||
|
@ -768,10 +756,9 @@ public class TestMainClientExec {
|
|||
Mockito.<Map<String, AuthChallenge>>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
|
||||
Mockito.verify(connManager).connect(managedConn, route, 567, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(connManager).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||
Mockito.verify(instream1).close();
|
||||
}
|
||||
|
||||
|
@ -796,14 +783,14 @@ public class TestMainClientExec {
|
|||
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||
context.setCredentialsProvider(credentialsProvider);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpResponse>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||
|
||||
Mockito.when(proxyAuthStrategy.select(
|
||||
|
@ -811,12 +798,11 @@ public class TestMainClientExec {
|
|||
Mockito.<Map<String, AuthChallenge>>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
|
||||
Mockito.verify(connManager).connect(managedConn, route, 567, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(connManager).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||
Mockito.verify(instream1, Mockito.never()).close();
|
||||
Mockito.verify(managedConn).close();
|
||||
Mockito.verify(endpoint).close();
|
||||
}
|
||||
|
||||
@Test(expected = HttpException.class)
|
||||
|
@ -828,9 +814,9 @@ public class TestMainClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
|
||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
||||
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,9 +36,10 @@ import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
|||
import org.apache.hc.client5.http.HttpRoute;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionRequest;
|
||||
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||
import org.apache.hc.client5.http.io.ConnectionEndpoint;
|
||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||
import org.apache.hc.client5.http.methods.HttpGet;
|
||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||
|
@ -50,7 +51,6 @@ import org.apache.hc.core5.http.ConnectionReuseStrategy;
|
|||
import org.apache.hc.core5.http.HttpException;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
||||
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
@ -74,9 +74,9 @@ public class TestMinimalClientExec {
|
|||
@Mock
|
||||
private HttpExecutionAware execAware;
|
||||
@Mock
|
||||
private ConnectionRequest connRequest;
|
||||
private LeaseRequest connRequest;
|
||||
@Mock
|
||||
private HttpClientConnection managedConn;
|
||||
private ConnectionEndpoint endpoint;
|
||||
|
||||
private MinimalClientExec minimalClientExec;
|
||||
private HttpHost target;
|
||||
|
@ -88,10 +88,10 @@ public class TestMinimalClientExec {
|
|||
requestExecutor, connManager, reuseStrategy, keepAliveStrategy);
|
||||
target = new HttpHost("foo", 80);
|
||||
|
||||
Mockito.when(connManager.requestConnection(
|
||||
Mockito.when(connManager.lease(
|
||||
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
|
||||
Mockito.when(connRequest.get(
|
||||
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(managedConn);
|
||||
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(endpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -106,24 +106,22 @@ public class TestMinimalClientExec {
|
|||
context.setRequestConfig(config);
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
final ClassicHttpResponse finalResponse = minimalClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
|
||||
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
||||
Mockito.verify(connManager).connect(managedConn, route, 123, context);
|
||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
||||
Mockito.verify(managedConn).setSocketTimeout(234);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(connManager).connect(endpoint, 123, TimeUnit.MILLISECONDS, context);
|
||||
Mockito.verify(endpoint).setSocketTimeout(234);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Assert.assertSame(managedConn, context.getConnection());
|
||||
Assert.assertNotNull(finalResponse);
|
||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||
}
|
||||
|
@ -141,11 +139,10 @@ public class TestMinimalClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -156,11 +153,11 @@ public class TestMinimalClientExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(678L);
|
||||
|
||||
final ClassicHttpResponse finalResponse = minimalClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 678L, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(managedConn, Mockito.never()).close();
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(connManager).release(endpoint, null, 678L, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint, Mockito.never()).close();
|
||||
|
||||
Assert.assertNotNull(finalResponse);
|
||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||
|
@ -183,11 +180,10 @@ public class TestMinimalClientExec {
|
|||
.setStream(new ByteArrayInputStream(new byte[]{}))
|
||||
.build());
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
Mockito.when(reuseStrategy.keepAlive(
|
||||
Mockito.same(request),
|
||||
|
@ -195,23 +191,23 @@ public class TestMinimalClientExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
||||
|
||||
final ClassicHttpResponse finalResponse = minimalClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(connManager).requestConnection(route, null);
|
||||
Mockito.verify(connManager).lease(route, null);
|
||||
Mockito.verify(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
||||
Mockito.verify(connManager, Mockito.never()).releaseConnection(
|
||||
Mockito.same(managedConn),
|
||||
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||
Mockito.verify(connManager, Mockito.never()).release(
|
||||
Mockito.same(endpoint),
|
||||
Mockito.any(),
|
||||
Mockito.anyInt(),
|
||||
Mockito.<TimeUnit>any());
|
||||
Mockito.verify(managedConn, Mockito.never()).close();
|
||||
Mockito.verify(endpoint, Mockito.never()).close();
|
||||
|
||||
Assert.assertNotNull(finalResponse);
|
||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||
finalResponse.close();
|
||||
|
||||
Mockito.verify(connManager, Mockito.times(1)).releaseConnection(
|
||||
managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
||||
Mockito.verify(connManager, Mockito.times(1)).release(
|
||||
endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -222,14 +218,14 @@ public class TestMinimalClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
context.setRequestConfig(config);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(true);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(true);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(managedConn).setSocketTimeout(3000);
|
||||
Mockito.verify(endpoint).setSocketTimeout(3000);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -238,14 +234,14 @@ public class TestMinimalClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
Mockito.verify(managedConn, Mockito.never()).setSocketTimeout(Mockito.anyInt());
|
||||
Mockito.verify(endpoint, Mockito.never()).setSocketTimeout(Mockito.anyInt());
|
||||
}
|
||||
|
||||
@Test(expected=RequestAbortedException.class)
|
||||
|
@ -254,7 +250,7 @@ public class TestMinimalClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.FALSE);
|
||||
Mockito.when(execAware.isAborted()).thenReturn(Boolean.TRUE);
|
||||
try {
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
|
@ -281,9 +277,9 @@ public class TestMinimalClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
|
||||
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
|
@ -295,16 +291,15 @@ public class TestMinimalClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
|
||||
|
||||
try {
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -315,16 +310,15 @@ public class TestMinimalClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
|
||||
|
||||
try {
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -335,16 +329,15 @@ public class TestMinimalClientExec {
|
|||
final HttpClientContext context = new HttpClientContext();
|
||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
|
||||
|
||||
try {
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
} catch (final Exception ex) {
|
||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
||||
|
||||
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
@ -356,15 +349,15 @@ public class TestMinimalClientExec {
|
|||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||
|
||||
final ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
|
||||
Mockito.when(requestExecutor.execute(
|
||||
Mockito.<ClassicHttpRequest>any(),
|
||||
Mockito.<HttpClientConnection>any(),
|
||||
Mockito.when(endpoint.execute(
|
||||
Mockito.same(request),
|
||||
Mockito.<HttpRequestExecutor>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||
|
||||
minimalClientExec.execute(request, context, execAware);
|
||||
|
||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||
Mockito.verify(requestExecutor).execute(reqCaptor.capture(), Mockito.<HttpClientConnection>any(), Mockito.<HttpClientContext>any());
|
||||
Mockito.verify(endpoint).execute(reqCaptor.capture(), Mockito.<HttpRequestExecutor>any(), Mockito.<HttpClientContext>any());
|
||||
|
||||
Assert.assertEquals("/test", reqCaptor.getValue().getRequestUri());
|
||||
}
|
||||
|
|
|
@ -121,7 +121,6 @@ public class TestRedirectExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
redirectExec.execute(request, context, execAware);
|
||||
|
@ -173,7 +172,6 @@ public class TestRedirectExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
redirectExec.execute(request, context, execAware);
|
||||
|
@ -207,7 +205,6 @@ public class TestRedirectExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||
|
||||
redirectExec.execute(request, context, execAware);
|
||||
|
@ -253,11 +250,9 @@ public class TestRedirectExec {
|
|||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(target),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(target));
|
||||
Mockito.when(httpRoutePlanner.determineRoute(
|
||||
Mockito.eq(otherHost),
|
||||
Mockito.<RoutedHttpRequest>any(),
|
||||
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(otherHost));
|
||||
|
||||
redirectExec.execute(request, context, execAware);
|
||||
|
|
|
@ -43,7 +43,7 @@ public class TestResponseEntityWrapper {
|
|||
|
||||
private InputStream instream;
|
||||
private HttpEntity entity;
|
||||
private ConnectionHolder connHolder;
|
||||
private EndpointHolder endpointHolder;
|
||||
private ResponseEntityProxy wrapper;
|
||||
|
||||
@Before
|
||||
|
@ -51,83 +51,83 @@ public class TestResponseEntityWrapper {
|
|||
instream = Mockito.mock(InputStream.class);
|
||||
entity = Mockito.mock(HttpEntity.class);
|
||||
Mockito.when(entity.getContent()).thenReturn(instream);
|
||||
connHolder = Mockito.mock(ConnectionHolder.class);
|
||||
wrapper = new ResponseEntityProxy(entity, connHolder);
|
||||
endpointHolder = Mockito.mock(EndpointHolder.class);
|
||||
wrapper = new ResponseEntityProxy(entity, endpointHolder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityStreamClosed() throws Exception {
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
EntityUtils.consume(wrapper);
|
||||
|
||||
Mockito.verify(instream, Mockito.times(1)).close();
|
||||
Mockito.verify(connHolder).releaseConnection();
|
||||
Mockito.verify(endpointHolder).releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityStreamClosedIOError() throws Exception {
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
Mockito.doThrow(new IOException()).when(instream).close();
|
||||
try {
|
||||
EntityUtils.consume(wrapper);
|
||||
Assert.fail("IOException expected");
|
||||
} catch (final IOException ex) {
|
||||
}
|
||||
Mockito.verify(connHolder).abortConnection();
|
||||
Mockito.verify(endpointHolder).abortConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntityStreamClosedIOErrorAlreadyReleased() throws Exception {
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReleased()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReleased()).thenReturn(true);
|
||||
Mockito.doThrow(new SocketException()).when(instream).close();
|
||||
EntityUtils.consume(wrapper);
|
||||
Mockito.verify(connHolder).close();
|
||||
Mockito.verify(endpointHolder).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityWriteTo() throws Exception {
|
||||
final OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
wrapper.writeTo(outstream);
|
||||
Mockito.verify(connHolder).releaseConnection();
|
||||
Mockito.verify(endpointHolder).releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityWriteToIOError() throws Exception {
|
||||
final OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
Mockito.doThrow(new IOException()).when(entity).writeTo(outstream);
|
||||
try {
|
||||
wrapper.writeTo(outstream);
|
||||
Assert.fail("IOException expected");
|
||||
} catch (final IOException ex) {
|
||||
}
|
||||
Mockito.verify(connHolder, Mockito.never()).releaseConnection();
|
||||
Mockito.verify(connHolder).abortConnection();
|
||||
Mockito.verify(endpointHolder, Mockito.never()).releaseConnection();
|
||||
Mockito.verify(endpointHolder).abortConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityEndOfStream() throws Exception {
|
||||
Mockito.when(instream.read()).thenReturn(-1);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
final InputStream content = wrapper.getContent();
|
||||
Assert.assertEquals(-1, content.read());
|
||||
Mockito.verify(instream).close();
|
||||
Mockito.verify(connHolder).releaseConnection();
|
||||
Mockito.verify(endpointHolder).releaseConnection();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReusableEntityEndOfStreamIOError() throws Exception {
|
||||
Mockito.when(instream.read()).thenReturn(-1);
|
||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
||||
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||
Mockito.doThrow(new IOException()).when(instream).close();
|
||||
final InputStream content = wrapper.getContent();
|
||||
try {
|
||||
|
@ -135,7 +135,7 @@ public class TestResponseEntityWrapper {
|
|||
Assert.fail("IOException expected");
|
||||
} catch (final IOException ex) {
|
||||
}
|
||||
Mockito.verify(connHolder).abortConnection();
|
||||
Mockito.verify(endpointHolder).abortConnection();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue