Exemplo n.º 1
0
    private ForwarderError HandleRequestBodyFailure(HttpContext context, StreamCopyResult requestBodyCopyResult, Exception requestBodyException, Exception additionalException)
    {
        ForwarderError requestBodyError;
        int            statusCode;

        switch (requestBodyCopyResult)
        {
        // Failed while trying to copy the request body from the client. It's ambiguous if the request or response failed first.
        case StreamCopyResult.InputError:
            requestBodyError = ForwarderError.RequestBodyClient;
            statusCode       = StatusCodes.Status400BadRequest;
            break;

        // Failed while trying to copy the request body to the destination. It's ambiguous if the request or response failed first.
        case StreamCopyResult.OutputError:
            requestBodyError = ForwarderError.RequestBodyDestination;
            statusCode       = StatusCodes.Status502BadGateway;
            break;

        // Canceled while trying to copy the request body, either due to a client disconnect or a timeout. This probably caused the response to fail as a secondary error.
        case StreamCopyResult.Canceled:
            requestBodyError = ForwarderError.RequestBodyCanceled;
            // Timeouts (504s) are handled at the SendAsync call site.
            // The request body should only be canceled by the RequestAborted token.
            statusCode = StatusCodes.Status502BadGateway;
            break;

        default:
            throw new NotImplementedException(requestBodyCopyResult.ToString());
        }

        ReportProxyError(context, requestBodyError, new AggregateException(requestBodyException, additionalException));

        // We don't know if the client is still around to see this error, but set it for diagnostics to see.
        if (!context.Response.HasStarted)
        {
            // Nothing has been sent to the client yet, we can still send a good error response.
            context.Response.Clear();
            context.Response.StatusCode = statusCode;
            return(requestBodyError);
        }

        ResetOrAbort(context, isCancelled: requestBodyCopyResult == StreamCopyResult.Canceled);

        return(requestBodyError);
    }
Exemplo n.º 2
0
        private async Task HandleResponseBodyErrorAsync(HttpContext context, StreamCopyHttpContent requestContent, StreamCopyResult responseBodyCopyResult, Exception responseBodyException)
        {
            if (requestContent?.ConsumptionTask.IsCompleted == true)
            {
                var(requestBodyCopyResult, requestBodyError) = await requestContent.ConsumptionTask;

                // Check for request body errors, these may have triggered the response error.
                if (requestBodyCopyResult != StreamCopyResult.Success)
                {
                    HandleRequestBodyFailure(context, requestBodyCopyResult, requestBodyError, responseBodyException);
                    return;
                }
            }

            var error = responseBodyCopyResult switch
            {
                StreamCopyResult.InputError => ProxyError.ResponseBodyDestination,
                StreamCopyResult.OutputError => ProxyError.ResponseBodyClient,
                StreamCopyResult.Canceled => ProxyError.ResponseBodyCanceled,
                _ => throw new NotImplementedException(responseBodyCopyResult.ToString()),
            };

            ReportProxyError(context, error, responseBodyException);

            if (!context.Response.HasStarted)
            {
                // Nothing has been sent to the client yet, we can still send a good error response.
                context.Response.Clear();
                context.Response.StatusCode = StatusCodes.Status502BadGateway;
                return;
            }

            // The response has already started, we must forcefully terminate it so the client doesn't get the
            // the mistaken impression that the truncated response is complete.
            ResetOrAbort(context, isCancelled: responseBodyCopyResult == StreamCopyResult.Canceled);
        }