Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    *
    * Licensed under the Apache License, Version 2.0 (the "License").
    * You may not use this file except in compliance with the License.
    * A copy of the License is located at
    *
    *  http://aws.amazon.com/apache2.0
    *
   * or in the "license" file accompanying this file. This file 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.
   */
  package com.amazonaws.http;
  import static com.amazonaws.SDKGlobalConfiguration.DISABLE_CERT_CHECKING_SYSTEM_PROPERTY;
  import static com.amazonaws.SDKGlobalConfiguration.PROFILING_SYSTEM_PROPERTY;
  import static com.amazonaws.event.SDKProgressPublisher.publishProgress;
  import static com.amazonaws.event.SDKProgressPublisher.publishRequestContentLength;
  import static com.amazonaws.event.SDKProgressPublisher.publishResponseContentLength;
  import static com.amazonaws.util.AWSRequestMetrics.Field.AWSErrorCode;
  import static com.amazonaws.util.AWSRequestMetrics.Field.AWSRequestID;
  import static com.amazonaws.util.AWSRequestMetrics.Field.Exception;
  import static com.amazonaws.util.AWSRequestMetrics.Field.HttpClientPoolAvailableCount;
  import static com.amazonaws.util.AWSRequestMetrics.Field.HttpClientPoolLeasedCount;
  import static com.amazonaws.util.AWSRequestMetrics.Field.HttpClientPoolPendingCount;
  import static com.amazonaws.util.AWSRequestMetrics.Field.HttpRequestTime;
  import static com.amazonaws.util.AWSRequestMetrics.Field.RedirectLocation;
  import static com.amazonaws.util.AWSRequestMetrics.Field.RequestCount;
  import static com.amazonaws.util.AWSRequestMetrics.Field.RequestSigningTime;
  import static com.amazonaws.util.AWSRequestMetrics.Field.RetryPauseTime;
  import static com.amazonaws.util.AWSRequestMetrics.Field.ServiceEndpoint;
  import static com.amazonaws.util.AWSRequestMetrics.Field.ServiceName;
  import static com.amazonaws.util.AWSRequestMetrics.Field.StatusCode;
  import static com.amazonaws.util.AWSRequestMetrics.Field.ThrottleException;
  import static com.amazonaws.util.IOUtils.closeQuietly;
  
  import java.net.URI;
  import java.util.Arrays;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  
  
 
 public class AmazonHttpClient {
     private static final String HEADER_USER_AGENT = "User-Agent";

    
Logger used for the purpose of logging the AWS request id extracted either from the http header response or from the response body.
 
     private static final Log requestIdLog = LogFactory.getLog("com.amazonaws.requestId");
    
Logger providing detailed information on requests/responses. Users can enable this logger to get access to AWS request IDs for responses, individual requests and parameters sent to AWS, etc.
 
     private static final Log requestLog = LogFactory.getLog("com.amazonaws.request");

    
Logger for more detailed debugging information, that might not be as useful for end users (ex: HTTP client configuration, etc).
 
     static final Log log = LogFactory.getLog(AmazonHttpClient.class);
 
     private static final HttpRequestFactory httpRequestFactory = new HttpRequestFactory();
     private static final HttpClientFactory httpClientFactory = new HttpClientFactory();
 
     static {
         // Customers have reported XML parsing issues with the following
         // JVM versions, which don't occur with more recent versions, so
         // if we detect any of these, give customers a heads up.
         // https://bugs.openjdk.java.net/browse/JDK-8028111
         List<StringproblematicJvmVersions = Arrays.asList(
             "1.6.0_06""1.6.0_13""1.6.0_17""1.6.0_65""1.7.0_45");
         String jvmVersion = System.getProperty("java.version");
         if (problematicJvmVersions.contains(jvmVersion)) {
             .warn("Detected a possible problem with the current JVM version (" + jvmVersion + ").  " +
                      "If you experience XML parsing problems using the SDK, try upgrading to a more recent JVM update.");
         }
     }

    
Internal client for sending HTTP requests
 
     private final HttpClient httpClient;

    
Client configuration options, such as proxy settings, max retries, etc.
 
     private final ClientConfiguration config;

    
Cache of metadata for recently executed requests for diagnostic purposes
 
     private final ResponseMetadataCache responseMetadataCache;

    
A request metric collector used specifically for this http client; or null if there is none. This collector, if specified, always takes precedence over the one specified at the AWS SDK level.

 
     private final RequestMetricCollector requestMetricCollector;

    
The time difference in seconds between this client and AWS.
 
     private volatile int timeOffset = SDKGlobalTime.getGlobalTimeOffset();

    
Constructs a new AWS client using the specified client configuration options (ex: max retry attempts, proxy settings, etc).

Parameters:
config Configuration options specifying how this client will communicate with AWS (ex: proxy settings, retry count, etc.).
 
     public AmazonHttpClient(ClientConfiguration config) {
         this(confignull);
     }

    
Constructs a new AWS client using the specified client configuration options (ex: max retry attempts, proxy settings, etc), and request metric collector.

Parameters:
config Configuration options specifying how this client will communicate with AWS (ex: proxy settings, retry count, etc.).
requestMetricCollector client specific request metric collector, which takes precedence over the one at the AWS SDK level; or null if there is none.
 
     public AmazonHttpClient(ClientConfiguration configRequestMetricCollector requestMetricCollector) {
         this(config.createHttpClient(config), requestMetricCollector);
     }

    
Package-protected constructor for unit test purposes.
 
             ClientConfiguration config,
             HttpClient httpClient,
             RequestMetricCollector requestMetricCollector) {
 
         this. = config;
         this. = httpClient;
         this. = requestMetricCollector;
     }

    
Returns additional response metadata for an executed request. Response metadata isn't considered part of the standard results returned by an operation, so it's accessed instead through this diagnostic interface. Response metadata is typically used for troubleshooting issues with AWS support staff when services aren't acting as expected.

Parameters:
request A previously executed AmazonWebServiceRequest object, whose response metadata is desired.
Returns:
The response metadata for the specified request, otherwise null if there is no response metadata available for the request.
 
         return .get(request);
     }

    
Disables the default strict hostname verification in this client and instead uses a browser compatible hostname verification strategy (i.e. cert hostname wildcards are evaulated more liberally).
 
     public void disableStrictHostnameVerification() {
 
         /*
          * If SSL cert checking for endpoints is disabled, we don't need
          * to do any changes to the SSL context.
          */
         if (System.getProperty() != null) {
             return;
         }
 
         try {
             SchemeRegistry schemeRegistry = .getConnectionManager().getSchemeRegistry();
             if (sf == null) {
                 sf = new SdkTLSSocketFactory(
                         SSLContext.getDefault(),
                         .);
             }
             Scheme https = new Scheme("https", 443, sf);
             schemeRegistry.register(https);
         } catch (NoSuchAlgorithmException e) {
             throw new AmazonClientException("Unable to access default SSL context to disable strict hostname verification");
         }
     }
    
Executes the request and returns the result.

Parameters:
request The AmazonWebServices request to send to the remote server
responseHandler A response handler to accept a successful response from the remote server
errorResponseHandler A response handler to accept an unsuccessful response from the remote server
executionContext Additional information about the context of this web service call
 
     public <T> Response<T> execute(Request<?> request,
             HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
             HttpResponseHandler<AmazonServiceExceptionerrorResponseHandler,
             ExecutionContext executionContext) {
         if (executionContext == null)
             throw new AmazonClientException("Internal SDK Error: No execution context parameter specified.");
         final List<RequestHandler2requestHandler2s = requestHandler2s(requestexecutionContext);
         AmazonWebServiceRequest awsreq = request.getOriginalRequest();
         ProgressListener listener = awsreq.getGeneralProgressListener();
         Map<StringStringcustomHeaders = awsreq.getCustomRequestHeaders();
         if (customHeaders != null) {
             request.getHeaders().putAll(customHeaders);
         }
         final AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
         Response<T> response = null;
         final InputStream origContent = request.getContent();
         final InputStream toBeClosed = beforeRequest(request); // for progress tracking
         // make "notCloseable", so reset would work with retries
         final InputStream notCloseable = (toBeClosed == null)
             ? null
             : ReleasableInputStream.wrap(toBeClosed).disableClose()
             ;
         request.setContent(notCloseable);
         try {
             response = executeHelper(requestresponseHandler,
                     errorResponseHandlerexecutionContext);
             TimingInfo timingInfo = awsRequestMetrics.getTimingInfo().endTiming();
             afterResponse(requestrequestHandler2sresponsetimingInfo);
             return response;
         } catch (AmazonClientException e) {
             afterError(requestresponserequestHandler2se);
             throw e;
         } finally {
             // Always close so any progress tracking would get the final events propagated.
             closeQuietly(toBeClosed);
             request.setContent(origContent); // restore the original content
         }
     }

    
Publishes the "request content length" event, and returns an input stream, which will be made mark-and-resettable if possible, for progress tracking purposes.

Returns:
an input stream, which will be made mark-and-resettable if possible, for progress tracking purposes; or null if the request doesn't have an input stream
 
     private InputStream beforeRequest(Request<?> request) {
         final AmazonWebServiceRequest awsreq = request.getOriginalRequest();
         ProgressListener listener = awsreq.getGeneralProgressListener();
         Map<String,Stringheaders = request.getHeaders();
         String s = headers.get("Content-Length");
         if (s != null) {
             try {
                 long contentLength = Long.parseLong(s);
                 publishRequestContentLength(listenercontentLength);
             } catch (NumberFormatException e) {
                 .warn("Cannot parse the Content-Length header of the request.");
             }
         }
         InputStream content = request.getContent();
         if (content == null)
             return null;
         if (!content.markSupported()) {
             // try to wrap the content input stream to become
             // mark-and-resettable for signing and retry purposes.
             if (content instanceof FileInputStream) {
                 try {
                     // ResettableInputStream supports mark-and-reset without
                     // memory buffering
                     content = new ResettableInputStream((FileInputStream)content);
                 } catch (IOException e) {
                     if (.isDebugEnabled())
                         .debug("For the record; ignore otherwise"e);
                 }
             }
         }
         if (!content.markSupported())
             content = new SdkBufferedInputStream(content);
         final InputStream is = ProgressInputStream.inputStreamForRequest(contentawsreq);
         if (. == null)
             return is;
         return new UnreliableFilterInputStream
             (is.isFakeIOException())
             .withBytesReadBeforeException(
                 .getBytesReadBeforeException())
             .withMaxNumErrors(
                 .getMaxNumErrors())
             .withResetIntervalBeforeException(
                 .getResetIntervalBeforeException())
             ;
     }
 
     private void afterError(Request<?> requestResponse<?> response,
             List<RequestHandler2requestHandler2sAmazonClientException e) {
         for (RequestHandler2 handler2 : requestHandler2s) {
             handler2.afterError(requestresponsee);
         }
     }
 
     private <T> void afterResponse(Request<?> request,
             List<RequestHandler2requestHandler2s,
             Response<T> response,
             TimingInfo timingInfo) {
         for (RequestHandler2 handler2 : requestHandler2s) {
             handler2.afterResponse(requestresponse);
         }
     }
 
     private List<RequestHandler2requestHandler2s(Request<?> request,
             ExecutionContext executionContext) {
         List<RequestHandler2requestHandler2s = executionContext
                 .getRequestHandler2s();
         if (requestHandler2s == null) {
             return Collections.emptyList();
         }
         // Apply any additional service specific request handlers that need
         // to be run
         for (RequestHandler2 requestHandler2 : requestHandler2s) {
             // If the request handler is a type of CredentialsRequestHandler,
             // then set the credentials in the request handler.
             if (requestHandler2 instanceof CredentialsRequestHandler)
                 ((CredentialsRequestHandlerrequestHandler2)
                         .setCredentials(executionContext.getCredentials());
             requestHandler2.beforeRequest(request);
         }
         return requestHandler2s;
     }

    
Internal method to execute the HTTP method given.
 
     private <T> Response<T> executeHelper(final Request<?> request,
             HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
             HttpResponseHandler<AmazonServiceExceptionerrorResponseHandler,
             final ExecutionContext executionContext) {
         /*
          * add the service endpoint to the logs. You can infer service name from
          * service endpoint
          */
         final AWSRequestMetrics awsRequestMetrics =
             executionContext.getAwsRequestMetrics()
             .addPropertyWith(request.getServiceName())
             .addPropertyWith(request.getEndpoint())
             ;
         // Apply whatever request options we know how to handle, such as
         // user-agent.
         setUserAgent(request);
         // Make a copy of the original request params and headers so that we can
         // permute it in this loop and start over with the original every time.
         final Map<StringStringoriginalParameters =
             new LinkedHashMap<StringString>(request.getParameters());
         final Map<StringStringoriginalHeaders =
             new HashMap<StringString>(request.getHeaders());
         // Always mark the input stream before execution.
         final InputStream originalContent = request.getContent();
         if (originalContent != null && originalContent.markSupported()) {
             AmazonWebServiceRequest awsreq = request.getOriginalRequest();
             final int readLimit = awsreq.getRequestClientOptions().getReadLimit();
             originalContent.mark(readLimit);
         }
         final ExecOneRequestParams p = new ExecOneRequestParams();
         while (true) {
             p.initPerRetry();
             if (p.redirectedURI != null) {
                 /*
                  * [scheme:][//authority][path][?query][#fragment]
                  */
                 String scheme = p.redirectedURI.getScheme();
                 String beforeAuthority = scheme == null ? "" : scheme + "://";
                 String authority = p.redirectedURI.getAuthority();
                 String path = p.redirectedURI.getPath();
 
                 request.setEndpoint(URI.create(beforeAuthority + authority));
                 request.setResourcePath(path);
             }
             if (p.authRetryParam != null) {
                 request.setEndpoint(p.authRetryParam.getEndpointForRetry());
             }
             awsRequestMetrics.setCounter(p.requestCount);
             if (p.isRetry()) {
                 request.setParameters(originalParameters);
                 request.setHeaders(originalHeaders);
                 request.setContent(originalContent);
             }
             try {
                 Response<T> response = executeOneRequest(requestresponseHandler,
                     errorResponseHandlerexecutionContextawsRequestMetrics,
                     p);
                 if (response != null)
                     return response;
             } catch (IOException ioe) {
                 if (.isInfoEnabled()) {
                     .info("Unable to execute HTTP request: " + ioe.getMessage(), ioe);
                 }
                 captureExceptionMetrics(ioeawsRequestMetrics);
                 awsRequestMetrics.addProperty(null);
                 AmazonClientException ace = new AmazonClientException(
                         "Unable to execute HTTP request: " + ioe.getMessage(),
                         ioe);
                 if (!shouldRetry(request.getOriginalRequest(),
                                 p.apacheRequest,
                                 ace,
                                 p.requestCount,
                                 .getRetryPolicy())) {
                     throw lastReset(acerequest);
                 }
                 // Cache the retryable exception
                 p.retriedException = ace;
             } catch(RuntimeException e) {
                 throw lastReset(
                         captureExceptionMetrics(eawsRequestMetrics),
                         request);
             } catch(Error e) {
                 throw lastReset(
                         captureExceptionMetrics(eawsRequestMetrics),
                         request);
             } finally {
                 /*
                  * Some response handlers need to manually manage the HTTP
                  * connection and will take care of releasing the connection on
                  * their own, but if this response handler doesn't need the
                  * connection left open, we go ahead and release the it to free
                  * up resources.
                  */
                 if (!p.leaveHttpConnectionOpen) {
                     if (p.apacheResponse != null) {
                         HttpEntity entity = p.apacheResponse.getEntity();
                         if (entity != null) {
                             try {
                                 closeQuietly(entity.getContent(), );
                             } catch (IOException e) {
                                 .warn("Cannot close the response content."e);
                             }
                         }
                     }
                 }
             }
         } /* end while (true) */
     }

    
Used to perform a last reset on the content input stream (if mark-supported); this is so that, for backward compatibility reason, any "blind" retry (ie without calling reset) by user of this library with the same input stream (such as ByteArrayInputStream) could still succeed.

Parameters:
t the failure
apacheRequest the request, if known; or null otherwise.
Returns:
the failure as given
 
     private <T extends Throwable> T lastReset(final T t,
             final Request<?> req) {
         try {
             InputStream content = req.getContent();
             if (content != null) {
                 if (content.markSupported())
                     content.reset();
             }
         } catch (Exception ex) {
             .debug(
                 "FYI: failed to reset content inputstream before throwing up",
                  ex);
         }
         return t;
     }

    
Stateful parameters that are used for executing a single http request.
 
     private static class ExecOneRequestParams {
         private Signer signer;    // cached
         private URI signerURI;
         int requestCount// monotonic increasing
         AmazonClientException retriedException// last retryable exception
 
         HttpRequestBase apacheRequest;
         URI redirectedURI;
 
         /*
          * Depending on which response handler we end up choosing to handle the
          * HTTP response, it might require us to leave the underlying HTTP
          * connection open, depending on whether or not it reads the complete
          * HTTP response stream from the HTTP connection, or if delays reading
          * any of the content until after a response is returned to the caller.
          */
         boolean leaveHttpConnectionOpen;
 
         boolean isRetry() {
             return  > 1 ||
                     != null ||
                     != null;
         }
 
         void initPerRetry() {
             ++;
              = null;
              = null;
              = false;
         }
 
         Signer newSigner(final Request<?> request,
                 final ExecutionContext execContext) {
             if ( != null) {
                  = .getEndpointForRetry();
                  = .getSignerForRetry();
                 // Push the local signer override back to the execution context
                 execContext.setSigner();
             } else if ( != null
                     && !.equals()) {
                  = ;
                  = execContext.getSignerByURI();
             } else if ( == null) {
                  = request.getEndpoint();
                  = execContext.getSignerByURI();
             }
             return ;
         }

        

Throws:
com.amazonaws.util.FakeIOException thrown only during test simulation
 
                 final HttpRequestFactory httpRequestFactory,
                 final Request<?> request,
                 final ClientConfiguration config,
                 final ExecutionContext execContextthrows FakeIOException {
              = httpRequestFactory.createHttpRequest(requestconfigexecContext);
             if ( != null)
                 .setURI();
             return ;
         }
 
         void resetBeforeHttpRequest() {
              = null;
              = null;
              = null;
         }
     }

    
Returns the response from executing one http request; or null for retry.
 
     private <T> Response<T> executeOneRequest(final Request<?> request,
             final HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
             final HttpResponseHandler<AmazonServiceExceptionerrorResponseHandler,
             final ExecutionContext execContext,
             final AWSRequestMetrics awsRequestMetrics,
             ExecOneRequestParams execParams)
             throws IOException {
         // Reset the request input stream
         if (execParams.isRetry()) {
             InputStream requestInputStream = request.getContent();
             if (requestInputStream != null) {
                 if (requestInputStream.markSupported()) {
                     try {
                         requestInputStream.reset();
                     } catch(IOException ex) {
                         throw new ResetException("Failed to reset the request input stream"ex);
                     }
                 }
             }
         }
         if (.isDebugEnabled())
             .debug("Sending Request: " + request);
         final AWSCredentials credentials = execContext.getCredentials();
         final AmazonWebServiceRequest awsreq = request.getOriginalRequest();
         final ProgressListener listener = awsreq.getGeneralProgressListener();
 
         if (execParams.isRetry()) {
             publishProgress(listener.);
             // Notify the progress listener of the retry
             awsRequestMetrics.startEvent();
             try {
                 // don't pause if the retry was not due to a redirection
                 // ie when retried exception is null
                 if (execParams.retriedException != null) {
                     pauseBeforeNextRetry(request.getOriginalRequest(),
                         execParams.retriedExceptionexecParams.requestCount,
                         .getRetryPolicy());
                 }
             } finally {
                 awsRequestMetrics.endEvent();
             }
         }
 
         // Sign the request if a signer was provided
         execParams.newSigner(requestexecContext);
         if (execParams.signer != null && credentials != null) {
             awsRequestMetrics.startEvent();
             try {
                 if ( != 0) {
                     // Always use the client level timeOffset if it was
                     // non-zero; Otherwise, we respect the timeOffset in the
                     // request, which could have been externally configured (at
                     // least for the 1st non-retry request).
                     //
                     // For retry due to clock skew, the timeOffset in the
                     // request used for the retry is assumed to have been
                     // adjusted when execution reaches here.
                     request.setTimeOffset();
                 }
                 execParams.signer.sign(requestcredentials);
             } finally {
                 awsRequestMetrics.endEvent();
             }
         }
         execParams.newApacheRequest(requestexecContext);
 
         captureConnectionPoolMetrics(.getConnectionManager(), awsRequestMetrics);
         HttpContext httpContext = new BasicHttpContext();
         httpContext.setAttribute(
             AWSRequestMetrics.class.getSimpleName(),
             awsRequestMetrics);
         execParams.resetBeforeHttpRequest();
         awsRequestMetrics.startEvent();
 
         /////////// Send HTTP request ////////////
         final boolean isHeaderReqIdAvail;
         try {
             execParams.apacheResponse = .execute(execParams.apacheRequesthttpContext);
             isHeaderReqIdAvail = logHeaderRequestId(execParams.apacheResponse);
         } finally {
             awsRequestMetrics.endEvent();
         }
 
         final StatusLine statusLine = execParams.apacheResponse.getStatusLine();
         final int statusCode = statusLine == null ? -1 : statusLine.getStatusCode();
         if (isRequestSuccessful(execParams.apacheResponse)) {
             awsRequestMetrics.addProperty(statusCode);
             /*
              * If we get back any 2xx status code, then we know we should
              * treat the service call as successful.
              */
             execParams.leaveHttpConnectionOpen = responseHandler.needsConnectionLeftOpen();
             HttpResponse httpResponse = createResponse(execParams.apacheRequest,
                     requestexecParams.apacheResponse);
             T response = handleResponse(requestresponseHandler,
                     execParams.apacheRequesthttpResponseexecParams.apacheResponse,
                     execContextisHeaderReqIdAvail);
             return new Response<T>(responsehttpResponse);
         }
         if (isTemporaryRedirect(execParams.apacheResponse)) {
             /*
              * S3 sends 307 Temporary Redirects if you try to delete an
              * EU bucket from the US endpoint. If we get a 307, we'll
              * point the HTTP method to the redirected location, and let
              * the next retry deliver the request to the right location.
              */
             Header[] locationHeaders = execParams.apacheResponse.getHeaders("location");
             String redirectedLocation = locationHeaders[0].getValue();
             if (.isDebugEnabled())
                 .debug("Redirecting to: " + redirectedLocation);
             execParams.redirectedURI = URI.create(redirectedLocation);
             awsRequestMetrics.addPropertyWith(statusCode)
                 .addPropertyWith(redirectedLocation)
                 .addPropertyWith(null)
                 ;
             return null// => retry
         }
         execParams.leaveHttpConnectionOpen = errorResponseHandler.needsConnectionLeftOpen();
         final AmazonServiceException ase = handleErrorResponse(request,
                 errorResponseHandlerexecParams.apacheRequestexecParams.apacheResponse);
         awsRequestMetrics
             .addPropertyWith(ase.getRequestId())
             .addPropertyWith(ase.getErrorCode())
             .addPropertyWith(ase.getStatusCode());
         // Check whether we should internally retry the auth error
         execParams.authRetryParam = null;
         AuthErrorRetryStrategy authRetry = execContext.getAuthErrorRetryStrategy();
         if ( authRetry != null ) {
             HttpResponse httpResponse = createResponse(execParams.apacheRequestrequestexecParams.apacheResponse);
             execParams.authRetryParam = authRetry.shouldRetryWithAuthParam(requesthttpResponsease);
         }
         if (execParams.authRetryParam == null &&
             !shouldRetry(request.getOriginalRequest(),
                 execParams.apacheRequest,
                 ase,
                 execParams.requestCount,
                 .getRetryPolicy())) {
             throw ase;
         }
         // Comment out for now. Ref: CR2662349
         // Preserve the cause of retry before retrying
         // awsRequestMetrics.addProperty(RetryCause, ase);
         if (RetryUtils.isThrottlingException(ase)) {
             awsRequestMetrics.incrementCounterWith()
                              .addProperty(ase)
                              ;
         }
         // Cache the retryable exception
         execParams.retriedException = ase;
         /*
          * Checking for clock skew error again because we don't want to set the
          * global time offset for every service exception.
          */
         if (RetryUtils.isClockSkewError(ase)) {
             int clockSkew = parseClockSkewOffset(execParams.apacheResponsease);
             SDKGlobalTime.setGlobalTimeOffset( = clockSkew);
             request.setTimeOffset();  // adjust time offset for the retry
         }
         return null// => retry
     }

    
Used to log the "x-amzn-RequestId" header at DEBUG level, if any, from the response. This method assumes the apache http request/response has just been successfully executed. The request id is logged using the "com.amazonaws.requestId" logger if it was enabled at DEBUG level; otherwise, it is logged at DEBUG level using the "com.amazonaws.request" logger.

Returns:
true if the AWS request id is available from the http header; false otherwise.
 
     private boolean logHeaderRequestId(final org.apache.http.HttpResponse res) {
         final Header reqIdHeader =
         final boolean isHeaderReqIdAvail = reqIdHeader != null;
 
         if (.isDebugEnabled() || .isDebugEnabled()) {
             final String msg = .
                 + ": "
                 + (isHeaderReqIdAvail ? reqIdHeader.getValue() : "not available");
             if (.isDebugEnabled())
                 .debug(msg);
             else
                 .debug(msg);
         }
         return isHeaderReqIdAvail;
     }

    
Used to log the request id (extracted from the response) at DEBUG level. This method is called only if there is no request id present in the http response header. The request id is logged using the "com.amazonaws.requestId" logger if it was enabled at DEBUG level; otherwise, it is logged using at DEBUG level using the "com.amazonaws.request" logger.
 
     private void logResponseRequestId(final String awsRequestId) {
         if (.isDebugEnabled() || .isDebugEnabled()) {
             final String msg = "AWS Request ID: "
                     + (awsRequestId == null ? "not available" : awsRequestId);
             if (.isDebugEnabled())
                 .debug(msg);
             else
                 .debug(msg);
         }
     }

    
Captures the connection pool metrics.
 
     private void captureConnectionPoolMetrics(ClientConnectionManager connectionManager,
             AWSRequestMetrics awsRequestMetrics) {
         if (awsRequestMetrics.isEnabled()
                 && connectionManager instanceof ConnPoolControl) {
             ConnPoolControl<?> control = (ConnPoolControl<?>) connectionManager;
             PoolStats stats = control.getTotalStats();
             awsRequestMetrics
                 .withCounter(stats.getAvailable())
                 .withCounter(stats.getLeased())
                 .withCounter(stats.getPending())
                 ;
         }
     }

    
Capture the metrics for the given throwable.
 
     private <T extends Throwable> T captureExceptionMetrics(T t,
             AWSRequestMetrics awsRequestMetrics) {
         awsRequestMetrics.incrementCounterWith()
                          .addProperty(t);
         if (t instanceof AmazonServiceException) {
             AmazonServiceException ase = (AmazonServiceExceptiont;
             if (RetryUtils.isThrottlingException(ase)) {
                 awsRequestMetrics.incrementCounterWith()
                                  .addProperty(ase);
             }
         }
         return t;
     }

    
Sets a User-Agent for the specified request, taking into account any custom data.
 
     private void setUserAgent(Request<?> request) {
         String userAgent = .getUserAgent();
         if ( !userAgent.equals(.) ) {
             userAgent += ", " + .;
         }
         if ( userAgent != null ) {
             request.addHeader(userAgent);
         }
         AmazonWebServiceRequest awsreq = request.getOriginalRequest();
         RequestClientOptions opts = awsreq.getRequestClientOptions();
         if (opts != null) {
             String userAgentMarker = opts.getClientMarker(.);
             if (userAgentMarker != null) {
                 request.addHeader(,
                     createUserAgentString(userAgentuserAgentMarker));
             }
         }
     }

    
Appends the given user-agent string to the existing one and returns it.
 
     private static String createUserAgentString(String existingUserAgentStringString userAgent) {
         if (existingUserAgentString.contains(userAgent)) {
             return existingUserAgentString;
         } else {
             return existingUserAgentString.trim() + " " + userAgent.trim();
         }
     }

    
Shuts down this HTTP client object, releasing any resources that might be held open. This is an optional method, and callers are not expected to call it, but can if they want to explicitly release any open resources. Once a client has been shutdown, it cannot be used to make more requests.
 
     public void shutdown() {
         IdleConnectionReaper.removeConnectionManager(.getConnectionManager());
     }

    
Returns true if a failed request should be retried.

Parameters:
originalRequest The original service request that is being executed.
method The current HTTP method being executed.
exception The client/service exception from the failed request.
requestCount The number of times the current request has been attempted.
Returns:
True if the failed request should be retried.
 
     private boolean shouldRetry(AmazonWebServiceRequest originalRequest,
                                 HttpRequestBase method,
                                 AmazonClientException exception,
                                 int requestCount,
                                 RetryPolicy retryPolicy) {
         final int retries = requestCount - 1;
 
         int maxErrorRetry = .getMaxErrorRetry();
         // We should use the maxErrorRetry in
         // the RetryPolicy if either the user has not explicitly set it in
         // ClientConfiguration, or the RetryPolicy is configured to take
         // higher precedence.
         if ( maxErrorRetry < 0
                 || !retryPolicy.isMaxErrorRetryInClientConfigHonored() ) {
             maxErrorRetry = retryPolicy.getMaxErrorRetry();
         }
 
         // Immediately fails when it has exceeds the max retry count.
         if (retries >= maxErrorRetryreturn false;
 
         // Never retry on requests containing non-repeatable entity
         if (method instanceof HttpEntityEnclosingRequest) {
             HttpEntity entity = ((HttpEntityEnclosingRequest)method).getEntity();
             if (entity != null && !entity.isRepeatable()) {
                 if (.isDebugEnabled()) {
                     .debug("Entity not repeatable");
                 }
                 return false;
             }
         }
 
         // Pass all the context information to the RetryCondition and let it
         // decide whether it should be retried.
         return retryPolicy.getRetryCondition().shouldRetry(originalRequest,
                                                            exception,
                                                            retries);
     }
 
     private static boolean isTemporaryRedirect(org.apache.http.HttpResponse response) {
         int status = response.getStatusLine().getStatusCode();
         return status == . &&
                          response.getHeaders("Location") != null &&
                          response.getHeaders("Location").length > 0;
     }
 
     private boolean isRequestSuccessful(org.apache.http.HttpResponse response) {
         int status = response.getStatusLine().getStatusCode();
         return status / 100 == . / 100;
     }

    
Handles a successful response from a service call by unmarshalling the results using the specified response handler.

Parameters:
<T> The type of object expected in the response.
request The original request that generated the response being handled.
responseHandler The response unmarshaller used to interpret the contents of the response.
method The HTTP method that was invoked, and contains the contents of the response.
executionContext Extra state information about the request currently being executed.
isHeaderReqIdAvail true if the AWS request id is available from the http response header; false otherwise.
Returns:
The contents of the response, unmarshalled using the specified response handler.
Throws:
java.io.IOException If any problems were encountered reading the response contents from the HTTP method object.
    @SuppressWarnings("deprecation")
    private <T> T handleResponse(Request<?> request,
            HttpResponseHandler<AmazonWebServiceResponse<T>> responseHandler,
            HttpRequestBase methodHttpResponse httpResponse,
            org.apache.http.HttpResponse apacheHttpResponse,
            ExecutionContext executionContext,
            final boolean isHeaderReqIdAvailthrows IOException
    {
        AmazonWebServiceRequest awsreq = request.getOriginalRequest();
        ProgressListener listener = awsreq.getGeneralProgressListener();
        try {
            /*
             * Apply the byte counting stream wrapper if the legacy runtime profiling is enabled.
             */
            CountingInputStream countingInputStream = null;
            InputStream is = httpResponse.getContent();
            if (is != null) {
                if (System.getProperty() != null) {
                    is = countingInputStream = new CountingInputStream(is);
                    httpResponse.setContent(is);
                }
                httpResponse.setContent(
                    ProgressInputStream.inputStreamForResponse(isawsreq));
            }
            Map<String,Stringheaders = httpResponse.getHeaders();
            String s = headers.get("Content-Length");
            if (s != null) {
                try {
                    long contentLength = Long.parseLong(s);
                    publishResponseContentLength(listenercontentLength);
                } catch (NumberFormatException e) {
                    .warn("Cannot parse the Content-Length header of the response.");
                }
            }
            AWSRequestMetrics awsRequestMetrics = executionContext.getAwsRequestMetrics();
            AmazonWebServiceResponse<? extends T> awsResponse;
            awsRequestMetrics.startEvent(.);
            try {
                awsResponse = responseHandler.handle(httpResponse);
            } finally {
                awsRequestMetrics.endEvent(.);
            }
            if (countingInputStream != null) {
                awsRequestMetrics.setCounter(.countingInputStream.getByteCount());
            }
            if (awsResponse == null)
                throw new RuntimeException("Unable to unmarshall response metadata. Response Code: " +
                        httpResponse.getStatusCode() + ", Response Text: " + httpResponse.getStatusText());
            .add(request.getOriginalRequest(), awsResponse.getResponseMetadata());
            final String awsRequestId = awsResponse.getRequestId();
            if (.isDebugEnabled()) {
                final StatusLine statusLine = apacheHttpResponse.getStatusLine();
                .debug("Received successful response: "
                    + (statusLine == null ? null : statusLine.getStatusCode())
                    + ", AWS Request ID: " + awsRequestId);
            }
            if (!isHeaderReqIdAvail) {
                // Logs the AWS request ID extracted from the payload if
                // it is not available from the response header.
                logResponseRequestId(awsRequestId);
            }
            awsRequestMetrics.addProperty(awsRequestId);
            return awsResponse.getResult();
        } catch (CRC32MismatchException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } catch (AmazonClientException e) {
            throw e;    // simply rethrow rather than further wrapping it
        } catch (Exception e) {
            String errorMessage = "Unable to unmarshall response (" + e.getMessage() + "). Response Code: " +
                        httpResponse.getStatusCode() + ", Response Text: " + httpResponse.getStatusText();
            throw new AmazonClientException(errorMessagee);
        }
    }

    
Responsible for handling an error response, including unmarshalling the error response into the most specific exception type possible, and throwing the exception.

Parameters:
request The request that generated the error response being handled.
errorResponseHandler The response handler responsible for unmarshalling the error response.
method The HTTP method containing the actual response content.
Throws:
java.io.IOException If any problems are encountering reading the error response.
        HttpResponseHandler<AmazonServiceExceptionerrorResponseHandler,
        HttpRequestBase method,
        final org.apache.http.HttpResponse apacheHttpResponsethrows IOException
    {
        final StatusLine statusLine = apacheHttpResponse.getStatusLine();
        final int statusCode;
        final String reasonPhrase;
        if (statusLine == null) {
            statusCode = -1;
            reasonPhrase = null;
        } else {
            statusCode = statusLine.getStatusCode();
            reasonPhrase = statusLine.getReasonPhrase();
        }
        HttpResponse response = createResponse(methodrequestapacheHttpResponse);
        AmazonServiceException exception = null;
        try {
            exception = errorResponseHandler.handle(response);
            if (.isDebugEnabled())
                .debug("Received error response: " + exception);
        } catch (Exception e) {
            // If the errorResponseHandler doesn't work, then check for error
            // responses that don't have any content
            if (statusCode == 413) {
                exception = new AmazonServiceException("Request entity too large");
                exception.setServiceName(request.getServiceName());
                exception.setStatusCode(statusCode);
                exception.setErrorType(.);
                exception.setErrorCode("Request entity too large");
            } else if (statusCode == 503
                    && "Service Unavailable".equalsIgnoreCase(reasonPhrase)) {
                exception = new AmazonServiceException("Service unavailable");
                exception.setServiceName(request.getServiceName());
                exception.setStatusCode(statusCode);
                exception.setErrorType(.);
                exception.setErrorCode("Service unavailable");
            } else if (e instanceof IOException) {
                throw (IOExceptione;
            } else {
                String errorMessage = "Unable to unmarshall error response ("
                        + e.getMessage() + "). Response Code: "
                        + (statusLine == null ? "None" : statusCode)
                        + ", Response Text: " + reasonPhrase;
                throw new AmazonClientException(errorMessagee);
            }
        }
        exception.setStatusCode(statusCode);
        exception.setServiceName(request.getServiceName());
        exception.fillInStackTrace();
        return exception;
    }

    
Creates and initializes an HttpResponse object suitable to be passed to an HTTP response handler object.

Parameters:
method The HTTP method that was invoked to get the response.
request The HTTP request associated with the response.
Returns:
The new, initialized HttpResponse object ready to be passed to an HTTP response handler object.
Throws:
java.io.IOException If there were any problems getting any response information from the HttpClient method object.
    private HttpResponse createResponse(HttpRequestBase methodRequest<?> requestorg.apache.http.HttpResponse apacheHttpResponsethrows IOException {
        HttpResponse httpResponse = new HttpResponse(requestmethod);
        if (apacheHttpResponse.getEntity() != null) {
            httpResponse.setContent(apacheHttpResponse.getEntity().getContent());
        }
        httpResponse.setStatusCode(apacheHttpResponse.getStatusLine().getStatusCode());
        httpResponse.setStatusText(apacheHttpResponse.getStatusLine().getReasonPhrase());
        for (Header header : apacheHttpResponse.getAllHeaders()) {
            httpResponse.addHeader(header.getName(), header.getValue());
        }
        return httpResponse;
    }

    
Sleep for a period of time on failed request to avoid flooding a service with retries.

Parameters:
originalRequest The original service request that is being executed.
previousException Exception information for the previous attempt, if any.
requestCount current request count (including the next attempt after the delay)
retryPolicy The retry policy configured in this http client.
    private void pauseBeforeNextRetry(AmazonWebServiceRequest originalRequest,
                                    AmazonClientException previousException,
                                    int requestCount,
                                    RetryPolicy retryPolicy) {
        final int retries = requestCount // including next attempt
         &