use of org.apache.http.conn.ClientConnectionRequest in project robolectric by robolectric.
the class DefaultRequestDirector method execute.
// non-javadoc, see interface ClientRequestDirector
public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException, IOException {
HttpRequest orig = request;
RequestWrapper origWrapper = wrapRequest(orig);
origWrapper.setParams(params);
HttpRoute origRoute = determineRoute(target, origWrapper, context);
virtualHost = (HttpHost) orig.getParams().getParameter(ClientPNames.VIRTUAL_HOST);
RoutedRequest roureq = new RoutedRequest(origWrapper, origRoute);
long timeout = ConnManagerParams.getTimeout(params);
int execCount = 0;
boolean reuse = false;
boolean done = false;
try {
HttpResponse response = null;
while (!done) {
// In this loop, the RoutedRequest may be replaced by a
// followup request and route. The request and route passed
// in the method arguments will be replaced. The original
// request is still available in 'orig'.
RequestWrapper wrapper = roureq.getRequest();
HttpRoute route = roureq.getRoute();
response = null;
// See if we have a user token bound to the execution context
Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
// Allocate connection if needed
if (managedConn == null) {
ClientConnectionRequest connRequest = connManager.requestConnection(route, userToken);
if (orig instanceof AbortableHttpRequest) {
((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
}
try {
managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException interrupted) {
InterruptedIOException iox = new InterruptedIOException();
iox.initCause(interrupted);
throw iox;
}
if (HttpConnectionParams.isStaleCheckingEnabled(params)) {
// validate connection
if (managedConn.isOpen()) {
this.log.debug("Stale connection check");
if (managedConn.isStale()) {
this.log.debug("Stale connection detected");
managedConn.close();
}
}
}
}
if (orig instanceof AbortableHttpRequest) {
((AbortableHttpRequest) orig).setReleaseTrigger(managedConn);
}
// Reopen connection if needed
if (!managedConn.isOpen()) {
managedConn.open(route, context, params);
} else {
managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
}
try {
establishRoute(route, context);
} catch (TunnelRefusedException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage());
}
response = ex.getResponse();
break;
}
// Reset headers on the request wrapper
wrapper.resetHeaders();
// Re-write request URI if needed
rewriteRequestURI(wrapper, route);
// Use virtual host if set
target = virtualHost;
if (target == null) {
target = route.getTargetHost();
}
HttpHost proxy = route.getProxyHost();
// Populate the execution context
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
context.setAttribute(ExecutionContext.HTTP_PROXY_HOST, proxy);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, managedConn);
context.setAttribute(ClientContext.TARGET_AUTH_STATE, targetAuthState);
context.setAttribute(ClientContext.PROXY_AUTH_STATE, proxyAuthState);
// Run request protocol interceptors
requestExec.preProcess(wrapper, httpProcessor, context);
boolean retrying = true;
Exception retryReason = null;
while (retrying) {
// Increment total exec count (with redirects)
execCount++;
// Increment exec count for this particular request
wrapper.incrementExecCount();
if (!wrapper.isRepeatable()) {
this.log.debug("Cannot retry non-repeatable request");
if (retryReason != null) {
throw new NonRepeatableRequestException("Cannot retry request " + "with a non-repeatable request entity. The cause lists the " + "reason the original request failed: " + retryReason);
} else {
throw new NonRepeatableRequestException("Cannot retry request " + "with a non-repeatable request entity.");
}
}
try {
if (this.log.isDebugEnabled()) {
this.log.debug("Attempt " + execCount + " to execute request");
}
response = requestExec.execute(wrapper, managedConn, context);
retrying = false;
} catch (IOException ex) {
this.log.debug("Closing the connection.");
managedConn.close();
if (retryHandler.retryRequest(ex, wrapper.getExecCount(), context)) {
if (this.log.isInfoEnabled()) {
this.log.info("I/O exception (" + ex.getClass().getName() + ") caught when processing request: " + ex.getMessage());
}
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
this.log.info("Retrying request");
retryReason = ex;
} else {
throw ex;
}
// just re-open connection and re-try the request
if (!route.isTunnelled()) {
this.log.debug("Reopening the direct connection.");
managedConn.open(route, context, params);
} else {
// otherwise give up
this.log.debug("Proxied connection. Need to start over.");
retrying = false;
}
}
}
if (response == null) {
// Need to start over
continue;
}
// Run response protocol interceptors
response.setParams(params);
requestExec.postProcess(response, httpProcessor, context);
// The connection is in or can be brought to a re-usable state.
reuse = reuseStrategy.keepAlive(response, context);
if (reuse) {
// Set the idle duration of this connection
long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
if (this.log.isDebugEnabled()) {
if (duration >= 0) {
this.log.debug("Connection can be kept alive for " + duration + " ms");
} else {
this.log.debug("Connection can be kept alive indefinitely");
}
}
}
RoutedRequest followup = handleResponse(roureq, response, context);
if (followup == null) {
done = true;
} else {
if (reuse) {
// Make sure the response body is fully consumed, if present
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
// entity consumed above is not an auto-release entity,
// need to mark the connection re-usable explicitly
managedConn.markReusable();
} else {
managedConn.close();
}
// check if we can use the same connection for the followup
if (!followup.getRoute().equals(roureq.getRoute())) {
releaseConnection();
}
roureq = followup;
}
if (managedConn != null && userToken == null) {
userToken = userTokenHandler.getUserToken(context);
context.setAttribute(ClientContext.USER_TOKEN, userToken);
if (userToken != null) {
managedConn.setState(userToken);
}
}
}
// check for entity, release connection if possible
if ((response == null) || (response.getEntity() == null) || !response.getEntity().isStreaming()) {
// connection not needed and (assumed to be) in re-usable state
if (reuse)
managedConn.markReusable();
releaseConnection();
} else {
// install an auto-release entity
HttpEntity entity = response.getEntity();
entity = new BasicManagedEntity(entity, managedConn, reuse);
response.setEntity(entity);
}
return response;
} catch (HttpException | RuntimeException | IOException ex) {
abortConnection();
throw ex;
}
}
use of org.apache.http.conn.ClientConnectionRequest in project jersey by jersey.
the class HelloWorldTest method testConnectionClosingOnExceptionsForErrorResponses.
/**
* JERSEY-2157 reproducer.
* <p>
* The test ensures that entities of the error responses which cause
* WebApplicationException being thrown by a JAX-RS client are buffered
* and that the underlying input connections are automatically released
* in such case.
*/
@Test
public void testConnectionClosingOnExceptionsForErrorResponses() {
final BasicClientConnectionManager cm = new BasicClientConnectionManager();
final AtomicInteger connectionCounter = new AtomicInteger(0);
final ClientConfig config = new ClientConfig().property(ApacheClientProperties.CONNECTION_MANAGER, new ClientConnectionManager() {
@Override
public SchemeRegistry getSchemeRegistry() {
return cm.getSchemeRegistry();
}
@Override
public ClientConnectionRequest requestConnection(final HttpRoute route, final Object state) {
connectionCounter.incrementAndGet();
final ClientConnectionRequest wrappedRequest = cm.requestConnection(route, state);
/**
* To explain the following long piece of code:
*
* All the code does is to just create a wrapper implementations
* for the AHC connection management interfaces.
*
* The only really important piece of code is the
* {@link org.apache.http.conn.ManagedClientConnection#releaseConnection()} implementation,
* where the connectionCounter is decremented when a managed connection instance
* is released by AHC runtime. In our test, this is expected to happen
* as soon as the exception is created for an error response
* (as the error response entity gets buffered in
* {@link org.glassfish.jersey.client.JerseyInvocation#convertToException(javax.ws.rs.core.Response)}).
*/
return new ClientConnectionRequest() {
@Override
public ManagedClientConnection getConnection(long timeout, TimeUnit tunit) throws InterruptedException, ConnectionPoolTimeoutException {
final ManagedClientConnection wrappedConnection = wrappedRequest.getConnection(timeout, tunit);
return new ManagedClientConnection() {
@Override
public boolean isSecure() {
return wrappedConnection.isSecure();
}
@Override
public HttpRoute getRoute() {
return wrappedConnection.getRoute();
}
@Override
public SSLSession getSSLSession() {
return wrappedConnection.getSSLSession();
}
@Override
public void open(HttpRoute route, HttpContext context, HttpParams params) throws IOException {
wrappedConnection.open(route, context, params);
}
@Override
public void tunnelTarget(boolean secure, HttpParams params) throws IOException {
wrappedConnection.tunnelTarget(secure, params);
}
@Override
public void tunnelProxy(HttpHost next, boolean secure, HttpParams params) throws IOException {
wrappedConnection.tunnelProxy(next, secure, params);
}
@Override
public void layerProtocol(HttpContext context, HttpParams params) throws IOException {
wrappedConnection.layerProtocol(context, params);
}
@Override
public void markReusable() {
wrappedConnection.markReusable();
}
@Override
public void unmarkReusable() {
wrappedConnection.unmarkReusable();
}
@Override
public boolean isMarkedReusable() {
return wrappedConnection.isMarkedReusable();
}
@Override
public void setState(Object state) {
wrappedConnection.setState(state);
}
@Override
public Object getState() {
return wrappedConnection.getState();
}
@Override
public void setIdleDuration(long duration, TimeUnit unit) {
wrappedConnection.setIdleDuration(duration, unit);
}
@Override
public boolean isResponseAvailable(int timeout) throws IOException {
return wrappedConnection.isResponseAvailable(timeout);
}
@Override
public void sendRequestHeader(HttpRequest request) throws HttpException, IOException {
wrappedConnection.sendRequestHeader(request);
}
@Override
public void sendRequestEntity(HttpEntityEnclosingRequest request) throws HttpException, IOException {
wrappedConnection.sendRequestEntity(request);
}
@Override
public HttpResponse receiveResponseHeader() throws HttpException, IOException {
return wrappedConnection.receiveResponseHeader();
}
@Override
public void receiveResponseEntity(HttpResponse response) throws HttpException, IOException {
wrappedConnection.receiveResponseEntity(response);
}
@Override
public void flush() throws IOException {
wrappedConnection.flush();
}
@Override
public void close() throws IOException {
wrappedConnection.close();
}
@Override
public boolean isOpen() {
return wrappedConnection.isOpen();
}
@Override
public boolean isStale() {
return wrappedConnection.isStale();
}
@Override
public void setSocketTimeout(int timeout) {
wrappedConnection.setSocketTimeout(timeout);
}
@Override
public int getSocketTimeout() {
return wrappedConnection.getSocketTimeout();
}
@Override
public void shutdown() throws IOException {
wrappedConnection.shutdown();
}
@Override
public HttpConnectionMetrics getMetrics() {
return wrappedConnection.getMetrics();
}
@Override
public InetAddress getLocalAddress() {
return wrappedConnection.getLocalAddress();
}
@Override
public int getLocalPort() {
return wrappedConnection.getLocalPort();
}
@Override
public InetAddress getRemoteAddress() {
return wrappedConnection.getRemoteAddress();
}
@Override
public int getRemotePort() {
return wrappedConnection.getRemotePort();
}
@Override
public void releaseConnection() throws IOException {
connectionCounter.decrementAndGet();
wrappedConnection.releaseConnection();
}
@Override
public void abortConnection() throws IOException {
wrappedConnection.abortConnection();
}
@Override
public String getId() {
return wrappedConnection.getId();
}
@Override
public void bind(Socket socket) throws IOException {
wrappedConnection.bind(socket);
}
@Override
public Socket getSocket() {
return wrappedConnection.getSocket();
}
};
}
@Override
public void abortRequest() {
wrappedRequest.abortRequest();
}
};
}
@Override
public void releaseConnection(ManagedClientConnection conn, long keepalive, TimeUnit tunit) {
cm.releaseConnection(conn, keepalive, tunit);
}
@Override
public void closeExpiredConnections() {
cm.closeExpiredConnections();
}
@Override
public void closeIdleConnections(long idletime, TimeUnit tunit) {
cm.closeIdleConnections(idletime, tunit);
}
@Override
public void shutdown() {
cm.shutdown();
}
});
config.connectorProvider(new ApacheConnectorProvider());
final Client client = ClientBuilder.newClient(config);
final WebTarget rootTarget = client.target(getBaseUri()).path(ROOT_PATH);
// Test that connection is getting closed properly for error responses.
try {
final String response = rootTarget.path("error").request().get(String.class);
fail("Exception expected. Received: " + response);
} catch (InternalServerErrorException isee) {
// do nothing - connection should be closed properly by now
}
// Fail if the previous connection has not been closed automatically.
assertEquals(0, connectionCounter.get());
try {
final String response = rootTarget.path("error2").request().get(String.class);
fail("Exception expected. Received: " + response);
} catch (InternalServerErrorException isee) {
assertEquals("Received unexpected data.", "Error2.", isee.getResponse().readEntity(String.class));
// Test buffering:
// second read would fail if entity was not buffered
assertEquals("Unexpected data in the entity buffer.", "Error2.", isee.getResponse().readEntity(String.class));
}
assertEquals(0, connectionCounter.get());
}
use of org.apache.http.conn.ClientConnectionRequest in project robovm by robovm.
the class DefaultRequestDirector method execute.
// non-javadoc, see interface ClientRequestDirector
public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws HttpException, IOException {
HttpRequest orig = request;
RequestWrapper origWrapper = wrapRequest(orig);
origWrapper.setParams(params);
HttpRoute origRoute = determineRoute(target, origWrapper, context);
RoutedRequest roureq = new RoutedRequest(origWrapper, origRoute);
long timeout = ConnManagerParams.getTimeout(params);
int execCount = 0;
boolean reuse = false;
HttpResponse response = null;
boolean done = false;
try {
while (!done) {
// In this loop, the RoutedRequest may be replaced by a
// followup request and route. The request and route passed
// in the method arguments will be replaced. The original
// request is still available in 'orig'.
RequestWrapper wrapper = roureq.getRequest();
HttpRoute route = roureq.getRoute();
// See if we have a user token bound to the execution context
Object userToken = context.getAttribute(ClientContext.USER_TOKEN);
// Allocate connection if needed
if (managedConn == null) {
ClientConnectionRequest connRequest = connManager.requestConnection(route, userToken);
if (orig instanceof AbortableHttpRequest) {
((AbortableHttpRequest) orig).setConnectionRequest(connRequest);
}
try {
managedConn = connRequest.getConnection(timeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException interrupted) {
InterruptedIOException iox = new InterruptedIOException();
iox.initCause(interrupted);
throw iox;
}
if (HttpConnectionParams.isStaleCheckingEnabled(params)) {
// validate connection
this.log.debug("Stale connection check");
if (managedConn.isStale()) {
this.log.debug("Stale connection detected");
// BEGIN android-changed
try {
managedConn.close();
} catch (IOException ignored) {
// SSLSocket's will throw IOException
// because they can't send a "close
// notify" protocol message to the
// server. Just supresss any
// exceptions related to closing the
// stale connection.
}
// END android-changed
}
}
}
if (orig instanceof AbortableHttpRequest) {
((AbortableHttpRequest) orig).setReleaseTrigger(managedConn);
}
// Reopen connection if needed
if (!managedConn.isOpen()) {
managedConn.open(route, context, params);
} else // BEGIN android-added
{
// b/3241899 set the per request timeout parameter on reused connections
managedConn.setSocketTimeout(HttpConnectionParams.getSoTimeout(params));
}
try {
establishRoute(route, context);
} catch (TunnelRefusedException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage());
}
response = ex.getResponse();
break;
}
// Reset headers on the request wrapper
wrapper.resetHeaders();
// Re-write request URI if needed
rewriteRequestURI(wrapper, route);
// Use virtual host if set
target = (HttpHost) wrapper.getParams().getParameter(ClientPNames.VIRTUAL_HOST);
if (target == null) {
target = route.getTargetHost();
}
HttpHost proxy = route.getProxyHost();
// Populate the execution context
context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, target);
context.setAttribute(ExecutionContext.HTTP_PROXY_HOST, proxy);
context.setAttribute(ExecutionContext.HTTP_CONNECTION, managedConn);
context.setAttribute(ClientContext.TARGET_AUTH_STATE, targetAuthState);
context.setAttribute(ClientContext.PROXY_AUTH_STATE, proxyAuthState);
// Run request protocol interceptors
requestExec.preProcess(wrapper, httpProcessor, context);
context.setAttribute(ExecutionContext.HTTP_REQUEST, wrapper);
boolean retrying = true;
while (retrying) {
// Increment total exec count (with redirects)
execCount++;
// Increment exec count for this particular request
wrapper.incrementExecCount();
if (wrapper.getExecCount() > 1 && !wrapper.isRepeatable()) {
throw new NonRepeatableRequestException("Cannot retry request " + "with a non-repeatable request entity");
}
try {
if (this.log.isDebugEnabled()) {
this.log.debug("Attempt " + execCount + " to execute request");
}
response = requestExec.execute(wrapper, managedConn, context);
retrying = false;
} catch (IOException ex) {
this.log.debug("Closing the connection.");
managedConn.close();
if (retryHandler.retryRequest(ex, execCount, context)) {
if (this.log.isInfoEnabled()) {
this.log.info("I/O exception (" + ex.getClass().getName() + ") caught when processing request: " + ex.getMessage());
}
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
this.log.info("Retrying request");
} else {
throw ex;
}
// just re-open connection and re-try the request
if (route.getHopCount() == 1) {
this.log.debug("Reopening the direct connection.");
managedConn.open(route, context, params);
} else {
// otherwise give up
throw ex;
}
}
}
// Run response protocol interceptors
response.setParams(params);
requestExec.postProcess(response, httpProcessor, context);
// The connection is in or can be brought to a re-usable state.
reuse = reuseStrategy.keepAlive(response, context);
if (reuse) {
// Set the idle duration of this connection
long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
managedConn.setIdleDuration(duration, TimeUnit.MILLISECONDS);
}
RoutedRequest followup = handleResponse(roureq, response, context);
if (followup == null) {
done = true;
} else {
if (reuse) {
this.log.debug("Connection kept alive");
// Make sure the response body is fully consumed, if present
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
// entity consumed above is not an auto-release entity,
// need to mark the connection re-usable explicitly
managedConn.markReusable();
} else {
managedConn.close();
}
// check if we can use the same connection for the followup
if (!followup.getRoute().equals(roureq.getRoute())) {
releaseConnection();
}
roureq = followup;
}
userToken = this.userTokenHandler.getUserToken(context);
context.setAttribute(ClientContext.USER_TOKEN, userToken);
if (managedConn != null) {
managedConn.setState(userToken);
}
}
// check for entity, release connection if possible
if ((response == null) || (response.getEntity() == null) || !response.getEntity().isStreaming()) {
// connection not needed and (assumed to be) in re-usable state
if (reuse)
managedConn.markReusable();
releaseConnection();
} else {
// install an auto-release entity
HttpEntity entity = response.getEntity();
entity = new BasicManagedEntity(entity, managedConn, reuse);
response.setEntity(entity);
}
return response;
} catch (HttpException ex) {
abortConnection();
throw ex;
} catch (IOException ex) {
abortConnection();
throw ex;
} catch (RuntimeException ex) {
abortConnection();
throw ex;
}
}
use of org.apache.http.conn.ClientConnectionRequest in project robovm by robovm.
the class HttpRequestBase method abort.
public void abort() {
ClientConnectionRequest localRequest;
ConnectionReleaseTrigger localTrigger;
this.abortLock.lock();
try {
if (this.aborted) {
return;
}
this.aborted = true;
localRequest = connRequest;
localTrigger = releaseTrigger;
} finally {
this.abortLock.unlock();
}
// setReleaseTrigger or setConnectionRequest.
if (localRequest != null) {
localRequest.abortRequest();
}
if (localTrigger != null) {
try {
localTrigger.abortConnection();
} catch (IOException ex) {
// ignore
}
}
}
use of org.apache.http.conn.ClientConnectionRequest in project XobotOS by xamarin.
the class HttpRequestBase method abort.
public void abort() {
ClientConnectionRequest localRequest;
ConnectionReleaseTrigger localTrigger;
this.abortLock.lock();
try {
if (this.aborted) {
return;
}
this.aborted = true;
localRequest = connRequest;
localTrigger = releaseTrigger;
} finally {
this.abortLock.unlock();
}
// setReleaseTrigger or setConnectionRequest.
if (localRequest != null) {
localRequest.abortRequest();
}
if (localTrigger != null) {
try {
localTrigger.abortConnection();
} catch (IOException ex) {
// ignore
}
}
}
Aggregations