| File: Core\IISHttpContextOfT.cs | Web Access |
| Project: src\aspnetcore\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; } try { 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; } } finally { // Defensive finally in case any of the above code throws an exception // Important cleanup, this ensures native is done with async completions and we can cleanup resources // If this somehow didn't run and native was still doing async completions, we could end up AVing // when trying to access managed objects that were already collected. // 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; } }