Skip to content

Add Request Decompression middleware #40279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 48 commits into from
Jun 3, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
77923d6
Add Request Decompression middleware
david-acker Feb 17, 2022
d888b86
Fix API baselines
david-acker Feb 17, 2022
ca2b675
Minor fixes
david-acker Feb 18, 2022
d3d074a
Eagerly resolve decompression provider and stream
david-acker Feb 18, 2022
4a4e902
Pass requests to endpoint instead of returning 415
david-acker Feb 18, 2022
8ad1352
Revert request body to original value
david-acker Feb 18, 2022
f8d2604
Seal decompression providers
david-acker Feb 18, 2022
12c4519
Use constructor injection for logger
david-acker Feb 19, 2022
e000add
Remove unused property
david-acker Feb 19, 2022
e2a9963
Seal more classes
david-acker Feb 19, 2022
74622dd
Only create RequestDecompressionBody if a decompresison provider exists
david-acker Feb 19, 2022
b4ddfd3
Remove Content-Encoding header if decompressed
david-acker Feb 19, 2022
1d43fef
Fix extensions namespaces
david-acker Feb 19, 2022
fa98756
Remove RequestDecompressionBody
david-acker Feb 19, 2022
e055698
Fix class name
david-acker Feb 19, 2022
03e31c1
Directly instantiate default providers
david-acker Feb 19, 2022
dca2b17
Replace Single with cast
david-acker Feb 19, 2022
202cd2d
Add tests
david-acker Feb 20, 2022
087cf21
Store providers in dictionary
david-acker Feb 20, 2022
8857a63
Fix API baselines
david-acker Feb 20, 2022
c453739
Add MaxRequestBodySize to RequestDecompressionOptions
david-acker Feb 21, 2022
2d674b1
Clean up
david-acker Feb 22, 2022
76fe411
Add, clean up tests
david-acker Feb 22, 2022
7b297ca
Add IRequestSizeLimitMetadata
david-acker Feb 28, 2022
ef9f9cc
Use updated middleware design
david-acker Feb 28, 2022
be883d9
Merge branch 'main' into request-decompression
david-acker Feb 28, 2022
d0e3ea5
Address PR feedback
david-acker Mar 1, 2022
1302dac
Address PR feedback
david-acker Mar 2, 2022
7acf307
Update DefaultRequestDecompressionProvider.cs
pranavkm Mar 2, 2022
f6304d0
Update DefaultRequestDecompressionProvider.cs
pranavkm Mar 2, 2022
71c3cb4
Update RequestDecompressionMiddleware.cs
pranavkm Mar 2, 2022
c96647a
Merge branch 'main' into request-decompression
pranavkm Mar 2, 2022
245ac78
Update RequestDecompressionMiddleware.cs
pranavkm Mar 2, 2022
9a2268e
Use default implementations for BeginRead, EndRead
david-acker Mar 3, 2022
e5376e5
Merge branch 'main' into request-decompression
sebastienros Apr 5, 2022
3ffb5f9
Merge branch 'main' into request-decompression
sebastienros May 9, 2022
38eb172
Make MaxRequestBodySize nullable
david-acker May 16, 2022
ea3a334
Implement IRequestSizeLimitMetadata
david-acker May 16, 2022
c293ade
Add security concern to remarks
david-acker May 16, 2022
7beceb9
Add test for invalid compressed data
david-acker May 16, 2022
cd32124
Set IHttpMaxRequestBodySizeFeature using IRequestSizeLimitMetadata
david-acker May 17, 2022
b33b594
Merge branch 'main' into request-decompression
david-acker May 19, 2022
519310c
Add benchmarks
david-acker May 20, 2022
e31ef58
Remove unneeded project references
david-acker May 20, 2022
18632ef
Pass all write operations to inner stream
david-acker May 20, 2022
3f39a4d
Replace async/await with AsTask
david-acker May 20, 2022
b670356
Fix variable name
david-acker May 25, 2022
5cb34b6
Merge branch 'main' into request-decompression
sebastienros Jun 3, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions AspNetCore.sln
Original file line number Diff line number Diff line change
Expand Up @@ -1658,6 +1658,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Compon
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Components.SdkAnalyzers.Tests", "src\Tools\SDK-Analyzers\Components\test\Microsoft.AspNetCore.Components.SdkAnalyzers.Tests.csproj", "{DC349A25-0DBF-4468-99E1-B95C22D3A7EF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RequestDecompression", "RequestDecompression", "{5465F96F-33D5-454E-9C40-494E58AEEE5D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.RequestDecompression.Tests", "src\Middleware\RequestDecompression\test\Microsoft.AspNetCore.RequestDecompression.Tests.csproj", "{97996D39-7722-4AFC-A41A-AD61CA7A413D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RequestDecompressionSample", "src\Middleware\RequestDecompression\sample\RequestDecompressionSample.csproj", "{37144E52-611B-40E8-807C-2821F5A814CB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.RequestDecompression", "src\Middleware\RequestDecompression\src\Microsoft.AspNetCore.RequestDecompression.csproj", "{559FE354-7E08-4310-B4F3-AE30F34DEED5}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LinkabilityChecker", "LinkabilityChecker", "{94F95276-7CDF-44A8-B159-D09702EF6794}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinkabilityChecker", "src\Tools\LinkabilityChecker\LinkabilityChecker.csproj", "{EA7D844B-C180-41C7-9D55-273AD88BF71F}"
Expand Down Expand Up @@ -9938,6 +9945,54 @@ Global
{DC349A25-0DBF-4468-99E1-B95C22D3A7EF}.Release|x64.Build.0 = Release|Any CPU
{DC349A25-0DBF-4468-99E1-B95C22D3A7EF}.Release|x86.ActiveCfg = Release|Any CPU
{DC349A25-0DBF-4468-99E1-B95C22D3A7EF}.Release|x86.Build.0 = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|arm64.ActiveCfg = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|arm64.Build.0 = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|x64.ActiveCfg = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|x64.Build.0 = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|x86.ActiveCfg = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Debug|x86.Build.0 = Debug|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|Any CPU.Build.0 = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|arm64.ActiveCfg = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|arm64.Build.0 = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|x64.ActiveCfg = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|x64.Build.0 = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|x86.ActiveCfg = Release|Any CPU
{97996D39-7722-4AFC-A41A-AD61CA7A413D}.Release|x86.Build.0 = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|arm64.ActiveCfg = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|arm64.Build.0 = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|x64.ActiveCfg = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|x64.Build.0 = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|x86.ActiveCfg = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Debug|x86.Build.0 = Debug|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|Any CPU.Build.0 = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|arm64.ActiveCfg = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|arm64.Build.0 = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|x64.ActiveCfg = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|x64.Build.0 = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|x86.ActiveCfg = Release|Any CPU
{37144E52-611B-40E8-807C-2821F5A814CB}.Release|x86.Build.0 = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|arm64.ActiveCfg = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|arm64.Build.0 = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|x64.ActiveCfg = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|x64.Build.0 = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|x86.ActiveCfg = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Debug|x86.Build.0 = Debug|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|Any CPU.Build.0 = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|arm64.ActiveCfg = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|arm64.Build.0 = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|x64.ActiveCfg = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|x64.Build.0 = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|x86.ActiveCfg = Release|Any CPU
{559FE354-7E08-4310-B4F3-AE30F34DEED5}.Release|x86.Build.0 = Release|Any CPU
{EA7D844B-C180-41C7-9D55-273AD88BF71F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA7D844B-C180-41C7-9D55-273AD88BF71F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA7D844B-C180-41C7-9D55-273AD88BF71F}.Debug|arm64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -10774,6 +10829,10 @@ Global
{CC45FA2D-128B-485D-BA6D-DFD9735CB3C3} = {6C06163A-80E9-49C1-817C-B391852BA563}
{825BCF97-67A9-4834-B3A8-C3DC97A90E41} = {CC45FA2D-128B-485D-BA6D-DFD9735CB3C3}
{DC349A25-0DBF-4468-99E1-B95C22D3A7EF} = {CC45FA2D-128B-485D-BA6D-DFD9735CB3C3}
{5465F96F-33D5-454E-9C40-494E58AEEE5D} = {E5963C9F-20A6-4385-B364-814D2581FADF}
{97996D39-7722-4AFC-A41A-AD61CA7A413D} = {5465F96F-33D5-454E-9C40-494E58AEEE5D}
{37144E52-611B-40E8-807C-2821F5A814CB} = {5465F96F-33D5-454E-9C40-494E58AEEE5D}
{559FE354-7E08-4310-B4F3-AE30F34DEED5} = {5465F96F-33D5-454E-9C40-494E58AEEE5D}
{94F95276-7CDF-44A8-B159-D09702EF6794} = {0B200A66-B809-4ED3-A790-CB1C2E80975E}
{EA7D844B-C180-41C7-9D55-273AD88BF71F} = {94F95276-7CDF-44A8-B159-D09702EF6794}
EndGlobalSection
Expand Down
1 change: 1 addition & 0 deletions eng/ProjectReferences.props
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Localization.Routing" ProjectPath="$(RepoRoot)src\Middleware\Localization.Routing\src\Microsoft.AspNetCore.Localization.Routing.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Localization" ProjectPath="$(RepoRoot)src\Middleware\Localization\src\Microsoft.AspNetCore.Localization.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.MiddlewareAnalysis" ProjectPath="$(RepoRoot)src\Middleware\MiddlewareAnalysis\src\Microsoft.AspNetCore.MiddlewareAnalysis.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.RequestDecompression" ProjectPath="$(RepoRoot)src\Middleware\RequestDecompression\src\Microsoft.AspNetCore.RequestDecompression.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.ResponseCaching.Abstractions" ProjectPath="$(RepoRoot)src\Middleware\ResponseCaching.Abstractions\src\Microsoft.AspNetCore.ResponseCaching.Abstractions.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.ResponseCaching" ProjectPath="$(RepoRoot)src\Middleware\ResponseCaching\src\Microsoft.AspNetCore.ResponseCaching.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.ResponseCompression" ProjectPath="$(RepoRoot)src\Middleware\ResponseCompression\src\Microsoft.AspNetCore.ResponseCompression.csproj" />
Expand Down
1 change: 1 addition & 0 deletions eng/SharedFramework.Local.props
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<AspNetCoreAppReference Include="Microsoft.AspNetCore.HttpsPolicy" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Localization.Routing" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.Localization" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.RequestDecompression" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.ResponseCaching.Abstractions" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.ResponseCaching" />
<AspNetCoreAppReference Include="Microsoft.AspNetCore.ResponseCompression" />
Expand Down
2 changes: 2 additions & 0 deletions src/Framework/test/TestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ static TestData()
"Microsoft.AspNetCore.Mvc.ViewFeatures",
"Microsoft.AspNetCore.Razor",
"Microsoft.AspNetCore.Razor.Runtime",
"Microsoft.AspNetCore.RequestDecompression",
"Microsoft.AspNetCore.ResponseCaching",
"Microsoft.AspNetCore.ResponseCaching.Abstractions",
"Microsoft.AspNetCore.ResponseCompression",
Expand Down Expand Up @@ -210,6 +211,7 @@ static TestData()
{ "Microsoft.AspNetCore.Mvc.ViewFeatures", "7.0.0.0" },
{ "Microsoft.AspNetCore.Razor", "7.0.0.0" },
{ "Microsoft.AspNetCore.Razor.Runtime", "7.0.0.0" },
{ "Microsoft.AspNetCore.RequestDecompression", "7.0.0.0" },
{ "Microsoft.AspNetCore.ResponseCaching", "7.0.0.0" },
{ "Microsoft.AspNetCore.ResponseCaching.Abstractions", "7.0.0.0" },
{ "Microsoft.AspNetCore.ResponseCompression", "7.0.0.0" },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.AspNetCore.Http.Metadata;

/// <summary>
/// Interface marking attributes that specify the maximum allowed size of the request body.
/// </summary>
public interface IRequestSizeLimitMetadata
{
/// <summary>
/// The maximum allowed size of the current request body in bytes.
/// </summary>
long MaxRequestBodySize { get; }
}
2 changes: 2 additions & 0 deletions src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
Microsoft.AspNetCore.Http.EndpointMetadataCollection.GetRequiredMetadata<T>() -> T!
Microsoft.AspNetCore.Http.Metadata.IFromFormMetadata
Microsoft.AspNetCore.Http.Metadata.IFromFormMetadata.Name.get -> string?
Microsoft.AspNetCore.Http.Metadata.IRequestSizeLimitMetadata
Microsoft.AspNetCore.Http.Metadata.IRequestSizeLimitMetadata.MaxRequestBodySize.get -> long
abstract Microsoft.AspNetCore.Http.HttpResponse.ContentType.get -> string?
Microsoft.AspNetCore.Http.Metadata.ISkipStatusCodePagesMetadata
5 changes: 4 additions & 1 deletion src/Middleware/Middleware.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
"src\\Middleware\\MiddlewareAnalysis\\samples\\MiddlewareAnalysisSample\\MiddlewareAnalysisSample.csproj",
"src\\Middleware\\MiddlewareAnalysis\\src\\Microsoft.AspNetCore.MiddlewareAnalysis.csproj",
"src\\Middleware\\MiddlewareAnalysis\\test\\Microsoft.AspNetCore.MiddlewareAnalysis.Tests.csproj",
"src\\Middleware\\RequestDecompression\\sample\\RequestDecompressionSample.csproj",
"src\\Middleware\\RequestDecompression\\src\\Microsoft.AspNetCore.RequestDecompression.csproj",
"src\\Middleware\\RequestDecompression\\test\\Microsoft.AspNetCore.RequestDecompression.Tests.csproj",
"src\\Middleware\\ResponseCaching.Abstractions\\src\\Microsoft.AspNetCore.ResponseCaching.Abstractions.csproj",
"src\\Middleware\\ResponseCaching\\samples\\ResponseCachingSample\\ResponseCachingSample.csproj",
"src\\Middleware\\ResponseCaching\\src\\Microsoft.AspNetCore.ResponseCaching.csproj",
Expand Down Expand Up @@ -115,4 +118,4 @@
"src\\Servers\\Kestrel\\Transport.Sockets\\src\\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.RequestDecompression;

namespace RequestDecompressionSample;

public class CustomDecompressionProvider : IDecompressionProvider
{
public Stream GetDecompressionStream(Stream stream)
{
// Create a custom decompression stream wrapper here.
return stream;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:6164/",
"sslPort": 0
}
},
"profiles": {
"RequestDecompressionSample": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000/",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Reference Include="Microsoft.AspNetCore.RequestDecompression" />
<Reference Include="Microsoft.AspNetCore.Server.Kestrel" />
<Reference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>

</Project>
48 changes: 48 additions & 0 deletions src/Middleware/RequestDecompression/sample/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace RequestDecompressionSample;

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRequestDecompression(options =>
{
options.DecompressionProviders.Add("custom", new CustomDecompressionProvider());
});
}

public void Configure(IApplicationBuilder app)
{
app.UseRequestDecompression();
app.Map("/test", testApp =>
{
testApp.Run(async context =>
{
using var reader = new StreamReader(context.Request.Body);
var decompressedBody = await reader.ReadToEndAsync(context.RequestAborted);

await context.Response.WriteAsync(decompressedBody, context.RequestAborted);
});
});
}

public static Task Main(string[] args)
{
var host = new HostBuilder()
.ConfigureWebHost(webHostBuilder =>
{
webHostBuilder
.UseKestrel()
.ConfigureLogging(factory =>
{
factory.AddConsole()
.SetMinimumLevel(LogLevel.Debug);
})
.UseStartup<Startup>();
}).Build();

return host.RunAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO.Compression;

namespace Microsoft.AspNetCore.RequestDecompression;

/// <summary>
/// Brotli decompression provider.
/// </summary>
internal sealed class BrotliDecompressionProvider : IDecompressionProvider
{
/// <inheritdoc />
public Stream GetDecompressionStream(Stream stream)
{
return new BrotliStream(stream, CompressionMode.Decompress, leaveOpen: true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.RequestDecompression;

/// <inheritdoc />
internal sealed partial class DefaultRequestDecompressionProvider : IRequestDecompressionProvider
{
private readonly ILogger _logger;
private readonly IDictionary<string, IDecompressionProvider> _providers;

public DefaultRequestDecompressionProvider(
ILogger<DefaultRequestDecompressionProvider> logger,
IOptions<RequestDecompressionOptions> options)
{
if (logger is null)
{
throw new ArgumentNullException(nameof(logger));
}

if (options is null)
{
throw new ArgumentNullException(nameof(options));
}

_logger = logger;
_providers = options.Value.DecompressionProviders;
}

/// <inheritdoc />
public Stream? GetDecompressionStream(HttpContext context)
{
var encodings = context.Request.Headers.ContentEncoding;

if (StringValues.IsNullOrEmpty(encodings))
{
Log.NoContentEncoding(_logger);
return null;
}

if (encodings.Count > 1)
{
Log.MultipleContentEncodingsSpecified(_logger);
return null;
}

string encodingName = encodings!;

if (_providers.TryGetValue(encodingName, out var matchingProvider))
{
Log.DecompressingWith(_logger, encodingName);

context.Request.Headers.Remove(HeaderNames.ContentEncoding);

return matchingProvider.GetDecompressionStream(context.Request.Body);
}

Log.NoDecompressionProvider(_logger);
return null;
}

private static partial class Log
{
[LoggerMessage(1, LogLevel.Trace, "The Content-Encoding header is empty or not specified. Skipping request decompression.", EventName = "NoContentEncoding")]
public static partial void NoContentEncoding(ILogger logger);

[LoggerMessage(2, LogLevel.Debug, "Request decompression is not supported for multiple Content-Encodings.", EventName = "MultipleContentEncodingsSpecified")]
public static partial void MultipleContentEncodingsSpecified(ILogger logger);

[LoggerMessage(3, LogLevel.Debug, "No matching request decompression provider found.", EventName = "NoDecompressionProvider")]
public static partial void NoDecompressionProvider(ILogger logger);

public static void DecompressingWith(ILogger logger, string contentEncoding)
{
if (logger.IsEnabled(LogLevel.Debug)
{
DecompressingWithCore(logger, contentEncoding.ToLowerInvariant());
}
}

[LoggerMessage(4, LogLevel.Debug, "The request will be decompressed with '{ContentEncoding}'.", EventName = "DecompressingWith", SkipEnabledCheck = true)]
private static partial void DecompressingWithCore(ILogger logger, string contentEncoding);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO.Compression;

namespace Microsoft.AspNetCore.RequestDecompression;

/// <summary>
/// DEFLATE decompression provider.
/// </summary>
internal sealed class DeflateDecompressionProvider : IDecompressionProvider
{
/// <inheritdoc />
public Stream GetDecompressionStream(Stream stream)
{
return new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true);
}
}
Loading