File: Core\IISHttpContextOfT.cs
Web Access
Project: src\src\Servers\IIS\IIS\src\Microsoft.AspNetCore.Server.IIS.csproj (Microsoft.AspNetCore.Server.IIS)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Buffers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
 
namespace Microsoft.AspNetCore.Server.IIS.Core;
 
using BadHttpRequestException = Microsoft.AspNetCore.Http.BadHttpRequestException;
 
internal sealed class IISHttpContextOfT<TContext> : IISHttpContext where TContext : notnull
{
    private readonly IHttpApplication<TContext> _application;
 
    public IISHttpContextOfT(MemoryPool<byte> memoryPool, IHttpApplication<TContext> application, NativeSafeHandle pInProcessHandler, IISServerOptions options, IISHttpServer server, ILogger logger, bool useLatin1)
        : base(memoryPool, pInProcessHandler, options, server, logger, useLatin1)
    {
        _application = application;
    }
 
    public override async Task<bool> ProcessRequestAsync()
    {
        var context = default(TContext);
        var success = true;
 
        try
        {
            InitializeContext();
 
            try
            {
                context = _application.CreateContext(this);
 
                await _application.ProcessRequestAsync(context);
            }
            catch (BadHttpRequestException ex)
            {
                SetBadRequestState(ex);
                ReportApplicationError(ex);
                success = false;
            }
            catch (Exception ex)
            {
                if ((ex is OperationCanceledException || ex is IOException) && ClientDisconnected)
                {
                    ReportRequestAborted();
                }
                else
                {
                    ReportApplicationError(ex);
                }
 
                success = false;
            }
 
            if (ResponsePipeWrapper != null)
            {
                await ResponsePipeWrapper.CompleteAsync();
            }
 
            _streams.Stop();
 
            if (!HasResponseStarted && _applicationException == null && _onStarting != null)
            {
                await FireOnStarting();
                // Dispose
            }
 
            if (!success && HasResponseStarted && AdvancedHttp2FeaturesSupported())
            {
                // HTTP/2 INTERNAL_ERROR = 0x2 https://tools.ietf.org/html/rfc7540#section-7
                // Otherwise the default is Cancel = 0x8 (h2) or 0x010c (h3).
                if (HttpVersion == System.Net.HttpVersion.Version20)
                {
                    // HTTP/2 INTERNAL_ERROR = 0x2 https://tools.ietf.org/html/rfc7540#section-7
                    SetResetCode(2);
                }
                else if (HttpVersion == System.Net.HttpVersion.Version30)
                {
                    // HTTP/3 H3_INTERNAL_ERROR = 0x0102 https://quicwg.org/base-drafts/draft-ietf-quic-http.html#section-8.1
                    SetResetCode(0x0102);
                }
            }
 
            if (!_requestAborted)
            {
                await ProduceEnd();
            }
            else if (!HasResponseStarted && _requestRejectedException == null)
            {
                // If the request was aborted and no response was sent, we use status code 499 for logging               
                StatusCode = ClientDisconnected ? StatusCodes.Status499ClientClosedRequest : 0;
                success = false;
            }
 
            // Complete response writer and request reader pipe sides
            _bodyOutput.Complete();
            _bodyInputPipe?.Reader.Complete();
 
            // Allow writes to drain
            if (_writeBodyTask != null)
            {
                await _writeBodyTask;
            }
 
            // Cancel all remaining IO, there might be reads pending if not entire request body was sent by client
            AsyncIO?.Complete();
 
            if (_readBodyTask != null)
            {
                await _readBodyTask;
            }
        }
        catch (Exception ex)
        {
            success = false;
            ReportApplicationError(ex);
        }
        finally
        {
            if (_onCompleted != null)
            {
                await FireOnCompleted();
            }
 
            if (context != null)
            {
                try
                {
                    _application.DisposeContext(context, _applicationException);
                }
                catch (Exception ex)
                {
                    ReportApplicationError(ex);
                }
            }
        }
        return success;
    }
}