/* * Copyright 2010-2018 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. */ using Amazon.Runtime.Internal.Transform; using Amazon.Runtime.Internal.Util; using Amazon.Util; using System; using System.Diagnostics; using System.Net; namespace Amazon.Runtime.Internal { /// /// The exception handler for HttpErrorResponseException exception. /// public class HttpErrorResponseExceptionHandler : ExceptionHandler { /// /// The constructor for HttpErrorResponseExceptionHandler. /// /// in instance of ILogger. public HttpErrorResponseExceptionHandler(ILogger logger) : base(logger) { } /// /// Handles an exception for the given execution context. /// /// The execution context, it contains the /// request and response context. /// The exception to handle. /// /// 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. /// public override bool HandleException(IExecutionContext executionContext, HttpErrorResponseException exception) { var requestContext = executionContext.RequestContext; var httpErrorResponse = exception.Response; // 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, statusCode : httpErrorResponse.StatusCode); } 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; } /// /// Checks if a HTTP 404 status code is returned which needs to be suppressed and /// processes it. /// If a suppressed 404 is present, it unmarshalls the response and returns true to /// indicate that a suppressed 404 was processed, else returns false. /// /// The execution context, it contains the /// request and response context. /// /// /// If a suppressed 404 is present, returns true, else returns false. /// private bool HandleSuppressed404(IExecutionContext executionContext, IWebResponseData httpErrorResponse) { var requestContext = executionContext.RequestContext; var responseContext = executionContext.ResponseContext; // If the error is a 404 and the request is configured to supress it, // then unmarshall as much as we can. if (httpErrorResponse != null && httpErrorResponse.StatusCode == HttpStatusCode.NotFound && requestContext.Request.Suppress404Exceptions) { using (httpErrorResponse.ResponseBody) { var unmarshaller = requestContext.Unmarshaller; var readEntireResponse = requestContext.ClientConfig.LogResponse || AWSConfigs.LoggingConfig.LogResponses != ResponseLoggingOption.Never; UnmarshallerContext errorContext = unmarshaller.CreateContext( httpErrorResponse, readEntireResponse, httpErrorResponse.ResponseBody.OpenResponse(), requestContext.Metrics); try { responseContext.Response = unmarshaller.Unmarshall(errorContext); responseContext.Response.ContentLength = httpErrorResponse.ContentLength; responseContext.Response.HttpStatusCode = httpErrorResponse.StatusCode; return true; } catch (Exception unmarshallException) { this.Logger.Debug(unmarshallException, "Failed to unmarshall 404 response when it was supressed."); } } } return false; } } }