mirror of
https://github.com/apache/httpcomponents-client.git
synced 2025-02-16 23:16:33 +00:00
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.osgi.services.ProxyConfiguration;
|
import org.apache.hc.client5.http.osgi.services.ProxyConfiguration;
|
||||||
import org.apache.hc.core5.http.HttpException;
|
import org.apache.hc.core5.http.HttpException;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
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.http.protocol.HttpContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +52,7 @@ public OSGiHttpRoutePlanner(final List<ProxyConfiguration> proxyConfigurations)
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@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;
|
HttpHost proxyHost = null;
|
||||||
for (final ProxyConfiguration proxyConfiguration : proxyConfigurations) {
|
for (final ProxyConfiguration proxyConfiguration : proxyConfigurations) {
|
||||||
if (proxyConfiguration.isEnabled()) {
|
if (proxyConfiguration.isEnabled()) {
|
||||||
|
@ -51,41 +51,41 @@ public class TestOSGiHttpRoutePlanner {
|
|||||||
public void testDeterminProxy() throws Exception {
|
public void testDeterminProxy() throws Exception {
|
||||||
OSGiHttpRoutePlanner planner = new OSGiHttpRoutePlanner(singletonList(pc1));
|
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);
|
assertNull(proxy);
|
||||||
|
|
||||||
proxy = planner.determineProxy(new HttpHost("there", 9090), null, null);
|
proxy = planner.determineProxy(new HttpHost("there", 9090), null);
|
||||||
assertNotNull(proxy);
|
assertNotNull(proxy);
|
||||||
assertTrue(proxy.getHostName().equals("proxy1"));
|
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);
|
assertNotNull(proxy);
|
||||||
assertTrue(proxy.getHostName().equals("proxy1"));
|
assertTrue(proxy.getHostName().equals("proxy1"));
|
||||||
|
|
||||||
final InetAddress addr = InetAddress.getByName("localhost");
|
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);
|
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);
|
assertNull(proxy);
|
||||||
|
|
||||||
|
|
||||||
// test with more than one registration of proxyConfiguration
|
// test with more than one registration of proxyConfiguration
|
||||||
planner = new OSGiHttpRoutePlanner(asList(pc1, pc2));
|
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);
|
assertNull(proxy);
|
||||||
|
|
||||||
proxy = planner.determineProxy(new HttpHost("there", 9090), null, null);
|
proxy = planner.determineProxy(new HttpHost("there", 9090), null);
|
||||||
assertNotNull(proxy);
|
assertNotNull(proxy);
|
||||||
assertTrue(proxy.getHostName().equals("proxy1")); // the first one
|
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);
|
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);
|
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);
|
assertNull(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,11 +93,11 @@ public void testDeterminProxy() throws Exception {
|
|||||||
public void testMasking() throws Exception {
|
public void testMasking() throws Exception {
|
||||||
final OSGiHttpRoutePlanner planner = new OSGiHttpRoutePlanner(singletonList(pc2));
|
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);
|
assertNotNull(proxy);
|
||||||
assertTrue(proxy.getHostName().equals("proxy2"));
|
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);
|
assertNotNull(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.DnsResolver;
|
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.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
||||||
import org.apache.hc.client5.http.auth.CredentialsProvider;
|
import org.apache.hc.client5.http.auth.CredentialsProvider;
|
||||||
@ -45,15 +44,13 @@
|
|||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.cookie.BasicCookieStore;
|
import org.apache.hc.client5.http.cookie.BasicCookieStore;
|
||||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
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.ManagedHttpClientConnectionFactory;
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
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.BasicCredentialsProvider;
|
||||||
import org.apache.hc.client5.http.impl.sync.CloseableHttpClient;
|
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.impl.sync.HttpClients;
|
||||||
import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
|
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.methods.HttpGet;
|
||||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||||
@ -71,6 +68,9 @@
|
|||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
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.DefaultClassicHttpResponseFactory;
|
||||||
import org.apache.hc.core5.http.impl.io.DefaultHttpRequestWriterFactory;
|
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.HttpMessageParser;
|
||||||
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
||||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
||||||
@ -107,18 +107,30 @@ public Header parseHeader(final CharArrayBuffer buffer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
return new LenientHttpResponseParser(lineParser, DefaultClassicHttpResponseFactory.INSTANCE, h1Config);
|
return new DefaultHttpResponseParser(lineParser, DefaultClassicHttpResponseFactory.INSTANCE, h1Config);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory = new DefaultHttpRequestWriterFactory();
|
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
|
// Use a custom connection factory to customize the process of
|
||||||
// initialization of outgoing HTTP connections. Beside standard connection
|
// initialization of outgoing HTTP connections. Beside standard connection
|
||||||
// configuration parameters HTTP connection factory can define message
|
// configuration parameters HTTP connection factory can define message
|
||||||
// parser / writer routines to be employed by individual connections.
|
// parser / writer routines to be employed by individual connections.
|
||||||
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
|
HttpConnectionFactory<ManagedHttpClientConnection> connFactory = new ManagedHttpClientConnectionFactory(
|
||||||
H1Config.DEFAULT, requestWriterFactory, responseParserFactory);
|
h1Config, connectionConfig, requestWriterFactory, responseParserFactory);
|
||||||
|
|
||||||
// Client HTTP connection objects when fully initialized can be bound to
|
// Client HTTP connection objects when fully initialized can be bound to
|
||||||
// an arbitrary network socket. The process of network socket initialization,
|
// an arbitrary network socket. The process of network socket initialization,
|
||||||
@ -161,26 +173,9 @@ public InetAddress[] resolve(final String host) throws UnknownHostException {
|
|||||||
// Configure the connection manager to use socket configuration either
|
// Configure the connection manager to use socket configuration either
|
||||||
// by default or for a specific host.
|
// by default or for a specific host.
|
||||||
connManager.setDefaultSocketConfig(socketConfig);
|
connManager.setDefaultSocketConfig(socketConfig);
|
||||||
connManager.setSocketConfig(new HttpHost("somehost", 80), socketConfig);
|
|
||||||
// Validate connections after 1 sec of inactivity
|
// Validate connections after 1 sec of inactivity
|
||||||
connManager.setValidateAfterInactivity(1000);
|
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
|
// Configure total max or per route limits for persistent connections
|
||||||
// that can be kept in the pool or leased by the connection manager.
|
// that can be kept in the pool or leased by the connection manager.
|
||||||
connManager.setMaxTotal(100);
|
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
|
* 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;
|
package org.apache.hc.client5.http.impl.io;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
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.DnsResolver;
|
||||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SchemePortResolver;
|
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.HttpClientConnectionManager;
|
||||||
import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
|
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.io.ManagedHttpClientConnection;
|
||||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
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.HttpHost;
|
||||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
|
||||||
import org.apache.hc.core5.http.config.Lookup;
|
import org.apache.hc.core5.http.config.Lookup;
|
||||||
import org.apache.hc.core5.http.config.Registry;
|
import org.apache.hc.core5.http.config.Registry;
|
||||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
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.http.protocol.HttpContext;
|
||||||
import org.apache.hc.core5.util.Args;
|
import org.apache.hc.core5.util.Args;
|
||||||
import org.apache.hc.core5.util.Asserts;
|
import org.apache.hc.core5.util.Asserts;
|
||||||
@ -80,12 +85,12 @@
|
|||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
@Contract(threading = ThreadingBehavior.SAFE)
|
@Contract(threading = ThreadingBehavior.SAFE)
|
||||||
public class BasicHttpClientConnectionManager implements HttpClientConnectionManager, Closeable {
|
public class BasicHttpClientConnectionManager implements HttpClientConnectionManager {
|
||||||
|
|
||||||
private final Logger log = LogManager.getLogger(getClass());
|
private final Logger log = LogManager.getLogger(getClass());
|
||||||
|
|
||||||
private final HttpClientConnectionOperator connectionOperator;
|
private final HttpClientConnectionOperator connectionOperator;
|
||||||
private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||||
|
|
||||||
private ManagedHttpClientConnection conn;
|
private ManagedHttpClientConnection conn;
|
||||||
private HttpRoute route;
|
private HttpRoute route;
|
||||||
@ -94,9 +99,8 @@ public class BasicHttpClientConnectionManager implements HttpClientConnectionMan
|
|||||||
private long expiry;
|
private long expiry;
|
||||||
private boolean leased;
|
private boolean leased;
|
||||||
private SocketConfig socketConfig;
|
private SocketConfig socketConfig;
|
||||||
private ConnectionConfig connConfig;
|
|
||||||
|
|
||||||
private final AtomicBoolean isShutdown;
|
private final AtomicBoolean closed;
|
||||||
|
|
||||||
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
||||||
return RegistryBuilder.<ConnectionSocketFactory>create()
|
return RegistryBuilder.<ConnectionSocketFactory>create()
|
||||||
@ -107,13 +111,11 @@ private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
|||||||
|
|
||||||
public BasicHttpClientConnectionManager(
|
public BasicHttpClientConnectionManager(
|
||||||
final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
|
final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||||
final SchemePortResolver schemePortResolver,
|
final SchemePortResolver schemePortResolver,
|
||||||
final DnsResolver dnsResolver) {
|
final DnsResolver dnsResolver) {
|
||||||
this(
|
this(new DefaultHttpClientConnectionOperator(
|
||||||
new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
|
socketFactoryRegistry, schemePortResolver, dnsResolver), connFactory);
|
||||||
connFactory
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,19 +123,18 @@ public BasicHttpClientConnectionManager(
|
|||||||
*/
|
*/
|
||||||
public BasicHttpClientConnectionManager(
|
public BasicHttpClientConnectionManager(
|
||||||
final HttpClientConnectionOperator httpClientConnectionOperator,
|
final HttpClientConnectionOperator httpClientConnectionOperator,
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||||
super();
|
super();
|
||||||
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
|
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
|
||||||
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
|
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
|
||||||
this.expiry = Long.MAX_VALUE;
|
this.expiry = Long.MAX_VALUE;
|
||||||
this.socketConfig = SocketConfig.DEFAULT;
|
this.socketConfig = SocketConfig.DEFAULT;
|
||||||
this.connConfig = ConnectionConfig.DEFAULT;
|
this.closed = new AtomicBoolean(false);
|
||||||
this.isShutdown = new AtomicBoolean(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasicHttpClientConnectionManager(
|
public BasicHttpClientConnectionManager(
|
||||||
final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
|
final Lookup<ConnectionSocketFactory> socketFactoryRegistry,
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||||
this(socketFactoryRegistry, connFactory, null, null);
|
this(socketFactoryRegistry, connFactory, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ public BasicHttpClientConnectionManager() {
|
|||||||
@Override
|
@Override
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
try {
|
try {
|
||||||
shutdown();
|
close();
|
||||||
} finally { // Make sure we call overridden method even if shutdown barfs
|
} finally { // Make sure we call overridden method even if shutdown barfs
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
@ -157,7 +158,9 @@ protected void finalize() throws Throwable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
shutdown();
|
if (this.closed.compareAndSet(false, true)) {
|
||||||
|
shutdownConnection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRoute getRoute() {
|
HttpRoute getRoute() {
|
||||||
@ -176,37 +179,30 @@ public synchronized void setSocketConfig(final SocketConfig socketConfig) {
|
|||||||
this.socketConfig = socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
|
this.socketConfig = socketConfig != null ? socketConfig : SocketConfig.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized ConnectionConfig getConnectionConfig() {
|
@Override
|
||||||
return connConfig;
|
public LeaseRequest lease(final HttpRoute route, final Object state) {
|
||||||
}
|
return new LeaseRequest() {
|
||||||
|
|
||||||
public synchronized void setConnectionConfig(final ConnectionConfig connConfig) {
|
|
||||||
this.connConfig = connConfig != null ? connConfig : ConnectionConfig.DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ConnectionRequest requestConnection(
|
public ConnectionEndpoint get(
|
||||||
final HttpRoute route,
|
final long timeout,
|
||||||
final Object state) {
|
final TimeUnit tunit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
Args.notNull(route, "Route");
|
try {
|
||||||
return new ConnectionRequest() {
|
return new InternalConnectionEndpoint(route, getConnection(route, state));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new ExecutionException(ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean cancel() {
|
public boolean cancel() {
|
||||||
// Nothing to abort, since requests are immediate.
|
|
||||||
return false;
|
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) {
|
if (this.conn != null) {
|
||||||
this.log.debug("Closing connection");
|
this.log.debug("Closing connection");
|
||||||
try {
|
try {
|
||||||
@ -220,7 +216,7 @@ private void closeConnection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void shutdownConnection() {
|
private synchronized void shutdownConnection() {
|
||||||
if (this.conn != null) {
|
if (this.conn != null) {
|
||||||
this.log.debug("Shutting down connection");
|
this.log.debug("Shutting down connection");
|
||||||
try {
|
try {
|
||||||
@ -243,8 +239,8 @@ private void checkExpiry() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized HttpClientConnection getConnection(final HttpRoute route, final Object state) {
|
synchronized ManagedHttpClientConnection getConnection(final HttpRoute route, final Object state) throws IOException {
|
||||||
Asserts.check(!this.isShutdown.get(), "Connection manager has been shut down");
|
Asserts.check(!this.closed.get(), "Connection manager has been shut down");
|
||||||
if (this.log.isDebugEnabled()) {
|
if (this.log.isDebugEnabled()) {
|
||||||
this.log.debug("Get connection for route " + route);
|
this.log.debug("Get connection for route " + route);
|
||||||
}
|
}
|
||||||
@ -256,23 +252,32 @@ synchronized HttpClientConnection getConnection(final HttpRoute route, final Obj
|
|||||||
this.state = state;
|
this.state = state;
|
||||||
checkExpiry();
|
checkExpiry();
|
||||||
if (this.conn == null) {
|
if (this.conn == null) {
|
||||||
this.conn = this.connFactory.create(route, this.connConfig);
|
this.conn = this.connFactory.createConnection(null);
|
||||||
}
|
}
|
||||||
this.leased = true;
|
this.leased = true;
|
||||||
return this.conn;
|
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
|
@Override
|
||||||
public synchronized void releaseConnection(
|
public synchronized void release(
|
||||||
final HttpClientConnection conn,
|
final ConnectionEndpoint endpoint,
|
||||||
final Object state,
|
final Object state,
|
||||||
final long keepalive, final TimeUnit tunit) {
|
final long keepalive, final TimeUnit tunit) {
|
||||||
Args.notNull(conn, "Connection");
|
Args.notNull(endpoint, "Endpoint");
|
||||||
Asserts.check(conn == this.conn, "Connection not obtained from this manager");
|
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||||
if (this.log.isDebugEnabled()) {
|
final ManagedHttpClientConnection conn = internalEndpoint.detach();
|
||||||
|
if (conn != null && this.log.isDebugEnabled()) {
|
||||||
this.log.debug("Releasing connection " + conn);
|
this.log.debug("Releasing connection " + conn);
|
||||||
}
|
}
|
||||||
if (this.isShutdown.get()) {
|
if (this.closed.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -306,45 +311,47 @@ public synchronized void releaseConnection(
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void connect(
|
public void connect(
|
||||||
final HttpClientConnection conn,
|
final ConnectionEndpoint endpoint,
|
||||||
final HttpRoute route,
|
final long connectTimeout,
|
||||||
final int connectTimeout,
|
final TimeUnit timeUnit,
|
||||||
final HttpContext context) throws IOException {
|
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");
|
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||||
|
if (internalEndpoint.isConnected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final HttpRoute route = internalEndpoint.getRoute();
|
||||||
final HttpHost host;
|
final HttpHost host;
|
||||||
if (route.getProxyHost() != null) {
|
if (route.getProxyHost() != null) {
|
||||||
host = route.getProxyHost();
|
host = route.getProxyHost();
|
||||||
} else {
|
} else {
|
||||||
host = route.getTargetHost();
|
host = route.getTargetHost();
|
||||||
}
|
}
|
||||||
final InetSocketAddress localAddress = route.getLocalSocketAddress();
|
this.connectionOperator.connect(
|
||||||
this.connectionOperator.connect(this.conn, host, localAddress,
|
internalEndpoint.getConnection(),
|
||||||
connectTimeout, this.socketConfig, context);
|
host,
|
||||||
|
route.getLocalSocketAddress(),
|
||||||
|
(int) (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS).toMillis(connectTimeout),
|
||||||
|
this.socketConfig,
|
||||||
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void upgrade(
|
public void upgrade(
|
||||||
final HttpClientConnection conn,
|
final ConnectionEndpoint endpoint,
|
||||||
final HttpRoute route,
|
|
||||||
final HttpContext context) throws IOException {
|
final HttpContext context) throws IOException {
|
||||||
Args.notNull(conn, "Connection");
|
Args.notNull(endpoint, "Endpoint");
|
||||||
Args.notNull(route, "HTTP route");
|
Args.notNull(route, "HTTP route");
|
||||||
Asserts.check(conn == this.conn, "Connection not obtained from this manager");
|
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||||
this.connectionOperator.upgrade(this.conn, route.getTargetHost(), context);
|
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() {
|
public synchronized void closeExpired() {
|
||||||
if (this.isShutdown.get()) {
|
if (this.closed.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.leased) {
|
if (!this.leased) {
|
||||||
@ -352,10 +359,9 @@ public synchronized void closeExpired() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void closeIdle(final long idletime, final TimeUnit tunit) {
|
public synchronized void closeIdle(final long idletime, final TimeUnit tunit) {
|
||||||
Args.notNull(tunit, "Time unit");
|
Args.notNull(tunit, "Time unit");
|
||||||
if (this.isShutdown.get()) {
|
if (this.closed.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.leased) {
|
if (!this.leased) {
|
||||||
@ -370,11 +376,75 @@ public synchronized void closeIdle(final long idletime, final TimeUnit tunit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public synchronized void shutdown() {
|
public boolean isConnected() {
|
||||||
if (this.isShutdown.compareAndSet(false, true)) {
|
final ManagedHttpClientConnection conn = getConnection();
|
||||||
shutdownConnection();
|
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.LayeredConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
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.HttpHost;
|
||||||
import org.apache.hc.core5.http.config.Lookup;
|
import org.apache.hc.core5.http.config.Lookup;
|
||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
import org.apache.hc.core5.http.config.SocketConfig;
|
||||||
@ -191,6 +192,9 @@ public void upgrade(
|
|||||||
}
|
}
|
||||||
final LayeredConnectionSocketFactory lsf = (LayeredConnectionSocketFactory) sf;
|
final LayeredConnectionSocketFactory lsf = (LayeredConnectionSocketFactory) sf;
|
||||||
Socket sock = conn.getSocket();
|
Socket sock = conn.getSocket();
|
||||||
|
if (sock == null) {
|
||||||
|
throw new ConnectionClosedException("Connection is closed");
|
||||||
|
}
|
||||||
final int port = this.schemePortResolver.resolve(host);
|
final int port = this.schemePortResolver.resolve(host);
|
||||||
sock = lsf.createLayeredSocket(sock, host.getHostName(), port, context);
|
sock = lsf.createLayeredSocket(sock, host.getHostName(), port, context);
|
||||||
conn.bind(sock);
|
conn.bind(sock);
|
||||||
|
@ -32,35 +32,41 @@
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.nio.charset.CharsetEncoder;
|
import java.nio.charset.CharsetEncoder;
|
||||||
import java.util.Map;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
import javax.net.ssl.SSLSocket;
|
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.io.ManagedHttpClientConnection;
|
||||||
|
import org.apache.hc.client5.http.utils.Identifiable;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.hc.core5.http.ContentLengthStrategy;
|
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.config.H1Config;
|
||||||
import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection;
|
import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection;
|
||||||
import org.apache.hc.core5.http.impl.io.SocketHolder;
|
import org.apache.hc.core5.http.impl.io.SocketHolder;
|
||||||
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
|
||||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
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.
|
* Default {@link ManagedHttpClientConnection} implementation.
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
public class DefaultManagedHttpClientConnection extends DefaultBHttpClientConnection
|
public class DefaultManagedHttpClientConnection
|
||||||
implements ManagedHttpClientConnection, HttpContext {
|
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 String id;
|
||||||
private final Map<String, Object> attributes;
|
private final AtomicBoolean closed;
|
||||||
|
|
||||||
private volatile boolean shutdown;
|
|
||||||
|
|
||||||
public DefaultManagedHttpClientConnection(
|
public DefaultManagedHttpClientConnection(
|
||||||
final String id,
|
final String id,
|
||||||
@ -75,7 +81,7 @@ public DefaultManagedHttpClientConnection(
|
|||||||
super(buffersize, chardecoder, charencoder, h1Config, incomingContentStrategy, outgoingContentStrategy,
|
super(buffersize, chardecoder, charencoder, h1Config, incomingContentStrategy, outgoingContentStrategy,
|
||||||
requestWriterFactory, responseParserFactory);
|
requestWriterFactory, responseParserFactory);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.attributes = new ConcurrentHashMap<>();
|
this.closed = new AtomicBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultManagedHttpClientConnection(
|
public DefaultManagedHttpClientConnection(
|
||||||
@ -89,15 +95,9 @@ public String getId() {
|
|||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shutdown() throws IOException {
|
|
||||||
this.shutdown = true;
|
|
||||||
super.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(final SocketHolder socketHolder) throws IOException {
|
public void bind(final SocketHolder socketHolder) throws IOException {
|
||||||
if (this.shutdown) {
|
if (this.closed.get()) {
|
||||||
final Socket socket = socketHolder.getSocket();
|
final Socket socket = socketHolder.getSocket();
|
||||||
socket.close(); // allow this to throw...
|
socket.close(); // allow this to throw...
|
||||||
// ...but if it doesn't, explicitly throw one ourselves.
|
// ...but if it doesn't, explicitly throw one ourselves.
|
||||||
@ -123,22 +123,58 @@ public SSLSession getSSLSession() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public Object getAttribute(final String id) {
|
public void setSocketTimeout(final int timeout) {
|
||||||
return this.attributes.get(id);
|
if (this.log.isDebugEnabled()) {
|
||||||
|
this.log.debug(this.id + ": set socket timeout to " + timeout);
|
||||||
|
}
|
||||||
|
super.setSocketTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAttribute(final String id, final Object obj) {
|
public void shutdown() throws IOException {
|
||||||
this.attributes.put(id, obj);
|
if (this.closed.compareAndSet(false, true)) {
|
||||||
|
if (this.log.isDebugEnabled()) {
|
||||||
|
this.log.debug(this.id + ": Shutdown connection");
|
||||||
|
}
|
||||||
|
super.shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object removeAttribute(final String id) {
|
public void bind(final Socket socket) throws IOException {
|
||||||
return this.attributes.remove(id);
|
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;
|
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.Charset;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.nio.charset.CharsetEncoder;
|
import java.nio.charset.CharsetEncoder;
|
||||||
import java.nio.charset.CodingErrorAction;
|
import java.nio.charset.CodingErrorAction;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
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.client5.http.io.ManagedHttpClientConnection;
|
||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
@ -45,43 +45,38 @@
|
|||||||
import org.apache.hc.core5.http.config.H1Config;
|
import org.apache.hc.core5.http.config.H1Config;
|
||||||
import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
|
import org.apache.hc.core5.http.impl.DefaultContentLengthStrategy;
|
||||||
import org.apache.hc.core5.http.impl.io.DefaultHttpRequestWriterFactory;
|
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.HttpMessageParserFactory;
|
||||||
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
|
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.
|
* Factory for {@link ManagedHttpClientConnection} instances.
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
@Contract(threading = ThreadingBehavior.IMMUTABLE)
|
@Contract(threading = ThreadingBehavior.IMMUTABLE)
|
||||||
public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> {
|
public class ManagedHttpClientConnectionFactory implements HttpConnectionFactory<ManagedHttpClientConnection> {
|
||||||
|
|
||||||
private static final AtomicLong COUNTER = new AtomicLong();
|
private static final AtomicLong COUNTER = new AtomicLong();
|
||||||
|
|
||||||
public static final ManagedHttpClientConnectionFactory INSTANCE = new ManagedHttpClientConnectionFactory();
|
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 H1Config h1Config;
|
||||||
|
private final ConnectionConfig connectionConfig;
|
||||||
private final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory;
|
private final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory;
|
||||||
private final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory;
|
private final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory;
|
||||||
private final ContentLengthStrategy incomingContentStrategy;
|
private final ContentLengthStrategy incomingContentStrategy;
|
||||||
private final ContentLengthStrategy outgoingContentStrategy;
|
private final ContentLengthStrategy outgoingContentStrategy;
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 4.4
|
|
||||||
*/
|
|
||||||
public ManagedHttpClientConnectionFactory(
|
public ManagedHttpClientConnectionFactory(
|
||||||
final H1Config h1Config,
|
final H1Config h1Config,
|
||||||
|
final ConnectionConfig connectionConfig,
|
||||||
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
||||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory,
|
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory,
|
||||||
final ContentLengthStrategy incomingContentStrategy,
|
final ContentLengthStrategy incomingContentStrategy,
|
||||||
final ContentLengthStrategy outgoingContentStrategy) {
|
final ContentLengthStrategy outgoingContentStrategy) {
|
||||||
super();
|
super();
|
||||||
this.h1Config = h1Config != null ? h1Config : H1Config.DEFAULT;
|
this.h1Config = h1Config != null ? h1Config : H1Config.DEFAULT;
|
||||||
|
this.connectionConfig = connectionConfig != null ? connectionConfig : ConnectionConfig.DEFAULT;
|
||||||
this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
|
this.requestWriterFactory = requestWriterFactory != null ? requestWriterFactory :
|
||||||
DefaultHttpRequestWriterFactory.INSTANCE;
|
DefaultHttpRequestWriterFactory.INSTANCE;
|
||||||
this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
|
this.responseParserFactory = responseParserFactory != null ? responseParserFactory :
|
||||||
@ -94,31 +89,32 @@ public ManagedHttpClientConnectionFactory(
|
|||||||
|
|
||||||
public ManagedHttpClientConnectionFactory(
|
public ManagedHttpClientConnectionFactory(
|
||||||
final H1Config h1Config,
|
final H1Config h1Config,
|
||||||
|
final ConnectionConfig connectionConfig,
|
||||||
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
|
||||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
||||||
this(h1Config, requestWriterFactory, responseParserFactory, null, null);
|
this(h1Config, connectionConfig, requestWriterFactory, responseParserFactory, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManagedHttpClientConnectionFactory(
|
public ManagedHttpClientConnectionFactory(
|
||||||
final H1Config h1Config,
|
final H1Config h1Config,
|
||||||
|
final ConnectionConfig connectionConfig,
|
||||||
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
|
||||||
this(h1Config, null, responseParserFactory);
|
this(h1Config, connectionConfig, null, responseParserFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManagedHttpClientConnectionFactory() {
|
public ManagedHttpClientConnectionFactory() {
|
||||||
this(null, null);
|
this(null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ManagedHttpClientConnection create(final HttpRoute route, final ConnectionConfig config) {
|
public ManagedHttpClientConnection createConnection(final Socket socket) throws IOException {
|
||||||
final ConnectionConfig cconfig = config != null ? config : ConnectionConfig.DEFAULT;
|
|
||||||
CharsetDecoder chardecoder = null;
|
CharsetDecoder chardecoder = null;
|
||||||
CharsetEncoder charencoder = null;
|
CharsetEncoder charencoder = null;
|
||||||
final Charset charset = cconfig.getCharset();
|
final Charset charset = this.connectionConfig.getCharset();
|
||||||
final CodingErrorAction malformedInputAction = cconfig.getMalformedInputAction() != null ?
|
final CodingErrorAction malformedInputAction = this.connectionConfig.getMalformedInputAction() != null ?
|
||||||
cconfig.getMalformedInputAction() : CodingErrorAction.REPORT;
|
this.connectionConfig.getMalformedInputAction() : CodingErrorAction.REPORT;
|
||||||
final CodingErrorAction unmappableInputAction = cconfig.getUnmappableInputAction() != null ?
|
final CodingErrorAction unmappableInputAction = this.connectionConfig.getUnmappableInputAction() != null ?
|
||||||
cconfig.getUnmappableInputAction() : CodingErrorAction.REPORT;
|
this.connectionConfig.getUnmappableInputAction() : CodingErrorAction.REPORT;
|
||||||
if (charset != null) {
|
if (charset != null) {
|
||||||
chardecoder = charset.newDecoder();
|
chardecoder = charset.newDecoder();
|
||||||
chardecoder.onMalformedInput(malformedInputAction);
|
chardecoder.onMalformedInput(malformedInputAction);
|
||||||
@ -128,12 +124,9 @@ public ManagedHttpClientConnection create(final HttpRoute route, final Connectio
|
|||||||
charencoder.onUnmappableCharacter(unmappableInputAction);
|
charencoder.onUnmappableCharacter(unmappableInputAction);
|
||||||
}
|
}
|
||||||
final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
|
final String id = "http-outgoing-" + Long.toString(COUNTER.getAndIncrement());
|
||||||
return new LoggingManagedHttpClientConnection(
|
final DefaultManagedHttpClientConnection conn = new DefaultManagedHttpClientConnection(
|
||||||
id,
|
id,
|
||||||
log,
|
connectionConfig.getBufferSize(),
|
||||||
headerlog,
|
|
||||||
wirelog,
|
|
||||||
cconfig.getBufferSize(),
|
|
||||||
chardecoder,
|
chardecoder,
|
||||||
charencoder,
|
charencoder,
|
||||||
h1Config,
|
h1Config,
|
||||||
@ -141,6 +134,10 @@ public ManagedHttpClientConnection create(final HttpRoute route, final Connectio
|
|||||||
outgoingContentStrategy,
|
outgoingContentStrategy,
|
||||||
requestWriterFactory,
|
requestWriterFactory,
|
||||||
responseParserFactory);
|
responseParserFactory);
|
||||||
|
if (socket != null) {
|
||||||
|
conn.bind(socket);
|
||||||
|
}
|
||||||
|
return conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.hc.client5.http.impl.io;
|
package org.apache.hc.client5.http.impl.io;
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -37,15 +35,17 @@
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
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.DnsResolver;
|
||||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SchemePortResolver;
|
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.HttpClientConnectionManager;
|
||||||
import org.apache.hc.client5.http.io.HttpClientConnectionOperator;
|
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.io.ManagedHttpClientConnection;
|
||||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||||
@ -53,70 +53,68 @@
|
|||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.function.Callback;
|
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.HttpHost;
|
||||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
|
||||||
import org.apache.hc.core5.http.config.Lookup;
|
import org.apache.hc.core5.http.config.Lookup;
|
||||||
import org.apache.hc.core5.http.config.Registry;
|
import org.apache.hc.core5.http.config.Registry;
|
||||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
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.HttpClientConnection;
|
||||||
|
import org.apache.hc.core5.http.io.HttpConnectionFactory;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.apache.hc.core5.pool.ConnPoolControl;
|
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.ConnPoolPolicy;
|
||||||
import org.apache.hc.core5.pool.PoolEntry;
|
import org.apache.hc.core5.pool.PoolEntry;
|
||||||
import org.apache.hc.core5.pool.PoolStats;
|
import org.apache.hc.core5.pool.PoolStats;
|
||||||
import org.apache.hc.core5.pool.StrictConnPool;
|
import org.apache.hc.core5.pool.StrictConnPool;
|
||||||
import org.apache.hc.core5.util.Args;
|
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.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code ClientConnectionPoolManager} maintains a pool of
|
* {@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
|
* from multiple execution threads. Connections are pooled on a per route
|
||||||
* basis. A request for a route which already the manager has persistent
|
* basis. A request for a route which already the manager has persistent
|
||||||
* connections for available in the pool will be services by leasing
|
* 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>
|
* <p>
|
||||||
* {@code ClientConnectionPoolManager} maintains a maximum limit of connection
|
* {@code ClientConnectionPoolManager} maintains a maximum limit of connection
|
||||||
* on a per route basis and in total. Per default this implementation will
|
* on a per route basis and in total. Connection limits, however, can be adjusted
|
||||||
* create no more than than 2 concurrent connections per given route
|
* using {@link ConnPoolControl} methods.
|
||||||
* 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>
|
|
||||||
* <p>
|
* <p>
|
||||||
* Total time to live (TTL) set at construction time defines maximum life span
|
* Total time to live (TTL) set at construction time defines maximum life span
|
||||||
* of persistent connections regardless of their expiration setting. No persistent
|
* of persistent connections regardless of their expiration setting. No persistent
|
||||||
* connection will be re-used past its TTL value.
|
* connection will be re-used past its TTL value.
|
||||||
* </p>
|
|
||||||
* <p>
|
* <p>
|
||||||
* The handling of stale connections was changed in version 4.4.
|
* The handling of stale connections was changed in version 4.4.
|
||||||
* Previously, the code would check every connection by default before re-using it.
|
* 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 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 last use of the connection exceeds the timeout that has been set.
|
||||||
* The default timeout is set to 5000ms - see
|
* The default timeout is set to 5000ms.
|
||||||
* {@link #PoolingHttpClientConnectionManager(HttpClientConnectionOperator, HttpConnectionFactory, long, TimeUnit)}
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
|
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
|
||||||
public class PoolingHttpClientConnectionManager
|
public class PoolingHttpClientConnectionManager
|
||||||
implements HttpClientConnectionManager, ConnPoolControl<HttpRoute>, Closeable {
|
implements HttpClientConnectionManager, ConnPoolControl<HttpRoute> {
|
||||||
|
|
||||||
private final Logger log = LogManager.getLogger(getClass());
|
private final Logger log = LogManager.getLogger(getClass());
|
||||||
|
|
||||||
public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 25;
|
public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 25;
|
||||||
public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
|
public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 5;
|
||||||
|
|
||||||
private final ConfigData configData;
|
|
||||||
private final StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool;
|
private final StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool;
|
||||||
private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||||
private final HttpClientConnectionOperator connectionOperator;
|
private final HttpClientConnectionOperator connectionOperator;
|
||||||
private final AtomicBoolean isShutDown;
|
private final AtomicBoolean closed;
|
||||||
|
|
||||||
|
private volatile SocketConfig defaultSocketConfig;
|
||||||
private volatile int validateAfterInactivity;
|
private volatile int validateAfterInactivity;
|
||||||
|
|
||||||
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
|
||||||
@ -130,8 +128,9 @@ public PoolingHttpClientConnectionManager() {
|
|||||||
this(getDefaultRegistry());
|
this(getDefaultRegistry());
|
||||||
}
|
}
|
||||||
|
|
||||||
public PoolingHttpClientConnectionManager(final long timeToLive, final TimeUnit tunit) {
|
public PoolingHttpClientConnectionManager(
|
||||||
this(getDefaultRegistry(), null, null ,null, timeToLive, tunit);
|
final long timeToLive, final TimeUnit tunit) {
|
||||||
|
this(getDefaultRegistry(), null, null ,null, ConnPoolPolicy.LIFO, null, timeToLive, tunit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PoolingHttpClientConnectionManager(
|
public PoolingHttpClientConnectionManager(
|
||||||
@ -147,49 +146,46 @@ public PoolingHttpClientConnectionManager(
|
|||||||
|
|
||||||
public PoolingHttpClientConnectionManager(
|
public PoolingHttpClientConnectionManager(
|
||||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||||
this(socketFactoryRegistry, connFactory, null);
|
this(socketFactoryRegistry, connFactory, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PoolingHttpClientConnectionManager(
|
public PoolingHttpClientConnectionManager(
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory) {
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory) {
|
||||||
this(getDefaultRegistry(), connFactory, null);
|
this(getDefaultRegistry(), connFactory, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PoolingHttpClientConnectionManager(
|
public PoolingHttpClientConnectionManager(
|
||||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||||
final DnsResolver dnsResolver) {
|
final DnsResolver dnsResolver) {
|
||||||
this(socketFactoryRegistry, connFactory, null, dnsResolver, -1, TimeUnit.MILLISECONDS);
|
this(socketFactoryRegistry, connFactory, null, dnsResolver, ConnPoolPolicy.LIFO, null, -1, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PoolingHttpClientConnectionManager(
|
public PoolingHttpClientConnectionManager(
|
||||||
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
final Registry<ConnectionSocketFactory> socketFactoryRegistry,
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||||
final SchemePortResolver schemePortResolver,
|
final SchemePortResolver schemePortResolver,
|
||||||
final DnsResolver dnsResolver,
|
final DnsResolver dnsResolver,
|
||||||
|
final ConnPoolPolicy connPoolPolicy,
|
||||||
|
final ConnPoolListener<HttpRoute> connPoolListener,
|
||||||
final long timeToLive, final TimeUnit tunit) {
|
final long timeToLive, final TimeUnit tunit) {
|
||||||
this(
|
this(new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
|
||||||
new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver),
|
connFactory, connPoolPolicy, connPoolListener, timeToLive, tunit);
|
||||||
connFactory,
|
|
||||||
timeToLive, tunit
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 4.4
|
|
||||||
*/
|
|
||||||
public PoolingHttpClientConnectionManager(
|
public PoolingHttpClientConnectionManager(
|
||||||
final HttpClientConnectionOperator httpClientConnectionOperator,
|
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) {
|
final long timeToLive, final TimeUnit tunit) {
|
||||||
super();
|
super();
|
||||||
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
|
this.connectionOperator = Args.notNull(httpClientConnectionOperator, "Connection operator");
|
||||||
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
|
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
|
||||||
this.configData = new ConfigData();
|
|
||||||
this.pool = new StrictConnPool<>(
|
this.pool = new StrictConnPool<>(
|
||||||
DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive, tunit, ConnPoolPolicy.LIFO, null);
|
DEFAULT_MAX_CONNECTIONS_PER_ROUTE, DEFAULT_MAX_TOTAL_CONNECTIONS, timeToLive, tunit, connPoolPolicy, connPoolListener);
|
||||||
this.isShutDown = new AtomicBoolean(false);
|
this.closed = new AtomicBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,15 +200,14 @@ public PoolingHttpClientConnectionManager(
|
|||||||
this.connectionOperator = new DefaultHttpClientConnectionOperator(
|
this.connectionOperator = new DefaultHttpClientConnectionOperator(
|
||||||
socketFactoryRegistry, schemePortResolver, dnsResolver);
|
socketFactoryRegistry, schemePortResolver, dnsResolver);
|
||||||
this.connFactory = ManagedHttpClientConnectionFactory.INSTANCE;
|
this.connFactory = ManagedHttpClientConnectionFactory.INSTANCE;
|
||||||
this.configData = new ConfigData();
|
|
||||||
this.pool = pool;
|
this.pool = pool;
|
||||||
this.isShutDown = new AtomicBoolean(false);
|
this.closed = new AtomicBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
try {
|
try {
|
||||||
shutdown();
|
close();
|
||||||
} finally {
|
} finally {
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
@ -220,139 +215,112 @@ protected void finalize() throws Throwable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
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) {
|
private InternalConnectionEndpoint cast(final ConnectionEndpoint endpoint) {
|
||||||
final StringBuilder buf = new StringBuilder();
|
if (endpoint instanceof InternalConnectionEndpoint) {
|
||||||
buf.append("[route: ").append(route).append("]");
|
return (InternalConnectionEndpoint) endpoint;
|
||||||
if (state != null) {
|
} else {
|
||||||
buf.append("[state: ").append(state).append("]");
|
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
|
@Override
|
||||||
public ConnectionRequest requestConnection(
|
public LeaseRequest lease(
|
||||||
final HttpRoute route,
|
final HttpRoute route,
|
||||||
final Object state) {
|
final Object state) {
|
||||||
Args.notNull(route, "HTTP route");
|
Args.notNull(route, "HTTP route");
|
||||||
if (this.log.isDebugEnabled()) {
|
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
|
@Override
|
||||||
public boolean cancel() {
|
public boolean cancel() {
|
||||||
return future.cancel(true);
|
return leaseFuture.cancel(true);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpClientConnection get(
|
|
||||||
final long timeout,
|
|
||||||
final TimeUnit tunit) throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException {
|
|
||||||
return leaseConnection(future, timeout, tunit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@Override
|
||||||
public void releaseConnection(
|
public void release(
|
||||||
final HttpClientConnection managedConn,
|
final ConnectionEndpoint endpoint,
|
||||||
final Object state,
|
final Object state,
|
||||||
final long keepAlive, final TimeUnit timeUnit) {
|
final long keepAlive, final TimeUnit timeUnit) {
|
||||||
Args.notNull(managedConn, "Managed connection");
|
Args.notNull(endpoint, "Managed endpoint");
|
||||||
synchronized (managedConn) {
|
final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = cast(endpoint).detach();
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
if (entry == null) {
|
||||||
if (poolProxy.isDetached()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = poolProxy.detach();
|
|
||||||
try {
|
|
||||||
final ManagedHttpClientConnection conn = entry.getConnection();
|
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;
|
final TimeUnit effectiveUnit = timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS;
|
||||||
entry.updateConnection(keepAlive, effectiveUnit, state);
|
entry.updateConnection(keepAlive, effectiveUnit, state);
|
||||||
if (this.log.isDebugEnabled()) {
|
if (this.log.isDebugEnabled()) {
|
||||||
@ -362,85 +330,61 @@ public void releaseConnection(
|
|||||||
} else {
|
} else {
|
||||||
s = "indefinitely";
|
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 {
|
} finally {
|
||||||
final ManagedHttpClientConnection conn = entry.getConnection();
|
this.pool.release(entry, reusable);
|
||||||
this.pool.release(entry, conn.isOpen() && poolProxy.isRouteComplete());
|
|
||||||
if (this.log.isDebugEnabled()) {
|
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
|
@Override
|
||||||
public void connect(
|
public void connect(
|
||||||
final HttpClientConnection managedConn,
|
final ConnectionEndpoint endpoint,
|
||||||
final HttpRoute route,
|
final long connectTimeout,
|
||||||
final int connectTimeout,
|
final TimeUnit timeUnit,
|
||||||
final HttpContext context) throws IOException {
|
final HttpContext context) throws IOException {
|
||||||
Args.notNull(managedConn, "Managed Connection");
|
Args.notNull(endpoint, "Managed endpoint");
|
||||||
Args.notNull(route, "HTTP route");
|
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||||
final ManagedHttpClientConnection conn;
|
if (internalEndpoint.isConnected()) {
|
||||||
synchronized (managedConn) {
|
return;
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
|
||||||
conn = poolProxy.getConnection();
|
|
||||||
}
|
}
|
||||||
|
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getPoolEntry();
|
||||||
|
if (!poolEntry.hasConnection()) {
|
||||||
|
poolEntry.assignConnection(connFactory.createConnection(null));
|
||||||
|
}
|
||||||
|
final HttpRoute route = poolEntry.getRoute();
|
||||||
final HttpHost host;
|
final HttpHost host;
|
||||||
if (route.getProxyHost() != null) {
|
if (route.getProxyHost() != null) {
|
||||||
host = route.getProxyHost();
|
host = route.getProxyHost();
|
||||||
} else {
|
} else {
|
||||||
host = route.getTargetHost();
|
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(
|
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
|
@Override
|
||||||
public void upgrade(
|
public void upgrade(
|
||||||
final HttpClientConnection managedConn,
|
final ConnectionEndpoint endpoint,
|
||||||
final HttpRoute route,
|
|
||||||
final HttpContext context) throws IOException {
|
final HttpContext context) throws IOException {
|
||||||
Args.notNull(managedConn, "Managed Connection");
|
Args.notNull(endpoint, "Managed endpoint");
|
||||||
Args.notNull(route, "HTTP route");
|
final InternalConnectionEndpoint internalEndpoint = cast(endpoint);
|
||||||
final ManagedHttpClientConnection conn;
|
final PoolEntry<HttpRoute, ManagedHttpClientConnection> poolEntry = internalEndpoint.getValidatedPoolEntry();
|
||||||
synchronized (managedConn) {
|
final HttpRoute route = poolEntry.getRoute();
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(managedConn);
|
this.connectionOperator.upgrade(poolEntry.getConnection(), route.getTargetHost(), context);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -513,35 +457,11 @@ public Set<HttpRoute> getRoutes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SocketConfig getDefaultSocketConfig() {
|
public SocketConfig getDefaultSocketConfig() {
|
||||||
return this.configData.getDefaultSocketConfig();
|
return this.defaultSocketConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
|
public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
|
||||||
this.configData.setDefaultSocketConfig(defaultSocketConfig);
|
this.defaultSocketConfig = 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -555,12 +475,11 @@ public int getValidateAfterInactivity() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines period of inactivity in milliseconds after which persistent connections must
|
* Defines period of inactivity in milliseconds after which persistent connections must
|
||||||
* be re-validated prior to being {@link #leaseConnection(java.util.concurrent.Future,
|
* be re-validated prior to being {@link #lease(HttpRoute, Object)} leased} to the consumer.
|
||||||
* long, java.util.concurrent.TimeUnit) leased} to the consumer. Non-positive value passed
|
* Non-positive value passed to this method disables connection validation. This check helps
|
||||||
* to this method disables connection validation. This check helps detect connections
|
* detect connections that have become stale (half-closed) while kept inactive in the pool.
|
||||||
* 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
|
* @since 4.4
|
||||||
*/
|
*/
|
||||||
@ -571,14 +490,11 @@ public void setValidateAfterInactivity(final int ms) {
|
|||||||
static class ConfigData {
|
static class ConfigData {
|
||||||
|
|
||||||
private final Map<HttpHost, SocketConfig> socketConfigMap;
|
private final Map<HttpHost, SocketConfig> socketConfigMap;
|
||||||
private final Map<HttpHost, ConnectionConfig> connectionConfigMap;
|
|
||||||
private volatile SocketConfig defaultSocketConfig;
|
private volatile SocketConfig defaultSocketConfig;
|
||||||
private volatile ConnectionConfig defaultConnectionConfig;
|
|
||||||
|
|
||||||
ConfigData() {
|
ConfigData() {
|
||||||
super();
|
super();
|
||||||
this.socketConfigMap = new ConcurrentHashMap<>();
|
this.socketConfigMap = new ConcurrentHashMap<>();
|
||||||
this.connectionConfigMap = new ConcurrentHashMap<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketConfig getDefaultSocketConfig() {
|
public SocketConfig getDefaultSocketConfig() {
|
||||||
@ -589,14 +505,6 @@ public void setDefaultSocketConfig(final SocketConfig defaultSocketConfig) {
|
|||||||
this.defaultSocketConfig = defaultSocketConfig;
|
this.defaultSocketConfig = defaultSocketConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectionConfig getDefaultConnectionConfig() {
|
|
||||||
return this.defaultConnectionConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultConnectionConfig(final ConnectionConfig defaultConnectionConfig) {
|
|
||||||
this.defaultConnectionConfig = defaultConnectionConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SocketConfig getSocketConfig(final HttpHost host) {
|
public SocketConfig getSocketConfig(final HttpHost host) {
|
||||||
return this.socketConfigMap.get(host);
|
return this.socketConfigMap.get(host);
|
||||||
}
|
}
|
||||||
@ -605,12 +513,76 @@ public void setSocketConfig(final HttpHost host, final SocketConfig socketConfig
|
|||||||
this.socketConfigMap.put(host, socketConfig);
|
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) {
|
class InternalConnectionEndpoint extends ConnectionEndpoint {
|
||||||
this.connectionConfigMap.put(host, connectionConfig);
|
|
||||||
|
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 @@
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.DnsResolver;
|
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.ConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
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.RegistryBuilder;
|
||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
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.
|
* Builder for {@link PoolingHttpClientConnectionManager} instances.
|
||||||
@ -67,11 +71,13 @@
|
|||||||
*/
|
*/
|
||||||
public class PoolingHttpClientConnectionManagerBuilder {
|
public class PoolingHttpClientConnectionManagerBuilder {
|
||||||
|
|
||||||
|
private HttpConnectionFactory<ManagedHttpClientConnection> connectionFactory;
|
||||||
private LayeredConnectionSocketFactory sslSocketFactory;
|
private LayeredConnectionSocketFactory sslSocketFactory;
|
||||||
|
private SchemePortResolver schemePortResolver;
|
||||||
private DnsResolver dnsResolver;
|
private DnsResolver dnsResolver;
|
||||||
|
private ConnPoolPolicy connPoolPolicy;
|
||||||
|
private ConnPoolListener<HttpRoute> connPoolListener;
|
||||||
private SocketConfig defaultSocketConfig;
|
private SocketConfig defaultSocketConfig;
|
||||||
private ConnectionConfig defaultConnectionConfig;
|
|
||||||
|
|
||||||
private boolean systemProperties;
|
private boolean systemProperties;
|
||||||
|
|
||||||
@ -91,7 +97,16 @@ public static PoolingHttpClientConnectionManagerBuilder create() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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(
|
public final PoolingHttpClientConnectionManagerBuilder setSSLSocketFactory(
|
||||||
final LayeredConnectionSocketFactory sslSocketFactory) {
|
final LayeredConnectionSocketFactory sslSocketFactory) {
|
||||||
@ -99,6 +114,38 @@ public final PoolingHttpClientConnectionManagerBuilder setSSLSocketFactory(
|
|||||||
return this;
|
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.
|
* Assigns maximum total connection value.
|
||||||
*/
|
*/
|
||||||
@ -123,18 +170,8 @@ public final PoolingHttpClientConnectionManagerBuilder setDefaultSocketConfig(fi
|
|||||||
return this;
|
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
|
* Sets maximum time to live for persistent connections
|
||||||
*
|
|
||||||
* @since 4.4
|
|
||||||
*/
|
*/
|
||||||
public final PoolingHttpClientConnectionManagerBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {
|
public final PoolingHttpClientConnectionManagerBuilder setConnectionTimeToLive(final long connTimeToLive, final TimeUnit connTimeToLiveTimeUnit) {
|
||||||
this.connTimeToLive = connTimeToLive;
|
this.connTimeToLive = connTimeToLive;
|
||||||
@ -153,14 +190,6 @@ public final PoolingHttpClientConnectionManagerBuilder setValidateAfterInactivit
|
|||||||
return this;
|
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
|
* Use system properties when creating and configuring default
|
||||||
* implementations.
|
* implementations.
|
||||||
@ -170,13 +199,6 @@ public final PoolingHttpClientConnectionManagerBuilder useSystemProperties() {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] split(final String s) {
|
|
||||||
if (TextUtils.isBlank(s)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return s.split(" *, *");
|
|
||||||
}
|
|
||||||
|
|
||||||
public PoolingHttpClientConnectionManager build() {
|
public PoolingHttpClientConnectionManager build() {
|
||||||
@SuppressWarnings("resource")
|
@SuppressWarnings("resource")
|
||||||
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
|
final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
|
||||||
@ -187,18 +209,17 @@ public PoolingHttpClientConnectionManager build() {
|
|||||||
SSLConnectionSocketFactory.getSystemSocketFactory() :
|
SSLConnectionSocketFactory.getSystemSocketFactory() :
|
||||||
SSLConnectionSocketFactory.getSocketFactory()))
|
SSLConnectionSocketFactory.getSocketFactory()))
|
||||||
.build(),
|
.build(),
|
||||||
null,
|
connectionFactory,
|
||||||
null,
|
schemePortResolver,
|
||||||
dnsResolver,
|
dnsResolver,
|
||||||
|
connPoolPolicy,
|
||||||
|
connPoolListener,
|
||||||
connTimeToLive,
|
connTimeToLive,
|
||||||
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
|
connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
|
||||||
poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
|
poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
|
||||||
if (defaultSocketConfig != null) {
|
if (defaultSocketConfig != null) {
|
||||||
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
|
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
|
||||||
}
|
}
|
||||||
if (defaultConnectionConfig != null) {
|
|
||||||
poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
|
|
||||||
}
|
|
||||||
if (maxConnTotal > 0) {
|
if (maxConnTotal > 0) {
|
||||||
poolingmgr.setMaxTotal(maxConnTotal);
|
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.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal class.
|
|
||||||
*
|
|
||||||
* @since 4.3
|
|
||||||
*/
|
|
||||||
class LoggingInputStream extends InputStream {
|
class LoggingInputStream extends InputStream {
|
||||||
|
|
||||||
private final InputStream in;
|
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.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -49,6 +49,7 @@ public LoggingOutputStream(final OutputStream out, final Wire wire) {
|
|||||||
@Override
|
@Override
|
||||||
public void write(final int b) throws IOException {
|
public void write(final int b) throws IOException {
|
||||||
try {
|
try {
|
||||||
|
out.write(b);
|
||||||
wire.output(b);
|
wire.output(b);
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
wire.output("[write] I/O error: " + ex.getMessage());
|
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.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -33,14 +33,15 @@
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
import org.apache.hc.core5.http.impl.io.SocketHolder;
|
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;
|
private final Wire wire;
|
||||||
|
|
||||||
LoggingSocketHolder(final Socket socket, final Wire wire) {
|
public LoggingSocketHolder(final Socket socket, final String id, final Logger log) {
|
||||||
super(socket);
|
super(socket);
|
||||||
this.wire = wire;
|
this.wire = new Wire(log, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -24,52 +24,36 @@
|
|||||||
* <http://www.apache.org/>.
|
* <http://www.apache.org/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package org.apache.hc.client5.http.impl.io;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
package org.apache.hc.client5.http.impl.logging;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
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.hc.core5.util.Args;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs data to the wire LOG.
|
|
||||||
*
|
|
||||||
* @since 4.0
|
|
||||||
*/
|
|
||||||
@Contract(threading = ThreadingBehavior.IMMUTABLE)
|
|
||||||
class Wire {
|
class Wire {
|
||||||
|
|
||||||
private final Logger log;
|
private final Logger log;
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
/**
|
Wire(final Logger log, final String id) {
|
||||||
* @since 4.3
|
super();
|
||||||
*/
|
|
||||||
public Wire(final Logger log, final String id) {
|
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wire(final Logger log) {
|
private void wire(final String header, final byte[] b, final int pos, final int off) {
|
||||||
this(log, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void wire(final String header, final InputStream instream)
|
|
||||||
throws IOException {
|
|
||||||
final StringBuilder buffer = new StringBuilder();
|
final StringBuilder buffer = new StringBuilder();
|
||||||
int ch;
|
for (int i = 0; i < off; i++) {
|
||||||
while ((ch = instream.read()) != -1) {
|
final int ch = b[pos + i];
|
||||||
if (ch == 13) {
|
if (ch == 13) {
|
||||||
buffer.append("[\\r]");
|
buffer.append("[\\r]");
|
||||||
} else if (ch == 10) {
|
} else if (ch == 10) {
|
||||||
buffer.append("[\\n]\"");
|
buffer.append("[\\n]\"");
|
||||||
buffer.insert(0, "\"");
|
buffer.insert(0, "\"");
|
||||||
buffer.insert(0, header);
|
buffer.insert(0, header);
|
||||||
log.debug(id + " " + buffer.toString());
|
this.log.debug(this.id + " " + buffer.toString());
|
||||||
buffer.setLength(0);
|
buffer.setLength(0);
|
||||||
} else if ((ch < 32) || (ch > 127)) {
|
} else if ((ch < 32) || (ch > 127)) {
|
||||||
buffer.append("[0x");
|
buffer.append("[0x");
|
||||||
@ -83,70 +67,73 @@ private void wire(final String header, final InputStream instream)
|
|||||||
buffer.append('\"');
|
buffer.append('\"');
|
||||||
buffer.insert(0, '\"');
|
buffer.insert(0, '\"');
|
||||||
buffer.insert(0, header);
|
buffer.insert(0, header);
|
||||||
log.debug(id + " " + buffer.toString());
|
this.log.debug(this.id + " " + buffer.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean enabled() {
|
public boolean isEnabled() {
|
||||||
return log.isDebugEnabled();
|
return this.log.isDebugEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void output(final InputStream outstream)
|
public void output(final byte[] b, final int pos, final int off) {
|
||||||
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 {
|
|
||||||
Args.notNull(b, "Output");
|
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)
|
public void input(final byte[] b, final int pos, final int off) {
|
||||||
throws IOException {
|
|
||||||
Args.notNull(b, "Input");
|
Args.notNull(b, "Input");
|
||||||
wire("<< ", new ByteArrayInputStream(b, off, len));
|
wire("<< ", b, pos, off);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void output(final byte[] b)
|
public void output(final byte[] b) {
|
||||||
throws IOException {
|
|
||||||
Args.notNull(b, "Output");
|
Args.notNull(b, "Output");
|
||||||
wire(">> ", new ByteArrayInputStream(b));
|
output(b, 0, b.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void input(final byte[] b)
|
public void input(final byte[] b) {
|
||||||
throws IOException {
|
|
||||||
Args.notNull(b, "Input");
|
Args.notNull(b, "Input");
|
||||||
wire("<< ", new ByteArrayInputStream(b));
|
input(b, 0, b.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void output(final int b)
|
public void output(final int b) {
|
||||||
throws IOException {
|
|
||||||
output(new byte[] {(byte) b});
|
output(new byte[] {(byte) b});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void input(final int b)
|
public void input(final int b) {
|
||||||
throws IOException {
|
|
||||||
input(new byte[] {(byte) b});
|
input(new byte[] {(byte) b});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void output(final String s)
|
public void output(final String s) {
|
||||||
throws IOException {
|
|
||||||
Args.notNull(s, "Output");
|
Args.notNull(s, "Output");
|
||||||
output(s.getBytes());
|
output(s.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void input(final String s)
|
public void input(final String s) {
|
||||||
throws IOException {
|
|
||||||
Args.notNull(s, "Input");
|
Args.notNull(s, "Input");
|
||||||
input(s.getBytes());
|
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.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.http.HttpException;
|
import org.apache.hc.core5.http.HttpException;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
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.http.protocol.HttpContext;
|
||||||
import org.apache.hc.core5.util.Args;
|
import org.apache.hc.core5.util.Args;
|
||||||
|
|
||||||
@ -59,7 +58,6 @@ public DefaultProxyRoutePlanner(final HttpHost proxy) {
|
|||||||
@Override
|
@Override
|
||||||
protected HttpHost determineProxy(
|
protected HttpHost determineProxy(
|
||||||
final HttpHost target,
|
final HttpHost target,
|
||||||
final HttpRequest request,
|
|
||||||
final HttpContext context) throws HttpException {
|
final HttpContext context) throws HttpException {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
import org.apache.hc.core5.http.HttpRequest;
|
import org.apache.hc.core5.http.HttpRequest;
|
||||||
import org.apache.hc.core5.http.ProtocolException;
|
import org.apache.hc.core5.http.ProtocolException;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
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
|
* Default implementation of an {@link HttpRoutePlanner}. It will not make use of
|
||||||
@ -63,11 +63,7 @@ public DefaultRoutePlanner(final SchemePortResolver schemePortResolver) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HttpRoute determineRoute(
|
public HttpRoute determineRoute(final HttpHost host, final HttpContext context) throws HttpException {
|
||||||
final HttpHost host,
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpContext context) throws HttpException {
|
|
||||||
Args.notNull(request, "Request");
|
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
throw new ProtocolException("Target host is not specified");
|
throw new ProtocolException("Target host is not specified");
|
||||||
}
|
}
|
||||||
@ -76,7 +72,7 @@ public HttpRoute determineRoute(
|
|||||||
final InetAddress local = config.getLocalAddress();
|
final InetAddress local = config.getLocalAddress();
|
||||||
HttpHost proxy = config.getProxy();
|
HttpHost proxy = config.getProxy();
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
proxy = determineProxy(host, request, context);
|
proxy = determineProxy(host, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
final HttpHost target;
|
final HttpHost target;
|
||||||
@ -100,6 +96,20 @@ public HttpRoute determineRoute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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.
|
* This implementation returns null.
|
||||||
*
|
*
|
||||||
@ -107,7 +117,6 @@ public HttpRoute determineRoute(
|
|||||||
*/
|
*/
|
||||||
protected HttpHost determineProxy(
|
protected HttpHost determineProxy(
|
||||||
final HttpHost target,
|
final HttpHost target,
|
||||||
final HttpRequest request,
|
|
||||||
final HttpContext context) throws HttpException {
|
final HttpContext context) throws HttpException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.http.HttpException;
|
import org.apache.hc.core5.http.HttpException;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
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.http.protocol.HttpContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,10 +72,7 @@ public SystemDefaultRoutePlanner(final ProxySelector proxySelector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpHost determineProxy(
|
protected HttpHost determineProxy(final HttpHost target, final HttpContext context) throws HttpException {
|
||||||
final HttpHost target,
|
|
||||||
final HttpRequest request,
|
|
||||||
final HttpContext context) throws HttpException {
|
|
||||||
final URI targetURI;
|
final URI targetURI;
|
||||||
try {
|
try {
|
||||||
targetURI = new URI(target.toURI());
|
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 java.io.IOException;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.impl.sync.AbstractResponseHandler;
|
|
||||||
import org.apache.hc.client5.http.protocol.ClientProtocolException;
|
import org.apache.hc.client5.http.protocol.ClientProtocolException;
|
||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
@ -39,13 +38,13 @@
|
|||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
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
|
* 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.
|
* body is consumed and an {@link org.apache.hc.client5.http.protocol.HttpResponseException} is thrown.
|
||||||
* <p>
|
* <p>
|
||||||
* If this is used with
|
* If this is used with
|
||||||
* {@link org.apache.hc.client5.http.sync.HttpClient#execute(
|
* {@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.
|
* HttpClient may handle redirects (3xx responses) internally.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
@ -32,12 +32,11 @@
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
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.client5.http.io.HttpClientConnectionManager;
|
||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.concurrent.Cancellable;
|
import org.apache.hc.core5.concurrent.Cancellable;
|
||||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,26 +45,25 @@
|
|||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
|
@Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
|
||||||
class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable {
|
class EndpointHolder implements Cancellable, Closeable {
|
||||||
|
|
||||||
private final Logger log;
|
private final Logger log;
|
||||||
|
|
||||||
private final HttpClientConnectionManager manager;
|
private final HttpClientConnectionManager manager;
|
||||||
private final HttpClientConnection managedConn;
|
private final ConnectionEndpoint endpoint;
|
||||||
private final AtomicBoolean released;
|
private final AtomicBoolean released;
|
||||||
private volatile boolean reusable;
|
private volatile boolean reusable;
|
||||||
private volatile Object state;
|
private volatile Object state;
|
||||||
private volatile long validDuration;
|
private volatile long validDuration;
|
||||||
private volatile TimeUnit tunit;
|
|
||||||
|
|
||||||
public ConnectionHolder(
|
public EndpointHolder(
|
||||||
final Logger log,
|
final Logger log,
|
||||||
final HttpClientConnectionManager manager,
|
final HttpClientConnectionManager manager,
|
||||||
final HttpClientConnection managedConn) {
|
final ConnectionEndpoint endpoint) {
|
||||||
super();
|
super();
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.managedConn = managedConn;
|
this.endpoint = endpoint;
|
||||||
this.released = new AtomicBoolean(false);
|
this.released = new AtomicBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,54 +84,46 @@ public void setState(final Object state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setValidFor(final long duration, final TimeUnit tunit) {
|
public void setValidFor(final long duration, final TimeUnit tunit) {
|
||||||
synchronized (this.managedConn) {
|
this.validDuration = (tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(duration);
|
||||||
this.validDuration = duration;
|
|
||||||
this.tunit = tunit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void releaseConnection(final boolean reusable) {
|
private void releaseConnection(final boolean reusable) {
|
||||||
if (this.released.compareAndSet(false, true)) {
|
if (this.released.compareAndSet(false, true)) {
|
||||||
synchronized (this.managedConn) {
|
synchronized (this.endpoint) {
|
||||||
if (reusable) {
|
if (reusable) {
|
||||||
this.manager.releaseConnection(this.managedConn,
|
this.manager.release(this.endpoint, this.state, this.validDuration, TimeUnit.MILLISECONDS);
|
||||||
this.state, this.validDuration, this.tunit);
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
this.managedConn.close();
|
this.endpoint.close();
|
||||||
log.debug("Connection discarded");
|
log.debug("Connection discarded");
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
if (this.log.isDebugEnabled()) {
|
if (this.log.isDebugEnabled()) {
|
||||||
this.log.debug(ex.getMessage(), ex);
|
this.log.debug(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.manager.releaseConnection(
|
this.manager.release(this.endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void releaseConnection() {
|
public void releaseConnection() {
|
||||||
releaseConnection(this.reusable);
|
releaseConnection(this.reusable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void abortConnection() {
|
public void abortConnection() {
|
||||||
if (this.released.compareAndSet(false, true)) {
|
if (this.released.compareAndSet(false, true)) {
|
||||||
synchronized (this.managedConn) {
|
synchronized (this.endpoint) {
|
||||||
try {
|
try {
|
||||||
this.managedConn.shutdown();
|
this.endpoint.shutdown();
|
||||||
log.debug("Connection discarded");
|
log.debug("Connection discarded");
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
if (this.log.isDebugEnabled()) {
|
if (this.log.isDebugEnabled()) {
|
||||||
this.log.debug(ex.getMessage(), ex);
|
this.log.debug(ex.getMessage(), ex);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.manager.releaseConnection(
|
this.manager.release(this.endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -99,7 +99,7 @@
|
|||||||
import org.apache.hc.core5.http.protocol.RequestContent;
|
import org.apache.hc.core5.http.protocol.RequestContent;
|
||||||
import org.apache.hc.core5.http.protocol.RequestTargetHost;
|
import org.apache.hc.core5.http.protocol.RequestTargetHost;
|
||||||
import org.apache.hc.core5.http.protocol.RequestUserAgent;
|
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;
|
import org.apache.hc.core5.util.VersionInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -547,14 +547,11 @@ public final HttpClientBuilder useSystemProperties() {
|
|||||||
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
|
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
|
||||||
* to stop and release the background thread.
|
* to stop and release the background thread.
|
||||||
* <p>
|
* <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.
|
* 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 #setConnectionManagerShared(boolean)
|
||||||
* @see HttpClientConnectionManager#closeExpired()
|
* @see ConnPoolControl#closeExpired()
|
||||||
*
|
*
|
||||||
* @since 4.4
|
* @since 4.4
|
||||||
*/
|
*/
|
||||||
@ -570,14 +567,11 @@ public final HttpClientBuilder evictExpiredConnections() {
|
|||||||
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
|
* One MUST explicitly close HttpClient with {@link CloseableHttpClient#close()} in order
|
||||||
* to stop and release the background thread.
|
* to stop and release the background thread.
|
||||||
* <p>
|
* <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.
|
* 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 #setConnectionManagerShared(boolean)
|
||||||
* @see HttpClientConnectionManager#closeExpired()
|
* @see ConnPoolControl#closeIdle(long, TimeUnit)
|
||||||
*
|
*
|
||||||
* @param maxIdleTime maximum time persistent connections can stay idle while kept alive
|
* @param maxIdleTime maximum time persistent connections can stay idle while kept alive
|
||||||
* in the connection pool. Connections whose inactivity period exceeds this value will
|
* in the connection pool. Connections whose inactivity period exceeds this value will
|
||||||
@ -652,13 +646,6 @@ protected void addCloseable(final Closeable closeable) {
|
|||||||
closeables.add(closeable);
|
closeables.add(closeable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] split(final String s) {
|
|
||||||
if (TextUtils.isBlank(s)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return s.split(" *, *");
|
|
||||||
}
|
|
||||||
|
|
||||||
public CloseableHttpClient build() {
|
public CloseableHttpClient build() {
|
||||||
// Create main request executor
|
// Create main request executor
|
||||||
// We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
|
// We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
|
||||||
@ -873,10 +860,9 @@ public boolean keepAlive(
|
|||||||
if (closeablesCopy == null) {
|
if (closeablesCopy == null) {
|
||||||
closeablesCopy = new ArrayList<>(1);
|
closeablesCopy = new ArrayList<>(1);
|
||||||
}
|
}
|
||||||
final HttpClientConnectionManager cm = connManagerCopy;
|
|
||||||
|
|
||||||
if (evictExpiredConnections || evictIdleConnections) {
|
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);
|
maxIdleTime > 0 ? maxIdleTime : 10, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS);
|
||||||
closeablesCopy.add(new Closeable() {
|
closeablesCopy.add(new Closeable() {
|
||||||
|
|
||||||
@ -888,19 +874,12 @@ public void close() throws IOException {
|
|||||||
});
|
});
|
||||||
connectionEvictor.start();
|
connectionEvictor.start();
|
||||||
}
|
}
|
||||||
closeablesCopy.add(new Closeable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException {
|
|
||||||
cm.shutdown();
|
|
||||||
}
|
}
|
||||||
|
closeablesCopy.add(connManagerCopy);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InternalHttpClient(
|
return new InternalHttpClient(
|
||||||
execChain,
|
execChain,
|
||||||
connManagerCopy,
|
|
||||||
routePlannerCopy,
|
routePlannerCopy,
|
||||||
cookieSpecRegistryCopy,
|
cookieSpecRegistryCopy,
|
||||||
authSchemeRegistryCopy,
|
authSchemeRegistryCopy,
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
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;
|
import org.apache.hc.core5.util.Args;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,7 +42,6 @@
|
|||||||
*/
|
*/
|
||||||
public final class IdleConnectionEvictor {
|
public final class IdleConnectionEvictor {
|
||||||
|
|
||||||
private final HttpClientConnectionManager connectionManager;
|
|
||||||
private final ThreadFactory threadFactory;
|
private final ThreadFactory threadFactory;
|
||||||
private final Thread thread;
|
private final Thread thread;
|
||||||
private final long sleepTimeMs;
|
private final long sleepTimeMs;
|
||||||
@ -50,12 +50,12 @@ public final class IdleConnectionEvictor {
|
|||||||
private volatile Exception exception;
|
private volatile Exception exception;
|
||||||
|
|
||||||
public IdleConnectionEvictor(
|
public IdleConnectionEvictor(
|
||||||
final HttpClientConnectionManager connectionManager,
|
final ConnPoolControl<?> connectionManager,
|
||||||
final ThreadFactory threadFactory,
|
final ThreadFactory threadFactory,
|
||||||
final long sleepTime, final TimeUnit sleepTimeUnit,
|
final long sleepTime, final TimeUnit sleepTimeUnit,
|
||||||
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
||||||
this.connectionManager = Args.notNull(connectionManager, "Connection manager");
|
Args.notNull(connectionManager, "Connection manager");
|
||||||
this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory();
|
this.threadFactory = threadFactory != null ? threadFactory : new DefaultThreadFactory("idle-connection-evictor", true);
|
||||||
this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
|
this.sleepTimeMs = sleepTimeUnit != null ? sleepTimeUnit.toMillis(sleepTime) : sleepTime;
|
||||||
this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;
|
this.maxIdleTimeMs = maxIdleTimeUnit != null ? maxIdleTimeUnit.toMillis(maxIdleTime) : maxIdleTime;
|
||||||
this.thread = this.threadFactory.newThread(new Runnable() {
|
this.thread = this.threadFactory.newThread(new Runnable() {
|
||||||
@ -78,14 +78,14 @@ public void run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IdleConnectionEvictor(
|
public IdleConnectionEvictor(
|
||||||
final HttpClientConnectionManager connectionManager,
|
final ConnPoolControl<?> connectionManager,
|
||||||
final long sleepTime, final TimeUnit sleepTimeUnit,
|
final long sleepTime, final TimeUnit sleepTimeUnit,
|
||||||
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
||||||
this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);
|
this(connectionManager, null, sleepTime, sleepTimeUnit, maxIdleTime, maxIdleTimeUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IdleConnectionEvictor(
|
public IdleConnectionEvictor(
|
||||||
final HttpClientConnectionManager connectionManager,
|
final ConnPoolControl<?> connectionManager,
|
||||||
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
final long maxIdleTime, final TimeUnit maxIdleTimeUnit) {
|
||||||
this(connectionManager, null,
|
this(connectionManager, null,
|
||||||
maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,
|
maxIdleTime > 0 ? maxIdleTime : 5, maxIdleTimeUnit != null ? maxIdleTimeUnit : TimeUnit.SECONDS,
|
||||||
@ -108,16 +108,4 @@ public void awaitTermination(final long time, final TimeUnit tunit) throws Inter
|
|||||||
thread.join((tunit != null ? tunit : TimeUnit.MILLISECONDS).toMillis(time));
|
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.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
|
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
|
||||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
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.Configurable;
|
||||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
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 Logger log = LogManager.getLogger(getClass());
|
||||||
|
|
||||||
private final ClientExecChain execChain;
|
private final ClientExecChain execChain;
|
||||||
private final HttpClientConnectionManager connManager;
|
|
||||||
private final HttpRoutePlanner routePlanner;
|
private final HttpRoutePlanner routePlanner;
|
||||||
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
|
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
|
||||||
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
|
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
|
||||||
@ -81,7 +79,6 @@ class InternalHttpClient extends CloseableHttpClient implements Configurable {
|
|||||||
|
|
||||||
public InternalHttpClient(
|
public InternalHttpClient(
|
||||||
final ClientExecChain execChain,
|
final ClientExecChain execChain,
|
||||||
final HttpClientConnectionManager connManager,
|
|
||||||
final HttpRoutePlanner routePlanner,
|
final HttpRoutePlanner routePlanner,
|
||||||
final Lookup<CookieSpecProvider> cookieSpecRegistry,
|
final Lookup<CookieSpecProvider> cookieSpecRegistry,
|
||||||
final Lookup<AuthSchemeProvider> authSchemeRegistry,
|
final Lookup<AuthSchemeProvider> authSchemeRegistry,
|
||||||
@ -91,10 +88,8 @@ public InternalHttpClient(
|
|||||||
final List<Closeable> closeables) {
|
final List<Closeable> closeables) {
|
||||||
super();
|
super();
|
||||||
Args.notNull(execChain, "HTTP client exec chain");
|
Args.notNull(execChain, "HTTP client exec chain");
|
||||||
Args.notNull(connManager, "HTTP connection manager");
|
|
||||||
Args.notNull(routePlanner, "HTTP route planner");
|
Args.notNull(routePlanner, "HTTP route planner");
|
||||||
this.execChain = execChain;
|
this.execChain = execChain;
|
||||||
this.connManager = connManager;
|
|
||||||
this.routePlanner = routePlanner;
|
this.routePlanner = routePlanner;
|
||||||
this.cookieSpecRegistry = cookieSpecRegistry;
|
this.cookieSpecRegistry = cookieSpecRegistry;
|
||||||
this.authSchemeRegistry = authSchemeRegistry;
|
this.authSchemeRegistry = authSchemeRegistry;
|
||||||
@ -105,10 +100,11 @@ public InternalHttpClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private HttpRoute determineRoute(
|
private HttpRoute determineRoute(
|
||||||
final HttpHost target,
|
final HttpHost host,
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpContext context) throws HttpException {
|
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) {
|
private void setupContext(final HttpClientContext context) {
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
@ -39,10 +40,11 @@
|
|||||||
import org.apache.hc.client5.http.auth.ChallengeType;
|
import org.apache.hc.client5.http.auth.ChallengeType;
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
|
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.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.HttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||||
import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
|
import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
|
||||||
@ -54,6 +56,7 @@
|
|||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
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.ConnectionReuseStrategy;
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.hc.core5.http.HttpException;
|
import org.apache.hc.core5.http.HttpException;
|
||||||
@ -64,7 +67,6 @@
|
|||||||
import org.apache.hc.core5.http.HttpStatus;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.apache.hc.core5.http.HttpVersion;
|
import org.apache.hc.core5.http.HttpVersion;
|
||||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
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.BufferedHttpEntity;
|
||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||||
@ -162,22 +164,24 @@ public ClassicHttpResponse execute(
|
|||||||
|
|
||||||
Object userToken = context.getUserToken();
|
Object userToken = context.getUserToken();
|
||||||
|
|
||||||
final ConnectionRequest connRequest = connManager.requestConnection(route, userToken);
|
final LeaseRequest leaseRequest = connManager.lease(route, userToken);
|
||||||
if (execAware != null) {
|
if (execAware != null) {
|
||||||
if (execAware.isAborted()) {
|
if (execAware.isAborted()) {
|
||||||
connRequest.cancel();
|
leaseRequest.cancel();
|
||||||
throw new RequestAbortedException("Request aborted");
|
throw new RequestAbortedException("Request aborted");
|
||||||
} else {
|
} else {
|
||||||
execAware.setCancellable(connRequest);
|
execAware.setCancellable(leaseRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final RequestConfig config = context.getRequestConfig();
|
final RequestConfig config = context.getRequestConfig();
|
||||||
|
|
||||||
final HttpClientConnection managedConn;
|
final ConnectionEndpoint endpoint;
|
||||||
try {
|
try {
|
||||||
final int timeout = config.getConnectionRequestTimeout();
|
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) {
|
} catch(final InterruptedException interrupted) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new RequestAbortedException("Request aborted", interrupted);
|
throw new RequestAbortedException("Request aborted", interrupted);
|
||||||
@ -189,12 +193,12 @@ public ClassicHttpResponse execute(
|
|||||||
throw new RequestAbortedException("Request execution failed", cause);
|
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 {
|
try {
|
||||||
if (execAware != null) {
|
if (execAware != null) {
|
||||||
execAware.setCancellable(connHolder);
|
execAware.setCancellable(endpointHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
final AuthExchange targetAuthExchange = context.getAuthExchange(route.getTargetHost());
|
final AuthExchange targetAuthExchange = context.getAuthExchange(route.getTargetHost());
|
||||||
@ -213,10 +217,12 @@ public ClassicHttpResponse execute(
|
|||||||
throw new RequestAbortedException("Request aborted");
|
throw new RequestAbortedException("Request aborted");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!managedConn.isOpen()) {
|
if (!endpoint.isConnected()) {
|
||||||
|
endpointHolder.markNonReusable();
|
||||||
this.log.debug("Opening connection " + route);
|
this.log.debug("Opening connection " + route);
|
||||||
try {
|
try {
|
||||||
establishRoute(managedConn, route, request, context);
|
establishRoute(endpoint, route, request, context);
|
||||||
|
endpointHolder.markReusable();
|
||||||
} catch (final TunnelRefusedException ex) {
|
} catch (final TunnelRefusedException ex) {
|
||||||
if (this.log.isDebugEnabled()) {
|
if (this.log.isDebugEnabled()) {
|
||||||
this.log.debug(ex.getMessage());
|
this.log.debug(ex.getMessage());
|
||||||
@ -227,7 +233,7 @@ public ClassicHttpResponse execute(
|
|||||||
}
|
}
|
||||||
final int timeout = config.getSocketTimeout();
|
final int timeout = config.getSocketTimeout();
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
managedConn.setSocketTimeout(timeout);
|
endpoint.setSocketTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (execAware != null && execAware.isAborted()) {
|
if (execAware != null && execAware.isAborted()) {
|
||||||
@ -253,7 +259,7 @@ public ClassicHttpResponse execute(
|
|||||||
route.getProxyHost(), ChallengeType.PROXY, request, proxyAuthExchange, context);
|
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.
|
// The connection is in or can be brought to a re-usable state.
|
||||||
if (reuseStrategy.keepAlive(request, response, context)) {
|
if (reuseStrategy.keepAlive(request, response, context)) {
|
||||||
@ -268,10 +274,10 @@ public ClassicHttpResponse execute(
|
|||||||
}
|
}
|
||||||
this.log.debug("Connection can be kept alive " + s);
|
this.log.debug("Connection can be kept alive " + s);
|
||||||
}
|
}
|
||||||
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
endpointHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
||||||
connHolder.markReusable();
|
endpointHolder.markReusable();
|
||||||
} else {
|
} else {
|
||||||
connHolder.markNonReusable();
|
endpointHolder.markNonReusable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.getMethod().equalsIgnoreCase("TRACE")) {
|
if (request.getMethod().equalsIgnoreCase("TRACE")) {
|
||||||
@ -283,10 +289,10 @@ public ClassicHttpResponse execute(
|
|||||||
targetAuthExchange, proxyAuthExchange, route, request, response, context)) {
|
targetAuthExchange, proxyAuthExchange, route, request, response, context)) {
|
||||||
// Make sure the response body is fully consumed, if present
|
// Make sure the response body is fully consumed, if present
|
||||||
final HttpEntity entity = response.getEntity();
|
final HttpEntity entity = response.getEntity();
|
||||||
if (connHolder.isReusable()) {
|
if (endpointHolder.isReusable()) {
|
||||||
EntityUtils.consume(entity);
|
EntityUtils.consume(entity);
|
||||||
} else {
|
} else {
|
||||||
managedConn.close();
|
endpoint.close();
|
||||||
if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
|
if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
|
||||||
&& proxyAuthExchange.getAuthScheme() != null
|
&& proxyAuthExchange.getAuthScheme() != null
|
||||||
&& proxyAuthExchange.getAuthScheme().isConnectionBased()) {
|
&& proxyAuthExchange.getAuthScheme().isConnectionBased()) {
|
||||||
@ -318,18 +324,18 @@ public ClassicHttpResponse execute(
|
|||||||
context.setAttribute(HttpClientContext.USER_TOKEN, userToken);
|
context.setAttribute(HttpClientContext.USER_TOKEN, userToken);
|
||||||
}
|
}
|
||||||
if (userToken != null) {
|
if (userToken != null) {
|
||||||
connHolder.setState(userToken);
|
endpointHolder.setState(userToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for entity, release connection if possible
|
// check for entity, release connection if possible
|
||||||
final HttpEntity entity = response.getEntity();
|
final HttpEntity entity = response.getEntity();
|
||||||
if (entity == null || !entity.isStreaming()) {
|
if (entity == null || !entity.isStreaming()) {
|
||||||
// connection not needed and (assumed to be) in re-usable state
|
// connection not needed and (assumed to be) in re-usable state
|
||||||
connHolder.releaseConnection();
|
endpointHolder.releaseConnection();
|
||||||
return new CloseableHttpResponse(response, null);
|
return new CloseableHttpResponse(response, null);
|
||||||
} else {
|
} else {
|
||||||
ResponseEntityProxy.enchance(response, connHolder);
|
ResponseEntityProxy.enchance(response, endpointHolder);
|
||||||
return new CloseableHttpResponse(response, connHolder);
|
return new CloseableHttpResponse(response, endpointHolder);
|
||||||
}
|
}
|
||||||
} catch (final ConnectionShutdownException ex) {
|
} catch (final ConnectionShutdownException ex) {
|
||||||
final InterruptedIOException ioex = new InterruptedIOException(
|
final InterruptedIOException ioex = new InterruptedIOException(
|
||||||
@ -337,7 +343,7 @@ public ClassicHttpResponse execute(
|
|||||||
ioex.initCause(ex);
|
ioex.initCause(ex);
|
||||||
throw ioex;
|
throw ioex;
|
||||||
} catch (final HttpException | RuntimeException | IOException ex) {
|
} catch (final HttpException | RuntimeException | IOException ex) {
|
||||||
connHolder.abortConnection();
|
endpointHolder.abortConnection();
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,7 +352,7 @@ public ClassicHttpResponse execute(
|
|||||||
* Establishes the target route.
|
* Establishes the target route.
|
||||||
*/
|
*/
|
||||||
void establishRoute(
|
void establishRoute(
|
||||||
final HttpClientConnection managedConn,
|
final ConnectionEndpoint endpoint,
|
||||||
final HttpRoute route,
|
final HttpRoute route,
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpClientContext context) throws HttpException, IOException {
|
final HttpClientContext context) throws HttpException, IOException {
|
||||||
@ -362,23 +368,23 @@ void establishRoute(
|
|||||||
|
|
||||||
case HttpRouteDirector.CONNECT_TARGET:
|
case HttpRouteDirector.CONNECT_TARGET:
|
||||||
this.connManager.connect(
|
this.connManager.connect(
|
||||||
managedConn,
|
endpoint,
|
||||||
route,
|
|
||||||
timeout > 0 ? timeout : 0,
|
timeout > 0 ? timeout : 0,
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
context);
|
context);
|
||||||
tracker.connectTarget(route.isSecure());
|
tracker.connectTarget(route.isSecure());
|
||||||
break;
|
break;
|
||||||
case HttpRouteDirector.CONNECT_PROXY:
|
case HttpRouteDirector.CONNECT_PROXY:
|
||||||
this.connManager.connect(
|
this.connManager.connect(
|
||||||
managedConn,
|
endpoint,
|
||||||
route,
|
|
||||||
timeout > 0 ? timeout : 0,
|
timeout > 0 ? timeout : 0,
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
context);
|
context);
|
||||||
final HttpHost proxy = route.getProxyHost();
|
final HttpHost proxy = route.getProxyHost();
|
||||||
tracker.connectProxy(proxy, false);
|
tracker.connectProxy(proxy, false);
|
||||||
break;
|
break;
|
||||||
case HttpRouteDirector.TUNNEL_TARGET: {
|
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.");
|
this.log.debug("Tunnel to target created.");
|
||||||
tracker.tunnelTarget(secure);
|
tracker.tunnelTarget(secure);
|
||||||
} break;
|
} break;
|
||||||
@ -395,7 +401,7 @@ void establishRoute(
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case HttpRouteDirector.LAYER_PROTOCOL:
|
case HttpRouteDirector.LAYER_PROTOCOL:
|
||||||
this.connManager.upgrade(managedConn, route, context);
|
this.connManager.upgrade(endpoint, context);
|
||||||
tracker.layerProtocol(route.isSecure());
|
tracker.layerProtocol(route.isSecure());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -403,7 +409,6 @@ void establishRoute(
|
|||||||
throw new HttpException("Unable to establish route: " +
|
throw new HttpException("Unable to establish route: " +
|
||||||
"planned = " + route + "; current = " + fact);
|
"planned = " + route + "; current = " + fact);
|
||||||
case HttpRouteDirector.COMPLETE:
|
case HttpRouteDirector.COMPLETE:
|
||||||
this.connManager.routeComplete(managedConn, route, context);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unknown step indicator "
|
throw new IllegalStateException("Unknown step indicator "
|
||||||
@ -422,7 +427,7 @@ void establishRoute(
|
|||||||
* information about the tunnel, that is left to the caller.
|
* information about the tunnel, that is left to the caller.
|
||||||
*/
|
*/
|
||||||
private boolean createTunnelToTarget(
|
private boolean createTunnelToTarget(
|
||||||
final HttpClientConnection managedConn,
|
final ConnectionEndpoint endpoint,
|
||||||
final HttpRoute route,
|
final HttpRoute route,
|
||||||
final HttpRequest request,
|
final HttpRequest request,
|
||||||
final HttpClientContext context) throws HttpException, IOException {
|
final HttpClientContext context) throws HttpException, IOException {
|
||||||
@ -442,18 +447,18 @@ private boolean createTunnelToTarget(
|
|||||||
this.requestExecutor.preProcess(connect, this.proxyHttpProcessor, context);
|
this.requestExecutor.preProcess(connect, this.proxyHttpProcessor, context);
|
||||||
|
|
||||||
while (response == null) {
|
while (response == null) {
|
||||||
if (!managedConn.isOpen()) {
|
if (!endpoint.isConnected()) {
|
||||||
this.connManager.connect(
|
this.connManager.connect(
|
||||||
managedConn,
|
endpoint,
|
||||||
route,
|
|
||||||
timeout > 0 ? timeout : 0,
|
timeout > 0 ? timeout : 0,
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
|
connect.removeHeaders(HttpHeaders.PROXY_AUTHORIZATION);
|
||||||
this.authenticator.addAuthResponse(proxy, ChallengeType.PROXY, connect, proxyAuthExchange, context);
|
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();
|
final int status = response.getCode();
|
||||||
if (status < HttpStatus.SC_SUCCESS) {
|
if (status < HttpStatus.SC_SUCCESS) {
|
||||||
@ -472,7 +477,7 @@ private boolean createTunnelToTarget(
|
|||||||
final HttpEntity entity = response.getEntity();
|
final HttpEntity entity = response.getEntity();
|
||||||
EntityUtils.consume(entity);
|
EntityUtils.consume(entity);
|
||||||
} else {
|
} else {
|
||||||
managedConn.close();
|
endpoint.close();
|
||||||
}
|
}
|
||||||
response = null;
|
response = null;
|
||||||
}
|
}
|
||||||
@ -489,7 +494,7 @@ private boolean createTunnelToTarget(
|
|||||||
response.setEntity(new BufferedHttpEntity(entity));
|
response.setEntity(new BufferedHttpEntity(entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
managedConn.close();
|
endpoint.close();
|
||||||
throw new TunnelRefusedException("CONNECT refused by proxy: " +
|
throw new TunnelRefusedException("CONNECT refused by proxy: " +
|
||||||
new StatusLine(response), response);
|
new StatusLine(response), response);
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,16 @@
|
|||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
|
||||||
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.HttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
@ -45,11 +48,12 @@
|
|||||||
import org.apache.hc.core5.annotation.Contract;
|
import org.apache.hc.core5.annotation.Contract;
|
||||||
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
import org.apache.hc.core5.annotation.ThreadingBehavior;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
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.ConnectionReuseStrategy;
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.hc.core5.http.HttpException;
|
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.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.DefaultHttpProcessor;
|
||||||
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
||||||
import org.apache.hc.core5.http.protocol.HttpProcessor;
|
import org.apache.hc.core5.http.protocol.HttpProcessor;
|
||||||
@ -86,20 +90,16 @@ public MinimalClientExec(
|
|||||||
final HttpClientConnectionManager connManager,
|
final HttpClientConnectionManager connManager,
|
||||||
final ConnectionReuseStrategy reuseStrategy,
|
final ConnectionReuseStrategy reuseStrategy,
|
||||||
final ConnectionKeepAliveStrategy keepAliveStrategy) {
|
final ConnectionKeepAliveStrategy keepAliveStrategy) {
|
||||||
Args.notNull(requestExecutor, "HTTP request executor");
|
this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
|
||||||
Args.notNull(connManager, "Client connection manager");
|
this.connManager = Args.notNull(connManager, "Connection manager");
|
||||||
Args.notNull(reuseStrategy, "Connection reuse strategy");
|
this.reuseStrategy = reuseStrategy != null ? reuseStrategy : DefaultConnectionReuseStrategy.INSTANCE;
|
||||||
Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
|
this.keepAliveStrategy = keepAliveStrategy != null ? keepAliveStrategy : DefaultConnectionKeepAliveStrategy.INSTANCE;
|
||||||
this.httpProcessor = new DefaultHttpProcessor(
|
this.httpProcessor = new DefaultHttpProcessor(
|
||||||
new RequestContent(),
|
new RequestContent(),
|
||||||
new RequestTargetHost(),
|
new RequestTargetHost(),
|
||||||
new RequestClientConnControl(),
|
new RequestClientConnControl(),
|
||||||
new RequestUserAgent(VersionInfo.getSoftwareInfo(
|
new RequestUserAgent(VersionInfo.getSoftwareInfo(
|
||||||
"Apache-HttpClient", "org.apache.hc.client5", getClass())));
|
"Apache-HttpClient", "org.apache.hc.client5", getClass())));
|
||||||
this.requestExecutor = requestExecutor;
|
|
||||||
this.connManager = connManager;
|
|
||||||
this.reuseStrategy = reuseStrategy;
|
|
||||||
this.keepAliveStrategy = keepAliveStrategy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -111,7 +111,7 @@ public ClassicHttpResponse execute(
|
|||||||
Args.notNull(context, "HTTP context");
|
Args.notNull(context, "HTTP context");
|
||||||
|
|
||||||
final HttpRoute route = request.getRoute();
|
final HttpRoute route = request.getRoute();
|
||||||
final ConnectionRequest connRequest = connManager.requestConnection(route, null);
|
final LeaseRequest connRequest = connManager.lease(route, null);
|
||||||
if (execAware != null) {
|
if (execAware != null) {
|
||||||
if (execAware.isAborted()) {
|
if (execAware.isAborted()) {
|
||||||
connRequest.cancel();
|
connRequest.cancel();
|
||||||
@ -122,10 +122,12 @@ public ClassicHttpResponse execute(
|
|||||||
|
|
||||||
final RequestConfig config = context.getRequestConfig();
|
final RequestConfig config = context.getRequestConfig();
|
||||||
|
|
||||||
final HttpClientConnection managedConn;
|
final ConnectionEndpoint endpoint;
|
||||||
try {
|
try {
|
||||||
final int timeout = config.getConnectionRequestTimeout();
|
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) {
|
} catch(final InterruptedException interrupted) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new RequestAbortedException("Request aborted", interrupted);
|
throw new RequestAbortedException("Request aborted", interrupted);
|
||||||
@ -137,57 +139,54 @@ public ClassicHttpResponse execute(
|
|||||||
throw new RequestAbortedException("Request execution failed", cause);
|
throw new RequestAbortedException("Request execution failed", cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ConnectionHolder connHolder = new ConnectionHolder(log, connManager, managedConn);
|
final EndpointHolder endpointHolder = new EndpointHolder(log, connManager, endpoint);
|
||||||
try {
|
try {
|
||||||
if (execAware != null) {
|
if (execAware != null) {
|
||||||
if (execAware.isAborted()) {
|
if (execAware.isAborted()) {
|
||||||
connHolder.close();
|
endpointHolder.close();
|
||||||
throw new RequestAbortedException("Request aborted");
|
throw new RequestAbortedException("Request aborted");
|
||||||
}
|
}
|
||||||
execAware.setCancellable(connHolder);
|
execAware.setCancellable(endpointHolder);
|
||||||
}
|
}
|
||||||
|
if (!endpoint.isConnected()) {
|
||||||
if (!managedConn.isOpen()) {
|
|
||||||
final int timeout = config.getConnectTimeout();
|
final int timeout = config.getConnectTimeout();
|
||||||
this.connManager.connect(
|
this.connManager.connect(
|
||||||
managedConn,
|
endpoint,
|
||||||
route,
|
|
||||||
timeout > 0 ? timeout : 0,
|
timeout > 0 ? timeout : 0,
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
context);
|
context);
|
||||||
this.connManager.routeComplete(managedConn, route, context);
|
|
||||||
}
|
}
|
||||||
final int timeout = config.getSocketTimeout();
|
final int timeout = config.getSocketTimeout();
|
||||||
if (timeout >= 0) {
|
if (timeout >= 0) {
|
||||||
managedConn.setSocketTimeout(timeout);
|
endpoint.setSocketTimeout(timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
|
context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
|
|
||||||
context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
|
context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
|
||||||
|
|
||||||
httpProcessor.process(request, request.getEntity(), context);
|
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);
|
httpProcessor.process(response, response.getEntity(), context);
|
||||||
|
|
||||||
// The connection is in or can be brought to a re-usable state.
|
// The connection is in or can be brought to a re-usable state.
|
||||||
if (reuseStrategy.keepAlive(request, response, context)) {
|
if (reuseStrategy.keepAlive(request, response, context)) {
|
||||||
// Set the idle duration of this connection
|
// Set the idle duration of this connection
|
||||||
final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
|
final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
|
||||||
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
endpointHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
|
||||||
connHolder.markReusable();
|
endpointHolder.markReusable();
|
||||||
} else {
|
} else {
|
||||||
connHolder.markNonReusable();
|
endpointHolder.markNonReusable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for entity, release connection if possible
|
// check for entity, release connection if possible
|
||||||
final HttpEntity entity = response.getEntity();
|
final HttpEntity entity = response.getEntity();
|
||||||
if (entity == null || !entity.isStreaming()) {
|
if (entity == null || !entity.isStreaming()) {
|
||||||
// connection not needed and (assumed to be) in re-usable state
|
// connection not needed and (assumed to be) in re-usable state
|
||||||
connHolder.releaseConnection();
|
endpointHolder.releaseConnection();
|
||||||
return new CloseableHttpResponse(response, null);
|
return new CloseableHttpResponse(response, null);
|
||||||
} else {
|
} else {
|
||||||
ResponseEntityProxy.enchance(response, connHolder);
|
ResponseEntityProxy.enchance(response, endpointHolder);
|
||||||
return new CloseableHttpResponse(response, connHolder);
|
return new CloseableHttpResponse(response, endpointHolder);
|
||||||
}
|
}
|
||||||
} catch (final ConnectionShutdownException ex) {
|
} catch (final ConnectionShutdownException ex) {
|
||||||
final InterruptedIOException ioex = new InterruptedIOException(
|
final InterruptedIOException ioex = new InterruptedIOException(
|
||||||
@ -195,7 +194,7 @@ public ClassicHttpResponse execute(
|
|||||||
ioex.initCause(ex);
|
ioex.initCause(ex);
|
||||||
throw ioex;
|
throw ioex;
|
||||||
} catch (final HttpException | RuntimeException | IOException ex) {
|
} catch (final HttpException | RuntimeException | IOException ex) {
|
||||||
connHolder.abortConnection();
|
endpointHolder.abortConnection();
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,8 +110,8 @@ protected CloseableHttpResponse doExecute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() throws IOException {
|
||||||
this.connManager.shutdown();
|
this.connManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.HttpConnectionFactory;
|
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.RouteInfo.LayerType;
|
import org.apache.hc.client5.http.RouteInfo.LayerType;
|
||||||
import org.apache.hc.client5.http.RouteInfo.TunnelType;
|
import org.apache.hc.client5.http.RouteInfo.TunnelType;
|
||||||
@ -66,6 +65,7 @@
|
|||||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||||
import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
|
import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
|
||||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
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.BufferedHttpEntity;
|
||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
|
||||||
@ -83,7 +83,7 @@
|
|||||||
*/
|
*/
|
||||||
public class ProxyClient {
|
public class ProxyClient {
|
||||||
|
|
||||||
private final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
private final HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||||
private final ConnectionConfig connectionConfig;
|
private final ConnectionConfig connectionConfig;
|
||||||
private final RequestConfig requestConfig;
|
private final RequestConfig requestConfig;
|
||||||
private final HttpProcessor httpProcessor;
|
private final HttpProcessor httpProcessor;
|
||||||
@ -98,7 +98,7 @@ public class ProxyClient {
|
|||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
public ProxyClient(
|
public ProxyClient(
|
||||||
final HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory,
|
final HttpConnectionFactory<ManagedHttpClientConnection> connFactory,
|
||||||
final ConnectionConfig connectionConfig,
|
final ConnectionConfig connectionConfig,
|
||||||
final RequestConfig requestConfig) {
|
final RequestConfig requestConfig) {
|
||||||
super();
|
super();
|
||||||
@ -148,8 +148,7 @@ public Socket tunnel(
|
|||||||
this.requestConfig.getLocalAddress(),
|
this.requestConfig.getLocalAddress(),
|
||||||
proxy, false, TunnelType.TUNNELLED, LayerType.PLAIN);
|
proxy, false, TunnelType.TUNNELLED, LayerType.PLAIN);
|
||||||
|
|
||||||
final ManagedHttpClientConnection conn = this.connFactory.create(
|
final ManagedHttpClientConnection conn = this.connFactory.createConnection(null);
|
||||||
route, this.connectionConfig);
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
final HttpContext context = new BasicHttpContext();
|
||||||
ClassicHttpResponse response;
|
ClassicHttpResponse response;
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ public ClassicHttpResponse execute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
currentRoute = this.routePlanner.determineRoute(newTarget, redirect, context);
|
currentRoute = this.routePlanner.determineRoute(newTarget, context);
|
||||||
if (this.log.isDebugEnabled()) {
|
if (this.log.isDebugEnabled()) {
|
||||||
this.log.debug("Redirecting to '" + redirectUri + "' via " + currentRoute);
|
this.log.debug("Redirecting to '" + redirectUri + "' via " + currentRoute);
|
||||||
}
|
}
|
||||||
|
@ -45,35 +45,35 @@
|
|||||||
*/
|
*/
|
||||||
class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher {
|
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();
|
final HttpEntity entity = response.getEntity();
|
||||||
if (entity != null && entity.isStreaming() && connHolder != null) {
|
if (entity != null && entity.isStreaming() && connHolder != null) {
|
||||||
response.setEntity(new ResponseEntityProxy(entity, connHolder));
|
response.setEntity(new ResponseEntityProxy(entity, connHolder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseEntityProxy(final HttpEntity entity, final ConnectionHolder connHolder) {
|
ResponseEntityProxy(final HttpEntity entity, final EndpointHolder endpointHolder) {
|
||||||
super(entity);
|
super(entity);
|
||||||
this.connHolder = connHolder;
|
this.endpointHolder = endpointHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanup() throws IOException {
|
private void cleanup() throws IOException {
|
||||||
if (this.connHolder != null) {
|
if (this.endpointHolder != null) {
|
||||||
this.connHolder.close();
|
this.endpointHolder.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void abortConnection() {
|
private void abortConnection() {
|
||||||
if (this.connHolder != null) {
|
if (this.endpointHolder != null) {
|
||||||
this.connHolder.abortConnection();
|
this.endpointHolder.abortConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void releaseConnection() {
|
public void releaseConnection() {
|
||||||
if (this.connHolder != null) {
|
if (this.endpointHolder != null) {
|
||||||
this.connHolder.releaseConnection();
|
this.endpointHolder.releaseConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ public boolean eofDetected(final InputStream wrapped) throws IOException {
|
|||||||
@Override
|
@Override
|
||||||
public boolean streamClosed(final InputStream wrapped) throws IOException {
|
public boolean streamClosed(final InputStream wrapped) throws IOException {
|
||||||
try {
|
try {
|
||||||
final boolean open = connHolder != null && !connHolder.isReleased();
|
final boolean open = endpointHolder != null && !endpointHolder.isReleased();
|
||||||
// this assumes that closing the stream will
|
// this assumes that closing the stream will
|
||||||
// consume the remainder of the response body:
|
// consume the remainder of the response body:
|
||||||
try {
|
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
|
* Client connection endpoint that can be used to execute message exchanges.
|
||||||
* from a connection manager.
|
|
||||||
*
|
*
|
||||||
*
|
* @since 5.0
|
||||||
* @since 4.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;
|
||||||
|
|
||||||
/**
|
public abstract boolean isConnected();
|
||||||
* Creates a ConnectTimeoutException with a {@code null} detail message.
|
|
||||||
*/
|
|
||||||
public ConnectionPoolTimeoutException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public abstract void setSocketTimeout(int timeout);
|
||||||
* Creates a ConnectTimeoutException with the specified detail message.
|
|
||||||
*
|
public abstract void shutdown() throws IOException;
|
||||||
* @param message The exception detail message
|
|
||||||
*/
|
|
||||||
public ConnectionPoolTimeoutException(final String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -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;
|
package org.apache.hc.client5.http.io;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,137 +40,77 @@
|
|||||||
* HTTP connections, manage persistent connections and synchronize access to
|
* HTTP connections, manage persistent connections and synchronize access to
|
||||||
* persistent connections making sure that only one thread of execution can
|
* persistent connections making sure that only one thread of execution can
|
||||||
* have access to a connection at a time.
|
* have access to a connection at a time.
|
||||||
* </p>
|
|
||||||
* <p>
|
* <p>
|
||||||
* Implementations of this interface must be thread-safe. Access to shared
|
* Implementations of this interface must be thread-safe. Access to shared
|
||||||
* data must be synchronized as methods of this interface may be executed
|
* data must be synchronized as methods of this interface may be executed
|
||||||
* from multiple threads.
|
* from multiple threads.
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
public interface HttpClientConnectionManager {
|
public interface HttpClientConnectionManager extends Closeable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new {@link ConnectionRequest}, from which a
|
* Returns a {@link LeaseRequest} object which can be used to obtain
|
||||||
* {@link HttpClientConnection} can be obtained or the request can be
|
* a {@link ConnectionEndpoint} to cancel the request by calling
|
||||||
* aborted.
|
* {@link LeaseRequest#cancel()}.
|
||||||
* <p>
|
* <p>
|
||||||
* Please note that newly allocated connections can be returned
|
* Please note that newly allocated endpoints can be leased
|
||||||
* in the closed state. The consumer of that connection is responsible
|
* {@link ConnectionEndpoint#isConnected() disconnected}. The consumer of the endpoint
|
||||||
* for fully establishing the route the to the connection target
|
* is responsible for fully establishing the route to the endpoint target
|
||||||
* by calling {@link #connect(HttpClientConnection, HttpRoute, int, HttpContext)} connect} in order to connect
|
* by calling {@link #connect(ConnectionEndpoint, long, TimeUnit, HttpContext)}
|
||||||
* directly to the target or to the first proxy hop, optionally calling
|
* in order to connect directly to the target or to the first proxy hop,
|
||||||
* {@link #upgrade(HttpClientConnection, HttpRoute, HttpContext)} upgrade} method to upgrade
|
* and optionally calling {@link #upgrade(ConnectionEndpoint, HttpContext)} method
|
||||||
* the connection after having executed {@code CONNECT} method to
|
* to upgrade the underlying transport to Transport Layer Security after having
|
||||||
* all intermediate proxy hops and and finally calling {@link #routeComplete(HttpClientConnection, HttpRoute,
|
* executed a {@code CONNECT} method to all intermediate proxy hops.
|
||||||
* HttpContext)} routeComplete} to mark the route
|
|
||||||
* as fully completed.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @param route HTTP route of the requested connection.
|
* @param route HTTP route of the requested connection.
|
||||||
* @param state expected state of the connection or {@code null}
|
* @param state expected state of the connection or {@code null}
|
||||||
* if the connection is not expected to carry any state.
|
* 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
|
* re-usable by other consumers. Optionally, the maximum period
|
||||||
* of how long the manager should keep the connection alive can be
|
* of how long the manager should keep the connection alive can be
|
||||||
* defined using {@code validDuration} and {@code timeUnit}
|
* defined using {@code validDuration} and {@code timeUnit}
|
||||||
* parameters.
|
* 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 validDuration the duration of time this connection is valid for reuse.
|
||||||
* @param timeUnit the time unit.
|
* @param timeUnit the time unit.
|
||||||
*
|
*
|
||||||
* @see #closeExpired()
|
* @see #closeExpired()
|
||||||
*/
|
*/
|
||||||
void releaseConnection(
|
void release(ConnectionEndpoint endpoint, Object newState, long validDuration, TimeUnit timeUnit);
|
||||||
HttpClientConnection conn, 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
|
* 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 endpoint the managed endpoint.
|
||||||
* @param route the route of the connection.
|
* @param connectTimeout connect timeout.
|
||||||
* @param connectTimeout connect timeout in milliseconds.
|
* @param timeUnit the time unit.
|
||||||
* @param context the actual HTTP context.
|
* @param context the actual HTTP context.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
void connect(
|
void connect(
|
||||||
HttpClientConnection conn,
|
ConnectionEndpoint endpoint,
|
||||||
HttpRoute route,
|
long connectTimeout,
|
||||||
int connectTimeout,
|
TimeUnit timeUnit,
|
||||||
HttpContext context) throws IOException;
|
HttpContext context) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upgrades the underlying connection socket to TLS/SSL (or another layering
|
* Upgrades the endpoint's underlying transport to Transport Layer Security.
|
||||||
* protocol) after having executed {@code CONNECT} method to all
|
|
||||||
* intermediate proxy hops
|
|
||||||
*
|
*
|
||||||
* @param conn the managed connection.
|
* @param endpoint the managed endpoint.
|
||||||
* @param route the route of the connection.
|
|
||||||
* @param context the actual HTTP context.
|
* @param context the actual HTTP context.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
void upgrade(
|
void upgrade(
|
||||||
HttpClientConnection conn,
|
ConnectionEndpoint endpoint,
|
||||||
HttpRoute route,
|
|
||||||
HttpContext context) throws IOException;
|
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 @@
|
|||||||
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.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.
|
* 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,
|
* This method will block until a connection becomes available,
|
||||||
* the timeout expires, or the connection manager is shut down.
|
* the timeout expires, or the connection manager is shut down.
|
||||||
* Timeouts are handled with millisecond precision.
|
* Timeouts are handled with millisecond precision.
|
||||||
@ -59,12 +58,12 @@ public interface ConnectionRequest extends Cancellable {
|
|||||||
* @return a connection that can be used to communicate
|
* @return a connection that can be used to communicate
|
||||||
* along the given route
|
* along the given route
|
||||||
*
|
*
|
||||||
* @throws ConnectionPoolTimeoutException
|
* @throws TimeoutException
|
||||||
* in case of a timeout
|
* in case of a timeout
|
||||||
* @throws InterruptedException
|
* @throws InterruptedException
|
||||||
* if the calling thread is interrupted while waiting
|
* if the calling thread is interrupted while waiting
|
||||||
*/
|
*/
|
||||||
HttpClientConnection get(long timeout, TimeUnit tunit)
|
ConnectionEndpoint get(long timeout, TimeUnit tunit)
|
||||||
throws InterruptedException, ExecutionException, ConnectionPoolTimeoutException;
|
throws InterruptedException, ExecutionException, TimeoutException;
|
||||||
|
|
||||||
}
|
}
|
@ -44,12 +44,6 @@
|
|||||||
*/
|
*/
|
||||||
public interface ManagedHttpClientConnection extends 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
|
* Binds this connection to the given socket. The connection
|
||||||
* is considered open if it is bound and the underlying socket
|
* is considered open if it is bound and the underlying socket
|
||||||
|
@ -48,13 +48,9 @@
|
|||||||
public interface HttpRoutePlanner {
|
public interface HttpRoutePlanner {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines the route for a request.
|
* Determines the route for the given host.
|
||||||
*
|
*
|
||||||
* @param target the target host for the request.
|
* @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.
|
* @param context the context to use for the subsequent execution.
|
||||||
* Implementations may accept {@code null}.
|
* Implementations may accept {@code null}.
|
||||||
*
|
*
|
||||||
@ -62,8 +58,19 @@ public interface HttpRoutePlanner {
|
|||||||
*
|
*
|
||||||
* @throws HttpException in case of a problem
|
* @throws HttpException in case of a problem
|
||||||
*/
|
*/
|
||||||
HttpRoute determineRoute(HttpHost target,
|
HttpRoute determineRoute(HttpHost target, HttpContext context) throws HttpException;
|
||||||
HttpRequest request,
|
|
||||||
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/>.
|
* <http://www.apache.org/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package org.apache.hc.client5.http;
|
|
||||||
|
|
||||||
import org.apache.hc.core5.http.HttpConnection;
|
package org.apache.hc.client5.http.utils;
|
||||||
import org.apache.hc.core5.http.config.ConnectionConfig;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 void testHttpHostConnectExceptionFromCauseHostAndRemoteAddress() throws E
|
|||||||
Assert.assertEquals("Connect to localhost [/1.2.3.4, /5.6.7.8] refused", ctx.getMessage());
|
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.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.impl.sync.AbstractResponseHandler;
|
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.client5.http.protocol.HttpResponseException;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
import java.io.InputStream;
|
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.client5.http.protocol.HttpResponseException;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
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.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.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.localserver.LocalServerTestBase;
|
||||||
import org.apache.hc.client5.http.methods.HttpGet;
|
import org.apache.hc.client5.http.methods.HttpGet;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
@ -44,13 +45,11 @@
|
|||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.MalformedChunkCodingException;
|
import org.apache.hc.core5.http.MalformedChunkCodingException;
|
||||||
import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnection;
|
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.HttpRequestHandler;
|
||||||
import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
|
import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
|
||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
import org.apache.hc.core5.http.protocol.HttpCoreContext;
|
||||||
import org.apache.hc.core5.pool.PoolStats;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -62,19 +61,18 @@ public void testReleaseOnEntityConsumeContent() throws Exception {
|
|||||||
this.connManager.setMaxTotal(1);
|
this.connManager.setMaxTotal(1);
|
||||||
|
|
||||||
// Zero connections in the pool
|
// Zero connections in the pool
|
||||||
PoolStats stats = this.connManager.getTotalStats();
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(0, stats.getAvailable());
|
|
||||||
|
|
||||||
final HttpHost target = start();
|
final HttpHost target = start();
|
||||||
// Get some random data
|
// Get some random data
|
||||||
final HttpGet httpget = new HttpGet("/random/20000");
|
final HttpGet httpget = new HttpGet("/random/20000");
|
||||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
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 {
|
try {
|
||||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||||
} catch (final ConnectionPoolTimeoutException expected) {
|
} catch (final TimeoutException expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
final HttpEntity e = response.getEntity();
|
final HttpEntity e = response.getEntity();
|
||||||
@ -82,14 +80,13 @@ public void testReleaseOnEntityConsumeContent() throws Exception {
|
|||||||
EntityUtils.consume(e);
|
EntityUtils.consume(e);
|
||||||
|
|
||||||
// Expect one connection in the pool
|
// Expect one connection in the pool
|
||||||
stats = this.connManager.getTotalStats();
|
Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(1, stats.getAvailable());
|
|
||||||
|
|
||||||
// Make sure one connection is available
|
// Make sure one connection is available
|
||||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
this.connManager.releaseConnection(conn, null, -1, null);
|
this.connManager.release(endpoint, null, -1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -98,19 +95,18 @@ public void testReleaseOnEntityWriteTo() throws Exception {
|
|||||||
this.connManager.setMaxTotal(1);
|
this.connManager.setMaxTotal(1);
|
||||||
|
|
||||||
// Zero connections in the pool
|
// Zero connections in the pool
|
||||||
PoolStats stats = this.connManager.getTotalStats();
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(0, stats.getAvailable());
|
|
||||||
|
|
||||||
final HttpHost target = start();
|
final HttpHost target = start();
|
||||||
// Get some random data
|
// Get some random data
|
||||||
final HttpGet httpget = new HttpGet("/random/20000");
|
final HttpGet httpget = new HttpGet("/random/20000");
|
||||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
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 {
|
try {
|
||||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||||
} catch (final ConnectionPoolTimeoutException expected) {
|
} catch (final TimeoutException expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
final HttpEntity e = response.getEntity();
|
final HttpEntity e = response.getEntity();
|
||||||
@ -119,14 +115,13 @@ public void testReleaseOnEntityWriteTo() throws Exception {
|
|||||||
e.writeTo(outsteam);
|
e.writeTo(outsteam);
|
||||||
|
|
||||||
// Expect one connection in the pool
|
// Expect one connection in the pool
|
||||||
stats = this.connManager.getTotalStats();
|
Assert.assertEquals(1, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(1, stats.getAvailable());
|
|
||||||
|
|
||||||
// Make sure one connection is available
|
// Make sure one connection is available
|
||||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
this.connManager.releaseConnection(conn, null, -1, null);
|
this.connManager.release(endpoint, null, -1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -135,8 +130,7 @@ public void testReleaseOnAbort() throws Exception {
|
|||||||
this.connManager.setMaxTotal(1);
|
this.connManager.setMaxTotal(1);
|
||||||
|
|
||||||
// Zero connections in the pool
|
// Zero connections in the pool
|
||||||
final PoolStats stats = this.connManager.getTotalStats();
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(0, stats.getAvailable());
|
|
||||||
|
|
||||||
final HttpHost target = start();
|
final HttpHost target = start();
|
||||||
|
|
||||||
@ -144,11 +138,11 @@ public void testReleaseOnAbort() throws Exception {
|
|||||||
final HttpGet httpget = new HttpGet("/random/20000");
|
final HttpGet httpget = new HttpGet("/random/20000");
|
||||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
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 {
|
try {
|
||||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||||
} catch (final ConnectionPoolTimeoutException expected) {
|
} catch (final TimeoutException expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
final HttpEntity e = response.getEntity();
|
final HttpEntity e = response.getEntity();
|
||||||
@ -159,10 +153,10 @@ public void testReleaseOnAbort() throws Exception {
|
|||||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
|
|
||||||
// Make sure one connection is available
|
// Make sure one connection is available
|
||||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint = connreq2.get(250, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
this.connManager.releaseConnection(conn, null, -1, null);
|
this.connManager.release(endpoint, null, -1, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -212,11 +206,11 @@ public void writeTo(
|
|||||||
final HttpGet httpget = new HttpGet("/dropdead");
|
final HttpGet httpget = new HttpGet("/dropdead");
|
||||||
final ClassicHttpResponse response = this.httpclient.execute(target, httpget);
|
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 {
|
try {
|
||||||
connreq.get(250, TimeUnit.MILLISECONDS);
|
connreq1.get(250, TimeUnit.MILLISECONDS);
|
||||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
||||||
} catch (final ConnectionPoolTimeoutException expected) {
|
} catch (final TimeoutException expected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
final HttpEntity e = response.getEntity();
|
final HttpEntity e = response.getEntity();
|
||||||
@ -233,10 +227,10 @@ public void writeTo(
|
|||||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
|
|
||||||
// Make sure one connection is available
|
// Make sure one connection is available
|
||||||
connreq = this.connManager.requestConnection(new HttpRoute(target), null);
|
final LeaseRequest connreq2 = this.connManager.lease(new HttpRoute(target), null);
|
||||||
final HttpClientConnection conn = connreq.get(250, TimeUnit.MILLISECONDS);
|
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;
|
package org.apache.hc.client5.http.impl.integration;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
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.HttpRoute;
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
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.localserver.LocalServerTestBase;
|
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
import org.apache.hc.core5.http.ClassicHttpResponse;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.HttpStatus;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
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.message.BasicClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||||
import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
|
import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
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.HttpProcessor;
|
||||||
import org.apache.hc.core5.http.protocol.RequestConnControl;
|
import org.apache.hc.core5.http.protocol.RequestConnControl;
|
||||||
import org.apache.hc.core5.http.protocol.RequestContent;
|
import org.apache.hc.core5.http.protocol.RequestContent;
|
||||||
@ -62,22 +58,6 @@
|
|||||||
*/
|
*/
|
||||||
public class TestConnectionManagement extends LocalServerTestBase {
|
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.
|
* Tests releasing and re-using a connection after a response is read.
|
||||||
*/
|
*/
|
||||||
@ -91,79 +71,60 @@ public void testReleaseConnection() throws Exception {
|
|||||||
final int rsplen = 8;
|
final int rsplen = 8;
|
||||||
final String uri = "/random/" + rsplen;
|
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();
|
final HttpContext context = new BasicHttpContext();
|
||||||
|
|
||||||
HttpClientConnection conn = getConnection(this.connManager, route);
|
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||||
this.connManager.connect(conn, route, 0, context);
|
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
this.connManager.routeComplete(conn, route, context);
|
|
||||||
|
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||||
|
|
||||||
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
||||||
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
||||||
|
|
||||||
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
||||||
exec.preProcess(request, httpProcessor, context);
|
exec.preProcess(request, httpProcessor, context);
|
||||||
ClassicHttpResponse response = exec.execute(request, conn, context);
|
try (final ClassicHttpResponse response1 = endpoint1.execute(request, exec, context)) {
|
||||||
|
Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
|
||||||
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
|
|
||||||
|
|
||||||
// check that there is no auto-release by default
|
// check that there is no auto-release by default
|
||||||
try {
|
try {
|
||||||
// this should fail quickly, connection has not been released
|
// this should fail quickly, connection has not been released
|
||||||
getConnection(this.connManager, route, 10L, TimeUnit.MILLISECONDS);
|
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
leaseRequest2.get(10, TimeUnit.MILLISECONDS);
|
||||||
} catch (final ConnectionPoolTimeoutException e) {
|
Assert.fail("TimeoutException expected");
|
||||||
|
} catch (final TimeoutException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.close();
|
endpoint1.close();
|
||||||
this.connManager.releaseConnection(conn, null, -1, null);
|
this.connManager.release(endpoint1, null, -1, null);
|
||||||
conn = getConnection(this.connManager, route);
|
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||||
Assert.assertFalse("connection should have been closed", conn.isOpen());
|
final ConnectionEndpoint endpoint2 = leaseRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
|
Assert.assertFalse(endpoint2.isConnected());
|
||||||
|
|
||||||
this.connManager.connect(conn, route, 0, context);
|
this.connManager.connect(endpoint2, 0, TimeUnit.MILLISECONDS, context);
|
||||||
this.connManager.routeComplete(conn, route, context);
|
|
||||||
|
|
||||||
// repeat the communication, no need to prepare the request again
|
try (final ClassicHttpResponse response2 = endpoint2.execute(request, exec, context)) {
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
|
||||||
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
|
|
||||||
|
|
||||||
// release connection after marking it for re-use
|
// release connection after marking it for re-use
|
||||||
// expect the next connection obtained to be open
|
// expect the next connection obtained to be open
|
||||||
this.connManager.releaseConnection(conn, null, -1, null);
|
this.connManager.release(endpoint2, null, -1, null);
|
||||||
conn = getConnection(this.connManager, route);
|
|
||||||
Assert.assertTrue("connection should have been open", conn.isOpen());
|
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
|
// repeat the communication, no need to prepare the request again
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
try (final ClassicHttpResponse response3 = endpoint3.execute(request, exec, context)) {
|
||||||
response = exec.execute(request, conn, context);
|
Assert.assertEquals(HttpStatus.SC_OK, response3.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
Assert.assertEquals("wrong status in third response",
|
this.connManager.release(endpoint3, null, -1, null);
|
||||||
HttpStatus.SC_OK,
|
this.connManager.close();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,96 +140,71 @@ public void testReleaseConnectionWithTimeLimits() throws Exception {
|
|||||||
final int rsplen = 8;
|
final int rsplen = 8;
|
||||||
final String uri = "/random/" + rsplen;
|
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();
|
final HttpContext context = new BasicHttpContext();
|
||||||
|
|
||||||
HttpClientConnection conn = getConnection(this.connManager, route);
|
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||||
this.connManager.connect(conn, route, 0, context);
|
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
this.connManager.routeComplete(conn, route, context);
|
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||||
|
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
|
||||||
|
|
||||||
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
final HttpProcessor httpProcessor = new DefaultHttpProcessor(
|
||||||
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
new RequestTargetHost(), new RequestContent(), new RequestConnControl());
|
||||||
|
|
||||||
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
final HttpRequestExecutor exec = new HttpRequestExecutor();
|
||||||
exec.preProcess(request, httpProcessor, context);
|
exec.preProcess(request, httpProcessor, context);
|
||||||
ClassicHttpResponse response = exec.execute(request, conn, context);
|
try (final ClassicHttpResponse response1 = endpoint1.execute(request, exec, context)) {
|
||||||
|
Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
|
||||||
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
|
|
||||||
|
|
||||||
// check that there is no auto-release by default
|
// check that there is no auto-release by default
|
||||||
try {
|
try {
|
||||||
// this should fail quickly, connection has not been released
|
// this should fail quickly, connection has not been released
|
||||||
getConnection(this.connManager, route, 10L, TimeUnit.MILLISECONDS);
|
final LeaseRequest leaseRequest2 = this.connManager.lease(route, null);
|
||||||
Assert.fail("ConnectionPoolTimeoutException should have been thrown");
|
leaseRequest2.get(10, TimeUnit.MILLISECONDS);
|
||||||
} catch (final ConnectionPoolTimeoutException e) {
|
Assert.fail("TimeoutException expected");
|
||||||
|
} catch (final TimeoutException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.close();
|
endpoint1.close();
|
||||||
this.connManager.releaseConnection(conn, null, 100, TimeUnit.MILLISECONDS);
|
this.connManager.release(endpoint1, null, 100, TimeUnit.MILLISECONDS);
|
||||||
conn = getConnection(this.connManager, route);
|
|
||||||
Assert.assertFalse("connection should have been closed", conn.isOpen());
|
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
|
// repeat the communication, no need to prepare the request again
|
||||||
this.connManager.connect(conn, route, 0, context);
|
try (final ClassicHttpResponse response3 = endpoint3.execute(request, exec, context)) {
|
||||||
this.connManager.routeComplete(conn, route, context);
|
Assert.assertEquals(HttpStatus.SC_OK, response3.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
this.connManager.release(endpoint3, null, 100, TimeUnit.MILLISECONDS);
|
||||||
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);
|
|
||||||
Thread.sleep(150);
|
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
|
// repeat the communication, no need to prepare the request again
|
||||||
this.connManager.connect(conn, route, 0, context);
|
this.connManager.connect(endpoint4, 0, TimeUnit.MILLISECONDS, context);
|
||||||
this.connManager.routeComplete(conn, route, context);
|
|
||||||
|
|
||||||
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
|
try (final ClassicHttpResponse response4 = endpoint4.execute(request, exec, context)) {
|
||||||
response = exec.execute(request, conn, context);
|
Assert.assertEquals(HttpStatus.SC_OK, response4.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
Assert.assertEquals("wrong status in third response",
|
this.connManager.close();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -280,15 +216,15 @@ public void testCloseExpiredIdleConnections() throws Exception {
|
|||||||
final HttpRoute route = new HttpRoute(target, null, false);
|
final HttpRoute route = new HttpRoute(target, null, false);
|
||||||
final HttpContext context = new BasicHttpContext();
|
final HttpContext context = new BasicHttpContext();
|
||||||
|
|
||||||
final HttpClientConnection conn = getConnection(this.connManager, route);
|
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||||
this.connManager.connect(conn, route, 0, context);
|
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
this.connManager.routeComplete(conn, route, context);
|
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||||
|
|
||||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||||
Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
|
Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
|
||||||
Assert.assertEquals(1, this.connManager.getStats(route).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.
|
// Released, still active.
|
||||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||||
@ -311,7 +247,7 @@ public void testCloseExpiredIdleConnections() throws Exception {
|
|||||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
|
Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
|
||||||
|
|
||||||
this.connManager.shutdown();
|
this.connManager.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -327,15 +263,15 @@ public void testCloseExpiredTTLConnections() throws Exception {
|
|||||||
final HttpRoute route = new HttpRoute(target, null, false);
|
final HttpRoute route = new HttpRoute(target, null, false);
|
||||||
final HttpContext context = new BasicHttpContext();
|
final HttpContext context = new BasicHttpContext();
|
||||||
|
|
||||||
final HttpClientConnection conn = getConnection(this.connManager, route);
|
final LeaseRequest leaseRequest1 = this.connManager.lease(route, null);
|
||||||
this.connManager.connect(conn, route, 0, context);
|
final ConnectionEndpoint endpoint1 = leaseRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
this.connManager.routeComplete(conn, route, context);
|
this.connManager.connect(endpoint1, 0, TimeUnit.MILLISECONDS, context);
|
||||||
|
|
||||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||||
Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
|
Assert.assertEquals(1, this.connManager.getTotalStats().getLeased());
|
||||||
Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
|
Assert.assertEquals(1, this.connManager.getStats(route).getLeased());
|
||||||
// Release, let remain idle for forever
|
// 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.
|
// Released, still active.
|
||||||
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
Assert.assertEquals(Collections.singleton(route), this.connManager.getRoutes());
|
||||||
@ -358,64 +294,7 @@ public void testCloseExpiredTTLConnections() throws Exception {
|
|||||||
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
Assert.assertEquals(0, this.connManager.getTotalStats().getAvailable());
|
||||||
Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
|
Assert.assertEquals(0, this.connManager.getStats(route).getAvailable());
|
||||||
|
|
||||||
this.connManager.shutdown();
|
this.connManager.close();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.GZIPOutputStream;
|
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.impl.sync.CloseableHttpClient;
|
||||||
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
import org.apache.hc.client5.http.localserver.LocalServerTestBase;
|
||||||
import org.apache.hc.client5.http.methods.HttpGet;
|
import org.apache.hc.client5.http.methods.HttpGet;
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
import org.apache.hc.client5.http.protocol.UserTokenHandler;
|
import org.apache.hc.client5.http.protocol.UserTokenHandler;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.ClassicHttpResponse;
|
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.HttpException;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.HttpStatus;
|
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.HttpRequestHandler;
|
||||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||||
import org.apache.hc.core5.http.io.entity.StringEntity;
|
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||||
@ -119,12 +119,10 @@ public Object getUserToken(final HttpRoute route, final HttpContext context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final HttpContext context : contexts) {
|
for (final HttpContext context : contexts) {
|
||||||
final String uid = (String) context.getAttribute("user");
|
final String state0 = (String) context.getAttribute("r0");
|
||||||
|
Assert.assertNotNull(state0);
|
||||||
for (int r = 0; r < requestCount; r++) {
|
for (int r = 1; r < requestCount; r++) {
|
||||||
final String state = (String) context.getAttribute("r" + r);
|
Assert.assertEquals(state0, (String) context.getAttribute("r" + r));
|
||||||
Assert.assertNotNull(state);
|
|
||||||
Assert.assertEquals(uid, state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,13 +174,8 @@ public void run() {
|
|||||||
this.context);
|
this.context);
|
||||||
this.count++;
|
this.count++;
|
||||||
|
|
||||||
final HttpClientConnection conn = this.context.getConnection(HttpClientConnection.class);
|
final HttpConnection conn = this.context.getConnection();
|
||||||
final HttpContext connContext = (HttpContext) conn;
|
final String connuid = Integer.toHexString(System.identityHashCode(conn));
|
||||||
String connuid = (String) connContext.getAttribute("user");
|
|
||||||
if (connuid == null) {
|
|
||||||
connContext.setAttribute("user", this.uid);
|
|
||||||
connuid = this.uid;
|
|
||||||
}
|
|
||||||
this.context.setAttribute("r" + r, connuid);
|
this.context.setAttribute("r" + r, connuid);
|
||||||
EntityUtils.consume(response.getEntity());
|
EntityUtils.consume(response.getEntity());
|
||||||
}
|
}
|
||||||
|
@ -33,19 +33,18 @@
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.DnsResolver;
|
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.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SchemePortResolver;
|
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.io.ManagedHttpClientConnection;
|
||||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
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.Lookup;
|
||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
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.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -60,7 +59,7 @@ public class TestBasicHttpClientConnectionManager {
|
|||||||
@Mock
|
@Mock
|
||||||
private ManagedHttpClientConnection conn;
|
private ManagedHttpClientConnection conn;
|
||||||
@Mock
|
@Mock
|
||||||
private HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connFactory;
|
private HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
|
||||||
@Mock
|
@Mock
|
||||||
private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
|
private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
|
||||||
@Mock
|
@Mock
|
||||||
@ -88,26 +87,24 @@ public void testLeaseReleaseNonReusable() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("localhost", 80);
|
final HttpHost target = new HttpHost("localhost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
Assert.assertFalse(conn1.isOpen());
|
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.getRoute());
|
||||||
Assert.assertNull(mgr.getState());
|
Assert.assertNull(mgr.getState());
|
||||||
|
|
||||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn2);
|
Assert.assertNotNull(conn2);
|
||||||
Assert.assertFalse(conn2.isOpen());
|
Assert.assertFalse(conn2.isConnected());
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(2)).create(
|
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -115,29 +112,27 @@ public void testLeaseReleaseReusable() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
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 LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
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(route, mgr.getRoute());
|
||||||
Assert.assertEquals(null, mgr.getState());
|
Assert.assertEquals(null, mgr.getState());
|
||||||
|
|
||||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn2);
|
Assert.assertNotNull(conn2);
|
||||||
Assert.assertTrue(conn2.isOpen());
|
Assert.assertTrue(conn2.isConnected());
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -145,30 +140,27 @@ public void testLeaseReleaseReusableWithState() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, "some state");
|
final LeaseRequest connRequest1 = mgr.lease(route, "some state");
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
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(route, mgr.getRoute());
|
||||||
Assert.assertEquals("some other state", mgr.getState());
|
Assert.assertEquals("some other state", mgr.getState());
|
||||||
|
|
||||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, "some other state");
|
final LeaseRequest connRequest2 = mgr.lease(route, "some other state");
|
||||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn2);
|
Assert.assertNotNull(conn2);
|
||||||
Assert.assertTrue(conn2.isOpen());
|
Assert.assertTrue(conn2.isConnected());
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -176,35 +168,30 @@ public void testLeaseDifferentRoute() throws Exception {
|
|||||||
final HttpHost target1 = new HttpHost("somehost", 80);
|
final HttpHost target1 = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route1 = new HttpRoute(target1);
|
final HttpRoute route1 = new HttpRoute(target1);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.<HttpRoute>any(), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route1, null);
|
final LeaseRequest connRequest1 = mgr.lease(route1, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route1), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
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(route1, mgr.getRoute());
|
||||||
Assert.assertEquals(null, mgr.getState());
|
Assert.assertEquals(null, mgr.getState());
|
||||||
|
|
||||||
final HttpHost target2 = new HttpHost("otherhost", 80);
|
final HttpHost target2 = new HttpHost("otherhost", 80);
|
||||||
final HttpRoute route2 = new HttpRoute(target2);
|
final HttpRoute route2 = new HttpRoute(target2);
|
||||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route2, null);
|
final LeaseRequest connRequest2 = mgr.lease(route2, null);
|
||||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn2);
|
Assert.assertNotNull(conn2);
|
||||||
Assert.assertFalse(conn2.isOpen());
|
Assert.assertFalse(conn2.isConnected());
|
||||||
|
|
||||||
Mockito.verify(conn).close();
|
Mockito.verify(conn).close();
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route1), Mockito.<ConnectionConfig>any());
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
|
||||||
Mockito.eq(route2), Mockito.<ConnectionConfig>any());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -212,49 +199,41 @@ public void testLeaseExpired() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
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(route, mgr.getRoute());
|
||||||
Assert.assertEquals(null, mgr.getState());
|
Assert.assertEquals(null, mgr.getState());
|
||||||
|
|
||||||
Thread.sleep(50);
|
Thread.sleep(50);
|
||||||
|
|
||||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint conn2 = connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn2);
|
Assert.assertNotNull(conn2);
|
||||||
Assert.assertFalse(conn2.isOpen());
|
Assert.assertFalse(conn2.isConnected());
|
||||||
|
|
||||||
Mockito.verify(conn).close();
|
Mockito.verify(conn).close();
|
||||||
Mockito.verify(connFactory, Mockito.times(2)).create(
|
Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
|
||||||
public void testLeaseInvalidArg() throws Exception {
|
|
||||||
mgr.requestConnection(null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
@Test(expected=IllegalArgumentException.class)
|
||||||
public void testReleaseInvalidArg() throws Exception {
|
public void testReleaseInvalidArg() throws Exception {
|
||||||
mgr.releaseConnection(null, null, 0, TimeUnit.MILLISECONDS);
|
mgr.release(null, null, 0, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalStateException.class)
|
@Test(expected=IllegalStateException.class)
|
||||||
public void testReleaseAnotherConnection() throws Exception {
|
public void testReleaseAnotherConnection() throws Exception {
|
||||||
final HttpClientConnection wrongCon = Mockito.mock(HttpClientConnection.class);
|
final ConnectionEndpoint wrongCon = Mockito.mock(ConnectionEndpoint.class);
|
||||||
mgr.releaseConnection(wrongCon, null, 0, TimeUnit.MILLISECONDS);
|
mgr.release(wrongCon, null, 0, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -262,26 +241,24 @@ public void testShutdown() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
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();
|
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final ConnectionRequest connRequest2 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest2 = mgr.lease(route, null);
|
||||||
connRequest2.get(0, TimeUnit.MILLISECONDS);
|
connRequest2.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.fail("IllegalStateException expected");
|
Assert.fail("IllegalStateException expected");
|
||||||
} catch (final IllegalStateException ex) {
|
} catch (final IllegalStateException ex) {
|
||||||
@ -290,7 +267,7 @@ public void testShutdown() throws Exception {
|
|||||||
// Should have no effect
|
// Should have no effect
|
||||||
mgr.closeExpired();
|
mgr.closeExpired();
|
||||||
mgr.closeIdle(0L, TimeUnit.MILLISECONDS);
|
mgr.closeIdle(0L, TimeUnit.MILLISECONDS);
|
||||||
mgr.shutdown();
|
mgr.close();
|
||||||
|
|
||||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
||||||
}
|
}
|
||||||
@ -300,19 +277,17 @@ public void testCloseExpired() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
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(route, mgr.getRoute());
|
||||||
Assert.assertEquals(null, mgr.getState());
|
Assert.assertEquals(null, mgr.getState());
|
||||||
@ -329,19 +304,17 @@ public void testCloseIdle() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
Mockito.verify(connFactory, Mockito.times(1)).create(
|
Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any());
|
|
||||||
|
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
|
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(route, mgr.getRoute());
|
||||||
Assert.assertEquals(null, mgr.getState());
|
Assert.assertEquals(null, mgr.getState());
|
||||||
@ -358,13 +331,12 @@ public void testAlreadyLeased() throws Exception {
|
|||||||
final HttpHost target = new HttpHost("somehost", 80);
|
final HttpHost target = new HttpHost("somehost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
mgr.releaseConnection(conn1, null, 100, TimeUnit.MILLISECONDS);
|
mgr.release(endpoint1, null, 100, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
mgr.getConnection(route, null);
|
mgr.getConnection(route, null);
|
||||||
mgr.getConnection(route, null);
|
mgr.getConnection(route, null);
|
||||||
@ -377,12 +349,11 @@ public void testTargetConnect() throws Exception {
|
|||||||
final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
||||||
final HttpRoute route = new HttpRoute(target, local, true);
|
final HttpRoute route = new HttpRoute(target, local, true);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||||
@ -401,7 +372,7 @@ public void testTargetConnect() throws Exception {
|
|||||||
Mockito.<InetSocketAddress>any(),
|
Mockito.<InetSocketAddress>any(),
|
||||||
Mockito.<HttpContext>any())).thenReturn(socket);
|
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(dnsResolver, Mockito.times(1)).resolve("somehost");
|
||||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||||
@ -409,8 +380,6 @@ public void testTargetConnect() throws Exception {
|
|||||||
Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
|
Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
|
||||||
new InetSocketAddress(remote, 8443),
|
new InetSocketAddress(remote, 8443),
|
||||||
new InetSocketAddress(local, 0), context);
|
new InetSocketAddress(local, 0), context);
|
||||||
|
|
||||||
mgr.routeComplete(conn1, route, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -421,12 +390,11 @@ public void testProxyConnectAndUpgrade() throws Exception {
|
|||||||
final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
||||||
final HttpRoute route = new HttpRoute(target, local, proxy, true);
|
final HttpRoute route = new HttpRoute(target, local, proxy, true);
|
||||||
|
|
||||||
Mockito.when(connFactory.create(
|
Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
|
||||||
Mockito.eq(route), Mockito.<ConnectionConfig>any())).thenReturn(conn);
|
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(0, TimeUnit.MILLISECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||||
@ -447,7 +415,7 @@ public void testProxyConnectAndUpgrade() throws Exception {
|
|||||||
Mockito.<InetSocketAddress>any(),
|
Mockito.<InetSocketAddress>any(),
|
||||||
Mockito.<HttpContext>any())).thenReturn(socket);
|
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(dnsResolver, Mockito.times(1)).resolve("someproxy");
|
||||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
|
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
|
||||||
@ -458,13 +426,11 @@ public void testProxyConnectAndUpgrade() throws Exception {
|
|||||||
|
|
||||||
Mockito.when(conn.getSocket()).thenReturn(socket);
|
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(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||||
Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
|
Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
|
||||||
socket, "somehost", 8443, context);
|
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 void testUpgrade() throws Exception {
|
|||||||
final HttpContext context = new BasicHttpContext();
|
final HttpContext context = new BasicHttpContext();
|
||||||
final HttpHost host = new HttpHost("somehost", -1, "https");
|
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(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
|
||||||
Mockito.when(schemePortResolver.resolve(host)).thenReturn(443);
|
Mockito.when(schemePortResolver.resolve(host)).thenReturn(443);
|
||||||
Mockito.when(sslSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
|
Mockito.when(sslSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
|
||||||
|
@ -34,20 +34,18 @@
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
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.DnsResolver;
|
||||||
import org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SchemePortResolver;
|
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.io.ManagedHttpClientConnection;
|
||||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||||
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
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.Lookup;
|
||||||
import org.apache.hc.core5.http.config.SocketConfig;
|
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.http.protocol.HttpContext;
|
||||||
import org.apache.hc.core5.pool.PoolEntry;
|
import org.apache.hc.core5.pool.PoolEntry;
|
||||||
import org.apache.hc.core5.pool.StrictConnPool;
|
import org.apache.hc.core5.pool.StrictConnPool;
|
||||||
@ -109,14 +107,12 @@ public void testLeaseRelease() throws Exception {
|
|||||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
Assert.assertNotSame(conn, conn1);
|
Assert.assertNotSame(conn, endpoint1);
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
|
||||||
poolProxy.markRouteComplete();
|
|
||||||
|
|
||||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
Mockito.verify(pool).release(entry, true);
|
Mockito.verify(pool).release(entry, true);
|
||||||
}
|
}
|
||||||
@ -138,12 +134,12 @@ public void testReleaseRouteIncomplete() throws Exception {
|
|||||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
Assert.assertNotSame(conn, conn1);
|
Assert.assertNotSame(conn, endpoint1);
|
||||||
|
|
||||||
mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
|
mgr.release(endpoint1, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
Mockito.verify(pool).release(entry, false);
|
Mockito.verify(pool).release(entry, false);
|
||||||
}
|
}
|
||||||
@ -160,11 +156,11 @@ public void testLeaseFutureCancelled() throws Exception {
|
|||||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
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);
|
connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=ConnectionPoolTimeoutException.class)
|
@Test(expected=TimeoutException.class)
|
||||||
public void testLeaseFutureTimeout() throws Exception {
|
public void testLeaseFutureTimeout() throws Exception {
|
||||||
final HttpHost target = new HttpHost("localhost", 80);
|
final HttpHost target = new HttpHost("localhost", 80);
|
||||||
final HttpRoute route = new HttpRoute(target);
|
final HttpRoute route = new HttpRoute(target);
|
||||||
@ -173,7 +169,7 @@ public void testLeaseFutureTimeout() throws Exception {
|
|||||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
|
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
|
||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
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);
|
connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,14 +186,12 @@ public void testReleaseReusable() throws Exception {
|
|||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
Assert.assertTrue(conn1.isOpen());
|
Assert.assertTrue(endpoint1.isConnected());
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
|
||||||
poolProxy.markRouteComplete();
|
|
||||||
|
|
||||||
mgr.releaseConnection(conn1, "some state", 10, TimeUnit.MILLISECONDS);
|
mgr.release(endpoint1, "some state", 10, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
Mockito.verify(pool).release(entry, true);
|
Mockito.verify(pool).release(entry, true);
|
||||||
Assert.assertEquals("some state", entry.getState());
|
Assert.assertEquals("some state", entry.getState());
|
||||||
@ -216,14 +210,12 @@ public void testReleaseNonReusable() throws Exception {
|
|||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||||
Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
|
Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
Assert.assertFalse(conn1.isOpen());
|
Assert.assertFalse(endpoint1.isConnected());
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
|
||||||
poolProxy.markRouteComplete();
|
|
||||||
|
|
||||||
mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
|
mgr.release(endpoint1, "some state", 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
Mockito.verify(pool).release(entry, false);
|
Mockito.verify(pool).release(entry, false);
|
||||||
Assert.assertEquals(null, entry.getState());
|
Assert.assertEquals(null, entry.getState());
|
||||||
@ -240,16 +232,14 @@ public void testTargetConnect() throws Exception {
|
|||||||
entry.assignConnection(conn);
|
entry.assignConnection(conn);
|
||||||
|
|
||||||
Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
|
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.isCancelled()).thenReturn(false);
|
||||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
final CPoolProxy poolProxy = CPoolProxy.getProxy(conn1);
|
|
||||||
poolProxy.markRouteComplete();
|
|
||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||||
@ -268,7 +258,7 @@ public void testTargetConnect() throws Exception {
|
|||||||
Mockito.<InetSocketAddress>any(),
|
Mockito.<InetSocketAddress>any(),
|
||||||
Mockito.<HttpContext>any())).thenReturn(socket);
|
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(dnsResolver, Mockito.times(1)).resolve("somehost");
|
||||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||||
@ -276,8 +266,6 @@ public void testTargetConnect() throws Exception {
|
|||||||
Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
|
Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
|
||||||
new InetSocketAddress(remote, 8443),
|
new InetSocketAddress(remote, 8443),
|
||||||
new InetSocketAddress(local, 0), context);
|
new InetSocketAddress(local, 0), context);
|
||||||
|
|
||||||
mgr.routeComplete(conn1, route, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -292,24 +280,22 @@ public void testProxyConnectAndUpgrade() throws Exception {
|
|||||||
entry.assignConnection(conn);
|
entry.assignConnection(conn);
|
||||||
|
|
||||||
Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
|
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.isCancelled()).thenReturn(false);
|
||||||
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
|
||||||
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
Mockito.when(pool.lease(route, null, null)).thenReturn(future);
|
||||||
|
|
||||||
final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
|
final LeaseRequest connRequest1 = mgr.lease(route, null);
|
||||||
final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
|
final ConnectionEndpoint endpoint1 = connRequest1.get(1, TimeUnit.SECONDS);
|
||||||
Assert.assertNotNull(conn1);
|
Assert.assertNotNull(endpoint1);
|
||||||
|
|
||||||
final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
|
final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
|
||||||
final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
|
final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
|
||||||
final Socket mockSock = Mockito.mock(Socket.class);
|
final Socket mockSock = Mockito.mock(Socket.class);
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
final SocketConfig sconfig = SocketConfig.custom().build();
|
final SocketConfig sconfig = SocketConfig.custom().build();
|
||||||
final ConnectionConfig cconfig = ConnectionConfig.custom().build();
|
|
||||||
|
|
||||||
mgr.setDefaultSocketConfig(sconfig);
|
mgr.setDefaultSocketConfig(sconfig);
|
||||||
mgr.setDefaultConnectionConfig(cconfig);
|
|
||||||
|
|
||||||
Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
|
Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
|
||||||
Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
|
Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
|
||||||
@ -325,7 +311,7 @@ public void testProxyConnectAndUpgrade() throws Exception {
|
|||||||
Mockito.<InetSocketAddress>any(),
|
Mockito.<InetSocketAddress>any(),
|
||||||
Mockito.<HttpContext>any())).thenReturn(mockSock);
|
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(dnsResolver, Mockito.times(1)).resolve("someproxy");
|
||||||
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
|
Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
|
||||||
@ -334,15 +320,14 @@ public void testProxyConnectAndUpgrade() throws Exception {
|
|||||||
new InetSocketAddress(remote, 8080),
|
new InetSocketAddress(remote, 8080),
|
||||||
new InetSocketAddress(local, 0), context);
|
new InetSocketAddress(local, 0), context);
|
||||||
|
|
||||||
|
Mockito.when(conn.isOpen()).thenReturn(true);
|
||||||
Mockito.when(conn.getSocket()).thenReturn(mockSock);
|
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(schemePortResolver, Mockito.times(1)).resolve(target);
|
||||||
Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
|
Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
|
||||||
mockSock, "somehost", 8443, context);
|
mockSock, "somehost", 8443, context);
|
||||||
|
|
||||||
mgr.routeComplete(conn1, route, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,10 +61,9 @@ public void setup() {
|
|||||||
@Test
|
@Test
|
||||||
public void testDefaultProxyDirect() throws Exception {
|
public void testDefaultProxyDirect() throws Exception {
|
||||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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(target, route.getTargetHost());
|
||||||
Assert.assertEquals(defaultProxy, route.getProxyHost());
|
Assert.assertEquals(defaultProxy, route.getProxyHost());
|
||||||
@ -80,7 +79,7 @@ public void testViaProxy() throws Exception {
|
|||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
context.setRequestConfig(RequestConfig.custom().setProxy(proxy).build());
|
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(target, route.getTargetHost());
|
||||||
Assert.assertEquals(proxy, route.getProxyHost());
|
Assert.assertEquals(proxy, route.getProxyHost());
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
package org.apache.hc.client5.http.impl.routing;
|
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.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SchemePortResolver;
|
import org.apache.hc.client5.http.SchemePortResolver;
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
@ -37,6 +39,8 @@
|
|||||||
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
import org.apache.hc.core5.http.message.BasicHttpRequest;
|
||||||
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
import org.apache.hc.core5.http.protocol.BasicHttpContext;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
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.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -60,10 +64,9 @@ public void setup() {
|
|||||||
@Test
|
@Test
|
||||||
public void testDirect() throws Exception {
|
public void testDirect() throws Exception {
|
||||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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(target, route.getTargetHost());
|
||||||
Assert.assertEquals(1, route.getHopCount());
|
Assert.assertEquals(1, route.getHopCount());
|
||||||
@ -75,10 +78,9 @@ public void testDirect() throws Exception {
|
|||||||
public void testDirectDefaultPort() throws Exception {
|
public void testDirectDefaultPort() throws Exception {
|
||||||
final HttpHost target = new HttpHost("somehost", -1, "https");
|
final HttpHost target = new HttpHost("somehost", -1, "https");
|
||||||
Mockito.when(schemePortResolver.resolve(target)).thenReturn(443);
|
Mockito.when(schemePortResolver.resolve(target)).thenReturn(443);
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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(new HttpHost("somehost", 443, "https"), route.getTargetHost());
|
||||||
Assert.assertEquals(1, route.getHopCount());
|
Assert.assertEquals(1, route.getHopCount());
|
||||||
@ -89,11 +91,10 @@ public void testDirectDefaultPort() throws Exception {
|
|||||||
public void testViaProxy() throws Exception {
|
public void testViaProxy() throws Exception {
|
||||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||||
final HttpHost proxy = new HttpHost("proxy", 8080);
|
final HttpHost proxy = new HttpHost("proxy", 8080);
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
context.setRequestConfig(RequestConfig.custom().setProxy(proxy).build());
|
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(target, route.getTargetHost());
|
||||||
Assert.assertEquals(proxy, route.getProxyHost());
|
Assert.assertEquals(proxy, route.getProxyHost());
|
||||||
@ -104,10 +105,28 @@ public void testViaProxy() throws Exception {
|
|||||||
|
|
||||||
@Test(expected= ProtocolException.class)
|
@Test(expected= ProtocolException.class)
|
||||||
public void testNullTarget() throws Exception {
|
public void testNullTarget() throws Exception {
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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 org.apache.hc.client5.http.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.SchemePortResolver;
|
import org.apache.hc.client5.http.SchemePortResolver;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
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.BasicHttpContext;
|
||||||
import org.apache.hc.core5.http.protocol.HttpContext;
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
@ -68,10 +66,9 @@ public void setup() {
|
|||||||
@Test
|
@Test
|
||||||
public void testDirect() throws Exception {
|
public void testDirect() throws Exception {
|
||||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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(target, route.getTargetHost());
|
||||||
Assert.assertEquals(1, route.getHopCount());
|
Assert.assertEquals(1, route.getHopCount());
|
||||||
@ -83,10 +80,9 @@ public void testDirect() throws Exception {
|
|||||||
public void testDirectDefaultPort() throws Exception {
|
public void testDirectDefaultPort() throws Exception {
|
||||||
final HttpHost target = new HttpHost("somehost", -1, "https");
|
final HttpHost target = new HttpHost("somehost", -1, "https");
|
||||||
Mockito.when(schemePortResolver.resolve(target)).thenReturn(443);
|
Mockito.when(schemePortResolver.resolve(target)).thenReturn(443);
|
||||||
final HttpRequest request = new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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(new HttpHost("somehost", 443, "https"), route.getTargetHost());
|
||||||
Assert.assertEquals(1, route.getHopCount());
|
Assert.assertEquals(1, route.getHopCount());
|
||||||
@ -109,11 +105,9 @@ public void testProxy() throws Exception {
|
|||||||
Mockito.when(proxySelector.select(new URI("http://somehost:80"))).thenReturn(proxies);
|
Mockito.when(proxySelector.select(new URI("http://somehost:80"))).thenReturn(proxies);
|
||||||
|
|
||||||
final HttpHost target = new HttpHost("somehost", 80, "http");
|
final HttpHost target = new HttpHost("somehost", 80, "http");
|
||||||
final HttpRequest request =
|
|
||||||
new BasicHttpRequest("GET", "/");
|
|
||||||
|
|
||||||
final HttpContext context = new BasicHttpContext();
|
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(target, route.getTargetHost());
|
||||||
Assert.assertEquals(2, route.getHopCount());
|
Assert.assertEquals(2, route.getHopCount());
|
||||||
|
@ -32,8 +32,7 @@
|
|||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
|
|
||||||
import org.apache.hc.client5.http.ConnectionPoolTimeoutException;
|
import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
|
||||||
import org.apache.hc.client5.http.sync.ConnectionBackoffStrategy;
|
|
||||||
import org.apache.hc.core5.http.HttpResponse;
|
import org.apache.hc.core5.http.HttpResponse;
|
||||||
import org.apache.hc.core5.http.HttpStatus;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.apache.hc.core5.http.message.BasicHttpResponse;
|
import org.apache.hc.core5.http.message.BasicHttpResponse;
|
||||||
@ -50,11 +49,6 @@ public void setUp() {
|
|||||||
impl = new DefaultBackoffStrategy();
|
impl = new DefaultBackoffStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isABackoffStrategy() {
|
|
||||||
assertTrue(impl instanceof ConnectionBackoffStrategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void backsOffForSocketTimeouts() {
|
public void backsOffForSocketTimeouts() {
|
||||||
assertTrue(impl.shouldBackoff(new SocketTimeoutException()));
|
assertTrue(impl.shouldBackoff(new SocketTimeoutException()));
|
||||||
@ -67,7 +61,7 @@ public void backsOffForConnectionTimeouts() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void doesNotBackOffForConnectionManagerTimeout() {
|
public void doesNotBackOffForConnectionManagerTimeout() {
|
||||||
assertFalse(impl.shouldBackoff(new ConnectionPoolTimeoutException()));
|
assertFalse(impl.shouldBackoff(new ConnectionRequestTimeoutException()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -29,28 +29,32 @@
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.client5.http.io.HttpClientConnectionManager;
|
||||||
import org.apache.hc.core5.http.io.HttpClientConnection;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@SuppressWarnings({"static-access"}) // test code
|
@SuppressWarnings({"static-access"}) // test code
|
||||||
public class TestConnectionHolder {
|
public class TestEndpointHolder {
|
||||||
|
|
||||||
|
@Mock
|
||||||
private Logger log;
|
private Logger log;
|
||||||
|
@Mock
|
||||||
private HttpClientConnectionManager mgr;
|
private HttpClientConnectionManager mgr;
|
||||||
private HttpClientConnection conn;
|
@Mock
|
||||||
private ConnectionHolder connHolder;
|
private ConnectionEndpoint endpoint;
|
||||||
|
|
||||||
|
private EndpointHolder connHolder;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
log = Mockito.mock(Logger.class);
|
MockitoAnnotations.initMocks(this);
|
||||||
mgr = Mockito.mock(HttpClientConnectionManager.class);
|
connHolder = new EndpointHolder(log, mgr, endpoint);
|
||||||
conn = Mockito.mock(HttpClientConnection.class);
|
|
||||||
connHolder = new ConnectionHolder(log, mgr, conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -59,14 +63,14 @@ public void testAbortConnection() throws Exception {
|
|||||||
|
|
||||||
Assert.assertTrue(connHolder.isReleased());
|
Assert.assertTrue(connHolder.isReleased());
|
||||||
|
|
||||||
Mockito.verify(conn).shutdown();
|
Mockito.verify(endpoint).shutdown();
|
||||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
connHolder.abortConnection();
|
connHolder.abortConnection();
|
||||||
|
|
||||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
Mockito.verify(endpoint, Mockito.times(1)).shutdown();
|
||||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<ConnectionEndpoint>any(),
|
||||||
Mockito.anyObject(),
|
Mockito.anyObject(),
|
||||||
Mockito.anyLong(),
|
Mockito.anyLong(),
|
||||||
Mockito.<TimeUnit>any());
|
Mockito.<TimeUnit>any());
|
||||||
@ -74,14 +78,14 @@ public void testAbortConnection() throws Exception {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAbortConnectionIOError() throws Exception {
|
public void testAbortConnectionIOError() throws Exception {
|
||||||
Mockito.doThrow(new IOException()).when(conn).shutdown();
|
Mockito.doThrow(new IOException()).when(endpoint).shutdown();
|
||||||
|
|
||||||
connHolder.abortConnection();
|
connHolder.abortConnection();
|
||||||
|
|
||||||
Assert.assertTrue(connHolder.isReleased());
|
Assert.assertTrue(connHolder.isReleased());
|
||||||
|
|
||||||
Mockito.verify(conn).shutdown();
|
Mockito.verify(endpoint).shutdown();
|
||||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -90,14 +94,14 @@ public void testCancell() throws Exception {
|
|||||||
|
|
||||||
Assert.assertTrue(connHolder.isReleased());
|
Assert.assertTrue(connHolder.isReleased());
|
||||||
|
|
||||||
Mockito.verify(conn).shutdown();
|
Mockito.verify(endpoint).shutdown();
|
||||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
Assert.assertFalse(connHolder.cancel());
|
Assert.assertFalse(connHolder.cancel());
|
||||||
|
|
||||||
Mockito.verify(conn, Mockito.times(1)).shutdown();
|
Mockito.verify(endpoint, Mockito.times(1)).shutdown();
|
||||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<ConnectionEndpoint>any(),
|
||||||
Mockito.anyObject(),
|
Mockito.anyObject(),
|
||||||
Mockito.anyLong(),
|
Mockito.anyLong(),
|
||||||
Mockito.<TimeUnit>any());
|
Mockito.<TimeUnit>any());
|
||||||
@ -113,13 +117,13 @@ public void testReleaseConnectionReusable() throws Exception {
|
|||||||
|
|
||||||
Assert.assertTrue(connHolder.isReleased());
|
Assert.assertTrue(connHolder.isReleased());
|
||||||
|
|
||||||
Mockito.verify(conn, Mockito.never()).close();
|
Mockito.verify(endpoint, Mockito.never()).close();
|
||||||
Mockito.verify(mgr).releaseConnection(conn, "some state", 100, TimeUnit.SECONDS);
|
Mockito.verify(mgr).release(endpoint, "some state", 100000, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
connHolder.releaseConnection();
|
connHolder.releaseConnection();
|
||||||
|
|
||||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<ConnectionEndpoint>any(),
|
||||||
Mockito.anyObject(),
|
Mockito.anyObject(),
|
||||||
Mockito.anyLong(),
|
Mockito.anyLong(),
|
||||||
Mockito.<TimeUnit>any());
|
Mockito.<TimeUnit>any());
|
||||||
@ -135,13 +139,13 @@ public void testReleaseConnectionNonReusable() throws Exception {
|
|||||||
|
|
||||||
Assert.assertTrue(connHolder.isReleased());
|
Assert.assertTrue(connHolder.isReleased());
|
||||||
|
|
||||||
Mockito.verify(conn, Mockito.times(1)).close();
|
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||||
Mockito.verify(mgr).releaseConnection(conn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(mgr).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
connHolder.releaseConnection();
|
connHolder.releaseConnection();
|
||||||
|
|
||||||
Mockito.verify(mgr, Mockito.times(1)).releaseConnection(
|
Mockito.verify(mgr, Mockito.times(1)).release(
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<ConnectionEndpoint>any(),
|
||||||
Mockito.anyObject(),
|
Mockito.anyObject(),
|
||||||
Mockito.anyLong(),
|
Mockito.anyLong(),
|
||||||
Mockito.<TimeUnit>any());
|
Mockito.<TimeUnit>any());
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
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.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
@ -41,7 +41,7 @@ public class TestIdleConnectionEvictor {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEvictExpiredAndIdle() throws Exception {
|
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,
|
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
|
||||||
500, TimeUnit.MILLISECONDS, 3, TimeUnit.SECONDS);
|
500, TimeUnit.MILLISECONDS, 3, TimeUnit.SECONDS);
|
||||||
connectionEvictor.start();
|
connectionEvictor.start();
|
||||||
@ -60,7 +60,7 @@ public void testEvictExpiredAndIdle() throws Exception {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEvictExpiredOnly() throws Exception {
|
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,
|
final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(cm,
|
||||||
500, TimeUnit.MILLISECONDS, 0, TimeUnit.SECONDS);
|
500, TimeUnit.MILLISECONDS, 0, TimeUnit.SECONDS);
|
||||||
connectionEvictor.start();
|
connectionEvictor.start();
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
|
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
|
||||||
import org.apache.hc.client5.http.cookie.CookieStore;
|
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.HttpGet;
|
||||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||||
import org.apache.hc.client5.http.protocol.ClientProtocolException;
|
import org.apache.hc.client5.http.protocol.ClientProtocolException;
|
||||||
@ -44,12 +43,10 @@
|
|||||||
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
|
||||||
import org.apache.hc.core5.http.HttpException;
|
import org.apache.hc.core5.http.HttpException;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.HttpRequest;
|
|
||||||
import org.apache.hc.core5.http.config.Lookup;
|
import org.apache.hc.core5.http.config.Lookup;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,7 +56,6 @@
|
|||||||
public class TestInternalHttpClient {
|
public class TestInternalHttpClient {
|
||||||
|
|
||||||
private ClientExecChain execChain;
|
private ClientExecChain execChain;
|
||||||
private HttpClientConnectionManager connManager;
|
|
||||||
private HttpRoutePlanner routePlanner;
|
private HttpRoutePlanner routePlanner;
|
||||||
private Lookup<CookieSpecProvider> cookieSpecRegistry;
|
private Lookup<CookieSpecProvider> cookieSpecRegistry;
|
||||||
private Lookup<AuthSchemeProvider> authSchemeRegistry;
|
private Lookup<AuthSchemeProvider> authSchemeRegistry;
|
||||||
@ -75,7 +71,6 @@ public class TestInternalHttpClient {
|
|||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
execChain = Mockito.mock(ClientExecChain.class);
|
execChain = Mockito.mock(ClientExecChain.class);
|
||||||
connManager = Mockito.mock(HttpClientConnectionManager.class);
|
|
||||||
routePlanner = Mockito.mock(HttpRoutePlanner.class);
|
routePlanner = Mockito.mock(HttpRoutePlanner.class);
|
||||||
cookieSpecRegistry = Mockito.mock(Lookup.class);
|
cookieSpecRegistry = Mockito.mock(Lookup.class);
|
||||||
authSchemeRegistry = Mockito.mock(Lookup.class);
|
authSchemeRegistry = Mockito.mock(Lookup.class);
|
||||||
@ -85,7 +80,7 @@ public void setup() throws Exception {
|
|||||||
closeable1 = Mockito.mock(Closeable.class);
|
closeable1 = Mockito.mock(Closeable.class);
|
||||||
closeable2 = Mockito.mock(Closeable.class);
|
closeable2 = Mockito.mock(Closeable.class);
|
||||||
|
|
||||||
client = new InternalHttpClient(execChain, connManager, routePlanner,
|
client = new InternalHttpClient(execChain, routePlanner,
|
||||||
cookieSpecRegistry, authSchemeRegistry, cookieStore, credentialsProvider,
|
cookieSpecRegistry, authSchemeRegistry, cookieStore, credentialsProvider,
|
||||||
defaultConfig, Arrays.asList(closeable1, closeable2));
|
defaultConfig, Arrays.asList(closeable1, closeable2));
|
||||||
|
|
||||||
@ -96,17 +91,12 @@ public void testExecute() throws Exception {
|
|||||||
final HttpGet httpget = new HttpGet("http://somehost/stuff");
|
final HttpGet httpget = new HttpGet("http://somehost/stuff");
|
||||||
final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
|
final HttpRoute route = new HttpRoute(new HttpHost("somehost", 80));
|
||||||
|
|
||||||
final ArgumentCaptor<HttpRequest> argcap = ArgumentCaptor.forClass(HttpRequest.class);
|
|
||||||
Mockito.when(routePlanner.determineRoute(
|
Mockito.when(routePlanner.determineRoute(
|
||||||
Mockito.eq(new HttpHost("somehost")),
|
Mockito.eq(new HttpHost("somehost")),
|
||||||
argcap.capture(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
client.execute(httpget);
|
client.execute(httpget);
|
||||||
|
|
||||||
Assert.assertNotNull(argcap.getValue());
|
|
||||||
Assert.assertSame(httpget, argcap.getValue());
|
|
||||||
|
|
||||||
Mockito.verify(execChain).execute(
|
Mockito.verify(execChain).execute(
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
Mockito.<RoutedHttpRequest>any(),
|
||||||
Mockito.<HttpClientContext>any(),
|
Mockito.<HttpClientContext>any(),
|
||||||
@ -120,7 +110,6 @@ public void testExecuteHttpException() throws Exception {
|
|||||||
|
|
||||||
Mockito.when(routePlanner.determineRoute(
|
Mockito.when(routePlanner.determineRoute(
|
||||||
Mockito.eq(new HttpHost("somehost")),
|
Mockito.eq(new HttpHost("somehost")),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
Mockito.when(execChain.execute(
|
Mockito.when(execChain.execute(
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
Mockito.<RoutedHttpRequest>any(),
|
||||||
@ -137,7 +126,6 @@ public void testExecuteDefaultContext() throws Exception {
|
|||||||
|
|
||||||
Mockito.when(routePlanner.determineRoute(
|
Mockito.when(routePlanner.determineRoute(
|
||||||
Mockito.eq(new HttpHost("somehost")),
|
Mockito.eq(new HttpHost("somehost")),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
@ -157,7 +145,6 @@ public void testExecuteRequestConfig() throws Exception {
|
|||||||
|
|
||||||
Mockito.when(routePlanner.determineRoute(
|
Mockito.when(routePlanner.determineRoute(
|
||||||
Mockito.eq(new HttpHost("somehost")),
|
Mockito.eq(new HttpHost("somehost")),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
final RequestConfig config = RequestConfig.custom().build();
|
final RequestConfig config = RequestConfig.custom().build();
|
||||||
@ -176,7 +163,6 @@ public void testExecuteLocalContext() throws Exception {
|
|||||||
|
|
||||||
Mockito.when(routePlanner.determineRoute(
|
Mockito.when(routePlanner.determineRoute(
|
||||||
Mockito.eq(new HttpHost("somehost")),
|
Mockito.eq(new HttpHost("somehost")),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
final HttpClientContext context = HttpClientContext.create();
|
final HttpClientContext context = HttpClientContext.create();
|
||||||
|
@ -49,9 +49,10 @@
|
|||||||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
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.BasicScheme;
|
||||||
import org.apache.hc.client5.http.impl.auth.NTLMScheme;
|
import org.apache.hc.client5.http.impl.auth.NTLMScheme;
|
||||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||||
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.HttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||||
import org.apache.hc.client5.http.methods.HttpGet;
|
import org.apache.hc.client5.http.methods.HttpGet;
|
||||||
import org.apache.hc.client5.http.methods.HttpPost;
|
import org.apache.hc.client5.http.methods.HttpPost;
|
||||||
@ -109,9 +110,9 @@ public class TestMainClientExec {
|
|||||||
@Mock
|
@Mock
|
||||||
private HttpExecutionAware execAware;
|
private HttpExecutionAware execAware;
|
||||||
@Mock
|
@Mock
|
||||||
private ConnectionRequest connRequest;
|
private LeaseRequest connRequest;
|
||||||
@Mock
|
@Mock
|
||||||
private HttpClientConnection managedConn;
|
private ConnectionEndpoint endpoint;
|
||||||
|
|
||||||
private MainClientExec mainClientExec;
|
private MainClientExec mainClientExec;
|
||||||
private HttpHost target;
|
private HttpHost target;
|
||||||
@ -125,10 +126,10 @@ public void setup() throws Exception {
|
|||||||
target = new HttpHost("foo", 80);
|
target = new HttpHost("foo", 80);
|
||||||
proxy = new HttpHost("bar", 8888);
|
proxy = new HttpHost("bar", 8888);
|
||||||
|
|
||||||
Mockito.when(connManager.requestConnection(
|
Mockito.when(connManager.lease(
|
||||||
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
|
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
|
||||||
Mockito.when(connRequest.get(
|
Mockito.when(connRequest.get(
|
||||||
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(managedConn);
|
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -143,24 +144,22 @@ public void testExecRequestNonPersistentConnection() throws Exception {
|
|||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
|
Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
|
||||||
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
||||||
Mockito.verify(connManager).connect(managedConn, route, 123, context);
|
Mockito.verify(connManager).connect(endpoint, 123, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
Mockito.verify(endpoint).setSocketTimeout(234);
|
||||||
Mockito.verify(managedConn).setSocketTimeout(234);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
|
||||||
|
|
||||||
Assert.assertSame(managedConn, context.getConnection());
|
|
||||||
Assert.assertNull(context.getUserToken());
|
Assert.assertNull(context.getUserToken());
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||||
@ -177,11 +176,10 @@ public void testExecRequestPersistentConnection() throws Exception {
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -192,11 +190,11 @@ public void testExecRequestPersistentConnection() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(678L);
|
Mockito.<HttpClientContext>any())).thenReturn(678L);
|
||||||
|
|
||||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 678L, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 678L, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(managedConn, Mockito.never()).close();
|
Mockito.verify(endpoint, Mockito.never()).close();
|
||||||
|
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||||
@ -213,11 +211,10 @@ public void testExecRequestPersistentStatefulConnection() throws Exception {
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -228,11 +225,11 @@ public void testExecRequestPersistentStatefulConnection() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn("this and that");
|
Mockito.<HttpClientContext>any())).thenReturn("this and that");
|
||||||
|
|
||||||
mainClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, "this and that", 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, "this and that", 0, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(managedConn, Mockito.never()).close();
|
Mockito.verify(endpoint, Mockito.never()).close();
|
||||||
|
|
||||||
Assert.assertEquals("this and that", context.getUserToken());
|
Assert.assertEquals("this and that", context.getUserToken());
|
||||||
}
|
}
|
||||||
@ -252,11 +249,10 @@ public void testExecRequestConnectionRelease() throws Exception {
|
|||||||
.setStream(new ByteArrayInputStream(new byte[]{}))
|
.setStream(new ByteArrayInputStream(new byte[]{}))
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -264,23 +260,23 @@ public void testExecRequestConnectionRelease() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
||||||
|
|
||||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(connManager, Mockito.never()).releaseConnection(
|
Mockito.verify(connManager, Mockito.never()).release(
|
||||||
Mockito.same(managedConn),
|
Mockito.same(endpoint),
|
||||||
Mockito.any(),
|
Mockito.any(),
|
||||||
Mockito.anyInt(),
|
Mockito.anyInt(),
|
||||||
Mockito.<TimeUnit>any());
|
Mockito.<TimeUnit>any());
|
||||||
Mockito.verify(managedConn, Mockito.never()).close();
|
Mockito.verify(endpoint, Mockito.never()).close();
|
||||||
|
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||||
finalResponse.close();
|
finalResponse.close();
|
||||||
|
|
||||||
Mockito.verify(connManager, Mockito.times(1)).releaseConnection(
|
Mockito.verify(connManager, Mockito.times(1)).release(
|
||||||
managedConn, null, 0, TimeUnit.MILLISECONDS);
|
endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -291,14 +287,14 @@ public void testSocketTimeoutExistingConnection() throws Exception {
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(true);
|
Mockito.when(endpoint.isConnected()).thenReturn(true);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
Mockito.verify(managedConn).setSocketTimeout(3000);
|
Mockito.verify(endpoint).setSocketTimeout(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -307,14 +303,14 @@ public void testSocketTimeoutReset() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
mainClientExec.execute(request, context, execAware);
|
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)
|
@Test(expected=RequestAbortedException.class)
|
||||||
@ -323,7 +319,7 @@ public void testExecAbortedPriorToConnectionLease() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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);
|
Mockito.when(execAware.isAborted()).thenReturn(Boolean.TRUE);
|
||||||
try {
|
try {
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
@ -343,7 +339,7 @@ public void testExecAbortedPriorToConnectionSetup() throws Exception {
|
|||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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);
|
Mockito.when(execAware.isAborted()).thenReturn(Boolean.FALSE, Boolean.TRUE);
|
||||||
try {
|
try {
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
@ -351,9 +347,9 @@ public void testExecAbortedPriorToConnectionSetup() throws Exception {
|
|||||||
Mockito.verify(connRequest, Mockito.times(1)).get(345, TimeUnit.MILLISECONDS);
|
Mockito.verify(connRequest, Mockito.times(1)).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
||||||
Mockito.verify(connManager, Mockito.never()).connect(
|
Mockito.verify(connManager, Mockito.never()).connect(
|
||||||
Mockito.same(managedConn),
|
Mockito.same(endpoint),
|
||||||
Mockito.<HttpRoute>any(),
|
|
||||||
Mockito.anyInt(),
|
Mockito.anyInt(),
|
||||||
|
Mockito.<TimeUnit>any(),
|
||||||
Mockito.<HttpContext>any());
|
Mockito.<HttpContext>any());
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@ -370,13 +366,13 @@ public void testExecAbortedPriorToRequestExecution() throws Exception {
|
|||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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);
|
Mockito.when(execAware.isAborted()).thenReturn(Boolean.FALSE, Boolean.FALSE, Boolean.TRUE);
|
||||||
try {
|
try {
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
Mockito.verify(connRequest, Mockito.times(1)).get(345, TimeUnit.MILLISECONDS);
|
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.verify(requestExecutor, Mockito.never()).execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpClientConnection>any(),
|
||||||
@ -417,11 +413,10 @@ public void testExecRequestRetryOnAuthChallenge() throws Exception {
|
|||||||
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||||
context.setCredentialsProvider(credentialsProvider);
|
context.setCredentialsProvider(credentialsProvider);
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -434,7 +429,7 @@ public void testExecRequestRetryOnAuthChallenge() throws Exception {
|
|||||||
|
|
||||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(
|
final ClassicHttpResponse finalResponse = mainClientExec.execute(
|
||||||
request, context, execAware);
|
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(instream1).close();
|
||||||
Mockito.verify(instream2, Mockito.never()).close();
|
Mockito.verify(instream2, Mockito.never()).close();
|
||||||
|
|
||||||
@ -469,11 +464,10 @@ public void testExecEntityEnclosingRequestRetryOnAuthChallenge() throws Exceptio
|
|||||||
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||||
context.setCredentialsProvider(credentialsProvider);
|
context.setCredentialsProvider(credentialsProvider);
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -487,8 +481,8 @@ public void testExecEntityEnclosingRequestRetryOnAuthChallenge() throws Exceptio
|
|||||||
|
|
||||||
final ClassicHttpResponse finalResponse = mainClientExec.execute(
|
final ClassicHttpResponse finalResponse = mainClientExec.execute(
|
||||||
request, context, execAware);
|
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(managedConn).close();
|
Mockito.verify(endpoint).close();
|
||||||
Mockito.verify(instream2, Mockito.never()).close();
|
Mockito.verify(instream2, Mockito.never()).close();
|
||||||
|
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
@ -518,11 +512,10 @@ public void testExecEntityEnclosingRequest() throws Exception {
|
|||||||
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||||
context.setCredentialsProvider(credentialsProvider);
|
context.setCredentialsProvider(credentialsProvider);
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenAnswer(new Answer<HttpResponse>() {
|
Mockito.<HttpClientContext>any())).thenAnswer(new Answer<HttpResponse>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -553,9 +546,9 @@ public void testExecConnectionShutDown() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
|
Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
|
||||||
|
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
@ -567,15 +560,15 @@ public void testExecRuntimeException() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
|
Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@ -587,15 +580,15 @@ public void testExecHttpException() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
|
Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@ -607,15 +600,15 @@ public void testExecIOException() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
|
Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mainClientExec.execute(request, context, execAware);
|
mainClientExec.execute(request, context, execAware);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@ -631,12 +624,11 @@ public void testEstablishDirectRoute() throws Exception {
|
|||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -649,12 +641,11 @@ public void testEstablishRouteDirectProxy() throws Exception {
|
|||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -668,20 +659,19 @@ public void testEstablishRouteViaProxyTunnel() throws Exception {
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.<ClassicHttpRequest>any(),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
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).connect(endpoint, 321, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
|
||||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
||||||
Mockito.verify(requestExecutor).execute(
|
Mockito.verify(endpoint).execute(
|
||||||
reqCaptor.capture(),
|
reqCaptor.capture(),
|
||||||
Mockito.same(managedConn),
|
Mockito.same(requestExecutor),
|
||||||
Mockito.same(context));
|
Mockito.same(context));
|
||||||
final HttpRequest connect = reqCaptor.getValue();
|
final HttpRequest connect = reqCaptor.getValue();
|
||||||
Assert.assertNotNull(connect);
|
Assert.assertNotNull(connect);
|
||||||
@ -697,13 +687,13 @@ public void testEstablishRouteViaProxyTunnelUnexpectedResponse() throws Exceptio
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(101, "Lost");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(101, "Lost");
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.<ClassicHttpRequest>any(),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = HttpException.class)
|
@Test(expected = HttpException.class)
|
||||||
@ -714,20 +704,18 @@ public void testEstablishRouteViaProxyTunnelFailure() throws Exception {
|
|||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(500, "Boom");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(500, "Boom");
|
||||||
response.setEntity(new StringEntity("Ka-boom"));
|
response.setEntity(new StringEntity("Ka-boom"));
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.<ClassicHttpRequest>any(),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mainClientExec.establishRoute(managedConn, route, request, context);
|
mainClientExec.establishRoute(endpoint, route, request, context);
|
||||||
} catch (final TunnelRefusedException ex) {
|
} catch (final TunnelRefusedException ex) {
|
||||||
final ClassicHttpResponse r = ex.getResponse();
|
final ClassicHttpResponse r = ex.getResponse();
|
||||||
Assert.assertEquals("Ka-boom", EntityUtils.toString(r.getEntity()));
|
Assert.assertEquals("Ka-boom", EntityUtils.toString(r.getEntity()));
|
||||||
|
Mockito.verify(endpoint).close();
|
||||||
Mockito.verify(managedConn).close();
|
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,14 +741,14 @@ public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengePersistentConnec
|
|||||||
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||||
context.setCredentialsProvider(credentialsProvider);
|
context.setCredentialsProvider(credentialsProvider);
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpResponse>any(),
|
Mockito.<HttpResponse>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
Mockito.<HttpClientContext>any())).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.<ClassicHttpRequest>any(),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||||
|
|
||||||
Mockito.when(proxyAuthStrategy.select(
|
Mockito.when(proxyAuthStrategy.select(
|
||||||
@ -768,10 +756,9 @@ public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengePersistentConnec
|
|||||||
Mockito.<Map<String, AuthChallenge>>any(),
|
Mockito.<Map<String, AuthChallenge>>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
|
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).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
|
||||||
Mockito.verify(instream1).close();
|
Mockito.verify(instream1).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,14 +783,14 @@ public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengeNonPersistentCon
|
|||||||
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
|
||||||
context.setCredentialsProvider(credentialsProvider);
|
context.setCredentialsProvider(credentialsProvider);
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpResponse>any(),
|
Mockito.<HttpResponse>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.<ClassicHttpRequest>any(),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
Mockito.<HttpClientContext>any())).thenReturn(response1, response2);
|
||||||
|
|
||||||
Mockito.when(proxyAuthStrategy.select(
|
Mockito.when(proxyAuthStrategy.select(
|
||||||
@ -811,12 +798,11 @@ public void testEstablishRouteViaProxyTunnelRetryOnAuthChallengeNonPersistentCon
|
|||||||
Mockito.<Map<String, AuthChallenge>>any(),
|
Mockito.<Map<String, AuthChallenge>>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(Collections.<AuthScheme>singletonList(new BasicScheme()));
|
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).connect(endpoint, 567, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
|
||||||
Mockito.verify(instream1, Mockito.never()).close();
|
Mockito.verify(instream1, Mockito.never()).close();
|
||||||
Mockito.verify(managedConn).close();
|
Mockito.verify(endpoint).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = HttpException.class)
|
@Test(expected = HttpException.class)
|
||||||
@ -828,9 +814,9 @@ public void testEstablishRouteViaProxyTunnelMultipleHops() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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.HttpRoute;
|
import org.apache.hc.client5.http.HttpRoute;
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.entity.EntityBuilder;
|
import org.apache.hc.client5.http.entity.EntityBuilder;
|
||||||
import org.apache.hc.client5.http.impl.io.ConnectionShutdownException;
|
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
|
||||||
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.HttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.io.LeaseRequest;
|
||||||
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
import org.apache.hc.client5.http.methods.HttpExecutionAware;
|
||||||
import org.apache.hc.client5.http.methods.HttpGet;
|
import org.apache.hc.client5.http.methods.HttpGet;
|
||||||
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
import org.apache.hc.client5.http.methods.RoutedHttpRequest;
|
||||||
@ -50,7 +51,6 @@
|
|||||||
import org.apache.hc.core5.http.HttpException;
|
import org.apache.hc.core5.http.HttpException;
|
||||||
import org.apache.hc.core5.http.HttpHost;
|
import org.apache.hc.core5.http.HttpHost;
|
||||||
import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
|
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.apache.hc.core5.http.message.BasicClassicHttpResponse;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -74,9 +74,9 @@ public class TestMinimalClientExec {
|
|||||||
@Mock
|
@Mock
|
||||||
private HttpExecutionAware execAware;
|
private HttpExecutionAware execAware;
|
||||||
@Mock
|
@Mock
|
||||||
private ConnectionRequest connRequest;
|
private LeaseRequest connRequest;
|
||||||
@Mock
|
@Mock
|
||||||
private HttpClientConnection managedConn;
|
private ConnectionEndpoint endpoint;
|
||||||
|
|
||||||
private MinimalClientExec minimalClientExec;
|
private MinimalClientExec minimalClientExec;
|
||||||
private HttpHost target;
|
private HttpHost target;
|
||||||
@ -88,10 +88,10 @@ public void setup() throws Exception {
|
|||||||
requestExecutor, connManager, reuseStrategy, keepAliveStrategy);
|
requestExecutor, connManager, reuseStrategy, keepAliveStrategy);
|
||||||
target = new HttpHost("foo", 80);
|
target = new HttpHost("foo", 80);
|
||||||
|
|
||||||
Mockito.when(connManager.requestConnection(
|
Mockito.when(connManager.lease(
|
||||||
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
|
Mockito.<HttpRoute>any(), Mockito.any())).thenReturn(connRequest);
|
||||||
Mockito.when(connRequest.get(
|
Mockito.when(connRequest.get(
|
||||||
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(managedConn);
|
Mockito.anyLong(), Mockito.<TimeUnit>any())).thenReturn(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -106,24 +106,22 @@ public void testExecRequestNonPersistentConnection() throws Exception {
|
|||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
final ClassicHttpResponse finalResponse = minimalClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
|
Mockito.verify(execAware, Mockito.times(1)).setCancellable(connRequest);
|
||||||
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
Mockito.verify(execAware, Mockito.times(2)).setCancellable(Mockito.<Cancellable>any());
|
||||||
Mockito.verify(connManager).connect(managedConn, route, 123, context);
|
Mockito.verify(connManager).connect(endpoint, 123, TimeUnit.MILLISECONDS, context);
|
||||||
Mockito.verify(connManager).routeComplete(managedConn, route, context);
|
Mockito.verify(endpoint).setSocketTimeout(234);
|
||||||
Mockito.verify(managedConn).setSocketTimeout(234);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
|
||||||
|
|
||||||
Assert.assertSame(managedConn, context.getConnection());
|
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||||
}
|
}
|
||||||
@ -141,11 +139,10 @@ public void testExecRequestPersistentConnection() throws Exception {
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -156,11 +153,11 @@ public void testExecRequestPersistentConnection() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(678L);
|
Mockito.<HttpClientContext>any())).thenReturn(678L);
|
||||||
|
|
||||||
final ClassicHttpResponse finalResponse = minimalClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 678L, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 678L, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(managedConn, Mockito.never()).close();
|
Mockito.verify(endpoint, Mockito.never()).close();
|
||||||
|
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||||
@ -183,11 +180,10 @@ public void testExecRequestConnectionRelease() throws Exception {
|
|||||||
.setStream(new ByteArrayInputStream(new byte[]{}))
|
.setStream(new ByteArrayInputStream(new byte[]{}))
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(managedConn.isStale()).thenReturn(Boolean.FALSE);
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.when(requestExecutor.execute(
|
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
Mockito.when(reuseStrategy.keepAlive(
|
Mockito.when(reuseStrategy.keepAlive(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
@ -195,23 +191,23 @@ public void testExecRequestConnectionRelease() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
|
||||||
|
|
||||||
final ClassicHttpResponse finalResponse = minimalClientExec.execute(request, context, execAware);
|
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(connRequest).get(345, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(requestExecutor, Mockito.times(1)).execute(request, managedConn, context);
|
Mockito.verify(endpoint, Mockito.times(1)).execute(request, requestExecutor, context);
|
||||||
Mockito.verify(connManager, Mockito.never()).releaseConnection(
|
Mockito.verify(connManager, Mockito.never()).release(
|
||||||
Mockito.same(managedConn),
|
Mockito.same(endpoint),
|
||||||
Mockito.any(),
|
Mockito.any(),
|
||||||
Mockito.anyInt(),
|
Mockito.anyInt(),
|
||||||
Mockito.<TimeUnit>any());
|
Mockito.<TimeUnit>any());
|
||||||
Mockito.verify(managedConn, Mockito.never()).close();
|
Mockito.verify(endpoint, Mockito.never()).close();
|
||||||
|
|
||||||
Assert.assertNotNull(finalResponse);
|
Assert.assertNotNull(finalResponse);
|
||||||
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
Assert.assertTrue(finalResponse instanceof CloseableHttpResponse);
|
||||||
finalResponse.close();
|
finalResponse.close();
|
||||||
|
|
||||||
Mockito.verify(connManager, Mockito.times(1)).releaseConnection(
|
Mockito.verify(connManager, Mockito.times(1)).release(
|
||||||
managedConn, null, 0, TimeUnit.MILLISECONDS);
|
endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
Mockito.verify(managedConn, Mockito.times(1)).close();
|
Mockito.verify(endpoint, Mockito.times(1)).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -222,14 +218,14 @@ public void testSocketTimeoutExistingConnection() throws Exception {
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
context.setRequestConfig(config);
|
context.setRequestConfig(config);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(true);
|
Mockito.when(endpoint.isConnected()).thenReturn(true);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
Mockito.verify(managedConn).setSocketTimeout(3000);
|
Mockito.verify(endpoint).setSocketTimeout(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -238,14 +234,14 @@ public void testSocketTimeoutReset() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
|
||||||
Mockito.when(managedConn.isOpen()).thenReturn(Boolean.TRUE);
|
Mockito.when(endpoint.isConnected()).thenReturn(Boolean.TRUE);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.same(request),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
minimalClientExec.execute(request, context, execAware);
|
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)
|
@Test(expected=RequestAbortedException.class)
|
||||||
@ -254,7 +250,7 @@ public void testExecAbortedPriorToConnectionLease() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
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);
|
Mockito.when(execAware.isAborted()).thenReturn(Boolean.TRUE);
|
||||||
try {
|
try {
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
@ -281,9 +277,9 @@ public void testExecConnectionShutDown() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
|
Mockito.<HttpClientContext>any())).thenThrow(new ConnectionShutdownException());
|
||||||
|
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
@ -295,16 +291,15 @@ public void testExecRuntimeException() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
|
Mockito.<HttpClientContext>any())).thenThrow(new RuntimeException("Ka-boom"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,16 +310,15 @@ public void testExecHttpException() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
|
Mockito.<HttpClientContext>any())).thenThrow(new HttpException("Ka-boom"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,16 +329,15 @@ public void testExecIOException() throws Exception {
|
|||||||
final HttpClientContext context = new HttpClientContext();
|
final HttpClientContext context = new HttpClientContext();
|
||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
|
Mockito.<HttpClientContext>any())).thenThrow(new IOException("Ka-boom"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
Mockito.verify(connManager).releaseConnection(managedConn, null, 0, TimeUnit.MILLISECONDS);
|
Mockito.verify(connManager).release(endpoint, null, 0, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,15 +349,15 @@ public void absoluteUriIsRewrittenToRelativeBeforeBeingPassedInRequestLine() thr
|
|||||||
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
final RoutedHttpRequest request = RoutedHttpRequest.adapt(new HttpGet("http://bar/test"), route);
|
||||||
|
|
||||||
final ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
|
final ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
|
||||||
Mockito.when(requestExecutor.execute(
|
Mockito.when(endpoint.execute(
|
||||||
Mockito.<ClassicHttpRequest>any(),
|
Mockito.same(request),
|
||||||
Mockito.<HttpClientConnection>any(),
|
Mockito.<HttpRequestExecutor>any(),
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(response);
|
Mockito.<HttpClientContext>any())).thenReturn(response);
|
||||||
|
|
||||||
minimalClientExec.execute(request, context, execAware);
|
minimalClientExec.execute(request, context, execAware);
|
||||||
|
|
||||||
final ArgumentCaptor<ClassicHttpRequest> reqCaptor = ArgumentCaptor.forClass(ClassicHttpRequest.class);
|
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());
|
Assert.assertEquals("/test", reqCaptor.getValue().getRequestUri());
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,6 @@ public void testFundamentals() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||||
Mockito.when(httpRoutePlanner.determineRoute(
|
Mockito.when(httpRoutePlanner.determineRoute(
|
||||||
Mockito.eq(target),
|
Mockito.eq(target),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
redirectExec.execute(request, context, execAware);
|
redirectExec.execute(request, context, execAware);
|
||||||
@ -173,7 +172,6 @@ public void testMaxRedirect() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||||
Mockito.when(httpRoutePlanner.determineRoute(
|
Mockito.when(httpRoutePlanner.determineRoute(
|
||||||
Mockito.eq(target),
|
Mockito.eq(target),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
redirectExec.execute(request, context, execAware);
|
redirectExec.execute(request, context, execAware);
|
||||||
@ -207,7 +205,6 @@ public void testRelativeRedirect() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||||
Mockito.when(httpRoutePlanner.determineRoute(
|
Mockito.when(httpRoutePlanner.determineRoute(
|
||||||
Mockito.eq(target),
|
Mockito.eq(target),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(route);
|
Mockito.<HttpClientContext>any())).thenReturn(route);
|
||||||
|
|
||||||
redirectExec.execute(request, context, execAware);
|
redirectExec.execute(request, context, execAware);
|
||||||
@ -253,11 +250,9 @@ public void testCrossSiteRedirect() throws Exception {
|
|||||||
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
Mockito.<HttpClientContext>any())).thenReturn(redirect);
|
||||||
Mockito.when(httpRoutePlanner.determineRoute(
|
Mockito.when(httpRoutePlanner.determineRoute(
|
||||||
Mockito.eq(target),
|
Mockito.eq(target),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(target));
|
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(target));
|
||||||
Mockito.when(httpRoutePlanner.determineRoute(
|
Mockito.when(httpRoutePlanner.determineRoute(
|
||||||
Mockito.eq(otherHost),
|
Mockito.eq(otherHost),
|
||||||
Mockito.<RoutedHttpRequest>any(),
|
|
||||||
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(otherHost));
|
Mockito.<HttpClientContext>any())).thenReturn(new HttpRoute(otherHost));
|
||||||
|
|
||||||
redirectExec.execute(request, context, execAware);
|
redirectExec.execute(request, context, execAware);
|
||||||
|
@ -43,7 +43,7 @@ public class TestResponseEntityWrapper {
|
|||||||
|
|
||||||
private InputStream instream;
|
private InputStream instream;
|
||||||
private HttpEntity entity;
|
private HttpEntity entity;
|
||||||
private ConnectionHolder connHolder;
|
private EndpointHolder endpointHolder;
|
||||||
private ResponseEntityProxy wrapper;
|
private ResponseEntityProxy wrapper;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@ -51,83 +51,83 @@ public void setup() throws Exception {
|
|||||||
instream = Mockito.mock(InputStream.class);
|
instream = Mockito.mock(InputStream.class);
|
||||||
entity = Mockito.mock(HttpEntity.class);
|
entity = Mockito.mock(HttpEntity.class);
|
||||||
Mockito.when(entity.getContent()).thenReturn(instream);
|
Mockito.when(entity.getContent()).thenReturn(instream);
|
||||||
connHolder = Mockito.mock(ConnectionHolder.class);
|
endpointHolder = Mockito.mock(EndpointHolder.class);
|
||||||
wrapper = new ResponseEntityProxy(entity, connHolder);
|
wrapper = new ResponseEntityProxy(entity, endpointHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReusableEntityStreamClosed() throws Exception {
|
public void testReusableEntityStreamClosed() throws Exception {
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||||
EntityUtils.consume(wrapper);
|
EntityUtils.consume(wrapper);
|
||||||
|
|
||||||
Mockito.verify(instream, Mockito.times(1)).close();
|
Mockito.verify(instream, Mockito.times(1)).close();
|
||||||
Mockito.verify(connHolder).releaseConnection();
|
Mockito.verify(endpointHolder).releaseConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReusableEntityStreamClosedIOError() throws Exception {
|
public void testReusableEntityStreamClosedIOError() throws Exception {
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
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();
|
Mockito.doThrow(new IOException()).when(instream).close();
|
||||||
try {
|
try {
|
||||||
EntityUtils.consume(wrapper);
|
EntityUtils.consume(wrapper);
|
||||||
Assert.fail("IOException expected");
|
Assert.fail("IOException expected");
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
}
|
}
|
||||||
Mockito.verify(connHolder).abortConnection();
|
Mockito.verify(endpointHolder).abortConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEntityStreamClosedIOErrorAlreadyReleased() throws Exception {
|
public void testEntityStreamClosedIOErrorAlreadyReleased() throws Exception {
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||||
Mockito.when(connHolder.isReleased()).thenReturn(true);
|
Mockito.when(endpointHolder.isReleased()).thenReturn(true);
|
||||||
Mockito.doThrow(new SocketException()).when(instream).close();
|
Mockito.doThrow(new SocketException()).when(instream).close();
|
||||||
EntityUtils.consume(wrapper);
|
EntityUtils.consume(wrapper);
|
||||||
Mockito.verify(connHolder).close();
|
Mockito.verify(endpointHolder).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReusableEntityWriteTo() throws Exception {
|
public void testReusableEntityWriteTo() throws Exception {
|
||||||
final OutputStream outstream = Mockito.mock(OutputStream.class);
|
final OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||||
wrapper.writeTo(outstream);
|
wrapper.writeTo(outstream);
|
||||||
Mockito.verify(connHolder).releaseConnection();
|
Mockito.verify(endpointHolder).releaseConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReusableEntityWriteToIOError() throws Exception {
|
public void testReusableEntityWriteToIOError() throws Exception {
|
||||||
final OutputStream outstream = Mockito.mock(OutputStream.class);
|
final OutputStream outstream = Mockito.mock(OutputStream.class);
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
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);
|
Mockito.doThrow(new IOException()).when(entity).writeTo(outstream);
|
||||||
try {
|
try {
|
||||||
wrapper.writeTo(outstream);
|
wrapper.writeTo(outstream);
|
||||||
Assert.fail("IOException expected");
|
Assert.fail("IOException expected");
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
}
|
}
|
||||||
Mockito.verify(connHolder, Mockito.never()).releaseConnection();
|
Mockito.verify(endpointHolder, Mockito.never()).releaseConnection();
|
||||||
Mockito.verify(connHolder).abortConnection();
|
Mockito.verify(endpointHolder).abortConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReusableEntityEndOfStream() throws Exception {
|
public void testReusableEntityEndOfStream() throws Exception {
|
||||||
Mockito.when(instream.read()).thenReturn(-1);
|
Mockito.when(instream.read()).thenReturn(-1);
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
Mockito.when(entity.isStreaming()).thenReturn(true);
|
||||||
Mockito.when(connHolder.isReusable()).thenReturn(true);
|
Mockito.when(endpointHolder.isReusable()).thenReturn(true);
|
||||||
final InputStream content = wrapper.getContent();
|
final InputStream content = wrapper.getContent();
|
||||||
Assert.assertEquals(-1, content.read());
|
Assert.assertEquals(-1, content.read());
|
||||||
Mockito.verify(instream).close();
|
Mockito.verify(instream).close();
|
||||||
Mockito.verify(connHolder).releaseConnection();
|
Mockito.verify(endpointHolder).releaseConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReusableEntityEndOfStreamIOError() throws Exception {
|
public void testReusableEntityEndOfStreamIOError() throws Exception {
|
||||||
Mockito.when(instream.read()).thenReturn(-1);
|
Mockito.when(instream.read()).thenReturn(-1);
|
||||||
Mockito.when(entity.isStreaming()).thenReturn(true);
|
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();
|
Mockito.doThrow(new IOException()).when(instream).close();
|
||||||
final InputStream content = wrapper.getContent();
|
final InputStream content = wrapper.getContent();
|
||||||
try {
|
try {
|
||||||
@ -135,7 +135,7 @@ public void testReusableEntityEndOfStreamIOError() throws Exception {
|
|||||||
Assert.fail("IOException expected");
|
Assert.fail("IOException expected");
|
||||||
} catch (final IOException ex) {
|
} catch (final IOException ex) {
|
||||||
}
|
}
|
||||||
Mockito.verify(connHolder).abortConnection();
|
Mockito.verify(endpointHolder).abortConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user