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 ValueTask <ForwarderError> HandleResponseBodyErrorAsync(HttpContext context, StreamCopyHttpContent?requestContent, StreamCopyResult responseBodyCopyResult, Exception responseBodyException, CancellationTokenSource requestCancellationSource)
    {
        if (requestContent is not null && requestContent.Started)
        {
            var alreadyFinished = requestContent.ConsumptionTask.IsCompleted == true;

            if (!alreadyFinished)
            {
                requestCancellationSource.Cancel();
            }

            var(requestBodyCopyResult, requestBodyError) = await requestContent.ConsumptionTask;

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

        var error = responseBodyCopyResult switch
        {
            StreamCopyResult.InputError => ForwarderError.ResponseBodyDestination,
            StreamCopyResult.OutputError => ForwarderError.ResponseBodyClient,
            StreamCopyResult.Canceled => ForwarderError.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(error);
        }

        // 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);

        return(error);
    }