diff --git a/src/Http/Http/src/Features/FormFeature.cs b/src/Http/Http/src/Features/FormFeature.cs index a9128f8f3f01..a7807f0ab9d1 100644 --- a/src/Http/Http/src/Features/FormFeature.cs +++ b/src/Http/Http/src/Features/FormFeature.cs @@ -16,11 +16,12 @@ namespace Microsoft.AspNetCore.Http.Features; /// public class FormFeature : IFormFeature { - private readonly HttpRequest _request; + private readonly HttpRequest? _request; private readonly Endpoint? _endpoint; private FormOptions _options; private Task? _parsedFormTask; private IFormCollection? _form; + private MediaTypeHeaderValue? _formContentType; // null iff _form is null /// /// Initializes a new instance of . @@ -31,7 +32,7 @@ public FormFeature(IFormCollection form) ArgumentNullException.ThrowIfNull(form); Form = form; - _request = default!; + _formContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); _options = FormOptions.Default; } @@ -71,8 +72,19 @@ private MediaTypeHeaderValue? ContentType { get { - _ = MediaTypeHeaderValue.TryParse(_request.ContentType, out var mt); - return mt; + MediaTypeHeaderValue? mt = null; + + if (_request is not null) + { + _ = MediaTypeHeaderValue.TryParse(_request.ContentType, out mt); + } + + if (_form is not null && mt is null) + { + mt = _formContentType; + } + + return mt; } } @@ -87,6 +99,11 @@ public bool HasFormContentType return true; } + if (_request is null) + { + return false; + } + var contentType = ContentType; return HasApplicationFormContentType(contentType) || HasMultipartFormContentType(contentType); } @@ -106,6 +123,14 @@ public IFormCollection? Form { _parsedFormTask = null; _form = value; + if (_form is null) + { + _formContentType = null; + } + else + { + _formContentType ??= new MediaTypeHeaderValue("application/x-www-form-urlencoded"); + } } } @@ -151,6 +176,11 @@ public Task ReadFormAsync(CancellationToken cancellationToken) private async Task InnerReadFormAsync(CancellationToken cancellationToken) { + if (_request is null) + { + throw new InvalidOperationException("Cannot read form from this request. Request is 'null'."); + } + HandleUncheckedAntiforgeryValidationFeature(); _options = _endpoint is null ? _options : GetFormOptionsFromMetadata(_options, _endpoint); @@ -326,6 +356,10 @@ private static bool HasMultipartFormContentType([NotNullWhen(true)] MediaTypeHea private bool ResolveHasInvalidAntiforgeryValidationFeature() { + if (_request is null) + { + return false; + } var hasInvokedMiddleware = _request.HttpContext.Items.ContainsKey("__AntiforgeryMiddlewareWithEndpointInvoked"); var hasInvalidToken = _request.HttpContext.Features.Get() is { IsValid: false }; return hasInvokedMiddleware && hasInvalidToken;