Skip to content
This repository was archived by the owner on Sep 9, 2022. It is now read-only.

Commit 2598062

Browse files
committed
Init
1 parent b84d810 commit 2598062

25 files changed

+1430
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,5 @@ UpgradeLog*.htm
172172

173173
# Microsoft Fakes
174174
FakesAssemblies/
175+
src/NuGetPackage/*.nupkg
176+
src/NuGetPackage/lib/

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,24 @@ Microsoft.AspNet.WebApi.MessageHandlers.Compression
22
===================================================
33

44
Drop-in module for ASP.Net WebAPI that enables `GZip` and `Deflate` support
5+
6+
7+
### How to use
8+
**Server side**:
9+
You need to add the compression handler as the last applied message handler on outgoing requests, and the first one on incoming requests.
10+
To do that, just add the following line to your `App_Start\WebApiConfig.cs` file after adding all your other message handlers:
11+
```csharp
12+
config.MessageHandlers.Insert(0, new CompressionHandler(new GZipCompressor(), new DeflateCompressor()));
13+
```
14+
This will insert the `CompressionHandler` to the request pipeline as the first one on incoming requests, and the last one on outgoing requests.
15+
16+
**Client side**:
17+
You need to apply the following code when creating your `HttpClient`:
18+
```csharp
19+
var client =
20+
new HttpClient(
21+
new DecompressionHandler(new HttpClientHandler(), new GZipCompressor(), new DeflateCompressor()));
22+
23+
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
24+
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
25+
```
Binary file not shown.
Binary file not shown.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 2013
4+
VisualStudioVersion = 12.0.30501.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuGetPackage", "NuGetPackage\NuGetPackage.csproj", "{0451BAEF-DF2E-4B98-8644-94EE9415E389}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.WebApi.MessageHandlers.Compression", "Microsoft.AspNet.WebApi.MessageHandlers.Compression\Microsoft.AspNet.WebApi.MessageHandlers.Compression.csproj", "{56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{0451BAEF-DF2E-4B98-8644-94EE9415E389}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{56E19FF7-9AC7-48C5-9AC2-105F55AA16E1}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
EndGlobal
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<GhostDoc>
2+
<SpellChecker>
3+
<IncludeExtensions>
4+
</IncludeExtensions>
5+
<IgnoreExtensions>
6+
</IgnoreExtensions>
7+
<IgnoreFiles>
8+
</IgnoreFiles>
9+
</SpellChecker>
10+
<HelpConfigurations selected="HelpFile">
11+
<HelpConfiguration name="HelpFile">
12+
<OutputPath>.\Help</OutputPath>
13+
<ImageFolderPath />
14+
<HtmlFormats>
15+
<HtmlHelp>true</HtmlHelp>
16+
<MSHelpViewer>false</MSHelpViewer>
17+
<MSHelp2>false</MSHelp2>
18+
<Website>false</Website>
19+
</HtmlFormats>
20+
<IncludeScopes>
21+
<Public>true</Public>
22+
<Internal>false</Internal>
23+
<Protected>false</Protected>
24+
<Private>false</Private>
25+
<Inherited>true</Inherited>
26+
<EnableTags>false</EnableTags>
27+
<TagList />
28+
</IncludeScopes>
29+
<ResolveCrefLinks>true</ResolveCrefLinks>
30+
<HeaderText />
31+
<FooterText />
32+
<SelectedProjects />
33+
</HelpConfiguration>
34+
</HelpConfigurations>
35+
</GhostDoc>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
namespace Microsoft.AspNet.WebApi.MessageHandlers.Compression
2+
{
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Net.Http;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
using Microsoft.AspNet.WebApi.MessageHandlers.Compression.Interfaces;
10+
using Microsoft.AspNet.WebApi.MessageHandlers.Compression.Models;
11+
12+
/// <summary>
13+
/// Message handler for handling gzip/deflate requests/responses.
14+
/// </summary>
15+
public class CompressionHandler : DelegatingHandler
16+
{
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="CompressionHandler" /> class.
19+
/// </summary>
20+
/// <param name="compressors">The compressors.</param>
21+
public CompressionHandler(params ICompressor[] compressors)
22+
{
23+
this.Compressors = compressors;
24+
}
25+
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="CompressionHandler" /> class.
28+
/// </summary>
29+
/// <param name="innerHandler">The inner handler.</param>
30+
/// <param name="compressors">The compressors.</param>
31+
public CompressionHandler(HttpMessageHandler innerHandler, params ICompressor[] compressors)
32+
{
33+
this.InnerHandler = innerHandler;
34+
this.Compressors = compressors;
35+
}
36+
37+
/// <summary>
38+
/// Gets the compressors.
39+
/// </summary>
40+
/// <value>The compressors.</value>
41+
public ICollection<ICompressor> Compressors { get; private set; }
42+
43+
/// <summary>
44+
/// send as an asynchronous operation.
45+
/// </summary>
46+
/// <param name="request">The HTTP request message to send to the server.</param>
47+
/// <param name="cancellationToken">A cancellation token to cancel operation.</param>
48+
/// <returns>Returns <see cref="T:System.Threading.Tasks.Task`1" />. The task object representing the asynchronous operation.</returns>
49+
protected override async Task<HttpResponseMessage> SendAsync(
50+
HttpRequestMessage request,
51+
CancellationToken cancellationToken)
52+
{
53+
var response = await base.SendAsync(request, cancellationToken);
54+
55+
if (request.Headers.AcceptEncoding.Any() && response.Content != null)
56+
{
57+
// As per RFC2616.14.3:
58+
// Ignores encodings with quality == 0
59+
// If multiple content-codings are acceptable, then the acceptable content-coding with the highest non-zero qvalue is preferred.
60+
var compressor = (from encoding in request.Headers.AcceptEncoding
61+
let quality = encoding.Quality ?? 1.0
62+
where quality > 0
63+
join c in this.Compressors on encoding.Value.ToLowerInvariant() equals
64+
c.EncodingType.ToLowerInvariant()
65+
orderby quality descending
66+
select c).FirstOrDefault();
67+
68+
if (compressor != null)
69+
{
70+
response.Content = new CompressedContent(response.Content, compressor);
71+
}
72+
}
73+
74+
return response;
75+
}
76+
}
77+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
namespace Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors
2+
{
3+
using System.IO;
4+
using System.Threading.Tasks;
5+
6+
using Microsoft.AspNet.WebApi.MessageHandlers.Compression.Interfaces;
7+
8+
/// <summary>
9+
/// Base compressor for compressing streams.
10+
/// </summary>
11+
public abstract class BaseCompressor : ICompressor
12+
{
13+
/// <summary>
14+
/// Gets the encoding type.
15+
/// </summary>
16+
/// <value>The encoding type.</value>
17+
public abstract string EncodingType { get; }
18+
19+
/// <summary>
20+
/// Creates the compression stream.
21+
/// </summary>
22+
/// <param name="output">The output stream.</param>
23+
/// <returns>The compressed stream.</returns>
24+
public abstract Stream CreateCompressionStream(Stream output);
25+
26+
/// <summary>
27+
/// Creates the decompression stream.
28+
/// </summary>
29+
/// <param name="input">The input stream.</param>
30+
/// <returns>The decompressed stream.</returns>
31+
public abstract Stream CreateDecompressionStream(Stream input);
32+
33+
/// <summary>
34+
/// Compresses the specified source stream onto the destination stream.
35+
/// </summary>
36+
/// <param name="source">The source.</param>
37+
/// <param name="destination">The destination.</param>
38+
/// <returns>An async void.</returns>
39+
public virtual Task Compress(Stream source, Stream destination)
40+
{
41+
var compressed = this.CreateCompressionStream(destination);
42+
43+
return this.Pump(source, compressed).ContinueWith(task => compressed.Dispose());
44+
}
45+
46+
/// <summary>
47+
/// Decompresses the specified source stream onto the destination stream.
48+
/// </summary>
49+
/// <param name="source">The source.</param>
50+
/// <param name="destination">The destination.</param>
51+
/// <returns>An async void.</returns>
52+
public virtual Task Decompress(Stream source, Stream destination)
53+
{
54+
var decompressed = this.CreateDecompressionStream(source);
55+
56+
return this.Pump(decompressed, destination).ContinueWith(task => decompressed.Dispose());
57+
}
58+
59+
/// <summary>
60+
/// Copies the specified input stream onto the output stream.
61+
/// </summary>
62+
/// <param name="input">The input.</param>
63+
/// <param name="output">The output.</param>
64+
/// <returns>An async void.</returns>
65+
protected virtual Task Pump(Stream input, Stream output)
66+
{
67+
return input.CopyToAsync(output);
68+
}
69+
}
70+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors
2+
{
3+
using System.IO;
4+
using System.IO.Compression;
5+
6+
/// <summary>
7+
/// Compressor for handling <c>deflate</c> encodings.
8+
/// </summary>
9+
public class DeflateCompressor : BaseCompressor
10+
{
11+
/// <summary>
12+
/// Gets the encoding type.
13+
/// </summary>
14+
/// <value>The encoding type.</value>
15+
public override string EncodingType
16+
{
17+
get { return "deflate"; }
18+
}
19+
20+
/// <summary>
21+
/// Creates the compression stream.
22+
/// </summary>
23+
/// <param name="output">The output stream.</param>
24+
/// <returns>The compressed stream.</returns>
25+
public override Stream CreateCompressionStream(Stream output)
26+
{
27+
return new DeflateStream(output, CompressionMode.Compress, true);
28+
}
29+
30+
/// <summary>
31+
/// Creates the decompression stream.
32+
/// </summary>
33+
/// <param name="input">The input stream.</param>
34+
/// <returns>The decompressed stream.</returns>
35+
public override Stream CreateDecompressionStream(Stream input)
36+
{
37+
return new DeflateStream(input, CompressionMode.Decompress, true);
38+
}
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
namespace Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors
2+
{
3+
using System.IO;
4+
using System.IO.Compression;
5+
6+
/// <summary>
7+
/// Compressor for handling <c>gzip</c> encodings.
8+
/// </summary>
9+
public class GZipCompressor : BaseCompressor
10+
{
11+
/// <summary>
12+
/// Gets the encoding type.
13+
/// </summary>
14+
/// <value>The encoding type.</value>
15+
public override string EncodingType
16+
{
17+
get { return "gzip"; }
18+
}
19+
20+
/// <summary>
21+
/// Creates the compression stream.
22+
/// </summary>
23+
/// <param name="output">The output stream.</param>
24+
/// <returns>The compressed stream.</returns>
25+
public override Stream CreateCompressionStream(Stream output)
26+
{
27+
return new GZipStream(output, CompressionMode.Compress, true);
28+
}
29+
30+
/// <summary>
31+
/// Creates the decompression stream.
32+
/// </summary>
33+
/// <param name="input">The input stream.</param>
34+
/// <returns>The decompressed stream.</returns>
35+
public override Stream CreateDecompressionStream(Stream input)
36+
{
37+
return new GZipStream(input, CompressionMode.Decompress, true);
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)