/// <summary>
        /// Handles an exception for the given execution context.
        /// </summary>
        /// <param name="executionContext">The execution context, it contains the
        /// request and response context.</param>
        /// <param name="exception">The exception to handle.</param>
        /// <returns>
        /// Returns a boolean value which indicates if the original exception
        /// should be rethrown.
        /// This method can also throw a new exception to replace the original exception.
        /// </returns>
        public override bool HandleException(IExecutionContext executionContext, UnityHttpErrorResponseException exception)
        {
            LogCurlRequest(exception.Request);

            var requestContext    = executionContext.RequestContext;
            var httpErrorResponse = exception.Response;

            var errorResponse = new ErrorResponse();

            if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzRequestIdHeader))
            {
                errorResponse.RequestId = httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzRequestIdHeader);
                requestContext.Metrics.AddProperty(Metric.AWSRequestID, httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzRequestIdHeader));
            }

            if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzErrorTypeHeader))
            {
                errorResponse.Code = httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzErrorTypeHeader);
            }

            if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzErrorMessageHeader))
            {
                errorResponse.Message = httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzErrorMessageHeader);
            }

            if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzId2Header))
            {
                requestContext.Metrics.AddProperty(Metric.AmzId2, httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzId2Header));
            }

            requestContext.Metrics.AddProperty(Metric.StatusCode, httpErrorResponse.StatusCode);

            Exception unmarshalledException = null;
            var       unmarshaller          = requestContext.Unmarshaller as ISimplifiedErrorUnmarshaller;

            if (unmarshaller != null)
            {
                unmarshalledException = unmarshaller.UnmarshallException(httpErrorResponse, errorResponse, exception);
                LogErrorMessage(unmarshalledException, errorResponse);
                throw unmarshalledException;
            }
            else
            {
                var baseServiceException = new T();
                baseServiceException.RequestId  = errorResponse.RequestId;
                baseServiceException.ErrorCode  = errorResponse.Code;
                baseServiceException.StatusCode = httpErrorResponse.StatusCode;
                throw baseServiceException;
            }
        }
        /// <summary>
        /// Handles an exception for the given execution context.
        /// </summary>
        /// <param name="executionContext">The execution context, it contains the
        /// request and response context.</param>
        /// <param name="exception">The exception to handle.</param>
        /// <returns>
        /// Returns a boolean value which indicates if the original exception
        /// should be rethrown.
        /// This method can also throw a new exception to replace the original exception.
        /// </returns>
        public override bool HandleException(IExecutionContext executionContext, UnityHttpErrorResponseException exception)
        {
            var requestContext    = executionContext.RequestContext;
            var httpErrorResponse = exception.Response;

            var unityResponseData = (UnityWebResponseData)httpErrorResponse.ResponseBody;

            if (!unityResponseData.IsResponseBodyPresent)
            {
                //for backward compatibility when the response error message is missing
                LogCurlRequest(exception.Request);
                var errorResponse = new ErrorResponse();
                if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzRequestIdHeader))
                {
                    errorResponse.RequestId = httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzRequestIdHeader);
                    requestContext.Metrics.AddProperty(Metric.AWSRequestID, httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzRequestIdHeader));
                }

                if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzErrorTypeHeader))
                {
                    errorResponse.Code = httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzErrorTypeHeader);
                }

                if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzErrorMessageHeader))
                {
                    errorResponse.Message = httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzErrorMessageHeader);
                }

                if (httpErrorResponse.IsHeaderPresent(HeaderKeys.XAmzId2Header))
                {
                    requestContext.Metrics.AddProperty(Metric.AmzId2, httpErrorResponse.GetHeaderValue(HeaderKeys.XAmzId2Header));
                }

                requestContext.Metrics.AddProperty(Metric.StatusCode, httpErrorResponse.StatusCode);

                Exception unmarshalledException = null;
                var       unmarshaller          = requestContext.Unmarshaller as ISimplifiedErrorUnmarshaller;
                if (unmarshaller != null)
                {
                    unmarshalledException = unmarshaller.UnmarshallException(httpErrorResponse, errorResponse, exception);
                    LogErrorMessage(unmarshalledException, errorResponse);
                    throw unmarshalledException;
                }
                else
                {
                    var baseServiceException = new AmazonServiceException();
                    baseServiceException.RequestId  = errorResponse.RequestId;
                    baseServiceException.ErrorCode  = errorResponse.Code;
                    baseServiceException.StatusCode = httpErrorResponse.StatusCode;
                    throw baseServiceException;
                }
            }
            else
            {
                // If 404 was suppressed and successfully unmarshalled,
                // don't rethrow the original exception.
                if (HandleSuppressed404(executionContext, httpErrorResponse))
                {
                    return(false);
                }

                requestContext.Metrics.AddProperty(Metric.StatusCode, httpErrorResponse.StatusCode);

                AmazonServiceException errorResponseException = null;
                // Unmarshall the service error response and throw the corresponding service exception.
                try
                {
                    using (httpErrorResponse.ResponseBody)
                    {
                        var unmarshaller       = requestContext.Unmarshaller;
                        var readEntireResponse = true;

                        var errorContext = unmarshaller.CreateContext(httpErrorResponse,
                                                                      readEntireResponse,
                                                                      httpErrorResponse.ResponseBody.OpenResponse(),
                                                                      requestContext.Metrics);

                        try
                        {
                            errorResponseException = unmarshaller.UnmarshallException(errorContext,
                                                                                      exception, httpErrorResponse.StatusCode);
                        }
                        catch (Exception e)
                        {
                            // Rethrow Amazon service or client exceptions
                            if (e is AmazonServiceException ||
                                e is AmazonClientException)
                            {
                                throw;
                            }

                            // Else, there was an issue with the response body, throw AmazonUnmarshallingException
                            var requestId = httpErrorResponse.GetHeaderValue(HeaderKeys.RequestIdHeader);
                            var body      = errorContext.ResponseBody;
                            throw new AmazonUnmarshallingException(requestId, lastKnownLocation: null, responseBody: body, innerException: e);
                        }

                        Debug.Assert(errorResponseException != null);

                        requestContext.Metrics.AddProperty(Metric.AWSRequestID, errorResponseException.RequestId);
                        requestContext.Metrics.AddProperty(Metric.AWSErrorCode, errorResponseException.ErrorCode);

                        var logResponseBody = requestContext.ClientConfig.LogResponse ||
                                              AWSConfigs.LoggingConfig.LogResponses != ResponseLoggingOption.Never;
                        if (logResponseBody)
                        {
                            this.Logger.Error(errorResponseException, "Received error response: [{0}]",
                                              errorContext.ResponseBody);
                        }
                    }
                }
                catch (Exception unmarshallException)
                {
                    this.Logger.Error(unmarshallException, "Failed to unmarshall a service error response.");
                    throw;
                }

                throw errorResponseException;
            }
        }