Issue #1053 - Drop support Android and remove Fennec - Part 1a: Remove mobile/android

This commit is contained in:
Matt A. Tobin 2019-04-23 15:32:23 -04:00 committed by Roy Tam
commit c9b411d6cd
3891 changed files with 0 additions and 428084 deletions

View file

@ -1,104 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.client.BackoffManager;
import ch.boye.httpclientandroidlib.client.ConnectionBackoffStrategy;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.util.Args;
/**
* @since 4.3
*/
@Immutable
public class BackoffStrategyExec implements ClientExecChain {
private final ClientExecChain requestExecutor;
private final ConnectionBackoffStrategy connectionBackoffStrategy;
private final BackoffManager backoffManager;
public BackoffStrategyExec(
final ClientExecChain requestExecutor,
final ConnectionBackoffStrategy connectionBackoffStrategy,
final BackoffManager backoffManager) {
super();
Args.notNull(requestExecutor, "HTTP client request executor");
Args.notNull(connectionBackoffStrategy, "Connection backoff strategy");
Args.notNull(backoffManager, "Backoff manager");
this.requestExecutor = requestExecutor;
this.connectionBackoffStrategy = connectionBackoffStrategy;
this.backoffManager = backoffManager;
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
Args.notNull(route, "HTTP route");
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
CloseableHttpResponse out = null;
try {
out = this.requestExecutor.execute(route, request, context, execAware);
} catch (final Exception ex) {
if (out != null) {
out.close();
}
if (this.connectionBackoffStrategy.shouldBackoff(ex)) {
this.backoffManager.backOff(route);
}
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
if (ex instanceof HttpException) {
throw (HttpException) ex;
}
if (ex instanceof IOException) {
throw (IOException) ex;
}
throw new UndeclaredThrowableException(ex);
}
if (this.connectionBackoffStrategy.shouldBackoff(out)) {
this.backoffManager.backOff(route);
} else {
this.backoffManager.probe(route);
}
return out;
}
}

View file

@ -1,74 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
/**
* This interface represents an element in the HTTP request execution chain. Each element can
* either be a decorator around another element that implements a cross cutting aspect or
* a self-contained executor capable of producing a response for the given request.
* <p/>
* Important: please note it is required for decorators that implement post execution aspects
* or response post-processing of any sort to release resources associated with the response
* by calling {@link CloseableHttpResponse#close()} methods in case of an I/O, protocol or
* runtime exception, or in case the response is not propagated to the caller.
*
* @since 4.3
*/
public interface ClientExecChain {
/**
* Executes th request either by transmitting it to the target server or
* by passing it onto the next executor in the request execution chain.
*
* @param route connection route.
* @param request current request.
* @param clientContext current HTTP context.
* @param execAware receiver of notifications of blocking I/O operations.
* @return HTTP response either received from the opposite endpoint
* or generated locally.
* @throws IOException in case of a I/O error.
* (this type of exceptions are potentially recoverable).
* @throws HttpException in case of an HTTP protocol error
* (usually this type of exceptions are non-recoverable).
*/
CloseableHttpResponse execute(
HttpRoute route,
HttpRequestWrapper request,
HttpClientContext clientContext,
HttpExecutionAware execAware) throws IOException, HttpException;
}

View file

@ -1,153 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
import ch.boye.httpclientandroidlib.HttpClientConnection;
import ch.boye.httpclientandroidlib.annotation.ThreadSafe;
import ch.boye.httpclientandroidlib.concurrent.Cancellable;
import ch.boye.httpclientandroidlib.conn.ConnectionReleaseTrigger;
import ch.boye.httpclientandroidlib.conn.HttpClientConnectionManager;
/**
* Internal connection holder.
*
* @since 4.3
*/
@ThreadSafe
class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable {
public HttpClientAndroidLog log;
private final HttpClientConnectionManager manager;
private final HttpClientConnection managedConn;
private volatile boolean reusable;
private volatile Object state;
private volatile long validDuration;
private volatile TimeUnit tunit;
private volatile boolean released;
public ConnectionHolder(
final HttpClientAndroidLog log,
final HttpClientConnectionManager manager,
final HttpClientConnection managedConn) {
super();
this.log = log;
this.manager = manager;
this.managedConn = managedConn;
}
public boolean isReusable() {
return this.reusable;
}
public void markReusable() {
this.reusable = true;
}
public void markNonReusable() {
this.reusable = false;
}
public void setState(final Object state) {
this.state = state;
}
public void setValidFor(final long duration, final TimeUnit tunit) {
synchronized (this.managedConn) {
this.validDuration = duration;
this.tunit = tunit;
}
}
public void releaseConnection() {
synchronized (this.managedConn) {
if (this.released) {
return;
}
this.released = true;
if (this.reusable) {
this.manager.releaseConnection(this.managedConn,
this.state, this.validDuration, this.tunit);
} else {
try {
this.managedConn.close();
log.debug("Connection discarded");
} catch (final IOException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
} finally {
this.manager.releaseConnection(
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
}
}
}
}
public void abortConnection() {
synchronized (this.managedConn) {
if (this.released) {
return;
}
this.released = true;
try {
this.managedConn.shutdown();
log.debug("Connection discarded");
} catch (final IOException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
} finally {
this.manager.releaseConnection(
this.managedConn, null, 0, TimeUnit.MILLISECONDS);
}
}
}
public boolean cancel() {
final boolean alreadyReleased = this.released;
log.debug("Cancelling request execution");
abortConnection();
return !alreadyReleased;
}
public boolean isReleased() {
return this.released;
}
public void close() throws IOException {
abortConnection();
}
}

View file

@ -1,185 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.util.Locale;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HeaderIterator;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.ProtocolVersion;
import ch.boye.httpclientandroidlib.StatusLine;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.params.HttpParams;
/**
* A proxy class for {@link ch.boye.httpclientandroidlib.HttpResponse} that can be used to release client connection
* associated with the original response.
*
* @since 4.3
*/
@NotThreadSafe
class HttpResponseProxy implements CloseableHttpResponse {
private final HttpResponse original;
private final ConnectionHolder connHolder;
public HttpResponseProxy(final HttpResponse original, final ConnectionHolder connHolder) {
this.original = original;
this.connHolder = connHolder;
ResponseEntityProxy.enchance(original, connHolder);
}
public void close() throws IOException {
if (this.connHolder != null) {
this.connHolder.abortConnection();
}
}
public StatusLine getStatusLine() {
return original.getStatusLine();
}
public void setStatusLine(final StatusLine statusline) {
original.setStatusLine(statusline);
}
public void setStatusLine(final ProtocolVersion ver, final int code) {
original.setStatusLine(ver, code);
}
public void setStatusLine(final ProtocolVersion ver, final int code, final String reason) {
original.setStatusLine(ver, code, reason);
}
public void setStatusCode(final int code) throws IllegalStateException {
original.setStatusCode(code);
}
public void setReasonPhrase(final String reason) throws IllegalStateException {
original.setReasonPhrase(reason);
}
public HttpEntity getEntity() {
return original.getEntity();
}
public void setEntity(final HttpEntity entity) {
original.setEntity(entity);
}
public Locale getLocale() {
return original.getLocale();
}
public void setLocale(final Locale loc) {
original.setLocale(loc);
}
public ProtocolVersion getProtocolVersion() {
return original.getProtocolVersion();
}
public boolean containsHeader(final String name) {
return original.containsHeader(name);
}
public Header[] getHeaders(final String name) {
return original.getHeaders(name);
}
public Header getFirstHeader(final String name) {
return original.getFirstHeader(name);
}
public Header getLastHeader(final String name) {
return original.getLastHeader(name);
}
public Header[] getAllHeaders() {
return original.getAllHeaders();
}
public void addHeader(final Header header) {
original.addHeader(header);
}
public void addHeader(final String name, final String value) {
original.addHeader(name, value);
}
public void setHeader(final Header header) {
original.setHeader(header);
}
public void setHeader(final String name, final String value) {
original.setHeader(name, value);
}
public void setHeaders(final Header[] headers) {
original.setHeaders(headers);
}
public void removeHeader(final Header header) {
original.removeHeader(header);
}
public void removeHeaders(final String name) {
original.removeHeaders(name);
}
public HeaderIterator headerIterator() {
return original.headerIterator();
}
public HeaderIterator headerIterator(final String name) {
return original.headerIterator(name);
}
@Deprecated
public HttpParams getParams() {
return original.getParams();
}
@Deprecated
public void setParams(final HttpParams params) {
original.setParams(params);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("HttpResponseProxy{");
sb.append(original);
sb.append('}');
return sb.toString();
}
}

View file

@ -1,568 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
/* LogFactory removed by HttpClient for Android script. */
import ch.boye.httpclientandroidlib.ConnectionReuseStrategy;
import ch.boye.httpclientandroidlib.HttpClientConnection;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.HttpRequest;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.auth.AUTH;
import ch.boye.httpclientandroidlib.auth.AuthProtocolState;
import ch.boye.httpclientandroidlib.auth.AuthState;
import ch.boye.httpclientandroidlib.client.AuthenticationStrategy;
import ch.boye.httpclientandroidlib.client.NonRepeatableRequestException;
import ch.boye.httpclientandroidlib.client.UserTokenHandler;
import ch.boye.httpclientandroidlib.client.config.RequestConfig;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.client.protocol.RequestClientConnControl;
import ch.boye.httpclientandroidlib.conn.ConnectionKeepAliveStrategy;
import ch.boye.httpclientandroidlib.conn.ConnectionRequest;
import ch.boye.httpclientandroidlib.conn.HttpClientConnectionManager;
import ch.boye.httpclientandroidlib.conn.routing.BasicRouteDirector;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.conn.routing.HttpRouteDirector;
import ch.boye.httpclientandroidlib.conn.routing.RouteTracker;
import ch.boye.httpclientandroidlib.entity.BufferedHttpEntity;
import ch.boye.httpclientandroidlib.impl.auth.HttpAuthenticator;
import ch.boye.httpclientandroidlib.impl.conn.ConnectionShutdownException;
import ch.boye.httpclientandroidlib.message.BasicHttpRequest;
import ch.boye.httpclientandroidlib.protocol.HttpCoreContext;
import ch.boye.httpclientandroidlib.protocol.HttpProcessor;
import ch.boye.httpclientandroidlib.protocol.HttpRequestExecutor;
import ch.boye.httpclientandroidlib.protocol.ImmutableHttpProcessor;
import ch.boye.httpclientandroidlib.protocol.RequestTargetHost;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.EntityUtils;
/**
* The last request executor in the HTTP request execution chain
* that is responsible for execution of request / response
* exchanges with the opposite endpoint.
* This executor will automatically retry the request in case
* of an authentication challenge by an intermediate proxy or
* by the target server.
*
* @since 4.3
*/
@Immutable
public class MainClientExec implements ClientExecChain {
public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
private final HttpRequestExecutor requestExecutor;
private final HttpClientConnectionManager connManager;
private final ConnectionReuseStrategy reuseStrategy;
private final ConnectionKeepAliveStrategy keepAliveStrategy;
private final HttpProcessor proxyHttpProcessor;
private final AuthenticationStrategy targetAuthStrategy;
private final AuthenticationStrategy proxyAuthStrategy;
private final HttpAuthenticator authenticator;
private final UserTokenHandler userTokenHandler;
private final HttpRouteDirector routeDirector;
public MainClientExec(
final HttpRequestExecutor requestExecutor,
final HttpClientConnectionManager connManager,
final ConnectionReuseStrategy reuseStrategy,
final ConnectionKeepAliveStrategy keepAliveStrategy,
final AuthenticationStrategy targetAuthStrategy,
final AuthenticationStrategy proxyAuthStrategy,
final UserTokenHandler userTokenHandler) {
Args.notNull(requestExecutor, "HTTP request executor");
Args.notNull(connManager, "Client connection manager");
Args.notNull(reuseStrategy, "Connection reuse strategy");
Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
Args.notNull(targetAuthStrategy, "Target authentication strategy");
Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
Args.notNull(userTokenHandler, "User token handler");
this.authenticator = new HttpAuthenticator();
this.proxyHttpProcessor = new ImmutableHttpProcessor(
new RequestTargetHost(), new RequestClientConnControl());
this.routeDirector = new BasicRouteDirector();
this.requestExecutor = requestExecutor;
this.connManager = connManager;
this.reuseStrategy = reuseStrategy;
this.keepAliveStrategy = keepAliveStrategy;
this.targetAuthStrategy = targetAuthStrategy;
this.proxyAuthStrategy = proxyAuthStrategy;
this.userTokenHandler = userTokenHandler;
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
Args.notNull(route, "HTTP route");
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
AuthState targetAuthState = context.getTargetAuthState();
if (targetAuthState == null) {
targetAuthState = new AuthState();
context.setAttribute(HttpClientContext.TARGET_AUTH_STATE, targetAuthState);
}
AuthState proxyAuthState = context.getProxyAuthState();
if (proxyAuthState == null) {
proxyAuthState = new AuthState();
context.setAttribute(HttpClientContext.PROXY_AUTH_STATE, proxyAuthState);
}
if (request instanceof HttpEntityEnclosingRequest) {
RequestEntityProxy.enhance((HttpEntityEnclosingRequest) request);
}
Object userToken = context.getUserToken();
final ConnectionRequest connRequest = connManager.requestConnection(route, userToken);
if (execAware != null) {
if (execAware.isAborted()) {
connRequest.cancel();
throw new RequestAbortedException("Request aborted");
} else {
execAware.setCancellable(connRequest);
}
}
final RequestConfig config = context.getRequestConfig();
final HttpClientConnection managedConn;
try {
final int timeout = config.getConnectionRequestTimeout();
managedConn = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
} catch(final InterruptedException interrupted) {
Thread.currentThread().interrupt();
throw new RequestAbortedException("Request aborted", interrupted);
} catch(final ExecutionException ex) {
Throwable cause = ex.getCause();
if (cause == null) {
cause = ex;
}
throw new RequestAbortedException("Request execution failed", cause);
}
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
if (config.isStaleConnectionCheckEnabled()) {
// validate connection
if (managedConn.isOpen()) {
this.log.debug("Stale connection check");
if (managedConn.isStale()) {
this.log.debug("Stale connection detected");
managedConn.close();
}
}
}
final ConnectionHolder connHolder = new ConnectionHolder(this.log, this.connManager, managedConn);
try {
if (execAware != null) {
execAware.setCancellable(connHolder);
}
HttpResponse response;
for (int execCount = 1;; execCount++) {
if (execCount > 1 && !RequestEntityProxy.isRepeatable(request)) {
throw new NonRepeatableRequestException("Cannot retry request " +
"with a non-repeatable request entity.");
}
if (execAware != null && execAware.isAborted()) {
throw new RequestAbortedException("Request aborted");
}
if (!managedConn.isOpen()) {
this.log.debug("Opening connection " + route);
try {
establishRoute(proxyAuthState, managedConn, route, request, context);
} catch (final TunnelRefusedException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage());
}
response = ex.getResponse();
break;
}
}
final int timeout = config.getSocketTimeout();
if (timeout >= 0) {
managedConn.setSocketTimeout(timeout);
}
if (execAware != null && execAware.isAborted()) {
throw new RequestAbortedException("Request aborted");
}
if (this.log.isDebugEnabled()) {
this.log.debug("Executing request " + request.getRequestLine());
}
if (!request.containsHeader(AUTH.WWW_AUTH_RESP)) {
if (this.log.isDebugEnabled()) {
this.log.debug("Target auth state: " + targetAuthState.getState());
}
this.authenticator.generateAuthResponse(request, targetAuthState, context);
}
if (!request.containsHeader(AUTH.PROXY_AUTH_RESP) && !route.isTunnelled()) {
if (this.log.isDebugEnabled()) {
this.log.debug("Proxy auth state: " + proxyAuthState.getState());
}
this.authenticator.generateAuthResponse(request, proxyAuthState, context);
}
response = requestExecutor.execute(request, managedConn, context);
// The connection is in or can be brought to a re-usable state.
if (reuseStrategy.keepAlive(response, context)) {
// Set the idle duration of this connection
final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
if (this.log.isDebugEnabled()) {
final String s;
if (duration > 0) {
s = "for " + duration + " " + TimeUnit.MILLISECONDS;
} else {
s = "indefinitely";
}
this.log.debug("Connection can be kept alive " + s);
}
connHolder.setValidFor(duration, TimeUnit.MILLISECONDS);
connHolder.markReusable();
} else {
connHolder.markNonReusable();
}
if (needAuthentication(
targetAuthState, proxyAuthState, route, response, context)) {
// Make sure the response body is fully consumed, if present
final HttpEntity entity = response.getEntity();
if (connHolder.isReusable()) {
EntityUtils.consume(entity);
} else {
managedConn.close();
if (proxyAuthState.getState() == AuthProtocolState.SUCCESS
&& proxyAuthState.getAuthScheme() != null
&& proxyAuthState.getAuthScheme().isConnectionBased()) {
this.log.debug("Resetting proxy auth state");
proxyAuthState.reset();
}
if (targetAuthState.getState() == AuthProtocolState.SUCCESS
&& targetAuthState.getAuthScheme() != null
&& targetAuthState.getAuthScheme().isConnectionBased()) {
this.log.debug("Resetting target auth state");
targetAuthState.reset();
}
}
// discard previous auth headers
final HttpRequest original = request.getOriginal();
if (!original.containsHeader(AUTH.WWW_AUTH_RESP)) {
request.removeHeaders(AUTH.WWW_AUTH_RESP);
}
if (!original.containsHeader(AUTH.PROXY_AUTH_RESP)) {
request.removeHeaders(AUTH.PROXY_AUTH_RESP);
}
} else {
break;
}
}
if (userToken == null) {
userToken = userTokenHandler.getUserToken(context);
context.setAttribute(HttpClientContext.USER_TOKEN, userToken);
}
if (userToken != null) {
connHolder.setState(userToken);
}
// check for entity, release connection if possible
final HttpEntity entity = response.getEntity();
if (entity == null || !entity.isStreaming()) {
// connection not needed and (assumed to be) in re-usable state
connHolder.releaseConnection();
return new HttpResponseProxy(response, null);
} else {
return new HttpResponseProxy(response, connHolder);
}
} catch (final ConnectionShutdownException ex) {
final InterruptedIOException ioex = new InterruptedIOException(
"Connection has been shut down");
ioex.initCause(ex);
throw ioex;
} catch (final HttpException ex) {
connHolder.abortConnection();
throw ex;
} catch (final IOException ex) {
connHolder.abortConnection();
throw ex;
} catch (final RuntimeException ex) {
connHolder.abortConnection();
throw ex;
}
}
/**
* Establishes the target route.
*/
void establishRoute(
final AuthState proxyAuthState,
final HttpClientConnection managedConn,
final HttpRoute route,
final HttpRequest request,
final HttpClientContext context) throws HttpException, IOException {
final RequestConfig config = context.getRequestConfig();
final int timeout = config.getConnectTimeout();
final RouteTracker tracker = new RouteTracker(route);
int step;
do {
final HttpRoute fact = tracker.toRoute();
step = this.routeDirector.nextStep(route, fact);
switch (step) {
case HttpRouteDirector.CONNECT_TARGET:
this.connManager.connect(
managedConn,
route,
timeout > 0 ? timeout : 0,
context);
tracker.connectTarget(route.isSecure());
break;
case HttpRouteDirector.CONNECT_PROXY:
this.connManager.connect(
managedConn,
route,
timeout > 0 ? timeout : 0,
context);
final HttpHost proxy = route.getProxyHost();
tracker.connectProxy(proxy, false);
break;
case HttpRouteDirector.TUNNEL_TARGET: {
final boolean secure = createTunnelToTarget(
proxyAuthState, managedConn, route, request, context);
this.log.debug("Tunnel to target created.");
tracker.tunnelTarget(secure);
} break;
case HttpRouteDirector.TUNNEL_PROXY: {
// The most simple example for this case is a proxy chain
// of two proxies, where P1 must be tunnelled to P2.
// route: Source -> P1 -> P2 -> Target (3 hops)
// fact: Source -> P1 -> Target (2 hops)
final int hop = fact.getHopCount()-1; // the hop to establish
final boolean secure = createTunnelToProxy(route, hop, context);
this.log.debug("Tunnel to proxy created.");
tracker.tunnelProxy(route.getHopTarget(hop), secure);
} break;
case HttpRouteDirector.LAYER_PROTOCOL:
this.connManager.upgrade(managedConn, route, context);
tracker.layerProtocol(route.isSecure());
break;
case HttpRouteDirector.UNREACHABLE:
throw new HttpException("Unable to establish route: " +
"planned = " + route + "; current = " + fact);
case HttpRouteDirector.COMPLETE:
this.connManager.routeComplete(managedConn, route, context);
break;
default:
throw new IllegalStateException("Unknown step indicator "
+ step + " from RouteDirector.");
}
} while (step > HttpRouteDirector.COMPLETE);
}
/**
* Creates a tunnel to the target server.
* The connection must be established to the (last) proxy.
* A CONNECT request for tunnelling through the proxy will
* be created and sent, the response received and checked.
* This method does <i>not</i> update the connection with
* information about the tunnel, that is left to the caller.
*/
private boolean createTunnelToTarget(
final AuthState proxyAuthState,
final HttpClientConnection managedConn,
final HttpRoute route,
final HttpRequest request,
final HttpClientContext context) throws HttpException, IOException {
final RequestConfig config = context.getRequestConfig();
final int timeout = config.getConnectTimeout();
final HttpHost target = route.getTargetHost();
final HttpHost proxy = route.getProxyHost();
HttpResponse response = null;
final String authority = target.toHostString();
final HttpRequest connect = new BasicHttpRequest("CONNECT", authority, request.getProtocolVersion());
this.requestExecutor.preProcess(connect, this.proxyHttpProcessor, context);
while (response == null) {
if (!managedConn.isOpen()) {
this.connManager.connect(
managedConn,
route,
timeout > 0 ? timeout : 0,
context);
}
connect.removeHeaders(AUTH.PROXY_AUTH_RESP);
this.authenticator.generateAuthResponse(connect, proxyAuthState, context);
response = this.requestExecutor.execute(connect, managedConn, context);
final int status = response.getStatusLine().getStatusCode();
if (status < 200) {
throw new HttpException("Unexpected response to CONNECT request: " +
response.getStatusLine());
}
if (config.isAuthenticationEnabled()) {
if (this.authenticator.isAuthenticationRequested(proxy, response,
this.proxyAuthStrategy, proxyAuthState, context)) {
if (this.authenticator.handleAuthChallenge(proxy, response,
this.proxyAuthStrategy, proxyAuthState, context)) {
// Retry request
if (this.reuseStrategy.keepAlive(response, context)) {
this.log.debug("Connection kept alive");
// Consume response content
final HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
} else {
managedConn.close();
}
response = null;
}
}
}
}
final int status = response.getStatusLine().getStatusCode();
if (status > 299) {
// Buffer response content
final HttpEntity entity = response.getEntity();
if (entity != null) {
response.setEntity(new BufferedHttpEntity(entity));
}
managedConn.close();
throw new TunnelRefusedException("CONNECT refused by proxy: " +
response.getStatusLine(), response);
}
// How to decide on security of the tunnelled connection?
// The socket factory knows only about the segment to the proxy.
// Even if that is secure, the hop to the target may be insecure.
// Leave it to derived classes, consider insecure by default here.
return false;
}
/**
* Creates a tunnel to an intermediate proxy.
* This method is <i>not</i> implemented in this class.
* It just throws an exception here.
*/
private boolean createTunnelToProxy(
final HttpRoute route,
final int hop,
final HttpClientContext context) throws HttpException {
// Have a look at createTunnelToTarget and replicate the parts
// you need in a custom derived class. If your proxies don't require
// authentication, it is not too hard. But for the stock version of
// HttpClient, we cannot make such simplifying assumptions and would
// have to include proxy authentication code. The HttpComponents team
// is currently not in a position to support rarely used code of this
// complexity. Feel free to submit patches that refactor the code in
// createTunnelToTarget to facilitate re-use for proxy tunnelling.
throw new HttpException("Proxy chains are not supported.");
}
private boolean needAuthentication(
final AuthState targetAuthState,
final AuthState proxyAuthState,
final HttpRoute route,
final HttpResponse response,
final HttpClientContext context) {
final RequestConfig config = context.getRequestConfig();
if (config.isAuthenticationEnabled()) {
HttpHost target = context.getTargetHost();
if (target == null) {
target = route.getTargetHost();
}
if (target.getPort() < 0) {
target = new HttpHost(
target.getHostName(),
route.getTargetHost().getPort(),
target.getSchemeName());
}
final boolean targetAuthRequested = this.authenticator.isAuthenticationRequested(
target, response, this.targetAuthStrategy, targetAuthState, context);
HttpHost proxy = route.getProxyHost();
// if proxy is not set use target host instead
if (proxy == null) {
proxy = route.getTargetHost();
}
final boolean proxyAuthRequested = this.authenticator.isAuthenticationRequested(
proxy, response, this.proxyAuthStrategy, proxyAuthState, context);
if (targetAuthRequested) {
return this.authenticator.handleAuthChallenge(target, response,
this.targetAuthStrategy, targetAuthState, context);
}
if (proxyAuthRequested) {
return this.authenticator.handleAuthChallenge(proxy, response,
this.proxyAuthStrategy, proxyAuthState, context);
}
}
return false;
}
}

View file

@ -1,251 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
/* LogFactory removed by HttpClient for Android script. */
import ch.boye.httpclientandroidlib.ConnectionReuseStrategy;
import ch.boye.httpclientandroidlib.HttpClientConnection;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.HttpRequest;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.ProtocolException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.client.config.RequestConfig;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.client.protocol.RequestClientConnControl;
import ch.boye.httpclientandroidlib.client.utils.URIUtils;
import ch.boye.httpclientandroidlib.conn.ConnectionKeepAliveStrategy;
import ch.boye.httpclientandroidlib.conn.ConnectionRequest;
import ch.boye.httpclientandroidlib.conn.HttpClientConnectionManager;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.impl.conn.ConnectionShutdownException;
import ch.boye.httpclientandroidlib.protocol.HttpCoreContext;
import ch.boye.httpclientandroidlib.protocol.HttpProcessor;
import ch.boye.httpclientandroidlib.protocol.HttpRequestExecutor;
import ch.boye.httpclientandroidlib.protocol.ImmutableHttpProcessor;
import ch.boye.httpclientandroidlib.protocol.RequestContent;
import ch.boye.httpclientandroidlib.protocol.RequestTargetHost;
import ch.boye.httpclientandroidlib.protocol.RequestUserAgent;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.VersionInfo;
/**
* Request executor that implements the most fundamental aspects of
* the HTTP specification and the most straight-forward request / response
* exchange with the target server. This executor does not support
* execution via proxy and will make no attempts to retry the request
* in case of a redirect, authentication challenge or I/O error.
*
* @since 4.3
*/
@Immutable
public class MinimalClientExec implements ClientExecChain {
public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
private final HttpRequestExecutor requestExecutor;
private final HttpClientConnectionManager connManager;
private final ConnectionReuseStrategy reuseStrategy;
private final ConnectionKeepAliveStrategy keepAliveStrategy;
private final HttpProcessor httpProcessor;
public MinimalClientExec(
final HttpRequestExecutor requestExecutor,
final HttpClientConnectionManager connManager,
final ConnectionReuseStrategy reuseStrategy,
final ConnectionKeepAliveStrategy keepAliveStrategy) {
Args.notNull(requestExecutor, "HTTP request executor");
Args.notNull(connManager, "Client connection manager");
Args.notNull(reuseStrategy, "Connection reuse strategy");
Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
this.httpProcessor = new ImmutableHttpProcessor(
new RequestContent(),
new RequestTargetHost(),
new RequestClientConnControl(),
new RequestUserAgent(VersionInfo.getUserAgent(
"Apache-HttpClient", "ch.boye.httpclientandroidlib.client", getClass())));
this.requestExecutor = requestExecutor;
this.connManager = connManager;
this.reuseStrategy = reuseStrategy;
this.keepAliveStrategy = keepAliveStrategy;
}
static void rewriteRequestURI(
final HttpRequestWrapper request,
final HttpRoute route) throws ProtocolException {
try {
URI uri = request.getURI();
if (uri != null) {
// Make sure the request URI is relative
if (uri.isAbsolute()) {
uri = URIUtils.rewriteURI(uri, null, true);
} else {
uri = URIUtils.rewriteURI(uri);
}
request.setURI(uri);
}
} catch (final URISyntaxException ex) {
throw new ProtocolException("Invalid URI: " + request.getRequestLine().getUri(), ex);
}
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
Args.notNull(route, "HTTP route");
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
rewriteRequestURI(request, route);
final ConnectionRequest connRequest = connManager.requestConnection(route, null);
if (execAware != null) {
if (execAware.isAborted()) {
connRequest.cancel();
throw new RequestAbortedException("Request aborted");
} else {
execAware.setCancellable(connRequest);
}
}
final RequestConfig config = context.getRequestConfig();
final HttpClientConnection managedConn;
try {
final int timeout = config.getConnectionRequestTimeout();
managedConn = connRequest.get(timeout > 0 ? timeout : 0, TimeUnit.MILLISECONDS);
} catch(final InterruptedException interrupted) {
Thread.currentThread().interrupt();
throw new RequestAbortedException("Request aborted", interrupted);
} catch(final ExecutionException ex) {
Throwable cause = ex.getCause();
if (cause == null) {
cause = ex;
}
throw new RequestAbortedException("Request execution failed", cause);
}
final ConnectionHolder releaseTrigger = new ConnectionHolder(log, connManager, managedConn);
try {
if (execAware != null) {
if (execAware.isAborted()) {
releaseTrigger.close();
throw new RequestAbortedException("Request aborted");
} else {
execAware.setCancellable(releaseTrigger);
}
}
if (!managedConn.isOpen()) {
final int timeout = config.getConnectTimeout();
this.connManager.connect(
managedConn,
route,
timeout > 0 ? timeout : 0,
context);
this.connManager.routeComplete(managedConn, route, context);
}
final int timeout = config.getSocketTimeout();
if (timeout >= 0) {
managedConn.setSocketTimeout(timeout);
}
HttpHost target = null;
final HttpRequest original = request.getOriginal();
if (original instanceof HttpUriRequest) {
final URI uri = ((HttpUriRequest) original).getURI();
if (uri.isAbsolute()) {
target = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
}
}
if (target == null) {
target = route.getTargetHost();
}
context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, managedConn);
context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
httpProcessor.process(request, context);
final HttpResponse response = requestExecutor.execute(request, managedConn, context);
httpProcessor.process(response, context);
// The connection is in or can be brought to a re-usable state.
if (reuseStrategy.keepAlive(response, context)) {
// Set the idle duration of this connection
final long duration = keepAliveStrategy.getKeepAliveDuration(response, context);
releaseTrigger.setValidFor(duration, TimeUnit.MILLISECONDS);
releaseTrigger.markReusable();
} else {
releaseTrigger.markNonReusable();
}
// check for entity, release connection if possible
final HttpEntity entity = response.getEntity();
if (entity == null || !entity.isStreaming()) {
// connection not needed and (assumed to be) in re-usable state
releaseTrigger.releaseConnection();
return new HttpResponseProxy(response, null);
} else {
return new HttpResponseProxy(response, releaseTrigger);
}
} catch (final ConnectionShutdownException ex) {
final InterruptedIOException ioex = new InterruptedIOException(
"Connection has been shut down");
ioex.initCause(ex);
throw ioex;
} catch (final HttpException ex) {
releaseTrigger.abortConnection();
throw ex;
} catch (final IOException ex) {
releaseTrigger.abortConnection();
throw ex;
} catch (final RuntimeException ex) {
releaseTrigger.abortConnection();
throw ex;
}
}
}

View file

@ -1,214 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
/* LogFactory removed by HttpClient for Android script. */
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.HttpRequest;
import ch.boye.httpclientandroidlib.ProtocolException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.auth.AuthScope;
import ch.boye.httpclientandroidlib.auth.UsernamePasswordCredentials;
import ch.boye.httpclientandroidlib.client.CredentialsProvider;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.methods.HttpUriRequest;
import ch.boye.httpclientandroidlib.client.params.ClientPNames;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.client.utils.URIUtils;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.impl.client.BasicCredentialsProvider;
import ch.boye.httpclientandroidlib.params.HttpParams;
import ch.boye.httpclientandroidlib.protocol.HttpCoreContext;
import ch.boye.httpclientandroidlib.protocol.HttpProcessor;
import ch.boye.httpclientandroidlib.util.Args;
/**
* Request executor in the request execution chain that is responsible
* for implementation of HTTP specification requirements.
* Internally this executor relies on a {@link HttpProcessor} to populate
* requisite HTTP request headers, process HTTP response headers and update
* session state in {@link HttpClientContext}.
* <p/>
* Further responsibilities such as communication with the opposite
* endpoint is delegated to the next executor in the request execution
* chain.
*
* @since 4.3
*/
@Immutable
@SuppressWarnings("deprecation")
public class ProtocolExec implements ClientExecChain {
public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
private final ClientExecChain requestExecutor;
private final HttpProcessor httpProcessor;
public ProtocolExec(final ClientExecChain requestExecutor, final HttpProcessor httpProcessor) {
Args.notNull(requestExecutor, "HTTP client request executor");
Args.notNull(httpProcessor, "HTTP protocol processor");
this.requestExecutor = requestExecutor;
this.httpProcessor = httpProcessor;
}
void rewriteRequestURI(
final HttpRequestWrapper request,
final HttpRoute route) throws ProtocolException {
try {
URI uri = request.getURI();
if (uri != null) {
if (route.getProxyHost() != null && !route.isTunnelled()) {
// Make sure the request URI is absolute
if (!uri.isAbsolute()) {
final HttpHost target = route.getTargetHost();
uri = URIUtils.rewriteURI(uri, target, true);
} else {
uri = URIUtils.rewriteURI(uri);
}
} else {
// Make sure the request URI is relative
if (uri.isAbsolute()) {
uri = URIUtils.rewriteURI(uri, null, true);
} else {
uri = URIUtils.rewriteURI(uri);
}
}
request.setURI(uri);
}
} catch (final URISyntaxException ex) {
throw new ProtocolException("Invalid URI: " + request.getRequestLine().getUri(), ex);
}
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException,
HttpException {
Args.notNull(route, "HTTP route");
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
final HttpRequest original = request.getOriginal();
URI uri = null;
if (original instanceof HttpUriRequest) {
uri = ((HttpUriRequest) original).getURI();
} else {
final String uriString = original.getRequestLine().getUri();
try {
uri = URI.create(uriString);
} catch (final IllegalArgumentException ex) {
if (this.log.isDebugEnabled()) {
this.log.debug("Unable to parse '" + uriString + "' as a valid URI; " +
"request URI and Host header may be inconsistent", ex);
}
}
}
request.setURI(uri);
// Re-write request URI if needed
rewriteRequestURI(request, route);
final HttpParams params = request.getParams();
HttpHost virtualHost = (HttpHost) params.getParameter(ClientPNames.VIRTUAL_HOST);
// HTTPCLIENT-1092 - add the port if necessary
if (virtualHost != null && virtualHost.getPort() == -1) {
final int port = route.getTargetHost().getPort();
if (port != -1) {
virtualHost = new HttpHost(virtualHost.getHostName(), port,
virtualHost.getSchemeName());
}
if (this.log.isDebugEnabled()) {
this.log.debug("Using virtual host" + virtualHost);
}
}
HttpHost target = null;
if (virtualHost != null) {
target = virtualHost;
} else {
if (uri != null && uri.isAbsolute() && uri.getHost() != null) {
target = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
}
}
if (target == null) {
target = route.getTargetHost();
}
// Get user info from the URI
if (uri != null) {
final String userinfo = uri.getUserInfo();
if (userinfo != null) {
CredentialsProvider credsProvider = context.getCredentialsProvider();
if (credsProvider == null) {
credsProvider = new BasicCredentialsProvider();
context.setCredentialsProvider(credsProvider);
}
credsProvider.setCredentials(
new AuthScope(target),
new UsernamePasswordCredentials(userinfo));
}
}
// Run request protocol interceptors
context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, target);
context.setAttribute(HttpClientContext.HTTP_ROUTE, route);
context.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
this.httpProcessor.process(request, context);
final CloseableHttpResponse response = this.requestExecutor.execute(route, request,
context, execAware);
try {
// Run response protocol interceptors
context.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
this.httpProcessor.process(response, context);
return response;
} catch (final RuntimeException ex) {
response.close();
throw ex;
} catch (final IOException ex) {
response.close();
throw ex;
} catch (final HttpException ex) {
response.close();
throw ex;
}
}
}

View file

@ -1,185 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
/* LogFactory removed by HttpClient for Android script. */
import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.HttpHost;
import ch.boye.httpclientandroidlib.HttpRequest;
import ch.boye.httpclientandroidlib.ProtocolException;
import ch.boye.httpclientandroidlib.annotation.ThreadSafe;
import ch.boye.httpclientandroidlib.auth.AuthScheme;
import ch.boye.httpclientandroidlib.auth.AuthState;
import ch.boye.httpclientandroidlib.client.RedirectException;
import ch.boye.httpclientandroidlib.client.RedirectStrategy;
import ch.boye.httpclientandroidlib.client.config.RequestConfig;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.client.utils.URIUtils;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoutePlanner;
import ch.boye.httpclientandroidlib.util.Args;
import ch.boye.httpclientandroidlib.util.EntityUtils;
/**
* Request executor in the request execution chain that is responsible
* for handling of request redirects.
* <p/>
* Further responsibilities such as communication with the opposite
* endpoint is delegated to the next executor in the request execution
* chain.
*
* @since 4.3
*/
@ThreadSafe
public class RedirectExec implements ClientExecChain {
public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
private final ClientExecChain requestExecutor;
private final RedirectStrategy redirectStrategy;
private final HttpRoutePlanner routePlanner;
public RedirectExec(
final ClientExecChain requestExecutor,
final HttpRoutePlanner routePlanner,
final RedirectStrategy redirectStrategy) {
super();
Args.notNull(requestExecutor, "HTTP client request executor");
Args.notNull(routePlanner, "HTTP route planner");
Args.notNull(redirectStrategy, "HTTP redirect strategy");
this.requestExecutor = requestExecutor;
this.routePlanner = routePlanner;
this.redirectStrategy = redirectStrategy;
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
Args.notNull(route, "HTTP route");
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
final List<URI> redirectLocations = context.getRedirectLocations();
if (redirectLocations != null) {
redirectLocations.clear();
}
final RequestConfig config = context.getRequestConfig();
final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;
HttpRoute currentRoute = route;
HttpRequestWrapper currentRequest = request;
for (int redirectCount = 0;;) {
final CloseableHttpResponse response = requestExecutor.execute(
currentRoute, currentRequest, context, execAware);
try {
if (config.isRedirectsEnabled() &&
this.redirectStrategy.isRedirected(currentRequest, response, context)) {
if (redirectCount >= maxRedirects) {
throw new RedirectException("Maximum redirects ("+ maxRedirects + ") exceeded");
}
redirectCount++;
final HttpRequest redirect = this.redirectStrategy.getRedirect(
currentRequest, response, context);
if (!redirect.headerIterator().hasNext()) {
final HttpRequest original = request.getOriginal();
redirect.setHeaders(original.getAllHeaders());
}
currentRequest = HttpRequestWrapper.wrap(redirect);
if (currentRequest instanceof HttpEntityEnclosingRequest) {
RequestEntityProxy.enhance((HttpEntityEnclosingRequest) currentRequest);
}
final URI uri = currentRequest.getURI();
final HttpHost newTarget = URIUtils.extractHost(uri);
if (newTarget == null) {
throw new ProtocolException("Redirect URI does not specify a valid host name: " +
uri);
}
// Reset virtual host and auth states if redirecting to another host
if (!currentRoute.getTargetHost().equals(newTarget)) {
final AuthState targetAuthState = context.getTargetAuthState();
if (targetAuthState != null) {
this.log.debug("Resetting target auth state");
targetAuthState.reset();
}
final AuthState proxyAuthState = context.getProxyAuthState();
if (proxyAuthState != null) {
final AuthScheme authScheme = proxyAuthState.getAuthScheme();
if (authScheme != null && authScheme.isConnectionBased()) {
this.log.debug("Resetting proxy auth state");
proxyAuthState.reset();
}
}
}
currentRoute = this.routePlanner.determineRoute(newTarget, currentRequest, context);
if (this.log.isDebugEnabled()) {
this.log.debug("Redirecting to '" + uri + "' via " + currentRoute);
}
EntityUtils.consume(response.getEntity());
response.close();
} else {
return response;
}
} catch (final RuntimeException ex) {
response.close();
throw ex;
} catch (final IOException ex) {
response.close();
throw ex;
} catch (final HttpException ex) {
// Protocol exception related to a direct.
// The underlying connection may still be salvaged.
try {
EntityUtils.consume(response.getEntity());
} catch (final IOException ioex) {
this.log.debug("I/O error while releasing connection", ioex);
} finally {
response.close();
}
throw ex;
}
}
}
}

View file

@ -1,55 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.InterruptedIOException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
/**
* Signals that the request has been aborted.
*
* @since 4.3
*/
@Immutable
public class RequestAbortedException extends InterruptedIOException {
private static final long serialVersionUID = 4973849966012490112L;
public RequestAbortedException(final String message) {
super(message);
}
public RequestAbortedException(final String message, final Throwable cause) {
super(message);
if (cause != null) {
initCause(cause);
}
}
}

View file

@ -1,137 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpEntityEnclosingRequest;
import ch.boye.httpclientandroidlib.HttpRequest;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
/**
* A Proxy class for {@link ch.boye.httpclientandroidlib.HttpEntity} enclosed in a request message.
*
* @since 4.3
*/
@NotThreadSafe
class RequestEntityProxy implements HttpEntity {
static void enhance(final HttpEntityEnclosingRequest request) {
final HttpEntity entity = request.getEntity();
if (entity != null && !entity.isRepeatable() && !isEnhanced(entity)) {
request.setEntity(new RequestEntityProxy(entity));
}
}
static boolean isEnhanced(final HttpEntity entity) {
return entity instanceof RequestEntityProxy;
}
static boolean isRepeatable(final HttpRequest request) {
if (request instanceof HttpEntityEnclosingRequest) {
final HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
if (entity != null) {
if (isEnhanced(entity)) {
final RequestEntityProxy proxy = (RequestEntityProxy) entity;
if (!proxy.isConsumed()) {
return true;
}
}
return entity.isRepeatable();
}
}
return true;
}
private final HttpEntity original;
private boolean consumed = false;
RequestEntityProxy(final HttpEntity original) {
super();
this.original = original;
}
public HttpEntity getOriginal() {
return original;
}
public boolean isConsumed() {
return consumed;
}
public boolean isRepeatable() {
return original.isRepeatable();
}
public boolean isChunked() {
return original.isChunked();
}
public long getContentLength() {
return original.getContentLength();
}
public Header getContentType() {
return original.getContentType();
}
public Header getContentEncoding() {
return original.getContentEncoding();
}
public InputStream getContent() throws IOException, IllegalStateException {
return original.getContent();
}
public void writeTo(final OutputStream outstream) throws IOException {
consumed = true;
original.writeTo(outstream);
}
public boolean isStreaming() {
return original.isStreaming();
}
@Deprecated
public void consumeContent() throws IOException {
consumed = true;
original.consumeContent();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("RequestEntityProxy{");
sb.append(original);
sb.append('}');
return sb.toString();
}
}

View file

@ -1,152 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.conn.EofSensorInputStream;
import ch.boye.httpclientandroidlib.conn.EofSensorWatcher;
import ch.boye.httpclientandroidlib.entity.HttpEntityWrapper;
/**
* A wrapper class for {@link HttpEntity} enclosed in a response message.
*
* @since 4.3
*/
@NotThreadSafe
class ResponseEntityProxy extends HttpEntityWrapper implements EofSensorWatcher {
private final ConnectionHolder connHolder;
public static void enchance(final HttpResponse response, final ConnectionHolder connHolder) {
final HttpEntity entity = response.getEntity();
if (entity != null && entity.isStreaming() && connHolder != null) {
response.setEntity(new ResponseEntityProxy(entity, connHolder));
}
}
ResponseEntityProxy(final HttpEntity entity, final ConnectionHolder connHolder) {
super(entity);
this.connHolder = connHolder;
}
private void cleanup() {
if (this.connHolder != null) {
this.connHolder.abortConnection();
}
}
public void releaseConnection() throws IOException {
if (this.connHolder != null) {
try {
if (this.connHolder.isReusable()) {
this.connHolder.releaseConnection();
}
} finally {
cleanup();
}
}
}
@Override
public boolean isRepeatable() {
return false;
}
@Override
public InputStream getContent() throws IOException {
return new EofSensorInputStream(this.wrappedEntity.getContent(), this);
}
@Deprecated
@Override
public void consumeContent() throws IOException {
releaseConnection();
}
@Override
public void writeTo(final OutputStream outstream) throws IOException {
try {
this.wrappedEntity.writeTo(outstream);
releaseConnection();
} finally {
cleanup();
}
}
public boolean eofDetected(final InputStream wrapped) throws IOException {
try {
// there may be some cleanup required, such as
// reading trailers after the response body:
wrapped.close();
releaseConnection();
} finally {
cleanup();
}
return false;
}
public boolean streamClosed(final InputStream wrapped) throws IOException {
try {
final boolean open = connHolder != null && !connHolder.isReleased();
// this assumes that closing the stream will
// consume the remainder of the response body:
try {
wrapped.close();
releaseConnection();
} catch (final SocketException ex) {
if (open) {
throw ex;
}
}
} finally {
cleanup();
}
return false;
}
public boolean streamAbort(final InputStream wrapped) throws IOException {
cleanup();
return false;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ResponseEntityProxy{");
sb.append(wrappedEntity);
sb.append('}');
return sb.toString();
}
}

View file

@ -1,126 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
/* LogFactory removed by HttpClient for Android script. */
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.NoHttpResponseException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.client.HttpRequestRetryHandler;
import ch.boye.httpclientandroidlib.client.NonRepeatableRequestException;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.util.Args;
/**
* Request executor in the request execution chain that is responsible
* for making a decision whether a request failed due to an I/O error
* should be re-executed.
* <p/>
* Further responsibilities such as communication with the opposite
* endpoint is delegated to the next executor in the request execution
* chain.
*
* @since 4.3
*/
@Immutable
public class RetryExec implements ClientExecChain {
public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
private final ClientExecChain requestExecutor;
private final HttpRequestRetryHandler retryHandler;
public RetryExec(
final ClientExecChain requestExecutor,
final HttpRequestRetryHandler retryHandler) {
Args.notNull(requestExecutor, "HTTP request executor");
Args.notNull(retryHandler, "HTTP request retry handler");
this.requestExecutor = requestExecutor;
this.retryHandler = retryHandler;
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
Args.notNull(route, "HTTP route");
Args.notNull(request, "HTTP request");
Args.notNull(context, "HTTP context");
final Header[] origheaders = request.getAllHeaders();
for (int execCount = 1;; execCount++) {
try {
return this.requestExecutor.execute(route, request, context, execAware);
} catch (final IOException ex) {
if (execAware != null && execAware.isAborted()) {
this.log.debug("Request has been aborted");
throw ex;
}
if (retryHandler.retryRequest(ex, execCount, context)) {
if (this.log.isInfoEnabled()) {
this.log.info("I/O exception ("+ ex.getClass().getName() +
") caught when processing request to "
+ route +
": "
+ ex.getMessage());
}
if (this.log.isDebugEnabled()) {
this.log.debug(ex.getMessage(), ex);
}
if (!RequestEntityProxy.isRepeatable(request)) {
this.log.debug("Cannot retry non-repeatable request");
throw new NonRepeatableRequestException("Cannot retry request " +
"with a non-repeatable request entity", ex);
}
request.setHeaders(origheaders);
if (this.log.isInfoEnabled()) {
this.log.info("Retrying request to " + route);
}
} else {
if (ex instanceof NoHttpResponseException) {
final NoHttpResponseException updatedex = new NoHttpResponseException(
route.getTargetHost().toHostString() + " failed to respond");
updatedex.setStackTrace(ex.getStackTrace());
throw updatedex;
} else {
throw ex;
}
}
}
}
}
}

View file

@ -1,108 +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 ch.boye.httpclientandroidlib.impl.execchain;
import java.io.IOException;
import java.io.InterruptedIOException;
import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
/* LogFactory removed by HttpClient for Android script. */
import ch.boye.httpclientandroidlib.Header;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.annotation.Immutable;
import ch.boye.httpclientandroidlib.client.ServiceUnavailableRetryStrategy;
import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
import ch.boye.httpclientandroidlib.client.methods.HttpExecutionAware;
import ch.boye.httpclientandroidlib.client.methods.HttpRequestWrapper;
import ch.boye.httpclientandroidlib.client.protocol.HttpClientContext;
import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
import ch.boye.httpclientandroidlib.util.Args;
/**
* Request executor in the request execution chain that is responsible
* for making a decision whether a request that received a non-2xx response
* from the target server should be re-executed.
* <p/>
* Further responsibilities such as communication with the opposite
* endpoint is delegated to the next executor in the request execution
* chain.
*
* @since 4.3
*/
@Immutable
public class ServiceUnavailableRetryExec implements ClientExecChain {
public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
private final ClientExecChain requestExecutor;
private final ServiceUnavailableRetryStrategy retryStrategy;
public ServiceUnavailableRetryExec(
final ClientExecChain requestExecutor,
final ServiceUnavailableRetryStrategy retryStrategy) {
super();
Args.notNull(requestExecutor, "HTTP request executor");
Args.notNull(retryStrategy, "Retry strategy");
this.requestExecutor = requestExecutor;
this.retryStrategy = retryStrategy;
}
public CloseableHttpResponse execute(
final HttpRoute route,
final HttpRequestWrapper request,
final HttpClientContext context,
final HttpExecutionAware execAware) throws IOException, HttpException {
final Header[] origheaders = request.getAllHeaders();
for (int c = 1;; c++) {
final CloseableHttpResponse response = this.requestExecutor.execute(
route, request, context, execAware);
try {
if (this.retryStrategy.retryRequest(response, c, context)) {
response.close();
final long nextInterval = this.retryStrategy.getRetryInterval();
if (nextInterval > 0) {
try {
this.log.trace("Wait for " + nextInterval);
Thread.sleep(nextInterval);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new InterruptedIOException();
}
}
request.setHeaders(origheaders);
} else {
return response;
}
} catch (final RuntimeException ex) {
response.close();
throw ex;
}
}
}
}

View file

@ -1,55 +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 ch.boye.httpclientandroidlib.impl.execchain;
import ch.boye.httpclientandroidlib.HttpException;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.annotation.Immutable;
/**
* Signals that the tunnel request was rejected by the proxy host.
*
* @since 4.0
*/
@Immutable
public class TunnelRefusedException extends HttpException {
private static final long serialVersionUID = -8646722842745617323L;
private final HttpResponse response;
public TunnelRefusedException(final String message, final HttpResponse response) {
super(message);
this.response = response;
}
public HttpResponse getResponse() {
return this.response;
}
}

View file

@ -1,31 +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/>.
*
*/
/**
* HTTP request execution chain APIs.
*/
package ch.boye.httpclientandroidlib.impl.execchain;