Skip to content

Commit fecaf78

Browse files
committed
Don't allocate the FormFeature eagerly
- Expose FormOptions on DefaultHttpContext - Use those options on DefaultHttpContext when the FormFeature is initialized
1 parent 8dfee5e commit fecaf78

File tree

6 files changed

+27
-8
lines changed

6 files changed

+27
-8
lines changed

src/Http/Http/src/DefaultHttpContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ public void Uninitialize()
6262
_websockets?.Uninitialize();
6363
}
6464

65+
public FormOptions FormOptions { get; set; }
66+
6567
private IItemsFeature ItemsFeature =>
6668
_features.Fetch(ref _features.Cache.Items, _newItemsFeature);
6769

src/Http/Http/src/Features/FormFeature.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public FormFeature(HttpRequest request, FormOptions options)
4848
}
4949

5050
_request = request;
51-
_options = options;
51+
_options = (request.HttpContext is DefaultHttpContext defaultHttpContext) ? defaultHttpContext.FormOptions ?? options : options;
5252
}
5353

5454
private MediaTypeHeaderValue ContentType

src/Http/Http/src/HttpContextFactory.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,12 @@ public HttpContext Create(IFeatureCollection featureCollection)
4242
_httpContextAccessor.HttpContext = httpContext;
4343
}
4444

45-
var formFeature = new FormFeature(httpContext.Request, _formOptions);
46-
featureCollection.Set<IFormFeature>(formFeature);
45+
httpContext.FormOptions = _formOptions;
4746

4847
return httpContext;
4948
}
5049

51-
private static HttpContext CreateHttpContext(IFeatureCollection featureCollection)
50+
private static DefaultHttpContext CreateHttpContext(IFeatureCollection featureCollection)
5251
{
5352
if (featureCollection is IHttpContextContainer container)
5453
{

src/Http/Http/src/IHttpContextContainer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ namespace Microsoft.AspNetCore.Http
66
{
77
public interface IHttpContextContainer
88
{
9-
HttpContext HttpContext { get; }
9+
DefaultHttpContext HttpContext { get; }
1010
}
1111
}

src/Http/Http/test/Features/FormFeatureTests.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ public async Task ReadFormAsync_0ContentLength_ReturnsEmptyForm()
2929
Assert.Same(FormCollection.Empty, formCollection);
3030
}
3131

32+
[Fact]
33+
public async Task FormFeatureReadsOptionsFromDefaultHttpContext()
34+
{
35+
var context = new DefaultHttpContext();
36+
context.Request.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
37+
context.FormOptions = new FormOptions
38+
{
39+
ValueCountLimit = 1
40+
};
41+
42+
var formContent = Encoding.UTF8.GetBytes("foo=bar&baz=2");
43+
context.Request.Body = new NonSeekableReadStream(formContent);
44+
45+
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
46+
47+
Assert.Equal("Form value count limit 1 exceeded.", exception.Message);
48+
}
49+
3250
[Theory]
3351
[InlineData(true)]
3452
[InlineData(false)]
@@ -391,7 +409,7 @@ public async Task ReadFormAsync_ValueCountLimitExceeded_Throw(bool bufferRequest
391409
IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 });
392410
context.Features.Set<IFormFeature>(formFeature);
393411

394-
var exception = await Assert.ThrowsAsync<InvalidDataException> (() => context.Request.ReadFormAsync());
412+
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
395413
Assert.Equal("Form value count limit 2 exceeded.", exception.Message);
396414
}
397415

@@ -416,7 +434,7 @@ public async Task ReadFormAsync_ValueCountLimitExceededWithFiles_Throw(bool buff
416434
IFormFeature formFeature = new FormFeature(context.Request, new FormOptions() { BufferBody = bufferRequest, ValueCountLimit = 2 });
417435
context.Features.Set<IFormFeature>(formFeature);
418436

419-
var exception = await Assert.ThrowsAsync<InvalidDataException> (() => context.Request.ReadFormAsync());
437+
var exception = await Assert.ThrowsAsync<InvalidDataException>(() => context.Request.ReadFormAsync());
420438
Assert.Equal("Form value count limit 2 exceeded.", exception.Message);
421439
}
422440

src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ public CancellationToken RequestAborted
277277

278278
protected HttpResponseHeaders HttpResponseHeaders { get; } = new HttpResponseHeaders();
279279

280-
HttpContext IHttpContextContainer.HttpContext
280+
DefaultHttpContext IHttpContextContainer.HttpContext
281281
{
282282
get
283283
{

0 commit comments

Comments
 (0)